@makolabs/ripple 2.5.9 → 3.0.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 (183) hide show
  1. package/README.md +403 -497
  2. package/dist/adapters/storage/S3Adapter.d.ts +49 -1
  3. package/dist/adapters/storage/S3Adapter.js +38 -1
  4. package/dist/adapters/storage/types.d.ts +20 -0
  5. package/dist/ai/AIChatInterface.svelte +2 -1
  6. package/dist/ai/AIChatInterface.svelte.d.ts +2 -1
  7. package/dist/ai/CodeRenderer.svelte +7 -2
  8. package/dist/ai/CodeRenderer.svelte.d.ts +2 -1
  9. package/dist/ai/ComposeDropdown.svelte +1 -1
  10. package/dist/ai/MessageBox.svelte +3 -3
  11. package/dist/ai/MessageBox.svelte.d.ts +3 -2
  12. package/dist/ai/ThinkingDisplay.svelte +4 -3
  13. package/dist/ai/ThinkingDisplay.svelte.d.ts +2 -1
  14. package/dist/ai/ai-types.d.ts +55 -1
  15. package/dist/button/Button.svelte +5 -5
  16. package/dist/button/button-types.d.ts +49 -4
  17. package/dist/button/button.d.ts +9 -9
  18. package/dist/button/button.js +6 -6
  19. package/dist/charts/Chart.svelte +8 -16
  20. package/dist/charts/chart-types.d.ts +78 -1
  21. package/dist/drawer/Drawer.svelte +6 -26
  22. package/dist/drawer/drawer-types.d.ts +33 -12
  23. package/dist/drawer/drawer.d.ts +3 -3
  24. package/dist/drawer/drawer.js +1 -1
  25. package/dist/elements/accordion/Accordion.svelte +6 -17
  26. package/dist/elements/accordion/accordion-types.d.ts +53 -6
  27. package/dist/elements/alert/Alert.svelte +3 -0
  28. package/dist/elements/badge/Badge.svelte +1 -1
  29. package/dist/elements/badge/badge-types.d.ts +22 -0
  30. package/dist/elements/badge/badge.d.ts +3 -3
  31. package/dist/elements/badge/badge.js +1 -1
  32. package/dist/elements/combobox/ComboBox.svelte +247 -0
  33. package/dist/elements/combobox/ComboBox.svelte.d.ts +4 -0
  34. package/dist/elements/combobox/combobox-types.d.ts +41 -0
  35. package/dist/elements/combobox/combobox-types.js +1 -0
  36. package/dist/elements/context-menu/ContextMenu.svelte +137 -0
  37. package/dist/elements/context-menu/ContextMenu.svelte.d.ts +4 -0
  38. package/dist/elements/context-menu/context-menu-types.d.ts +40 -0
  39. package/dist/elements/context-menu/context-menu-types.js +1 -0
  40. package/dist/elements/dropdown/Dropdown.svelte +1 -1
  41. package/dist/elements/dropdown/Select.svelte +4 -1
  42. package/dist/elements/dropdown/dropdown-types.d.ts +114 -0
  43. package/dist/elements/dropdown/dropdown.d.ts +3 -3
  44. package/dist/elements/dropdown/dropdown.js +2 -2
  45. package/dist/elements/dropdown/select.d.ts +3 -3
  46. package/dist/elements/dropdown/select.js +2 -2
  47. package/dist/elements/empty-state/EmptyState.svelte +1 -1
  48. package/dist/elements/empty-state/empty-state-types.d.ts +32 -1
  49. package/dist/elements/empty-state/empty-state.d.ts +3 -3
  50. package/dist/elements/empty-state/empty-state.js +2 -2
  51. package/dist/elements/file-upload/FileUpload.svelte +5 -0
  52. package/dist/elements/file-upload/file-upload-types.d.ts +59 -0
  53. package/dist/elements/pagination/Pagination.svelte +53 -21
  54. package/dist/elements/pagination/Pagination.svelte.d.ts +33 -5
  55. package/dist/elements/popover/Popover.svelte +234 -0
  56. package/dist/elements/popover/Popover.svelte.d.ts +4 -0
  57. package/dist/elements/popover/index.d.ts +2 -0
  58. package/dist/elements/popover/index.js +1 -0
  59. package/dist/elements/popover/popover-types.d.ts +60 -0
  60. package/dist/elements/popover/popover-types.js +1 -0
  61. package/dist/elements/progress/Progress.svelte +32 -7
  62. package/dist/elements/progress/progress-types.d.ts +48 -1
  63. package/dist/elements/skeleton/Skeleton.svelte +56 -0
  64. package/dist/elements/skeleton/Skeleton.svelte.d.ts +4 -0
  65. package/dist/elements/skeleton/index.d.ts +2 -0
  66. package/dist/elements/skeleton/index.js +1 -0
  67. package/dist/elements/skeleton/skeleton-types.d.ts +50 -0
  68. package/dist/elements/skeleton/skeleton-types.js +1 -0
  69. package/dist/elements/spinner/Spinner.svelte +1 -1
  70. package/dist/elements/spinner/spinner-types.d.ts +20 -0
  71. package/dist/elements/spinner/spinner.d.ts +3 -3
  72. package/dist/elements/spinner/spinner.js +2 -2
  73. package/dist/elements/tooltip/Tooltip.svelte +108 -11
  74. package/dist/elements/tooltip/tooltip-types.d.ts +49 -1
  75. package/dist/file-browser/FileBrowser.svelte +21 -12
  76. package/dist/filters/CompactFilters.svelte +221 -33
  77. package/dist/filters/CompactFilters.svelte.d.ts +1 -1
  78. package/dist/filters/FilterBar.svelte +184 -0
  79. package/dist/filters/FilterBar.svelte.d.ts +4 -0
  80. package/dist/filters/FilterPopover.svelte +346 -0
  81. package/dist/filters/FilterPopover.svelte.d.ts +4 -0
  82. package/dist/filters/date-presets.d.ts +15 -0
  83. package/dist/filters/date-presets.js +107 -0
  84. package/dist/filters/filter-types.d.ts +69 -3
  85. package/dist/filters/index.d.ts +5 -0
  86. package/dist/filters/index.js +4 -0
  87. package/dist/filters/sync-filters-to-url.svelte.d.ts +37 -0
  88. package/dist/filters/sync-filters-to-url.svelte.js +114 -0
  89. package/dist/forms/DateRange.svelte +4 -2
  90. package/dist/forms/Input.svelte +2 -2
  91. package/dist/forms/MarketSelector.svelte +8 -3
  92. package/dist/forms/NumberInput.svelte +4 -4
  93. package/dist/forms/RadioGroup.svelte +123 -0
  94. package/dist/forms/RadioGroup.svelte.d.ts +4 -0
  95. package/dist/forms/SegmentedControl.svelte +11 -4
  96. package/dist/forms/Slider.svelte +72 -3
  97. package/dist/forms/Tags.svelte +14 -5
  98. package/dist/forms/Textarea.svelte +126 -0
  99. package/dist/forms/Textarea.svelte.d.ts +4 -0
  100. package/dist/forms/Toggle.svelte +8 -8
  101. package/dist/forms/calendar/Calendar.svelte +218 -0
  102. package/dist/forms/calendar/Calendar.svelte.d.ts +4 -0
  103. package/dist/forms/calendar/calendar-types.d.ts +46 -0
  104. package/dist/forms/calendar/calendar-types.js +1 -0
  105. package/dist/forms/calendar/index.d.ts +2 -0
  106. package/dist/forms/calendar/index.js +1 -0
  107. package/dist/forms/date-picker/DatePicker.svelte +144 -0
  108. package/dist/forms/date-picker/DatePicker.svelte.d.ts +4 -0
  109. package/dist/forms/date-picker/date-picker-types.d.ts +29 -0
  110. package/dist/forms/date-picker/date-picker-types.js +1 -0
  111. package/dist/forms/form-types.d.ts +425 -6
  112. package/dist/forms/market/market-selector-types.d.ts +52 -1
  113. package/dist/forms/segmented-control.d.ts +5 -2
  114. package/dist/forms/segmented-control.js +16 -5
  115. package/dist/forms/slider.d.ts +3 -3
  116. package/dist/forms/slider.js +2 -2
  117. package/dist/funcs/user-management.remote.js +1 -1
  118. package/dist/header/Breadcrumbs.svelte +4 -20
  119. package/dist/header/PageHeader.svelte +6 -14
  120. package/dist/header/breadcrumbs.d.ts +3 -11
  121. package/dist/header/breadcrumbs.js +10 -5
  122. package/dist/header/header-types.d.ts +62 -11
  123. package/dist/index.d.ts +35 -9
  124. package/dist/index.js +24 -4
  125. package/dist/layout/activity-list/ActivityList.svelte +13 -7
  126. package/dist/layout/activity-list/activity-list-types.d.ts +46 -7
  127. package/dist/layout/card/Card.svelte +12 -15
  128. package/dist/layout/card/MetricCard.svelte +50 -32
  129. package/dist/layout/card/card-types.d.ts +114 -4
  130. package/dist/layout/navbar/navbar-types.d.ts +48 -0
  131. package/dist/layout/navbar/navbar.d.ts +3 -3
  132. package/dist/layout/navbar/navbar.js +2 -2
  133. package/dist/layout/sidebar/Sidebar.svelte +87 -11
  134. package/dist/layout/sidebar/sidebar-types.d.ts +60 -1
  135. package/dist/layout/stepper/Stepper.svelte +288 -0
  136. package/dist/layout/stepper/Stepper.svelte.d.ts +4 -0
  137. package/dist/layout/stepper/stepper-types.d.ts +80 -0
  138. package/dist/layout/stepper/stepper-types.js +1 -0
  139. package/dist/layout/table/Table.svelte +91 -85
  140. package/dist/layout/table/table-types.d.ts +148 -24
  141. package/dist/layout/table/table.d.ts +3 -3
  142. package/dist/layout/table/table.js +2 -2
  143. package/dist/layout/tabs/Tab.svelte +6 -2
  144. package/dist/layout/tabs/Tab.svelte.d.ts +4 -1
  145. package/dist/layout/tabs/TabGroup.svelte +9 -2
  146. package/dist/layout/tabs/tabs-types.d.ts +63 -0
  147. package/dist/layout/tabs/tabs.d.ts +3 -3
  148. package/dist/layout/tabs/tabs.js +12 -6
  149. package/dist/modal/ConfirmDialog.svelte +65 -0
  150. package/dist/modal/ConfirmDialog.svelte.d.ts +4 -0
  151. package/dist/modal/Modal.svelte +6 -26
  152. package/dist/modal/confirm-dialog-types.d.ts +39 -0
  153. package/dist/modal/confirm-dialog-types.js +1 -0
  154. package/dist/modal/modal-types.d.ts +51 -12
  155. package/dist/modal/modal.d.ts +3 -3
  156. package/dist/modal/modal.js +3 -3
  157. package/dist/pipeline/Pipeline.svelte +8 -3
  158. package/dist/pipeline/pipeline-types.d.ts +55 -3
  159. package/dist/pipeline/pipeline.d.ts +18 -3
  160. package/dist/pipeline/pipeline.js +7 -2
  161. package/dist/server/s3.d.ts +35 -3
  162. package/dist/sonner/Toaster.svelte +29 -0
  163. package/dist/sonner/Toaster.svelte.d.ts +4 -0
  164. package/dist/sonner/index.d.ts +21 -0
  165. package/dist/sonner/index.js +20 -0
  166. package/dist/user-management/UserManagement.svelte +22 -16
  167. package/dist/user-management/UserModal.svelte +10 -7
  168. package/dist/user-management/UserTable.svelte +16 -17
  169. package/dist/user-management/UserViewModal.svelte +11 -11
  170. package/dist/user-management/user-management-types.d.ts +118 -31
  171. package/dist/variants.d.ts +1 -1
  172. package/dist/variants.js +1 -1
  173. package/package.json +7 -4
  174. package/dist/config/ai.d.ts +0 -13
  175. package/dist/config/ai.js +0 -44
  176. package/dist/elements/empty-state/EmptyStateTestWrapper.svelte +0 -25
  177. package/dist/elements/empty-state/EmptyStateTestWrapper.svelte.d.ts +0 -8
  178. package/dist/elements/tooltip/TooltipTestWrapper.svelte +0 -14
  179. package/dist/elements/tooltip/TooltipTestWrapper.svelte.d.ts +0 -7
  180. package/dist/helper/deprecation.d.ts +0 -14
  181. package/dist/helper/deprecation.js +0 -24
  182. package/dist/modal/ModalFooterTestWrapper.svelte +0 -17
  183. package/dist/modal/ModalFooterTestWrapper.svelte.d.ts +0 -8
