polymorph-ui-components 0.1.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 (242) hide show
  1. package/README.md +354 -0
  2. package/dist/Accordion/Accordion.svelte +28 -0
  3. package/dist/Accordion/Accordion.svelte.d.ts +4 -0
  4. package/dist/Accordion/properties.d.ts +7 -0
  5. package/dist/Accordion/properties.js +1 -0
  6. package/dist/Animations/ModalAnimation.svelte +55 -0
  7. package/dist/Animations/ModalAnimation.svelte.d.ts +12 -0
  8. package/dist/Animations/OverlayAnimation.svelte +14 -0
  9. package/dist/Animations/OverlayAnimation.svelte.d.ts +7 -0
  10. package/dist/Avatar/Avatar.svelte +122 -0
  11. package/dist/Avatar/Avatar.svelte.d.ts +4 -0
  12. package/dist/Avatar/properties.d.ts +15 -0
  13. package/dist/Avatar/properties.js +1 -0
  14. package/dist/Badge/Badge.svelte +53 -0
  15. package/dist/Badge/Badge.svelte.d.ts +4 -0
  16. package/dist/Badge/properties.d.ts +6 -0
  17. package/dist/Badge/properties.js +1 -0
  18. package/dist/Banner/Banner.svelte +158 -0
  19. package/dist/Banner/Banner.svelte.d.ts +4 -0
  20. package/dist/Banner/properties.d.ts +19 -0
  21. package/dist/Banner/properties.js +1 -0
  22. package/dist/Book/Book.svelte +281 -0
  23. package/dist/Book/Book.svelte.d.ts +4 -0
  24. package/dist/Book/properties.d.ts +24 -0
  25. package/dist/Book/properties.js +1 -0
  26. package/dist/Browser/Browser.svelte +176 -0
  27. package/dist/Browser/Browser.svelte.d.ts +3 -0
  28. package/dist/Browser/properties.d.ts +14 -0
  29. package/dist/Browser/properties.js +1 -0
  30. package/dist/Button/Button.svelte +153 -0
  31. package/dist/Button/Button.svelte.d.ts +4 -0
  32. package/dist/Button/properties.d.ts +24 -0
  33. package/dist/Button/properties.js +1 -0
  34. package/dist/Calendar/Calendar.svelte +477 -0
  35. package/dist/Calendar/Calendar.svelte.d.ts +4 -0
  36. package/dist/Calendar/properties.d.ts +30 -0
  37. package/dist/Calendar/properties.js +1 -0
  38. package/dist/Carousel/Carousel.svelte +258 -0
  39. package/dist/Carousel/Carousel.svelte.d.ts +4 -0
  40. package/dist/Carousel/properties.d.ts +20 -0
  41. package/dist/Carousel/properties.js +1 -0
  42. package/dist/CheckListItem/CheckListItem.svelte +65 -0
  43. package/dist/CheckListItem/CheckListItem.svelte.d.ts +4 -0
  44. package/dist/CheckListItem/properties.d.ts +15 -0
  45. package/dist/CheckListItem/properties.js +1 -0
  46. package/dist/Checkbox/Checkbox.svelte +157 -0
  47. package/dist/Checkbox/Checkbox.svelte.d.ts +4 -0
  48. package/dist/Checkbox/properties.d.ts +17 -0
  49. package/dist/Checkbox/properties.js +1 -0
  50. package/dist/Choicebox/Choicebox.svelte +85 -0
  51. package/dist/Choicebox/Choicebox.svelte.d.ts +4 -0
  52. package/dist/Choicebox/properties.d.ts +14 -0
  53. package/dist/Choicebox/properties.js +1 -0
  54. package/dist/ColorPicker/ColorPicker.svelte +583 -0
  55. package/dist/ColorPicker/ColorPicker.svelte.d.ts +4 -0
  56. package/dist/ColorPicker/properties.d.ts +15 -0
  57. package/dist/ColorPicker/properties.js +1 -0
  58. package/dist/Combobox/Combobox.svelte +432 -0
  59. package/dist/Combobox/Combobox.svelte.d.ts +6 -0
  60. package/dist/Combobox/properties.d.ts +42 -0
  61. package/dist/Combobox/properties.js +1 -0
  62. package/dist/CommandMenu/CommandMenu.svelte +452 -0
  63. package/dist/CommandMenu/CommandMenu.svelte.d.ts +4 -0
  64. package/dist/CommandMenu/properties.d.ts +26 -0
  65. package/dist/CommandMenu/properties.js +1 -0
  66. package/dist/ContextMenu/ContextMenu.svelte +308 -0
  67. package/dist/ContextMenu/ContextMenu.svelte.d.ts +4 -0
  68. package/dist/ContextMenu/properties.d.ts +26 -0
  69. package/dist/ContextMenu/properties.js +1 -0
  70. package/dist/Gauge/Gauge.svelte +70 -0
  71. package/dist/Gauge/Gauge.svelte.d.ts +4 -0
  72. package/dist/Gauge/properties.d.ts +9 -0
  73. package/dist/Gauge/properties.js +1 -0
  74. package/dist/GridItem/GridItem.svelte +145 -0
  75. package/dist/GridItem/GridItem.svelte.d.ts +4 -0
  76. package/dist/GridItem/properties.d.ts +15 -0
  77. package/dist/GridItem/properties.js +1 -0
  78. package/dist/Icon/Icon.svelte +61 -0
  79. package/dist/Icon/Icon.svelte.d.ts +4 -0
  80. package/dist/Icon/properties.d.ts +12 -0
  81. package/dist/Icon/properties.js +1 -0
  82. package/dist/IconStack/IconStack.svelte +55 -0
  83. package/dist/IconStack/IconStack.svelte.d.ts +4 -0
  84. package/dist/IconStack/properties.d.ts +9 -0
  85. package/dist/IconStack/properties.js +1 -0
  86. package/dist/Img/Img.svelte +37 -0
  87. package/dist/Img/Img.svelte.d.ts +4 -0
  88. package/dist/Img/properties.d.ts +13 -0
  89. package/dist/Img/properties.js +1 -0
  90. package/dist/Input/Input.svelte +349 -0
  91. package/dist/Input/Input.svelte.d.ts +8 -0
  92. package/dist/Input/properties.d.ts +45 -0
  93. package/dist/Input/properties.js +1 -0
  94. package/dist/InputButton/InputButton.svelte +252 -0
  95. package/dist/InputButton/InputButton.svelte.d.ts +7 -0
  96. package/dist/InputButton/properties.d.ts +22 -0
  97. package/dist/InputButton/properties.js +1 -0
  98. package/dist/KeyboardInput/KeyboardInput.svelte +93 -0
  99. package/dist/KeyboardInput/KeyboardInput.svelte.d.ts +4 -0
  100. package/dist/KeyboardInput/properties.d.ts +12 -0
  101. package/dist/KeyboardInput/properties.js +1 -0
  102. package/dist/ListItem/ListItem.svelte +309 -0
  103. package/dist/ListItem/ListItem.svelte.d.ts +4 -0
  104. package/dist/ListItem/properties.d.ts +34 -0
  105. package/dist/ListItem/properties.js +1 -0
  106. package/dist/Loader/Loader.svelte +90 -0
  107. package/dist/Loader/Loader.svelte.d.ts +4 -0
  108. package/dist/Loader/properties.d.ts +4 -0
  109. package/dist/Loader/properties.js +1 -0
  110. package/dist/LoadingDots/LoadingDots.svelte +59 -0
  111. package/dist/LoadingDots/LoadingDots.svelte.d.ts +3 -0
  112. package/dist/LoadingDots/properties.d.ts +8 -0
  113. package/dist/LoadingDots/properties.js +1 -0
  114. package/dist/Menu/Menu.svelte +356 -0
  115. package/dist/Menu/Menu.svelte.d.ts +4 -0
  116. package/dist/Menu/properties.d.ts +28 -0
  117. package/dist/Menu/properties.js +1 -0
  118. package/dist/Modal/Modal.svelte +357 -0
  119. package/dist/Modal/Modal.svelte.d.ts +4 -0
  120. package/dist/Modal/properties.d.ts +39 -0
  121. package/dist/Modal/properties.js +1 -0
  122. package/dist/Pagination/Pagination.svelte +148 -0
  123. package/dist/Pagination/Pagination.svelte.d.ts +4 -0
  124. package/dist/Pagination/properties.d.ts +14 -0
  125. package/dist/Pagination/properties.js +1 -0
  126. package/dist/Phone/Phone.svelte +234 -0
  127. package/dist/Phone/Phone.svelte.d.ts +3 -0
  128. package/dist/Phone/properties.d.ts +11 -0
  129. package/dist/Phone/properties.js +1 -0
  130. package/dist/Pill/Pill.svelte +130 -0
  131. package/dist/Pill/Pill.svelte.d.ts +4 -0
  132. package/dist/Pill/properties.d.ts +16 -0
  133. package/dist/Pill/properties.js +1 -0
  134. package/dist/Progress/Progress.svelte +68 -0
  135. package/dist/Progress/Progress.svelte.d.ts +4 -0
  136. package/dist/Progress/properties.d.ts +10 -0
  137. package/dist/Progress/properties.js +1 -0
  138. package/dist/Radio/Radio.svelte +124 -0
  139. package/dist/Radio/Radio.svelte.d.ts +4 -0
  140. package/dist/Radio/properties.d.ts +15 -0
  141. package/dist/Radio/properties.js +1 -0
  142. package/dist/RelativeTime/RelativeTime.svelte +109 -0
  143. package/dist/RelativeTime/RelativeTime.svelte.d.ts +4 -0
  144. package/dist/RelativeTime/properties.d.ts +13 -0
  145. package/dist/RelativeTime/properties.js +1 -0
  146. package/dist/Scroller/Scroller.svelte +390 -0
  147. package/dist/Scroller/Scroller.svelte.d.ts +4 -0
  148. package/dist/Scroller/properties.d.ts +30 -0
  149. package/dist/Scroller/properties.js +1 -0
  150. package/dist/Select/Select.svelte +472 -0
  151. package/dist/Select/Select.svelte.d.ts +4 -0
  152. package/dist/Select/properties.d.ts +20 -0
  153. package/dist/Select/properties.js +1 -0
  154. package/dist/Sheet/Sheet.svelte +264 -0
  155. package/dist/Sheet/Sheet.svelte.d.ts +4 -0
  156. package/dist/Sheet/properties.d.ts +19 -0
  157. package/dist/Sheet/properties.js +1 -0
  158. package/dist/Shimmer/Shimmer.svelte +44 -0
  159. package/dist/Shimmer/Shimmer.svelte.d.ts +4 -0
  160. package/dist/Shimmer/properties.d.ts +4 -0
  161. package/dist/Shimmer/properties.js +1 -0
  162. package/dist/Slider/Slider.svelte +147 -0
  163. package/dist/Slider/Slider.svelte.d.ts +4 -0
  164. package/dist/Slider/properties.d.ts +17 -0
  165. package/dist/Slider/properties.js +1 -0
  166. package/dist/Snippet/Snippet.svelte +123 -0
  167. package/dist/Snippet/Snippet.svelte.d.ts +4 -0
  168. package/dist/Snippet/properties.d.ts +15 -0
  169. package/dist/Snippet/properties.js +1 -0
  170. package/dist/SplitButton/SplitButton.svelte +145 -0
  171. package/dist/SplitButton/SplitButton.svelte.d.ts +4 -0
  172. package/dist/SplitButton/properties.d.ts +17 -0
  173. package/dist/SplitButton/properties.js +1 -0
  174. package/dist/SplitInput/SplitInput.svelte +225 -0
  175. package/dist/SplitInput/SplitInput.svelte.d.ts +7 -0
  176. package/dist/SplitInput/properties.d.ts +20 -0
  177. package/dist/SplitInput/properties.js +1 -0
  178. package/dist/Stepper/Step.svelte +88 -0
  179. package/dist/Stepper/Step.svelte.d.ts +4 -0
  180. package/dist/Stepper/Stepper.svelte +64 -0
  181. package/dist/Stepper/Stepper.svelte.d.ts +4 -0
  182. package/dist/Stepper/properties.d.ts +27 -0
  183. package/dist/Stepper/properties.js +1 -0
  184. package/dist/Table/Table.svelte +357 -0
  185. package/dist/Table/Table.svelte.d.ts +4 -0
  186. package/dist/Table/properties.d.ts +26 -0
  187. package/dist/Table/properties.js +1 -0
  188. package/dist/Tabs/Tabs.svelte +303 -0
  189. package/dist/Tabs/Tabs.svelte.d.ts +4 -0
  190. package/dist/Tabs/properties.d.ts +30 -0
  191. package/dist/Tabs/properties.js +1 -0
  192. package/dist/ThemeSwitcher/ThemeSwitcher.svelte +249 -0
  193. package/dist/ThemeSwitcher/ThemeSwitcher.svelte.d.ts +4 -0
  194. package/dist/ThemeSwitcher/properties.d.ts +19 -0
  195. package/dist/ThemeSwitcher/properties.js +1 -0
  196. package/dist/Toast/Toast.svelte +220 -0
  197. package/dist/Toast/Toast.svelte.d.ts +4 -0
  198. package/dist/Toast/properties.d.ts +24 -0
  199. package/dist/Toast/properties.js +1 -0
  200. package/dist/Toggle/Toggle.svelte +99 -0
  201. package/dist/Toggle/Toggle.svelte.d.ts +4 -0
  202. package/dist/Toggle/properties.d.ts +9 -0
  203. package/dist/Toggle/properties.js +1 -0
  204. package/dist/Toolbar/Toolbar.svelte +142 -0
  205. package/dist/Toolbar/Toolbar.svelte.d.ts +4 -0
  206. package/dist/Toolbar/properties.d.ts +16 -0
  207. package/dist/Toolbar/properties.js +1 -0
  208. package/dist/Tooltip/Tooltip.svelte +153 -0
  209. package/dist/Tooltip/Tooltip.svelte.d.ts +4 -0
  210. package/dist/Tooltip/properties.d.ts +13 -0
  211. package/dist/Tooltip/properties.js +1 -0
  212. package/dist/assets/back.svg +3 -0
  213. package/dist/assets/battery.svg +5 -0
  214. package/dist/assets/checkmark.svg +3 -0
  215. package/dist/assets/chevron-down-sm.svg +3 -0
  216. package/dist/assets/chevron-down.svg +3 -0
  217. package/dist/assets/chevron-left-lg.svg +3 -0
  218. package/dist/assets/chevron-left.svg +3 -0
  219. package/dist/assets/chevron-right-lg.svg +3 -0
  220. package/dist/assets/chevron-right.svg +3 -0
  221. package/dist/assets/chevron-up.svg +3 -0
  222. package/dist/assets/close.svg +4 -0
  223. package/dist/assets/copy.svg +4 -0
  224. package/dist/assets/error-circle.svg +5 -0
  225. package/dist/assets/lock.svg +3 -0
  226. package/dist/assets/minus.svg +3 -0
  227. package/dist/assets/monitor.svg +5 -0
  228. package/dist/assets/moon.svg +3 -0
  229. package/dist/assets/palette.svg +7 -0
  230. package/dist/assets/search.svg +4 -0
  231. package/dist/assets/signal.svg +6 -0
  232. package/dist/assets/sort-default.svg +4 -0
  233. package/dist/assets/sun.svg +11 -0
  234. package/dist/assets/swap-vertical.svg +6 -0
  235. package/dist/assets/wifi.svg +3 -0
  236. package/dist/index.d.ts +103 -0
  237. package/dist/index.js +55 -0
  238. package/dist/types.d.ts +42 -0
  239. package/dist/types.js +1 -0
  240. package/dist/utils.d.ts +28 -0
  241. package/dist/utils.js +294 -0
  242. package/package.json +91 -0
