@drivenets/design-system 0.8.0 → 0.9.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 (67) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/index.cjs +1567 -1077
  3. package/dist/index.d.cts +857 -135
  4. package/dist/index.d.cts.map +1 -1
  5. package/dist/index.d.ts +857 -135
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +1555 -1079
  8. package/dist/index.js.map +1 -1
  9. package/dist/index.min.css +1 -1
  10. package/package.json +19 -17
  11. package/src/components/ds-autocomplete/ds-autocomplete.module.scss +0 -1
  12. package/src/components/ds-button/versions/ds-button-new/ds-button-new.module.scss +25 -9
  13. package/src/components/ds-button/versions/ds-button-new/ds-button-new.tsx +5 -5
  14. package/src/components/ds-button/versions/ds-button-new/ds-button-new.types.ts +11 -1
  15. package/src/components/ds-button/versions/ds-button-new/index.ts +4 -1
  16. package/src/components/ds-button-v3/ds-button-v3.module.scss +391 -0
  17. package/src/components/ds-button-v3/ds-button-v3.tsx +55 -0
  18. package/src/components/ds-button-v3/ds-button-v3.types.ts +58 -0
  19. package/src/components/ds-button-v3/index.ts +6 -0
  20. package/src/components/ds-comment-card/ds-comment-card.module.scss +2 -2
  21. package/src/components/ds-comments-drawer/components/comments-filter-modal/comments-filter-modal.tsx +1 -1
  22. package/src/components/ds-comments-drawer/ds-comments-drawer.tsx +3 -9
  23. package/src/components/ds-date-picker/ds-date-picker.module.scss +10 -0
  24. package/src/components/ds-date-picker/ds-date-picker.tsx +4 -2
  25. package/src/components/ds-date-range-picker/ds-date-range-picker.tsx +2 -2
  26. package/src/components/ds-drawer/ds-drawer.tsx +6 -9
  27. package/src/components/ds-drawer/ds-drawer.types.ts +4 -2
  28. package/src/components/ds-form-control/ds-form-control.tsx +2 -3
  29. package/src/components/ds-panel/ds-panel.module.scss +4 -1
  30. package/src/components/ds-panel/ds-panel.tsx +8 -3
  31. package/src/components/ds-panel/ds-panel.types.ts +8 -1
  32. package/src/components/ds-panel/index.ts +4 -1
  33. package/src/components/ds-select/ds-select.module.scss +4 -1
  34. package/src/components/ds-split-button/ds-split-button.module.scss +99 -0
  35. package/src/components/ds-split-button/ds-split-button.tsx +49 -0
  36. package/src/components/ds-split-button/ds-split-button.types.ts +25 -0
  37. package/src/components/ds-split-button/index.ts +10 -0
  38. package/src/components/ds-stack/ds-stack.module.scss +4 -0
  39. package/src/components/ds-stack/ds-stack.tsx +35 -0
  40. package/src/components/ds-stack/ds-stack.types.ts +19 -0
  41. package/src/components/ds-stack/index.ts +18 -0
  42. package/src/components/ds-table/components/ds-table-body-virtualized/ds-table-body-virtualized.tsx +2 -2
  43. package/src/components/ds-table/components/ds-table-bulk-actions/ds-table-bulk-actions.module.scss +5 -8
  44. package/src/components/ds-table/components/ds-table-cell/ds-table-cell.tsx +7 -4
  45. package/src/components/ds-table/components/ds-table-cell/ds-table-cell.types.ts +6 -0
  46. package/src/components/ds-table/ds-table.module.scss +6 -0
  47. package/src/components/ds-table/ds-table.tsx +3 -0
  48. package/src/components/ds-time-picker/ds-time-picker.module.scss +11 -0
  49. package/src/components/ds-time-picker/ds-time-picker.tsx +32 -12
  50. package/src/components/ds-time-picker/ds-time-picker.types.ts +6 -0
  51. package/src/components/ds-tree/ds-tree.types.ts +2 -2
  52. package/src/index.ts +4 -0
  53. package/src/styles/_breakpoints.module.scss +5 -0
  54. package/src/styles/_grid.scss +5 -1
  55. package/src/styles/_mixin.scss +2 -2
  56. package/src/styles/_responsive.scss +13 -0
  57. package/src/styles/_root_updated.scss +20 -20
  58. package/src/styles/_scrollbars.scss +6 -1
  59. package/src/styles/_variables.scss +2 -0
  60. package/src/styles/shared/_button.scss +2 -0
  61. package/src/styles/shared/_input.scss +3 -40
  62. package/src/utils/responsive.browser.test.ts +94 -0
  63. package/src/utils/responsive.ts +79 -0
  64. package/src/utils/responsive.unit.test.ts +54 -0
  65. package/src/utils/type-utils.ts +1 -0
  66. package/src/utils/use-controlled.browser.test.ts +6 -6
  67. package/src/utils/use-controlled.ts +1 -1
