tsquare 0.4.0 → 0.4.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.1
4
+
5
+ ```tsquare
6
+ image map height=200 "Pickup" # a map placeholder: roads and a pin, instead of the X
7
+ accordion "How long does shipping take?" open
8
+ text "Orders arrive in 3–5 business days."
9
+ accordion "Can I return an item?" # closed: only the title row
10
+ toast "Message sent" action="Undo" icon=check # pinned to the bottom (above a tab bar), or position=top
11
+ ```
12
+
13
+ - **Toast** is an overlay like Modal and Drawer: a direct child of a Screen, listed last.
14
+ - **Measured:** three new requests (a ride map, an FAQ, a "saved" message), two runs per model. All 12 outputs were valid and used the new pieces, except one Haiku run that drew a plain image labeled "Map". The prompt grew by about 195 tokens.
15
+ - **Breadcrumbs** don't need a component: `text "Home / Settings / Profile" sm muted`. The Text docs page now shows this.
16
+
3
17
  ## 0.4.0
4
18
 
5
19
  ### New components
package/dist/catalog.d.ts CHANGED
@@ -134,6 +134,18 @@ export declare const componentDefinitions: {
134
134
  variant: string;
135
135
  };
136
136
  };
137
+ Accordion: {
138
+ props: z.ZodObject<{
139
+ title: z.ZodOptional<z.ZodNullable<z.ZodString>>;
140
+ open: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
141
+ }, z.core.$strip>;
142
+ slots: string[];
143
+ description: string;
144
+ example: {
145
+ title: string;
146
+ open: boolean;
147
+ };
148
+ };
137
149
  Divider: {
138
150
  props: z.ZodObject<{
139
151
  vertical: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
@@ -214,6 +226,10 @@ export declare const componentDefinitions: {
214
226
  width: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>>;
215
227
  label: z.ZodOptional<z.ZodNullable<z.ZodString>>;
216
228
  rounded: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
229
+ kind: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
230
+ map: "map";
231
+ photo: "photo";
232
+ }>>>;
217
233
  }, z.core.$strip>;
218
234
  slots: never[];
219
235
  description: string;
@@ -590,6 +606,23 @@ export declare const componentDefinitions: {
590
606
  size: number;
591
607
  };
592
608
  };
609
+ Toast: {
610
+ props: z.ZodObject<{
611
+ text: z.ZodOptional<z.ZodNullable<z.ZodString>>;
612
+ action: z.ZodOptional<z.ZodNullable<z.ZodString>>;
613
+ icon: z.ZodOptional<z.ZodNullable<z.ZodString>>;
614
+ position: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
615
+ bottom: "bottom";
616
+ top: "top";
617
+ }>>>;
618
+ }, z.core.$strip>;
619
+ slots: never[];
620
+ description: string;
621
+ example: {
622
+ text: string;
623
+ action: string;
624
+ };
625
+ };
593
626
  };
594
627
  export declare const catalog: import("@json-render/core").Catalog<{
595
628
  spec: import("@json-render/core").SchemaType<"object", {
@@ -754,6 +787,18 @@ export declare const catalog: import("@json-render/core").Catalog<{
754
787
  variant: string;
755
788
  };
756
789
  };
790
+ Accordion: {
791
+ props: z.ZodObject<{
792
+ title: z.ZodOptional<z.ZodNullable<z.ZodString>>;
793
+ open: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
794
+ }, z.core.$strip>;
795
+ slots: string[];
796
+ description: string;
797
+ example: {
798
+ title: string;
799
+ open: boolean;
800
+ };
801
+ };
757
802
  Divider: {
758
803
  props: z.ZodObject<{
759
804
  vertical: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
@@ -834,6 +879,10 @@ export declare const catalog: import("@json-render/core").Catalog<{
834
879
  width: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>>;
835
880
  label: z.ZodOptional<z.ZodNullable<z.ZodString>>;
836
881
  rounded: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
882
+ kind: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
883
+ map: "map";
884
+ photo: "photo";
885
+ }>>>;
837
886
  }, z.core.$strip>;
838
887
  slots: never[];
839
888
  description: string;
@@ -1210,6 +1259,23 @@ export declare const catalog: import("@json-render/core").Catalog<{
1210
1259
  size: number;
1211
1260
  };
1212
1261
  };
1262
+ Toast: {
1263
+ props: z.ZodObject<{
1264
+ text: z.ZodOptional<z.ZodNullable<z.ZodString>>;
1265
+ action: z.ZodOptional<z.ZodNullable<z.ZodString>>;
1266
+ icon: z.ZodOptional<z.ZodNullable<z.ZodString>>;
1267
+ position: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
1268
+ bottom: "bottom";
1269
+ top: "top";
1270
+ }>>>;
1271
+ }, z.core.$strip>;
1272
+ slots: never[];
1273
+ description: string;
1274
+ example: {
1275
+ text: string;
1276
+ action: string;
1277
+ };
1278
+ };
1213
1279
  };
