@danxbot/ui 25.2.0 → 26.0.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.
@@ -9,29 +9,71 @@ export type SecretValue = {
9
9
  } | {
10
10
  kind: "cleared";
11
11
  };
12
+ /**
13
+ * The result of testing the stored secret, supplied by the caller from a server answer. Never inferred
14
+ * from the value being filled: only `verified` is green.
15
+ */
16
+ export type SecretStatus =
17
+ /** The provider accepted it. `checkedAt` is when. */
18
+ {
19
+ kind: "verified";
20
+ checkedAt?: string | Date;
21
+ }
22
+ /** The provider refused it or could not be reached; `reason` is its words, printed as text. Never empty. */
23
+ | {
24
+ kind: "failed";
25
+ reason: string;
26
+ checkedAt?: string | Date;
27
+ }
28
+ /** Nothing can test this secret (an OAuth client secret); `message` is the caller's words saying so. Never empty. */
29
+ | {
30
+ kind: "unverifiable";
31
+ message: string;
32
+ }
33
+ /** Never tested. What an absent `status` reads as. */
34
+ | {
35
+ kind: "unchecked";
36
+ }
37
+ /** A test is running. */
38
+ | {
39
+ kind: "checking";
40
+ };
41
+ /** How Clear acts: `staged` waits for the surrounding form's Save; `immediate` is a row the caller deletes at once. */
42
+ export type SecretClearMode = "staged" | "immediate";
12
43
  export interface SecretFieldProps extends Pick<FieldProps, "label" | "description" | "error" | "required" | "disabled" | "name" | "className">, Pick<InputProps, "size" | "placeholder"> {
13
44
  /** The pending edit. See the module doc comment for why this is not a `string`. */
14
45
  value: SecretValue;
15
46
  onChange: (value: SecretValue) => void;
16
47
  /**
17
- * Whether a secret is CURRENTLY stored server-side, independent of `value`
18
- * — this is the fact the empty, masked field is standing in for. Drives the
19
- * "a secret is stored" announcement, the hint row, and whether the clear
20
- * action is offered at all (there is nothing to clear when nothing is set).
48
+ * Whether a secret is CURRENTLY stored server-side, independent of `value`.
49
+ * While one is (and it is not marked cleared) the component draws the stored
50
+ * face and NO input; Clear is offered only then.
21
51
  */
22
52
  configured: boolean;
23
53
  /**
24
54
  * A partial, already-safe rendering of the stored value — e.g. `{ prefix:
25
55
  * "sk-ab", suffix: "9f4c" }` for a key the consuming app's own API already
26
56
  * truncates before it ever reaches the client. This is NOT the secret; it
27
- * is a confirmation aid ("is this the key I think it is?") and is shown
28
- * only while a stored value exists and has not been typed over or cleared.
57
+ * is a frame of reference ("is this the key I think it is?"). Absent, the
58
+ * stored face shows dots only.
29
59
  */
30
60
  hint?: {
31
61
  prefix: string;
32
62
  suffix: string;
33
63
  };
34
- /** When the stored value was last written, for the same confirmation purpose as `hint`. */
64
+ /**
65
+ * The result of the last test of the stored secret, from the server. Absent
66
+ * reads "Not checked" — a value being filled is never "Verified".
67
+ */
68
+ status?: SecretStatus;
69
+ /**
70
+ * Tests the stored secret again. Absent, or `status` is `unverifiable`, the
71
+ * Re-verify button is not drawn. While `status` is `checking` it is busy.
72
+ */
73
+ onVerify?: () => void;
74
+ /** `staged` (default): Clear waits for the form's Save and offers Undo. `immediate`: a row that saves by itself. */
75
+ clear?: SecretClearMode;
76
+ /** When the stored value was last written, for the same frame of reference as `hint`. */
35
77
  updatedAt?: string | Date;
36
78
  /** Who wrote it, if the caller's system tracks that. */
37
79
  updatedBy?: string;
@@ -45,4 +87,4 @@ export interface SecretFieldProps extends Pick<FieldProps, "label" | "descriptio
45
87
  clearConfirmLabel?: string;
46
88
  ref?: Ref<HTMLInputElement>;
47
89
  }
