@juspay/svelte-ui-components 4.27.6 → 4.28.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 (164) hide show
  1. package/README.md +140 -36
  2. package/dist/Animations/ModalAnimation.svelte +15 -1
  3. package/dist/Animations/OverlayAnimation.svelte +7 -1
  4. package/dist/AreaChart/AreaChart.svelte +366 -85
  5. package/dist/AspectRatio/AspectRatio.svelte +51 -0
  6. package/dist/AspectRatio/AspectRatio.svelte.d.ts +3 -0
  7. package/dist/AspectRatio/properties.d.ts +27 -0
  8. package/dist/AspectRatio/properties.js +1 -0
  9. package/dist/Banner/Banner.svelte +10 -4
  10. package/dist/Banner/properties.d.ts +8 -0
  11. package/dist/BarChart/BarChart.svelte +156 -49
  12. package/dist/Book/Book.svelte +14 -1
  13. package/dist/BrandLoader/BrandLoader.svelte +76 -12
  14. package/dist/Button/Button.svelte +56 -11
  15. package/dist/Calendar/Calendar.svelte +88 -61
  16. package/dist/Card/Card.svelte +1 -1
  17. package/dist/Carousel/Carousel.svelte +6 -3
  18. package/dist/ChatComposer/ChatComposer.svelte +54 -4
  19. package/dist/ChatComposer/dictationState.d.ts +15 -0
  20. package/dist/ChatComposer/dictationState.js +9 -0
  21. package/dist/ChatComposer/properties.d.ts +28 -1
  22. package/dist/ChatMessage/ChatMessage.svelte +27 -1
  23. package/dist/CheckListItem/CheckListItem.svelte +3 -3
  24. package/dist/Checkbox/Checkbox.svelte +84 -3
  25. package/dist/Checkbox/properties.d.ts +45 -13
  26. package/dist/ChipInput/ChipInput.svelte +70 -3
  27. package/dist/ChipInput/properties.d.ts +16 -0
  28. package/dist/Choicebox/Choicebox.svelte +156 -1
  29. package/dist/Choicebox/group.d.ts +63 -0
  30. package/dist/Choicebox/group.js +127 -0
  31. package/dist/Choicebox/properties.d.ts +46 -0
  32. package/dist/ColorPicker/ColorPicker.svelte +169 -20
  33. package/dist/ColorPicker/properties.d.ts +16 -0
  34. package/dist/Combobox/Combobox.svelte +87 -25
  35. package/dist/Combobox/properties.d.ts +23 -0
  36. package/dist/CommandMenu/CommandMenu.svelte +27 -11
  37. package/dist/ContextMenu/ContextMenu.svelte +31 -37
  38. package/dist/DateRangePicker/DateRangePicker.svelte +171 -73
  39. package/dist/DeltaIndicator/DeltaIndicator.svelte +3 -3
  40. package/dist/Draggable/Draggable.svelte +12 -7
  41. package/dist/DualAxisBarChart/DualAxisBarChart.svelte +11 -4
  42. package/dist/EmptyState/EmptyState.svelte +1 -1
  43. package/dist/FileDropzoneTrigger/FileDropzoneTrigger.svelte +1 -1
  44. package/dist/FileInput/FileInput.svelte +50 -1
  45. package/dist/FileInput/properties.d.ts +7 -0
  46. package/dist/FunnelChart/FunnelChart.svelte +40 -12
  47. package/dist/FunnelChart/properties.d.ts +7 -1
  48. package/dist/Gallery/Gallery.svelte +20 -13
  49. package/dist/Gallery/properties.d.ts +8 -0
  50. package/dist/GridItem/GridItem.svelte +31 -1
  51. package/dist/HITL/HITL.svelte +35 -9
  52. package/dist/Icon/Icon.svelte +19 -3
  53. package/dist/Input/Input.svelte +24 -10
  54. package/dist/Input/properties.d.ts +37 -1
  55. package/dist/InputButton/InputButton.svelte +86 -11
  56. package/dist/InputButton/properties.d.ts +10 -1
  57. package/dist/Label/Label.svelte +54 -0
  58. package/dist/Label/Label.svelte.d.ts +3 -0
  59. package/dist/Label/properties.d.ts +26 -0
  60. package/dist/Label/properties.js +1 -0
  61. package/dist/LineChart/LineChart.svelte +385 -94
  62. package/dist/ListItem/ListItem.svelte +121 -15
  63. package/dist/Loader/Loader.svelte +22 -2
  64. package/dist/LoadingDots/LoadingDots.svelte +21 -0
  65. package/dist/MediaUpload/MediaUpload.svelte +13 -3
  66. package/dist/Menu/Menu.svelte +56 -28
  67. package/dist/Modal/Modal.svelte +77 -42
  68. package/dist/Pagination/Pagination.svelte +9 -2
  69. package/dist/Phone/Phone.svelte +4 -0
  70. package/dist/PieChart/PieChart.svelte +282 -38
  71. package/dist/PieChart/properties.d.ts +9 -0
  72. package/dist/Pill/Pill.svelte +14 -5
  73. package/dist/Progress/Progress.svelte +20 -0
  74. package/dist/Radio/Radio.svelte +58 -1
  75. package/dist/Radio/properties.d.ts +23 -0
  76. package/dist/RatingGroup/RatingGroup.svelte +283 -0
  77. package/dist/RatingGroup/RatingGroup.svelte.d.ts +4 -0
  78. package/dist/RatingGroup/properties.d.ts +73 -0
  79. package/dist/RatingGroup/properties.js +1 -0
  80. package/dist/RelativeTime/RelativeTime.svelte +1 -1
  81. package/dist/SankeyChart/SankeyChart.svelte +272 -50
  82. package/dist/SankeyChart/properties.d.ts +9 -0
  83. package/dist/Scroller/Scroller.svelte +37 -2
  84. package/dist/Select/Select.svelte +166 -46
  85. package/dist/Select/properties.d.ts +7 -0
  86. package/dist/Separator/Separator.svelte +48 -0
  87. package/dist/Separator/Separator.svelte.d.ts +3 -0
  88. package/dist/Separator/properties.d.ts +22 -0
  89. package/dist/Separator/properties.js +1 -0
  90. package/dist/Sheet/Sheet.svelte +60 -21
  91. package/dist/Shimmer/Shimmer.svelte +15 -0
  92. package/dist/Slider/Slider.svelte +87 -6
  93. package/dist/Slider/properties.d.ts +26 -0
  94. package/dist/Snippet/Snippet.svelte +4 -0
  95. package/dist/Snippet/copyState.svelte.d.ts +13 -1
  96. package/dist/Snippet/copyState.svelte.js +27 -1
  97. package/dist/Snippet/properties.d.ts +7 -0
  98. package/dist/SoundKit/SoundKit.js +9 -8
  99. package/dist/SplitInput/SplitInput.svelte +68 -2
  100. package/dist/SplitInput/properties.d.ts +23 -0
  101. package/dist/StatCard/StatCard.svelte +6 -6
  102. package/dist/Status/Status.svelte +2 -2
  103. package/dist/Stepper/Step.svelte +19 -6
  104. package/dist/Stepper/Stepper.svelte +108 -35
  105. package/dist/Table/BuiltinCell.svelte +2 -2
  106. package/dist/Table/Table.svelte +373 -55
  107. package/dist/Table/properties.d.ts +134 -3
  108. package/dist/Tabs/Tabs.svelte +263 -65
  109. package/dist/Tabs/properties.d.ts +23 -0
  110. package/dist/TaskList/TaskList.svelte +14 -5
  111. package/dist/ThemeSwitcher/ThemeSwitcher.svelte +23 -0
  112. package/dist/ThinkingIndicator/ThinkingIndicator.svelte +13 -5
  113. package/dist/Toast/Toast.svelte +27 -2
  114. package/dist/Toggle/Toggle.svelte +79 -7
  115. package/dist/Toggle/Toggle.svelte.d.ts +1 -1
  116. package/dist/Toggle/properties.d.ts +30 -7
  117. package/dist/ToolCallLog/ToolCallLog.svelte +59 -21
  118. package/dist/ToolCallLog/properties.d.ts +10 -0
  119. package/dist/Toolbar/Toolbar.svelte +1 -1
  120. package/dist/Tooltip/Tooltip.svelte +20 -2
  121. package/dist/Tooltip/tooltip-action.js +39 -4
  122. package/dist/TypewriterText/TypewriterText.svelte +34 -2
  123. package/dist/TypewriterText/properties.d.ts +18 -5
  124. package/dist/_chart/ChartContainer.svelte +12 -0
  125. package/dist/_chart/ChartTooltip.svelte +18 -4
  126. package/dist/_chart/Legend.svelte +21 -0
  127. package/dist/_chart/Legend.svelte.d.ts +15 -0
  128. package/dist/_chart/geometry.d.ts +54 -1
  129. package/dist/_chart/geometry.js +122 -14
  130. package/dist/_chart/interactions.d.ts +5 -1
  131. package/dist/_chart/interactions.js +9 -5
  132. package/dist/_chart/scales.js +16 -0
  133. package/dist/_chart/temporal.d.ts +45 -0
  134. package/dist/_chart/temporal.js +116 -0
  135. package/dist/_field/description.d.ts +50 -0
  136. package/dist/_field/description.js +51 -0
  137. package/dist/_interaction/dismissal.d.ts +67 -0
  138. package/dist/_interaction/dismissal.js +137 -0
  139. package/dist/_interaction/focus.d.ts +73 -0
  140. package/dist/_interaction/focus.js +143 -0
  141. package/dist/assets/star.svg +5 -0
  142. package/dist/index.d.ts +13 -1
  143. package/dist/index.js +21 -1
  144. package/dist/reduced-motion.svelte.d.ts +37 -0
  145. package/dist/reduced-motion.svelte.js +44 -0
  146. package/dist/styles/theme-dark.css +778 -0
  147. package/dist/types.d.ts +4 -2
  148. package/dist/utils.d.ts +62 -1
  149. package/dist/utils.js +80 -21
  150. package/dist-codemod/{bin.js → codemod/bin.js} +13 -2
  151. package/dist-codemod/{cli.js → codemod/cli.js} +48 -3
  152. package/dist-codemod/codemod/migrate-audit.js +395 -0
  153. package/dist-codemod/codemod/migration-assets/legacy-display.css +120 -0
  154. package/dist-codemod/codemod/migration-assets/legacy-palette.css +106 -0
  155. package/dist-codemod/codemod/migration-assets/wc-display.json +492 -0
  156. package/dist-codemod/migrate/analyze.js +804 -0
  157. package/dist-codemod/migrate/chart-tooltip-selector.js +301 -0
  158. package/dist-wc/index.js +13992 -4323
  159. package/package.json +13 -6
  160. package/dist/Modal/focus-trap.d.ts +0 -42
  161. package/dist/Modal/focus-trap.js +0 -57
  162. /package/dist-codemod/{legacy-pairs.js → codemod/legacy-pairs.js} +0 -0
  163. /package/dist-codemod/{transform.js → codemod/transform.js} +0 -0
  164. /package/dist-codemod/{wc-children.js → codemod/wc-children.js} +0 -0
