@donkit-ai/design-system 0.3.4 → 0.4.2

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.
Files changed (45) hide show
  1. package/dist/index.cjs.js +22 -0
  2. package/dist/index.es.js +1105 -0
  3. package/dist/tokens.css +1 -0
  4. package/package.json +15 -9
  5. package/src/components/Accordion.css +0 -70
  6. package/src/components/Accordion.jsx +0 -42
  7. package/src/components/Alert.css +0 -93
  8. package/src/components/Alert.jsx +0 -47
  9. package/src/components/Badge.css +0 -52
  10. package/src/components/Badge.jsx +0 -25
  11. package/src/components/Button.css +0 -103
  12. package/src/components/Button.jsx +0 -80
  13. package/src/components/Card.css +0 -46
  14. package/src/components/Card.jsx +0 -70
  15. package/src/components/Checkbox.css +0 -88
  16. package/src/components/Checkbox.jsx +0 -47
  17. package/src/components/Code.css +0 -30
  18. package/src/components/Code.jsx +0 -27
  19. package/src/components/CodeAccordion.css +0 -80
  20. package/src/components/CodeAccordion.jsx +0 -42
  21. package/src/components/Input.css +0 -163
  22. package/src/components/Input.jsx +0 -55
  23. package/src/components/Link.css +0 -18
  24. package/src/components/Link.jsx +0 -21
  25. package/src/components/Modal.css +0 -70
  26. package/src/components/Modal.jsx +0 -72
  27. package/src/components/Radio.css +0 -115
  28. package/src/components/Radio.jsx +0 -42
  29. package/src/components/Select.css +0 -167
  30. package/src/components/Select.jsx +0 -118
  31. package/src/components/Stepper.css +0 -183
  32. package/src/components/Stepper.jsx +0 -104
  33. package/src/components/Tabs.css +0 -87
  34. package/src/components/Tabs.jsx +0 -81
  35. package/src/components/Textarea.css +0 -116
  36. package/src/components/Textarea.jsx +0 -41
  37. package/src/components/Toggle.css +0 -133
  38. package/src/components/Toggle.jsx +0 -38
  39. package/src/components/Tooltip.css +0 -134
  40. package/src/components/Tooltip.jsx +0 -148
  41. package/src/components/Typography.css +0 -74
  42. package/src/components/Typography.jsx +0 -42
  43. package/src/index.js +0 -24
  44. package/src/styles/iconSizes.js +0 -15
  45. package/src/styles/tokens.css +0 -298
