@spunto/design-system 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -0
- package/package.json +2 -1
- package/src/components/terminal.tsx +35 -3
- package/src/index.ts +1 -1
package/README.md
CHANGED
|
@@ -51,6 +51,10 @@ const nextConfig = { transpilePackages: ["@spunto/design-system"] }
|
|
|
51
51
|
(a confirmation variant, non-dismissible), `Tooltip`. Their portals render into
|
|
52
52
|
the provider's overlay container; `Tooltip`'s shared delay group is mounted by the
|
|
53
53
|
provider too.
|
|
54
|
+
- _Terminal_ — `Terminal` (+`TerminalHandle`, `TerminalOptions`), a transport-agnostic
|
|
55
|
+
xterm.js surface: mount, shared dark ANSI theme, fit-on-resize. No opinion on where
|
|
56
|
+
bytes come from (WebSocket, SSE, a static string) — feed it via the `write`/`writeln`
|
|
57
|
+
ref handle. Opt-in addons through `options` (currently `webLinks`, clickable URLs).
|
|
54
58
|
- **`SpuntoProvider` + `toast()`** — the imperative toast system (see below). The
|
|
55
59
|
provider is also the umbrella that mounts the tooltip delay group and the overlay
|
|
56
60
|
portal container the dialogs/selects render into.
|
|
@@ -104,6 +108,26 @@ toast.dismiss(id)
|
|
|
104
108
|
`toastPosition` (default `"top-right"`), `toastDuration` (default `5000`, `0` =
|
|
105
109
|
persistent) and `toastLimit` (default `3`).
|
|
106
110
|
|
|
111
|
+
## LLM / agent docs (`llms.txt`)
|
|
112
|
+
|
|
113
|
+
The [showcase](showcase/) also exposes its documentation as **plain markdown**,
|
|
114
|
+
so coding agents can consume the component APIs directly. Everything is generated
|
|
115
|
+
from the same content that drives the visual pages
|
|
116
|
+
(`showcase/src/content/components.ts`) — there is no second source to keep in sync.
|
|
117
|
+
|
|
118
|
+
Served both in dev (Vite middleware) and in the built site (static files) at
|
|
119
|
+
`https://design.spunto.net`:
|
|
120
|
+
|
|
121
|
+
- **`/llms.txt`** — index (llmstxt.org convention) linking every page.
|
|
122
|
+
- **`/<component>.md`** — one page per component with import, example and the full
|
|
123
|
+
props API (e.g. `/button.md`, `/select.md`).
|
|
124
|
+
- **`/colors.md`**, `/typography.md`, `/radius.md` — the foundations/tokens.
|
|
125
|
+
- **`/llms-full.txt`** — every page concatenated into a single file.
|
|
126
|
+
|
|
127
|
+
Adding a component = add its entry to `content/components.ts` + a demo file in
|
|
128
|
+
`showcase/src/demos/`; the visual page and its `.md` are then produced
|
|
129
|
+
automatically (see `showcase/vite-plugin-llms.ts`).
|
|
130
|
+
|
|
107
131
|
## Peer requirements
|
|
108
132
|
|
|
109
133
|
- React 19+, and a **Tailwind CSS v4** pipeline in the consuming app.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spunto/design-system",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Spunto's shared design system — warm/flame tokens, color constants, and UI primitives.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@xterm/addon-fit": "^0.11.0",
|
|
48
|
+
"@xterm/addon-web-links": "^0.12.0",
|
|
48
49
|
"@xterm/xterm": "^6.0.0",
|
|
49
50
|
"class-variance-authority": "^0.7.1",
|
|
50
51
|
"clsx": "^2.1.1",
|
|
@@ -42,6 +42,11 @@ export interface TerminalHandle {
|
|
|
42
42
|
focus: () => void
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
export interface TerminalOptions {
|
|
46
|
+
/** Turns URLs in terminal output into clickable links (`@xterm/addon-web-links`). */
|
|
47
|
+
webLinks?: boolean
|
|
48
|
+
}
|
|
49
|
+
|
|
45
50
|
export interface TerminalProps {
|
|
46
51
|
className?: string
|
|
47
52
|
fontSize?: number
|
|
@@ -52,6 +57,12 @@ export interface TerminalProps {
|
|
|
52
57
|
* common case this primitive was built for.
|
|
53
58
|
*/
|
|
54
59
|
onData?: (data: string) => void
|
|
60
|
+
/**
|
|
61
|
+
* Opt-in xterm addons — kept out of the base bundle since most consumers
|
|
62
|
+
* (plain log output) don't need them. Read once at mount, like the other
|
|
63
|
+
* props here.
|
|
64
|
+
*/
|
|
65
|
+
options?: TerminalOptions
|
|
55
66
|
}
|
|
56
67
|
|
|
57
68
|
/**
|
|
@@ -61,18 +72,29 @@ export interface TerminalProps {
|
|
|
61
72
|
* plug in on top.
|
|
62
73
|
*/
|
|
63
74
|
const Terminal = forwardRef<TerminalHandle, TerminalProps>(function Terminal(
|
|
64
|
-
{ className, fontSize = 13, scrollback = 5000, onData },
|
|
75
|
+
{ className, fontSize = 13, scrollback = 5000, onData, options },
|
|
65
76
|
ref
|
|
66
77
|
) {
|
|
67
78
|
const outerRef = useRef<HTMLDivElement>(null)
|
|
68
79
|
const mountRef = useRef<HTMLDivElement>(null)
|
|
69
80
|
const termRef = useRef<XTerm | null>(null)
|
|
81
|
+
// xterm mounts asynchronously (dynamic import); a consumer wiring up a
|
|
82
|
+
// transport (WebSocket, SSE...) in its own effect can easily win that race
|
|
83
|
+
// and call write() before termRef exists. Queue those calls instead of
|
|
84
|
+
// dropping them, and flush in order once xterm is ready.
|
|
85
|
+
const pendingRef = useRef<Array<{ method: "write" | "writeln"; data: string | Uint8Array }>>([])
|
|
70
86
|
|
|
71
87
|
useImperativeHandle(
|
|
72
88
|
ref,
|
|
73
89
|
() => ({
|
|
74
|
-
write: (data) =>
|
|
75
|
-
|
|
90
|
+
write: (data) => {
|
|
91
|
+
if (termRef.current) termRef.current.write(data)
|
|
92
|
+
else pendingRef.current.push({ method: "write", data })
|
|
93
|
+
},
|
|
94
|
+
writeln: (data) => {
|
|
95
|
+
if (termRef.current) termRef.current.writeln(data)
|
|
96
|
+
else pendingRef.current.push({ method: "writeln", data })
|
|
97
|
+
},
|
|
76
98
|
clear: () => termRef.current?.clear(),
|
|
77
99
|
focus: () => termRef.current?.focus(),
|
|
78
100
|
}),
|
|
@@ -103,6 +125,10 @@ const Terminal = forwardRef<TerminalHandle, TerminalProps>(function Terminal(
|
|
|
103
125
|
|
|
104
126
|
const fitAddon = new FitAddon()
|
|
105
127
|
term.loadAddon(fitAddon)
|
|
128
|
+
if (options?.webLinks) {
|
|
129
|
+
const { WebLinksAddon } = await import("@xterm/addon-web-links")
|
|
130
|
+
term.loadAddon(new WebLinksAddon())
|
|
131
|
+
}
|
|
106
132
|
// FitAddon computes available space from *this* element's parent minus
|
|
107
133
|
// this element's own padding — it has no idea about an outer wrapper's
|
|
108
134
|
// padding/border. Mounting on a padding-less, border-less inner div (see
|
|
@@ -113,6 +139,12 @@ const Terminal = forwardRef<TerminalHandle, TerminalProps>(function Terminal(
|
|
|
113
139
|
fitAddon.fit()
|
|
114
140
|
termRef.current = term
|
|
115
141
|
|
|
142
|
+
for (const { method, data } of pendingRef.current) {
|
|
143
|
+
if (method === "writeln") term.writeln(data as string)
|
|
144
|
+
else term.write(data)
|
|
145
|
+
}
|
|
146
|
+
pendingRef.current = []
|
|
147
|
+
|
|
116
148
|
if (onData) term.onData(onData)
|
|
117
149
|
|
|
118
150
|
resizeObserver = new ResizeObserver(() => fitAddon.fit())
|
package/src/index.ts
CHANGED
|
@@ -24,7 +24,7 @@ export { Avatar, AvatarImage, AvatarFallback } from "./components/avatar"
|
|
|
24
24
|
// xterm.js surface — theme + fit-on-resize, transport-agnostic (feed it via
|
|
25
25
|
// the write/writeln ref handle).
|
|
26
26
|
export { Terminal } from "./components/terminal"
|
|
27
|
-
export type { TerminalHandle, TerminalProps } from "./components/terminal"
|
|
27
|
+
export type { TerminalHandle, TerminalProps, TerminalOptions } from "./components/terminal"
|
|
28
28
|
|
|
29
29
|
// Inline, declarative status banner (persistent) — the counterpart to `toast()`.
|
|
30
30
|
// `alertVariants` ships from this directive-free module so it stays RSC-callable.
|