package/README.md CHANGED
@@ -122,33 +122,36 @@ fix to something that did not work.
122
122
 
123
123
  ### Inputs & Form Controls
124
124
 
125
- | Component | Description | Docs |
126
- | --------------- | ---------------------------------------------------------------------------------------------------------------------------------- | --------------------------- |
127
- | **Button** | Action trigger with circular loader, progress bar, icon/children snippets, and aria-expanded support. | [docs](docs/Button.md) |
128
- | **Input** | Text field with built-in validation for email, phone, password, and custom patterns. Supports text transformers and textarea mode. | [docs](docs/Input.md) |
129
- | **InputButton** | Input field fused with action buttons — for search bars, OTP entry, coupon codes. | [docs](docs/InputButton.md) |
130
- | **Select** | Dropdown picker with single-select (with search), multi-select (checkboxes + Select All + Apply), and custom content slots. | [docs](docs/Select.md) |
131
- | **Toggle** | Labeled on/off switch with sliding ball animation. | [docs](docs/Toggle.md) |
132
- | **Checkbox** | Styled checkbox input with custom SVG checkmark. | [docs](docs/Checkbox.md) |
133
- | **Radio** | Styled radio button with custom circular indicator. | [docs](docs/Radio.md) |
134
- | **Slider** | Range slider with configurable min, max, step, and optional value display. | [docs](docs/Slider.md) |
135
- | **Choicebox** | Selectable option group with single-select (radio) or multi-select (checkbox) behavior and custom content. | [docs](docs/Choicebox.md) |
125
+ | Component | Description | Docs |
126
+ | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------- |
127
+ | **Button** | Action trigger with circular loader, progress bar, icon/children snippets, and aria-expanded support. | [docs](docs/Button.md) |
128
+ | **Input** | Text field with built-in validation for email, phone, password, and custom patterns. Supports text transformers and textarea mode. | [docs](docs/Input.md) |
129
+ | **InputButton** | Input field fused with action buttons — for search bars, OTP entry, coupon codes. | [docs](docs/InputButton.md) |
130
+ | **Select** | Dropdown picker with single-select (with search), multi-select (checkboxes + Select All + Apply), and custom content slots. | [docs](docs/Select.md) |
131
+ | **Toggle** | Labeled on/off switch with sliding ball animation. | [docs](docs/Toggle.md) |
132
+ | **Checkbox** | Styled checkbox input with custom SVG checkmark. | [docs](docs/Checkbox.md) |
133
+ | **Radio** | Styled radio button with custom circular indicator. | [docs](docs/Radio.md) |
134
+ | **Slider** | Range slider with configurable min, max, step, and optional value display. | [docs](docs/Slider.md) |
135
+ | **Choicebox** | Selectable option group with single-select (radio) or multi-select (checkbox) behavior and custom content. | [docs](docs/Choicebox.md) |
136
+ | **Label** | A real `<label>` element — clicking the text focuses (and for a checkbox or radio, activates) the control named by `for`, with an optional accessible required marker. | [docs](docs/Label.md) |
137
+ | **RatingGroup** | Star rating input — a single `role="slider"` tab stop driven by arrow keys, Home/End or a click, with optional half stars and native form participation. | [docs](docs/RatingGroup.md) |
136
138
 