1214
1280
  }>;
1215
1281
  export type ComponentName = keyof typeof componentDefinitions;
@@ -207,7 +207,7 @@ var wireframeSchema = defineSchema(
207
207
  "The root element MUST be a Board. A Board's children are Screens (and optional Notes placed beside them).",
208
208
  "Every Screen MUST be a direct child of the Board. Each Screen is one view of the product; use several Screens to show several views or states.",
209
209
  "Screens lay out their children top to bottom. Use Stack (direction row/column) and Grid inside a Screen to arrange content.",
210
- "Modal and Drawer are overlays. They MUST be direct children of a Screen, and SHOULD be listed last in the Screen's children so they draw on top.",
210
+ "Modal, Drawer and Toast are overlays. They MUST be direct children of a Screen, and SHOULD be listed last in the Screen's children so they draw on top.",
211
211
  "NavBar goes first in a Screen's children and TabBar goes last (before any overlay).",
212
212
  "This is a low-fidelity wireframe: prefer placeholders (Image boxes, Text with lines) over invented copy, unless the copy matters to the design.",
213
213
  'Every element MUST include a "children" array. Leaf elements use an empty array: "children": [].',
@@ -310,6 +310,15 @@ var componentDefinitions = {
310
310
  description: "Bordered container with optional title. Children stack vertically.",
311
311
  example: { title: "Revenue", variant: "outline" }
312
312
  },
313
+ Accordion: {
314
+ props: z.object({
315
+ title: o(z.string()),
316
+ open: o(z.boolean()).describe("Show the children. Default closed: only the title row")
317
+ }),
318
+ slots: ["default"],
319
+ description: "Collapsible section: a title row with a chevron, children below when open. Stack several for an FAQ.",
320
+ example: { title: "Shipping", open: true }
321
+ },
313
322
  Divider: {
314
323
  props: z.object({ vertical: o(z.boolean()) }),
315
324
  slots: [],
@@ -363,10 +372,11 @@ var componentDefinitions = {
363
372
  height: o(z.number()),
364
373
  width: o(z.union([z.number(), z.string()])).describe("Default fills the container width"),
365
374
  label: o(z.string()),
366
- rounded: o(z.boolean())
375
+ rounded: o(z.boolean()),
376
+ kind: o(z.enum(["photo", "map"])).describe("map draws roads and a pin instead of the X")
367
377
  }),
368
378
  slots: [],
369
- description: "Image placeholder: a box with an X through it.",
379
+ description: "Image placeholder: a box with an X through it, or a map.",
370
380
  example: { height: 180, label: "Hero photo" }
371
381
  },
372
382
  Chart: {
@@ -593,6 +603,17 @@ var componentDefinitions = {
593
603
  slots: ["default"],
594
604
  description: "Panel sliding in from an edge: side nav (left), filters/details (right), or bottom sheet. Must be a direct child of a Screen, listed last.",
595
605
  example: { side: "left", title: "Menu", size: 300 }
606
+ },
607
+ Toast: {
608
+ props: z.object({
609
+ text: o(z.string()),
610
+ action: o(z.string()).describe('A text button, e.g. "Undo"'),
611
+ icon: o(iconName),
612
+ position: o(z.enum(["bottom", "top"])).describe("Default bottom, above a TabBar")
613
+ }),
614
+ slots: [],
615
+ description: "Short message over the screen, e.g. after saving. Must be a direct child of a Screen, listed last.",
616
+ example: { text: "Message sent", action: "Undo" }
596
617
  }
597
618
  };
