@dryui/ui 1.6.0 → 1.7.0

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 (41) hide show
  1. package/dist/accordion/accordion-item.svelte +9 -0
  2. package/dist/accordion/accordion-root.svelte +1 -1
  3. package/dist/alert/alert.svelte +1 -0
  4. package/dist/avatar/avatar.svelte +1 -1
  5. package/dist/button/button.svelte +3 -2
  6. package/dist/card/card-root.svelte +1 -0
  7. package/dist/chart/chart-y-axis.svelte +5 -0
  8. package/dist/checkbox/checkbox-input.svelte +30 -31
  9. package/dist/combobox/combobox-content.svelte +1 -0
  10. package/dist/combobox/combobox-item.svelte +9 -0
  11. package/dist/command-palette/command-palette-item.svelte +9 -0
  12. package/dist/command-palette/command-palette-list.svelte +1 -0
  13. package/dist/context-menu/context-menu-content.svelte +1 -0
  14. package/dist/data-grid/data-grid-cell.svelte +5 -0
  15. package/dist/dropdown-menu/dropdown-menu-content.svelte +7 -0
  16. package/dist/image/image.svelte +5 -0
  17. package/dist/internal/menu-item.svelte +10 -1
  18. package/dist/internal/modal-content.svelte +18 -0
  19. package/dist/internal/nav-arrow-button.svelte +21 -5
  20. package/dist/menubar/menubar-content.svelte +1 -0
  21. package/dist/menubar/menubar-item.svelte +10 -1
  22. package/dist/number-input/number-input-button.svelte +1 -0
  23. package/dist/pin-input/pin-input-cell.svelte +1 -0
  24. package/dist/popover/popover-content.svelte +6 -0
  25. package/dist/progress/progress.svelte +1 -0
  26. package/dist/radio-group/radio-group-item-input.svelte +17 -2
  27. package/dist/reveal/reveal.svelte +1 -1
  28. package/dist/select/select-content.svelte +1 -0
  29. package/dist/select/select-item.svelte +9 -0
  30. package/dist/select/select-trigger-button.svelte +18 -1
  31. package/dist/skeleton/skeleton.svelte +2 -0
  32. package/dist/slider/slider-input.svelte +1 -0
  33. package/dist/text/text.svelte +1 -0
  34. package/dist/theme-toggle/theme-toggle.svelte +12 -2
  35. package/dist/themes/dark.css +6 -0
  36. package/dist/themes/default.css +92 -0
  37. package/dist/toast/toast-provider.svelte +1 -0
  38. package/dist/toast/toast-root.svelte +1 -0
  39. package/dist/tooltip/tooltip-content.svelte +5 -0
  40. package/dist/video-embed/video-embed-button.svelte +2 -1
  41. package/package.json +2 -2
@@ -46,6 +46,15 @@
46
46
  display: grid;
47
47
  border-bottom: 1px solid var(--dry-color-stroke-weak);
48
48
 
49
+ transition:
50
+ opacity var(--dry-duration-fast) var(--dry-ease-out),
51
+ transform var(--dry-duration-fast) var(--dry-ease-out);
52
+
53
+ @starting-style {
54
+ opacity: 0;
55
+ transform: translateY(4px);
56
+ }
57
+
49
58
  &:last-child {
50
59
  border-bottom: none;
51
60
  }
@@ -47,7 +47,7 @@
47
47
  });
48
48
  </script>
49
49
 
50
- <div data-accordion data-orientation={orientation} class={className} {...rest}>
50
+ <div data-accordion data-dry-stagger data-orientation={orientation} class={className} {...rest}>
51
51
  {@render children()}
52
52
  </div>
53
53
 
@@ -83,6 +83,7 @@
83
83
  var(--dry-alert-padding, var(--dry-space-6))
84
84
  )
85
85
  );
86
+ --dry-btn-radius: var(--dry-radius-nested);
86
87
 
87
88
  container-type: inline-size;
88
89
  display: grid;
@@ -121,7 +121,7 @@
121
121
  font-size: var(--dry-avatar-font-size);
122
122
  font-weight: 600;
123
123
  line-height: 1;
124
- border: 1px solid var(--dry-color-stroke-weak);
124
+ box-shadow: inset 0 0 0 1px var(--dry-image-edge);
125
125
  overflow: hidden;
126
126
  user-select: none;
127
127
  }
@@ -177,6 +177,7 @@
177
177
  text-decoration: none;
178
178
  white-space: nowrap;
179
179
  user-select: none;
180
+ transform-origin: center;
180
181
  transition:
181
182
  background var(--dry-duration-fast) var(--dry-ease-default),
