@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,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 };
|