@drivenets/design-system 0.6.1 → 0.7.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 +27 -0
- package/dist/index.cjs +12394 -8354
- package/dist/index.d.cts +806 -118
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +806 -118
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12376 -8357
- package/dist/index.js.map +1 -1
- package/dist/index.min.css +1 -1
- package/package.json +25 -23
- package/src/components/ds-autocomplete/ds-autocomplete.module.scss +2 -1
- package/src/components/ds-autocomplete/ds-autocomplete.tsx +47 -40
- package/src/components/ds-autocomplete/ds-autocomplete.types.tsx +37 -14
- package/src/components/ds-button/versions/ds-button-new/ds-button-new.module.scss +3 -7
- package/src/components/ds-comment-bubble/components/ds-comment-thread/ds-comment-thread.module.scss +62 -0
- package/src/components/ds-comment-bubble/components/ds-comment-thread/ds-comment-thread.tsx +83 -0
- package/src/components/ds-comment-bubble/components/ds-comment-thread/ds-comment-thread.types.ts +12 -0
- package/src/components/ds-comment-bubble/components/ds-comment-thread/index.ts +2 -0
- package/src/components/ds-comment-bubble/components/ds-thread-item/ds-thread-item.module.scss +149 -0
- package/src/components/ds-comment-bubble/components/ds-thread-item/ds-thread-item.tsx +147 -0
- package/src/components/ds-comment-bubble/components/ds-thread-item/ds-thread-item.types.ts +15 -0
- package/src/components/ds-comment-bubble/components/ds-thread-item/index.ts +2 -0
- package/src/components/ds-comment-bubble/ds-comment-bubble.module.scss +298 -0
- package/src/components/ds-comment-bubble/ds-comment-bubble.tsx +241 -0
- package/src/components/ds-comment-bubble/ds-comment-bubble.types.ts +27 -0
- package/src/components/ds-comment-bubble/hooks/index.ts +3 -0
- package/src/components/ds-comment-bubble/hooks/use-auto-resize.ts +17 -0
- package/src/components/ds-comment-bubble/hooks/use-click-outside.ts +22 -0
- package/src/components/ds-comment-bubble/hooks/use-scroll-overflow.ts +27 -0
- package/src/components/ds-comment-bubble/index.ts +6 -0
- package/src/components/ds-comment-card/ds-comment-card.module.scss +162 -0
- package/src/components/ds-comment-card/ds-comment-card.tsx +171 -0
- package/src/components/ds-comment-card/ds-comment-card.types.ts +45 -0
- package/src/components/ds-comment-card/index.ts +2 -0
- package/src/components/ds-comment-indicator/ds-comment-indicator.module.scss +65 -0
- package/src/components/ds-comment-indicator/ds-comment-indicator.tsx +48 -0
- package/src/components/ds-comment-indicator/ds-comment-indicator.types.ts +13 -0
- package/src/components/ds-comment-indicator/index.ts +2 -0
- package/src/components/ds-comments-drawer/comments-filters.test.ts +483 -0
- package/src/components/ds-comments-drawer/comments-filters.ts +134 -0
- package/src/components/ds-comments-drawer/comments-filters.types.ts +14 -0
- package/src/components/ds-comments-drawer/components/comments-filter-modal/comments-filter-modal.module.scss +92 -0
- package/src/components/ds-comments-drawer/components/comments-filter-modal/comments-filter-modal.tsx +219 -0
- package/src/components/ds-comments-drawer/components/comments-filter-modal/comments-filter-modal.types.ts +12 -0
- package/src/components/ds-comments-drawer/components/comments-filter-modal/index.ts +2 -0
- package/src/components/ds-comments-drawer/ds-comments-drawer.module.scss +67 -0
- package/src/components/ds-comments-drawer/ds-comments-drawer.tsx +215 -0
- package/src/components/ds-comments-drawer/ds-comments-drawer.types.ts +23 -0
- package/src/components/ds-comments-drawer/index.ts +3 -0
- package/src/components/ds-dropdown-menu/ds-dropdown-menu.tsx +2 -0
- package/src/components/ds-expandable-text-input/ds-expandable-text-input.tsx +8 -4
- package/src/components/ds-file-upload/types/accept-types.ts +0 -1
- package/src/components/ds-filter-status-icon/ds-filter-status-icon.module.scss +19 -0
- package/src/components/ds-filter-status-icon/ds-filter-status-icon.tsx +35 -0
- package/src/components/ds-filter-status-icon/ds-filter-status-icon.types.ts +31 -0
- package/src/components/ds-filter-status-icon/index.ts +3 -0
- package/src/components/ds-icon/custom-icons/index.ts +10 -0
- package/src/components/ds-icon/custom-icons/special-failed.tsx +16 -0
- package/src/components/ds-icon/custom-icons/special-paused.tsx +16 -0
- package/src/components/ds-icon/custom-icons/special-running.tsx +16 -0
- package/src/components/ds-icon/custom-icons/special-warning.tsx +16 -0
- package/src/components/ds-panel/ds-panel.module.scss +3 -3
- package/src/components/ds-progress-arc/ds-progress-arc.module.scss +57 -0
- package/src/components/ds-progress-arc/ds-progress-arc.tsx +111 -0
- package/src/components/ds-progress-arc/ds-progress-arc.types.ts +34 -0
- package/src/components/ds-progress-arc/index.ts +3 -0
- package/src/components/ds-progress-arc/utils.test.ts +79 -0
- package/src/components/ds-progress-arc/utils.ts +61 -0
- package/src/components/ds-progress-donut/ds-progress-donut.module.scss +67 -0
- package/src/components/ds-progress-donut/ds-progress-donut.tsx +83 -0
- package/src/components/ds-progress-donut/ds-progress-donut.types.ts +38 -0
- package/src/components/ds-progress-donut/index.ts +2 -0
- package/src/components/ds-progress-donut/utils.ts +1 -0
- package/src/components/ds-progress-linear/ds-progress-linear.module.scss +100 -0
- package/src/components/ds-progress-linear/ds-progress-linear.tsx +107 -0
- package/src/components/ds-progress-linear/ds-progress-linear.types.ts +72 -0
- package/src/components/ds-progress-linear/index.ts +2 -0
- package/src/components/ds-progress-linear/utils.test.ts +70 -0
- package/src/components/ds-progress-linear/utils.ts +7 -0
- package/src/components/ds-radio-group/ds-radio-group.tsx +2 -0
- package/src/components/ds-select/ds-select.tsx +2 -1
- package/src/components/ds-select/ds-select.types.tsx +7 -0
- package/src/components/ds-stepper/components/ds-step.tsx +1 -1
- package/src/components/ds-stepper/ds-stepper.module.scss +16 -2
- package/src/components/ds-stepper/ds-stepper.tsx +3 -1
- package/src/components/ds-table/components/ds-table-body-virtualized/ds-table-body-virtualized.module.scss +9 -0
- package/src/components/ds-table/components/ds-table-body-virtualized/ds-table-body-virtualized.tsx +137 -0
- package/src/components/ds-table/components/ds-table-body-virtualized/ds-table-body-virtualized.types.ts +22 -0
- package/src/components/ds-table/components/ds-table-body-virtualized/index.ts +2 -0
- package/src/components/ds-table/components/ds-table-cell/ds-table-cell.module.scss +3 -1
- package/src/components/ds-table/components/ds-table-header/ds-table-header.module.scss +7 -10
- package/src/components/ds-table/components/ds-table-header/ds-table-header.tsx +3 -4
- package/src/components/ds-table/components/ds-table-row/ds-table-row.module.scss +13 -53
- package/src/components/ds-table/components/ds-table-row/ds-table-row.tsx +32 -85
- package/src/components/ds-table/components/ds-table-row/ds-table-row.types.ts +0 -6
- package/src/components/ds-table/components/ds-table-row-expandable-cell/ds-table-row-expandable-cell.module.scss +10 -0
- package/src/components/ds-table/components/ds-table-row-expandable-cell/ds-table-row-expandable-cell.tsx +45 -0
- package/src/components/ds-table/components/ds-table-row-expandable-cell/ds-table-row-expandable-cell.types.ts +7 -0
- package/src/components/ds-table/components/ds-table-row-expandable-cell/index.ts +2 -0
- package/src/components/ds-table/components/ds-table-row-selectable-cell/ds-table-row-selectable-cell.module.scss +6 -0
- package/src/components/ds-table/components/ds-table-row-selectable-cell/ds-table-row-selectable-cell.tsx +30 -0
- package/src/components/ds-table/components/ds-table-row-selectable-cell/ds-table-row-selectable-cell.types.ts +6 -0
- package/src/components/ds-table/components/ds-table-row-selectable-cell/index.ts +2 -0
- package/src/components/ds-table/components/ds-table-row-virtualized/ds-table-row-virtualized.module.scss +80 -0
- package/src/components/ds-table/components/ds-table-row-virtualized/ds-table-row-virtualized.tsx +95 -0
- package/src/components/ds-table/components/ds-table-row-virtualized/ds-table-row-virtualized.types.ts +11 -0
- package/src/components/ds-table/components/ds-table-row-virtualized/index.ts +2 -0
- package/src/components/ds-table/context/ds-table-context.tsx +0 -9
- package/src/components/ds-table/ds-table.module.scss +4 -17
- package/src/components/ds-table/ds-table.tsx +44 -77
- package/src/components/ds-table/ds-table.types.ts +57 -12
- package/src/components/ds-table/index.ts +1 -0
- package/src/components/ds-table/styles/_mixins.scss +15 -0
- package/src/components/ds-table/styles/_variables.scss +2 -2
- package/src/components/ds-table/utils/{column-styling.ts → column-size.ts} +4 -14
- package/src/components/ds-table/utils/constants.ts +4 -0
- package/src/components/ds-tag/index.tsx +1 -0
- package/src/components/ds-tag-filter/ds-tag-filter.module.scss +13 -15
- package/src/components/ds-tag-filter/ds-tag-filter.tsx +38 -72
- package/src/components/ds-tag-filter/ds-tag-filter.types.ts +2 -3
- package/src/components/ds-tag-filter/hooks/use-tag-overflow-calculation.ts +12 -62
- package/src/components/ds-tag-filter/utils.test.ts +2 -108
- package/src/components/ds-tag-filter/utils.ts +2 -12
- package/src/components/ds-tree/ds-tree.module.scss +283 -0
- package/src/components/ds-tree/ds-tree.tsx +172 -0
- package/src/components/ds-tree/ds-tree.types.ts +83 -0
- package/src/components/ds-tree/ds-tree.utils.ts +11 -0
- package/src/components/ds-tree/index.ts +3 -0
- package/src/index.ts +9 -0
- package/src/utils/format-relative-time.test.ts +74 -0
- package/src/utils/format-relative-time.ts +52 -0
- package/src/utils/numbers.test.ts +24 -0
- package/src/utils/numbers.ts +1 -0
- package/src/components/ds-table/utils/create-columns-grid-template.ts +0 -23
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
import { Progress } from '@ark-ui/react';
|
|
3
|
+
import classNames from 'classnames';
|
|
4
|
+
|
|
5
|
+
import { DsIcon } from '../ds-icon';
|
|
6
|
+
import { DsTypography } from '../ds-typography';
|
|
7
|
+
import styles from './ds-progress-donut.module.scss';
|
|
8
|
+
import type {
|
|
9
|
+
DsProgressDonutProps,
|
|
10
|
+
ProgressDonutSize,
|
|
11
|
+
ProgressDonutVariant,
|
|
12
|
+
} from './ds-progress-donut.types';
|
|
13
|
+
import { clampValue } from './utils';
|
|
14
|
+
|
|
15
|
+
const sizeStyleMap: Record<ProgressDonutSize, string> = Object.freeze({
|
|
16
|
+
small: styles.small,
|
|
17
|
+
medium: styles.medium,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const variantStyleMap: Record<ProgressDonutVariant, string> = Object.freeze({
|
|
21
|
+
default: styles.default,
|
|
22
|
+
success: styles.success,
|
|
23
|
+
error: styles.error,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const DsProgressDonut = ({
|
|
27
|
+
value = 0,
|
|
28
|
+
size = 'medium',
|
|
29
|
+
variant = 'default',
|
|
30
|
+
children,
|
|
31
|
+
className,
|
|
32
|
+
style,
|
|
33
|
+
ref,
|
|
34
|
+
}: DsProgressDonutProps) => {
|
|
35
|
+
const effectiveValue = variant === 'success' ? 100 : clampValue(value);
|
|
36
|
+
|
|
37
|
+
const renderIcon = (iconName: 'check' | 'close', colorClass: string) => (
|
|
38
|
+
<DsIcon
|
|
39
|
+
variant="rounded"
|
|
40
|
+
icon={iconName}
|
|
41
|
+
size="large"
|
|
42
|
+
className={classNames({ [styles.iconMediumSize]: size === 'medium' }, colorClass)}
|
|
43
|
+
/>
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
const renderCenter = () => {
|
|
47
|
+
if (children) {
|
|
48
|
+
return children;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (variant === 'success') {
|
|
52
|
+
return renderIcon('check', styles.iconSuccess);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (variant === 'error') {
|
|
56
|
+
return renderIcon('close', styles.iconError);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<DsTypography variant={size === 'medium' ? 'heading3' : 'body-md-md'} asChild>
|
|
61
|
+
<span>{effectiveValue}%</span>
|
|
62
|
+
</DsTypography>
|
|
63
|
+
);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<Progress.Root
|
|
68
|
+
ref={ref as React.Ref<HTMLDivElement>}
|
|
69
|
+
value={effectiveValue}
|
|
70
|
+
className={classNames(styles.root, sizeStyleMap[size], variantStyleMap[variant], className)}
|
|
71
|
+
style={style}
|
|
72
|
+
>
|
|
73
|
+
<Progress.Circle className={styles.circle}>
|
|
74
|
+
<Progress.CircleTrack className={styles.track} />
|
|
75
|
+
<Progress.CircleRange className={styles.range} />
|
|
76
|
+
</Progress.Circle>
|
|
77
|
+
|
|
78
|
+
<div className={styles.center}>{renderCenter()}</div>
|
|
79
|
+
</Progress.Root>
|
|
80
|
+
);
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export default DsProgressDonut;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { CSSProperties, ReactNode, Ref } from 'react';
|
|
2
|
+
|
|
3
|
+
export const progressDonutSizes = ['small', 'medium'] as const;
|
|
4
|
+
export type ProgressDonutSize = (typeof progressDonutSizes)[number];
|
|
5
|
+
|
|
6
|
+
export const progressDonutVariants = ['default', 'success', 'error'] as const;
|
|
7
|
+
export type ProgressDonutVariant = (typeof progressDonutVariants)[number];
|
|
8
|
+
|
|
9
|
+
export interface DsProgressDonutProps {
|
|
10
|
+
/**
|
|
11
|
+
* Progress value between 0 and 100
|
|
12
|
+
* @default 0
|
|
13
|
+
*/
|
|
14
|
+
value?: number;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Size of the donut progress indicator
|
|
18
|
+
* @default 'medium'
|
|
19
|
+
*/
|
|
20
|
+
size?: ProgressDonutSize;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Visual variant of the donut progress indicator
|
|
24
|
+
* @default 'default'
|
|
25
|
+
*/
|
|
26
|
+
variant?: ProgressDonutVariant;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Custom content to display in the center of the donut, overriding the default text or icon
|
|
30
|
+
*/
|
|
31
|
+
children?: ReactNode;
|
|
32
|
+
|
|
33
|
+
className?: string;
|
|
34
|
+
|
|
35
|
+
style?: CSSProperties;
|
|
36
|
+
|
|
37
|
+
ref?: Ref<HTMLElement>;
|
|
38
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { clampValue } from '../../utils/numbers';
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
@use '../../styles/typography';
|
|
2
|
+
|
|
3
|
+
$border-radius: 4px;
|
|
4
|
+
|
|
5
|
+
.root {
|
|
6
|
+
display: flex;
|
|
7
|
+
flex-direction: column;
|
|
8
|
+
width: 100%;
|
|
9
|
+
|
|
10
|
+
&.sizeSmall {
|
|
11
|
+
gap: var(--spacing-4xs);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
&.sizeMedium,
|
|
15
|
+
&.sizeLarge {
|
|
16
|
+
gap: var(--spacing-3xs);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.header {
|
|
21
|
+
display: flex;
|
|
22
|
+
align-items: flex-start;
|
|
23
|
+
justify-content: space-between;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.label {
|
|
27
|
+
@include typography.body-sm-md;
|
|
28
|
+
color: var(--color-font-main);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.valueText {
|
|
32
|
+
@include typography.body-sm-reg;
|
|
33
|
+
color: var(--color-font-main);
|
|
34
|
+
flex-shrink: 0;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.track {
|
|
38
|
+
width: 100%;
|
|
39
|
+
background-color: var(--color-background-tertiary);
|
|
40
|
+
border-radius: $border-radius;
|
|
41
|
+
overflow: hidden;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.trackSmall {
|
|
45
|
+
height: 2px;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.trackMedium {
|
|
49
|
+
height: 4px;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.trackLarge {
|
|
53
|
+
height: 8px;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.range {
|
|
57
|
+
height: 100%;
|
|
58
|
+
border-radius: $border-radius;
|
|
59
|
+
transition: width 0.2s ease;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.variantProgress {
|
|
63
|
+
background-color: var(--color-background-selected);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.variantInterrupted {
|
|
67
|
+
background-color: var(--color-background-warning-strong);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.variantSuccess {
|
|
71
|
+
background-color: var(--color-background-success-strong);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.variantError {
|
|
75
|
+
background-color: var(--color-background-danger-strong);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.caption {
|
|
79
|
+
@include typography.body-xs-reg;
|
|
80
|
+
display: flex;
|
|
81
|
+
align-items: center;
|
|
82
|
+
gap: var(--spacing-3xs);
|
|
83
|
+
padding-top: var(--spacing-4xs);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.captionDefault {
|
|
87
|
+
color: var(--color-font-secondary);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.captionSuccess {
|
|
91
|
+
color: var(--color-background-success-strong);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.captionError {
|
|
95
|
+
color: var(--color-background-danger-strong);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.captionInterrupted {
|
|
99
|
+
color: var(--color-font-warning);
|
|
100
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { Progress } from '@ark-ui/react';
|
|
2
|
+
import classNames from 'classnames';
|
|
3
|
+
|
|
4
|
+
import { DsIcon, type IconName } from '../ds-icon';
|
|
5
|
+
|
|
6
|
+
import styles from './ds-progress-linear.module.scss';
|
|
7
|
+
import type { DsProgressLinearProps, ProgressLinearVariant } from './ds-progress-linear.types';
|
|
8
|
+
import { calculatePercentage } from './utils';
|
|
9
|
+
|
|
10
|
+
const rangeVariantClass: Record<ProgressLinearVariant, string | undefined> = Object.freeze({
|
|
11
|
+
initial: undefined,
|
|
12
|
+
progress: styles.variantProgress,
|
|
13
|
+
interrupted: styles.variantInterrupted,
|
|
14
|
+
success: styles.variantSuccess,
|
|
15
|
+
error: styles.variantError,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const captionVariantClass: Record<ProgressLinearVariant, string> = Object.freeze({
|
|
19
|
+
initial: styles.captionDefault,
|
|
20
|
+
progress: styles.captionDefault,
|
|
21
|
+
interrupted: styles.captionInterrupted,
|
|
22
|
+
success: styles.captionSuccess,
|
|
23
|
+
error: styles.captionError,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const captionIcon: Partial<Record<ProgressLinearVariant, IconName>> = Object.freeze({
|
|
27
|
+
success: 'check_circle',
|
|
28
|
+
error: 'cancel',
|
|
29
|
+
interrupted: 'warning',
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const sizeClass: Record<string, string> = Object.freeze({
|
|
33
|
+
small: styles.sizeSmall,
|
|
34
|
+
medium: styles.sizeMedium,
|
|
35
|
+
large: styles.sizeLarge,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const trackSizeClass: Record<string, string> = Object.freeze({
|
|
39
|
+
small: styles.trackSmall,
|
|
40
|
+
medium: styles.trackMedium,
|
|
41
|
+
large: styles.trackLarge,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Design system ProgressLinear component
|
|
46
|
+
*/
|
|
47
|
+
const DsProgressLinear = ({
|
|
48
|
+
value = 0,
|
|
49
|
+
min = 0,
|
|
50
|
+
max = 100,
|
|
51
|
+
variant = 'progress',
|
|
52
|
+
size = 'medium',
|
|
53
|
+
label,
|
|
54
|
+
showValue = true,
|
|
55
|
+
caption,
|
|
56
|
+
className,
|
|
57
|
+
style,
|
|
58
|
+
ref,
|
|
59
|
+
}: DsProgressLinearProps) => {
|
|
60
|
+
const hasHeader = label !== undefined || showValue;
|
|
61
|
+
const icon = captionIcon[variant];
|
|
62
|
+
const percentage = calculatePercentage(value, min, max);
|
|
63
|
+
|
|
64
|
+
const renderCaption = (caption?: DsProgressLinearProps['caption']) => {
|
|
65
|
+
if (caption === undefined) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (typeof caption !== 'string') {
|
|
70
|
+
return caption;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<div className={classNames(styles.caption, captionVariantClass[variant])}>
|
|
75
|
+
{icon && <DsIcon icon={icon} size="tiny" filled />}
|
|
76
|
+
<span>{caption}</span>
|
|
77
|
+
</div>
|
|
78
|
+
);
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<Progress.Root
|
|
83
|
+
ref={ref}
|
|
84
|
+
value={value}
|
|
85
|
+
min={min}
|
|
86
|
+
max={max}
|
|
87
|
+
className={classNames(styles.root, sizeClass[size], className)}
|
|
88
|
+
style={style}
|
|
89
|
+
>
|
|
90
|
+
{hasHeader && (
|
|
91
|
+
<div className={styles.header}>
|
|
92
|
+
{label && <Progress.Label className={styles.label}>{label}</Progress.Label>}
|
|
93
|
+
|
|
94
|
+
{showValue && <Progress.ValueText className={styles.valueText}>{percentage}%</Progress.ValueText>}
|
|
95
|
+
</div>
|
|
96
|
+
)}
|
|
97
|
+
|
|
98
|
+
<Progress.Track className={classNames(styles.track, trackSizeClass[size])}>
|
|
99
|
+
<Progress.Range className={classNames(styles.range, rangeVariantClass[variant])} />
|
|
100
|
+
</Progress.Track>
|
|
101
|
+
|
|
102
|
+
{renderCaption(caption)}
|
|
103
|
+
</Progress.Root>
|
|
104
|
+
);
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
export default DsProgressLinear;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
|
|
3
|
+
export const progressLinearVariants = ['initial', 'progress', 'interrupted', 'success', 'error'] as const;
|
|
4
|
+
export type ProgressLinearVariant = (typeof progressLinearVariants)[number];
|
|
5
|
+
|
|
6
|
+
export const progressLinearSizes = ['small', 'medium', 'large'] as const;
|
|
7
|
+
export type ProgressLinearSize = (typeof progressLinearSizes)[number];
|
|
8
|
+
|
|
9
|
+
export interface DsProgressLinearProps {
|
|
10
|
+
/**
|
|
11
|
+
* The current progress value (0–100)
|
|
12
|
+
* @default 0
|
|
13
|
+
*/
|
|
14
|
+
value?: number;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The minimum value
|
|
18
|
+
* @default 0
|
|
19
|
+
*/
|
|
20
|
+
min?: number;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The maximum value
|
|
24
|
+
* @default 100
|
|
25
|
+
*/
|
|
26
|
+
max?: number;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The visual variant controlling bar color and caption styling
|
|
30
|
+
* @default 'progress'
|
|
31
|
+
*/
|
|
32
|
+
variant?: ProgressLinearVariant;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The size of the progress bar track
|
|
36
|
+
* @default 'medium'
|
|
37
|
+
*/
|
|
38
|
+
size?: ProgressLinearSize;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Label displayed above the progress bar (left side)
|
|
42
|
+
*/
|
|
43
|
+
label?: React.ReactNode;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Whether to show the percentage value text (right side of label row)
|
|
47
|
+
* @default true
|
|
48
|
+
*/
|
|
49
|
+
showValue?: boolean;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Caption/helper text below the progress bar.
|
|
53
|
+
* When a string is provided, it is auto-styled with an icon and color based on the variant.
|
|
54
|
+
* When a ReactNode is provided, it is rendered as-is.
|
|
55
|
+
*/
|
|
56
|
+
caption?: React.ReactNode | string;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Additional CSS class names
|
|
60
|
+
*/
|
|
61
|
+
className?: string;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Additional styles to apply to the component
|
|
65
|
+
*/
|
|
66
|
+
style?: React.CSSProperties;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Ref to the root element
|
|
70
|
+
*/
|
|
71
|
+
ref?: React.Ref<HTMLDivElement>;
|
|
72
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { calculatePercentage } from './utils';
|
|
4
|
+
|
|
5
|
+
describe('calculatePercentage', () => {
|
|
6
|
+
it('should return 0 when max equals min', () => {
|
|
7
|
+
expect(calculatePercentage(50, 100, 100)).toBe(0);
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it('should return 0 when max is less than min', () => {
|
|
11
|
+
expect(calculatePercentage(50, 100, 50)).toBe(0);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('should calculate 0% for value at minimum', () => {
|
|
15
|
+
expect(calculatePercentage(0, 0, 100)).toBe(0);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('should calculate 100% for value at maximum', () => {
|
|
19
|
+
expect(calculatePercentage(100, 0, 100)).toBe(100);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('should calculate 50% for value at midpoint', () => {
|
|
23
|
+
expect(calculatePercentage(50, 0, 100)).toBe(50);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should round to nearest integer for fractional percentages', () => {
|
|
27
|
+
expect(calculatePercentage(33, 0, 100)).toBe(33);
|
|
28
|
+
expect(calculatePercentage(66, 0, 100)).toBe(66);
|
|
29
|
+
expect(calculatePercentage(67, 0, 100)).toBe(67);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should handle non-zero minimum values', () => {
|
|
33
|
+
expect(calculatePercentage(50, 25, 75)).toBe(50);
|
|
34
|
+
expect(calculatePercentage(25, 25, 75)).toBe(0);
|
|
35
|
+
expect(calculatePercentage(75, 25, 75)).toBe(100);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should handle negative values', () => {
|
|
39
|
+
expect(calculatePercentage(-50, -100, 0)).toBe(50);
|
|
40
|
+
expect(calculatePercentage(-100, -100, 0)).toBe(0);
|
|
41
|
+
expect(calculatePercentage(0, -100, 0)).toBe(100);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should handle decimal values and round correctly', () => {
|
|
45
|
+
expect(calculatePercentage(33.3, 0, 100)).toBe(33);
|
|
46
|
+
expect(calculatePercentage(33.5, 0, 100)).toBe(34);
|
|
47
|
+
expect(calculatePercentage(33.7, 0, 100)).toBe(34);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('should handle value below minimum (clamping not enforced)', () => {
|
|
51
|
+
// Component doesn't clamp values, so negative percentages are possible
|
|
52
|
+
expect(calculatePercentage(-10, 0, 100)).toBe(-10);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('should handle value above maximum (clamping not enforced)', () => {
|
|
56
|
+
// Component doesn't clamp values, so > 100% is possible
|
|
57
|
+
expect(calculatePercentage(150, 0, 100)).toBe(150);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should handle large numbers', () => {
|
|
61
|
+
expect(calculatePercentage(5000, 0, 10000)).toBe(50);
|
|
62
|
+
expect(calculatePercentage(1000000, 0, 2000000)).toBe(50);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('should handle small decimal ranges', () => {
|
|
66
|
+
expect(calculatePercentage(0.5, 0, 1)).toBe(50);
|
|
67
|
+
expect(calculatePercentage(0.25, 0, 1)).toBe(25);
|
|
68
|
+
expect(calculatePercentage(0.75, 0, 1)).toBe(75);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
@@ -64,6 +64,7 @@ const Item: React.FC<DsRadioGroupItemProps> = ({
|
|
|
64
64
|
* Use compound component pattern instead: DsRadioGroup.Root + DsRadioGroup.Item
|
|
65
65
|
* @deprecated
|
|
66
66
|
*/
|
|
67
|
+
/* c8 ignore start */
|
|
67
68
|
export const DsRadioGroupLegacy: React.FC<DsRadioGroupLegacyProps> = ({
|
|
68
69
|
options,
|
|
69
70
|
value,
|
|
@@ -99,6 +100,7 @@ export const DsRadioGroupLegacy: React.FC<DsRadioGroupLegacyProps> = ({
|
|
|
99
100
|
))}
|
|
100
101
|
</RadioGroupPrimitive.Root>
|
|
101
102
|
);
|
|
103
|
+
/* c8 ignore stop */
|
|
102
104
|
|
|
103
105
|
/**
|
|
104
106
|
* Design system RadioGroup component
|
|
@@ -30,6 +30,7 @@ const DsSelect = ({
|
|
|
30
30
|
className,
|
|
31
31
|
placeholder = 'Click to select a value',
|
|
32
32
|
disabled,
|
|
33
|
+
renderOption,
|
|
33
34
|
...multiselectProps
|
|
34
35
|
}: DsSelectProps) => {
|
|
35
36
|
const [searchTerm, setSearchTerm] = useState('');
|
|
@@ -191,7 +192,7 @@ const DsSelect = ({
|
|
|
191
192
|
<Select.Item item={item}>
|
|
192
193
|
{multiselectProps.multiple && <DsCheckbox checked={checked} />}
|
|
193
194
|
{item.icon && <DsIcon className={styles.itemIcon} icon={item.icon} aria-hidden="true" />}
|
|
194
|
-
<Select.ItemText>{item.label}</Select.ItemText>
|
|
195
|
+
<Select.ItemText>{renderOption ? renderOption(item) : item.label}</Select.ItemText>
|
|
195
196
|
</Select.Item>
|
|
196
197
|
</DsTypography>
|
|
197
198
|
);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
2
3
|
import type { IconName } from '../ds-icon';
|
|
3
4
|
|
|
4
5
|
export type SelectSize = 'default' | 'small';
|
|
@@ -56,6 +57,12 @@ export type DsSelectProps = {
|
|
|
56
57
|
* @default 'default'
|
|
57
58
|
*/
|
|
58
59
|
size?: SelectSize;
|
|
60
|
+
/**
|
|
61
|
+
* Custom render function for dropdown options.
|
|
62
|
+
* When provided, replaces the default label text inside each dropdown item.
|
|
63
|
+
* The string `label` is still used for search, trigger text, chips, and accessibility.
|
|
64
|
+
*/
|
|
65
|
+
renderOption?: (option: DsSelectOption) => ReactNode;
|
|
59
66
|
} & (
|
|
60
67
|
| {
|
|
61
68
|
clearable?: undefined | false;
|
|
@@ -109,7 +109,7 @@ export function DsStep({
|
|
|
109
109
|
<div {...context.stepsApi.getIndicatorProps({ index })} className={styles.indicatorContainer}>
|
|
110
110
|
{renderIndicator()}
|
|
111
111
|
|
|
112
|
-
{!isHorizontal && <DsStepSeparator index={index} />}
|
|
112
|
+
{!isHorizontal && !isSingleVariant && <DsStepSeparator index={index} />}
|
|
113
113
|
</div>
|
|
114
114
|
|
|
115
115
|
{children}
|
|
@@ -32,6 +32,7 @@ $actions-gap: var(--spacing-3xs);
|
|
|
32
32
|
$drag-handle-size: 20px;
|
|
33
33
|
|
|
34
34
|
$horizontal-current-min-width: 256px;
|
|
35
|
+
$horizontal-other-min-width: 50px;
|
|
35
36
|
$horizontal-description-line-clamp: 2;
|
|
36
37
|
|
|
37
38
|
.dragHandle {
|
|
@@ -46,6 +47,10 @@ $horizontal-description-line-clamp: 2;
|
|
|
46
47
|
.root {
|
|
47
48
|
background: var(--color-background);
|
|
48
49
|
overflow-y: auto;
|
|
50
|
+
|
|
51
|
+
&.floating {
|
|
52
|
+
border-radius: inherit;
|
|
53
|
+
}
|
|
49
54
|
}
|
|
50
55
|
|
|
51
56
|
.verticalActions {
|
|
@@ -213,7 +218,7 @@ $horizontal-description-line-clamp: 2;
|
|
|
213
218
|
.stepsContainer {
|
|
214
219
|
display: flex;
|
|
215
220
|
flex: 1 1 0;
|
|
216
|
-
align-items:
|
|
221
|
+
align-items: stretch;
|
|
217
222
|
min-width: 0;
|
|
218
223
|
overflow-x: auto;
|
|
219
224
|
}
|
|
@@ -227,14 +232,23 @@ $horizontal-description-line-clamp: 2;
|
|
|
227
232
|
|
|
228
233
|
.step {
|
|
229
234
|
flex: 1 1 0;
|
|
235
|
+
align-self: stretch;
|
|
236
|
+
align-items: center;
|
|
230
237
|
padding: var(--spacing-3xs) var(--spacing-xs);
|
|
231
238
|
gap: var(--spacing-sm);
|
|
232
239
|
border-radius: var(--spacing-2xs);
|
|
233
240
|
overflow: clip;
|
|
241
|
+
min-width: $horizontal-other-min-width;
|
|
234
242
|
|
|
235
243
|
&[data-current] {
|
|
244
|
+
flex-grow: 2;
|
|
245
|
+
max-width: none;
|
|
236
246
|
min-width: $horizontal-current-min-width;
|
|
237
247
|
border-radius: var(--spacing-2xs);
|
|
248
|
+
|
|
249
|
+
.stepLabel {
|
|
250
|
+
flex-shrink: 0;
|
|
251
|
+
}
|
|
238
252
|
}
|
|
239
253
|
}
|
|
240
254
|
|
|
@@ -266,7 +280,7 @@ $horizontal-description-line-clamp: 2;
|
|
|
266
280
|
white-space: nowrap;
|
|
267
281
|
overflow: hidden;
|
|
268
282
|
text-overflow: ellipsis;
|
|
269
|
-
flex-shrink:
|
|
283
|
+
flex-shrink: 1;
|
|
270
284
|
}
|
|
271
285
|
|
|
272
286
|
.horizontalSeparator {
|
|
@@ -33,15 +33,17 @@ export function DsStepper({
|
|
|
33
33
|
{...stepsApi.getRootProps()}
|
|
34
34
|
className={classnames(
|
|
35
35
|
styles.root,
|
|
36
|
+
'scrollbar-thin',
|
|
36
37
|
{
|
|
37
38
|
[styles.variantSingle]: variant === 'single',
|
|
39
|
+
[styles.floating]: floating,
|
|
38
40
|
},
|
|
39
41
|
className,
|
|
40
42
|
)}
|
|
41
43
|
>
|
|
42
44
|
{isHorizontal ? (
|
|
43
45
|
<>
|
|
44
|
-
<div className={styles.stepsContainer}>{children}</div>
|
|
46
|
+
<div className={classnames(styles.stepsContainer, 'scrollbar-thin')}>{children}</div>
|
|
45
47
|
|
|
46
48
|
{actions && <div className={styles.horizontalActions}>{actions}</div>}
|
|
47
49
|
</>
|