@sincpro/web-ui 0.1.0 → 1.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.
- package/README.md +40 -13
- package/dist/components/activity/Activity.d.ts +69 -0
- package/dist/components/activity/Activity.js +279 -0
- package/dist/components/activity/ActivityBadge.d.ts +16 -0
- package/dist/components/activity/ActivityBadge.js +29 -0
- package/dist/components/{chatter → activity}/Messages.d.ts +2 -2
- package/dist/components/{chatter → activity}/Messages.js +9 -6
- package/dist/components/activity/index.d.ts +4 -0
- package/dist/components/activity/index.js +5 -0
- package/dist/components/assist/AssistMark.d.ts +3 -3
- package/dist/components/assist/AssistMark.js +1 -1
- package/dist/components/assist/assist.d.ts +1 -1
- package/dist/components/assist/assist.js +1 -1
- package/dist/components/calendar/RecordCalendar.d.ts +48 -0
- package/dist/components/calendar/RecordCalendar.js +101 -0
- package/dist/components/calendar/index.d.ts +1 -0
- package/dist/components/calendar/index.js +1 -0
- package/dist/components/form/Sheet.d.ts +4 -0
- package/dist/components/form/Sheet.js +16 -5
- package/dist/components/gantt/RecordGantt.d.ts +44 -0
- package/dist/components/gantt/RecordGantt.js +110 -0
- package/dist/components/gantt/index.d.ts +1 -0
- package/dist/components/gantt/index.js +1 -0
- package/dist/components/index.d.ts +4 -1
- package/dist/components/index.js +4 -1
- package/dist/components/lines/LineItems.d.ts +45 -5
- package/dist/components/lines/LineItems.js +106 -18
- package/dist/components/listing/BoardColumns.d.ts +39 -0
- package/dist/components/listing/BoardColumns.js +138 -0
- package/dist/components/listing/Listing.js +1 -1
- package/dist/components/listing/ListingBar.d.ts +46 -2
- package/dist/components/listing/ListingBar.js +47 -5
- package/dist/components/listing/PivotExplorer.d.ts +34 -0
- package/dist/components/listing/PivotExplorer.js +86 -0
- package/dist/components/listing/RecordCard.d.ts +6 -8
- package/dist/components/listing/RecordCard.js +13 -7
- package/dist/components/listing/Row.d.ts +25 -2
- package/dist/components/listing/Row.js +30 -13
- package/dist/components/listing/index.d.ts +2 -0
- package/dist/components/listing/index.js +2 -0
- package/dist/components/listing/set.d.ts +1 -1
- package/dist/components/navigation/index.d.ts +0 -2
- package/dist/components/navigation/index.js +2 -3
- package/dist/components/record/RecordAudit.d.ts +17 -0
- package/dist/components/record/RecordAudit.js +27 -0
- package/dist/components/record/RecordHeader.d.ts +27 -17
- package/dist/components/record/RecordHeader.js +64 -20
- package/dist/components/record/RecordNotices.d.ts +37 -0
- package/dist/components/record/RecordNotices.js +75 -0
- package/dist/components/record/RecordRibbon.d.ts +13 -0
- package/dist/components/record/RecordRibbon.js +22 -0
- package/dist/components/record/ThumbBar.js +1 -1
- package/dist/components/record/index.d.ts +2 -0
- package/dist/components/record/index.js +2 -0
- package/dist/components/search/CriteriaChips.d.ts +6 -1
- package/dist/components/search/CriteriaChips.js +71 -20
- package/dist/components/search/SearchBar.d.ts +4 -1
- package/dist/components/search/SearchBar.js +15 -7
- package/dist/components/timeline/RecordTimeline.d.ts +60 -0
- package/dist/components/timeline/RecordTimeline.js +214 -0
- package/dist/components/timeline/TimelineToolbar.d.ts +30 -0
- package/dist/components/timeline/TimelineToolbar.js +31 -0
- package/dist/components/timeline/index.d.ts +3 -0
- package/dist/components/timeline/index.js +3 -0
- package/dist/components/timeline/time.d.ts +43 -0
- package/dist/components/timeline/time.js +135 -0
- package/dist/foundations/copy.d.ts +194 -18
- package/dist/foundations/copy.es.js +142 -15
- package/dist/foundations/copy.js +133 -11
- package/dist/foundations/index.d.ts +1 -1
- package/dist/foundations/match.d.ts +23 -0
- package/dist/foundations/match.js +63 -0
- package/dist/foundations/slots.d.ts +1 -1
- package/dist/foundations/slots.js +8 -3
- package/dist/foundations/types.d.ts +7 -0
- package/dist/foundations/types.js +0 -36
- package/dist/primitives/block/index.d.ts +1 -1
- package/dist/primitives/block/index.js +1 -1
- package/dist/primitives/cell/CellStack.d.ts +7 -1
- package/dist/primitives/cell/CellStack.js +5 -2
- package/dist/primitives/choice/ComboBox.d.ts +3 -0
- package/dist/primitives/choice/ComboBox.js +10 -6
- package/dist/primitives/choice/KanbanState.d.ts +14 -0
- package/dist/primitives/choice/KanbanState.js +37 -0
- package/dist/primitives/choice/Priority.d.ts +20 -0
- package/dist/primitives/choice/Priority.js +41 -0
- package/dist/primitives/choice/SearchField.d.ts +10 -1
- package/dist/primitives/choice/SearchField.js +21 -2
- package/dist/primitives/choice/Slider.d.ts +6 -1
- package/dist/primitives/choice/Slider.js +2 -2
- package/dist/primitives/choice/index.d.ts +2 -0
- package/dist/primitives/choice/index.js +2 -0
- package/dist/primitives/date/Calendar.js +30 -6
- package/dist/primitives/date/DatePicker.d.ts +11 -3
- package/dist/primitives/date/DatePicker.js +12 -8
- package/dist/primitives/date/DateTime.d.ts +35 -0
- package/dist/primitives/date/DateTime.js +100 -0
- package/dist/primitives/date/index.d.ts +1 -0
- package/dist/primitives/date/index.js +4 -2
- package/dist/primitives/dialog/Dialog.d.ts +9 -3
- package/dist/primitives/dialog/Dialog.js +41 -5
- package/dist/primitives/field/DropZone.js +1 -1
- package/dist/primitives/field/Field.d.ts +14 -2
- package/dist/primitives/field/Field.js +25 -14
- package/dist/primitives/field/copy.d.ts +16 -0
- package/dist/primitives/field/copy.js +69 -0
- package/dist/primitives/field/index.d.ts +2 -0
- package/dist/primitives/field/index.js +4 -0
- package/dist/primitives/field/note.d.ts +55 -0
- package/dist/primitives/field/note.js +117 -0
- package/dist/primitives/index.d.ts +1 -0
- package/dist/primitives/index.js +1 -0
- package/dist/primitives/menu/Menu.d.ts +28 -0
- package/dist/primitives/menu/Menu.js +47 -17
- package/dist/primitives/notice/Callout.js +1 -1
- package/dist/primitives/notice/Flag.d.ts +13 -0
- package/dist/primitives/notice/Flag.js +31 -0
- package/dist/primitives/notice/index.d.ts +2 -1
- package/dist/primitives/notice/index.js +2 -1
- package/dist/primitives/overlay/Preview.d.ts +19 -0
- package/dist/primitives/overlay/Preview.js +69 -0
- package/dist/primitives/overlay/index.d.ts +1 -0
- package/dist/primitives/overlay/index.js +3 -1
- package/dist/primitives/picker/MatchedText.d.ts +10 -0
- package/dist/primitives/picker/MatchedText.js +12 -0
- package/dist/primitives/picker/Picker.d.ts +67 -4
- package/dist/primitives/picker/Picker.js +142 -23
- package/dist/primitives/table/CellCopy.d.ts +20 -0
- package/dist/primitives/table/CellCopy.js +23 -0
- package/dist/primitives/table/DataTable.d.ts +55 -1
- package/dist/primitives/table/DataTable.js +126 -40
- package/dist/primitives/table/EditableTable.d.ts +102 -2
- package/dist/primitives/table/EditableTable.js +287 -32
- package/dist/primitives/table/ReportTable.js +2 -1
- package/dist/primitives/table/RowActions.js +7 -2
- package/dist/primitives/table/SheetTable.d.ts +4 -1
- package/dist/primitives/table/SheetTable.js +38 -5
- package/dist/primitives/table/Table.d.ts +5 -0
- package/dist/primitives/table/Table.js +17 -8
- package/dist/primitives/table/index.d.ts +2 -2
- package/dist/primitives/table/index.js +1 -1
- package/dist/primitives/tabs/Tabs.d.ts +2 -2
- package/dist/primitives/tabs/Tabs.js +1 -1
- package/dist/primitives/tag/Tags.d.ts +2 -0
- package/dist/primitives/tag/Tags.js +2 -1
- package/dist/primitives/tag/TagsField.d.ts +13 -0
- package/dist/primitives/tag/TagsField.js +39 -10
- package/dist/primitives/tag/choices.d.ts +2 -0
- package/dist/primitives/tree/Tree.d.ts +56 -0
- package/dist/primitives/tree/Tree.js +74 -0
- package/dist/primitives/tree/index.d.ts +1 -0
- package/dist/primitives/tree/index.js +3 -0
- package/dist/primitives/value/Avatar.d.ts +16 -0
- package/dist/primitives/value/Avatar.js +91 -0
- package/dist/primitives/value/Copyable.d.ts +11 -0
- package/dist/primitives/value/Copyable.js +27 -6
- package/dist/primitives/value/Fecha.js +10 -1
- package/dist/primitives/value/Person.d.ts +6 -51
- package/dist/primitives/value/Person.js +9 -148
- package/dist/primitives/value/ProgressBar.d.ts +31 -0
- package/dist/primitives/value/ProgressBar.js +53 -0
- package/dist/primitives/value/Relation.d.ts +22 -5
- package/dist/primitives/value/Relation.js +42 -14
- package/dist/primitives/value/Totals.d.ts +102 -7
- package/dist/primitives/value/Totals.js +52 -2
- package/dist/primitives/value/Value.d.ts +0 -37
- package/dist/primitives/value/Value.js +0 -39
- package/dist/primitives/value/contact.d.ts +30 -0
- package/dist/primitives/value/contact.js +51 -0
- package/dist/primitives/value/index.d.ts +5 -4
- package/dist/primitives/value/index.js +5 -4
- package/dist/tokens.css +179 -7
- package/dist/views/list/List.d.ts +32 -3
- package/dist/views/list/List.js +51 -7
- package/dist/views/list/ListView.d.ts +1 -1
- package/dist/views/list/ListView.js +70 -13
- package/dist/views/list/columns.js +8 -1
- package/dist/views/list/derive.d.ts +12 -1
- package/dist/views/list/derive.js +29 -3
- package/dist/views/list/presentations.d.ts +5 -2
- package/dist/views/list/presentations.js +35 -3
- package/dist/views/list/types.d.ts +57 -1
- package/dist/views/list/useNarrowList.d.ts +10 -0
- package/dist/views/list/useNarrowList.js +20 -6
- package/dist/views/record/Record.d.ts +41 -8
- package/dist/views/record/Record.js +113 -28
- package/dist/views/record/index.d.ts +1 -1
- package/package.json +15 -4
- package/dist/components/chatter/Chatter.d.ts +0 -161
- package/dist/components/chatter/Chatter.js +0 -232
- package/dist/components/chatter/index.d.ts +0 -3
- package/dist/components/chatter/index.js +0 -4
- package/dist/components/navigation/CommandPalette.d.ts +0 -40
- package/dist/components/navigation/CommandPalette.js +0 -114
- package/dist/components/navigation/commands.d.ts +0 -30
- package/dist/components/navigation/commands.js +0 -30
- /package/dist/components/{chatter → activity}/Timeline.d.ts +0 -0
- /package/dist/components/{chatter → activity}/Timeline.js +0 -0
|
@@ -3,14 +3,29 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { useUiCopy } from "../../foundations/copy.js";
|
|
4
4
|
import { buttonClasses, } from "../button/Button.js";
|
|
5
5
|
import { Popover } from "../overlay/Popover.js";
|
|
6
|
-
import { Check, ChevronDown } from "lucide-react";
|
|
7
|
-
import { Autocomplete, Button as AriaButton, Header, Input, Menu as AriaMenu, MenuItem, MenuSection, MenuTrigger, SearchField, Separator, useFilter, } from "react-aria-components";
|
|
6
|
+
import { Check, ChevronDown, ChevronRight } from "lucide-react";
|
|
7
|
+
import { Autocomplete, Button as AriaButton, Header, Input, Keyboard, Menu as AriaMenu, MenuItem, MenuSection, MenuTrigger, SearchField, Separator, SubmenuTrigger, useFilter, } from "react-aria-components";
|
|
8
8
|
const WIDTH = {
|
|
9
9
|
/** A menu of short verbs hanging off an icon: "duplicate", "delete". */
|
|
10
10
|
sm: "min-w-44 max-w-64",
|
|
11
11
|
md: "min-w-56 max-w-80",
|
|
12
12
|
lg: "min-w-80 max-w-(--container-short)",
|
|
13
13
|
};
|
|
14
|
+
/** A submenu opens beside its row, flush against the parent panel and pulled up by the
|
|
15
|
+
* panel's padding plus its hairline (`p-1` + 1), so its first row lines up with the row that
|
|
16
|
+
* opened it — a submenu that starts half a row lower reads as belonging to the next one. */
|
|
17
|
+
const SUBMENU_OFFSET = 0;
|
|
18
|
+
const SUBMENU_CROSS_OFFSET = -5;
|
|
19
|
+
/** Every option of the tree by id, children included: a submenu is a separate React Aria
|
|
20
|
+
* menu with its own `onAction`, and both have to reach the same handlers. */
|
|
21
|
+
export function indexOptions(options, into = new Map()) {
|
|
22
|
+
for (const o of options) {
|
|
23
|
+
into.set(o.id, o);
|
|
24
|
+
if (o.items !== undefined)
|
|
25
|
+
indexOptions(o.items, into);
|
|
26
|
+
}
|
|
27
|
+
return into;
|
|
28
|
+
}
|
|
14
29
|
export function Menu({ label, groups, onSelect, surface = "canvas", align = "start", icon: Trigger,
|
|
15
30
|
/** The menu as a control of a list ("filters ▾") carries the chevron; the
|
|
16
31
|
* actions `⋯` does not, because the icon already says there is more. */
|
|
@@ -29,18 +44,41 @@ chevron = true, active = false, iconOnly = false, variant = "button", searchPlac
|
|
|
29
44
|
: surface === "chrome"
|
|
30
45
|
? `border-chrome-muted/35 bg-chrome-raised text-chrome-ink hover:border-chrome-accent/45 ${active ? "border-chrome-accent/60" : ""}`
|
|
31
46
|
: `border-line-strong bg-surface hover:border-primary/45 hover:bg-primary/5 ${active ? "border-primary/60 text-primary" : "text-ink"}`;
|
|
32
|
-
const
|
|
33
|
-
const
|
|
34
|
-
const byId = new Map(groups.flatMap((g) => g.options.map((o) => [o.id, o])));
|
|
35
|
-
const menu = (_jsx(AriaMenu, { "aria-label": label, shouldCloseOnSelect: closeOnSelect, onAction: (key) => {
|
|
47
|
+
const byId = indexOptions(groups.flatMap((g) => g.options));
|
|
48
|
+
const menu = (_jsx(MenuList, { label: label, groups: groups, width: width, closeOnSelect: closeOnSelect, onAction: (key) => {
|
|
36
49
|
const option = byId.get(String(key));
|
|
37
50
|
option?.onSelect?.();
|
|
38
51
|
onSelect?.(String(key));
|
|
39
|
-
},
|
|
52
|
+
}, emptyText: emptyText ?? copy.menu.empty }));
|
|
53
|
+
return (_jsxs(MenuTrigger, { children: [_jsx(AriaButton, { "aria-label": iconOnly ? label : undefined, ...(role === undefined ? {} : { "data-emphasis": role }), className: ({ isPressed, isFocusVisible }) => role === undefined
|
|
54
|
+
? `inline-flex h-(--size-control-sm) shrink-0 cursor-default items-center gap-1.5 border text-micro font-medium whitespace-nowrap outline-0 transition-colors duration-(--duration-instant) ${isFocusVisible ? "outline-2 outline-offset-2 outline-primary" : ""} ${iconOnly ? "w-(--size-control-sm) justify-center rounded-pill" : "rounded-control px-2.5"} ${triggerClass(isPressed)}`
|
|
55
|
+
: `${buttonClasses(role, size, surface)} gap-1.5`, children: _jsxs("span", { className: "contents", title: title ?? (iconOnly ? label : undefined), children: [Trigger === undefined ? (iconOnly ? (_jsx(ChevronDown, { className: "size-(--size-icon-sm)", strokeWidth: 2, "aria-hidden": true })) : null) : (_jsx(Trigger, { className: "size-(--size-icon-sm)", strokeWidth: 2, "aria-hidden": true })), iconOnly ? null : label, chevron && !iconOnly ? (_jsx(ChevronDown, { className: "size-(--size-icon-sm)", strokeWidth: 2, "aria-hidden": true })) : null] }) }), _jsx(Popover, { placement: align === "end" ? "bottom end" : "bottom start", className: WIDTH[width], children: searchPlaceholder === undefined ? (menu) : (
|
|
56
|
+
/* The search box stays at the top: in a menu of twenty-five entries,
|
|
57
|
+
scrolling loses exactly the control that explains why only three are
|
|
58
|
+
visible. It filters on label AND hint — half the entries of this
|
|
59
|
+
product are told apart only by the hint. */
|
|
60
|
+
_jsxs(Autocomplete, { filter: contains, children: [_jsx(SearchField, { "aria-label": searchPlaceholder, autoFocus: true, className: "border-b border-line px-2 pt-2 pb-2", children: _jsx(Input, { placeholder: searchPlaceholder, className: "h-(--size-control-sm) w-full rounded-control border border-line-strong bg-surface px-2.5 text-meta text-ink outline-0 placeholder:text-muted focus-visible:border-primary" }) }), menu] })) })] }));
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The panel of a `Menu`: its groups and rows, and the submenus hanging from them. Internal —
|
|
64
|
+
* it is not exported from the family — and separate from the trigger for two reasons: a
|
|
65
|
+
* submenu is this same panel one level down, and a panel can be rendered on the server
|
|
66
|
+
* without the trigger's popover, which is how the tests see the rows.
|
|
67
|
+
*/
|
|
68
|
+
export function MenuList({ label, groups, onAction, closeOnSelect, emptyText, width = "md", }) {
|
|
69
|
+
/* Per panel: a submenu without icons does not inherit its parent's mark column. */
|
|
70
|
+
const hasMarks = groups.some((g) => g.options.some((o) => o.checked !== undefined || o.icon !== undefined));
|
|
71
|
+
const hasHints = groups.some((g) => g.options.some((o) => o.hint !== undefined));
|
|
72
|
+
const row = (o) => {
|
|
73
|
+
const Icon = o.icon;
|
|
74
|
+
const opens = o.items !== undefined;
|
|
75
|
+
const checked = !opens && o.checked === true;
|
|
76
|
+
return (_jsxs(MenuItem, { id: o.id, textValue: o.hint === undefined ? o.label : `${o.label} ${o.hint}`, isDisabled: o.disabled, className: `flex w-full cursor-default rounded-control ${hasHints ? "items-start py-1.5" : "items-center py-1"} gap-2 px-2 text-left outline-0 transition-colors duration-(--duration-instant) data-focused:bg-primary/8 data-open:bg-primary/8 disabled:opacity-45`, children: [hasMarks ? (_jsx("span", { className: `${hasHints ? "mt-0.5" : ""} flex size-(--size-icon-sm) shrink-0 items-center justify-center`, children: checked ? (_jsx(Check, { className: "size-(--size-icon-sm) text-primary", strokeWidth: 2.5, "aria-hidden": true })) : Icon !== undefined ? (_jsx(Icon, { className: "size-(--size-icon-sm) text-muted", strokeWidth: 2, "aria-hidden": true })) : null })) : null, _jsxs("span", { className: "min-w-0 flex-1", children: [_jsxs("span", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: `truncate text-meta ${checked ? "font-medium text-ink" : "text-ink"}`, children: o.label }), o.badge === undefined ? null : typeof o.badge === "string" ? (_jsx("span", { className: "inline-flex shrink-0 items-center rounded-pill border border-warn/30 bg-warn/10 px-2 py-0.5 text-micro text-warn", children: o.badge })) : (_jsx("span", { className: "ml-auto shrink-0", children: o.badge }))] }), o.hint === undefined ? null : (_jsx("span", { className: "mt-0.5 block truncate text-micro text-muted", children: o.hint }))] }), o.shortcut === undefined ? null : (_jsx(Keyboard, { className: "shrink-0 self-center pl-3 font-mono text-micro text-muted", children: o.shortcut })), opens ? (_jsx(ChevronRight, { className: "size-(--size-icon-sm) shrink-0 self-center text-muted", strokeWidth: 2, "aria-hidden": true })) : null] }, o.id));
|
|
77
|
+
};
|
|
78
|
+
return (_jsx(AriaMenu, { "aria-label": label, shouldCloseOnSelect: closeOnSelect, onAction: onAction, renderEmptyState: () => (_jsx("p", { className: "px-3 py-3 text-meta text-muted italic", children: emptyText })), className: "max-h-[inherit] overflow-y-auto p-1 outline-0", children: groups.map((g, gi) => (_jsxs(MenuSection, { className: "[&:not(:first-child)]:mt-1 [&:not(:first-child)]:border-t [&:not(:first-child)]:border-line [&:not(:first-child)]:pt-1", children: [g.label === undefined ? null : (
|
|
40
79
|
/* Same skeleton as the row: the label sits on the text column. */
|
|
41
80
|
_jsxs(Header, { className: "flex items-center gap-2 px-2 pt-1 pb-0.5 text-micro font-medium text-muted", children: [hasMarks ? (_jsx("span", { className: "size-(--size-icon-sm) shrink-0", "aria-hidden": true })) : null, g.label] })), g.options.flatMap((o) => {
|
|
42
|
-
const
|
|
43
|
-
const item = (_jsxs(MenuItem, { id: o.id, textValue: o.hint === undefined ? o.label : `${o.label} ${o.hint}`, isDisabled: o.disabled, className: `flex w-full cursor-default rounded-control ${hasHints ? "items-start py-1.5" : "items-center py-1"} gap-2 px-2 text-left outline-0 transition-colors duration-(--duration-instant) data-focused:bg-primary/8 disabled:opacity-45`, children: [hasMarks ? (_jsx("span", { className: `${hasHints ? "mt-0.5" : ""} flex size-(--size-icon-sm) shrink-0 items-center justify-center`, children: o.checked === true ? (_jsx(Check, { className: "size-(--size-icon-sm) text-primary", strokeWidth: 2.5, "aria-hidden": true })) : Icon !== undefined ? (_jsx(Icon, { className: "size-(--size-icon-sm) text-muted", strokeWidth: 2, "aria-hidden": true })) : null })) : null, _jsxs("span", { className: "min-w-0 flex-1", children: [_jsxs("span", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: `truncate text-meta ${o.checked === true ? "font-medium text-ink" : "text-ink"}`, children: o.label }), o.badge === undefined ? null : typeof o.badge === "string" ? (_jsx("span", { className: "inline-flex shrink-0 items-center rounded-pill border border-warn/30 bg-warn/10 px-2 py-0.5 text-micro text-warn", children: o.badge })) : (_jsx("span", { className: "ml-auto shrink-0", children: o.badge }))] }), o.hint === undefined ? null : (_jsx("span", { className: "mt-0.5 block truncate text-micro text-muted", children: o.hint }))] })] }, o.id));
|
|
81
|
+
const item = o.items === undefined ? (row(o)) : (_jsxs(SubmenuTrigger, { children: [row(o), _jsx(Popover, { offset: SUBMENU_OFFSET, crossOffset: SUBMENU_CROSS_OFFSET, className: WIDTH[width], children: _jsx(MenuList, { label: o.label, groups: [{ options: [...o.items] }], onAction: onAction, closeOnSelect: closeOnSelect, emptyText: emptyText, width: width }) })] }, o.id));
|
|
44
82
|
return o.divider === true
|
|
45
83
|
? [
|
|
46
84
|
_jsx(Separator, { className: "my-1 h-px border-0 bg-line" }, `${o.id}-divider`),
|
|
@@ -48,12 +86,4 @@ chevron = true, active = false, iconOnly = false, variant = "button", searchPlac
|
|
|
48
86
|
]
|
|
49
87
|
: [item];
|
|
50
88
|
})] }, g.label ?? gi))) }));
|
|
51
|
-
return (_jsxs(MenuTrigger, { children: [_jsx(AriaButton, { "aria-label": iconOnly ? label : undefined, ...(role === undefined ? {} : { "data-emphasis": role }), className: ({ isPressed, isFocusVisible }) => role === undefined
|
|
52
|
-
? `inline-flex h-(--size-control-sm) shrink-0 cursor-default items-center gap-1.5 border text-micro font-medium whitespace-nowrap outline-0 transition-colors duration-(--duration-instant) ${isFocusVisible ? "outline-2 outline-offset-2 outline-primary" : ""} ${iconOnly ? "w-(--size-control-sm) justify-center rounded-pill" : "rounded-control px-2.5"} ${triggerClass(isPressed)}`
|
|
53
|
-
: `${buttonClasses(role, size, surface)} gap-1.5`, children: _jsxs("span", { className: "contents", title: title ?? (iconOnly ? label : undefined), children: [Trigger === undefined ? (iconOnly ? (_jsx(ChevronDown, { className: "size-(--size-icon-sm)", strokeWidth: 2, "aria-hidden": true })) : null) : (_jsx(Trigger, { className: "size-(--size-icon-sm)", strokeWidth: 2, "aria-hidden": true })), iconOnly ? null : label, chevron && !iconOnly ? (_jsx(ChevronDown, { className: "size-(--size-icon-sm)", strokeWidth: 2, "aria-hidden": true })) : null] }) }), _jsx(Popover, { placement: align === "end" ? "bottom end" : "bottom start", className: WIDTH[width], children: searchPlaceholder === undefined ? (menu) : (
|
|
54
|
-
/* The search box stays at the top: in a menu of twenty-five entries,
|
|
55
|
-
scrolling loses exactly the control that explains why only three are
|
|
56
|
-
visible. It filters on label AND hint — half the entries of this
|
|
57
|
-
product are told apart only by the hint. */
|
|
58
|
-
_jsxs(Autocomplete, { filter: contains, children: [_jsx(SearchField, { "aria-label": searchPlaceholder, autoFocus: true, className: "border-b border-line px-2 pt-2 pb-2", children: _jsx(Input, { placeholder: searchPlaceholder, className: "h-(--size-control-sm) w-full rounded-control border border-line-strong bg-surface px-2.5 text-meta text-ink outline-0 placeholder:text-muted focus-visible:border-primary" }) }), menu] })) })] }));
|
|
59
89
|
}
|
|
@@ -24,5 +24,5 @@ export function Callout({ children, tone = "info", title, action, onDismiss, dis
|
|
|
24
24
|
/* `status` y no `alert`: `alert` interrumpe al lector de pantalla y se
|
|
25
25
|
reserva para lo que pasó JUSTO AHORA. Un aviso que ya estaba cuando la
|
|
26
26
|
pantalla abrió no interrumpe nada. */
|
|
27
|
-
role: "status", className: `flex min-w-0 items-start gap-2.5 rounded-box border ${SKIN[tone]} ${byDensity(d, "px-3 py-2.5", "px-2.5 py-2")}`, children: [_jsx(Icon, { className: "mt-0.5 size-(--size-icon-sm) shrink-0", strokeWidth: 2, "aria-hidden": true }), _jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-1", children: [title === undefined ? null : (_jsx("p", { className: "text-meta font-medium text-ink", children: title })), _jsx("div", { className: "min-w-0 text-meta text-ink", children: children })] }), action === undefined ? null : _jsx("span", { className: "shrink-0", children: action }), onDismiss === undefined ? null : (_jsx("button", { type: "button", onClick: onDismiss, "aria-label": dismissLabel ?? "cerrar", title: dismissLabel ?? "cerrar", className: "-mr-1 shrink-0 rounded-control p-0.5 text-muted transition-colors duration-(--duration-instant) hover:bg-ink/6 hover:text-ink", children: _jsx(X, { className: "size-(--size-icon-sm)", strokeWidth: 2 }) }))] }));
|
|
27
|
+
role: "status", className: `flex min-w-0 items-start gap-2.5 rounded-box border ${SKIN[tone]} ${byDensity(d, "px-3 py-2.5", "px-2.5 py-2")}`, children: [_jsx(Icon, { className: "mt-0.5 size-(--size-icon-sm) shrink-0", strokeWidth: 2, "aria-hidden": true }), _jsxs("div", { className: "flex min-w-0 flex-1 flex-wrap items-start gap-x-3 gap-y-2", children: [_jsxs("div", { className: "flex min-w-0 flex-1 basis-(--container-name) flex-col gap-1", children: [title === undefined ? null : (_jsx("p", { className: "text-meta font-medium text-ink", children: title })), _jsx("div", { className: "min-w-0 text-meta text-ink", children: children })] }), action === undefined ? null : _jsx("span", { className: "shrink-0", children: action })] }), onDismiss === undefined ? null : (_jsx("button", { type: "button", onClick: onDismiss, "aria-label": dismissLabel ?? "cerrar", title: dismissLabel ?? "cerrar", className: "-mr-1 shrink-0 rounded-control p-0.5 text-muted transition-colors duration-(--duration-instant) hover:bg-ink/6 hover:text-ink", children: _jsx(X, { className: "size-(--size-icon-sm)", strokeWidth: 2 }) }))] }));
|
|
28
28
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Tone } from "../../foundations/types.js";
|
|
2
|
+
import type { ReactNode } from "react";
|
|
3
|
+
export type FlagTone = Extract<Tone, "bad" | "warn" | "info" | "good">;
|
|
4
|
+
export type FlagProps = {
|
|
5
|
+
tone: FlagTone;
|
|
6
|
+
/** The sentence the mark stands for — «Sin existencias». It names the mark and heads
|
|
7
|
+
* the popover. */
|
|
8
|
+
label: string;
|
|
9
|
+
/** What explains it, inside the popover: the figures, what to do. */
|
|
10
|
+
children?: ReactNode;
|
|
11
|
+
};
|
|
12
|
+
/** A toned mark that opens its sentence. See the file's header. */
|
|
13
|
+
export declare function Flag({ tone, label, children }: FlagProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { tv } from "../../foundations/variants.js";
|
|
4
|
+
import { Popover } from "../overlay/Popover.js";
|
|
5
|
+
import { CircleAlert, CircleCheck, Info, TriangleAlert } from "lucide-react";
|
|
6
|
+
import { Button, Dialog, DialogTrigger, Heading } from "react-aria-components";
|
|
7
|
+
const ICON = {
|
|
8
|
+
bad: CircleAlert,
|
|
9
|
+
warn: TriangleAlert,
|
|
10
|
+
info: Info,
|
|
11
|
+
good: CircleCheck,
|
|
12
|
+
};
|
|
13
|
+
const mark = tv({
|
|
14
|
+
base: "inline-flex size-5 shrink-0 cursor-default items-center justify-center rounded-pill outline-0 transition-colors duration-(--duration-instant) forced-colors:text-[ButtonText]",
|
|
15
|
+
variants: {
|
|
16
|
+
tone: {
|
|
17
|
+
bad: "bg-bad/12 text-bad hover:bg-bad/20 aria-expanded:bg-bad/20",
|
|
18
|
+
warn: "bg-warn/15 text-warn hover:bg-warn/25 aria-expanded:bg-warn/25",
|
|
19
|
+
info: "bg-info/12 text-info hover:bg-info/20 aria-expanded:bg-info/20",
|
|
20
|
+
good: "bg-good/12 text-good hover:bg-good/20 aria-expanded:bg-good/20",
|
|
21
|
+
},
|
|
22
|
+
isFocusVisible: {
|
|
23
|
+
true: "outline-2 outline-offset-1 outline-primary forced-colors:outline-[Highlight]",
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
/** A toned mark that opens its sentence. See the file's header. */
|
|
28
|
+
export function Flag({ tone, label, children }) {
|
|
29
|
+
const Icon = ICON[tone];
|
|
30
|
+
return (_jsxs(DialogTrigger, { children: [_jsx("span", { className: "inline-flex shrink-0", onClick: (e) => e.stopPropagation(), children: _jsx(Button, { "aria-label": label, className: (state) => mark({ ...state, tone }), children: _jsx(Icon, { className: "size-(--size-icon-sm)", strokeWidth: 2.25, "aria-hidden": true }) }) }), _jsx(Popover, { placement: "bottom start", className: "max-w-72 rounded-box", children: _jsxs(Dialog, { className: "flex flex-col gap-1 px-3 py-2.5 outline-0", children: [_jsx(Heading, { slot: "title", className: "text-meta font-medium text-ink", children: label }), children === undefined ? null : (_jsx("div", { className: "text-micro leading-relaxed text-muted", children: children }))] }) })] }));
|
|
31
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { Callout, type CalloutProps } from "./Callout.js";
|
|
2
|
+
export { Flag, type FlagProps, type FlagTone } from "./Flag.js";
|
|
2
3
|
export { Empty, Failed, ICONO_ROTO, Missing, Skeleton, } from "./Notice.js";
|
|
3
|
-
export {
|
|
4
|
+
export { ToastProvider, type ToastSpec, useToast, useToastIfAny, } from "./Toast.js";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/* How a view says that there is nothing, that it failed, or that nobody knows
|
|
2
2
|
how to draw it. */
|
|
3
3
|
export { Callout } from "./Callout.js";
|
|
4
|
+
export { Flag } from "./Flag.js";
|
|
4
5
|
export { Empty, Failed, ICONO_ROTO, Missing, Skeleton, } from "./Notice.js";
|
|
5
|
-
export {
|
|
6
|
+
export { ToastProvider, useToast, useToastIfAny, } from "./Toast.js";
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type PopoverProps } from "./Popover.js";
|
|
2
|
+
import { type ReactElement, type ReactNode } from "react";
|
|
3
|
+
export type PreviewProps = {
|
|
4
|
+
/** What the preview is of — a link to the record, written as an element: a React Aria
|
|
5
|
+
* `Link`, or anything that forwards `ref` and spreads native props. It must be
|
|
6
|
+
* focusable: the keyboard reaches the preview through it. */
|
|
7
|
+
trigger: ReactElement;
|
|
8
|
+
/** The accessible name of the floating card: «Resumen de Distribuidora Andina». */
|
|
9
|
+
label: string;
|
|
10
|
+
/** What floats: a `RelationCard`, a few facts. It may hold actions — «Abrir». */
|
|
11
|
+
children: ReactNode;
|
|
12
|
+
placement?: PopoverProps["placement"];
|
|
13
|
+
/** Milliseconds resting on the trigger before it opens. 600 by default — see above. */
|
|
14
|
+
delay?: number;
|
|
15
|
+
closeDelay?: number;
|
|
16
|
+
/** The trigger stays, the preview does not open. */
|
|
17
|
+
disabled?: boolean;
|
|
18
|
+
};
|
|
19
|
+
export declare function Preview({ trigger, label, children, placement, delay, closeDelay, disabled, }: PreviewProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Popover } from "./Popover.js";
|
|
4
|
+
import { isValidElement } from "react";
|
|
5
|
+
import { setInteractionModality } from "react-aria";
|
|
6
|
+
import { Focusable, Link, PreviewTrigger } from "react-aria-components";
|
|
7
|
+
/**
|
|
8
|
+
* A glance at a record without leaving the screen: the customer of an invoice, the product
|
|
9
|
+
* of a line — who or what it is, shown when the pointer rests on its name, the keyboard
|
|
10
|
+
* stops on it or a finger presses it long.
|
|
11
|
+
*
|
|
12
|
+
* Context: it sits between the two other things that float from a mark.
|
|
13
|
+
*
|
|
14
|
+
* - `Tooltip` is a LABEL: a few words about a control, never interactive — React Aria makes
|
|
15
|
+
* it a `role="tooltip"` the keyboard cannot enter. A customer's debt, phone and «Abrir»
|
|
16
|
+
* are not a label.
|
|
17
|
+
* - `PopoverTrigger` is ASKED FOR: a press on a button opens a dialog that takes the focus
|
|
18
|
+
* until it is closed. Right for a small form; too much ceremony to see whose NIT it is.
|
|
19
|
+
*
|
|
20
|
+
* `Preview` is React Aria's `PreviewTrigger`: a NON-modal popover (`role="dialog"`, named by
|
|
21
|
+
* `label`) that opens on hover, on keyboard focus and on long press, and that MAY hold
|
|
22
|
+
* interactive content. It does not take the focus when it opens — the person who tabs past
|
|
23
|
+
* a column of customers keeps walking the table — but Tab from the trigger goes into it,
|
|
24
|
+
* Escape closes it and returns to the trigger, and the pointer can travel diagonally from the
|
|
25
|
+
* name to the card without it closing (React Aria's safe area). A long press moves the focus
|
|
26
|
+
* into it, so a touch screen reader lands on the card. All of that is React Aria's; this
|
|
27
|
+
* only floats it on the system's `Popover` — the surface, hairline, radius and `float`
|
|
28
|
+
* shadow everything that opens over the page has.
|
|
29
|
+
*
|
|
30
|
+
* ── The delays: 600 ms to open, 200 ms to close ──────────────────────
|
|
31
|
+
*
|
|
32
|
+
* They are React Aria's defaults, written here so a change in the library does not change
|
|
33
|
+
* the system silently. 600 ms is the line between crossing and resting: in a table the
|
|
34
|
+
* pointer crosses customer names all day on its way to something else, and a card of 18rem
|
|
35
|
+
* that covered four rows on every pass would be noise. Below ~400 ms it opens on the way;
|
|
36
|
+
* above a second it feels broken to the person who did stop to look. Keyboard focus waits the
|
|
37
|
+
* same, so tabbing quickly does not open a card per row. Once one is open the next opens at
|
|
38
|
+
* once (React Aria's warm-up): comparing the customers of six invoices is a run down the
|
|
39
|
+
* column, not six waits. It is shorter than a tooltip's on purpose — a preview is asked for
|
|
40
|
+
* by resting on a NAME you want to know about; a tooltip names an icon you mostly know.
|
|
41
|
+
* 200 ms to close is only for the jittery exit; the trip to the card is covered by the
|
|
42
|
+
* safe area, not by the delay.
|
|
43
|
+
*
|
|
44
|
+
* ── The trigger ──────────────────────────────────────────────────────
|
|
45
|
+
*
|
|
46
|
+
* React Aria hands the trigger its hover, focus, long-press and `aria-*` props through
|
|
47
|
+
* context. A React Aria `Link` — the name of a `RelationValue` — reads that context itself,
|
|
48
|
+
* so it is passed as is. Anything else — a system `Button`, a `ButtonLink`, a plain `<a>` —
|
|
49
|
+
* goes through `Focusable`, the adapter that clones those props and a `ref` onto an element
|
|
50
|
+
* that forwards `ref` and spreads native props (the same one `TooltipTrigger` uses). Wrapping
|
|
51
|
+
* the `Link` too would hand it the props twice.
|
|
52
|
+
*/
|
|
53
|
+
const PREVIEW_DELAY = 600;
|
|
54
|
+
const PREVIEW_CLOSE_DELAY = 200;
|
|
55
|
+
export function Preview({ trigger, label, children, placement = "bottom start", delay = PREVIEW_DELAY, closeDelay = PREVIEW_CLOSE_DELAY, disabled = false, }) {
|
|
56
|
+
const readsContext = isValidElement(trigger) && trigger.type === Link;
|
|
57
|
+
return (
|
|
58
|
+
/* React Aria opens a preview on hover only once it KNOWS the pointer is in use — and it
|
|
59
|
+
learns that from a press, not from a move. On a page just loaded, before any click, the
|
|
60
|
+
pointer rested on a name and nothing opened. Entering the trigger with a mouse says it,
|
|
61
|
+
in the capture phase so it is said before React Aria's own hover handler asks. */
|
|
62
|
+
_jsx("span", { className: "contents", onPointerOverCapture: (event) => {
|
|
63
|
+
if (event.pointerType === "mouse")
|
|
64
|
+
setInteractionModality("pointer");
|
|
65
|
+
}, children: _jsxs(PreviewTrigger, { delay: delay, closeDelay: closeDelay, isDisabled: disabled, children: [readsContext ? (trigger) : (
|
|
66
|
+
/* React Aria types the child as an intrinsic element; a component that forwards
|
|
67
|
+
`ref` and spreads native props is the same thing to it at runtime. */
|
|
68
|
+
_jsx(Focusable, { children: trigger })), _jsx(Popover, { placement: placement, "aria-label": label, children: _jsx("div", { className: "max-h-[inherit] max-w-sm overflow-auto p-3", children: children }) })] }) }));
|
|
69
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { Popover, type PopoverProps } from "./Popover.js";
|
|
2
2
|
export { PopoverTrigger, type PopoverTriggerProps, } from "./PopoverTrigger.js";
|
|
3
|
+
export { Preview, type PreviewProps } from "./Preview.js";
|
|
3
4
|
export { Tooltip, type TooltipProps, TooltipTrigger, } from "./Tooltip.js";
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/* LO QUE FLOTA anclado a algo: el calendario de un selector de fecha, la lista de un
|
|
2
|
-
combobox, un formulario chico abierto desde un botón, el nombre de un ícono
|
|
2
|
+
combobox, un formulario chico abierto desde un botón, el nombre de un ícono, el vistazo
|
|
3
|
+
a un registro al pasar por su nombre. */
|
|
3
4
|
export { Popover } from "./Popover.js";
|
|
4
5
|
export { PopoverTrigger, } from "./PopoverTrigger.js";
|
|
6
|
+
export { Preview } from "./Preview.js";
|
|
5
7
|
export { Tooltip, TooltipTrigger, } from "./Tooltip.js";
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A text with the part that matched the search marked — internal to the lists that filter
|
|
3
|
+
* as you type (`Picker`, `TagsField`). A `<mark>`, so it is also said as marked text, and
|
|
4
|
+
* bold besides the tint: in forced colors the tint is gone and the weight is what remains.
|
|
5
|
+
*/
|
|
6
|
+
export declare function MatchedText({ text, query, locale, }: {
|
|
7
|
+
text: string;
|
|
8
|
+
query: string;
|
|
9
|
+
locale?: string;
|
|
10
|
+
}): string | (string | import("react").JSX.Element)[];
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { matchSpans } from "../../foundations/match.js";
|
|
3
|
+
/**
|
|
4
|
+
* A text with the part that matched the search marked — internal to the lists that filter
|
|
5
|
+
* as you type (`Picker`, `TagsField`). A `<mark>`, so it is also said as marked text, and
|
|
6
|
+
* bold besides the tint: in forced colors the tint is gone and the weight is what remains.
|
|
7
|
+
*/
|
|
8
|
+
export function MatchedText({ text, query, locale, }) {
|
|
9
|
+
if (query.trim() === "")
|
|
10
|
+
return text;
|
|
11
|
+
return matchSpans(text, query, locale).map((span, index) => span.hit ? (_jsx("mark", { className: "rounded-mark bg-accent/25 font-semibold text-current", children: span.text }, index)) : (span.text));
|
|
12
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { OpenTarget } from "../../foundations/types.js";
|
|
1
2
|
import { type FormMode } from "../field/mode.js";
|
|
2
3
|
import type { LucideIcon } from "lucide-react";
|
|
3
4
|
import { type ReactNode } from "react";
|
|
@@ -18,19 +19,53 @@ export interface PickerItem {
|
|
|
18
19
|
* on the box and finding the product, and having to remember what it was
|
|
19
20
|
* called. Drawing every code of every option is not an alternative. */
|
|
20
21
|
haystack?: string;
|
|
22
|
+
/** The header this item is listed under. Consecutive items with the same section share
|
|
23
|
+
* one header; an item without it is listed loose, outside any section. */
|
|
24
|
+
section?: string;
|
|
25
|
+
/** A person or a company: its face before the name — the photo, or its initials when
|
|
26
|
+
* `true`. Who is being chosen is recognised before it is read, in the list and in the field. */
|
|
27
|
+
avatar?: true | string;
|
|
28
|
+
/** What is read at a glance on the right, in tabular figures: the balance owed, the stock,
|
|
29
|
+
* a state badge, a priority — a widget, not text. Where `meta` describes, this COMPARES:
|
|
30
|
+
* lined up in one column, eight customers' debts are read top to bottom. */
|
|
31
|
+
aside?: ReactNode;
|
|
21
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* What the list shows and how many are left out of it. Capped at 8 with the footer count,
|
|
35
|
+
* unless the list loads incrementally — then everything that arrived is listed and the
|
|
36
|
+
* scroll asks for more.
|
|
37
|
+
*/
|
|
38
|
+
export declare function shownRows(filtered: readonly PickerItem[], { loading, incremental }: {
|
|
39
|
+
loading: boolean;
|
|
40
|
+
incremental: boolean;
|
|
41
|
+
}): {
|
|
42
|
+
visible: readonly PickerItem[];
|
|
43
|
+
remaining: number;
|
|
44
|
+
};
|
|
22
45
|
export type PickerProps = {
|
|
23
46
|
id?: string;
|
|
24
47
|
items: readonly PickerItem[];
|
|
25
48
|
value?: string;
|
|
26
49
|
onChange?: (id: string) => void;
|
|
27
50
|
placeholder?: string;
|
|
28
|
-
/**
|
|
29
|
-
*
|
|
30
|
-
|
|
51
|
+
/** «Buscar más…»: the last option of the list, always there when this is — the record
|
|
52
|
+
* may not be among the eight, or two of them may need their columns to tell apart. It
|
|
53
|
+
* gets what was typed, so the list that chooses (`List onChoose`, in a modal of the
|
|
54
|
+
* workspace) opens on the same search. */
|
|
55
|
+
onBrowseAll?: (query: string) => void;
|
|
56
|
+
/** «Crear «…»»: a record made from the typed text alone (Odoo's `name_create`); it returns
|
|
57
|
+
* the new id — or a promise of it — and the field chooses it. Offered while something is
|
|
58
|
+
* typed that no option is called exactly. The consumer appends the new item to `items`. */
|
|
59
|
+
onCreate?: (name: string) => string | Promise<string>;
|
|
60
|
+
/** «Crear y editar…»: the new record needs more than a name — open its form (in a workspace,
|
|
61
|
+
* a modal) with the typed text as the name. Choosing it there is the consumer's. */
|
|
62
|
+
onCreateAndEdit?: (name: string) => void;
|
|
31
63
|
/** Open the chosen record. Drawn as a trailing affordance, the way a many2one
|
|
32
64
|
* offers "open" next to "pick". Absent when there is nothing chosen. */
|
|
33
|
-
onOpen?: (id: string) => void;
|
|
65
|
+
onOpen?: (id: string, to: OpenTarget) => void;
|
|
66
|
+
/** Where the chosen record can open, the first being the button's (a modal, by default: the
|
|
67
|
+
* form stays behind); the rest go in «Abrir en…». `onOpen` is told which was picked. */
|
|
68
|
+
openTargets?: readonly OpenTarget[];
|
|
34
69
|
emptyText?: string;
|
|
35
70
|
/** Placeholder of the field while it is being typed into. It is NOT a second
|
|
36
71
|
* box — the field itself is the search. */
|
|
@@ -39,10 +74,38 @@ export type PickerProps = {
|
|
|
39
74
|
* while loading reads as "there is nothing", which is a different answer. */
|
|
40
75
|
loading?: boolean;
|
|
41
76
|
loadingText?: string;
|
|
77
|
+
/** The list grows from the backend: called when its end scrolls into view. The consumer
|
|
78
|
+
* appends the next page to `items`; with nothing more to fetch it does nothing. Turns off
|
|
79
|
+
* the cap of 8 and the footer count. */
|
|
80
|
+
onLoadMore?: () => void;
|
|
81
|
+
/** A page asked for by `onLoadMore` is on its way: a quiet row at the end says so. Unlike
|
|
82
|
+
* `loading`, the rows already there stay. */
|
|
83
|
+
loadingMore?: boolean;
|
|
42
84
|
describedBy?: string;
|
|
43
85
|
invalid?: boolean;
|
|
44
86
|
disabled?: boolean;
|
|
87
|
+
/** The name of the control when it is NOT inside a `Field` — a cell of an editable table.
|
|
88
|
+
* Inside a field, the field's label names it. */
|
|
89
|
+
"aria-label"?: string;
|
|
45
90
|
/** Forces the mode. By default it inherits the form's: in read mode it draws the name. */
|
|
46
91
|
mode?: FormMode;
|
|
47
92
|
};
|
|
48
93
|
export declare function Picker({ mode, ...props }: PickerProps): import("react").JSX.Element;
|
|
94
|
+
/**
|
|
95
|
+
* The list of a `Picker`: its rows, the section headers, the «Buscar más…» row and the loading
|
|
96
|
+
* row at the end. Internal — not exported from the family — and apart from the combobox so it
|
|
97
|
+
* can be rendered on the server without a popover, which is how the tests see the rows.
|
|
98
|
+
*/
|
|
99
|
+
export declare function PickerOptions({ items, marks, hints, remaining, query, emptyText, onLoadMore, loadingMore, "aria-label": ariaLabel, }: {
|
|
100
|
+
items: readonly PickerItem[];
|
|
101
|
+
marks: boolean;
|
|
102
|
+
hints: boolean;
|
|
103
|
+
remaining: number;
|
|
104
|
+
/** What was typed: it is marked in every row, so each row says why it is there. */
|
|
105
|
+
query?: string;
|
|
106
|
+
emptyText: string;
|
|
107
|
+
onLoadMore?: () => void;
|
|
108
|
+
loadingMore?: boolean;
|
|
109
|
+
/** Only when rendered outside the combobox, which otherwise names the list. */
|
|
110
|
+
"aria-label"?: string;
|
|
111
|
+
}): import("react").JSX.Element;
|