182
183
  border-color var(--dry-duration-fast) var(--dry-ease-default),
@@ -191,7 +192,7 @@
191
192
  }
192
193
 
193
194
  &:active:not([data-disabled]) {
194
- transform: translateY(1px);
195
+ transform: scale(0.98);
195
196
  }
196
197
 
197
198
  &[data-disabled] {
@@ -499,7 +500,7 @@
499
500
  --_dry-btn-padding-x: var(--dry-btn-padding-x, 0);
500
501
  --_dry-btn-padding-y: var(--dry-btn-padding-y, 0);
501
502
  aspect-ratio: 1;
502
- height: var(--dry-space-8);
503
+ height: var(--dry-space-10);
503
504
  --_dry-btn-radius: var(--dry-btn-radius, var(--dry-radius-sm));
504
505
  --_dry-btn-font-size: var(
505
506
  --dry-btn-font-size,
@@ -69,6 +69,7 @@
69
69
  0px,
70
70
  calc(var(--dry-card-radius) - var(--dry-card-padding, var(--dry-space-8)))
71
71
  );
72
+ --dry-btn-radius: var(--dry-radius-nested);
72
73
 
73
74
  container-type: inline-size;
74
75
  display: grid;
@@ -45,6 +45,7 @@
45
45
  font-size="11"
46
46
  fill="currentColor"
47
47
  opacity="0.6"
48
+ data-chart-tick-label
48
49
  >
49
50
  {Math.round(tick.value)}
50
51
  </text>
@@ -63,4 +64,8 @@
63
64
  [data-chart-axis] {
64
65
  color: var(--dry-chart-axis-color);
65
66
  }
67
+
68
+ [data-chart-tick-label] {
69
+ font-variant-numeric: tabular-nums;
70
+ }
66
71
  </style>
@@ -133,8 +133,21 @@
133
133
 
134
134
  &::after {
135
135
  content: '';
136
- display: none;
137
- transition: transform var(--dry-duration-fast) var(--dry-ease-spring);
136
+ display: block;
137
+ height: 60%;
138
+ aspect-ratio: 35 / 60;
139
+ border: solid transparent;
140
+ border-width: 0 2px 2px 0;
141
+ margin-left: calc(var(--dry-checkbox-size) * 0.52);
142
+ margin-top: calc(var(--dry-checkbox-size) * -0.18);
143
+ transform-origin: center;
144
+ opacity: 0;
145
+ transform: rotate(45deg) scale(0.25);
146
+ filter: blur(4px);
147
+ transition:
148
+ opacity var(--dry-duration-fast) var(--dry-ease-spring-snappy),
149
+ transform var(--dry-duration-fast) var(--dry-ease-spring-snappy),
150
+ filter var(--dry-duration-fast) var(--dry-ease-spring-snappy);
138
151
  }
139
152
 
140
153
  &[data-state='checked'] {
@@ -143,16 +156,10 @@
143
156
  box-shadow: inset 0 0 0 1px var(--dry-color-stroke-selected);
144
157
 
145
158
  &::after {
146
- display: block;
147
- height: 60%;
148
- aspect-ratio: 35 / 60;
149
- border: solid var(--dry-checkbox-check-color);
150
- border-width: 0 2px 2px 0;
151
- margin-left: calc(var(--dry-checkbox-size) * 0.52);
152
- margin-top: calc(var(--dry-checkbox-size) * -0.18);
159
+ border-color: var(--dry-checkbox-check-color);
160
+ opacity: 1;
153
161
  transform: rotate(45deg) scale(1);
154
- transform-origin: center;
155
- animation: checkScale var(--dry-duration-fast) var(--dry-ease-spring);
162
+ filter: blur(0);
156
163
  }
157
164
  }
158
165
 
@@ -163,11 +170,15 @@
163
170
  box-shadow: inset 0 0 0 1px var(--dry-color-stroke-selected);
164
171
 
165
172
  &::after {
166
- display: block;
167
173
  height: 2px;
174
+ aspect-ratio: auto;
175
+ border: none;
168
176
  background: var(--dry-checkbox-check-color);
177
+ margin-left: 0;
178
+ margin-top: 0;
179
+ opacity: 1;
169
180
  transform: scale(1);
170
- animation: dashScale var(--dry-duration-fast) var(--dry-ease-spring);
181
+ filter: blur(0);
171
182
  }
172
183
  }
173
184
 
@@ -226,28 +237,16 @@
226
237
  --dry-checkbox-radius: var(--dry-radius-md);
227
238
  }
228
239
 
