* Hook & Fun style
* Remove core of omi
* Update demos
This commit is contained in:
dntzhang 2019-07-20 13:13:01 +08:00
parent a54b093788
commit b482731dda
43 changed files with 129 additions and 8427 deletions

View File

@ -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

View File

@ -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或者局部 storedata全放这里组件没有私有 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

View File

@ -1,10 +0,0 @@
<html>
<head></head>
<body>
<script src="b.js"></script>
</body>
</html>

View File

@ -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')

View File

@ -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
}

View File

@ -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) }
}
}

View File

@ -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
)
}

View File

@ -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() {}
}

View File

@ -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

View File

@ -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)
}
})
}

View File

@ -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 }))
}
}

View File

@ -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
}
}
}
}

View File

@ -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.

View File

@ -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)
}
}

View File

@ -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()
})
}
}

View File

@ -1,6 +0,0 @@
import Document from './document'
export default {
document: new Document(0)
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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

View File

@ -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()
}
})
}

View File

@ -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;
}
}
}

View File

@ -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
}

View File

@ -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;

View File

@ -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) { }
}

View File

@ -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)
}
}

View File

@ -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, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;');
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;
}

View File

@ -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)
}

View File

@ -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'
})
}

View File

@ -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] = ''
}
}
}

View File

@ -1,7 +0,0 @@
import { define } from './define'
export function tag(name) {
return function(target) {
define(name, target)
}
}

View File

@ -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 })
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}
}
}

View File

@ -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
}

View File

@ -0,0 +1,5 @@
import layout from './layout/layout-node'
export function render(node){
console.log(layout(node()))
}