@hyperfixi/behaviors 2.0.0 → 2.1.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 +35 -6
- package/dist/all.browser.global.js.map +1 -1
- package/dist/autodismiss.browser.global.js +3 -0
- package/dist/autodismiss.browser.global.js.map +1 -0
- package/dist/behaviors/autodismiss.cjs +177 -0
- package/dist/behaviors/autodismiss.cjs.map +1 -0
- package/dist/behaviors/autodismiss.d.cts +15 -0
- package/dist/behaviors/autodismiss.d.ts +15 -0
- package/dist/behaviors/autodismiss.js +15 -0
- package/dist/behaviors/autodismiss.js.map +1 -0
- package/dist/behaviors/clickoutside.cjs +123 -0
- package/dist/behaviors/clickoutside.cjs.map +1 -0
- package/dist/behaviors/clickoutside.d.cts +15 -0
- package/dist/behaviors/clickoutside.d.ts +15 -0
- package/dist/behaviors/clickoutside.js +15 -0
- package/dist/behaviors/clickoutside.js.map +1 -0
- package/dist/behaviors/clipboard.cjs +193 -0
- package/dist/behaviors/clipboard.cjs.map +1 -0
- package/dist/behaviors/clipboard.d.cts +15 -0
- package/dist/behaviors/clipboard.d.ts +15 -0
- package/dist/behaviors/clipboard.js +15 -0
- package/dist/behaviors/clipboard.js.map +1 -0
- package/dist/behaviors/draggable.cjs +49 -7
- package/dist/behaviors/draggable.cjs.map +1 -1
- package/dist/behaviors/draggable.d.cts +2 -1
- package/dist/behaviors/draggable.d.ts +2 -1
- package/dist/behaviors/draggable.js +2 -1
- package/dist/behaviors/focustrap.cjs +191 -0
- package/dist/behaviors/focustrap.cjs.map +1 -0
- package/dist/behaviors/focustrap.d.cts +15 -0
- package/dist/behaviors/focustrap.d.ts +15 -0
- package/dist/behaviors/focustrap.js +15 -0
- package/dist/behaviors/focustrap.js.map +1 -0
- package/dist/behaviors/removable.cjs +9 -2
- package/dist/behaviors/removable.cjs.map +1 -1
- package/dist/behaviors/removable.d.cts +1 -1
- package/dist/behaviors/removable.d.ts +1 -1
- package/dist/behaviors/removable.js +2 -1
- package/dist/behaviors/resizable.cjs +54 -7
- package/dist/behaviors/resizable.cjs.map +1 -1
- package/dist/behaviors/resizable.d.cts +1 -1
- package/dist/behaviors/resizable.d.ts +1 -1
- package/dist/behaviors/resizable.js +2 -1
- package/dist/behaviors/scrollreveal.cjs +149 -0
- package/dist/behaviors/scrollreveal.cjs.map +1 -0
- package/dist/behaviors/scrollreveal.d.cts +15 -0
- package/dist/behaviors/scrollreveal.d.ts +15 -0
- package/dist/behaviors/scrollreveal.js +15 -0
- package/dist/behaviors/scrollreveal.js.map +1 -0
- package/dist/behaviors/sortable.cjs +49 -7
- package/dist/behaviors/sortable.cjs.map +1 -1
- package/dist/behaviors/sortable.d.cts +1 -1
- package/dist/behaviors/sortable.d.ts +1 -1
- package/dist/behaviors/sortable.js +2 -1
- package/dist/behaviors/tabs.cjs +247 -0
- package/dist/behaviors/tabs.cjs.map +1 -0
- package/dist/behaviors/tabs.d.cts +15 -0
- package/dist/behaviors/tabs.d.ts +15 -0
- package/dist/behaviors/tabs.js +15 -0
- package/dist/behaviors/tabs.js.map +1 -0
- package/dist/behaviors/toggleable.cjs +36 -7
- package/dist/behaviors/toggleable.cjs.map +1 -1
- package/dist/behaviors/toggleable.d.cts +2 -1
- package/dist/behaviors/toggleable.d.ts +2 -1
- package/dist/behaviors/toggleable.js +2 -1
- package/dist/chunk-244WSZOL.js +67 -0
- package/dist/chunk-244WSZOL.js.map +1 -0
- package/dist/chunk-2NSKQMNM.js +99 -0
- package/dist/chunk-2NSKQMNM.js.map +1 -0
- package/dist/chunk-64DIQGQI.js +37 -0
- package/dist/chunk-64DIQGQI.js.map +1 -0
- package/dist/chunk-6TJXDCAQ.js +11 -0
- package/dist/chunk-6TJXDCAQ.js.map +1 -0
- package/dist/chunk-7JDV2THA.js +62 -0
- package/dist/chunk-7JDV2THA.js.map +1 -0
- package/dist/chunk-AFGA54SA.js +116 -0
- package/dist/chunk-AFGA54SA.js.map +1 -0
- package/dist/chunk-DYHBKDKB.js +62 -0
- package/dist/chunk-DYHBKDKB.js.map +1 -0
- package/dist/chunk-GPTHAUWN.js +58 -0
- package/dist/chunk-GPTHAUWN.js.map +1 -0
- package/dist/chunk-GVJPA2EK.js +68 -0
- package/dist/chunk-GVJPA2EK.js.map +1 -0
- package/dist/chunk-H2MCHR5A.js +89 -0
- package/dist/chunk-H2MCHR5A.js.map +1 -0
- package/dist/{chunk-2NQHIHD5.js → chunk-H5Y5ARYG.js} +6 -3
- package/dist/chunk-H5Y5ARYG.js.map +1 -0
- package/dist/chunk-JKBWIJFI.js +155 -0
- package/dist/chunk-JKBWIJFI.js.map +1 -0
- package/dist/chunk-QKDYW4VM.js +70 -0
- package/dist/chunk-QKDYW4VM.js.map +1 -0
- package/dist/chunk-RB7OB6OD.js +51 -0
- package/dist/chunk-RB7OB6OD.js.map +1 -0
- package/dist/chunk-RPERQTFU.js +75 -0
- package/dist/chunk-RPERQTFU.js.map +1 -0
- package/dist/chunk-S4QDV2MH.js +75 -0
- package/dist/chunk-S4QDV2MH.js.map +1 -0
- package/dist/chunk-WTUVPVSD.js +80 -0
- package/dist/chunk-WTUVPVSD.js.map +1 -0
- package/dist/chunk-YHQRFUWV.js +62 -0
- package/dist/chunk-YHQRFUWV.js.map +1 -0
- package/dist/chunk-ZQQZTMCJ.js +64 -0
- package/dist/chunk-ZQQZTMCJ.js.map +1 -0
- package/dist/clickoutside.browser.global.js +12 -0
- package/dist/clickoutside.browser.global.js.map +1 -0
- package/dist/clipboard.browser.global.js +3 -0
- package/dist/clipboard.browser.global.js.map +1 -0
- package/dist/core.browser.global.js +3 -3
- package/dist/core.browser.global.js.map +1 -1
- package/dist/draggable.browser.global.js +2 -2
- package/dist/draggable.browser.global.js.map +1 -1
- package/dist/focustrap.browser.global.js +9 -0
- package/dist/focustrap.browser.global.js.map +1 -0
- package/dist/index.cjs +1270 -50
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -7
- package/dist/index.d.ts +13 -7
- package/dist/index.js +155 -48
- package/dist/index.js.map +1 -1
- package/dist/loaders.cjs +1151 -30
- package/dist/loaders.cjs.map +1 -1
- package/dist/loaders.js +9 -3
- package/dist/registry.d.cts +1 -1
- package/dist/registry.d.ts +1 -1
- package/dist/removable.browser.global.js +2 -2
- package/dist/removable.browser.global.js.map +1 -1
- package/dist/resizable.browser.global.js +2 -2
- package/dist/resizable.browser.global.js.map +1 -1
- package/dist/schemas/index.cjs +343 -1
- package/dist/schemas/index.cjs.map +1 -1
- package/dist/schemas/index.d.cts +45 -3
- package/dist/schemas/index.d.ts +45 -3
- package/dist/schemas/index.js +34 -4
- package/dist/schemas/index.js.map +1 -1
- package/dist/scrollreveal.browser.global.js +11 -0
- package/dist/scrollreveal.browser.global.js.map +1 -0
- package/dist/sortable.browser.global.js +2 -2
- package/dist/sortable.browser.global.js.map +1 -1
- package/dist/tabs.browser.global.js +3 -0
- package/dist/tabs.browser.global.js.map +1 -0
- package/dist/toggleable.browser.global.js +2 -2
- package/dist/toggleable.browser.global.js.map +1 -1
- package/dist/{types-CCc_2wAb.d.cts → types-DCCtVQS5.d.cts} +1 -1
- package/dist/{types-CCc_2wAb.d.ts → types-DCCtVQS5.d.ts} +1 -1
- package/package.json +45 -2
- package/src/behaviors/autodismiss.test.ts +61 -0
- package/src/behaviors/autodismiss.ts +107 -0
- package/src/behaviors/clickoutside.test.ts +52 -0
- package/src/behaviors/clickoutside.ts +77 -0
- package/src/behaviors/clipboard.test.ts +67 -0
- package/src/behaviors/clipboard.ts +130 -0
- package/src/behaviors/draggable.ts +62 -15
- package/src/behaviors/focustrap.test.ts +59 -0
- package/src/behaviors/focustrap.ts +158 -0
- package/src/behaviors/index.ts +37 -0
- package/src/behaviors/integration.test.ts +120 -45
- package/src/behaviors/removable.ts +4 -5
- package/src/behaviors/resizable.ts +63 -14
- package/src/behaviors/scrollreveal.test.ts +59 -0
- package/src/behaviors/scrollreveal.ts +78 -0
- package/src/behaviors/sortable.ts +61 -14
- package/src/behaviors/tabs.test.ts +81 -0
- package/src/behaviors/tabs.ts +196 -0
- package/src/behaviors/toggleable.ts +45 -13
- package/src/generated/metadata.ts +38 -7
- package/src/generated/types.ts +5 -5
- package/src/index.test.ts +143 -5
- package/src/index.ts +65 -13
- package/src/loaders.ts +18 -0
- package/src/registry.test.ts +26 -5
- package/src/schemas/autodismiss.schema.ts +66 -0
- package/src/schemas/clickoutside.schema.ts +39 -0
- package/src/schemas/clipboard.schema.ts +72 -0
- package/src/schemas/focustrap.schema.ts +53 -0
- package/src/schemas/index.ts +18 -0
- package/src/schemas/scrollreveal.schema.ts +60 -0
- package/src/schemas/tabs.schema.ts +66 -0
- package/src/schemas/types.ts +13 -1
- package/dist/chunk-2NQHIHD5.js.map +0 -1
- package/dist/chunk-3Q652JQB.js +0 -37
- package/dist/chunk-3Q652JQB.js.map +0 -1
- package/dist/chunk-HMRPQWQU.js +0 -37
- package/dist/chunk-HMRPQWQU.js.map +0 -1
- package/dist/chunk-MEP6B7XW.js +0 -37
- package/dist/chunk-MEP6B7XW.js.map +0 -1
- package/dist/chunk-URBOGGW6.js +0 -32
- package/dist/chunk-URBOGGW6.js.map +0 -1
- package/dist/chunk-WU37DFAL.js +0 -37
- package/dist/chunk-WU37DFAL.js.map +0 -1
package/dist/schemas/index.js
CHANGED
|
@@ -1,18 +1,36 @@
|
|
|
1
|
-
import {
|
|
2
|
-
draggableSchema
|
|
3
|
-
} from "../chunk-G6WR2AYR.js";
|
|
4
1
|
import {
|
|
5
2
|
removableSchema
|
|
6
3
|
} from "../chunk-272NKUJ3.js";
|
|
7
4
|
import {
|
|
8
5
|
resizableSchema
|
|
9
6
|
} from "../chunk-V5IWDPDP.js";
|
|
7
|
+
import {
|
|
8
|
+
scrollRevealSchema
|
|
9
|
+
} from "../chunk-GPTHAUWN.js";
|
|
10
10
|
import {
|
|
11
11
|
sortableSchema
|
|
12
12
|
} from "../chunk-BWZ6EGII.js";
|
|
13
|
+
import {
|
|
14
|
+
tabsSchema
|
|
15
|
+
} from "../chunk-GVJPA2EK.js";
|
|
13
16
|
import {
|
|
14
17
|
toggleableSchema
|
|
15
18
|
} from "../chunk-WUHHMDAA.js";
|
|
19
|
+
import {
|
|
20
|
+
autoDismissSchema
|
|
21
|
+
} from "../chunk-ZQQZTMCJ.js";
|
|
22
|
+
import {
|
|
23
|
+
clickOutsideSchema
|
|
24
|
+
} from "../chunk-64DIQGQI.js";
|
|
25
|
+
import {
|
|
26
|
+
clipboardSchema
|
|
27
|
+
} from "../chunk-QKDYW4VM.js";
|
|
28
|
+
import {
|
|
29
|
+
draggableSchema
|
|
30
|
+
} from "../chunk-G6WR2AYR.js";
|
|
31
|
+
import {
|
|
32
|
+
focusTrapSchema
|
|
33
|
+
} from "../chunk-RB7OB6OD.js";
|
|
16
34
|
|
|
17
35
|
// src/schemas/index.ts
|
|
18
36
|
var ALL_SCHEMAS = {
|
|
@@ -20,7 +38,13 @@ var ALL_SCHEMAS = {
|
|
|
20
38
|
Sortable: sortableSchema,
|
|
21
39
|
Resizable: resizableSchema,
|
|
22
40
|
Removable: removableSchema,
|
|
23
|
-
Toggleable: toggleableSchema
|
|
41
|
+
Toggleable: toggleableSchema,
|
|
42
|
+
Clipboard: clipboardSchema,
|
|
43
|
+
AutoDismiss: autoDismissSchema,
|
|
44
|
+
ClickOutside: clickOutsideSchema,
|
|
45
|
+
FocusTrap: focusTrapSchema,
|
|
46
|
+
ScrollReveal: scrollRevealSchema,
|
|
47
|
+
Tabs: tabsSchema
|
|
24
48
|
};
|
|
25
49
|
function getSchemaNames() {
|
|
26
50
|
return Object.keys(ALL_SCHEMAS);
|
|
@@ -30,12 +54,18 @@ function findSchema(name) {
|
|
|
30
54
|
}
|
|
31
55
|
export {
|
|
32
56
|
ALL_SCHEMAS,
|
|
57
|
+
autoDismissSchema,
|
|
58
|
+
clickOutsideSchema,
|
|
59
|
+
clipboardSchema,
|
|
33
60
|
draggableSchema,
|
|
34
61
|
findSchema,
|
|
62
|
+
focusTrapSchema,
|
|
35
63
|
getSchemaNames,
|
|
36
64
|
removableSchema,
|
|
37
65
|
resizableSchema,
|
|
66
|
+
scrollRevealSchema,
|
|
38
67
|
sortableSchema,
|
|
68
|
+
tabsSchema,
|
|
39
69
|
toggleableSchema
|
|
40
70
|
};
|
|
41
71
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/schemas/index.ts"],"sourcesContent":["/**\n * Behavior Schemas\n *\n * Central export point for all behavior schemas.\n * Used by the registry and code generation.\n */\n\n// Types\nexport type {\n BehaviorSchema,\n BehaviorCategory,\n BehaviorTier,\n ParameterSchema,\n EventSchema,\n BehaviorModule,\n LokaScriptInstance,\n} from './types';\n\n// Individual schemas\nexport { draggableSchema } from './draggable.schema';\nexport { sortableSchema } from './sortable.schema';\nexport { resizableSchema } from './resizable.schema';\nexport { removableSchema } from './removable.schema';\nexport { toggleableSchema } from './toggleable.schema';\n\n// All schemas as a collection\nimport { draggableSchema } from './draggable.schema';\nimport { sortableSchema } from './sortable.schema';\nimport { resizableSchema } from './resizable.schema';\nimport { removableSchema } from './removable.schema';\nimport { toggleableSchema } from './toggleable.schema';\nimport type { BehaviorSchema } from './types';\n\n/**\n * All behavior schemas indexed by name.\n */\nexport const ALL_SCHEMAS: Record<string, BehaviorSchema> = {\n Draggable: draggableSchema,\n Sortable: sortableSchema,\n Resizable: resizableSchema,\n Removable: removableSchema,\n Toggleable: toggleableSchema,\n};\n\n/**\n * Get all schema names.\n */\nexport function getSchemaNames(): string[] {\n return Object.keys(ALL_SCHEMAS);\n}\n\n/**\n * Find a schema by name. Returns undefined if not found.\n *\n * Note: For the throwing version, use `getSchema()` from the registry\n * (exported from '@hyperfixi/behaviors').\n */\nexport function findSchema(name: string): BehaviorSchema | undefined {\n return ALL_SCHEMAS[name];\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../src/schemas/index.ts"],"sourcesContent":["/**\n * Behavior Schemas\n *\n * Central export point for all behavior schemas.\n * Used by the registry and code generation.\n */\n\n// Types\nexport type {\n BehaviorSchema,\n BehaviorCategory,\n BehaviorTier,\n ParameterSchema,\n EventSchema,\n BehaviorModule,\n LokaScriptInstance,\n} from './types';\n\n// Individual schemas\nexport { draggableSchema } from './draggable.schema';\nexport { sortableSchema } from './sortable.schema';\nexport { resizableSchema } from './resizable.schema';\nexport { removableSchema } from './removable.schema';\nexport { toggleableSchema } from './toggleable.schema';\nexport { clipboardSchema } from './clipboard.schema';\nexport { autoDismissSchema } from './autodismiss.schema';\nexport { clickOutsideSchema } from './clickoutside.schema';\nexport { focusTrapSchema } from './focustrap.schema';\nexport { scrollRevealSchema } from './scrollreveal.schema';\nexport { tabsSchema } from './tabs.schema';\n\n// All schemas as a collection\nimport { draggableSchema } from './draggable.schema';\nimport { sortableSchema } from './sortable.schema';\nimport { resizableSchema } from './resizable.schema';\nimport { removableSchema } from './removable.schema';\nimport { toggleableSchema } from './toggleable.schema';\nimport { clipboardSchema } from './clipboard.schema';\nimport { autoDismissSchema } from './autodismiss.schema';\nimport { clickOutsideSchema } from './clickoutside.schema';\nimport { focusTrapSchema } from './focustrap.schema';\nimport { scrollRevealSchema } from './scrollreveal.schema';\nimport { tabsSchema } from './tabs.schema';\nimport type { BehaviorSchema } from './types';\n\n/**\n * All behavior schemas indexed by name.\n */\nexport const ALL_SCHEMAS: Record<string, BehaviorSchema> = {\n Draggable: draggableSchema,\n Sortable: sortableSchema,\n Resizable: resizableSchema,\n Removable: removableSchema,\n Toggleable: toggleableSchema,\n Clipboard: clipboardSchema,\n AutoDismiss: autoDismissSchema,\n ClickOutside: clickOutsideSchema,\n FocusTrap: focusTrapSchema,\n ScrollReveal: scrollRevealSchema,\n Tabs: tabsSchema,\n};\n\n/**\n * Get all schema names.\n */\nexport function getSchemaNames(): string[] {\n return Object.keys(ALL_SCHEMAS);\n}\n\n/**\n * Find a schema by name. Returns undefined if not found.\n *\n * Note: For the throwing version, use `getSchema()` from the registry\n * (exported from '@hyperfixi/behaviors').\n */\nexport function findSchema(name: string): BehaviorSchema | undefined {\n return ALL_SCHEMAS[name];\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgDO,IAAM,cAA8C;AAAA,EACzD,WAAW;AAAA,EACX,UAAU;AAAA,EACV,WAAW;AAAA,EACX,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,aAAa;AAAA,EACb,cAAc;AAAA,EACd,WAAW;AAAA,EACX,cAAc;AAAA,EACd,MAAM;AACR;AAKO,SAAS,iBAA2B;AACzC,SAAO,OAAO,KAAK,WAAW;AAChC;AAQO,SAAS,WAAW,MAA0C;AACnE,SAAO,YAAY,IAAI;AACzB;","names":[]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";var HyperFixiBehaviors=(()=>{var s=Object.defineProperty;var h=Object.getOwnPropertyDescriptor;var m=Object.getOwnPropertyNames;var v=Object.prototype.hasOwnProperty;var f=(t,e)=>{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},g=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of m(e))!v.call(t,o)&&o!==r&&s(t,o,{get:()=>e[o],enumerable:!(n=h(e,o))||n.enumerable});return t};var y=t=>g(s({},"__esModule",{value:!0}),t);var k={};f(k,{default:()=>S,registerScrollReveal:()=>c,scrollRevealMetadata:()=>w,scrollRevealSource:()=>b});var i={name:"ScrollReveal",category:"layout",tier:"common",version:"1.0.0",description:"Adds a class when the element enters the viewport via IntersectionObserver",parameters:[{name:"cls",type:"string",optional:!0,default:"revealed",description:"CSS class added when element enters viewport"},{name:"threshold",type:"number",optional:!0,default:.1,description:"Intersection ratio threshold (0-1) for triggering"},{name:"once",type:"boolean",optional:!0,default:!0,description:"If true, disconnect observer after first intersection"},{name:"rootMargin",type:"string",optional:!0,default:"0px",description:"CSS margin around the viewport for triggering earlier or later"}],events:[{name:"scrollreveal:enter",description:"Fired when the element enters the viewport"},{name:"scrollreveal:exit",description:"Fired when the element exits the viewport"}],requirements:["Uses IntersectionObserver API (supported in all modern browsers)"],source:`
|
|
2
|
+
behavior ScrollReveal(cls, threshold, once, rootMargin)
|
|
3
|
+
init
|
|
4
|
+
if cls is undefined set cls to "revealed"
|
|
5
|
+
if threshold is undefined set threshold to 0.1
|
|
6
|
+
if once is undefined set once to true
|
|
7
|
+
if rootMargin is undefined set rootMargin to "0px"
|
|
8
|
+
end
|
|
9
|
+
-- Imperative installer handles IntersectionObserver setup
|
|
10
|
+
end`.trim()};function a(){if(typeof window>"u")return null;let t=window;return t.lokascript||t.hyperfixi||null}var b=i.source,w=i;function x(t,e){let r=typeof e.cls=="string"?e.cls:"revealed",n=typeof e.threshold=="number"?e.threshold:.1,o=e.once!==!1,p=typeof e.rootMargin=="string"?e.rootMargin:"0px",l=new IntersectionObserver(d=>{for(let u of d)u.isIntersecting?(t.classList.add(r),t.dispatchEvent(new CustomEvent("scrollreveal:enter",{bubbles:!0})),o&&l.disconnect()):o||(t.classList.remove(r),t.dispatchEvent(new CustomEvent("scrollreveal:exit",{bubbles:!0})))},{threshold:n,rootMargin:p});l.observe(t)}async function c(t){let e=t||a();if(!e)throw new Error("LokaScript not found. Make sure @hyperfixi/core is loaded before registering behaviors.");let r={type:"behavior",name:"ScrollReveal",parameters:["cls","threshold","once","rootMargin"],eventHandlers:[],imperativeInstaller:x},n=e.createContext?e.createContext():{locals:new Map,globals:new Map};await e.execute(r,n)}a()&&c().catch(console.error);var S={source:i.source,metadata:i,register:c};return y(k);})();
|
|
11
|
+
//# sourceMappingURL=scrollreveal.browser.global.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/behaviors/scrollreveal.ts","../src/schemas/scrollreveal.schema.ts","../src/schemas/types.ts"],"sourcesContent":["/**\n * ScrollReveal Behavior — Imperative Implementation\n *\n * Adds a class or fires events when the element enters or exits the viewport.\n * Uses the IntersectionObserver web standard API.\n */\n\nimport { scrollRevealSchema } from '../schemas/scrollreveal.schema';\nimport type { LokaScriptInstance } from '../schemas/types';\nimport { resolveRuntime } from '../schemas/types';\n\n// Re-export schema-derived values\nexport const scrollRevealSource = scrollRevealSchema.source;\nexport const scrollRevealMetadata = scrollRevealSchema;\n\n/**\n * Imperative installer for ScrollReveal behavior.\n */\nfunction installScrollReveal(element: HTMLElement, params: Record<string, any>): void {\n const cls = typeof params.cls === 'string' ? params.cls : 'revealed';\n const threshold = typeof params.threshold === 'number' ? params.threshold : 0.1;\n const once = params.once !== false;\n const rootMargin = typeof params.rootMargin === 'string' ? params.rootMargin : '0px';\n\n const observer = new IntersectionObserver(\n entries => {\n for (const entry of entries) {\n if (entry.isIntersecting) {\n element.classList.add(cls);\n element.dispatchEvent(new CustomEvent('scrollreveal:enter', { bubbles: true }));\n if (once) {\n observer.disconnect();\n }\n } else if (!once) {\n element.classList.remove(cls);\n element.dispatchEvent(new CustomEvent('scrollreveal:exit', { bubbles: true }));\n }\n }\n },\n { threshold, rootMargin }\n );\n\n observer.observe(element);\n}\n\n/**\n * Register the ScrollReveal behavior with LokaScript.\n */\nexport async function registerScrollReveal(hyperfixi?: LokaScriptInstance): Promise<void> {\n const hf = hyperfixi || resolveRuntime();\n\n if (!hf) {\n throw new Error(\n 'LokaScript not found. Make sure @hyperfixi/core is loaded before registering behaviors.'\n );\n }\n\n const syntheticNode = {\n type: 'behavior',\n name: 'ScrollReveal',\n parameters: ['cls', 'threshold', 'once', 'rootMargin'],\n eventHandlers: [],\n imperativeInstaller: installScrollReveal,\n };\n const ctx = hf.createContext ? hf.createContext() : { locals: new Map(), globals: new Map() };\n await hf.execute(syntheticNode, ctx);\n}\n\n// Auto-register when loaded as a script tag\nif (resolveRuntime()) {\n registerScrollReveal().catch(console.error);\n}\n\nexport default {\n source: scrollRevealSchema.source,\n metadata: scrollRevealSchema,\n register: registerScrollReveal,\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 name: 'rootMargin',\n type: 'string',\n optional: true,\n default: '0px',\n description: 'CSS margin around the viewport for triggering earlier or later',\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, rootMargin)\n init\n if cls is undefined set cls to \"revealed\"\n if threshold is undefined set threshold to 0.1\n if once is undefined set once to true\n if rootMargin is undefined set rootMargin to \"0px\"\n end\n -- Imperative installer handles IntersectionObserver setup\nend`.trim(),\n};\n","/**\n * Behavior Schema Types\n *\n * Defines the structure for behavior metadata used for:\n * - Code generation (TypeScript types, documentation)\n * - Runtime categorization and lazy loading\n * - Tooling and IDE integration\n */\n\n/**\n * Behavior categories for organization.\n * - ui: Visual interaction behaviors (drag, resize, sort)\n * - data: Data manipulation behaviors (remove, transform)\n * - animation: Animation and transition behaviors\n * - form: Form-related behaviors (validation, toggle states)\n * - layout: Layout behaviors (sticky, scrollspy)\n */\nexport type BehaviorCategory = 'ui' | 'data' | 'animation' | 'form' | 'layout';\n\n/**\n * Loading tiers for lazy loading optimization.\n * - core: Always loaded (essential behaviors)\n * - common: High usage (loaded for typical apps)\n * - optional: Low usage (loaded on demand)\n */\nexport type BehaviorTier = 'core' | 'common' | 'optional';\n\n/**\n * Schema for a behavior parameter.\n */\nexport interface ParameterSchema {\n name: string;\n type: 'string' | 'number' | 'boolean' | 'selector' | 'element';\n optional?: boolean;\n default?: string | number | boolean;\n /** Allowed values for constrained parameters */\n enum?: string[];\n description: string;\n}\n\n/**\n * Schema for a behavior event.\n */\nexport interface EventSchema {\n name: string;\n description: string;\n}\n\n/**\n * Complete schema for a behavior.\n * This is the source of truth for all behavior metadata.\n */\nexport interface BehaviorSchema {\n /** Behavior name (PascalCase) */\n name: string;\n /** Category for organization */\n category: BehaviorCategory;\n /** Loading tier for lazy loading */\n tier: BehaviorTier;\n /** Semantic version */\n version: string;\n /** Human-readable description */\n description: string;\n /** Parameter definitions */\n parameters: ParameterSchema[];\n /** Event definitions */\n events: EventSchema[];\n /** The hyperscript behavior source code */\n source: string;\n /** Optional requirements or notes */\n requirements?: string[];\n}\n\n/**\n * Runtime behavior module interface.\n * This is what gets registered with the hyperfixi runtime.\n */\nexport interface BehaviorModule {\n source: string;\n metadata: BehaviorSchema;\n register: (hyperfixi?: LokaScriptInstance) => Promise<void>;\n}\n\n/**\n * Minimal LokaScript instance interface for behavior registration.\n */\nexport interface LokaScriptInstance {\n compileSync: (\n code: string,\n options?: { traditional?: boolean; language?: string }\n ) => {\n ok: boolean;\n ast?: unknown;\n errors?: Array<{ message: string; line?: number; column?: number }>;\n };\n execute: (ast: unknown, ctx: unknown) => Promise<unknown>;\n createContext?: () => { locals: Map<string, unknown>; globals: Map<string, unknown> };\n}\n\n/**\n * Typed window interface for behavior auto-registration.\n * Avoids `(window as any)` casts throughout the codebase.\n * Checks both `window.lokascript` and `window.hyperfixi` for the runtime instance.\n */\nexport interface LokaScriptWindow {\n lokascript?: LokaScriptInstance;\n hyperfixi?: LokaScriptInstance;\n __hyperfixi_behaviors_ready?: Promise<void> | undefined;\n}\n\n/**\n * Resolve the LokaScript runtime from window globals.\n * Checks both `window.lokascript` and `window.hyperfixi`.\n */\nexport function resolveRuntime(): LokaScriptInstance | null {\n if (typeof window === 'undefined') return null;\n const win = window as unknown as LokaScriptWindow;\n return win.lokascript || win.hyperfixi || null;\n}\n"],"mappings":"scAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,aAAAE,EAAA,yBAAAC,EAAA,yBAAAC,EAAA,uBAAAC,ICQO,IAAMC,EAAqC,CAChD,KAAM,eACN,SAAU,SACV,KAAM,SACN,QAAS,QACT,YAAa,6EACb,WAAY,CACV,CACE,KAAM,MACN,KAAM,SACN,SAAU,GACV,QAAS,WACT,YAAa,8CACf,EACA,CACE,KAAM,YACN,KAAM,SACN,SAAU,GACV,QAAS,GACT,YAAa,mDACf,EACA,CACE,KAAM,OACN,KAAM,UACN,SAAU,GACV,QAAS,GACT,YAAa,uDACf,EACA,CACE,KAAM,aACN,KAAM,SACN,SAAU,GACV,QAAS,MACT,YAAa,gEACf,CACF,EACA,OAAQ,CACN,CAAE,KAAM,qBAAsB,YAAa,4CAA6C,EACxF,CAAE,KAAM,oBAAqB,YAAa,2CAA4C,CACxF,EACA,aAAc,CAAC,kEAAkE,EACjF,OAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KASL,KAAK,CACV,ECuDO,SAASC,GAA4C,CAC1D,GAAI,OAAO,OAAW,IAAa,OAAO,KAC1C,IAAMC,EAAM,OACZ,OAAOA,EAAI,YAAcA,EAAI,WAAa,IAC5C,CF1GO,IAAMC,EAAqBC,EAAmB,OACxCC,EAAuBD,EAKpC,SAASE,EAAoBC,EAAsBC,EAAmC,CACpF,IAAMC,EAAM,OAAOD,EAAO,KAAQ,SAAWA,EAAO,IAAM,WACpDE,EAAY,OAAOF,EAAO,WAAc,SAAWA,EAAO,UAAY,GACtEG,EAAOH,EAAO,OAAS,GACvBI,EAAa,OAAOJ,EAAO,YAAe,SAAWA,EAAO,WAAa,MAEzEK,EAAW,IAAI,qBACnBC,GAAW,CACT,QAAWC,KAASD,EACdC,EAAM,gBACRR,EAAQ,UAAU,IAAIE,CAAG,EACzBF,EAAQ,cAAc,IAAI,YAAY,qBAAsB,CAAE,QAAS,EAAK,CAAC,CAAC,EAC1EI,GACFE,EAAS,WAAW,GAEZF,IACVJ,EAAQ,UAAU,OAAOE,CAAG,EAC5BF,EAAQ,cAAc,IAAI,YAAY,oBAAqB,CAAE,QAAS,EAAK,CAAC,CAAC,EAGnF,EACA,CAAE,UAAAG,EAAW,WAAAE,CAAW,CAC1B,EAEAC,EAAS,QAAQN,CAAO,CAC1B,CAKA,eAAsBS,EAAqBC,EAA+C,CACxF,IAAMC,EAAKD,GAAaE,EAAe,EAEvC,GAAI,CAACD,EACH,MAAM,IAAI,MACR,yFACF,EAGF,IAAME,EAAgB,CACpB,KAAM,WACN,KAAM,eACN,WAAY,CAAC,MAAO,YAAa,OAAQ,YAAY,EACrD,cAAe,CAAC,EAChB,oBAAqBd,CACvB,EACMe,EAAMH,EAAG,cAAgBA,EAAG,cAAc,EAAI,CAAE,OAAQ,IAAI,IAAO,QAAS,IAAI,GAAM,EAC5F,MAAMA,EAAG,QAAQE,EAAeC,CAAG,CACrC,CAGIF,EAAe,GACjBH,EAAqB,EAAE,MAAM,QAAQ,KAAK,EAG5C,IAAOM,EAAQ,CACb,OAAQlB,EAAmB,OAC3B,SAAUA,EACV,SAAUY,CACZ","names":["scrollreveal_exports","__export","scrollreveal_default","registerScrollReveal","scrollRevealMetadata","scrollRevealSource","scrollRevealSchema","resolveRuntime","win","scrollRevealSource","scrollRevealSchema","scrollRevealMetadata","installScrollReveal","element","params","cls","threshold","once","rootMargin","observer","entries","entry","registerScrollReveal","hyperfixi","hf","resolveRuntime","syntheticNode","ctx","scrollreveal_default"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var HyperFixiBehaviors=(()=>{var
|
|
1
|
+
"use strict";var HyperFixiBehaviors=(()=>{var s=Object.defineProperty;var g=Object.getOwnPropertyDescriptor;var h=Object.getOwnPropertyNames;var v=Object.prototype.hasOwnProperty;var f=(e,t)=>{for(var r in t)s(e,r,{get:t[r],enumerable:!0})},b=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of h(t))!v.call(e,n)&&n!==r&&s(e,n,{get:()=>t[n],enumerable:!(o=g(t,n))||o.enumerable});return e};var S=e=>b(s({},"__esModule",{value:!0}),e);var E={};f(E,{default:()=>k,registerSortable:()=>c,sortableMetadata:()=>x,sortableSource:()=>w});var i={name:"Sortable",category:"ui",tier:"common",version:"1.0.0",description:"Makes child elements reorderable via drag-and-drop",parameters:[{name:"handle",type:"selector",optional:!0,default:"none",description:"CSS selector for drag handles within items"},{name:"dragClass",type:"string",optional:!0,default:"sorting",description:"CSS class added to item during drag"}],events:[{name:"sortable:start",description:"Fired when drag begins"},{name:"sortable:move",description:"Fired during drag \u2014 handle this event to reorder DOM elements"},{name:"sortable:end",description:"Fired when drag completes"}],requirements:["Users must handle DOM reordering in sortable:move event handlers"],source:`
|
|
2
2
|
behavior Sortable(handle, dragClass)
|
|
3
3
|
init
|
|
4
4
|
if no dragClass set dragClass to "sorting"
|
|
@@ -21,5 +21,5 @@ behavior Sortable(handle, dragClass)
|
|
|
21
21
|
trigger sortable:end on me
|
|
22
22
|
end
|
|
23
23
|
end
|
|
24
|
-
`.trim()};var
|
|
24
|
+
`.trim()};function l(){if(typeof window>"u")return null;let e=window;return e.lokascript||e.hyperfixi||null}var w=i.source,x=i;function y(e,t){let r=t.dragClass||"sorting",o=t.handle||null;e.addEventListener("pointerdown",n=>{let d=n.target,a=d.closest("li");if(!a||!e.contains(a)||o&&!d.closest(o))return;n.preventDefault(),a.classList.add(r),e.dispatchEvent(new CustomEvent("sortable:start",{bubbles:!0,detail:{item:a}}));function m(u){e.dispatchEvent(new CustomEvent("sortable:move",{bubbles:!0,detail:{clientY:u.clientY,item:a}}))}function p(){document.removeEventListener("pointermove",m),document.removeEventListener("pointerup",p),a.classList.remove(r),e.dispatchEvent(new CustomEvent("sortable:end",{bubbles:!0,detail:{item:a}}))}document.addEventListener("pointermove",m),document.addEventListener("pointerup",p)})}async function c(e){let t=e||l();if(!t)throw new Error("LokaScript not found. Make sure @hyperfixi/core is loaded before registering behaviors.");let r={type:"behavior",name:"Sortable",parameters:["handle","dragClass"],eventHandlers:[],imperativeInstaller:y},o=t.createContext?t.createContext():{locals:new Map,globals:new Map};await t.execute(r,o)}l()&&c().catch(console.error);var k={source:i.source,metadata:i,register:c};return S(E);})();
|
|
25
25
|
//# sourceMappingURL=sortable.browser.global.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/behaviors/sortable.ts","../src/schemas/sortable.schema.ts"],"sourcesContent":["/**\n * Sortable Behavior\n *\n * A behavior for drag-and-drop reordering of list items.\n * Apply to a container element; children become sortable.\n *\n * @example\n * ```html\n * <ul _=\"install Sortable\">\n * <li>Item 1</li>\n * <li>Item 2</li>\n * </ul>\n * ```\n */\n\nimport { sortableSchema } from '../schemas/sortable.schema';\nimport type { LokaScriptInstance, LokaScriptWindow } from '../schemas/types';\n\n// Re-export schema-derived values for backwards compatibility\nexport const sortableSource = sortableSchema.source;\nexport const sortableMetadata = sortableSchema;\n\n/**\n * Register the Sortable behavior with LokaScript.\n */\nexport async function registerSortable(hyperfixi?: LokaScriptInstance): Promise<void> {\n const hf =\n hyperfixi ||\n (typeof window !== 'undefined' ? (window as unknown as LokaScriptWindow).lokascript : null);\n\n if (!hf) {\n throw new Error(\n 'LokaScript not found. Make sure @hyperfixi/core is loaded before registering behaviors.'\n );\n }\n\n const result = hf.compileSync(sortableSchema.source, { traditional: true });\n\n if (!result.ok) {\n throw new Error(`Failed to compile Sortable behavior: ${JSON.stringify(result.errors)}`);\n }\n\n const ctx = hf.createContext ? hf.createContext() : { locals: new Map(), globals: new Map() };\n await hf.execute(result.ast, ctx);\n}\n\n// Auto-register when loaded as a script tag\nif (typeof window !== 'undefined' && (window as unknown as LokaScriptWindow).lokascript) {\n registerSortable().catch(console.error);\n}\n\nexport default {\n source: sortableSchema.source,\n metadata: sortableSchema,\n register: registerSortable,\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 no dragClass set dragClass to \"sorting\"\n end\n on pointerdown(target, clientY) from me\n set item to closest <li/> in target\n if no item exit\n if handle\n set handleEl to target.closest(handle)\n if no handleEl exit\n end\n halt the event\n add dragClass to item\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 item\n trigger sortable:end on me\n end\nend\n`.trim(),\n};\n"],"mappings":"scAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,aAAAE,EAAA,qBAAAC,EAAA,qBAAAC,EAAA,mBAAAC,ICYO,IAAMC,EAAiC,CAC5C,KAAM,WACN,SAAU,KACV,KAAM,SACN,QAAS,QACT,YAAa,qDACb,WAAY,CACV,CACE,KAAM,SACN,KAAM,WACN,SAAU,GACV,QAAS,OACT,YAAa,4CACf,EACA,CACE,KAAM,YACN,KAAM,SACN,SAAU,GACV,QAAS,UACT,YAAa,qCACf,CACF,EACA,OAAQ,CACN,CAAE,KAAM,iBAAkB,YAAa,wBAAyB,EAChE,CACE,KAAM,gBACN,YAAa,oEACf,EACA,CAAE,KAAM,eAAgB,YAAa,2BAA4B,CACnE,EACA,aAAc,CAAC,kEAAkE,EACjF,OAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuBR,KAAK,CACP,EDhDO,IAAMC,EAAiBC,EAAe,OAChCC,EAAmBD,EAKhC,eAAsBE,EAAiBC,EAA+C,CACpF,IAAMC,EACJD,IACC,OAAO,OAAW,IAAe,OAAuC,WAAa,MAExF,GAAI,CAACC,EACH,MAAM,IAAI,MACR,yFACF,EAGF,IAAMC,EAASD,EAAG,YAAYJ,EAAe,OAAQ,CAAE,YAAa,EAAK,CAAC,EAE1E,GAAI,CAACK,EAAO,GACV,MAAM,IAAI,MAAM,wCAAwC,KAAK,UAAUA,EAAO,MAAM,CAAC,EAAE,EAGzF,IAAMC,EAAMF,EAAG,cAAgBA,EAAG,cAAc,EAAI,CAAE,OAAQ,IAAI,IAAO,QAAS,IAAI,GAAM,EAC5F,MAAMA,EAAG,QAAQC,EAAO,IAAKC,CAAG,CAClC,CAGI,OAAO,OAAW,KAAgB,OAAuC,YAC3EJ,EAAiB,EAAE,MAAM,QAAQ,KAAK,EAGxC,IAAOK,EAAQ,CACb,OAAQP,EAAe,OACvB,SAAUA,EACV,SAAUE,CACZ","names":["sortable_exports","__export","sortable_default","registerSortable","sortableMetadata","sortableSource","sortableSchema","sortableSource","sortableSchema","sortableMetadata","registerSortable","hyperfixi","hf","result","ctx","sortable_default"]}
|
|
1
|
+
{"version":3,"sources":["../src/behaviors/sortable.ts","../src/schemas/sortable.schema.ts","../src/schemas/types.ts"],"sourcesContent":["/**\n * Sortable Behavior — Imperative Implementation\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 *\n * @example\n * ```html\n * <ul _=\"install Sortable\">\n * <li>Item 1</li>\n * <li>Item 2</li>\n * </ul>\n * ```\n */\n\nimport { sortableSchema } from '../schemas/sortable.schema';\nimport type { LokaScriptInstance } from '../schemas/types';\nimport { resolveRuntime } from '../schemas/types';\n\n// Re-export schema-derived values for backwards compatibility\nexport const sortableSource = sortableSchema.source;\nexport const sortableMetadata = sortableSchema;\n\n/**\n * Imperative installer for Sortable behavior.\n */\nfunction installSortable(element: HTMLElement, params: Record<string, any>): void {\n const dragClass = params.dragClass || 'sorting';\n const handleSelector = params.handle || null;\n\n element.addEventListener('pointerdown', (e: PointerEvent) => {\n const target = e.target as HTMLElement;\n const item = target.closest('li');\n if (!item || !element.contains(item)) return;\n\n // If a handle selector is specified, only start drag from the handle\n if (handleSelector) {\n const handleEl = target.closest(handleSelector);\n if (!handleEl) return;\n }\n\n e.preventDefault();\n item.classList.add(dragClass);\n element.dispatchEvent(new CustomEvent('sortable:start', { bubbles: true, detail: { item } }));\n\n function onMove(ev: PointerEvent) {\n element.dispatchEvent(\n new CustomEvent('sortable:move', {\n bubbles: true,\n detail: { clientY: ev.clientY, item },\n })\n );\n }\n\n function onUp() {\n document.removeEventListener('pointermove', onMove);\n document.removeEventListener('pointerup', onUp);\n item!.classList.remove(dragClass);\n element.dispatchEvent(new CustomEvent('sortable:end', { bubbles: true, detail: { item } }));\n }\n\n document.addEventListener('pointermove', onMove);\n document.addEventListener('pointerup', onUp);\n });\n}\n\n/**\n * Register the Sortable behavior with LokaScript.\n */\nexport async function registerSortable(hyperfixi?: LokaScriptInstance): Promise<void> {\n const hf = hyperfixi || resolveRuntime();\n\n if (!hf) {\n throw new Error(\n 'LokaScript not found. Make sure @hyperfixi/core is loaded before registering behaviors.'\n );\n }\n\n const syntheticNode = {\n type: 'behavior',\n name: 'Sortable',\n parameters: ['handle', 'dragClass'],\n eventHandlers: [],\n imperativeInstaller: installSortable,\n };\n const ctx = hf.createContext ? hf.createContext() : { locals: new Map(), globals: new Map() };\n await hf.execute(syntheticNode, ctx);\n}\n\n// Auto-register when loaded as a script tag\nif (resolveRuntime()) {\n registerSortable().catch(console.error);\n}\n\nexport default {\n source: sortableSchema.source,\n metadata: sortableSchema,\n register: registerSortable,\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 no dragClass set dragClass to \"sorting\"\n end\n on pointerdown(target, clientY) from me\n set item to closest <li/> in target\n if no item exit\n if handle\n set handleEl to target.closest(handle)\n if no handleEl exit\n end\n halt the event\n add dragClass to item\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 item\n trigger sortable:end on me\n end\nend\n`.trim(),\n};\n","/**\n * Behavior Schema Types\n *\n * Defines the structure for behavior metadata used for:\n * - Code generation (TypeScript types, documentation)\n * - Runtime categorization and lazy loading\n * - Tooling and IDE integration\n */\n\n/**\n * Behavior categories for organization.\n * - ui: Visual interaction behaviors (drag, resize, sort)\n * - data: Data manipulation behaviors (remove, transform)\n * - animation: Animation and transition behaviors\n * - form: Form-related behaviors (validation, toggle states)\n * - layout: Layout behaviors (sticky, scrollspy)\n */\nexport type BehaviorCategory = 'ui' | 'data' | 'animation' | 'form' | 'layout';\n\n/**\n * Loading tiers for lazy loading optimization.\n * - core: Always loaded (essential behaviors)\n * - common: High usage (loaded for typical apps)\n * - optional: Low usage (loaded on demand)\n */\nexport type BehaviorTier = 'core' | 'common' | 'optional';\n\n/**\n * Schema for a behavior parameter.\n */\nexport interface ParameterSchema {\n name: string;\n type: 'string' | 'number' | 'boolean' | 'selector' | 'element';\n optional?: boolean;\n default?: string | number | boolean;\n /** Allowed values for constrained parameters */\n enum?: string[];\n description: string;\n}\n\n/**\n * Schema for a behavior event.\n */\nexport interface EventSchema {\n name: string;\n description: string;\n}\n\n/**\n * Complete schema for a behavior.\n * This is the source of truth for all behavior metadata.\n */\nexport interface BehaviorSchema {\n /** Behavior name (PascalCase) */\n name: string;\n /** Category for organization */\n category: BehaviorCategory;\n /** Loading tier for lazy loading */\n tier: BehaviorTier;\n /** Semantic version */\n version: string;\n /** Human-readable description */\n description: string;\n /** Parameter definitions */\n parameters: ParameterSchema[];\n /** Event definitions */\n events: EventSchema[];\n /** The hyperscript behavior source code */\n source: string;\n /** Optional requirements or notes */\n requirements?: string[];\n}\n\n/**\n * Runtime behavior module interface.\n * This is what gets registered with the hyperfixi runtime.\n */\nexport interface BehaviorModule {\n source: string;\n metadata: BehaviorSchema;\n register: (hyperfixi?: LokaScriptInstance) => Promise<void>;\n}\n\n/**\n * Minimal LokaScript instance interface for behavior registration.\n */\nexport interface LokaScriptInstance {\n compileSync: (\n code: string,\n options?: { traditional?: boolean; language?: string }\n ) => {\n ok: boolean;\n ast?: unknown;\n errors?: Array<{ message: string; line?: number; column?: number }>;\n };\n execute: (ast: unknown, ctx: unknown) => Promise<unknown>;\n createContext?: () => { locals: Map<string, unknown>; globals: Map<string, unknown> };\n}\n\n/**\n * Typed window interface for behavior auto-registration.\n * Avoids `(window as any)` casts throughout the codebase.\n * Checks both `window.lokascript` and `window.hyperfixi` for the runtime instance.\n */\nexport interface LokaScriptWindow {\n lokascript?: LokaScriptInstance;\n hyperfixi?: LokaScriptInstance;\n __hyperfixi_behaviors_ready?: Promise<void> | undefined;\n}\n\n/**\n * Resolve the LokaScript runtime from window globals.\n * Checks both `window.lokascript` and `window.hyperfixi`.\n */\nexport function resolveRuntime(): LokaScriptInstance | null {\n if (typeof window === 'undefined') return null;\n const win = window as unknown as LokaScriptWindow;\n return win.lokascript || win.hyperfixi || null;\n}\n"],"mappings":"scAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,aAAAE,EAAA,qBAAAC,EAAA,qBAAAC,EAAA,mBAAAC,ICYO,IAAMC,EAAiC,CAC5C,KAAM,WACN,SAAU,KACV,KAAM,SACN,QAAS,QACT,YAAa,qDACb,WAAY,CACV,CACE,KAAM,SACN,KAAM,WACN,SAAU,GACV,QAAS,OACT,YAAa,4CACf,EACA,CACE,KAAM,YACN,KAAM,SACN,SAAU,GACV,QAAS,UACT,YAAa,qCACf,CACF,EACA,OAAQ,CACN,CAAE,KAAM,iBAAkB,YAAa,wBAAyB,EAChE,CACE,KAAM,gBACN,YAAa,oEACf,EACA,CAAE,KAAM,eAAgB,YAAa,2BAA4B,CACnE,EACA,aAAc,CAAC,kEAAkE,EACjF,OAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuBR,KAAK,CACP,EC+CO,SAASC,GAA4C,CAC1D,GAAI,OAAO,OAAW,IAAa,OAAO,KAC1C,IAAMC,EAAM,OACZ,OAAOA,EAAI,YAAcA,EAAI,WAAa,IAC5C,CF9FO,IAAMC,EAAiBC,EAAe,OAChCC,EAAmBD,EAKhC,SAASE,EAAgBC,EAAsBC,EAAmC,CAChF,IAAMC,EAAYD,EAAO,WAAa,UAChCE,EAAiBF,EAAO,QAAU,KAExCD,EAAQ,iBAAiB,cAAgBI,GAAoB,CAC3D,IAAMC,EAASD,EAAE,OACXE,EAAOD,EAAO,QAAQ,IAAI,EAIhC,GAHI,CAACC,GAAQ,CAACN,EAAQ,SAASM,CAAI,GAG/BH,GAEE,CADaE,EAAO,QAAQF,CAAc,EAC/B,OAGjBC,EAAE,eAAe,EACjBE,EAAK,UAAU,IAAIJ,CAAS,EAC5BF,EAAQ,cAAc,IAAI,YAAY,iBAAkB,CAAE,QAAS,GAAM,OAAQ,CAAE,KAAAM,CAAK,CAAE,CAAC,CAAC,EAE5F,SAASC,EAAOC,EAAkB,CAChCR,EAAQ,cACN,IAAI,YAAY,gBAAiB,CAC/B,QAAS,GACT,OAAQ,CAAE,QAASQ,EAAG,QAAS,KAAAF,CAAK,CACtC,CAAC,CACH,CACF,CAEA,SAASG,GAAO,CACd,SAAS,oBAAoB,cAAeF,CAAM,EAClD,SAAS,oBAAoB,YAAaE,CAAI,EAC9CH,EAAM,UAAU,OAAOJ,CAAS,EAChCF,EAAQ,cAAc,IAAI,YAAY,eAAgB,CAAE,QAAS,GAAM,OAAQ,CAAE,KAAAM,CAAK,CAAE,CAAC,CAAC,CAC5F,CAEA,SAAS,iBAAiB,cAAeC,CAAM,EAC/C,SAAS,iBAAiB,YAAaE,CAAI,CAC7C,CAAC,CACH,CAKA,eAAsBC,EAAiBC,EAA+C,CACpF,IAAMC,EAAKD,GAAaE,EAAe,EAEvC,GAAI,CAACD,EACH,MAAM,IAAI,MACR,yFACF,EAGF,IAAME,EAAgB,CACpB,KAAM,WACN,KAAM,WACN,WAAY,CAAC,SAAU,WAAW,EAClC,cAAe,CAAC,EAChB,oBAAqBf,CACvB,EACMgB,EAAMH,EAAG,cAAgBA,EAAG,cAAc,EAAI,CAAE,OAAQ,IAAI,IAAO,QAAS,IAAI,GAAM,EAC5F,MAAMA,EAAG,QAAQE,EAAeC,CAAG,CACrC,CAGIF,EAAe,GACjBH,EAAiB,EAAE,MAAM,QAAQ,KAAK,EAGxC,IAAOM,EAAQ,CACb,OAAQnB,EAAe,OACvB,SAAUA,EACV,SAAUa,CACZ","names":["sortable_exports","__export","sortable_default","registerSortable","sortableMetadata","sortableSource","sortableSchema","resolveRuntime","win","sortableSource","sortableSchema","sortableMetadata","installSortable","element","params","dragClass","handleSelector","e","target","item","onMove","ev","onUp","registerSortable","hyperfixi","hf","resolveRuntime","syntheticNode","ctx","sortable_default"]}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
"use strict";var HyperFixiBehaviors=(()=>{var g=Object.defineProperty;var L=Object.getOwnPropertyDescriptor;var S=Object.getOwnPropertyNames;var x=Object.prototype.hasOwnProperty;var T=(t,a)=>{for(var c in a)g(t,c,{get:a[c],enumerable:!0})},E=(t,a,c,u)=>{if(a&&typeof a=="object"||typeof a=="function")for(let i of S(a))!x.call(t,i)&&i!==c&&g(t,i,{get:()=>a[i],enumerable:!(u=L(a,i))||u.enumerable});return t};var C=t=>E(g({},"__esModule",{value:!0}),t);var P={};T(P,{default:()=>z,registerTabs:()=>w,tabsMetadata:()=>I,tabsSource:()=>M});var m={name:"Tabs",category:"ui",tier:"core",version:"1.0.0",description:"WAI-ARIA compliant tabs with roving tabindex keyboard navigation. Auto-wires role, aria-selected, aria-controls, and aria-labelledby attributes.",parameters:[{name:"orientation",type:"string",optional:!0,default:"horizontal",enum:["horizontal","vertical"],description:"Arrow key direction: horizontal (Left/Right) or vertical (Up/Down)"},{name:"activeTab",type:"number",optional:!0,default:0,description:"Initial active tab index (zero-based)"},{name:"wrap",type:"boolean",optional:!0,default:!0,description:"Wrap to first/last tab when navigating past the end"},{name:"activeClass",type:"string",optional:!0,default:"active",description:"CSS class applied to the active tab and its panel"}],events:[{name:"tabs:change",description:"Fired before tab selection changes (cancelable via preventDefault)"},{name:"tabs:changed",description:"Fired after tab selection has changed"}],requirements:['Sets role="tablist" on the tab container','Sets role="tab" on tab buttons and role="tabpanel" on content panels',"Manages aria-selected, aria-controls, aria-labelledby, and tabindex","Keyboard: Arrow keys navigate, Home/End jump to first/last, Tab exits tablist"],source:["behavior Tabs(orientation, activeTab, wrap, activeClass)"," init",' if orientation is undefined set orientation to "horizontal"'," if activeTab is undefined set activeTab to 0"," if wrap is undefined set wrap to true",' if activeClass is undefined set activeClass to "active"'," end"," -- Imperative installer handles ARIA wiring and keyboard navigation","end"].join(`
|
|
2
|
+
`)};function y(){if(typeof window>"u")return null;let t=window;return t.lokascript||t.hyperfixi||null}var M=m.source,I=m,B=0;function A(t,a){return t.id||(t.id=`${a}-${++B}`),t.id}function H(t,a){let c=a.orientation==="vertical"?"vertical":"horizontal",u=a.wrap!==!1,i=a.activeClass||"active",k=typeof a.activeTab=="number"?a.activeTab:0,n=Array.from(t.querySelectorAll('[role="tab"]')),o=Array.from(t.querySelectorAll('[role="tabpanel"]'));if(n.length===0||o.length===0)return;let d=t.querySelector('[role="tablist"]')||n[0].parentElement;d&&!d.getAttribute("role")&&d.setAttribute("role","tablist"),d&&d.setAttribute("aria-orientation",c);let l=Math.min(n.length,o.length);for(let e=0;e<l;e++){let r=A(n[e],"tab"),f=A(o[e],"tabpanel");n[e].setAttribute("aria-controls",f),o[e].setAttribute("aria-labelledby",r)}let b=-1;function v(e,r){if(e===r||e<0||e>=l)return!1;let f={tab:n[e],panel:o[e],index:e,previousIndex:r},h=new CustomEvent("tabs:change",{bubbles:!0,cancelable:!0,detail:f});return t.dispatchEvent(h),h.defaultPrevented?!1:(r>=0&&r<l&&(n[r].setAttribute("aria-selected","false"),n[r].setAttribute("tabindex","-1"),n[r].classList.remove(i),o[r].setAttribute("aria-hidden","true"),o[r].classList.remove(i)),n[e].setAttribute("aria-selected","true"),n[e].setAttribute("tabindex","0"),n[e].classList.add(i),o[e].setAttribute("aria-hidden","false"),o[e].classList.add(i),b=e,t.dispatchEvent(new CustomEvent("tabs:changed",{bubbles:!0,detail:f})),!0)}for(let e=0;e<l;e++)n[e].setAttribute("aria-selected","false"),n[e].setAttribute("tabindex","-1"),n[e].classList.remove(i),o[e].setAttribute("aria-hidden","true"),o[e].classList.remove(i);let p=Math.max(0,Math.min(k,l-1));n[p].setAttribute("aria-selected","true"),n[p].setAttribute("tabindex","0"),n[p].classList.add(i),o[p].setAttribute("aria-hidden","false"),o[p].classList.add(i),b=p;for(let e=0;e<l;e++)n[e].addEventListener("click",()=>{v(e,b),n[e].focus()});(d||t).addEventListener("keydown",e=>{let r=c==="horizontal",f=r?"ArrowRight":"ArrowDown",h=r?"ArrowLeft":"ArrowUp",s=null;e.key===f?(s=b+1,s>=l&&(s=u?0:null)):e.key===h?(s=b-1,s<0&&(s=u?l-1:null)):e.key==="Home"?s=0:e.key==="End"&&(s=l-1),s!==null&&(e.preventDefault(),v(s,b)&&n[s].focus())}),t.addEventListener("tabs:select",(e=>{let r=e.detail?.index;typeof r=="number"&&v(r,b)}))}async function w(t){let a=t||y();if(!a)throw new Error("LokaScript not found. Make sure @hyperfixi/core is loaded before registering behaviors.");let c={type:"behavior",name:"Tabs",parameters:["orientation","activeTab","wrap","activeClass"],eventHandlers:[],imperativeInstaller:H},u=a.createContext?a.createContext():{locals:new Map,globals:new Map};await a.execute(c,u)}y()&&w().catch(console.error);var z={source:m.source,metadata:m,register:w};return C(P);})();
|
|
3
|
+
//# sourceMappingURL=tabs.browser.global.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/behaviors/tabs.ts","../src/schemas/tabs.schema.ts","../src/schemas/types.ts"],"sourcesContent":["/**\n * Tabs Behavior — Imperative Implementation\n *\n * WAI-ARIA compliant tabs with roving tabindex keyboard navigation.\n * Auto-wires role, aria-selected, aria-controls, and aria-labelledby.\n */\n\nimport { tabsSchema } from '../schemas/tabs.schema';\nimport type { LokaScriptInstance } from '../schemas/types';\nimport { resolveRuntime } from '../schemas/types';\n\nexport const tabsSource = tabsSchema.source;\nexport const tabsMetadata = tabsSchema;\n\nlet idCounter = 0;\n\nfunction ensureId(el: HTMLElement, prefix: string): string {\n if (!el.id) {\n el.id = `${prefix}-${++idCounter}`;\n }\n return el.id;\n}\n\n/**\n * Imperative installer for Tabs behavior.\n */\nfunction installTabs(element: HTMLElement, params: Record<string, any>): void {\n const orientation = params.orientation === 'vertical' ? 'vertical' : 'horizontal';\n const wrap = params.wrap !== false;\n const activeClass = (params.activeClass as string) || 'active';\n const initialIndex = typeof params.activeTab === 'number' ? params.activeTab : 0;\n\n // Discover tabs and panels\n const tabs = Array.from(element.querySelectorAll<HTMLElement>('[role=\"tab\"]'));\n const panels = Array.from(element.querySelectorAll<HTMLElement>('[role=\"tabpanel\"]'));\n\n if (tabs.length === 0 || panels.length === 0) return;\n\n // Find or mark the tablist\n const tablist = element.querySelector<HTMLElement>('[role=\"tablist\"]') || tabs[0].parentElement;\n if (tablist && !tablist.getAttribute('role')) {\n tablist.setAttribute('role', 'tablist');\n }\n if (tablist) {\n tablist.setAttribute('aria-orientation', orientation);\n }\n\n // Wire IDs, aria-controls, aria-labelledby\n const count = Math.min(tabs.length, panels.length);\n for (let i = 0; i < count; i++) {\n const tabId = ensureId(tabs[i], 'tab');\n const panelId = ensureId(panels[i], 'tabpanel');\n tabs[i].setAttribute('aria-controls', panelId);\n panels[i].setAttribute('aria-labelledby', tabId);\n }\n\n let currentIndex = -1;\n\n function selectTab(index: number, previousIndex: number): boolean {\n if (index === previousIndex || index < 0 || index >= count) return false;\n\n const detail = {\n tab: tabs[index],\n panel: panels[index],\n index,\n previousIndex,\n };\n\n // Cancelable before-event\n const changeEvent = new CustomEvent('tabs:change', {\n bubbles: true,\n cancelable: true,\n detail,\n });\n element.dispatchEvent(changeEvent);\n if (changeEvent.defaultPrevented) return false;\n\n // Deactivate previous\n if (previousIndex >= 0 && previousIndex < count) {\n tabs[previousIndex].setAttribute('aria-selected', 'false');\n tabs[previousIndex].setAttribute('tabindex', '-1');\n tabs[previousIndex].classList.remove(activeClass);\n panels[previousIndex].setAttribute('aria-hidden', 'true');\n panels[previousIndex].classList.remove(activeClass);\n }\n\n // Activate new\n tabs[index].setAttribute('aria-selected', 'true');\n tabs[index].setAttribute('tabindex', '0');\n tabs[index].classList.add(activeClass);\n panels[index].setAttribute('aria-hidden', 'false');\n panels[index].classList.add(activeClass);\n\n currentIndex = index;\n\n element.dispatchEvent(new CustomEvent('tabs:changed', { bubbles: true, detail }));\n return true;\n }\n\n // Initialize all tabs as inactive, then activate initial\n for (let i = 0; i < count; i++) {\n tabs[i].setAttribute('aria-selected', 'false');\n tabs[i].setAttribute('tabindex', '-1');\n tabs[i].classList.remove(activeClass);\n panels[i].setAttribute('aria-hidden', 'true');\n panels[i].classList.remove(activeClass);\n }\n\n const clamped = Math.max(0, Math.min(initialIndex, count - 1));\n // Directly activate without firing change event on init\n tabs[clamped].setAttribute('aria-selected', 'true');\n tabs[clamped].setAttribute('tabindex', '0');\n tabs[clamped].classList.add(activeClass);\n panels[clamped].setAttribute('aria-hidden', 'false');\n panels[clamped].classList.add(activeClass);\n currentIndex = clamped;\n\n // Click handler\n for (let i = 0; i < count; i++) {\n tabs[i].addEventListener('click', () => {\n selectTab(i, currentIndex);\n tabs[i].focus();\n });\n }\n\n // Keyboard handler on tablist\n const keyTarget = tablist || element;\n keyTarget.addEventListener('keydown', (e: KeyboardEvent) => {\n const isHorizontal = orientation === 'horizontal';\n const nextKey = isHorizontal ? 'ArrowRight' : 'ArrowDown';\n const prevKey = isHorizontal ? 'ArrowLeft' : 'ArrowUp';\n\n let nextIndex: number | null = null;\n\n if (e.key === nextKey) {\n nextIndex = currentIndex + 1;\n if (nextIndex >= count) nextIndex = wrap ? 0 : null;\n } else if (e.key === prevKey) {\n nextIndex = currentIndex - 1;\n if (nextIndex < 0) nextIndex = wrap ? count - 1 : null;\n } else if (e.key === 'Home') {\n nextIndex = 0;\n } else if (e.key === 'End') {\n nextIndex = count - 1;\n }\n\n if (nextIndex !== null) {\n e.preventDefault();\n if (selectTab(nextIndex, currentIndex)) {\n tabs[nextIndex].focus();\n }\n }\n });\n\n // Programmatic tab selection\n element.addEventListener('tabs:select', ((e: CustomEvent) => {\n const index = e.detail?.index;\n if (typeof index === 'number') {\n selectTab(index, currentIndex);\n }\n }) as EventListener);\n}\n\n/**\n * Register the Tabs behavior with LokaScript.\n */\nexport async function registerTabs(hyperfixi?: LokaScriptInstance): Promise<void> {\n const hf = hyperfixi || resolveRuntime();\n\n if (!hf) {\n throw new Error(\n 'LokaScript not found. Make sure @hyperfixi/core is loaded before registering behaviors.'\n );\n }\n\n const syntheticNode = {\n type: 'behavior',\n name: 'Tabs',\n parameters: ['orientation', 'activeTab', 'wrap', 'activeClass'],\n eventHandlers: [],\n imperativeInstaller: installTabs,\n };\n const ctx = hf.createContext ? hf.createContext() : { locals: new Map(), globals: new Map() };\n await hf.execute(syntheticNode, ctx);\n}\n\n// Auto-register when loaded as a script tag\nif (resolveRuntime()) {\n registerTabs().catch(console.error);\n}\n\nexport default {\n source: tabsSchema.source,\n metadata: tabsSchema,\n register: registerTabs,\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: [\n 'behavior Tabs(orientation, activeTab, wrap, activeClass)',\n ' init',\n ' if orientation is undefined set orientation to \"horizontal\"',\n ' if activeTab is undefined set activeTab to 0',\n ' if wrap is undefined set wrap to true',\n ' if activeClass is undefined set activeClass to \"active\"',\n ' end',\n ' -- Imperative installer handles ARIA wiring and keyboard navigation',\n 'end',\n ].join('\\n'),\n};\n","/**\n * Behavior Schema Types\n *\n * Defines the structure for behavior metadata used for:\n * - Code generation (TypeScript types, documentation)\n * - Runtime categorization and lazy loading\n * - Tooling and IDE integration\n */\n\n/**\n * Behavior categories for organization.\n * - ui: Visual interaction behaviors (drag, resize, sort)\n * - data: Data manipulation behaviors (remove, transform)\n * - animation: Animation and transition behaviors\n * - form: Form-related behaviors (validation, toggle states)\n * - layout: Layout behaviors (sticky, scrollspy)\n */\nexport type BehaviorCategory = 'ui' | 'data' | 'animation' | 'form' | 'layout';\n\n/**\n * Loading tiers for lazy loading optimization.\n * - core: Always loaded (essential behaviors)\n * - common: High usage (loaded for typical apps)\n * - optional: Low usage (loaded on demand)\n */\nexport type BehaviorTier = 'core' | 'common' | 'optional';\n\n/**\n * Schema for a behavior parameter.\n */\nexport interface ParameterSchema {\n name: string;\n type: 'string' | 'number' | 'boolean' | 'selector' | 'element';\n optional?: boolean;\n default?: string | number | boolean;\n /** Allowed values for constrained parameters */\n enum?: string[];\n description: string;\n}\n\n/**\n * Schema for a behavior event.\n */\nexport interface EventSchema {\n name: string;\n description: string;\n}\n\n/**\n * Complete schema for a behavior.\n * This is the source of truth for all behavior metadata.\n */\nexport interface BehaviorSchema {\n /** Behavior name (PascalCase) */\n name: string;\n /** Category for organization */\n category: BehaviorCategory;\n /** Loading tier for lazy loading */\n tier: BehaviorTier;\n /** Semantic version */\n version: string;\n /** Human-readable description */\n description: string;\n /** Parameter definitions */\n parameters: ParameterSchema[];\n /** Event definitions */\n events: EventSchema[];\n /** The hyperscript behavior source code */\n source: string;\n /** Optional requirements or notes */\n requirements?: string[];\n}\n\n/**\n * Runtime behavior module interface.\n * This is what gets registered with the hyperfixi runtime.\n */\nexport interface BehaviorModule {\n source: string;\n metadata: BehaviorSchema;\n register: (hyperfixi?: LokaScriptInstance) => Promise<void>;\n}\n\n/**\n * Minimal LokaScript instance interface for behavior registration.\n */\nexport interface LokaScriptInstance {\n compileSync: (\n code: string,\n options?: { traditional?: boolean; language?: string }\n ) => {\n ok: boolean;\n ast?: unknown;\n errors?: Array<{ message: string; line?: number; column?: number }>;\n };\n execute: (ast: unknown, ctx: unknown) => Promise<unknown>;\n createContext?: () => { locals: Map<string, unknown>; globals: Map<string, unknown> };\n}\n\n/**\n * Typed window interface for behavior auto-registration.\n * Avoids `(window as any)` casts throughout the codebase.\n * Checks both `window.lokascript` and `window.hyperfixi` for the runtime instance.\n */\nexport interface LokaScriptWindow {\n lokascript?: LokaScriptInstance;\n hyperfixi?: LokaScriptInstance;\n __hyperfixi_behaviors_ready?: Promise<void> | undefined;\n}\n\n/**\n * Resolve the LokaScript runtime from window globals.\n * Checks both `window.lokascript` and `window.hyperfixi`.\n */\nexport function resolveRuntime(): LokaScriptInstance | null {\n if (typeof window === 'undefined') return null;\n const win = window as unknown as LokaScriptWindow;\n return win.lokascript || win.hyperfixi || null;\n}\n"],"mappings":"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","names":["tabs_exports","__export","tabs_default","registerTabs","tabsMetadata","tabsSource","tabsSchema","resolveRuntime","win","tabsSource","tabsSchema","tabsMetadata","idCounter","ensureId","el","prefix","installTabs","element","params","orientation","wrap","activeClass","initialIndex","tabs","panels","tablist","count","i","tabId","panelId","currentIndex","selectTab","index","previousIndex","detail","changeEvent","clamped","isHorizontal","nextKey","prevKey","nextIndex","registerTabs","hyperfixi","hf","resolveRuntime","syntheticNode","ctx","tabs_default"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var HyperFixiBehaviors=(()=>{var
|
|
1
|
+
"use strict";var HyperFixiBehaviors=(()=>{var a=Object.defineProperty;var l=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var p=Object.prototype.hasOwnProperty;var m=(t,e)=>{for(var r in e)a(t,r,{get:e[r],enumerable:!0})},d=(t,e,r,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of g(e))!p.call(t,n)&&n!==r&&a(t,n,{get:()=>e[n],enumerable:!(o=l(e,n))||o.enumerable});return t};var u=t=>d(a({},"__esModule",{value:!0}),t);var y={};m(y,{default:()=>b,registerToggleable:()=>c,toggleableMetadata:()=>h,toggleableSource:()=>f});var i={name:"Toggleable",category:"form",tier:"core",version:"1.0.0",description:"Toggles a CSS class on click",parameters:[{name:"cls",type:"string",optional:!0,default:"active",description:"CSS class to toggle"},{name:"target",type:"selector",optional:!0,default:"me",description:"Element to toggle the class on"}],events:[{name:"toggleable:on",description:"Fired when class is added"},{name:"toggleable:off",description:"Fired when class is removed"}],source:`
|
|
2
2
|
behavior Toggleable(cls, target)
|
|
3
3
|
init
|
|
4
4
|
if cls is undefined
|
|
@@ -12,5 +12,5 @@ behavior Toggleable(cls, target)
|
|
|
12
12
|
toggle .{cls} on target
|
|
13
13
|
end
|
|
14
14
|
end
|
|
15
|
-
`.trim()};var f=
|
|
15
|
+
`.trim()};function s(){if(typeof window>"u")return null;let t=window;return t.lokascript||t.hyperfixi||null}var f=i.source,h=i;function v(t,e){let r=e.cls||"active",o=t;if(e.target&&e.target!=="me")if(typeof e.target=="string"){let n=document.querySelector(e.target);n instanceof HTMLElement&&(o=n)}else e.target instanceof HTMLElement&&(o=e.target);t.addEventListener("click",()=>{let n=o.classList.contains(r);o.classList.toggle(r),o.dispatchEvent(new CustomEvent(n?"toggleable:off":"toggleable:on",{bubbles:!0}))})}async function c(t){let e=t||s();if(!e)throw new Error("LokaScript not found. Make sure @hyperfixi/core is loaded before registering behaviors.");let r={type:"behavior",name:"Toggleable",parameters:["cls","target"],eventHandlers:[],imperativeInstaller:v},o=e.createContext?e.createContext():{locals:new Map,globals:new Map};await e.execute(r,o)}s()&&c().catch(console.error);var b={source:i.source,metadata:i,register:c};return u(y);})();
|
|
16
16
|
//# sourceMappingURL=toggleable.browser.global.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/behaviors/toggleable.ts","../src/schemas/toggleable.schema.ts"],"sourcesContent":["/**\n * Toggleable Behavior\n *\n * A behavior that toggles a CSS class on click.\n * Useful for accordions, dropdowns, and toggle buttons.\n *\n * @example\n * ```html\n * <button _=\"install Toggleable\">Toggle</button>\n *\n * <button _=\"install Toggleable(cls: expanded, target: #menu)\">Menu</button>\n * ```\n */\n\nimport { toggleableSchema } from '../schemas/toggleable.schema';\nimport type { LokaScriptInstance
|
|
1
|
+
{"version":3,"sources":["../src/behaviors/toggleable.ts","../src/schemas/toggleable.schema.ts","../src/schemas/types.ts"],"sourcesContent":["/**\n * Toggleable Behavior — Imperative Implementation\n *\n * A behavior that toggles a CSS class on click.\n * Useful for accordions, dropdowns, and toggle buttons.\n *\n * Uses direct DOM APIs instead of compiling hyperscript source,\n * because `toggle .{cls}` template interpolation doesn't resolve\n * behavior parameters at runtime.\n *\n * @example\n * ```html\n * <button _=\"install Toggleable\">Toggle</button>\n *\n * <button _=\"install Toggleable(cls: expanded, target: #menu)\">Menu</button>\n * ```\n */\n\nimport { toggleableSchema } from '../schemas/toggleable.schema';\nimport type { LokaScriptInstance } from '../schemas/types';\nimport { resolveRuntime } from '../schemas/types';\n\n// Re-export schema-derived values for backwards compatibility\nexport const toggleableSource = toggleableSchema.source;\nexport const toggleableMetadata = toggleableSchema;\n\n/**\n * Imperative installer for Toggleable behavior.\n * Called directly by the runtime when `install Toggleable` is executed.\n */\nfunction installToggleable(element: HTMLElement, params: Record<string, any>): void {\n const cls = params.cls || 'active';\n\n // Resolve target element\n let targetEl: HTMLElement = element;\n if (params.target && params.target !== 'me') {\n if (typeof params.target === 'string') {\n const found = document.querySelector(params.target);\n if (found instanceof HTMLElement) targetEl = found;\n } else if (params.target instanceof HTMLElement) {\n targetEl = params.target;\n }\n }\n\n element.addEventListener('click', () => {\n const wasOn = targetEl.classList.contains(cls);\n targetEl.classList.toggle(cls);\n targetEl.dispatchEvent(\n new CustomEvent(wasOn ? 'toggleable:off' : 'toggleable:on', { bubbles: true })\n );\n });\n}\n\n/**\n * Register the Toggleable behavior with LokaScript.\n * Uses imperative installer via synthetic behavior node.\n */\nexport async function registerToggleable(hyperfixi?: LokaScriptInstance): Promise<void> {\n const hf = hyperfixi || resolveRuntime();\n\n if (!hf) {\n throw new Error(\n 'LokaScript not found. Make sure @hyperfixi/core is loaded before registering behaviors.'\n );\n }\n\n const syntheticNode = {\n type: 'behavior',\n name: 'Toggleable',\n parameters: ['cls', 'target'],\n eventHandlers: [],\n imperativeInstaller: installToggleable,\n };\n const ctx = hf.createContext ? hf.createContext() : { locals: new Map(), globals: new Map() };\n await hf.execute(syntheticNode, ctx);\n}\n\n// Auto-register when loaded as a script tag\nif (resolveRuntime()) {\n registerToggleable().catch(console.error);\n}\n\nexport default {\n source: toggleableSchema.source,\n metadata: toggleableSchema,\n register: registerToggleable,\n};\n","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 end\nend\n`.trim(),\n};\n","/**\n * Behavior Schema Types\n *\n * Defines the structure for behavior metadata used for:\n * - Code generation (TypeScript types, documentation)\n * - Runtime categorization and lazy loading\n * - Tooling and IDE integration\n */\n\n/**\n * Behavior categories for organization.\n * - ui: Visual interaction behaviors (drag, resize, sort)\n * - data: Data manipulation behaviors (remove, transform)\n * - animation: Animation and transition behaviors\n * - form: Form-related behaviors (validation, toggle states)\n * - layout: Layout behaviors (sticky, scrollspy)\n */\nexport type BehaviorCategory = 'ui' | 'data' | 'animation' | 'form' | 'layout';\n\n/**\n * Loading tiers for lazy loading optimization.\n * - core: Always loaded (essential behaviors)\n * - common: High usage (loaded for typical apps)\n * - optional: Low usage (loaded on demand)\n */\nexport type BehaviorTier = 'core' | 'common' | 'optional';\n\n/**\n * Schema for a behavior parameter.\n */\nexport interface ParameterSchema {\n name: string;\n type: 'string' | 'number' | 'boolean' | 'selector' | 'element';\n optional?: boolean;\n default?: string | number | boolean;\n /** Allowed values for constrained parameters */\n enum?: string[];\n description: string;\n}\n\n/**\n * Schema for a behavior event.\n */\nexport interface EventSchema {\n name: string;\n description: string;\n}\n\n/**\n * Complete schema for a behavior.\n * This is the source of truth for all behavior metadata.\n */\nexport interface BehaviorSchema {\n /** Behavior name (PascalCase) */\n name: string;\n /** Category for organization */\n category: BehaviorCategory;\n /** Loading tier for lazy loading */\n tier: BehaviorTier;\n /** Semantic version */\n version: string;\n /** Human-readable description */\n description: string;\n /** Parameter definitions */\n parameters: ParameterSchema[];\n /** Event definitions */\n events: EventSchema[];\n /** The hyperscript behavior source code */\n source: string;\n /** Optional requirements or notes */\n requirements?: string[];\n}\n\n/**\n * Runtime behavior module interface.\n * This is what gets registered with the hyperfixi runtime.\n */\nexport interface BehaviorModule {\n source: string;\n metadata: BehaviorSchema;\n register: (hyperfixi?: LokaScriptInstance) => Promise<void>;\n}\n\n/**\n * Minimal LokaScript instance interface for behavior registration.\n */\nexport interface LokaScriptInstance {\n compileSync: (\n code: string,\n options?: { traditional?: boolean; language?: string }\n ) => {\n ok: boolean;\n ast?: unknown;\n errors?: Array<{ message: string; line?: number; column?: number }>;\n };\n execute: (ast: unknown, ctx: unknown) => Promise<unknown>;\n createContext?: () => { locals: Map<string, unknown>; globals: Map<string, unknown> };\n}\n\n/**\n * Typed window interface for behavior auto-registration.\n * Avoids `(window as any)` casts throughout the codebase.\n * Checks both `window.lokascript` and `window.hyperfixi` for the runtime instance.\n */\nexport interface LokaScriptWindow {\n lokascript?: LokaScriptInstance;\n hyperfixi?: LokaScriptInstance;\n __hyperfixi_behaviors_ready?: Promise<void> | undefined;\n}\n\n/**\n * Resolve the LokaScript runtime from window globals.\n * Checks both `window.lokascript` and `window.hyperfixi`.\n */\nexport function resolveRuntime(): LokaScriptInstance | null {\n if (typeof window === 'undefined') return null;\n const win = window as unknown as LokaScriptWindow;\n return win.lokascript || win.hyperfixi || null;\n}\n"],"mappings":"scAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,aAAAE,EAAA,uBAAAC,EAAA,uBAAAC,EAAA,qBAAAC,ICQO,IAAMC,EAAmC,CAC9C,KAAM,aACN,SAAU,OACV,KAAM,OACN,QAAS,QACT,YAAa,+BACb,WAAY,CACV,CACE,KAAM,MACN,KAAM,SACN,SAAU,GACV,QAAS,SACT,YAAa,qBACf,EACA,CACE,KAAM,SACN,KAAM,WACN,SAAU,GACV,QAAS,KACT,YAAa,gCACf,CACF,EACA,OAAQ,CACN,CAAE,KAAM,gBAAiB,YAAa,2BAA4B,EAClE,CAAE,KAAM,iBAAkB,YAAa,6BAA8B,CACvE,EACA,OAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcR,KAAK,CACP,ECiEO,SAASC,GAA4C,CAC1D,GAAI,OAAO,OAAW,IAAa,OAAO,KAC1C,IAAMC,EAAM,OACZ,OAAOA,EAAI,YAAcA,EAAI,WAAa,IAC5C,CF/FO,IAAMC,EAAmBC,EAAiB,OACpCC,EAAqBD,EAMlC,SAASE,EAAkBC,EAAsBC,EAAmC,CAClF,IAAMC,EAAMD,EAAO,KAAO,SAGtBE,EAAwBH,EAC5B,GAAIC,EAAO,QAAUA,EAAO,SAAW,KACrC,GAAI,OAAOA,EAAO,QAAW,SAAU,CACrC,IAAMG,EAAQ,SAAS,cAAcH,EAAO,MAAM,EAC9CG,aAAiB,cAAaD,EAAWC,EAC/C,MAAWH,EAAO,kBAAkB,cAClCE,EAAWF,EAAO,QAItBD,EAAQ,iBAAiB,QAAS,IAAM,CACtC,IAAMK,EAAQF,EAAS,UAAU,SAASD,CAAG,EAC7CC,EAAS,UAAU,OAAOD,CAAG,EAC7BC,EAAS,cACP,IAAI,YAAYE,EAAQ,iBAAmB,gBAAiB,CAAE,QAAS,EAAK,CAAC,CAC/E,CACF,CAAC,CACH,CAMA,eAAsBC,EAAmBC,EAA+C,CACtF,IAAMC,EAAKD,GAAaE,EAAe,EAEvC,GAAI,CAACD,EACH,MAAM,IAAI,MACR,yFACF,EAGF,IAAME,EAAgB,CACpB,KAAM,WACN,KAAM,aACN,WAAY,CAAC,MAAO,QAAQ,EAC5B,cAAe,CAAC,EAChB,oBAAqBX,CACvB,EACMY,EAAMH,EAAG,cAAgBA,EAAG,cAAc,EAAI,CAAE,OAAQ,IAAI,IAAO,QAAS,IAAI,GAAM,EAC5F,MAAMA,EAAG,QAAQE,EAAeC,CAAG,CACrC,CAGIF,EAAe,GACjBH,EAAmB,EAAE,MAAM,QAAQ,KAAK,EAG1C,IAAOM,EAAQ,CACb,OAAQf,EAAiB,OACzB,SAAUA,EACV,SAAUS,CACZ","names":["toggleable_exports","__export","toggleable_default","registerToggleable","toggleableMetadata","toggleableSource","toggleableSchema","resolveRuntime","win","toggleableSource","toggleableSchema","toggleableMetadata","installToggleable","element","params","cls","targetEl","found","wasOn","registerToggleable","hyperfixi","hf","resolveRuntime","syntheticNode","ctx","toggleable_default"]}
|
|
@@ -97,4 +97,4 @@ interface LokaScriptInstance {
|
|
|
97
97
|
};
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
export type {
|
|
100
|
+
export type { BehaviorSchema as B, EventSchema as E, LokaScriptInstance as L, ParameterSchema as P, BehaviorModule as a, BehaviorCategory as b, BehaviorTier as c };
|
|
@@ -97,4 +97,4 @@ interface LokaScriptInstance {
|
|
|
97
97
|
};
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
export type {
|
|
100
|
+
export type { BehaviorSchema as B, EventSchema as E, LokaScriptInstance as L, ParameterSchema as P, BehaviorModule as a, BehaviorCategory as b, BehaviorTier as c };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperfixi/behaviors",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Reusable hyperscript behaviors for LokaScript",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -56,7 +56,43 @@
|
|
|
56
56
|
"./removable.browser.js": "./dist/removable.browser.global.js",
|
|
57
57
|
"./toggleable.browser.js": "./dist/toggleable.browser.global.js",
|
|
58
58
|
"./sortable.browser.js": "./dist/sortable.browser.global.js",
|
|
59
|
+
"./clipboard": {
|
|
60
|
+
"types": "./dist/behaviors/clipboard.d.ts",
|
|
61
|
+
"import": "./dist/behaviors/clipboard.js",
|
|
62
|
+
"require": "./dist/behaviors/clipboard.cjs"
|
|
63
|
+
},
|
|
64
|
+
"./autodismiss": {
|
|
65
|
+
"types": "./dist/behaviors/autodismiss.d.ts",
|
|
66
|
+
"import": "./dist/behaviors/autodismiss.js",
|
|
67
|
+
"require": "./dist/behaviors/autodismiss.cjs"
|
|
68
|
+
},
|
|
69
|
+
"./clickoutside": {
|
|
70
|
+
"types": "./dist/behaviors/clickoutside.d.ts",
|
|
71
|
+
"import": "./dist/behaviors/clickoutside.js",
|
|
72
|
+
"require": "./dist/behaviors/clickoutside.cjs"
|
|
73
|
+
},
|
|
74
|
+
"./focustrap": {
|
|
75
|
+
"types": "./dist/behaviors/focustrap.d.ts",
|
|
76
|
+
"import": "./dist/behaviors/focustrap.js",
|
|
77
|
+
"require": "./dist/behaviors/focustrap.cjs"
|
|
78
|
+
},
|
|
79
|
+
"./scrollreveal": {
|
|
80
|
+
"types": "./dist/behaviors/scrollreveal.d.ts",
|
|
81
|
+
"import": "./dist/behaviors/scrollreveal.js",
|
|
82
|
+
"require": "./dist/behaviors/scrollreveal.cjs"
|
|
83
|
+
},
|
|
84
|
+
"./tabs": {
|
|
85
|
+
"types": "./dist/behaviors/tabs.d.ts",
|
|
86
|
+
"import": "./dist/behaviors/tabs.js",
|
|
87
|
+
"require": "./dist/behaviors/tabs.cjs"
|
|
88
|
+
},
|
|
59
89
|
"./resizable.browser.js": "./dist/resizable.browser.global.js",
|
|
90
|
+
"./clipboard.browser.js": "./dist/clipboard.browser.global.js",
|
|
91
|
+
"./autodismiss.browser.js": "./dist/autodismiss.browser.global.js",
|
|
92
|
+
"./clickoutside.browser.js": "./dist/clickoutside.browser.global.js",
|
|
93
|
+
"./focustrap.browser.js": "./dist/focustrap.browser.global.js",
|
|
94
|
+
"./scrollreveal.browser.js": "./dist/scrollreveal.browser.global.js",
|
|
95
|
+
"./tabs.browser.js": "./dist/tabs.browser.global.js",
|
|
60
96
|
"./all.browser.js": "./dist/all.browser.global.js",
|
|
61
97
|
"./core.browser.js": "./dist/core.browser.global.js"
|
|
62
98
|
},
|
|
@@ -71,7 +107,8 @@
|
|
|
71
107
|
"build:watch": "tsup --watch",
|
|
72
108
|
"typecheck": "tsc --noEmit",
|
|
73
109
|
"test": "vitest run",
|
|
74
|
-
"test:watch": "vitest"
|
|
110
|
+
"test:watch": "vitest",
|
|
111
|
+
"test:check": "vitest run --reporter=dot 2>&1 | tail -5"
|
|
75
112
|
},
|
|
76
113
|
"peerDependencies": {
|
|
77
114
|
"@hyperfixi/core": "*"
|
|
@@ -91,6 +128,12 @@
|
|
|
91
128
|
"resizable",
|
|
92
129
|
"removable",
|
|
93
130
|
"toggleable",
|
|
131
|
+
"clipboard",
|
|
132
|
+
"autodismiss",
|
|
133
|
+
"clickoutside",
|
|
134
|
+
"focustrap",
|
|
135
|
+
"scrollreveal",
|
|
136
|
+
"tabs",
|
|
94
137
|
"ui-components"
|
|
95
138
|
],
|
|
96
139
|
"license": "MIT",
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
describe('AutoDismiss behavior', () => {
|
|
4
|
+
describe('registerAutoDismiss', () => {
|
|
5
|
+
it('should register with synthetic node via execute', async () => {
|
|
6
|
+
const { registerAutoDismiss } = await import('./autodismiss');
|
|
7
|
+
const mock = {
|
|
8
|
+
compileSync: vi.fn(),
|
|
9
|
+
execute: vi.fn().mockResolvedValue(undefined),
|
|
10
|
+
createContext: vi.fn().mockReturnValue({ locals: new Map(), globals: new Map() }),
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
await registerAutoDismiss(mock);
|
|
14
|
+
|
|
15
|
+
expect(mock.compileSync).not.toHaveBeenCalled();
|
|
16
|
+
expect(mock.execute).toHaveBeenCalledWith(
|
|
17
|
+
expect.objectContaining({
|
|
18
|
+
type: 'behavior',
|
|
19
|
+
name: 'AutoDismiss',
|
|
20
|
+
imperativeInstaller: expect.any(Function),
|
|
21
|
+
}),
|
|
22
|
+
expect.objectContaining({ locals: expect.any(Map), globals: expect.any(Map) })
|
|
23
|
+
);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should throw when no runtime available', async () => {
|
|
27
|
+
const { registerAutoDismiss } = await import('./autodismiss');
|
|
28
|
+
await expect(registerAutoDismiss(undefined)).rejects.toThrowError(/LokaScript not found/);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
describe('schema', () => {
|
|
33
|
+
it('should export valid metadata', async () => {
|
|
34
|
+
const { autoDismissMetadata } = await import('./autodismiss');
|
|
35
|
+
expect(autoDismissMetadata.name).toBe('AutoDismiss');
|
|
36
|
+
expect(autoDismissMetadata.category).toBe('ui');
|
|
37
|
+
expect(autoDismissMetadata.tier).toBe('core');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should have source containing behavior declaration', async () => {
|
|
41
|
+
const { autoDismissSource } = await import('./autodismiss');
|
|
42
|
+
expect(autoDismissSource).toContain('behavior AutoDismiss');
|
|
43
|
+
expect(autoDismissSource).toContain('autodismiss:dismissed');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should document all lifecycle events', async () => {
|
|
47
|
+
const { autoDismissMetadata } = await import('./autodismiss');
|
|
48
|
+
const eventNames = autoDismissMetadata.events.map(e => e.name);
|
|
49
|
+
expect(eventNames).toContain('autodismiss:start');
|
|
50
|
+
expect(eventNames).toContain('autodismiss:dismissed');
|
|
51
|
+
expect(eventNames).toContain('autodismiss:paused');
|
|
52
|
+
expect(eventNames).toContain('autodismiss:resumed');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('should have fade enum for effect parameter', async () => {
|
|
56
|
+
const { autoDismissMetadata } = await import('./autodismiss');
|
|
57
|
+
const effectParam = autoDismissMetadata.parameters.find(p => p.name === 'effect');
|
|
58
|
+
expect(effectParam?.enum).toEqual(['fade', 'none']);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AutoDismiss Behavior — Imperative Implementation
|
|
3
|
+
*
|
|
4
|
+
* Auto-removes elements after a configurable delay.
|
|
5
|
+
* Supports pause-on-hover and fade effect using standard setTimeout/clearTimeout.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { autoDismissSchema } from '../schemas/autodismiss.schema';
|
|
9
|
+
import type { LokaScriptInstance } from '../schemas/types';
|
|
10
|
+
import { resolveRuntime } from '../schemas/types';
|
|
11
|
+
|
|
12
|
+
// Re-export schema-derived values
|
|
13
|
+
export const autoDismissSource = autoDismissSchema.source;
|
|
14
|
+
export const autoDismissMetadata = autoDismissSchema;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Imperative installer for AutoDismiss behavior.
|
|
18
|
+
*/
|
|
19
|
+
function installAutoDismiss(element: HTMLElement, params: Record<string, any>): void {
|
|
20
|
+
const delay = typeof params.delay === 'number' ? params.delay : 5000;
|
|
21
|
+
const pauseOnHover = params.pauseOnHover !== false;
|
|
22
|
+
const effect = params.effect === 'fade' ? 'fade' : 'none';
|
|
23
|
+
|
|
24
|
+
let timerId: ReturnType<typeof setTimeout> | null = null;
|
|
25
|
+
let remaining = delay;
|
|
26
|
+
let startedAt = Date.now();
|
|
27
|
+
|
|
28
|
+
function dismiss() {
|
|
29
|
+
const event = new CustomEvent('autodismiss:dismissed', {
|
|
30
|
+
bubbles: true,
|
|
31
|
+
cancelable: true,
|
|
32
|
+
});
|
|
33
|
+
element.dispatchEvent(event);
|
|
34
|
+
|
|
35
|
+
if (event.defaultPrevented) return;
|
|
36
|
+
|
|
37
|
+
if (effect === 'fade') {
|
|
38
|
+
element.style.transition = 'opacity 300ms';
|
|
39
|
+
element.style.opacity = '0';
|
|
40
|
+
setTimeout(() => element.remove(), 300);
|
|
41
|
+
} else {
|
|
42
|
+
element.remove();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function start() {
|
|
47
|
+
startedAt = Date.now();
|
|
48
|
+
timerId = setTimeout(dismiss, remaining);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Start the countdown
|
|
52
|
+
element.dispatchEvent(new CustomEvent('autodismiss:start', { bubbles: true }));
|
|
53
|
+
start();
|
|
54
|
+
|
|
55
|
+
if (pauseOnHover) {
|
|
56
|
+
element.addEventListener('mouseenter', () => {
|
|
57
|
+
if (timerId != null) {
|
|
58
|
+
clearTimeout(timerId);
|
|
59
|
+
timerId = null;
|
|
60
|
+
remaining -= Date.now() - startedAt;
|
|
61
|
+
if (remaining < 0) remaining = 0;
|
|
62
|
+
element.dispatchEvent(new CustomEvent('autodismiss:paused', { bubbles: true }));
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
element.addEventListener('mouseleave', () => {
|
|
67
|
+
if (timerId == null && element.isConnected) {
|
|
68
|
+
element.dispatchEvent(new CustomEvent('autodismiss:resumed', { bubbles: true }));
|
|
69
|
+
start();
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Register the AutoDismiss behavior with LokaScript.
|
|
77
|
+
*/
|
|
78
|
+
export async function registerAutoDismiss(hyperfixi?: LokaScriptInstance): Promise<void> {
|
|
79
|
+
const hf = hyperfixi || resolveRuntime();
|
|
80
|
+
|
|
81
|
+
if (!hf) {
|
|
82
|
+
throw new Error(
|
|
83
|
+
'LokaScript not found. Make sure @hyperfixi/core is loaded before registering behaviors.'
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const syntheticNode = {
|
|
88
|
+
type: 'behavior',
|
|
89
|
+
name: 'AutoDismiss',
|
|
90
|
+
parameters: ['delay', 'pauseOnHover', 'effect'],
|
|
91
|
+
eventHandlers: [],
|
|
92
|
+
imperativeInstaller: installAutoDismiss,
|
|
93
|
+
};
|
|
94
|
+
const ctx = hf.createContext ? hf.createContext() : { locals: new Map(), globals: new Map() };
|
|
95
|
+
await hf.execute(syntheticNode, ctx);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Auto-register when loaded as a script tag
|
|
99
|
+
if (resolveRuntime()) {
|
|
100
|
+
registerAutoDismiss().catch(console.error);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export default {
|
|
104
|
+
source: autoDismissSchema.source,
|
|
105
|
+
metadata: autoDismissSchema,
|
|
106
|
+
register: registerAutoDismiss,
|
|
107
|
+
};
|