229
- @keyframes checkScale {
230
- from {
231
- transform: rotate(45deg) scale(0);
240
+ @media (prefers-reduced-motion: reduce) {
241
+ input::after {
242
+ transition: none;
243
+ filter: none;
232
244
  }
233
- to {
245
+ input[data-state='checked']::after {
234
246
  transform: rotate(45deg) scale(1);
235
247
  }
236
- }
237
-
238
- @keyframes dashScale {
239
- from {
240
- transform: scale(0);
241
- }
242
- to {
243
- transform: scale(1);
244
- }
245
- }
246
-
247
- @media (prefers-reduced-motion: reduce) {
248
- input[data-state='checked']::after,
249
248
  input[data-state='indeterminate']::after {
250
- animation: none;
249
+ transform: scale(1);
251
250
  }
252
251
  }
253
252
  </style>
@@ -64,6 +64,7 @@
64
64
  id={ctx.contentId}
65
65
  aria-labelledby={ctx.inputId}
66
66
  data-combobox-content
67
+ data-dry-stagger
67
68
  data-state={ctx.open ? 'open' : 'closed'}
68
69
  class={className}
69
70
  {...rest}
@@ -97,6 +97,15 @@
97
97
  outline: none;
98
98
  color: var(--dry-color-text-strong);
99
99
  min-height: var(--dry-space-10);
100
+
101
+ transition:
102
+ opacity var(--dry-duration-fast) var(--dry-ease-out),
103
+ transform var(--dry-duration-fast) var(--dry-ease-out);
104
+
105
+ @starting-style {
106
+ opacity: 0;
107
+ transform: translateY(4px);
108
+ }
100
109
  }
101
110
 
102
111
  [data-combobox-item][data-has-icon] {
@@ -71,6 +71,15 @@
71
71
  cursor: pointer;
72
72
  color: var(--dry-color-text-strong);
73
73
  min-height: var(--dry-space-11);
74
+
75
+ transition:
76
+ opacity var(--dry-duration-fast) var(--dry-ease-out),
77
+ transform var(--dry-duration-fast) var(--dry-ease-out);
78
+
79
+ @starting-style {
80
+ opacity: 0;
81
+ transform: translateY(4px);
82
+ }
74
83
  }
75
84
 
76
85
  [data-command-palette-item]:hover:not([data-disabled]) {
@@ -15,6 +15,7 @@
15
15
  <div
16
16
  role="listbox"
17
17
  data-command-palette-list
18
+ data-dry-stagger
18
19
  id={ctx.listId}
19
20
  aria-label="Commands"
20
21
  class={className}
@@ -60,6 +60,7 @@
60
60
  id={ctx.contentId}
61
61
  aria-labelledby={ctx.triggerId}
62
62
  data-context-menu-content
63
+ data-dry-stagger
63
64
  data-state={ctx.open ? 'open' : 'closed'}
64
65
  class={className}
65
66
  {style}
@@ -29,4 +29,9 @@
29
29
  background: inherit;
30
30
  box-shadow: 2px 0 4px -2px rgb(15 23 42 / 0.1);
31
31
  }
32
+
33
+ [data-dg-cell][data-type='number'],
34
+ [data-dg-cell][data-align='end'] {
35
+ font-variant-numeric: tabular-nums;
36
+ }
32
37
  </style>
@@ -58,6 +58,7 @@
58
58
  id={ctx.contentId}
59
59
  aria-labelledby={ctx.triggerId}
60
60
  data-dropdown-menu-content
61
+ data-dry-stagger
61
62
  data-state={ctx.open ? 'open' : 'closed'}
62
63
  class={className}
63
64
  ontoggle={(e) => {
@@ -97,12 +98,18 @@
97
98
  var(--dry-menu-radius, var(--dry-radius-lg)) - var(--dry-menu-padding, var(--dry-space-2))
98
99
  )
99
100
  );
101
+ --dry-btn-radius: var(--dry-radius-nested);
100
102
 
101
103
  transition:
102
104
  opacity var(--dry-duration-fast) var(--dry-ease-emphasized),
103
105
  transform var(--dry-duration-fast) var(--dry-ease-emphasized);
104
106
  }
105
107
 
108
+ [data-dropdown-menu-content][data-state='closed'] {
109
+ transition-duration: calc(var(--dry-duration-fast) / 2);
110
+ transition-timing-function: var(--dry-ease-out);
111
+ }
112
+
106
113
  [data-dropdown-menu-content]:not(:popover-open) {
107
114
  display: none;
108
115
  }
@@ -67,6 +67,11 @@
67
67
  object-fit: var(--dry-image-object-fit);
68
68
  }
69
69
 