137
139
  ### Display & Data
138
140
 
139
- | Component | Description | Docs |
140
- | ---------------- | ----------------------------------------------------------------------------------------------- | ---------------------------- |
141
- | **Avatar** | Circular avatar with image (Img with fallback) or text initial. | [docs](docs/Avatar.md) |
142
- | **Badge** | Icon with a numeric/text badge overlay in the corner. | [docs](docs/Badge.md) |
143
- | **GridItem** | Grid cell with icon, label, and loading overlay animation. | [docs](docs/GridItem.md) |
144
- | **Icon** | Clickable icon with optional text label. | [docs](docs/Icon.md) |
145
- | **IconStack** | Layered horizontal stack of overlapping circular icons/avatars. | [docs](docs/IconStack.md) |
146
- | **Img** | Image with automatic fallback on load error. | [docs](docs/Img.md) |
147
- | **ListItem** | Multi-section list row with images, labels, and accordion expansion. | [docs](docs/ListItem.md) |
148
- | **Pill** | Compact label/tag for status or categories, optionally clickable with a11y. | [docs](docs/Pill.md) |
149
- | **Status** | Full-screen status display for success/failure screens. | [docs](docs/Status.md) |
150
- | **Table** | Data table with keyed columns, built-in cell renderers, sorting, pagination and selection. | [docs](docs/Table.md) |
151
- | **RelativeTime** | Auto-updating relative time display ("5 minutes ago") with locale support and optional tooltip. | [docs](docs/RelativeTime.md) |
141
+ | Component | Description | Docs |
142
+ | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- |
143
+ | **Avatar** | Circular avatar with image (Img with fallback) or text initial. | [docs](docs/Avatar.md) |
144
+ | **Badge** | Icon with a numeric/text badge overlay in the corner. | [docs](docs/Badge.md) |
145
+ | **GridItem** | Grid cell with icon, label, and loading overlay animation. | [docs](docs/GridItem.md) |
146
+ | **Icon** | Clickable icon with optional text label. | [docs](docs/Icon.md) |
147
+ | **IconStack** | Layered horizontal stack of overlapping circular icons/avatars. | [docs](docs/IconStack.md) |
148
+ | **Img** | Image with automatic fallback on load error. | [docs](docs/Img.md) |
149
+ | **ListItem** | Multi-section list row with images, labels, and accordion expansion. | [docs](docs/ListItem.md) |
150
+ | **Pill** | Compact label/tag for status or categories, optionally clickable with a11y. | [docs](docs/Pill.md) |
151
+ | **Status** | Full-screen status display for success/failure screens. | [docs](docs/Status.md) |
152
+ | **Table** | Data table with keyed columns, built-in cell renderers, sorting, pagination and selection. | [docs](docs/Table.md) |
153
+ | **RelativeTime** | Auto-updating relative time display ("5 minutes ago") with locale support and optional tooltip. | [docs](docs/RelativeTime.md) |
154
+ | **AspectRatio** | Constrains content to a fixed width-to-height ratio using CSS `aspect-ratio`, reserving layout space before an image, video or iframe loads. | [docs](docs/AspectRatio.md) |
152
155
 
