@pixel-point/toolcraft 0.0.6 → 0.0.8

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 (48) hide show
  1. package/package.json +1 -1
  2. package/src/generate.test.mjs +1 -1
  3. package/templates/runtime/contracts/component-contracts.test.ts +123 -15
  4. package/templates/runtime/contracts/component-contracts.ts +93 -19
  5. package/templates/runtime/contracts/decision-contracts.test.ts +3 -2
  6. package/templates/runtime/contracts/decision-contracts.ts +2 -2
  7. package/templates/runtime/export/export.test.ts +31 -0
  8. package/templates/runtime/export/export.ts +41 -0
  9. package/templates/runtime/react/canvas-shell.test.tsx +77 -1
  10. package/templates/runtime/react/canvas-shell.tsx +178 -23
  11. package/templates/runtime/react/control-conditions.ts +166 -0
  12. package/templates/runtime/react/controls-panel-filedrop-reorder.test.tsx +176 -0
  13. package/templates/runtime/react/controls-panel.test.tsx +590 -9
  14. package/templates/runtime/react/controls-panel.tsx +472 -10
  15. package/templates/runtime/react/media-file.ts +19 -0
  16. package/templates/runtime/schema/define-toolcraft.test.ts +2 -0
  17. package/templates/runtime/schema/define-toolcraft.ts +11 -3
  18. package/templates/runtime/schema/types.ts +27 -0
  19. package/templates/runtime/state/reducer.test.ts +357 -0
  20. package/templates/runtime/state/reducer.ts +195 -9
  21. package/templates/runtime/state/types.ts +12 -2
  22. package/templates/runtime/testing/performance.test.ts +1282 -48
  23. package/templates/runtime/testing/performance.ts +676 -39
  24. package/templates/starter/AGENTS.md +13 -12
  25. package/templates/starter/docs/toolcraft/README.md +4 -3
  26. package/templates/starter/docs/toolcraft/acceptance-testing.md +17 -7
  27. package/templates/starter/docs/toolcraft/assembly-workflow.md +9 -7
  28. package/templates/starter/docs/toolcraft/component-rules.md +20 -7
  29. package/templates/starter/docs/toolcraft/custom-controls.md +9 -5
  30. package/templates/starter/docs/toolcraft/performance.md +51 -13
  31. package/templates/starter/docs/toolcraft/renderer-technique.md +4 -0
  32. package/templates/starter/docs/toolcraft/schema-reference.md +11 -6
  33. package/templates/starter/docs/toolcraft/workflow.md +7 -10
  34. package/templates/starter/e2e/app-performance.spec.ts +136 -3
  35. package/templates/starter/e2e/performance-helpers.ts +197 -0
  36. package/templates/starter/package.json +4 -1
  37. package/templates/starter/src/app/starter-acceptance.test.ts +529 -19
  38. package/templates/starter/src/app/starter-acceptance.ts +269 -12
  39. package/templates/starter/src/app/starter-performance.test.ts +67 -6
  40. package/templates/ui/components/controls/actions/actions-control.tsx +3 -5
  41. package/templates/ui/components/controls/collection-actions/collection-actions-control.tsx +60 -0
  42. package/templates/ui/components/controls/collection-actions/index.ts +4 -0
  43. package/templates/ui/components/controls/file-drop/file-drop-control.tsx +340 -44
  44. package/templates/ui/components/controls/file-drop/index.ts +1 -1
  45. package/templates/ui/components/controls/font-picker/font-picker-control.tsx +1 -6
  46. package/templates/ui/components/controls/index.ts +9 -0
  47. package/templates/ui/components/panel/panel-section.tsx +53 -1
  48. package/templates/ui/index.ts +1 -0
