omiax
* Hook & Fun style * Remove core of omi * Update demos
This commit is contained in:
parent
a54b093788
commit
b482731dda
|
@ -0,0 +1,35 @@
|
|||
//逻辑store外置,UI只负责渲染
|
||||
const Counter = (props, store) => {
|
||||
return <div>
|
||||
<button onClick={store.sub}>sub</button>
|
||||
<text>{store.data.count}</text>
|
||||
<button onClick={store.add}>add</button>
|
||||
</div>
|
||||
}
|
||||
|
||||
Counter.store = _ => {
|
||||
return {
|
||||
data: {
|
||||
count: 1
|
||||
},
|
||||
add() {
|
||||
this.data.count++
|
||||
},
|
||||
sub() {
|
||||
this.data.count--
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const App = (props, store) => {
|
||||
return <div>
|
||||
<Counter></Counter>
|
||||
</div>
|
||||
}
|
||||
|
||||
App.store = _ => {
|
||||
|
||||
}
|
||||
|
||||
render(<App />)
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
|
@ -1,23 +1,31 @@
|
|||
import layoutNode from '../../src/layout/layout-node'
|
||||
import '../../src/index'
|
||||
import { render } from '../../src/index'
|
||||
|
||||
var size = getSize();
|
||||
const size = getSize();
|
||||
|
||||
const vnode = <surface top={0} left={0} width={size.width} height={size.height} enableCSSLayout={true}>
|
||||
<group style={getPageStyle()}>
|
||||
<text style={getTitleStyle()}>
|
||||
Professor PuddinPop
|
||||
//全局 store或者局部 store,data全放这里,组件没有私有 data,只可以有 props
|
||||
const store = {
|
||||
|
||||
}
|
||||
|
||||
//UI is UI,没有 data
|
||||
const App = (props, store) => {
|
||||
return <surface top={0} left={0} width={size.width} height={size.height} enableCSSLayout={true}>
|
||||
<group style={getPageStyle()}>
|
||||
<text style={getTitleStyle()}>
|
||||
Professor PuddinPop
|
||||
</text>
|
||||
<group style={getImageGroupStyle()}>
|
||||
<image src='https://placekitten.com/720/840' style={getImageStyle()} fadeIn={true} />
|
||||
</group>
|
||||
<text style={getExcerptStyle()}>
|
||||
With these words the Witch fell down in a brown, melted, shapeless mass and began to spread over the clean boards of the kitchen floor. Seeing that she had really melted away to nothing, Dorothy drew another bucket of water and threw it over the mess. She then swept it all out the door. After picking out the silver shoe, which was all that was left of the old woman, she cleaned and dried it with a cloth, and put it on her foot again. Then, being at last free to do as she chose, she ran out to the courtyard to tell the Lion that the Wicked Witch of the West had come to an end, and that they were no longer prisoners in a strange land.
|
||||
</text>
|
||||
<group style={getImageGroupStyle()}>
|
||||
<image src='https://placekitten.com/720/840' style={getImageStyle()} fadeIn={true} />
|
||||
</group>
|
||||
<text style={getExcerptStyle()}>
|
||||
With these words the Witch fell down in a brown, melted, shapeless mass and began to spread over the clean boards of the kitchen floor. Seeing that she had really melted away to nothing, Dorothy drew another bucket of water and threw it over the mess. She then swept it all out the door. After picking out the silver shoe, which was all that was left of the old woman, she cleaned and dried it with a cloth, and put it on her foot again. Then, being at last free to do as she chose, she ran out to the courtyard to tell the Lion that the Wicked Witch of the West had come to an end, and that they were no longer prisoners in a strange land.
|
||||
</text>
|
||||
</group>
|
||||
</surface>
|
||||
</surface>
|
||||
}
|
||||
|
||||
console.log(layoutNode(vnode))
|
||||
//渲染并注入 store
|
||||
console.log(render(App, store))
|
||||
|
||||
function getSize() {
|
||||
return {
|
||||
|
@ -83,4 +91,4 @@ function getExcerptStyle() {
|
|||
|
||||
function FontFace() {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
|
@ -1,10 +0,0 @@
|
|||
<html>
|
||||
|
||||
<head></head>
|
||||
|
||||
<body>
|
||||
|
||||
<script src="b.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -1,29 +0,0 @@
|
|||
import { define, WeElement, render } from '../../src/index'
|
||||
|
||||
define('my-counter', class extends WeElement {
|
||||
count = 1
|
||||
|
||||
sub = () => {
|
||||
this.count--
|
||||
this.update()
|
||||
}
|
||||
|
||||
add = () => {
|
||||
this.count++
|
||||
this.update()
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<button onClick={this.sub}>-</button>
|
||||
<span style={{
|
||||
color: 'red'
|
||||
}}>{this.count}</span>
|
||||
<button onClick={this.add}>+</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
render(<my-counter />, 'body')
|
|
@ -1,5 +1,32 @@
|
|||
import { define, WeElement, tag, render} from './omi/omi.js'
|
||||
import { render } from './render'
|
||||
import { h } from './h'
|
||||
|
||||
const root = getGlobal()
|
||||
|
||||
|
||||
root.Omi = { h, version: '0.0.0' }
|
||||
|
||||
function getGlobal() {
|
||||
if (
|
||||
typeof global !== 'object' ||
|
||||
!global ||
|
||||
global.Math !== Math ||
|
||||
global.Array !== Array
|
||||
) {
|
||||
if (typeof self !== 'undefined') {
|
||||
return self
|
||||
} else if (typeof window !== 'undefined') {
|
||||
return window
|
||||
} else if (typeof global !== 'undefined') {
|
||||
return global
|
||||
}
|
||||
return (function () {
|
||||
return this
|
||||
})()
|
||||
}
|
||||
return global
|
||||
}
|
||||
|
||||
export {
|
||||
define, WeElement, tag, render
|
||||
}
|
||||
render
|
||||
}
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
/**
|
||||
* classNames based on https://github.com/JedWatson/classnames
|
||||
* by Jed Watson
|
||||
* Licensed under the MIT License
|
||||
* https://github.com/JedWatson/classnames/blob/master/LICENSE
|
||||
* modified by dntzhang
|
||||
*/
|
||||
|
||||
var hasOwn = {}.hasOwnProperty
|
||||
|
||||
export function classNames() {
|
||||
var classes = []
|
||||
|
||||
for (var i = 0; i < arguments.length; i++) {
|
||||
var arg = arguments[i]
|
||||
if (!arg) continue
|
||||
|
||||
var argType = typeof arg
|
||||
|
||||
if (argType === 'string' || argType === 'number') {
|
||||
classes.push(arg)
|
||||
} else if (Array.isArray(arg) && arg.length) {
|
||||
var inner = classNames.apply(null, arg)
|
||||
if (inner) {
|
||||
classes.push(inner)
|
||||
}
|
||||
} else if (argType === 'object') {
|
||||
for (var key in arg) {
|
||||
if (hasOwn.call(arg, key) && arg[key]) {
|
||||
classes.push(key)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return classes.join(' ')
|
||||
}
|
||||
|
||||
export function extractClass() {
|
||||
const [props, ...args] = Array.prototype.slice.call(arguments, 0)
|
||||
if (props) {
|
||||
if (props['class']) {
|
||||
args.unshift(props['class'])
|
||||
delete props['class']
|
||||
} else if (props.className) {
|
||||
args.unshift(props.className)
|
||||
delete props.className
|
||||
}
|
||||
}
|
||||
if (args.length > 0) {
|
||||
return { 'class': classNames.apply(null, args) }
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
import { extend } from './util'
|
||||
import { h } from './h'
|
||||
|
||||
/**
|
||||
* Clones the given VNode, optionally adding attributes/props and replacing its children.
|
||||
* @param {VNode} vnode The virtual DOM element to clone
|
||||
* @param {Object} props Attributes/props to add when cloning
|
||||
* @param {VNode} rest Any additional arguments will be used as replacement children.
|
||||
*/
|
||||
export function cloneElement(vnode, props) {
|
||||
return h(
|
||||
vnode.nodeName,
|
||||
extend(extend({}, vnode.attributes), props),
|
||||
arguments.length > 2 ? [].slice.call(arguments, 2) : vnode.children
|
||||
)
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
import { FORCE_RENDER } from './constants'
|
||||
import { renderComponent } from './vdom/component'
|
||||
import options from './options'
|
||||
import { nProps, assign } from './util'
|
||||
|
||||
let id = 0
|
||||
|
||||
export default class Component {
|
||||
static is = 'WeElement'
|
||||
|
||||
constructor(props, store) {
|
||||
this.props = assign(
|
||||
nProps(this.constructor.props),
|
||||
this.constructor.defaultProps,
|
||||
props
|
||||
)
|
||||
this.elementId = id++
|
||||
this.data = this.constructor.data || this.data || {}
|
||||
|
||||
this._preCss = null
|
||||
|
||||
this.store = store
|
||||
}
|
||||
|
||||
update(callback) {
|
||||
this._willUpdate = true
|
||||
if (callback)
|
||||
(this._renderCallbacks = this._renderCallbacks || []).push(callback)
|
||||
renderComponent(this, FORCE_RENDER)
|
||||
if (options.componentChange) options.componentChange(this, this.base)
|
||||
this._willUpdate = false
|
||||
}
|
||||
|
||||
fire(type, data) {
|
||||
Object.keys(this.props).every(key => {
|
||||
if ('on' + type.toLowerCase() === key.toLowerCase()) {
|
||||
this.props[key]({ detail: data })
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
render() {}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
// render modes
|
||||
|
||||
export const NO_RENDER = 0
|
||||
export const SYNC_RENDER = 1
|
||||
export const FORCE_RENDER = 2
|
||||
export const ASYNC_RENDER = 3
|
||||
|
||||
export const ATTR_KEY = '__omiattr_'
|
||||
|
||||
// DOM properties that should NOT have "px" added when numeric
|
||||
export const IS_NON_DIMENSIONAL = /acit|ex(?:s|g|n|p|$)|rph|ows|mnc|ntw|ine[ch]|zoo|^ord/i
|
|
@ -1,82 +0,0 @@
|
|||
import options from './options'
|
||||
|
||||
const OBJECTTYPE = '[object Object]'
|
||||
const ARRAYTYPE = '[object Array]'
|
||||
|
||||
export function define(name, ctor) {
|
||||
options.mapping[name] = ctor
|
||||
if (ctor.use) {
|
||||
ctor.updatePath = getPath(ctor.use)
|
||||
} else if (ctor.data) { //Compatible with older versions
|
||||
ctor.updatePath = getUpdatePath(ctor.data)
|
||||
}
|
||||
}
|
||||
|
||||
export function getPath(obj) {
|
||||
if (Object.prototype.toString.call(obj) === '[object Array]') {
|
||||
const result = {}
|
||||
obj.forEach(item => {
|
||||
if (typeof item === 'string') {
|
||||
result[item] = true
|
||||
} else {
|
||||
const tempPath = item[Object.keys(item)[0]]
|
||||
if (typeof tempPath === 'string') {
|
||||
result[tempPath] = true
|
||||
} else {
|
||||
if(typeof tempPath[0] === 'string'){
|
||||
result[tempPath[0]] = true
|
||||
}else{
|
||||
tempPath[0].forEach(path => result[path] = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
return result
|
||||
} else {
|
||||
return getUpdatePath(obj)
|
||||
}
|
||||
}
|
||||
|
||||
export function getUpdatePath(data) {
|
||||
const result = {}
|
||||
dataToPath(data, result)
|
||||
return result
|
||||
}
|
||||
|
||||
function dataToPath(data, result) {
|
||||
Object.keys(data).forEach(key => {
|
||||
result[key] = true
|
||||
const type = Object.prototype.toString.call(data[key])
|
||||
if (type === OBJECTTYPE) {
|
||||
_objToPath(data[key], key, result)
|
||||
} else if (type === ARRAYTYPE) {
|
||||
_arrayToPath(data[key], key, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function _objToPath(data, path, result) {
|
||||
Object.keys(data).forEach(key => {
|
||||
result[path + '.' + key] = true
|
||||
delete result[path]
|
||||
const type = Object.prototype.toString.call(data[key])
|
||||
if (type === OBJECTTYPE) {
|
||||
_objToPath(data[key], path + '.' + key, result)
|
||||
} else if (type === ARRAYTYPE) {
|
||||
_arrayToPath(data[key], path + '.' + key, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function _arrayToPath(data, path, result) {
|
||||
data.forEach((item, index) => {
|
||||
result[path + '[' + index + ']'] = true
|
||||
delete result[path]
|
||||
const type = Object.prototype.toString.call(item)
|
||||
if (type === OBJECTTYPE) {
|
||||
_objToPath(item, path + '[' + index + ']', result)
|
||||
} else if (type === ARRAYTYPE) {
|
||||
_arrayToPath(item, path + '[' + index + ']', result)
|
||||
}
|
||||
})
|
||||
}
|
|
@ -1,183 +0,0 @@
|
|||
import { IS_NON_DIMENSIONAL } from '../constants'
|
||||
import { applyRef } from '../util'
|
||||
import options from '../options'
|
||||
|
||||
/** Create an element with the given nodeName.
|
||||
* @param {String} nodeName
|
||||
* @param {Boolean} [isSvg=false] If `true`, creates an element within the SVG namespace.
|
||||
* @returns {Element} node
|
||||
*/
|
||||
export function createNode(nodeName, isSvg) {
|
||||
let node = isSvg
|
||||
? options.doc.createElementNS('http://www.w3.org/2000/svg', nodeName)
|
||||
: options.doc.createElement(nodeName)
|
||||
node.normalizedNodeName = nodeName
|
||||
return node
|
||||
}
|
||||
|
||||
function parseCSSText(cssText) {
|
||||
let cssTxt = cssText.replace(/\/\*(.|\s)*?\*\//g, ' ').replace(/\s+/g, ' ')
|
||||
let style = {},
|
||||
[a, b, rule] = cssTxt.match(/ ?(.*?) ?{([^}]*)}/) || [a, b, cssTxt]
|
||||
let cssToJs = s => s.replace(/\W+\w/g, match => match.slice(-1).toUpperCase())
|
||||
let properties = rule
|
||||
.split(';')
|
||||
.map(o => o.split(':').map(x => x && x.trim()))
|
||||
for (let [property, value] of properties) style[cssToJs(property)] = value
|
||||
return style
|
||||
}
|
||||
|
||||
/** Remove a child node from its parent if attached.
|
||||
* @param {Element} node The node to remove
|
||||
*/
|
||||
export function removeNode(node) {
|
||||
let parentNode = node.parentNode
|
||||
if (parentNode) parentNode.removeChild(node)
|
||||
}
|
||||
|
||||
/** Set a named attribute on the given Node, with special behavior for some names and event handlers.
|
||||
* If `value` is `null`, the attribute/handler will be removed.
|
||||
* @param {Element} node An element to mutate
|
||||
* @param {string} name The name/key to set, such as an event or attribute name
|
||||
* @param {any} old The last value that was set for this name/node pair
|
||||
* @param {any} value An attribute value, such as a function to be used as an event handler
|
||||
* @param {Boolean} isSvg Are we currently diffing inside an svg?
|
||||
* @private
|
||||
*/
|
||||
export function setAccessor(node, name, old, value, isSvg) {
|
||||
if (name === 'className') name = 'class'
|
||||
|
||||
if (name === 'key') {
|
||||
// ignore
|
||||
} else if (name === 'ref') {
|
||||
applyRef(old, null)
|
||||
applyRef(value, node)
|
||||
} else if (name === 'class' && !isSvg) {
|
||||
node.className = value || ''
|
||||
} else if (name === 'style') {
|
||||
if (options.isWeb) {
|
||||
if (!value || typeof value === 'string' || typeof old === 'string') {
|
||||
node.style.cssText = value || ''
|
||||
}
|
||||
if (value && typeof value === 'object') {
|
||||
if (typeof old !== 'string') {
|
||||
for (let i in old) if (!(i in value)) node.style[i] = ''
|
||||
}
|
||||
for (let i in value) {
|
||||
node.style[i] =
|
||||
typeof value[i] === 'number' && IS_NON_DIMENSIONAL.test(i) === false
|
||||
? value[i] + 'px'
|
||||
: value[i]
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let oldJson = old,
|
||||
currentJson = value
|
||||
if (typeof old === 'string') {
|
||||
oldJson = parseCSSText(old)
|
||||
}
|
||||
if (typeof value == 'string') {
|
||||
currentJson = parseCSSText(value)
|
||||
}
|
||||
|
||||
let result = {},
|
||||
changed = false
|
||||
|
||||
if (oldJson) {
|
||||
for (let key in oldJson) {
|
||||
if (typeof currentJson == 'object' && !(key in currentJson)) {
|
||||
result[key] = ''
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
|
||||
for (let ckey in currentJson) {
|
||||
if (currentJson[ckey] !== oldJson[ckey]) {
|
||||
result[ckey] = currentJson[ckey]
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
node.setStyles(result)
|
||||
}
|
||||
} else {
|
||||
node.setStyles(currentJson)
|
||||
}
|
||||
}
|
||||
} else if (name === 'dangerouslySetInnerHTML') {
|
||||
if (value) node.innerHTML = value.__html || ''
|
||||
} else if (name[0] == 'o' && name[1] == 'n') {
|
||||
let useCapture = name !== (name = name.replace(/Capture$/, ''))
|
||||
name = name.toLowerCase().substring(2)
|
||||
if (value) {
|
||||
if (!old) {
|
||||
node.addEventListener(name, eventProxy, useCapture)
|
||||
if (name == 'tap') {
|
||||
node.addEventListener('touchstart', touchStart, useCapture)
|
||||
node.addEventListener('touchend', touchEnd, useCapture)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
node.removeEventListener(name, eventProxy, useCapture)
|
||||
if (name == 'tap') {
|
||||
node.removeEventListener('touchstart', touchStart, useCapture)
|
||||
node.removeEventListener('touchend', touchEnd, useCapture)
|
||||
}
|
||||
}
|
||||
;(node._listeners || (node._listeners = {}))[name] = value
|
||||
} else if (name !== 'list' && name !== 'type' && !isSvg && name in node) {
|
||||
setProperty(node, name, value == null ? '' : value)
|
||||
if (value == null || value === false) node.removeAttribute(name)
|
||||
} else {
|
||||
let ns = isSvg && name !== (name = name.replace(/^xlink:?/, ''))
|
||||
if (value == null || value === false) {
|
||||
if (ns)
|
||||
node.removeAttributeNS(
|
||||
'http://www.w3.org/1999/xlink',
|
||||
name.toLowerCase()
|
||||
)
|
||||
else node.removeAttribute(name)
|
||||
} else if (typeof value !== 'function') {
|
||||
if (ns)
|
||||
node.setAttributeNS(
|
||||
'http://www.w3.org/1999/xlink',
|
||||
name.toLowerCase(),
|
||||
value
|
||||
)
|
||||
else node.setAttribute(name, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Attempt to set a DOM property to the given value.
|
||||
* IE & FF throw for certain property-value combinations.
|
||||
*/
|
||||
function setProperty(node, name, value) {
|
||||
try {
|
||||
node[name] = value
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
/** Proxy an event to hooked event handlers
|
||||
* @private
|
||||
*/
|
||||
function eventProxy(e) {
|
||||
return this._listeners[e.type]((options.event && options.event(e)) || e)
|
||||
}
|
||||
|
||||
function touchStart(e) {
|
||||
this.___touchX = e.touches[0].pageX
|
||||
this.___touchY = e.touches[0].pageY
|
||||
this.___scrollTop = document.body.scrollTop
|
||||
}
|
||||
|
||||
function touchEnd(e) {
|
||||
if (
|
||||
Math.abs(e.changedTouches[0].pageX - this.___touchX) < 30 &&
|
||||
Math.abs(e.changedTouches[0].pageY - this.___touchY) < 30 &&
|
||||
Math.abs(document.body.scrollTop - this.___scrollTop) < 30
|
||||
) {
|
||||
this.dispatchEvent(new CustomEvent('tap', { detail: e }))
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
export function getHost(component) {
|
||||
let base = component.base
|
||||
if (base) {
|
||||
while (base.parentNode) {
|
||||
if (base.parentNode._component) {
|
||||
return base.parentNode._component
|
||||
} else {
|
||||
base = base.parentNode
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
## document.js
|
||||
|
||||
Implement this web document for client rendering, send instructions to the client through it.
|
||||
|
||||
## element.js
|
||||
|
||||
Implement this web element for client rendering. It has the same API as dom elment.
|
|
@ -1,59 +0,0 @@
|
|||
import Element from './element'
|
||||
import TextNode from './text-node'
|
||||
import { addDoc, removeDoc } from './util'
|
||||
|
||||
|
||||
export default class Document {
|
||||
constructor(id) {
|
||||
this.id = id
|
||||
addDoc(id, this)
|
||||
this.nodeMap = {}
|
||||
this._isMockDocument = true
|
||||
}
|
||||
|
||||
// createBody(type, props) {
|
||||
// if (!this.body) {
|
||||
// const el = new Element(type, props)
|
||||
// el.didMount = true
|
||||
// el.ownerDocument = this
|
||||
// el.docId = this.id
|
||||
// el.style.alignItems = 'flex-start'
|
||||
// this.body = el
|
||||
// }
|
||||
|
||||
// return this.body
|
||||
// }
|
||||
|
||||
createElement(tagName, props) {
|
||||
let el = new Element(tagName, props)
|
||||
el.ownerDocument = this
|
||||
el.docId = this.id
|
||||
return el
|
||||
}
|
||||
|
||||
createTextNode(txt){
|
||||
const node = new TextNode(txt)
|
||||
node.docId = this.id
|
||||
return node
|
||||
}
|
||||
|
||||
destroy() {
|
||||
delete this.listener
|
||||
delete this.nodeMap
|
||||
removeDoc(this.id)
|
||||
}
|
||||
|
||||
addEventListener(ref, type) {
|
||||
//document.addEvent(this.id, ref, type)
|
||||
}
|
||||
|
||||
removeEventListener(ref, type) {
|
||||
//document.removeEvent(this.id, ref, type)
|
||||
}
|
||||
|
||||
|
||||
scrollTo(ref, x, y, animated) {
|
||||
document.scrollTo(this.id, ref, x, y, animated)
|
||||
}
|
||||
|
||||
}
|
|
@ -1,274 +0,0 @@
|
|||
import {
|
||||
getDoc,
|
||||
uniqueId,
|
||||
linkParent,
|
||||
insertIndex,
|
||||
moveIndex,
|
||||
removeIndex
|
||||
} from './util'
|
||||
|
||||
const displayMap = {
|
||||
div: 'block',
|
||||
span: 'inline-block'
|
||||
}
|
||||
|
||||
function registerNode(docId, node) {
|
||||
const doc = getDoc(docId)
|
||||
doc.nodeMap[node.nodeId] = node
|
||||
}
|
||||
|
||||
export default class Element {
|
||||
constructor(type) {
|
||||
this.nodeType = 1
|
||||
this.nodeId = uniqueId()
|
||||
this.ref = this.nodeId
|
||||
this.type = type
|
||||
this.attributes = {}
|
||||
this.style = {
|
||||
display: displayMap[type]
|
||||
}
|
||||
this.classStyle = {}
|
||||
this.event = {}
|
||||
this.childNodes = []
|
||||
|
||||
this.nodeName = this.type
|
||||
|
||||
this.parentNode = null
|
||||
this.nextSibling = null
|
||||
this.previousSibling = null
|
||||
this.firstChild = null
|
||||
}
|
||||
|
||||
appendChild(node) {
|
||||
if (!node.parentNode) {
|
||||
linkParent(node, this)
|
||||
insertIndex(node, this.childNodes, this.childNodes.length, true)
|
||||
|
||||
if (this.docId != undefined) {
|
||||
registerNode(this.docId, node)
|
||||
}
|
||||
|
||||
|
||||
//this.ownerDocument.addElement(this.ref, node.toJSON(), -1)
|
||||
|
||||
} else {
|
||||
node.parentNode.removeChild(node)
|
||||
|
||||
this.appendChild(node)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
this.firstChild = this.childNodes[0]
|
||||
|
||||
|
||||
}
|
||||
|
||||
insertBefore(node, before) {
|
||||
if (!node.parentNode) {
|
||||
linkParent(node, this)
|
||||
const index = insertIndex(
|
||||
node,
|
||||
this.childNodes,
|
||||
this.childNodes.indexOf(before),
|
||||
true
|
||||
)
|
||||
if (this.docId != undefined) {
|
||||
registerNode(this.docId, node)
|
||||
}
|
||||
|
||||
|
||||
//this.ownerDocument.addElement(this.ref, node.toJSON(), index)
|
||||
|
||||
} else {
|
||||
node.parentNode.removeChild(node)
|
||||
this.insertBefore(node, before)
|
||||
return
|
||||
}
|
||||
|
||||
this.firstChild = this.childNodes[0]
|
||||
}
|
||||
|
||||
insertAfter(node, after) {
|
||||
if (node.parentNode && node.parentNode !== this) {
|
||||
return
|
||||
}
|
||||
if (
|
||||
node === after ||
|
||||
(node.previousSibling && node.previousSibling === after)
|
||||
) {
|
||||
return
|
||||
}
|
||||
if (!node.parentNode) {
|
||||
linkParent(node, this)
|
||||
const index = insertIndex(
|
||||
node,
|
||||
this.childNodes,
|
||||
this.childNodes.indexOf(after) + 1,
|
||||
true
|
||||
)
|
||||
|
||||
if (this.docId != undefined) {
|
||||
registerNode(this.docId, node)
|
||||
}
|
||||
|
||||
//this.ownerDocument.addElement(this.ref, node.toJSON(), index)
|
||||
|
||||
} else {
|
||||
const index = moveIndex(
|
||||
node,
|
||||
this.childNodes,
|
||||
this.childNodes.indexOf(after) + 1
|
||||
)
|
||||
|
||||
//this.ownerDocument.moveElement(node.ref, this.ref, index)
|
||||
|
||||
}
|
||||
|
||||
this.firstChild = this.childNodes[0]
|
||||
}
|
||||
|
||||
removeChild(node) {
|
||||
if (node.parentNode) {
|
||||
removeIndex(node, this.childNodes, true)
|
||||
|
||||
|
||||
this.ownerDocument.removeElement(node.ref)
|
||||
|
||||
}
|
||||
|
||||
node.parentNode = null
|
||||
|
||||
|
||||
|
||||
this.firstChild = this.childNodes[0]
|
||||
}
|
||||
|
||||
setAttribute(key, value, silent) {
|
||||
if (this.attributes[key] === value && silent !== false) {
|
||||
return
|
||||
}
|
||||
this.attributes[key] = value
|
||||
if (!silent) {
|
||||
const result = {}
|
||||
result[key] = value
|
||||
|
||||
this.ownerDocument.setAttr(this.ref, result)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
removeAttribute(key) {
|
||||
if (this.attributes[key]) {
|
||||
delete this.attributes[key]
|
||||
}
|
||||
}
|
||||
|
||||
setStyle(key, value, silent) {
|
||||
if (this.style[key] === value && silent !== false) {
|
||||
return
|
||||
}
|
||||
this.style[key] = value
|
||||
if (!silent && this.ownerDocument) {
|
||||
const result = {}
|
||||
result[key] = value
|
||||
|
||||
this.ownerDocument.setStyles(this.ref, result)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
setStyles(styles) {
|
||||
Object.assign(this.style, styles)
|
||||
if (this.ownerDocument) {
|
||||
|
||||
this.ownerDocument.setStyles(this.ref, styles)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
setClassStyle(classStyle) {
|
||||
for (const key in this.classStyle) {
|
||||
this.classStyle[key] = ''
|
||||
}
|
||||
|
||||
Object.assign(this.classStyle, classStyle)
|
||||
|
||||
|
||||
this.ownerDocument.setStyles(this.ref, this.toStyle())
|
||||
|
||||
}
|
||||
|
||||
addEventListener(type, handler) {
|
||||
if (!this.event[type]) {
|
||||
this.event[type] = handler
|
||||
|
||||
//this.ownerDocument.addEvent(this.ref, type)
|
||||
}
|
||||
}
|
||||
|
||||
removeEventListener(type) {
|
||||
if (this.event[type]) {
|
||||
delete this.event[type]
|
||||
let doc = getDoc(this.docId)
|
||||
doc.nodeMap[this.ref] &&
|
||||
doc.nodeMap[this.ref].event &&
|
||||
doc.nodeMap[this.ref].event[type]
|
||||
? (doc.nodeMap[this.ref].event[type] = null)
|
||||
: ''
|
||||
|
||||
this.ownerDocument.removeEvent(this.ref, type)
|
||||
}
|
||||
}
|
||||
|
||||
fireEvent(type, e) {
|
||||
const handler = this.event[type]
|
||||
if (handler) {
|
||||
return handler.call(this, e)
|
||||
}
|
||||
}
|
||||
|
||||
toStyle() {
|
||||
return Object.assign({}, this.classStyle, this.style)
|
||||
}
|
||||
|
||||
getComputedStyle() { }
|
||||
|
||||
toJSON() {
|
||||
let result = {
|
||||
id: this.ref,
|
||||
type: this.type,
|
||||
docId: this.docId || -10000,
|
||||
attributes: this.attributes ? this.attributes : {}
|
||||
}
|
||||
result.attributes.style = this.toStyle()
|
||||
|
||||
const event = Object.keys(this.event)
|
||||
if (event.length) {
|
||||
result.event = event
|
||||
}
|
||||
|
||||
if (this.childNodes.length) {
|
||||
result.children = this.childNodes.map(child => child.toJSON())
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
replaceChild(newChild, oldChild) {
|
||||
this.insertBefore(newChild, oldChild)
|
||||
this.removeChild(oldChild)
|
||||
}
|
||||
|
||||
destroy() {
|
||||
const doc = getDoc(this.docId)
|
||||
|
||||
if (doc) {
|
||||
delete doc.nodeMap[this.nodeId]
|
||||
}
|
||||
|
||||
this.parentNode = null
|
||||
this.childNodes.forEach(child => {
|
||||
child.destroy()
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
import Document from './document'
|
||||
|
||||
|
||||
export default {
|
||||
document: new Document(0)
|
||||
}
|
|
@ -1,88 +0,0 @@
|
|||
import {
|
||||
getDoc,
|
||||
uniqueId
|
||||
} from './util'
|
||||
|
||||
|
||||
function registerNode(docId, node) {
|
||||
const doc = getDoc(docId)
|
||||
doc.nodeMap[node.nodeId] = node
|
||||
}
|
||||
|
||||
export default class TextNode {
|
||||
constructor(nodeValue) {
|
||||
this.nodeType = 3
|
||||
this.nodeId = uniqueId()
|
||||
this.ref = this.nodeId
|
||||
this.attributes = {}
|
||||
this.style = {
|
||||
display: 'inline'
|
||||
}
|
||||
this.classStyle = {}
|
||||
this.event = {}
|
||||
this.nodeValue = nodeValue
|
||||
this.parentNode = null
|
||||
this.nextSibling = null
|
||||
this.previousSibling = null
|
||||
this.firstChild = null
|
||||
this.type = 'text'
|
||||
}
|
||||
|
||||
setAttribute(key, value, silent) {
|
||||
if (this.attributes[key] === value && silent !== false) {
|
||||
return
|
||||
}
|
||||
this.attributes[key] = value
|
||||
if (!silent) {
|
||||
const result = {}
|
||||
result[key] = value
|
||||
|
||||
this.ownerDocument.setAttr(this.ref, result)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
removeAttribute(key) {
|
||||
if (this.attributes[key]) {
|
||||
delete this.attributes[key]
|
||||
}
|
||||
}
|
||||
|
||||
toStyle() {
|
||||
return Object.assign({}, this.classStyle, this.style)
|
||||
}
|
||||
|
||||
splitText() {
|
||||
|
||||
}
|
||||
|
||||
getComputedStyle() { }
|
||||
|
||||
toJSON() {
|
||||
let result = {
|
||||
id: this.ref,
|
||||
type: this.type,
|
||||
docId: this.docId || -10000,
|
||||
attributes: this.attributes ? this.attributes : {}
|
||||
}
|
||||
result.attributes.style = this.toStyle()
|
||||
|
||||
const event = Object.keys(this.event)
|
||||
if (event.length) {
|
||||
result.event = event
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
destroy() {
|
||||
const doc = getDoc(this.docId)
|
||||
|
||||
if (doc) {
|
||||
delete doc.nodeMap[this.nodeId]
|
||||
}
|
||||
|
||||
this.parentNode = null
|
||||
|
||||
}
|
||||
}
|
|
@ -1,138 +0,0 @@
|
|||
let nodeId = 1
|
||||
export function uniqueId() {
|
||||
return nodeId++
|
||||
}
|
||||
|
||||
let docMap = {}
|
||||
|
||||
export function addDoc(id, doc) {
|
||||
docMap[id] = doc
|
||||
}
|
||||
|
||||
export function getDoc(id) {
|
||||
return docMap[id]
|
||||
}
|
||||
|
||||
export function removeDoc(id) {
|
||||
delete docMap[id]
|
||||
}
|
||||
|
||||
let sendBridgeFlag = {}
|
||||
|
||||
export function getSendBridgeFlag() {
|
||||
return sendBridgeFlag
|
||||
}
|
||||
|
||||
export function setSendBridgeFlag(docId, flag) {
|
||||
return (sendBridgeFlag[docId] = flag)
|
||||
}
|
||||
|
||||
export function insertIndex(target, list, newIndex) {
|
||||
if (newIndex < 0) {
|
||||
newIndex = 0
|
||||
}
|
||||
const before = list[newIndex - 1]
|
||||
const after = list[newIndex]
|
||||
list.splice(newIndex, 0, target)
|
||||
|
||||
before && (before.nextSibling = target)
|
||||
target.previousSibling = before
|
||||
target.nextSibling = after
|
||||
after && (after.previousSibling = target)
|
||||
|
||||
return newIndex
|
||||
}
|
||||
|
||||
export function moveIndex(target, list, newIndex) {
|
||||
const index = list.indexOf(target)
|
||||
|
||||
if (index < 0) {
|
||||
return -1
|
||||
}
|
||||
|
||||
const before = list[index - 1]
|
||||
const after = list[index + 1]
|
||||
before && (before.nextSibling = after)
|
||||
after && (after.previousSibling = before)
|
||||
|
||||
list.splice(index, 1)
|
||||
let newIndexAfter = newIndex
|
||||
if (index <= newIndex) {
|
||||
newIndexAfter = newIndex - 1
|
||||
}
|
||||
const beforeNew = list[newIndexAfter - 1]
|
||||
const afterNew = list[newIndexAfter]
|
||||
list.splice(newIndexAfter, 0, target)
|
||||
|
||||
beforeNew && (beforeNew.nextSibling = target)
|
||||
target.previousSibling = beforeNew
|
||||
target.nextSibling = afterNew
|
||||
afterNew && (afterNew.previousSibling = target)
|
||||
|
||||
if (index === newIndexAfter) {
|
||||
return -1
|
||||
}
|
||||
return newIndex
|
||||
}
|
||||
|
||||
export function removeIndex(target, list, changeSibling) {
|
||||
const index = list.indexOf(target)
|
||||
|
||||
if (index < 0) {
|
||||
return
|
||||
}
|
||||
if (changeSibling) {
|
||||
const before = list[index - 1]
|
||||
const after = list[index + 1]
|
||||
before && (before.nextSibling = after)
|
||||
after && (after.previousSibling = before)
|
||||
}
|
||||
list.splice(index, 1)
|
||||
}
|
||||
|
||||
export function remove(target, list) {
|
||||
const index = list.indexOf(target)
|
||||
|
||||
if (index < 0) {
|
||||
return
|
||||
}
|
||||
|
||||
const before = list[index - 1]
|
||||
const after = list[index + 1]
|
||||
before && (before.nextSibling = after)
|
||||
after && (after.previousSibling = before)
|
||||
|
||||
list.splice(index, 1)
|
||||
}
|
||||
|
||||
export function linkParent(node, parent) {
|
||||
node.parentNode = parent
|
||||
if (parent.docId) {
|
||||
node.docId = parent.docId
|
||||
node.ownerDocument = parent.ownerDocument
|
||||
node.ownerDocument.nodeMap[node.nodeId] = node
|
||||
node.depth = parent.depth + 1
|
||||
}
|
||||
|
||||
node.childNodes && node.childNodes.forEach(child => {
|
||||
linkParent(child, node)
|
||||
})
|
||||
}
|
||||
|
||||
export function nextElement(node) {
|
||||
while (node) {
|
||||
if (node.nodeType === 1) {
|
||||
return node
|
||||
}
|
||||
node = node.nextSibling
|
||||
}
|
||||
}
|
||||
|
||||
export function previousElement(node) {
|
||||
while (node) {
|
||||
if (node.nodeType === 1) {
|
||||
return node
|
||||
}
|
||||
node = node.previousSibling
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
import Component from './component'
|
||||
|
||||
export default class ModelView extends Component {
|
||||
static observe = true
|
||||
|
||||
static mergeUpdate = true
|
||||
|
||||
beforeInstall() {
|
||||
this.data = this.vm.data
|
||||
}
|
||||
}
|
|
@ -1,249 +0,0 @@
|
|||
/* obaa 1.0.0
|
||||
* By dntzhang
|
||||
* Github: https://github.com/Tencent/omi
|
||||
* MIT Licensed.
|
||||
*/
|
||||
|
||||
var obaa = function(target, arr, callback) {
|
||||
var _observe = function(target, arr, callback) {
|
||||
if (!target.$observer) target.$observer = this
|
||||
var $observer = target.$observer
|
||||
var eventPropArr = []
|
||||
if (obaa.isArray(target)) {
|
||||
if (target.length === 0) {
|
||||
target.$observeProps = {}
|
||||
target.$observeProps.$observerPath = '#'
|
||||
}
|
||||
$observer.mock(target)
|
||||
}
|
||||
for (var prop in target) {
|
||||
if (target.hasOwnProperty(prop)) {
|
||||
if (callback) {
|
||||
if (obaa.isArray(arr) && obaa.isInArray(arr, prop)) {
|
||||
eventPropArr.push(prop)
|
||||
$observer.watch(target, prop)
|
||||
} else if (obaa.isString(arr) && prop == arr) {
|
||||
eventPropArr.push(prop)
|
||||
$observer.watch(target, prop)
|
||||
}
|
||||
} else {
|
||||
eventPropArr.push(prop)
|
||||
$observer.watch(target, prop)
|
||||
}
|
||||
}
|
||||
}
|
||||
$observer.target = target
|
||||
if (!$observer.propertyChangedHandler) $observer.propertyChangedHandler = []
|
||||
var propChanged = callback ? callback : arr
|
||||
$observer.propertyChangedHandler.push({
|
||||
all: !callback,
|
||||
propChanged: propChanged,
|
||||
eventPropArr: eventPropArr
|
||||
})
|
||||
}
|
||||
_observe.prototype = {
|
||||
onPropertyChanged: function(prop, value, oldValue, target, path) {
|
||||
if (value !== oldValue && this.propertyChangedHandler) {
|
||||
var rootName = obaa._getRootName(prop, path)
|
||||
for (
|
||||
var i = 0, len = this.propertyChangedHandler.length;
|
||||
i < len;
|
||||
i++
|
||||
) {
|
||||
var handler = this.propertyChangedHandler[i]
|
||||
if (
|
||||
handler.all ||
|
||||
obaa.isInArray(handler.eventPropArr, rootName) ||
|
||||
rootName.indexOf('Array-') === 0
|
||||
) {
|
||||
handler.propChanged.call(this.target, prop, value, oldValue, path)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (prop.indexOf('Array-') !== 0 && typeof value === 'object') {
|
||||
this.watch(target, prop, target.$observeProps.$observerPath)
|
||||
}
|
||||
},
|
||||
mock: function(target) {
|
||||
var self = this
|
||||
obaa.methods.forEach(function(item) {
|
||||
target[item] = function() {
|
||||
var old = Array.prototype.slice.call(this, 0)
|
||||
var result = Array.prototype[item].apply(
|
||||
this,
|
||||
Array.prototype.slice.call(arguments)
|
||||
)
|
||||
if (new RegExp('\\b' + item + '\\b').test(obaa.triggerStr)) {
|
||||
for (var cprop in this) {
|
||||
if (this.hasOwnProperty(cprop) && !obaa.isFunction(this[cprop])) {
|
||||
self.watch(this, cprop, this.$observeProps.$observerPath)
|
||||
}
|
||||
}
|
||||
//todo
|
||||
self.onPropertyChanged(
|
||||
'Array-' + item,
|
||||
this,
|
||||
old,
|
||||
this,
|
||||
this.$observeProps.$observerPath
|
||||
)
|
||||
}
|
||||
return result
|
||||
}
|
||||
target[
|
||||
'pure' + item.substring(0, 1).toUpperCase() + item.substring(1)
|
||||
] = function() {
|
||||
return Array.prototype[item].apply(
|
||||
this,
|
||||
Array.prototype.slice.call(arguments)
|
||||
)
|
||||
}
|
||||
})
|
||||
},
|
||||
watch: function(target, prop, path) {
|
||||
if (prop === '$observeProps' || prop === '$observer') return
|
||||
if (obaa.isFunction(target[prop])) return
|
||||
if (!target.$observeProps) target.$observeProps = {}
|
||||
if (path !== undefined) {
|
||||
target.$observeProps.$observerPath = path
|
||||
} else {
|
||||
target.$observeProps.$observerPath = '#'
|
||||
}
|
||||
var self = this
|
||||
var currentValue = (target.$observeProps[prop] = target[prop])
|
||||
Object.defineProperty(target, prop, {
|
||||
get: function() {
|
||||
return this.$observeProps[prop]
|
||||
},
|
||||
set: function(value) {
|
||||
var old = this.$observeProps[prop]
|
||||
this.$observeProps[prop] = value
|
||||
self.onPropertyChanged(
|
||||
prop,
|
||||
value,
|
||||
old,
|
||||
this,
|
||||
target.$observeProps.$observerPath
|
||||
)
|
||||
}
|
||||
})
|
||||
if (typeof currentValue == 'object') {
|
||||
if (obaa.isArray(currentValue)) {
|
||||
this.mock(currentValue)
|
||||
if (currentValue.length === 0) {
|
||||
if (!currentValue.$observeProps) currentValue.$observeProps = {}
|
||||
if (path !== undefined) {
|
||||
currentValue.$observeProps.$observerPath = path
|
||||
} else {
|
||||
currentValue.$observeProps.$observerPath = '#'
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var cprop in currentValue) {
|
||||
if (currentValue.hasOwnProperty(cprop)) {
|
||||
this.watch(
|
||||
currentValue,
|
||||
cprop,
|
||||
target.$observeProps.$observerPath + '-' + prop
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return new _observe(target, arr, callback)
|
||||
}
|
||||
|
||||
obaa.methods = [
|
||||
'concat',
|
||||
'copyWithin',
|
||||
'entries',
|
||||
'every',
|
||||
'fill',
|
||||
'filter',
|
||||
'find',
|
||||
'findIndex',
|
||||
'forEach',
|
||||
'includes',
|
||||
'indexOf',
|
||||
'join',
|
||||
'keys',
|
||||
'lastIndexOf',
|
||||
'map',
|
||||
'pop',
|
||||
'push',
|
||||
'reduce',
|
||||
'reduceRight',
|
||||
'reverse',
|
||||
'shift',
|
||||
'slice',
|
||||
'some',
|
||||
'sort',
|
||||
'splice',
|
||||
'toLocaleString',
|
||||
'toString',
|
||||
'unshift',
|
||||
'values',
|
||||
'size'
|
||||
]
|
||||
obaa.triggerStr = [
|
||||
'concat',
|
||||
'copyWithin',
|
||||
'fill',
|
||||
'pop',
|
||||
'push',
|
||||
'reverse',
|
||||
'shift',
|
||||
'sort',
|
||||
'splice',
|
||||
'unshift',
|
||||
'size'
|
||||
].join(',')
|
||||
|
||||
obaa.isArray = function(obj) {
|
||||
return Object.prototype.toString.call(obj) === '[object Array]'
|
||||
}
|
||||
|
||||
obaa.isString = function(obj) {
|
||||
return typeof obj === 'string'
|
||||
}
|
||||
|
||||
obaa.isInArray = function(arr, item) {
|
||||
for (var i = arr.length; --i > -1; ) {
|
||||
if (item === arr[i]) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
obaa.isFunction = function(obj) {
|
||||
return Object.prototype.toString.call(obj) == '[object Function]'
|
||||
}
|
||||
|
||||
obaa._getRootName = function(prop, path) {
|
||||
if (path === '#') {
|
||||
return prop
|
||||
}
|
||||
return path.split('-')[1]
|
||||
}
|
||||
|
||||
obaa.add = function(obj, prop) {
|
||||
var $observer = obj.$observer
|
||||
$observer.watch(obj, prop)
|
||||
}
|
||||
|
||||
obaa.set = function(obj, prop, value, exec) {
|
||||
if (!exec) {
|
||||
obj[prop] = value
|
||||
}
|
||||
var $observer = obj.$observer
|
||||
$observer.watch(obj, prop)
|
||||
if (exec) {
|
||||
obj[prop] = value
|
||||
}
|
||||
}
|
||||
|
||||
Array.prototype.size = function(length) {
|
||||
this.length = length
|
||||
}
|
||||
|
||||
export default obaa
|
|
@ -1,22 +0,0 @@
|
|||
import obaa from './obaa'
|
||||
import { fireTick } from './tick'
|
||||
|
||||
export function proxyUpdate(ele) {
|
||||
let timeout = null
|
||||
obaa(ele.data, () => {
|
||||
if (ele._willUpdate) {
|
||||
return
|
||||
}
|
||||
if (ele.constructor.mergeUpdate) {
|
||||
clearTimeout(timeout)
|
||||
|
||||
timeout = setTimeout(() => {
|
||||
ele.update()
|
||||
fireTick()
|
||||
}, 0)
|
||||
} else {
|
||||
ele.update()
|
||||
fireTick()
|
||||
}
|
||||
})
|
||||
}
|
|
@ -1,978 +0,0 @@
|
|||
export = Omi;
|
||||
export as namespace Omi;
|
||||
|
||||
declare namespace Omi {
|
||||
type Callback = (...args: any[]) => void;
|
||||
type Key = string | number;
|
||||
type Ref<T> = (instance: T) => void;
|
||||
type ComponentChild = VNode<any> | object | string | number | boolean | null;
|
||||
type ComponentChildren = ComponentChild[] | ComponentChild;
|
||||
|
||||
interface Attributes {
|
||||
key?: string | number | any;
|
||||
}
|
||||
|
||||
interface ClassAttributes<T> extends Attributes {
|
||||
ref?: Ref<T>;
|
||||
}
|
||||
|
||||
interface OmiDOMAttributes {
|
||||
children?: ComponentChildren;
|
||||
dangerouslySetInnerHTML?: {
|
||||
__html: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this to manually set the attributes of a custom element
|
||||
*
|
||||
* declare global {
|
||||
* namespace JSX {
|
||||
* interface IntrinsicElements {
|
||||
* 'hello-element': CustomElementBaseAttributes & {
|
||||
* propFromParent: string;
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
interface CustomElementBaseAttributes extends ClassAttributes<any>, OmiDOMAttributes {}
|
||||
|
||||
/**
|
||||
* Define the contract for a virtual node in omi.
|
||||
*
|
||||
* A virtual node has a name, a map of attributes, an array
|
||||
* of child {VNode}s and a key. The key is used by omi for
|
||||
* internal purposes.
|
||||
*/
|
||||
interface VNode<P = any> {
|
||||
nodeName: string;
|
||||
attributes: P;
|
||||
children: Array<VNode<any> | string>;
|
||||
key?: Key | null;
|
||||
}
|
||||
|
||||
type RenderableProps<P, RefType = any> = Readonly<
|
||||
P & Attributes & { children?: ComponentChildren; ref?: Ref<RefType> }
|
||||
>;
|
||||
|
||||
interface WeElement<P, D> {
|
||||
install?(): void;
|
||||
installed?(): void;
|
||||
uninstall?(): void;
|
||||
beforeUpdate?(): void;
|
||||
afterUpdate?(): void;
|
||||
updated?(): void;
|
||||
beforeRender?(): void;
|
||||
receiveProps?(props: RenderableProps<P>, oldProps:RenderableProps<P>): any;
|
||||
}
|
||||
|
||||
interface ModelView<P, D> {
|
||||
install?(): void;
|
||||
installed?(): void;
|
||||
uninstall?(): void;
|
||||
beforeUpdate?(): void;
|
||||
afterUpdate?(): void;
|
||||
updated?(): void;
|
||||
beforeRender?(): void;
|
||||
receiveProps?(props: RenderableProps<P>, oldProps:RenderableProps<P>): any;
|
||||
}
|
||||
|
||||
interface Component<P, D> {
|
||||
install?(): void;
|
||||
installed?(): void;
|
||||
uninstall?(): void;
|
||||
beforeUpdate?(): void;
|
||||
afterUpdate?(): void;
|
||||
updated?(): void;
|
||||
beforeRender?(): void;
|
||||
receiveProps?(props: RenderableProps<P>, oldProps:RenderableProps<P>): any;
|
||||
}
|
||||
|
||||
abstract class WeElement<P = {}, D = {}> {
|
||||
constructor();
|
||||
|
||||
// Allow static members to reference class type parameters
|
||||
// https://github.com/Microsoft/TypeScript/issues/24018
|
||||
static props: object;
|
||||
static data: object;
|
||||
static observe: boolean;
|
||||
static mergeUpdate: boolean;
|
||||
static css: string;
|
||||
|
||||
props: RenderableProps<P>;
|
||||
data: D;
|
||||
host: HTMLElement;
|
||||
|
||||
update(): void;
|
||||
fire(name: string, data?: object): void;
|
||||
css(): string;
|
||||
// Abstract methods don't infer argument types
|
||||
// https://github.com/Microsoft/TypeScript/issues/14887
|
||||
abstract render(props: RenderableProps<P>, data: D): void;
|
||||
}
|
||||
|
||||
// The class type (not instance of class)
|
||||
// https://stackoverflow.com/q/42753968/2777142
|
||||
interface WeElementConstructor {
|
||||
new(): WeElement;
|
||||
}
|
||||
|
||||
abstract class ModelView<P = {}, D = {}> {
|
||||
constructor();
|
||||
|
||||
// Allow static members to reference class type parameters
|
||||
// https://github.com/Microsoft/TypeScript/issues/24018
|
||||
static props: object;
|
||||
static data: object;
|
||||
static observe: boolean;
|
||||
static mergeUpdate: boolean;
|
||||
|
||||
props: RenderableProps<P>;
|
||||
data: D;
|
||||
host: HTMLElement;
|
||||
|
||||
update(): void;
|
||||
fire(name: string, data?: object): void;
|
||||
|
||||
// Abstract methods don't infer argument types
|
||||
// https://github.com/Microsoft/TypeScript/issues/14887
|
||||
abstract render(props: RenderableProps<P>, data: D): void;
|
||||
}
|
||||
|
||||
abstract class Component<P = {}, D = {}> {
|
||||
constructor();
|
||||
|
||||
// Allow static members to reference class type parameters
|
||||
// https://github.com/Microsoft/TypeScript/issues/24018
|
||||
static props: object;
|
||||
static data: object;
|
||||
static observe: boolean;
|
||||
static mergeUpdate: boolean;
|
||||
static css: string;
|
||||
|
||||
props: RenderableProps<P>;
|
||||
data: D;
|
||||
host: HTMLElement;
|
||||
|
||||
update(): void;
|
||||
fire(name: string, data?: object): void;
|
||||
css(): string;
|
||||
// Abstract methods don't infer argument types
|
||||
// https://github.com/Microsoft/TypeScript/issues/14887
|
||||
abstract render(props: RenderableProps<P>, data: D): void;
|
||||
}
|
||||
|
||||
function h<P>(
|
||||
node: string,
|
||||
params: Attributes & P | null,
|
||||
...children: ComponentChildren[]
|
||||
): VNode<any>;
|
||||
function h(
|
||||
node: string,
|
||||
params: JSX.HTMLAttributes & JSX.SVGAttributes & Record<string, any> | null,
|
||||
...children: ComponentChildren[]
|
||||
): VNode<any>;
|
||||
|
||||
function render(vnode: ComponentChild, parent: string | Element | Document | ShadowRoot | DocumentFragment, store?: object, empty?: boolean, merge?: string | Element | Document | ShadowRoot | DocumentFragment): void;
|
||||
|
||||
function define(name: string, ctor: WeElementConstructor): void;
|
||||
function tag(name: string, pure?: boolean): (ctor: WeElementConstructor) => void;
|
||||
function tick(callback: Callback, scope?: any): void;
|
||||
function nextTick(callback: Callback, scope?: any): void;
|
||||
function observe(target: WeElementConstructor): void;
|
||||
function getHost(element: WeElement): WeElement;
|
||||
function classNames(...args: any[]): string;
|
||||
function extractClass(...args: any[]): object;
|
||||
|
||||
var options: {
|
||||
vnode?: (vnode: VNode<any>) => void;
|
||||
event?: (event: Event) => Event;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
type Defaultize<Props, Defaults> =
|
||||
// Distribute over unions
|
||||
Props extends any
|
||||
? // Make any properties included in Default optional
|
||||
& Partial<Pick<Props, Extract<keyof Props, keyof Defaults>>>
|
||||
// Include the remaining properties from Props
|
||||
& Pick<Props, Exclude<keyof Props, keyof Defaults>>
|
||||
: never;
|
||||
|
||||
declare global {
|
||||
namespace JSX {
|
||||
interface Element extends Omi.VNode<any> {
|
||||
}
|
||||
|
||||
interface ElementClass extends Omi.WeElement<any, any> {
|
||||
}
|
||||
|
||||
interface ElementClass extends Omi.Component<any, any> {
|
||||
}
|
||||
|
||||
interface ElementAttributesProperty {
|
||||
props: any;
|
||||
}
|
||||
|
||||
interface ElementChildrenAttribute {
|
||||
children: any;
|
||||
}
|
||||
|
||||
type LibraryManagedAttributes<Component, Props> =
|
||||
Component extends { defaultProps: infer Defaults }
|
||||
? Defaultize<Props, Defaults>
|
||||
: Props;
|
||||
|
||||
interface SVGAttributes extends HTMLAttributes {
|
||||
accentHeight?: number | string;
|
||||
accumulate?: "none" | "sum";
|
||||
additive?: "replace" | "sum";
|
||||
alignmentBaseline?: "auto" | "baseline" | "before-edge" | "text-before-edge" | "middle" | "central" | "after-edge" | "text-after-edge" | "ideographic" | "alphabetic" | "hanging" | "mathematical" | "inherit";
|
||||
allowReorder?: "no" | "yes";
|
||||
alphabetic?: number | string;
|
||||
amplitude?: number | string;
|
||||
arabicForm?: "initial" | "medial" | "terminal" | "isolated";
|
||||
ascent?: number | string;
|
||||
attributeName?: string;
|
||||
attributeType?: string;
|
||||
autoReverse?: number | string;
|
||||
azimuth?: number | string;
|
||||
baseFrequency?: number | string;
|
||||
baselineShift?: number | string;
|
||||
baseProfile?: number | string;
|
||||
bbox?: number | string;
|
||||
begin?: number | string;
|
||||
bias?: number | string;
|
||||
by?: number | string;
|
||||
calcMode?: number | string;
|
||||
capHeight?: number | string;
|
||||
clip?: number | string;
|
||||
clipPath?: string;
|
||||
clipPathUnits?: number | string;
|
||||
clipRule?: number | string;
|
||||
colorInterpolation?: number | string;
|
||||
colorInterpolationFilters?: "auto" | "sRGB" | "linearRGB" | "inherit";
|
||||
colorProfile?: number | string;
|
||||
colorRendering?: number | string;
|
||||
contentScriptType?: number | string;
|
||||
contentStyleType?: number | string;
|
||||
cursor?: number | string;
|
||||
cx?: number | string;
|
||||
cy?: number | string;
|
||||
d?: string;
|
||||
decelerate?: number | string;
|
||||
descent?: number | string;
|
||||
diffuseConstant?: number | string;
|
||||
direction?: number | string;
|
||||
display?: number | string;
|
||||
divisor?: number | string;
|
||||
dominantBaseline?: number | string;
|
||||
dur?: number | string;
|
||||
dx?: number | string;
|
||||
dy?: number | string;
|
||||
edgeMode?: number | string;
|
||||
elevation?: number | string;
|
||||
enableBackground?: number | string;
|
||||
end?: number | string;
|
||||
exponent?: number | string;
|
||||
externalResourcesRequired?: number | string;
|
||||
fill?: string;
|
||||
fillOpacity?: number | string;
|
||||
fillRule?: "nonzero" | "evenodd" | "inherit";
|
||||
filter?: string;
|
||||
filterRes?: number | string;
|
||||
filterUnits?: number | string;
|
||||
floodColor?: number | string;
|
||||
floodOpacity?: number | string;
|
||||
focusable?: number | string;
|
||||
fontFamily?: string;
|
||||
fontSize?: number | string;
|
||||
fontSizeAdjust?: number | string;
|
||||
fontStretch?: number | string;
|
||||
fontStyle?: number | string;
|
||||
fontVariant?: number | string;
|
||||
fontWeight?: number | string;
|
||||
format?: number | string;
|
||||
from?: number | string;
|
||||
fx?: number | string;
|
||||
fy?: number | string;
|
||||
g1?: number | string;
|
||||
g2?: number | string;
|
||||
glyphName?: number | string;
|
||||
glyphOrientationHorizontal?: number | string;
|
||||
glyphOrientationVertical?: number | string;
|
||||
glyphRef?: number | string;
|
||||
gradientTransform?: string;
|
||||
gradientUnits?: string;
|
||||
hanging?: number | string;
|
||||
horizAdvX?: number | string;
|
||||
horizOriginX?: number | string;
|
||||
ideographic?: number | string;
|
||||
imageRendering?: number | string;
|
||||
in2?: number | string;
|
||||
in?: string;
|
||||
intercept?: number | string;
|
||||
k1?: number | string;
|
||||
k2?: number | string;
|
||||
k3?: number | string;
|
||||
k4?: number | string;
|
||||
k?: number | string;
|
||||
kernelMatrix?: number | string;
|
||||
kernelUnitLength?: number | string;
|
||||
kerning?: number | string;
|
||||
keyPoints?: number | string;
|
||||
keySplines?: number | string;
|
||||
keyTimes?: number | string;
|
||||
lengthAdjust?: number | string;
|
||||
letterSpacing?: number | string;
|
||||
lightingColor?: number | string;
|
||||
limitingConeAngle?: number | string;
|
||||
local?: number | string;
|
||||
markerEnd?: string;
|
||||
markerHeight?: number | string;
|
||||
markerMid?: string;
|
||||
markerStart?: string;
|
||||
markerUnits?: number | string;
|
||||
markerWidth?: number | string;
|
||||
mask?: string;
|
||||
maskContentUnits?: number | string;
|
||||
maskUnits?: number | string;
|
||||
mathematical?: number | string;
|
||||
mode?: number | string;
|
||||
numOctaves?: number | string;
|
||||
offset?: number | string;
|
||||
opacity?: number | string;
|
||||
operator?: number | string;
|
||||
order?: number | string;
|
||||
orient?: number | string;
|
||||
orientation?: number | string;
|
||||
origin?: number | string;
|
||||
overflow?: number | string;
|
||||
overlinePosition?: number | string;
|
||||
overlineThickness?: number | string;
|
||||
paintOrder?: number | string;
|
||||
panose1?: number | string;
|
||||
pathLength?: number | string;
|
||||
patternContentUnits?: string;
|
||||
patternTransform?: number | string;
|
||||
patternUnits?: string;
|
||||
pointerEvents?: number | string;
|
||||
points?: string;
|
||||
pointsAtX?: number | string;
|
||||
pointsAtY?: number | string;
|
||||
pointsAtZ?: number | string;
|
||||
preserveAlpha?: number | string;
|
||||
preserveAspectRatio?: string;
|
||||
primitiveUnits?: number | string;
|
||||
r?: number | string;
|
||||
radius?: number | string;
|
||||
refX?: number | string;
|
||||
refY?: number | string;
|
||||
renderingIntent?: number | string;
|
||||
repeatCount?: number | string;
|
||||
repeatDur?: number | string;
|
||||
requiredExtensions?: number | string;
|
||||
requiredFeatures?: number | string;
|
||||
restart?: number | string;
|
||||
result?: string;
|
||||
rotate?: number | string;
|
||||
rx?: number | string;
|
||||
ry?: number | string;
|
||||
scale?: number | string;
|
||||
seed?: number | string;
|
||||
shapeRendering?: number | string;
|
||||
slope?: number | string;
|
||||
spacing?: number | string;
|
||||
specularConstant?: number | string;
|
||||
specularExponent?: number | string;
|
||||
speed?: number | string;
|
||||
spreadMethod?: string;
|
||||
startOffset?: number | string;
|
||||
stdDeviation?: number | string;
|
||||
stemh?: number | string;
|
||||
stemv?: number | string;
|
||||
stitchTiles?: number | string;
|
||||
stopColor?: string;
|
||||
stopOpacity?: number | string;
|
||||
strikethroughPosition?: number | string;
|
||||
strikethroughThickness?: number | string;
|
||||
string?: number | string;
|
||||
stroke?: string;
|
||||
strokeDasharray?: string | number;
|
||||
strokeDashoffset?: string | number;
|
||||
strokeLinecap?: "butt" | "round" | "square" | "inherit";
|
||||
strokeLinejoin?: "miter" | "round" | "bevel" | "inherit";
|
||||
strokeMiterlimit?: string;
|
||||
strokeOpacity?: number | string;
|
||||
strokeWidth?: number | string;
|
||||
surfaceScale?: number | string;
|
||||
systemLanguage?: number | string;
|
||||
tableValues?: number | string;
|
||||
targetX?: number | string;
|
||||
targetY?: number | string;
|
||||
textAnchor?: string;
|
||||
textDecoration?: number | string;
|
||||
textLength?: number | string;
|
||||
textRendering?: number | string;
|
||||
to?: number | string;
|
||||
transform?: string;
|
||||
u1?: number | string;
|
||||
u2?: number | string;
|
||||
underlinePosition?: number | string;
|
||||
underlineThickness?: number | string;
|
||||
unicode?: number | string;
|
||||
unicodeBidi?: number | string;
|
||||
unicodeRange?: number | string;
|
||||
unitsPerEm?: number | string;
|
||||
vAlphabetic?: number | string;
|
||||
values?: string;
|
||||
vectorEffect?: number | string;
|
||||
version?: string;
|
||||
vertAdvY?: number | string;
|
||||
vertOriginX?: number | string;
|
||||
vertOriginY?: number | string;
|
||||
vHanging?: number | string;
|
||||
vIdeographic?: number | string;
|
||||
viewBox?: string;
|
||||
viewTarget?: number | string;
|
||||
visibility?: number | string;
|
||||
vMathematical?: number | string;
|
||||
widths?: number | string;
|
||||
wordSpacing?: number | string;
|
||||
writingMode?: number | string;
|
||||
x1?: number | string;
|
||||
x2?: number | string;
|
||||
x?: number | string;
|
||||
xChannelSelector?: string;
|
||||
xHeight?: number | string;
|
||||
xlinkActuate?: string;
|
||||
xlinkArcrole?: string;
|
||||
xlinkHref?: string;
|
||||
xlinkRole?: string;
|
||||
xlinkShow?: string;
|
||||
xlinkTitle?: string;
|
||||
xlinkType?: string;
|
||||
xmlBase?: string;
|
||||
xmlLang?: string;
|
||||
xmlns?: string;
|
||||
xmlnsXlink?: string;
|
||||
xmlSpace?: string;
|
||||
y1?: number | string;
|
||||
y2?: number | string;
|
||||
y?: number | string;
|
||||
yChannelSelector?: string;
|
||||
z?: number | string;
|
||||
zoomAndPan?: string;
|
||||
}
|
||||
|
||||
interface PathAttributes {
|
||||
d: string;
|
||||
}
|
||||
|
||||
interface EventHandler<E extends Event> {
|
||||
(event: E): void;
|
||||
}
|
||||
|
||||
type ClipboardEventHandler = EventHandler<ClipboardEvent>;
|
||||
type CompositionEventHandler = EventHandler<CompositionEvent>;
|
||||
type DragEventHandler = EventHandler<DragEvent>;
|
||||
type FocusEventHandler = EventHandler<FocusEvent>;
|
||||
type KeyboardEventHandler = EventHandler<KeyboardEvent>;
|
||||
type MouseEventHandler = EventHandler<MouseEvent>;
|
||||
type TouchEventHandler = EventHandler<TouchEvent>;
|
||||
type UIEventHandler = EventHandler<UIEvent>;
|
||||
type WheelEventHandler = EventHandler<WheelEvent>;
|
||||
type AnimationEventHandler = EventHandler<AnimationEvent>;
|
||||
type TransitionEventHandler = EventHandler<TransitionEvent>;
|
||||
type GenericEventHandler = EventHandler<Event>;
|
||||
type PointerEventHandler = EventHandler<PointerEvent>;
|
||||
|
||||
interface DOMAttributes extends Omi.OmiDOMAttributes {
|
||||
// Image Events
|
||||
onLoad?: GenericEventHandler;
|
||||
onError?: GenericEventHandler;
|
||||
onLoadCapture?: GenericEventHandler;
|
||||
|
||||
// Clipboard Events
|
||||
onCopy?: ClipboardEventHandler;
|
||||
onCopyCapture?: ClipboardEventHandler;
|
||||
onCut?: ClipboardEventHandler;
|
||||
onCutCapture?: ClipboardEventHandler;
|
||||
onPaste?: ClipboardEventHandler;
|
||||
onPasteCapture?: ClipboardEventHandler;
|
||||
|
||||
// Composition Events
|
||||
onCompositionEnd?: CompositionEventHandler;
|
||||
onCompositionEndCapture?: CompositionEventHandler;
|
||||
onCompositionStart?: CompositionEventHandler;
|
||||
onCompositionStartCapture?: CompositionEventHandler;
|
||||
onCompositionUpdate?: CompositionEventHandler;
|
||||
onCompositionUpdateCapture?: CompositionEventHandler;
|
||||
|
||||
// Focus Events
|
||||
onFocus?: FocusEventHandler;
|
||||
onFocusCapture?: FocusEventHandler;
|
||||
onBlur?: FocusEventHandler;
|
||||
onBlurCapture?: FocusEventHandler;
|
||||
|
||||
// Form Events
|
||||
onChange?: GenericEventHandler;
|
||||
onChangeCapture?: GenericEventHandler;
|
||||
onInput?: GenericEventHandler;
|
||||
onInputCapture?: GenericEventHandler;
|
||||
onSearch?: GenericEventHandler;
|
||||
onSearchCapture?: GenericEventHandler;
|
||||
onSubmit?: GenericEventHandler;
|
||||
onSubmitCapture?: GenericEventHandler;
|
||||
|
||||
// Keyboard Events
|
||||
onKeyDown?: KeyboardEventHandler;
|
||||
onKeyDownCapture?: KeyboardEventHandler;
|
||||
onKeyPress?: KeyboardEventHandler;
|
||||
onKeyPressCapture?: KeyboardEventHandler;
|
||||
onKeyUp?: KeyboardEventHandler;
|
||||
onKeyUpCapture?: KeyboardEventHandler;
|
||||
|
||||
// Media Events
|
||||
onAbort?: GenericEventHandler;
|
||||
onAbortCapture?: GenericEventHandler;
|
||||
onCanPlay?: GenericEventHandler;
|
||||
onCanPlayCapture?: GenericEventHandler;
|
||||
onCanPlayThrough?: GenericEventHandler;
|
||||
onCanPlayThroughCapture?: GenericEventHandler;
|
||||
onDurationChange?: GenericEventHandler;
|
||||
onDurationChangeCapture?: GenericEventHandler;
|
||||
onEmptied?: GenericEventHandler;
|
||||
onEmptiedCapture?: GenericEventHandler;
|
||||
onEncrypted?: GenericEventHandler;
|
||||
onEncryptedCapture?: GenericEventHandler;
|
||||
onEnded?: GenericEventHandler;
|
||||
onEndedCapture?: GenericEventHandler;
|
||||
onLoadedData?: GenericEventHandler;
|
||||
onLoadedDataCapture?: GenericEventHandler;
|
||||
onLoadedMetadata?: GenericEventHandler;
|
||||
onLoadedMetadataCapture?: GenericEventHandler;
|
||||
onLoadStart?: GenericEventHandler;
|
||||
onLoadStartCapture?: GenericEventHandler;
|
||||
onPause?: GenericEventHandler;
|
||||
onPauseCapture?: GenericEventHandler;
|
||||
onPlay?: GenericEventHandler;
|
||||
onPlayCapture?: GenericEventHandler;
|
||||
onPlaying?: GenericEventHandler;
|
||||
onPlayingCapture?: GenericEventHandler;
|
||||
onProgress?: GenericEventHandler;
|
||||
onProgressCapture?: GenericEventHandler;
|
||||
onRateChange?: GenericEventHandler;
|
||||
onRateChangeCapture?: GenericEventHandler;
|
||||
onSeeked?: GenericEventHandler;
|
||||
onSeekedCapture?: GenericEventHandler;
|
||||
onSeeking?: GenericEventHandler;
|
||||
onSeekingCapture?: GenericEventHandler;
|
||||
onStalled?: GenericEventHandler;
|
||||
onStalledCapture?: GenericEventHandler;
|
||||
onSuspend?: GenericEventHandler;
|
||||
onSuspendCapture?: GenericEventHandler;
|
||||
onTimeUpdate?: GenericEventHandler;
|
||||
onTimeUpdateCapture?: GenericEventHandler;
|
||||
onVolumeChange?: GenericEventHandler;
|
||||
onVolumeChangeCapture?: GenericEventHandler;
|
||||
onWaiting?: GenericEventHandler;
|
||||
onWaitingCapture?: GenericEventHandler;
|
||||
|
||||
// MouseEvents
|
||||
onClick?: MouseEventHandler;
|
||||
onClickCapture?: MouseEventHandler;
|
||||
onContextMenu?: MouseEventHandler;
|
||||
onContextMenuCapture?: MouseEventHandler;
|
||||
onDblClick?: MouseEventHandler;
|
||||
onDblClickCapture?: MouseEventHandler;
|
||||
onDrag?: DragEventHandler;
|
||||
onDragCapture?: DragEventHandler;
|
||||
onDragEnd?: DragEventHandler;
|
||||
onDragEndCapture?: DragEventHandler;
|
||||
onDragEnter?: DragEventHandler;
|
||||
onDragEnterCapture?: DragEventHandler;
|
||||
onDragExit?: DragEventHandler;
|
||||
onDragExitCapture?: DragEventHandler;
|
||||
onDragLeave?: DragEventHandler;
|
||||
onDragLeaveCapture?: DragEventHandler;
|
||||
onDragOver?: DragEventHandler;
|
||||
onDragOverCapture?: DragEventHandler;
|
||||
onDragStart?: DragEventHandler;
|
||||
onDragStartCapture?: DragEventHandler;
|
||||
onDrop?: DragEventHandler;
|
||||
onDropCapture?: DragEventHandler;
|
||||
onMouseDown?: MouseEventHandler;
|
||||
onMouseDownCapture?: MouseEventHandler;
|
||||
onMouseEnter?: MouseEventHandler;
|
||||
onMouseEnterCapture?: MouseEventHandler;
|
||||
onMouseLeave?: MouseEventHandler;
|
||||
onMouseLeaveCapture?: MouseEventHandler;
|
||||
onMouseMove?: MouseEventHandler;
|
||||
onMouseMoveCapture?: MouseEventHandler;
|
||||
onMouseOut?: MouseEventHandler;
|
||||
onMouseOutCapture?: MouseEventHandler;
|
||||
onMouseOver?: MouseEventHandler;
|
||||
onMouseOverCapture?: MouseEventHandler;
|
||||
onMouseUp?: MouseEventHandler;
|
||||
onMouseUpCapture?: MouseEventHandler;
|
||||
|
||||
// Selection Events
|
||||
onSelect?: GenericEventHandler;
|
||||
onSelectCapture?: GenericEventHandler;
|
||||
|
||||
// Touch Events
|
||||
onTouchCancel?: TouchEventHandler;
|
||||
onTouchCancelCapture?: TouchEventHandler;
|
||||
onTouchEnd?: TouchEventHandler;
|
||||
onTouchEndCapture?: TouchEventHandler;
|
||||
onTouchMove?: TouchEventHandler;
|
||||
onTouchMoveCapture?: TouchEventHandler;
|
||||
onTouchStart?: TouchEventHandler;
|
||||
onTouchStartCapture?: TouchEventHandler;
|
||||
|
||||
// Pointer Events
|
||||
onPointerOver?: PointerEventHandler;
|
||||
onPointerOverCapture?: PointerEventHandler;
|
||||
onPointerEnter?: PointerEventHandler;
|
||||
onPointerEnterCapture?: PointerEventHandler;
|
||||
onPointerDown?: PointerEventHandler;
|
||||
onPointerDownCapture?: PointerEventHandler;
|
||||
onPointerMove?: PointerEventHandler;
|
||||
onPointerMoveCapture?: PointerEventHandler;
|
||||
onPointerUp?: PointerEventHandler;
|
||||
onPointerUpCapture?: PointerEventHandler;
|
||||
onPointerCancel?: PointerEventHandler;
|
||||
onPointerCancelCapture?: PointerEventHandler;
|
||||
onPointerOut?: PointerEventHandler;
|
||||
onPointerOutCapture?: PointerEventHandler;
|
||||
onPointerLeave?: PointerEventHandler;
|
||||
onPointerLeaveCapture?: PointerEventHandler;
|
||||
onGotPointerCapture?: PointerEventHandler;
|
||||
onGotPointerCaptureCapture?: PointerEventHandler;
|
||||
onLostPointerCapture?: PointerEventHandler;
|
||||
onLostPointerCaptureCapture?: PointerEventHandler;
|
||||
|
||||
// UI Events
|
||||
onScroll?: UIEventHandler;
|
||||
onScrollCapture?: UIEventHandler;
|
||||
|
||||
// Wheel Events
|
||||
onWheel?: WheelEventHandler;
|
||||
onWheelCapture?: WheelEventHandler;
|
||||
|
||||
// Animation Events
|
||||
onAnimationStart?: AnimationEventHandler;
|
||||
onAnimationStartCapture?: AnimationEventHandler;
|
||||
onAnimationEnd?: AnimationEventHandler;
|
||||
onAnimationEndCapture?: AnimationEventHandler;
|
||||
onAnimationIteration?: AnimationEventHandler;
|
||||
onAnimationIterationCapture?: AnimationEventHandler;
|
||||
|
||||
// Transition Events
|
||||
onTransitionEnd?: TransitionEventHandler;
|
||||
onTransitionEndCapture?: TransitionEventHandler;
|
||||
}
|
||||
|
||||
interface HTMLAttributes extends Omi.ClassAttributes<any>, DOMAttributes {
|
||||
// Standard HTML Attributes
|
||||
accept?: string;
|
||||
acceptCharset?: string;
|
||||
accessKey?: string;
|
||||
action?: string;
|
||||
allowFullScreen?: boolean;
|
||||
allowTransparency?: boolean;
|
||||
alt?: string;
|
||||
async?: boolean;
|
||||
autocomplete?: string;
|
||||
autofocus?: boolean;
|
||||
autoPlay?: boolean;
|
||||
capture?: boolean;
|
||||
cellPadding?: number | string;
|
||||
cellSpacing?: number | string;
|
||||
charSet?: string;
|
||||
challenge?: string;
|
||||
checked?: boolean;
|
||||
class?: string;
|
||||
className?: string;
|
||||
cols?: number;
|
||||
colSpan?: number;
|
||||
content?: string;
|
||||
contentEditable?: boolean;
|
||||
contextMenu?: string;
|
||||
controls?: boolean;
|
||||
controlsList?: string;
|
||||
coords?: string;
|
||||
crossOrigin?: string;
|
||||
data?: string;
|
||||
dateTime?: string;
|
||||
default?: boolean;
|
||||
defer?: boolean;
|
||||
dir?: string;
|
||||
disabled?: boolean;
|
||||
download?: any;
|
||||
draggable?: boolean;
|
||||
encType?: string;
|
||||
form?: string;
|
||||
formAction?: string;
|
||||
formEncType?: string;
|
||||
formMethod?: string;
|
||||
formNoValidate?: boolean;
|
||||
formTarget?: string;
|
||||
frameBorder?: number | string;
|
||||
headers?: string;
|
||||
height?: number | string;
|
||||
hidden?: boolean;
|
||||
high?: number;
|
||||
href?: string;
|
||||
hrefLang?: string;
|
||||
for?: string;
|
||||
httpEquiv?: string;
|
||||
icon?: string;
|
||||
id?: string;
|
||||
inputMode?: string;
|
||||
integrity?: string;
|
||||
is?: string;
|
||||
keyParams?: string;
|
||||
keyType?: string;
|
||||
kind?: string;
|
||||
label?: string;
|
||||
lang?: string;
|
||||
list?: string;
|
||||
loop?: boolean;
|
||||
low?: number;
|
||||
manifest?: string;
|
||||
marginHeight?: number;
|
||||
marginWidth?: number;
|
||||
max?: number | string;
|
||||
maxLength?: number;
|
||||
media?: string;
|
||||
mediaGroup?: string;
|
||||
method?: string;
|
||||
min?: number | string;
|
||||
minLength?: number;
|
||||
multiple?: boolean;
|
||||
muted?: boolean;
|
||||
name?: string;
|
||||
noValidate?: boolean;
|
||||
open?: boolean;
|
||||
optimum?: number;
|
||||
pattern?: string;
|
||||
placeholder?: string;
|
||||
playsInline?: boolean;
|
||||
poster?: string;
|
||||
preload?: string;
|
||||
radioGroup?: string;
|
||||
readOnly?: boolean;
|
||||
rel?: string;
|
||||
required?: boolean;
|
||||
role?: string;
|
||||
rows?: number;
|
||||
rowSpan?: number;
|
||||
sandbox?: string;
|
||||
scope?: string;
|
||||
scoped?: boolean;
|
||||
scrolling?: string;
|
||||
seamless?: boolean;
|
||||
selected?: boolean;
|
||||
shape?: string;
|
||||
size?: number;
|
||||
sizes?: string;
|
||||
slot?: string;
|
||||
span?: number;
|
||||
spellcheck?: boolean;
|
||||
src?: string;
|
||||
srcset?: string;
|
||||
srcDoc?: string;
|
||||
srcLang?: string;
|
||||
srcSet?: string;
|
||||
start?: number;
|
||||
step?: number | string;
|
||||
style?: any;
|
||||
summary?: string;
|
||||
tabIndex?: number;
|
||||
target?: string;
|
||||
title?: string;
|
||||
type?: string;
|
||||
useMap?: string;
|
||||
value?: string | string[] | number;
|
||||
width?: number | string;
|
||||
wmode?: string;
|
||||
wrap?: string;
|
||||
|
||||
// RDFa Attributes
|
||||
about?: string;
|
||||
datatype?: string;
|
||||
inlist?: any;
|
||||
prefix?: string;
|
||||
property?: string;
|
||||
resource?: string;
|
||||
typeof?: string;
|
||||
vocab?: string;
|
||||
}
|
||||
|
||||
interface IntrinsicElements {
|
||||
// HTML
|
||||
a: HTMLAttributes;
|
||||
abbr: HTMLAttributes;
|
||||
address: HTMLAttributes;
|
||||
area: HTMLAttributes;
|
||||
article: HTMLAttributes;
|
||||
aside: HTMLAttributes;
|
||||
audio: HTMLAttributes;
|
||||
b: HTMLAttributes;
|
||||
base: HTMLAttributes;
|
||||
bdi: HTMLAttributes;
|
||||
bdo: HTMLAttributes;
|
||||
big: HTMLAttributes;
|
||||
blockquote: HTMLAttributes;
|
||||
body: HTMLAttributes;
|
||||
br: HTMLAttributes;
|
||||
button: HTMLAttributes;
|
||||
canvas: HTMLAttributes;
|
||||
caption: HTMLAttributes;
|
||||
cite: HTMLAttributes;
|
||||
code: HTMLAttributes;
|
||||
col: HTMLAttributes;
|
||||
colgroup: HTMLAttributes;
|
||||
data: HTMLAttributes;
|
||||
datalist: HTMLAttributes;
|
||||
dd: HTMLAttributes;
|
||||
del: HTMLAttributes;
|
||||
details: HTMLAttributes;
|
||||
dfn: HTMLAttributes;
|
||||
dialog: HTMLAttributes;
|
||||
div: HTMLAttributes;
|
||||
dl: HTMLAttributes;
|
||||
dt: HTMLAttributes;
|
||||
em: HTMLAttributes;
|
||||
embed: HTMLAttributes;
|
||||
fieldset: HTMLAttributes;
|
||||
figcaption: HTMLAttributes;
|
||||
figure: HTMLAttributes;
|
||||
footer: HTMLAttributes;
|
||||
form: HTMLAttributes;
|
||||
h1: HTMLAttributes;
|
||||
h2: HTMLAttributes;
|
||||
h3: HTMLAttributes;
|
||||
h4: HTMLAttributes;
|
||||
h5: HTMLAttributes;
|
||||
h6: HTMLAttributes;
|
||||
head: HTMLAttributes;
|
||||
header: HTMLAttributes;
|
||||
hr: HTMLAttributes;
|
||||
html: HTMLAttributes;
|
||||
i: HTMLAttributes;
|
||||
iframe: HTMLAttributes;
|
||||
img: HTMLAttributes;
|
||||
input: HTMLAttributes;
|
||||
ins: HTMLAttributes;
|
||||
kbd: HTMLAttributes;
|
||||
keygen: HTMLAttributes;
|
||||
label: HTMLAttributes;
|
||||
legend: HTMLAttributes;
|
||||
li: HTMLAttributes;
|
||||
link: HTMLAttributes;
|
||||
main: HTMLAttributes;
|
||||
map: HTMLAttributes;
|
||||
mark: HTMLAttributes;
|
||||
menu: HTMLAttributes;
|
||||
menuitem: HTMLAttributes;
|
||||
meta: HTMLAttributes;
|
||||
meter: HTMLAttributes;
|
||||
nav: HTMLAttributes;
|
||||
noscript: HTMLAttributes;
|
||||
object: HTMLAttributes;
|
||||
ol: HTMLAttributes;
|
||||
optgroup: HTMLAttributes;
|
||||
option: HTMLAttributes;
|
||||
output: HTMLAttributes;
|
||||
p: HTMLAttributes;
|
||||
param: HTMLAttributes;
|
||||
picture: HTMLAttributes;
|
||||
pre: HTMLAttributes;
|
||||
progress: HTMLAttributes;
|
||||
q: HTMLAttributes;
|
||||
rp: HTMLAttributes;
|
||||
rt: HTMLAttributes;
|
||||
ruby: HTMLAttributes;
|
||||
s: HTMLAttributes;
|
||||
samp: HTMLAttributes;
|
||||
script: HTMLAttributes;
|
||||
section: HTMLAttributes;
|
||||
select: HTMLAttributes;
|
||||
slot: HTMLAttributes;
|
||||
small: HTMLAttributes;
|
||||
source: HTMLAttributes;
|
||||
span: HTMLAttributes;
|
||||
strong: HTMLAttributes;
|
||||
style: HTMLAttributes;
|
||||
sub: HTMLAttributes;
|
||||
summary: HTMLAttributes;
|
||||
sup: HTMLAttributes;
|
||||
table: HTMLAttributes;
|
||||
tbody: HTMLAttributes;
|
||||
td: HTMLAttributes;
|
||||
textarea: HTMLAttributes;
|
||||
tfoot: HTMLAttributes;
|
||||
th: HTMLAttributes;
|
||||
thead: HTMLAttributes;
|
||||
time: HTMLAttributes;
|
||||
title: HTMLAttributes;
|
||||
tr: HTMLAttributes;
|
||||
track: HTMLAttributes;
|
||||
u: HTMLAttributes;
|
||||
ul: HTMLAttributes;
|
||||
"var": HTMLAttributes;
|
||||
video: HTMLAttributes;
|
||||
wbr: HTMLAttributes;
|
||||
|
||||
//SVG
|
||||
svg: SVGAttributes;
|
||||
animate: SVGAttributes;
|
||||
circle: SVGAttributes;
|
||||
clipPath: SVGAttributes;
|
||||
defs: SVGAttributes;
|
||||
ellipse: SVGAttributes;
|
||||
feBlend: SVGAttributes;
|
||||
feColorMatrix: SVGAttributes;
|
||||
feComponentTransfer: SVGAttributes;
|
||||
feComposite: SVGAttributes;
|
||||
feConvolveMatrix: SVGAttributes;
|
||||
feDiffuseLighting: SVGAttributes;
|
||||
feDisplacementMap: SVGAttributes;
|
||||
feFlood: SVGAttributes;
|
||||
feGaussianBlur: SVGAttributes;
|
||||
feImage: SVGAttributes;
|
||||
feMerge: SVGAttributes;
|
||||
feMergeNode: SVGAttributes;
|
||||
feMorphology: SVGAttributes;
|
||||
feOffset: SVGAttributes;
|
||||
feSpecularLighting: SVGAttributes;
|
||||
feTile: SVGAttributes;
|
||||
feTurbulence: SVGAttributes;
|
||||
filter: SVGAttributes;
|
||||
foreignObject: SVGAttributes;
|
||||
g: SVGAttributes;
|
||||
image: SVGAttributes;
|
||||
line: SVGAttributes;
|
||||
linearGradient: SVGAttributes;
|
||||
marker: SVGAttributes;
|
||||
mask: SVGAttributes;
|
||||
path: SVGAttributes;
|
||||
pattern: SVGAttributes;
|
||||
polygon: SVGAttributes;
|
||||
polyline: SVGAttributes;
|
||||
radialGradient: SVGAttributes;
|
||||
rect: SVGAttributes;
|
||||
stop: SVGAttributes;
|
||||
symbol: SVGAttributes;
|
||||
text: SVGAttributes;
|
||||
tspan: SVGAttributes;
|
||||
use: SVGAttributes;
|
||||
[tagName: string]: any;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
import { h } from './h'
|
||||
import Component from './component'
|
||||
import { render } from './render'
|
||||
import { tag } from './tag'
|
||||
import { define } from './define'
|
||||
import options from './options'
|
||||
|
||||
const WeElement = Component
|
||||
const root = getGlobal()
|
||||
const omiax = {
|
||||
h,
|
||||
tag,
|
||||
define,
|
||||
Component,
|
||||
render,
|
||||
WeElement,
|
||||
options
|
||||
}
|
||||
|
||||
root.Omi = omiax
|
||||
root.omi = omiax
|
||||
root.omiax = omiax
|
||||
root.omiax.version = '0.0.0'
|
||||
|
||||
export default {
|
||||
h,
|
||||
tag,
|
||||
define,
|
||||
Component,
|
||||
render,
|
||||
WeElement,
|
||||
options
|
||||
}
|
||||
|
||||
export {
|
||||
h,
|
||||
tag,
|
||||
define,
|
||||
Component,
|
||||
render,
|
||||
WeElement,
|
||||
options
|
||||
}
|
||||
|
||||
function getGlobal() {
|
||||
if (
|
||||
typeof global !== 'object' ||
|
||||
!global ||
|
||||
global.Math !== Math ||
|
||||
global.Array !== Array
|
||||
) {
|
||||
if (typeof self !== 'undefined') {
|
||||
return self
|
||||
} else if (typeof window !== 'undefined') {
|
||||
return window
|
||||
} else if (typeof global !== 'undefined') {
|
||||
return global
|
||||
}
|
||||
return (function() {
|
||||
return this
|
||||
})()
|
||||
}
|
||||
return global
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
/* @flow */
|
||||
|
||||
import { createElement, cloneElement, Component, type Node } from 'react';
|
||||
|
||||
declare var h: createElement;
|
||||
|
||||
declare function render(vnode: Node, parent: Element, toReplace?: Element): Element;
|
||||
|
||||
export { h, createElement, cloneElement, Component, render };
|
||||
export default { h, createElement, cloneElement, Component, render };
|
||||
|
||||
declare export function rerender(): void;
|
||||
declare export var options: Object;
|
|
@ -1,59 +0,0 @@
|
|||
import mock from './mock/index'
|
||||
|
||||
function getGlobal() {
|
||||
if (
|
||||
typeof global !== 'object' ||
|
||||
!global ||
|
||||
global.Math !== Math ||
|
||||
global.Array !== Array
|
||||
) {
|
||||
if (typeof self !== 'undefined') {
|
||||
return self
|
||||
} else if (typeof window !== 'undefined') {
|
||||
return window
|
||||
} else if (typeof global !== 'undefined') {
|
||||
return global
|
||||
}
|
||||
return (function() {
|
||||
return this
|
||||
})()
|
||||
}
|
||||
return global
|
||||
}
|
||||
|
||||
/** Global options
|
||||
* @public
|
||||
* @namespace options {Object}
|
||||
*/
|
||||
export default {
|
||||
scopedStyle: true,
|
||||
mapping: {},
|
||||
isWeb: true,
|
||||
staticStyleMapping: {},
|
||||
doc: mock.document,
|
||||
//doc: typeof document === 'object' ? document : null,
|
||||
root: getGlobal(),
|
||||
//styleCache :[{ctor:ctor,ctorName:ctorName,style:style}]
|
||||
styleCache: []
|
||||
//componentChange(component, element) { },
|
||||
/** If `true`, `prop` changes trigger synchronous component updates.
|
||||
* @name syncComponentUpdates
|
||||
* @type Boolean
|
||||
* @default true
|
||||
*/
|
||||
//syncComponentUpdates: true,
|
||||
|
||||
/** Processes all created VNodes.
|
||||
* @param {VNode} vnode A newly-created VNode to normalize/process
|
||||
*/
|
||||
//vnode(vnode) { }
|
||||
|
||||
/** Hook invoked after a component is mounted. */
|
||||
//afterMount(component) { },
|
||||
|
||||
/** Hook invoked after the DOM is updated with a component's latest render. */
|
||||
//afterUpdate(component) { }
|
||||
|
||||
/** Hook invoked immediately before a component is unmounted. */
|
||||
// beforeUnmount(component) { }
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
import options from './options'
|
||||
import { defer } from './util'
|
||||
import { renderComponent } from './vdom/component'
|
||||
|
||||
/** Managed queue of dirty components to be re-rendered */
|
||||
|
||||
let items = []
|
||||
|
||||
export function enqueueRender(component) {
|
||||
if (items.push(component) == 1) {
|
||||
;(options.debounceRendering || defer)(rerender)
|
||||
}
|
||||
}
|
||||
|
||||
/** Rerender all enqueued dirty components */
|
||||
export function rerender() {
|
||||
let p
|
||||
while ( (p = items.pop()) ) {
|
||||
renderComponent(p)
|
||||
}
|
||||
}
|
|
@ -1,255 +0,0 @@
|
|||
/**
|
||||
* preact-render-to-string based on preact-render-to-string
|
||||
* by Jason Miller
|
||||
* Licensed under the MIT License
|
||||
* https://github.com/developit/preact-render-to-string
|
||||
*
|
||||
* modified by dntzhang
|
||||
*/
|
||||
|
||||
import options from './options'
|
||||
|
||||
import {
|
||||
addScopedAttrStatic,
|
||||
getCtorName,
|
||||
scopeHost,
|
||||
scoper
|
||||
} from './style'
|
||||
|
||||
|
||||
const encodeEntities = s => String(s)
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"');
|
||||
|
||||
const indent = (s, char) => String(s).replace(/(\n+)/g, '$1' + (char || '\t'));
|
||||
|
||||
const mapping = options.mapping
|
||||
|
||||
const VOID_ELEMENTS = /^(area|base|br|col|embed|hr|img|input|link|meta|param|source|track|wbr)$/;
|
||||
|
||||
const isLargeString = (s, length, ignoreLines) => (String(s).length > (length || 40) || (!ignoreLines && String(s).indexOf('\n') !== -1) || String(s).indexOf('<') !== -1);
|
||||
|
||||
const JS_TO_CSS = {};
|
||||
|
||||
// Convert an Object style to a CSSText string
|
||||
function styleObjToCss(s) {
|
||||
let str = '';
|
||||
for (let prop in s) {
|
||||
let val = s[prop];
|
||||
if (val != null) {
|
||||
if (str) str += ' ';
|
||||
// str += jsToCss(prop);
|
||||
str += JS_TO_CSS[prop] || (JS_TO_CSS[prop] = prop.replace(/([A-Z])/g, '-$1').toLowerCase());
|
||||
str += ': ';
|
||||
str += val;
|
||||
if (typeof val === 'number' && IS_NON_DIMENSIONAL.test(prop) === false) {
|
||||
str += 'px';
|
||||
}
|
||||
str += ';';
|
||||
}
|
||||
}
|
||||
return str || undefined;
|
||||
}
|
||||
|
||||
export function renderToString(vnode, opts, store, isSvgMode){
|
||||
store = store || {};
|
||||
opts = Object.assign({
|
||||
scopedCSS: true
|
||||
},opts)
|
||||
const css = {}
|
||||
const html = _renderToString(vnode, opts, store, isSvgMode, css)
|
||||
return {
|
||||
css: Object.values(css),
|
||||
html: html
|
||||
}
|
||||
}
|
||||
|
||||
/** The default export is an alias of `render()`. */
|
||||
function _renderToString(vnode, opts, store, isSvgMode, css) {
|
||||
if (vnode == null || typeof vnode === 'boolean') {
|
||||
return '';
|
||||
}
|
||||
|
||||
let nodeName = vnode.nodeName,
|
||||
attributes = vnode.attributes,
|
||||
isComponent = false;
|
||||
|
||||
|
||||
let pretty = true && opts.pretty,
|
||||
indentChar = pretty && typeof pretty === 'string' ? pretty : '\t';
|
||||
|
||||
// #text nodes
|
||||
if (typeof vnode !== 'object' && !nodeName) {
|
||||
return encodeEntities(vnode);
|
||||
}
|
||||
|
||||
// components
|
||||
const ctor = mapping[nodeName]
|
||||
if (ctor) {
|
||||
isComponent = true;
|
||||
|
||||
let props = getNodeProps(vnode),
|
||||
rendered;
|
||||
// class-based components
|
||||
let c = new ctor(props, store);
|
||||
// turn off stateful re-rendering:
|
||||
c._disable = c.__x = true;
|
||||
c.props = props;
|
||||
c.store = store;
|
||||
if (c.install) c.install();
|
||||
if (c.beforeRender) c.beforeRender();
|
||||
rendered = c.render(c.props, c.data, c.store);
|
||||
|
||||
if(opts.scopedCSS){
|
||||
|
||||
if (c.constructor.css || c.css) {
|
||||
|
||||
const cssStr = c.constructor.css ? c.constructor.css : (typeof c.css === 'function' ? c.css() : c.css)
|
||||
const cssAttr = '_s' + getCtorName(c.constructor)
|
||||
css[cssAttr] = {
|
||||
id: cssAttr,
|
||||
css: scoper(cssStr, cssAttr)
|
||||
}
|
||||
addScopedAttrStatic(
|
||||
rendered,
|
||||
cssAttr
|
||||
)
|
||||
}
|
||||
|
||||
c.scopedCSSAttr = vnode.css
|
||||
scopeHost(rendered, c.scopedCSSAttr)
|
||||
}
|
||||
|
||||
return _renderToString(rendered, opts, store, false, css);
|
||||
}
|
||||
|
||||
|
||||
// render JSX to HTML
|
||||
let s = '', html;
|
||||
|
||||
if (attributes) {
|
||||
let attrs = Object.keys(attributes);
|
||||
|
||||
// allow sorting lexicographically for more determinism (useful for tests, such as via preact-jsx-chai)
|
||||
if (opts && opts.sortAttributes === true) attrs.sort();
|
||||
|
||||
for (let i = 0; i < attrs.length; i++) {
|
||||
let name = attrs[i],
|
||||
v = attributes[name];
|
||||
if (name === 'children') continue;
|
||||
|
||||
if (name.match(/[\s\n\\/='"\0<>]/)) continue;
|
||||
|
||||
if (!(opts && opts.allAttributes) && (name === 'key' || name === 'ref')) continue;
|
||||
|
||||
if (name === 'className') {
|
||||
if (attributes['class']) continue;
|
||||
name = 'class';
|
||||
}
|
||||
else if (isSvgMode && name.match(/^xlink:?./)) {
|
||||
name = name.toLowerCase().replace(/^xlink:?/, 'xlink:');
|
||||
}
|
||||
|
||||
if (name === 'style' && v && typeof v === 'object') {
|
||||
v = styleObjToCss(v);
|
||||
}
|
||||
|
||||
let hooked = opts.attributeHook && opts.attributeHook(name, v, store, opts, isComponent);
|
||||
if (hooked || hooked === '') {
|
||||
s += hooked;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (name === 'dangerouslySetInnerHTML') {
|
||||
html = v && v.__html;
|
||||
}
|
||||
else if ((v || v === 0 || v === '') && typeof v !== 'function') {
|
||||
if (v === true || v === '') {
|
||||
v = name;
|
||||
// in non-xml mode, allow boolean attributes
|
||||
if (!opts || !opts.xml) {
|
||||
s += ' ' + name;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
s += ` ${name}="${encodeEntities(v)}"`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// account for >1 multiline attribute
|
||||
if (pretty) {
|
||||
let sub = s.replace(/^\n\s*/, ' ');
|
||||
if (sub !== s && !~sub.indexOf('\n')) s = sub;
|
||||
else if (pretty && ~s.indexOf('\n')) s += '\n';
|
||||
}
|
||||
|
||||
s = `<${nodeName}${s}>`;
|
||||
if (String(nodeName).match(/[\s\n\\/='"\0<>]/)) throw s;
|
||||
|
||||
let isVoid = String(nodeName).match(VOID_ELEMENTS);
|
||||
if (isVoid) s = s.replace(/>$/, ' />');
|
||||
|
||||
let pieces = [];
|
||||
if (html) {
|
||||
// if multiline, indent.
|
||||
if (pretty && isLargeString(html)) {
|
||||
html = '\n' + indentChar + indent(html, indentChar);
|
||||
}
|
||||
s += html;
|
||||
}
|
||||
else if (vnode.children) {
|
||||
let hasLarge = pretty && ~s.indexOf('\n');
|
||||
for (let i = 0; i < vnode.children.length; i++) {
|
||||
let child = vnode.children[i];
|
||||
if (child != null && child !== false) {
|
||||
let childSvgMode = nodeName === 'svg' ? true : nodeName === 'foreignObject' ? false : isSvgMode,
|
||||
ret = _renderToString(child, opts, store, childSvgMode, css);
|
||||
if (pretty && !hasLarge && isLargeString(ret)) hasLarge = true;
|
||||
if (ret) pieces.push(ret);
|
||||
}
|
||||
}
|
||||
if (pretty && hasLarge) {
|
||||
for (let i = pieces.length; i--;) {
|
||||
pieces[i] = '\n' + indentChar + indent(pieces[i], indentChar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pieces.length) {
|
||||
s += pieces.join('');
|
||||
}
|
||||
else if (opts && opts.xml) {
|
||||
return s.substring(0, s.length - 1) + ' />';
|
||||
}
|
||||
|
||||
if (!isVoid) {
|
||||
if (pretty && ~s.indexOf('\n')) s += '\n';
|
||||
s += `</${nodeName}>`;
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
function assign(obj, props) {
|
||||
for (let i in props) obj[i] = props[i];
|
||||
return obj;
|
||||
}
|
||||
|
||||
function getNodeProps(vnode) {
|
||||
let props = assign({}, vnode.attributes);
|
||||
props.children = vnode.children;
|
||||
|
||||
let defaultProps = vnode.nodeName.defaultProps;
|
||||
if (defaultProps !== undefined) {
|
||||
for (let i in defaultProps) {
|
||||
if (props[i] === undefined) {
|
||||
props[i] = defaultProps[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return props;
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
import { diff } from './vdom/diff'
|
||||
|
||||
/** Render JSX into a `parent` Element.
|
||||
* @param {VNode} vnode A (JSX) VNode to render
|
||||
* @param {Element} parent DOM element to render into
|
||||
* @param {object} [store]
|
||||
* @public
|
||||
*/
|
||||
export function render(vnode, parent, store, empty, merge) {
|
||||
parent = typeof parent === 'string' ? document.querySelector(parent) : parent
|
||||
|
||||
if (empty) {
|
||||
while (parent.firstChild) {
|
||||
parent.removeChild(parent.firstChild)
|
||||
}
|
||||
}
|
||||
|
||||
if (merge) {
|
||||
merge =
|
||||
typeof merge === 'string'
|
||||
? document.querySelector(merge)
|
||||
: merge
|
||||
}
|
||||
|
||||
return diff(merge, vnode, store, false, parent, false, true)
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
export function rpx(str) {
|
||||
return str.replace(/([1-9]\d*|0)(\.\d*)*rpx/g, (a, b) => {
|
||||
return (window.innerWidth * Number(b)) / 750 + 'px'
|
||||
})
|
||||
}
|
|
@ -1,128 +0,0 @@
|
|||
import options from './options'
|
||||
|
||||
let styleId = 0
|
||||
|
||||
export function getCtorName(ctor) {
|
||||
for (let i = 0, len = options.styleCache.length; i < len; i++) {
|
||||
let item = options.styleCache[i]
|
||||
|
||||
if (item.ctor === ctor) {
|
||||
return item.attrName
|
||||
}
|
||||
}
|
||||
|
||||
let attrName = 's' + styleId
|
||||
options.styleCache.push({ ctor, attrName })
|
||||
styleId++
|
||||
|
||||
return attrName
|
||||
}
|
||||
|
||||
// many thanks to https://github.com/thomaspark/scoper/
|
||||
export function scoper(css, prefix) {
|
||||
prefix = '[' + prefix.toLowerCase() + ']'
|
||||
// https://www.w3.org/TR/css-syntax-3/#lexical
|
||||
css = css.replace(/\/\*[^*]*\*+([^/][^*]*\*+)*\//g, '')
|
||||
// eslint-disable-next-line
|
||||
let re = new RegExp('([^\r\n,{}:]+)(:[^\r\n,{}]+)?(,(?=[^{}]*{)|\s*{)', 'g')
|
||||
/**
|
||||
* Example:
|
||||
*
|
||||
* .classname::pesudo { color:red }
|
||||
*
|
||||
* g1 is normal selector `.classname`
|
||||
* g2 is pesudo class or pesudo element
|
||||
* g3 is the suffix
|
||||
*/
|
||||
css = css.replace(re, (g0, g1, g2, g3) => {
|
||||
if (typeof g2 === 'undefined') {
|
||||
g2 = ''
|
||||
}
|
||||
|
||||
/* eslint-ignore-next-line */
|
||||
if (
|
||||
g1.match(
|
||||
/^\s*(@media|\d+%?|@-webkit-keyframes|@keyframes|to|from|@font-face)/
|
||||
)
|
||||
) {
|
||||
return g1 + g2 + g3
|
||||
}
|
||||
|
||||
let appendClass = g1.replace(/(\s*)$/, '') + prefix + g2
|
||||
//let prependClass = prefix + ' ' + g1.trim() + g2;
|
||||
|
||||
return appendClass + g3
|
||||
//return appendClass + ',' + prependClass + g3;
|
||||
})
|
||||
|
||||
return css
|
||||
}
|
||||
|
||||
export function addStyle(cssText, id) {
|
||||
id = id.toLowerCase()
|
||||
let ele = document.getElementById(id)
|
||||
let head = document.getElementsByTagName('head')[0]
|
||||
if (ele && ele.parentNode === head) {
|
||||
head.removeChild(ele)
|
||||
}
|
||||
|
||||
let someThingStyles = document.createElement('style')
|
||||
head.appendChild(someThingStyles)
|
||||
someThingStyles.setAttribute('type', 'text/css')
|
||||
someThingStyles.setAttribute('id', id)
|
||||
if (window.ActiveXObject) {
|
||||
someThingStyles.styleSheet.cssText = cssText
|
||||
} else {
|
||||
someThingStyles.textContent = cssText
|
||||
}
|
||||
}
|
||||
|
||||
export function addStyleWithoutId(cssText) {
|
||||
let head = document.getElementsByTagName('head')[0]
|
||||
let someThingStyles = document.createElement('style')
|
||||
head.appendChild(someThingStyles)
|
||||
someThingStyles.setAttribute('type', 'text/css')
|
||||
|
||||
if (window.ActiveXObject) {
|
||||
someThingStyles.styleSheet.cssText = cssText
|
||||
} else {
|
||||
someThingStyles.textContent = cssText
|
||||
}
|
||||
}
|
||||
|
||||
export function addScopedAttrStatic(vdom, attr) {
|
||||
if (options.scopedStyle) {
|
||||
scopeVdom(attr, vdom)
|
||||
}
|
||||
}
|
||||
|
||||
export function addStyleToHead(style, attr) {
|
||||
if (options.scopedStyle) {
|
||||
if (!options.staticStyleMapping[attr]) {
|
||||
addStyle(scoper(style, attr), attr)
|
||||
options.staticStyleMapping[attr] = true
|
||||
}
|
||||
} else if (!options.staticStyleMapping[attr]) {
|
||||
addStyleWithoutId(style)
|
||||
options.staticStyleMapping[attr] = true
|
||||
}
|
||||
}
|
||||
|
||||
export function scopeVdom(attr, vdom) {
|
||||
if (typeof vdom === 'object') {
|
||||
vdom.attributes = vdom.attributes || {}
|
||||
vdom.attributes[attr] = ''
|
||||
vdom.css = vdom.css || {}
|
||||
vdom.css[attr] = ''
|
||||
vdom.children.forEach(child => scopeVdom(attr, child))
|
||||
}
|
||||
}
|
||||
|
||||
export function scopeHost(vdom, css) {
|
||||
if (typeof vdom === 'object' && css) {
|
||||
vdom.attributes = vdom.attributes || {}
|
||||
for (let key in css) {
|
||||
vdom.attributes[key] = ''
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
import { define } from './define'
|
||||
|
||||
export function tag(name) {
|
||||
return function(target) {
|
||||
define(name, target)
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
const callbacks = []
|
||||
const nextTickCallback = []
|
||||
|
||||
export function tick(fn, scope) {
|
||||
callbacks.push({ fn, scope })
|
||||
}
|
||||
|
||||
export function fireTick() {
|
||||
callbacks.forEach(item => {
|
||||
item.fn.call(item.scope)
|
||||
})
|
||||
|
||||
nextTickCallback.forEach(nextItem => {
|
||||
nextItem.fn.call(nextItem.scope)
|
||||
})
|
||||
nextTickCallback.length = 0
|
||||
}
|
||||
|
||||
export function nextTick(fn, scope) {
|
||||
nextTickCallback.push({ fn, scope })
|
||||
}
|
|
@ -1,226 +0,0 @@
|
|||
'use strict'
|
||||
/* eslint-disable no-unused-vars */
|
||||
var getOwnPropertySymbols = Object.getOwnPropertySymbols
|
||||
var hasOwnProperty = Object.prototype.hasOwnProperty
|
||||
var propIsEnumerable = Object.prototype.propertyIsEnumerable
|
||||
|
||||
function toObject(val) {
|
||||
if (val === null || val === undefined) {
|
||||
throw new TypeError('Object.assign cannot be called with null or undefined')
|
||||
}
|
||||
|
||||
return Object(val)
|
||||
}
|
||||
|
||||
export function assign(target, source) {
|
||||
var from
|
||||
var to = toObject(target)
|
||||
var symbols
|
||||
|
||||
for (var s = 1; s < arguments.length; s++) {
|
||||
from = Object(arguments[s])
|
||||
|
||||
for (var key in from) {
|
||||
if (hasOwnProperty.call(from, key)) {
|
||||
to[key] = from[key]
|
||||
}
|
||||
}
|
||||
|
||||
if (getOwnPropertySymbols) {
|
||||
symbols = getOwnPropertySymbols(from)
|
||||
for (var i = 0; i < symbols.length; i++) {
|
||||
if (propIsEnumerable.call(from, symbols[i])) {
|
||||
to[symbols[i]] = from[symbols[i]]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return to
|
||||
}
|
||||
|
||||
if (typeof Element !== 'undefined' && !Element.prototype.addEventListener) {
|
||||
var oListeners = {};
|
||||
function runListeners(oEvent) {
|
||||
if (!oEvent) { oEvent = window.event; }
|
||||
for (var iLstId = 0, iElId = 0, oEvtListeners = oListeners[oEvent.type]; iElId < oEvtListeners.aEls.length; iElId++) {
|
||||
if (oEvtListeners.aEls[iElId] === this) {
|
||||
for (iLstId; iLstId < oEvtListeners.aEvts[iElId].length; iLstId++) { oEvtListeners.aEvts[iElId][iLstId].call(this, oEvent); }
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Element.prototype.addEventListener = function (sEventType, fListener /*, useCapture (will be ignored!) */) {
|
||||
if (oListeners.hasOwnProperty(sEventType)) {
|
||||
var oEvtListeners = oListeners[sEventType];
|
||||
for (var nElIdx = -1, iElId = 0; iElId < oEvtListeners.aEls.length; iElId++) {
|
||||
if (oEvtListeners.aEls[iElId] === this) { nElIdx = iElId; break; }
|
||||
}
|
||||
if (nElIdx === -1) {
|
||||
oEvtListeners.aEls.push(this);
|
||||
oEvtListeners.aEvts.push([fListener]);
|
||||
this["on" + sEventType] = runListeners;
|
||||
} else {
|
||||
var aElListeners = oEvtListeners.aEvts[nElIdx];
|
||||
if (this["on" + sEventType] !== runListeners) {
|
||||
aElListeners.splice(0);
|
||||
this["on" + sEventType] = runListeners;
|
||||
}
|
||||
for (var iLstId = 0; iLstId < aElListeners.length; iLstId++) {
|
||||
if (aElListeners[iLstId] === fListener) { return; }
|
||||
}
|
||||
aElListeners.push(fListener);
|
||||
}
|
||||
} else {
|
||||
oListeners[sEventType] = { aEls: [this], aEvts: [[fListener]] };
|
||||
this["on" + sEventType] = runListeners;
|
||||
}
|
||||
};
|
||||
Element.prototype.removeEventListener = function (sEventType, fListener /*, useCapture (will be ignored!) */) {
|
||||
if (!oListeners.hasOwnProperty(sEventType)) { return; }
|
||||
var oEvtListeners = oListeners[sEventType];
|
||||
for (var nElIdx = -1, iElId = 0; iElId < oEvtListeners.aEls.length; iElId++) {
|
||||
if (oEvtListeners.aEls[iElId] === this) { nElIdx = iElId; break; }
|
||||
}
|
||||
if (nElIdx === -1) { return; }
|
||||
for (var iLstId = 0, aElListeners = oEvtListeners.aEvts[nElIdx]; iLstId < aElListeners.length; iLstId++) {
|
||||
if (aElListeners[iLstId] === fListener) { aElListeners.splice(iLstId, 1); }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
if (typeof Object.create !== 'function') {
|
||||
Object.create = function(proto, propertiesObject) {
|
||||
if (typeof proto !== 'object' && typeof proto !== 'function') {
|
||||
throw new TypeError('Object prototype may only be an Object: ' + proto)
|
||||
} else if (proto === null) {
|
||||
throw new Error(
|
||||
"This browser's implementation of Object.create is a shim and doesn't support 'null' as the first argument."
|
||||
)
|
||||
}
|
||||
|
||||
// if (typeof propertiesObject != 'undefined') {
|
||||
// throw new Error("This browser's implementation of Object.create is a shim and doesn't support a second argument.");
|
||||
// }
|
||||
|
||||
function F() {}
|
||||
F.prototype = proto
|
||||
|
||||
return new F()
|
||||
}
|
||||
}
|
||||
|
||||
if (!String.prototype.trim) {
|
||||
String.prototype.trim = function () {
|
||||
return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy all properties from `props` onto `obj`.
|
||||
* @param {Object} obj Object onto which properties should be copied.
|
||||
* @param {Object} props Object from which to copy properties.
|
||||
* @returns obj
|
||||
* @private
|
||||
*/
|
||||
export function extend(obj, props) {
|
||||
for (let i in props) obj[i] = props[i]
|
||||
return obj
|
||||
}
|
||||
|
||||
/** Invoke or update a ref, depending on whether it is a function or object ref.
|
||||
* @param {object|function} [ref=null]
|
||||
* @param {any} [value]
|
||||
*/
|
||||
export function applyRef(ref, value) {
|
||||
if (ref) {
|
||||
if (typeof ref == 'function') ref(value)
|
||||
else ref.current = value
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call a function asynchronously, as soon as possible. Makes
|
||||
* use of HTML Promise to schedule the callback if available,
|
||||
* otherwise falling back to `setTimeout` (mainly for IE<11).
|
||||
*
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
let usePromise = typeof Promise == 'function'
|
||||
|
||||
// for native
|
||||
if (
|
||||
typeof document !== 'object' &&
|
||||
typeof global !== 'undefined' &&
|
||||
global.__config__
|
||||
) {
|
||||
if (global.__config__.platform === 'android') {
|
||||
usePromise = true
|
||||
} else {
|
||||
let systemVersion =
|
||||
(global.__config__.systemVersion &&
|
||||
global.__config__.systemVersion.split('.')[0]) ||
|
||||
0
|
||||
if (systemVersion > 8) {
|
||||
usePromise = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const defer = usePromise
|
||||
? Promise.resolve().then.bind(Promise.resolve())
|
||||
: setTimeout
|
||||
|
||||
export function isArray(obj) {
|
||||
return Object.prototype.toString.call(obj) === '[object Array]'
|
||||
}
|
||||
|
||||
export function nProps(props) {
|
||||
if (!props || isArray(props)) return {}
|
||||
const result = {}
|
||||
Object.keys(props).forEach(key => {
|
||||
result[key] = props[key].value
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
export function getUse(data, paths) {
|
||||
const obj = []
|
||||
paths.forEach((path, index) => {
|
||||
const isPath = typeof path === 'string'
|
||||
if (isPath) {
|
||||
obj[index] = getTargetByPath(data, path)
|
||||
} else {
|
||||
const key = Object.keys(path)[0]
|
||||
const value = path[key]
|
||||
if (typeof value === 'string') {
|
||||
obj[index] = getTargetByPath(data, value)
|
||||
} else {
|
||||
const tempPath = value[0]
|
||||
if (typeof tempPath === 'string') {
|
||||
const tempVal = getTargetByPath(data, tempPath)
|
||||
obj[index] = value[1] ? value[1](tempVal) : tempVal
|
||||
} else {
|
||||
const args = []
|
||||
tempPath.forEach(path =>{
|
||||
args.push(getTargetByPath(data, path))
|
||||
})
|
||||
obj[index] = value[1].apply(null, args)
|
||||
}
|
||||
}
|
||||
obj[key] = obj[index]
|
||||
}
|
||||
})
|
||||
return obj
|
||||
}
|
||||
|
||||
export function getTargetByPath(origin, path) {
|
||||
const arr = path.replace(/]/g, '').replace(/\[/g, '.').split('.')
|
||||
let current = origin
|
||||
for (let i = 0, len = arr.length; i < len; i++) {
|
||||
current = current[arr[i]]
|
||||
}
|
||||
return current
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
import Component from '../component'
|
||||
import { getUse } from '../util'
|
||||
import { getPath } from '../define'
|
||||
/** Retains a pool of Components for re-use, keyed on component name.
|
||||
* Note: since component names are not unique or even necessarily available, these are primarily a form of sharding.
|
||||
* @private
|
||||
*/
|
||||
const components = {}
|
||||
|
||||
/** Reclaim a component for later re-use by the recycler. */
|
||||
export function collectComponent(component) {
|
||||
let name = component.constructor.name
|
||||
;(components[name] || (components[name] = [])).push(component)
|
||||
}
|
||||
|
||||
/** Create a component. Normalizes differences between PFC's and classful Components. */
|
||||
export function createComponent(Ctor, props, context, vnode) {
|
||||
let list = components[Ctor.name],
|
||||
inst
|
||||
|
||||
if (Ctor.prototype && Ctor.prototype.render) {
|
||||
inst = new Ctor(props, context)
|
||||
Component.call(inst, props, context)
|
||||
} else {
|
||||
inst = new Component(props, context)
|
||||
inst.constructor = Ctor
|
||||
inst.render = doRender
|
||||
}
|
||||
vnode && (inst.scopedCssAttr = vnode.css)
|
||||
|
||||
if ( inst.store && inst.store.data) {
|
||||
if(inst.constructor.use){
|
||||
inst.use = getUse(inst.store.data, inst.constructor.use)
|
||||
inst.store.instances.push(inst)
|
||||
} else if(inst.initUse){
|
||||
const use = inst.initUse()
|
||||
inst._updatePath = getPath(use)
|
||||
inst.use = getUse(inst.store.data, use)
|
||||
inst.store.instances.push(inst)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (list) {
|
||||
for (let i = list.length; i--; ) {
|
||||
if (list[i].constructor === Ctor) {
|
||||
inst.nextBase = list[i].nextBase
|
||||
list.splice(i, 1)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return inst
|
||||
}
|
||||
|
||||
/** The `.render()` method for a PFC backing instance. */
|
||||
function doRender(props, data, context) {
|
||||
return this.constructor(props, context)
|
||||
}
|
|
@ -1,355 +0,0 @@
|
|||
import {
|
||||
SYNC_RENDER,
|
||||
NO_RENDER,
|
||||
FORCE_RENDER,
|
||||
ASYNC_RENDER,
|
||||
ATTR_KEY
|
||||
} from '../constants'
|
||||
import options from '../options'
|
||||
import { extend, applyRef } from '../util'
|
||||
import { enqueueRender } from '../render-queue'
|
||||
import { getNodeProps } from './index'
|
||||
import {
|
||||
diff,
|
||||
mounts,
|
||||
diffLevel,
|
||||
flushMounts,
|
||||
recollectNodeTree,
|
||||
removeChildren
|
||||
} from './diff'
|
||||
import { createComponent, collectComponent } from './component-recycler'
|
||||
import { removeNode } from '../dom/index'
|
||||
import {
|
||||
addScopedAttrStatic,
|
||||
getCtorName,
|
||||
scopeHost
|
||||
} from '../style'
|
||||
import { proxyUpdate } from '../observe'
|
||||
|
||||
/** Set a component's `props` (generally derived from JSX attributes).
|
||||
* @param {Object} props
|
||||
* @param {Object} [opts]
|
||||
* @param {boolean} [opts.renderSync=false] If `true` and {@link options.syncComponentUpdates} is `true`, triggers synchronous rendering.
|
||||
* @param {boolean} [opts.render=true] If `false`, no render will be triggered.
|
||||
*/
|
||||
export function setComponentProps(component, props, opts, context, mountAll) {
|
||||
if (component._disable) return
|
||||
component._disable = true
|
||||
|
||||
if ((component.__ref = props.ref)) delete props.ref
|
||||
if ((component.__key = props.key)) delete props.key
|
||||
|
||||
if (!component.base || mountAll) {
|
||||
if (component.beforeInstall) component.beforeInstall()
|
||||
if (component.install) component.install()
|
||||
if (component.constructor.observe) {
|
||||
proxyUpdate(component)
|
||||
}
|
||||
}
|
||||
|
||||
if (context && context !== component.context) {
|
||||
if (!component.prevContext) component.prevContext = component.context
|
||||
component.context = context
|
||||
}
|
||||
|
||||
if (!component.prevProps) component.prevProps = component.props
|
||||
component.props = props
|
||||
|
||||
component._disable = false
|
||||
|
||||
if (opts !== NO_RENDER) {
|
||||
if (
|
||||
opts === SYNC_RENDER ||
|
||||
options.syncComponentUpdates !== false ||
|
||||
!component.base
|
||||
) {
|
||||
renderComponent(component, SYNC_RENDER, mountAll)
|
||||
} else {
|
||||
enqueueRender(component)
|
||||
}
|
||||
}
|
||||
|
||||
applyRef(component.__ref, component)
|
||||
}
|
||||
|
||||
function shallowComparison(old, attrs) {
|
||||
let name
|
||||
|
||||
for (name in old) {
|
||||
if (attrs[name] == null && old[name] != null) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if (old.children.length > 0 || attrs.children.length > 0) {
|
||||
return true
|
||||
}
|
||||
|
||||
for (name in attrs) {
|
||||
if (name != 'children') {
|
||||
let type = typeof attrs[name]
|
||||
if (type == 'function' || type == 'object') {
|
||||
return true
|
||||
} else if (attrs[name] != old[name]) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Render a Component, triggering necessary lifecycle events and taking High-Order Components into account.
|
||||
* @param {Component} component
|
||||
* @param {Object} [opts]
|
||||
* @param {boolean} [opts.build=false] If `true`, component will build and store a DOM node if not already associated with one.
|
||||
* @private
|
||||
*/
|
||||
export function renderComponent(component, opts, mountAll, isChild) {
|
||||
if (component._disable) return
|
||||
|
||||
let props = component.props,
|
||||
data = component.data,
|
||||
context = component.context,
|
||||
previousProps = component.prevProps || props,
|
||||
previousState = component.prevState || data,
|
||||
previousContext = component.prevContext || context,
|
||||
isUpdate = component.base,
|
||||
nextBase = component.nextBase,
|
||||
initialBase = isUpdate || nextBase,
|
||||
initialChildComponent = component._component,
|
||||
skip = false,
|
||||
rendered,
|
||||
inst,
|
||||
cbase
|
||||
|
||||
// if updating
|
||||
if (isUpdate) {
|
||||
component.props = previousProps
|
||||
component.data = previousState
|
||||
component.context = previousContext
|
||||
if (component.store || opts == FORCE_RENDER || shallowComparison(previousProps, props)) {
|
||||
let receiveResult = true
|
||||
if (component.receiveProps) {
|
||||
receiveResult = component.receiveProps(props, previousProps)
|
||||
}
|
||||
if (receiveResult !== false) {
|
||||
skip = false
|
||||
if (component.beforeUpdate) {
|
||||
component.beforeUpdate(props, data, context)
|
||||
}
|
||||
} else {
|
||||
skip = true
|
||||
}
|
||||
} else {
|
||||
skip = true
|
||||
}
|
||||
component.props = props
|
||||
component.data = data
|
||||
component.context = context
|
||||
}
|
||||
|
||||
component.prevProps = component.prevState = component.prevContext = component.nextBase = null
|
||||
|
||||
if (!skip) {
|
||||
component.beforeRender && component.beforeRender()
|
||||
rendered = component.render(props, data, context)
|
||||
|
||||
//don't rerender
|
||||
if (component.constructor.css || component.css) {
|
||||
addScopedAttrStatic(
|
||||
rendered,
|
||||
'_s' + getCtorName(component.constructor)
|
||||
)
|
||||
}
|
||||
|
||||
scopeHost(rendered, component.scopedCssAttr)
|
||||
|
||||
// context to pass to the child, can be updated via (grand-)parent component
|
||||
if (component.getChildContext) {
|
||||
context = extend(extend({}, context), component.getChildContext())
|
||||
}
|
||||
|
||||
let childComponent = rendered && rendered.nodeName,
|
||||
toUnmount,
|
||||
base,
|
||||
ctor = options.mapping[childComponent]
|
||||
|
||||
if (ctor) {
|
||||
// set up high order component link
|
||||
|
||||
let childProps = getNodeProps(rendered)
|
||||
inst = initialChildComponent
|
||||
|
||||
if (inst && inst.constructor === ctor && childProps.key == inst.__key) {
|
||||
setComponentProps(inst, childProps, SYNC_RENDER, context, false)
|
||||
} else {
|
||||
toUnmount = inst
|
||||
|
||||
component._component = inst = createComponent(ctor, childProps, context)
|
||||
inst.nextBase = inst.nextBase || nextBase
|
||||
inst._parentComponent = component
|
||||
setComponentProps(inst, childProps, NO_RENDER, context, false)
|
||||
renderComponent(inst, SYNC_RENDER, mountAll, true)
|
||||
}
|
||||
|
||||
base = inst.base
|
||||
} else {
|
||||
cbase = initialBase
|
||||
|
||||
// destroy high order component link
|
||||
toUnmount = initialChildComponent
|
||||
if (toUnmount) {
|
||||
cbase = component._component = null
|
||||
}
|
||||
|
||||
if (initialBase || opts === SYNC_RENDER) {
|
||||
if (cbase) cbase._component = null
|
||||
base = diff(
|
||||
cbase,
|
||||
rendered,
|
||||
context,
|
||||
mountAll || !isUpdate,
|
||||
initialBase && initialBase.parentNode,
|
||||
true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (initialBase && base !== initialBase && inst !== initialChildComponent) {
|
||||
let baseParent = initialBase.parentNode
|
||||
if (baseParent && base !== baseParent) {
|
||||
baseParent.replaceChild(base, initialBase)
|
||||
|
||||
if (!toUnmount) {
|
||||
initialBase._component = null
|
||||
recollectNodeTree(initialBase, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (toUnmount) {
|
||||
unmountComponent(toUnmount)
|
||||
}
|
||||
|
||||
component.base = base
|
||||
if (base && !isChild) {
|
||||
let componentRef = component,
|
||||
t = component
|
||||
while ((t = t._parentComponent)) {
|
||||
;(componentRef = t).base = base
|
||||
}
|
||||
base._component = componentRef
|
||||
base._componentConstructor = componentRef.constructor
|
||||
}
|
||||
}
|
||||
|
||||
if (!isUpdate || mountAll) {
|
||||
mounts.unshift(component)
|
||||
} else if (!skip) {
|
||||
// Ensure that pending componentDidMount() hooks of child components
|
||||
// are called before the componentDidUpdate() hook in the parent.
|
||||
// Note: disabled as it causes duplicate hooks, see https://github.com/developit/preact/issues/750
|
||||
// flushMounts();
|
||||
|
||||
if (component.afterUpdate) {
|
||||
//deprecated
|
||||
component.afterUpdate(previousProps, previousState, previousContext)
|
||||
}
|
||||
if (component.updated) {
|
||||
component.updated(previousProps, previousState, previousContext)
|
||||
}
|
||||
if (options.afterUpdate) options.afterUpdate(component)
|
||||
}
|
||||
|
||||
if (component._renderCallbacks != null) {
|
||||
while (component._renderCallbacks.length)
|
||||
component._renderCallbacks.pop().call(component)
|
||||
}
|
||||
|
||||
if (!diffLevel && !isChild) flushMounts()
|
||||
}
|
||||
|
||||
/** Apply the Component referenced by a VNode to the DOM.
|
||||
* @param {Element} dom The DOM node to mutate
|
||||
* @param {VNode} vnode A Component-referencing VNode
|
||||
* @returns {Element} dom The created/mutated element
|
||||
* @private
|
||||
*/
|
||||
export function buildComponentFromVNode(dom, vnode, context, mountAll) {
|
||||
let c = dom && dom._component,
|
||||
originalComponent = c,
|
||||
oldDom = dom,
|
||||
isDirectOwner = c && dom._componentConstructor === vnode.nodeName,
|
||||
isOwner = isDirectOwner,
|
||||
props = getNodeProps(vnode)
|
||||
while (c && !isOwner && (c = c._parentComponent)) {
|
||||
isOwner = c.constructor === vnode.nodeName
|
||||
}
|
||||
|
||||
if (c && isOwner && (!mountAll || c._component)) {
|
||||
setComponentProps(c, props, ASYNC_RENDER, context, mountAll)
|
||||
dom = c.base
|
||||
} else {
|
||||
if (originalComponent && !isDirectOwner) {
|
||||
unmountComponent(originalComponent)
|
||||
dom = oldDom = null
|
||||
}
|
||||
|
||||
c = createComponent(vnode.nodeName, props, context, vnode)
|
||||
if (dom && !c.nextBase) {
|
||||
c.nextBase = dom
|
||||
// passing dom/oldDom as nextBase will recycle it if unused, so bypass recycling on L229:
|
||||
oldDom = null
|
||||
}
|
||||
setComponentProps(c, props, SYNC_RENDER, context, mountAll)
|
||||
dom = c.base
|
||||
|
||||
if (oldDom && dom !== oldDom) {
|
||||
oldDom._component = null
|
||||
recollectNodeTree(oldDom, false)
|
||||
}
|
||||
}
|
||||
|
||||
return dom
|
||||
}
|
||||
|
||||
/** Remove a component from the DOM and recycle it.
|
||||
* @param {Component} component The Component instance to unmount
|
||||
* @private
|
||||
*/
|
||||
export function unmountComponent(component) {
|
||||
if (options.beforeUnmount) options.beforeUnmount(component)
|
||||
|
||||
let base = component.base
|
||||
|
||||
component._disable = true
|
||||
|
||||
if (component.uninstall) component.uninstall()
|
||||
|
||||
if (component.store && component.store.instances) {
|
||||
for (let i = 0, len = component.store.instances.length; i < len; i++) {
|
||||
if (component.store.instances[i] === component) {
|
||||
component.store.instances.splice(i, 1)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component.base = null
|
||||
|
||||
// recursively tear down & recollect high-order component children:
|
||||
let inner = component._component
|
||||
if (inner) {
|
||||
unmountComponent(inner)
|
||||
} else if (base) {
|
||||
if (base[ATTR_KEY] != null) applyRef(base[ATTR_KEY].ref, null)
|
||||
|
||||
component.nextBase = base
|
||||
|
||||
removeNode(base)
|
||||
collectComponent(component)
|
||||
|
||||
removeChildren(base)
|
||||
}
|
||||
|
||||
applyRef(component.__ref, null)
|
||||
}
|
|
@ -1,365 +0,0 @@
|
|||
import { ATTR_KEY } from '../constants'
|
||||
import { isSameNodeType, isNamedNode } from './index'
|
||||
import { buildComponentFromVNode } from './component'
|
||||
import { createNode, setAccessor } from '../dom/index'
|
||||
import { unmountComponent } from './component'
|
||||
import options from '../options'
|
||||
import { applyRef } from '../util'
|
||||
import { removeNode } from '../dom/index'
|
||||
import { isArray } from '../util'
|
||||
import { draw } from '../../cax/draw'
|
||||
/** Queue of components that have been mounted and are awaiting componentDidMount */
|
||||
export const mounts = []
|
||||
|
||||
/** Diff recursion count, used to track the end of the diff cycle. */
|
||||
export let diffLevel = 0
|
||||
|
||||
/** Global flag indicating if the diff is currently within an SVG */
|
||||
let isSvgMode = false
|
||||
|
||||
/** Global flag indicating if the diff is performing hydration */
|
||||
let hydrating = false
|
||||
|
||||
/** Invoke queued componentDidMount lifecycle methods */
|
||||
export function flushMounts() {
|
||||
let c
|
||||
while ((c = mounts.pop())) {
|
||||
if (options.afterMount) options.afterMount(c)
|
||||
if (c.installed) c.installed()
|
||||
}
|
||||
}
|
||||
|
||||
/** Apply differences in a given vnode (and it's deep children) to a real DOM Node.
|
||||
* @param {Element} [dom=null] A DOM node to mutate into the shape of the `vnode`
|
||||
* @param {VNode} vnode A VNode (with descendants forming a tree) representing the desired DOM structure
|
||||
* @returns {Element} dom The created/mutated element
|
||||
* @private
|
||||
*/
|
||||
export function diff(dom, vnode, context, mountAll, parent, componentRoot, fromRender) {
|
||||
// diffLevel having been 0 here indicates initial entry into the diff (not a subdiff)
|
||||
if (!diffLevel++) {
|
||||
// when first starting the diff, check if we're diffing an SVG or within an SVG
|
||||
isSvgMode = parent != null && parent.ownerSVGElement !== undefined
|
||||
|
||||
// hydration is indicated by the existing element to be diffed not having a prop cache
|
||||
hydrating = dom != null && !(ATTR_KEY in dom)
|
||||
}
|
||||
let ret
|
||||
|
||||
if (isArray(vnode)) {
|
||||
vnode = {
|
||||
nodeName: 'span',
|
||||
children: vnode
|
||||
}
|
||||
}
|
||||
|
||||
ret = idiff(dom, vnode, context, mountAll, componentRoot)
|
||||
// append the element if its a new parent
|
||||
if (parent && ret.parentNode !== parent) {
|
||||
if (fromRender) {
|
||||
parent.appendChild(draw(ret))
|
||||
} else {
|
||||
parent.appendChild(ret)
|
||||
}
|
||||
}
|
||||
|
||||
// diffLevel being reduced to 0 means we're exiting the diff
|
||||
if (!--diffLevel) {
|
||||
hydrating = false
|
||||
// invoke queued componentDidMount lifecycle methods
|
||||
if (!componentRoot) flushMounts()
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
/** Internals of `diff()`, separated to allow bypassing diffLevel / mount flushing. */
|
||||
function idiff(dom, vnode, context, mountAll, componentRoot) {
|
||||
let out = dom,
|
||||
prevSvgMode = isSvgMode
|
||||
|
||||
// empty values (null, undefined, booleans) render as empty Text nodes
|
||||
if (vnode == null || typeof vnode === 'boolean') vnode = ''
|
||||
|
||||
// If the VNode represents a Component, perform a component diff:
|
||||
let vnodeName = vnode.nodeName
|
||||
if (options.mapping[vnodeName]) {
|
||||
vnode.nodeName = options.mapping[vnodeName]
|
||||
return buildComponentFromVNode(dom, vnode, context, mountAll)
|
||||
}
|
||||
if (typeof vnodeName == 'function') {
|
||||
return buildComponentFromVNode(dom, vnode, context, mountAll)
|
||||
}
|
||||
|
||||
// Fast case: Strings & Numbers create/update Text nodes.
|
||||
if (typeof vnode === 'string' || typeof vnode === 'number') {
|
||||
// update if it's already a Text node:
|
||||
if (
|
||||
dom &&
|
||||
dom.splitText !== undefined &&
|
||||
dom.parentNode &&
|
||||
(!dom._component || componentRoot)
|
||||
) {
|
||||
/* istanbul ignore if */ /* Browser quirk that can't be covered: https://github.com/developit/preact/commit/fd4f21f5c45dfd75151bd27b4c217d8003aa5eb9 */
|
||||
if (dom.nodeValue != vnode) {
|
||||
dom.nodeValue = vnode
|
||||
}
|
||||
} else {
|
||||
// it wasn't a Text node: replace it with one and recycle the old Element
|
||||
out = options.doc.createTextNode(vnode)
|
||||
if (dom) {
|
||||
if (dom.parentNode) dom.parentNode.replaceChild(out, dom)
|
||||
recollectNodeTree(dom, true)
|
||||
}
|
||||
}
|
||||
|
||||
//ie8 error
|
||||
try {
|
||||
out[ATTR_KEY] = true
|
||||
} catch (e) {}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// Tracks entering and exiting SVG namespace when descending through the tree.
|
||||
isSvgMode =
|
||||
vnodeName === 'svg'
|
||||
? true
|
||||
: vnodeName === 'foreignObject'
|
||||
? false
|
||||
: isSvgMode
|
||||
|
||||
// If there's no existing element or it's the wrong type, create a new one:
|
||||
vnodeName = String(vnodeName)
|
||||
if (!dom || !isNamedNode(dom, vnodeName)) {
|
||||
out = createNode(vnodeName, isSvgMode)
|
||||
|
||||
if (dom) {
|
||||
// move children into the replacement node
|
||||
while (dom.firstChild) out.appendChild(dom.firstChild)
|
||||
|
||||
// if the previous Element was mounted into the DOM, replace it inline
|
||||
if (dom.parentNode) dom.parentNode.replaceChild(out, dom)
|
||||
|
||||
// recycle the old element (skips non-Element node types)
|
||||
recollectNodeTree(dom, true)
|
||||
}
|
||||
}
|
||||
|
||||
let fc = out.firstChild,
|
||||
props = out[ATTR_KEY],
|
||||
vchildren = vnode.children
|
||||
|
||||
if (props == null) {
|
||||
props = out[ATTR_KEY] = {}
|
||||
for (let a = out.attributes, i = a.length; i--; )
|
||||
props[a[i].name] = a[i].value
|
||||
}
|
||||
|
||||
// Optimization: fast-path for elements containing a single TextNode:
|
||||
if (
|
||||
!hydrating &&
|
||||
vchildren &&
|
||||
vchildren.length === 1 &&
|
||||
typeof vchildren[0] === 'string' &&
|
||||
fc != null &&
|
||||
fc.splitText !== undefined &&
|
||||
fc.nextSibling == null
|
||||
) {
|
||||
if (fc.nodeValue != vchildren[0]) {
|
||||
fc.nodeValue = vchildren[0]
|
||||
//update rendering obj
|
||||
fc._renderText.text = fc.nodeValue
|
||||
}
|
||||
}
|
||||
// otherwise, if there are existing or new children, diff them:
|
||||
else if ((vchildren && vchildren.length) || fc != null) {
|
||||
innerDiffNode(
|
||||
out,
|
||||
vchildren,
|
||||
context,
|
||||
mountAll,
|
||||
hydrating || props.dangerouslySetInnerHTML != null
|
||||
)
|
||||
}
|
||||
|
||||
// Apply attributes/props from VNode to the DOM Element:
|
||||
diffAttributes(out, vnode.attributes, props)
|
||||
|
||||
// restore previous SVG mode: (in case we're exiting an SVG namespace)
|
||||
isSvgMode = prevSvgMode
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
/** Apply child and attribute changes between a VNode and a DOM Node to the DOM.
|
||||
* @param {Element} dom Element whose children should be compared & mutated
|
||||
* @param {Array} vchildren Array of VNodes to compare to `dom.childNodes`
|
||||
* @param {Object} context Implicitly descendant context object (from most recent `getChildContext()`)
|
||||
* @param {Boolean} mountAll
|
||||
* @param {Boolean} isHydrating If `true`, consumes externally created elements similar to hydration
|
||||
*/
|
||||
function innerDiffNode(dom, vchildren, context, mountAll, isHydrating) {
|
||||
let originalChildren = dom.childNodes,
|
||||
children = [],
|
||||
keyed = {},
|
||||
keyedLen = 0,
|
||||
min = 0,
|
||||
len = originalChildren.length,
|
||||
childrenLen = 0,
|
||||
vlen = vchildren ? vchildren.length : 0,
|
||||
j,
|
||||
c,
|
||||
f,
|
||||
vchild,
|
||||
child
|
||||
|
||||
// Build up a map of keyed children and an Array of unkeyed children:
|
||||
if (len !== 0) {
|
||||
for (let i = 0; i < len; i++) {
|
||||
let child = originalChildren[i],
|
||||
props = child[ATTR_KEY],
|
||||
key =
|
||||
vlen && props
|
||||
? child._component
|
||||
? child._component.__key
|
||||
: props.key
|
||||
: null
|
||||
if (key != null) {
|
||||
keyedLen++
|
||||
keyed[key] = child
|
||||
} else if (
|
||||
props ||
|
||||
(child.splitText !== undefined
|
||||
? isHydrating
|
||||
? child.nodeValue.trim()
|
||||
: true
|
||||
: isHydrating)
|
||||
) {
|
||||
children[childrenLen++] = child
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (vlen !== 0) {
|
||||
for (let i = 0; i < vlen; i++) {
|
||||
vchild = vchildren[i]
|
||||
child = null
|
||||
|
||||
// attempt to find a node based on key matching
|
||||
let key = vchild.key
|
||||
if (key != null) {
|
||||
if (keyedLen && keyed[key] !== undefined) {
|
||||
child = keyed[key]
|
||||
keyed[key] = undefined
|
||||
keyedLen--
|
||||
}
|
||||
}
|
||||
// attempt to pluck a node of the same type from the existing children
|
||||
else if (!child && min < childrenLen) {
|
||||
for (j = min; j < childrenLen; j++) {
|
||||
if (
|
||||
children[j] !== undefined &&
|
||||
isSameNodeType((c = children[j]), vchild, isHydrating)
|
||||
) {
|
||||
child = c
|
||||
children[j] = undefined
|
||||
if (j === childrenLen - 1) childrenLen--
|
||||
if (j === min) min++
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// morph the matched/found/created DOM child to match vchild (deep)
|
||||
child = idiff(child, vchild, context, mountAll)
|
||||
|
||||
f = originalChildren[i]
|
||||
if (child && child !== dom && child !== f) {
|
||||
if (f == null) {
|
||||
dom.appendChild(child)
|
||||
} else if (child === f.nextSibling) {
|
||||
removeNode(f)
|
||||
} else {
|
||||
dom.insertBefore(child, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove unused keyed children:
|
||||
if (keyedLen) {
|
||||
for (let i in keyed)
|
||||
if (keyed[i] !== undefined) recollectNodeTree(keyed[i], false)
|
||||
}
|
||||
|
||||
// remove orphaned unkeyed children:
|
||||
while (min <= childrenLen) {
|
||||
if ((child = children[childrenLen--]) !== undefined)
|
||||
recollectNodeTree(child, false)
|
||||
}
|
||||
}
|
||||
|
||||
/** Recursively recycle (or just unmount) a node and its descendants.
|
||||
* @param {Node} node DOM node to start unmount/removal from
|
||||
* @param {Boolean} [unmountOnly=false] If `true`, only triggers unmount lifecycle, skips removal
|
||||
*/
|
||||
export function recollectNodeTree(node, unmountOnly) {
|
||||
let component = node._component
|
||||
if (component) {
|
||||
// if node is owned by a Component, unmount that component (ends up recursing back here)
|
||||
unmountComponent(component)
|
||||
} else {
|
||||
// If the node's VNode had a ref function, invoke it with null here.
|
||||
// (this is part of the React spec, and smart for unsetting references)
|
||||
if (node[ATTR_KEY] != null) applyRef(node[ATTR_KEY].ref, null)
|
||||
|
||||
if (unmountOnly === false || node[ATTR_KEY] == null) {
|
||||
removeNode(node)
|
||||
}
|
||||
|
||||
removeChildren(node)
|
||||
}
|
||||
}
|
||||
|
||||
/** Recollect/unmount all children.
|
||||
* - we use .lastChild here because it causes less reflow than .firstChild
|
||||
* - it's also cheaper than accessing the .childNodes Live NodeList
|
||||
*/
|
||||
export function removeChildren(node) {
|
||||
node = node.lastChild
|
||||
while (node) {
|
||||
let next = node.previousSibling
|
||||
recollectNodeTree(node, true)
|
||||
node = next
|
||||
}
|
||||
}
|
||||
|
||||
/** Apply differences in attributes from a VNode to the given DOM Element.
|
||||
* @param {Element} dom Element with attributes to diff `attrs` against
|
||||
* @param {Object} attrs The desired end-state key-value attribute pairs
|
||||
* @param {Object} old Current/previous attributes (from previous VNode or element's prop cache)
|
||||
*/
|
||||
function diffAttributes(dom, attrs, old) {
|
||||
let name
|
||||
|
||||
// remove attributes no longer present on the vnode by setting them to undefined
|
||||
for (name in old) {
|
||||
if (!(attrs && attrs[name] != null) && old[name] != null) {
|
||||
setAccessor(dom, name, old[name], (old[name] = undefined), isSvgMode)
|
||||
}
|
||||
}
|
||||
|
||||
// add new & update changed attributes
|
||||
for (name in attrs) {
|
||||
if (
|
||||
name !== 'children' &&
|
||||
name !== 'innerHTML' &&
|
||||
(!(name in old) ||
|
||||
attrs[name] !==
|
||||
(name === 'value' || name === 'checked' ? dom[name] : old[name]))
|
||||
) {
|
||||
setAccessor(dom, name, old[name], (old[name] = attrs[name]), isSvgMode)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
import { extend } from '../util'
|
||||
import options from '../options'
|
||||
|
||||
const mapping = options.mapping
|
||||
/**
|
||||
* Check if two nodes are equivalent.
|
||||
*
|
||||
* @param {Node} node DOM Node to compare
|
||||
* @param {VNode} vnode Virtual DOM node to compare
|
||||
* @param {boolean} [hydrating=false] If true, ignores component constructors when comparing.
|
||||
* @private
|
||||
*/
|
||||
export function isSameNodeType(node, vnode, hydrating) {
|
||||
if (typeof vnode === 'string' || typeof vnode === 'number') {
|
||||
return node.splitText !== undefined
|
||||
}
|
||||
if (typeof vnode.nodeName === 'string') {
|
||||
var ctor = mapping[vnode.nodeName]
|
||||
if (ctor) {
|
||||
return hydrating || node._componentConstructor === ctor
|
||||
}
|
||||
return !node._componentConstructor && isNamedNode(node, vnode.nodeName)
|
||||
}
|
||||
return hydrating || node._componentConstructor === vnode.nodeName
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an Element has a given nodeName, case-insensitively.
|
||||
*
|
||||
* @param {Element} node A DOM Element to inspect the name of.
|
||||
* @param {String} nodeName Unnormalized name to compare against.
|
||||
*/
|
||||
export function isNamedNode(node, nodeName) {
|
||||
return (
|
||||
node.normalizedNodeName === nodeName ||
|
||||
node.nodeName.toLowerCase() === nodeName.toLowerCase()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Reconstruct Component-style `props` from a VNode.
|
||||
* Ensures default/fallback values from `defaultProps`:
|
||||
* Own-properties of `defaultProps` not present in `vnode.attributes` are added.
|
||||
*
|
||||
* @param {VNode} vnode
|
||||
* @returns {Object} props
|
||||
*/
|
||||
export function getNodeProps(vnode) {
|
||||
let props = extend({}, vnode.attributes)
|
||||
props.children = vnode.children
|
||||
|
||||
let defaultProps = vnode.nodeName.defaultProps
|
||||
if (defaultProps !== undefined) {
|
||||
for (let i in defaultProps) {
|
||||
if (props[i] === undefined) {
|
||||
props[i] = defaultProps[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return props
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
import layout from './layout/layout-node'
|
||||
|
||||
export function render(node){
|
||||
console.log(layout(node()))
|
||||
}
|
Loading…
Reference in New Issue