153
156
  ### Feedback & Loading
154
157
 
@@ -178,17 +181,18 @@ fix to something that did not work.
178
181
 
179
182
  ### Navigation & Structure
180
183
 
181
- | Component | Description | Docs |
182
- | ----------------- | ---------------------------------------------------------------------------------------------- | ----------------------------- |
183
- | **Accordion** | Expandable/collapsible container with CSS grid animation. | [docs](docs/Accordion.md) |
184
- | **Carousel** | Horizontal content slider with swipe and pagination dots. | [docs](docs/Carousel.md) |
185
- | **CheckListItem** | Checklist row with checkbox, label, and toggleable checked state. | [docs](docs/CheckListItem.md) |
186
- | **Pagination** | Page navigation with previous/next buttons and numbered page links. | [docs](docs/Pagination.md) |
187
- | **Scroller** | Overflowing item list with arrow navigation, gradient edges, drag-to-scroll, and snap support. | [docs](docs/Scroller.md) |
188
- | **Stepper** | Multi-step progress indicator with completed, active, and pending states. | [docs](docs/Stepper.md) |
189
- | **Step** | Individual step within a Stepper — renders number, label, and connector. | [docs](docs/Step.md) |
190
- | **Tabs** | Tabbed interface with animated active indicator. | [docs](docs/Tabs.md) |
191
- | **Toolbar** | Fixed header bar with back button, title, and customizable content areas. | [docs](docs/Toolbar.md) |
184
+ | Component | Description | Docs |
185
+ | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- |
186
+ | **Accordion** | Expandable/collapsible container with CSS grid animation. | [docs](docs/Accordion.md) |
187
+ | **Carousel** | Horizontal content slider with swipe and pagination dots. | [docs](docs/Carousel.md) |
188
+ | **CheckListItem** | Checklist row with checkbox, label, and toggleable checked state. | [docs](docs/CheckListItem.md) |
189
+ | **Pagination** | Page navigation with previous/next buttons and numbered page links. | [docs](docs/Pagination.md) |
190
+ | **Scroller** | Overflowing item list with arrow navigation, gradient edges, drag-to-scroll, and snap support. | [docs](docs/Scroller.md) |
191
+ | **Stepper** | Multi-step progress indicator with completed, active, and pending states. | [docs](docs/Stepper.md) |
192
+ | **Step** | Individual step within a Stepper — renders number, label, and connector. | [docs](docs/Step.md) |
193
+ | **Tabs** | Tabbed interface with animated active indicator. | [docs](docs/Tabs.md) |
194
+ | **Toolbar** | Fixed header bar with back button, title, and customizable content areas. | [docs](docs/Toolbar.md) |
195
+ | **Separator** | Horizontal or vertical divider — decorative and out of the accessibility tree by default, `role="separator"` when it demarcates meaningful sections. | [docs](docs/Separator.md) |
192
196
 
