@hyperfixi/behaviors 2.2.1 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/all.browser.global.js +316 -54
- package/dist/all.browser.global.js.map +1 -1
- package/dist/autodismiss.browser.global.js +54 -2
- package/dist/autodismiss.browser.global.js.map +1 -1
- package/dist/behaviors/autodismiss.cjs +54 -18
- package/dist/behaviors/autodismiss.cjs.map +1 -1
- package/dist/behaviors/autodismiss.js +2 -2
- package/dist/behaviors/clickoutside.cjs +23 -4
- package/dist/behaviors/clickoutside.cjs.map +1 -1
- package/dist/behaviors/clickoutside.js +2 -2
- package/dist/behaviors/clipboard.cjs +43 -21
- package/dist/behaviors/clipboard.cjs.map +1 -1
- package/dist/behaviors/clipboard.js +2 -2
- package/dist/behaviors/focustrap.cjs +44 -3
- package/dist/behaviors/focustrap.cjs.map +1 -1
- package/dist/behaviors/focustrap.js +2 -2
- package/dist/behaviors/removable.cjs +7 -4
- package/dist/behaviors/removable.cjs.map +1 -1
- package/dist/behaviors/removable.js +2 -2
- package/dist/behaviors/resizable.cjs +22 -14
- package/dist/behaviors/resizable.cjs.map +1 -1
- package/dist/behaviors/resizable.js +2 -2
- package/dist/behaviors/scrollreveal.cjs +25 -13
- package/dist/behaviors/scrollreveal.cjs.map +1 -1
- package/dist/behaviors/scrollreveal.js +2 -2
- package/dist/behaviors/sortable.cjs +18 -12
- package/dist/behaviors/sortable.cjs.map +1 -1
- package/dist/behaviors/sortable.js +2 -2
- package/dist/behaviors/tabs.cjs +80 -11
- package/dist/behaviors/tabs.cjs.map +1 -1
- package/dist/behaviors/tabs.js +2 -2
- package/dist/behaviors/toggleable.cjs +5 -2
- package/dist/behaviors/toggleable.cjs.map +1 -1
- package/dist/behaviors/toggleable.js +2 -2
- package/dist/chunk-66U2RSYJ.js +100 -0
- package/dist/chunk-66U2RSYJ.js.map +1 -0
- package/dist/{chunk-2NSKQMNM.js → chunk-7O7UOSBH.js} +2 -2
- package/dist/{chunk-244WSZOL.js → chunk-EKKJVXDZ.js} +2 -2
- package/dist/{chunk-AFGA54SA.js → chunk-F3CASJ7Q.js} +2 -2
- package/dist/{chunk-YHQRFUWV.js → chunk-GALKOMJ5.js} +2 -2
- package/dist/{chunk-272NKUJ3.js → chunk-HMU342XE.js} +8 -5
- package/dist/chunk-HMU342XE.js.map +1 -0
- package/dist/chunk-HQDYH45I.js +137 -0
- package/dist/chunk-HQDYH45I.js.map +1 -0
- package/dist/{chunk-WTUVPVSD.js → chunk-IQM32TEY.js} +2 -2
- package/dist/{chunk-H5Y5ARYG.js → chunk-L52AGCMP.js} +2 -2
- package/dist/{chunk-H2MCHR5A.js → chunk-LQJOQTBZ.js} +2 -2
- package/dist/{chunk-7JDV2THA.js → chunk-MVNHMYIK.js} +11 -11
- package/dist/{chunk-BWZ6EGII.js → chunk-NC6I6T7T.js} +19 -13
- package/dist/{chunk-BWZ6EGII.js.map → chunk-NC6I6T7T.js.map} +1 -1
- package/dist/chunk-OJ3YWO3W.js +92 -0
- package/dist/chunk-OJ3YWO3W.js.map +1 -0
- package/dist/{chunk-64DIQGQI.js → chunk-SLOXO6IY.js} +24 -5
- package/dist/chunk-SLOXO6IY.js.map +1 -0
- package/dist/{chunk-RPERQTFU.js → chunk-TLLGH5KX.js} +2 -2
- package/dist/{chunk-V5IWDPDP.js → chunk-U5GNXZUF.js} +23 -15
- package/dist/{chunk-V5IWDPDP.js.map → chunk-U5GNXZUF.js.map} +1 -1
- package/dist/{chunk-GPTHAUWN.js → chunk-URZGNPTQ.js} +26 -14
- package/dist/chunk-URZGNPTQ.js.map +1 -0
- package/dist/chunk-WOTZO7K4.js +92 -0
- package/dist/chunk-WOTZO7K4.js.map +1 -0
- package/dist/{chunk-JKBWIJFI.js → chunk-WPOQIMCC.js} +2 -2
- package/dist/{chunk-WUHHMDAA.js → chunk-XYZ7FOXJ.js} +6 -3
- package/dist/{chunk-WUHHMDAA.js.map → chunk-XYZ7FOXJ.js.map} +1 -1
- package/dist/{chunk-DYHBKDKB.js → chunk-ZZ2WSAX3.js} +2 -2
- package/dist/clickoutside.browser.global.js +16 -5
- package/dist/clickoutside.browser.global.js.map +1 -1
- package/dist/clipboard.browser.global.js +43 -2
- package/dist/clipboard.browser.global.js.map +1 -1
- package/dist/core.browser.global.js +5 -2
- package/dist/core.browser.global.js.map +1 -1
- package/dist/focustrap.browser.global.js +46 -5
- package/dist/focustrap.browser.global.js.map +1 -1
- package/dist/index.cjs +321 -102
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +21 -21
- package/dist/loaders.cjs +321 -102
- package/dist/loaders.cjs.map +1 -1
- package/dist/loaders.js +11 -11
- package/dist/removable.browser.global.js +8 -5
- package/dist/removable.browser.global.js.map +1 -1
- package/dist/resizable.browser.global.js +24 -16
- package/dist/resizable.browser.global.js.map +1 -1
- package/dist/resolver.browser.global.js +407 -0
- package/dist/resolver.browser.global.js.map +1 -0
- package/dist/schemas/index.cjs +321 -102
- package/dist/schemas/index.cjs.map +1 -1
- package/dist/schemas/index.js +10 -10
- package/dist/scrollreveal.browser.global.js +27 -8
- package/dist/scrollreveal.browser.global.js.map +1 -1
- package/dist/sortable.browser.global.js +19 -13
- package/dist/sortable.browser.global.js.map +1 -1
- package/dist/tabs.browser.global.js +80 -2
- package/dist/tabs.browser.global.js.map +1 -1
- package/dist/toggleable.browser.global.js +6 -3
- package/dist/toggleable.browser.global.js.map +1 -1
- package/package.json +1 -1
- package/src/behavior-resolver.ts +91 -0
- package/src/browser-resolver-bundle.ts +42 -0
- package/src/schemas/autodismiss.schema.ts +54 -18
- package/src/schemas/clickoutside.schema.ts +22 -3
- package/src/schemas/clipboard.schema.ts +43 -21
- package/src/schemas/focustrap.schema.ts +44 -3
- package/src/schemas/removable.schema.ts +7 -4
- package/src/schemas/resizable.schema.ts +22 -14
- package/src/schemas/scrollreveal.schema.ts +25 -13
- package/src/schemas/sortable.schema.ts +18 -12
- package/src/schemas/tabs.schema.ts +80 -11
- package/src/schemas/toggleable.schema.ts +5 -2
- package/dist/chunk-272NKUJ3.js.map +0 -1
- package/dist/chunk-64DIQGQI.js.map +0 -1
- package/dist/chunk-GPTHAUWN.js.map +0 -1
- package/dist/chunk-GVJPA2EK.js +0 -68
- package/dist/chunk-GVJPA2EK.js.map +0 -1
- package/dist/chunk-QKDYW4VM.js +0 -70
- package/dist/chunk-QKDYW4VM.js.map +0 -1
- package/dist/chunk-RB7OB6OD.js +0 -51
- package/dist/chunk-RB7OB6OD.js.map +0 -1
- package/dist/chunk-ZQQZTMCJ.js +0 -64
- package/dist/chunk-ZQQZTMCJ.js.map +0 -1
- /package/dist/{chunk-2NSKQMNM.js.map → chunk-7O7UOSBH.js.map} +0 -0
- /package/dist/{chunk-244WSZOL.js.map → chunk-EKKJVXDZ.js.map} +0 -0
- /package/dist/{chunk-AFGA54SA.js.map → chunk-F3CASJ7Q.js.map} +0 -0
- /package/dist/{chunk-YHQRFUWV.js.map → chunk-GALKOMJ5.js.map} +0 -0
- /package/dist/{chunk-WTUVPVSD.js.map → chunk-IQM32TEY.js.map} +0 -0
- /package/dist/{chunk-H5Y5ARYG.js.map → chunk-L52AGCMP.js.map} +0 -0
- /package/dist/{chunk-H2MCHR5A.js.map → chunk-LQJOQTBZ.js.map} +0 -0
- /package/dist/{chunk-7JDV2THA.js.map → chunk-MVNHMYIK.js.map} +0 -0
- /package/dist/{chunk-RPERQTFU.js.map → chunk-TLLGH5KX.js.map} +0 -0
- /package/dist/{chunk-JKBWIJFI.js.map → chunk-WPOQIMCC.js.map} +0 -0
- /package/dist/{chunk-DYHBKDKB.js.map → chunk-ZZ2WSAX3.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/schemas/toggleable.schema.ts","../src/schemas/removable.schema.ts","../src/schemas/autodismiss.schema.ts","../src/schemas/clipboard.schema.ts","../src/schemas/draggable.schema.ts","../src/schemas/clickoutside.schema.ts","../src/schemas/scrollreveal.schema.ts","../src/schemas/tabs.schema.ts","../src/schemas/focustrap.schema.ts","../src/schemas/sortable.schema.ts","../src/schemas/resizable.schema.ts","../src/behavior-resolver.ts","../src/browser-resolver-bundle.ts"],"sourcesContent":["import type { BehaviorSchema } from './types';\n\n/**\n * Toggleable Behavior Schema\n *\n * Toggles a CSS class on click.\n * Useful for accordions, dropdowns, and toggle buttons.\n */\nexport const toggleableSchema: BehaviorSchema = {\n name: 'Toggleable',\n category: 'form',\n tier: 'core',\n version: '1.0.0',\n description: 'Toggles a CSS class on click',\n parameters: [\n {\n name: 'cls',\n type: 'string',\n optional: true,\n default: 'active',\n description: 'CSS class to toggle',\n },\n {\n name: 'target',\n type: 'selector',\n optional: true,\n default: 'me',\n description: 'Element to toggle the class on',\n },\n ],\n events: [\n { name: 'toggleable:on', description: 'Fired when class is added' },\n { name: 'toggleable:off', description: 'Fired when class is removed' },\n ],\n source: `\nbehavior Toggleable(cls, target)\n init\n if cls is undefined\n set cls to \"active\"\n end\n if target is undefined\n set target to me\n end\n end\n on click\n toggle .{cls} on target\n js(target, cls)\n var eventName = target.classList.contains(cls) ? 'toggleable:on' : 'toggleable:off';\n target.dispatchEvent(new CustomEvent(eventName, { bubbles: true }));\n end\n end\nend`.trim(),\n};\n","import type { BehaviorSchema } from './types';\n\n/**\n * Removable Behavior Schema\n *\n * Removes an element when a trigger is clicked.\n * Supports optional confirmation and transition effects.\n *\n * @since 1.2.0 — `trigger` parameter renamed to `triggerEl` to avoid\n * shadowing the hyperscript `trigger` command keyword. Users migrating\n * from v1.x should update: `install Removable(triggerEl: .close-btn)`.\n */\nexport const removableSchema: BehaviorSchema = {\n name: 'Removable',\n category: 'data',\n tier: 'common',\n version: '1.2.0',\n description: 'Makes elements removable on click',\n parameters: [\n {\n name: 'triggerEl',\n type: 'selector',\n optional: true,\n default: 'me',\n description: 'Element that triggers removal (e.g., a close button)',\n },\n {\n name: 'confirmRemoval',\n type: 'boolean',\n optional: true,\n default: false,\n description: 'Show confirmation dialog before removal',\n },\n {\n name: 'effect',\n type: 'string',\n optional: true,\n default: 'none',\n enum: ['fade', 'none'],\n description: 'Transition effect: \"fade\" or \"none\"',\n },\n ],\n events: [\n { name: 'removable:before', description: 'Fired before removal (cancelable)' },\n { name: 'removable:removed', description: 'Fired after removal' },\n ],\n source: `\nbehavior Removable(triggerEl, confirmRemoval, effect)\n init\n if triggerEl is undefined\n set triggerEl to me\n end\n end\n on click from triggerEl\n if confirmRemoval\n js(me)\n if (!window.confirm(\"Are you sure?\")) return \"cancel\";\n end\n if it is \"cancel\"\n halt\n end\n end\n trigger removable:before\n if effect is \"fade\"\n transition opacity to 0 over 300ms\n end\n trigger removable:removed\n remove me\n end\nend\n`.trim(),\n};\n","import type { BehaviorSchema } from './types';\n\n/**\n * AutoDismiss Behavior Schema\n *\n * Auto-removes flash messages and toasts after a configurable delay.\n * Supports pause-on-hover and fade effect.\n */\nexport const autoDismissSchema: BehaviorSchema = {\n name: 'AutoDismiss',\n category: 'ui',\n tier: 'core',\n version: '1.0.0',\n description: 'Auto-removes elements after a delay with optional pause-on-hover',\n parameters: [\n {\n name: 'delay',\n type: 'number',\n optional: true,\n default: 5000,\n description: 'Time in ms before the element is removed',\n },\n {\n name: 'pauseOnHover',\n type: 'boolean',\n optional: true,\n default: true,\n description: 'Pause the countdown when the mouse hovers over the element',\n },\n {\n name: 'effect',\n type: 'string',\n optional: true,\n default: 'none',\n enum: ['fade', 'none'],\n description: 'Transition effect before removal: \"fade\" or \"none\"',\n },\n ],\n events: [\n { name: 'autodismiss:start', description: 'Fired when the countdown timer starts' },\n {\n name: 'autodismiss:dismissed',\n description: 'Fired before removal (cancelable via preventDefault)',\n },\n { name: 'autodismiss:paused', description: 'Fired when the timer is paused on hover' },\n { name: 'autodismiss:resumed', description: 'Fired when the timer resumes on mouseleave' },\n ],\n source: `\nbehavior AutoDismiss(delay, pauseOnHover, effect)\n init\n if delay is undefined\n set delay to 5000\n end\n if pauseOnHover is undefined\n set pauseOnHover to true\n end\n if effect is undefined\n set effect to \"none\"\n end\n js(me, delay, effect, pauseOnHover)\n me.dispatchEvent(new CustomEvent('autodismiss:start', { bubbles: true }));\n var remaining = delay;\n var startedAt = Date.now();\n var timerId = null;\n function dismiss() {\n var ev = new CustomEvent('autodismiss:dismissed', { bubbles: true, cancelable: true });\n me.dispatchEvent(ev);\n if (ev.defaultPrevented) return;\n if (effect === 'fade') {\n me.style.transition = 'opacity 300ms';\n me.style.opacity = '0';\n setTimeout(function() { me.remove(); }, 300);\n } else {\n me.remove();\n }\n }\n function start() {\n startedAt = Date.now();\n timerId = setTimeout(dismiss, remaining);\n }\n start();\n if (pauseOnHover) {\n me.addEventListener('mouseenter', function() {\n if (timerId != null) {\n clearTimeout(timerId);\n timerId = null;\n remaining -= Date.now() - startedAt;\n if (remaining < 0) remaining = 0;\n me.dispatchEvent(new CustomEvent('autodismiss:paused', { bubbles: true }));\n }\n });\n me.addEventListener('mouseleave', function() {\n if (timerId == null && me.isConnected) {\n me.dispatchEvent(new CustomEvent('autodismiss:resumed', { bubbles: true }));\n start();\n }\n });\n }\n end\n end\nend`.trim(),\n};\n","import type { BehaviorSchema } from './types';\n\n/**\n * Clipboard Behavior Schema\n *\n * Copies text to clipboard on click with visual feedback.\n * Uses the Clipboard API with execCommand fallback.\n */\nexport const clipboardSchema: BehaviorSchema = {\n name: 'Clipboard',\n category: 'ui',\n tier: 'core',\n version: '1.0.0',\n description: 'Copies text to clipboard on click with visual feedback',\n parameters: [\n {\n name: 'text',\n type: 'string',\n optional: true,\n description: 'Literal text to copy (takes priority over source)',\n },\n {\n name: 'source',\n type: 'selector',\n optional: true,\n default: 'me',\n description: 'Element whose textContent or value is copied',\n },\n {\n name: 'feedback',\n type: 'selector',\n optional: true,\n description: 'Element to show .copied feedback on (defaults to the installed element)',\n },\n {\n name: 'feedbackDuration',\n type: 'number',\n optional: true,\n default: 2000,\n description: 'Duration in ms to show .copied class feedback',\n },\n ],\n events: [\n { name: 'clipboard:copied', description: 'Fired after text is copied successfully' },\n { name: 'clipboard:error', description: 'Fired when clipboard write fails' },\n ],\n requirements: [\n 'navigator.clipboard.writeText() requires HTTPS or localhost',\n 'Falls back to document.execCommand(\"copy\") for older browsers',\n ],\n source: `\nbehavior Clipboard(text, source, feedback, feedbackDuration)\n init\n if feedbackDuration is undefined\n set feedbackDuration to 2000\n end\n if source is undefined\n set source to me\n end\n end\n on click\n if text is not undefined\n set copyText to text\n else\n set copyText to source's textContent\n end\n js(me, copyText, feedback, feedbackDuration)\n async function copyToClipboard(t) {\n if (navigator.clipboard && navigator.clipboard.writeText) {\n await navigator.clipboard.writeText(t);\n return;\n }\n var ta = document.createElement('textarea');\n ta.value = t;\n ta.style.position = 'fixed';\n ta.style.opacity = '0';\n document.body.appendChild(ta);\n ta.select();\n try { document.execCommand('copy'); } finally { document.body.removeChild(ta); }\n }\n try {\n await copyToClipboard(copyText);\n var feedbackEl = feedback ? (typeof feedback === 'string' ? document.querySelector(feedback) : feedback) : me;\n if (!feedbackEl) feedbackEl = me;\n feedbackEl.classList.add('copied');\n me.dispatchEvent(new CustomEvent('clipboard:copied', { bubbles: true, detail: { text: copyText } }));\n setTimeout(function() { feedbackEl.classList.remove('copied'); }, feedbackDuration);\n } catch(err) {\n me.dispatchEvent(new CustomEvent('clipboard:error', { bubbles: true, detail: { error: err } }));\n }\n end\n end\nend`.trim(),\n};\n","import type { BehaviorSchema } from './types';\n\n/**\n * Draggable Behavior Schema\n *\n * Makes elements draggable with pointer events.\n * Supports custom drag handles and lifecycle events.\n */\nexport const draggableSchema: BehaviorSchema = {\n name: 'Draggable',\n category: 'ui',\n tier: 'core',\n version: '1.0.0',\n description: 'Makes elements draggable with pointer events',\n parameters: [\n {\n name: 'dragHandle',\n type: 'selector',\n optional: true,\n default: 'me',\n description: 'CSS selector for the drag handle element',\n },\n ],\n events: [\n { name: 'draggable:start', description: 'Fired when drag begins' },\n { name: 'draggable:move', description: 'Fired during each movement' },\n { name: 'draggable:end', description: 'Fired when drag completes' },\n ],\n requirements: ['position: absolute or position: fixed on the element'],\n source: `\nbehavior Draggable(dragHandle)\n init\n if no dragHandle set dragHandle to me\n end\n on pointerdown(clientX, clientY) from dragHandle\n halt the event\n trigger draggable:start\n measure x\n set startX to it\n measure y\n set startY to it\n set xoff to clientX - startX\n set yoff to clientY - startY\n repeat until event pointerup from document\n wait for pointermove(clientX, clientY) or\n pointerup(clientX, clientY) from document\n add { left: \\${clientX - xoff}px; top: \\${clientY - yoff}px; }\n trigger draggable:move\n end\n trigger draggable:end\n end\nend\n`.trim(),\n};\n","import type { BehaviorSchema } from './types';\n\n/**\n * ClickOutside Behavior Schema\n *\n * Fires an event when the user clicks outside the element.\n * Uses pointerdown instead of click to avoid timing issues.\n */\nexport const clickOutsideSchema: BehaviorSchema = {\n name: 'ClickOutside',\n category: 'ui',\n tier: 'core',\n version: '1.0.0',\n description: 'Fires an event when the user clicks outside the element',\n parameters: [\n {\n name: 'active',\n type: 'boolean',\n optional: true,\n default: true,\n description: 'Whether the listener is active (can be toggled programmatically)',\n },\n ],\n events: [\n { name: 'clickoutside', description: 'Fired when a pointer press occurs outside the element' },\n {\n name: 'clickoutside:activate',\n description: 'Listen for this event to programmatically activate detection',\n },\n {\n name: 'clickoutside:deactivate',\n description: 'Listen for this event to programmatically deactivate detection',\n },\n ],\n requirements: ['Uses pointerdown instead of click to avoid timing issues with removed elements'],\n source: `\nbehavior ClickOutside(active)\n init\n if active is undefined\n set active to true\n end\n end\n on pointerdown from document\n js(me, active)\n if (!me.isConnected) return;\n if (active && !me.contains(event.target)) {\n me.dispatchEvent(new CustomEvent('clickoutside', { bubbles: true }));\n }\n end\n end\n on clickoutside:activate\n set active to true\n end\n on clickoutside:deactivate\n set active to false\n end\nend`.trim(),\n};\n","import type { BehaviorSchema } from './types';\n\n/**\n * ScrollReveal Behavior Schema\n *\n * Adds a class or fires events when the element enters or exits the viewport.\n * Uses the IntersectionObserver web standard API.\n */\nexport const scrollRevealSchema: BehaviorSchema = {\n name: 'ScrollReveal',\n category: 'layout',\n tier: 'common',\n version: '1.0.0',\n description: 'Adds a class when the element enters the viewport via IntersectionObserver',\n parameters: [\n {\n name: 'cls',\n type: 'string',\n optional: true,\n default: 'revealed',\n description: 'CSS class added when element enters viewport',\n },\n {\n name: 'threshold',\n type: 'number',\n optional: true,\n default: 0.1,\n description: 'Intersection ratio threshold (0-1) for triggering',\n },\n {\n name: 'once',\n type: 'boolean',\n optional: true,\n default: true,\n description: 'If true, disconnect observer after first intersection',\n },\n ],\n events: [\n { name: 'scrollreveal:enter', description: 'Fired when the element enters the viewport' },\n { name: 'scrollreveal:exit', description: 'Fired when the element exits the viewport' },\n ],\n requirements: ['Uses IntersectionObserver API (supported in all modern browsers)'],\n source: `\nbehavior ScrollReveal(cls, threshold, once)\n init\n if cls is undefined\n set cls to \"revealed\"\n end\n if threshold is undefined\n set threshold to 0.1\n end\n if once is undefined\n set once to true\n end\n js(me, cls, threshold, once)\n var obs = new IntersectionObserver(function(entries) {\n for (var i = 0; i < entries.length; i++) {\n if (entries[i].isIntersecting) {\n me.classList.add(cls);\n me.dispatchEvent(new CustomEvent('scrollreveal:enter', { bubbles: true }));\n if (once) obs.disconnect();\n } else if (!once) {\n me.classList.remove(cls);\n me.dispatchEvent(new CustomEvent('scrollreveal:exit', { bubbles: true }));\n }\n }\n }, { threshold: threshold });\n obs.observe(me);\n end\n end\nend`.trim(),\n};\n","import type { BehaviorSchema } from './types';\n\nexport const tabsSchema: BehaviorSchema = {\n name: 'Tabs',\n category: 'ui',\n tier: 'core',\n version: '1.0.0',\n description:\n 'WAI-ARIA compliant tabs with roving tabindex keyboard navigation. ' +\n 'Auto-wires role, aria-selected, aria-controls, and aria-labelledby attributes.',\n parameters: [\n {\n name: 'orientation',\n type: 'string',\n optional: true,\n default: 'horizontal',\n enum: ['horizontal', 'vertical'],\n description: 'Arrow key direction: horizontal (Left/Right) or vertical (Up/Down)',\n },\n {\n name: 'activeTab',\n type: 'number',\n optional: true,\n default: 0,\n description: 'Initial active tab index (zero-based)',\n },\n {\n name: 'wrap',\n type: 'boolean',\n optional: true,\n default: true,\n description: 'Wrap to first/last tab when navigating past the end',\n },\n {\n name: 'activeClass',\n type: 'string',\n optional: true,\n default: 'active',\n description: 'CSS class applied to the active tab and its panel',\n },\n ],\n events: [\n {\n name: 'tabs:change',\n description: 'Fired before tab selection changes (cancelable via preventDefault)',\n },\n { name: 'tabs:changed', description: 'Fired after tab selection has changed' },\n ],\n requirements: [\n 'Sets role=\"tablist\" on the tab container',\n 'Sets role=\"tab\" on tab buttons and role=\"tabpanel\" on content panels',\n 'Manages aria-selected, aria-controls, aria-labelledby, and tabindex',\n 'Keyboard: Arrow keys navigate, Home/End jump to first/last, Tab exits tablist',\n ],\n source: `\nbehavior Tabs(orientation, activeTab, wrap, activeClass)\n init\n if orientation is undefined\n set orientation to \"horizontal\"\n end\n if activeTab is undefined\n set activeTab to 0\n end\n if wrap is undefined\n set wrap to true\n end\n if activeClass is undefined\n set activeClass to \"active\"\n end\n js(me, orientation, activeTab, wrap, activeClass)\n var tabs = Array.from(me.querySelectorAll('[role=\"tab\"]'));\n var panels = Array.from(me.querySelectorAll('[role=\"tabpanel\"]'));\n if (tabs.length === 0 || panels.length === 0) return;\n var tablist = me.querySelector('[role=\"tablist\"]') || tabs[0].parentElement;\n if (tablist) tablist.setAttribute('aria-orientation', orientation);\n var count = Math.min(tabs.length, panels.length);\n var idN = 0;\n for (var i = 0; i < count; i++) {\n if (!tabs[i].id) tabs[i].id = 'tab-' + (++idN);\n if (!panels[i].id) panels[i].id = 'tabpanel-' + idN;\n tabs[i].setAttribute('aria-controls', panels[i].id);\n panels[i].setAttribute('aria-labelledby', tabs[i].id);\n }\n var cur = Math.max(0, Math.min(activeTab, count - 1));\n function activate(idx, prev) {\n if (idx === prev || idx < 0 || idx >= count) return false;\n var ev = new CustomEvent('tabs:change', { bubbles: true, cancelable: true, detail: { index: idx, previousIndex: prev } });\n me.dispatchEvent(ev);\n if (ev.defaultPrevented) return false;\n if (prev >= 0 && prev < count) {\n tabs[prev].setAttribute('aria-selected', 'false');\n tabs[prev].setAttribute('tabindex', '-1');\n tabs[prev].classList.remove(activeClass);\n panels[prev].setAttribute('aria-hidden', 'true');\n panels[prev].classList.remove(activeClass);\n }\n tabs[idx].setAttribute('aria-selected', 'true');\n tabs[idx].setAttribute('tabindex', '0');\n tabs[idx].classList.add(activeClass);\n panels[idx].setAttribute('aria-hidden', 'false');\n panels[idx].classList.add(activeClass);\n cur = idx;\n me.dispatchEvent(new CustomEvent('tabs:changed', { bubbles: true, detail: { index: idx } }));\n return true;\n }\n for (var j = 0; j < count; j++) {\n tabs[j].setAttribute('aria-selected', 'false');\n tabs[j].setAttribute('tabindex', '-1');\n panels[j].setAttribute('aria-hidden', 'true');\n panels[j].classList.remove(activeClass);\n }\n tabs[cur].setAttribute('aria-selected', 'true');\n tabs[cur].setAttribute('tabindex', '0');\n tabs[cur].classList.add(activeClass);\n panels[cur].setAttribute('aria-hidden', 'false');\n panels[cur].classList.add(activeClass);\n for (var k = 0; k < count; k++) {\n (function(idx) {\n tabs[idx].addEventListener('click', function() { if (activate(idx, cur)) tabs[idx].focus(); });\n })(k);\n }\n (tablist || me).addEventListener('keydown', function(e) {\n var nk = orientation === 'horizontal' ? 'ArrowRight' : 'ArrowDown';\n var pk = orientation === 'horizontal' ? 'ArrowLeft' : 'ArrowUp';\n var next = null;\n if (e.key === nk) { next = cur + 1; if (next >= count) next = wrap ? 0 : null; }\n else if (e.key === pk) { next = cur - 1; if (next < 0) next = wrap ? count - 1 : null; }\n else if (e.key === 'Home') next = 0;\n else if (e.key === 'End') next = count - 1;\n if (next !== null) { e.preventDefault(); if (activate(next, cur)) tabs[next].focus(); }\n });\n end\n end\nend`.trim(),\n};\n","import type { BehaviorSchema } from './types';\n\n/**\n * FocusTrap Behavior Schema\n *\n * Confines Tab navigation inside an element and restores focus on release.\n * Manages aria-modal for accessibility compliance.\n */\nexport const focusTrapSchema: BehaviorSchema = {\n name: 'FocusTrap',\n category: 'ui',\n tier: 'core',\n version: '1.0.0',\n description: 'Confines Tab navigation inside an element with ARIA support',\n parameters: [\n {\n name: 'active',\n type: 'boolean',\n optional: true,\n default: true,\n description: 'Whether the trap is active on install',\n },\n {\n name: 'initialFocus',\n type: 'selector',\n optional: true,\n description: 'Element to focus when the trap activates',\n },\n {\n name: 'returnFocus',\n type: 'boolean',\n optional: true,\n default: true,\n description: 'Restore focus to the previously focused element on deactivation',\n },\n ],\n events: [\n { name: 'focustrap:activated', description: 'Fired when the trap is activated' },\n { name: 'focustrap:deactivated', description: 'Fired when the trap is deactivated' },\n ],\n requirements: [\n 'Sets aria-modal=\"true\" on the element when active',\n 'Listens for focustrap:activate and focustrap:deactivate custom events for programmatic control',\n ],\n source: `\nbehavior FocusTrap(active, initialFocus, returnFocus)\n init\n if active is undefined\n set active to true\n end\n if returnFocus is undefined\n set returnFocus to true\n end\n js(me, active, initialFocus, returnFocus)\n var FOCUSABLE = 'a[href],button:not(:disabled),input:not(:disabled),select:not(:disabled),textarea:not(:disabled),[tabindex]:not([tabindex=\"-1\"])';\n var isActive = false;\n var previouslyFocused = null;\n function getFocusable() { return Array.from(me.querySelectorAll(FOCUSABLE)); }\n function activate() {\n if (isActive) return;\n isActive = true;\n previouslyFocused = document.activeElement;\n me.setAttribute('aria-modal', 'true');\n var initEl = initialFocus ? (typeof initialFocus === 'string' ? me.querySelector(initialFocus) : initialFocus) : null;\n if (initEl) { initEl.focus(); } else { var f = getFocusable(); if (f.length) f[0].focus(); }\n me.dispatchEvent(new CustomEvent('focustrap:activated', { bubbles: true }));\n }\n function deactivate() {\n if (!isActive) return;\n isActive = false;\n me.removeAttribute('aria-modal');\n if (returnFocus && previouslyFocused instanceof HTMLElement) previouslyFocused.focus();\n previouslyFocused = null;\n me.dispatchEvent(new CustomEvent('focustrap:deactivated', { bubbles: true }));\n }\n me.addEventListener('keydown', function(e) {\n if (!isActive || e.key !== 'Tab') return;\n var focusable = getFocusable();\n if (focusable.length === 0) { e.preventDefault(); return; }\n e.preventDefault();\n var idx = focusable.indexOf(document.activeElement);\n if (e.shiftKey) {\n focusable[idx <= 0 ? focusable.length - 1 : idx - 1].focus();\n } else {\n focusable[idx >= focusable.length - 1 ? 0 : idx + 1].focus();\n }\n });\n me.addEventListener('focustrap:activate', function() { activate(); });\n me.addEventListener('focustrap:deactivate', function() { deactivate(); });\n if (active) activate();\n end\n end\nend`.trim(),\n};\n","import type { BehaviorSchema } from './types';\n\n/**\n * Sortable Behavior Schema\n *\n * Drag-and-drop reordering of list items.\n * Apply to a container element; children become sortable.\n *\n * Note: This behavior fires lifecycle events but does NOT automatically\n * reorder DOM elements. Users must handle actual reordering in their\n * `sortable:move` event handlers.\n */\nexport const sortableSchema: BehaviorSchema = {\n name: 'Sortable',\n category: 'ui',\n tier: 'common',\n version: '1.0.0',\n description: 'Makes child elements reorderable via drag-and-drop',\n parameters: [\n {\n name: 'handle',\n type: 'selector',\n optional: true,\n default: 'none',\n description: 'CSS selector for drag handles within items',\n },\n {\n name: 'dragClass',\n type: 'string',\n optional: true,\n default: 'sorting',\n description: 'CSS class added to item during drag',\n },\n ],\n events: [\n { name: 'sortable:start', description: 'Fired when drag begins' },\n {\n name: 'sortable:move',\n description: 'Fired during drag — handle this event to reorder DOM elements',\n },\n { name: 'sortable:end', description: 'Fired when drag completes' },\n ],\n requirements: ['Users must handle DOM reordering in sortable:move event handlers'],\n source: `\nbehavior Sortable(handle, dragClass)\n init\n if dragClass is undefined\n set dragClass to \"sorting\"\n end\n end\n on pointerdown(clientY) from me\n js(me, handle, event)\n var target = event.target;\n var item = target.closest(\"li\");\n if (!item || !me.contains(item)) return false;\n if (handle && !target.closest(handle)) return false;\n event.preventDefault();\n event.stopPropagation();\n return true;\n end\n if it is false\n exit\n end\n add .{dragClass} to me\n trigger sortable:start on me\n repeat until event pointerup from document\n wait for pointermove(clientY) from document\n trigger sortable:move on me\n end\n remove .{dragClass} from me\n trigger sortable:end on me\n end\nend`.trim(),\n};\n","import type { BehaviorSchema } from './types';\n\n/**\n * Resizable Behavior Schema\n *\n * Makes elements resizable by dragging edges or corners.\n * Supports minimum/maximum dimensions and resize handles.\n */\nexport const resizableSchema: BehaviorSchema = {\n name: 'Resizable',\n category: 'ui',\n tier: 'optional',\n version: '1.0.0',\n description: 'Makes elements resizable by dragging',\n parameters: [\n {\n name: 'handle',\n type: 'selector',\n optional: true,\n default: 'me',\n description: 'CSS selector for the resize handle (defaults to the element itself)',\n },\n {\n name: 'minWidth',\n type: 'number',\n optional: true,\n default: 50,\n description: 'Minimum width in pixels',\n },\n {\n name: 'minHeight',\n type: 'number',\n optional: true,\n default: 50,\n description: 'Minimum height in pixels',\n },\n {\n name: 'maxWidth',\n type: 'number',\n optional: true,\n default: 9999,\n description: 'Maximum width in pixels',\n },\n {\n name: 'maxHeight',\n type: 'number',\n optional: true,\n default: 9999,\n description: 'Maximum height in pixels',\n },\n ],\n events: [\n { name: 'resizable:start', description: 'Fired when resize begins' },\n { name: 'resizable:resize', description: 'Fired during resize' },\n { name: 'resizable:end', description: 'Fired when resize completes' },\n ],\n source: `\nbehavior Resizable(handle, minWidth, minHeight, maxWidth, maxHeight)\n init\n if handle is undefined\n set handle to me\n end\n if minWidth is undefined\n set minWidth to 50\n end\n if minHeight is undefined\n set minHeight to 50\n end\n if maxWidth is undefined\n set maxWidth to 9999\n end\n if maxHeight is undefined\n set maxHeight to 9999\n end\n end\n on pointerdown(clientX, clientY) from handle\n halt the event\n trigger resizable:start\n measure width\n set startWidth to it\n measure height\n set startHeight to it\n set startX to clientX\n set startY to clientY\n repeat until event pointerup from document\n wait for pointermove(clientX, clientY) or pointerup from document\n js(startWidth, startHeight, clientX, clientY, startX, startY, minWidth, maxWidth, minHeight, maxHeight, me)\n var nw = Math.max(minWidth, Math.min(maxWidth, startWidth + (clientX - startX)));\n var nh = Math.max(minHeight, Math.min(maxHeight, startHeight + (clientY - startY)));\n me.style.width = nw + 'px';\n me.style.height = nh + 'px';\n end\n trigger resizable:resize\n end\n trigger resizable:end\n end\nend\n`.trim(),\n};\n","/**\n * Behavior Resolver — Lazy compilation of hyperscript behaviors\n *\n * Provides a resolver function that compiles behavior source strings on demand.\n * When the runtime encounters `install X` and X isn't registered, it calls\n * the resolver. If the resolver has source for X, it compiles it, registers\n * the behavior, and installation proceeds normally.\n *\n * @example\n * ```typescript\n * import { createBehaviorResolver } from '@hyperfixi/behaviors/resolver';\n *\n * const resolve = createBehaviorResolver(window.hyperfixi, window._hyperscript.behaviors);\n * window._hyperscript.behaviors.resolve = resolve;\n *\n * // Now `install Toggleable` will compile the behavior on first use\n * ```\n */\n\nimport { toggleableSchema } from './schemas/toggleable.schema';\nimport { removableSchema } from './schemas/removable.schema';\nimport { autoDismissSchema } from './schemas/autodismiss.schema';\nimport { clipboardSchema } from './schemas/clipboard.schema';\nimport { draggableSchema } from './schemas/draggable.schema';\nimport { clickOutsideSchema } from './schemas/clickoutside.schema';\nimport { scrollRevealSchema } from './schemas/scrollreveal.schema';\nimport { tabsSchema } from './schemas/tabs.schema';\nimport { focusTrapSchema } from './schemas/focustrap.schema';\nimport { sortableSchema } from './schemas/sortable.schema';\nimport { resizableSchema } from './schemas/resizable.schema';\n\nexport const BEHAVIOR_SOURCES: Record<string, string> = {\n Toggleable: toggleableSchema.source,\n Removable: removableSchema.source,\n AutoDismiss: autoDismissSchema.source,\n Clipboard: clipboardSchema.source,\n Draggable: draggableSchema.source,\n ClickOutside: clickOutsideSchema.source,\n ScrollReveal: scrollRevealSchema.source,\n Tabs: tabsSchema.source,\n FocusTrap: focusTrapSchema.source,\n Sortable: sortableSchema.source,\n Resizable: resizableSchema.source,\n};\n\ninterface CompileResult {\n ok: boolean;\n ast?: any;\n errors?: unknown[];\n}\n\ninterface BehaviorAPI {\n set(name: string, definition: any): void;\n}\n\ninterface HyperFixiAPI {\n compileSync(code: string, options?: { traditional?: boolean }): CompileResult;\n}\n\n/**\n * Create a behavior resolver that compiles hyperscript source on demand.\n *\n * The returned function is meant to be assigned to `_hyperscript.behaviors.resolve`.\n * When called with a behavior name, it looks up the source, compiles it,\n * and registers the resulting AST in the behavior registry.\n *\n * @param hyperfixi - The hyperfixi API (needs compileSync)\n * @param behaviorAPI - The behavior registry API (needs set)\n * @returns Resolver function: (name: string) => boolean\n */\nexport function createBehaviorResolver(\n hyperfixi: HyperFixiAPI,\n behaviorAPI: BehaviorAPI\n): (name: string) => boolean {\n return (name: string): boolean => {\n const source = BEHAVIOR_SOURCES[name];\n if (!source) return false;\n\n const result = hyperfixi.compileSync(source, { traditional: true });\n if (!result.ok || !result.ast) return false;\n\n const ast = result.ast as any;\n behaviorAPI.set(name, {\n name: ast.name,\n parameters: ast.parameters,\n eventHandlers: ast.eventHandlers,\n initBlock: ast.initBlock,\n });\n return true;\n };\n}\n","/**\n * Browser Behavior Resolver Bundle\n *\n * Pre-registers all standard behavior definitions with the hyperfixi runtime.\n * Include after hyperfixi.js — all standard behaviors become available.\n *\n * Usage:\n * <script src=\"hyperfixi.js\"></script>\n * <script src=\"hyperfixi-behaviors.js\"></script>\n * <!-- install Toggleable, Draggable, etc. just work -->\n */\n\nimport { BEHAVIOR_SOURCES } from './behavior-resolver';\n\nfunction init() {\n const hf = (window as any).hyperfixi;\n if (!hf?.compileSync || !hf?.execute) return;\n\n // Compile and register each behavior definition with the runtime.\n // This is equivalent to having them in a <script type=\"text/hyperscript\"> block.\n for (const [name, source] of Object.entries(BEHAVIOR_SOURCES)) {\n const result = hf.compileSync(source, { traditional: true });\n if (result?.ok && result.ast) {\n // execute() registers the behavior in the runtime's behaviorRegistry\n hf.execute(result.ast).catch(() => {\n // Async — errors handled silently\n });\n }\n }\n\n // Re-scan: the attribute processor may have already processed elements\n // and failed (behaviors weren't registered). Reset and re-init.\n const ap = hf.attributeProcessor;\n if (ap) {\n ap.reset();\n ap.init();\n }\n}\n\nif (typeof window !== 'undefined') {\n init();\n}\n"],"mappings":"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","names":["toggleableSchema","removableSchema","autoDismissSchema","clipboardSchema","draggableSchema","clickOutsideSchema","scrollRevealSchema","tabsSchema","focusTrapSchema","sortableSchema","resizableSchema","BEHAVIOR_SOURCES","toggleableSchema","removableSchema","autoDismissSchema","clipboardSchema","draggableSchema","clickOutsideSchema","scrollRevealSchema","tabsSchema","focusTrapSchema","sortableSchema","resizableSchema","init","hf","name","source","BEHAVIOR_SOURCES","result","ap"]}
|
package/dist/schemas/index.cjs
CHANGED
|
@@ -120,27 +120,33 @@ var sortableSchema = {
|
|
|
120
120
|
source: `
|
|
121
121
|
behavior Sortable(handle, dragClass)
|
|
122
122
|
init
|
|
123
|
-
if
|
|
123
|
+
if dragClass is undefined
|
|
124
|
+
set dragClass to "sorting"
|
|
125
|
+
end
|
|
124
126
|
end
|
|
125
|
-
on pointerdown(
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
if
|
|
127
|
+
on pointerdown(clientY) from me
|
|
128
|
+
js(me, handle, event)
|
|
129
|
+
var target = event.target;
|
|
130
|
+
var item = target.closest("li");
|
|
131
|
+
if (!item || !me.contains(item)) return false;
|
|
132
|
+
if (handle && !target.closest(handle)) return false;
|
|
133
|
+
event.preventDefault();
|
|
134
|
+
event.stopPropagation();
|
|
135
|
+
return true;
|
|
131
136
|
end
|
|
132
|
-
|
|
133
|
-
|
|
137
|
+
if it is false
|
|
138
|
+
exit
|
|
139
|
+
end
|
|
140
|
+
add .{dragClass} to me
|
|
134
141
|
trigger sortable:start on me
|
|
135
142
|
repeat until event pointerup from document
|
|
136
143
|
wait for pointermove(clientY) from document
|
|
137
144
|
trigger sortable:move on me
|
|
138
145
|
end
|
|
139
|
-
remove dragClass from
|
|
146
|
+
remove .{dragClass} from me
|
|
140
147
|
trigger sortable:end on me
|
|
141
148
|
end
|
|
142
|
-
end
|
|
143
|
-
`.trim()
|
|
149
|
+
end`.trim()
|
|
144
150
|
};
|
|
145
151
|
|
|
146
152
|
// src/schemas/resizable.schema.ts
|
|
@@ -195,11 +201,21 @@ var resizableSchema = {
|
|
|
195
201
|
source: `
|
|
196
202
|
behavior Resizable(handle, minWidth, minHeight, maxWidth, maxHeight)
|
|
197
203
|
init
|
|
198
|
-
if
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
if
|
|
202
|
-
|
|
204
|
+
if handle is undefined
|
|
205
|
+
set handle to me
|
|
206
|
+
end
|
|
207
|
+
if minWidth is undefined
|
|
208
|
+
set minWidth to 50
|
|
209
|
+
end
|
|
210
|
+
if minHeight is undefined
|
|
211
|
+
set minHeight to 50
|
|
212
|
+
end
|
|
213
|
+
if maxWidth is undefined
|
|
214
|
+
set maxWidth to 9999
|
|
215
|
+
end
|
|
216
|
+
if maxHeight is undefined
|
|
217
|
+
set maxHeight to 9999
|
|
218
|
+
end
|
|
203
219
|
end
|
|
204
220
|
on pointerdown(clientX, clientY) from handle
|
|
205
221
|
halt the event
|
|
@@ -211,15 +227,13 @@ behavior Resizable(handle, minWidth, minHeight, maxWidth, maxHeight)
|
|
|
211
227
|
set startX to clientX
|
|
212
228
|
set startY to clientY
|
|
213
229
|
repeat until event pointerup from document
|
|
214
|
-
wait for pointermove(clientX, clientY) or
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
if newHeight > maxHeight set newHeight to maxHeight
|
|
222
|
-
add { width: \${newWidth}px; height: \${newHeight}px; }
|
|
230
|
+
wait for pointermove(clientX, clientY) or pointerup from document
|
|
231
|
+
js(startWidth, startHeight, clientX, clientY, startX, startY, minWidth, maxWidth, minHeight, maxHeight, me)
|
|
232
|
+
var nw = Math.max(minWidth, Math.min(maxWidth, startWidth + (clientX - startX)));
|
|
233
|
+
var nh = Math.max(minHeight, Math.min(maxHeight, startHeight + (clientY - startY)));
|
|
234
|
+
me.style.width = nw + 'px';
|
|
235
|
+
me.style.height = nh + 'px';
|
|
236
|
+
end
|
|
223
237
|
trigger resizable:resize
|
|
224
238
|
end
|
|
225
239
|
trigger resizable:end
|
|
@@ -244,7 +258,7 @@ var removableSchema = {
|
|
|
244
258
|
description: "Element that triggers removal (e.g., a close button)"
|
|
245
259
|
},
|
|
246
260
|
{
|
|
247
|
-
name: "
|
|
261
|
+
name: "confirmRemoval",
|
|
248
262
|
type: "boolean",
|
|
249
263
|
optional: true,
|
|
250
264
|
default: false,
|
|
@@ -264,15 +278,18 @@ var removableSchema = {
|
|
|
264
278
|
{ name: "removable:removed", description: "Fired after removal" }
|
|
265
279
|
],
|
|
266
280
|
source: `
|
|
267
|
-
behavior Removable(triggerEl,
|
|
281
|
+
behavior Removable(triggerEl, confirmRemoval, effect)
|
|
268
282
|
init
|
|
269
283
|
if triggerEl is undefined
|
|
270
284
|
set triggerEl to me
|
|
271
285
|
end
|
|
272
286
|
end
|
|
273
287
|
on click from triggerEl
|
|
274
|
-
if
|
|
275
|
-
|
|
288
|
+
if confirmRemoval
|
|
289
|
+
js(me)
|
|
290
|
+
if (!window.confirm("Are you sure?")) return "cancel";
|
|
291
|
+
end
|
|
292
|
+
if it is "cancel"
|
|
276
293
|
halt
|
|
277
294
|
end
|
|
278
295
|
end
|
|
@@ -326,9 +343,12 @@ behavior Toggleable(cls, target)
|
|
|
326
343
|
end
|
|
327
344
|
on click
|
|
328
345
|
toggle .{cls} on target
|
|
346
|
+
js(target, cls)
|
|
347
|
+
var eventName = target.classList.contains(cls) ? 'toggleable:on' : 'toggleable:off';
|
|
348
|
+
target.dispatchEvent(new CustomEvent(eventName, { bubbles: true }));
|
|
349
|
+
end
|
|
329
350
|
end
|
|
330
|
-
end
|
|
331
|
-
`.trim()
|
|
351
|
+
end`.trim()
|
|
332
352
|
};
|
|
333
353
|
|
|
334
354
|
// src/schemas/clipboard.schema.ts
|
|
@@ -374,27 +394,49 @@ var clipboardSchema = {
|
|
|
374
394
|
"navigator.clipboard.writeText() requires HTTPS or localhost",
|
|
375
395
|
'Falls back to document.execCommand("copy") for older browsers'
|
|
376
396
|
],
|
|
377
|
-
source:
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
397
|
+
source: `
|
|
398
|
+
behavior Clipboard(text, source, feedback, feedbackDuration)
|
|
399
|
+
init
|
|
400
|
+
if feedbackDuration is undefined
|
|
401
|
+
set feedbackDuration to 2000
|
|
402
|
+
end
|
|
403
|
+
if source is undefined
|
|
404
|
+
set source to me
|
|
405
|
+
end
|
|
406
|
+
end
|
|
407
|
+
on click
|
|
408
|
+
if text is not undefined
|
|
409
|
+
set copyText to text
|
|
410
|
+
else
|
|
411
|
+
set copyText to source's textContent
|
|
412
|
+
end
|
|
413
|
+
js(me, copyText, feedback, feedbackDuration)
|
|
414
|
+
async function copyToClipboard(t) {
|
|
415
|
+
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
416
|
+
await navigator.clipboard.writeText(t);
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
var ta = document.createElement('textarea');
|
|
420
|
+
ta.value = t;
|
|
421
|
+
ta.style.position = 'fixed';
|
|
422
|
+
ta.style.opacity = '0';
|
|
423
|
+
document.body.appendChild(ta);
|
|
424
|
+
ta.select();
|
|
425
|
+
try { document.execCommand('copy'); } finally { document.body.removeChild(ta); }
|
|
426
|
+
}
|
|
427
|
+
try {
|
|
428
|
+
await copyToClipboard(copyText);
|
|
429
|
+
var feedbackEl = feedback ? (typeof feedback === 'string' ? document.querySelector(feedback) : feedback) : me;
|
|
430
|
+
if (!feedbackEl) feedbackEl = me;
|
|
431
|
+
feedbackEl.classList.add('copied');
|
|
432
|
+
me.dispatchEvent(new CustomEvent('clipboard:copied', { bubbles: true, detail: { text: copyText } }));
|
|
433
|
+
setTimeout(function() { feedbackEl.classList.remove('copied'); }, feedbackDuration);
|
|
434
|
+
} catch(err) {
|
|
435
|
+
me.dispatchEvent(new CustomEvent('clipboard:error', { bubbles: true, detail: { error: err } }));
|
|
436
|
+
}
|
|
437
|
+
end
|
|
438
|
+
end
|
|
439
|
+
end`.trim()
|
|
398
440
|
};
|
|
399
441
|
|
|
400
442
|
// src/schemas/autodismiss.schema.ts
|
|
@@ -437,24 +479,60 @@ var autoDismissSchema = {
|
|
|
437
479
|
{ name: "autodismiss:paused", description: "Fired when the timer is paused on hover" },
|
|
438
480
|
{ name: "autodismiss:resumed", description: "Fired when the timer resumes on mouseleave" }
|
|
439
481
|
],
|
|
440
|
-
source:
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
482
|
+
source: `
|
|
483
|
+
behavior AutoDismiss(delay, pauseOnHover, effect)
|
|
484
|
+
init
|
|
485
|
+
if delay is undefined
|
|
486
|
+
set delay to 5000
|
|
487
|
+
end
|
|
488
|
+
if pauseOnHover is undefined
|
|
489
|
+
set pauseOnHover to true
|
|
490
|
+
end
|
|
491
|
+
if effect is undefined
|
|
492
|
+
set effect to "none"
|
|
493
|
+
end
|
|
494
|
+
js(me, delay, effect, pauseOnHover)
|
|
495
|
+
me.dispatchEvent(new CustomEvent('autodismiss:start', { bubbles: true }));
|
|
496
|
+
var remaining = delay;
|
|
497
|
+
var startedAt = Date.now();
|
|
498
|
+
var timerId = null;
|
|
499
|
+
function dismiss() {
|
|
500
|
+
var ev = new CustomEvent('autodismiss:dismissed', { bubbles: true, cancelable: true });
|
|
501
|
+
me.dispatchEvent(ev);
|
|
502
|
+
if (ev.defaultPrevented) return;
|
|
503
|
+
if (effect === 'fade') {
|
|
504
|
+
me.style.transition = 'opacity 300ms';
|
|
505
|
+
me.style.opacity = '0';
|
|
506
|
+
setTimeout(function() { me.remove(); }, 300);
|
|
507
|
+
} else {
|
|
508
|
+
me.remove();
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
function start() {
|
|
512
|
+
startedAt = Date.now();
|
|
513
|
+
timerId = setTimeout(dismiss, remaining);
|
|
514
|
+
}
|
|
515
|
+
start();
|
|
516
|
+
if (pauseOnHover) {
|
|
517
|
+
me.addEventListener('mouseenter', function() {
|
|
518
|
+
if (timerId != null) {
|
|
519
|
+
clearTimeout(timerId);
|
|
520
|
+
timerId = null;
|
|
521
|
+
remaining -= Date.now() - startedAt;
|
|
522
|
+
if (remaining < 0) remaining = 0;
|
|
523
|
+
me.dispatchEvent(new CustomEvent('autodismiss:paused', { bubbles: true }));
|
|
524
|
+
}
|
|
525
|
+
});
|
|
526
|
+
me.addEventListener('mouseleave', function() {
|
|
527
|
+
if (timerId == null && me.isConnected) {
|
|
528
|
+
me.dispatchEvent(new CustomEvent('autodismiss:resumed', { bubbles: true }));
|
|
529
|
+
start();
|
|
530
|
+
}
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
end
|
|
534
|
+
end
|
|
535
|
+
end`.trim()
|
|
458
536
|
};
|
|
459
537
|
|
|
460
538
|
// src/schemas/clickoutside.schema.ts
|
|
@@ -474,19 +552,38 @@ var clickOutsideSchema = {
|
|
|
474
552
|
}
|
|
475
553
|
],
|
|
476
554
|
events: [
|
|
477
|
-
{ name: "clickoutside", description: "Fired when a pointer press occurs outside the element" }
|
|
555
|
+
{ name: "clickoutside", description: "Fired when a pointer press occurs outside the element" },
|
|
556
|
+
{
|
|
557
|
+
name: "clickoutside:activate",
|
|
558
|
+
description: "Listen for this event to programmatically activate detection"
|
|
559
|
+
},
|
|
560
|
+
{
|
|
561
|
+
name: "clickoutside:deactivate",
|
|
562
|
+
description: "Listen for this event to programmatically deactivate detection"
|
|
563
|
+
}
|
|
478
564
|
],
|
|
479
565
|
requirements: ["Uses pointerdown instead of click to avoid timing issues with removed elements"],
|
|
480
566
|
source: `
|
|
481
567
|
behavior ClickOutside(active)
|
|
482
568
|
init
|
|
483
|
-
if active is undefined
|
|
569
|
+
if active is undefined
|
|
570
|
+
set active to true
|
|
571
|
+
end
|
|
484
572
|
end
|
|
485
573
|
on pointerdown from document
|
|
486
|
-
|
|
487
|
-
|
|
574
|
+
js(me, active)
|
|
575
|
+
if (!me.isConnected) return;
|
|
576
|
+
if (active && !me.contains(event.target)) {
|
|
577
|
+
me.dispatchEvent(new CustomEvent('clickoutside', { bubbles: true }));
|
|
578
|
+
}
|
|
488
579
|
end
|
|
489
580
|
end
|
|
581
|
+
on clickoutside:activate
|
|
582
|
+
set active to true
|
|
583
|
+
end
|
|
584
|
+
on clickoutside:deactivate
|
|
585
|
+
set active to false
|
|
586
|
+
end
|
|
490
587
|
end`.trim()
|
|
491
588
|
};
|
|
492
589
|
|
|
@@ -530,10 +627,51 @@ var focusTrapSchema = {
|
|
|
530
627
|
source: `
|
|
531
628
|
behavior FocusTrap(active, initialFocus, returnFocus)
|
|
532
629
|
init
|
|
533
|
-
if active is undefined
|
|
534
|
-
|
|
630
|
+
if active is undefined
|
|
631
|
+
set active to true
|
|
632
|
+
end
|
|
633
|
+
if returnFocus is undefined
|
|
634
|
+
set returnFocus to true
|
|
635
|
+
end
|
|
636
|
+
js(me, active, initialFocus, returnFocus)
|
|
637
|
+
var FOCUSABLE = 'a[href],button:not(:disabled),input:not(:disabled),select:not(:disabled),textarea:not(:disabled),[tabindex]:not([tabindex="-1"])';
|
|
638
|
+
var isActive = false;
|
|
639
|
+
var previouslyFocused = null;
|
|
640
|
+
function getFocusable() { return Array.from(me.querySelectorAll(FOCUSABLE)); }
|
|
641
|
+
function activate() {
|
|
642
|
+
if (isActive) return;
|
|
643
|
+
isActive = true;
|
|
644
|
+
previouslyFocused = document.activeElement;
|
|
645
|
+
me.setAttribute('aria-modal', 'true');
|
|
646
|
+
var initEl = initialFocus ? (typeof initialFocus === 'string' ? me.querySelector(initialFocus) : initialFocus) : null;
|
|
647
|
+
if (initEl) { initEl.focus(); } else { var f = getFocusable(); if (f.length) f[0].focus(); }
|
|
648
|
+
me.dispatchEvent(new CustomEvent('focustrap:activated', { bubbles: true }));
|
|
649
|
+
}
|
|
650
|
+
function deactivate() {
|
|
651
|
+
if (!isActive) return;
|
|
652
|
+
isActive = false;
|
|
653
|
+
me.removeAttribute('aria-modal');
|
|
654
|
+
if (returnFocus && previouslyFocused instanceof HTMLElement) previouslyFocused.focus();
|
|
655
|
+
previouslyFocused = null;
|
|
656
|
+
me.dispatchEvent(new CustomEvent('focustrap:deactivated', { bubbles: true }));
|
|
657
|
+
}
|
|
658
|
+
me.addEventListener('keydown', function(e) {
|
|
659
|
+
if (!isActive || e.key !== 'Tab') return;
|
|
660
|
+
var focusable = getFocusable();
|
|
661
|
+
if (focusable.length === 0) { e.preventDefault(); return; }
|
|
662
|
+
e.preventDefault();
|
|
663
|
+
var idx = focusable.indexOf(document.activeElement);
|
|
664
|
+
if (e.shiftKey) {
|
|
665
|
+
focusable[idx <= 0 ? focusable.length - 1 : idx - 1].focus();
|
|
666
|
+
} else {
|
|
667
|
+
focusable[idx >= focusable.length - 1 ? 0 : idx + 1].focus();
|
|
668
|
+
}
|
|
669
|
+
});
|
|
670
|
+
me.addEventListener('focustrap:activate', function() { activate(); });
|
|
671
|
+
me.addEventListener('focustrap:deactivate', function() { deactivate(); });
|
|
672
|
+
if (active) activate();
|
|
673
|
+
end
|
|
535
674
|
end
|
|
536
|
-
-- Imperative installer handles Tab key trapping and focus management
|
|
537
675
|
end`.trim()
|
|
538
676
|
};
|
|
539
677
|
|
|
@@ -565,13 +703,6 @@ var scrollRevealSchema = {
|
|
|
565
703
|
optional: true,
|
|
566
704
|
default: true,
|
|
567
705
|
description: "If true, disconnect observer after first intersection"
|
|
568
|
-
},
|
|
569
|
-
{
|
|
570
|
-
name: "rootMargin",
|
|
571
|
-
type: "string",
|
|
572
|
-
optional: true,
|
|
573
|
-
default: "0px",
|
|
574
|
-
description: "CSS margin around the viewport for triggering earlier or later"
|
|
575
706
|
}
|
|
576
707
|
],
|
|
577
708
|
events: [
|
|
@@ -580,14 +711,33 @@ var scrollRevealSchema = {
|
|
|
580
711
|
],
|
|
581
712
|
requirements: ["Uses IntersectionObserver API (supported in all modern browsers)"],
|
|
582
713
|
source: `
|
|
583
|
-
behavior ScrollReveal(cls, threshold, once
|
|
714
|
+
behavior ScrollReveal(cls, threshold, once)
|
|
584
715
|
init
|
|
585
|
-
if cls is undefined
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
if
|
|
716
|
+
if cls is undefined
|
|
717
|
+
set cls to "revealed"
|
|
718
|
+
end
|
|
719
|
+
if threshold is undefined
|
|
720
|
+
set threshold to 0.1
|
|
721
|
+
end
|
|
722
|
+
if once is undefined
|
|
723
|
+
set once to true
|
|
724
|
+
end
|
|
725
|
+
js(me, cls, threshold, once)
|
|
726
|
+
var obs = new IntersectionObserver(function(entries) {
|
|
727
|
+
for (var i = 0; i < entries.length; i++) {
|
|
728
|
+
if (entries[i].isIntersecting) {
|
|
729
|
+
me.classList.add(cls);
|
|
730
|
+
me.dispatchEvent(new CustomEvent('scrollreveal:enter', { bubbles: true }));
|
|
731
|
+
if (once) obs.disconnect();
|
|
732
|
+
} else if (!once) {
|
|
733
|
+
me.classList.remove(cls);
|
|
734
|
+
me.dispatchEvent(new CustomEvent('scrollreveal:exit', { bubbles: true }));
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
}, { threshold: threshold });
|
|
738
|
+
obs.observe(me);
|
|
739
|
+
end
|
|
589
740
|
end
|
|
590
|
-
-- Imperative installer handles IntersectionObserver setup
|
|
591
741
|
end`.trim()
|
|
592
742
|
};
|
|
593
743
|
|
|
@@ -642,17 +792,86 @@ var tabsSchema = {
|
|
|
642
792
|
"Manages aria-selected, aria-controls, aria-labelledby, and tabindex",
|
|
643
793
|
"Keyboard: Arrow keys navigate, Home/End jump to first/last, Tab exits tablist"
|
|
644
794
|
],
|
|
645
|
-
source:
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
795
|
+
source: `
|
|
796
|
+
behavior Tabs(orientation, activeTab, wrap, activeClass)
|
|
797
|
+
init
|
|
798
|
+
if orientation is undefined
|
|
799
|
+
set orientation to "horizontal"
|
|
800
|
+
end
|
|
801
|
+
if activeTab is undefined
|
|
802
|
+
set activeTab to 0
|
|
803
|
+
end
|
|
804
|
+
if wrap is undefined
|
|
805
|
+
set wrap to true
|
|
806
|
+
end
|
|
807
|
+
if activeClass is undefined
|
|
808
|
+
set activeClass to "active"
|
|
809
|
+
end
|
|
810
|
+
js(me, orientation, activeTab, wrap, activeClass)
|
|
811
|
+
var tabs = Array.from(me.querySelectorAll('[role="tab"]'));
|
|
812
|
+
var panels = Array.from(me.querySelectorAll('[role="tabpanel"]'));
|
|
813
|
+
if (tabs.length === 0 || panels.length === 0) return;
|
|
814
|
+
var tablist = me.querySelector('[role="tablist"]') || tabs[0].parentElement;
|
|
815
|
+
if (tablist) tablist.setAttribute('aria-orientation', orientation);
|
|
816
|
+
var count = Math.min(tabs.length, panels.length);
|
|
817
|
+
var idN = 0;
|
|
818
|
+
for (var i = 0; i < count; i++) {
|
|
819
|
+
if (!tabs[i].id) tabs[i].id = 'tab-' + (++idN);
|
|
820
|
+
if (!panels[i].id) panels[i].id = 'tabpanel-' + idN;
|
|
821
|
+
tabs[i].setAttribute('aria-controls', panels[i].id);
|
|
822
|
+
panels[i].setAttribute('aria-labelledby', tabs[i].id);
|
|
823
|
+
}
|
|
824
|
+
var cur = Math.max(0, Math.min(activeTab, count - 1));
|
|
825
|
+
function activate(idx, prev) {
|
|
826
|
+
if (idx === prev || idx < 0 || idx >= count) return false;
|
|
827
|
+
var ev = new CustomEvent('tabs:change', { bubbles: true, cancelable: true, detail: { index: idx, previousIndex: prev } });
|
|
828
|
+
me.dispatchEvent(ev);
|
|
829
|
+
if (ev.defaultPrevented) return false;
|
|
830
|
+
if (prev >= 0 && prev < count) {
|
|
831
|
+
tabs[prev].setAttribute('aria-selected', 'false');
|
|
832
|
+
tabs[prev].setAttribute('tabindex', '-1');
|
|
833
|
+
tabs[prev].classList.remove(activeClass);
|
|
834
|
+
panels[prev].setAttribute('aria-hidden', 'true');
|
|
835
|
+
panels[prev].classList.remove(activeClass);
|
|
836
|
+
}
|
|
837
|
+
tabs[idx].setAttribute('aria-selected', 'true');
|
|
838
|
+
tabs[idx].setAttribute('tabindex', '0');
|
|
839
|
+
tabs[idx].classList.add(activeClass);
|
|
840
|
+
panels[idx].setAttribute('aria-hidden', 'false');
|
|
841
|
+
panels[idx].classList.add(activeClass);
|
|
842
|
+
cur = idx;
|
|
843
|
+
me.dispatchEvent(new CustomEvent('tabs:changed', { bubbles: true, detail: { index: idx } }));
|
|
844
|
+
return true;
|
|
845
|
+
}
|
|
846
|
+
for (var j = 0; j < count; j++) {
|
|
847
|
+
tabs[j].setAttribute('aria-selected', 'false');
|
|
848
|
+
tabs[j].setAttribute('tabindex', '-1');
|
|
849
|
+
panels[j].setAttribute('aria-hidden', 'true');
|
|
850
|
+
panels[j].classList.remove(activeClass);
|
|
851
|
+
}
|
|
852
|
+
tabs[cur].setAttribute('aria-selected', 'true');
|
|
853
|
+
tabs[cur].setAttribute('tabindex', '0');
|
|
854
|
+
tabs[cur].classList.add(activeClass);
|
|
855
|
+
panels[cur].setAttribute('aria-hidden', 'false');
|
|
856
|
+
panels[cur].classList.add(activeClass);
|
|
857
|
+
for (var k = 0; k < count; k++) {
|
|
858
|
+
(function(idx) {
|
|
859
|
+
tabs[idx].addEventListener('click', function() { if (activate(idx, cur)) tabs[idx].focus(); });
|
|
860
|
+
})(k);
|
|
861
|
+
}
|
|
862
|
+
(tablist || me).addEventListener('keydown', function(e) {
|
|
863
|
+
var nk = orientation === 'horizontal' ? 'ArrowRight' : 'ArrowDown';
|
|
864
|
+
var pk = orientation === 'horizontal' ? 'ArrowLeft' : 'ArrowUp';
|
|
865
|
+
var next = null;
|
|
866
|
+
if (e.key === nk) { next = cur + 1; if (next >= count) next = wrap ? 0 : null; }
|
|
867
|
+
else if (e.key === pk) { next = cur - 1; if (next < 0) next = wrap ? count - 1 : null; }
|
|
868
|
+
else if (e.key === 'Home') next = 0;
|
|
869
|
+
else if (e.key === 'End') next = count - 1;
|
|
870
|
+
if (next !== null) { e.preventDefault(); if (activate(next, cur)) tabs[next].focus(); }
|
|
871
|
+
});
|
|
872
|
+
end
|
|
873
|
+
end
|
|
874
|
+
end`.trim()
|
|
656
875
|
};
|
|
657
876
|
|
|
658
877
|
// src/schemas/index.ts
|