@drivenets/design-system 0.17.0 → 0.18.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.
- package/CHANGELOG.md +24 -0
- package/dist/index.cjs +1797 -805
- package/dist/index.d.cts +117 -53
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +117 -53
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1799 -809
- package/dist/index.js.map +1 -1
- package/dist/index.min.css +1 -1
- package/package.json +3 -3
- package/src/components/ds-alert-banner/ds-alert-banner-global.figma.ts +49 -0
- package/src/components/ds-alert-banner/ds-alert-banner.figma.ts +51 -0
- package/src/components/ds-autocomplete/ds-autocomplete.module.scss +15 -4
- package/src/components/ds-autocomplete/ds-autocomplete.tsx +10 -3
- package/src/components/ds-autocomplete/ds-autocomplete.types.ts +8 -0
- package/src/components/ds-button-v3/ds-button-v3.figma.ts +5 -3
- package/src/components/ds-button-v3/ds-button-v3.module.scss +84 -17
- package/src/components/ds-button-v3/ds-button-v3.tsx +2 -0
- package/src/components/ds-button-v3/ds-button-v3.types.ts +11 -2
- package/src/components/ds-button-v3/ds-button-v4.figma.ts +121 -0
- package/src/components/ds-comment-bubble/ds-comment-bubble.figma.ts +52 -0
- package/src/components/ds-comment-card/ds-comment-card.figma.ts +36 -0
- package/src/components/ds-comment-indicator/ds-comment-indicator.figma.ts +32 -0
- package/src/components/ds-comments-drawer/ds-comments-drawer.figma.ts +19 -0
- package/src/components/ds-select/ds-select.figma.ts +2 -1
- package/src/components/ds-select/ds-select.tsx +6 -1
- package/src/components/ds-select/ds-select.types.ts +2 -1
- package/src/components/ds-slider/ds-slider.figma.ts +29 -0
- package/src/components/ds-slider/ds-slider.module.scss +104 -0
- package/src/components/ds-slider/ds-slider.tsx +118 -0
- package/src/components/ds-slider/ds-slider.types.ts +102 -0
- package/src/components/ds-slider/ds-slider.utils.ts +14 -0
- package/src/components/ds-slider/index.ts +11 -0
- package/src/components/ds-smart-tabs/figma/ds-smart-tabs-tab.figma.ts +83 -0
- package/src/components/ds-smart-tabs/figma/ds-smart-tabs.figma.ts +23 -0
- package/src/components/ds-table/components/ds-table-group-header-cell/ds-table-group-header-cell.module.scss +5 -1
- package/src/components/ds-table/components/ds-table-group-header-cell/ds-table-group-header-cell.tsx +15 -3
- package/src/components/ds-table/components/ds-table-header/ds-table-header.module.scss +15 -1
- package/src/components/ds-table/components/ds-table-header/ds-table-header.tsx +29 -6
- package/src/components/ds-table/components/ds-table-resize-handle/ds-table-resize-handle.module.scss +23 -0
- package/src/components/ds-table/components/ds-table-resize-handle/ds-table-resize-handle.tsx +218 -0
- package/src/components/ds-table/components/ds-table-resize-handle/ds-table-resize-handle.types.ts +14 -0
- package/src/components/ds-table/components/ds-table-resize-handle/index.ts +1 -0
- package/src/components/ds-table/components/ds-table-resize-overlay/ds-table-resize-overlay.module.scss +18 -0
- package/src/components/ds-table/components/ds-table-resize-overlay/ds-table-resize-overlay.tsx +16 -0
- package/src/components/ds-table/components/ds-table-resize-overlay/ds-table-resize-overlay.types.ts +13 -0
- package/src/components/ds-table/components/ds-table-resize-overlay/index.ts +1 -0
- package/src/components/ds-table/components/ds-table-row/ds-table-row.module.scss +1 -1
- package/src/components/ds-table/components/ds-table-row/ds-table-row.tsx +9 -2
- package/src/components/ds-table/components/ds-table-row-virtualized/ds-table-row-virtualized.module.scss +2 -1
- package/src/components/ds-table/components/ds-table-row-virtualized/ds-table-row-virtualized.tsx +9 -2
- package/src/components/ds-table/components/edit/cell-editors/ds-table-edit-cell-checkbox.tsx +2 -2
- package/src/components/ds-table/components/edit/cell-editors/ds-table-edit-cell-date.tsx +2 -1
- package/src/components/ds-table/components/edit/cell-editors/ds-table-edit-cell-number.tsx +2 -1
- package/src/components/ds-table/components/edit/cell-editors/ds-table-edit-cell-select.tsx +2 -1
- package/src/components/ds-table/components/edit/cell-editors/ds-table-edit-cell-text.tsx +2 -1
- package/src/components/ds-table/components/edit/ds-table-editing-cell/ds-table-editing-cell.tsx +12 -3
- package/src/components/ds-table/context/ds-table-context.tsx +208 -0
- package/src/components/ds-table/ds-table-defaults.ts +42 -0
- package/src/components/ds-table/ds-table.module.scss +4 -1
- package/src/components/ds-table/ds-table.tsx +139 -214
- package/src/components/ds-table/ds-table.types.ts +53 -47
- package/src/components/ds-table/grouping/utils/column-group.ts +7 -5
- package/src/components/ds-table/hooks/use-cell-editor.ts +5 -1
- package/src/components/ds-table/hooks/use-column-resize.ts +385 -0
- package/src/components/ds-table/hooks/use-editing-state.ts +190 -0
- package/src/components/ds-table/index.ts +1 -0
- package/src/components/ds-table/styles/_variables.scss +2 -1
- package/src/components/ds-table/utils/column-size-meta.augmentation.ts +16 -0
- package/src/components/ds-table/utils/column-size.ts +213 -10
- package/src/components/ds-table/utils/column-size.unit.test.ts +213 -0
- package/src/components/ds-table/utils/constants.ts +28 -0
- package/src/components/ds-table/utils/frozen-body.ts +33 -0
- package/src/components/ds-table/utils/frozen-body.unit.test.ts +44 -0
- package/src/components/ds-table/utils/table-api.ts +42 -0
- package/src/components/ds-table/utils/table-api.unit.test.ts +82 -0
- package/src/components/ds-table/utils/table-columns.tsx +119 -0
- package/src/components/ds-table/utils/table-columns.unit.test.ts +199 -0
- package/src/components/ds-tag/ds-tag.figma.ts +51 -0
- package/src/components/ds-tag-filter/ds-tag-filter.figma.ts +16 -0
- package/src/components/ds-tag-filter/ds-tag-filter.module.scss +7 -35
- package/src/components/ds-tag-filter/ds-tag-filter.tsx +34 -57
- package/src/components/ds-tag-filter/ds-tag-filter.types.ts +2 -1
- package/src/components/ds-tag-filter/hooks/use-tag-overflow-calculation.ts +13 -18
- package/src/components/ds-text-input/ds-input-field-v02.figma.ts +29 -4
- package/src/components/ds-text-input/ds-text-input.figma.ts +3 -2
- package/src/components/ds-text-input/ds-text-input.tsx +1 -0
- package/src/components/ds-text-input/ds-text-input.types.ts +1 -1
- package/src/components/ds-tree/ds-tree.figma.ts +54 -0
- package/src/components/ds-workspace-layout/ds-workspace-layout.figma.ts +99 -0
- package/src/components/ds-workspace-layout/ds-workspace-layout.module.scss +1 -8
- package/src/index.ts +1 -0
- package/src/styles/_gradients.scss +19 -0
- package/src/styles/_root.scss +39 -15
- package/src/styles/_typography.scss +1 -0
- package/src/styles/shared/_input.scss +10 -0
- package/src/styles/styles.scss +1 -0
- package/src/components/ds-table/context/ds-table-context.ts +0 -112
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// url=https://www.figma.com/design/nha3m67y7S57cHCSuQO2gp/DAP-Design-System-1.2?node-id=19208-6889
|
|
2
|
+
// source=https://github.com/drivenets/design-system/tree/main/packages/design-system/src/components/ds-comment-indicator
|
|
3
|
+
// component=DsCommentIndicator
|
|
4
|
+
//
|
|
5
|
+
// The linked node is `Structure_CommentIndicatorV1`, the inner structure shared by the
|
|
6
|
+
// indicator variants. The `type` axis (placeholder / default / action-required) maps
|
|
7
|
+
// directly to the `type` prop; on the bare structure node it has no value, so it falls
|
|
8
|
+
// back to `default`. For the `placeholder` state no avatar is shown; the `default` /
|
|
9
|
+
// `action-required` states carry the initiator's avatar. `avatarSrc` is a photo URL
|
|
10
|
+
// and `avatarName` is content — neither is derivable from Figma — so `avatarName` is
|
|
11
|
+
// emitted as a placeholder for the developer to fill in (see `ds-avatar.figma.ts`).
|
|
12
|
+
import figma from 'figma';
|
|
13
|
+
|
|
14
|
+
const instance = figma.selectedInstance;
|
|
15
|
+
|
|
16
|
+
const type =
|
|
17
|
+
instance.getEnum('type', {
|
|
18
|
+
placeholder: 'placeholder',
|
|
19
|
+
default: 'default',
|
|
20
|
+
'action-required': 'action-required',
|
|
21
|
+
'action required': 'action-required',
|
|
22
|
+
}) ?? 'default';
|
|
23
|
+
|
|
24
|
+
export default {
|
|
25
|
+
example:
|
|
26
|
+
type === 'placeholder'
|
|
27
|
+
? figma.code`<DsCommentIndicator type="placeholder" onClick={() => {}} />`
|
|
28
|
+
: figma.code`<DsCommentIndicator type="${type}" avatarName="Full Name" onClick={() => {}} />`,
|
|
29
|
+
imports: ["import { DsCommentIndicator } from '@drivenets/design-system';"],
|
|
30
|
+
id: 'ds-comment-indicator',
|
|
31
|
+
metadata: { nestable: true },
|
|
32
|
+
} satisfies figma.Template;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// url=https://www.figma.com/design/nha3m67y7S57cHCSuQO2gp/DAP-Design-System-1.2?node-id=19346-10511
|
|
2
|
+
// source=https://github.com/drivenets/design-system/tree/main/packages/design-system/src/components/ds-comments-drawer
|
|
3
|
+
// component=DsCommentsDrawer
|
|
4
|
+
//
|
|
5
|
+
// `DsCommentsDrawerV1` is the comments side panel. Unlike `ds-drawer` / `ds-modal` it
|
|
6
|
+
// does not compose its children through slots: the toolbar, search, and the comment
|
|
7
|
+
// list are all internal, and the cards are rendered from the `comments` data array.
|
|
8
|
+
// There is therefore nothing to resolve via `executeTemplate` — the snippet emits
|
|
9
|
+
// `comments` / `onOpenChange` identifier placeholders for the developer to wire to
|
|
10
|
+
// state. The Figma `Type` axis (`Default` / `Regular`) has no `DsCommentsDrawer` prop
|
|
11
|
+
// equivalent — both render the same composition.
|
|
12
|
+
import figma from 'figma';
|
|
13
|
+
|
|
14
|
+
export default {
|
|
15
|
+
example: figma.code`<DsCommentsDrawer open comments={comments} onOpenChange={() => {}} />`,
|
|
16
|
+
imports: ["import { DsCommentsDrawer } from '@drivenets/design-system';"],
|
|
17
|
+
id: 'ds-comments-drawer',
|
|
18
|
+
metadata: { nestable: false },
|
|
19
|
+
} satisfies figma.Template;
|
|
@@ -8,6 +8,7 @@ const instance = figma.selectedInstance;
|
|
|
8
8
|
const size = instance.getEnum('Size', {
|
|
9
9
|
Default: 'default',
|
|
10
10
|
Small: 'small',
|
|
11
|
+
Large: 'large',
|
|
11
12
|
});
|
|
12
13
|
|
|
13
14
|
const state = instance.getEnum('State', {
|
|
@@ -22,7 +23,7 @@ const state = instance.getEnum('State', {
|
|
|
22
23
|
|
|
23
24
|
const disabled = state === 'disable';
|
|
24
25
|
|
|
25
|
-
const sizeAttr = size === 'small' ?
|
|
26
|
+
const sizeAttr = size === 'small' || size === 'large' ? `size="${size}"` : '';
|
|
26
27
|
|
|
27
28
|
// Multi-select is driven by the nested dropdown menu's `Type` (Checkbox = multi). The menu
|
|
28
29
|
// lives inside the select tree even when collapsed, so the designer's intent is read in any
|
|
@@ -135,7 +135,12 @@ const DsSelect = ({
|
|
|
135
135
|
lazyMount
|
|
136
136
|
>
|
|
137
137
|
<Select.Control
|
|
138
|
-
className={classNames(
|
|
138
|
+
className={classNames(
|
|
139
|
+
styles.control,
|
|
140
|
+
size === 'small' && styles.small,
|
|
141
|
+
size === 'large' && styles.large,
|
|
142
|
+
className,
|
|
143
|
+
)}
|
|
139
144
|
style={style}
|
|
140
145
|
onBlur={onBlur}
|
|
141
146
|
onKeyDown={(e) => {
|
|
@@ -2,7 +2,8 @@ import type React from 'react';
|
|
|
2
2
|
import type { ReactNode } from 'react';
|
|
3
3
|
import type { IconName } from '../ds-icon';
|
|
4
4
|
|
|
5
|
-
export
|
|
5
|
+
export const selectSizes = ['small', 'default', 'large'] as const;
|
|
6
|
+
export type SelectSize = (typeof selectSizes)[number];
|
|
6
7
|
|
|
7
8
|
export interface DsSelectOption {
|
|
8
9
|
/**
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// url=https://www.figma.com/design/nha3m67y7S57cHCSuQO2gp/DAP-Design-System-1.2?node-id=29879-165
|
|
2
|
+
// source=https://github.com/drivenets/design-system/tree/main/packages/design-system/src/components/ds-slider
|
|
3
|
+
// component=DsSlider
|
|
4
|
+
import figma from 'figma';
|
|
5
|
+
|
|
6
|
+
const instance = figma.selectedInstance;
|
|
7
|
+
|
|
8
|
+
const type = instance.getEnum('type', {
|
|
9
|
+
value: 'value',
|
|
10
|
+
range: 'range',
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const isRange = type === 'range';
|
|
14
|
+
|
|
15
|
+
const attrs = [
|
|
16
|
+
'label="Input label"',
|
|
17
|
+
isRange ? 'type="range"' : '',
|
|
18
|
+
isRange ? 'defaultValue={[36, 60]}' : 'defaultValue={36}',
|
|
19
|
+
isRange ? "thumbLabels={['Minimum', 'Maximum']}" : '',
|
|
20
|
+
]
|
|
21
|
+
.filter(Boolean)
|
|
22
|
+
.join(' ');
|
|
23
|
+
|
|
24
|
+
export default {
|
|
25
|
+
example: figma.code`<DsSlider ${attrs} />`,
|
|
26
|
+
imports: ["import { DsSlider } from '@drivenets/design-system';"],
|
|
27
|
+
id: 'ds-slider',
|
|
28
|
+
metadata: { nestable: false },
|
|
29
|
+
} satisfies figma.Template;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
.root {
|
|
2
|
+
--ds-slider-thumb-size: var(--md);
|
|
3
|
+
--ds-slider-thumb-size-active: var(--lg);
|
|
4
|
+
--ds-slider-thumb-border: 2px;
|
|
5
|
+
--ds-slider-thumb-border-active: 4px;
|
|
6
|
+
--ds-slider-track-height: 4px;
|
|
7
|
+
--ds-slider-focus-ring: 3px;
|
|
8
|
+
--ds-slider-radius: 9999px;
|
|
9
|
+
--ds-slider-transition: 0.2s;
|
|
10
|
+
|
|
11
|
+
display: flex;
|
|
12
|
+
flex-direction: column;
|
|
13
|
+
gap: var(--sm);
|
|
14
|
+
width: 100%;
|
|
15
|
+
|
|
16
|
+
&.small {
|
|
17
|
+
--ds-slider-thumb-size: var(--standard);
|
|
18
|
+
--ds-slider-thumb-size-active: var(--md);
|
|
19
|
+
--ds-slider-track-height: 2px;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
&.large {
|
|
23
|
+
--ds-slider-thumb-size: var(--lg);
|
|
24
|
+
--ds-slider-thumb-size-active: 28px;
|
|
25
|
+
--ds-slider-thumb-border: 3px;
|
|
26
|
+
--ds-slider-thumb-border-active: 5px;
|
|
27
|
+
--ds-slider-track-height: 8px;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
&[data-disabled] {
|
|
31
|
+
cursor: not-allowed;
|
|
32
|
+
|
|
33
|
+
.range {
|
|
34
|
+
background: var(--background-disable);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.thumb {
|
|
38
|
+
cursor: not-allowed;
|
|
39
|
+
border-color: var(--background-disable);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.header {
|
|
45
|
+
display: flex;
|
|
46
|
+
align-items: center;
|
|
47
|
+
justify-content: space-between;
|
|
48
|
+
gap: var(--xs);
|
|
49
|
+
padding-bottom: var(--4xs);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.valueText {
|
|
53
|
+
margin-left: auto;
|
|
54
|
+
text-align: right;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.control {
|
|
58
|
+
position: relative;
|
|
59
|
+
display: flex;
|
|
60
|
+
align-items: center;
|
|
61
|
+
min-height: var(--ds-slider-thumb-size-active);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.track {
|
|
65
|
+
flex: 1;
|
|
66
|
+
height: var(--ds-slider-track-height);
|
|
67
|
+
background: var(--background-secondary-hover);
|
|
68
|
+
border-radius: var(--ds-slider-radius);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.range {
|
|
72
|
+
height: 100%;
|
|
73
|
+
background: var(--background-primary);
|
|
74
|
+
border-radius: var(--ds-slider-radius);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.thumb {
|
|
78
|
+
box-sizing: border-box;
|
|
79
|
+
width: var(--ds-slider-thumb-size);
|
|
80
|
+
height: var(--ds-slider-thumb-size);
|
|
81
|
+
background: var(--background);
|
|
82
|
+
border: var(--ds-slider-thumb-border) solid var(--background-primary);
|
|
83
|
+
border-radius: var(--ds-slider-radius);
|
|
84
|
+
outline: none;
|
|
85
|
+
cursor: pointer;
|
|
86
|
+
transition:
|
|
87
|
+
width var(--ds-slider-transition),
|
|
88
|
+
height var(--ds-slider-transition),
|
|
89
|
+
border-width var(--ds-slider-transition),
|
|
90
|
+
border-color var(--ds-slider-transition),
|
|
91
|
+
box-shadow var(--ds-slider-transition);
|
|
92
|
+
|
|
93
|
+
&:not([data-disabled]):hover,
|
|
94
|
+
&:focus-visible {
|
|
95
|
+
width: var(--ds-slider-thumb-size-active);
|
|
96
|
+
height: var(--ds-slider-thumb-size-active);
|
|
97
|
+
border-width: var(--ds-slider-thumb-border-active);
|
|
98
|
+
border-color: var(--background-primary-hover);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
&:focus-visible {
|
|
102
|
+
box-shadow: 0 0 0 var(--ds-slider-focus-ring) var(--background-secondary-hover);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { Slider, type SliderValueChangeDetails } from '@ark-ui/react/slider';
|
|
2
|
+
import classNames from 'classnames';
|
|
3
|
+
import { useControlled } from '../../utils/use-controlled';
|
|
4
|
+
import { DsTypography } from '../ds-typography';
|
|
5
|
+
import type { DsSliderProps, DsSliderValue } from './ds-slider.types';
|
|
6
|
+
import { toArray } from './ds-slider.utils';
|
|
7
|
+
import styles from './ds-slider.module.scss';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @summary Selects a numeric value or a numeric interval by dragging thumbs along a track.
|
|
11
|
+
*
|
|
12
|
+
* Use for picking a number or interval from a known continuous range where visual
|
|
13
|
+
* adjustment beats typing (filter ranges, thresholds, capacity limits). For exact
|
|
14
|
+
* numeric entry use DsNumberInput; for a few discrete options use DsSegmentGroup.
|
|
15
|
+
*/
|
|
16
|
+
const DsSlider = ({
|
|
17
|
+
ref,
|
|
18
|
+
className,
|
|
19
|
+
style,
|
|
20
|
+
label,
|
|
21
|
+
type = 'value',
|
|
22
|
+
size = 'medium',
|
|
23
|
+
min = 0,
|
|
24
|
+
max = 100,
|
|
25
|
+
step = 1,
|
|
26
|
+
value,
|
|
27
|
+
defaultValue,
|
|
28
|
+
name,
|
|
29
|
+
disabled = false,
|
|
30
|
+
thumbLabels,
|
|
31
|
+
formatValue = String,
|
|
32
|
+
onValueChange,
|
|
33
|
+
onValueChangeEnd,
|
|
34
|
+
}: DsSliderProps) => {
|
|
35
|
+
const isRange = type === 'range';
|
|
36
|
+
|
|
37
|
+
const controlledValue = toArray(value);
|
|
38
|
+
const fallbackValue = isRange ? [min, max] : [min];
|
|
39
|
+
|
|
40
|
+
const toPublicValue = (next: number[]): DsSliderValue =>
|
|
41
|
+
isRange ? [next[0] ?? min, next[1] ?? max] : (next[0] ?? min);
|
|
42
|
+
|
|
43
|
+
const [values, setValues] = useControlled<number[]>(
|
|
44
|
+
controlledValue,
|
|
45
|
+
controlledValue !== undefined ? (next) => onValueChange?.(toPublicValue(next)) : undefined,
|
|
46
|
+
toArray(defaultValue) ?? fallbackValue,
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
const handleValueChange = (details: SliderValueChangeDetails) => {
|
|
50
|
+
setValues(details.value);
|
|
51
|
+
|
|
52
|
+
if (controlledValue === undefined) {
|
|
53
|
+
onValueChange?.(toPublicValue(details.value));
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const valueText = isRange
|
|
58
|
+
? `${formatValue(values[0] ?? min)}-${formatValue(values[1] ?? max)}`
|
|
59
|
+
: formatValue(values[0] ?? min);
|
|
60
|
+
|
|
61
|
+
const textColor = disabled ? 'disabled' : 'main';
|
|
62
|
+
|
|
63
|
+
const thumbAriaLabels = isRange ? thumbLabels : label ? [label] : thumbLabels;
|
|
64
|
+
|
|
65
|
+
const rootClass = classNames(
|
|
66
|
+
styles.root,
|
|
67
|
+
{
|
|
68
|
+
[styles.small]: size === 'small',
|
|
69
|
+
[styles.large]: size === 'large',
|
|
70
|
+
},
|
|
71
|
+
className,
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<Slider.Root
|
|
76
|
+
ref={ref}
|
|
77
|
+
className={rootClass}
|
|
78
|
+
style={style}
|
|
79
|
+
value={values}
|
|
80
|
+
min={min}
|
|
81
|
+
max={max}
|
|
82
|
+
step={step}
|
|
83
|
+
name={name}
|
|
84
|
+
disabled={disabled}
|
|
85
|
+
aria-label={thumbAriaLabels}
|
|
86
|
+
onValueChange={handleValueChange}
|
|
87
|
+
onValueChangeEnd={(details) => onValueChangeEnd?.(toPublicValue(details.value))}
|
|
88
|
+
>
|
|
89
|
+
<div className={styles.header}>
|
|
90
|
+
{label && (
|
|
91
|
+
<DsTypography variant="body-sm-md" color={textColor}>
|
|
92
|
+
{label}
|
|
93
|
+
</DsTypography>
|
|
94
|
+
)}
|
|
95
|
+
|
|
96
|
+
<DsTypography variant="body-sm-md" color={textColor} className={styles.valueText}>
|
|
97
|
+
{valueText}
|
|
98
|
+
</DsTypography>
|
|
99
|
+
</div>
|
|
100
|
+
|
|
101
|
+
<Slider.Control className={styles.control}>
|
|
102
|
+
<Slider.Track className={styles.track}>
|
|
103
|
+
<Slider.Range className={styles.range} />
|
|
104
|
+
</Slider.Track>
|
|
105
|
+
|
|
106
|
+
{values.map((_, index) => (
|
|
107
|
+
<Slider.Thumb key={index} index={index} className={styles.thumb}>
|
|
108
|
+
<Slider.HiddenInput />
|
|
109
|
+
</Slider.Thumb>
|
|
110
|
+
))}
|
|
111
|
+
</Slider.Control>
|
|
112
|
+
</Slider.Root>
|
|
113
|
+
);
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
DsSlider.displayName = 'DsSlider';
|
|
117
|
+
|
|
118
|
+
export default DsSlider;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type { CSSProperties, Ref } from 'react';
|
|
2
|
+
|
|
3
|
+
export const sliderTypes = ['value', 'range'] as const;
|
|
4
|
+
export type DsSliderType = (typeof sliderTypes)[number];
|
|
5
|
+
|
|
6
|
+
export const sliderSizes = ['small', 'medium', 'large'] as const;
|
|
7
|
+
export type DsSliderSize = (typeof sliderSizes)[number];
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Value for a `value` slider (single number) or a `range` slider ([min, max] tuple).
|
|
11
|
+
*/
|
|
12
|
+
export type DsSliderValue = number | [number, number];
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Props for the DsSlider component.
|
|
16
|
+
*/
|
|
17
|
+
export type DsSliderProps = {
|
|
18
|
+
/**
|
|
19
|
+
* Forwarded ref for the slider root element.
|
|
20
|
+
*/
|
|
21
|
+
ref?: Ref<HTMLDivElement>;
|
|
22
|
+
|
|
23
|
+
className?: string;
|
|
24
|
+
|
|
25
|
+
style?: CSSProperties;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Visible label rendered above the track. Becomes the accessible name of the control.
|
|
29
|
+
*/
|
|
30
|
+
label?: string;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Selection mode: a single value or a `[min, max]` interval.
|
|
34
|
+
* @default 'value'
|
|
35
|
+
*/
|
|
36
|
+
type?: DsSliderType;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Drives thumb and track sizing together (S/M/L → 16/20/24px thumb, 2/4/8px track).
|
|
40
|
+
* Accepts a responsive value (e.g. `{ md: 'small', lg: 'medium' }`).
|
|
41
|
+
* @default 'medium'
|
|
42
|
+
*/
|
|
43
|
+
size?: DsSliderSize;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Lowest selectable value.
|
|
47
|
+
* @default 0
|
|
48
|
+
*/
|
|
49
|
+
min?: number;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Highest selectable value.
|
|
53
|
+
* @default 100
|
|
54
|
+
*/
|
|
55
|
+
max?: number;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Granularity that the value snaps to. Must be greater than 0.
|
|
59
|
+
* Accepts a responsive value (e.g. `{ md: 5, lg: 1 }`).
|
|
60
|
+
* @default 1
|
|
61
|
+
*/
|
|
62
|
+
step?: number;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Controlled value. A number for `type="value"`, a `[min, max]` tuple for `type="range"`.
|
|
66
|
+
*/
|
|
67
|
+
value?: DsSliderValue;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Uncontrolled initial value. Defaults to `min` for `value` and `[min, max]` for `range`.
|
|
71
|
+
*/
|
|
72
|
+
defaultValue?: DsSliderValue;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Form field name applied to the hidden inputs.
|
|
76
|
+
*/
|
|
77
|
+
name?: string;
|
|
78
|
+
|
|
79
|
+
disabled?: boolean;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Accessible name per thumb. Required for `type="range"` (e.g. `['Minimum', 'Maximum']`).
|
|
83
|
+
* Accepts a responsive value (e.g. `{ md: ['Min', 'Max'], lg: ['Minimum', 'Maximum'] }`).
|
|
84
|
+
*/
|
|
85
|
+
thumbLabels?: string[];
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Formats each number shown in the output above the track. Range values are joined with `-`.
|
|
89
|
+
* @default String
|
|
90
|
+
*/
|
|
91
|
+
formatValue?: (value: number) => string;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Called live while the value changes (drag or keyboard).
|
|
95
|
+
*/
|
|
96
|
+
onValueChange?: (value: DsSliderValue) => void;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Called once an interaction settles (pointer released or key committed).
|
|
100
|
+
*/
|
|
101
|
+
onValueChangeEnd?: (value: DsSliderValue) => void;
|
|
102
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { DsSliderValue } from './ds-slider.types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Normalizes the public value (a number or a `[min, max]` tuple) into the
|
|
5
|
+
* `number[]` shape Ark's slider works with. Returns `undefined` when no value
|
|
6
|
+
* is provided so controlled/uncontrolled detection stays intact.
|
|
7
|
+
*/
|
|
8
|
+
export const toArray = (value: DsSliderValue | undefined): number[] | undefined => {
|
|
9
|
+
if (value === undefined) {
|
|
10
|
+
return undefined;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return Array.isArray(value) ? value : [value];
|
|
14
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ComponentProps } from 'react';
|
|
2
|
+
|
|
3
|
+
import { withResponsiveProps } from '../../utils/responsive';
|
|
4
|
+
import DsSliderBase from './ds-slider';
|
|
5
|
+
|
|
6
|
+
export const DsSlider = withResponsiveProps(DsSliderBase, ['size', 'step', 'thumbLabels']);
|
|
7
|
+
|
|
8
|
+
DsSlider.displayName = 'DsSlider';
|
|
9
|
+
|
|
10
|
+
export type DsSliderProps = ComponentProps<typeof DsSlider>;
|
|
11
|
+
export type { DsSliderValue, DsSliderType, DsSliderSize } from './ds-slider.types';
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// url=https://www.figma.com/design/nha3m67y7S57cHCSuQO2gp/DAP-Design-System-1.2?node-id=15707-16204
|
|
2
|
+
// source=https://github.com/drivenets/design-system/tree/main/packages/design-system/src/components/ds-smart-tabs
|
|
3
|
+
// component=DsSmartTabs.Tab
|
|
4
|
+
//
|
|
5
|
+
// `Part_SmartTabV1` maps to `DsSmartTabs.Tab`, resolved inside the group's
|
|
6
|
+
// `Smart tabs slot` (nestable). Each item = colored icon badge + label + count.
|
|
7
|
+
//
|
|
8
|
+
// Variant divergence — the Figma `state` axis (selected/unselected/hover/focus)
|
|
9
|
+
// is mostly visual: selection is owned by `DsSmartTabs` (`activeTab`), and
|
|
10
|
+
// hover/focus are driven by CSS. Only `disabled` maps to a `DsSmartTabs.Tab` prop.
|
|
11
|
+
//
|
|
12
|
+
// `color` is intentionally not emitted: it is a fixed semantic per-category value
|
|
13
|
+
// (encoded in the nested badge's `category` variant, not a tab-level property) and
|
|
14
|
+
// the category→color mapping is owned by the design system, so the developer sets
|
|
15
|
+
// it explicitly. `value` is data, not derivable from Figma, so slugify the label
|
|
16
|
+
// as a sensible default for the developer to confirm/replace.
|
|
17
|
+
import figma from 'figma';
|
|
18
|
+
|
|
19
|
+
const instance = figma.selectedInstance;
|
|
20
|
+
|
|
21
|
+
const state = instance.getEnum('state', {
|
|
22
|
+
selected: 'selected',
|
|
23
|
+
unselected: 'unselected',
|
|
24
|
+
hover: 'hover',
|
|
25
|
+
focus: 'focus',
|
|
26
|
+
disabled: 'disabled',
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// Label and count are plain text layers (not component properties): the first
|
|
30
|
+
// text child is the label, the second is the right-aligned count.
|
|
31
|
+
const texts = instance.children.filter((child): child is figma.TextHandle => child.type === 'TEXT');
|
|
32
|
+
const label = texts[0]?.textContent.trim() || 'Label';
|
|
33
|
+
const count = texts[1]?.textContent.trim() ?? '';
|
|
34
|
+
|
|
35
|
+
const value = label
|
|
36
|
+
.toLowerCase()
|
|
37
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
38
|
+
.replace(/^-+|-+$/g, '');
|
|
39
|
+
|
|
40
|
+
// The badge glyph maps to `DsSmartTabs.Tab.icon` (an icon-name string). Prefer a
|
|
41
|
+
// connected ds-icon's Code Connect id and fall back to the glyph layer name.
|
|
42
|
+
const resolveIcon = (): string => {
|
|
43
|
+
const node = instance
|
|
44
|
+
.findConnectedInstances((n) => n.codeConnectId()?.startsWith('ds-icon-') ?? false, {
|
|
45
|
+
traverseInstances: true,
|
|
46
|
+
})
|
|
47
|
+
.find((n): n is figma.InstanceHandle => n.type === 'INSTANCE');
|
|
48
|
+
|
|
49
|
+
const id = node?.codeConnectId();
|
|
50
|
+
if (id?.startsWith('ds-icon-o-')) {
|
|
51
|
+
return id.slice('ds-icon-o-'.length);
|
|
52
|
+
}
|
|
53
|
+
if (id?.startsWith('ds-icon-s-')) {
|
|
54
|
+
return id.slice('ds-icon-s-'.length);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return (node?.name ?? 'circle')
|
|
58
|
+
.replace(/^DAP_GM_[OS]_/, '')
|
|
59
|
+
.replace(/^DAP_/, '')
|
|
60
|
+
.replace(/[\s/]+/g, '_')
|
|
61
|
+
.toLowerCase();
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// `content` is number|string and is not auto-formatted: emit a numeric literal for
|
|
65
|
+
// a plain integer, otherwise keep the pre-formatted string (e.g. "1,273").
|
|
66
|
+
const contentAttr = /^\d+$/.test(count) ? `content={${count}}` : `content="${count}"`;
|
|
67
|
+
|
|
68
|
+
const attrs = [
|
|
69
|
+
`value="${value}"`,
|
|
70
|
+
`label="${label}"`,
|
|
71
|
+
`icon="${resolveIcon()}"`,
|
|
72
|
+
contentAttr,
|
|
73
|
+
state === 'disabled' ? 'disabled' : '',
|
|
74
|
+
]
|
|
75
|
+
.filter(Boolean)
|
|
76
|
+
.join(' ');
|
|
77
|
+
|
|
78
|
+
export default {
|
|
79
|
+
example: figma.code`<DsSmartTabs.Tab ${attrs} />`,
|
|
80
|
+
imports: ["import { DsSmartTabs } from '@drivenets/design-system';"],
|
|
81
|
+
id: 'ds-smart-tabs-tab',
|
|
82
|
+
metadata: { nestable: true },
|
|
83
|
+
} satisfies figma.Template;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// url=https://www.figma.com/design/nha3m67y7S57cHCSuQO2gp/DAP-Design-System-1.2?node-id=34864-129238
|
|
2
|
+
// source=https://github.com/drivenets/design-system/tree/main/packages/design-system/src/components/ds-smart-tabs
|
|
3
|
+
// component=DsSmartTabs
|
|
4
|
+
//
|
|
5
|
+
// `DsSmartTabsV1` is the smart-tabs filter row. It maps to `DsSmartTabs`, whose
|
|
6
|
+
// `Smart tabs slot` resolves each item via its own template (`DsSmartTabs.Tab`),
|
|
7
|
+
// so added/removed tabs stay in sync.
|
|
8
|
+
//
|
|
9
|
+
// `activeTab` and `onTabClick` are the controlled selection pair. Figma models
|
|
10
|
+
// only the row chrome — selection state is authored in code, so the snippet emits
|
|
11
|
+
// identifier placeholders for the developer to wire to component state.
|
|
12
|
+
import figma from 'figma';
|
|
13
|
+
|
|
14
|
+
const tabs = figma.selectedInstance.getSlot('Smart tabs slot');
|
|
15
|
+
|
|
16
|
+
export default {
|
|
17
|
+
example: figma.code`<DsSmartTabs activeTab={activeTab} onTabClick={setActiveTab}>
|
|
18
|
+
${tabs}
|
|
19
|
+
</DsSmartTabs>`,
|
|
20
|
+
imports: ["import { DsSmartTabs } from '@drivenets/design-system';"],
|
|
21
|
+
id: 'ds-smart-tabs',
|
|
22
|
+
metadata: { nestable: false },
|
|
23
|
+
} satisfies figma.Template;
|
|
@@ -3,11 +3,15 @@
|
|
|
3
3
|
|
|
4
4
|
.groupHeaderCell {
|
|
5
5
|
@include typography.body-sm-md;
|
|
6
|
+
position: relative;
|
|
6
7
|
color: var(--font-main);
|
|
7
8
|
height: var(--ds-table-header-height);
|
|
8
9
|
padding: 0;
|
|
9
10
|
border-bottom: vars.$border-width solid var(--color-dap-gray-400);
|
|
10
|
-
|
|
11
|
+
|
|
12
|
+
&:not(:first-child) {
|
|
13
|
+
border-left: vars.$group-border-width solid var(--border);
|
|
14
|
+
}
|
|
11
15
|
}
|
|
12
16
|
|
|
13
17
|
.groupHeaderContent {
|
package/src/components/ds-table/components/ds-table-group-header-cell/ds-table-group-header-cell.tsx
CHANGED
|
@@ -3,21 +3,27 @@ import { DsButtonV3 } from '../../../ds-button-v3';
|
|
|
3
3
|
import { TableHead } from '../core-table';
|
|
4
4
|
import { useDsTableContext } from '../../context/ds-table-context';
|
|
5
5
|
import { getGroupColumnSizeStyle } from '../../grouping';
|
|
6
|
+
import { getResizableHeaderStyle } from '../../utils/column-size';
|
|
6
7
|
import { defaultDsTableLocale } from '../../ds-table.types';
|
|
8
|
+
import { DsTableResizeHandle } from '../ds-table-resize-handle';
|
|
7
9
|
import type { DsTableGroupHeaderCellProps } from './ds-table-group-header-cell.types';
|
|
8
10
|
import styles from './ds-table-group-header-cell.module.scss';
|
|
9
11
|
|
|
10
12
|
export const DsTableGroupHeaderCell = <TData, TValue>({
|
|
11
13
|
header,
|
|
12
14
|
}: DsTableGroupHeaderCellProps<TData, TValue>) => {
|
|
13
|
-
const { collapsedColumnGroups, onToggleColumnGroup, locale } =
|
|
15
|
+
const { collapsedColumnGroups, onToggleColumnGroup, locale, resizableColumns, resizeSizingReady } =
|
|
16
|
+
useDsTableContext<TData, TValue>();
|
|
14
17
|
|
|
15
18
|
const groupId = header.column.id;
|
|
16
19
|
const visibleLeafColumns = header.column.getLeafColumns().filter((leaf) => leaf.getIsVisible());
|
|
17
|
-
const groupStyle =
|
|
20
|
+
const groupStyle = resizeSizingReady
|
|
21
|
+
? getResizableHeaderStyle(header.id)
|
|
22
|
+
: getGroupColumnSizeStyle(visibleLeafColumns, {});
|
|
18
23
|
|
|
19
24
|
const isCollapsible = header.column.columnDef.meta?.group?.collapsible ?? false;
|
|
20
25
|
const isCollapsed = collapsedColumnGroups?.includes(groupId) ?? false;
|
|
26
|
+
const canResize = resizableColumns && !isCollapsed && header.column.getCanResize();
|
|
21
27
|
|
|
22
28
|
const mergedLocale = { ...defaultDsTableLocale, ...locale };
|
|
23
29
|
const toggleLabel = isCollapsed ? mergedLocale.expandColumnGroup : mergedLocale.collapseColumnGroup;
|
|
@@ -25,7 +31,12 @@ export const DsTableGroupHeaderCell = <TData, TValue>({
|
|
|
25
31
|
const handleToggle = () => onToggleColumnGroup?.(groupId);
|
|
26
32
|
|
|
27
33
|
return (
|
|
28
|
-
<TableHead
|
|
34
|
+
<TableHead
|
|
35
|
+
data-column-id={groupId}
|
|
36
|
+
className={styles.groupHeaderCell}
|
|
37
|
+
style={groupStyle}
|
|
38
|
+
colSpan={header.colSpan}
|
|
39
|
+
>
|
|
29
40
|
<div className={styles.groupHeaderContent}>
|
|
30
41
|
<span className={styles.groupLabel}>
|
|
31
42
|
{flexRender(header.column.columnDef.header, header.getContext())}
|
|
@@ -43,6 +54,7 @@ export const DsTableGroupHeaderCell = <TData, TValue>({
|
|
|
43
54
|
/>
|
|
44
55
|
)}
|
|
45
56
|
</div>
|
|
57
|
+
{canResize && <DsTableResizeHandle header={header} />}
|
|
46
58
|
</TableHead>
|
|
47
59
|
);
|
|
48
60
|
};
|