@@ -2,53 +2,149 @@ import type { ClassValue } from 'tailwind-variants';
2
2
  import type { Snippet } from 'svelte';
3
3
  import type { Component } from 'svelte';
4
4
  import type { VariantSizes } from '../../index.js';
5
+ /** Single menu entry in a `<Dropdown>` section. */
5
6
  export type DropdownItem = {
7
+ /** Visible text. */
6
8
  label: string;
9
+ /** If set, renders the item as a link; otherwise as a button. Typed to SvelteKit routes. */
7
10
  href?: `/${string}`;
11
+ /** Optional icon rendered on the left. */
8
12
  icon?: Component;
13
+ /** Click handler (ignored when `href` is set — native navigation wins). */
9
14
  onclick?: () => void;
15
+ /** Visually highlight the item as the current route/selection. */
10
16
  active?: boolean;
11
17
  };
18
+ /** A visually grouped subset of items — renders with a separator between sections. */
12
19
  export type DropSection = {
13
20
  items: DropdownItem[];
14
21
  };
22
+ /**
23
+ * Optional header at the top of the dropdown panel (user profile snippet,
24
+ * workspace switcher heading, etc.).
25
+ */
15
26
  export type DropHeaderConfig = {
16
27
  title?: string;
17
28
  subtitle?: string;
29
+ /** Custom header content. Takes precedence over `title`/`subtitle`. */
18
30
  content?: Snippet<[]>;
19
31
  class?: ClassValue;
20
32
  titleClass?: ClassValue;
21
33
  subtitleClass?: ClassValue;
34
+ /** Click handler for the header row. */
22
35
  onclick?: () => void;
23
36
  };