193
197
  ### Actions
194
198
 
@@ -317,6 +321,39 @@ Every component reads its visual properties from CSS custom properties with sens
317
321
  </div>
318
322
  ```
319
323
 
324
+ ### Dark Mode
325
+
326
+ The library ships a dark theme. Import it once and every component follows
327
+ `data-theme="dark"` on the document root — which is what `ThemeSwitcher`
328
+ already writes:
329
+
330
+ ```js
331
+ import '@juspay/svelte-ui-components/theme-dark.css';
332
+ ```
333
+
334
+ ```svelte
335
+ <script>
336
+ import { ThemeSwitcher } from '@juspay/svelte-ui-components';
337
+ </script>
338
+
339
+ <ThemeSwitcher
340
+ mode="segment"
341
+ onchange={(_, resolved) => {
342
+ document.documentElement.dataset.theme = resolved;
343
+ }}
344
+ />
345
+ ```
346
+
347
+ The stylesheet only re-declares custom properties, so it composes with your own
348
+ theme rather than replacing it: anything you set on a more specific ancestor
349
+ still wins, and any variable you have not set keeps the library's dark value.
350
+
351
+ It also works for the `<sui-*>` custom elements. Custom properties inherit
352
+ across shadow boundaries, which is the only route into a shadow root from
353
+ outside — a selector-based override such as
354
+ `[data-theme='dark'] .my-part { … }` applies in the Svelte build and is dead
355
+ for the web component. Theme through variables and both work.
356
+
320
357
  ### Scoped Theming
321
358
 
322
359
  Because CSS variables cascade, you can scope different themes to different parts of your app:
@@ -344,6 +381,73 @@ Because CSS variables cascade, you can scope different themes to different parts
344
381
  </style>
345
382
  ```
