tsquare 0.3.1 → 0.3.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 ADDED
@@ -0,0 +1,91 @@
1
+ # Changelog
2
+
3
+ ## 0.3.2
4
+
5
+ - **`grow` on Select**, like Input: `select "State" grow` fills the rest of a row. Sonnet wrote it in 5 of 9 eval runs, its only remaining mistake; with it, every stored Sonnet text output is valid.
6
+ - **Docs:** a new [Embedding](docs/embedding.md) page for Notion, GitHub and your own site, and the Radio page shows radios side by side (`stack row` + `radio`).
7
+ - **Tests and CI:** a test suite (`npm test`), run on Node 20, 22 and 24 for every pull request, plus a check that eval scores, docs and the skill match what's committed.
8
+ - `CHANGELOG.md` is now included in the npm package.
9
+
10
+ ## 0.3.1
11
+
12
+ ### Older wireframes are upgraded in one step
13
+
14
+ - All support for older syntax now lives in one module (`upgradeWireframe`, `upgradeSpec`), run before parsing. The parser, catalog and renderer only know the current language.
15
+ - **Links made before 0.3.0 render again** when a comment follows an element on the same line (`screen phone "Home" # main`): the comment moves onto its own line. Text you write or paste still gets the error, so new comments go on their own line.
16
+ - `decodeWireframe` returns the upgraded text, so a decoded link always means what it did when it was made.
17
+
18
+ ### Better suggestions for unknown icons
19
+
20
+ - Common guesses that aren't Lucide names now suggest what was meant: `compose` → `square-pen`, `call` → `phone`, `person` → `user`, `bag` → `shopping-bag`, `notification` → `bell`, `close` → `x`.
21
+ - Among equally close matches, the usual directions come first: `chevron` suggests `chevron-right, chevron-left, chevron-down, chevron-up`.
22
+ - On a list item, `trailingIcon=chevron` (or `toggle`, `avatar`…) says to write `trailing=chevron`, since that's a kind, not an icon.
23
+
24
+ ## 0.3.0
25
+
26
+ ### Renamed: `icon` is now `leadingIcon` on Button and ListItem
27
+
28
+ Buttons and list items take an icon on either side, so the prop names now say which side:
29
+
30
+ | Before | Now |
31
+ |---|---|
32
+ | `button "Download" icon=download` | `button "Download" leadingIcon=download` |
33
+ | (not possible) | `button "Next" trailingIcon=chevron-right` |
34
+ | `listitem "Inbox" leading=icon icon=inbox` | `listitem "Inbox" leadingIcon=inbox` |
35
+ | `listitem "Delete" trailing=icon trailingIcon=trash-2` | `listitem "Delete" trailingIcon=trash-2` |
36
+
37
+ - **Nothing breaks.** The old `icon=` spelling still works on both components, so existing files and shared render links render the same. `tsquare fmt` rewrites it to `leadingIcon=`. The prompt, the skill and the docs only teach the new names.
38
+ - **Buttons can have a trailing icon**, for Next, external links or dropdowns. Both sides work together.
39
+ - `leading` and `trailing` on ListItem stay as before. They pick what fills each side (`avatar`, `image`, `checkbox`, `chevron`, `badge`, `toggle`, …). An icon or text value implies its kind, so `leading=icon` and `trailing=icon` are optional.
40
+ - `icon` stays as it is on TabBar items (`{label=Home icon=house}`) and on the Icon component.
41
+
42
+ ### Changed: comments go on their own line
43
+
44
+ A line that starts with `#` is a comment. Anywhere else, `#` is ordinary text, so order numbers, tags and hex colors need no quotes:
45
+
46
+ ```tsquare
47
+ # the orders page
48
+ screen desktop "Orders"
49
+ table columns=[Order, Customer] data=[[#1001, Ana Torres], [#1002, Ben Lee]]
50
+ ```
51
+
52
+ - **Why:** comments used to start at any `#` after a space. That cut off `[#1001, Ana Torres]` and broke the table, which happened to Sonnet in 3 of 4 eval runs. Across 160 eval outputs, models never wrote a comment.
53
+ - **Upgrading:** a comment after an element on the same line (`screen phone "Home" # main`) is now an error that tells you to move it to its own line. Nothing is dropped silently.
54
+
55
+ ### Clearer errors for props on the wrong component
56
+
57
+ When a word or prop belongs to a different component, the error now says which one:
58
+
59
+ ```
60
+ Input: fullWidth is a Button prop, not an Input one; an Input already fills its width (width=… sets a fixed one), so remove it
61
+ Card has no prop "border": border is a Stack prop, not a Card one
62
+ ```
63
+
64
+ A prop or list wrapped onto its own line says where it belongs, instead of "unknown component":
65
+
66
+ ```
67
+ trailing=…: props go on the same line as their component; move it to the end of line 15
68
+ a list must stay on one line; join this to line 6
69
+ ```
70
+
71
+ ### Playground
72
+
73
+ - A CodeMirror editor: highlighting, autocomplete for components, options, props, Lucide icons and accent colors, and problems underlined on their line.
74
+ - Light and dark themes.
75
+ - Zoom and pan, zoom to a single screen, full screen and a resizable split.
76
+ - Copy link: share link, SVG/PNG image links, Markdown and HTML snippets.
77
+ - An examples gallery with thumbnails.
78
+
79
+ ### Library
80
+
81
+ - `encodeWireframe` / `decodeWireframe` for share and render links.
82
+ - `boardLayout()` returns the board size and each screen's position.
83
+
84
+ ### List items: a value implies its kind
85
+
86
+ - `trailingIcon=trash-2` without `trailing=icon` used to render nothing, silently. Now the value implies the kind.
87
+ - A value that contradicts an explicit kind is an error that names the fix, for example: `leadingIcon only shows with leading=icon (this item has leading=avatar); remove one of them`.
88
+
89
+ ### Examples
90
+
91
+ - New: `sign-in`, `dashboard`, `checkout` and `states`.
package/README.md CHANGED
@@ -50,7 +50,7 @@ A wireframe can be embedded anywhere an image works (Notion, GitHub, docs sites)
50
50
  ![Login](https://tsquare.dev/svg/zNYwxDsIwEAT7vGJ…)
51
51
  ```
52
52
 
53
- The playground's **Copy link** menu makes these. The text is compressed into the URL, not encrypted, so anyone with the link can read it; see [privacy](https://tsquare.dev/privacy). `encodeWireframe` and `decodeWireframe` in the library produce and read the same links.
53
+ The playground's **Copy link** menu makes these; [Embedding](docs/embedding.md) has the steps for Notion, GitHub and your own site. The text is compressed into the URL, not encrypted, so anyone with the link can read it; see [privacy](https://tsquare.dev/privacy). `encodeWireframe` and `decodeWireframe` in the library produce and read the same links.
54
54
 
55
55
  ## The language
56
56
 
package/dist/catalog.d.ts CHANGED
@@ -341,6 +341,7 @@ export declare const componentDefinitions: {
341
341
  label: z.ZodOptional<z.ZodNullable<z.ZodString>>;
342
342
  value: z.ZodOptional<z.ZodNullable<z.ZodString>>;
343
343
  placeholder: z.ZodOptional<z.ZodNullable<z.ZodString>>;
344
+ grow: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
344
345
  width: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>>;
345
346
  }, z.core.$strip>;
346
347
  slots: never[];
@@ -864,6 +865,7 @@ export declare const catalog: import("@json-render/core").Catalog<{
864
865
  label: z.ZodOptional<z.ZodNullable<z.ZodString>>;
865
866
  value: z.ZodOptional<z.ZodNullable<z.ZodString>>;
866
867
  placeholder: z.ZodOptional<z.ZodNullable<z.ZodString>>;
868
+ grow: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
867
869
  width: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>>;
868
870
  }, z.core.$strip>;
869
871
  slots: never[];
@@ -433,6 +433,7 @@ var componentDefinitions = {
433
433
  label: o(z.string()),
434
434
  value: o(z.string()),
435
435
  placeholder: o(z.string()),
436
+ grow: o(z.boolean()).describe("Fill the remaining space in a row"),
436
437
  width: o(z.union([z.number(), z.string()])).describe("Fixed width, e.g. 320. Default fills the space.")
437
438
  }),
438
439
  slots: [],
@@ -1053,7 +1054,7 @@ function Input({ element, dir }) {
1053
1054
  }
1054
1055
  function Select({ element, dir }) {
1055
1056
  const p = element.props;
1056
- return /* @__PURE__ */ jsxs(Box, { style: { flexDirection: "column", gap: 6, ...fieldWidth(p.width, dir) }, children: [
1057
+ return /* @__PURE__ */ jsxs(Box, { style: { flexDirection: "column", gap: 6, ...fieldWidth(p.width, dir), ...p.grow ? { flexGrow: 1 } : {} }, children: [
1057
1058
  /* @__PURE__ */ jsx(FieldLabel, { text: p.label }),
1058
1059
  /* @__PURE__ */ jsxs(Field, { children: [
1059
1060
  /* @__PURE__ */ jsx(Box, { style: { flexGrow: 1, color: p.value ? theme.ink : theme.muted }, children: p.value ?? p.placeholder ?? "Select\u2026" }),
package/dist/cli.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  printWireframeText,
7
7
  renderWireframe,
8
8
  wireframePrompt
9
- } from "./chunks/chunk-YCIRLKKD.js";
9
+ } from "./chunks/chunk-X46EDSCQ.js";
10
10
 
11
11
  // src/cli.ts
12
12
  import { readFile, writeFile } from "node:fs/promises";
package/dist/index.js CHANGED
@@ -20,7 +20,7 @@ import {
20
20
  upgradeSpec,
21
21
  upgradeWireframe,
22
22
  wireframePrompt
23
- } from "./chunks/chunk-YCIRLKKD.js";
23
+ } from "./chunks/chunk-X46EDSCQ.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-YCIRLKKD.js";
14
+ } from "../chunks/chunk-X46EDSCQ.js";
15
15
 
16
16
  // src/playground/index.ts
17
17
  import { createServer } from "node:http";
@@ -242,18 +242,26 @@ var EXAMPLES = {
242
242
  checkbox "Checked" checked
243
243
  checkbox "Unchecked"`,
244
244
  Radio: `board
245
- screen custom width=300 height=130
245
+ screen custom width=380 height=230
246
246
  radio "Selected" checked
247
247
  radio "Not selected"
248
- radio "Not selected"`,
248
+ radio "Not selected"
249
+ text "Side by side: put them in a row" sm muted
250
+ stack row gap=20
251
+ radio "Standard" checked
252
+ radio "Express"
253
+ radio "Pickup"`,
249
254
  Toggle: `board
250
255
  screen custom width=300 height=100
251
256
  toggle "On" on
252
257
  toggle "Off" off`,
253
258
  Select: `board
254
- screen custom width=320 height=170
259
+ screen custom width=380 height=260
255
260
  select "Country" value="Mexico"
256
- select "Size" placeholder="Choose one" width=160`,
261
+ select "Size" placeholder="Choose one" width=160
262
+ stack row gap=12
263
+ input "City" placeholder="Monterrey" grow
264
+ select "State" value="Nuevo Le\xF3n" grow`,
257
265
  NavBar: `board
258
266
  screen custom width=380 height=240 padding=0 gap=0
259
267
  navbar "leading=menu" leading=menu actions=[search, bell]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tsquare",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
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",
@@ -44,7 +44,8 @@
44
44
  "examples/*.tsq",
45
45
  "assets/mark.png",
46
46
  "LICENSE",
47
- "README.md"
47
+ "README.md",
48
+ "CHANGELOG.md"
48
49
  ],
49
50
  "engines": {
50
51
  "node": ">=20"
@@ -62,7 +63,8 @@
62
63
  "eval:prompts": "tsx eval/prompts.ts",
63
64
  "eval:score": "tsx eval/score.ts",
64
65
  "build": "tsx scripts/build.ts",
65
- "prepare": "npm run build"
66
+ "prepare": "npm run build",
67
+ "test": "tsx --test test/*.test.ts"
66
68
  },
67
69
  "dependencies": {
68
70
  "@fontsource/inter": "5.3.0",
@@ -142,6 +142,7 @@ Dropdown field (closed state).
142
142
  - label: string (main text)
143
143
  - value: string
144
144
  - placeholder: string
145
+ - grow: boolean — Fill the remaining space in a row
145
146
  - width: number | string — Fixed width, e.g. 320. Default fills the space.
146
147
 
147
148
  ### NavBar