dsviz 0.0.0-stage → 2.0.0
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/LICENSE +21 -0
- package/README.md +35 -2
- package/dist/camera.d.ts +25 -0
- package/dist/camera.js +27 -0
- package/dist/camera.js.map +7 -0
- package/dist/connector.d.ts +65 -0
- package/dist/connector.js +108 -0
- package/dist/connector.js.map +7 -0
- package/dist/describe.d.ts +44 -0
- package/dist/describe.js +131 -0
- package/dist/describe.js.map +7 -0
- package/dist/ds/array.d.ts +51 -0
- package/dist/ds/array.js +62 -0
- package/dist/ds/array.js.map +7 -0
- package/dist/ds/common.d.ts +9 -0
- package/dist/ds/common.js +10 -0
- package/dist/ds/common.js.map +7 -0
- package/dist/ds/graph.d.ts +39 -0
- package/dist/ds/graph.js +57 -0
- package/dist/ds/graph.js.map +7 -0
- package/dist/ds/grid.d.ts +30 -0
- package/dist/ds/grid.js +41 -0
- package/dist/ds/grid.js.map +7 -0
- package/dist/ds/index.d.ts +8 -0
- package/dist/ds/index.js +9 -0
- package/dist/ds/index.js.map +7 -0
- package/dist/ds/linkedList.d.ts +46 -0
- package/dist/ds/linkedList.js +68 -0
- package/dist/ds/linkedList.js.map +7 -0
- package/dist/ds/pointer.d.ts +23 -0
- package/dist/ds/pointer.js +35 -0
- package/dist/ds/pointer.js.map +7 -0
- package/dist/ds/stackQueue.d.ts +5 -0
- package/dist/ds/stackQueue.js +49 -0
- package/dist/ds/stackQueue.js.map +7 -0
- package/dist/ds/tree.d.ts +53 -0
- package/dist/ds/tree.js +87 -0
- package/dist/ds/tree.js.map +7 -0
- package/dist/easing.d.ts +14 -0
- package/dist/easing.js +21 -0
- package/dist/easing.js.map +7 -0
- package/dist/fx.d.ts +21 -0
- package/dist/fx.js +27 -0
- package/dist/fx.js.map +7 -0
- package/dist/geom/index.d.ts +2 -0
- package/dist/geom/index.js +3 -0
- package/dist/geom/index.js.map +7 -0
- package/dist/geom/math.d.ts +34 -0
- package/dist/geom/math.js +74 -0
- package/dist/geom/math.js.map +7 -0
- package/dist/geom/shapes.d.ts +69 -0
- package/dist/geom/shapes.js +105 -0
- package/dist/geom/shapes.js.map +7 -0
- package/dist/handle.d.ts +30 -0
- package/dist/handle.js +13 -0
- package/dist/handle.js.map +7 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +7 -0
- package/dist/mathtext.d.ts +29 -0
- package/dist/mathtext.js +142 -0
- package/dist/mathtext.js.map +7 -0
- package/dist/mem/index.d.ts +2 -0
- package/dist/mem/index.js +3 -0
- package/dist/mem/index.js.map +7 -0
- package/dist/mem/memory.d.ts +47 -0
- package/dist/mem/memory.js +41 -0
- package/dist/mem/memory.js.map +7 -0
- package/dist/mem/stackHeap.d.ts +48 -0
- package/dist/mem/stackHeap.js +76 -0
- package/dist/mem/stackHeap.js.map +7 -0
- package/dist/path.d.ts +23 -0
- package/dist/path.js +49 -0
- package/dist/path.js.map +7 -0
- package/dist/player.d.ts +49 -0
- package/dist/player.js +100 -0
- package/dist/player.js.map +7 -0
- package/dist/plot/index.d.ts +2 -0
- package/dist/plot/index.js +3 -0
- package/dist/plot/index.js.map +7 -0
- package/dist/plot/marks.d.ts +120 -0
- package/dist/plot/marks.js +200 -0
- package/dist/plot/marks.js.map +7 -0
- package/dist/plot/plane.d.ts +45 -0
- package/dist/plot/plane.js +41 -0
- package/dist/plot/plane.js.map +7 -0
- package/dist/prob/bars.d.ts +67 -0
- package/dist/prob/bars.js +82 -0
- package/dist/prob/bars.js.map +7 -0
- package/dist/prob/index.d.ts +3 -0
- package/dist/prob/index.js +4 -0
- package/dist/prob/index.js.map +7 -0
- package/dist/prob/tree.d.ts +39 -0
- package/dist/prob/tree.js +57 -0
- package/dist/prob/tree.js.map +7 -0
- package/dist/prob/venn.d.ts +38 -0
- package/dist/prob/venn.js +89 -0
- package/dist/prob/venn.js.map +7 -0
- package/dist/react/Diagram.d.ts +47 -0
- package/dist/react/Diagram.js +41 -0
- package/dist/react/Diagram.js.map +7 -0
- package/dist/react/MathText.d.ts +9 -0
- package/dist/react/MathText.js +15 -0
- package/dist/react/MathText.js.map +7 -0
- package/dist/react/controls-styles.d.ts +9 -0
- package/dist/react/controls-styles.js +109 -0
- package/dist/react/controls-styles.js.map +7 -0
- package/dist/react/controls.d.ts +84 -0
- package/dist/react/controls.js +146 -0
- package/dist/react/controls.js.map +7 -0
- package/dist/react/hooks.d.ts +48 -0
- package/dist/react/hooks.js +67 -0
- package/dist/react/hooks.js.map +7 -0
- package/dist/react/index.d.ts +4 -0
- package/dist/react/index.js +5 -0
- package/dist/react/index.js.map +7 -0
- package/dist/render.d.ts +61 -0
- package/dist/render.js +294 -0
- package/dist/render.js.map +7 -0
- package/dist/scene.d.ts +138 -0
- package/dist/scene.js +94 -0
- package/dist/scene.js.map +7 -0
- package/dist/sched/gantt.d.ts +49 -0
- package/dist/sched/gantt.js +65 -0
- package/dist/sched/gantt.js.map +7 -0
- package/dist/sched/index.d.ts +2 -0
- package/dist/sched/index.js +3 -0
- package/dist/sched/index.js.map +7 -0
- package/dist/sched/simulate.d.ts +55 -0
- package/dist/sched/simulate.js +78 -0
- package/dist/sched/simulate.js.map +7 -0
- package/dist/static.d.ts +8 -0
- package/dist/static.js +26 -0
- package/dist/static.js.map +7 -0
- package/dist/styles.d.ts +3 -0
- package/dist/styles.js +241 -0
- package/dist/styles.js.map +7 -0
- package/dist/sys/architecture.d.ts +104 -0
- package/dist/sys/architecture.js +167 -0
- package/dist/sys/architecture.js.map +7 -0
- package/dist/sys/index.d.ts +1 -0
- package/dist/sys/index.js +2 -0
- package/dist/sys/index.js.map +7 -0
- package/dist/themes.d.ts +13 -0
- package/dist/themes.js +8 -0
- package/dist/themes.js.map +7 -0
- package/dist/uml/classDiagram.d.ts +72 -0
- package/dist/uml/classDiagram.js +84 -0
- package/dist/uml/classDiagram.js.map +7 -0
- package/dist/uml/index.d.ts +3 -0
- package/dist/uml/index.js +4 -0
- package/dist/uml/index.js.map +7 -0
- package/dist/uml/sequence.d.ts +58 -0
- package/dist/uml/sequence.js +121 -0
- package/dist/uml/sequence.js.map +7 -0
- package/dist/uml/stateMachine.d.ts +40 -0
- package/dist/uml/stateMachine.js +89 -0
- package/dist/uml/stateMachine.js.map +7 -0
- package/dist/vec.d.ts +21 -0
- package/dist/vec.js +24 -0
- package/dist/vec.js.map +7 -0
- package/package.json +93 -4
- package/src/camera.ts +50 -0
- package/src/connector.ts +182 -0
- package/src/describe.ts +181 -0
- package/src/ds/array.ts +108 -0
- package/src/ds/common.ts +16 -0
- package/src/ds/graph.ts +104 -0
- package/src/ds/grid.ts +70 -0
- package/src/ds/index.ts +8 -0
- package/src/ds/linkedList.ts +117 -0
- package/src/ds/pointer.ts +55 -0
- package/src/ds/stackQueue.ts +59 -0
- package/src/ds/tree.ts +139 -0
- package/src/easing.ts +24 -0
- package/src/fx.ts +46 -0
- package/src/geom/index.ts +2 -0
- package/src/geom/math.ts +85 -0
- package/src/geom/shapes.ts +158 -0
- package/src/handle.ts +40 -0
- package/src/index.ts +37 -0
- package/src/mathtext.ts +139 -0
- package/src/mem/index.ts +2 -0
- package/src/mem/memory.ts +85 -0
- package/src/mem/stackHeap.ts +127 -0
- package/src/path.ts +68 -0
- package/src/player.ts +153 -0
- package/src/plot/index.ts +2 -0
- package/src/plot/marks.ts +298 -0
- package/src/plot/plane.ts +82 -0
- package/src/prob/bars.ts +132 -0
- package/src/prob/index.ts +3 -0
- package/src/prob/tree.ts +94 -0
- package/src/prob/venn.ts +144 -0
- package/src/react/Diagram.tsx +97 -0
- package/src/react/MathText.tsx +21 -0
- package/src/react/controls-styles.ts +111 -0
- package/src/react/controls.tsx +297 -0
- package/src/react/hooks.ts +112 -0
- package/src/react/index.ts +4 -0
- package/src/render.ts +445 -0
- package/src/scene.ts +238 -0
- package/src/sched/gantt.ts +110 -0
- package/src/sched/index.ts +2 -0
- package/src/sched/simulate.ts +140 -0
- package/src/static.ts +35 -0
- package/src/styles.ts +272 -0
- package/src/sys/architecture.ts +257 -0
- package/src/sys/index.ts +1 -0
- package/src/themes.ts +26 -0
- package/src/uml/classDiagram.ts +145 -0
- package/src/uml/index.ts +3 -0
- package/src/uml/sequence.ts +218 -0
- package/src/uml/stateMachine.ts +133 -0
- package/src/vec.ts +28 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/prob/venn.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Two-set Venn diagrams with regions you can highlight and click.\n *\n * Two circles are easy to draw. The hard part is the REGIONS: \"A only\", \"B\n * only\" and the lens \"A and B\" are not circles, they're shapes bounded by\n * arcs of both circles. We find where the circles cross, then walk around each\n * region's boundary arc by arc:\n *\n * lens = A's arc inside B, then B's arc inside A\n * A only = A's arc outside B, then B's arc inside A (walked backwards)\n * B only = B's arc outside A, then A's arc inside B (walked backwards)\n *\n * Each region is a closed `path` with a fixed number of points, so when you\n * drag a circle the regions morph smoothly.\n */\nimport { circleIntersections } from '../geom/math';\nimport { handle } from '../handle';\nimport { Scene, SceneNode, Tone, circle, path, text } from '../scene';\nimport { Vec, vdist } from '../vec';\n\nexport interface Disc {\n x: number;\n y: number;\n r: number;\n}\n\nexport type VennRegion = 'aOnly' | 'bOnly' | 'both' | 'neither';\n\ntype Pt = [number, number];\nconst N = 64; // points per region boundary\n\nfunction arc(c: Disc, a0: number, a1: number, n: number): Pt[] {\n return Array.from({ length: n }, (_, i) => {\n const t = a0 + ((a1 - a0) * i) / (n - 1);\n return [c.x + c.r * Math.cos(t), c.y + c.r * Math.sin(t)] as Pt;\n });\n}\n\n/** Boundary points of each region (empty array for an empty region). */\nexport function vennRegions(a: Disc, b: Disc): Record<'aOnly' | 'bOnly' | 'both', Pt[]> {\n const d = vdist(a, b);\n const full = (c: Disc) => arc(c, 0, 2 * Math.PI * (1 - 1 / N), N);\n if (d >= a.r + b.r) return { aOnly: full(a), bOnly: full(b), both: [] }; // apart\n if (d <= Math.abs(a.r - b.r)) {\n // one inside the other: the inner disc is the lens; the outer's \"only\" part is a ring,\n // which a single closed path can't express, so we draw the outer disc (the inner one sits on top)\n const [inner, outer] = a.r <= b.r ? [a, b] : [b, a];\n const ring = full(outer);\n return a === outer ? { aOnly: ring, bOnly: [], both: full(inner) } : { aOnly: [], bOnly: ring, both: full(inner) };\n }\n const phi = Math.atan2(b.y - a.y, b.x - a.x); // direction A \u2192 B\n const alpha = Math.acos((a.r * a.r + d * d - b.r * b.r) / (2 * a.r * d)); // half-angle of A's arc inside B\n const psi = phi + Math.PI; // direction B \u2192 A\n const beta = Math.acos((b.r * b.r + d * d - a.r * a.r) / (2 * b.r * d));\n const h = N / 2;\n const aIn = arc(a, phi - alpha, phi + alpha, h);\n const bIn = arc(b, psi - beta, psi + beta, h);\n const aOut = arc(a, phi + alpha, phi - alpha + 2 * Math.PI, h);\n const bOut = arc(b, psi + beta, psi - beta + 2 * Math.PI, h);\n return {\n both: [...aIn, ...bIn],\n aOnly: [...aOut, ...[...bIn].reverse()],\n bOnly: [...bOut, ...[...aIn].reverse()],\n };\n}\n\n/** Areas of each region (same units as r\u00B2). */\nexport function vennAreas(a: Disc, b: Disc): { a: number; b: number; both: number; aOnly: number; bOnly: number } {\n const d = vdist(a, b);\n const A = Math.PI * a.r * a.r, B = Math.PI * b.r * b.r;\n let both: number;\n if (d >= a.r + b.r) both = 0;\n else if (d <= Math.abs(a.r - b.r)) both = Math.PI * Math.min(a.r, b.r) ** 2;\n else {\n const r1 = a.r, r2 = b.r;\n both =\n r1 * r1 * Math.acos((d * d + r1 * r1 - r2 * r2) / (2 * d * r1)) +\n r2 * r2 * Math.acos((d * d + r2 * r2 - r1 * r1) / (2 * d * r2)) -\n 0.5 * Math.sqrt((-d + r1 + r2) * (d + r1 - r2) * (d - r1 + r2) * (d + r1 + r2));\n }\n return { a: A, b: B, both, aOnly: A - both, bOnly: B - both };\n}\n\n/** Which region a point falls in. */\nexport function vennRegionAt(p: Vec, a: Disc, b: Disc): VennRegion {\n const inA = vdist(p, a) <= a.r, inB = vdist(p, b) <= b.r;\n return inA && inB ? 'both' : inA ? 'aOnly' : inB ? 'bOnly' : 'neither';\n}\n\nexport interface VennOptions {\n id?: string;\n labels?: [string, string];\n /** Regions to shade. */\n highlight?: readonly VennRegion[];\n tone?: Tone;\n /** The universe rectangle around both circles (for \"neither\"), as [x, y, w, h]. */\n universe?: [number, number, number, number];\n /** Region paths emit clicks with `{ region }` in data. */\n interactive?: boolean;\n /** Give each circle a drag handle at its centre; drag data is `{ set: 'a' | 'b' }`. */\n draggable?: boolean;\n /** Pulse the drag handles until the reader first touches one. */\n hint?: boolean;\n}\n\nexport function venn2(a: Disc, b: Disc, o: VennOptions = {}): Scene {\n const id = o.id ?? 'venn';\n const hl = new Set(o.highlight ?? []);\n const regions = vennRegions(a, b);\n const tone = o.tone ?? 'accent';\n const nodes: SceneNode[] = [];\n if (o.universe) {\n const [ux, uy, uw, uh] = o.universe;\n nodes.push({ kind: 'rect', id: `${id}:U`, x: ux + uw / 2, y: uy + uh / 2, w: uw, h: uh, rx: 8, role: 'universe', tone: hl.has('neither') ? tone : undefined, interactive: o.interactive, data: { region: 'neither' } });\n nodes.push(text({ id: `${id}:U:label`, x: ux + 12, y: uy + 14, text: 'U', size: 13, role: 'math', anchor: 'start' }));\n }\n // regions keep their ids even when empty, so they can fade back in\n for (const r of ['aOnly', 'bOnly', 'both'] as const) {\n const pts = regions[r];\n if (!pts.length) continue;\n nodes.push(path({ id: `${id}:${r}`, points: pts, closed: true, role: 'region', tone: hl.has(r) ? tone : 'muted', interactive: o.interactive, data: { region: r } }));\n }\n nodes.push(\n circle({ id: `${id}:A`, x: a.x, y: a.y, r: a.r, role: 'outline' }),\n circle({ id: `${id}:B`, x: b.x, y: b.y, r: b.r, role: 'outline' }),\n );\n const [la, lb] = o.labels ?? ['A', 'B'];\n // labels sit outside each circle, away from the other one\n const dir = Math.atan2(b.y - a.y, b.x - a.x);\n const lab = (c: Disc, away: number, s: string, k: string) =>\n text({ id: `${id}:${k}:label`, x: c.x + Math.cos(away) * c.r * 0.72 - Math.sin(away) * 0, y: c.y - c.r * 0.82, text: s, size: 16, role: 'math' });\n nodes.push(lab(a, dir + Math.PI, la, 'A'), lab(b, dir, lb, 'B'));\n if (o.draggable) {\n // A small VISIBLE handle at each centre. (An invisible drag zone over the\n // regions would make the same spot mean \"drag\" or \"click\" depending on\n // where exactly you pressed, with nothing on screen to say which.)\n nodes.push(\n ...handle({ id: `${id}:A:drag`, x: a.x, y: a.y, hint: o.hint, data: { set: 'a' } }),\n ...handle({ id: `${id}:B:drag`, x: b.x, y: b.y, hint: o.hint, data: { set: 'b' } }),\n );\n }\n return { nodes };\n}\n\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { ViewEvent } from '../render';
|
|
2
|
+
import { Scene } from '../scene';
|
|
3
|
+
import type { Easing } from '../easing';
|
|
4
|
+
export interface DiagramProps {
|
|
5
|
+
scene: Scene;
|
|
6
|
+
/**
|
|
7
|
+
* 'natural' (default): drawn at 1 scene unit = 1px (× `scale`), centred, and
|
|
8
|
+
* shrunk only when the container is narrower. Every diagram gets the same text
|
|
9
|
+
* size and line weight. 'fill': stretch to the container (width 100%, `height`).
|
|
10
|
+
*/
|
|
11
|
+
size?: 'natural' | 'fill';
|
|
12
|
+
/** Pixels per scene unit in natural mode. Default 1. */
|
|
13
|
+
scale?: number;
|
|
14
|
+
/** CSS height in 'fill' mode. Default 240. */
|
|
15
|
+
height?: number | string;
|
|
16
|
+
/**
|
|
17
|
+
* The camera. A fixed [x, y, w, h] never moves: use it for plots, anything
|
|
18
|
+
* draggable, and step-through diagrams (`fitViewBox(allFrames)`). 'auto'
|
|
19
|
+
* (default) grows to fit and otherwise stays still; see `camera`.
|
|
20
|
+
*/
|
|
21
|
+
viewBox?: 'auto' | [number, number, number, number];
|
|
22
|
+
/** How an 'auto' camera follows the scene: 'grow' (default) or 'fit'. */
|
|
23
|
+
camera?: 'grow' | 'fit';
|
|
24
|
+
padding?: number;
|
|
25
|
+
/** Animation length in ms (default 420). */
|
|
26
|
+
duration?: number;
|
|
27
|
+
/** Easing curve (default easeOutSoft). Try easeInQuad for falling things. */
|
|
28
|
+
ease?: Easing;
|
|
29
|
+
onClick?: (e: ViewEvent) => void;
|
|
30
|
+
onDragStart?: (e: ViewEvent) => void;
|
|
31
|
+
onDrag?: (e: ViewEvent) => void;
|
|
32
|
+
onDragEnd?: (e: ViewEvent) => void;
|
|
33
|
+
className?: string;
|
|
34
|
+
/** Accessible description of what the diagram shows. */
|
|
35
|
+
label?: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* React wrapper around createView().
|
|
39
|
+
*
|
|
40
|
+
* The idea: React owns *when* to render (props changed), the view owns *how*
|
|
41
|
+
* (keyed diff + tweening directly on DOM nodes, outside React's reconciler).
|
|
42
|
+
* Two consequences worth knowing:
|
|
43
|
+
* - We never put SVG children in JSX; the view manages them, so React can't fight it.
|
|
44
|
+
* - Event handlers are read through a ref, so passing a fresh inline `onDrag`
|
|
45
|
+
* every render doesn't tear down and rebuild the view's listeners.
|
|
46
|
+
*/
|
|
47
|
+
export declare function Diagram({ scene, size, scale, height, viewBox, camera, padding, duration, ease, onClick, onDragStart, onDrag, onDragEnd, className, label }: DiagramProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef } from "react";
|
|
3
|
+
import { createView } from "../render.js";
|
|
4
|
+
function Diagram({ scene, size = "natural", scale, height = 240, viewBox = "auto", camera, padding, duration, ease, onClick, onDragStart, onDrag, onDragEnd, className, label }) {
|
|
5
|
+
const svgRef = useRef(null);
|
|
6
|
+
const viewRef = useRef(null);
|
|
7
|
+
const dragging = useRef(null);
|
|
8
|
+
const sceneRef = useRef(scene);
|
|
9
|
+
sceneRef.current = scene;
|
|
10
|
+
const handlers = useRef({ onClick, onDragStart, onDrag, onDragEnd });
|
|
11
|
+
handlers.current = { onClick, onDragStart, onDrag, onDragEnd };
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
const view = createView(svgRef.current, { viewBox, camera, padding, duration, ease, size, scale });
|
|
14
|
+
viewRef.current = view;
|
|
15
|
+
const offs = [
|
|
16
|
+
view.on("click", (e) => handlers.current.onClick?.(e)),
|
|
17
|
+
view.on("dragstart", (e) => (dragging.current = e.keyboard ? "key" : "pointer", handlers.current.onDragStart?.(e))),
|
|
18
|
+
view.on("drag", (e) => handlers.current.onDrag?.(e)),
|
|
19
|
+
view.on("dragend", (e) => (dragging.current = null, handlers.current.onDragEnd?.(e)))
|
|
20
|
+
];
|
|
21
|
+
view.render(sceneRef.current);
|
|
22
|
+
return () => {
|
|
23
|
+
offs.forEach((off) => off());
|
|
24
|
+
view.destroy();
|
|
25
|
+
viewRef.current = null;
|
|
26
|
+
};
|
|
27
|
+
}, [padding, duration, ease, size, scale, camera]);
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
viewRef.current?.setViewBox(viewBox);
|
|
30
|
+
}, [Array.isArray(viewBox) ? viewBox.join(",") : viewBox]);
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
const d = dragging.current;
|
|
33
|
+
viewRef.current?.render(scene, d ? { duration: d === "key" ? 120 : 0, camera: false } : void 0);
|
|
34
|
+
}, [scene]);
|
|
35
|
+
const style = size === "natural" ? { display: "block", maxWidth: "100%", height: "auto", margin: "0 auto" } : { width: "100%", height, display: "block" };
|
|
36
|
+
return /* @__PURE__ */ jsx("svg", { ref: svgRef, className, style, role: "img", "aria-label": label });
|
|
37
|
+
}
|
|
38
|
+
export {
|
|
39
|
+
Diagram
|
|
40
|
+
};
|
|
41
|
+
//# sourceMappingURL=Diagram.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/react/Diagram.tsx"],
|
|
4
|
+
"sourcesContent": ["import { useEffect, useRef } from 'react';\nimport { View, ViewEvent, createView } from '../render';\nimport { Scene } from '../scene';\nimport type { Easing } from '../easing';\n\nexport interface DiagramProps {\n scene: Scene;\n /**\n * 'natural' (default): drawn at 1 scene unit = 1px (\u00D7 `scale`), centred, and\n * shrunk only when the container is narrower. Every diagram gets the same text\n * size and line weight. 'fill': stretch to the container (width 100%, `height`).\n */\n size?: 'natural' | 'fill';\n /** Pixels per scene unit in natural mode. Default 1. */\n scale?: number;\n /** CSS height in 'fill' mode. Default 240. */\n height?: number | string;\n /**\n * The camera. A fixed [x, y, w, h] never moves: use it for plots, anything\n * draggable, and step-through diagrams (`fitViewBox(allFrames)`). 'auto'\n * (default) grows to fit and otherwise stays still; see `camera`.\n */\n viewBox?: 'auto' | [number, number, number, number];\n /** How an 'auto' camera follows the scene: 'grow' (default) or 'fit'. */\n camera?: 'grow' | 'fit';\n padding?: number;\n /** Animation length in ms (default 420). */\n duration?: number;\n /** Easing curve (default easeOutSoft). Try easeInQuad for falling things. */\n ease?: Easing;\n onClick?: (e: ViewEvent) => void;\n onDragStart?: (e: ViewEvent) => void;\n onDrag?: (e: ViewEvent) => void;\n onDragEnd?: (e: ViewEvent) => void;\n className?: string;\n /** Accessible description of what the diagram shows. */\n label?: string;\n}\n\n/**\n * React wrapper around createView().\n *\n * The idea: React owns *when* to render (props changed), the view owns *how*\n * (keyed diff + tweening directly on DOM nodes, outside React's reconciler).\n * Two consequences worth knowing:\n * - We never put SVG children in JSX; the view manages them, so React can't fight it.\n * - Event handlers are read through a ref, so passing a fresh inline `onDrag`\n * every render doesn't tear down and rebuild the view's listeners.\n */\nexport function Diagram({ scene, size = 'natural', scale, height = 240, viewBox = 'auto', camera, padding, duration, ease, onClick, onDragStart, onDrag, onDragEnd, className, label }: DiagramProps) {\n const svgRef = useRef<SVGSVGElement>(null);\n const viewRef = useRef<View | null>(null);\n const dragging = useRef<null | 'pointer' | 'key'>(null);\n const sceneRef = useRef(scene);\n sceneRef.current = scene;\n const handlers = useRef({ onClick, onDragStart, onDrag, onDragEnd });\n handlers.current = { onClick, onDragStart, onDrag, onDragEnd };\n\n // Create / destroy the view. `viewBox`, `padding`, `duration` are creation options.\n useEffect(() => {\n const view = createView(svgRef.current!, { viewBox, camera, padding, duration, ease, size, scale });\n viewRef.current = view;\n const offs = [\n view.on('click', (e) => handlers.current.onClick?.(e)),\n view.on('dragstart', (e) => ((dragging.current = e.keyboard ? 'key' : 'pointer'), handlers.current.onDragStart?.(e))),\n view.on('drag', (e) => handlers.current.onDrag?.(e)),\n view.on('dragend', (e) => ((dragging.current = null), handlers.current.onDragEnd?.(e))),\n ];\n view.render(sceneRef.current);\n return () => {\n offs.forEach((off) => off());\n view.destroy();\n viewRef.current = null;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [padding, duration, ease, size, scale, camera]);\n\n // Camera changes don't need a new view.\n useEffect(() => {\n viewRef.current?.setViewBox(viewBox);\n // a fixed camera is a new array each render; compare by value\n }, [Array.isArray(viewBox) ? viewBox.join(',') : viewBox]);\n\n // Every scene change: render. While the user drags, skip tweening AND freeze\n // the camera, so the thing under the cursor stays glued to it.\n useEffect(() => {\n // (A pointer drag follows the finger with no tween; an arrow-key press is a\n // discrete jump, so it gets a short one.)\n const d = dragging.current;\n viewRef.current?.render(scene, d ? { duration: d === 'key' ? 120 : 0, camera: false } : undefined);\n }, [scene]);\n\n const style = size === 'natural'\n ? { display: 'block', maxWidth: '100%', height: 'auto', margin: '0 auto' } // overflow comes from the stylesheet: visible, or clipped for a fixed viewBox\n : { width: '100%', height, display: 'block' };\n return <svg ref={svgRef} className={className} style={style} role=\"img\" aria-label={label} />;\n}\n"],
|
|
5
|
+
"mappings": "AA+FS;AA/FT,SAAS,WAAW,cAAc;AAClC,SAA0B,kBAAkB;AAgDrC,SAAS,QAAQ,EAAE,OAAO,OAAO,WAAW,OAAO,SAAS,KAAK,UAAU,QAAQ,QAAQ,SAAS,UAAU,MAAM,SAAS,aAAa,QAAQ,WAAW,WAAW,MAAM,GAAiB;AACpM,QAAM,SAAS,OAAsB,IAAI;AACzC,QAAM,UAAU,OAAoB,IAAI;AACxC,QAAM,WAAW,OAAiC,IAAI;AACtD,QAAM,WAAW,OAAO,KAAK;AAC7B,WAAS,UAAU;AACnB,QAAM,WAAW,OAAO,EAAE,SAAS,aAAa,QAAQ,UAAU,CAAC;AACnE,WAAS,UAAU,EAAE,SAAS,aAAa,QAAQ,UAAU;AAG7D,YAAU,MAAM;AACd,UAAM,OAAO,WAAW,OAAO,SAAU,EAAE,SAAS,QAAQ,SAAS,UAAU,MAAM,MAAM,MAAM,CAAC;AAClG,YAAQ,UAAU;AAClB,UAAM,OAAO;AAAA,MACX,KAAK,GAAG,SAAS,CAAC,MAAM,SAAS,QAAQ,UAAU,CAAC,CAAC;AAAA,MACrD,KAAK,GAAG,aAAa,CAAC,OAAQ,SAAS,UAAU,EAAE,WAAW,QAAQ,WAAY,SAAS,QAAQ,cAAc,CAAC,EAAE;AAAA,MACpH,KAAK,GAAG,QAAQ,CAAC,MAAM,SAAS,QAAQ,SAAS,CAAC,CAAC;AAAA,MACnD,KAAK,GAAG,WAAW,CAAC,OAAQ,SAAS,UAAU,MAAO,SAAS,QAAQ,YAAY,CAAC,EAAE;AAAA,IACxF;AACA,SAAK,OAAO,SAAS,OAAO;AAC5B,WAAO,MAAM;AACX,WAAK,QAAQ,CAAC,QAAQ,IAAI,CAAC;AAC3B,WAAK,QAAQ;AACb,cAAQ,UAAU;AAAA,IACpB;AAAA,EAEF,GAAG,CAAC,SAAS,UAAU,MAAM,MAAM,OAAO,MAAM,CAAC;AAGjD,YAAU,MAAM;AACd,YAAQ,SAAS,WAAW,OAAO;AAAA,EAErC,GAAG,CAAC,MAAM,QAAQ,OAAO,IAAI,QAAQ,KAAK,GAAG,IAAI,OAAO,CAAC;AAIzD,YAAU,MAAM;AAGd,UAAM,IAAI,SAAS;AACnB,YAAQ,SAAS,OAAO,OAAO,IAAI,EAAE,UAAU,MAAM,QAAQ,MAAM,GAAG,QAAQ,MAAM,IAAI,MAAS;AAAA,EACnG,GAAG,CAAC,KAAK,CAAC;AAEV,QAAM,QAAQ,SAAS,YACnB,EAAE,SAAS,SAAS,UAAU,QAAQ,QAAQ,QAAQ,QAAQ,SAAS,IACvE,EAAE,OAAO,QAAQ,QAAQ,SAAS,QAAQ;AAC9C,SAAO,oBAAC,SAAI,KAAK,QAAQ,WAAsB,OAAc,MAAK,OAAM,cAAY,OAAO;AAC7F;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The same TeX-lite typesetting as a diagram's maths labels, for the HTML
|
|
3
|
+
* around it, so a status line and a label set "x²" the same way.
|
|
4
|
+
*
|
|
5
|
+
* <MathText tex="a^2 + b^2 = c^2" />
|
|
6
|
+
*/
|
|
7
|
+
export declare function MathText({ tex }: {
|
|
8
|
+
tex: string;
|
|
9
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Fragment } from "react";
|
|
3
|
+
import { parseMath } from "../mathtext.js";
|
|
4
|
+
import { injectControlStyles } from "./controls-styles.js";
|
|
5
|
+
function MathText({ tex }) {
|
|
6
|
+
injectControlStyles();
|
|
7
|
+
return /* @__PURE__ */ jsx("span", { className: "dvc-math", children: parseMath(tex).map((s, i) => {
|
|
8
|
+
const inner = s.italic ? /* @__PURE__ */ jsx("i", { children: s.text }) : /* @__PURE__ */ jsx(Fragment, { children: s.text });
|
|
9
|
+
return s.shift === 1 ? /* @__PURE__ */ jsx("sup", { children: inner }, i) : s.shift === -1 ? /* @__PURE__ */ jsx("sub", { children: inner }, i) : /* @__PURE__ */ jsx(Fragment, { children: inner }, i);
|
|
10
|
+
}) });
|
|
11
|
+
}
|
|
12
|
+
export {
|
|
13
|
+
MathText
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=MathText.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/react/MathText.tsx"],
|
|
4
|
+
"sourcesContent": ["import { Fragment } from 'react';\nimport { parseMath } from '../mathtext';\nimport { injectControlStyles } from './controls-styles';\n\n/**\n * The same TeX-lite typesetting as a diagram's maths labels, for the HTML\n * around it, so a status line and a label set \"x\u00B2\" the same way.\n *\n * <MathText tex=\"a^2 + b^2 = c^2\" />\n */\nexport function MathText({ tex }: { tex: string }) {\n injectControlStyles();\n return (\n <span className=\"dvc-math\">\n {parseMath(tex).map((s, i) => {\n const inner = s.italic ? <i>{s.text}</i> : <Fragment>{s.text}</Fragment>;\n return s.shift === 1 ? <sup key={i}>{inner}</sup> : s.shift === -1 ? <sub key={i}>{inner}</sub> : <Fragment key={i}>{inner}</Fragment>;\n })}\n </span>\n );\n}\n"],
|
|
5
|
+
"mappings": "AAeiC;AAfjC,SAAS,gBAAgB;AACzB,SAAS,iBAAiB;AAC1B,SAAS,2BAA2B;AAQ7B,SAAS,SAAS,EAAE,IAAI,GAAoB;AACjD,sBAAoB;AACpB,SACE,oBAAC,UAAK,WAAU,YACb,oBAAU,GAAG,EAAE,IAAI,CAAC,GAAG,MAAM;AAC5B,UAAM,QAAQ,EAAE,SAAS,oBAAC,OAAG,YAAE,MAAK,IAAO,oBAAC,YAAU,YAAE,MAAK;AAC7D,WAAO,EAAE,UAAU,IAAI,oBAAC,SAAa,mBAAJ,CAAU,IAAS,EAAE,UAAU,KAAK,oBAAC,SAAa,mBAAJ,CAAU,IAAS,oBAAC,YAAkB,mBAAJ,CAAU;AAAA,EAC7H,CAAC,GACH;AAEJ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CSS for the controls. Deliberately quiet: small, flat, neutral greys with one
|
|
3
|
+
* blue accent, so the diagram is the thing you look at. They read the same
|
|
4
|
+
* --dv-* variables as the diagrams (defined on `.dvc`), so a host app restyles
|
|
5
|
+
* both from one place, or swaps the controls for its own entirely.
|
|
6
|
+
*/
|
|
7
|
+
export declare const CONTROLS_CSS = "\n.dvc {\n --dvc-ink: var(--dv-fg); --dvc-sub: #6b6b6b; --dvc-line: #d9d9d9; --dvc-track: #ececec; --dvc-bg: #fff; --dvc-soft: #f5f5f5;\n --dvc-accent: #456dff; --dvc-strong: #1a1a1a; --dvc-strong-ink: #fff; --dvc-hl: #fdf3d3; --dvc-hl-bar: #f7c325;\n font-family: var(--dv-font); color: var(--dvc-ink);\n}\n:root[data-theme=\"dark\"] .dvc, .dark .dvc {\n --dvc-sub: #a3a3a3; --dvc-line: #3d3d3d; --dvc-track: #333; --dvc-bg: #1e1e1e; --dvc-soft: #262626;\n --dvc-accent: #7491ff; --dvc-strong: #f2f2f2; --dvc-strong-ink: #141414; --dvc-hl: #3d3100; --dvc-hl-bar: #d7a613;\n}\n@media (prefers-color-scheme: dark) {\n :root:not([data-theme=\"light\"]):not(.light) .dvc {\n --dvc-sub: #a3a3a3; --dvc-line: #3d3d3d; --dvc-track: #333; --dvc-bg: #1e1e1e; --dvc-soft: #262626;\n --dvc-accent: #7491ff; --dvc-strong: #f2f2f2; --dvc-strong-ink: #141414; --dvc-hl: #3d3100; --dvc-hl-bar: #d7a613;\n }\n}\n.dvc-field { display: flex; align-items: center; gap: 10px; font-size: 13px; }\n.dvc-label { color: var(--dvc-sub); white-space: nowrap; }\n.dvc-readout { display: inline-grid; justify-items: end; font-variant-numeric: tabular-nums; font-kerning: none; font-weight: 600; white-space: nowrap; min-width: 3ch; flex: none; }\n.dvc-readout > * { grid-area: 1 / 1; }\n.dvc-readout-sizer { visibility: hidden; }\n\n.dvc-btn { all: unset; box-sizing: border-box; display: inline-flex; align-items: center; justify-content: center; gap: 6px; height: 30px; padding: 0 12px; border-radius: 7px; cursor: pointer; font: 500 13px var(--dv-font); color: var(--dvc-ink); background: var(--dvc-bg); border: 1px solid var(--dvc-line); transition: background .12s, border-color .12s; }\n.dvc-btn:hover:not(:disabled) { background: var(--dvc-soft); }\n.dvc-btn:active:not(:disabled) { transform: translateY(1px); }\n.dvc-btn:focus-visible { outline: 2px solid var(--dvc-accent); outline-offset: 1px; }\n.dvc-btn:disabled { opacity: .4; cursor: default; }\n.dvc-btn.is-primary { background: var(--dvc-strong); color: var(--dvc-strong-ink); border-color: var(--dvc-strong); }\n.dvc-btn.is-primary:hover:not(:disabled) { background: color-mix(in srgb, var(--dvc-strong) 85%, #888); }\n\n.dvc-slider { position: relative; display: flex; align-items: center; flex: 1; height: 22px; touch-action: none; user-select: none; min-width: 90px; }\n.dvc-track { position: relative; flex: 1; height: 8px; border-radius: 4px; background: var(--dvc-track); }\n.dvc-range { position: absolute; height: 100%; border-radius: 4px; background: var(--dvc-accent); }\n.dvc-slider { --dvc-thumb: 18px; }\n/* notches: dots inside the track, in a layer inset by half a thumb so they line up with its centre */\n.dvc-ticks { position: absolute; top: 0; bottom: 0; left: calc(var(--dvc-thumb) / 2); right: calc(var(--dvc-thumb) / 2); pointer-events: none; }\n.dvc-tick { position: absolute; top: 50%; width: 4px; height: 4px; border-radius: 50%; transform: translate(-50%, -50%); background: color-mix(in srgb, var(--dvc-sub) 45%, transparent); }\n.dvc-tick.is-on { background: rgb(255 255 255 / .75); }\n.dvc-thumb { box-sizing: border-box; display: block; width: var(--dvc-thumb); height: var(--dvc-thumb); border-radius: 50%; background: var(--dvc-bg); border: 2px solid var(--dvc-accent); box-shadow: 0 1px 2px rgb(0 0 0 / .2); cursor: grab; }\n.dvc-thumb:hover { box-shadow: 0 0 0 5px color-mix(in srgb, var(--dvc-accent) 18%, transparent); }\n.dvc-thumb:focus-visible { outline: none; box-shadow: 0 0 0 5px color-mix(in srgb, var(--dvc-accent) 35%, transparent); }\n.dvc-thumb:active { cursor: grabbing; }\n\n.dvc-seg { display: inline-flex; gap: 2px; padding: 2px; border-radius: 8px; background: var(--dvc-track); }\n.dvc-seg-item { all: unset; box-sizing: border-box; padding: 4px 11px; border-radius: 6px; cursor: pointer; font: 500 13px var(--dv-font); color: var(--dvc-sub); }\n.dvc-seg-item:hover { color: var(--dvc-ink); }\n.dvc-seg-item[data-state=\"on\"] { background: var(--dvc-bg); color: var(--dvc-ink); box-shadow: 0 1px 2px rgb(0 0 0 / .12); }\n.dvc-seg-item:focus-visible { outline: 2px solid var(--dvc-accent); outline-offset: 1px; }\n\n.dvc-select { all: unset; box-sizing: border-box; display: inline-flex; align-items: center; gap: 8px; height: 30px; padding: 0 10px; border-radius: 7px; cursor: pointer; font: 500 13px var(--dv-font); border: 1px solid var(--dvc-line); background: var(--dvc-bg); }\n.dvc-select:focus-visible { outline: 2px solid var(--dvc-accent); }\n.dvc-caret { color: var(--dvc-sub); }\n.dvc-menu { z-index: 50; padding: 4px; border-radius: 9px; background: var(--dvc-bg); border: 1px solid var(--dvc-line); box-shadow: 0 6px 20px rgb(0 0 0 / .1); font: 13px var(--dv-font); }\n.dvc-menu-item { padding: 6px 10px; border-radius: 6px; cursor: pointer; outline: none; }\n.dvc-menu-item[data-highlighted] { background: var(--dvc-soft); }\n\n.dvc-switch { all: unset; box-sizing: border-box; width: 30px; height: 18px; border-radius: 9px; cursor: pointer; background: var(--dvc-line); position: relative; transition: background .15s; }\n.dvc-switch[data-state=\"checked\"] { background: var(--dvc-accent); }\n.dvc-switch:focus-visible { outline: 2px solid var(--dvc-accent); outline-offset: 2px; }\n.dvc-switch-thumb { display: block; width: 14px; height: 14px; border-radius: 50%; background: #fff; transform: translateX(2px); transition: transform .15s; box-shadow: 0 1px 2px rgb(0 0 0 / .25); }\n.dvc-switch-thumb[data-state=\"checked\"] { transform: translateX(14px); }\n\n.dvc-stepper { display: inline-flex; align-items: stretch; height: 30px; border-radius: 7px; border: 1px solid var(--dvc-line); overflow: hidden; background: var(--dvc-bg); }\n.dvc-stepper button { all: unset; box-sizing: border-box; width: 28px; text-align: center; cursor: pointer; color: var(--dvc-sub); font-size: 15px; }\n.dvc-stepper button:hover:not(:disabled) { background: var(--dvc-soft); color: var(--dvc-ink); }\n.dvc-stepper button:disabled { opacity: .35; cursor: default; }\n.dvc-stepper button:focus-visible { outline: 2px solid var(--dvc-accent); outline-offset: -2px; }\n.dvc-stepper output { min-width: 36px; padding: 0 4px; display: grid; place-items: center; font: 600 13px var(--dv-font); font-variant-numeric: tabular-nums; border-inline: 1px solid var(--dvc-line); }\n\n.dvc-transport { display: flex; align-items: center; gap: 4px; font-size: 13px; }\n.dvc-transport button { all: unset; box-sizing: border-box; display: grid; place-items: center; width: 28px; height: 28px; border-radius: 50%; cursor: pointer; color: var(--dvc-sub); }\n.dvc-transport button:hover:not(:disabled) { background: var(--dvc-soft); color: var(--dvc-ink); }\n.dvc-transport button.is-play { background: var(--dvc-accent); color: #fff; }\n.dvc-transport button.is-play:hover { background: color-mix(in srgb, var(--dvc-accent) 85%, #000); color: #fff; }\n.dvc-transport button:focus-visible { outline: 2px solid var(--dvc-accent); }\n.dvc-transport button:disabled { opacity: .3; cursor: default; }\n.dvc-scrub { margin: 0 8px; }\n\n.dvc-input { all: unset; box-sizing: border-box; height: 30px; padding: 0 9px; border-radius: 7px; font: 500 13px var(--dv-mono); color: var(--dvc-ink); border: 1px solid var(--dvc-line); background: var(--dvc-bg); }\n.dvc-input:focus { border-color: var(--dvc-accent); }\n\n.dvc-code { margin: 0; padding: 8px 4px; border-radius: 8px; background: var(--dvc-soft); font: 12.5px/1.7 var(--dv-mono); color: var(--dvc-sub); overflow-x: auto; }\n.dvc-code-line { white-space: pre; padding: 0 10px; border-radius: 4px; transition: background .2s, color .2s; }\n.dvc-code-line.is-active { color: var(--dvc-ink); background: var(--dvc-hl); box-shadow: inset 2px 0 0 var(--dvc-hl-bar); }\n/* maths in HTML: same font and rules as the diagram's maths labels */\n.dvc-math { font-family: var(--dv-math-font, \"STIX Two Text\", \"Times New Roman\", serif); font-size: 1.12em; white-space: nowrap; }\n.dvc-math i { font-style: italic; }\n.dvc-math sup, .dvc-math sub { font-size: .7em; line-height: 0; }\n@media (prefers-reduced-motion: reduce) { .dvc, .dvc * { transition: none !important; } }\n";
|
|
8
|
+
/** Idempotent; cheap enough to call from every control's render. */
|
|
9
|
+
export declare function injectControlStyles(): void;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { injectStyles } from "../styles.js";
|
|
2
|
+
const CONTROLS_CSS = (
|
|
3
|
+
/* css */
|
|
4
|
+
`
|
|
5
|
+
.dvc {
|
|
6
|
+
--dvc-ink: var(--dv-fg); --dvc-sub: #6b6b6b; --dvc-line: #d9d9d9; --dvc-track: #ececec; --dvc-bg: #fff; --dvc-soft: #f5f5f5;
|
|
7
|
+
--dvc-accent: #456dff; --dvc-strong: #1a1a1a; --dvc-strong-ink: #fff; --dvc-hl: #fdf3d3; --dvc-hl-bar: #f7c325;
|
|
8
|
+
font-family: var(--dv-font); color: var(--dvc-ink);
|
|
9
|
+
}
|
|
10
|
+
:root[data-theme="dark"] .dvc, .dark .dvc {
|
|
11
|
+
--dvc-sub: #a3a3a3; --dvc-line: #3d3d3d; --dvc-track: #333; --dvc-bg: #1e1e1e; --dvc-soft: #262626;
|
|
12
|
+
--dvc-accent: #7491ff; --dvc-strong: #f2f2f2; --dvc-strong-ink: #141414; --dvc-hl: #3d3100; --dvc-hl-bar: #d7a613;
|
|
13
|
+
}
|
|
14
|
+
@media (prefers-color-scheme: dark) {
|
|
15
|
+
:root:not([data-theme="light"]):not(.light) .dvc {
|
|
16
|
+
--dvc-sub: #a3a3a3; --dvc-line: #3d3d3d; --dvc-track: #333; --dvc-bg: #1e1e1e; --dvc-soft: #262626;
|
|
17
|
+
--dvc-accent: #7491ff; --dvc-strong: #f2f2f2; --dvc-strong-ink: #141414; --dvc-hl: #3d3100; --dvc-hl-bar: #d7a613;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
.dvc-field { display: flex; align-items: center; gap: 10px; font-size: 13px; }
|
|
21
|
+
.dvc-label { color: var(--dvc-sub); white-space: nowrap; }
|
|
22
|
+
.dvc-readout { display: inline-grid; justify-items: end; font-variant-numeric: tabular-nums; font-kerning: none; font-weight: 600; white-space: nowrap; min-width: 3ch; flex: none; }
|
|
23
|
+
.dvc-readout > * { grid-area: 1 / 1; }
|
|
24
|
+
.dvc-readout-sizer { visibility: hidden; }
|
|
25
|
+
|
|
26
|
+
.dvc-btn { all: unset; box-sizing: border-box; display: inline-flex; align-items: center; justify-content: center; gap: 6px; height: 30px; padding: 0 12px; border-radius: 7px; cursor: pointer; font: 500 13px var(--dv-font); color: var(--dvc-ink); background: var(--dvc-bg); border: 1px solid var(--dvc-line); transition: background .12s, border-color .12s; }
|
|
27
|
+
.dvc-btn:hover:not(:disabled) { background: var(--dvc-soft); }
|
|
28
|
+
.dvc-btn:active:not(:disabled) { transform: translateY(1px); }
|
|
29
|
+
.dvc-btn:focus-visible { outline: 2px solid var(--dvc-accent); outline-offset: 1px; }
|
|
30
|
+
.dvc-btn:disabled { opacity: .4; cursor: default; }
|
|
31
|
+
.dvc-btn.is-primary { background: var(--dvc-strong); color: var(--dvc-strong-ink); border-color: var(--dvc-strong); }
|
|
32
|
+
.dvc-btn.is-primary:hover:not(:disabled) { background: color-mix(in srgb, var(--dvc-strong) 85%, #888); }
|
|
33
|
+
|
|
34
|
+
.dvc-slider { position: relative; display: flex; align-items: center; flex: 1; height: 22px; touch-action: none; user-select: none; min-width: 90px; }
|
|
35
|
+
.dvc-track { position: relative; flex: 1; height: 8px; border-radius: 4px; background: var(--dvc-track); }
|
|
36
|
+
.dvc-range { position: absolute; height: 100%; border-radius: 4px; background: var(--dvc-accent); }
|
|
37
|
+
.dvc-slider { --dvc-thumb: 18px; }
|
|
38
|
+
/* notches: dots inside the track, in a layer inset by half a thumb so they line up with its centre */
|
|
39
|
+
.dvc-ticks { position: absolute; top: 0; bottom: 0; left: calc(var(--dvc-thumb) / 2); right: calc(var(--dvc-thumb) / 2); pointer-events: none; }
|
|
40
|
+
.dvc-tick { position: absolute; top: 50%; width: 4px; height: 4px; border-radius: 50%; transform: translate(-50%, -50%); background: color-mix(in srgb, var(--dvc-sub) 45%, transparent); }
|
|
41
|
+
.dvc-tick.is-on { background: rgb(255 255 255 / .75); }
|
|
42
|
+
.dvc-thumb { box-sizing: border-box; display: block; width: var(--dvc-thumb); height: var(--dvc-thumb); border-radius: 50%; background: var(--dvc-bg); border: 2px solid var(--dvc-accent); box-shadow: 0 1px 2px rgb(0 0 0 / .2); cursor: grab; }
|
|
43
|
+
.dvc-thumb:hover { box-shadow: 0 0 0 5px color-mix(in srgb, var(--dvc-accent) 18%, transparent); }
|
|
44
|
+
.dvc-thumb:focus-visible { outline: none; box-shadow: 0 0 0 5px color-mix(in srgb, var(--dvc-accent) 35%, transparent); }
|
|
45
|
+
.dvc-thumb:active { cursor: grabbing; }
|
|
46
|
+
|
|
47
|
+
.dvc-seg { display: inline-flex; gap: 2px; padding: 2px; border-radius: 8px; background: var(--dvc-track); }
|
|
48
|
+
.dvc-seg-item { all: unset; box-sizing: border-box; padding: 4px 11px; border-radius: 6px; cursor: pointer; font: 500 13px var(--dv-font); color: var(--dvc-sub); }
|
|
49
|
+
.dvc-seg-item:hover { color: var(--dvc-ink); }
|
|
50
|
+
.dvc-seg-item[data-state="on"] { background: var(--dvc-bg); color: var(--dvc-ink); box-shadow: 0 1px 2px rgb(0 0 0 / .12); }
|
|
51
|
+
.dvc-seg-item:focus-visible { outline: 2px solid var(--dvc-accent); outline-offset: 1px; }
|
|
52
|
+
|
|
53
|
+
.dvc-select { all: unset; box-sizing: border-box; display: inline-flex; align-items: center; gap: 8px; height: 30px; padding: 0 10px; border-radius: 7px; cursor: pointer; font: 500 13px var(--dv-font); border: 1px solid var(--dvc-line); background: var(--dvc-bg); }
|
|
54
|
+
.dvc-select:focus-visible { outline: 2px solid var(--dvc-accent); }
|
|
55
|
+
.dvc-caret { color: var(--dvc-sub); }
|
|
56
|
+
.dvc-menu { z-index: 50; padding: 4px; border-radius: 9px; background: var(--dvc-bg); border: 1px solid var(--dvc-line); box-shadow: 0 6px 20px rgb(0 0 0 / .1); font: 13px var(--dv-font); }
|
|
57
|
+
.dvc-menu-item { padding: 6px 10px; border-radius: 6px; cursor: pointer; outline: none; }
|
|
58
|
+
.dvc-menu-item[data-highlighted] { background: var(--dvc-soft); }
|
|
59
|
+
|
|
60
|
+
.dvc-switch { all: unset; box-sizing: border-box; width: 30px; height: 18px; border-radius: 9px; cursor: pointer; background: var(--dvc-line); position: relative; transition: background .15s; }
|
|
61
|
+
.dvc-switch[data-state="checked"] { background: var(--dvc-accent); }
|
|
62
|
+
.dvc-switch:focus-visible { outline: 2px solid var(--dvc-accent); outline-offset: 2px; }
|
|
63
|
+
.dvc-switch-thumb { display: block; width: 14px; height: 14px; border-radius: 50%; background: #fff; transform: translateX(2px); transition: transform .15s; box-shadow: 0 1px 2px rgb(0 0 0 / .25); }
|
|
64
|
+
.dvc-switch-thumb[data-state="checked"] { transform: translateX(14px); }
|
|
65
|
+
|
|
66
|
+
.dvc-stepper { display: inline-flex; align-items: stretch; height: 30px; border-radius: 7px; border: 1px solid var(--dvc-line); overflow: hidden; background: var(--dvc-bg); }
|
|
67
|
+
.dvc-stepper button { all: unset; box-sizing: border-box; width: 28px; text-align: center; cursor: pointer; color: var(--dvc-sub); font-size: 15px; }
|
|
68
|
+
.dvc-stepper button:hover:not(:disabled) { background: var(--dvc-soft); color: var(--dvc-ink); }
|
|
69
|
+
.dvc-stepper button:disabled { opacity: .35; cursor: default; }
|
|
70
|
+
.dvc-stepper button:focus-visible { outline: 2px solid var(--dvc-accent); outline-offset: -2px; }
|
|
71
|
+
.dvc-stepper output { min-width: 36px; padding: 0 4px; display: grid; place-items: center; font: 600 13px var(--dv-font); font-variant-numeric: tabular-nums; border-inline: 1px solid var(--dvc-line); }
|
|
72
|
+
|
|
73
|
+
.dvc-transport { display: flex; align-items: center; gap: 4px; font-size: 13px; }
|
|
74
|
+
.dvc-transport button { all: unset; box-sizing: border-box; display: grid; place-items: center; width: 28px; height: 28px; border-radius: 50%; cursor: pointer; color: var(--dvc-sub); }
|
|
75
|
+
.dvc-transport button:hover:not(:disabled) { background: var(--dvc-soft); color: var(--dvc-ink); }
|
|
76
|
+
.dvc-transport button.is-play { background: var(--dvc-accent); color: #fff; }
|
|
77
|
+
.dvc-transport button.is-play:hover { background: color-mix(in srgb, var(--dvc-accent) 85%, #000); color: #fff; }
|
|
78
|
+
.dvc-transport button:focus-visible { outline: 2px solid var(--dvc-accent); }
|
|
79
|
+
.dvc-transport button:disabled { opacity: .3; cursor: default; }
|
|
80
|
+
.dvc-scrub { margin: 0 8px; }
|
|
81
|
+
|
|
82
|
+
.dvc-input { all: unset; box-sizing: border-box; height: 30px; padding: 0 9px; border-radius: 7px; font: 500 13px var(--dv-mono); color: var(--dvc-ink); border: 1px solid var(--dvc-line); background: var(--dvc-bg); }
|
|
83
|
+
.dvc-input:focus { border-color: var(--dvc-accent); }
|
|
84
|
+
|
|
85
|
+
.dvc-code { margin: 0; padding: 8px 4px; border-radius: 8px; background: var(--dvc-soft); font: 12.5px/1.7 var(--dv-mono); color: var(--dvc-sub); overflow-x: auto; }
|
|
86
|
+
.dvc-code-line { white-space: pre; padding: 0 10px; border-radius: 4px; transition: background .2s, color .2s; }
|
|
87
|
+
.dvc-code-line.is-active { color: var(--dvc-ink); background: var(--dvc-hl); box-shadow: inset 2px 0 0 var(--dvc-hl-bar); }
|
|
88
|
+
/* maths in HTML: same font and rules as the diagram's maths labels */
|
|
89
|
+
.dvc-math { font-family: var(--dv-math-font, "STIX Two Text", "Times New Roman", serif); font-size: 1.12em; white-space: nowrap; }
|
|
90
|
+
.dvc-math i { font-style: italic; }
|
|
91
|
+
.dvc-math sup, .dvc-math sub { font-size: .7em; line-height: 0; }
|
|
92
|
+
@media (prefers-reduced-motion: reduce) { .dvc, .dvc * { transition: none !important; } }
|
|
93
|
+
`
|
|
94
|
+
);
|
|
95
|
+
const ID = "dsviz-control-styles";
|
|
96
|
+
function injectControlStyles() {
|
|
97
|
+
if (typeof document === "undefined") return;
|
|
98
|
+
injectStyles();
|
|
99
|
+
if (document.getElementById(ID)) return;
|
|
100
|
+
const el = document.createElement("style");
|
|
101
|
+
el.id = ID;
|
|
102
|
+
el.textContent = CONTROLS_CSS;
|
|
103
|
+
document.head.appendChild(el);
|
|
104
|
+
}
|
|
105
|
+
export {
|
|
106
|
+
CONTROLS_CSS,
|
|
107
|
+
injectControlStyles
|
|
108
|
+
};
|
|
109
|
+
//# sourceMappingURL=controls-styles.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/react/controls-styles.ts"],
|
|
4
|
+
"sourcesContent": ["import { injectStyles } from '../styles';\n\n/**\n * CSS for the controls. Deliberately quiet: small, flat, neutral greys with one\n * blue accent, so the diagram is the thing you look at. They read the same\n * --dv-* variables as the diagrams (defined on `.dvc`), so a host app restyles\n * both from one place, or swaps the controls for its own entirely.\n */\nexport const CONTROLS_CSS = /* css */ `\n.dvc {\n --dvc-ink: var(--dv-fg); --dvc-sub: #6b6b6b; --dvc-line: #d9d9d9; --dvc-track: #ececec; --dvc-bg: #fff; --dvc-soft: #f5f5f5;\n --dvc-accent: #456dff; --dvc-strong: #1a1a1a; --dvc-strong-ink: #fff; --dvc-hl: #fdf3d3; --dvc-hl-bar: #f7c325;\n font-family: var(--dv-font); color: var(--dvc-ink);\n}\n:root[data-theme=\"dark\"] .dvc, .dark .dvc {\n --dvc-sub: #a3a3a3; --dvc-line: #3d3d3d; --dvc-track: #333; --dvc-bg: #1e1e1e; --dvc-soft: #262626;\n --dvc-accent: #7491ff; --dvc-strong: #f2f2f2; --dvc-strong-ink: #141414; --dvc-hl: #3d3100; --dvc-hl-bar: #d7a613;\n}\n@media (prefers-color-scheme: dark) {\n :root:not([data-theme=\"light\"]):not(.light) .dvc {\n --dvc-sub: #a3a3a3; --dvc-line: #3d3d3d; --dvc-track: #333; --dvc-bg: #1e1e1e; --dvc-soft: #262626;\n --dvc-accent: #7491ff; --dvc-strong: #f2f2f2; --dvc-strong-ink: #141414; --dvc-hl: #3d3100; --dvc-hl-bar: #d7a613;\n }\n}\n.dvc-field { display: flex; align-items: center; gap: 10px; font-size: 13px; }\n.dvc-label { color: var(--dvc-sub); white-space: nowrap; }\n.dvc-readout { display: inline-grid; justify-items: end; font-variant-numeric: tabular-nums; font-kerning: none; font-weight: 600; white-space: nowrap; min-width: 3ch; flex: none; }\n.dvc-readout > * { grid-area: 1 / 1; }\n.dvc-readout-sizer { visibility: hidden; }\n\n.dvc-btn { all: unset; box-sizing: border-box; display: inline-flex; align-items: center; justify-content: center; gap: 6px; height: 30px; padding: 0 12px; border-radius: 7px; cursor: pointer; font: 500 13px var(--dv-font); color: var(--dvc-ink); background: var(--dvc-bg); border: 1px solid var(--dvc-line); transition: background .12s, border-color .12s; }\n.dvc-btn:hover:not(:disabled) { background: var(--dvc-soft); }\n.dvc-btn:active:not(:disabled) { transform: translateY(1px); }\n.dvc-btn:focus-visible { outline: 2px solid var(--dvc-accent); outline-offset: 1px; }\n.dvc-btn:disabled { opacity: .4; cursor: default; }\n.dvc-btn.is-primary { background: var(--dvc-strong); color: var(--dvc-strong-ink); border-color: var(--dvc-strong); }\n.dvc-btn.is-primary:hover:not(:disabled) { background: color-mix(in srgb, var(--dvc-strong) 85%, #888); }\n\n.dvc-slider { position: relative; display: flex; align-items: center; flex: 1; height: 22px; touch-action: none; user-select: none; min-width: 90px; }\n.dvc-track { position: relative; flex: 1; height: 8px; border-radius: 4px; background: var(--dvc-track); }\n.dvc-range { position: absolute; height: 100%; border-radius: 4px; background: var(--dvc-accent); }\n.dvc-slider { --dvc-thumb: 18px; }\n/* notches: dots inside the track, in a layer inset by half a thumb so they line up with its centre */\n.dvc-ticks { position: absolute; top: 0; bottom: 0; left: calc(var(--dvc-thumb) / 2); right: calc(var(--dvc-thumb) / 2); pointer-events: none; }\n.dvc-tick { position: absolute; top: 50%; width: 4px; height: 4px; border-radius: 50%; transform: translate(-50%, -50%); background: color-mix(in srgb, var(--dvc-sub) 45%, transparent); }\n.dvc-tick.is-on { background: rgb(255 255 255 / .75); }\n.dvc-thumb { box-sizing: border-box; display: block; width: var(--dvc-thumb); height: var(--dvc-thumb); border-radius: 50%; background: var(--dvc-bg); border: 2px solid var(--dvc-accent); box-shadow: 0 1px 2px rgb(0 0 0 / .2); cursor: grab; }\n.dvc-thumb:hover { box-shadow: 0 0 0 5px color-mix(in srgb, var(--dvc-accent) 18%, transparent); }\n.dvc-thumb:focus-visible { outline: none; box-shadow: 0 0 0 5px color-mix(in srgb, var(--dvc-accent) 35%, transparent); }\n.dvc-thumb:active { cursor: grabbing; }\n\n.dvc-seg { display: inline-flex; gap: 2px; padding: 2px; border-radius: 8px; background: var(--dvc-track); }\n.dvc-seg-item { all: unset; box-sizing: border-box; padding: 4px 11px; border-radius: 6px; cursor: pointer; font: 500 13px var(--dv-font); color: var(--dvc-sub); }\n.dvc-seg-item:hover { color: var(--dvc-ink); }\n.dvc-seg-item[data-state=\"on\"] { background: var(--dvc-bg); color: var(--dvc-ink); box-shadow: 0 1px 2px rgb(0 0 0 / .12); }\n.dvc-seg-item:focus-visible { outline: 2px solid var(--dvc-accent); outline-offset: 1px; }\n\n.dvc-select { all: unset; box-sizing: border-box; display: inline-flex; align-items: center; gap: 8px; height: 30px; padding: 0 10px; border-radius: 7px; cursor: pointer; font: 500 13px var(--dv-font); border: 1px solid var(--dvc-line); background: var(--dvc-bg); }\n.dvc-select:focus-visible { outline: 2px solid var(--dvc-accent); }\n.dvc-caret { color: var(--dvc-sub); }\n.dvc-menu { z-index: 50; padding: 4px; border-radius: 9px; background: var(--dvc-bg); border: 1px solid var(--dvc-line); box-shadow: 0 6px 20px rgb(0 0 0 / .1); font: 13px var(--dv-font); }\n.dvc-menu-item { padding: 6px 10px; border-radius: 6px; cursor: pointer; outline: none; }\n.dvc-menu-item[data-highlighted] { background: var(--dvc-soft); }\n\n.dvc-switch { all: unset; box-sizing: border-box; width: 30px; height: 18px; border-radius: 9px; cursor: pointer; background: var(--dvc-line); position: relative; transition: background .15s; }\n.dvc-switch[data-state=\"checked\"] { background: var(--dvc-accent); }\n.dvc-switch:focus-visible { outline: 2px solid var(--dvc-accent); outline-offset: 2px; }\n.dvc-switch-thumb { display: block; width: 14px; height: 14px; border-radius: 50%; background: #fff; transform: translateX(2px); transition: transform .15s; box-shadow: 0 1px 2px rgb(0 0 0 / .25); }\n.dvc-switch-thumb[data-state=\"checked\"] { transform: translateX(14px); }\n\n.dvc-stepper { display: inline-flex; align-items: stretch; height: 30px; border-radius: 7px; border: 1px solid var(--dvc-line); overflow: hidden; background: var(--dvc-bg); }\n.dvc-stepper button { all: unset; box-sizing: border-box; width: 28px; text-align: center; cursor: pointer; color: var(--dvc-sub); font-size: 15px; }\n.dvc-stepper button:hover:not(:disabled) { background: var(--dvc-soft); color: var(--dvc-ink); }\n.dvc-stepper button:disabled { opacity: .35; cursor: default; }\n.dvc-stepper button:focus-visible { outline: 2px solid var(--dvc-accent); outline-offset: -2px; }\n.dvc-stepper output { min-width: 36px; padding: 0 4px; display: grid; place-items: center; font: 600 13px var(--dv-font); font-variant-numeric: tabular-nums; border-inline: 1px solid var(--dvc-line); }\n\n.dvc-transport { display: flex; align-items: center; gap: 4px; font-size: 13px; }\n.dvc-transport button { all: unset; box-sizing: border-box; display: grid; place-items: center; width: 28px; height: 28px; border-radius: 50%; cursor: pointer; color: var(--dvc-sub); }\n.dvc-transport button:hover:not(:disabled) { background: var(--dvc-soft); color: var(--dvc-ink); }\n.dvc-transport button.is-play { background: var(--dvc-accent); color: #fff; }\n.dvc-transport button.is-play:hover { background: color-mix(in srgb, var(--dvc-accent) 85%, #000); color: #fff; }\n.dvc-transport button:focus-visible { outline: 2px solid var(--dvc-accent); }\n.dvc-transport button:disabled { opacity: .3; cursor: default; }\n.dvc-scrub { margin: 0 8px; }\n\n.dvc-input { all: unset; box-sizing: border-box; height: 30px; padding: 0 9px; border-radius: 7px; font: 500 13px var(--dv-mono); color: var(--dvc-ink); border: 1px solid var(--dvc-line); background: var(--dvc-bg); }\n.dvc-input:focus { border-color: var(--dvc-accent); }\n\n.dvc-code { margin: 0; padding: 8px 4px; border-radius: 8px; background: var(--dvc-soft); font: 12.5px/1.7 var(--dv-mono); color: var(--dvc-sub); overflow-x: auto; }\n.dvc-code-line { white-space: pre; padding: 0 10px; border-radius: 4px; transition: background .2s, color .2s; }\n.dvc-code-line.is-active { color: var(--dvc-ink); background: var(--dvc-hl); box-shadow: inset 2px 0 0 var(--dvc-hl-bar); }\n/* maths in HTML: same font and rules as the diagram's maths labels */\n.dvc-math { font-family: var(--dv-math-font, \"STIX Two Text\", \"Times New Roman\", serif); font-size: 1.12em; white-space: nowrap; }\n.dvc-math i { font-style: italic; }\n.dvc-math sup, .dvc-math sub { font-size: .7em; line-height: 0; }\n@media (prefers-reduced-motion: reduce) { .dvc, .dvc * { transition: none !important; } }\n`;\n\nconst ID = 'dsviz-control-styles';\n\n/** Idempotent; cheap enough to call from every control's render. */\nexport function injectControlStyles(): void {\n if (typeof document === 'undefined') return;\n injectStyles(); // the --dv-* variables the controls read live in the core stylesheet\n if (document.getElementById(ID)) return;\n const el = document.createElement('style');\n el.id = ID;\n el.textContent = CONTROLS_CSS;\n document.head.appendChild(el);\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,oBAAoB;AAQtB,MAAM;AAAA;AAAA,EAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2FtC,MAAM,KAAK;AAGJ,SAAS,sBAA4B;AAC1C,MAAI,OAAO,aAAa,YAAa;AACrC,eAAa;AACb,MAAI,SAAS,eAAe,EAAE,EAAG;AACjC,QAAM,KAAK,SAAS,cAAc,OAAO;AACzC,KAAG,KAAK;AACR,KAAG,cAAc;AACjB,WAAS,KAAK,YAAY,EAAE;AAC9B;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import type { PlayerState } from './hooks';
|
|
3
|
+
export interface SliderProps {
|
|
4
|
+
value: number;
|
|
5
|
+
onChange: (v: number) => void;
|
|
6
|
+
min: number;
|
|
7
|
+
max: number;
|
|
8
|
+
step?: number;
|
|
9
|
+
label?: string;
|
|
10
|
+
/** Right-hand readout, e.g. `n = 64`. */
|
|
11
|
+
format?: (v: number) => ReactNode;
|
|
12
|
+
/** Draw a tick at each of these values. */
|
|
13
|
+
ticks?: number[];
|
|
14
|
+
className?: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function Slider({ value, onChange, min, max, step, label, format, ticks, className }: SliderProps): import("react").JSX.Element;
|
|
17
|
+
export interface SegmentedProps<T extends string> {
|
|
18
|
+
value: T;
|
|
19
|
+
onChange: (v: T) => void;
|
|
20
|
+
options: ReadonlyArray<T | {
|
|
21
|
+
value: T;
|
|
22
|
+
label: ReactNode;
|
|
23
|
+
}>;
|
|
24
|
+
label?: string;
|
|
25
|
+
}
|
|
26
|
+
/** Use instead of a dropdown when there are 2–4 options: every choice stays visible, one click. */
|
|
27
|
+
export declare function Segmented<T extends string>({ value, onChange, options, label }: SegmentedProps<T>): import("react").JSX.Element;
|
|
28
|
+
export interface SelectProps<T extends string> {
|
|
29
|
+
value: T;
|
|
30
|
+
onChange: (v: T) => void;
|
|
31
|
+
options: ReadonlyArray<T | {
|
|
32
|
+
value: T;
|
|
33
|
+
label: ReactNode;
|
|
34
|
+
}>;
|
|
35
|
+
label?: string;
|
|
36
|
+
}
|
|
37
|
+
export declare function Select<T extends string>({ value, onChange, options, label }: SelectProps<T>): import("react").JSX.Element;
|
|
38
|
+
export declare function Switch({ checked, onChange, label }: {
|
|
39
|
+
checked: boolean;
|
|
40
|
+
onChange: (v: boolean) => void;
|
|
41
|
+
label?: string;
|
|
42
|
+
}): import("react").JSX.Element;
|
|
43
|
+
export interface NumberStepperProps {
|
|
44
|
+
value: number;
|
|
45
|
+
onChange: (v: number) => void;
|
|
46
|
+
min?: number;
|
|
47
|
+
max?: number;
|
|
48
|
+
step?: number;
|
|
49
|
+
label?: string;
|
|
50
|
+
}
|
|
51
|
+
/** − n + : for small integers where dragging a slider would be fiddly (a search target). */
|
|
52
|
+
export declare function NumberStepper({ value, onChange, min, max, step, label }: NumberStepperProps): import("react").JSX.Element;
|
|
53
|
+
export interface TransportProps {
|
|
54
|
+
/** What usePlayer() returns. */
|
|
55
|
+
player: Pick<PlayerState<unknown>, 'index' | 'count' | 'playing' | 'first' | 'prev' | 'toggle' | 'next' | 'seek'>;
|
|
56
|
+
}
|
|
57
|
+
/** first / prev / play / next, a scrubber with a tick per step, and "Step i / n". `<Transport player={usePlayer(...)} />` */
|
|
58
|
+
export declare function Transport({ player: p }: TransportProps): import("react").JSX.Element;
|
|
59
|
+
/**
|
|
60
|
+
* A panel of source lines with the active one(s) highlighted. Feed it `frame.line`
|
|
61
|
+
* from a generator that yields `{ ..., line }`. Indentation is preserved.
|
|
62
|
+
*/
|
|
63
|
+
export declare function CodeTrace({ lines, active }: {
|
|
64
|
+
lines: readonly string[];
|
|
65
|
+
active?: number | readonly number[] | null;
|
|
66
|
+
}): import("react").JSX.Element;
|
|
67
|
+
export interface ButtonProps {
|
|
68
|
+
children: ReactNode;
|
|
69
|
+
onClick: () => void;
|
|
70
|
+
/** primary = filled, ghost = outlined. */
|
|
71
|
+
variant?: 'primary' | 'ghost';
|
|
72
|
+
disabled?: boolean;
|
|
73
|
+
title?: string;
|
|
74
|
+
}
|
|
75
|
+
export declare function Button({ children, onClick, variant, disabled, title }: ButtonProps): import("react").JSX.Element;
|
|
76
|
+
export interface TextInputProps {
|
|
77
|
+
value: string;
|
|
78
|
+
/** Called on Enter or blur (not every keystroke), so half-typed input doesn't re-run a diagram. */
|
|
79
|
+
onCommit: (v: string) => void;
|
|
80
|
+
label?: string;
|
|
81
|
+
width?: number | string;
|
|
82
|
+
placeholder?: string;
|
|
83
|
+
}
|
|
84
|
+
export declare function TextInput({ value, onCommit, label, width, placeholder }: TextInputProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as RSelect from "@radix-ui/react-select";
|
|
3
|
+
import * as RSlider from "@radix-ui/react-slider";
|
|
4
|
+
import * as RSwitch from "@radix-ui/react-switch";
|
|
5
|
+
import * as RToggle from "@radix-ui/react-toggle-group";
|
|
6
|
+
import { useEffect, useId, useRef, useState } from "react";
|
|
7
|
+
import { injectControlStyles } from "./controls-styles.js";
|
|
8
|
+
const cx = (...c) => c.filter(Boolean).join(" ");
|
|
9
|
+
function Readout({ children, widest }) {
|
|
10
|
+
return /* @__PURE__ */ jsxs("span", { className: "dvc-readout", children: [
|
|
11
|
+
widest && /* @__PURE__ */ jsx("span", { className: "dvc-readout-sizer", "aria-hidden": true, children: widest }),
|
|
12
|
+
/* @__PURE__ */ jsx("span", { children })
|
|
13
|
+
] });
|
|
14
|
+
}
|
|
15
|
+
function Field({ label, readout, widest, children, id }) {
|
|
16
|
+
return /* @__PURE__ */ jsxs("div", { className: "dvc dvc-field", children: [
|
|
17
|
+
label && /* @__PURE__ */ jsx("label", { className: "dvc-label", htmlFor: id, children: label }),
|
|
18
|
+
children,
|
|
19
|
+
readout !== void 0 && /* @__PURE__ */ jsx(Readout, { widest, children: readout })
|
|
20
|
+
] });
|
|
21
|
+
}
|
|
22
|
+
function useWidth() {
|
|
23
|
+
const ref = useRef(null);
|
|
24
|
+
const [w, setW] = useState(0);
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
const el = ref.current;
|
|
27
|
+
if (!el || typeof ResizeObserver === "undefined") return;
|
|
28
|
+
const ro = new ResizeObserver(([e]) => setW(e.contentRect.width));
|
|
29
|
+
ro.observe(el);
|
|
30
|
+
return () => ro.disconnect();
|
|
31
|
+
}, []);
|
|
32
|
+
return [ref, w];
|
|
33
|
+
}
|
|
34
|
+
function Ticks({ fractions, on, width }) {
|
|
35
|
+
if (fractions.length < 2 || !width || width / (fractions.length - 1) < 10) return null;
|
|
36
|
+
return /* @__PURE__ */ jsx("span", { className: "dvc-ticks", "aria-hidden": true, children: fractions.map((f, i) => /* @__PURE__ */ jsx("span", { className: cx("dvc-tick", on(i) && "is-on"), style: { left: `${f * 100}%` } }, i)) });
|
|
37
|
+
}
|
|
38
|
+
const widestOf = (format, min, max, step) => {
|
|
39
|
+
if (!format) return void 0;
|
|
40
|
+
const xs = [min, max, min + step, max - step].map((v) => format(v)).filter((x) => typeof x === "string" || typeof x === "number");
|
|
41
|
+
return xs.map(String).sort((a, b) => b.length - a.length)[0];
|
|
42
|
+
};
|
|
43
|
+
function Slider({ value, onChange, min, max, step = 1, label, format, ticks, className }) {
|
|
44
|
+
injectControlStyles();
|
|
45
|
+
const id = useId();
|
|
46
|
+
const [ref, width] = useWidth();
|
|
47
|
+
return /* @__PURE__ */ jsx(Field, { label, id, readout: format ? format(value) : void 0, widest: widestOf(format, min, max, step), children: /* @__PURE__ */ jsxs(RSlider.Root, { ref, id, className: cx("dvc-slider", className), value: [value], min, max, step, onValueChange: ([v]) => onChange(v), children: [
|
|
48
|
+
/* @__PURE__ */ jsx(RSlider.Track, { className: "dvc-track", children: /* @__PURE__ */ jsx(RSlider.Range, { className: "dvc-range" }) }),
|
|
49
|
+
ticks && /* @__PURE__ */ jsx(Ticks, { fractions: ticks.map((t) => (t - min) / (max - min)), on: (i) => ticks[i] <= value, width }),
|
|
50
|
+
/* @__PURE__ */ jsx(RSlider.Thumb, { className: "dvc-thumb", "aria-label": label ?? "value" })
|
|
51
|
+
] }) });
|
|
52
|
+
}
|
|
53
|
+
function Segmented({ value, onChange, options, label }) {
|
|
54
|
+
injectControlStyles();
|
|
55
|
+
return /* @__PURE__ */ jsx(Field, { label, children: /* @__PURE__ */ jsx(RToggle.Root, { type: "single", className: "dvc-seg", value, onValueChange: (v) => v && onChange(v), "aria-label": label, children: options.map((o) => {
|
|
56
|
+
const v = typeof o === "string" ? o : o.value;
|
|
57
|
+
return /* @__PURE__ */ jsx(RToggle.Item, { value: v, className: "dvc-seg-item", children: typeof o === "string" ? o : o.label }, v);
|
|
58
|
+
}) }) });
|
|
59
|
+
}
|
|
60
|
+
function Select({ value, onChange, options, label }) {
|
|
61
|
+
injectControlStyles();
|
|
62
|
+
const norm = options.map((o) => typeof o === "string" ? { value: o, label: o } : o);
|
|
63
|
+
return /* @__PURE__ */ jsx(Field, { label, children: /* @__PURE__ */ jsxs(RSelect.Root, { value, onValueChange: (v) => onChange(v), children: [
|
|
64
|
+
/* @__PURE__ */ jsxs(RSelect.Trigger, { className: "dvc-select", "aria-label": label, children: [
|
|
65
|
+
/* @__PURE__ */ jsx(RSelect.Value, {}),
|
|
66
|
+
/* @__PURE__ */ jsx(RSelect.Icon, { className: "dvc-caret", children: "\u25BE" })
|
|
67
|
+
] }),
|
|
68
|
+
/* @__PURE__ */ jsx(RSelect.Portal, { children: /* @__PURE__ */ jsx(RSelect.Content, { className: "dvc dvc-menu", position: "popper", sideOffset: 4, children: /* @__PURE__ */ jsx(RSelect.Viewport, { children: norm.map((o) => /* @__PURE__ */ jsx(RSelect.Item, { value: o.value, className: "dvc-menu-item", children: /* @__PURE__ */ jsx(RSelect.ItemText, { children: o.label }) }, o.value)) }) }) })
|
|
69
|
+
] }) });
|
|
70
|
+
}
|
|
71
|
+
function Switch({ checked, onChange, label }) {
|
|
72
|
+
injectControlStyles();
|
|
73
|
+
const id = useId();
|
|
74
|
+
return /* @__PURE__ */ jsx(Field, { label, id, children: /* @__PURE__ */ jsx(RSwitch.Root, { id, className: "dvc-switch", checked, onCheckedChange: onChange, children: /* @__PURE__ */ jsx(RSwitch.Thumb, { className: "dvc-switch-thumb" }) }) });
|
|
75
|
+
}
|
|
76
|
+
function NumberStepper({ value, onChange, min = -Infinity, max = Infinity, step = 1, label }) {
|
|
77
|
+
injectControlStyles();
|
|
78
|
+
const set = (v) => onChange(Math.min(max, Math.max(min, v)));
|
|
79
|
+
return /* @__PURE__ */ jsx(Field, { label, children: /* @__PURE__ */ jsxs("div", { className: "dvc dvc-stepper", role: "group", "aria-label": label, children: [
|
|
80
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: () => set(value - step), disabled: value <= min, "aria-label": "decrease", children: "\u2212" }),
|
|
81
|
+
/* @__PURE__ */ jsx("output", { children: value }),
|
|
82
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: () => set(value + step), disabled: value >= max, "aria-label": "increase", children: "+" })
|
|
83
|
+
] }) });
|
|
84
|
+
}
|
|
85
|
+
const Icon = ({ d }) => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 16 16", width: "16", height: "16", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d, fill: "currentColor" }) });
|
|
86
|
+
function Transport({ player: p }) {
|
|
87
|
+
injectControlStyles();
|
|
88
|
+
const last = Math.max(0, p.count - 1);
|
|
89
|
+
const [ref, width] = useWidth();
|
|
90
|
+
return /* @__PURE__ */ jsxs("div", { className: "dvc dvc-transport", children: [
|
|
91
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: p.first, disabled: p.index === 0, "aria-label": "First step", children: /* @__PURE__ */ jsx(Icon, { d: "M3 3h2v10H3zM13 3v10L6 8z" }) }),
|
|
92
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: p.prev, disabled: p.index === 0, "aria-label": "Previous step", children: /* @__PURE__ */ jsx(Icon, { d: "M12 3v10L5 8z" }) }),
|
|
93
|
+
/* @__PURE__ */ jsx("button", { type: "button", className: "is-play", onClick: p.toggle, "aria-label": p.playing ? "Pause" : "Play", children: /* @__PURE__ */ jsx(Icon, { d: p.playing ? "M4 3h3v10H4zM9 3h3v10H9z" : "M4 3l9 5-9 5z" }) }),
|
|
94
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: p.next, disabled: p.index >= last, "aria-label": "Next step", children: /* @__PURE__ */ jsx(Icon, { d: "M4 3v10l7-5zM11 3h2v10h-2z" }) }),
|
|
95
|
+
/* @__PURE__ */ jsxs(RSlider.Root, { ref, className: "dvc-slider dvc-scrub", value: [p.index], min: 0, max: last, step: 1, onValueChange: ([v]) => p.seek(v), children: [
|
|
96
|
+
/* @__PURE__ */ jsx(RSlider.Track, { className: "dvc-track", children: /* @__PURE__ */ jsx(RSlider.Range, { className: "dvc-range" }) }),
|
|
97
|
+
/* @__PURE__ */ jsx(Ticks, { fractions: Array.from({ length: p.count }, (_, i) => last ? i / last : 0), on: (i) => i <= p.index, width }),
|
|
98
|
+
/* @__PURE__ */ jsx(RSlider.Thumb, { className: "dvc-thumb", "aria-label": "Step" })
|
|
99
|
+
] }),
|
|
100
|
+
/* @__PURE__ */ jsxs(Readout, { widest: `Step ${last} / ${last}`, children: [
|
|
101
|
+
"Step ",
|
|
102
|
+
p.index,
|
|
103
|
+
" / ",
|
|
104
|
+
last
|
|
105
|
+
] })
|
|
106
|
+
] });
|
|
107
|
+
}
|
|
108
|
+
function CodeTrace({ lines, active }) {
|
|
109
|
+
injectControlStyles();
|
|
110
|
+
const on = new Set(active == null ? [] : typeof active === "number" ? [active] : active);
|
|
111
|
+
return /* @__PURE__ */ jsx("pre", { className: "dvc dvc-code", "aria-label": "Algorithm steps", children: lines.map((l, i) => /* @__PURE__ */ jsx("div", { className: cx("dvc-code-line", on.has(i) && "is-active"), "aria-current": on.has(i) ? "step" : void 0, children: l || " " }, i)) });
|
|
112
|
+
}
|
|
113
|
+
function Button({ children, onClick, variant = "ghost", disabled, title }) {
|
|
114
|
+
injectControlStyles();
|
|
115
|
+
return /* @__PURE__ */ jsx("button", { type: "button", className: cx("dvc dvc-btn", variant === "primary" && "is-primary"), onClick, disabled, title, children });
|
|
116
|
+
}
|
|
117
|
+
function TextInput({ value, onCommit, label, width = "10ch", placeholder }) {
|
|
118
|
+
injectControlStyles();
|
|
119
|
+
const id = useId();
|
|
120
|
+
return /* @__PURE__ */ jsx(Field, { label, id, children: /* @__PURE__ */ jsx(
|
|
121
|
+
"input",
|
|
122
|
+
{
|
|
123
|
+
id,
|
|
124
|
+
className: "dvc-input",
|
|
125
|
+
defaultValue: value,
|
|
126
|
+
placeholder,
|
|
127
|
+
spellCheck: false,
|
|
128
|
+
style: { width },
|
|
129
|
+
onKeyDown: (e) => e.key === "Enter" && onCommit(e.target.value),
|
|
130
|
+
onBlur: (e) => e.target.value !== value && onCommit(e.target.value)
|
|
131
|
+
},
|
|
132
|
+
value
|
|
133
|
+
) });
|
|
134
|
+
}
|
|
135
|
+
export {
|
|
136
|
+
Button,
|
|
137
|
+
CodeTrace,
|
|
138
|
+
NumberStepper,
|
|
139
|
+
Segmented,
|
|
140
|
+
Select,
|
|
141
|
+
Slider,
|
|
142
|
+
Switch,
|
|
143
|
+
TextInput,
|
|
144
|
+
Transport
|
|
145
|
+
};
|
|
146
|
+
//# sourceMappingURL=controls.js.map
|