37
+ /**
38
+ * Props for `<Dropdown>` — an action menu attached to a trigger button.
39
+ * Use for context actions, overflow menus, user profile menus, etc.
40
+ *
41
+ * For *form* selection (picking one of many values), use `<Select>`
42
+ * instead — that's a controlled form input.
43
+ *
44
+ * @example
45
+ * ```svelte
46
+ * <Dropdown
47
+ * label="Actions"
48
+ * sections={[
49
+ * {
50
+ * items: [
51
+ * { label: 'Edit', icon: EditIcon, onclick: () => edit() },
52
+ * { label: 'Duplicate', icon: CopyIcon, onclick: () => duplicate() }
53
+ * ]
54
+ * },
55
+ * { items: [{ label: 'Delete', icon: TrashIcon, onclick: () => remove() }] }
56
+ * ]}
57
+ * />
58
+ * ```
59
+ */
24
60
  export type DropdownMenuProps = {
61
+ /** Bindable open state. @default false */
25
62
  open?: boolean;
63
+ /** Ordered sections of items. A divider renders between adjacent sections. */
26
64
  sections: DropSection[];
65
+ /** Trigger button label. */
27
66
  label?: string;
67
+ /** Trigger button icon (rendered instead of or alongside `label`). */
28
68
  icon?: Component;
69
+ /** Classes on the outer positioned wrapper. */
29
70
  containerClass?: ClassValue;
71
+ /** Classes on each item button. */
30
72
  itemClass?: ClassValue;
73
+ /** Classes on the trigger button. */
31
74
  class?: ClassValue;
32
75
  size?: VariantSizes;
33
76
  disabled?: boolean;
77
+ /**
78
+ * Panel placement anchored to the trigger's corner:
79
+ * - `'bottom-right'` (default) — typical dropdown to the right
80
+ * - `'bottom-left'` — dropdown aligned to the trigger's left edge
81
+ * - `'top-right'` / `'top-left'` — upward-opening (use when near page bottom)
82
+ */
34
83
  position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
84
+ /**
85
+ * Explicit panel width. Accepts any CSS value (`'200px'`, `'12rem'`,
86
+ * `'100%'`). @default auto-sized to content
87
+ */
35
88
  width?: string;
89
+ /** Optional header shown above the first section. */
36
90
  header?: DropHeaderConfig;
37
91
  testId?: string;
38
92
  };