346
383
 
384
+ ### Bridging Your Own Token Scale
385
+
386
+ The library names a property per component element (`--{component}-{element}-{property}`),
387
+ so components render correctly with no stylesheet at all. Most design systems
388
+ name the opposite thing: a short scale of values — a handful of neutrals, lines
389
+ and radii — composed everywhere.
390
+
391
+ Restating a scale as hundreds of per-component declarations, and keeping them in
392
+ step by hand, is not the intended cost. Define your scale once and declare the
393
+ component tokens **in terms of it**; the cascade does the rest, and a value
394
+ changes in one place:
395
+
396
+ ```css
397
+ /* Your scale — the only values you maintain. */
398
+ :root {
399
+ --acme-surface-1: #ffffff;
400
+ --acme-surface-2: #f4f5f7;
401
+ --acme-line-2: #d6d9de;
402
+ --acme-ink-1: #1a1d21;
403
+ --acme-ink-2: #5b6371;
404
+ --acme-accent: #3b5bdb;
405
+ --acme-radius-md: 8px;
406
+ }
407
+
408
+ [data-theme='dark'] {
409
+ --acme-surface-1: #14161a;
410
+ --acme-surface-2: #1e2126;
411
+ --acme-line-2: #333942;
412
+ --acme-ink-1: #e6e8eb;
413
+ --acme-ink-2: #9aa3b2;
414
+ --acme-accent: #748ffc;
415
+ }
416
+
417
+ /* The bridge — component tokens expressed as your scale. Write it once. */
418
+ :root {
419
+ --button-color: var(--acme-accent);
420
+ --button-text-color: var(--acme-surface-1);
421
+ --button-border-radius: var(--acme-radius-md);
422
+ --button-secondary-text-color: var(--acme-ink-1);
423
+ --button-secondary-border-color: var(--acme-line-2);
424
+
425
+ --input-background: var(--acme-surface-1);
426
+ --input-text-color: var(--acme-ink-1);
427
+ --input-border: 1px solid var(--acme-line-2);
428
+ --input-placeholder-color: var(--acme-ink-2);
429
+
430
+ --table-header-background: var(--acme-surface-2);
431
+ --table-content-color: var(--acme-ink-1);
432
+ --table-border: 1px solid var(--acme-line-2);
433
+ }
434
+ ```
435
+
436
+ Note that a few tokens take a full shorthand rather than a bare colour —
437
+ `--input-border` and `--table-border` above are `1px solid …`, not `…`. Setting
438
+ one to a colour alone produces an invalid declaration and no border at all,
439
+ which is silent. Each component's page in [docs/](docs/) gives the shape it
440
+ expects.
441
+
442
+ Both themes now come from seven values. Because the bridge only re-declares
443
+ custom properties it composes with the shipped dark theme rather than fighting
444
+ it: import `theme-dark.css` for the components you have not bridged, and your
445
+ own declarations win wherever they are more specific.
446
+
447
+ The same file works for the `<sui-*>` elements, since custom properties are the
448
+ one thing that crosses a shadow boundary. A rule that reaches _inside_ a
449
+ component — `[data-theme='dark'] .my-part { … }` — silently does nothing there.
450
+
347
451
  ### CSS Variable Reference
