@botiverse/raft-ui 0.31.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,10 @@
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
+
1
8
  ## [0.31.0](https://github.com/botiverse/raft-design/compare/v0.30.0...v0.31.0) (2026-10-23)
2
9
 
3
10
  ### Design System
package/dist/wip.d.mts CHANGED
@@ -762,6 +762,13 @@ type ChoiceListCommonProps = {
762
762
  */
763
763
  searchValue?: string;
764
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[];
765
772
  /** The clear button's accessible name. */
766
773
  clearSearchLabel: string;
767
774
  /** The line under the chosen rows when nothing else matches. */
package/dist/wip.mjs CHANGED
@@ -2400,15 +2400,18 @@ function searchTextOf(item) {
2400
2400
  if (item.searchText !== void 0) return item.searchText;
2401
2401
  return typeof item.label === "string" ? item.label : "";
2402
2402
  }
2403
- function visibleItems(items, needle, pinned, chosen) {
2403
+ function visibleItems(items, needle, pinned, chosen, matchedValues) {
2404
2404
  if (!needle) return {
2405
2405
  rows: items,
2406
2406
  noMatch: false
2407
2407
  };
2408
- const matches = (item) => searchTextOf(item).toLowerCase().includes(needle);
2409
- 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);
2410
2412
  const top = items.filter((item) => isPinned(item) || chosen.includes(item.value) && !matches(item));
2411
- 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));
2412
2415
  return {
2413
2416
  rows: [...top, ...rest],
2414
2417
  noMatch: !items.some(matches)
@@ -2441,7 +2444,7 @@ function layoutSections(rows, groups) {
2441
2444
  };
2442
2445
  }
2443
2446
  function ChoiceList(props) {
2444
- const { items, search = "auto", "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, disabled = false, searchLabel, searchPlaceholder, defaultSearchValue = "", searchValue, onSearchValueChange, clearSearchLabel, noMatchLabel, empty, groups, footer, fill = false, 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;
2445
2448
  const value = props.value;
2446
2449
  const chosen = useMemo(() => value === null ? [] : typeof value === "string" ? [value] : value, [value]);
2447
2450
  const [ownQuery, setOwnQuery] = useState(defaultSearchValue);
@@ -2471,7 +2474,7 @@ function ChoiceList(props) {
2471
2474
  setPinnedFor(query);
2472
2475
  setPinned(chosen);
2473
2476
  }
2474
- const { rows, noMatch } = visibleItems(items, searchable ? query.trim().toLowerCase() : "", pinned, chosen);
2477
+ const { rows, noMatch } = visibleItems(items, searchable ? query.trim().toLowerCase() : "", pinned, chosen, matchedValues);
2475
2478
  const hasAction = rows.some((item) => item.action !== void 0 && item.action !== null);
2476
2479
  const slots = choiceList({
2477
2480
  scroll: searchable && !fill,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botiverse/raft-ui",
3
- "version": "0.31.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",