@@ -1,70 +0,0 @@
1
- .ds-modal-overlay {
2
- position: fixed;
3
- top: 0;
4
- left: 0;
5
- right: 0;
6
- bottom: 0;
7
- background-color: var(--color-overlay);
8
- display: flex;
9
- align-items: flex-start;
10
- justify-content: center;
11
- z-index: 1000;
12
- padding: var(--space-m);
13
- overflow-y: auto;
14
- }
15
-
16
- .ds-modal {
17
- background-color: var(--color-bg);
18
- border: 1px solid var(--color-border);
19
- border-radius: var(--radius-s);
20
- display: flex;
21
- flex-direction: column;
22
- margin: auto 0;
23
- }
24
-
25
- .ds-modal--s {
26
- width: 100%;
27
- max-width: 400px;
28
- }
29
-
30
- .ds-modal--m {
31
- width: 100%;
32
- max-width: 600px;
33
- }
34
-
35
- .ds-modal--l {
36
- width: 100%;
37
- max-width: 900px;
38
- }
39
-
40
- .ds-modal__header {
41
- display: flex;
42
- align-items: center;
43
- justify-content: space-between;
44
- padding: var(--space-l);
45
- }
46
-
47
- .ds-modal__title {
48
- font-size: var(--font-size-h3);
49
- font-weight: 400;
50
- color: var(--color-txt-icon-1);
51
- margin: 0;
52
- }
53
-
54
- .ds-modal__body {
55
- padding: 0 var(--space-l) var(--space-l);
56
- flex: 1;
57
- }
58
-
59
- .ds-modal__footer {
60
- display: flex;
61
- align-items: center;
62
- justify-content: flex-start;
63
- gap: var(--space-s);
64
- padding: var(--space-s) var(--space-l) var(--space-l);
65
- background-color: var(--color-bg);
66
- position: relative;
67
- z-index: 10;
68
- border-bottom-left-radius: var(--space-s);
69
- border-bottom-right-radius: var(--space-s);
70
- }
@@ -1,72 +0,0 @@
1
- import React, { useEffect, useRef } from 'react';
2
- import { X } from 'lucide-react';
3
- import { iconSizes } from '../styles/iconSizes';
4
- import { Button } from './Button';
5
- import './Modal.css';
6
-
7
- export function Modal({
8
- children,
9
- title,
10
- onClose,
11
- size = 'm',
12
- ...props
13
- }) {
14
- const modalRef = useRef(null);
15
- const titleId = React.useId();
16
-
17
- useEffect(() => {
18
- const handleEscape = (e) => {
19
- if (e.key === 'Escape') onClose?.();
20
- };
21
- const handleClickOutside = (e) => {
22
- if (modalRef.current && !modalRef.current.contains(e.target)) {
23
- onClose?.();
24
- }
25
- };
26
-
27
- document.addEventListener('keydown', handleEscape);
28
- document.addEventListener('mousedown', handleClickOutside);
29
- return () => {
30
- document.removeEventListener('keydown', handleEscape);
31
- document.removeEventListener('mousedown', handleClickOutside);
32
- };
33
- }, [onClose]);
34
-
35
- // Separate ModalFooter from other children
36
- const childrenArray = React.Children.toArray(children);
37
- const footer = childrenArray.find(child => child?.type === ModalFooter);
38
- const bodyContent = childrenArray.filter(child => child?.type !== ModalFooter);
39
-
40
- return (
41
- <div className="ds-modal-overlay" {...props}>
42
- <div
43
- className={`ds-modal ds-modal--${size}`}
44
- ref={modalRef}
45
- role="dialog"
46
- aria-modal="true"
47
- aria-labelledby={title ? titleId : undefined}
48
- >
49
- {(title || onClose) && (
50
- <div className="ds-modal__header">
51
- {title && <h3 id={titleId} className="ds-modal__title">{title}</h3>}
52
- {onClose && (
53
- <Button
54
- variant="ghost"
55
- size="small"
56
- icon={<X size={iconSizes.s} strokeWidth={1.5} />}
57
- onClick={onClose}
58
- aria-label="Close modal"
59
- />
60
- )}
61
- </div>
62
- )}
63
- <div className="ds-modal__body">{bodyContent}</div>
64
- {footer}
65
- </div>
66
- </div>
67
- );
68
- }
69
-
70
- export function ModalFooter({ children }) {
71
- return <div className="ds-modal__footer">{children}</div>;
72
- }
@@ -1,115 +0,0 @@
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--s .ds-radio__circle {
74
- width: var(--icon-s);
75
- height: var(--icon-s);
76
- }
77
-
78
- .ds-radio--s .ds-radio__dot {
79
- width: 8px;
80
- height: 8px;
81
- }
82
-
83
- .ds-radio--s .ds-radio__label {
84
- font-size: var(--font-size-p2);
85
- }
86
-
87
- /* Medium */
88
- .ds-radio--m .ds-radio__circle {
89
- width: var(--icon-m);
90
- height: var(--icon-m);
91
- }
92
-
93
- .ds-radio--m .ds-radio__dot {
94
- width: 10px;
95
- height: 10px;
96
- }
97
-
98
- .ds-radio--m .ds-radio__label {
99
- font-size: var(--font-size-p1);
100
- }
101
-
102
- /* Large */
103
- .ds-radio--l .ds-radio__circle {
104
- width: var(--icon-l);
105
- height: var(--icon-l);
106
- }
107
-
108
- .ds-radio--l .ds-radio__dot {
109
- width: 12px;
110
- height: 12px;
111
- }
112
-
113
- .ds-radio--l .ds-radio__label {
114
- font-size: var(--font-size-p1);
115
- }
@@ -1,42 +0,0 @@
1
- import React from 'react';
2
- import './Radio.css';
3
-
4
- export function Radio({
5
- checked = false,
6
- onChange,
7
- size = 'm',
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
- }
@@ -1,167 +0,0 @@
1
- .ds-select-wrapper {
2
- display: flex;
3
- flex-direction: column;
4
- gap: var(--space-xs);
5
- }
6
-
7
- .ds-select-wrapper--full {
8
- width: 100%;
9
- }
10
-
11
- .ds-select-wrapper--disabled {
12
- opacity: 0.5;
13
- cursor: not-allowed;
14
- }
15
-
16
- .ds-select-label {
17
- font-size: var(--font-size-p2);
18
- font-weight: 400;
19
- color: var(--color-txt-icon-1);
20
- }
21
-
22
- .ds-select-container {
23
- position: relative;
24
- }
25
-
26
- .ds-select-trigger {
27
- width: 100%;
28
- display: flex;
29
- align-items: center;
30
- justify-content: space-between;
31
- gap: var(--space-s);
32
- font-family: inherit;
33
- color: var(--color-txt-icon-1);
34
- background-color: transparent;
35
- border: 1px solid var(--color-border);
36
- cursor: pointer;
37
- transition: border-color var(--transition-normal);
38
- text-align: left;
39
- line-height: 1.5;
40
- }
41
-
42
- .ds-select-trigger > span {
43
- flex: 1;
44
- min-width: 0;
45
- overflow: hidden;
46
- text-overflow: ellipsis;
47
- white-space: nowrap;
48
- }
49
-
50
- .ds-select-trigger:hover:not(:disabled) {
51
- border-color: var(--color-border-hover);
52
- }
53
-
54
- .ds-select-trigger:disabled {
55
- cursor: not-allowed;
56
- }
57
-
58
- .ds-select-trigger--error {
59
- border-color: var(--color-error);
60
- }
61
-
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
-
70
- .ds-select-trigger--s {
71
- height: var(--height-s);
72
- padding: 0 calc(var(--height-s) / 4);
73
- font-size: var(--font-size-p2);
74
- border-radius: var(--radius-xs);
75
- }
76
-
77
- .ds-select-trigger--m {
78
- height: var(--height-m);
79
- padding: 0 calc(var(--height-m) / 4);
80
- font-size: var(--font-size-p1);
81
- border-radius: var(--radius-s);
82
- }
83
-
84
- .ds-select-placeholder {
85
- color: var(--color-txt-icon-2);
86
- }
87
-
88
- .ds-select-icon {
89
- flex-shrink: 0;
90
- color: var(--color-txt-icon-2);
91
- transition: transform var(--transition-normal);
92
- }
93
-
94
- .ds-select-icon--open {
95
- transform: rotate(180deg);
96
- }
97
-
98
- .ds-select-icon--up {
99
- transform: rotate(0deg);
100
- }
101
-
102
- .ds-select-dropdown {
103
- position: absolute;
104
- left: 0;
105
- right: 0;
106
- background-color: var(--color-bg);
107
- border: 1px solid var(--color-border);
108
- z-index: 100;
109
- max-height: 300px;
110
- overflow-y: auto;
111
- }
112
-
113
- /* Dropdown direction */
114
- .ds-select-dropdown--down {
115
- top: calc(100% + 4px);
116
- }
117
-
118
- .ds-select-dropdown--up {
119
- bottom: calc(100% + 4px);
120
- }
121
-
122
- .ds-select-dropdown--s {
123
- border-radius: var(--radius-xs);
124
- }
125
-
126
- .ds-select-dropdown--m {
127
- border-radius: var(--radius-s);
128
- }
129
-
130
- .ds-select-option {
131
- width: 100%;
132
- font-family: inherit;
133
- color: var(--color-txt-icon-1);
134
- background-color: transparent;
135
- border: none;
136
- cursor: pointer;
137
- text-align: left;
138
- transition: background-color var(--transition-normal);
139
- line-height: 1.5;
140
- white-space: normal;
141
- word-wrap: break-word;
142
- }
143
-
144
- .ds-select-option--s {
145
- min-height: var(--height-s);
146
- padding: var(--space-xs) calc(var(--height-s) / 4);
147
- font-size: var(--font-size-p2);
148
- }
149
-
150
- .ds-select-option--m {
151
- min-height: var(--height-m);
152
- padding: var(--space-xs) calc(var(--height-m) / 4);
153
- font-size: var(--font-size-p1);
154
- }
155
-
156
- .ds-select-option:hover {
157
- background-color: var(--color-item-bg-hover);
158
- }
159
-
160
- .ds-select-option--selected {
161
- background-color: var(--color-item-bg-selected);
162
- }
163
-
164
- .ds-select-error {
165
- font-size: var(--font-size-p2);
166
- color: var(--color-error);
167
- }
@@ -1,118 +0,0 @@
1
- import React, { useState, useRef, useEffect } from 'react';
2
- import { ChevronDown } from 'lucide-react';
3
- import { iconSizes } from '../styles/iconSizes';
4
- import './Select.css';
5
-
6
- export function Select({
7
- label,
8
- value,
9
- onChange,
10
- options = [],
11
- placeholder = 'Select option',
12
- error,
13
- fullWidth = true,
14
- size = 'm',
15
- disabled = false,
16
- id,
17
- ...props
18
- }) {
19
- const [isOpen, setIsOpen] = useState(false);
20
- const [dropdownDirection, setDropdownDirection] = useState('down');
21
- const selectRef = useRef(null);
22
- const dropdownRef = useRef(null);
23
- const selectId = id || `select-${React.useId()}`;
24
- const labelId = `${selectId}-label`;
25
- const errorId = error ? `${selectId}-error` : undefined;
26
-
27
- useEffect(() => {
28
- const handleClickOutside = (e) => {
29
- if (selectRef.current && !selectRef.current.contains(e.target)) {
30
- setIsOpen(false);
31
- }
32
- };
33
-
34
- document.addEventListener('mousedown', handleClickOutside);
35
- return () => document.removeEventListener('mousedown', handleClickOutside);
36
- }, []);
37
-
38
- useEffect(() => {
39
- if (isOpen && selectRef.current) {
40
- const triggerRect = selectRef.current.getBoundingClientRect();
41
- const viewportHeight = window.innerHeight;
42
- const spaceBelow = viewportHeight - triggerRect.bottom;
43
- const spaceAbove = triggerRect.top;
44
- const dropdownHeight = 300; // max-height of dropdown
45
-
46
- // Open upward if not enough space below and more space above
47
- if (spaceBelow < dropdownHeight && spaceAbove > spaceBelow) {
48
- setDropdownDirection('up');
49
- } else {
50
- setDropdownDirection('down');
51
- }
52
- }
53
- }, [isOpen]);
54
-
55
- const selectedOption = options.find(opt => opt.value === value);
56
- const iconSize = size === 'xs' ? iconSizes.xs : size === 'small' ? iconSizes.s : iconSizes.m;
57
-
58
- return (
59
- <div className={`ds-select-wrapper ${fullWidth ? 'ds-select-wrapper--full' : ''} ${disabled ? 'ds-select-wrapper--disabled' : ''}`}>
60
- {label && (
61
- <label id={labelId} className="ds-select-label">
62
- {label}
63
- </label>
64
- )}
65
- <div className="ds-select-container" ref={selectRef}>
66
- <button
67
- type="button"
68
- id={selectId}
69
- role="combobox"
70
- aria-haspopup="listbox"
71
- aria-expanded={isOpen}
72
- aria-labelledby={label ? labelId : undefined}
73
- aria-invalid={error ? 'true' : 'false'}
74
- aria-describedby={errorId}
75
- className={`ds-select-trigger ds-select-trigger--${size} ${error ? 'ds-select-trigger--error' : ''}`}
76
- onClick={() => !disabled && setIsOpen(!isOpen)}
77
- disabled={disabled}
78
- {...props}
79
- >
80
- <span className={selectedOption ? '' : 'ds-select-placeholder'}>
81
- {selectedOption?.label || placeholder}
82
- </span>
83
- <ChevronDown
84
- size={iconSize}
85
- strokeWidth={1.5}
86
- className={`ds-select-icon ${isOpen && dropdownDirection === 'down' ? 'ds-select-icon--open' : ''} ${isOpen && dropdownDirection === 'up' ? 'ds-select-icon--up' : ''}`}
87
- aria-hidden="true"
88
- />
89
- </button>
90
- {isOpen && (
91
- <div
92
- ref={dropdownRef}
93
- role="listbox"
94
- aria-labelledby={label ? labelId : undefined}
95
- className={`ds-select-dropdown ds-select-dropdown--${size} ds-select-dropdown--${dropdownDirection}`}
96
- >
97
- {options.map((option) => (
98
- <button
99
- key={option.value}
100
- type="button"
101
- role="option"
102
- aria-selected={value === option.value}
103
- className={`ds-select-option ds-select-option--${size} ${value === option.value ? 'ds-select-option--selected' : ''}`}
104
- onClick={() => {
105
- onChange?.(option.value);
106
- setIsOpen(false);
107
- }}
108
- >
109
- {option.label}
110
- </button>
111
- ))}
112
- </div>
113
- )}
114
- </div>
115
- {error && <span id={errorId} className="ds-select-error" role="alert">{error}</span>}
116
- </div>
117
- );
118
- }