@ketvietlab/ketjs-view 0.1.1

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/dist/island.js ADDED
@@ -0,0 +1,278 @@
1
+ // Islands: the seam where a theme meets behaviour.
2
+ //
3
+ // The rule this implements is the one that keeps a third-party theme safe: a theme
4
+ // PLACES an island and never writes one. Placement is a KTL tag, which cannot carry
5
+ // code; the island itself is a module's `html` view, which is trusted. So the theme
6
+ // decides where interactivity goes and the module decides what it does, and neither
7
+ // can reach into the other.
8
+ import { renderToString } from './ssr.js';
9
+ import { escapeHtml } from './host.js';
10
+ import { mountHydrated } from './mount.js';
11
+ export const ISLAND_TAG = 'ket-island';
12
+ // The view layer carries its own errors rather than reaching into the kernel for
13
+ // them. That single import was the only thing pointing out of this layer, and it
14
+ // is what would have made the view and the kernel mutually dependent once they
15
+ // became separate packages.
16
+ export class IslandError extends Error {
17
+ code;
18
+ hint;
19
+ constructor(d) {
20
+ super(d.message);
21
+ this.name = 'IslandError';
22
+ this.code = d.code;
23
+ this.hint = d.hint ?? null;
24
+ }
25
+ }
26
+ const controllerOf = (created) => typeof created === 'function' ? { view: created } : created;
27
+ const jsonProps = (name, props) => {
28
+ const seen = new WeakSet();
29
+ const visit = (value) => {
30
+ if (value == null || typeof value === 'string' || typeof value === 'boolean')
31
+ return value;
32
+ if (typeof value === 'number') {
33
+ if (!Number.isFinite(value))
34
+ throw new TypeError('non-finite number');
35
+ return value;
36
+ }
37
+ if (typeof value !== 'object')
38
+ throw new TypeError(typeof value);
39
+ if (value instanceof Date) {
40
+ if (Number.isNaN(value.getTime()))
41
+ throw new TypeError('invalid date');
42
+ return value.toJSON();
43
+ }
44
+ if (seen.has(value))
45
+ throw new TypeError('cyclic value');
46
+ seen.add(value);
47
+ let out;
48
+ if (Array.isArray(value)) {
49
+ out = value.map(visit);
50
+ }
51
+ else {
52
+ const prototype = Object.getPrototypeOf(value);
53
+ if (prototype !== null && prototype !== Object.prototype)
54
+ throw new TypeError('non-plain object');
55
+ const object = Object.create(null);
56
+ for (const key of Object.keys(value).sort())
57
+ object[key] = visit(value[key]);
58
+ out = object;
59
+ }
60
+ seen.delete(value);
61
+ return out;
62
+ };
63
+ try {
64
+ const canonical = visit(props);
65
+ const raw = JSON.stringify(canonical);
66
+ const revived = JSON.parse(raw);
67
+ if (typeof revived !== 'object' || revived === null || Array.isArray(revived))
68
+ throw new TypeError('not an object');
69
+ return { raw, revived: revived };
70
+ }
71
+ catch {
72
+ throw new IslandError({
73
+ code: 'E_ISLAND_PROPS',
74
+ message: `island "${name}" received props that are not JSON-serializable`,
75
+ hint: 'island props cross the server/browser boundary; pass plain JSON data only',
76
+ });
77
+ }
78
+ };
79
+ const islandKey = (name, props, fields) => {
80
+ if (fields === undefined)
81
+ return jsonProps(name, props).raw;
82
+ const values = fields.map((field) => {
83
+ if (!(field in props))
84
+ throw new IslandError({
85
+ code: 'E_ISLAND_KEY',
86
+ message: `island "${name}" key prop "${field}" is missing`,
87
+ });
88
+ return props[field];
89
+ });
90
+ return JSON.stringify(values);
91
+ };
92
+ /**
93
+ * Render an island to markup, carrying its props alongside so the client can
94
+ * revive it with exactly the same input the server used. A different input would
95
+ * mean a different tree, and hydration would rightly refuse it.
96
+ */
97
+ export function renderIsland(name, factory, props, options = {}) {
98
+ const { raw, revived } = jsonProps(name, props);
99
+ const key = islandKey(name, revived, options.key);
100
+ const controller = controllerOf(factory(revived));
101
+ try {
102
+ return (`<${ISLAND_TAG} data-island="${escapeHtml(name)}" data-key="${escapeHtml(key)}" data-props="${escapeHtml(raw)}">` +
103
+ renderToString(controller.view()) +
104
+ `</${ISLAND_TAG}>`);
105
+ }
106
+ finally {
107
+ controller.dispose?.();
108
+ }
109
+ }
110
+ const elementsOf = (root) => {
111
+ const out = [];
112
+ const nodeName = root.nodeName ??
113
+ root.tagName;
114
+ if (nodeName?.toLowerCase() === ISLAND_TAG)
115
+ out.push(root);
116
+ out.push(...root.querySelectorAll(ISLAND_TAG));
117
+ return out;
118
+ };
119
+ const childrenOf = (root) => [
120
+ ...(root.childNodes ?? root.children ?? []),
121
+ ];
122
+ const parsedProps = (name, element) => {
123
+ const raw = element.getAttribute('data-props');
124
+ try {
125
+ const parsed = raw ? JSON.parse(raw) : {};
126
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed))
127
+ throw new TypeError();
128
+ const normalized = jsonProps(name, parsed);
129
+ return { props: normalized.revived, raw: normalized.raw };
130
+ }
131
+ catch {
132
+ throw new IslandError({ code: 'E_ISLAND_PROPS', message: `island "${name}" has unreadable props` });
133
+ }
134
+ };
135
+ const identityOf = (element) => {
136
+ const name = element.getAttribute('data-island');
137
+ if (!name)
138
+ return null;
139
+ const parsed = parsedProps(name, element);
140
+ const key = element.getAttribute('data-key') ?? parsed.raw;
141
+ element.setAttribute?.('data-key', key);
142
+ return { name, key, id: JSON.stringify([name, key]) };
143
+ };
144
+ const uniqueByIdentity = (elements, onDuplicate) => {
145
+ const unique = new Map();
146
+ const duplicates = new Set();
147
+ for (const element of elements) {
148
+ const identity = identityOf(element);
149
+ if (!identity)
150
+ continue;
151
+ if (unique.has(identity.id)) {
152
+ duplicates.add(identity.id);
153
+ unique.delete(identity.id);
154
+ onDuplicate?.(identity);
155
+ }
156
+ else if (!duplicates.has(identity.id))
157
+ unique.set(identity.id, element);
158
+ }
159
+ return unique;
160
+ };
161
+ export function createIslandManager(host, registry, options = {}) {
162
+ const instances = new WeakMap();
163
+ const disposeElement = (element) => {
164
+ const managed = instances.get(element);
165
+ if (!managed)
166
+ return;
167
+ instances.delete(element);
168
+ managed.live.dispose();
169
+ };
170
+ const hydrate = (root) => {
171
+ const out = [];
172
+ for (const element of elementsOf(root)) {
173
+ const existing = instances.get(element);
174
+ if (existing) {
175
+ out.push(existing.live);
176
+ continue;
177
+ }
178
+ const identity = identityOf(element);
179
+ if (!identity)
180
+ continue;
181
+ const factory = registry[identity.name];
182
+ if (!factory) {
183
+ if (options.strict === false)
184
+ continue;
185
+ throw new IslandError({
186
+ code: 'E_UNKNOWN_ISLAND',
187
+ message: `the page places island "${identity.name}", which no installed module provides`,
188
+ hint: `registered islands: ${Object.keys(registry).join(', ') || '(none)'}`,
189
+ });
190
+ }
191
+ const parsed = parsedProps(identity.name, element);
192
+ const controller = controllerOf(factory(parsed.props));
193
+ const mounted = mountHydrated(host, element, controller.view);
194
+ let disposed = false;
195
+ const live = {
196
+ name: identity.name,
197
+ key: identity.key,
198
+ props: parsed.props,
199
+ element,
200
+ dispose: () => {
201
+ if (disposed)
202
+ return;
203
+ disposed = true;
204
+ mounted.dispose();
205
+ controller.dispose?.();
206
+ },
207
+ };
208
+ instances.set(element, { live, controller, rawProps: parsed.raw });
209
+ out.push(live);
210
+ }
211
+ return out;
212
+ };
213
+ const reconcile = (slot, nextContent) => {
214
+ const current = elementsOf(slot);
215
+ const next = elementsOf(nextContent);
216
+ const ambiguous = new Map();
217
+ const rememberDuplicate = (identity) => ambiguous.set(identity.id, identity);
218
+ const currentById = uniqueByIdentity(current, rememberDuplicate);
219
+ const nextById = uniqueByIdentity(next, rememberDuplicate);
220
+ for (const identity of ambiguous.values())
221
+ console.warn(`island "${identity.name}" has duplicate key ${identity.key}; remounting ambiguous instances`);
222
+ const preserved = new Set();
223
+ for (const [id, nextElement] of nextById) {
224
+ const currentElement = currentById.get(id);
225
+ const managed = currentElement ? instances.get(currentElement) : undefined;
226
+ if (!currentElement || !managed)
227
+ continue;
228
+ const identity = identityOf(nextElement);
229
+ const parsed = parsedProps(identity.name, nextElement);
230
+ if (managed.rawProps !== parsed.raw) {
231
+ if (!managed.controller.update)
232
+ continue;
233
+ managed.controller.update(parsed.props);
234
+ managed.rawProps = parsed.raw;
235
+ managed.live.props = parsed.props;
236
+ currentElement.setAttribute?.('data-props', parsed.raw);
237
+ currentElement.setAttribute?.('data-key', identity.key);
238
+ }
239
+ const parent = nextElement.parentNode ?? nextElement.parent;
240
+ if (!parent)
241
+ continue;
242
+ host.insert(parent, currentElement, nextElement);
243
+ host.remove(nextElement);
244
+ preserved.add(currentElement);
245
+ }
246
+ for (const element of current)
247
+ if (!preserved.has(element))
248
+ disposeElement(element);
249
+ for (const child of childrenOf(slot))
250
+ host.remove(child);
251
+ for (const child of childrenOf(nextContent))
252
+ host.insert(slot, child, null);
253
+ return hydrate(slot);
254
+ };
255
+ return {
256
+ hydrate,
257
+ reconcile,
258
+ dispose: (root) => {
259
+ for (const element of elementsOf(root))
260
+ disposeElement(element);
261
+ },
262
+ };
263
+ }
264
+ /**
265
+ * Find every island in a server-rendered page and bring it to life. Only the
266
+ * islands are hydrated — the rest of the page stays inert markup, which is the
267
+ * whole point of rendering a theme to a string in the first place.
268
+ */
269
+ /*
270
+ * Note the missing parameter: an earlier version took the mount function, and the
271
+ * first caller passed the one that BUILDS rather than the one that ADOPTS — so the
272
+ * island quietly rendered a second copy of itself beside the server's. An API that
273
+ * makes the wrong choice expressible will eventually have it chosen.
274
+ */
275
+ export function hydrateIslands(host, root, registry, options = {}) {
276
+ return createIslandManager(host, registry, options).hydrate(root);
277
+ }
278
+ //# sourceMappingURL=island.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"island.js","sourceRoot":"","sources":["../../../../../packages/ketjs-view/src/island.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { Fragment, jsx as jsxDEV } from './jsx-runtime.ts';
2
+ export type { JSX, JSXChild, JSXComponent, IntrinsicProps } from './jsx-runtime.ts';
3
+ //# sourceMappingURL=jsx-dev-runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsx-dev-runtime.d.ts","sourceRoot":"","sources":["../../../../packages/ketjs-view/src/jsx-dev-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,GAAG,IAAI,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAC1D,YAAY,EAAE,GAAG,EAAE,QAAQ,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA"}
@@ -0,0 +1,2 @@
1
+ export { Fragment, jsx as jsxDEV } from './jsx-runtime.js';
2
+ //# sourceMappingURL=jsx-dev-runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsx-dev-runtime.js","sourceRoot":"","sources":["../../../../../packages/ketjs-view/src/jsx-dev-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,GAAG,IAAI,MAAM,EAAE,MAAM,kBAAkB,CAAA"}
@@ -0,0 +1,46 @@
1
+ import type { Renderable, TemplateResult } from './render.ts';
2
+ /** JSX additionally normalises nested arrays into fragments before rendering. */
3
+ export type JSXChild = Renderable | readonly JSXChild[];
4
+ export type JSXComponent<Props = Record<string, unknown>> = (props: Props) => TemplateResult;
5
+ export type IntrinsicProps = {
6
+ children?: JSXChild;
7
+ class?: string;
8
+ className?: string;
9
+ id?: string;
10
+ title?: string;
11
+ role?: string;
12
+ href?: string | null;
13
+ type?: string;
14
+ name?: string | null;
15
+ value?: unknown;
16
+ disabled?: boolean;
17
+ checked?: boolean;
18
+ selected?: boolean;
19
+ hidden?: boolean;
20
+ style?: string | Record<string, string | number | null | undefined>;
21
+ onClick?: (event: Event) => void;
22
+ onInput?: (event: Event) => void;
23
+ onChange?: (event: Event) => void;
24
+ onSubmit?: (event: Event) => void;
25
+ [name: string]: unknown;
26
+ };
27
+ export declare namespace JSX {
28
+ type Element = TemplateResult;
29
+ type ElementType = string | JSXComponent<never>;
30
+ interface ElementChildrenAttribute {
31
+ children: JSXChild;
32
+ }
33
+ interface IntrinsicElements {
34
+ [tag: string]: IntrinsicProps;
35
+ }
36
+ }
37
+ type RuntimeProps = Record<string, unknown> & {
38
+ children?: JSXChild;
39
+ };
40
+ export declare function jsx(type: string | JSXComponent<RuntimeProps>, properties: RuntimeProps | null, _key?: unknown): TemplateResult;
41
+ export declare const jsxs: typeof jsx;
42
+ export declare function Fragment(props: {
43
+ children?: JSXChild;
44
+ }): TemplateResult;
45
+ export {};
46
+ //# sourceMappingURL=jsx-runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsx-runtime.d.ts","sourceRoot":"","sources":["../../../../packages/ketjs-view/src/jsx-runtime.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAE7D,iFAAiF;AACjF,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,SAAS,QAAQ,EAAE,CAAA;AACvD,MAAM,MAAM,YAAY,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,KAAK,cAAc,CAAA;AAE5F,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,EAAE,QAAQ,CAAA;IACnB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAA;IACnE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;IAChC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;IAChC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;IACjC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;IACjC,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;CACxB,CAAA;AAED,yBAAiB,GAAG,CAAC;IACnB,KAAY,OAAO,GAAG,cAAc,CAAA;IACpC,KAAY,WAAW,GAAG,MAAM,GAAG,YAAY,CAAC,KAAK,CAAC,CAAA;IACtD,UAAiB,wBAAwB;QACvC,QAAQ,EAAE,QAAQ,CAAA;KACnB;IACD,UAAiB,iBAAiB;QAChC,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAAA;KAC9B;CACF;AA8ED,KAAK,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAAE,QAAQ,CAAC,EAAE,QAAQ,CAAA;CAAE,CAAA;AAErE,wBAAgB,GAAG,CACjB,IAAI,EAAE,MAAM,GAAG,YAAY,CAAC,YAAY,CAAC,EACzC,UAAU,EAAE,YAAY,GAAG,IAAI,EAC/B,IAAI,CAAC,EAAE,OAAO,GACb,cAAc,CAsChB;AAED,eAAO,MAAM,IAAI,YAAM,CAAA;AAEvB,wBAAgB,QAAQ,CAAC,KAAK,EAAE;IAAE,QAAQ,CAAC,EAAE,QAAQ,CAAA;CAAE,GAAG,cAAc,CAGvE"}
@@ -0,0 +1,117 @@
1
+ // The automatic JSX runtime for Ket.
2
+ //
3
+ // JSX is authoring syntax only. It compiles to calls in this file, and those calls
4
+ // produce the same TemplateResult the tagged-template API does. There is no VDOM:
5
+ // static element shapes are cached, while props and children remain renderer holes.
6
+ import { html } from './render.js';
7
+ const VOID = new Set([
8
+ 'area',
9
+ 'base',
10
+ 'br',
11
+ 'col',
12
+ 'embed',
13
+ 'hr',
14
+ 'img',
15
+ 'input',
16
+ 'link',
17
+ 'meta',
18
+ 'source',
19
+ 'track',
20
+ 'wbr',
21
+ ]);
22
+ const TAG = /^[a-z][a-z0-9-]*$/;
23
+ const ATTRIBUTE = /^[A-Za-z_:][A-Za-z0-9:._-]*$/;
24
+ const shapeCache = new Map();
25
+ const fragmentCache = new Map();
26
+ const templateStrings = (segments) => {
27
+ const strings = [...segments];
28
+ Object.defineProperty(strings, 'raw', { value: Object.freeze([...segments]), enumerable: false });
29
+ return Object.freeze(strings);
30
+ };
31
+ const shapeFor = (tag, attributes, hasChildren) => {
32
+ const key = JSON.stringify([tag, attributes, hasChildren]);
33
+ const cached = shapeCache.get(key);
34
+ if (cached)
35
+ return cached;
36
+ const segments = [`<${tag}`];
37
+ for (const name of attributes) {
38
+ segments[segments.length - 1] += ` ${name}=`;
39
+ segments.push('');
40
+ }
41
+ segments[segments.length - 1] += '>';
42
+ if (hasChildren)
43
+ segments.push('');
44
+ if (!VOID.has(tag))
45
+ segments[segments.length - 1] += `</${tag}>`;
46
+ const strings = templateStrings(segments);
47
+ shapeCache.set(key, strings);
48
+ return strings;
49
+ };
50
+ const fragmentShape = (length) => {
51
+ const cached = fragmentCache.get(length);
52
+ if (cached)
53
+ return cached;
54
+ const strings = templateStrings(Array.from({ length: length + 1 }, () => ''));
55
+ fragmentCache.set(length, strings);
56
+ return strings;
57
+ };
58
+ const fragment = (children) => {
59
+ const values = Array.isArray(children) ? children.map(normalizeChild) : [normalizeChild(children)];
60
+ return html(fragmentShape(values.length), ...values);
61
+ };
62
+ const normalizeChild = (child) => (Array.isArray(child) ? fragment(child) : child);
63
+ const cssName = (name) => name.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
64
+ const styleValue = (value) => {
65
+ if (!value || typeof value !== 'object' || Array.isArray(value))
66
+ return value;
67
+ return Object.entries(value)
68
+ .filter(([, part]) => part != null && part !== false)
69
+ .map(([name, part]) => `${cssName(name)}:${String(part)}`)
70
+ .join(';');
71
+ };
72
+ const attributeName = (name) => {
73
+ if (name === 'className')
74
+ return 'class';
75
+ if (name === 'htmlFor')
76
+ return 'for';
77
+ if (/^on[A-Z]/.test(name))
78
+ return `on:${name.slice(2).toLowerCase()}`;
79
+ return name;
80
+ };
81
+ export function jsx(type, properties, _key) {
82
+ const props = properties ?? {};
83
+ if (typeof type === 'function')
84
+ return type(props);
85
+ if (!TAG.test(type))
86
+ throw new TypeError(`invalid JSX element name "${type}"`);
87
+ if ('dangerouslySetInnerHTML' in props) {
88
+ throw new TypeError('Ket JSX has no dangerouslySetInnerHTML; pass trusted compiler output through trustedMarkup()');
89
+ }
90
+ if ('ref' in props)
91
+ throw new TypeError('Ket JSX does not expose mutable element refs');
92
+ const entries = Object.entries(props)
93
+ .filter(([name]) => name !== 'children' && name !== 'key')
94
+ .map(([sourceName, value]) => ({ sourceName, name: attributeName(sourceName), value }));
95
+ const seen = new Set();
96
+ for (const entry of entries) {
97
+ if (!ATTRIBUTE.test(entry.name))
98
+ throw new TypeError(`invalid JSX attribute name "${entry.name}"`);
99
+ if (seen.has(entry.name))
100
+ throw new TypeError(`JSX attribute "${entry.name}" was provided more than once`);
101
+ seen.add(entry.name);
102
+ }
103
+ const hasChildren = props.children !== undefined && props.children !== null && props.children !== false;
104
+ if (VOID.has(type) && hasChildren)
105
+ throw new TypeError(`<${type}> is a void element and cannot have children`);
106
+ const values = entries.map((entry) => entry.sourceName === 'style' ? styleValue(entry.value) : entry.value);
107
+ if (hasChildren)
108
+ values.push(normalizeChild(props.children));
109
+ return html(shapeFor(type, entries.map((entry) => entry.name), hasChildren), ...values);
110
+ }
111
+ export const jsxs = jsx;
112
+ export function Fragment(props) {
113
+ if (props.children === undefined || props.children === null || props.children === false)
114
+ return fragment([]);
115
+ return fragment(props.children);
116
+ }
117
+ //# sourceMappingURL=jsx-runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsx-runtime.js","sourceRoot":"","sources":["../../../../../packages/ketjs-view/src/jsx-runtime.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { TemplateResult } from './render.ts';
2
+ import type { Host, HostNode } from './host.ts';
3
+ export type Mounted = {
4
+ /** Stop re-rendering. The DOM is left as it is. */
5
+ dispose(): void;
6
+ /** Render once, outside the reactive graph. */
7
+ refresh(): void;
8
+ };
9
+ /** Render into a container and keep it in sync with whatever signals the view reads. */
10
+ export declare function mount(host: Host, container: HostNode, view: () => TemplateResult): Mounted;
11
+ /** The same, but adopting server-rendered markup rather than building it. */
12
+ export declare function mountHydrated(host: Host, container: HostNode, view: () => TemplateResult): Mounted;
13
+ //# sourceMappingURL=mount.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mount.d.ts","sourceRoot":"","sources":["../../../../packages/ketjs-view/src/mount.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAQ,cAAc,EAAE,MAAM,aAAa,CAAA;AAEvD,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAE/C,MAAM,MAAM,OAAO,GAAG;IACpB,mDAAmD;IACnD,OAAO,IAAI,IAAI,CAAA;IACf,+CAA+C;IAC/C,OAAO,IAAI,IAAI,CAAA;CAChB,CAAA;AAeD,wFAAwF;AACxF,wBAAgB,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,cAAc,GAAG,OAAO,CAE1F;AAED,6EAA6E;AAC7E,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,cAAc,GAAG,OAAO,CAclG"}
package/dist/mount.js ADDED
@@ -0,0 +1,44 @@
1
+ // Where reactivity meets rendering.
2
+ //
3
+ // The renderer and the signal graph were built separately on purpose — one knows
4
+ // nothing about the other, and each is testable alone. This is the twenty lines
5
+ // that join them: an effect that re-renders, so reading a signal inside a view
6
+ // subscribes the view to it. Nothing else in the framework depends on this file,
7
+ // so a caller who wants to drive renders by hand still can.
8
+ import { createRoot, hydrateRoot } from './render.js';
9
+ import { effect } from './signal.js';
10
+ function drive(root, view) {
11
+ const stop = effect(() => {
12
+ root.render(view());
13
+ });
14
+ return {
15
+ dispose: () => {
16
+ stop();
17
+ root.dispose();
18
+ },
19
+ refresh: () => root.render(view()),
20
+ };
21
+ }
22
+ /** Render into a container and keep it in sync with whatever signals the view reads. */
23
+ export function mount(host, container, view) {
24
+ return drive(createRoot(host, container), view);
25
+ }
26
+ /** The same, but adopting server-rendered markup rather than building it. */
27
+ export function mountHydrated(host, container, view) {
28
+ let root = null;
29
+ const stop = effect(() => {
30
+ const result = view();
31
+ if (root)
32
+ root.render(result);
33
+ else
34
+ root = hydrateRoot(host, container, result);
35
+ });
36
+ return {
37
+ dispose: () => {
38
+ stop();
39
+ root?.dispose();
40
+ },
41
+ refresh: () => root?.render(view()),
42
+ };
43
+ }
44
+ //# sourceMappingURL=mount.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mount.js","sourceRoot":"","sources":["../../../../../packages/ketjs-view/src/mount.ts"],"names":[],"mappings":"AAAA,oCAAoC;AACpC,EAAE;AACF,iFAAiF;AACjF,gFAAgF;AAChF,+EAA+E;AAC/E,iFAAiF;AACjF,4DAA4D;AAE5D,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAErD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAUpC,SAAS,KAAK,CAAC,IAAU,EAAE,IAA0B;IACnD,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,EAAE;QACvB,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAA;IACrB,CAAC,CAAC,CAAA;IACF,OAAO;QACL,OAAO,EAAE,GAAG,EAAE;YACZ,IAAI,EAAE,CAAA;YACN,IAAI,CAAC,OAAO,EAAE,CAAA;QAChB,CAAC;QACD,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;KACnC,CAAA;AACH,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,KAAK,CAAC,IAAU,EAAE,SAAmB,EAAE,IAA0B;IAC/E,OAAO,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE,IAAI,CAAC,CAAA;AACjD,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,aAAa,CAAC,IAAU,EAAE,SAAmB,EAAE,IAA0B;IACvF,IAAI,IAAI,GAAgB,IAAI,CAAA;IAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,EAAE;QACvB,MAAM,MAAM,GAAG,IAAI,EAAE,CAAA;QACrB,IAAI,IAAI;YAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;;YACxB,IAAI,GAAG,WAAW,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,CAAC,CAAA;IAClD,CAAC,CAAC,CAAA;IACF,OAAO;QACL,OAAO,EAAE,GAAG,EAAE;YACZ,IAAI,EAAE,CAAA;YACN,IAAI,EAAE,OAAO,EAAE,CAAA;QACjB,CAAC;QACD,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;KACpC,CAAA;AACH,CAAC"}
@@ -0,0 +1,39 @@
1
+ import type { Host, HostNode } from './host.ts';
2
+ import type { Markup } from './ssr.ts';
3
+ declare const RESULT: unique symbol;
4
+ declare const EACH: unique symbol;
5
+ export type TemplateResult = {
6
+ [RESULT]: true;
7
+ strings: readonly string[];
8
+ values: unknown[];
9
+ };
10
+ export type EachResult = {
11
+ [EACH]: true;
12
+ items: unknown[];
13
+ keyOf: (item: unknown, i: number) => unknown;
14
+ render: (item: unknown, i: number) => TemplateResult;
15
+ };
16
+ /** Values the renderer understands without falling back to `[object Object]`. */
17
+ export type Renderable = TemplateResult | EachResult | Markup | string | number | boolean | null | undefined;
18
+ export declare function html(strings: TemplateStringsArray, ...values: unknown[]): TemplateResult;
19
+ export declare const isResult: (v: unknown) => v is TemplateResult;
20
+ export declare function each<T>(items: Iterable<T>, keyOf: (item: T, i: number) => unknown, render: (item: T, i: number) => TemplateResult): EachResult;
21
+ export declare const isEach: (v: unknown) => v is EachResult;
22
+ export declare function when(cond: unknown, render: () => TemplateResult, otherwise?: () => TemplateResult): TemplateResult | string;
23
+ export declare const EVENT_PREFIX = "on:";
24
+ export type Root = {
25
+ render(result: TemplateResult): void;
26
+ /** Detach behaviour; optionally remove the rendered nodes too. */
27
+ dispose(options?: {
28
+ remove?: boolean;
29
+ }): void;
30
+ };
31
+ export declare function createRoot(host: Host, container: HostNode): Root;
32
+ /**
33
+ * Attach to server-rendered markup. On a mismatch it throws rather than silently
34
+ * patching over a difference, because a hydration that half-works is worse than one
35
+ * that fails loudly: the caller can fall back to a clean client render.
36
+ */
37
+ export declare function hydrateRoot(host: Host, container: HostNode, result: TemplateResult): Root;
38
+ export {};
39
+ //# sourceMappingURL=render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../../../packages/ketjs-view/src/render.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAE/C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AAEtC,QAAA,MAAM,MAAM,eAAuB,CAAA;AACnC,QAAA,MAAM,IAAI,eAAqB,CAAA;AAE/B,MAAM,MAAM,cAAc,GAAG;IAAE,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,MAAM,EAAE,OAAO,EAAE,CAAA;CAAE,CAAA;AAC9F,MAAM,MAAM,UAAU,GAAG;IACvB,CAAC,IAAI,CAAC,EAAE,IAAI,CAAA;IACZ,KAAK,EAAE,OAAO,EAAE,CAAA;IAChB,KAAK,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAA;IAC5C,MAAM,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,cAAc,CAAA;CACrD,CAAA;AACD,iFAAiF;AACjF,MAAM,MAAM,UAAU,GAAG,cAAc,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAA;AAE5G,wBAAgB,IAAI,CAAC,OAAO,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,cAAc,CAExF;AACD,eAAO,MAAM,QAAQ,MAAO,OAAO,KAAG,CAAC,IAAI,cAAmD,CAAA;AAE9F,wBAAgB,IAAI,CAAC,CAAC,EACpB,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,EAClB,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,EACtC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,KAAK,cAAc,GAC7C,UAAU,CAOZ;AACD,eAAO,MAAM,MAAM,MAAO,OAAO,KAAG,CAAC,IAAI,UAAyC,CAAA;AAElF,wBAAgB,IAAI,CAClB,IAAI,EAAE,OAAO,EACb,MAAM,EAAE,MAAM,cAAc,EAC5B,SAAS,CAAC,EAAE,MAAM,cAAc,GAC/B,cAAc,GAAG,MAAM,CAEzB;AAWD,eAAO,MAAM,YAAY,QAAQ,CAAA;AA6VjC,MAAM,MAAM,IAAI,GAAG;IACjB,MAAM,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAAA;IACpC,kEAAkE;IAClE,OAAO,CAAC,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAA;CAC9C,CAAA;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,GAAG,IAAI,CAgBhE;AA8ID;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,cAAc,GAAG,IAAI,CAuBzF"}