@donkit-ai/design-system 0.2.18 → 0.2.19
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/README.md +178 -9
- package/package.json +1 -1
- package/src/components/Button.css +7 -0
- package/src/components/Card.css +9 -1
- package/src/components/Card.jsx +34 -1
- package/src/components/Input.css +23 -0
- package/src/components/Radio.css +115 -0
- package/src/components/Radio.jsx +42 -0
- package/src/components/Select.css +7 -0
- package/src/components/Select.jsx +1 -1
- package/src/components/Stepper.css +16 -0
- package/src/components/Stepper.jsx +1 -1
- package/src/components/Tabs.css +7 -0
- package/src/components/Textarea.css +6 -0
- package/src/index.js +1 -0
- package/src/styles/tokens.css +1 -0
package/README.md
CHANGED
|
@@ -37,13 +37,16 @@ npm install @donkit-ai/design-system@latest
|
|
|
37
37
|
|
|
38
38
|
## Компоненты
|
|
39
39
|
|
|
40
|
-
- **Button** - кнопки с вариантами (primary, secondary, ghost) и размерами (small, medium, large). Поддерживает `href` для рендера как ссылка
|
|
41
|
-
- **Tabs** - вкладки с состоянием selected в
|
|
42
|
-
- **Input** - текстовые поля с поддержкой иконок, ошибок и подсказок (small, medium)
|
|
43
|
-
- **
|
|
40
|
+
- **Button** - кнопки с вариантами (primary, secondary, ghost) и размерами (xs, small, medium, large). Поддерживает `href` для рендера как ссылка
|
|
41
|
+
- **Tabs** - вкладки с состоянием selected в четырех размерах (xs, small, medium, large). Поддерживает `href` для рендера как ссылка
|
|
42
|
+
- **Input** - текстовые поля с поддержкой иконок, ошибок и подсказок (xs, small, medium)
|
|
43
|
+
- **Textarea** - многострочное текстовое поле (xs, small, medium)
|
|
44
|
+
- **Select** - выпадающий список с кастомным дизайном (xs, small, medium)
|
|
45
|
+
- **Stepper** - числовое поле с кнопками +/- для изменения значения (xs, small, medium)
|
|
44
46
|
- **Toggle** - переключатель для включения/выключения опций (xs, small, medium, large)
|
|
45
47
|
- **Checkbox** - чекбокс для выбора опций (xs, small, medium, large)
|
|
46
|
-
- **
|
|
48
|
+
- **Radio** - радиокнопка для выбора одного варианта из группы (xs, small, medium, large)
|
|
49
|
+
- **Card** - карточки двух типов: info (информационная, прозрачный фон) и interactive (интерактивная с hover эффектом). Поддерживает `href` для рендера как ссылка
|
|
47
50
|
- **Typography** - H1-H4, P1-P3 компоненты
|
|
48
51
|
- **Code** - inline и block код с monospace шрифтом
|
|
49
52
|
- **Link** - ссылки акцентным цветом, при hover цвет меняется и появляется подчеркивание
|
|
@@ -113,20 +116,25 @@ import { iconSizes } from '@donkit-ai/design-system';
|
|
|
113
116
|
**Соответствие размеров компонентам:**
|
|
114
117
|
|
|
115
118
|
- **16px (xs)** - очень мелкие элементы
|
|
119
|
+
- Extra Small кнопки (`size="xs"`)
|
|
120
|
+
- Extra Small табы (`size="xs"`)
|
|
121
|
+
|
|
116
122
|
- **20px (s)** - компактные элементы
|
|
117
123
|
- Small кнопки (`size="small"`)
|
|
118
|
-
-
|
|
124
|
+
- Small табы (`size="small"`)
|
|
119
125
|
- Modal (иконка закрытия)
|
|
120
126
|
- Accordion, CodeAccordion
|
|
121
127
|
|
|
122
128
|
- **24px (m)** - стандартные элементы
|
|
123
129
|
- Medium кнопки (`size="medium"`, по умолчанию)
|
|
130
|
+
- Medium табы (`size="medium"`)
|
|
124
131
|
- Input (иконки в полях ввода)
|
|
125
132
|
- Alert (иконки статусов)
|
|
126
133
|
- Select (иконка выпадающего списка)
|
|
127
134
|
|
|
128
135
|
- **28px (l)** - крупные элементы
|
|
129
136
|
- Large кнопки (`size="large"`)
|
|
137
|
+
- Large табы (`size="large"`)
|
|
130
138
|
|
|
131
139
|
- **48px (xl)** - очень крупные элементы
|
|
132
140
|
|
|
@@ -334,6 +342,9 @@ document.documentElement.setAttribute('data-theme', 'light');
|
|
|
334
342
|
<Button variant="ghost">Ghost</Button>
|
|
335
343
|
|
|
336
344
|
// Размеры с соответствующими иконками
|
|
345
|
+
<Button size="xs" icon={<Mail size={16} strokeWidth={1.5} />}>
|
|
346
|
+
Extra Small
|
|
347
|
+
</Button>
|
|
337
348
|
<Button size="small" icon={<Mail size={20} strokeWidth={1.5} />}>
|
|
338
349
|
Small
|
|
339
350
|
</Button>
|
|
@@ -376,7 +387,8 @@ import { AlertCircle } from 'lucide-react';
|
|
|
376
387
|
</Tab>
|
|
377
388
|
</Tabs>
|
|
378
389
|
|
|
379
|
-
// With icons (
|
|
390
|
+
// With icons (размер иконки соответствует размеру таба)
|
|
391
|
+
// xs: 16px, small: 20px, medium: 24px, large: 28px
|
|
380
392
|
<Tabs size="small">
|
|
381
393
|
<Tab
|
|
382
394
|
selected={selectedTab === 'alerts'}
|
|
@@ -417,7 +429,7 @@ import { AlertCircle } from 'lucide-react';
|
|
|
417
429
|
- Hover: фон `--color-item-bg-hover`, текст `--color-txt-icon-1`
|
|
418
430
|
- Default: текст `--color-txt-icon-2`
|
|
419
431
|
|
|
420
|
-
**Размеры:** small, medium, large
|
|
432
|
+
**Размеры:** xs, small, medium, large
|
|
421
433
|
|
|
422
434
|
**Дополнительно:** поддержка иконок и disabled состояния
|
|
423
435
|
|
|
@@ -709,6 +721,129 @@ import { AlertCircle } from 'lucide-react';
|
|
|
709
721
|
- Невыбранное состояние: фон `--color-item-bg`, border `--color-border`, hover `--color-border-hover`
|
|
710
722
|
- Иконка галочки (Check) белого цвета при checked
|
|
711
723
|
|
|
724
|
+
### Radio
|
|
725
|
+
|
|
726
|
+
Радиокнопка для выбора одного варианта из группы. Размеры привязаны к размерам иконок.
|
|
727
|
+
|
|
728
|
+
```jsx
|
|
729
|
+
// Basic radio
|
|
730
|
+
<Radio
|
|
731
|
+
checked={selectedOption === 'option1'}
|
|
732
|
+
onChange={() => setSelectedOption('option1')}
|
|
733
|
+
name="options"
|
|
734
|
+
value="option1"
|
|
735
|
+
label="Option 1"
|
|
736
|
+
/>
|
|
737
|
+
|
|
738
|
+
// Extra Small size (16px)
|
|
739
|
+
<Radio
|
|
740
|
+
size="xs"
|
|
741
|
+
checked={size === 'xs'}
|
|
742
|
+
onChange={() => setSize('xs')}
|
|
743
|
+
name="size"
|
|
744
|
+
value="xs"
|
|
745
|
+
label="Extra Small"
|
|
746
|
+
/>
|
|
747
|
+
|
|
748
|
+
// Small size (20px)
|
|
749
|
+
<Radio
|
|
750
|
+
size="small"
|
|
751
|
+
checked={size === 'small'}
|
|
752
|
+
onChange={() => setSize('small')}
|
|
753
|
+
name="size"
|
|
754
|
+
value="small"
|
|
755
|
+
label="Small"
|
|
756
|
+
/>
|
|
757
|
+
|
|
758
|
+
// Medium size (24px, default)
|
|
759
|
+
<Radio
|
|
760
|
+
size="medium"
|
|
761
|
+
checked={size === 'medium'}
|
|
762
|
+
onChange={() => setSize('medium')}
|
|
763
|
+
name="size"
|
|
764
|
+
value="medium"
|
|
765
|
+
label="Medium"
|
|
766
|
+
/>
|
|
767
|
+
|
|
768
|
+
// Large size (28px)
|
|
769
|
+
<Radio
|
|
770
|
+
size="large"
|
|
771
|
+
checked={size === 'large'}
|
|
772
|
+
onChange={() => setSize('large')}
|
|
773
|
+
name="size"
|
|
774
|
+
value="large"
|
|
775
|
+
label="Large"
|
|
776
|
+
/>
|
|
777
|
+
|
|
778
|
+
// Radio group example
|
|
779
|
+
<div>
|
|
780
|
+
<Radio
|
|
781
|
+
checked={paymentMethod === 'card'}
|
|
782
|
+
onChange={() => setPaymentMethod('card')}
|
|
783
|
+
name="payment"
|
|
784
|
+
value="card"
|
|
785
|
+
label="Credit Card"
|
|
786
|
+
/>
|
|
787
|
+
<Radio
|
|
788
|
+
checked={paymentMethod === 'paypal'}
|
|
789
|
+
onChange={() => setPaymentMethod('paypal')}
|
|
790
|
+
name="payment"
|
|
791
|
+
value="paypal"
|
|
792
|
+
label="PayPal"
|
|
793
|
+
/>
|
|
794
|
+
<Radio
|
|
795
|
+
checked={paymentMethod === 'bank'}
|
|
796
|
+
onChange={() => setPaymentMethod('bank')}
|
|
797
|
+
name="payment"
|
|
798
|
+
value="bank"
|
|
799
|
+
label="Bank Transfer"
|
|
800
|
+
/>
|
|
801
|
+
</div>
|
|
802
|
+
|
|
803
|
+
// Without label (for tables/lists where context is clear)
|
|
804
|
+
<Radio
|
|
805
|
+
checked={isSelected}
|
|
806
|
+
onChange={() => setIsSelected(true)}
|
|
807
|
+
name="selection"
|
|
808
|
+
value="item1"
|
|
809
|
+
/>
|
|
810
|
+
|
|
811
|
+
// Disabled states
|
|
812
|
+
<Radio
|
|
813
|
+
checked={false}
|
|
814
|
+
onChange={() => {}}
|
|
815
|
+
name="disabled-group"
|
|
816
|
+
value="disabled1"
|
|
817
|
+
label="Disabled unchecked"
|
|
818
|
+
disabled
|
|
819
|
+
/>
|
|
820
|
+
|
|
821
|
+
<Radio
|
|
822
|
+
checked={true}
|
|
823
|
+
onChange={() => {}}
|
|
824
|
+
name="disabled-group"
|
|
825
|
+
value="disabled2"
|
|
826
|
+
label="Disabled checked"
|
|
827
|
+
disabled
|
|
828
|
+
/>
|
|
829
|
+
```
|
|
830
|
+
|
|
831
|
+
**Параметры:**
|
|
832
|
+
- `checked` - состояние радиокнопки (true/false)
|
|
833
|
+
- `onChange` - функция обработки изменения состояния, получает новое значение (boolean)
|
|
834
|
+
- `name` - имя группы радиокнопок (обязательно для группировки)
|
|
835
|
+
- `value` - значение радиокнопки
|
|
836
|
+
- `size` - размер: "xs", "small", "medium" или "large" (default: "medium")
|
|
837
|
+
- `label` - текст подписи (опционально)
|
|
838
|
+
- `disabled` - отключить радиокнопку
|
|
839
|
+
- `id` - пользовательский ID (по умолчанию генерируется автоматически)
|
|
840
|
+
|
|
841
|
+
**Стиль:**
|
|
842
|
+
- Размеры привязаны к иконкам: xs (16px), small (20px), medium (24px), large (28px)
|
|
843
|
+
- Выбранное состояние: фон `--color-status-success`, border `--color-status-success` (зеленый), белая точка внутри
|
|
844
|
+
- Невыбранное состояние: фон `--color-item-bg`, border `--color-border`, hover `--color-border-hover`
|
|
845
|
+
- Круглая форма (border-radius: 50%)
|
|
846
|
+
|
|
712
847
|
### Card
|
|
713
848
|
|
|
714
849
|
Карточки бывают двух типов:
|
|
@@ -734,11 +869,45 @@ import { AlertCircle } from 'lucide-react';
|
|
|
734
869
|
<Card padding="small">Small padding</Card>
|
|
735
870
|
<Card padding="medium">Medium padding</Card>
|
|
736
871
|
<Card padding="large">Large padding</Card>
|
|
872
|
+
|
|
873
|
+
// Card как ссылка (рендерит <a> вместо <div>)
|
|
874
|
+
// При обычном клике: вызывается onClick (preventDefault автоматический)
|
|
875
|
+
// При Cmd/Ctrl+Click или Middle Click: открывается новая вкладка
|
|
876
|
+
<Card
|
|
877
|
+
padding="medium"
|
|
878
|
+
variant="interactive"
|
|
879
|
+
href="/dashboard"
|
|
880
|
+
onClick={() => navigate('/dashboard')}
|
|
881
|
+
>
|
|
882
|
+
<H4>Dashboard</H4>
|
|
883
|
+
<P1>Go to dashboard page</P1>
|
|
884
|
+
</Card>
|
|
885
|
+
|
|
886
|
+
<Card
|
|
887
|
+
padding="medium"
|
|
888
|
+
variant="interactive"
|
|
889
|
+
href="https://example.com"
|
|
890
|
+
>
|
|
891
|
+
<H4>External Link</H4>
|
|
892
|
+
<P1>Visit external site</P1>
|
|
893
|
+
</Card>
|
|
894
|
+
|
|
895
|
+
// Disabled Card Link
|
|
896
|
+
<Card
|
|
897
|
+
padding="medium"
|
|
898
|
+
variant="interactive"
|
|
899
|
+
href="/disabled"
|
|
900
|
+
disabled
|
|
901
|
+
>
|
|
902
|
+
<H4>Disabled</H4>
|
|
903
|
+
<P1>This card is disabled</P1>
|
|
904
|
+
</Card>
|
|
737
905
|
```
|
|
738
906
|
|
|
739
907
|
**Стиль:**
|
|
740
908
|
- **variant="info"** (по умолчанию): прозрачный фон, border `--color-border`
|
|
741
|
-
- **variant="interactive"**: фон `--color-item-bg`, при hover фон `--color-item-bg-hover
|
|
909
|
+
- **variant="interactive"**: фон `--color-item-bg`, при hover фон `--color-item-bg-hover`, курсор pointer
|
|
910
|
+
- Поддержка `href` для рендера как ссылка с умной обработкой кликов
|
|
742
911
|
|
|
743
912
|
### Code
|
|
744
913
|
|
package/package.json
CHANGED
|
@@ -61,6 +61,13 @@
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
/* Sizes */
|
|
64
|
+
.ds-button--xs {
|
|
65
|
+
height: var(--height-xs);
|
|
66
|
+
padding: 0 calc(var(--height-xs) / 2);
|
|
67
|
+
font-size: var(--font-size-p3);
|
|
68
|
+
border-radius: var(--radius-xs);
|
|
69
|
+
}
|
|
70
|
+
|
|
64
71
|
.ds-button--small {
|
|
65
72
|
height: var(--height-s);
|
|
66
73
|
padding: 0 calc(var(--height-s) / 2);
|
package/src/components/Card.css
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
border-radius: var(--radius-s);
|
|
4
4
|
border: 1px solid var(--color-border);
|
|
5
5
|
transition: border-color var(--transition-normal), background-color var(--transition-normal);
|
|
6
|
+
text-decoration: none;
|
|
7
|
+
color: inherit;
|
|
6
8
|
}
|
|
7
9
|
|
|
8
10
|
.ds-card--interactive {
|
|
@@ -11,10 +13,16 @@
|
|
|
11
13
|
border: none;
|
|
12
14
|
}
|
|
13
15
|
|
|
14
|
-
.ds-card--interactive:hover {
|
|
16
|
+
.ds-card--interactive:hover:not([aria-disabled="true"]) {
|
|
15
17
|
background-color: var(--color-item-bg-hover);
|
|
16
18
|
}
|
|
17
19
|
|
|
20
|
+
.ds-card[aria-disabled="true"] {
|
|
21
|
+
opacity: 0.5;
|
|
22
|
+
cursor: not-allowed;
|
|
23
|
+
pointer-events: none;
|
|
24
|
+
}
|
|
25
|
+
|
|
18
26
|
.ds-card--none {
|
|
19
27
|
padding: 0;
|
|
20
28
|
}
|
package/src/components/Card.jsx
CHANGED
|
@@ -7,10 +7,12 @@ export function Card({
|
|
|
7
7
|
variant = 'info',
|
|
8
8
|
hover = false, // deprecated, use variant="interactive"
|
|
9
9
|
onClick,
|
|
10
|
+
href,
|
|
11
|
+
disabled = false,
|
|
10
12
|
...props
|
|
11
13
|
}) {
|
|
12
14
|
const cardVariant = hover ? 'interactive' : variant;
|
|
13
|
-
const isInteractive = cardVariant === 'interactive' || onClick;
|
|
15
|
+
const isInteractive = cardVariant === 'interactive' || onClick || href;
|
|
14
16
|
|
|
15
17
|
const className = [
|
|
16
18
|
'ds-card',
|
|
@@ -18,10 +20,41 @@ export function Card({
|
|
|
18
20
|
isInteractive && 'ds-card--interactive',
|
|
19
21
|
].filter(Boolean).join(' ');
|
|
20
22
|
|
|
23
|
+
// Render as link if href is provided
|
|
24
|
+
if (href) {
|
|
25
|
+
const handleClick = (e) => {
|
|
26
|
+
if (disabled) {
|
|
27
|
+
e.preventDefault();
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
// При Cmd/Ctrl+Click или Middle Click — пусть браузер откроет новую вкладку
|
|
31
|
+
if (e.metaKey || e.ctrlKey || e.button === 1) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
// Обычный клик — preventDefault и вызов onClick
|
|
35
|
+
e.preventDefault();
|
|
36
|
+
onClick?.(e);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<a
|
|
41
|
+
className={className}
|
|
42
|
+
href={disabled ? undefined : href}
|
|
43
|
+
onClick={handleClick}
|
|
44
|
+
aria-disabled={disabled ? 'true' : undefined}
|
|
45
|
+
{...props}
|
|
46
|
+
>
|
|
47
|
+
{children}
|
|
48
|
+
</a>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Render as button if interactive with onClick
|
|
21
53
|
const Element = isInteractive && onClick ? 'button' : 'div';
|
|
22
54
|
const interactiveProps = isInteractive && onClick ? {
|
|
23
55
|
type: 'button',
|
|
24
56
|
onClick,
|
|
57
|
+
disabled,
|
|
25
58
|
} : {};
|
|
26
59
|
|
|
27
60
|
return (
|
package/src/components/Input.css
CHANGED
|
@@ -58,6 +58,13 @@
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
/* Sizes */
|
|
61
|
+
.ds-input--xs {
|
|
62
|
+
height: var(--height-xs);
|
|
63
|
+
padding: 0 calc(var(--height-xs) / 4);
|
|
64
|
+
font-size: var(--font-size-p3);
|
|
65
|
+
border-radius: var(--radius-xs);
|
|
66
|
+
}
|
|
67
|
+
|
|
61
68
|
.ds-input--small {
|
|
62
69
|
height: var(--height-s);
|
|
63
70
|
padding: 0 calc(var(--height-s) / 4);
|
|
@@ -72,6 +79,10 @@
|
|
|
72
79
|
border-radius: var(--radius-s);
|
|
73
80
|
}
|
|
74
81
|
|
|
82
|
+
.ds-input--with-icon.ds-input--xs {
|
|
83
|
+
padding-left: calc(var(--height-xs) / 4 + 16px + var(--height-xs) / 4);
|
|
84
|
+
}
|
|
85
|
+
|
|
75
86
|
.ds-input--with-icon.ds-input--small {
|
|
76
87
|
padding-left: calc(var(--height-s) / 4 + 20px + var(--height-s) / 4);
|
|
77
88
|
}
|
|
@@ -80,6 +91,10 @@
|
|
|
80
91
|
padding-left: calc(var(--height-m) / 4 + 24px + var(--height-m) / 4);
|
|
81
92
|
}
|
|
82
93
|
|
|
94
|
+
.ds-input--with-icon-right.ds-input--xs {
|
|
95
|
+
padding-right: calc(var(--height-xs) / 4 + 16px + var(--height-xs) / 4);
|
|
96
|
+
}
|
|
97
|
+
|
|
83
98
|
.ds-input--with-icon-right.ds-input--small {
|
|
84
99
|
padding-right: calc(var(--height-s) / 4 + 20px + var(--height-s) / 4);
|
|
85
100
|
}
|
|
@@ -96,6 +111,10 @@
|
|
|
96
111
|
pointer-events: none;
|
|
97
112
|
}
|
|
98
113
|
|
|
114
|
+
.ds-input-icon--xs {
|
|
115
|
+
left: 6px;
|
|
116
|
+
}
|
|
117
|
+
|
|
99
118
|
.ds-input-icon--small {
|
|
100
119
|
left: 8px;
|
|
101
120
|
}
|
|
@@ -121,6 +140,10 @@
|
|
|
121
140
|
color: var(--color-txt-icon-1);
|
|
122
141
|
}
|
|
123
142
|
|
|
143
|
+
.ds-input-icon-right--xs {
|
|
144
|
+
right: 6px;
|
|
145
|
+
}
|
|
146
|
+
|
|
124
147
|
.ds-input-icon-right--small {
|
|
125
148
|
right: 8px;
|
|
126
149
|
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
.ds-radio {
|
|
2
|
+
display: inline-flex;
|
|
3
|
+
align-items: center;
|
|
4
|
+
gap: var(--space-s);
|
|
5
|
+
cursor: pointer;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.ds-radio--disabled {
|
|
9
|
+
opacity: 0.5;
|
|
10
|
+
cursor: not-allowed;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.ds-radio__input {
|
|
14
|
+
position: absolute;
|
|
15
|
+
opacity: 0;
|
|
16
|
+
pointer-events: none;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.ds-radio__circle {
|
|
20
|
+
position: relative;
|
|
21
|
+
display: flex;
|
|
22
|
+
align-items: center;
|
|
23
|
+
justify-content: center;
|
|
24
|
+
background-color: var(--color-item-bg);
|
|
25
|
+
border: 1px solid var(--color-border);
|
|
26
|
+
transition: background-color var(--transition-normal), border-color var(--transition-normal);
|
|
27
|
+
flex-shrink: 0;
|
|
28
|
+
border-radius: 50%;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.ds-radio__input:checked + .ds-radio__circle {
|
|
32
|
+
background-color: var(--color-status-success);
|
|
33
|
+
border-color: var(--color-status-success);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.ds-radio__input:not(:checked) + .ds-radio__circle:hover {
|
|
37
|
+
border-color: var(--color-border-hover);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.ds-radio__dot {
|
|
41
|
+
background-color: var(--color-white);
|
|
42
|
+
border-radius: 50%;
|
|
43
|
+
opacity: 0;
|
|
44
|
+
transition: opacity var(--transition-normal);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.ds-radio__input:checked + .ds-radio__circle .ds-radio__dot {
|
|
48
|
+
opacity: 1;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.ds-radio__label {
|
|
52
|
+
font-size: var(--font-size-p1);
|
|
53
|
+
color: var(--color-txt-icon-1);
|
|
54
|
+
user-select: none;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* Extra Small */
|
|
58
|
+
.ds-radio--xs .ds-radio__circle {
|
|
59
|
+
width: var(--icon-xs);
|
|
60
|
+
height: var(--icon-xs);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.ds-radio--xs .ds-radio__dot {
|
|
64
|
+
width: 6px;
|
|
65
|
+
height: 6px;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.ds-radio--xs .ds-radio__label {
|
|
69
|
+
font-size: var(--font-size-p3);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/* Small */
|
|
73
|
+
.ds-radio--small .ds-radio__circle {
|
|
74
|
+
width: var(--icon-s);
|
|
75
|
+
height: var(--icon-s);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.ds-radio--small .ds-radio__dot {
|
|
79
|
+
width: 8px;
|
|
80
|
+
height: 8px;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.ds-radio--small .ds-radio__label {
|
|
84
|
+
font-size: var(--font-size-p2);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/* Medium */
|
|
88
|
+
.ds-radio--medium .ds-radio__circle {
|
|
89
|
+
width: var(--icon-m);
|
|
90
|
+
height: var(--icon-m);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.ds-radio--medium .ds-radio__dot {
|
|
94
|
+
width: 10px;
|
|
95
|
+
height: 10px;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.ds-radio--medium .ds-radio__label {
|
|
99
|
+
font-size: var(--font-size-p1);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/* Large */
|
|
103
|
+
.ds-radio--large .ds-radio__circle {
|
|
104
|
+
width: var(--icon-l);
|
|
105
|
+
height: var(--icon-l);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.ds-radio--large .ds-radio__dot {
|
|
109
|
+
width: 12px;
|
|
110
|
+
height: 12px;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.ds-radio--large .ds-radio__label {
|
|
114
|
+
font-size: var(--font-size-p1);
|
|
115
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import './Radio.css';
|
|
3
|
+
|
|
4
|
+
export function Radio({
|
|
5
|
+
checked = false,
|
|
6
|
+
onChange,
|
|
7
|
+
size = 'medium',
|
|
8
|
+
disabled = false,
|
|
9
|
+
label,
|
|
10
|
+
name,
|
|
11
|
+
value,
|
|
12
|
+
id,
|
|
13
|
+
...props
|
|
14
|
+
}) {
|
|
15
|
+
const radioId = id || `radio-${React.useId()}`;
|
|
16
|
+
|
|
17
|
+
const className = [
|
|
18
|
+
'ds-radio',
|
|
19
|
+
`ds-radio--${size}`,
|
|
20
|
+
disabled && 'ds-radio--disabled',
|
|
21
|
+
].filter(Boolean).join(' ');
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<label className={className} htmlFor={radioId}>
|
|
25
|
+
<input
|
|
26
|
+
type="radio"
|
|
27
|
+
id={radioId}
|
|
28
|
+
className="ds-radio__input"
|
|
29
|
+
checked={checked}
|
|
30
|
+
onChange={(e) => onChange?.(e.target.checked)}
|
|
31
|
+
disabled={disabled}
|
|
32
|
+
name={name}
|
|
33
|
+
value={value}
|
|
34
|
+
{...props}
|
|
35
|
+
/>
|
|
36
|
+
<span className="ds-radio__circle">
|
|
37
|
+
<span className="ds-radio__dot" />
|
|
38
|
+
</span>
|
|
39
|
+
{label && <span className="ds-radio__label">{label}</span>}
|
|
40
|
+
</label>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
@@ -60,6 +60,13 @@
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
/* Sizes */
|
|
63
|
+
.ds-select-trigger--xs {
|
|
64
|
+
height: var(--height-xs);
|
|
65
|
+
padding: 0 calc(var(--height-xs) / 4);
|
|
66
|
+
font-size: var(--font-size-p3);
|
|
67
|
+
border-radius: var(--radius-xs);
|
|
68
|
+
}
|
|
69
|
+
|
|
63
70
|
.ds-select-trigger--small {
|
|
64
71
|
height: var(--height-s);
|
|
65
72
|
padding: 0 calc(var(--height-s) / 4);
|
|
@@ -53,7 +53,7 @@ export function Select({
|
|
|
53
53
|
}, [isOpen]);
|
|
54
54
|
|
|
55
55
|
const selectedOption = options.find(opt => opt.value === value);
|
|
56
|
-
const iconSize = size === 'small' ? iconSizes.s : iconSizes.m;
|
|
56
|
+
const iconSize = size === 'xs' ? iconSizes.xs : size === 'small' ? iconSizes.s : iconSizes.m;
|
|
57
57
|
|
|
58
58
|
return (
|
|
59
59
|
<div className={`ds-select-wrapper ${fullWidth ? 'ds-select-wrapper--full' : ''} ${disabled ? 'ds-select-wrapper--disabled' : ''}`}>
|
|
@@ -98,6 +98,22 @@
|
|
|
98
98
|
|
|
99
99
|
/* Sizes */
|
|
100
100
|
|
|
101
|
+
/* Extra Small */
|
|
102
|
+
.ds-stepper--xs {
|
|
103
|
+
height: var(--height-xs);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.ds-stepper--xs .ds-stepper-button {
|
|
107
|
+
width: var(--height-xs);
|
|
108
|
+
padding: 0;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.ds-stepper--xs .ds-stepper-input {
|
|
112
|
+
font-size: var(--font-size-p3);
|
|
113
|
+
letter-spacing: var(--letter-spacing-p3);
|
|
114
|
+
padding: 0 var(--space-xs);
|
|
115
|
+
}
|
|
116
|
+
|
|
101
117
|
/* Small */
|
|
102
118
|
.ds-stepper--small {
|
|
103
119
|
height: var(--height-s);
|
|
@@ -57,7 +57,7 @@ export function Stepper({
|
|
|
57
57
|
disabled && 'ds-stepper--disabled',
|
|
58
58
|
].filter(Boolean).join(' ');
|
|
59
59
|
|
|
60
|
-
const iconSize = size === 'small' ? iconSizes.s : iconSizes.m;
|
|
60
|
+
const iconSize = size === 'xs' ? iconSizes.xs : size === 'small' ? iconSizes.s : iconSizes.m;
|
|
61
61
|
|
|
62
62
|
return (
|
|
63
63
|
<div className={className}>
|
package/src/components/Tabs.css
CHANGED
|
@@ -37,6 +37,13 @@
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
/* Sizes */
|
|
40
|
+
.ds-tab--xs {
|
|
41
|
+
height: var(--height-xs);
|
|
42
|
+
padding: 0 calc(var(--height-xs) / 2);
|
|
43
|
+
font-size: var(--font-size-p3);
|
|
44
|
+
border-radius: var(--radius-xs);
|
|
45
|
+
}
|
|
46
|
+
|
|
40
47
|
.ds-tab--small {
|
|
41
48
|
height: var(--height-s);
|
|
42
49
|
padding: 0 calc(var(--height-s) / 2);
|
|
@@ -87,6 +87,12 @@
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
/* Sizes */
|
|
90
|
+
.ds-textarea--xs {
|
|
91
|
+
padding: var(--space-xs);
|
|
92
|
+
font-size: var(--font-size-p3);
|
|
93
|
+
border-radius: var(--radius-xs);
|
|
94
|
+
}
|
|
95
|
+
|
|
90
96
|
.ds-textarea--small {
|
|
91
97
|
padding: var(--space-xs) var(--space-s);
|
|
92
98
|
font-size: var(--font-size-p2);
|
package/src/index.js
CHANGED