@tangle-network/ui 11.16.9 → 11.16.10
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
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @tangle-network/ui
|
|
2
2
|
|
|
3
|
+
## 11.16.10
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 06b665d: A closed terminal command is two lines of plain text that end in an ellipsis when cut, with the whole command in its title, so a reader can see that text is missing. Terminal output wraps on every width again: scrolling it sideways on a phone clipped columns with no sign that more was there.
|
|
8
|
+
|
|
3
9
|
## 11.16.9
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
|
@@ -19,10 +19,6 @@ export interface CommandPreviewProps {
|
|
|
19
19
|
* dark terminal. It scopes the dark token set onto itself with
|
|
20
20
|
* `data-theme="dark"`, so stderr, the badges and the muted prompt keep the
|
|
21
21
|
* contrast they were designed with on a dark ground, in a light console too.
|
|
22
|
-
*
|
|
23
|
-
* On a phone the output keeps its own lines and scrolls sideways inside the
|
|
24
|
-
* block: wrapped output breaks the columns of a listing and splits hashes
|
|
25
|
-
* and URLs mid-token. The command still wraps between its tokens.
|
|
26
22
|
*/
|
|
27
23
|
export declare const CommandPreview: import("react").MemoExoticComponent<({ part, defaultExpanded, className }: CommandPreviewProps) => import("react").JSX.Element>;
|
|
28
24
|
//#endregion
|
|
@@ -138,20 +138,12 @@ function ExitBadge({ output, status }) {
|
|
|
138
138
|
children: label
|
|
139
139
|
});
|
|
140
140
|
}
|
|
141
|
-
|
|
142
|
-
* A command split at its whitespace, each token in an inline box. Browsers
|
|
143
|
-
* break after a hyphen, which split `--short` into `--` and `short` on a
|
|
144
|
-
* phone. A box moves to the next line whole, and breaks inside only when it
|
|
145
|
-
* is wider than the line (a full SHA). The text is unchanged, so a copy still
|
|
146
|
-
* pastes the exact command.
|
|
147
|
-
*/
|
|
148
|
-
function CommandText({ command, all }) {
|
|
141
|
+
function CommandText({ command }) {
|
|
149
142
|
const tokens = command.split(/(\s+)/);
|
|
150
|
-
|
|
151
|
-
return /* @__PURE__ */ jsxs(Fragment$1, { children: [tokens.slice(0, limit).map((token, i) => token.length > 0 && !/\s/.test(token) ? /* @__PURE__ */ jsx("span", {
|
|
143
|
+
return /* @__PURE__ */ jsx(Fragment$1, { children: tokens.map((token, i) => token.length > 0 && !/\s/.test(token) ? /* @__PURE__ */ jsx("span", {
|
|
152
144
|
className: "inline-block max-w-full [overflow-wrap:anywhere]",
|
|
153
145
|
children: token
|
|
154
|
-
}, i) : token)
|
|
146
|
+
}, i) : token) });
|
|
155
147
|
}
|
|
156
148
|
/**
|
|
157
149
|
* One shell command as a terminal block: a `$ command` prompt line with its
|
|
@@ -162,10 +154,6 @@ function CommandText({ command, all }) {
|
|
|
162
154
|
* dark terminal. It scopes the dark token set onto itself with
|
|
163
155
|
* `data-theme="dark"`, so stderr, the badges and the muted prompt keep the
|
|
164
156
|
* contrast they were designed with on a dark ground, in a light console too.
|
|
165
|
-
*
|
|
166
|
-
* On a phone the output keeps its own lines and scrolls sideways inside the
|
|
167
|
-
* block: wrapped output breaks the columns of a listing and splits hashes
|
|
168
|
-
* and URLs mid-token. The command still wraps between its tokens.
|
|
169
157
|
*/
|
|
170
158
|
const CommandPreview = memo(({ part, defaultExpanded = false, className }) => {
|
|
171
159
|
const [expanded, setExpanded] = useState(defaultExpanded);
|
|
@@ -183,11 +171,9 @@ const CommandPreview = memo(({ part, defaultExpanded = false, className }) => {
|
|
|
183
171
|
children: "$"
|
|
184
172
|
}),
|
|
185
173
|
/* @__PURE__ */ jsx("code", {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
all: expanded
|
|
190
|
-
})
|
|
174
|
+
title: expanded ? void 0 : command,
|
|
175
|
+
className: cn("min-w-0 flex-1 whitespace-pre-wrap [overflow-wrap:anywhere]", expanded ? "" : "line-clamp-2"),
|
|
176
|
+
children: expanded ? /* @__PURE__ */ jsx(CommandText, { command }) : command
|
|
191
177
|
}),
|
|
192
178
|
/* @__PURE__ */ jsx("span", {
|
|
193
179
|
className: "flex shrink-0 max-sm:order-last max-sm:basis-full max-sm:pl-4",
|
|
@@ -226,21 +212,21 @@ const CommandPreview = memo(({ part, defaultExpanded = false, className }) => {
|
|
|
226
212
|
tabIndex: 0,
|
|
227
213
|
role: "region",
|
|
228
214
|
"aria-label": "stdout",
|
|
229
|
-
className: cn("max-h-80 overflow-auto whitespace-pre-wrap [overflow-wrap:anywhere]
|
|
215
|
+
className: cn("max-h-80 overflow-auto whitespace-pre-wrap [overflow-wrap:anywhere] px-3 py-2 leading-relaxed", focusRing),
|
|
230
216
|
children: output.stdout
|
|
231
217
|
}) : null,
|
|
232
218
|
output.stderr ? /* @__PURE__ */ jsx("pre", {
|
|
233
219
|
tabIndex: 0,
|
|
234
220
|
role: "region",
|
|
235
221
|
"aria-label": "stderr",
|
|
236
|
-
className: cn("max-h-80 overflow-auto whitespace-pre-wrap [overflow-wrap:anywhere]
|
|
222
|
+
className: cn("max-h-80 overflow-auto whitespace-pre-wrap [overflow-wrap:anywhere] border-t border-white/10 px-3 py-2 leading-relaxed text-[var(--surface-danger-text)]", focusRing),
|
|
237
223
|
children: output.stderr
|
|
238
224
|
}) : null,
|
|
239
225
|
errorText ? /* @__PURE__ */ jsx("pre", {
|
|
240
226
|
tabIndex: 0,
|
|
241
227
|
role: "region",
|
|
242
228
|
"aria-label": "error",
|
|
243
|
-
className: cn("max-h-80 overflow-auto whitespace-pre-wrap [overflow-wrap:anywhere]
|
|
229
|
+
className: cn("max-h-80 overflow-auto whitespace-pre-wrap [overflow-wrap:anywhere] border-t border-white/10 px-3 py-2 leading-relaxed text-[var(--surface-danger-text)]", focusRing),
|
|
244
230
|
children: errorText
|
|
245
231
|
}) : null
|
|
246
232
|
]
|
package/package.json
CHANGED
|
@@ -30,8 +30,9 @@ describe("CommandPreview", () => {
|
|
|
30
30
|
expect(screen.getByText("exit 2").className).toContain("surface-danger");
|
|
31
31
|
});
|
|
32
32
|
|
|
33
|
-
it("boxes each token so a phone wraps between flags", () => {
|
|
33
|
+
it("boxes each token of an opened command so a phone wraps between flags", () => {
|
|
34
34
|
render(<CommandPreview part={part({ output: "M a" })} />);
|
|
35
|
+
fireEvent.click(screen.getByRole("button"));
|
|
35
36
|
const flag = screen.getByText("--short");
|
|
36
37
|
expect(flag.tagName).toBe("SPAN");
|
|
37
38
|
expect(flag.className).toContain("inline-block");
|
|
@@ -61,6 +62,14 @@ describe("CommandPreview", () => {
|
|
|
61
62
|
expect(screen.getByText("exit 0 · tool reported error").className).toContain("surface-warning");
|
|
62
63
|
});
|
|
63
64
|
|
|
65
|
+
it("shows a closed command as plain text that ends in an ellipsis, whole in its title", () => {
|
|
66
|
+
render(<CommandPreview part={part({ output: "M a" })} />);
|
|
67
|
+
const code = screen.getByTestId("command-preview").querySelector("code");
|
|
68
|
+
expect(code?.className).toContain("line-clamp-2");
|
|
69
|
+
expect(code).toHaveAttribute("title", "git status --short");
|
|
70
|
+
expect(code?.querySelector("span")).toBeNull();
|
|
71
|
+
});
|
|
72
|
+
|
|
64
73
|
it("is a quiet row until opened, then a dark terminal", () => {
|
|
65
74
|
render(<CommandPreview part={part({ output: "M a" })} />);
|
|
66
75
|
const block = screen.getByTestId("command-preview");
|
|
@@ -187,23 +187,11 @@ function ExitBadge({
|
|
|
187
187
|
);
|
|
188
188
|
}
|
|
189
189
|
|
|
190
|
-
|
|
191
|
-
* box; a long script renders the rest as plain text. */
|
|
192
|
-
const BOXED_TOKENS = 64;
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* A command split at its whitespace, each token in an inline box. Browsers
|
|
196
|
-
* break after a hyphen, which split `--short` into `--` and `short` on a
|
|
197
|
-
* phone. A box moves to the next line whole, and breaks inside only when it
|
|
198
|
-
* is wider than the line (a full SHA). The text is unchanged, so a copy still
|
|
199
|
-
* pastes the exact command.
|
|
200
|
-
*/
|
|
201
|
-
function CommandText({ command, all }: { command: string; all: boolean }) {
|
|
190
|
+
function CommandText({ command }: { command: string }) {
|
|
202
191
|
const tokens = command.split(/(\s+)/);
|
|
203
|
-
const limit = all ? tokens.length : BOXED_TOKENS * 2;
|
|
204
192
|
return (
|
|
205
193
|
<>
|
|
206
|
-
{tokens.
|
|
194
|
+
{tokens.map((token, i) =>
|
|
207
195
|
token.length > 0 && !/\s/.test(token) ? (
|
|
208
196
|
// Tokens repeat (two spaces, two "&&"), so position is the key.
|
|
209
197
|
<span key={i} className="inline-block max-w-full [overflow-wrap:anywhere]">
|
|
@@ -213,7 +201,6 @@ function CommandText({ command, all }: { command: string; all: boolean }) {
|
|
|
213
201
|
token
|
|
214
202
|
),
|
|
215
203
|
)}
|
|
216
|
-
{limit < tokens.length ? tokens.slice(limit).join("") : null}
|
|
217
204
|
</>
|
|
218
205
|
);
|
|
219
206
|
}
|
|
@@ -227,10 +214,6 @@ function CommandText({ command, all }: { command: string; all: boolean }) {
|
|
|
227
214
|
* dark terminal. It scopes the dark token set onto itself with
|
|
228
215
|
* `data-theme="dark"`, so stderr, the badges and the muted prompt keep the
|
|
229
216
|
* contrast they were designed with on a dark ground, in a light console too.
|
|
230
|
-
*
|
|
231
|
-
* On a phone the output keeps its own lines and scrolls sideways inside the
|
|
232
|
-
* block: wrapped output breaks the columns of a listing and splits hashes
|
|
233
|
-
* and URLs mid-token. The command still wraps between its tokens.
|
|
234
217
|
*/
|
|
235
218
|
export const CommandPreview = memo(
|
|
236
219
|
({ part, defaultExpanded = false, className }: CommandPreviewProps) => {
|
|
@@ -260,15 +243,16 @@ export const CommandPreview = memo(
|
|
|
260
243
|
$
|
|
261
244
|
</span>
|
|
262
245
|
<code
|
|
246
|
+
title={expanded ? undefined : command}
|
|
263
247
|
className={cn(
|
|
264
248
|
"min-w-0 flex-1 whitespace-pre-wrap [overflow-wrap:anywhere]",
|
|
265
|
-
// Closed, two lines of
|
|
266
|
-
//
|
|
267
|
-
//
|
|
268
|
-
expanded ? "" : "
|
|
249
|
+
// Closed, two lines of plain text that end in an ellipsis when
|
|
250
|
+
// cut, with the whole command in the title. Opened, each token
|
|
251
|
+
// is a box that wraps whole (line-clamp does not count boxes).
|
|
252
|
+
expanded ? "" : "line-clamp-2",
|
|
269
253
|
)}
|
|
270
254
|
>
|
|
271
|
-
<CommandText command={command}
|
|
255
|
+
{expanded ? <CommandText command={command} /> : command}
|
|
272
256
|
</code>
|
|
273
257
|
{/* On a phone the badge takes its own line under the command, so the
|
|
274
258
|
command keeps the row's width. */}
|
|
@@ -326,7 +310,7 @@ export const CommandPreview = memo(
|
|
|
326
310
|
role="region"
|
|
327
311
|
aria-label="stdout"
|
|
328
312
|
className={cn(
|
|
329
|
-
"max-h-80 overflow-auto whitespace-pre-wrap [overflow-wrap:anywhere]
|
|
313
|
+
"max-h-80 overflow-auto whitespace-pre-wrap [overflow-wrap:anywhere] px-3 py-2 leading-relaxed",
|
|
330
314
|
focusRing,
|
|
331
315
|
)}
|
|
332
316
|
>
|
|
@@ -339,7 +323,7 @@ export const CommandPreview = memo(
|
|
|
339
323
|
role="region"
|
|
340
324
|
aria-label="stderr"
|
|
341
325
|
className={cn(
|
|
342
|
-
"max-h-80 overflow-auto whitespace-pre-wrap [overflow-wrap:anywhere]
|
|
326
|
+
"max-h-80 overflow-auto whitespace-pre-wrap [overflow-wrap:anywhere] border-t border-white/10 px-3 py-2 leading-relaxed text-[var(--surface-danger-text)]",
|
|
343
327
|
focusRing,
|
|
344
328
|
)}
|
|
345
329
|
>
|
|
@@ -352,7 +336,7 @@ export const CommandPreview = memo(
|
|
|
352
336
|
role="region"
|
|
353
337
|
aria-label="error"
|
|
354
338
|
className={cn(
|
|
355
|
-
"max-h-80 overflow-auto whitespace-pre-wrap [overflow-wrap:anywhere]
|
|
339
|
+
"max-h-80 overflow-auto whitespace-pre-wrap [overflow-wrap:anywhere] border-t border-white/10 px-3 py-2 leading-relaxed text-[var(--surface-danger-text)]",
|
|
356
340
|
focusRing,
|
|
357
341
|
)}
|
|
358
342
|
>
|