@hyperfixi/behaviors 2.0.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.
Files changed (118) hide show
  1. package/dist/all.browser.global.js +116 -0
  2. package/dist/all.browser.global.js.map +1 -0
  3. package/dist/behaviors/draggable.cjs +109 -0
  4. package/dist/behaviors/draggable.cjs.map +1 -0
  5. package/dist/behaviors/draggable.d.cts +15 -0
  6. package/dist/behaviors/draggable.d.ts +15 -0
  7. package/dist/behaviors/draggable.js +14 -0
  8. package/dist/behaviors/draggable.js.map +1 -0
  9. package/dist/behaviors/removable.cjs +120 -0
  10. package/dist/behaviors/removable.cjs.map +1 -0
  11. package/dist/behaviors/removable.d.cts +15 -0
  12. package/dist/behaviors/removable.d.ts +15 -0
  13. package/dist/behaviors/removable.js +14 -0
  14. package/dist/behaviors/removable.js.map +1 -0
  15. package/dist/behaviors/resizable.cjs +146 -0
  16. package/dist/behaviors/resizable.cjs.map +1 -0
  17. package/dist/behaviors/resizable.d.cts +15 -0
  18. package/dist/behaviors/resizable.d.ts +15 -0
  19. package/dist/behaviors/resizable.js +14 -0
  20. package/dist/behaviors/resizable.js.map +1 -0
  21. package/dist/behaviors/sortable.cjs +119 -0
  22. package/dist/behaviors/sortable.cjs.map +1 -0
  23. package/dist/behaviors/sortable.d.cts +15 -0
  24. package/dist/behaviors/sortable.d.ts +15 -0
  25. package/dist/behaviors/sortable.js +14 -0
  26. package/dist/behaviors/sortable.js.map +1 -0
  27. package/dist/behaviors/toggleable.cjs +105 -0
  28. package/dist/behaviors/toggleable.cjs.map +1 -0
  29. package/dist/behaviors/toggleable.d.cts +15 -0
  30. package/dist/behaviors/toggleable.d.ts +15 -0
  31. package/dist/behaviors/toggleable.js +14 -0
  32. package/dist/behaviors/toggleable.js.map +1 -0
  33. package/dist/chunk-272NKUJ3.js +63 -0
  34. package/dist/chunk-272NKUJ3.js.map +1 -0
  35. package/dist/chunk-2NQHIHD5.js +37 -0
  36. package/dist/chunk-2NQHIHD5.js.map +1 -0
  37. package/dist/chunk-3DVDS7CT.js +170 -0
  38. package/dist/chunk-3DVDS7CT.js.map +1 -0
  39. package/dist/chunk-3Q652JQB.js +37 -0
  40. package/dist/chunk-3Q652JQB.js.map +1 -0
  41. package/dist/chunk-BWZ6EGII.js +62 -0
  42. package/dist/chunk-BWZ6EGII.js.map +1 -0
  43. package/dist/chunk-G6WR2AYR.js +52 -0
  44. package/dist/chunk-G6WR2AYR.js.map +1 -0
  45. package/dist/chunk-HMRPQWQU.js +37 -0
  46. package/dist/chunk-HMRPQWQU.js.map +1 -0
  47. package/dist/chunk-MEP6B7XW.js +37 -0
  48. package/dist/chunk-MEP6B7XW.js.map +1 -0
  49. package/dist/chunk-URBOGGW6.js +32 -0
  50. package/dist/chunk-URBOGGW6.js.map +1 -0
  51. package/dist/chunk-V5IWDPDP.js +89 -0
  52. package/dist/chunk-V5IWDPDP.js.map +1 -0
  53. package/dist/chunk-WU37DFAL.js +37 -0
  54. package/dist/chunk-WU37DFAL.js.map +1 -0
  55. package/dist/chunk-WUHHMDAA.js +48 -0
  56. package/dist/chunk-WUHHMDAA.js.map +1 -0
  57. package/dist/core.browser.global.js +39 -0
  58. package/dist/core.browser.global.js.map +1 -0
  59. package/dist/draggable.browser.global.js +25 -0
  60. package/dist/draggable.browser.global.js.map +1 -0
  61. package/dist/index.cjs +907 -0
  62. package/dist/index.cjs.map +1 -0
  63. package/dist/index.d.cts +134 -0
  64. package/dist/index.d.ts +134 -0
  65. package/dist/index.js +193 -0
  66. package/dist/index.js.map +1 -0
  67. package/dist/loaders.cjs +562 -0
  68. package/dist/loaders.cjs.map +1 -0
  69. package/dist/loaders.d.cts +2 -0
  70. package/dist/loaders.d.ts +2 -0
  71. package/dist/loaders.js +8 -0
  72. package/dist/loaders.js.map +1 -0
  73. package/dist/registry.cjs +214 -0
  74. package/dist/registry.cjs.map +1 -0
  75. package/dist/registry.d.cts +116 -0
  76. package/dist/registry.d.ts +116 -0
  77. package/dist/registry.js +47 -0
  78. package/dist/registry.js.map +1 -0
  79. package/dist/removable.browser.global.js +23 -0
  80. package/dist/removable.browser.global.js.map +1 -0
  81. package/dist/resizable.browser.global.js +35 -0
  82. package/dist/resizable.browser.global.js.map +1 -0
  83. package/dist/schemas/index.cjs +353 -0
  84. package/dist/schemas/index.cjs.map +1 -0
  85. package/dist/schemas/index.d.cts +75 -0
  86. package/dist/schemas/index.d.ts +75 -0
  87. package/dist/schemas/index.js +41 -0
  88. package/dist/schemas/index.js.map +1 -0
  89. package/dist/sortable.browser.global.js +25 -0
  90. package/dist/sortable.browser.global.js.map +1 -0
  91. package/dist/toggleable.browser.global.js +16 -0
  92. package/dist/toggleable.browser.global.js.map +1 -0
  93. package/dist/types-CCc_2wAb.d.cts +100 -0
  94. package/dist/types-CCc_2wAb.d.ts +100 -0
  95. package/package.json +109 -0
  96. package/src/behaviors/draggable.ts +60 -0
  97. package/src/behaviors/index.ts +40 -0
  98. package/src/behaviors/integration.test.ts +80 -0
  99. package/src/behaviors/removable.ts +55 -0
  100. package/src/behaviors/resizable.ts +55 -0
  101. package/src/behaviors/sortable.ts +56 -0
  102. package/src/behaviors/toggleable.ts +55 -0
  103. package/src/core-bundle.ts +35 -0
  104. package/src/generated/index.ts +9 -0
  105. package/src/generated/metadata.ts +78 -0
  106. package/src/generated/types.ts +51 -0
  107. package/src/index.test.ts +180 -0
  108. package/src/index.ts +222 -0
  109. package/src/loaders.ts +39 -0
  110. package/src/registry.test.ts +207 -0
  111. package/src/registry.ts +304 -0
  112. package/src/schemas/draggable.schema.ts +54 -0
  113. package/src/schemas/index.ts +60 -0
  114. package/src/schemas/removable.schema.ts +69 -0
  115. package/src/schemas/resizable.schema.ts +91 -0
  116. package/src/schemas/sortable.schema.ts +68 -0
  117. package/src/schemas/toggleable.schema.ts +50 -0
  118. package/src/schemas/types.ts +107 -0
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Behavior Schema Types
3
+ *
4
+ * Defines the structure for behavior metadata used for:
5
+ * - Code generation (TypeScript types, documentation)
6
+ * - Runtime categorization and lazy loading
7
+ * - Tooling and IDE integration
8
+ */
9
+ /**
10
+ * Behavior categories for organization.
11
+ * - ui: Visual interaction behaviors (drag, resize, sort)
12
+ * - data: Data manipulation behaviors (remove, transform)
13
+ * - animation: Animation and transition behaviors
14
+ * - form: Form-related behaviors (validation, toggle states)
15
+ * - layout: Layout behaviors (sticky, scrollspy)
16
+ */
17
+ type BehaviorCategory = 'ui' | 'data' | 'animation' | 'form' | 'layout';
18
+ /**
19
+ * Loading tiers for lazy loading optimization.
20
+ * - core: Always loaded (essential behaviors)
21
+ * - common: High usage (loaded for typical apps)
22
+ * - optional: Low usage (loaded on demand)
23
+ */
24
+ type BehaviorTier = 'core' | 'common' | 'optional';
25
+ /**
26
+ * Schema for a behavior parameter.
27
+ */
28
+ interface ParameterSchema {
29
+ name: string;
30
+ type: 'string' | 'number' | 'boolean' | 'selector' | 'element';
31
+ optional?: boolean;
32
+ default?: string | number | boolean;
33
+ /** Allowed values for constrained parameters */
34
+ enum?: string[];
35
+ description: string;
36
+ }
37
+ /**
38
+ * Schema for a behavior event.
39
+ */
40
+ interface EventSchema {
41
+ name: string;
42
+ description: string;
43
+ }
44
+ /**
45
+ * Complete schema for a behavior.
46
+ * This is the source of truth for all behavior metadata.
47
+ */
48
+ interface BehaviorSchema {
49
+ /** Behavior name (PascalCase) */
50
+ name: string;
51
+ /** Category for organization */
52
+ category: BehaviorCategory;
53
+ /** Loading tier for lazy loading */
54
+ tier: BehaviorTier;
55
+ /** Semantic version */
56
+ version: string;
57
+ /** Human-readable description */
58
+ description: string;
59
+ /** Parameter definitions */
60
+ parameters: ParameterSchema[];
61
+ /** Event definitions */
62
+ events: EventSchema[];
63
+ /** The hyperscript behavior source code */
64
+ source: string;
65
+ /** Optional requirements or notes */
66
+ requirements?: string[];
67
+ }
68
+ /**
69
+ * Runtime behavior module interface.
70
+ * This is what gets registered with the hyperfixi runtime.
71
+ */
72
+ interface BehaviorModule {
73
+ source: string;
74
+ metadata: BehaviorSchema;
75
+ register: (hyperfixi?: LokaScriptInstance) => Promise<void>;
76
+ }
77
+ /**
78
+ * Minimal LokaScript instance interface for behavior registration.
79
+ */
80
+ interface LokaScriptInstance {
81
+ compileSync: (code: string, options?: {
82
+ traditional?: boolean;
83
+ language?: string;
84
+ }) => {
85
+ ok: boolean;
86
+ ast?: unknown;
87
+ errors?: Array<{
88
+ message: string;
89
+ line?: number;
90
+ column?: number;
91
+ }>;
92
+ };
93
+ execute: (ast: unknown, ctx: unknown) => Promise<unknown>;
94
+ createContext?: () => {
95
+ locals: Map<string, unknown>;
96
+ globals: Map<string, unknown>;
97
+ };
98
+ }
99
+
100
+ export type { BehaviorModule as B, EventSchema as E, LokaScriptInstance as L, ParameterSchema as P, BehaviorSchema as a, BehaviorCategory as b, BehaviorTier as c };
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Behavior Schema Types
3
+ *
4
+ * Defines the structure for behavior metadata used for:
5
+ * - Code generation (TypeScript types, documentation)
6
+ * - Runtime categorization and lazy loading
7
+ * - Tooling and IDE integration
8
+ */
9
+ /**
10
+ * Behavior categories for organization.
11
+ * - ui: Visual interaction behaviors (drag, resize, sort)
12
+ * - data: Data manipulation behaviors (remove, transform)
13
+ * - animation: Animation and transition behaviors
14
+ * - form: Form-related behaviors (validation, toggle states)
15
+ * - layout: Layout behaviors (sticky, scrollspy)
16
+ */
17
+ type BehaviorCategory = 'ui' | 'data' | 'animation' | 'form' | 'layout';
18
+ /**
19
+ * Loading tiers for lazy loading optimization.
20
+ * - core: Always loaded (essential behaviors)
21
+ * - common: High usage (loaded for typical apps)
22
+ * - optional: Low usage (loaded on demand)
23
+ */
24
+ type BehaviorTier = 'core' | 'common' | 'optional';
25
+ /**
26
+ * Schema for a behavior parameter.
27
+ */
28
+ interface ParameterSchema {
29
+ name: string;
30
+ type: 'string' | 'number' | 'boolean' | 'selector' | 'element';
31
+ optional?: boolean;
32
+ default?: string | number | boolean;
33
+ /** Allowed values for constrained parameters */
34
+ enum?: string[];
35
+ description: string;
36
+ }
37
+ /**
38
+ * Schema for a behavior event.
39
+ */
40
+ interface EventSchema {
41
+ name: string;
42
+ description: string;
43
+ }
44
+ /**
45
+ * Complete schema for a behavior.
46
+ * This is the source of truth for all behavior metadata.
47
+ */
48
+ interface BehaviorSchema {
49
+ /** Behavior name (PascalCase) */
50
+ name: string;
51
+ /** Category for organization */
52
+ category: BehaviorCategory;
53
+ /** Loading tier for lazy loading */
54
+ tier: BehaviorTier;
55
+ /** Semantic version */
56
+ version: string;
57
+ /** Human-readable description */
58
+ description: string;
59
+ /** Parameter definitions */
60
+ parameters: ParameterSchema[];
61
+ /** Event definitions */
62
+ events: EventSchema[];
63
+ /** The hyperscript behavior source code */
64
+ source: string;
65
+ /** Optional requirements or notes */
66
+ requirements?: string[];
67
+ }
68
+ /**
69
+ * Runtime behavior module interface.
70
+ * This is what gets registered with the hyperfixi runtime.
71
+ */
72
+ interface BehaviorModule {
73
+ source: string;
74
+ metadata: BehaviorSchema;
75
+ register: (hyperfixi?: LokaScriptInstance) => Promise<void>;
76
+ }
77
+ /**
78
+ * Minimal LokaScript instance interface for behavior registration.
79
+ */
80
+ interface LokaScriptInstance {
81
+ compileSync: (code: string, options?: {
82
+ traditional?: boolean;
83
+ language?: string;
84
+ }) => {
85
+ ok: boolean;
86
+ ast?: unknown;
87
+ errors?: Array<{
88
+ message: string;
89
+ line?: number;
90
+ column?: number;
91
+ }>;
92
+ };
93
+ execute: (ast: unknown, ctx: unknown) => Promise<unknown>;
94
+ createContext?: () => {
95
+ locals: Map<string, unknown>;
96
+ globals: Map<string, unknown>;
97
+ };
98
+ }
99
+
100
+ export type { BehaviorModule as B, EventSchema as E, LokaScriptInstance as L, ParameterSchema as P, BehaviorSchema as a, BehaviorCategory as b, BehaviorTier as c };
package/package.json ADDED
@@ -0,0 +1,109 @@
1
+ {
2
+ "name": "@hyperfixi/behaviors",
3
+ "version": "2.0.0",
4
+ "description": "Reusable hyperscript behaviors for LokaScript",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.mjs",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
14
+ },
15
+ "./registry": {
16
+ "types": "./dist/registry.d.ts",
17
+ "import": "./dist/registry.js",
18
+ "require": "./dist/registry.cjs"
19
+ },
20
+ "./loaders": {
21
+ "types": "./dist/loaders.d.ts",
22
+ "import": "./dist/loaders.js",
23
+ "require": "./dist/loaders.cjs"
24
+ },
25
+ "./schemas": {
26
+ "types": "./dist/schemas/index.d.ts",
27
+ "import": "./dist/schemas/index.js",
28
+ "require": "./dist/schemas/index.cjs"
29
+ },
30
+ "./draggable": {
31
+ "types": "./dist/behaviors/draggable.d.ts",
32
+ "import": "./dist/behaviors/draggable.js",
33
+ "require": "./dist/behaviors/draggable.cjs"
34
+ },
35
+ "./removable": {
36
+ "types": "./dist/behaviors/removable.d.ts",
37
+ "import": "./dist/behaviors/removable.js",
38
+ "require": "./dist/behaviors/removable.cjs"
39
+ },
40
+ "./toggleable": {
41
+ "types": "./dist/behaviors/toggleable.d.ts",
42
+ "import": "./dist/behaviors/toggleable.js",
43
+ "require": "./dist/behaviors/toggleable.cjs"
44
+ },
45
+ "./sortable": {
46
+ "types": "./dist/behaviors/sortable.d.ts",
47
+ "import": "./dist/behaviors/sortable.js",
48
+ "require": "./dist/behaviors/sortable.cjs"
49
+ },
50
+ "./resizable": {
51
+ "types": "./dist/behaviors/resizable.d.ts",
52
+ "import": "./dist/behaviors/resizable.js",
53
+ "require": "./dist/behaviors/resizable.cjs"
54
+ },
55
+ "./draggable.browser.js": "./dist/draggable.browser.global.js",
56
+ "./removable.browser.js": "./dist/removable.browser.global.js",
57
+ "./toggleable.browser.js": "./dist/toggleable.browser.global.js",
58
+ "./sortable.browser.js": "./dist/sortable.browser.global.js",
59
+ "./resizable.browser.js": "./dist/resizable.browser.global.js",
60
+ "./all.browser.js": "./dist/all.browser.global.js",
61
+ "./core.browser.js": "./dist/core.browser.global.js"
62
+ },
63
+ "files": [
64
+ "dist",
65
+ "src"
66
+ ],
67
+ "scripts": {
68
+ "generate": "tsx scripts/generate.ts",
69
+ "prebuild": "npm run generate",
70
+ "build": "tsup",
71
+ "build:watch": "tsup --watch",
72
+ "typecheck": "tsc --noEmit",
73
+ "test": "vitest run",
74
+ "test:watch": "vitest"
75
+ },
76
+ "peerDependencies": {
77
+ "@hyperfixi/core": "*"
78
+ },
79
+ "devDependencies": {
80
+ "@hyperfixi/core": "*",
81
+ "tsup": "^8.0.0",
82
+ "typescript": "^5.0.0",
83
+ "vitest": "^4.0.0"
84
+ },
85
+ "keywords": [
86
+ "hyperscript",
87
+ "hyperfixi",
88
+ "behaviors",
89
+ "draggable",
90
+ "sortable",
91
+ "resizable",
92
+ "removable",
93
+ "toggleable",
94
+ "ui-components"
95
+ ],
96
+ "license": "MIT",
97
+ "repository": {
98
+ "type": "git",
99
+ "url": "https://github.com/codetalcott/hyperfixi.git",
100
+ "directory": "packages/behaviors"
101
+ },
102
+ "publishConfig": {
103
+ "access": "public"
104
+ },
105
+ "bugs": {
106
+ "url": "https://github.com/codetalcott/hyperfixi/issues"
107
+ },
108
+ "homepage": "https://github.com/codetalcott/hyperfixi/tree/main/packages/behaviors#readme"
109
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Draggable Behavior
3
+ *
4
+ * A reusable behavior that makes elements draggable with pointer events.
5
+ * Supports custom drag handles, lifecycle events, and smooth positioning.
6
+ *
7
+ * @example
8
+ * ```html
9
+ * <!-- Basic usage -->
10
+ * <div _="install Draggable">Drag me!</div>
11
+ *
12
+ * <!-- With custom drag handle -->
13
+ * <div _="install Draggable(dragHandle: .titlebar)">
14
+ * <div class="titlebar">Drag here</div>
15
+ * <div class="content">Content</div>
16
+ * </div>
17
+ * ```
18
+ */
19
+
20
+ import { draggableSchema } from '../schemas/draggable.schema';
21
+ import type { LokaScriptInstance, LokaScriptWindow } from '../schemas/types';
22
+
23
+ // Re-export schema-derived values for backwards compatibility
24
+ export const draggableSource = draggableSchema.source;
25
+ export const draggableMetadata = draggableSchema;
26
+
27
+ /**
28
+ * Register the Draggable behavior with LokaScript.
29
+ */
30
+ export async function registerDraggable(hyperfixi?: LokaScriptInstance): Promise<void> {
31
+ const hf =
32
+ hyperfixi ||
33
+ (typeof window !== 'undefined' ? (window as unknown as LokaScriptWindow).lokascript : null);
34
+
35
+ if (!hf) {
36
+ throw new Error(
37
+ 'LokaScript not found. Make sure @hyperfixi/core is loaded before registering behaviors.'
38
+ );
39
+ }
40
+
41
+ const result = hf.compileSync(draggableSchema.source, { traditional: true });
42
+
43
+ if (!result.ok) {
44
+ throw new Error(`Failed to compile Draggable behavior: ${JSON.stringify(result.errors)}`);
45
+ }
46
+
47
+ const ctx = hf.createContext ? hf.createContext() : { locals: new Map(), globals: new Map() };
48
+ await hf.execute(result.ast, ctx);
49
+ }
50
+
51
+ // Auto-register when loaded as a script tag
52
+ if (typeof window !== 'undefined' && (window as unknown as LokaScriptWindow).lokascript) {
53
+ registerDraggable().catch(console.error);
54
+ }
55
+
56
+ export default {
57
+ source: draggableSchema.source,
58
+ metadata: draggableSchema,
59
+ register: registerDraggable,
60
+ };
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Behaviors Index
3
+ *
4
+ * Re-exports all behavior implementations.
5
+ */
6
+
7
+ export {
8
+ draggableSource,
9
+ draggableMetadata,
10
+ registerDraggable,
11
+ default as Draggable,
12
+ } from './draggable';
13
+
14
+ export {
15
+ sortableSource,
16
+ sortableMetadata,
17
+ registerSortable,
18
+ default as Sortable,
19
+ } from './sortable';
20
+
21
+ export {
22
+ resizableSource,
23
+ resizableMetadata,
24
+ registerResizable,
25
+ default as Resizable,
26
+ } from './resizable';
27
+
28
+ export {
29
+ removableSource,
30
+ removableMetadata,
31
+ registerRemovable,
32
+ default as Removable,
33
+ } from './removable';
34
+
35
+ export {
36
+ toggleableSource,
37
+ toggleableMetadata,
38
+ registerToggleable,
39
+ default as Toggleable,
40
+ } from './toggleable';
@@ -0,0 +1,80 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import type { LokaScriptInstance } from '../schemas/types';
3
+ import { registerDraggable, draggableSource } from './draggable';
4
+ import { registerToggleable, toggleableSource } from './toggleable';
5
+ import { registerRemovable, removableSource } from './removable';
6
+ import { registerSortable, sortableSource } from './sortable';
7
+ import { registerResizable, resizableSource } from './resizable';
8
+
9
+ function createMockInstance(overrides: Partial<LokaScriptInstance> = {}): LokaScriptInstance {
10
+ return {
11
+ compileSync: vi.fn().mockReturnValue({ ok: true, ast: { type: 'behavior' } }),
12
+ execute: vi.fn().mockResolvedValue(undefined),
13
+ createContext: vi.fn().mockReturnValue({ locals: new Map(), globals: new Map() }),
14
+ ...overrides,
15
+ };
16
+ }
17
+
18
+ const behaviors = [
19
+ { name: 'Draggable', register: registerDraggable, source: draggableSource },
20
+ { name: 'Toggleable', register: registerToggleable, source: toggleableSource },
21
+ { name: 'Removable', register: registerRemovable, source: removableSource },
22
+ { name: 'Sortable', register: registerSortable, source: sortableSource },
23
+ { name: 'Resizable', register: registerResizable, source: resizableSource },
24
+ ] as const;
25
+
26
+ describe('behavior registration integration', () => {
27
+ for (const { name, register, source } of behaviors) {
28
+ describe(name, () => {
29
+ it('should compile with traditional parser', async () => {
30
+ const mock = createMockInstance();
31
+ await register(mock);
32
+
33
+ expect(mock.compileSync).toHaveBeenCalledWith(source, { traditional: true });
34
+ });
35
+
36
+ it('should create context and execute', async () => {
37
+ const mock = createMockInstance();
38
+ await register(mock);
39
+
40
+ expect(mock.createContext).toHaveBeenCalled();
41
+ expect(mock.execute).toHaveBeenCalledWith(
42
+ { type: 'behavior' },
43
+ { locals: expect.any(Map), globals: expect.any(Map) }
44
+ );
45
+ });
46
+
47
+ it('should throw on compile failure', async () => {
48
+ const mock = createMockInstance({
49
+ compileSync: vi.fn().mockReturnValue({
50
+ ok: false,
51
+ errors: [{ message: 'syntax error', line: 1 }],
52
+ }),
53
+ });
54
+
55
+ await expect(register(mock)).rejects.toThrowError(new RegExp(`Failed to compile ${name}`));
56
+ });
57
+
58
+ it('should throw when lokascript is not available', async () => {
59
+ await expect(register(undefined)).rejects.toThrowError(/LokaScript not found/);
60
+ });
61
+
62
+ it('should fall back to manual context when createContext is missing', async () => {
63
+ const mock = createMockInstance();
64
+ // Remove createContext
65
+ delete (mock as Partial<LokaScriptInstance>).createContext;
66
+
67
+ await register(mock);
68
+
69
+ // Should still call execute with a fallback context
70
+ expect(mock.execute).toHaveBeenCalledWith(
71
+ { type: 'behavior' },
72
+ expect.objectContaining({
73
+ locals: expect.any(Map),
74
+ globals: expect.any(Map),
75
+ })
76
+ );
77
+ });
78
+ });
79
+ }
80
+ });
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Removable Behavior
3
+ *
4
+ * A behavior that removes an element when a trigger is clicked.
5
+ * Supports optional confirmation and transition effects.
6
+ *
7
+ * @example
8
+ * ```html
9
+ * <div _="install Removable">Click to remove</div>
10
+ *
11
+ * <div _="install Removable(confirm: true)">With confirmation</div>
12
+ * ```
13
+ */
14
+
15
+ import { removableSchema } from '../schemas/removable.schema';
16
+ import type { LokaScriptInstance, LokaScriptWindow } from '../schemas/types';
17
+
18
+ // Re-export schema-derived values for backwards compatibility
19
+ export const removableSource = removableSchema.source;
20
+ export const removableMetadata = removableSchema;
21
+
22
+ /**
23
+ * Register the Removable behavior with LokaScript.
24
+ */
25
+ export async function registerRemovable(hyperfixi?: LokaScriptInstance): Promise<void> {
26
+ const hf =
27
+ hyperfixi ||
28
+ (typeof window !== 'undefined' ? (window as unknown as LokaScriptWindow).lokascript : null);
29
+
30
+ if (!hf) {
31
+ throw new Error(
32
+ 'LokaScript not found. Make sure @hyperfixi/core is loaded before registering behaviors.'
33
+ );
34
+ }
35
+
36
+ const result = hf.compileSync(removableSchema.source, { traditional: true });
37
+
38
+ if (!result.ok) {
39
+ throw new Error(`Failed to compile Removable behavior: ${JSON.stringify(result.errors)}`);
40
+ }
41
+
42
+ const ctx = hf.createContext ? hf.createContext() : { locals: new Map(), globals: new Map() };
43
+ await hf.execute(result.ast, ctx);
44
+ }
45
+
46
+ // Auto-register when loaded as a script tag
47
+ if (typeof window !== 'undefined' && (window as unknown as LokaScriptWindow).lokascript) {
48
+ registerRemovable().catch(console.error);
49
+ }
50
+
51
+ export default {
52
+ source: removableSchema.source,
53
+ metadata: removableSchema,
54
+ register: registerRemovable,
55
+ };
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Resizable Behavior
3
+ *
4
+ * A behavior that makes elements resizable by dragging edges or corners.
5
+ * Supports minimum/maximum dimensions and resize handles.
6
+ *
7
+ * @example
8
+ * ```html
9
+ * <div _="install Resizable" style="width: 200px; height: 150px;">
10
+ * Resize me!
11
+ * </div>
12
+ * ```
13
+ */
14
+
15
+ import { resizableSchema } from '../schemas/resizable.schema';
16
+ import type { LokaScriptInstance, LokaScriptWindow } from '../schemas/types';
17
+
18
+ // Re-export schema-derived values for backwards compatibility
19
+ export const resizableSource = resizableSchema.source;
20
+ export const resizableMetadata = resizableSchema;
21
+
22
+ /**
23
+ * Register the Resizable behavior with LokaScript.
24
+ */
25
+ export async function registerResizable(hyperfixi?: LokaScriptInstance): Promise<void> {
26
+ const hf =
27
+ hyperfixi ||
28
+ (typeof window !== 'undefined' ? (window as unknown as LokaScriptWindow).lokascript : null);
29
+
30
+ if (!hf) {
31
+ throw new Error(
32
+ 'LokaScript not found. Make sure @hyperfixi/core is loaded before registering behaviors.'
33
+ );
34
+ }
35
+
36
+ const result = hf.compileSync(resizableSchema.source, { traditional: true });
37
+
38
+ if (!result.ok) {
39
+ throw new Error(`Failed to compile Resizable behavior: ${JSON.stringify(result.errors)}`);
40
+ }
41
+
42
+ const ctx = hf.createContext ? hf.createContext() : { locals: new Map(), globals: new Map() };
43
+ await hf.execute(result.ast, ctx);
44
+ }
45
+
46
+ // Auto-register when loaded as a script tag
47
+ if (typeof window !== 'undefined' && (window as unknown as LokaScriptWindow).lokascript) {
48
+ registerResizable().catch(console.error);
49
+ }
50
+
51
+ export default {
52
+ source: resizableSchema.source,
53
+ metadata: resizableSchema,
54
+ register: registerResizable,
55
+ };
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Sortable Behavior
3
+ *
4
+ * A behavior for drag-and-drop reordering of list items.
5
+ * Apply to a container element; children become sortable.
6
+ *
7
+ * @example
8
+ * ```html
9
+ * <ul _="install Sortable">
10
+ * <li>Item 1</li>
11
+ * <li>Item 2</li>
12
+ * </ul>
13
+ * ```
14
+ */
15
+
16
+ import { sortableSchema } from '../schemas/sortable.schema';
17
+ import type { LokaScriptInstance, LokaScriptWindow } from '../schemas/types';
18
+
19
+ // Re-export schema-derived values for backwards compatibility
20
+ export const sortableSource = sortableSchema.source;
21
+ export const sortableMetadata = sortableSchema;
22
+
23
+ /**
24
+ * Register the Sortable behavior with LokaScript.
25
+ */
26
+ export async function registerSortable(hyperfixi?: LokaScriptInstance): Promise<void> {
27
+ const hf =
28
+ hyperfixi ||
29
+ (typeof window !== 'undefined' ? (window as unknown as LokaScriptWindow).lokascript : null);
30
+
31
+ if (!hf) {
32
+ throw new Error(
33
+ 'LokaScript not found. Make sure @hyperfixi/core is loaded before registering behaviors.'
34
+ );
35
+ }
36
+
37
+ const result = hf.compileSync(sortableSchema.source, { traditional: true });
38
+
39
+ if (!result.ok) {
40
+ throw new Error(`Failed to compile Sortable behavior: ${JSON.stringify(result.errors)}`);
41
+ }
42
+
43
+ const ctx = hf.createContext ? hf.createContext() : { locals: new Map(), globals: new Map() };
44
+ await hf.execute(result.ast, ctx);
45
+ }
46
+
47
+ // Auto-register when loaded as a script tag
48
+ if (typeof window !== 'undefined' && (window as unknown as LokaScriptWindow).lokascript) {
49
+ registerSortable().catch(console.error);
50
+ }
51
+
52
+ export default {
53
+ source: sortableSchema.source,
54
+ metadata: sortableSchema,
55
+ register: registerSortable,
56
+ };