@hypen-space/web 0.4.980 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. package/README.md +20 -13
  2. package/dist/canvas/events.js +46 -7
  3. package/dist/canvas/events.js.map +1 -1
  4. package/dist/canvas/index.d.ts +0 -1
  5. package/dist/canvas/index.js +0 -1
  6. package/dist/canvas/index.js.map +1 -1
  7. package/dist/canvas/layout.js +68 -98
  8. package/dist/canvas/layout.js.map +1 -1
  9. package/dist/canvas/paint.js +168 -71
  10. package/dist/canvas/paint.js.map +1 -1
  11. package/dist/canvas/renderer.d.ts +8 -3
  12. package/dist/canvas/renderer.js +32 -43
  13. package/dist/canvas/renderer.js.map +1 -1
  14. package/dist/canvas/text.js +2 -9
  15. package/dist/canvas/text.js.map +1 -1
  16. package/dist/canvas/types.d.ts +3 -0
  17. package/dist/canvas/utils.d.ts +0 -23
  18. package/dist/canvas/utils.js +3 -67
  19. package/dist/canvas/utils.js.map +1 -1
  20. package/dist/canvas/variants.d.ts +49 -0
  21. package/dist/canvas/variants.js +137 -0
  22. package/dist/canvas/variants.js.map +1 -0
  23. package/dist/dom/applicators/events.js +1 -0
  24. package/dist/dom/applicators/events.js.map +1 -1
  25. package/dist/dom/applicators/font.d.ts +11 -6
  26. package/dist/dom/applicators/font.js +16 -27
  27. package/dist/dom/applicators/font.js.map +1 -1
  28. package/dist/dom/applicators/index.js +47 -45
  29. package/dist/dom/applicators/index.js.map +1 -1
  30. package/dist/dom/canvas/index.js +2 -2
  31. package/dist/dom/canvas/index.js.map +1 -1
  32. package/dist/dom/components/app.js +2 -2
  33. package/dist/dom/components/app.js.map +1 -1
  34. package/dist/dom/components/audio.js +2 -2
  35. package/dist/dom/components/audio.js.map +1 -1
  36. package/dist/dom/components/avatar.js +3 -4
  37. package/dist/dom/components/avatar.js.map +1 -1
  38. package/dist/dom/components/badge.js +3 -4
  39. package/dist/dom/components/badge.js.map +1 -1
  40. package/dist/dom/components/button.js +2 -2
  41. package/dist/dom/components/button.js.map +1 -1
  42. package/dist/dom/components/card.js +2 -2
  43. package/dist/dom/components/card.js.map +1 -1
  44. package/dist/dom/components/center.js +2 -2
  45. package/dist/dom/components/center.js.map +1 -1
  46. package/dist/dom/components/checkbox.js +4 -5
  47. package/dist/dom/components/checkbox.js.map +1 -1
  48. package/dist/dom/components/column.js +2 -2
  49. package/dist/dom/components/column.js.map +1 -1
  50. package/dist/dom/components/container.js +2 -2
  51. package/dist/dom/components/container.js.map +1 -1
  52. package/dist/dom/components/divider.js +2 -2
  53. package/dist/dom/components/divider.js.map +1 -1
  54. package/dist/dom/components/grid.js +10 -10
  55. package/dist/dom/components/grid.js.map +1 -1
  56. package/dist/dom/components/heading.js +4 -6
  57. package/dist/dom/components/heading.js.map +1 -1
  58. package/dist/dom/components/hypenapp.js +2 -2
  59. package/dist/dom/components/hypenapp.js.map +1 -1
  60. package/dist/dom/components/icon.js +4 -5
  61. package/dist/dom/components/icon.js.map +1 -1
  62. package/dist/dom/components/image.js +2 -2
  63. package/dist/dom/components/image.js.map +1 -1
  64. package/dist/dom/components/index.d.ts +2 -2
  65. package/dist/dom/components/index.js +2 -2
  66. package/dist/dom/components/index.js.map +1 -1
  67. package/dist/dom/components/input.js +2 -2
  68. package/dist/dom/components/input.js.map +1 -1
  69. package/dist/dom/components/link.js +2 -2
  70. package/dist/dom/components/link.js.map +1 -1
  71. package/dist/dom/components/list.js +2 -2
  72. package/dist/dom/components/list.js.map +1 -1
  73. package/dist/dom/components/paragraph.js +3 -4
  74. package/dist/dom/components/paragraph.js.map +1 -1
  75. package/dist/dom/components/progressbar.js +3 -3
  76. package/dist/dom/components/progressbar.js.map +1 -1
  77. package/dist/dom/components/route.js +2 -2
  78. package/dist/dom/components/route.js.map +1 -1
  79. package/dist/dom/components/router.js +2 -2
  80. package/dist/dom/components/router.js.map +1 -1
  81. package/dist/dom/components/row.js +10 -10
  82. package/dist/dom/components/row.js.map +1 -1
  83. package/dist/dom/components/select.js +3 -4
  84. package/dist/dom/components/select.js.map +1 -1
  85. package/dist/dom/components/slider.js +2 -2
  86. package/dist/dom/components/slider.js.map +1 -1
  87. package/dist/dom/components/spacer.js +2 -2
  88. package/dist/dom/components/spacer.js.map +1 -1
  89. package/dist/dom/components/spinner.js +4 -4
  90. package/dist/dom/components/spinner.js.map +1 -1
  91. package/dist/dom/components/stack.js +10 -10
  92. package/dist/dom/components/stack.js.map +1 -1
  93. package/dist/dom/components/switch.js +5 -6
  94. package/dist/dom/components/switch.js.map +1 -1
  95. package/dist/dom/components/text.js +4 -7
  96. package/dist/dom/components/text.js.map +1 -1
  97. package/dist/dom/components/textarea.js +2 -2
  98. package/dist/dom/components/textarea.js.map +1 -1
  99. package/dist/dom/components/video.js +2 -2
  100. package/dist/dom/components/video.js.map +1 -1
  101. package/dist/dom/debug.js +6 -8
  102. package/dist/dom/debug.js.map +1 -1
  103. package/dist/dom/index.d.ts +0 -1
  104. package/dist/dom/index.js +0 -1
  105. package/dist/dom/index.js.map +1 -1
  106. package/dist/dom/renderer.js +2 -3
  107. package/dist/dom/renderer.js.map +1 -1
  108. package/dist/variants.d.ts +90 -0
  109. package/dist/variants.js +206 -0
  110. package/dist/variants.js.map +1 -0
  111. package/package.json +2 -2
  112. package/src/canvas/QUICKSTART.md +12 -7
  113. package/src/canvas/README.md +8 -5
  114. package/src/canvas/events.ts +49 -7
  115. package/src/canvas/index.ts +0 -8
  116. package/src/canvas/layout.ts +68 -103
  117. package/src/canvas/paint.ts +172 -69
  118. package/src/canvas/renderer.ts +38 -46
  119. package/src/canvas/text.ts +2 -9
  120. package/src/canvas/types.ts +14 -0
  121. package/src/canvas/utils.ts +3 -69
  122. package/src/canvas/variants.ts +153 -0
  123. package/src/dom/README.md +8 -7
  124. package/src/dom/applicators/events.ts +1 -0
  125. package/src/dom/applicators/font.ts +16 -29
  126. package/src/dom/applicators/index.ts +56 -46
  127. package/src/dom/canvas/index.ts +2 -2
  128. package/src/dom/components/app.ts +2 -2
  129. package/src/dom/components/audio.ts +2 -2
  130. package/src/dom/components/avatar.ts +3 -4
  131. package/src/dom/components/badge.ts +3 -4
  132. package/src/dom/components/button.ts +2 -2
  133. package/src/dom/components/card.ts +2 -2
  134. package/src/dom/components/center.ts +2 -2
  135. package/src/dom/components/checkbox.ts +4 -5
  136. package/src/dom/components/column.ts +2 -2
  137. package/src/dom/components/container.ts +2 -2
  138. package/src/dom/components/divider.ts +2 -2
  139. package/src/dom/components/grid.ts +10 -10
  140. package/src/dom/components/heading.ts +4 -6
  141. package/src/dom/components/hypenapp.ts +2 -2
  142. package/src/dom/components/icon.ts +4 -5
  143. package/src/dom/components/image.ts +2 -2
  144. package/src/dom/components/index.ts +3 -3
  145. package/src/dom/components/input.ts +2 -2
  146. package/src/dom/components/link.ts +2 -2
  147. package/src/dom/components/list.ts +2 -2
  148. package/src/dom/components/paragraph.ts +3 -4
  149. package/src/dom/components/progressbar.ts +3 -3
  150. package/src/dom/components/route.ts +2 -2
  151. package/src/dom/components/router.ts +2 -2
  152. package/src/dom/components/row.ts +10 -10
  153. package/src/dom/components/select.ts +3 -4
  154. package/src/dom/components/slider.ts +2 -2
  155. package/src/dom/components/spacer.ts +2 -2
  156. package/src/dom/components/spinner.ts +4 -4
  157. package/src/dom/components/stack.ts +10 -10
  158. package/src/dom/components/switch.ts +5 -6
  159. package/src/dom/components/text.ts +4 -7
  160. package/src/dom/components/textarea.ts +2 -2
  161. package/src/dom/components/video.ts +2 -2
  162. package/src/dom/debug.ts +6 -8
  163. package/src/dom/index.ts +0 -8
  164. package/src/dom/renderer.ts +2 -3
  165. package/src/variants.ts +249 -0
  166. package/dist/client.d.ts +0 -36
  167. package/dist/client.js +0 -47
  168. package/dist/client.js.map +0 -1
  169. package/src/client.ts +0 -88
