diff --git a/alpinejs/README.md b/alpinejs/README.md index b1035e8..f1c807f 100644 --- a/alpinejs/README.md +++ b/alpinejs/README.md @@ -28,7 +28,14 @@ import persist from 'jslibs/alpinejs/v3/persist/dist/module.esm.js'; Alpine.start(); })(); +``` + +Note that AlpineJS now requires ES target 2017 or later to work: +```handlebars +{{ $params := dict }} +{{ $opts := dict "sourceMap" $sourceMap "minify" (ne hugo.Environment "development") "target" "es2017" "params" $params }} +{{ $js := $js | js.Build $opts }} ``` Note that this works great in combination with [Turbo](https://github.com/gohugoio/hugo-mod-jslibs/tree/master/turbo), but you would need to set up something like [these listeners](https://gist.github.com/bep/a9809f0cb119e44e8ddbe37dd1e58b50) to make it work properly. diff --git a/alpinejs/packages/alpinejs/dist/cdn.js b/alpinejs/packages/alpinejs/dist/cdn.js index 8efaead..895c485 100644 --- a/alpinejs/packages/alpinejs/dist/cdn.js +++ b/alpinejs/packages/alpinejs/dist/cdn.js @@ -3,6 +3,7 @@ var flushPending = false; var flushing = false; var queue = []; + var lastFlushedIndex = -1; function scheduler(callback) { queueJob(callback); } @@ -13,7 +14,7 @@ } function dequeueJob(job) { let index = queue.indexOf(job); - if (index !== -1) + if (index !== -1 && index > lastFlushedIndex) queue.splice(index, 1); } function queueFlush() { @@ -27,8 +28,10 @@ flushing = true; for (let i = 0; i < queue.length; i++) { queue[i](); + lastFlushedIndex = i; } queue.length = 0; + lastFlushedIndex = -1; flushing = false; } @@ -46,13 +49,13 @@ function setReactivityEngine(engine) { reactive = engine.reactive; release = engine.release; - effect = (callback) => engine.effect(callback, {scheduler: (task) => { + effect = (callback) => engine.effect(callback, { scheduler: (task) => { if (shouldSchedule) { scheduler(task); } else { task(); } - }}); + } }); raw = engine.raw; } function overrideEffect(override) { @@ -64,7 +67,7 @@ let wrappedEffect = (callback) => { let effectReference = effect(callback); if (!el._x_effects) { - el._x_effects = new Set(); + el._x_effects = /* @__PURE__ */ new Set(); el._x_runEffects = () => { el._x_effects.forEach((i) => i()); }; @@ -83,6 +86,120 @@ }]; } + // packages/alpinejs/src/utils/dispatch.js + function dispatch(el, name, detail = {}) { + el.dispatchEvent( + new CustomEvent(name, { + detail, + bubbles: true, + // Allows events to pass the shadow DOM barrier. + composed: true, + cancelable: true + }) + ); + } + + // packages/alpinejs/src/utils/walk.js + function walk(el, callback) { + if (typeof ShadowRoot === "function" && el instanceof ShadowRoot) { + Array.from(el.children).forEach((el2) => walk(el2, callback)); + return; + } + let skip = false; + callback(el, () => skip = true); + if (skip) + return; + let node = el.firstElementChild; + while (node) { + walk(node, callback, false); + node = node.nextElementSibling; + } + } + + // packages/alpinejs/src/utils/warn.js + function warn(message, ...args) { + console.warn(`Alpine Warning: ${message}`, ...args); + } + + // packages/alpinejs/src/lifecycle.js + var started = false; + function start() { + if (started) + warn("Alpine has already been initialized on this page. Calling Alpine.start() more than once can cause problems."); + started = true; + if (!document.body) + warn("Unable to initialize. Trying to load Alpine before `` is available. Did you forget to add `defer` in Alpine's ` + ``` @@ -29,7 +36,7 @@ Like all Alpine extensions, you can include this either via ` - - ... + + + ... ``` @@ -33,7 +33,7 @@ This is by far the simplest way to get started with Alpine. Include the followin Notice the `@3.x.x` in the provided CDN link. This will pull the latest version of Alpine version 3. For stability in production, it's recommended that you hardcode the latest version in the CDN link. ```alpine - + ``` That's it! Alpine is now available for use inside your page. @@ -61,8 +61,9 @@ Alpine.start() > The `window.Alpine = Alpine` bit is optional, but is nice to have for freedom and flexibility. Like when tinkering with Alpine from the devtools for example. - > If you imported Alpine into a bundle, you have to make sure you are registering any extension code IN BETWEEN when you import the `Alpine` global object, and when you initialize Alpine by calling `Alpine.start()`. +> Ensure that `Alpine.start()` is only called once per page. Calling it more than once will result in multiple "instances" of Alpine running at the same time. + [→ Read more about extending Alpine](/advanced/extending) diff --git a/alpinejs/packages/docs/src/en/essentials/lifecycle.md b/alpinejs/packages/docs/src/en/essentials/lifecycle.md index 7a6d321..f3f9297 100644 --- a/alpinejs/packages/docs/src/en/essentials/lifecycle.md +++ b/alpinejs/packages/docs/src/en/essentials/lifecycle.md @@ -87,7 +87,7 @@ document.addEventListener('alpine:init', () => { ### `alpine:initialized` -Alpine also offers a hook that you can use to execute code After it's done initializing called `alpine:initialized`: +Alpine also offers a hook that you can use to execute code AFTER it's done initializing called `alpine:initialized`: ```js document.addEventListener('alpine:initialized', () => { diff --git a/alpinejs/packages/docs/src/en/globals/alpine-data.md b/alpinejs/packages/docs/src/en/globals/alpine-data.md index 51e40a6..d2b84dc 100644 --- a/alpinejs/packages/docs/src/en/globals/alpine-data.md +++ b/alpinejs/packages/docs/src/en/globals/alpine-data.md @@ -87,6 +87,43 @@ Alpine.data('dropdown', () => ({ })) ``` + +## Destroy functions + +If your component contains a `destroy()` method, Alpine will automatically execute it before cleaning up the component. + +A primary example for this is when registering an event handler with another library or a browser API that isn't available through Alpine. +See the following example code on how to use the `destroy()` method to clean up such a handler. + +```js +Alpine.data('timer', () => ({ + timer: null, + counter: 0, + init() { + // Register an event handler that references the component instance + this.timer = setInterval(() => { + console.log('Increased counter to', ++this.counter); + }, 1000); + }, + destroy() { + // Detach the handler, avoiding memory and side-effect leakage + clearInterval(this.timer); + }, +})) +``` + +An example where a component is destroyed is when using one inside an `x-if`: + +```html + + + + + +``` + ## Using magic properties diff --git a/alpinejs/packages/docs/src/en/magics/watch.md b/alpinejs/packages/docs/src/en/magics/watch.md index e70886e..3fc402a 100644 --- a/alpinejs/packages/docs/src/en/magics/watch.md +++ b/alpinejs/packages/docs/src/en/magics/watch.md @@ -39,7 +39,7 @@ When the ` - + + ## x-mask The primary API for using this plugin is the `x-mask` directive. @@ -80,13 +82,14 @@ Notice how the text you type into the input field must adhere to the format prov The following wildcard characters are supported in masks: -| Wildcard | Description | -| -------------------------- | --------------------------- | -| `*` | Any character | -| `a` | Only alpha characters (a-z, A-Z) | -| `9` | Only numeric characters (0-9) | +| Wildcard | Description | +| -------- | -------------------------------- | +| `*` | Any character | +| `a` | Only alpha characters (a-z, A-Z) | +| `9` | Only numeric characters (0-9) | + ## Dynamic Masks Sometimes simple mask literals (i.e. `(999) 999-9999`) are not sufficient. In these cases, `x-mask:dynamic` allows you to dynamically generate masks on the fly based on user input. @@ -113,7 +116,7 @@ Try it for yourself by typing a number that starts with "34" and one that doesn' -`x-mask:dynamic` also accepts a function as a result of the expression and will automatically pass it the `$input` as the the first paramter. For example: +`x-mask:dynamic` also accepts a function as a result of the expression and will automatically pass it the `$input` as the the first parameter. For example: ```alpine @@ -128,6 +131,7 @@ function creditCardMask(input) { ``` + ## Money Inputs Because writing your own dynamic mask expression for money inputs is fairly complex, Alpine offers a prebuilt one and makes it available as `$money()`. @@ -155,3 +159,28 @@ If you wish to swap the periods for commas and vice versa (as is required in cer + +You may also choose to override the thousands separator by supplying a third optional argument: + +```alpine + +``` + + +
+ +
+ + + +You can also override the default precision of 2 digits by using any desired number of digits as the fourth optional argument: + +```alpine + +``` + + +
+ +
+ diff --git a/alpinejs/packages/docs/src/en/plugins/morph.md b/alpinejs/packages/docs/src/en/plugins/morph.md index 2ff0232..135a459 100644 --- a/alpinejs/packages/docs/src/en/plugins/morph.md +++ b/alpinejs/packages/docs/src/en/plugins/morph.md @@ -9,7 +9,7 @@ graph_image: https://alpinejs.dev/social_morph.jpg Alpine's Morph plugin allows you to "morph" an element on the page into the provided HTML template, all while preserving any browser or Alpine state within the "morphed" element. -This is useful for updating HTML from a server request without loosing Alpine's on-page state. A utility like this is at the core of full-stack frameworks like [Laravel Livewire](https://laravel-livewire.com/) and [Phoenix LiveView](https://dockyard.com/blog/2018/12/12/phoenix-liveview-interactive-real-time-apps-no-need-to-write-javascript). +This is useful for updating HTML from a server request without losing Alpine's on-page state. A utility like this is at the core of full-stack frameworks like [Laravel Livewire](https://laravel-livewire.com/) and [Phoenix LiveView](https://dockyard.com/blog/2018/12/12/phoenix-liveview-interactive-real-time-apps-no-need-to-write-javascript). The best way to understand its purpose is with the following interactive visualization. Give it a try! @@ -41,10 +41,10 @@ You can include the CDN build of this plugin as a ` + - + ``` ### Via NPM diff --git a/alpinejs/packages/docs/src/en/plugins/persist.md b/alpinejs/packages/docs/src/en/plugins/persist.md index d08bd76..f885019 100644 --- a/alpinejs/packages/docs/src/en/plugins/persist.md +++ b/alpinejs/packages/docs/src/en/plugins/persist.md @@ -22,10 +22,10 @@ You can include the CDN build of this plugin as a ` + - + ``` ### Via NPM @@ -204,4 +204,4 @@ Alpine.data('dropdown', function () { Alpine.store('darkMode', { on: Alpine.$persist(true).as('darkMode_on') }); -``` \ No newline at end of file +``` diff --git a/alpinejs/packages/docs/src/en/start-here.md b/alpinejs/packages/docs/src/en/start-here.md index f3e9ef5..0886426 100644 --- a/alpinejs/packages/docs/src/en/start-here.md +++ b/alpinejs/packages/docs/src/en/start-here.md @@ -12,7 +12,7 @@ Using a text editor, fill the file with these contents: ```alpine - +

diff --git a/alpinejs/packages/docs/src/en/ui.md b/alpinejs/packages/docs/src/en/ui.md deleted file mode 100644 index 14a4b16..0000000 --- a/alpinejs/packages/docs/src/en/ui.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -order: 5 -title: UI -font-type: mono -type: sub-directory ---- diff --git a/alpinejs/packages/focus/dist/cdn.js b/alpinejs/packages/focus/dist/cdn.js index af5dd15..bc7c110 100644 --- a/alpinejs/packages/focus/dist/cdn.js +++ b/alpinejs/packages/focus/dist/cdn.js @@ -1,13 +1,15 @@ (() => { // node_modules/tabbable/dist/index.esm.js - /*! - * tabbable 5.2.1 - * @license MIT, https://github.com/focus-trap/tabbable/blob/master/LICENSE - */ - var candidateSelectors = ["input", "select", "textarea", "a[href]", "button", "[tabindex]", "audio[controls]", "video[controls]", '[contenteditable]:not([contenteditable="false"])', "details>summary:first-of-type", "details"]; + var candidateSelectors = ["input", "select", "textarea", "a[href]", "button", "[tabindex]:not(slot)", "audio[controls]", "video[controls]", '[contenteditable]:not([contenteditable="false"])', "details>summary:first-of-type", "details"]; var candidateSelector = /* @__PURE__ */ candidateSelectors.join(","); - var matches = typeof Element === "undefined" ? function() { + var NoElement = typeof Element === "undefined"; + var matches = NoElement ? function() { } : Element.prototype.matches || Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector; + var getRootNode = !NoElement && Element.prototype.getRootNode ? function(element) { + return element.getRootNode(); + } : function(element) { + return element.ownerDocument; + }; var getCandidates = function getCandidates2(el, includeContainer, filter) { var candidates = Array.prototype.slice.apply(el.querySelectorAll(candidateSelector)); if (includeContainer && matches.call(el, candidateSelector)) { @@ -16,19 +18,53 @@ candidates = candidates.filter(filter); return candidates; }; - var isContentEditable = function isContentEditable2(node) { - return node.contentEditable === "true"; - }; - var getTabindex = function getTabindex2(node) { - var tabindexAttr = parseInt(node.getAttribute("tabindex"), 10); - if (!isNaN(tabindexAttr)) { - return tabindexAttr; - } - if (isContentEditable(node)) { - return 0; + var getCandidatesIteratively = function getCandidatesIteratively2(elements, includeContainer, options) { + var candidates = []; + var elementsToCheck = Array.from(elements); + while (elementsToCheck.length) { + var element = elementsToCheck.shift(); + if (element.tagName === "SLOT") { + var assigned = element.assignedElements(); + var content = assigned.length ? assigned : element.children; + var nestedCandidates = getCandidatesIteratively2(content, true, options); + if (options.flatten) { + candidates.push.apply(candidates, nestedCandidates); + } else { + candidates.push({ + scope: element, + candidates: nestedCandidates + }); + } + } else { + var validCandidate = matches.call(element, candidateSelector); + if (validCandidate && options.filter(element) && (includeContainer || !elements.includes(element))) { + candidates.push(element); + } + var shadowRoot = element.shadowRoot || // check for an undisclosed shadow + typeof options.getShadowRoot === "function" && options.getShadowRoot(element); + var validShadowRoot = !options.shadowRootFilter || options.shadowRootFilter(element); + if (shadowRoot && validShadowRoot) { + var _nestedCandidates = getCandidatesIteratively2(shadowRoot === true ? element.children : shadowRoot.children, true, options); + if (options.flatten) { + candidates.push.apply(candidates, _nestedCandidates); + } else { + candidates.push({ + scope: element, + candidates: _nestedCandidates + }); + } + } else { + elementsToCheck.unshift.apply(elementsToCheck, element.children); + } + } } - if ((node.nodeName === "AUDIO" || node.nodeName === "VIDEO" || node.nodeName === "DETAILS") && node.getAttribute("tabindex") === null) { - return 0; + return candidates; + }; + var getTabindex = function getTabindex2(node, isScope) { + if (node.tabIndex < 0) { + if ((isScope || /^(AUDIO|VIDEO|DETAILS)$/.test(node.tagName) || node.isContentEditable) && isNaN(parseInt(node.getAttribute("tabindex"), 10))) { + return 0; + } } return node.tabIndex; }; @@ -58,7 +94,7 @@ if (!node.name) { return true; } - var radioScope = node.form || node.ownerDocument; + var radioScope = node.form || getRootNode(node); var queryRadios = function queryRadios2(name) { return radioScope.querySelectorAll('input[type="radio"][name="' + name + '"]'); }; @@ -82,7 +118,12 @@ var isNonTabbableRadio = function isNonTabbableRadio2(node) { return isRadio(node) && !isTabbableRadio(node); }; - var isHidden = function isHidden2(node, displayCheck) { + var isZeroArea = function isZeroArea2(node) { + var _node$getBoundingClie = node.getBoundingClientRect(), width = _node$getBoundingClie.width, height = _node$getBoundingClie.height; + return width === 0 && height === 0; + }; + var isHidden = function isHidden2(node, _ref) { + var displayCheck = _ref.displayCheck, getShadowRoot = _ref.getShadowRoot; if (getComputedStyle(node).visibility === "hidden") { return true; } @@ -91,31 +132,43 @@ if (matches.call(nodeUnderDetails, "details:not([open]) *")) { return true; } + var nodeRootHost = getRootNode(node).host; + var nodeIsAttached = (nodeRootHost === null || nodeRootHost === void 0 ? void 0 : nodeRootHost.ownerDocument.contains(nodeRootHost)) || node.ownerDocument.contains(node); if (!displayCheck || displayCheck === "full") { - while (node) { - if (getComputedStyle(node).display === "none") { - return true; + if (typeof getShadowRoot === "function") { + var originalNode = node; + while (node) { + var parentElement = node.parentElement; + var rootNode = getRootNode(node); + if (parentElement && !parentElement.shadowRoot && getShadowRoot(parentElement) === true) { + return isZeroArea(node); + } else if (node.assignedSlot) { + node = node.assignedSlot; + } else if (!parentElement && rootNode !== node.ownerDocument) { + node = rootNode.host; + } else { + node = parentElement; + } } - node = node.parentElement; + node = originalNode; + } + if (nodeIsAttached) { + return !node.getClientRects().length; } } else if (displayCheck === "non-zero-area") { - var _node$getBoundingClie = node.getBoundingClientRect(), width = _node$getBoundingClie.width, height = _node$getBoundingClie.height; - return width === 0 && height === 0; + return isZeroArea(node); } return false; }; var isDisabledFromFieldset = function isDisabledFromFieldset2(node) { - if (isInput(node) || node.tagName === "SELECT" || node.tagName === "TEXTAREA" || node.tagName === "BUTTON") { + if (/^(INPUT|BUTTON|SELECT|TEXTAREA)$/.test(node.tagName)) { var parentNode = node.parentElement; while (parentNode) { if (parentNode.tagName === "FIELDSET" && parentNode.disabled) { for (var i = 0; i < parentNode.children.length; i++) { var child = parentNode.children.item(i); if (child.tagName === "LEGEND") { - if (child.contains(node)) { - return false; - } - return true; + return matches.call(parentNode, "fieldset[disabled] *") ? true : !child.contains(node); } } return true; @@ -126,44 +179,89 @@ return false; }; var isNodeMatchingSelectorFocusable = function isNodeMatchingSelectorFocusable2(options, node) { - if (node.disabled || isHiddenInput(node) || isHidden(node, options.displayCheck) || isDetailsWithSummary(node) || isDisabledFromFieldset(node)) { + if (node.disabled || isHiddenInput(node) || isHidden(node, options) || // For a details element with a summary, the summary element gets the focus + isDetailsWithSummary(node) || isDisabledFromFieldset(node)) { return false; } return true; }; var isNodeMatchingSelectorTabbable = function isNodeMatchingSelectorTabbable2(options, node) { - if (!isNodeMatchingSelectorFocusable(options, node) || isNonTabbableRadio(node) || getTabindex(node) < 0) { + if (isNonTabbableRadio(node) || getTabindex(node) < 0 || !isNodeMatchingSelectorFocusable(options, node)) { return false; } return true; }; - var tabbable = function tabbable2(el, options) { - options = options || {}; + var isValidShadowRootTabbable = function isValidShadowRootTabbable2(shadowHostNode) { + var tabIndex = parseInt(shadowHostNode.getAttribute("tabindex"), 10); + if (isNaN(tabIndex) || tabIndex >= 0) { + return true; + } + return false; + }; + var sortByOrder = function sortByOrder2(candidates) { var regularTabbables = []; var orderedTabbables = []; - var candidates = getCandidates(el, options.includeContainer, isNodeMatchingSelectorTabbable.bind(null, options)); - candidates.forEach(function(candidate, i) { - var candidateTabindex = getTabindex(candidate); + candidates.forEach(function(item, i) { + var isScope = !!item.scope; + var element = isScope ? item.scope : item; + var candidateTabindex = getTabindex(element, isScope); + var elements = isScope ? sortByOrder2(item.candidates) : element; if (candidateTabindex === 0) { - regularTabbables.push(candidate); + isScope ? regularTabbables.push.apply(regularTabbables, elements) : regularTabbables.push(element); } else { orderedTabbables.push({ documentOrder: i, tabIndex: candidateTabindex, - node: candidate + item, + isScope, + content: elements }); } }); - var tabbableNodes = orderedTabbables.sort(sortOrderedTabbables).map(function(a) { - return a.node; - }).concat(regularTabbables); - return tabbableNodes; + return orderedTabbables.sort(sortOrderedTabbables).reduce(function(acc, sortable) { + sortable.isScope ? acc.push.apply(acc, sortable.content) : acc.push(sortable.content); + return acc; + }, []).concat(regularTabbables); + }; + var tabbable = function tabbable2(el, options) { + options = options || {}; + var candidates; + if (options.getShadowRoot) { + candidates = getCandidatesIteratively([el], options.includeContainer, { + filter: isNodeMatchingSelectorTabbable.bind(null, options), + flatten: false, + getShadowRoot: options.getShadowRoot, + shadowRootFilter: isValidShadowRootTabbable + }); + } else { + candidates = getCandidates(el, options.includeContainer, isNodeMatchingSelectorTabbable.bind(null, options)); + } + return sortByOrder(candidates); }; var focusable = function focusable2(el, options) { options = options || {}; - var candidates = getCandidates(el, options.includeContainer, isNodeMatchingSelectorFocusable.bind(null, options)); + var candidates; + if (options.getShadowRoot) { + candidates = getCandidatesIteratively([el], options.includeContainer, { + filter: isNodeMatchingSelectorFocusable.bind(null, options), + flatten: true, + getShadowRoot: options.getShadowRoot + }); + } else { + candidates = getCandidates(el, options.includeContainer, isNodeMatchingSelectorFocusable.bind(null, options)); + } return candidates; }; + var isTabbable = function isTabbable2(node, options) { + options = options || {}; + if (!node) { + throw new Error("No node provided"); + } + if (matches.call(node, candidateSelector) === false) { + return false; + } + return isNodeMatchingSelectorTabbable(options, node); + }; var focusableCandidateSelector = /* @__PURE__ */ candidateSelectors.concat("iframe").join(","); var isFocusable = function isFocusable2(node, options) { options = options || {}; @@ -177,37 +275,24 @@ }; // node_modules/focus-trap/dist/focus-trap.esm.js - /*! - * focus-trap 6.6.1 - * @license MIT, https://github.com/focus-trap/focus-trap/blob/master/LICENSE - */ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); - if (enumerableOnly) { - symbols = symbols.filter(function(sym) { - return Object.getOwnPropertyDescriptor(object, sym).enumerable; - }); - } - keys.push.apply(keys, symbols); + enumerableOnly && (symbols = symbols.filter(function(sym) { + return Object.getOwnPropertyDescriptor(object, sym).enumerable; + })), keys.push.apply(keys, symbols); } return keys; } function _objectSpread2(target) { for (var i = 1; i < arguments.length; i++) { - var source = arguments[i] != null ? arguments[i] : {}; - if (i % 2) { - ownKeys(Object(source), true).forEach(function(key) { - _defineProperty(target, key, source[key]); - }); - } else if (Object.getOwnPropertyDescriptors) { - Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); - } else { - ownKeys(Object(source)).forEach(function(key) { - Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); - }); - } + var source = null != arguments[i] ? arguments[i] : {}; + i % 2 ? ownKeys(Object(source), true).forEach(function(key) { + _defineProperty(target, key, source[key]); + }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function(key) { + Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); + }); } return target; } @@ -282,64 +367,103 @@ } return typeof value === "function" ? value.apply(void 0, params) : value; }; + var getActualTarget = function getActualTarget2(event) { + return event.target.shadowRoot && typeof event.composedPath === "function" ? event.composedPath()[0] : event.target; + }; var createFocusTrap = function createFocusTrap2(elements, userOptions) { - var doc = document; + var doc = (userOptions === null || userOptions === void 0 ? void 0 : userOptions.document) || document; var config = _objectSpread2({ returnFocusOnDeactivate: true, escapeDeactivates: true, delayInitialFocus: true }, userOptions); var state = { + // containers given to createFocusTrap() + // @type {Array} containers: [], + // list of objects identifying tabbable nodes in `containers` in the trap + // NOTE: it's possible that a group has no tabbable nodes if nodes get removed while the trap + // is active, but the trap should never get to a state where there isn't at least one group + // with at least one tabbable node in it (that would lead to an error condition that would + // result in an error being thrown) + // @type {Array<{ + // container: HTMLElement, + // tabbableNodes: Array, // empty if none + // focusableNodes: Array, // empty if none + // firstTabbableNode: HTMLElement|null, + // lastTabbableNode: HTMLElement|null, + // nextTabbableNode: (node: HTMLElement, forward: boolean) => HTMLElement|undefined + // }>} + containerGroups: [], + // same order/length as `containers` list + // references to objects in `containerGroups`, but only those that actually have + // tabbable nodes in them + // NOTE: same order as `containers` and `containerGroups`, but __not necessarily__ + // the same length tabbableGroups: [], nodeFocusedBeforeActivation: null, mostRecentlyFocusedNode: null, active: false, paused: false, + // timer ID for when delayInitialFocus is true and initial focus in this trap + // has been delayed during activation delayInitialFocusTimer: void 0 }; var trap; var getOption = function getOption2(configOverrideOptions, optionName, configOptionName) { return configOverrideOptions && configOverrideOptions[optionName] !== void 0 ? configOverrideOptions[optionName] : config[configOptionName || optionName]; }; - var containersContain = function containersContain2(element) { - return state.containers.some(function(container) { - return container.contains(element); + var findContainerIndex = function findContainerIndex2(element) { + return state.containerGroups.findIndex(function(_ref) { + var container = _ref.container, tabbableNodes = _ref.tabbableNodes; + return container.contains(element) || // fall back to explicit tabbable search which will take into consideration any + // web components if the `tabbableOptions.getShadowRoot` option was used for + // the trap, enabling shadow DOM support in tabbable (`Node.contains()` doesn't + // look inside web components even if open) + tabbableNodes.find(function(node) { + return node === element; + }); }); }; var getNodeForOption = function getNodeForOption2(optionName) { var optionValue = config[optionName]; + if (typeof optionValue === "function") { + for (var _len2 = arguments.length, params = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { + params[_key2 - 1] = arguments[_key2]; + } + optionValue = optionValue.apply(void 0, params); + } + if (optionValue === true) { + optionValue = void 0; + } if (!optionValue) { - return null; + if (optionValue === void 0 || optionValue === false) { + return optionValue; + } + throw new Error("`".concat(optionName, "` was specified but was not a node, or did not return a node")); } var node = optionValue; if (typeof optionValue === "string") { node = doc.querySelector(optionValue); if (!node) { - throw new Error("`".concat(optionName, "` refers to no known node")); - } - } - if (typeof optionValue === "function") { - node = optionValue(); - if (!node) { - throw new Error("`".concat(optionName, "` did not return a node")); + throw new Error("`".concat(optionName, "` as selector refers to no known node")); } } return node; }; var getInitialFocusNode = function getInitialFocusNode2() { - var node; - if (getOption({}, "initialFocus") === false) { + var node = getNodeForOption("initialFocus"); + if (node === false) { return false; } - if (getNodeForOption("initialFocus") !== null) { - node = getNodeForOption("initialFocus"); - } else if (containersContain(doc.activeElement)) { - node = doc.activeElement; - } else { - var firstTabbableGroup = state.tabbableGroups[0]; - var firstTabbableNode = firstTabbableGroup && firstTabbableGroup.firstTabbableNode; - node = firstTabbableNode || getNodeForOption("fallbackFocus"); + if (node === void 0) { + if (findContainerIndex(doc.activeElement) >= 0) { + node = doc.activeElement; + } else { + var firstTabbableGroup = state.tabbableGroups[0]; + var firstTabbableNode = firstTabbableGroup && firstTabbableGroup.firstTabbableNode; + node = firstTabbableNode || getNodeForOption("fallbackFocus"); + } } if (!node) { throw new Error("Your focus-trap needs to have at least one focusable element"); @@ -347,18 +471,44 @@ return node; }; var updateTabbableNodes = function updateTabbableNodes2() { - state.tabbableGroups = state.containers.map(function(container) { - var tabbableNodes = tabbable(container); - if (tabbableNodes.length > 0) { - return { - container, - firstTabbableNode: tabbableNodes[0], - lastTabbableNode: tabbableNodes[tabbableNodes.length - 1] - }; - } - return void 0; - }).filter(function(group) { - return !!group; + state.containerGroups = state.containers.map(function(container) { + var tabbableNodes = tabbable(container, config.tabbableOptions); + var focusableNodes = focusable(container, config.tabbableOptions); + return { + container, + tabbableNodes, + focusableNodes, + firstTabbableNode: tabbableNodes.length > 0 ? tabbableNodes[0] : null, + lastTabbableNode: tabbableNodes.length > 0 ? tabbableNodes[tabbableNodes.length - 1] : null, + /** + * Finds the __tabbable__ node that follows the given node in the specified direction, + * in this container, if any. + * @param {HTMLElement} node + * @param {boolean} [forward] True if going in forward tab order; false if going + * in reverse. + * @returns {HTMLElement|undefined} The next tabbable node, if any. + */ + nextTabbableNode: function nextTabbableNode(node) { + var forward = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : true; + var nodeIdx = focusableNodes.findIndex(function(n) { + return n === node; + }); + if (nodeIdx < 0) { + return void 0; + } + if (forward) { + return focusableNodes.slice(nodeIdx + 1).find(function(n) { + return isTabbable(n, config.tabbableOptions); + }); + } + return focusableNodes.slice(0, nodeIdx).reverse().find(function(n) { + return isTabbable(n, config.tabbableOptions); + }); + } + }; + }); + state.tabbableGroups = state.containerGroups.filter(function(group) { + return group.tabbableNodes.length > 0; }); if (state.tabbableGroups.length <= 0 && !getNodeForOption("fallbackFocus")) { throw new Error("Your focus-trap must have at least one container with at least one tabbable node in it at all times"); @@ -384,16 +534,28 @@ } }; var getReturnFocusNode = function getReturnFocusNode2(previousActiveElement) { - var node = getNodeForOption("setReturnFocus"); - return node ? node : previousActiveElement; + var node = getNodeForOption("setReturnFocus", previousActiveElement); + return node ? node : node === false ? false : previousActiveElement; }; var checkPointerDown = function checkPointerDown2(e) { - if (containersContain(e.target)) { + var target = getActualTarget(e); + if (findContainerIndex(target) >= 0) { return; } if (valueOrHandler(config.clickOutsideDeactivates, e)) { trap.deactivate({ - returnFocus: config.returnFocusOnDeactivate && !isFocusable(e.target) + // if, on deactivation, we should return focus to the node originally-focused + // when the trap was activated (or the configured `setReturnFocus` node), + // then assume it's also OK to return focus to the outside node that was + // just clicked, causing deactivation, as long as that node is focusable; + // if it isn't focusable, then return focus to the original node focused + // on activation (or the configured `setReturnFocus` node) + // NOTE: by setting `returnFocus: false`, deactivate() will do nothing, + // which will result in the outside click setting focus to the node + // that was clicked, whether it's focusable or not; by setting + // `returnFocus: true`, we'll attempt to re-focus the node originally-focused + // on activation (or the configured `setReturnFocus` node) + returnFocus: config.returnFocusOnDeactivate && !isFocusable(target, config.tabbableOptions) }); return; } @@ -403,10 +565,11 @@ e.preventDefault(); }; var checkFocusIn = function checkFocusIn2(e) { - var targetContained = containersContain(e.target); - if (targetContained || e.target instanceof Document) { + var target = getActualTarget(e); + var targetContained = findContainerIndex(target) >= 0; + if (targetContained || target instanceof Document) { if (targetContained) { - state.mostRecentlyFocusedNode = e.target; + state.mostRecentlyFocusedNode = target; } } else { e.stopImmediatePropagation(); @@ -414,13 +577,12 @@ } }; var checkTab = function checkTab2(e) { + var target = getActualTarget(e); updateTabbableNodes(); var destinationNode = null; if (state.tabbableGroups.length > 0) { - var containerIndex = findIndex(state.tabbableGroups, function(_ref) { - var container = _ref.container; - return container.contains(e.target); - }); + var containerIndex = findContainerIndex(target); + var containerGroup = containerIndex >= 0 ? state.containerGroups[containerIndex] : void 0; if (containerIndex < 0) { if (e.shiftKey) { destinationNode = state.tabbableGroups[state.tabbableGroups.length - 1].lastTabbableNode; @@ -430,9 +592,9 @@ } else if (e.shiftKey) { var startOfGroupIndex = findIndex(state.tabbableGroups, function(_ref2) { var firstTabbableNode = _ref2.firstTabbableNode; - return e.target === firstTabbableNode; + return target === firstTabbableNode; }); - if (startOfGroupIndex < 0 && state.tabbableGroups[containerIndex].container === e.target) { + if (startOfGroupIndex < 0 && (containerGroup.container === target || isFocusable(target, config.tabbableOptions) && !isTabbable(target, config.tabbableOptions) && !containerGroup.nextTabbableNode(target, false))) { startOfGroupIndex = containerIndex; } if (startOfGroupIndex >= 0) { @@ -443,9 +605,9 @@ } else { var lastOfGroupIndex = findIndex(state.tabbableGroups, function(_ref3) { var lastTabbableNode = _ref3.lastTabbableNode; - return e.target === lastTabbableNode; + return target === lastTabbableNode; }); - if (lastOfGroupIndex < 0 && state.tabbableGroups[containerIndex].container === e.target) { + if (lastOfGroupIndex < 0 && (containerGroup.container === target || isFocusable(target, config.tabbableOptions) && !isTabbable(target, config.tabbableOptions) && !containerGroup.nextTabbableNode(target))) { lastOfGroupIndex = containerIndex; } if (lastOfGroupIndex >= 0) { @@ -463,7 +625,7 @@ } }; var checkKey = function checkKey2(e) { - if (isEscapeEvent(e) && valueOrHandler(config.escapeDeactivates) !== false) { + if (isEscapeEvent(e) && valueOrHandler(config.escapeDeactivates, e) !== false) { e.preventDefault(); trap.deactivate(); return; @@ -474,10 +636,11 @@ } }; var checkClick = function checkClick2(e) { - if (valueOrHandler(config.clickOutsideDeactivates, e)) { + var target = getActualTarget(e); + if (findContainerIndex(target) >= 0) { return; } - if (containersContain(e.target)) { + if (valueOrHandler(config.clickOutsideDeactivates, e)) { return; } if (valueOrHandler(config.allowOutsideClick, e)) { @@ -525,6 +688,12 @@ return trap; }; trap = { + get active() { + return state.active; + }, + get paused() { + return state.paused; + }, activate: function activate(activateOptions) { if (state.active) { return this; @@ -561,19 +730,24 @@ if (!state.active) { return this; } + var options = _objectSpread2({ + onDeactivate: config.onDeactivate, + onPostDeactivate: config.onPostDeactivate, + checkCanReturnFocus: config.checkCanReturnFocus + }, deactivateOptions); clearTimeout(state.delayInitialFocusTimer); state.delayInitialFocusTimer = void 0; removeListeners(); state.active = false; state.paused = false; activeFocusTraps.deactivateTrap(trap); - var onDeactivate = getOption(deactivateOptions, "onDeactivate"); - var onPostDeactivate = getOption(deactivateOptions, "onPostDeactivate"); - var checkCanReturnFocus = getOption(deactivateOptions, "checkCanReturnFocus"); + var onDeactivate = getOption(options, "onDeactivate"); + var onPostDeactivate = getOption(options, "onPostDeactivate"); + var checkCanReturnFocus = getOption(options, "checkCanReturnFocus"); + var returnFocus = getOption(options, "returnFocus", "returnFocusOnDeactivate"); if (onDeactivate) { onDeactivate(); } - var returnFocus = getOption(deactivateOptions, "returnFocus", "returnFocusOnDeactivate"); var finishDeactivation = function finishDeactivation2() { delay(function() { if (returnFocus) { @@ -670,7 +844,7 @@ focusables() { if (Array.isArray(within)) return within; - return focusable(within, {displayCheck: "none"}); + return focusable(within, { displayCheck: "none" }); }, all() { return this.focusables(); @@ -730,57 +904,66 @@ setTimeout(() => { if (!el2.hasAttribute("tabindex")) el2.setAttribute("tabindex", "0"); - el2.focus({preventScroll: this._noscroll}); + el2.focus({ preventScroll: this._noscroll }); }); } }; }); - Alpine.directive("trap", Alpine.skipDuringClone((el, {expression, modifiers}, {effect, evaluateLater, cleanup}) => { - let evaluator = evaluateLater(expression); - let oldValue = false; - let trap = createFocusTrap(el, { - escapeDeactivates: false, - allowOutsideClick: true, - fallbackFocus: () => el, - initialFocus: el.querySelector("[autofocus]") - }); - let undoInert = () => { - }; - let undoDisableScrolling = () => { - }; - const releaseFocus = () => { - undoInert(); - undoInert = () => { + Alpine.directive("trap", Alpine.skipDuringClone( + (el, { expression, modifiers }, { effect, evaluateLater, cleanup }) => { + let evaluator = evaluateLater(expression); + let oldValue = false; + let options = { + escapeDeactivates: false, + allowOutsideClick: true, + fallbackFocus: () => el }; - undoDisableScrolling(); - undoDisableScrolling = () => { + let autofocusEl = el.querySelector("[autofocus]"); + if (autofocusEl) + options.initialFocus = autofocusEl; + let trap = createFocusTrap(el, options); + let undoInert = () => { }; - trap.deactivate({ - returnFocus: !modifiers.includes("noreturn") - }); - }; - effect(() => evaluator((value) => { - if (oldValue === value) - return; - if (value && !oldValue) { - setTimeout(() => { - if (modifiers.includes("inert")) - undoInert = setInert(el); - if (modifiers.includes("noscroll")) - undoDisableScrolling = disableScrolling(); - trap.activate(); + let undoDisableScrolling = () => { + }; + const releaseFocus = () => { + undoInert(); + undoInert = () => { + }; + undoDisableScrolling(); + undoDisableScrolling = () => { + }; + trap.deactivate({ + returnFocus: !modifiers.includes("noreturn") }); - } - if (!value && oldValue) { - releaseFocus(); - } - oldValue = !!value; - })); - cleanup(releaseFocus); - }, (el, {expression, modifiers}, {evaluate}) => { - if (modifiers.includes("inert") && evaluate(expression)) - setInert(el); - })); + }; + effect(() => evaluator((value) => { + if (oldValue === value) + return; + if (value && !oldValue) { + setTimeout(() => { + if (modifiers.includes("inert")) + undoInert = setInert(el); + if (modifiers.includes("noscroll")) + undoDisableScrolling = disableScrolling(); + trap.activate(); + }); + } + if (!value && oldValue) { + releaseFocus(); + } + oldValue = !!value; + })); + cleanup(releaseFocus); + }, + // When cloning, we only want to add aria-hidden attributes to the + // DOM and not try to actually trap, as trapping can mess with the + // live DOM and isn't just isolated to the cloned DOM. + (el, { expression, modifiers }, { evaluate }) => { + if (modifiers.includes("inert") && evaluate(expression)) + setInert(el); + } + )); } function setInert(el) { let undos = []; @@ -798,9 +981,11 @@ if (el.isSameNode(document.body) || !el.parentNode) return; Array.from(el.parentNode.children).forEach((sibling) => { - if (!sibling.isSameNode(el)) + if (sibling.isSameNode(el)) { + crawlSiblingsUp(el.parentNode, callback); + } else { callback(sibling); - crawlSiblingsUp(el.parentNode, callback); + } }); } function disableScrolling() { @@ -820,3 +1005,17 @@ window.Alpine.plugin(src_default); }); })(); +/*! Bundled license information: + +tabbable/dist/index.esm.js: + (*! + * tabbable 5.3.3 + * @license MIT, https://github.com/focus-trap/tabbable/blob/master/LICENSE + *) + +focus-trap/dist/focus-trap.esm.js: + (*! + * focus-trap 6.9.4 + * @license MIT, https://github.com/focus-trap/focus-trap/blob/master/LICENSE + *) +*/ diff --git a/alpinejs/packages/focus/dist/cdn.min.js b/alpinejs/packages/focus/dist/cdn.min.js index ba2af16..e66df21 100644 --- a/alpinejs/packages/focus/dist/cdn.min.js +++ b/alpinejs/packages/focus/dist/cdn.min.js @@ -1,9 +1,15 @@ -(()=>{var j=["input","select","textarea","a[href]","button","[tabindex]","audio[controls]","video[controls]",'[contenteditable]:not([contenteditable="false"])',"details>summary:first-of-type","details"],_=j.join(","),A=typeof Element=="undefined"?function(){}:Element.prototype.matches||Element.prototype.msMatchesSelector||Element.prototype.webkitMatchesSelector,G=function(e,t,a){var u=Array.prototype.slice.apply(e.querySelectorAll(_));return t&&A.call(e,_)&&u.unshift(e),u=u.filter(a),u},Z=function(e){return e.contentEditable==="true"},M=function(e){var t=parseInt(e.getAttribute("tabindex"),10);return isNaN(t)?Z(e)||(e.nodeName==="AUDIO"||e.nodeName==="VIDEO"||e.nodeName==="DETAILS")&&e.getAttribute("tabindex")===null?0:e.tabIndex:t},$=function(e,t){return e.tabIndex===t.tabIndex?e.documentOrder-t.documentOrder:e.tabIndex-t.tabIndex},C=function(e){return e.tagName==="INPUT"},ee=function(e){return C(e)&&e.type==="hidden"},te=function(e){var t=e.tagName==="DETAILS"&&Array.prototype.slice.apply(e.children).some(function(a){return a.tagName==="SUMMARY"});return t},re=function(e,t){for(var a=0;asummary:first-of-type"),u=a?e.parentElement:e;if(A.call(u,"details:not([open]) *"))return!0;if(!t||t==="full")for(;e;){if(getComputedStyle(e).display==="none")return!0;e=e.parentElement}else if(t==="non-zero-area"){var r=e.getBoundingClientRect(),s=r.width,l=r.height;return s===0&&l===0}return!1},oe=function(e){if(C(e)||e.tagName==="SELECT"||e.tagName==="TEXTAREA"||e.tagName==="BUTTON")for(var t=e.parentElement;t;){if(t.tagName==="FIELDSET"&&t.disabled){for(var a=0;a0){var a=i[i.length-1];a!==t&&a.pause()}var u=i.indexOf(t);u===-1||i.splice(u,1),i.push(t)},deactivateTrap:function(t){var a=i.indexOf(t);a!==-1&&i.splice(a,1),i.length>0&&i[i.length-1].unpause()}}}(),de=function(e){return e.tagName&&e.tagName.toLowerCase()==="input"&&typeof e.select=="function"},be=function(e){return e.key==="Escape"||e.key==="Esc"||e.keyCode===27},ve=function(e){return e.key==="Tab"||e.keyCode===9},U=function(e){return setTimeout(e,0)},L=function(e,t){var a=-1;return e.every(function(u,r){return t(u)?(a=r,!1):!0}),a},D=function(e){for(var t=arguments.length,a=new Array(t>1?t-1:0),u=1;u0)return{container:n,firstTabbableNode:o[0],lastTabbableNode:o[o.length-1]}}).filter(function(n){return!!n}),r.tabbableGroups.length<=0&&!b("fallbackFocus"))throw new Error("Your focus-trap must have at least one container with at least one tabbable node in it at all times")},p=function f(n){if(n!==!1&&n!==a.activeElement){if(!n||!n.focus){f(v());return}n.focus({preventScroll:!!u.preventScroll}),r.mostRecentlyFocusedNode=n,de(n)&&n.select()}},E=function(n){var o=b("setReturnFocus");return o||n},y=function(n){if(!h(n.target)){if(D(u.clickOutsideDeactivates,n)){s.deactivate({returnFocus:u.returnFocusOnDeactivate&&!k(n.target)});return}D(u.allowOutsideClick,n)||n.preventDefault()}},w=function(n){var o=h(n.target);o||n.target instanceof Document?o&&(r.mostRecentlyFocusedNode=n.target):(n.stopImmediatePropagation(),p(r.mostRecentlyFocusedNode||v()))},Q=function(n){m();var o=null;if(r.tabbableGroups.length>0){var c=L(r.tabbableGroups,function(S){var N=S.container;return N.contains(n.target)});if(c<0)n.shiftKey?o=r.tabbableGroups[r.tabbableGroups.length-1].lastTabbableNode:o=r.tabbableGroups[0].firstTabbableNode;else if(n.shiftKey){var d=L(r.tabbableGroups,function(S){var N=S.firstTabbableNode;return n.target===N});if(d<0&&r.tabbableGroups[c].container===n.target&&(d=c),d>=0){var g=d===0?r.tabbableGroups.length-1:d-1,F=r.tabbableGroups[g];o=F.lastTabbableNode}}else{var T=L(r.tabbableGroups,function(S){var N=S.lastTabbableNode;return n.target===N});if(T<0&&r.tabbableGroups[c].container===n.target&&(T=c),T>=0){var X=T===r.tabbableGroups.length-1?0:T+1,J=r.tabbableGroups[X];o=J.firstTabbableNode}}}else o=b("fallbackFocus");o&&(n.preventDefault(),p(o))},R=function(n){if(be(n)&&D(u.escapeDeactivates)!==!1){n.preventDefault(),s.deactivate();return}if(ve(n)){Q(n);return}},x=function(n){D(u.clickOutsideDeactivates,n)||h(n.target)||D(u.allowOutsideClick,n)||(n.preventDefault(),n.stopImmediatePropagation())},I=function(){if(!!r.active)return H.activateTrap(s),r.delayInitialFocusTimer=u.delayInitialFocus?U(function(){p(v())}):p(v()),a.addEventListener("focusin",w,!0),a.addEventListener("mousedown",y,{capture:!0,passive:!1}),a.addEventListener("touchstart",y,{capture:!0,passive:!1}),a.addEventListener("click",x,{capture:!0,passive:!1}),a.addEventListener("keydown",R,{capture:!0,passive:!1}),s},P=function(){if(!!r.active)return a.removeEventListener("focusin",w,!0),a.removeEventListener("mousedown",y,!0),a.removeEventListener("touchstart",y,!0),a.removeEventListener("click",x,!0),a.removeEventListener("keydown",R,!0),s};return s={activate:function(n){if(r.active)return this;var o=l(n,"onActivate"),c=l(n,"onPostActivate"),d=l(n,"checkCanFocusTrap");d||m(),r.active=!0,r.paused=!1,r.nodeFocusedBeforeActivation=a.activeElement,o&&o();var g=function(){d&&m(),I(),c&&c()};return d?(d(r.containers.concat()).then(g,g),this):(g(),this)},deactivate:function(n){if(!r.active)return this;clearTimeout(r.delayInitialFocusTimer),r.delayInitialFocusTimer=void 0,P(),r.active=!1,r.paused=!1,H.deactivateTrap(s);var o=l(n,"onDeactivate"),c=l(n,"onPostDeactivate"),d=l(n,"checkCanReturnFocus");o&&o();var g=l(n,"returnFocus","returnFocusOnDeactivate"),F=function(){U(function(){g&&p(E(r.nodeFocusedBeforeActivation)),c&&c()})};return g&&d?(d(E(r.nodeFocusedBeforeActivation)).then(F,F),this):(F(),this)},pause:function(){return r.paused||!r.active?this:(r.paused=!0,P(),this)},unpause:function(){return!r.paused||!r.active?this:(r.paused=!1,m(),I(),this)},updateContainerElements:function(n){var o=[].concat(n).filter(Boolean);return r.containers=o.map(function(c){return typeof c=="string"?a.querySelector(c):c}),r.active&&m(),this}},s.updateContainerElements(e),s};function Y(i){let e,t;window.addEventListener("focusin",()=>{e=t,t=document.activeElement}),i.magic("focus",a=>{let u=a;return{__noscroll:!1,__wrapAround:!1,within(r){return u=r,this},withoutScrolling(){return this.__noscroll=!0,this},noscroll(){return this.__noscroll=!0,this},withWrapAround(){return this.__wrapAround=!0,this},wrap(){return this.withWrapAround()},focusable(r){return k(r)},previouslyFocused(){return e},lastFocused(){return e},focused(){return t},focusables(){return Array.isArray(u)?u:W(u,{displayCheck:"none"})},all(){return this.focusables()},isFirst(r){let s=this.all();return s[0]&&s[0].isSameNode(r)},isLast(r){let s=this.all();return s.length&&s.slice(-1)[0].isSameNode(r)},getFirst(){return this.all()[0]},getLast(){return this.all().slice(-1)[0]},getNext(){let r=this.all(),s=document.activeElement;if(r.indexOf(s)!==-1)return this.__wrapAround&&r.indexOf(s)===r.length-1?r[0]:r[r.indexOf(s)+1]},getPrevious(){let r=this.all(),s=document.activeElement;if(r.indexOf(s)!==-1)return this.__wrapAround&&r.indexOf(s)===0?r.slice(-1)[0]:r[r.indexOf(s)-1]},first(){this.focus(this.getFirst())},last(){this.focus(this.getLast())},next(){this.focus(this.getNext())},previous(){this.focus(this.getPrevious())},prev(){return this.previous()},focus(r){!r||setTimeout(()=>{r.hasAttribute("tabindex")||r.setAttribute("tabindex","0"),r.focus({preventScroll:this._noscroll})})}}}),i.directive("trap",i.skipDuringClone((a,{expression:u,modifiers:r},{effect:s,evaluateLater:l,cleanup:h})=>{let b=l(u),v=!1,m=K(a,{escapeDeactivates:!1,allowOutsideClick:!0,fallbackFocus:()=>a,initialFocus:a.querySelector("[autofocus]")}),p=()=>{},E=()=>{},y=()=>{p(),p=()=>{},E(),E=()=>{},m.deactivate({returnFocus:!r.includes("noreturn")})};s(()=>b(w=>{v!==w&&(w&&!v&&setTimeout(()=>{r.includes("inert")&&(p=V(a)),r.includes("noscroll")&&(E=pe()),m.activate()}),!w&&v&&y(),v=!!w)})),h(y)},(a,{expression:u,modifiers:r},{evaluate:s})=>{r.includes("inert")&&s(u)&&V(a)}))}function V(i){let e=[];return z(i,t=>{let a=t.hasAttribute("aria-hidden");t.setAttribute("aria-hidden","true"),e.push(()=>a||t.removeAttribute("aria-hidden"))}),()=>{for(;e.length;)e.pop()()}}function z(i,e){i.isSameNode(document.body)||!i.parentNode||Array.from(i.parentNode.children).forEach(t=>{t.isSameNode(i)||e(t),z(i.parentNode,e)})}function pe(){let i=document.documentElement.style.overflow,e=document.documentElement.style.paddingRight,t=window.innerWidth-document.documentElement.clientWidth;return document.documentElement.style.overflow="hidden",document.documentElement.style.paddingRight=`${t}px`,()=>{document.documentElement.style.overflow=i,document.documentElement.style.paddingRight=e}}document.addEventListener("alpine:init",()=>{window.Alpine.plugin(Y)});})(); -/*! -* focus-trap 6.6.1 -* @license MIT, https://github.com/focus-trap/focus-trap/blob/master/LICENSE -*/ -/*! -* tabbable 5.2.1 -* @license MIT, https://github.com/focus-trap/tabbable/blob/master/LICENSE +(()=>{var K=["input","select","textarea","a[href]","button","[tabindex]:not(slot)","audio[controls]","video[controls]",'[contenteditable]:not([contenteditable="false"])',"details>summary:first-of-type","details"],I=K.join(","),V=typeof Element>"u",N=V?function(){}:Element.prototype.matches||Element.prototype.msMatchesSelector||Element.prototype.webkitMatchesSelector,G=!V&&Element.prototype.getRootNode?function(i){return i.getRootNode()}:function(i){return i.ownerDocument},_=function(e,t,a){var n=Array.prototype.slice.apply(e.querySelectorAll(I));return t&&N.call(e,I)&&n.unshift(e),n=n.filter(a),n},$=function i(e,t,a){for(var n=[],r=Array.from(e);r.length;){var s=r.shift();if(s.tagName==="SLOT"){var l=s.assignedElements(),m=l.length?l:s.children,h=i(m,!0,a);a.flatten?n.push.apply(n,h):n.push({scope:s,candidates:h})}else{var v=N.call(s,I);v&&a.filter(s)&&(t||!e.includes(s))&&n.push(s);var p=s.shadowRoot||typeof a.getShadowRoot=="function"&&a.getShadowRoot(s),y=!a.shadowRootFilter||a.shadowRootFilter(s);if(p&&y){var T=i(p===!0?s.children:p.children,!0,a);a.flatten?n.push.apply(n,T):n.push({scope:s,candidates:T})}else r.unshift.apply(r,s.children)}}return n},Y=function(e,t){return e.tabIndex<0&&(t||/^(AUDIO|VIDEO|DETAILS)$/.test(e.tagName)||e.isContentEditable)&&isNaN(parseInt(e.getAttribute("tabindex"),10))?0:e.tabIndex},se=function(e,t){return e.tabIndex===t.tabIndex?e.documentOrder-t.documentOrder:e.tabIndex-t.tabIndex},Z=function(e){return e.tagName==="INPUT"},ce=function(e){return Z(e)&&e.type==="hidden"},le=function(e){var t=e.tagName==="DETAILS"&&Array.prototype.slice.apply(e.children).some(function(a){return a.tagName==="SUMMARY"});return t},fe=function(e,t){for(var a=0;asummary:first-of-type"),s=r?e.parentElement:e;if(N.call(s,"details:not([open]) *"))return!0;var l=G(e).host,m=l?.ownerDocument.contains(l)||e.ownerDocument.contains(e);if(!a||a==="full"){if(typeof n=="function"){for(var h=e;e;){var v=e.parentElement,p=G(e);if(v&&!v.shadowRoot&&n(v)===!0)return W(e);e.assignedSlot?e=e.assignedSlot:!v&&p!==e.ownerDocument?e=p.host:e=v}e=h}if(m)return!e.getClientRects().length}else if(a==="non-zero-area")return W(e);return!1},pe=function(e){if(/^(INPUT|BUTTON|SELECT|TEXTAREA)$/.test(e.tagName))for(var t=e.parentElement;t;){if(t.tagName==="FIELDSET"&&t.disabled){for(var a=0;a=0)},me=function i(e){var t=[],a=[];return e.forEach(function(n,r){var s=!!n.scope,l=s?n.scope:n,m=Y(l,s),h=s?i(n.candidates):l;m===0?s?t.push.apply(t,h):t.push(l):a.push({documentOrder:r,tabIndex:m,item:n,isScope:s,content:h})}),a.sort(se).reduce(function(n,r){return r.isScope?n.push.apply(n,r.content):n.push(r.content),n},[]).concat(t)},z=function(e,t){t=t||{};var a;return t.getShadowRoot?a=$([e],t.includeContainer,{filter:M.bind(null,t),flatten:!1,getShadowRoot:t.getShadowRoot,shadowRootFilter:ge}):a=_(e,t.includeContainer,M.bind(null,t)),me(a)},L=function(e,t){t=t||{};var a;return t.getShadowRoot?a=$([e],t.includeContainer,{filter:x.bind(null,t),flatten:!0,getShadowRoot:t.getShadowRoot}):a=_(e,t.includeContainer,x.bind(null,t)),a},A=function(e,t){if(t=t||{},!e)throw new Error("No node provided");return N.call(e,I)===!1?!1:M(t,e)},ye=K.concat("iframe").join(","),D=function(e,t){if(t=t||{},!e)throw new Error("No node provided");return N.call(e,ye)===!1?!1:x(t,e)};function Q(i,e){var t=Object.keys(i);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(i);e&&(a=a.filter(function(n){return Object.getOwnPropertyDescriptor(i,n).enumerable})),t.push.apply(t,a)}return t}function X(i){for(var e=1;e0){var a=i[i.length-1];a!==t&&a.pause()}var n=i.indexOf(t);n===-1||i.splice(n,1),i.push(t)},deactivateTrap:function(t){var a=i.indexOf(t);a!==-1&&i.splice(a,1),i.length>0&&i[i.length-1].unpause()}}}(),Te=function(e){return e.tagName&&e.tagName.toLowerCase()==="input"&&typeof e.select=="function"},Fe=function(e){return e.key==="Escape"||e.key==="Esc"||e.keyCode===27},Se=function(e){return e.key==="Tab"||e.keyCode===9},ee=function(e){return setTimeout(e,0)},te=function(e,t){var a=-1;return e.every(function(n,r){return t(n)?(a=r,!1):!0}),a},O=function(e){for(var t=arguments.length,a=new Array(t>1?t-1:0),n=1;n1?c-1:0),f=1;f=0)o=a.activeElement;else{var u=r.tabbableGroups[0],c=u&&u.firstTabbableNode;o=c||h("fallbackFocus")}if(!o)throw new Error("Your focus-trap needs to have at least one focusable element");return o},p=function(){if(r.containerGroups=r.containers.map(function(o){var u=z(o,n.tabbableOptions),c=L(o,n.tabbableOptions);return{container:o,tabbableNodes:u,focusableNodes:c,firstTabbableNode:u.length>0?u[0]:null,lastTabbableNode:u.length>0?u[u.length-1]:null,nextTabbableNode:function(f){var g=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!0,w=c.findIndex(function(S){return S===f});if(!(w<0))return g?c.slice(w+1).find(function(S){return A(S,n.tabbableOptions)}):c.slice(0,w).reverse().find(function(S){return A(S,n.tabbableOptions)})}}}),r.tabbableGroups=r.containerGroups.filter(function(o){return o.tabbableNodes.length>0}),r.tabbableGroups.length<=0&&!h("fallbackFocus"))throw new Error("Your focus-trap must have at least one container with at least one tabbable node in it at all times")},y=function d(o){if(o!==!1&&o!==a.activeElement){if(!o||!o.focus){d(v());return}o.focus({preventScroll:!!n.preventScroll}),r.mostRecentlyFocusedNode=o,Te(o)&&o.select()}},T=function(o){var u=h("setReturnFocus",o);return u||(u===!1?!1:o)},F=function(o){var u=P(o);if(!(m(u)>=0)){if(O(n.clickOutsideDeactivates,o)){s.deactivate({returnFocus:n.returnFocusOnDeactivate&&!D(u,n.tabbableOptions)});return}O(n.allowOutsideClick,o)||o.preventDefault()}},R=function(o){var u=P(o),c=m(u)>=0;c||u instanceof Document?c&&(r.mostRecentlyFocusedNode=u):(o.stopImmediatePropagation(),y(r.mostRecentlyFocusedNode||v()))},k=function(o){var u=P(o);p();var c=null;if(r.tabbableGroups.length>0){var b=m(u),f=b>=0?r.containerGroups[b]:void 0;if(b<0)o.shiftKey?c=r.tabbableGroups[r.tabbableGroups.length-1].lastTabbableNode:c=r.tabbableGroups[0].firstTabbableNode;else if(o.shiftKey){var g=te(r.tabbableGroups,function(j){var B=j.firstTabbableNode;return u===B});if(g<0&&(f.container===u||D(u,n.tabbableOptions)&&!A(u,n.tabbableOptions)&&!f.nextTabbableNode(u,!1))&&(g=b),g>=0){var w=g===0?r.tabbableGroups.length-1:g-1,S=r.tabbableGroups[w];c=S.lastTabbableNode}}else{var C=te(r.tabbableGroups,function(j){var B=j.lastTabbableNode;return u===B});if(C<0&&(f.container===u||D(u,n.tabbableOptions)&&!A(u,n.tabbableOptions)&&!f.nextTabbableNode(u))&&(C=b),C>=0){var oe=C===r.tabbableGroups.length-1?0:C+1,ue=r.tabbableGroups[oe];c=ue.firstTabbableNode}}}else c=h("fallbackFocus");c&&(o.preventDefault(),y(c))},E=function(o){if(Fe(o)&&O(n.escapeDeactivates,o)!==!1){o.preventDefault(),s.deactivate();return}if(Se(o)){k(o);return}},q=function(o){var u=P(o);m(u)>=0||O(n.clickOutsideDeactivates,o)||O(n.allowOutsideClick,o)||(o.preventDefault(),o.stopImmediatePropagation())},H=function(){if(r.active)return J.activateTrap(s),r.delayInitialFocusTimer=n.delayInitialFocus?ee(function(){y(v())}):y(v()),a.addEventListener("focusin",R,!0),a.addEventListener("mousedown",F,{capture:!0,passive:!1}),a.addEventListener("touchstart",F,{capture:!0,passive:!1}),a.addEventListener("click",q,{capture:!0,passive:!1}),a.addEventListener("keydown",E,{capture:!0,passive:!1}),s},U=function(){if(r.active)return a.removeEventListener("focusin",R,!0),a.removeEventListener("mousedown",F,!0),a.removeEventListener("touchstart",F,!0),a.removeEventListener("click",q,!0),a.removeEventListener("keydown",E,!0),s};return s={get active(){return r.active},get paused(){return r.paused},activate:function(o){if(r.active)return this;var u=l(o,"onActivate"),c=l(o,"onPostActivate"),b=l(o,"checkCanFocusTrap");b||p(),r.active=!0,r.paused=!1,r.nodeFocusedBeforeActivation=a.activeElement,u&&u();var f=function(){b&&p(),H(),c&&c()};return b?(b(r.containers.concat()).then(f,f),this):(f(),this)},deactivate:function(o){if(!r.active)return this;var u=X({onDeactivate:n.onDeactivate,onPostDeactivate:n.onPostDeactivate,checkCanReturnFocus:n.checkCanReturnFocus},o);clearTimeout(r.delayInitialFocusTimer),r.delayInitialFocusTimer=void 0,U(),r.active=!1,r.paused=!1,J.deactivateTrap(s);var c=l(u,"onDeactivate"),b=l(u,"onPostDeactivate"),f=l(u,"checkCanReturnFocus"),g=l(u,"returnFocus","returnFocusOnDeactivate");c&&c();var w=function(){ee(function(){g&&y(T(r.nodeFocusedBeforeActivation)),b&&b()})};return g&&f?(f(T(r.nodeFocusedBeforeActivation)).then(w,w),this):(w(),this)},pause:function(){return r.paused||!r.active?this:(r.paused=!0,U(),this)},unpause:function(){return!r.paused||!r.active?this:(r.paused=!1,p(),H(),this)},updateContainerElements:function(o){var u=[].concat(o).filter(Boolean);return r.containers=u.map(function(c){return typeof c=="string"?a.querySelector(c):c}),r.active&&p(),this}},s.updateContainerElements(e),s};function ne(i){let e,t;window.addEventListener("focusin",()=>{e=t,t=document.activeElement}),i.magic("focus",a=>{let n=a;return{__noscroll:!1,__wrapAround:!1,within(r){return n=r,this},withoutScrolling(){return this.__noscroll=!0,this},noscroll(){return this.__noscroll=!0,this},withWrapAround(){return this.__wrapAround=!0,this},wrap(){return this.withWrapAround()},focusable(r){return D(r)},previouslyFocused(){return e},lastFocused(){return e},focused(){return t},focusables(){return Array.isArray(n)?n:L(n,{displayCheck:"none"})},all(){return this.focusables()},isFirst(r){let s=this.all();return s[0]&&s[0].isSameNode(r)},isLast(r){let s=this.all();return s.length&&s.slice(-1)[0].isSameNode(r)},getFirst(){return this.all()[0]},getLast(){return this.all().slice(-1)[0]},getNext(){let r=this.all(),s=document.activeElement;if(r.indexOf(s)!==-1)return this.__wrapAround&&r.indexOf(s)===r.length-1?r[0]:r[r.indexOf(s)+1]},getPrevious(){let r=this.all(),s=document.activeElement;if(r.indexOf(s)!==-1)return this.__wrapAround&&r.indexOf(s)===0?r.slice(-1)[0]:r[r.indexOf(s)-1]},first(){this.focus(this.getFirst())},last(){this.focus(this.getLast())},next(){this.focus(this.getNext())},previous(){this.focus(this.getPrevious())},prev(){return this.previous()},focus(r){r&&setTimeout(()=>{r.hasAttribute("tabindex")||r.setAttribute("tabindex","0"),r.focus({preventScroll:this._noscroll})})}}}),i.directive("trap",i.skipDuringClone((a,{expression:n,modifiers:r},{effect:s,evaluateLater:l,cleanup:m})=>{let h=l(n),v=!1,p={escapeDeactivates:!1,allowOutsideClick:!0,fallbackFocus:()=>a},y=a.querySelector("[autofocus]");y&&(p.initialFocus=y);let T=re(a,p),F=()=>{},R=()=>{},k=()=>{F(),F=()=>{},R(),R=()=>{},T.deactivate({returnFocus:!r.includes("noreturn")})};s(()=>h(E=>{v!==E&&(E&&!v&&setTimeout(()=>{r.includes("inert")&&(F=ae(a)),r.includes("noscroll")&&(R=Ee()),T.activate()}),!E&&v&&k(),v=!!E)})),m(k)},(a,{expression:n,modifiers:r},{evaluate:s})=>{r.includes("inert")&&s(n)&&ae(a)}))}function ae(i){let e=[];return ie(i,t=>{let a=t.hasAttribute("aria-hidden");t.setAttribute("aria-hidden","true"),e.push(()=>a||t.removeAttribute("aria-hidden"))}),()=>{for(;e.length;)e.pop()()}}function ie(i,e){i.isSameNode(document.body)||!i.parentNode||Array.from(i.parentNode.children).forEach(t=>{t.isSameNode(i)?ie(i.parentNode,e):e(t)})}function Ee(){let i=document.documentElement.style.overflow,e=document.documentElement.style.paddingRight,t=window.innerWidth-document.documentElement.clientWidth;return document.documentElement.style.overflow="hidden",document.documentElement.style.paddingRight=`${t}px`,()=>{document.documentElement.style.overflow=i,document.documentElement.style.paddingRight=e}}document.addEventListener("alpine:init",()=>{window.Alpine.plugin(ne)});})(); +/*! Bundled license information: + +tabbable/dist/index.esm.js: + (*! + * tabbable 5.3.3 + * @license MIT, https://github.com/focus-trap/tabbable/blob/master/LICENSE + *) + +focus-trap/dist/focus-trap.esm.js: + (*! + * focus-trap 6.9.4 + * @license MIT, https://github.com/focus-trap/focus-trap/blob/master/LICENSE + *) */ diff --git a/alpinejs/packages/focus/dist/module.cjs.js b/alpinejs/packages/focus/dist/module.cjs.js index ec3a3eb..5a8d600 100644 --- a/alpinejs/packages/focus/dist/module.cjs.js +++ b/alpinejs/packages/focus/dist/module.cjs.js @@ -1,690 +1,860 @@ var __create = Object.create; var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __markAsModule = (target) => __defProp(target, "__esModule", {value: true}); -var __commonJS = (callback, module2) => () => { - if (!module2) { - module2 = {exports: {}}; - callback(module2.exports, module2); - } - return module2.exports; +var __commonJS = (cb, mod) => function __require() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; var __export = (target, all) => { for (var name in all) - __defProp(target, name, {get: all[name], enumerable: true}); + __defProp(target, name, { get: all[name], enumerable: true }); }; -var __exportStar = (target, module2, desc) => { - if (module2 && typeof module2 === "object" || typeof module2 === "function") { - for (let key of __getOwnPropNames(module2)) - if (!__hasOwnProp.call(target, key) && key !== "default") - __defProp(target, key, {get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable}); +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } - return target; -}; -var __toModule = (module2) => { - return __exportStar(__markAsModule(__defProp(module2 != null ? __create(__getProtoOf(module2)) : {}, "default", module2 && module2.__esModule && "default" in module2 ? {get: () => module2.default, enumerable: true} : {value: module2, enumerable: true})), module2); + return to; }; +var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod +)); +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // node_modules/tabbable/dist/index.js -var require_dist = __commonJS((exports2) => { - /*! - * tabbable 5.2.1 - * @license MIT, https://github.com/focus-trap/tabbable/blob/master/LICENSE - */ - "use strict"; - Object.defineProperty(exports2, "__esModule", {value: true}); - var candidateSelectors = ["input", "select", "textarea", "a[href]", "button", "[tabindex]", "audio[controls]", "video[controls]", '[contenteditable]:not([contenteditable="false"])', "details>summary:first-of-type", "details"]; - var candidateSelector = /* @__PURE__ */ candidateSelectors.join(","); - var matches = typeof Element === "undefined" ? function() { - } : Element.prototype.matches || Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector; - var getCandidates = function getCandidates2(el, includeContainer, filter) { - var candidates = Array.prototype.slice.apply(el.querySelectorAll(candidateSelector)); - if (includeContainer && matches.call(el, candidateSelector)) { - candidates.unshift(el); - } - candidates = candidates.filter(filter); - return candidates; - }; - var isContentEditable = function isContentEditable2(node) { - return node.contentEditable === "true"; - }; - var getTabindex = function getTabindex2(node) { - var tabindexAttr = parseInt(node.getAttribute("tabindex"), 10); - if (!isNaN(tabindexAttr)) { - return tabindexAttr; - } - if (isContentEditable(node)) { - return 0; - } - if ((node.nodeName === "AUDIO" || node.nodeName === "VIDEO" || node.nodeName === "DETAILS") && node.getAttribute("tabindex") === null) { - return 0; - } - return node.tabIndex; - }; - var sortOrderedTabbables = function sortOrderedTabbables2(a, b) { - return a.tabIndex === b.tabIndex ? a.documentOrder - b.documentOrder : a.tabIndex - b.tabIndex; - }; - var isInput = function isInput2(node) { - return node.tagName === "INPUT"; - }; - var isHiddenInput = function isHiddenInput2(node) { - return isInput(node) && node.type === "hidden"; - }; - var isDetailsWithSummary = function isDetailsWithSummary2(node) { - var r = node.tagName === "DETAILS" && Array.prototype.slice.apply(node.children).some(function(child) { - return child.tagName === "SUMMARY"; - }); - return r; - }; - var getCheckedRadio = function getCheckedRadio2(nodes, form) { - for (var i = 0; i < nodes.length; i++) { - if (nodes[i].checked && nodes[i].form === form) { - return nodes[i]; +var require_dist = __commonJS({ + "node_modules/tabbable/dist/index.js"(exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + var candidateSelectors = ["input", "select", "textarea", "a[href]", "button", "[tabindex]:not(slot)", "audio[controls]", "video[controls]", '[contenteditable]:not([contenteditable="false"])', "details>summary:first-of-type", "details"]; + var candidateSelector = /* @__PURE__ */ candidateSelectors.join(","); + var NoElement = typeof Element === "undefined"; + var matches = NoElement ? function() { + } : Element.prototype.matches || Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector; + var getRootNode = !NoElement && Element.prototype.getRootNode ? function(element) { + return element.getRootNode(); + } : function(element) { + return element.ownerDocument; + }; + var getCandidates = function getCandidates2(el, includeContainer, filter) { + var candidates = Array.prototype.slice.apply(el.querySelectorAll(candidateSelector)); + if (includeContainer && matches.call(el, candidateSelector)) { + candidates.unshift(el); } - } - }; - var isTabbableRadio = function isTabbableRadio2(node) { - if (!node.name) { - return true; - } - var radioScope = node.form || node.ownerDocument; - var queryRadios = function queryRadios2(name) { - return radioScope.querySelectorAll('input[type="radio"][name="' + name + '"]'); + candidates = candidates.filter(filter); + return candidates; }; - var radioSet; - if (typeof window !== "undefined" && typeof window.CSS !== "undefined" && typeof window.CSS.escape === "function") { - radioSet = queryRadios(window.CSS.escape(node.name)); - } else { - try { - radioSet = queryRadios(node.name); - } catch (err) { - console.error("Looks like you have a radio button with a name attribute containing invalid CSS selector characters and need the CSS.escape polyfill: %s", err.message); - return false; + var getCandidatesIteratively = function getCandidatesIteratively2(elements, includeContainer, options) { + var candidates = []; + var elementsToCheck = Array.from(elements); + while (elementsToCheck.length) { + var element = elementsToCheck.shift(); + if (element.tagName === "SLOT") { + var assigned = element.assignedElements(); + var content = assigned.length ? assigned : element.children; + var nestedCandidates = getCandidatesIteratively2(content, true, options); + if (options.flatten) { + candidates.push.apply(candidates, nestedCandidates); + } else { + candidates.push({ + scope: element, + candidates: nestedCandidates + }); + } + } else { + var validCandidate = matches.call(element, candidateSelector); + if (validCandidate && options.filter(element) && (includeContainer || !elements.includes(element))) { + candidates.push(element); + } + var shadowRoot = element.shadowRoot || // check for an undisclosed shadow + typeof options.getShadowRoot === "function" && options.getShadowRoot(element); + var validShadowRoot = !options.shadowRootFilter || options.shadowRootFilter(element); + if (shadowRoot && validShadowRoot) { + var _nestedCandidates = getCandidatesIteratively2(shadowRoot === true ? element.children : shadowRoot.children, true, options); + if (options.flatten) { + candidates.push.apply(candidates, _nestedCandidates); + } else { + candidates.push({ + scope: element, + candidates: _nestedCandidates + }); + } + } else { + elementsToCheck.unshift.apply(elementsToCheck, element.children); + } + } } - } - var checked = getCheckedRadio(radioSet, node.form); - return !checked || checked === node; - }; - var isRadio = function isRadio2(node) { - return isInput(node) && node.type === "radio"; - }; - var isNonTabbableRadio = function isNonTabbableRadio2(node) { - return isRadio(node) && !isTabbableRadio(node); - }; - var isHidden = function isHidden2(node, displayCheck) { - if (getComputedStyle(node).visibility === "hidden") { - return true; - } - var isDirectSummary = matches.call(node, "details>summary:first-of-type"); - var nodeUnderDetails = isDirectSummary ? node.parentElement : node; - if (matches.call(nodeUnderDetails, "details:not([open]) *")) { - return true; - } - if (!displayCheck || displayCheck === "full") { - while (node) { - if (getComputedStyle(node).display === "none") { - return true; + return candidates; + }; + var getTabindex = function getTabindex2(node, isScope) { + if (node.tabIndex < 0) { + if ((isScope || /^(AUDIO|VIDEO|DETAILS)$/.test(node.tagName) || node.isContentEditable) && isNaN(parseInt(node.getAttribute("tabindex"), 10))) { + return 0; } - node = node.parentElement; } - } else if (displayCheck === "non-zero-area") { - var _node$getBoundingClie = node.getBoundingClientRect(), width = _node$getBoundingClie.width, height = _node$getBoundingClie.height; - return width === 0 && height === 0; - } - return false; - }; - var isDisabledFromFieldset = function isDisabledFromFieldset2(node) { - if (isInput(node) || node.tagName === "SELECT" || node.tagName === "TEXTAREA" || node.tagName === "BUTTON") { - var parentNode = node.parentElement; - while (parentNode) { - if (parentNode.tagName === "FIELDSET" && parentNode.disabled) { - for (var i = 0; i < parentNode.children.length; i++) { - var child = parentNode.children.item(i); - if (child.tagName === "LEGEND") { - if (child.contains(node)) { - return false; - } - return true; - } - } - return true; + return node.tabIndex; + }; + var sortOrderedTabbables = function sortOrderedTabbables2(a, b) { + return a.tabIndex === b.tabIndex ? a.documentOrder - b.documentOrder : a.tabIndex - b.tabIndex; + }; + var isInput = function isInput2(node) { + return node.tagName === "INPUT"; + }; + var isHiddenInput = function isHiddenInput2(node) { + return isInput(node) && node.type === "hidden"; + }; + var isDetailsWithSummary = function isDetailsWithSummary2(node) { + var r = node.tagName === "DETAILS" && Array.prototype.slice.apply(node.children).some(function(child) { + return child.tagName === "SUMMARY"; + }); + return r; + }; + var getCheckedRadio = function getCheckedRadio2(nodes, form) { + for (var i = 0; i < nodes.length; i++) { + if (nodes[i].checked && nodes[i].form === form) { + return nodes[i]; } - parentNode = parentNode.parentElement; } - } - return false; - }; - var isNodeMatchingSelectorFocusable = function isNodeMatchingSelectorFocusable2(options, node) { - if (node.disabled || isHiddenInput(node) || isHidden(node, options.displayCheck) || isDetailsWithSummary(node) || isDisabledFromFieldset(node)) { - return false; - } - return true; - }; - var isNodeMatchingSelectorTabbable = function isNodeMatchingSelectorTabbable2(options, node) { - if (!isNodeMatchingSelectorFocusable(options, node) || isNonTabbableRadio(node) || getTabindex(node) < 0) { - return false; - } - return true; - }; - var tabbable = function tabbable2(el, options) { - options = options || {}; - var regularTabbables = []; - var orderedTabbables = []; - var candidates = getCandidates(el, options.includeContainer, isNodeMatchingSelectorTabbable.bind(null, options)); - candidates.forEach(function(candidate, i) { - var candidateTabindex = getTabindex(candidate); - if (candidateTabindex === 0) { - regularTabbables.push(candidate); + }; + var isTabbableRadio = function isTabbableRadio2(node) { + if (!node.name) { + return true; + } + var radioScope = node.form || getRootNode(node); + var queryRadios = function queryRadios2(name) { + return radioScope.querySelectorAll('input[type="radio"][name="' + name + '"]'); + }; + var radioSet; + if (typeof window !== "undefined" && typeof window.CSS !== "undefined" && typeof window.CSS.escape === "function") { + radioSet = queryRadios(window.CSS.escape(node.name)); } else { - orderedTabbables.push({ - documentOrder: i, - tabIndex: candidateTabindex, - node: candidate - }); + try { + radioSet = queryRadios(node.name); + } catch (err) { + console.error("Looks like you have a radio button with a name attribute containing invalid CSS selector characters and need the CSS.escape polyfill: %s", err.message); + return false; + } } - }); - var tabbableNodes = orderedTabbables.sort(sortOrderedTabbables).map(function(a) { - return a.node; - }).concat(regularTabbables); - return tabbableNodes; - }; - var focusable2 = function focusable3(el, options) { - options = options || {}; - var candidates = getCandidates(el, options.includeContainer, isNodeMatchingSelectorFocusable.bind(null, options)); - return candidates; - }; - var isTabbable = function isTabbable2(node, options) { - options = options || {}; - if (!node) { - throw new Error("No node provided"); - } - if (matches.call(node, candidateSelector) === false) { - return false; - } - return isNodeMatchingSelectorTabbable(options, node); - }; - var focusableCandidateSelector = /* @__PURE__ */ candidateSelectors.concat("iframe").join(","); - var isFocusable2 = function isFocusable3(node, options) { - options = options || {}; - if (!node) { - throw new Error("No node provided"); - } - if (matches.call(node, focusableCandidateSelector) === false) { - return false; - } - return isNodeMatchingSelectorFocusable(options, node); - }; - exports2.focusable = focusable2; - exports2.isFocusable = isFocusable2; - exports2.isTabbable = isTabbable; - exports2.tabbable = tabbable; -}); - -// node_modules/focus-trap/dist/focus-trap.js -var require_focus_trap = __commonJS((exports2) => { - /*! - * focus-trap 6.6.1 - * @license MIT, https://github.com/focus-trap/focus-trap/blob/master/LICENSE - */ - "use strict"; - Object.defineProperty(exports2, "__esModule", {value: true}); - var tabbable = require_dist(); - function ownKeys(object, enumerableOnly) { - var keys = Object.keys(object); - if (Object.getOwnPropertySymbols) { - var symbols = Object.getOwnPropertySymbols(object); - if (enumerableOnly) { - symbols = symbols.filter(function(sym) { - return Object.getOwnPropertyDescriptor(object, sym).enumerable; - }); + var checked = getCheckedRadio(radioSet, node.form); + return !checked || checked === node; + }; + var isRadio = function isRadio2(node) { + return isInput(node) && node.type === "radio"; + }; + var isNonTabbableRadio = function isNonTabbableRadio2(node) { + return isRadio(node) && !isTabbableRadio(node); + }; + var isZeroArea = function isZeroArea2(node) { + var _node$getBoundingClie = node.getBoundingClientRect(), width = _node$getBoundingClie.width, height = _node$getBoundingClie.height; + return width === 0 && height === 0; + }; + var isHidden = function isHidden2(node, _ref) { + var displayCheck = _ref.displayCheck, getShadowRoot = _ref.getShadowRoot; + if (getComputedStyle(node).visibility === "hidden") { + return true; } - keys.push.apply(keys, symbols); - } - return keys; - } - function _objectSpread2(target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i] != null ? arguments[i] : {}; - if (i % 2) { - ownKeys(Object(source), true).forEach(function(key) { - _defineProperty(target, key, source[key]); - }); - } else if (Object.getOwnPropertyDescriptors) { - Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); - } else { - ownKeys(Object(source)).forEach(function(key) { - Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); - }); + var isDirectSummary = matches.call(node, "details>summary:first-of-type"); + var nodeUnderDetails = isDirectSummary ? node.parentElement : node; + if (matches.call(nodeUnderDetails, "details:not([open]) *")) { + return true; } - } - return target; - } - function _defineProperty(obj, key, value) { - if (key in obj) { - Object.defineProperty(obj, key, { - value, - enumerable: true, - configurable: true, - writable: true - }); - } else { - obj[key] = value; - } - return obj; - } - var activeFocusTraps = function() { - var trapQueue = []; - return { - activateTrap: function activateTrap(trap) { - if (trapQueue.length > 0) { - var activeTrap = trapQueue[trapQueue.length - 1]; - if (activeTrap !== trap) { - activeTrap.pause(); + var nodeRootHost = getRootNode(node).host; + var nodeIsAttached = (nodeRootHost === null || nodeRootHost === void 0 ? void 0 : nodeRootHost.ownerDocument.contains(nodeRootHost)) || node.ownerDocument.contains(node); + if (!displayCheck || displayCheck === "full") { + if (typeof getShadowRoot === "function") { + var originalNode = node; + while (node) { + var parentElement = node.parentElement; + var rootNode = getRootNode(node); + if (parentElement && !parentElement.shadowRoot && getShadowRoot(parentElement) === true) { + return isZeroArea(node); + } else if (node.assignedSlot) { + node = node.assignedSlot; + } else if (!parentElement && rootNode !== node.ownerDocument) { + node = rootNode.host; + } else { + node = parentElement; + } } + node = originalNode; } - var trapIndex = trapQueue.indexOf(trap); - if (trapIndex === -1) { - trapQueue.push(trap); - } else { - trapQueue.splice(trapIndex, 1); - trapQueue.push(trap); - } - }, - deactivateTrap: function deactivateTrap(trap) { - var trapIndex = trapQueue.indexOf(trap); - if (trapIndex !== -1) { - trapQueue.splice(trapIndex, 1); + if (nodeIsAttached) { + return !node.getClientRects().length; } - if (trapQueue.length > 0) { - trapQueue[trapQueue.length - 1].unpause(); + } else if (displayCheck === "non-zero-area") { + return isZeroArea(node); + } + return false; + }; + var isDisabledFromFieldset = function isDisabledFromFieldset2(node) { + if (/^(INPUT|BUTTON|SELECT|TEXTAREA)$/.test(node.tagName)) { + var parentNode = node.parentElement; + while (parentNode) { + if (parentNode.tagName === "FIELDSET" && parentNode.disabled) { + for (var i = 0; i < parentNode.children.length; i++) { + var child = parentNode.children.item(i); + if (child.tagName === "LEGEND") { + return matches.call(parentNode, "fieldset[disabled] *") ? true : !child.contains(node); + } + } + return true; + } + parentNode = parentNode.parentElement; } } + return false; }; - }(); - var isSelectableInput = function isSelectableInput2(node) { - return node.tagName && node.tagName.toLowerCase() === "input" && typeof node.select === "function"; - }; - var isEscapeEvent = function isEscapeEvent2(e) { - return e.key === "Escape" || e.key === "Esc" || e.keyCode === 27; - }; - var isTabEvent = function isTabEvent2(e) { - return e.key === "Tab" || e.keyCode === 9; - }; - var delay = function delay2(fn) { - return setTimeout(fn, 0); - }; - var findIndex = function findIndex2(arr, fn) { - var idx = -1; - arr.every(function(value, i) { - if (fn(value)) { - idx = i; + var isNodeMatchingSelectorFocusable = function isNodeMatchingSelectorFocusable2(options, node) { + if (node.disabled || isHiddenInput(node) || isHidden(node, options) || // For a details element with a summary, the summary element gets the focus + isDetailsWithSummary(node) || isDisabledFromFieldset(node)) { return false; } return true; - }); - return idx; - }; - var valueOrHandler = function valueOrHandler2(value) { - for (var _len = arguments.length, params = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { - params[_key - 1] = arguments[_key]; - } - return typeof value === "function" ? value.apply(void 0, params) : value; - }; - var createFocusTrap2 = function createFocusTrap3(elements, userOptions) { - var doc = document; - var config = _objectSpread2({ - returnFocusOnDeactivate: true, - escapeDeactivates: true, - delayInitialFocus: true - }, userOptions); - var state = { - containers: [], - tabbableGroups: [], - nodeFocusedBeforeActivation: null, - mostRecentlyFocusedNode: null, - active: false, - paused: false, - delayInitialFocusTimer: void 0 - }; - var trap; - var getOption = function getOption2(configOverrideOptions, optionName, configOptionName) { - return configOverrideOptions && configOverrideOptions[optionName] !== void 0 ? configOverrideOptions[optionName] : config[configOptionName || optionName]; - }; - var containersContain = function containersContain2(element) { - return state.containers.some(function(container) { - return container.contains(element); - }); }; - var getNodeForOption = function getNodeForOption2(optionName) { - var optionValue = config[optionName]; - if (!optionValue) { - return null; + var isNodeMatchingSelectorTabbable = function isNodeMatchingSelectorTabbable2(options, node) { + if (isNonTabbableRadio(node) || getTabindex(node) < 0 || !isNodeMatchingSelectorFocusable(options, node)) { + return false; } - var node = optionValue; - if (typeof optionValue === "string") { - node = doc.querySelector(optionValue); - if (!node) { - throw new Error("`".concat(optionName, "` refers to no known node")); - } + return true; + }; + var isValidShadowRootTabbable = function isValidShadowRootTabbable2(shadowHostNode) { + var tabIndex = parseInt(shadowHostNode.getAttribute("tabindex"), 10); + if (isNaN(tabIndex) || tabIndex >= 0) { + return true; } - if (typeof optionValue === "function") { - node = optionValue(); - if (!node) { - throw new Error("`".concat(optionName, "` did not return a node")); + return false; + }; + var sortByOrder = function sortByOrder2(candidates) { + var regularTabbables = []; + var orderedTabbables = []; + candidates.forEach(function(item, i) { + var isScope = !!item.scope; + var element = isScope ? item.scope : item; + var candidateTabindex = getTabindex(element, isScope); + var elements = isScope ? sortByOrder2(item.candidates) : element; + if (candidateTabindex === 0) { + isScope ? regularTabbables.push.apply(regularTabbables, elements) : regularTabbables.push(element); + } else { + orderedTabbables.push({ + documentOrder: i, + tabIndex: candidateTabindex, + item, + isScope, + content: elements + }); } - } - return node; + }); + return orderedTabbables.sort(sortOrderedTabbables).reduce(function(acc, sortable) { + sortable.isScope ? acc.push.apply(acc, sortable.content) : acc.push(sortable.content); + return acc; + }, []).concat(regularTabbables); }; - var getInitialFocusNode = function getInitialFocusNode2() { - var node; - if (getOption({}, "initialFocus") === false) { - return false; - } - if (getNodeForOption("initialFocus") !== null) { - node = getNodeForOption("initialFocus"); - } else if (containersContain(doc.activeElement)) { - node = doc.activeElement; + var tabbable = function tabbable2(el, options) { + options = options || {}; + var candidates; + if (options.getShadowRoot) { + candidates = getCandidatesIteratively([el], options.includeContainer, { + filter: isNodeMatchingSelectorTabbable.bind(null, options), + flatten: false, + getShadowRoot: options.getShadowRoot, + shadowRootFilter: isValidShadowRootTabbable + }); } else { - var firstTabbableGroup = state.tabbableGroups[0]; - var firstTabbableNode = firstTabbableGroup && firstTabbableGroup.firstTabbableNode; - node = firstTabbableNode || getNodeForOption("fallbackFocus"); + candidates = getCandidates(el, options.includeContainer, isNodeMatchingSelectorTabbable.bind(null, options)); } - if (!node) { - throw new Error("Your focus-trap needs to have at least one focusable element"); - } - return node; + return sortByOrder(candidates); }; - var updateTabbableNodes = function updateTabbableNodes2() { - state.tabbableGroups = state.containers.map(function(container) { - var tabbableNodes = tabbable.tabbable(container); - if (tabbableNodes.length > 0) { - return { - container, - firstTabbableNode: tabbableNodes[0], - lastTabbableNode: tabbableNodes[tabbableNodes.length - 1] - }; - } - return void 0; - }).filter(function(group) { - return !!group; - }); - if (state.tabbableGroups.length <= 0 && !getNodeForOption("fallbackFocus")) { - throw new Error("Your focus-trap must have at least one container with at least one tabbable node in it at all times"); + var focusable2 = function focusable3(el, options) { + options = options || {}; + var candidates; + if (options.getShadowRoot) { + candidates = getCandidatesIteratively([el], options.includeContainer, { + filter: isNodeMatchingSelectorFocusable.bind(null, options), + flatten: true, + getShadowRoot: options.getShadowRoot + }); + } else { + candidates = getCandidates(el, options.includeContainer, isNodeMatchingSelectorFocusable.bind(null, options)); } + return candidates; }; - var tryFocus = function tryFocus2(node) { - if (node === false) { - return; + var isTabbable = function isTabbable2(node, options) { + options = options || {}; + if (!node) { + throw new Error("No node provided"); } - if (node === doc.activeElement) { - return; + if (matches.call(node, candidateSelector) === false) { + return false; } - if (!node || !node.focus) { - tryFocus2(getInitialFocusNode()); - return; + return isNodeMatchingSelectorTabbable(options, node); + }; + var focusableCandidateSelector = /* @__PURE__ */ candidateSelectors.concat("iframe").join(","); + var isFocusable2 = function isFocusable3(node, options) { + options = options || {}; + if (!node) { + throw new Error("No node provided"); } - node.focus({ - preventScroll: !!config.preventScroll - }); - state.mostRecentlyFocusedNode = node; - if (isSelectableInput(node)) { - node.select(); + if (matches.call(node, focusableCandidateSelector) === false) { + return false; } + return isNodeMatchingSelectorFocusable(options, node); }; - var getReturnFocusNode = function getReturnFocusNode2(previousActiveElement) { - var node = getNodeForOption("setReturnFocus"); - return node ? node : previousActiveElement; - }; - var checkPointerDown = function checkPointerDown2(e) { - if (containersContain(e.target)) { - return; + exports.focusable = focusable2; + exports.isFocusable = isFocusable2; + exports.isTabbable = isTabbable; + exports.tabbable = tabbable; + } +}); + +// node_modules/focus-trap/dist/focus-trap.js +var require_focus_trap = __commonJS({ + "node_modules/focus-trap/dist/focus-trap.js"(exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + var tabbable = require_dist(); + function ownKeys(object, enumerableOnly) { + var keys = Object.keys(object); + if (Object.getOwnPropertySymbols) { + var symbols = Object.getOwnPropertySymbols(object); + enumerableOnly && (symbols = symbols.filter(function(sym) { + return Object.getOwnPropertyDescriptor(object, sym).enumerable; + })), keys.push.apply(keys, symbols); } - if (valueOrHandler(config.clickOutsideDeactivates, e)) { - trap.deactivate({ - returnFocus: config.returnFocusOnDeactivate && !tabbable.isFocusable(e.target) + return keys; + } + function _objectSpread2(target) { + for (var i = 1; i < arguments.length; i++) { + var source = null != arguments[i] ? arguments[i] : {}; + i % 2 ? ownKeys(Object(source), true).forEach(function(key) { + _defineProperty(target, key, source[key]); + }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function(key) { + Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); - return; } - if (valueOrHandler(config.allowOutsideClick, e)) { - return; - } - e.preventDefault(); - }; - var checkFocusIn = function checkFocusIn2(e) { - var targetContained = containersContain(e.target); - if (targetContained || e.target instanceof Document) { - if (targetContained) { - state.mostRecentlyFocusedNode = e.target; - } + return target; + } + function _defineProperty(obj, key, value) { + if (key in obj) { + Object.defineProperty(obj, key, { + value, + enumerable: true, + configurable: true, + writable: true + }); } else { - e.stopImmediatePropagation(); - tryFocus(state.mostRecentlyFocusedNode || getInitialFocusNode()); + obj[key] = value; } - }; - var checkTab = function checkTab2(e) { - updateTabbableNodes(); - var destinationNode = null; - if (state.tabbableGroups.length > 0) { - var containerIndex = findIndex(state.tabbableGroups, function(_ref) { - var container = _ref.container; - return container.contains(e.target); - }); - if (containerIndex < 0) { - if (e.shiftKey) { - destinationNode = state.tabbableGroups[state.tabbableGroups.length - 1].lastTabbableNode; - } else { - destinationNode = state.tabbableGroups[0].firstTabbableNode; - } - } else if (e.shiftKey) { - var startOfGroupIndex = findIndex(state.tabbableGroups, function(_ref2) { - var firstTabbableNode = _ref2.firstTabbableNode; - return e.target === firstTabbableNode; - }); - if (startOfGroupIndex < 0 && state.tabbableGroups[containerIndex].container === e.target) { - startOfGroupIndex = containerIndex; + return obj; + } + var activeFocusTraps = function() { + var trapQueue = []; + return { + activateTrap: function activateTrap(trap) { + if (trapQueue.length > 0) { + var activeTrap = trapQueue[trapQueue.length - 1]; + if (activeTrap !== trap) { + activeTrap.pause(); + } } - if (startOfGroupIndex >= 0) { - var destinationGroupIndex = startOfGroupIndex === 0 ? state.tabbableGroups.length - 1 : startOfGroupIndex - 1; - var destinationGroup = state.tabbableGroups[destinationGroupIndex]; - destinationNode = destinationGroup.lastTabbableNode; + var trapIndex = trapQueue.indexOf(trap); + if (trapIndex === -1) { + trapQueue.push(trap); + } else { + trapQueue.splice(trapIndex, 1); + trapQueue.push(trap); } - } else { - var lastOfGroupIndex = findIndex(state.tabbableGroups, function(_ref3) { - var lastTabbableNode = _ref3.lastTabbableNode; - return e.target === lastTabbableNode; - }); - if (lastOfGroupIndex < 0 && state.tabbableGroups[containerIndex].container === e.target) { - lastOfGroupIndex = containerIndex; + }, + deactivateTrap: function deactivateTrap(trap) { + var trapIndex = trapQueue.indexOf(trap); + if (trapIndex !== -1) { + trapQueue.splice(trapIndex, 1); } - if (lastOfGroupIndex >= 0) { - var _destinationGroupIndex = lastOfGroupIndex === state.tabbableGroups.length - 1 ? 0 : lastOfGroupIndex + 1; - var _destinationGroup = state.tabbableGroups[_destinationGroupIndex]; - destinationNode = _destinationGroup.firstTabbableNode; + if (trapQueue.length > 0) { + trapQueue[trapQueue.length - 1].unpause(); } } - } else { - destinationNode = getNodeForOption("fallbackFocus"); - } - if (destinationNode) { - e.preventDefault(); - tryFocus(destinationNode); - } + }; + }(); + var isSelectableInput = function isSelectableInput2(node) { + return node.tagName && node.tagName.toLowerCase() === "input" && typeof node.select === "function"; }; - var checkKey = function checkKey2(e) { - if (isEscapeEvent(e) && valueOrHandler(config.escapeDeactivates) !== false) { - e.preventDefault(); - trap.deactivate(); - return; - } - if (isTabEvent(e)) { - checkTab(e); - return; - } + var isEscapeEvent = function isEscapeEvent2(e) { + return e.key === "Escape" || e.key === "Esc" || e.keyCode === 27; }; - var checkClick = function checkClick2(e) { - if (valueOrHandler(config.clickOutsideDeactivates, e)) { - return; - } - if (containersContain(e.target)) { - return; - } - if (valueOrHandler(config.allowOutsideClick, e)) { - return; - } - e.preventDefault(); - e.stopImmediatePropagation(); + var isTabEvent = function isTabEvent2(e) { + return e.key === "Tab" || e.keyCode === 9; }; - var addListeners = function addListeners2() { - if (!state.active) { - return; - } - activeFocusTraps.activateTrap(trap); - state.delayInitialFocusTimer = config.delayInitialFocus ? delay(function() { - tryFocus(getInitialFocusNode()); - }) : tryFocus(getInitialFocusNode()); - doc.addEventListener("focusin", checkFocusIn, true); - doc.addEventListener("mousedown", checkPointerDown, { - capture: true, - passive: false - }); - doc.addEventListener("touchstart", checkPointerDown, { - capture: true, - passive: false - }); - doc.addEventListener("click", checkClick, { - capture: true, - passive: false - }); - doc.addEventListener("keydown", checkKey, { - capture: true, - passive: false + var delay = function delay2(fn) { + return setTimeout(fn, 0); + }; + var findIndex = function findIndex2(arr, fn) { + var idx = -1; + arr.every(function(value, i) { + if (fn(value)) { + idx = i; + return false; + } + return true; }); - return trap; + return idx; }; - var removeListeners = function removeListeners2() { - if (!state.active) { - return; + var valueOrHandler = function valueOrHandler2(value) { + for (var _len = arguments.length, params = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + params[_key - 1] = arguments[_key]; } - doc.removeEventListener("focusin", checkFocusIn, true); - doc.removeEventListener("mousedown", checkPointerDown, true); - doc.removeEventListener("touchstart", checkPointerDown, true); - doc.removeEventListener("click", checkClick, true); - doc.removeEventListener("keydown", checkKey, true); - return trap; + return typeof value === "function" ? value.apply(void 0, params) : value; }; - trap = { - activate: function activate(activateOptions) { - if (state.active) { - return this; + var getActualTarget = function getActualTarget2(event) { + return event.target.shadowRoot && typeof event.composedPath === "function" ? event.composedPath()[0] : event.target; + }; + var createFocusTrap2 = function createFocusTrap3(elements, userOptions) { + var doc = (userOptions === null || userOptions === void 0 ? void 0 : userOptions.document) || document; + var config = _objectSpread2({ + returnFocusOnDeactivate: true, + escapeDeactivates: true, + delayInitialFocus: true + }, userOptions); + var state = { + // containers given to createFocusTrap() + // @type {Array} + containers: [], + // list of objects identifying tabbable nodes in `containers` in the trap + // NOTE: it's possible that a group has no tabbable nodes if nodes get removed while the trap + // is active, but the trap should never get to a state where there isn't at least one group + // with at least one tabbable node in it (that would lead to an error condition that would + // result in an error being thrown) + // @type {Array<{ + // container: HTMLElement, + // tabbableNodes: Array, // empty if none + // focusableNodes: Array, // empty if none + // firstTabbableNode: HTMLElement|null, + // lastTabbableNode: HTMLElement|null, + // nextTabbableNode: (node: HTMLElement, forward: boolean) => HTMLElement|undefined + // }>} + containerGroups: [], + // same order/length as `containers` list + // references to objects in `containerGroups`, but only those that actually have + // tabbable nodes in them + // NOTE: same order as `containers` and `containerGroups`, but __not necessarily__ + // the same length + tabbableGroups: [], + nodeFocusedBeforeActivation: null, + mostRecentlyFocusedNode: null, + active: false, + paused: false, + // timer ID for when delayInitialFocus is true and initial focus in this trap + // has been delayed during activation + delayInitialFocusTimer: void 0 + }; + var trap; + var getOption = function getOption2(configOverrideOptions, optionName, configOptionName) { + return configOverrideOptions && configOverrideOptions[optionName] !== void 0 ? configOverrideOptions[optionName] : config[configOptionName || optionName]; + }; + var findContainerIndex = function findContainerIndex2(element) { + return state.containerGroups.findIndex(function(_ref) { + var container = _ref.container, tabbableNodes = _ref.tabbableNodes; + return container.contains(element) || // fall back to explicit tabbable search which will take into consideration any + // web components if the `tabbableOptions.getShadowRoot` option was used for + // the trap, enabling shadow DOM support in tabbable (`Node.contains()` doesn't + // look inside web components even if open) + tabbableNodes.find(function(node) { + return node === element; + }); + }); + }; + var getNodeForOption = function getNodeForOption2(optionName) { + var optionValue = config[optionName]; + if (typeof optionValue === "function") { + for (var _len2 = arguments.length, params = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { + params[_key2 - 1] = arguments[_key2]; + } + optionValue = optionValue.apply(void 0, params); } - var onActivate = getOption(activateOptions, "onActivate"); - var onPostActivate = getOption(activateOptions, "onPostActivate"); - var checkCanFocusTrap = getOption(activateOptions, "checkCanFocusTrap"); - if (!checkCanFocusTrap) { - updateTabbableNodes(); + if (optionValue === true) { + optionValue = void 0; } - state.active = true; - state.paused = false; - state.nodeFocusedBeforeActivation = doc.activeElement; - if (onActivate) { - onActivate(); + if (!optionValue) { + if (optionValue === void 0 || optionValue === false) { + return optionValue; + } + throw new Error("`".concat(optionName, "` was specified but was not a node, or did not return a node")); } - var finishActivation = function finishActivation2() { - if (checkCanFocusTrap) { - updateTabbableNodes(); + var node = optionValue; + if (typeof optionValue === "string") { + node = doc.querySelector(optionValue); + if (!node) { + throw new Error("`".concat(optionName, "` as selector refers to no known node")); } - addListeners(); - if (onPostActivate) { - onPostActivate(); + } + return node; + }; + var getInitialFocusNode = function getInitialFocusNode2() { + var node = getNodeForOption("initialFocus"); + if (node === false) { + return false; + } + if (node === void 0) { + if (findContainerIndex(doc.activeElement) >= 0) { + node = doc.activeElement; + } else { + var firstTabbableGroup = state.tabbableGroups[0]; + var firstTabbableNode = firstTabbableGroup && firstTabbableGroup.firstTabbableNode; + node = firstTabbableNode || getNodeForOption("fallbackFocus"); } - }; - if (checkCanFocusTrap) { - checkCanFocusTrap(state.containers.concat()).then(finishActivation, finishActivation); - return this; } - finishActivation(); - return this; - }, - deactivate: function deactivate(deactivateOptions) { - if (!state.active) { - return this; + if (!node) { + throw new Error("Your focus-trap needs to have at least one focusable element"); } - clearTimeout(state.delayInitialFocusTimer); - state.delayInitialFocusTimer = void 0; - removeListeners(); - state.active = false; - state.paused = false; - activeFocusTraps.deactivateTrap(trap); - var onDeactivate = getOption(deactivateOptions, "onDeactivate"); - var onPostDeactivate = getOption(deactivateOptions, "onPostDeactivate"); - var checkCanReturnFocus = getOption(deactivateOptions, "checkCanReturnFocus"); - if (onDeactivate) { - onDeactivate(); - } - var returnFocus = getOption(deactivateOptions, "returnFocus", "returnFocusOnDeactivate"); - var finishDeactivation = function finishDeactivation2() { - delay(function() { - if (returnFocus) { - tryFocus(getReturnFocusNode(state.nodeFocusedBeforeActivation)); - } - if (onPostDeactivate) { - onPostDeactivate(); + return node; + }; + var updateTabbableNodes = function updateTabbableNodes2() { + state.containerGroups = state.containers.map(function(container) { + var tabbableNodes = tabbable.tabbable(container, config.tabbableOptions); + var focusableNodes = tabbable.focusable(container, config.tabbableOptions); + return { + container, + tabbableNodes, + focusableNodes, + firstTabbableNode: tabbableNodes.length > 0 ? tabbableNodes[0] : null, + lastTabbableNode: tabbableNodes.length > 0 ? tabbableNodes[tabbableNodes.length - 1] : null, + /** + * Finds the __tabbable__ node that follows the given node in the specified direction, + * in this container, if any. + * @param {HTMLElement} node + * @param {boolean} [forward] True if going in forward tab order; false if going + * in reverse. + * @returns {HTMLElement|undefined} The next tabbable node, if any. + */ + nextTabbableNode: function nextTabbableNode(node) { + var forward = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : true; + var nodeIdx = focusableNodes.findIndex(function(n) { + return n === node; + }); + if (nodeIdx < 0) { + return void 0; + } + if (forward) { + return focusableNodes.slice(nodeIdx + 1).find(function(n) { + return tabbable.isTabbable(n, config.tabbableOptions); + }); + } + return focusableNodes.slice(0, nodeIdx).reverse().find(function(n) { + return tabbable.isTabbable(n, config.tabbableOptions); + }); } + }; + }); + state.tabbableGroups = state.containerGroups.filter(function(group) { + return group.tabbableNodes.length > 0; + }); + if (state.tabbableGroups.length <= 0 && !getNodeForOption("fallbackFocus")) { + throw new Error("Your focus-trap must have at least one container with at least one tabbable node in it at all times"); + } + }; + var tryFocus = function tryFocus2(node) { + if (node === false) { + return; + } + if (node === doc.activeElement) { + return; + } + if (!node || !node.focus) { + tryFocus2(getInitialFocusNode()); + return; + } + node.focus({ + preventScroll: !!config.preventScroll + }); + state.mostRecentlyFocusedNode = node; + if (isSelectableInput(node)) { + node.select(); + } + }; + var getReturnFocusNode = function getReturnFocusNode2(previousActiveElement) { + var node = getNodeForOption("setReturnFocus", previousActiveElement); + return node ? node : node === false ? false : previousActiveElement; + }; + var checkPointerDown = function checkPointerDown2(e) { + var target = getActualTarget(e); + if (findContainerIndex(target) >= 0) { + return; + } + if (valueOrHandler(config.clickOutsideDeactivates, e)) { + trap.deactivate({ + // if, on deactivation, we should return focus to the node originally-focused + // when the trap was activated (or the configured `setReturnFocus` node), + // then assume it's also OK to return focus to the outside node that was + // just clicked, causing deactivation, as long as that node is focusable; + // if it isn't focusable, then return focus to the original node focused + // on activation (or the configured `setReturnFocus` node) + // NOTE: by setting `returnFocus: false`, deactivate() will do nothing, + // which will result in the outside click setting focus to the node + // that was clicked, whether it's focusable or not; by setting + // `returnFocus: true`, we'll attempt to re-focus the node originally-focused + // on activation (or the configured `setReturnFocus` node) + returnFocus: config.returnFocusOnDeactivate && !tabbable.isFocusable(target, config.tabbableOptions) }); - }; - if (returnFocus && checkCanReturnFocus) { - checkCanReturnFocus(getReturnFocusNode(state.nodeFocusedBeforeActivation)).then(finishDeactivation, finishDeactivation); - return this; + return; } - finishDeactivation(); - return this; - }, - pause: function pause() { - if (state.paused || !state.active) { - return this; + if (valueOrHandler(config.allowOutsideClick, e)) { + return; } - state.paused = true; - removeListeners(); - return this; - }, - unpause: function unpause() { - if (!state.paused || !state.active) { - return this; + e.preventDefault(); + }; + var checkFocusIn = function checkFocusIn2(e) { + var target = getActualTarget(e); + var targetContained = findContainerIndex(target) >= 0; + if (targetContained || target instanceof Document) { + if (targetContained) { + state.mostRecentlyFocusedNode = target; + } + } else { + e.stopImmediatePropagation(); + tryFocus(state.mostRecentlyFocusedNode || getInitialFocusNode()); } - state.paused = false; + }; + var checkTab = function checkTab2(e) { + var target = getActualTarget(e); updateTabbableNodes(); - addListeners(); - return this; - }, - updateContainerElements: function updateContainerElements(containerElements) { - var elementsAsArray = [].concat(containerElements).filter(Boolean); - state.containers = elementsAsArray.map(function(element) { - return typeof element === "string" ? doc.querySelector(element) : element; + var destinationNode = null; + if (state.tabbableGroups.length > 0) { + var containerIndex = findContainerIndex(target); + var containerGroup = containerIndex >= 0 ? state.containerGroups[containerIndex] : void 0; + if (containerIndex < 0) { + if (e.shiftKey) { + destinationNode = state.tabbableGroups[state.tabbableGroups.length - 1].lastTabbableNode; + } else { + destinationNode = state.tabbableGroups[0].firstTabbableNode; + } + } else if (e.shiftKey) { + var startOfGroupIndex = findIndex(state.tabbableGroups, function(_ref2) { + var firstTabbableNode = _ref2.firstTabbableNode; + return target === firstTabbableNode; + }); + if (startOfGroupIndex < 0 && (containerGroup.container === target || tabbable.isFocusable(target, config.tabbableOptions) && !tabbable.isTabbable(target, config.tabbableOptions) && !containerGroup.nextTabbableNode(target, false))) { + startOfGroupIndex = containerIndex; + } + if (startOfGroupIndex >= 0) { + var destinationGroupIndex = startOfGroupIndex === 0 ? state.tabbableGroups.length - 1 : startOfGroupIndex - 1; + var destinationGroup = state.tabbableGroups[destinationGroupIndex]; + destinationNode = destinationGroup.lastTabbableNode; + } + } else { + var lastOfGroupIndex = findIndex(state.tabbableGroups, function(_ref3) { + var lastTabbableNode = _ref3.lastTabbableNode; + return target === lastTabbableNode; + }); + if (lastOfGroupIndex < 0 && (containerGroup.container === target || tabbable.isFocusable(target, config.tabbableOptions) && !tabbable.isTabbable(target, config.tabbableOptions) && !containerGroup.nextTabbableNode(target))) { + lastOfGroupIndex = containerIndex; + } + if (lastOfGroupIndex >= 0) { + var _destinationGroupIndex = lastOfGroupIndex === state.tabbableGroups.length - 1 ? 0 : lastOfGroupIndex + 1; + var _destinationGroup = state.tabbableGroups[_destinationGroupIndex]; + destinationNode = _destinationGroup.firstTabbableNode; + } + } + } else { + destinationNode = getNodeForOption("fallbackFocus"); + } + if (destinationNode) { + e.preventDefault(); + tryFocus(destinationNode); + } + }; + var checkKey = function checkKey2(e) { + if (isEscapeEvent(e) && valueOrHandler(config.escapeDeactivates, e) !== false) { + e.preventDefault(); + trap.deactivate(); + return; + } + if (isTabEvent(e)) { + checkTab(e); + return; + } + }; + var checkClick = function checkClick2(e) { + var target = getActualTarget(e); + if (findContainerIndex(target) >= 0) { + return; + } + if (valueOrHandler(config.clickOutsideDeactivates, e)) { + return; + } + if (valueOrHandler(config.allowOutsideClick, e)) { + return; + } + e.preventDefault(); + e.stopImmediatePropagation(); + }; + var addListeners = function addListeners2() { + if (!state.active) { + return; + } + activeFocusTraps.activateTrap(trap); + state.delayInitialFocusTimer = config.delayInitialFocus ? delay(function() { + tryFocus(getInitialFocusNode()); + }) : tryFocus(getInitialFocusNode()); + doc.addEventListener("focusin", checkFocusIn, true); + doc.addEventListener("mousedown", checkPointerDown, { + capture: true, + passive: false + }); + doc.addEventListener("touchstart", checkPointerDown, { + capture: true, + passive: false + }); + doc.addEventListener("click", checkClick, { + capture: true, + passive: false }); - if (state.active) { + doc.addEventListener("keydown", checkKey, { + capture: true, + passive: false + }); + return trap; + }; + var removeListeners = function removeListeners2() { + if (!state.active) { + return; + } + doc.removeEventListener("focusin", checkFocusIn, true); + doc.removeEventListener("mousedown", checkPointerDown, true); + doc.removeEventListener("touchstart", checkPointerDown, true); + doc.removeEventListener("click", checkClick, true); + doc.removeEventListener("keydown", checkKey, true); + return trap; + }; + trap = { + get active() { + return state.active; + }, + get paused() { + return state.paused; + }, + activate: function activate(activateOptions) { + if (state.active) { + return this; + } + var onActivate = getOption(activateOptions, "onActivate"); + var onPostActivate = getOption(activateOptions, "onPostActivate"); + var checkCanFocusTrap = getOption(activateOptions, "checkCanFocusTrap"); + if (!checkCanFocusTrap) { + updateTabbableNodes(); + } + state.active = true; + state.paused = false; + state.nodeFocusedBeforeActivation = doc.activeElement; + if (onActivate) { + onActivate(); + } + var finishActivation = function finishActivation2() { + if (checkCanFocusTrap) { + updateTabbableNodes(); + } + addListeners(); + if (onPostActivate) { + onPostActivate(); + } + }; + if (checkCanFocusTrap) { + checkCanFocusTrap(state.containers.concat()).then(finishActivation, finishActivation); + return this; + } + finishActivation(); + return this; + }, + deactivate: function deactivate(deactivateOptions) { + if (!state.active) { + return this; + } + var options = _objectSpread2({ + onDeactivate: config.onDeactivate, + onPostDeactivate: config.onPostDeactivate, + checkCanReturnFocus: config.checkCanReturnFocus + }, deactivateOptions); + clearTimeout(state.delayInitialFocusTimer); + state.delayInitialFocusTimer = void 0; + removeListeners(); + state.active = false; + state.paused = false; + activeFocusTraps.deactivateTrap(trap); + var onDeactivate = getOption(options, "onDeactivate"); + var onPostDeactivate = getOption(options, "onPostDeactivate"); + var checkCanReturnFocus = getOption(options, "checkCanReturnFocus"); + var returnFocus = getOption(options, "returnFocus", "returnFocusOnDeactivate"); + if (onDeactivate) { + onDeactivate(); + } + var finishDeactivation = function finishDeactivation2() { + delay(function() { + if (returnFocus) { + tryFocus(getReturnFocusNode(state.nodeFocusedBeforeActivation)); + } + if (onPostDeactivate) { + onPostDeactivate(); + } + }); + }; + if (returnFocus && checkCanReturnFocus) { + checkCanReturnFocus(getReturnFocusNode(state.nodeFocusedBeforeActivation)).then(finishDeactivation, finishDeactivation); + return this; + } + finishDeactivation(); + return this; + }, + pause: function pause() { + if (state.paused || !state.active) { + return this; + } + state.paused = true; + removeListeners(); + return this; + }, + unpause: function unpause() { + if (!state.paused || !state.active) { + return this; + } + state.paused = false; updateTabbableNodes(); + addListeners(); + return this; + }, + updateContainerElements: function updateContainerElements(containerElements) { + var elementsAsArray = [].concat(containerElements).filter(Boolean); + state.containers = elementsAsArray.map(function(element) { + return typeof element === "string" ? doc.querySelector(element) : element; + }); + if (state.active) { + updateTabbableNodes(); + } + return this; } - return this; - } + }; + trap.updateContainerElements(elements); + return trap; }; - trap.updateContainerElements(elements); - return trap; - }; - exports2.createFocusTrap = createFocusTrap2; + exports.createFocusTrap = createFocusTrap2; + } }); // packages/focus/builds/module.js -__markAsModule(exports); -__export(exports, { +var module_exports = {}; +__export(module_exports, { default: () => module_default }); +module.exports = __toCommonJS(module_exports); // packages/focus/src/index.js -var import_focus_trap = __toModule(require_focus_trap()); -var import_tabbable = __toModule(require_dist()); +var import_focus_trap = __toESM(require_focus_trap()); +var import_tabbable = __toESM(require_dist()); function src_default(Alpine) { let lastFocused; let currentFocused; @@ -731,7 +901,7 @@ function src_default(Alpine) { focusables() { if (Array.isArray(within)) return within; - return (0, import_tabbable.focusable)(within, {displayCheck: "none"}); + return (0, import_tabbable.focusable)(within, { displayCheck: "none" }); }, all() { return this.focusables(); @@ -791,57 +961,66 @@ function src_default(Alpine) { setTimeout(() => { if (!el2.hasAttribute("tabindex")) el2.setAttribute("tabindex", "0"); - el2.focus({preventScroll: this._noscroll}); + el2.focus({ preventScroll: this._noscroll }); }); } }; }); - Alpine.directive("trap", Alpine.skipDuringClone((el, {expression, modifiers}, {effect, evaluateLater, cleanup}) => { - let evaluator = evaluateLater(expression); - let oldValue = false; - let trap = (0, import_focus_trap.createFocusTrap)(el, { - escapeDeactivates: false, - allowOutsideClick: true, - fallbackFocus: () => el, - initialFocus: el.querySelector("[autofocus]") - }); - let undoInert = () => { - }; - let undoDisableScrolling = () => { - }; - const releaseFocus = () => { - undoInert(); - undoInert = () => { + Alpine.directive("trap", Alpine.skipDuringClone( + (el, { expression, modifiers }, { effect, evaluateLater, cleanup }) => { + let evaluator = evaluateLater(expression); + let oldValue = false; + let options = { + escapeDeactivates: false, + allowOutsideClick: true, + fallbackFocus: () => el }; - undoDisableScrolling(); - undoDisableScrolling = () => { + let autofocusEl = el.querySelector("[autofocus]"); + if (autofocusEl) + options.initialFocus = autofocusEl; + let trap = (0, import_focus_trap.createFocusTrap)(el, options); + let undoInert = () => { }; - trap.deactivate({ - returnFocus: !modifiers.includes("noreturn") - }); - }; - effect(() => evaluator((value) => { - if (oldValue === value) - return; - if (value && !oldValue) { - setTimeout(() => { - if (modifiers.includes("inert")) - undoInert = setInert(el); - if (modifiers.includes("noscroll")) - undoDisableScrolling = disableScrolling(); - trap.activate(); + let undoDisableScrolling = () => { + }; + const releaseFocus = () => { + undoInert(); + undoInert = () => { + }; + undoDisableScrolling(); + undoDisableScrolling = () => { + }; + trap.deactivate({ + returnFocus: !modifiers.includes("noreturn") }); - } - if (!value && oldValue) { - releaseFocus(); - } - oldValue = !!value; - })); - cleanup(releaseFocus); - }, (el, {expression, modifiers}, {evaluate}) => { - if (modifiers.includes("inert") && evaluate(expression)) - setInert(el); - })); + }; + effect(() => evaluator((value) => { + if (oldValue === value) + return; + if (value && !oldValue) { + setTimeout(() => { + if (modifiers.includes("inert")) + undoInert = setInert(el); + if (modifiers.includes("noscroll")) + undoDisableScrolling = disableScrolling(); + trap.activate(); + }); + } + if (!value && oldValue) { + releaseFocus(); + } + oldValue = !!value; + })); + cleanup(releaseFocus); + }, + // When cloning, we only want to add aria-hidden attributes to the + // DOM and not try to actually trap, as trapping can mess with the + // live DOM and isn't just isolated to the cloned DOM. + (el, { expression, modifiers }, { evaluate }) => { + if (modifiers.includes("inert") && evaluate(expression)) + setInert(el); + } + )); } function setInert(el) { let undos = []; @@ -859,9 +1038,11 @@ function crawlSiblingsUp(el, callback) { if (el.isSameNode(document.body) || !el.parentNode) return; Array.from(el.parentNode.children).forEach((sibling) => { - if (!sibling.isSameNode(el)) + if (sibling.isSameNode(el)) { + crawlSiblingsUp(el.parentNode, callback); + } else { callback(sibling); - crawlSiblingsUp(el.parentNode, callback); + } }); } function disableScrolling() { @@ -878,3 +1059,19 @@ function disableScrolling() { // packages/focus/builds/module.js var module_default = src_default; +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = {}); +/*! Bundled license information: + +tabbable/dist/index.js: + (*! + * tabbable 5.3.3 + * @license MIT, https://github.com/focus-trap/tabbable/blob/master/LICENSE + *) + +focus-trap/dist/focus-trap.js: + (*! + * focus-trap 6.9.4 + * @license MIT, https://github.com/focus-trap/focus-trap/blob/master/LICENSE + *) +*/ diff --git a/alpinejs/packages/focus/dist/module.esm.js b/alpinejs/packages/focus/dist/module.esm.js index 7a59b91..64fb01f 100644 --- a/alpinejs/packages/focus/dist/module.esm.js +++ b/alpinejs/packages/focus/dist/module.esm.js @@ -1,12 +1,14 @@ // node_modules/tabbable/dist/index.esm.js -/*! -* tabbable 5.2.1 -* @license MIT, https://github.com/focus-trap/tabbable/blob/master/LICENSE -*/ -var candidateSelectors = ["input", "select", "textarea", "a[href]", "button", "[tabindex]", "audio[controls]", "video[controls]", '[contenteditable]:not([contenteditable="false"])', "details>summary:first-of-type", "details"]; +var candidateSelectors = ["input", "select", "textarea", "a[href]", "button", "[tabindex]:not(slot)", "audio[controls]", "video[controls]", '[contenteditable]:not([contenteditable="false"])', "details>summary:first-of-type", "details"]; var candidateSelector = /* @__PURE__ */ candidateSelectors.join(","); -var matches = typeof Element === "undefined" ? function() { +var NoElement = typeof Element === "undefined"; +var matches = NoElement ? function() { } : Element.prototype.matches || Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector; +var getRootNode = !NoElement && Element.prototype.getRootNode ? function(element) { + return element.getRootNode(); +} : function(element) { + return element.ownerDocument; +}; var getCandidates = function getCandidates2(el, includeContainer, filter) { var candidates = Array.prototype.slice.apply(el.querySelectorAll(candidateSelector)); if (includeContainer && matches.call(el, candidateSelector)) { @@ -15,19 +17,53 @@ var getCandidates = function getCandidates2(el, includeContainer, filter) { candidates = candidates.filter(filter); return candidates; }; -var isContentEditable = function isContentEditable2(node) { - return node.contentEditable === "true"; -}; -var getTabindex = function getTabindex2(node) { - var tabindexAttr = parseInt(node.getAttribute("tabindex"), 10); - if (!isNaN(tabindexAttr)) { - return tabindexAttr; - } - if (isContentEditable(node)) { - return 0; +var getCandidatesIteratively = function getCandidatesIteratively2(elements, includeContainer, options) { + var candidates = []; + var elementsToCheck = Array.from(elements); + while (elementsToCheck.length) { + var element = elementsToCheck.shift(); + if (element.tagName === "SLOT") { + var assigned = element.assignedElements(); + var content = assigned.length ? assigned : element.children; + var nestedCandidates = getCandidatesIteratively2(content, true, options); + if (options.flatten) { + candidates.push.apply(candidates, nestedCandidates); + } else { + candidates.push({ + scope: element, + candidates: nestedCandidates + }); + } + } else { + var validCandidate = matches.call(element, candidateSelector); + if (validCandidate && options.filter(element) && (includeContainer || !elements.includes(element))) { + candidates.push(element); + } + var shadowRoot = element.shadowRoot || // check for an undisclosed shadow + typeof options.getShadowRoot === "function" && options.getShadowRoot(element); + var validShadowRoot = !options.shadowRootFilter || options.shadowRootFilter(element); + if (shadowRoot && validShadowRoot) { + var _nestedCandidates = getCandidatesIteratively2(shadowRoot === true ? element.children : shadowRoot.children, true, options); + if (options.flatten) { + candidates.push.apply(candidates, _nestedCandidates); + } else { + candidates.push({ + scope: element, + candidates: _nestedCandidates + }); + } + } else { + elementsToCheck.unshift.apply(elementsToCheck, element.children); + } + } } - if ((node.nodeName === "AUDIO" || node.nodeName === "VIDEO" || node.nodeName === "DETAILS") && node.getAttribute("tabindex") === null) { - return 0; + return candidates; +}; +var getTabindex = function getTabindex2(node, isScope) { + if (node.tabIndex < 0) { + if ((isScope || /^(AUDIO|VIDEO|DETAILS)$/.test(node.tagName) || node.isContentEditable) && isNaN(parseInt(node.getAttribute("tabindex"), 10))) { + return 0; + } } return node.tabIndex; }; @@ -57,7 +93,7 @@ var isTabbableRadio = function isTabbableRadio2(node) { if (!node.name) { return true; } - var radioScope = node.form || node.ownerDocument; + var radioScope = node.form || getRootNode(node); var queryRadios = function queryRadios2(name) { return radioScope.querySelectorAll('input[type="radio"][name="' + name + '"]'); }; @@ -81,7 +117,12 @@ var isRadio = function isRadio2(node) { var isNonTabbableRadio = function isNonTabbableRadio2(node) { return isRadio(node) && !isTabbableRadio(node); }; -var isHidden = function isHidden2(node, displayCheck) { +var isZeroArea = function isZeroArea2(node) { + var _node$getBoundingClie = node.getBoundingClientRect(), width = _node$getBoundingClie.width, height = _node$getBoundingClie.height; + return width === 0 && height === 0; +}; +var isHidden = function isHidden2(node, _ref) { + var displayCheck = _ref.displayCheck, getShadowRoot = _ref.getShadowRoot; if (getComputedStyle(node).visibility === "hidden") { return true; } @@ -90,31 +131,43 @@ var isHidden = function isHidden2(node, displayCheck) { if (matches.call(nodeUnderDetails, "details:not([open]) *")) { return true; } + var nodeRootHost = getRootNode(node).host; + var nodeIsAttached = (nodeRootHost === null || nodeRootHost === void 0 ? void 0 : nodeRootHost.ownerDocument.contains(nodeRootHost)) || node.ownerDocument.contains(node); if (!displayCheck || displayCheck === "full") { - while (node) { - if (getComputedStyle(node).display === "none") { - return true; + if (typeof getShadowRoot === "function") { + var originalNode = node; + while (node) { + var parentElement = node.parentElement; + var rootNode = getRootNode(node); + if (parentElement && !parentElement.shadowRoot && getShadowRoot(parentElement) === true) { + return isZeroArea(node); + } else if (node.assignedSlot) { + node = node.assignedSlot; + } else if (!parentElement && rootNode !== node.ownerDocument) { + node = rootNode.host; + } else { + node = parentElement; + } } - node = node.parentElement; + node = originalNode; + } + if (nodeIsAttached) { + return !node.getClientRects().length; } } else if (displayCheck === "non-zero-area") { - var _node$getBoundingClie = node.getBoundingClientRect(), width = _node$getBoundingClie.width, height = _node$getBoundingClie.height; - return width === 0 && height === 0; + return isZeroArea(node); } return false; }; var isDisabledFromFieldset = function isDisabledFromFieldset2(node) { - if (isInput(node) || node.tagName === "SELECT" || node.tagName === "TEXTAREA" || node.tagName === "BUTTON") { + if (/^(INPUT|BUTTON|SELECT|TEXTAREA)$/.test(node.tagName)) { var parentNode = node.parentElement; while (parentNode) { if (parentNode.tagName === "FIELDSET" && parentNode.disabled) { for (var i = 0; i < parentNode.children.length; i++) { var child = parentNode.children.item(i); if (child.tagName === "LEGEND") { - if (child.contains(node)) { - return false; - } - return true; + return matches.call(parentNode, "fieldset[disabled] *") ? true : !child.contains(node); } } return true; @@ -125,44 +178,89 @@ var isDisabledFromFieldset = function isDisabledFromFieldset2(node) { return false; }; var isNodeMatchingSelectorFocusable = function isNodeMatchingSelectorFocusable2(options, node) { - if (node.disabled || isHiddenInput(node) || isHidden(node, options.displayCheck) || isDetailsWithSummary(node) || isDisabledFromFieldset(node)) { + if (node.disabled || isHiddenInput(node) || isHidden(node, options) || // For a details element with a summary, the summary element gets the focus + isDetailsWithSummary(node) || isDisabledFromFieldset(node)) { return false; } return true; }; var isNodeMatchingSelectorTabbable = function isNodeMatchingSelectorTabbable2(options, node) { - if (!isNodeMatchingSelectorFocusable(options, node) || isNonTabbableRadio(node) || getTabindex(node) < 0) { + if (isNonTabbableRadio(node) || getTabindex(node) < 0 || !isNodeMatchingSelectorFocusable(options, node)) { return false; } return true; }; -var tabbable = function tabbable2(el, options) { - options = options || {}; +var isValidShadowRootTabbable = function isValidShadowRootTabbable2(shadowHostNode) { + var tabIndex = parseInt(shadowHostNode.getAttribute("tabindex"), 10); + if (isNaN(tabIndex) || tabIndex >= 0) { + return true; + } + return false; +}; +var sortByOrder = function sortByOrder2(candidates) { var regularTabbables = []; var orderedTabbables = []; - var candidates = getCandidates(el, options.includeContainer, isNodeMatchingSelectorTabbable.bind(null, options)); - candidates.forEach(function(candidate, i) { - var candidateTabindex = getTabindex(candidate); + candidates.forEach(function(item, i) { + var isScope = !!item.scope; + var element = isScope ? item.scope : item; + var candidateTabindex = getTabindex(element, isScope); + var elements = isScope ? sortByOrder2(item.candidates) : element; if (candidateTabindex === 0) { - regularTabbables.push(candidate); + isScope ? regularTabbables.push.apply(regularTabbables, elements) : regularTabbables.push(element); } else { orderedTabbables.push({ documentOrder: i, tabIndex: candidateTabindex, - node: candidate + item, + isScope, + content: elements }); } }); - var tabbableNodes = orderedTabbables.sort(sortOrderedTabbables).map(function(a) { - return a.node; - }).concat(regularTabbables); - return tabbableNodes; + return orderedTabbables.sort(sortOrderedTabbables).reduce(function(acc, sortable) { + sortable.isScope ? acc.push.apply(acc, sortable.content) : acc.push(sortable.content); + return acc; + }, []).concat(regularTabbables); +}; +var tabbable = function tabbable2(el, options) { + options = options || {}; + var candidates; + if (options.getShadowRoot) { + candidates = getCandidatesIteratively([el], options.includeContainer, { + filter: isNodeMatchingSelectorTabbable.bind(null, options), + flatten: false, + getShadowRoot: options.getShadowRoot, + shadowRootFilter: isValidShadowRootTabbable + }); + } else { + candidates = getCandidates(el, options.includeContainer, isNodeMatchingSelectorTabbable.bind(null, options)); + } + return sortByOrder(candidates); }; var focusable = function focusable2(el, options) { options = options || {}; - var candidates = getCandidates(el, options.includeContainer, isNodeMatchingSelectorFocusable.bind(null, options)); + var candidates; + if (options.getShadowRoot) { + candidates = getCandidatesIteratively([el], options.includeContainer, { + filter: isNodeMatchingSelectorFocusable.bind(null, options), + flatten: true, + getShadowRoot: options.getShadowRoot + }); + } else { + candidates = getCandidates(el, options.includeContainer, isNodeMatchingSelectorFocusable.bind(null, options)); + } return candidates; }; +var isTabbable = function isTabbable2(node, options) { + options = options || {}; + if (!node) { + throw new Error("No node provided"); + } + if (matches.call(node, candidateSelector) === false) { + return false; + } + return isNodeMatchingSelectorTabbable(options, node); +}; var focusableCandidateSelector = /* @__PURE__ */ candidateSelectors.concat("iframe").join(","); var isFocusable = function isFocusable2(node, options) { options = options || {}; @@ -176,37 +274,24 @@ var isFocusable = function isFocusable2(node, options) { }; // node_modules/focus-trap/dist/focus-trap.esm.js -/*! -* focus-trap 6.6.1 -* @license MIT, https://github.com/focus-trap/focus-trap/blob/master/LICENSE -*/ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); - if (enumerableOnly) { - symbols = symbols.filter(function(sym) { - return Object.getOwnPropertyDescriptor(object, sym).enumerable; - }); - } - keys.push.apply(keys, symbols); + enumerableOnly && (symbols = symbols.filter(function(sym) { + return Object.getOwnPropertyDescriptor(object, sym).enumerable; + })), keys.push.apply(keys, symbols); } return keys; } function _objectSpread2(target) { for (var i = 1; i < arguments.length; i++) { - var source = arguments[i] != null ? arguments[i] : {}; - if (i % 2) { - ownKeys(Object(source), true).forEach(function(key) { - _defineProperty(target, key, source[key]); - }); - } else if (Object.getOwnPropertyDescriptors) { - Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); - } else { - ownKeys(Object(source)).forEach(function(key) { - Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); - }); - } + var source = null != arguments[i] ? arguments[i] : {}; + i % 2 ? ownKeys(Object(source), true).forEach(function(key) { + _defineProperty(target, key, source[key]); + }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function(key) { + Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); + }); } return target; } @@ -281,64 +366,103 @@ var valueOrHandler = function valueOrHandler2(value) { } return typeof value === "function" ? value.apply(void 0, params) : value; }; +var getActualTarget = function getActualTarget2(event) { + return event.target.shadowRoot && typeof event.composedPath === "function" ? event.composedPath()[0] : event.target; +}; var createFocusTrap = function createFocusTrap2(elements, userOptions) { - var doc = document; + var doc = (userOptions === null || userOptions === void 0 ? void 0 : userOptions.document) || document; var config = _objectSpread2({ returnFocusOnDeactivate: true, escapeDeactivates: true, delayInitialFocus: true }, userOptions); var state = { + // containers given to createFocusTrap() + // @type {Array} containers: [], + // list of objects identifying tabbable nodes in `containers` in the trap + // NOTE: it's possible that a group has no tabbable nodes if nodes get removed while the trap + // is active, but the trap should never get to a state where there isn't at least one group + // with at least one tabbable node in it (that would lead to an error condition that would + // result in an error being thrown) + // @type {Array<{ + // container: HTMLElement, + // tabbableNodes: Array, // empty if none + // focusableNodes: Array, // empty if none + // firstTabbableNode: HTMLElement|null, + // lastTabbableNode: HTMLElement|null, + // nextTabbableNode: (node: HTMLElement, forward: boolean) => HTMLElement|undefined + // }>} + containerGroups: [], + // same order/length as `containers` list + // references to objects in `containerGroups`, but only those that actually have + // tabbable nodes in them + // NOTE: same order as `containers` and `containerGroups`, but __not necessarily__ + // the same length tabbableGroups: [], nodeFocusedBeforeActivation: null, mostRecentlyFocusedNode: null, active: false, paused: false, + // timer ID for when delayInitialFocus is true and initial focus in this trap + // has been delayed during activation delayInitialFocusTimer: void 0 }; var trap; var getOption = function getOption2(configOverrideOptions, optionName, configOptionName) { return configOverrideOptions && configOverrideOptions[optionName] !== void 0 ? configOverrideOptions[optionName] : config[configOptionName || optionName]; }; - var containersContain = function containersContain2(element) { - return state.containers.some(function(container) { - return container.contains(element); + var findContainerIndex = function findContainerIndex2(element) { + return state.containerGroups.findIndex(function(_ref) { + var container = _ref.container, tabbableNodes = _ref.tabbableNodes; + return container.contains(element) || // fall back to explicit tabbable search which will take into consideration any + // web components if the `tabbableOptions.getShadowRoot` option was used for + // the trap, enabling shadow DOM support in tabbable (`Node.contains()` doesn't + // look inside web components even if open) + tabbableNodes.find(function(node) { + return node === element; + }); }); }; var getNodeForOption = function getNodeForOption2(optionName) { var optionValue = config[optionName]; + if (typeof optionValue === "function") { + for (var _len2 = arguments.length, params = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { + params[_key2 - 1] = arguments[_key2]; + } + optionValue = optionValue.apply(void 0, params); + } + if (optionValue === true) { + optionValue = void 0; + } if (!optionValue) { - return null; + if (optionValue === void 0 || optionValue === false) { + return optionValue; + } + throw new Error("`".concat(optionName, "` was specified but was not a node, or did not return a node")); } var node = optionValue; if (typeof optionValue === "string") { node = doc.querySelector(optionValue); if (!node) { - throw new Error("`".concat(optionName, "` refers to no known node")); - } - } - if (typeof optionValue === "function") { - node = optionValue(); - if (!node) { - throw new Error("`".concat(optionName, "` did not return a node")); + throw new Error("`".concat(optionName, "` as selector refers to no known node")); } } return node; }; var getInitialFocusNode = function getInitialFocusNode2() { - var node; - if (getOption({}, "initialFocus") === false) { + var node = getNodeForOption("initialFocus"); + if (node === false) { return false; } - if (getNodeForOption("initialFocus") !== null) { - node = getNodeForOption("initialFocus"); - } else if (containersContain(doc.activeElement)) { - node = doc.activeElement; - } else { - var firstTabbableGroup = state.tabbableGroups[0]; - var firstTabbableNode = firstTabbableGroup && firstTabbableGroup.firstTabbableNode; - node = firstTabbableNode || getNodeForOption("fallbackFocus"); + if (node === void 0) { + if (findContainerIndex(doc.activeElement) >= 0) { + node = doc.activeElement; + } else { + var firstTabbableGroup = state.tabbableGroups[0]; + var firstTabbableNode = firstTabbableGroup && firstTabbableGroup.firstTabbableNode; + node = firstTabbableNode || getNodeForOption("fallbackFocus"); + } } if (!node) { throw new Error("Your focus-trap needs to have at least one focusable element"); @@ -346,18 +470,44 @@ var createFocusTrap = function createFocusTrap2(elements, userOptions) { return node; }; var updateTabbableNodes = function updateTabbableNodes2() { - state.tabbableGroups = state.containers.map(function(container) { - var tabbableNodes = tabbable(container); - if (tabbableNodes.length > 0) { - return { - container, - firstTabbableNode: tabbableNodes[0], - lastTabbableNode: tabbableNodes[tabbableNodes.length - 1] - }; - } - return void 0; - }).filter(function(group) { - return !!group; + state.containerGroups = state.containers.map(function(container) { + var tabbableNodes = tabbable(container, config.tabbableOptions); + var focusableNodes = focusable(container, config.tabbableOptions); + return { + container, + tabbableNodes, + focusableNodes, + firstTabbableNode: tabbableNodes.length > 0 ? tabbableNodes[0] : null, + lastTabbableNode: tabbableNodes.length > 0 ? tabbableNodes[tabbableNodes.length - 1] : null, + /** + * Finds the __tabbable__ node that follows the given node in the specified direction, + * in this container, if any. + * @param {HTMLElement} node + * @param {boolean} [forward] True if going in forward tab order; false if going + * in reverse. + * @returns {HTMLElement|undefined} The next tabbable node, if any. + */ + nextTabbableNode: function nextTabbableNode(node) { + var forward = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : true; + var nodeIdx = focusableNodes.findIndex(function(n) { + return n === node; + }); + if (nodeIdx < 0) { + return void 0; + } + if (forward) { + return focusableNodes.slice(nodeIdx + 1).find(function(n) { + return isTabbable(n, config.tabbableOptions); + }); + } + return focusableNodes.slice(0, nodeIdx).reverse().find(function(n) { + return isTabbable(n, config.tabbableOptions); + }); + } + }; + }); + state.tabbableGroups = state.containerGroups.filter(function(group) { + return group.tabbableNodes.length > 0; }); if (state.tabbableGroups.length <= 0 && !getNodeForOption("fallbackFocus")) { throw new Error("Your focus-trap must have at least one container with at least one tabbable node in it at all times"); @@ -383,16 +533,28 @@ var createFocusTrap = function createFocusTrap2(elements, userOptions) { } }; var getReturnFocusNode = function getReturnFocusNode2(previousActiveElement) { - var node = getNodeForOption("setReturnFocus"); - return node ? node : previousActiveElement; + var node = getNodeForOption("setReturnFocus", previousActiveElement); + return node ? node : node === false ? false : previousActiveElement; }; var checkPointerDown = function checkPointerDown2(e) { - if (containersContain(e.target)) { + var target = getActualTarget(e); + if (findContainerIndex(target) >= 0) { return; } if (valueOrHandler(config.clickOutsideDeactivates, e)) { trap.deactivate({ - returnFocus: config.returnFocusOnDeactivate && !isFocusable(e.target) + // if, on deactivation, we should return focus to the node originally-focused + // when the trap was activated (or the configured `setReturnFocus` node), + // then assume it's also OK to return focus to the outside node that was + // just clicked, causing deactivation, as long as that node is focusable; + // if it isn't focusable, then return focus to the original node focused + // on activation (or the configured `setReturnFocus` node) + // NOTE: by setting `returnFocus: false`, deactivate() will do nothing, + // which will result in the outside click setting focus to the node + // that was clicked, whether it's focusable or not; by setting + // `returnFocus: true`, we'll attempt to re-focus the node originally-focused + // on activation (or the configured `setReturnFocus` node) + returnFocus: config.returnFocusOnDeactivate && !isFocusable(target, config.tabbableOptions) }); return; } @@ -402,10 +564,11 @@ var createFocusTrap = function createFocusTrap2(elements, userOptions) { e.preventDefault(); }; var checkFocusIn = function checkFocusIn2(e) { - var targetContained = containersContain(e.target); - if (targetContained || e.target instanceof Document) { + var target = getActualTarget(e); + var targetContained = findContainerIndex(target) >= 0; + if (targetContained || target instanceof Document) { if (targetContained) { - state.mostRecentlyFocusedNode = e.target; + state.mostRecentlyFocusedNode = target; } } else { e.stopImmediatePropagation(); @@ -413,13 +576,12 @@ var createFocusTrap = function createFocusTrap2(elements, userOptions) { } }; var checkTab = function checkTab2(e) { + var target = getActualTarget(e); updateTabbableNodes(); var destinationNode = null; if (state.tabbableGroups.length > 0) { - var containerIndex = findIndex(state.tabbableGroups, function(_ref) { - var container = _ref.container; - return container.contains(e.target); - }); + var containerIndex = findContainerIndex(target); + var containerGroup = containerIndex >= 0 ? state.containerGroups[containerIndex] : void 0; if (containerIndex < 0) { if (e.shiftKey) { destinationNode = state.tabbableGroups[state.tabbableGroups.length - 1].lastTabbableNode; @@ -429,9 +591,9 @@ var createFocusTrap = function createFocusTrap2(elements, userOptions) { } else if (e.shiftKey) { var startOfGroupIndex = findIndex(state.tabbableGroups, function(_ref2) { var firstTabbableNode = _ref2.firstTabbableNode; - return e.target === firstTabbableNode; + return target === firstTabbableNode; }); - if (startOfGroupIndex < 0 && state.tabbableGroups[containerIndex].container === e.target) { + if (startOfGroupIndex < 0 && (containerGroup.container === target || isFocusable(target, config.tabbableOptions) && !isTabbable(target, config.tabbableOptions) && !containerGroup.nextTabbableNode(target, false))) { startOfGroupIndex = containerIndex; } if (startOfGroupIndex >= 0) { @@ -442,9 +604,9 @@ var createFocusTrap = function createFocusTrap2(elements, userOptions) { } else { var lastOfGroupIndex = findIndex(state.tabbableGroups, function(_ref3) { var lastTabbableNode = _ref3.lastTabbableNode; - return e.target === lastTabbableNode; + return target === lastTabbableNode; }); - if (lastOfGroupIndex < 0 && state.tabbableGroups[containerIndex].container === e.target) { + if (lastOfGroupIndex < 0 && (containerGroup.container === target || isFocusable(target, config.tabbableOptions) && !isTabbable(target, config.tabbableOptions) && !containerGroup.nextTabbableNode(target))) { lastOfGroupIndex = containerIndex; } if (lastOfGroupIndex >= 0) { @@ -462,7 +624,7 @@ var createFocusTrap = function createFocusTrap2(elements, userOptions) { } }; var checkKey = function checkKey2(e) { - if (isEscapeEvent(e) && valueOrHandler(config.escapeDeactivates) !== false) { + if (isEscapeEvent(e) && valueOrHandler(config.escapeDeactivates, e) !== false) { e.preventDefault(); trap.deactivate(); return; @@ -473,10 +635,11 @@ var createFocusTrap = function createFocusTrap2(elements, userOptions) { } }; var checkClick = function checkClick2(e) { - if (valueOrHandler(config.clickOutsideDeactivates, e)) { + var target = getActualTarget(e); + if (findContainerIndex(target) >= 0) { return; } - if (containersContain(e.target)) { + if (valueOrHandler(config.clickOutsideDeactivates, e)) { return; } if (valueOrHandler(config.allowOutsideClick, e)) { @@ -524,6 +687,12 @@ var createFocusTrap = function createFocusTrap2(elements, userOptions) { return trap; }; trap = { + get active() { + return state.active; + }, + get paused() { + return state.paused; + }, activate: function activate(activateOptions) { if (state.active) { return this; @@ -560,19 +729,24 @@ var createFocusTrap = function createFocusTrap2(elements, userOptions) { if (!state.active) { return this; } + var options = _objectSpread2({ + onDeactivate: config.onDeactivate, + onPostDeactivate: config.onPostDeactivate, + checkCanReturnFocus: config.checkCanReturnFocus + }, deactivateOptions); clearTimeout(state.delayInitialFocusTimer); state.delayInitialFocusTimer = void 0; removeListeners(); state.active = false; state.paused = false; activeFocusTraps.deactivateTrap(trap); - var onDeactivate = getOption(deactivateOptions, "onDeactivate"); - var onPostDeactivate = getOption(deactivateOptions, "onPostDeactivate"); - var checkCanReturnFocus = getOption(deactivateOptions, "checkCanReturnFocus"); + var onDeactivate = getOption(options, "onDeactivate"); + var onPostDeactivate = getOption(options, "onPostDeactivate"); + var checkCanReturnFocus = getOption(options, "checkCanReturnFocus"); + var returnFocus = getOption(options, "returnFocus", "returnFocusOnDeactivate"); if (onDeactivate) { onDeactivate(); } - var returnFocus = getOption(deactivateOptions, "returnFocus", "returnFocusOnDeactivate"); var finishDeactivation = function finishDeactivation2() { delay(function() { if (returnFocus) { @@ -669,7 +843,7 @@ function src_default(Alpine) { focusables() { if (Array.isArray(within)) return within; - return focusable(within, {displayCheck: "none"}); + return focusable(within, { displayCheck: "none" }); }, all() { return this.focusables(); @@ -729,57 +903,66 @@ function src_default(Alpine) { setTimeout(() => { if (!el2.hasAttribute("tabindex")) el2.setAttribute("tabindex", "0"); - el2.focus({preventScroll: this._noscroll}); + el2.focus({ preventScroll: this._noscroll }); }); } }; }); - Alpine.directive("trap", Alpine.skipDuringClone((el, {expression, modifiers}, {effect, evaluateLater, cleanup}) => { - let evaluator = evaluateLater(expression); - let oldValue = false; - let trap = createFocusTrap(el, { - escapeDeactivates: false, - allowOutsideClick: true, - fallbackFocus: () => el, - initialFocus: el.querySelector("[autofocus]") - }); - let undoInert = () => { - }; - let undoDisableScrolling = () => { - }; - const releaseFocus = () => { - undoInert(); - undoInert = () => { + Alpine.directive("trap", Alpine.skipDuringClone( + (el, { expression, modifiers }, { effect, evaluateLater, cleanup }) => { + let evaluator = evaluateLater(expression); + let oldValue = false; + let options = { + escapeDeactivates: false, + allowOutsideClick: true, + fallbackFocus: () => el }; - undoDisableScrolling(); - undoDisableScrolling = () => { + let autofocusEl = el.querySelector("[autofocus]"); + if (autofocusEl) + options.initialFocus = autofocusEl; + let trap = createFocusTrap(el, options); + let undoInert = () => { }; - trap.deactivate({ - returnFocus: !modifiers.includes("noreturn") - }); - }; - effect(() => evaluator((value) => { - if (oldValue === value) - return; - if (value && !oldValue) { - setTimeout(() => { - if (modifiers.includes("inert")) - undoInert = setInert(el); - if (modifiers.includes("noscroll")) - undoDisableScrolling = disableScrolling(); - trap.activate(); + let undoDisableScrolling = () => { + }; + const releaseFocus = () => { + undoInert(); + undoInert = () => { + }; + undoDisableScrolling(); + undoDisableScrolling = () => { + }; + trap.deactivate({ + returnFocus: !modifiers.includes("noreturn") }); - } - if (!value && oldValue) { - releaseFocus(); - } - oldValue = !!value; - })); - cleanup(releaseFocus); - }, (el, {expression, modifiers}, {evaluate}) => { - if (modifiers.includes("inert") && evaluate(expression)) - setInert(el); - })); + }; + effect(() => evaluator((value) => { + if (oldValue === value) + return; + if (value && !oldValue) { + setTimeout(() => { + if (modifiers.includes("inert")) + undoInert = setInert(el); + if (modifiers.includes("noscroll")) + undoDisableScrolling = disableScrolling(); + trap.activate(); + }); + } + if (!value && oldValue) { + releaseFocus(); + } + oldValue = !!value; + })); + cleanup(releaseFocus); + }, + // When cloning, we only want to add aria-hidden attributes to the + // DOM and not try to actually trap, as trapping can mess with the + // live DOM and isn't just isolated to the cloned DOM. + (el, { expression, modifiers }, { evaluate }) => { + if (modifiers.includes("inert") && evaluate(expression)) + setInert(el); + } + )); } function setInert(el) { let undos = []; @@ -797,9 +980,11 @@ function crawlSiblingsUp(el, callback) { if (el.isSameNode(document.body) || !el.parentNode) return; Array.from(el.parentNode.children).forEach((sibling) => { - if (!sibling.isSameNode(el)) + if (sibling.isSameNode(el)) { + crawlSiblingsUp(el.parentNode, callback); + } else { callback(sibling); - crawlSiblingsUp(el.parentNode, callback); + } }); } function disableScrolling() { @@ -819,3 +1004,17 @@ var module_default = src_default; export { module_default as default }; +/*! Bundled license information: + +tabbable/dist/index.esm.js: + (*! + * tabbable 5.3.3 + * @license MIT, https://github.com/focus-trap/tabbable/blob/master/LICENSE + *) + +focus-trap/dist/focus-trap.esm.js: + (*! + * focus-trap 6.9.4 + * @license MIT, https://github.com/focus-trap/focus-trap/blob/master/LICENSE + *) +*/ diff --git a/alpinejs/packages/focus/package.json b/alpinejs/packages/focus/package.json index 476b983..7979fe9 100644 --- a/alpinejs/packages/focus/package.json +++ b/alpinejs/packages/focus/package.json @@ -1,13 +1,20 @@ { "name": "@alpinejs/focus", - "version": "3.10.3", + "version": "3.13.1", "description": "Manage focus within a page", + "homepage": "https://alpinejs.dev/plugins/focus", + "repository": { + "type": "git", + "url": "https://github.com/alpinejs/alpine.git", + "directory": "packages/focus" + }, "author": "Caleb Porzio", "license": "MIT", "main": "dist/module.cjs.js", "module": "dist/module.esm.js", "unpkg": "dist/cdn.min.js", "dependencies": { - "focus-trap": "^6.6.1" + "focus-trap": "^6.9.4", + "tabbable": "^5.3.3" } } diff --git a/alpinejs/packages/focus/src/index.js b/alpinejs/packages/focus/src/index.js index 01c8c07..74cf9e1 100644 --- a/alpinejs/packages/focus/src/index.js +++ b/alpinejs/packages/focus/src/index.js @@ -102,12 +102,17 @@ export default function (Alpine) { let oldValue = false - let trap = createFocusTrap(el, { + let options = { escapeDeactivates: false, allowOutsideClick: true, fallbackFocus: () => el, - initialFocus: el.querySelector('[autofocus]') - }) + } + + let autofocusEl = el.querySelector('[autofocus]') + + if (autofocusEl) options.initialFocus = autofocusEl + + let trap = createFocusTrap(el, options) let undoInert = () => {} let undoDisableScrolling = () => {} @@ -176,9 +181,11 @@ function crawlSiblingsUp(el, callback) { if (el.isSameNode(document.body) || ! el.parentNode) return Array.from(el.parentNode.children).forEach(sibling => { - if (! sibling.isSameNode(el)) callback(sibling) - - crawlSiblingsUp(el.parentNode, callback) + if (sibling.isSameNode(el)) { + crawlSiblingsUp(el.parentNode, callback) + } else { + callback(sibling) + } }) } diff --git a/alpinejs/packages/history/builds/module.js b/alpinejs/packages/history/builds/module.js index a7d9aba..122f73e 100644 --- a/alpinejs/packages/history/builds/module.js +++ b/alpinejs/packages/history/builds/module.js @@ -1,3 +1,5 @@ import history from '../src/index.js' +import { track } from '../src/index.js' export default history +export { track } diff --git a/alpinejs/packages/history/package.json b/alpinejs/packages/history/package.json index 08355c2..924ff48 100644 --- a/alpinejs/packages/history/package.json +++ b/alpinejs/packages/history/package.json @@ -2,6 +2,12 @@ "name": "@alpinejs/history", "version": "3.0.0-alpha.0", "description": "Sync Alpine data with the browser's query string", + "homepage": "https://alpinejs.dev/", + "repository": { + "type": "git", + "url": "https://github.com/alpinejs/alpine.git", + "directory": "packages/history" + }, "author": "Caleb Porzio", "license": "MIT", "main": "dist/module.cjs.js", diff --git a/alpinejs/packages/history/src/index.js b/alpinejs/packages/history/src/index.js index f230d80..d08ca39 100644 --- a/alpinejs/packages/history/src/index.js +++ b/alpinejs/packages/history/src/index.js @@ -1,76 +1 @@ -export default function history(Alpine) { - Alpine.magic('queryString', (el, { interceptor }) => { - let alias - - return interceptor((initialValue, getter, setter, path, key) => { - let pause = false - let queryKey = alias || path - - let value = initialValue - let url = new URL(window.location.href) - - if (url.searchParams.has(queryKey)) { - value = url.searchParams.get(queryKey) - } - - setter(value) - - let object = { value } - - url.searchParams.set(queryKey, value) - - replace(url.toString(), path, object) - - window.addEventListener('popstate', (e) => { - if (! e.state) return - if (! e.state.alpine) return - - Object.entries(e.state.alpine).forEach(([newKey, { value }]) => { - if (newKey !== key) return - - pause = true - - Alpine.disableEffectScheduling(() => { - setter(value) - }) - - pause = false - }) - }) - - Alpine.effect(() => { - let value = getter() - - if (pause) return - - let object = { value } - - let url = new URL(window.location.href) - - url.searchParams.set(queryKey, value) - - push(url.toString(), path, object) - }) - - return value - }, func => { - func.as = key => { alias = key; return func } - }) - }) -} - -function replace(url, key, object) { - let state = window.history.state || {} - - if (! state.alpine) state.alpine = {} - - state.alpine[key] = object - - window.history.replaceState(state, '', url) -} - -function push(url, key, object) { - let state = { alpine: {...window.history.state.alpine, ...{[key]: object}} } - - window.history.pushState(state, '', url) -} +// This plugin has been moved into the livewire/livewire repository until it's more stable and ready to tag. diff --git a/alpinejs/packages/history/src/url.js b/alpinejs/packages/history/src/url.js deleted file mode 100644 index 7e2b4b6..0000000 --- a/alpinejs/packages/history/src/url.js +++ /dev/null @@ -1,36 +0,0 @@ - -export function hasQueryParam(param) { - let queryParams = new URLSearchParams(window.location.search); - - return queryParams.has(param) -} - -export function getQueryParam(param) { - let queryParams = new URLSearchParams(window.location.search); - - return queryParams.get(param) -} - -export function setQueryParam(param, value) { - let queryParams = new URLSearchParams(window.location.search); - - queryParams.set(param, value) - - let url = urlFromQueryParams(queryParams) - - history.replaceState(history.state, '', url) -} - -function urlFromParams(params = {}) { - let queryParams = new URLSearchParams(window.location.search); - - Object.entries(params).forEach(([key, value]) => { - queryParams.set(key, value) - }) - - let queryString = Array.from(queryParams.entries()).length > 0 - ? '?'+params.toString() - : '' - - return window.location.origin + window.location.pathname + '?'+queryString + window.location.hash -} diff --git a/alpinejs/packages/intersect/dist/cdn.js b/alpinejs/packages/intersect/dist/cdn.js index 9257505..1568163 100644 --- a/alpinejs/packages/intersect/dist/cdn.js +++ b/alpinejs/packages/intersect/dist/cdn.js @@ -1,11 +1,11 @@ (() => { // packages/intersect/src/index.js function src_default(Alpine) { - Alpine.directive("intersect", (el, {value, expression, modifiers}, {evaluateLater, cleanup}) => { + Alpine.directive("intersect", (el, { value, expression, modifiers }, { evaluateLater, cleanup }) => { let evaluate = evaluateLater(expression); let options = { rootMargin: getRootMargin(modifiers), - threshold: getThreshhold(modifiers) + threshold: getThreshold(modifiers) }; let observer = new IntersectionObserver((entries) => { entries.forEach((entry) => { @@ -21,7 +21,7 @@ }); }); } - function getThreshhold(modifiers) { + function getThreshold(modifiers) { if (modifiers.includes("full")) return 0.99; if (modifiers.includes("half")) diff --git a/alpinejs/packages/intersect/dist/cdn.min.js b/alpinejs/packages/intersect/dist/cdn.min.js index b049f57..028e85b 100644 --- a/alpinejs/packages/intersect/dist/cdn.min.js +++ b/alpinejs/packages/intersect/dist/cdn.min.js @@ -1 +1 @@ -(()=>{function c(e){e.directive("intersect",(t,{value:i,expression:l,modifiers:n},{evaluateLater:r,cleanup:o})=>{let s=r(l),d={rootMargin:p(n),threshold:f(n)},u=new IntersectionObserver(h=>{h.forEach(a=>{a.isIntersecting!==(i==="leave")&&(s(),n.includes("once")&&u.disconnect())})},d);u.observe(t),o(()=>{u.disconnect()})})}function f(e){if(e.includes("full"))return .99;if(e.includes("half"))return .5;if(!e.includes("threshold"))return 0;let t=e[e.indexOf("threshold")+1];return t==="100"?1:t==="0"?0:Number(`.${t}`)}function x(e){let t=e.match(/^(-?[0-9]+)(px|%)?$/);return t?t[1]+(t[2]||"px"):void 0}function p(e){let t="margin",i="0px 0px 0px 0px",l=e.indexOf(t);if(l===-1)return i;let n=[];for(let r=1;r<5;r++)n.push(x(e[l+r]||""));return n=n.filter(r=>r!==void 0),n.length?n.join(" ").trim():i}document.addEventListener("alpine:init",()=>{window.Alpine.plugin(c)});})(); +(()=>{function o(e){e.directive("intersect",(t,{value:i,expression:l,modifiers:n},{evaluateLater:r,cleanup:c})=>{let s=r(l),a={rootMargin:x(n),threshold:f(n)},u=new IntersectionObserver(d=>{d.forEach(h=>{h.isIntersecting!==(i==="leave")&&(s(),n.includes("once")&&u.disconnect())})},a);u.observe(t),c(()=>{u.disconnect()})})}function f(e){if(e.includes("full"))return .99;if(e.includes("half"))return .5;if(!e.includes("threshold"))return 0;let t=e[e.indexOf("threshold")+1];return t==="100"?1:t==="0"?0:Number(`.${t}`)}function p(e){let t=e.match(/^(-?[0-9]+)(px|%)?$/);return t?t[1]+(t[2]||"px"):void 0}function x(e){let t="margin",i="0px 0px 0px 0px",l=e.indexOf(t);if(l===-1)return i;let n=[];for(let r=1;r<5;r++)n.push(p(e[l+r]||""));return n=n.filter(r=>r!==void 0),n.length?n.join(" ").trim():i}document.addEventListener("alpine:init",()=>{window.Alpine.plugin(o)});})(); diff --git a/alpinejs/packages/intersect/dist/module.cjs.js b/alpinejs/packages/intersect/dist/module.cjs.js index 71f5c47..792ad1c 100644 --- a/alpinejs/packages/intersect/dist/module.cjs.js +++ b/alpinejs/packages/intersect/dist/module.cjs.js @@ -1,23 +1,35 @@ var __defProp = Object.defineProperty; -var __markAsModule = (target) => __defProp(target, "__esModule", {value: true}); +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) - __defProp(target, name, {get: all[name], enumerable: true}); + __defProp(target, name, { get: all[name], enumerable: true }); }; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // packages/intersect/builds/module.js -__markAsModule(exports); -__export(exports, { +var module_exports = {}; +__export(module_exports, { default: () => module_default }); +module.exports = __toCommonJS(module_exports); // packages/intersect/src/index.js function src_default(Alpine) { - Alpine.directive("intersect", (el, {value, expression, modifiers}, {evaluateLater, cleanup}) => { + Alpine.directive("intersect", (el, { value, expression, modifiers }, { evaluateLater, cleanup }) => { let evaluate = evaluateLater(expression); let options = { rootMargin: getRootMargin(modifiers), - threshold: getThreshhold(modifiers) + threshold: getThreshold(modifiers) }; let observer = new IntersectionObserver((entries) => { entries.forEach((entry) => { @@ -33,7 +45,7 @@ function src_default(Alpine) { }); }); } -function getThreshhold(modifiers) { +function getThreshold(modifiers) { if (modifiers.includes("full")) return 0.99; if (modifiers.includes("half")) @@ -67,3 +79,5 @@ function getRootMargin(modifiers) { // packages/intersect/builds/module.js var module_default = src_default; +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = {}); diff --git a/alpinejs/packages/intersect/dist/module.esm.js b/alpinejs/packages/intersect/dist/module.esm.js index 2ed0c3e..75c8b60 100644 --- a/alpinejs/packages/intersect/dist/module.esm.js +++ b/alpinejs/packages/intersect/dist/module.esm.js @@ -1,10 +1,10 @@ // packages/intersect/src/index.js function src_default(Alpine) { - Alpine.directive("intersect", (el, {value, expression, modifiers}, {evaluateLater, cleanup}) => { + Alpine.directive("intersect", (el, { value, expression, modifiers }, { evaluateLater, cleanup }) => { let evaluate = evaluateLater(expression); let options = { rootMargin: getRootMargin(modifiers), - threshold: getThreshhold(modifiers) + threshold: getThreshold(modifiers) }; let observer = new IntersectionObserver((entries) => { entries.forEach((entry) => { @@ -20,7 +20,7 @@ function src_default(Alpine) { }); }); } -function getThreshhold(modifiers) { +function getThreshold(modifiers) { if (modifiers.includes("full")) return 0.99; if (modifiers.includes("half")) diff --git a/alpinejs/packages/intersect/package.json b/alpinejs/packages/intersect/package.json index 6e5aa3c..c733970 100644 --- a/alpinejs/packages/intersect/package.json +++ b/alpinejs/packages/intersect/package.json @@ -1,7 +1,13 @@ { "name": "@alpinejs/intersect", - "version": "3.10.3", + "version": "3.13.1", "description": "Trigger JavaScript when an element enters the viewport", + "homepage": "https://alpinejs.dev/plugins/intersect", + "repository": { + "type": "git", + "url": "https://github.com/alpinejs/alpine.git", + "directory": "packages/intersect" + }, "author": "Caleb Porzio", "license": "MIT", "main": "dist/module.cjs.js", diff --git a/alpinejs/packages/intersect/src/index.js b/alpinejs/packages/intersect/src/index.js index 0880258..5a4c89e 100644 --- a/alpinejs/packages/intersect/src/index.js +++ b/alpinejs/packages/intersect/src/index.js @@ -4,7 +4,7 @@ export default function (Alpine) { let options = { rootMargin: getRootMargin(modifiers), - threshold: getThreshhold(modifiers), + threshold: getThreshold(modifiers), } let observer = new IntersectionObserver(entries => { @@ -26,7 +26,7 @@ export default function (Alpine) { }) } -function getThreshhold(modifiers) { +function getThreshold(modifiers) { if (modifiers.includes('full')) return 0.99 if (modifiers.includes('half')) return 0.5 if (! modifiers.includes('threshold')) return 0 diff --git a/alpinejs/packages/mask/dist/cdn.js b/alpinejs/packages/mask/dist/cdn.js index 65785cf..7e2e6d6 100644 --- a/alpinejs/packages/mask/dist/cdn.js +++ b/alpinejs/packages/mask/dist/cdn.js @@ -1,29 +1,34 @@ (() => { // packages/mask/src/index.js function src_default(Alpine) { - Alpine.directive("mask", (el, {value, expression}, {effect, evaluateLater}) => { + Alpine.directive("mask", (el, { value, expression }, { effect, evaluateLater }) => { let templateFn = () => expression; let lastInputValue = ""; - if (["function", "dynamic"].includes(value)) { - let evaluator = evaluateLater(expression); - effect(() => { - templateFn = (input) => { - let result; - Alpine.dontAutoEvaluateFunctions(() => { - evaluator((value2) => { - result = typeof value2 === "function" ? value2(input) : value2; - }, {scope: { - $input: input, - $money: formatMoney.bind({el}) - }}); - }); - return result; - }; - processInputValue(el); - }); - } else { - processInputValue(el); - } + queueMicrotask(() => { + if (["function", "dynamic"].includes(value)) { + let evaluator = evaluateLater(expression); + effect(() => { + templateFn = (input) => { + let result; + Alpine.dontAutoEvaluateFunctions(() => { + evaluator((value2) => { + result = typeof value2 === "function" ? value2(input) : value2; + }, { scope: { + // These are "magics" we'll make available to the x-mask:function: + "$input": input, + "$money": formatMoney.bind({ el }) + } }); + }); + return result; + }; + processInputValue(el, false); + }); + } else { + processInputValue(el, false); + } + if (el._x_model) + el._x_model.set(el.value); + }); el.addEventListener("input", () => processInputValue(el)); el.addEventListener("blur", () => processInputValue(el, false)); function processInputValue(el2, shouldRestoreCursor = true) { @@ -52,14 +57,20 @@ let rebuiltInput = buildUp(template, strippedDownInput); return rebuiltInput; } - }); + }).before("model"); } function restoreCursorPosition(el, template, callback) { let cursorPosition = el.selectionStart; let unformattedValue = el.value; callback(); let beforeLeftOfCursorBeforeFormatting = unformattedValue.slice(0, cursorPosition); - let newPosition = buildUp(template, stripDown(template, beforeLeftOfCursorBeforeFormatting)).length; + let newPosition = buildUp( + template, + stripDown( + template, + beforeLeftOfCursorBeforeFormatting + ) + ).length; el.setSelectionRange(newPosition, newPosition); } function stripDown(template, input) { @@ -67,7 +78,7 @@ let output = ""; let regexes = { "9": /[0-9]/, - a: /[a-zA-Z]/, + "a": /[a-zA-Z]/, "*": /[a-zA-Z0-9]/ }; let wildcardTemplate = ""; @@ -112,8 +123,14 @@ } return output; } - function formatMoney(input, delimeter = ".", thousands) { - thousands = delimeter === "," && thousands === void 0 ? "." : ","; + function formatMoney(input, delimiter = ".", thousands, precision = 2) { + if (input === "-") + return "-"; + if (/^\D+$/.test(input)) + return "9"; + if (thousands === null || thousands === void 0) { + thousands = delimiter === "," ? "." : ","; + } let addThousands = (input2, thousands2) => { let output = ""; let counter = 0; @@ -130,15 +147,16 @@ } return output; }; - let strippedInput = input.replaceAll(new RegExp(`[^0-9\\${delimeter}]`, "g"), ""); - let template = Array.from({length: strippedInput.split(delimeter)[0].length}).fill("9").join(""); - template = addThousands(template, thousands); - if (input.includes(delimeter)) - template += `${delimeter}99`; + let minus = input.startsWith("-") ? "-" : ""; + let strippedInput = input.replaceAll(new RegExp(`[^0-9\\${delimiter}]`, "g"), ""); + let template = Array.from({ length: strippedInput.split(delimiter)[0].length }).fill("9").join(""); + template = `${minus}${addThousands(template, thousands)}`; + if (precision > 0 && input.includes(delimiter)) + template += `${delimiter}` + "9".repeat(precision); queueMicrotask(() => { - if (this.el.value.endsWith(delimeter)) + if (this.el.value.endsWith(delimiter)) return; - if (this.el.value[this.el.selectionStart - 1] === delimeter) { + if (this.el.value[this.el.selectionStart - 1] === delimiter) { this.el.setSelectionRange(this.el.selectionStart - 1, this.el.selectionStart - 1); } }); diff --git a/alpinejs/packages/mask/dist/cdn.min.js b/alpinejs/packages/mask/dist/cdn.min.js index e9f052c..1c4fcd7 100644 --- a/alpinejs/packages/mask/dist/cdn.min.js +++ b/alpinejs/packages/mask/dist/cdn.min.js @@ -1 +1 @@ -(()=>{function b(i){i.directive("mask",(t,{value:e,expression:o},{effect:s,evaluateLater:f})=>{let n=()=>o,u="";if(["function","dynamic"].includes(e)){let r=f(o);s(()=>{n=c=>{let p;return i.dontAutoEvaluateFunctions(()=>{r(a=>{p=typeof a=="function"?a(c):a},{scope:{$input:c,$money:k.bind({el:t})}})}),p},l(t)})}else l(t);t.addEventListener("input",()=>l(t)),t.addEventListener("blur",()=>l(t,!1));function l(r,c=!0){let p=r.value,a=n(p);if(!a||a==="false")return!1;if(u.length-r.value.length==1)return u=r.value;let g=()=>{u=r.value=d(p,a)};c?I(r,a,()=>{g()}):g()}function d(r,c){if(r==="")return"";let p=h(c,r);return v(c,p)}})}function I(i,t,e){let o=i.selectionStart,s=i.value;e();let f=s.slice(0,o),n=v(t,h(t,f)).length;i.setSelectionRange(n,n)}function h(i,t){let e=t,o="",s={"9":/[0-9]/,a:/[a-zA-Z]/,"*":/[a-zA-Z0-9]/},f="";for(let n=0;n{let l="",d=0;for(let r=n.length-1;r>=0;r--)n[r]!==u&&(d===3?(l=n[r]+u+l,d=0):l=n[r]+l,d++);return l},s=i.replaceAll(new RegExp(`[^0-9\\${t}]`,"g"),""),f=Array.from({length:s.split(t)[0].length}).fill("9").join("");return f=o(f,e),i.includes(t)&&(f+=`${t}99`),queueMicrotask(()=>{this.el.value.endsWith(t)||this.el.value[this.el.selectionStart-1]===t&&this.el.setSelectionRange(this.el.selectionStart-1,this.el.selectionStart-1)}),f}document.addEventListener("alpine:init",()=>{window.Alpine.plugin(b)});})(); +(()=>{function h(n){n.directive("mask",(e,{value:t,expression:u},{effect:s,evaluateLater:c})=>{let l=()=>u,r="";queueMicrotask(()=>{if(["function","dynamic"].includes(t)){let o=c(u);s(()=>{l=a=>{let f;return n.dontAutoEvaluateFunctions(()=>{o(d=>{f=typeof d=="function"?d(a):d},{scope:{$input:a,$money:m.bind({el:e})}})}),f},i(e,!1)})}else i(e,!1);e._x_model&&e._x_model.set(e.value)}),e.addEventListener("input",()=>i(e)),e.addEventListener("blur",()=>i(e,!1));function i(o,a=!0){let f=o.value,d=l(f);if(!d||d==="false")return!1;if(r.length-o.value.length===1)return r=o.value;let g=()=>{r=o.value=p(f,d)};a?k(o,d,()=>{g()}):g()}function p(o,a){if(o==="")return"";let f=v(a,o);return b(a,f)}}).before("model")}function k(n,e,t){let u=n.selectionStart,s=n.value;t();let c=s.slice(0,u),l=b(e,v(e,c)).length;n.setSelectionRange(l,l)}function v(n,e){let t=e,u="",s={9:/[0-9]/,a:/[a-zA-Z]/,"*":/[a-zA-Z0-9]/},c="";for(let l=0;l{let o="",a=0;for(let f=i.length-1;f>=0;f--)i[f]!==p&&(a===3?(o=i[f]+p+o,a=0):o=i[f]+o,a++);return o},c=n.startsWith("-")?"-":"",l=n.replaceAll(new RegExp(`[^0-9\\${e}]`,"g"),""),r=Array.from({length:l.split(e)[0].length}).fill("9").join("");return r=`${c}${s(r,t)}`,u>0&&n.includes(e)&&(r+=`${e}`+"9".repeat(u)),queueMicrotask(()=>{this.el.value.endsWith(e)||this.el.value[this.el.selectionStart-1]===e&&this.el.setSelectionRange(this.el.selectionStart-1,this.el.selectionStart-1)}),r}document.addEventListener("alpine:init",()=>{window.Alpine.plugin(h)});})(); diff --git a/alpinejs/packages/mask/dist/module.cjs.js b/alpinejs/packages/mask/dist/module.cjs.js index c8e14f4..c2cf950 100644 --- a/alpinejs/packages/mask/dist/module.cjs.js +++ b/alpinejs/packages/mask/dist/module.cjs.js @@ -1,42 +1,59 @@ var __defProp = Object.defineProperty; -var __markAsModule = (target) => __defProp(target, "__esModule", {value: true}); +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) - __defProp(target, name, {get: all[name], enumerable: true}); + __defProp(target, name, { get: all[name], enumerable: true }); }; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // packages/mask/builds/module.js -__markAsModule(exports); -__export(exports, { +var module_exports = {}; +__export(module_exports, { default: () => module_default, stripDown: () => stripDown }); +module.exports = __toCommonJS(module_exports); // packages/mask/src/index.js function src_default(Alpine) { - Alpine.directive("mask", (el, {value, expression}, {effect, evaluateLater}) => { + Alpine.directive("mask", (el, { value, expression }, { effect, evaluateLater }) => { let templateFn = () => expression; let lastInputValue = ""; - if (["function", "dynamic"].includes(value)) { - let evaluator = evaluateLater(expression); - effect(() => { - templateFn = (input) => { - let result; - Alpine.dontAutoEvaluateFunctions(() => { - evaluator((value2) => { - result = typeof value2 === "function" ? value2(input) : value2; - }, {scope: { - $input: input, - $money: formatMoney.bind({el}) - }}); - }); - return result; - }; - processInputValue(el); - }); - } else { - processInputValue(el); - } + queueMicrotask(() => { + if (["function", "dynamic"].includes(value)) { + let evaluator = evaluateLater(expression); + effect(() => { + templateFn = (input) => { + let result; + Alpine.dontAutoEvaluateFunctions(() => { + evaluator((value2) => { + result = typeof value2 === "function" ? value2(input) : value2; + }, { scope: { + // These are "magics" we'll make available to the x-mask:function: + "$input": input, + "$money": formatMoney.bind({ el }) + } }); + }); + return result; + }; + processInputValue(el, false); + }); + } else { + processInputValue(el, false); + } + if (el._x_model) + el._x_model.set(el.value); + }); el.addEventListener("input", () => processInputValue(el)); el.addEventListener("blur", () => processInputValue(el, false)); function processInputValue(el2, shouldRestoreCursor = true) { @@ -65,14 +82,20 @@ function src_default(Alpine) { let rebuiltInput = buildUp(template, strippedDownInput); return rebuiltInput; } - }); + }).before("model"); } function restoreCursorPosition(el, template, callback) { let cursorPosition = el.selectionStart; let unformattedValue = el.value; callback(); let beforeLeftOfCursorBeforeFormatting = unformattedValue.slice(0, cursorPosition); - let newPosition = buildUp(template, stripDown(template, beforeLeftOfCursorBeforeFormatting)).length; + let newPosition = buildUp( + template, + stripDown( + template, + beforeLeftOfCursorBeforeFormatting + ) + ).length; el.setSelectionRange(newPosition, newPosition); } function stripDown(template, input) { @@ -80,7 +103,7 @@ function stripDown(template, input) { let output = ""; let regexes = { "9": /[0-9]/, - a: /[a-zA-Z]/, + "a": /[a-zA-Z]/, "*": /[a-zA-Z0-9]/ }; let wildcardTemplate = ""; @@ -125,8 +148,14 @@ function buildUp(template, input) { } return output; } -function formatMoney(input, delimeter = ".", thousands) { - thousands = delimeter === "," && thousands === void 0 ? "." : ","; +function formatMoney(input, delimiter = ".", thousands, precision = 2) { + if (input === "-") + return "-"; + if (/^\D+$/.test(input)) + return "9"; + if (thousands === null || thousands === void 0) { + thousands = delimiter === "," ? "." : ","; + } let addThousands = (input2, thousands2) => { let output = ""; let counter = 0; @@ -143,15 +172,16 @@ function formatMoney(input, delimeter = ".", thousands) { } return output; }; - let strippedInput = input.replaceAll(new RegExp(`[^0-9\\${delimeter}]`, "g"), ""); - let template = Array.from({length: strippedInput.split(delimeter)[0].length}).fill("9").join(""); - template = addThousands(template, thousands); - if (input.includes(delimeter)) - template += `${delimeter}99`; + let minus = input.startsWith("-") ? "-" : ""; + let strippedInput = input.replaceAll(new RegExp(`[^0-9\\${delimiter}]`, "g"), ""); + let template = Array.from({ length: strippedInput.split(delimiter)[0].length }).fill("9").join(""); + template = `${minus}${addThousands(template, thousands)}`; + if (precision > 0 && input.includes(delimiter)) + template += `${delimiter}` + "9".repeat(precision); queueMicrotask(() => { - if (this.el.value.endsWith(delimeter)) + if (this.el.value.endsWith(delimiter)) return; - if (this.el.value[this.el.selectionStart - 1] === delimeter) { + if (this.el.value[this.el.selectionStart - 1] === delimiter) { this.el.setSelectionRange(this.el.selectionStart - 1, this.el.selectionStart - 1); } }); @@ -160,3 +190,7 @@ function formatMoney(input, delimeter = ".", thousands) { // packages/mask/builds/module.js var module_default = src_default; +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + stripDown +}); diff --git a/alpinejs/packages/mask/dist/module.esm.js b/alpinejs/packages/mask/dist/module.esm.js index f7fc100..e2bc0ba 100644 --- a/alpinejs/packages/mask/dist/module.esm.js +++ b/alpinejs/packages/mask/dist/module.esm.js @@ -1,28 +1,33 @@ // packages/mask/src/index.js function src_default(Alpine) { - Alpine.directive("mask", (el, {value, expression}, {effect, evaluateLater}) => { + Alpine.directive("mask", (el, { value, expression }, { effect, evaluateLater }) => { let templateFn = () => expression; let lastInputValue = ""; - if (["function", "dynamic"].includes(value)) { - let evaluator = evaluateLater(expression); - effect(() => { - templateFn = (input) => { - let result; - Alpine.dontAutoEvaluateFunctions(() => { - evaluator((value2) => { - result = typeof value2 === "function" ? value2(input) : value2; - }, {scope: { - $input: input, - $money: formatMoney.bind({el}) - }}); - }); - return result; - }; - processInputValue(el); - }); - } else { - processInputValue(el); - } + queueMicrotask(() => { + if (["function", "dynamic"].includes(value)) { + let evaluator = evaluateLater(expression); + effect(() => { + templateFn = (input) => { + let result; + Alpine.dontAutoEvaluateFunctions(() => { + evaluator((value2) => { + result = typeof value2 === "function" ? value2(input) : value2; + }, { scope: { + // These are "magics" we'll make available to the x-mask:function: + "$input": input, + "$money": formatMoney.bind({ el }) + } }); + }); + return result; + }; + processInputValue(el, false); + }); + } else { + processInputValue(el, false); + } + if (el._x_model) + el._x_model.set(el.value); + }); el.addEventListener("input", () => processInputValue(el)); el.addEventListener("blur", () => processInputValue(el, false)); function processInputValue(el2, shouldRestoreCursor = true) { @@ -51,14 +56,20 @@ function src_default(Alpine) { let rebuiltInput = buildUp(template, strippedDownInput); return rebuiltInput; } - }); + }).before("model"); } function restoreCursorPosition(el, template, callback) { let cursorPosition = el.selectionStart; let unformattedValue = el.value; callback(); let beforeLeftOfCursorBeforeFormatting = unformattedValue.slice(0, cursorPosition); - let newPosition = buildUp(template, stripDown(template, beforeLeftOfCursorBeforeFormatting)).length; + let newPosition = buildUp( + template, + stripDown( + template, + beforeLeftOfCursorBeforeFormatting + ) + ).length; el.setSelectionRange(newPosition, newPosition); } function stripDown(template, input) { @@ -66,7 +77,7 @@ function stripDown(template, input) { let output = ""; let regexes = { "9": /[0-9]/, - a: /[a-zA-Z]/, + "a": /[a-zA-Z]/, "*": /[a-zA-Z0-9]/ }; let wildcardTemplate = ""; @@ -111,8 +122,14 @@ function buildUp(template, input) { } return output; } -function formatMoney(input, delimeter = ".", thousands) { - thousands = delimeter === "," && thousands === void 0 ? "." : ","; +function formatMoney(input, delimiter = ".", thousands, precision = 2) { + if (input === "-") + return "-"; + if (/^\D+$/.test(input)) + return "9"; + if (thousands === null || thousands === void 0) { + thousands = delimiter === "," ? "." : ","; + } let addThousands = (input2, thousands2) => { let output = ""; let counter = 0; @@ -129,15 +146,16 @@ function formatMoney(input, delimeter = ".", thousands) { } return output; }; - let strippedInput = input.replaceAll(new RegExp(`[^0-9\\${delimeter}]`, "g"), ""); - let template = Array.from({length: strippedInput.split(delimeter)[0].length}).fill("9").join(""); - template = addThousands(template, thousands); - if (input.includes(delimeter)) - template += `${delimeter}99`; + let minus = input.startsWith("-") ? "-" : ""; + let strippedInput = input.replaceAll(new RegExp(`[^0-9\\${delimiter}]`, "g"), ""); + let template = Array.from({ length: strippedInput.split(delimiter)[0].length }).fill("9").join(""); + template = `${minus}${addThousands(template, thousands)}`; + if (precision > 0 && input.includes(delimiter)) + template += `${delimiter}` + "9".repeat(precision); queueMicrotask(() => { - if (this.el.value.endsWith(delimeter)) + if (this.el.value.endsWith(delimiter)) return; - if (this.el.value[this.el.selectionStart - 1] === delimeter) { + if (this.el.value[this.el.selectionStart - 1] === delimiter) { this.el.setSelectionRange(this.el.selectionStart - 1, this.el.selectionStart - 1); } }); diff --git a/alpinejs/packages/mask/package.json b/alpinejs/packages/mask/package.json index 9a1b7f9..dbfd497 100644 --- a/alpinejs/packages/mask/package.json +++ b/alpinejs/packages/mask/package.json @@ -1,7 +1,13 @@ { "name": "@alpinejs/mask", - "version": "3.10.3", + "version": "3.13.1", "description": "An Alpine plugin for input masking", + "homepage": "https://alpinejs.dev/plugins/mask", + "repository": { + "type": "git", + "url": "https://github.com/alpinejs/alpine.git", + "directory": "packages/mask" + }, "author": "Caleb Porzio", "license": "MIT", "main": "dist/module.cjs.js", diff --git a/alpinejs/packages/mask/src/index.js b/alpinejs/packages/mask/src/index.js index b73a258..818b1c5 100644 --- a/alpinejs/packages/mask/src/index.js +++ b/alpinejs/packages/mask/src/index.js @@ -4,39 +4,44 @@ export default function (Alpine) { let templateFn = () => expression let lastInputValue = '' - if (['function', 'dynamic'].includes(value)) { - // This is an x-mask:function directive. - - let evaluator = evaluateLater(expression) - - effect(() => { - templateFn = input => { - let result - - // We need to prevent "auto-evaluation" of functions like - // x-on expressions do so that we can use them as mask functions. - Alpine.dontAutoEvaluateFunctions(() => { - evaluator(value => { - result = typeof value === 'function' ? value(input) : value - }, { scope: { - // These are "magics" we'll make available to the x-mask:function: - '$input': input, - '$money': formatMoney.bind({ el }), - }}) - }) - - return result - } - - // Run on initialize which serves a dual purpose: - // - Initializing the mask on the input if it has an initial value. - // - Running the template function to set up reactivity, so that - // when a dependancy inside it changes, the input re-masks. - processInputValue(el) - }) - } else { - processInputValue(el) - } + queueMicrotask(() => { + if (['function', 'dynamic'].includes(value)) { + // This is an x-mask:function directive. + + let evaluator = evaluateLater(expression) + + effect(() => { + templateFn = input => { + let result + + // We need to prevent "auto-evaluation" of functions like + // x-on expressions do so that we can use them as mask functions. + Alpine.dontAutoEvaluateFunctions(() => { + evaluator(value => { + result = typeof value === 'function' ? value(input) : value + }, { scope: { + // These are "magics" we'll make available to the x-mask:function: + '$input': input, + '$money': formatMoney.bind({ el }), + }}) + }) + + return result + } + + // Run on initialize which serves a dual purpose: + // - Initializing the mask on the input if it has an initial value. + // - Running the template function to set up reactivity, so that + // when a dependency inside it changes, the input re-masks. + processInputValue(el, false) + }) + } else { + processInputValue(el, false) + } + + // Override x-model's initial value... + if (el._x_model) el._x_model.set(el.value) + }) el.addEventListener('input', () => processInputValue(el)) // Don't "restoreCursorPosition" on "blur", because Safari @@ -56,7 +61,9 @@ export default function (Alpine) { return lastInputValue = el.value } - let setInput = () => { lastInputValue = el.value = formatInput(input, template) } + let setInput = () => { + lastInputValue = el.value = formatInput(input, template) + } if (shouldRestoreCursor) { // When an input element's value is set, it moves the cursor to the end @@ -79,7 +86,7 @@ export default function (Alpine) { return rebuiltInput } - }) + }).before('model') } export function restoreCursorPosition(el, template, callback) { @@ -163,9 +170,13 @@ export function buildUp(template, input) { return output } -function formatMoney(input, delimeter = '.', thousands) { - thousands = (delimeter === ',' && thousands === undefined) - ? '.' : ',' +export function formatMoney(input, delimiter = '.', thousands, precision = 2) { + if (input === '-') return '-' + if (/^\D+$/.test(input)) return '9' + + if (thousands === null || thousands === undefined) { + thousands = delimiter === "," ? "." : "," + } let addThousands = (input, thousands) => { let output = '' @@ -186,17 +197,19 @@ function formatMoney(input, delimeter = '.', thousands) { return output } - let strippedInput = input.replaceAll(new RegExp(`[^0-9\\${delimeter}]`, 'g'), '') - let template = Array.from({ length: strippedInput.split(delimeter)[0].length }).fill('9').join('') + let minus = input.startsWith('-') ? '-' : '' + let strippedInput = input.replaceAll(new RegExp(`[^0-9\\${delimiter}]`, 'g'), '') + let template = Array.from({ length: strippedInput.split(delimiter)[0].length }).fill('9').join('') - template = addThousands(template, thousands) + template = `${minus}${addThousands(template, thousands)}` - if (input.includes(delimeter)) template += `${delimeter}99` + if (precision > 0 && input.includes(delimiter)) + template += `${delimiter}` + '9'.repeat(precision) queueMicrotask(() => { - if (this.el.value.endsWith(delimeter)) return + if (this.el.value.endsWith(delimiter)) return - if (this.el.value[this.el.selectionStart - 1] === delimeter) { + if (this.el.value[this.el.selectionStart - 1] === delimiter) { this.el.setSelectionRange(this.el.selectionStart - 1, this.el.selectionStart - 1) } }) diff --git a/alpinejs/packages/morph/dist/cdn.js b/alpinejs/packages/morph/dist/cdn.js index 3971815..f8b135b 100644 --- a/alpinejs/packages/morph/dist/cdn.js +++ b/alpinejs/packages/morph/dist/cdn.js @@ -1,83 +1,10 @@ (() => { - // packages/morph/src/dom.js - var DomManager = class { - el = void 0; - constructor(el) { - this.el = el; - } - traversals = { - first: "firstElementChild", - next: "nextElementSibling", - parent: "parentElement" - }; - nodes() { - this.traversals = { - first: "firstChild", - next: "nextSibling", - parent: "parentNode" - }; - return this; - } - first() { - return this.teleportTo(this.el[this.traversals["first"]]); - } - next() { - return this.teleportTo(this.teleportBack(this.el[this.traversals["next"]])); - } - before(insertee) { - this.el[this.traversals["parent"]].insertBefore(insertee, this.el); - return insertee; - } - replace(replacement) { - this.el[this.traversals["parent"]].replaceChild(replacement, this.el); - return replacement; - } - append(appendee) { - this.el.appendChild(appendee); - return appendee; - } - teleportTo(el) { - if (!el) - return el; - if (el._x_teleport) - return el._x_teleport; - return el; - } - teleportBack(el) { - if (!el) - return el; - if (el._x_teleportBack) - return el._x_teleportBack; - return el; - } - }; - function dom(el) { - return new DomManager(el); - } - function createElement(html) { - const template = document.createElement("template"); - template.innerHTML = html; - return template.content.firstElementChild; - } - function textOrComment(el) { - return el.nodeType === 3 || el.nodeType === 8; - } - // packages/morph/src/morph.js - var resolveStep = () => { - }; - var logger = () => { - }; - async function morph(from, toHtml, options) { + function morph(from, toHtml, options) { + monkeyPatchDomSetAttributeToAllowAtSymbols(); let fromEl; let toEl; - let key, lookahead, updating, updated, removing, removed, adding, added, debug; - function breakpoint(message) { - if (!debug) - return; - logger((message || "").replace("\n", "\\n"), fromEl, toEl); - return new Promise((resolve) => resolveStep = () => resolve()); - } + let key, lookahead, updating, updated, removing, removed, adding, added; function assignOptions(options2 = {}) { let defaultGetKey = (el) => el.getAttribute("key"); let noop = () => { @@ -90,50 +17,50 @@ added = options2.added || noop; key = options2.key || defaultGetKey; lookahead = options2.lookahead || false; - debug = options2.debug || false; } - async function patch(from2, to) { + function patch(from2, to) { if (differentElementNamesTypesOrKeys(from2, to)) { - let result = patchElement(from2, to); - await breakpoint("Swap elements"); - return result; + return swapElements(from2, to); } let updateChildrenOnly = false; if (shouldSkip(updating, from2, to, () => updateChildrenOnly = true)) return; - window.Alpine && initializeAlpineOnTo(from2, to, () => updateChildrenOnly = true); + if (from2.nodeType === 1 && window.Alpine) { + window.Alpine.cloneNode(from2, to); + } if (textOrComment(to)) { - await patchNodeValue(from2, to); + patchNodeValue(from2, to); updated(from2, to); return; } if (!updateChildrenOnly) { - await patchAttributes(from2, to); + patchAttributes(from2, to); } updated(from2, to); - await patchChildren(from2, to); + patchChildren(from2, to); } function differentElementNamesTypesOrKeys(from2, to) { return from2.nodeType != to.nodeType || from2.nodeName != to.nodeName || getKey(from2) != getKey(to); } - function patchElement(from2, to) { + function swapElements(from2, to) { if (shouldSkip(removing, from2)) return; let toCloned = to.cloneNode(true); if (shouldSkip(adding, toCloned)) return; - dom(from2).replace(toCloned); + from2.replaceWith(toCloned); removed(from2); added(toCloned); } - async function patchNodeValue(from2, to) { + function patchNodeValue(from2, to) { let value = to.nodeValue; if (from2.nodeValue !== value) { from2.nodeValue = value; - await breakpoint("Change text node to: " + value); } } - async function patchAttributes(from2, to) { + function patchAttributes(from2, to) { + if (from2._x_transitioning) + return; if (from2._x_isShown && !to._x_isShown) { return; } @@ -146,7 +73,6 @@ let name = domAttributes[i].name; if (!to.hasAttribute(name)) { from2.removeAttribute(name); - await breakpoint("Remove attribute"); } } for (let i = toAttributes.length - 1; i >= 0; i--) { @@ -154,95 +80,127 @@ let value = toAttributes[i].value; if (from2.getAttribute(name) !== value) { from2.setAttribute(name, value); - await breakpoint(`Set [${name}] attribute to: "${value}"`); } } } - async function patchChildren(from2, to) { - let domChildren = from2.childNodes; - let toChildren = to.childNodes; - let toKeyToNodeMap = keyToMap(toChildren); - let domKeyDomNodeMap = keyToMap(domChildren); - let currentTo = dom(to).nodes().first(); - let currentFrom = dom(from2).nodes().first(); - let domKeyHoldovers = {}; + function patchChildren(from2, to) { + let fromKeys = keyToMap(from2.children); + let fromKeyHoldovers = {}; + let currentTo = getFirstNode(to); + let currentFrom = getFirstNode(from2); while (currentTo) { let toKey = getKey(currentTo); - let domKey = getKey(currentFrom); + let fromKey = getKey(currentFrom); if (!currentFrom) { - if (toKey && domKeyHoldovers[toKey]) { - let holdover = domKeyHoldovers[toKey]; - dom(from2).append(holdover); + if (toKey && fromKeyHoldovers[toKey]) { + let holdover = fromKeyHoldovers[toKey]; + from2.appendChild(holdover); currentFrom = holdover; - await breakpoint("Add element (from key)"); } else { - let added2 = addNodeTo(currentTo, from2) || {}; - await breakpoint("Add element: " + (added2.outerHTML || added2.nodeValue)); - currentTo = dom(currentTo).nodes().next(); + if (!shouldSkip(adding, currentTo)) { + let clone = currentTo.cloneNode(true); + from2.appendChild(clone); + added(clone); + } + currentTo = getNextSibling(to, currentTo); continue; } } - if (lookahead) { - let nextToElementSibling = dom(currentTo).next(); + let isIf = (node) => node && node.nodeType === 8 && node.textContent === "[if BLOCK]> node && node.nodeType === 8 && node.textContent === "[if ENDBLOCK]> 0) { + nestedIfCount--; + } else if (isEnd(next) && nestedIfCount === 0) { + currentFrom = next; + break; + } + currentFrom = next; + } + let fromBlockEnd = currentFrom; + nestedIfCount = 0; + let toBlockStart = currentTo; + while (currentTo) { + let next = getNextSibling(to, currentTo); + if (isIf(next)) { + nestedIfCount++; + } else if (isEnd(next) && nestedIfCount > 0) { + nestedIfCount--; + } else if (isEnd(next) && nestedIfCount === 0) { + currentTo = next; + break; + } + currentTo = next; + } + let toBlockEnd = currentTo; + let fromBlock = new Block(fromBlockStart, fromBlockEnd); + let toBlock = new Block(toBlockStart, toBlockEnd); + patchChildren(fromBlock, toBlock); + continue; + } + if (currentFrom.nodeType === 1 && lookahead && !currentFrom.isEqualNode(currentTo)) { + let nextToElementSibling = getNextSibling(to, currentTo); let found = false; while (!found && nextToElementSibling) { - if (currentFrom.isEqualNode(nextToElementSibling)) { + if (nextToElementSibling.nodeType === 1 && currentFrom.isEqualNode(nextToElementSibling)) { found = true; - currentFrom = addNodeBefore(currentTo, currentFrom); - domKey = getKey(currentFrom); - await breakpoint("Move element (lookahead)"); + currentFrom = addNodeBefore(from2, currentTo, currentFrom); + fromKey = getKey(currentFrom); } - nextToElementSibling = dom(nextToElementSibling).next(); + nextToElementSibling = getNextSibling(to, nextToElementSibling); } } - if (toKey !== domKey) { - if (!toKey && domKey) { - domKeyHoldovers[domKey] = currentFrom; - currentFrom = addNodeBefore(currentTo, currentFrom); - domKeyHoldovers[domKey].remove(); - currentFrom = dom(currentFrom).nodes().next(); - currentTo = dom(currentTo).nodes().next(); - await breakpoint('No "to" key'); + if (toKey !== fromKey) { + if (!toKey && fromKey) { + fromKeyHoldovers[fromKey] = currentFrom; + currentFrom = addNodeBefore(from2, currentTo, currentFrom); + fromKeyHoldovers[fromKey].remove(); + currentFrom = getNextSibling(from2, currentFrom); + currentTo = getNextSibling(to, currentTo); continue; } - if (toKey && !domKey) { - if (domKeyDomNodeMap[toKey]) { - currentFrom = dom(currentFrom).replace(domKeyDomNodeMap[toKey]); - await breakpoint('No "from" key'); + if (toKey && !fromKey) { + if (fromKeys[toKey]) { + currentFrom.replaceWith(fromKeys[toKey]); + currentFrom = fromKeys[toKey]; } } - if (toKey && domKey) { - domKeyHoldovers[domKey] = currentFrom; - let domKeyNode = domKeyDomNodeMap[toKey]; - if (domKeyNode) { - currentFrom = dom(currentFrom).replace(domKeyNode); - await breakpoint('Move "from" key'); + if (toKey && fromKey) { + let fromKeyNode = fromKeys[toKey]; + if (fromKeyNode) { + fromKeyHoldovers[fromKey] = currentFrom; + currentFrom.replaceWith(fromKeyNode); + currentFrom = fromKeyNode; } else { - domKeyHoldovers[domKey] = currentFrom; - currentFrom = addNodeBefore(currentTo, currentFrom); - domKeyHoldovers[domKey].remove(); - currentFrom = dom(currentFrom).next(); - currentTo = dom(currentTo).next(); - await breakpoint("Swap elements with keys"); + fromKeyHoldovers[fromKey] = currentFrom; + currentFrom = addNodeBefore(from2, currentTo, currentFrom); + fromKeyHoldovers[fromKey].remove(); + currentFrom = getNextSibling(from2, currentFrom); + currentTo = getNextSibling(to, currentTo); continue; } } } - let currentFromNext = currentFrom && dom(currentFrom).nodes().next(); - await patch(currentFrom, currentTo); - currentTo = currentTo && dom(currentTo).nodes().next(); + let currentFromNext = currentFrom && getNextSibling(from2, currentFrom); + patch(currentFrom, currentTo); + currentTo = currentTo && getNextSibling(to, currentTo); currentFrom = currentFromNext; } let removals = []; while (currentFrom) { if (!shouldSkip(removing, currentFrom)) removals.push(currentFrom); - currentFrom = dom(currentFrom).nodes().next(); + currentFrom = getNextSibling(from2, currentFrom); } while (removals.length) { let domForRemoval = removals.shift(); domForRemoval.remove(); - await breakpoint("remove el"); removed(domForRemoval); } } @@ -251,60 +209,117 @@ } function keyToMap(els) { let map = {}; - els.forEach((el) => { + for (let el of els) { let theKey = getKey(el); if (theKey) { map[theKey] = el; } - }); - return map; - } - function addNodeTo(node, parent) { - if (!shouldSkip(adding, node)) { - let clone = node.cloneNode(true); - dom(parent).append(clone); - added(clone); - return clone; } - return null; + return map; } - function addNodeBefore(node, beforeMe) { + function addNodeBefore(parent, node, beforeMe) { if (!shouldSkip(adding, node)) { let clone = node.cloneNode(true); - dom(beforeMe).before(clone); + parent.insertBefore(clone, beforeMe); added(clone); return clone; } - return beforeMe; + return node; } assignOptions(options); fromEl = from; - toEl = createElement(toHtml); + toEl = typeof toHtml === "string" ? createElement(toHtml) : toHtml; if (window.Alpine && window.Alpine.closestDataStack && !from._x_dataStack) { toEl._x_dataStack = window.Alpine.closestDataStack(from); - toEl._x_dataStack && window.Alpine.clone(from, toEl); + toEl._x_dataStack && window.Alpine.cloneNode(from, toEl); } - await breakpoint(); - await patch(from, toEl); + patch(from, toEl); fromEl = void 0; toEl = void 0; return from; } - morph.step = () => resolveStep(); - morph.log = (theLogger) => { - logger = theLogger; + morph.step = () => { + }; + morph.log = () => { }; function shouldSkip(hook, ...args) { let skip = false; hook(...args, () => skip = true); return skip; } - function initializeAlpineOnTo(from, to, childrenOnly) { - if (from.nodeType !== 1) - return; - if (from._x_dataStack) { - window.Alpine.clone(from, to); + var patched = false; + function createElement(html) { + const template = document.createElement("template"); + template.innerHTML = html; + return template.content.firstElementChild; + } + function textOrComment(el) { + return el.nodeType === 3 || el.nodeType === 8; + } + var Block = class { + constructor(start, end) { + this.startComment = start; + this.endComment = end; } + get children() { + let children = []; + let currentNode = this.startComment.nextSibling; + while (currentNode && currentNode !== this.endComment) { + children.push(currentNode); + currentNode = currentNode.nextSibling; + } + return children; + } + appendChild(child) { + this.endComment.before(child); + } + get firstChild() { + let first = this.startComment.nextSibling; + if (first === this.endComment) + return; + return first; + } + nextNode(reference) { + let next = reference.nextSibling; + if (next === this.endComment) + return; + return next; + } + insertBefore(newNode, reference) { + reference.before(newNode); + return newNode; + } + }; + function getFirstNode(parent) { + return parent.firstChild; + } + function getNextSibling(parent, reference) { + if (reference._x_teleport) { + return reference._x_teleport; + } + let next; + if (parent instanceof Block) { + next = parent.nextNode(reference); + } else { + next = reference.nextSibling; + } + return next; + } + function monkeyPatchDomSetAttributeToAllowAtSymbols() { + if (patched) + return; + patched = true; + let original = Element.prototype.setAttribute; + let hostDiv = document.createElement("div"); + Element.prototype.setAttribute = function newSetAttribute(name, value) { + if (!name.includes("@")) { + return original.call(this, name, value); + } + hostDiv.innerHTML = ``; + let attr = hostDiv.firstElementChild.getAttributeNode(name); + hostDiv.firstElementChild.removeAttributeNode(attr); + this.setAttributeNode(attr); + }; } // packages/morph/src/index.js diff --git a/alpinejs/packages/morph/dist/cdn.min.js b/alpinejs/packages/morph/dist/cdn.min.js index 54a4944..ddd9ffb 100644 --- a/alpinejs/packages/morph/dist/cdn.min.js +++ b/alpinejs/packages/morph/dist/cdn.min.js @@ -1,2 +1 @@ -(()=>{var F=class{el=void 0;constructor(i){this.el=i}traversals={first:"firstElementChild",next:"nextElementSibling",parent:"parentElement"};nodes(){return this.traversals={first:"firstChild",next:"nextSibling",parent:"parentNode"},this}first(){return this.teleportTo(this.el[this.traversals.first])}next(){return this.teleportTo(this.teleportBack(this.el[this.traversals.next]))}before(i){return this.el[this.traversals.parent].insertBefore(i,this.el),i}replace(i){return this.el[this.traversals.parent].replaceChild(i,this.el),i}append(i){return this.el.appendChild(i),i}teleportTo(i){return i&&(i._x_teleport?i._x_teleport:i)}teleportBack(i){return i&&(i._x_teleportBack?i._x_teleportBack:i)}};function o(a){return new F(a)}function H(a){let i=document.createElement("template");return i.innerHTML=a,i.content.firstElementChild}function L(a){return a.nodeType===3||a.nodeType===8}var j=()=>{},R=()=>{};async function g(a,i,v){let A,m,C,K,O,b,N,S,k,_,B;function d(e){if(!!B)return R((e||"").replace(` -`,"\\n"),A,m),new Promise(t=>j=()=>t())}function q(e={}){let t=p=>p.getAttribute("key"),n=()=>{};O=e.updating||n,b=e.updated||n,N=e.removing||n,S=e.removed||n,k=e.adding||n,_=e.added||n,C=e.key||t,K=e.lookahead||!1,B=e.debug||!1}async function M(e,t){if(z(e,t)){let p=G(e,t);return await d("Swap elements"),p}let n=!1;if(!y(O,e,t,()=>n=!0)){if(window.Alpine&&W(e,t,()=>n=!0),L(t)){await P(e,t),b(e,t);return}n||await I(e,t),b(e,t),await J(e,t)}}function z(e,t){return e.nodeType!=t.nodeType||e.nodeName!=t.nodeName||x(e)!=x(t)}function G(e,t){if(y(N,e))return;let n=t.cloneNode(!0);y(k,n)||(o(e).replace(n),S(e),_(n))}async function P(e,t){let n=t.nodeValue;e.nodeValue!==n&&(e.nodeValue=n,await d("Change text node to: "+n))}async function I(e,t){if(e._x_isShown&&!t._x_isShown||!e._x_isShown&&t._x_isShown)return;let n=Array.from(e.attributes),p=Array.from(t.attributes);for(let h=n.length-1;h>=0;h--){let c=n[h].name;t.hasAttribute(c)||(e.removeAttribute(c),await d("Remove attribute"))}for(let h=p.length-1;h>=0;h--){let c=p[h].name,l=p[h].value;e.getAttribute(c)!==l&&(e.setAttribute(c,l),await d(`Set [${c}] attribute to: "${l}"`))}}async function J(e,t){let n=e.childNodes,p=t.childNodes,h=V(p),c=V(n),l=o(t).nodes().first(),r=o(e).nodes().first(),w={};for(;l;){let u=x(l),f=x(r);if(!r)if(u&&w[u]){let s=w[u];o(e).append(s),r=s,await d("Add element (from key)")}else{let s=Q(l,e)||{};await d("Add element: "+(s.outerHTML||s.nodeValue)),l=o(l).nodes().next();continue}if(K){let s=o(l).next(),D=!1;for(;!D&&s;)r.isEqualNode(s)&&(D=!0,r=T(l,r),f=x(r),await d("Move element (lookahead)")),s=o(s).next()}if(u!==f){if(!u&&f){w[f]=r,r=T(l,r),w[f].remove(),r=o(r).nodes().next(),l=o(l).nodes().next(),await d('No "to" key');continue}if(u&&!f&&c[u]&&(r=o(r).replace(c[u]),await d('No "from" key')),u&&f){w[f]=r;let s=c[u];if(s)r=o(r).replace(s),await d('Move "from" key');else{w[f]=r,r=T(l,r),w[f].remove(),r=o(r).next(),l=o(l).next(),await d("Swap elements with keys");continue}}}let U=r&&o(r).nodes().next();await M(r,l),l=l&&o(l).nodes().next(),r=U}let E=[];for(;r;)y(N,r)||E.push(r),r=o(r).nodes().next();for(;E.length;){let u=E.shift();u.remove(),await d("remove el"),S(u)}}function x(e){return e&&e.nodeType===1&&C(e)}function V(e){let t={};return e.forEach(n=>{let p=x(n);p&&(t[p]=n)}),t}function Q(e,t){if(!y(k,e)){let n=e.cloneNode(!0);return o(t).append(n),_(n),n}return null}function T(e,t){if(!y(k,e)){let n=e.cloneNode(!0);return o(t).before(n),_(n),n}return t}return q(v),A=a,m=H(i),window.Alpine&&window.Alpine.closestDataStack&&!a._x_dataStack&&(m._x_dataStack=window.Alpine.closestDataStack(a),m._x_dataStack&&window.Alpine.clone(a,m)),await d(),await M(a,m),A=void 0,m=void 0,a}g.step=()=>j();g.log=a=>{R=a};function y(a,...i){let v=!1;return a(...i,()=>v=!0),v}function W(a,i,v){a.nodeType===1&&a._x_dataStack&&window.Alpine.clone(a,i)}function $(a){a.morph=g}document.addEventListener("alpine:init",()=>{window.Alpine.plugin($)});})(); +(()=>{function E(d,r,u){Y();let m,h,b,B,O,_,v,T,A,C;function W(e={}){let n=a=>a.getAttribute("key"),o=()=>{};O=e.updating||o,_=e.updated||o,v=e.removing||o,T=e.removed||o,A=e.adding||o,C=e.added||o,b=e.key||n,B=e.lookahead||!1}function D(e,n){if(q(e,n))return I(e,n);let o=!1;if(!y(O,e,n,()=>o=!0)){if(e.nodeType===1&&window.Alpine&&window.Alpine.cloneNode(e,n),X(n)){$(e,n),_(e,n);return}o||G(e,n),_(e,n),L(e,n)}}function q(e,n){return e.nodeType!=n.nodeType||e.nodeName!=n.nodeName||g(e)!=g(n)}function I(e,n){if(y(v,e))return;let o=n.cloneNode(!0);y(A,o)||(e.replaceWith(o),T(e),C(o))}function $(e,n){let o=n.nodeValue;e.nodeValue!==o&&(e.nodeValue=o)}function G(e,n){if(e._x_transitioning||e._x_isShown&&!n._x_isShown||!e._x_isShown&&n._x_isShown)return;let o=Array.from(e.attributes),a=Array.from(n.attributes);for(let i=o.length-1;i>=0;i--){let t=o[i].name;n.hasAttribute(t)||e.removeAttribute(t)}for(let i=a.length-1;i>=0;i--){let t=a[i].name,x=a[i].value;e.getAttribute(t)!==x&&e.setAttribute(t,x)}}function L(e,n){let o=H(e.children),a={},i=V(n),t=V(e);for(;i;){let s=g(i),p=g(t);if(!t)if(s&&a[s]){let l=a[s];e.appendChild(l),t=l}else{if(!y(A,i)){let l=i.cloneNode(!0);e.appendChild(l),C(l)}i=c(n,i);continue}let S=l=>l&&l.nodeType===8&&l.textContent==="[if BLOCK]>l&&l.nodeType===8&&l.textContent==="[if ENDBLOCK]>0)l--;else if(N(f)&&l===0){t=f;break}t=f}let R=t;l=0;let j=i;for(;i;){let f=c(n,i);if(S(f))l++;else if(N(f)&&l>0)l--;else if(N(f)&&l===0){i=f;break}i=f}let z=i,J=new w(k,R),Q=new w(j,z);L(J,Q);continue}if(t.nodeType===1&&B&&!t.isEqualNode(i)){let l=c(n,i),k=!1;for(;!k&&l;)l.nodeType===1&&t.isEqualNode(l)&&(k=!0,t=K(e,i,t),p=g(t)),l=c(n,l)}if(s!==p){if(!s&&p){a[p]=t,t=K(e,i,t),a[p].remove(),t=c(e,t),i=c(n,i);continue}if(s&&!p&&o[s]&&(t.replaceWith(o[s]),t=o[s]),s&&p){let l=o[s];if(l)a[p]=t,t.replaceWith(l),t=l;else{a[p]=t,t=K(e,i,t),a[p].remove(),t=c(e,t),i=c(n,i);continue}}}let P=t&&c(e,t);D(t,i),i=i&&c(n,i),t=P}let x=[];for(;t;)y(v,t)||x.push(t),t=c(e,t);for(;x.length;){let s=x.shift();s.remove(),T(s)}}function g(e){return e&&e.nodeType===1&&b(e)}function H(e){let n={};for(let o of e){let a=g(o);a&&(n[a]=o)}return n}function K(e,n,o){if(!y(A,n)){let a=n.cloneNode(!0);return e.insertBefore(a,o),C(a),a}return n}return W(u),m=d,h=typeof r=="string"?U(r):r,window.Alpine&&window.Alpine.closestDataStack&&!d._x_dataStack&&(h._x_dataStack=window.Alpine.closestDataStack(d),h._x_dataStack&&window.Alpine.cloneNode(d,h)),D(d,h),m=void 0,h=void 0,d}E.step=()=>{};E.log=()=>{};function y(d,...r){let u=!1;return d(...r,()=>u=!0),u}var F=!1;function U(d){let r=document.createElement("template");return r.innerHTML=d,r.content.firstElementChild}function X(d){return d.nodeType===3||d.nodeType===8}var w=class{constructor(r,u){this.startComment=r,this.endComment=u}get children(){let r=[],u=this.startComment.nextSibling;for(;u&&u!==this.endComment;)r.push(u),u=u.nextSibling;return r}appendChild(r){this.endComment.before(r)}get firstChild(){let r=this.startComment.nextSibling;if(r!==this.endComment)return r}nextNode(r){let u=r.nextSibling;if(u!==this.endComment)return u}insertBefore(r,u){return u.before(r),r}};function V(d){return d.firstChild}function c(d,r){if(r._x_teleport)return r._x_teleport;let u;return d instanceof w?u=d.nextNode(r):u=r.nextSibling,u}function Y(){if(F)return;F=!0;let d=Element.prototype.setAttribute,r=document.createElement("div");Element.prototype.setAttribute=function(m,h){if(!m.includes("@"))return d.call(this,m,h);r.innerHTML=``;let b=r.firstElementChild.getAttributeNode(m);r.firstElementChild.removeAttributeNode(b),this.setAttributeNode(b)}}function M(d){d.morph=E}document.addEventListener("alpine:init",()=>{window.Alpine.plugin(M)});})(); diff --git a/alpinejs/packages/morph/dist/module.cjs.js b/alpinejs/packages/morph/dist/module.cjs.js index 98dc391..667fd75 100644 --- a/alpinejs/packages/morph/dist/module.cjs.js +++ b/alpinejs/packages/morph/dist/module.cjs.js @@ -1,103 +1,35 @@ var __defProp = Object.defineProperty; -var __markAsModule = (target) => __defProp(target, "__esModule", {value: true}); +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) - __defProp(target, name, {get: all[name], enumerable: true}); + __defProp(target, name, { get: all[name], enumerable: true }); }; -var __publicField = (obj, key, value) => { - if (typeof key !== "symbol") - key += ""; - if (key in obj) - return __defProp(obj, key, {enumerable: true, configurable: true, writable: true, value}); - return obj[key] = value; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; }; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // packages/morph/builds/module.js -__markAsModule(exports); -__export(exports, { +var module_exports = {}; +__export(module_exports, { default: () => module_default, morph: () => morph }); - -// packages/morph/src/dom.js -var DomManager = class { - constructor(el) { - __publicField(this, "el"); - __publicField(this, "traversals", { - first: "firstElementChild", - next: "nextElementSibling", - parent: "parentElement" - }); - this.el = el; - } - nodes() { - this.traversals = { - first: "firstChild", - next: "nextSibling", - parent: "parentNode" - }; - return this; - } - first() { - return this.teleportTo(this.el[this.traversals["first"]]); - } - next() { - return this.teleportTo(this.teleportBack(this.el[this.traversals["next"]])); - } - before(insertee) { - this.el[this.traversals["parent"]].insertBefore(insertee, this.el); - return insertee; - } - replace(replacement) { - this.el[this.traversals["parent"]].replaceChild(replacement, this.el); - return replacement; - } - append(appendee) { - this.el.appendChild(appendee); - return appendee; - } - teleportTo(el) { - if (!el) - return el; - if (el._x_teleport) - return el._x_teleport; - return el; - } - teleportBack(el) { - if (!el) - return el; - if (el._x_teleportBack) - return el._x_teleportBack; - return el; - } -}; -function dom(el) { - return new DomManager(el); -} -function createElement(html) { - const template = document.createElement("template"); - template.innerHTML = html; - return template.content.firstElementChild; -} -function textOrComment(el) { - return el.nodeType === 3 || el.nodeType === 8; -} +module.exports = __toCommonJS(module_exports); // packages/morph/src/morph.js -var resolveStep = () => { -}; -var logger = () => { -}; -async function morph(from, toHtml, options) { +function morph(from, toHtml, options) { + monkeyPatchDomSetAttributeToAllowAtSymbols(); let fromEl; let toEl; - let key, lookahead, updating, updated, removing, removed, adding, added, debug; - function breakpoint(message) { - if (!debug) - return; - logger((message || "").replace("\n", "\\n"), fromEl, toEl); - return new Promise((resolve) => resolveStep = () => resolve()); - } + let key, lookahead, updating, updated, removing, removed, adding, added; function assignOptions(options2 = {}) { let defaultGetKey = (el) => el.getAttribute("key"); let noop = () => { @@ -110,50 +42,50 @@ async function morph(from, toHtml, options) { added = options2.added || noop; key = options2.key || defaultGetKey; lookahead = options2.lookahead || false; - debug = options2.debug || false; } - async function patch(from2, to) { + function patch(from2, to) { if (differentElementNamesTypesOrKeys(from2, to)) { - let result = patchElement(from2, to); - await breakpoint("Swap elements"); - return result; + return swapElements(from2, to); } let updateChildrenOnly = false; if (shouldSkip(updating, from2, to, () => updateChildrenOnly = true)) return; - window.Alpine && initializeAlpineOnTo(from2, to, () => updateChildrenOnly = true); + if (from2.nodeType === 1 && window.Alpine) { + window.Alpine.cloneNode(from2, to); + } if (textOrComment(to)) { - await patchNodeValue(from2, to); + patchNodeValue(from2, to); updated(from2, to); return; } if (!updateChildrenOnly) { - await patchAttributes(from2, to); + patchAttributes(from2, to); } updated(from2, to); - await patchChildren(from2, to); + patchChildren(from2, to); } function differentElementNamesTypesOrKeys(from2, to) { return from2.nodeType != to.nodeType || from2.nodeName != to.nodeName || getKey(from2) != getKey(to); } - function patchElement(from2, to) { + function swapElements(from2, to) { if (shouldSkip(removing, from2)) return; let toCloned = to.cloneNode(true); if (shouldSkip(adding, toCloned)) return; - dom(from2).replace(toCloned); + from2.replaceWith(toCloned); removed(from2); added(toCloned); } - async function patchNodeValue(from2, to) { + function patchNodeValue(from2, to) { let value = to.nodeValue; if (from2.nodeValue !== value) { from2.nodeValue = value; - await breakpoint("Change text node to: " + value); } } - async function patchAttributes(from2, to) { + function patchAttributes(from2, to) { + if (from2._x_transitioning) + return; if (from2._x_isShown && !to._x_isShown) { return; } @@ -166,7 +98,6 @@ async function morph(from, toHtml, options) { let name = domAttributes[i].name; if (!to.hasAttribute(name)) { from2.removeAttribute(name); - await breakpoint("Remove attribute"); } } for (let i = toAttributes.length - 1; i >= 0; i--) { @@ -174,95 +105,127 @@ async function morph(from, toHtml, options) { let value = toAttributes[i].value; if (from2.getAttribute(name) !== value) { from2.setAttribute(name, value); - await breakpoint(`Set [${name}] attribute to: "${value}"`); } } } - async function patchChildren(from2, to) { - let domChildren = from2.childNodes; - let toChildren = to.childNodes; - let toKeyToNodeMap = keyToMap(toChildren); - let domKeyDomNodeMap = keyToMap(domChildren); - let currentTo = dom(to).nodes().first(); - let currentFrom = dom(from2).nodes().first(); - let domKeyHoldovers = {}; + function patchChildren(from2, to) { + let fromKeys = keyToMap(from2.children); + let fromKeyHoldovers = {}; + let currentTo = getFirstNode(to); + let currentFrom = getFirstNode(from2); while (currentTo) { let toKey = getKey(currentTo); - let domKey = getKey(currentFrom); + let fromKey = getKey(currentFrom); if (!currentFrom) { - if (toKey && domKeyHoldovers[toKey]) { - let holdover = domKeyHoldovers[toKey]; - dom(from2).append(holdover); + if (toKey && fromKeyHoldovers[toKey]) { + let holdover = fromKeyHoldovers[toKey]; + from2.appendChild(holdover); currentFrom = holdover; - await breakpoint("Add element (from key)"); } else { - let added2 = addNodeTo(currentTo, from2) || {}; - await breakpoint("Add element: " + (added2.outerHTML || added2.nodeValue)); - currentTo = dom(currentTo).nodes().next(); + if (!shouldSkip(adding, currentTo)) { + let clone = currentTo.cloneNode(true); + from2.appendChild(clone); + added(clone); + } + currentTo = getNextSibling(to, currentTo); continue; } } - if (lookahead) { - let nextToElementSibling = dom(currentTo).next(); + let isIf = (node) => node && node.nodeType === 8 && node.textContent === "[if BLOCK]> node && node.nodeType === 8 && node.textContent === "[if ENDBLOCK]> 0) { + nestedIfCount--; + } else if (isEnd(next) && nestedIfCount === 0) { + currentFrom = next; + break; + } + currentFrom = next; + } + let fromBlockEnd = currentFrom; + nestedIfCount = 0; + let toBlockStart = currentTo; + while (currentTo) { + let next = getNextSibling(to, currentTo); + if (isIf(next)) { + nestedIfCount++; + } else if (isEnd(next) && nestedIfCount > 0) { + nestedIfCount--; + } else if (isEnd(next) && nestedIfCount === 0) { + currentTo = next; + break; + } + currentTo = next; + } + let toBlockEnd = currentTo; + let fromBlock = new Block(fromBlockStart, fromBlockEnd); + let toBlock = new Block(toBlockStart, toBlockEnd); + patchChildren(fromBlock, toBlock); + continue; + } + if (currentFrom.nodeType === 1 && lookahead && !currentFrom.isEqualNode(currentTo)) { + let nextToElementSibling = getNextSibling(to, currentTo); let found = false; while (!found && nextToElementSibling) { - if (currentFrom.isEqualNode(nextToElementSibling)) { + if (nextToElementSibling.nodeType === 1 && currentFrom.isEqualNode(nextToElementSibling)) { found = true; - currentFrom = addNodeBefore(currentTo, currentFrom); - domKey = getKey(currentFrom); - await breakpoint("Move element (lookahead)"); + currentFrom = addNodeBefore(from2, currentTo, currentFrom); + fromKey = getKey(currentFrom); } - nextToElementSibling = dom(nextToElementSibling).next(); + nextToElementSibling = getNextSibling(to, nextToElementSibling); } } - if (toKey !== domKey) { - if (!toKey && domKey) { - domKeyHoldovers[domKey] = currentFrom; - currentFrom = addNodeBefore(currentTo, currentFrom); - domKeyHoldovers[domKey].remove(); - currentFrom = dom(currentFrom).nodes().next(); - currentTo = dom(currentTo).nodes().next(); - await breakpoint('No "to" key'); + if (toKey !== fromKey) { + if (!toKey && fromKey) { + fromKeyHoldovers[fromKey] = currentFrom; + currentFrom = addNodeBefore(from2, currentTo, currentFrom); + fromKeyHoldovers[fromKey].remove(); + currentFrom = getNextSibling(from2, currentFrom); + currentTo = getNextSibling(to, currentTo); continue; } - if (toKey && !domKey) { - if (domKeyDomNodeMap[toKey]) { - currentFrom = dom(currentFrom).replace(domKeyDomNodeMap[toKey]); - await breakpoint('No "from" key'); + if (toKey && !fromKey) { + if (fromKeys[toKey]) { + currentFrom.replaceWith(fromKeys[toKey]); + currentFrom = fromKeys[toKey]; } } - if (toKey && domKey) { - domKeyHoldovers[domKey] = currentFrom; - let domKeyNode = domKeyDomNodeMap[toKey]; - if (domKeyNode) { - currentFrom = dom(currentFrom).replace(domKeyNode); - await breakpoint('Move "from" key'); + if (toKey && fromKey) { + let fromKeyNode = fromKeys[toKey]; + if (fromKeyNode) { + fromKeyHoldovers[fromKey] = currentFrom; + currentFrom.replaceWith(fromKeyNode); + currentFrom = fromKeyNode; } else { - domKeyHoldovers[domKey] = currentFrom; - currentFrom = addNodeBefore(currentTo, currentFrom); - domKeyHoldovers[domKey].remove(); - currentFrom = dom(currentFrom).next(); - currentTo = dom(currentTo).next(); - await breakpoint("Swap elements with keys"); + fromKeyHoldovers[fromKey] = currentFrom; + currentFrom = addNodeBefore(from2, currentTo, currentFrom); + fromKeyHoldovers[fromKey].remove(); + currentFrom = getNextSibling(from2, currentFrom); + currentTo = getNextSibling(to, currentTo); continue; } } } - let currentFromNext = currentFrom && dom(currentFrom).nodes().next(); - await patch(currentFrom, currentTo); - currentTo = currentTo && dom(currentTo).nodes().next(); + let currentFromNext = currentFrom && getNextSibling(from2, currentFrom); + patch(currentFrom, currentTo); + currentTo = currentTo && getNextSibling(to, currentTo); currentFrom = currentFromNext; } let removals = []; while (currentFrom) { if (!shouldSkip(removing, currentFrom)) removals.push(currentFrom); - currentFrom = dom(currentFrom).nodes().next(); + currentFrom = getNextSibling(from2, currentFrom); } while (removals.length) { let domForRemoval = removals.shift(); domForRemoval.remove(); - await breakpoint("remove el"); removed(domForRemoval); } } @@ -271,60 +234,117 @@ async function morph(from, toHtml, options) { } function keyToMap(els) { let map = {}; - els.forEach((el) => { + for (let el of els) { let theKey = getKey(el); if (theKey) { map[theKey] = el; } - }); - return map; - } - function addNodeTo(node, parent) { - if (!shouldSkip(adding, node)) { - let clone = node.cloneNode(true); - dom(parent).append(clone); - added(clone); - return clone; } - return null; + return map; } - function addNodeBefore(node, beforeMe) { + function addNodeBefore(parent, node, beforeMe) { if (!shouldSkip(adding, node)) { let clone = node.cloneNode(true); - dom(beforeMe).before(clone); + parent.insertBefore(clone, beforeMe); added(clone); return clone; } - return beforeMe; + return node; } assignOptions(options); fromEl = from; - toEl = createElement(toHtml); + toEl = typeof toHtml === "string" ? createElement(toHtml) : toHtml; if (window.Alpine && window.Alpine.closestDataStack && !from._x_dataStack) { toEl._x_dataStack = window.Alpine.closestDataStack(from); - toEl._x_dataStack && window.Alpine.clone(from, toEl); + toEl._x_dataStack && window.Alpine.cloneNode(from, toEl); } - await breakpoint(); - await patch(from, toEl); + patch(from, toEl); fromEl = void 0; toEl = void 0; return from; } -morph.step = () => resolveStep(); -morph.log = (theLogger) => { - logger = theLogger; +morph.step = () => { +}; +morph.log = () => { }; function shouldSkip(hook, ...args) { let skip = false; hook(...args, () => skip = true); return skip; } -function initializeAlpineOnTo(from, to, childrenOnly) { - if (from.nodeType !== 1) - return; - if (from._x_dataStack) { - window.Alpine.clone(from, to); +var patched = false; +function createElement(html) { + const template = document.createElement("template"); + template.innerHTML = html; + return template.content.firstElementChild; +} +function textOrComment(el) { + return el.nodeType === 3 || el.nodeType === 8; +} +var Block = class { + constructor(start, end) { + this.startComment = start; + this.endComment = end; } + get children() { + let children = []; + let currentNode = this.startComment.nextSibling; + while (currentNode && currentNode !== this.endComment) { + children.push(currentNode); + currentNode = currentNode.nextSibling; + } + return children; + } + appendChild(child) { + this.endComment.before(child); + } + get firstChild() { + let first = this.startComment.nextSibling; + if (first === this.endComment) + return; + return first; + } + nextNode(reference) { + let next = reference.nextSibling; + if (next === this.endComment) + return; + return next; + } + insertBefore(newNode, reference) { + reference.before(newNode); + return newNode; + } +}; +function getFirstNode(parent) { + return parent.firstChild; +} +function getNextSibling(parent, reference) { + if (reference._x_teleport) { + return reference._x_teleport; + } + let next; + if (parent instanceof Block) { + next = parent.nextNode(reference); + } else { + next = reference.nextSibling; + } + return next; +} +function monkeyPatchDomSetAttributeToAllowAtSymbols() { + if (patched) + return; + patched = true; + let original = Element.prototype.setAttribute; + let hostDiv = document.createElement("div"); + Element.prototype.setAttribute = function newSetAttribute(name, value) { + if (!name.includes("@")) { + return original.call(this, name, value); + } + hostDiv.innerHTML = ``; + let attr = hostDiv.firstElementChild.getAttributeNode(name); + hostDiv.firstElementChild.removeAttributeNode(attr); + this.setAttributeNode(attr); + }; } // packages/morph/src/index.js @@ -334,3 +354,7 @@ function src_default(Alpine) { // packages/morph/builds/module.js var module_default = src_default; +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + morph +}); diff --git a/alpinejs/packages/morph/dist/module.esm.js b/alpinejs/packages/morph/dist/module.esm.js index dfbdfcb..f94615c 100644 --- a/alpinejs/packages/morph/dist/module.esm.js +++ b/alpinejs/packages/morph/dist/module.esm.js @@ -1,82 +1,9 @@ -// packages/morph/src/dom.js -var DomManager = class { - el = void 0; - constructor(el) { - this.el = el; - } - traversals = { - first: "firstElementChild", - next: "nextElementSibling", - parent: "parentElement" - }; - nodes() { - this.traversals = { - first: "firstChild", - next: "nextSibling", - parent: "parentNode" - }; - return this; - } - first() { - return this.teleportTo(this.el[this.traversals["first"]]); - } - next() { - return this.teleportTo(this.teleportBack(this.el[this.traversals["next"]])); - } - before(insertee) { - this.el[this.traversals["parent"]].insertBefore(insertee, this.el); - return insertee; - } - replace(replacement) { - this.el[this.traversals["parent"]].replaceChild(replacement, this.el); - return replacement; - } - append(appendee) { - this.el.appendChild(appendee); - return appendee; - } - teleportTo(el) { - if (!el) - return el; - if (el._x_teleport) - return el._x_teleport; - return el; - } - teleportBack(el) { - if (!el) - return el; - if (el._x_teleportBack) - return el._x_teleportBack; - return el; - } -}; -function dom(el) { - return new DomManager(el); -} -function createElement(html) { - const template = document.createElement("template"); - template.innerHTML = html; - return template.content.firstElementChild; -} -function textOrComment(el) { - return el.nodeType === 3 || el.nodeType === 8; -} - // packages/morph/src/morph.js -var resolveStep = () => { -}; -var logger = () => { -}; -async function morph(from, toHtml, options) { +function morph(from, toHtml, options) { + monkeyPatchDomSetAttributeToAllowAtSymbols(); let fromEl; let toEl; - let key, lookahead, updating, updated, removing, removed, adding, added, debug; - function breakpoint(message) { - if (!debug) - return; - logger((message || "").replace("\n", "\\n"), fromEl, toEl); - return new Promise((resolve) => resolveStep = () => resolve()); - } + let key, lookahead, updating, updated, removing, removed, adding, added; function assignOptions(options2 = {}) { let defaultGetKey = (el) => el.getAttribute("key"); let noop = () => { @@ -89,50 +16,50 @@ async function morph(from, toHtml, options) { added = options2.added || noop; key = options2.key || defaultGetKey; lookahead = options2.lookahead || false; - debug = options2.debug || false; } - async function patch(from2, to) { + function patch(from2, to) { if (differentElementNamesTypesOrKeys(from2, to)) { - let result = patchElement(from2, to); - await breakpoint("Swap elements"); - return result; + return swapElements(from2, to); } let updateChildrenOnly = false; if (shouldSkip(updating, from2, to, () => updateChildrenOnly = true)) return; - window.Alpine && initializeAlpineOnTo(from2, to, () => updateChildrenOnly = true); + if (from2.nodeType === 1 && window.Alpine) { + window.Alpine.cloneNode(from2, to); + } if (textOrComment(to)) { - await patchNodeValue(from2, to); + patchNodeValue(from2, to); updated(from2, to); return; } if (!updateChildrenOnly) { - await patchAttributes(from2, to); + patchAttributes(from2, to); } updated(from2, to); - await patchChildren(from2, to); + patchChildren(from2, to); } function differentElementNamesTypesOrKeys(from2, to) { return from2.nodeType != to.nodeType || from2.nodeName != to.nodeName || getKey(from2) != getKey(to); } - function patchElement(from2, to) { + function swapElements(from2, to) { if (shouldSkip(removing, from2)) return; let toCloned = to.cloneNode(true); if (shouldSkip(adding, toCloned)) return; - dom(from2).replace(toCloned); + from2.replaceWith(toCloned); removed(from2); added(toCloned); } - async function patchNodeValue(from2, to) { + function patchNodeValue(from2, to) { let value = to.nodeValue; if (from2.nodeValue !== value) { from2.nodeValue = value; - await breakpoint("Change text node to: " + value); } } - async function patchAttributes(from2, to) { + function patchAttributes(from2, to) { + if (from2._x_transitioning) + return; if (from2._x_isShown && !to._x_isShown) { return; } @@ -145,7 +72,6 @@ async function morph(from, toHtml, options) { let name = domAttributes[i].name; if (!to.hasAttribute(name)) { from2.removeAttribute(name); - await breakpoint("Remove attribute"); } } for (let i = toAttributes.length - 1; i >= 0; i--) { @@ -153,95 +79,127 @@ async function morph(from, toHtml, options) { let value = toAttributes[i].value; if (from2.getAttribute(name) !== value) { from2.setAttribute(name, value); - await breakpoint(`Set [${name}] attribute to: "${value}"`); } } } - async function patchChildren(from2, to) { - let domChildren = from2.childNodes; - let toChildren = to.childNodes; - let toKeyToNodeMap = keyToMap(toChildren); - let domKeyDomNodeMap = keyToMap(domChildren); - let currentTo = dom(to).nodes().first(); - let currentFrom = dom(from2).nodes().first(); - let domKeyHoldovers = {}; + function patchChildren(from2, to) { + let fromKeys = keyToMap(from2.children); + let fromKeyHoldovers = {}; + let currentTo = getFirstNode(to); + let currentFrom = getFirstNode(from2); while (currentTo) { let toKey = getKey(currentTo); - let domKey = getKey(currentFrom); + let fromKey = getKey(currentFrom); if (!currentFrom) { - if (toKey && domKeyHoldovers[toKey]) { - let holdover = domKeyHoldovers[toKey]; - dom(from2).append(holdover); + if (toKey && fromKeyHoldovers[toKey]) { + let holdover = fromKeyHoldovers[toKey]; + from2.appendChild(holdover); currentFrom = holdover; - await breakpoint("Add element (from key)"); } else { - let added2 = addNodeTo(currentTo, from2) || {}; - await breakpoint("Add element: " + (added2.outerHTML || added2.nodeValue)); - currentTo = dom(currentTo).nodes().next(); + if (!shouldSkip(adding, currentTo)) { + let clone = currentTo.cloneNode(true); + from2.appendChild(clone); + added(clone); + } + currentTo = getNextSibling(to, currentTo); continue; } } - if (lookahead) { - let nextToElementSibling = dom(currentTo).next(); + let isIf = (node) => node && node.nodeType === 8 && node.textContent === "[if BLOCK]> node && node.nodeType === 8 && node.textContent === "[if ENDBLOCK]> 0) { + nestedIfCount--; + } else if (isEnd(next) && nestedIfCount === 0) { + currentFrom = next; + break; + } + currentFrom = next; + } + let fromBlockEnd = currentFrom; + nestedIfCount = 0; + let toBlockStart = currentTo; + while (currentTo) { + let next = getNextSibling(to, currentTo); + if (isIf(next)) { + nestedIfCount++; + } else if (isEnd(next) && nestedIfCount > 0) { + nestedIfCount--; + } else if (isEnd(next) && nestedIfCount === 0) { + currentTo = next; + break; + } + currentTo = next; + } + let toBlockEnd = currentTo; + let fromBlock = new Block(fromBlockStart, fromBlockEnd); + let toBlock = new Block(toBlockStart, toBlockEnd); + patchChildren(fromBlock, toBlock); + continue; + } + if (currentFrom.nodeType === 1 && lookahead && !currentFrom.isEqualNode(currentTo)) { + let nextToElementSibling = getNextSibling(to, currentTo); let found = false; while (!found && nextToElementSibling) { - if (currentFrom.isEqualNode(nextToElementSibling)) { + if (nextToElementSibling.nodeType === 1 && currentFrom.isEqualNode(nextToElementSibling)) { found = true; - currentFrom = addNodeBefore(currentTo, currentFrom); - domKey = getKey(currentFrom); - await breakpoint("Move element (lookahead)"); + currentFrom = addNodeBefore(from2, currentTo, currentFrom); + fromKey = getKey(currentFrom); } - nextToElementSibling = dom(nextToElementSibling).next(); + nextToElementSibling = getNextSibling(to, nextToElementSibling); } } - if (toKey !== domKey) { - if (!toKey && domKey) { - domKeyHoldovers[domKey] = currentFrom; - currentFrom = addNodeBefore(currentTo, currentFrom); - domKeyHoldovers[domKey].remove(); - currentFrom = dom(currentFrom).nodes().next(); - currentTo = dom(currentTo).nodes().next(); - await breakpoint('No "to" key'); + if (toKey !== fromKey) { + if (!toKey && fromKey) { + fromKeyHoldovers[fromKey] = currentFrom; + currentFrom = addNodeBefore(from2, currentTo, currentFrom); + fromKeyHoldovers[fromKey].remove(); + currentFrom = getNextSibling(from2, currentFrom); + currentTo = getNextSibling(to, currentTo); continue; } - if (toKey && !domKey) { - if (domKeyDomNodeMap[toKey]) { - currentFrom = dom(currentFrom).replace(domKeyDomNodeMap[toKey]); - await breakpoint('No "from" key'); + if (toKey && !fromKey) { + if (fromKeys[toKey]) { + currentFrom.replaceWith(fromKeys[toKey]); + currentFrom = fromKeys[toKey]; } } - if (toKey && domKey) { - domKeyHoldovers[domKey] = currentFrom; - let domKeyNode = domKeyDomNodeMap[toKey]; - if (domKeyNode) { - currentFrom = dom(currentFrom).replace(domKeyNode); - await breakpoint('Move "from" key'); + if (toKey && fromKey) { + let fromKeyNode = fromKeys[toKey]; + if (fromKeyNode) { + fromKeyHoldovers[fromKey] = currentFrom; + currentFrom.replaceWith(fromKeyNode); + currentFrom = fromKeyNode; } else { - domKeyHoldovers[domKey] = currentFrom; - currentFrom = addNodeBefore(currentTo, currentFrom); - domKeyHoldovers[domKey].remove(); - currentFrom = dom(currentFrom).next(); - currentTo = dom(currentTo).next(); - await breakpoint("Swap elements with keys"); + fromKeyHoldovers[fromKey] = currentFrom; + currentFrom = addNodeBefore(from2, currentTo, currentFrom); + fromKeyHoldovers[fromKey].remove(); + currentFrom = getNextSibling(from2, currentFrom); + currentTo = getNextSibling(to, currentTo); continue; } } } - let currentFromNext = currentFrom && dom(currentFrom).nodes().next(); - await patch(currentFrom, currentTo); - currentTo = currentTo && dom(currentTo).nodes().next(); + let currentFromNext = currentFrom && getNextSibling(from2, currentFrom); + patch(currentFrom, currentTo); + currentTo = currentTo && getNextSibling(to, currentTo); currentFrom = currentFromNext; } let removals = []; while (currentFrom) { if (!shouldSkip(removing, currentFrom)) removals.push(currentFrom); - currentFrom = dom(currentFrom).nodes().next(); + currentFrom = getNextSibling(from2, currentFrom); } while (removals.length) { let domForRemoval = removals.shift(); domForRemoval.remove(); - await breakpoint("remove el"); removed(domForRemoval); } } @@ -250,60 +208,117 @@ async function morph(from, toHtml, options) { } function keyToMap(els) { let map = {}; - els.forEach((el) => { + for (let el of els) { let theKey = getKey(el); if (theKey) { map[theKey] = el; } - }); - return map; - } - function addNodeTo(node, parent) { - if (!shouldSkip(adding, node)) { - let clone = node.cloneNode(true); - dom(parent).append(clone); - added(clone); - return clone; } - return null; + return map; } - function addNodeBefore(node, beforeMe) { + function addNodeBefore(parent, node, beforeMe) { if (!shouldSkip(adding, node)) { let clone = node.cloneNode(true); - dom(beforeMe).before(clone); + parent.insertBefore(clone, beforeMe); added(clone); return clone; } - return beforeMe; + return node; } assignOptions(options); fromEl = from; - toEl = createElement(toHtml); + toEl = typeof toHtml === "string" ? createElement(toHtml) : toHtml; if (window.Alpine && window.Alpine.closestDataStack && !from._x_dataStack) { toEl._x_dataStack = window.Alpine.closestDataStack(from); - toEl._x_dataStack && window.Alpine.clone(from, toEl); + toEl._x_dataStack && window.Alpine.cloneNode(from, toEl); } - await breakpoint(); - await patch(from, toEl); + patch(from, toEl); fromEl = void 0; toEl = void 0; return from; } -morph.step = () => resolveStep(); -morph.log = (theLogger) => { - logger = theLogger; +morph.step = () => { +}; +morph.log = () => { }; function shouldSkip(hook, ...args) { let skip = false; hook(...args, () => skip = true); return skip; } -function initializeAlpineOnTo(from, to, childrenOnly) { - if (from.nodeType !== 1) - return; - if (from._x_dataStack) { - window.Alpine.clone(from, to); +var patched = false; +function createElement(html) { + const template = document.createElement("template"); + template.innerHTML = html; + return template.content.firstElementChild; +} +function textOrComment(el) { + return el.nodeType === 3 || el.nodeType === 8; +} +var Block = class { + constructor(start, end) { + this.startComment = start; + this.endComment = end; } + get children() { + let children = []; + let currentNode = this.startComment.nextSibling; + while (currentNode && currentNode !== this.endComment) { + children.push(currentNode); + currentNode = currentNode.nextSibling; + } + return children; + } + appendChild(child) { + this.endComment.before(child); + } + get firstChild() { + let first = this.startComment.nextSibling; + if (first === this.endComment) + return; + return first; + } + nextNode(reference) { + let next = reference.nextSibling; + if (next === this.endComment) + return; + return next; + } + insertBefore(newNode, reference) { + reference.before(newNode); + return newNode; + } +}; +function getFirstNode(parent) { + return parent.firstChild; +} +function getNextSibling(parent, reference) { + if (reference._x_teleport) { + return reference._x_teleport; + } + let next; + if (parent instanceof Block) { + next = parent.nextNode(reference); + } else { + next = reference.nextSibling; + } + return next; +} +function monkeyPatchDomSetAttributeToAllowAtSymbols() { + if (patched) + return; + patched = true; + let original = Element.prototype.setAttribute; + let hostDiv = document.createElement("div"); + Element.prototype.setAttribute = function newSetAttribute(name, value) { + if (!name.includes("@")) { + return original.call(this, name, value); + } + hostDiv.innerHTML = ``; + let attr = hostDiv.firstElementChild.getAttributeNode(name); + hostDiv.firstElementChild.removeAttributeNode(attr); + this.setAttributeNode(attr); + }; } // packages/morph/src/index.js diff --git a/alpinejs/packages/morph/package.json b/alpinejs/packages/morph/package.json index ed63cd9..c47be90 100644 --- a/alpinejs/packages/morph/package.json +++ b/alpinejs/packages/morph/package.json @@ -1,7 +1,13 @@ { "name": "@alpinejs/morph", - "version": "3.10.3", + "version": "3.13.1", "description": "Diff and patch a block of HTML on a page with an HTML template", + "homepage": "https://alpinejs.dev/plugins/morph", + "repository": { + "type": "git", + "url": "https://github.com/alpinejs/alpine.git", + "directory": "packages/morph" + }, "author": "Caleb Porzio", "license": "MIT", "main": "dist/module.cjs.js", diff --git a/alpinejs/packages/morph/src/dom.js b/alpinejs/packages/morph/src/dom.js deleted file mode 100644 index 0511dcc..0000000 --- a/alpinejs/packages/morph/src/dom.js +++ /dev/null @@ -1,68 +0,0 @@ -class DomManager { - el = undefined - - constructor(el) { - this.el = el - } - - traversals = { - 'first': 'firstElementChild', - 'next': 'nextElementSibling', - 'parent': 'parentElement', - } - - nodes() { - this.traversals = { - 'first': 'firstChild', - 'next': 'nextSibling', - 'parent': 'parentNode', - }; return this - } - - first() { - return this.teleportTo(this.el[this.traversals['first']]) - } - - next() { - return this.teleportTo(this.teleportBack(this.el[this.traversals['next']])) - } - - before(insertee) { - this.el[this.traversals['parent']].insertBefore(insertee, this.el); return insertee - } - - replace(replacement) { - this.el[this.traversals['parent']].replaceChild(replacement, this.el); return replacement - } - - append(appendee) { - this.el.appendChild(appendee); return appendee - } - - teleportTo(el) { - if (! el) return el - if (el._x_teleport) return el._x_teleport - return el - } - - teleportBack(el) { - if (! el) return el - if (el._x_teleportBack) return el._x_teleportBack - return el - } -} - -export function dom(el) { - return new DomManager(el) -} - -export function createElement(html) { - const template = document.createElement('template') - template.innerHTML = html - return template.content.firstElementChild -} - -export function textOrComment(el) { - return el.nodeType === 3 - || el.nodeType === 8 -} diff --git a/alpinejs/packages/morph/src/morph.js b/alpinejs/packages/morph/src/morph.js index b472c6c..928d1ab 100644 --- a/alpinejs/packages/morph/src/morph.js +++ b/alpinejs/packages/morph/src/morph.js @@ -1,34 +1,18 @@ -import { dom, createElement, textOrComment} from './dom.js' let resolveStep = () => {} let logger = () => {} -export async function morph(from, toHtml, options) { +export function morph(from, toHtml, options) { + monkeyPatchDomSetAttributeToAllowAtSymbols() + // We're defining these globals and methods inside this function (instead of outside) // because it's an async function and if run twice, they would overwrite // each other. let fromEl let toEl - let key - ,lookahead - ,updating - ,updated - ,removing - ,removed - ,adding - ,added - ,debug - - - function breakpoint(message) { - if (! debug) return - - logger((message || '').replace('\n', '\\n'), fromEl, toEl) - - return new Promise(resolve => resolveStep = () => resolve()) - } + let key, lookahead, updating, updated, removing, removed, adding, added function assignOptions(options = {}) { let defaultGetKey = el => el.getAttribute('key') @@ -42,44 +26,37 @@ export async function morph(from, toHtml, options) { added = options.added || noop key = options.key || defaultGetKey lookahead = options.lookahead || false - debug = options.debug || false } - async function patch(from, to) { - // This is a time saver, however, it won't catch differences in nested