@hyperfixi/behaviors 2.5.1 → 2.7.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/README.md +100 -0
- package/dist/all.browser.global.js +43 -40
- package/dist/all.browser.global.js.map +1 -1
- package/dist/autodismiss.browser.global.js +2 -2
- package/dist/autodismiss.browser.global.js.map +1 -1
- package/dist/behaviors/autodismiss.cjs +5 -54
- package/dist/behaviors/autodismiss.cjs.map +1 -1
- package/dist/behaviors/autodismiss.d.cts +3 -2
- package/dist/behaviors/autodismiss.d.ts +3 -2
- package/dist/behaviors/autodismiss.js +1 -1
- package/dist/behaviors/clickoutside.cjs +6 -28
- package/dist/behaviors/clickoutside.cjs.map +1 -1
- package/dist/behaviors/clickoutside.d.cts +3 -2
- package/dist/behaviors/clickoutside.d.ts +3 -2
- package/dist/behaviors/clickoutside.js +2 -2
- package/dist/behaviors/clipboard.cjs +30 -86
- package/dist/behaviors/clipboard.cjs.map +1 -1
- package/dist/behaviors/clipboard.d.cts +3 -2
- package/dist/behaviors/clipboard.d.ts +3 -2
- package/dist/behaviors/clipboard.js +2 -2
- package/dist/behaviors/draggable.cjs +6 -41
- package/dist/behaviors/draggable.cjs.map +1 -1
- package/dist/behaviors/draggable.d.cts +3 -3
- package/dist/behaviors/draggable.d.ts +3 -3
- package/dist/behaviors/draggable.js +2 -2
- package/dist/behaviors/focustrap.cjs +5 -81
- package/dist/behaviors/focustrap.cjs.map +1 -1
- package/dist/behaviors/focustrap.d.cts +3 -2
- package/dist/behaviors/focustrap.d.ts +3 -2
- package/dist/behaviors/focustrap.js +1 -1
- package/dist/behaviors/removable.d.cts +1 -1
- package/dist/behaviors/removable.d.ts +1 -1
- package/dist/behaviors/resizable.cjs +9 -49
- package/dist/behaviors/resizable.cjs.map +1 -1
- package/dist/behaviors/resizable.d.cts +3 -2
- package/dist/behaviors/resizable.d.ts +3 -2
- package/dist/behaviors/resizable.js +2 -2
- package/dist/behaviors/scrollreveal.cjs +5 -32
- package/dist/behaviors/scrollreveal.cjs.map +1 -1
- package/dist/behaviors/scrollreveal.d.cts +3 -2
- package/dist/behaviors/scrollreveal.d.ts +3 -2
- package/dist/behaviors/scrollreveal.js +1 -1
- package/dist/behaviors/sortable.cjs +8 -43
- package/dist/behaviors/sortable.cjs.map +1 -1
- package/dist/behaviors/sortable.d.cts +3 -2
- package/dist/behaviors/sortable.d.ts +3 -2
- package/dist/behaviors/sortable.js +2 -2
- package/dist/behaviors/tabs.cjs +5 -120
- package/dist/behaviors/tabs.cjs.map +1 -1
- package/dist/behaviors/tabs.d.cts +3 -2
- package/dist/behaviors/tabs.d.ts +3 -2
- package/dist/behaviors/tabs.js +1 -1
- package/dist/behaviors/toggleable.cjs +5 -27
- package/dist/behaviors/toggleable.cjs.map +1 -1
- package/dist/behaviors/toggleable.d.cts +3 -3
- package/dist/behaviors/toggleable.d.ts +3 -3
- package/dist/behaviors/toggleable.js +1 -1
- package/dist/{chunk-SLOXO6IY.js → chunk-26IX7QU7.js} +2 -2
- package/dist/{chunk-SLOXO6IY.js.map → chunk-26IX7QU7.js.map} +1 -1
- package/dist/chunk-2HUF6RMI.js +40 -0
- package/dist/chunk-2HUF6RMI.js.map +1 -0
- package/dist/{chunk-ZBSWTV6I.js → chunk-5LFOFVZ3.js} +5 -5
- package/dist/chunk-5LFOFVZ3.js.map +1 -0
- package/dist/{chunk-BBIIOGMF.js → chunk-6EG2MNC7.js} +6 -6
- package/dist/chunk-7NGOA3T5.js +40 -0
- package/dist/chunk-7NGOA3T5.js.map +1 -0
- package/dist/{chunk-ZZ2WSAX3.js → chunk-7TPDLB7W.js} +7 -29
- package/dist/chunk-7TPDLB7W.js.map +1 -0
- package/dist/chunk-CR3J7VV6.js +40 -0
- package/dist/chunk-CR3J7VV6.js.map +1 -0
- package/dist/chunk-EDBG2F57.js +40 -0
- package/dist/chunk-EDBG2F57.js.map +1 -0
- package/dist/{chunk-G6WR2AYR.js → chunk-FBQ3X3UY.js} +2 -2
- package/dist/chunk-FBQ3X3UY.js.map +1 -0
- package/dist/chunk-HX663BJ4.js +40 -0
- package/dist/chunk-HX663BJ4.js.map +1 -0
- package/dist/chunk-KROW43CG.js +40 -0
- package/dist/chunk-KROW43CG.js.map +1 -0
- package/dist/chunk-ORBJ7MRW.js +40 -0
- package/dist/chunk-ORBJ7MRW.js.map +1 -0
- package/dist/{chunk-V2M4W3LO.js → chunk-PDMOOWFW.js} +4 -4
- package/dist/chunk-PDMOOWFW.js.map +1 -0
- package/dist/chunk-SLSCZV4A.js +40 -0
- package/dist/chunk-SLSCZV4A.js.map +1 -0
- package/dist/chunk-WKBRZGGL.js +40 -0
- package/dist/chunk-WKBRZGGL.js.map +1 -0
- package/dist/{chunk-WOTZO7K4.js → chunk-YXS27XM6.js} +26 -23
- package/dist/chunk-YXS27XM6.js.map +1 -0
- package/dist/clickoutside.browser.global.js +3 -3
- package/dist/clickoutside.browser.global.js.map +1 -1
- package/dist/clipboard.browser.global.js +27 -24
- package/dist/clipboard.browser.global.js.map +1 -1
- 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 +2 -2
- package/dist/focustrap.browser.global.js.map +1 -1
- package/dist/index.cjs +120 -563
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +41 -3
- package/dist/index.d.ts +41 -3
- package/dist/index.js +44 -16
- package/dist/index.js.map +1 -1
- package/dist/loaders.cjs +86 -563
- package/dist/loaders.cjs.map +1 -1
- package/dist/loaders.js +6 -6
- package/dist/registry.d.cts +1 -1
- package/dist/registry.d.ts +1 -1
- package/dist/resizable.browser.global.js +5 -5
- package/dist/resizable.browser.global.js.map +1 -1
- package/dist/resolver.browser.global.js +34 -31
- package/dist/resolver.browser.global.js.map +1 -1
- package/dist/schemas/index.cjs +34 -31
- 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 +5 -5
- package/dist/scrollreveal.browser.global.js +2 -2
- package/dist/scrollreveal.browser.global.js.map +1 -1
- package/dist/sortable.browser.global.js +4 -4
- package/dist/sortable.browser.global.js.map +1 -1
- package/dist/tabs.browser.global.js +2 -2
- package/dist/tabs.browser.global.js.map +1 -1
- package/dist/toggleable.browser.global.js +2 -2
- package/dist/toggleable.browser.global.js.map +1 -1
- package/dist/{types-BY-jB5FV.d.ts → types-DCCtVQS5.d.cts} +1 -1
- package/dist/{types-BY-jB5FV.d.cts → types-DCCtVQS5.d.ts} +1 -1
- package/package.json +4 -4
- package/src/behaviors/autodismiss.test.ts +15 -9
- package/src/behaviors/autodismiss.ts +15 -70
- package/src/behaviors/clickoutside.test.ts +17 -9
- package/src/behaviors/clickoutside.ts +13 -39
- package/src/behaviors/clipboard.test.ts +16 -10
- package/src/behaviors/clipboard.ts +15 -93
- package/src/behaviors/curated-runtime.test.ts +158 -0
- package/src/behaviors/draggable.ts +15 -59
- package/src/behaviors/experimental-runtime.test.ts +136 -0
- package/src/behaviors/focustrap.test.ts +15 -9
- package/src/behaviors/focustrap.ts +17 -121
- package/src/behaviors/integration.test.ts +9 -64
- package/src/behaviors/optional-runtime.test.ts +251 -0
- package/src/behaviors/resizable.ts +14 -61
- package/src/behaviors/scrollreveal.test.ts +17 -9
- package/src/behaviors/scrollreveal.ts +17 -41
- package/src/behaviors/sortable.ts +15 -58
- package/src/behaviors/tabs.test.ts +16 -10
- package/src/behaviors/tabs.ts +18 -160
- package/src/behaviors/toggleable.ts +14 -41
- package/src/curation.test.ts +45 -0
- package/src/curation.ts +58 -0
- package/src/index.ts +14 -0
- package/src/registry.test.ts +6 -11
- package/src/schemas/clickoutside.schema.ts +1 -1
- package/src/schemas/clipboard.schema.ts +25 -22
- package/src/schemas/draggable.schema.ts +2 -1
- package/src/schemas/resizable.schema.ts +5 -4
- package/src/schemas/sortable.schema.ts +4 -3
- package/dist/chunk-7O7UOSBH.js +0 -99
- package/dist/chunk-7O7UOSBH.js.map +0 -1
- package/dist/chunk-EKKJVXDZ.js +0 -67
- package/dist/chunk-EKKJVXDZ.js.map +0 -1
- package/dist/chunk-F3CASJ7Q.js +0 -116
- package/dist/chunk-F3CASJ7Q.js.map +0 -1
- package/dist/chunk-G6WR2AYR.js.map +0 -1
- package/dist/chunk-GALKOMJ5.js +0 -62
- package/dist/chunk-GALKOMJ5.js.map +0 -1
- package/dist/chunk-IMDFEGIT.js +0 -75
- package/dist/chunk-IMDFEGIT.js.map +0 -1
- package/dist/chunk-IT6TYVMW.js +0 -80
- package/dist/chunk-IT6TYVMW.js.map +0 -1
- package/dist/chunk-LQJOQTBZ.js +0 -89
- package/dist/chunk-LQJOQTBZ.js.map +0 -1
- package/dist/chunk-S4QDV2MH.js +0 -75
- package/dist/chunk-S4QDV2MH.js.map +0 -1
- package/dist/chunk-V2M4W3LO.js.map +0 -1
- package/dist/chunk-WOTZO7K4.js.map +0 -1
- package/dist/chunk-WPOQIMCC.js +0 -155
- package/dist/chunk-WPOQIMCC.js.map +0 -1
- package/dist/chunk-ZBSWTV6I.js.map +0 -1
- package/dist/chunk-ZZ2WSAX3.js.map +0 -1
- /package/dist/{chunk-BBIIOGMF.js.map → chunk-6EG2MNC7.js.map} +0 -0
package/src/behaviors/tabs.ts
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Tabs Behavior
|
|
2
|
+
* Tabs Behavior
|
|
3
3
|
*
|
|
4
4
|
* WAI-ARIA compliant tabs with roving tabindex keyboard navigation.
|
|
5
|
-
* Auto-wires role, aria-selected, aria-controls, and aria-labelledby.
|
|
5
|
+
* Auto-wires role, aria-selected, aria-controls, and aria-labelledby. The ARIA
|
|
6
|
+
* wiring / keyboard-navigation logic lives in the schema's hyperscript `source`
|
|
7
|
+
* (an `init`-block `js()` body).
|
|
8
|
+
*
|
|
9
|
+
* Compiled from its hyperscript `source` — the single source of truth shared with
|
|
10
|
+
* the CDN resolver bundle and patterns-reference. This collapses Tabs onto the one
|
|
11
|
+
* runtime path (no more imperative-installer fork between CDN and npm);
|
|
12
|
+
* see docs-internal/BEHAVIORS_CONSOLIDATION_PLAN.md §3d.
|
|
6
13
|
*/
|
|
7
14
|
|
|
8
15
|
import { tabsSchema } from '../schemas/tabs.schema';
|
|
@@ -12,157 +19,9 @@ import { resolveRuntime } from '../schemas/types';
|
|
|
12
19
|
export const tabsSource = tabsSchema.source;
|
|
13
20
|
export const tabsMetadata = tabsSchema;
|
|
14
21
|
|
|
15
|
-
let idCounter = 0;
|
|
16
|
-
|
|
17
|
-
function ensureId(el: HTMLElement, prefix: string): string {
|
|
18
|
-
if (!el.id) {
|
|
19
|
-
el.id = `${prefix}-${++idCounter}`;
|
|
20
|
-
}
|
|
21
|
-
return el.id;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Imperative installer for Tabs behavior.
|
|
26
|
-
*/
|
|
27
|
-
function installTabs(element: HTMLElement, params: Record<string, any>): void {
|
|
28
|
-
const orientation = params.orientation === 'vertical' ? 'vertical' : 'horizontal';
|
|
29
|
-
const wrap = params.wrap !== false;
|
|
30
|
-
const activeClass = (params.activeClass as string) || 'active';
|
|
31
|
-
const initialIndex = typeof params.activeTab === 'number' ? params.activeTab : 0;
|
|
32
|
-
|
|
33
|
-
// Discover tabs and panels
|
|
34
|
-
const tabs = Array.from(element.querySelectorAll<HTMLElement>('[role="tab"]'));
|
|
35
|
-
const panels = Array.from(element.querySelectorAll<HTMLElement>('[role="tabpanel"]'));
|
|
36
|
-
|
|
37
|
-
if (tabs.length === 0 || panels.length === 0) return;
|
|
38
|
-
|
|
39
|
-
// Find or mark the tablist
|
|
40
|
-
const tablist = element.querySelector<HTMLElement>('[role="tablist"]') || tabs[0].parentElement;
|
|
41
|
-
if (tablist && !tablist.getAttribute('role')) {
|
|
42
|
-
tablist.setAttribute('role', 'tablist');
|
|
43
|
-
}
|
|
44
|
-
if (tablist) {
|
|
45
|
-
tablist.setAttribute('aria-orientation', orientation);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Wire IDs, aria-controls, aria-labelledby
|
|
49
|
-
const count = Math.min(tabs.length, panels.length);
|
|
50
|
-
for (let i = 0; i < count; i++) {
|
|
51
|
-
const tabId = ensureId(tabs[i], 'tab');
|
|
52
|
-
const panelId = ensureId(panels[i], 'tabpanel');
|
|
53
|
-
tabs[i].setAttribute('aria-controls', panelId);
|
|
54
|
-
panels[i].setAttribute('aria-labelledby', tabId);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
let currentIndex = -1;
|
|
58
|
-
|
|
59
|
-
function selectTab(index: number, previousIndex: number): boolean {
|
|
60
|
-
if (index === previousIndex || index < 0 || index >= count) return false;
|
|
61
|
-
|
|
62
|
-
const detail = {
|
|
63
|
-
tab: tabs[index],
|
|
64
|
-
panel: panels[index],
|
|
65
|
-
index,
|
|
66
|
-
previousIndex,
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
// Cancelable before-event
|
|
70
|
-
const changeEvent = new CustomEvent('tabs:change', {
|
|
71
|
-
bubbles: true,
|
|
72
|
-
cancelable: true,
|
|
73
|
-
detail,
|
|
74
|
-
});
|
|
75
|
-
element.dispatchEvent(changeEvent);
|
|
76
|
-
if (changeEvent.defaultPrevented) return false;
|
|
77
|
-
|
|
78
|
-
// Deactivate previous
|
|
79
|
-
if (previousIndex >= 0 && previousIndex < count) {
|
|
80
|
-
tabs[previousIndex].setAttribute('aria-selected', 'false');
|
|
81
|
-
tabs[previousIndex].setAttribute('tabindex', '-1');
|
|
82
|
-
tabs[previousIndex].classList.remove(activeClass);
|
|
83
|
-
panels[previousIndex].setAttribute('aria-hidden', 'true');
|
|
84
|
-
panels[previousIndex].classList.remove(activeClass);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// Activate new
|
|
88
|
-
tabs[index].setAttribute('aria-selected', 'true');
|
|
89
|
-
tabs[index].setAttribute('tabindex', '0');
|
|
90
|
-
tabs[index].classList.add(activeClass);
|
|
91
|
-
panels[index].setAttribute('aria-hidden', 'false');
|
|
92
|
-
panels[index].classList.add(activeClass);
|
|
93
|
-
|
|
94
|
-
currentIndex = index;
|
|
95
|
-
|
|
96
|
-
element.dispatchEvent(new CustomEvent('tabs:changed', { bubbles: true, detail }));
|
|
97
|
-
return true;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// Initialize all tabs as inactive, then activate initial
|
|
101
|
-
for (let i = 0; i < count; i++) {
|
|
102
|
-
tabs[i].setAttribute('aria-selected', 'false');
|
|
103
|
-
tabs[i].setAttribute('tabindex', '-1');
|
|
104
|
-
tabs[i].classList.remove(activeClass);
|
|
105
|
-
panels[i].setAttribute('aria-hidden', 'true');
|
|
106
|
-
panels[i].classList.remove(activeClass);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const clamped = Math.max(0, Math.min(initialIndex, count - 1));
|
|
110
|
-
// Directly activate without firing change event on init
|
|
111
|
-
tabs[clamped].setAttribute('aria-selected', 'true');
|
|
112
|
-
tabs[clamped].setAttribute('tabindex', '0');
|
|
113
|
-
tabs[clamped].classList.add(activeClass);
|
|
114
|
-
panels[clamped].setAttribute('aria-hidden', 'false');
|
|
115
|
-
panels[clamped].classList.add(activeClass);
|
|
116
|
-
currentIndex = clamped;
|
|
117
|
-
|
|
118
|
-
// Click handler
|
|
119
|
-
for (let i = 0; i < count; i++) {
|
|
120
|
-
tabs[i].addEventListener('click', () => {
|
|
121
|
-
selectTab(i, currentIndex);
|
|
122
|
-
tabs[i].focus();
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// Keyboard handler on tablist
|
|
127
|
-
const keyTarget = tablist || element;
|
|
128
|
-
keyTarget.addEventListener('keydown', (e: KeyboardEvent) => {
|
|
129
|
-
const isHorizontal = orientation === 'horizontal';
|
|
130
|
-
const nextKey = isHorizontal ? 'ArrowRight' : 'ArrowDown';
|
|
131
|
-
const prevKey = isHorizontal ? 'ArrowLeft' : 'ArrowUp';
|
|
132
|
-
|
|
133
|
-
let nextIndex: number | null = null;
|
|
134
|
-
|
|
135
|
-
if (e.key === nextKey) {
|
|
136
|
-
nextIndex = currentIndex + 1;
|
|
137
|
-
if (nextIndex >= count) nextIndex = wrap ? 0 : null;
|
|
138
|
-
} else if (e.key === prevKey) {
|
|
139
|
-
nextIndex = currentIndex - 1;
|
|
140
|
-
if (nextIndex < 0) nextIndex = wrap ? count - 1 : null;
|
|
141
|
-
} else if (e.key === 'Home') {
|
|
142
|
-
nextIndex = 0;
|
|
143
|
-
} else if (e.key === 'End') {
|
|
144
|
-
nextIndex = count - 1;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
if (nextIndex !== null) {
|
|
148
|
-
e.preventDefault();
|
|
149
|
-
if (selectTab(nextIndex, currentIndex)) {
|
|
150
|
-
tabs[nextIndex].focus();
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
// Programmatic tab selection
|
|
156
|
-
element.addEventListener('tabs:select', ((e: CustomEvent) => {
|
|
157
|
-
const index = e.detail?.index;
|
|
158
|
-
if (typeof index === 'number') {
|
|
159
|
-
selectTab(index, currentIndex);
|
|
160
|
-
}
|
|
161
|
-
}) as EventListener);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
22
|
/**
|
|
165
|
-
* Register the Tabs behavior with LokaScript
|
|
23
|
+
* Register the Tabs behavior with LokaScript by compiling its
|
|
24
|
+
* hyperscript source and executing the resulting behavior definition.
|
|
166
25
|
*/
|
|
167
26
|
export async function registerTabs(hyperfixi?: LokaScriptInstance): Promise<void> {
|
|
168
27
|
const hf = hyperfixi || resolveRuntime();
|
|
@@ -173,15 +32,14 @@ export async function registerTabs(hyperfixi?: LokaScriptInstance): Promise<void
|
|
|
173
32
|
);
|
|
174
33
|
}
|
|
175
34
|
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
};
|
|
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
|
+
|
|
183
41
|
const ctx = hf.createContext ? hf.createContext() : { locals: new Map(), globals: new Map() };
|
|
184
|
-
await hf.execute(
|
|
42
|
+
await hf.execute(result.ast, ctx);
|
|
185
43
|
}
|
|
186
44
|
|
|
187
45
|
// Auto-register when loaded as a script tag
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Toggleable Behavior
|
|
2
|
+
* Toggleable Behavior
|
|
3
3
|
*
|
|
4
4
|
* A behavior that toggles a CSS class on click.
|
|
5
5
|
* Useful for accordions, dropdowns, and toggle buttons.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* behavior
|
|
7
|
+
* Compiled from its hyperscript `source` (the single source of truth shared with
|
|
8
|
+
* the CDN resolver bundle and patterns-reference). The `.{cls}` dynamic class
|
|
9
|
+
* selector resolves the behavior's `cls` parameter at runtime — see
|
|
10
|
+
* `packages/core/src/commands/behaviors/__tests__/template-interpolation.test.ts`.
|
|
10
11
|
*
|
|
11
12
|
* @example
|
|
12
13
|
* ```html
|
|
@@ -25,35 +26,8 @@ export const toggleableSource = toggleableSchema.source;
|
|
|
25
26
|
export const toggleableMetadata = toggleableSchema;
|
|
26
27
|
|
|
27
28
|
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*/
|
|
31
|
-
function installToggleable(element: HTMLElement, params: Record<string, any>): void {
|
|
32
|
-
const cls = params.cls || 'active';
|
|
33
|
-
|
|
34
|
-
// Resolve target element
|
|
35
|
-
let targetEl: HTMLElement = element;
|
|
36
|
-
if (params.target && params.target !== 'me') {
|
|
37
|
-
if (typeof params.target === 'string') {
|
|
38
|
-
const found = document.querySelector(params.target);
|
|
39
|
-
if (found instanceof HTMLElement) targetEl = found;
|
|
40
|
-
} else if (params.target instanceof HTMLElement) {
|
|
41
|
-
targetEl = params.target;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
element.addEventListener('click', () => {
|
|
46
|
-
const wasOn = targetEl.classList.contains(cls);
|
|
47
|
-
targetEl.classList.toggle(cls);
|
|
48
|
-
targetEl.dispatchEvent(
|
|
49
|
-
new CustomEvent(wasOn ? 'toggleable:off' : 'toggleable:on', { bubbles: true })
|
|
50
|
-
);
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Register the Toggleable behavior with LokaScript.
|
|
56
|
-
* Uses imperative installer via synthetic behavior node.
|
|
29
|
+
* Register the Toggleable behavior with LokaScript by compiling its
|
|
30
|
+
* hyperscript source and executing the resulting behavior definition.
|
|
57
31
|
*/
|
|
58
32
|
export async function registerToggleable(hyperfixi?: LokaScriptInstance): Promise<void> {
|
|
59
33
|
const hf = hyperfixi || resolveRuntime();
|
|
@@ -64,15 +38,14 @@ export async function registerToggleable(hyperfixi?: LokaScriptInstance): Promis
|
|
|
64
38
|
);
|
|
65
39
|
}
|
|
66
40
|
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
};
|
|
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
|
+
|
|
74
47
|
const ctx = hf.createContext ? hf.createContext() : { locals: new Map(), globals: new Map() };
|
|
75
|
-
await hf.execute(
|
|
48
|
+
await hf.execute(result.ast, ctx);
|
|
76
49
|
}
|
|
77
50
|
|
|
78
51
|
// Auto-register when loaded as a script tag
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
CURATED_BEHAVIORS,
|
|
4
|
+
OPTIONAL_BEHAVIORS,
|
|
5
|
+
EXPERIMENTAL_BEHAVIORS,
|
|
6
|
+
CURATION_STATUS,
|
|
7
|
+
curationStatusOf,
|
|
8
|
+
isCurated,
|
|
9
|
+
} from './curation';
|
|
10
|
+
import { ALL_BEHAVIOR_NAMES } from './generated/metadata';
|
|
11
|
+
|
|
12
|
+
describe('curation', () => {
|
|
13
|
+
it('partitions all behaviors into exactly one status', () => {
|
|
14
|
+
const all = [...CURATED_BEHAVIORS, ...OPTIONAL_BEHAVIORS, ...EXPERIMENTAL_BEHAVIORS];
|
|
15
|
+
// No overlaps.
|
|
16
|
+
expect(new Set(all).size).toBe(all.length);
|
|
17
|
+
// Covers exactly the known behavior set.
|
|
18
|
+
expect(new Set(all)).toEqual(new Set(ALL_BEHAVIOR_NAMES));
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('marks the curated 5', () => {
|
|
22
|
+
expect([...CURATED_BEHAVIORS].sort()).toEqual(
|
|
23
|
+
['AutoDismiss', 'ClickOutside', 'Clipboard', 'Removable', 'Toggleable'].sort()
|
|
24
|
+
);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('marks the experimental 3 (beyond the boundary)', () => {
|
|
28
|
+
expect([...EXPERIMENTAL_BEHAVIORS].sort()).toEqual(['Draggable', 'Resizable', 'Sortable']);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('curationStatusOf / isCurated agree with the table', () => {
|
|
32
|
+
expect(curationStatusOf('Toggleable')).toBe('curated');
|
|
33
|
+
expect(curationStatusOf('Draggable')).toBe('experimental');
|
|
34
|
+
expect(curationStatusOf('Tabs')).toBe('optional');
|
|
35
|
+
expect(curationStatusOf('Nope')).toBeUndefined();
|
|
36
|
+
expect(isCurated('Clipboard')).toBe(true);
|
|
37
|
+
expect(isCurated('Sortable')).toBe(false);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('every behavior has a status', () => {
|
|
41
|
+
for (const name of ALL_BEHAVIOR_NAMES) {
|
|
42
|
+
expect(CURATION_STATUS[name]).toBeDefined();
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
});
|
package/src/curation.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Curation status — the product decision about which behaviors are first-class.
|
|
3
|
+
*
|
|
4
|
+
* This is ORTHOGONAL to {@link BehaviorTier} (core/common/optional), which is about
|
|
5
|
+
* lazy-loading priority. Curation is about support level and the boundary rule:
|
|
6
|
+
*
|
|
7
|
+
* A behavior is a named, parameterized, *reusable inline script* — `on event →
|
|
8
|
+
* DOM action`. Not a component. When it needs an observer, a focus model, or an
|
|
9
|
+
* async pointer loop, it has left hyperfixi's lane.
|
|
10
|
+
*
|
|
11
|
+
* See docs-internal/BEHAVIORS_CONSOLIDATION_PLAN.md for the full rationale.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export type CurationStatus = 'curated' | 'optional' | 'experimental';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Curated set — reliable, runtime-tested, multilingual. The supported story.
|
|
18
|
+
* Real `on event → DOM action` behaviors (Tier A) plus two honestly-labeled
|
|
19
|
+
* JS-backed conveniences (Clipboard, AutoDismiss).
|
|
20
|
+
*/
|
|
21
|
+
export const CURATED_BEHAVIORS = [
|
|
22
|
+
'Toggleable',
|
|
23
|
+
'Removable',
|
|
24
|
+
'ClickOutside',
|
|
25
|
+
'Clipboard',
|
|
26
|
+
'AutoDismiss',
|
|
27
|
+
] as const;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Optional — useful, kept, documented as primitives / nice-to-haves.
|
|
31
|
+
* FocusTrap + ClickOutside are the primitives a Modal composes from; ScrollReveal
|
|
32
|
+
* is a nice-to-have; Tabs is high-value but heavy.
|
|
33
|
+
*/
|
|
34
|
+
export const OPTIONAL_BEHAVIORS = ['FocusTrap', 'ScrollReveal', 'Tabs'] as const;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Experimental — stateful async components (drag/sort/resize). These sit *beyond*
|
|
38
|
+
* the inline-scripting boundary; kept working but explicitly outside the curated,
|
|
39
|
+
* supported, marketed story.
|
|
40
|
+
*/
|
|
41
|
+
export const EXPERIMENTAL_BEHAVIORS = ['Draggable', 'Sortable', 'Resizable'] as const;
|
|
42
|
+
|
|
43
|
+
/** Curation status for every behavior, keyed by name. */
|
|
44
|
+
export const CURATION_STATUS: Record<string, CurationStatus> = {
|
|
45
|
+
...Object.fromEntries(CURATED_BEHAVIORS.map(n => [n, 'curated' as const])),
|
|
46
|
+
...Object.fromEntries(OPTIONAL_BEHAVIORS.map(n => [n, 'optional' as const])),
|
|
47
|
+
...Object.fromEntries(EXPERIMENTAL_BEHAVIORS.map(n => [n, 'experimental' as const])),
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/** Curation status for a behavior name, or undefined if unknown. */
|
|
51
|
+
export function curationStatusOf(name: string): CurationStatus | undefined {
|
|
52
|
+
return CURATION_STATUS[name];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** True for the curated, supported set. */
|
|
56
|
+
export function isCurated(name: string): boolean {
|
|
57
|
+
return CURATION_STATUS[name] === 'curated';
|
|
58
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -185,6 +185,20 @@ export {
|
|
|
185
185
|
BEHAVIOR_TIERS,
|
|
186
186
|
} from './generated/metadata';
|
|
187
187
|
|
|
188
|
+
// =============================================================================
|
|
189
|
+
// Curation status (curated / optional / experimental) — see curation.ts
|
|
190
|
+
// =============================================================================
|
|
191
|
+
|
|
192
|
+
export type { CurationStatus } from './curation';
|
|
193
|
+
export {
|
|
194
|
+
CURATED_BEHAVIORS,
|
|
195
|
+
OPTIONAL_BEHAVIORS,
|
|
196
|
+
EXPERIMENTAL_BEHAVIORS,
|
|
197
|
+
CURATION_STATUS,
|
|
198
|
+
curationStatusOf,
|
|
199
|
+
isCurated,
|
|
200
|
+
} from './curation';
|
|
201
|
+
|
|
188
202
|
// =============================================================================
|
|
189
203
|
// Convenience functions
|
|
190
204
|
// =============================================================================
|
package/src/registry.test.ts
CHANGED
|
@@ -175,7 +175,7 @@ describe('registry', () => {
|
|
|
175
175
|
});
|
|
176
176
|
|
|
177
177
|
describe('registerWithRuntime', () => {
|
|
178
|
-
it('should load and call module.register (
|
|
178
|
+
it('should load and call module.register (Draggable — now source-compiled)', async () => {
|
|
179
179
|
const mockInstance = {
|
|
180
180
|
compileSync: vi.fn().mockReturnValue({ ok: true, ast: {} }),
|
|
181
181
|
execute: vi.fn().mockResolvedValue(undefined),
|
|
@@ -185,15 +185,10 @@ describe('registry', () => {
|
|
|
185
185
|
await loadBehavior('Draggable');
|
|
186
186
|
await registerWithRuntime('Draggable', mockInstance);
|
|
187
187
|
|
|
188
|
-
//
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
name: 'Draggable',
|
|
193
|
-
imperativeInstaller: expect.any(Function),
|
|
194
|
-
}),
|
|
195
|
-
expect.objectContaining({ locals: expect.any(Map), globals: expect.any(Map) })
|
|
196
|
-
);
|
|
188
|
+
// Draggable used to install imperatively; it now compiles its hyperscript
|
|
189
|
+
// `source` like every other behavior (no imperative installer).
|
|
190
|
+
expect(mockInstance.compileSync).toHaveBeenCalled();
|
|
191
|
+
expect(mockInstance.execute).toHaveBeenCalled();
|
|
197
192
|
});
|
|
198
193
|
|
|
199
194
|
it('should load and call module.register (compiled behavior)', async () => {
|
|
@@ -221,7 +216,7 @@ describe('registry', () => {
|
|
|
221
216
|
|
|
222
217
|
await loadAll();
|
|
223
218
|
await registerAllWithRuntime(mockInstance);
|
|
224
|
-
// execute called for each behavior (
|
|
219
|
+
// execute called for each behavior (all source-compiled now)
|
|
225
220
|
expect(mockInstance.execute.mock.calls.length).toBeGreaterThanOrEqual(10);
|
|
226
221
|
});
|
|
227
222
|
});
|
|
@@ -41,7 +41,7 @@ behavior ClickOutside(active)
|
|
|
41
41
|
end
|
|
42
42
|
end
|
|
43
43
|
on pointerdown from document
|
|
44
|
-
js(me, active)
|
|
44
|
+
js(me, active, event)
|
|
45
45
|
if (!me.isConnected) return;
|
|
46
46
|
if (active && !me.contains(event.target)) {
|
|
47
47
|
me.dispatchEvent(new CustomEvent('clickoutside', { bubbles: true }));
|
|
@@ -65,29 +65,32 @@ behavior Clipboard(text, source, feedback, feedbackDuration)
|
|
|
65
65
|
set copyText to source's textContent
|
|
66
66
|
end
|
|
67
67
|
js(me, copyText, feedback, feedbackDuration)
|
|
68
|
-
async
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
// Wrapped in an async IIFE: hyperscript's js() block has no top-level await.
|
|
69
|
+
(async function() {
|
|
70
|
+
async function copyToClipboard(t) {
|
|
71
|
+
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
72
|
+
await navigator.clipboard.writeText(t);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
var ta = document.createElement('textarea');
|
|
76
|
+
ta.value = t;
|
|
77
|
+
ta.style.position = 'fixed';
|
|
78
|
+
ta.style.opacity = '0';
|
|
79
|
+
document.body.appendChild(ta);
|
|
80
|
+
ta.select();
|
|
81
|
+
try { document.execCommand('copy'); } finally { document.body.removeChild(ta); }
|
|
72
82
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
if (!feedbackEl) feedbackEl = me;
|
|
85
|
-
feedbackEl.classList.add('copied');
|
|
86
|
-
me.dispatchEvent(new CustomEvent('clipboard:copied', { bubbles: true, detail: { text: copyText } }));
|
|
87
|
-
setTimeout(function() { feedbackEl.classList.remove('copied'); }, feedbackDuration);
|
|
88
|
-
} catch(err) {
|
|
89
|
-
me.dispatchEvent(new CustomEvent('clipboard:error', { bubbles: true, detail: { error: err } }));
|
|
90
|
-
}
|
|
83
|
+
try {
|
|
84
|
+
await copyToClipboard(copyText);
|
|
85
|
+
var feedbackEl = feedback ? (typeof feedback === 'string' ? document.querySelector(feedback) : feedback) : me;
|
|
86
|
+
if (!feedbackEl) feedbackEl = me;
|
|
87
|
+
feedbackEl.classList.add('copied');
|
|
88
|
+
me.dispatchEvent(new CustomEvent('clipboard:copied', { bubbles: true, detail: { text: copyText } }));
|
|
89
|
+
setTimeout(function() { feedbackEl.classList.remove('copied'); }, feedbackDuration);
|
|
90
|
+
} catch(err) {
|
|
91
|
+
me.dispatchEvent(new CustomEvent('clipboard:error', { bubbles: true, detail: { error: err } }));
|
|
92
|
+
}
|
|
93
|
+
})();
|
|
91
94
|
end
|
|
92
95
|
end
|
|
93
96
|
end`.trim(),
|
|
@@ -11,7 +11,8 @@ export const draggableSchema: BehaviorSchema = {
|
|
|
11
11
|
category: 'ui',
|
|
12
12
|
tier: 'core',
|
|
13
13
|
version: '1.0.0',
|
|
14
|
-
description:
|
|
14
|
+
description:
|
|
15
|
+
'Makes elements draggable with pointer events (EXPERIMENTAL — stateful async component, beyond the inline-scripting boundary; not part of the curated set)',
|
|
15
16
|
parameters: [
|
|
16
17
|
{
|
|
17
18
|
name: 'dragHandle',
|
|
@@ -11,7 +11,8 @@ export const resizableSchema: BehaviorSchema = {
|
|
|
11
11
|
category: 'ui',
|
|
12
12
|
tier: 'optional',
|
|
13
13
|
version: '1.0.0',
|
|
14
|
-
description:
|
|
14
|
+
description:
|
|
15
|
+
'Makes elements resizable by dragging (EXPERIMENTAL — stateful async component, beyond the inline-scripting boundary; not part of the curated set)',
|
|
15
16
|
parameters: [
|
|
16
17
|
{
|
|
17
18
|
name: 'minWidth',
|
|
@@ -59,15 +60,15 @@ behavior Resizable(minWidth, minHeight, maxWidth, maxHeight)
|
|
|
59
60
|
set startX to clientX
|
|
60
61
|
set startY to clientY
|
|
61
62
|
repeat until event pointerup from document
|
|
62
|
-
wait for pointermove(clientX, clientY) from document
|
|
63
|
+
wait for pointermove(clientX, clientY) or pointerup(clientX, clientY) from document
|
|
63
64
|
set newWidth to startWidth + clientX - startX
|
|
64
65
|
set newHeight to startHeight + clientY - startY
|
|
65
66
|
if newWidth < minWidth then set newWidth to minWidth end
|
|
66
67
|
if newWidth > maxWidth then set newWidth to maxWidth end
|
|
67
68
|
if newHeight < minHeight then set newHeight to minHeight end
|
|
68
69
|
if newHeight > maxHeight then set newHeight to maxHeight end
|
|
69
|
-
set my
|
|
70
|
-
set my
|
|
70
|
+
set my *width to newWidth + "px"
|
|
71
|
+
set my *height to newHeight + "px"
|
|
71
72
|
trigger resizable:resize
|
|
72
73
|
end
|
|
73
74
|
trigger resizable:end
|
|
@@ -15,7 +15,8 @@ export const sortableSchema: BehaviorSchema = {
|
|
|
15
15
|
category: 'ui',
|
|
16
16
|
tier: 'common',
|
|
17
17
|
version: '1.0.0',
|
|
18
|
-
description:
|
|
18
|
+
description:
|
|
19
|
+
'Makes child elements reorderable via drag-and-drop (EXPERIMENTAL — stateful async component, beyond the inline-scripting boundary; not part of the curated set)',
|
|
19
20
|
parameters: [
|
|
20
21
|
{
|
|
21
22
|
name: 'dragClass',
|
|
@@ -42,7 +43,7 @@ behavior Sortable(dragClass)
|
|
|
42
43
|
end
|
|
43
44
|
end
|
|
44
45
|
on pointerdown(clientY) from me
|
|
45
|
-
set item to the closest
|
|
46
|
+
set item to the target.closest("li")
|
|
46
47
|
if item is null
|
|
47
48
|
exit
|
|
48
49
|
end
|
|
@@ -50,7 +51,7 @@ behavior Sortable(dragClass)
|
|
|
50
51
|
add .{dragClass} to item
|
|
51
52
|
trigger sortable:start on me
|
|
52
53
|
repeat until event pointerup from document
|
|
53
|
-
wait for pointermove(clientY) from document
|
|
54
|
+
wait for pointermove(clientY) or pointerup(clientY) from document
|
|
54
55
|
trigger sortable:move on me
|
|
55
56
|
end
|
|
56
57
|
remove .{dragClass} from item
|
package/dist/chunk-7O7UOSBH.js
DELETED
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
clipboardSchema
|
|
3
|
-
} from "./chunk-WOTZO7K4.js";
|
|
4
|
-
import {
|
|
5
|
-
resolveRuntime
|
|
6
|
-
} from "./chunk-6TJXDCAQ.js";
|
|
7
|
-
|
|
8
|
-
// src/behaviors/clipboard.ts
|
|
9
|
-
var clipboardSource = clipboardSchema.source;
|
|
10
|
-
var clipboardMetadata = clipboardSchema;
|
|
11
|
-
async function copyToClipboard(text) {
|
|
12
|
-
if (navigator.clipboard?.writeText) {
|
|
13
|
-
await navigator.clipboard.writeText(text);
|
|
14
|
-
return;
|
|
15
|
-
}
|
|
16
|
-
const textarea = document.createElement("textarea");
|
|
17
|
-
textarea.value = text;
|
|
18
|
-
textarea.style.position = "fixed";
|
|
19
|
-
textarea.style.opacity = "0";
|
|
20
|
-
document.body.appendChild(textarea);
|
|
21
|
-
textarea.select();
|
|
22
|
-
try {
|
|
23
|
-
document.execCommand("copy");
|
|
24
|
-
} finally {
|
|
25
|
-
document.body.removeChild(textarea);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
function resolveElement(element, param) {
|
|
29
|
-
if (!param || param === "me") return element;
|
|
30
|
-
if (param instanceof HTMLElement) return param;
|
|
31
|
-
if (typeof param === "string") {
|
|
32
|
-
return element.querySelector(param) || document.querySelector(param) || null;
|
|
33
|
-
}
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
function installClipboard(element, params) {
|
|
37
|
-
const feedbackDuration = typeof params.feedbackDuration === "number" ? params.feedbackDuration : 2e3;
|
|
38
|
-
element.addEventListener("click", async () => {
|
|
39
|
-
let copyText;
|
|
40
|
-
if (params.text != null) {
|
|
41
|
-
copyText = String(params.text);
|
|
42
|
-
} else {
|
|
43
|
-
const sourceEl = resolveElement(element, params.source) || element;
|
|
44
|
-
copyText = sourceEl.value ?? sourceEl.textContent ?? "";
|
|
45
|
-
}
|
|
46
|
-
try {
|
|
47
|
-
await copyToClipboard(copyText);
|
|
48
|
-
const feedbackEl = resolveElement(element, params.feedback) || element;
|
|
49
|
-
feedbackEl.classList.add("copied");
|
|
50
|
-
setTimeout(() => feedbackEl.classList.remove("copied"), feedbackDuration);
|
|
51
|
-
element.dispatchEvent(
|
|
52
|
-
new CustomEvent("clipboard:copied", {
|
|
53
|
-
bubbles: true,
|
|
54
|
-
detail: { text: copyText }
|
|
55
|
-
})
|
|
56
|
-
);
|
|
57
|
-
} catch (error) {
|
|
58
|
-
element.dispatchEvent(
|
|
59
|
-
new CustomEvent("clipboard:error", {
|
|
60
|
-
bubbles: true,
|
|
61
|
-
detail: { error }
|
|
62
|
-
})
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
async function registerClipboard(hyperfixi) {
|
|
68
|
-
const hf = hyperfixi || resolveRuntime();
|
|
69
|
-
if (!hf) {
|
|
70
|
-
throw new Error(
|
|
71
|
-
"LokaScript not found. Make sure @hyperfixi/core is loaded before registering behaviors."
|
|
72
|
-
);
|
|
73
|
-
}
|
|
74
|
-
const syntheticNode = {
|
|
75
|
-
type: "behavior",
|
|
76
|
-
name: "Clipboard",
|
|
77
|
-
parameters: ["text", "source", "feedback", "feedbackDuration"],
|
|
78
|
-
eventHandlers: [],
|
|
79
|
-
imperativeInstaller: installClipboard
|
|
80
|
-
};
|
|
81
|
-
const ctx = hf.createContext ? hf.createContext() : { locals: /* @__PURE__ */ new Map(), globals: /* @__PURE__ */ new Map() };
|
|
82
|
-
await hf.execute(syntheticNode, ctx);
|
|
83
|
-
}
|
|
84
|
-
if (resolveRuntime()) {
|
|
85
|
-
registerClipboard().catch(console.error);
|
|
86
|
-
}
|
|
87
|
-
var clipboard_default = {
|
|
88
|
-
source: clipboardSchema.source,
|
|
89
|
-
metadata: clipboardSchema,
|
|
90
|
-
register: registerClipboard
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
export {
|
|
94
|
-
clipboardSource,
|
|
95
|
-
clipboardMetadata,
|
|
96
|
-
registerClipboard,
|
|
97
|
-
clipboard_default
|
|
98
|
-
};
|
|
99
|
-
//# sourceMappingURL=chunk-7O7UOSBH.js.map
|