diff --git a/package-lock.json b/package-lock.json index ae3f246..896b80a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,16 @@ { "name": "freshjuice-hubspot-theme", - "version": "1.2.0", + "version": "1.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "freshjuice-hubspot-theme", - "version": "1.2.0", + "version": "1.3.0", "license": "GPL-3.0-or-later", "devDependencies": { "@alpinejs/collapse": "^3.13.10", + "@alpinejs/focus": "^3.13.10", "@alpinejs/intersect": "^3.13.10", "@tailwindcss/aspect-ratio": "^0.4.2", "@tailwindcss/forms": "^0.5.7", @@ -52,6 +53,16 @@ "integrity": "sha512-D4CRrwXdhuJdQX8gJvYBajMj90I85huf395eB8E+PfGy2QQZOxZxd92TWzaMLnMQlFHPkZ+chZmFuewjZ7y52Q==", "dev": true }, + "node_modules/@alpinejs/focus": { + "version": "3.13.10", + "resolved": "https://registry.npmjs.org/@alpinejs/focus/-/focus-3.13.10.tgz", + "integrity": "sha512-4W4AvVtqq3Ozosa+PEopIJqAIoyWOll24t/LClNmQPPl3exsns84sfN+V5SVPLfbBH+uoaCkxEq2rae6U7/MBA==", + "dev": true, + "dependencies": { + "focus-trap": "^6.9.4", + "tabbable": "^5.3.3" + } + }, "node_modules/@alpinejs/intersect": { "version": "3.13.10", "resolved": "https://registry.npmjs.org/@alpinejs/intersect/-/intersect-3.13.10.tgz", @@ -1807,6 +1818,15 @@ "integrity": "sha512-UJaPOARxOcRv9NoiRh6PpNnTetSCldrh8SJ7+0X4PRjeJZbNNo5lzTYEg39fCw2RUrxK6Y0GPuiL0D1N5z+yTw==", "dev": true }, + "node_modules/focus-trap": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-6.9.4.tgz", + "integrity": "sha512-v2NTsZe2FF59Y+sDykKY+XjqZ0cPfhq/hikWVL88BqLivnNiEffAsac6rP6H45ff9wG9LL5ToiDqrLEP9GX9mw==", + "dev": true, + "dependencies": { + "tabbable": "^5.3.3" + } + }, "node_modules/for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -4528,6 +4548,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/tabbable": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-5.3.3.tgz", + "integrity": "sha512-QD9qKY3StfbZqWOPLp0++pOrAVb/HbUi5xCc8cUo4XjP19808oaMiDzn0leBY5mCespIBM0CIZePzZjgzR83kA==", + "dev": true + }, "node_modules/tailwindcss": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.3.tgz", diff --git a/package.json b/package.json index 5e7e343..c33e172 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "freshjuice-hubspot-theme", - "version": "1.2.0", + "version": "1.3.0", "description": "Hubspot CMS theme boilerplate with TailwindCSS, AlpineJS, and more.", "main": "index.js", "scripts": { @@ -54,6 +54,7 @@ "homepage": "https://github.com/freshjuice-dev/freshjuice-hubspot-theme#readme", "devDependencies": { "@alpinejs/collapse": "^3.13.10", + "@alpinejs/focus": "^3.13.10", "@alpinejs/intersect": "^3.13.10", "@tailwindcss/aspect-ratio": "^0.4.2", "@tailwindcss/forms": "^0.5.7", diff --git a/source/js/main.js b/source/js/main.js index 0a06f2e..6aafdb8 100644 --- a/source/js/main.js +++ b/source/js/main.js @@ -6,6 +6,7 @@ import flyingPages from "flying-pages-module"; import Alpine from "alpinejs"; import intersect from "@alpinejs/intersect"; import collapse from "@alpinejs/collapse"; +import focus from "@alpinejs/focus"; import dataDOM from "./modules/Alpine.data/DOM"; // The window.Alpine = Alpine bit is optional, but is nice to have for @@ -28,6 +29,7 @@ function domReady(callback) { // Add plugins to Alpine Alpine.plugin(intersect); Alpine.plugin(collapse); +Alpine.plugin(focus); Alpine.data("xDOM", dataDOM); diff --git a/theme/css/tailwind.css b/theme/css/tailwind.css index a477d83..2f6a810 100644 --- a/theme/css/tailwind.css +++ b/theme/css/tailwind.css @@ -1834,6 +1834,10 @@ lite-youtube.lyt-activated > .lty-playbtn{ margin-top:0px !important; } +.-fj-mb-px{ + margin-bottom:-1px; +} + .fj-mb-2{ margin-bottom:0.5rem; } @@ -2126,6 +2130,10 @@ lite-youtube.lyt-activated > .lty-playbtn{ align-items:center; } +.fj-items-stretch{ + align-items:stretch; +} + .fj-justify-end{ justify-content:flex-end; } @@ -2261,18 +2269,35 @@ lite-youtube.lyt-activated > .lty-playbtn{ border-top-right-radius:0.25rem; } +.fj-rounded-t-md{ + border-top-left-radius:0.375rem; + border-top-right-radius:0.375rem; +} + .fj-rounded-bl-none{ border-bottom-left-radius:0px; } +.fj-rounded-tl-none{ + border-top-left-radius:0px; +} + .fj-border{ border-width:1px; } +.fj-border-l{ + border-left-width:1px; +} + .fj-border-l-4{ border-left-width:4px; } +.fj-border-r{ + border-right-width:1px; +} + .fj-border-t{ border-top-width:1px; } @@ -2296,6 +2321,10 @@ lite-youtube.lyt-activated > .lty-playbtn{ border-color:rgb(28 25 23 / 0.1); } +.fj-border-transparent{ + border-color:transparent; +} + .fj-bg-amber-100{ --fj-bg-opacity:1; background-color:rgb(254 243 199 / var(--fj-bg-opacity)); @@ -2420,6 +2449,10 @@ lite-youtube.lyt-activated > .lty-playbtn{ padding:1rem; } +.fj-p-8{ + padding:2rem; +} + .\!fj-py-0{ padding-top:0px !important; padding-bottom:0px !important; diff --git a/theme/js/main.js b/theme/js/main.js index e0ad75c..b992289 100644 --- a/theme/js/main.js +++ b/theme/js/main.js @@ -1219,7 +1219,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el); let wantsScale = wantsAll || modifiers.includes("scale"); let opacityValue = wantsOpacity ? 0 : 1; let scaleValue = wantsScale ? modifierValue(modifiers, "scale", 95) / 100 : 1; - let delay = modifierValue(modifiers, "delay", 0) / 1e3; + let delay3 = modifierValue(modifiers, "delay", 0) / 1e3; let origin = modifierValue(modifiers, "origin", "center"); let property = "opacity, transform"; let durationIn = modifierValue(modifiers, "duration", 150) / 1e3; @@ -1228,7 +1228,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el); if (transitioningIn) { el._x_transition.enter.during = { transformOrigin: origin, - transitionDelay: `${delay}s`, + transitionDelay: `${delay3}s`, transitionProperty: property, transitionDuration: `${durationIn}s`, transitionTimingFunction: easing @@ -1245,7 +1245,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el); if (transitioningOut) { el._x_transition.leave.during = { transformOrigin: origin, - transitionDelay: `${delay}s`, + transitionDelay: `${delay3}s`, transitionProperty: property, transitionDuration: `${durationOut}s`, transitionTimingFunction: easing @@ -1402,7 +1402,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el); if (interrupted) return; let duration = Number(getComputedStyle(el).transitionDuration.replace(/,.*/, "").replace("s", "")) * 1e3; - let delay = Number(getComputedStyle(el).transitionDelay.replace(/,.*/, "").replace("s", "")) * 1e3; + let delay3 = Number(getComputedStyle(el).transitionDelay.replace(/,.*/, "").replace("s", "")) * 1e3; if (duration === 0) duration = Number(getComputedStyle(el).animationDuration.replace("s", "")) * 1e3; mutateDom(() => { @@ -1416,7 +1416,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el); stages.end(); }); releaseNextTicks(); - setTimeout(el._x_transitioning.finish, duration + delay); + setTimeout(el._x_transitioning.finish, duration + delay3); reachedEnd = true; }); }); @@ -3641,6 +3641,1008 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el); } var module_default3 = src_default3; + // node_modules/@alpinejs/focus/dist/module.esm.js + 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); + } + candidates = candidates.filter(filter); + return candidates; + }; + 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); + } + } + } + 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; + }; + 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 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 { + 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 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; + } + 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; + } + 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; + } + if (nodeIsAttached) { + return !node.getClientRects().length; + } + } 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 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; + }; + var isNodeMatchingSelectorTabbable = function isNodeMatchingSelectorTabbable2(options, node) { + if (isNonTabbableRadio(node) || getTabindex(node) < 0 || !isNodeMatchingSelectorFocusable(options, node)) { + return false; + } + return true; + }; + 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 = []; + 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 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; + 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 || {}; + if (!node) { + throw new Error("No node provided"); + } + if (matches.call(node, focusableCandidateSelector) === false) { + return false; + } + return isNodeMatchingSelectorFocusable(options, node); + }; + function ownKeys2(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); + } + return keys; + } + function _objectSpread2(target) { + for (var i = 1; i < arguments.length; i++) { + var source = null != arguments[i] ? arguments[i] : {}; + i % 2 ? ownKeys2(Object(source), true).forEach(function(key) { + _defineProperty(target, key, source[key]); + }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys2(Object(source)).forEach(function(key) { + Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); + }); + } + 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 = /* @__PURE__ */ function() { + var trapQueue = []; + return { + activateTrap: function activateTrap(trap) { + if (trapQueue.length > 0) { + var activeTrap = trapQueue[trapQueue.length - 1]; + if (activeTrap !== trap) { + activeTrap.pause(); + } + } + 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 (trapQueue.length > 0) { + trapQueue[trapQueue.length - 1].unpause(); + } + } + }; + }(); + 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; + 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 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 = (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); + } + if (optionValue === true) { + optionValue = void 0; + } + 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 node = optionValue; + if (typeof optionValue === "string") { + node = doc.querySelector(optionValue); + if (!node) { + throw new Error("`".concat(optionName, "` as selector refers to no known node")); + } + } + 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 (!node) { + throw new Error("Your focus-trap needs to have at least one focusable element"); + } + return node; + }; + var updateTabbableNodes = function updateTabbableNodes2() { + 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"); + } + }; + 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 && !isFocusable(target, config.tabbableOptions) + }); + return; + } + if (valueOrHandler(config.allowOutsideClick, e)) { + return; + } + 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()); + } + }; + var checkTab = function checkTab2(e) { + var target = getActualTarget(e); + updateTabbableNodes(); + 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 || isFocusable(target, config.tabbableOptions) && !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 || isFocusable(target, config.tabbableOptions) && !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 + }); + 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; + } + }; + trap.updateContainerElements(elements); + return trap; + }; + function src_default4(Alpine2) { + let lastFocused; + let currentFocused; + window.addEventListener("focusin", () => { + lastFocused = currentFocused; + currentFocused = document.activeElement; + }); + Alpine2.magic("focus", (el) => { + let within = el; + return { + __noscroll: false, + __wrapAround: false, + within(el2) { + within = el2; + return this; + }, + withoutScrolling() { + this.__noscroll = true; + return this; + }, + noscroll() { + this.__noscroll = true; + return this; + }, + withWrapAround() { + this.__wrapAround = true; + return this; + }, + wrap() { + return this.withWrapAround(); + }, + focusable(el2) { + return isFocusable(el2); + }, + previouslyFocused() { + return lastFocused; + }, + lastFocused() { + return lastFocused; + }, + focused() { + return currentFocused; + }, + focusables() { + if (Array.isArray(within)) + return within; + return focusable(within, { displayCheck: "none" }); + }, + all() { + return this.focusables(); + }, + isFirst(el2) { + let els = this.all(); + return els[0] && els[0].isSameNode(el2); + }, + isLast(el2) { + let els = this.all(); + return els.length && els.slice(-1)[0].isSameNode(el2); + }, + getFirst() { + return this.all()[0]; + }, + getLast() { + return this.all().slice(-1)[0]; + }, + getNext() { + let list = this.all(); + let current = document.activeElement; + if (list.indexOf(current) === -1) + return; + if (this.__wrapAround && list.indexOf(current) === list.length - 1) { + return list[0]; + } + return list[list.indexOf(current) + 1]; + }, + getPrevious() { + let list = this.all(); + let current = document.activeElement; + if (list.indexOf(current) === -1) + return; + if (this.__wrapAround && list.indexOf(current) === 0) { + return list.slice(-1)[0]; + } + return list[list.indexOf(current) - 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(el2) { + if (!el2) + return; + setTimeout(() => { + if (!el2.hasAttribute("tabindex")) + el2.setAttribute("tabindex", "0"); + el2.focus({ preventScroll: this.__noscroll }); + }); + } + }; + }); + Alpine2.directive("trap", Alpine2.skipDuringClone( + (el, { expression, modifiers }, { effect: effect3, evaluateLater: evaluateLater2, cleanup: cleanup2 }) => { + let evaluator = evaluateLater2(expression); + let oldValue = false; + let options = { + escapeDeactivates: false, + allowOutsideClick: true, + fallbackFocus: () => el + }; + if (modifiers.includes("noautofocus")) { + options.initialFocus = false; + } else { + let autofocusEl = el.querySelector("[autofocus]"); + if (autofocusEl) + options.initialFocus = autofocusEl; + } + let trap = createFocusTrap(el, options); + let undoInert = () => { + }; + let undoDisableScrolling = () => { + }; + const releaseFocus = () => { + undoInert(); + undoInert = () => { + }; + undoDisableScrolling(); + undoDisableScrolling = () => { + }; + trap.deactivate({ + returnFocus: !modifiers.includes("noreturn") + }); + }; + effect3(() => evaluator((value) => { + if (oldValue === value) + return; + if (value && !oldValue) { + if (modifiers.includes("noscroll")) + undoDisableScrolling = disableScrolling(); + if (modifiers.includes("inert")) + undoInert = setInert(el); + setTimeout(() => { + trap.activate(); + }, 15); + } + if (!value && oldValue) { + releaseFocus(); + } + oldValue = !!value; + })); + cleanup2(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: evaluate2 }) => { + if (modifiers.includes("inert") && evaluate2(expression)) + setInert(el); + } + )); + } + function setInert(el) { + let undos = []; + crawlSiblingsUp(el, (sibling) => { + let cache = sibling.hasAttribute("aria-hidden"); + sibling.setAttribute("aria-hidden", "true"); + undos.push(() => cache || sibling.removeAttribute("aria-hidden")); + }); + return () => { + while (undos.length) + undos.pop()(); + }; + } + function crawlSiblingsUp(el, callback) { + if (el.isSameNode(document.body) || !el.parentNode) + return; + Array.from(el.parentNode.children).forEach((sibling) => { + if (sibling.isSameNode(el)) { + crawlSiblingsUp(el.parentNode, callback); + } else { + callback(sibling); + } + }); + } + function disableScrolling() { + let overflow = document.documentElement.style.overflow; + let paddingRight = document.documentElement.style.paddingRight; + let scrollbarWidth = window.innerWidth - document.documentElement.clientWidth; + document.documentElement.style.overflow = "hidden"; + document.documentElement.style.paddingRight = `${scrollbarWidth}px`; + return () => { + document.documentElement.style.overflow = overflow; + document.documentElement.style.paddingRight = paddingRight; + }; + } + var module_default4 = src_default4; + // source/js/modules/Alpine.data/DOM.js var import_debugLog = __toESM(require_debugLog()); var import_loadScript = __toESM(require_loadScript()); @@ -3672,6 +4674,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el); } module_default.plugin(module_default2); module_default.plugin(module_default3); + module_default.plugin(module_default4); module_default.data("xDOM", DOM_default); if (navigator.userAgent.indexOf("Safari") != -1 && navigator.userAgent.indexOf("Chrome") == -1) { (0, import_loadScript2.default)("//cdn.jsdelivr.net/npm/balance-text@3.3.1/balancetext.min.js", "async", () => { @@ -3689,3 +4692,21 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el); }); }); })(); +/*! Bundled license information: + +@alpinejs/focus/dist/module.esm.js: + (*! 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/theme/modules/accordion.module/fields.json b/theme/modules/accordion.module/fields.json index d7b978b..fa76def 100644 --- a/theme/modules/accordion.module/fields.json +++ b/theme/modules/accordion.module/fields.json @@ -31,26 +31,20 @@ "required" : false, "locked" : false, "type" : "richtext", - "default" : "Lorem ipsum dolor sit amet consectetur adipisicing elit. In magnam quod natus deleniti architecto eaque consequuntur ex, illo neque iste repellendus modi, quasi ipsa commodi saepe? Provident ipsa nulla earum." + "default" : "

What is Lorem Ipsum?

Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.

" } ], "tab" : "CONTENT", "expanded" : false, "type" : "group", "default" : [ { - "question" : "Question", - "answer" : "Lorem ipsum dolor sit amet consectetur adipisicing elit. In magnam quod natus deleniti architecto eaque consequuntur ex, illo neque iste repellendus modi, quasi ipsa commodi saepe? Provident ipsa nulla earum." + "question" : "Question 1", + "answer" : "

What is Lorem Ipsum?

Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.

" }, { - "question" : "Question", - "answer" : "Lorem ipsum dolor sit amet consectetur adipisicing elit. In magnam quod natus deleniti architecto eaque consequuntur ex, illo neque iste repellendus modi, quasi ipsa commodi saepe? Provident ipsa nulla earum." + "question" : "Question 2", + "answer" : "

Why do we use it?

It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like).

