@db-vincent/components 0.1.0 → 0.1.1

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 (66) hide show
  1. package/package.json +3 -3
  2. package/src/astro/Avatar.astro +88 -0
  3. package/src/astro/AvatarGroup.astro +63 -0
  4. package/src/astro/Chip.astro +22 -3
  5. package/src/astro/Drawer.astro +30 -0
  6. package/src/astro/Grid.astro +7 -1
  7. package/src/astro/GridItem.astro +3 -1
  8. package/src/astro/Menu.astro +151 -0
  9. package/src/astro/MenuItem.astro +57 -0
  10. package/src/astro/Modal.astro +10 -3
  11. package/src/astro/Pagination.astro +82 -32
  12. package/src/astro/Popover.astro +51 -0
  13. package/src/astro/Progress.astro +71 -0
  14. package/src/astro/Select.astro +211 -194
  15. package/src/astro/Skeleton.astro +4 -2
  16. package/src/astro/Spinner.astro +1 -0
  17. package/src/astro/Stepper.astro +82 -0
  18. package/src/astro/Switch.astro +78 -0
  19. package/src/astro/Table.astro +90 -76
  20. package/src/astro/Tabs.astro +83 -0
  21. package/src/astro/TextField.astro +100 -82
  22. package/src/astro/Toast.astro +1 -1
  23. package/src/astro/Tooltip.astro +54 -0
  24. package/src/data/icons.ts +16 -0
  25. package/src/scripts/avatar.ts +33 -0
  26. package/src/scripts/menu.ts +218 -0
  27. package/src/scripts/tabs.ts +127 -0
  28. package/src/scripts/toast.ts +45 -11
  29. package/src/scripts/tooltip.ts +127 -0
  30. package/src/styles/accordion.css +2 -0
  31. package/src/styles/alert.css +2 -0
  32. package/src/styles/avatar.css +131 -0
  33. package/src/styles/badge.css +2 -0
  34. package/src/styles/base.css +2 -0
  35. package/src/styles/breadcrumbs.css +2 -0
  36. package/src/styles/button.css +13 -2
  37. package/src/styles/card.css +8 -4
  38. package/src/styles/chip.css +2 -0
  39. package/src/styles/choice.css +8 -2
  40. package/src/styles/code.css +2 -0
  41. package/src/styles/empty.css +2 -0
  42. package/src/styles/example.css +2 -0
  43. package/src/styles/grid.css +2 -0
  44. package/src/styles/input.css +11 -1
  45. package/src/styles/menu.css +151 -0
  46. package/src/styles/modal.css +169 -27
  47. package/src/styles/motion.css +21 -3
  48. package/src/styles/nav.css +2 -0
  49. package/src/styles/navbar.css +2 -0
  50. package/src/styles/page-header.css +3 -0
  51. package/src/styles/pagination.css +4 -0
  52. package/src/styles/popover.css +134 -0
  53. package/src/styles/progress.css +95 -0
  54. package/src/styles/section.css +2 -0
  55. package/src/styles/select.css +12 -1
  56. package/src/styles/skeleton.css +2 -0
  57. package/src/styles/spinner.css +2 -0
  58. package/src/styles/sr-only.css +14 -0
  59. package/src/styles/stepper.css +169 -0
  60. package/src/styles/switch.css +143 -0
  61. package/src/styles/table.css +2 -0
  62. package/src/styles/tabs.css +120 -0
  63. package/src/styles/theme-toggle.css +2 -0
  64. package/src/styles/toast.css +41 -23
  65. package/src/styles/tooltip.css +63 -0
  66. package/src/styles/topbar.css +2 -0
