Skip to content

Commit

Permalink
feat: MathML support (#7836)
Browse files Browse the repository at this point in the history
close #7820
  • Loading branch information
sto3psl authored Dec 8, 2023
1 parent bc7698d commit d42b6ba
Show file tree
Hide file tree
Showing 19 changed files with 372 additions and 157 deletions.
4 changes: 2 additions & 2 deletions packages/compiler-dom/src/parserOptions.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { ParserOptions, NodeTypes, Namespaces } from '@vue/compiler-core'
import { isVoidTag, isHTMLTag, isSVGTag } from '@vue/shared'
import { isVoidTag, isHTMLTag, isSVGTag, isMathMLTag } from '@vue/shared'
import { TRANSITION, TRANSITION_GROUP } from './runtimeHelpers'
import { decodeHtmlBrowser } from './decodeHtmlBrowser'

export const parserOptions: ParserOptions = {
parseMode: 'html',
isVoidTag,
isNativeTag: tag => isHTMLTag(tag) || isSVGTag(tag),
isNativeTag: tag => isHTMLTag(tag) || isSVGTag(tag) || isMathMLTag(tag),
isPreTag: tag => tag === 'pre',
decodeEntities: __BROWSER__ ? decodeHtmlBrowser : undefined,

Expand Down
22 changes: 17 additions & 5 deletions packages/runtime-core/src/apiCreateApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
ComponentPublicInstance
} from './componentPublicInstance'
import { Directive, validateDirectiveName } from './directives'
import { RootRenderFunction } from './renderer'
import { ElementNamespace, RootRenderFunction } from './renderer'
import { InjectionKey } from './apiInject'
import { warn } from './warning'
import { createVNode, cloneVNode, VNode } from './vnode'
Expand Down Expand Up @@ -47,7 +47,7 @@ export interface App<HostElement = any> {
mount(
rootContainer: HostElement | string,
isHydrate?: boolean,
isSVG?: boolean
namespace?: boolean | ElementNamespace
): ComponentPublicInstance
unmount(): void
provide<T>(key: InjectionKey<T> | string, value: T): this
Expand Down Expand Up @@ -297,7 +297,7 @@ export function createAppAPI<HostElement>(
mount(
rootContainer: HostElement,
isHydrate?: boolean,
isSVG?: boolean
namespace?: boolean | ElementNamespace
): any {
if (!isMounted) {
// #5571
Expand All @@ -313,17 +313,29 @@ export function createAppAPI<HostElement>(
// this will be set on the root instance on initial mount.
vnode.appContext = context

if (namespace === true) {
namespace = 'svg'
} else if (namespace === false) {
namespace = undefined
}

// HMR root reload
if (__DEV__) {
context.reload = () => {
render(cloneVNode(vnode), rootContainer, isSVG)
// casting to ElementNamespace because TS doesn't guarantee type narrowing
// over function boundaries
render(
cloneVNode(vnode),
rootContainer,
namespace as ElementNamespace
)
}
}

if (isHydrate && hydrate) {
hydrate(vnode as VNode<Node, Element>, rootContainer as any)
} else {
render(vnode, rootContainer, isSVG)
render(vnode, rootContainer, namespace)
}
isMounted = true
app._container = rootContainer
Expand Down
14 changes: 10 additions & 4 deletions packages/runtime-core/src/compat/global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
} from '@vue/shared'
import { warn } from '../warning'
import { cloneVNode, createVNode } from '../vnode'
import { RootRenderFunction } from '../renderer'
import { ElementNamespace, RootRenderFunction } from '../renderer'
import {
App,
AppConfig,
Expand Down Expand Up @@ -503,15 +503,21 @@ function installCompatMount(
container = selectorOrEl || document.createElement('div')
}

const isSVG = container instanceof SVGElement
let namespace: ElementNamespace
if (container instanceof SVGElement) namespace = 'svg'
else if (
typeof MathMLElement === 'function' &&
container instanceof MathMLElement
)
namespace = 'mathml'

// HMR root reload
if (__DEV__) {
context.reload = () => {
const cloned = cloneVNode(vnode)
// compat mode will use instance if not reset to null
cloned.component = null
render(cloned, container, isSVG)
render(cloned, container, namespace)
}
}

Expand All @@ -538,7 +544,7 @@ function installCompatMount(
container.innerHTML = ''

// TODO hydration
render(vnode, container, isSVG)
render(vnode, container, namespace)

if (container instanceof Element) {
container.removeAttribute('v-cloak')
Expand Down
15 changes: 11 additions & 4 deletions packages/runtime-core/src/components/KeepAlive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ import {
queuePostRenderEffect,
MoveType,
RendererElement,
RendererNode
RendererNode,
ElementNamespace
} from '../renderer'
import { setTransitionHooks } from './BaseTransition'
import { ComponentRenderContext } from '../componentPublicInstance'
Expand All @@ -64,7 +65,7 @@ export interface KeepAliveContext extends ComponentRenderContext {
vnode: VNode,
container: RendererElement,
anchor: RendererNode | null,
isSVG: boolean,
namespace: ElementNamespace,
optimized: boolean
) => void
deactivate: (vnode: VNode) => void
Expand Down Expand Up @@ -125,7 +126,13 @@ const KeepAliveImpl: ComponentOptions = {
} = sharedContext
const storageContainer = createElement('div')

sharedContext.activate = (vnode, container, anchor, isSVG, optimized) => {
sharedContext.activate = (
vnode,
container,
anchor,
namespace,
optimized
) => {
const instance = vnode.component!
move(vnode, container, anchor, MoveType.ENTER, parentSuspense)
// in case props have changed
Expand All @@ -136,7 +143,7 @@ const KeepAliveImpl: ComponentOptions = {
anchor,
instance,
parentSuspense,
isSVG,
namespace,
vnode.slotScopeIds,
optimized
)
Expand Down
51 changes: 26 additions & 25 deletions packages/runtime-core/src/components/Suspense.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ import {
MoveType,
SetupRenderEffectFn,
RendererNode,
RendererElement
RendererElement,
ElementNamespace
} from '../renderer'
import { queuePostFlushCb } from '../scheduler'
import { filterSingleRoot, updateHOCHostEl } from '../componentRenderUtils'
Expand Down Expand Up @@ -63,7 +64,7 @@ export const SuspenseImpl = {
anchor: RendererNode | null,
parentComponent: ComponentInternalInstance | null,
parentSuspense: SuspenseBoundary | null,
isSVG: boolean,
namespace: ElementNamespace,
slotScopeIds: string[] | null,
optimized: boolean,
// platform-specific impl passed from renderer
Expand All @@ -76,7 +77,7 @@ export const SuspenseImpl = {
anchor,
parentComponent,
parentSuspense,
isSVG,
namespace,
slotScopeIds,
optimized,
rendererInternals
Expand All @@ -88,7 +89,7 @@ export const SuspenseImpl = {
container,
anchor,
parentComponent,
isSVG,
namespace,
slotScopeIds,
optimized,
rendererInternals
Expand Down Expand Up @@ -130,7 +131,7 @@ function mountSuspense(
anchor: RendererNode | null,
parentComponent: ComponentInternalInstance | null,
parentSuspense: SuspenseBoundary | null,
isSVG: boolean,
namespace: ElementNamespace,
slotScopeIds: string[] | null,
optimized: boolean,
rendererInternals: RendererInternals
Expand All @@ -147,7 +148,7 @@ function mountSuspense(
container,
hiddenContainer,
anchor,
isSVG,
namespace,
slotScopeIds,
optimized,
rendererInternals
Expand All @@ -161,7 +162,7 @@ function mountSuspense(
null,
parentComponent,
suspense,
isSVG,
namespace,
slotScopeIds
)
// now check if we have encountered any async deps
Expand All @@ -179,7 +180,7 @@ function mountSuspense(
anchor,
parentComponent,
null, // fallback tree will not have suspense context
isSVG,
namespace,
slotScopeIds
)
setActiveBranch(suspense, vnode.ssFallback!)
Expand All @@ -195,7 +196,7 @@ function patchSuspense(
container: RendererElement,
anchor: RendererNode | null,
parentComponent: ComponentInternalInstance | null,
isSVG: boolean,
namespace: ElementNamespace,
slotScopeIds: string[] | null,
optimized: boolean,
{ p: patch, um: unmount, o: { createElement } }: RendererInternals
Expand All @@ -218,7 +219,7 @@ function patchSuspense(
null,
parentComponent,
suspense,
isSVG,
namespace,
slotScopeIds,
optimized
)
Expand All @@ -232,7 +233,7 @@ function patchSuspense(
anchor,
parentComponent,
null, // fallback tree will not have suspense context
isSVG,
namespace,
slotScopeIds,
optimized
)
Expand Down Expand Up @@ -267,7 +268,7 @@ function patchSuspense(
null,
parentComponent,
suspense,
isSVG,
namespace,
slotScopeIds,
optimized
)
Expand All @@ -281,7 +282,7 @@ function patchSuspense(
anchor,
parentComponent,
null, // fallback tree will not have suspense context
isSVG,
namespace,
slotScopeIds,
optimized
)
Expand All @@ -296,7 +297,7 @@ function patchSuspense(
anchor,
parentComponent,
suspense,
isSVG,
namespace,
slotScopeIds,
optimized
)
Expand All @@ -311,7 +312,7 @@ function patchSuspense(
null,
parentComponent,
suspense,
isSVG,
namespace,
slotScopeIds,
optimized
)
Expand All @@ -330,7 +331,7 @@ function patchSuspense(
anchor,
parentComponent,
suspense,
isSVG,
namespace,
slotScopeIds,
optimized
)
Expand All @@ -349,7 +350,7 @@ function patchSuspense(
null,
parentComponent,
suspense,
isSVG,
namespace,
slotScopeIds,
optimized
)
Expand All @@ -376,7 +377,7 @@ export interface SuspenseBoundary {
vnode: VNode<RendererNode, RendererElement, SuspenseProps>
parent: SuspenseBoundary | null
parentComponent: ComponentInternalInstance | null
isSVG: boolean
namespace: ElementNamespace
container: RendererElement
hiddenContainer: RendererElement
anchor: RendererNode | null
Expand Down Expand Up @@ -413,7 +414,7 @@ function createSuspenseBoundary(
container: RendererElement,
hiddenContainer: RendererElement,
anchor: RendererNode | null,
isSVG: boolean,
namespace: ElementNamespace,
slotScopeIds: string[] | null,
optimized: boolean,
rendererInternals: RendererInternals,
Expand Down Expand Up @@ -455,7 +456,7 @@ function createSuspenseBoundary(
vnode,
parent: parentSuspense,
parentComponent,
isSVG,
namespace,
container,
hiddenContainer,
anchor,
Expand Down Expand Up @@ -576,7 +577,7 @@ function createSuspenseBoundary(
return
}

const { vnode, activeBranch, parentComponent, container, isSVG } =
const { vnode, activeBranch, parentComponent, container, namespace } =
suspense

// invoke @fallback event
Expand All @@ -594,7 +595,7 @@ function createSuspenseBoundary(
next(activeBranch!),
parentComponent,
null, // fallback tree will not have suspense context
isSVG,
namespace,
slotScopeIds,
optimized
)
Expand Down Expand Up @@ -675,7 +676,7 @@ function createSuspenseBoundary(
// consider the comment placeholder case.
hydratedEl ? null : next(instance.subTree),
suspense,
isSVG,
namespace,
optimized
)
if (placeholder) {
Expand Down Expand Up @@ -721,7 +722,7 @@ function hydrateSuspense(
vnode: VNode,
parentComponent: ComponentInternalInstance | null,
parentSuspense: SuspenseBoundary | null,
isSVG: boolean,
namespace: ElementNamespace,
slotScopeIds: string[] | null,
optimized: boolean,
rendererInternals: RendererInternals,
Expand All @@ -742,7 +743,7 @@ function hydrateSuspense(
node.parentNode!,
document.createElement('div'),
null,
isSVG,
namespace,
slotScopeIds,
optimized,
rendererInternals,
Expand Down
Loading

0 comments on commit d42b6ba

Please sign in to comment.