refactor: rename packages
This commit is contained in:
0
packages/runtime-dom/src/components/transition.ts
Normal file
0
packages/runtime-dom/src/components/transition.ts
Normal file
20
packages/runtime-dom/src/index.ts
Normal file
20
packages/runtime-dom/src/index.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { createRenderer, VNode, Component } from '@vue/runtime-core'
|
||||
import { nodeOps } from './nodeOps'
|
||||
import { patchData } from './patchData'
|
||||
import { teardownVNode } from './teardownVNode'
|
||||
|
||||
const { render: _render } = createRenderer({
|
||||
nodeOps,
|
||||
patchData,
|
||||
teardownVNode
|
||||
})
|
||||
|
||||
type publicRender = (
|
||||
node: VNode | null,
|
||||
container: HTMLElement
|
||||
) => Component | null
|
||||
export const render = _render as publicRender
|
||||
|
||||
// re-export everything from core
|
||||
// h, Component, observer API, nextTick, flags & types
|
||||
export * from '@vue/runtime-core'
|
||||
31
packages/runtime-dom/src/modules/attrs.ts
Normal file
31
packages/runtime-dom/src/modules/attrs.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
const xlinkNS = 'http://www.w3.org/1999/xlink'
|
||||
|
||||
function isXlink(name: string): boolean {
|
||||
return name.charAt(5) === ':' && name.slice(0, 5) === 'xlink'
|
||||
}
|
||||
|
||||
function getXlinkProp(name: string): string {
|
||||
return isXlink(name) ? name.slice(6, name.length) : ''
|
||||
}
|
||||
|
||||
export function patchAttr(
|
||||
el: Element,
|
||||
key: string,
|
||||
value: any,
|
||||
isSVG: boolean
|
||||
) {
|
||||
// isSVG short-circuits isXlink check
|
||||
if (isSVG && isXlink(key)) {
|
||||
if (value == null) {
|
||||
el.removeAttributeNS(xlinkNS, getXlinkProp(key))
|
||||
} else {
|
||||
el.setAttributeNS(xlinkNS, key, value)
|
||||
}
|
||||
} else {
|
||||
if (value == null) {
|
||||
el.removeAttribute(key)
|
||||
} else {
|
||||
el.setAttribute(key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
11
packages/runtime-dom/src/modules/class.ts
Normal file
11
packages/runtime-dom/src/modules/class.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
// compiler should normlaize class + :class bindings on the same element
|
||||
// into a single binding ['staticClass', dynamic]
|
||||
|
||||
export function patchClass(el: Element, value: string, isSVG: boolean) {
|
||||
// directly setting className should be faster than setAttribute in theory
|
||||
if (isSVG) {
|
||||
el.setAttribute('class', value)
|
||||
} else {
|
||||
el.className = value
|
||||
}
|
||||
}
|
||||
142
packages/runtime-dom/src/modules/events.ts
Normal file
142
packages/runtime-dom/src/modules/events.ts
Normal file
@@ -0,0 +1,142 @@
|
||||
const delegateRE = /^(?:click|dblclick|submit|(?:key|mouse|touch).*)$/
|
||||
|
||||
type EventValue = Function | Function[]
|
||||
type TargetRef = { el: Element | Document }
|
||||
|
||||
export function patchEvent(
|
||||
el: Element,
|
||||
name: string,
|
||||
prevValue: EventValue | null,
|
||||
nextValue: EventValue | null
|
||||
) {
|
||||
if (delegateRE.test(name) && !__JSDOM__) {
|
||||
handleDelegatedEvent(el, name, nextValue)
|
||||
} else {
|
||||
handleNormalEvent(el, name, prevValue, nextValue)
|
||||
}
|
||||
}
|
||||
|
||||
const eventCounts: Record<string, number> = {}
|
||||
const attachedGlobalHandlers: Record<string, Function> = {}
|
||||
|
||||
export function handleDelegatedEvent(
|
||||
el: any,
|
||||
name: string,
|
||||
value: EventValue | null
|
||||
) {
|
||||
const count = eventCounts[name]
|
||||
let store = el.__events
|
||||
if (value) {
|
||||
if (!count) {
|
||||
attachGlobalHandler(name)
|
||||
}
|
||||
if (!store) {
|
||||
store = el.__events = {}
|
||||
}
|
||||
if (!store[name]) {
|
||||
eventCounts[name]++
|
||||
}
|
||||
store[name] = value
|
||||
} else if (store && store[name]) {
|
||||
eventCounts[name]--
|
||||
store[name] = null
|
||||
if (count === 1) {
|
||||
removeGlobalHandler(name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function attachGlobalHandler(name: string) {
|
||||
const handler = (attachedGlobalHandlers[name] = (e: Event) => {
|
||||
const { type } = e
|
||||
const isClick = type === 'click' || type === 'dblclick'
|
||||
if (isClick && (e as MouseEvent).button !== 0) {
|
||||
e.stopPropagation()
|
||||
return false
|
||||
}
|
||||
e.stopPropagation = stopPropagation
|
||||
const targetRef: TargetRef = { el: document }
|
||||
Object.defineProperty(e, 'currentTarget', {
|
||||
configurable: true,
|
||||
get() {
|
||||
return targetRef.el
|
||||
}
|
||||
})
|
||||
dispatchEvent(e, name, isClick, targetRef)
|
||||
})
|
||||
document.addEventListener(name, handler)
|
||||
eventCounts[name] = 0
|
||||
}
|
||||
|
||||
function stopPropagation() {
|
||||
this.cancelBubble = true
|
||||
if (!this.immediatePropagationStopped) {
|
||||
this.stopImmediatePropagation()
|
||||
}
|
||||
}
|
||||
|
||||
function dispatchEvent(
|
||||
e: Event,
|
||||
name: string,
|
||||
isClick: boolean,
|
||||
targetRef: TargetRef
|
||||
) {
|
||||
let el = e.target as any
|
||||
while (el != null) {
|
||||
// Don't process clicks on disabled elements
|
||||
if (isClick && el.disabled) {
|
||||
break
|
||||
}
|
||||
const store = el.__events
|
||||
if (store) {
|
||||
const value = store[name]
|
||||
if (value) {
|
||||
targetRef.el = el
|
||||
invokeEvents(e, value)
|
||||
if (e.cancelBubble) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
el = el.parentNode
|
||||
}
|
||||
}
|
||||
|
||||
function invokeEvents(e: Event, value: EventValue) {
|
||||
if (Array.isArray(value)) {
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
value[i](e)
|
||||
}
|
||||
} else {
|
||||
value(e)
|
||||
}
|
||||
}
|
||||
|
||||
function removeGlobalHandler(name: string) {
|
||||
document.removeEventListener(name, attachedGlobalHandlers[name] as any)
|
||||
eventCounts[name] = 0
|
||||
}
|
||||
|
||||
function handleNormalEvent(el: Element, name: string, prev: any, next: any) {
|
||||
const invoker = prev && prev.invoker
|
||||
if (next) {
|
||||
if (invoker) {
|
||||
prev.invoker = null
|
||||
invoker.value = next
|
||||
next.invoker = invoker
|
||||
} else {
|
||||
el.addEventListener(name, createInvoker(next))
|
||||
}
|
||||
} else if (invoker) {
|
||||
el.removeEventListener(name, invoker)
|
||||
}
|
||||
}
|
||||
|
||||
function createInvoker(value: any) {
|
||||
const invoker = ((e: Event) => {
|
||||
invokeEvents(e, invoker.value)
|
||||
}) as any
|
||||
invoker.value = value
|
||||
value.invoker = invoker
|
||||
return invoker
|
||||
}
|
||||
18
packages/runtime-dom/src/modules/props.ts
Normal file
18
packages/runtime-dom/src/modules/props.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { VNode, ChildrenFlags } from '@vue/runtime-core'
|
||||
|
||||
export function patchDOMProp(
|
||||
el: any,
|
||||
key: string,
|
||||
value: any,
|
||||
prevVNode: VNode,
|
||||
unmountChildren: any
|
||||
) {
|
||||
if (key === 'innerHTML' || key === 'textContent') {
|
||||
if (prevVNode && prevVNode.children) {
|
||||
unmountChildren(prevVNode.children, prevVNode.childFlags)
|
||||
prevVNode.children = null
|
||||
prevVNode.childFlags = ChildrenFlags.NO_CHILDREN
|
||||
}
|
||||
}
|
||||
el[key] = value
|
||||
}
|
||||
28
packages/runtime-dom/src/modules/style.ts
Normal file
28
packages/runtime-dom/src/modules/style.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { isString } from '@vue/shared'
|
||||
|
||||
// style properties that should NOT have "px" added when numeric
|
||||
const nonNumericRE = /acit|ex(?:s|g|n|p|$)|rph|ows|mnc|ntw|ine[ch]|zoo|^ord/i
|
||||
|
||||
export function patchStyle(el: any, prev: any, next: any, data: any) {
|
||||
const { style } = el
|
||||
if (!next) {
|
||||
el.removeAttribute('style')
|
||||
} else if (isString(next)) {
|
||||
style.cssText = next
|
||||
} else {
|
||||
for (const key in next) {
|
||||
let value = next[key]
|
||||
if (typeof value === 'number' && !nonNumericRE.test(key)) {
|
||||
value = value + 'px'
|
||||
}
|
||||
style[key] = value
|
||||
}
|
||||
if (prev && !isString(prev)) {
|
||||
for (const key in prev) {
|
||||
if (!next[key]) {
|
||||
style[key] = ''
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
35
packages/runtime-dom/src/nodeOps.ts
Normal file
35
packages/runtime-dom/src/nodeOps.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
const svgNS = 'http://www.w3.org/2000/svg'
|
||||
|
||||
export const nodeOps = {
|
||||
createElement: (tag: string, isSVG?: boolean): Element =>
|
||||
isSVG ? document.createElementNS(svgNS, tag) : document.createElement(tag),
|
||||
|
||||
createText: (text: string): Text => document.createTextNode(text),
|
||||
|
||||
setText: (node: Text, text: string) => {
|
||||
node.nodeValue = text
|
||||
},
|
||||
|
||||
appendChild: (parent: Node, child: Node) => {
|
||||
parent.appendChild(child)
|
||||
},
|
||||
|
||||
insertBefore: (parent: Node, child: Node, ref: Node) => {
|
||||
parent.insertBefore(child, ref)
|
||||
},
|
||||
|
||||
removeChild: (parent: Node, child: Node) => {
|
||||
parent.removeChild(child)
|
||||
},
|
||||
|
||||
clearContent: (node: Node) => {
|
||||
node.textContent = ''
|
||||
},
|
||||
|
||||
parentNode: (node: Node): Node | null => node.parentNode,
|
||||
|
||||
nextSibling: (node: Node): Node | null => node.nextSibling,
|
||||
|
||||
querySelector: (selector: string): Node | null =>
|
||||
document.querySelector(selector)
|
||||
}
|
||||
47
packages/runtime-dom/src/patchData.ts
Normal file
47
packages/runtime-dom/src/patchData.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { VNode } from '@vue/runtime-core'
|
||||
import { patchClass } from './modules/class'
|
||||
import { patchStyle } from './modules/style'
|
||||
import { patchAttr } from './modules/attrs'
|
||||
import { patchDOMProp } from './modules/props'
|
||||
import { patchEvent } from './modules/events'
|
||||
import { isOn } from '@vue/shared'
|
||||
|
||||
// value, checked, selected & muted
|
||||
// plus anything with upperCase letter in it are always patched as properties
|
||||
const domPropsRE = /\W|^(?:value|checked|selected|muted)$/
|
||||
|
||||
export function patchData(
|
||||
el: Element,
|
||||
key: string,
|
||||
prevValue: any,
|
||||
nextValue: any,
|
||||
prevVNode: VNode,
|
||||
nextVNode: VNode,
|
||||
isSVG: boolean,
|
||||
unmountChildren: any
|
||||
) {
|
||||
switch (key) {
|
||||
// special
|
||||
case 'class':
|
||||
patchClass(el, nextValue, isSVG)
|
||||
break
|
||||
case 'style':
|
||||
patchStyle(el, prevValue, nextValue, nextVNode.data)
|
||||
break
|
||||
default:
|
||||
if (isOn(key)) {
|
||||
patchEvent(el, key.slice(2).toLowerCase(), prevValue, nextValue)
|
||||
} else if (domPropsRE.test(key)) {
|
||||
patchDOMProp(
|
||||
el,
|
||||
key[8].toLowerCase() + key.slice(9),
|
||||
nextValue,
|
||||
prevVNode,
|
||||
unmountChildren
|
||||
)
|
||||
} else {
|
||||
patchAttr(el, key, nextValue, isSVG)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
14
packages/runtime-dom/src/teardownVNode.ts
Normal file
14
packages/runtime-dom/src/teardownVNode.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { VNode } from '@vue/runtime-core'
|
||||
import { handleDelegatedEvent } from './modules/events'
|
||||
import { isOn } from '@vue/shared'
|
||||
|
||||
export function teardownVNode(vnode: VNode) {
|
||||
const { el, data } = vnode
|
||||
if (data != null) {
|
||||
for (const key in data) {
|
||||
if (isOn(key)) {
|
||||
handleDelegatedEvent(el, key.slice(2).toLowerCase(), null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user