@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 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 p-1"],
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: { frame: ["max-h-72 overflow-y-auto overscroll-contain"] } },
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 matches = (item) => searchTextOf(item).toLowerCase().includes(needle);
2400
- const isPinned = (item) => pinned.includes(item.value);
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 rest = items.filter((item) => !top.includes(item) && matches(item));
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 [query, setQuery] = useState(defaultSearchValue);
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) setQuery("");
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({ scroll: searchable });
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
- setPinned(chosen);
2448
- }, [chosen]);
2505
+ }, [setQuery]);
2449
2506
  const clearQuery = useCallback(() => {
2450
2507
  setQuery("");
2451
- setPinned(chosen);
2452
2508
  inputRef.current?.focus();
2453
- }, [chosen]);
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 ${rows.length}` }
2516
+ style: { gridRow: `1 / span ${gridRows}` }
2460
2517
  };
2461
- const rowElements = rows.map((item) => {
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__ */ jsx("div", {
2607
+ }) : null, /* @__PURE__ */ jsxs("div", {
2533
2608
  "data-slot": "choice-list-frame",
2534
2609
  className: slots.frame(),
2535
- children: items.length === 0 ? /* @__PURE__ */ jsx("p", {
2536
- "data-slot": "choice-list-note",
2537
- className: slots.note(),
2538
- children: empty
2539
- }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [rows.length > 0 ? /* @__PURE__ */ jsxs("div", {
2540
- "data-slot": "choice-list-rows",
2541
- className: slots.rows(),
2542
- children: [props.multiple ? /* @__PURE__ */ jsx(CheckboxGroup, {
2543
- "data-slot": "choice-list-group",
2544
- value: props.value,
2545
- onValueChange: props.onValueChange,
2546
- ...groupProps,
2547
- children: rowElements
2548
- }) : /* @__PURE__ */ jsx(RadioGroup, {
2549
- "data-slot": "choice-list-group",
2550
- value: props.value,
2551
- onValueChange: props.onValueChange,
2552
- ...groupProps,
2553
- children: rowElements
2554
- }), rows.map((item, index) => item.action !== void 0 && item.action !== null ? /* @__PURE__ */ jsx("div", {
2555
- "data-slot": "choice-list-action",
2556
- className: slots.action(),
2557
- style: { gridRow: index + 1 },
2558
- children: item.action
2559
- }, item.value) : null)]
2560
- }) : null, searchable ? /* @__PURE__ */ jsx("p", {
2561
- role: "status",
2562
- "data-slot": "choice-list-status",
2563
- className: noMatch ? slots.note() : "sr-only",
2564
- children: noMatch ? noMatchLabel : null
2565
- }) : null] })
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botiverse/raft-ui",
3
- "version": "0.30.0",
3
+ "version": "0.32.0",
4
4
  "description": "React components and CSS foundations for the Raft Design System.",
5
5
  "keywords": [
6
6
  "agent-skills",