tsquare 0.4.0 → 0.4.2
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 +18 -0
- package/dist/catalog.d.ts +74 -0
- package/dist/chunks/{chunk-2IDCJVKK.js → chunk-NREXWHAE.js} +69 -11
- package/dist/cli.js +1 -1
- package/dist/components.d.ts +6 -0
- package/dist/index.js +1 -1
- package/dist/playground/index.js +36 -8
- package/dist/prompt.d.ts +1 -1
- package/package.json +1 -1
- package/skill/tsquare/SKILL.md +1 -1
- package/skill/tsquare/reference.md +14 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.2
|
|
4
|
+
|
|
5
|
+
- **Toast corners:** `position` also takes `topLeft`, `topRight`, `bottomLeft` and `bottomRight`, besides `top` and `bottom` (centered, the default). Desktop apps often show toasts in a corner.
|
|
6
|
+
|
|
7
|
+
## 0.4.1
|
|
8
|
+
|
|
9
|
+
```tsquare
|
|
10
|
+
image map height=200 "Pickup" # a map placeholder: roads and a pin, instead of the X
|
|
11
|
+
accordion "How long does shipping take?" open
|
|
12
|
+
text "Orders arrive in 3–5 business days."
|
|
13
|
+
accordion "Can I return an item?" # closed: only the title row
|
|
14
|
+
toast "Message sent" action="Undo" icon=check # pinned to the bottom (above a tab bar), or position=top
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
- **Toast** is an overlay like Modal and Drawer: a direct child of a Screen, listed last.
|
|
18
|
+
- **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.
|
|
19
|
+
- **Breadcrumbs** don't need a component: `text "Home / Settings / Profile" sm muted`. The Text docs page now shows this.
|
|
20
|
+
|
|
3
21
|
## 0.4.0
|
|
4
22
|
|
|
5
23
|
### 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,27 @@ 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
|
+
bottomLeft: "bottomLeft";
|
|
617
|
+
bottomRight: "bottomRight";
|
|
618
|
+
top: "top";
|
|
619
|
+
topLeft: "topLeft";
|
|
620
|
+
topRight: "topRight";
|
|
621
|
+
}>>>;
|
|
622
|
+
}, z.core.$strip>;
|
|
623
|
+
slots: never[];
|
|
624
|
+
description: string;
|
|
625
|
+
example: {
|
|
626
|
+
text: string;
|
|
627
|
+
action: string;
|
|
628
|
+
};
|
|
629
|
+
};
|
|
593
630
|
};
|
|
594
631
|
export declare const catalog: import("@json-render/core").Catalog<{
|
|
595
632
|
spec: import("@json-render/core").SchemaType<"object", {
|
|
@@ -754,6 +791,18 @@ export declare const catalog: import("@json-render/core").Catalog<{
|
|
|
754
791
|
variant: string;
|
|
755
792
|
};
|
|
756
793
|
};
|
|
794
|
+
Accordion: {
|
|
795
|
+
props: z.ZodObject<{
|
|
796
|
+
title: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
797
|
+
open: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
|
|
798
|
+
}, z.core.$strip>;
|
|
799
|
+
slots: string[];
|
|
800
|
+
description: string;
|
|
801
|
+
example: {
|
|
802
|
+
title: string;
|
|
803
|
+
open: boolean;
|
|
804
|
+
};
|
|
805
|
+
};
|
|
757
806
|
Divider: {
|
|
758
807
|
props: z.ZodObject<{
|
|
759
808
|
vertical: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
|
|
@@ -834,6 +883,10 @@ export declare const catalog: import("@json-render/core").Catalog<{
|
|
|
834
883
|
width: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>>;
|
|
835
884
|
label: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
836
885
|
rounded: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
|
|
886
|
+
kind: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
887
|
+
map: "map";
|
|
888
|
+
photo: "photo";
|
|
889
|
+
}>>>;
|
|
837
890
|
}, z.core.$strip>;
|
|
838
891
|
slots: never[];
|
|
839
892
|
description: string;
|
|
@@ -1210,6 +1263,27 @@ export declare const catalog: import("@json-render/core").Catalog<{
|
|
|
1210
1263
|
size: number;
|
|
1211
1264
|
};
|
|
1212
1265
|
};
|
|
1266
|
+
Toast: {
|
|
1267
|
+
props: z.ZodObject<{
|
|
1268
|
+
text: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
1269
|
+
action: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
1270
|
+
icon: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
1271
|
+
position: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
1272
|
+
bottom: "bottom";
|
|
1273
|
+
bottomLeft: "bottomLeft";
|
|
1274
|
+
bottomRight: "bottomRight";
|
|
1275
|
+
top: "top";
|
|
1276
|
+
topLeft: "topLeft";
|
|
1277
|
+
topRight: "topRight";
|
|
1278
|
+
}>>>;
|
|
1279
|
+
}, z.core.$strip>;
|
|
1280
|
+
slots: never[];
|
|
1281
|
+
description: string;
|
|
1282
|
+
example: {
|
|
1283
|
+
text: string;
|
|
1284
|
+
action: string;
|
|
1285
|
+
};
|
|
1286
|
+
};
|
|
1213
1287
|
};
|
|
1214
1288
|
}>;
|
|
1215
1289
|
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
|
|
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", "topLeft", "topRight", "bottomLeft", "bottomRight"])).describe("Default bottom (centered), 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,17 @@ function Drawer({ element, children }) {
|
|
|
1647
1690
|
}
|
|
1648
1691
|
) });
|
|
1649
1692
|
}
|
|
1693
|
+
function Toast({ element, aboveTabBar }) {
|
|
1694
|
+
const p = element.props;
|
|
1695
|
+
const position = p.position ?? "bottom";
|
|
1696
|
+
const top = position.startsWith("top");
|
|
1697
|
+
const side = position.endsWith("Left") ? "flex-start" : position.endsWith("Right") ? "flex-end" : "center";
|
|
1698
|
+
return /* @__PURE__ */ jsx(Box, { style: { position: "absolute", left: 16, right: 16, justifyContent: side, ...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: [
|
|
1699
|
+
p.icon ? /* @__PURE__ */ jsx(IconGlyph, { name: p.icon, size: 18, color: theme.onPrimary }) : null,
|
|
1700
|
+
/* @__PURE__ */ jsx(Box, { style: { flexShrink: 1 }, children: p.text ?? "" }),
|
|
1701
|
+
p.action ? /* @__PURE__ */ jsx(Box, { style: { fontWeight: 700, marginLeft: 8, flexShrink: 0 }, children: p.action }) : null
|
|
1702
|
+
] }) });
|
|
1703
|
+
}
|
|
1650
1704
|
var registry = {
|
|
1651
1705
|
Board,
|
|
1652
1706
|
Screen,
|
|
@@ -1654,6 +1708,7 @@ var registry = {
|
|
|
1654
1708
|
Stack,
|
|
1655
1709
|
Grid,
|
|
1656
1710
|
Card,
|
|
1711
|
+
Accordion,
|
|
1657
1712
|
Divider,
|
|
1658
1713
|
Spacer,
|
|
1659
1714
|
Heading,
|
|
@@ -1681,7 +1736,8 @@ var registry = {
|
|
|
1681
1736
|
ListItem,
|
|
1682
1737
|
Table,
|
|
1683
1738
|
Modal,
|
|
1684
|
-
Drawer
|
|
1739
|
+
Drawer,
|
|
1740
|
+
Toast
|
|
1685
1741
|
};
|
|
1686
1742
|
|
|
1687
1743
|
// src/text.ts
|
|
@@ -1709,7 +1765,9 @@ var PRIMARY_PROP = {
|
|
|
1709
1765
|
NavBar: "title",
|
|
1710
1766
|
ListItem: "title",
|
|
1711
1767
|
Modal: "title",
|
|
1712
|
-
Drawer: "title"
|
|
1768
|
+
Drawer: "title",
|
|
1769
|
+
Accordion: "title",
|
|
1770
|
+
Toast: "text"
|
|
1713
1771
|
};
|
|
1714
1772
|
function unwrap(t) {
|
|
1715
1773
|
let cur = t;
|
|
@@ -2225,7 +2283,7 @@ function checkSpec(spec) {
|
|
|
2225
2283
|
if (el.type === "Screen" && !(root.children ?? []).includes(id)) {
|
|
2226
2284
|
issues.push(`${id}: Screen must be a direct child of the Board`);
|
|
2227
2285
|
}
|
|
2228
|
-
if (el.type === "Modal" || el.type === "Drawer") {
|
|
2286
|
+
if (el.type === "Modal" || el.type === "Drawer" || el.type === "Toast") {
|
|
2229
2287
|
const parent = Object.entries(spec.elements).find(([, p]) => p.children?.includes(id));
|
|
2230
2288
|
if (parent && parent[1].type !== "Screen") {
|
|
2231
2289
|
issues.push(`${id}: ${el.type} must be a direct child of a Screen (found in ${parent[1].type} "${parent[0]}")`);
|
|
@@ -2552,7 +2610,7 @@ var RULES = `## Rules
|
|
|
2552
2610
|
2. Each Screen is one view of the product. Use several Screens to show several views or states.
|
|
2553
2611
|
3. A Screen lays out its children top to bottom. Use Stack (direction row or column) and Grid to arrange content.
|
|
2554
2612
|
4. NavBar is pinned to the top of its Screen and TabBar to the bottom.
|
|
2555
|
-
5. Modal and
|
|
2613
|
+
5. Modal, Drawer and Toast are overlays. They must be direct children of a Screen.
|
|
2556
2614
|
6. This is a low-fidelity wireframe. Prefer placeholders (Image boxes, Text with lines) over invented copy unless the copy matters.
|
|
2557
2615
|
7. Only use the components and props listed below. All props are optional unless marked required.
|
|
2558
2616
|
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
package/dist/components.d.ts
CHANGED
|
@@ -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
package/dist/playground/index.js
CHANGED
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
renderWireframePng,
|
|
12
12
|
renderWireframeSvg,
|
|
13
13
|
wireframePrompt
|
|
14
|
-
} from "../chunks/chunk-
|
|
14
|
+
} from "../chunks/chunk-NREXWHAE.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=
|
|
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=
|
|
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,24 @@ 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
|
|
398
|
+
screen desktop "Corners: topLeft, topRight, bottomLeft, bottomRight" width=900 height=420
|
|
399
|
+
heading "Dashboard" level=2
|
|
400
|
+
image height=220
|
|
401
|
+
toast "topRight" position=topRight
|
|
402
|
+
toast "bottomLeft" action="Undo" position=bottomLeft`
|
|
375
403
|
};
|
|
376
404
|
|
|
377
405
|
// 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
|
|
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
package/skill/tsquare/SKILL.md
CHANGED
|
@@ -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
|
|
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" | "topLeft" | "topRight" | "bottomLeft" | "bottomRight" — Default bottom (centered), above a TabBar
|