@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,2 @@
1
+ # Everything here is auto-generated. Edit the generators, not these files.
2
+ * linguist-generated=true
@@ -0,0 +1,120 @@
1
+ // Auto-generated by scripts/generate-elements.mjs — DO NOT EDIT
2
+ // TypeScript declarations for @colletdev/core main entry point.
3
+
4
+ import { CxElement, CxFormElement } from '../src/runtime.js';
5
+
6
+ /** All available component names (kebab-case, matching <cx-{name}> tags). */
7
+ export type ComponentName =
8
+ | 'accordion'
9
+ | 'activity-group'
10
+ | 'alert'
11
+ | 'autocomplete'
12
+ | 'avatar'
13
+ | 'backdrop'
14
+ | 'badge'
15
+ | 'breadcrumb'
16
+ | 'button'
17
+ | 'card'
18
+ | 'carousel'
19
+ | 'chat-input'
20
+ | 'checkbox'
21
+ | 'code-block'
22
+ | 'collapsible'
23
+ | 'date-picker'
24
+ | 'dialog'
25
+ | 'drawer'
26
+ | 'fab'
27
+ | 'file-upload'
28
+ | 'listbox'
29
+ | 'menu'
30
+ | 'message-bubble'
31
+ | 'message-group'
32
+ | 'message-part'
33
+ | 'pagination'
34
+ | 'popover'
35
+ | 'profile-menu'
36
+ | 'progress'
37
+ | 'radio-group'
38
+ | 'scrollbar'
39
+ | 'search-bar'
40
+ | 'select'
41
+ | 'sidebar'
42
+ | 'skeleton'
43
+ | 'slider'
44
+ | 'speed-dial'
45
+ | 'spinner'
46
+ | 'split-button'
47
+ | 'stepper'
48
+ | 'switch'
49
+ | 'table'
50
+ | 'tabs'
51
+ | 'text'
52
+ | 'text-input'
53
+ | 'thinking'
54
+ | 'toast'
55
+ | 'toggle-group'
56
+ | 'tooltip';
57
+
58
+ /** Options for `init()`. */
59
+ export interface InitOptions {
60
+ /** Base URL for all assets. Derives `{baseUrl}/tokens.css`, `{baseUrl}/cx-utilities.css`, and `{baseUrl}/wasm_api_bg.wasm`. */
61
+ baseUrl?: string;
62
+ /** Explicit URL for tokens.css (overrides baseUrl). */
63
+ tokensUrl?: string;
64
+ /** Explicit URL for cx-utilities.css (overrides baseUrl). */
65
+ utilitiesUrl?: string;
66
+ /** Explicit URL for the WASM binary (overrides baseUrl). */
67
+ wasmUrl?: string;
68
+ /**
69
+ * Register only these components (kebab-case names). Default: all.
70
+ *
71
+ * Enables tree-shaking — only the behavior JS for listed components is
72
+ * downloaded. Unlisted components never leave the server.
73
+ *
74
+ * @example init({ components: ['button', 'text-input', 'select'] })
75
+ */
76
+ components?: ComponentName[];
77
+ /**
78
+ * If true, WASM loads in background — init() returns after styles load.
79
+ * Elements render immediately when WASM is ready (no blank flash).
80
+ *
81
+ * Combine with `components` for maximum performance:
82
+ * @example init({ lazy: true, components: ['button', 'card'] })
83
+ */
84
+ lazy?: boolean;
85
+ }
86
+
87
+ /**
88
+ * Initialize Collet Custom Elements.
89
+ *
90
+ * Loads WASM + shared styles, then registers Custom Elements.
91
+ * Must be called before using any <cx-*> element.
92
+ *
93
+ * Auto-detect mode (default, no "components" option): scans the DOM for
94
+ * existing <cx-*> elements and registers only those. A MutationObserver then
95
+ * watches for new elements added later (route changes, lazy loads) and
96
+ * auto-registers them on-demand. Zero configuration, zero waste.
97
+ *
98
+ * FOUC prevention: injects :not(:defined) CSS immediately, hiding
99
+ * <cx-*> elements until their class is registered. No flash of empty content.
100
+ *
101
+ * Component behavior JS is loaded via dynamic import — only the components
102
+ * you use are downloaded. Bundlers (Vite, Webpack, Rollup) automatically
103
+ * code-split each component into its own chunk.
104
+ *
105
+ * @example
106
+ * // Zero-config — auto-detects from DOM + watches for new elements
107
+ * await init();
108
+ *
109
+ * // Selective — only 3 components, no auto-detection
110
+ * await init({ components: ['button', 'text-input', 'select'] });
111
+ *
112
+ * // Lazy + auto-detect — fastest possible first paint
113
+ * await init({ lazy: true });
114
+ */
115
+ export function init(options?: InitOptions): Promise<void>;
116
+
117
+ /** All available component names for selective registration. */
118
+ export const componentNames: readonly ComponentName[];
119
+
120
+ export { CxElement, CxFormElement };
@@ -0,0 +1,521 @@
1
+ // Auto-generated by scripts/generate-elements.mjs — DO NOT EDIT
2
+ // Main entry point for @colletdev/core Custom Elements.
3
+ //
4
+ // Usage:
5
+ // import { init } from '@colletdev/core';
6
+ // await init(); // all components (recommended)
7
+ // await init({ components: ['button', 'card'] }); // only load what you use
8
+ // await init({ lazy: true }); // non-blocking WASM
9
+ // await init({ lazy: true, components: ['button', 'card'] }); // both optimizations
10
+ // // <cx-*> elements are now registered and functional.
11
+ //
12
+ // Tree-shaking: component behavior JS is loaded via dynamic import().
13
+ // When using `components: [...]`, only the listed components' JS files
14
+ // are downloaded — the rest never leave the server. Bundlers (Vite,
15
+ // Webpack, Rollup) automatically code-split each component into its
16
+ // own chunk.
17
+ //
18
+ // LAZY LOADING: WASM binary (~893 KB), CSS strings (~173 KB), and WASM
19
+ // glue (~21 KB) are loaded via dynamic import() inside init() — NOT at
20
+ // module level. This means `import { init } from '@colletdev/core'`
21
+ // costs only ~4 KB. Everything else loads on-demand when init() is called.
22
+
23
+ import { initWasm, loadSharedStyles, loadInlineSharedStyles, loadMotionStyles, loadInlineMotionStyles, injectTokensToHead, injectFoucPrevention, CxElement, CxFormElement } from '../src/runtime.js';
24
+
25
+ // Package version — used for CDN fallback URL
26
+ const PKG_VERSION = '0.1.3';
27
+
28
+ // ─── Lazy WASM + CSS ───
29
+ // WASM glue and CSS strings are NOT imported at module level.
30
+ // They're loaded on first init() call via dynamic import(), which lets
31
+ // bundlers code-split them into separate chunks. The main entry point
32
+ // stays tiny (~4 KB) — the heavy assets only download when needed.
33
+ let _cx_render = null;
34
+ let _wasmInit = null;
35
+
36
+ async function _ensureWasm() {
37
+ if (!_cx_render) {
38
+ const wasm = await import('../wasm/wasm_api.js');
39
+ _wasmInit = wasm.default;
40
+ _cx_render = wasm.cx_render;
41
+ }
42
+ }
43
+
44
+ // Thin wrappers: cx_render dispatcher → per-component functions.
45
+ // Element definitions receive these as wasmFn(config) — the dispatcher
46
+ // is invisible to consumers. Same DX, 91 KB less WASM.
47
+ // The wrappers call _cx_render (populated by _ensureWasm in init).
48
+ const cx_accordion = (config) => _cx_render('accordion', config);
49
+ const cx_activity_group = (config) => _cx_render('activity_group', config);
50
+ const cx_alert = (config) => _cx_render('alert', config);
51
+ const cx_autocomplete = (config) => _cx_render('autocomplete', config);
52
+ const cx_avatar = (config) => _cx_render('avatar', config);
53
+ const cx_backdrop = (config) => _cx_render('backdrop', config);
54
+ const cx_badge = (config) => _cx_render('badge', config);
55
+ const cx_breadcrumb = (config) => _cx_render('breadcrumb', config);
56
+ const cx_button = (config) => _cx_render('button', config);
57
+ const cx_card = (config) => _cx_render('card', config);
58
+ const cx_carousel = (config) => _cx_render('carousel', config);
59
+ const cx_chat_input = (config) => _cx_render('chat_input', config);
60
+ const cx_checkbox = (config) => _cx_render('checkbox', config);
61
+ const cx_code_block = (config) => _cx_render('code_block', config);
62
+ const cx_collapsible = (config) => _cx_render('collapsible', config);
63
+ const cx_date_picker = (config) => _cx_render('date_picker', config);
64
+ const cx_dialog = (config) => _cx_render('dialog', config);
65
+ const cx_drawer = (config) => _cx_render('drawer', config);
66
+ const cx_fab = (config) => _cx_render('fab', config);
67
+ const cx_file_upload = (config) => _cx_render('file_upload', config);
68
+ const cx_listbox = (config) => _cx_render('listbox', config);
69
+ const cx_menu = (config) => _cx_render('menu', config);
70
+ const cx_message_bubble = (config) => _cx_render('message_bubble', config);
71
+ const cx_message_group = (config) => _cx_render('message_group', config);
72
+ const cx_message_part = (config) => _cx_render('message_part', config);
73
+ const cx_pagination = (config) => _cx_render('pagination', config);
74
+ const cx_popover = (config) => _cx_render('popover', config);
75
+ const cx_profile_menu = (config) => _cx_render('profile_menu', config);
76
+ const cx_progress = (config) => _cx_render('progress', config);
77
+ const cx_radio_group = (config) => _cx_render('radio_group', config);
78
+ const cx_scrollbar = (config) => _cx_render('scrollbar', config);
79
+ const cx_search_bar = (config) => _cx_render('search_bar', config);
80
+ const cx_select = (config) => _cx_render('select', config);
81
+ const cx_sidebar = (config) => _cx_render('sidebar', config);
82
+ const cx_skeleton = (config) => _cx_render('skeleton', config);
83
+ const cx_slider = (config) => _cx_render('slider', config);
84
+ const cx_speed_dial = (config) => _cx_render('speed_dial', config);
85
+ const cx_spinner = (config) => _cx_render('spinner', config);
86
+ const cx_split_button = (config) => _cx_render('split_button', config);
87
+ const cx_stepper = (config) => _cx_render('stepper', config);
88
+ const cx_switch = (config) => _cx_render('switch', config);
89
+ const cx_table = (config) => _cx_render('table', config);
90
+ const cx_tabs = (config) => _cx_render('tabs', config);
91
+ const cx_text = (config) => _cx_render('text', config);
92
+ const cx_text_input = (config) => _cx_render('text_input', config);
93
+ const cx_thinking = (config) => _cx_render('thinking', config);
94
+ const cx_toast = (config) => _cx_render('toast', config);
95
+ const cx_toggle_group = (config) => _cx_render('toggle_group', config);
96
+ const cx_tooltip = (config) => _cx_render('tooltip', config);
97
+
98
+ // Component registry — keyed by kebab-case name (matches <cx-{name}> tag).
99
+ // Each thunk dynamically imports its element definition file and calls
100
+ // customElements.define(). Only invoked components are downloaded.
101
+ const _registry = {
102
+ 'accordion': async () => {
103
+ const { defineCxAccordion } = await import('../src/elements/accordion.js');
104
+ defineCxAccordion(cx_accordion, CxElement);
105
+ },
106
+ 'activity-group': async () => {
107
+ const { defineCxActivityGroup } = await import('../src/elements/activity_group.js');
108
+ defineCxActivityGroup(cx_activity_group, CxElement);
109
+ },
110
+ 'alert': async () => {
111
+ const { defineCxAlert } = await import('../src/elements/alert.js');
112
+ defineCxAlert(cx_alert, CxElement);
113
+ },
114
+ 'autocomplete': async () => {
115
+ const { defineCxAutocomplete } = await import('../src/elements/autocomplete.js');
116
+ defineCxAutocomplete(cx_autocomplete, CxFormElement);
117
+ },
118
+ 'avatar': async () => {
119
+ const { defineCxAvatar } = await import('../src/elements/avatar.js');
120
+ defineCxAvatar(cx_avatar, CxElement);
121
+ },
122
+ 'backdrop': async () => {
123
+ const { defineCxBackdrop } = await import('../src/elements/backdrop.js');
124
+ defineCxBackdrop(cx_backdrop, CxElement);
125
+ },
126
+ 'badge': async () => {
127
+ const { defineCxBadge } = await import('../src/elements/badge.js');
128
+ defineCxBadge(cx_badge, CxElement);
129
+ },
130
+ 'breadcrumb': async () => {
131
+ const { defineCxBreadcrumb } = await import('../src/elements/breadcrumb.js');
132
+ defineCxBreadcrumb(cx_breadcrumb, CxElement);
133
+ },
134
+ 'button': async () => {
135
+ const { defineCxButton } = await import('../src/elements/button.js');
136
+ defineCxButton(cx_button, CxElement);
137
+ },
138
+ 'card': async () => {
139
+ const { defineCxCard } = await import('../src/elements/card.js');
140
+ defineCxCard(cx_card, CxElement);
141
+ },
142
+ 'carousel': async () => {
143
+ const { defineCxCarousel } = await import('../src/elements/carousel.js');
144
+ defineCxCarousel(cx_carousel, CxElement);
145
+ },
146
+ 'chat-input': async () => {
147
+ const { defineCxChatInput } = await import('../src/elements/chat_input.js');
148
+ defineCxChatInput(cx_chat_input, CxElement);
149
+ },
150
+ 'checkbox': async () => {
151
+ const { defineCxCheckbox } = await import('../src/elements/checkbox.js');
152
+ defineCxCheckbox(cx_checkbox, CxFormElement);
153
+ },
154
+ 'code-block': async () => {
155
+ const { defineCxCodeBlock } = await import('../src/elements/code_block.js');
156
+ defineCxCodeBlock(cx_code_block, CxElement);
157
+ },
158
+ 'collapsible': async () => {
159
+ const { defineCxCollapsible } = await import('../src/elements/collapsible.js');
160
+ defineCxCollapsible(cx_collapsible, CxElement);
161
+ },
162
+ 'date-picker': async () => {
163
+ const { defineCxDatePicker } = await import('../src/elements/date_picker.js');
164
+ defineCxDatePicker(cx_date_picker, CxFormElement);
165
+ },
166
+ 'dialog': async () => {
167
+ const { defineCxDialog } = await import('../src/elements/dialog.js');
168
+ defineCxDialog(cx_dialog, CxElement);
169
+ },
170
+ 'drawer': async () => {
171
+ const { defineCxDrawer } = await import('../src/elements/drawer.js');
172
+ defineCxDrawer(cx_drawer, CxElement);
173
+ },
174
+ 'fab': async () => {
175
+ const { defineCxFab } = await import('../src/elements/fab.js');
176
+ defineCxFab(cx_fab, CxElement);
177
+ },
178
+ 'file-upload': async () => {
179
+ const { defineCxFileUpload } = await import('../src/elements/file_upload.js');
180
+ defineCxFileUpload(cx_file_upload, CxElement);
181
+ },
182
+ 'listbox': async () => {
183
+ const { defineCxListbox } = await import('../src/elements/listbox.js');
184
+ defineCxListbox(cx_listbox, CxElement);
185
+ },
186
+ 'menu': async () => {
187
+ const { defineCxMenu } = await import('../src/elements/menu.js');
188
+ defineCxMenu(cx_menu, CxElement);
189
+ },
190
+ 'message-bubble': async () => {
191
+ const { defineCxMessageBubble } = await import('../src/elements/message_bubble.js');
192
+ defineCxMessageBubble(cx_message_bubble, CxElement);
193
+ },
194
+ 'message-group': async () => {
195
+ const { defineCxMessageGroup } = await import('../src/elements/message_group.js');
196
+ defineCxMessageGroup(cx_message_group, CxElement);
197
+ },
198
+ 'message-part': async () => {
199
+ const { defineCxMessagePart } = await import('../src/elements/message_part.js');
200
+ defineCxMessagePart(cx_message_part, CxElement);
201
+ },
202
+ 'pagination': async () => {
203
+ const { defineCxPagination } = await import('../src/elements/pagination.js');
204
+ defineCxPagination(cx_pagination, CxElement);
205
+ },
206
+ 'popover': async () => {
207
+ const { defineCxPopover } = await import('../src/elements/popover.js');
208
+ defineCxPopover(cx_popover, CxElement);
209
+ },
210
+ 'profile-menu': async () => {
211
+ const { defineCxProfileMenu } = await import('../src/elements/profile_menu.js');
212
+ defineCxProfileMenu(cx_profile_menu, CxElement);
213
+ },
214
+ 'progress': async () => {
215
+ const { defineCxProgress } = await import('../src/elements/progress.js');
216
+ defineCxProgress(cx_progress, CxElement);
217
+ },
218
+ 'radio-group': async () => {
219
+ const { defineCxRadioGroup } = await import('../src/elements/radio_group.js');
220
+ defineCxRadioGroup(cx_radio_group, CxFormElement);
221
+ },
222
+ 'scrollbar': async () => {
223
+ const { defineCxScrollbar } = await import('../src/elements/scrollbar.js');
224
+ defineCxScrollbar(cx_scrollbar, CxElement);
225
+ },
226
+ 'search-bar': async () => {
227
+ const { defineCxSearchBar } = await import('../src/elements/search_bar.js');
228
+ defineCxSearchBar(cx_search_bar, CxElement);
229
+ },
230
+ 'select': async () => {
231
+ const { defineCxSelect } = await import('../src/elements/select.js');
232
+ defineCxSelect(cx_select, CxFormElement);
233
+ },
234
+ 'sidebar': async () => {
235
+ const { defineCxSidebar } = await import('../src/elements/sidebar.js');
236
+ defineCxSidebar(cx_sidebar, CxElement);
237
+ },
238
+ 'skeleton': async () => {
239
+ const { defineCxSkeleton } = await import('../src/elements/skeleton.js');
240
+ defineCxSkeleton(cx_skeleton, CxElement);
241
+ },
242
+ 'slider': async () => {
243
+ const { defineCxSlider } = await import('../src/elements/slider.js');
244
+ defineCxSlider(cx_slider, CxFormElement);
245
+ },
246
+ 'speed-dial': async () => {
247
+ const { defineCxSpeedDial } = await import('../src/elements/speed_dial.js');
248
+ defineCxSpeedDial(cx_speed_dial, CxElement);
249
+ },
250
+ 'spinner': async () => {
251
+ const { defineCxSpinner } = await import('../src/elements/spinner.js');
252
+ defineCxSpinner(cx_spinner, CxElement);
253
+ },
254
+ 'split-button': async () => {
255
+ const { defineCxSplitButton } = await import('../src/elements/split_button.js');
256
+ defineCxSplitButton(cx_split_button, CxElement);
257
+ },
258
+ 'stepper': async () => {
259
+ const { defineCxStepper } = await import('../src/elements/stepper.js');
260
+ defineCxStepper(cx_stepper, CxElement);
261
+ },
262
+ 'switch': async () => {
263
+ const { defineCxSwitch } = await import('../src/elements/switch.js');
264
+ defineCxSwitch(cx_switch, CxFormElement);
265
+ },
266
+ 'table': async () => {
267
+ const { defineCxTable } = await import('../src/elements/table.js');
268
+ defineCxTable(cx_table, CxElement);
269
+ },
270
+ 'tabs': async () => {
271
+ const { defineCxTabs } = await import('../src/elements/tabs.js');
272
+ defineCxTabs(cx_tabs, CxElement);
273
+ },
274
+ 'text': async () => {
275
+ const { defineCxText } = await import('../src/elements/text.js');
276
+ defineCxText(cx_text, CxElement);
277
+ },
278
+ 'text-input': async () => {
279
+ const { defineCxTextInput } = await import('../src/elements/text_input.js');
280
+ defineCxTextInput(cx_text_input, CxFormElement);
281
+ },
282
+ 'thinking': async () => {
283
+ const { defineCxThinking } = await import('../src/elements/thinking.js');
284
+ defineCxThinking(cx_thinking, CxElement);
285
+ },
286
+ 'toast': async () => {
287
+ const { defineCxToast } = await import('../src/elements/toast.js');
288
+ defineCxToast(cx_toast, CxElement);
289
+ },
290
+ 'toggle-group': async () => {
291
+ const { defineCxToggleGroup } = await import('../src/elements/toggle_group.js');
292
+ defineCxToggleGroup(cx_toggle_group, CxFormElement);
293
+ },
294
+ 'tooltip': async () => {
295
+ const { defineCxTooltip } = await import('../src/elements/tooltip.js');
296
+ defineCxTooltip(cx_tooltip, CxElement);
297
+ },
298
+ };
299
+
300
+ // All available component names (for validation and enumeration)
301
+ export const componentNames = Object.keys(_registry);
302
+
303
+ // ─── WASM Loading with Fallback Chain ───
304
+ // 1. Explicit URL (wasmUrl or baseUrl) — always tried first
305
+ // 2. import.meta.url default (wasm-pack) — works in plain ESM, some bundlers
306
+ // 3. public/ probe — checks if user copied WASM to public/ (common Vite pattern)
307
+ // 4. CDN fallback (jsdelivr) — works when package is published to npm
308
+ //
309
+ // Helper: validate a WASM response before passing to WebAssembly.instantiate.
310
+ // Prevents cryptic "expected magic word" errors when server returns HTML (SPA fallback).
311
+ async function fetchWasmValidated(url) {
312
+ const resp = await fetch(url);
313
+ if (!resp.ok) throw new Error(`HTTP ${resp.status} for ${url}`);
314
+ const type = resp.headers.get('Content-Type') || '';
315
+ // Accept application/wasm, application/octet-stream, or no type (e.g., file:// protocol)
316
+ if (type && !type.includes('wasm') && !type.includes('octet-stream')) {
317
+ throw new Error(`Wrong MIME type "${type}" for ${url} (expected application/wasm)`);
318
+ }
319
+ return resp;
320
+ }
321
+
322
+ async function loadWasm(resolvedWasm) {
323
+ // Ensure WASM glue is loaded (lazy import)
324
+ await _ensureWasm();
325
+
326
+ // Explicit URL provided — use it directly
327
+ if (resolvedWasm) {
328
+ return initWasm(() => _wasmInit({ module_or_path: resolvedWasm }));
329
+ }
330
+
331
+ // Try default import.meta.url resolution (works in plain ESM + some bundlers)
332
+ try {
333
+ return await initWasm(() => _wasmInit());
334
+ } catch (primaryError) {
335
+ const msg = String(primaryError.message || primaryError);
336
+ const isBundlerIssue = msg.includes('expected magic word') || msg.includes('CompileError')
337
+ || msg.includes('failed to asynchronously prepare') || msg.includes('Unexpected token')
338
+ || msg.includes('Incorrect response MIME type');
339
+
340
+ if (!isBundlerIssue) throw primaryError;
341
+
342
+ // Try /wasm_api_bg.wasm (user may have copied to public/)
343
+ try {
344
+ const resp = await fetchWasmValidated('/wasm_api_bg.wasm');
345
+ return await initWasm(() => _wasmInit({ module_or_path: resp }));
346
+ } catch { /* not in public/ */ }
347
+
348
+ console.warn('[cx] WASM not found locally. Trying CDN...');
349
+
350
+ // CDN fallback — jsdelivr mirrors npm packages
351
+ const cdnUrl = `https://cdn.jsdelivr.net/npm/@colletdev/core@${PKG_VERSION}/wasm/wasm_api_bg.wasm`;
352
+ try {
353
+ const resp = await fetchWasmValidated(cdnUrl);
354
+ return await initWasm(() => _wasmInit({ module_or_path: resp }));
355
+ } catch (cdnError) {
356
+ throw new Error(
357
+ '[cx] WASM binary could not be loaded.\n\n' +
358
+ 'Run this once after install:\n' +
359
+ ' cp node_modules/@colletdev/core/wasm/wasm_api_bg.wasm public/\n\n' +
360
+ 'Then reload. No code changes needed — init() finds it automatically.\n\n' +
361
+ `(This step is not needed once @colletdev/core is published to npm.)\n` +
362
+ `Debug: ${primaryError.message}`
363
+ );
364
+ }
365
+ }
366
+ }
367
+
368
+ // ─── Auto-Detect ───
369
+ // Scan the document for existing cx-* elements and return their names.
370
+ // Used when init() is called without a components list — zero-config tree-shaking.
371
+ function detectComponentsFromDOM() {
372
+ const found = new Set();
373
+ for (const el of document.querySelectorAll('*')) {
374
+ const tag = el.tagName.toLowerCase();
375
+ if (tag.startsWith('cx-')) {
376
+ const name = tag.slice(3);
377
+ if (name in _registry) found.add(name);
378
+ }
379
+ }
380
+ return found;
381
+ }
382
+
383
+ // ─── SPA Auto-Registration ───
384
+ // MutationObserver watches for new cx-* elements entering the DOM after init().
385
+ // When a new Collet element appears (React route change, lazy-loaded component,
386
+ // conditional render), its behavior JS is dynamically imported and registered
387
+ // automatically. The developer never needs to maintain a component list.
388
+ let _observer = null;
389
+ const _registered = new Set();
390
+
391
+ function startAutoRegistration() {
392
+ if (_observer) return;
393
+ _observer = new MutationObserver((mutations) => {
394
+ for (const mutation of mutations) {
395
+ for (const node of mutation.addedNodes) {
396
+ if (node.nodeType !== 1) continue;
397
+ // Check the added node itself
398
+ _maybeRegister(node);
399
+ // Check descendants (e.g., a React subtree mount)
400
+ if (node.querySelectorAll) {
401
+ for (const child of node.querySelectorAll('*')) {
402
+ _maybeRegister(child);
403
+ }
404
+ }
405
+ }
406
+ }
407
+ });
408
+ _observer.observe(document.body, { childList: true, subtree: true });
409
+ }
410
+
411
+ function _maybeRegister(el) {
412
+ const tag = el.tagName.toLowerCase();
413
+ if (!tag.startsWith('cx-')) return;
414
+ const name = tag.slice(3);
415
+ if (_registered.has(name) || !(name in _registry)) return;
416
+ _registered.add(name);
417
+ // Fire-and-forget — dynamic import + define. Element renders
418
+ // when its class upgrades (built into Custom Elements spec).
419
+ _registry[name]();
420
+ }
421
+
422
+ export async function init(options = {}) {
423
+ const {
424
+ // Explicit asset URLs (optional — zero-config works without these)
425
+ baseUrl,
426
+ tokensUrl,
427
+ utilitiesUrl,
428
+ wasmUrl,
429
+ // Selective: only register these components (kebab-case names, e.g. 'button', 'text-input')
430
+ components,
431
+ // Lazy: start WASM loading but don't wait — elements render when WASM is ready
432
+ lazy,
433
+ } = options;
434
+
435
+ // FOUC prevention — injected immediately, before any async work.
436
+ // Hides cx-* elements via :not(:defined) until their class registers.
437
+ injectFoucPrevention(Object.keys(_registry));
438
+
439
+ const useExplicitCss = !!(tokensUrl || utilitiesUrl || baseUrl != null);
440
+
441
+ // Use != null (not truthiness) so baseUrl: '' works correctly
442
+ const resolvedTokens = tokensUrl || (baseUrl != null ? `${baseUrl}/tokens.css` : null);
443
+ const resolvedUtilities = utilitiesUrl || (baseUrl != null ? `${baseUrl}/cx-utilities.css` : null);
444
+ const resolvedWasm = wasmUrl || (baseUrl != null ? `${baseUrl}/wasm_api_bg.wasm` : undefined);
445
+
446
+ // Start WASM loading (with fallback chain)
447
+ const wasmPromise = loadWasm(resolvedWasm);
448
+
449
+ const styleTasks = [];
450
+
451
+ if (useExplicitCss) {
452
+ // Explicit URLs provided — fetch CSS from URLs (original behavior)
453
+ if (resolvedUtilities) {
454
+ styleTasks.push(loadSharedStyles([resolvedUtilities]));
455
+ }
456
+ if (resolvedTokens) {
457
+ if (!document.querySelector(`link[href="${resolvedTokens}"]`)) {
458
+ const link = document.createElement('link');
459
+ link.rel = 'stylesheet';
460
+ link.href = resolvedTokens;
461
+ document.head.appendChild(link);
462
+ }
463
+ styleTasks.push(loadMotionStyles(resolvedTokens));
464
+ }
465
+ } else {
466
+ // Zero-config — lazy-load CSS strings (dynamic import keeps them out of main chunk).
467
+ // TOKENS_CSS goes to <head> (vars, fonts, themes — inherits into Shadow DOM).
468
+ // TOKENS_SHADOW_CSS is the pre-split Shadow DOM subset (animations, motion, component rules).
469
+ // No runtime CSS parsing needed — the build produces the exact strings for each context.
470
+ const { TOKENS_CSS, TOKENS_SHADOW_CSS, UTILITIES_CSS } = await import('./styles.js');
471
+ injectTokensToHead(TOKENS_CSS);
472
+ styleTasks.push(loadInlineMotionStyles(TOKENS_SHADOW_CSS));
473
+ styleTasks.push(loadInlineSharedStyles(UTILITIES_CSS));
474
+ }
475
+
476
+ if (lazy) {
477
+ await Promise.all(styleTasks);
478
+ } else {
479
+ await Promise.all([wasmPromise, ...styleTasks]);
480
+ }
481
+
482
+ // Determine which components to register.
483
+ let names;
484
+ let autoDetected = false;
485
+
486
+ if (components) {
487
+ // Explicit list — register exactly these, warn on unknowns.
488
+ names = components.filter(c => c in _registry);
489
+ const unknown = components.filter(c => !(c in _registry));
490
+ if (unknown.length > 0) {
491
+ console.warn(`[cx] Unknown components: ${unknown.join(', ')}. Available: ${Object.keys(_registry).join(', ')}`);
492
+ }
493
+ } else {
494
+ // Auto-detect: scan DOM for cx-* elements already present.
495
+ const found = detectComponentsFromDOM();
496
+ if (found.size > 0) {
497
+ names = [...found];
498
+ autoDetected = true;
499
+ } else {
500
+ // Nothing in DOM yet (SPA with deferred rendering) — register all.
501
+ names = Object.keys(_registry);
502
+ }
503
+ }
504
+
505
+ // Register components — dynamic imports load only their behavior JS.
506
+ await Promise.all(names.map(name => _registry[name]()));
507
+ for (const name of names) _registered.add(name);
508
+
509
+ // Start MutationObserver for SPA auto-registration.
510
+ // New cx-* elements that appear later (route changes, lazy loads)
511
+ // are automatically imported and registered on-demand.
512
+ if (!components) {
513
+ startAutoRegistration();
514
+ }
515
+
516
+ const mode = autoDetected ? ` Auto-detected ${names.length} from DOM.` : '';
517
+ console.log(`[cx] ${names.length} Custom Elements registered.${lazy ? ' WASM loading in background.' : ' WASM ready.'}${mode}`);
518
+ }
519
+
520
+ // Re-export base classes for advanced usage
521
+ export { CxElement, CxFormElement };