93
+ /** Single option in a `<Select>` list. */
39
94
  export type SelectItem = {
95
+ /** Visible text. */
40
96
  label: string;
97
+ /** Underlying form value. */
41
98
  value: string;
42
99
  disabled?: boolean;
100
+ /** Optional icon rendered next to the label. */
43
101
  icon?: Component;
102
+ /** Short helper text shown below the label in the dropdown. */
44
103
  description?: string;
104
+ /**
105
+ * Group name — items with the same `group` are rendered together
106
+ * under a group heading. Items without `group` render at the top.
107
+ */
45
108
  group?: string;
46
109
  };
110
+ /**
111
+ * Props for `<Select>` — a controlled single- or multi-select form input
112
+ * with optional search. For free-typing + filter UX prefer `<ComboBox>`;
113
+ * for a short list of radio-style options use `<RadioGroup>`.
114
+ *
115
+ * @example
116
+ * ```svelte
117
+ * <Select
118
+ * items={[
119
+ * { value: 'draft', label: 'Draft' },
120
+ * { value: 'published', label: 'Published' },
121
+ * { value: 'archived', label: 'Archived' }
122
+ * ]}
123
+ * bind:value={status}
124
+ * />
125
+ * ```
126
+ *
127
+ * @example
128
+ * ```svelte
129
+ * <!-- Multi-select with server-side search -->
130
+ * <Select
131
+ * multiple
132
+ * searchable
133
+ * items={[]}
134
+ * onsearch={async (q) => await api.searchTags(q)}
135
+ * bind:value={selectedTags}
136
+ * />
137
+ * ```
138
+ */
47
139
  export type SelectProps = {
140
+ /** Static list of options. Omit + pair with `onsearch` for server-side search. */
48
141
  items?: SelectItem[];
142
+ /** Bindable selected value (string) or values (`multiple` mode). */
49
143
  value?: string | string[];
144
+ /** Allow selecting multiple items. Changes `value` to `string[]`. @default false */
50
145
  multiple?: boolean;
51
146
  placeholder?: string;
147
+ /** Show a search input at the top of the dropdown. @default false */
52
148
  searchable?: boolean;
53
149
  disabled?: boolean;
54
150
  size?: VariantSizes;
@@ -58,21 +154,39 @@ export type SelectProps = {
58
154
  itemClass?: ClassValue;
59
155
  triggerClass?: ClassValue;
60
156
  searchInputClass?: ClassValue;
157
+ /** Show a × when a value is selected. @default true */
61
158
  clearable?: boolean;
159
+ /** Icon rendered in the trigger (e.g. search icon for an "Add filter" menu). */
62
160
  icon?: Component;
63
161
  iconClass?: ClassValue;
64
162
  errors?: string[];
163
+ /** Fires on selection change. Value shape depends on `multiple`. */
65
164
  onselect?: ({ value }: {
66
165
  value: string | string[];
67
166
  }) => void;
167
+ /** Fires when the dropdown panel opens. */
68
168
  onopen?: () => void;
169
+ /** Fires when the dropdown panel closes. */
69
170
  onclose?: () => void;
70
171
  testId?: string;
172
+ /**
173
+ * Server-side search handler. When set, local filtering is bypassed
174
+ * and this is called (debounced by `debounceMs`) whenever the user
175
+ * types. Return items to display.
176
+ */
71
177
  onsearch?: (query: string) => SelectItem[] | Promise<SelectItem[]>;
178
+ /** Debounce delay for `onsearch`. @default 200 */
72
179
  debounceMs?: number;
180
+ /** Minimum query length before `onsearch` fires. @default 0 */
73
181
  minSearchLength?: number;
182
+ /** Text shown while an async `onsearch` is in flight. @default 'Loading…' */
74
183
  loadingText?: string;
184
+ /** Text shown when the item list is empty. @default 'No results' */
75
185
  emptyText?: string;
186
+ /**
187
+ * Per-item custom rendering. Receives the item and its state flags.
188
+ * Use for rich options (avatars, two-line cards, etc.).
189
+ */
76
190
  itemSnippet?: Snippet<[SelectItem, {
77
191
  highlighted: boolean;
78
192
  selected: boolean;
@@ -30,7 +30,7 @@ export declare const dropdownMenu: import("tailwind-variants").TVReturnType<{
30
30
  headerTitle: string;
31
31
  headerSubtitle: string;
32
32
  };
33
- base: {
33
+ md: {
34
34
  trigger: string;
35
35
  item: string;
36
36
  itemIcon: string;
@@ -113,7 +113,7 @@ export declare const dropdownMenu: import("tailwind-variants").TVReturnType<{
113
113
  headerTitle: string;
114
114
  headerSubtitle: string;
115
115
  };
116
- base: {
116
+ md: {
117
117
  trigger: string;
118
118
  item: string;
119
119
  itemIcon: string;
@@ -196,7 +196,7 @@ export declare const dropdownMenu: import("tailwind-variants").TVReturnType<{
196
196
  headerTitle: string;
197
197
  headerSubtitle: string;
198
198
  };
199
- base: {
199
+ md: {
200
200
  trigger: string;
201
201
  item: string;
202
202
  itemIcon: string;
@@ -44,7 +44,7 @@ export const dropdownMenu = tv({
44
44
  headerTitle: 'text-xs',
45
45
  headerSubtitle: 'text-xs'
46
46
  },
47
- [Size.BASE]: {
47
+ [Size.MD]: {
48
48
  trigger: 'px-3 py-2 text-sm',
49
49
  item: 'px-4 py-2 text-sm',
50
50
  itemIcon: 'mr-3 size-5',
@@ -88,7 +88,7 @@ export const dropdownMenu = tv({
88
88
  },
89
89
  defaultVariants: {
90
90
  position: 'bottom-right',
91
- size: Size.BASE,
91
+ size: Size.MD,
92
92
  isOpen: false,
93
93
  iconOnly: false
94
94
  }
@@ -14,7 +14,7 @@ export declare const selectTV: import("tailwind-variants").TVReturnType<{
14
14
  item: string;
15
15
  base: string;
16
16
  };
17
- base: {
17
+ md: {
18
18
  trigger: string;
19
19
  triggerIcon: string;
20
20
  container: string;
@@ -85,7 +85,7 @@ export declare const selectTV: import("tailwind-variants").TVReturnType<{
85
85
  item: string;
86
86
  base: string;
87
87
  };
88
- base: {
88
+ md: {
89
89
  trigger: string;
90
90
  triggerIcon: string;
91
91
  container: string;
@@ -156,7 +156,7 @@ export declare const selectTV: import("tailwind-variants").TVReturnType<{
156
156
  item: string;
157
157
  base: string;
158
158
  };
159
- base: {
159
+ md: {
160
160
  trigger: string;
161
161
  triggerIcon: string;
162
162
  container: string;
@@ -32,7 +32,7 @@ export const selectTV = tv({
32
32
  item: 'px-2.5 py-1.5 text-xs',
33
33
  base: 'min-w-32'
34
34
  },
35
- [Size.BASE]: {
35
+ [Size.MD]: {
36
36
  trigger: 'h-10 px-3 py-2 text-base gap-2',
37
37
  triggerIcon: 'h-4 w-4',
38
38
  container: 'max-h-60',
@@ -80,7 +80,7 @@ export const selectTV = tv({
80
80
  }
81
81
  },
82
82
  defaultVariants: {
83
- size: 'base',
83
+ size: 'md',
84
84
  disabled: false,
85
85
  multiple: false,
86
86
  error: false
@@ -8,7 +8,7 @@
8
8
  let {
9
9
  title,
10
10
  description,
11
- size = Size.BASE,
11
+ size = Size.MD,
12
12
  class: className = '',
13
13
  icon,
14
14
  action,
@@ -1,12 +1,43 @@
1
1
  import type { ClassValue } from 'tailwind-variants';
2
2
  import type { Snippet } from 'svelte';
3
- export type EmptyStateSize = 'sm' | 'base' | 'lg' | 'xl';
3
+ /** Density variants specific to EmptyState. */
4
+ export type EmptyStateSize = 'sm' | 'md' | 'lg' | 'xl';
5
+ /**
6
+ * Props for `<EmptyState>` — centered placeholder shown when a list,
7
+ * table, or panel has no content to display yet. Put an illustration,
8
+ * a clear title, a helpful description, and a primary action that
9
+ * breaks the blank-page anxiety.
10
+ *
11
+ * @example
12
+ * ```svelte
13
+ * <EmptyState
14
+ * title="No customers yet"
15
+ * description="Once you import or create a customer they'll appear here."
16
+ * >
17
+ * {#snippet icon()}
18
+ * <svg viewBox="0 0 24 24">…</svg>
19
+ * {/snippet}
20
+ * {#snippet action()}
21
+ * <Button color="primary" onclick={create}>Add customer</Button>
22
+ * {/snippet}
23
+ * </EmptyState>
24
+ * ```
25
+ */
4
26
  export type EmptyStateProps = {
27
+ /** Heading — keep short, focus on what's missing. */
5
28
  title: string;
29
+ /** One-sentence explanation of what's missing and what to do. */
6
30
  description?: string;
31
+ /** @default 'md' */
7
32
  size?: EmptyStateSize;
8
33
  class?: ClassValue;
34
+ /**
35
+ * Icon/illustration snippet. Unlike other components that take an icon
36
+ * `Component`, EmptyState uses a `Snippet` so consumers can inline SVGs
37
+ * or illustrations with arbitrary markup (common empty-state pattern).
38
+ */
9
39
  icon?: Snippet;
40
+ /** Primary action snippet — usually a single Button. */
10
41
  action?: Snippet;
11
42
  testId?: string;
12
43
  };
@@ -6,7 +6,7 @@ export declare const emptyState: import("tailwind-variants").TVReturnType<{
6
6
  title: string;
7
7
  description: string;
8
8
  };
9
- base: {
9
+ md: {
10
10
  wrapper: string;
11
11
  iconWrapper: string;
12
12
  title: string;
@@ -39,7 +39,7 @@ export declare const emptyState: import("tailwind-variants").TVReturnType<{
39
39
  title: string;
40
40
  description: string;
41
41
  };
42
- base: {
42
+ md: {
43
43
  wrapper: string;
44
44
  iconWrapper: string;
45
45
  title: string;
@@ -72,7 +72,7 @@ export declare const emptyState: import("tailwind-variants").TVReturnType<{
72
72
  title: string;
73
73
  description: string;
74
74
  };
75
- base: {
75
+ md: {
76
76
  wrapper: string;
77
77
  iconWrapper: string;
78
78
  title: string;
@@ -16,7 +16,7 @@ export const emptyState = tv({
16
16
  title: 'text-sm',
17
17
  description: 'text-xs'
18
18
  },
19
- [Size.BASE]: {
19
+ [Size.MD]: {
20
20
  wrapper: 'gap-3 p-8',
21
21
  iconWrapper: 'h-10 w-10',
22
22
  title: 'text-base',
@@ -37,6 +37,6 @@ export const emptyState = tv({
37
37
  }
38
38
  },
39
39
  defaultVariants: {
40
- size: Size.BASE
40
+ size: Size.MD
41
41
  }
42
42
  });
@@ -4,6 +4,9 @@
4
4
  import Button from '../../button/Button.svelte';
5
5
  import Spinner from '../spinner/Spinner.svelte';
6
6
  import { Size, Color } from '../../variants.js';
7
+ import { fade } from 'svelte/transition';
8
+ import { flip } from 'svelte/animate';
9
+ import { quintOut } from 'svelte/easing';
7
10
  import type { FileUploadProps, StagedFile } from '../../index.js';
8
11
 
9
12
  let {
@@ -330,6 +333,8 @@
330
333
  class={cn('flex items-center gap-3 px-3 py-2', status === 'success' && 'opacity-60')}
331
334
  data-fileupload-row=""
332
335
  data-status={status}
336
+ transition:fade={{ duration: 300, easing: quintOut }}
337
+ animate:flip={{ duration: 350, easing: quintOut }}
333
338
  >
334
339
  {#if status === 'ready'}
335
340
  <span
@@ -24,6 +24,54 @@ export interface StagedFile {
24
24
  /** Optional error message rendered under the file name while status='error'. */
25
25
  error?: string;
26
26
  }
27
+ /**
28
+ * Props for `<FileUpload>` — a flexible drag-and-drop zone that supports
29
+ * single-file pick, multi-file staging, and "rich mode" with per-file
30
+ * upload progress.
31
+ *
32
+ * **Mode selection** is via `maxFiles`:
33
+ * - `maxFiles=1` (default) → single-file: `onfiles` fires immediately.
34
+ * - `maxFiles>1` (omit `bind:files`) → simple multi-file staging.
35
+ * - `maxFiles>1` + `bind:files` + `clearAfterUpload={false}` → rich mode
36
+ * with per-file status icons + progress bars driven by the consumer.
37
+ *
38
+ * For browsing files already on a remote storage (S3, GDrive), use
39
+ * `<FileBrowser>` instead.
40
+ *
41
+ * @example
42
+ * ```svelte
43
+ * <!-- Simple single-file -->
44
+ * <FileUpload allowedMimeTypes={['.csv']} onfiles={(files) => upload(files[0])} />
45
+ * ```
46
+ *
47
+ * @example
48
+ * ```svelte
49
+ * <!-- Multi-file rich mode with per-row progress -->
50
+ * <script lang="ts">
51
+ * let files = $state<StagedFile[]>([]);
52
+ * async function handleFiles(toUpload: File[]) {
53
+ * for (const file of toUpload) {
54
+ * const item = files.find(f => f.file === file)!;
55
+ * item.status = 'uploading';
56
+ * try {
57
+ * await api.upload(file, (pct) => (item.progress = pct));
58
+ * item.status = 'success';
59
+ * } catch (err) {
60
+ * item.status = 'error';
61
+ * item.error = String(err);
62
+ * }
63
+ * }
64
+ * }
65
+ * </script>
66
+ *
67
+ * <FileUpload
68
+ * maxFiles={10}
69
+ * bind:files
70
+ * clearAfterUpload={false}
71
+ * onfiles={handleFiles}
72
+ * />
73
+ * ```
74
+ */
27
75
  export interface FileUploadProps {
28
76
  /**
29
77
  * Array of allowed file MIME types or extensions.
@@ -119,12 +167,23 @@ export interface FileUploadProps {
119
167
  /** Optional snippet rendered above the dropzone (for titles, selects, banners). */
120
168
  header?: Snippet;
121
169
  }
170
+ /**
171
+ * Props for `<FilesPreview>` — renders a list of already-uploaded files
172
+ * with per-row delete affordance. Pair with `<FileUpload>` to show the
173
+ * "files uploaded so far" beneath the dropzone.
174
+ */
122
175
  export interface FilePreviewProps {
123
176
  files: UploadedFile[];
177
+ /** Fires when the user clicks the × on a file row. */
124
178
  ondelete?: (fileId: string, index: number) => void;
125
179
  class?: ClassValue;
126
180
  testId?: string;
127
181
  }
182
+ /**
183
+ * A file that has already been uploaded to your backend (vs `StagedFile`,
184
+ * which represents a file in flight). Field naming mirrors common
185
+ * server-returned shapes — adapt as needed.
186
+ */
128
187
  export interface UploadedFile {
129
188
  FileID: string;
130
189
  OriginalFilename: string;
@@ -4,7 +4,35 @@
4
4
  import type { ClassValue } from 'tailwind-variants';
5
5
 
6
6
  /**
7
- * Pagination component props
7
+ * Props for `<Pagination>` page navigation controls. Used standalone
8
+ * for client-driven lists, or automatically inside `<Table>` when
9
+ * `pagination` is on.
10
+ *
11
+ * `currentPage` is a regular (non-bindable) prop — pass it in and
12
+ * update via `onpagechange`, or set `internalState={true}` and omit
13
+ * `currentPage` to let the component track pages itself. Most apps
14
+ * prefer external state so the URL or a store can drive it.
15
+ *
16
+ * @example
17
+ * ```svelte
18
+ * <Pagination
19
+ * currentPage={page}
20
+ * totalItems={42}
21
+ * pageSize={10}
22
+ * onpagechange={(p) => goto(`?page=${p}`)}
23
+ * />
24
+ * ```
25
+ *
26
+ * @example
27
+ * ```svelte
28
+ * <!-- Compact "Page 3 of 7" mode for tight footers -->
29
+ * <Pagination
30
+ * {totalItems}
31
+ * pageSize={20}
32
+ * template="compact"
33
+ * showFirstLast={false}
34
+ * />
35
+ * ```
8
36
  */
9
37
  export interface PaginationProps {
10
38
  /** Current page number (1-indexed). If not provided, component manages state internally. */
@@ -14,13 +42,13 @@
14
42
  /** Number of items per page */
15
43
  pageSize?: number;
16
44
  /** Callback when page changes */
17
- onPageChange?: (page: number) => void;
45
+ onpagechange?: (page: number) => void;
18
46
  /** Callback when page size changes */
19
- onPageSizeChange?: (pageSize: number) => void;
47
+ onpagesizechange?: (pageSize: number) => void;
20
48
  /** Callback when first page is clicked */
21
- onFirstPage?: () => void;
49
+ onfirstpage?: () => void;
22
50
  /** Callback when last page is clicked */
23
- onLastPage?: () => void;
51
+ onlastpage?: () => void;
24
52
  /** Whether pagination controls are disabled */
25
53
  disabled?: boolean;
26
54
  /** Show page size selector */
@@ -62,10 +90,10 @@
62
90
  currentPage: externalCurrentPage,
63
91
  totalItems,
64
92
  pageSize: externalPageSize,
65
- onPageChange,
66
- onPageSizeChange,
67
- onFirstPage,
68
- onLastPage,
93
+ onpagechange,
94
+ onpagesizechange,
95
+ onfirstpage,
96
+ onlastpage,
69
97
  disabled = false,
70
98
  showPageSize = false,
71
99
  pageSizeOptions = [5, 10, 25, 50, 100],
@@ -140,7 +168,7 @@
140
168
  if (internalState && externalCurrentPage === undefined) {
141
169
  internalCurrentPage = page;
142
170
  }
143
- onPageChange?.(page);
171
+ onpagechange?.(page);
144
172
  }
145
173
  }
146
174
 
@@ -150,8 +178,8 @@
150
178
  if (internalState && externalCurrentPage === undefined) {
151
179
  internalCurrentPage = targetPage;
152
180
  }
153
- onPageChange?.(targetPage);
154
- onFirstPage?.();
181
+ onpagechange?.(targetPage);
182
+ onfirstpage?.();
155
183
  }
156
184
  }
157
185
 
@@ -161,8 +189,8 @@
161
189
  if (internalState && externalCurrentPage === undefined) {
162
190
  internalCurrentPage = targetPage;
163
191
  }
164
- onPageChange?.(targetPage);
165
- onLastPage?.();
192
+ onpagechange?.(targetPage);
193
+ onlastpage?.();
166
194
  }
167
195
  }
168
196
 
@@ -172,7 +200,7 @@
172
200
  if (internalState && externalCurrentPage === undefined) {
173
201
  internalCurrentPage = targetPage;
174
202
  }
175
- onPageChange?.(targetPage);
203
+ onpagechange?.(targetPage);
176
204
  }
177
205
  }
178
206
 
@@ -182,7 +210,7 @@
182
210
  if (internalState && externalCurrentPage === undefined) {
183
211
  internalCurrentPage = targetPage;
184
212
  }
185
- onPageChange?.(targetPage);
213
+ onpagechange?.(targetPage);
186
214
  }
187
215
  }
188
216
 
@@ -203,14 +231,14 @@
203
231
  if (internalState && externalCurrentPage === undefined) {
204
232
  internalCurrentPage = adjustedPage;
205
233
  }
206
- onPageChange?.(adjustedPage);
234
+ onpagechange?.(adjustedPage);
207
235
  }
208
236
 
209
237
  // Update page size
210
238
  if (internalState && externalPageSize === undefined) {
211
239
  internalPageSize = newPageSize;
212
240
  }
213
- onPageSizeChange?.(newPageSize);
241
+ onpagesizechange?.(newPageSize);
214
242
  }
215
243
 
216
244
  /**
@@ -246,8 +274,10 @@
246
274
  const shouldShowPagination = $derived(!hideWhenNoItems || validTotalItems > 0);
247
275
  const shouldShowControls = $derived(!hideWhenSinglePage || totalPages > 1);
248
276
 
249
- // Default classes using ripple-ui design system
250
- const defaultWrapperClass = 'flex items-center justify-between p-4';
277
+ // Default classes using ripple-ui design system.
278
+ // `flex-wrap` + `gap-y-3` stacks the info row and button row on narrow
279
+ // viewports instead of squeezing them onto one line.
280
+ const defaultWrapperClass = 'flex flex-wrap items-center justify-between gap-y-3 p-4';
251
281
  const defaultInfoClass = 'text-default-500 text-sm';
252
282
  const defaultButtonClass =
253
283
  'relative inline-flex items-center rounded-md px-2 py-1 text-sm font-medium';
@@ -293,7 +323,9 @@
293
323
  {/if}
294
324
 
295
325
  {#if shouldShowControls && showNavigation}
296
- <div class="flex items-center gap-1">
326
+ <!-- `flex-wrap` lets page-number buttons wrap to a second row
327
+ rather than overflowing the container on narrow viewports. -->
328
+ <div class="flex flex-wrap items-center gap-1">
297
329
  {#if showFirstLast}
298
330
  <button
299
331
  onclick={firstPage}