@wallarm-org/design-system 0.29.2 → 0.30.0-rc-feature-AS-884.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.
Files changed (26) hide show
  1. package/dist/components/Selection/Selection.d.ts +18 -0
  2. package/dist/components/Selection/Selection.js +99 -0
  3. package/dist/components/Selection/SelectionAll.d.ts +6 -0
  4. package/dist/components/Selection/SelectionAll.js +20 -0
  5. package/dist/components/Selection/SelectionBulkBar/SelectionBulkBar.d.ts +8 -0
  6. package/dist/components/Selection/SelectionBulkBar/SelectionBulkBar.js +37 -0
  7. package/dist/components/Selection/SelectionBulkBar/SelectionBulkBarSummary.d.ts +2 -0
  8. package/dist/components/Selection/SelectionBulkBar/SelectionBulkBarSummary.js +52 -0
  9. package/dist/components/Selection/SelectionBulkBar/index.d.ts +1 -0
  10. package/dist/components/Selection/SelectionBulkBar/index.js +2 -0
  11. package/dist/components/Selection/SelectionContext.d.ts +14 -0
  12. package/dist/components/Selection/SelectionContext.js +3 -0
  13. package/dist/components/Selection/SelectionItem.d.ts +10 -0
  14. package/dist/components/Selection/SelectionItem.js +40 -0
  15. package/dist/components/Selection/classes.d.ts +1 -0
  16. package/dist/components/Selection/classes.js +3 -0
  17. package/dist/components/Selection/index.d.ts +4 -0
  18. package/dist/components/Selection/index.js +5 -0
  19. package/dist/components/Selection/useSelectionContext.d.ts +2 -0
  20. package/dist/components/Selection/useSelectionContext.js +8 -0
  21. package/dist/components/Selection/useSelectionState.d.ts +23 -0
  22. package/dist/components/Selection/useSelectionState.js +99 -0
  23. package/dist/index.d.ts +1 -0
  24. package/dist/index.js +2 -1
  25. package/dist/metadata/components.json +89 -2
  26. package/package.json +1 -1
