@playgenx/components 0.2.1 → 0.2.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.
package/README.md CHANGED
@@ -1,62 +1,444 @@
1
1
  # `@playgenx/components`
2
2
 
3
- Default React 19 implementations for every entry in `DEFAULT_REGISTRY`. Pair with `@playgenx/registry` and the parser/validator pipeline.
3
+ Default React 19 implementations for every entry in `DEFAULT_REGISTRY`.
4
+ The components, a per-Provider reactive state store, error boundaries,
5
+ and a CLI for inspecting state snapshots.
4
6
 
5
- ## Install
7
+ ```bash
8
+ npm install @playgenx/components
9
+ ```
10
+
11
+ React 19 is a peer dependency — your app provides it.
12
+
13
+ ```jsonc
14
+ // package.json (the bits you need)
15
+ {
16
+ "dependencies": {
17
+ "@playgenx/components": "^0.2.1",
18
+ "react": "^19.2.0",
19
+ "react-dom": "^19.2.0"
20
+ }
21
+ }
22
+ ```
23
+
24
+ > Looking for the **renderer** (parser + tree walker)? That's a
25
+ > separate package — `@playgenx/renderer`. This package is the
26
+ > component library; the renderer consumes it.
27
+
28
+ ---
29
+
30
+ ## Quick start
31
+
32
+ ```tsx
33
+ import {
34
+ Slider,
35
+ PlaygroundStateProvider,
36
+ usePlaygroundState,
37
+ } from '@playgenx/components';
38
+ import { useState } from 'react';
39
+
40
+ // 1. Standalone, no state — works without a Provider
41
+ export function StaticVolume() {
42
+ return <Slider min={0} max={10} value={4} label="Volume" />;
43
+ }
44
+
45
+ // 2. With shared state — wrap your tree
46
+ export function VolumePanel() {
47
+ return (
48
+ <PlaygroundStateProvider initial={{ volume: 5 }}>
49
+ <Slider min={0} max={10} stateKey="volume" label="Volume" />
50
+ <VolumeReadout />
51
+ </PlaygroundStateProvider>
52
+ );
53
+ }
6
54
 
7
- ```sh
8
- pnpm add @playgenx/components react@^19 react-dom@^19
55
+ function VolumeReadout() {
56
+ const state = usePlaygroundState();
57
+ return <span>Current: {state.get<number>('volume')}</span>;
58
+ }
9
59
  ```
10
60
 
11
- React 19 is a peer dependency; this package does not bundle it.
61
+ ---
62
+
63
+ ## What's in the box
64
+
65
+ ### Components (PascalCase, React 19)
66
+
67
+ Every component accepts JSON-friendly props. See `index.ts` for the
68
+ full surface.
69
+
70
+ | Component | Purpose | Notable props |
71
+ |---------------|--------------------------------------------|--------------------------------|
72
+ | `Button` | Headless button | `label`, `variant`, `onClick` |
73
+ | `TextField` | Controlled / uncontrolled input | `value`, `onChange` |
74
+ | `Slider` | Range input | `min`, `max`, `value`, `stateKey` |
75
+ | `Chart` | bar / line / pie SVG charts | `kind`, `data`, `title` |
76
+ | `Container` | Layout primitive | `padding`, `gap` |
77
+ | `Code` | Inline code / `<pre><code>` | `language` |
78
+ | `Heading` | `<h1>`–`<h6>` | `level` |
79
+ | `Text` | `<p>` with weight + color | `weight`, `color` |
80
+ | `Stepper` | Multi-step reveal | `steps`, `initial` |
81
+ | `Card` | Titled card | `title`, `children` |
82
+ | `List` | `<ul>` / `<ol>` from array | `items`, `ordered` |
83
+
84
+ ### State store + React glue
85
+
86
+ | Export | What it does |
87
+ |------------------------------|-----------------------------------------------------------|
88
+ | `createPlaygroundState(initial?)` | Create a standalone state store |
89
+ | `PlaygroundStateProvider` | Wrap your tree with a Provider |
90
+ | `usePlaygroundState()` | Read the nearest store |
91
+ | `useBoundValue(key, fb)` | Get a live `[value, setter]` tuple (re-renders on change) |
92
+ | `useBoundValueOrUndefined(key, fb)` | Same; returns `undefined` if no key/provider |
93
+ | `useStoreSnapshot()` | Non-subscribing `{get, set, subscribe, snapshot, ...}` |
94
+ | `useBoundSelector(key, sel, fb)` | Live bound value with selector transform; only re-renders on slice change |
95
+ | `useMultiBoundValue(bindings)` | Bind multiple keys; returns `Record<key, [value, setter]>` |
96
+ | `useStateAction(action)` | Build an `onClick` from `{set, toggle}` config |
97
+
98
+ ### Pure helpers (no React, no Provider)
99
+
100
+ | Export | Returns |
101
+ |-----------------------|------------------------------------|
102
+ | `dumpState(state)` | JSON v1 envelope (sorted keys) |
103
+ | `diffState(a, b)` | `{added, changed, removed}` or null |
104
+ | `diffSnapshots(prev, next)` | Same as `diffState` but pure |
105
+ | `validateStateKey(k)` | `null` if valid, error message if not |
106
+ | `clearState(state)` | (void) — sets every key to undefined |
107
+ | `batch(state, fn)` | Atomic set commit, per-key dedup |
108
+
109
+ ### Error handling
12
110
 
13
- ## What's in here
111
+ | Export | Purpose |
112
+ |------------------------------|------------------------------------|
113
+ | `ArtifactErrorBoundary` | Class-component error boundary |
114
+ | `ShowSource` | Render-prop source-toggle |
14
115
 
15
- 11 components, each matching a name in `@playgenx/registry`:
116
+ ### Registry
16
117
 
17
- - `Button` — primary / secondary / ghost variant, disabled state, click handler.
18
- - `TextField` — labeled controlled-or-uncontrolled input.
19
- - `Slider` clamped range input with optional caption.
20
- - `Chart` bar / line / pie, hand-rolled SVG, no chart library.
21
- - `Container` — vertical flex wrapper with padding + gap.
22
- - `Code` — inline or `<pre><code>` formatting, language data-attribute.
23
- - `Heading` — `<h1>`..`<h6>` with size-by-level, clamped.
24
- - `Text` — `<p>` with weight, size, color.
25
- - `Stepper` — multi-step reveal with previous/current/future states.
26
- - `Card` — bordered + shadowed wrapper with elevation prop.
27
- - `List` — `<ul>` or `<ol>` from an array of arbitrary values.
118
+ | Export | Purpose |
119
+ |-------------------------|--------------------------------------|
120
+ | `componentMap` | Frozen default registry (11 entries) |
121
+ | `createRegistry(overrides)` | Returns a new frozen map |
28
122
 
29
- ## Use
123
+ ---
124
+
125
+ ## Three ways to use the state store
126
+
127
+ ### 1. Standalone, outside React
128
+
129
+ ```ts
130
+ import { createPlaygroundState } from '@playgenx/components';
131
+
132
+ const state = createPlaygroundState({ count: 0 });
133
+ state.set('count', 5);
134
+ state.get('count'); // 5
135
+ state.snapshot(); // { count: 5 }
136
+ state.subscribe('count', (v) => console.log('count is now', v));
137
+ state.set('count', 10); // → console.log fires on the next microtask
138
+ ```
139
+
140
+ ### 2. React tree with a Provider
30
141
 
31
142
  ```tsx
32
- import { Button, Container, Heading, Text, componentMap } from '@playgenx/components';
33
- import { DEFAULT_REGISTRY, findSchema } from '@playgenx/registry';
143
+ import { PlaygroundStateProvider, useBoundValue } from '@playgenx/components';
34
144
 
