foldkit 0.90.1 → 0.92.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.
Files changed (41) hide show
  1. package/README.md +2 -0
  2. package/dist/canvas/index.d.ts +5 -0
  3. package/dist/canvas/index.d.ts.map +1 -0
  4. package/dist/canvas/index.js +2 -0
  5. package/dist/canvas/paint.d.ts +14 -0
  6. package/dist/canvas/paint.d.ts.map +1 -0
  7. package/dist/canvas/paint.js +144 -0
  8. package/dist/canvas/public.d.ts +3 -0
  9. package/dist/canvas/public.d.ts.map +1 -0
  10. package/dist/canvas/public.js +1 -0
  11. package/dist/canvas/shape.d.ts +188 -0
  12. package/dist/canvas/shape.d.ts.map +1 -0
  13. package/dist/canvas/shape.js +103 -0
  14. package/dist/canvas/view.d.ts +38 -0
  15. package/dist/canvas/view.d.ts.map +1 -0
  16. package/dist/canvas/view.js +97 -0
  17. package/dist/devTools/overlay.d.ts +1 -0
  18. package/dist/devTools/overlay.d.ts.map +1 -1
  19. package/dist/devTools/overlay.js +3 -3
  20. package/dist/devTools/store.d.ts +13 -2
  21. package/dist/devTools/store.d.ts.map +1 -1
  22. package/dist/devTools/store.js +24 -9
  23. package/dist/html/index.d.ts +3 -3
  24. package/dist/html/index.d.ts.map +1 -1
  25. package/dist/index.d.ts +1 -0
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +1 -0
  28. package/dist/runtime/runtime.d.ts +4 -0
  29. package/dist/runtime/runtime.d.ts.map +1 -1
  30. package/dist/runtime/runtime.js +56 -16
  31. package/dist/subscription/animationFrame.d.ts +53 -0
  32. package/dist/subscription/animationFrame.d.ts.map +1 -0
  33. package/dist/subscription/animationFrame.js +47 -0
  34. package/dist/subscription/public.d.ts +2 -0
  35. package/dist/subscription/public.d.ts.map +1 -1
  36. package/dist/subscription/public.js +1 -0
  37. package/dist/ui/dragAndDrop/index.d.ts +1 -1
  38. package/dist/ui/listbox/multi.d.ts +1 -1
  39. package/dist/ui/listbox/shared.d.ts +1 -1
  40. package/dist/ui/listbox/single.d.ts +1 -1
  41. package/package.json +5 -1
package/README.md CHANGED
@@ -157,6 +157,7 @@ Foldkit is a complete system, not a collection of libraries you stitch together.
157
157
  - **Submodels**: A pattern for composing nested modules. A child owns its own Model, Messages, update function, and view; the parent embeds it and wraps child Messages in a `Got*Message` envelope. The pattern scales unchanged from a login form to a multi-page app.
158
158
  - **OutMessage**: A typed channel for a child Submodel to emit domain events up to its parent, so the parent reacts to meaningful facts instead of internal child Messages.
159
159
  - **UI Components**: Accessible, keyboard-friendly primitives covering Button, Checkbox, Combobox, Dialog, Disclosure, DragAndDrop, Fieldset, Input, Listbox, Menu, Popover, RadioGroup, Select, Switch, Tabs, Textarea, and Transition. Every component is a Submodel with a typed `ViewConfig`, domain-event callbacks like `onSelected`, `onClosed`, and `onToggled`, and `className` plus `attributes` props on every slot for styling and extension. Animated components share a `Transition` Submodel that coordinates CSS enter and leave animations.
160
+ - **Canvas**: Declarative 2D rendering. Describe a scene as a tree of `Shape` values (Rect, Circle, Path, Text, plus Group, which composes children under translate / rotate / scale / opacity), pass them to `Canvas.view`, and the runtime re-paints on every patch. The canvas pixels are a pure function of the shapes, so DevTools time-travel reproduces past frames exactly. Pair with `Subscription.animationFrame` for `requestAnimationFrame`-driven Subscriptions.
160
161
  - **Field Validation**: Per-field validation state modeled as a discriminated union. Define rules as data, apply them in update, and the Model tracks the result.
