@makolabs/ripple 1.7.11 → 1.9.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 (135) hide show
  1. package/README.md +16 -0
  2. package/dist/adapters/ai/OpenAIAdapter.d.ts +8 -1
  3. package/dist/adapters/ai/OpenAIAdapter.js +2 -2
  4. package/dist/adapters/storage/BaseAdapter.js +2 -2
  5. package/dist/adapters/storage/S3Adapter.js +1 -6
  6. package/dist/adapters/storage/types.d.ts +3 -3
  7. package/dist/ai/AIChatInterface.svelte +0 -1
  8. package/dist/ai/ai-chat-interface.d.ts +21 -22
  9. package/dist/ai/ai-types.d.ts +44 -0
  10. package/dist/ai/ai-types.js +1 -0
  11. package/dist/ai/content-detector.js +0 -1
  12. package/dist/button/Button.svelte +9 -2
  13. package/dist/button/button-types.d.ts +25 -0
  14. package/dist/button/button-types.js +1 -0
  15. package/dist/button/button.d.ts +39 -40
  16. package/dist/charts/Chart.svelte +11 -23
  17. package/dist/charts/chart-types.d.ts +137 -0
  18. package/dist/charts/chart-types.js +1 -0
  19. package/dist/drawer/Drawer.svelte +57 -23
  20. package/dist/drawer/drawer-types.d.ts +33 -0
  21. package/dist/drawer/drawer-types.js +1 -0
  22. package/dist/drawer/drawer.d.ts +18 -19
  23. package/dist/elements/accordion/Accordion.svelte +39 -18
  24. package/dist/elements/accordion/accordion-types.d.ts +29 -0
  25. package/dist/elements/accordion/accordion-types.js +1 -0
  26. package/dist/elements/accordion/accordion.d.ts +21 -22
  27. package/dist/elements/alert/Alert.svelte +20 -8
  28. package/dist/elements/badge/Badge.svelte +5 -2
  29. package/dist/elements/badge/badge-types.d.ts +11 -0
  30. package/dist/elements/badge/badge-types.js +1 -0
  31. package/dist/elements/badge/badge.d.ts +39 -40
  32. package/dist/elements/dropdown/Dropdown.svelte +18 -2
  33. package/dist/elements/dropdown/Select.svelte +17 -5
  34. package/dist/elements/dropdown/dropdown-types.d.ts +68 -0
  35. package/dist/elements/dropdown/dropdown-types.js +1 -0
  36. package/dist/elements/dropdown/dropdown.d.ts +18 -19
  37. package/dist/elements/dropdown/select.d.ts +18 -19
  38. package/dist/elements/file-upload/file-upload-types.d.ts +68 -0
  39. package/dist/elements/file-upload/file-upload-types.js +1 -0
  40. package/dist/elements/pagination/Pagination.svelte +15 -2
  41. package/dist/elements/pagination/Pagination.svelte.d.ts +1 -0
  42. package/dist/elements/progress/progress-types.d.ts +22 -0
  43. package/dist/elements/progress/progress-types.js +1 -0
  44. package/dist/elements/timeline/timeline-types.d.ts +11 -0
  45. package/dist/elements/timeline/timeline-types.js +1 -0
  46. package/dist/filters/filter-types.d.ts +24 -0
  47. package/dist/filters/filter-types.js +1 -0
  48. package/dist/forms/Checkbox.svelte +16 -4
  49. package/dist/forms/Form.svelte +0 -2
  50. package/dist/forms/Input.svelte +19 -5
  51. package/dist/forms/NumberInput.svelte +8 -1
  52. package/dist/forms/RadioInputs.svelte +14 -5
  53. package/dist/forms/Slider.svelte +6 -4
  54. package/dist/forms/Toggle.svelte +67 -29
  55. package/dist/forms/form-types.d.ts +168 -0
  56. package/dist/forms/form-types.js +1 -0
  57. package/dist/forms/slider.d.ts +72 -10
  58. package/dist/forms/slider.js +21 -0
  59. package/dist/header/Breadcrumbs.svelte +47 -24
  60. package/dist/header/PageHeader.svelte +12 -2
  61. package/dist/header/breadcrumbs.d.ts +47 -39
  62. package/dist/header/header-types.d.ts +43 -0
  63. package/dist/header/header-types.js +1 -0
  64. package/dist/helper/deprecation.d.ts +14 -0
  65. package/dist/helper/deprecation.js +24 -0
  66. package/dist/helper/testid.d.ts +10 -0
  67. package/dist/helper/testid.js +17 -0
  68. package/dist/index.d.ts +37 -1007
  69. package/dist/index.js +38 -14
  70. package/dist/layout/activity-list/activity-list-types.d.ts +30 -0
  71. package/dist/layout/activity-list/activity-list-types.js +1 -0
  72. package/dist/layout/activity-list/activity-list.d.ts +21 -22
  73. package/dist/layout/card/Card.svelte +19 -5
  74. package/dist/layout/card/card-types.d.ts +43 -0
  75. package/dist/layout/card/card-types.js +1 -0
  76. package/dist/layout/card/card.d.ts +21 -22
  77. package/dist/layout/card/metric-card.d.ts +3 -3
  78. package/dist/layout/card/ranked-card.d.ts +2 -1
  79. package/dist/layout/navbar/Navbar.svelte +14 -16
  80. package/dist/layout/navbar/navbar-types.d.ts +19 -0
  81. package/dist/layout/navbar/navbar-types.js +1 -0
  82. package/dist/layout/navbar/navbar.d.ts +19 -19
  83. package/dist/layout/sidebar/Sidebar.svelte +6 -3
  84. package/dist/layout/sidebar/sidebar-types.d.ts +59 -0
  85. package/dist/layout/sidebar/sidebar-types.js +1 -0
  86. package/dist/layout/table/Table.svelte +237 -303
  87. package/dist/layout/table/table-types.d.ts +82 -0
  88. package/dist/layout/table/table-types.js +1 -0
  89. package/dist/layout/table/table.d.ts +24 -25
  90. package/dist/layout/tabs/Tab.svelte +3 -1
  91. package/dist/layout/tabs/TabGroup.svelte +7 -4
  92. package/dist/layout/tabs/tabs-types.d.ts +43 -0
  93. package/dist/layout/tabs/tabs-types.js +1 -0
  94. package/dist/layout/tabs/tabs.d.ts +39 -40
  95. package/dist/modal/Modal.svelte +124 -21
  96. package/dist/modal/modal-types.d.ts +34 -0
  97. package/dist/modal/modal-types.js +1 -0
  98. package/dist/modal/modal.d.ts +18 -19
  99. package/dist/modal/modal.js +2 -2
  100. package/dist/types/echarts.d.ts +27 -0
  101. package/dist/user-management/UserModal.svelte +1 -1
  102. package/dist/user-management/UserTable.svelte +3 -3
  103. package/dist/user-management/UserViewModal.svelte +2 -2
  104. package/dist/user-management/user-management-types.d.ts +156 -0
  105. package/dist/user-management/user-management-types.js +1 -0
  106. package/dist/variants.d.ts +13 -13
  107. package/package.json +9 -7
  108. package/dist/ai/AIChatInterfaceTestWrapper.svelte +0 -26
  109. package/dist/ai/AIChatInterfaceTestWrapper.svelte.d.ts +0 -17
  110. package/dist/button/ButtonTestWrapper.svelte +0 -10
  111. package/dist/button/ButtonTestWrapper.svelte.d.ts +0 -7
  112. package/dist/drawer/DrawerTestWrapper.svelte +0 -19
  113. package/dist/drawer/DrawerTestWrapper.svelte.d.ts +0 -9
  114. package/dist/elements/accordion/AccordionTestWrapper.svelte +0 -21
  115. package/dist/elements/accordion/AccordionTestWrapper.svelte.d.ts +0 -10
  116. package/dist/elements/badge/BadgeTestWrapper.svelte +0 -14
  117. package/dist/elements/badge/BadgeTestWrapper.svelte.d.ts +0 -9
  118. package/dist/forms/CheckboxTestWrapper.svelte +0 -8
  119. package/dist/forms/CheckboxTestWrapper.svelte.d.ts +0 -4
  120. package/dist/forms/InputTestWrapper.svelte +0 -8
  121. package/dist/forms/InputTestWrapper.svelte.d.ts +0 -4
  122. package/dist/forms/ToggleTestWrapper.svelte +0 -8
  123. package/dist/forms/ToggleTestWrapper.svelte.d.ts +0 -7
  124. package/dist/layout/card/CardTestWrapper.svelte +0 -15
  125. package/dist/layout/card/CardTestWrapper.svelte.d.ts +0 -7
  126. package/dist/modal/ModalTestWrapper.svelte +0 -20
  127. package/dist/modal/ModalTestWrapper.svelte.d.ts +0 -8
  128. package/dist/user-management/UserManagementTestWrapper.svelte +0 -32
  129. package/dist/user-management/UserManagementTestWrapper.svelte.d.ts +0 -12
  130. package/dist/user-management/UserModalTestWrapper.svelte +0 -22
  131. package/dist/user-management/UserModalTestWrapper.svelte.d.ts +0 -7
  132. package/dist/user-management/UserTableTestWrapper.svelte +0 -41
  133. package/dist/user-management/UserTableTestWrapper.svelte.d.ts +0 -7
  134. package/dist/user-management/UserViewModalTestWrapper.svelte +0 -22
  135. package/dist/user-management/UserViewModalTestWrapper.svelte.d.ts +0 -7
