UNPKG

28.3 kBJavaScriptView Raw
1import { H as HOOK_CURRENT, a as HOOK_MOUNT, b as HOOK_UPDATED, c as HOOK_MOUNTED, d as HOOK_UNMOUNT, e as HOOK_UPDATE, A as ARRAY_EMPTY, I as IGNORE_CHILDREN, f as HYDRATE_PROPS, K as KEY, S as SUPPORT_STYLE_SHEET, C as CACHE_STYLE_SHEET, M as META_MAP_CHILDREN, g as META_KEYES, h as META_STYLE_SHEET, i as STYLE_SHEET_KEY, N as NODE_HOST, j as NODE_TYPE, E as ELEMENT_TRUE_VALUES, k as ELEMENT_PROPS, l as ELEMENT_IGNORE_ATTR } from './chunk/constants.js';
2import { i as isFunction, a as isEqualArray, b as isArray, p as promise } from './chunk/utils.js';
3
4function update(hook, type) {
5 hook[0] && (hook[1] = hook[0](hook[1], type));
6}
7
8function updateAll(hooks, type) {
9 for (let i in hooks) update(hooks[i], type);
10}
11
12function useHook(reducer, initialState) {
13 if (HOOK_CURRENT.ref.hook) {
14 return HOOK_CURRENT.ref.hook.use(reducer, initialState)[1];
15 }
16}
17
18function useRender() {
19 return HOOK_CURRENT.ref.render;
20}
21
22function useHost() {
23 return useHook(0, { current: HOOK_CURRENT.ref.host });
24}
25
26function createHookCollection(render, host) {
27 let hooks = {};
28 let mounted;
29 let hook = {
30 use,
31 load,
32 updated,
33 unmount
34 };
35
36 let ref = { hook, host, render };
37
38 function load(callback, param) {
39 HOOK_CURRENT.index = 0;
40 HOOK_CURRENT.ref = ref;
41 let resolve = callback(param);
42 HOOK_CURRENT.ref = 0;
43 return resolve;
44 }
45 function use(reducer, state) {
46 let index = HOOK_CURRENT.index++;
47 let mount;
48 // record the hook and the initial state of this
49 if (!hooks[index]) {
50 hooks[index] = [null, state];
51 mount = 1;
52 }
53 // The hook always receives the last reduce.
54 hooks[index][0] = reducer;
55 update(hooks[index], mount ? HOOK_MOUNT : HOOK_UPDATE);
56 return hooks[index];
57 }
58 function updated() {
59 let type = mounted ? HOOK_UPDATED : HOOK_MOUNTED;
60 mounted = 1;
61 updateAll(hooks, type);
62 }
63 function unmount() {
64 updateAll(hooks, HOOK_UNMOUNT);
65 }
66 return hook;
67}
68
69function useState(initialState) {
70 let render = useRender();
71 return useHook((state, type) => {
72 if (HOOK_MOUNT == type) {
73 state[0] = isFunction(initialState) ? initialState() : initialState;
74 state[1] = nextState => {
75 nextState = isFunction(nextState)
76 ? nextState(state[0])
77 : nextState;
78 if (nextState != state[0]) {
79 state[0] = nextState;
80 render();
81 }
82 };
83 }
84 return state;
85 }, []);
86}
87
88function useEffect(callback, args) {
89 // define whether the effect in the render cycle should be regenerated
90 let executeEffect;
91 useHook((state, type) => {
92 if (executeEffect == null) {
93 executeEffect =
94 args && state[0] ? !isEqualArray(args, state[0]) : true;
95 state[0] = args;
96 }
97
98 switch (type) {
99 case HOOK_UPDATE:
100 case HOOK_UNMOUNT:
101 // save the current args, for comparison
102 if ((executeEffect || type == HOOK_UNMOUNT) && state[1]) {
103 // compare the previous snapshot with the generated state
104 state[1]();
105 // clean the effect collector
106 state[1] = 0;
107 }
108 // delete the previous argument for a hook
109 // run if the hook is inserted in a new node
110 // Why? ... to perform again dom operations associated with the parent
111 if (type == HOOK_UNMOUNT) {
112 state[0] = null;
113 }
114 break;
115 case HOOK_MOUNTED:
116 case HOOK_UPDATED:
117 // save the current args, for comparison, repeats due to additional type HOOK_MOUNTED
118 if (executeEffect || type == HOOK_MOUNTED) {
119 // save the effect collector
120 state[1] = callback();
121 }
122 // save the comparison argument
123 break;
124 }
125 return state;
126 }, []);
127}
128
129function useRef(current) {
130 return useHook(0, { current });
131}
132
133function useMemo(callback, args = ARRAY_EMPTY) {
134 let state = useHook(0, []);
135
136 if (!state[0] || (state[0] && !isEqualArray(state[0], args))) {
137 state[1] = callback();
138 }
139 state[0] = args;
140 return state[1];
141}
142
143function useReducer(reducer, initialState) {
144 let render = useRender();
145 let hook = useHook((state, type) => {
146 if (HOOK_MOUNT == type) {
147 state[0] = initialState;
148 state[1] = action => {
149 let nextState = state[2](state[0], action);
150 if (nextState != state[0]) {
151 state[0] = nextState;
152 render();
153 }
154 };
155 }
156 return state;
157 }, []);
158 // allows the reduce to always access the scope of the component
159 hook[2] = reducer;
160
161 return hook;
162}
163
164/**
165 *
166 * @param {import("./render").HTMLNode} node
167 * @param {Object} props
168 * @param {Object} nextProps
169 * @param {boolean} isSvg
170 * @param {Object} handlers
171 **/
172function diffProps(node, props, nextProps, isSvg, handlers) {
173 props = props || {};
174
175 for (let key in props) {
176 if (!(key in nextProps)) {
177 setProperty(node, key, props[key], null, isSvg, handlers);
178 }
179 }
180 let ignoreChildren;
181 for (let key in nextProps) {
182 setProperty(node, key, props[key], nextProps[key], isSvg, handlers);
183 ignoreChildren = ignoreChildren || IGNORE_CHILDREN[key];
184 }
185 return ignoreChildren;
186}
187
188function setProperty(node, key, prevValue, nextValue, isSvg, handlers) {
189 key = key == "class" && !isSvg ? "className" : key;
190 // define empty value
191 prevValue = prevValue == null ? null : prevValue;
192 nextValue = nextValue == null ? null : nextValue;
193
194 if (key in node && HYDRATE_PROPS[key]) {
195 prevValue = node[key];
196 }
197
198 if (nextValue === prevValue) return;
199
200 if (
201 key[0] == "o" &&
202 key[1] == "n" &&
203 (isFunction(nextValue) || isFunction(prevValue))
204 ) {
205 setEvent(node, key, nextValue, handlers);
206 return;
207 }
208
209 switch (key) {
210 /**
211 * add support {@link https://developer.mozilla.org/es/docs/Web/API/CSSStyleSheet}
212 */
213 case "styleSheet":
214 if (SUPPORT_STYLE_SHEET)
215 node.shadowRoot.adoptedStyleSheets = []
216 .concat(nextValue)
217 .map(cssText => {
218 if (cssText instanceof CSSStyleSheet) {
219 return cssText;
220 }
221 if (!CACHE_STYLE_SHEET[cssText]) {
222 CACHE_STYLE_SHEET[cssText] = new CSSStyleSheet();
223 CACHE_STYLE_SHEET[cssText].replace(cssText);
224 }
225
226 return CACHE_STYLE_SHEET[cssText];
227 });
228
229 break;
230 case "ref":
231 if (nextValue) nextValue.current = node;
232 break;
233 case "style":
234 setStyle(node, prevValue || "", nextValue || "");
235 break;
236 case "key":
237 node[KEY] = nextValue;
238 break;
239 default:
240 if (!isSvg && key != "list" && key in node) {
241 node[key] = nextValue == null ? "" : nextValue;
242 } else if (nextValue == null) {
243 node.removeAttribute(key);
244 } else {
245 node.setAttribute(
246 key,
247 typeof nextValue == "object"
248 ? JSON.stringify(nextValue)
249 : nextValue
250 );
251 }
252 }
253}
254
255/**
256 *
257 * @param {import("./render").HTMLNode} node
258 * @param {string} type
259 * @param {function} [nextHandler]
260 * @param {object} handlers
261 */
262function setEvent(node, type, nextHandler, handlers) {
263 // get the name of the event to use
264 type = type.slice(type[2] == "-" ? 3 : 2);
265 // add handleEvent to handlers
266 if (!handlers.handleEvent) {
267 /**
268 * {@link https://developer.mozilla.org/es/docs/Web/API/EventTarget/addEventListener#The_value_of_this_within_the_handler}
269 **/
270 handlers.handleEvent = event => handlers[event.type].call(node, event);
271 }
272 if (nextHandler) {
273 // create the subscriber if it does not exist
274 if (!handlers[type]) {
275 node.addEventListener(type, handlers);
276 }
277 // update the associated event
278 handlers[type] = nextHandler;
279 } else {
280 // delete the associated event
281 if (handlers[type]) {
282 node.removeEventListener(type, handlers);
283 delete handlers[type];
284 }
285 }
286}
287/**
288 * define style as string inline,this generates less mutation
289 * to the sun and cleans the previously defined properties.
290 * @param {import("./render").HTMLNode} node
291 * @param {(string|object)} prevValue
292 * @param {(string|object)} nextValue
293 */
294function setStyle(node, prevValue, nextValue) {
295 let style = node.style,
296 prevIsObject;
297 if (typeof prevValue == "object") {
298 prevIsObject = true;
299 for (let key in prevValue) {
300 if (!(key in nextValue)) setPropertyStyle(style, key, null);
301 }
302 }
303 if (typeof nextValue == "object") {
304 for (let key in nextValue) {
305 let value = nextValue[key];
306 if (prevIsObject && prevValue[key] === value) continue;
307 setPropertyStyle(style, key, value);
308 }
309 } else {
310 style.cssText = nextValue;
311 }
312}
313
314function setPropertyStyle(style, key, value) {
315 let method = "setProperty";
316 if (value == null) {
317 method = "removeProperty";
318 value = null;
319 }
320 if (~key.indexOf("-")) {
321 style[method](key, value);
322 } else {
323 style[key] = value;
324 }
325}
326
327let vNodeEmpty = createElement(null, { children: "" });
328
329/**
330 * @param {VnodeType} nodeType
331 * @param {VnodeProps} [props]
332 * @param {Vnode|Vnode[]} [children]
333 * @returns {Vnode}
334 **/
335function createElement(nodeType, props, ...children) {
336 let vnode = { children, ...props, nodeType: nodeType || null };
337 return vnode;
338}
339/**
340 * toVnode, processes the object for correct use within the diff process.
341 **/
342function toVnode(value) {
343 if (isVnodeValue(value)) {
344 return value;
345 } else {
346 if (!value[META_MAP_CHILDREN]) {
347 let scan = mapChildren(value.children);
348 value.children = scan.children;
349 if (scan.keyes) {
350 value[META_KEYES] = scan.keyes;
351 }
352 value[META_MAP_CHILDREN] = true;
353 }
354 if (value.styleSheet && !SUPPORT_STYLE_SHEET) {
355 if (!value[META_STYLE_SHEET]) {
356 value.children.unshift(
357 toVnode(
358 createElement(
359 "style",
360 value[META_KEYES] ? { key: STYLE_SHEET_KEY } : {},
361 value.styleSheet
362 )
363 )
364 );
365 if (value[META_KEYES]) {
366 value[META_KEYES].unshift(STYLE_SHEET_KEY);
367 }
368 }
369 value[META_STYLE_SHEET] = true;
370 }
371 }
372 return value;
373}
374
375function mapChildren(children, scan = { children: [] }, deep = 0) {
376 if (isArray(children)) {
377 let length = children.length;
378 for (let i = 0; i < length; i++) {
379 mapChildren(children[i], scan, deep + 1);
380 }
381 } else {
382 if (children == null && !deep) return scan;
383
384 let vnode = toVnode(children);
385
386 if (vnode != null && typeof vnode == "object") {
387 if (isFunction(vnode.nodeType)) {
388 let { nodeType, ...props } = vnode;
389 return mapChildren(nodeType(props), scan, deep + 1);
390 }
391 if ("key" in vnode) {
392 scan.keyes = scan.keyes || [];
393 if (!~scan.keyes.indexOf(vnode.key)) {
394 scan.keyes.push(vnode.key);
395 }
396 }
397 }
398
399 scan.children.push(vnode);
400 }
401 return scan;
402}
403
404function isVnodeEmpty(value) {
405 let type = typeof value;
406 return value == null || type == "boolean" || type == "function";
407}
408
409function fillVnodeValue(value) {
410 return isVnodeEmpty(value)
411 ? vNodeEmpty
412 : createElement(null, { children: "" + value });
413}
414
415function isVnodeValue(value) {
416 let type = typeof value;
417 return (
418 value == null ||
419 type == "string" ||
420 type == "number" ||
421 type == "function" ||
422 type == "boolean"
423 );
424}
425
426/**
427 * @typedef {(Object<string,any>)} VnodeProps;
428 *
429 * @typedef {(Function|string)} VnodeType;
430 *
431 * @typedef {{type:VnodeType,props:VnodeProps}} Vnode
432 **/
433
434/**
435 *
436 * @param {import("./render").ConfigRender} config
437 * @param {import("./render").HTMLNode} node
438 * @param {import("./vnode").Vnode} nextVnode
439 * @param {boolean} isSvg
440 * @param {Function} currentUpdateComponent
441 * @return {import("./render").HTMLNode}
442 **/
443function diff(id, node, nextVnode, isSvg) {
444 let { vnode, handlers = {} } = (node && node[id]) || {};
445
446 if (vnode == nextVnode && vnode != null) return node;
447
448 nextVnode = isVnodeValue(nextVnode) ? fillVnodeValue(nextVnode) : nextVnode;
449
450 let { nodeType, shadowDom, children, ...props } = vnode || {};
451
452 let {
453 nodeType: nextNodeType,
454 shadowDom: nextShadowDom,
455 children: nextChildren,
456 ...nextProps
457 } = nextVnode;
458
459 isSvg = isSvg || nextNodeType == "svg";
460
461 if (nextNodeType != NODE_HOST && getNodeName(node) !== nextNodeType) {
462 let nextNode = createNode(nextNodeType, isSvg);
463 let parent = node && node.parentNode;
464
465 if (parent) {
466 parent.replaceChild(nextNode, node);
467 }
468
469 node = nextNode;
470 handlers = {};
471 }
472 if (nextNodeType == null) {
473 if (node.nodeValue != nextChildren) {
474 node.nodeValue = nextChildren;
475 }
476 } else {
477 if (shadowDom != nextShadowDom) {
478 let { shadowRoot } = node;
479 let mode =
480 nextShadowDom && !shadowRoot
481 ? "open"
482 : !nextShadowDom && shadowRoot
483 ? "closed"
484 : 0;
485 if (mode) node.attachShadow({ mode });
486 }
487
488 let ignoreChildren = diffProps(
489 node,
490 props,
491 nextProps,
492 isSvg,
493 handlers);
494 if (!ignoreChildren && children != nextChildren) {
495 diffChildren(
496 id,
497 nextShadowDom ? node.shadowRoot : node,
498 nextChildren,
499 nextProps[META_KEYES],
500 isSvg
501 );
502 }
503 }
504 node[id] = { vnode: nextVnode, handlers };
505 return node;
506}
507/**
508 *
509 * @param {import("./render").ConfigRender} config
510 * @param {import("./render").HTMLNode} parent
511 * @param {import("./vnode").Vnode[]} [nextChildren]
512 * @param {boolean} isSvg
513 */
514function diffChildren(id, parent, children, keyes, isSvg) {
515 let childrenLenght = children.length;
516 let { childNodes } = parent;
517 let childNodesKeyes = {};
518 let childNodesLength = childNodes.length;
519 let index = keyes
520 ? 0
521 : childNodesLength > childrenLenght
522 ? childrenLenght
523 : childNodesLength;
524
525 for (; index < childNodesLength; index++) {
526 let childNode = childNodes[index];
527 let key = index;
528 if (keyes) {
529 key = childNode[KEY];
530 if (keyes.indexOf(key) > -1) {
531 childNodesKeyes[key] = childNode;
532 continue;
533 }
534 }
535 index--;
536 childNodesLength--;
537 parent.removeChild(childNode);
538 }
539 for (let i = 0; i < childrenLenght; i++) {
540 let child = children[i];
541 let indexChildNode = childNodes[i];
542 let key = keyes ? child.key : i;
543 let childNode = keyes ? childNodesKeyes[key] : indexChildNode;
544
545 if (keyes && childNode) {
546 if (childNode != indexChildNode) {
547 parent.insertBefore(childNode, indexChildNode);
548 }
549 }
550
551 let nextChildNode = diff(id, childNode, child, isSvg);
552
553 if (!childNode) {
554 if (childNodes[i]) {
555 parent.insertBefore(nextChildNode, childNodes[i]);
556 } else {
557 parent.appendChild(nextChildNode);
558 }
559 }
560 }
561}
562
563/**
564 *
565 * @param {string} type
566 * @param {boolean} isSvg
567 * @returns {import("./render").HTMLNode}
568 */
569function createNode(type, isSvg) {
570 let doc = document;
571 let nextNode;
572 if (type != null) {
573 nextNode = isSvg
574 ? doc.createElementNS("http://www.w3.org/2000/svg", type)
575 : doc.createElement(type);
576 } else {
577 nextNode = doc.createTextNode("");
578 }
579 return nextNode;
580}
581
582/**
583 * returns the localName of the node
584 * @param {import("./render").HTMLNode} node
585 */
586function getNodeName(node) {
587 if (!node) return;
588 if (!node[NODE_TYPE]) {
589 node[NODE_TYPE] = node.nodeName.toLowerCase();
590 }
591 let localName = node[NODE_TYPE];
592 return localName == "#text" ? null : localName;
593}
594
595function render(vnode, node, id = "vnode") {
596 if (
597 vnode != null &&
598 typeof vnode == "object" &&
599 vnode.nodeType != NODE_HOST
600 ) {
601 vnode = createElement(NODE_HOST, { children: vnode });
602 }
603 vnode = toVnode(vnode);
604 diff(id, node, vnode);
605 return node;
606}
607
608function setAttr(node, attr, value) {
609 if (value == null) {
610 node.removeAttribute(attr);
611 } else {
612 node.setAttribute(
613 attr,
614 typeof value == "object" ? JSON.stringify(value) : value
615 );
616 }
617}
618
619function formatType(value, type = String) {
620 try {
621 if (type == Boolean) {
622 value = ELEMENT_TRUE_VALUES.indexOf(value) > -1;
623 } else if (typeof value == "string") {
624 value =
625 type == Number
626 ? Number(value)
627 : type == Object || type == Array
628 ? JSON.parse(value)
629 : type == Date
630 ? new Date(value)
631 : value;
632 }
633 if ({}.toString.call(value) == `[object ${type.name}]`) {
634 return { value, error: type == Number && Number.isNaN(value) };
635 }
636 } catch (e) {}
637
638 return { value, error: true };
639}
640
641function propToAttr(prop) {
642 return prop.replace(/([A-Z])/g, "-$1").toLowerCase();
643}
644
645function attrToProp(attr) {
646 return attr.replace(/-(\w)/g, (all, letter) => letter.toUpperCase());
647}
648
649function dispatchEvent(node, type, customEventInit) {
650 node.dispatchEvent(
651 new CustomEvent(
652 type,
653 typeof customEventInit == "object" ? customEventInit : null
654 )
655 );
656}
657
658let defer = Promise.resolve();
659let queue = [];
660let running;
661
662let maxFps = 1000 / 60;
663
664const IMPORTANT = Symbol("important");
665
666function clearQueue() {
667 let time = performance.now();
668
669 let length = queue.length;
670 let current = queue;
671
672 queue = [];
673
674 while (length--) {
675 let callback = current[length];
676 if (callback[IMPORTANT] || performance.now() - time < maxFps) {
677 callback();
678 } else {
679 queue = queue.concat(current.slice(0, length + 1));
680 break;
681 }
682 }
683
684 if (queue.length) {
685 requestAnimationFrame(clearQueue);
686 return;
687 }
688 running = false;
689}
690/**
691 * add a task to the queue
692 * @param {Function} callback
693 * @returns {Promise} Generate a promise that show if the queue is complete
694 */
695function addQueue(callback) {
696 if (!running) {
697 running = true;
698 defer.then(clearQueue);
699 }
700 if (!queue.includes(callback)) queue.push(callback);
701}
702
703class Element extends HTMLElement {
704 constructor() {
705 super();
706 /**
707 * identifier to store the virtual-dom state,
708 * this is unique between instances of the
709 * component to securely consider the host status
710 */
711 let id = Symbol("vnode");
712
713 let isPrevent;
714 let isUnmount;
715
716 this[ELEMENT_PROPS] = {};
717
718 let isMounted;
719
720 let resolveUpdate;
721
722 let rerender = () => {
723 // disables blocking, allowing the cycle to be regenerate
724 isPrevent = false;
725 // After the first render it disables the important condition
726 if (rerender[IMPORTANT]) rerender[IMPORTANT] = false;
727 try {
728 render(
729 hooks.load(this.render, { ...this[ELEMENT_PROPS] }),
730 this,
731 id
732 );
733
734 resolveUpdate();
735 } catch (e) {
736 this.error(e);
737 }
738 };
739 // mark the first render as important, this speeds up the rendering
740 rerender[IMPORTANT] = true;
741
742 this.update = () => {
743 if (isUnmount) return;
744 let rendered = this.rendered;
745 if (!isPrevent) {
746 isPrevent = true;
747 // create a promise to observe the status of the update
748 rendered = promise(resolve => (resolveUpdate = resolve)).then(
749 // the UPDATED state is only propagated through
750 // the resolution of the promise
751 // Why? ... to improve communication between web-component parent and children
752 hooks.updated
753 );
754
755 // if the component is already mounted, avoid using this.mounted,
756 // to speed up the microtask
757 isMounted
758 ? addQueue(rerender)
759 : this.mounted.then(() => {
760 isMounted = true;
761 addQueue(rerender);
762 });
763 }
764
765 return (this.rendered = rendered);
766 };
767
768 // any update from hook is added to a separate queue
769 let hooks = createHookCollection(() => addQueue(this.update), this);
770
771 // creates a collection of microtask
772 // associated with the mounted of the component
773
774 this.mounted = promise(
775 resolve =>
776 (this.mount = () => {
777 isMounted = false;
778 // allows the reuse of the component when it is isUnmounted and mounted
779 if (isUnmount == true) {
780 isUnmount = false;
781 this.mounted = this.update();
782 }
783 resolve();
784 })
785 );
786 /**
787 * creates a collection of microtask
788 * associated with the unmounted of the component
789 */
790 this.unmounted = promise(
791 resolve =>
792 (this.unmount = () => {
793 isUnmount = true;
794 hooks.unmount();
795 resolve();
796 })
797 );
798
799 this.initialize();
800
801 this.update();
802 }
803 connectedCallback() {
804 this.mount();
805 }
806 disconnectedCallback() {
807 this.unmount();
808 }
809 attributeChangedCallback(attr, oldValue, value) {
810 if (attr === this[ELEMENT_IGNORE_ATTR] || oldValue === value) return;
811 this[attrToProp(attr)] = value;
812 }
813}
814
815/**
816 * register the component, be it a class or function
817 * @param {string} nodeType
818 * @param {Function} component
819 * @return {Function} returns a jsx component
820 */
821function customElement(nodeType, component) {
822 if (isFunction(nodeType)) {
823 component = nodeType;
824
825 let CustomElement = class extends Element {};
826 let prototype = CustomElement.prototype;
827
828 let props = component.props;
829
830 prototype.error = component.error || console.error;
831 prototype.render = component;
832
833 prototype.initialize = function() {
834 let length = initialize.length;
835 while (length--) initialize[length](this);
836 };
837
838 let initialize = [];
839
840 let attrs = [];
841
842 for (let prop in props)
843 setProperty$1(prototype, initialize, attrs, prop, props[prop]);
844
845 CustomElement.observedAttributes = attrs;
846
847 return CustomElement;
848 } else {
849 customElements.define(
850 nodeType,
851 component instanceof Element ? component : customElement(component)
852 );
853
854 return props => createElement(nodeType, props);
855 }
856}
857
858function setProperty$1(prototype, initialize, attrs, prop, schema) {
859 let attr = propToAttr(prop);
860
861 schema = schema.name ? { type: schema } : schema;
862
863 if (prop in prototype) return;
864
865 function set(nextValue) {
866 let prevValue = this[ELEMENT_PROPS][prop];
867
868 if (isFunction(nextValue)) {
869 nextValue = nextValue(prevValue);
870 }
871 let { value, error } = formatType(nextValue, schema.type);
872
873 if (error && value != null) {
874 throw `the observable [${prop}] must be of the type [${schema.type.name}]`;
875 }
876
877 if (prevValue == value) return;
878
879 this[ELEMENT_PROPS][prop] = value;
880
881 let rendered = this.update();
882
883 if (schema.event) {
884 rendered.then(() =>
885 dispatchEvent(this, schema.event.type || prop, schema.event)
886 );
887 }
888
889 if (schema.reflect) {
890 // the default properties are only reflected once the web-component is mounted
891 this.mounted.then(() => {
892 this[ELEMENT_IGNORE_ATTR] = attr; //update is prevented
893 setAttr(
894 this,
895 attr,
896 schema.type == Boolean && !value ? null : value //
897 );
898 this[ELEMENT_IGNORE_ATTR] = false; // an upcoming update is allowed
899 });
900 }
901 }
902
903 function get() {
904 return this[ELEMENT_PROPS][prop];
905 }
906
907 Object.defineProperty(prototype, prop, { set, get });
908
909 if ("value" in schema) {
910 initialize.push(self => (self[prop] = schema.value));
911 }
912 attrs.push(attr);
913}
914
915function useProp(name) {
916 let ref = useHost();
917 if (name in ref.current) {
918 if (!ref[name]) {
919 ref[name] = [null, nextValue => (ref.current[name] = nextValue)];
920 }
921 ref[name][0] = ref.current[name];
922 return ref[name];
923 }
924}
925
926function useEvent(type, customEventInit) {
927 let ref = useHost();
928 if (!ref[type]) {
929 ref[type] = detail =>
930 dispatchEvent(
931 ref.current,
932 type,
933 detail ? { ...customEventInit, detail } : customEventInit
934 );
935 }
936 return ref[type];
937}
938
939function usePublic(name, value) {
940 let { current } = useHost();
941 if (current[name] != value) {
942 current[name] = value;
943 }
944 return current[name];
945}
946
947export { Element, createHookCollection, customElement, createElement as h, render, toVnode, useEffect, useEvent, useHook, useHost, useMemo, useProp, usePublic, useReducer, useRef, useRender, useState };
948//# sourceMappingURL=core.js.map