@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
package/src/server.d.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// Collet Server Renderer — Pre-render components to HTML in Node.js.
|
|
2
|
+
|
|
3
|
+
export interface RenderResult {
|
|
4
|
+
/** The component HTML fragment (shadow content). */
|
|
5
|
+
html: string;
|
|
6
|
+
/** SVG sprite definitions. Empty string if no icons used. */
|
|
7
|
+
sprites: string;
|
|
8
|
+
/** Accessibility metadata for the host element. */
|
|
9
|
+
a11y: {
|
|
10
|
+
role?: string;
|
|
11
|
+
focusable: boolean;
|
|
12
|
+
keyboard_pattern: string;
|
|
13
|
+
aria: Record<string, string>;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface ServerRenderer {
|
|
18
|
+
/**
|
|
19
|
+
* Render a component to its inner HTML.
|
|
20
|
+
* Returns the shadow content, sprites, and a11y metadata.
|
|
21
|
+
*/
|
|
22
|
+
renderToString(component: string, config: Record<string, unknown>): RenderResult;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Render a complete `<cx-{name}>` element with Declarative Shadow DOM.
|
|
26
|
+
* The browser paints this instantly — no JavaScript needed.
|
|
27
|
+
*
|
|
28
|
+
* @param component - Component name (snake_case: 'button', 'text_input')
|
|
29
|
+
* @param config - Component props
|
|
30
|
+
* @param children - Optional light DOM content for slot projection
|
|
31
|
+
*/
|
|
32
|
+
renderDSD(component: string, config: Record<string, unknown>, children?: string): string;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Render just the `<template shadowrootmode="open">` fragment.
|
|
36
|
+
* Use when the host element already exists in your HTML.
|
|
37
|
+
*/
|
|
38
|
+
renderDSDFragment(component: string, config: Record<string, unknown>): string;
|
|
39
|
+
|
|
40
|
+
/** Render GFM markdown to sanitized HTML. */
|
|
41
|
+
renderMarkdown(input: string): string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface CreateRendererOptions {
|
|
45
|
+
/** Custom path to wasm_api_bg.wasm. Defaults to the bundled WASM. */
|
|
46
|
+
wasmPath?: string;
|
|
47
|
+
/** URL for the shared stylesheet in DSD templates. Defaults to '/@colletdev/cx-utilities.css'. */
|
|
48
|
+
stylesUrl?: string;
|
|
49
|
+
/** URL for the motion stylesheet in DSD templates. Defaults to '/@colletdev/tokens-shadow.css'. */
|
|
50
|
+
motionUrl?: string;
|
|
51
|
+
/** Inline CSS directly into DSD templates instead of using <link>. Best for static site generators. */
|
|
52
|
+
inlineStyles?: boolean;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Create a server renderer instance.
|
|
57
|
+
*
|
|
58
|
+
* Loads the WASM binary synchronously from disk (~5ms one-time cost).
|
|
59
|
+
* Reuse the returned renderer for all render calls.
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```ts
|
|
63
|
+
* import { createRenderer } from '@colletdev/core/server';
|
|
64
|
+
*
|
|
65
|
+
* const cx = await createRenderer();
|
|
66
|
+
* const html = cx.renderDSD('button', { label: 'Click', variant: 'filled' });
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export function createRenderer(options?: CreateRendererOptions): Promise<ServerRenderer>;
|
package/src/server.js
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
// Collet Server Renderer — Pre-render components to HTML in Node.js.
|
|
2
|
+
//
|
|
3
|
+
// This module loads the WASM binary synchronously (no fetch, no browser APIs)
|
|
4
|
+
// and exposes renderToString() / renderDSD() for server-side or build-time
|
|
5
|
+
// rendering. The output can be injected as Declarative Shadow DOM so the
|
|
6
|
+
// browser paints components BEFORE any JavaScript executes.
|
|
7
|
+
//
|
|
8
|
+
// Usage:
|
|
9
|
+
// import { createRenderer } from '@colletdev/core/server';
|
|
10
|
+
// const { renderToString, renderDSD } = await createRenderer();
|
|
11
|
+
//
|
|
12
|
+
// // Render component HTML (inner shadow content)
|
|
13
|
+
// const html = renderToString('button', { label: 'Click', variant: 'filled' });
|
|
14
|
+
//
|
|
15
|
+
// // Render full Declarative Shadow DOM element
|
|
16
|
+
// const dsd = renderDSD('button', { label: 'Click', variant: 'filled' });
|
|
17
|
+
// // → '<cx-button variant="filled" label="Click">
|
|
18
|
+
// // <template shadowrootmode="open">
|
|
19
|
+
// // <link rel="stylesheet" href="...">
|
|
20
|
+
// // <svg>...</svg><button class="...">Click</button>
|
|
21
|
+
// // </template>
|
|
22
|
+
// // </cx-button>'
|
|
23
|
+
|
|
24
|
+
import { readFileSync } from 'fs';
|
|
25
|
+
import { dirname, join } from 'path';
|
|
26
|
+
import { fileURLToPath } from 'url';
|
|
27
|
+
import { UTILITIES_CSS, TOKENS_SHADOW_CSS } from '../generated/styles.js';
|
|
28
|
+
|
|
29
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
30
|
+
|
|
31
|
+
// Resolve paths relative to the package root (src/ → parent)
|
|
32
|
+
const WASM_PATH = join(__dirname, '..', 'wasm', 'wasm_api_bg.wasm');
|
|
33
|
+
|
|
34
|
+
// ─── Serialization ───
|
|
35
|
+
// Convert a props object to kebab-case HTML attributes.
|
|
36
|
+
// Boolean true → bare attribute, false/null → omitted, rest → quoted value.
|
|
37
|
+
function propsToAttributes(props) {
|
|
38
|
+
const parts = [];
|
|
39
|
+
for (const [key, value] of Object.entries(props)) {
|
|
40
|
+
if (value === false || value === null || value === undefined) continue;
|
|
41
|
+
const attr = key.replace(/_/g, '-');
|
|
42
|
+
if (value === true) {
|
|
43
|
+
parts.push(attr);
|
|
44
|
+
} else if (typeof value === 'object') {
|
|
45
|
+
// Arrays/objects → JSON attribute (for items, options, steps, etc.)
|
|
46
|
+
parts.push(`${attr}='${JSON.stringify(value).replace(/'/g, ''')}'`);
|
|
47
|
+
} else {
|
|
48
|
+
parts.push(`${attr}="${String(value).replace(/"/g, '"')}"`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return parts.length > 0 ? ' ' + parts.join(' ') : '';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Create a server renderer instance.
|
|
56
|
+
*
|
|
57
|
+
* Loads the WASM binary synchronously from disk and returns render functions.
|
|
58
|
+
* Call this once at startup (or build-time plugin init), then reuse the
|
|
59
|
+
* returned functions for all render calls — WASM initialization is a one-time
|
|
60
|
+
* cost (~5ms).
|
|
61
|
+
*
|
|
62
|
+
* @param {object} [options]
|
|
63
|
+
* @param {string} [options.wasmPath] - Custom path to wasm_api_bg.wasm
|
|
64
|
+
* @param {string} [options.stylesUrl] - URL path for the shared stylesheet <link> in DSD templates.
|
|
65
|
+
* Defaults to '/@colletdev/cx-utilities.css'.
|
|
66
|
+
* Set to the URL where cx-utilities.css is served in your app.
|
|
67
|
+
* @param {string} [options.motionUrl] - URL path for the motion/animation stylesheet <link>.
|
|
68
|
+
* Defaults to '/@colletdev/tokens-shadow.css'.
|
|
69
|
+
* @param {boolean} [options.inlineStyles] - When true, inline the CSS directly into each DSD template
|
|
70
|
+
* instead of using <link> elements. Eliminates the stylesheet
|
|
71
|
+
* network request at the cost of larger HTML. Best for
|
|
72
|
+
* static-site generators where HTML is cached.
|
|
73
|
+
* @returns {Promise<{ renderToString, renderDSD, renderDSDFragment }>}
|
|
74
|
+
*/
|
|
75
|
+
export async function createRenderer(options = {}) {
|
|
76
|
+
const {
|
|
77
|
+
wasmPath = WASM_PATH,
|
|
78
|
+
stylesUrl = '/@colletdev/cx-utilities.css',
|
|
79
|
+
motionUrl = '/@colletdev/tokens-shadow.css',
|
|
80
|
+
inlineStyles = false,
|
|
81
|
+
} = options;
|
|
82
|
+
|
|
83
|
+
// Load WASM glue module dynamically (it uses import.meta.url internally
|
|
84
|
+
// but we bypass that by providing the bytes directly via initSync).
|
|
85
|
+
const wasmGlue = await import('../wasm/wasm_api.js');
|
|
86
|
+
const { initSync, cx_render, cx_render_markdown } = wasmGlue;
|
|
87
|
+
|
|
88
|
+
// Read WASM binary from disk and initialize synchronously.
|
|
89
|
+
// initSync uses WebAssembly.Module + WebAssembly.Instance (no fetch).
|
|
90
|
+
const wasmBytes = readFileSync(wasmPath);
|
|
91
|
+
initSync({ module: wasmBytes });
|
|
92
|
+
|
|
93
|
+
// Use pre-inlined CSS from generated/styles.js (no filesystem reads needed)
|
|
94
|
+
const inlineCss = inlineStyles ? UTILITIES_CSS + '\n' + TOKENS_SHADOW_CSS : '';
|
|
95
|
+
|
|
96
|
+
// Build the stylesheet block that goes inside each DSD template.
|
|
97
|
+
// Browsers deduplicate <link> parsing across shadow roots pointing to
|
|
98
|
+
// the same URL — this is a Chrome/Firefox/Safari DSD optimization.
|
|
99
|
+
function stylesheetBlock() {
|
|
100
|
+
if (inlineStyles && inlineCss) {
|
|
101
|
+
return `<style>${inlineCss}</style>`;
|
|
102
|
+
}
|
|
103
|
+
return `<link rel="stylesheet" href="${stylesUrl}"><link rel="stylesheet" href="${motionUrl}">`;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Render a component to its inner HTML string.
|
|
108
|
+
*
|
|
109
|
+
* Returns only the shadow content (no host element, no template wrapper).
|
|
110
|
+
* Use this when you need raw HTML for custom injection or testing.
|
|
111
|
+
*
|
|
112
|
+
* @param {string} component - Component name (snake_case: 'button', 'text_input')
|
|
113
|
+
* @param {object} config - Component props matching the Rust config struct
|
|
114
|
+
* @returns {{ html: string, sprites: string, a11y: object }}
|
|
115
|
+
*/
|
|
116
|
+
function renderToString(component, config) {
|
|
117
|
+
const result = cx_render(component, config);
|
|
118
|
+
return result;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Render a complete Declarative Shadow DOM element.
|
|
123
|
+
*
|
|
124
|
+
* Returns a full `<cx-{name}>` element with a `<template shadowrootmode="open">`
|
|
125
|
+
* containing the pre-rendered shadow content and stylesheet references.
|
|
126
|
+
* The browser paints this instantly — no JavaScript needed for first render.
|
|
127
|
+
*
|
|
128
|
+
* When the Custom Element class is registered (via init()), the element
|
|
129
|
+
* "upgrades" and becomes interactive. The DSD shadow root is reused —
|
|
130
|
+
* no re-creation, no flash.
|
|
131
|
+
*
|
|
132
|
+
* @param {string} component - Component name (snake_case: 'button', 'text_input')
|
|
133
|
+
* @param {object} config - Component props matching the Rust config struct
|
|
134
|
+
* @param {string} [children] - Light DOM content (projected via <slot>)
|
|
135
|
+
* @returns {string} Full HTML string ready for insertion into a document
|
|
136
|
+
*/
|
|
137
|
+
function renderDSD(component, config, children = '') {
|
|
138
|
+
const result = cx_render(component, config);
|
|
139
|
+
const tag = `cx-${component.replace(/_/g, '-')}`;
|
|
140
|
+
const attrs = propsToAttributes(config);
|
|
141
|
+
const styles = stylesheetBlock();
|
|
142
|
+
const shadow = `${styles}${result.sprites}${result.html}`;
|
|
143
|
+
|
|
144
|
+
return `<${tag}${attrs}><template shadowrootmode="open">${shadow}</template>${children}</${tag}>`;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Render just the DSD template fragment (no host element).
|
|
149
|
+
*
|
|
150
|
+
* Use this when you already have the host element in your HTML and need
|
|
151
|
+
* to inject the template as a child. Useful for Vite transformIndexHtml
|
|
152
|
+
* or framework-specific SSR integrations.
|
|
153
|
+
*
|
|
154
|
+
* @param {string} component - Component name (snake_case: 'button', 'text_input')
|
|
155
|
+
* @param {object} config - Component props matching the Rust config struct
|
|
156
|
+
* @returns {string} `<template shadowrootmode="open">...</template>`
|
|
157
|
+
*/
|
|
158
|
+
function renderDSDFragment(component, config) {
|
|
159
|
+
const result = cx_render(component, config);
|
|
160
|
+
const styles = stylesheetBlock();
|
|
161
|
+
const shadow = `${styles}${result.sprites}${result.html}`;
|
|
162
|
+
return `<template shadowrootmode="open">${shadow}</template>`;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Render markdown to sanitized HTML.
|
|
167
|
+
*
|
|
168
|
+
* @param {string} input - GFM markdown string
|
|
169
|
+
* @returns {string} `<div class="cx-prose">...</div>`
|
|
170
|
+
*/
|
|
171
|
+
function renderMarkdown(input) {
|
|
172
|
+
return cx_render_markdown(input);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return { renderToString, renderDSD, renderDSDFragment, renderMarkdown };
|
|
176
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// streaming-markdown (smd) — vendored from https://github.com/thetarnav/streaming-markdown
|
|
2
|
+
// License: MIT — Copyright (c) thetarnav
|
|
3
|
+
// Version: latest as of 2026-03-09
|
|
4
|
+
// Size: ~3KB gzipped
|
|
5
|
+
//
|
|
6
|
+
// Streaming markdown parser that incrementally adds DOM nodes as tokens arrive.
|
|
7
|
+
// Used by Collet's message-stream behavior module for real-time AI responses.
|
|
8
|
+
//
|
|
9
|
+
// API:
|
|
10
|
+
// smd.parser(renderer) — create parser with a renderer
|
|
11
|
+
// smd.parser_write(parser, s) — write markdown tokens
|
|
12
|
+
// smd.parser_end(parser) — end stream, flush remaining
|
|
13
|
+
// smd.default_renderer(el) — create default DOM renderer targeting element
|
|
14
|
+
|
|
15
|
+
var D=2,C=3,h=4,b=5,B=6,U=7,G=8,S=9,x=10,m=11,H=12,K=13,M=14,Q=15,w=16,q=17,W=18,P=19,Y=20,y=21,F=22,$=23,v=24,X=25,j=26,z=27,J=28,V=29,Z=30,p=31;var I=1,k=2,L=4,T=8,f=16;function ee(e){switch(e){case I:return"href";case k:return"src";case L:return"class";case T:return"checked";case f:return"start"}}var ne=e=>{switch(e){case 1:return 3;case 2:return 4;case 3:return 5;case 4:return 6;case 5:return 7;default:return 8}},te=ne;var O=24;function ae(e){let c=new Uint32Array(O);return c[0]=1,{renderer:e,text:"",pending:"",tokens:c,len:0,token:1,fence_end:0,blockquote_idx:0,hr_char:"",hr_chars:0,fence_start:0,spaces:new Uint8Array(O),indent:"",indent_len:0,table_state:0}}function ce(e){e.pending.length>0&&o(e,`
|
|
16
|
+
`)}function a(e){e.text.length!==0&&(e.renderer.add_text(e.renderer.data,e.text),e.text="")}function _(e){e.len-=1,e.token=e.tokens[e.len],e.renderer.end_token(e.renderer.data)}function i(e,c){(e.tokens[e.len]===24||e.tokens[e.len]===23)&&c!==25&&_(e),e.len+=1,e.tokens[e.len]=c,e.token=c,e.renderer.add_token(e.renderer.data,c)}function re(e,c,n){for(;n<=e.len;){if(e.tokens[n]===c)return n;n+=1}return-1}function l(e,c){for(e.fence_start=0;e.len>c;)_(e)}function u(e,c){let n=0;for(let t=0;t<=e.len&&(c-=e.spaces[t],!(c<0));t+=1)switch(e.tokens[t]){case 9:case 10:case 20:case 25:n=t;break}for(;e.len>n;)_(e);return c}function A(e,c){let n=-1,t=-1;for(let s=e.blockquote_idx+1;s<=e.len;s+=1)if(e.tokens[s]===25){if(e.indent_len<e.spaces[s]){t=-1;break}t=s}else e.tokens[s]===c&&(n=s);return t===-1?n===-1?(l(e,e.blockquote_idx),i(e,c),!0):(l(e,n),!1):(l(e,t),i(e,c),!0)}function g(e,c){i(e,25),e.spaces[e.len]=e.indent_len+c,E(e),e.token=103}function E(e){e.indent="",e.indent_len=0,e.pending=""}function N(e){switch(e){case 48:case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:return!0;default:return!1}}function ie(e){switch(e){case 32:case 58:case 59:case 41:case 44:case 33:case 46:case 63:case 93:case 10:return!0;default:return!1}}function se(e){return N(e)||ie(e)}function o(e,c){for(let n of c){if(e.token===101){switch(n){case" ":e.indent_len+=1;continue;case" ":e.indent_len+=4;continue}let s=u(e,e.indent_len);e.indent_len=0,e.token=e.tokens[e.len],s>0&&o(e," ".repeat(s))}let t=e.pending+n;switch(e.token){case 21:case 1:case 20:case 24:case 23:switch(e.pending[0]){case void 0:e.pending=n;continue;case" ":e.pending=n,e.indent+=" ",e.indent_len+=1;continue;case" ":e.pending=n,e.indent+=" ",e.indent_len+=4;continue;case`
|
|
17
|
+
`:if(e.tokens[e.len]===25&&e.token===21){_(e),E(e),e.pending=n;continue}l(e,e.blockquote_idx),E(e),e.blockquote_idx=0,e.fence_start=0,e.pending=n;continue;case"#":switch(n){case"#":if(e.pending.length<6){e.pending=t;continue}break;case" ":u(e,e.indent_len),i(e,te(e.pending.length)),E(e);continue}break;case">":{let r=re(e,20,e.blockquote_idx+1);r===-1?(l(e,e.blockquote_idx),e.blockquote_idx+=1,e.fence_start=0,i(e,20)):e.blockquote_idx=r,E(e),e.pending=n;continue}case"-":case"*":case"_":if(e.hr_chars===0&&(e.hr_chars=1,e.hr_char=e.pending),e.hr_chars>0){switch(n){case e.hr_char:e.hr_chars+=1,e.pending=t;continue;case" ":e.pending=t;continue;case`
|
|
18
|
+
`:if(e.hr_chars<3)break;u(e,e.indent_len),e.renderer.add_token(e.renderer.data,22),e.renderer.end_token(e.renderer.data),E(e),e.hr_chars=0;continue}e.hr_chars=0}if(e.pending[0]!="_"&&e.pending[1]===" "){A(e,23),g(e,2),o(e,t.slice(2));continue}break;case"`":if(e.pending.length<3){if(n==="`"){e.pending=t,e.fence_start=t.length;continue}e.fence_start=0;break}switch(n){case"`":e.pending.length===e.fence_start?(e.pending=t,e.fence_start=t.length):(i(e,2),E(e),e.fence_start=0,o(e,t));continue;case`
|
|
19
|
+
`:{u(e,e.indent_len),i(e,10),e.pending.length>e.fence_start&&e.renderer.set_attr(e.renderer.data,L,e.pending.slice(e.fence_start)),E(e),e.token=101;continue}default:e.pending=t;continue}case"+":if(n!==" ")break;A(e,23),g(e,2);continue;case"0":case"1":case"2":case"3":case"4":case"5":case"6":case"7":case"8":case"9":if(e.pending[e.pending.length-1]==="."){if(n!==" ")break;A(e,24)&&e.pending!=="1."&&e.renderer.set_attr(e.renderer.data,f,e.pending.slice(0,-1)),g(e,e.pending.length+1);continue}else{let r=n.charCodeAt(0);if(r===46||N(r)){e.pending=t;continue}}break;case"|":l(e,e.blockquote_idx),i(e,27),i(e,28),e.pending="",o(e,n);continue}let s=t;if(e.token===21)e.token=e.tokens[e.len],e.renderer.add_token(e.renderer.data,21),e.renderer.end_token(e.renderer.data);else if(e.indent_len>=4){let r=0;for(;r<4;r+=1)if(e.indent[r]===" "){r=r+1;break}s=e.indent.slice(r)+t,i(e,9)}else i(e,2);E(e),o(e,s);continue;case 27:if(e.table_state===1)switch(n){case"-":case" ":case"|":case":":e.pending=t;continue;case`
|
|
20
|
+
`:e.table_state=2,e.pending="";continue;default:_(e),e.table_state=0;break}else switch(e.pending){case"|":i(e,28),e.pending="",o(e,n);continue;case`
|
|
21
|
+
`:_(e),e.pending="",e.table_state=0,o(e,n);continue}break;case 28:switch(e.pending){case"":break;case"|":i(e,29),_(e),e.pending="",o(e,n);continue;case`
|
|
22
|
+
`:_(e),e.table_state=Math.min(e.table_state+1,2),e.pending="",o(e,n);continue;default:i(e,29),o(e,n);continue}break;case 29:if(e.pending==="|"){a(e),_(e),e.pending="",o(e,n);continue}break;case 9:switch(t){case`
|
|
23
|
+
`:case`
|
|
24
|
+
`:case`
|
|
25
|
+
`:case`
|
|
26
|
+
`:case`
|
|
27
|
+
`:e.text+=`
|
|
28
|
+
`,e.pending="";continue;case`
|
|
29
|
+
`:case`
|
|
30
|
+
`:case`
|
|
31
|
+
`:case`
|
|
32
|
+
`:e.pending=t;continue;default:e.pending.length!==0?(a(e),_(e),e.pending=n):e.text+=n;continue}case 10:switch(n){case"`":e.pending=t;continue;case`
|
|
33
|
+
`:if(t.length===e.fence_start+e.fence_end+1){a(e),_(e),e.pending="",e.fence_start=0,e.fence_end=0,e.token=101;continue}e.token=101;break;case" ":if(e.pending[0]===`
|
|
34
|
+
`){e.pending=t,e.fence_end+=1;continue}break}e.text+=e.pending,e.pending=n,e.fence_end=1;continue;case 11:switch(n){case"`":t.length===e.fence_start+ +(e.pending[0]===" ")?(a(e),_(e),e.pending="",e.fence_start=0):e.pending=t;continue;case`
|
|
35
|
+
`:e.text+=e.pending,e.pending="",e.token=21,e.blockquote_idx=0,a(e);continue;case" ":e.text+=e.pending,e.pending=n;continue;default:e.text+=t,e.pending="";continue}case 103:switch(e.pending.length){case 0:if(n!=="[")break;e.pending=t;continue;case 1:if(n!==" "&&n!=="x")break;e.pending=t;continue;case 2:if(n!=="]")break;e.pending=t;continue;case 3:if(n!==" ")break;e.renderer.add_token(e.renderer.data,26),e.pending[1]==="x"&&e.renderer.set_attr(e.renderer.data,T,""),e.renderer.end_token(e.renderer.data),e.pending=" ";continue}e.token=e.tokens[e.len],e.pending="",o(e,t);continue;case 14:case 15:{let r="*",d=12;if(e.token===15&&(r="_",d=13),r===e.pending){if(a(e),r===n){_(e),e.pending="";continue}i(e,d),e.pending=n;continue}break}case 12:case 13:{let r="*",d=14;switch(e.token===13&&(r="_",d=15),e.pending){case r:r===n?e.tokens[e.len-1]===d?e.pending=t:(a(e),i(e,d),e.pending=""):(a(e),_(e),e.pending=n);continue;case r+r:let R=e.token;a(e),_(e),_(e),r!==n?(i(e,R),e.pending=n):e.pending="";continue}break}case 16:if(t==="~~"){a(e),_(e),e.pending="";continue}break;case 105:n===`
|
|
36
|
+
`?(a(e),i(e,30),e.pending=""):(e.token=e.tokens[e.len],e.pending[0]==="\u005b"?e.text+="[":e.text+="$$",e.pending="",o(e,n));continue;case 30:if(t==="\\]"||t==="$$"){a(e),_(e),e.pending="";continue}break;case 31:if(t==="\\)"||e.pending[0]==="$"){a(e),_(e),n===")"?e.pending="":e.pending=n;continue}break;case 102:t==="http://"||t==="https://"?(a(e),i(e,18),e.pending=t,e.text=t):"http:/"[e.pending.length]===n||"https:/"[e.pending.length]===n?e.pending=t:(e.token=e.tokens[e.len],o(e,n));continue;case 17:case 19:if(e.pending==="]"){a(e),n==="("?e.pending=t:(_(e),e.pending=n);continue}if(e.pending[0]==="]"&&e.pending[1]==="("){if(n===")"){let r=e.token===17?I:k,d=e.pending.slice(2);e.renderer.set_attr(e.renderer.data,r,d),_(e),e.pending=""}else e.pending+=n;continue}break;case 18:n===" "||n===`
|
|
37
|
+
`||n==="\\"?(e.renderer.set_attr(e.renderer.data,I,e.pending),a(e),_(e),e.pending=n):(e.text+=n,e.pending=t);continue;case 104:if(t.startsWith("<br")){if(t.length===3||n===" "||n==="/"&&(t.length===4||e.pending[e.pending.length-1]===" ")){e.pending=t;continue}if(n===">"){a(e),e.token=e.tokens[e.len],e.renderer.add_token(e.renderer.data,21),e.renderer.end_token(e.renderer.data),e.pending="";continue}}e.token=e.tokens[e.len],e.text+="<",e.pending=e.pending.slice(1),o(e,n);continue}switch(e.pending[0]){case"\\":if(e.token===19||e.token===30||e.token===31)break;switch(n){case"(":a(e),i(e,31),e.pending="";continue;case"[":e.token=105,e.pending=t;continue;case`
|
|
38
|
+
`:e.pending=n;continue;default:let s=n.charCodeAt(0);e.pending="",e.text+=N(s)||s>=65&&s<=90||s>=97&&s<=122?t:n;continue}case`
|
|
39
|
+
`:switch(e.token){case 19:case 30:case 31:break;case 3:case 4:case 5:case 6:case 7:case 8:a(e),l(e,e.blockquote_idx),e.blockquote_idx=0,e.pending=n;continue;default:a(e),e.pending=n,e.token=21,e.blockquote_idx=0;continue}break;case"<":if(e.token!==19&&e.token!==30&&e.token!==31){a(e),e.pending=t,e.token=104;continue}break;case"`":if(e.token===19)break;n==="`"?(e.fence_start+=1,e.pending=t):(e.fence_start+=1,a(e),i(e,11),e.text=n===" "||n===`
|
|
40
|
+
`?"":n,e.pending="");continue;case"_":case"*":{if(e.token===19||e.token===30||e.token===31||e.token===14)break;let s=12,r=14,d=e.pending[0];if(d==="_"&&(s=13,r=15),e.pending.length===1){if(d===n){e.pending=t;continue}if(n!==" "&&n!==`
|
|
41
|
+
`){a(e),i(e,s),e.pending=n;continue}}else{if(d===n){a(e),i(e,r),i(e,s),e.pending="";continue}if(n!==" "&&n!==`
|
|
42
|
+
`){a(e),i(e,r),e.pending=n;continue}}break}case"~":if(e.token!==19&&e.token!==16){if(e.pending==="~"){if(n==="~"){e.pending=t;continue}}else if(n!==" "&&n!==`
|
|
43
|
+
`){a(e),i(e,16),e.pending=n;continue}}break;case"$":if(e.token!==19&&e.token!==16&&e.pending==="$")if(n==="$"){e.token=105,e.pending=t;continue}else{if(se(n.charCodeAt(0)))break;a(e),i(e,31),e.pending=n;continue}break;case"[":if(e.token!==19&&e.token!==17&&e.token!==30&&e.token!==31&&n!=="]"){a(e),i(e,17),e.pending=n;continue}break;case"!":if(e.token!==19&&n==="["){a(e),i(e,19),e.pending="";continue}break;case" ":if(e.pending.length===1&&n===" ")continue;break}if(e.token!==19&&e.token!==17&&e.token!==30&&e.token!==31&&n==="h"&&(e.pending===" "||e.pending==="")){e.text+=e.pending,e.pending=n,e.token=102;continue}e.text+=e.pending,e.pending=n}a(e)}function _e(e){return{add_token:oe,end_token:de,add_text:Ee,set_attr:le,data:{nodes:[e,,,,,],index:0}}}function oe(e,c){let n=e.nodes[e.index],t;switch(c){case 1:return;case 20:t=document.createElement("blockquote");break;case 2:t=document.createElement("p");break;case 21:t=document.createElement("br");break;case 22:t=document.createElement("hr");break;case 3:t=document.createElement("h1");break;case 4:t=document.createElement("h2");break;case 5:t=document.createElement("h3");break;case 6:t=document.createElement("h4");break;case 7:t=document.createElement("h5");break;case 8:t=document.createElement("h6");break;case 12:case 13:t=document.createElement("em");break;case 14:case 15:t=document.createElement("strong");break;case 16:t=document.createElement("s");break;case 11:t=document.createElement("code");break;case 18:case 17:t=document.createElement("a");break;case 19:t=document.createElement("img");break;case 23:t=document.createElement("ul");break;case 24:t=document.createElement("ol");break;case 25:t=document.createElement("li");break;case 26:let s=t=document.createElement("input");s.type="checkbox",s.disabled=!0;break;case 9:case 10:n=n.appendChild(document.createElement("pre")),t=document.createElement("code");break;case 27:t=document.createElement("table");break;case 28:switch(n.children.length){case 0:n=n.appendChild(document.createElement("thead"));break;case 1:n=n.appendChild(document.createElement("tbody"));break;default:n=n.children[1]}t=document.createElement("tr");break;case 29:t=document.createElement(n.parentElement?.tagName==="THEAD"?"th":"td");break;case 30:t=document.createElement("equation-block");break;case 31:t=document.createElement("equation-inline");break}e.nodes[++e.index]=n.appendChild(t)}function de(e){e.index-=1}function Ee(e,c){e.nodes[e.index].appendChild(document.createTextNode(c))}function le(e,c,n){e.nodes[e.index].setAttribute(ee(c),n)}export{Y as BLOCKQUOTE,j as CHECKBOX,T as CHECKED,S as CODE_BLOCK,x as CODE_FENCE,m as CODE_INLINE,Z as EQUATION_BLOCK,p as EQUATION_INLINE,C as HEADING_1,h as HEADING_2,b as HEADING_3,B as HEADING_4,U as HEADING_5,G as HEADING_6,I as HREF,P as IMAGE,H as ITALIC_AST,K as ITALIC_UND,L as LANG,y as LINE_BREAK,q as LINK,X as LIST_ITEM,v as LIST_ORDERED,$ as LIST_UNORDERED,D as PARAGRAPH,W as RAW_URL,F as RULE,k as SRC,f as START,w as STRIKE,M as STRONG_AST,Q as STRONG_UND,z as TABLE,V as TABLE_CELL,J as TABLE_ROW,_e as default_renderer,ae as parser,ce as parser_end,o as parser_write};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// Collet Vite Plugin — WASM MIME, auto-copy, preload hints, and DSD pre-rendering.
|
|
2
|
+
//
|
|
3
|
+
// Usage in vite.config.ts:
|
|
4
|
+
// import { colletPlugin } from '@colletdev/core/vite-plugin';
|
|
5
|
+
// export default defineConfig({ plugins: [colletPlugin()] });
|
|
6
|
+
|
|
7
|
+
export interface ColletPluginOptions {
|
|
8
|
+
/**
|
|
9
|
+
* Inject `<link rel="preload">` for the WASM binary.
|
|
10
|
+
* Starts downloading early, in parallel with script parsing.
|
|
11
|
+
* @default true
|
|
12
|
+
*/
|
|
13
|
+
preload?: boolean;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Pre-render `<cx-*>` elements in static HTML as Declarative Shadow DOM.
|
|
17
|
+
* Only affects elements present in index.html (not React/Vue runtime renders).
|
|
18
|
+
* For SSR frameworks, use `@colletdev/core/server` directly.
|
|
19
|
+
* @default false
|
|
20
|
+
*/
|
|
21
|
+
prerender?: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Vite plugin for Collet. Handles:
|
|
26
|
+
* - WASM MIME type (dev server)
|
|
27
|
+
* - Auto-copy WASM to public/ (dev)
|
|
28
|
+
* - WASM + CSS preload hints (build)
|
|
29
|
+
* - Serves utility CSS for DSD `<link>` refs (dev)
|
|
30
|
+
* - Optional DSD pre-rendering of static `<cx-*>` elements
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* import { colletPlugin } from '@colletdev/core/vite-plugin';
|
|
35
|
+
*
|
|
36
|
+
* export default defineConfig({
|
|
37
|
+
* plugins: [colletPlugin()],
|
|
38
|
+
* });
|
|
39
|
+
*
|
|
40
|
+
* // With DSD pre-rendering:
|
|
41
|
+
* export default defineConfig({
|
|
42
|
+
* plugins: [colletPlugin({ prerender: true })],
|
|
43
|
+
* });
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export function colletPlugin(options?: ColletPluginOptions): any;
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
// Collet Vite Plugin — WASM MIME, auto-copy, preload hints, and DSD pre-rendering.
|
|
2
|
+
//
|
|
3
|
+
// Handles the operational friction of using WASM Custom Elements with Vite:
|
|
4
|
+
// 1. Serves .wasm with correct MIME type (dev server)
|
|
5
|
+
// 2. Copies WASM binary to public/ so Vite can serve it (dev + build)
|
|
6
|
+
// 3. Injects <link rel="preload"> for WASM + CSS (faster init)
|
|
7
|
+
// 4. Serves utility CSS and motion CSS for DSD <link> refs (dev server)
|
|
8
|
+
// 5. Provides DSD pre-rendering for SSR frameworks (transformIndexHtml)
|
|
9
|
+
//
|
|
10
|
+
// Usage in vite.config.ts:
|
|
11
|
+
// import { colletPlugin } from '@colletdev/core/vite-plugin';
|
|
12
|
+
// export default defineConfig({ plugins: [colletPlugin()] });
|
|
13
|
+
//
|
|
14
|
+
// // With options:
|
|
15
|
+
// colletPlugin({
|
|
16
|
+
// prerender: true, // Enable DSD pre-rendering in HTML
|
|
17
|
+
// preload: true, // Inject <link rel="preload"> for WASM
|
|
18
|
+
// })
|
|
19
|
+
|
|
20
|
+
import { existsSync, copyFileSync, mkdirSync, readFileSync } from 'fs';
|
|
21
|
+
import { dirname, join, resolve } from 'path';
|
|
22
|
+
import { fileURLToPath } from 'url';
|
|
23
|
+
import { UTILITIES_CSS, TOKENS_SHADOW_CSS } from '../generated/styles.js';
|
|
24
|
+
|
|
25
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
26
|
+
const PKG_ROOT = join(__dirname, '..');
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @param {object} [options]
|
|
30
|
+
* @param {boolean} [options.preload=true] - Inject <link rel="preload"> for WASM binary and CSS.
|
|
31
|
+
* @param {boolean} [options.prerender=false] - Pre-render <cx-*> elements in HTML as Declarative Shadow DOM.
|
|
32
|
+
* Only affects static HTML (transformIndexHtml). For React SSR,
|
|
33
|
+
* use `@colletdev/core/server` directly in your SSR handler.
|
|
34
|
+
*/
|
|
35
|
+
export function colletPlugin(options = {}) {
|
|
36
|
+
const {
|
|
37
|
+
preload = true,
|
|
38
|
+
prerender = false,
|
|
39
|
+
} = options;
|
|
40
|
+
|
|
41
|
+
// Lazy-initialized server renderer (only when prerender=true)
|
|
42
|
+
let _renderer = null;
|
|
43
|
+
|
|
44
|
+
// Resolved paths (set in configResolved)
|
|
45
|
+
let publicDir = '';
|
|
46
|
+
let wasmPublicPath = '/wasm_api_bg.wasm';
|
|
47
|
+
let utilitiesCssPath = '/@colletdev/cx-utilities.css';
|
|
48
|
+
let motionCssPath = '/@colletdev/tokens-shadow.css';
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
name: 'collet',
|
|
52
|
+
|
|
53
|
+
// Pre-bundle Collet packages during dev startup so Vite doesn't
|
|
54
|
+
// re-optimize on every page load. Without this, Vite's dependency
|
|
55
|
+
// scanner misses the lazy WASM/CSS imports and triggers full-page
|
|
56
|
+
// reloads when they're first encountered.
|
|
57
|
+
config() {
|
|
58
|
+
return {
|
|
59
|
+
optimizeDeps: {
|
|
60
|
+
include: ['@colletdev/core'],
|
|
61
|
+
exclude: ['@colletdev/core/wasm/wasm_api.js'],
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
configResolved(config) {
|
|
67
|
+
publicDir = config.publicDir || resolve(config.root, 'public');
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
// ─── Dev Server Setup ───
|
|
71
|
+
// 1. Serve .wasm with correct Content-Type
|
|
72
|
+
// 2. Copy WASM to public/ if missing
|
|
73
|
+
// 3. Serve CSS assets for DSD <link> refs
|
|
74
|
+
configureServer(server) {
|
|
75
|
+
// Copy WASM to public/ if not already there (one-time, idempotent)
|
|
76
|
+
const wasmSrc = join(PKG_ROOT, 'wasm', 'wasm_api_bg.wasm');
|
|
77
|
+
const wasmDest = join(publicDir, 'wasm_api_bg.wasm');
|
|
78
|
+
if (existsSync(wasmSrc) && !existsSync(wasmDest)) {
|
|
79
|
+
mkdirSync(publicDir, { recursive: true });
|
|
80
|
+
copyFileSync(wasmSrc, wasmDest);
|
|
81
|
+
server.config.logger.info('[collet] Copied wasm_api_bg.wasm → public/');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
server.middlewares.use((req, res, next) => {
|
|
85
|
+
// WASM MIME type fix (Vite serves .wasm as octet-stream by default)
|
|
86
|
+
if (req.url?.endsWith('.wasm')) {
|
|
87
|
+
res.setHeader('Content-Type', 'application/wasm');
|
|
88
|
+
return next();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Serve utility CSS for DSD <link> references.
|
|
92
|
+
// In production, the consumer copies these to their static dir.
|
|
93
|
+
// In dev, we serve them from pre-inlined generated/styles.js.
|
|
94
|
+
if (req.url === utilitiesCssPath) {
|
|
95
|
+
res.setHeader('Content-Type', 'text/css');
|
|
96
|
+
res.end(UTILITIES_CSS);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
if (req.url === motionCssPath) {
|
|
100
|
+
res.setHeader('Content-Type', 'text/css');
|
|
101
|
+
res.end(TOKENS_SHADOW_CSS);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
next();
|
|
106
|
+
});
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
// ─── Build: Copy WASM to output ───
|
|
110
|
+
// Ensures the WASM binary is in the build output alongside JS chunks.
|
|
111
|
+
generateBundle() {
|
|
112
|
+
const wasmSrc = join(PKG_ROOT, 'wasm', 'wasm_api_bg.wasm');
|
|
113
|
+
if (existsSync(wasmSrc)) {
|
|
114
|
+
this.emitFile({
|
|
115
|
+
type: 'asset',
|
|
116
|
+
fileName: 'wasm_api_bg.wasm',
|
|
117
|
+
source: readFileSync(wasmSrc),
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
// ─── HTML Transform ───
|
|
123
|
+
// Inject preload hints and optionally pre-render <cx-*> elements.
|
|
124
|
+
async transformIndexHtml(html) {
|
|
125
|
+
const tags = [];
|
|
126
|
+
|
|
127
|
+
// Preload hints — start downloading WASM and CSS early, in parallel
|
|
128
|
+
// with script parsing. This shaves 100-300ms off init() in production.
|
|
129
|
+
if (preload) {
|
|
130
|
+
tags.push({
|
|
131
|
+
tag: 'link',
|
|
132
|
+
attrs: {
|
|
133
|
+
rel: 'preload',
|
|
134
|
+
href: wasmPublicPath,
|
|
135
|
+
as: 'fetch',
|
|
136
|
+
crossorigin: 'anonymous',
|
|
137
|
+
},
|
|
138
|
+
injectTo: 'head-prepend',
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// DSD pre-rendering — scan HTML for <cx-*> elements and inject
|
|
143
|
+
// <template shadowrootmode="open"> with pre-rendered shadow content.
|
|
144
|
+
// Only works for elements present in the static HTML (not React/Vue
|
|
145
|
+
// runtime renders). For SSR frameworks, use @colletdev/core/server.
|
|
146
|
+
if (prerender) {
|
|
147
|
+
html = await prerenderDSD(html);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return { html, tags };
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
// ─── DSD Pre-Rendering ───
|
|
155
|
+
// Parse static HTML for <cx-*> elements, extract attributes, call WASM
|
|
156
|
+
// renderer, inject DSD templates. This runs at build time — the WASM
|
|
157
|
+
// binary is a build dependency, not a runtime dependency.
|
|
158
|
+
async function prerenderDSD(html) {
|
|
159
|
+
// Lazy-init the renderer (first call only, ~5ms)
|
|
160
|
+
if (!_renderer) {
|
|
161
|
+
try {
|
|
162
|
+
const { createRenderer } = await import('./server.js');
|
|
163
|
+
_renderer = await createRenderer({
|
|
164
|
+
stylesUrl: utilitiesCssPath,
|
|
165
|
+
motionUrl: motionCssPath,
|
|
166
|
+
});
|
|
167
|
+
} catch (e) {
|
|
168
|
+
console.warn(`[collet] DSD pre-rendering unavailable: ${e.message}`);
|
|
169
|
+
return html;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Match self-closing and pair <cx-*> tags with attributes.
|
|
174
|
+
// This is intentionally simple — it handles static HTML from index.html,
|
|
175
|
+
// not arbitrary nested structures. For complex SSR, use @colletdev/core/server.
|
|
176
|
+
const CX_TAG_RE = /<(cx-[a-z-]+)((?:\s+[a-z-]+(?:=(?:"[^"]*"|'[^']*'|[^\s>]*))?)*)\s*(?:\/>|>([\s\S]*?)<\/\1>)/gi;
|
|
177
|
+
|
|
178
|
+
return html.replace(CX_TAG_RE, (match, tag, attrString, children) => {
|
|
179
|
+
try {
|
|
180
|
+
const component = tag.slice(3).replace(/-/g, '_');
|
|
181
|
+
const config = parseAttributes(attrString);
|
|
182
|
+
const fragment = _renderer.renderDSDFragment(component, config);
|
|
183
|
+
const inner = children || '';
|
|
184
|
+
return `<${tag}${attrString}>${fragment}${inner}</${tag}>`;
|
|
185
|
+
} catch (e) {
|
|
186
|
+
// If pre-rendering fails for a component, leave it as-is.
|
|
187
|
+
// It will render client-side when WASM loads.
|
|
188
|
+
console.warn(`[collet] DSD pre-render failed for ${tag}: ${e.message}`);
|
|
189
|
+
return match;
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Parse an HTML attribute string into a config object.
|
|
196
|
+
// Handles: bare attrs (disabled), quoted values, JSON arrays/objects.
|
|
197
|
+
function parseAttributes(attrString) {
|
|
198
|
+
const config = {};
|
|
199
|
+
if (!attrString) return config;
|
|
200
|
+
|
|
201
|
+
const ATTR_RE = /([a-z][a-z0-9-]*)\s*(?:=\s*(?:"([^"]*)"|'([^']*)'|(\S+)))?/gi;
|
|
202
|
+
let m;
|
|
203
|
+
while ((m = ATTR_RE.exec(attrString))) {
|
|
204
|
+
const key = m[1].replace(/-/g, '_');
|
|
205
|
+
const raw = m[2] ?? m[3] ?? m[4];
|
|
206
|
+
|
|
207
|
+
if (raw === undefined) {
|
|
208
|
+
// Bare attribute (e.g., disabled, dismissible)
|
|
209
|
+
config[key] = true;
|
|
210
|
+
} else if (raw === 'true') {
|
|
211
|
+
config[key] = true;
|
|
212
|
+
} else if (raw === 'false') {
|
|
213
|
+
config[key] = false;
|
|
214
|
+
} else if (raw.length > 0 && (raw[0] === '[' || raw[0] === '{')) {
|
|
215
|
+
try { config[key] = JSON.parse(raw); } catch { config[key] = raw; }
|
|
216
|
+
} else {
|
|
217
|
+
config[key] = raw;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return config;
|
|
221
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "wasm-api",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"description": "WASM bindings for the Resumable Rust component library",
|
|
5
|
+
"version": "0.1.0",
|
|
6
|
+
"files": [
|
|
7
|
+
"wasm_api_bg.wasm",
|
|
8
|
+
"wasm_api.js",
|
|
9
|
+
"wasm_api.d.ts"
|
|
10
|
+
],
|
|
11
|
+
"main": "wasm_api.js",
|
|
12
|
+
"types": "wasm_api.d.ts",
|
|
13
|
+
"sideEffects": [
|
|
14
|
+
"./snippets/*"
|
|
15
|
+
]
|
|
16
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Single dispatcher for all component renders.
|
|
6
|
+
*
|
|
7
|
+
* Replaces 44 individual `#[wasm_bindgen]` exports with one entry point.
|
|
8
|
+
* Each wasm-bindgen export generates a `catch_unwind` wrapper (~2 KB each).
|
|
9
|
+
* By consolidating to a single export, we eliminate 43 redundant wrappers
|
|
10
|
+
* (~91 KB savings in the final WASM binary).
|
|
11
|
+
*
|
|
12
|
+
* JS calls `cx_render("button", { label: "Click" })` instead of
|
|
13
|
+
* `cx_button({ label: "Click" })`. The generated index.js creates
|
|
14
|
+
* thin wrapper functions so the DX is unchanged.
|
|
15
|
+
*
|
|
16
|
+
* # Errors
|
|
17
|
+
*
|
|
18
|
+
* Returns `JsError` if the component name is unknown or the config
|
|
19
|
+
* can't be deserialized.
|
|
20
|
+
*/
|
|
21
|
+
export function cx_render(component: string, config: any): any;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Render GFM markdown to sanitized HTML.
|
|
25
|
+
*
|
|
26
|
+
* Returns a `<div class="cx-prose">...</div>` wrapper containing the
|
|
27
|
+
* rendered HTML. Raw HTML in the markdown source is escaped (not passed
|
|
28
|
+
* through), making the output XSS-safe by construction.
|
|
29
|
+
*
|
|
30
|
+
* # Example (from JS)
|
|
31
|
+
*
|
|
32
|
+
* ```js
|
|
33
|
+
* const html = cx_render_markdown("**Hello** world");
|
|
34
|
+
* // → '<div class="cx-prose"><p><strong>Hello</strong> world</p>\n</div>'
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export function cx_render_markdown(input: string): string;
|
|
38
|
+
|
|
39
|
+
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
|
|
40
|
+
|
|
41
|
+
export interface InitOutput {
|
|
42
|
+
readonly memory: WebAssembly.Memory;
|
|
43
|
+
readonly cx_render: (a: number, b: number, c: number, d: number) => void;
|
|
44
|
+
readonly cx_render_markdown: (a: number, b: number, c: number) => void;
|
|
45
|
+
readonly __wbindgen_export: (a: number, b: number) => number;
|
|
46
|
+
readonly __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
|
|
47
|
+
readonly __wbindgen_export3: (a: number) => void;
|
|
48
|
+
readonly __wbindgen_add_to_stack_pointer: (a: number) => number;
|
|
49
|
+
readonly __wbindgen_export4: (a: number, b: number, c: number) => void;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export type SyncInitInput = BufferSource | WebAssembly.Module;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Instantiates the given `module`, which can either be bytes or
|
|
56
|
+
* a precompiled `WebAssembly.Module`.
|
|
57
|
+
*
|
|
58
|
+
* @param {{ module: SyncInitInput }} module - Passing `SyncInitInput` directly is deprecated.
|
|
59
|
+
*
|
|
60
|
+
* @returns {InitOutput}
|
|
61
|
+
*/
|
|
62
|
+
export function initSync(module: { module: SyncInitInput } | SyncInitInput): InitOutput;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* If `module_or_path` is {RequestInfo} or {URL}, makes a request and
|
|
66
|
+
* for everything else, calls `WebAssembly.instantiate` directly.
|
|
67
|
+
*
|
|
68
|
+
* @param {{ module_or_path: InitInput | Promise<InitInput> }} module_or_path - Passing `InitInput` directly is deprecated.
|
|
69
|
+
*
|
|
70
|
+
* @returns {Promise<InitOutput>}
|
|
71
|
+
*/
|
|
72
|
+
export default function __wbg_init (module_or_path?: { module_or_path: InitInput | Promise<InitInput> } | InitInput | Promise<InitInput>): Promise<InitOutput>;
|