@@ -0,0 +1,357 @@
1
+ <script lang="ts">
2
+ import type { TableProperties, TableCellValue } from './properties';
3
+ import Button from '../Button/Button.svelte';
4
+ import chevronUpSvg from '../assets/chevron-up.svg?raw';
5
+ import chevronDownSvg from '../assets/chevron-down.svg?raw';
6
+ import sortDefaultSvg from '../assets/sort-default.svg?raw';
7
+
8
+ let {
9
+ tableTitle = '',
10
+ tableHeaders = [],
11
+ tableData = [],
12
+ sortable = true,
13
+ sortableColumns,
14
+ stickyHeader = false,
15
+ isTableScrollable = false,
16
+ isContentScrollable = false,
17
+ testId,
18
+ caption,
19
+ sortAscIcon,
20
+ sortDescIcon,
21
+ sortDefaultIcon,
22
+ cell,
23
+ empty,
24
+ onrowclick,
25
+ onsort,
26
+ classes
27
+ }: TableProperties = $props();
28
+
29
+ let sortColumn = $state<number | null>(null);
30
+ let sortDirection = $state<'asc' | 'desc'>('asc');
31
+
32
+ function isColumnSortable(colIndex: number): boolean {
33
+ if (!sortable) {
34
+ return false;
35
+ }
36
+ if (sortableColumns) {
37
+ return sortableColumns.includes(colIndex);
38
+ }
39
+ return true;
40
+ }
41
+
42
+ let sortedTableData = $derived.by(() => {
43
+ if (sortColumn === null) {
44
+ return [...tableData];
45
+ }
46
+
47
+ const colIndex = sortColumn;
48
+ const direction = sortDirection;
49
+
50
+ return [...tableData].sort((a, b) => {
51
+ const valueA = a[colIndex];
52
+ const valueB = b[colIndex];
53
+
54
+ if (typeof valueA === 'number' && typeof valueB === 'number') {
55
+ return direction === 'asc' ? valueA - valueB : valueB - valueA;
56
+ } else if (typeof valueA === 'string' && typeof valueB === 'string') {
57
+ return direction === 'asc' ? valueA.localeCompare(valueB) : valueB.localeCompare(valueA);
58
+ } else if (typeof valueA === 'boolean' && typeof valueB === 'boolean') {
59
+ return direction === 'asc'
60
+ ? valueA === valueB
61
+ ? 0
62
+ : valueA
63
+ ? -1
64
+ : 1
65
+ : valueA === valueB
66
+ ? 0
67
+ : valueA
68
+ ? 1
69
+ : -1;
70
+ }
71
+ return 0;
72
+ });
73
+ });
74
+
75
+ function handleSort(colIndex: number) {
76
+ if (!isColumnSortable(colIndex)) {
77
+ return;
78
+ }
79
+
80
+ if (sortColumn === colIndex) {
81
+ sortDirection = sortDirection === 'asc' ? 'desc' : 'asc';
82
+ } else {
83
+ sortColumn = colIndex;
84
+ sortDirection = 'asc';
85
+ }
86
+ onsort?.(colIndex, sortDirection);
87
+ }
88
+
89
+ function handleRowClick(rowIndex: number, rowData: TableCellValue[]) {
90
+ onrowclick?.(rowIndex, rowData);
91
+ }
92
+
93
+ function handleRowKeydown(event: KeyboardEvent, rowIndex: number, rowData: TableCellValue[]) {
94
+ if (event.key === 'Enter' || event.key === ' ') {
95
+ event.preventDefault();
96
+ onrowclick?.(rowIndex, rowData);
97
+ }
98
+ }
99
+
100
+ let isRowClickable = $derived(typeof onrowclick === 'function');
101
+ let isStickyHeader = $derived(stickyHeader || isTableScrollable);
102
+ </script>
103
+
104
+ {#if typeof tableTitle === 'string' && tableTitle.length > 0}
105
+ <div class="table-title">
106
+ {tableTitle}
107
+ </div>
108
+ {/if}
109
+ {#if tableHeaders.length !== 0 || tableData.length !== 0}
110
+ <div
111
+ class="table-container {isTableScrollable ? 'scrollable-table' : ''} {classes ?? ''}"
112
+ data-pw={testId}
113
+ >
114
+ <table>
115
+ {#if caption}
116
+ <caption class="sr-only">{caption}</caption>
117
+ {/if}
118
+ <thead>
119
+ <tr>
120
+ {#each tableHeaders as header, colIndex (colIndex)}
121
+ <th class="table-header" class:table-header-sticky={isStickyHeader}>
122
+ <span class="table-header-content">
123
+ {header}
124
+ {#if isColumnSortable(colIndex)}
125
+ <div class="sort-button">
126
+ <Button onclick={() => handleSort(colIndex)} ariaLabel="Sort by {header}">
127
+ {#if sortColumn === colIndex && sortDirection === 'asc'}
128
+ {#if typeof sortAscIcon === 'function'}
129
+ {@render sortAscIcon()}
130
+ {:else}
131
+ <span class="sort-icon">
132
+ <!-- eslint-disable svelte/no-at-html-tags -->
133
+ {@html chevronUpSvg}
134
+ </span>
135
+ {/if}
136
+ {:else if sortColumn === colIndex && sortDirection === 'desc'}
137
+ {#if typeof sortDescIcon === 'function'}
138
+ {@render sortDescIcon()}
139
+ {:else}
140
+ <span class="sort-icon">
141
+ <!-- eslint-disable svelte/no-at-html-tags -->
142
+ {@html chevronDownSvg}
143
+ </span>
144
+ {/if}
145
+ {:else if typeof sortDefaultIcon === 'function'}
146
+ {@render sortDefaultIcon()}
147
+ {:else}
148
+ <span class="sort-icon sort-icon-idle">
149
+ <!-- eslint-disable svelte/no-at-html-tags -->
150
+ {@html sortDefaultSvg}
151
+ </span>
152
+ {/if}
153
+ </Button>
154
+ </div>
155
+ {/if}
156
+ </span>
157
+ </th>
158
+ {/each}
159
+ </tr>
160
+ </thead>
161
+ <tbody>
162
+ {#if sortedTableData.length === 0 && typeof empty === 'function'}
163
+ <tr>
164
+ <td class="table-empty" colspan={tableHeaders.length}>
165
+ {@render empty()}
166
+ </td>
167
+ </tr>
168
+ {:else}
169
+ {#each sortedTableData as row, rowIndex (rowIndex)}
170
+ <tr
171
+ class="table-row"
172
+ class:table-row-clickable={isRowClickable}
173
+ onclick={isRowClickable ? () => handleRowClick(rowIndex, row) : null}
174
+ onkeydown={isRowClickable ? (e) => handleRowKeydown(e, rowIndex, row) : null}
175
+ tabindex={isRowClickable ? 0 : null}
176
+ >
177
+ {#each row as cellValue, colIndex (colIndex)}
178
+ <td class="table-content">
179
+ <div class={isContentScrollable ? 'scrollable-content' : ''}>
180
+ {#if typeof cell === 'function'}
181
+ {@render cell(cellValue, rowIndex, colIndex)}
182
+ {:else}
183
+ {cellValue}
184
+ {/if}
185
+ </div>
186
+ </td>
187
+ {/each}
188
+ </tr>
189
+ {/each}
190
+ {/if}
191
+ </tbody>
192
+ </table>
193
+ </div>
194
+ {/if}
195
+
196
+ <style>
197
+ .table-title {
198
+ margin: var(--table-title-margin, 0px 0px 12px 0px);
199
+ font-size: var(--table-title-font-size, 18px);
200
+ font-weight: var(--table-title-font-weight, 600);
201
+ color: var(--table-title-color, currentColor);
202
+ font-family: var(--table-title-font-family);
203
+ padding: var(--table-title-padding);
204
+ }
205
+
206
+ .table-container {
207
+ border: var(--table-border, 1px solid currentColor);
208
+ border-radius: var(--table-border-radius, 8px);
209
+ width: var(--table-container-width, 100%);
210
+ overflow: hidden;
211
+ }
212
+
213
+ .scrollable-table {
214
+ height: var(--table-container-height, 143px);
215
+ overflow-y: auto;
216
+ }
217
+
218
+ table {
219
+ width: var(--table-width, 100%);
220
+ border-collapse: var(--table-border-collapse, collapse);
221
+ }
222
+
223
+ .table-header,
224
+ .table-content {
225
+ border: var(--table-inner-border, none);
226
+ padding: var(--table-padding, 12px 16px);
227
+ text-align: var(--table-text-align, left);
228
+ width: var(--table-column-width);
229
+ word-break: break-all;
230
+ }
231
+
232
+ .scrollable-content {
233
+ overflow-y: auto;
234
+ height: var(--table-scrollable-column-height, 20px);
235
+ }
236
+
237
+ .table-header {
238
+ background-color: var(
239
+ --table-header-background,
240
+ var(--table-header-border-bgcolor, transparent)
241
+ );
242
+ font-size: var(--table-header-font-size, 14px);
243
+ font-family: var(--table-header-font-family);
244
+ font-weight: var(--table-header-font-weight, 600);
245
+ letter-spacing: var(--table-header-letter-spacing, 0.02em);
246
+ text-transform: var(--table-header-text-transform);
247
+ color: var(--table-header-color, var(--table-header-font-color, currentColor));
248
+ }
249
+
250
+ .table-header-content {
251
+ display: flex;
252
+ align-items: center;
253
+ gap: 4px;
254
+ }
255
+
256
+ .table-header-sticky {
257
+ position: sticky;
258
+ top: var(--table-header-sticky-top, 0);
259
+ z-index: 1;
260
+ }
261
+
262
+ .table-content {
263
+ background-color: var(--table-content-background, var(--table-content-border-bgcolor));
264
+ font-size: var(--table-content-font-size, 14px);
265
+ font-family: var(--table-content-font-family);
266
+ color: var(--table-content-color, var(--table-content-font-color, currentColor));
267
+ }
268
+
269
+ .table-row {
270
+ border-bottom: var(--table-row-border, 1px solid #e4e4e7);
271
+ background-color: var(--table-row-background);
272
+ }
273
+
274
+ .table-row:last-child {
275
+ border-bottom: var(--table-row-last-border, none);
276
+ }
277
+
278
+ .table-row:nth-child(even) {
279
+ background-color: var(--table-row-alt-background, var(--table-row-background));
280
+ }
281
+
282
+ .table-row:hover {
283
+ background-color: var(--table-row-hover-background);
284
+ }
285
+
286
+ .table-row:hover > .table-content {
287
+ background-color: var(
288
+ --table-row-hover-background,
289
+ var(--table-content-background, var(--table-content-border-bgcolor))
290
+ );
291
+ }
292
+
293
+ .table-row-clickable {
294
+ cursor: pointer;
295
+ }
296
+
297
+ .table-row-clickable:focus-visible {
298
+ outline: 2px solid var(--table-focus-outline-color, currentColor);
299
+ outline-offset: -2px;
300
+ }
301
+
302
+ .sort-button {
303
+ --button-color: transparent;
304
+ --button-border: none;
305
+ --button-padding: 2px;
306
+ --button-margin: 0;
307
+ --button-text-color: var(--table-sort-button-color, inherit);
308
+ --button-border-radius: 4px;
309
+ --button-width: fit-content;
310
+ --button-height: fit-content;
311
+ --button-hover-color: var(--table-sort-button-hover-background, rgba(0, 0, 0, 0.05));
312
+ --button-hover-text-color: var(
313
+ --table-sort-button-hover-color,
314
+ var(--table-sort-button-color, inherit)
315
+ );
316
+ display: inline-flex;
317
+ align-items: center;
318
+ line-height: 1;
319
+ }
320
+
321
+ .sort-button :global(.sort-icon) {
322
+ display: inline-flex;
323
+ align-items: center;
324
+ }
325
+
326
+ .sort-button :global(.sort-icon svg) {
327
+ width: var(--table-sort-icon-size, 14px);
328
+ height: var(--table-sort-icon-size, 14px);
329
+ display: block;
330
+ }
331
+
332
+ .sort-button :global(.sort-icon-idle) {
333
+ opacity: var(--table-sort-idle-opacity, 0.3);
334
+ }
335
+
336
+ .sort-button:hover :global(.sort-icon-idle) {
337
+ opacity: 0.6;
338
+ }
339
+
340
+ .table-empty {
341
+ padding: var(--table-empty-padding, 32px 24px);
342
+ text-align: center;
343
+ color: var(--table-empty-color, currentColor);
344
+ }
345
+
346
+ .sr-only {
347
+ position: absolute;
348
+ width: 1px;
349
+ height: 1px;
350
+ padding: 0;
351
+ overflow: hidden;
352
+ clip: rect(0, 0, 0, 0);
353
+ clip-path: inset(50%);
354
+ white-space: nowrap;
355
+ border-width: 0;
356
+ }
357
+ </style>
@@ -0,0 +1,4 @@
1
+ import type { TableProperties } from './properties';
2
+ declare const Table: import("svelte").Component<TableProperties, {}, "">;
3
+ type Table = ReturnType<typeof Table>;
4
+ export default Table;
@@ -0,0 +1,26 @@
1
+ import type { Snippet } from 'svelte';
2
+ export type TableCellValue = string | number | boolean | null | Record<string, unknown> | unknown[];
3
+ export type SortDirection = 'asc' | 'desc';
4
+ export type TableProperties = OptionalTableProperties & TableEventProperties;
5
+ export type OptionalTableProperties = {
6
+ tableTitle?: string | null;
7
+ tableHeaders?: string[];
8
+ tableData?: Array<TableCellValue[]>;
9
+ sortable?: boolean;
10
+ sortableColumns?: number[];
11
+ stickyHeader?: boolean;
12
+ isTableScrollable?: boolean;
13
+ isContentScrollable?: boolean;
14
+ testId?: string;
15
+ caption?: string;
16
+ sortAscIcon?: Snippet;
17
+ sortDescIcon?: Snippet;
18
+ sortDefaultIcon?: Snippet;
19
+ cell?: Snippet<[TableCellValue, number, number]>;
20
+ empty?: Snippet;
21
+ classes?: string;
22
+ };
23
+ export type TableEventProperties = {
24
+ onrowclick?: (rowIndex: number, rowData: TableCellValue[]) => void;
25
+ onsort?: (columnIndex: number, direction: SortDirection) => void;
26
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,303 @@
1
+ <script lang="ts">
2
+ import type { TabItem, TabsProperties } from './properties';
3
+ import chevronLeftSvg from '../assets/chevron-left.svg?raw';
4
+ import chevronRightSvg from '../assets/chevron-right.svg?raw';
5
+
6
+ let {
7
+ items,
8
+ activeIndex = $bindable(0),
9
+ activeKey,
10
+ disabled = false,
11
+ testId,
12
+ scrollLeftIcon,
13
+ scrollRightIcon,
14
+ tab,
15
+ classes,
16
+ onchange,
17
+ onkeychange
18
+ }: TabsProperties = $props();
19
+
20
+ const isObjectMode = $derived(items.length > 0 && typeof items.at(0) === 'object');
21
+
22
+ function toTabItem(item: string | TabItem): TabItem | null {
23
+ return typeof item === 'object' ? item : null;
24
+ }
25
+
26
+ function toStringLabel(item: string | TabItem): string {
27
+ return typeof item === 'string' ? item : item.label;
28
+ }
29
+
30
+ const resolvedActiveIndex = $derived(
31
+ isObjectMode
32
+ ? items.findIndex((item) => {
33
+ const tabItem = toTabItem(item);
34
+ return tabItem !== null && tabItem.key === activeKey;
35
+ })
36
+ : activeIndex
37
+ );
38
+
39
+ function isActiveItem(index: number): boolean {
40
+ return index === resolvedActiveIndex;
41
+ }
42
+
43
+ let scrollContainer: HTMLDivElement | null = null;
44
+ let canScrollLeft = $state(false);
45
+ let canScrollRight = $state(false);
46
+
47
+ function updateOverflow(): void {
48
+ if (scrollContainer === null) {
49
+ return;
50
+ }
51
+ const { scrollLeft, scrollWidth, clientWidth } = scrollContainer;
52
+ canScrollLeft = scrollLeft > 1;
53
+ canScrollRight = scrollLeft + clientWidth < scrollWidth - 1;
54
+ }
55
+
56
+ function scroll(direction: 'left' | 'right'): void {
57
+ if (scrollContainer === null) {
58
+ return;
59
+ }
60
+ const amount = scrollContainer.clientWidth * 0.6;
61
+ scrollContainer.scrollBy({
62
+ left: direction === 'left' ? -amount : amount,
63
+ behavior: 'smooth'
64
+ });
65
+ }
66
+
67
+ function handleTabClick(index: number): void {
68
+ if (disabled) {
69
+ return;
70
+ }
71
+ if (isObjectMode) {
72
+ const rawItem = items.at(index);
73
+ if (typeof rawItem !== 'object') {
74
+ return;
75
+ }
76
+ const tabItem = toTabItem(rawItem)!;
77
+ if (tabItem.key === activeKey) {
78
+ return;
79
+ }
80
+ onkeychange?.(tabItem.key);
81
+ } else {
82
+ if (index === activeIndex) {
83
+ return;
84
+ }
85
+ const rawLabel = items.at(index);
86
+ if (typeof rawLabel !== 'string') {
87
+ return;
88
+ }
89
+ activeIndex = index;
90
+ onchange?.(index, rawLabel);
91
+ }
92
+ }
93
+
94
+ function handleKeydown(event: KeyboardEvent, index: number): void {
95
+ if (event.key === 'Enter' || event.key === ' ') {
96
+ event.preventDefault();
97
+ handleTabClick(index);
98
+ }
99
+ }
100
+
101
+ function initOverflow(node: HTMLDivElement): { destroy: () => void } {
102
+ scrollContainer = node;
103
+ updateOverflow();
104
+ const observer = new MutationObserver(updateOverflow);
105
+ observer.observe(node, { childList: true, subtree: true });
106
+ return {
107
+ destroy() {
108
+ observer.disconnect();
109
+ }
110
+ };
111
+ }
112
+ </script>
113
+
114
+ <div class="tabs-wrapper {classes ?? ''}" class:disabled data-pw={testId}>
115
+ {#if canScrollLeft}
116
+ <button
117
+ class="tabs-arrow tabs-arrow-left"
118
+ aria-label="Scroll tabs left"
119
+ onclick={() => scroll('left')}
120
+ >
121
+ {#if typeof scrollLeftIcon === 'function'}
122
+ {@render scrollLeftIcon()}
123
+ {:else}
124
+ <!-- eslint-disable svelte/no-at-html-tags -->
125
+ {@html chevronLeftSvg}
126
+ {/if}
127
+ </button>
128
+ {/if}
129
+ <div
130
+ class="tabs-bar"
131
+ class:fade-left={canScrollLeft}
132
+ class:fade-right={canScrollRight}
133
+ role="tablist"
134
+ use:initOverflow
135
+ onscroll={updateOverflow}
136
+ >
137
+ {#each items as item, index (isObjectMode ? (toTabItem(item)?.key ?? index) : index)}
138
+ {@const tabItem = toTabItem(item)}
139
+ {@const label = toStringLabel(item)}
140
+ <div
141
+ class="tabs-item"
142
+ class:active={isActiveItem(index)}
143
+ role="tab"
144
+ aria-selected={isActiveItem(index)}
145
+ aria-disabled={disabled ? true : null}
146
+ tabindex={isActiveItem(index) ? 0 : -1}
147
+ data-pw={tabItem?.testId}
148
+ onclick={() => handleTabClick(index)}
149
+ onkeydown={(event) => handleKeydown(event, index)}
150
+ >
151
+ {#if typeof tab === 'function'}
152
+ {@render tab({ label, index, active: isActiveItem(index), subtitle: tabItem?.subtitle })}
153
+ {:else}
154
+ {label}
155
+ {/if}
156
+ {#if isActiveItem(index)}
157
+ <span class="tabs-indicator"></span>
158
+ {/if}
159
+ </div>
160
+ {/each}
161
+ </div>
162
+ {#if canScrollRight}
163
+ <button
164
+ class="tabs-arrow tabs-arrow-right"
165
+ aria-label="Scroll tabs right"
166
+ onclick={() => scroll('right')}
167
+ >
168
+ {#if typeof scrollRightIcon === 'function'}
169
+ {@render scrollRightIcon()}
170
+ {:else}
171
+ <!-- eslint-disable svelte/no-at-html-tags -->
172
+ {@html chevronRightSvg}
173
+ {/if}
174
+ </button>
175
+ {/if}
176
+ </div>
177
+
178
+ <style>
179
+ .tabs-wrapper {
180
+ display: flex;
181
+ align-items: stretch;
182
+ position: relative;
183
+ max-width: 100%;
184
+ background: var(--tabs-bar-background, transparent);
185
+ border-bottom: var(--tabs-bar-border-bottom, 1px solid #e4e4e7);
186
+ border-radius: var(--tabs-bar-border-radius, 0);
187
+ }
188
+
189
+ .tabs-wrapper.disabled {
190
+ opacity: var(--tabs-disabled-opacity, 0.5);
191
+ pointer-events: none;
192
+ }
193
+
194
+ .tabs-bar {
195
+ display: flex;
196
+ flex: 1;
197
+ min-width: 0;
198
+ padding: var(--tabs-bar-padding, 0px);
199
+ gap: var(--tabs-bar-gap, 0px);
200
+ overflow-x: auto;
201
+ scrollbar-width: none;
202
+ }
203
+
204
+ .tabs-bar::-webkit-scrollbar {
205
+ display: none;
206
+ }
207
+
208
+ .tabs-bar.fade-left {
209
+ mask-image: linear-gradient(to right, transparent, black var(--tabs-fade-size, 32px));
210
+ -webkit-mask-image: linear-gradient(to right, transparent, black var(--tabs-fade-size, 32px));
211
+ }
212
+
213
+ .tabs-bar.fade-right {
214
+ mask-image: linear-gradient(to left, transparent, black var(--tabs-fade-size, 32px));
215
+ -webkit-mask-image: linear-gradient(to left, transparent, black var(--tabs-fade-size, 32px));
216
+ }
217
+
218
+ .tabs-bar.fade-left.fade-right {
219
+ mask-image: linear-gradient(
220
+ to right,
221
+ transparent,
222
+ black var(--tabs-fade-size, 32px),
223
+ black calc(100% - var(--tabs-fade-size, 32px)),
224
+ transparent
225
+ );
226
+ -webkit-mask-image: linear-gradient(
227
+ to right,
228
+ transparent,
229
+ black var(--tabs-fade-size, 32px),
230
+ black calc(100% - var(--tabs-fade-size, 32px)),
231
+ transparent
232
+ );
233
+ }
234
+
235
+ .tabs-arrow {
236
+ display: flex;
237
+ align-items: center;
238
+ justify-content: center;
239
+ flex-shrink: 0;
240
+ width: var(--tabs-arrow-size, 28px);
241
+ padding: var(--tabs-arrow-padding, 0);
242
+ border: var(--tabs-arrow-border, none);
243
+ background: var(--tabs-arrow-background, var(--tabs-bar-background, #ffffff));
244
+ color: var(--tabs-arrow-color, var(--tabs-item-color, currentColor));
245
+ cursor: pointer;
246
+ z-index: 1;
247
+ transition: var(--tabs-arrow-transition, color 0.2s ease);
248
+ font-family: inherit;
249
+ }
250
+
251
+ .tabs-arrow:hover {
252
+ color: var(--tabs-arrow-hover-color, var(--tabs-active-color, currentColor));
253
+ background: var(
254
+ --tabs-arrow-hover-background,
255
+ var(--tabs-arrow-background, var(--tabs-bar-background, #ffffff))
256
+ );
257
+ }
258
+
259
+ .tabs-item {
260
+ display: flex;
261
+ align-items: center;
262
+ position: relative;
263
+ padding: var(--tabs-item-padding, 12px 16px);
264
+ font-size: var(--tabs-item-font-size, 14px);
265
+ font-weight: var(--tabs-item-font-weight, 400);
266
+ font-family: var(--tabs-item-font-family, inherit);
267
+ color: var(--tabs-item-color, currentColor);
268
+ cursor: var(--tabs-item-cursor, pointer);
269
+ background: var(--tabs-item-background, transparent);
270
+ border: none;
271
+ border-radius: var(--tabs-item-border-radius, 0);
272
+ outline: none;
273
+ white-space: nowrap;
274
+ flex-shrink: 0;
275
+ user-select: none;
276
+ transition: var(--tabs-transition, color 0.2s ease, background 0.2s ease);
277
+ }
278
+
279
+ .tabs-item:hover:not(.active):not([aria-disabled]) {
280
+ color: var(--tabs-hover-color, currentColor);
281
+ background: var(--tabs-hover-background, transparent);
282
+ }
283
+
284
+ .tabs-item.active {
285
+ color: var(--tabs-active-color, currentColor);
286
+ font-weight: var(--tabs-active-font-weight, 600);
287
+ background: var(--tabs-active-background, transparent);
288
+ }
289
+
290
+ .tabs-item[aria-disabled] {
291
+ cursor: var(--tabs-disabled-cursor, not-allowed);
292
+ }
293
+
294
+ .tabs-indicator {
295
+ position: absolute;
296
+ bottom: 0;
297
+ left: 0;
298
+ right: 0;
299
+ height: var(--tabs-indicator-height, 2px);
300
+ background-color: var(--tabs-indicator-color, currentColor);
301
+ border-radius: var(--tabs-indicator-border-radius, 2px 2px 0 0);
302
+ }
303
+ </style>
@@ -0,0 +1,4 @@
1
+ import type { TabsProperties } from './properties';
2
+ declare const Tabs: import("svelte").Component<TabsProperties, {}, "activeIndex">;
3
+ type Tabs = ReturnType<typeof Tabs>;
4
+ export default Tabs;