@@ -0,0 +1,58 @@
1
+ import type { ButtonHTMLAttributes, Ref } from 'react';
2
+ import type { IconType } from '../ds-icon';
3
+ import type { ResponsiveValue } from '../../utils/responsive';
4
+
5
+ export const buttonV3Variants = ['primary', 'secondary', 'tertiary'] as const;
6
+ export type ButtonV3Variant = (typeof buttonV3Variants)[number];
7
+
8
+ export const buttonV3Colors = ['default', 'error', 'light'] as const;
9
+ export type ButtonV3Color = (typeof buttonV3Colors)[number];
10
+
11
+ export const buttonV3Sizes = ['large', 'medium', 'small', 'tiny'] as const;
12
+ export type ButtonV3Size = (typeof buttonV3Sizes)[number];
13
+
14
+ export interface DsButtonV3BaseProps extends ButtonHTMLAttributes<HTMLButtonElement> {
15
+ ref?: Ref<HTMLButtonElement>;
16
+
17
+ /**
18
+ * - `default` — standard light-UI palette
19
+ * - `error` — destructive / danger palette (red tones)
20
+ * - `light` — palette for dark-background surfaces (Figma **Type** onDark)
21
+ * @default 'default'
22
+ */
23
+ color?: ButtonV3Color;
24
+
25
+ /**
26
+ * @default 'primary'
27
+ */
28
+ variant?: ButtonV3Variant;
29
+
30
+ /**
31
+ * @default 'medium'
32
+ */
33
+ size?: ButtonV3Size;
34
+
35
+ /**
36
+ * @default false
37
+ */
38
+ selected?: boolean;
39
+
40
+ /**
41
+ * Leading icon. When set without children, renders as icon-only (square) layout.
42
+ */
43
+ icon?: IconType;
44
+
45
+ /**
46
+ * Shows a spinner as the leading element and disables interaction.
47
+ * @default false
48
+ */
49
+ loading?: boolean;
50
+ }
51
+
52
+ export interface DsButtonV3Props extends Omit<DsButtonV3BaseProps, 'size'> {
53
+ /**
54
+ * Size of the button. Accepts a static value or a responsive object.
55
+ * @default 'medium'
56
+ */
57
+ size?: ResponsiveValue<ButtonV3Size>;
58
+ }
@@ -0,0 +1,6 @@
1
+ import { withResponsiveProps } from '../../utils/responsive';
2
+ import DsButtonV3Base from './ds-button-v3';
3
+
4
+ export const DsButtonV3 = withResponsiveProps(DsButtonV3Base, ['size']);
5
+
6
+ export * from './ds-button-v3.types';
@@ -1,4 +1,4 @@
1
- @import '../../styles/mixin';
1
+ @use '../../styles/mixin' as mixins;
2
2
 
3
3
  $side-color-width: 4px;
4
4
  $border-width: 1px;
@@ -30,7 +30,7 @@ $transition-duration: 0.2s;
30
30
  }