161
162
  - **Virtual DOM**: Declarative views powered by [Snabbdom](https://github.com/snabbdom/snabbdom), with lazy memoization and fast, keyed diffing. Views are plain functions of your Model.
162
163
  - **DevTools**: Built-in overlay for inspecting Messages, Model state, and Commands. Time-travel mode rewinds your UI to any past Model, Inspect mode browses snapshots without pausing, and Submodel drill-in filtering scopes the Message list to any nested module.
@@ -191,6 +192,7 @@ This is what makes Foldkit unusually AI-friendly. The same property that makes t
191
192
  - **[WebSocket Chat](https://foldkit.dev/example-apps/websocket-chat)** — Managed Resources with WebSocket integration
192
193
  - **[Kanban](https://foldkit.dev/example-apps/kanban)** — Drag-and-drop kanban board with cross-column reordering and keyboard navigation
193
194
  - **[Pixel Art](https://foldkit.dev/example-apps/pixel-art)** — Grid-based pixel editor with painting, erasing, and palette selection
195
+ - **[Canvas Art](https://foldkit.dev/example-apps/canvas-art)** — Declarative 2D canvas with shapes, animation-frame Subscriptions, and pointer events
194
196
  - **[UI Showcase](https://foldkit.dev/example-apps/ui-showcase)** — Interactive showcase of every Foldkit UI component
195
197
  - **[Typing Game](https://github.com/foldkit/foldkit/tree/main/packages/typing-game)** — Multiplayer typing game with Effect RPC backend ([play it live](https://typingterminal.com))
196
198
 
@@ -0,0 +1,5 @@
1
+ export { BezierTo, Circle, Close, Group, LineCap, LineJoin, LineTo, MoveTo, Path, PathInstruction, Point, QuadTo, Rect, Text, TextAlign, TextBaseline, } from './shape.js';
2
+ export type { Shape } from './shape.js';
3
+ export { view } from './view.js';
4
+ export type { ViewConfig } from './view.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/canvas/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,MAAM,EACN,KAAK,EACL,KAAK,EACL,OAAO,EACP,QAAQ,EACR,MAAM,EACN,MAAM,EACN,IAAI,EACJ,eAAe,EACf,KAAK,EACL,MAAM,EACN,IAAI,EACJ,IAAI,EACJ,SAAS,EACT,YAAY,GACb,MAAM,YAAY,CAAA;AAEnB,YAAY,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAEvC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEhC,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA"}
@@ -0,0 +1,2 @@
1
+ export { BezierTo, Circle, Close, Group, LineCap, LineJoin, LineTo, MoveTo, Path, PathInstruction, Point, QuadTo, Rect, Text, TextAlign, TextBaseline, } from './shape.js';
2
+ export { view } from './view.js';
@@ -0,0 +1,14 @@
1
+ import type { Shape } from './shape.js';
2
+ /**
3
+ * Paint a single `Shape` to the 2D context. Each call is bracketed by
4
+ * `ctx.save` / `ctx.restore` so per-shape state mutations (fillStyle,
5
+ * lineWidth, font, transforms applied by `Group`, etc.) cannot leak to
6
+ * sibling shapes. Recurses into `Group` children inside the saved scope.
7
+ */
8
+ export declare const paintShape: (ctx: CanvasRenderingContext2D) => (shape: Shape) => void;
9
+ /**
10
+ * Clear the canvas and paint every shape in `shapes` against the given
11
+ * 2D context. Called by `Canvas.view` on insert and on every postpatch.
12
+ */
13
+ export declare const paintScene: (ctx: CanvasRenderingContext2D, width: number, height: number, shapes: ReadonlyArray<Shape>) => void;
14
+ //# sourceMappingURL=paint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paint.d.ts","sourceRoot":"","sources":["../../src/canvas/paint.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAQV,KAAK,EAIN,MAAM,YAAY,CAAA;AAoJnB;;;;;GAKG;AACH,eAAO,MAAM,UAAU,GACpB,KAAK,wBAAwB,MAC7B,OAAO,KAAK,KAAG,IAYf,CAAA;AAEH;;;GAGG;AACH,eAAO,MAAM,UAAU,GACrB,KAAK,wBAAwB,EAC7B,OAAO,MAAM,EACb,QAAQ,MAAM,EACd,QAAQ,aAAa,CAAC,KAAK,CAAC,KAC3B,IAGF,CAAA"}
@@ -0,0 +1,144 @@
1
+ import { Array, Match } from 'effect';
2
+ const lineCapForCanvas = {
3
+ Butt: 'butt',
4
+ Round: 'round',
5
+ Square: 'square',
6
+ };
7
+ const lineJoinForCanvas = {
8
+ Miter: 'miter',
9
+ Round: 'round',
10
+ Bevel: 'bevel',
11
+ };
12
+ const textAlignForCanvas = {
13
+ Left: 'left',
14
+ Center: 'center',
15
+ Right: 'right',
16
+ Start: 'start',
17
+ End: 'end',
18
+ };
19
+ const textBaselineForCanvas = {
20
+ Top: 'top',
21
+ Middle: 'middle',
22
+ Bottom: 'bottom',
23
+ Alphabetic: 'alphabetic',
24
+ Hanging: 'hanging',
25
+ Ideographic: 'ideographic',
26
+ };
27
+ const paintRect = (ctx) => (rect) => {
28
+ if (rect.fill !== undefined) {
29
+ ctx.fillStyle = rect.fill;
30
+ ctx.fillRect(rect.x, rect.y, rect.width, rect.height);
31
+ }
32
+ if (rect.stroke !== undefined) {
33
+ ctx.strokeStyle = rect.stroke;
34
+ if (rect.lineWidth !== undefined) {
35
+ ctx.lineWidth = rect.lineWidth;
36
+ }
37
+ ctx.strokeRect(rect.x, rect.y, rect.width, rect.height);
38
+ }
39
+ };
40
+ const paintCircle = (ctx) => (circle) => {
41
+ ctx.beginPath();
42
+ ctx.arc(circle.x, circle.y, circle.radius, 0, Math.PI * 2);
43
+ if (circle.fill !== undefined) {
44
+ ctx.fillStyle = circle.fill;
45
+ ctx.fill();
46
+ }
47
+ if (circle.stroke !== undefined) {
48
+ ctx.strokeStyle = circle.stroke;
49
+ if (circle.lineWidth !== undefined) {
50
+ ctx.lineWidth = circle.lineWidth;
51
+ }
52
+ ctx.stroke();
53
+ }
54
+ };
55
+ const applyPathInstruction = (ctx) => (instruction) => Match.value(instruction).pipe(Match.tagsExhaustive({
56
+ MoveTo: ({ x, y }) => ctx.moveTo(x, y),
57
+ LineTo: ({ x, y }) => ctx.lineTo(x, y),
58
+ QuadTo: ({ cpx, cpy, x, y }) => ctx.quadraticCurveTo(cpx, cpy, x, y),
59
+ BezierTo: ({ cp1x, cp1y, cp2x, cp2y, x, y }) => ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y),
60
+ Close: () => ctx.closePath(),
61
+ }));
62
+ const paintPath = (ctx) => (path) => {
63
+ ctx.beginPath();
64
+ Array.forEach(path.instructions, applyPathInstruction(ctx));
65
+ if (path.fill !== undefined) {
66
+ ctx.fillStyle = path.fill;
67
+ ctx.fill();
68
+ }
69
+ if (path.stroke !== undefined) {
70
+ ctx.strokeStyle = path.stroke;
71
+ if (path.lineWidth !== undefined) {
72
+ ctx.lineWidth = path.lineWidth;
73
+ }
74
+ if (path.lineCap !== undefined) {
75
+ ctx.lineCap = lineCapForCanvas[path.lineCap];
76
+ }
77
+ if (path.lineJoin !== undefined) {
78
+ ctx.lineJoin = lineJoinForCanvas[path.lineJoin];
79
+ }
80
+ ctx.stroke();
81
+ }
82
+ };
83
+ const paintText = (ctx) => (text) => {
84
+ if (text.font !== undefined) {
85
+ ctx.font = text.font;
86
+ }
87
+ if (text.align !== undefined) {
88
+ ctx.textAlign = textAlignForCanvas[text.align];
89
+ }
90
+ if (text.baseline !== undefined) {
91
+ ctx.textBaseline = textBaselineForCanvas[text.baseline];
92
+ }
93
+ if (text.fill !== undefined) {
94
+ ctx.fillStyle = text.fill;
95
+ ctx.fillText(text.content, text.x, text.y);
96
+ }
97
+ if (text.stroke !== undefined) {
98
+ ctx.strokeStyle = text.stroke;
99
+ if (text.lineWidth !== undefined) {
100
+ ctx.lineWidth = text.lineWidth;
101
+ }
102
+ ctx.strokeText(text.content, text.x, text.y);
103
+ }
104
+ };
105
+ const paintGroup = (ctx) => (group) => {
106
+ if (group.opacity !== undefined) {
107
+ ctx.globalAlpha *= group.opacity;
108
+ }
109
+ if (group.translate !== undefined) {
110
+ ctx.translate(group.translate.x, group.translate.y);
111
+ }
112
+ if (group.rotate !== undefined) {
113
+ ctx.rotate(group.rotate);
114
+ }
115
+ if (group.scale !== undefined) {
116
+ ctx.scale(group.scale.x, group.scale.y);
117
+ }
118
+ Array.forEach(group.shapes, paintShape(ctx));
119
+ };
120
+ /**
121
+ * Paint a single `Shape` to the 2D context. Each call is bracketed by
122
+ * `ctx.save` / `ctx.restore` so per-shape state mutations (fillStyle,
123
+ * lineWidth, font, transforms applied by `Group`, etc.) cannot leak to
124
+ * sibling shapes. Recurses into `Group` children inside the saved scope.
125
+ */
126
+ export const paintShape = (ctx) => (shape) => {
127
+ ctx.save();
128
+ Match.value(shape).pipe(Match.tagsExhaustive({
129
+ Rect: paintRect(ctx),
130
+ Circle: paintCircle(ctx),
131
+ Path: paintPath(ctx),
132
+ Text: paintText(ctx),
133
+ Group: paintGroup(ctx),
134
+ }));
135
+ ctx.restore();
136
+ };
137
+ /**
138
+ * Clear the canvas and paint every shape in `shapes` against the given
139
+ * 2D context. Called by `Canvas.view` on insert and on every postpatch.
140
+ */
141
+ export const paintScene = (ctx, width, height, shapes) => {
142
+ ctx.clearRect(0, 0, width, height);
143
+ Array.forEach(shapes, paintShape(ctx));
144
+ };
@@ -0,0 +1,3 @@
1
+ export { BezierTo, Circle, Close, Group, LineCap, LineJoin, LineTo, MoveTo, Path, PathInstruction, Point, QuadTo, Rect, Text, TextAlign, TextBaseline, view, } from './index.js';
2
+ export type { Shape, ViewConfig } from './index.js';
3
+ //# sourceMappingURL=public.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/canvas/public.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,MAAM,EACN,KAAK,EACL,KAAK,EACL,OAAO,EACP,QAAQ,EACR,MAAM,EACN,MAAM,EACN,IAAI,EACJ,eAAe,EACf,KAAK,EACL,MAAM,EACN,IAAI,EACJ,IAAI,EACJ,SAAS,EACT,YAAY,EACZ,IAAI,GACL,MAAM,YAAY,CAAA;AAEnB,YAAY,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA"}
@@ -0,0 +1 @@
1
+ export { BezierTo, Circle, Close, Group, LineCap, LineJoin, LineTo, MoveTo, Path, PathInstruction, Point, QuadTo, Rect, Text, TextAlign, TextBaseline, view, } from './index.js';
@@ -0,0 +1,188 @@
1
+ import { Schema as S } from 'effect';
2
+ /** A 2D point in canvas-local coordinates. */
3
+ export declare const Point: S.Struct<{
4
+ readonly x: S.Number;
5
+ readonly y: S.Number;
6
+ }>;
7
+ /** A 2D point in canvas-local coordinates. */
8
+ export type Point = typeof Point.Type;
9
+ /** Move the path cursor to a point without drawing. */
10
+ export declare const MoveTo: import("../schema/index.js").CallableTaggedStruct<"MoveTo", {
11
+ x: S.Number;
12
+ y: S.Number;
13
+ }>;
14
+ /** Move the path cursor to a point without drawing. */
15
+ export type MoveTo = typeof MoveTo.Type;
16
+ /** Draw a straight line from the cursor to a point. */
17
+ export declare const LineTo: import("../schema/index.js").CallableTaggedStruct<"LineTo", {
18
+ x: S.Number;
19
+ y: S.Number;
20
+ }>;
21
+ /** Draw a straight line from the cursor to a point. */
22
+ export type LineTo = typeof LineTo.Type;
23
+ /** Draw a quadratic Bezier curve from the cursor through a control point to an end point. */
24
+ export declare const QuadTo: import("../schema/index.js").CallableTaggedStruct<"QuadTo", {
25
+ cpx: S.Number;
26
+ cpy: S.Number;
27
+ x: S.Number;
28
+ y: S.Number;
29
+ }>;
30
+ /** Draw a quadratic Bezier curve from the cursor through a control point to an end point. */
31
+ export type QuadTo = typeof QuadTo.Type;
32
+ /** Draw a cubic Bezier curve from the cursor through two control points to an end point. */
33
+ export declare const BezierTo: import("../schema/index.js").CallableTaggedStruct<"BezierTo", {
34
+ cp1x: S.Number;
35
+ cp1y: S.Number;
36
+ cp2x: S.Number;
37
+ cp2y: S.Number;
38
+ x: S.Number;
39
+ y: S.Number;
40
+ }>;
41
+ /** Draw a cubic Bezier curve from the cursor through two control points to an end point. */
42
+ export type BezierTo = typeof BezierTo.Type;
43
+ /** Close the current path by drawing a line back to its starting point. */
44
+ export declare const Close: import("../schema/index.js").CallableTaggedStruct<"Close", {}>;
45
+ /** Close the current path by drawing a line back to its starting point. */
46
+ export type Close = typeof Close.Type;
47
+ /** A single drawing instruction within a `Path` shape. */
48
+ export declare const PathInstruction: S.Union<readonly [import("../schema/index.js").CallableTaggedStruct<"MoveTo", {
49
+ x: S.Number;
50
+ y: S.Number;
51
+ }>, import("../schema/index.js").CallableTaggedStruct<"LineTo", {
52
+ x: S.Number;
53
+ y: S.Number;
54
+ }>, import("../schema/index.js").CallableTaggedStruct<"QuadTo", {
55
+ cpx: S.Number;
56
+ cpy: S.Number;
57
+ x: S.Number;
58
+ y: S.Number;
59
+ }>, import("../schema/index.js").CallableTaggedStruct<"BezierTo", {
60
+ cp1x: S.Number;
61
+ cp1y: S.Number;
62
+ cp2x: S.Number;
63
+ cp2y: S.Number;
64
+ x: S.Number;
65
+ y: S.Number;
66
+ }>, import("../schema/index.js").CallableTaggedStruct<"Close", {}>]>;
67
+ /** A single drawing instruction within a `Path` shape. */
68
+ export type PathInstruction = typeof PathInstruction.Type;
69
+ /** Stroke cap style: how the ends of an open stroked subpath are rendered. */
70
+ export declare const LineCap: S.Literals<readonly ["Butt", "Round", "Square"]>;
71
+ /** Stroke cap style: how the ends of an open stroked subpath are rendered. */
72
+ export type LineCap = typeof LineCap.Type;
73
+ /** Stroke join style: how two connected stroked segments meet. */
74
+ export declare const LineJoin: S.Literals<readonly ["Miter", "Round", "Bevel"]>;
75
+ /** Stroke join style: how two connected stroked segments meet. */
76
+ export type LineJoin = typeof LineJoin.Type;
77
+ /** Horizontal alignment of a `Text` shape relative to its anchor x coordinate. */
78
+ export declare const TextAlign: S.Literals<readonly ["Left", "Center", "Right", "Start", "End"]>;
79
+ /** Horizontal alignment of a `Text` shape relative to its anchor x coordinate. */
80
+ export type TextAlign = typeof TextAlign.Type;
81
+ /** Vertical alignment of a `Text` shape relative to its anchor y coordinate. */
82
+ export declare const TextBaseline: S.Literals<readonly ["Top", "Middle", "Bottom", "Alphabetic", "Hanging", "Ideographic"]>;
83
+ /** Vertical alignment of a `Text` shape relative to its anchor y coordinate. */
84
+ export type TextBaseline = typeof TextBaseline.Type;
85
+ /** An axis-aligned rectangle. */
86
+ export declare const Rect: import("../schema/index.js").CallableTaggedStruct<"Rect", {
87
+ x: S.Number;
88
+ y: S.Number;
89
+ width: S.Number;
90
+ height: S.Number;
91
+ fill: S.optional<S.String>;
92
+ stroke: S.optional<S.String>;
93
+ lineWidth: S.optional<S.Number>;
94
+ }>;
95
+ /** An axis-aligned rectangle. */
96
+ export type Rect = typeof Rect.Type;
97
+ /** A filled or stroked circle. */
98
+ export declare const Circle: import("../schema/index.js").CallableTaggedStruct<"Circle", {
99
+ x: S.Number;
100
+ y: S.Number;
101
+ radius: S.Number;
102
+ fill: S.optional<S.String>;
103
+ stroke: S.optional<S.String>;
104
+ lineWidth: S.optional<S.Number>;
105
+ }>;
106
+ /** A filled or stroked circle. */
107
+ export type Circle = typeof Circle.Type;
108
+ /** A path built from a sequence of `PathInstruction`s. */
109
+ export declare const Path: import("../schema/index.js").CallableTaggedStruct<"Path", {
110
+ instructions: S.$Array<S.Union<readonly [import("../schema/index.js").CallableTaggedStruct<"MoveTo", {
111
+ x: S.Number;
112
+ y: S.Number;
113
+ }>, import("../schema/index.js").CallableTaggedStruct<"LineTo", {
114
+ x: S.Number;
115
+ y: S.Number;
116
+ }>, import("../schema/index.js").CallableTaggedStruct<"QuadTo", {
117
+ cpx: S.Number;
118
+ cpy: S.Number;
119
+ x: S.Number;
120
+ y: S.Number;
121
+ }>, import("../schema/index.js").CallableTaggedStruct<"BezierTo", {
122
+ cp1x: S.Number;
123
+ cp1y: S.Number;
124
+ cp2x: S.Number;
125
+ cp2y: S.Number;
126
+ x: S.Number;
127
+ y: S.Number;
128
+ }>, import("../schema/index.js").CallableTaggedStruct<"Close", {}>]>>;
129
+ fill: S.optional<S.String>;
130
+ stroke: S.optional<S.String>;
131
+ lineWidth: S.optional<S.Number>;
132
+ lineCap: S.optional<S.Literals<readonly ["Butt", "Round", "Square"]>>;
133
+ lineJoin: S.optional<S.Literals<readonly ["Miter", "Round", "Bevel"]>>;
134
+ }>;
135
+ /** A path built from a sequence of `PathInstruction`s. */
136
+ export type Path = typeof Path.Type;
137
+ /** A single line of text drawn with a font, fill, and optional stroke. */
138
+ export declare const Text: import("../schema/index.js").CallableTaggedStruct<"Text", {
139
+ x: S.Number;
140
+ y: S.Number;
141
+ content: S.String;
142
+ font: S.optional<S.String>;
143
+ fill: S.optional<S.String>;
144
+ stroke: S.optional<S.String>;
145
+ lineWidth: S.optional<S.Number>;
146
+ align: S.optional<S.Literals<readonly ["Left", "Center", "Right", "Start", "End"]>>;
147
+ baseline: S.optional<S.Literals<readonly ["Top", "Middle", "Bottom", "Alphabetic", "Hanging", "Ideographic"]>>;
148
+ }>;
149
+ /** A single line of text drawn with a font, fill, and optional stroke. */
150
+ export type Text = typeof Text.Type;
151
+ /**
152
+ * A scene-graph node that applies a 2D transform and global alpha to a list of
153
+ * child shapes. Transforms compose multiplicatively when groups are nested.
154
+ *
155
+ * Defined via the `interface` form so the recursion (`shapes: ReadonlyArray<Shape>`
156
+ * where `Shape` includes `Group` itself) resolves under TypeScript's lazy
157
+ * interface evaluation. The matching runtime Schema uses `S.suspend`.
158
+ */
159
+ export interface Group extends Readonly<{
160
+ readonly _tag: 'Group';
161
+ readonly shapes: ReadonlyArray<Shape>;
162
+ readonly translate?: Point | undefined;
163
+ readonly rotate?: number | undefined;
164
+ readonly scale?: Point | undefined;
165
+ readonly opacity?: number | undefined;
166
+ }> {
167
+ }
168
+ /**
169
+ * A drawable scene-graph node. Composing `Group` recursively builds a tree;
170
+ * the painter walks the tree depth-first, applying transforms via
171
+ * `ctx.save` / `ctx.restore`.
172
+ */
173
+ export type Shape = typeof Rect.Type | typeof Circle.Type | typeof Path.Type | typeof Text.Type | Group;
174
+ /** Construct a `Group` shape that wraps its children in a transformed scope. */
175
+ export declare const Group: import("../schema/index.js").CallableTaggedStruct<"Group", {
176
+ shapes: S.$Array<S.Schema<Shape>>;
177
+ translate: S.optional<S.Struct<{
178
+ readonly x: S.Number;
179
+ readonly y: S.Number;
180
+ }>>;
181
+ rotate: S.optional<S.Number>;
182
+ scale: S.optional<S.Struct<{
183
+ readonly x: S.Number;
184
+ readonly y: S.Number;
185
+ }>>;
186
+ opacity: S.optional<S.Number>;
187
+ }>;
188
+ //# sourceMappingURL=shape.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shape.d.ts","sourceRoot":"","sources":["../../src/canvas/shape.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,103 @@
1
+ import { Schema as S } from 'effect';
2
+ import { ts } from '../schema/index.js';
3
+ /** A 2D point in canvas-local coordinates. */
4
+ export const Point = S.Struct({ x: S.Number, y: S.Number });
5
+ /** Move the path cursor to a point without drawing. */
6
+ export const MoveTo = ts('MoveTo', { x: S.Number, y: S.Number });
7
+ /** Draw a straight line from the cursor to a point. */
8
+ export const LineTo = ts('LineTo', { x: S.Number, y: S.Number });
9
+ /** Draw a quadratic Bezier curve from the cursor through a control point to an end point. */
10
+ export const QuadTo = ts('QuadTo', {
11
+ cpx: S.Number,
12
+ cpy: S.Number,
13
+ x: S.Number,
14
+ y: S.Number,
15
+ });
16
+ /** Draw a cubic Bezier curve from the cursor through two control points to an end point. */
17
+ export const BezierTo = ts('BezierTo', {
18
+ cp1x: S.Number,
19
+ cp1y: S.Number,
20
+ cp2x: S.Number,
21
+ cp2y: S.Number,
22
+ x: S.Number,
23
+ y: S.Number,
24
+ });
25
+ /** Close the current path by drawing a line back to its starting point. */
26
+ export const Close = ts('Close');
27
+ /** A single drawing instruction within a `Path` shape. */
28
+ export const PathInstruction = S.Union([
29
+ MoveTo,
30
+ LineTo,
31
+ QuadTo,
32
+ BezierTo,
33
+ Close,
34
+ ]);
35
+ /** Stroke cap style: how the ends of an open stroked subpath are rendered. */
36
+ export const LineCap = S.Literals(['Butt', 'Round', 'Square']);
37
+ /** Stroke join style: how two connected stroked segments meet. */
38
+ export const LineJoin = S.Literals(['Miter', 'Round', 'Bevel']);
39
+ /** Horizontal alignment of a `Text` shape relative to its anchor x coordinate. */
40
+ export const TextAlign = S.Literals(['Left', 'Center', 'Right', 'Start', 'End']);
41
+ /** Vertical alignment of a `Text` shape relative to its anchor y coordinate. */
42
+ export const TextBaseline = S.Literals([
43
+ 'Top',
44
+ 'Middle',
45
+ 'Bottom',
46
+ 'Alphabetic',
47
+ 'Hanging',
48
+ 'Ideographic',
49
+ ]);
50
+ /** An axis-aligned rectangle. */
51
+ export const Rect = ts('Rect', {
52
+ x: S.Number,
53
+ y: S.Number,
54
+ width: S.Number,
55
+ height: S.Number,
56
+ fill: S.optional(S.String),
57
+ stroke: S.optional(S.String),
58
+ lineWidth: S.optional(S.Number),
59
+ });
60
+ /** A filled or stroked circle. */
61
+ export const Circle = ts('Circle', {
62
+ x: S.Number,
63
+ y: S.Number,
64
+ radius: S.Number,
65
+ fill: S.optional(S.String),
66
+ stroke: S.optional(S.String),
67
+ lineWidth: S.optional(S.Number),
68
+ });
69
+ /** A path built from a sequence of `PathInstruction`s. */
70
+ export const Path = ts('Path', {
71
+ instructions: S.Array(PathInstruction),
72
+ fill: S.optional(S.String),
73
+ stroke: S.optional(S.String),
74
+ lineWidth: S.optional(S.Number),
75
+ lineCap: S.optional(LineCap),
76
+ lineJoin: S.optional(LineJoin),
77
+ });
78
+ /** A single line of text drawn with a font, fill, and optional stroke. */
79
+ export const Text = ts('Text', {
80
+ x: S.Number,
81
+ y: S.Number,
82
+ content: S.String,
83
+ font: S.optional(S.String),
84
+ fill: S.optional(S.String),
85
+ stroke: S.optional(S.String),
86
+ lineWidth: S.optional(S.Number),
87
+ align: S.optional(TextAlign),
88
+ baseline: S.optional(TextBaseline),
89
+ });
90
+ /**
91
+ * Lazy reference to the full `Shape` union. Used inside `Group`'s `shapes`
92
+ * field so the schema can describe its own children without a forward
93
+ * declaration cycle.
94
+ */
95
+ const Shape = S.suspend(() => S.Union([Rect, Circle, Path, Text, Group]));
96
+ /** Construct a `Group` shape that wraps its children in a transformed scope. */
97
+ export const Group = ts('Group', {
98
+ shapes: S.Array(Shape),
99
+ translate: S.optional(Point),
100
+ rotate: S.optional(S.Number),
101
+ scale: S.optional(Point),
102
+ opacity: S.optional(S.Number),
103
+ });
@@ -0,0 +1,38 @@
1
+ import type { Html } from '../html/index.js';
2
+ import type { Point, Shape } from './shape.js';
3
+ /**
4
+ * Configuration for `Canvas.view`. Pointer handlers are optional and
5
+ * receive a `Point` already translated to the canvas's internal coordinate
6
+ * space (the `width` and `height` passed here), independent of how the
7
+ * canvas is sized in CSS.
8
+ */
9
+ export type ViewConfig<Message> = Readonly<{
10
+ width: number;
11
+ height: number;
12
+ shapes: ReadonlyArray<Shape>;
13
+ className?: string | undefined;
14
+ onPointerDown?: ((point: Point) => Message) | undefined;
15
+ onPointerMove?: ((point: Point) => Message) | undefined;
16
+ onPointerUp?: ((point: Point) => Message) | undefined;
17
+ }>;
18
+ /**
19
+ * A virtual DOM `<canvas>` element backed by a declarative scene description.
20
+ * The insert hook captures the 2D context and paints the initial scene; the
21
+ * postpatch hook re-paints on every render. The canvas is a pure function of
22
+ * `shapes`. Same shapes produce the same pixels.
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * Canvas.view<Message>({
27
+ * width: 400,
28
+ * height: 300,
29
+ * shapes: [
30
+ * Canvas.Rect({ x: 0, y: 0, width: 400, height: 300, fill: '#000' }),
31
+ * Canvas.Circle({ x: 200, y: 150, radius: 50, fill: '#f0a' }),
32
+ * ],
33
+ * onPointerDown: ({ x, y }) => ClickedCanvas({ x, y }),
34
+ * })
35
+ * ```
36
+ */
37
+ export declare const view: <Message>(config: ViewConfig<Message>) => Html;
38
+ //# sourceMappingURL=view.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../../src/canvas/view.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAA;AAG5C,OAAO,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAE9C;;;;;GAKG;AACH,MAAM,MAAM,UAAU,CAAC,OAAO,IAAI,QAAQ,CAAC;IACzC,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,CAAA;IAC5B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC9B,aAAa,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,GAAG,SAAS,CAAA;IACvD,aAAa,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,GAAG,SAAS,CAAA;IACvD,WAAW,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,GAAG,SAAS,CAAA;CACtD,CAAC,CAAA;AA8BF;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,IAAI,GAAI,OAAO,EAAE,QAAQ,UAAU,CAAC,OAAO,CAAC,KAAG,IAyExD,CAAA"}
@@ -0,0 +1,97 @@
1
+ import { Array, Effect, Predicate, Record, String, pipe } from 'effect';
2
+ import { h } from 'snabbdom';
3
+ import { Dispatch } from '../runtime/index.js';
4
+ import { paintScene } from './paint.js';
5
+ /**
6
+ * Per-element 2D context cache. Keyed by the live `<canvas>` element so the
7
+ * postpatch hook reads the same context the insert hook captured. `WeakMap`
8
+ * lets the entry be reclaimed if the element is removed.
9
+ */
10
+ const contextStore = new WeakMap();
11
+ const toCanvasPoint = (canvas, event) => {
12
+ const rect = canvas.getBoundingClientRect();
13
+ const scaleX = rect.width === 0 ? 1 : canvas.width / rect.width;
14
+ const scaleY = rect.height === 0 ? 1 : canvas.height / rect.height;
15
+ return {
16
+ x: (event.clientX - rect.left) * scaleX,
17
+ y: (event.clientY - rect.top) * scaleY,
18
+ };
19
+ };
20
+ const classesFromClassName = (className) => pipe(className, String.split(/\s+/), Array.filter(String.isNonEmpty), Record.fromIterableWith(name => [name, true]));
21
+ /**
22
+ * A virtual DOM `<canvas>` element backed by a declarative scene description.
23
+ * The insert hook captures the 2D context and paints the initial scene; the
24
+ * postpatch hook re-paints on every render. The canvas is a pure function of
25
+ * `shapes`. Same shapes produce the same pixels.
26
+ *
27
+ * @example
28
+ * ```typescript
29
+ * Canvas.view<Message>({
30
+ * width: 400,
31
+ * height: 300,
32
+ * shapes: [
33
+ * Canvas.Rect({ x: 0, y: 0, width: 400, height: 300, fill: '#000' }),
34
+ * Canvas.Circle({ x: 200, y: 150, radius: 50, fill: '#f0a' }),
35
+ * ],
36
+ * onPointerDown: ({ x, y }) => ClickedCanvas({ x, y }),
37
+ * })
38
+ * ```
39
+ */
40
+ export const view = (config) => Effect.gen(function* () {
41
+ const { dispatchSync } = yield* Dispatch;
42
+ const { width, height, shapes, className, onPointerDown, onPointerMove, onPointerUp, } = config;
43
+ const pointerListener = (toMessage) => (event) => {
44
+ const target = event.currentTarget;
45
+ if (target instanceof HTMLCanvasElement) {
46
+ dispatchSync(toMessage(toCanvasPoint(target, event)));
47
+ }
48
+ };
49
+ const listeners = {
50
+ ...(onPointerDown !== undefined && {
51
+ pointerdown: pointerListener(onPointerDown),
52
+ }),
53
+ ...(onPointerMove !== undefined && {
54
+ pointermove: pointerListener(onPointerMove),
55
+ }),
56
+ ...(onPointerUp !== undefined && {
57
+ pointerup: pointerListener(onPointerUp),
58
+ }),
59
+ };
60
+ const data = {
61
+ props: { width, height },
62
+ on: listeners,
63
+ ...(className !== undefined && {
64
+ class: classesFromClassName(className),
65
+ }),
66
+ hook: {
67
+ insert: vnode => {
68
+ if (!(vnode.elm instanceof HTMLCanvasElement)) {
69
+ return;
70
+ }
71
+ const canvas = vnode.elm;
72
+ const nullableContext = canvas.getContext('2d');
73
+ if (Predicate.isNull(nullableContext)) {
74
+ return;
75
+ }
76
+ contextStore.set(canvas, nullableContext);
77
+ paintScene(nullableContext, width, height, shapes);
78
+ },
79
+ postpatch: (_oldVnode, vnode) => {
80
+ if (!(vnode.elm instanceof HTMLCanvasElement)) {
81
+ return;
82
+ }
83
+ const nullableContext = contextStore.get(vnode.elm);
84
+ if (nullableContext === undefined) {
85
+ return;
86
+ }
87
+ paintScene(nullableContext, width, height, shapes);
88
+ },
89
+ destroy: vnode => {
90
+ if (vnode.elm instanceof HTMLCanvasElement) {
91
+ contextStore.delete(vnode.elm);
92
+ }
93
+ },
94
+ },
95
+ };
96
+ return h('canvas', data);
97
+ });
@@ -7,6 +7,7 @@ declare const StoreService_base: Context.ServiceClass<StoreService, "foldkit/Dev
7
7
  recordMessage: (message: Readonly<{
8
8
  _tag: string;
9
9
  }>, modelBeforeUpdate: unknown, modelAfterUpdate: unknown, commands: ReadonlyArray<CommandRecord>, isModelChanged: boolean) => Effect.Effect<void>;
10
+ updateLatestModel: (model: unknown) => Effect.Effect<void>;
10
11
  attachRenderedMounts: (mountStarts: ReadonlyArray<MountRecord>, mountEnds: ReadonlyArray<MountRecord>) => Effect.Effect<void>;
11
12
  getModelAtIndex: (index: number) => Effect.Effect<unknown>;
12
13
  getMessageAtIndex: (index: number) => Effect.Effect<Option.Option<unknown>>;
@@ -1 +1 @@
1
- {"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../../src/devTools/overlay.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,OAAO,EACP,MAAM,EAGN,OAAO,EAGP,MAAM,EAKN,MAAM,IAAI,CAAC,EAGX,eAAe,EAEhB,MAAM,QAAQ,CAAA;AAEf,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAA;AAa9C,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAO3E,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,aAAa,EAElB,KAAK,WAAW,EAChB,KAAK,UAAU,EAChB,MAAM,YAAY,CAAA;;oFAiYJ,CAAC;;;;;;;;;;;;;AAtIhB,cAAM,YAAa,SAAQ,iBAE1B;CAAG;;AAEJ,cAAM,iBAAkB,SAAQ,sBAGC;CAAG;AAEpC,eAAO,MAAM,UAAU;;iBAGsB,CAAA;AAE7C,eAAO,MAAM,YAAY;;iBAGwB,CAAA;AAWjD,eAAO,MAAM,MAAM;;;;wBAUlB,CAAA;AAED,eAAO,MAAM,YAAY;;;;;;;;wBAIqB,CAAA;AAE9C,eAAO,MAAM,aAAa;;;;;;wBAYzB,CAAA;AAED,eAAO,MAAM,MAAM;;wBASlB,CAAA;AAED,eAAO,MAAM,KAAK;;wBASjB,CAAA;AAED,eAAO,MAAM,WAAW;;6BAYvB,CAAA;AA2/CD,eAAO,MAAM,aAAa,GACxB,OAAO,aAAa,EACpB,UAAU,gBAAgB,EAC1B,MAAM,YAAY,EAClB,aAAa,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,sCAoDhC,CAAA"}
1
+ {"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../../src/devTools/overlay.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,OAAO,EACP,MAAM,EAGN,OAAO,EAGP,MAAM,EAKN,MAAM,IAAI,CAAC,EAGX,eAAe,EAEhB,MAAM,QAAQ,CAAA;AAEf,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAA;AAa9C,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAO3E,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,aAAa,EAElB,KAAK,WAAW,EAChB,KAAK,UAAU,EAChB,MAAM,YAAY,CAAA;;oFA8aQ,CAAC;;;;;;;;;;;;;;AAnL5B,cAAM,YAAa,SAAQ,iBAE1B;CAAG;;AAEJ,cAAM,iBAAkB,SAAQ,sBAGC;CAAG;AAEpC,eAAO,MAAM,UAAU;;iBAGsB,CAAA;AAE7C,eAAO,MAAM,YAAY;;iBAGwB,CAAA;AAWjD,eAAO,MAAM,MAAM;;;;wBAUlB,CAAA;AAED,eAAO,MAAM,YAAY;;;;;;;;wBAIqB,CAAA;AAE9C,eAAO,MAAM,aAAa;;;;;;wBAYzB,CAAA;AAED,eAAO,MAAM,MAAM;;wBASlB,CAAA;AAED,eAAO,MAAM,KAAK;;wBASjB,CAAA;AAED,eAAO,MAAM,WAAW;;6BAYvB,CAAA;AA2/CD,eAAO,MAAM,aAAa,GACxB,OAAO,aAAa,EACpB,UAAU,gBAAgB,EAC1B,MAAM,YAAY,EAClB,aAAa,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,sCAoDhC,CAAA"}