@botiverse/raft-ui 0.30.0 → 0.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/dist/wip.d.mts +40 -1
- package/dist/wip.mjs +133 -50
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,29 @@
|
|
|
1
|
+
## [0.32.0](https://github.com/botiverse/raft-design/compare/v0.31.0...v0.32.0) (2026-10-23)
|
|
2
|
+
|
|
3
|
+
### Added
|
|
4
|
+
|
|
5
|
+
- **ChoiceList** (wip): `matchedValues`, for a product with its own search (a ranked people search shared with mentions). With it ChoiceList shows the values the caller's search found, in the caller's order, instead of matching `searchText` itself; the chosen rows still come first and "No match" still shows. A value given twice shows once. Pass matches for the current text, and keep the previous ones while a slower search works. ([#780](https://github.com/botiverse/raft-design/pull/780))
|
|
6
|
+
- Docs: https://raft-design.botiverse.build/components/choice-list/
|
|
7
|
+
|
|
8
|
+
## [0.31.0](https://github.com/botiverse/raft-design/compare/v0.30.0...v0.31.0) (2026-10-23)
|
|
9
|
+
|
|
10
|
+
### Design System
|
|
11
|
+
|
|
12
|
+
- **A row swipe on a phone**: a swipe starts once the finger has gone 10px on the web (twice as far across as up or down), and swipes that start within 24px of the screen edge stay with the browser. A release applies the action past 40% of the row's width, or past 20% with a quick flick. The uncovered layer is soft until a release would apply, then solid `success` with ink, and ticks once on Android as it turns solid. It says "Done"; the menu keeps "Mark as Done". The row leaves at once, with an 8-second Undo. On a phone, Activity's Mark as Done stays in the row as a button only screen readers see. ([#775](https://github.com/botiverse/raft-design/pull/775), [#776](https://github.com/botiverse/raft-design/pull/776))
|
|
13
|
+
- Why: Activity on a phone moved Mark as Done to the swipe (stdrc); the swipe must be predictable, reversible, and reachable without swiping.
|
|
14
|
+
- Affects: a rule for products.
|
|
15
|
+
- Docs: https://raft-design.botiverse.build/patterns/responsive/#touch-screens
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- **ChoiceList** (wip): ([#774](https://github.com/botiverse/raft-design/pull/774))
|
|
20
|
+
- `groups` with headings. Each group is named by its heading, and the arrow keys cross groups.
|
|
21
|
+
- `searchValue` / `onSearchValueChange`, so the app can read and set the search text. It hears `""` when the box hides.
|
|
22
|
+
- `footer`, which stays in view while the rows scroll.
|
|
23
|
+
- `fill`, which fills its container's height.
|
|
24
|
+
- The frame now wraps a `choice-list-scroller`.
|
|
25
|
+
- Docs: https://raft-design.botiverse.build/components/choice-list/
|
|
26
|
+
|
|
1
27
|
## [0.30.0](https://github.com/botiverse/raft-design/compare/v0.29.0...v0.30.0) (2026-10-23)
|
|
2
28
|
|
|
3
29
|
### Design System
|
package/dist/wip.d.mts
CHANGED
|
@@ -727,6 +727,13 @@ type ChoiceListItem = {
|
|
|
727
727
|
*/
|
|
728
728
|
action?: ReactNode;
|
|
729
729
|
disabled?: boolean;
|
|
730
|
+
/** The `value` of the group in `groups` this item is listed under. */
|
|
731
|
+
group?: string;
|
|
732
|
+
};
|
|
733
|
+
type ChoiceListGroup = {
|
|
734
|
+
value: string;
|
|
735
|
+
/** The small heading over the group's rows, such as "Agents". */
|
|
736
|
+
label: ReactNode;
|
|
730
737
|
};
|
|
731
738
|
type ChoiceListCommonProps = {
|
|
732
739
|
items: readonly ChoiceListItem[];
|
|
@@ -748,12 +755,44 @@ type ChoiceListCommonProps = {
|
|
|
748
755
|
searchPlaceholder?: string;
|
|
749
756
|
/** The search box's text when the list first draws, such as a search carried over. */
|
|
750
757
|
defaultSearchValue?: string;
|
|
758
|
+
/**
|
|
759
|
+
* The search box's text, for a caller that uses it: a "Create “…”" row
|
|
760
|
+
* named after it, or a no-match line that quotes it. With it, the caller
|
|
761
|
+
* owns the text, and `onSearchValueChange` reports each change.
|
|
762
|
+
*/
|
|
763
|
+
searchValue?: string;
|
|
764
|
+
onSearchValueChange?: (value: string) => void;
|
|
765
|
+
/**
|
|
766
|
+
* The values of the items that match the search text, in the order to show
|
|
767
|
+
* them, for a caller with its own search (a ranked people search shared
|
|
768
|
+
* with mentions). With it ChoiceList doesn't match `searchText` itself; it
|
|
769
|
+
* still keeps the chosen rows first and says when nothing matches.
|
|
770
|
+
*/
|
|
771
|
+
matchedValues?: readonly string[];
|
|
751
772
|
/** The clear button's accessible name. */
|
|
752
773
|
clearSearchLabel: string;
|
|
753
774
|
/** The line under the chosen rows when nothing else matches. */
|
|
754
775
|
noMatchLabel?: ReactNode;
|
|
755
776
|
/** The line drawn when there are no items at all. */
|
|
756
777
|
empty?: ReactNode;
|
|
778
|
+
/**
|
|
779
|
+
* Headings that split the rows by kind, in this order, such as Agents then
|
|
780
|
+
* People. Each item names its group; a group with no rows to show, or a
|
|
781
|
+
* search that leaves it empty, draws no heading.
|
|
782
|
+
*/
|
|
783
|
+
groups?: readonly ChoiceListGroup[];
|
|
784
|
+
/**
|
|
785
|
+
* A row of the caller's under the list, inside its frame, that stays in
|
|
786
|
+
* view while the rows scroll: the way out when the item isn't there, such
|
|
787
|
+
* as "Create an agent".
|
|
788
|
+
*/
|
|
789
|
+
footer?: ReactNode;
|
|
790
|
+
/**
|
|
791
|
+
* The list takes the height it is given and its rows scroll inside it, for
|
|
792
|
+
* a sheet or panel whose main content is the list. Otherwise a list with a
|
|
793
|
+
* search scrolls past 18rem.
|
|
794
|
+
*/
|
|
795
|
+
fill?: boolean;
|
|
757
796
|
className?: string;
|
|
758
797
|
};
|
|
759
798
|
type ChoiceListSingleProps = ChoiceListCommonProps & {
|
|
@@ -769,4 +808,4 @@ type ChoiceListMultipleProps = ChoiceListCommonProps & {
|
|
|
769
808
|
type ChoiceListProps = ChoiceListSingleProps | ChoiceListMultipleProps;
|
|
770
809
|
export declare function ChoiceList(props: ChoiceListProps): import("react").JSX.Element;
|
|
771
810
|
//#endregion
|
|
772
|
-
export { Dialog as AnnouncementDialog, DialogClose as AnnouncementDialogClose, DialogTrigger as AnnouncementDialogTrigger, type ChoiceListItem, type ChoiceListMultipleProps, type ChoiceListProps, type ChoiceListSingleProps, type ComboboxSelectGroup, type ComboboxSelectMessages, type ComboboxSelectOption, type ComboboxSelectProps, type ComboboxSelectSelection, type ComboboxSelectValue, type CommentCardMetaProps, type CommentCardProps, type CommentCardQuoteProps, type CommentCardTriggerProps, type CommentEntryAuthorProps, type CommentEntryBodyProps, type CommentEntryHeaderProps, type CommentEntryProps, type CommentEntryTimeProps, type CommentMarginItemProps, type CommentMarginLayout, type CommentMarginLayoutItem, type CommentMarginLayoutOptions, type CommentMarginProps, type CommentMarkerProps, DialogCommit, type DialogCommitProps, DialogFooterNote, type DialogFooterNoteProps, DialogSheetBack, type DialogSheetBackProps, DialogSheetContent, type DialogSheetContentProps, DropdownMenuLinkItem, type DropdownMenuLinkItemProps, type EllipsisProps, type EllipsisState, type EllipsisToggleProps, type HoldThenMoveOptions, type InboxItemLeadingBadgeProps, type InboxItemSkeletonListProps, type InboxItemSkeletonProps, type ListRowSkeletonProps, MessageItemDelegatedAvatar, type MessageItemDelegatedAvatarProps, MessageItemDelegatedBy, MessageItemDelegatedByButton, type MessageItemDelegatedByButtonProps, MessageItemDelegatedByName, type MessageItemDelegatedByNameProps, type MessageItemDelegatedByProps, MessageListJumpControls, type MessageListJumpControlsProps, MessageListJumpPill, MessageListJumpPillDismiss, type MessageListJumpPillDismissProps, MessageListJumpPillGroup, type MessageListJumpPillGroupProps, type MessageListJumpPillProps, MessageQuotedPreviewAuthorDelegatedBy, type MessageQuotedPreviewAuthorDelegatedByProps, MessageReferenceIcon, type MessageReferenceIconProps, MessageReferenceReadMark, type MessageReferenceReadMarkProps, type MeterHeaderProps, type MeterIndicatorProps, type MeterLabelProps, type MeterProps, type MeterTrackProps, type MeterValueProps, MobileNavServerItem, type MobileNavServerItemProps, MobileNavServerPopover, MobileNavServerPopoverContent, type MobileNavServerPopoverContentProps, MobileNavServerPopoverDestination, type MobileNavServerPopoverDestinationProps, MobileNavServerPopoverDestinations, type MobileNavServerPopoverDestinationsProps, MobileNavServerPopoverGroup, type MobileNavServerPopoverGroupProps, MobileNavServerPopoverList, type MobileNavServerPopoverListProps, type MobileNavServerPopoverProps, MobileNavServerPopoverRow, MobileNavServerPopoverRowBody, type MobileNavServerPopoverRowBodyProps, MobileNavServerPopoverRowDescription, type MobileNavServerPopoverRowDescriptionProps, MobileNavServerPopoverRowLabel, type MobileNavServerPopoverRowLabelProps, type MobileNavServerPopoverRowProps, type OverlayLayerKind, type OverlayLayerProviderProps, PopoverActions, type PopoverActionsProps, PopoverBody, type PopoverBodyProps, PreviewCardActions, type PreviewCardActionsProps, PreviewCardBody, type PreviewCardBodyProps, PreviewCardEyebrow, type PreviewCardEyebrowProps, PreviewCardFooter, type PreviewCardFooterProps, PreviewCardMeta, type PreviewCardMetaProps, type PullToRefresh, type PullToRefreshIndicatorProps, type PullToRefreshPlatform, type PullToRefreshState, type UseCommentMarginFitsOptions, type UsePullToRefreshOptions };
|
|
811
|
+
export { Dialog as AnnouncementDialog, DialogClose as AnnouncementDialogClose, DialogTrigger as AnnouncementDialogTrigger, type ChoiceListGroup, type ChoiceListItem, type ChoiceListMultipleProps, type ChoiceListProps, type ChoiceListSingleProps, type ComboboxSelectGroup, type ComboboxSelectMessages, type ComboboxSelectOption, type ComboboxSelectProps, type ComboboxSelectSelection, type ComboboxSelectValue, type CommentCardMetaProps, type CommentCardProps, type CommentCardQuoteProps, type CommentCardTriggerProps, type CommentEntryAuthorProps, type CommentEntryBodyProps, type CommentEntryHeaderProps, type CommentEntryProps, type CommentEntryTimeProps, type CommentMarginItemProps, type CommentMarginLayout, type CommentMarginLayoutItem, type CommentMarginLayoutOptions, type CommentMarginProps, type CommentMarkerProps, DialogCommit, type DialogCommitProps, DialogFooterNote, type DialogFooterNoteProps, DialogSheetBack, type DialogSheetBackProps, DialogSheetContent, type DialogSheetContentProps, DropdownMenuLinkItem, type DropdownMenuLinkItemProps, type EllipsisProps, type EllipsisState, type EllipsisToggleProps, type HoldThenMoveOptions, type InboxItemLeadingBadgeProps, type InboxItemSkeletonListProps, type InboxItemSkeletonProps, type ListRowSkeletonProps, MessageItemDelegatedAvatar, type MessageItemDelegatedAvatarProps, MessageItemDelegatedBy, MessageItemDelegatedByButton, type MessageItemDelegatedByButtonProps, MessageItemDelegatedByName, type MessageItemDelegatedByNameProps, type MessageItemDelegatedByProps, MessageListJumpControls, type MessageListJumpControlsProps, MessageListJumpPill, MessageListJumpPillDismiss, type MessageListJumpPillDismissProps, MessageListJumpPillGroup, type MessageListJumpPillGroupProps, type MessageListJumpPillProps, MessageQuotedPreviewAuthorDelegatedBy, type MessageQuotedPreviewAuthorDelegatedByProps, MessageReferenceIcon, type MessageReferenceIconProps, MessageReferenceReadMark, type MessageReferenceReadMarkProps, type MeterHeaderProps, type MeterIndicatorProps, type MeterLabelProps, type MeterProps, type MeterTrackProps, type MeterValueProps, MobileNavServerItem, type MobileNavServerItemProps, MobileNavServerPopover, MobileNavServerPopoverContent, type MobileNavServerPopoverContentProps, MobileNavServerPopoverDestination, type MobileNavServerPopoverDestinationProps, MobileNavServerPopoverDestinations, type MobileNavServerPopoverDestinationsProps, MobileNavServerPopoverGroup, type MobileNavServerPopoverGroupProps, MobileNavServerPopoverList, type MobileNavServerPopoverListProps, type MobileNavServerPopoverProps, MobileNavServerPopoverRow, MobileNavServerPopoverRowBody, type MobileNavServerPopoverRowBodyProps, MobileNavServerPopoverRowDescription, type MobileNavServerPopoverRowDescriptionProps, MobileNavServerPopoverRowLabel, type MobileNavServerPopoverRowLabelProps, type MobileNavServerPopoverRowProps, type OverlayLayerKind, type OverlayLayerProviderProps, PopoverActions, type PopoverActionsProps, PopoverBody, type PopoverBodyProps, PreviewCardActions, type PreviewCardActionsProps, PreviewCardBody, type PreviewCardBodyProps, PreviewCardEyebrow, type PreviewCardEyebrowProps, PreviewCardFooter, type PreviewCardFooterProps, PreviewCardMeta, type PreviewCardMetaProps, type PullToRefresh, type PullToRefreshIndicatorProps, type PullToRefreshPlatform, type PullToRefreshState, type UseCommentMarginFitsOptions, type UsePullToRefreshOptions };
|
package/dist/wip.mjs
CHANGED
|
@@ -2333,9 +2333,12 @@ const choiceList = tv({
|
|
|
2333
2333
|
slots: {
|
|
2334
2334
|
root: ["grid min-w-0 gap-2"],
|
|
2335
2335
|
searchInput: ["[&::-webkit-search-cancel-button]:appearance-none"],
|
|
2336
|
-
frame: ["min-w-0 rounded-container border border-line-hairline bg-layer-card
|
|
2336
|
+
frame: ["flex min-w-0 flex-col overflow-hidden", "rounded-container border border-line-hairline bg-layer-card"],
|
|
2337
|
+
scroller: ["min-h-0 min-w-0 p-1"],
|
|
2337
2338
|
rows: ["grid grid-cols-[minmax(0,1fr)_auto] gap-x-0 gap-y-0.5"],
|
|
2338
2339
|
group: ["col-span-2 col-start-1 grid grid-cols-subgrid grid-rows-subgrid gap-x-0 gap-y-0.5"],
|
|
2340
|
+
section: ["col-span-2 col-start-1 grid grid-cols-subgrid grid-rows-subgrid"],
|
|
2341
|
+
heading: ["col-span-2 px-2.5 pt-2 pb-1", "font-sans text-caption font-bold text-foreground-hint"],
|
|
2339
2342
|
item: [
|
|
2340
2343
|
"col-span-2 flex min-w-0 items-start gap-2.5 rounded-chip px-2.5",
|
|
2341
2344
|
"min-h-option py-option-inset",
|
|
@@ -2353,10 +2356,16 @@ const choiceList = tv({
|
|
|
2353
2356
|
"mt-option-inset pointer-coarse:mt-[calc((--spacing(11)-1lh)/2)]",
|
|
2354
2357
|
"font-sans text-subhead"
|
|
2355
2358
|
],
|
|
2356
|
-
note: ["px-2.5 py-2 font-sans text-callout text-foreground-hint"]
|
|
2359
|
+
note: ["px-2.5 py-2 font-sans text-callout text-foreground-hint"],
|
|
2360
|
+
footer: ["shrink-0 border-t border-line-seam p-1"]
|
|
2357
2361
|
},
|
|
2358
2362
|
variants: {
|
|
2359
|
-
scroll: { true: {
|
|
2363
|
+
scroll: { true: { scroller: ["max-h-72 overflow-y-auto overscroll-contain"] } },
|
|
2364
|
+
fill: { true: {
|
|
2365
|
+
root: ["flex min-h-0 flex-1 flex-col"],
|
|
2366
|
+
frame: ["min-h-0 flex-1"],
|
|
2367
|
+
scroller: ["flex-1 overflow-y-auto overscroll-contain"]
|
|
2368
|
+
} },
|
|
2360
2369
|
hasAction: { true: { item: ["pr-11"] } }
|
|
2361
2370
|
}
|
|
2362
2371
|
});
|
|
@@ -2391,25 +2400,59 @@ function searchTextOf(item) {
|
|
|
2391
2400
|
if (item.searchText !== void 0) return item.searchText;
|
|
2392
2401
|
return typeof item.label === "string" ? item.label : "";
|
|
2393
2402
|
}
|
|
2394
|
-
function visibleItems(items, needle, pinned, chosen) {
|
|
2403
|
+
function visibleItems(items, needle, pinned, chosen, matchedValues) {
|
|
2395
2404
|
if (!needle) return {
|
|
2396
2405
|
rows: items,
|
|
2397
2406
|
noMatch: false
|
|
2398
2407
|
};
|
|
2399
|
-
const
|
|
2400
|
-
const
|
|
2408
|
+
const matched = matchedValues ? new Set(matchedValues) : null;
|
|
2409
|
+
const matches = (item) => matched ? matched.has(item.value) : searchTextOf(item).toLowerCase().includes(needle);
|
|
2410
|
+
const pinnedSet = new Set(pinned);
|
|
2411
|
+
const isPinned = (item) => pinnedSet.has(item.value);
|
|
2401
2412
|
const top = items.filter((item) => isPinned(item) || chosen.includes(item.value) && !matches(item));
|
|
2402
|
-
const
|
|
2413
|
+
const byValue = matchedValues ? new Map(items.map((item) => [item.value, item])) : null;
|
|
2414
|
+
const rest = (byValue && matched ? [...matched].flatMap((value) => byValue.get(value) ?? []) : items).filter((item) => !top.includes(item) && matches(item));
|
|
2403
2415
|
return {
|
|
2404
2416
|
rows: [...top, ...rest],
|
|
2405
2417
|
noMatch: !items.some(matches)
|
|
2406
2418
|
};
|
|
2407
2419
|
}
|
|
2420
|
+
function layoutSections(rows, groups) {
|
|
2421
|
+
const known = new Set(groups?.map((group) => group.value));
|
|
2422
|
+
const sections = groups ? groups.map((group) => ({
|
|
2423
|
+
group,
|
|
2424
|
+
rows: rows.filter((item) => item.group === group.value)
|
|
2425
|
+
})) : [];
|
|
2426
|
+
sections.push({
|
|
2427
|
+
group: null,
|
|
2428
|
+
rows: rows.filter((item) => !groups || item.group === void 0 || !known.has(item.group))
|
|
2429
|
+
});
|
|
2430
|
+
const drawn = sections.filter((section) => section.rows.length > 0);
|
|
2431
|
+
const gridRowOf = /* @__PURE__ */ new Map();
|
|
2432
|
+
let gridRows = 0;
|
|
2433
|
+
for (const section of drawn) {
|
|
2434
|
+
if (section.group) gridRows += 1;
|
|
2435
|
+
for (const item of section.rows) {
|
|
2436
|
+
gridRows += 1;
|
|
2437
|
+
gridRowOf.set(item.value, gridRows);
|
|
2438
|
+
}
|
|
2439
|
+
}
|
|
2440
|
+
return {
|
|
2441
|
+
sections: drawn,
|
|
2442
|
+
gridRowOf,
|
|
2443
|
+
gridRows
|
|
2444
|
+
};
|
|
2445
|
+
}
|
|
2408
2446
|
function ChoiceList(props) {
|
|
2409
|
-
const { items, search = "auto", "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, disabled = false, searchLabel, searchPlaceholder, defaultSearchValue = "", clearSearchLabel, noMatchLabel, empty, className } = props;
|
|
2447
|
+
const { items, search = "auto", "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, disabled = false, searchLabel, searchPlaceholder, defaultSearchValue = "", searchValue, onSearchValueChange, matchedValues, clearSearchLabel, noMatchLabel, empty, groups, footer, fill = false, className } = props;
|
|
2410
2448
|
const value = props.value;
|
|
2411
2449
|
const chosen = useMemo(() => value === null ? [] : typeof value === "string" ? [value] : value, [value]);
|
|
2412
|
-
const [
|
|
2450
|
+
const [ownQuery, setOwnQuery] = useState(defaultSearchValue);
|
|
2451
|
+
const query = searchValue ?? ownQuery;
|
|
2452
|
+
const setQuery = useCallback((next) => {
|
|
2453
|
+
if (searchValue === void 0) setOwnQuery(next);
|
|
2454
|
+
onSearchValueChange?.(next);
|
|
2455
|
+
}, [searchValue, onSearchValueChange]);
|
|
2413
2456
|
const [pinned, setPinned] = useState(chosen);
|
|
2414
2457
|
const inputRef = useRef(null);
|
|
2415
2458
|
const baseId = useId();
|
|
@@ -2417,11 +2460,26 @@ function ChoiceList(props) {
|
|
|
2417
2460
|
const [wasSearchable, setWasSearchable] = useState(searchable);
|
|
2418
2461
|
if (wasSearchable !== searchable) {
|
|
2419
2462
|
setWasSearchable(searchable);
|
|
2420
|
-
if (!searchable)
|
|
2463
|
+
if (!searchable) setOwnQuery("");
|
|
2464
|
+
}
|
|
2465
|
+
useEffect(() => {
|
|
2466
|
+
if (!searchable && searchValue) onSearchValueChange?.("");
|
|
2467
|
+
}, [
|
|
2468
|
+
searchable,
|
|
2469
|
+
searchValue,
|
|
2470
|
+
onSearchValueChange
|
|
2471
|
+
]);
|
|
2472
|
+
const [pinnedFor, setPinnedFor] = useState(query);
|
|
2473
|
+
if (pinnedFor !== query) {
|
|
2474
|
+
setPinnedFor(query);
|
|
2475
|
+
setPinned(chosen);
|
|
2421
2476
|
}
|
|
2422
|
-
const { rows, noMatch } = visibleItems(items, searchable ? query.trim().toLowerCase() : "", pinned, chosen);
|
|
2477
|
+
const { rows, noMatch } = visibleItems(items, searchable ? query.trim().toLowerCase() : "", pinned, chosen, matchedValues);
|
|
2423
2478
|
const hasAction = rows.some((item) => item.action !== void 0 && item.action !== null);
|
|
2424
|
-
const slots = choiceList({
|
|
2479
|
+
const slots = choiceList({
|
|
2480
|
+
scroll: searchable && !fill,
|
|
2481
|
+
fill
|
|
2482
|
+
});
|
|
2425
2483
|
useEffect(() => {
|
|
2426
2484
|
if (process.env.NODE_ENV === "production") return;
|
|
2427
2485
|
if (!ariaLabel && !ariaLabelledBy) console.warn("raft-ui: a ChoiceList has neither aria-label nor aria-labelledby.");
|
|
@@ -2444,21 +2502,20 @@ function ChoiceList(props) {
|
|
|
2444
2502
|
}, [focusSearch]);
|
|
2445
2503
|
const changeQuery = useCallback((event) => {
|
|
2446
2504
|
setQuery(event.currentTarget.value);
|
|
2447
|
-
|
|
2448
|
-
}, [chosen]);
|
|
2505
|
+
}, [setQuery]);
|
|
2449
2506
|
const clearQuery = useCallback(() => {
|
|
2450
2507
|
setQuery("");
|
|
2451
|
-
setPinned(chosen);
|
|
2452
2508
|
inputRef.current?.focus();
|
|
2453
|
-
}, [
|
|
2509
|
+
}, [setQuery]);
|
|
2510
|
+
const { sections, gridRowOf, gridRows } = layoutSections(rows, groups);
|
|
2454
2511
|
const groupProps = {
|
|
2455
2512
|
"aria-label": ariaLabel,
|
|
2456
2513
|
"aria-labelledby": ariaLabelledBy,
|
|
2457
2514
|
disabled,
|
|
2458
2515
|
className: slots.group(),
|
|
2459
|
-
style: { gridRow: `1 / span ${
|
|
2516
|
+
style: { gridRow: `1 / span ${gridRows}` }
|
|
2460
2517
|
};
|
|
2461
|
-
const
|
|
2518
|
+
const rowElement = (item) => {
|
|
2462
2519
|
const id = `${baseId}-${items.indexOf(item)}`;
|
|
2463
2520
|
const lines = descriptionLines(item.description).slice(0, MAX_DESCRIPTION_LINES);
|
|
2464
2521
|
const rowDisabled = disabled || item.disabled === true;
|
|
@@ -2499,6 +2556,24 @@ function ChoiceList(props) {
|
|
|
2499
2556
|
})
|
|
2500
2557
|
]
|
|
2501
2558
|
}, item.value);
|
|
2559
|
+
};
|
|
2560
|
+
const rowElements = sections.map((section, index) => {
|
|
2561
|
+
if (!section.group) return section.rows.map(rowElement);
|
|
2562
|
+
const headingId = `${baseId}-group-${index}`;
|
|
2563
|
+
const start = (gridRowOf.get(section.rows[0].value) ?? 1) - 1;
|
|
2564
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
2565
|
+
role: "group",
|
|
2566
|
+
"aria-labelledby": headingId,
|
|
2567
|
+
"data-slot": "choice-list-section",
|
|
2568
|
+
className: slots.section(),
|
|
2569
|
+
style: { gridRow: `${start} / span ${section.rows.length + 1}` },
|
|
2570
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
2571
|
+
id: headingId,
|
|
2572
|
+
"data-slot": "choice-list-heading",
|
|
2573
|
+
className: slots.heading(),
|
|
2574
|
+
children: section.group.label
|
|
2575
|
+
}), section.rows.map(rowElement)]
|
|
2576
|
+
}, section.group.value);
|
|
2502
2577
|
});
|
|
2503
2578
|
return /* @__PURE__ */ jsxs("div", {
|
|
2504
2579
|
"data-slot": "choice-list",
|
|
@@ -2529,40 +2604,48 @@ function ChoiceList(props) {
|
|
|
2529
2604
|
})
|
|
2530
2605
|
}) : null
|
|
2531
2606
|
]
|
|
2532
|
-
}) : null, /* @__PURE__ */
|
|
2607
|
+
}) : null, /* @__PURE__ */ jsxs("div", {
|
|
2533
2608
|
"data-slot": "choice-list-frame",
|
|
2534
2609
|
className: slots.frame(),
|
|
2535
|
-
children:
|
|
2536
|
-
"data-slot": "choice-list-
|
|
2537
|
-
className: slots.
|
|
2538
|
-
children:
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
children: [
|
|
2543
|
-
"data-slot": "choice-list-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2610
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
2611
|
+
"data-slot": "choice-list-scroller",
|
|
2612
|
+
className: slots.scroller(),
|
|
2613
|
+
children: items.length === 0 ? /* @__PURE__ */ jsx("p", {
|
|
2614
|
+
"data-slot": "choice-list-note",
|
|
2615
|
+
className: slots.note(),
|
|
2616
|
+
children: empty
|
|
2617
|
+
}) : /* @__PURE__ */ jsxs(Fragment$1, { children: [rows.length > 0 ? /* @__PURE__ */ jsxs("div", {
|
|
2618
|
+
"data-slot": "choice-list-rows",
|
|
2619
|
+
className: slots.rows(),
|
|
2620
|
+
children: [props.multiple ? /* @__PURE__ */ jsx(CheckboxGroup, {
|
|
2621
|
+
"data-slot": "choice-list-group",
|
|
2622
|
+
value: props.value,
|
|
2623
|
+
onValueChange: props.onValueChange,
|
|
2624
|
+
...groupProps,
|
|
2625
|
+
children: rowElements
|
|
2626
|
+
}) : /* @__PURE__ */ jsx(RadioGroup, {
|
|
2627
|
+
"data-slot": "choice-list-group",
|
|
2628
|
+
value: props.value,
|
|
2629
|
+
onValueChange: props.onValueChange,
|
|
2630
|
+
...groupProps,
|
|
2631
|
+
children: rowElements
|
|
2632
|
+
}), sections.flatMap((section) => section.rows.map((item) => item.action !== void 0 && item.action !== null ? /* @__PURE__ */ jsx("div", {
|
|
2633
|
+
"data-slot": "choice-list-action",
|
|
2634
|
+
className: slots.action(),
|
|
2635
|
+
style: { gridRow: gridRowOf.get(item.value) },
|
|
2636
|
+
children: item.action
|
|
2637
|
+
}, item.value) : null))]
|
|
2638
|
+
}) : null, searchable ? /* @__PURE__ */ jsx("p", {
|
|
2639
|
+
role: "status",
|
|
2640
|
+
"data-slot": "choice-list-status",
|
|
2641
|
+
className: noMatch ? slots.note() : "sr-only",
|
|
2642
|
+
children: noMatch ? noMatchLabel : null
|
|
2643
|
+
}) : null] })
|
|
2644
|
+
}), footer !== void 0 && footer !== null ? /* @__PURE__ */ jsx("div", {
|
|
2645
|
+
"data-slot": "choice-list-footer",
|
|
2646
|
+
className: slots.footer(),
|
|
2647
|
+
children: footer
|
|
2648
|
+
}) : null]
|
|
2566
2649
|
})]
|
|
2567
2650
|
});
|
|
2568
2651
|
}
|