48
- export declare function SecretField({ value, onChange, configured, hint, updatedAt, updatedBy, revealable, clearConfirmLabel, label, description, error, required, disabled, name, placeholder, size, className, ref, }: SecretFieldProps): import("react").JSX.Element;
90
+ export declare function SecretField({ value, onChange, configured, hint, status, onVerify, clear, updatedAt, updatedBy, revealable, clearConfirmLabel, label, description, error, required, disabled, name, placeholder, size, className, ref, }: SecretFieldProps): import("react").JSX.Element;
@@ -113,8 +113,21 @@ export interface TabListProps {
113
113
  className?: string;
114
114
  children: ReactNode;
115
115
  variant?: VariantProps<typeof tabs>["variant"];
116
+ /**
117
+ * The words for the two scroll buttons a strip that overflows grows on the edge that has more tabs. DX-4973.
118
+ *
119
+ * ABSENT MEANS FADE ONLY. A strip wider than its box always fades its content out at the edge that has more (that is the cue, and it
120
+ * needs no colour: it fades the tabs themselves, not a patch of the surface over them). The buttons are the part a keyboard or a
121
+ * screen reader can act on, and the library has no default language, so the caller supplies what they say ("Show earlier tabs",
122
+ * "Show later tabs") rather than the strip speaking English by itself. Pass them wherever a strip can overflow. A button shows
123
+ * only on the edge that has more.
124
+ */
125
+ scrollLabels?: {
126
+ before: string;
127
+ after: string;
128
+ };
116
129
  }
