@marwes-ui/svelte 1.3.0 → 1.4.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 (182) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +43 -11
  3. package/dist/components/README.md +31 -0
  4. package/dist/components/accordion/AccordionField.svelte +20 -6
  5. package/dist/components/accordion/index.d.ts +5 -2
  6. package/dist/components/accordion/index.js +7 -1
  7. package/dist/components/accordion/types.d.ts +3 -0
  8. package/dist/components/avatar/AvatarGroup.svelte +5 -2
  9. package/dist/components/avatar/AvatarGroup.svelte.d.ts +1 -0
  10. package/dist/components/avatar/TeamAvatarGroup.svelte +1 -0
  11. package/dist/components/avatar/TeamAvatarGroup.svelte.d.ts +1 -0
  12. package/dist/components/avatar/index.d.ts +7 -1
  13. package/dist/components/avatar/index.js +6 -0
  14. package/dist/components/avatar/types.d.ts +28 -0
  15. package/dist/components/badge/BadgeGroup.svelte +2 -1
  16. package/dist/components/badge/index.d.ts +5 -1
  17. package/dist/components/badge/index.js +4 -0
  18. package/dist/components/badge/types.d.ts +3 -0
  19. package/dist/components/banner/Banner.svelte +67 -0
  20. package/dist/components/banner/Banner.svelte.d.ts +4 -0
  21. package/dist/components/banner/ErrorBanner.svelte +9 -0
  22. package/dist/components/banner/ErrorBanner.svelte.d.ts +4 -0
  23. package/dist/components/banner/InfoBanner.svelte +9 -0
  24. package/dist/components/banner/InfoBanner.svelte.d.ts +4 -0
  25. package/dist/components/banner/SuccessBanner.svelte +9 -0
  26. package/dist/components/banner/SuccessBanner.svelte.d.ts +4 -0
  27. package/dist/components/banner/WarningBanner.svelte +9 -0
  28. package/dist/components/banner/WarningBanner.svelte.d.ts +4 -0
  29. package/dist/components/banner/index.d.ts +7 -0
  30. package/dist/components/banner/index.js +6 -0
  31. package/dist/components/banner/types.d.ts +14 -0
  32. package/dist/components/banner/types.js +1 -0
  33. package/dist/components/breadcrumb/Breadcrumb.svelte +115 -0
  34. package/dist/components/breadcrumb/Breadcrumb.svelte.d.ts +4 -0
  35. package/dist/components/breadcrumb/index.d.ts +2 -0
  36. package/dist/components/breadcrumb/index.js +1 -0
  37. package/dist/components/breadcrumb/types.d.ts +8 -0
  38. package/dist/components/breadcrumb/types.js +1 -0
  39. package/dist/components/button/Button.svelte +8 -4
  40. package/dist/components/button/DestructiveButton.svelte +1 -1
  41. package/dist/components/button/IconButton.svelte +9 -0
  42. package/dist/components/button/IconButton.svelte.d.ts +4 -0
  43. package/dist/components/button/index.d.ts +24 -1
  44. package/dist/components/button/index.js +23 -0
  45. package/dist/components/button/types.d.ts +30 -1
  46. package/dist/components/card/Card.svelte +2 -1
  47. package/dist/components/card/index.d.ts +4 -1
  48. package/dist/components/card/index.js +3 -0
  49. package/dist/components/card/types.d.ts +4 -0
  50. package/dist/components/checkbox/CheckboxField.svelte +4 -3
  51. package/dist/components/checkbox/CheckboxGroupField.svelte +21 -9
  52. package/dist/components/checkbox/index.d.ts +2 -2
  53. package/dist/components/checkbox/index.js +4 -1
  54. package/dist/components/checkbox/types.d.ts +7 -0
  55. package/dist/components/context-menu/ContextMenu.svelte +56 -0
  56. package/dist/components/context-menu/ContextMenu.svelte.d.ts +4 -0
  57. package/dist/components/context-menu/index.d.ts +2 -0
  58. package/dist/components/context-menu/index.js +1 -0
  59. package/dist/components/context-menu/types.d.ts +7 -0
  60. package/dist/components/context-menu/types.js +1 -0
  61. package/dist/components/date-picker/DatePicker.svelte +14 -2
  62. package/dist/components/date-picker/DatePickerField.svelte +72 -0
  63. package/dist/components/date-picker/DatePickerField.svelte.d.ts +4 -0
  64. package/dist/components/date-picker/index.d.ts +2 -2
  65. package/dist/components/date-picker/index.js +3 -1
  66. package/dist/components/date-picker/types.d.ts +15 -0
  67. package/dist/components/dialog/Dialog.svelte +1 -0
  68. package/dist/components/dialog/DialogModal.svelte +12 -0
  69. package/dist/components/dialog/index.d.ts +1 -1
  70. package/dist/components/dialog/types.d.ts +7 -3
  71. package/dist/components/drawer/Drawer.svelte +132 -0
  72. package/dist/components/drawer/Drawer.svelte.d.ts +4 -0
  73. package/dist/components/drawer/index.d.ts +2 -0
  74. package/dist/components/drawer/index.js +1 -0
  75. package/dist/components/drawer/types.d.ts +16 -0
  76. package/dist/components/drawer/types.js +1 -0
  77. package/dist/components/heading/H1.svelte +10 -0
  78. package/dist/components/heading/H2.svelte +6 -0
  79. package/dist/components/heading/H3.svelte +7 -0
  80. package/dist/components/input/CurrencyField.svelte +1 -1
  81. package/dist/components/input/Input.svelte +1 -0
  82. package/dist/components/input/InputField.svelte +4 -3
  83. package/dist/components/input/InputOtp.svelte +21 -44
  84. package/dist/components/input/InputOtpField.svelte +81 -0
  85. package/dist/components/input/InputOtpField.svelte.d.ts +4 -0
  86. package/dist/components/input/RichText.svelte +7 -6
  87. package/dist/components/input/RichTextField.svelte +4 -3
  88. package/dist/components/input/Select.svelte +7 -31
  89. package/dist/components/input/SelectField.svelte +6 -3
  90. package/dist/components/input/Textarea.svelte +1 -0
  91. package/dist/components/input/TextareaField.svelte +20 -5
  92. package/dist/components/input/index.d.ts +12 -4
  93. package/dist/components/input/index.js +19 -3
  94. package/dist/components/input/types.d.ts +59 -5
  95. package/dist/components/pagination/Pagination.svelte +399 -0
  96. package/dist/components/pagination/Pagination.svelte.d.ts +4 -0
  97. package/dist/components/pagination/PaginationField.svelte +72 -0
  98. package/dist/components/pagination/PaginationField.svelte.d.ts +4 -0
  99. package/dist/components/pagination/index.d.ts +2 -0
  100. package/dist/components/pagination/index.js +2 -0
  101. package/dist/components/pagination/types.d.ts +40 -0
  102. package/dist/components/pagination/types.js +1 -0
  103. package/dist/components/progress-bar/ProgressBar.svelte +50 -0
  104. package/dist/components/progress-bar/ProgressBar.svelte.d.ts +4 -0
  105. package/dist/components/progress-bar/index.d.ts +2 -0
  106. package/dist/components/progress-bar/index.js +1 -0
  107. package/dist/components/progress-bar/types.d.ts +6 -0
  108. package/dist/components/progress-bar/types.js +1 -0
  109. package/dist/components/radio/OptionRadioGroup.svelte +39 -5
  110. package/dist/components/radio/OptionRadioGroup.svelte.d.ts +2 -5
  111. package/dist/components/radio/Radio.svelte +1 -0
  112. package/dist/components/radio/RadioGroupField.svelte +4 -3
  113. package/dist/components/radio/RatingRadioGroup.svelte +18 -3
  114. package/dist/components/radio/YesNoRadioGroup.svelte +18 -3
  115. package/dist/components/radio/index.d.ts +4 -2
  116. package/dist/components/radio/index.js +6 -1
  117. package/dist/components/radio/types.d.ts +47 -0
  118. package/dist/components/segmented-control/SegmentedControl.svelte +125 -0
  119. package/dist/components/segmented-control/SegmentedControl.svelte.d.ts +25 -0
  120. package/dist/components/segmented-control/SegmentedControlField.svelte +76 -0
  121. package/dist/components/segmented-control/SegmentedControlField.svelte.d.ts +25 -0
  122. package/dist/components/segmented-control/index.d.ts +2 -0
  123. package/dist/components/segmented-control/index.js +2 -0
  124. package/dist/components/segmented-control/types.d.ts +41 -0
  125. package/dist/components/segmented-control/types.js +1 -0
  126. package/dist/components/skip-link/SkipLink.svelte +12 -0
  127. package/dist/components/skip-link/SkipLink.svelte.d.ts +4 -0
  128. package/dist/components/skip-link/index.d.ts +2 -0
  129. package/dist/components/skip-link/index.js +1 -0
  130. package/dist/components/skip-link/types.d.ts +7 -0
  131. package/dist/components/skip-link/types.js +1 -0
  132. package/dist/components/slider/SliderField.svelte +9 -8
  133. package/dist/components/slider/index.d.ts +5 -2
  134. package/dist/components/slider/index.js +7 -1
  135. package/dist/components/slider/types.d.ts +21 -0
  136. package/dist/components/spinner/EmptyStateSpinner.svelte +2 -3
  137. package/dist/components/spinner/EmptyStateSpinner.svelte.d.ts +1 -2
  138. package/dist/components/spinner/Spinner.svelte +2 -0
  139. package/dist/components/spinner/index.d.ts +2 -1
  140. package/dist/components/spinner/index.js +1 -0
  141. package/dist/components/spinner/types.d.ts +1 -0
  142. package/dist/components/switch/Switch.svelte +1 -1
  143. package/dist/components/switch/SwitchField.svelte +6 -4
  144. package/dist/components/switch/index.d.ts +4 -2
  145. package/dist/components/switch/index.js +6 -1
  146. package/dist/components/switch/types.d.ts +3 -0
  147. package/dist/components/tab/TabGroup.svelte +7 -4
  148. package/dist/components/text/Text.svelte +23 -0
  149. package/dist/components/text/Text.svelte.d.ts +4 -0
  150. package/dist/components/text/index.d.ts +4 -0
  151. package/dist/components/text/index.js +2 -0
  152. package/dist/components/text/types.d.ts +15 -0
  153. package/dist/components/text/types.js +1 -0
  154. package/dist/components/tooltip/TooltipGroup.svelte +10 -2
  155. package/dist/index.d.ts +47 -29
  156. package/dist/index.js +51 -13
  157. package/dist/provider/MarwesProvider.svelte +26 -14
  158. package/dist/provider/types.d.ts +5 -2
  159. package/package.json +6 -5
  160. package/dist/components/accordion/README.md +0 -19
  161. package/dist/components/avatar/README.md +0 -19
  162. package/dist/components/badge/README.md +0 -16
  163. package/dist/components/button/README.md +0 -21
  164. package/dist/components/card/README.md +0 -15
  165. package/dist/components/checkbox/README.md +0 -17
  166. package/dist/components/date-picker/README.md +0 -17
  167. package/dist/components/dialog/README.md +0 -23
  168. package/dist/components/divider/README.md +0 -15
  169. package/dist/components/heading/README.md +0 -13
  170. package/dist/components/icon/README.md +0 -18
  171. package/dist/components/input/README.md +0 -24
  172. package/dist/components/paragraph/README.md +0 -13
  173. package/dist/components/radio/README.md +0 -16
  174. package/dist/components/skeleton/README.md +0 -16
  175. package/dist/components/slider/README.md +0 -20
  176. package/dist/components/spacing/README.md +0 -15
  177. package/dist/components/spinner/README.md +0 -19
  178. package/dist/components/stat-tile/README.md +0 -15
  179. package/dist/components/switch/README.md +0 -17
  180. package/dist/components/tab/README.md +0 -26
  181. package/dist/components/toast/README.md +0 -35
  182. package/dist/components/tooltip/README.md +0 -22
