diff --git a/README.md b/README.md index 5871190..9832b4e 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,13 @@ **Social Media Photo by [chuttersnap](https://unsplash.com/@chuttersnap) on [Unsplash](https://unsplash.com/)** +### 📣 Community Announcement -This module integrates [augmentor](https://github.com/WebReflection/augmentor#readme) in [wickedElements](https://github.com/WebReflection/wicked-elements#readme) for a ~2.4K all-inclusive package and zero polyfills needed whatsoever. +Please ask questions in the [dedicated discussions repository](https://github.com/WebReflection/discussions), to help the community around this project grow ♥ + +--- + +This module integrates [µhooks](https://github.com/WebReflection/uhooks#readme) in [wickedElements](https://github.com/WebReflection/wicked-elements#readme) for a *~2K* all-inclusive package and zero polyfills needed whatsoever. The compatibility is the same as _wickedElements_, meaning IE11+ and other Desktop/Mobile browsers. @@ -25,7 +30,7 @@ The callback is used as `render` method and automatically augmented and invoked ### In A Nutshell -All [augmentor hooks](https://github.com/WebReflection/augmentor#available-hooks) are available, and `useEffect` is granted to run *before* `disconnected`, if it returns a callback to drop the effect. +All [hooks](https://github.com/WebReflection/augmentor#available-hooks) are available, and `useEffect` is granted to run *before* `disconnected`, if it returns a callback to drop the effect. **[Live Demo](https://codepen.io/WebReflection/pen/mdJVERz)** @@ -73,22 +78,22 @@ define('button.counter', {
- Sure thing! Following a lighterhtml integration example, also live in CodePen: + Sure thing! Following a µhtml integration example, also live in CodePen: **[Live Demo](https://codepen.io/WebReflection/pen/poJyjGy)** ```js -import {render, html, svg} from 'lighterhtml'; +import {render, html, svg} from 'uhtml'; import {define, useState} from 'hooked-elements'; // as mixin -const LighterHTML = { +const MicroHTML = { html() { return render(this.element, html.apply(null, arguments)); }, svg() { return render(this.element, svg.apply(null, arguments)); } }; define('button.counter', { - ...LighterHTML, + ...MicroHTML, render(element) { const [count, update] = useState(1); element.onclick = () => update(count + 1); diff --git a/cjs/index.js b/cjs/index.js index 1da81b4..70dfdbe 100644 --- a/cjs/index.js +++ b/cjs/index.js @@ -1,5 +1,5 @@ 'use strict'; -const {augmentor, dropEffect, hasEffect} = require('augmentor'); +const {hooked, dropEffect, hasEffect} = require('uhooks'); const {define: $define, defineAsync: $async} = require('wicked-elements'); // default init with auto-augmented and invoked render @@ -22,7 +22,7 @@ exports.defineAsync = defineAsync; const render = wicked => { const {disconnected, element, render} = wicked; - const hook = augmentor(render.bind(wicked, element)); + const hook = hooked(render.bind(wicked, element)); wicked.disconnected = () => { if (hasEffect(hook)) dropEffect(hook); @@ -43,7 +43,7 @@ exports.render = render; exports.useCallback = m.useCallback; exports.useMemo = m.useMemo; exports.useRef = m.useRef; -})(require('augmentor')); +})(require('uhooks')); (m => { exports.get = m.get; diff --git a/esm/index.js b/esm/index.js index ad7b1f7..33e25ca 100644 --- a/esm/index.js +++ b/esm/index.js @@ -1,4 +1,4 @@ -import {augmentor, dropEffect, hasEffect} from 'augmentor'; +import {hooked, dropEffect, hasEffect} from 'uhooks'; import {define as $define, defineAsync as $async} from 'wicked-elements'; // default init with auto-augmented and invoked render @@ -19,7 +19,7 @@ export const defineAsync = (selector, callback) => { export const render = wicked => { const {disconnected, element, render} = wicked; - const hook = augmentor(render.bind(wicked, element)); + const hook = hooked(render.bind(wicked, element)); wicked.disconnected = () => { if (hasEffect(hook)) dropEffect(hook); @@ -37,7 +37,7 @@ export { useCallback, useMemo, useRef -} from 'augmentor'; +} from 'uhooks'; export { get, diff --git a/index.js b/index.js index db729d0..be4504f 100644 --- a/index.js +++ b/index.js @@ -1,519 +1,447 @@ var hookedElements = (function (exports) { 'use strict'; - var compat = typeof cancelAnimationFrame === 'function'; - var cAF = compat ? cancelAnimationFrame : clearTimeout; - var rAF = compat ? requestAnimationFrame : setTimeout; - function reraf(limit) { - var force, timer, callback, self, args; - reset(); - return function reschedule(_callback, _self, _args) { - callback = _callback; - self = _self; - args = _args; - if (!timer) timer = rAF(invoke); - if (--force < 0) stop(true); - return stop; + var Lie = typeof Promise === 'function' ? Promise : function (fn) { + var queue = [], + resolved = 0, + value; + fn(function ($) { + value = $; + resolved = 1; + queue.splice(0).forEach(then); + }); + return { + then: then }; - function invoke() { - reset(); - callback.apply(self, args || []); + function then(fn) { + return resolved ? setTimeout(fn, 0, value) : queue.push(fn), this; } + }; - function reset() { - force = limit || Infinity; - timer = compat ? 0 : null; + var info = null, + schedule = new Set(); + + var invoke = function invoke(effect) { + var $ = effect.$, + r = effect.r, + h = effect.h; + + if (isFunction(r)) { + fx.get(h)["delete"](effect); + r(); } - function stop(flush) { - var didStop = !!timer; + if (isFunction(effect.r = $())) fx.get(h).add(effect); + }; - if (didStop) { - cAF(timer); - if (flush) invoke(); - } + var runSchedule = function runSchedule() { + var previous = schedule; + schedule = new Set(); + previous.forEach(function (_ref) { + var h = _ref.h, + c = _ref.c, + a = _ref.a, + e = _ref.e; + // avoid running schedules when the hook is + // re-executed before such schedule happens + if (e) h.apply(c, a); + }); + }; - return didStop; - } + var fx = new WeakMap(); + var effects = []; + var layoutEffects = []; + function different(value, i) { + return value !== this[i]; } - - var umap = (function (_) { - return { - // About: get: _.get.bind(_) - // It looks like WebKit/Safari didn't optimize bind at all, - // so that using bind slows it down by 60%. - // Firefox and Chrome are just fine in both cases, - // so let's use the approach that works fast everywhere 👍 - get: function get(key) { - return _.get(key); - }, - set: function set(key, value) { - return _.set(key, value), value; - } + var dropEffect = function dropEffect(hook) { + var effects = fx.get(hook); + if (effects) wait.then(function () { + effects.forEach(function (effect) { + effect.r(); + effect.r = null; + }); + effects.clear(); + }); + }; + var getInfo = function getInfo() { + return info; + }; + var hasEffect = function hasEffect(hook) { + return fx.has(hook); + }; + var isFunction = function isFunction(f) { + return typeof f === 'function'; + }; + var hooked = function hooked(callback) { + var current = { + h: hook, + c: null, + a: null, + e: 0, + i: 0, + s: [] }; - }); + return hook; - /*! (c) Andrea Giammarchi - ISC */ - var state = null; // main exports - - var augmentor = function augmentor(fn) { - var stack = []; - return function hook() { - var prev = state; - var after = []; - state = { - hook: hook, - args: arguments, - stack: stack, - i: 0, - length: stack.length, - after: after - }; + function hook() { + var prev = info; + info = current; + current.e = current.i = 0; try { - return fn.apply(null, arguments); + return callback.apply(current.c = this, current.a = arguments); } finally { - state = prev; - - for (var i = 0, length = after.length; i < length; i++) { - after[i](); - } + info = prev; + if (effects.length) wait.then(effects.forEach.bind(effects.splice(0), invoke)); + if (layoutEffects.length) layoutEffects.splice(0).forEach(invoke); } - }; - }; - - var updates = umap(new WeakMap()); - - var hookdate = function hookdate(hook, ctx, args) { - hook.apply(ctx, args); + } }; - - var defaults = { - async: false, - always: false + var reschedule = function reschedule(info) { + if (!schedule.has(info)) { + info.e = 1; + schedule.add(info); + wait.then(runSchedule); + } }; + var wait = new Lie(function ($) { + return $(); + }); - var getValue = function getValue(value, f) { - return typeof f == 'function' ? f(value) : f; + var createContext = function createContext(value) { + return { + _: new Set(), + provide: provide, + value: value + }; }; + var useContext = function useContext(_ref) { + var _ = _ref._, + value = _ref.value; - var useReducer = function useReducer(reducer, value, init, options) { - var i = state.i++; - var _state = state, - hook = _state.hook, - args = _state.args, - stack = _state.stack, - length = _state.length; - if (i === length) state.length = stack.push({}); - var ref = stack[i]; - ref.args = args; - - if (i === length) { - var fn = typeof init === 'function'; + _.add(getInfo()); - var _ref = (fn ? options : init) || options || defaults, - asy = _ref.async, - always = _ref.always; - - ref.$ = fn ? init(value) : getValue(void 0, value); - ref._ = asy ? updates.get(hook) || updates.set(hook, reraf()) : hookdate; + return value; + }; - ref.f = function (value) { - var $value = reducer(ref.$, value); + function provide(newValue) { + var _ = this._, + value = this.value; - if (always || ref.$ !== $value) { - ref.$ = $value; + if (value !== newValue) { + this._ = new Set(); + this.value = newValue; - ref._(hook, null, ref.args); - } - }; + _.forEach(function (_ref2) { + var h = _ref2.h, + c = _ref2.c, + a = _ref2.a; + h.apply(c, a); + }); } + } - return [ref.$, ref.f]; - }; // useState - - var useState = function useState(value, options) { - return useReducer(getValue, value, void 0, options); - }; // useContext - - var hooks = new WeakMap(); - - var invoke = function invoke(_ref2) { - var hook = _ref2.hook, - args = _ref2.args; - hook.apply(null, args); - }; - - var createContext = function createContext(value) { - var context = { - value: value, - provide: provide - }; - hooks.set(context, []); - return context; + var useCallback = function useCallback(fn, guards) { + return useMemo(function () { + return fn; + }, guards); }; - var useContext = function useContext(context) { - var _state2 = state, - hook = _state2.hook, - args = _state2.args; - var stack = hooks.get(context); - var info = { - hook: hook, - args: args + var useMemo = function useMemo(memo, guards) { + var info = getInfo(); + var i = info.i, + s = info.s; + if (i === s.length || !guards || guards.some(different, s[i]._)) s[i] = { + $: memo(), + _: guards }; - if (!stack.some(update, info)) stack.push(info); - return context.value; + return s[info.i++].$; }; - function provide(value) { - if (this.value !== value) { - this.value = value; - hooks.get(this).forEach(invoke); - } - } - - function update(_ref3) { - var hook = _ref3.hook; - return hook === this.hook; - } // dropEffect, hasEffect, useEffect, useLayoutEffect - - - var effects = new WeakMap(); - var fx = umap(effects); - - var stop = function stop() {}; - - var createEffect = function createEffect(asy) { - return function (effect, guards) { - var i = state.i++; - var _state3 = state, - hook = _state3.hook, - after = _state3.after, - stack = _state3.stack, - length = _state3.length; - - if (i < length) { - var info = stack[i]; - var _update = info.update, - values = info.values, - _stop = info.stop; - - if (!guards || guards.some(different, values)) { - info.values = guards; - if (asy) _stop(asy); - var clean = info.clean; - - if (clean) { - info.clean = null; - clean(); - } - - var _invoke = function _invoke() { - info.clean = effect(); - }; - - if (asy) _update(_invoke);else after.push(_invoke); - } - } else { - var _update2 = asy ? reraf() : stop; - - var _info = { - clean: null, - update: _update2, - values: guards, - stop: stop + var createEffect = function createEffect(stack) { + return function (callback, guards) { + var info = getInfo(); + var i = info.i, + s = info.s, + h = info.h; + var call = i === s.length; + info.i++; + + if (call) { + if (!fx.has(h)) fx.set(h, new Set()); + s[i] = { + $: callback, + _: guards, + r: null, + h: h }; - state.length = stack.push(_info); - (fx.get(hook) || fx.set(hook, [])).push(_info); - - var _invoke2 = function _invoke2() { - _info.clean = effect(); - }; - - if (asy) _info.stop = _update2(_invoke2);else after.push(_invoke2); } + + if (call || !guards || guards.some(different, s[i]._)) stack.push(s[i]); + s[i].$ = callback; + s[i]._ = guards; }; }; - var dropEffect = function dropEffect(hook) { - (effects.get(hook) || []).forEach(function (info) { - var clean = info.clean, - stop = info.stop; - stop(); - - if (clean) { - info.clean = null; - clean(); + var useEffect = createEffect(effects); + var useLayoutEffect = createEffect(layoutEffects); + + var getValue = function getValue(value, f) { + return isFunction(f) ? f(value) : f; + }; + + var useReducer = function useReducer(reducer, value, init) { + var info = getInfo(); + var i = info.i, + s = info.s; + if (i === s.length) s.push({ + $: isFunction(init) ? init(value) : getValue(void 0, value), + set: function set(value) { + s[i].$ = reducer(s[i].$, value); + reschedule(info); } }); + var _s$info$i = s[info.i++], + $ = _s$info$i.$, + set = _s$info$i.set; + return [$, set]; }; - var hasEffect = effects.has.bind(effects); - var useEffect = createEffect(true); - var useLayoutEffect = createEffect(false); // useMemo, useCallback - - var useMemo = function useMemo(memo, guards) { - var i = state.i++; - var _state4 = state, - stack = _state4.stack, - length = _state4.length; - if (i === length) state.length = stack.push({ - $: memo(), - _: guards - });else if (!guards || guards.some(different, stack[i]._)) stack[i] = { - $: memo(), - _: guards - }; - return stack[i].$; + var useState = function useState(value) { + return useReducer(getValue, value); }; - var useCallback = function useCallback(fn, guards) { - return useMemo(function () { - return fn; - }, guards); - }; // useRef - - var useRef = function useRef(value) { - var i = state.i++; - var _state5 = state, - stack = _state5.stack, - length = _state5.length; - if (i === length) state.length = stack.push({ - current: value + + var useRef = function useRef(current) { + var info = getInfo(); + var i = info.i, + s = info.s; + if (i === s.length) s.push({ + current: current }); - return stack[i]; + return s[info.i++]; }; - function different(value, i) { - return value !== this[i]; - } - - var asCustomElement = (function (root, upgrade) { - var wm = new WeakMap(); - var ao = new WeakMap(); - var filter = [].filter; - - var attributeChanged = function attributeChanged(records, mo) { - for (var i = 0, length = records.length; i < length; i++) { - var _records$i = records[i], - target = _records$i.target, - attributeName = _records$i.attributeName, - oldValue = _records$i.oldValue; - var newValue = target.getAttribute(attributeName); - ao.get(mo).call(target, attributeName, oldValue, newValue); - } - }; + var TRUE = true, + FALSE = false; + var QSA$1 = 'querySelectorAll'; - var elements = function elements(target) { - return 'querySelectorAll' in target; - }; + function add(node) { + this.observe(node, { + subtree: TRUE, + childList: TRUE + }); + } + /** + * Start observing a generic document or root element. + * @param {Function} callback triggered per each dis/connected node + * @param {Element?} root by default, the global document to observe + * @param {Function?} MO by default, the global MutationObserver + * @returns {MutationObserver} + */ - var mainLoop = function mainLoop(records) { - for (var i = 0, length = records.length; i < length; i++) { - var _records$i2 = records[i], - addedNodes = _records$i2.addedNodes, - removedNodes = _records$i2.removedNodes; - parse(filter.call(addedNodes, elements), 'c', new Set()); - parse(filter.call(removedNodes, elements), 'd', new Set()); - } - }; - var parse = function parse(nodes, key, parsed) { + var notify = function notify(callback, root, MO) { + var loop = function loop(nodes, added, removed, connected, pass) { for (var i = 0, length = nodes.length; i < length; i++) { - var target = nodes[i]; + var node = nodes[i]; + + if (pass || QSA$1 in node) { + if (connected) { + if (!added.has(node)) { + added.add(node); + removed["delete"](node); + callback(node, connected); + } + } else if (!removed.has(node)) { + removed.add(node); + added["delete"](node); + callback(node, connected); + } - if (!parsed.has(target)) { - parsed.add(target); - if (wm.has(target)) wm.get(target)[key].forEach(call, target);else if (key === 'c') upgrade(target); - parse(target.querySelectorAll('*'), key, parsed); + if (!pass) loop(node[QSA$1]('*'), added, removed, connected, TRUE); } } }; - var set = function set(target) { - var sets = { - c: new Set(), - d: new Set() - }; - wm.set(target, sets); - return sets; - }; - - var sdo = new MutationObserver(mainLoop); - sdo.observe(root, { - childList: true, - subtree: true - }); - return function (target, _ref) { - var connectedCallback = _ref.connectedCallback, - disconnectedCallback = _ref.disconnectedCallback, - observedAttributes = _ref.observedAttributes, - attributeChangedCallback = _ref.attributeChangedCallback; - mainLoop(sdo.takeRecords()); - - var _ref2 = wm.get(target) || set(target), - c = _ref2.c, - d = _ref2.d; - - if (observedAttributes) { - var mo = new MutationObserver(attributeChanged); - mo.observe(target, { - attributes: true, - attributeOldValue: true, - attributeFilter: observedAttributes.map(function (attributeName) { - if (target.hasAttribute(attributeName)) attributeChangedCallback.call(target, attributeName, null, target.getAttribute(attributeName)); - return attributeName; - }) - }); - ao.set(mo, attributeChangedCallback); + var observer = new (MO || MutationObserver)(function (records) { + for (var added = new Set(), removed = new Set(), i = 0, length = records.length; i < length; i++) { + var _records$i = records[i], + addedNodes = _records$i.addedNodes, + removedNodes = _records$i.removedNodes; + loop(removedNodes, added, removed, FALSE, FALSE); + loop(addedNodes, added, removed, TRUE, FALSE); } + }); + observer.add = add; + observer.add(root || document); + return observer; + }; - if (disconnectedCallback) d.add(disconnectedCallback); + var QSA = 'querySelectorAll'; + var _self = self, + document$1 = _self.document, + Element = _self.Element, + MutationObserver$1 = _self.MutationObserver, + Set$1 = _self.Set, + WeakMap$1 = _self.WeakMap; - if (connectedCallback) { - c.add(connectedCallback); - if (!(target.ownerDocument.compareDocumentPosition(target) & target.DOCUMENT_POSITION_DISCONNECTED)) connectedCallback.call(target); - } + var elements = function elements(element) { + return QSA in element; + }; - return target; - }; - }); + var filter = [].filter; + var QSAO = (function (options) { + var live = new WeakMap$1(); - function call(back) { - back.call(this); - } - - var Lie = typeof Promise === 'function' ? Promise : function (fn) { - var queue = [], - resolved = 0; - fn(function () { - resolved = 1; - queue.splice(0).forEach(then); - }); - return { - then: then + var drop = function drop(elements) { + for (var i = 0, length = elements.length; i < length; i++) { + live["delete"](elements[i]); + } }; - function then(fn) { - return resolved ? setTimeout(fn) : queue.push(fn), this; - } - }; - var utils = (function (root, query, config, defined, setup) { - // exports - var get = function get(selector) { - var i = query.indexOf(selector); - return i < 0 ? void 0 : config[i].o; - }; + var flush = function flush() { + var records = observer.takeRecords(); - var upgrade = function upgrade(node) { - upgradeNode(node, new Set()); + for (var i = 0, length = records.length; i < length; i++) { + parse(filter.call(records[i].removedNodes, elements), false); + parse(filter.call(records[i].addedNodes, elements), true); + } }; - var whenDefined = function whenDefined(selector) { - if (!(selector in defined)) { - var _, - $ = new Lie(function ($) { - _ = $; - }); - - defined[selector] = { - _: _, - $: $ - }; - } + var matches = function matches(element) { + return element.matches || element.webkitMatchesSelector || element.msMatchesSelector; + }; - return defined[selector].$; - }; // util + var notifier = function notifier(element, connected) { + var selectors; + if (connected) { + for (var q, m = matches(element), i = 0, length = query.length; i < length; i++) { + if (m.call(element, q = query[i])) { + if (!live.has(element)) live.set(element, new Set$1()); + selectors = live.get(element); - var setupList = function setupList(nodes, parsed) { - for (var i = 0, length = nodes.length; i < length; i++) { - if (!parsed.has(nodes[i])) { - parsed.add(nodes[i]); - upgradeNode(nodes[i], parsed); + if (!selectors.has(q)) { + selectors.add(q); + options.handle(element, connected, q); + } + } } + } else if (live.has(element)) { + selectors = live.get(element); + live["delete"](element); + selectors.forEach(function (q) { + options.handle(element, connected, q); + }); } }; - var upgradeAll = function upgradeAll(node, parsed) { - if (query.length) setupList(node.querySelectorAll(query), parsed); - }; + var parse = function parse(elements) { + var connected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; - var upgradeNode = function upgradeNode(node, parsed) { - for (var i = 0, length = query.length; i < length; i++) { - if ((node.matches || node.webkitMatchesSelector || node.msMatchesSelector).call(node, query[i])) setup(node, config[i]); + for (var i = 0, length = elements.length; i < length; i++) { + notifier(elements[i], connected); } - - if (parsed) upgradeAll(node, parsed); }; + var query = options.query; + var root = options.root || document$1; + var observer = notify(notifier, root, MutationObserver$1); + var attachShadow = Element.prototype.attachShadow; + if (attachShadow) Element.prototype.attachShadow = function (init) { + var shadowRoot = attachShadow.call(this, init); + observer.add(shadowRoot); + return shadowRoot; + }; + if (query.length) parse(root[QSA](query)); return { - get: get, - upgrade: upgrade, - whenDefined: whenDefined, - $: setupList, - _: asCustomElement(root, upgradeNode) + drop: drop, + flush: flush, + observer: observer, + parse: parse }; }); var create = Object.create, keys = Object.keys; - var config = []; + var attributes = new WeakMap(); + var lazy = new Set(); var query = []; + var config = {}; var defined = {}; - var lazy = new Set(); - var wicked = new WeakMap(); - var callbacks = new WeakMap(); - - var _utils = utils(document, query, config, defined, function (value, _ref) { - var m = _ref.m, - l = _ref.l, - o = _ref.o; - - if (!m.has(value)) { - var handler = create(o, { - element: { - enumerable: true, - value: value - } - }); - m.set(value, 0); - if (!wicked.has(value)) wicked.set(value, []); - wicked.get(value).push(handler); - for (var i = 0, length = l.length; i < length; i++) { - value.addEventListener(l[i].t, handler, l[i].o); + var attributeChangedCallback = function attributeChangedCallback(records, o) { + for (var h = attributes.get(o), i = 0, length = records.length; i < length; i++) { + var _records$i = records[i], + target = _records$i.target, + attributeName = _records$i.attributeName, + oldValue = _records$i.oldValue; + var newValue = target.getAttribute(attributeName); + h.attributeChanged(attributeName, oldValue, newValue); + } + }; + + var set = function set(value, m, l, o) { + var handler = create(o, { + element: { + enumerable: true, + value: value } + }); - if (handler.init) handler.init(); - asCustomElement$1(value, o); + for (var i = 0, length = l.length; i < length; i++) { + value.addEventListener(l[i].t, handler, l[i].o); } - }), - get = _utils.get, - upgrade = _utils.upgrade, - whenDefined = _utils.whenDefined, - setupList = _utils.$, - asCustomElement$1 = _utils._; - - var delegate = function delegate(key, method, notAC) { - return function (name) { - for (var h = wicked.get(this), i = 0, length = h.length; i < length; i++) { - if (method === h[i][key] && (notAC || -1 < (h[i].observedAttributes || []).indexOf(name))) method.apply(h[i], arguments); - } - }; + + m.set(value, handler); + if (handler.init) handler.init(); + var observedAttributes = o.observedAttributes; + + if (observedAttributes) { + var mo = new MutationObserver(attributeChangedCallback); + mo.observe(value, { + attributes: true, + attributeOldValue: true, + attributeFilter: observedAttributes.map(function (attributeName) { + if (value.hasAttribute(attributeName)) handler.attributeChanged(attributeName, null, value.getAttribute(attributeName)); + return attributeName; + }) + }); + attributes.set(mo, handler); + } + + return handler; }; - var define = function define(selector, definition) { - if (get(selector)) throw new Error('duplicated: ' + selector); + var _QSAO = QSAO({ + query: query, + handle: function handle(element, connected, selector) { + var _config$selector = config[selector], + m = _config$selector.m, + l = _config$selector.l, + o = _config$selector.o; + var handler = m.get(element) || set(element, m, l, o); + var method = connected ? 'connected' : 'disconnected'; + if (method in handler) handler[method](); + } + }), + drop = _QSAO.drop, + flush = _QSAO.flush, + parse = _QSAO.parse; + + var get = function get(selector) { + return (config[selector] || attributes).o; + }; + var define$1 = function define(selector, definition) { + if (-1 < query.indexOf(selector)) throw new Error('duplicated: ' + selector); + flush(); var listeners = []; var retype = create(null); for (var k = keys(definition), i = 0, length = k.length; i < length; i++) { var key = k[i]; - if (/^(?:connected|disconnected|attributeChanged)$/.test(key)) { - if (!callbacks.has(definition[key])) callbacks.set(definition[key], delegate(key, definition[key], key[0] !== 'a')); - definition[key + 'Callback'] = callbacks.get(definition[key]); - } else if (/^on/.test(key) && !/Options$/.test(key)) { + if (/^on/.test(key) && !/Options$/.test(key)) { var options = definition[key + 'Options'] || false; var lower = key.toLowerCase(); var type = lower.slice(2); @@ -541,52 +469,72 @@ var hookedElements = (function (exports) { } query.push(selector); - config.push({ + config[selector] = { m: new WeakMap(), l: listeners, o: definition - }); - setupList(document.querySelectorAll(selector), new Set()); + }; + parse(document.querySelectorAll(selector)); whenDefined(selector); if (!lazy.has(selector)) defined[selector]._(); }; - var defineAsync = function defineAsync(selector, callback, _) { + var defineAsync$1 = function defineAsync(selector, callback, _) { lazy.add(selector); - define(selector, { + define$1(selector, { init: function init() { if (lazy.has(selector)) { lazy["delete"](selector); - callback().then(function (_ref2) { - var definition = _ref2["default"]; - var i = query.indexOf(selector); - query.splice(i, 1); - config.splice(i, 1); + callback().then(function (_ref) { + var definition = _ref["default"]; + query.splice(query.indexOf(selector), 1); + drop(document.querySelectorAll(selector)); - (_ || define)(selector, definition); + (_ || define$1)(selector, definition); }); } } }); }; + var upgrade = function upgrade(element) { + if (query.length) { + flush(); + parse([element]); + } + }; + var whenDefined = function whenDefined(selector) { + if (!(selector in defined)) { + var _, + $ = new Lie(function ($) { + _ = $; + }); + + defined[selector] = { + _: _, + $: $ + }; + } + + return defined[selector].$; + }; function init() { render(this); } - var define$1 = function define$1(selector, definition) { - define(selector, typeof definition === 'function' ? { + var define = function define(selector, definition) { + define$1(selector, typeof definition === 'function' ? { init: init, render: definition } : (definition.init || (definition.init = init), definition)); }; - var defineAsync$1 = function defineAsync$1(selector, callback) { - defineAsync(selector, callback, define$1); + var defineAsync = function defineAsync(selector, callback) { + defineAsync$1(selector, callback, define); }; var render = function render(wicked) { var disconnected = wicked.disconnected, element = wicked.element, render = wicked.render; - var hook = augmentor(render.bind(wicked, element)); + var hook = hooked(render.bind(wicked, element)); wicked.disconnected = function () { if (hasEffect(hook)) dropEffect(hook); @@ -597,8 +545,8 @@ var hookedElements = (function (exports) { }; exports.createContext = createContext; - exports.define = define$1; - exports.defineAsync = defineAsync$1; + exports.define = define; + exports.defineAsync = defineAsync; exports.get = get; exports.render = render; exports.upgrade = upgrade; diff --git a/min.js b/min.js index 03c7c71..0a373a5 100644 --- a/min.js +++ b/min.js @@ -1,2 +1 @@ -var hookedElements=function(e){"use strict";var t="function"==typeof cancelAnimationFrame,n=t?cancelAnimationFrame:clearTimeout,r=t?requestAnimationFrame:setTimeout;function a(e){var a,u,o,i,c;return s(),function(e,t,n){return o=e,i=t,c=n,u||(u=r(l)),--a<0&&f(!0),f};function l(){s(),o.apply(i,c||[])}function s(){a=e||1/0,u=t?0:null}function f(e){var t=!!u;return t&&(n(u),e&&l()),t}}var u=function(e){return{get:function(t){return e.get(t)},set:function(t,n){return e.set(t,n),n}}},o=null,i=u(new WeakMap),c=function(e,t,n){e.apply(t,n)},l={async:!1,always:!1},s=function(e,t){return"function"==typeof t?t(e):t},f=function(e,t,n,r){var u=o.i++,f=o,h=f.hook,v=f.args,d=f.stack,p=f.length;u===p&&(o.length=d.push({}));var g=d[u];if(g.args=v,u===p){var m="function"==typeof n,k=(m?r:n)||r||l,b=k.async,w=k.always;g.$=m?n(t):s(void 0,t),g._=b?i.get(h)||i.set(h,a()):c,g.f=function(t){var n=e(g.$,t);(w||g.$!==n)&&(g.$=n,g._(h,null,g.args))}}return[g.$,g.f]},h=new WeakMap,v=function(e){var t=e.hook,n=e.args;t.apply(null,n)}; -/*! (c) Andrea Giammarchi - ISC */function d(e){this.value!==e&&(this.value=e,h.get(this).forEach(v))}function p(e){return e.hook===this.hook}var g=new WeakMap,m=u(g),k=function(){},b=function(e){return function(t,n){var r=o.i++,u=o,i=u.hook,c=u.after,l=u.stack;if(r1&&void 0!==arguments[1])||arguments[1],r=0,u=e.length;r({get:t=>e.get(t),set:(t,n)=>(e.set(t,n),n)}) -/*! (c) Andrea Giammarchi - ISC */;let l=null;const r=a(new WeakMap),c=(e,t,n)=>{e.apply(t,n)},u={async:!1,always:!1},i=(e,t)=>"function"==typeof t?t(e):t,h=(e,t,n,s)=>{const a=l.i++,{hook:h,args:d,stack:f,length:p}=l;a===p&&(l.length=f.push({}));const g=f[a];if(g.args=d,a===p){const a="function"==typeof n,{async:l,always:d}=(a?s:n)||s||u;g.$=a?n(t):i(void 0,t),g._=l?r.get(h)||r.set(h,o()):c,g.f=t=>{const n=e(g.$,t);(d||g.$!==n)&&(g.$=n,g._(h,null,g.args))}}return[g.$,g.f]},d=new WeakMap,f=({hook:e,args:t})=>{e.apply(null,t)};function p(e){this.value!==e&&(this.value=e,d.get(this).forEach(f))}function g({hook:e}){return e===this.hook}const m=new WeakMap,k=a(m),w=()=>{},b=e=>(t,n)=>{const s=l.i++,{hook:a,after:r,stack:c,length:u}=l;if(s{o.clean=t()};e?a(l):r.push(l)}}else{const s=e?o():w,u={clean:null,update:s,values:n,stop:w};l.length=c.push(u),(k.get(a)||k.set(a,[])).push(u);const i=()=>{u.clean=t()};e?u.stop=s(i):r.push(i)}},v=m.has.bind(m),y=b(!0),S=b(!1),C=(e,t)=>{const n=l.i++,{stack:s,length:o}=l;return n===o?l.length=s.push({$:e(),_:t}):t&&!t.some(M,s[n]._)||(s[n]={$:e(),_:t}),s[n].$};function M(e,t){return e!==this[t]}var $=(e,t)=>{const n=new WeakMap,s=new WeakMap,{filter:o}=[],a=(e,t)=>{for(let n=0,{length:o}=e;n"querySelectorAll"in e,r=e=>{for(let t=0,{length:n}=e;t{for(let a=0,{length:l}=e;a{r(u.takeRecords());const{c:i,d:h}=n.get(e)||(e=>{const t={c:new Set,d:new Set};return n.set(e,t),t})(e);if(l){const t=new MutationObserver(a);t.observe(e,{attributes:!0,attributeOldValue:!0,attributeFilter:l.map(t=>(e.hasAttribute(t)&&c.call(e,t,null,e.getAttribute(t)),t))}),s.set(t,c)}return o&&h.add(o),t&&(i.add(t),e.ownerDocument.compareDocumentPosition(e)&e.DOCUMENT_POSITION_DISCONNECTED||t.call(e)),e}};function A(e){e.call(this)}const E="function"==typeof Promise?Promise:function(e){let t=[],n=0;return e(()=>{n=1,t.splice(0).forEach(s)}),{then:s};function s(e){return n?setTimeout(e):t.push(e),this}};const{create:O,keys:_}=Object,D=[],W=[],N={},T=new Set,q=new WeakMap,x=new WeakMap,{get:L,upgrade:F,whenDefined:P,$:I,_:R}=((e,t,n,s,o)=>{const a=(e,t)=>{for(let n=0,{length:s}=e;n{for(let s=0,{length:a}=t;s{t.length&&a(e.querySelectorAll(t),n)})(e,s)};return{get:e=>{const s=t.indexOf(e);return s<0?void 0:n[s].o},upgrade:e=>{l(e,new Set)},whenDefined:e=>{if(!(e in s)){let t,n=new E(e=>{t=e});s[e]={_:t,$:n}}return s[e].$},$:a,_:$(e,l)}})(document,W,D,N,(e,{m:t,l:n,o:s})=>{if(!t.has(e)){const o=O(s,{element:{enumerable:!0,value:e}});t.set(e,0),q.has(e)||q.set(e,[]),q.get(e).push(o);for(let t=0,{length:s}=n;tfunction(s){for(let o=q.get(this),a=0,{length:l}=o;a{if(L(e))throw new Error("duplicated: "+e);const n=[],s=O(null);for(let e=_(t),o=0,{length:a}=e;o{j(e,"function"==typeof t?{init:U,render:t}:(t.init||(t.init=U),t))},B=e=>{const{disconnected:t,element:n,render:s}=e,o=(e=>{const t=[];return function n(){const s=l,o=[];l={hook:n,args:arguments,stack:t,i:0,length:t.length,after:o};try{return e.apply(null,arguments)}finally{l=s;for(let e=0,{length:t}=o;e{v(o)&&(e=>{(m.get(e)||[]).forEach(e=>{const{clean:t,stop:n}=e;n(),t&&(e.clean=null,t())})})(o),t&&t.call(e)},(e.render=o)()};return e.createContext=e=>{const t={value:e,provide:p};return d.set(t,[]),t},e.define=z,e.defineAsync=(e,t)=>{((e,t,n)=>{T.add(e),j(e,{init(){T.has(e)&&(T.delete(e),t().then(({default:t})=>{const s=W.indexOf(e);W.splice(s,1),D.splice(s,1),(n||j)(e,t)}))}})})(e,t,z)},e.get=L,e.render=B,e.upgrade=F,e.useCallback=(e,t)=>C(()=>e,t),e.useContext=e=>{const{hook:t,args:n}=l,s=d.get(e),o={hook:t,args:n};return s.some(g,o)||s.push(o),e.value},e.useEffect=y,e.useLayoutEffect=S,e.useMemo=C,e.useReducer=h,e.useRef=e=>{const t=l.i++,{stack:n,length:s}=l;return t===s&&(l.length=n.push({current:e})),n[t]},e.useState=(e,t)=>h(i,e,void 0,t),e.whenDefined=P,e}({}); +var hookedElements=function(e){"use strict";var t=Promise;let n=null,s=new Set;const o=e=>{const{$:t,r:n,h:s}=e;u(n)&&(l.get(s).delete(e),n()),u(e.r=t())&&l.get(s).add(e)},r=()=>{const e=s;s=new Set,e.forEach((({h:e,c:t,a:n,e:s})=>{s&&e.apply(t,n)}))},l=new WeakMap,a=[],c=[];function i(e,t){return e!==this[t]}const d=()=>n,u=e=>"function"==typeof e,h=e=>{const t={h:s,c:null,a:null,e:0,i:0,s:[]};return s;function s(){const s=n;n=t,t.e=t.i=0;try{return e.apply(t.c=this,t.a=arguments)}finally{n=s,a.length&&f.then(a.forEach.bind(a.splice(0),o)),c.length&&c.splice(0).forEach(o)}}},f=new t((e=>e()));function p(e){const{_:t,value:n}=this;n!==e&&(this._=new Set,this.value=e,t.forEach((({h:e,c:t,a:n})=>{e.apply(t,n)})))}const g=(e,t)=>{const n=d(),{i:s,s:o}=n;return s!==o.length&&t&&!t.some(i,o[s]._)||(o[s]={$:e(),_:t}),o[n.i++].$},w=e=>(t,n)=>{const s=d(),{i:o,s:r,h:a}=s,c=o===r.length;s.i++,c&&(l.has(a)||l.set(a,new Set),r[o]={$:t,_:n,r:null,h:a}),(c||!n||n.some(i,r[o]._))&&e.push(r[o]),r[o].$=t,r[o]._=n},b=w(a),m=w(c),v=(e,t)=>u(t)?t(e):t,y=(e,t,n)=>{const o=d(),{i:l,s:a}=o;l===a.length&&a.push({$:u(n)?n(t):v(void 0,t),set:t=>{a[l].$=e(a[l].$,t),(e=>{s.has(e)||(e.e=1,s.add(e),f.then(r))})(o)}});const{$:c,set:i}=a[o.i++];return[c,i]},S=!0,E=!1,$="querySelectorAll";function _(e){this.observe(e,{subtree:S,childList:S})}const M="querySelectorAll",{document:k,Element:A,MutationObserver:O,Set:C,WeakMap:q}=self,L=e=>M in e,{filter:N}=[];const{create:x,keys:W}=Object,R=new WeakMap,V=new Set,j=[],D={},F={},P=(e,t)=>{for(let n=R.get(t),s=0,{length:o}=e;s{const t=new q,n=(n,s)=>{let r;if(s)for(let l,a=(e=>e.matches||e.webkitMatchesSelector||e.msMatchesSelector)(n),c=0,{length:i}=o;c{e.handle(n,s,t)})))},s=(e,t=!0)=>{for(let s=0,{length:o}=e;s{const s=(t,n,o,r,l)=>{for(let a=0,{length:c}=t;a{for(let t=new Set,n=new Set,o=0,{length:r}=e;o{for(let n=0,{length:s}=e;n{const e=l.takeRecords();for(let t=0,{length:n}=e;t{const o=x(s,{element:{enumerable:!0,value:e}});for(let t=0,{length:s}=n;t(e.hasAttribute(t)&&o.attributeChanged(t,null,e.getAttribute(t)),t)))}),R.set(t,o)}return o})(e,s,o,r),a=t?"connected":"disconnected";a in l&&l[a]()}}),H=(e,t)=>{if(-1{if(!(e in F)){let n,s=new t((e=>{n=e}));F[e]={_:n,$:s}}return F[e].$};function J(){Q(this)}const K=(e,t)=>{H(e,"function"==typeof t?{init:J,render:t}:(t.init||(t.init=J),t))},Q=e=>{const{disconnected:t,element:n,render:s}=e,o=h(s.bind(e,n));return e.disconnected=()=>{(e=>l.has(e))(o)&&(e=>{const t=l.get(e);t&&f.then((()=>{t.forEach((e=>{e.r(),e.r=null})),t.clear()}))})(o),t&&t.call(e)},(e.render=o)()};return e.createContext=e=>({_:new Set,provide:p,value:e}),e.define=K,e.defineAsync=(e,t)=>{((e,t,n)=>{V.add(e),H(e,{init(){V.has(e)&&(V.delete(e),t().then((({default:t})=>{j.splice(j.indexOf(e),1),z(document.querySelectorAll(e)),(n||H)(e,t)})))}})})(e,t,K)},e.get=e=>(D[e]||R).o,e.render=Q,e.upgrade=e=>{j.length&&(B(),G([e]))},e.useCallback=(e,t)=>g((()=>e),t),e.useContext=({_:e,value:t})=>(e.add(d()),t),e.useEffect=b,e.useLayoutEffect=m,e.useMemo=g,e.useReducer=y,e.useRef=e=>{const t=d(),{i:n,s:s}=t;return n===s.length&&s.push({current:e}),s[t.i++]},e.useState=e=>y(v,e),e.whenDefined=I,e}({}); diff --git a/package.json b/package.json index 2bb41b7..8626aaa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hooked-elements", - "version": "1.2.1", + "version": "2.2.2", "description": "wickedElements 🧙 with render hooks", "main": "./cjs/index.js", "scripts": { @@ -21,23 +21,23 @@ "author": "Andrea Giammarchi", "license": "ISC", "devDependencies": { - "@babel/core": "^7.10.5", - "@babel/preset-env": "^7.10.4", - "@ungap/degap": "^0.2.0", - "ascjs": "^4.0.1", + "@babel/core": "^7.14.0", + "@babel/preset-env": "^7.14.1", + "@ungap/degap": "^0.2.6", + "ascjs": "^5.0.1", "http-server": "^0.12.3", - "rollup": "^2.23.0", + "rollup": "^2.47.0", "rollup-plugin-babel": "^4.4.0", - "rollup-plugin-includepaths": "^0.2.3", + "rollup-plugin-includepaths": "^0.2.4", "rollup-plugin-node-resolve": "^5.2.0", - "rollup-plugin-terser": "^6.1.0", - "terser": "^4.8.0" + "rollup-plugin-terser": "^7.0.2", + "terser": "^5.7.0" }, "module": "./esm/index.js", "unpkg": "min.js", "dependencies": { - "augmentor": "^2.2.0", - "wicked-elements": "^3.0.19" + "uhooks": "^0.2.8", + "wicked-elements": "^3.1.2" }, "repository": { "type": "git", diff --git a/rollup/babel.config.js b/rollup/babel.config.js index 02974e8..db109e4 100644 --- a/rollup/babel.config.js +++ b/rollup/babel.config.js @@ -10,6 +10,7 @@ export default { ], output: { + esModule: false, exports: 'named', file: './index.js', format: 'iife', diff --git a/rollup/new.config.js b/rollup/new.config.js index 023ab1f..74f9b6f 100644 --- a/rollup/new.config.js +++ b/rollup/new.config.js @@ -8,7 +8,8 @@ export default { includePaths({ include: { '@ungap/element-matches': 'node_modules/@ungap/degap/element-matches.js', - '@ungap/node-contains': 'node_modules/@ungap/degap/node-contains.js' + '@ungap/node-contains': 'node_modules/@ungap/degap/node-contains.js', + '@webreflection/lie': 'node_modules/@ungap/degap/promise.js' }, }), resolve({module: true}), @@ -16,6 +17,7 @@ export default { ], output: { + esModule: false, exports: 'named', file: './new.js', format: 'iife', diff --git a/test/counter.html b/test/counter.html index 475a031..a8baa76 100644 --- a/test/counter.html +++ b/test/counter.html @@ -4,7 +4,7 @@ - wicked counter + hooked counter