@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.
Files changed (75) hide show
  1. package/dist/components/FilterDropdown/FilterDropdown.d.ts +58 -0
  2. package/dist/components/FilterDropdown/FilterDropdown.js +168 -0
  3. package/dist/components/FilterDropdown/FilterDropdownAllOption.d.ts +14 -0
  4. package/dist/components/FilterDropdown/FilterDropdownAllOption.js +25 -0
  5. package/dist/components/FilterDropdown/FilterDropdownClear.d.ts +12 -0
  6. package/dist/components/FilterDropdown/FilterDropdownClear.js +33 -0
  7. package/dist/components/FilterDropdown/FilterDropdownContent.d.ts +13 -0
  8. package/dist/components/FilterDropdown/FilterDropdownContent.js +57 -0
  9. package/dist/components/FilterDropdown/FilterDropdownContext.d.ts +60 -0
  10. package/dist/components/FilterDropdown/FilterDropdownContext.js +21 -0
  11. package/dist/components/FilterDropdown/FilterDropdownEmpty.d.ts +9 -0
  12. package/dist/components/FilterDropdown/FilterDropdownEmpty.js +21 -0
  13. package/dist/components/FilterDropdown/FilterDropdownFooter.d.ts +9 -0
  14. package/dist/components/FilterDropdown/FilterDropdownFooter.js +19 -0
  15. package/dist/components/FilterDropdown/FilterDropdownFooterClear.d.ts +9 -0
  16. package/dist/components/FilterDropdown/FilterDropdownFooterClear.js +40 -0
  17. package/dist/components/FilterDropdown/FilterDropdownGroup.d.ts +5 -0
  18. package/dist/components/FilterDropdown/FilterDropdownGroup.js +8 -0
  19. package/dist/components/FilterDropdown/FilterDropdownGroupLabel.d.ts +4 -0
  20. package/dist/components/FilterDropdown/FilterDropdownGroupLabel.js +8 -0
  21. package/dist/components/FilterDropdown/FilterDropdownOption.d.ts +15 -0
  22. package/dist/components/FilterDropdown/FilterDropdownOption.js +32 -0
  23. package/dist/components/FilterDropdown/FilterDropdownSearch.d.ts +12 -0
  24. package/dist/components/FilterDropdown/FilterDropdownSearch.js +38 -0
  25. package/dist/components/FilterDropdown/FilterDropdownSelected.d.ts +16 -0
  26. package/dist/components/FilterDropdown/FilterDropdownSelected.js +38 -0
  27. package/dist/components/FilterDropdown/FilterDropdownTrigger.d.ts +16 -0
  28. package/dist/components/FilterDropdown/FilterDropdownTrigger.js +139 -0
  29. package/dist/components/FilterDropdown/classes.d.ts +16 -0
  30. package/dist/components/FilterDropdown/classes.js +43 -0
  31. package/dist/components/FilterDropdown/index.d.ts +15 -0
  32. package/dist/components/FilterDropdown/index.js +15 -0
  33. package/dist/components/FilterDropdown/lib/index.d.ts +1 -0
  34. package/dist/components/FilterDropdown/lib/index.js +1 -0
  35. package/dist/components/FilterDropdown/lib/values.d.ts +59 -0
  36. package/dist/components/FilterDropdown/lib/values.js +58 -0
  37. package/dist/components/Select/Select.d.ts +1 -1
  38. package/dist/components/Select/SelectContent.d.ts +2 -1
  39. package/dist/components/Select/SelectContent.js +3 -2
  40. package/dist/components/Select/SelectEmptyState.d.ts +1 -0
  41. package/dist/components/Select/SelectEmptyState.js +2 -1
  42. package/dist/components/Select/SelectFooter.d.ts +7 -2
  43. package/dist/components/Select/SelectFooter.js +6 -3
  44. package/dist/components/Select/SelectGroup.d.ts +8 -2
  45. package/dist/components/Select/SelectGroup.js +3 -2
  46. package/dist/components/Select/SelectGroupLabel.d.ts +5 -2
  47. package/dist/components/Select/SelectGroupLabel.js +2 -2
  48. package/dist/components/Select/SelectOption.js +1 -1
  49. package/dist/components/Select/SelectOptionHint.d.ts +11 -0
  50. package/dist/components/Select/SelectOptionHint.js +15 -0
  51. package/dist/components/Select/SelectPositioner.d.ts +13 -3
  52. package/dist/components/Select/SelectPositioner.js +2 -1
  53. package/dist/components/Select/SelectSearchInput.d.ts +5 -2
  54. package/dist/components/Select/SelectSearchInput.js +11 -1
  55. package/dist/components/Select/classes.d.ts +3 -0
  56. package/dist/components/Select/classes.js +13 -0
  57. package/dist/components/Select/index.d.ts +4 -2
  58. package/dist/components/Select/index.js +2 -0
  59. package/dist/components/Table/TableBody/TableBodyVirtualizedCore.js +1 -1
  60. package/dist/components/Table/TableBody/TableBodyVirtualizedWindow.js +9 -25
  61. package/dist/components/Table/TableInner/TableInnerWindow.js +0 -1
  62. package/dist/components/Table/hooks/infiniteScroll/useInfiniteScroll.d.ts +1 -1
  63. package/dist/components/Table/hooks/infiniteScroll/usePrependScrollAnchor.d.ts +0 -1
  64. package/dist/components/Table/hooks/infiniteScroll/usePrependScrollAnchor.js +10 -12
  65. package/dist/components/Table/hooks/infiniteScroll/useScrollEdge.d.ts +1 -4
  66. package/dist/components/Table/hooks/infiniteScroll/useScrollEdge.js +17 -4
  67. package/dist/components/Table/lib/index.d.ts +0 -1
  68. package/dist/components/Table/lib/index.js +0 -1
  69. package/dist/components/Table/types.d.ts +1 -4
  70. package/dist/index.d.ts +2 -1
  71. package/dist/index.js +2 -1
  72. package/dist/metadata/components.json +6160 -983
  73. package/package.json +1 -1
  74. package/dist/components/Table/lib/scrollRoot.d.ts +0 -18
  75. 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 SelectContentProps = Omit<ArkUiSelect.ContentProps, 'className'>;
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,5 +1,6 @@
1
1
  import type { FC, ReactNode } from 'react';
2
2
  export interface SelectEmptyStateProps {
3
3
  description?: ReactNode;
4
+ className?: string;
4
5
  }
5
6
  export declare const SelectEmptyState: FC<SelectEmptyStateProps>;
@@ -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
- export type SelectFooterProps = Omit<HTMLAttributes<HTMLDivElement>, 'className'>;
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
- const SelectFooter = (props)=>{
5
- const testId = useTestId('footer');
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('bg-component-outline-button-bg py-8 px-16 shrink-0 border-t border-border-primary')
10
+ className: cn(selectFooterVariants({
11
+ variant
12
+ }))
10
13
  });
11
14
  };
12
15
  SelectFooter.displayName = 'SelectFooter';
@@ -1,2 +1,8 @@
1
- import type { FC, PropsWithChildren } from 'react';
2
- export declare const SelectGroup: FC<PropsWithChildren>;
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