598
619
  var catalog = defineCatalog(wireframeSchema, {
@@ -743,7 +764,7 @@ function Screen({ element, children }) {
743
764
  const type = isValidElement(c) ? c.props.element?.type : null;
744
765
  if (type === "NavBar") top.push(c);
745
766
  else if (type === "TabBar") bottom.push(c);
746
- else if (type === "Modal" || type === "Drawer") overlays.push(c);
767
+ else if (type === "Modal" || type === "Drawer" || type === "Toast") overlays.push(c);
747
768
  else body.push(c);
748
769
  }
749
770
  return /* @__PURE__ */ jsxs(Box, { style: { flexDirection: "column", flexShrink: 0 }, children: [
@@ -782,7 +803,7 @@ function Screen({ element, children }) {
782
803
  }
783
804
  ),
784
805
  bottom,
785
- overlays
806
+ overlays.map((o2) => isValidElement(o2) ? cloneElement(o2, { aboveTabBar: bottom.length > 0 }) : o2)
786
807
  ] })
787
808
  ]
788
809
  }
@@ -885,6 +906,16 @@ function Card({ element, children, dir, stretch }) {
885
906
  }
886
907
  );
887
908
  }
909
+ function Accordion({ element, children }) {
910
+ const p = element.props;
911
+ return /* @__PURE__ */ jsxs(Box, { style: { flexDirection: "column", borderBottom: `1px solid ${theme.line}` }, children: [
912
+ /* @__PURE__ */ jsxs(Box, { style: { alignItems: "center", justifyContent: "space-between", gap: 12, padding: "12px 0" }, children: [
913
+ /* @__PURE__ */ jsx(Box, { style: { fontSize: 15, fontWeight: 600, color: theme.ink }, children: p.title ?? "" }),
914
+ /* @__PURE__ */ jsx(IconGlyph, { name: p.open ? "chevron-up" : "chevron-down", size: 18, color: theme.muted })
915
+ ] }),
916
+ p.open ? /* @__PURE__ */ jsx(Box, { style: { flexDirection: "column", gap: 10, paddingBottom: 14 }, children: withDir(children, "column") }) : null
917
+ ] });
918
+ }
888
919
  function Divider({ element, dir }) {
889
920
  const vertical = element.props.vertical ?? dir === "row";
890
921
  return vertical ? /* @__PURE__ */ jsx(Box, { style: { width: 1, alignSelf: "stretch", backgroundColor: theme.line, flexShrink: 0 } }) : /* @__PURE__ */ jsx(Box, { style: { height: 1, alignSelf: "stretch", backgroundColor: theme.line, flexShrink: 0 } });
@@ -961,6 +992,7 @@ function Bullets({ element }) {
961
992
  ] }, i);
962
993
  }) });
963
994
  }
