@reshape-biotech/design-system 1.2.5 → 1.2.7

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 (175) hide show
  1. package/README.md +3 -1
  2. package/dist/app.css +97 -97
  3. package/dist/components/activity/Activity.stories.svelte +104 -104
  4. package/dist/components/activity/Activity.svelte +112 -112
  5. package/dist/components/avatar/Avatar.stories.svelte +23 -23
  6. package/dist/components/avatar/Avatar.svelte +54 -54
  7. package/dist/components/banner/Banner.stories.svelte +105 -105
  8. package/dist/components/banner/Banner.svelte +42 -42
  9. package/dist/components/button/Button.stories.svelte +61 -61
  10. package/dist/components/button/Button.svelte +95 -95
  11. package/dist/components/card/Card.stories.svelte +112 -112
  12. package/dist/components/card/Card.svelte +18 -18
  13. package/dist/components/checkbox/Checkbox.stories.svelte +8 -8
  14. package/dist/components/checkbox/Checkbox.svelte +17 -17
  15. package/dist/components/collapsible/Collapsible.stories.svelte +26 -26
  16. package/dist/components/collapsible/components/collapsible-content.svelte +20 -20
  17. package/dist/components/collapsible/components/collapsible-trigger.svelte +12 -12
  18. package/dist/components/combobox/Combobox.stories.svelte +412 -412
  19. package/dist/components/combobox/components/combobox-add.svelte +8 -8
  20. package/dist/components/combobox/components/combobox-content.svelte +39 -39
  21. package/dist/components/combobox/components/combobox-indicator.svelte +1 -1
  22. package/dist/components/datepicker/DatePicker.stories.svelte +196 -196
  23. package/dist/components/datepicker/DatePicker.svelte +173 -173
  24. package/dist/components/divider/Divider.stories.svelte +7 -7
  25. package/dist/components/divider/Divider.svelte +9 -9
  26. package/dist/components/drawer/Drawer.stories.svelte +51 -51
  27. package/dist/components/drawer/Drawer.svelte +33 -33
  28. package/dist/components/drawer/DrawerLabel.svelte +10 -10
  29. package/dist/components/dropdown/Dropdown.stories.svelte +210 -210
  30. package/dist/components/dropdown/Dropdown.svelte +57 -57
  31. package/dist/components/dropdown/components/DropdownContent.svelte +16 -16
  32. package/dist/components/dropdown/components/DropdownMenu.svelte +10 -10
  33. package/dist/components/dropdown/components/DropdownTrigger.svelte +37 -37
  34. package/dist/components/dropdown/components/OutlinedButton.svelte +9 -9
  35. package/dist/components/empty-content/EmptyContent.stories.svelte +38 -38
  36. package/dist/components/empty-content/EmptyContent.svelte +12 -12
  37. package/dist/components/graphs/bar-chart/BarChart.stories.svelte +91 -91
  38. package/dist/components/graphs/bar-chart/BarChart.svelte +147 -147
  39. package/dist/components/graphs/bar-chart/StackedBarChart.stories.svelte +57 -57
  40. package/dist/components/graphs/bar-chart/StackedBarChart.svelte +198 -199
  41. package/dist/components/graphs/chart/Chart.stories.svelte +96 -96
  42. package/dist/components/graphs/chart/Chart.svelte +207 -207
  43. package/dist/components/graphs/line/LineChart.stories.svelte +138 -138
  44. package/dist/components/graphs/line/LineChart.svelte +140 -142
  45. package/dist/components/graphs/matrix/Matrix.stories.svelte +117 -117
  46. package/dist/components/graphs/matrix/Matrix.svelte +141 -141
  47. package/dist/components/graphs/multiline/MultiLineChart.stories.svelte +168 -168
  48. package/dist/components/graphs/multiline/MultiLineChart.svelte +236 -236
  49. package/dist/components/graphs/scatterplot/Scatterplot.stories.svelte +84 -84
  50. package/dist/components/graphs/scatterplot/Scatterplot.svelte +302 -302
  51. package/dist/components/graphs/utils/duration.d.ts +1 -0
  52. package/dist/components/graphs/utils/duration.js +33 -0
  53. package/dist/components/graphs/utils/tooltipFormatter.js +1 -1
  54. package/dist/components/icon-button/IconButton.stories.svelte +64 -64
  55. package/dist/components/icon-button/IconButton.svelte +88 -88
  56. package/dist/components/icons/AnalysisIcon.stories.svelte +18 -18
  57. package/dist/components/icons/AnalysisIcon.svelte +96 -96
  58. package/dist/components/icons/Icon.stories.svelte +111 -111
  59. package/dist/components/icons/Icon.svelte +17 -17
  60. package/dist/components/icons/PrincipalIcon.svelte +59 -59
  61. package/dist/components/icons/custom/Halo.svelte +31 -31
  62. package/dist/components/icons/custom/Well.svelte +27 -27
  63. package/dist/components/icons/index.d.ts +3 -2
  64. package/dist/components/icons/index.js +3 -1
  65. package/dist/components/image/Image.svelte +42 -42
  66. package/dist/components/input/Input.stories.svelte +55 -55
  67. package/dist/components/input/Input.svelte +121 -121
  68. package/dist/components/label/Label.stories.svelte +18 -18
  69. package/dist/components/label/Label.svelte +11 -11
  70. package/dist/components/list/List.stories.svelte +84 -84
  71. package/dist/components/list/List.svelte +20 -20
  72. package/dist/components/logo/Logo.stories.svelte +15 -15
  73. package/dist/components/logo/Logo.svelte +30 -30
  74. package/dist/components/manual-cfu-counter/ManualCFUCounter.stories.svelte +102 -102
  75. package/dist/components/manual-cfu-counter/ManualCFUCounter.svelte +557 -565
  76. package/dist/components/manual-cfu-counter/test/ManualCFUCounterTestWrapper.svelte +11 -11
  77. package/dist/components/markdown/Markdown.stories.svelte +10 -10
  78. package/dist/components/markdown/Markdown.svelte +6 -6
  79. package/dist/components/modal/Modal.stories.svelte +29 -29
  80. package/dist/components/modal/Modal.svelte +71 -71
  81. package/dist/components/multi-cfu-counter/MultiCFUCounter.stories.svelte +215 -0
  82. package/dist/components/multi-cfu-counter/MultiCFUCounter.stories.svelte.d.ts +3 -0
  83. package/dist/components/multi-cfu-counter/MultiCFUCounter.svelte +662 -0
  84. package/dist/components/multi-cfu-counter/MultiCFUCounter.svelte.d.ts +32 -0
  85. package/dist/components/multi-cfu-counter/index.d.ts +1 -0
  86. package/dist/components/multi-cfu-counter/index.js +1 -0
  87. package/dist/components/multi-cfu-counter/test/MultiCFUCounterTestWrapper.svelte +28 -0
  88. package/dist/components/multi-cfu-counter/test/MultiCFUCounterTestWrapper.svelte.d.ts +20 -0
  89. package/dist/components/notification-popup/NotificationPopup.stories.svelte +18 -18
  90. package/dist/components/notification-popup/NotificationPopup.svelte +26 -26
  91. package/dist/components/notifications/Notifications.stories.svelte +101 -101
  92. package/dist/components/notifications/Notifications.svelte +9 -9
  93. package/dist/components/pill/Pill.stories.svelte +8 -8
  94. package/dist/components/pill/Pill.svelte +27 -27
  95. package/dist/components/progress-circle/ProgressCircle.stories.svelte +8 -8
  96. package/dist/components/progress-circle/ProgressCircle.svelte +54 -54
  97. package/dist/components/required-status-indicator/RequiredStatusIndicator.stories.svelte +18 -18
  98. package/dist/components/required-status-indicator/RequiredStatusIndicator.svelte +14 -14
  99. package/dist/components/segmented-control-buttons/ControlButton.svelte +36 -36
  100. package/dist/components/segmented-control-buttons/SegmentedControlButtons.stories.svelte +35 -35
  101. package/dist/components/segmented-control-buttons/SegmentedControlButtons.svelte +13 -13
  102. package/dist/components/select/Select.stories.svelte +77 -77
  103. package/dist/components/select/Select.svelte +114 -114
  104. package/dist/components/select-new/Select.stories.svelte +188 -188
  105. package/dist/components/select-new/components/Group.svelte +17 -17
  106. package/dist/components/select-new/components/MultiSelectTrigger.svelte +57 -57
  107. package/dist/components/select-new/components/SelectContent.svelte +22 -22
  108. package/dist/components/select-new/components/SelectGroupHeading.svelte +10 -10
  109. package/dist/components/select-new/components/SelectItem.svelte +25 -25
  110. package/dist/components/select-new/components/SelectTrigger.svelte +38 -38
  111. package/dist/components/sjsf-wrappers/SjsfNumberInputWrapper.svelte +76 -76
  112. package/dist/components/sjsf-wrappers/SjsfNumberInputWrapper.svelte.d.ts +1 -1
  113. package/dist/components/sjsf-wrappers/SjsfTextInputWrapper.svelte +53 -53
  114. package/dist/components/sjsf-wrappers/SjsfTextInputWrapper.svelte.d.ts +1 -1
  115. package/dist/components/sjsf-wrappers/sjsfCustomTheme.js +1 -1
  116. package/dist/components/skeleton-loader/SkeletonLoader.stories.svelte +32 -32
  117. package/dist/components/skeleton-loader/SkeletonLoader.svelte +10 -10
  118. package/dist/components/skeleton-loader/StatcardSkeleton.svelte +9 -9
  119. package/dist/components/skeleton-loader/components/Skeleton.svelte +7 -7
  120. package/dist/components/skeleton-loader/components/SkeletonImage.svelte +12 -12
  121. package/dist/components/slider/Slider.stories.svelte +23 -23
  122. package/dist/components/slider/Slider.svelte +107 -107
  123. package/dist/components/spinner/Spinner.stories.svelte +8 -8
  124. package/dist/components/spinner/Spinner.svelte +18 -18
  125. package/dist/components/stat-card/StatCard.stories.svelte +26 -26
  126. package/dist/components/stat-card/StatCard.svelte +128 -128
  127. package/dist/components/status-badge/StatusBadge.stories.svelte +365 -365
  128. package/dist/components/status-badge/StatusBadge.svelte +54 -54
  129. package/dist/components/stepper/Stepper.stories.svelte +219 -219
  130. package/dist/components/stepper/components/stepper-root.svelte +12 -12
  131. package/dist/components/stepper/components/stepper-step.svelte +83 -83
  132. package/dist/components/table/Table.stories.svelte +87 -87
  133. package/dist/components/table/Table.svelte +32 -32
  134. package/dist/components/table/components/TBody.svelte +7 -7
  135. package/dist/components/table/components/THead.svelte +7 -7
  136. package/dist/components/table/components/Td.svelte +8 -8
  137. package/dist/components/table/components/Th.svelte +8 -8
  138. package/dist/components/table/components/Tr.svelte +11 -11
  139. package/dist/components/tabs/Tabs.stories.svelte +20 -20
  140. package/dist/components/tabs/Tabs.svelte +8 -8
  141. package/dist/components/tabs/components/Content.svelte +8 -8
  142. package/dist/components/tabs/components/Tab.svelte +14 -14
  143. package/dist/components/tabs/components/Tabs.svelte +7 -7
  144. package/dist/components/tag/Tag.stories.svelte +57 -57
  145. package/dist/components/tag/Tag.svelte +95 -95
  146. package/dist/components/textarea/Textarea.stories.svelte +70 -70
  147. package/dist/components/textarea/Textarea.svelte +76 -76
  148. package/dist/components/toast/Toast.stories.svelte +204 -204
  149. package/dist/components/toast/Toast.svelte +53 -53
  150. package/dist/components/toggle/Toggle.stories.svelte +9 -9
  151. package/dist/components/toggle/Toggle.svelte +53 -53
  152. package/dist/components/toggle-icon-button/ToggleIconButton.stories.svelte +152 -152
  153. package/dist/components/toggle-icon-button/ToggleIconButton.svelte +99 -99
  154. package/dist/components/tooltip/Tooltip.stories.svelte +105 -105
  155. package/dist/components/tooltip/Tooltip.svelte +26 -26
  156. package/dist/fonts/index.js +1 -1
  157. package/dist/index.d.ts +4 -1
  158. package/dist/index.js +5 -1
  159. package/dist/notifications.d.ts +1 -4
  160. package/dist/notifications.js +1 -1
  161. package/dist/styles.d.ts +1 -0
  162. package/dist/styles.js +4 -0
  163. package/dist/tailwind-safelist.js +406 -398
  164. package/dist/tailwind.preset.d.ts +4 -0
  165. package/dist/tailwind.preset.js +10 -10
  166. package/dist/tokens/colors.d.ts +246 -0
  167. package/dist/tokens/colors.js +139 -0
  168. package/dist/tokens/index.d.ts +3 -0
  169. package/dist/tokens/index.js +5 -0
  170. package/dist/tokens/typography.d.ts +48 -0
  171. package/dist/tokens/typography.js +48 -0
  172. package/dist/tokens.d.ts +16 -252
  173. package/dist/tokens.js +33 -164
  174. package/dist/types/fonts.d.ts +2 -2
  175. package/package.json +398 -78
