@donkit-ai/design-system 0.2.13 → 0.2.15
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 +30 -4
- package/package.json +1 -1
- package/src/components/Button.css +7 -4
- package/src/components/Button.jsx +43 -3
- package/src/components/Card.css +1 -1
- package/src/components/Tabs.css +5 -2
- package/src/components/Tabs.jsx +43 -3
- package/src/styles/iconSizes.js +2 -2
- package/src/styles/tokens.css +1 -1
package/README.md
CHANGED
|
@@ -37,8 +37,8 @@ npm install @donkit-ai/design-system@latest
|
|
|
37
37
|
|
|
38
38
|
## Компоненты
|
|
39
39
|
|
|
40
|
-
- **Button** - кнопки с вариантами (primary, secondary, ghost) и размерами (small, medium, large)
|
|
41
|
-
- **Tabs** - вкладки с состоянием selected в трех размерах (small, medium, large)
|
|
40
|
+
- **Button** - кнопки с вариантами (primary, secondary, ghost) и размерами (small, medium, large). Поддерживает `href` для рендера как ссылка
|
|
41
|
+
- **Tabs** - вкладки с состоянием selected в трех размерах (small, medium, large). Поддерживает `href` для рендера как ссылка
|
|
42
42
|
- **Input** - текстовые поля с поддержкой иконок, ошибок и подсказок (small, medium)
|
|
43
43
|
- **Stepper** - числовое поле с кнопками +/- для изменения значения (small, medium)
|
|
44
44
|
- **Card** - карточки двух типов: info (информационная, прозрачный фон) и interactive (интерактивная с hover эффектом)
|
|
@@ -81,6 +81,17 @@ function MyComponent() {
|
|
|
81
81
|
</Card>
|
|
82
82
|
);
|
|
83
83
|
}
|
|
84
|
+
|
|
85
|
+
// Button как ссылка (рендерит <a> вместо <button>)
|
|
86
|
+
// При обычном клике: вызывается onClick (preventDefault автоматический)
|
|
87
|
+
// При Cmd/Ctrl+Click или Middle Click: открывается новая вкладка
|
|
88
|
+
<Button variant="primary" href="/dashboard" onClick={() => navigate('/dashboard')}>
|
|
89
|
+
Go to Dashboard
|
|
90
|
+
</Button>
|
|
91
|
+
|
|
92
|
+
<Button variant="secondary" href="https://example.com">
|
|
93
|
+
Visit Example
|
|
94
|
+
</Button>
|
|
84
95
|
```
|
|
85
96
|
|
|
86
97
|
### 3. Иконки
|
|
@@ -94,7 +105,7 @@ function MyComponent() {
|
|
|
94
105
|
```javascript
|
|
95
106
|
import { iconSizes } from '@donkit-ai/design-system';
|
|
96
107
|
|
|
97
|
-
// iconSizes = { xs: 16, s: 20, m: 24, l: 28, xl:
|
|
108
|
+
// iconSizes = { xs: 16, s: 20, m: 24, l: 28, xl: 48 }
|
|
98
109
|
```
|
|
99
110
|
|
|
100
111
|
**Соответствие размеров компонентам:**
|
|
@@ -115,7 +126,7 @@ import { iconSizes } from '@donkit-ai/design-system';
|
|
|
115
126
|
- **28px (l)** - крупные элементы
|
|
116
127
|
- Large кнопки (`size="large"`)
|
|
117
128
|
|
|
118
|
-
- **
|
|
129
|
+
- **48px (xl)** - очень крупные элементы
|
|
119
130
|
|
|
120
131
|
**Всегда используется `strokeWidth={1.5}`** для единообразия дизайна.
|
|
121
132
|
|
|
@@ -382,6 +393,21 @@ import { AlertCircle } from 'lucide-react';
|
|
|
382
393
|
<Tab selected>Active</Tab>
|
|
383
394
|
<Tab disabled>Disabled</Tab>
|
|
384
395
|
</Tabs>
|
|
396
|
+
|
|
397
|
+
// As links (с href) - рендерит <a> вместо <button>
|
|
398
|
+
// При обычном клике: вызывается onClick (preventDefault автоматический)
|
|
399
|
+
// При Cmd/Ctrl+Click или Middle Click: открывается новая вкладка
|
|
400
|
+
<Tabs size="medium">
|
|
401
|
+
<Tab selected href="/overview" onClick={() => navigate('/overview')}>
|
|
402
|
+
Overview
|
|
403
|
+
</Tab>
|
|
404
|
+
<Tab href="/details" onClick={() => navigate('/details')}>
|
|
405
|
+
Details
|
|
406
|
+
</Tab>
|
|
407
|
+
<Tab href="/settings" onClick={() => navigate('/settings')}>
|
|
408
|
+
Settings
|
|
409
|
+
</Tab>
|
|
410
|
+
</Tabs>
|
|
385
411
|
```
|
|
386
412
|
|
|
387
413
|
**Стили:**
|
package/package.json
CHANGED
|
@@ -13,11 +13,14 @@
|
|
|
13
13
|
border-color var(--transition-normal),
|
|
14
14
|
opacity var(--transition-normal);
|
|
15
15
|
white-space: nowrap;
|
|
16
|
+
text-decoration: none;
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
.ds-button:disabled
|
|
19
|
+
.ds-button:disabled,
|
|
20
|
+
.ds-button[aria-disabled="true"] {
|
|
19
21
|
opacity: 0.5;
|
|
20
22
|
cursor: not-allowed;
|
|
23
|
+
pointer-events: none;
|
|
21
24
|
}
|
|
22
25
|
|
|
23
26
|
.ds-button__icon {
|
|
@@ -32,7 +35,7 @@
|
|
|
32
35
|
background-color: var(--color-accent);
|
|
33
36
|
}
|
|
34
37
|
|
|
35
|
-
.ds-button--primary:hover:not(:disabled) {
|
|
38
|
+
.ds-button--primary:hover:not(:disabled):not([aria-disabled="true"]) {
|
|
36
39
|
background-color: var(--color-accent-hover);
|
|
37
40
|
}
|
|
38
41
|
|
|
@@ -42,7 +45,7 @@
|
|
|
42
45
|
border: 1px solid var(--color-border);
|
|
43
46
|
}
|
|
44
47
|
|
|
45
|
-
.ds-button--secondary:hover:not(:disabled) {
|
|
48
|
+
.ds-button--secondary:hover:not(:disabled):not([aria-disabled="true"]) {
|
|
46
49
|
background-color: var(--color-item-bg-hover);
|
|
47
50
|
border-color: var(--color-border-hover);
|
|
48
51
|
}
|
|
@@ -52,7 +55,7 @@
|
|
|
52
55
|
background-color: transparent;
|
|
53
56
|
}
|
|
54
57
|
|
|
55
|
-
.ds-button--ghost:hover:not(:disabled) {
|
|
58
|
+
.ds-button--ghost:hover:not(:disabled):not([aria-disabled="true"]) {
|
|
56
59
|
background-color: var(--color-item-bg-hover);
|
|
57
60
|
color: var(--color-txt-icon-1);
|
|
58
61
|
}
|
|
@@ -10,6 +10,7 @@ export function Button({
|
|
|
10
10
|
disabled = false,
|
|
11
11
|
onClick,
|
|
12
12
|
type = 'button',
|
|
13
|
+
href,
|
|
13
14
|
'aria-label': ariaLabel,
|
|
14
15
|
...props
|
|
15
16
|
}) {
|
|
@@ -23,6 +24,47 @@ export function Button({
|
|
|
23
24
|
isIconOnly && 'ds-button--icon-only',
|
|
24
25
|
].filter(Boolean).join(' ');
|
|
25
26
|
|
|
27
|
+
const content = (
|
|
28
|
+
<>
|
|
29
|
+
{icon && !isIconOnly && <span className="ds-button__icon" aria-hidden="true">{icon}</span>}
|
|
30
|
+
{children}
|
|
31
|
+
{isIconOnly && <span className="ds-button__icon" aria-hidden="true">{icon}</span>}
|
|
32
|
+
</>
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
// Render as link if href is provided
|
|
36
|
+
if (href) {
|
|
37
|
+
const handleClick = (e) => {
|
|
38
|
+
if (disabled) {
|
|
39
|
+
e.preventDefault();
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// При Cmd/Ctrl+Click или Middle Click — пусть браузер откроет новую вкладку
|
|
44
|
+
if (e.metaKey || e.ctrlKey || e.button === 1) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Обычный клик — preventDefault и вызов onClick
|
|
49
|
+
e.preventDefault();
|
|
50
|
+
onClick?.(e);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<a
|
|
55
|
+
className={className}
|
|
56
|
+
href={disabled ? undefined : href}
|
|
57
|
+
onClick={handleClick}
|
|
58
|
+
aria-label={ariaLabel}
|
|
59
|
+
aria-disabled={disabled ? 'true' : undefined}
|
|
60
|
+
{...props}
|
|
61
|
+
>
|
|
62
|
+
{content}
|
|
63
|
+
</a>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Render as button (default)
|
|
26
68
|
return (
|
|
27
69
|
<button
|
|
28
70
|
type={type}
|
|
@@ -32,9 +74,7 @@ export function Button({
|
|
|
32
74
|
aria-label={ariaLabel}
|
|
33
75
|
{...props}
|
|
34
76
|
>
|
|
35
|
-
{
|
|
36
|
-
{children}
|
|
37
|
-
{isIconOnly && <span className="ds-button__icon" aria-hidden="true">{icon}</span>}
|
|
77
|
+
{content}
|
|
38
78
|
</button>
|
|
39
79
|
);
|
|
40
80
|
}
|
package/src/components/Card.css
CHANGED
package/src/components/Tabs.css
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
color: var(--color-txt-icon-1);
|
|
18
18
|
transition: border-color var(--transition-normal), background-color var(--transition-normal);
|
|
19
19
|
white-space: nowrap;
|
|
20
|
+
text-decoration: none;
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
/* Variants */
|
|
@@ -25,7 +26,7 @@
|
|
|
25
26
|
color: var(--color-txt-icon-2);
|
|
26
27
|
}
|
|
27
28
|
|
|
28
|
-
.ds-tab--ghost:hover:not(.ds-tab--selected):not(:disabled) {
|
|
29
|
+
.ds-tab--ghost:hover:not(.ds-tab--selected):not(:disabled):not([aria-disabled="true"]) {
|
|
29
30
|
background-color: var(--color-item-bg-hover);
|
|
30
31
|
color: var(--color-txt-icon-1);
|
|
31
32
|
}
|
|
@@ -58,9 +59,11 @@
|
|
|
58
59
|
gap: var(--space-s);
|
|
59
60
|
}
|
|
60
61
|
|
|
61
|
-
.ds-tab:disabled
|
|
62
|
+
.ds-tab:disabled,
|
|
63
|
+
.ds-tab[aria-disabled="true"] {
|
|
62
64
|
opacity: 0.5;
|
|
63
65
|
cursor: not-allowed;
|
|
66
|
+
pointer-events: none;
|
|
64
67
|
}
|
|
65
68
|
|
|
66
69
|
.ds-tab-icon {
|
package/src/components/Tabs.jsx
CHANGED
|
@@ -14,7 +14,7 @@ export function Tabs({ children, size = 'medium', variant = 'ghost', ...props })
|
|
|
14
14
|
);
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
export function Tab({ children, selected = false, onClick, size = 'medium', variant = 'ghost', disabled = false, icon, ...props }) {
|
|
17
|
+
export function Tab({ children, selected = false, onClick, size = 'medium', variant = 'ghost', disabled = false, icon, href, ...props }) {
|
|
18
18
|
const isIconOnly = icon && !children;
|
|
19
19
|
|
|
20
20
|
const className = [
|
|
@@ -25,6 +25,47 @@ export function Tab({ children, selected = false, onClick, size = 'medium', vari
|
|
|
25
25
|
isIconOnly && 'ds-tab--icon-only',
|
|
26
26
|
].filter(Boolean).join(' ');
|
|
27
27
|
|
|
28
|
+
const content = (
|
|
29
|
+
<>
|
|
30
|
+
{icon && <span className="ds-tab-icon">{icon}</span>}
|
|
31
|
+
{children}
|
|
32
|
+
</>
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
// Render as link if href is provided
|
|
36
|
+
if (href) {
|
|
37
|
+
const handleClick = (e) => {
|
|
38
|
+
if (disabled) {
|
|
39
|
+
e.preventDefault();
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// При Cmd/Ctrl+Click или Middle Click — пусть браузер откроет новую вкладку
|
|
44
|
+
if (e.metaKey || e.ctrlKey || e.button === 1) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Обычный клик — preventDefault и вызов onClick
|
|
49
|
+
e.preventDefault();
|
|
50
|
+
onClick?.(e);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<a
|
|
55
|
+
role="tab"
|
|
56
|
+
aria-current={selected ? 'page' : undefined}
|
|
57
|
+
aria-disabled={disabled ? 'true' : undefined}
|
|
58
|
+
className={className}
|
|
59
|
+
href={disabled ? undefined : href}
|
|
60
|
+
onClick={handleClick}
|
|
61
|
+
{...props}
|
|
62
|
+
>
|
|
63
|
+
{content}
|
|
64
|
+
</a>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Render as button (default)
|
|
28
69
|
return (
|
|
29
70
|
<button
|
|
30
71
|
role="tab"
|
|
@@ -34,8 +75,7 @@ export function Tab({ children, selected = false, onClick, size = 'medium', vari
|
|
|
34
75
|
disabled={disabled}
|
|
35
76
|
{...props}
|
|
36
77
|
>
|
|
37
|
-
{
|
|
38
|
-
{children}
|
|
78
|
+
{content}
|
|
39
79
|
</button>
|
|
40
80
|
);
|
|
41
81
|
}
|
package/src/styles/iconSizes.js
CHANGED