@@ -0,0 +1,399 @@
1
+ <script lang="ts">
2
+ import {
3
+ IconName,
4
+ clampPaginationPage,
5
+ createPaginationControlRecipe,
6
+ createPaginationEllipsisRecipe,
7
+ createPaginationListItemRecipe,
8
+ createPaginationListRecipe,
9
+ createPaginationPageRecipe,
10
+ createPaginationRecipe,
11
+ resolvePaginationAdaptiveProfile,
12
+ resolvePaginationItemAriaLabel,
13
+ } from "@marwes-ui/core";
14
+ import { onMount } from "svelte";
15
+ import { mergeClass } from "../../internal/merge-class.js";
16
+ import Icon from "../icon/Icon.svelte";
17
+ import type { PaginationAdaptiveProfile, PaginationResolvedControlDisplay } from "@marwes-ui/core";
18
+ import type { PaginationProps } from "./types.js";
19
+
20
+ let {
21
+ pageCount,
22
+ page = $bindable(undefined),
23
+ defaultPage,
24
+ siblingCount,
25
+ boundaryCount,
26
+ maxVisibleItems,
27
+ controlDisplay = "auto",
28
+ adaptive = true,
29
+ showPrevNext,
30
+ showFirstLast,
31
+ disabled,
32
+ firstLabel = "First",
33
+ previousLabel = "Previous",
34
+ nextLabel = "Next",
35
+ lastLabel = "Last",
36
+ ariaLabel,
37
+ ariaLabelledBy,
38
+ ariaDescribedBy,
39
+ getItemAriaLabel,
40
+ onpagechange,
41
+ class: className,
42
+ id,
43
+ }: PaginationProps = $props();
44
+
45
+ let internalPage = $state<number | undefined>(undefined);
46
+ let rootElement = $state<HTMLElement | undefined>(undefined);
47
+ let adaptiveProfile = $state<PaginationAdaptiveProfile | undefined>(undefined);
48
+ let frame = 0;
49
+
50
+ const resolvedPage = $derived(
51
+ clampPaginationPage(page !== undefined ? page : internalPage, pageCount)
52
+ );
53
+
54
+ $effect(() => {
55
+ if (internalPage === undefined) {
56
+ internalPage = clampPaginationPage(defaultPage, pageCount);
57
+ }
58
+ });
59
+
60
+ function selectPage(nextPage: number): void {
61
+ if (disabled) return;
62
+
63
+ const resolved = clampPaginationPage(nextPage, pageCount);
64
+ if (resolved === 0 || resolved === resolvedPage) return;
65
+
66
+ if (page !== undefined) {
67
+ page = resolved;
68
+ } else {
69
+ internalPage = resolved;
70
+ }
71
+ onpagechange?.(resolved);
72
+ }
73
+
74
+ function parsePxValue(value: string, fallback: number): number {
75
+ const parsed = Number.parseFloat(value);
76
+ return Number.isFinite(parsed) ? parsed : fallback;
77
+ }
78
+
79
+ function resolveControlWidths(
80
+ controls: HTMLElement[],
81
+ itemSize: number
82
+ ): { labelControlWidth: number; iconControlWidth: number } {
83
+ const labelControlWidth = controls.reduce((total, control) => {
84
+ const icon = control.querySelector<HTMLElement>(".mw-pagination__control-icon");
85
+ const label = control.querySelector<HTMLElement>(".mw-pagination__control-label");
86
+ const iconWidth = icon?.getBoundingClientRect().width ?? 0;
87
+ const labelWidth = label?.scrollWidth ?? label?.getBoundingClientRect().width ?? 0;
88
+ const labelGap = iconWidth > 0 && labelWidth > 0 ? 4 : 0;
89
+ const measuredLabelWidth = iconWidth + labelGap + labelWidth;
90
+
91
+ return total + Math.max(control.getBoundingClientRect().width, measuredLabelWidth);
92
+ }, 0);
93
+
94
+ return {
95
+ labelControlWidth,
96
+ iconControlWidth: controls.length * itemSize,
97
+ };
98
+ }
99
+
100
+ function measureAdaptiveProfile(): void {
101
+ const parent = rootElement?.parentElement;
102
+ if (!rootElement || !parent || adaptive === false || typeof window === "undefined") {
103
+ adaptiveProfile = undefined;
104
+ return;
105
+ }
106
+
107
+ const rootStyles = window.getComputedStyle(rootElement);
108
+ const parentStyles = window.getComputedStyle(parent);
109
+ const itemSize = parsePxValue(rootStyles.getPropertyValue("--mw-pagination-size"), 32);
110
+ const itemGap = parsePxValue(rootStyles.getPropertyValue("--mw-pagination-gap"), 2);
111
+ const sectionGap = parsePxValue(
112
+ rootStyles.getPropertyValue("--mw-pagination-section-gap"),
113
+ 12
114
+ );
115
+ const parentWidth =
116
+ parent.getBoundingClientRect().width -
117
+ parsePxValue(parentStyles.paddingLeft, 0) -
118
+ parsePxValue(parentStyles.paddingRight, 0);
119
+
120
+ if (parentWidth <= 0) {
121
+ adaptiveProfile = undefined;
122
+ return;
123
+ }
124
+
125
+ const controls = Array.from(rootElement.querySelectorAll<HTMLElement>(".mw-pagination__control"));
126
+ const { labelControlWidth, iconControlWidth } = resolveControlWidths(controls, itemSize);
127
+ adaptiveProfile = resolvePaginationAdaptiveProfile({
128
+ containerWidth: parentWidth,
129
+ labelControlWidth,
130
+ iconControlWidth,
131
+ controlCount: controls.length,
132
+ itemSize,
133
+ itemGap,
134
+ sectionGap,
135
+ pageCount,
136
+ ...(siblingCount !== undefined ? { siblingCount } : {}),
137
+ ...(boundaryCount !== undefined ? { boundaryCount } : {}),
138
+ ...(maxVisibleItems !== undefined ? { maxVisibleItems } : {}),
139
+ controlDisplay,
140
+ });
141
+ }
142
+
143
+ function requestMeasure(): void {
144
+ if (typeof window === "undefined") return;
145
+ window.cancelAnimationFrame(frame);
146
+ frame = window.requestAnimationFrame(measureAdaptiveProfile);
147
+ }
148
+
149
+ onMount(() => {
150
+ requestMeasure();
151
+
152
+ const parent = rootElement?.parentElement;
153
+ const resizeObserver =
154
+ typeof window !== "undefined" && window.ResizeObserver && rootElement && parent
155
+ ? new window.ResizeObserver(requestMeasure)
156
+ : undefined;
157
+
158
+ if (rootElement) resizeObserver?.observe(rootElement);
159
+ if (parent) resizeObserver?.observe(parent);
160
+ window.addEventListener("resize", requestMeasure);
161
+
162
+ return () => {
163
+ window.cancelAnimationFrame(frame);
164
+ resizeObserver?.disconnect();
165
+ window.removeEventListener("resize", requestMeasure);
166
+ };
167
+ });
168
+
169
+ $effect(() => {
170
+ adaptive;
171
+ boundaryCount;
172
+ controlDisplay;
173
+ maxVisibleItems;
174
+ pageCount;
175
+ siblingCount;
176
+ requestMeasure();
177
+ });
178
+
179
+ const resolvedControlDisplay = $derived<PaginationResolvedControlDisplay>(
180
+ adaptive && adaptiveProfile
181
+ ? adaptiveProfile.controlDisplay
182
+ : controlDisplay === "icon"
183
+ ? "icon"
184
+ : "label"
185
+ );
186
+ const resolvedMaxVisibleItems = $derived(
187
+ adaptive && adaptiveProfile ? adaptiveProfile.maxVisibleItems : maxVisibleItems
188
+ );
189
+ const rootKit = $derived(
190
+ createPaginationRecipe({
191
+ page: resolvedPage,
192
+ pageCount,
193
+ ...(siblingCount !== undefined ? { siblingCount } : {}),
194
+ ...(boundaryCount !== undefined ? { boundaryCount } : {}),
195
+ ...(resolvedMaxVisibleItems !== undefined ? { maxVisibleItems: resolvedMaxVisibleItems } : {}),
196
+ controlDisplay: resolvedControlDisplay,
197
+ ...(showPrevNext !== undefined ? { showPrevNext } : {}),
198
+ ...(showFirstLast !== undefined ? { showFirstLast } : {}),
199
+ ...(disabled !== undefined ? { disabled } : {}),
200
+ ...(ariaLabel !== undefined ? { ariaLabel } : {}),
201
+ ...(ariaLabelledBy !== undefined ? { ariaLabelledBy } : {}),
202
+ ...(ariaDescribedBy !== undefined ? { ariaDescribedBy } : {}),
203
+ firstLabel,
204
+ previousLabel,
205
+ nextLabel,
206
+ lastLabel,
207
+ ...(getItemAriaLabel !== undefined ? { getItemAriaLabel } : {}),
208
+ })
209
+ );
210
+ const listKit = $derived(createPaginationListRecipe());
211
+ const listItemKit = $derived(createPaginationListItemRecipe());
212
+ const previousDisabled = $derived(disabled || resolvedPage <= 1);
213
+ const nextDisabled = $derived(disabled || resolvedPage <= 0 || resolvedPage >= pageCount);
214
+ const firstDisabled = $derived(disabled || resolvedPage <= 1);
215
+ const lastDisabled = $derived(disabled || resolvedPage <= 0 || resolvedPage >= pageCount);
216
+ const firstKit = $derived(
217
+ createPaginationControlRecipe({
218
+ direction: "first",
219
+ disabled: firstDisabled,
220
+ label: firstLabel,
221
+ ...(getItemAriaLabel !== undefined
222
+ ? {
223
+ ariaLabel: resolvePaginationItemAriaLabel(getItemAriaLabel, {
224
+ type: "first",
225
+ page: 1,
226
+ selected: false,
227
+ }),
228
+ }
229
+ : {}),
230
+ })
231
+ );
232
+ const previousKit = $derived(
233
+ createPaginationControlRecipe({
234
+ direction: "previous",
235
+ disabled: previousDisabled,
236
+ label: previousLabel,
237
+ ...(getItemAriaLabel !== undefined
238
+ ? {
239
+ ariaLabel: resolvePaginationItemAriaLabel(getItemAriaLabel, {
240
+ type: "previous",
241
+ page: resolvedPage - 1,
242
+ selected: false,
243
+ }),
244
+ }
245
+ : {}),
246
+ })
247
+ );
248
+ const nextKit = $derived(
249
+ createPaginationControlRecipe({
250
+ direction: "next",
251
+ disabled: nextDisabled,
252
+ label: nextLabel,
253
+ ...(getItemAriaLabel !== undefined
254
+ ? {
255
+ ariaLabel: resolvePaginationItemAriaLabel(getItemAriaLabel, {
256
+ type: "next",
257
+ page: resolvedPage + 1,
258
+ selected: false,
259
+ }),
260
+ }
261
+ : {}),
262
+ })
263
+ );
264
+ const lastKit = $derived(
265
+ createPaginationControlRecipe({
266
+ direction: "last",
267
+ disabled: lastDisabled,
268
+ label: lastLabel,
269
+ ...(getItemAriaLabel !== undefined
270
+ ? {
271
+ ariaLabel: resolvePaginationItemAriaLabel(getItemAriaLabel, {
272
+ type: "last",
273
+ page: pageCount,
274
+ selected: false,
275
+ }),
276
+ }
277
+ : {}),
278
+ })
279
+ );
280
+ const mergedClass = $derived(mergeClass(rootKit.className, className));
281
+ const rootStyle = $derived(rootKit.vars["--mw-pagination-list-width"]
282
+ ? `--mw-pagination-list-width: ${rootKit.vars["--mw-pagination-list-width"]};`
283
+ : undefined);
284
+ </script>
285
+
286
+ <nav
287
+ {id}
288
+ bind:this={rootElement}
289
+ class={mergedClass}
290
+ style={rootStyle}
291
+ aria-label={rootKit.a11y.ariaLabel}
292
+ aria-labelledby={rootKit.a11y.ariaLabelledBy}
293
+ aria-describedby={rootKit.a11y.ariaDescribedBy}
294
+ data-component="pagination"
295
+ data-control-display={rootKit.controlDisplay}
296
+ >
297
+ {#if rootKit.showFirstLast}
298
+ <button
299
+ type="button"
300
+ class={firstKit.className}
301
+ aria-label={firstKit.a11y.ariaLabel}
302
+ aria-disabled={firstKit.a11y.ariaDisabled}
303
+ disabled={firstDisabled}
304
+ onclick={() => selectPage(1)}
305
+ >
306
+ <span class="mw-pagination__control-icon">
307
+ <Icon name={IconName.ChevronsLeft} decorative size={12} />
308
+ </span>
309
+ <span class="mw-pagination__control-label">{firstLabel}</span>
310
+ </button>
311
+ {/if}
312
+
313
+ {#if rootKit.showPrevNext}
314
+ <button
315
+ type="button"
316
+ class={previousKit.className}
317
+ aria-label={previousKit.a11y.ariaLabel}
318
+ aria-disabled={previousKit.a11y.ariaDisabled}
319
+ disabled={previousDisabled}
320
+ onclick={() => selectPage(resolvedPage - 1)}
321
+ >
322
+ <span class="mw-pagination__control-icon">
323
+ <Icon name={IconName.ChevronLeft} decorative size={12} />
324
+ </span>
325
+ <span class="mw-pagination__control-label">{previousLabel}</span>
326
+ </button>
327
+ {/if}
328
+
329
+ <ul class={listKit.className} role={listKit.a11y.role}>
330
+ {#each rootKit.items as item (item.key)}
331
+ <li class={listItemKit.className}>
332
+ {#if item.type !== "page"}
333
+ {@const ellipsisKit = createPaginationEllipsisRecipe()}
334
+ <span class={ellipsisKit.className} aria-hidden={ellipsisKit.a11y.ariaHidden}>
335
+ ...
336
+ </span>
337
+ {:else}
338
+ {@const pageKit = createPaginationPageRecipe({
339
+ page: item.page,
340
+ selected: item.selected,
341
+ ...(disabled !== undefined ? { disabled } : {}),
342
+ ...(getItemAriaLabel !== undefined
343
+ ? {
344
+ ariaLabel: resolvePaginationItemAriaLabel(getItemAriaLabel, {
345
+ type: "page",
346
+ page: item.page,
347
+ selected: item.selected,
348
+ }),
349
+ }
350
+ : {}),
351
+ })}
352
+ <button
353
+ type="button"
354
+ class={pageKit.className}
355
+ aria-label={pageKit.a11y.ariaLabel}
356
+ aria-current={pageKit.a11y.ariaCurrent}
357
+ aria-disabled={pageKit.a11y.ariaDisabled}
358
+ disabled={disabled}
359
+ onclick={() => selectPage(item.page)}
360
+ >
361
+ {item.page}
362
+ </button>
363
+ {/if}
364
+ </li>
365
+ {/each}
366
+ </ul>
367
+
368
+ {#if rootKit.showPrevNext}
369
+ <button
370
+ type="button"
371
+ class={nextKit.className}
372
+ aria-label={nextKit.a11y.ariaLabel}
373
+ aria-disabled={nextKit.a11y.ariaDisabled}
374
+ disabled={nextDisabled}
375
+ onclick={() => selectPage(resolvedPage + 1)}
376
+ >
377
+ <span class="mw-pagination__control-label">{nextLabel}</span>
378
+ <span class="mw-pagination__control-icon">
379
+ <Icon name={IconName.ChevronRight} decorative size={12} />
380
+ </span>
381
+ </button>
382
+ {/if}
383
+
384
+ {#if rootKit.showFirstLast}
385
+ <button
386
+ type="button"
387
+ class={lastKit.className}
388
+ aria-label={lastKit.a11y.ariaLabel}
389
+ aria-disabled={lastKit.a11y.ariaDisabled}
390
+ disabled={lastDisabled}
391
+ onclick={() => selectPage(pageCount)}
392
+ >
393
+ <span class="mw-pagination__control-label">{lastLabel}</span>
394
+ <span class="mw-pagination__control-icon">
395
+ <Icon name={IconName.ChevronsRight} decorative size={12} />
396
+ </span>
397
+ </button>
398
+ {/if}
399
+ </nav>
@@ -0,0 +1,4 @@
1
+ import type { PaginationProps } from "./types.js";
2
+ declare const Pagination: import("svelte").Component<PaginationProps, {}, "page">;
3
+ type Pagination = ReturnType<typeof Pagination>;
4
+ export default Pagination;
@@ -0,0 +1,72 @@
1
+ <script lang="ts">
2
+ import { buildInputFieldA11yIds } from "@marwes-ui/core";
3
+ import { mergeClass } from "../../internal/merge-class.js";
4
+ import Text from "../text/Text.svelte";
5
+ import Pagination from "./Pagination.svelte";
6
+ import type { PaginationFieldProps, PaginationProps } from "./types.js";
7
+
8
+ let {
9
+ id: userProvidedId,
10
+ label,
11
+ description,
12
+ error,
13
+ pagination,
14
+ ariaDescribedBy,
15
+ class: className,
16
+ }: PaginationFieldProps = $props();
17
+
18
+ const uniqueId = $props.id();
19
+ const fieldId = $derived(userProvidedId ?? `mw-pagination-${uniqueId}`);
20
+ const labelId = $derived(`${fieldId}-label`);
21
+
22
+ function hasTextContent(text: string | undefined): boolean {
23
+ return text !== undefined && text.trim().length > 0;
24
+ }
25
+
26
+ const hasDescription = $derived(hasTextContent(description));
27
+ const hasError = $derived(hasTextContent(error));
28
+
29
+ const a11yIds = $derived(
30
+ buildInputFieldA11yIds({
31
+ id: fieldId,
32
+ hasHelperText: hasDescription,
33
+ hasError,
34
+ externalDescribedBy: ariaDescribedBy,
35
+ })
36
+ );
37
+
38
+ const wrapperClass = $derived(
39
+ mergeClass("mw-pagination-field", hasError && "mw-pagination-field--invalid", className)
40
+ );
41
+
42
+ const paginationProps = $derived.by((): PaginationProps => {
43
+ const props: PaginationProps = {
44
+ ...pagination,
45
+ ariaLabelledBy: labelId,
46
+ } as PaginationProps;
47
+ if (a11yIds.describedBy) {
48
+ props.ariaDescribedBy = a11yIds.describedBy;
49
+ }
50
+ return props;
51
+ });
52
+ </script>
53
+
54
+ <div class={wrapperClass}>
55
+ <span class="mw-pagination-field__label" id={labelId}>
56
+ <Text variant="label">{label}</Text>
57
+ </span>
58
+
59
+ {#if hasDescription && !hasError}
60
+ <div class="mw-pagination-field__description" id={a11yIds.helperTextId}>
61
+ <Text variant="caption">{description}</Text>
62
+ </div>
63
+ {/if}
64
+
65
+ <Pagination {...paginationProps} />
66
+
67
+ {#if hasError}
68
+ <div class="mw-pagination-field__error" id={a11yIds.errorId} aria-live="polite">
69
+ <Text variant="caption">{error}</Text>
70
+ </div>
71
+ {/if}
72
+ </div>
@@ -0,0 +1,4 @@
1
+ import type { PaginationFieldProps } from "./types.js";
2
+ declare const PaginationField: import("svelte").Component<PaginationFieldProps, {}, "">;
3
+ type PaginationField = ReturnType<typeof PaginationField>;
4
+ export default PaginationField;
@@ -0,0 +1,2 @@
1
+ export { default as PaginationField } from "./PaginationField.svelte";
2
+ export type { PaginationFieldProps } from "./types.js";
@@ -0,0 +1,2 @@
1
+ // `Pagination` atom intentionally NOT re-exported — use `PaginationField`.
2
+ export { default as PaginationField } from "./PaginationField.svelte";
@@ -0,0 +1,40 @@
1
+ import type { PaginationControlDisplay, PaginationGetItemAriaLabel } from "@marwes-ui/core";
2
+ export interface PaginationProps {
3
+ pageCount: number;
4
+ page?: number;
5
+ defaultPage?: number;
6
+ siblingCount?: number;
7
+ boundaryCount?: number;
8
+ maxVisibleItems?: number;
9
+ controlDisplay?: PaginationControlDisplay;
10
+ adaptive?: boolean;
11
+ showPrevNext?: boolean;
12
+ showFirstLast?: boolean;
13
+ disabled?: boolean;
14
+ firstLabel?: string;
15
+ previousLabel?: string;
16
+ nextLabel?: string;
17
+ lastLabel?: string;
18
+ ariaLabel?: string;
19
+ ariaLabelledBy?: string;
20
+ ariaDescribedBy?: string;
21
+ getItemAriaLabel?: PaginationGetItemAriaLabel;
22
+ onpagechange?: (page: number) => void;
23
+ class?: string;
24
+ id?: string;
25
+ }
26
+ export interface PaginationFieldProps {
27
+ /** Optional: if omitted, a stable id is generated. */
28
+ id?: string;
29
+ /** Field label (required for accessibility). */
30
+ label: string;
31
+ /** Optional description text. */
32
+ description?: string;
33
+ /** Optional error message. */
34
+ error?: string;
35
+ /** Props forwarded to the Pagination atom. */
36
+ pagination: Omit<PaginationProps, "ariaLabel" | "ariaLabelledBy" | "ariaDescribedBy">;
37
+ /** Additional aria-describedby IDs to merge with internal description/error IDs. */
38
+ ariaDescribedBy?: string;
39
+ class?: string;
40
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,50 @@
1
+ <script lang="ts">
2
+ import { createProgressBarRecipe } from "@marwes-ui/core";
3
+ import { cssVarsToStyle, mergeStyle } from "../../internal/css-vars.js";
4
+ import { mergeClass } from "../../internal/merge-class.js";
5
+ import type { ProgressBarProps } from "./types.js";
6
+
7
+ let {
8
+ class: className,
9
+ style,
10
+ dataAttributes,
11
+ ...options
12
+ }: ProgressBarProps = $props();
13
+
14
+ const kit = $derived(createProgressBarRecipe(options));
15
+ const mergedClass = $derived(mergeClass(kit.className, className));
16
+ const mergedStyle = $derived(mergeStyle(cssVarsToStyle(kit.vars), style));
17
+ const hasLabelRow = $derived(kit.showLabel || kit.showPercentage);
18
+ </script>
19
+
20
+ <div
21
+ class={mergedClass}
22
+ style={mergedStyle}
23
+ id={kit.a11y.id}
24
+ role={kit.a11y.role}
25
+ aria-valuemin={kit.a11y.ariaValueMin}
26
+ aria-valuemax={kit.a11y.ariaValueMax}
27
+ aria-valuenow={kit.a11y.ariaValueNow}
28
+ aria-valuetext={kit.a11y.ariaValueText}
29
+ aria-label={kit.a11y.ariaLabel}
30
+ aria-labelledby={kit.a11y.ariaLabelledBy}
31
+ aria-describedby={kit.a11y.ariaDescribedBy}
32
+ aria-disabled={kit.a11y.ariaDisabled ? "true" : undefined}
33
+ {...kit.dataAttributes}
34
+ {...dataAttributes}
35
+ >
36
+ {#if hasLabelRow}
37
+ <div class="mw-progress-bar__label-row">
38
+ {#if kit.showLabel}
39
+ <span id={kit.labelId} class={kit.labelClassName}>{kit.label}</span>
40
+ {/if}
41
+ {#if kit.showPercentage}
42
+ <span class={kit.percentageClassName}>{kit.percentageLabel}</span>
43
+ {/if}
44
+ </div>
45
+ {/if}
46
+
47
+ <div class={kit.trackClassName} aria-hidden="true">
48
+ <span class={kit.fillClassName}></span>
49
+ </div>
50
+ </div>
@@ -0,0 +1,4 @@
1
+ import type { ProgressBarProps } from "./types.js";
2
+ declare const ProgressBar: import("svelte").Component<ProgressBarProps, {}, "">;
3
+ type ProgressBar = ReturnType<typeof ProgressBar>;
4
+ export default ProgressBar;
@@ -0,0 +1,2 @@
1
+ export { default as ProgressBar } from "./ProgressBar.svelte";
2
+ export type { ProgressBarProps } from "./types.js";
@@ -0,0 +1 @@
1
+ export { default as ProgressBar } from "./ProgressBar.svelte";
@@ -0,0 +1,6 @@
1
+ import type { ProgressBarOptions } from "@marwes-ui/core";
2
+ export interface ProgressBarProps extends ProgressBarOptions {
3
+ class?: string;
4
+ style?: string | undefined;
5
+ dataAttributes?: Record<string, string>;
6
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,6 +1,8 @@
1
1
  <script lang="ts">
2
+ import Text from "../text/Text.svelte";
2
3
  import Radio from "./Radio.svelte";
3
4
  import RadioGroupField from "./RadioGroupField.svelte";
5
+ import type { RadioGroupFieldOption } from "./types.js";
4
6
 
5
7
  interface OptionRadioGroupProps {
6
8
  name: string;
@@ -8,7 +10,7 @@
8
10
  description?: string;
9
11
  error?: string;
10
12
  ariaDescribedBy?: string;
11
- options: Array<{ value: string; label: string; disabled?: boolean }>;
13
+ options: RadioGroupFieldOption[];
12
14
  value?: string;
13
15
  defaultValue?: string;
14
16
  onchange?: (value: string) => void;
@@ -19,11 +21,23 @@
19
21
 
20
22
  let { name, options, value, defaultValue, onchange, disabled, required, error, ...fieldProps }: OptionRadioGroupProps = $props();
21
23
 
22
- let selected = $state(value ?? defaultValue ?? "");
24
+ function getInitialSelected(): string {
25
+ return defaultValue ?? "";
26
+ }
27
+
28
+ const isControlled = $derived(value !== undefined);
29
+ let internalSelected = $state(getInitialSelected());
30
+ const selected = $derived(isControlled ? (value ?? "") : internalSelected);
23
31
  const isInvalid = $derived(error !== undefined && error.trim().length > 0);
24
32
 
33
+ function hasTextContent(text: string | undefined): boolean {
34
+ return text !== undefined && text.trim().length > 0;
35
+ }
36
+
25
37
  function handleChange(optValue: string) {
26
- selected = optValue;
38
+ if (!isControlled) {
39
+ internalSelected = optValue;
40
+ }
27
41
  onchange?.(optValue);
28
42
  }
29
43
  </script>
@@ -36,17 +50,37 @@
36
50
  dataAttributes={{ "data-purpose": "selection" }}
37
51
  >
38
52
  {#each options as opt (opt.value)}
39
- <label class="mw-radio-group-field__option">
53
+ {@const optionLabelId = `${name}-${opt.value}-label`}
54
+ {@const optionDescriptionId = `${name}-${opt.value}-description`}
55
+ {@const hasOptionDescription = hasTextContent(opt.description)}
56
+ <label
57
+ class={`mw-radio-group-field__option${hasOptionDescription ? " mw-radio-group-field__option--with-description" : ""}`}
58
+ >
40
59
  <Radio
41
60
  {name}
42
61
  value={opt.value}
62
+ ariaLabelledBy={optionLabelId}
63
+ {...(hasOptionDescription ? { ariaDescribedBy: optionDescriptionId } : {})}
43
64
  checked={selected === opt.value}
44
65
  disabled={disabled || opt.disabled || false}
45
66
  invalid={isInvalid}
46
67
  required={required === true}
47
68
  onchange={() => handleChange(opt.value)}
48
69
  />
49
- <span class="mw-p mw-p--sm">{opt.label}</span>
70
+ <span class="mw-radio-group-field__option-content">
71
+ <Text id={optionLabelId} variant="label" class="mw-radio-group-field__option-label">
72
+ {opt.label}
73
+ </Text>
74
+ {#if hasOptionDescription}
75
+ <Text
76
+ id={optionDescriptionId}
77
+ variant="label-small"
78
+ class="mw-radio-group-field__option-description"
79
+ >
80
+ {opt.description}
81
+ </Text>
82
+ {/if}
83
+ </span>
50
84
  </label>
51
85
  {/each}
52
86
  </RadioGroupField>