70
+ img[data-state='loaded'],
71
+ img[data-state='fallback'] {
72
+ box-shadow: inset 0 0 0 1px var(--dry-image-edge);
73
+ }
74
+
70
75
  img[data-state='fallback'] {
71
76
  opacity: 0.95;
72
77
  }
@@ -62,7 +62,16 @@
62
62
  outline: none;
63
63
  color: var(--dry-color-text-strong);
64
64
  min-height: var(--dry-space-11);
65
- transition: background var(--dry-duration-fast) var(--dry-ease-default);
65
+
66
+ transition:
67
+ background var(--dry-duration-fast) var(--dry-ease-default),
68
+ opacity var(--dry-duration-fast) var(--dry-ease-out),
69
+ transform var(--dry-duration-fast) var(--dry-ease-out);
70
+
71
+ @starting-style {
72
+ opacity: 0;
73
+ transform: translateY(4px);
74
+ }
66
75
  }
67
76
 
68
77
  div:hover:not([data-disabled]),
@@ -132,6 +132,7 @@
132
132
  var(--dry-dialog-padding)
133
133
  )
134
134
  );
135
+ --dry-btn-radius: var(--dry-radius-nested);
135
136
 
136
137
  container-type: inline-size;
137
138
  justify-self: stretch;
@@ -150,6 +151,11 @@
150
151
  transform var(--dry-duration-normal) var(--dry-ease-spring-snappy);
151
152
  }
152
153
 
154
+ [data-modal-content][data-variant='dialog'][data-state='closed'] [data-modal-panel] {
155
+ transition-duration: var(--dry-duration-fast);
156
+ transition-timing-function: var(--dry-ease-out);
157
+ }
158
+
153
159
  [data-modal-content][data-variant='dialog'][data-state='open'] [data-modal-panel] {
154
160
  opacity: 1;
155
161
  transform: scale(1) translateY(0);
@@ -189,6 +195,8 @@
189
195
  --dry-dialog-shadow: var(--dry-shadow-overlay);
190
196
  --dry-dialog-padding: var(--dry-space-6);
191
197
  --dry-dialog-max-width: 32rem;
198
+ --dry-radius-nested: max(0px, calc(var(--dry-dialog-radius) - var(--dry-dialog-padding)));
199
+ --dry-btn-radius: var(--dry-radius-nested);
192
200
 
193
201
  container-type: inline-size;
194
202
  justify-self: stretch;
@@ -208,6 +216,11 @@
208
216
  transform var(--dry-duration-normal) var(--dry-ease-spring-snappy);
209
217
  }
210
218
 
219
+ [data-modal-content][data-variant='alert-dialog'][data-state='closed'] [data-modal-panel] {
220
+ transition-duration: var(--dry-duration-fast);
221
+ transition-timing-function: var(--dry-ease-out);
222
+ }
223
+
211
224
  [data-modal-content][data-variant='alert-dialog'][data-state='open'] [data-modal-panel] {
212
225
  opacity: 1;
213
226
  transform: scale(1) translateY(0);
@@ -282,6 +295,11 @@
282
295
  opacity var(--dry-duration-normal) var(--dry-ease-out);
283
296
  }
284
297
 
