@drivenets/design-system 0.13.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -0
- package/README.md +1 -1
- package/dist/index.cjs +1155 -381
- package/dist/index.d.cts +371 -21
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +371 -21
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1151 -381
- package/dist/index.js.map +1 -1
- package/dist/index.min.css +1 -1
- package/package.json +16 -13
- package/src/components/ds-button-v3/ds-button-v3.figma.ts +99 -0
- package/src/components/ds-button-v3/ds-button-v3.module.scss +22 -22
- package/src/components/ds-card/figma/ds-card-content.figma.ts +15 -0
- package/src/components/ds-card/figma/ds-card-footer.figma.ts +15 -0
- package/src/components/ds-card/figma/ds-card-header.figma.ts +15 -0
- package/src/components/ds-card/figma/ds-card.figma.ts +72 -0
- package/src/components/ds-date-picker/ds-date-picker.figma.ts +19 -0
- package/src/components/ds-drawer/ds-drawer.module.scss +14 -0
- package/src/components/ds-drawer/ds-drawer.tsx +20 -1
- package/src/components/ds-drawer/ds-drawer.types.ts +7 -0
- package/src/components/ds-file-upload/hooks/use-file-upload.ts +7 -0
- package/src/components/ds-form-control/ds-form-control.figma.ts +76 -0
- package/src/components/ds-icon/figma/ds-icon-material.figma.batch.ts +10 -0
- package/src/components/ds-icon/figma/ds-icon-special.figma.batch.ts +18 -0
- package/src/components/ds-icon/figma/ds-icon.figma.batch.json +2873 -0
- package/src/components/ds-modal/figma/ds-modal-content.figma.ts +18 -0
- package/src/components/ds-modal/figma/ds-modal-footer.figma.ts +19 -0
- package/src/components/ds-modal/figma/ds-modal-header.figma.ts +21 -0
- package/src/components/ds-modal/figma/ds-modal.figma.ts +36 -0
- package/src/components/ds-popover/ds-popover.module.scss +58 -16
- package/src/components/ds-popover/ds-popover.tsx +148 -24
- package/src/components/ds-popover/ds-popover.types.ts +95 -12
- package/src/components/ds-popover/index.ts +1 -1
- package/src/components/ds-progress-task-bar/ds-progress-task-bar.figma.ts +29 -0
- package/src/components/ds-progress-task-bar/ds-progress-task-bar.module.scss +39 -0
- package/src/components/ds-progress-task-bar/ds-progress-task-bar.tsx +122 -0
- package/src/components/ds-progress-task-bar/ds-progress-task-bar.types.ts +65 -0
- package/src/components/ds-progress-task-bar/index.ts +2 -0
- package/src/components/ds-progress-task-bar/utils.ts +51 -0
- package/src/components/ds-select/ds-select.figma.ts +53 -0
- package/src/components/ds-split-button/ds-split-button.figma.ts +95 -0
- package/src/components/ds-status-badge-v2/ds-status-badge-v2.figma.ts +41 -0
- package/src/components/ds-table/components/ds-table-body-virtualized/ds-table-body-virtualized.tsx +8 -3
- package/src/components/ds-table/components/ds-table-group-header-cell/ds-table-group-header-cell.module.scss +31 -0
- package/src/components/ds-table/components/ds-table-group-header-cell/ds-table-group-header-cell.tsx +48 -0
- package/src/components/ds-table/components/ds-table-group-header-cell/ds-table-group-header-cell.types.ts +12 -0
- package/src/components/ds-table/components/ds-table-group-header-cell/index.ts +2 -0
- package/src/components/ds-table/components/ds-table-header/ds-table-header.module.scss +4 -0
- package/src/components/ds-table/components/ds-table-header/ds-table-header.tsx +55 -39
- package/src/components/ds-table/components/ds-table-row/ds-table-row.module.scss +5 -1
- package/src/components/ds-table/components/ds-table-row/ds-table-row.tsx +4 -0
- package/src/components/ds-table/components/ds-table-row-virtualized/ds-table-row-virtualized.module.scss +5 -1
- package/src/components/ds-table/components/ds-table-row-virtualized/ds-table-row-virtualized.tsx +4 -0
- package/src/components/ds-table/components/edit/ds-table-editable-cell/ds-table-editable-cell.module.scss +14 -2
- package/src/components/ds-table/components/edit/ds-table-editable-cell/ds-table-editable-cell.tsx +19 -0
- package/src/components/ds-table/context/ds-table-context.ts +4 -0
- package/src/components/ds-table/ds-table-column.types.ts +24 -0
- package/src/components/ds-table/ds-table.tsx +48 -6
- package/src/components/ds-table/ds-table.types.ts +62 -0
- package/src/components/ds-table/figma/ds-table-expandable.figma.ts +17 -0
- package/src/components/ds-table/figma/ds-table.figma.ts +16 -0
- package/src/components/ds-table/grouping/hooks/use-column-groups.ts +73 -0
- package/src/components/ds-table/grouping/index.ts +5 -0
- package/src/components/ds-table/grouping/types/column-group-meta.augmentation.ts +26 -0
- package/src/components/ds-table/grouping/types/column-group.types.ts +35 -0
- package/src/components/ds-table/grouping/utils/column-group.ts +119 -0
- package/src/components/ds-table/index.ts +4 -0
- package/src/components/ds-table/styles/_variables.scss +1 -0
- package/src/components/ds-table/utils/constants.ts +5 -0
- package/src/components/ds-tabs/figma/ds-tabs-tab-vertical.figma.ts +78 -0
- package/src/components/ds-tabs/figma/ds-tabs-tab.figma.ts +89 -0
- package/src/components/ds-tabs/figma/ds-tabs-vertical.figma.ts +31 -0
- package/src/components/ds-tabs/figma/ds-tabs.figma.ts +29 -0
- package/src/components/ds-tag/ds-tag.module.scss +22 -1
- package/src/components/ds-tag/ds-tag.tsx +16 -3
- package/src/components/ds-tag/ds-tag.types.ts +22 -8
- package/src/components/ds-tag/ds-tag.unit.test.ts +32 -0
- package/src/components/ds-tag-filter/ds-tag-filter.tsx +14 -22
- package/src/components/ds-text-input/ds-text-input.figma.ts +60 -0
- package/src/components/ds-time-picker/ds-time-picker.figma.ts +18 -0
- package/src/index.ts +1 -0
- package/src/styles/_root_new.scss +2 -0
- package/src/styles/_scrollbars.scss +27 -50
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// url=https://www.figma.com/design/nha3m67y7S57cHCSuQO2gp/DAP-Design-System-1.2?node-id=14841-6024
|
|
2
|
+
// source=https://github.com/drivenets/design-system/tree/main/packages/design-system/src/components/ds-tabs
|
|
3
|
+
// component=DsTabs.Tab
|
|
4
|
+
//
|
|
5
|
+
// `DAP_Tab item - vertical_v01` maps to `DsTabs.Tab`, resolved inside the vertical
|
|
6
|
+
// `tabs slot` (nestable). Same code component as the horizontal tab item; the two
|
|
7
|
+
// differ in Figma only by casing (`Show Leading Icon`) and by the vertical set
|
|
8
|
+
// having no `Menu Actions` property.
|
|
9
|
+
//
|
|
10
|
+
// Variant divergence — `State`, `Selected` and `Size` have no `DsTabs.Tab` prop
|
|
11
|
+
// (see `ds-tabs-tab.figma.ts` for the rationale).
|
|
12
|
+
import figma from 'figma';
|
|
13
|
+
|
|
14
|
+
const instance = figma.selectedInstance;
|
|
15
|
+
|
|
16
|
+
const label = instance.getString('Tab Name');
|
|
17
|
+
const showIcon = instance.getBoolean('Show Leading Icon');
|
|
18
|
+
const showBadge = instance.getBoolean('Show Badge');
|
|
19
|
+
|
|
20
|
+
// `value` is required by `DsTabsTabProps` but is data, not derivable from Figma.
|
|
21
|
+
const value = label
|
|
22
|
+
? label
|
|
23
|
+
.toLowerCase()
|
|
24
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
25
|
+
.replace(/^-+|-+$/g, '')
|
|
26
|
+
: 'tab';
|
|
27
|
+
|
|
28
|
+
// Leading icon → `DsTabs.Tab.icon` name, read from the connected ds-icon instance.
|
|
29
|
+
const resolveIcon = (): string | undefined => {
|
|
30
|
+
const node = instance
|
|
31
|
+
.findConnectedInstances((n) => n.codeConnectId()?.startsWith('ds-icon-') ?? false, {
|
|
32
|
+
traverseInstances: true,
|
|
33
|
+
})
|
|
34
|
+
.find((n): n is figma.InstanceHandle => n.type === 'INSTANCE');
|
|
35
|
+
|
|
36
|
+
if (!node) {
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const id = node.codeConnectId();
|
|
41
|
+
if (id?.startsWith('ds-icon-o-')) {
|
|
42
|
+
return id.slice('ds-icon-o-'.length);
|
|
43
|
+
}
|
|
44
|
+
if (id?.startsWith('ds-icon-s-')) {
|
|
45
|
+
return id.slice('ds-icon-s-'.length);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return node.name
|
|
49
|
+
.replace(/^DAP_GM_[OS]_/, '')
|
|
50
|
+
.replace(/^DAP_/, '')
|
|
51
|
+
.replace(/[\s/]+/g, '_')
|
|
52
|
+
.toLowerCase();
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const icon = showIcon ? resolveIcon() : undefined;
|
|
56
|
+
|
|
57
|
+
// Badge count is freeform nested text, read from the badge instance when shown.
|
|
58
|
+
const resolveBadge = (): string | undefined => {
|
|
59
|
+
const badge = instance.findInstance('DAP_Tab badge_v01', { traverseInstances: true });
|
|
60
|
+
if (badge.type !== 'INSTANCE') {
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
return badge.children.find((c): c is figma.TextHandle => c.type === 'TEXT')?.textContent;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const badge = showBadge ? resolveBadge() : undefined;
|
|
67
|
+
const badgeAttr = badge ? (/^\d+$/.test(badge) ? `badge={${badge}}` : `badge="${badge}"`) : '';
|
|
68
|
+
|
|
69
|
+
const attrs = [`value="${value}"`, `label="${label}"`, icon ? `icon="${icon}"` : '', badgeAttr]
|
|
70
|
+
.filter(Boolean)
|
|
71
|
+
.join(' ');
|
|
72
|
+
|
|
73
|
+
export default {
|
|
74
|
+
example: figma.code`<DsTabs.Tab ${attrs} />`,
|
|
75
|
+
imports: ["import { DsTabs } from '@drivenets/design-system'"],
|
|
76
|
+
id: 'ds-tabs-tab-vertical',
|
|
77
|
+
metadata: { nestable: true },
|
|
78
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// url=https://www.figma.com/design/nha3m67y7S57cHCSuQO2gp/DAP-Design-System-1.2?node-id=14829-217
|
|
2
|
+
// source=https://github.com/drivenets/design-system/tree/main/packages/design-system/src/components/ds-tabs
|
|
3
|
+
// component=DsTabs.Tab
|
|
4
|
+
//
|
|
5
|
+
// `DAP_Tab item - horizontal_v01` maps to `DsTabs.Tab`. It resolves inside the
|
|
6
|
+
// horizontal `tabs slot` (nestable).
|
|
7
|
+
//
|
|
8
|
+
// Variant divergence — these Figma axes intentionally have no `DsTabs.Tab` prop:
|
|
9
|
+
// • `State` (Default/Hover/Pressed) — visual only, driven by CSS.
|
|
10
|
+
// • `Selected` (Yes/No) — selection is owned by `DsTabs.Root` (`value`), not the tab.
|
|
11
|
+
// • `Size` (Base) — size lives on `DsTabs.Root` (`size`), not the tab.
|
|
12
|
+
import figma from 'figma';
|
|
13
|
+
|
|
14
|
+
const instance = figma.selectedInstance;
|
|
15
|
+
|
|
16
|
+
const label = instance.getString('Tab Name');
|
|
17
|
+
const showIcon = instance.getBoolean('Show leading icon');
|
|
18
|
+
const showBadge = instance.getBoolean('Show Badge');
|
|
19
|
+
const hasMenu = instance.getBoolean('Menu Actions');
|
|
20
|
+
|
|
21
|
+
// `value` is required by `DsTabsTabProps` but is data, not derivable from Figma.
|
|
22
|
+
// Slugify the label as a sensible default for the developer to confirm/replace.
|
|
23
|
+
const value = label
|
|
24
|
+
? label
|
|
25
|
+
.toLowerCase()
|
|
26
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
27
|
+
.replace(/^-+|-+$/g, '')
|
|
28
|
+
: 'tab';
|
|
29
|
+
|
|
30
|
+
// The leading icon maps to `DsTabs.Tab.icon` (an icon-name string). It is a
|
|
31
|
+
// connected ds-icon instance: read its Code Connect id (`ds-icon-o-`/`-s-`) and
|
|
32
|
+
// fall back to the layer name when it is unavailable.
|
|
33
|
+
const resolveIcon = (): string | undefined => {
|
|
34
|
+
const node = instance
|
|
35
|
+
.findConnectedInstances((n) => n.codeConnectId()?.startsWith('ds-icon-') ?? false, {
|
|
36
|
+
traverseInstances: true,
|
|
37
|
+
})
|
|
38
|
+
.find((n): n is figma.InstanceHandle => n.type === 'INSTANCE');
|
|
39
|
+
|
|
40
|
+
if (!node) {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const id = node.codeConnectId();
|
|
45
|
+
if (id?.startsWith('ds-icon-o-')) {
|
|
46
|
+
return id.slice('ds-icon-o-'.length);
|
|
47
|
+
}
|
|
48
|
+
if (id?.startsWith('ds-icon-s-')) {
|
|
49
|
+
return id.slice('ds-icon-s-'.length);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return node.name
|
|
53
|
+
.replace(/^DAP_GM_[OS]_/, '')
|
|
54
|
+
.replace(/^DAP_/, '')
|
|
55
|
+
.replace(/[\s/]+/g, '_')
|
|
56
|
+
.toLowerCase();
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const icon = showIcon ? resolveIcon() : undefined;
|
|
60
|
+
|
|
61
|
+
// The badge count is freeform nested text (`DAP_Tab badge_v01`), not a component
|
|
62
|
+
// property, so read it from the badge instance when shown.
|
|
63
|
+
const resolveBadge = (): string | undefined => {
|
|
64
|
+
const badge = instance.findInstance('DAP_Tab badge_v01', { traverseInstances: true });
|
|
65
|
+
if (badge.type !== 'INSTANCE') {
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
return badge.children.find((c): c is figma.TextHandle => c.type === 'TEXT')?.textContent;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const badge = showBadge ? resolveBadge() : undefined;
|
|
72
|
+
const badgeAttr = badge ? (/^\d+$/.test(badge) ? `badge={${badge}}` : `badge="${badge}"`) : '';
|
|
73
|
+
|
|
74
|
+
const attrs = [
|
|
75
|
+
`value="${value}"`,
|
|
76
|
+
`label="${label}"`,
|
|
77
|
+
icon ? `icon="${icon}"` : '',
|
|
78
|
+
badgeAttr,
|
|
79
|
+
hasMenu ? 'menuActionItems={[]} onMenuActionSelect={() => {}}' : '',
|
|
80
|
+
]
|
|
81
|
+
.filter(Boolean)
|
|
82
|
+
.join(' ');
|
|
83
|
+
|
|
84
|
+
export default {
|
|
85
|
+
example: figma.code`<DsTabs.Tab ${attrs} />`,
|
|
86
|
+
imports: ["import { DsTabs } from '@drivenets/design-system'"],
|
|
87
|
+
id: 'ds-tabs-tab',
|
|
88
|
+
metadata: { nestable: true },
|
|
89
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// url=https://www.figma.com/design/nha3m67y7S57cHCSuQO2gp/DAP-Design-System-1.2?node-id=14841-11560
|
|
2
|
+
// source=https://github.com/drivenets/design-system/tree/main/packages/design-system/src/components/ds-tabs
|
|
3
|
+
// component=DsTabs
|
|
4
|
+
//
|
|
5
|
+
// `DAP_Tabs group-vertical_v01` is the vertical tab bar. Horizontal and vertical
|
|
6
|
+
// are separate Figma component sets but a single code component switched by the
|
|
7
|
+
// `orientation` prop, so this template mirrors `ds-tabs.figma.ts` with
|
|
8
|
+
// `orientation="vertical"`. The `tabs slot` resolves each vertical tab item via
|
|
9
|
+
// its own template (`DsTabs.Tab`); `DsTabs.Content` panels are authored in code.
|
|
10
|
+
import figma from 'figma';
|
|
11
|
+
|
|
12
|
+
// The vertical set labels its size `Base` (= default `medium`); also accept the
|
|
13
|
+
// horizontal naming so a future shared variant keeps mapping to the `size` prop.
|
|
14
|
+
const size = figma.selectedInstance.getEnum('Size', {
|
|
15
|
+
Base: 'medium',
|
|
16
|
+
medium: 'medium',
|
|
17
|
+
small: 'small',
|
|
18
|
+
});
|
|
19
|
+
const sizeAttr = size === 'small' ? ' size="small"' : '';
|
|
20
|
+
|
|
21
|
+
const tabs = figma.selectedInstance.getSlot('tabs slot');
|
|
22
|
+
|
|
23
|
+
export default {
|
|
24
|
+
example: figma.code`<DsTabs.Root orientation="vertical"${sizeAttr}>
|
|
25
|
+
<DsTabs.List>${tabs}</DsTabs.List>
|
|
26
|
+
{/* Add a <DsTabs.Content value="..."> panel for each tab */}
|
|
27
|
+
</DsTabs.Root>`,
|
|
28
|
+
imports: ["import { DsTabs } from '@drivenets/design-system'"],
|
|
29
|
+
id: 'ds-tabs-vertical',
|
|
30
|
+
metadata: { nestable: false },
|
|
31
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// url=https://www.figma.com/design/nha3m67y7S57cHCSuQO2gp/DAP-Design-System-1.2?node-id=14841-11053
|
|
2
|
+
// source=https://github.com/drivenets/design-system/tree/main/packages/design-system/src/components/ds-tabs
|
|
3
|
+
// component=DsTabs
|
|
4
|
+
//
|
|
5
|
+
// `DAP_Tabs group-horizontal_v01` is the horizontal tab bar. It maps to the
|
|
6
|
+
// composed `DsTabs.Root` + `DsTabs.List`. The `tabs slot` resolves each tab item
|
|
7
|
+
// via its own Code Connect template (`DsTabs.Tab`), so added/removed tabs stay in
|
|
8
|
+
// sync. Figma only models the tab bar — the `DsTabs.Content` panels have no Figma
|
|
9
|
+
// equivalent and are authored in code, so the snippet emits a hint instead.
|
|
10
|
+
import figma from 'figma';
|
|
11
|
+
|
|
12
|
+
const instance = figma.selectedInstance;
|
|
13
|
+
|
|
14
|
+
// Figma's group `Size` is the code `size` prop; `medium` is the default so only
|
|
15
|
+
// `small` is emitted.
|
|
16
|
+
const size = instance.getEnum('Size', { medium: 'medium', small: 'small' });
|
|
17
|
+
const sizeAttr = size === 'small' ? ' size="small"' : '';
|
|
18
|
+
|
|
19
|
+
const tabs = instance.getSlot('tabs slot');
|
|
20
|
+
|
|
21
|
+
export default {
|
|
22
|
+
example: figma.code`<DsTabs.Root orientation="horizontal"${sizeAttr}>
|
|
23
|
+
<DsTabs.List>${tabs}</DsTabs.List>
|
|
24
|
+
{/* Add a <DsTabs.Content value="..."> panel for each tab */}
|
|
25
|
+
</DsTabs.Root>`,
|
|
26
|
+
imports: ["import { DsTabs } from '@drivenets/design-system'"],
|
|
27
|
+
id: 'ds-tabs',
|
|
28
|
+
metadata: { nestable: false },
|
|
29
|
+
};
|
|
@@ -63,7 +63,9 @@
|
|
|
63
63
|
background: var(--background);
|
|
64
64
|
border-color: var(--border-contrast);
|
|
65
65
|
|
|
66
|
-
.label
|
|
66
|
+
.label,
|
|
67
|
+
.key,
|
|
68
|
+
.value {
|
|
67
69
|
color: var(--font-disabled);
|
|
68
70
|
}
|
|
69
71
|
|
|
@@ -105,6 +107,25 @@
|
|
|
105
107
|
@include typography.ellipsis;
|
|
106
108
|
}
|
|
107
109
|
|
|
110
|
+
.keyValue {
|
|
111
|
+
min-width: 0;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.key {
|
|
115
|
+
flex-shrink: 0;
|
|
116
|
+
color: var(--font-main);
|
|
117
|
+
|
|
118
|
+
&::after {
|
|
119
|
+
content: ':';
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.value {
|
|
124
|
+
@include typography.ellipsis;
|
|
125
|
+
|
|
126
|
+
color: var(--font-secondary);
|
|
127
|
+
}
|
|
128
|
+
|
|
108
129
|
.icon {
|
|
109
130
|
flex-shrink: 0;
|
|
110
131
|
display: flex;
|
|
@@ -3,6 +3,7 @@ import classNames from 'classnames';
|
|
|
3
3
|
import styles from './ds-tag.module.scss';
|
|
4
4
|
import type { DsTagProps } from './ds-tag.types';
|
|
5
5
|
import { DsIcon } from '../ds-icon';
|
|
6
|
+
import { DsStack } from '../ds-stack';
|
|
6
7
|
import { DsTypography } from '../ds-typography';
|
|
7
8
|
|
|
8
9
|
/**
|
|
@@ -11,6 +12,7 @@ import { DsTypography } from '../ds-typography';
|
|
|
11
12
|
const DsTag = ({
|
|
12
13
|
ref,
|
|
13
14
|
label,
|
|
15
|
+
value,
|
|
14
16
|
className,
|
|
15
17
|
style = {},
|
|
16
18
|
size = 'medium',
|
|
@@ -102,9 +104,20 @@ const DsTag = ({
|
|
|
102
104
|
))}
|
|
103
105
|
</span>
|
|
104
106
|
)}
|
|
105
|
-
|
|
106
|
-
{
|
|
107
|
-
|
|
107
|
+
{variant === 'key-value' ? (
|
|
108
|
+
<DsStack direction="row" alignItems="center" gap="var(--3xs)" className={styles.keyValue}>
|
|
109
|
+
<DsTypography variant={size === 'small' ? 'body-xs-md' : 'body-sm-md'} className={styles.key}>
|
|
110
|
+
{label}
|
|
111
|
+
</DsTypography>
|
|
112
|
+
<DsTypography variant={size === 'small' ? 'body-xs-reg' : 'body-sm-reg'} className={styles.value}>
|
|
113
|
+
{value}
|
|
114
|
+
</DsTypography>
|
|
115
|
+
</DsStack>
|
|
116
|
+
) : (
|
|
117
|
+
<DsTypography variant={size === 'small' ? 'body-xs-reg' : 'body-sm-reg'} className={styles.label}>
|
|
118
|
+
{label}
|
|
119
|
+
</DsTypography>
|
|
120
|
+
)}
|
|
108
121
|
{onDelete && !disabled && (
|
|
109
122
|
<button
|
|
110
123
|
type="button"
|
|
@@ -3,16 +3,16 @@ import type { CSSProperties, KeyboardEvent, MouseEvent, ReactNode, Ref } from 'r
|
|
|
3
3
|
export const tagSizes = ['medium', 'small'] as const;
|
|
4
4
|
export type TagSize = (typeof tagSizes)[number];
|
|
5
5
|
|
|
6
|
-
export const tagVariants = ['default', 'include', 'exclude'] as const;
|
|
6
|
+
export const tagVariants = ['default', 'include', 'exclude', 'key-value'] as const;
|
|
7
7
|
export type TagVariant = (typeof tagVariants)[number];
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
interface DsTagBaseProps {
|
|
10
10
|
/**
|
|
11
11
|
* Ref to the tag element
|
|
12
12
|
*/
|
|
13
13
|
ref?: Ref<HTMLElement>;
|
|
14
14
|
/**
|
|
15
|
-
* The label text to display in the tag
|
|
15
|
+
* The label text to display in the tag. For the `key-value` variant this is the key.
|
|
16
16
|
*/
|
|
17
17
|
label: ReactNode;
|
|
18
18
|
/**
|
|
@@ -50,11 +50,6 @@ export interface DsTagProps {
|
|
|
50
50
|
* @default false
|
|
51
51
|
*/
|
|
52
52
|
selected?: boolean;
|
|
53
|
-
/**
|
|
54
|
-
* Variant of the tag
|
|
55
|
-
* @default 'default'
|
|
56
|
-
*/
|
|
57
|
-
variant?: TagVariant;
|
|
58
53
|
/**
|
|
59
54
|
* Whether the tag is disabled
|
|
60
55
|
* @default false
|
|
@@ -71,3 +66,22 @@ export interface DsTagProps {
|
|
|
71
66
|
icon?: ReactNode;
|
|
72
67
|
};
|
|
73
68
|
}
|
|
69
|
+
|
|
70
|
+
interface DsTagStandardProps extends DsTagBaseProps {
|
|
71
|
+
/**
|
|
72
|
+
* Variant of the tag
|
|
73
|
+
* @default 'default'
|
|
74
|
+
*/
|
|
75
|
+
variant?: 'default' | 'include' | 'exclude';
|
|
76
|
+
value?: never;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
interface DsTagKeyValueProps extends DsTagBaseProps {
|
|
80
|
+
variant: 'key-value';
|
|
81
|
+
/**
|
|
82
|
+
* Secondary-colored value rendered after the key (`label`). Required for the `key-value` variant.
|
|
83
|
+
*/
|
|
84
|
+
value: ReactNode;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export type DsTagProps = DsTagStandardProps | DsTagKeyValueProps;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/* eslint-disable vitest/expect-expect */
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
import { describe, expectTypeOf, it } from 'vitest';
|
|
4
|
+
import type { DsTagProps, TagVariant } from './ds-tag.types';
|
|
5
|
+
|
|
6
|
+
describe('DsTagProps discriminated union', () => {
|
|
7
|
+
it('includes key-value in the variant union', () => {
|
|
8
|
+
expectTypeOf<TagVariant>().toEqualTypeOf<'default' | 'include' | 'exclude' | 'key-value'>();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('allows standard variants without a value', () => {
|
|
12
|
+
expectTypeOf<{ label: string }>().toExtend<DsTagProps>();
|
|
13
|
+
expectTypeOf<{ label: string; variant: 'default' }>().toExtend<DsTagProps>();
|
|
14
|
+
expectTypeOf<{ label: string; variant: 'include' }>().toExtend<DsTagProps>();
|
|
15
|
+
expectTypeOf<{ label: string; variant: 'exclude' }>().toExtend<DsTagProps>();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('requires a value for the key-value variant', () => {
|
|
19
|
+
expectTypeOf<{ label: string; variant: 'key-value'; value: string }>().toExtend<DsTagProps>();
|
|
20
|
+
expectTypeOf<{ label: string; variant: 'key-value' }>().not.toExtend<DsTagProps>();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('forbids a value on standard variants', () => {
|
|
24
|
+
expectTypeOf<{ label: string; value: string }>().not.toExtend<DsTagProps>();
|
|
25
|
+
expectTypeOf<{ label: string; variant: 'default'; value: string }>().not.toExtend<DsTagProps>();
|
|
26
|
+
expectTypeOf<{ label: string; variant: 'include'; value: string }>().not.toExtend<DsTagProps>();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('types the key-value value as ReactNode', () => {
|
|
30
|
+
expectTypeOf<Extract<DsTagProps, { variant: 'key-value' }>['value']>().toEqualTypeOf<ReactNode>();
|
|
31
|
+
});
|
|
32
|
+
});
|
|
@@ -5,7 +5,7 @@ import styles from './ds-tag-filter.module.scss';
|
|
|
5
5
|
import type { DsTagFilterProps, TagFilterItem } from './ds-tag-filter.types';
|
|
6
6
|
import { useTagOverflowCalculation } from './hooks/use-tag-overflow-calculation';
|
|
7
7
|
import { DsTypography } from '../ds-typography';
|
|
8
|
-
import { DsTag } from '../ds-tag';
|
|
8
|
+
import { DsTag, type DsTagProps } from '../ds-tag';
|
|
9
9
|
import { DsButton } from '../ds-button';
|
|
10
10
|
import { DsIcon } from '../ds-icon';
|
|
11
11
|
|
|
@@ -51,20 +51,19 @@ const DsTagFilter = ({
|
|
|
51
51
|
return null;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
// Merging per-item overrides with the filter-controlled props drops the
|
|
55
|
+
// discriminated-union narrowing of `DsTagProps` (a known TS spread limitation),
|
|
56
|
+
// so build the props once and assert the union type.
|
|
57
|
+
const buildTagProps = (item: TagFilterItem): DsTagProps =>
|
|
58
|
+
({
|
|
59
|
+
...item.slotProps?.tag,
|
|
60
|
+
label: item.label,
|
|
61
|
+
selected: item.selected,
|
|
62
|
+
onClick: onItemSelect ? () => onItemSelect(item) : undefined,
|
|
63
|
+
onDelete: onItemDelete ? () => onItemDelete(item) : undefined,
|
|
64
|
+
}) as DsTagProps;
|
|
56
65
|
|
|
57
|
-
|
|
58
|
-
<DsTag
|
|
59
|
-
{...tagProps}
|
|
60
|
-
key={item.id}
|
|
61
|
-
label={item.label}
|
|
62
|
-
selected={item.selected}
|
|
63
|
-
onClick={onItemSelect ? () => onItemSelect(item) : undefined}
|
|
64
|
-
onDelete={onItemDelete ? () => onItemDelete(item) : undefined}
|
|
65
|
-
/>
|
|
66
|
-
);
|
|
67
|
-
};
|
|
66
|
+
const renderTag = (item: TagFilterItem) => <DsTag key={item.id} {...buildTagProps(item)} />;
|
|
68
67
|
|
|
69
68
|
const handleExpandToggle = () => {
|
|
70
69
|
const newExpanded = !expanded;
|
|
@@ -75,14 +74,7 @@ const DsTagFilter = ({
|
|
|
75
74
|
const measurementContainer = (
|
|
76
75
|
<div ref={measurementRef} className={styles.measurementContainer} aria-hidden="true">
|
|
77
76
|
{items.map((item) => (
|
|
78
|
-
<DsTag
|
|
79
|
-
key={item.id}
|
|
80
|
-
data-measure-tag=""
|
|
81
|
-
label={item.label}
|
|
82
|
-
selected={item.selected}
|
|
83
|
-
onClick={onItemSelect ? () => onItemSelect(item) : undefined}
|
|
84
|
-
onDelete={onItemDelete ? () => onItemDelete(item) : undefined}
|
|
85
|
-
/>
|
|
77
|
+
<DsTag key={item.id} data-measure-tag="" {...buildTagProps(item)} />
|
|
86
78
|
))}
|
|
87
79
|
</div>
|
|
88
80
|
);
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// url=https://www.figma.com/design/nha3m67y7S57cHCSuQO2gp/DAP-Design-System-1.2?node-id=13346-18325
|
|
2
|
+
// source=https://github.com/drivenets/design-system/tree/main/packages/design-system/src/components/ds-text-input
|
|
3
|
+
// component=DsTextInput
|
|
4
|
+
//
|
|
5
|
+
// The Figma component `DAP_input_v01` is a single multi-type input. Its `Type`
|
|
6
|
+
// variant selects which code component to render:
|
|
7
|
+
// Number -> DsNumberInput
|
|
8
|
+
// Password -> DsPasswordInput
|
|
9
|
+
// Standard/Error/Read -> DsTextInput
|
|
10
|
+
import figma from 'figma';
|
|
11
|
+
|
|
12
|
+
const instance = figma.selectedInstance;
|
|
13
|
+
|
|
14
|
+
const type = instance.getEnum('Type', {
|
|
15
|
+
Standard: 'standard',
|
|
16
|
+
Error: 'error',
|
|
17
|
+
'Read Only': 'readOnly',
|
|
18
|
+
Number: 'number',
|
|
19
|
+
Password: 'password',
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const size = instance.getEnum('Size', {
|
|
23
|
+
Small: 'small',
|
|
24
|
+
Default: 'default',
|
|
25
|
+
Large: 'default',
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const state = instance.getEnum('State', {
|
|
29
|
+
Default: 'default',
|
|
30
|
+
Hover: 'hover',
|
|
31
|
+
'Focus/ Typing': 'focus',
|
|
32
|
+
Disabled: 'disabled',
|
|
33
|
+
'Read only': 'readOnly',
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const disabled = state === 'disabled';
|
|
37
|
+
const readOnly = type === 'readOnly' || state === 'readOnly';
|
|
38
|
+
|
|
39
|
+
const sizeAttr = size === 'small' ? 'size="small"' : '';
|
|
40
|
+
|
|
41
|
+
const componentName =
|
|
42
|
+
type === 'number' ? 'DsNumberInput' : type === 'password' ? 'DsPasswordInput' : 'DsTextInput';
|
|
43
|
+
|
|
44
|
+
// `DsFormControl` member name and attribute string, surfaced so a parent `DsFormControl`
|
|
45
|
+
// template can emit `<DsFormControl.${fcMember} ${fcProps} />`.
|
|
46
|
+
const fcMember = type === 'number' ? 'NumberInput' : type === 'password' ? 'PasswordInput' : 'TextInput';
|
|
47
|
+
|
|
48
|
+
const fcProps = [sizeAttr, disabled ? 'disabled' : '', readOnly ? 'readOnly' : ''].filter(Boolean).join(' ');
|
|
49
|
+
|
|
50
|
+
export default {
|
|
51
|
+
example:
|
|
52
|
+
type === 'number'
|
|
53
|
+
? figma.code`<DsNumberInput ${sizeAttr} ${disabled ? 'disabled' : ''} />`
|
|
54
|
+
: type === 'password'
|
|
55
|
+
? figma.code`<DsPasswordInput ${sizeAttr} ${disabled ? 'disabled' : ''} />`
|
|
56
|
+
: figma.code`<DsTextInput ${sizeAttr} ${disabled ? 'disabled' : ''} ${readOnly ? 'readOnly' : ''} />`,
|
|
57
|
+
imports: [`import { ${componentName} } from '@drivenets/design-system'`],
|
|
58
|
+
id: 'ds-text-input',
|
|
59
|
+
metadata: { nestable: true, props: { fcMember, fcProps } },
|
|
60
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// url=https://www.figma.com/design/nha3m67y7S57cHCSuQO2gp/DAP-Design-System-1.2?node-id=30102-172478
|
|
2
|
+
// source=https://github.com/drivenets/design-system/tree/main/packages/design-system/src/components/ds-time-picker
|
|
3
|
+
// component=DsTimePicker
|
|
4
|
+
//
|
|
5
|
+
// `DAP_hh_mm_drop_down_v1.0` exposes no component properties. The snippet is therefore an
|
|
6
|
+
// illustrative controlled-usage starter (props are not derived from Figma) showing the
|
|
7
|
+
// idiomatic `useState` + `value`/`onChange` pattern. `fcMember`/`fcProps` are surfaced so
|
|
8
|
+
// a parent `DsFormControl` template can render `<DsFormControl.TimePicker />`.
|
|
9
|
+
import figma from 'figma';
|
|
10
|
+
|
|
11
|
+
export default {
|
|
12
|
+
example: figma.code`const [value, setValue] = useState<Date | null>(null);
|
|
13
|
+
|
|
14
|
+
<DsTimePicker value={value} onChange={setValue} placeholder="hh:mm AM/PM" />`,
|
|
15
|
+
imports: ["import { useState } from 'react'", "import { DsTimePicker } from '@drivenets/design-system'"],
|
|
16
|
+
id: 'ds-time-picker',
|
|
17
|
+
metadata: { nestable: true, props: { fcMember: 'TimePicker', fcProps: '' } },
|
|
18
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -39,6 +39,7 @@ export * from './components/ds-popover';
|
|
|
39
39
|
export * from './components/ds-progress-arc';
|
|
40
40
|
export * from './components/ds-progress-donut';
|
|
41
41
|
export * from './components/ds-progress-linear';
|
|
42
|
+
export * from './components/ds-progress-task-bar';
|
|
42
43
|
export * from './components/ds-radio-group';
|
|
43
44
|
export * from './components/ds-segment-group';
|
|
44
45
|
export * from './components/ds-select';
|
|
@@ -264,6 +264,7 @@
|
|
|
264
264
|
--background-secondary-hover: var(--color-dap-blue-050);
|
|
265
265
|
--background-secondary-selected-weak: var(--color-dap-gray-100);
|
|
266
266
|
--background-success: var(--color-dap-green-075);
|
|
267
|
+
--background-success-medium: var(--color-dap-green-500);
|
|
267
268
|
--background-success-strong: var(--color-dap-green-600);
|
|
268
269
|
--background-success-strong-hover: var(--color-dap-green-700);
|
|
269
270
|
--background-tertiary: var(--color-dap-gray-200);
|
|
@@ -327,6 +328,7 @@
|
|
|
327
328
|
--icon-secondary: var(--color-dap-gray-600);
|
|
328
329
|
--icon-success: var(--color-dap-green-700);
|
|
329
330
|
--icon-success-light: var(--color-dap-green-400);
|
|
331
|
+
--icon-tertiary: var(--color-dap-brand-200);
|
|
330
332
|
--icon-warning: var(--color-dap-orange-600);
|
|
331
333
|
--icon-warning-light: var(--color-dap-orange-400);
|
|
332
334
|
--light-buttons-primary: var(--color-dap-dark-blue-300);
|
|
@@ -1,44 +1,12 @@
|
|
|
1
1
|
$scrollbar-border-radius: 100px;
|
|
2
|
-
$scrollbar-default-size:
|
|
3
|
-
$scrollbar-
|
|
2
|
+
$scrollbar-default-size: 10px;
|
|
3
|
+
$scrollbar-hover-size: 12px;
|
|
4
|
+
$scrollbar-thin-size: 8px;
|
|
4
5
|
|
|
5
|
-
@mixin scrollbar-
|
|
6
|
+
@mixin scrollbar-auto-hide($rest-size, $hover-size) {
|
|
6
7
|
&::-webkit-scrollbar {
|
|
7
|
-
width: $size;
|
|
8
|
-
height: $size;
|
|
9
|
-
background: var(--background-secondary);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
&::-webkit-scrollbar-track {
|
|
13
|
-
background: var(--background-secondary);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
&::-webkit-scrollbar-thumb {
|
|
17
|
-
background: var(--background-deselected-hover);
|
|
18
|
-
border-radius: $scrollbar-border-radius;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
&::-webkit-scrollbar-corner {
|
|
22
|
-
background: var(--background-secondary);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
@mixin firefox-scrollbar($size) {
|
|
27
|
-
@-moz-document url-prefix() {
|
|
28
|
-
@if $size == $scrollbar-thin-size {
|
|
29
|
-
scrollbar-width: thin;
|
|
30
|
-
} @else {
|
|
31
|
-
scrollbar-width: auto;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
scrollbar-color: var(--background-deselected-hover) var(--background-secondary);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
@mixin scrollbar-on-hover {
|
|
39
|
-
&::-webkit-scrollbar {
|
|
40
|
-
width: $scrollbar-thin-size;
|
|
41
|
-
height: $scrollbar-thin-size;
|
|
8
|
+
width: $rest-size;
|
|
9
|
+
height: $rest-size;
|
|
42
10
|
background: transparent;
|
|
43
11
|
}
|
|
44
12
|
|
|
@@ -51,33 +19,42 @@ $scrollbar-thin-size: 4px;
|
|
|
51
19
|
}
|
|
52
20
|
|
|
53
21
|
&::-webkit-scrollbar-thumb {
|
|
54
|
-
background-color:
|
|
22
|
+
background-color: var(--background-tertiary);
|
|
55
23
|
border-radius: $scrollbar-border-radius;
|
|
56
24
|
transition: background-color 0.2s;
|
|
57
25
|
}
|
|
58
26
|
|
|
59
|
-
&:hover
|
|
60
|
-
|
|
61
|
-
|
|
27
|
+
&:hover {
|
|
28
|
+
&::-webkit-scrollbar {
|
|
29
|
+
width: $hover-size;
|
|
30
|
+
height: $hover-size;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
&::-webkit-scrollbar-track {
|
|
34
|
+
background: var(--background-secondary);
|
|
35
|
+
}
|
|
62
36
|
|
|
63
|
-
|
|
64
|
-
|
|
37
|
+
&::-webkit-scrollbar-thumb {
|
|
38
|
+
background-color: var(--background-deselected-hover);
|
|
39
|
+
}
|
|
65
40
|
}
|
|
66
41
|
|
|
67
42
|
scrollbar-width: thin;
|
|
68
|
-
scrollbar-color:
|
|
43
|
+
scrollbar-color: var(--background-tertiary) transparent;
|
|
69
44
|
|
|
70
45
|
&:hover {
|
|
71
|
-
scrollbar-color: var(--background-
|
|
46
|
+
scrollbar-color: var(--background-deselected-hover) var(--background-secondary);
|
|
72
47
|
}
|
|
73
48
|
}
|
|
74
49
|
|
|
50
|
+
@mixin scrollbar-on-hover {
|
|
51
|
+
@include scrollbar-auto-hide($scrollbar-default-size, $scrollbar-hover-size);
|
|
52
|
+
}
|
|
53
|
+
|
|
75
54
|
* {
|
|
76
|
-
@include scrollbar-
|
|
77
|
-
@include firefox-scrollbar($scrollbar-default-size);
|
|
55
|
+
@include scrollbar-auto-hide($scrollbar-default-size, $scrollbar-hover-size);
|
|
78
56
|
}
|
|
79
57
|
|
|
80
58
|
.scrollbar-thin {
|
|
81
|
-
@include scrollbar-
|
|
82
|
-
@include firefox-scrollbar($scrollbar-thin-size);
|
|
59
|
+
@include scrollbar-auto-hide($scrollbar-thin-size, $scrollbar-thin-size);
|
|
83
60
|
}
|