@@ -1,442 +1,442 @@
1
1
  <script module lang="ts">
2
- import { defineMeta } from '@storybook/addon-svelte-csf';
3
- import { userEvent, within } from '@storybook/test';
4
- import { Root as ComboboxRootForMeta } from './index';
5
- import * as Combobox from './index';
6
- import { Icon } from '../icons';
7
- import IconButton from '../icon-button/IconButton.svelte';
8
- import Divider from '../divider/Divider.svelte';
9
- import Tag from '../tag/Tag.svelte';
10
- import Button from '../button/Button.svelte';
11
-
12
- const { Story } = defineMeta({
13
- component: ComboboxRootForMeta,
14
- title: 'Design System/Combobox',
15
- tags: ['autodocs'],
16
- parameters: {
17
- design: {
18
- type: 'figma',
19
- url: 'https://www.figma.com/design/VHTMNdy8PAXAMx43edNZGW/%F0%9F%92%A0--Reshape-Design-System%3A-V1?node-id=9-3294&t=sCuBI8dX6K6NjNR6-0'
20
- }
21
- }
22
- });
23
-
24
- const fruits = [
25
- { value: 'mango', label: 'Mango' },
26
- { value: 'watermelon', label: 'Watermelon' },
27
- { value: 'apple', label: 'Apple' },
28
- { value: 'pineapple', label: 'Pineapple' },
29
- { value: 'orange', label: 'Orange' },
30
- { value: 'grape', label: 'Grape' },
31
- { value: 'strawberry', label: 'Strawberry' },
32
- { value: 'banana', label: 'Banana' },
33
- { value: 'kiwi', label: 'Kiwi' },
34
- { value: 'peach', label: 'Peach' },
35
- { value: 'cherry', label: 'Cherry' },
36
- { value: 'blueberry', label: 'Blueberry' },
37
- { value: 'raspberry', label: 'Raspberry' },
38
- { value: 'blackberry', label: 'Blackberry' },
39
- { value: 'plum', label: 'Plum' },
40
- { value: 'apricot', label: 'Apricot' },
41
- { value: 'pear', label: 'Pear' },
42
- { value: 'grapefruit', label: 'Grapefruit' }
43
- ];
44
-
45
- const categories = [
46
- { value: 'citrus', label: 'Citrus', items: ['orange', 'grapefruit', 'lemon'] },
47
- {
48
- value: 'berries',
49
- label: 'Berries',
50
- items: ['strawberry', 'blueberry', 'raspberry', 'blackberry']
51
- },
52
- { value: 'tropical', label: 'Tropical', items: ['mango', 'pineapple', 'banana', 'kiwi'] },
53
- { value: 'stone', label: 'Stone Fruits', items: ['peach', 'cherry', 'plum', 'apricot'] },
54
- { value: 'other', label: 'Other', items: ['apple', 'pear', 'watermelon', 'grape'] }
55
- ];
56
-
57
- let searchValue = $state('');
58
- let searchValueSingle = $state('');
59
- let searchValueGrouped = $state('');
60
- let searchValueCustom = $state('');
61
-
62
- let selected = $state<string[]>([]);
63
- let selectedSingle = $state<string>('');
64
- let selectedGrouped = $state<string[]>([]);
65
- let selectedCustom = $state<string[]>([]);
66
-
67
- const filteredFruits = $derived(
68
- searchValue === ''
69
- ? fruits
70
- : fruits.filter((fruit) => fruit.label.toLowerCase().includes(searchValue.toLowerCase()))
71
- );
72
-
73
- const filteredFruitsSingle = $derived(
74
- searchValueSingle === ''
75
- ? fruits
76
- : fruits.filter((fruit) =>
77
- fruit.label.toLowerCase().includes(searchValueSingle.toLowerCase())
78
- )
79
- );
80
-
81
- const filteredFruitsGrouped = $derived(
82
- searchValueGrouped === ''
83
- ? fruits
84
- : fruits.filter((fruit) =>
85
- fruit.label.toLowerCase().includes(searchValueGrouped.toLowerCase())
86
- )
87
- );
88
-
89
- const filteredFruitsCustom = $derived(
90
- searchValueCustom === ''
91
- ? fruits
92
- : fruits.filter((fruit) =>
93
- fruit.label.toLowerCase().includes(searchValueCustom.toLowerCase())
94
- )
95
- );
96
-
97
- const exactMatch = $derived(
98
- filteredFruits.find((fruit) => fruit.value.toLowerCase() === searchValue.toLowerCase())
99
- );
100
-
101
- const exactMatchCustom = $derived(
102
- filteredFruitsCustom.find(
103
- (fruit) => fruit.value.toLowerCase() === searchValueCustom.toLowerCase()
104
- )
105
- );
106
-
107
- let customAnchor = $state<HTMLElement>(null!);
108
- let customAnchorButton = $state<HTMLElement>(null!);
109
- let customAnchorSingle = $state<HTMLElement>(null!);
110
- let customAnchorGrouped = $state<HTMLElement>(null!);
111
- let customAnchorCustom = $state<HTMLElement>(null!);
2
+ import { defineMeta } from '@storybook/addon-svelte-csf';
3
+ import { userEvent, within } from '@storybook/test';
4
+ import { Root as ComboboxRootForMeta } from './index';
5
+ import * as Combobox from './index';
6
+ import { Icon } from '../icons';
7
+ import IconButton from '../icon-button/IconButton.svelte';
8
+ import Divider from '../divider/Divider.svelte';
9
+ import Tag from '../tag/Tag.svelte';
10
+ import Button from '../button/Button.svelte';
11
+
12
+ const { Story } = defineMeta({
13
+ component: ComboboxRootForMeta,
14
+ title: 'Design System/Combobox',
15
+ tags: ['autodocs'],
16
+ parameters: {
17
+ design: {
18
+ type: 'figma',
19
+ url: 'https://www.figma.com/design/VHTMNdy8PAXAMx43edNZGW/%F0%9F%92%A0--Reshape-Design-System%3A-V1?node-id=9-3294&t=sCuBI8dX6K6NjNR6-0',
20
+ },
21
+ },
22
+ });
23
+
24
+ const fruits = [
25
+ { value: 'mango', label: 'Mango' },
26
+ { value: 'watermelon', label: 'Watermelon' },
27
+ { value: 'apple', label: 'Apple' },
28
+ { value: 'pineapple', label: 'Pineapple' },
29
+ { value: 'orange', label: 'Orange' },
30
+ { value: 'grape', label: 'Grape' },
31
+ { value: 'strawberry', label: 'Strawberry' },
32
+ { value: 'banana', label: 'Banana' },
33
+ { value: 'kiwi', label: 'Kiwi' },
34
+ { value: 'peach', label: 'Peach' },
35
+ { value: 'cherry', label: 'Cherry' },
36
+ { value: 'blueberry', label: 'Blueberry' },
37
+ { value: 'raspberry', label: 'Raspberry' },
38
+ { value: 'blackberry', label: 'Blackberry' },
39
+ { value: 'plum', label: 'Plum' },
40
+ { value: 'apricot', label: 'Apricot' },
41
+ { value: 'pear', label: 'Pear' },
42
+ { value: 'grapefruit', label: 'Grapefruit' },
43
+ ];
44
+
45
+ const categories = [
46
+ { value: 'citrus', label: 'Citrus', items: ['orange', 'grapefruit', 'lemon'] },
47
+ {
48
+ value: 'berries',
49
+ label: 'Berries',
50
+ items: ['strawberry', 'blueberry', 'raspberry', 'blackberry'],
51
+ },
52
+ { value: 'tropical', label: 'Tropical', items: ['mango', 'pineapple', 'banana', 'kiwi'] },
53
+ { value: 'stone', label: 'Stone Fruits', items: ['peach', 'cherry', 'plum', 'apricot'] },
54
+ { value: 'other', label: 'Other', items: ['apple', 'pear', 'watermelon', 'grape'] },
55
+ ];
56
+
57
+ let searchValue = $state('');
58
+ let searchValueSingle = $state('');
59
+ let searchValueGrouped = $state('');
60
+ let searchValueCustom = $state('');
61
+
62
+ let selected = $state<string[]>([]);
63
+ let selectedSingle = $state<string>('');
64
+ let selectedGrouped = $state<string[]>([]);
65
+ let selectedCustom = $state<string[]>([]);
66
+
67
+ const filteredFruits = $derived(
68
+ searchValue === ''
69
+ ? fruits
70
+ : fruits.filter((fruit) => fruit.label.toLowerCase().includes(searchValue.toLowerCase()))
71
+ );
72
+
73
+ const filteredFruitsSingle = $derived(
74
+ searchValueSingle === ''
75
+ ? fruits
76
+ : fruits.filter((fruit) =>
77
+ fruit.label.toLowerCase().includes(searchValueSingle.toLowerCase())
78
+ )
79
+ );
80
+
81
+ const filteredFruitsGrouped = $derived(
82
+ searchValueGrouped === ''
83
+ ? fruits
84
+ : fruits.filter((fruit) =>
85
+ fruit.label.toLowerCase().includes(searchValueGrouped.toLowerCase())
86
+ )
87
+ );
88
+
89
+ const filteredFruitsCustom = $derived(
90
+ searchValueCustom === ''
91
+ ? fruits
92
+ : fruits.filter((fruit) =>
93
+ fruit.label.toLowerCase().includes(searchValueCustom.toLowerCase())
94
+ )
95
+ );
96
+
97
+ const exactMatch = $derived(
98
+ filteredFruits.find((fruit) => fruit.value.toLowerCase() === searchValue.toLowerCase())
99
+ );
100
+
101
+ const exactMatchCustom = $derived(
102
+ filteredFruitsCustom.find(
103
+ (fruit) => fruit.value.toLowerCase() === searchValueCustom.toLowerCase()
104
+ )
105
+ );
106
+
107
+ let customAnchor = $state<HTMLElement>(null!);
108
+ let customAnchorButton = $state<HTMLElement>(null!);
109
+ let customAnchorSingle = $state<HTMLElement>(null!);
110
+ let customAnchorGrouped = $state<HTMLElement>(null!);
111
+ let customAnchorCustom = $state<HTMLElement>(null!);
112
112
  </script>
