@budibase/bbui 1.0.0 → 1.0.1

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 (128) hide show
  1. package/LICENSE +375 -0
  2. package/README.md +19 -17
  3. package/dist/bbui.es.js +2 -0
  4. package/dist/bbui.es.js.map +1 -0
  5. package/package.json +68 -26
  6. package/src/ActionButton/ActionButton.svelte +83 -0
  7. package/src/ActionGroup/ActionGroup.svelte +26 -0
  8. package/src/ActionMenu/ActionMenu.svelte +43 -0
  9. package/src/Actions/ClickOutside.svench.svx +30 -0
  10. package/src/Actions/PositionDropdown.svench.svx +81 -0
  11. package/src/Actions/autoresize_textarea.js +14 -0
  12. package/src/Actions/click_outside.js +18 -0
  13. package/src/Actions/position_dropdown.js +66 -0
  14. package/src/Avatar/Avatar.svelte +49 -0
  15. package/src/Badge/Badge.svelte +29 -0
  16. package/src/Button/Button.svelte +52 -0
  17. package/src/Button/Button.svench +138 -0
  18. package/src/ButtonGroup/ButtonGroup.svelte +19 -0
  19. package/src/ClearButton/ClearButton.svelte +19 -0
  20. package/src/ColorPicker/ColorPicker.svelte +292 -0
  21. package/src/DetailSummary/DetailSummary.svelte +83 -0
  22. package/src/Divider/Divider.svelte +25 -0
  23. package/src/Drawer/Drawer.svelte +85 -0
  24. package/src/Drawer/Drawer.svench +42 -0
  25. package/src/Drawer/DrawerContent.svelte +46 -0
  26. package/src/Form/Checkbox.svelte +23 -0
  27. package/src/Form/Combobox.svelte +44 -0
  28. package/src/Form/Core/Checkbox.svelte +67 -0
  29. package/src/Form/Core/Combobox.svelte +156 -0
  30. package/src/Form/Core/DatePicker.svelte +183 -0
  31. package/src/Form/Core/Dropzone.svelte +393 -0
  32. package/src/Form/Core/Multiselect.svelte +88 -0
  33. package/src/Form/Core/Picker.svelte +241 -0
  34. package/src/Form/Core/RadioGroup.svelte +47 -0
  35. package/src/Form/Core/Search.svelte +101 -0
  36. package/src/Form/Core/Select.svelte +81 -0
  37. package/src/Form/Core/Stepper.svelte +172 -0
  38. package/src/Form/Core/Switch.svelte +35 -0
  39. package/src/Form/Core/TextArea.svelte +60 -0
  40. package/src/Form/Core/TextField.svelte +104 -0
  41. package/src/Form/Core/index.js +12 -0
  42. package/src/Form/DatePicker.svelte +33 -0
  43. package/src/Form/Dropzone.svelte +34 -0
  44. package/src/Form/Field.svelte +41 -0
  45. package/src/Form/FieldLabel.svelte +27 -0
  46. package/src/Form/Input.svelte +38 -45
  47. package/src/Form/Multiselect.svelte +39 -0
  48. package/src/Form/RadioGroup.svelte +38 -0
  49. package/src/Form/Search.svelte +32 -0
  50. package/src/Form/Select.svelte +45 -43
  51. package/src/Form/Stepper.svelte +45 -0
  52. package/src/Form/TextArea.svelte +25 -44
  53. package/src/Form/Toggle.svelte +23 -0
  54. package/src/Icon/Icon.svelte +47 -0
  55. package/src/InlineAlert/InlineAlert.svelte +56 -0
  56. package/src/Label/Label.svelte +67 -0
  57. package/src/Layout/Layout.svelte +75 -0
  58. package/src/Layout/Page.svelte +25 -0
  59. package/src/Link/Link.svelte +22 -0
  60. package/src/List/Items/DetailSummary.svench +53 -0
  61. package/src/Menu/Item.svelte +45 -0
  62. package/src/Menu/Menu.svelte +7 -0
  63. package/src/Menu/Menu.svench +19 -0
  64. package/src/Menu/Section.svelte +10 -0
  65. package/src/Menu/Separator.svelte +1 -0
  66. package/src/Modal/Content.svelte +6 -0
  67. package/src/Modal/CustomContent.svelte +38 -0
  68. package/src/Modal/Modal.svelte +133 -0
  69. package/src/Modal/Modal.svench +117 -0
  70. package/src/Modal/ModalContent.svelte +139 -0
  71. package/src/Modal/QuizModal.svelte +54 -0
  72. package/src/Notification/Notification.svelte +20 -0
  73. package/src/Notification/NotificationDisplay.svelte +36 -0
  74. package/src/Pagination/Pagination.svelte +57 -0
  75. package/src/Popover/Popover.svelte +52 -0
  76. package/src/Popover/Popover.svench +121 -0
  77. package/src/ProgressBar/ProgressBar.svelte +54 -0
  78. package/src/ProgressCircle/ProgressCircle.svelte +62 -0
  79. package/src/SideNavigation/Item.svelte +45 -0
  80. package/src/SideNavigation/Navigation.svelte +12 -0
  81. package/src/StatusLight/StatusLight.svelte +41 -0
  82. package/src/Stores/Notifications.svench.svx +78 -0
  83. package/src/Stores/notifications.js +56 -0
  84. package/src/Table/ArrayRenderer.svelte +17 -0
  85. package/src/Table/AttachmentRenderer.svelte +55 -0
  86. package/src/Table/BooleanRenderer.svelte +42 -0
  87. package/src/Table/CellRenderer.svelte +37 -0
  88. package/src/Table/DateTimeRenderer.svelte +13 -0
  89. package/src/Table/InternalRenderer.svelte +28 -0
  90. package/src/Table/RelationshipRenderer.svelte +40 -0
  91. package/src/Table/SelectEditRenderer.svelte +16 -0
  92. package/src/Table/StringRenderer.svelte +13 -0
  93. package/src/Table/Table.svelte +506 -0
  94. package/src/Table/index.js +1 -0
  95. package/src/Tabs/Tab.svelte +66 -0
  96. package/src/Tabs/Tabs.svelte +105 -0
  97. package/src/Tags/Tag.svelte +43 -0
  98. package/src/Tags/Tags.svelte +7 -0
  99. package/src/Tooltip/Tooltip.svelte +24 -0
  100. package/src/TreeView/Item.svelte +41 -0
  101. package/src/TreeView/Tree.svelte +16 -0
  102. package/src/Typography/Body.svelte +19 -0
  103. package/src/Typography/Code.svelte +10 -0
  104. package/src/Typography/Detail.svelte +15 -0
  105. package/src/Typography/Heading.svelte +16 -0
  106. package/src/bbui.css +96 -0
  107. package/src/context.js +3 -0
  108. package/src/index.js +75 -10
  109. package/src/spectrum-icons-rollup.js +31 -0
  110. package/src/spectrum-icons-vite.js +31 -0
  111. package/src/utils/helpers.js +8 -0
  112. package/dist/bundle.css +0 -6
  113. package/dist/bundle.css.map +0 -18
  114. package/dist/index.js +0 -919
  115. package/dist/index.mjs +0 -906
  116. package/src/Branding/Budibase-logo.svelte +0 -68
  117. package/src/Branding/Logo.svelte +0 -16
  118. package/src/Branding/Logo.svench +0 -8
  119. package/src/Form/Button.svelte +0 -52
  120. package/src/Form/Button.svench +0 -26
  121. package/src/Form/Input.svench +0 -8
  122. package/src/Form/Select.svench +0 -8
  123. package/src/Form/TextArea.svench +0 -8
  124. package/src/Links/Home.svelte +0 -49
  125. package/src/Links/Home.svench +0 -19
  126. package/src/actions/autoresize_textarea.js +0 -14
  127. package/src/icons/Contribution.svelte +0 -14
  128. package/src/index.svench.svx +0 -35