@@ -0,0 +1,18 @@
1
+ import { type ReactNode } from 'react';
2
+ import { type TestableProps } from '../../utils/testId';
3
+ export interface SelectionProps<T> extends TestableProps {
4
+ /** Source array — used for select-all and shift-click range ordering. */
5
+ items: T[];
6
+ /** Stable id extractor for items. */
7
+ getItemId: (item: T) => string;
8
+ /** Controlled selection state — array of selected item ids. */
9
+ value: string[];
10
+ /** Called with the next ordered array of selected ids. */
11
+ onChange: (ids: string[]) => void;
12
+ className?: string;
13
+ children?: ReactNode;
14
+ }
15
+ export declare const Selection: {
16
+ <T>({ items, getItemId, value, onChange, className, "data-testid": testId, children, }: SelectionProps<T>): import("react/jsx-runtime").JSX.Element;
17
+ displayName: string;
18
+ };
@@ -0,0 +1,99 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { useCallback, useMemo, useRef, useState } from "react";
3
+ import { Popover } from "@ark-ui/react/popover";
4
+ import { useIsKeyPressed } from "../../hooks/useIsKeyPressed.js";
5
+ import { cn } from "../../utils/cn.js";
6
+ import { TestIdProvider } from "../../utils/testId.js";
7
+ import { SelectionContext } from "./SelectionContext.js";
8
+ import { useSelectionState } from "./useSelectionState.js";
9
+ const SELECTION_BULKBAR_HEIGHT = 52;
10
+ const SELECTION_BULKBAR_OFFSET = 32;
11
+ const SELECTION_BULKBAR_POSITIONING = Object.freeze({
12
+ strategy: 'absolute',
13
+ placement: 'bottom',
14
+ gutter: 32,
15
+ overlap: true,
16
+ flip: false,
17
+ offset: {
18
+ mainAxis: -(SELECTION_BULKBAR_HEIGHT + SELECTION_BULKBAR_OFFSET)
19
+ }
20
+ });
21
+ const Selection = ({ items, getItemId, value, onChange, className, 'data-testid': testId, children })=>{
22
+ const disabledMapRef = useRef(new Map());
23
+ const [disabledTick, setDisabledTick] = useState(0);
24
+ const disabledIds = useMemo(()=>{
25
+ const set = new Set();
26
+ for (const [id, isDisabled] of disabledMapRef.current)if (isDisabled) set.add(id);
27
+ return set;
28
+ }, [
29
+ disabledTick
30
+ ]);
31
+ const registerDisabled = useCallback((id, disabled)=>{
32
+ disabledMapRef.current.set(id, disabled);
33
+ setDisabledTick((t)=>t + 1);
34
+ return ()=>{
35
+ disabledMapRef.current.delete(id);
36
+ setDisabledTick((t)=>t + 1);
37
+ };
38
+ }, []);
39
+ const shiftKeyRef = useIsKeyPressed('Shift');
40
+ const state = useSelectionState({
41
+ items,
42
+ getItemId,
43
+ value,
44
+ onChange,
45
+ disabledIds
46
+ });
47
+ const toggleItem = useCallback((id, opts)=>{
48
+ const shiftKey = opts?.shiftKey ?? shiftKeyRef.current;
49
+ state.toggleItem(id, {
50
+ shiftKey
51
+ });
52
+ }, [
53
+ shiftKeyRef,
54
+ state
55
+ ]);
56
+ const ctxValue = useMemo(()=>({
57
+ itemIds: state.itemIds,
58
+ enabledItemIds: state.enabledItemIds,
59
+ selectedIds: state.selectedIds,
60
+ isSelected: state.isSelected,
61
+ isAllSelected: state.isAllSelected,
62
+ isIndeterminate: state.isIndeterminate,
63
+ toggleItem,
64
+ selectAll: state.selectAll,
65
+ clear: state.clear,
66
+ registerDisabled
67
+ }), [
68
+ state.itemIds,
69
+ state.enabledItemIds,
70
+ state.selectedIds,
71
+ state.isSelected,
72
+ state.isAllSelected,
73
+ state.isIndeterminate,
74
+ state.selectAll,
75
+ state.clear,
76
+ toggleItem,
77
+ registerDisabled
78
+ ]);
79
+ return /*#__PURE__*/ jsx(SelectionContext.Provider, {
80
+ value: ctxValue,
81
+ children: /*#__PURE__*/ jsx(TestIdProvider, {
82
+ value: testId,
83
+ children: /*#__PURE__*/ jsx(Popover.Root, {
84
+ open: value.length > 0,
85
+ closeOnInteractOutside: false,
86
+ portalled: false,
87
+ positioning: SELECTION_BULKBAR_POSITIONING,
88
+ children: /*#__PURE__*/ jsx(Popover.Anchor, {
89
+ "data-slot": "selection",
90
+ "data-testid": testId,
91
+ className: cn('relative outline-none', className),
92
+ children: children
93
+ })
94
+ })
95
+ })
96
+ });
97
+ };
98
+ Selection.displayName = 'Selection';
99
+ export { Selection };
@@ -0,0 +1,6 @@
1
+ import type { FC } from 'react';
2
+ export interface SelectionAllProps {
3
+ 'data-testid'?: string;
4
+ 'aria-label'?: string;
5
+ }
6
+ export declare const SelectionAll: FC<SelectionAllProps>;
@@ -0,0 +1,20 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { useTestId } from "../../utils/testId.js";
3
+ import { Checkbox, CheckboxIndicator } from "../Checkbox/index.js";
4
+ import { useSelectionContext } from "./useSelectionContext.js";
5
+ const SelectionAll = ({ 'data-testid': testIdProp, 'aria-label': ariaLabel = 'Select all' })=>{
6
+ const { isAllSelected, isIndeterminate, enabledItemIds, selectAll, clear } = useSelectionContext();
7
+ const fallbackTestId = useTestId('all');
8
+ const testId = testIdProp ?? fallbackTestId;
9
+ return /*#__PURE__*/ jsx(Checkbox, {
10
+ "data-testid": testId,
11
+ "data-slot": "selection-all",
12
+ "aria-label": ariaLabel,
13
+ checked: isIndeterminate ? 'indeterminate' : isAllSelected,
14
+ disabled: 0 === enabledItemIds.length,
15
+ onCheckedChange: ()=>isAllSelected ? clear() : selectAll(),
16
+ children: /*#__PURE__*/ jsx(CheckboxIndicator, {})
17
+ });
18
+ };
19
+ SelectionAll.displayName = 'SelectionAll';
20
+ export { SelectionAll };
@@ -0,0 +1,8 @@
1
+ import type { FC, ReactNode } from 'react';
2
+ export interface SelectionBulkBarProps {
3
+ /** Override the toolbar accessible name. Defaults to "Bulk actions". */
4
+ 'aria-label'?: string;
5
+ 'data-testid'?: string;
6
+ children?: ReactNode;
7
+ }
8
+ export declare const SelectionBulkBar: FC<SelectionBulkBarProps>;
@@ -0,0 +1,37 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { Popover } from "@ark-ui/react/popover";
3
+ import { Portal } from "@ark-ui/react/portal";
4
+ import { cn } from "../../../utils/cn.js";
5
+ import { useTestId } from "../../../utils/testId.js";
6
+ import { HStack } from "../../Stack/index.js";
7
+ import { SelectionBulkBarSummary } from "./SelectionBulkBarSummary.js";
8
+ const SelectionBulkBar = ({ 'aria-label': ariaLabel = 'Bulk actions', 'data-testid': testIdProp, children })=>{
9
+ const fallbackTestId = useTestId('bulk-bar');
10
+ const testId = testIdProp ?? fallbackTestId;
11
+ return /*#__PURE__*/ jsx(Portal, {
12
+ children: /*#__PURE__*/ jsx(Popover.Positioner, {
13
+ className: "z-50",
14
+ children: /*#__PURE__*/ jsx(Popover.Content, {
15
+ role: "toolbar",
16
+ "aria-label": ariaLabel,
17
+ "data-slot": "selection-bulk-bar",
18
+ "data-testid": testId,
19
+ className: cn('bg-component-toast-bg rounded-16 shadow-lg', 'pl-12 pr-8 py-8', 'data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:slide-in-from-bottom data-[state=open]:duration-300', 'data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-bottom data-[state=closed]:duration-150'),
20
+ children: /*#__PURE__*/ jsxs(HStack, {
21
+ gap: 40,
22
+ align: "center",
23
+ children: [
24
+ /*#__PURE__*/ jsx(SelectionBulkBarSummary, {}),
25
+ /*#__PURE__*/ jsx(HStack, {
26
+ gap: 8,
27
+ align: "center",
28
+ children: children
29
+ })
30
+ ]
31
+ })
32
+ })
33
+ })
34
+ });
35
+ };
36
+ SelectionBulkBar.displayName = 'SelectionBulkBar';
37
+ export { SelectionBulkBar };
@@ -0,0 +1,2 @@
1
+ import type { FC } from 'react';
2
+ export declare const SelectionBulkBarSummary: FC;
@@ -0,0 +1,52 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useTestId } from "../../../utils/testId.js";
3
+ import { Link } from "../../Link/index.js";
4
+ import { HStack } from "../../Stack/index.js";
5
+ import { Text } from "../../Text/index.js";
6
+ import { useSelectionContext } from "../useSelectionContext.js";
7
+ const SelectionBulkBarSummary = ()=>{
8
+ const { isAllSelected, selectedIds, selectAll, clear } = useSelectionContext();
9
+ const testId = useTestId('bulk-bar-summary');
10
+ const count = selectedIds.size;
11
+ return /*#__PURE__*/ jsxs("div", {
12
+ "data-testid": testId,
13
+ className: "flex items-center gap-16 p-8",
14
+ children: [
15
+ /*#__PURE__*/ jsxs(Text, {
16
+ size: "sm",
17
+ color: "primary-alt",
18
+ weight: "medium",
19
+ children: [
20
+ count,
21
+ " selected"
22
+ ]
23
+ }),
24
+ /*#__PURE__*/ jsxs(HStack, {
25
+ gap: 6,
26
+ children: [
27
+ /*#__PURE__*/ jsx(Link, {
28
+ type: isAllSelected ? 'muted' : 'alt',
29
+ size: "md",
30
+ onClick: selectAll,
31
+ disabled: isAllSelected,
32
+ children: "Select all"
33
+ }),
34
+ /*#__PURE__*/ jsx(Text, {
35
+ size: "sm",
36
+ color: "tertiary-alt",
37
+ weight: "medium",
38
+ children: "\xb7"
39
+ }),
40
+ /*#__PURE__*/ jsx(Link, {
41
+ type: "alt",
42
+ size: "md",
43
+ onClick: clear,
44
+ children: "Clear"
45
+ })
46
+ ]
47
+ })
48
+ ]
49
+ });
50
+ };
51
+ SelectionBulkBarSummary.displayName = 'SelectionBulkBarSummary';
52
+ export { SelectionBulkBarSummary };
@@ -0,0 +1 @@
1
+ export { SelectionBulkBar, type SelectionBulkBarProps } from './SelectionBulkBar';
@@ -0,0 +1,2 @@
1
+ import { SelectionBulkBar } from "./SelectionBulkBar.js";
2
+ export { SelectionBulkBar };
@@ -0,0 +1,14 @@
1
+ import type { ToggleItemOptions } from './useSelectionState';
2
+ export interface SelectionContextValue {
3
+ itemIds: string[];
4
+ enabledItemIds: string[];
5
+ selectedIds: Set<string>;
6
+ isSelected: (id: string) => boolean;
7
+ isAllSelected: boolean;
8
+ isIndeterminate: boolean;
9
+ toggleItem: (id: string, opts?: ToggleItemOptions) => void;
10
+ selectAll: () => void;
11
+ clear: () => void;
12
+ registerDisabled: (id: string, disabled: boolean) => () => void;
13
+ }
14
+ export declare const SelectionContext: import("react").Context<SelectionContextValue | null>;
@@ -0,0 +1,3 @@
1
+ import { createContext } from "react";
2
+ const SelectionContext = createContext(null);
3
+ export { SelectionContext };
@@ -0,0 +1,10 @@
1
+ import { type FC, type ReactNode } from 'react';
2
+ export interface SelectionItemProps {
3
+ /** Item id — must match an id present in the `<Selection>` `items` prop. */
4
+ itemId: string;
5
+ /** When true, the checkbox is disabled and the item is excluded from select-all and ranges. */
6
+ disabled?: boolean;
7
+ className?: string;
8
+ children?: ReactNode;
9
+ }
10
+ export declare const SelectionItem: FC<SelectionItemProps>;
@@ -0,0 +1,40 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useEffect } from "react";
3
+ import { cn } from "../../utils/cn.js";
4
+ import { Checkbox, CheckboxIndicator } from "../Checkbox/index.js";
5
+ import { selectionItemVariants } from "./classes.js";
6
+ import { useSelectionContext } from "./useSelectionContext.js";
7
+ const SelectionItem = ({ itemId, disabled = false, className, children })=>{
8
+ const { isSelected, toggleItem, registerDisabled } = useSelectionContext();
9
+ const selected = isSelected(itemId);
10
+ useEffect(()=>registerDisabled(itemId, disabled), [
11
+ itemId,
12
+ disabled,
13
+ registerDisabled
14
+ ]);
15
+ const handleClickCapture = (e)=>{
16
+ if (disabled || !e.shiftKey) return;
17
+ e.preventDefault();
18
+ e.stopPropagation();
19
+ toggleItem(itemId, {
20
+ shiftKey: true
21
+ });
22
+ };
23
+ return /*#__PURE__*/ jsxs("div", {
24
+ "data-slot": "selection-item",
25
+ "data-selected": selected || void 0,
26
+ className: cn(selectionItemVariants(), className),
27
+ onClickCapture: handleClickCapture,
28
+ children: [
29
+ /*#__PURE__*/ jsx(Checkbox, {
30
+ checked: selected,
31
+ disabled: disabled,
32
+ onCheckedChange: ()=>toggleItem(itemId),
33
+ children: /*#__PURE__*/ jsx(CheckboxIndicator, {})
34
+ }),
35
+ children
36
+ ]
37
+ });
38
+ };
39
+ SelectionItem.displayName = 'SelectionItem';
40
+ export { SelectionItem };
@@ -0,0 +1 @@
1
+ export declare const selectionItemVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
@@ -0,0 +1,3 @@
1
+ import { cva } from "class-variance-authority";
2
+ const selectionItemVariants = cva('flex items-start gap-12');
3
+ export { selectionItemVariants };
@@ -0,0 +1,4 @@
1
+ export { Selection, type SelectionProps } from './Selection';
2
+ export { SelectionAll, type SelectionAllProps } from './SelectionAll';
3
+ export { SelectionBulkBar, type SelectionBulkBarProps, } from './SelectionBulkBar';
4
+ export { SelectionItem, type SelectionItemProps } from './SelectionItem';
@@ -0,0 +1,5 @@
1
+ import { Selection } from "./Selection.js";
2
+ import { SelectionAll } from "./SelectionAll.js";
3
+ import { SelectionBulkBar } from "./SelectionBulkBar/index.js";
4
+ import { SelectionItem } from "./SelectionItem.js";
5
+ export { Selection, SelectionAll, SelectionBulkBar, SelectionItem };
@@ -0,0 +1,2 @@
1
+ import { type SelectionContextValue } from './SelectionContext';
2
+ export declare const useSelectionContext: () => SelectionContextValue;
@@ -0,0 +1,8 @@
1
+ import { useContext } from "react";
2
+ import { SelectionContext } from "./SelectionContext.js";
3
+ const useSelectionContext = ()=>{
4
+ const ctx = useContext(SelectionContext);
5
+ if (!ctx) throw new Error('Selection sub-components (SelectionItem, SelectionAll, SelectionBulkBar) must be used inside <Selection>.');
6
+ return ctx;
7
+ };
8
+ export { useSelectionContext };
@@ -0,0 +1,23 @@
1
+ export interface UseSelectionStateParams<T> {
2
+ items: T[];
3
+ getItemId: (item: T) => string;
4
+ value: string[];
5
+ onChange: (ids: string[]) => void;
6
+ /** Set of itemIds that cannot be toggled and are excluded from selectAll. */
7
+ disabledIds?: Set<string>;
8
+ }
9
+ export interface ToggleItemOptions {
10
+ shiftKey?: boolean;
11
+ }
12
+ export interface UseSelectionStateResult {
13
+ itemIds: string[];
14
+ enabledItemIds: string[];
15
+ selectedIds: Set<string>;
16
+ isSelected: (id: string) => boolean;
17
+ isAllSelected: boolean;
18
+ isIndeterminate: boolean;
19
+ toggleItem: (id: string, opts?: ToggleItemOptions) => void;
20
+ selectAll: () => void;
21
+ clear: () => void;
22
+ }
23
+ export declare const useSelectionState: <T>({ items, getItemId, value, onChange, disabledIds, }: UseSelectionStateParams<T>) => UseSelectionStateResult;
@@ -0,0 +1,99 @@
1
+ import { useCallback, useMemo, useRef } from "react";
2
+ const EMPTY_DISABLED = new Set();
3
+ const useSelectionState = ({ items, getItemId, value, onChange, disabledIds })=>{
4
+ const itemIds = useMemo(()=>items.map(getItemId), [
5
+ items,
6
+ getItemId
7
+ ]);
8
+ const itemIdSet = useMemo(()=>new Set(itemIds), [
9
+ itemIds
10
+ ]);
11
+ const disabled = disabledIds ?? EMPTY_DISABLED;
12
+ const enabledItemIds = useMemo(()=>itemIds.filter((id)=>!disabled.has(id)), [
13
+ itemIds,
14
+ disabled
15
+ ]);
16
+ const selectedIds = useMemo(()=>new Set(value), [
17
+ value
18
+ ]);
19
+ const lastToggledIdRef = useRef(null);
20
+ const isSelected = useCallback((id)=>selectedIds.has(id), [
21
+ selectedIds
22
+ ]);
23
+ const enabledSelectedCount = useMemo(()=>{
24
+ let n = 0;
25
+ for (const id of enabledItemIds)if (selectedIds.has(id)) n++;
26
+ return n;
27
+ }, [
28
+ enabledItemIds,
29
+ selectedIds
30
+ ]);
31
+ const isAllSelected = enabledItemIds.length > 0 && enabledSelectedCount === enabledItemIds.length;
32
+ const isIndeterminate = enabledSelectedCount > 0 && enabledSelectedCount < enabledItemIds.length;
33
+ const emitOrdered = useCallback((ids)=>{
34
+ const next = [];
35
+ for (const id of itemIds)if (ids.has(id)) next.push(id);
36
+ for (const id of value)if (!itemIdSet.has(id) && ids.has(id)) next.push(id);
37
+ onChange(next);
38
+ }, [
39
+ itemIds,
40
+ itemIdSet,
41
+ value,
42
+ onChange
43
+ ]);
44
+ const toggleItem = useCallback((id, opts)=>{
45
+ if (!itemIdSet.has(id)) return;
46
+ if (disabled.has(id)) return;
47
+ const lastId = lastToggledIdRef.current;
48
+ const wantsRange = !!opts?.shiftKey && null !== lastId && lastId !== id;
49
+ if (wantsRange) {
50
+ const fromIdx = itemIds.indexOf(lastId);
51
+ const toIdx = itemIds.indexOf(id);
52
+ if (-1 !== fromIdx && -1 !== toIdx) {
53
+ const start = Math.min(fromIdx, toIdx);
54
+ const end = Math.max(fromIdx, toIdx);
55
+ const selecting = !selectedIds.has(id);
56
+ const next = new Set(selectedIds);
57
+ for (const rangeId of itemIds.slice(start, end + 1))if (!disabled.has(rangeId)) if (selecting) next.add(rangeId);
58
+ else next.delete(rangeId);
59
+ emitOrdered(next);
60
+ lastToggledIdRef.current = id;
61
+ return;
62
+ }
63
+ }
64
+ const next = new Set(selectedIds);
65
+ if (next.has(id)) next.delete(id);
66
+ else next.add(id);
67
+ emitOrdered(next);
68
+ lastToggledIdRef.current = id;
69
+ }, [
70
+ itemIdSet,
71
+ disabled,
72
+ itemIds,
73
+ selectedIds,
74
+ emitOrdered
75
+ ]);
76
+ const selectAll = useCallback(()=>{
77
+ emitOrdered(new Set(enabledItemIds));
78
+ }, [
79
+ enabledItemIds,
80
+ emitOrdered
81
+ ]);
82
+ const clear = useCallback(()=>{
83
+ onChange([]);
84
+ }, [
85
+ onChange
86
+ ]);
87
+ return {
88
+ itemIds,
89
+ enabledItemIds,
90
+ selectedIds,
91
+ isSelected,
92
+ isAllSelected,
93
+ isIndeterminate,
94
+ toggleItem,
95
+ selectAll,
96
+ clear
97
+ };
98
+ };
99
+ export { useSelectionState };
package/dist/index.d.ts CHANGED
@@ -44,6 +44,7 @@ export { ScrollArea, ScrollAreaContent, type ScrollAreaContentProps, ScrollAreaC
44
44
  export { SegmentedControl, SegmentedControlButton, type SegmentedControlButtonProps, SegmentedControlItem, type SegmentedControlItemProps, type SegmentedControlProps, SegmentedControlSeparator, type SegmentedControlSeparatorProps, } from './components/SegmentedControl';
45
45
  export { SegmentedTabs, SegmentedTabsButton, SegmentedTabsContent, SegmentedTabsList, SegmentedTabsSeparator, SegmentedTabsTrigger, SegmentedTabsTriggerButton, } from './components/SegmentedTabs';
46
46
  export { Select, SelectButton, SelectClearTrigger, SelectContent, SelectFooter, SelectGroup, SelectGroupLabel, SelectHeader, SelectInput, SelectOption, SelectOptionDescription, SelectOptionIndicator, SelectOptionText, SelectPositioner, SelectSearchInput, SelectSeparator, } from './components/Select';
47
+ export { Selection, SelectionAll, type SelectionAllProps, SelectionBulkBar, type SelectionBulkBarProps, SelectionItem, type SelectionItemProps, type SelectionProps, } from './components/Selection';
47
48
  export { Separator, type SeparatorProps } from './components/Separator';
48
49
  export { Skeleton, type SkeletonProps } from './components/Skeleton';
49
50
  export { SplitButton, type SplitButtonProps } from './components/SplitButton';
package/dist/index.js CHANGED
@@ -33,6 +33,7 @@ import { ScrollArea, ScrollAreaContent, ScrollAreaCorner, ScrollAreaScrollbar, S
33
33
  import { SegmentedControl, SegmentedControlButton, SegmentedControlItem, SegmentedControlSeparator } from "./components/SegmentedControl/index.js";
34
34
  import { SegmentedTabs, SegmentedTabsButton, SegmentedTabsContent, SegmentedTabsList, SegmentedTabsSeparator, SegmentedTabsTrigger, SegmentedTabsTriggerButton } from "./components/SegmentedTabs/index.js";
35
35
  import { Select, SelectButton, SelectClearTrigger, SelectContent, SelectFooter, SelectGroup, SelectGroupLabel, SelectHeader, SelectInput, SelectOption, SelectOptionDescription, SelectOptionIndicator, SelectOptionText, SelectPositioner, SelectSearchInput, SelectSeparator } from "./components/Select/index.js";
36
+ import { Selection, SelectionAll, SelectionBulkBar, SelectionItem } from "./components/Selection/index.js";
36
37
  import { Separator } from "./components/Separator/index.js";
37
38
  import { Skeleton } from "./components/Skeleton/index.js";
38
39
  import { SplitButton } from "./components/SplitButton/index.js";
@@ -50,4 +51,4 @@ import { ToggleButton } from "./components/ToggleButton/index.js";
50
51
  import { Tooltip, TooltipContent, TooltipTrigger } from "./components/Tooltip/index.js";
51
52
  import { Tour, beaconStepEffect, useTour, waitForStepEvent } from "./components/Tour/index.js";
52
53
  import { TestIdProvider, useTestId } from "./utils/testId.js";
53
- export { Alert, AlertClose, AlertContent, AlertControls, AlertDescription, AlertIcon, AlertTitle, Attribute, AttributeActions, AttributeActionsContent, AttributeActionsItem, AttributeActionsTarget, AttributeLabel, AttributeLabelDescription, AttributeLabelInfo, AttributeValue, Badge, Button, Calendar, CalendarApplyButton, CalendarBody, CalendarContent, CalendarDate, CalendarDateTime, CalendarDayName, CalendarFooter, CalendarFooterControls, CalendarGrid, CalendarGrids, CalendarHeader, CalendarInputHeader, CalendarKeyboardHints, CalendarPresetItem, CalendarPresets, CalendarProvider, CalendarResetButton, CalendarTrigger, Card, CardContent, CardFooter, CardHeader, CardTitle, Checkbox, CheckboxDescription, CheckboxGroup, CheckboxIndicator, CheckboxLabel, Code, Country, CountryFlag, CountryName, DAY_NAMES, DEFAULT_RANGE_PRESETS, DEFAULT_SINGLE_PRESETS, DateFormatProvider, DateInput, DateRangeEndValue, DateRangeInput, DateRangeProvider, DateRangeSeparator, DateRangeStartValue, Drawer, DrawerBody, DrawerClose, DrawerContent, DrawerFooter, DrawerFooterControls, DrawerHeader, DrawerPositioner, DrawerResizeHandle, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuContent, DropdownMenuContextTrigger, DropdownMenuFooter, DropdownMenuGroup, DropdownMenuInput, DropdownMenuItem, DropdownMenuItemContent, DropdownMenuItemDescription, DropdownMenuItemIcon, DropdownMenuItemText, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuTrigger, DropdownMenuTriggerItem, Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle, FilterInput, FilterInputChip, FilterInputFieldMenu, FilterInputOperatorMenu, Flex, FormatDateTime, HStack, Heading, Input, InputGroup, InputGroupAddon, InputGroupText, Ip, IpAddress, IpCountry, IpList, IpPort, IpProvider, Kbd, KbdGroup, Link, Loader, MONTH_NAMES, NumberInput, NumericBadge, OverflowTooltip, OverflowTooltipContent, Popover, PopoverContent, PopoverTrigger, Radio, RadioDescription, RadioGroup, RadioIndicator, RadioLabel, ScrollArea, ScrollAreaContent, ScrollAreaCorner, ScrollAreaScrollbar, ScrollAreaViewport, SegmentedControl, SegmentedControlButton, SegmentedControlItem, SegmentedControlSeparator, SegmentedTabs, SegmentedTabsButton, SegmentedTabsContent, SegmentedTabsList, SegmentedTabsSeparator, SegmentedTabsTrigger, SegmentedTabsTriggerButton, Select, SelectButton, SelectClearTrigger, SelectContent, SelectFooter, SelectGroup, SelectGroupLabel, SelectHeader, SelectInput, SelectOption, SelectOptionDescription, SelectOptionIndicator, SelectOptionText, SelectPositioner, SelectSearchInput, SelectSeparator, Separator, Skeleton, SplitButton, Stack, Switch, SwitchControl, SwitchDescription, SwitchLabel, Table, TableActionBar, TableEmptyState, TableSettingsMenu, Tabs, TabsButton, TabsContent, TabsLineActions, TabsList, TabsSeparator, TabsTrigger, Tag, TagClose, TestIdProvider, Text, Textarea, ThemeProvider, Time, TimeInput, Toast, ToastActions, Toaster, ToggleButton, Tooltip, TooltipContent, TooltipTrigger, Tour, VStack, ZonedDateTime, beaconStepEffect, cardVariants, createTableColumnHelper, datacenters, drawerContentVariants, drawerPositionerVariants, getLocalTimeZone, parseDate, parseDateTime, parseTime, parseZonedDateTime, proxyTypes, sourceLabels, toaster, today, useCalendarContext, useDateFormat, useDateRangeContext, useDrawerContext, useTestId, useTheme, useTour, waitForStepEvent };
54
+ export { Alert, AlertClose, AlertContent, AlertControls, AlertDescription, AlertIcon, AlertTitle, Attribute, AttributeActions, AttributeActionsContent, AttributeActionsItem, AttributeActionsTarget, AttributeLabel, AttributeLabelDescription, AttributeLabelInfo, AttributeValue, Badge, Button, Calendar, CalendarApplyButton, CalendarBody, CalendarContent, CalendarDate, CalendarDateTime, CalendarDayName, CalendarFooter, CalendarFooterControls, CalendarGrid, CalendarGrids, CalendarHeader, CalendarInputHeader, CalendarKeyboardHints, CalendarPresetItem, CalendarPresets, CalendarProvider, CalendarResetButton, CalendarTrigger, Card, CardContent, CardFooter, CardHeader, CardTitle, Checkbox, CheckboxDescription, CheckboxGroup, CheckboxIndicator, CheckboxLabel, Code, Country, CountryFlag, CountryName, DAY_NAMES, DEFAULT_RANGE_PRESETS, DEFAULT_SINGLE_PRESETS, DateFormatProvider, DateInput, DateRangeEndValue, DateRangeInput, DateRangeProvider, DateRangeSeparator, DateRangeStartValue, Drawer, DrawerBody, DrawerClose, DrawerContent, DrawerFooter, DrawerFooterControls, DrawerHeader, DrawerPositioner, DrawerResizeHandle, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuContent, DropdownMenuContextTrigger, DropdownMenuFooter, DropdownMenuGroup, DropdownMenuInput, DropdownMenuItem, DropdownMenuItemContent, DropdownMenuItemDescription, DropdownMenuItemIcon, DropdownMenuItemText, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuTrigger, DropdownMenuTriggerItem, Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle, FilterInput, FilterInputChip, FilterInputFieldMenu, FilterInputOperatorMenu, Flex, FormatDateTime, HStack, Heading, Input, InputGroup, InputGroupAddon, InputGroupText, Ip, IpAddress, IpCountry, IpList, IpPort, IpProvider, Kbd, KbdGroup, Link, Loader, MONTH_NAMES, NumberInput, NumericBadge, OverflowTooltip, OverflowTooltipContent, Popover, PopoverContent, PopoverTrigger, Radio, RadioDescription, RadioGroup, RadioIndicator, RadioLabel, ScrollArea, ScrollAreaContent, ScrollAreaCorner, ScrollAreaScrollbar, ScrollAreaViewport, SegmentedControl, SegmentedControlButton, SegmentedControlItem, SegmentedControlSeparator, SegmentedTabs, SegmentedTabsButton, SegmentedTabsContent, SegmentedTabsList, SegmentedTabsSeparator, SegmentedTabsTrigger, SegmentedTabsTriggerButton, Select, SelectButton, SelectClearTrigger, SelectContent, SelectFooter, SelectGroup, SelectGroupLabel, SelectHeader, SelectInput, SelectOption, SelectOptionDescription, SelectOptionIndicator, SelectOptionText, SelectPositioner, SelectSearchInput, SelectSeparator, Selection, SelectionAll, SelectionBulkBar, SelectionItem, Separator, Skeleton, SplitButton, Stack, Switch, SwitchControl, SwitchDescription, SwitchLabel, Table, TableActionBar, TableEmptyState, TableSettingsMenu, Tabs, TabsButton, TabsContent, TabsLineActions, TabsList, TabsSeparator, TabsTrigger, Tag, TagClose, TestIdProvider, Text, Textarea, ThemeProvider, Time, TimeInput, Toast, ToastActions, Toaster, ToggleButton, Tooltip, TooltipContent, TooltipTrigger, Tour, VStack, ZonedDateTime, beaconStepEffect, cardVariants, createTableColumnHelper, datacenters, drawerContentVariants, drawerPositionerVariants, getLocalTimeZone, parseDate, parseDateTime, parseTime, parseZonedDateTime, proxyTypes, sourceLabels, toaster, today, useCalendarContext, useDateFormat, useDateRangeContext, useDrawerContext, useTestId, useTheme, useTour, waitForStepEvent };
@@ -1,6 +1,6 @@
1
1
  {
2
- "version": "0.29.1",
3
- "generatedAt": "2026-04-27T09:32:45.403Z",
2
+ "version": "0.29.2",
3
+ "generatedAt": "2026-04-27T14:28:46.652Z",
4
4
  "components": [
5
5
  {
6
6
  "name": "Alert",
@@ -23958,6 +23958,93 @@
23958
23958
  }
23959
23959
  ]
23960
23960
  },
23961
+ {
23962
+ "name": "Selection",
23963
+ "importPath": "@wallarm-org/design-system/Selection",
23964
+ "props": [
23965
+ {
23966
+ "name": "items",
23967
+ "type": "T[]",
23968
+ "required": true,
23969
+ "description": "Source array — used for select-all and shift-click range ordering."
23970
+ },
23971
+ {
23972
+ "name": "getItemId",
23973
+ "type": "(item: T) => string",
23974
+ "required": true,
23975
+ "description": "Stable id extractor for items."
23976
+ },
23977
+ {
23978
+ "name": "value",
23979
+ "type": "string[]",
23980
+ "required": true,
23981
+ "description": "Controlled selection state — array of selected item ids."
23982
+ }
23983
+ ],
23984
+ "variants": [],
23985
+ "subComponents": [
23986
+ {
23987
+ "name": "SelectionAll",
23988
+ "props": []
23989
+ },
23990
+ {
23991
+ "name": "SelectionBulkBar",
23992
+ "props": []
23993
+ },
23994
+ {
23995
+ "name": "SelectionItem",
23996
+ "props": [
23997
+ {
23998
+ "name": "itemId",
23999
+ "type": "string",
24000
+ "required": true,
24001
+ "description": "Item id — must match an id present in the `<Selection>` `items` prop."
24002
+ },
24003
+ {
24004
+ "name": "disabled",
24005
+ "type": "boolean | undefined",
24006
+ "required": false,
24007
+ "description": "When true, the checkbox is disabled and the item is excluded from select-all and ranges.",
24008
+ "defaultValue": "false"
24009
+ }
24010
+ ]
24011
+ }
24012
+ ],
24013
+ "examples": [
24014
+ {
24015
+ "name": "Default",
24016
+ "code": "() => {\n const [selected, setSelected] = useState<string[]>([]);\n\n return (\n <Selection items={clusters} getItemId={c => c.id} value={selected} onChange={setSelected}>\n <VStack gap={12}>\n {clusters.map(c => (\n <SelectionItem key={c.id} itemId={c.id}>\n <ClusterCard cluster={c} />\n </SelectionItem>\n ))}\n </VStack>\n\n <SelectionBulkBar>\n <Button\n variant='ghost'\n color='neutral-alt'\n onClick={() => alert(`Duplicate ${selected.length}`)}\n >\n <Copy /> Duplicate\n </Button>\n <Button color='brand' onClick={() => alert(`Delete ${selected.length}`)}>\n <Trash2 /> Delete\n </Button>\n </SelectionBulkBar>\n </Selection>\n );\n}"
24017
+ },
24018
+ {
24019
+ "name": "WithSelectAll",
24020
+ "code": "() => {\n const [selected, setSelected] = useState<string[]>([]);\n\n return (\n <Selection items={clusters} getItemId={c => c.id} value={selected} onChange={setSelected}>\n <VStack gap={16}>\n <HStack gap={8} align='center'>\n <SelectionAll />\n <Text size='sm' color='secondary'>\n Select all\n </Text>\n </HStack>\n\n <VStack gap={12}>\n {clusters.map(c => (\n <SelectionItem key={c.id} itemId={c.id}>\n <ClusterCard cluster={c} />\n </SelectionItem>\n ))}\n </VStack>\n </VStack>\n\n <SelectionBulkBar>\n <Button color='brand' onClick={() => alert(`Delete ${selected.length}`)}>\n <Trash2 /> Delete\n </Button>\n </SelectionBulkBar>\n </Selection>\n );\n}"
24021
+ },
24022
+ {
24023
+ "name": "Grid",
24024
+ "code": "() => {\n const [selected, setSelected] = useState<string[]>([]);\n\n return (\n <Selection items={clusters} getItemId={c => c.id} value={selected} onChange={setSelected}>\n <div className='grid grid-cols-3 gap-12'>\n {clusters.map(c => (\n <SelectionItem key={c.id} itemId={c.id}>\n <ClusterCard cluster={c} />\n </SelectionItem>\n ))}\n </div>\n\n <SelectionBulkBar>\n <Button onClick={() => alert(selected.join(', '))}>Inspect</Button>\n </SelectionBulkBar>\n </Selection>\n );\n}"
24025
+ },
24026
+ {
24027
+ "name": "WithDisabled",
24028
+ "code": "() => {\n const [selected, setSelected] = useState<string[]>([]);\n\n return (\n <Selection items={clusters} getItemId={c => c.id} value={selected} onChange={setSelected}>\n <VStack gap={8}>\n <HStack gap={8} align='center'>\n <SelectionAll />\n <Text size='sm' color='secondary'>\n Select all (locked items skipped)\n </Text>\n </HStack>\n\n <VStack gap={12}>\n {clusters.map(c => (\n <SelectionItem key={c.id} itemId={c.id} disabled={c.locked}>\n <ClusterCard cluster={c} />\n </SelectionItem>\n ))}\n </VStack>\n </VStack>\n\n <SelectionBulkBar>\n <Button color='brand' onClick={() => alert(`Delete ${selected.length}`)}>\n <Trash2 /> Delete\n </Button>\n </SelectionBulkBar>\n </Selection>\n );\n}"
24029
+ },
24030
+ {
24031
+ "name": "RangeSelection",
24032
+ "code": "() => {\n const [selected, setSelected] = useState<string[]>([]);\n\n return (\n <Selection items={clusters} getItemId={c => c.id} value={selected} onChange={setSelected}>\n <VStack gap={12}>\n <Text size='sm' color='secondary'>\n Tip: hold <kbd>Shift</kbd> and click another checkbox to select a range.\n </Text>\n {clusters.map(c => (\n <SelectionItem key={c.id} itemId={c.id}>\n <ClusterCard cluster={c} />\n </SelectionItem>\n ))}\n </VStack>\n\n <SelectionBulkBar>\n <Button color='brand' onClick={() => alert(`Selected: ${selected.join(', ')}`)}>\n Confirm\n </Button>\n </SelectionBulkBar>\n </Selection>\n );\n}"
24033
+ },
24034
+ {
24035
+ "name": "BulkActions",
24036
+ "code": "() => {\n const [selected, setSelected] = useState<string[]>([]);\n\n return (\n <Selection items={clusters} getItemId={c => c.id} value={selected} onChange={setSelected}>\n <VStack gap={12}>\n {clusters.map(c => (\n <SelectionItem key={c.id} itemId={c.id}>\n <ClusterCard cluster={c} />\n </SelectionItem>\n ))}\n </VStack>\n\n <SelectionBulkBar>\n <Button\n variant='ghost'\n color='neutral-alt'\n onClick={() => alert(`Move ${selected.length}`)}\n >\n <Folder /> Move\n </Button>\n <Button\n variant='ghost'\n color='neutral-alt'\n onClick={() => alert(`Duplicate ${selected.length}`)}\n >\n <Copy /> Duplicate\n </Button>\n <Button color='brand' onClick={() => alert(`Delete ${selected.length}`)}>\n <Trash2 /> Delete\n </Button>\n </SelectionBulkBar>\n </Selection>\n );\n}"
24037
+ },
24038
+ {
24039
+ "name": "EmptyAndPartial",
24040
+ "code": "() => {\n const [items, setItems] = useState<Cluster[]>(clusters);\n const [selected, setSelected] = useState<string[]>(['1', 'ghost']);\n\n // Demonstrate cleanup pattern: drop ids that no longer exist in items.\n useEffect(() => {\n setSelected(prev => prev.filter(id => items.some(c => c.id === id)));\n }, [items]);\n\n return (\n <VStack gap={16}>\n <HStack gap={8}>\n <Button onClick={() => setItems([])} variant='outline'>\n Clear items\n </Button>\n <Button onClick={() => setItems(clusters)} variant='outline'>\n Restore items\n </Button>\n </HStack>\n\n <Selection items={items} getItemId={c => c.id} value={selected} onChange={setSelected}>\n <VStack gap={12}>\n {items.length === 0 ? (\n <Text size='sm' color='secondary'>\n No items.\n </Text>\n ) : (\n items.map(c => (\n <SelectionItem key={c.id} itemId={c.id}>\n <ClusterCard cluster={c} />\n </SelectionItem>\n ))\n )}\n </VStack>\n\n <SelectionBulkBar>\n <Button color='brand' onClick={() => alert(`Delete ${selected.length}`)}>\n <Trash2 /> Delete\n </Button>\n </SelectionBulkBar>\n </Selection>\n </VStack>\n );\n}"
24041
+ },
24042
+ {
24043
+ "name": "WithoutBulkBar",
24044
+ "code": "() => {\n const [selected, setSelected] = useState<string[]>([]);\n\n return (\n <Selection items={clusters} getItemId={c => c.id} value={selected} onChange={setSelected}>\n <VStack gap={16}>\n <Text size='sm' color='secondary'>\n Selected: {selected.length}\n </Text>\n\n <VStack gap={12}>\n {clusters.map(c => (\n <SelectionItem key={c.id} itemId={c.id}>\n <ClusterCard cluster={c} />\n </SelectionItem>\n ))}\n </VStack>\n </VStack>\n </Selection>\n );\n}"
24045
+ }
24046
+ ]
24047
+ },
23961
24048
  {
23962
24049
  "name": "Separator",
23963
24050
  "importPath": "@wallarm-org/design-system/Separator",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wallarm-org/design-system",
3
- "version": "0.29.2",
3
+ "version": "0.30.0-rc-feature-AS-884.1",
4
4
  "description": "Core design system library with React components and Storybook documentation",
5
5
  "publishConfig": {
6
6
  "access": "public",