@@ -0,0 +1,249 @@
1
+ /**
2
+ * Shared variant (responsive breakpoint + interaction state) support.
3
+ *
4
+ * The engine emits applicator props using the canonical key format:
5
+ *
6
+ * <camelBase><variant?><argSuffix>
7
+ *
8
+ * - camelBase: camelCase applicator name, e.g. "padding", "backgroundColor"
9
+ * - variant?: "@<bp>" and/or ":<state>", in that order if combined.
10
+ * bp in { sm, md, lg, xl, 2xl }
11
+ * state in { hover, focus, active, disabled,
12
+ * focus-visible, focus-within }
13
+ * combined example: "backgroundColor@md:hover" (BOTH md AND hover)
14
+ * - argSuffix: ".<index>" (almost always ".0") or ".<name>" for named args.
15
+ *
16
+ * Examples emitted by the engine:
17
+ * "padding.0", "padding@md.0", "backgroundColor:hover.0",
18
+ * "backgroundColor@md:hover.0".
19
+ *
20
+ * IMPORTANT: the variant marker sits BETWEEN the base name and the ".0" arg
21
+ * suffix. A lookup that forgets the ".0" (e.g. building just "padding@md")
22
+ * MISSES the real key. Always parse the variant out of the full key.
23
+ *
24
+ * Both the DOM applicator path and the Canvas renderer import this module so
25
+ * breakpoint pixels, state names, and precedence stay byte-compatible across
26
+ * renderers. The DOM renderer leans on the CSS engine for actual resolution
27
+ * (media queries + pseudo-classes), so it only needs PARSE_* here; Canvas does
28
+ * its own paint/layout and therefore also uses the runtime resolver.
29
+ */
30
+
31
+ /**
32
+ * Tailwind breakpoint min-widths (px). Order matters: ascending min-width.
33
+ * Mirrors the DOM `BREAKPOINTS` table and the iOS reference.
34
+ */
35
+ export const BREAKPOINTS: Record<string, number> = {
36
+ sm: 640,
37
+ md: 768,
38
+ lg: 1024,
39
+ xl: 1280,
40
+ "2xl": 1536,
41
+ };
42
+
43
+ /** Breakpoint names in ascending min-width order (sm < md < lg < xl < 2xl). */
44
+ export const BREAKPOINT_ORDER: readonly string[] = ["sm", "md", "lg", "xl", "2xl"];
45
+
46
+ /** Interaction-state names recognised in variant keys (same set as the DOM). */
47
+ export const VALID_STATES: readonly string[] = [
48
+ "hover",
49
+ "focus",
50
+ "active",
51
+ "disabled",
52
+ "focus-visible",
53
+ "focus-within",
54
+ ];
55
+ const VALID_STATE_SET = new Set(VALID_STATES);
56
+
57
+ /** Parsed shape of a single prop key. */
58
+ export interface ParsedVariantKey {
59
+ /** camelCase base applicator name, e.g. "backgroundColor". */
60
+ base: string;
61
+ /** Breakpoint name (sm/md/lg/xl/2xl) or null if none. */
62
+ breakpoint: string | null;
63
+ /** Interaction state name or null if none. */
64
+ state: string | null;
65
+ /** Arg suffix without the leading dot (e.g. "0", "to"), or null if none. */
66
+ arg: string | null;
67
+ }
68
+
69
+ /**
70
+ * Parse a prop key into `{ base, breakpoint, state, arg }`.
71
+ *
72
+ * Splits the arg suffix first (the LAST `.<token>`), then peels the variant
73
+ * markers (`@bp` and/or `:state`) off the remainder. An unknown breakpoint or
74
+ * state is left as part of the base name (caller decides what to do); this
75
+ * matches the DOM behaviour where an invalid `@invalid` / `:invalid` simply
76
+ * never matches a real variant.
77
+ *
78
+ * Examples:
79
+ * "padding.0" -> { base:"padding", breakpoint:null, state:null, arg:"0" }
80
+ * "padding@md.0" -> { base:"padding", breakpoint:"md", state:null, arg:"0" }
81
+ * "backgroundColor:hover.0" -> { base:"backgroundColor", breakpoint:null, state:"hover", arg:"0" }
82
+ * "backgroundColor@md:hover.0" -> { base:"backgroundColor", breakpoint:"md", state:"hover", arg:"0" }
83
+ * "backgroundColor@md:hover" -> { base:"backgroundColor", breakpoint:"md", state:"hover", arg:null }
84
+ */
85
+ export function parseVariantKey(key: string): ParsedVariantKey {
86
+ let work = key;
87
+ let arg: string | null = null;
88
+
89
+ // Peel the arg suffix: the segment after the LAST dot, but only if that dot
90
+ // comes AFTER any variant markers (so we never split inside "focus-within"
91
+ // — that has no dot — and never treat "padding" alone as having an arg).
92
+ const lastDot = work.lastIndexOf(".");
93
+ if (lastDot > 0) {
94
+ arg = work.slice(lastDot + 1);
95
+ work = work.slice(0, lastDot);
96
+ }
97
+
98
+ // Peel the state marker (":state") off the end of the remainder.
99
+ let state: string | null = null;
100
+ const colon = work.indexOf(":");
101
+ if (colon !== -1) {
102
+ const candidate = work.slice(colon + 1);
103
+ if (VALID_STATE_SET.has(candidate)) {
104
+ state = candidate;
105
+ work = work.slice(0, colon);
106
+ }
107
+ }
108
+
109
+ // Peel the breakpoint marker ("@bp").
110
+ let breakpoint: string | null = null;
111
+ const at = work.indexOf("@");
112
+ if (at !== -1) {
113
+ const candidate = work.slice(at + 1);
114
+ if (candidate in BREAKPOINTS) {
115
+ breakpoint = candidate;
116
+ work = work.slice(0, at);
117
+ }
118
+ }
119
+
120
+ return { base: work, breakpoint, state, arg };
121
+ }
122
+
123
+ /** The set of interaction states currently active on a node. */
124
+ export interface ActiveStates {
125
+ hover?: boolean;
126
+ focus?: boolean;
127
+ active?: boolean;
128
+ disabled?: boolean;
129
+ "focus-visible"?: boolean;
130
+ "focus-within"?: boolean;
131
+ }
132
+
133
+ /**
134
+ * Precedence rank for a parsed variant (higher wins). Combines the breakpoint
135
+ * tier and the state tier into a single sortable number.
136
+ *
137
+ * Precedence (low -> high), later overrides earlier:
138
+ * base
139
+ * < breakpoints ascending (sm < md < lg < xl < 2xl)
140
+ * < disabled < hover < focus < active
141
+ *
142
+ * State always outranks any breakpoint (a `:hover` override beats a `@2xl`
143
+ * sizing override on the same prop), matching the iOS reference where state
144
+ * overrides are merged AFTER the responsive base. Within the same state tier,
145
+ * a higher breakpoint still breaks the tie so `@md:hover` beats `:hover`.
146
+ */
147
+ const STATE_RANK: Record<string, number> = {
148
+ disabled: 1,
149
+ hover: 2,
150
+ // focus-visible / focus-within are focus-flavoured states: they share the
151
+ // `focus` precedence slot (NOT base/0) so they outrank hover and lose to
152
+ // active, matching the engine's `state_rank` in portable/variant.rs.
153
+ focus: 3,
154
+ "focus-visible": 3,
155
+ "focus-within": 3,
156
+ active: 4,
157
+ };
158
+
159
+ // State tier must be weighted by a value strictly greater than the largest
160
+ // possible breakpoint tier so the bp tiebreak can never leak across state
161
+ // bands (mirrors the engine's STATE_STEP > max-breakpoint invariant). Derived
162
+ // from BREAKPOINT_ORDER.length so adding breakpoints can't silently break it.
163
+ const STATE_WEIGHT = BREAKPOINT_ORDER.length + 1;
164
+
165
+ function variantRank(breakpoint: string | null, state: string | null): number {
166
+ const bpTier = breakpoint ? BREAKPOINT_ORDER.indexOf(breakpoint) + 1 : 0; // 0..len
167
+ const stateTier = state ? STATE_RANK[state] ?? 0 : 0; // 0..4
168
+ // State tier dominates; breakpoint tier breaks ties within a state tier.
169
+ return stateTier * STATE_WEIGHT + bpTier;
170
+ }
171
+
172
+ /**
173
+ * Is a parsed variant currently applicable, given the viewport width and the
174
+ * active interaction states? A combined key requires BOTH conditions.
175
+ */
176
+ function variantApplies(
177
+ parsed: ParsedVariantKey,
178
+ width: number,
179
+ states: ActiveStates,
180
+ ): boolean {
181
+ if (parsed.breakpoint) {
182
+ const minWidth = BREAKPOINTS[parsed.breakpoint];
183
+ if (minWidth === undefined || width < minWidth) return false;
184
+ }
185
+ if (parsed.state) {
186
+ if (!states[parsed.state as keyof ActiveStates]) return false;
187
+ }
188
+ return true;
189
+ }
190
+
191
+ /**
192
+ * Resolve variant-bearing props against the current viewport width and active
193
+ * interaction states, producing a flat map of `base -> winning value`.
194
+ *
195
+ * Input keys are the already-normalised flat applicator keys (variant markers
196
+ * present, arg suffix already stripped by the applicator-grouping pass), e.g.
197
+ * `{ padding: 8, "padding@md": 16, "backgroundColor:hover": "red" }`.
198
+ *
199
+ * Only bases that actually have at least one applicable variant appear in the
200
+ * result with an overridden value; a base with only its plain entry resolves to
201
+ * that plain value. The caller merges the result over the node's base props.
202
+ */
203
+ export function resolveVariantProps(
204
+ props: Record<string, unknown>,
205
+ width: number,
206
+ states: ActiveStates,
207
+ ): Record<string, unknown> {
208
+ // base -> { value, rank }
209
+ const winners = new Map<string, { value: unknown; rank: number }>();
210
+
211
+ for (const key of Object.keys(props)) {
212
+ const parsed = parseVariantKey(key);
213
+ // Only consider entries that carry a variant marker. Plain keys (no bp/state)
214
+ // are the base and are handled implicitly via rank 0 below so a base with a
215
+ // single applicable variant still falls back to base when the variant is off.
216
+ if (!parsed.breakpoint && !parsed.state) {
217
+ // Seed the base value at rank 0 so variant lookups have a fallback and so
218
+ // a base that ALSO has variants resolves correctly when none apply.
219
+ const existing = winners.get(parsed.base);
220
+ if (!existing || existing.rank === 0) {
221
+ winners.set(parsed.base, { value: props[key], rank: 0 });
222
+ }
223
+ continue;
224
+ }
225
+
226
+ if (!variantApplies(parsed, width, states)) continue;
227
+
228
+ const rank = variantRank(parsed.breakpoint, parsed.state);
229
+ const existing = winners.get(parsed.base);
230
+ if (!existing || rank >= existing.rank) {
231
+ winners.set(parsed.base, { value: props[key], rank });
232
+ }
233
+ }
234
+
235
+ const out: Record<string, unknown> = {};
236
+ for (const [base, win] of winners) {
237
+ out[base] = win.value;
238
+ }
239
+ return out;
240
+ }
241
+
242
+ /** True if any key in `props` carries a variant marker (`@bp` or `:state`). */
243
+ export function hasVariantProps(props: Record<string, unknown>): boolean {
244
+ for (const key of Object.keys(props)) {
245
+ const parsed = parseVariantKey(key);
246
+ if (parsed.breakpoint || parsed.state) return true;
247
+ }
248
+ return false;
249
+ }
package/dist/client.d.ts DELETED
@@ -1,36 +0,0 @@
1
- /**
2
- * createHypenClient — single-call wiring for renderer + engine.
3
- *
4
- * Replaces the boilerplate:
5
- * const renderer = new DOMRenderer(container, engine);
6
- * engine.onPatches((patches) => renderer.applyPatches(patches));
7
- *
8
- * Works with either a local Engine (`setRenderCallback`) or RemoteEngine
9
- * (`onPatches`) — they expose different APIs but the same intent.
10
- */
11
- import type { Patch } from "@hypen-space/core/types";
12
- import { DOMRenderer } from "./dom/renderer.js";
13
- import type { DebugConfig } from "./dom/debug.js";
14
- import { CanvasRenderer } from "./canvas/renderer.js";
15
- import type { CanvasRendererOptions } from "./canvas/types.js";
16
- interface PatchSourceLike {
17
- dispatchAction(name: string, payload?: unknown): void;
18
- onPatches?(callback: (patches: Patch[]) => void): unknown;
19
- setRenderCallback?(callback: (patches: Patch[]) => void): void;
20
- }
21
- export interface DomClientOptions {
22
- debug?: Partial<DebugConfig>;
23
- }
24
- export interface DomClient {
25
- renderer: DOMRenderer;
26
- destroy(): void;
27
- }
28
- export declare function createDomClient(container: HTMLElement, engine: PatchSourceLike, options?: DomClientOptions): DomClient;
29
- export interface CanvasClientOptions extends Partial<CanvasRendererOptions> {
30
- }
31
- export interface CanvasClient {
32
- renderer: CanvasRenderer;
33
- destroy(): void;
34
- }
35
- export declare function createCanvasClient(canvas: HTMLCanvasElement, engine: PatchSourceLike, options?: CanvasClientOptions): CanvasClient;
36
- export {};
package/dist/client.js DELETED
@@ -1,47 +0,0 @@
1
- /**
2
- * createHypenClient — single-call wiring for renderer + engine.
3
- *
4
- * Replaces the boilerplate:
5
- * const renderer = new DOMRenderer(container, engine);
6
- * engine.onPatches((patches) => renderer.applyPatches(patches));
7
- *
8
- * Works with either a local Engine (`setRenderCallback`) or RemoteEngine
9
- * (`onPatches`) — they expose different APIs but the same intent.
10
- */
11
- import { DOMRenderer } from "./dom/renderer.js";
12
- import { CanvasRenderer } from "./canvas/renderer.js";
13
- function attachPatchListener(engine, callback) {
14
- if (typeof engine.onPatches === "function") {
15
- engine.onPatches(callback);
16
- return;
17
- }
18
- if (typeof engine.setRenderCallback === "function") {
19
- engine.setRenderCallback(callback);
20
- return;
21
- }
22
- throw new Error("createHypenClient: engine has neither onPatches() nor setRenderCallback() — cannot subscribe to patches.");
23
- }
24
- export function createDomClient(container, engine, options) {
25
- const renderer = new DOMRenderer(container, engine, options?.debug);
26
- attachPatchListener(engine, (patches) => renderer.applyPatches(patches));
27
- return {
28
- renderer,
29
- destroy() {
30
- // DOMRenderer has no destroy yet; clearing the container is the
31
- // closest approximation. Patch subscriptions live on the engine —
32
- // the caller controls engine lifetime, so we don't tear them down.
33
- container.innerHTML = "";
34
- },
35
- };
36
- }
37
- export function createCanvasClient(canvas, engine, options) {
38
- const renderer = new CanvasRenderer(canvas, engine, options);
39
- attachPatchListener(engine, (patches) => renderer.applyPatches(patches));
40
- return {
41
- renderer,
42
- destroy() {
43
- renderer.destroy();
44
- },
45
- };
46
- }
47
- //# sourceMappingURL=client.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAStD,SAAS,mBAAmB,CAC1B,MAAuB,EACvB,QAAoC;IAEpC,IAAI,OAAO,MAAM,CAAC,SAAS,KAAK,UAAU,EAAE,CAAC;QAC3C,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QAC3B,OAAO;IACT,CAAC;IACD,IAAI,OAAO,MAAM,CAAC,iBAAiB,KAAK,UAAU,EAAE,CAAC;QACnD,MAAM,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;QACnC,OAAO;IACT,CAAC;IACD,MAAM,IAAI,KAAK,CACb,0GAA0G,CAC3G,CAAC;AACJ,CAAC;AAWD,MAAM,UAAU,eAAe,CAC7B,SAAsB,EACtB,MAAuB,EACvB,OAA0B;IAE1B,MAAM,QAAQ,GAAG,IAAI,WAAW,CAAC,SAAS,EAAE,MAAa,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;IAC3E,mBAAmB,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;IACzE,OAAO;QACL,QAAQ;QACR,OAAO;YACL,gEAAgE;YAChE,kEAAkE;YAClE,mEAAmE;YACnE,SAAS,CAAC,SAAS,GAAG,EAAE,CAAC;QAC3B,CAAC;KACF,CAAC;AACJ,CAAC;AASD,MAAM,UAAU,kBAAkB,CAChC,MAAyB,EACzB,MAAuB,EACvB,OAA6B;IAE7B,MAAM,QAAQ,GAAG,IAAI,cAAc,CAAC,MAAM,EAAE,MAAa,EAAE,OAAO,CAAC,CAAC;IACpE,mBAAmB,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;IACzE,OAAO;QACL,QAAQ;QACR,OAAO;YACL,QAAQ,CAAC,OAAO,EAAE,CAAC;QACrB,CAAC;KACF,CAAC;AACJ,CAAC"}
package/src/client.ts DELETED
@@ -1,88 +0,0 @@
1
- /**
2
- * createHypenClient — single-call wiring for renderer + engine.
3
- *
4
- * Replaces the boilerplate:
5
- * const renderer = new DOMRenderer(container, engine);
6
- * engine.onPatches((patches) => renderer.applyPatches(patches));
7
- *
8
- * Works with either a local Engine (`setRenderCallback`) or RemoteEngine
9
- * (`onPatches`) — they expose different APIs but the same intent.
10
- */
11
-
12
- import type { Patch } from "@hypen-space/core/types";
13
- import { DOMRenderer } from "./dom/renderer.js";
14
- import type { DebugConfig } from "./dom/debug.js";
15
- import { CanvasRenderer } from "./canvas/renderer.js";
16
- import type { CanvasRendererOptions } from "./canvas/types.js";
17
-
18
- interface PatchSourceLike {
19
- dispatchAction(name: string, payload?: unknown): void;
20
- onPatches?(callback: (patches: Patch[]) => void): unknown;
21
- setRenderCallback?(callback: (patches: Patch[]) => void): void;
22
- }
23
-
24
- function attachPatchListener(
25
- engine: PatchSourceLike,
26
- callback: (patches: Patch[]) => void,
27
- ): void {
28
- if (typeof engine.onPatches === "function") {
29
- engine.onPatches(callback);
30
- return;
31
- }
32
- if (typeof engine.setRenderCallback === "function") {
33
- engine.setRenderCallback(callback);
34
- return;
35
- }
36
- throw new Error(
37
- "createHypenClient: engine has neither onPatches() nor setRenderCallback() — cannot subscribe to patches.",
38
- );
39
- }
40
-
41
- export interface DomClientOptions {
42
- debug?: Partial<DebugConfig>;
43
- }
44
-
45
- export interface DomClient {
46
- renderer: DOMRenderer;
47
- destroy(): void;
48
- }
49
-
50
- export function createDomClient(
51
- container: HTMLElement,
52
- engine: PatchSourceLike,
53
- options?: DomClientOptions,
54
- ): DomClient {
55
- const renderer = new DOMRenderer(container, engine as any, options?.debug);
56
- attachPatchListener(engine, (patches) => renderer.applyPatches(patches));
57
- return {
58
- renderer,
59
- destroy() {
60
- // DOMRenderer has no destroy yet; clearing the container is the
61
- // closest approximation. Patch subscriptions live on the engine —
62
- // the caller controls engine lifetime, so we don't tear them down.
63
- container.innerHTML = "";
64
- },
65
- };
66
- }
67
-
68
- export interface CanvasClientOptions extends Partial<CanvasRendererOptions> {}
69
-
70
- export interface CanvasClient {
71
- renderer: CanvasRenderer;
72
- destroy(): void;
73
- }
74
-
75
- export function createCanvasClient(
76
- canvas: HTMLCanvasElement,
77
- engine: PatchSourceLike,
78
- options?: CanvasClientOptions,
79
- ): CanvasClient {
80
- const renderer = new CanvasRenderer(canvas, engine as any, options);
81
- attachPatchListener(engine, (patches) => renderer.applyPatches(patches));
82
- return {
83
- renderer,
84
- destroy() {
85
- renderer.destroy();
86
- },
87
- };
88
- }