35
- function App() {
145
+ function VolumeControl() {
146
+ // Live-bound: writes to state on change, re-renders on external writes
147
+ const [volume, setVolume] = useBoundValue<number>('volume', 50);
36
148
  return (
37
- <Container>
38
- <Heading level={2}>Hello</Heading>
39
- <Text>A short description.</Text>
40
- <Button label="Continue" variant="primary" />
41
- </Container>
149
+ <input
150
+ type="range"
151
+ min={0}
152
+ max={100}
153
+ value={volume}
154
+ onChange={(e) => setVolume(Number(e.currentTarget.value))}
155
+ />
42
156
  );
43
157
  }
44
158
 
45
- // Render-time lookup:
46
- const HeadingC = componentMap['Heading'];
47
- return <HeadingC level={2}>title</HeadingC>;
159
+ export function App() {
160
+ return (
161
+ <PlaygroundStateProvider initial={{ volume: 50 }}>
162
+ <VolumeControl />
163
+ </PlaygroundStateProvider>
164
+ );
165
+ }
166
+ ```
167
+
168
+ ### 3. State-bound component (the simple path)
169
+
170
+ ```tsx
171
+ // No need to write your own useBoundValue — Slider + stateKey does it.
172
+ <PlaygroundStateProvider initial={{ volume: 50 }}>
173
+ <Slider min={0} max={100} stateKey="volume" />
174
+ </PlaygroundStateProvider>
175
+ ```
176
+
177
+ ---
178
+
179
+ ## Flexibility patterns — pick the right hook for the job
180
+
181
+ v0.2.2 ships five hooks for binding components to state. They differ
182
+ in **what triggers a re-render**, **what they assume about Providers**,
183
+ and **how they expose state to your code**. Pick the lowest-cost one
184
+ that fits.
185
+
186
+ | Hook | Subscribes? | Needs Provider? | SSR-safe? | Use when… |
187
+ |------------------------|-------------|------------------|-----------|-----------------------------------------|
188
+ | `useBoundValue` | yes | yes (throws) | yes | You need to re-render on state changes and a Provider is mandatory |
189
+ | `useBoundValueOrUndefined` | yes | no (graceful) | yes | `stateKey` is optional; no Provider = no-op binding |
190
+ | `useStoreSnapshot` | **no** | yes (throws) | n/a | You read/write state in handlers but don't want re-renders |
191
+ | `useBoundSelector` | yes (filtered) | yes (throws) | yes | One key holds an object; you only care about one slice |
192
+ | `useMultiBoundValue` | yes (1 per key) | yes (throws) | yes | A form/dashboard binds 5-10 keys; you want a Record |
193
+
194
+ ### `useStoreSnapshot` — for non-subscribing reads
195
+
196
+ When you need state in event handlers but don't want the component to
197
+ re-render on every change:
198
+
199
+ ```tsx
200
+ import { useStoreSnapshot } from '@playgenx/components';
201
+
202
+ function SaveButton() {
203
+ const { get, set, snapshot } = useStoreSnapshot();
204
+ return (
205
+ <button onClick={() => {
206
+ // Read multiple keys atomically, write back, no re-render
207
+ const form = snapshot();
208
+ if (form.dirty) {
209
+ set('savedAt', Date.now());
210
+ api.save(form);
211
+ }
212
+ }}>
213
+ Save
214
+ </button>
215
+ );
216
+ }
48
217
  ```
49
218
 
50
- ## Determinism
219
+ The hook returns `{ state, get, set, subscribe, snapshot, replaceAll }` —
220
+ all stable references for the Provider's lifetime.
51
221
 
52
- Components are render-only and **never** reference `Math.random`, `Date.now`, or runtime-crypto APIs. Hashing inputs (validation, storage) is fully reproducible — `<Chart kind="bar" data={...} />` renders the same SVG every time given the same data.
222
+ ### `useBoundSelector` slice-aware subscriptions
53
223
 
54
- If you mount these in an environment where a renderer may pass non-deterministic callbacks, run inside a sandboxed iframe that the LLM never controls.
224
+ When one key holds an object and you only care about one field:
225
+
226
+ ```tsx
227
+ import { useBoundSelector } from '@playgenx/components';
228
+
229
+ interface User { name: string; age: number; email: string; }
230
+
231
+ function CurrentUserBadge() {
232
+ // Only re-renders when `name` changes, not when `age` changes.
233
+ const [name] = useBoundSelector<User, string>(
234
+ 'currentUser',
235
+ (u) => u?.name ?? 'guest',
236
+ 'guest',
237
+ );
238
+ return <span>Hi, {name}!</span>;
239
+ }
240
+ ```
241
+
242
+ **Important**: write selectors that return primitives or stable refs.
243
+ A selector that returns a fresh object (`u => ({...u})`) defeats the
244
+ slice-detection and re-renders on every store change.
245
+
246
+ ### `useMultiBoundValue` — bind many keys at once
247
+
248
+ For forms and dashboards where you have several bound inputs in one
249
+ component:
250
+
251
+ ```tsx
252
+ import { useMultiBoundValue } from '@playgenx/components';
253
+
254
+ function SettingsForm() {
255
+ const form = useMultiBoundValue({
256
+ name: { fallback: '' },
257
+ email: { fallback: '' },
258
+ age: { fallback: 0 },
259
+ role: { fallback: 'user' },
260
+ });
261
+ return (
262
+ <>
263
+ <input value={form.name[0]} onChange={e => form.name[1](e.target.value)} />
264
+ <input value={form.email[0]} onChange={e => form.email[1](e.target.value)} />
265
+ <input type="number" value={form.age[0]} onChange={e => form.age[1](+e.target.value)} />
266
+ <select value={form.role[0]} onChange={e => form.role[1](e.target.value)}>
267
+ <option value="user">User</option>
268
+ <option value="admin">Admin</option>
269
+ </select>
270
+ </>
271
+ );
272
+ }
273
+ ```
274
+
275
+ The hook subscribes once per key (so 5 keys = 5 subscriptions). For
276
+ 50+ rows of dynamic data, use `useStoreSnapshot` + manual `get`/`set`
277
+ calls instead — the hook count is bounded.
278
+
279
+ ### SSR — state is reflected in the first render
280
+
281
+ All `useBoundValue*` hooks use React 19's `useSyncExternalStore` so
282
+ the **server-rendered HTML matches the live store value**, not a
283
+ fallback. `renderToString(<Slider stateKey="v" />)` inside a Provider
284
+ with `initial={{ v: 7 }}` produces `<input value="7" ... />` — no
285
+ hydration mismatch.
286
+
287
+ ```ts
288
+ // Server
289
+ import { renderToString } from 'react-dom/server';
290
+ import { Slider, PlaygroundStateProvider } from '@playgenx/components';
291
+
292
+ const html = renderToString(
293
+ <PlaygroundStateProvider initial={{ volume: 50 }}>
294
+ <Slider min={0} max={100} stateKey="volume" />
295
+ </PlaygroundStateProvider>
296
+ );
297
+ // html contains `value="50"` — not `value="0"` (the local fallback)
298
+ ```
299
+
300
+ If your framework has a `renderToReadableStream` or similar, the same
301
+ guarantee holds. The hook count is **3** (down from 5 in 0.2.1)
302
+ thanks to `useSyncExternalStore` collapsing the previous
303
+ `useState + useState + useEffect` trio.
304
+
305
+ ---
306
+
307
+ ## Slider — the three operating modes
308
+
309
+ The `Slider` component accepts `value` and/or `stateKey`. They mean
310
+ different things:
311
+
312
+ | Pass | Mode | Behavior |
313
+ |---------------------|--------------------------|---------------------------------------|
314
+ | Neither | **Uncontrolled** | Owns its own local state |
315
+ | `value={50}` only | **Controlled, read-only** | User input is ignored (no onChange wired) |
316
+ | `stateKey="volume"` | **Bound to state** | Reads/writes via the Provider |
317
+
318
+ The bound mode wins when both are present. `value` is clamped to
319
+ `[min, max]` on read; NaN clamps to `min`; `min === max` disables the
320
+ slider.
321
+
322
+ ---
323
+
324
+ ## The CLI: `playgenx-state`
325
+
326
+ After `npm install @playgenx/components`, you get a `playgenx-state`
327
+ binary on your PATH (via npm's `bin` field). It operates on JSON
328
+ snapshots on stdin/stdout.
329
+
330
+ ```bash
331
+ # Pretty-print a snapshot in the v1 envelope format
332
+ $ echo '{"volume":5,"user":{"name":"a"}}' | playgenx-state snapshot
333
+ {
334
+ "version": 1,
335
+ "keys": [
336
+ "user",
337
+ "volume"
338
+ ],
339
+ "values": {
340
+ "volume": 5,
341
+ "user": { "name": "a" }
342
+ }
343
+ }
344
+
345
+ # Validate stateKey strings before using them in a body
346
+ $ echo '["good","bad key","has/slash"]' | playgenx-state validate
347
+ [
348
+ { "key": "good", "ok": true },
349
+ { "key": "bad key", "ok": false, "error": "stateKey must not contain whitespace" },
350
+ { "key": "has/slash", "ok": false, "error": "stateKey contains forbidden characters..." }
351
+ ]
352
+ # exit code 3 (validation failed)
353
+
354
+ # Diff two snapshots
355
+ $ echo '{"prev":{"a":1},"next":{"a":2,"b":3}}' | playgenx-state diff
356
+ { "added": ["b"], "changed": ["a"], "removed": [] }
357
+
358
+ # Inspect keys / count
359
+ $ echo '{"b":1,"a":2,"c":3}' | playgenx-state keys
360
+ [ "a", "b", "c" ]
361
+ $ echo '{"b":1,"a":2,"c":3}' | playgenx-state count
362
+ { "keys": 3 }
363
+ ```
364
+
365
+ **Exit codes:** `0` ok, `1` unknown subcommand, `2` bad input, `3`
366
+ validation failure.
367
+
368
+ These are the same helpers exported from the package as library
369
+ functions (`dumpState`, `diffSnapshots`, `validateStateKey`, etc.) —
370
+ the CLI is a thin wrapper. Use whichever fits.
371
+
372
+ ---
373
+
374
+ ## Architecture notes
375
+
376
+ - **Per-Provider scope.** Each `PlaygroundStateProvider` creates an
377
+ independent store. Nested Providers create nested scopes (a child
378
+ Provider does not see the parent's keys).
379
+ - **HMR-safe.** Subscribers are cleared on Provider unmount, so a
380
+ hot-reload that re-mounts the Provider doesn't leak subscribers to
381
+ the old store.
382
+ - **Microtask batched.** `set()` schedules subscriber fires on the
383
+ next microtask. Multiple sets in the same tick produce one fire
384
+ per affected key. Use `batch(state, fn)` if you want each
385
+ subscriber to see only the LAST value set in a group.
386
+ - **No deep clone.** Values are stored by reference. Don't mutate
387
+ objects after `set()`-ing them — use a fresh object instead.
388
+ - **`Object.is` equality.** Setting a value that `Object.is`-equals
389
+ the current value is a no-op (no subscriber fire, no flush). This
390
+ means `set('x', NaN)` twice fires once, and `set('x', undefined)`
391
+ on an unset key is a no-op (since `Object.is(undefined, undefined)`
392
+ is `true`).
393
+ - **Sub-Provider remount drops old subscribers.** Subscribers from a
394
+ unmounted Provider's tree do not fire for sets on a NEW Provider's
395
+ store, even with the same key name. (Verified by the A.7 hardening
396
+ test.)
397
+
398
+ ---
399
+
400
+ ## TypeScript
401
+
402
+ This package is written in TypeScript with strict types. The
403
+ `dist/index.d.mts` declarations are exhaustive — you can `import
404
+ type { SliderProps, PlaygroundState, StateDiff }` etc.
405
+
406
+ Common imports:
407
+
408
+ ```ts
409
+ import type {
410
+ SliderProps,
411
+ ButtonProps,
412
+ PlaygroundState,
413
+ StateAction,
414
+ StateDiff,
415
+ StateEnvelope,
416
+ RenderBodyOptions,
417
+ } from '@playgenx/components';
418
+ ```
419
+
420
+ ---
55
421
 
56
422
  ## Versioning
57
423
 
58
- This package follows PlayGenX's overall version policy (mirror `playgenx` core). A component's prop signature is part of the public contract; new optional props are non-breaking, removing/renaming is a breaking change.
424
+ - **0.1.x** Component-only, no state store. `Slider` had no
425
+ `stateKey` prop.
426
+ - **0.2.0** — Adds `PlaygroundStateProvider`, `useBoundValue*`,
427
+ `useStateAction`, `ArtifactErrorBoundary`, `ShowSource`,
428
+ `createRegistry`, the pure helpers (`dumpState` etc.), and the
429
+ `playgenx-state` CLI binary. The `stateKey` prop on `Slider` is
430
+ fully wired and uses the new state store.
431
+ - **0.2.1** — Exposes the CLI binary via the package's `bin` field
432
+ so `npx playgenx-state` works after a fresh install.
433
+ - **0.2.2** — SSR fix: `useBoundValueOrUndefined` now uses React 19's
434
+ `useSyncExternalStore` so `renderToString` reflects the Provider's
435
+ live value (no more "fallback on server, real value after hydration"
436
+ mismatch). Adds three flexibility hooks: `useStoreSnapshot`
437
+ (non-subscribing), `useBoundSelector` (slice-aware subscription),
438
+ `useMultiBoundValue` (batch key binding). 108 tests passing.
439
+
440
+ ---
59
441
 
60
442
  ## License
61
443
 
62
- MIT — see [LICENSE](../../LICENSE).
444
+ MIT — same as the parent project.
package/dist/index.d.mts CHANGED
@@ -281,11 +281,18 @@ declare function usePlaygroundState(): PlaygroundState;
281
281
  *
282
282
  * Implementation note: this hook ALWAYS calls the same number of
283
283
  * React hooks regardless of whether `key` is set or a Provider is in
284
- * scope. The "no binding" / "no Provider" branch uses dummy local
285
- * state so the hook count stays aligned across renders. That means a
284
+ * scope. The "no binding" / "no Provider" branch returns a static
285
+ * tuple so the hook count stays aligned across renders. That means a
286
286
  * component can flip `stateKey` from defined to undefined (or move in
287
287
  * or out of a Provider) without crashing with a hooks-order error.
288
288
  *
289
+ * The hook uses React 19's `useSyncExternalStore` so SSR renders the
290
+ * Provider's current value synchronously — no "value=fallback on
291
+ * server, value=real after hydration" surprise. The hook count drops
292
+ * from 5 (useContext + useState + useState + useEffect + useCallback)
293
+ * to 3 (useContext + useSyncExternalStore + useCallback) as a side
294
+ * benefit.
295
+ *
289
296
  * Components that accept a `stateKey` prop should call this internally
290
297
  * and use the returned tuple as a drop-in for the underlying
291
298
  * value/onChange pair. The return type widens to `readonly [...] | undefined`
@@ -298,6 +305,98 @@ declare function usePlaygroundState(): PlaygroundState;
298
305
  */
299
306
  declare function useBoundValueOrUndefined<T>(key: string | undefined, fallback: T): readonly [T, (next: T) => void] | undefined;
300
307
  declare function useBoundValue<T>(key: string, fallback: T): readonly [T, (next: T) => void];
308
+ /**
309
+ * Non-subscribing accessor for the store. Returns a stable tuple of
310
+ * imperative API methods (`get`, `set`, `subscribe`, `snapshot`,
311
+ * `replaceAll`) plus the raw `state` ref — none of which trigger a
312
+ * re-render when used.
313
+ *
314
+ * When to use this instead of `useBoundValue`:
315
+ *
316
+ * - You need to read state inside an event handler (no render needed).
317
+ * - You need to set state from many different handlers, not one bound prop.
318
+ * - You're implementing a custom hook that wraps the store.
319
+ * - You want to subscribe imperatively (for analytics, side-effects).
320
+ *
321
+ * When NOT to use this: if you need the component to RE-RENDER on
322
+ * state changes, use `useBoundValue` (which subscribes for you).
323
+ *
324
+ * @example
325
+ * function LogoutButton() {
326
+ * const { get, set } = useStoreSnapshot();
327
+ * return (
328
+ * <button onClick={() => {
329
+ * if (get<boolean>('confirmLogout')) set('confirmLogout', false);
330
+ * doLogout();
331
+ * }}>Log out</button>
332
+ * );
333
+ * }
334
+ */
335
+ declare function useStoreSnapshot(): {
336
+ readonly state: PlaygroundState;
337
+ readonly get: <T = unknown>(key: string) => T | undefined;
338
+ readonly set: <T = unknown>(key: string, value: T) => void;
339
+ readonly subscribe: (key: string, cb: (value: unknown) => void) => () => void;
340
+ readonly snapshot: () => Readonly<Record<string, unknown>>;
341
+ readonly replaceAll: (values: Record<string, unknown>) => void;
342
+ };
343
+ /**
344
+ * Bind a state key with a selector transform. Returns the SELECTED
345
+ * value, not the raw value. The component only re-renders when the
346
+ * selected slice changes — not when OTHER fields on the same key
347
+ * change.
348
+ *
349
+ * Useful for normalized state where one key holds an object and you
350
+ * only care about one property:
351
+ *
352
+ * @example
353
+ * interface User { name: string; age: number; email: string; }
354
+ * const userName = useBoundSelector<User, string>(
355
+ * 'currentUser',
356
+ * (u) => u?.name ?? '(anonymous)',
357
+ * 'guest'
358
+ * );
359
+ * // Setting `currentUser.age` does NOT re-render this component.
360
+ * // Setting `currentUser.name` DOES re-render this component.
361
+ *
362
+ * The setter writes the SELECTED value as-is to the store. For
363
+ * partial-merge semantics (e.g., "set only the name, keep other
364
+ * fields"), use `useStoreSnapshot()` directly and merge yourself.
365
+ *
366
+ * If the selector throws, the error propagates and the component
367
+ * unmounts via the nearest error boundary. Wrap your selector in
368
+ * a try/catch if you need resilience.
369
+ */
370
+ declare function useBoundSelector<T, U>(key: string, selector: (raw: T | undefined) => U, fallback: U): readonly [U, (next: U) => void];
371
+ /**
372
+ * Bind multiple keys at once. Returns a `Record<key, [value, setter]>`
373
+ * for the keys you specify. Each setter writes back to its own key.
374
+ *
375
+ * Useful for forms and dashboards where multiple bound inputs share
376
+ * a single Provider.
377
+ *
378
+ * @example
379
+ * const form = useMultiBoundValue({
380
+ * name: { fallback: '' },
381
+ * age: { fallback: 0 },
382
+ * email: { fallback: '' },
383
+ * });
384
+ * // form.name[0] === current name string
385
+ * // form.age[1](42) writes 42 to state.age
386
+ *
387
+ * The hook subscribes ONCE per key (so 5 keys = 5 subscriptions,
388
+ * not a single batched subscription). If you bind a LOT of keys,
389
+ * consider using `useStoreSnapshot()` instead — it doesn't subscribe.
390
+ *
391
+ * @example
392
+ * // 50-row table, each row needs its own value
393
+ * const { get, set } = useStoreSnapshot();
394
+ * rows.map(row => <input value={get(`cell-${row.id}`) ?? ''}
395
+ * onChange={e => set(`cell-${row.id}`, e.target.value)} />);
396
+ */
397
+ declare function useMultiBoundValue<K extends string>(bindings: Record<K, {
398
+ fallback: unknown;
399
+ }>): { readonly [P in K]: readonly [unknown, (next: unknown) => void]; };
301
400
  /**
302
401
  * State-binding action shape. Used by `<Button onClickAction={...}>`.
303
402
  * { set: { count: 1 } } -> sets state.count = 1
@@ -506,5 +605,5 @@ declare const componentMap: ComponentMap;
506
605
  */
507
606
  declare function createRegistry(overrides: Partial<ComponentMap>): ComponentMap;
508
607
  //#endregion
509
- export { ArtifactErrorBoundary, type ArtifactErrorBoundaryProps, Button, type ButtonProps, Card, type CardProps, Chart, type ChartKind, type ChartProps, Code, type CodeProps, type ComponentMap, Container, type ContainerProps, Heading, type HeadingProps, List, type ListProps, type PlaygroundState, PlaygroundStateProvider, type PlaygroundStateProviderProps, ShowSource, type ShowSourceProps, Slider, type SliderProps, type StateAction, type StateDiff, type StateEnvelope, type Step, Stepper, type StepperProps, Text, TextField, type TextFieldProps, type TextProps, batch, clearState, componentMap, createPlaygroundState, createRegistry, diffSnapshots, diffState, dumpState, useBoundValue, useBoundValueOrUndefined, usePlaygroundState, useStateAction, validateStateKey };
608
+ export { ArtifactErrorBoundary, type ArtifactErrorBoundaryProps, Button, type ButtonProps, Card, type CardProps, Chart, type ChartKind, type ChartProps, Code, type CodeProps, type ComponentMap, Container, type ContainerProps, Heading, type HeadingProps, List, type ListProps, type PlaygroundState, PlaygroundStateProvider, type PlaygroundStateProviderProps, ShowSource, type ShowSourceProps, Slider, type SliderProps, type StateAction, type StateDiff, type StateEnvelope, type Step, Stepper, type StepperProps, Text, TextField, type TextFieldProps, type TextProps, batch, clearState, componentMap, createPlaygroundState, createRegistry, diffSnapshots, diffState, dumpState, useBoundSelector, useBoundValue, useBoundValueOrUndefined, useMultiBoundValue, usePlaygroundState, useStateAction, useStoreSnapshot, validateStateKey };
510
609
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/Button.tsx","../src/TextField.tsx","../src/Slider.tsx","../src/Chart.tsx","../src/Container.tsx","../src/Code.tsx","../src/Heading.tsx","../src/Text.tsx","../src/Stepper.tsx","../src/Card.tsx","../src/List.tsx","../src/state.tsx","../src/stateHelpers.ts","../src/ArtifactErrorBoundary.tsx","../src/ShowSource.tsx","../src/createRegistry.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/Button.tsx","../src/TextField.tsx","../src/Slider.tsx","../src/Chart.tsx","../src/Container.tsx","../src/Code.tsx","../src/Heading.tsx","../src/Text.tsx","../src/Stepper.tsx","../src/Card.tsx","../src/List.tsx","../src/state.tsx","../src/stateHelpers.ts","../src/ArtifactErrorBoundary.tsx","../src/ShowSource.tsx","../src/createRegistry.ts"],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -308,11 +308,18 @@ function usePlaygroundState() {
308
308
  *
309
309
  * Implementation note: this hook ALWAYS calls the same number of
310
310
  * React hooks regardless of whether `key` is set or a Provider is in
311
- * scope. The "no binding" / "no Provider" branch uses dummy local
312
- * state so the hook count stays aligned across renders. That means a
311
+ * scope. The "no binding" / "no Provider" branch returns a static
312
+ * tuple so the hook count stays aligned across renders. That means a
313
313
  * component can flip `stateKey` from defined to undefined (or move in
314
314
  * or out of a Provider) without crashing with a hooks-order error.
315
315
  *
316
+ * The hook uses React 19's `useSyncExternalStore` so SSR renders the
317
+ * Provider's current value synchronously — no "value=fallback on
318
+ * server, value=real after hydration" surprise. The hook count drops
319
+ * from 5 (useContext + useState + useState + useEffect + useCallback)
320
+ * to 3 (useContext + useSyncExternalStore + useCallback) as a side
321
+ * benefit.
322
+ *
316
323
  * Components that accept a `stateKey` prop should call this internally
317
324
  * and use the returned tuple as a drop-in for the underlying
318
325
  * value/onChange pair. The return type widens to `readonly [...] | undefined`
@@ -326,21 +333,30 @@ function usePlaygroundState() {
326
333
  function useBoundValueOrUndefined(key, fallback) {
327
334
  const ctx = React.useContext(PlaygroundStateContext);
328
335
  const bound = key !== void 0 && ctx !== null;
329
- const [value, setValue] = React.useState(fallback);
330
- const [, force] = React.useState(0);
331
- React.useEffect(() => {
332
- if (!bound || key === void 0 || ctx === null) return;
333
- const initial = ctx.state.get(key) ?? fallback;
334
- setValue(initial);
335
- return ctx.state.subscribe(key, (next) => {
336
- setValue(next);
337
- force((n) => n + 1);
338
- });
336
+ const value = React.useSyncExternalStore(React.useCallback((onStoreChange) => {
337
+ if (!bound || key === void 0 || ctx === null) return () => {};
338
+ return ctx.state.subscribe(key, onStoreChange);
339
339
  }, [
340
340
  bound,
341
341
  ctx,
342
342
  key
343
- ]);
343
+ ]), React.useCallback(() => {
344
+ if (!bound || key === void 0 || ctx === null) return fallback;
345
+ return ctx.state.get(key) ?? fallback;
346
+ }, [
347
+ bound,
348
+ ctx,
349
+ key,
350
+ fallback
351
+ ]), React.useCallback(() => {
352
+ if (!bound || key === void 0 || ctx === null) return fallback;
353
+ return ctx.state.get(key) ?? fallback;
354
+ }, [
355
+ bound,
356
+ ctx,
357
+ key,
358
+ fallback
359
+ ]));
344
360
  const set = React.useCallback((next) => {
345
361
  if (!bound || key === void 0 || ctx === null) return;
346
362
  ctx.state.set(key, next);
@@ -358,6 +374,124 @@ function useBoundValue(key, fallback) {
358
374
  return bound;
359
375
  }
360
376
  /**
377
+ * Non-subscribing accessor for the store. Returns a stable tuple of
378
+ * imperative API methods (`get`, `set`, `subscribe`, `snapshot`,
379
+ * `replaceAll`) plus the raw `state` ref — none of which trigger a
380
+ * re-render when used.
381
+ *
382
+ * When to use this instead of `useBoundValue`:
383
+ *
384
+ * - You need to read state inside an event handler (no render needed).
385
+ * - You need to set state from many different handlers, not one bound prop.
386
+ * - You're implementing a custom hook that wraps the store.
387
+ * - You want to subscribe imperatively (for analytics, side-effects).
388
+ *
389
+ * When NOT to use this: if you need the component to RE-RENDER on
390
+ * state changes, use `useBoundValue` (which subscribes for you).
391
+ *
392
+ * @example
393
+ * function LogoutButton() {
394
+ * const { get, set } = useStoreSnapshot();
395
+ * return (
396
+ * <button onClick={() => {
397
+ * if (get<boolean>('confirmLogout')) set('confirmLogout', false);
398
+ * doLogout();
399
+ * }}>Log out</button>
400
+ * );
401
+ * }
402
+ */
403
+ function useStoreSnapshot() {
404
+ const ctx = React.useContext(PlaygroundStateContext);
405
+ if (ctx === null) throw new Error("useStoreSnapshot() must be called inside a <PlaygroundStateProvider>.");
406
+ return {
407
+ state: ctx.state,
408
+ get: ctx.state.get,
409
+ set: ctx.state.set,
410
+ subscribe: ctx.state.subscribe,
411
+ snapshot: ctx.state.snapshot,
412
+ replaceAll: ctx.state.replaceAll
413
+ };
414
+ }
415
+ /**
416
+ * Bind a state key with a selector transform. Returns the SELECTED
417
+ * value, not the raw value. The component only re-renders when the
418
+ * selected slice changes — not when OTHER fields on the same key
419
+ * change.
420
+ *
421
+ * Useful for normalized state where one key holds an object and you
422
+ * only care about one property:
423
+ *
424
+ * @example
425
+ * interface User { name: string; age: number; email: string; }
426
+ * const userName = useBoundSelector<User, string>(
427
+ * 'currentUser',
428
+ * (u) => u?.name ?? '(anonymous)',
429
+ * 'guest'
430
+ * );
431
+ * // Setting `currentUser.age` does NOT re-render this component.
432
+ * // Setting `currentUser.name` DOES re-render this component.
433
+ *
434
+ * The setter writes the SELECTED value as-is to the store. For
435
+ * partial-merge semantics (e.g., "set only the name, keep other
436
+ * fields"), use `useStoreSnapshot()` directly and merge yourself.
437
+ *
438
+ * If the selector throws, the error propagates and the component
439
+ * unmounts via the nearest error boundary. Wrap your selector in
440
+ * a try/catch if you need resilience.
441
+ */
442
+ function useBoundSelector(key, selector, fallback) {
443
+ const bound = useBoundValueOrUndefined(key, fallback);
444
+ const raw = bound === void 0 ? void 0 : bound[0];
445
+ const value = React.useMemo(() => selector(raw), [
446
+ raw,
447
+ selector,
448
+ fallback
449
+ ]);
450
+ const set = React.useCallback((next) => {
451
+ if (bound === void 0) return;
452
+ bound[1](next);
453
+ }, [bound]);
454
+ if (bound === void 0) throw new Error("useBoundSelector requires a non-undefined `key` and a <PlaygroundStateProvider> ancestor.");
455
+ return [value, set];
456
+ }
457
+ /**
458
+ * Bind multiple keys at once. Returns a `Record<key, [value, setter]>`
459
+ * for the keys you specify. Each setter writes back to its own key.
460
+ *
461
+ * Useful for forms and dashboards where multiple bound inputs share
462
+ * a single Provider.
463
+ *
464
+ * @example
465
+ * const form = useMultiBoundValue({
466
+ * name: { fallback: '' },
467
+ * age: { fallback: 0 },
468
+ * email: { fallback: '' },
469
+ * });
470
+ * // form.name[0] === current name string
471
+ * // form.age[1](42) writes 42 to state.age
472
+ *
473
+ * The hook subscribes ONCE per key (so 5 keys = 5 subscriptions,
474
+ * not a single batched subscription). If you bind a LOT of keys,
475
+ * consider using `useStoreSnapshot()` instead — it doesn't subscribe.
476
+ *
477
+ * @example
478
+ * // 50-row table, each row needs its own value
479
+ * const { get, set } = useStoreSnapshot();
480
+ * rows.map(row => <input value={get(`cell-${row.id}`) ?? ''}
481
+ * onChange={e => set(`cell-${row.id}`, e.target.value)} />);
482
+ */
483
+ function useMultiBoundValue(bindings) {
484
+ if (React.useContext(PlaygroundStateContext) === null) throw new Error("useMultiBoundValue() must be called inside a <PlaygroundStateProvider>.");
485
+ const result = {};
486
+ const keys = Object.keys(bindings);
487
+ for (const k of keys) {
488
+ const b = useBoundValueOrUndefined(k, bindings[k].fallback);
489
+ if (b === void 0) result[k] = [bindings[k].fallback, () => {}];
490
+ else result[k] = b;
491
+ }
492
+ return result;
493
+ }
494
+ /**
361
495
  * Apply a StateAction to the nearest PlaygroundState. Returns an
362
496
  * onClick handler that fires the action. If action is undefined
363
497
  * the handler is a no-op.
@@ -1184,6 +1318,6 @@ function createRegistry(overrides) {
1184
1318
  return Object.freeze(merged);
1185
1319
  }
1186
1320
  //#endregion
1187
- export { ArtifactErrorBoundary, Button, Card, Chart, Code, Container, Heading, List, PlaygroundStateProvider, ShowSource, Slider, Stepper, Text, TextField, batch, clearState, componentMap, createPlaygroundState, createRegistry, diffSnapshots, diffState, dumpState, useBoundValue, useBoundValueOrUndefined, usePlaygroundState, useStateAction, validateStateKey };
1321
+ export { ArtifactErrorBoundary, Button, Card, Chart, Code, Container, Heading, List, PlaygroundStateProvider, ShowSource, Slider, Stepper, Text, TextField, batch, clearState, componentMap, createPlaygroundState, createRegistry, diffSnapshots, diffState, dumpState, useBoundSelector, useBoundValue, useBoundValueOrUndefined, useMultiBoundValue, usePlaygroundState, useStateAction, useStoreSnapshot, validateStateKey };
1188
1322
 
1189
1323
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["internal"],"sources":["../src/theme.ts","../src/Button.tsx","../src/TextField.tsx","../src/state.tsx","../src/Slider.tsx","../src/Chart.tsx","../src/Container.tsx","../src/Code.tsx","../src/Heading.tsx","../src/Text.tsx","../src/Stepper.tsx","../src/Card.tsx","../src/List.tsx","../src/stateHelpers.ts","../src/ShowSource.tsx","../src/ArtifactErrorBoundary.tsx","../src/createRegistry.ts"],"sourcesContent":["/**\n * Shared theme tokens for @playgenx/components.\n *\n * All styling is driven from this file. There is intentionally no\n * \"config\" theme or runtime theme provider — these are the default\n * implementations of the registry, and a downstream host app can swap\n * them out entirely. Tokens live as constants so they're stable\n * across renders and don't allocate per call.\n */\n\nexport const colors = {\n bg: '#ffffff',\n fg: '#0f172a',\n mutedFg: '#475569',\n border: '#e2e8f0',\n primary: '#2563eb',\n primaryFg: '#ffffff',\n secondaryFg: '#0f172a',\n ghostFg: '#1d4ed8',\n cardBg: '#f8fafc',\n cardBorder: '#e2e8f0',\n codeBg: '#f1f5f9',\n codeFg: '#0f172a',\n sliderTrack: '#cbd5e1',\n sliderFill: '#2563eb',\n sliderThumb: '#1d4ed8',\n bar: '#2563eb',\n barLabel: '#0f172a',\n pie: ['#2563eb', '#16a34a', '#f59e0b', '#dc2626'],\n line: '#2563eb',\n stepperPast: '#16a34a',\n stepperCurrent: '#2563eb',\n stepperFuture: '#cbd5e1',\n} as const;\n\nexport const space = {\n none: '0',\n xs: '4px',\n sm: '8px',\n md: '12px',\n lg: '16px',\n xl: '24px',\n} as const;\n\nexport const radius = {\n sm: '4px',\n md: '6px',\n lg: '8px',\n} as const;\n\n/**\n * Common React-friendly prop accepts for content. Components that\n * accept children of arbitrary shape (Heading, Text, Card, Container,\n * ...) use this so the host can pass strings or JSX interchangeably.\n */\nexport type Children = string | number | React.ReactNode;\n\nimport type * as React from 'react';\n","import * as React from 'react';\nimport { colors, radius } from './theme.js';\n\n/**\n * Headless-style wrapper over `<button>` accepting the props defined in\n * `DEFAULT_COMPONENT_SCHEMAS.Button`. Pass `onClick` through; this\n * implementation does NOT execute arbitrary functions (deterministic\n * renderer constraint) so the click handler is rendered inert at mount.\n */\nexport interface ButtonProps {\n /** Visible text. Required. */\n label: string;\n /** Variant. Defaults to 'primary'. */\n variant?: 'primary' | 'secondary' | 'ghost';\n /** Disabled state. Defaults to false. */\n disabled?: boolean;\n /**\n * Optional click handler. The default impl forwards to onClick if\n * present; in a deterministic renderer pass `noEvents` instead.\n */\n onClick?: React.MouseEventHandler<HTMLButtonElement>;\n}\n\nexport function Button({\n label,\n variant = 'primary',\n disabled = false,\n onClick,\n}: ButtonProps): React.JSX.Element {\n const styles: React.CSSProperties = {\n fontFamily: 'inherit',\n fontSize: '14px',\n fontWeight: 500,\n padding: '8px 14px',\n borderRadius: radius.md,\n border: '1px solid transparent',\n cursor: disabled ? 'not-allowed' : 'pointer',\n opacity: disabled ? 0.5 : 1,\n background:\n variant === 'primary'\n ? colors.primary\n : variant === 'secondary'\n ? colors.secondaryFg\n : 'transparent',\n color:\n variant === 'ghost' ? colors.ghostFg : variant === 'secondary' ? colors.bg : colors.primaryFg,\n borderColor: variant === 'ghost' ? colors.border : 'transparent',\n };\n return (\n <button type=\"button\" disabled={disabled} onClick={onClick} style={styles} data-pgx=\"Button\">\n {label}\n </button>\n );\n}\n","import * as React from 'react';\nimport { colors, radius } from './theme.js';\n\nexport interface TextFieldProps {\n label?: string;\n value?: string;\n placeholder?: string;\n disabled?: boolean;\n /**\n * onChange is reported as `node` in the schema (it must be a\n * function reference, which the validator cannot statically type).\n * We forward to React's controlled input handler.\n */\n onChange?: React.ChangeEventHandler<HTMLInputElement>;\n}\n\n/**\n * Controlled text input. Without `value`/`onChange`, behaves as\n * uncontrolled (uses its own state via defaultValue). When a stable\n * (deterministic) caller wires both, the input is fully controlled.\n */\nexport function TextField({\n label,\n value,\n placeholder,\n disabled = false,\n onChange,\n}: TextFieldProps): React.JSX.Element {\n const wrapperStyle: React.CSSProperties = {\n display: 'flex',\n flexDirection: 'column',\n gap: '4px',\n fontFamily: 'inherit',\n };\n const labelStyle: React.CSSProperties = {\n fontSize: '12px',\n fontWeight: 500,\n color: colors.mutedFg,\n };\n const inputStyle: React.CSSProperties = {\n fontFamily: 'inherit',\n fontSize: '14px',\n padding: '8px 10px',\n border: `1px solid ${colors.border}`,\n borderRadius: radius.md,\n background: colors.bg,\n color: colors.fg,\n outline: 'none',\n };\n const inputProps: React.InputHTMLAttributes<HTMLInputElement> = {\n placeholder,\n disabled,\n onChange,\n };\n // Use uncontrolled defaultValue when caller omits value. We can't\n // set defaultValue AND value without React warning, so branch.\n if (value !== undefined) inputProps.value = value;\n else inputProps.defaultValue = '';\n return (\n <label style={wrapperStyle} data-pgx=\"TextField\">\n {label !== undefined ? <span style={labelStyle}>{label}</span> : null}\n <input {...inputProps} style={inputStyle} />\n </label>\n );\n}\n","/**\n * Per-render interactive state store. Used by PlaygroundStateProvider to\n * back interactive components (Slider, TextField, Button, Chart) without\n * requiring them to be fully controlled.\n *\n * Design notes:\n * - The store is a singleton instance per Provider, NOT React context.\n * Components consume it via usePlaygroundState() inside React renders,\n * and via .subscribe() / .get() / .set() from non-React callers.\n * - `set` is synchronous; subscribers fire in registration order on the\n * next microtask (so multiple sets in a single tick produce a single\n * re-render per subscriber).\n * - `set` with `===` equal value is a no-op (no subscriber fires).\n * - Throws if used outside a PlaygroundStateProvider (when required by\n * the caller's contract).\n *\n * @packageDocumentation\n */\n\nimport * as React from 'react';\n\n/**\n * Per-render state store. Components read/write values keyed by string.\n * One store per Provider instance; nested Providers create nested scopes.\n */\nexport interface PlaygroundState {\n /** Read a value by key. Returns undefined if unset. */\n get<T = unknown>(key: string): T | undefined;\n /**\n * Set a value. Triggers re-render of subscribers. No-op if the new\n * value is `===` to the current value.\n */\n set<T = unknown>(key: string, value: T): void;\n /**\n * Subscribe to changes on a single key. The callback fires on every\n * `set(key, ...)` with a different value. Returns an unsubscribe\n * function. Non-React callers can use this directly.\n */\n subscribe(key: string, cb: (value: unknown) => void): () => void;\n /**\n * Bulk-read: returns a shallow snapshot of all keys. Useful for\n * snapshotting state at a moment in time (e.g., for undo).\n */\n snapshot(): Readonly<Record<string, unknown>>;\n /** Bulk-write: replace all values. Subscribers fire for changed keys. */\n replaceAll(values: Record<string, unknown>): void;\n}\n\ninterface InternalState extends PlaygroundState {\n /** Test seam: forces sync-fire for unit tests. */\n _flush(): void;\n /**\n * Test seam: run `fn` with batch dedup enabled. While inside the\n * batch, repeated `set(key, ...)` calls collapse to a single\n * subscriber fire per key with the LAST value set. Returns\n * whatever `fn` returns.\n *\n * This is the same primitive as the `batch(state, fn)` helper in\n * stateHelpers.ts but exposed as a method for callers that already\n * hold a state ref.\n */\n _batch<T>(fn: () => T): T;\n /**\n * Internal seam: drop every subscriber from every key. Used by\n * PlaygroundStateProvider's unmount cleanup to prevent HMR\n * subscriber leaks. Not part of the public PlaygroundState\n * surface — do not call from app code (you have `subscribe()`'s\n * returned unsub function for the public path).\n */\n _clearAllSubscribers(): void;\n}\n\n/**\n * Create a fresh state store. Public so PlaygroundStateProvider can\n * construct one, but consumers should use Provider/usePlaygroundState\n * to access stores (not direct construction).\n *\n * The optional type parameter is the \"shape\" of values you intend to\n * store. It's purely a documentation convenience — the store does\n * not enforce it (so you can store heterogeneous values for\n * playgrounds that mix kinds), but `get<T>()` and `set<T>()` will\n * infer correctly when you pass it here.\n */\nexport function createPlaygroundState<T = unknown>(\n initial: Record<string, T> = {},\n): PlaygroundState {\n const values = new Map<string, unknown>(Object.entries(initial));\n // key -> Set of subscribers. We use Set for O(1) add/remove and\n // dedup of identical subscribers.\n const subs = new Map<string, Set<(value: unknown) => void>>();\n\n // Pending (key, value) pairs to fire on the next microtask. We\n // batch so a sequence of `set()` calls in the same tick produces a\n // single subscriber fire per affected key.\n let pending: Array<{ key: string; value: unknown }> = [];\n let scheduled = false;\n // Transactional batching: when `batchDepth > 0`, set() pushes to\n // `batchedPending` instead of `pending`. flush() flushes the\n // NON-batched pending queue (preserving history) but the batched\n // queue is collapsed: only the LAST value per key is kept. This\n // is what `batch(state, fn)` enables — atomic, deduplicated commits.\n let batchDepth = 0;\n let batchedPending: Array<{ key: string; value: unknown }> = [];\n\n const flush = (): void => {\n if (pending.length === 0) return;\n const batch = pending;\n pending = [];\n scheduled = false;\n // Fire every pending (key, value) pair, in order. We do NOT\n // dedupe — each `set()` call is a distinct event and subscribers\n // want to see the full history (e.g. for analytics). React\n // batches re-renders via the microtask flush anyway, so multiple\n // fires for the same key collapse into one render.\n for (const { key, value } of batch) {\n const list = subs.get(key);\n if (list) {\n // Snapshot the subscriber set so callbacks that unsubscribe\n // themselves mid-fire don't mutate the iteration source.\n for (const cb of [...list]) {\n try {\n cb(value);\n } catch (err) {\n // Swallow subscriber errors so one bad subscriber doesn't\n // take down the whole tree. In development we re-raise\n // the error to console.error so the bad subscriber is\n // diagnosable from the browser devtools; in production\n // we stay silent to avoid log spam.\n if (process.env.NODE_ENV !== 'production') {\n console.error(\n '[playgenx] subscriber for key %s threw:',\n key,\n err,\n );\n }\n }\n }\n }\n }\n };\n\n const schedule = (): void => {\n if (scheduled) return;\n scheduled = true;\n // queueMicrotask is available in Node 22+ and all modern browsers.\n // Falls back to Promise.resolve().then for older runtimes.\n if (typeof queueMicrotask === 'function') {\n queueMicrotask(flush);\n } else {\n Promise.resolve().then(flush);\n }\n };\n\n const state: InternalState = {\n get<T = unknown>(key: string): T | undefined {\n return values.get(key) as T | undefined;\n },\n set<T = unknown>(key: string, value: T): void {\n if (Object.is(values.get(key), value)) return; // no-op\n values.set(key, value);\n // Inside a batch: push to the dedupe queue instead of pending.\n // Outside a batch: push to pending (full-history mode).\n if (batchDepth > 0) {\n batchedPending.push({ key, value });\n } else {\n pending.push({ key, value });\n }\n schedule();\n },\n subscribe(key: string, cb: (value: unknown) => void): () => void {\n let list = subs.get(key);\n if (!list) {\n list = new Set();\n subs.set(key, list);\n }\n list.add(cb);\n return () => {\n const l = subs.get(key);\n if (l) {\n l.delete(cb);\n if (l.size === 0) subs.delete(key);\n }\n };\n },\n snapshot(): Readonly<Record<string, unknown>> {\n return Object.fromEntries(values);\n },\n replaceAll(values: Record<string, unknown>): void {\n for (const [k, v] of Object.entries(values)) {\n state.set(k, v);\n }\n },\n _flush(): void {\n flush();\n },\n _batch<T>(fn: () => T): T {\n batchDepth++;\n try {\n return fn();\n } finally {\n batchDepth--;\n // After the batch: if anything landed in batchedPending,\n // move it to pending AS A SINGLE EVENT PER KEY. Walk in\n // reverse so the LAST set wins (later writes to the same\n // key override earlier ones).\n if (batchDepth === 0 && batchedPending.length > 0) {\n const lastPerKey = new Map<string, unknown>();\n for (let i = batchedPending.length - 1; i >= 0; i--) {\n const { key, value } = batchedPending[i]!;\n if (!lastPerKey.has(key)) {\n lastPerKey.set(key, value);\n pending.push({ key, value });\n }\n }\n batchedPending = [];\n }\n }\n },\n _clearAllSubscribers(): void {\n // Replace with fresh maps; old subscribers are dropped on the\n // GC pass once their closure references go out of scope. This\n // is intentionally a hard reset — used only on Provider\n // unmount, where every subscriber in the tree is going away.\n subs.clear();\n // Also drop any pending fires that would have been delivered\n // to those now-dead subscribers. Without this, a stale set\n // queued just before unmount would still fire `cb(value)` on\n // a callback that has no consumer.\n pending = [];\n batchedPending = [];\n scheduled = false;\n },\n };\n return state;\n}\n\ninterface ProviderContextValue {\n state: PlaygroundState;\n}\n\n/**\n * React context. Exposed as a type only — consumers should use\n * PlaygroundStateProvider and usePlaygroundState rather than reading\n * the context directly.\n */\nconst PlaygroundStateContext = React.createContext<ProviderContextValue | null>(\n null,\n);\n\nexport interface PlaygroundStateProviderProps {\n /** Initial state values keyed by name. */\n initial?: Record<string, unknown>;\n /**\n * Optional pre-existing state. If supplied, `initial` is merged on\n * top (initial wins for overlapping keys). Use this for SSR\n * rehydration or seeded values.\n */\n seed?: Record<string, unknown>;\n children: React.ReactNode;\n}\n\n/**\n * Provide a PlaygroundState scope to descendant components.\n *\n * Each Provider instance has its own store; nested Providers create\n * independent scopes. Components rendered outside any Provider will\n * throw a clear error if they call usePlaygroundState.\n */\nexport function PlaygroundStateProvider(\n props: PlaygroundStateProviderProps,\n): React.JSX.Element {\n // Create the store once per Provider instance. The lazy initializer\n // ensures re-mounting (e.g. HMR) doesn't carry stale state across\n // refreshes.\n const [state] = React.useState(() => {\n const s = createPlaygroundState({ ...props.seed, ...props.initial });\n return s;\n });\n\n // Cleanup on unmount: clear all subscribers so a hot-reload doesn't\n // leak subscriptions across renders. Without this, every HMR cycle\n // would leave the OLD store with stale subscribers that fire on\n // every set — even though no component is listening.\n //\n // Why we don't drop the values Map: by the time this cleanup runs,\n // the closure over the store is unreachable. Letting the GC collect\n // it is enough. Subscribers are the leak risk because they're\n // closures that reference component-local state (setValue, force).\n React.useEffect(() => {\n return () => {\n // Clear all subscribers via the test seam. (The store doesn't\n // expose a public clear-all API because removing subscribers\n // without notifying them is almost always a bug. Unmount is\n // the one legitimate case.)\n (state as unknown as { _clearAllSubscribers?: () => void })\n ._clearAllSubscribers?.();\n };\n }, [state]);\n\n const value = React.useMemo(() => ({ state }), [state]);\n\n return React.createElement(\n PlaygroundStateContext.Provider,\n { value },\n props.children,\n );\n}\n\n/**\n * Hook to access the nearest PlaygroundState store. Throws a clear\n * error if called outside a Provider so consumers get a usable\n * diagnostic instead of a `Cannot read properties of undefined`.\n *\n * Note for @playgenx/renderer users: the renderer's `renderBody`\n * does NOT yet auto-wrap with a PlaygroundStateProvider. You'll\n * need to wrap your own tree with `<PlaygroundStateProvider>` (or\n * use the lower-level `renderNodes` API) before state-bound\n * components can resolve. The `withState` option on `renderBody`\n * is planned for a future renderer release (tracked in v0.6.0).\n */\nexport function usePlaygroundState(): PlaygroundState {\n const ctx = React.useContext(PlaygroundStateContext);\n if (ctx === null) {\n throw new Error(\n 'usePlaygroundState() must be called inside a <PlaygroundStateProvider>. ' +\n 'Wrap your component tree with the Provider. (A future renderer ' +\n 'release will auto-wrap; for now, do it explicitly.)',\n );\n }\n return ctx.state;\n}\n\n/**\n * Optional helper for binding a component prop to a state key. Returns\n * the live value (re-renders subscribers on change) and a setter. Pass\n * `undefined` for `key` to disable the binding — the component behaves\n * as if it had no stateKey, and `set` becomes a no-op. Safe to call\n * outside a Provider.\n *\n * Implementation note: this hook ALWAYS calls the same number of\n * React hooks regardless of whether `key` is set or a Provider is in\n * scope. The \"no binding\" / \"no Provider\" branch uses dummy local\n * state so the hook count stays aligned across renders. That means a\n * component can flip `stateKey` from defined to undefined (or move in\n * or out of a Provider) without crashing with a hooks-order error.\n *\n * Components that accept a `stateKey` prop should call this internally\n * and use the returned tuple as a drop-in for the underlying\n * value/onChange pair. The return type widens to `readonly [...] | undefined`\n * so the caller can still branch on `if (bound)` — but they don't have\n * to (the tuple is always safe to index).\n *\n * @example\n * const bound = useBoundValueOrUndefined<number>(stateKey, 50);\n * // ... onChange={(e) => bound?.[1](Number(e.currentTarget.value))}\n */\nexport function useBoundValueOrUndefined<T>(\n key: string | undefined,\n fallback: T,\n): readonly [T, (next: T) => void] | undefined {\n // Read the Provider context. `useContext` is unconditional and counts\n // as a hook, but its *value* can be null — that's fine. The point\n // is we never skip hooks based on a runtime condition.\n const ctx = React.useContext(PlaygroundStateContext);\n const bound = key !== undefined && ctx !== null;\n\n // Always allocate the same hook slots so the count is constant.\n // We use `fallback` as the initial value in both branches; if a\n // Provider + key are present the effect below pulls the live value.\n const [value, setValue] = React.useState<T>(fallback);\n const [, force] = React.useState(0);\n React.useEffect(() => {\n if (!bound || key === undefined || ctx === null) return;\n const initial = (ctx.state.get<T>(key) ?? fallback) as T;\n setValue(initial);\n const unsub = ctx.state.subscribe(key, (next) => {\n setValue(next as T);\n force((n) => n + 1);\n });\n return unsub;\n // We deliberately exclude `fallback` from deps: a changing fallback\n // would re-subscribe on every render. The cost is that if `fallback`\n // changes the visible value won't refresh — but that mirrors how\n // useBoundValue behaves (no refresh on fallback change either).\n }, [bound, ctx, key]);\n const set = React.useCallback(\n (next: T) => {\n if (!bound || key === undefined || ctx === null) return; // no-op\n ctx.state.set<T>(key, next);\n },\n [bound, ctx, key],\n );\n // When no binding is active, callers get an explicit `undefined`\n // tuple so they can branch on `if (bound)` without falsey\n // confusion (a `0` or `''` value would otherwise hide the binding\n // state).\n if (!bound) return undefined;\n return [value, set] as const;\n}\n\nexport function useBoundValue<T>(\n key: string,\n fallback: T,\n): readonly [T, (next: T) => void] {\n const bound = useBoundValueOrUndefined<T>(key, fallback);\n if (bound === undefined) {\n throw new Error(\n 'useBoundValue(key, ...) requires both a non-undefined `key` and a ' +\n '<PlaygroundStateProvider> ancestor. Use useBoundValueOrUndefined ' +\n 'if you want optional binding.',\n );\n }\n return bound;\n}\n\n/**\n * State-binding action shape. Used by `<Button onClickAction={...}>`.\n * { set: { count: 1 } } -> sets state.count = 1\n * { toggle: 'open' } -> sets state.open = !state.open\n */\nexport type StateAction =\n | { set?: Record<string, unknown>; toggle?: string }\n | undefined;\n\n/**\n * Apply a StateAction to the nearest PlaygroundState. Returns an\n * onClick handler that fires the action. If action is undefined\n * the handler is a no-op.\n */\nexport function useStateAction(\n action: StateAction,\n): (event: unknown) => void {\n const state = usePlaygroundState();\n // The `event` parameter (from onClick / onSubmit) is the React\n // event the caller hands us. We don't introspect it — actions\n // are identified purely by their `action` config. The eslint\n // config's `argsIgnorePattern` doesn't apply to callback params\n // inside `React.useCallback` closures (it only sees the outer\n // function's params), so we use a void cast to silence the lint\n // while keeping the type signature for callers.\n return React.useCallback(\n (event: unknown) => {\n void event; // explicitly unused\n if (action === undefined) return;\n if (action.set) {\n for (const [k, v] of Object.entries(action.set)) {\n state.set(k, v);\n }\n }\n if (action.toggle !== undefined) {\n const key = action.toggle;\n const current = state.get<unknown>(key);\n state.set(key, !current);\n }\n },\n [action, state],\n );\n}\n","import * as React from 'react';\nimport { colors } from './theme.js';\nimport { useBoundValueOrUndefined } from './state.jsx';\n\nexport interface SliderProps {\n /** Lower bound, inclusive. Required. */\n min: number;\n /** Upper bound, inclusive. Required. */\n max: number;\n /** Initial / controlled value. */\n value?: number;\n /** Increment between stops. Defaults to 1. */\n step?: number;\n /** Optional caption rendered above the slider. */\n label?: string;\n /**\n * When set, the slider is \"bound\" to the playground state: initial\n * value comes from state.get(stateKey), onChange writes state.set.\n * `value` prop is ignored when stateKey is present.\n */\n stateKey?: string;\n}\n\n/**\n * Range input. Three operating modes:\n *\n * 1. **Uncontrolled** (no `value`, no `stateKey`): the slider owns\n * its value as local React state. The onChange mutates that state.\n * Use this when nothing else needs to observe the value.\n *\n * 2. **Controlled by `value` prop**: the slider is read-only —\n * user input is ignored because there is no `onChange` callback\n * wired by the deterministic renderer. Use this for \"static\"\n * sliders in artifacts. (If you want fully interactive control,\n * use mode 3.)\n *\n * 3. **Bound to PlaygroundState via `stateKey`**: the slider reads\n * its value from the nearest Provider's store (initial: either\n * the store's current value OR `value` prop, whichever is\n * present; the live store wins when bound). On change, the\n * slider writes to the store. Other components can subscribe\n * to the same key.\n *\n * In all modes the displayed value is clamped to `[min, max]`. NaN\n * inputs clamp to `min`. When `min === max` the input is disabled.\n */\nexport function Slider({ min, max, value, step = 1, label, stateKey }: SliderProps): React.JSX.Element {\n // When stateKey is set, bind to playground state. useBoundValue\n // throws if no Provider is in scope; useBoundValueOrUndefined\n // returns undefined when stateKey is undefined so the rest of the\n // component can use the local-state behaviour.\n const [internal, setInternal] = React.useState(() => clamp(value ?? min, min, max));\n const bound = useBoundValueOrUndefined<number>(stateKey, internal);\n const controlled = value !== undefined;\n // When stateKey is bound, the bound value is the source of truth.\n const current = stateKey !== undefined && bound\n ? clamp(bound[0], min, max)\n : controlled\n ? clamp(value, min, max)\n : internal;\n const trackStyle: React.CSSProperties = {\n display: 'flex',\n flexDirection: 'column',\n gap: '6px',\n fontFamily: 'inherit',\n width: '100%',\n };\n const labelStyle: React.CSSProperties = {\n fontSize: '12px',\n color: colors.mutedFg,\n };\n const wrapStyle: React.CSSProperties = { display: 'flex', alignItems: 'center', gap: '10px' };\n const inputStyle: React.CSSProperties = { flex: 1, accentColor: colors.sliderFill };\n const valueStyle: React.CSSProperties = {\n minWidth: '32px',\n textAlign: 'right',\n fontVariantNumeric: 'tabular-nums',\n fontSize: '14px',\n color: colors.fg,\n };\n return (\n <div style={trackStyle} data-pgx=\"Slider\">\n {label !== undefined ? <span style={labelStyle}>{label}</span> : null}\n <div style={wrapStyle}>\n <input\n type=\"range\"\n min={min}\n max={max}\n step={step}\n value={current}\n disabled={min === max}\n aria-label={label}\n onChange={(e) => {\n const next = Number(e.currentTarget.value);\n if (stateKey !== undefined && bound) {\n bound[1](next);\n } else if (!controlled) {\n setInternal(next);\n }\n }}\n style={inputStyle}\n />\n <span style={valueStyle}>{current}</span>\n </div>\n </div>\n );\n}\n\nfunction clamp(n: number, lo: number, hi: number): number {\n if (Number.isNaN(n)) return lo;\n return Math.min(hi, Math.max(lo, n));\n}\n","import * as React from 'react';\nimport { colors } from './theme.js';\n\nexport type ChartKind = 'bar' | 'line' | 'pie';\n\n/**\n * The schema lets `data` be any ReactNode, but in practice callers\n * pass JSON-shaped arrays. We narrow at runtime:\n *\n * - bar: `{ labels: string[], values: number[] }`\n * - line: `{ x: number[], y: number[] }` or `{ series: { label, points: {x,y} }[] }`\n * - pie: `{ labels: string[], values: number[] }`\n *\n * Anything that doesn't fit is rendered as a `<pre>` fallback.\n */\nexport interface ChartProps {\n kind: ChartKind;\n data: unknown;\n title?: string;\n}\n\nexport function Chart({ kind, data, title }: ChartProps): React.JSX.Element {\n return (\n <div data-pgx=\"Chart\" data-chart-kind={kind} style={{ fontFamily: 'inherit' }}>\n {title !== undefined ? (\n <div style={{ fontSize: '14px', fontWeight: 600, color: colors.fg, marginBottom: '6px' }}>\n {title}\n </div>\n ) : null}\n {renderChart(kind, data)}\n </div>\n );\n}\n\nfunction renderChart(kind: ChartKind, data: unknown): React.JSX.Element {\n if (kind === 'bar') return renderBar(data);\n if (kind === 'line') return renderLine(data);\n return renderPie(data);\n}\n\nfunction renderBar(data: unknown): React.JSX.Element {\n const parsed = parseLabeled(data);\n if (!parsed) return fallback('bar chart', data);\n const { labels, values } = parsed;\n const max = Math.max(1, ...values);\n const width = 320;\n const height = 160;\n const barWidth = width / Math.max(1, labels.length);\n return (\n <svg\n width={width}\n height={height}\n role=\"img\"\n aria-label=\"Bar chart\"\n style={{ display: 'block' }}\n >\n {values.map((v, i) => {\n const h = (Math.max(0, v) / max) * (height - 24);\n return (\n <g key={i}>\n <rect\n x={i * barWidth + 2}\n y={height - 12 - h}\n width={Math.max(1, barWidth - 4)}\n height={h}\n fill={colors.bar}\n rx={2}\n />\n <text\n x={i * barWidth + barWidth / 2}\n y={height - 2}\n fontSize={10}\n textAnchor=\"middle\"\n fill={colors.barLabel}\n >\n {(labels[i] ?? '').slice(0, 8)}\n </text>\n </g>\n );\n })}\n </svg>\n );\n}\n\nfunction renderLine(data: unknown): React.JSX.Element {\n // Two accepted shapes; pick whichever parses cleanly.\n let points: Array<{ x: number; y: number }> = [];\n if (data && typeof data === 'object' && 'series' in (data as Record<string, unknown>)) {\n const series = (data as { series: Array<{ points?: Array<{ x: number; y: number }> }> }).series;\n const first = series?.[0];\n points = Array.isArray(first?.points) ? first.points : [];\n } else if (\n data &&\n typeof data === 'object' &&\n Array.isArray((data as { x?: unknown }).x) &&\n Array.isArray((data as { y?: unknown }).y)\n ) {\n const xArr = (data as { x: number[] }).x;\n const yArr = (data as { y: number[] }).y;\n points = xArr.map((x, i) => ({ x, y: yArr[i] ?? 0 }));\n }\n if (points.length === 0) return fallback('line chart', data);\n const xs = points.map((p) => p.x);\n const ys = points.map((p) => p.y);\n const xMin = Math.min(...xs);\n const xMax = Math.max(...xs);\n const yMin = Math.min(...ys);\n const yMax = Math.max(...ys);\n const w = 320;\n const h = 160;\n const sx = (x: number) => (xMax === xMin ? w / 2 : ((x - xMin) / (xMax - xMin)) * (w - 8) + 4);\n const sy = (y: number) =>\n yMax === yMin ? h / 2 : h - ((y - yMin) / (yMax - yMin)) * (h - 24) - 12;\n const path = points\n .map((p, i) => `${i === 0 ? 'M' : 'L'}${sx(p.x).toFixed(2)},${sy(p.y).toFixed(2)}`)\n .join(' ');\n return (\n <svg width={w} height={h} role=\"img\" aria-label=\"Line chart\" style={{ display: 'block' }}>\n <path d={path} fill=\"none\" stroke={colors.line} strokeWidth={2} />\n {points.map((p, i) => (\n <circle key={i} cx={sx(p.x)} cy={sy(p.y)} r={2} fill={colors.line} />\n ))}\n </svg>\n );\n}\n\nfunction renderPie(data: unknown): React.JSX.Element {\n const parsed = parseLabeled(data);\n if (!parsed) return fallback('pie chart', data);\n const total = parsed.values.reduce((a, b) => a + Math.max(0, b), 0) || 1;\n const cx = 80;\n const cy = 80;\n const r = 60;\n let angle = -Math.PI / 2;\n return (\n <svg width={160} height={160} role=\"img\" aria-label=\"Pie chart\" style={{ display: 'block' }}>\n {parsed.values.map((v, i) => {\n const slice = (Math.max(0, v) / total) * Math.PI * 2;\n const x1 = cx + r * Math.cos(angle);\n const y1 = cy + r * Math.sin(angle);\n const x2 = cx + r * Math.cos(angle + slice);\n const y2 = cy + r * Math.sin(angle + slice);\n const large = slice > Math.PI ? 1 : 0;\n const path =\n slice >= Math.PI * 2 - 1e-6\n ? `M ${cx - r} ${cy} A ${r} ${r} 0 1 1 ${cx + r} ${cy} A ${r} ${r} 0 1 1 ${cx - r} ${cy}`\n : `M ${cx} ${cy} L ${x1} ${y1} A ${r} ${r} 0 ${large} 1 ${x2} ${y2} Z`;\n angle += slice;\n const fill = colors.pie[i % colors.pie.length] ?? colors.bar;\n return <path key={i} d={path} fill={fill} />;\n })}\n </svg>\n );\n}\n\nfunction parseLabeled(data: unknown): { labels: string[]; values: number[] } | null {\n if (!data || typeof data !== 'object') return null;\n const labels = (data as { labels?: unknown }).labels;\n const values = (data as { values?: unknown }).values;\n if (!Array.isArray(labels) || !Array.isArray(values)) return null;\n if (labels.length !== values.length) return null;\n if (!labels.every((l) => typeof l === 'string' || typeof l === 'number')) return null;\n if (!values.every((v) => typeof v === 'number' || typeof v === 'string')) return null;\n return {\n labels: labels.map(String),\n values: values.map((v) => (typeof v === 'number' ? v : Number(v))),\n };\n}\n\nfunction fallback(label: string, data: unknown): React.JSX.Element {\n return (\n <pre\n style={{\n margin: 0,\n fontSize: '12px',\n background: colors.codeBg,\n color: colors.codeFg,\n padding: '8px',\n borderRadius: '4px',\n overflow: 'auto',\n }}\n >\n {label} data: {JSON.stringify(data, null, 2)}\n </pre>\n );\n}\n","import * as React from 'react';\n\nexport interface ContainerProps {\n padding?: string;\n gap?: string;\n children?: React.ReactNode;\n}\n\n/**\n * Layout wrapper. Defaults to a vertical flex container with 16px\n * padding and 12px gap when callers omit props.\n */\nexport function Container({ padding, gap, children }: ContainerProps): React.JSX.Element {\n const style: React.CSSProperties = {\n display: 'flex',\n flexDirection: 'column',\n padding: padding ?? '16px',\n gap: gap ?? '12px',\n fontFamily: 'inherit',\n color: 'inherit',\n boxSizing: 'border-box',\n };\n return (\n <div style={style} data-pgx=\"Container\">\n {children}\n </div>\n );\n}\n","import * as React from 'react';\nimport { colors, radius } from './theme.js';\n\nexport interface CodeProps {\n language?: string;\n children?: React.ReactNode;\n}\n\n/**\n * Inline code formatter. Renders children as a `<code>` element inside\n * a styled wrapper. If `children` is a single string, it displays\n * verbatim; for multi-line content we fall back to a `<pre>`-styled\n * block.\n */\nexport function Code({ language, children }: CodeProps): React.JSX.Element {\n const isString = typeof children === 'string';\n const isMulti = isString && (children as string).includes('\\n');\n if (isMulti) {\n return (\n <pre\n data-pgx=\"Code\"\n data-language={language ?? 'text'}\n style={{\n background: colors.codeBg,\n color: colors.codeFg,\n padding: '12px',\n borderRadius: radius.md,\n fontSize: '12px',\n overflow: 'auto',\n margin: 0,\n }}\n >\n <code>{children}</code>\n </pre>\n );\n }\n return (\n <code\n data-pgx=\"Code-inline\"\n data-language={language ?? 'text'}\n style={{\n background: colors.codeBg,\n color: colors.codeFg,\n padding: '2px 6px',\n borderRadius: radius.sm,\n fontSize: '0.9em',\n }}\n >\n {children}\n </code>\n );\n}\n","import * as React from 'react';\nimport { colors } from './theme.js';\n\nexport interface HeadingProps {\n /**\n * Heading level (1..6). Out-of-range or undefined falls back to 2.\n * The renderer should never see an `Undefined` value here unless the\n * schema validator said optional props can be omitted.\n */\n level?: number;\n color?: string;\n children?: React.ReactNode;\n}\n\nconst sizes: Record<number, string> = {\n 1: '24px',\n 2: '20px',\n 3: '18px',\n 4: '16px',\n 5: '14px',\n 6: '13px',\n};\n\nexport function Heading({ level, color, children }: HeadingProps): React.JSX.Element {\n const safeLevel = clampLevel(level);\n const size = sizes[safeLevel] ?? sizes[2]!;\n const style: React.CSSProperties = {\n fontFamily: 'inherit',\n fontSize: size,\n fontWeight: 700,\n color: color ?? colors.fg,\n margin: 0,\n lineHeight: 1.3,\n };\n // Render an element corresponding to the level. React enforces\n // TagName = 'h1' | 'h2' ... via JSX, so we switch dynamically via\n // createElement.\n return React.createElement(`h${safeLevel}`, { style, 'data-pgx': `Heading` }, children);\n}\n\nfunction clampLevel(level: number | undefined): 1 | 2 | 3 | 4 | 5 | 6 {\n if (typeof level !== 'number' || !Number.isFinite(level)) return 2;\n const i = Math.floor(level);\n if (i < 1) return 1;\n if (i > 6) return 6;\n return i as 1 | 2 | 3 | 4 | 5 | 6;\n}\n","import * as React from 'react';\nimport { colors } from './theme.js';\n\nexport interface TextProps {\n weight?: 'normal' | 'bold';\n size?: string;\n color?: string;\n children?: React.ReactNode;\n}\n\nexport function Text({ weight = 'normal', size, color, children }: TextProps): React.JSX.Element {\n const style: React.CSSProperties = {\n fontFamily: 'inherit',\n fontSize: size ?? '14px',\n fontWeight: weight === 'bold' ? 600 : 400,\n color: color ?? colors.fg,\n margin: 0,\n lineHeight: 1.5,\n };\n return (\n <p style={style} data-pgx=\"Text\">\n {children}\n </p>\n );\n}\n","import * as React from 'react';\nimport { colors } from './theme.js';\n\nexport interface Step {\n id: string;\n title: string;\n body?: React.ReactNode;\n}\n\nexport interface StepperProps {\n steps: Step[];\n /** 0-indexed initial step. Out-of-range falls back to 0. */\n initial?: number;\n}\n\n/**\n * Multi-step reveal. State: the active index. Previous steps can be\n * revisited; future steps are disabled until reached.\n */\nexport function Stepper({ steps, initial }: StepperProps): React.JSX.Element {\n const initialIdx = clampIndex(initial ?? 0, steps.length);\n const [active, setActive] = React.useState(initialIdx);\n const wrapStyle: React.CSSProperties = {\n fontFamily: 'inherit',\n display: 'flex',\n flexDirection: 'column',\n gap: '12px',\n };\n const listStyle: React.CSSProperties = {\n display: 'flex',\n gap: '6px',\n listStyle: 'none',\n padding: 0,\n margin: 0,\n };\n const stepBtnBase: React.CSSProperties = {\n width: '28px',\n height: '28px',\n borderRadius: '50%',\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontFamily: 'inherit',\n fontSize: '12px',\n fontWeight: 600,\n border: '1px solid transparent',\n };\n const bodyStyle: React.CSSProperties = {\n border: `1px solid ${colors.border}`,\n borderRadius: '6px',\n padding: '10px',\n background: colors.bg,\n color: colors.fg,\n };\n return (\n <div data-pgx=\"Stepper\" style={wrapStyle}>\n <ol style={listStyle}>\n {steps.map((s, i) => {\n const isPast = i < active;\n const isCurrent = i === active;\n const future = i > active;\n const stepStyle: React.CSSProperties = {\n ...stepBtnBase,\n background: isCurrent\n ? colors.stepperCurrent\n : isPast\n ? colors.stepperPast\n : colors.stepperFuture,\n color: isCurrent || isPast ? '#fff' : colors.fg,\n opacity: future ? 0.6 : 1,\n cursor: future ? 'not-allowed' : 'pointer',\n };\n return (\n <li key={s.id}>\n <button\n type=\"button\"\n aria-label={`Step ${i + 1}: ${s.title}`}\n aria-current={isCurrent ? 'step' : undefined}\n disabled={future}\n onClick={() => setActive(i)}\n style={stepStyle}\n >\n {i + 1}\n </button>\n </li>\n );\n })}\n </ol>\n <div style={bodyStyle}>\n <div style={{ fontWeight: 600, marginBottom: '4px', fontSize: '14px' }}>\n {steps[active]?.title ?? ''}\n </div>\n <div style={{ fontSize: '13px' }}>{steps[active]?.body ?? null}</div>\n </div>\n </div>\n );\n}\n\nfunction clampIndex(n: number, len: number): number {\n if (len === 0) return 0;\n if (!Number.isFinite(n)) return 0;\n return Math.min(len - 1, Math.max(0, Math.floor(n)));\n}\n","import * as React from 'react';\nimport { colors, radius, space } from './theme.js';\n\nexport interface CardProps {\n title?: string;\n /**\n * Visual elevation. 0 = flat (border only), 1+ = heavier shadow.\n * Defaults to 1.\n */\n elevation?: number;\n children?: React.ReactNode;\n}\n\nexport function Card({ title, elevation = 1, children }: CardProps): React.JSX.Element {\n const shadow =\n elevation >= 3\n ? '0 4px 12px rgba(15, 23, 42, 0.18)'\n : elevation === 2\n ? '0 2px 8px rgba(15, 23, 42, 0.12)'\n : elevation === 1\n ? '0 1px 2px rgba(15, 23, 42, 0.06)'\n : 'none';\n const cardStyle: React.CSSProperties = {\n background: colors.cardBg,\n border: `1px solid ${colors.cardBorder}`,\n borderRadius: radius.md,\n boxShadow: shadow,\n padding: space.md,\n fontFamily: 'inherit',\n color: colors.fg,\n display: 'flex',\n flexDirection: 'column',\n gap: space.sm,\n };\n const titleStyle: React.CSSProperties = {\n fontSize: '14px',\n fontWeight: 600,\n margin: 0,\n };\n return (\n <section data-pgx=\"Card\" style={cardStyle}>\n {title !== undefined ? <h3 style={titleStyle}>{title}</h3> : null}\n {children}\n </section>\n );\n}\n","import * as React from 'react';\nimport { colors } from './theme.js';\n\nexport interface ListProps {\n /**\n * Items to render. Schema marks this as `node`; in practice callers\n * pass arrays of strings/numbers/ReactNodes. Anything else is\n * rendered as a single bullet containing the value.\n */\n items?: unknown;\n /** When true, renders as `<ol>` instead of `<ul>`. */\n ordered?: boolean;\n /** Override the wrapper element for full control. */\n children?: React.ReactNode;\n}\n\n/**\n * List of items. Renders `items` as a list of strings/numbers (the\n * common artifact prompt output). If `children` are passed they take\n * precedence over `items`.\n */\nexport function List({ items, ordered, children }: ListProps): React.JSX.Element {\n const style: React.CSSProperties = {\n margin: 0,\n paddingLeft: '20px',\n fontFamily: 'inherit',\n color: colors.fg,\n fontSize: '14px',\n lineHeight: 1.6,\n };\n if (children !== undefined && children !== null) {\n return React.createElement(ordered ? 'ol' : 'ul', { style, 'data-pgx': 'List' }, children);\n }\n const arr = Array.isArray(items) ? items : items === undefined ? [] : [items];\n return React.createElement(\n ordered ? 'ol' : 'ul',\n { style, 'data-pgx': 'List' },\n arr.map((item, i) => {\n const node: React.ReactNode =\n typeof item === 'string' || typeof item === 'number' ? String(item) : JSON.stringify(item);\n return <li key={i}>{node}</li>;\n }),\n );\n}\n","/**\n * Helper functions for working with {@link PlaygroundState}.\n *\n * These are pure operations over a `PlaygroundState` — no React, no\n * hooks, no I/O. They live alongside the store so that:\n * - Devtools / CLI scripts can operate on a state without React\n * (the bin/state-cli.ts script uses these directly).\n * - Test code can drive a store through a thin façade.\n * - Server-side renderers can dump, validate, and diff snapshots\n * without needing a DOM.\n *\n * @packageDocumentation\n */\n\nimport type { PlaygroundState } from './state.jsx';\n\n/**\n * Structured diff between two state snapshots. Pure function — does\n * not touch the stores. Returns `null` when the snapshots are\n * shallowly equal (no additions, no changes, no removals).\n *\n * @example\n * const a = { x: 1, y: 2 };\n * const b = { x: 1, y: 3, z: 4 };\n * diffSnapshots(a, b); // { added: ['z'], changed: ['y'], removed: [] }\n */\nexport interface StateDiff {\n /** Keys present in `next` but absent from `prev`. */\n added: string[];\n /** Keys whose value changed (using `Object.is` to compare). */\n changed: string[];\n /** Keys present in `prev` but absent from `next`. */\n removed: string[];\n}\n\nexport function diffSnapshots(\n prev: Readonly<Record<string, unknown>>,\n next: Readonly<Record<string, unknown>>,\n): StateDiff | null {\n const added: string[] = [];\n const changed: string[] = [];\n const removed: string[] = [];\n const prevKeys = Object.keys(prev);\n const nextKeys = Object.keys(next);\n const prevSet = new Set(prevKeys);\n const nextSet = new Set(nextKeys);\n for (const k of nextKeys) {\n if (!prevSet.has(k)) {\n added.push(k);\n continue;\n }\n if (!Object.is(prev[k], next[k])) {\n changed.push(k);\n }\n }\n for (const k of prevKeys) {\n if (!nextSet.has(k)) removed.push(k);\n }\n added.sort();\n changed.sort();\n removed.sort();\n if (added.length === 0 && changed.length === 0 && removed.length === 0) {\n return null;\n }\n return { added, changed, removed };\n}\n\n/**\n * Convenience: take snapshots of both stores and diff them. Returns\n * `null` when equal. Useful in tests and debug endpoints.\n */\nexport function diffState(\n _a: PlaygroundState,\n _b: PlaygroundState,\n prev?: Readonly<Record<string, unknown>>,\n next?: Readonly<Record<string, unknown>>,\n): StateDiff | null {\n const aSnap = prev ?? _a.snapshot();\n const bSnap = next ?? _b.snapshot();\n return diffSnapshots(aSnap, bSnap);\n}\n\n/**\n * Validate a state-key string. Returns `null` on success, or a\n * human-readable error message on failure. The rules:\n *\n * - 1..64 characters\n * - No whitespace\n * - Only alphanumerics, dots, dashes, underscores\n * - Must start with an alphabetic character (so a parser can\n * safely infer `<Slider stateKey=\"...\">` from a body without\n * swallowing accidental numeric keys).\n *\n * Note: keys like `with/slash` or `with spaces` are rejected because\n * the schema-driven body parser uses them as attribute names —\n * a key with weird characters would break the round-trip.\n */\nexport function validateStateKey(key: string): string | null {\n if (key.length === 0) return 'stateKey must be a non-empty string';\n if (key.length > 64) return 'stateKey must be at most 64 characters';\n if (/\\s/.test(key)) return 'stateKey must not contain whitespace';\n if (!/^[A-Za-z][A-Za-z0-9._-]*$/.test(key)) {\n return (\n 'stateKey contains forbidden characters (allowed: A-Z, a-z, ' +\n '0-9, dot, dash, underscore; must start with a letter)'\n );\n }\n return null;\n}\n\n/**\n * Remove every key from the store, firing subscribers with `undefined`.\n * After this call, `state.snapshot()` is `{}`.\n */\nexport function clearState(state: PlaygroundState): void {\n // Snapshot first to avoid mutating the iteration source.\n for (const k of Object.keys(state.snapshot())) {\n state.set(k, undefined);\n }\n}\n\n/**\n * JSON-envelope snapshot for offline inspection. Useful for:\n * - piping into `jq` / debug endpoints\n * - attaching to error reports\n * - round-tripping through `JSON.parse(state.snapshot)`.\n *\n * The `version` field is bumped if the envelope shape ever changes,\n * so consumers can branch on it.\n */\nexport interface StateEnvelope {\n /** Always 1 for now. */\n version: 1;\n /** Sorted list of keys (stable for diffing). */\n keys: string[];\n /** Shallow key→value map. */\n values: Record<string, unknown>;\n}\n\nexport function dumpState(state: PlaygroundState): string {\n const snap = state.snapshot();\n const envelope: StateEnvelope = {\n version: 1,\n keys: Object.keys(snap).sort(),\n values: { ...snap },\n };\n return JSON.stringify(envelope, null, 2);\n}\n\n/**\n * Apply multiple `set` calls as a single atomic batch. Each\n * subscriber sees only the LAST value written to its key in this\n * batch. The store still batches subscriber fires via the microtask\n * scheduler — `batch` does not flush synchronously, it only ensures\n * that within the batch, repeated `set` calls to the same key don't\n * queue redundant fires.\n *\n * Useful for: undo/redo, multi-field form commits, hydrated state\n * restore where you want each subscriber to fire exactly once with\n * the final value.\n *\n * @example\n * batch(state, (s) => {\n * s.set('x', 1);\n * s.set('y', 2);\n * s.set('x', 3); // overwrites; subscriber sees only 3\n * });\n */\nexport function batch<T>(\n state: PlaygroundState,\n fn: (state: PlaygroundState) => T,\n): T {\n // `_batch` is the underlying transactional primitive on the store.\n // We type-cast because the public PlaygroundState interface doesn't\n // expose this test seam — only the helper does.\n const internal = state as unknown as {\n _batch: (fn: () => T) => T;\n };\n return internal._batch(() => fn(state));\n}","/**\n * Render-prop component that shows a toggle-able raw-source panel.\n * Consumer controls the trigger UI via a children render prop.\n *\n * Design notes:\n * - Render-prop pattern (not props.children-as-trigger) because the\n * trigger UI varies wildly across consumers (button, link, icon,\n * inline text). The consumer gets `(toggle, showing)` and decides\n * what to render.\n * - The source panel is a `<pre>` with `<code>` inside. Plain-text;\n * no syntax highlighting (avoiding a 50KB highlight.js dep).\n * Consumers who need highlighting can compose with their own\n * syntax-highlighter.\n * - The panel is rendered INLINE (not in a portal/tooltip) so the\n * toggle's visual feedback is immediate.\n *\n * @packageDocumentation\n */\n\nimport * as React from 'react';\n\nexport interface ShowSourceProps {\n /** The raw body to display when the user expands the source. */\n body: string;\n /** Source language hint. Used in `data-language` for styling hooks. */\n language?: 'tsx' | 'json';\n /**\n * Children is a render prop that receives `(toggle, showing)`.\n * The consumer is expected to render a trigger element (button,\n * link, etc.) and call `toggle` on user interaction.\n */\n children: (toggle: () => void, showing: boolean) => React.ReactNode;\n}\n\n/**\n * Toggle button + expandable source panel. The trigger UI is the\n * consumer's choice; the panel is plain `<pre><code>`.\n */\nexport function ShowSource(props: ShowSourceProps): React.JSX.Element {\n const { body, language, children } = props;\n const [showing, setShowing] = React.useState(false);\n // Wrap setShowing to keep the toggle reference stable. Consumers\n // can pass `toggle` to a `useEffect` dep array without retriggering.\n const toggle = React.useCallback(() => {\n setShowing((s) => !s);\n }, []);\n\n return (\n <>\n {children(toggle, showing)}\n {showing ? (\n <pre\n data-pgx=\"ShowSource\"\n data-language={language ?? 'text'}\n style={{\n background: '#0f172a',\n color: '#e2e8f0',\n padding: '12px',\n borderRadius: '6px',\n overflowX: 'auto',\n fontFamily: 'ui-monospace, Menlo, monospace',\n fontSize: '12px',\n lineHeight: 1.5,\n margin: '8px 0 0',\n maxHeight: '320px',\n whiteSpace: 'pre',\n }}\n >\n <code>{body}</code>\n </pre>\n ) : null}\n </>\n );\n}\n","/**\n * Error boundary for rendered artifacts. Catches render-time errors\n * (malformed body, throw from a component, etc.) and shows a recoverable\n * fallback. Without this, a single bad artifact blanks the student's\n * whole page.\n *\n * Design notes:\n * - Uses React's class-component error boundary API (the only\n * first-class option in React 18/19).\n * - Default fallback shows the error message + an optional \"Show source\"\n * toggle that reveals the raw body. Consumer can override with\n * `fallback` for custom UX.\n * - `onError` fires before the fallback renders so consumers can log\n * to Sentry / Datadog / etc.\n *\n * @packageDocumentation\n */\n\nimport * as React from 'react';\n\nimport { ShowSource } from './ShowSource.js';\n\nexport interface ArtifactErrorBoundaryProps {\n children: React.ReactNode;\n /**\n * Called when a render error is caught. The `info.componentStack`\n * string is the React component stack at the point of error. Log\n * to your observability backend here.\n */\n onError?: (error: Error, info: { componentStack: string }) => void;\n /**\n * Optional body string. If present and the consumer renders the\n * default fallback, a \"Show source\" toggle will be available that\n * reveals this body verbatim. Ignored if a custom `fallback` is\n * supplied (the consumer is responsible for surfacing source).\n */\n body?: string;\n /**\n * Source language hint for the ShowSource toggle in the default\n * fallback. Defaults to 'tsx' (most artifacts are TSX).\n */\n language?: 'tsx' | 'json';\n /**\n * Optional custom fallback. Pass a React element for a static fallback\n * or a function that receives the error for a dynamic one. If\n * omitted, the default fallback renders a panel with the error\n * message and (if `body` is supplied) a ShowSource toggle.\n */\n fallback?: React.ReactNode | ((error: Error) => React.ReactNode);\n /**\n * Label shown in the default fallback header. Defaults to the\n * artifact kind identifier (e.g. \"playground artifact failed to\n * render\"). The consumer is expected to pass the kind.\n */\n kind?: string;\n}\n\ninterface State {\n error: Error | null;\n}\n\n/**\n * Default fallback panel. Renders the error message and, if `body` is\n * provided, a ShowSource toggle. Designed to be a calm, recoverable\n * surface — not a stack-trace dump that panics users.\n */\nfunction DefaultFallback({\n error,\n body,\n language,\n kind,\n}: {\n error: Error;\n body?: string;\n language?: 'tsx' | 'json';\n kind?: string;\n}): React.JSX.Element {\n const label = kind ? `${kind} artifact failed to render` : 'Artifact failed to render';\n return (\n <div\n role=\"alert\"\n data-pgx=\"ArtifactErrorBoundary\"\n data-pgx-kind={kind}\n style={{\n border: '1px solid #fca5a5',\n background: '#fef2f2',\n color: '#7f1d1d',\n borderRadius: '8px',\n padding: '12px 16px',\n fontFamily: 'ui-sans-serif, system-ui, sans-serif',\n fontSize: '14px',\n maxWidth: '720px',\n margin: '12px 0',\n }}\n >\n <div style={{ fontWeight: 600, marginBottom: '6px' }}>{label}</div>\n <code\n data-pgx=\"error-message\"\n style={{\n display: 'block',\n fontFamily: 'ui-monospace, Menlo, monospace',\n fontSize: '12px',\n background: 'rgba(0,0,0,0.04)',\n padding: '6px 8px',\n borderRadius: '4px',\n whiteSpace: 'pre-wrap',\n wordBreak: 'break-word',\n }}\n >\n {error.message}\n </code>\n {body !== undefined ? (\n <div style={{ marginTop: '8px' }}>\n <ShowSource body={body} language={language}>\n {(toggle, showing) => (\n <button\n type=\"button\"\n onClick={toggle}\n data-pgx=\"show-source-toggle\"\n style={{\n background: 'transparent',\n border: '1px solid #fca5a5',\n color: '#7f1d1d',\n padding: '4px 10px',\n fontSize: '12px',\n borderRadius: '4px',\n cursor: 'pointer',\n }}\n >\n {showing ? 'Hide source' : 'Show source'}\n </button>\n )}\n </ShowSource>\n </div>\n ) : null}\n </div>\n );\n}\n\n/**\n * Error boundary. Catches render-time errors in `children` and shows\n * the fallback. The error state is reset on prop change of `children`\n * (or explicit `resetKey` bump) so the consumer can recover by\n * re-rendering.\n */\nexport class ArtifactErrorBoundary extends React.Component<\n ArtifactErrorBoundaryProps,\n State\n> {\n state: State = { error: null };\n\n static getDerivedStateFromError(error: Error): State {\n return { error };\n }\n\n override componentDidCatch(error: Error, info: React.ErrorInfo): void {\n if (this.props.onError) {\n try {\n this.props.onError(error, { componentStack: info.componentStack ?? '' });\n } catch {\n // Swallow — onError callback errors must not break rendering.\n }\n }\n }\n\n override render(): React.ReactNode {\n const { error } = this.state;\n if (error === null) return this.props.children;\n\n const { fallback, body, language, kind } = this.props;\n if (typeof fallback === 'function') return fallback(error);\n if (fallback !== undefined) return fallback;\n return (\n <DefaultFallback\n error={error}\n body={body}\n language={language}\n kind={kind}\n />\n );\n }\n}\n","/**\n * `createRegistry(overrides)` — build a component map with the default\n * 11 components plus caller overrides. Returns a frozen map so post-hoc\n * mutation can't surprise concurrent renders.\n *\n * Lowercase HTML tags (div, span, etc.) are NOT in this map; they're\n * intrinsic to React and handled by `renderBody` directly.\n *\n * @packageDocumentation\n */\n\nimport type { ComponentType } from 'react';\n\nimport { Button } from './Button.js';\nimport { Card } from './Card.js';\nimport { Chart } from './Chart.js';\nimport { Code } from './Code.js';\nimport { Container } from './Container.js';\nimport { Heading } from './Heading.js';\nimport { List } from './List.js';\nimport { Slider } from './Slider.js';\nimport { Stepper } from './Stepper.js';\nimport { Text } from './Text.js';\nimport { TextField } from './TextField.js';\n\n/**\n * Map of PascalCase component name to React component. Loose typing\n * (`ComponentType<any>`) because each component's prop shape differs and\n * the runtime doesn't know which one it's looking up. Consumers who\n * need stricter types can build their own typed wrapper around\n * `renderBody`.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type ComponentMap = Record<string, ComponentType<any>>;\n\nconst DEFAULT_REGISTRY: ComponentMap = Object.freeze({\n Button,\n Card,\n Chart,\n Code,\n Container,\n Heading,\n List,\n Slider,\n Stepper,\n Text,\n TextField,\n});\n\n/**\n * The full default registry (Button, Card, Chart, Code, Container,\n * Heading, List, Slider, Stepper, Text, TextField). Frozen. Use\n * `createRegistry(overrides)` to extend.\n */\nexport const componentMap: ComponentMap = DEFAULT_REGISTRY;\n\n/**\n * Build a new registry by merging the defaults with caller-supplied\n * overrides. The returned map is frozen (Object.freeze) to prevent\n * post-hoc mutation that would surprise concurrent renders.\n *\n * **Lowercase HTML tags are NOT in this map.** The renderer handles\n * `div`, `span`, etc. as React intrinsic elements separately. Calling\n * `createRegistry({ div: StubDiv })` will NOT override the renderer\n * for `<div>` (the renderer uses the lowercase lookup path first).\n *\n * @example\n * ```ts\n * const map = createRegistry({\n * MathExpression: MathExpressionComponent,\n * LatexBlock: LatexBlockComponent,\n * });\n * ```\n */\nexport function createRegistry(overrides: Partial<ComponentMap>): ComponentMap {\n // Merge: defaults are the base; overrides win. Lowercase keys are\n // filtered out because they refer to React intrinsic HTML tags\n // (div, span, etc.) that renderBody handles intrinsically — the\n // caller cannot override intrinsic rendering via the registry.\n // Object.freeze on the result prevents consumers from accidentally\n // mutating the global componentMap by mutating their copy.\n const merged: ComponentMap = { ...DEFAULT_REGISTRY };\n for (const key of Object.keys(overrides) as (keyof ComponentMap)[]) {\n const value = overrides[key];\n if (value === undefined) continue;\n if (key[0] !== key[0]!.toUpperCase()) continue; // skip lowercase\n merged[key] = value;\n }\n return Object.freeze(merged);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["internal"],"sources":["../src/theme.ts","../src/Button.tsx","../src/TextField.tsx","../src/state.tsx","../src/Slider.tsx","../src/Chart.tsx","../src/Container.tsx","../src/Code.tsx","../src/Heading.tsx","../src/Text.tsx","../src/Stepper.tsx","../src/Card.tsx","../src/List.tsx","../src/stateHelpers.ts","../src/ShowSource.tsx","../src/ArtifactErrorBoundary.tsx","../src/createRegistry.ts"],"sourcesContent":["/**\n * Shared theme tokens for @playgenx/components.\n *\n * All styling is driven from this file. There is intentionally no\n * \"config\" theme or runtime theme provider — these are the default\n * implementations of the registry, and a downstream host app can swap\n * them out entirely. Tokens live as constants so they're stable\n * across renders and don't allocate per call.\n */\n\nexport const colors = {\n bg: '#ffffff',\n fg: '#0f172a',\n mutedFg: '#475569',\n border: '#e2e8f0',\n primary: '#2563eb',\n primaryFg: '#ffffff',\n secondaryFg: '#0f172a',\n ghostFg: '#1d4ed8',\n cardBg: '#f8fafc',\n cardBorder: '#e2e8f0',\n codeBg: '#f1f5f9',\n codeFg: '#0f172a',\n sliderTrack: '#cbd5e1',\n sliderFill: '#2563eb',\n sliderThumb: '#1d4ed8',\n bar: '#2563eb',\n barLabel: '#0f172a',\n pie: ['#2563eb', '#16a34a', '#f59e0b', '#dc2626'],\n line: '#2563eb',\n stepperPast: '#16a34a',\n stepperCurrent: '#2563eb',\n stepperFuture: '#cbd5e1',\n} as const;\n\nexport const space = {\n none: '0',\n xs: '4px',\n sm: '8px',\n md: '12px',\n lg: '16px',\n xl: '24px',\n} as const;\n\nexport const radius = {\n sm: '4px',\n md: '6px',\n lg: '8px',\n} as const;\n\n/**\n * Common React-friendly prop accepts for content. Components that\n * accept children of arbitrary shape (Heading, Text, Card, Container,\n * ...) use this so the host can pass strings or JSX interchangeably.\n */\nexport type Children = string | number | React.ReactNode;\n\nimport type * as React from 'react';\n","import * as React from 'react';\nimport { colors, radius } from './theme.js';\n\n/**\n * Headless-style wrapper over `<button>` accepting the props defined in\n * `DEFAULT_COMPONENT_SCHEMAS.Button`. Pass `onClick` through; this\n * implementation does NOT execute arbitrary functions (deterministic\n * renderer constraint) so the click handler is rendered inert at mount.\n */\nexport interface ButtonProps {\n /** Visible text. Required. */\n label: string;\n /** Variant. Defaults to 'primary'. */\n variant?: 'primary' | 'secondary' | 'ghost';\n /** Disabled state. Defaults to false. */\n disabled?: boolean;\n /**\n * Optional click handler. The default impl forwards to onClick if\n * present; in a deterministic renderer pass `noEvents` instead.\n */\n onClick?: React.MouseEventHandler<HTMLButtonElement>;\n}\n\nexport function Button({\n label,\n variant = 'primary',\n disabled = false,\n onClick,\n}: ButtonProps): React.JSX.Element {\n const styles: React.CSSProperties = {\n fontFamily: 'inherit',\n fontSize: '14px',\n fontWeight: 500,\n padding: '8px 14px',\n borderRadius: radius.md,\n border: '1px solid transparent',\n cursor: disabled ? 'not-allowed' : 'pointer',\n opacity: disabled ? 0.5 : 1,\n background:\n variant === 'primary'\n ? colors.primary\n : variant === 'secondary'\n ? colors.secondaryFg\n : 'transparent',\n color:\n variant === 'ghost' ? colors.ghostFg : variant === 'secondary' ? colors.bg : colors.primaryFg,\n borderColor: variant === 'ghost' ? colors.border : 'transparent',\n };\n return (\n <button type=\"button\" disabled={disabled} onClick={onClick} style={styles} data-pgx=\"Button\">\n {label}\n </button>\n );\n}\n","import * as React from 'react';\nimport { colors, radius } from './theme.js';\n\nexport interface TextFieldProps {\n label?: string;\n value?: string;\n placeholder?: string;\n disabled?: boolean;\n /**\n * onChange is reported as `node` in the schema (it must be a\n * function reference, which the validator cannot statically type).\n * We forward to React's controlled input handler.\n */\n onChange?: React.ChangeEventHandler<HTMLInputElement>;\n}\n\n/**\n * Controlled text input. Without `value`/`onChange`, behaves as\n * uncontrolled (uses its own state via defaultValue). When a stable\n * (deterministic) caller wires both, the input is fully controlled.\n */\nexport function TextField({\n label,\n value,\n placeholder,\n disabled = false,\n onChange,\n}: TextFieldProps): React.JSX.Element {\n const wrapperStyle: React.CSSProperties = {\n display: 'flex',\n flexDirection: 'column',\n gap: '4px',\n fontFamily: 'inherit',\n };\n const labelStyle: React.CSSProperties = {\n fontSize: '12px',\n fontWeight: 500,\n color: colors.mutedFg,\n };\n const inputStyle: React.CSSProperties = {\n fontFamily: 'inherit',\n fontSize: '14px',\n padding: '8px 10px',\n border: `1px solid ${colors.border}`,\n borderRadius: radius.md,\n background: colors.bg,\n color: colors.fg,\n outline: 'none',\n };\n const inputProps: React.InputHTMLAttributes<HTMLInputElement> = {\n placeholder,\n disabled,\n onChange,\n };\n // Use uncontrolled defaultValue when caller omits value. We can't\n // set defaultValue AND value without React warning, so branch.\n if (value !== undefined) inputProps.value = value;\n else inputProps.defaultValue = '';\n return (\n <label style={wrapperStyle} data-pgx=\"TextField\">\n {label !== undefined ? <span style={labelStyle}>{label}</span> : null}\n <input {...inputProps} style={inputStyle} />\n </label>\n );\n}\n","/**\n * Per-render interactive state store. Used by PlaygroundStateProvider to\n * back interactive components (Slider, TextField, Button, Chart) without\n * requiring them to be fully controlled.\n *\n * Design notes:\n * - The store is a singleton instance per Provider, NOT React context.\n * Components consume it via usePlaygroundState() inside React renders,\n * and via .subscribe() / .get() / .set() from non-React callers.\n * - `set` is synchronous; subscribers fire in registration order on the\n * next microtask (so multiple sets in a single tick produce a single\n * re-render per subscriber).\n * - `set` with `===` equal value is a no-op (no subscriber fires).\n * - Throws if used outside a PlaygroundStateProvider (when required by\n * the caller's contract).\n *\n * @packageDocumentation\n */\n\nimport * as React from 'react';\n\n/**\n * Per-render state store. Components read/write values keyed by string.\n * One store per Provider instance; nested Providers create nested scopes.\n */\nexport interface PlaygroundState {\n /** Read a value by key. Returns undefined if unset. */\n get<T = unknown>(key: string): T | undefined;\n /**\n * Set a value. Triggers re-render of subscribers. No-op if the new\n * value is `===` to the current value.\n */\n set<T = unknown>(key: string, value: T): void;\n /**\n * Subscribe to changes on a single key. The callback fires on every\n * `set(key, ...)` with a different value. Returns an unsubscribe\n * function. Non-React callers can use this directly.\n */\n subscribe(key: string, cb: (value: unknown) => void): () => void;\n /**\n * Bulk-read: returns a shallow snapshot of all keys. Useful for\n * snapshotting state at a moment in time (e.g., for undo).\n */\n snapshot(): Readonly<Record<string, unknown>>;\n /** Bulk-write: replace all values. Subscribers fire for changed keys. */\n replaceAll(values: Record<string, unknown>): void;\n}\n\ninterface InternalState extends PlaygroundState {\n /** Test seam: forces sync-fire for unit tests. */\n _flush(): void;\n /**\n * Test seam: run `fn` with batch dedup enabled. While inside the\n * batch, repeated `set(key, ...)` calls collapse to a single\n * subscriber fire per key with the LAST value set. Returns\n * whatever `fn` returns.\n *\n * This is the same primitive as the `batch(state, fn)` helper in\n * stateHelpers.ts but exposed as a method for callers that already\n * hold a state ref.\n */\n _batch<T>(fn: () => T): T;\n /**\n * Internal seam: drop every subscriber from every key. Used by\n * PlaygroundStateProvider's unmount cleanup to prevent HMR\n * subscriber leaks. Not part of the public PlaygroundState\n * surface — do not call from app code (you have `subscribe()`'s\n * returned unsub function for the public path).\n */\n _clearAllSubscribers(): void;\n}\n\n/**\n * Create a fresh state store. Public so PlaygroundStateProvider can\n * construct one, but consumers should use Provider/usePlaygroundState\n * to access stores (not direct construction).\n *\n * The optional type parameter is the \"shape\" of values you intend to\n * store. It's purely a documentation convenience — the store does\n * not enforce it (so you can store heterogeneous values for\n * playgrounds that mix kinds), but `get<T>()` and `set<T>()` will\n * infer correctly when you pass it here.\n */\nexport function createPlaygroundState<T = unknown>(\n initial: Record<string, T> = {},\n): PlaygroundState {\n const values = new Map<string, unknown>(Object.entries(initial));\n // key -> Set of subscribers. We use Set for O(1) add/remove and\n // dedup of identical subscribers.\n const subs = new Map<string, Set<(value: unknown) => void>>();\n\n // Pending (key, value) pairs to fire on the next microtask. We\n // batch so a sequence of `set()` calls in the same tick produces a\n // single subscriber fire per affected key.\n let pending: Array<{ key: string; value: unknown }> = [];\n let scheduled = false;\n // Transactional batching: when `batchDepth > 0`, set() pushes to\n // `batchedPending` instead of `pending`. flush() flushes the\n // NON-batched pending queue (preserving history) but the batched\n // queue is collapsed: only the LAST value per key is kept. This\n // is what `batch(state, fn)` enables — atomic, deduplicated commits.\n let batchDepth = 0;\n let batchedPending: Array<{ key: string; value: unknown }> = [];\n\n const flush = (): void => {\n if (pending.length === 0) return;\n const batch = pending;\n pending = [];\n scheduled = false;\n // Fire every pending (key, value) pair, in order. We do NOT\n // dedupe — each `set()` call is a distinct event and subscribers\n // want to see the full history (e.g. for analytics). React\n // batches re-renders via the microtask flush anyway, so multiple\n // fires for the same key collapse into one render.\n for (const { key, value } of batch) {\n const list = subs.get(key);\n if (list) {\n // Snapshot the subscriber set so callbacks that unsubscribe\n // themselves mid-fire don't mutate the iteration source.\n for (const cb of [...list]) {\n try {\n cb(value);\n } catch (err) {\n // Swallow subscriber errors so one bad subscriber doesn't\n // take down the whole tree. In development we re-raise\n // the error to console.error so the bad subscriber is\n // diagnosable from the browser devtools; in production\n // we stay silent to avoid log spam.\n if (process.env.NODE_ENV !== 'production') {\n console.error(\n '[playgenx] subscriber for key %s threw:',\n key,\n err,\n );\n }\n }\n }\n }\n }\n };\n\n const schedule = (): void => {\n if (scheduled) return;\n scheduled = true;\n // queueMicrotask is available in Node 22+ and all modern browsers.\n // Falls back to Promise.resolve().then for older runtimes.\n if (typeof queueMicrotask === 'function') {\n queueMicrotask(flush);\n } else {\n Promise.resolve().then(flush);\n }\n };\n\n const state: InternalState = {\n get<T = unknown>(key: string): T | undefined {\n return values.get(key) as T | undefined;\n },\n set<T = unknown>(key: string, value: T): void {\n if (Object.is(values.get(key), value)) return; // no-op\n values.set(key, value);\n // Inside a batch: push to the dedupe queue instead of pending.\n // Outside a batch: push to pending (full-history mode).\n if (batchDepth > 0) {\n batchedPending.push({ key, value });\n } else {\n pending.push({ key, value });\n }\n schedule();\n },\n subscribe(key: string, cb: (value: unknown) => void): () => void {\n let list = subs.get(key);\n if (!list) {\n list = new Set();\n subs.set(key, list);\n }\n list.add(cb);\n return () => {\n const l = subs.get(key);\n if (l) {\n l.delete(cb);\n if (l.size === 0) subs.delete(key);\n }\n };\n },\n snapshot(): Readonly<Record<string, unknown>> {\n return Object.fromEntries(values);\n },\n replaceAll(values: Record<string, unknown>): void {\n for (const [k, v] of Object.entries(values)) {\n state.set(k, v);\n }\n },\n _flush(): void {\n flush();\n },\n _batch<T>(fn: () => T): T {\n batchDepth++;\n try {\n return fn();\n } finally {\n batchDepth--;\n // After the batch: if anything landed in batchedPending,\n // move it to pending AS A SINGLE EVENT PER KEY. Walk in\n // reverse so the LAST set wins (later writes to the same\n // key override earlier ones).\n if (batchDepth === 0 && batchedPending.length > 0) {\n const lastPerKey = new Map<string, unknown>();\n for (let i = batchedPending.length - 1; i >= 0; i--) {\n const { key, value } = batchedPending[i]!;\n if (!lastPerKey.has(key)) {\n lastPerKey.set(key, value);\n pending.push({ key, value });\n }\n }\n batchedPending = [];\n }\n }\n },\n _clearAllSubscribers(): void {\n // Replace with fresh maps; old subscribers are dropped on the\n // GC pass once their closure references go out of scope. This\n // is intentionally a hard reset — used only on Provider\n // unmount, where every subscriber in the tree is going away.\n subs.clear();\n // Also drop any pending fires that would have been delivered\n // to those now-dead subscribers. Without this, a stale set\n // queued just before unmount would still fire `cb(value)` on\n // a callback that has no consumer.\n pending = [];\n batchedPending = [];\n scheduled = false;\n },\n };\n return state;\n}\n\ninterface ProviderContextValue {\n state: PlaygroundState;\n}\n\n/**\n * React context. Exposed as a type only — consumers should use\n * PlaygroundStateProvider and usePlaygroundState rather than reading\n * the context directly.\n */\nconst PlaygroundStateContext = React.createContext<ProviderContextValue | null>(\n null,\n);\n\nexport interface PlaygroundStateProviderProps {\n /** Initial state values keyed by name. */\n initial?: Record<string, unknown>;\n /**\n * Optional pre-existing state. If supplied, `initial` is merged on\n * top (initial wins for overlapping keys). Use this for SSR\n * rehydration or seeded values.\n */\n seed?: Record<string, unknown>;\n children: React.ReactNode;\n}\n\n/**\n * Provide a PlaygroundState scope to descendant components.\n *\n * Each Provider instance has its own store; nested Providers create\n * independent scopes. Components rendered outside any Provider will\n * throw a clear error if they call usePlaygroundState.\n */\nexport function PlaygroundStateProvider(\n props: PlaygroundStateProviderProps,\n): React.JSX.Element {\n // Create the store once per Provider instance. The lazy initializer\n // ensures re-mounting (e.g. HMR) doesn't carry stale state across\n // refreshes.\n const [state] = React.useState(() => {\n const s = createPlaygroundState({ ...props.seed, ...props.initial });\n return s;\n });\n\n // Cleanup on unmount: clear all subscribers so a hot-reload doesn't\n // leak subscriptions across renders. Without this, every HMR cycle\n // would leave the OLD store with stale subscribers that fire on\n // every set — even though no component is listening.\n //\n // Why we don't drop the values Map: by the time this cleanup runs,\n // the closure over the store is unreachable. Letting the GC collect\n // it is enough. Subscribers are the leak risk because they're\n // closures that reference component-local state (setValue, force).\n React.useEffect(() => {\n return () => {\n // Clear all subscribers via the test seam. (The store doesn't\n // expose a public clear-all API because removing subscribers\n // without notifying them is almost always a bug. Unmount is\n // the one legitimate case.)\n (state as unknown as { _clearAllSubscribers?: () => void })\n ._clearAllSubscribers?.();\n };\n }, [state]);\n\n const value = React.useMemo(() => ({ state }), [state]);\n\n return React.createElement(\n PlaygroundStateContext.Provider,\n { value },\n props.children,\n );\n}\n\n/**\n * Hook to access the nearest PlaygroundState store. Throws a clear\n * error if called outside a Provider so consumers get a usable\n * diagnostic instead of a `Cannot read properties of undefined`.\n *\n * Note for @playgenx/renderer users: the renderer's `renderBody`\n * does NOT yet auto-wrap with a PlaygroundStateProvider. You'll\n * need to wrap your own tree with `<PlaygroundStateProvider>` (or\n * use the lower-level `renderNodes` API) before state-bound\n * components can resolve. The `withState` option on `renderBody`\n * is planned for a future renderer release (tracked in v0.6.0).\n */\nexport function usePlaygroundState(): PlaygroundState {\n const ctx = React.useContext(PlaygroundStateContext);\n if (ctx === null) {\n throw new Error(\n 'usePlaygroundState() must be called inside a <PlaygroundStateProvider>. ' +\n 'Wrap your component tree with the Provider. (A future renderer ' +\n 'release will auto-wrap; for now, do it explicitly.)',\n );\n }\n return ctx.state;\n}\n\n/**\n * Optional helper for binding a component prop to a state key. Returns\n * the live value (re-renders subscribers on change) and a setter. Pass\n * `undefined` for `key` to disable the binding — the component behaves\n * as if it had no stateKey, and `set` becomes a no-op. Safe to call\n * outside a Provider.\n *\n * Implementation note: this hook ALWAYS calls the same number of\n * React hooks regardless of whether `key` is set or a Provider is in\n * scope. The \"no binding\" / \"no Provider\" branch returns a static\n * tuple so the hook count stays aligned across renders. That means a\n * component can flip `stateKey` from defined to undefined (or move in\n * or out of a Provider) without crashing with a hooks-order error.\n *\n * The hook uses React 19's `useSyncExternalStore` so SSR renders the\n * Provider's current value synchronously — no \"value=fallback on\n * server, value=real after hydration\" surprise. The hook count drops\n * from 5 (useContext + useState + useState + useEffect + useCallback)\n * to 3 (useContext + useSyncExternalStore + useCallback) as a side\n * benefit.\n *\n * Components that accept a `stateKey` prop should call this internally\n * and use the returned tuple as a drop-in for the underlying\n * value/onChange pair. The return type widens to `readonly [...] | undefined`\n * so the caller can still branch on `if (bound)` — but they don't have\n * to (the tuple is always safe to index).\n *\n * @example\n * const bound = useBoundValueOrUndefined<number>(stateKey, 50);\n * // ... onChange={(e) => bound?.[1](Number(e.currentTarget.value))}\n */\nexport function useBoundValueOrUndefined<T>(\n key: string | undefined,\n fallback: T,\n): readonly [T, (next: T) => void] | undefined {\n // Hook 1: read the Provider context. Always called (no conditional).\n const ctx = React.useContext(PlaygroundStateContext);\n\n // Read the current value via useSyncExternalStore. This is the\n // SSR-safe primitive: it runs synchronously during renderToString\n // (via getServerSnapshot) AND during hydration (via getSnapshot),\n // guaranteeing server and client agree on the first render value.\n //\n // We pin the snapshot function identity with useCallback so React's\n // bail-out logic can short-circuit when the store hasn't changed.\n // The snapshot closes over `ctx`, `key`, and `fallback`; if any of\n // those change between renders, React re-reads the value. (Stable\n // identity also means we don't re-subscribe on every render.)\n const bound = key !== undefined && ctx !== null;\n const value = React.useSyncExternalStore(\n // subscribe: register a callback that triggers a re-render.\n // React calls this once on mount; the returned function is the\n // unsubscribe. If `bound` is false, return a no-op unsub.\n React.useCallback(\n (onStoreChange: () => void) => {\n if (!bound || key === undefined || ctx === null) return () => {};\n return ctx.state.subscribe(key, onStoreChange);\n },\n [bound, ctx, key],\n ),\n // getSnapshot: client-side read. Must match getServerSnapshot\n // for hydration to succeed without warnings.\n React.useCallback((): T => {\n if (!bound || key === undefined || ctx === null) return fallback;\n return (ctx.state.get<T>(key) ?? fallback) as T;\n }, [bound, ctx, key, fallback]),\n // getServerSnapshot: SSR read. Same as getSnapshot because the\n // store is the same on server and client (same Provider seed).\n React.useCallback((): T => {\n if (!bound || key === undefined || ctx === null) return fallback;\n return (ctx.state.get<T>(key) ?? fallback) as T;\n }, [bound, ctx, key, fallback]),\n );\n\n // Hook 3: the setter. No-op when unbound.\n const set = React.useCallback(\n (next: T) => {\n if (!bound || key === undefined || ctx === null) return;\n ctx.state.set<T>(key, next);\n },\n [bound, ctx, key],\n );\n // When no binding is active, callers get an explicit `undefined`\n // tuple so they can branch on `if (bound)` without falsey\n // confusion (a `0` or `''` value would otherwise hide the binding\n // state).\n if (!bound) return undefined;\n return [value, set] as const;\n}\n\nexport function useBoundValue<T>(\n key: string,\n fallback: T,\n): readonly [T, (next: T) => void] {\n const bound = useBoundValueOrUndefined<T>(key, fallback);\n if (bound === undefined) {\n throw new Error(\n 'useBoundValue(key, ...) requires both a non-undefined `key` and a ' +\n '<PlaygroundStateProvider> ancestor. Use useBoundValueOrUndefined ' +\n 'if you want optional binding.',\n );\n }\n return bound;\n}\n\n/**\n * Non-subscribing accessor for the store. Returns a stable tuple of\n * imperative API methods (`get`, `set`, `subscribe`, `snapshot`,\n * `replaceAll`) plus the raw `state` ref — none of which trigger a\n * re-render when used.\n *\n * When to use this instead of `useBoundValue`:\n *\n * - You need to read state inside an event handler (no render needed).\n * - You need to set state from many different handlers, not one bound prop.\n * - You're implementing a custom hook that wraps the store.\n * - You want to subscribe imperatively (for analytics, side-effects).\n *\n * When NOT to use this: if you need the component to RE-RENDER on\n * state changes, use `useBoundValue` (which subscribes for you).\n *\n * @example\n * function LogoutButton() {\n * const { get, set } = useStoreSnapshot();\n * return (\n * <button onClick={() => {\n * if (get<boolean>('confirmLogout')) set('confirmLogout', false);\n * doLogout();\n * }}>Log out</button>\n * );\n * }\n */\nexport function useStoreSnapshot(): {\n readonly state: PlaygroundState;\n readonly get: <T = unknown>(key: string) => T | undefined;\n readonly set: <T = unknown>(key: string, value: T) => void;\n readonly subscribe: (key: string, cb: (value: unknown) => void) => () => void;\n readonly snapshot: () => Readonly<Record<string, unknown>>;\n readonly replaceAll: (values: Record<string, unknown>) => void;\n} {\n const ctx = React.useContext(PlaygroundStateContext);\n if (ctx === null) {\n throw new Error(\n 'useStoreSnapshot() must be called inside a <PlaygroundStateProvider>.',\n );\n }\n // Stable references — the store itself never changes for the\n // lifetime of the Provider, so we can hand back the methods\n // directly. (No useCallback wrapper needed; the methods are bound\n // to the same store instance for the Provider's lifetime.)\n return {\n state: ctx.state,\n get: ctx.state.get,\n set: ctx.state.set,\n subscribe: ctx.state.subscribe,\n snapshot: ctx.state.snapshot,\n replaceAll: ctx.state.replaceAll,\n };\n}\n\n/**\n * Bind a state key with a selector transform. Returns the SELECTED\n * value, not the raw value. The component only re-renders when the\n * selected slice changes — not when OTHER fields on the same key\n * change.\n *\n * Useful for normalized state where one key holds an object and you\n * only care about one property:\n *\n * @example\n * interface User { name: string; age: number; email: string; }\n * const userName = useBoundSelector<User, string>(\n * 'currentUser',\n * (u) => u?.name ?? '(anonymous)',\n * 'guest'\n * );\n * // Setting `currentUser.age` does NOT re-render this component.\n * // Setting `currentUser.name` DOES re-render this component.\n *\n * The setter writes the SELECTED value as-is to the store. For\n * partial-merge semantics (e.g., \"set only the name, keep other\n * fields\"), use `useStoreSnapshot()` directly and merge yourself.\n *\n * If the selector throws, the error propagates and the component\n * unmounts via the nearest error boundary. Wrap your selector in\n * a try/catch if you need resilience.\n */\nexport function useBoundSelector<T, U>(\n key: string,\n selector: (raw: T | undefined) => U,\n fallback: U,\n): readonly [U, (next: U) => void] {\n // Call useBoundValueOrUndefined once at the top level. The hook\n // count for THIS call is fixed (3 — useContext + useSyncExternalStore\n // + useCallback). We derive the selected value via useMemo on\n // `bound[0]`; we derive the setter via useCallback. Total hooks\n // here: 5 (the 3 from useBoundValueOrUndefined + useMemo +\n // useCallback).\n //\n // We pass `fallback` (typed `U`) as the bound hook's fallback.\n // The bound hook's T == our U here; if the key is unset in the\n // store, we get `fallback` (U). The selector then runs over it.\n // This matches the \"missing-key → fallback\" pattern that selectors\n // already expect.\n const bound = useBoundValueOrUndefined<U>(key, fallback);\n const raw = bound === undefined ? undefined : bound[0];\n // useMemo with [raw] dep: if raw reference is the same (Object.is),\n // return the cached selected value. If the selector transforms to\n // the same primitive, React's bail-out kicks in for free.\n const value = React.useMemo<U>(\n () => selector(raw),\n [raw, selector, fallback],\n );\n // Setter: write the selected value back to the store. We need to\n // be careful not to call useBoundValueOrUndefined again (would\n // duplicate hooks). Instead, capture the setter from the bound\n // tuple — it's stable across renders (useCallback in the hook).\n const set = React.useCallback(\n (next: U) => {\n if (bound === undefined) return;\n // Type assertion: the caller is responsible for the\n // contract that `U` is assignable to `T`.\n bound[1](next as unknown as T);\n },\n [bound],\n );\n // If the underlying binding is undefined (no Provider / unbound),\n // throw — useBoundSelector requires a binding by definition.\n if (bound === undefined) {\n throw new Error(\n 'useBoundSelector requires a non-undefined `key` and a ' +\n '<PlaygroundStateProvider> ancestor.',\n );\n }\n return [value, set] as const;\n}\n\n/**\n * Bind multiple keys at once. Returns a `Record<key, [value, setter]>`\n * for the keys you specify. Each setter writes back to its own key.\n *\n * Useful for forms and dashboards where multiple bound inputs share\n * a single Provider.\n *\n * @example\n * const form = useMultiBoundValue({\n * name: { fallback: '' },\n * age: { fallback: 0 },\n * email: { fallback: '' },\n * });\n * // form.name[0] === current name string\n * // form.age[1](42) writes 42 to state.age\n *\n * The hook subscribes ONCE per key (so 5 keys = 5 subscriptions,\n * not a single batched subscription). If you bind a LOT of keys,\n * consider using `useStoreSnapshot()` instead — it doesn't subscribe.\n *\n * @example\n * // 50-row table, each row needs its own value\n * const { get, set } = useStoreSnapshot();\n * rows.map(row => <input value={get(`cell-${row.id}`) ?? ''}\n * onChange={e => set(`cell-${row.id}`, e.target.value)} />);\n */\nexport function useMultiBoundValue<K extends string>(\n bindings: Record<K, { fallback: unknown }>,\n): { readonly [P in K]: readonly [unknown, (next: unknown) => void] } {\n const ctx = React.useContext(PlaygroundStateContext);\n if (ctx === null) {\n throw new Error(\n 'useMultiBoundValue() must be called inside a <PlaygroundStateProvider>.',\n );\n }\n // We can't call useBoundValueOrUndefined in a loop (Rules of Hooks\n // require a fixed call count per render), so we call it once per\n // declared key. Object.keys order is stable per the spec, so the\n // hook order is stable across renders.\n const result = {} as { [P in K]: readonly [unknown, (next: unknown) => void] };\n // The hook count is `Object.keys(bindings).length` — call each one\n // unconditionally with the same key in the same order.\n const keys = Object.keys(bindings) as K[];\n // For each key, call useBoundValueOrUndefined. We need to compose\n // these into a Record, but useBoundValueOrUndefined itself calls\n // hooks. We can't wrap it in a helper without losing the hook\n // order — instead we just call it directly per key.\n //\n // Practical note: this hook is awkward to use with arbitrary key\n // counts because the hook count depends on the bindings object.\n // For most use cases (5-10 keys) this is fine. If you need 50+\n // keys, use `useStoreSnapshot()` directly.\n for (const k of keys) {\n const b = useBoundValueOrUndefined<unknown>(\n k,\n bindings[k].fallback,\n );\n if (b === undefined) {\n // No Provider — but ctx above says there IS one. Should never\n // happen. Defensive fallback: return [fallback, noop].\n result[k] = [bindings[k].fallback, () => {}] as const;\n } else {\n result[k] = b;\n }\n }\n return result;\n}\n\n/**\n * State-binding action shape. Used by `<Button onClickAction={...}>`.\n * { set: { count: 1 } } -> sets state.count = 1\n * { toggle: 'open' } -> sets state.open = !state.open\n */\nexport type StateAction =\n | { set?: Record<string, unknown>; toggle?: string }\n | undefined;\n\n/**\n * Apply a StateAction to the nearest PlaygroundState. Returns an\n * onClick handler that fires the action. If action is undefined\n * the handler is a no-op.\n */\nexport function useStateAction(\n action: StateAction,\n): (event: unknown) => void {\n const state = usePlaygroundState();\n // The `event` parameter (from onClick / onSubmit) is the React\n // event the caller hands us. We don't introspect it — actions\n // are identified purely by their `action` config. The eslint\n // config's `argsIgnorePattern` doesn't apply to callback params\n // inside `React.useCallback` closures (it only sees the outer\n // function's params), so we use a void cast to silence the lint\n // while keeping the type signature for callers.\n return React.useCallback(\n (event: unknown) => {\n void event; // explicitly unused\n if (action === undefined) return;\n if (action.set) {\n for (const [k, v] of Object.entries(action.set)) {\n state.set(k, v);\n }\n }\n if (action.toggle !== undefined) {\n const key = action.toggle;\n const current = state.get<unknown>(key);\n state.set(key, !current);\n }\n },\n [action, state],\n );\n}\n","import * as React from 'react';\nimport { colors } from './theme.js';\nimport { useBoundValueOrUndefined } from './state.jsx';\n\nexport interface SliderProps {\n /** Lower bound, inclusive. Required. */\n min: number;\n /** Upper bound, inclusive. Required. */\n max: number;\n /** Initial / controlled value. */\n value?: number;\n /** Increment between stops. Defaults to 1. */\n step?: number;\n /** Optional caption rendered above the slider. */\n label?: string;\n /**\n * When set, the slider is \"bound\" to the playground state: initial\n * value comes from state.get(stateKey), onChange writes state.set.\n * `value` prop is ignored when stateKey is present.\n */\n stateKey?: string;\n}\n\n/**\n * Range input. Three operating modes:\n *\n * 1. **Uncontrolled** (no `value`, no `stateKey`): the slider owns\n * its value as local React state. The onChange mutates that state.\n * Use this when nothing else needs to observe the value.\n *\n * 2. **Controlled by `value` prop**: the slider is read-only —\n * user input is ignored because there is no `onChange` callback\n * wired by the deterministic renderer. Use this for \"static\"\n * sliders in artifacts. (If you want fully interactive control,\n * use mode 3.)\n *\n * 3. **Bound to PlaygroundState via `stateKey`**: the slider reads\n * its value from the nearest Provider's store (initial: either\n * the store's current value OR `value` prop, whichever is\n * present; the live store wins when bound). On change, the\n * slider writes to the store. Other components can subscribe\n * to the same key.\n *\n * In all modes the displayed value is clamped to `[min, max]`. NaN\n * inputs clamp to `min`. When `min === max` the input is disabled.\n */\nexport function Slider({ min, max, value, step = 1, label, stateKey }: SliderProps): React.JSX.Element {\n // When stateKey is set, bind to playground state. useBoundValue\n // throws if no Provider is in scope; useBoundValueOrUndefined\n // returns undefined when stateKey is undefined so the rest of the\n // component can use the local-state behaviour.\n const [internal, setInternal] = React.useState(() => clamp(value ?? min, min, max));\n const bound = useBoundValueOrUndefined<number>(stateKey, internal);\n const controlled = value !== undefined;\n // When stateKey is bound, the bound value is the source of truth.\n const current = stateKey !== undefined && bound\n ? clamp(bound[0], min, max)\n : controlled\n ? clamp(value, min, max)\n : internal;\n const trackStyle: React.CSSProperties = {\n display: 'flex',\n flexDirection: 'column',\n gap: '6px',\n fontFamily: 'inherit',\n width: '100%',\n };\n const labelStyle: React.CSSProperties = {\n fontSize: '12px',\n color: colors.mutedFg,\n };\n const wrapStyle: React.CSSProperties = { display: 'flex', alignItems: 'center', gap: '10px' };\n const inputStyle: React.CSSProperties = { flex: 1, accentColor: colors.sliderFill };\n const valueStyle: React.CSSProperties = {\n minWidth: '32px',\n textAlign: 'right',\n fontVariantNumeric: 'tabular-nums',\n fontSize: '14px',\n color: colors.fg,\n };\n return (\n <div style={trackStyle} data-pgx=\"Slider\">\n {label !== undefined ? <span style={labelStyle}>{label}</span> : null}\n <div style={wrapStyle}>\n <input\n type=\"range\"\n min={min}\n max={max}\n step={step}\n value={current}\n disabled={min === max}\n aria-label={label}\n onChange={(e) => {\n const next = Number(e.currentTarget.value);\n if (stateKey !== undefined && bound) {\n bound[1](next);\n } else if (!controlled) {\n setInternal(next);\n }\n }}\n style={inputStyle}\n />\n <span style={valueStyle}>{current}</span>\n </div>\n </div>\n );\n}\n\nfunction clamp(n: number, lo: number, hi: number): number {\n if (Number.isNaN(n)) return lo;\n return Math.min(hi, Math.max(lo, n));\n}\n","import * as React from 'react';\nimport { colors } from './theme.js';\n\nexport type ChartKind = 'bar' | 'line' | 'pie';\n\n/**\n * The schema lets `data` be any ReactNode, but in practice callers\n * pass JSON-shaped arrays. We narrow at runtime:\n *\n * - bar: `{ labels: string[], values: number[] }`\n * - line: `{ x: number[], y: number[] }` or `{ series: { label, points: {x,y} }[] }`\n * - pie: `{ labels: string[], values: number[] }`\n *\n * Anything that doesn't fit is rendered as a `<pre>` fallback.\n */\nexport interface ChartProps {\n kind: ChartKind;\n data: unknown;\n title?: string;\n}\n\nexport function Chart({ kind, data, title }: ChartProps): React.JSX.Element {\n return (\n <div data-pgx=\"Chart\" data-chart-kind={kind} style={{ fontFamily: 'inherit' }}>\n {title !== undefined ? (\n <div style={{ fontSize: '14px', fontWeight: 600, color: colors.fg, marginBottom: '6px' }}>\n {title}\n </div>\n ) : null}\n {renderChart(kind, data)}\n </div>\n );\n}\n\nfunction renderChart(kind: ChartKind, data: unknown): React.JSX.Element {\n if (kind === 'bar') return renderBar(data);\n if (kind === 'line') return renderLine(data);\n return renderPie(data);\n}\n\nfunction renderBar(data: unknown): React.JSX.Element {\n const parsed = parseLabeled(data);\n if (!parsed) return fallback('bar chart', data);\n const { labels, values } = parsed;\n const max = Math.max(1, ...values);\n const width = 320;\n const height = 160;\n const barWidth = width / Math.max(1, labels.length);\n return (\n <svg\n width={width}\n height={height}\n role=\"img\"\n aria-label=\"Bar chart\"\n style={{ display: 'block' }}\n >\n {values.map((v, i) => {\n const h = (Math.max(0, v) / max) * (height - 24);\n return (\n <g key={i}>\n <rect\n x={i * barWidth + 2}\n y={height - 12 - h}\n width={Math.max(1, barWidth - 4)}\n height={h}\n fill={colors.bar}\n rx={2}\n />\n <text\n x={i * barWidth + barWidth / 2}\n y={height - 2}\n fontSize={10}\n textAnchor=\"middle\"\n fill={colors.barLabel}\n >\n {(labels[i] ?? '').slice(0, 8)}\n </text>\n </g>\n );\n })}\n </svg>\n );\n}\n\nfunction renderLine(data: unknown): React.JSX.Element {\n // Two accepted shapes; pick whichever parses cleanly.\n let points: Array<{ x: number; y: number }> = [];\n if (data && typeof data === 'object' && 'series' in (data as Record<string, unknown>)) {\n const series = (data as { series: Array<{ points?: Array<{ x: number; y: number }> }> }).series;\n const first = series?.[0];\n points = Array.isArray(first?.points) ? first.points : [];\n } else if (\n data &&\n typeof data === 'object' &&\n Array.isArray((data as { x?: unknown }).x) &&\n Array.isArray((data as { y?: unknown }).y)\n ) {\n const xArr = (data as { x: number[] }).x;\n const yArr = (data as { y: number[] }).y;\n points = xArr.map((x, i) => ({ x, y: yArr[i] ?? 0 }));\n }\n if (points.length === 0) return fallback('line chart', data);\n const xs = points.map((p) => p.x);\n const ys = points.map((p) => p.y);\n const xMin = Math.min(...xs);\n const xMax = Math.max(...xs);\n const yMin = Math.min(...ys);\n const yMax = Math.max(...ys);\n const w = 320;\n const h = 160;\n const sx = (x: number) => (xMax === xMin ? w / 2 : ((x - xMin) / (xMax - xMin)) * (w - 8) + 4);\n const sy = (y: number) =>\n yMax === yMin ? h / 2 : h - ((y - yMin) / (yMax - yMin)) * (h - 24) - 12;\n const path = points\n .map((p, i) => `${i === 0 ? 'M' : 'L'}${sx(p.x).toFixed(2)},${sy(p.y).toFixed(2)}`)\n .join(' ');\n return (\n <svg width={w} height={h} role=\"img\" aria-label=\"Line chart\" style={{ display: 'block' }}>\n <path d={path} fill=\"none\" stroke={colors.line} strokeWidth={2} />\n {points.map((p, i) => (\n <circle key={i} cx={sx(p.x)} cy={sy(p.y)} r={2} fill={colors.line} />\n ))}\n </svg>\n );\n}\n\nfunction renderPie(data: unknown): React.JSX.Element {\n const parsed = parseLabeled(data);\n if (!parsed) return fallback('pie chart', data);\n const total = parsed.values.reduce((a, b) => a + Math.max(0, b), 0) || 1;\n const cx = 80;\n const cy = 80;\n const r = 60;\n let angle = -Math.PI / 2;\n return (\n <svg width={160} height={160} role=\"img\" aria-label=\"Pie chart\" style={{ display: 'block' }}>\n {parsed.values.map((v, i) => {\n const slice = (Math.max(0, v) / total) * Math.PI * 2;\n const x1 = cx + r * Math.cos(angle);\n const y1 = cy + r * Math.sin(angle);\n const x2 = cx + r * Math.cos(angle + slice);\n const y2 = cy + r * Math.sin(angle + slice);\n const large = slice > Math.PI ? 1 : 0;\n const path =\n slice >= Math.PI * 2 - 1e-6\n ? `M ${cx - r} ${cy} A ${r} ${r} 0 1 1 ${cx + r} ${cy} A ${r} ${r} 0 1 1 ${cx - r} ${cy}`\n : `M ${cx} ${cy} L ${x1} ${y1} A ${r} ${r} 0 ${large} 1 ${x2} ${y2} Z`;\n angle += slice;\n const fill = colors.pie[i % colors.pie.length] ?? colors.bar;\n return <path key={i} d={path} fill={fill} />;\n })}\n </svg>\n );\n}\n\nfunction parseLabeled(data: unknown): { labels: string[]; values: number[] } | null {\n if (!data || typeof data !== 'object') return null;\n const labels = (data as { labels?: unknown }).labels;\n const values = (data as { values?: unknown }).values;\n if (!Array.isArray(labels) || !Array.isArray(values)) return null;\n if (labels.length !== values.length) return null;\n if (!labels.every((l) => typeof l === 'string' || typeof l === 'number')) return null;\n if (!values.every((v) => typeof v === 'number' || typeof v === 'string')) return null;\n return {\n labels: labels.map(String),\n values: values.map((v) => (typeof v === 'number' ? v : Number(v))),\n };\n}\n\nfunction fallback(label: string, data: unknown): React.JSX.Element {\n return (\n <pre\n style={{\n margin: 0,\n fontSize: '12px',\n background: colors.codeBg,\n color: colors.codeFg,\n padding: '8px',\n borderRadius: '4px',\n overflow: 'auto',\n }}\n >\n {label} data: {JSON.stringify(data, null, 2)}\n </pre>\n );\n}\n","import * as React from 'react';\n\nexport interface ContainerProps {\n padding?: string;\n gap?: string;\n children?: React.ReactNode;\n}\n\n/**\n * Layout wrapper. Defaults to a vertical flex container with 16px\n * padding and 12px gap when callers omit props.\n */\nexport function Container({ padding, gap, children }: ContainerProps): React.JSX.Element {\n const style: React.CSSProperties = {\n display: 'flex',\n flexDirection: 'column',\n padding: padding ?? '16px',\n gap: gap ?? '12px',\n fontFamily: 'inherit',\n color: 'inherit',\n boxSizing: 'border-box',\n };\n return (\n <div style={style} data-pgx=\"Container\">\n {children}\n </div>\n );\n}\n","import * as React from 'react';\nimport { colors, radius } from './theme.js';\n\nexport interface CodeProps {\n language?: string;\n children?: React.ReactNode;\n}\n\n/**\n * Inline code formatter. Renders children as a `<code>` element inside\n * a styled wrapper. If `children` is a single string, it displays\n * verbatim; for multi-line content we fall back to a `<pre>`-styled\n * block.\n */\nexport function Code({ language, children }: CodeProps): React.JSX.Element {\n const isString = typeof children === 'string';\n const isMulti = isString && (children as string).includes('\\n');\n if (isMulti) {\n return (\n <pre\n data-pgx=\"Code\"\n data-language={language ?? 'text'}\n style={{\n background: colors.codeBg,\n color: colors.codeFg,\n padding: '12px',\n borderRadius: radius.md,\n fontSize: '12px',\n overflow: 'auto',\n margin: 0,\n }}\n >\n <code>{children}</code>\n </pre>\n );\n }\n return (\n <code\n data-pgx=\"Code-inline\"\n data-language={language ?? 'text'}\n style={{\n background: colors.codeBg,\n color: colors.codeFg,\n padding: '2px 6px',\n borderRadius: radius.sm,\n fontSize: '0.9em',\n }}\n >\n {children}\n </code>\n );\n}\n","import * as React from 'react';\nimport { colors } from './theme.js';\n\nexport interface HeadingProps {\n /**\n * Heading level (1..6). Out-of-range or undefined falls back to 2.\n * The renderer should never see an `Undefined` value here unless the\n * schema validator said optional props can be omitted.\n */\n level?: number;\n color?: string;\n children?: React.ReactNode;\n}\n\nconst sizes: Record<number, string> = {\n 1: '24px',\n 2: '20px',\n 3: '18px',\n 4: '16px',\n 5: '14px',\n 6: '13px',\n};\n\nexport function Heading({ level, color, children }: HeadingProps): React.JSX.Element {\n const safeLevel = clampLevel(level);\n const size = sizes[safeLevel] ?? sizes[2]!;\n const style: React.CSSProperties = {\n fontFamily: 'inherit',\n fontSize: size,\n fontWeight: 700,\n color: color ?? colors.fg,\n margin: 0,\n lineHeight: 1.3,\n };\n // Render an element corresponding to the level. React enforces\n // TagName = 'h1' | 'h2' ... via JSX, so we switch dynamically via\n // createElement.\n return React.createElement(`h${safeLevel}`, { style, 'data-pgx': `Heading` }, children);\n}\n\nfunction clampLevel(level: number | undefined): 1 | 2 | 3 | 4 | 5 | 6 {\n if (typeof level !== 'number' || !Number.isFinite(level)) return 2;\n const i = Math.floor(level);\n if (i < 1) return 1;\n if (i > 6) return 6;\n return i as 1 | 2 | 3 | 4 | 5 | 6;\n}\n","import * as React from 'react';\nimport { colors } from './theme.js';\n\nexport interface TextProps {\n weight?: 'normal' | 'bold';\n size?: string;\n color?: string;\n children?: React.ReactNode;\n}\n\nexport function Text({ weight = 'normal', size, color, children }: TextProps): React.JSX.Element {\n const style: React.CSSProperties = {\n fontFamily: 'inherit',\n fontSize: size ?? '14px',\n fontWeight: weight === 'bold' ? 600 : 400,\n color: color ?? colors.fg,\n margin: 0,\n lineHeight: 1.5,\n };\n return (\n <p style={style} data-pgx=\"Text\">\n {children}\n </p>\n );\n}\n","import * as React from 'react';\nimport { colors } from './theme.js';\n\nexport interface Step {\n id: string;\n title: string;\n body?: React.ReactNode;\n}\n\nexport interface StepperProps {\n steps: Step[];\n /** 0-indexed initial step. Out-of-range falls back to 0. */\n initial?: number;\n}\n\n/**\n * Multi-step reveal. State: the active index. Previous steps can be\n * revisited; future steps are disabled until reached.\n */\nexport function Stepper({ steps, initial }: StepperProps): React.JSX.Element {\n const initialIdx = clampIndex(initial ?? 0, steps.length);\n const [active, setActive] = React.useState(initialIdx);\n const wrapStyle: React.CSSProperties = {\n fontFamily: 'inherit',\n display: 'flex',\n flexDirection: 'column',\n gap: '12px',\n };\n const listStyle: React.CSSProperties = {\n display: 'flex',\n gap: '6px',\n listStyle: 'none',\n padding: 0,\n margin: 0,\n };\n const stepBtnBase: React.CSSProperties = {\n width: '28px',\n height: '28px',\n borderRadius: '50%',\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontFamily: 'inherit',\n fontSize: '12px',\n fontWeight: 600,\n border: '1px solid transparent',\n };\n const bodyStyle: React.CSSProperties = {\n border: `1px solid ${colors.border}`,\n borderRadius: '6px',\n padding: '10px',\n background: colors.bg,\n color: colors.fg,\n };\n return (\n <div data-pgx=\"Stepper\" style={wrapStyle}>\n <ol style={listStyle}>\n {steps.map((s, i) => {\n const isPast = i < active;\n const isCurrent = i === active;\n const future = i > active;\n const stepStyle: React.CSSProperties = {\n ...stepBtnBase,\n background: isCurrent\n ? colors.stepperCurrent\n : isPast\n ? colors.stepperPast\n : colors.stepperFuture,\n color: isCurrent || isPast ? '#fff' : colors.fg,\n opacity: future ? 0.6 : 1,\n cursor: future ? 'not-allowed' : 'pointer',\n };\n return (\n <li key={s.id}>\n <button\n type=\"button\"\n aria-label={`Step ${i + 1}: ${s.title}`}\n aria-current={isCurrent ? 'step' : undefined}\n disabled={future}\n onClick={() => setActive(i)}\n style={stepStyle}\n >\n {i + 1}\n </button>\n </li>\n );\n })}\n </ol>\n <div style={bodyStyle}>\n <div style={{ fontWeight: 600, marginBottom: '4px', fontSize: '14px' }}>\n {steps[active]?.title ?? ''}\n </div>\n <div style={{ fontSize: '13px' }}>{steps[active]?.body ?? null}</div>\n </div>\n </div>\n );\n}\n\nfunction clampIndex(n: number, len: number): number {\n if (len === 0) return 0;\n if (!Number.isFinite(n)) return 0;\n return Math.min(len - 1, Math.max(0, Math.floor(n)));\n}\n","import * as React from 'react';\nimport { colors, radius, space } from './theme.js';\n\nexport interface CardProps {\n title?: string;\n /**\n * Visual elevation. 0 = flat (border only), 1+ = heavier shadow.\n * Defaults to 1.\n */\n elevation?: number;\n children?: React.ReactNode;\n}\n\nexport function Card({ title, elevation = 1, children }: CardProps): React.JSX.Element {\n const shadow =\n elevation >= 3\n ? '0 4px 12px rgba(15, 23, 42, 0.18)'\n : elevation === 2\n ? '0 2px 8px rgba(15, 23, 42, 0.12)'\n : elevation === 1\n ? '0 1px 2px rgba(15, 23, 42, 0.06)'\n : 'none';\n const cardStyle: React.CSSProperties = {\n background: colors.cardBg,\n border: `1px solid ${colors.cardBorder}`,\n borderRadius: radius.md,\n boxShadow: shadow,\n padding: space.md,\n fontFamily: 'inherit',\n color: colors.fg,\n display: 'flex',\n flexDirection: 'column',\n gap: space.sm,\n };\n const titleStyle: React.CSSProperties = {\n fontSize: '14px',\n fontWeight: 600,\n margin: 0,\n };\n return (\n <section data-pgx=\"Card\" style={cardStyle}>\n {title !== undefined ? <h3 style={titleStyle}>{title}</h3> : null}\n {children}\n </section>\n );\n}\n","import * as React from 'react';\nimport { colors } from './theme.js';\n\nexport interface ListProps {\n /**\n * Items to render. Schema marks this as `node`; in practice callers\n * pass arrays of strings/numbers/ReactNodes. Anything else is\n * rendered as a single bullet containing the value.\n */\n items?: unknown;\n /** When true, renders as `<ol>` instead of `<ul>`. */\n ordered?: boolean;\n /** Override the wrapper element for full control. */\n children?: React.ReactNode;\n}\n\n/**\n * List of items. Renders `items` as a list of strings/numbers (the\n * common artifact prompt output). If `children` are passed they take\n * precedence over `items`.\n */\nexport function List({ items, ordered, children }: ListProps): React.JSX.Element {\n const style: React.CSSProperties = {\n margin: 0,\n paddingLeft: '20px',\n fontFamily: 'inherit',\n color: colors.fg,\n fontSize: '14px',\n lineHeight: 1.6,\n };\n if (children !== undefined && children !== null) {\n return React.createElement(ordered ? 'ol' : 'ul', { style, 'data-pgx': 'List' }, children);\n }\n const arr = Array.isArray(items) ? items : items === undefined ? [] : [items];\n return React.createElement(\n ordered ? 'ol' : 'ul',\n { style, 'data-pgx': 'List' },\n arr.map((item, i) => {\n const node: React.ReactNode =\n typeof item === 'string' || typeof item === 'number' ? String(item) : JSON.stringify(item);\n return <li key={i}>{node}</li>;\n }),\n );\n}\n","/**\n * Helper functions for working with {@link PlaygroundState}.\n *\n * These are pure operations over a `PlaygroundState` — no React, no\n * hooks, no I/O. They live alongside the store so that:\n * - Devtools / CLI scripts can operate on a state without React\n * (the bin/state-cli.ts script uses these directly).\n * - Test code can drive a store through a thin façade.\n * - Server-side renderers can dump, validate, and diff snapshots\n * without needing a DOM.\n *\n * @packageDocumentation\n */\n\nimport type { PlaygroundState } from './state.jsx';\n\n/**\n * Structured diff between two state snapshots. Pure function — does\n * not touch the stores. Returns `null` when the snapshots are\n * shallowly equal (no additions, no changes, no removals).\n *\n * @example\n * const a = { x: 1, y: 2 };\n * const b = { x: 1, y: 3, z: 4 };\n * diffSnapshots(a, b); // { added: ['z'], changed: ['y'], removed: [] }\n */\nexport interface StateDiff {\n /** Keys present in `next` but absent from `prev`. */\n added: string[];\n /** Keys whose value changed (using `Object.is` to compare). */\n changed: string[];\n /** Keys present in `prev` but absent from `next`. */\n removed: string[];\n}\n\nexport function diffSnapshots(\n prev: Readonly<Record<string, unknown>>,\n next: Readonly<Record<string, unknown>>,\n): StateDiff | null {\n const added: string[] = [];\n const changed: string[] = [];\n const removed: string[] = [];\n const prevKeys = Object.keys(prev);\n const nextKeys = Object.keys(next);\n const prevSet = new Set(prevKeys);\n const nextSet = new Set(nextKeys);\n for (const k of nextKeys) {\n if (!prevSet.has(k)) {\n added.push(k);\n continue;\n }\n if (!Object.is(prev[k], next[k])) {\n changed.push(k);\n }\n }\n for (const k of prevKeys) {\n if (!nextSet.has(k)) removed.push(k);\n }\n added.sort();\n changed.sort();\n removed.sort();\n if (added.length === 0 && changed.length === 0 && removed.length === 0) {\n return null;\n }\n return { added, changed, removed };\n}\n\n/**\n * Convenience: take snapshots of both stores and diff them. Returns\n * `null` when equal. Useful in tests and debug endpoints.\n */\nexport function diffState(\n _a: PlaygroundState,\n _b: PlaygroundState,\n prev?: Readonly<Record<string, unknown>>,\n next?: Readonly<Record<string, unknown>>,\n): StateDiff | null {\n const aSnap = prev ?? _a.snapshot();\n const bSnap = next ?? _b.snapshot();\n return diffSnapshots(aSnap, bSnap);\n}\n\n/**\n * Validate a state-key string. Returns `null` on success, or a\n * human-readable error message on failure. The rules:\n *\n * - 1..64 characters\n * - No whitespace\n * - Only alphanumerics, dots, dashes, underscores\n * - Must start with an alphabetic character (so a parser can\n * safely infer `<Slider stateKey=\"...\">` from a body without\n * swallowing accidental numeric keys).\n *\n * Note: keys like `with/slash` or `with spaces` are rejected because\n * the schema-driven body parser uses them as attribute names —\n * a key with weird characters would break the round-trip.\n */\nexport function validateStateKey(key: string): string | null {\n if (key.length === 0) return 'stateKey must be a non-empty string';\n if (key.length > 64) return 'stateKey must be at most 64 characters';\n if (/\\s/.test(key)) return 'stateKey must not contain whitespace';\n if (!/^[A-Za-z][A-Za-z0-9._-]*$/.test(key)) {\n return (\n 'stateKey contains forbidden characters (allowed: A-Z, a-z, ' +\n '0-9, dot, dash, underscore; must start with a letter)'\n );\n }\n return null;\n}\n\n/**\n * Remove every key from the store, firing subscribers with `undefined`.\n * After this call, `state.snapshot()` is `{}`.\n */\nexport function clearState(state: PlaygroundState): void {\n // Snapshot first to avoid mutating the iteration source.\n for (const k of Object.keys(state.snapshot())) {\n state.set(k, undefined);\n }\n}\n\n/**\n * JSON-envelope snapshot for offline inspection. Useful for:\n * - piping into `jq` / debug endpoints\n * - attaching to error reports\n * - round-tripping through `JSON.parse(state.snapshot)`.\n *\n * The `version` field is bumped if the envelope shape ever changes,\n * so consumers can branch on it.\n */\nexport interface StateEnvelope {\n /** Always 1 for now. */\n version: 1;\n /** Sorted list of keys (stable for diffing). */\n keys: string[];\n /** Shallow key→value map. */\n values: Record<string, unknown>;\n}\n\nexport function dumpState(state: PlaygroundState): string {\n const snap = state.snapshot();\n const envelope: StateEnvelope = {\n version: 1,\n keys: Object.keys(snap).sort(),\n values: { ...snap },\n };\n return JSON.stringify(envelope, null, 2);\n}\n\n/**\n * Apply multiple `set` calls as a single atomic batch. Each\n * subscriber sees only the LAST value written to its key in this\n * batch. The store still batches subscriber fires via the microtask\n * scheduler — `batch` does not flush synchronously, it only ensures\n * that within the batch, repeated `set` calls to the same key don't\n * queue redundant fires.\n *\n * Useful for: undo/redo, multi-field form commits, hydrated state\n * restore where you want each subscriber to fire exactly once with\n * the final value.\n *\n * @example\n * batch(state, (s) => {\n * s.set('x', 1);\n * s.set('y', 2);\n * s.set('x', 3); // overwrites; subscriber sees only 3\n * });\n */\nexport function batch<T>(\n state: PlaygroundState,\n fn: (state: PlaygroundState) => T,\n): T {\n // `_batch` is the underlying transactional primitive on the store.\n // We type-cast because the public PlaygroundState interface doesn't\n // expose this test seam — only the helper does.\n const internal = state as unknown as {\n _batch: (fn: () => T) => T;\n };\n return internal._batch(() => fn(state));\n}","/**\n * Render-prop component that shows a toggle-able raw-source panel.\n * Consumer controls the trigger UI via a children render prop.\n *\n * Design notes:\n * - Render-prop pattern (not props.children-as-trigger) because the\n * trigger UI varies wildly across consumers (button, link, icon,\n * inline text). The consumer gets `(toggle, showing)` and decides\n * what to render.\n * - The source panel is a `<pre>` with `<code>` inside. Plain-text;\n * no syntax highlighting (avoiding a 50KB highlight.js dep).\n * Consumers who need highlighting can compose with their own\n * syntax-highlighter.\n * - The panel is rendered INLINE (not in a portal/tooltip) so the\n * toggle's visual feedback is immediate.\n *\n * @packageDocumentation\n */\n\nimport * as React from 'react';\n\nexport interface ShowSourceProps {\n /** The raw body to display when the user expands the source. */\n body: string;\n /** Source language hint. Used in `data-language` for styling hooks. */\n language?: 'tsx' | 'json';\n /**\n * Children is a render prop that receives `(toggle, showing)`.\n * The consumer is expected to render a trigger element (button,\n * link, etc.) and call `toggle` on user interaction.\n */\n children: (toggle: () => void, showing: boolean) => React.ReactNode;\n}\n\n/**\n * Toggle button + expandable source panel. The trigger UI is the\n * consumer's choice; the panel is plain `<pre><code>`.\n */\nexport function ShowSource(props: ShowSourceProps): React.JSX.Element {\n const { body, language, children } = props;\n const [showing, setShowing] = React.useState(false);\n // Wrap setShowing to keep the toggle reference stable. Consumers\n // can pass `toggle` to a `useEffect` dep array without retriggering.\n const toggle = React.useCallback(() => {\n setShowing((s) => !s);\n }, []);\n\n return (\n <>\n {children(toggle, showing)}\n {showing ? (\n <pre\n data-pgx=\"ShowSource\"\n data-language={language ?? 'text'}\n style={{\n background: '#0f172a',\n color: '#e2e8f0',\n padding: '12px',\n borderRadius: '6px',\n overflowX: 'auto',\n fontFamily: 'ui-monospace, Menlo, monospace',\n fontSize: '12px',\n lineHeight: 1.5,\n margin: '8px 0 0',\n maxHeight: '320px',\n whiteSpace: 'pre',\n }}\n >\n <code>{body}</code>\n </pre>\n ) : null}\n </>\n );\n}\n","/**\n * Error boundary for rendered artifacts. Catches render-time errors\n * (malformed body, throw from a component, etc.) and shows a recoverable\n * fallback. Without this, a single bad artifact blanks the student's\n * whole page.\n *\n * Design notes:\n * - Uses React's class-component error boundary API (the only\n * first-class option in React 18/19).\n * - Default fallback shows the error message + an optional \"Show source\"\n * toggle that reveals the raw body. Consumer can override with\n * `fallback` for custom UX.\n * - `onError` fires before the fallback renders so consumers can log\n * to Sentry / Datadog / etc.\n *\n * @packageDocumentation\n */\n\nimport * as React from 'react';\n\nimport { ShowSource } from './ShowSource.js';\n\nexport interface ArtifactErrorBoundaryProps {\n children: React.ReactNode;\n /**\n * Called when a render error is caught. The `info.componentStack`\n * string is the React component stack at the point of error. Log\n * to your observability backend here.\n */\n onError?: (error: Error, info: { componentStack: string }) => void;\n /**\n * Optional body string. If present and the consumer renders the\n * default fallback, a \"Show source\" toggle will be available that\n * reveals this body verbatim. Ignored if a custom `fallback` is\n * supplied (the consumer is responsible for surfacing source).\n */\n body?: string;\n /**\n * Source language hint for the ShowSource toggle in the default\n * fallback. Defaults to 'tsx' (most artifacts are TSX).\n */\n language?: 'tsx' | 'json';\n /**\n * Optional custom fallback. Pass a React element for a static fallback\n * or a function that receives the error for a dynamic one. If\n * omitted, the default fallback renders a panel with the error\n * message and (if `body` is supplied) a ShowSource toggle.\n */\n fallback?: React.ReactNode | ((error: Error) => React.ReactNode);\n /**\n * Label shown in the default fallback header. Defaults to the\n * artifact kind identifier (e.g. \"playground artifact failed to\n * render\"). The consumer is expected to pass the kind.\n */\n kind?: string;\n}\n\ninterface State {\n error: Error | null;\n}\n\n/**\n * Default fallback panel. Renders the error message and, if `body` is\n * provided, a ShowSource toggle. Designed to be a calm, recoverable\n * surface — not a stack-trace dump that panics users.\n */\nfunction DefaultFallback({\n error,\n body,\n language,\n kind,\n}: {\n error: Error;\n body?: string;\n language?: 'tsx' | 'json';\n kind?: string;\n}): React.JSX.Element {\n const label = kind ? `${kind} artifact failed to render` : 'Artifact failed to render';\n return (\n <div\n role=\"alert\"\n data-pgx=\"ArtifactErrorBoundary\"\n data-pgx-kind={kind}\n style={{\n border: '1px solid #fca5a5',\n background: '#fef2f2',\n color: '#7f1d1d',\n borderRadius: '8px',\n padding: '12px 16px',\n fontFamily: 'ui-sans-serif, system-ui, sans-serif',\n fontSize: '14px',\n maxWidth: '720px',\n margin: '12px 0',\n }}\n >\n <div style={{ fontWeight: 600, marginBottom: '6px' }}>{label}</div>\n <code\n data-pgx=\"error-message\"\n style={{\n display: 'block',\n fontFamily: 'ui-monospace, Menlo, monospace',\n fontSize: '12px',\n background: 'rgba(0,0,0,0.04)',\n padding: '6px 8px',\n borderRadius: '4px',\n whiteSpace: 'pre-wrap',\n wordBreak: 'break-word',\n }}\n >\n {error.message}\n </code>\n {body !== undefined ? (\n <div style={{ marginTop: '8px' }}>\n <ShowSource body={body} language={language}>\n {(toggle, showing) => (\n <button\n type=\"button\"\n onClick={toggle}\n data-pgx=\"show-source-toggle\"\n style={{\n background: 'transparent',\n border: '1px solid #fca5a5',\n color: '#7f1d1d',\n padding: '4px 10px',\n fontSize: '12px',\n borderRadius: '4px',\n cursor: 'pointer',\n }}\n >\n {showing ? 'Hide source' : 'Show source'}\n </button>\n )}\n </ShowSource>\n </div>\n ) : null}\n </div>\n );\n}\n\n/**\n * Error boundary. Catches render-time errors in `children` and shows\n * the fallback. The error state is reset on prop change of `children`\n * (or explicit `resetKey` bump) so the consumer can recover by\n * re-rendering.\n */\nexport class ArtifactErrorBoundary extends React.Component<\n ArtifactErrorBoundaryProps,\n State\n> {\n state: State = { error: null };\n\n static getDerivedStateFromError(error: Error): State {\n return { error };\n }\n\n override componentDidCatch(error: Error, info: React.ErrorInfo): void {\n if (this.props.onError) {\n try {\n this.props.onError(error, { componentStack: info.componentStack ?? '' });\n } catch {\n // Swallow — onError callback errors must not break rendering.\n }\n }\n }\n\n override render(): React.ReactNode {\n const { error } = this.state;\n if (error === null) return this.props.children;\n\n const { fallback, body, language, kind } = this.props;\n if (typeof fallback === 'function') return fallback(error);\n if (fallback !== undefined) return fallback;\n return (\n <DefaultFallback\n error={error}\n body={body}\n language={language}\n kind={kind}\n />\n );\n }\n}\n","/**\n * `createRegistry(overrides)` — build a component map with the default\n * 11 components plus caller overrides. Returns a frozen map so post-hoc\n * mutation can't surprise concurrent renders.\n *\n * Lowercase HTML tags (div, span, etc.) are NOT in this map; they're\n * intrinsic to React and handled by `renderBody` directly.\n *\n * @packageDocumentation\n */\n\nimport type { ComponentType } from 'react';\n\nimport { Button } from './Button.js';\nimport { Card } from './Card.js';\nimport { Chart } from './Chart.js';\nimport { Code } from './Code.js';\nimport { Container } from './Container.js';\nimport { Heading } from './Heading.js';\nimport { List } from './List.js';\nimport { Slider } from './Slider.js';\nimport { Stepper } from './Stepper.js';\nimport { Text } from './Text.js';\nimport { TextField } from './TextField.js';\n\n/**\n * Map of PascalCase component name to React component. Loose typing\n * (`ComponentType<any>`) because each component's prop shape differs and\n * the runtime doesn't know which one it's looking up. Consumers who\n * need stricter types can build their own typed wrapper around\n * `renderBody`.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type ComponentMap = Record<string, ComponentType<any>>;\n\nconst DEFAULT_REGISTRY: ComponentMap = Object.freeze({\n Button,\n Card,\n Chart,\n Code,\n Container,\n Heading,\n List,\n Slider,\n Stepper,\n Text,\n TextField,\n});\n\n/**\n * The full default registry (Button, Card, Chart, Code, Container,\n * Heading, List, Slider, Stepper, Text, TextField). Frozen. Use\n * `createRegistry(overrides)` to extend.\n */\nexport const componentMap: ComponentMap = DEFAULT_REGISTRY;\n\n/**\n * Build a new registry by merging the defaults with caller-supplied\n * overrides. The returned map is frozen (Object.freeze) to prevent\n * post-hoc mutation that would surprise concurrent renders.\n *\n * **Lowercase HTML tags are NOT in this map.** The renderer handles\n * `div`, `span`, etc. as React intrinsic elements separately. Calling\n * `createRegistry({ div: StubDiv })` will NOT override the renderer\n * for `<div>` (the renderer uses the lowercase lookup path first).\n *\n * @example\n * ```ts\n * const map = createRegistry({\n * MathExpression: MathExpressionComponent,\n * LatexBlock: LatexBlockComponent,\n * });\n * ```\n */\nexport function createRegistry(overrides: Partial<ComponentMap>): ComponentMap {\n // Merge: defaults are the base; overrides win. Lowercase keys are\n // filtered out because they refer to React intrinsic HTML tags\n // (div, span, etc.) that renderBody handles intrinsically — the\n // caller cannot override intrinsic rendering via the registry.\n // Object.freeze on the result prevents consumers from accidentally\n // mutating the global componentMap by mutating their copy.\n const merged: ComponentMap = { ...DEFAULT_REGISTRY };\n for (const key of Object.keys(overrides) as (keyof ComponentMap)[]) {\n const value = overrides[key];\n if (value === undefined) continue;\n if (key[0] !== key[0]!.toUpperCase()) continue; // skip lowercase\n merged[key] = value;\n }\n return Object.freeze(merged);\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playgenx/components",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "Default React 19 implementations for every entry in DEFAULT_REGISTRY. Pair with @playgenx/registry and the parser/validator pipeline.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.mjs",