@@ -0,0 +1,176 @@
1
+ import { cleanup, fireEvent, render, screen } from "@testing-library/react";
2
+ import * as React from "react";
3
+ import { afterEach, beforeAll, describe, expect, it, vi } from "vitest";
4
+
5
+ import { defineToolcraft } from "../schema/define-toolcraft";
6
+ import type { FileDropPreview } from "@repo/ui";
7
+ import { ControlsPanel } from "./controls-panel";
8
+ import { ToolcraftRoot } from "./toolcraft-root";
9
+ import { useToolcraft } from "./use-toolcraft";
10
+
11
+ vi.mock("@repo/ui", async (importOriginal) => {
12
+ const actual = await importOriginal<typeof import("@repo/ui")>();
13
+
14
+ return {
15
+ ...actual,
16
+ FileDrop: ({
17
+ assetKind = "image",
18
+ onPreviewReorder,
19
+ previews = [],
20
+ }: {
21
+ assetKind?: "file" | "image";
22
+ onPreviewReorder?: (previews: FileDropPreview[]) => void;
23
+ previews?: readonly FileDropPreview[];
24
+ }) => (
25
+ <button
26
+ onClick={() => {
27
+ onPreviewReorder?.([...previews].reverse());
28
+ }}
29
+ type="button"
30
+ >
31
+ Reorder {assetKind}
32
+ </button>
33
+ ),
34
+ };
35
+ });
36
+
37
+ beforeAll(() => {
38
+ Object.defineProperty(window, "matchMedia", {
39
+ value: (query: string) => ({
40
+ addEventListener: () => undefined,
41
+ addListener: () => undefined,
42
+ dispatchEvent: () => false,
43
+ matches: query === "(prefers-reduced-motion: reduce)",
44
+ media: query,
45
+ onchange: null,
46
+ removeEventListener: () => undefined,
47
+ removeListener: () => undefined,
48
+ }),
49
+ writable: true,
50
+ });
51
+ });
52
+
53
+ afterEach(() => {
54
+ cleanup();
55
+ });
56
+
57
+ function StateProbe() {
58
+ const { state } = useToolcraft();
59
+
60
+ return (
61
+ <span data-testid="media-ids">
62
+ {state.mediaAssets.map((asset) => asset.id).join(",")}
63
+ </span>
64
+ );
65
+ }
66
+
67
+ describe("ControlsPanel fileDrop reorder integration", () => {
68
+ it("commits image and file preview sorting back to runtime media order separately", async () => {
69
+ const schema = defineToolcraft({
70
+ canvas: { enabled: true, upload: true },
71
+ panels: {
72
+ controls: {
73
+ sections: [
74
+ {
75
+ controls: {
76
+ images: {
77
+ label: "Images",
78
+ multiple: true,
79
+ target: "input.images",
80
+ type: "fileDrop",
81
+ },
82
+ files: {
83
+ assetKind: "file",
84
+ label: "Files",
85
+ multiple: true,
86
+ target: "input.files",
87
+ type: "fileDrop",
88
+ },
89
+ },
90
+ title: "Sources",
91
+ },
92
+ ],
93
+ title: "Controls",
94
+ },
95
+ },
96
+ });
97
+
98
+ render(
99
+ <ToolcraftRoot
100
+ initialState={{
101
+ layers: [
102
+ { id: "layer-img-1", kind: "layer", name: "Image 1", visible: true },
103
+ { id: "layer-file-1", kind: "layer", name: "File 1", visible: true },
104
+ { id: "layer-img-2", kind: "layer", name: "Image 2", visible: true },
105
+ { id: "layer-file-2", kind: "layer", name: "File 2", visible: true },
106
+ ],
107
+ mediaAssets: [
108
+ {
109
+ assetKind: "image",
110
+ dataUrl: "data:image/png;base64,aW1nMQ==",
111
+ fileName: "one.png",
112
+ id: "img-1",
113
+ layerId: "layer-img-1",
114
+ mimeType: "image/png",
115
+ position: { x: 0, y: 0 },
116
+ size: { height: 64, unit: "px", width: 64 },
117
+ sourceTarget: "input.images",
118
+ },
119
+ {
120
+ assetKind: "file",
121
+ dataUrl: "data:text/plain;base64,ZmlsZTE=",
122
+ fileName: "one.txt",
123
+ id: "file-1",
124
+ layerId: "layer-file-1",
125
+ mimeType: "text/plain",
126
+ position: { x: 0, y: 0 },
127
+ sourceTarget: "input.files",
128
+ },
129
+ {
130
+ assetKind: "image",
131
+ dataUrl: "data:image/png;base64,aW1nMg==",
132
+ fileName: "two.png",
133
+ id: "img-2",
134
+ layerId: "layer-img-2",
135
+ mimeType: "image/png",
136
+ position: { x: 0, y: 0 },
137
+ size: { height: 64, unit: "px", width: 64 },
138
+ sourceTarget: "input.images",
139
+ },
140
+ {
141
+ assetKind: "file",
142
+ dataUrl: "data:application/json;base64,e30=",
143
+ fileName: "two.json",
144
+ id: "file-2",
145
+ layerId: "layer-file-2",
146
+ mimeType: "application/json",
147
+ position: { x: 0, y: 0 },
148
+ sourceTarget: "input.files",
149
+ },
150
+ ],
151
+ selectedLayerId: "layer-file-2",
152
+ }}
153
+ schema={schema}
154
+ >
155
+ <ControlsPanel framed={false} />
156
+ <StateProbe />
157
+ </ToolcraftRoot>,
158
+ );
159
+
160
+ expect(screen.getByTestId("media-ids").textContent).toBe(
161
+ "img-1,file-1,img-2,file-2",
162
+ );
163
+
164
+ fireEvent.click(screen.getByRole("button", { name: "Reorder image" }));
165
+
166
+ expect(screen.getByTestId("media-ids").textContent).toBe(
167
+ "img-2,file-1,img-1,file-2",
168
+ );
169
+
170
+ fireEvent.click(screen.getByRole("button", { name: "Reorder file" }));
171
+
172
+ expect(screen.getByTestId("media-ids").textContent).toBe(
173
+ "img-2,file-2,img-1,file-1",
174
+ );
175
+ });
176
+ });