@360crewing/ui 0.1.3

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 (106) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/LICENSE +21 -0
  3. package/README.md +46 -0
  4. package/dist/components/Avatar.d.ts +20 -0
  5. package/dist/components/Avatar.js +17 -0
  6. package/dist/components/Badge.d.ts +19 -0
  7. package/dist/components/Badge.js +10 -0
  8. package/dist/components/Breadcrumbs.d.ts +19 -0
  9. package/dist/components/Breadcrumbs.js +12 -0
  10. package/dist/components/Button.d.ts +38 -0
  11. package/dist/components/Button.js +50 -0
  12. package/dist/components/Card.d.ts +12 -0
  13. package/dist/components/Card.js +6 -0
  14. package/dist/components/Checkbox.d.ts +14 -0
  15. package/dist/components/Checkbox.js +9 -0
  16. package/dist/components/CheckboxField.d.ts +16 -0
  17. package/dist/components/CheckboxField.js +17 -0
  18. package/dist/components/CollapsibleFields.d.ts +9 -0
  19. package/dist/components/CollapsibleFields.js +8 -0
  20. package/dist/components/ContentLoader.d.ts +8 -0
  21. package/dist/components/ContentLoader.js +14 -0
  22. package/dist/components/Delimeter.d.ts +3 -0
  23. package/dist/components/Delimeter.js +6 -0
  24. package/dist/components/DetailItem.d.ts +8 -0
  25. package/dist/components/DetailItem.js +6 -0
  26. package/dist/components/DropdownButton.d.ts +15 -0
  27. package/dist/components/DropdownButton.js +29 -0
  28. package/dist/components/FileUpload.d.ts +32 -0
  29. package/dist/components/FileUpload.js +75 -0
  30. package/dist/components/FormActionButtons.d.ts +18 -0
  31. package/dist/components/FormActionButtons.js +10 -0
  32. package/dist/components/Icon.d.ts +20 -0
  33. package/dist/components/Icon.js +11 -0
  34. package/dist/components/IconButton.d.ts +14 -0
  35. package/dist/components/IconButton.js +9 -0
  36. package/dist/components/InformationPanel.d.ts +14 -0
  37. package/dist/components/InformationPanel.js +6 -0
  38. package/dist/components/LayoutBlock.d.ts +6 -0
  39. package/dist/components/LayoutBlock.js +5 -0
  40. package/dist/components/Page.d.ts +12 -0
  41. package/dist/components/Page.js +6 -0
  42. package/dist/components/Pagination.d.ts +19 -0
  43. package/dist/components/Pagination.js +35 -0
  44. package/dist/components/Popover.d.ts +27 -0
  45. package/dist/components/Popover.js +130 -0
  46. package/dist/components/SearchInput.d.ts +27 -0
  47. package/dist/components/SearchInput.js +44 -0
  48. package/dist/components/ShadowedBlock.d.ts +9 -0
  49. package/dist/components/ShadowedBlock.js +6 -0
  50. package/dist/components/SidebarMenu.d.ts +27 -0
  51. package/dist/components/SidebarMenu.js +16 -0
  52. package/dist/components/SkeletonLoader.d.ts +4 -0
  53. package/dist/components/SkeletonLoader.js +7 -0
  54. package/dist/components/StatusBadge.d.ts +20 -0
  55. package/dist/components/StatusBadge.js +11 -0
  56. package/dist/components/Table.d.ts +39 -0
  57. package/dist/components/Table.js +24 -0
  58. package/dist/components/Tabs.d.ts +34 -0
  59. package/dist/components/Tabs.js +95 -0
  60. package/dist/components/Tag.d.ts +20 -0
  61. package/dist/components/Tag.js +11 -0
  62. package/dist/components/TextField.d.ts +45 -0
  63. package/dist/components/TextField.js +53 -0
  64. package/dist/components/TextareaField.d.ts +18 -0
  65. package/dist/components/TextareaField.js +11 -0
  66. package/dist/components/Toggle.d.ts +10 -0
  67. package/dist/components/Toggle.js +9 -0
  68. package/dist/components/ToggleField.d.ts +16 -0
  69. package/dist/components/ToggleField.js +17 -0
  70. package/dist/components/Tooltip.d.ts +25 -0
  71. package/dist/components/Tooltip.js +128 -0
  72. package/dist/index.d.ts +64 -0
  73. package/dist/index.js +35 -0
  74. package/dist/styles/Avatar.css +47 -0
  75. package/dist/styles/Badge.css +172 -0
  76. package/dist/styles/Breadcrumbs.css +54 -0
  77. package/dist/styles/Button.css +416 -0
  78. package/dist/styles/Card.css +34 -0
  79. package/dist/styles/Checkbox.css +102 -0
  80. package/dist/styles/CheckboxField.css +75 -0
  81. package/dist/styles/CollapsibleFields.css +53 -0
  82. package/dist/styles/Delimeter.css +7 -0
  83. package/dist/styles/DetailItem.css +18 -0
  84. package/dist/styles/DropdownButton.css +82 -0
  85. package/dist/styles/Error.css +14 -0
  86. package/dist/styles/FileUpload.css +113 -0
  87. package/dist/styles/Icon.css +12 -0
  88. package/dist/styles/IconButton.css +68 -0
  89. package/dist/styles/InformationPanel.css +84 -0
  90. package/dist/styles/Page.css +46 -0
  91. package/dist/styles/Pagination.css +150 -0
  92. package/dist/styles/Popover.css +28 -0
  93. package/dist/styles/ShadowedBlock.css +13 -0
  94. package/dist/styles/SidebarMenu.css +151 -0
  95. package/dist/styles/StatusBadge.css +63 -0
  96. package/dist/styles/Table.css +126 -0
  97. package/dist/styles/Tabs.css +193 -0
  98. package/dist/styles/Tag.css +110 -0
  99. package/dist/styles/TextField.css +276 -0
  100. package/dist/styles/Toggle.css +105 -0
  101. package/dist/styles/ToggleField.css +73 -0
  102. package/dist/styles/Tooltip.css +30 -0
  103. package/dist/styles/tokens.css +361 -0
  104. package/dist/styles/typography.css +169 -0
  105. package/dist/styles.css +33 -0
  106. package/package.json +50 -0
