@danxbot/ui 3.9.1 → 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 +5395 -5113
- package/dist/index.js.map +1 -1
- package/dist/types/components/InlineEdit.d.ts +141 -0
- package/dist/types/index.d.ts +1 -0
- package/package.json +2 -2
|
@@ -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;
|
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";
|
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",
|
|
@@ -73,7 +73,7 @@
|
|
|
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",
|