113
113
 
114
114
  <Story name="Multiple Selection" asChild>
115
- <Combobox.Root
116
- onOpenChange={(o) => {
117
- if (!o) searchValue = '';
118
- }}
119
- type="multiple"
120
- name="favoriteFruit"
121
- items={filteredFruits}
122
- bind:value={selected}
123
- >
124
- <div class="flex gap-2">
125
- {#each selected as fruit}
126
- <Tag>
127
- {fruit}
128
- </Tag>
129
- {/each}
130
- </div>
131
- <Combobox.Trigger>
132
- <div bind:this={customAnchor}>
133
- <IconButton rounded={false}>
134
- <Icon iconName="Plus" />
135
- </IconButton>
136
- </div>
137
- </Combobox.Trigger>
138
- <Combobox.Content {customAnchor} class="flex flex-col justify-between">
139
- <div>
140
- <Combobox.Input
141
- placeholder="Search a fruit"
142
- oninput={(e: Event) => (searchValue = (e.target as HTMLInputElement).value)}
143
- autofocus
144
- />
145
- <Divider />
146
- </div>
147
- <div class="flex flex-grow flex-col">
148
- {#if filteredFruits.length > 0}
149
- <Combobox.Group>
150
- <Combobox.GroupHeading>Fruits</Combobox.GroupHeading>
151
- {#each filteredFruits as fruit (fruit.value)}
152
- <Combobox.Item value={fruit.value} label={fruit.label}>
153
- {#snippet children({ selected })}
154
- {fruit.label}
155
- {#if selected}
156
- <Combobox.Indicator />
157
- {/if}
158
- {/snippet}
159
- </Combobox.Item>
160
- {:else}
161
- <span class="block px-5 py-2 text-sm text-muted-foreground"> No results found </span>
162
- {/each}
163
- </Combobox.Group>
164
- {/if}
165
- </div>
166
- {#if !exactMatch && searchValue !== ''}
167
- <Divider />
168
-
169
- <Combobox.Add
170
- onclick={() => {
171
- selected.push(searchValue);
172
- fruits.push({ value: searchValue, label: searchValue });
173
- searchValue = '';
174
- }}
175
- >
176
- <p>Add new fruit</p>
177
- </Combobox.Add>
178
- {/if}
179
- </Combobox.Content>
180
- </Combobox.Root>
115
+ <Combobox.Root
116
+ onOpenChange={(o) => {
117
+ if (!o) searchValue = '';
118
+ }}
119
+ type="multiple"
120
+ name="favoriteFruit"
121
+ items={filteredFruits}
122
+ bind:value={selected}
123
+ >
124
+ <div class="flex gap-2">
125
+ {#each selected as fruit}
126
+ <Tag>
127
+ {fruit}
128
+ </Tag>
129
+ {/each}
130
+ </div>
131
+ <Combobox.Trigger>
132
+ <div bind:this={customAnchor}>
133
+ <IconButton rounded={false}>
134
+ <Icon iconName="Plus" />
135
+ </IconButton>
136
+ </div>
137
+ </Combobox.Trigger>
138
+ <Combobox.Content {customAnchor} class="flex flex-col justify-between">
139
+ <div>
140
+ <Combobox.Input
141
+ placeholder="Search a fruit"
142
+ oninput={(e: Event) => (searchValue = (e.target as HTMLInputElement).value)}
143
+ autofocus
144
+ />
145
+ <Divider />
146
+ </div>
147
+ <div class="flex flex-grow flex-col">
148
+ {#if filteredFruits.length > 0}
149
+ <Combobox.Group>
150
+ <Combobox.GroupHeading>Fruits</Combobox.GroupHeading>
151
+ {#each filteredFruits as fruit (fruit.value)}
152
+ <Combobox.Item value={fruit.value} label={fruit.label}>
153
+ {#snippet children({ selected })}
154
+ {fruit.label}
155
+ {#if selected}
156
+ <Combobox.Indicator />
157
+ {/if}
158
+ {/snippet}
159
+ </Combobox.Item>
160
+ {:else}
161
+ <span class="block px-5 py-2 text-sm text-muted-foreground"> No results found </span>
162
+ {/each}
163
+ </Combobox.Group>
164
+ {/if}
165
+ </div>
166
+ {#if !exactMatch && searchValue !== ''}
167
+ <Divider />
168
+
169
+ <Combobox.Add
170
+ onclick={() => {
171
+ selected.push(searchValue);
172
+ fruits.push({ value: searchValue, label: searchValue });
173
+ searchValue = '';
174
+ }}
175
+ >
176
+ <p>Add new fruit</p>
177
+ </Combobox.Add>
178
+ {/if}
179
+ </Combobox.Content>
180
+ </Combobox.Root>
181
181
  </Story>
182
182
 
183
183
  <Story name="Single Selection" asChild>
184
- <Combobox.Root
185
- onOpenChange={(o) => {
186
- if (!o) searchValueSingle = '';
187
- }}
188
- type="single"
189
- name="singleFruit"
190
- items={filteredFruitsSingle}
191
- bind:value={selectedSingle}
192
- >
193
- <Combobox.Trigger>
194
- <div bind:this={customAnchorSingle}>
195
- <Button variant="secondary" size="sm">
196
- {selectedSingle ? selectedSingle : 'Select a fruit'}
197
- </Button>
198
- </div>
199
- </Combobox.Trigger>
200
- <Combobox.Content class="flex flex-col justify-between" customAnchor={customAnchorSingle}>
201
- <div class="flex flex-grow flex-col">
202
- {#if filteredFruitsSingle.length > 0}
203
- <Combobox.Group>
204
- <Combobox.GroupHeading>Fruits</Combobox.GroupHeading>
205
- {#each filteredFruitsSingle as fruit (fruit.value)}
206
- <Combobox.Item value={fruit.value} label={fruit.label}>
207
- {#snippet children({ selected })}
208
- {fruit.label}
209
- {#if selected}
210
- <Combobox.Indicator />
211
- {/if}
212
- {/snippet}
213
- </Combobox.Item>
214
- {:else}
215
- <span class="block px-5 py-2 text-sm text-muted-foreground"> No results found </span>
216
- {/each}
217
- </Combobox.Group>
218
- {/if}
219
- </div>
220
- </Combobox.Content>
221
- </Combobox.Root>
184
+ <Combobox.Root
185
+ onOpenChange={(o) => {
186
+ if (!o) searchValueSingle = '';
187
+ }}
188
+ type="single"
189
+ name="singleFruit"
190
+ items={filteredFruitsSingle}
191
+ bind:value={selectedSingle}
192
+ >
193
+ <Combobox.Trigger>
194
+ <div bind:this={customAnchorSingle}>
195
+ <Button variant="secondary" size="sm">
196
+ {selectedSingle ? selectedSingle : 'Select a fruit'}
197
+ </Button>
198
+ </div>
199
+ </Combobox.Trigger>
200
+ <Combobox.Content class="flex flex-col justify-between" customAnchor={customAnchorSingle}>
201
+ <div class="flex flex-grow flex-col">
202
+ {#if filteredFruitsSingle.length > 0}
203
+ <Combobox.Group>
204
+ <Combobox.GroupHeading>Fruits</Combobox.GroupHeading>
205
+ {#each filteredFruitsSingle as fruit (fruit.value)}
206
+ <Combobox.Item value={fruit.value} label={fruit.label}>
207
+ {#snippet children({ selected })}
208
+ {fruit.label}
209
+ {#if selected}
210
+ <Combobox.Indicator />
211
+ {/if}
212
+ {/snippet}
213
+ </Combobox.Item>
214
+ {:else}
215
+ <span class="block px-5 py-2 text-sm text-muted-foreground"> No results found </span>
216
+ {/each}
217
+ </Combobox.Group>
218
+ {/if}
219
+ </div>
220
+ </Combobox.Content>
221
+ </Combobox.Root>
222
222
  </Story>
223
223
 
224
224
  <Story name="Grouped Items" asChild>
225
- <Combobox.Root
226
- onOpenChange={(o) => {
227
- if (!o) searchValueGrouped = '';
228
- }}
229
- type="multiple"
230
- name="groupedFruits"
231
- items={filteredFruitsGrouped}
232
- bind:value={selectedGrouped}
233
- >
234
- <div class="flex flex-wrap gap-2">
235
- {#each selectedGrouped as fruit}
236
- <Tag>
237
- {fruit}
238
- </Tag>
239
- {/each}
240
- </div>
241
- <Combobox.Trigger>
242
- <div bind:this={customAnchorGrouped}>
243
- <Button variant="primary" size="sm">
244
- <Icon iconName="List" />
245
- Select fruits by category
246
- </Button>
247
- </div>
248
- </Combobox.Trigger>
249
- <Combobox.Content class="flex flex-col justify-between" customAnchor={customAnchorGrouped}>
250
- <div>
251
- <Combobox.Input
252
- placeholder="Search across categories"
253
- oninput={(e: Event) => (searchValueGrouped = (e.target as HTMLInputElement).value)}
254
- autofocus
255
- />
256
- <Divider />
257
- </div>
258
- <div class="flex max-h-80 flex-grow flex-col overflow-y-auto">
259
- {#if searchValueGrouped === ''}
260
- {#each categories as category}
261
- <Combobox.Group>
262
- <Combobox.GroupHeading>{category.label}</Combobox.GroupHeading>
263
- {#each category.items as item}
264
- {@const fruit = fruits.find((f) => f.value === item)}
265
- {#if fruit}
266
- <Combobox.Item value={fruit.value} label={fruit.label}>
267
- {#snippet children({ selected })}
268
- {fruit.label}
269
- {#if selected}
270
- <Combobox.Indicator />
271
- {/if}
272
- {/snippet}
273
- </Combobox.Item>
274
- {/if}
275
- {/each}
276
- </Combobox.Group>
277
- {/each}
278
- {:else if filteredFruitsGrouped.length > 0}
279
- <Combobox.Group>
280
- <Combobox.GroupHeading>Search Results</Combobox.GroupHeading>
281
- {#each filteredFruitsGrouped as fruit (fruit.value)}
282
- <Combobox.Item value={fruit.value} label={fruit.label}>
283
- {#snippet children({ selected })}
284
- {fruit.label}
285
- {#if selected}
286
- <Combobox.Indicator />
287
- {/if}
288
- {/snippet}
289
- </Combobox.Item>
290
- {/each}
291
- </Combobox.Group>
292
- {:else}
293
- <span class="text-muted-foreground block px-5 py-2 text-sm"> No results found </span>
294
- {/if}
295
- </div>
296
- </Combobox.Content>
297
- </Combobox.Root>
225
+ <Combobox.Root
226
+ onOpenChange={(o) => {
227
+ if (!o) searchValueGrouped = '';
228
+ }}
229
+ type="multiple"
230
+ name="groupedFruits"
231
+ items={filteredFruitsGrouped}
232
+ bind:value={selectedGrouped}
233
+ >
234
+ <div class="flex flex-wrap gap-2">
235
+ {#each selectedGrouped as fruit}
236
+ <Tag>
237
+ {fruit}
238
+ </Tag>
239
+ {/each}
240
+ </div>
241
+ <Combobox.Trigger>
242
+ <div bind:this={customAnchorGrouped}>
243
+ <Button variant="primary" size="sm">
244
+ <Icon iconName="List" />
245
+ Select fruits by category
246
+ </Button>
247
+ </div>
248
+ </Combobox.Trigger>
249
+ <Combobox.Content class="flex flex-col justify-between" customAnchor={customAnchorGrouped}>
250
+ <div>
251
+ <Combobox.Input
252
+ placeholder="Search across categories"
253
+ oninput={(e: Event) => (searchValueGrouped = (e.target as HTMLInputElement).value)}
254
+ autofocus
255
+ />
256
+ <Divider />
257
+ </div>
258
+ <div class="flex max-h-80 flex-grow flex-col overflow-y-auto">
259
+ {#if searchValueGrouped === ''}
260
+ {#each categories as category}
261
+ <Combobox.Group>
262
+ <Combobox.GroupHeading>{category.label}</Combobox.GroupHeading>
263
+ {#each category.items as item}
264
+ {@const fruit = fruits.find((f) => f.value === item)}
265
+ {#if fruit}
266
+ <Combobox.Item value={fruit.value} label={fruit.label}>
267
+ {#snippet children({ selected })}
268
+ {fruit.label}
269
+ {#if selected}
270
+ <Combobox.Indicator />
271
+ {/if}
272
+ {/snippet}
273
+ </Combobox.Item>
274
+ {/if}
275
+ {/each}
276
+ </Combobox.Group>
277
+ {/each}
278
+ {:else if filteredFruitsGrouped.length > 0}
279
+ <Combobox.Group>
280
+ <Combobox.GroupHeading>Search Results</Combobox.GroupHeading>
281
+ {#each filteredFruitsGrouped as fruit (fruit.value)}
282
+ <Combobox.Item value={fruit.value} label={fruit.label}>
283
+ {#snippet children({ selected })}
284
+ {fruit.label}
285
+ {#if selected}
286
+ <Combobox.Indicator />
287
+ {/if}
288
+ {/snippet}
289
+ </Combobox.Item>
290
+ {/each}
291
+ </Combobox.Group>
292
+ {:else}
293
+ <span class="text-muted-foreground block px-5 py-2 text-sm"> No results found </span>
294
+ {/if}
295
+ </div>
296
+ </Combobox.Content>
297
+ </Combobox.Root>
298
298
  </Story>
299
299
 
300
300
  <Story
301
- name="Interaction Test"
302
- asChild
303
- play={async ({ canvasElement }) => {
304
- // Get the canvas element
305
- const canvas = within(canvasElement);
301
+ name="Interaction Test"
302
+ asChild
303
+ play={async ({ canvasElement }) => {
304
+ // Get the canvas element
305
+ const canvas = within(canvasElement);
306
306
 
307
- // Find and click the trigger button to open the combobox
308
- const triggerButton = canvas.getByTestId('combobox-trigger');
309
- await userEvent.click(triggerButton);
307
+ // Find and click the trigger button to open the combobox
308
+ const triggerButton = canvas.getByTestId('combobox-trigger');
309
+ await userEvent.click(triggerButton);
310
310
 
311
- // Wait for the combobox content to appear in the document
312
- await new Promise((resolve) => setTimeout(resolve, 300));
311
+ // Wait for the combobox content to appear in the document
312
+ await new Promise((resolve) => setTimeout(resolve, 300));
313
313
 
314
- // Find the combobox content in the document
315
- const comboboxContent = document.querySelector(
316
- '[data-testid="combobox-content"]'
317
- ) as HTMLElement;
318
- if (!comboboxContent) {
319
- console.log('Combobox content not found');
320
- return;
321
- }
314
+ // Find the combobox content in the document
315
+ const comboboxContent = document.querySelector(
316
+ '[data-testid="combobox-content"]'
317
+ ) as HTMLElement;
318
+ if (!comboboxContent) {
319
+ console.log('Combobox content not found');
320
+ return;
321
+ }
322
322
 
323
- // Use within to scope queries to the combobox content
324
- const contentScope = within(comboboxContent);
325
- const searchInput = contentScope.getByTestId('combobox-input');
323
+ // Use within to scope queries to the combobox content
324
+ const contentScope = within(comboboxContent);
325
+ const searchInput = contentScope.getByTestId('combobox-input');
326
326
 
327
- // Type "berry" in the search input
328
- await userEvent.type(searchInput, 'berry');
327
+ // Type "berry" in the search input
328
+ await userEvent.type(searchInput, 'berry');
329
329
 
330
- // Wait for the filtering to complete
331
- await new Promise((resolve) => setTimeout(resolve, 300));
330
+ // Wait for the filtering to complete
331
+ await new Promise((resolve) => setTimeout(resolve, 300));
332
332
 
333
- // Find and click on the Strawberry option
334
- const strawberryOption = contentScope.getByText('Strawberry');
335
- await userEvent.click(strawberryOption);
333
+ // Find and click on the Strawberry option
334
+ const strawberryOption = contentScope.getByText('Strawberry');
335
+ await userEvent.click(strawberryOption);
336
336
 
337
- // Wait for selection to be processed
337
+ // Wait for selection to be processed
338
338
 
339
- // Open the combobox again
339
+ // Open the combobox again
340
340
 
341
- // Get the search input again
341
+ // Get the search input again
342
342
 
343
- // Clear the previous search and type "mango"
344
- await userEvent.clear(searchInput);
345
- await userEvent.type(searchInput, 'mango');
343
+ // Clear the previous search and type "mango"
344
+ await userEvent.clear(searchInput);
345
+ await userEvent.type(searchInput, 'mango');
346
346
 
347
- // Wait for filtering to complete
348
- await new Promise((resolve) => setTimeout(resolve, 300));
347
+ // Wait for filtering to complete
348
+ await new Promise((resolve) => setTimeout(resolve, 300));
349
349
 
350
- // Find and click on the Mango option
351
- const mangoOption = contentScope.getByText('Mango');
352
- await userEvent.click(mangoOption);
350
+ // Find and click on the Mango option
351
+ const mangoOption = contentScope.getByText('Mango');
352
+ await userEvent.click(mangoOption);
353
353
 
354
- await userEvent.keyboard('{Escape}');
354
+ await userEvent.keyboard('{Escape}');
355
355
 
356
- // Test complete
357
- console.log('Successfully selected Strawberry and Mango');
358
- }}
356
+ // Test complete
357
+ console.log('Successfully selected Strawberry and Mango');
358
+ }}
359
359
  >
360
- <div data-testid="combobox-container">
361
- <Combobox.Root
362
- onOpenChange={(o) => {
363
- if (!o) searchValue = '';
364
- }}
365
- type="multiple"
366
- name="favoriteFruit"
367
- items={filteredFruits}
368
- bind:value={selected}
369
- >
370
- <div class="flex gap-2" data-testid="selected-tags">
371
- {#each selected as fruit}
372
- <Tag>
373
- <div data-value={fruit}>
374
- {fruit}
375
- </div>
376
- </Tag>
377
- {/each}
378
- </div>
379
- <Combobox.Trigger data-testid="combobox-trigger">
380
- <div bind:this={customAnchor}>
381
- <IconButton rounded={false}>
382
- <Icon iconName="Plus" />
383
- </IconButton>
384
- </div>
385
- </Combobox.Trigger>
386
- <Combobox.Content
387
- {customAnchor}
388
- class="flex flex-col justify-between"
389
- data-testid="combobox-content"
390
- >
391
- <div>
392
- <Combobox.Input
393
- placeholder="Search a fruit"
394
- oninput={(e: Event) => (searchValue = (e.target as HTMLInputElement).value)}
395
- autofocus
396
- data-testid="combobox-input"
397
- />
398
- <Divider />
399
- </div>
400
- <div class="flex flex-grow flex-col">
401
- {#if filteredFruits.length > 0}
402
- <Combobox.Group>
403
- <Combobox.GroupHeading>Fruits</Combobox.GroupHeading>
404
- {#each filteredFruits as fruit (fruit.value)}
405
- <Combobox.Item
406
- value={fruit.value}
407
- label={fruit.label}
408
- data-testid={`fruit-option-${fruit.value}`}
409
- >
410
- {#snippet children({ selected })}
411
- {fruit.label}
412
- {#if selected}
413
- <Combobox.Indicator />
414
- {/if}
415
- {/snippet}
416
- </Combobox.Item>
417
- {:else}
418
- <span class="block px-5 py-2 text-sm text-muted-foreground">
419
- No results found
420
- </span>
421
- {/each}
422
- </Combobox.Group>
423
- {/if}
424
- </div>
425
- {#if !exactMatch && searchValue !== ''}
426
- <Divider />
427
-
428
- <Combobox.Add
429
- data-testid="add-new-fruit"
430
- onclick={() => {
431
- selected.push(searchValue);
432
- fruits.push({ value: searchValue, label: searchValue });
433
- searchValue = '';
434
- }}
435
- >
436
- <p>Add new fruit</p>
437
- </Combobox.Add>
438
- {/if}
439
- </Combobox.Content>
440
- </Combobox.Root>
441
- </div>
360
+ <div data-testid="combobox-container">
361
+ <Combobox.Root
362
+ onOpenChange={(o) => {
363
+ if (!o) searchValue = '';
364
+ }}
365
+ type="multiple"
366
+ name="favoriteFruit"
367
+ items={filteredFruits}
368
+ bind:value={selected}
369
+ >
370
+ <div class="flex gap-2" data-testid="selected-tags">
371
+ {#each selected as fruit}
372
+ <Tag>
373
+ <div data-value={fruit}>
374
+ {fruit}
375
+ </div>
376
+ </Tag>
377
+ {/each}
378
+ </div>
379
+ <Combobox.Trigger data-testid="combobox-trigger">
380
+ <div bind:this={customAnchor}>
381
+ <IconButton rounded={false}>
382
+ <Icon iconName="Plus" />
383
+ </IconButton>
384
+ </div>
385
+ </Combobox.Trigger>
386
+ <Combobox.Content
387
+ {customAnchor}
388
+ class="flex flex-col justify-between"
389
+ data-testid="combobox-content"
390
+ >
391
+ <div>
392
+ <Combobox.Input
393
+ placeholder="Search a fruit"
394
+ oninput={(e: Event) => (searchValue = (e.target as HTMLInputElement).value)}
395
+ autofocus
396
+ data-testid="combobox-input"
397
+ />
398
+ <Divider />
399
+ </div>
400
+ <div class="flex flex-grow flex-col">
401
+ {#if filteredFruits.length > 0}
402
+ <Combobox.Group>
403
+ <Combobox.GroupHeading>Fruits</Combobox.GroupHeading>
404
+ {#each filteredFruits as fruit (fruit.value)}
405
+ <Combobox.Item
406
+ value={fruit.value}
407
+ label={fruit.label}
408
+ data-testid={`fruit-option-${fruit.value}`}
409
+ >
410
+ {#snippet children({ selected })}
411
+ {fruit.label}
412
+ {#if selected}
413
+ <Combobox.Indicator />
414
+ {/if}
415
+ {/snippet}
416
+ </Combobox.Item>
417
+ {:else}
418
+ <span class="block px-5 py-2 text-sm text-muted-foreground">
419
+ No results found
420
+ </span>
421
+ {/each}
422
+ </Combobox.Group>
423
+ {/if}
424
+ </div>
425
+ {#if !exactMatch && searchValue !== ''}
426
+ <Divider />
427
+
428
+ <Combobox.Add
429
+ data-testid="add-new-fruit"
430
+ onclick={() => {
431
+ selected.push(searchValue);
432
+ fruits.push({ value: searchValue, label: searchValue });
433
+ searchValue = '';
434
+ }}
435
+ >
436
+ <p>Add new fruit</p>
437
+ </Combobox.Add>
438
+ {/if}
439
+ </Combobox.Content>
440
+ </Combobox.Root>
441
+ </div>
442
442
  </Story>