@tensor_1/react 2.47.0 → 2.49.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/README.md +540 -2
- package/dist/{SchedulingCalendar-B6TakO2h.d.ts → SchedulingCalendar-WWyFL3Eo.d.ts} +51 -2
- package/dist/announce.d.ts +10 -0
- package/dist/announce.js +30 -0
- package/dist/chart-analytic.cjs +33 -25
- package/dist/chart-preset.cjs +23 -15
- package/dist/chart.cjs +23 -15
- package/dist/combobox-model.d.ts +10 -1
- package/dist/combobox-model.js +15 -0
- package/dist/command-palette-model.d.ts +44 -0
- package/dist/command-palette-model.js +36 -0
- package/dist/components/AccountMenu.d.ts +44 -0
- package/dist/components/AccountMenu.js +43 -0
- package/dist/components/AppShell.d.ts +45 -2
- package/dist/components/AppShell.js +116 -5
- package/dist/components/AuditLog.d.ts +128 -0
- package/dist/components/AuditLog.js +196 -0
- package/dist/components/BrandProfiles.js +4 -3
- package/dist/components/Breadcrumbs.d.ts +9 -2
- package/dist/components/Breadcrumbs.js +3 -2
- package/dist/components/Button.d.ts +12 -5
- package/dist/components/Button.js +7 -3
- package/dist/components/Card.d.ts +18 -1
- package/dist/components/Card.js +5 -1
- package/dist/components/ChangeHighlight.d.ts +30 -0
- package/dist/components/ChangeHighlight.js +21 -0
- package/dist/components/ChartCore.js +2 -1
- package/dist/components/Checkbox.d.ts +27 -1
- package/dist/components/Checkbox.js +31 -2
- package/dist/components/Chip.d.ts +7 -3
- package/dist/components/Chip.js +2 -2
- package/dist/components/CodeDisplay.d.ts +65 -0
- package/dist/components/CodeDisplay.js +124 -0
- package/dist/components/Combobox.d.ts +27 -6
- package/dist/components/Combobox.js +195 -58
- package/dist/components/CommandPalette.d.ts +36 -1
- package/dist/components/CommandPalette.js +254 -2
- package/dist/components/ContactCard.d.ts +66 -0
- package/dist/components/ContactCard.js +74 -0
- package/dist/components/Count.d.ts +24 -0
- package/dist/components/Count.js +32 -0
- package/dist/components/DashboardCanvas.js +14 -0
- package/dist/components/DataWorkspace.d.ts +167 -0
- package/dist/components/DataWorkspace.js +380 -0
- package/dist/components/DateFieldParts.d.ts +2 -1
- package/dist/components/DateFieldParts.js +7 -0
- package/dist/components/DatePicker.d.ts +9 -2
- package/dist/components/DatePicker.js +67 -28
- package/dist/components/DateRangePicker.d.ts +12 -2
- package/dist/components/DateRangePicker.js +13 -12
- package/dist/components/DetailPage.d.ts +7 -1
- package/dist/components/DetailPage.js +2 -1
- package/dist/components/Dialogs.d.ts +71 -10
- package/dist/components/Dialogs.js +130 -30
- package/dist/components/DiffViewer.d.ts +23 -3
- package/dist/components/DiffViewer.js +26 -12
- package/dist/components/DiscardPrompt.js +16 -0
- package/dist/components/DisplayPreferences.d.ts +83 -0
- package/dist/components/DisplayPreferences.js +185 -0
- package/dist/components/EditorialHome.d.ts +23 -3
- package/dist/components/EditorialHome.js +16 -11
- package/dist/components/EntityPicker.d.ts +20 -3
- package/dist/components/EntityPicker.js +32 -13
- package/dist/components/FilterEditor.d.ts +18 -4
- package/dist/components/FilterEditor.js +141 -19
- package/dist/components/FocusOnMount.d.ts +282 -0
- package/dist/components/FocusOnMount.js +12 -0
- package/dist/components/InfoTip.js +11 -12
- package/dist/components/InlineEdit.d.ts +87 -20
- package/dist/components/InlineEdit.js +197 -54
- package/dist/components/Input.d.ts +12 -2
- package/dist/components/Input.js +5 -3
- package/dist/components/Kanban.d.ts +14 -3
- package/dist/components/Kanban.js +9 -4
- package/dist/components/Kbd.d.ts +6 -1
- package/dist/components/Kbd.js +6 -6
- package/dist/components/Lightbox.d.ts +41 -5
- package/dist/components/Lightbox.js +95 -9
- package/dist/components/MatchReview.d.ts +40 -1
- package/dist/components/MatchReview.js +130 -4
- package/dist/components/MetricInput.js +3 -2
- package/dist/components/Modal.d.ts +2 -1
- package/dist/components/Modal.js +13 -4
- package/dist/components/MotionList.d.ts +303 -0
- package/dist/components/MotionList.js +175 -0
- package/dist/components/NavFavourites.d.ts +5 -0
- package/dist/components/NavFavourites.js +7 -7
- package/dist/components/OtpInput.d.ts +33 -0
- package/dist/components/OtpInput.js +123 -0
- package/dist/components/PageHeader.d.ts +7 -1
- package/dist/components/PageHeader.js +2 -2
- package/dist/components/Pagination.js +6 -5
- package/dist/components/PasswordInput.d.ts +34 -0
- package/dist/components/PasswordInput.js +101 -0
- package/dist/components/Peek.js +3 -3
- package/dist/components/Popover.js +11 -0
- package/dist/components/PrintLayout.d.ts +63 -0
- package/dist/components/PrintLayout.js +114 -0
- package/dist/components/QrCode.d.ts +47 -0
- package/dist/components/QrCode.js +55 -0
- package/dist/components/QrScanner.d.ts +95 -0
- package/dist/components/QrScanner.js +266 -0
- package/dist/components/RelationshipGraph.d.ts +32 -1
- package/dist/components/RelationshipGraph.js +22 -6
- package/dist/components/RelationshipGraphLayered.d.ts +1 -1
- package/dist/components/RelationshipGraphLayered.js +268 -118
- package/dist/components/RelationshipGraphList.js +33 -6
- package/dist/components/RuleBuilder.js +39 -7
- package/dist/components/SchedulingAgenda.d.ts +3 -1
- package/dist/components/SchedulingCalendar.d.ts +3 -1
- package/dist/components/SchedulingCalendar.js +43 -4
- package/dist/components/SchedulingResourceDay.d.ts +57 -0
- package/dist/components/SchedulingResourceDay.js +287 -0
- package/dist/components/SchedulingTimeGrid.d.ts +3 -1
- package/dist/components/SchedulingTimeline.d.ts +3 -1
- package/dist/components/SearchSuggest.d.ts +23 -3
- package/dist/components/SearchSuggest.js +56 -18
- package/dist/components/Segmented.d.ts +39 -4
- package/dist/components/Segmented.js +39 -5
- package/dist/components/Select.d.ts +3 -2
- package/dist/components/Select.js +7 -1
- package/dist/components/ShortcutHint.d.ts +11 -10
- package/dist/components/ShortcutHint.js +44 -38
- package/dist/components/Sidebar.d.ts +36 -4
- package/dist/components/Sidebar.js +37 -12
- package/dist/components/SortableList.d.ts +45 -0
- package/dist/components/SortableList.js +147 -0
- package/dist/components/Stat.d.ts +28 -3
- package/dist/components/Stat.js +13 -3
- package/dist/components/States.d.ts +33 -1
- package/dist/components/States.js +43 -1
- package/dist/components/StatusPill.d.ts +14 -3
- package/dist/components/StatusPill.js +11 -3
- package/dist/components/Steps.js +2 -1
- package/dist/components/Table.d.ts +9 -2
- package/dist/components/Table.js +4 -2
- package/dist/components/TableControls.js +18 -58
- package/dist/components/TableOverflowProbe.d.ts +12 -0
- package/dist/components/TableOverflowProbe.js +27 -0
- package/dist/components/Tabs.d.ts +2 -1
- package/dist/components/Tabs.js +10 -2
- package/dist/components/TagInput.d.ts +67 -0
- package/dist/components/TagInput.js +342 -0
- package/dist/components/Textarea.d.ts +5 -0
- package/dist/components/Textarea.js +2 -2
- package/dist/components/TimePicker.d.ts +80 -0
- package/dist/components/TimePicker.js +347 -0
- package/dist/components/Toast.d.ts +1 -1
- package/dist/components/Toast.js +109 -4
- package/dist/components/Tooltip.d.ts +8 -4
- package/dist/components/Tooltip.js +86 -28
- package/dist/components/Tree.d.ts +8 -0
- package/dist/components/Tree.js +11 -5
- package/dist/display-preferences-model.d.ts +53 -0
- package/dist/display-preferences-model.js +64 -0
- package/dist/emoji.cjs +143 -49
- package/dist/filter-model.d.ts +59 -3
- package/dist/filter-model.js +67 -2
- package/dist/hooks/useAnchoredPosition.js +14 -2
- package/dist/hooks/useChangeHighlight.d.ts +33 -0
- package/dist/hooks/useChangeHighlight.js +44 -0
- package/dist/hooks/useDeferredReorder.d.ts +32 -0
- package/dist/hooks/useDeferredReorder.js +47 -0
- package/dist/hooks/useDialog.d.ts +5 -0
- package/dist/hooks/useDialog.js +17 -3
- package/dist/hooks/useKeyboardGrab.d.ts +58 -0
- package/dist/hooks/useKeyboardGrab.js +118 -0
- package/dist/hooks/useOptimisticValue.d.ts +51 -0
- package/dist/hooks/useOptimisticValue.js +61 -0
- package/dist/hooks/useReducedMotion.d.ts +4 -1
- package/dist/hooks/useReducedMotion.js +7 -1
- package/dist/hooks/useResolvedFilterLabels.d.ts +15 -0
- package/dist/hooks/useResolvedFilterLabels.js +34 -0
- package/dist/hooks/useSlidingIndicator.d.ts +18 -0
- package/dist/hooks/useSlidingIndicator.js +80 -0
- package/dist/hooks/useVirtualRows.d.ts +21 -2
- package/dist/hooks/useVirtualRows.js +30 -3
- package/dist/icons/Icon.d.ts +1 -1
- package/dist/index.cjs +19687 -13423
- package/dist/index.d.cts +3419 -651
- package/dist/index.d.ts +48 -18
- package/dist/index.js +153 -9
- package/dist/labels-context.d.ts +93 -3
- package/dist/motion.d.ts +11 -0
- package/dist/motion.js +35 -0
- package/dist/overlay-stack.d.ts +6 -0
- package/dist/overlay-stack.js +13 -0
- package/dist/qr-model.d.ts +65 -0
- package/dist/qr-model.js +323 -0
- package/dist/relationship-graph-model.d.ts +92 -3
- package/dist/relationship-graph-model.js +134 -15
- package/dist/reorder.d.ts +30 -0
- package/dist/reorder.js +74 -0
- package/dist/rich-text.cjs +46 -4
- package/dist/scheduling-resource-model.d.ts +76 -0
- package/dist/scheduling-resource-model.js +74 -0
- package/dist/search-suggest-model.js +3 -1
- package/dist/shell-context.d.ts +11 -0
- package/dist/shell-context.js +7 -0
- package/dist/time-field-model.d.ts +46 -0
- package/dist/time-field-model.js +152 -0
- package/dist/toast-store.d.ts +22 -3
- package/dist/toast-store.js +26 -9
- package/package.json +2 -1
|
@@ -3,11 +3,11 @@ import { ReactNode } from 'react';
|
|
|
3
3
|
|
|
4
4
|
/** Every word `InlineEdit` renders or announces. `{label}` is the field's name. */
|
|
5
5
|
interface InlineEditLabels {
|
|
6
|
-
/** Added to the view button's name after the value: "…, Edit {label}". */
|
|
6
|
+
/** Added to the view button's name after the value: "…, Edit {label}"; the icon trigger's whole name. */
|
|
7
7
|
edit: string;
|
|
8
8
|
save: string;
|
|
9
9
|
cancel: string;
|
|
10
|
-
/** Polite status while `onSave` runs. */
|
|
10
|
+
/** Polite status while `onSave` runs (shown after 300 ms, so a fast save does not flash it). */
|
|
11
11
|
saving: string;
|
|
12
12
|
/** Polite status after a save. */
|
|
13
13
|
saved: string;
|
|
@@ -15,50 +15,114 @@ interface InlineEditLabels {
|
|
|
15
15
|
failed: string;
|
|
16
16
|
/** What the view shows when the value is empty and no `placeholder` was given. */
|
|
17
17
|
empty: string;
|
|
18
|
+
/** Visually hidden before a `readOnlyReason`, so it is read as one: "Read-only: …". */
|
|
19
|
+
readOnly: string;
|
|
18
20
|
}
|
|
19
21
|
declare const DEFAULT_INLINE_EDIT_LABELS: InlineEditLabels;
|
|
22
|
+
/** Where an `InlineEdit` is (HAR-1833). `saved` holds until the field is opened again. */
|
|
23
|
+
type InlineEditState = 'idle' | 'editing' | 'saving' | 'saved' | 'error';
|
|
20
24
|
/** What a custom editor receives. Spread the field props onto your control. */
|
|
21
|
-
interface InlineEditEditorProps {
|
|
25
|
+
interface InlineEditEditorProps<T = string> {
|
|
22
26
|
/** The draft. */
|
|
23
|
-
value:
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
+
value: T;
|
|
28
|
+
/** Change the draft. With `commit="change"` this also saves it. Ignored while a save runs. */
|
|
29
|
+
onChange: (next: T) => void;
|
|
30
|
+
/**
|
|
31
|
+
* Save the draft (what Enter does in the default editor). Pass the value to save one you
|
|
32
|
+
* just chose: `save(next)` does not wait for the draft to update, so it never saves a stale one.
|
|
33
|
+
*/
|
|
34
|
+
save: (next?: T) => void;
|
|
27
35
|
cancel: () => void;
|
|
28
|
-
/** `id`, the accessible name, the error wiring and
|
|
36
|
+
/** `id`, the accessible name, the error wiring, and the busy state while saving. */
|
|
29
37
|
field: {
|
|
30
38
|
id: string;
|
|
31
39
|
'aria-label': string;
|
|
32
40
|
'aria-describedby': string | undefined;
|
|
33
41
|
'aria-invalid': true | undefined;
|
|
42
|
+
/** True once a save has run for 300 ms (changes are ignored from its start, so a fast save never greys the control). */
|
|
34
43
|
disabled: boolean;
|
|
44
|
+
/** The same moment as `disabled`, for a text control that should keep focus and its text selectable. */
|
|
45
|
+
readOnly: boolean;
|
|
35
46
|
};
|
|
36
47
|
}
|
|
37
|
-
|
|
48
|
+
/** What `renderError` receives besides the rejection itself. */
|
|
49
|
+
interface InlineEditErrorContext<T = string> {
|
|
50
|
+
/** The rejection's message, else `labels.failed`: what the default rendering shows. */
|
|
51
|
+
message: ReactNode;
|
|
52
|
+
/** The draft that failed. */
|
|
53
|
+
draft: T;
|
|
54
|
+
/** Send the draft again. Show it when a retry can help (a timeout, not a refusal). */
|
|
55
|
+
retry: () => void;
|
|
56
|
+
/** Close the editor and drop the draft, e.g. after "Reload latest" on a version conflict. */
|
|
57
|
+
cancel: () => void;
|
|
58
|
+
}
|
|
59
|
+
interface InlineEditProps<T = string> {
|
|
38
60
|
/** The saved value. */
|
|
39
|
-
value:
|
|
61
|
+
value: T;
|
|
40
62
|
/**
|
|
41
63
|
* Save the new value. Return a promise to show the pending state; a rejection keeps the
|
|
42
64
|
* editor open with the error under it (the rejection's message, else `labels.failed`).
|
|
65
|
+
* The editor waits for it: the value shows as saved only once it resolves.
|
|
43
66
|
*/
|
|
44
|
-
onSave: (next:
|
|
67
|
+
onSave: (next: T) => void | Promise<unknown>;
|
|
45
68
|
/** The field's name: "Title", "Due date". It names the edit button and the editor. */
|
|
46
69
|
label: string;
|
|
47
|
-
/**
|
|
48
|
-
|
|
70
|
+
/**
|
|
71
|
+
* How the saved value shows. Default: the text itself (`String(value)`); pass it for any
|
|
72
|
+
* value that is not a string (an option, a person, a time window).
|
|
73
|
+
*/
|
|
74
|
+
renderView?: (value: T) => ReactNode;
|
|
49
75
|
/**
|
|
50
76
|
* A custom editor: a `Select`, a `Combobox`, a date field. Spread `field` onto the control.
|
|
51
|
-
* Default: an `Input`, or a `Textarea` with `multiline
|
|
77
|
+
* Default: an `Input`, or a `Textarea` with `multiline` (string values only).
|
|
52
78
|
*/
|
|
53
|
-
renderEditor?: (props: InlineEditEditorProps) => ReactNode;
|
|
79
|
+
renderEditor?: (props: InlineEditEditorProps<T>) => ReactNode;
|
|
54
80
|
/** Edit in a textarea: Enter adds a line, Ctrl/⌘+Enter saves. */
|
|
55
81
|
multiline?: boolean;
|
|
56
82
|
/** Return a message to refuse the draft; nothing is saved while it returns one. */
|
|
57
|
-
validate?: (next:
|
|
83
|
+
validate?: (next: T) => ReactNode | undefined;
|
|
84
|
+
/** Whether two values are the same (an unchanged draft saves nothing). Default `Object.is`. */
|
|
85
|
+
equals?: (a: T, b: T) => boolean;
|
|
86
|
+
/** Whether a value counts as empty (the view then shows `placeholder`). Default: `null`, `undefined` or `''`. */
|
|
87
|
+
isEmpty?: (value: T) => boolean;
|
|
88
|
+
/**
|
|
89
|
+
* When the draft is saved (HAR-1833).
|
|
90
|
+
* `'explicit'` (default): Enter or Save only; leaving the field keeps the draft open.
|
|
91
|
+
* `'blur'`: also when focus leaves the editor (text fields of a record).
|
|
92
|
+
* `'change'`: as soon as the editor reports a change (a select, a toggle, a date), with no
|
|
93
|
+
* Save button; leaving it unchanged closes it.
|
|
94
|
+
*/
|
|
95
|
+
commit?: 'explicit' | 'blur' | 'change';
|
|
58
96
|
/** Shown in the view while the value is empty, e.g. "Add a description". */
|
|
59
97
|
placeholder?: ReactNode;
|
|
60
|
-
/** Read-only: the value shows as plain text, with no edit
|
|
98
|
+
/** Read-only: the value shows as plain text, with no edit control. */
|
|
61
99
|
disabled?: boolean;
|
|
100
|
+
/**
|
|
101
|
+
* Why the field cannot be edited here ("Set by the integration"). Makes it read-only and
|
|
102
|
+
* shows the reason under the value, which is described by it.
|
|
103
|
+
*/
|
|
104
|
+
readOnlyReason?: ReactNode;
|
|
105
|
+
/**
|
|
106
|
+
* `'value'` (default): the whole value is the button, named "{value}, Edit {label}".
|
|
107
|
+
* `'icon'`: the value is plain text and a pencil button after it is named only "Edit {label}"
|
|
108
|
+
* (for a value that is itself a link, a chip or long text).
|
|
109
|
+
*/
|
|
110
|
+
trigger?: 'value' | 'icon';
|
|
111
|
+
/** Controlled open state, e.g. one field of a record open at a time. */
|
|
112
|
+
editing?: boolean;
|
|
113
|
+
/** Called when the field asks to open (`true`) or close (`false`). */
|
|
114
|
+
onEditingChange?: (editing: boolean) => void;
|
|
115
|
+
/** Controlled draft, e.g. to report unsaved input. Reset to `value` on open. */
|
|
116
|
+
draft?: T;
|
|
117
|
+
/** Called with every change of the draft, and with `value` when the field opens. */
|
|
118
|
+
onDraftChange?: (draft: T) => void;
|
|
119
|
+
/**
|
|
120
|
+
* Renders a failed save under the editor, in place of the message: a Try again button that
|
|
121
|
+
* calls `retry`, or a Reload latest after a version conflict.
|
|
122
|
+
*/
|
|
123
|
+
renderError?: (error: unknown, context: InlineEditErrorContext<T>) => ReactNode;
|
|
124
|
+
/** Called on every change of `InlineEditState`. */
|
|
125
|
+
onStateChange?: (state: InlineEditState) => void;
|
|
62
126
|
/** Each word defaults to `UixLabelsProvider` `inlineEdit`, then to English. */
|
|
63
127
|
labels?: Partial<InlineEditLabels>;
|
|
64
128
|
className?: string;
|
|
@@ -67,8 +131,11 @@ interface InlineEditProps {
|
|
|
67
131
|
* A value that is edited in place (HAR-1381; TENSOR C16 `editable-record.tsx`): the value is
|
|
68
132
|
* a button that says what it edits; activating it swaps in an editor with Save and Cancel.
|
|
69
133
|
* Enter saves and Escape cancels; while `onSave` runs the editor is busy; a failed save keeps
|
|
70
|
-
* the draft and shows why; afterwards focus is back on the value
|
|
134
|
+
* the draft and shows why; afterwards focus is back on the value, which shows what was saved
|
|
135
|
+
* until `value` catches up. HAR-1833: any value type (`equals`, `renderView`, `renderEditor`),
|
|
136
|
+
* saving on blur or on change (`commit`), controllable `editing` and `draft`, `renderError`
|
|
137
|
+
* with retry, `onStateChange`, an icon trigger, and a `readOnlyReason`.
|
|
71
138
|
*/
|
|
72
|
-
declare function InlineEdit({ value, onSave, label, renderView, renderEditor, multiline, validate, placeholder, disabled, labels: labelOverrides, className, }: InlineEditProps): react.JSX.Element;
|
|
139
|
+
declare function InlineEdit<T = string>({ value, onSave, label, renderView, renderEditor, multiline, validate, equals, isEmpty, commit, placeholder, disabled, readOnlyReason, trigger, editing: editingProp, onEditingChange, draft: draftProp, onDraftChange, renderError, onStateChange, labels: labelOverrides, className, }: InlineEditProps<T>): react.JSX.Element;
|
|
73
140
|
|
|
74
|
-
export { DEFAULT_INLINE_EDIT_LABELS, InlineEdit, type InlineEditEditorProps, type InlineEditLabels, type InlineEditProps };
|
|
141
|
+
export { DEFAULT_INLINE_EDIT_LABELS, InlineEdit, type InlineEditEditorProps, type InlineEditErrorContext, type InlineEditLabels, type InlineEditProps, type InlineEditState };
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useEffect, useId, useRef, useState } from "react";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useId, useLayoutEffect, useRef, useState } from "react";
|
|
4
4
|
import { cx } from "../cx.js";
|
|
5
5
|
import { fillLabel } from "../fill-label.js";
|
|
6
6
|
import { useUixLabels } from "../labels-context.js";
|
|
7
|
+
import { useDelayedPending } from "../hooks/useDelayedPending.js";
|
|
7
8
|
import { PencilIcon } from "../icons/components.js";
|
|
8
9
|
import { Button } from "./Button.js";
|
|
9
10
|
import { Input } from "./Input.js";
|
|
@@ -15,8 +16,10 @@ const DEFAULT_INLINE_EDIT_LABELS = {
|
|
|
15
16
|
saving: "Saving\u2026",
|
|
16
17
|
saved: "Saved",
|
|
17
18
|
failed: "Could not save.",
|
|
18
|
-
empty: "Not set"
|
|
19
|
+
empty: "Not set",
|
|
20
|
+
readOnly: "Read-only:"
|
|
19
21
|
};
|
|
22
|
+
const defaultEmpty = (value) => value == null || value === "";
|
|
20
23
|
function InlineEdit({
|
|
21
24
|
value,
|
|
22
25
|
onSave,
|
|
@@ -25,22 +28,45 @@ function InlineEdit({
|
|
|
25
28
|
renderEditor,
|
|
26
29
|
multiline = false,
|
|
27
30
|
validate,
|
|
31
|
+
equals = Object.is,
|
|
32
|
+
isEmpty = defaultEmpty,
|
|
33
|
+
commit = "explicit",
|
|
28
34
|
placeholder,
|
|
29
35
|
disabled = false,
|
|
36
|
+
readOnlyReason,
|
|
37
|
+
trigger = "value",
|
|
38
|
+
editing: editingProp,
|
|
39
|
+
onEditingChange,
|
|
40
|
+
draft: draftProp,
|
|
41
|
+
onDraftChange,
|
|
42
|
+
renderError,
|
|
43
|
+
onStateChange,
|
|
30
44
|
labels: labelOverrides,
|
|
31
45
|
className
|
|
32
46
|
}) {
|
|
33
47
|
const labels = { ...DEFAULT_INLINE_EDIT_LABELS, ...useUixLabels().inlineEdit, ...labelOverrides };
|
|
34
48
|
const id = useId();
|
|
35
49
|
const errorId = `${id}-error`;
|
|
36
|
-
const
|
|
37
|
-
const [
|
|
50
|
+
const reasonId = `${id}-reason`;
|
|
51
|
+
const [editingState, setEditingState] = useState(false);
|
|
52
|
+
const isEditing = editingProp ?? editingState;
|
|
53
|
+
const [draftState, setDraftState] = useState(value);
|
|
54
|
+
const draft = draftProp !== void 0 ? draftProp : draftState;
|
|
38
55
|
const [pending, setPending] = useState(false);
|
|
56
|
+
const pendingVisible = useDelayedPending(pending) && pending;
|
|
39
57
|
const [error, setError] = useState();
|
|
40
58
|
const [status, setStatus] = useState("");
|
|
59
|
+
const [saved, setSaved] = useState(false);
|
|
60
|
+
const [accepted, setAccepted] = useState(null);
|
|
41
61
|
const viewRef = useRef(null);
|
|
42
62
|
const editorRef = useRef(null);
|
|
43
|
-
const
|
|
63
|
+
const focusView = useRef(false);
|
|
64
|
+
const editingRef = useRef(isEditing);
|
|
65
|
+
editingRef.current = isEditing;
|
|
66
|
+
const inFlight = useRef(false);
|
|
67
|
+
const lastSent = useRef(null);
|
|
68
|
+
const session = useRef(0);
|
|
69
|
+
const pressInside = useRef(false);
|
|
44
70
|
const mounted = useRef(true);
|
|
45
71
|
useEffect(() => {
|
|
46
72
|
mounted.current = true;
|
|
@@ -48,83 +74,143 @@ function InlineEdit({
|
|
|
48
74
|
mounted.current = false;
|
|
49
75
|
};
|
|
50
76
|
}, []);
|
|
77
|
+
const lastValue = useRef(value);
|
|
78
|
+
useLayoutEffect(() => {
|
|
79
|
+
if (equals(lastValue.current, value)) return;
|
|
80
|
+
lastValue.current = value;
|
|
81
|
+
setAccepted(null);
|
|
82
|
+
});
|
|
83
|
+
const shown = accepted ? accepted.value : value;
|
|
51
84
|
useEffect(() => {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
85
|
+
if (pendingVisible && pending) setStatus(labels.saving);
|
|
86
|
+
}, [pendingVisible, pending]);
|
|
87
|
+
const state = pending ? "saving" : error?.failure ? "error" : isEditing ? "editing" : saved ? "saved" : "idle";
|
|
88
|
+
const onStateChangeRef = useRef(onStateChange);
|
|
89
|
+
onStateChangeRef.current = onStateChange;
|
|
90
|
+
const reported = useRef("idle");
|
|
91
|
+
useEffect(() => {
|
|
92
|
+
if (reported.current === state) return;
|
|
93
|
+
reported.current = state;
|
|
94
|
+
onStateChangeRef.current?.(state);
|
|
95
|
+
}, [state]);
|
|
96
|
+
const setEditing = (next) => {
|
|
97
|
+
editingRef.current = next;
|
|
98
|
+
if (editingProp === void 0) setEditingState(next);
|
|
99
|
+
onEditingChange?.(next);
|
|
100
|
+
};
|
|
101
|
+
const setDraft = (next) => {
|
|
102
|
+
if (draftProp === void 0) setDraftState(next);
|
|
103
|
+
onDraftChange?.(next);
|
|
104
|
+
};
|
|
105
|
+
useEffect(() => {
|
|
106
|
+
if (isEditing) {
|
|
107
|
+
const control = editorRef.current?.querySelector("input, textarea, select, button, [tabindex]");
|
|
108
|
+
control?.focus();
|
|
109
|
+
if (control instanceof HTMLInputElement || control instanceof HTMLTextAreaElement) control.select();
|
|
57
110
|
return;
|
|
58
111
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
112
|
+
if (focusView.current) {
|
|
113
|
+
focusView.current = false;
|
|
114
|
+
viewRef.current?.focus();
|
|
115
|
+
}
|
|
116
|
+
}, [isEditing]);
|
|
117
|
+
const wasEditing = useRef(isEditing);
|
|
118
|
+
useLayoutEffect(() => {
|
|
119
|
+
if (isEditing && !wasEditing.current && editingProp !== void 0) resetForOpen();
|
|
120
|
+
wasEditing.current = isEditing;
|
|
121
|
+
});
|
|
122
|
+
function resetForOpen() {
|
|
123
|
+
setDraft(shown);
|
|
65
124
|
setError(void 0);
|
|
66
125
|
setStatus("");
|
|
67
|
-
|
|
126
|
+
setSaved(false);
|
|
127
|
+
lastSent.current = null;
|
|
128
|
+
}
|
|
129
|
+
const start = () => {
|
|
130
|
+
session.current += 1;
|
|
131
|
+
resetForOpen();
|
|
68
132
|
setEditing(true);
|
|
69
133
|
};
|
|
70
|
-
const close = () => {
|
|
71
|
-
|
|
134
|
+
const close = (returnFocus) => {
|
|
135
|
+
focusView.current = returnFocus;
|
|
136
|
+
inFlight.current = false;
|
|
72
137
|
setEditing(false);
|
|
73
138
|
};
|
|
74
139
|
const cancel = () => {
|
|
75
|
-
if (
|
|
140
|
+
if (inFlight.current) return;
|
|
76
141
|
setError(void 0);
|
|
77
|
-
|
|
142
|
+
setDraft(shown);
|
|
143
|
+
close(true);
|
|
78
144
|
};
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
145
|
+
const failureMessage = (reason) => typeof reason === "string" && reason ? reason : reason instanceof Error && reason.message ? reason.message : labels.failed;
|
|
146
|
+
const send = (next, explicit) => {
|
|
147
|
+
if (!editingRef.current || inFlight.current) return;
|
|
148
|
+
if (!explicit && error?.failure && lastSent.current && equals(lastSent.current.value, next)) return;
|
|
149
|
+
const issue = validate?.(next);
|
|
82
150
|
if (issue != null) {
|
|
83
|
-
setError(issue);
|
|
151
|
+
setError({ message: issue });
|
|
84
152
|
return;
|
|
85
153
|
}
|
|
86
|
-
if (
|
|
87
|
-
|
|
154
|
+
if (equals(next, shown)) {
|
|
155
|
+
setError(void 0);
|
|
156
|
+
close(explicit);
|
|
88
157
|
return;
|
|
89
158
|
}
|
|
90
159
|
setError(void 0);
|
|
160
|
+
lastSent.current = { value: next };
|
|
161
|
+
const mine = session.current;
|
|
91
162
|
let result;
|
|
92
163
|
try {
|
|
93
|
-
result = onSave(
|
|
164
|
+
result = onSave(next);
|
|
94
165
|
} catch (thrown) {
|
|
95
|
-
setError(
|
|
166
|
+
setError({ message: failureMessage(thrown), failure: { reason: thrown } });
|
|
96
167
|
return;
|
|
97
168
|
}
|
|
98
|
-
|
|
169
|
+
const done = () => {
|
|
170
|
+
setAccepted({ value: next });
|
|
99
171
|
setStatus(labels.saved);
|
|
100
|
-
|
|
172
|
+
setSaved(true);
|
|
173
|
+
if (editingRef.current && session.current === mine) close(explicit);
|
|
174
|
+
};
|
|
175
|
+
if (!result || typeof result.then !== "function") {
|
|
176
|
+
done();
|
|
101
177
|
return;
|
|
102
178
|
}
|
|
179
|
+
inFlight.current = true;
|
|
103
180
|
setPending(true);
|
|
104
|
-
setStatus(labels.saving);
|
|
105
181
|
result.then(
|
|
106
182
|
() => {
|
|
107
183
|
if (!mounted.current) return;
|
|
184
|
+
inFlight.current = false;
|
|
108
185
|
setPending(false);
|
|
109
|
-
|
|
110
|
-
close();
|
|
186
|
+
done();
|
|
111
187
|
},
|
|
112
188
|
(reason) => {
|
|
113
189
|
if (!mounted.current) return;
|
|
190
|
+
inFlight.current = false;
|
|
114
191
|
setPending(false);
|
|
192
|
+
if (session.current !== mine) return;
|
|
115
193
|
setStatus("");
|
|
116
|
-
setError(
|
|
117
|
-
focusNext.current = null;
|
|
194
|
+
setError({ message: failureMessage(reason), failure: { reason } });
|
|
118
195
|
editorRef.current?.querySelector("input, textarea, select")?.focus();
|
|
119
196
|
}
|
|
120
197
|
);
|
|
121
198
|
};
|
|
199
|
+
const save = (next) => send(next === void 0 ? draft : next, true);
|
|
200
|
+
const retry = () => send(lastSent.current && equals(lastSent.current.value, draft) ? lastSent.current.value : draft, true);
|
|
201
|
+
const change = (next) => {
|
|
202
|
+
if (inFlight.current) return;
|
|
203
|
+
setDraft(next);
|
|
204
|
+
if (error && !error.failure) setError(void 0);
|
|
205
|
+
if (commit === "change") send(next, true);
|
|
206
|
+
};
|
|
122
207
|
const onEditorKeyDown = (event) => {
|
|
123
208
|
if (event.key === "Escape") {
|
|
209
|
+
if (event.defaultPrevented || event.target.closest?.('[aria-expanded="true"]')) return;
|
|
124
210
|
event.preventDefault();
|
|
125
211
|
event.stopPropagation();
|
|
126
212
|
cancel();
|
|
127
|
-
} else if (event.key === "Enter" && !event.defaultPrevented) {
|
|
213
|
+
} else if (event.key === "Enter" && !event.defaultPrevented && commit !== "change") {
|
|
128
214
|
const inField = event.target.matches("input, textarea");
|
|
129
215
|
if (!inField) return;
|
|
130
216
|
const isTextarea = event.target.tagName === "TEXTAREA";
|
|
@@ -133,15 +219,56 @@ function InlineEdit({
|
|
|
133
219
|
save();
|
|
134
220
|
}
|
|
135
221
|
};
|
|
222
|
+
const onEditorBlur = (event) => {
|
|
223
|
+
if (commit === "explicit") return;
|
|
224
|
+
const next = event.relatedTarget;
|
|
225
|
+
if (next && event.currentTarget.contains(next)) return;
|
|
226
|
+
if (pressInside.current) return;
|
|
227
|
+
if (next) {
|
|
228
|
+
send(draft, false);
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
const draftNow = draft;
|
|
232
|
+
setTimeout(() => {
|
|
233
|
+
if (!editingRef.current || pressInside.current) return;
|
|
234
|
+
if (editorRef.current?.contains(document.activeElement)) return;
|
|
235
|
+
send(draftNow, false);
|
|
236
|
+
}, 0);
|
|
237
|
+
};
|
|
238
|
+
const onEditorPointerDown = () => {
|
|
239
|
+
pressInside.current = true;
|
|
240
|
+
const release = () => {
|
|
241
|
+
setTimeout(() => {
|
|
242
|
+
pressInside.current = false;
|
|
243
|
+
}, 0);
|
|
244
|
+
window.removeEventListener("pointerup", release, true);
|
|
245
|
+
window.removeEventListener("pointercancel", release, true);
|
|
246
|
+
};
|
|
247
|
+
window.addEventListener("pointerup", release, true);
|
|
248
|
+
window.addEventListener("pointercancel", release, true);
|
|
249
|
+
};
|
|
136
250
|
const liveRegion = /* @__PURE__ */ jsx("span", { className: "uix-visually-hidden", role: "status", "aria-live": "polite", children: status });
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
251
|
+
const empty = isEmpty(shown);
|
|
252
|
+
const display = empty ? /* @__PURE__ */ jsx("span", { className: "uix-inline-edit__placeholder", children: placeholder ?? labels.empty }) : renderView?.(shown) ?? String(shown);
|
|
253
|
+
if (disabled || readOnlyReason != null) {
|
|
254
|
+
return /* @__PURE__ */ jsxs("span", { className: cx("uix-inline-edit", "uix-inline-edit--readonly", readOnlyReason != null && "uix-inline-edit--reason", className), children: [
|
|
255
|
+
/* @__PURE__ */ jsx("span", { className: "uix-inline-edit__value", "aria-describedby": readOnlyReason != null ? reasonId : void 0, children: display }),
|
|
256
|
+
readOnlyReason != null && /* @__PURE__ */ jsxs("span", { id: reasonId, className: "uix-inline-edit__reason", children: [
|
|
257
|
+
/* @__PURE__ */ jsxs("span", { className: "uix-visually-hidden", children: [
|
|
258
|
+
labels.readOnly,
|
|
259
|
+
" "
|
|
260
|
+
] }),
|
|
261
|
+
readOnlyReason
|
|
262
|
+
] })
|
|
263
|
+
] });
|
|
140
264
|
}
|
|
141
|
-
if (!
|
|
142
|
-
return /* @__PURE__ */ jsxs("span", { className: cx("uix-inline-edit", className), children: [
|
|
143
|
-
/* @__PURE__ */ jsxs(
|
|
144
|
-
/* @__PURE__ */ jsx("span", { className: "uix-inline-edit__value", children:
|
|
265
|
+
if (!isEditing) {
|
|
266
|
+
return /* @__PURE__ */ jsxs("span", { className: cx("uix-inline-edit", trigger === "icon" && "uix-inline-edit--icon-trigger", className), children: [
|
|
267
|
+
trigger === "icon" ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
268
|
+
/* @__PURE__ */ jsx("span", { className: "uix-inline-edit__value", children: display }),
|
|
269
|
+
/* @__PURE__ */ jsx("button", { ref: viewRef, type: "button", className: "uix-inline-edit__trigger", "aria-label": fillLabel(labels.edit, { label }), onClick: start, children: /* @__PURE__ */ jsx(PencilIcon, { size: "sm" }) })
|
|
270
|
+
] }) : /* @__PURE__ */ jsxs("button", { ref: viewRef, type: "button", className: "uix-inline-edit__view", onClick: start, children: [
|
|
271
|
+
/* @__PURE__ */ jsx("span", { className: "uix-inline-edit__value", children: display }),
|
|
145
272
|
/* @__PURE__ */ jsxs("span", { className: "uix-visually-hidden", children: [
|
|
146
273
|
", ",
|
|
147
274
|
fillLabel(labels.edit, { label })
|
|
@@ -156,17 +283,33 @@ function InlineEdit({
|
|
|
156
283
|
"aria-label": label,
|
|
157
284
|
"aria-describedby": error != null ? errorId : void 0,
|
|
158
285
|
"aria-invalid": error != null ? true : void 0,
|
|
159
|
-
disabled:
|
|
286
|
+
disabled: pendingVisible,
|
|
287
|
+
readOnly: pendingVisible
|
|
160
288
|
};
|
|
289
|
+
const textDraft = typeof draft === "string" ? draft : String(draft ?? "");
|
|
290
|
+
const errorBody = error && (error.failure && renderError ? renderError(error.failure.reason, { message: error.message, draft, retry, cancel }) : error.message);
|
|
161
291
|
return /* @__PURE__ */ jsxs("span", { className: cx("uix-inline-edit", "uix-inline-edit--editing", className), children: [
|
|
162
|
-
/* @__PURE__ */ jsxs(
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
292
|
+
/* @__PURE__ */ jsxs(
|
|
293
|
+
"div",
|
|
294
|
+
{
|
|
295
|
+
ref: editorRef,
|
|
296
|
+
className: "uix-inline-edit__editor",
|
|
297
|
+
role: "group",
|
|
298
|
+
"aria-label": fillLabel(labels.edit, { label }),
|
|
299
|
+
"aria-busy": pending || void 0,
|
|
300
|
+
onKeyDown: onEditorKeyDown,
|
|
301
|
+
onBlur: onEditorBlur,
|
|
302
|
+
onPointerDownCapture: onEditorPointerDown,
|
|
303
|
+
children: [
|
|
304
|
+
/* @__PURE__ */ jsx("div", { className: "uix-inline-edit__control", children: renderEditor ? renderEditor({ value: draft, onChange: change, save, cancel, field }) : multiline ? /* @__PURE__ */ jsx(Textarea, { ...field, disabled: false, rows: 3, value: textDraft, invalid: error != null, onChange: (event) => change(event.currentTarget.value) }) : /* @__PURE__ */ jsx(Input, { ...field, disabled: false, size: "sm", value: textDraft, invalid: error != null, onChange: (event) => change(event.currentTarget.value) }) }),
|
|
305
|
+
/* @__PURE__ */ jsxs("span", { className: "uix-inline-edit__actions", children: [
|
|
306
|
+
commit !== "change" && /* @__PURE__ */ jsx(Button, { type: "button", size: "sm", variant: "primary", loading: pending, onMouseDown: (event) => event.preventDefault(), onClick: () => save(), children: labels.save }),
|
|
307
|
+
/* @__PURE__ */ jsx(Button, { type: "button", size: "sm", disabled: pendingVisible, onMouseDown: (event) => event.preventDefault(), onClick: cancel, children: labels.cancel })
|
|
308
|
+
] }),
|
|
309
|
+
errorBody != null && /* @__PURE__ */ jsx("div", { id: errorId, className: "uix-field__error uix-inline-edit__error", role: "alert", children: errorBody })
|
|
310
|
+
]
|
|
311
|
+
}
|
|
312
|
+
),
|
|
170
313
|
liveRegion
|
|
171
314
|
] });
|
|
172
315
|
}
|
|
@@ -2,7 +2,11 @@ import * as react from 'react';
|
|
|
2
2
|
import { InputHTMLAttributes, ReactNode, AriaAttributes } from 'react';
|
|
3
3
|
|
|
4
4
|
interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size'> {
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* `sm` 28 px, `md` 36 px (default), `lg` 44 px: the touch-target floor of a public page, the
|
|
7
|
+
* same height as `Button size="lg"` (HAR-1812).
|
|
8
|
+
*/
|
|
9
|
+
size?: 'sm' | 'md' | 'lg';
|
|
6
10
|
invalid?: boolean;
|
|
7
11
|
valid?: boolean;
|
|
8
12
|
/**
|
|
@@ -16,6 +20,12 @@ interface InputGroupProps {
|
|
|
16
20
|
children: ReactNode;
|
|
17
21
|
leadingIcon?: ReactNode;
|
|
18
22
|
trailingIcon?: ReactNode;
|
|
23
|
+
/**
|
|
24
|
+
* A control at the end of the field, inside its border: a reveal toggle, a clear or a copy
|
|
25
|
+
* button (HAR-1376). Give it the class `uix-input-group__action` (an icon button sized to the
|
|
26
|
+
* field) and an accessible name. It takes the place of `trailingIcon`.
|
|
27
|
+
*/
|
|
28
|
+
trailingAction?: ReactNode;
|
|
19
29
|
className?: string;
|
|
20
30
|
/** Injected by `<Field>` when it wraps the group; forwarded onto the child control. */
|
|
21
31
|
id?: string;
|
|
@@ -29,6 +39,6 @@ interface InputGroupProps {
|
|
|
29
39
|
* single child element (the child's own props win) so label/message association survives
|
|
30
40
|
* the extra div (UIX-A11Y-3).
|
|
31
41
|
*/
|
|
32
|
-
declare function InputGroup({ children, leadingIcon, trailingIcon, className, id, 'aria-describedby': describedBy, 'aria-invalid': invalid, 'aria-required': required, }: InputGroupProps): react.JSX.Element;
|
|
42
|
+
declare function InputGroup({ children, leadingIcon, trailingIcon, trailingAction, className, id, 'aria-describedby': describedBy, 'aria-invalid': invalid, 'aria-required': required, }: InputGroupProps): react.JSX.Element;
|
|
33
43
|
|
|
34
44
|
export { Input, InputGroup, type InputGroupProps, type InputProps };
|
package/dist/components/Input.js
CHANGED
|
@@ -6,7 +6,7 @@ const Input = forwardRef(
|
|
|
6
6
|
"input",
|
|
7
7
|
{
|
|
8
8
|
ref,
|
|
9
|
-
className: cx("uix-input", size
|
|
9
|
+
className: cx("uix-input", size !== "md" && `uix-input--${size}`, className),
|
|
10
10
|
"aria-invalid": invalid || void 0,
|
|
11
11
|
"data-valid": valid || void 0,
|
|
12
12
|
"data-warning": warning || void 0,
|
|
@@ -19,6 +19,7 @@ function InputGroup({
|
|
|
19
19
|
children,
|
|
20
20
|
leadingIcon,
|
|
21
21
|
trailingIcon,
|
|
22
|
+
trailingAction,
|
|
22
23
|
className,
|
|
23
24
|
id,
|
|
24
25
|
"aria-describedby": describedBy,
|
|
@@ -37,13 +38,14 @@ function InputGroup({
|
|
|
37
38
|
className: cx(
|
|
38
39
|
"uix-input-group",
|
|
39
40
|
leadingIcon && "uix-input-group--has-leading",
|
|
40
|
-
trailingIcon && "uix-input-group--has-trailing",
|
|
41
|
+
(trailingIcon || trailingAction) && "uix-input-group--has-trailing",
|
|
42
|
+
trailingAction && "uix-input-group--has-action",
|
|
41
43
|
className
|
|
42
44
|
),
|
|
43
45
|
children: [
|
|
44
46
|
leadingIcon && /* @__PURE__ */ jsx("span", { className: "uix-input-group__icon", "aria-hidden": "true", children: leadingIcon }),
|
|
45
47
|
control,
|
|
46
|
-
trailingIcon && /* @__PURE__ */ jsx("span", { className: "uix-input-group__icon uix-input-group__icon--trailing", "aria-hidden": "true", children: trailingIcon })
|
|
48
|
+
trailingAction ?? (trailingIcon && /* @__PURE__ */ jsx("span", { className: "uix-input-group__icon uix-input-group__icon--trailing", "aria-hidden": "true", children: trailingIcon }))
|
|
47
49
|
]
|
|
48
50
|
}
|
|
49
51
|
);
|
|
@@ -13,9 +13,11 @@ declare function Kanban({ announcement, children, className, ...props }: KanbanP
|
|
|
13
13
|
interface KanbanColumnProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {
|
|
14
14
|
title?: ReactNode;
|
|
15
15
|
count?: number;
|
|
16
|
+
/** A dragged card would land in this column: the column body is tinted and outlined (HAR-2590). */
|
|
17
|
+
dropTarget?: boolean;
|
|
16
18
|
children?: ReactNode;
|
|
17
19
|
}
|
|
18
|
-
declare function KanbanColumn({ title, count, children, className, ...props }: KanbanColumnProps): react.JSX.Element;
|
|
20
|
+
declare function KanbanColumn({ title, count, dropTarget, children, className, ...props }: KanbanColumnProps): react.JSX.Element;
|
|
19
21
|
type KanbanMoveDirection = 'up' | 'down' | 'left' | 'right';
|
|
20
22
|
interface KanbanCardProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {
|
|
21
23
|
title?: ReactNode;
|
|
@@ -26,8 +28,17 @@ interface KanbanCardProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'>
|
|
|
26
28
|
* the board-level `announcement` so SR users hear the result.
|
|
27
29
|
*/
|
|
28
30
|
onMove?: (dir: KanbanMoveDirection) => void;
|
|
31
|
+
/** The card is being dragged with the pointer: it lifts (HAR-2590). Call `settleDrop(card)` when it lands. */
|
|
32
|
+
dragging?: boolean;
|
|
29
33
|
children?: ReactNode;
|
|
30
34
|
}
|
|
31
|
-
declare function KanbanCard({ title, meta, children, className, onMove, onKeyDown, ...props }: KanbanCardProps): react.JSX.Element;
|
|
35
|
+
declare function KanbanCard({ title, meta, children, className, onMove, onKeyDown, dragging, ...props }: KanbanCardProps): react.JSX.Element;
|
|
36
|
+
type KanbanDropLineProps = HTMLAttributes<HTMLDivElement>;
|
|
37
|
+
/**
|
|
38
|
+
* Where a dragged card would land between two cards (HAR-2590): an accent line with an end mark.
|
|
39
|
+
* Render it in the column at the insertion point while a drag is over it (also after the last
|
|
40
|
+
* card); it is decorative (the keyboard path and the board's `announcement` say where it goes).
|
|
41
|
+
*/
|
|
42
|
+
declare function KanbanDropLine({ className, ...props }: KanbanDropLineProps): react.JSX.Element;
|
|
32
43
|
|
|
33
|
-
export { Kanban, KanbanCard, type KanbanCardProps, KanbanColumn, type KanbanColumnProps, type KanbanMoveDirection, type KanbanProps };
|
|
44
|
+
export { Kanban, KanbanCard, type KanbanCardProps, KanbanColumn, type KanbanColumnProps, KanbanDropLine, type KanbanDropLineProps, type KanbanMoveDirection, type KanbanProps };
|