@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.
Files changed (119) hide show
  1. package/README.md +77 -0
  2. package/custom-elements.json +6037 -0
  3. package/generated/.gitattributes +2 -0
  4. package/generated/index.d.ts +120 -0
  5. package/generated/index.js +521 -0
  6. package/generated/styles.js +2845 -0
  7. package/package.json +56 -0
  8. package/src/elements/accordion.d.ts +20 -0
  9. package/src/elements/accordion.js +92 -0
  10. package/src/elements/activity_group.d.ts +19 -0
  11. package/src/elements/activity_group.js +27 -0
  12. package/src/elements/alert.d.ts +24 -0
  13. package/src/elements/alert.js +40 -0
  14. package/src/elements/autocomplete.d.ts +30 -0
  15. package/src/elements/autocomplete.js +671 -0
  16. package/src/elements/avatar.d.ts +18 -0
  17. package/src/elements/avatar.js +28 -0
  18. package/src/elements/backdrop.d.ts +14 -0
  19. package/src/elements/backdrop.js +28 -0
  20. package/src/elements/badge.d.ts +21 -0
  21. package/src/elements/badge.js +42 -0
  22. package/src/elements/breadcrumb.d.ts +17 -0
  23. package/src/elements/breadcrumb.js +41 -0
  24. package/src/elements/button.d.ts +24 -0
  25. package/src/elements/button.js +36 -0
  26. package/src/elements/card.d.ts +21 -0
  27. package/src/elements/card.js +67 -0
  28. package/src/elements/carousel.d.ts +23 -0
  29. package/src/elements/carousel.js +895 -0
  30. package/src/elements/chat_input.d.ts +22 -0
  31. package/src/elements/chat_input.js +78 -0
  32. package/src/elements/checkbox.d.ts +21 -0
  33. package/src/elements/checkbox.js +114 -0
  34. package/src/elements/code_block.d.ts +21 -0
  35. package/src/elements/code_block.js +27 -0
  36. package/src/elements/collapsible.d.ts +20 -0
  37. package/src/elements/collapsible.js +93 -0
  38. package/src/elements/date_picker.d.ts +30 -0
  39. package/src/elements/date_picker.js +528 -0
  40. package/src/elements/dialog.d.ts +20 -0
  41. package/src/elements/dialog.js +314 -0
  42. package/src/elements/drawer.d.ts +20 -0
  43. package/src/elements/drawer.js +318 -0
  44. package/src/elements/fab.d.ts +22 -0
  45. package/src/elements/fab.js +36 -0
  46. package/src/elements/file_upload.d.ts +26 -0
  47. package/src/elements/file_upload.js +59 -0
  48. package/src/elements/listbox.d.ts +19 -0
  49. package/src/elements/listbox.js +250 -0
  50. package/src/elements/menu.d.ts +20 -0
  51. package/src/elements/menu.js +224 -0
  52. package/src/elements/message_bubble.d.ts +23 -0
  53. package/src/elements/message_bubble.js +29 -0
  54. package/src/elements/message_group.d.ts +18 -0
  55. package/src/elements/message_group.js +28 -0
  56. package/src/elements/message_part.d.ts +35 -0
  57. package/src/elements/message_part.js +153 -0
  58. package/src/elements/pagination.d.ts +22 -0
  59. package/src/elements/pagination.js +36 -0
  60. package/src/elements/popover.d.ts +26 -0
  61. package/src/elements/popover.js +191 -0
  62. package/src/elements/profile_menu.d.ts +20 -0
  63. package/src/elements/profile_menu.js +213 -0
  64. package/src/elements/progress.d.ts +18 -0
  65. package/src/elements/progress.js +31 -0
  66. package/src/elements/radio_group.d.ts +22 -0
  67. package/src/elements/radio_group.js +70 -0
  68. package/src/elements/scrollbar.d.ts +19 -0
  69. package/src/elements/scrollbar.js +299 -0
  70. package/src/elements/search_bar.d.ts +27 -0
  71. package/src/elements/search_bar.js +98 -0
  72. package/src/elements/select.d.ts +26 -0
  73. package/src/elements/select.js +485 -0
  74. package/src/elements/sidebar.d.ts +21 -0
  75. package/src/elements/sidebar.js +322 -0
  76. package/src/elements/skeleton.d.ts +17 -0
  77. package/src/elements/skeleton.js +31 -0
  78. package/src/elements/slider.d.ts +28 -0
  79. package/src/elements/slider.js +93 -0
  80. package/src/elements/speed_dial.d.ts +23 -0
  81. package/src/elements/speed_dial.js +370 -0
  82. package/src/elements/spinner.d.ts +15 -0
  83. package/src/elements/spinner.js +28 -0
  84. package/src/elements/split_button.d.ts +23 -0
  85. package/src/elements/split_button.js +281 -0
  86. package/src/elements/stepper.d.ts +20 -0
  87. package/src/elements/stepper.js +31 -0
  88. package/src/elements/switch.d.ts +22 -0
  89. package/src/elements/switch.js +129 -0
  90. package/src/elements/table.d.ts +29 -0
  91. package/src/elements/table.js +371 -0
  92. package/src/elements/tabs.d.ts +19 -0
  93. package/src/elements/tabs.js +139 -0
  94. package/src/elements/text.d.ts +26 -0
  95. package/src/elements/text.js +32 -0
  96. package/src/elements/text_input.d.ts +36 -0
  97. package/src/elements/text_input.js +121 -0
  98. package/src/elements/thinking.d.ts +17 -0
  99. package/src/elements/thinking.js +28 -0
  100. package/src/elements/toast.d.ts +23 -0
  101. package/src/elements/toast.js +209 -0
  102. package/src/elements/toggle_group.d.ts +22 -0
  103. package/src/elements/toggle_group.js +176 -0
  104. package/src/elements/tooltip.d.ts +18 -0
  105. package/src/elements/tooltip.js +64 -0
  106. package/src/markdown.d.ts +24 -0
  107. package/src/markdown.js +66 -0
  108. package/src/runtime.d.ts +35 -0
  109. package/src/runtime.js +790 -0
  110. package/src/server.d.ts +69 -0
  111. package/src/server.js +176 -0
  112. package/src/streaming-markdown.js +43 -0
  113. package/src/vite-plugin.d.ts +46 -0
  114. package/src/vite-plugin.js +221 -0
  115. package/wasm/package.json +16 -0
  116. package/wasm/wasm_api.d.ts +72 -0
  117. package/wasm/wasm_api.js +593 -0
  118. package/wasm/wasm_api_bg.wasm +0 -0
  119. package/wasm/wasm_api_bg.wasm.d.ts +10 -0
