@tangle-network/ui 11.36.0 → 11.38.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/CHANGELOG.md +20 -0
- package/dist/code-presentation.d.ts +2 -0
- package/dist/code-presentation.js +2 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.js +5 -2
- package/dist/lib/code-presentation.d.ts +92 -0
- package/dist/lib/code-presentation.js +437 -0
- package/dist/lib/surface-motion.js +34 -13
- package/dist/markdown/api-schema.d.ts +9 -0
- package/dist/markdown/api-schema.js +20 -0
- package/dist/markdown/code-block.d.ts +15 -7
- package/dist/markdown/code-block.js +120 -268
- package/dist/markdown.d.ts +4 -2
- package/dist/markdown.js +4 -2
- package/dist/primitives/button.js +2 -1
- package/dist/primitives/code-block.d.ts +1 -1
- package/dist/primitives/popover.js +11 -3
- package/dist/primitives/wizard.d.ts +30 -0
- package/dist/primitives/wizard.js +158 -0
- package/dist/primitives.d.ts +2 -1
- package/dist/primitives.js +2 -1
- package/package.json +7 -2
- package/src/code-presentation.ts +2 -0
- package/src/lib/code-presentation.ts +257 -0
- package/src/lib/surface-motion.tsx +22 -15
- package/src/markdown/api-presentation.test.tsx +63 -0
- package/src/markdown/api-schema.tsx +9 -0
- package/src/markdown/code-block.tsx +54 -185
- package/src/markdown/index.ts +2 -1
- package/src/primitives/button.tsx +2 -1
- package/src/primitives/code-block.tsx +1 -1
- package/src/primitives/index.ts +3 -0
- package/src/primitives/popover.tsx +6 -8
- package/src/primitives/wizard.stories.tsx +51 -0
- package/src/primitives/wizard.test.tsx +106 -0
- package/src/primitives/wizard.tsx +212 -0
- package/src/styles/presentation.css +8 -0
|
@@ -1,186 +1,23 @@
|
|
|
1
1
|
import { focusRing, focusRingInset } from "../lib/focus.js";
|
|
2
2
|
import { cn } from "../lib/utils.js";
|
|
3
|
-
import {
|
|
3
|
+
import { LANGUAGE_NAMES, PLAIN_TEXT, SYNTAX, apiMetadataText, bindCodeTabs, codeBlockGrammar, codePreStyle, codePresentation, codeTextStyle, createCopyFeedback, tokenStyle, tokenize } from "../lib/code-presentation.js";
|
|
4
|
+
import { memo, useEffect, useId, useRef, useState } from "react";
|
|
4
5
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
5
6
|
import { Check, Copy, FileCode2 } from "lucide-react";
|
|
6
7
|
//#region src/markdown/code-block.tsx
|
|
7
|
-
const SYNTAX = {
|
|
8
|
-
comment: "var(--syntax-comment, currentColor)",
|
|
9
|
-
keyword: "var(--syntax-keyword, currentColor)",
|
|
10
|
-
string: "var(--syntax-string, currentColor)",
|
|
11
|
-
function: "var(--syntax-function, currentColor)",
|
|
12
|
-
number: "var(--syntax-number, currentColor)",
|
|
13
|
-
variable: "var(--syntax-variable, currentColor)",
|
|
14
|
-
foreground: "var(--syntax-foreground, currentColor)"
|
|
15
|
-
};
|
|
16
|
-
const SHIKI_THEME = "tangle-syntax";
|
|
17
|
-
const BRAND_COLOR_FOR_SHIKI = {
|
|
18
|
-
"var(--shiki-foreground)": SYNTAX.foreground,
|
|
19
|
-
"var(--shiki-token-comment)": SYNTAX.comment,
|
|
20
|
-
"var(--shiki-token-keyword)": SYNTAX.keyword,
|
|
21
|
-
"var(--shiki-token-string)": SYNTAX.string,
|
|
22
|
-
"var(--shiki-token-string-expression)": SYNTAX.string,
|
|
23
|
-
"var(--shiki-token-function)": SYNTAX.function,
|
|
24
|
-
"var(--shiki-token-constant)": SYNTAX.number,
|
|
25
|
-
"var(--shiki-token-link)": SYNTAX.number,
|
|
26
|
-
"var(--shiki-token-parameter)": SYNTAX.variable,
|
|
27
|
-
"var(--shiki-token-punctuation)": SYNTAX.foreground
|
|
28
|
-
};
|
|
29
|
-
const GRAMMARS = {
|
|
30
|
-
typescript: () => import("shiki/langs/typescript.mjs"),
|
|
31
|
-
tsx: () => import("shiki/langs/tsx.mjs"),
|
|
32
|
-
javascript: () => import("shiki/langs/javascript.mjs"),
|
|
33
|
-
jsx: () => import("shiki/langs/jsx.mjs"),
|
|
34
|
-
json: () => import("shiki/langs/json.mjs"),
|
|
35
|
-
jsonc: () => import("shiki/langs/jsonc.mjs"),
|
|
36
|
-
bash: () => import("shiki/langs/bash.mjs"),
|
|
37
|
-
python: () => import("shiki/langs/python.mjs"),
|
|
38
|
-
html: () => import("shiki/langs/html.mjs"),
|
|
39
|
-
css: () => import("shiki/langs/css.mjs"),
|
|
40
|
-
scss: () => import("shiki/langs/scss.mjs"),
|
|
41
|
-
markdown: () => import("shiki/langs/markdown.mjs"),
|
|
42
|
-
mdx: () => import("shiki/langs/mdx.mjs"),
|
|
43
|
-
yaml: () => import("shiki/langs/yaml.mjs"),
|
|
44
|
-
toml: () => import("shiki/langs/toml.mjs"),
|
|
45
|
-
sql: () => import("shiki/langs/sql.mjs"),
|
|
46
|
-
diff: () => import("shiki/langs/diff.mjs"),
|
|
47
|
-
go: () => import("shiki/langs/go.mjs"),
|
|
48
|
-
rust: () => import("shiki/langs/rust.mjs"),
|
|
49
|
-
solidity: () => import("shiki/langs/solidity.mjs"),
|
|
50
|
-
ruby: () => import("shiki/langs/ruby.mjs"),
|
|
51
|
-
java: () => import("shiki/langs/java.mjs"),
|
|
52
|
-
kotlin: () => import("shiki/langs/kotlin.mjs"),
|
|
53
|
-
swift: () => import("shiki/langs/swift.mjs"),
|
|
54
|
-
php: () => import("shiki/langs/php.mjs"),
|
|
55
|
-
c: () => import("shiki/langs/c.mjs"),
|
|
56
|
-
cpp: () => import("shiki/langs/cpp.mjs"),
|
|
57
|
-
csharp: () => import("shiki/langs/csharp.mjs"),
|
|
58
|
-
graphql: () => import("shiki/langs/graphql.mjs"),
|
|
59
|
-
xml: () => import("shiki/langs/xml.mjs"),
|
|
60
|
-
dockerfile: () => import("shiki/langs/dockerfile.mjs")
|
|
61
|
-
};
|
|
62
|
-
const LANGUAGE_ALIASES = {
|
|
63
|
-
ts: "typescript",
|
|
64
|
-
mts: "typescript",
|
|
65
|
-
cts: "typescript",
|
|
66
|
-
js: "javascript",
|
|
67
|
-
mjs: "javascript",
|
|
68
|
-
cjs: "javascript",
|
|
69
|
-
node: "javascript",
|
|
70
|
-
sh: "bash",
|
|
71
|
-
shell: "bash",
|
|
72
|
-
zsh: "bash",
|
|
73
|
-
console: "bash",
|
|
74
|
-
shellscript: "bash",
|
|
75
|
-
py: "python",
|
|
76
|
-
python3: "python",
|
|
77
|
-
yml: "yaml",
|
|
78
|
-
md: "markdown",
|
|
79
|
-
rs: "rust",
|
|
80
|
-
sol: "solidity",
|
|
81
|
-
rb: "ruby",
|
|
82
|
-
kt: "kotlin",
|
|
83
|
-
cs: "csharp",
|
|
84
|
-
"c#": "csharp",
|
|
85
|
-
"c++": "cpp",
|
|
86
|
-
gql: "graphql",
|
|
87
|
-
svg: "xml",
|
|
88
|
-
docker: "dockerfile",
|
|
89
|
-
patch: "diff",
|
|
90
|
-
htm: "html"
|
|
91
|
-
};
|
|
92
|
-
const LANGUAGE_NAMES = {
|
|
93
|
-
typescript: "TypeScript",
|
|
94
|
-
tsx: "TSX",
|
|
95
|
-
javascript: "JavaScript",
|
|
96
|
-
jsx: "JSX",
|
|
97
|
-
json: "JSON",
|
|
98
|
-
jsonc: "JSONC",
|
|
99
|
-
bash: "Bash",
|
|
100
|
-
python: "Python",
|
|
101
|
-
html: "HTML",
|
|
102
|
-
css: "CSS",
|
|
103
|
-
scss: "SCSS",
|
|
104
|
-
markdown: "Markdown",
|
|
105
|
-
mdx: "MDX",
|
|
106
|
-
yaml: "YAML",
|
|
107
|
-
toml: "TOML",
|
|
108
|
-
sql: "SQL",
|
|
109
|
-
diff: "Diff",
|
|
110
|
-
go: "Go",
|
|
111
|
-
rust: "Rust",
|
|
112
|
-
solidity: "Solidity",
|
|
113
|
-
ruby: "Ruby",
|
|
114
|
-
java: "Java",
|
|
115
|
-
kotlin: "Kotlin",
|
|
116
|
-
swift: "Swift",
|
|
117
|
-
php: "PHP",
|
|
118
|
-
c: "C",
|
|
119
|
-
cpp: "C++",
|
|
120
|
-
csharp: "C#",
|
|
121
|
-
graphql: "GraphQL",
|
|
122
|
-
xml: "XML",
|
|
123
|
-
dockerfile: "Dockerfile"
|
|
124
|
-
};
|
|
125
|
-
/** The Shiki grammar for a fence language, or undefined for plain text. */
|
|
126
|
-
const PLAIN_TEXT = /* @__PURE__ */ new Set([
|
|
127
|
-
"text",
|
|
128
|
-
"txt",
|
|
129
|
-
"plain",
|
|
130
|
-
"plaintext"
|
|
131
|
-
]);
|
|
132
|
-
function codeBlockGrammar(language) {
|
|
133
|
-
if (!language) return void 0;
|
|
134
|
-
const id = language.toLowerCase();
|
|
135
|
-
const resolved = LANGUAGE_ALIASES[id] ?? id;
|
|
136
|
-
return GRAMMARS[resolved] ? resolved : void 0;
|
|
137
|
-
}
|
|
138
|
-
let highlighterPromise;
|
|
139
|
-
const grammarLoads = /* @__PURE__ */ new Map();
|
|
140
|
-
function loadHighlighter() {
|
|
141
|
-
return highlighterPromise ??= Promise.all([import("shiki/core"), import("shiki/engine/javascript")]).then(([core, engine]) => core.createHighlighterCore({
|
|
142
|
-
themes: [core.createCssVariablesTheme({
|
|
143
|
-
name: SHIKI_THEME,
|
|
144
|
-
variablePrefix: "--shiki-",
|
|
145
|
-
fontStyle: true
|
|
146
|
-
})],
|
|
147
|
-
langs: [],
|
|
148
|
-
engine: engine.createJavaScriptRegexEngine()
|
|
149
|
-
})).catch((error) => {
|
|
150
|
-
highlighterPromise = void 0;
|
|
151
|
-
throw error;
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
async function tokenize(code, grammar) {
|
|
155
|
-
const highlighter = await loadHighlighter();
|
|
156
|
-
let load = grammarLoads.get(grammar);
|
|
157
|
-
if (!load) {
|
|
158
|
-
load = GRAMMARS[grammar]().then((module) => highlighter.loadLanguage(module.default));
|
|
159
|
-
load.catch(() => grammarLoads.delete(grammar));
|
|
160
|
-
grammarLoads.set(grammar, load);
|
|
161
|
-
}
|
|
162
|
-
await load;
|
|
163
|
-
return highlighter.codeToTokensBase(code, {
|
|
164
|
-
lang: grammar,
|
|
165
|
-
theme: SHIKI_THEME
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
function tokenStyle(token) {
|
|
169
|
-
const color = token.color ? BRAND_COLOR_FOR_SHIKI[token.color] ?? SYNTAX.foreground : void 0;
|
|
170
|
-
const style = token.fontStyle ?? 0;
|
|
171
|
-
if (!color && !style) return void 0;
|
|
172
|
-
return {
|
|
173
|
-
...color ? { color } : {},
|
|
174
|
-
...style & 1 ? { fontStyle: "italic" } : {},
|
|
175
|
-
...style & 2 ? { fontWeight: "bold" } : {},
|
|
176
|
-
...style & 4 ? { textDecoration: "underline" } : {}
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
8
|
/**
|
|
180
9
|
* Code with Shiki highlighting in Brand's syntax colors. It renders readable
|
|
181
10
|
* plain code first (and on the server), then highlights once its grammar loads.
|
|
182
11
|
*/
|
|
183
|
-
const CodeBlock = memo(({ code, language, label, filename, showLineNumbers = false, light, className, children, ...props }) => {
|
|
12
|
+
const CodeBlock = memo(({ code: defaultCode, language: defaultLanguage, label, filename: defaultFilename, examples, metadata, showLineNumbers = false, light, className, children, ...props }) => {
|
|
13
|
+
const [selected, setSelected] = useState(0);
|
|
14
|
+
const tabId = useId(), tabList = useRef(null);
|
|
15
|
+
const selectedIndex = Math.min(selected, Math.max(0, (examples?.length ?? 1) - 1));
|
|
16
|
+
const example = examples?.[selectedIndex];
|
|
17
|
+
const code = example?.code ?? defaultCode, language = example?.language ?? defaultLanguage, filename = example?.filename ?? defaultFilename;
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
if (tabList.current) return bindCodeTabs(tabList.current, setSelected);
|
|
20
|
+
}, [examples?.length]);
|
|
184
21
|
const grammar = codeBlockGrammar(language);
|
|
185
22
|
const [highlighted, setHighlighted] = useState(null);
|
|
186
23
|
useEffect(() => {
|
|
@@ -199,21 +36,8 @@ const CodeBlock = memo(({ code, language, label, filename, showLineNumbers = fal
|
|
|
199
36
|
}, [code, grammar]);
|
|
200
37
|
const languageName = grammar ? LANGUAGE_NAMES[grammar] : PLAIN_TEXT.has(language?.toLowerCase() ?? "") ? void 0 : language;
|
|
201
38
|
const headerLabel = label ?? (filename ? void 0 : languageName);
|
|
202
|
-
const hasHeader = Boolean(filename || headerLabel);
|
|
39
|
+
const hasHeader = Boolean(filename || headerLabel || metadata || examples?.length);
|
|
203
40
|
const mode = light === void 0 ? {} : { "data-theme": light ? "light" : "dark" };
|
|
204
|
-
const preStyle = {
|
|
205
|
-
margin: 0,
|
|
206
|
-
padding: "var(--code-padding-y, 0.625rem) var(--code-padding-x, 0.75rem)",
|
|
207
|
-
background: "transparent",
|
|
208
|
-
color: SYNTAX.foreground,
|
|
209
|
-
fontSize: "var(--code-font-size, 0.8125rem)",
|
|
210
|
-
lineHeight: "var(--code-line-height, 1.5)",
|
|
211
|
-
overflowX: "auto"
|
|
212
|
-
};
|
|
213
|
-
const codeStyle = {
|
|
214
|
-
fontFamily: "var(--font-mono, 'JetBrains Mono', ui-monospace, monospace)",
|
|
215
|
-
whiteSpace: "pre"
|
|
216
|
-
};
|
|
217
41
|
const isHighlighted = Boolean(highlighted && highlighted.code === code && highlighted.grammar === grammar);
|
|
218
42
|
const lines = isHighlighted ? highlighted.lines.map((line) => line.map((token) => ({
|
|
219
43
|
content: token.content,
|
|
@@ -221,113 +45,141 @@ const CodeBlock = memo(({ code, language, label, filename, showLineNumbers = fal
|
|
|
221
45
|
}))) : code.split("\n").map((line) => [{ content: line }]);
|
|
222
46
|
const regionName = filename ?? headerLabel;
|
|
223
47
|
return /* @__PURE__ */ jsxs("div", {
|
|
224
|
-
className: cn(
|
|
48
|
+
className: cn(codePresentation.root, className),
|
|
225
49
|
"data-highlighted": isHighlighted ? "true" : void 0,
|
|
226
50
|
...props,
|
|
227
51
|
...mode,
|
|
228
52
|
children: [
|
|
229
53
|
hasHeader && /* @__PURE__ */ jsxs("div", {
|
|
230
|
-
className:
|
|
231
|
-
children: [
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
54
|
+
className: codePresentation.header,
|
|
55
|
+
children: [
|
|
56
|
+
metadata && /* @__PURE__ */ jsx("span", {
|
|
57
|
+
className: "tangle-api-meta",
|
|
58
|
+
children: apiMetadataText(metadata)
|
|
59
|
+
}),
|
|
60
|
+
filename ? /* @__PURE__ */ jsxs("span", {
|
|
61
|
+
className: "flex min-w-0 items-center gap-2 font-sans text-sm",
|
|
62
|
+
children: [
|
|
63
|
+
/* @__PURE__ */ jsx(FileCode2, {
|
|
64
|
+
"aria-hidden": true,
|
|
65
|
+
className: "size-4 shrink-0 text-muted-foreground"
|
|
66
|
+
}),
|
|
67
|
+
/* @__PURE__ */ jsx("span", {
|
|
68
|
+
className: "min-w-0 truncate font-mono font-medium text-foreground",
|
|
69
|
+
title: filename,
|
|
70
|
+
children: filename
|
|
71
|
+
}),
|
|
72
|
+
languageName && /* @__PURE__ */ jsx("span", {
|
|
73
|
+
className: "shrink-0 text-muted-foreground",
|
|
74
|
+
children: languageName
|
|
75
|
+
})
|
|
76
|
+
]
|
|
77
|
+
}) : /* @__PURE__ */ jsx("span", {
|
|
78
|
+
className: "font-sans text-sm font-medium text-muted-foreground",
|
|
79
|
+
children: headerLabel
|
|
80
|
+
}),
|
|
81
|
+
children,
|
|
82
|
+
examples?.length ? /* @__PURE__ */ jsx(CopyButton, { text: code }) : null
|
|
83
|
+
]
|
|
252
84
|
}),
|
|
253
85
|
!hasHeader && children && /* @__PURE__ */ jsx("div", {
|
|
254
86
|
className: "absolute right-2 top-2 z-10 flex items-center gap-2 opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100",
|
|
255
87
|
children
|
|
256
88
|
}),
|
|
257
|
-
/* @__PURE__ */ jsx("
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
className:
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
89
|
+
examples && examples.length > 1 && /* @__PURE__ */ jsx("div", {
|
|
90
|
+
role: "tablist",
|
|
91
|
+
"aria-label": "Code examples",
|
|
92
|
+
ref: tabList,
|
|
93
|
+
className: codePresentation.tabs,
|
|
94
|
+
children: examples.map((item, index) => /* @__PURE__ */ jsx("button", {
|
|
95
|
+
id: `${tabId}-tab-${index}`,
|
|
96
|
+
type: "button",
|
|
97
|
+
role: "tab",
|
|
98
|
+
className: codePresentation.tab,
|
|
99
|
+
"data-state": index === selectedIndex ? "active" : "inactive",
|
|
100
|
+
"aria-selected": index === selectedIndex,
|
|
101
|
+
tabIndex: index === selectedIndex ? 0 : -1,
|
|
102
|
+
"aria-controls": `${tabId}-panel`,
|
|
103
|
+
children: item.label
|
|
104
|
+
}, index))
|
|
105
|
+
}),
|
|
106
|
+
/* @__PURE__ */ jsx("div", {
|
|
107
|
+
id: `${tabId}-panel`,
|
|
108
|
+
role: examples && examples.length > 1 ? "tabpanel" : void 0,
|
|
109
|
+
"aria-labelledby": examples && examples.length > 1 ? `${tabId}-tab-${selectedIndex}` : void 0,
|
|
110
|
+
children: /* @__PURE__ */ jsx("pre", {
|
|
111
|
+
tabIndex: 0,
|
|
112
|
+
role: "region",
|
|
113
|
+
"aria-label": regionName ? `${regionName} code` : "Code",
|
|
114
|
+
className: focusRingInset,
|
|
115
|
+
style: codePreStyle,
|
|
116
|
+
children: /* @__PURE__ */ jsx("code", {
|
|
117
|
+
style: codeTextStyle,
|
|
118
|
+
children: !isHighlighted && !showLineNumbers ? code : lines.map((line, index) => /* @__PURE__ */ jsxs("span", { children: [
|
|
119
|
+
showLineNumbers && /* @__PURE__ */ jsx("span", {
|
|
120
|
+
"aria-hidden": "true",
|
|
121
|
+
"data-line-number": true,
|
|
122
|
+
className: "inline-block select-none pr-4 text-right",
|
|
123
|
+
style: {
|
|
124
|
+
color: SYNTAX.comment,
|
|
125
|
+
minWidth: "2.5em"
|
|
126
|
+
},
|
|
127
|
+
children: index + 1
|
|
128
|
+
}),
|
|
129
|
+
line.map((token, tokenIndex) => /* @__PURE__ */ jsx("span", {
|
|
130
|
+
style: token.style,
|
|
131
|
+
children: token.content
|
|
132
|
+
}, tokenIndex)),
|
|
133
|
+
index < lines.length - 1 ? "\n" : null
|
|
134
|
+
] }, index))
|
|
135
|
+
})
|
|
282
136
|
})
|
|
283
137
|
})
|
|
284
138
|
]
|
|
285
139
|
});
|
|
286
140
|
});
|
|
287
141
|
CodeBlock.displayName = "CodeBlock";
|
|
288
|
-
/** Copy-to-clipboard button for use inside CodeBlock. */
|
|
289
|
-
const CopyButton = memo(({ text }) => {
|
|
290
|
-
const [copied,
|
|
291
|
-
|
|
292
|
-
|
|
142
|
+
/** Copy-to-clipboard button for use inside CodeBlock or other exact-text actions. */
|
|
143
|
+
const CopyButton = memo(({ text, label: actionLabel, copiedLabel = "Copied", failedLabel = "Copy failed", className, onClick, ...props }) => {
|
|
144
|
+
const [{ copied, status, pending, loading, longRunning }, setFeedback] = useState({
|
|
145
|
+
copied: false,
|
|
146
|
+
status: "",
|
|
147
|
+
pending: false
|
|
148
|
+
});
|
|
149
|
+
const button = useRef(null);
|
|
150
|
+
const feedback = useRef(null);
|
|
293
151
|
useEffect(() => {
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
152
|
+
const controller = createCopyFeedback(setFeedback, void 0, button.current ?? void 0);
|
|
153
|
+
feedback.current = controller;
|
|
154
|
+
return () => controller.dispose();
|
|
297
155
|
}, []);
|
|
298
|
-
const handleCopy =
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
setStatus("Copy failed");
|
|
309
|
-
}
|
|
310
|
-
timerRef.current = setTimeout(() => {
|
|
311
|
-
setCopied(false);
|
|
312
|
-
setStatus("");
|
|
313
|
-
}, 2e3);
|
|
314
|
-
}, [text]);
|
|
315
|
-
const label = copied ? "Copied" : "Copy to clipboard";
|
|
316
|
-
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("button", {
|
|
156
|
+
const handleCopy = (event) => {
|
|
157
|
+
if (pending || props["aria-disabled"] === true || props["aria-disabled"] === "true") return;
|
|
158
|
+
onClick?.(event);
|
|
159
|
+
if (!event.defaultPrevented) feedback.current?.copy(text);
|
|
160
|
+
};
|
|
161
|
+
const label = copied ? copiedLabel : actionLabel && status === "Copy failed" ? failedLabel : actionLabel ?? "Copy to clipboard";
|
|
162
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("button", {
|
|
163
|
+
...props,
|
|
164
|
+
ref: button,
|
|
165
|
+
"data-copy-loading": !!loading,
|
|
317
166
|
type: "button",
|
|
318
167
|
onClick: handleCopy,
|
|
319
|
-
className: cn(
|
|
320
|
-
"aria-label": label,
|
|
168
|
+
className: cn(codePresentation.copy, actionLabel && "gap-2 px-3", focusRing, className),
|
|
169
|
+
"aria-label": pending ? "Copying to clipboard" : label,
|
|
170
|
+
"aria-busy": pending || props["aria-busy"],
|
|
171
|
+
"aria-disabled": pending || props["aria-disabled"],
|
|
321
172
|
title: label,
|
|
322
|
-
children: copied ? /* @__PURE__ */ jsx(Check, {
|
|
173
|
+
children: [copied ? /* @__PURE__ */ jsx(Check, {
|
|
323
174
|
"aria-hidden": "true",
|
|
324
175
|
className: "w-3.5 h-3.5 text-[var(--surface-success-text)]"
|
|
325
176
|
}) : /* @__PURE__ */ jsx(Copy, {
|
|
326
177
|
"aria-hidden": "true",
|
|
327
178
|
className: "w-3.5 h-3.5 text-muted-foreground"
|
|
328
|
-
})
|
|
179
|
+
}), actionLabel && /* @__PURE__ */ jsx("span", { children: label })]
|
|
329
180
|
}), /* @__PURE__ */ jsx("span", {
|
|
330
|
-
className:
|
|
181
|
+
className: codePresentation.copyStatus,
|
|
182
|
+
"data-copy-long-work": !!longRunning,
|
|
331
183
|
role: "status",
|
|
332
184
|
"aria-live": "polite",
|
|
333
185
|
children: status
|
package/dist/markdown.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Markdown, MarkdownLinkChip, MarkdownLinkChipResolver, MarkdownProps, getSanitizedMarkdownHeadingIdFromRawFragment } from "./markdown/markdown.js";
|
|
2
|
-
import {
|
|
2
|
+
import { codeBlockGrammar } from "./lib/code-presentation.js";
|
|
3
|
+
import { CodeBlock, CodeBlockProps, CopyButton, CopyButtonProps } from "./markdown/code-block.js";
|
|
3
4
|
import { fenceInfo } from "./markdown/code-meta.js";
|
|
4
5
|
import { numericColumns, tableCsv } from "./markdown/markdown-table.js";
|
|
5
|
-
|
|
6
|
+
import { ApiSchema, ApiSchemaProps } from "./markdown/api-schema.js";
|
|
7
|
+
export { ApiSchema, type ApiSchemaProps, CodeBlock, type CodeBlockProps, CopyButton, type CopyButtonProps, Markdown, type MarkdownLinkChip, type MarkdownLinkChipResolver, type MarkdownProps, codeBlockGrammar, fenceInfo, getSanitizedMarkdownHeadingIdFromRawFragment, numericColumns, tableCsv };
|
package/dist/markdown.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { codeBlockGrammar } from "./lib/code-presentation.js";
|
|
2
|
+
import { CodeBlock, CopyButton } from "./markdown/code-block.js";
|
|
2
3
|
import { fenceInfo } from "./markdown/code-meta.js";
|
|
3
4
|
import { numericColumns, tableCsv } from "./markdown/markdown-table.js";
|
|
4
5
|
import { Markdown, getSanitizedMarkdownHeadingIdFromRawFragment } from "./markdown/markdown.js";
|
|
5
|
-
|
|
6
|
+
import { ApiSchema } from "./markdown/api-schema.js";
|
|
7
|
+
export { ApiSchema, CodeBlock, CopyButton, Markdown, codeBlockGrammar, fenceInfo, getSanitizedMarkdownHeadingIdFromRawFragment, numericColumns, tableCsv };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { controlMotion } from "../lib/motion.js";
|
|
1
2
|
import { ixControl, ixControlSoft, ixSelected } from "../lib/interaction.js";
|
|
2
3
|
import { focusRing } from "../lib/focus.js";
|
|
3
4
|
import { cn } from "../lib/utils.js";
|
|
@@ -6,7 +7,7 @@ import { Slot } from "@radix-ui/react-slot";
|
|
|
6
7
|
import * as React from "react";
|
|
7
8
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
9
|
//#region src/primitives/button.tsx
|
|
9
|
-
const bareButton = `${focusRing} ${ixControlSoft} disabled:pointer-events-none disabled:opacity-50 aria-disabled:cursor-not-allowed aria-disabled:opacity-50`;
|
|
10
|
+
const bareButton = `${focusRing} ${controlMotion} ${ixControlSoft} disabled:pointer-events-none disabled:opacity-50 aria-disabled:cursor-not-allowed aria-disabled:opacity-50`;
|
|
10
11
|
/** One Button render's classes: variant and size, the toggle states, then the caller's. */
|
|
11
12
|
function buttonClassName(variant, size, pressed, className) {
|
|
12
13
|
const toggle = pressed === void 0 ? void 0 : `${ixControl} ${ixSelected}`;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CodeBlock, CodeBlockProps, CopyButton } from "../markdown/code-block.js";
|
|
1
|
+
import { CodeBlock, CodeBlockProps, CopyButton, CopyButtonProps } from "../markdown/code-block.js";
|
|
2
2
|
//#region src/primitives/code-block.d.ts
|
|
3
3
|
export interface InlineCodeProps extends React.HTMLAttributes<HTMLElement> {}
|
|
4
4
|
export declare function InlineCode({ className, children, ...props }: InlineCodeProps): import("react").JSX.Element;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import { surfaceMotion } from "../lib/motion.js";
|
|
2
3
|
import { cn } from "../lib/utils.js";
|
|
4
|
+
import { SurfaceMotion } from "../lib/surface-motion.js";
|
|
3
5
|
import * as React from "react";
|
|
4
6
|
import { jsx } from "react/jsx-runtime";
|
|
5
7
|
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
@@ -13,12 +15,18 @@ const PopoverClose = PopoverPrimitive.Close;
|
|
|
13
15
|
* shadow as `DropdownMenuContent`. Width defaults to 18rem; pass a width class
|
|
14
16
|
* for wider content and keep long text wrapping inside it.
|
|
15
17
|
*/
|
|
16
|
-
const PopoverContent = React.forwardRef(({ className, align = "center", sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx(PopoverPrimitive.Content, {
|
|
18
|
+
const PopoverContent = React.forwardRef(({ className, align = "center", sideOffset = 4, asChild, children, ...props }, ref) => /* @__PURE__ */ jsx(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx(PopoverPrimitive.Content, {
|
|
17
19
|
ref,
|
|
18
20
|
align,
|
|
19
21
|
sideOffset,
|
|
20
|
-
className: cn("z-50 w-72 max-w-[calc(100vw-2rem)] origin-(--radix-popover-content-transform-origin) rounded-xl border border-border bg-card p-4 text-foreground shadow-[var(--shadow-card)] outline-hidden",
|
|
21
|
-
...props
|
|
22
|
+
className: cn("z-50 w-72 max-w-[calc(100vw-2rem)] origin-(--radix-popover-content-transform-origin) rounded-xl border border-border bg-card p-4 text-foreground shadow-[var(--shadow-card)] outline-hidden", surfaceMotion, className),
|
|
23
|
+
...props,
|
|
24
|
+
asChild: true,
|
|
25
|
+
children: /* @__PURE__ */ jsx(SurfaceMotion, {
|
|
26
|
+
kind: "popover",
|
|
27
|
+
asChild,
|
|
28
|
+
children
|
|
29
|
+
})
|
|
22
30
|
}) }));
|
|
23
31
|
PopoverContent.displayName = PopoverPrimitive.Content.displayName;
|
|
24
32
|
//#endregion
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
//#region src/primitives/wizard.d.ts
|
|
3
|
+
export interface WizardProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
4
|
+
children: React.ReactNode;
|
|
5
|
+
/** Drives the active step; omit for uncontrolled with `defaultStep`. */
|
|
6
|
+
step?: number;
|
|
7
|
+
defaultStep?: number;
|
|
8
|
+
onStepChange?: (step: number) => void;
|
|
9
|
+
/** Fires when the last step's primary action resolves. */
|
|
10
|
+
onFinished?: () => void;
|
|
11
|
+
}
|
|
12
|
+
export declare function Wizard({ children, step, defaultStep, onStepChange, onFinished, className, ...rest }: WizardProps): React.JSX.Element;
|
|
13
|
+
export interface WizardStepProps {
|
|
14
|
+
/** Shown in the rail (and the mobile position line). Steps read at a glance; keep it one or two words. */
|
|
15
|
+
title: string;
|
|
16
|
+
children: React.ReactNode;
|
|
17
|
+
/** The footer's primary action label. Omit when the step renders its own actions. */
|
|
18
|
+
nextLabel?: string;
|
|
19
|
+
/** Runs before advancing. Resolve (or return a non-false value) to advance; return false or throw to stay — the step's own content shows why. */
|
|
20
|
+
onNext?: () => Promise<unknown> | unknown;
|
|
21
|
+
/** Disables the primary action (a required choice is still missing). */
|
|
22
|
+
nextDisabled?: boolean;
|
|
23
|
+
/** Hides the Back button for steps where going back makes no sense (a completed handshake). */
|
|
24
|
+
hideBack?: boolean;
|
|
25
|
+
}
|
|
26
|
+
export declare function WizardStep({ title, children, nextLabel, onNext, nextDisabled, hideBack }: WizardStepProps): React.JSX.Element;
|
|
27
|
+
export interface Wizard extends React.FC<WizardProps> {
|
|
28
|
+
Step: typeof WizardStep;
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|