@wallarm-org/design-system 1.28.2-rc-fix-table-window-scroll-root.1 → 1.29.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/dist/components/FilterDropdown/FilterDropdown.d.ts +58 -0
- package/dist/components/FilterDropdown/FilterDropdown.js +168 -0
- package/dist/components/FilterDropdown/FilterDropdownAllOption.d.ts +14 -0
- package/dist/components/FilterDropdown/FilterDropdownAllOption.js +25 -0
- package/dist/components/FilterDropdown/FilterDropdownClear.d.ts +12 -0
- package/dist/components/FilterDropdown/FilterDropdownClear.js +33 -0
- package/dist/components/FilterDropdown/FilterDropdownContent.d.ts +13 -0
- package/dist/components/FilterDropdown/FilterDropdownContent.js +57 -0
- package/dist/components/FilterDropdown/FilterDropdownContext.d.ts +60 -0
- package/dist/components/FilterDropdown/FilterDropdownContext.js +21 -0
- package/dist/components/FilterDropdown/FilterDropdownEmpty.d.ts +9 -0
- package/dist/components/FilterDropdown/FilterDropdownEmpty.js +21 -0
- package/dist/components/FilterDropdown/FilterDropdownFooter.d.ts +9 -0
- package/dist/components/FilterDropdown/FilterDropdownFooter.js +19 -0
- package/dist/components/FilterDropdown/FilterDropdownFooterClear.d.ts +9 -0
- package/dist/components/FilterDropdown/FilterDropdownFooterClear.js +40 -0
- package/dist/components/FilterDropdown/FilterDropdownGroup.d.ts +5 -0
- package/dist/components/FilterDropdown/FilterDropdownGroup.js +8 -0
- package/dist/components/FilterDropdown/FilterDropdownGroupLabel.d.ts +4 -0
- package/dist/components/FilterDropdown/FilterDropdownGroupLabel.js +8 -0
- package/dist/components/FilterDropdown/FilterDropdownOption.d.ts +15 -0
- package/dist/components/FilterDropdown/FilterDropdownOption.js +32 -0
- package/dist/components/FilterDropdown/FilterDropdownSearch.d.ts +12 -0
- package/dist/components/FilterDropdown/FilterDropdownSearch.js +38 -0
- package/dist/components/FilterDropdown/FilterDropdownSelected.d.ts +16 -0
- package/dist/components/FilterDropdown/FilterDropdownSelected.js +38 -0
- package/dist/components/FilterDropdown/FilterDropdownTrigger.d.ts +16 -0
- package/dist/components/FilterDropdown/FilterDropdownTrigger.js +139 -0
- package/dist/components/FilterDropdown/classes.d.ts +16 -0
- package/dist/components/FilterDropdown/classes.js +43 -0
- package/dist/components/FilterDropdown/index.d.ts +15 -0
- package/dist/components/FilterDropdown/index.js +15 -0
- package/dist/components/FilterDropdown/lib/index.d.ts +1 -0
- package/dist/components/FilterDropdown/lib/index.js +1 -0
- package/dist/components/FilterDropdown/lib/values.d.ts +59 -0
- package/dist/components/FilterDropdown/lib/values.js +58 -0
- package/dist/components/Select/Select.d.ts +1 -1
- package/dist/components/Select/SelectContent.d.ts +2 -1
- package/dist/components/Select/SelectContent.js +3 -2
- package/dist/components/Select/SelectEmptyState.d.ts +1 -0
- package/dist/components/Select/SelectEmptyState.js +2 -1
- package/dist/components/Select/SelectFooter.d.ts +7 -2
- package/dist/components/Select/SelectFooter.js +6 -3
- package/dist/components/Select/SelectGroup.d.ts +8 -2
- package/dist/components/Select/SelectGroup.js +3 -2
- package/dist/components/Select/SelectGroupLabel.d.ts +5 -2
- package/dist/components/Select/SelectGroupLabel.js +2 -2
- package/dist/components/Select/SelectOption.js +1 -1
- package/dist/components/Select/SelectOptionHint.d.ts +11 -0
- package/dist/components/Select/SelectOptionHint.js +15 -0
- package/dist/components/Select/SelectPositioner.d.ts +13 -3
- package/dist/components/Select/SelectPositioner.js +2 -1
- package/dist/components/Select/SelectSearchInput.d.ts +5 -2
- package/dist/components/Select/SelectSearchInput.js +11 -1
- package/dist/components/Select/classes.d.ts +3 -0
- package/dist/components/Select/classes.js +13 -0
- package/dist/components/Select/index.d.ts +4 -2
- package/dist/components/Select/index.js +2 -0
- package/dist/components/Table/TableBody/TableBodyVirtualizedCore.js +1 -1
- package/dist/components/Table/TableBody/TableBodyVirtualizedWindow.js +9 -25
- package/dist/components/Table/TableInner/TableInnerWindow.js +0 -1
- package/dist/components/Table/hooks/infiniteScroll/useInfiniteScroll.d.ts +1 -1
- package/dist/components/Table/hooks/infiniteScroll/usePrependScrollAnchor.d.ts +0 -1
- package/dist/components/Table/hooks/infiniteScroll/usePrependScrollAnchor.js +10 -12
- package/dist/components/Table/hooks/infiniteScroll/useScrollEdge.d.ts +1 -4
- package/dist/components/Table/hooks/infiniteScroll/useScrollEdge.js +17 -4
- package/dist/components/Table/lib/index.d.ts +0 -1
- package/dist/components/Table/lib/index.js +0 -1
- package/dist/components/Table/types.d.ts +1 -4
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/metadata/components.json +6160 -983
- package/package.json +1 -1
- package/dist/components/Table/lib/scrollRoot.d.ts +0 -18
- package/dist/components/Table/lib/scrollRoot.js +0 -22
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useContext } from "react";
|
|
3
|
+
import { useTestId } from "../../utils/testId.js";
|
|
4
|
+
import { SelectOption } from "../Select/SelectOption.js";
|
|
5
|
+
import { SelectOptionHint } from "../Select/SelectOptionHint.js";
|
|
6
|
+
import { SelectOptionIndicator } from "../Select/SelectOptionIndicator.js";
|
|
7
|
+
import { SelectOptionText } from "../Select/SelectOptionText.js";
|
|
8
|
+
import { FilterDropdownAliasContext, useFilterDropdownContext } from "./FilterDropdownContext.js";
|
|
9
|
+
const FilterDropdownOption = ({ item, hint, children, 'data-testid': testIdProp, ...props })=>{
|
|
10
|
+
const { collection } = useFilterDropdownContext();
|
|
11
|
+
const alias = useContext(FilterDropdownAliasContext);
|
|
12
|
+
const value = collection.getItemValue(item);
|
|
13
|
+
const isCopy = alias?.source !== void 0 && collection.getItemValue(alias.source) === value;
|
|
14
|
+
const copyTestId = useTestId('selected-option');
|
|
15
|
+
return /*#__PURE__*/ jsxs(SelectOption, {
|
|
16
|
+
...props,
|
|
17
|
+
item: isCopy && alias ? alias : item,
|
|
18
|
+
"data-slot": "filter-dropdown-option",
|
|
19
|
+
"data-testid": testIdProp ?? (isCopy ? copyTestId : void 0),
|
|
20
|
+
children: [
|
|
21
|
+
/*#__PURE__*/ jsx(SelectOptionText, {
|
|
22
|
+
children: children ?? collection.stringifyItem(item)
|
|
23
|
+
}),
|
|
24
|
+
null != hint && /*#__PURE__*/ jsx(SelectOptionHint, {
|
|
25
|
+
children: hint
|
|
26
|
+
}),
|
|
27
|
+
/*#__PURE__*/ jsx(SelectOptionIndicator, {})
|
|
28
|
+
]
|
|
29
|
+
});
|
|
30
|
+
};
|
|
31
|
+
FilterDropdownOption.displayName = 'FilterDropdownOption';
|
|
32
|
+
export { FilterDropdownOption };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { FC } from 'react';
|
|
2
|
+
import { type TestableProps } from '../../utils/testId';
|
|
3
|
+
import { type SelectSearchInputProps } from '../Select/SelectSearchInput';
|
|
4
|
+
export interface FilterDropdownSearchProps extends Omit<SelectSearchInputProps, 'value' | 'onChange' | 'data-testid'>, TestableProps {
|
|
5
|
+
/** Called after the query changes; the root owns the query itself. */
|
|
6
|
+
onChange?: (query: string) => void;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* The search field pinned above the list. Renders only once the collection reaches
|
|
10
|
+
* `searchThreshold` items, and takes focus when the menu opens. Attributes land on the `<input>`.
|
|
11
|
+
*/
|
|
12
|
+
export declare const FilterDropdownSearch: FC<FilterDropdownSearchProps>;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useSelectContext } from "@ark-ui/react/select";
|
|
3
|
+
import { useTestId } from "../../utils/testId.js";
|
|
4
|
+
import { SelectSearchInput } from "../Select/SelectSearchInput.js";
|
|
5
|
+
import { useFilterDropdownContext } from "./FilterDropdownContext.js";
|
|
6
|
+
const FilterDropdownSearch = ({ onChange, 'aria-label': ariaLabel, 'data-testid': testIdProp, ...props })=>{
|
|
7
|
+
const { label, query, setQuery, isSearchable } = useFilterDropdownContext();
|
|
8
|
+
const testId = useTestId('search', testIdProp);
|
|
9
|
+
const select = useSelectContext();
|
|
10
|
+
if (!isSearchable) return null;
|
|
11
|
+
const handleChange = (next)=>{
|
|
12
|
+
setQuery(next);
|
|
13
|
+
onChange?.(next);
|
|
14
|
+
};
|
|
15
|
+
const highlighted = select.highlightedItem;
|
|
16
|
+
const activeDescendant = highlighted ? select.getItemProps({
|
|
17
|
+
item: highlighted
|
|
18
|
+
}).id : void 0;
|
|
19
|
+
return /*#__PURE__*/ jsx("div", {
|
|
20
|
+
"data-slot": "filter-dropdown-search",
|
|
21
|
+
className: "-mb-3",
|
|
22
|
+
children: /*#__PURE__*/ jsx(SelectSearchInput, {
|
|
23
|
+
"data-autofocus": "",
|
|
24
|
+
role: "combobox",
|
|
25
|
+
"aria-autocomplete": "list",
|
|
26
|
+
"aria-expanded": select.open,
|
|
27
|
+
"aria-controls": select.getContentProps().id,
|
|
28
|
+
"aria-activedescendant": activeDescendant,
|
|
29
|
+
...props,
|
|
30
|
+
"aria-label": ariaLabel ?? `Search ${label}`,
|
|
31
|
+
value: query,
|
|
32
|
+
onChange: handleChange,
|
|
33
|
+
"data-testid": testId
|
|
34
|
+
})
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
FilterDropdownSearch.displayName = 'FilterDropdownSearch';
|
|
38
|
+
export { FilterDropdownSearch };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ComponentProps, ReactNode } from 'react';
|
|
2
|
+
import type { CollectionItem } from '@ark-ui/react/collection';
|
|
3
|
+
import { SelectGroup } from '../Select/SelectGroup';
|
|
4
|
+
export interface FilterDropdownSelectedProps<T extends CollectionItem = CollectionItem> extends Omit<ComponentProps<typeof SelectGroup>, 'children'> {
|
|
5
|
+
/** @default 'Selected' */
|
|
6
|
+
label?: ReactNode;
|
|
7
|
+
/**
|
|
8
|
+
* Renders one row; return the same `FilterDropdownOption` as in the list (hint included) and it
|
|
9
|
+
* becomes this row's copy. Defaults to a plain option with the item's label.
|
|
10
|
+
*/
|
|
11
|
+
children?: (item: T) => ReactNode;
|
|
12
|
+
}
|
|
13
|
+
export declare function FilterDropdownSelected<T extends CollectionItem>({ label, children, 'data-testid': testIdProp, ...props }: FilterDropdownSelectedProps<T>): import("react").JSX.Element | null;
|
|
14
|
+
export declare namespace FilterDropdownSelected {
|
|
15
|
+
var displayName: string;
|
|
16
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useTestId } from "../../utils/testId.js";
|
|
3
|
+
import { SelectGroup } from "../Select/SelectGroup.js";
|
|
4
|
+
import { SelectGroupLabel } from "../Select/SelectGroupLabel.js";
|
|
5
|
+
import { SelectSeparator } from "../Select/SelectSeparator.js";
|
|
6
|
+
import { FilterDropdownAliasContext, useFilterDropdownContext } from "./FilterDropdownContext.js";
|
|
7
|
+
import { FilterDropdownOption } from "./FilterDropdownOption.js";
|
|
8
|
+
const FilterDropdownSelected = ({ label = 'Selected', children, 'data-testid': testIdProp, ...props })=>{
|
|
9
|
+
const { showSelected, aliasItems } = useFilterDropdownContext();
|
|
10
|
+
const testId = useTestId('selected', testIdProp);
|
|
11
|
+
if (!showSelected) return null;
|
|
12
|
+
return /*#__PURE__*/ jsxs(Fragment, {
|
|
13
|
+
children: [
|
|
14
|
+
/*#__PURE__*/ jsxs(SelectGroup, {
|
|
15
|
+
...props,
|
|
16
|
+
"data-slot": "filter-dropdown-selected",
|
|
17
|
+
"data-testid": testId,
|
|
18
|
+
children: [
|
|
19
|
+
/*#__PURE__*/ jsx(SelectGroupLabel, {
|
|
20
|
+
children: label
|
|
21
|
+
}),
|
|
22
|
+
aliasItems.map((alias)=>{
|
|
23
|
+
const source = alias.source;
|
|
24
|
+
return /*#__PURE__*/ jsx(FilterDropdownAliasContext.Provider, {
|
|
25
|
+
value: alias,
|
|
26
|
+
children: children ? children(source) : /*#__PURE__*/ jsx(FilterDropdownOption, {
|
|
27
|
+
item: source
|
|
28
|
+
})
|
|
29
|
+
}, alias.value);
|
|
30
|
+
})
|
|
31
|
+
]
|
|
32
|
+
}),
|
|
33
|
+
/*#__PURE__*/ jsx(SelectSeparator, {})
|
|
34
|
+
]
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
FilterDropdownSelected.displayName = 'FilterDropdownSelected';
|
|
38
|
+
export { FilterDropdownSelected };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type ButtonHTMLAttributes, type FC, type ReactNode, type Ref } from 'react';
|
|
2
|
+
import { type TestableProps } from '../../utils/testId';
|
|
3
|
+
export interface FilterDropdownTriggerProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'children'>, TestableProps {
|
|
4
|
+
ref?: Ref<HTMLButtonElement>;
|
|
5
|
+
/**
|
|
6
|
+
* Only a `<FilterDropdownClear />`, to replace the ✕ rendered in multi mode. The label is
|
|
7
|
+
* derived from the value and is not overridable.
|
|
8
|
+
*/
|
|
9
|
+
children?: ReactNode;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* The 36px trigger. Dashed while unset, solid once set; reads «All …» / the value in single mode
|
|
13
|
+
* and «Name», «Name • value» or «Name • N» in multi mode. In multi mode Backspace/Delete on the
|
|
14
|
+
* focused trigger clears the filter.
|
|
15
|
+
*/
|
|
16
|
+
export declare const FilterDropdownTrigger: FC<FilterDropdownTriggerProps>;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Children, isValidElement } from "react";
|
|
3
|
+
import { Select } from "@ark-ui/react/select";
|
|
4
|
+
import { cn } from "../../utils/cn.js";
|
|
5
|
+
import { mergeRefs } from "../../utils/mergeRefs.js";
|
|
6
|
+
import { TestIdProvider, useTestId } from "../../utils/testId.js";
|
|
7
|
+
import { NumericBadge } from "../NumericBadge/index.js";
|
|
8
|
+
import { OverflowTooltip, OverflowTooltipContent, OverflowTooltipTrigger } from "../OverflowTooltip/index.js";
|
|
9
|
+
import { SelectArrow } from "../Select/SelectArrow.js";
|
|
10
|
+
import { filterDropdownControlVariants, filterDropdownLabelVariants, filterDropdownTriggerVariants } from "./classes.js";
|
|
11
|
+
import { FilterDropdownClear } from "./FilterDropdownClear.js";
|
|
12
|
+
import { useFilterDropdownContext } from "./FilterDropdownContext.js";
|
|
13
|
+
const CLEAR_KEYS = new Set([
|
|
14
|
+
'Backspace',
|
|
15
|
+
'Delete'
|
|
16
|
+
]);
|
|
17
|
+
const TruncatedText = ({ text, emphasis, className })=>/*#__PURE__*/ jsx(TestIdProvider, {
|
|
18
|
+
value: void 0,
|
|
19
|
+
children: /*#__PURE__*/ jsxs(OverflowTooltip, {
|
|
20
|
+
children: [
|
|
21
|
+
/*#__PURE__*/ jsx(OverflowTooltipTrigger, {
|
|
22
|
+
children: /*#__PURE__*/ jsx("span", {
|
|
23
|
+
className: cn(filterDropdownLabelVariants({
|
|
24
|
+
emphasis
|
|
25
|
+
}), className),
|
|
26
|
+
children: text
|
|
27
|
+
})
|
|
28
|
+
}),
|
|
29
|
+
/*#__PURE__*/ jsx(OverflowTooltipContent, {
|
|
30
|
+
children: text
|
|
31
|
+
})
|
|
32
|
+
]
|
|
33
|
+
})
|
|
34
|
+
});
|
|
35
|
+
const Separator = ()=>/*#__PURE__*/ jsx("span", {
|
|
36
|
+
"aria-hidden": true,
|
|
37
|
+
className: "shrink-0 text-xs text-text-tertiary",
|
|
38
|
+
children: "•"
|
|
39
|
+
});
|
|
40
|
+
const FilterDropdownTrigger = ({ ref, className, children, onKeyDown, 'aria-label': ariaLabel, 'data-testid': testIdProp, ...props })=>{
|
|
41
|
+
const { label, allLabel, multiple, value, collection, clear, triggerRef } = useFilterDropdownContext();
|
|
42
|
+
const controlTestId = useTestId('control');
|
|
43
|
+
const testId = useTestId('trigger', testIdProp);
|
|
44
|
+
const isSet = value.length > 0;
|
|
45
|
+
const clearable = multiple && isSet;
|
|
46
|
+
const labels = value.map((v)=>collection.stringify(v) ?? v);
|
|
47
|
+
const customClear = Children.toArray(children).find((child)=>/*#__PURE__*/ isValidElement(child) && child.type === FilterDropdownClear);
|
|
48
|
+
const handleKeyDown = (event)=>{
|
|
49
|
+
onKeyDown?.(event);
|
|
50
|
+
if (event.defaultPrevented || !clearable || !CLEAR_KEYS.has(event.key)) return;
|
|
51
|
+
event.preventDefault();
|
|
52
|
+
clear();
|
|
53
|
+
};
|
|
54
|
+
let content;
|
|
55
|
+
let composedLabel = label;
|
|
56
|
+
if (multiple) if (isSet) if (1 === value.length) {
|
|
57
|
+
content = /*#__PURE__*/ jsxs(Fragment, {
|
|
58
|
+
children: [
|
|
59
|
+
/*#__PURE__*/ jsx(TruncatedText, {
|
|
60
|
+
text: label,
|
|
61
|
+
emphasis: "name"
|
|
62
|
+
}),
|
|
63
|
+
/*#__PURE__*/ jsx(Separator, {}),
|
|
64
|
+
/*#__PURE__*/ jsx(TruncatedText, {
|
|
65
|
+
text: labels[0] ?? '',
|
|
66
|
+
emphasis: "value",
|
|
67
|
+
className: "min-w-24"
|
|
68
|
+
})
|
|
69
|
+
]
|
|
70
|
+
});
|
|
71
|
+
composedLabel = `${label}, ${labels[0]}`;
|
|
72
|
+
} else {
|
|
73
|
+
content = /*#__PURE__*/ jsxs(Fragment, {
|
|
74
|
+
children: [
|
|
75
|
+
/*#__PURE__*/ jsx(TruncatedText, {
|
|
76
|
+
text: label,
|
|
77
|
+
emphasis: "name"
|
|
78
|
+
}),
|
|
79
|
+
/*#__PURE__*/ jsx(Separator, {}),
|
|
80
|
+
/*#__PURE__*/ jsx("span", {
|
|
81
|
+
"aria-hidden": true,
|
|
82
|
+
className: "inline-flex shrink-0",
|
|
83
|
+
children: /*#__PURE__*/ jsx(NumericBadge, {
|
|
84
|
+
type: "primary",
|
|
85
|
+
children: value.length
|
|
86
|
+
})
|
|
87
|
+
})
|
|
88
|
+
]
|
|
89
|
+
});
|
|
90
|
+
composedLabel = `${label}, ${value.length} selected: ${labels.join(', ')}`;
|
|
91
|
+
}
|
|
92
|
+
else content = /*#__PURE__*/ jsx(TruncatedText, {
|
|
93
|
+
text: label,
|
|
94
|
+
emphasis: "name"
|
|
95
|
+
});
|
|
96
|
+
else {
|
|
97
|
+
content = isSet ? /*#__PURE__*/ jsx(TruncatedText, {
|
|
98
|
+
text: labels[0] ?? '',
|
|
99
|
+
emphasis: "value"
|
|
100
|
+
}) : /*#__PURE__*/ jsx(TruncatedText, {
|
|
101
|
+
text: allLabel,
|
|
102
|
+
emphasis: "name"
|
|
103
|
+
});
|
|
104
|
+
if (isSet) composedLabel = `${label}, ${labels[0]}`;
|
|
105
|
+
}
|
|
106
|
+
return /*#__PURE__*/ jsxs(Select.Control, {
|
|
107
|
+
"data-slot": "filter-dropdown-control",
|
|
108
|
+
"data-testid": controlTestId,
|
|
109
|
+
className: filterDropdownControlVariants({
|
|
110
|
+
applied: isSet,
|
|
111
|
+
clearable
|
|
112
|
+
}),
|
|
113
|
+
children: [
|
|
114
|
+
/*#__PURE__*/ jsxs(Select.Trigger, {
|
|
115
|
+
...props,
|
|
116
|
+
ref: mergeRefs(ref, triggerRef),
|
|
117
|
+
"data-slot": "filter-dropdown-trigger",
|
|
118
|
+
"data-testid": testId,
|
|
119
|
+
"aria-label": ariaLabel ?? composedLabel,
|
|
120
|
+
onKeyDown: handleKeyDown,
|
|
121
|
+
className: cn(filterDropdownTriggerVariants({
|
|
122
|
+
clearable
|
|
123
|
+
}), className),
|
|
124
|
+
children: [
|
|
125
|
+
/*#__PURE__*/ jsx("span", {
|
|
126
|
+
className: "flex min-w-0 items-center gap-4 overflow-hidden",
|
|
127
|
+
children: content
|
|
128
|
+
}),
|
|
129
|
+
!clearable && /*#__PURE__*/ jsx(SelectArrow, {
|
|
130
|
+
className: "text-icon-primary"
|
|
131
|
+
})
|
|
132
|
+
]
|
|
133
|
+
}),
|
|
134
|
+
customClear ?? /*#__PURE__*/ jsx(FilterDropdownClear, {})
|
|
135
|
+
]
|
|
136
|
+
});
|
|
137
|
+
};
|
|
138
|
+
FilterDropdownTrigger.displayName = 'FilterDropdownTrigger';
|
|
139
|
+
export { FilterDropdownTrigger };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The pill that holds the trigger and, when a multi filter is set, the ✕. It owns the border,
|
|
3
|
+
* surface and state overlays so the two buttons read as one control (Figma `filter-dropdown`).
|
|
4
|
+
*/
|
|
5
|
+
export declare const filterDropdownControlVariants: (props?: ({
|
|
6
|
+
applied?: boolean | null | undefined;
|
|
7
|
+
clearable?: boolean | null | undefined;
|
|
8
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
9
|
+
export declare const filterDropdownTriggerVariants: (props?: ({
|
|
10
|
+
clearable?: boolean | null | undefined;
|
|
11
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
12
|
+
export declare const filterDropdownLabelVariants: (props?: ({
|
|
13
|
+
emphasis?: "name" | "value" | null | undefined;
|
|
14
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
15
|
+
export declare const filterDropdownClearClassName: string;
|
|
16
|
+
export declare const filterDropdownContentClassName: string;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { cva } from "class-variance-authority";
|
|
2
|
+
import { cn } from "../../utils/cn.js";
|
|
3
|
+
const filterDropdownControlVariants = cva(cn('inline-flex h-36 min-w-0 max-w-180 items-stretch', 'rounded-12 border-1 border-border-primary bg-component-outline-button-bg', 'font-sans text-sm text-text-primary', 'overlay hover:not-data-disabled:overlay-states-primary-hover', 'active:not-data-disabled:overlay-states-primary-pressed data-[state=open]:overlay-states-primary-pressed', 'transition-[border,box-shadow,opacity]', 'has-[[data-slot=filter-dropdown-trigger]:focus-visible]:ring-3 has-[[data-slot=filter-dropdown-trigger]:focus-visible]:ring-focus-primary', 'data-disabled:opacity-50 data-disabled:cursor-not-allowed'), {
|
|
4
|
+
variants: {
|
|
5
|
+
applied: {
|
|
6
|
+
true: 'border-solid shadow-2xs has-[[data-slot=filter-dropdown-trigger]:focus-visible]:shadow-none',
|
|
7
|
+
false: 'border-dashed'
|
|
8
|
+
},
|
|
9
|
+
clearable: {
|
|
10
|
+
true: 'pr-6',
|
|
11
|
+
false: ''
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
defaultVariants: {
|
|
15
|
+
applied: false,
|
|
16
|
+
clearable: false
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
const filterDropdownTriggerVariants = cva(cn('flex min-w-0 flex-1 items-center gap-8 py-8 pl-16', 'cursor-pointer outline-none disabled:cursor-not-allowed', '[&_svg]:pointer-events-none [&_svg]:shrink-0'), {
|
|
20
|
+
variants: {
|
|
21
|
+
clearable: {
|
|
22
|
+
true: 'pr-4',
|
|
23
|
+
false: 'pr-10'
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
defaultVariants: {
|
|
27
|
+
clearable: false
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
const filterDropdownLabelVariants = cva('min-w-0 truncate', {
|
|
31
|
+
variants: {
|
|
32
|
+
emphasis: {
|
|
33
|
+
value: 'font-medium',
|
|
34
|
+
name: 'font-normal'
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
defaultVariants: {
|
|
38
|
+
emphasis: 'name'
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
const filterDropdownClearClassName = cn('inline-flex size-24 shrink-0 items-center justify-center self-center rounded-6', 'cursor-pointer text-icon-secondary transition-colors hover:not-disabled:text-icon-primary', 'outline-none focus-visible:ring-3 focus-visible:ring-focus-primary', 'disabled:cursor-not-allowed [&_svg]:icon-md [&_svg]:pointer-events-none');
|
|
42
|
+
const filterDropdownContentClassName = cn('min-w-128 max-w-360', 'max-h-[min(340px,var(--available-height))]');
|
|
43
|
+
export { filterDropdownClearClassName, filterDropdownContentClassName, filterDropdownControlVariants, filterDropdownLabelVariants, filterDropdownTriggerVariants };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export { filterDropdownControlVariants, filterDropdownTriggerVariants } from './classes';
|
|
2
|
+
export { FilterDropdown, type FilterDropdownOpenChangeDetails, type FilterDropdownProps, type FilterDropdownValueChangeDetails, } from './FilterDropdown';
|
|
3
|
+
export { FilterDropdownAllOption, type FilterDropdownAllOptionProps, } from './FilterDropdownAllOption';
|
|
4
|
+
export { FilterDropdownClear, type FilterDropdownClearProps } from './FilterDropdownClear';
|
|
5
|
+
export { FilterDropdownContent, type FilterDropdownContentProps } from './FilterDropdownContent';
|
|
6
|
+
export { type UseFilterDropdownResult, useFilterDropdown } from './FilterDropdownContext';
|
|
7
|
+
export { FilterDropdownEmpty, type FilterDropdownEmptyProps } from './FilterDropdownEmpty';
|
|
8
|
+
export { FilterDropdownFooter, type FilterDropdownFooterProps } from './FilterDropdownFooter';
|
|
9
|
+
export { FilterDropdownFooterClear, type FilterDropdownFooterClearProps, } from './FilterDropdownFooterClear';
|
|
10
|
+
export { FilterDropdownGroup, type FilterDropdownGroupProps } from './FilterDropdownGroup';
|
|
11
|
+
export { FilterDropdownGroupLabel, type FilterDropdownGroupLabelProps, } from './FilterDropdownGroupLabel';
|
|
12
|
+
export { FilterDropdownOption, type FilterDropdownOptionProps } from './FilterDropdownOption';
|
|
13
|
+
export { FilterDropdownSearch, type FilterDropdownSearchProps } from './FilterDropdownSearch';
|
|
14
|
+
export { FilterDropdownSelected, type FilterDropdownSelectedProps } from './FilterDropdownSelected';
|
|
15
|
+
export { FilterDropdownTrigger, type FilterDropdownTriggerProps } from './FilterDropdownTrigger';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export { filterDropdownControlVariants, filterDropdownTriggerVariants } from "./classes.js";
|
|
2
|
+
export { FilterDropdown } from "./FilterDropdown.js";
|
|
3
|
+
export { FilterDropdownAllOption } from "./FilterDropdownAllOption.js";
|
|
4
|
+
export { FilterDropdownClear } from "./FilterDropdownClear.js";
|
|
5
|
+
export { FilterDropdownContent } from "./FilterDropdownContent.js";
|
|
6
|
+
export { useFilterDropdown } from "./FilterDropdownContext.js";
|
|
7
|
+
export { FilterDropdownEmpty } from "./FilterDropdownEmpty.js";
|
|
8
|
+
export { FilterDropdownFooter } from "./FilterDropdownFooter.js";
|
|
9
|
+
export { FilterDropdownFooterClear } from "./FilterDropdownFooterClear.js";
|
|
10
|
+
export { FilterDropdownGroup } from "./FilterDropdownGroup.js";
|
|
11
|
+
export { FilterDropdownGroupLabel } from "./FilterDropdownGroupLabel.js";
|
|
12
|
+
export { FilterDropdownOption } from "./FilterDropdownOption.js";
|
|
13
|
+
export { FilterDropdownSearch } from "./FilterDropdownSearch.js";
|
|
14
|
+
export { FilterDropdownSelected } from "./FilterDropdownSelected.js";
|
|
15
|
+
export { FilterDropdownTrigger } from "./FilterDropdownTrigger.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ALL_VALUE, createAliasItem, createAllItem, type FilterDropdownSpecialItem, isAliasValue, isSpecialItem, SELECTED_PREFIX, toAliasValue, toBaseValue, toConsumerValue, toInternalValue, } from './values';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ALL_VALUE, SELECTED_PREFIX, createAliasItem, createAllItem, isAliasValue, isSpecialItem, toAliasValue, toBaseValue, toConsumerValue, toInternalValue } from "./values.js";
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { CollectionItem, ListCollection } from '@ark-ui/react/collection';
|
|
2
|
+
/**
|
|
3
|
+
* Value of the single-mode «All …» option inside Ark. The consumer never sees it: it maps to `[]`.
|
|
4
|
+
*/
|
|
5
|
+
export declare const ALL_VALUE = "__all__";
|
|
6
|
+
/**
|
|
7
|
+
* Prefix of the alias values that back the rows of the multi-mode "Selected" section. Ark keys
|
|
8
|
+
* items by value, so a row rendered twice needs a second value; the root strips the prefix before
|
|
9
|
+
* anything reaches the consumer.
|
|
10
|
+
*/
|
|
11
|
+
export declare const SELECTED_PREFIX = "__selected__:";
|
|
12
|
+
declare const SPECIAL: unique symbol;
|
|
13
|
+
/** An item that exists only inside the Ark collection: the «All» sentinel or a "Selected" alias. */
|
|
14
|
+
export interface FilterDropdownSpecialItem<T extends CollectionItem = CollectionItem> {
|
|
15
|
+
readonly [SPECIAL]: true;
|
|
16
|
+
readonly value: string;
|
|
17
|
+
readonly label: string;
|
|
18
|
+
/** The base item an alias duplicates; absent on the «All» sentinel. */
|
|
19
|
+
readonly source?: T;
|
|
20
|
+
}
|
|
21
|
+
export declare const isSpecialItem: (item: unknown) => item is FilterDropdownSpecialItem;
|
|
22
|
+
export declare const toAliasValue: (value: string) => string;
|
|
23
|
+
export declare const isAliasValue: (value: string) => boolean;
|
|
24
|
+
export declare const toBaseValue: (value: string) => string;
|
|
25
|
+
export declare const createAllItem: (label: string) => FilterDropdownSpecialItem;
|
|
26
|
+
export declare const createAliasItem: <T extends CollectionItem>(item: T, collection: ListCollection<T>) => FilterDropdownSpecialItem<T>;
|
|
27
|
+
interface ToInternalValueOptions {
|
|
28
|
+
multiple: boolean;
|
|
29
|
+
/** Base values that currently have an alias row in the "Selected" section. */
|
|
30
|
+
aliased: ReadonlySet<string>;
|
|
31
|
+
/**
|
|
32
|
+
* Single mode: the «All» row is in the collection. Without it an unset value stays `[]`, so Ark
|
|
33
|
+
* never selects or highlights a value it cannot find.
|
|
34
|
+
* @default true
|
|
35
|
+
*/
|
|
36
|
+
hasAll?: boolean;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Consumer value → the value handed to Ark.
|
|
40
|
+
* - single: `[]` becomes the «All» sentinel, so «All» shows as picked;
|
|
41
|
+
* - multi: every picked value that has an alias row is doubled with its alias, so the copy in
|
|
42
|
+
* "Selected" and the original in the list tick together.
|
|
43
|
+
*/
|
|
44
|
+
export declare const toInternalValue: (value: readonly string[], { multiple, aliased, hasAll }: ToInternalValueOptions) => string[];
|
|
45
|
+
interface ToConsumerValueOptions {
|
|
46
|
+
multiple: boolean;
|
|
47
|
+
/** The internal value Ark had before this change. */
|
|
48
|
+
previousInternal: readonly string[];
|
|
49
|
+
/** The consumer value before this change. */
|
|
50
|
+
previousValue: readonly string[];
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Ark's next value → consumer value. Never returns the sentinel or an alias.
|
|
54
|
+
* - single: the sentinel (or nothing) becomes `[]`;
|
|
55
|
+
* - multi: Ark only ever toggles, so the change is read as a diff against what Ark had — an alias
|
|
56
|
+
* toggles its base value, which is how unticking a copy in "Selected" unticks the original.
|
|
57
|
+
*/
|
|
58
|
+
export declare const toConsumerValue: (next: readonly string[], { multiple, previousInternal, previousValue }: ToConsumerValueOptions) => string[];
|
|
59
|
+
export {};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
const ALL_VALUE = '__all__';
|
|
2
|
+
const SELECTED_PREFIX = '__selected__:';
|
|
3
|
+
const SPECIAL = Symbol('filter-dropdown-special-item');
|
|
4
|
+
const isSpecialItem = (item)=>'object' == typeof item && null !== item && SPECIAL in item;
|
|
5
|
+
const toAliasValue = (value)=>`${SELECTED_PREFIX}${value}`;
|
|
6
|
+
const isAliasValue = (value)=>value.startsWith(SELECTED_PREFIX);
|
|
7
|
+
const toBaseValue = (value)=>isAliasValue(value) ? value.slice(SELECTED_PREFIX.length) : value;
|
|
8
|
+
const createAllItem = (label)=>({
|
|
9
|
+
[SPECIAL]: true,
|
|
10
|
+
value: ALL_VALUE,
|
|
11
|
+
label
|
|
12
|
+
});
|
|
13
|
+
const createAliasItem = (item, collection)=>({
|
|
14
|
+
[SPECIAL]: true,
|
|
15
|
+
value: toAliasValue(collection.getItemValue(item) ?? ''),
|
|
16
|
+
label: collection.stringifyItem(item) ?? '',
|
|
17
|
+
source: item
|
|
18
|
+
});
|
|
19
|
+
const toInternalValue = (value, { multiple, aliased, hasAll = true })=>{
|
|
20
|
+
if (!multiple) {
|
|
21
|
+
const [first] = value;
|
|
22
|
+
if (void 0 === first) return hasAll ? [
|
|
23
|
+
ALL_VALUE
|
|
24
|
+
] : [];
|
|
25
|
+
return [
|
|
26
|
+
first
|
|
27
|
+
];
|
|
28
|
+
}
|
|
29
|
+
return [
|
|
30
|
+
...value,
|
|
31
|
+
...value.filter((v)=>aliased.has(v)).map(toAliasValue)
|
|
32
|
+
];
|
|
33
|
+
};
|
|
34
|
+
const toConsumerValue = (next, { multiple, previousInternal, previousValue })=>{
|
|
35
|
+
if (!multiple) {
|
|
36
|
+
const [first] = next;
|
|
37
|
+
return void 0 === first || first === ALL_VALUE ? [] : [
|
|
38
|
+
toBaseValue(first)
|
|
39
|
+
];
|
|
40
|
+
}
|
|
41
|
+
const before = new Set(previousInternal);
|
|
42
|
+
const after = new Set(next);
|
|
43
|
+
let result = [
|
|
44
|
+
...previousValue
|
|
45
|
+
];
|
|
46
|
+
for (const v of next){
|
|
47
|
+
if (before.has(v) || v === ALL_VALUE) continue;
|
|
48
|
+
const base = toBaseValue(v);
|
|
49
|
+
if (!result.includes(base)) result.push(base);
|
|
50
|
+
}
|
|
51
|
+
for (const v of previousInternal){
|
|
52
|
+
if (after.has(v)) continue;
|
|
53
|
+
const base = toBaseValue(v);
|
|
54
|
+
result = result.filter((r)=>r !== base);
|
|
55
|
+
}
|
|
56
|
+
return result;
|
|
57
|
+
};
|
|
58
|
+
export { ALL_VALUE, SELECTED_PREFIX, createAliasItem, createAllItem, isAliasValue, isSpecialItem, toAliasValue, toBaseValue, toConsumerValue, toInternalValue };
|
|
@@ -6,7 +6,7 @@ export interface SelectBaseProps {
|
|
|
6
6
|
/** Override default floating positioning (merged with DS defaults). */
|
|
7
7
|
positioning?: SelectRootProps<CollectionItem>['positioning'];
|
|
8
8
|
}
|
|
9
|
-
type SelectProps<T extends CollectionItem> = SelectNativeProps<T> & SelectBaseProps & TestableProps;
|
|
9
|
+
export type SelectProps<T extends CollectionItem> = SelectNativeProps<T> & SelectBaseProps & TestableProps;
|
|
10
10
|
export declare function Select<T extends CollectionItem>({ children, loading, disabled, positioning: positioningOverride, 'data-testid': testId, ...props }: SelectProps<T>): import("react").JSX.Element;
|
|
11
11
|
export declare namespace Select {
|
|
12
12
|
var displayName: string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type FC } from 'react';
|
|
2
2
|
import { Select as ArkUiSelect } from '@ark-ui/react/select';
|
|
3
|
-
type
|
|
3
|
+
import { type TestableProps } from '../../utils/testId';
|
|
4
|
+
type SelectContentProps = Omit<ArkUiSelect.ContentProps, 'className'> & TestableProps;
|
|
4
5
|
export declare const SelectContent: FC<SelectContentProps>;
|
|
5
6
|
export {};
|
|
@@ -5,8 +5,8 @@ import { cn } from "../../utils/cn.js";
|
|
|
5
5
|
import { useTestId } from "../../utils/testId.js";
|
|
6
6
|
import { ScrollArea, ScrollAreaContent, ScrollAreaCorner, ScrollAreaScrollbar, ScrollAreaViewport } from "../ScrollArea/index.js";
|
|
7
7
|
import { SelectEmptyState } from "./SelectEmptyState.js";
|
|
8
|
-
const SelectContent = ({ children, ...props })=>{
|
|
9
|
-
const testId = useTestId('content');
|
|
8
|
+
const SelectContent = ({ children, 'data-testid': testIdProp, ...props })=>{
|
|
9
|
+
const testId = useTestId('content', testIdProp);
|
|
10
10
|
const isEmpty = 0 === Children.count(children);
|
|
11
11
|
return /*#__PURE__*/ jsx(Select.List, {
|
|
12
12
|
...props,
|
|
@@ -16,6 +16,7 @@ const SelectContent = ({ children, ...props })=>{
|
|
|
16
16
|
children: /*#__PURE__*/ jsxs(ScrollArea, {
|
|
17
17
|
children: [
|
|
18
18
|
/*#__PURE__*/ jsx(ScrollAreaViewport, {
|
|
19
|
+
"data-no-autofocus": "",
|
|
19
20
|
children: /*#__PURE__*/ jsx(ScrollAreaContent, {
|
|
20
21
|
className: "flex flex-col gap-1",
|
|
21
22
|
children: isEmpty ? /*#__PURE__*/ jsx(SelectEmptyState, {}) : children
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
2
|
import { EmptyState, EmptyStateDescription, EmptyStateMessage } from "../EmptyState/index.js";
|
|
3
|
-
const SelectEmptyState = ({ description = 'No results' })=>/*#__PURE__*/ jsx(EmptyState, {
|
|
3
|
+
const SelectEmptyState = ({ description = 'No results', className })=>/*#__PURE__*/ jsx(EmptyState, {
|
|
4
4
|
type: "no-results",
|
|
5
|
+
className: className,
|
|
5
6
|
children: /*#__PURE__*/ jsx(EmptyStateMessage, {
|
|
6
7
|
children: /*#__PURE__*/ jsx(EmptyStateDescription, {
|
|
7
8
|
children: description
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
-
import type { FC, HTMLAttributes } from 'react';
|
|
2
|
-
|
|
1
|
+
import type { FC, HTMLAttributes, Ref } from 'react';
|
|
2
|
+
import type { VariantProps } from 'class-variance-authority';
|
|
3
|
+
import { type TestableProps } from '../../utils/testId';
|
|
4
|
+
import { selectFooterVariants } from './classes';
|
|
5
|
+
export type SelectFooterProps = Omit<HTMLAttributes<HTMLDivElement>, 'className'> & VariantProps<typeof selectFooterVariants> & TestableProps & {
|
|
6
|
+
ref?: Ref<HTMLDivElement>;
|
|
7
|
+
};
|
|
3
8
|
export declare const SelectFooter: FC<SelectFooterProps>;
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
2
|
import { cn } from "../../utils/cn.js";
|
|
3
3
|
import { useTestId } from "../../utils/testId.js";
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
import { selectFooterVariants } from "./classes.js";
|
|
5
|
+
const SelectFooter = ({ variant = 'default', 'data-testid': testIdProp, ...props })=>{
|
|
6
|
+
const testId = useTestId('footer', testIdProp);
|
|
6
7
|
return /*#__PURE__*/ jsx("div", {
|
|
7
8
|
...props,
|
|
8
9
|
"data-testid": testId,
|
|
9
|
-
className: cn(
|
|
10
|
+
className: cn(selectFooterVariants({
|
|
11
|
+
variant
|
|
12
|
+
}))
|
|
10
13
|
});
|
|
11
14
|
};
|
|
12
15
|
SelectFooter.displayName = 'SelectFooter';
|
|
@@ -1,2 +1,8 @@
|
|
|
1
|
-
import type { FC,
|
|
2
|
-
|
|
1
|
+
import type { FC, Ref } from 'react';
|
|
2
|
+
import { Select as ArkUiSelect } from '@ark-ui/react/select';
|
|
3
|
+
import { type TestableProps } from '../../utils/testId';
|
|
4
|
+
type SelectGroupProps = Omit<ArkUiSelect.ItemGroupProps, 'className'> & TestableProps & {
|
|
5
|
+
ref?: Ref<HTMLDivElement>;
|
|
6
|
+
};
|
|
7
|
+
export declare const SelectGroup: FC<SelectGroupProps>;
|
|
8
|
+
export {};
|
|
@@ -2,9 +2,10 @@ import { jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { Select } from "@ark-ui/react/select";
|
|
3
3
|
import { cn } from "../../utils/cn.js";
|
|
4
4
|
import { useTestId } from "../../utils/testId.js";
|
|
5
|
-
const SelectGroup = ({ children })=>{
|
|
6
|
-
const testId = useTestId('group');
|
|
5
|
+
const SelectGroup = ({ children, 'data-testid': testIdProp, ...props })=>{
|
|
6
|
+
const testId = useTestId('group', testIdProp);
|
|
7
7
|
return /*#__PURE__*/ jsx(Select.ItemGroup, {
|
|
8
|
+
...props,
|
|
8
9
|
"data-testid": testId,
|
|
9
10
|
className: cn('flex flex-col gap-1'),
|
|
10
11
|
children: children
|