@wallarm-org/design-system 0.14.1 → 0.14.2

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.
@@ -1,12 +1,12 @@
1
1
  import { cva } from "class-variance-authority";
2
- const chipVariants = cva('group/chip relative flex items-center justify-center px-4 py-0 min-h-[20px] border border-solid rounded-8', {
2
+ const chipVariants = cva('group/chip relative flex items-center justify-center pl-4 pr-0 py-0 min-h-[20px] border border-solid rounded-8', {
3
3
  variants: {
4
4
  error: {
5
5
  true: 'bg-bg-light-danger border-border-danger',
6
6
  false: 'bg-badge-badge-bg border-border-primary'
7
7
  },
8
8
  interactive: {
9
- true: 'cursor-pointer',
9
+ true: 'cursor-pointer px-4',
10
10
  false: ''
11
11
  }
12
12
  },
@@ -106,7 +106,7 @@ const FilterInputField = ({ className, ...props })=>{
106
106
  }),
107
107
  buildingChipData ? /*#__PURE__*/ jsxs("div", {
108
108
  ref: buildingChipRef,
109
- className: cn(buildingChipWrapperClass, hasContent && 'ml-8'),
109
+ className: buildingChipWrapperClass,
110
110
  children: [
111
111
  /*#__PURE__*/ jsx(FilterInputChip, {
112
112
  building: true,
@@ -12,7 +12,7 @@ export declare const filterInputInnerVariants: (props?: ({
12
12
  hasContent?: boolean | null | undefined;
13
13
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
14
14
  /** Wrapper that visually groups the building chip and the filter input */
15
- export declare const buildingChipWrapperClass = "flex items-center gap-2 min-w-0 rounded-8 border border-solid border-border-strong-primary bg-badge-badge-bg";
15
+ export declare const buildingChipWrapperClass = "flex items-center min-w-0 rounded-8 border border-solid border-border-strong-primary bg-badge-badge-bg ml-8";
16
16
  /** Native input element inside the query bar */
17
17
  export declare const filterInputInputVariants: (props?: ({
18
18
  hasContent?: boolean | null | undefined;
@@ -20,7 +20,7 @@ const filterInputContainerVariants = cva('relative flex min-h-40 w-full overflow
20
20
  },
21
21
  multiRow: {
22
22
  true: 'items-start',
23
- false: 'items-center'
23
+ false: 'items-stretch'
24
24
  }
25
25
  },
26
26
  defaultVariants: {
@@ -28,7 +28,7 @@ const filterInputContainerVariants = cva('relative flex min-h-40 w-full overflow
28
28
  multiRow: false
29
29
  }
30
30
  });
31
- const filterInputInnerVariants = cva('flex min-h-full w-full cursor-text flex-wrap items-center gap-y-4 py-4', {
31
+ const filterInputInnerVariants = cva('flex min-h-full w-full cursor-text flex-wrap items-center gap-y-4 py-8', {
32
32
  variants: {
33
33
  hasContent: {
34
34
  true: 'pl-4',
@@ -39,7 +39,7 @@ const filterInputInnerVariants = cva('flex min-h-full w-full cursor-text flex-wr
39
39
  hasContent: false
40
40
  }
41
41
  });
42
- const buildingChipWrapperClass = 'flex items-center gap-2 min-w-0 rounded-8 border border-solid border-border-strong-primary bg-badge-badge-bg';
42
+ const buildingChipWrapperClass = 'flex items-center min-w-0 rounded-8 border border-solid border-border-strong-primary bg-badge-badge-bg ml-8';
43
43
  const filterInputInputVariants = cva('h-auto border-none bg-transparent p-0 text-sm shadow-none outline-none ring-0', {
44
44
  variants: {
45
45
  hasContent: {
@@ -106,7 +106,7 @@ const FilterInputFieldMenu = ({ fields, filterText = '', onSelect, open = false,
106
106
  onHighlightChange: onHighlightChange,
107
107
  children: /*#__PURE__*/ jsxs(DropdownMenuContent, {
108
108
  ref: menuRef,
109
- className: cn('w-[300px]', className),
109
+ className: cn('w-[300px] max-h-[430px]', className),
110
110
  "data-slot": "filter-input-field-menu",
111
111
  children: [
112
112
  !filterText && showRecent && /*#__PURE__*/ jsx(RecentSection, {
@@ -55,7 +55,7 @@ const FilterInputOperatorMenu = ({ fieldType, operators, onSelect, open = false,
55
55
  onHighlightChange: onHighlightChange,
56
56
  children: /*#__PURE__*/ jsxs(DropdownMenuContent, {
57
57
  ref: menuRef,
58
- className: cn('w-256', className),
58
+ className: cn('w-256 max-h-[430px]', className),
59
59
  children: [
60
60
  filteredGroups.length > 0 ? filteredGroups.map((group, groupIdx)=>/*#__PURE__*/ jsxs(Fragment, {
61
61
  children: [
@@ -60,7 +60,7 @@ const FilterInputValueMenu = ({ values, onSelect, onCommit, open = false, onOpen
60
60
  onHighlightChange: onHighlightChange,
61
61
  children: /*#__PURE__*/ jsxs(DropdownMenuContent, {
62
62
  ref: menuRef,
63
- className: cn(widthClass, className),
63
+ className: cn(widthClass, 'max-h-[430px]', className),
64
64
  style: widthStyle,
65
65
  children: [
66
66
  displayValues.length > 0 ? /*#__PURE__*/ jsx(DropdownMenuGroup, {
@@ -7,7 +7,7 @@ const ScrollAreaViewport = (props)=>{
7
7
  return /*#__PURE__*/ jsx(ScrollArea.Viewport, {
8
8
  ...props,
9
9
  "data-testid": testId,
10
- className: cn('h-full outline-none overscroll-x-none')
10
+ className: cn('h-full outline-none')
11
11
  });
12
12
  };
13
13
  ScrollAreaViewport.displayName = 'ScrollAreaViewport';
@@ -1,18 +1,21 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
- import { useRef } from "react";
2
+ import { useCallback, useRef } from "react";
3
3
  import { useVirtualizer } from "@tanstack/react-virtual";
4
4
  import { TABLE_VIRTUALIZATION_OVERSCAN } from "../lib/index.js";
5
5
  import { useTableContext } from "../TableContext/index.js";
6
6
  import { TableBodyVirtualizedCore } from "./TableBodyVirtualizedCore.js";
7
+ import { useSmoothScrollOnSort } from "./useSmoothScrollOnSort.js";
7
8
  const TableBodyVirtualizedContainer = ()=>{
8
9
  const { table, estimateRowHeight, overscan } = useTableContext();
9
10
  const tbodyRef = useRef(null);
11
+ const getScrollElement = useCallback(()=>tbodyRef.current?.closest('[data-table-scroll-container]') ?? null, []);
10
12
  const virtualizer = useVirtualizer({
11
13
  count: table.getRowModel().rows.length,
12
- getScrollElement: ()=>tbodyRef.current?.closest('[data-table-scroll-container]') ?? null,
14
+ getScrollElement,
13
15
  estimateSize: estimateRowHeight ?? (()=>40),
14
16
  overscan: overscan ?? TABLE_VIRTUALIZATION_OVERSCAN
15
17
  });
18
+ useSmoothScrollOnSort(table, getScrollElement);
16
19
  return /*#__PURE__*/ jsx(TableBodyVirtualizedCore, {
17
20
  tbodyRef: tbodyRef,
18
21
  virtualizer: virtualizer
@@ -2,6 +2,6 @@ import type { FC, RefObject } from 'react';
2
2
  import type { Virtualizer } from '@tanstack/react-virtual';
3
3
  export interface TableBodyVirtualizedCoreProps {
4
4
  tbodyRef: RefObject<HTMLTableSectionElement | null>;
5
- virtualizer: Virtualizer<Window, Element> | Virtualizer<Element, Element>;
5
+ virtualizer: Virtualizer<Window, Element> | Virtualizer<HTMLElement, Element> | Virtualizer<Element, Element>;
6
6
  }
7
7
  export declare const TableBodyVirtualizedCore: FC<TableBodyVirtualizedCoreProps>;
@@ -1,9 +1,10 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
- import { useRef } from "react";
2
+ import { useCallback, useRef } from "react";
3
3
  import { useWindowVirtualizer } from "@tanstack/react-virtual";
4
4
  import { TABLE_VIRTUALIZATION_OVERSCAN } from "../lib/index.js";
5
5
  import { useTableContext } from "../TableContext/index.js";
6
6
  import { TableBodyVirtualizedCore } from "./TableBodyVirtualizedCore.js";
7
+ import { useSmoothScrollOnSort } from "./useSmoothScrollOnSort.js";
7
8
  function getDocumentOffsetTop(el) {
8
9
  let offset = 0;
9
10
  let current = el;
@@ -22,6 +23,8 @@ const TableBodyVirtualizedWindow = ()=>{
22
23
  overscan: overscan ?? TABLE_VIRTUALIZATION_OVERSCAN,
23
24
  scrollMargin: tbodyRef.current ? getDocumentOffsetTop(tbodyRef.current) : 0
24
25
  });
26
+ const getScrollTarget = useCallback(()=>window, []);
27
+ useSmoothScrollOnSort(table, getScrollTarget);
25
28
  return /*#__PURE__*/ jsx(TableBodyVirtualizedCore, {
26
29
  tbodyRef: tbodyRef,
27
30
  virtualizer: virtualizer
@@ -0,0 +1,7 @@
1
+ import type { Table as TanStackTable } from '@tanstack/react-table';
2
+ /**
3
+ * Smooth-scrolls the table to the top when sorting changes.
4
+ * Prevents the jarring jump that occurs when the virtualizer
5
+ * recalculates row positions after a sort.
6
+ */
7
+ export declare function useSmoothScrollOnSort<T>(table: TanStackTable<T>, getScrollTarget: () => HTMLElement | Window | null): void;
@@ -0,0 +1,19 @@
1
+ import { useEffect, useRef } from "react";
2
+ function useSmoothScrollOnSort(table, getScrollTarget) {
3
+ const prevSortingRef = useRef(table.getState().sorting);
4
+ const sorting = table.getState().sorting;
5
+ useEffect(()=>{
6
+ if (prevSortingRef.current === sorting) return;
7
+ prevSortingRef.current = sorting;
8
+ const target = getScrollTarget();
9
+ if (!target) return;
10
+ target.scrollTo({
11
+ top: 0,
12
+ behavior: 'smooth'
13
+ });
14
+ }, [
15
+ sorting,
16
+ getScrollTarget
17
+ ]);
18
+ }
19
+ export { useSmoothScrollOnSort };
@@ -1,5 +1,5 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
- import { useCallback, useEffect, useRef } from "react";
2
+ import { useEffect, useRef } from "react";
3
3
  import { useTestId } from "../../../utils/testId.js";
4
4
  import { ScrollArea, ScrollAreaScrollbar, ScrollAreaViewport } from "../../ScrollArea/index.js";
5
5
  import { useEndReached } from "../hooks/index.js";
@@ -13,85 +13,59 @@ const TableInnerWindow = ({ isEmpty, showSettings, ariaLabel, children })=>{
13
13
  const { table, onEndReached, onEndReachedThreshold } = useTableContext();
14
14
  const testId = useTestId('window');
15
15
  const rootRef = useRef(null);
16
- const headerScrollRef = useRef(null);
17
- const bodyScrollRef = useRef(null);
18
- const isSyncing = useRef(false);
16
+ const scrollRef = useRef(null);
19
17
  const containerWidth = useContainerWidth(rootRef);
20
18
  useEndReached({
21
19
  mode: 'window',
22
20
  onEndReached,
23
21
  threshold: onEndReachedThreshold
24
22
  });
25
- const syncScroll = useCallback((source, target)=>{
26
- if (isSyncing.current) return;
27
- isSyncing.current = true;
28
- target.scrollLeft = source.scrollLeft;
29
- isSyncing.current = false;
30
- }, []);
31
23
  useEffect(()=>{
32
- const header = headerScrollRef.current;
33
- const body = bodyScrollRef.current;
34
- if (!header || !body) return;
35
- const onBodyScroll = ()=>{
36
- syncScroll(body, header);
37
- rootRef.current?.toggleAttribute('data-scrolled', body.scrollLeft > 0);
24
+ const scrollEl = scrollRef.current;
25
+ if (!scrollEl) return;
26
+ const onScroll = ()=>{
27
+ rootRef.current?.toggleAttribute('data-scrolled', scrollEl.scrollLeft > 0);
38
28
  };
39
- const onHeaderScroll = ()=>syncScroll(header, body);
40
- body.addEventListener('scroll', onBodyScroll, {
41
- passive: true
42
- });
43
- header.addEventListener('scroll', onHeaderScroll, {
29
+ scrollEl.addEventListener('scroll', onScroll, {
44
30
  passive: true
45
31
  });
46
- return ()=>{
47
- body.removeEventListener('scroll', onBodyScroll);
48
- header.removeEventListener('scroll', onHeaderScroll);
49
- };
50
- }, [
51
- syncScroll
52
- ]);
32
+ return ()=>scrollEl.removeEventListener('scroll', onScroll);
33
+ }, []);
53
34
  const totalSize = table.getTotalSize();
54
35
  const tableWidth = Math.max(containerWidth, totalSize);
55
36
  const tableStyles = 'table-fixed border-separate border-spacing-0';
56
37
  return /*#__PURE__*/ jsxs("div", {
57
38
  ref: rootRef,
58
39
  "data-testid": testId,
59
- className: "group/scroll outline-none",
40
+ className: "group/scroll relative outline-none",
60
41
  children: [
61
- /*#__PURE__*/ jsxs("div", {
62
- className: "sticky top-0 z-30 relative",
63
- children: [
64
- /*#__PURE__*/ jsx("div", {
65
- ref: headerScrollRef,
66
- className: "overflow-hidden rounded-t-12 border border-b-0 border-border-primary-light",
67
- children: /*#__PURE__*/ jsxs("table", {
68
- className: tableStyles,
69
- style: {
70
- width: tableWidth
71
- },
72
- "aria-hidden": true,
73
- children: [
74
- /*#__PURE__*/ jsx(TableColGroup, {
75
- tableWidth: tableWidth
76
- }),
77
- /*#__PURE__*/ jsx(TableHead, {})
78
- ]
79
- })
80
- }),
81
- showSettings && /*#__PURE__*/ jsx(TableSettingsMenu, {})
82
- ]
83
- }),
84
42
  /*#__PURE__*/ jsxs(ScrollArea, {
85
- className: "group/scroll rounded-b-12 border border-t-0 border-border-primary-light",
43
+ className: "group/scroll rounded-12 border border-border-primary-light",
86
44
  children: [
87
45
  /*#__PURE__*/ jsxs(ScrollAreaViewport, {
88
- ref: bodyScrollRef,
46
+ ref: scrollRef,
89
47
  "data-table-scroll-container": true,
90
48
  style: {
91
49
  overflowX: 'auto',
92
50
  overflowY: 'hidden'
93
51
  },
94
52
  children: [
53
+ /*#__PURE__*/ jsx("div", {
54
+ className: "sticky top-0 z-30",
55
+ children: /*#__PURE__*/ jsxs("table", {
56
+ className: tableStyles,
57
+ style: {
58
+ width: tableWidth
59
+ },
60
+ "aria-hidden": true,
61
+ children: [
62
+ /*#__PURE__*/ jsx(TableColGroup, {
63
+ tableWidth: tableWidth
64
+ }),
65
+ /*#__PURE__*/ jsx(TableHead, {})
66
+ ]
67
+ })
68
+ }),
95
69
  /*#__PURE__*/ jsxs("table", {
96
70
  className: tableStyles,
97
71
  style: {
@@ -112,7 +86,8 @@ const TableInnerWindow = ({ isEmpty, showSettings, ariaLabel, children })=>{
112
86
  orientation: "horizontal"
113
87
  })
114
88
  ]
115
- })
89
+ }),
90
+ showSettings && /*#__PURE__*/ jsx(TableSettingsMenu, {})
116
91
  ]
117
92
  });
118
93
  };
@@ -112,7 +112,7 @@ const TableSettingsMenu = ()=>{
112
112
  })
113
113
  }),
114
114
  /*#__PURE__*/ jsxs(DropdownMenuContent, {
115
- className: cn('min-w-256'),
115
+ className: cn('min-w-256 max-h-[430px]'),
116
116
  children: [
117
117
  /*#__PURE__*/ jsx(DropdownMenuInput, {
118
118
  placeholder: "Search",
@@ -1,6 +1,6 @@
1
1
  {
2
- "version": "0.14.0",
3
- "generatedAt": "2026-03-19T08:25:17.978Z",
2
+ "version": "0.14.1",
3
+ "generatedAt": "2026-03-20T04:01:58.193Z",
4
4
  "components": [
5
5
  {
6
6
  "name": "Alert",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wallarm-org/design-system",
3
- "version": "0.14.1",
3
+ "version": "0.14.2",
4
4
  "description": "Core design system library with React components and Storybook documentation",
5
5
  "publishConfig": {
6
6
  "access": "public",