31
31
  }
32
32
 
33
- @include disabled-overlay;
33
+ @include mixins.disabled-overlay;
34
34
  }
35
35
 
36
36
  .sideColor {
@@ -19,7 +19,7 @@ export const CommentsFilterModal = ({
19
19
  availableAuthors,
20
20
  availableLabels,
21
21
  }: CommentsFilterModalProps) => {
22
- const [selectedTab, setSelectedTab] = useState<string>('statuses');
22
+ const [selectedTab, setSelectedTab] = useState('statuses');
23
23
 
24
24
  const handleStatusToggle = (status: 'unresolved' | 'resolved' | 'action-required', checked: boolean) => {
25
25
  onFiltersChange({
@@ -7,13 +7,7 @@ import { DsButton } from '../ds-button';
7
7
  import { DsIcon } from '../ds-icon';
8
8
  import { DsTextInput } from '../ds-text-input';
9
9
  import { DsTagFilter, type TagFilterItem } from '../ds-tag-filter';
10
- import {
11
- type CommentsFilterState,
12
- initialFilterState,
13
- applyFilters,
14
- filtersToTags,
15
- removeTag,
16
- } from './comments-filters';
10
+ import { initialFilterState, applyFilters, filtersToTags, removeTag } from './comments-filters';
17
11
  import { CommentsFilterModal } from './components/comments-filter-modal';
18
12
 
19
13
  export const DsCommentsDrawer = ({
@@ -36,8 +30,8 @@ export const DsCommentsDrawer = ({
36
30
  style,
37
31
  }: DsCommentsDrawerProps) => {
38
32
  const [isFilterModalOpen, setIsFilterModalOpen] = useState(false);
39
- const [pendingFilters, setPendingFilters] = useState<CommentsFilterState>(initialFilterState);
40
- const [appliedFilters, setAppliedFilters] = useState<CommentsFilterState>(initialFilterState);
33
+ const [pendingFilters, setPendingFilters] = useState(initialFilterState);
34
+ const [appliedFilters, setAppliedFilters] = useState(initialFilterState);
41
35
 
42
36
  const authorsMap = new Map<string, string>();
43
37
  const labelsSet = new Set<string>();
@@ -2,6 +2,16 @@
2
2
 
3
3
  .control {
4
4
  display: flex;
5
+
6
+ &:not([data-disabled]):where(:hover, :focus-within) {
7
+ .clearTrigger {
8
+ visibility: visible;
9
+ }
10
+ }
11
+ }
12
+
13
+ .clearTrigger {
14
+ visibility: hidden;
5
15
  }
6
16
 
7
17
  .positioner {
@@ -1,5 +1,5 @@
1
1
  import { type ChangeEvent, Fragment, useEffect, useRef, useState } from 'react';
2
- import { DatePicker, type DateValue } from '@ark-ui/react/date-picker';
2
+ import { DatePicker } from '@ark-ui/react/date-picker';
3
3
  import { Portal } from '@ark-ui/react/portal';
4
4
  import type { DsDatePickerProps } from './ds-date-picker.types';
5
5
  import {
@@ -42,7 +42,7 @@ const DsDatePicker = ({
42
42
  }: DsDatePickerProps) => {
43
43
  const defaultValue = toIntlDate(_defaultValue);
44
44
 
45
- const [value, setValue] = useControlled<DateValue | null>(
45
+ const [value, setValue] = useControlled(
46
46
  toIntlDate(_value),
47
47
  onChange ? (v) => onChange(fromIntlDate(v)) : undefined,
48
48
  defaultValue ?? null,
@@ -145,6 +145,7 @@ const DsDatePicker = ({
145
145
  {showClearButton && (
146
146
  <DatePicker.ClearTrigger asChild onClick={() => setValue(null)}>
147
147
  <DsButton
148
+ className={styles.clearTrigger}
148
149
  design="v1.2"
149
150
  size="tiny"
150
151
  buttonType="tertiary"
@@ -184,6 +185,7 @@ const DsDatePicker = ({
184
185
  }}
185
186
  min={isSameDay(value, min) ? _min : undefined}
186
187
  max={isSameDay(value, max) ? _max : undefined}
188
+ hideClearButton={true}
187
189
  disabled={disabled || !value}
188
190
  readOnly={readOnly}
189
191
  {...slotProps?.timePicker}
@@ -3,7 +3,7 @@ import { DsFormControl } from '../ds-form-control';
3
3
  import { DsButton } from '../ds-button';
4
4
  import { DsIcon } from '../ds-icon';
5
5
  import { useControlled } from '../../utils/use-controlled';
6
- import type { DateRangeValue, DsDateRangePickerProps } from './ds-date-range-picker.types';
6
+ import type { DsDateRangePickerProps } from './ds-date-range-picker.types';
7
7
  import styles from './ds-date-range-picker.module.scss';
8
8
  import { earlierDate, laterDate } from './ds-date-range-picker.utils';
9
9
 
@@ -24,7 +24,7 @@ const DsDateRangePicker = ({
24
24
  locale,
25
25
  slotProps,
26
26
  }: DsDateRangePickerProps) => {
27
- const [value, setValue] = useControlled<DateRangeValue>(valueProp, onChange, defaultValue);
27
+ const [value, setValue] = useControlled(valueProp, onChange, defaultValue);
28
28
 
29
29
  const [startDate, endDate] = value;
30
30
 
@@ -6,12 +6,8 @@ import type { DsDrawerProps } from './ds-drawer.types';
6
6
  import styles from './ds-drawer.module.scss';
7
7
  import { DsIcon } from '../ds-icon';
8
8
  import { DsTypography } from '../ds-typography';
9
+ import { useResponsiveValue } from '../../utils/responsive';
9
10
 
10
- /**
11
- * Composable drawer component.
12
- * Supports grid-based sizing, flexible positioning, and compound components.
13
- * Use columns prop to control drawer width (1-12 grid columns).
14
- */
15
11
  const DsDrawer = ({
16
12
  open,
17
13
  onOpenChange,
@@ -25,9 +21,12 @@ const DsDrawer = ({
25
21
  className,
26
22
  children,
27
23
  }: DsDrawerProps) => {
24
+ const resolvedColumns = useResponsiveValue(columns);
25
+
28
26
  const handleOpenChange = (details: { open: boolean }) => {
29
27
  onOpenChange(details.open);
30
28
  };
29
+
31
30
  const Wrapper = portal ? Portal : Fragment;
32
31
 
33
32
  return (
@@ -48,10 +47,8 @@ const DsDrawer = ({
48
47
  styles.drawer,
49
48
  styles[`position-${position}`],
50
49
  className,
51
-
52
- // @ts-expect-error: these classnames are generated dynamically in scss
53
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
54
- styles[`cols-${String(columns)}`],
50
+ // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
51
+ styles[`cols-${resolvedColumns}`],
55
52
  )}
56
53
  >
57
54
  <div className={styles.content}>{children}</div>
@@ -1,5 +1,6 @@
1
1
  import type { CSSProperties, ReactNode } from 'react';
2
2
  import type { UseDialogProps as DialogProps } from '@ark-ui/react/dialog';
3
+ import type { ResponsiveValue } from '../../utils/responsive';
3
4
 
4
5
  /**
5
6
  * Available positions for the drawer
@@ -20,10 +21,11 @@ export interface DsDrawerProps extends Pick<DialogProps, 'closeOnEscape' | 'clos
20
21
  */
21
22
  onOpenChange: (open: boolean) => void;
22
23
  /**
23
- * Number of grid columns the drawer should span (1-12)
24
+ * Number of grid columns the drawer should span (1-12).
25
+ * Accepts a responsive value, e.g. `{ lg: 4, md: 6 }`.
24
26
  * @default 4
25
27
  */
26
- columns?: DsDrawerColumns;
28
+ columns?: ResponsiveValue<DsDrawerColumns>;
27
29
  /**
28
30
  * Position of the drawer
29
31
  * @default 'end'
@@ -63,9 +63,8 @@ const DsFormControl = ({
63
63
  styles.container,
64
64
  className,
65
65
 
66
- // @ts-expect-error: `info` doesn't have its own classname
67
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
68
- status && message && styles[status],
66
+ // Casting because `info` doesn't have its own classname
67
+ status && message && styles[status as keyof typeof styles],
69
68
  )}
70
69
  style={style}
71
70
  >
@@ -2,7 +2,10 @@
2
2
  position: relative;
3
3
  background: var(--white);
4
4
  padding: var(--spacing-6);
5
- width: 340px;
5
+ width: 20vw;
6
+ min-width: 240px;
7
+ max-width: 480px;
8
+ height: 100vh;
6
9
  border-inline-end: 1px solid transparent;
7
10
 
8
11
  &[data-state='open']:hover,
@@ -3,7 +3,7 @@ import * as Collapsible from '@radix-ui/react-collapsible';
3
3
  import classnames from 'classnames';
4
4
  import styles from './ds-panel.module.scss';
5
5
  import { DsIcon } from '../ds-icon';
6
- import type { DsPanelCollapseButtonProps, DsPanelProps } from './ds-panel.types';
6
+ import type { DsPanelBaseProps, DsPanelCollapseButtonProps } from './ds-panel.types';
7
7
 
8
8
  function useDraggable(enabled: boolean) {
9
9
  const rootRef = useRef<HTMLDivElement>(null);
@@ -84,20 +84,24 @@ function useDraggable(enabled: boolean) {
84
84
  return rootRef;
85
85
  }
86
86
 
87
- export function DsPanel({
87
+ export function DsPanelBase({
88
88
  open,
89
89
  onOpenChange,
90
90
  children,
91
91
  className,
92
+ style,
92
93
  slotProps,
93
94
  variant = 'docked',
95
+ width,
94
96
  draggable = false,
95
97
  disablePadding = false,
96
98
  ...props
97
- }: DsPanelProps) {
99
+ }: DsPanelBaseProps) {
98
100
  const isDraggable = variant === 'floating' && draggable;
99
101
  const rootRef = useDraggable(isDraggable);
100
102
 
103
+ const rootStyle = width ? { ...style, width } : style;
104
+
101
105
  return (
102
106
  <Collapsible.Root
103
107
  ref={rootRef}
@@ -108,6 +112,7 @@ export function DsPanel({
108
112
  [styles.variantFloating]: variant === 'floating',
109
113
  [styles.disablePadding]: disablePadding,
110
114
  })}
115
+ style={rootStyle}
111
116
  {...props}
112
117
  >
113
118
  <DsPanelCollapseButton {...slotProps?.collapseButton} />
@@ -1,9 +1,12 @@
1
1
  import type * as Collapsible from '@radix-ui/react-collapsible';
2
2
 
3
+ import type { ResponsiveValue } from '../../utils/responsive';
4
+
3
5
  export type DsPanelVariant = 'docked' | 'floating';
4
6
 
5
- export type DsPanelProps = Omit<Collapsible.CollapsibleProps, 'onOpenChange'> & {
7
+ export type DsPanelBaseProps = Omit<Collapsible.CollapsibleProps, 'onOpenChange'> & {
6
8
  variant?: DsPanelVariant;
9
+ width?: number;
7
10
  draggable?: boolean;
8
11
  disablePadding?: boolean;
9
12
  slotProps?: {
@@ -12,6 +15,10 @@ export type DsPanelProps = Omit<Collapsible.CollapsibleProps, 'onOpenChange'> &
12
15
  onOpenChange?: (open: boolean) => void;
13
16
  };
14
17
 
18
+ export type DsPanelProps = Omit<DsPanelBaseProps, 'width'> & {
19
+ width?: ResponsiveValue<number>;
20
+ };
21
+
15
22
  export type DsPanelCollapseButtonProps = {
16
23
  onClick?: () => void;
17
24
  collapsed?: boolean;
@@ -1,2 +1,5 @@
1
- export { DsPanel } from './ds-panel';
1
+ import { withResponsiveProps } from '../../utils/responsive';
2
+ import { DsPanelBase } from './ds-panel';
3
+
4
+ export const DsPanel = withResponsiveProps(DsPanelBase, ['width']);
2
5
  export type { DsPanelProps, DsPanelVariant, DsPanelCollapseButtonProps } from './ds-panel.types';
@@ -53,8 +53,11 @@
53
53
  @include typography.ellipsis;
54
54
  grid-column: 1;
55
55
  grid-row: 1;
56
- color: var(--color-font-secondary);
57
56
  text-align: start;
57
+
58
+ .trigger:not([data-disabled]) & {
59
+ color: var(--color-font-secondary);
60
+ }
58
61
  }
59
62
 
60
63
  .multiSelectItemsContainer {
@@ -0,0 +1,99 @@
1
+ @use '../../styles/shared/button' as button;
2
+
3
+ $highlighted-z-index: 1;
4
+ $divider-z-index: $highlighted-z-index + 1;
5
+ $divider-width: 1px;
6
+ $border-width: 1px;
7
+
8
+ @mixin when-button-disabled {
9
+ .root:has(.actionButton:disabled) & {
10
+ @content;
11
+ }
12
+ }
13
+
14
+ @mixin when-select-disabled {
15
+ .root:has(.select[data-disabled]) & {
16
+ @content;
17
+ }
18
+ }
19
+
20
+ @mixin when-button-highlighted {
21
+ .root:has(.actionButton:not(:disabled):is(:hover, :focus-visible, :active, [data-selected='true'])) & {
22
+ @content;
23
+ }
24
+ }
25
+
26
+ @mixin when-select-highlighted {
27
+ .root:has(
28
+ .select:not([data-disabled]):is(:hover, :active, [data-state='open']),
29
+ .select:not([data-disabled]) :focus-visible
30
+ )
31
+ & {
32
+ @content;
33
+ }
34
+ }
35
+
36
+ .root {
37
+ display: inline-flex;
38
+
39
+ .actionButton {
40
+ border-top-right-radius: 0;
41
+ border-bottom-right-radius: 0;
42
+ }
43
+ }
44
+
45
+ .actionButton {
46
+ @include when-button-highlighted {
47
+ z-index: $highlighted-z-index;
48
+ transition: border-color button.$transition-duration-quick;
49
+ }
50
+
51
+ &:not(:disabled):is(:hover, :active, [data-selected='true']) {
52
+ border-right-color: var(--border-border-secondary-hover);
53
+ }
54
+
55
+ &:not(:disabled):focus-visible {
56
+ border-right-color: var(--border-border-inverse);
57
+ }
58
+ }
59
+
60
+ .select {
61
+ margin-left: -$divider-width;
62
+ border-top-left-radius: 0;
63
+ border-bottom-left-radius: 0;
64
+ }
65
+
66
+ .dividerAnchor {
67
+ position: relative;
68
+ }
69
+
70
+ .dividerWrapper {
71
+ position: absolute;
72
+ top: $border-width;
73
+ bottom: $border-width;
74
+ left: -$divider-width;
75
+ z-index: $divider-z-index;
76
+ width: $divider-width;
77
+ padding: var(--spacing-3xs) 0;
78
+ background-color: var(--background-background);
79
+
80
+ @include when-button-highlighted {
81
+ display: none;
82
+ }
83
+ @include when-select-highlighted {
84
+ display: none;
85
+ }
86
+ }
87
+
88
+ .divider {
89
+ background-color: var(--color-border-secondary);
90
+ width: $divider-width;
91
+ height: 100%;
92
+
93
+ @include when-button-disabled {
94
+ background-color: var(--border-border-disabled);
95
+ }
96
+ @include when-select-disabled {
97
+ background-color: var(--border-border-disabled);
98
+ }
99
+ }
@@ -0,0 +1,49 @@
1
+ import classNames from 'classnames';
2
+ import { DsSelect, type SelectSize } from '../ds-select';
3
+ import styles from './ds-split-button.module.scss';
4
+ import type { DsSplitButtonProps, SplitButtonSize } from './ds-split-button.types';
5
+ import { DsButtonV3 } from '../ds-button-v3';
6
+
7
+ const DsSplitButton = ({
8
+ ref,
9
+ className,
10
+ style,
11
+ size = 'medium',
12
+ disabled,
13
+ slotProps,
14
+ }: DsSplitButtonProps) => {
15
+ const { className: buttonClassName, disabled: buttonDisabled, ...buttonProps } = slotProps.button;
16
+
17
+ const { className: selectClassName, disabled: selectDisabled, ...selectProps } = slotProps.select;
18
+
19
+ return (
20
+ <div ref={ref} className={classNames(styles.root, className)} style={style}>
21
+ <DsButtonV3
22
+ {...buttonProps}
23
+ variant="secondary"
24
+ size={size}
25
+ disabled={buttonDisabled ?? disabled}
26
+ className={classNames(styles.actionButton, buttonClassName)}
27
+ />
28
+
29
+ <div className={styles.dividerAnchor}>
30
+ <div className={styles.dividerWrapper}>
31
+ <div className={styles.divider} />
32
+ </div>
33
+ </div>
34
+
35
+ <DsSelect
36
+ {...selectProps}
37
+ size={getSelectSize(size)}
38
+ disabled={selectDisabled ?? disabled}
39
+ className={classNames(styles.select, selectClassName)}
40
+ />
41
+ </div>
42
+ );
43
+ };
44
+
45
+ const getSelectSize = (size: SplitButtonSize): SelectSize => {
46
+ return size === 'medium' ? 'default' : 'small';
47
+ };
48
+
49
+ export default DsSplitButton;
@@ -0,0 +1,25 @@
1
+ import type { CSSProperties, Ref } from 'react';
2
+ import type { DsButtonV3Props } from '../ds-button-v3';
3
+ import type { DsSelectProps } from '../ds-select';
4
+ import type { DistributiveOmit } from '../../utils/type-utils';
5
+
6
+ export const splitButtonSizes = ['medium', 'small'] as const;
7
+ export type SplitButtonSize = (typeof splitButtonSizes)[number];
8
+
9
+ type ButtonSlotProps = Omit<DsButtonV3Props, 'variant' | 'color' | 'size'>;
10
+
11
+ type SelectSlotProps = DistributiveOmit<DsSelectProps, 'size'>;
12
+
13
+ export interface DsSplitButtonSlotProps {
14
+ button: ButtonSlotProps;
15
+ select: SelectSlotProps;
16
+ }
17
+
18
+ export interface DsSplitButtonProps {
19
+ ref?: Ref<HTMLDivElement>;
20
+ className?: string;
21
+ style?: CSSProperties;
22
+ size?: SplitButtonSize;
23
+ disabled?: boolean;
24
+ slotProps: DsSplitButtonSlotProps;
25
+ }
@@ -0,0 +1,10 @@
1
+ import type { ComponentProps } from 'react';
2
+ import { withResponsiveProps } from '../../utils/responsive';
3
+ import DsSplitButtonBase from './ds-split-button';
4
+ export { type DsSplitButtonSlotProps, splitButtonSizes } from './ds-split-button.types';
5
+
6
+ export const DsSplitButton = withResponsiveProps(DsSplitButtonBase, ['size']);
7
+
8
+ DsSplitButton.displayName = 'DsSplitButton';
9
+
10
+ export type DsSplitButtonProps = ComponentProps<typeof DsSplitButton>;
@@ -0,0 +1,4 @@
1
+ .root {
2
+ display: flex;
3
+ flex-direction: column;
4
+ }
@@ -0,0 +1,35 @@
1
+ import classNames from 'classnames';
2
+
3
+ import styles from './ds-stack.module.scss';
4
+ import type { DsStackProps } from './ds-stack.types';
5
+
6
+ export const DsStack = ({
7
+ direction,
8
+ gap,
9
+ alignItems,
10
+ justifyContent,
11
+ flex,
12
+ flexWrap,
13
+ width,
14
+ children,
15
+ className,
16
+ style,
17
+ ref,
18
+ }: DsStackProps) => {
19
+ const layoutStyle: React.CSSProperties = {
20
+ flexDirection: direction,
21
+ gap,
22
+ alignItems,
23
+ justifyContent,
24
+ flex,
25
+ flexWrap,
26
+ width,
27
+ ...style,
28
+ };
29
+
30
+ return (
31
+ <div ref={ref} className={classNames(styles.root, className)} style={layoutStyle}>
32
+ {children}
33
+ </div>
34
+ );
35
+ };
@@ -0,0 +1,19 @@
1
+ import type { Properties } from 'csstype';
2
+
3
+ type CSSProps = Properties<string | number>;
4
+ import type { CSSProperties, ReactNode, Ref } from 'react';
5
+
6
+ export interface DsStackProps {
7
+ direction?: CSSProps['flexDirection'];
8
+ gap?: CSSProps['gap'];
9
+ alignItems?: CSSProps['alignItems'];
10
+ justifyContent?: CSSProps['justifyContent'];
11
+ flex?: CSSProps['flex'];
12
+ flexWrap?: CSSProps['flexWrap'];
13
+ width?: CSSProps['width'];
14
+
15
+ children?: ReactNode;
16
+ className?: string;
17
+ style?: CSSProperties;
18
+ ref?: Ref<HTMLDivElement>;
19
+ }
@@ -0,0 +1,18 @@
1
+ import type { ComponentProps } from 'react';
2
+
3
+ import { withResponsiveProps } from '../../utils/responsive';
4
+ import { DsStack as DsStackBase } from './ds-stack';
5
+
6
+ export const DsStack = withResponsiveProps(DsStackBase, [
7
+ 'direction',
8
+ 'gap',
9
+ 'alignItems',
10
+ 'justifyContent',
11
+ 'flex',
12
+ 'flexWrap',
13
+ 'width',
14
+ ]);
15
+
16
+ DsStack.displayName = 'DsStack';
17
+
18
+ export type DsStackProps = ComponentProps<typeof DsStack>;
@@ -16,8 +16,8 @@ export const DsTableBodyVirtualized = <TData,>({
16
16
  onScroll,
17
17
  rowSelection,
18
18
  }: DsTableBodyVirtualizedProps<TData>) => {
19
- const rowsMapRef = useRef<Map<string, HTMLTableRowElement>>(new Map());
20
- const rowHeightsMapRef = useRef<Map<string, number>>(new Map());
19
+ const rowsMapRef = useRef(new Map<string, HTMLTableRowElement>());
20
+ const rowHeightsMapRef = useRef(new Map<string, number>());
21
21
 
22
22
  const { rows } = table.getRowModel();
23
23
 
@@ -58,18 +58,15 @@
58
58
  gap: 8px;
59
59
 
60
60
  > .actionButton {
61
+ display: flex;
62
+ flex-direction: column;
63
+ align-items: center;
64
+ justify-content: center;
65
+ gap: var(--spacing-3xs);
61
66
  border-right: 1px solid var(--neutral-6);
62
67
  width: 68px;
63
68
  height: 48px;
64
69
  border-radius: 0;
65
-
66
- > .actionButtonContent {
67
- display: flex;
68
- flex-direction: column;
69
- align-items: center;
70
- justify-content: center;
71
- gap: 4px;
72
- }
73
70
  }
74
71
 
75
72
  > .actionButton:first-child {