298
+ [data-modal-content][data-variant='drawer'][data-state='closed'] [data-modal-panel] {
299
+ transition-duration: var(--dry-duration-fast);
300
+ transition-timing-function: var(--dry-ease-out);
301
+ }
302
+
285
303
  [data-modal-content][data-variant='drawer'][data-side='right'] [data-modal-panel] {
286
304
  grid-column: 2;
287
305
  height: 100%;
@@ -18,9 +18,25 @@
18
18
  </script>
19
19
 
20
20
  <Button {variant} {size} type="button" aria-label={label} {...rest}>
21
- {#if children}
22
- {@render children()}
23
- {:else}
24
- {glyph}
25
- {/if}
21
+ <span data-part="nav-arrow-icon" data-direction={direction}>
22
+ {#if children}
23
+ {@render children()}
24
+ {:else}
25
+ {glyph}
26
+ {/if}
27
+ </span>
26
28
  </Button>
29
+
30
+ <style>
31
+ [data-part='nav-arrow-icon'] {
32
+ display: inline-flex;
33
+ align-items: center;
34
+ justify-content: center;
35
+ }
36
+ [data-part='nav-arrow-icon'][data-direction='prev'] {
37
+ transform: translateX(-0.5px);
38
+ }
39
+ [data-part='nav-arrow-icon'][data-direction='next'] {
40
+ transform: translateX(0.5px);
41
+ }
42
+ </style>
@@ -99,6 +99,7 @@
99
99
  tabindex="-1"
100
100
  aria-labelledby={triggerEl?.id}
101
101
  data-menubar-content
102
+ data-dry-stagger
102
103
  data-state={menuCtx.open ? 'open' : 'closed'}
103
104
  class={className}
104
105
  ontoggle={(e) => {
@@ -69,7 +69,16 @@
69
69
  outline: none;
70
70
  color: var(--dry-color-text-strong);
71
71
  min-height: var(--dry-space-11);
72
- transition: background var(--dry-duration-fast) var(--dry-ease-default);
72
+
73
+ transition:
74
+ background var(--dry-duration-fast) var(--dry-ease-default),
75
+ opacity var(--dry-duration-fast) var(--dry-ease-out),
76
+ transform var(--dry-duration-fast) var(--dry-ease-out);
77
+
78
+ @starting-style {
79
+ opacity: 0;
80
+ transform: translateY(4px);
81
+ }
73
82
  }
74
83
 
75
84
  [data-menubar-item]:hover:not([data-disabled]),
@@ -82,6 +82,7 @@
82
82
  font-size: var(--dry-input-font-size);
83
83
  line-height: var(--dry-type-small-leading);
84
84
  font-family: var(--dry-font-sans);
85
+ font-variant-numeric: tabular-nums;
85
86
  color: var(--dry-input-color);
86
87
  background: var(--dry-input-bg);
87
88
  border: 1px solid var(--dry-input-border);
@@ -53,6 +53,7 @@
53
53
  height: var(--dry-pin-size);
54
54
  font-size: var(--dry-pin-font-size);
55
55
  font-family: var(--dry-font-mono);
56
+ font-variant-numeric: tabular-nums;
56
57
  font-weight: 500;
57
58
  color: var(--dry-color-text-strong);
58
59
  background: var(--dry-pin-bg);
@@ -61,6 +61,7 @@
61
61
  --dry-popover-shadow: var(--dry-overlay-shadow, var(--dry-shadow-lg));
62
62
  --dry-popover-padding: var(--dry-space-4);
63
63
  --dry-radius-nested: max(0px, calc(var(--dry-popover-radius) - var(--dry-popover-padding)));
64
+ --dry-btn-radius: var(--dry-radius-nested);
64
65
 
65
66
  inset: unset;
66
67
  margin: 0;
@@ -79,6 +80,11 @@
79
80
  transform var(--dry-duration-fast) var(--dry-ease-emphasized);
80
81
  }
81
82
 
83
+ [data-popover-content][data-state='closed'] {
84
+ transition-duration: calc(var(--dry-duration-fast) / 2);
85
+ transition-timing-function: var(--dry-ease-out);
86
+ }
87
+
82
88
  [data-popover-content]:not(:popover-open) {
83
89
  display: none;
84
90
  }
@@ -275,6 +275,7 @@
275
275
  font-size: var(--dry-type-ui-caption-size, var(--dry-text-xs-size, 0.75rem));
276
276
  color: var(--dry-color-text-weak, #64748b);
277
277
  white-space: nowrap;
278
+ font-variant-numeric: tabular-nums;
278
279
  }
279
280
 
280
281
  [data-part='label'][data-position='inside'] {
@@ -91,12 +91,18 @@
91
91
  position: absolute;
92
92
  top: 50%;
93
93
  left: 50%;
94
- transform: translate(-50%, -50%) scale(0);
94
+ transform: translate(-50%, -50%) scale(0.25);
95
+ opacity: 0;
96
+ filter: blur(4px);
95
97
  height: 8px;
96
98
  aspect-ratio: 1;
97
99
  border-radius: var(--dry-radius-full);
98
100
  background: var(--dry-color-on-brand);
99
- transition: transform var(--dry-duration-fast) var(--dry-ease-default);
101
+ transform-origin: center;
102
+ transition:
103
+ opacity var(--dry-duration-fast) var(--dry-ease-spring-snappy),
104
+ transform var(--dry-duration-fast) var(--dry-ease-spring-snappy),
105
+ filter var(--dry-duration-fast) var(--dry-ease-spring-snappy);
100
106
  }
101
107
 
102
108
  [data-radio-group-item] input[type='radio']:hover:not(:disabled) {
@@ -120,6 +126,15 @@
120
126
 
121
127
  [data-radio-group-item] input[type='radio']:checked::after {
122
128
  transform: translate(-50%, -50%) scale(1);
129
+ opacity: 1;
130
+ filter: blur(0);
131
+ }
132
+
133
+ @media (prefers-reduced-motion: reduce) {
134
+ [data-radio-group-item] input[type='radio']::after {
135
+ transition: none;
136
+ filter: none;
137
+ }
123
138
  }
124
139
 
125
140
  [data-radio-group-item] input[type='radio']:checked:hover:not(:disabled) {
@@ -128,7 +128,7 @@
128
128
  <style>
129
129
  [data-reveal] {
130
130
  --dry-reveal-distance: var(--dry-motion-distance-sm, 0.75rem);
131
- --dry-reveal-delay: 0ms;
131
+ --dry-reveal-delay: var(--dry-stagger-delay, 0ms);
132
132
  --dry-reveal-duration: var(--dry-duration-entrance, 480ms);
133
133
  --dry-reveal-ease: cubic-bezier(0.16, 1, 0.3, 1);
134
134
  --dry-reveal-hidden-opacity: var(--dry-motion-opacity-enter, 0);
@@ -123,6 +123,7 @@
123
123
  id={ctx.contentId}
124
124
  aria-labelledby={ctx.triggerId}
125
125
  data-select-content
126
+ data-dry-stagger
126
127
  data-state={ctx.open ? 'open' : 'closed'}
127
128
  class={className}
128
129
  ontoggle={(e) => {
@@ -81,6 +81,15 @@
81
81
  outline: none;
82
82
  color: var(--dry-color-text-strong);
83
83
  min-height: var(--dry-space-10);
84
+
85
+ transition:
86
+ opacity var(--dry-duration-fast) var(--dry-ease-out),
87
+ transform var(--dry-duration-fast) var(--dry-ease-out);
88
+
89
+ @starting-style {
90
+ opacity: 0;
91
+ transform: translateY(4px);
92
+ }
84
93
  }
85
94
 
86
95
  [data-select-item]:hover:not([data-disabled]),
@@ -33,6 +33,7 @@
33
33
  {@render children()}
34
34
  <svg
35
35
  data-indicator
36
+ data-state={ctx.open ? 'open' : 'closed'}
36
37
  xmlns="http://www.w3.org/2000/svg"
37
38
  viewBox="0 0 24 24"
38
39
  fill="none"
@@ -55,6 +56,22 @@
55
56
  aspect-ratio: 1;
56
57
  place-self: center;
57
58
  opacity: 0.5;
58
- transition: transform var(--dry-duration-fast) var(--dry-ease-default);
59
+ transform-origin: center;
60
+ transition:
61
+ opacity var(--dry-duration-fast) var(--dry-ease-spring-snappy),
62
+ transform var(--dry-duration-fast) var(--dry-ease-spring-snappy),
63
+ filter var(--dry-duration-fast) var(--dry-ease-spring-snappy);
64
+ }
65
+
66
+ svg[data-indicator][data-state='open'] {
67
+ opacity: 1;
68
+ transform: scale(1.05);
69
+ }
70
+
71
+ @media (prefers-reduced-motion: reduce) {
72
+ svg[data-indicator] {
73
+ transition: none;
74
+ filter: none;
75
+ }
59
76
  }
60
77
  </style>
@@ -91,10 +91,12 @@
91
91
  --dry-skeleton-radius: var(--dry-radius-full);
92
92
  aspect-ratio: 1;
93
93
  height: var(--_h, var(--dry-space-10));
94
+ box-shadow: inset 0 0 0 1px var(--dry-image-edge);
94
95
  }
95
96
 
96
97
  div[data-variant='rectangular'] {
97
98
  --dry-skeleton-radius: var(--dry-radius-sm);
98
99
  height: var(--_h, var(--dry-space-16));
100
+ box-shadow: inset 0 0 0 1px var(--dry-image-edge);
99
101
  }
100
102
  </style>
@@ -249,6 +249,7 @@
249
249
  padding-inline: var(--dry-space-4);
250
250
  font-size: var(--dry-text-sm-size, 0.875rem);
251
251
  font-weight: 600;
252
+ font-variant-numeric: tabular-nums;
252
253
  color: var(--dry-color-text);
253
254
  clip-path: inset(
254
255
  0 calc(100% - var(--dry-slider-progress, 50%)) 0 0 round var(--dry-radius-full)
@@ -60,6 +60,7 @@
60
60
  color: var(--dry-typography-text-color, var(--dry-color-text-strong));
61
61
  font-family: var(--dry-font-sans);
62
62
  line-height: 1.7;
63
+ text-wrap: pretty;
63
64
  }
64
65
 
65
66
  [data-color='muted'] {
@@ -113,7 +113,12 @@
113
113
  >
114
114
  {#snippet icon()}
115
115
  <span class="icons" data-mode={iconState}>
116
- <span class="icon sun" aria-hidden="true">
116
+ <span
117
+ class="icon sun"
118
+ data-dry-icon-reveal
119
+ data-hidden={iconState === 'dark' || undefined}
120
+ aria-hidden="true"
121
+ >
117
122
  {#if sunIcon}
118
123
  {@render sunIcon()}
119
124
  {:else}
@@ -138,7 +143,12 @@
138
143
  </svg>
139
144
  {/if}
140
145
  </span>
141
- <span class="icon moon" aria-hidden="true">
146
+ <span
147
+ class="icon moon"
148
+ data-dry-icon-reveal
149
+ data-hidden={iconState === 'light' || undefined}
150
+ aria-hidden="true"
151
+ >
142
152
  {#if moonIcon}
143
153
  {@render moonIcon()}
144
154
  {:else}
@@ -65,6 +65,9 @@
65
65
  --dry-color-bg-brand: var(--dry-color-fill-brand);
66
66
  --dry-color-bg-inverse: #ffffff;
67
67
 
68
+ /* ─── Image edge ring (dark) ─────────────────────────────────── */
69
+ --dry-image-edge: rgba(255, 255, 255, 0.1);
70
+
68
71
  /* ─── Component: Toggle ─────────────────────────────────────────
69
72
  Derived from semantic tokens so brand overrides (e.g. a consumer
70
73
  retheming --dry-color-fill-brand) flow through to toggles too.
@@ -283,6 +286,9 @@
283
286
  --dry-color-bg-brand: var(--dry-color-fill-brand);
284
287
  --dry-color-bg-inverse: #ffffff;
285
288
 
289
+ /* ─── Image edge ring (dark) ─────────────────────────────────── */
290
+ --dry-image-edge: rgba(255, 255, 255, 0.1);
291
+
286
292
  /* ─── Component: Toggle ─────────────────────────────────────────
287
293
  Derived from semantic tokens so brand overrides (e.g. a consumer
288
294
  retheming --dry-color-fill-brand) flow through to toggles too.
@@ -91,6 +91,12 @@ samp {
91
91
  --dry-color-bg-brand: var(--dry-color-fill-brand);
92
92
  --dry-color-bg-inverse: hsl(233, 18%, 9%);
93
93
 
94
+ /* ─── Image edge ring ────────────────────────────────────────────
95
+ Subtle 1px outline for image surfaces (avatars, images, image
96
+ skeletons). Prevents image edges from reading as surface
97
+ imperfections. Hardcoded rgba — not brand-derivable. */
98
+ --dry-image-edge: rgba(0, 0, 0, 0.1);
99
+
94
100
  /* ─── Component: Toggle ─────────────────────────────────────────
95
101
  Derived from semantic tokens so brand overrides (e.g. a consumer
96
102
  retheming --dry-color-fill-brand) flow through to toggles too.
@@ -365,6 +371,10 @@ samp {
365
371
  --dry-motion-blur-enter: 16px;
366
372
  --dry-motion-scale-enter: 0.96;
367
373
 
374
+ /* ─── Stagger ─────────────────────────────────────────────────── */
375
+ --dry-stagger-step: 60ms;
376
+ --dry-stagger-max: 8; /* cap delay so very long lists don't take forever */
377
+
368
378
  /* ─── Glass surface ───────────────────────────────────────────── */
369
379
  --dry-glass-blur: 12px;
370
380
  --dry-glass-tint: var(--dry-color-bg-raised);
@@ -501,3 +511,85 @@ samp {
501
511
  --dry-motion-scale-enter: 1;
502
512
  }
503
513
  }
514
+
515
+ /* Stagger — per-child transition-delay driven by `--dry-index`. The first
516
+ 12 children get `--dry-index` automatically via `:nth-child()`; for longer
517
+ lists set `--dry-index` on each child. The child must declare a
518
+ `transition` on its enter properties for the delay to have effect. */
519
+ [data-dry-stagger] > * {
520
+ --dry-stagger-delay: calc(
521
+ min(var(--dry-index, 0), var(--dry-stagger-max)) * var(--dry-stagger-step)
522
+ );
523
+ transition-delay: var(--dry-stagger-delay);
524
+ animation-delay: var(--dry-stagger-delay);
525
+ }
526
+
527
+ [data-dry-stagger] > *:nth-child(1) {
528
+ --dry-index: 0;
529
+ }
530
+ [data-dry-stagger] > *:nth-child(2) {
531
+ --dry-index: 1;
532
+ }
533
+ [data-dry-stagger] > *:nth-child(3) {
534
+ --dry-index: 2;
535
+ }
536
+ [data-dry-stagger] > *:nth-child(4) {
537
+ --dry-index: 3;
538
+ }
539
+ [data-dry-stagger] > *:nth-child(5) {
540
+ --dry-index: 4;
541
+ }
542
+ [data-dry-stagger] > *:nth-child(6) {
543
+ --dry-index: 5;
544
+ }
545
+ [data-dry-stagger] > *:nth-child(7) {
546
+ --dry-index: 6;
547
+ }
548
+ [data-dry-stagger] > *:nth-child(8) {
549
+ --dry-index: 7;
550
+ }
551
+ [data-dry-stagger] > *:nth-child(9) {
552
+ --dry-index: 8;
553
+ }
554
+ [data-dry-stagger] > *:nth-child(10) {
555
+ --dry-index: 9;
556
+ }
557
+ [data-dry-stagger] > *:nth-child(11) {
558
+ --dry-index: 10;
559
+ }
560
+ [data-dry-stagger] > *:nth-child(12) {
561
+ --dry-index: 11;
562
+ }
563
+
564
+ @media (prefers-reduced-motion: reduce) {
565
+ [data-dry-stagger] > * {
566
+ transition: none;
567
+ animation: none;
568
+ }
569
+ }
570
+
571
+ .dry-tabular-nums {
572
+ font-variant-numeric: tabular-nums;
573
+ }
574
+
575
+ [data-dry-icon-reveal] {
576
+ transition:
577
+ opacity var(--dry-duration-fast) var(--dry-ease-spring-snappy),
578
+ transform var(--dry-duration-fast) var(--dry-ease-spring-snappy),
579
+ filter var(--dry-duration-fast) var(--dry-ease-spring-snappy);
580
+ transform-origin: center;
581
+ }
582
+ [data-dry-icon-reveal][data-state='hidden'],
583
+ [data-dry-icon-reveal][data-hidden],
584
+ [data-dry-icon-reveal][hidden] {
585
+ opacity: 0;
586
+ transform: scale(0.25);
587
+ filter: blur(4px);
588
+ }
589
+ @media (prefers-reduced-motion: reduce) {
590
+ [data-dry-icon-reveal] {
591
+ transition: none;
592
+ filter: none;
593
+ transform: none;
594
+ }
595
+ }
@@ -47,6 +47,7 @@
47
47
  role="region"
48
48
  aria-label="Notifications"
49
49
  data-part="provider"
50
+ data-dry-stagger
50
51
  data-position={position}
51
52
  class={className}
52
53
  {...rest}
@@ -60,6 +60,7 @@
60
60
  [data-part='root'] {
61
61
  --dry-toast-accent: var(--dry-color-fill-info);
62
62
  --dry-radius-nested: max(0px, calc(var(--dry-radius-lg) - var(--dry-space-4)));
63
+ --dry-btn-radius: var(--dry-radius-nested);
63
64
 
64
65
  position: relative;
65
66
  background: var(--dry-toast-bg, var(--dry-color-bg-overlay));
@@ -70,6 +70,11 @@
70
70
  transform var(--dry-duration-fast) var(--dry-ease-emphasized);
71
71
  }
72
72
 
73
+ [data-tooltip-content][data-state='closed'] {
74
+ transition-duration: calc(var(--dry-duration-fast) / 2);
75
+ transition-timing-function: var(--dry-ease-out);
76
+ }
77
+
73
78
  [data-tooltip-content]:not(:popover-open) {
74
79
  display: none;
75
80
  }
@@ -166,10 +166,11 @@
166
166
  height: var(--dry-video-embed-play-size);
167
167
  aspect-ratio: 1;
168
168
  filter: drop-shadow(0 2px 8px rgb(15 23 42 / 0.3));
169
+ transform: translateX(1px);
169
170
  transition: transform var(--dry-duration-normal) var(--dry-ease-default);
170
171
  }
171
172
 
172
173
  .play-btn-slot:hover [data-part='play-icon'] {
173
- transform: scale(1.1);
174
+ transform: translateX(1px) scale(1.1);
174
175
  }
175
176
  </style>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dryui/ui",
3
- "version": "1.6.0",
3
+ "version": "1.7.0",
4
4
  "description": "Zero-dependency styled Svelte 5 components with scoped styles and --dry-* CSS variable theming.",
5
5
  "author": "Rob Balfre",
6
6
  "license": "MIT",
@@ -784,7 +784,7 @@
784
784
  "postpack": "bun ../../scripts/postpack-exports.ts"
785
785
  },
786
786
  "dependencies": {
787
- "@dryui/primitives": "^1.6.0"
787
+ "@dryui/primitives": "^1.7.0"
788
788
  },
789
789
  "peerDependencies": {
790
790
  "svelte": "^5.55.1"