@botiverse/raft-ui 0.31.0 → 0.32.1
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 +14 -0
- package/dist/wip.d.mts +7 -0
- package/dist/wip.mjs +23 -10
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## [0.32.1](https://github.com/botiverse/raft-design/compare/v0.32.0...v0.32.1) (2026-10-23)
|
|
2
|
+
|
|
3
|
+
### Fixed
|
|
4
|
+
|
|
5
|
+
- **ChoiceList** (wip): a row's name or description line that is cut off has its whole text as its `title` while it is cut off, so a long description can still be read with a mouse. ([#783](https://github.com/botiverse/raft-design/pull/783))
|
|
6
|
+
- Docs: https://raft-design.botiverse.build/components/choice-list/
|
|
7
|
+
|
|
8
|
+
## [0.32.0](https://github.com/botiverse/raft-design/compare/v0.31.0...v0.32.0) (2026-10-23)
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **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))
|
|
13
|
+
- Docs: https://raft-design.botiverse.build/components/choice-list/
|
|
14
|
+
|
|
1
15
|
## [0.31.0](https://github.com/botiverse/raft-design/compare/v0.30.0...v0.31.0) (2026-10-23)
|
|
2
16
|
|
|
3
17
|
### 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
|
@@ -2379,6 +2379,16 @@ function isDrawn(line) {
|
|
|
2379
2379
|
function descriptionLines(description) {
|
|
2380
2380
|
return (Array.isArray(description) ? description : [description]).filter(isDrawn);
|
|
2381
2381
|
}
|
|
2382
|
+
function CutLine({ id, slot, className, children }) {
|
|
2383
|
+
const ref = useOverflowTitle();
|
|
2384
|
+
return /* @__PURE__ */ jsx("span", {
|
|
2385
|
+
ref,
|
|
2386
|
+
id,
|
|
2387
|
+
"data-slot": slot,
|
|
2388
|
+
className,
|
|
2389
|
+
children
|
|
2390
|
+
});
|
|
2391
|
+
}
|
|
2382
2392
|
const NOT_TEXT_INPUTS = /* @__PURE__ */ new Set([
|
|
2383
2393
|
"button",
|
|
2384
2394
|
"checkbox",
|
|
@@ -2400,15 +2410,18 @@ function searchTextOf(item) {
|
|
|
2400
2410
|
if (item.searchText !== void 0) return item.searchText;
|
|
2401
2411
|
return typeof item.label === "string" ? item.label : "";
|
|
2402
2412
|
}
|
|
2403
|
-
function visibleItems(items, needle, pinned, chosen) {
|
|
2413
|
+
function visibleItems(items, needle, pinned, chosen, matchedValues) {
|
|
2404
2414
|
if (!needle) return {
|
|
2405
2415
|
rows: items,
|
|
2406
2416
|
noMatch: false
|
|
2407
2417
|
};
|
|
2408
|
-
const
|
|
2409
|
-
const
|
|
2418
|
+
const matched = matchedValues ? new Set(matchedValues) : null;
|
|
2419
|
+
const matches = (item) => matched ? matched.has(item.value) : searchTextOf(item).toLowerCase().includes(needle);
|
|
2420
|
+
const pinnedSet = new Set(pinned);
|
|
2421
|
+
const isPinned = (item) => pinnedSet.has(item.value);
|
|
2410
2422
|
const top = items.filter((item) => isPinned(item) || chosen.includes(item.value) && !matches(item));
|
|
2411
|
-
const
|
|
2423
|
+
const byValue = matchedValues ? new Map(items.map((item) => [item.value, item])) : null;
|
|
2424
|
+
const rest = (byValue && matched ? [...matched].flatMap((value) => byValue.get(value) ?? []) : items).filter((item) => !top.includes(item) && matches(item));
|
|
2412
2425
|
return {
|
|
2413
2426
|
rows: [...top, ...rest],
|
|
2414
2427
|
noMatch: !items.some(matches)
|
|
@@ -2441,7 +2454,7 @@ function layoutSections(rows, groups) {
|
|
|
2441
2454
|
};
|
|
2442
2455
|
}
|
|
2443
2456
|
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;
|
|
2457
|
+
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
2458
|
const value = props.value;
|
|
2446
2459
|
const chosen = useMemo(() => value === null ? [] : typeof value === "string" ? [value] : value, [value]);
|
|
2447
2460
|
const [ownQuery, setOwnQuery] = useState(defaultSearchValue);
|
|
@@ -2471,7 +2484,7 @@ function ChoiceList(props) {
|
|
|
2471
2484
|
setPinnedFor(query);
|
|
2472
2485
|
setPinned(chosen);
|
|
2473
2486
|
}
|
|
2474
|
-
const { rows, noMatch } = visibleItems(items, searchable ? query.trim().toLowerCase() : "", pinned, chosen);
|
|
2487
|
+
const { rows, noMatch } = visibleItems(items, searchable ? query.trim().toLowerCase() : "", pinned, chosen, matchedValues);
|
|
2475
2488
|
const hasAction = rows.some((item) => item.action !== void 0 && item.action !== null);
|
|
2476
2489
|
const slots = choiceList({
|
|
2477
2490
|
scroll: searchable && !fill,
|
|
@@ -2536,16 +2549,16 @@ function ChoiceList(props) {
|
|
|
2536
2549
|
/* @__PURE__ */ jsxs("span", {
|
|
2537
2550
|
"data-slot": "choice-list-body",
|
|
2538
2551
|
className: slots.body(),
|
|
2539
|
-
children: [/* @__PURE__ */ jsx(
|
|
2552
|
+
children: [/* @__PURE__ */ jsx(CutLine, {
|
|
2540
2553
|
id: `${id}-label`,
|
|
2541
|
-
|
|
2554
|
+
slot: "choice-list-label",
|
|
2542
2555
|
className: slots.label(),
|
|
2543
2556
|
children: item.label
|
|
2544
2557
|
}), lines.length > 0 ? /* @__PURE__ */ jsx("span", {
|
|
2545
2558
|
id: `${id}-description`,
|
|
2546
2559
|
className: "contents",
|
|
2547
|
-
children: lines.map((line, index) => /* @__PURE__ */ jsx(
|
|
2548
|
-
|
|
2560
|
+
children: lines.map((line, index) => /* @__PURE__ */ jsx(CutLine, {
|
|
2561
|
+
slot: "choice-list-description",
|
|
2549
2562
|
className: slots.description(),
|
|
2550
2563
|
children: line
|
|
2551
2564
|
}, index))
|