995
+ var MAP_ROADS = ["M0 42 C30 38 60 50 100 44", "M38 0 C42 30 34 60 44 100", "M0 78 L100 70", "M72 0 L80 100", "M0 16 L40 22", "M44 60 L100 92"];
964
996
  function Image({ element, dir }) {
965
997
  const p = element.props;
966
998
  const h = p.height ?? 160;
@@ -981,7 +1013,12 @@ function Image({ element, dir }) {
981
1013
  justifyContent: "center"
982
1014
  },
983
1015
  children: [
984
- /* @__PURE__ */ jsxs(
1016
+ p.kind === "map" ? /* @__PURE__ */ jsxs("svg", { width: "100%", height: "100%", viewBox: "0 0 100 100", preserveAspectRatio: "none", style: { position: "absolute", top: 0, left: 0 }, children: [
1017
+ /* @__PURE__ */ jsx("rect", { x: "0", y: "0", width: "100", height: "100", fill: theme.fill2 }),
1018
+ /* @__PURE__ */ jsx("rect", { x: "62", y: "8", width: "26", height: "22", fill: theme.fill }),
1019
+ /* @__PURE__ */ jsx("rect", { x: "8", y: "64", width: "20", height: "26", fill: theme.fill }),
1020
+ MAP_ROADS.map((d, i) => /* @__PURE__ */ jsx("path", { d, fill: "none", stroke: theme.paper, strokeWidth: i < 2 ? 7 : 4, vectorEffect: "non-scaling-stroke" }, i))
1021
+ ] }) : /* @__PURE__ */ jsxs(
985
1022
  "svg",
986
1023
  {
987
1024
  width: "100%",
@@ -995,6 +1032,10 @@ function Image({ element, dir }) {
995
1032
  ]
996
1033
  }
997
1034
  ),
1035
+ p.kind === "map" ? /* @__PURE__ */ jsx(Box, { style: { position: "absolute", left: 0, right: 0, top: 0, bottom: 0, alignItems: "center", justifyContent: "center", paddingBottom: 28 }, children: /* @__PURE__ */ jsxs("svg", { width: "28", height: "36", viewBox: "0 0 24 31", children: [
1036
+ /* @__PURE__ */ jsx("path", { d: "M12 1C6.5 1 2 5.3 2 10.7 2 18 12 30 12 30s10-12 10-19.3C22 5.3 17.5 1 12 1z", fill: theme.ink }),
1037
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "10.5", r: "3.6", fill: theme.paper })
1038
+ ] }) }) : null,
998
1039
  p.label ? /* @__PURE__ */ jsx(
999
1040
  Box,
1000
1041
  {
@@ -1003,7 +1044,9 @@ function Image({ element, dir }) {
1003
1044
  fontSize: 12,
1004
1045
  color: theme.muted,
1005
1046
  backgroundColor: theme.fill,
1006
- borderRadius: 4
1047
+ borderRadius: 4,
1048
+ // a map keeps its pin in the middle, so the label goes in the corner
1049
+ ...p.kind === "map" ? { position: "absolute", left: 8, bottom: 8, backgroundColor: theme.paper } : {}
1007
1050
  },
1008
1051
  children: p.label
1009
1052
  }
@@ -1647,6 +1690,15 @@ function Drawer({ element, children }) {
1647
1690
  }
1648
1691
  ) });
1649
1692
  }