@@ -0,0 +1,143 @@
1
+ @layer reset, tokens, base, components, motion, utilities;
2
+
3
+ @layer components {
4
+ .ds-switch {
5
+ --ds-switch-w: var(--switch-track-width-md);
6
+ --ds-switch-h: var(--switch-track-height-md);
7
+ align-items: flex-start;
8
+ cursor: pointer;
9
+ display: inline-flex;
10
+ gap: var(--switch-gap);
11
+ position: relative;
12
+ }
13
+
14
+ .ds-switch--sm {
15
+ --ds-switch-w: var(--switch-track-width-sm);
16
+ --ds-switch-h: var(--switch-track-height-sm);
17
+ }
18
+
19
+ .ds-switch__input {
20
+ height: var(--ds-switch-h);
21
+ margin: 0;
22
+ opacity: 0;
23
+ position: absolute;
24
+ width: var(--ds-switch-w);
25
+ }
26
+
27
+ .ds-switch__track {
28
+ align-items: center;
29
+ background: var(--switch-track-bg);
30
+ border-radius: var(--radius-full);
31
+ display: inline-flex;
32
+ flex: none;
33
+ height: var(--ds-switch-h);
34
+ padding: var(--switch-thumb-inset);
35
+ transition:
36
+ background-color var(--switch-duration) var(--switch-ease),
37
+ transform var(--duration-fast) var(--switch-ease);
38
+ width: var(--ds-switch-w);
39
+ }
40
+
41
+ .ds-switch__thumb {
42
+ background: var(--switch-thumb-bg);
43
+ border-radius: var(--radius-full);
44
+ height: calc(var(--ds-switch-h) - var(--switch-thumb-inset) * 2);
45
+ transition:
46
+ background-color var(--switch-duration) var(--switch-ease),
47
+ transform var(--switch-duration) var(--switch-ease);
48
+ width: calc(var(--ds-switch-h) - var(--switch-thumb-inset) * 2);
49
+ }
50
+
51
+ .ds-switch__input:checked + .ds-switch__track {
52
+ background: var(--switch-track-bg-checked);
53
+ }
54
+
55
+ .ds-switch__input:checked + .ds-switch__track .ds-switch__thumb {
56
+ background: var(--switch-thumb-bg-checked);
57
+ transform: translateX(calc(var(--ds-switch-w) - var(--ds-switch-h)));
58
+ }
59
+
60
+ @media (hover: hover) and (pointer: fine) {
61
+ .ds-switch:hover .ds-switch__input:not(:disabled) + .ds-switch__track {
62
+ background: var(--switch-track-bg-hover);
63
+ }
64
+
65
+ .ds-switch:hover
66
+ .ds-switch__input:not(:disabled):checked
67
+ + .ds-switch__track {
68
+ background: var(--switch-track-bg-checked-hover);
69
+ }
70
+ }
71
+
72
+ .ds-switch:has(.ds-switch__input:not(:disabled)):active .ds-switch__track {
73
+ transform: scale(var(--switch-press-scale));
74
+ }
75
+
76
+ .ds-switch__input:focus-visible + .ds-switch__track {
77
+ outline: var(--switch-focus-width) solid var(--switch-focus-color);
78
+ outline-offset: var(--switch-focus-offset);
79
+ }
80
+
81
+ .ds-switch__input[aria-invalid="true"] + .ds-switch__track {
82
+ box-shadow: inset 0 0 0 1px var(--switch-track-border-invalid);
83
+ }
84
+
85
+ .ds-switch__input:disabled + .ds-switch__track {
86
+ background: var(--switch-track-bg-disabled);
87
+ box-shadow: inset 0 0 0 1px var(--switch-track-border-disabled);
88
+ }
89
+
90
+ .ds-switch__input:disabled + .ds-switch__track .ds-switch__thumb {
91
+ background: var(--switch-thumb-bg-disabled);
92
+ }
93
+
94
+ .ds-switch:has(.ds-switch__input:disabled) {
95
+ cursor: not-allowed;
96
+ }
97
+
98
+ .ds-switch__label {
99
+ color: var(--switch-label-fg);
100
+ font-size: var(--text-sm);
101
+ line-height: var(--leading-sm);
102
+ /* Centre the first line on the track. */
103
+ padding-block-start: calc((var(--ds-switch-h) - var(--leading-sm)) / 2);
104
+ }
105
+
106
+ .ds-switch:has(.ds-switch__input:disabled) .ds-switch__label {
107
+ color: var(--switch-label-fg-disabled);
108
+ }
109
+
110
+ .ds-switch__hint,
111
+ .ds-switch__error {
112
+ display: block;
113
+ font-size: var(--text-sm);
114
+ line-height: var(--leading-sm);
115
+ margin-block-start: var(--space-0-5);
116
+ }
117
+
118
+ .ds-switch__hint {
119
+ color: var(--switch-hint-fg);
120
+ }
121
+
122
+ .ds-switch__error {
123
+ align-items: flex-start;
124
+ color: var(--switch-error-fg);
125
+ display: flex;
126
+ font-weight: var(--weight-medium);
127
+ gap: var(--space-1);
128
+ }
129
+
130
+ @media (prefers-reduced-motion: reduce) {
131
+ .ds-switch__thumb {
132
+ transition-property: background-color;
133
+ }
134
+
135
+ .ds-switch__track {
136
+ transition-property: background-color;
137
+ }
138
+
139
+ .ds-switch:has(.ds-switch__input:not(:disabled)):active .ds-switch__track {
140
+ transform: none;
141
+ }
142
+ }
143
+ }
@@ -1,3 +1,5 @@
1
+ @layer reset, tokens, base, components, motion, utilities;
2
+
1
3
  @layer components {
2
4
  .ds-table-wrap {
3
5
  border: 1px solid var(--table-border);
@@ -0,0 +1,120 @@
1
+ @layer reset, tokens, base, components, motion, utilities;
2
+
3
+ @layer components {
4
+ .ds-tabs {
5
+ display: grid;
6
+ width: 100%;
7
+ }
8
+
9
+ .ds-tabs__list {
10
+ border-block-end: 1px solid var(--tabs-list-border);
11
+ display: flex;
12
+ gap: var(--tabs-list-gap);
13
+ overflow-x: auto;
14
+ position: relative;
15
+ scrollbar-width: none;
16
+ }
17
+
18
+ .ds-tabs__tab {
19
+ align-items: center;
20
+ background: transparent;
21
+ border: 0;
22
+ border-radius: var(--tabs-tab-radius);
23
+ color: var(--tabs-tab-fg);
24
+ cursor: pointer;
25
+ display: inline-flex;
26
+ flex: none;
27
+ font-family: var(--font-body);
28
+ font-size: var(--tabs-tab-font-size);
29
+ font-weight: var(--tabs-tab-font-weight);
30
+ height: var(--tabs-tab-height);
31
+ line-height: var(--leading-sm);
32
+ padding-inline: var(--tabs-tab-padding-x);
33
+ position: relative;
34
+ transition:
35
+ background-color var(--duration-fast) var(--tabs-ease),
36
+ color var(--duration-fast) var(--tabs-ease),
37
+ transform var(--duration-fast) var(--tabs-ease);
38
+ white-space: nowrap;
39
+ }
40
+
41
+ .ds-tabs__tab[aria-selected="true"] {
42
+ color: var(--tabs-tab-fg-selected);
43
+ }
44
+
45
+ @media (hover: hover) and (pointer: fine) {
46
+ .ds-tabs__tab:hover:not(:disabled):not([aria-selected="true"]) {
47
+ background: var(--tabs-tab-bg-hover);
48
+ color: var(--tabs-tab-fg-hover);
49
+ }
50
+ }
51
+
52
+ .ds-tabs__tab:active:not(:disabled) {
53
+ transform: scale(0.97);
54
+ }
55
+
56
+ .ds-tabs__tab:focus-visible {
57
+ outline: var(--tabs-focus-width) solid var(--tabs-focus-color);
58
+ outline-offset: var(--tabs-focus-offset);
59
+ }
60
+
61
+ .ds-tabs__tab:disabled {
62
+ color: var(--tabs-tab-fg-disabled);
63
+ cursor: not-allowed;
64
+ }
65
+
66
+ /* Without script the selected tab carries its own underline. */
67
+ .ds-tabs__list:not([data-indicator])
68
+ .ds-tabs__tab[aria-selected="true"]::after {
69
+ background: var(--tabs-indicator-bg);
70
+ content: "";
71
+ height: var(--tabs-indicator-height);
72
+ inset-block-end: 0;
73
+ inset-inline: 0;
74
+ position: absolute;
75
+ }
76
+
77
+ /*
78
+ * Script measures the selected tab and sets --ds-tabs-x (px) and
79
+ * --ds-tabs-scale (unitless) against the full scroll width (--ds-tabs-track).
80
+ */
81
+ .ds-tabs__indicator {
82
+ background: var(--tabs-indicator-bg);
83
+ height: var(--tabs-indicator-height);
84
+ inset-block-end: 0;
85
+ left: 0;
86
+ pointer-events: none;
87
+ position: absolute;
88
+ transform: translateX(var(--ds-tabs-x, 0)) scaleX(var(--ds-tabs-scale, 0));
89
+ transform-origin: left;
90
+ width: var(--ds-tabs-track, 100%);
91
+ }
92
+
93
+ .ds-tabs__list[data-indicator="ready"] .ds-tabs__indicator {
94
+ transition: transform var(--tabs-duration) var(--tabs-ease);
95
+ }
96
+
97
+ .ds-tabs__panel {
98
+ padding-block-start: var(--tabs-panel-padding);
99
+ }
100
+
101
+ .ds-tabs__panel:focus-visible {
102
+ border-radius: var(--tabs-tab-radius);
103
+ outline: var(--tabs-focus-width) solid var(--tabs-focus-color);
104
+ outline-offset: var(--tabs-focus-width);
105
+ }
106
+
107
+ .ds-tabs__panel[hidden] {
108
+ display: none;
109
+ }
110
+
111
+ @media (prefers-reduced-motion: reduce) {
112
+ .ds-tabs__tab:active:not(:disabled) {
113
+ transform: none;
114
+ }
115
+
116
+ .ds-tabs__list[data-indicator="ready"] .ds-tabs__indicator {
117
+ transition: none;
118
+ }
119
+ }
120
+ }
@@ -1,3 +1,5 @@
1
+ @layer reset, tokens, base, components, motion, utilities;
2
+
1
3
  @layer components {
2
4
  .ds-theme-toggle__sun,
3
5
  .ds-theme-toggle__moon {
@@ -1,3 +1,5 @@
1
+ @layer reset, tokens, base, components, motion, utilities;
2
+
1
3
  @layer components {
2
4
  /* A toast is a neutral, raised popover surface. The type lives in the icon;
3
5
  the card itself stays calm so a stack never reads as inline content. */
@@ -94,8 +96,10 @@
94
96
  white-space: nowrap;
95
97
  }
96
98
 
97
- .ds-toast__action:hover {
98
- background: var(--toast-action-bg-hover);
99
+ @media (hover: hover) and (pointer: fine) {
100
+ .ds-toast__action:hover {
101
+ background: var(--toast-action-bg-hover);
102
+ }
99
103
  }
100
104
 
101
105
  .ds-toast__action:focus-visible {
@@ -121,9 +125,11 @@
121
125
  width: var(--space-7);
122
126
  }
123
127
 
124
- .ds-toast__close:hover {
125
- background: var(--toast-close-bg-hover);
126
- color: var(--toast-close-fg-hover);
128
+ @media (hover: hover) and (pointer: fine) {
129
+ .ds-toast__close:hover {
130
+ background: var(--toast-close-bg-hover);
131
+ color: var(--toast-close-fg-hover);
132
+ }
127
133
  }
128
134
 
129
135
  .ds-toast__close:focus-visible {
@@ -147,7 +153,6 @@
147
153
  /* Toast cards share one bottom-end anchor. Collapsed, older cards peek out
148
154
  behind the frontmost one; hover or keyboard focus expands the stack. */
149
155
  .ds-toast-region .ds-toast {
150
- animation: ds-toast-in var(--duration-base) var(--ease-standard);
151
156
  bottom: 0;
152
157
  inset-inline-end: 0;
153
158
  position: absolute;
@@ -157,18 +162,30 @@
157
162
  scale(calc(1 - var(--toast-index, 0) * var(--toast-stack-scale-step)));
158
163
  transform-origin: bottom center;
159
164
  transition:
160
- transform var(--duration-base) var(--ease-spring),
165
+ transform var(--duration-slow) var(--ease-spring),
161
166
  opacity var(--duration-base) var(--ease-standard);
162
167
  z-index: calc(100 - var(--toast-index, 0));
163
168
  }
164
169
 
170
+ @starting-style {
171
+ .ds-toast-region .ds-toast {
172
+ opacity: 0;
173
+ transform: translateY(100%) scale(0.98);
174
+ }
175
+ }
176
+
165
177
  .ds-toast-region:hover .ds-toast,
166
178
  .ds-toast-region:focus-within .ds-toast {
167
179
  transform: translateY(calc(-1 * var(--toast-offset, 0px))) scale(1);
168
180
  }
169
181
 
170
182
  .ds-toast-region .ds-toast[data-toast-leaving] {
171
- animation: ds-toast-out var(--duration-fast) var(--ease-exit) forwards;
183
+ opacity: 0;
184
+ pointer-events: none;
185
+ transform: translateY(100%) scale(0.98);
186
+ transition:
187
+ transform 150ms var(--ease-standard),
188
+ opacity 150ms var(--ease-standard);
172
189
  }
173
190
 
174
191
  .ds-toast-region .ds-toast[data-toast-limited] {
@@ -178,18 +195,6 @@
178
195
  transition: opacity var(--duration-fast) var(--ease-exit);
179
196
  }
180
197
 
181
- @keyframes ds-toast-in {
182
- from {
183
- opacity: 0;
184
- }
185
- }
186
-
187
- @keyframes ds-toast-out {
188
- to {
189
- opacity: 0;
190
- }
191
- }
192
-
193
198
  @keyframes ds-toast-spin {
194
199
  to {
195
200
  transform: rotate(360deg);
@@ -197,11 +202,24 @@
197
202
  }
198
203
 
199
204
  @media (prefers-reduced-motion: reduce) {
200
- .ds-toast-region .ds-toast,
201
- .ds-toast-region .ds-toast[data-toast-leaving],
205
+ .ds-toast-region .ds-toast {
206
+ transition: opacity 120ms var(--ease-standard);
207
+ }
208
+
209
+ @starting-style {
210
+ .ds-toast-region .ds-toast {
211
+ opacity: 0;
212
+ transform: none;
213
+ }
214
+ }
215
+
216
+ .ds-toast-region .ds-toast[data-toast-leaving] {
217
+ transform: none;
218
+ transition: opacity 120ms var(--ease-standard);
219
+ }
220
+
202
221
  .ds-toast--loading .ds-toast__icon {
203
222
  animation: none;
204
- transition: none;
205
223
  }
206
224
  }
207
225
  }
@@ -0,0 +1,63 @@
1
+ @layer reset, tokens, base, components, motion, utilities;
2
+
3
+ /* Positioning and the .ds-anchor wrapper live in popover.css. */
4
+ @layer components {
5
+ .ds-tooltip {
6
+ --ds-anchor-gap: var(--tooltip-gap);
7
+
8
+ background: var(--tooltip-bg);
9
+ border: 0;
10
+ border-radius: var(--tooltip-radius);
11
+ color: var(--tooltip-fg);
12
+ font-size: var(--tooltip-font-size);
13
+ line-height: var(--tooltip-line-height);
14
+ max-width: min(var(--tooltip-max-width), calc(100vw - var(--space-8)));
15
+ opacity: 0;
16
+ overflow: visible;
17
+ padding: var(--tooltip-padding-y) var(--tooltip-padding-x);
18
+ transform: scale(var(--tooltip-scale-from));
19
+ transition:
20
+ opacity var(--tooltip-duration) var(--tooltip-ease-exit),
21
+ transform var(--tooltip-duration) var(--tooltip-ease-exit),
22
+ display var(--tooltip-duration) allow-discrete,
23
+ overlay var(--tooltip-duration) allow-discrete;
24
+ width: max-content;
25
+ }
26
+
27
+ .ds-tooltip:popover-open {
28
+ opacity: 1;
29
+ transform: none;
30
+ transition:
31
+ opacity var(--tooltip-duration) var(--tooltip-ease-enter),
32
+ transform var(--tooltip-duration) var(--tooltip-ease-enter),
33
+ display var(--tooltip-duration) allow-discrete,
34
+ overlay var(--tooltip-duration) allow-discrete;
35
+ }
36
+
37
+ /* Set by script when another tooltip is open or just closed: skip the
38
+ animation so scanning a toolbar feels immediate. */
39
+ .ds-tooltip[data-instant],
40
+ .ds-tooltip[data-instant]:popover-open {
41
+ transition-duration: 0s;
42
+ }
43
+
44
+ @starting-style {
45
+ .ds-tooltip:popover-open {
46
+ opacity: 0;
47
+ transform: scale(var(--tooltip-scale-from));
48
+ }
49
+ }
50
+
51
+ @media (prefers-reduced-motion: reduce) {
52
+ .ds-tooltip,
53
+ .ds-tooltip:popover-open {
54
+ transform: none;
55
+ }
56
+
57
+ @starting-style {
58
+ .ds-tooltip:popover-open {
59
+ transform: none;
60
+ }
61
+ }
62
+ }
63
+ }
@@ -1,3 +1,5 @@
1
+ @layer reset, tokens, base, components, motion, utilities;
2
+
1
3
  @layer components {
2
4
  .ds-topbar {
3
5
  background: var(--topbar-bg);