@@ -0,0 +1,506 @@
1
+ <script>
2
+ import { createEventDispatcher } from "svelte"
3
+ import "@spectrum-css/table/dist/index-vars.css"
4
+ import CellRenderer from "./CellRenderer.svelte"
5
+ import SelectEditRenderer from "./SelectEditRenderer.svelte"
6
+ import { cloneDeep } from "lodash"
7
+
8
+ /**
9
+ * The expected schema is our normal couch schemas for our tables.
10
+ * Each field schema can be enriched with a few extra properties to customise
11
+ * the behaviour.
12
+ * All of these are optional and do not need to be added.
13
+ * displayName: Overrides the field name displayed as the column title
14
+ * sortable: Set to false to disable sorting data by a certain column
15
+ * editable: Set to false to disable editing a certain column if the
16
+ * allowEditColumns prop is true
17
+ */
18
+ export let data = []
19
+ export let schema = {}
20
+ export let showAutoColumns = false
21
+ export let rowCount = 0
22
+ export let quiet = false
23
+ export let loading = false
24
+ export let allowSelectRows = true
25
+ export let allowEditRows = true
26
+ export let allowEditColumns = true
27
+ export let selectedRows = []
28
+ export let editColumnTitle = "Edit"
29
+ export let customRenderers = []
30
+ export let disableSorting = false
31
+
32
+ const dispatch = createEventDispatcher()
33
+
34
+ // Config
35
+ const rowHeight = 55
36
+ const headerHeight = 36
37
+ const rowPreload = 5
38
+
39
+ // Sorting state
40
+ let sortColumn
41
+ let sortOrder
42
+
43
+ // Table state
44
+ let height = 0
45
+ let loaded = false
46
+ $: schema = fixSchema(schema)
47
+ $: if (!loading) loaded = true
48
+ $: rows = data ?? []
49
+ $: visibleRowCount = getVisibleRowCount(loaded, height, rows.length, rowCount)
50
+ $: contentStyle = getContentStyle(visibleRowCount, rowCount)
51
+ $: sortedRows = sortRows(rows, sortColumn, sortOrder)
52
+ $: fields = getFields(schema, showAutoColumns)
53
+ $: showEditColumn = allowEditRows || allowSelectRows
54
+
55
+ // Scrolling state
56
+ let timeout
57
+ let nextScrollTop = 0
58
+ let scrollTop = 0
59
+ $: firstVisibleRow = calculateFirstVisibleRow(scrollTop)
60
+ $: lastVisibleRow = calculateLastVisibleRow(
61
+ firstVisibleRow,
62
+ visibleRowCount,
63
+ rows.length
64
+ )
65
+
66
+ // Reset state when data changes
67
+ $: rows.length, reset()
68
+ const reset = () => {
69
+ nextScrollTop = 0
70
+ scrollTop = 0
71
+ clearTimeout(timeout)
72
+ timeout = null
73
+ }
74
+
75
+ const fixSchema = schema => {
76
+ let fixedSchema = {}
77
+ Object.entries(schema || {}).forEach(([fieldName, fieldSchema]) => {
78
+ if (typeof fieldSchema === "string") {
79
+ fixedSchema[fieldName] = {
80
+ type: fieldSchema,
81
+ name: fieldName,
82
+ }
83
+ } else {
84
+ fixedSchema[fieldName] = {
85
+ ...fieldSchema,
86
+ name: fieldName,
87
+ }
88
+ }
89
+ })
90
+ return fixedSchema
91
+ }
92
+
93
+ const getVisibleRowCount = (loaded, height, allRows, rowCount) => {
94
+ if (!loaded) {
95
+ return rowCount || 0
96
+ }
97
+ if (rowCount) {
98
+ return Math.min(allRows, rowCount)
99
+ }
100
+ return Math.min(allRows, Math.ceil(height / rowHeight))
101
+ }
102
+
103
+ const getContentStyle = (visibleRows, rowCount) => {
104
+ if (!rowCount || !visibleRows) {
105
+ return ""
106
+ }
107
+ return `height: ${headerHeight + visibleRows * (rowHeight + 1)}px;`
108
+ }
109
+
110
+ const sortRows = (rows, sortColumn, sortOrder) => {
111
+ if (!sortColumn || !sortOrder || disableSorting) {
112
+ return rows
113
+ }
114
+ return rows.slice().sort((a, b) => {
115
+ const colA = a[sortColumn]
116
+ const colB = b[sortColumn]
117
+ if (sortOrder === "Descending") {
118
+ return colA > colB ? -1 : 1
119
+ } else {
120
+ return colA > colB ? 1 : -1
121
+ }
122
+ })
123
+ }
124
+
125
+ const sortBy = fieldSchema => {
126
+ if (fieldSchema.sortable === false) {
127
+ return
128
+ }
129
+ if (fieldSchema.name === sortColumn) {
130
+ sortOrder = sortOrder === "Descending" ? "Ascending" : "Descending"
131
+ } else {
132
+ sortColumn = fieldSchema.name
133
+ sortOrder = "Descending"
134
+ }
135
+ dispatch("sort", { column: sortColumn, order: sortOrder })
136
+ }
137
+
138
+ const getDisplayName = schema => {
139
+ let name = schema?.displayName
140
+ if (schema && name === undefined) {
141
+ name = schema.name
142
+ }
143
+ return name || ""
144
+ }
145
+
146
+ const getFields = (schema, showAutoColumns) => {
147
+ let columns = []
148
+ let autoColumns = []
149
+ Object.entries(schema || {}).forEach(([field, fieldSchema]) => {
150
+ if (!field || !fieldSchema) {
151
+ return
152
+ }
153
+ if (!fieldSchema?.autocolumn) {
154
+ columns.push(fieldSchema)
155
+ } else if (showAutoColumns) {
156
+ autoColumns.push(fieldSchema)
157
+ }
158
+ })
159
+ return columns
160
+ .sort((a, b) => {
161
+ const orderA = a.order || Number.MAX_SAFE_INTEGER
162
+ const orderB = b.order || Number.MAX_SAFE_INTEGER
163
+ const nameA = getDisplayName(a)
164
+ const nameB = getDisplayName(b)
165
+ if (orderA !== orderB) {
166
+ return orderA < orderB ? orderA : orderB
167
+ }
168
+ return nameA < nameB ? a : b
169
+ })
170
+ .concat(autoColumns)
171
+ .map(column => column.name)
172
+ }
173
+
174
+ const onScroll = event => {
175
+ nextScrollTop = event.target.scrollTop
176
+ if (timeout) {
177
+ return
178
+ }
179
+ timeout = setTimeout(() => {
180
+ scrollTop = nextScrollTop
181
+ timeout = null
182
+ }, 50)
183
+ }
184
+
185
+ const calculateFirstVisibleRow = scrollTop => {
186
+ return Math.max(Math.floor(scrollTop / (rowHeight + 1)) - rowPreload, 0)
187
+ }
188
+
189
+ const calculateLastVisibleRow = (firstRow, visibleRowCount, allRowCount) => {
190
+ if (visibleRowCount === 0) {
191
+ return -1
192
+ }
193
+ return Math.min(firstRow + visibleRowCount + 2 * rowPreload, allRowCount)
194
+ }
195
+
196
+ const editColumn = (e, field) => {
197
+ e.stopPropagation()
198
+ dispatch("editcolumn", field)
199
+ }
200
+
201
+ const editRow = (e, row) => {
202
+ e.stopPropagation()
203
+ dispatch("editrow", cloneDeep(row))
204
+ }
205
+
206
+ const toggleSelectRow = row => {
207
+ if (!allowSelectRows) {
208
+ return
209
+ }
210
+ if (selectedRows.includes(row)) {
211
+ selectedRows = selectedRows.filter(selectedRow => selectedRow !== row)
212
+ } else {
213
+ selectedRows = [...selectedRows, row]
214
+ }
215
+ }
216
+ </script>
217
+
218
+ <div class="wrapper" bind:offsetHeight={height}>
219
+ {#if !loaded}
220
+ <div class="loading" style={contentStyle} />
221
+ {:else}
222
+ <div
223
+ on:scroll={onScroll}
224
+ class:quiet
225
+ style={`--row-height: ${rowHeight}px; --header-height: ${headerHeight}px;`}
226
+ class="container"
227
+ >
228
+ <div style={contentStyle}>
229
+ <table class="spectrum-Table" class:spectrum-Table--quiet={quiet}>
230
+ {#if fields.length}
231
+ <thead class="spectrum-Table-head">
232
+ <tr>
233
+ {#if showEditColumn}
234
+ <th class="spectrum-Table-headCell">
235
+ <div class="spectrum-Table-headCell-content">
236
+ {editColumnTitle || ""}
237
+ </div>
238
+ </th>
239
+ {/if}
240
+ {#each fields as field}
241
+ <th
242
+ class="spectrum-Table-headCell"
243
+ class:is-sortable={schema[field].sortable !== false}
244
+ class:is-sorted-desc={sortColumn === field &&
245
+ sortOrder === "Descending"}
246
+ class:is-sorted-asc={sortColumn === field &&
247
+ sortOrder === "Ascending"}
248
+ on:click={() => sortBy(schema[field])}
249
+ >
250
+ <div class="spectrum-Table-headCell-content">
251
+ <div class="title">{getDisplayName(schema[field])}</div>
252
+ {#if schema[field]?.autocolumn}
253
+ <svg
254
+ class="spectrum-Icon spectrum-Table-autoIcon"
255
+ focusable="false"
256
+ >
257
+ <use xlink:href="#spectrum-icon-18-MagicWand" />
258
+ </svg>
259
+ {/if}
260
+ {#if sortColumn === field}
261
+ <svg
262
+ class="spectrum-Icon spectrum-UIIcon-ArrowDown100 spectrum-Table-sortedIcon"
263
+ focusable="false"
264
+ aria-hidden="true"
265
+ >
266
+ <use xlink:href="#spectrum-css-icon-Arrow100" />
267
+ </svg>
268
+ {/if}
269
+ {#if allowEditColumns && schema[field]?.editable !== false}
270
+ <svg
271
+ class="spectrum-Icon spectrum-Table-editIcon"
272
+ focusable="false"
273
+ on:click={e => editColumn(e, field)}
274
+ >
275
+ <use xlink:href="#spectrum-icon-18-Edit" />
276
+ </svg>
277
+ {/if}
278
+ </div>
279
+ </th>
280
+ {/each}
281
+ </tr>
282
+ </thead>
283
+ {/if}
284
+ <tbody class="spectrum-Table-body">
285
+ {#if sortedRows?.length && fields.length}
286
+ {#each sortedRows as row, idx}
287
+ <tr
288
+ on:click={() => dispatch("click", row)}
289
+ on:click={() => toggleSelectRow(row)}
290
+ class="spectrum-Table-row"
291
+ class:hidden={idx < firstVisibleRow || idx > lastVisibleRow}
292
+ >
293
+ {#if idx >= firstVisibleRow && idx <= lastVisibleRow}
294
+ {#if showEditColumn}
295
+ <td
296
+ class="spectrum-Table-cell spectrum-Table-cell--divider"
297
+ >
298
+ <div class="spectrum-Table-cell-content">
299
+ <SelectEditRenderer
300
+ data={row}
301
+ selected={selectedRows.includes(row)}
302
+ onToggleSelection={() => toggleSelectRow(row)}
303
+ onEdit={e => editRow(e, row)}
304
+ {allowSelectRows}
305
+ {allowEditRows}
306
+ />
307
+ </div>
308
+ </td>
309
+ {/if}
310
+ {#each fields as field}
311
+ <td
312
+ class="spectrum-Table-cell"
313
+ class:spectrum-Table-cell--divider={!!schema[field]
314
+ .divider}
315
+ >
316
+ <div class="spectrum-Table-cell-content">
317
+ <CellRenderer
318
+ {customRenderers}
319
+ {row}
320
+ schema={schema[field]}
321
+ value={row[field]}
322
+ on:clickrelationship
323
+ >
324
+ <slot />
325
+ </CellRenderer>
326
+ </div>
327
+ </td>
328
+ {/each}
329
+ {/if}
330
+ </tr>
331
+ {/each}
332
+ {:else}
333
+ <tr class="placeholder-row">
334
+ {#if showEditColumn}
335
+ <td class="placeholder-offset" />
336
+ {/if}
337
+ {#each fields as field}
338
+ <td />
339
+ {/each}
340
+ <div class="placeholder" class:has-fields={fields.length > 0}>
341
+ <div class="placeholder-content">
342
+ <svg
343
+ class="spectrum-Icon spectrum-Icon--sizeXXL"
344
+ focusable="false"
345
+ >
346
+ <use xlink:href="#spectrum-icon-18-Table" />
347
+ </svg>
348
+ <div>No rows found</div>
349
+ </div>
350
+ </div>
351
+ </tr>
352
+ {/if}
353
+ </tbody>
354
+ </table>
355
+ </div>
356
+ </div>
357
+ {/if}
358
+ </div>
359
+
360
+ <style>
361
+ .wrapper {
362
+ background-color: var(--spectrum-alias-background-color-secondary);
363
+ overflow: hidden;
364
+ position: relative;
365
+ z-index: 0;
366
+ }
367
+
368
+ .container {
369
+ height: 100%;
370
+ position: relative;
371
+ overflow: auto;
372
+ }
373
+ .container.quiet {
374
+ border: none;
375
+ }
376
+ table {
377
+ width: 100%;
378
+ }
379
+
380
+ .spectrum-Table-headCell .spectrum-Icon {
381
+ pointer-events: all;
382
+ margin-left: var(
383
+ --spectrum-table-header-sort-icon-gap,
384
+ var(--spectrum-global-dimension-size-125)
385
+ );
386
+ }
387
+ .spectrum-Table-editIcon,
388
+ .spectrum-Table-autoIcon {
389
+ width: var(--spectrum-global-dimension-size-150);
390
+ height: var(--spectrum-global-dimension-size-150);
391
+ }
392
+ .spectrum-Table-editIcon {
393
+ opacity: 0;
394
+ }
395
+ .spectrum-Table-headCell:hover .spectrum-Table-editIcon {
396
+ opacity: 1;
397
+ transition: opacity 0.2s ease;
398
+ }
399
+
400
+ th {
401
+ vertical-align: middle;
402
+ height: var(--header-height);
403
+ position: sticky;
404
+ top: 0;
405
+ z-index: 2;
406
+ background-color: var(--spectrum-alias-background-color-secondary);
407
+ border-bottom: 1px solid
408
+ var(--spectrum-table-border-color, var(--spectrum-alias-border-color-mid));
409
+ }
410
+ .spectrum-Table-headCell-content {
411
+ white-space: nowrap;
412
+ display: flex;
413
+ flex-direction: row;
414
+ justify-content: flex-start;
415
+ align-items: center;
416
+ user-select: none;
417
+ }
418
+ .spectrum-Table-headCell-content .title {
419
+ overflow: hidden;
420
+ text-overflow: ellipsis;
421
+ }
422
+
423
+ .placeholder-row {
424
+ position: relative;
425
+ height: 150px;
426
+ }
427
+ .placeholder-row td {
428
+ border-top: none !important;
429
+ border-bottom: none !important;
430
+ }
431
+ .placeholder-offset {
432
+ width: 1px;
433
+ }
434
+ .placeholder {
435
+ top: 0;
436
+ height: 100%;
437
+ left: 0;
438
+ width: 100%;
439
+ position: absolute;
440
+ display: flex;
441
+ flex-direction: row;
442
+ justify-content: center;
443
+ align-items: center;
444
+ }
445
+ .placeholder.has-fields {
446
+ top: var(--header-height);
447
+ height: calc(100% - var(--header-height));
448
+ }
449
+
450
+ .placeholder-content {
451
+ padding: 20px;
452
+ display: flex;
453
+ flex-direction: column;
454
+ justify-content: center;
455
+ align-items: center;
456
+ color: var(
457
+ --spectrum-table-cell-text-color,
458
+ var(--spectrum-alias-text-color)
459
+ );
460
+ }
461
+ .placeholder-content div {
462
+ margin-top: 10px;
463
+ font-size: var(
464
+ --spectrum-table-cell-text-size,
465
+ var(--spectrum-alias-font-size-default)
466
+ );
467
+ text-align: center;
468
+ }
469
+
470
+ tbody {
471
+ z-index: 1;
472
+ }
473
+ tbody tr {
474
+ height: var(--row-height);
475
+ }
476
+ tbody tr.hidden {
477
+ height: calc(var(--row-height) + 1px);
478
+ }
479
+ td {
480
+ padding-top: 0;
481
+ padding-bottom: 0;
482
+ border-bottom: none;
483
+ border-top: 1px solid
484
+ var(--spectrum-table-border-color, var(--spectrum-alias-border-color-mid));
485
+ border-radius: 0;
486
+ }
487
+ tr:first-child td {
488
+ border-top: none;
489
+ }
490
+ tr:last-child td {
491
+ border-bottom: 1px solid
492
+ var(--spectrum-table-border-color, var(--spectrum-alias-border-color-mid));
493
+ }
494
+ td.spectrum-Table-cell--divider {
495
+ width: 1px;
496
+ }
497
+ .spectrum-Table-cell-content {
498
+ height: var(--row-height);
499
+ white-space: nowrap;
500
+ display: flex;
501
+ flex-direction: row;
502
+ justify-content: flex-start;
503
+ align-items: center;
504
+ gap: 4px;
505
+ }
506
+ </style>
@@ -0,0 +1 @@
1
+ export { default as Table } from "./Table.svelte"
@@ -0,0 +1,66 @@
1
+ <script>
2
+ import { getContext, onMount, createEventDispatcher } from "svelte"
3
+ import Portal from "svelte-portal"
4
+ export let title
5
+ export let icon = ""
6
+
7
+ const dispatch = createEventDispatcher()
8
+ const selected = getContext("tab")
9
+ let tab
10
+ let tabInfo
11
+
12
+ const setTabInfo = () => {
13
+ // If the tabs are being rendered inside a component which uses
14
+ // a svelte transition to enter, then this initial getBoundingClientRect
15
+ // will return an incorrect position.
16
+ // We just need to get this off the main thread to fix this, by using
17
+ // a 0ms timeout.
18
+ setTimeout(() => {
19
+ tabInfo = tab.getBoundingClientRect()
20
+ if ($selected.title === title) {
21
+ $selected.info = tabInfo
22
+ }
23
+ }, 0)
24
+ }
25
+
26
+ onMount(() => {
27
+ setTabInfo()
28
+ })
29
+
30
+ const onClick = () => {
31
+ $selected = { ...$selected, title, info: tab.getBoundingClientRect() }
32
+ dispatch("click")
33
+ }
34
+ </script>
35
+
36
+ <div
37
+ bind:this={tab}
38
+ on:click={onClick}
39
+ class:is-selected={$selected.title === title}
40
+ class="spectrum-Tabs-item"
41
+ class:emphasized={$selected.title === title && $selected.emphasized}
42
+ tabindex="0"
43
+ >
44
+ {#if icon}
45
+ <svg
46
+ class="spectrum-Icon spectrum-Icon--sizeM"
47
+ focusable="false"
48
+ aria-hidden="true"
49
+ aria-label="Folder"
50
+ >
51
+ <use xlink:href="#spectrum-icon-18-{icon}" />
52
+ </svg>
53
+ {/if}
54
+ <span class="spectrum-Tabs-itemLabel">{title}</span>
55
+ </div>
56
+ {#if $selected.title === title}
57
+ <Portal target=".spectrum-Tabs-content-{$selected.id}">
58
+ <slot />
59
+ </Portal>
60
+ {/if}
61
+
62
+ <style>
63
+ .emphasized {
64
+ color: var(--spectrum-global-color-blue-600);
65
+ }
66
+ </style>
@@ -0,0 +1,105 @@
1
+ <script>
2
+ import "@spectrum-css/tabs/dist/index-vars.css"
3
+ import { writable } from "svelte/store"
4
+ import { onMount, setContext, createEventDispatcher } from "svelte"
5
+
6
+ export let selected
7
+ export let vertical = false
8
+ export let noPadding = false
9
+ export let quiet = false
10
+ export let emphasized = false
11
+
12
+ let _id = id()
13
+ const tab = writable({ title: selected, id: _id, emphasized })
14
+ setContext("tab", tab)
15
+
16
+ let container
17
+
18
+ const dispatch = createEventDispatcher()
19
+
20
+ $: {
21
+ if ($tab.title !== selected) {
22
+ selected = $tab.title
23
+ dispatch("select", selected)
24
+ }
25
+ }
26
+
27
+ let top, left, width, height
28
+ $: calculateIndicatorLength($tab)
29
+ $: calculateIndicatorOffset($tab)
30
+
31
+ function calculateIndicatorLength() {
32
+ if (!vertical) {
33
+ width = $tab.info?.width + "px"
34
+ height = $tab.info?.height
35
+ } else {
36
+ height = $tab.info?.height + 4 + "px"
37
+ width = $tab.info?.width
38
+ }
39
+ }
40
+
41
+ function calculateIndicatorOffset() {
42
+ if (!vertical) {
43
+ left = $tab.info?.left - container?.getBoundingClientRect().left + "px"
44
+ } else {
45
+ top = $tab.info?.top - container?.getBoundingClientRect().top + "px"
46
+ }
47
+ }
48
+
49
+ onMount(() => {
50
+ calculateIndicatorLength()
51
+ calculateIndicatorOffset()
52
+ })
53
+
54
+ function id() {
55
+ return "_" + Math.random().toString(36).substr(2, 9)
56
+ }
57
+ </script>
58
+
59
+ <div
60
+ bind:this={container}
61
+ class:quiet
62
+ class="selected-border spectrum-Tabs {quiet &&
63
+ 'spectrum-Tabs--quiet'} spectrum-Tabs--{vertical
64
+ ? 'vertical'
65
+ : 'horizontal'}"
66
+ >
67
+ <slot />
68
+ {#if $tab.info}
69
+ <div
70
+ class="spectrum-Tabs-selectionIndicator indicator-transition"
71
+ style="{emphasized &&
72
+ 'background-color: var(--spectrum-global-color-blue-400)'}; width: {width}; height: {height}; left: {left}; top: {top};"
73
+ />
74
+ {/if}
75
+ </div>
76
+
77
+ <div
78
+ class="spectrum-Tabs-content spectrum-Tabs-content-{_id}"
79
+ class:noPadding
80
+ />
81
+
82
+ <style>
83
+ .quiet {
84
+ border-bottom: none !important;
85
+ }
86
+
87
+ .spectrum-Tabs {
88
+ padding-left: var(--spacing-xl);
89
+ padding-right: var(--spacing-xl);
90
+ position: relative;
91
+ border-bottom: var(--border-light);
92
+ }
93
+ .spectrum-Tabs-content {
94
+ margin-top: var(--spectrum-global-dimension-static-size-150);
95
+ }
96
+ .indicator-transition {
97
+ transition: all 200ms;
98
+ }
99
+ .spectrum-Tabs--horizontal .spectrum-Tabs-selectionIndicator {
100
+ bottom: 0 !important;
101
+ }
102
+ .noPadding {
103
+ margin: 0;
104
+ }
105
+ </style>