@@ -1,7 +1,8 @@
1
1
  <script lang="ts">
2
2
  import { cn } from '../../helper/cls.js';
3
+ import { buildTestId } from '../../helper/testid.js';
3
4
  import { Color } from '../../variants.js';
4
- import type { AlertProps } from '../../index.js';
5
+ import type { AlertProps, VariantColors } from '../../index.js';
5
6
 
6
7
  let {
7
8
  title,
@@ -9,30 +10,40 @@
9
10
  color = Color.DEFAULT,
10
11
  onclose,
11
12
  footer,
12
- class: className = ''
13
+ icon: Icon,
14
+ class: className = '',
15
+ testId
13
16
  }: AlertProps = $props();
14
17
 
15
18
  function handleClose() {
16
19
  onclose?.();
17
20
  }
18
21
 
19
- const colorClasses = {
22
+ const colorClasses: Record<VariantColors, string> = {
20
23
  [Color.DEFAULT]: 'bg-default-50 border-default-200 text-default-800',
21
24
  [Color.PRIMARY]: 'bg-primary-50 border-primary-200 text-primary-800',
25
+ [Color.SECONDARY]: 'bg-secondary-50 border-secondary-200 text-secondary-800',
26
+ [Color.INFO]: 'bg-info-50 border-info-200 text-info-800',
22
27
  [Color.SUCCESS]: 'bg-success-50 border-success-200 text-success-800',
23
28
  [Color.WARNING]: 'bg-warning-50 border-warning-200 text-warning-800',
24
- [Color.DANGER]: 'bg-danger-50 border-danger-200 text-danger-800',
25
- [Color.INFO]: 'bg-info-50 border-info-200 text-info-800'
29
+ [Color.DANGER]: 'bg-danger-50 border-danger-200 text-danger-800'
26
30
  };
27
31
  </script>
28
32
 
29
- <div class={cn('relative rounded-lg border p-4', colorClasses[color], className)}>
33
+ <div
34
+ role="alert"
35
+ class={cn('relative rounded-lg border p-4', colorClasses[color], className)}
36
+ data-testid={buildTestId('alert', undefined, testId)}
37
+ >
30
38
  <div class="flex items-start justify-between gap-4">
39
+ {#if Icon}
40
+ <Icon class="mt-0.5 h-5 w-5 shrink-0" />
41
+ {/if}
31
42
  <div class="flex-1">
32
43
  {#if title}
33
- <h4 class="font-semibold">{title}</h4>
44
+ <h4 class="font-semibold" data-testid={buildTestId('alert', 'title', testId)}>{title}</h4>
34
45
  {/if}
35
- <p class="text-sm">{message}</p>
46
+ <p class="text-sm" data-testid={buildTestId('alert', 'message', testId)}>{message}</p>
36
47
  </div>
37
48
  {#if onclose}
38
49
  <button
@@ -40,6 +51,7 @@
40
51
  class="hover:bg-default-200/20 flex-shrink-0 cursor-pointer rounded-md p-1"
41
52
  onclick={handleClose}
42
53
  aria-label="Close alert"
54
+ data-testid={buildTestId('alert', 'close', testId)}
43
55
  >
44
56
  <svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
45
57
  <path
@@ -1,5 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { cn } from '../../helper/cls.js';
3
+ import { buildTestId } from '../../helper/testid.js';
3
4
  import { badge } from './badge.js';
4
5
  import { Size, Color } from '../../variants.js';
5
6
  import type { BadgeProps } from '../../index.js';
@@ -9,7 +10,8 @@
9
10
  color = Color.DEFAULT,
10
11
  class: className = '',
11
12
  children,
12
- onclose: onClose
13
+ onclose: onClose,
14
+ testId
13
15
  }: BadgeProps = $props();
14
16
 
15
17
  const { base } = $derived(
@@ -27,7 +29,7 @@
27
29
  }
28
30
  </script>
29
31
 
30
- <span class={baseClass}>
32
+ <span class={baseClass} data-testid={buildTestId('badge', undefined, testId)}>
31
33
  {@render children()}
32
34
  {#if onClose}
33
35
  <button
@@ -37,6 +39,7 @@
37
39
  title="Close"
38
40
  tabindex="0"
39
41
  type="button"
42
+ data-testid={buildTestId('badge', 'close', testId)}
40
43
  >
41
44
  <svg
42
45
  xmlns="http://www.w3.org/2000/svg"
@@ -0,0 +1,11 @@
1
+ import type { ClassValue } from 'tailwind-variants';
2
+ import type { Snippet } from 'svelte';
3
+ import type { VariantColors, VariantSizes } from '../../index.js';
4
+ export type BadgeProps = {
5
+ size?: VariantSizes;
6
+ color?: VariantColors;
7
+ class?: ClassValue;
8
+ children: Snippet;
9
+ onclose?: (event: MouseEvent) => void;
10
+ testId?: string;
11
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -1,57 +1,56 @@
1
- import { Size, Color } from '../../variants.js';
2
1
  export declare const badge: import("tailwind-variants").TVReturnType<{
3
2
  size: {
4
- [Size.XS]: {
3
+ xs: {
5
4
  base: string;
6
5
  icon: string;
7
6
  };
8
- [Size.SM]: {
7
+ sm: {
9
8
  base: string;
10
9
  icon: string;
11
10
  };
12
- [Size.BASE]: {
11
+ base: {
13
12
  base: string;
14
13
  icon: string;
15
14
  };
16
- [Size.LG]: {
15
+ lg: {
17
16
  base: string;
18
17
  icon: string;
19
18
  };
20
- [Size.XL]: {
19
+ xl: {
21
20
  base: string;
22
21
  icon: string;
23
22
  };
24
- [Size.XXL]: {
23
+ "2xl": {
25
24
  base: string;
26
25
  icon: string;
27
26
  };
28
27
  };
29
28
  color: {
30
- [Color.DEFAULT]: {
29
+ default: {
31
30
  base: string;
32
31
  icon: string;
33
32
  };
34
- [Color.PRIMARY]: {
33
+ primary: {
35
34
  base: string;
36
35
  icon: string;
37
36
  };
38
- [Color.SECONDARY]: {
37
+ secondary: {
39
38
  base: string;
40
39
  icon: string;
41
40
  };
42
- [Color.SUCCESS]: {
41
+ success: {
43
42
  base: string;
44
43
  icon: string;
45
44
  };
46
- [Color.WARNING]: {
45
+ warning: {
47
46
  base: string;
48
47
  icon: string;
49
48
  };
50
- [Color.DANGER]: {
49
+ danger: {
51
50
  base: string;
52
51
  icon: string;
53
52
  };
54
- [Color.INFO]: {
53
+ info: {
55
54
  base: string;
56
55
  icon: string;
57
56
  };
@@ -61,57 +60,57 @@ export declare const badge: import("tailwind-variants").TVReturnType<{
61
60
  icon: string;
62
61
  }, undefined, {
63
62
  size: {
64
- [Size.XS]: {
63
+ xs: {
65
64
  base: string;
66
65
  icon: string;
67
66
  };
68
- [Size.SM]: {
67
+ sm: {
69
68
  base: string;
70
69
  icon: string;
71
70
  };
72
- [Size.BASE]: {
71
+ base: {
73
72
  base: string;
74
73
  icon: string;
75
74
  };
76
- [Size.LG]: {
75
+ lg: {
77
76
  base: string;
78
77
  icon: string;
79
78
  };
80
- [Size.XL]: {
79
+ xl: {
81
80
  base: string;
82
81
  icon: string;
83
82
  };
84
- [Size.XXL]: {
83
+ "2xl": {
85
84
  base: string;
86
85
  icon: string;
87
86
  };
88
87
  };
89
88
  color: {
90
- [Color.DEFAULT]: {
89
+ default: {
91
90
  base: string;
92
91
  icon: string;
93
92
  };
94
- [Color.PRIMARY]: {
93
+ primary: {
95
94
  base: string;
96
95
  icon: string;
97
96
  };
98
- [Color.SECONDARY]: {
97
+ secondary: {
99
98
  base: string;
100
99
  icon: string;
101
100
  };
102
- [Color.SUCCESS]: {
101
+ success: {
103
102
  base: string;
104
103
  icon: string;
105
104
  };
106
- [Color.WARNING]: {
105
+ warning: {
107
106
  base: string;
108
107
  icon: string;
109
108
  };
110
- [Color.DANGER]: {
109
+ danger: {
111
110
  base: string;
112
111
  icon: string;
113
112
  };
114
- [Color.INFO]: {
113
+ info: {
115
114
  base: string;
116
115
  icon: string;
117
116
  };
@@ -121,57 +120,57 @@ export declare const badge: import("tailwind-variants").TVReturnType<{
121
120
  icon: string;
122
121
  }, import("tailwind-variants").TVReturnType<{
123
122
  size: {
124
- [Size.XS]: {
123
+ xs: {
125
124
  base: string;
126
125
  icon: string;
127
126
  };
128
- [Size.SM]: {
127
+ sm: {
129
128
  base: string;
130
129
  icon: string;
131
130
  };
132
- [Size.BASE]: {
131
+ base: {
133
132
  base: string;
134
133
  icon: string;
135
134
  };
136
- [Size.LG]: {
135
+ lg: {
137
136
  base: string;
138
137
  icon: string;
139
138
  };
140
- [Size.XL]: {
139
+ xl: {
141
140
  base: string;
142
141
  icon: string;
143
142
  };
144
- [Size.XXL]: {
143
+ "2xl": {
145
144
  base: string;
146
145
  icon: string;
147
146
  };
148
147
  };
149
148
  color: {
150
- [Color.DEFAULT]: {
149
+ default: {
151
150
  base: string;
152
151
  icon: string;
153
152
  };
154
- [Color.PRIMARY]: {
153
+ primary: {
155
154
  base: string;
156
155
  icon: string;
157
156
  };
158
- [Color.SECONDARY]: {
157
+ secondary: {
159
158
  base: string;
160
159
  icon: string;
161
160
  };
162
- [Color.SUCCESS]: {
161
+ success: {
163
162
  base: string;
164
163
  icon: string;
165
164
  };
166
- [Color.WARNING]: {
165
+ warning: {
167
166
  base: string;
168
167
  icon: string;
169
168
  };
170
- [Color.DANGER]: {
169
+ danger: {
171
170
  base: string;
172
171
  icon: string;
173
172
  };
174
- [Color.INFO]: {
173
+ info: {
175
174
  base: string;
176
175
  icon: string;
177
176
  };
@@ -6,6 +6,7 @@
6
6
  import { Size } from '../../variants.js';
7
7
  import Portal from '../../utils/Portal.svelte';
8
8
  import { resolve } from '$app/paths';
9
+ import { buildTestId } from '../../helper/testid.js';
9
10
 
10
11
  let {
11
12
  sections = [],
@@ -19,7 +20,8 @@
19
20
  disabled = false,
20
21
  position = 'bottom-left',
21
22
  width = 'w-56',
22
- header
23
+ header,
24
+ testId
23
25
  }: DropdownMenuProps = $props();
24
26
 
25
27
  // Determine if we're in icon-only mode
@@ -134,6 +136,16 @@
134
136
  if (item.onclick) item.onclick();
135
137
  isOpen = false;
136
138
  }
139
+
140
+ /**
141
+ * Compute cumulative item counts per section so we can derive flat indices.
142
+ */
143
+ const sectionOffsets = $derived(
144
+ sections.reduce<number[]>((acc, sec, i) => {
145
+ acc.push(i === 0 ? 0 : acc[i - 1] + sections[i - 1].items.length);
146
+ return acc;
147
+ }, [])
148
+ );
137
149
  </script>
138
150
 
139
151
  <svelte:window onclick={handleClickOutside} />
@@ -148,6 +160,7 @@
148
160
  class={triggerClass_}
149
161
  onclick={handleToggle}
150
162
  {disabled}
163
+ data-testid={buildTestId('dropdown', 'trigger', testId)}
151
164
  >
152
165
  {#if label}
153
166
  {label}
@@ -183,6 +196,7 @@
183
196
  aria-labelledby="menu-button"
184
197
  style={dropdownStyles}
185
198
  transition:fly={{ duration: 150, y: 5, opacity: 0 }}
199
+ data-testid={buildTestId('dropdown', 'menu', testId)}
186
200
  >
187
201
  {#if header}
188
202
  <button class={headerClass_} onclick={header.onclick} aria-label="Header Actions">
@@ -202,12 +216,14 @@
202
216
  {#each sections as section_, sectionIndex (sectionIndex)}
203
217
  <div class={sectionClass}>
204
218
  {#each section_.items as menuItem, itemIndex (itemIndex)}
219
+ {@const flatIndex = sectionOffsets[sectionIndex] + itemIndex}
205
220
  {@const itemProps = {
206
221
  class: itemClass_,
207
222
  role: 'menuitem',
208
223
  tabindex: -1,
209
224
  id: `menu-item-${sectionIndex}-${itemIndex}`,
210
- 'data-active': menuItem.active
225
+ 'data-active': menuItem.active,
226
+ 'data-testid': buildTestId('dropdown', 'item', testId, flatIndex)
211
227
  }}
212
228
  {#if menuItem.href}
213
229
  <a href={resolve(menuItem.href as `/`)} {...itemProps}>
@@ -1,6 +1,7 @@
1
1
  <script lang="ts">
2
2
  import { tick } from 'svelte';
3
3
  import { cn } from '../../helper/cls.js';
4
+ import { buildTestId } from '../../helper/testid.js';
4
5
  import { selectTV } from './select.js';
5
6
  import type { SelectItem, SelectProps } from '../../index.js';
6
7
  import Badge from '../badge/Badge.svelte';
@@ -25,7 +26,8 @@
25
26
  triggerClass = '', // recently, just now
26
27
  onselect = () => {},
27
28
  onopen = () => {},
28
- onclose = () => {}
29
+ onclose = () => {},
30
+ testId
29
31
  }: SelectProps = $props();
30
32
 
31
33
  let open = $state(false);
@@ -34,6 +36,8 @@
34
36
  let searchInputRef = $state<HTMLInputElement | null>(null);
35
37
  let highlightedIndex = $state(-1);
36
38
 
39
+ const selectId = crypto.randomUUID().slice(0, 8);
40
+
37
41
  // Convert value to array for internal processing if multiple is true
38
42
  const valueArray = $derived.by(() => {
39
43
  if (multiple) {
@@ -199,8 +203,9 @@
199
203
  class={triggerClass_}
200
204
  aria-disabled={disabled}
201
205
  aria-haspopup="listbox"
202
- aria-labelledby="select-label"
206
+ aria-labelledby="{selectId}-label"
203
207
  data-state={open ? 'open' : 'closed'}
208
+ data-testid={buildTestId('select', 'trigger', testId)}
204
209
  >
205
210
  <button
206
211
  type="button"
@@ -219,11 +224,11 @@
219
224
  </Badge>
220
225
  {/each}
221
226
  {:else if !multiple && selectedItem}
222
- <span id="select-label" class="flex-1 truncate text-left">
227
+ <span id="{selectId}-label" class="flex-1 truncate text-left">
223
228
  {selectedItem.label}
224
229
  </span>
225
230
  {:else}
226
- <span id="select-label" class="text-default-500 px-1">
231
+ <span id="{selectId}-label" class="text-default-500 px-1">
227
232
  {placeholder}
228
233
  </span>
229
234
  {/if}
@@ -251,7 +256,12 @@
251
256
 
252
257
  {#if open}
253
258
  <Portal target={labelRef}>
254
- <div class={containerClass_} role="listbox" aria-labelledby="select-label">
259
+ <div
260
+ class={containerClass_}
261
+ role="listbox"
262
+ aria-labelledby="{selectId}-label"
263
+ data-testid={buildTestId('select', 'list', testId)}
264
+ >
255
265
  {#if searchable}
256
266
  <div class={searchInputClass_}>
257
267
  <svg
@@ -273,6 +283,7 @@
273
283
  class="ring-0 outline-0"
274
284
  placeholder="Search..."
275
285
  aria-label="Search select options"
286
+ data-testid={buildTestId('select', 'search', testId)}
276
287
  />
277
288
  </div>
278
289
  {/if}
@@ -296,6 +307,7 @@
296
307
  data-selected={valueArray.includes(item.value)}
297
308
  data-highlighted={index === highlightedIndex}
298
309
  data-index={index}
310
+ data-testid={buildTestId('select', 'option', testId, index)}
299
311
  >
300
312
  <span class="flex w-full items-center justify-between">
301
313
  <span class="flex items-center gap-2 overflow-hidden">
@@ -0,0 +1,68 @@
1
+ import type { ClassValue } from 'tailwind-variants';
2
+ import type { Snippet } from 'svelte';
3
+ import type { Component } from 'svelte';
4
+ import type { VariantSizes } from '../../index.js';
5
+ export type DropdownItem = {
6
+ label: string;
7
+ href?: `/${string}`;
8
+ icon?: Component;
9
+ onclick?: () => void;
10
+ active?: boolean;
11
+ };
12
+ export type DropSection = {
13
+ items: DropdownItem[];
14
+ };
15
+ export type DropHeaderConfig = {
16
+ title?: string;
17
+ subtitle?: string;
18
+ content?: Snippet<[]>;
19
+ class?: ClassValue;
20
+ titleClass?: ClassValue;
21
+ subtitleClass?: ClassValue;
22
+ onclick?: () => void;
23
+ };
24
+ export type DropdownMenuProps = {
25
+ open?: boolean;
26
+ sections: DropSection[];
27
+ label?: string;
28
+ icon?: Component;
29
+ containerClass?: ClassValue;
30
+ itemClass?: ClassValue;
31
+ class?: ClassValue;
32
+ size?: VariantSizes;
33
+ disabled?: boolean;
34
+ position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
35
+ width?: string;
36
+ header?: DropHeaderConfig;
37
+ testId?: string;
38
+ };
39
+ export type SelectItem = {
40
+ label: string;
41
+ value: string;
42
+ disabled?: boolean;
43
+ icon?: Component;
44
+ };
45
+ export type SelectProps = {
46
+ items: SelectItem[];
47
+ value?: string | string[];
48
+ multiple?: boolean;
49
+ placeholder?: string;
50
+ searchable?: boolean;
51
+ disabled?: boolean;
52
+ size?: VariantSizes;
53
+ class?: ClassValue;
54
+ containerClass?: ClassValue;
55
+ listClass?: ClassValue;
56
+ itemClass?: ClassValue;
57
+ triggerClass?: ClassValue;
58
+ searchInputClass?: ClassValue;
59
+ clearable?: boolean;
60
+ icon?: Component;
61
+ iconClass?: ClassValue;
62
+ onselect?: ({ value }: {
63
+ value: string | string[];
64
+ }) => void;
65
+ onopen?: () => void;
66
+ onclose?: () => void;
67
+ testId?: string;
68
+ };
@@ -0,0 +1 @@
1
+ export {};