lib/preact.rb in isomorfeus-preact-23.9.0.rc5 vs lib/preact.rb in isomorfeus-preact-23.9.0.rc6
- old
+ new
@@ -1,75 +1,72 @@
# backtick_javascript: true
# helpers: hash_get, hash_put
if RUBY_ENGINE == 'opal'
- class VNode
- # just a empty place holder to make is_a?(VNode) work
- # internally using the js implementation
+ %x{
+ let vnodeId = 0;
+
+ function vnode_eql(me, other) {
+ for(let prop in me) {
+ if (prop === 'props' && !(me[prop]["$=="](other[prop]))) {
+ return false;
+ } else if (me[prop] != other[prop]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ class VNode {
+ constructor(type, props, key, ref, original) {
+ this.type = type;
+ this.props = props;
+ this.key = key;
+ this.ref = ref;
+ this._children = null;
+ this._parent = null;
+ this._depth = 0;
+ this._dom = null;
+ this._nextDom = undefined;
+ this._component = null;
+ this._hydrating = null;
+ this._original = (original == null || original == nil) ? ++vnodeId : original;
+ this.constructor = undefined;
+ }
+ "$=="(other) { return vnode_eql(this, other); }
+ "$eql?"(other) { return vnode_eql(this, other); }
+ "$is_a?"(t) { return t === Opal.VNode; }
+ "$type"() { return this.type; }
+ "$props"() { return this.props; }
+ "$key"() { return this.key; }
+ "$ref"() { return this.ref; }
+ }
+ }
+ class VNode < `VNode`
+ def self.new(type, props, key, ref, original)
+ return `new VNode(type, props, key, ref, original)`
+ end
end
end
class Fragment
def initialize(props, _context)
@props = props
end
- if RUBY_ENGINE == 'opal'
- def render
- `Opal.Preact.render_buffer.pop()`
- children = @props[:children]
- `Opal.Preact.render_buffer.push(children.$$is_array ? children : [children])`
- nil
- end
- else
- def render
- ::Preact.render_buffer.pop
- ::Preact.render_buffer.push(@props[:children])
- end
+ def render
+ ::Preact.render_buffer.pop
+ ::Preact.render_buffer.push(@props[:children])
end
end
module Preact
EMPTY_ARR = []
UNSAFE_NAME = /[\s\n\\\/='"\0<>]/
if RUBY_ENGINE == 'opal'
%x{
- let vnodeId = 0;
-
- function vnode_eql(me, other) {
- for(let prop in me) {
- if (prop === 'props' && !(me[prop]["$=="](other[prop]))) {
- return false;
- } else if (me[prop] != other[prop]) {
- return false;
- }
- }
- return true;
- }
-
- class VNode {
- constructor(type, props, key, ref, original) {
- this.type = type;
- this.props = props;
- this.key = key;
- this.ref = ref;
- this._children = null;
- this._parent = null;
- this._depth = 0;
- this._dom = null;
- this._nextDom = undefined;
- this._component = null;
- this._hydrating = null;
- this._original = (original == null) ? ++vnodeId : original;
- this.constructor = undefined;
- }
- "$=="(other) { return vnode_eql(this, other); }
- "$eql?"(other) { return vnode_eql(this, other); }
- "$is_a?"(t) { return t === Opal.VNode; }
- }
-
function _catchError(error, vnode, oldVNode) {
let component, ctor, handled;
for (; (vnode = vnode._parent); ) {
if ((component = vnode._component) && !component._processingException) {
@@ -95,16 +92,16 @@
}
throw error;
}
- const EMPTY_OBJ = new VNode();
+ const EMPTY_VNODE = new VNode();
const EMPTY_ARR = [];
const slice = EMPTY_ARR.slice;
function hash_fetch(hash, key) {
- let val = $hash_get(hash, key);
+ let val = hash.get(key);
return (val === undefined || val === null) ? nil : val;
}
function assign(obj, props) {
for (let i in props) obj[i] = props[i];
@@ -295,21 +292,21 @@
oldDom,
isHydrating
) {
let i, j, oldVNode, childVNode, newDom, firstChildDom, refs;
- // This is a compression of oldParentVNode!=null && oldParentVNode != EMPTY_OBJ && oldParentVNode._children || EMPTY_ARR
- // as EMPTY_OBJ._children should be `undefined`.
+ // This is a compression of oldParentVNode!=null && oldParentVNode != EMPTY_VNODE && oldParentVNode._children || EMPTY_ARR
+ // as EMPTY_VNODE._children should be `undefined`.
let oldChildren = (oldParentVNode && oldParentVNode !== nil && oldParentVNode._children) ? oldParentVNode._children : EMPTY_ARR;
let oldChildrenLength = oldChildren.length;
newParentVNode._children = [];
for (i = 0; i < renderResult.length; i++) {
childVNode = renderResult[i];
- if (childVNode === nil || childVNode == null || typeof childVNode === 'boolean' || childVNode.$$is_boolean) {
+ if (childVNode === nil || childVNode == null || typeof childVNode === 'boolean' || childVNode.$$is_boolean || typeof childVNode === 'number' || childVNode.$$is_number) {
childVNode = newParentVNode._children[i] = null;
}
// If this newVNode is being reused (e.g. <div>{reuse}{reuse}</div>) in the same diff,
// or we are rendering a component (e.g. setState) copy the oldVNodes so it can have
// it's own DOM & etc. pointers
@@ -331,11 +328,11 @@
str
);
} else if (childVNode.$$is_array) {
childVNode = newParentVNode._children[i] = new VNode(
Opal.Fragment,
- #{{ children: `childVNode` }},
+ new Map([['children', childVNode]]),
null,
null,
null
);
} else if (childVNode._depth > 0) {
@@ -355,10 +352,11 @@
}
if (childVNode === nil || childVNode == null) {
continue;
}
+
childVNode._parent = newParentVNode;
childVNode._depth = newParentVNode._depth + 1;
// Check if we find a corresponding element in oldChildren.
// If found, delete the array item by setting to `undefined`.
@@ -390,11 +388,11 @@
}
oldVNode = null;
}
}
- oldVNode = (oldVNode && oldVNode !== nil) ? oldVNode : EMPTY_OBJ;
+ oldVNode = (oldVNode && oldVNode !== nil) ? oldVNode : EMPTY_VNODE;
// Morph the old element into the new one, but don't append it to the dom yet
diff(
parentDom,
childVNode,
@@ -790,11 +788,11 @@
function validate_props(newType, newProps) {
if (newType.declared_props && newType.declared_props !== nil) {
#{
`newType.declared_props`.each do |prop, value|
- `if (value.has("default") && !newProps.has(prop)) { newProps.set(prop, value.get("default")) }`
+ `if (value.has("default") && !newProps.has(prop)) { newProps.set(prop, hash_fetch(value, "default")) }`
nil
end
}
if (Opal.Isomorfeus.development) { #{`newType`.validate_props(`newProps`)} }
}
@@ -971,11 +969,11 @@
c._pendingError = c._processingException = null;
}
c._force = false;
- } else if (
+ } else if (
excessDomChildren == null &&
newVNode._original === oldVNode._original
) {
newVNode._children = oldVNode._children;
newVNode._dom = oldVNode._dom;
@@ -1019,12 +1017,10 @@
_catchError(e, c._vnode);
}
});
}
-
-
self.createVNode = function(type, props, key, ref, original) {
// V8 seems to be better at detecting type shapes if the object is allocated from the same call site
// Do not inline into createElement and coerceToVNode!
return new VNode(type, props, key, ref, original);
}
@@ -1033,11 +1029,11 @@
// We abuse the `replaceNode` parameter in `hydrate()` to signal if we are in
// hydration mode or not by passing the `hydrate` function instead of a DOM
// element..
let isHydrating = typeof replaceNode === 'function';
- let reno = (replaceNode !== nil && replaceNode);
+ let reno = (replaceNode && replaceNode !== nil);
let nohy_reno = (!isHydrating && reno);
// To be able to support calling `render()` multiple times on the same
// DOM node, we need to obtain a reference to the previous tree. We do
// this by assigning a new `_children` property to DOM nodes which points
@@ -1047,27 +1043,35 @@
? null
: (reno && replaceNode._children) || parentDom._children;
let ov = (oldVNode && oldVNode !== nil);
- vnode = (
- nohy_reno || parentDom
- )._children = self.$create_element(Opal.Fragment, nil, [vnode]);
+ vnode = (nohy_reno ? replaceNode : parentDom)._children = self.$create_element(Opal.Fragment, nil, [vnode]);
// List of effects that need to be called after diffing.
let commitQueue = [];
+
+ // Determine the new vnode tree and store it on the DOM element on
+ // our custom `_children` property.
diff(
+ // parentDom
parentDom,
- // Determine the new vnode tree and store it on the DOM element on
- // our custom `_children` property.
+ // newVNode
vnode,
- ov ? oldVNode : EMPTY_OBJ,
+ // oldVNode
+ ov ? oldVNode : EMPTY_VNODE,
+ // globalContext
new Map(),
+ // isSvg
parentDom.ownerSVGElement !== undefined,
+ // excessDomChildren
nohy_reno ? [replaceNode] : ov ? null : parentDom.firstChild ? slice.call(parentDom.childNodes) : null,
+ // commitQueue
commitQueue,
+ // oldDom
nohy_reno ? replaceNode : ov ? oldVNode._dom : parentDom.firstChild,
+ // isHydrating
isHydrating
);
// Flush all queued effects
commitRoot(commitQueue, vnode);
@@ -1117,21 +1121,22 @@
}
}
self.process = function() {
let queue;
- while ((self.process._rerenderCount = self.rerender_queue.length)) {
+ while ((self.rerender_count = self.rerender_queue.length)) {
queue = self.rerender_queue.sort((a, b) => a._vnode._depth - b._vnode._depth);
self.rerender_queue = [];
// Don't update `renderCount` yet. Keep its value non-zero to prevent unnecessary
// process() calls from getting scheduled while `queue` is still being consumed.
queue.some(c => {
if (c._dirty) renderComponent(c);
});
}
}
- self.process._rerenderCount = 0;
+ self.rerender_count = 0;
+ self.rerender_queue = [];
}
else
IS_NON_DIMENSIONAL = /acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|^--/i.freeze
JS_TO_CSS = {}
ENCODED_ENTITIES = /[&<>"]/.freeze
@@ -1151,15 +1156,11 @@
"__cC#{self._ctxi += 1}"
end
def clone_element(vnode, props = nil, children = nil)
normalized_props = {}
- if RUBY_ENGINE == 'opal'
- normalized_props.merge!(`vnode.props`)
- else
- normalized_props.merge!(vnode.props)
- end
+ normalized_props.merge!(vnode.props)
if props
normalized_props.merge!(props)
key = normalized_props.delete(:key)
ref = normalized_props.delete(:ref)
@@ -1168,15 +1169,11 @@
ref = nil
end
normalized_props[:children] = children unless children.nil?
- if RUBY_ENGINE == 'opal'
- `self.createVNode(vnode.type, normalized_props, #{key || `vnode.key`}, #{ref || `vnode.ref`}, null)`
- else
- ::VNode.new(vnode.type, normalized_props, key || vnode.key, ref || vnode.ref)
- end
+ ::VNode.new(vnode.type, normalized_props, key || vnode.key, ref || vnode.ref)
end
def create_context(const_name, default_value = nil)
context = ::Preact::Context.new(default_value)
::Object.const_set(const_name, context)
@@ -1189,13 +1186,14 @@
end
if RUBY_ENGINE == 'opal'
attr_accessor :render_buffer
attr_accessor :rerender_queue
+ attr_accessor :rerender_count
def is_renderable?(res)
- `(res !== null && res !== undefined && res !== nil && res.$$is_string)`
+ `!!(res && res !== nil && res.$$is_string)`
end
def create_element(type, props = nil, children = nil)
if props
if props.JS['$$is_hash']
@@ -1223,17 +1221,24 @@
if (c.length > 0) { children = c; }
}
end
%x{
- if (children !== nil && children !== null) { normalized_props.set("children", children); }
+ if (children !== nil && children !== null) {
+ normalized_props.set("children", children.$$is_array ? children : [children]);
+ } else {
+ children = normalized_props.get("children");
+ if (children && !children.$$is_array) {
+ normalized_props.set("children", [children]);
+ }
+ }
return self.createVNode(type, normalized_props, key, ref, null);
}
end
def _enqueue_render(c)
- if ((`!c._dirty` && (`c._dirty = true`) && (rerender_queue << c) && `!self.process._rerenderCount++`))
+ if ((`!c._dirty` && (`c._dirty = true`) && (self.rerender_queue << c) && `!self.rerender_count++`))
`setTimeout(self.process)`
end
end
def _render_element(component, props, &block)
@@ -1244,30 +1249,30 @@
else { opr.push(self.$create_element(component, props, nil)); }
}
nil
end
- def hydrate(vnode, container_node)
- render(vnode, container_node, `self.render`)
- end
-
def element_or_query_to_n(element_or_query)
if `!element_or_query || element_or_query === nil`
return `null`
elsif `(element_or_query instanceof HTMLElement)`
return element_or_query
- elsif `(typeof element_or_query === 'string')` || element_or_query.is_a?(String)
+ elsif `(typeof element_or_query === 'string') || element_or_query.$$is_string`
return `document.body.querySelector(element_or_query)`
elsif `(typeof element_or_query === 'function')`
return element_or_query
elsif element_or_query.is_a?(::Browser::Element)
return element_or_query.to_n
else
return element_or_query
end
end
+ def hydrate(vnode, container_node)
+ render(vnode, container_node, `self.render`)
+ end
+
def render(vnode, container_node, replace_node = nil)
_init_render
container_node = element_or_query_to_n(container_node)
replace_node = element_or_query_to_n(replace_node)
`self.render(vnode, container_node, replace_node)`
@@ -1320,6 +1325,5 @@
_render_to_string(vnode, context)
end
end # RUBY_ENGINE
end
end
-