348
452
 
349
453
  Each component documents its full set of CSS variables in the [docs/](docs/) directory. The variable naming convention follows the pattern:
@@ -467,7 +571,7 @@ src/lib/
467
571
  {Component}.svelte # component implementation
468
572
  properties.ts # prop type definitions
469
573
  types.ts # shared types (ValidationState, InputDataType, etc.)
470
- utils.ts # shared utilities (validateInput, createDebouncer)
574
+ utils.ts # shared utilities (validateInput, prefersReducedMotion, body scroll lock)
471
575
  index.ts # public exports
472
576
 
473
577
  docs/ # component documentation (one markdown file per component)
@@ -1,6 +1,7 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from 'svelte';
3
3
  import { fly, fade } from 'svelte/transition';
4
+ import { prefersReducedMotion } from '../utils';
4
5
  import type { ModalAlign, ModalEntryAnimation } from '../Modal/properties';
5
6
  import type { ModalTransition } from '../types';
6
7
 
@@ -25,6 +26,16 @@
25
26
  let flyAnimationProperties = $derived.by(() => {
26
27
  const base = { x: 0, y: 0, duration: 380 };
27
28
 
29
+ // Both the distance and the duration go to zero, and the distance is the part
30
+ // that matters: `fly` interpolates towards 0, so duration 0 with y still at 300
31
+ // paints the modal 300px off-target on its first frame and then snaps. Returning
32
+ // `base` unchanged is exactly "appear in place" -- it already has x and y at 0 --
33
+ // so only the duration needs zeroing alongside it. These values feed
34
+ // `in:fly|global={...}`, which no stylesheet can reach, so the guard is here.
35
+ if (prefersReducedMotion()) {
36
+ return { ...base, duration: 0 };
37
+ }
38
+
28
39
  // entryAnimation, when set, overrides the align-based default below —
29
40
  // e.g. a centered modal (which normally fades) can opt into the same
30
41
  // fly distances top/bottom alignment already use.
@@ -45,7 +56,10 @@
45
56
  }
46
57
  });
47
58
 
48
- let fadeAnimationProperties = { duration: 300 };
59
+ // The fade is opacity-only, so it is not the movement the preference targets --
60
+ // but it is still an animation, and the cheapest honest thing is to drop it too
61
+ // rather than argue the distinction at every call site.
62
+ let fadeAnimationProperties = $derived({ duration: prefersReducedMotion() ? 0 : 300 });
49
63
 
50
64
  let useFlyAnimation = $derived(
51
65
  entryAnimation != null ? entryAnimation !== 'fade' : align === 'top' || align === 'bottom'
@@ -13,8 +13,14 @@
13
13
  </script>
14
14
 
15
15
  {#if fadeIn}
16
+ <!-- Same latent bug as Toast.svelte's `in:fly`: `fadeIn` (like Toast's
17
+ `showToast`) is whatever the caller passes on this component's own
18
+ first render, so a local `in:` would never play when a caller mounts
19
+ with `fadeIn` already true -- exactly the "fades in on mount" case
20
+ this prop exists for (see docs/OverlayAnimation.md). `|global` makes
21
+ the intro play on creation regardless. -->
16
22
  <div
17
- in:fade={{ duration: 350 }}
23
+ in:fade|global={{ duration: 350 }}
18
24
  out:fade={{ duration: 350 }}
19
25
  data-pw={typeof testId === 'string' ? testId : null}
20
26
  testID={typeof testId === 'string' ? testId : null}