117
- export declare function TabList({ className, children, variant }: TabListProps): import("react").JSX.Element;
130
+ export declare function TabList({ className, children, variant, scrollLabels }: TabListProps): import("react").JSX.Element;
118
131
  export interface TabProps extends Omit<BaseTabs.Tab.Props, "className"> {
119
132
  className?: string;
120
133
  variant?: VariantProps<typeof tabs>["variant"];
@@ -13,7 +13,8 @@ export declare function assertSteps(steps: readonly Step[], current: number): vo
13
13
  /**
14
14
  * What one step IS, given where the cursor is.
15
15
  *
16
- * PRECEDENCE, and the first rule is the interesting one. `blocked` outranks
16
+ * PRECEDENCE: failed, blocked, current, complete, unverified, skipped, incomplete, upcoming. DX-4973 puts `failed` first.
17
+ * The next rule is the interesting one. `blocked` outranks
17
18
  * everything, including `complete`, wherever the step sits. Data saying both
18
19
  * is contradictory, and when a record contradicts itself the exception is what
19
20
  * the reader needs — the same call `ProvenanceBadge` makes when it stays quiet
@@ -35,6 +35,18 @@ export interface Step {
35
35
  * An empty string throws, for the same reason an empty `blocked` does: the words ARE the spoken state.
36
36
  */
37
37
  unverified?: string;
38
+ /**
39
+ * A check of this step ran and FAILED, and what it said. DX-4973.
40
+ *
41
+ * The VALUE is the reason, supplied by the caller ("Asana refused the token", "The bot is not in that channel"): the library cannot
42
+ * know what a flow checks, and the words are printed in red under the label and spoken as the step's state (so start with what
43
+ * happened, because no fixed word like "failed" is added). It is the one red marker a step can carry on purpose, distinct from
44
+ * `blocked` (cannot start yet, amber, and the only one that gates the forward control), `unverified` (done, nothing to test, grey),
45
+ * `skipped` (left on purpose, grey) and `incomplete` (passed over, red cross). A failed step does NOT gate forward movement by
46
+ * itself: add `blocked` as well when it must. It outranks every other state, `blocked` and the cursor included, because a failure is
47
+ * the thing a reader must not miss; it is counted in `StepperProgress.failed` and in neither chip. An empty string throws.
48
+ */
49
+ failed?: string;
38
50
  /**
39
51
  * Why the flow cannot move on from here. Absent means it can.
40
52
  *
@@ -56,14 +68,16 @@ export interface Step {
56
68
  * What a step IS right now — derived from the steps and the cursor, never
57
69
  * stored.
58
70
  *
59
- * Seven, not two, because "finished", "you are here", "done but unproven", "you left it on purpose",
71
+ * Eight, not two, because "finished", "you are here", "done but unproven", "you left it on purpose",
60
72
  * "you missed it", "not reached yet" and "this is what is stopping you" call for
61
73
  * different next actions and one absence of action. Collapsing them to a boolean is what
62
74
  * produces a rail where a skipped step and an untouched one look identical.
63
75
  */
64
76
  export type StepStatus =
77
+ /** Carries `failed` words: a check ran and refused it. Beats every other reading, `blocked` included. Red. DX-4973. */
78
+ "failed"
65
79
  /** `complete: true`. */
66
- "complete"
80
+ | "complete"
67
81
  /** Carries a `blocked` reason. Beats every other reading — see `stepStatus`. */
68
82
  | "blocked"
69
83
  /** The cursor is on it. */
@@ -91,12 +105,14 @@ export interface StepperProgress {
91
105
  /** How many steps are `complete`, anywhere in the flow. */
92
106
  complete: number;
93
107
  /**
94
- * Behind the cursor, not complete and marked neither `skipped` nor `unverified`: the steps missed, the ones the red chip counts. (Renamed in meaning by
108
+ * Behind the cursor, not complete and marked none of `skipped`, `unverified` or `failed`: the steps missed, the ones the red chip counts. (Renamed in meaning by
95
109
  * DX-4963: a step the person skipped on purpose is `acknowledged`, not counted here.)
96
110
  */
97
111
  skipped: number;
98
112
  /** Steps marked `skipped` that are not complete, anywhere in the flow: left on purpose, counted in the neutral chip. DX-4963. */
99
113
  acknowledged: number;
114
+ /** Steps carrying `failed` words, anywhere in the flow. Counted in no chip. DX-4973. */
115
+ failed: number;
100
116
  /** Steps carrying `unverified` words that are not complete, anywhere in the flow: done, with nothing to test. Counted in no chip. DX-4968. */
101
117
  unverified: number;
102
118
  }
@@ -29,7 +29,7 @@ export { EditGutter, type EditGutterProps } from "./components/EditGutter";
29
29
  export { InlineMarkdownEdit, type InlineMarkdownEditProps } from "./components/InlineMarkdownEdit";
30
30
  export type { EditActivation } from "./components/edit/activation";
31
31
  export type { EditCommit, EditOutcome, EditRefusal } from "./components/edit/outcome";
32
- export { SecretField, type SecretFieldProps, type SecretValue } from "./components/SecretField";
32
+ export { SecretField, type SecretClearMode, type SecretFieldProps, type SecretStatus, type SecretValue } from "./components/SecretField";
33
33
  export { PasswordInput, type PasswordInputProps } from "./components/PasswordInput";
34
34
  export { PasswordRequirements, type PasswordRequirementsProps, type PasswordRequirementRule, } from "./components/PasswordRequirements";
35
35
  export { SettingRow, SettingGroup, type SettingRowProps, type SettingGroupProps, type SettingRowControlRenderProps, } from "./components/SettingRow";
@@ -45,10 +45,22 @@ export interface FormsStrings {
45
45
  label: string;
46
46
  };
47
47
  secretField: {
48
- /** Screen-reader-only note that a secret is already stored for the field. */
49
- storedNotice: string;
50
- /** Placeholder while the stored secret is marked for removal. */
51
- willBeRemoved: string;
48
+ /** Status word of a stored secret whose last test passed. */
49
+ statusVerified: string;
50
+ /** Status word of a stored secret whose last test failed (the provider's reason is printed beside it). */
51
+ statusFailed: string;
52
+ /** Status word of a stored secret that has never been tested. */
53
+ statusUnchecked: string;
54
+ /** Status word while a test of the stored secret runs. */
55
+ statusChecking: string;
56
+ /** Status word of a stored secret nothing can test (the caller's own words say why). */
57
+ statusUnverifiable: string;
58
+ /** Button that tests the stored secret again. */
59
+ reverify: string;
60
+ /** Line under the status; `when` is the already-formatted instant the secret was last tested. */
61
+ checked: (when: string) => string;
62
+ /** Banner text while the stored secret is being replaced (a new value typed after Clear). */
63
+ replacedOnSave: string;
52
64
  /** Placeholder of an empty field when no secret is stored. */
53
65
  notSet: string;
54
66
  /** Accessible name of the reveal button for typed text while it is hidden. */
@@ -67,6 +79,8 @@ export interface FormsStrings {
67
79
  clearTitle: string;
68
80
  /** Body of the clear confirmation; `masked` is the stored value's visible ends ("sk-…ab"), or null when the caller gave no hint. */
69
81
  clearDescription: (masked: string | null) => string;
82
+ /** Body of the clear confirmation for a row that removes the secret at once; `masked` as above. */
83
+ clearNowDescription: (masked: string | null) => string;
70
84
  /** Default label of the clear confirmation's destructive button. */
71
85
  clearConfirm: string;
72
86
  /** Who/when line under the field; `when` is the already-formatted instant and either argument may be absent. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danxbot/ui",
3
- "version": "25.2.0",
3
+ "version": "26.0.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",