@w6w/ui 0.0.0-stage → 0.1.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 +48 -0
- package/LICENSE +21 -0
- package/README.md +260 -2
- package/dist/ActionTestForm.d.ts +76 -0
- package/dist/AddConnectionModal.d.ts +24 -0
- package/dist/AppPicker.d.ts +83 -0
- package/dist/CodeBlock-CZu4TFSi.cjs +15 -0
- package/dist/CodeBlock-CZu4TFSi.cjs.map +1 -0
- package/dist/CodeBlock-Dot3Pd7P.js +2889 -0
- package/dist/CodeBlock-Dot3Pd7P.js.map +1 -0
- package/dist/CodeBlock.d.ts +65 -0
- package/dist/CodeEditor.d.ts +42 -0
- package/dist/ConfirmModal-DJPYXE9t.cjs +11 -0
- package/dist/ConfirmModal-DJPYXE9t.cjs.map +1 -0
- package/dist/ConfirmModal-sY1tzkBO.js +6335 -0
- package/dist/ConfirmModal-sY1tzkBO.js.map +1 -0
- package/dist/Copyable-1niV9gUa.js +771 -0
- package/dist/Copyable-1niV9gUa.js.map +1 -0
- package/dist/Copyable-CYZU1o4X.cjs +2 -0
- package/dist/Copyable-CYZU1o4X.cjs.map +1 -0
- package/dist/JsonEditor.d.ts +60 -0
- package/dist/NodeConfigForm.d.ts +70 -0
- package/dist/ParamsForm.d.ts +56 -0
- package/dist/PropertyEntryForm.d.ts +56 -0
- package/dist/RetryPolicyFields.d.ts +18 -0
- package/dist/StepBuilderModal.d.ts +375 -0
- package/dist/TriggerFillForm.d.ts +52 -0
- package/dist/WaitEditor.d.ts +6 -0
- package/dist/WorkflowFlowEditor.d.ts +119 -0
- package/dist/YamlEditor.d.ts +46 -0
- package/dist/app-categories.d.ts +38 -0
- package/dist/app-pages.d.ts +111 -0
- package/dist/code.cjs +2 -0
- package/dist/code.cjs.map +1 -0
- package/dist/code.d.ts +29 -0
- package/dist/code.mjs +7 -0
- package/dist/code.mjs.map +1 -0
- package/dist/components/ApiCallsPanel.d.ts +41 -0
- package/dist/components/AppIcon.d.ts +25 -0
- package/dist/components/AuthFieldsForm.d.ts +22 -0
- package/dist/components/Combobox.d.ts +24 -0
- package/dist/components/ConfirmModal.d.ts +33 -0
- package/dist/components/Copyable.d.ts +51 -0
- package/dist/components/CopyableText.d.ts +40 -0
- package/dist/components/DeleteButton.d.ts +16 -0
- package/dist/components/EditButton.d.ts +10 -0
- package/dist/components/ExecutionDetail.d.ts +70 -0
- package/dist/components/ExecutionFilters.d.ts +59 -0
- package/dist/components/ExecutionList.d.ts +60 -0
- package/dist/components/ExecutionLogPanel.d.ts +98 -0
- package/dist/components/ExecutionStats.d.ts +47 -0
- package/dist/components/ExpressionEditorModal.d.ts +42 -0
- package/dist/components/ExpressionInput.d.ts +36 -0
- package/dist/components/ExpressionOptions.d.ts +185 -0
- package/dist/components/HealthStatusPill.d.ts +25 -0
- package/dist/components/HistoryTimeline.d.ts +56 -0
- package/dist/components/Icon.d.ts +34 -0
- package/dist/components/IconButton.d.ts +60 -0
- package/dist/components/InfoTip.d.ts +15 -0
- package/dist/components/InternalIcon.d.ts +19 -0
- package/dist/components/ListItem.d.ts +25 -0
- package/dist/components/Modal.d.ts +29 -0
- package/dist/components/RepoSyncIndicator.d.ts +29 -0
- package/dist/components/ResolvedParams.d.ts +31 -0
- package/dist/components/ServerResources.d.ts +47 -0
- package/dist/components/StepStatusPill.d.ts +51 -0
- package/dist/components/UptimeStrip.d.ts +56 -0
- package/dist/components/execution-format.d.ts +24 -0
- package/dist/components/expression-dom.d.ts +154 -0
- package/dist/components/expression-template.d.ts +86 -0
- package/dist/components/history-scale.d.ts +33 -0
- package/dist/components/icons.d.ts +41 -0
- package/dist/components/resolved-clip.d.ts +42 -0
- package/dist/components/server-resources-format.d.ts +68 -0
- package/dist/components/server-resources.fixture.d.ts +9 -0
- package/dist/components/use-copy.d.ts +14 -0
- package/dist/createW6WApi.d.ts +31 -0
- package/dist/flow-connect.d.ts +138 -0
- package/dist/flow-fanout.d.ts +15 -0
- package/dist/flow-types.d.ts +356 -0
- package/dist/flow-utils.d.ts +284 -0
- package/dist/flow.cjs +3 -0
- package/dist/flow.cjs.map +1 -0
- package/dist/flow.d.ts +22 -0
- package/dist/flow.mjs +1977 -0
- package/dist/flow.mjs.map +1 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +94 -0
- package/dist/index.mjs +1811 -0
- package/dist/index.mjs.map +1 -0
- package/dist/oauth-popup.d.ts +17 -0
- package/dist/output-shape.d.ts +58 -0
- package/dist/provider.d.ts +420 -0
- package/dist/resolve-params.d.ts +112 -0
- package/dist/resolved-json.d.ts +21 -0
- package/dist/run-visuals.d.ts +90 -0
- package/dist/step-preview-state.d.ts +143 -0
- package/dist/theme.d.ts +32 -0
- package/dist/trigger-fields.d.ts +56 -0
- package/dist/types.d.ts +413 -0
- package/dist/ui.css +1 -0
- package/dist/use-app-action-defs.d.ts +7 -0
- package/dist/use-enter-submit.d.ts +23 -0
- package/dist/use-seed-sources.d.ts +16 -0
- package/package.json +111 -3
- package/src/code.css +542 -0
- package/src/styles/_buttons.scss +38 -0
- package/src/styles/_chips.scss +210 -0
- package/src/styles/_code.scss +139 -0
- package/src/styles/_copyable.scss +147 -0
- package/src/styles/_data-vars.scss +38 -0
- package/src/styles/_execution-history.scss +282 -0
- package/src/styles/_execution-log.scss +178 -0
- package/src/styles/_expression-field.scss +65 -0
- package/src/styles/_expression-inline.scss +63 -0
- package/src/styles/_expression-modal.scss +292 -0
- package/src/styles/_fields.scss +161 -0
- package/src/styles/_flow.scss +217 -0
- package/src/styles/_fx.scss +158 -0
- package/src/styles/_health.scss +46 -0
- package/src/styles/_history-timeline.scss +156 -0
- package/src/styles/_icon-button.scss +22 -0
- package/src/styles/_icon.scss +15 -0
- package/src/styles/_icons.scss +31 -0
- package/src/styles/_incoming-state.scss +46 -0
- package/src/styles/_info-tip.scss +9 -0
- package/src/styles/_layout.scss +6 -0
- package/src/styles/_lists.scss +64 -0
- package/src/styles/_modal.scss +125 -0
- package/src/styles/_multiselect.scss +69 -0
- package/src/styles/_repo-sync-indicator.scss +99 -0
- package/src/styles/_scale.scss +70 -0
- package/src/styles/_sections.scss +36 -0
- package/src/styles/_server-resources.scss +163 -0
- package/src/styles/_step-builder.scss +376 -0
- package/src/styles/_step-config.scss +195 -0
- package/src/styles/_tabs.scss +54 -0
- package/src/styles/_tester.scss +111 -0
- package/src/styles/_tokens.scss +141 -0
- package/src/styles/_uptime.scss +61 -0
- package/src/styles.css +4208 -0
- package/src/styles.scss +61 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { StepMeta } from '../provider.tsx';
|
|
3
|
+
import { StepStatus } from './StepStatusPill.tsx';
|
|
4
|
+
/**
|
|
5
|
+
* A step's or run's failure, already normalised by the HOST from the workflow
|
|
6
|
+
* spec's `StepError` (`code`/`message`/`phase`/`retryable`). The panel never
|
|
7
|
+
* parses an `unknown` error itself — same "host owns the data" split as the
|
|
8
|
+
* rest of this file. Rendered in `TriggerFillForm`'s error visual: a
|
|
9
|
+
* `.w6w-result.w6w-error` box, an optional `<code>` badge line, then the message.
|
|
10
|
+
*/
|
|
11
|
+
export interface ExecutionLogError {
|
|
12
|
+
/** `StepError.code`. Optional: the host may normalise an error that carries no code. */
|
|
13
|
+
code?: string;
|
|
14
|
+
/** The human-readable reason. Never empty when the host supplies it. */
|
|
15
|
+
message: string;
|
|
16
|
+
/** `StepError.phase`, when known. Carried for the host; not rendered. */
|
|
17
|
+
phase?: string;
|
|
18
|
+
/** `StepError.retryable`, when known. Carried for the host; not rendered. */
|
|
19
|
+
retryable?: boolean;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* One entry of `RunState.stepErrors` — a step failure the run recorded and
|
|
23
|
+
* moved past (`onError: "continue-record"`, or a failure an error edge
|
|
24
|
+
* handled), so the run itself may still have succeeded.
|
|
25
|
+
*/
|
|
26
|
+
export interface ExecutionLogRecordedError {
|
|
27
|
+
/** The step the error belongs to. */
|
|
28
|
+
stepId: string;
|
|
29
|
+
/** Human-readable step name. Falls back to `stepId` when rendered. */
|
|
30
|
+
label?: string;
|
|
31
|
+
error: ExecutionLogError;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* One step's display row — an already-mapped, already-resolved slice of a
|
|
35
|
+
* `RunState`/`StepExecution` (workflow spec). The HOST maps its own run
|
|
36
|
+
* state into this shape (same "host owns the data, the panel is
|
|
37
|
+
* presentational" split `readOnly` already establishes elsewhere in this
|
|
38
|
+
* package) — this component never fetches, polls, or reaches for an SDK.
|
|
39
|
+
*/
|
|
40
|
+
export interface ExecutionLogStep {
|
|
41
|
+
/** Stable id for this row — typically the step id from the workflow definition. */
|
|
42
|
+
id: string;
|
|
43
|
+
/** Human-readable step name. Falls back to `id` when omitted. */
|
|
44
|
+
label?: string;
|
|
45
|
+
status: StepStatus;
|
|
46
|
+
/** ISO-8601 timestamp the step started, once it has. */
|
|
47
|
+
startedAt?: string;
|
|
48
|
+
/** ISO-8601 timestamp the step finished, once it has. */
|
|
49
|
+
finishedAt?: string;
|
|
50
|
+
/** The resolved input sent to the step's action, once it is known. */
|
|
51
|
+
input?: unknown;
|
|
52
|
+
/** The step's output, once it has one. */
|
|
53
|
+
output?: unknown;
|
|
54
|
+
/**
|
|
55
|
+
* What ran (`StepExecution.meta`): app, version, action and connection id. Shown as a
|
|
56
|
+
* Metadata block after Output. Absent or `null` ⇒ no block at all (R-12: no filler).
|
|
57
|
+
*/
|
|
58
|
+
meta?: StepMeta | null;
|
|
59
|
+
/**
|
|
60
|
+
* Why the step failed (`StepExecution.error`, "present on failed"). Rendered
|
|
61
|
+
* below the row's box and outside its lazy `<details>` body, so the reason
|
|
62
|
+
* reads without expanding the row.
|
|
63
|
+
*/
|
|
64
|
+
error?: ExecutionLogError;
|
|
65
|
+
}
|
|
66
|
+
export interface ExecutionLogPanelProps {
|
|
67
|
+
/** The run's steps, rendered in exactly this order — never re-sorted. */
|
|
68
|
+
steps: ExecutionLogStep[];
|
|
69
|
+
/** Shown instead of the list when `steps` is empty. */
|
|
70
|
+
emptyLabel?: ReactNode;
|
|
71
|
+
/**
|
|
72
|
+
* Supplied ⇒ the panel grows a header row carrying a dismiss control that
|
|
73
|
+
* calls this and nothing else (T1.1.1). Omitted ⇒ no header row at all, no
|
|
74
|
+
* extra DOM node. The panel still owns no run state — it only reports the
|
|
75
|
+
* click; the host decides what dismissing means.
|
|
76
|
+
*/
|
|
77
|
+
onDismiss?: () => void;
|
|
78
|
+
/**
|
|
79
|
+
* The run's own failure (`RunState.error`). Rendered below the dismiss head
|
|
80
|
+
* and above the steps — in the empty branch too, since a run that failed
|
|
81
|
+
* before any step ran has nothing else to say why.
|
|
82
|
+
*/
|
|
83
|
+
runError?: ExecutionLogError;
|
|
84
|
+
/**
|
|
85
|
+
* Step failures the run recorded and moved past (`RunState.stepErrors`),
|
|
86
|
+
* one error block each, in the order given, after `runError`.
|
|
87
|
+
*/
|
|
88
|
+
stepErrors?: ExecutionLogRecordedError[];
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Read-only log of a workflow run's steps, in the order given: each row is
|
|
92
|
+
* the step's status pill, its timing, and its resolved input/output.
|
|
93
|
+
*
|
|
94
|
+
* A pure display leaf — no data fetching, no polling, no layout media
|
|
95
|
+
* queries (the host docks the panel; see `_scale.scss`'s breakpoint
|
|
96
|
+
* docstring). Fills whatever box its host gives it.
|
|
97
|
+
*/
|
|
98
|
+
export declare function ExecutionLogPanel({ steps, emptyLabel, onDismiss, runError, stepErrors, }: ExecutionLogPanelProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* The aggregate numbers of a history view — the same rows the list shows,
|
|
4
|
+
* rolled up (D1: stats are computed over the same visibility the list uses, so
|
|
5
|
+
* the two can never disagree about who may see what).
|
|
6
|
+
*
|
|
7
|
+
* `succeeded`/`canceled` are carried even though the strip renders no card for
|
|
8
|
+
* them today: the host's payload has them, the breakdown is what a host needs
|
|
9
|
+
* for a chart or a chip row, and a host re-deriving them from the list would be
|
|
10
|
+
* computing the same total a second time.
|
|
11
|
+
*/
|
|
12
|
+
export interface ExecutionStatsValue {
|
|
13
|
+
/** Every run in the current filter — the denominator of `successRate`. */
|
|
14
|
+
total: number;
|
|
15
|
+
succeeded: number;
|
|
16
|
+
failed: number;
|
|
17
|
+
canceled: number;
|
|
18
|
+
/** Runs that are queued or running right now. `> 0` is what makes the
|
|
19
|
+
* `In flight` card exist at all. */
|
|
20
|
+
inFlight: number;
|
|
21
|
+
/** `0…1`, or `null` when the host has no rate to report (no runs at all —
|
|
22
|
+
* a rate over zero runs is not 0%). */
|
|
23
|
+
successRate: number | null;
|
|
24
|
+
/** Mean wall-clock duration of the FINISHED runs, or `null` when none has
|
|
25
|
+
* finished. */
|
|
26
|
+
avgDurationMs: number | null;
|
|
27
|
+
}
|
|
28
|
+
export interface ExecutionStatsProps {
|
|
29
|
+
/** The aggregate, or `null` while nothing has loaded yet — rendered as `—`
|
|
30
|
+
* per card rather than as a spinner, so the strip never changes height. */
|
|
31
|
+
stats: ExecutionStatsValue | null;
|
|
32
|
+
/** Caption above the cards, e.g. the window they cover ("Last 7 days").
|
|
33
|
+
* Omitted ⇒ no node at all. */
|
|
34
|
+
label?: ReactNode;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* A headline strip of run aggregates: one big value over a muted label per
|
|
38
|
+
* card.
|
|
39
|
+
*
|
|
40
|
+
* Promotes studio `DashboardPage.tsx`'s page-local `StatCard` into `ui`, with
|
|
41
|
+
* two differences that come from this being a shared component rather than one
|
|
42
|
+
* page's private helper: the values are pre-formatted here (a rate as `67%`, a
|
|
43
|
+
* duration through `formatDurationMs`) so every consumer renders the same
|
|
44
|
+
* string, and each card carries `data-stat-value` so a host can assert on the
|
|
45
|
+
* value without re-parsing its own formatting.
|
|
46
|
+
*/
|
|
47
|
+
export declare function ExecutionStats({ stats, label }: ExecutionStatsProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { ExprValue, SecretValue } from '../types.ts';
|
|
2
|
+
import { ExpressionOptions } from './ExpressionOptions.tsx';
|
|
3
|
+
/**
|
|
4
|
+
* A near-full-screen editor for an expression value. Left: the data sources in
|
|
5
|
+
* scope (variables, secrets, and the workflow state leading to this step) — one
|
|
6
|
+
* click inserts a colored TAG (chip) at the caret. Right: the expression editor
|
|
7
|
+
* (top, where tags read distinctly from plain text) over the `{{ }}` template
|
|
8
|
+
* form that gets saved plus a live Result pane (bottom) that previews the
|
|
9
|
+
* expression against user-supplied sample values for the injected scope.
|
|
10
|
+
*
|
|
11
|
+
* The value it saves is the same `ExprValue | string` the inline field and the
|
|
12
|
+
* engine already use (see `expression-template.ts` / `expression-dom.ts`).
|
|
13
|
+
*/
|
|
14
|
+
export interface ExpressionEditorModalProps {
|
|
15
|
+
value: ExprValue | string | SecretValue | undefined;
|
|
16
|
+
masked?: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* The field being edited holds multi-line text (a `text`-typed param, or one
|
|
19
|
+
* flagged `config.multiline`). Enter then inserts a literal `"\n"` at the
|
|
20
|
+
* caret instead of being swallowed, and `aria-multiline` follows. Omitted ⇒
|
|
21
|
+
* single-line, as every existing consumer expects.
|
|
22
|
+
*/
|
|
23
|
+
multiline?: boolean;
|
|
24
|
+
options: ExpressionOptions;
|
|
25
|
+
/** Field name shown in the modal title. */
|
|
26
|
+
fieldLabel?: string;
|
|
27
|
+
/** Expression mode's commit. Not used in `mode="json-binding"` (see `onBind`). */
|
|
28
|
+
onSave?: (next: ExprValue | string) => void;
|
|
29
|
+
onClose: () => void;
|
|
30
|
+
/**
|
|
31
|
+
* `"json-binding"`: pick ONE upstream step output for a whole `json`/`group`
|
|
32
|
+
* param. The rail shows only the Workflow state slot, each step gets an
|
|
33
|
+
* "Entire output" leaf, and a click calls `onBind({ $: ref })` (the plain
|
|
34
|
+
* one-key object, never an `ExprValue`) and closes. No chips editor, no
|
|
35
|
+
* Save, no template/Result panes. Absent ⇒ expression mode, unchanged.
|
|
36
|
+
*/
|
|
37
|
+
mode?: "json-binding";
|
|
38
|
+
onBind?: (next: {
|
|
39
|
+
$: string;
|
|
40
|
+
}) => void;
|
|
41
|
+
}
|
|
42
|
+
export declare function ExpressionEditorModal({ value, masked, multiline, options, fieldLabel, onSave, onClose, mode, onBind, }: ExpressionEditorModalProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { ExprValue, SecretValue } from '../types.ts';
|
|
2
|
+
/**
|
|
3
|
+
* ExpressionInput — a single field that reads like a textbox but whose contents
|
|
4
|
+
* are inline SEGMENTS: plain text plus var/secret/expr chips (Notion/Zapier
|
|
5
|
+
* blocks). You can type directly; to browse the data sources in scope
|
|
6
|
+
* (variables, secrets, upstream step outputs) and build a reference, open the
|
|
7
|
+
* full editor via the ƒx button — see {@link ExpressionEditorModal}.
|
|
8
|
+
*
|
|
9
|
+
* Value in ↔ out: incoming `value` is a plain string, an `ExprValue`, or a
|
|
10
|
+
* sealed `SecretValue`. `onChange` emits the leanest faithful form — a plain
|
|
11
|
+
* string when pure-text, an `ExprValue` for mixed content, or a sealed
|
|
12
|
+
* `SecretValue` once a masked field is encrypted.
|
|
13
|
+
*/
|
|
14
|
+
export interface ExpressionInputProps {
|
|
15
|
+
value: ExprValue | string | SecretValue | undefined;
|
|
16
|
+
onChange: (next: ExprValue | string | SecretValue) => void;
|
|
17
|
+
placeholder?: string;
|
|
18
|
+
/** Mask typed text as dots + seal on blur (used for secret-typed params). */
|
|
19
|
+
masked?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* The underlying param holds multi-line text (a `text`-typed param, or one
|
|
22
|
+
* flagged `config.multiline` — the same fields that render a `textarea`).
|
|
23
|
+
* Enter then inserts a literal `"\n"` at the caret instead of being swallowed,
|
|
24
|
+
* and `aria-multiline` follows. Omitted ⇒ single-line, as every existing
|
|
25
|
+
* consumer expects.
|
|
26
|
+
*/
|
|
27
|
+
multiline?: boolean;
|
|
28
|
+
readOnly?: boolean;
|
|
29
|
+
/** Picker data; falls back to the nearest `ExpressionOptionsProvider`. */
|
|
30
|
+
options?: {
|
|
31
|
+
vars?: string[];
|
|
32
|
+
secrets?: string[];
|
|
33
|
+
};
|
|
34
|
+
"aria-label"?: string;
|
|
35
|
+
}
|
|
36
|
+
export declare function ExpressionInput({ value, onChange, placeholder, masked, multiline, readOnly, options, "aria-label": ariaLabel, }: ExpressionInputProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { SecretValue } from '../types.ts';
|
|
3
|
+
/**
|
|
4
|
+
* Drop the step being edited (or drafted, not yet persisted) from its own rail
|
|
5
|
+
* sources — a step cannot reference its own output.
|
|
6
|
+
*/
|
|
7
|
+
export declare function excludeSelfStep(steps: ExpressionStepSource[], selfId: string | null | undefined): ExpressionStepSource[];
|
|
8
|
+
/** An upstream step whose output this field can reference (`steps.<id>.output`). */
|
|
9
|
+
export interface ExpressionStepSource {
|
|
10
|
+
/** Step id — the key under `steps` in the run scope. */
|
|
11
|
+
id: string;
|
|
12
|
+
/** Human label (defaults to the id). */
|
|
13
|
+
label?: string;
|
|
14
|
+
/**
|
|
15
|
+
* The step's output field keys, when any are known (a manual trigger's
|
|
16
|
+
* configured `fields`, a built-in node's static output, or an app action's
|
|
17
|
+
* shape — see `outputsFrom`). Each entry feeds exactly one ref —
|
|
18
|
+
* `steps.<id>.output.<key>` — which is the canonical form the engine resolves
|
|
19
|
+
* (`RunScope.steps`; `core/rfcs/workflow.md` §"Expressions", `core/rfcs/node-types.md`
|
|
20
|
+
* "Executing a trigger node yields the run's start payload … which downstream
|
|
21
|
+
* nodes read as `steps.<triggerId>.output`").
|
|
22
|
+
*
|
|
23
|
+
* `key` is carried **verbatim**: a display-shortened key would build a ref
|
|
24
|
+
* that renders fine in the editor and evaluates to empty at run time, with no
|
|
25
|
+
* error. `label` is for display only and must never be substituted into a ref.
|
|
26
|
+
*
|
|
27
|
+
* **Omitted** (not `[]`) when the step declares no outputs, so a consumer can
|
|
28
|
+
* tell "nothing declared" from "declared none" without a special case.
|
|
29
|
+
*/
|
|
30
|
+
outputs?: {
|
|
31
|
+
key: string;
|
|
32
|
+
label?: string;
|
|
33
|
+
path?: boolean;
|
|
34
|
+
}[];
|
|
35
|
+
/**
|
|
36
|
+
* Where `outputs` came from, for an app-action step: the action's declared
|
|
37
|
+
* `output`, its `sample`, or the step's last test run (`output-shape.ts`).
|
|
38
|
+
* An entry with `path: true` is a dot path into nested output (`start.utc`),
|
|
39
|
+
* checked segment by segment; without it the key is one literal key.
|
|
40
|
+
*/
|
|
41
|
+
outputsFrom?: "declared" | "sample" | "test";
|
|
42
|
+
/**
|
|
43
|
+
* `true` when the step is an app action that declares no output shape and has
|
|
44
|
+
* no test run yet — the picker tells the author to run a test to see fields.
|
|
45
|
+
*/
|
|
46
|
+
needsTest?: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* `true` for an EXTERNAL app-action step only (R-7): the picker then offers a fixed
|
|
49
|
+
* Metadata group (`steps.<id>.meta.app|version|action|connectionId`). **Omitted, not
|
|
50
|
+
* `false`**, for triggers and every `@w6w/*` node. Carries no metadata VALUE: the group
|
|
51
|
+
* is just labels, and the value exists only at run time.
|
|
52
|
+
*/
|
|
53
|
+
hasMeta?: boolean;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* A document contributing pickable refs (`documents.<key>`, and one
|
|
57
|
+
* `documents.<key>.<field>` per top-level field when it qualifies).
|
|
58
|
+
*
|
|
59
|
+
* A document contributes field sub-entries **iff**: `doc.format === "json"`
|
|
60
|
+
* AND `JSON.parse(doc.content)` succeeds into a plain object, OR
|
|
61
|
+
* `doc.format === "yaml"` AND npm `yaml`'s `parse(doc.content)` succeeds into
|
|
62
|
+
* a plain object — where *plain object* means
|
|
63
|
+
* `typeof v === "object" && v !== null && !Array.isArray(v)`. This mirrors
|
|
64
|
+
* the engine's own gate: `documentsSeed`
|
|
65
|
+
* (`packages/server/packages/api/run-seed.ts`, read-only, out of scope) is the
|
|
66
|
+
* authority for each format — `format === "json"` or `format === "yaml"`,
|
|
67
|
+
* then a `try/catch` parse, falling back to the raw content string on either
|
|
68
|
+
* a non-matching format or a throw. `text`/`markdown`/`html` documents, and a
|
|
69
|
+
* `json`/`yaml` document whose parse throws or yields a non-plain-object
|
|
70
|
+
* (array/scalar), are excluded — offering a field ref outside this gate would
|
|
71
|
+
* fail at run time with `render_ref_unresolved`, because the run scope itself
|
|
72
|
+
* never parsed that document into an object.
|
|
73
|
+
*
|
|
74
|
+
* The two parsers (`@std/yaml` server-side, npm `yaml` here) are not
|
|
75
|
+
* identical for every input — they diverge on tab-indented content and on an
|
|
76
|
+
* unresolvable custom tag, both accepted, tested debt (D-3) — but agree on
|
|
77
|
+
* everything else, including a plain JSON object (JSON is a subset of YAML).
|
|
78
|
+
*/
|
|
79
|
+
export interface ExpressionDocumentSource {
|
|
80
|
+
/** Document key — the key under `documents` in the run scope. */
|
|
81
|
+
key: string;
|
|
82
|
+
/**
|
|
83
|
+
* The document's top-level field keys, when the gate above holds. Each
|
|
84
|
+
* entry feeds exactly one ref — `documents.<key>.<field>` — with `key`
|
|
85
|
+
* carried **verbatim**: a display-shortened key would build a ref that
|
|
86
|
+
* renders fine in the editor and evaluates to empty at run time, with no
|
|
87
|
+
* error.
|
|
88
|
+
*
|
|
89
|
+
* **Omitted** (not `[]`) when the document contributes no fields, so a
|
|
90
|
+
* consumer can tell "nothing declared" from "declared none" without a
|
|
91
|
+
* special case — mirrors {@link ExpressionStepSource.outputs}'s own rule.
|
|
92
|
+
*/
|
|
93
|
+
fields?: {
|
|
94
|
+
key: string;
|
|
95
|
+
}[];
|
|
96
|
+
}
|
|
97
|
+
/** Known variable/secret names offered in an ExpressionInput's insert menu. */
|
|
98
|
+
export interface ExpressionOptions {
|
|
99
|
+
vars?: string[];
|
|
100
|
+
secrets?: string[];
|
|
101
|
+
/**
|
|
102
|
+
* Function/run input keys in scope (`inputs.<name>`). Present when the field
|
|
103
|
+
* is edited inside a Function (the engine resolves these from `RunScope.inputs`);
|
|
104
|
+
* omitted for a standalone field.
|
|
105
|
+
*/
|
|
106
|
+
inputs?: string[];
|
|
107
|
+
/**
|
|
108
|
+
* Documents in scope (`documents.<key>`, plus `documents.<key>.<field>` for
|
|
109
|
+
* each document that qualifies — see {@link ExpressionDocumentSource}). A
|
|
110
|
+
* store-independent affordance: whatever the host passes is offered as
|
|
111
|
+
* insertable chips. Omitted when no documents are available.
|
|
112
|
+
*/
|
|
113
|
+
documents?: ExpressionDocumentSource[];
|
|
114
|
+
/**
|
|
115
|
+
* The workflow state leading to this step: upstream steps whose output is in
|
|
116
|
+
* scope (`steps.<id>.output`). Present only in a workflow context; omitted for
|
|
117
|
+
* a standalone field.
|
|
118
|
+
*/
|
|
119
|
+
steps?: ExpressionStepSource[];
|
|
120
|
+
/** Whether a trigger event is in scope (`trigger.event`). */
|
|
121
|
+
hasTrigger?: boolean;
|
|
122
|
+
/**
|
|
123
|
+
* Design-time sample values the Result preview substitutes for known refs,
|
|
124
|
+
* keyed by FULL ref (`"vars.from_email"`, `"documents.test"`). Seeded by the
|
|
125
|
+
* host from the project's real vars/documents so the preview shows actual
|
|
126
|
+
* values instead of the raw `{{ ref }}` template. Optional — a user-typed
|
|
127
|
+
* Sample value still overrides, and unknown refs keep the raw fallback.
|
|
128
|
+
*/
|
|
129
|
+
sampleValues?: Record<string, unknown>;
|
|
130
|
+
/**
|
|
131
|
+
* Seal a typed secret value into an at-rest `SecretValue` envelope via the
|
|
132
|
+
* host (the client has no key). Provided by studio (`POST /vault/seal`); when
|
|
133
|
+
* present, a secret-typed field encrypts on blur so its clear text never
|
|
134
|
+
* lands in the workflow/config JSON. Absent → the value stays a plain string
|
|
135
|
+
* and the server encrypts it on receive instead.
|
|
136
|
+
*/
|
|
137
|
+
sealSecret?: (value: string) => Promise<SecretValue>;
|
|
138
|
+
/**
|
|
139
|
+
* Create a new named variable via the host (`POST /vars`-shaped: the host
|
|
140
|
+
* persists it, `ui` never fetches). Powers the rail's "+ Add" control next
|
|
141
|
+
* to the Variables group label. Absent ⇒ the control is not rendered.
|
|
142
|
+
*/
|
|
143
|
+
createVar?: (input: {
|
|
144
|
+
name: string;
|
|
145
|
+
value: string;
|
|
146
|
+
description?: string;
|
|
147
|
+
}) => Promise<void>;
|
|
148
|
+
/**
|
|
149
|
+
* Create a new named secret via the host (`POST /vault`-shaped, plaintext
|
|
150
|
+
* value — the server encrypts it, `ui` never sees a key). Powers the rail's
|
|
151
|
+
* "+ Add" control next to the Secrets group label. Absent ⇒ the control is
|
|
152
|
+
* not rendered.
|
|
153
|
+
*/
|
|
154
|
+
createSecret?: (input: {
|
|
155
|
+
name: string;
|
|
156
|
+
value: string;
|
|
157
|
+
description?: string;
|
|
158
|
+
}) => Promise<void>;
|
|
159
|
+
}
|
|
160
|
+
export interface ExpressionOptionsProviderProps {
|
|
161
|
+
/**
|
|
162
|
+
* The scope this level CONTRIBUTES — not the whole scope. Shallow-merged over
|
|
163
|
+
* whatever is inherited (see the module doc): keys here win, keys absent are
|
|
164
|
+
* inherited, and an explicit `undefined` removes an inherited key for this
|
|
165
|
+
* subtree.
|
|
166
|
+
*/
|
|
167
|
+
value: ExpressionOptions;
|
|
168
|
+
children: ReactNode;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Contribute expression scope to every `ExpressionInput` below.
|
|
172
|
+
*
|
|
173
|
+
* Layers over the inherited scope rather than replacing it, so an app shell can
|
|
174
|
+
* provide vars/secrets/documents once and a page can add its `inputs` without
|
|
175
|
+
* restating them — and without a field somewhere in the page missing the rail
|
|
176
|
+
* because a prop was not threaded to it. See the module doc for the model.
|
|
177
|
+
*/
|
|
178
|
+
export declare function ExpressionOptionsProvider({ value, children }: ExpressionOptionsProviderProps): import("react").JSX.Element;
|
|
179
|
+
/**
|
|
180
|
+
* The scope in effect here — every contributing provider above, merged.
|
|
181
|
+
*
|
|
182
|
+
* Empty by default so a standalone `ExpressionInput` (no provider) still works
|
|
183
|
+
* — authors just type names by hand.
|
|
184
|
+
*/
|
|
185
|
+
export declare function useExpressionOptions(): ExpressionOptions;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* The four health states a probe can report — a thin LOCAL copy of the RFC's
|
|
4
|
+
* `HealthReport.state` union. `@w6w/ui` deliberately keeps a small literal type
|
|
5
|
+
* here rather than depend on `@w6w/types`, so the display component stays a
|
|
6
|
+
* pure-presentation leaf with no transport/spec coupling.
|
|
7
|
+
*/
|
|
8
|
+
export type HealthPillState = "ok" | "degraded" | "down" | "unknown";
|
|
9
|
+
export interface HealthStatusPillProps {
|
|
10
|
+
/** Which health state to render — drives the colour + default label. */
|
|
11
|
+
state: HealthPillState;
|
|
12
|
+
/** Override the visible text (defaults to a humanised form of `state`). */
|
|
13
|
+
label?: ReactNode;
|
|
14
|
+
/** Accessible label for the pill (falls back to the visible text). */
|
|
15
|
+
ariaLabel?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* A small, theme-aware status pill for a single health state.
|
|
19
|
+
*
|
|
20
|
+
* Renders a coloured dot + label using the `--w6w-health-*` tokens, so a host
|
|
21
|
+
* can restyle every state by overriding those custom properties (see
|
|
22
|
+
* `styles.css`). Colour is never the only signal — the text label carries the
|
|
23
|
+
* same meaning for accessibility.
|
|
24
|
+
*/
|
|
25
|
+
export declare function HealthStatusPill({ state, label, ariaLabel }: HealthStatusPillProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { UptimeCellState, UptimeDay } from './UptimeStrip.tsx';
|
|
2
|
+
/** The calendar window both lanes are plotted against. Both bounds inclusive. */
|
|
3
|
+
export interface HistoryWindow {
|
|
4
|
+
/** Inclusive first calendar day, `YYYY-MM-DD`. */
|
|
5
|
+
from: string;
|
|
6
|
+
/** Inclusive last calendar day, `YYYY-MM-DD`. */
|
|
7
|
+
to: string;
|
|
8
|
+
}
|
|
9
|
+
/** One entry in the vendor's incident feed. */
|
|
10
|
+
export interface VendorIncidentBar {
|
|
11
|
+
id?: string;
|
|
12
|
+
title: string;
|
|
13
|
+
state: UptimeCellState;
|
|
14
|
+
/** ISO instant. Absent = a point-in-time update, not a span. */
|
|
15
|
+
startedAt?: string;
|
|
16
|
+
updatedAt?: string;
|
|
17
|
+
/** ISO instant. Absent WITH `startedAt` present = still open. */
|
|
18
|
+
resolvedAt?: string;
|
|
19
|
+
components?: string[];
|
|
20
|
+
link?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface HistoryTimelineProps {
|
|
23
|
+
window: HistoryWindow;
|
|
24
|
+
/** Execution lane, oldest first, one entry per calendar day. */
|
|
25
|
+
days: UptimeDay[];
|
|
26
|
+
/** Vendor lane. `undefined` = this vendor publishes no incident history at all. */
|
|
27
|
+
incidents?: VendorIncidentBar[];
|
|
28
|
+
/** Overrides the vendor lane's empty text. */
|
|
29
|
+
vendorEmptyLabel?: string;
|
|
30
|
+
/** Clock injection for tests and for an open incident's right edge. Defaults to `Date.now()`. */
|
|
31
|
+
nowMs?: number;
|
|
32
|
+
ariaLabel?: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Two time series — our per-day execution history and the vendor's incident
|
|
36
|
+
* history — plotted on one shared x-axis, so "our calls failed *during* that
|
|
37
|
+
* vendor incident" is a visible alignment rather than a claim.
|
|
38
|
+
*
|
|
39
|
+
* Purely presentational, same discipline as `UptimeStrip`: `days` is already
|
|
40
|
+
* one already-decided state per calendar day (no sort, no reverse, no gap
|
|
41
|
+
* fill), and `incidents` is already the vendor's own feed. This component
|
|
42
|
+
* places them; it makes no judgement about what counts as an incident.
|
|
43
|
+
*
|
|
44
|
+
* `incidents === undefined` ("this vendor publishes no incident history") and
|
|
45
|
+
* `incidents === []` ("nothing happened in this window") are different facts
|
|
46
|
+
* and render different empty-row text — Stripe is the first, a quiet Slack
|
|
47
|
+
* window is the second. Either way the axis and the execution lane render in
|
|
48
|
+
* full, at full width: a vendor with no feed never shrinks the half of the
|
|
49
|
+
* chart that does have data.
|
|
50
|
+
*
|
|
51
|
+
* Severity is encoded twice, same rule as `UptimeStrip` and `HealthStatusPill`:
|
|
52
|
+
* a per-state class AND a geometry difference (fill height on a day cell,
|
|
53
|
+
* clip markers on a bar), never colour alone. Every cell and every bar
|
|
54
|
+
* carries a `title`.
|
|
55
|
+
*/
|
|
56
|
+
export declare function HistoryTimeline({ window: win, days, incidents, vendorEmptyLabel, nowMs, ariaLabel, }: HistoryTimelineProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { IconName } from './icons.tsx';
|
|
2
|
+
export interface IconProps {
|
|
3
|
+
/** Which glyph. Required — this component carries no default icon. */
|
|
4
|
+
name: IconName;
|
|
5
|
+
/** Rendered width AND height, in px. Default 16, the size every rail glyph and
|
|
6
|
+
* icon button in the tree already draws at. */
|
|
7
|
+
size?: number;
|
|
8
|
+
/**
|
|
9
|
+
* Accessible name. Omit it for the common case — a decorative glyph inside a
|
|
10
|
+
* button that already has one — and the `<svg>` is `aria-hidden`; pass it and
|
|
11
|
+
* the glyph becomes `role="img"` with that `aria-label`, for an icon standing
|
|
12
|
+
* alone as content.
|
|
13
|
+
*/
|
|
14
|
+
label?: string;
|
|
15
|
+
/** Merged with `w6w-icon`. */
|
|
16
|
+
className?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* One glyph from the shared set (`./icons.tsx`), sized by prop and coloured by
|
|
20
|
+
* `currentColor` — so a caller colours it with `color` on any ancestor, and it
|
|
21
|
+
* inherits hover/disabled/theme states for free.
|
|
22
|
+
*
|
|
23
|
+
* Accessibility is a two-way switch, never an absent middle: with no `label` the
|
|
24
|
+
* glyph is decorative (`aria-hidden`, `focusable="false"`) for the common case
|
|
25
|
+
* inside an already-labelled button; with a `label` it is `role="img"` with that
|
|
26
|
+
* name. There is no third state, because an unlabelled `<svg>` that is not
|
|
27
|
+
* hidden is exactly the noise a screen reader announces as "graphic".
|
|
28
|
+
*
|
|
29
|
+
* The four ARIA attributes are written out as plain expressions rather than
|
|
30
|
+
* spread from a conditional object: `biome check`'s `a11y/noSvgWithoutTitle`
|
|
31
|
+
* reads the JSX attributes it can see, and a spread hides them (measured —
|
|
32
|
+
* "Alternative text title element cannot be empty" on the spread form only).
|
|
33
|
+
*/
|
|
34
|
+
export declare function Icon(props: IconProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { IconName } from './icons.tsx';
|
|
3
|
+
export interface IconButtonProps {
|
|
4
|
+
/** Accessible name — ALWAYS rendered as `aria-label`. Required: an icon-only
|
|
5
|
+
* button with no name has no safe default (unlike `Copyable`'s `label`,
|
|
6
|
+
* which is always "Copy"). */
|
|
7
|
+
label: string;
|
|
8
|
+
/** The glyph, as caller-supplied markup. Still the primary path — pass this
|
|
9
|
+
* or `icon` (both given ⇒ `children` wins). */
|
|
10
|
+
children?: ReactNode;
|
|
11
|
+
/** The glyph, by name from the shared set (`./icons.tsx`) — e.g. `"history"`.
|
|
12
|
+
* Renders `<Icon name={icon} size={iconSize ?? 16} />`, decorative, so this
|
|
13
|
+
* button's `label` stays the only thing announced. */
|
|
14
|
+
icon?: IconName;
|
|
15
|
+
/** Size handed to `Icon`. Default 16. No effect without `icon`. */
|
|
16
|
+
iconSize?: number;
|
|
17
|
+
/** Tooltip override. Defaults to `label`; `aria-label` is ALWAYS `label`, so
|
|
18
|
+
* the two may legitimately differ (see the docblock). */
|
|
19
|
+
title?: string;
|
|
20
|
+
/** Required — an icon-only button that can't fire has no reason to exist. */
|
|
21
|
+
onClick: () => void;
|
|
22
|
+
disabled?: boolean;
|
|
23
|
+
className?: string;
|
|
24
|
+
/** Caller opts into danger styling; `IconButton` itself has no "delete" concept. */
|
|
25
|
+
danger?: boolean;
|
|
26
|
+
/** Passed straight through, for a toggle button. */
|
|
27
|
+
"aria-pressed"?: boolean;
|
|
28
|
+
/** Passed straight through, for a disclosure button. */
|
|
29
|
+
"aria-expanded"?: boolean;
|
|
30
|
+
/** Passed straight through, for a disclosure button naming the region it controls. */
|
|
31
|
+
"aria-controls"?: string;
|
|
32
|
+
"data-testid"?: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The primitive icon-only button: a caller-supplied glyph, a required
|
|
36
|
+
* accessible name, native `disabled`, and a merged `className`.
|
|
37
|
+
*
|
|
38
|
+
* `EditButton`/`DeleteButton` build on this and bundle one canonical glyph
|
|
39
|
+
* each — this component itself carries no glyph and no "edit"/"delete"
|
|
40
|
+
* meaning, only the `danger` styling hook.
|
|
41
|
+
*
|
|
42
|
+
* The glyph comes from one of two places. `children` is the original path and
|
|
43
|
+
* still works unchanged; `icon` names one from the shared set (`./icons.tsx`)
|
|
44
|
+
* and is rendered through `Icon`, so a caller no longer has to redraw (or
|
|
45
|
+
* import) an SVG for a glyph the set already holds. Given both, `children`
|
|
46
|
+
* wins — the named prop is the convenience, never a way to hide a caller's own
|
|
47
|
+
* markup.
|
|
48
|
+
*
|
|
49
|
+
* `label` is always the accessible name, and `title` overrides ONLY the
|
|
50
|
+
* tooltip. The two legitimately differ: studio's history button is named
|
|
51
|
+
* "Execution history" while, with nothing executed yet, its tooltip reads "No
|
|
52
|
+
* executions yet" — the tooltip says why the control is inert to a sighted
|
|
53
|
+
* user, the name stays the action, and a screen reader must keep hearing the
|
|
54
|
+
* latter.
|
|
55
|
+
*
|
|
56
|
+
* `ref` reaches the `<button>` itself (`forwardRef` — React 18, so the
|
|
57
|
+
* ref-as-prop syntax is not available), which is what a caller needs to move
|
|
58
|
+
* focus or measure the control.
|
|
59
|
+
*/
|
|
60
|
+
export declare const IconButton: import('react').ForwardRefExoticComponent<IconButtonProps & import('react').RefAttributes<HTMLButtonElement>>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
export interface InfoTipProps {
|
|
3
|
+
/** Accessible name AND tooltip of the toggle button (e.g. "About client secrets"). */
|
|
4
|
+
label: string;
|
|
5
|
+
/** The explanation, rendered only while expanded. */
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
className?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* A small "i" button that reveals a muted explanation block on click — for
|
|
11
|
+
* copy that would otherwise clutter a modal. Collapsed by default; the button
|
|
12
|
+
* carries `aria-expanded` and `aria-controls` pointing at the block, and the
|
|
13
|
+
* block is not rendered at all while collapsed.
|
|
14
|
+
*/
|
|
15
|
+
export declare function InfoTip({ label, children, className }: InfoTipProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* InternalIcon — an internal pseudo-app's glyph on a rounded tile, sized and
|
|
3
|
+
* shaped to match `AppIcon`'s image tile so internal (`@w6w/*`) nodes and app
|
|
4
|
+
* nodes read as the same family everywhere they appear (canvas, add-step
|
|
5
|
+
* picker, edit modal). The glyph markup comes from the node def
|
|
6
|
+
* (`InternalNodeDef.icon` / `internalNodeIcon`) — static, in-repo SVG (no user
|
|
7
|
+
* input). It strokes with the accent color and tracks the active theme.
|
|
8
|
+
*
|
|
9
|
+
* Deliberately NOT the shared `Icon` (`./Icon.tsx`), despite owning an `<svg>`:
|
|
10
|
+
* this is a DATA-DRIVEN per-app identity mark — its content is a markup string
|
|
11
|
+
* off the node def, one glyph per internal app, not a fixed UI glyph with a name
|
|
12
|
+
* in the set (`./icons.tsx`). Unifying them would mean changing
|
|
13
|
+
* `InternalNodeDef` to carry a name instead of its markup, which is a data-model
|
|
14
|
+
* change, not an icon migration.
|
|
15
|
+
*/
|
|
16
|
+
export declare function InternalIcon({ icon, size }: {
|
|
17
|
+
icon: string;
|
|
18
|
+
size?: number;
|
|
19
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
export interface ListItemProps {
|
|
3
|
+
/** Primary label — prominent, single-line with ellipsis overflow. */
|
|
4
|
+
title: ReactNode;
|
|
5
|
+
/** Secondary label under the title — muted, small, truncates. */
|
|
6
|
+
subtitle?: ReactNode;
|
|
7
|
+
/** Leading slot (e.g. an `<AppIcon />` or status glyph). */
|
|
8
|
+
icon?: ReactNode;
|
|
9
|
+
/** Trailing slot pushed to the right (e.g. a badge or chevron). */
|
|
10
|
+
trailing?: ReactNode;
|
|
11
|
+
/** Highlights the row as selected/current. Reflected as `aria-pressed` when clickable. */
|
|
12
|
+
active?: boolean;
|
|
13
|
+
/** When provided, the row renders as a focusable, keyboard-activatable button. */
|
|
14
|
+
onClick?: () => void;
|
|
15
|
+
/** Accessible label for the clickable row (falls back to the `title` DOM text). */
|
|
16
|
+
ariaLabel?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* A clean, reusable list row: leading icon · title over subtitle · trailing slot.
|
|
20
|
+
*
|
|
21
|
+
* Mirrors the look/behaviour of the saved-test button rows it replaces. When
|
|
22
|
+
* `onClick` is given it renders a `<button type="button">` (focusable, Enter/Space
|
|
23
|
+
* activatable) with `aria-pressed={active}`; otherwise a plain, non-interactive row.
|
|
24
|
+
*/
|
|
25
|
+
export declare function ListItem({ title, subtitle, icon, trailing, active, onClick, ariaLabel, }: ListItemProps): import("react").JSX.Element;
|