tsquare 0.2.0 → 0.3.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/README.md +20 -6
- package/dist/catalog.d.ts +24 -8
- package/dist/chunks/{chunk-L6GTIZQH.js → chunk-YCIRLKKD.js} +389 -161
- package/dist/cli.js +1 -1
- package/dist/icons.d.ts +2 -3
- package/dist/index.d.ts +3 -1
- package/dist/index.js +24 -1
- package/dist/playground/index.d.ts +12 -1
- package/dist/playground/index.html +180 -356
- package/dist/playground/index.js +100 -10
- package/dist/playground/language-data.d.ts +28 -0
- package/dist/playground/playground.js +50 -0
- package/dist/prompt.d.ts +1 -1
- package/dist/render.d.ts +21 -1
- package/dist/share.d.ts +8 -0
- package/dist/text.d.ts +6 -1
- package/dist/upgrade.d.ts +41 -0
- package/examples/checkout.tsq +15 -0
- package/examples/dashboard.tsq +27 -0
- package/examples/notes-mobile.tsq +9 -9
- package/examples/notes-web.tsq +6 -6
- package/examples/sign-in.tsq +14 -0
- package/examples/states.tsq +16 -0
- package/package.json +9 -1
- package/skill/tsquare/SKILL.md +3 -2
- package/skill/tsquare/reference.md +5 -4
package/dist/prompt.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export declare function componentDocs(): {
|
|
|
14
14
|
}[];
|
|
15
15
|
export declare function componentReference(): string;
|
|
16
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.";
|
|
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
|
|
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. */
|
|
20
20
|
export declare function wireframePrompt(): string;
|
package/dist/render.d.ts
CHANGED
|
@@ -5,7 +5,27 @@ export declare class SpecError extends Error {
|
|
|
5
5
|
}
|
|
6
6
|
/** Catalog validation plus the structural rules the renderer depends on. */
|
|
7
7
|
export declare function checkSpec(spec: Spec): string[];
|
|
8
|
-
|
|
8
|
+
export interface BoardItem {
|
|
9
|
+
type: "Screen" | "Note";
|
|
10
|
+
/** Screen name or note text, for labels in tools like the playground. */
|
|
11
|
+
name: string;
|
|
12
|
+
/** Box on the board in px, including the screen's name label above its frame. */
|
|
13
|
+
x: number;
|
|
14
|
+
y: number;
|
|
15
|
+
width: number;
|
|
16
|
+
height: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Where everything sits on the board: the canvas size (Satori needs it up
|
|
20
|
+
* front) and each screen's and note's box, laid out in rows exactly as the
|
|
21
|
+
* Board component does.
|
|
22
|
+
*/
|
|
23
|
+
export declare function boardLayout(spec: Spec): {
|
|
24
|
+
width: number;
|
|
25
|
+
height: number;
|
|
26
|
+
items: BoardItem[];
|
|
27
|
+
};
|
|
28
|
+
/** The canvas size for a board. */
|
|
9
29
|
export declare function boardSize(spec: Spec): {
|
|
10
30
|
width: number;
|
|
11
31
|
height: number;
|
package/dist/share.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Largest decoded text accepted, in bytes. Plenty for a board; stops a tiny URL from inflating into megabytes. */
|
|
2
|
+
export declare const MAX_SHARED_TEXT = 64000;
|
|
3
|
+
export declare function encodeWireframe(text: string): string;
|
|
4
|
+
/**
|
|
5
|
+
* The wireframe a link carries, upgraded to the current language: a link made
|
|
6
|
+
* by an older version means today what it meant then (see upgrade.ts).
|
|
7
|
+
*/
|
|
8
|
+
export declare function decodeWireframe(data: string): string;
|
package/dist/text.d.ts
CHANGED
|
@@ -17,11 +17,16 @@
|
|
|
17
17
|
* key=value → any prop; value is "string", number, true/false, word, [list] or {key=value …}
|
|
18
18
|
* list items are separated by commas only, so [Ana Torres, Admin] is two items;
|
|
19
19
|
* quote an item that contains a comma: ["$1,200", "Smith, J"]
|
|
20
|
-
* # comment
|
|
20
|
+
* # comment → only on a line of its own; anywhere else # is text ([#1001, …], accent=#1a73e8)
|
|
21
21
|
*/
|
|
22
22
|
import type { Spec } from "@json-render/core";
|
|
23
23
|
/** Which prop a quoted string fills, per component. */
|
|
24
24
|
export declare const PRIMARY_PROP: Record<string, string>;
|
|
25
|
+
/**
|
|
26
|
+
* For an error message: where a prop name or bare word that this component doesn't take
|
|
27
|
+
* belongs instead, e.g. fullWidth on an input → "fullWidth is a Button prop". Empty if nowhere.
|
|
28
|
+
*/
|
|
29
|
+
export declare function belongsElsewhere(component: string, word: string, asProp: boolean): string;
|
|
25
30
|
/** What a component accepts as bare words, for docs: option values (with their prop), ambiguous values, and boolean props. */
|
|
26
31
|
export declare function bareWords(component: string): {
|
|
27
32
|
options: {
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Everything tsquare does for wireframes written in an older version of the
|
|
3
|
+
* language, kept in one place so the parser, catalog and renderer only know
|
|
4
|
+
* the current language.
|
|
5
|
+
*
|
|
6
|
+
* upgradeWireframe(text) always-safe rewrites (renamed props);
|
|
7
|
+
* compileWireframe runs it first
|
|
8
|
+
* upgradeWireframe(text, { fromLink: true }) also the rules for text that came
|
|
9
|
+
* from a link made by an older version;
|
|
10
|
+
* decodeWireframe runs it
|
|
11
|
+
* upgradeSpec(spec) the renames, for JSON specs
|
|
12
|
+
*
|
|
13
|
+
* Rewrites keep every line where it was (except moving a comment onto its own
|
|
14
|
+
* line, which only happens for links), so problems still point at the right line.
|
|
15
|
+
*
|
|
16
|
+
* Adding an upgrade: a rename goes in RENAMED_PROPS. A change in meaning goes
|
|
17
|
+
* here only if old text can be recognised without guessing; otherwise new links
|
|
18
|
+
* get a new prefix letter in share.ts and the upgrade applies to the old letter.
|
|
19
|
+
*/
|
|
20
|
+
/** Props renamed in 0.3.0. The prompt, docs and autocomplete only teach the new names; `tsquare fmt` rewrites old ones. */
|
|
21
|
+
export declare const RENAMED_PROPS: Record<string, Record<string, string>>;
|
|
22
|
+
export interface UpgradeOptions {
|
|
23
|
+
/** The text came from a link (share link or render URL), which may predate 0.3.0. */
|
|
24
|
+
fromLink?: boolean;
|
|
25
|
+
}
|
|
26
|
+
/** Rewrites older syntax to the current language. Text that's already current comes back unchanged. */
|
|
27
|
+
export declare function upgradeWireframe(text: string, options?: UpgradeOptions): string;
|
|
28
|
+
/** The renames, for a JSON spec. In place; safe to call more than once. */
|
|
29
|
+
export declare function upgradeSpec<S extends {
|
|
30
|
+
elements: Record<string, {
|
|
31
|
+
type: string;
|
|
32
|
+
props?: Record<string, unknown>;
|
|
33
|
+
}>;
|
|
34
|
+
}>(spec: S): S;
|
|
35
|
+
/**
|
|
36
|
+
* Components whose main text may be a plain word (`avatar JD`, `icon search`), the parser's
|
|
37
|
+
* WORD_PRIMARY. Neither has option words, so their first plain word is always the main text.
|
|
38
|
+
* Kept here rather than imported, so the playground's browser bundle doesn't pull in the parser
|
|
39
|
+
* and catalog; scripts/build.ts fails if this drifts from the parser.
|
|
40
|
+
*/
|
|
41
|
+
export declare const PLAIN_WORD_MAIN_TEXT: string[];
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
board row "Checkout" accent=green
|
|
2
|
+
screen phone "Cart"
|
|
3
|
+
navbar "Cart" leading=back
|
|
4
|
+
list
|
|
5
|
+
listitem "Oat latte" subtitle="Large, extra shot" leading=image trailing=text trailingText="$5.40"
|
|
6
|
+
listitem "Croissant" subtitle="Warm" leading=image trailing=text trailingText="$3.20"
|
|
7
|
+
spacer
|
|
8
|
+
button primary lg "Checkout · $8.60" fullWidth
|
|
9
|
+
screen phone "Pay"
|
|
10
|
+
navbar "Cart" leading=back
|
|
11
|
+
text lines=4
|
|
12
|
+
drawer bottom "Payment" size=300
|
|
13
|
+
select "Card" value="Visa ending 6411"
|
|
14
|
+
toggle "Save card" on
|
|
15
|
+
button primary lg "Pay $8.60" fullWidth
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
board "Analytics" accent=blue
|
|
2
|
+
screen desktop "Dashboard" padding=0 height=640
|
|
3
|
+
stack row grow
|
|
4
|
+
stack width=220 border=right fill padding=16 gap=6
|
|
5
|
+
text "Acme" bold
|
|
6
|
+
list dividers=false
|
|
7
|
+
listitem "Overview" leadingIcon=layout-grid
|
|
8
|
+
listitem "Customers" leadingIcon=users
|
|
9
|
+
listitem "Orders" leadingIcon=receipt
|
|
10
|
+
listitem "Settings" leadingIcon=settings
|
|
11
|
+
stack grow padding=24 gap=20
|
|
12
|
+
stack row justify=between align=center
|
|
13
|
+
heading "Overview" level=2
|
|
14
|
+
stack row gap=8
|
|
15
|
+
input search placeholder="Search" width=220
|
|
16
|
+
button primary "Export" leadingIcon=download
|
|
17
|
+
avatar "DM"
|
|
18
|
+
grid columns=4 gap=12
|
|
19
|
+
card "Revenue"
|
|
20
|
+
heading "$48.2k" level=2
|
|
21
|
+
card "Orders"
|
|
22
|
+
heading "1,284" level=2
|
|
23
|
+
card "Customers"
|
|
24
|
+
heading "932" level=2
|
|
25
|
+
card "Refunds"
|
|
26
|
+
heading "12" level=2
|
|
27
|
+
table columns=[Order, Customer, Status, Total] data=[["#1042", Ana Torres, Paid, "$120"], ["#1041", Ben Cho, Pending, "$80"], ["#1040", Priya Nair, Paid, "$45"]]
|
|
@@ -16,7 +16,7 @@ board row "Notes app — mobile"
|
|
|
16
16
|
text sm "or" muted
|
|
17
17
|
stack grow
|
|
18
18
|
divider
|
|
19
|
-
button secondary lg "Continue with Google" fullWidth
|
|
19
|
+
button secondary lg "Continue with Google" fullWidth leadingIcon=globe
|
|
20
20
|
spacer
|
|
21
21
|
text sm "New here? Create an account" align=center muted
|
|
22
22
|
screen phone "2 · Notes"
|
|
@@ -24,13 +24,13 @@ board row "Notes app — mobile"
|
|
|
24
24
|
input search placeholder="Search notes"
|
|
25
25
|
tabs items=[All, Pinned, Shared] active=0
|
|
26
26
|
list
|
|
27
|
-
listitem "Grocery list" subtitle="Eggs, oat milk, basil…"
|
|
28
|
-
listitem "Trip ideas" subtitle="Lisbon in October?"
|
|
27
|
+
listitem "Grocery list" subtitle="Eggs, oat milk, basil…" leadingIcon=shopping-cart trailing=text trailingText="9:12"
|
|
28
|
+
listitem "Trip ideas" subtitle="Lisbon in October?" leadingIcon=map trailing=badge trailingText="2"
|
|
29
29
|
listitem leading=image trailing=chevron
|
|
30
30
|
listitem leading=image trailing=chevron
|
|
31
31
|
listitem leading=image trailing=chevron
|
|
32
32
|
stack row justify=end grow align=end
|
|
33
|
-
button primary "New note"
|
|
33
|
+
button primary "New note" leadingIcon=plus
|
|
34
34
|
tabbar items=[{label=Notes icon=notebook-pen}, {label=Search icon=search}, {label=Shared icon=users}, {label=Profile icon=user}] active=0
|
|
35
35
|
screen phone "3 · Side menu (drawer)"
|
|
36
36
|
navbar "Notes" leading=menu actions=[bell, more-vertical]
|
|
@@ -49,12 +49,12 @@ board row "Notes app — mobile"
|
|
|
49
49
|
text sm "dana@example.com" muted
|
|
50
50
|
divider
|
|
51
51
|
list dividers=false
|
|
52
|
-
listitem "All notes"
|
|
53
|
-
listitem "Folders"
|
|
54
|
-
listitem "Archive"
|
|
55
|
-
listitem "Settings"
|
|
52
|
+
listitem "All notes" leadingIcon=notebook-pen trailing=text trailingText="24"
|
|
53
|
+
listitem "Folders" leadingIcon=folder trailing=chevron
|
|
54
|
+
listitem "Archive" leadingIcon=archive
|
|
55
|
+
listitem "Settings" leadingIcon=settings
|
|
56
56
|
spacer
|
|
57
|
-
button secondary "Sign out"
|
|
57
|
+
button secondary "Sign out" leadingIcon=log-out fullWidth
|
|
58
58
|
screen phone "4 · Discard draft (modal)"
|
|
59
59
|
navbar "New note" leading=close actions=[image, check] align=center
|
|
60
60
|
heading "Untitled" level=2
|
package/examples/notes-web.tsq
CHANGED
|
@@ -7,10 +7,10 @@ board "Notes app — web"
|
|
|
7
7
|
text "Notebook" bold
|
|
8
8
|
spacer size=12
|
|
9
9
|
list dividers=false
|
|
10
|
-
listitem "Overview"
|
|
11
|
-
listitem "All notes"
|
|
12
|
-
listitem "Shared"
|
|
13
|
-
listitem "Settings"
|
|
10
|
+
listitem "Overview" leadingIcon=layout-dashboard
|
|
11
|
+
listitem "All notes" leadingIcon=notebook-pen trailing=text trailingText="128"
|
|
12
|
+
listitem "Shared" leadingIcon=users
|
|
13
|
+
listitem "Settings" leadingIcon=settings
|
|
14
14
|
spacer
|
|
15
15
|
stack row gap=10
|
|
16
16
|
avatar "DM" size=32
|
|
@@ -21,7 +21,7 @@ board "Notes app — web"
|
|
|
21
21
|
spacer
|
|
22
22
|
stack width=260
|
|
23
23
|
input search placeholder=Search
|
|
24
|
-
button "New note"
|
|
24
|
+
button "New note" leadingIcon=plus
|
|
25
25
|
grid columns=3 gap=20
|
|
26
26
|
card "Notes this week"
|
|
27
27
|
heading "42" level=1
|
|
@@ -38,7 +38,7 @@ board "Notes app — web"
|
|
|
38
38
|
stack row gap=12
|
|
39
39
|
heading "All notes" level=1
|
|
40
40
|
spacer
|
|
41
|
-
button secondary "Filters"
|
|
41
|
+
button secondary "Filters" leadingIcon=sliders-horizontal
|
|
42
42
|
table columns=[Title, Folder, Owner, Updated] rows=9
|
|
43
43
|
drawer right "Filters" size=340
|
|
44
44
|
select "Folder" placeholder="Any folder"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
board "Sign in"
|
|
2
|
+
screen phone "Sign in" padding=28 gap=16
|
|
3
|
+
spacer size=24
|
|
4
|
+
heading "Welcome back" level=1
|
|
5
|
+
text "Sign in to sync your notes." muted
|
|
6
|
+
input email "Email" placeholder="you@example.com"
|
|
7
|
+
input password "Password"
|
|
8
|
+
stack row justify=between
|
|
9
|
+
checkbox "Remember me" checked
|
|
10
|
+
button ghost sm "Forgot?"
|
|
11
|
+
button primary lg "Sign in" fullWidth
|
|
12
|
+
spacer
|
|
13
|
+
text sm "New here? Create an account" align=center muted
|
|
14
|
+
note "Show the error state when the password is wrong" width=200
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
board row "Empty and error states"
|
|
2
|
+
screen phone "No notes yet"
|
|
3
|
+
navbar "Notes" actions=[plus]
|
|
4
|
+
stack grow justify=center align=center gap=12 padding=24
|
|
5
|
+
image "Illustration" height=140 width=200
|
|
6
|
+
heading "No notes yet" level=2
|
|
7
|
+
text "Your notes will show up here." muted align=center
|
|
8
|
+
button primary "New note" leadingIcon=plus
|
|
9
|
+
screen phone "Couldn't load"
|
|
10
|
+
navbar "Notes" actions=[plus]
|
|
11
|
+
stack grow justify=center align=center gap=12 padding=24
|
|
12
|
+
icon triangle-alert size=40
|
|
13
|
+
heading "Something went wrong" level=2
|
|
14
|
+
text "Check your connection and try again." muted align=center
|
|
15
|
+
button secondary "Try again" leadingIcon=refresh-cw
|
|
16
|
+
badge "Offline" tone=warning
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tsquare",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.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",
|
|
@@ -76,6 +76,14 @@
|
|
|
76
76
|
"zod": "^4.6.5"
|
|
77
77
|
},
|
|
78
78
|
"devDependencies": {
|
|
79
|
+
"@codemirror/autocomplete": "^6.20.3",
|
|
80
|
+
"@codemirror/commands": "^6.11.1",
|
|
81
|
+
"@codemirror/language": "^6.12.4",
|
|
82
|
+
"@codemirror/lint": "^6.9.7",
|
|
83
|
+
"@codemirror/search": "^6.7.2",
|
|
84
|
+
"@codemirror/state": "^6.7.6",
|
|
85
|
+
"@codemirror/view": "^6.43.13",
|
|
86
|
+
"@lezer/highlight": "^1.2.5",
|
|
79
87
|
"esbuild": "^0.28.2",
|
|
80
88
|
"gpt-tokenizer": "^4.0.0",
|
|
81
89
|
"tsx": "^4.23.15",
|
package/skill/tsquare/SKILL.md
CHANGED
|
@@ -33,9 +33,10 @@ One element per line. Indent children two spaces under their parent. The first l
|
|
|
33
33
|
A line is the component name in lowercase, followed by arguments separated by spaces:
|
|
34
34
|
- "a quoted string" sets the component's main text prop (marked "main text" in reference.md)
|
|
35
35
|
- a bare word that is one of the component's option values sets that option: phone, desktop, primary, ghost, row, sm, left, bottom, password, …
|
|
36
|
-
- a bare prop name sets
|
|
36
|
+
- 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
|
|
37
37
|
- key=value sets any prop. Values: "string", number, true/false, bare word, [list, of, values], {key=value key=value}
|
|
38
|
-
|
|
38
|
+
|
|
39
|
+
Comments: 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.
|
|
39
40
|
|
|
40
41
|
Lists: 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].
|
|
41
42
|
|
|
@@ -106,7 +106,8 @@ Button. Primary is filled, secondary is outlined, ghost is text only.
|
|
|
106
106
|
- label: string (main text)
|
|
107
107
|
- variant: "primary" | "secondary" | "ghost"
|
|
108
108
|
- size: "sm" | "md" | "lg"
|
|
109
|
-
-
|
|
109
|
+
- leadingIcon: string — Lucide icon before the label, e.g. chevron-left for Back
|
|
110
|
+
- trailingIcon: string — Lucide icon after the label, e.g. chevron-right for Next
|
|
110
111
|
- fullWidth: boolean
|
|
111
112
|
|
|
112
113
|
### Input
|
|
@@ -170,10 +171,10 @@ Row in a List. Omit title for a placeholder bar.
|
|
|
170
171
|
- title: string (main text)
|
|
171
172
|
- subtitle: string
|
|
172
173
|
- leading: "none" | "icon" | "avatar" | "image" | "checkbox"
|
|
173
|
-
-
|
|
174
|
+
- leadingIcon: string — Lucide icon on the left; setting it implies leading=icon
|
|
174
175
|
- trailing: "none" | "chevron" | "toggle" | "text" | "badge" | "icon"
|
|
175
|
-
- trailingText: string
|
|
176
|
-
- trailingIcon: string — Lucide icon
|
|
176
|
+
- trailingText: string — Text for trailing=text or badge; setting it implies trailing=text
|
|
177
|
+
- trailingIcon: string — Lucide icon on the right; setting it implies trailing=icon
|
|
177
178
|
|
|
178
179
|
### Table
|
|
179
180
|
Table with headers. Rows are placeholder bars unless `data` is given.
|