truecanvas 0.1.0 → 0.3.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.
@@ -85,6 +85,11 @@ interface ImportInfo {
85
85
  source: string;
86
86
  typeOnly: boolean;
87
87
  names: string[];
88
+ /** named value imports, `{ Search as SearchIcon }` → { imported: "Search", local: "SearchIcon" } */
89
+ bindings: {
90
+ imported: string;
91
+ local: string;
92
+ }[];
88
93
  defaultName: string | null;
89
94
  start: number;
90
95
  end: number;
@@ -92,6 +97,8 @@ interface ImportInfo {
92
97
  lastSpecifierEnd: number | null;
93
98
  }
94
99
  interface CanvasDoc {
100
+ /** increases every time a doc is computed: lets clients drop a stale one that arrives late */
101
+ rev?: number;
95
102
  name: string;
96
103
  file: string;
97
104
  frames: CanvasFrame[];
@@ -188,7 +195,11 @@ declare class CanvasEditor {
188
195
  contentStart(n: CanvasNode): number;
189
196
  contentEnd(n: CanvasNode): number;
190
197
  childIndent(parent: CanvasNode): string;
191
- /** Re-indents lines 2..n of a snippet so it sits at `indent`. */
198
+ /**
199
+ * Re-indents lines 2..n of a snippet so it sits at `indent`. Lines that start
200
+ * inside a multi-line string or template literal are content, not code: they
201
+ * are kept exactly as written.
202
+ */
192
203
  shift(code: string, indent: string): string;
193
204
  private openToClose;
194
205
  private insertAt;
@@ -205,6 +216,14 @@ declare class CanvasEditor {
205
216
  replace(node: CanvasNode, jsx: string): void;
206
217
  private added;
207
218
  ensureImport(name: string, from: string): void;
219
+ /**
220
+ * Imports `name` from `from` and returns the local name to write in JSX. When
221
+ * the name is already taken by something else (another import, a local
222
+ * component), it is imported under `alias` instead: `{ Search as SearchIcon }`.
223
+ */
224
+ importAs(name: string, from: string, alias: string): string;
225
+ private importedAs;
226
+ private addImportLine;
208
227
  /** Adds a whole import statement unless every name it binds is already imported. */
209
228
  addImportStatement(statement: string): void;
210
229
  private importsPrepended;
@@ -233,16 +252,23 @@ interface DarkMode {
233
252
  /** Value written for light mode with the attribute strategy. */
234
253
  lightValue?: string;
235
254
  }
255
+ type Framework = "next" | "vite";
236
256
  interface TruecanvasConfig {
237
257
  root: string;
238
- /** Where your Next.js dev server runs. */
258
+ /** The app's framework: Next.js (App Router) or Vite + React. Detected from package.json. */
259
+ framework: Framework;
260
+ /** Where your app's dev server runs. */
239
261
  appUrl: string;
240
262
  /** Port of the Truecanvas editor + MCP server. */
241
263
  port: number;
242
264
  /** Folder holding *.canvas.tsx files. */
243
265
  canvasDir: string;
244
- /** Next.js app directory ("app" or "src/app"). */
266
+ /** Next.js app directory ("app" or "src/app"); for Vite, the source folder. */
245
267
  appDir: string;
268
+ /** Generated, dev-only render route (project-relative, gitignored). */
269
+ routeDir: string;
270
+ /** Vite: stylesheets every frame loads (default: the ones your entry module imports). */
271
+ css?: string[];
246
272
  /** Globs of component files shown in the Components panel. */
247
273
  components: string[];
248
274
  darkMode: DarkMode;
@@ -332,7 +358,7 @@ declare class Comments {
332
358
 
333
359
  interface GitFile {
334
360
  path: string;
335
- status: "modified" | "added" | "deleted" | "renamed" | "untracked";
361
+ status: "modified" | "added" | "deleted" | "renamed" | "untracked" | "conflicted";
336
362
  staged: boolean;
337
363
  }
338
364
  interface GitStatus {
@@ -410,6 +436,12 @@ declare class Git {
410
436
  publish(name: string, isPrivate: boolean): Promise<string>;
411
437
  /** git reports paths from the repo root; we show them from the project root. */
412
438
  private rel;
439
+ /**
440
+ * The project folder inside the repo ("apps/web/", or "" at the root), as git
441
+ * itself sees it. Asking git instead of comparing file system paths holds up
442
+ * through symlinks (macOS /var → /private/var), junctions and Windows short names.
443
+ */
444
+ private prefix;
413
445
  branches(): Promise<{
414
446
  current: string | null;
415
447
  local: string[];
@@ -463,6 +495,14 @@ type Command = {
463
495
  component: string;
464
496
  props?: Record<string, Literal>;
465
497
  text?: string;
498
+ } | {
499
+ op: "insert_icon";
500
+ canvas: string;
501
+ parent: string;
502
+ index?: number;
503
+ library: string;
504
+ name: string;
505
+ className?: string;
466
506
  } | {
467
507
  op: "replace";
468
508
  canvas: string;
@@ -665,7 +705,8 @@ declare class Workspace {
665
705
  private sources;
666
706
  private undoStacks;
667
707
  private redoStacks;
668
- readonly feed: HistoryEntry[];
708
+ /** Activity across canvases: labels only, never file copies. */
709
+ readonly feed: PublicEntry[];
669
710
  private seq;
670
711
  private queue;
671
712
  private listeners;
@@ -684,8 +725,16 @@ declare class Workspace {
684
725
  relFile(canvas: string): string;
685
726
  read(canvas: string): string;
686
727
  doc(canvas: string): CanvasDoc;
687
- /** A canvas doc with linked frames resolved to their page's layers. */
728
+ /**
729
+ * A canvas doc with linked frames resolved to their page's layers. Resolving
730
+ * reads and parses every linked page and layout, so the result is reused
731
+ * until the canvas source or one of those files changes (checked with stat).
732
+ */
688
733
  docFrom(canvas: string, source: string): CanvasDoc;
734
+ /** a doc computed later reflects the files at least as recently: its rev is higher */
735
+ private revision;
736
+ private docCache;
737
+ private stamp;
689
738
  /** Where a node's code lives: the canvas, or a linked page/layout file. */
690
739
  nodeSource(canvas: string, id: string): {
691
740
  node: CanvasNode;
@@ -735,11 +784,19 @@ declare class Workspace {
735
784
  private routeLinked;
736
785
  /** The page/layout file the command's layers live in, or null for the canvas. */
737
786
  private targetOf;
787
+ /** Applies a command to the file being edited and returns its history label. */
738
788
  private apply;
789
+ /** Edits to layers: props, text, classes, inserting, moving, wrapping. */
790
+ private applyLayerEdit;
791
+ /** Frames: creating, updating, backgrounds, presets, variant grids, main component frames. */
792
+ private applyFrameEdit;
793
+ /** Linked pages: adding a page, exploring a copy, applying it back. */
794
+ private applyPageEdit;
795
+ /** Scroll reveals and text animations. */
796
+ private applyMotionEdit;
797
+ /** New components, from scratch or from selected layers. */
798
+ private applyComponentEdit;
739
799
  private autoImport;
740
- private motion;
741
- /** work resolved (async) in exec before the synchronous apply */
742
- private pending;
743
800
  private cleanCache;
744
801
  isPrettierClean(source: string, file: string): Promise<boolean>;
745
802
  /** Pretty-prints an agent's JSX snippet so it lands in the file readable. */
@@ -747,6 +804,12 @@ declare class Workspace {
747
804
  private prettier;
748
805
  format(source: string, file: string): Promise<string>;
749
806
  private record;
807
+ /**
808
+ * Undo entries hold whole files (before and after). Keep their total under a
809
+ * budget by dropping the oldest entries across canvases, so long sessions on
810
+ * big pages don't grow without limit.
811
+ */
812
+ private trimHistory;
750
813
  /** Changes still in effect (not undone) on a canvas since a time, oldest first. */
751
814
  changesSince(canvas: string, since: number): PublicEntry[];
752
815
  historyState(canvas: string): {
@@ -809,7 +872,7 @@ declare const DEVICES: Device[];
809
872
  declare function findDevice(id: string | null | undefined): Device | undefined;
810
873
 
811
874
  /**
812
- * Writes an older version of a canvas next to the generated route so Next can
875
+ * Writes an older version of a canvas next to the generated route so the app can
813
876
  * render it like any canvas ("__compare__<name>"). Relative imports are
814
877
  * rewritten for the new location; alias imports (@/…) work unchanged.
815
878
  */
@@ -817,4 +880,109 @@ declare function writeCompare(config: TruecanvasConfig, canvas: string, source:
817
880
  /** Per frame: same, changed, added (only now) or removed (only before). */
818
881
  declare function frameChanges(before: string, after: string): Record<string, "changed" | "added" | "removed" | "same">;
819
882
 
820
- export { type Actor, type AttrRange, type CanvasDoc, CanvasEditor, type CanvasFrame, type CanvasNode, Catalog, type Command, Comments, type ComponentSpec, DEVICES, type DarkMode, type Device, EditError, type FrameLink, Git, type HistoryEntry, type ImportInfo, type NodeKind, type Preset, type PropSpec, type PropValue, type TruecanvasConfig, Workspace, type WorkspaceEvent, allNodes, attrCode, componentJsx, describeComponent, findDevice, findFrame, findNode, frameChanges, injectIds, loadConfig, outlineDoc, parseCanvas, readDesignTokens, textCode, writeCompare };
883
+ interface IconLibrary {
884
+ id: string;
885
+ label: string;
886
+ /** npm package to install */
887
+ package: string;
888
+ /** module the icons are imported from */
889
+ from: string;
890
+ homepage: string;
891
+ /** keeps one name per icon: drops aliases and non-icon exports */
892
+ pick: (name: string, all: Set<string>) => boolean;
893
+ }
894
+ declare const ICON_LIBRARIES: IconLibrary[];
895
+ declare function iconLibrary(id: string): IconLibrary | undefined;
896
+ interface Icon {
897
+ name: string;
898
+ svg: string;
899
+ }
900
+ /** Every icon of an installed library, from the disk cache or rendered once. */
901
+ declare function loadIcons(root: string, id: string): Promise<Icon[]>;
902
+ /**
903
+ * Ranks icons for a query: exact name, prefix, a near-typo of the whole name,
904
+ * substring; letters-in-order matches only fill in when there are few direct
905
+ * matches, tightest first.
906
+ */
907
+ declare function searchIcons(icons: Icon[], query: string, limit?: number): {
908
+ total: number;
909
+ icons: Icon[];
910
+ };
911
+ /** Which icon libraries are installed, for the picker and agents. */
912
+ declare function iconLibraries(root: string): {
913
+ id: string;
914
+ label: string;
915
+ package: string;
916
+ from: string;
917
+ homepage: string;
918
+ version: string | null;
919
+ }[];
920
+
921
+ interface ShadcnStatus {
922
+ /** components.json exists */
923
+ initialized: boolean;
924
+ /** where components land, relative to the project */
925
+ uiDir: string | null;
926
+ /** components already in the project */
927
+ installed: string[];
928
+ }
929
+ declare function shadcnStatus(root: string): ShadcnStatus;
930
+ /** Component names from the official registry, cached for an hour. */
931
+ declare function shadcnRegistry(): Promise<{
932
+ names: string[];
933
+ offline: boolean;
934
+ }>;
935
+ /** `shadcn init` with the defaults (writes components.json, lib/utils, theme CSS). */
936
+ declare function shadcnInit(root: string): Promise<{
937
+ ok: boolean;
938
+ out: string;
939
+ }>;
940
+ /** `shadcn add <names>`; initializes the project first when needed. */
941
+ declare function shadcnAdd(root: string, names: string[]): Promise<{
942
+ ok: boolean;
943
+ out: string;
944
+ added: string[];
945
+ }>;
946
+
947
+ interface InitReport {
948
+ done: string[];
949
+ todo: string[];
950
+ }
951
+ /** Does the app's next.config / vite.config already enable Truecanvas? */
952
+ declare function configStatus(root: string, framework?: Framework): {
953
+ file: string | null;
954
+ wrapped: boolean;
955
+ framework: Framework;
956
+ };
957
+ /**
958
+ * Sets up a Next.js or Vite project: enables the plugin in its config, adds a
959
+ * `canvas` script and ignores the generated route. Every step is idempotent
960
+ * and reported.
961
+ */
962
+ declare function initProject(config: TruecanvasConfig): InitReport;
963
+ /**
964
+ * Wraps a next.config's export in withTruecanvas(), touching only the exported
965
+ * expression: comments and code after it stay as they are. Null when the
966
+ * export can't be found (the user is told to wrap it by hand).
967
+ */
968
+ declare function wrapConfigExport(src: string): string | null;
969
+ /**
970
+ * Adds `truecanvas()` to a vite.config's plugins array, touching nothing
971
+ * else. Null when there's no plugins array to add it to.
972
+ */
973
+ declare function addVitePlugin(src: string): string | null;
974
+
975
+ /**
976
+ * Generates the dev-only render route `/truecanvas/[canvas]` (Next: an App
977
+ * Router page; Vite: an entry module the plugin serves) and a registry that
978
+ * lazily imports each canvas. Idempotent.
979
+ */
980
+ declare function syncRoute(config: TruecanvasConfig): boolean;
981
+ /**
982
+ * Stylesheets a Vite app loads globally: the ones its entry module (the
983
+ * script in index.html) imports. Root-relative ("/src/index.css"), or the
984
+ * package path for a package's stylesheet.
985
+ */
986
+ declare function viteStylesheets(root: string): string[];
987
+
988
+ export { type Actor, type AttrRange, type CanvasDoc, CanvasEditor, type CanvasFrame, type CanvasNode, Catalog, type Command, Comments, type ComponentSpec, DEVICES, type DarkMode, type Device, EditError, type FrameLink, Git, type HistoryEntry, ICON_LIBRARIES, type Icon, type IconLibrary, type ImportInfo, type NodeKind, type Preset, type PropSpec, type PropValue, type ShadcnStatus, type TruecanvasConfig, Workspace, type WorkspaceEvent, addVitePlugin, allNodes, attrCode, componentJsx, configStatus, describeComponent, findDevice, findFrame, findNode, frameChanges, iconLibraries, iconLibrary, initProject, injectIds, loadConfig, loadIcons, outlineDoc, parseCanvas, readDesignTokens, searchIcons, shadcnAdd, shadcnInit, shadcnRegistry, shadcnStatus, syncRoute, textCode, viteStylesheets, wrapConfigExport, writeCompare };
@@ -5,46 +5,46 @@ import {
5
5
  EditError,
6
6
  Git,
7
7
  Workspace,
8
+ addVitePlugin,
8
9
  allNodes,
9
10
  attrCode,
10
11
  componentJsx,
12
+ configStatus,
11
13
  describeComponent,
12
14
  findDevice,
13
15
  findFrame,
14
16
  findNode,
15
17
  frameChanges,
16
- idOf,
17
- loadConfig,
18
+ initProject,
18
19
  outlineDoc,
19
20
  parseCanvas,
20
- parseModule,
21
21
  readDesignTokens,
22
+ shadcnAdd,
23
+ shadcnInit,
24
+ shadcnRegistry,
25
+ shadcnStatus,
26
+ syncRoute,
22
27
  textCode,
23
- walk,
28
+ viteStylesheets,
29
+ wrapConfigExport,
24
30
  writeCompare
25
- } from "../chunk-WB35FXGP.js";
31
+ } from "../chunk-XWQ5MS24.js";
32
+ import {
33
+ injectIds
34
+ } from "../chunk-TSHD2S36.js";
35
+ import {
36
+ loadConfig
37
+ } from "../chunk-PBKX3SBC.js";
26
38
  import {
27
39
  Catalog
28
- } from "../chunk-753N4QRO.js";
29
-
30
- // src/core/inject.ts
31
- import MagicString from "magic-string";
32
- function injectIds(source, file) {
33
- let ast;
34
- try {
35
- ast = parseModule(source);
36
- } catch {
37
- return source;
38
- }
39
- const s = new MagicString(source);
40
- walk(ast, (node) => {
41
- if (node.type !== "JSXOpeningElement") return;
42
- if (node.attributes.some((a) => a.type === "JSXAttribute" && a.name.name === "data-tc")) return;
43
- const id = file ? `${file}#${idOf(node)}` : idOf(node);
44
- s.appendLeft((node.typeParameters ?? node.name).end, ` data-tc="${id}"`);
45
- });
46
- return s.toString();
47
- }
40
+ } from "../chunk-WU7NBTJH.js";
41
+ import {
42
+ ICON_LIBRARIES,
43
+ iconLibraries,
44
+ iconLibrary,
45
+ loadIcons,
46
+ searchIcons
47
+ } from "../chunk-C4SATRZT.js";
48
48
  export {
49
49
  CanvasEditor,
50
50
  Catalog,
@@ -52,20 +52,35 @@ export {
52
52
  DEVICES,
53
53
  EditError,
54
54
  Git,
55
+ ICON_LIBRARIES,
55
56
  Workspace,
57
+ addVitePlugin,
56
58
  allNodes,
57
59
  attrCode,
58
60
  componentJsx,
61
+ configStatus,
59
62
  describeComponent,
60
63
  findDevice,
61
64
  findFrame,
62
65
  findNode,
63
66
  frameChanges,
67
+ iconLibraries,
68
+ iconLibrary,
69
+ initProject,
64
70
  injectIds,
65
71
  loadConfig,
72
+ loadIcons,
66
73
  outlineDoc,
67
74
  parseCanvas,
68
75
  readDesignTokens,
76
+ searchIcons,
77
+ shadcnAdd,
78
+ shadcnInit,
79
+ shadcnRegistry,
80
+ shadcnStatus,
81
+ syncRoute,
69
82
  textCode,
83
+ viteStylesheets,
84
+ wrapConfigExport,
70
85
  writeCompare
71
86
  };