1693
+ function Toast({ element, aboveTabBar }) {
1694
+ const p = element.props;
1695
+ const top = p.position === "top";
1696
+ return /* @__PURE__ */ jsx(Box, { style: { position: "absolute", left: 16, right: 16, justifyContent: "center", ...top ? { top: 16 } : { bottom: aboveTabBar ? 92 : 24 } }, children: /* @__PURE__ */ jsxs(Box, { style: { alignItems: "center", gap: 12, padding: "12px 16px", borderRadius: 12, backgroundColor: theme.ink, color: theme.onPrimary, fontSize: 14, boxShadow: "0 6px 20px rgba(0,0,0,0.22)", maxWidth: 420 }, children: [
1697
+ p.icon ? /* @__PURE__ */ jsx(IconGlyph, { name: p.icon, size: 18, color: theme.onPrimary }) : null,
1698
+ /* @__PURE__ */ jsx(Box, { style: { flexShrink: 1 }, children: p.text ?? "" }),
1699
+ p.action ? /* @__PURE__ */ jsx(Box, { style: { fontWeight: 700, marginLeft: 8, flexShrink: 0 }, children: p.action }) : null
1700
+ ] }) });
1701
+ }
1650
1702
  var registry = {
1651
1703
  Board,
1652
1704
  Screen,
@@ -1654,6 +1706,7 @@ var registry = {
1654
1706
  Stack,
1655
1707
  Grid,
1656
1708
  Card,
1709
+ Accordion,
1657
1710
  Divider,
1658
1711
  Spacer,
1659
1712
  Heading,
@@ -1681,7 +1734,8 @@ var registry = {
1681
1734
  ListItem,
1682
1735
  Table,
1683
1736
  Modal,
1684
- Drawer
1737
+ Drawer,
1738
+ Toast
1685
1739
  };
1686
1740
 
1687
1741
  // src/text.ts
@@ -1709,7 +1763,9 @@ var PRIMARY_PROP = {
1709
1763
  NavBar: "title",
1710
1764
  ListItem: "title",
1711
1765
  Modal: "title",
1712
- Drawer: "title"
1766
+ Drawer: "title",
1767
+ Accordion: "title",
1768
+ Toast: "text"
1713
1769
  };
1714
1770
  function unwrap(t) {
1715
1771
  let cur = t;
@@ -2225,7 +2281,7 @@ function checkSpec(spec) {
2225
2281
  if (el.type === "Screen" && !(root.children ?? []).includes(id)) {
2226
2282
  issues.push(`${id}: Screen must be a direct child of the Board`);
2227
2283
  }
2228
- if (el.type === "Modal" || el.type === "Drawer") {
2284
+ if (el.type === "Modal" || el.type === "Drawer" || el.type === "Toast") {
2229
2285
  const parent = Object.entries(spec.elements).find(([, p]) => p.children?.includes(id));
2230
2286
  if (parent && parent[1].type !== "Screen") {
2231
2287
  issues.push(`${id}: ${el.type} must be a direct child of a Screen (found in ${parent[1].type} "${parent[0]}")`);
@@ -2552,7 +2608,7 @@ var RULES = `## Rules
2552
2608
  2. Each Screen is one view of the product. Use several Screens to show several views or states.
2553
2609
  3. A Screen lays out its children top to bottom. Use Stack (direction row or column) and Grid to arrange content.
2554
2610
  4. NavBar is pinned to the top of its Screen and TabBar to the bottom.
2555
- 5. Modal and Drawer are overlays. They must be direct children of a Screen.
2611
+ 5. Modal, Drawer and Toast are overlays. They must be direct children of a Screen.
2556
2612
  6. This is a low-fidelity wireframe. Prefer placeholders (Image boxes, Text with lines) over invented copy unless the copy matters.
2557
2613
  7. Only use the components and props listed below. All props are optional unless marked required.
2558
2614
  8. Wireframes are grayscale. The only UI colors: Board accent (one color for primary buttons, checked controls, toggles, active tabs and ghost buttons), Badge tone (success, warning, danger) and Input error. Only add an accent if the request asks for color or a brand.`;
package/dist/cli.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  printWireframeText,
7
7
  renderWireframe,
8
8
  wireframePrompt
9
- } from "./chunks/chunk-2IDCJVKK.js";
9
+ } from "./chunks/chunk-QLIHML44.js";
10
10
 
11
11
  // src/cli.ts
12
12
  import { readFile, writeFile } from "node:fs/promises";
@@ -28,6 +28,7 @@ declare function Note({ element, dir, aligned }: Props): React.JSX.Element;
28
28
  declare function Stack({ element, children, dir: parentDir, stretch }: Props): React.JSX.Element;
29
29
  declare function Grid({ element, children }: Props): React.JSX.Element;
30
30
  declare function Card({ element, children, dir, stretch }: Props): React.JSX.Element;
31
+ declare function Accordion({ element, children }: Props): React.JSX.Element;
31
32
  declare function Divider({ element, dir }: Props): React.JSX.Element;
32
33
  declare function Spacer({ element }: Props): React.JSX.Element;
33
34
  declare function Heading({ element }: Props): React.JSX.Element;
@@ -63,6 +64,9 @@ declare function ListItem({ element, colors }: Props): React.JSX.Element;
63
64
  declare function Table({ element }: Props): React.JSX.Element;
64
65
  declare function Modal({ element, children }: Props): React.JSX.Element;
65
66
  declare function Drawer({ element, children }: Props): React.JSX.Element;
67
+ declare function Toast({ element, aboveTabBar }: Props & {
68
+ aboveTabBar?: boolean;
69
+ }): React.JSX.Element;
66
70
  export declare const registry: {
67
71
  Board: typeof Board;
68
72
  Screen: typeof Screen;
@@ -70,6 +74,7 @@ export declare const registry: {
70
74
  Stack: typeof Stack;
71
75
  Grid: typeof Grid;
72
76
  Card: typeof Card;
77
+ Accordion: typeof Accordion;
73
78
  Divider: typeof Divider;
74
79
  Spacer: typeof Spacer;
75
80
  Heading: typeof Heading;
@@ -98,5 +103,6 @@ export declare const registry: {
98
103
  Table: typeof Table;
99
104
  Modal: typeof Modal;
100
105
  Drawer: typeof Drawer;
106
+ Toast: typeof Toast;
101
107
  };
102
108
  export {};
package/dist/index.js CHANGED
@@ -20,7 +20,7 @@ import {
20
20
  upgradeSpec,
21
21
  upgradeWireframe,
22
22
  wireframePrompt
23
- } from "./chunks/chunk-2IDCJVKK.js";
23
+ } from "./chunks/chunk-QLIHML44.js";
24
24
 
25
25
  // src/share.ts
26
26
  import { deflateRawSync, inflateRawSync } from "node:zlib";
@@ -11,7 +11,7 @@ import {
11
11
  renderWireframePng,
12
12
  renderWireframeSvg,
13
13
  wireframePrompt
14
- } from "../chunks/chunk-2IDCJVKK.js";
14
+ } from "../chunks/chunk-QLIHML44.js";
15
15
 
16
16
  // src/playground/index.ts
17
17
  import { createServer } from "node:http";
@@ -73,11 +73,11 @@ function languageData() {
73
73
  // src/playground/reference.ts
74
74
  var GROUPS = [
75
75
  { name: "Canvas", components: ["Board", "Screen", "Note"] },
76
- { name: "Layout", components: ["Stack", "Grid", "Card", "Divider", "Spacer"] },
76
+ { name: "Layout", components: ["Stack", "Grid", "Card", "Accordion", "Divider", "Spacer"] },
77
77
  { name: "Content", components: ["Heading", "Text", "Bullets", "Image", "Chart", "Icon", "Avatar", "Badge"] },
78
78
  { name: "Controls", components: ["Button", "Input", "Checkbox", "Radio", "Toggle", "Select", "Slider", "Progress", "Calendar"] },
79
79
  { name: "Navigation & data", components: ["NavBar", "TabBar", "Tabs", "Pagination", "List", "ListItem", "Table"] },
80
- { name: "Overlays", components: ["Modal", "Drawer"] }
80
+ { name: "Overlays", components: ["Modal", "Drawer", "Toast"] }
81
81
  ];
82
82
  var EXAMPLES = {
83
83
  Board: `board row "Checkout flow" gap=48 accent=blue
@@ -149,6 +149,14 @@ var EXAMPLES = {
149
149
  text lines=3
150
150
  card "filled" variant=filled grow
151
151
  text lines=3`,
152
+ Accordion: `board
153
+ screen custom width=380 height=330 gap=0
154
+ heading "FAQ" level=3
155
+ accordion "How long does shipping take?" open
156
+ text "Orders arrive in 3\u20135 business days." muted
157
+ accordion "Can I return an item?"
158
+ accordion "Do you ship internationally?"
159
+ accordion "How do I track my order?"`,
152
160
  Divider: `board
153
161
  screen custom width=360 height=150
154
162
  text "Above"
@@ -172,13 +180,15 @@ var EXAMPLES = {
172
180
  heading "Level 3" level=3
173
181
  heading "Centered" level=3 align=center`,
174
182
  Text: `board
175
- screen custom width=360 height=300
183
+ screen custom width=360 height=370
176
184
  text "Body text, default size"
177
185
  text lg "Large"
178
186
  text sm "Small and muted" muted
179
187
  text "Bold" bold
180
188
  text "Placeholder lines when lines is set and there's no text:" sm muted
181
- text lines=3`,
189
+ text lines=3
190
+ text "Breadcrumbs are small muted text:" sm muted
191
+ text "Home / Settings / Profile" sm muted`,
182
192
  Bullets: `board
183
193
  screen custom width=420 height=600
184
194
  text "Bullets" bold
@@ -190,12 +200,13 @@ var EXAMPLES = {
190
200
  text "One item can change its icon, or be muted" bold
191
201
  bullets icon=check items=[Unlimited boards, Share links, {label="SSO" icon=x muted}]`,
192
202
  Image: `board
193
- screen custom width=480 height=210
203
+ screen custom width=480 height=400
194
204
  stack row gap=12
195
205
  image "label" height=120 width=160
196
206
  image height=120 width=120 rounded
197
207
  image height=120
198
- text "In a row, an image without a width is square." sm muted`,
208
+ text "In a row, an image without a width is square." sm muted
209
+ image map height=150 "Map"`,
199
210
  Chart: `board
200
211
  screen custom width=640 height=430
201
212
  stack row gap=16
@@ -371,7 +382,19 @@ var EXAMPLES = {
371
382
  drawer bottom "Share" size=280
372
383
  list dividers=false
373
384
  listitem "Copy link" leadingIcon=link
374
- listitem "Message" leadingIcon=message-circle`
385
+ listitem "Message" leadingIcon=message-circle`,
386
+ Toast: `board
387
+ screen phone "Bottom, above a tab bar"
388
+ heading "Inbox" level=2
389
+ list
390
+ listitem "Ana Torres" subtitle="Lunch on Friday?" leading=avatar
391
+ listitem "Ben Cho" subtitle="Draft attached" leading=avatar
392
+ tabbar items=[{label=Inbox icon=inbox}, {label=Settings icon=settings}]
393
+ toast "Message sent" action="Undo" icon=check
394
+ screen phone "Top"
395
+ heading "Profile" level=2
396
+ image height=160
397
+ toast "Changes saved" position=top`
375
398
  };
376
399
 
377
400
  // src/playground/index.ts
package/dist/prompt.d.ts CHANGED
@@ -13,7 +13,7 @@ export declare function componentDocs(): {
13
13
  props: PropDoc[];
14
14
  }[];
15
15
  export declare function componentReference(): string;
16
- export declare const RULES = "## Rules\n1. The top element is a Board. The Board's children are Screens, plus optional Notes beside them.\n2. Each Screen is one view of the product. Use several Screens to show several views or states.\n3. A Screen lays out its children top to bottom. Use Stack (direction row or column) and Grid to arrange content.\n4. NavBar is pinned to the top of its Screen and TabBar to the bottom.\n5. Modal and Drawer are overlays. They must be direct children of a Screen.\n6. This is a low-fidelity wireframe. Prefer placeholders (Image boxes, Text with lines) over invented copy unless the copy matters.\n7. Only use the components and props listed below. All props are optional unless marked required.\n8. Wireframes are grayscale. The only UI colors: Board accent (one color for primary buttons, checked controls, toggles, active tabs and ghost buttons), Badge tone (success, warning, danger) and Input error. Only add an accent if the request asks for color or a brand.";
16
+ export declare const RULES = "## Rules\n1. The top element is a Board. The Board's children are Screens, plus optional Notes beside them.\n2. Each Screen is one view of the product. Use several Screens to show several views or states.\n3. A Screen lays out its children top to bottom. Use Stack (direction row or column) and Grid to arrange content.\n4. NavBar is pinned to the top of its Screen and TabBar to the bottom.\n5. Modal, Drawer and Toast are overlays. They must be direct children of a Screen.\n6. This is a low-fidelity wireframe. Prefer placeholders (Image boxes, Text with lines) over invented copy unless the copy matters.\n7. Only use the components and props listed below. All props are optional unless marked required.\n8. Wireframes are grayscale. The only UI colors: Board accent (one color for primary buttons, checked controls, toggles, active tabs and ghost buttons), Badge tone (success, warning, danger) and Input error. Only add an accent if the request asks for color or a brand.";
17
17
  export declare const TEXT_FORMAT = "## Output format: wireframe text\nOne element per line. Indent children two spaces under their parent. The first line is the board.\n\nA line is the component name in lowercase, followed by arguments separated by spaces:\n- \"a quoted string\" sets the component's main text prop (marked \"main text\" below)\n- a bare word that is one of the component's option values sets that option: phone, desktop, primary, ghost, row, sm, left, bottom, password, \u2026\n- a bare prop name sets that component's yes/no prop to true, only on components that have it (see each component's props below): checked (checkbox, radio), fullWidth (button), muted (text), grow (stack, card, input, list). `off` and `unchecked` set on/checked to false\n- key=value sets any prop. Values: \"string\", number, true/false, bare word, [list, of, values], {key=value key=value}\n\nComments: a line that starts with # is a comment. A comment must be on its own line, never after an element on the same line. Anywhere else, # is ordinary text: [#1001, #1002], \"Order #12345\", accent=#1a73e8.\n\nLists: items are separated by commas, and an item can contain spaces without quotes: [All notes, Pinned, Shared]. To put a comma inside an item, quote the item: [\"$1,200\", \"Smith, J\"]. Inside quotes, write \\\" for a quote character. Numbers in a list of text are fine: [2023, 2024].\n\nIf a bare word could mean more than one prop, write it as key=value.";
18
18
  export declare const EXAMPLE_REQUEST = "Two phone screens for a recipe app: a browse screen with search, category tabs, a grid of recipe cards and a tab bar; and a recipe detail screen with its options sheet open.";
19
19
  /** The system prompt for writing wireframe text. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tsquare",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Wireframes in plain text: easy for LLMs to write, fast to render as SVG or PNG.",
5
5
  "keywords": [
6
6
  "wireframe",
@@ -47,7 +47,7 @@ If a bare word could mean more than one prop, write it as key=value.
47
47
  2. Each Screen is one view of the product. Use several Screens to show several views or states.
48
48
  3. A Screen lays out its children top to bottom. Use Stack (direction row or column) and Grid to arrange content.
49
49
  4. NavBar is pinned to the top of its Screen and TabBar to the bottom.
50
- 5. Modal and Drawer are overlays. They must be direct children of a Screen.
50
+ 5. Modal, Drawer and Toast are overlays. They must be direct children of a Screen.
51
51
  6. This is a low-fidelity wireframe. Prefer placeholders (Image boxes, Text with lines) over invented copy unless the copy matters.
52
52
  7. Only use the components and props listed below. All props are optional unless marked required.
53
53
  8. Wireframes are grayscale. The only UI colors: Board accent (one color for primary buttons, checked controls, toggles, active tabs and ghost buttons), Badge tone (success, warning, danger) and Input error. Only add an accent if the request asks for color or a brand.
@@ -55,6 +55,11 @@ Bordered container with optional title. Children stack vertically.
55
55
  - grow: boolean
56
56
  - width: number | string — Fixed width, e.g. 320. Default fills the space.
57
57
 
58
+ ### Accordion
59
+ Collapsible section: a title row with a chevron, children below when open. Stack several for an FAQ.
60
+ - title: string (main text)
61
+ - open: boolean — Show the children. Default closed: only the title row
62
+
58
63
  ### Divider
59
64
  Thin separator line.
60
65
  - vertical: boolean
@@ -85,11 +90,12 @@ Bulleted, numbered or icon list of short lines.
85
90
  - icon: string — A Lucide icon instead of dots, e.g. check for a feature list
86
91
 
87
92
  ### Image
88
- Image placeholder: a box with an X through it.
93
+ Image placeholder: a box with an X through it, or a map.
89
94
  - height: number
90
95
  - width: number | string — Default fills the container width
91
96
  - label: string (main text)
92
97
  - rounded: boolean
98
+ - kind: "photo" | "map" — map draws roads and a pin instead of the X
93
99
 
94
100
  ### Chart
95
101
  Chart placeholder: a generic line, bar, area, pie or donut shape, no data.
@@ -236,3 +242,10 @@ Panel sliding in from an edge: side nav (left), filters/details (right), or bott
236
242
  - size: number — Width for left/right, height for bottom
237
243
  - scrim: boolean — Dim the screen behind. Default true.
238
244
  - handle: boolean — Grab handle on bottom sheets. Default true for bottom.
245
+
246
+ ### Toast
247
+ Short message over the screen, e.g. after saving. Must be a direct child of a Screen, listed last.
248
+ - text: string (main text)
249
+ - action: string — A text button, e.g. "Undo"
250
+ - icon: string — Lucide icon name in kebab-case, e.g. menu, search, arrow-left, settings, bell, user
251
+ - position: "bottom" | "top" — Default bottom, above a TabBar