@danxbot/ui 3.9.0 → 3.10.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/dist/index.js +5430 -5116
- package/dist/index.js.map +1 -1
- package/dist/types/components/InlineEdit.d.ts +141 -0
- package/dist/types/components/Table.d.ts +10 -2
- package/dist/types/components/Toggle.d.ts +40 -4
- package/dist/types/components/chat/Attachment.d.ts +47 -0
- package/dist/types/index.d.ts +2 -1
- package/package.json +3 -3
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { type Ref } from "react";
|
|
2
|
+
import { useRender } from "@base-ui/react/use-render";
|
|
3
|
+
/**
|
|
4
|
+
* The caller's refusal of a value, with the reason that will be shown.
|
|
5
|
+
*
|
|
6
|
+
* ONE OBJECT RATHER THAN TWO LOOSE RETURNS — `false` plus a separate message
|
|
7
|
+
* prop, say — because those two can disagree: a refusal with no sentence beside
|
|
8
|
+
* it is the mute rejection this whole component exists to prevent, and a
|
|
9
|
+
* sentence with nothing refusing it is a lie. This library already settled that
|
|
10
|
+
* shape three times over: `StatusOption.refusal`, `KanbanLane.refusal` and
|
|
11
|
+
* `SettingRow.readOnly: { reason }`.
|
|
12
|
+
*
|
|
13
|
+
* Written for the person who typed it — "a demand with this name already
|
|
14
|
+
* exists", not "invalid". It is the only thing they will see.
|
|
15
|
+
*/
|
|
16
|
+
export interface InlineEditRefusal {
|
|
17
|
+
refusal: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* What `onCommit` may report. Returning nothing accepts the value.
|
|
21
|
+
*
|
|
22
|
+
* A REFUSAL IS NOT AN EXCEPTION, and keeping the two apart is the point: a
|
|
23
|
+
* refusal is the caller's rule saying no (shown as its own sentence, the field
|
|
24
|
+
* stays open for a correction), while a thrown error or a rejected promise is
|
|
25
|
+
* the save FAILING (shown as `failureMessage`, the same text kept, retryable).
|
|
26
|
+
* Folding them together would put a stack trace's message in front of an
|
|
27
|
+
* end user, or bury a real outage as a validation note.
|
|
28
|
+
*/
|
|
29
|
+
export type InlineEditOutcome = void | InlineEditRefusal;
|
|
30
|
+
export interface InlineEditProps {
|
|
31
|
+
/**
|
|
32
|
+
* The committed value. Controlled — this component never holds the truth,
|
|
33
|
+
* it only holds the draft while somebody is typing one.
|
|
34
|
+
*/
|
|
35
|
+
value: string;
|
|
36
|
+
/**
|
|
37
|
+
* Commit a new value. Called ONLY when the text actually differs from
|
|
38
|
+
* `value`; see the module comment.
|
|
39
|
+
*
|
|
40
|
+
* May return a promise, in which case the field stays open and pending until
|
|
41
|
+
* it settles. Resolve/return `{ refusal }` to reject the value with a reason;
|
|
42
|
+
* throw or reject to report that the save itself failed.
|
|
43
|
+
*
|
|
44
|
+
* A SERVER'S 422 IS A REFUSAL, NOT A FAILURE — catch it and resolve to
|
|
45
|
+
* `{ refusal: <what the server said> }`. A duplicate name is the caller's
|
|
46
|
+
* rule being applied by the only party who can check it, and it reads to the
|
|
47
|
+
* person exactly like the local one; a rejected promise means the write did
|
|
48
|
+
* not happen for a reason nobody can act on by retyping.
|
|
49
|
+
*/
|
|
50
|
+
onCommit: (value: string) => InlineEditOutcome | Promise<InlineEditOutcome>;
|
|
51
|
+
/**
|
|
52
|
+
* The refusals that are knowable WITHOUT a request. Return the reason, or
|
|
53
|
+
* `null` to accept.
|
|
54
|
+
*
|
|
55
|
+
* Runs after the unchanged check and before `onCommit`, so a value that fails
|
|
56
|
+
* here never reaches the network — which is the whole point of it being
|
|
57
|
+
* separate: emptiness and length are decidable locally, uniqueness is not,
|
|
58
|
+
* and a client that guesses at the second one drifts from the server.
|
|
59
|
+
*
|
|
60
|
+
* A BARE STRING RATHER THAN `{ refusal }`, unlike `onCommit`'s return, and
|
|
61
|
+
* the difference is not an inconsistency: `onCommit` has to say WHICH of
|
|
62
|
+
* accepted-or-refused happened, so the reason needs a name to sit under.
|
|
63
|
+
* Everything this function returns is the reason, which is the same position
|
|
64
|
+
* `StatusOption.refusal` and `KanbanLane.refusal` are already a bare string
|
|
65
|
+
* in. An empty string throws, for the reason those do.
|
|
66
|
+
*
|
|
67
|
+
* It is shown through exactly the same channel a refusal from `onCommit` is —
|
|
68
|
+
* the person is not told where in the stack their name was turned down.
|
|
69
|
+
*/
|
|
70
|
+
validate?: (value: string) => string | null;
|
|
71
|
+
/**
|
|
72
|
+
* The accessible name, in BOTH modes. REQUIRED — see the module comment on
|
|
73
|
+
* why a control that renames itself mid-interaction is the defect this
|
|
74
|
+
* prevents.
|
|
75
|
+
*
|
|
76
|
+
* Name the FIELD ("Demand title"), not the action ("Edit") and not the
|
|
77
|
+
* current value: it is read in a list of controls where the value is
|
|
78
|
+
* announced separately.
|
|
79
|
+
*/
|
|
80
|
+
label: string;
|
|
81
|
+
/**
|
|
82
|
+
* What the display shows in place of a blank value, and the field's
|
|
83
|
+
* placeholder.
|
|
84
|
+
*
|
|
85
|
+
* A WORD, not an em-dash, and not nothing: a display whose entire content is
|
|
86
|
+
* punctuation has no name worth announcing, and one whose content is empty
|
|
87
|
+
* collapses to a few pixels — a control that cannot be hit. See
|
|
88
|
+
* `scripts/probe-card-header.mjs` for the zero-width family this belongs to.
|
|
89
|
+
*/
|
|
90
|
+
placeholder?: string;
|
|
91
|
+
/** Box ramp. Matches `Input`'s names; see the recipe on why not its padding. */
|
|
92
|
+
size?: "sm" | "md" | "lg";
|
|
93
|
+
/**
|
|
94
|
+
* Edit as a `<textarea>` that grows with its content.
|
|
95
|
+
*
|
|
96
|
+
* THE COMMIT KEY MOVES, because Enter has to insert a newline. Enter is a
|
|
97
|
+
* newline, Cmd/Ctrl+Enter commits, Escape still cancels and blur still
|
|
98
|
+
* commits. Nothing else changes.
|
|
99
|
+
*/
|
|
100
|
+
multiline?: boolean;
|
|
101
|
+
/**
|
|
102
|
+
* This value cannot be edited at all, AND WHY — a different fact from a
|
|
103
|
+
* value being refused, and it belongs on a different prop. `{ reason }`
|
|
104
|
+
* matches `SettingRow.readOnly`; there is no boolean form, because a control
|
|
105
|
+
* that refuses in silence is indistinguishable from one that is broken.
|
|
106
|
+
*
|
|
107
|
+
* The display stays focusable and `aria-disabled`, carrying the reason as
|
|
108
|
+
* its description and in a tooltip, so it can be asked.
|
|
109
|
+
*/
|
|
110
|
+
readOnly?: {
|
|
111
|
+
reason: string;
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
* What is shown when the commit REJECTS. Deliberately not the error's own
|
|
115
|
+
* message: that text is written for a log, and this one is read by whoever
|
|
116
|
+
* just typed a name.
|
|
117
|
+
*
|
|
118
|
+
* @default "Could not save. Your text is still here — press Enter to try again."
|
|
119
|
+
*/
|
|
120
|
+
failureMessage?: string;
|
|
121
|
+
/**
|
|
122
|
+
* The rejected error, handed on so it can be logged or reported. Without
|
|
123
|
+
* this the exception is swallowed entirely, which is the silent failure this
|
|
124
|
+
* library treats as a defect rather than as tidiness.
|
|
125
|
+
*/
|
|
126
|
+
onError?: (error: unknown) => void;
|
|
127
|
+
/**
|
|
128
|
+
* Render the DISPLAY as a different element. See the module comment: the
|
|
129
|
+
* rendered element is given `role="button"`, which replaces its own role.
|
|
130
|
+
*/
|
|
131
|
+
render?: useRender.RenderProp;
|
|
132
|
+
/**
|
|
133
|
+
* Applied to BOTH forms, and there is only one of these on purpose. Anything
|
|
134
|
+
* that changes one box's geometry has to change the other's, or the control
|
|
135
|
+
* jumps on click — a second `fieldClassName` would make that jump one prop
|
|
136
|
+
* away at all times.
|
|
137
|
+
*/
|
|
138
|
+
className?: string;
|
|
139
|
+
ref?: Ref<HTMLElement>;
|
|
140
|
+
}
|
|
141
|
+
export declare function InlineEdit({ value, onCommit, validate, label, placeholder, size, multiline, readOnly, failureMessage, onError, render, className, ref, }: InlineEditProps): import("react").JSX.Element;
|
|
@@ -54,8 +54,16 @@ export interface DataTableProps<TData> {
|
|
|
54
54
|
* styling the table picked — `cn` is tailwind-merge, and the last conflicting
|
|
55
55
|
* utility wins. That is deliberate: a tint that loses to the zebra fill is a
|
|
56
56
|
* tint nobody sees. It also means a background handed over here REPLACES the
|
|
57
|
-
* row's hover fill, so pass the hover with it (`bg-
|
|
58
|
-
* hover:bg-
|
|
57
|
+
* row's hover fill, so pass the hover with it (`bg-danger-subtle
|
|
58
|
+
* hover:bg-danger-subtle-hover`) if the row should still respond.
|
|
59
|
+
*
|
|
60
|
+
* THAT EXAMPLE USED TO NAME `warning`, WHICH HAS NO HOVER STEP. `-subtle`
|
|
61
|
+
* exists for every semantic family; `-subtle-hover` exists for `accent` and
|
|
62
|
+
* `danger` only. A consumer following the old wording got a hover class that
|
|
63
|
+
* compiled to nothing — no rule, no fill, no error anywhere, which is the
|
|
64
|
+
* same silent-nothing failure the theme bridge in `postbuild-css.mjs` exists
|
|
65
|
+
* to prevent one level up. Pick a family that has the step, or supply the
|
|
66
|
+
* hover colour yourself. `token-parity.test.ts` now sweeps this docblock.
|
|
59
67
|
*
|
|
60
68
|
* `index` is the row's position in `data`, not on the current page — the same
|
|
61
69
|
* number `getRowId` receives, so the two never disagree about which row is
|
|
@@ -64,10 +64,31 @@ export declare function Toolbar({ className, children, ref, ...props }: ToolbarP
|
|
|
64
64
|
export declare function ToolbarSeparator({ className }: {
|
|
65
65
|
className?: string;
|
|
66
66
|
}): import("react").JSX.Element;
|
|
67
|
-
|
|
67
|
+
type ToolbarButtonBase = Omit<BaseToolbar.Button.Props, "className" | "nativeButton" | "render"> & {
|
|
68
68
|
className?: string;
|
|
69
69
|
ref?: Ref<HTMLButtonElement>;
|
|
70
|
-
}
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* TWO FORMS, AND THE TYPE REFUSES TO MIX THEM.
|
|
73
|
+
*
|
|
74
|
+
* Either this renders its own `<button>` and wears `buttonVariants` — in which
|
|
75
|
+
* case `variant` / `size` / `iconOnly` choose which row of that table — or it
|
|
76
|
+
* renders somebody else's control through `render`, in which case that control
|
|
77
|
+
* already carries a variant table and this one must not add a second. The two
|
|
78
|
+
* are mutually exclusive rather than merely discouraged, because a `render`
|
|
79
|
+
* plus a `size` is not a preference somebody expressed: it is two size classes
|
|
80
|
+
* in one attribute with no rule for which wins. See `ToolbarButton`'s own doc
|
|
81
|
+
* for the measurement.
|
|
82
|
+
*/
|
|
83
|
+
export type ToolbarButtonProps = (ToolbarButtonBase & Pick<ButtonProps, "variant" | "size" | "iconOnly"> & {
|
|
84
|
+
/** The styled form owns the element, so there is nothing to render into. */
|
|
85
|
+
render?: undefined;
|
|
86
|
+
}) | (ToolbarButtonBase & {
|
|
87
|
+
render: NonNullable<BaseToolbar.Button.Props["render"]>;
|
|
88
|
+
variant?: never;
|
|
89
|
+
size?: never;
|
|
90
|
+
iconOnly?: never;
|
|
91
|
+
});
|
|
71
92
|
/**
|
|
72
93
|
* A button that is part of the toolbar's rotation.
|
|
73
94
|
*
|
|
@@ -85,8 +106,23 @@ export interface ToolbarButtonProps extends Omit<BaseToolbar.Button.Props, "clas
|
|
|
85
106
|
* ANYTHING ALREADY BUILT ON `Button` GOES IN THROUGH `render`, which is what
|
|
86
107
|
* keeps this from becoming a second button component:
|
|
87
108
|
* `<ToolbarButton render={<IconButton icon={…} label="Bold" />} />` registers
|
|
88
|
-
* exactly the same
|
|
89
|
-
*
|
|
109
|
+
* exactly the same and keeps the tooltip and the `disabledReason`.
|
|
110
|
+
*
|
|
111
|
+
* THAT PATH APPLIES NO VARIANT TABLE AT ALL, and the type enforces it —
|
|
112
|
+
* `variant`, `size` and `iconOnly` are not accepted beside `render`. Base UI's
|
|
113
|
+
* render slot CONCATENATES `className`; it does not run `cn`. So a recipe
|
|
114
|
+
* applied here landed in the same attribute as the rendered component's own,
|
|
115
|
+
* and which one won was decided by Tailwind's emission order rather than by
|
|
116
|
+
* either component. It measured fine while the two happened to agree — a
|
|
117
|
+
* default `render={<IconButton/>}` came out 36×36, identical to a standalone
|
|
118
|
+
* one, while carrying both `aspect-square` and `px-3.5` — and broke visibly the
|
|
119
|
+
* moment they disagreed: `<ToolbarButton size="lg" render={<IconButton
|
|
120
|
+
* size="sm" …/>} />` carried `h-control-lg` AND `h-control-sm` and rendered
|
|
121
|
+
* 48 × 36 with 24px of padding, a squashed oval neither component asked for.
|
|
122
|
+
*
|
|
123
|
+
* Unrepresentable beats documented, and it is free to do NOW: nothing has
|
|
124
|
+
* adopted the pair yet, so narrowing the type costs nothing that removing the
|
|
125
|
+
* props after adoption would have cost.
|
|
90
126
|
*/
|
|
91
127
|
export declare function ToolbarButton({ variant, size, iconOnly, className, children, ref, ...props }: ToolbarButtonProps): import("react").JSX.Element;
|
|
92
128
|
export interface ToolbarInputProps extends Omit<InputProps, "ref">, Pick<BaseToolbar.Input.Props, "focusableWhenDisabled"> {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type ReactNode, type Ref } from "react";
|
|
2
2
|
import type { ChatFile } from "./types";
|
|
3
|
+
import type { IconName } from "../Icon";
|
|
3
4
|
export type AttachmentLayout = "tile" | "row";
|
|
4
5
|
export interface AttachmentProps {
|
|
5
6
|
file: ChatFile;
|
|
@@ -24,6 +25,13 @@ export interface AttachmentProps {
|
|
|
24
25
|
* It goes inside the cluster, above the full-card preview trigger — rendered
|
|
25
26
|
* anywhere else it would sit UNDER that trigger and never receive a click.
|
|
26
27
|
* Keep it to a control or two: this is a corner of a tile, not a menu bar.
|
|
28
|
+
*
|
|
29
|
+
* FILL IT WITH `AttachmentAction`, which is exported for exactly this. The
|
|
30
|
+
* built-in download and remove are that component, so anything else lands in
|
|
31
|
+
* the cluster at a different size and, on a tile, without the hover fade the
|
|
32
|
+
* two beside it have. Any node is accepted — the slot has no opinion — but
|
|
33
|
+
* "matches the built-ins" is a real requirement and there is no way to hit it
|
|
34
|
+
* by hand. Pass `tinted` when `layout` is `"tile"`.
|
|
27
35
|
*/
|
|
28
36
|
action?: ReactNode;
|
|
29
37
|
onRemove?: (file: ChatFile) => void;
|
|
@@ -36,6 +44,45 @@ export interface AttachmentProps {
|
|
|
36
44
|
ref?: Ref<HTMLDivElement>;
|
|
37
45
|
}
|
|
38
46
|
export declare function Attachment({ file, layout, meta, action, onRemove, onPreview, onDownload, selected, disabled, className, ref, }: AttachmentProps): import("react").JSX.Element;
|
|
47
|
+
export interface AttachmentActionProps {
|
|
48
|
+
icon: IconName;
|
|
49
|
+
/** The accessible name AND the tooltip. Include the file: "Extract report.pdf". */
|
|
50
|
+
label: string;
|
|
51
|
+
onClick: () => void;
|
|
52
|
+
disabled?: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* On a tile the buttons sit over imagery, so they need their own ground —
|
|
55
|
+
* and they FADE IN on hover rather than sitting permanently over the picture.
|
|
56
|
+
*
|
|
57
|
+
* Pass `layout === "tile"`. Getting it wrong is not a style preference: a
|
|
58
|
+
* tinted control on a row is dark-on-dark, and an untinted one on a tile is
|
|
59
|
+
* a grey glyph over an arbitrary photograph.
|
|
60
|
+
*/
|
|
61
|
+
tinted?: boolean;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* One control in an attachment's action cluster.
|
|
65
|
+
*
|
|
66
|
+
* THE CONTROL `Attachment.action` IS MEANT TO BE FILLED WITH, and until now it
|
|
67
|
+
* was module-private — so the slot existed with nothing in the library that
|
|
68
|
+
* fits it. A consumer's own `IconButton` is a different size and a different
|
|
69
|
+
* resting state, and on a tile it does not fade in on `group-hover/attachment`
|
|
70
|
+
* with the built-in download and remove beside it, so the one control the
|
|
71
|
+
* consumer added was the one that looked wrong.
|
|
72
|
+
*
|
|
73
|
+
* It is deliberately NOT `IconButton`: `size-6` rather than a control height,
|
|
74
|
+
* no ripple, no `disabledReason`, and a tinted variant that only means anything
|
|
75
|
+
* inside `.group/attachment`. That is a corner-of-a-tile control, not a general
|
|
76
|
+
* one, and generalising it would give the cluster two different buttons again.
|
|
77
|
+
*
|
|
78
|
+
* <Attachment
|
|
79
|
+
* file={file}
|
|
80
|
+
* layout="tile"
|
|
81
|
+
* action={<AttachmentAction icon="sparkles" label={`Extract ${file.name}`}
|
|
82
|
+
* onClick={() => extract(file)} tinted />}
|
|
83
|
+
* />
|
|
84
|
+
*/
|
|
85
|
+
export declare function AttachmentAction({ icon, label, onClick, disabled, tinted, }: AttachmentActionProps): import("react").JSX.Element;
|
|
39
86
|
export interface AttachmentPreviewProps {
|
|
40
87
|
file: ChatFile | null;
|
|
41
88
|
onOpenChange: (open: boolean) => void;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -21,6 +21,7 @@ export { Skeleton, SkeletonText, LoadingOverlay, type SkeletonProps, type Skelet
|
|
|
21
21
|
export { ErrorBoundary } from "./components/ErrorBoundary";
|
|
22
22
|
export { Field, FieldSet, type FieldProps, type FieldSetProps } from "./components/Field";
|
|
23
23
|
export { Input, Textarea, type InputProps, type TextareaProps } from "./components/Input";
|
|
24
|
+
export { InlineEdit, type InlineEditProps, type InlineEditRefusal, type InlineEditOutcome, } from "./components/InlineEdit";
|
|
24
25
|
export { SecretField, type SecretFieldProps, type SecretValue } from "./components/SecretField";
|
|
25
26
|
export { SettingRow, SettingGroup, type SettingRowProps, type SettingGroupProps, type SettingRowControlRenderProps, } from "./components/SettingRow";
|
|
26
27
|
export { ConnectionCard, type ConnectionCardProps, type ConnectionHealth, } from "./components/ConnectionCard";
|
|
@@ -85,7 +86,7 @@ export { Message, MessagePartView, ToolCall, ChatMarker, type MessageProps, type
|
|
|
85
86
|
export { MessageScroller, type MessageScrollerProps, } from "./components/chat/MessageScroller";
|
|
86
87
|
export { Composer, type ComposerProps } from "./components/chat/Composer";
|
|
87
88
|
export { Markdown, CodeBlock, type MarkdownProps, type CodeBlockProps } from "./components/chat/Markdown";
|
|
88
|
-
export { Attachment, AttachmentList, AttachmentPreview, type AttachmentProps, type AttachmentListProps, type AttachmentPreviewProps, type AttachmentLayout, } from "./components/chat/Attachment";
|
|
89
|
+
export { Attachment, AttachmentAction, AttachmentList, AttachmentPreview, type AttachmentProps, type AttachmentActionProps, type AttachmentListProps, type AttachmentPreviewProps, type AttachmentLayout, } from "./components/chat/Attachment";
|
|
89
90
|
export { ModelSelector, type ModelSelectorProps, type ChatModel, } from "./components/chat/ModelSelector";
|
|
90
91
|
export { EffortControl, DEFAULT_EFFORT_LEVELS, type EffortControlProps, type EffortLevel, } from "./components/chat/EffortControl";
|
|
91
92
|
export { ContextMeter, ChatStatus, type ContextMeterProps, type ContextSegment, type UsageLimit, type ChatStatusProps, } from "./components/chat/ContextMeter";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@danxbot/ui",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.10.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Danxbot — a domain-agnostic React design system with motion as a first-class primitive.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -66,14 +66,14 @@
|
|
|
66
66
|
"build:types": "tsc -p tsconfig.build.json",
|
|
67
67
|
"build:demo": "vite build",
|
|
68
68
|
"build": "npm run build:lib && npm run build:demo",
|
|
69
|
-
"verify": "npm run typecheck && npm run
|
|
69
|
+
"verify": "npm run typecheck && npm run build && npm run test && npm run typecheck:previews && npm run audit:previews && npm run audit:visual-stale",
|
|
70
70
|
"audit:visual-stale": "node scripts/audit-visual-stale.mjs",
|
|
71
71
|
"preview": "vite preview",
|
|
72
72
|
"preview:built": "vite preview --outDir demo-dist --port 5801 --strictPort",
|
|
73
73
|
"gates": "npm run shoot && npm run a11y && node scripts/shoot-overlays.mjs && npm run probe",
|
|
74
74
|
"a11y": "node scripts/a11y-scan.mjs",
|
|
75
75
|
"shoot": "node scripts/shoot.mjs",
|
|
76
|
-
"probe": "node scripts/probe-scale.mjs && node scripts/probe-switch.mjs && node scripts/probe-slider.mjs && node scripts/probe-panel.mjs && node scripts/probe-popover-width.mjs && node scripts/probe-api.mjs && node scripts/probe-api-live.mjs && node scripts/probe-tabs-overflow.mjs && node scripts/probe-stat-row.mjs && node scripts/probe-packaging.mjs && node scripts/probe-containment.mjs && node scripts/probe-shell.mjs && node scripts/probe-card-header.mjs",
|
|
76
|
+
"probe": "node scripts/probe-scale.mjs && node scripts/probe-switch.mjs && node scripts/probe-slider.mjs && node scripts/probe-panel.mjs && node scripts/probe-popover-width.mjs && node scripts/probe-api.mjs && node scripts/probe-api-live.mjs && node scripts/probe-tabs-overflow.mjs && node scripts/probe-stat-row.mjs && node scripts/probe-packaging.mjs && node scripts/probe-containment.mjs && node scripts/probe-shell.mjs && node scripts/probe-card-header.mjs && node scripts/probe-inline-edit.mjs",
|
|
77
77
|
"sync": "node scripts/sync.mjs",
|
|
78
78
|
"visual": "node scripts/visual-docker.mjs",
|
|
79
79
|
"visual:update": "node scripts/visual-docker.mjs --update-snapshots",
|