@@ -0,0 +1,370 @@
1
+ // Custom behavior for <cx-speed-dial> — FAB trigger, icon morph, menu toggle, keyboard nav.
2
+ //
3
+ // The Rust component renders:
4
+ // <div data-speed-dial="{id}"> — container with directional flex
5
+ // <div data-speed-dial-backdrop> — optional overlay (hidden)
6
+ // <ul role="menu" data-speed-dial-menu> — action list (hidden)
7
+ // <li role="menuitem" data-action-id="{id}"> — each action
8
+ // <button data-speed-dial-trigger> — FAB button
9
+ // <span data-speed-dial-icon> — main icon (rotates 45deg on open)
10
+ // <span data-speed-dial-close-icon hidden> — swap icon (optional)
11
+ //
12
+ // This Custom Element wires up:
13
+ // - Click FAB to toggle menu open/close
14
+ // - Icon morph (45deg rotation or icon swap)
15
+ // - Backdrop show/hide
16
+ // - Staggered action reveal animation
17
+ // - Keyboard navigation (ArrowUp/Down, Home/End, Enter/Space, Escape)
18
+ // - Grace area timer (prevents accidental close on mouseleave)
19
+ // - cx-change with { open: bool }, cx-action with { id, label }
20
+ //
21
+ // Source: crates/wasm-api/src/speed_dial.rs
22
+
23
+ let _sheet;
24
+ function getSheet() {
25
+ if (!_sheet) {
26
+ _sheet = new CSSStyleSheet();
27
+ _sheet.replaceSync([
28
+ // Anchor for absolute positioning of menu
29
+ ':host { position: relative; display: inline-flex; }',
30
+ // Menu items start hidden for stagger animation
31
+ '[role="menuitem"] {',
32
+ ' transition: opacity 150ms ease-out, transform 150ms ease-out;',
33
+ '}',
34
+ // Backdrop covers viewport
35
+ '[data-speed-dial-backdrop] {',
36
+ ' transition: opacity 200ms ease-out;',
37
+ '}',
38
+ ].join('\n'));
39
+ }
40
+ return _sheet;
41
+ }
42
+
43
+ const GRACE_MS = 300;
44
+
45
+ export function defineCxSpeedDial(wasmFn, baseClass) {
46
+ class CxSpeedDial extends baseClass {
47
+ static observedAttributes = ['id', 'icon', 'aria-label', 'close-icon', 'actions', 'variant', 'shape', 'size', 'direction', 'backdrop', 'tooltips', 'disabled'];
48
+ static _booleanAttrs = new Set(['backdrop', 'tooltips', 'disabled']);
49
+
50
+ #graceTimer = null;
51
+ #outsideClick = null;
52
+
53
+ connectedCallback() {
54
+ const shadow = this._shadow;
55
+
56
+ const sheet = getSheet();
57
+ if (!shadow.adoptedStyleSheets.includes(sheet)) {
58
+ shadow.adoptedStyleSheets = [...shadow.adoptedStyleSheets, sheet];
59
+ }
60
+
61
+ if (!this._isInitialized) {
62
+ this._markInitialized();
63
+
64
+ // ── Click handler ──
65
+ shadow.addEventListener('click', (e) => {
66
+ // Backdrop click → close
67
+ if (e.target.closest('[data-speed-dial-backdrop]')) {
68
+ this.#close();
69
+ return;
70
+ }
71
+
72
+ // Trigger click → toggle
73
+ const trigger = e.target.closest('[data-speed-dial-trigger]');
74
+ if (trigger && !this._props.disabled) {
75
+ e.preventDefault();
76
+ this.#toggle();
77
+ return;
78
+ }
79
+
80
+ // Action item click → emit cx-action, close
81
+ const action = e.target.closest('[role="menuitem"]');
82
+ if (action && !action.hasAttribute('aria-disabled')) {
83
+ this._emit('cx-action', {
84
+ id: action.getAttribute('data-action-id') || action.id || '',
85
+ label: action.getAttribute('aria-label') || action.textContent.trim()
86
+ });
87
+ this.#close();
88
+ }
89
+ });
90
+
91
+ // ── Keyboard handler ──
92
+ shadow.addEventListener('keydown', (e) => this.#handleKey(e));
93
+
94
+ // ── Grace area: mouseleave / mouseenter ──
95
+ shadow.addEventListener('mouseleave', () => {
96
+ if (this.#isOpen()) {
97
+ this.#graceTimer = setTimeout(() => this.#close(), GRACE_MS);
98
+ }
99
+ });
100
+
101
+ shadow.addEventListener('mouseenter', () => {
102
+ if (this.#graceTimer) {
103
+ clearTimeout(this.#graceTimer);
104
+ this.#graceTimer = null;
105
+ }
106
+ });
107
+
108
+ // ── Click outside → close ──
109
+ this.#outsideClick = (e) => {
110
+ if (this.#isOpen() && !this.contains(e.target) && !this._shadow.contains(e.target)) {
111
+ this.#close();
112
+ }
113
+ };
114
+ document.addEventListener('mousedown', this.#outsideClick);
115
+ } // end _isInitialized guard
116
+
117
+ super.connectedCallback();
118
+ }
119
+
120
+ disconnectedCallback() {
121
+ if (this.#outsideClick) {
122
+ document.removeEventListener('mousedown', this.#outsideClick);
123
+ this.#outsideClick = null;
124
+ }
125
+ if (this.#graceTimer) {
126
+ clearTimeout(this.#graceTimer);
127
+ this.#graceTimer = null;
128
+ }
129
+ super.disconnectedCallback();
130
+ }
131
+
132
+ // ── DOM accessors ──
133
+
134
+ #getContainer() {
135
+ return this._shadow.querySelector('[data-speed-dial]');
136
+ }
137
+
138
+ #getTrigger() {
139
+ return this._shadow.querySelector('[data-speed-dial-trigger]');
140
+ }
141
+
142
+ #getMenu() {
143
+ return this._shadow.querySelector('[role="menu"]');
144
+ }
145
+
146
+ #getItems() {
147
+ return Array.from(
148
+ this._shadow.querySelectorAll('[role="menuitem"]:not([aria-disabled="true"])')
149
+ );
150
+ }
151
+
152
+ // ── Menu state ──
153
+
154
+ #isOpen() {
155
+ const trigger = this.#getTrigger();
156
+ return trigger ? trigger.getAttribute('aria-expanded') === 'true' : false;
157
+ }
158
+
159
+ #open() {
160
+ const trigger = this.#getTrigger();
161
+ const menu = this.#getMenu();
162
+ if (!trigger || !menu || this.#isOpen()) return;
163
+
164
+ // Clear grace timer — imperative open() must not be undone by a pending close
165
+ if (this.#graceTimer) {
166
+ clearTimeout(this.#graceTimer);
167
+ this.#graceTimer = null;
168
+ }
169
+
170
+ trigger.setAttribute('aria-expanded', 'true');
171
+ menu.setAttribute('data-open', '');
172
+ menu.classList.remove('hidden');
173
+ menu.style.display = 'flex';
174
+ menu.style.pointerEvents = 'auto';
175
+ menu.style.opacity = '1';
176
+
177
+ // Icon morph: rotate first icon span 45deg (plus → X)
178
+ const iconSpans = trigger.querySelectorAll('span[aria-hidden="true"]');
179
+ const iconEl = iconSpans.length ? iconSpans[0] : null;
180
+ if (iconEl) iconEl.style.transform = 'rotate(45deg)';
181
+
182
+ // Icon swap variant
183
+ const closeIcon = trigger.querySelector('[data-speed-dial-close-icon]');
184
+ if (closeIcon && iconEl) {
185
+ iconEl.classList.add('hidden');
186
+ closeIcon.classList.remove('hidden');
187
+ iconEl.style.transform = '';
188
+ }
189
+
190
+ // Backdrop
191
+ const backdrop = this._shadow.querySelector('[data-speed-dial-backdrop]');
192
+ if (backdrop) {
193
+ backdrop.setAttribute('data-open', '');
194
+ requestAnimationFrame(() => { backdrop.style.opacity = '1'; });
195
+ }
196
+
197
+ // Staggered action reveal
198
+ const actions = menu.querySelectorAll('[role="menuitem"]');
199
+ actions.forEach((a, i) => {
200
+ a.style.transitionDelay = `${i * 50}ms`;
201
+ a.style.opacity = '1';
202
+ a.style.transform = 'scale(1)';
203
+ });
204
+
205
+ this._emit('cx-change', { open: true });
206
+
207
+ // Focus first item
208
+ requestAnimationFrame(() => {
209
+ const items = this.#getItems();
210
+ if (items.length) items[0].focus();
211
+ });
212
+ }
213
+
214
+ #close() {
215
+ const trigger = this.#getTrigger();
216
+ const menu = this.#getMenu();
217
+ if (!trigger || !menu) return;
218
+
219
+ trigger.setAttribute('aria-expanded', 'false');
220
+
221
+ // Icon morph reset
222
+ const iconSpans = trigger.querySelectorAll('span[aria-hidden="true"]');
223
+ const iconEl = iconSpans.length ? iconSpans[0] : null;
224
+ if (iconEl) iconEl.style.transform = '';
225
+
226
+ // Icon swap reset
227
+ const closeIcon = trigger.querySelector('[data-speed-dial-close-icon]');
228
+ if (closeIcon && iconEl) {
229
+ iconEl.classList.remove('hidden');
230
+ closeIcon.classList.add('hidden');
231
+ }
232
+
233
+ // Backdrop
234
+ const backdrop = this._shadow.querySelector('[data-speed-dial-backdrop]');
235
+ if (backdrop) {
236
+ backdrop.style.opacity = '0';
237
+ setTimeout(() => { backdrop.removeAttribute('data-open'); }, 200);
238
+ }
239
+
240
+ // Collapse actions
241
+ const actions = menu.querySelectorAll('[role="menuitem"]');
242
+ actions.forEach(a => {
243
+ a.style.transitionDelay = '0ms';
244
+ a.style.opacity = '0';
245
+ a.style.transform = 'scale(0.3)';
246
+ });
247
+
248
+ menu.removeAttribute('data-open');
249
+ menu.classList.add('hidden');
250
+ menu.style.display = '';
251
+ menu.style.pointerEvents = '';
252
+ menu.style.opacity = '';
253
+
254
+ this._emit('cx-change', { open: false });
255
+ trigger.focus();
256
+ }
257
+
258
+ #toggle() {
259
+ if (this.#isOpen()) this.#close();
260
+ else this.#open();
261
+ }
262
+
263
+ // ── Keyboard navigation ──
264
+
265
+ #handleKey(e) {
266
+ // Trigger: Enter/Space toggle
267
+ const trigger = e.target.closest('[data-speed-dial-trigger]');
268
+ if (trigger) {
269
+ if (e.key === 'Enter' || e.key === ' ') {
270
+ e.preventDefault();
271
+ this.#toggle();
272
+ return;
273
+ }
274
+ // ArrowDown on trigger opens and focuses first item
275
+ if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
276
+ e.preventDefault();
277
+ if (!this.#isOpen()) this.#open();
278
+ return;
279
+ }
280
+ }
281
+
282
+ // Menu item navigation
283
+ const menuitem = e.target.closest('[role="menuitem"]');
284
+ if (!menuitem) return;
285
+
286
+ const items = this.#getItems();
287
+ const idx = items.indexOf(menuitem);
288
+ if (idx === -1) return;
289
+
290
+ const menu = this.#getMenu();
291
+ const orientation = menu?.getAttribute('aria-orientation') || 'vertical';
292
+
293
+ if (e.key === 'ArrowDown' || e.key === 'ArrowUp' ||
294
+ e.key === 'ArrowLeft' || e.key === 'ArrowRight') {
295
+ e.preventDefault();
296
+ const isNext = orientation === 'vertical'
297
+ ? (e.key === 'ArrowDown' || e.key === 'ArrowRight')
298
+ : (e.key === 'ArrowRight' || e.key === 'ArrowDown');
299
+ const ni = isNext
300
+ ? (idx + 1) % items.length
301
+ : (idx - 1 + items.length) % items.length;
302
+ items[ni].focus();
303
+ return;
304
+ }
305
+
306
+ if (e.key === 'Home') {
307
+ e.preventDefault();
308
+ if (items.length) items[0].focus();
309
+ return;
310
+ }
311
+
312
+ if (e.key === 'End') {
313
+ e.preventDefault();
314
+ if (items.length) items[items.length - 1].focus();
315
+ return;
316
+ }
317
+
318
+ if (e.key === 'Enter' || e.key === ' ') {
319
+ e.preventDefault();
320
+ if (!menuitem.hasAttribute('aria-disabled')) menuitem.click();
321
+ return;
322
+ }
323
+
324
+ if (e.key === 'Escape') {
325
+ e.preventDefault();
326
+ this.#close();
327
+ return;
328
+ }
329
+
330
+ if (e.key === 'Tab') {
331
+ this.#close();
332
+ }
333
+ }
334
+
335
+ // ── Public imperative API ──
336
+ open() { this.#open(); }
337
+ close() { this.#close(); }
338
+ toggle() { this.#toggle(); }
339
+
340
+ _doRender() {
341
+ try {
342
+ const wasOpen = this.#isOpen();
343
+
344
+ const result = wasmFn(this._props);
345
+ this._injectHtml(result);
346
+
347
+ const sheet = getSheet();
348
+ if (!this._shadow.adoptedStyleSheets.includes(sheet)) {
349
+ this._shadow.adoptedStyleSheets = [...this._shadow.adoptedStyleSheets, sheet];
350
+ }
351
+
352
+ // Initialize actions as collapsed (for stagger animation)
353
+ const menu = this.#getMenu();
354
+ if (menu) {
355
+ menu.querySelectorAll('[role="menuitem"]').forEach(a => {
356
+ a.style.opacity = '0';
357
+ a.style.transform = 'scale(0.3)';
358
+ });
359
+ }
360
+
361
+ if (wasOpen) this.#open();
362
+ } catch (e) {
363
+ console.error('[cx-speed-dial]', e);
364
+ }
365
+ }
366
+ }
367
+
368
+ customElements.define('cx-speed-dial', CxSpeedDial);
369
+ return CxSpeedDial;
370
+ }
@@ -0,0 +1,15 @@
1
+ // Auto-generated by scripts/generate-elements.mjs — DO NOT EDIT
2
+ // Source: crates/wasm-api/src/spinner.rs
3
+
4
+ export interface CxSpinnerAttributes {
5
+ id?: string;
6
+ variant?: 'circle' | 'square';
7
+ label?: string;
8
+ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
9
+ }
10
+
11
+ declare global {
12
+ interface HTMLElementTagNameMap {
13
+ 'cx-spinner': HTMLElement & CxSpinnerAttributes;
14
+ }
15
+ }
@@ -0,0 +1,28 @@
1
+ // Auto-generated by scripts/generate-elements.mjs — DO NOT EDIT
2
+ // Source: crates/wasm-api/src/spinner.rs
3
+
4
+ export function defineCxSpinner(wasmFn, baseClass) {
5
+ class CxSpinner extends baseClass {
6
+ static observedAttributes = ['id', 'variant', 'label', 'size'];
7
+ static _booleanAttrs = new Set([]);
8
+ static _focusable = false;
9
+ static _hostDisplay = 'inline-flex';
10
+
11
+
12
+ connectedCallback() {
13
+ super.connectedCallback();
14
+ }
15
+
16
+ _doRender() {
17
+ try {
18
+ const result = wasmFn(this._props);
19
+ this._injectHtml(result);
20
+ } catch (e) {
21
+ console.error('[cx-spinner]', e);
22
+ }
23
+ }
24
+ }
25
+
26
+ customElements.define('cx-spinner', CxSpinner);
27
+ return CxSpinner;
28
+ }
@@ -0,0 +1,23 @@
1
+ // Auto-generated by scripts/generate-elements.mjs — DO NOT EDIT
2
+ // Source: crates/wasm-api/src/split_button.rs
3
+
4
+ export interface CxSplitButtonAttributes {
5
+ id: string;
6
+ label: string;
7
+ entries?: string;
8
+ variant?: 'filled' | 'outline' | 'ghost';
9
+ intent?: 'neutral' | 'primary' | 'info' | 'success' | 'warning' | 'danger';
10
+ shape?: 'sharp' | 'rounded' | 'pill';
11
+ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
12
+ iconLeading?: string;
13
+ disabled?: boolean;
14
+ primaryDisabled?: boolean;
15
+ triggerDisabled?: boolean;
16
+ triggerLabel?: string;
17
+ }
18
+
19
+ declare global {
20
+ interface HTMLElementTagNameMap {
21
+ 'cx-split-button': HTMLElement & CxSplitButtonAttributes;
22
+ }
23
+ }