@@ -0,0 +1,193 @@
1
+ /* =====================================================================
2
+ * DS Tabs — tab navigation primitive.
3
+ * Variants: underline (default) | segmented | pill
4
+ * Sizes: sm | md | lg
5
+ * ===================================================================== */
6
+
7
+ .ds-tabs {
8
+ --ds-tabs-trigger-height: var(--control-height-md);
9
+ --ds-tabs-trigger-padding-x: var(--space-12);
10
+ --ds-tabs-font-size: var(--font-size-sm);
11
+ --ds-tabs-gap: var(--space-2);
12
+
13
+ display: flex;
14
+ flex-direction: column;
15
+ min-width: 0;
16
+ }
17
+
18
+ .ds-tabs--sm {
19
+ --ds-tabs-trigger-height: var(--control-height-sm);
20
+ --ds-tabs-trigger-padding-x: var(--space-8);
21
+ --ds-tabs-font-size: var(--font-size-xs);
22
+ }
23
+ .ds-tabs--lg {
24
+ --ds-tabs-trigger-height: var(--control-height-lg);
25
+ --ds-tabs-trigger-padding-x: var(--space-16);
26
+ --ds-tabs-font-size: var(--font-size-base);
27
+ }
28
+
29
+ .ds-tabs__list {
30
+ display: inline-flex;
31
+ align-items: stretch;
32
+ gap: var(--ds-tabs-gap);
33
+ min-width: 0;
34
+ }
35
+
36
+ .ds-tabs--full-width .ds-tabs__list {
37
+ display: flex;
38
+ width: 100%;
39
+ }
40
+ .ds-tabs--full-width .ds-tabs__trigger {
41
+ flex: 1 1 0;
42
+ justify-content: center;
43
+ }
44
+
45
+ .ds-tabs__trigger {
46
+ display: inline-flex;
47
+ align-items: center;
48
+ justify-content: center;
49
+ gap: var(--space-6);
50
+ height: var(--ds-tabs-trigger-height);
51
+ padding: 0 var(--ds-tabs-trigger-padding-x);
52
+ border: 1px solid transparent;
53
+ background: transparent;
54
+ color: var(--text-secondary);
55
+ font-family: var(--font-family-base);
56
+ font-weight: var(--font-weight-medium);
57
+ font-size: var(--ds-tabs-font-size);
58
+ line-height: 1;
59
+ cursor: pointer;
60
+ white-space: nowrap;
61
+ transition:
62
+ background-color var(--duration-fast) var(--easing-standard),
63
+ border-color var(--duration-fast) var(--easing-standard),
64
+ color var(--duration-fast) var(--easing-standard),
65
+ box-shadow var(--duration-fast) var(--easing-standard);
66
+ }
67
+ .ds-tabs__trigger:focus-visible {
68
+ outline: none;
69
+ box-shadow: var(--shadow-focus-brand);
70
+ }
71
+ .ds-tabs__trigger.is-disabled,
72
+ .ds-tabs__trigger[disabled] {
73
+ color: var(--text-disabled);
74
+ cursor: not-allowed;
75
+ pointer-events: none;
76
+ }
77
+
78
+ .ds-tabs__icon {
79
+ display: inline-flex;
80
+ flex: 0 0 auto;
81
+ width: 1em;
82
+ height: 1em;
83
+ align-items: center;
84
+ justify-content: center;
85
+ }
86
+ .ds-tabs__icon > svg {
87
+ width: 1em;
88
+ height: 1em;
89
+ fill: currentColor;
90
+ }
91
+ .ds-tabs__label {
92
+ min-width: 0;
93
+ text-overflow: ellipsis;
94
+ overflow: hidden;
95
+ }
96
+ .ds-tabs__badge {
97
+ display: inline-flex;
98
+ align-items: center;
99
+ justify-content: center;
100
+ min-width: 18px;
101
+ height: 18px;
102
+ padding: 0 var(--space-4);
103
+ background: var(--surface-secondary);
104
+ color: var(--text-secondary);
105
+ border-radius: var(--radius-pill);
106
+ font-size: 10px;
107
+ font-weight: var(--font-weight-semibold);
108
+ }
109
+ .ds-tabs__trigger.is-active .ds-tabs__badge {
110
+ background: var(--surface-brand-minimal);
111
+ color: var(--text-brand);
112
+ }
113
+
114
+ .ds-tabs__panel {
115
+ padding-top: var(--space-16);
116
+ }
117
+
118
+ /* ---------- Variant: underline ---------- */
119
+ .ds-tabs--underline .ds-tabs__list {
120
+ border-bottom: 1px solid var(--border-secondary);
121
+ position: relative;
122
+ }
123
+ .ds-tabs--underline .ds-tabs__trigger {
124
+ position: relative;
125
+ border-radius: 0;
126
+ margin-bottom: -1px;
127
+ }
128
+ .ds-tabs--underline .ds-tabs__trigger:hover:not(.is-disabled) {
129
+ color: var(--text-primary);
130
+ }
131
+ .ds-tabs--underline .ds-tabs__trigger.is-active {
132
+ color: var(--text-brand);
133
+ }
134
+
135
+ /* Sliding underline — single shared element positioned & sized in JS
136
+ * (see Tabs.tsx measure()). Transitions glide between triggers; opacity
137
+ * fade hides the first paint before measurement runs. */
138
+ .ds-tabs__indicator {
139
+ position: absolute;
140
+ left: 0;
141
+ bottom: -1px;
142
+ height: 2px;
143
+ background: var(--surface-brand);
144
+ border-radius: 2px 2px 0 0;
145
+ pointer-events: none;
146
+ will-change: transform, width;
147
+ transition:
148
+ transform 260ms cubic-bezier(0.4, 0, 0.2, 1),
149
+ width 260ms cubic-bezier(0.4, 0, 0.2, 1),
150
+ opacity 160ms ease;
151
+ }
152
+
153
+ /* Respect users who turn off animations system-wide. */
154
+ @media (prefers-reduced-motion: reduce) {
155
+ .ds-tabs__indicator { transition: opacity 160ms ease; }
156
+ }
157
+
158
+ /* ---------- Variant: segmented ---------- */
159
+ .ds-tabs--segmented .ds-tabs__list {
160
+ background: var(--surface-secondary-light);
161
+ border-radius: var(--radius-lg);
162
+ padding: var(--space-2);
163
+ gap: 0;
164
+ }
165
+ .ds-tabs--segmented .ds-tabs__trigger {
166
+ border-radius: calc(var(--radius-lg) - var(--space-2));
167
+ color: var(--text-secondary);
168
+ }
169
+ .ds-tabs--segmented .ds-tabs__trigger:hover:not(.is-disabled) {
170
+ color: var(--text-primary);
171
+ }
172
+ .ds-tabs--segmented .ds-tabs__trigger.is-active {
173
+ background: var(--surface-primary);
174
+ color: var(--text-primary);
175
+ box-shadow: var(--shadow-sm);
176
+ }
177
+
178
+ /* ---------- Variant: pill ---------- */
179
+ .ds-tabs--pill .ds-tabs__trigger {
180
+ border-radius: var(--radius-pill);
181
+ background: transparent;
182
+ }
183
+ .ds-tabs--pill .ds-tabs__trigger:hover:not(.is-disabled) {
184
+ background: var(--surface-secondary-light);
185
+ color: var(--text-primary);
186
+ }
187
+ .ds-tabs--pill .ds-tabs__trigger.is-active {
188
+ background: var(--surface-brand);
189
+ color: var(--text-tertiary);
190
+ }
191
+ .ds-tabs--pill .ds-tabs__trigger.is-active:hover {
192
+ background: var(--surface-brand-light);
193
+ }
@@ -0,0 +1,110 @@
1
+ /* =====================================================================
2
+ * DS Tag / Chip
3
+ * Mirrors Figma `Tag` set (6 colors × Filled / Soft).
4
+ * ===================================================================== */
5
+
6
+ .ds-tag {
7
+ display: inline-flex;
8
+ align-items: center;
9
+ gap: var(--space-2);
10
+ height: 24px;
11
+ padding: 0 var(--space-5);
12
+ border-radius: var(--radius-pill);
13
+ font-family: var(--font-family-base);
14
+ font-size: var(--font-size-sm);
15
+ font-weight: var(--font-weight-medium);
16
+ line-height: 1;
17
+ white-space: nowrap;
18
+ border: 1px solid transparent;
19
+ }
20
+
21
+ .ds-tag__label {
22
+ display: inline-flex;
23
+ align-items: center;
24
+ }
25
+
26
+ .ds-tag__icon {
27
+ display: inline-flex;
28
+ width: 1em;
29
+ height: 1em;
30
+ align-items: center;
31
+ justify-content: center;
32
+ }
33
+
34
+ .ds-tag__remove {
35
+ appearance: none;
36
+ background: transparent;
37
+ border: none;
38
+ color: inherit;
39
+ font-size: 14px;
40
+ line-height: 1;
41
+ padding: 0 0 0 var(--space-2);
42
+ cursor: pointer;
43
+ opacity: 0.6;
44
+ }
45
+
46
+ .ds-tag__remove:hover {
47
+ opacity: 1;
48
+ }
49
+
50
+ /* ===== Color × Style matrix ===== */
51
+
52
+ /* Brand */
53
+ .ds-tag--brand.ds-tag--filled {
54
+ background-color: var(--surface-brand);
55
+ color: var(--text-tertiary);
56
+ }
57
+ .ds-tag--brand.ds-tag--soft {
58
+ background-color: var(--surface-brand-minimal);
59
+ color: var(--text-brand);
60
+ }
61
+
62
+ /* Accent */
63
+ .ds-tag--accent.ds-tag--filled {
64
+ background-color: var(--surface-accent);
65
+ color: var(--text-tertiary);
66
+ }
67
+ .ds-tag--accent.ds-tag--soft {
68
+ background-color: var(--surface-accent-minimal);
69
+ color: var(--text-accent);
70
+ }
71
+
72
+ /* Success */
73
+ .ds-tag--success.ds-tag--filled {
74
+ background-color: var(--surface-success);
75
+ color: var(--text-tertiary);
76
+ }
77
+ .ds-tag--success.ds-tag--soft {
78
+ background-color: var(--surface-success-light);
79
+ color: var(--text-success);
80
+ }
81
+
82
+ /* Warning */
83
+ .ds-tag--warning.ds-tag--filled {
84
+ background-color: var(--surface-warning);
85
+ color: var(--text-tertiary);
86
+ }
87
+ .ds-tag--warning.ds-tag--soft {
88
+ background-color: var(--surface-warning-light);
89
+ color: var(--text-warning);
90
+ }
91
+
92
+ /* Error */
93
+ .ds-tag--error.ds-tag--filled {
94
+ background-color: var(--surface-error);
95
+ color: var(--text-tertiary);
96
+ }
97
+ .ds-tag--error.ds-tag--soft {
98
+ background-color: var(--surface-error-minimal);
99
+ color: var(--text-error);
100
+ }
101
+
102
+ /* Neutral */
103
+ .ds-tag--neutral.ds-tag--filled {
104
+ background-color: var(--surface-secondary);
105
+ color: var(--text-primary);
106
+ }
107
+ .ds-tag--neutral.ds-tag--soft {
108
+ background-color: var(--surface-secondary-light);
109
+ color: var(--text-secondary);
110
+ }
@@ -0,0 +1,276 @@
1
+ .text-field,
2
+ .textarea-field {
3
+ display: flex;
4
+ gap: 10px;
5
+ position: relative;
6
+
7
+ @media (max-width: 768px) {
8
+ flex-direction: column;
9
+ gap: 6px;
10
+ }
11
+
12
+ .label {
13
+ font-size: 12px;
14
+ width: 180px;
15
+ flex-shrink: 0;
16
+ align-self: center;
17
+
18
+ @media (max-width: 768px) {
19
+ font-size: 11px;
20
+ align-self: flex-start;
21
+ }
22
+ }
23
+
24
+ input {
25
+ background-color: white;
26
+ }
27
+
28
+ .input-container {
29
+ display: flex;
30
+ flex-direction: column;
31
+ gap: 8px;
32
+ width: 100%;
33
+ }
34
+
35
+ .form-control {
36
+ height: 40px;
37
+ padding: 14px 16px;
38
+ border-radius: 4px;
39
+ outline: none;
40
+ border: 1px solid var(--stroke-color);
41
+ font-size: 12px;
42
+ width: 100%;
43
+
44
+ &:focus {
45
+ border: 1px solid var(--text-brand);
46
+ }
47
+
48
+ &::placeholder {
49
+ color: var(--deactivate-grey-color);
50
+ font-size: 12px;
51
+ }
52
+ }
53
+
54
+ &[data-before-content] {
55
+ &::before {
56
+ display: flex;
57
+ align-items: center;
58
+ justify-content: center;
59
+ width: 20px;
60
+ height: 20px;
61
+ color: #B1BBC2;
62
+ background-color: var(--technical-gray-color);
63
+ border-radius: 50%;
64
+ content: attr(data-before-content);
65
+ position: absolute;
66
+ left: calc(-20px - 10px);
67
+ bottom: 10px;
68
+ }
69
+ }
70
+
71
+ &[data-after-content] {
72
+ &::after {
73
+ display: flex;
74
+ align-items: center;
75
+ justify-content: center;
76
+ width: 20px;
77
+ height: 20px;
78
+ color: #B1BBC2;
79
+ background-color: var(--technical-gray-color);
80
+ border-radius: 50%;
81
+ content: attr(data-after-content);
82
+ position: absolute;
83
+ left: calc(calc(-20px * 2) - 10px - 6px);
84
+ bottom: 10px;
85
+ }
86
+ }
87
+
88
+ &[data-unit] {
89
+ &::after {
90
+ content: attr(data-unit);
91
+ position: absolute;
92
+ right: 16px;
93
+ bottom: 14px;
94
+ font-size: 12px;
95
+ color: var(--deactivate-grey-color);
96
+ }
97
+ }
98
+
99
+ &.mandatory .label::after {
100
+ content: "*";
101
+ color: red;
102
+ margin-left: 2px;
103
+ }
104
+ }
105
+
106
+ .textarea-field {
107
+ .form-control {
108
+ height: 80px;
109
+ }
110
+ }
111
+
112
+ /* =====================================================================
113
+ * DS TextField — canonical design-system input.
114
+ * Activated when caller passes `size` prop. Pre-DS callers keep using
115
+ * the legacy `.text-field` / `.form-control` classes above.
116
+ * Sizes: sm (32) | md (40) | lg (44)
117
+ * States: default | focus | error | success | disabled
118
+ * Slots: prefix (text) | suffix (text) | leading icon | trailing icon
119
+ * ===================================================================== */
120
+
121
+ .ds-field {
122
+ display: flex;
123
+ flex-direction: column;
124
+ gap: var(--space-3);
125
+ font-family: var(--font-family-base);
126
+ }
127
+
128
+ .ds-field__label {
129
+ display: inline-flex;
130
+ align-items: center;
131
+ gap: var(--space-2);
132
+ color: var(--text-primary);
133
+ font-size: var(--font-size-sm);
134
+ font-weight: var(--font-weight-semibold);
135
+ line-height: 1.2;
136
+ }
137
+ .ds-field__required {
138
+ color: var(--text-error);
139
+ font-weight: var(--font-weight-bold);
140
+ }
141
+ .ds-field__optional {
142
+ color: var(--text-secondary);
143
+ font-weight: var(--font-weight-regular);
144
+ }
145
+
146
+ .ds-field__hint {
147
+ color: var(--text-secondary);
148
+ font-size: var(--font-size-xs);
149
+ line-height: 1.3;
150
+ }
151
+ .ds-field__error {
152
+ color: var(--text-error);
153
+ font-size: var(--font-size-xs);
154
+ line-height: 1.3;
155
+ display: inline-flex;
156
+ gap: var(--space-2);
157
+ }
158
+
159
+ .ds-input {
160
+ position: relative;
161
+ display: inline-flex;
162
+ align-items: center;
163
+ width: 100%;
164
+ background-color: var(--surface-primary);
165
+ border: 1px solid var(--border-primary);
166
+ border-radius: var(--radius-sm);
167
+ transition:
168
+ border-color var(--duration-fast) var(--easing-standard),
169
+ box-shadow var(--duration-fast) var(--easing-standard);
170
+ }
171
+
172
+ .ds-input:hover:not(.is-disabled):not(.is-error) {
173
+ border-color: var(--border-strong);
174
+ }
175
+ .ds-input:focus-within:not(.is-error) {
176
+ border-color: var(--border-brand);
177
+ box-shadow: var(--shadow-focus-brand);
178
+ }
179
+
180
+ .ds-input.is-error {
181
+ border-color: var(--border-error);
182
+ }
183
+ .ds-input.is-error:focus-within {
184
+ box-shadow: var(--shadow-focus-error);
185
+ }
186
+
187
+ .ds-input.is-success {
188
+ border-color: var(--border-success);
189
+ }
190
+
191
+ .ds-input.is-disabled,
192
+ .ds-input:has(input:disabled) {
193
+ background-color: var(--surface-disabled);
194
+ border-color: var(--border-disabled);
195
+ cursor: not-allowed;
196
+ }
197
+ .ds-input.is-disabled .ds-input__control,
198
+ .ds-input:has(input:disabled) .ds-input__control {
199
+ color: var(--text-disabled);
200
+ cursor: not-allowed;
201
+ }
202
+
203
+ /* Sizes */
204
+ .ds-input--sm { min-height: var(--control-height-sm); padding: 0 var(--space-8); font-size: var(--font-size-sm); }
205
+ .ds-input--md { min-height: var(--control-height-md); padding: 0 var(--space-10); font-size: var(--font-size-sm); }
206
+ .ds-input--lg { min-height: var(--control-height-lg); padding: 0 var(--space-12); font-size: var(--font-size-base); }
207
+
208
+ @media (pointer: coarse) {
209
+ .ds-input--sm,
210
+ .ds-input--md { min-height: var(--touch-target-min); }
211
+ }
212
+
213
+ /* Native control */
214
+ .ds-input__control {
215
+ flex: 1 1 auto;
216
+ min-width: 0;
217
+ height: 100%;
218
+ border: 0;
219
+ outline: none;
220
+ background: transparent;
221
+ color: var(--text-primary);
222
+ font: inherit;
223
+ padding: 0;
224
+ }
225
+ .ds-input__control::placeholder {
226
+ color: var(--text-placeholder);
227
+ }
228
+ .ds-input__control:disabled {
229
+ cursor: not-allowed;
230
+ }
231
+
232
+ /* Adornments — leading/trailing icon or text */
233
+ .ds-input__addon {
234
+ flex: 0 0 auto;
235
+ display: inline-flex;
236
+ align-items: center;
237
+ color: var(--icon-primary);
238
+ font-size: var(--font-size-sm);
239
+ gap: var(--space-2);
240
+ }
241
+ .ds-input__addon--leading { padding-right: var(--space-4); }
242
+ .ds-input__addon--trailing { padding-left: var(--space-4); }
243
+
244
+ .ds-input__addon > svg {
245
+ width: 1em;
246
+ height: 1em;
247
+ fill: currentColor;
248
+ }
249
+
250
+ /* Suffix (e.g. unit "kg", "USD") */
251
+ .ds-input__suffix {
252
+ flex: 0 0 auto;
253
+ color: var(--text-secondary);
254
+ font-size: var(--font-size-sm);
255
+ padding-left: var(--space-4);
256
+ user-select: none;
257
+ }
258
+
259
+ /* Inline action — for the trailing clear (×) / show-password (👁) button */
260
+ .ds-input__action {
261
+ appearance: none;
262
+ background: transparent;
263
+ border: 0;
264
+ padding: 0 var(--space-2);
265
+ margin-left: var(--space-2);
266
+ cursor: pointer;
267
+ color: var(--icon-primary);
268
+ display: inline-flex;
269
+ align-items: center;
270
+ border-radius: var(--radius-pill);
271
+ }
272
+ .ds-input__action:hover { color: var(--icon-brand); }
273
+ .ds-input__action:focus-visible {
274
+ outline: none;
275
+ box-shadow: var(--shadow-focus-brand);
276
+ }
@@ -0,0 +1,105 @@
1
+ /* =====================================================================
2
+ * DS Toggle (switch)
3
+ * Mirrors Figma `Toggle` set (sm 28×16 / md 36×20 × Off / On / Disabled).
4
+ * Tokens: surface-tertiary, surface-brand, surface-disabled, surface-primary.
5
+ * ===================================================================== */
6
+
7
+ .ds-toggle {
8
+ display: inline-flex;
9
+ align-items: center;
10
+ gap: var(--space-6);
11
+ cursor: pointer;
12
+ user-select: none;
13
+ line-height: 1;
14
+ }
15
+
16
+ .ds-toggle--disabled {
17
+ cursor: not-allowed;
18
+ }
19
+
20
+ .ds-toggle__input {
21
+ /* Visually hide native checkbox, but keep it accessible. */
22
+ position: absolute;
23
+ width: 1px;
24
+ height: 1px;
25
+ padding: 0;
26
+ margin: -1px;
27
+ overflow: hidden;
28
+ clip: rect(0 0 0 0);
29
+ white-space: nowrap;
30
+ border: 0;
31
+ }
32
+
33
+ .ds-toggle__track {
34
+ position: relative;
35
+ flex-shrink: 0;
36
+ display: inline-block;
37
+ background-color: var(--surface-tertiary);
38
+ border-radius: var(--radius-pill);
39
+ transition:
40
+ background-color var(--duration-fast) var(--easing-standard);
41
+ }
42
+
43
+ .ds-toggle--sm .ds-toggle__track {
44
+ width: 28px;
45
+ height: 16px;
46
+ }
47
+
48
+ .ds-toggle--md .ds-toggle__track {
49
+ width: 36px;
50
+ height: 20px;
51
+ }
52
+
53
+ .ds-toggle__thumb {
54
+ position: absolute;
55
+ top: 2px;
56
+ left: 2px;
57
+ background-color: var(--surface-primary);
58
+ border-radius: 50%;
59
+ box-shadow: 0 1px 2px rgba(38, 41, 43, 0.2);
60
+ transition:
61
+ left var(--duration-fast) var(--easing-standard),
62
+ background-color var(--duration-fast) var(--easing-standard);
63
+ }
64
+
65
+ .ds-toggle--sm .ds-toggle__thumb {
66
+ width: 12px;
67
+ height: 12px;
68
+ }
69
+
70
+ .ds-toggle--md .ds-toggle__thumb {
71
+ width: 16px;
72
+ height: 16px;
73
+ }
74
+
75
+ .ds-toggle__input:checked + .ds-toggle__track {
76
+ background-color: var(--surface-brand);
77
+ }
78
+
79
+ .ds-toggle--sm .ds-toggle__input:checked + .ds-toggle__track .ds-toggle__thumb {
80
+ left: 14px;
81
+ }
82
+
83
+ .ds-toggle--md .ds-toggle__input:checked + .ds-toggle__track .ds-toggle__thumb {
84
+ left: 18px;
85
+ }
86
+
87
+ .ds-toggle__input:disabled + .ds-toggle__track {
88
+ background-color: var(--surface-disabled);
89
+ cursor: not-allowed;
90
+ }
91
+
92
+ .ds-toggle__input:focus-visible + .ds-toggle__track {
93
+ box-shadow: var(--shadow-focus-brand);
94
+ }
95
+
96
+ .ds-toggle__label {
97
+ font-family: var(--font-family-base);
98
+ font-size: var(--font-size-sm);
99
+ color: var(--text-primary);
100
+ line-height: 1.3;
101
+ }
102
+
103
+ .ds-toggle--disabled .ds-toggle__label {
104
+ color: var(--text-disabled);
105
+ }