@hyperfixi/behaviors 3.3.0 → 4.0.1
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/CHANGELOG.md +199 -1
- package/README.md +29 -9
- package/dist/all.browser.global.js +45 -100
- package/dist/all.browser.global.js.map +1 -1
- package/dist/autodismiss.browser.global.js +5 -11
- package/dist/autodismiss.browser.global.js.map +1 -1
- package/dist/behaviors/autodismiss.cjs +19 -22
- package/dist/behaviors/autodismiss.cjs.map +1 -1
- package/dist/behaviors/autodismiss.d.cts +4 -4
- package/dist/behaviors/autodismiss.d.ts +4 -4
- package/dist/behaviors/autodismiss.js +3 -3
- package/dist/behaviors/clickoutside.cjs +19 -18
- package/dist/behaviors/clickoutside.cjs.map +1 -1
- package/dist/behaviors/clickoutside.d.cts +4 -4
- package/dist/behaviors/clickoutside.d.ts +4 -4
- package/dist/behaviors/clickoutside.js +3 -3
- package/dist/behaviors/clipboard.cjs +18 -19
- package/dist/behaviors/clipboard.cjs.map +1 -1
- package/dist/behaviors/clipboard.d.cts +4 -4
- package/dist/behaviors/clipboard.d.ts +4 -4
- package/dist/behaviors/clipboard.js +3 -3
- package/dist/behaviors/draggable.cjs +20 -25
- package/dist/behaviors/draggable.cjs.map +1 -1
- package/dist/behaviors/draggable.d.cts +4 -4
- package/dist/behaviors/draggable.d.ts +4 -4
- package/dist/behaviors/draggable.js +3 -3
- package/dist/behaviors/focustrap.cjs +18 -19
- package/dist/behaviors/focustrap.cjs.map +1 -1
- package/dist/behaviors/focustrap.d.cts +4 -4
- package/dist/behaviors/focustrap.d.ts +4 -4
- package/dist/behaviors/focustrap.js +3 -3
- package/dist/behaviors/removable.cjs +18 -21
- package/dist/behaviors/removable.cjs.map +1 -1
- package/dist/behaviors/removable.d.cts +4 -3
- package/dist/behaviors/removable.d.ts +4 -3
- package/dist/behaviors/removable.js +3 -3
- package/dist/behaviors/resizable.cjs +19 -19
- package/dist/behaviors/resizable.cjs.map +1 -1
- package/dist/behaviors/resizable.d.cts +4 -4
- package/dist/behaviors/resizable.d.ts +4 -4
- package/dist/behaviors/resizable.js +3 -3
- package/dist/behaviors/scrollreveal.cjs +19 -22
- package/dist/behaviors/scrollreveal.cjs.map +1 -1
- package/dist/behaviors/scrollreveal.d.cts +4 -4
- package/dist/behaviors/scrollreveal.d.ts +4 -4
- package/dist/behaviors/scrollreveal.js +3 -3
- package/dist/behaviors/sortable.cjs +19 -20
- package/dist/behaviors/sortable.cjs.map +1 -1
- package/dist/behaviors/sortable.d.cts +4 -4
- package/dist/behaviors/sortable.d.ts +4 -4
- package/dist/behaviors/sortable.js +3 -3
- package/dist/behaviors/tabs.cjs +20 -25
- package/dist/behaviors/tabs.cjs.map +1 -1
- package/dist/behaviors/tabs.d.cts +4 -4
- package/dist/behaviors/tabs.d.ts +4 -4
- package/dist/behaviors/tabs.js +3 -3
- package/dist/behaviors/toggleable.cjs +25 -26
- package/dist/behaviors/toggleable.cjs.map +1 -1
- package/dist/behaviors/toggleable.d.cts +4 -4
- package/dist/behaviors/toggleable.d.ts +4 -4
- package/dist/behaviors/toggleable.js +3 -3
- package/dist/chunk-2GIS4DCY.js +30 -0
- package/dist/chunk-2GIS4DCY.js.map +1 -0
- package/dist/chunk-3BCBZR6R.js +30 -0
- package/dist/chunk-3BCBZR6R.js.map +1 -0
- package/dist/chunk-4YUIDZAO.js +30 -0
- package/dist/chunk-4YUIDZAO.js.map +1 -0
- package/dist/{chunk-XYZ7FOXJ.js → chunk-AQCOK5J5.js} +10 -14
- package/dist/chunk-AQCOK5J5.js.map +1 -0
- package/dist/chunk-ATGHQQC7.js +30 -0
- package/dist/chunk-ATGHQQC7.js.map +1 -0
- package/dist/{chunk-HQDYH45I.js → chunk-CWLAXLWR.js} +5 -13
- package/dist/chunk-CWLAXLWR.js.map +1 -0
- package/dist/chunk-DMWN52SV.js +30 -0
- package/dist/chunk-DMWN52SV.js.map +1 -0
- package/dist/{chunk-PDMOOWFW.js → chunk-EIVPVTUI.js} +4 -8
- package/dist/{chunk-PDMOOWFW.js.map → chunk-EIVPVTUI.js.map} +1 -1
- package/dist/chunk-HHTEMPIT.js +30 -0
- package/dist/chunk-HHTEMPIT.js.map +1 -0
- package/dist/{chunk-26IX7QU7.js → chunk-HJESSMKB.js} +4 -6
- package/dist/{chunk-26IX7QU7.js.map → chunk-HJESSMKB.js.map} +1 -1
- package/dist/{chunk-5S7WN3ZQ.js → chunk-IFAH652L.js} +4 -7
- package/dist/chunk-IFAH652L.js.map +1 -0
- package/dist/chunk-IUGJG4RA.js +30 -0
- package/dist/chunk-IUGJG4RA.js.map +1 -0
- package/dist/{chunk-ZR66E3T6.js → chunk-JNLVXPHR.js} +13 -13
- package/dist/chunk-KEZEGPEX.js +30 -0
- package/dist/chunk-KEZEGPEX.js.map +1 -0
- package/dist/{chunk-66U2RSYJ.js → chunk-KP4GNXYS.js} +4 -10
- package/dist/chunk-KP4GNXYS.js.map +1 -0
- package/dist/chunk-KXQMCN4O.js +30 -0
- package/dist/chunk-KXQMCN4O.js.map +1 -0
- package/dist/{chunk-YXS27XM6.js → chunk-KYBOZ7C4.js} +3 -7
- package/dist/chunk-KYBOZ7C4.js.map +1 -0
- package/dist/chunk-LBWM6TTU.js +30 -0
- package/dist/chunk-LBWM6TTU.js.map +1 -0
- package/dist/{chunk-3DVDS7CT.js → chunk-LCDONZBX.js} +5 -5
- package/dist/chunk-LCDONZBX.js.map +1 -0
- package/dist/{chunk-OJ3YWO3W.js → chunk-NE76IBV2.js} +3 -7
- package/dist/chunk-NE76IBV2.js.map +1 -0
- package/dist/{chunk-HMU342XE.js → chunk-PVO6TZCZ.js} +3 -9
- package/dist/{chunk-HMU342XE.js.map → chunk-PVO6TZCZ.js.map} +1 -1
- package/dist/{chunk-URZGNPTQ.js → chunk-RILYRQ72.js} +4 -10
- package/dist/chunk-RILYRQ72.js.map +1 -0
- package/dist/{chunk-FBQ3X3UY.js → chunk-U4QMFVAM.js} +5 -13
- package/dist/chunk-U4QMFVAM.js.map +1 -0
- package/dist/chunk-VWDTOSE3.js +26 -0
- package/dist/chunk-VWDTOSE3.js.map +1 -0
- package/dist/chunk-YRQBU2OW.js +30 -0
- package/dist/chunk-YRQBU2OW.js.map +1 -0
- package/dist/clickoutside.browser.global.js +5 -7
- package/dist/clickoutside.browser.global.js.map +1 -1
- package/dist/clipboard.browser.global.js +4 -8
- package/dist/clipboard.browser.global.js.map +1 -1
- package/dist/core.browser.global.js +13 -25
- package/dist/core.browser.global.js.map +1 -1
- package/dist/draggable.browser.global.js +5 -13
- package/dist/draggable.browser.global.js.map +1 -1
- package/dist/focustrap.browser.global.js +4 -8
- package/dist/focustrap.browser.global.js.map +1 -1
- package/dist/index.cjs +96 -271
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -10
- package/dist/index.d.ts +10 -10
- package/dist/index.js +42 -55
- package/dist/index.js.map +1 -1
- package/dist/loaders.cjs +75 -237
- package/dist/loaders.cjs.map +1 -1
- package/dist/loaders.js +13 -13
- package/dist/registry.cjs +4 -4
- package/dist/registry.cjs.map +1 -1
- package/dist/registry.d.cts +5 -6
- package/dist/registry.d.ts +5 -6
- package/dist/registry.js +1 -1
- package/dist/removable.browser.global.js +3 -9
- package/dist/removable.browser.global.js.map +1 -1
- package/dist/resizable.browser.global.js +4 -7
- package/dist/resizable.browser.global.js.map +1 -1
- package/dist/resolver.browser.global.js +45 -100
- package/dist/resolver.browser.global.js.map +1 -1
- package/dist/schemas/index.cjs +38 -93
- package/dist/schemas/index.cjs.map +1 -1
- package/dist/schemas/index.d.cts +2 -2
- package/dist/schemas/index.d.ts +2 -2
- package/dist/schemas/index.js +11 -11
- package/dist/schemas/index.js.map +1 -1
- package/dist/scrollreveal.browser.global.js +5 -11
- package/dist/scrollreveal.browser.global.js.map +1 -1
- package/dist/sortable.browser.global.js +5 -9
- package/dist/sortable.browser.global.js.map +1 -1
- package/dist/tabs.browser.global.js +6 -14
- package/dist/tabs.browser.global.js.map +1 -1
- package/dist/toggleable.browser.global.js +9 -13
- package/dist/toggleable.browser.global.js.map +1 -1
- package/dist/{types-DCCtVQS5.d.cts → types-CbA4L8XJ.d.cts} +16 -23
- package/dist/{types-DCCtVQS5.d.ts → types-CbA4L8XJ.d.ts} +16 -23
- package/package.json +5 -5
- package/src/behavior-resolver.ts +24 -56
- package/src/behaviors/autodismiss.test.ts +12 -20
- package/src/behaviors/autodismiss.ts +8 -23
- package/src/behaviors/clickoutside.test.ts +13 -21
- package/src/behaviors/clickoutside.ts +8 -23
- package/src/behaviors/clipboard.test.ts +12 -34
- package/src/behaviors/clipboard.ts +8 -23
- package/src/behaviors/curated-runtime.test.ts +22 -24
- package/src/behaviors/draggable.ts +10 -24
- package/src/behaviors/experimental-runtime.test.ts +19 -18
- package/src/behaviors/focustrap.test.ts +12 -20
- package/src/behaviors/focustrap.ts +8 -23
- package/src/behaviors/integration.test.ts +19 -54
- package/src/behaviors/optional-runtime.test.ts +17 -22
- package/src/behaviors/removable.ts +6 -20
- package/src/behaviors/resizable.ts +9 -24
- package/src/behaviors/scrollreveal.test.ts +13 -21
- package/src/behaviors/scrollreveal.ts +8 -23
- package/src/behaviors/sortable.ts +7 -22
- package/src/behaviors/tabs.test.ts +12 -34
- package/src/behaviors/tabs.ts +8 -23
- package/src/behaviors/toggleable.ts +10 -26
- package/src/browser-resolver-bundle.ts +20 -30
- package/src/core-bundle.ts +11 -11
- package/src/index.test.ts +2 -2
- package/src/index.ts +30 -47
- package/src/registry.test.ts +9 -34
- package/src/registry.ts +7 -11
- package/src/schemas/autodismiss.schema.ts +3 -9
- package/src/schemas/clickoutside.schema.ts +3 -5
- package/src/schemas/clipboard.schema.ts +2 -6
- package/src/schemas/draggable.schema.ts +4 -12
- package/src/schemas/focustrap.schema.ts +2 -6
- package/src/schemas/index.ts +2 -1
- package/src/schemas/removable.schema.ts +2 -8
- package/src/schemas/resizable.schema.ts +3 -6
- package/src/schemas/scrollreveal.schema.ts +3 -9
- package/src/schemas/sortable.schema.ts +3 -7
- package/src/schemas/tabs.schema.ts +4 -12
- package/src/schemas/toggleable.schema.ts +10 -13
- package/src/schemas/types.ts +37 -30
- package/dist/chunk-2HUF6RMI.js +0 -40
- package/dist/chunk-2HUF6RMI.js.map +0 -1
- package/dist/chunk-3DVDS7CT.js.map +0 -1
- package/dist/chunk-5S7WN3ZQ.js.map +0 -1
- package/dist/chunk-66U2RSYJ.js.map +0 -1
- package/dist/chunk-6TJXDCAQ.js +0 -11
- package/dist/chunk-6TJXDCAQ.js.map +0 -1
- package/dist/chunk-7TPDLB7W.js +0 -40
- package/dist/chunk-7TPDLB7W.js.map +0 -1
- package/dist/chunk-CR3J7VV6.js +0 -40
- package/dist/chunk-CR3J7VV6.js.map +0 -1
- package/dist/chunk-EDBG2F57.js +0 -40
- package/dist/chunk-EDBG2F57.js.map +0 -1
- package/dist/chunk-FBQ3X3UY.js.map +0 -1
- package/dist/chunk-HQDYH45I.js.map +0 -1
- package/dist/chunk-HX663BJ4.js +0 -40
- package/dist/chunk-HX663BJ4.js.map +0 -1
- package/dist/chunk-KROW43CG.js +0 -40
- package/dist/chunk-KROW43CG.js.map +0 -1
- package/dist/chunk-L52AGCMP.js +0 -40
- package/dist/chunk-L52AGCMP.js.map +0 -1
- package/dist/chunk-MTI5PSRH.js +0 -40
- package/dist/chunk-MTI5PSRH.js.map +0 -1
- package/dist/chunk-OJ3YWO3W.js.map +0 -1
- package/dist/chunk-ORBJ7MRW.js +0 -40
- package/dist/chunk-ORBJ7MRW.js.map +0 -1
- package/dist/chunk-SLSCZV4A.js +0 -40
- package/dist/chunk-SLSCZV4A.js.map +0 -1
- package/dist/chunk-URZGNPTQ.js.map +0 -1
- package/dist/chunk-WKBRZGGL.js +0 -40
- package/dist/chunk-WKBRZGGL.js.map +0 -1
- package/dist/chunk-XYZ7FOXJ.js.map +0 -1
- package/dist/chunk-YXS27XM6.js.map +0 -1
- /package/dist/{chunk-ZR66E3T6.js.map → chunk-JNLVXPHR.js.map} +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Resizable Behavior
|
|
3
3
|
*
|
|
4
|
-
* Makes elements resizable by dragging.
|
|
5
|
-
* (single source of truth) — no imperative installer. The source
|
|
6
|
-
*
|
|
4
|
+
* Makes elements resizable by dragging. Defined from its hyperscript `source`
|
|
5
|
+
* (single source of truth) — no imperative installer. The source reads the start
|
|
6
|
+
* size from `my offsetWidth` / `my offsetHeight`, runs a `repeat until event pointerup` loop, clamps to
|
|
7
7
|
* min/max dimensions, and writes `*width` / `*height` inline styles.
|
|
8
8
|
*
|
|
9
9
|
* @example
|
|
@@ -15,34 +15,19 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import { resizableSchema } from '../schemas/resizable.schema';
|
|
18
|
-
import
|
|
19
|
-
import {
|
|
18
|
+
import { defineBehavior, resolveRuntime } from '../schemas/types';
|
|
19
|
+
import type { HyperscriptHost } from '../schemas/types';
|
|
20
20
|
|
|
21
21
|
// Re-export schema-derived values for backwards compatibility
|
|
22
22
|
export const resizableSource = resizableSchema.source;
|
|
23
23
|
export const resizableMetadata = resizableSchema;
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
|
-
*
|
|
27
|
-
* source
|
|
26
|
+
* Define the Resizable behavior on a hyperscript host (`window.hyperfixi` when none is given)
|
|
27
|
+
* from its source, as a `<script type="text/hyperscript">` would.
|
|
28
28
|
*/
|
|
29
|
-
export async function registerResizable(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
if (!hf) {
|
|
33
|
-
throw new Error(
|
|
34
|
-
'LokaScript not found. Make sure @hyperfixi/core is loaded before registering behaviors.'
|
|
35
|
-
);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const result = hf.compileSync(resizableSchema.source, { traditional: true });
|
|
39
|
-
|
|
40
|
-
if (!result.ok) {
|
|
41
|
-
throw new Error(`Failed to compile Resizable behavior: ${JSON.stringify(result.errors)}`);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const ctx = hf.createContext ? hf.createContext() : { locals: new Map(), globals: new Map() };
|
|
45
|
-
await hf.execute(result.ast, ctx);
|
|
29
|
+
export async function registerResizable(host?: HyperscriptHost): Promise<void> {
|
|
30
|
+
defineBehavior(resizableSchema, host);
|
|
46
31
|
}
|
|
47
32
|
|
|
48
33
|
// Auto-register when loaded as a script tag
|
|
@@ -2,38 +2,30 @@ import { describe, it, expect, vi } from 'vitest';
|
|
|
2
2
|
|
|
3
3
|
describe('ScrollReveal behavior', () => {
|
|
4
4
|
describe('registerScrollReveal', () => {
|
|
5
|
-
it('
|
|
5
|
+
it('defines the behavior on the host from its hyperscript source', async () => {
|
|
6
6
|
const { registerScrollReveal, scrollRevealSource } = await import('./scrollreveal');
|
|
7
|
-
const
|
|
8
|
-
compileSync: vi.fn().mockReturnValue({ ok: true, ast: { type: 'behavior' } }),
|
|
9
|
-
execute: vi.fn().mockResolvedValue(undefined),
|
|
10
|
-
createContext: vi.fn().mockReturnValue({ locals: new Map(), globals: new Map() }),
|
|
11
|
-
};
|
|
7
|
+
const host = { evaluate: vi.fn() };
|
|
12
8
|
|
|
13
|
-
await registerScrollReveal(
|
|
9
|
+
await registerScrollReveal(host);
|
|
14
10
|
|
|
15
|
-
expect(
|
|
16
|
-
expect(mock.execute).toHaveBeenCalledWith(
|
|
17
|
-
{ type: 'behavior' },
|
|
18
|
-
expect.objectContaining({ locals: expect.any(Map), globals: expect.any(Map) })
|
|
19
|
-
);
|
|
11
|
+
expect(host.evaluate).toHaveBeenCalledWith(scrollRevealSource);
|
|
20
12
|
});
|
|
21
13
|
|
|
22
|
-
it('should throw
|
|
14
|
+
it('should throw when the host rejects the source', async () => {
|
|
23
15
|
const { registerScrollReveal } = await import('./scrollreveal');
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
16
|
+
const host = {
|
|
17
|
+
evaluate: vi.fn(() => {
|
|
18
|
+
throw new Error('boom');
|
|
19
|
+
}),
|
|
28
20
|
};
|
|
29
|
-
await expect(registerScrollReveal(
|
|
30
|
-
/Failed to
|
|
21
|
+
await expect(registerScrollReveal(host)).rejects.toThrowError(
|
|
22
|
+
/Failed to define ScrollReveal/
|
|
31
23
|
);
|
|
32
24
|
});
|
|
33
25
|
|
|
34
|
-
it('should throw when no
|
|
26
|
+
it('should throw when no host is available', async () => {
|
|
35
27
|
const { registerScrollReveal } = await import('./scrollreveal');
|
|
36
|
-
await expect(registerScrollReveal(undefined)).rejects.toThrowError(/
|
|
28
|
+
await expect(registerScrollReveal(undefined)).rejects.toThrowError(/No hyperscript host/);
|
|
37
29
|
});
|
|
38
30
|
});
|
|
39
31
|
|
|
@@ -5,41 +5,26 @@
|
|
|
5
5
|
* Uses the IntersectionObserver web standard API (in its hyperscript `source`'s
|
|
6
6
|
* `init`-block `js()` body).
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
* the
|
|
8
|
+
* Defined from its hyperscript `source` — the single source of truth shared with
|
|
9
|
+
* the browser bundle and patterns-reference. This collapses ScrollReveal onto
|
|
10
10
|
* the one runtime path (no more imperative-installer fork between CDN and npm);
|
|
11
11
|
* see docs-internal/BEHAVIORS_CONSOLIDATION_PLAN.md §3d.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import { scrollRevealSchema } from '../schemas/scrollreveal.schema';
|
|
15
|
-
import
|
|
16
|
-
import {
|
|
15
|
+
import { defineBehavior, resolveRuntime } from '../schemas/types';
|
|
16
|
+
import type { HyperscriptHost } from '../schemas/types';
|
|
17
17
|
|
|
18
18
|
// Re-export schema-derived values
|
|
19
19
|
export const scrollRevealSource = scrollRevealSchema.source;
|
|
20
20
|
export const scrollRevealMetadata = scrollRevealSchema;
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
|
-
*
|
|
24
|
-
*
|
|
23
|
+
* Define the ScrollReveal behavior on a hyperscript host (`window.hyperfixi` when none is given)
|
|
24
|
+
* from its source, as a `<script type="text/hyperscript">` would.
|
|
25
25
|
*/
|
|
26
|
-
export async function registerScrollReveal(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if (!hf) {
|
|
30
|
-
throw new Error(
|
|
31
|
-
'LokaScript not found. Make sure @hyperfixi/core is loaded before registering behaviors.'
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const result = hf.compileSync(scrollRevealSchema.source, { traditional: true });
|
|
36
|
-
|
|
37
|
-
if (!result.ok) {
|
|
38
|
-
throw new Error(`Failed to compile ScrollReveal behavior: ${JSON.stringify(result.errors)}`);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const ctx = hf.createContext ? hf.createContext() : { locals: new Map(), globals: new Map() };
|
|
42
|
-
await hf.execute(result.ast, ctx);
|
|
26
|
+
export async function registerScrollReveal(host?: HyperscriptHost): Promise<void> {
|
|
27
|
+
defineBehavior(scrollRevealSchema, host);
|
|
43
28
|
}
|
|
44
29
|
|
|
45
30
|
// Auto-register when loaded as a script tag
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Sortable Behavior
|
|
3
3
|
*
|
|
4
4
|
* Drag-and-drop reordering of list items. Apply to a container element; its
|
|
5
|
-
* `<li>` children become sortable.
|
|
5
|
+
* `<li>` children become sortable. Defined from its hyperscript `source` (single
|
|
6
6
|
* source of truth) — no imperative installer.
|
|
7
7
|
*
|
|
8
8
|
* Note: This behavior fires lifecycle events but does NOT automatically reorder
|
|
@@ -18,34 +18,19 @@
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
import { sortableSchema } from '../schemas/sortable.schema';
|
|
21
|
-
import
|
|
22
|
-
import {
|
|
21
|
+
import { defineBehavior, resolveRuntime } from '../schemas/types';
|
|
22
|
+
import type { HyperscriptHost } from '../schemas/types';
|
|
23
23
|
|
|
24
24
|
// Re-export schema-derived values for backwards compatibility
|
|
25
25
|
export const sortableSource = sortableSchema.source;
|
|
26
26
|
export const sortableMetadata = sortableSchema;
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
|
-
*
|
|
30
|
-
* source
|
|
29
|
+
* Define the Sortable behavior on a hyperscript host (`window.hyperfixi` when none is given)
|
|
30
|
+
* from its source, as a `<script type="text/hyperscript">` would.
|
|
31
31
|
*/
|
|
32
|
-
export async function registerSortable(
|
|
33
|
-
|
|
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(sortableSchema.source, { traditional: true });
|
|
42
|
-
|
|
43
|
-
if (!result.ok) {
|
|
44
|
-
throw new Error(`Failed to compile Sortable 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);
|
|
32
|
+
export async function registerSortable(host?: HyperscriptHost): Promise<void> {
|
|
33
|
+
defineBehavior(sortableSchema, host);
|
|
49
34
|
}
|
|
50
35
|
|
|
51
36
|
// Auto-register when loaded as a script tag
|
|
@@ -2,50 +2,28 @@ import { describe, it, expect, vi } from 'vitest';
|
|
|
2
2
|
|
|
3
3
|
describe('Tabs behavior', () => {
|
|
4
4
|
describe('registerTabs', () => {
|
|
5
|
-
it('
|
|
5
|
+
it('defines the behavior on the host from its hyperscript source', async () => {
|
|
6
6
|
const { registerTabs, tabsSource } = await import('./tabs');
|
|
7
|
-
const
|
|
8
|
-
compileSync: vi.fn().mockReturnValue({ ok: true, ast: { type: 'behavior' } }),
|
|
9
|
-
execute: vi.fn().mockResolvedValue(undefined),
|
|
10
|
-
createContext: vi.fn().mockReturnValue({ locals: new Map(), globals: new Map() }),
|
|
11
|
-
};
|
|
7
|
+
const host = { evaluate: vi.fn() };
|
|
12
8
|
|
|
13
|
-
await registerTabs(
|
|
9
|
+
await registerTabs(host);
|
|
14
10
|
|
|
15
|
-
expect(
|
|
16
|
-
expect(mock.execute).toHaveBeenCalledWith(
|
|
17
|
-
{ type: 'behavior' },
|
|
18
|
-
expect.objectContaining({ locals: expect.any(Map), globals: expect.any(Map) })
|
|
19
|
-
);
|
|
11
|
+
expect(host.evaluate).toHaveBeenCalledWith(tabsSource);
|
|
20
12
|
});
|
|
21
13
|
|
|
22
|
-
it('should throw
|
|
14
|
+
it('should throw when the host rejects the source', async () => {
|
|
23
15
|
const { registerTabs } = await import('./tabs');
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
16
|
+
const host = {
|
|
17
|
+
evaluate: vi.fn(() => {
|
|
18
|
+
throw new Error('boom');
|
|
19
|
+
}),
|
|
28
20
|
};
|
|
29
|
-
await expect(registerTabs(
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it('should throw when no runtime available', async () => {
|
|
33
|
-
const { registerTabs } = await import('./tabs');
|
|
34
|
-
await expect(registerTabs(undefined)).rejects.toThrowError(/LokaScript not found/);
|
|
21
|
+
await expect(registerTabs(host)).rejects.toThrowError(/Failed to define Tabs/);
|
|
35
22
|
});
|
|
36
23
|
|
|
37
|
-
it('should
|
|
24
|
+
it('should throw when no host is available', async () => {
|
|
38
25
|
const { registerTabs } = await import('./tabs');
|
|
39
|
-
|
|
40
|
-
compileSync: vi.fn().mockReturnValue({ ok: true, ast: { type: 'behavior' } }),
|
|
41
|
-
execute: vi.fn().mockResolvedValue(undefined),
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
await registerTabs(mock as any);
|
|
45
|
-
expect(mock.execute).toHaveBeenCalledWith(
|
|
46
|
-
expect.anything(),
|
|
47
|
-
expect.objectContaining({ locals: expect.any(Map), globals: expect.any(Map) })
|
|
48
|
-
);
|
|
26
|
+
await expect(registerTabs(undefined)).rejects.toThrowError(/No hyperscript host/);
|
|
49
27
|
});
|
|
50
28
|
});
|
|
51
29
|
|
package/src/behaviors/tabs.ts
CHANGED
|
@@ -6,40 +6,25 @@
|
|
|
6
6
|
* wiring / keyboard-navigation logic lives in the schema's hyperscript `source`
|
|
7
7
|
* (an `init`-block `js()` body).
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
* the
|
|
9
|
+
* Defined from its hyperscript `source` — the single source of truth shared with
|
|
10
|
+
* the browser bundle and patterns-reference. This collapses Tabs onto the one
|
|
11
11
|
* runtime path (no more imperative-installer fork between CDN and npm);
|
|
12
12
|
* see docs-internal/BEHAVIORS_CONSOLIDATION_PLAN.md §3d.
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
import { tabsSchema } from '../schemas/tabs.schema';
|
|
16
|
-
import
|
|
17
|
-
import {
|
|
16
|
+
import { defineBehavior, resolveRuntime } from '../schemas/types';
|
|
17
|
+
import type { HyperscriptHost } from '../schemas/types';
|
|
18
18
|
|
|
19
19
|
export const tabsSource = tabsSchema.source;
|
|
20
20
|
export const tabsMetadata = tabsSchema;
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
|
-
*
|
|
24
|
-
*
|
|
23
|
+
* Define the Tabs behavior on a hyperscript host (`window.hyperfixi` when none is given)
|
|
24
|
+
* from its source, as a `<script type="text/hyperscript">` would.
|
|
25
25
|
*/
|
|
26
|
-
export async function registerTabs(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if (!hf) {
|
|
30
|
-
throw new Error(
|
|
31
|
-
'LokaScript not found. Make sure @hyperfixi/core is loaded before registering behaviors.'
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const result = hf.compileSync(tabsSchema.source, { traditional: true });
|
|
36
|
-
|
|
37
|
-
if (!result.ok) {
|
|
38
|
-
throw new Error(`Failed to compile Tabs behavior: ${JSON.stringify(result.errors)}`);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const ctx = hf.createContext ? hf.createContext() : { locals: new Map(), globals: new Map() };
|
|
42
|
-
await hf.execute(result.ast, ctx);
|
|
26
|
+
export async function registerTabs(host?: HyperscriptHost): Promise<void> {
|
|
27
|
+
defineBehavior(tabsSchema, host);
|
|
43
28
|
}
|
|
44
29
|
|
|
45
30
|
// Auto-register when loaded as a script tag
|
|
@@ -4,48 +4,32 @@
|
|
|
4
4
|
* A behavior that toggles a CSS class on click.
|
|
5
5
|
* Useful for accordions, dropdowns, and toggle buttons.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
* the
|
|
9
|
-
* selector resolves the behavior's `cls` parameter at runtime
|
|
10
|
-
* `packages/core/src/commands/behaviors/__tests__/template-interpolation.test.ts`.
|
|
7
|
+
* Defined from its hyperscript `source` (the single source of truth shared with
|
|
8
|
+
* the browser bundle and patterns-reference). The `.{cls}` dynamic class
|
|
9
|
+
* selector resolves the behavior's `cls` parameter at runtime.
|
|
11
10
|
*
|
|
12
11
|
* @example
|
|
13
12
|
* ```html
|
|
14
13
|
* <button _="install Toggleable">Toggle</button>
|
|
15
14
|
*
|
|
16
|
-
* <button _="install Toggleable(cls: expanded,
|
|
15
|
+
* <button _="install Toggleable(cls: 'expanded', targetEl: #menu)">Menu</button>
|
|
17
16
|
* ```
|
|
18
17
|
*/
|
|
19
18
|
|
|
20
19
|
import { toggleableSchema } from '../schemas/toggleable.schema';
|
|
21
|
-
import
|
|
22
|
-
import {
|
|
20
|
+
import { defineBehavior, resolveRuntime } from '../schemas/types';
|
|
21
|
+
import type { HyperscriptHost } from '../schemas/types';
|
|
23
22
|
|
|
24
23
|
// Re-export schema-derived values for backwards compatibility
|
|
25
24
|
export const toggleableSource = toggleableSchema.source;
|
|
26
25
|
export const toggleableMetadata = toggleableSchema;
|
|
27
26
|
|
|
28
27
|
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
28
|
+
* Define the Toggleable behavior on a hyperscript host (`window.hyperfixi` when none is given)
|
|
29
|
+
* from its source, as a `<script type="text/hyperscript">` would.
|
|
31
30
|
*/
|
|
32
|
-
export async function registerToggleable(
|
|
33
|
-
|
|
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(toggleableSchema.source, { traditional: true });
|
|
42
|
-
|
|
43
|
-
if (!result.ok) {
|
|
44
|
-
throw new Error(`Failed to compile Toggleable 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);
|
|
31
|
+
export async function registerToggleable(host?: HyperscriptHost): Promise<void> {
|
|
32
|
+
defineBehavior(toggleableSchema, host);
|
|
49
33
|
}
|
|
50
34
|
|
|
51
35
|
// Auto-register when loaded as a script tag
|
|
@@ -1,40 +1,30 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* The behaviors browser bundle: `resolver.browser.global.js`.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Defines every standard behavior on the hyperscript host, so `install Toggleable`,
|
|
5
|
+
* `install Draggable`, … just work. Include it after the host's script:
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
* <script src="
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* <script src="hyperfixi-hs.js"></script>
|
|
8
|
+
* <script src="resolver.browser.global.js"></script>
|
|
9
|
+
*
|
|
10
|
+
* The host is `@hyperfixi/engine` (`window.hyperfixi`, also `window._hyperscript`) or
|
|
11
|
+
* upstream `_hyperscript` itself: each source is defined with `evaluate`, as a page's
|
|
12
|
+
* `<script type="text/hyperscript">` would be. Loaded before the document is ready, this runs
|
|
13
|
+
* before the host reads the page, so every `install` finds its behavior; loaded later, the
|
|
14
|
+
* document is processed again so the installs can succeed now.
|
|
11
15
|
*/
|
|
12
16
|
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
function init() {
|
|
16
|
-
const hf = (window as any).hyperfixi;
|
|
17
|
-
if (!hf?.compileSync || !hf?.execute) return;
|
|
18
|
-
|
|
19
|
-
// Compile and register each behavior definition with the runtime.
|
|
20
|
-
// This is equivalent to having them in a <script type="text/hyperscript"> block.
|
|
21
|
-
for (const source of Object.values(BEHAVIOR_SOURCES)) {
|
|
22
|
-
const result = hf.compileSync(source, { traditional: true });
|
|
23
|
-
if (result?.ok && result.ast) {
|
|
24
|
-
// execute() registers the behavior in the runtime's behaviorRegistry
|
|
25
|
-
hf.execute(result.ast).catch(() => {
|
|
26
|
-
// Async — errors handled silently
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
}
|
|
17
|
+
import { defineBehaviors } from './behavior-resolver';
|
|
18
|
+
import { resolveRuntime } from './schemas/types';
|
|
30
19
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
ap.init();
|
|
20
|
+
function init(): void {
|
|
21
|
+
const host = resolveRuntime();
|
|
22
|
+
if (!host) {
|
|
23
|
+
console.error('[behaviors] no hyperscript host: load hyperfixi-hs.js before this bundle');
|
|
24
|
+
return;
|
|
37
25
|
}
|
|
26
|
+
defineBehaviors(host);
|
|
27
|
+
if (document.readyState !== 'loading') host.processNode?.(document.body);
|
|
38
28
|
}
|
|
39
29
|
|
|
40
30
|
if (typeof window !== 'undefined') {
|
package/src/core-bundle.ts
CHANGED
|
@@ -11,25 +11,25 @@ export { registerToggleable, toggleableSource, toggleableMetadata } from './beha
|
|
|
11
11
|
|
|
12
12
|
import { registerDraggable } from './behaviors/draggable';
|
|
13
13
|
import { registerToggleable } from './behaviors/toggleable';
|
|
14
|
-
import type {
|
|
14
|
+
import type { HyperscriptHost } from './schemas/types';
|
|
15
|
+
import { resolveRuntime } from './schemas/types';
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
|
-
*
|
|
18
|
+
* Define the core tier behaviors on a hyperscript host.
|
|
18
19
|
*/
|
|
19
|
-
export async function registerCore(
|
|
20
|
-
await Promise.all([registerDraggable(
|
|
20
|
+
export async function registerCore(host?: HyperscriptHost): Promise<void> {
|
|
21
|
+
await Promise.all([registerDraggable(host), registerToggleable(host)]);
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
25
|
+
* Resolves when the core behaviors are defined, when the package was loaded as a script tag
|
|
26
|
+
* after the host; `null` otherwise.
|
|
26
27
|
*/
|
|
27
28
|
export let ready: Promise<void> | null = null;
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
if (
|
|
31
|
-
ready = registerCore()
|
|
32
|
-
|
|
33
|
-
console.error('[behaviors] Core auto-registration failed:', err);
|
|
30
|
+
const _host = resolveRuntime();
|
|
31
|
+
if (_host) {
|
|
32
|
+
ready = registerCore(_host).catch(err => {
|
|
33
|
+
console.error('[behaviors] Core auto-definition failed:', err);
|
|
34
34
|
});
|
|
35
35
|
}
|
package/src/index.test.ts
CHANGED
|
@@ -195,7 +195,7 @@ describe('@hyperfixi/behaviors', () => {
|
|
|
195
195
|
|
|
196
196
|
it('should use triggerEl parameter (not trigger)', () => {
|
|
197
197
|
expect(removableSource).toContain('behavior Removable(triggerEl');
|
|
198
|
-
expect(removableSource).toContain('on click from triggerEl');
|
|
198
|
+
expect(removableSource).toContain('on click from (triggerEl or me)');
|
|
199
199
|
});
|
|
200
200
|
});
|
|
201
201
|
|
|
@@ -211,7 +211,7 @@ describe('@hyperfixi/behaviors', () => {
|
|
|
211
211
|
});
|
|
212
212
|
|
|
213
213
|
it('should default to "active" class', () => {
|
|
214
|
-
expect(toggleableSource).toContain(
|
|
214
|
+
expect(toggleableSource).toContain(`set element's cls to "active"`);
|
|
215
215
|
});
|
|
216
216
|
});
|
|
217
217
|
|
package/src/index.ts
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
*
|
|
27
27
|
* @example CDN usage
|
|
28
28
|
* ```html
|
|
29
|
-
* <script src="
|
|
29
|
+
* <script src="hyperfixi-hs.js"></script>
|
|
30
30
|
* <script src="@hyperfixi/behaviors/draggable.browser.js"></script>
|
|
31
31
|
* <!-- Draggable is auto-registered -->
|
|
32
32
|
* ```
|
|
@@ -119,7 +119,8 @@ export type {
|
|
|
119
119
|
ParameterSchema,
|
|
120
120
|
EventSchema,
|
|
121
121
|
BehaviorModule,
|
|
122
|
-
|
|
122
|
+
HyperscriptHost,
|
|
123
|
+
HyperscriptWindow,
|
|
123
124
|
} from './schemas/types';
|
|
124
125
|
|
|
125
126
|
// =============================================================================
|
|
@@ -214,15 +215,14 @@ import { registerClickOutside } from './behaviors/clickoutside';
|
|
|
214
215
|
import { registerFocusTrap } from './behaviors/focustrap';
|
|
215
216
|
import { registerScrollReveal } from './behaviors/scrollreveal';
|
|
216
217
|
import { registerTabs } from './behaviors/tabs';
|
|
217
|
-
import type {
|
|
218
|
+
import type { HyperscriptHost } from './schemas/types';
|
|
218
219
|
import { resolveRuntime } from './schemas/types';
|
|
219
|
-
import type { LokaScriptWindow } from './schemas/types';
|
|
220
220
|
|
|
221
221
|
/**
|
|
222
|
-
*
|
|
222
|
+
* Define every behavior on a hyperscript host.
|
|
223
223
|
*
|
|
224
|
-
* @param
|
|
225
|
-
*
|
|
224
|
+
* @param host - The host (`@hyperfixi/engine`'s `window.hyperfixi`, or upstream's
|
|
225
|
+
* `window._hyperscript`); defaults to the one on `window`
|
|
226
226
|
*
|
|
227
227
|
* @example
|
|
228
228
|
* ```javascript
|
|
@@ -230,59 +230,42 @@ import type { LokaScriptWindow } from './schemas/types';
|
|
|
230
230
|
* await registerAll();
|
|
231
231
|
* ```
|
|
232
232
|
*/
|
|
233
|
-
export async function registerAll(
|
|
233
|
+
export async function registerAll(host?: HyperscriptHost): Promise<void> {
|
|
234
234
|
await Promise.all([
|
|
235
|
-
registerDraggable(
|
|
236
|
-
registerRemovable(
|
|
237
|
-
registerToggleable(
|
|
238
|
-
registerSortable(
|
|
239
|
-
registerResizable(
|
|
240
|
-
registerClipboard(
|
|
241
|
-
registerAutoDismiss(
|
|
242
|
-
registerClickOutside(
|
|
243
|
-
registerFocusTrap(
|
|
244
|
-
registerScrollReveal(
|
|
245
|
-
registerTabs(
|
|
235
|
+
registerDraggable(host),
|
|
236
|
+
registerRemovable(host),
|
|
237
|
+
registerToggleable(host),
|
|
238
|
+
registerSortable(host),
|
|
239
|
+
registerResizable(host),
|
|
240
|
+
registerClipboard(host),
|
|
241
|
+
registerAutoDismiss(host),
|
|
242
|
+
registerClickOutside(host),
|
|
243
|
+
registerFocusTrap(host),
|
|
244
|
+
registerScrollReveal(host),
|
|
245
|
+
registerTabs(host),
|
|
246
246
|
]);
|
|
247
247
|
}
|
|
248
248
|
|
|
249
249
|
// =============================================================================
|
|
250
|
-
// Auto-
|
|
250
|
+
// Auto-definition for the browser bundles
|
|
251
251
|
// =============================================================================
|
|
252
252
|
|
|
253
253
|
/**
|
|
254
|
-
*
|
|
255
|
-
*
|
|
254
|
+
* Resolves when every behavior is defined, when the package was loaded as a script tag after
|
|
255
|
+
* the host; `null` otherwise.
|
|
256
256
|
*/
|
|
257
257
|
export let ready: Promise<void> | null = null;
|
|
258
258
|
|
|
259
|
-
//
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
lsWin.__hyperfixi_behaviors_ready = ready;
|
|
266
|
-
|
|
267
|
-
ready
|
|
259
|
+
// Loaded as a script tag after the host, before the document is ready, this runs before the
|
|
260
|
+
// host reads the page, so every `install` finds its behavior. Loaded later, the elements the
|
|
261
|
+
// host has already seen are processed again, so their installs can succeed now.
|
|
262
|
+
const _host = resolveRuntime();
|
|
263
|
+
if (_host) {
|
|
264
|
+
ready = registerAll(_host)
|
|
268
265
|
.then(() => {
|
|
269
|
-
|
|
270
|
-
attributeProcessor?: { scanAndProcessAll: () => Promise<void> };
|
|
271
|
-
processNode?: (node: Document) => void;
|
|
272
|
-
};
|
|
273
|
-
const savedPromise = lsWin.__hyperfixi_behaviors_ready;
|
|
274
|
-
delete lsWin.__hyperfixi_behaviors_ready;
|
|
275
|
-
|
|
276
|
-
if (hf.attributeProcessor?.scanAndProcessAll) {
|
|
277
|
-
hf.attributeProcessor.scanAndProcessAll().finally(() => {
|
|
278
|
-
lsWin.__hyperfixi_behaviors_ready = savedPromise;
|
|
279
|
-
});
|
|
280
|
-
} else if (hf.processNode) {
|
|
281
|
-
hf.processNode(document);
|
|
282
|
-
lsWin.__hyperfixi_behaviors_ready = savedPromise;
|
|
283
|
-
}
|
|
266
|
+
if (document.readyState !== 'loading') _host.processNode?.(document.body);
|
|
284
267
|
})
|
|
285
268
|
.catch(err => {
|
|
286
|
-
console.error('[behaviors] Auto-
|
|
269
|
+
console.error('[behaviors] Auto-definition failed:', err);
|
|
287
270
|
});
|
|
288
271
|
}
|