@colletdev/core 0.1.3
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 +77 -0
- package/custom-elements.json +6037 -0
- package/generated/.gitattributes +2 -0
- package/generated/index.d.ts +120 -0
- package/generated/index.js +521 -0
- package/generated/styles.js +2845 -0
- package/package.json +56 -0
- package/src/elements/accordion.d.ts +20 -0
- package/src/elements/accordion.js +92 -0
- package/src/elements/activity_group.d.ts +19 -0
- package/src/elements/activity_group.js +27 -0
- package/src/elements/alert.d.ts +24 -0
- package/src/elements/alert.js +40 -0
- package/src/elements/autocomplete.d.ts +30 -0
- package/src/elements/autocomplete.js +671 -0
- package/src/elements/avatar.d.ts +18 -0
- package/src/elements/avatar.js +28 -0
- package/src/elements/backdrop.d.ts +14 -0
- package/src/elements/backdrop.js +28 -0
- package/src/elements/badge.d.ts +21 -0
- package/src/elements/badge.js +42 -0
- package/src/elements/breadcrumb.d.ts +17 -0
- package/src/elements/breadcrumb.js +41 -0
- package/src/elements/button.d.ts +24 -0
- package/src/elements/button.js +36 -0
- package/src/elements/card.d.ts +21 -0
- package/src/elements/card.js +67 -0
- package/src/elements/carousel.d.ts +23 -0
- package/src/elements/carousel.js +895 -0
- package/src/elements/chat_input.d.ts +22 -0
- package/src/elements/chat_input.js +78 -0
- package/src/elements/checkbox.d.ts +21 -0
- package/src/elements/checkbox.js +114 -0
- package/src/elements/code_block.d.ts +21 -0
- package/src/elements/code_block.js +27 -0
- package/src/elements/collapsible.d.ts +20 -0
- package/src/elements/collapsible.js +93 -0
- package/src/elements/date_picker.d.ts +30 -0
- package/src/elements/date_picker.js +528 -0
- package/src/elements/dialog.d.ts +20 -0
- package/src/elements/dialog.js +314 -0
- package/src/elements/drawer.d.ts +20 -0
- package/src/elements/drawer.js +318 -0
- package/src/elements/fab.d.ts +22 -0
- package/src/elements/fab.js +36 -0
- package/src/elements/file_upload.d.ts +26 -0
- package/src/elements/file_upload.js +59 -0
- package/src/elements/listbox.d.ts +19 -0
- package/src/elements/listbox.js +250 -0
- package/src/elements/menu.d.ts +20 -0
- package/src/elements/menu.js +224 -0
- package/src/elements/message_bubble.d.ts +23 -0
- package/src/elements/message_bubble.js +29 -0
- package/src/elements/message_group.d.ts +18 -0
- package/src/elements/message_group.js +28 -0
- package/src/elements/message_part.d.ts +35 -0
- package/src/elements/message_part.js +153 -0
- package/src/elements/pagination.d.ts +22 -0
- package/src/elements/pagination.js +36 -0
- package/src/elements/popover.d.ts +26 -0
- package/src/elements/popover.js +191 -0
- package/src/elements/profile_menu.d.ts +20 -0
- package/src/elements/profile_menu.js +213 -0
- package/src/elements/progress.d.ts +18 -0
- package/src/elements/progress.js +31 -0
- package/src/elements/radio_group.d.ts +22 -0
- package/src/elements/radio_group.js +70 -0
- package/src/elements/scrollbar.d.ts +19 -0
- package/src/elements/scrollbar.js +299 -0
- package/src/elements/search_bar.d.ts +27 -0
- package/src/elements/search_bar.js +98 -0
- package/src/elements/select.d.ts +26 -0
- package/src/elements/select.js +485 -0
- package/src/elements/sidebar.d.ts +21 -0
- package/src/elements/sidebar.js +322 -0
- package/src/elements/skeleton.d.ts +17 -0
- package/src/elements/skeleton.js +31 -0
- package/src/elements/slider.d.ts +28 -0
- package/src/elements/slider.js +93 -0
- package/src/elements/speed_dial.d.ts +23 -0
- package/src/elements/speed_dial.js +370 -0
- package/src/elements/spinner.d.ts +15 -0
- package/src/elements/spinner.js +28 -0
- package/src/elements/split_button.d.ts +23 -0
- package/src/elements/split_button.js +281 -0
- package/src/elements/stepper.d.ts +20 -0
- package/src/elements/stepper.js +31 -0
- package/src/elements/switch.d.ts +22 -0
- package/src/elements/switch.js +129 -0
- package/src/elements/table.d.ts +29 -0
- package/src/elements/table.js +371 -0
- package/src/elements/tabs.d.ts +19 -0
- package/src/elements/tabs.js +139 -0
- package/src/elements/text.d.ts +26 -0
- package/src/elements/text.js +32 -0
- package/src/elements/text_input.d.ts +36 -0
- package/src/elements/text_input.js +121 -0
- package/src/elements/thinking.d.ts +17 -0
- package/src/elements/thinking.js +28 -0
- package/src/elements/toast.d.ts +23 -0
- package/src/elements/toast.js +209 -0
- package/src/elements/toggle_group.d.ts +22 -0
- package/src/elements/toggle_group.js +176 -0
- package/src/elements/tooltip.d.ts +18 -0
- package/src/elements/tooltip.js +64 -0
- package/src/markdown.d.ts +24 -0
- package/src/markdown.js +66 -0
- package/src/runtime.d.ts +35 -0
- package/src/runtime.js +790 -0
- package/src/server.d.ts +69 -0
- package/src/server.js +176 -0
- package/src/streaming-markdown.js +43 -0
- package/src/vite-plugin.d.ts +46 -0
- package/src/vite-plugin.js +221 -0
- package/wasm/package.json +16 -0
- package/wasm/wasm_api.d.ts +72 -0
- package/wasm/wasm_api.js +593 -0
- package/wasm/wasm_api_bg.wasm +0 -0
- package/wasm/wasm_api_bg.wasm.d.ts +10 -0
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
// Custom behavior for <cx-sidebar> — nav item click, group toggle, mobile drawer.
|
|
2
|
+
// Mirrors static/_behaviors/sidebar.js but operates inside shadow DOM.
|
|
3
|
+
// Includes full drawer open/close for the mobile hamburger menu because the
|
|
4
|
+
// Shadow DOM boundary prevents the separate dialog.js behavior from finding
|
|
5
|
+
// the drawer via document.getElementById().
|
|
6
|
+
// Source: crates/wasm-api/src/sidebar.rs
|
|
7
|
+
|
|
8
|
+
// ─── Animation Constants (matches drawer.js design tokens) ───
|
|
9
|
+
|
|
10
|
+
const OFF_SCREEN = {
|
|
11
|
+
right: 'translateX(100%)',
|
|
12
|
+
left: 'translateX(-100%)',
|
|
13
|
+
top: 'translateY(-100%)',
|
|
14
|
+
bottom: 'translateY(100%)',
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const ENTER_DURATION = 400;
|
|
18
|
+
const ENTER_EASING = 'cubic-bezier(0.2, 0, 0, 1)'; // --ease-snappy
|
|
19
|
+
const EXIT_DURATION = 250;
|
|
20
|
+
const EXIT_EASING = 'cubic-bezier(0.4, 0, 1, 1)';
|
|
21
|
+
const BACKDROP_ENTER_DURATION = 300;
|
|
22
|
+
const BACKDROP_EASING = 'ease-out';
|
|
23
|
+
|
|
24
|
+
// ─── Static Stylesheet (dialog backdrop override) ───
|
|
25
|
+
|
|
26
|
+
let _sheet;
|
|
27
|
+
function getSheet() {
|
|
28
|
+
if (!_sheet) {
|
|
29
|
+
_sheet = new CSSStyleSheet();
|
|
30
|
+
_sheet.replaceSync([
|
|
31
|
+
'dialog[data-dialog]::backdrop {',
|
|
32
|
+
' background: transparent !important;',
|
|
33
|
+
' backdrop-filter: none !important;',
|
|
34
|
+
' -webkit-backdrop-filter: none !important;',
|
|
35
|
+
'}',
|
|
36
|
+
'[data-dialog-panel] { position: relative; z-index: 1; }',
|
|
37
|
+
].join('\n'));
|
|
38
|
+
}
|
|
39
|
+
return _sheet;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function defineCxSidebar(wasmFn, baseClass) {
|
|
43
|
+
class CxSidebar extends baseClass {
|
|
44
|
+
static observedAttributes = ['id', 'label', 'groups', 'separators-after', 'side', 'state', 'shape', 'size'];
|
|
45
|
+
static _booleanAttrs = new Set([]);
|
|
46
|
+
|
|
47
|
+
connectedCallback() {
|
|
48
|
+
if (!this._isInitialized) {
|
|
49
|
+
this._markInitialized();
|
|
50
|
+
const shadow = this._shadow;
|
|
51
|
+
|
|
52
|
+
// Adopt stylesheet for dialog ::backdrop override
|
|
53
|
+
const sheet = getSheet();
|
|
54
|
+
if (!shadow.adoptedStyleSheets.includes(sheet)) {
|
|
55
|
+
shadow.adoptedStyleSheets = [...shadow.adoptedStyleSheets, sheet];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ─── Click Delegation ───
|
|
59
|
+
shadow.addEventListener('click', (e) => {
|
|
60
|
+
// Mobile hamburger trigger → open drawer
|
|
61
|
+
const dialogTrigger = e.target.closest('[data-dialog-trigger]');
|
|
62
|
+
if (dialogTrigger) {
|
|
63
|
+
const targetId = dialogTrigger.getAttribute('data-dialog-target');
|
|
64
|
+
if (targetId) {
|
|
65
|
+
const dialog = shadow.getElementById(targetId);
|
|
66
|
+
if (dialog) this.#openDrawer(dialog);
|
|
67
|
+
}
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Drawer close button
|
|
72
|
+
if (e.target.closest('[data-dialog-close]')) {
|
|
73
|
+
this.#closeDrawer();
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Drawer backdrop click (click on dialog element itself, not children)
|
|
78
|
+
const dialog = shadow.querySelector('dialog[data-dialog]');
|
|
79
|
+
if (dialog && dialog.open && e.target === dialog) {
|
|
80
|
+
this.#closeDrawer();
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Nav item click
|
|
85
|
+
const item = e.target.closest('[data-sidebar-item]');
|
|
86
|
+
if (item && !item.hasAttribute('aria-disabled')) {
|
|
87
|
+
const label = item.getAttribute('data-sidebar-label') || '';
|
|
88
|
+
const href = item.getAttribute('href') || '';
|
|
89
|
+
// Mark active across both desktop and mobile nav
|
|
90
|
+
shadow.querySelectorAll('[data-sidebar-item]').forEach(el => {
|
|
91
|
+
el.removeAttribute('data-active');
|
|
92
|
+
el.removeAttribute('aria-current');
|
|
93
|
+
});
|
|
94
|
+
item.setAttribute('data-active', '');
|
|
95
|
+
item.setAttribute('aria-current', 'page');
|
|
96
|
+
this._emit('cx-navigate', { label, href });
|
|
97
|
+
// Close mobile drawer if open
|
|
98
|
+
this.#closeDrawer();
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Collapsible group trigger
|
|
103
|
+
const groupTrigger = e.target.closest('[data-sidebar-group-trigger]');
|
|
104
|
+
if (groupTrigger) {
|
|
105
|
+
const expanded = groupTrigger.getAttribute('aria-expanded') === 'true';
|
|
106
|
+
const newExpanded = !expanded;
|
|
107
|
+
groupTrigger.setAttribute('aria-expanded', String(newExpanded));
|
|
108
|
+
const panelId = groupTrigger.getAttribute('aria-controls');
|
|
109
|
+
if (panelId) {
|
|
110
|
+
const panel = shadow.getElementById(panelId);
|
|
111
|
+
if (panel) {
|
|
112
|
+
if (newExpanded) {
|
|
113
|
+
panel.removeAttribute('data-collapsed');
|
|
114
|
+
} else {
|
|
115
|
+
panel.setAttribute('data-collapsed', '');
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// Sync collapsed group IDs to _props for re-render survival
|
|
120
|
+
const collapsedIds = [];
|
|
121
|
+
shadow.querySelectorAll('[data-sidebar-group-trigger][aria-expanded="false"]').forEach(t => {
|
|
122
|
+
const label = t.textContent.trim();
|
|
123
|
+
if (label) collapsedIds.push(label);
|
|
124
|
+
});
|
|
125
|
+
this._props._collapsed_groups = collapsedIds.join(',');
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Toggle sidebar state (expand/narrow)
|
|
130
|
+
const toggle = e.target.closest('[data-sidebar-toggle]');
|
|
131
|
+
if (toggle) {
|
|
132
|
+
const sidebar = shadow.querySelector('[data-sidebar]');
|
|
133
|
+
if (sidebar) {
|
|
134
|
+
const state = sidebar.getAttribute('data-sidebar-state') || 'expanded';
|
|
135
|
+
const next = state === 'expanded' ? 'narrow' : 'expanded';
|
|
136
|
+
sidebar.setAttribute('data-sidebar-state', next);
|
|
137
|
+
sidebar.style.setProperty('--sidebar-width', next === 'narrow' ? '4rem' : '16rem');
|
|
138
|
+
// Sync host prop — single source of truth for WASM re-renders.
|
|
139
|
+
this._props.state = next;
|
|
140
|
+
this._emit('cx-toggle', { state: next });
|
|
141
|
+
}
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// ─── Keyboard ───
|
|
147
|
+
shadow.addEventListener('keydown', (e) => {
|
|
148
|
+
if (e.key === 'Escape') {
|
|
149
|
+
// If drawer is open, close it first
|
|
150
|
+
const dialog = shadow.querySelector('dialog[data-dialog]');
|
|
151
|
+
if (dialog && dialog.open) {
|
|
152
|
+
e.preventDefault();
|
|
153
|
+
this.#closeDrawer();
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
// Otherwise collapse open group
|
|
157
|
+
const group = e.target.closest('[data-sidebar-group]');
|
|
158
|
+
if (group) {
|
|
159
|
+
const btn = group.querySelector('[data-sidebar-group-trigger]');
|
|
160
|
+
if (btn && btn.getAttribute('aria-expanded') === 'true') {
|
|
161
|
+
btn.setAttribute('aria-expanded', 'false');
|
|
162
|
+
const panelId = btn.getAttribute('aria-controls');
|
|
163
|
+
if (panelId) {
|
|
164
|
+
const panel = shadow.getElementById(panelId);
|
|
165
|
+
if (panel) panel.setAttribute('data-collapsed', '');
|
|
166
|
+
}
|
|
167
|
+
// Sync collapsed group IDs to _props for re-render survival
|
|
168
|
+
const collapsedIds = [];
|
|
169
|
+
shadow.querySelectorAll('[data-sidebar-group-trigger][aria-expanded="false"]').forEach(t => {
|
|
170
|
+
const label = t.textContent.trim();
|
|
171
|
+
if (label) collapsedIds.push(label);
|
|
172
|
+
});
|
|
173
|
+
this._props._collapsed_groups = collapsedIds.join(',');
|
|
174
|
+
btn.focus();
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
// Prevent native dialog cancel (would close without animation)
|
|
181
|
+
shadow.addEventListener('cancel', (e) => {
|
|
182
|
+
e.preventDefault();
|
|
183
|
+
this.#closeDrawer();
|
|
184
|
+
});
|
|
185
|
+
} // end _isInitialized guard
|
|
186
|
+
super.connectedCallback();
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
disconnectedCallback() {
|
|
190
|
+
this._unlockScroll();
|
|
191
|
+
super.disconnectedCallback();
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// ─── Overlay Management ───
|
|
195
|
+
|
|
196
|
+
#ensureOverlay(dialog) {
|
|
197
|
+
if (dialog.querySelector('[data-cx-overlay]')) return;
|
|
198
|
+
const el = document.createElement('div');
|
|
199
|
+
el.setAttribute('data-cx-overlay', '');
|
|
200
|
+
Object.assign(el.style, {
|
|
201
|
+
position: 'fixed',
|
|
202
|
+
inset: '0',
|
|
203
|
+
backgroundColor: 'oklch(0 0 0 / 0.3)',
|
|
204
|
+
backdropFilter: 'blur(4px)',
|
|
205
|
+
WebkitBackdropFilter: 'blur(4px)',
|
|
206
|
+
pointerEvents: 'none',
|
|
207
|
+
zIndex: '0',
|
|
208
|
+
opacity: '0',
|
|
209
|
+
});
|
|
210
|
+
dialog.prepend(el);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// ─── Open Drawer ───
|
|
214
|
+
|
|
215
|
+
#openDrawer(dialog) {
|
|
216
|
+
if (!dialog || dialog.open) return;
|
|
217
|
+
|
|
218
|
+
this.#ensureOverlay(dialog);
|
|
219
|
+
dialog.showModal();
|
|
220
|
+
this._lockScroll();
|
|
221
|
+
|
|
222
|
+
// rAF: dialog must be composited in top layer before animation
|
|
223
|
+
requestAnimationFrame(() => {
|
|
224
|
+
const panel = dialog.querySelector('[data-dialog-panel]');
|
|
225
|
+
const overlay = dialog.querySelector('[data-cx-overlay]');
|
|
226
|
+
const side = dialog.getAttribute('data-drawer') || 'left';
|
|
227
|
+
const offscreen = OFF_SCREEN[side] || OFF_SCREEN.left;
|
|
228
|
+
const reducedMotion = window.matchMedia?.('(prefers-reduced-motion: reduce)').matches;
|
|
229
|
+
|
|
230
|
+
if (panel) {
|
|
231
|
+
panel.animate(
|
|
232
|
+
[{ transform: offscreen }, { transform: 'none' }],
|
|
233
|
+
{ duration: reducedMotion ? 0 : ENTER_DURATION, easing: ENTER_EASING, fill: 'forwards' }
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (overlay) {
|
|
238
|
+
overlay.animate(
|
|
239
|
+
[{ opacity: 0 }, { opacity: 1 }],
|
|
240
|
+
{ duration: reducedMotion ? 0 : BACKDROP_ENTER_DURATION, easing: BACKDROP_EASING, fill: 'forwards' }
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
dialog.setAttribute('data-open', '');
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// ─── Close Drawer ───
|
|
249
|
+
|
|
250
|
+
#closeDrawer() {
|
|
251
|
+
const dialog = this._shadow.querySelector('dialog[data-dialog]');
|
|
252
|
+
if (!dialog || !dialog.open) return;
|
|
253
|
+
if (dialog.hasAttribute('data-closing')) return;
|
|
254
|
+
|
|
255
|
+
dialog.setAttribute('data-closing', '');
|
|
256
|
+
dialog.removeAttribute('data-open');
|
|
257
|
+
|
|
258
|
+
const panel = dialog.querySelector('[data-dialog-panel]');
|
|
259
|
+
const overlay = dialog.querySelector('[data-cx-overlay]');
|
|
260
|
+
const side = dialog.getAttribute('data-drawer') || 'left';
|
|
261
|
+
const offscreen = OFF_SCREEN[side] || OFF_SCREEN.left;
|
|
262
|
+
const reducedMotion = window.matchMedia?.('(prefers-reduced-motion: reduce)').matches;
|
|
263
|
+
const dur = reducedMotion ? 0 : EXIT_DURATION;
|
|
264
|
+
|
|
265
|
+
const cleanup = () => {
|
|
266
|
+
dialog.removeAttribute('data-closing');
|
|
267
|
+
dialog.close();
|
|
268
|
+
this._unlockScroll();
|
|
269
|
+
this._emit('cx-close', {});
|
|
270
|
+
// Return focus to hamburger trigger
|
|
271
|
+
const trigger = this._shadow.querySelector('[data-dialog-trigger]');
|
|
272
|
+
if (trigger) trigger.focus();
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
if (overlay) {
|
|
276
|
+
overlay.animate(
|
|
277
|
+
[{ opacity: 1 }, { opacity: 0 }],
|
|
278
|
+
{ duration: dur, easing: EXIT_EASING, fill: 'forwards' }
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (panel) {
|
|
283
|
+
const anim = panel.animate(
|
|
284
|
+
[{ transform: 'none' }, { transform: offscreen }],
|
|
285
|
+
{ duration: dur, easing: EXIT_EASING, fill: 'forwards' }
|
|
286
|
+
);
|
|
287
|
+
anim.finished.then(cleanup).catch(cleanup);
|
|
288
|
+
} else {
|
|
289
|
+
cleanup();
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// ── Public imperative API ──
|
|
294
|
+
open() { this.#openDrawer(this._shadow.querySelector('dialog[data-dialog]')); }
|
|
295
|
+
close() { this.#closeDrawer(); }
|
|
296
|
+
|
|
297
|
+
// ─── Render ───
|
|
298
|
+
|
|
299
|
+
_doRender() {
|
|
300
|
+
try {
|
|
301
|
+
this._props.slotted = true;
|
|
302
|
+
const result = wasmFn(this._props);
|
|
303
|
+
this._injectHtml(result);
|
|
304
|
+
|
|
305
|
+
// Re-adopt stylesheet (may be stripped by base _scheduleRender)
|
|
306
|
+
const sheet = getSheet();
|
|
307
|
+
if (!this._shadow.adoptedStyleSheets.includes(sheet)) {
|
|
308
|
+
this._shadow.adoptedStyleSheets = [...this._shadow.adoptedStyleSheets, sheet];
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Inject overlay into drawer dialog (destroyed by innerHTML, re-created)
|
|
312
|
+
const dialog = this._shadow.querySelector('dialog[data-dialog]');
|
|
313
|
+
if (dialog) this.#ensureOverlay(dialog);
|
|
314
|
+
} catch (e) {
|
|
315
|
+
console.error('[cx-sidebar]', e);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
customElements.define('cx-sidebar', CxSidebar);
|
|
321
|
+
return CxSidebar;
|
|
322
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Auto-generated by scripts/generate-elements.mjs — DO NOT EDIT
|
|
2
|
+
// Source: crates/wasm-api/src/skeleton.rs
|
|
3
|
+
|
|
4
|
+
export interface CxSkeletonAttributes {
|
|
5
|
+
id?: string;
|
|
6
|
+
variant?: 'text' | 'circle' | 'rectangular';
|
|
7
|
+
animation?: 'pulse' | 'wave';
|
|
8
|
+
label?: string;
|
|
9
|
+
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
10
|
+
lines?: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
declare global {
|
|
14
|
+
interface HTMLElementTagNameMap {
|
|
15
|
+
'cx-skeleton': HTMLElement & CxSkeletonAttributes;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// Auto-generated by scripts/generate-elements.mjs — DO NOT EDIT
|
|
2
|
+
// Source: crates/wasm-api/src/skeleton.rs
|
|
3
|
+
|
|
4
|
+
export function defineCxSkeleton(wasmFn, baseClass) {
|
|
5
|
+
class CxSkeleton extends baseClass {
|
|
6
|
+
static observedAttributes = ['id', 'variant', 'animation', 'label', 'size', 'lines'];
|
|
7
|
+
static _booleanAttrs = new Set([]);
|
|
8
|
+
static _numericAttrs = new Set(['lines']);
|
|
9
|
+
static _focusable = false;
|
|
10
|
+
static _hostDisplay = 'block';
|
|
11
|
+
|
|
12
|
+
set lines(v) { this._setProp('lines', v); }
|
|
13
|
+
get lines() { return this._props.lines; }
|
|
14
|
+
|
|
15
|
+
connectedCallback() {
|
|
16
|
+
super.connectedCallback();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
_doRender() {
|
|
20
|
+
try {
|
|
21
|
+
const result = wasmFn(this._props);
|
|
22
|
+
this._injectHtml(result);
|
|
23
|
+
} catch (e) {
|
|
24
|
+
console.error('[cx-skeleton]', e);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
customElements.define('cx-skeleton', CxSkeleton);
|
|
30
|
+
return CxSkeleton;
|
|
31
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Auto-generated by scripts/generate-elements.mjs — DO NOT EDIT
|
|
2
|
+
// Source: crates/wasm-api/src/slider.rs
|
|
3
|
+
|
|
4
|
+
export interface CxSliderAttributes {
|
|
5
|
+
id?: string;
|
|
6
|
+
label?: string;
|
|
7
|
+
ariaLabel?: string;
|
|
8
|
+
value?: number;
|
|
9
|
+
min?: number;
|
|
10
|
+
max?: number;
|
|
11
|
+
step?: number;
|
|
12
|
+
orientation?: 'horizontal' | 'vertical';
|
|
13
|
+
shape?: 'sharp' | 'rounded' | 'pill';
|
|
14
|
+
intent?: 'neutral' | 'primary' | 'info' | 'success' | 'warning' | 'danger';
|
|
15
|
+
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
16
|
+
showValue?: boolean;
|
|
17
|
+
valueText?: string;
|
|
18
|
+
helperText?: string;
|
|
19
|
+
errorText?: string;
|
|
20
|
+
disabled?: boolean;
|
|
21
|
+
unlabeled?: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
declare global {
|
|
25
|
+
interface HTMLElementTagNameMap {
|
|
26
|
+
'cx-slider': HTMLElement & CxSliderAttributes;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// Auto-generated by scripts/generate-elements.mjs — DO NOT EDIT
|
|
2
|
+
// Source: crates/wasm-api/src/slider.rs
|
|
3
|
+
|
|
4
|
+
export function defineCxSlider(wasmFn, baseClass) {
|
|
5
|
+
class CxSlider extends baseClass {
|
|
6
|
+
static observedAttributes = ['id', 'label', 'aria-label', 'value', 'min', 'max', 'step', 'orientation', 'shape', 'intent', 'size', 'show-value', 'value-text', 'helper-text', 'error-text', 'disabled', 'unlabeled'];
|
|
7
|
+
static _booleanAttrs = new Set(['show-value', 'disabled', 'unlabeled']);
|
|
8
|
+
static _numericAttrs = new Set(['value', 'min', 'max', 'step']);
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
// Sync the fill bar (--slider-percent CSS var) + value display text
|
|
12
|
+
#syncVisual(input) {
|
|
13
|
+
if (!input) return;
|
|
14
|
+
const min = parseFloat(input.min) || 0;
|
|
15
|
+
const max = parseFloat(input.max) || 100;
|
|
16
|
+
const val = parseFloat(input.value) || 0;
|
|
17
|
+
const range = max - min;
|
|
18
|
+
const pct = range > 0 ? ((val - min) / range) * 100 : 0;
|
|
19
|
+
input.style.setProperty('--slider-percent', String(Math.max(0, Math.min(100, pct))));
|
|
20
|
+
// Update value display text
|
|
21
|
+
const display = this._shadow.querySelector('[data-slider-value]');
|
|
22
|
+
if (display) display.textContent = val % 1 === 0 ? String(val) : val.toFixed(2);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
connectedCallback() {
|
|
26
|
+
if (!this._isInitialized) {
|
|
27
|
+
this._markInitialized();
|
|
28
|
+
// Delegated event listeners — attach once on shadow root
|
|
29
|
+
this._shadow.addEventListener('input', (e) => {
|
|
30
|
+
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') {
|
|
31
|
+
this._setFormValue(e.target.value);
|
|
32
|
+
this._emit('cx-input', { value: e.target.value });
|
|
33
|
+
// Sync fill bar on every input change (drag, keyboard, click)
|
|
34
|
+
this.#syncVisual(e.target);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
this._shadow.addEventListener('change', (e) => {
|
|
38
|
+
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' || e.target.tagName === 'SELECT') {
|
|
39
|
+
this._emit('cx-change', { value: e.target.value });
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// Forward focus events from inner interactive elements
|
|
44
|
+
this._shadow.addEventListener('focusin', (e) => {
|
|
45
|
+
this._emit('cx-focus', { relatedTarget: e.relatedTarget });
|
|
46
|
+
});
|
|
47
|
+
this._shadow.addEventListener('focusout', (e) => {
|
|
48
|
+
this._emit('cx-blur', { relatedTarget: e.relatedTarget });
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Forward keyboard events from inner interactive elements
|
|
52
|
+
this._shadow.addEventListener('keydown', (e) => {
|
|
53
|
+
this._emit('cx-keydown', { key: e.key, code: e.code, shiftKey: e.shiftKey, ctrlKey: e.ctrlKey, altKey: e.altKey, metaKey: e.metaKey });
|
|
54
|
+
});
|
|
55
|
+
this._shadow.addEventListener('keyup', (e) => {
|
|
56
|
+
this._emit('cx-keyup', { key: e.key, code: e.code, shiftKey: e.shiftKey, ctrlKey: e.ctrlKey, altKey: e.altKey, metaKey: e.metaKey });
|
|
57
|
+
});
|
|
58
|
+
} // end _isInitialized guard
|
|
59
|
+
super.connectedCallback();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// ── Public imperative API ──
|
|
63
|
+
focus() { const el = this._shadow.querySelector('input[type="range"]'); if (el) el.focus(); else super.focus(); }
|
|
64
|
+
|
|
65
|
+
_doRender() {
|
|
66
|
+
try {
|
|
67
|
+
const result = wasmFn(this._props);
|
|
68
|
+
this._injectHtml(result);
|
|
69
|
+
// Sync form value after render. Event delegation on shadow root
|
|
70
|
+
// avoids duplicate listeners (innerHTML replaces old DOM nodes,
|
|
71
|
+
// but shadow root persists — delegation handles new inputs).
|
|
72
|
+
const input = this._shadow.querySelector('input, textarea, select');
|
|
73
|
+
if (input) {
|
|
74
|
+
// Sync controlled value prop → internal input property.
|
|
75
|
+
// _injectHtml's focus-preservation restores the OLD typed value
|
|
76
|
+
// to maintain cursor position during re-renders. But when the
|
|
77
|
+
// value prop explicitly changes (e.g., clearing after submit),
|
|
78
|
+
// the controlled value must win.
|
|
79
|
+
if ('value' in this._props) input.value = this._props.value;
|
|
80
|
+
this._setFormValue(input.value || '');
|
|
81
|
+
}
|
|
82
|
+
// Sync fill bar after render
|
|
83
|
+
const rangeInput = this._shadow.querySelector('input[type="range"], input[data-slider]');
|
|
84
|
+
this.#syncVisual(rangeInput);
|
|
85
|
+
} catch (e) {
|
|
86
|
+
console.error('[cx-slider]', e);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
customElements.define('cx-slider', CxSlider);
|
|
92
|
+
return CxSlider;
|
|
93
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Auto-generated by scripts/generate-elements.mjs — DO NOT EDIT
|
|
2
|
+
// Source: crates/wasm-api/src/speed_dial.rs
|
|
3
|
+
|
|
4
|
+
export interface CxSpeedDialAttributes {
|
|
5
|
+
id: string;
|
|
6
|
+
icon: string;
|
|
7
|
+
ariaLabel?: string;
|
|
8
|
+
closeIcon?: string;
|
|
9
|
+
actions?: string;
|
|
10
|
+
variant?: 'filled' | 'outline' | 'ghost';
|
|
11
|
+
shape?: 'rounded' | 'pill';
|
|
12
|
+
size?: 'sm' | 'md' | 'lg';
|
|
13
|
+
direction?: 'up' | 'down' | 'left' | 'right';
|
|
14
|
+
backdrop?: boolean;
|
|
15
|
+
tooltips?: boolean;
|
|
16
|
+
disabled?: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
declare global {
|
|
20
|
+
interface HTMLElementTagNameMap {
|
|
21
|
+
'cx-speed-dial': HTMLElement & CxSpeedDialAttributes;
|
|
22
|
+
}
|
|
23
|
+
}
|