" }, { - "question" : "Question", - "answer" : "Lorem ipsum dolor sit amet consectetur adipisicing elit. In magnam quod natus deleniti architecto eaque consequuntur ex, illo neque iste repellendus modi, quasi ipsa commodi saepe? Provident ipsa nulla earum." - }, { - "question" : "Question", - "answer" : "Lorem ipsum dolor sit amet consectetur adipisicing elit. In magnam quod natus deleniti architecto eaque consequuntur ex, illo neque iste repellendus modi, quasi ipsa commodi saepe? Provident ipsa nulla earum." - }, { - "question" : "Question", - "answer" : "Lorem ipsum dolor sit amet consectetur adipisicing elit. In magnam quod natus deleniti architecto eaque consequuntur ex, illo neque iste repellendus modi, quasi ipsa commodi saepe? Provident ipsa nulla earum." + "question" : "Question 3", + "answer" : "

Where can I get some?

There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet. It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which looks reasonable. The generated Lorem Ipsum is therefore always free from repetition, injected humour, or non-characteristic words etc.

" } ] }, { "id" : "035814d7-a42a-8fdb-a342-298cfa4ab12e", diff --git a/theme/modules/accordion.module/module.html b/theme/modules/accordion.module/module.html index 48e7bdc..253a8cb 100644 --- a/theme/modules/accordion.module/module.html +++ b/theme/modules/accordion.module/module.html @@ -1,9 +1,3 @@ -{#{% for item in module.items %}#} -{# {% inline_text field="question" value="{{ item.question }}" %}#} -{# {% inline_rich_text field="answer" value="{{ item.answer }}" %}#} -{#{% endfor %}#} - - {% if module.enable_faq_schema %}