@budibase/bbui 1.1.1 → 1.1.2
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.
- package/LICENSE +375 -0
- package/README.md +19 -17
- package/dist/bbui.es.js +210 -0
- package/dist/bbui.es.js.map +1 -0
- package/package.json +71 -26
- package/src/ActionButton/ActionButton.svelte +95 -0
- package/src/ActionGroup/ActionGroup.svelte +26 -0
- package/src/ActionMenu/ActionMenu.svelte +44 -0
- package/src/Actions/ClickOutside.svench.svx +30 -0
- package/src/Actions/PositionDropdown.svench.svx +81 -0
- package/src/Actions/autoresize_textarea.js +14 -0
- package/src/Actions/click_outside.js +18 -0
- package/src/Actions/position_dropdown.js +66 -0
- package/src/Avatar/Avatar.svelte +49 -0
- package/src/Badge/Badge.svelte +29 -0
- package/src/Banner/Banner.svelte +72 -0
- package/src/Banner/BannerDisplay.svelte +31 -0
- package/src/Button/Button.svelte +114 -0
- package/src/Button/Button.svench +138 -0
- package/src/ButtonGroup/ButtonGroup.svelte +30 -0
- package/src/ClearButton/ClearButton.svelte +19 -0
- package/src/ColorPicker/ColorPicker.svelte +297 -0
- package/src/DetailSummary/DetailSummary.svelte +83 -0
- package/src/Divider/Divider.svelte +28 -0
- package/src/Drawer/Drawer.svelte +112 -0
- package/src/Drawer/Drawer.svench +42 -0
- package/src/Drawer/DrawerContent.svelte +46 -0
- package/src/Form/Checkbox.svelte +23 -0
- package/src/Form/Combobox.svelte +45 -0
- package/src/Form/Core/Checkbox.svelte +69 -0
- package/src/Form/Core/CheckboxGroup.svelte +68 -0
- package/src/Form/Core/Combobox.svelte +142 -0
- package/src/Form/Core/DatePicker.svelte +242 -0
- package/src/Form/Core/Dropzone.svelte +438 -0
- package/src/Form/Core/Multiselect.svelte +88 -0
- package/src/Form/Core/Picker.svelte +256 -0
- package/src/Form/Core/RadioGroup.svelte +47 -0
- package/src/Form/Core/RichTextField.svelte +42 -0
- package/src/Form/Core/Search.svelte +105 -0
- package/src/Form/Core/Select.svelte +76 -0
- package/src/Form/Core/Slider.svelte +86 -0
- package/src/Form/Core/Stepper.svelte +172 -0
- package/src/Form/Core/Switch.svelte +37 -0
- package/src/Form/Core/TextArea.svelte +78 -0
- package/src/Form/Core/TextField.svelte +119 -0
- package/src/Form/Core/index.js +15 -0
- package/src/Form/DatePicker.svelte +37 -0
- package/src/Form/Dropzone.svelte +40 -0
- package/src/Form/Field.svelte +42 -0
- package/src/Form/FieldLabel.svelte +32 -0
- package/src/Form/Input.svelte +40 -45
- package/src/Form/Multiselect.svelte +39 -0
- package/src/Form/RadioGroup.svelte +40 -0
- package/src/Form/RichTextField.svelte +36 -0
- package/src/Form/Search.svelte +36 -0
- package/src/Form/Select.svelte +48 -43
- package/src/Form/Slider.svelte +24 -0
- package/src/Form/Stepper.svelte +45 -0
- package/src/Form/TextArea.svelte +29 -44
- package/src/Form/Toggle.svelte +23 -0
- package/src/Icon/Icon.svelte +86 -0
- package/src/IconSideNav/IconSideNav.svelte +14 -0
- package/src/IconSideNav/IconSideNavItem.svelte +56 -0
- package/src/InlineAlert/InlineAlert.svelte +56 -0
- package/src/Label/Label.svelte +20 -0
- package/src/Layout/Layout.svelte +94 -0
- package/src/Layout/Page.svelte +32 -0
- package/src/Link/Link.svelte +22 -0
- package/src/List/Items/DetailSummary.svench +46 -8
- package/src/Markdown/MarkdownEditor.svelte +60 -0
- package/src/Markdown/MarkdownViewer.svelte +70 -0
- package/src/Markdown/SpectrumMDE.svelte +184 -0
- package/src/Menu/Item.svelte +45 -0
- package/src/Menu/Menu.svelte +7 -0
- package/src/Menu/Menu.svench +19 -0
- package/src/Menu/Section.svelte +10 -0
- package/src/Menu/Separator.svelte +1 -0
- package/src/Modal/Content.svelte +6 -0
- package/src/Modal/CustomContent.svelte +38 -0
- package/src/Modal/Modal.svelte +142 -0
- package/src/Modal/Modal.svench +117 -0
- package/src/Modal/ModalContent.svelte +190 -0
- package/src/Modal/QuizModal.svelte +54 -0
- package/src/Notification/Notification.svelte +70 -0
- package/src/Notification/NotificationDisplay.svelte +43 -0
- package/src/Pagination/Pagination.svelte +57 -0
- package/src/Popover/Popover.svelte +77 -0
- package/src/Popover/Popover.svench +121 -0
- package/src/ProgressBar/ProgressBar.svelte +54 -0
- package/src/ProgressCircle/ProgressCircle.svelte +62 -0
- package/src/SideNavigation/Item.svelte +47 -0
- package/src/SideNavigation/Navigation.svelte +12 -0
- package/src/StatusLight/StatusLight.svelte +64 -0
- package/src/Stores/Notifications.svench.svx +78 -0
- package/src/Stores/banner.js +37 -0
- package/src/Stores/notifications.js +84 -0
- package/src/Table/ArrayRenderer.svelte +17 -0
- package/src/Table/AttachmentRenderer.svelte +60 -0
- package/src/Table/BoldRenderer.svelte +15 -0
- package/src/Table/BooleanRenderer.svelte +42 -0
- package/src/Table/CellRenderer.svelte +69 -0
- package/src/Table/CodeRenderer.svelte +14 -0
- package/src/Table/DateTimeRenderer.svelte +29 -0
- package/src/Table/InternalRenderer.svelte +24 -0
- package/src/Table/RelationshipRenderer.svelte +40 -0
- package/src/Table/SelectEditRenderer.svelte +28 -0
- package/src/Table/StringRenderer.svelte +14 -0
- package/src/Table/Table.svelte +631 -0
- package/src/Table/index.js +1 -0
- package/src/Tabs/Tab.svelte +88 -0
- package/src/Tabs/Tabs.svelte +125 -0
- package/src/Tags/Tag.svelte +43 -0
- package/src/Tags/Tags.svelte +7 -0
- package/src/Tooltip/Tooltip.svelte +30 -0
- package/src/Tooltip/TooltipWrapper.svelte +60 -0
- package/src/TreeView/Item.svelte +41 -0
- package/src/TreeView/Tree.svelte +16 -0
- package/src/Typography/Body.svelte +21 -0
- package/src/Typography/Code.svelte +10 -0
- package/src/Typography/Detail.svelte +19 -0
- package/src/Typography/Heading.svelte +17 -0
- package/src/bbui.css +96 -0
- package/src/context.js +3 -0
- package/src/helpers.js +134 -0
- package/src/index.js +91 -11
- package/src/spectrum-icons-rollup.js +31 -0
- package/src/spectrum-icons-vite.js +31 -0
- package/dist/bundle.css +0 -7
- package/dist/bundle.css.map +0 -20
- package/dist/index.js +0 -1045
- package/dist/index.mjs +0 -1031
- package/src/Branding/Budibase-logo.svelte +0 -68
- package/src/Branding/Logo.svelte +0 -16
- package/src/Branding/Logo.svench +0 -8
- package/src/Form/Button.svelte +0 -52
- package/src/Form/Button.svench +0 -26
- package/src/Form/Input.svench +0 -8
- package/src/Form/Select.svench +0 -8
- package/src/Form/TextArea.svench +0 -8
- package/src/Links/Home.svelte +0 -49
- package/src/Links/Home.svench +0 -19
- package/src/List/Items/DetailSummary.svelte +0 -66
- package/src/actions/autoresize_textarea.js +0 -14
- package/src/icons/Contribution.svelte +0 -14
- package/src/index.svench.svx +0 -35
|
@@ -0,0 +1,631 @@
|
|
|
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, deepGet } from "../helpers"
|
|
7
|
+
import ProgressCircle from "../ProgressCircle/ProgressCircle.svelte"
|
|
8
|
+
import Checkbox from "../Form/Checkbox.svelte"
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The expected schema is our normal couch schemas for our tables.
|
|
12
|
+
* Each field schema can be enriched with a few extra properties to customise
|
|
13
|
+
* the behaviour.
|
|
14
|
+
* All of these are optional and do not need to be added.
|
|
15
|
+
* displayName: Overrides the field name displayed as the column title
|
|
16
|
+
* sortable: Set to false to disable sorting data by a certain column
|
|
17
|
+
* editable: Set to false to disable editing a certain column if the
|
|
18
|
+
* allowEditColumns prop is true
|
|
19
|
+
* width: the width of the column
|
|
20
|
+
* align: the alignment of the column
|
|
21
|
+
* template: a HBS or JS binding to use as the value
|
|
22
|
+
* background: the background color
|
|
23
|
+
* color: the text color
|
|
24
|
+
*/
|
|
25
|
+
export let data = []
|
|
26
|
+
export let schema = {}
|
|
27
|
+
export let showAutoColumns = false
|
|
28
|
+
export let rowCount = 0
|
|
29
|
+
export let quiet = false
|
|
30
|
+
export let loading = false
|
|
31
|
+
export let allowSelectRows
|
|
32
|
+
export let allowEditRows = true
|
|
33
|
+
export let allowEditColumns = true
|
|
34
|
+
export let selectedRows = []
|
|
35
|
+
export let customRenderers = []
|
|
36
|
+
export let disableSorting = false
|
|
37
|
+
export let autoSortColumns = true
|
|
38
|
+
export let compact = false
|
|
39
|
+
export let customPlaceholder = false
|
|
40
|
+
export let placeholderText = "No rows found"
|
|
41
|
+
|
|
42
|
+
const dispatch = createEventDispatcher()
|
|
43
|
+
|
|
44
|
+
// Config
|
|
45
|
+
const headerHeight = 36
|
|
46
|
+
$: rowHeight = compact ? 46 : 55
|
|
47
|
+
|
|
48
|
+
// Sorting state
|
|
49
|
+
let sortColumn
|
|
50
|
+
let sortOrder
|
|
51
|
+
|
|
52
|
+
// Table state
|
|
53
|
+
let height = 0
|
|
54
|
+
let loaded = false
|
|
55
|
+
let checkboxStatus = false
|
|
56
|
+
|
|
57
|
+
$: schema = fixSchema(schema)
|
|
58
|
+
$: if (!loading) loaded = true
|
|
59
|
+
$: fields = getFields(schema, showAutoColumns, autoSortColumns)
|
|
60
|
+
$: rows = fields?.length ? data || [] : []
|
|
61
|
+
$: totalRowCount = rows?.length || 0
|
|
62
|
+
$: visibleRowCount = getVisibleRowCount(
|
|
63
|
+
loaded,
|
|
64
|
+
height,
|
|
65
|
+
rows.length,
|
|
66
|
+
rowCount,
|
|
67
|
+
rowHeight
|
|
68
|
+
)
|
|
69
|
+
$: heightStyle = getHeightStyle(
|
|
70
|
+
visibleRowCount,
|
|
71
|
+
rowCount,
|
|
72
|
+
totalRowCount,
|
|
73
|
+
rowHeight
|
|
74
|
+
)
|
|
75
|
+
$: sortedRows = sortRows(rows, sortColumn, sortOrder)
|
|
76
|
+
$: gridStyle = getGridStyle(fields, schema, showEditColumn)
|
|
77
|
+
$: showEditColumn = allowEditRows || allowSelectRows
|
|
78
|
+
$: cellStyles = computeCellStyles(schema)
|
|
79
|
+
|
|
80
|
+
// Deselect the "select all" checkbox when the user navigates to a new page
|
|
81
|
+
$: {
|
|
82
|
+
let checkRowCount = rows.filter(o1 =>
|
|
83
|
+
selectedRows.some(o2 => o1._id === o2._id)
|
|
84
|
+
)
|
|
85
|
+
if (checkRowCount.length === 0) {
|
|
86
|
+
checkboxStatus = false
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const fixSchema = schema => {
|
|
91
|
+
let fixedSchema = {}
|
|
92
|
+
Object.entries(schema || {}).forEach(([fieldName, fieldSchema]) => {
|
|
93
|
+
if (typeof fieldSchema === "string") {
|
|
94
|
+
fixedSchema[fieldName] = {
|
|
95
|
+
type: fieldSchema,
|
|
96
|
+
name: fieldName,
|
|
97
|
+
}
|
|
98
|
+
} else {
|
|
99
|
+
fixedSchema[fieldName] = {
|
|
100
|
+
...fieldSchema,
|
|
101
|
+
name: fieldName,
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
})
|
|
105
|
+
return fixedSchema
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const getVisibleRowCount = (loaded, height, allRows, rowCount, rowHeight) => {
|
|
109
|
+
if (!loaded) {
|
|
110
|
+
return rowCount || 0
|
|
111
|
+
}
|
|
112
|
+
if (rowCount) {
|
|
113
|
+
return Math.min(allRows, rowCount)
|
|
114
|
+
}
|
|
115
|
+
return Math.min(allRows, Math.ceil(height / rowHeight))
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const getHeightStyle = (
|
|
119
|
+
visibleRowCount,
|
|
120
|
+
rowCount,
|
|
121
|
+
totalRowCount,
|
|
122
|
+
rowHeight
|
|
123
|
+
) => {
|
|
124
|
+
if (!rowCount || !visibleRowCount || totalRowCount <= rowCount) {
|
|
125
|
+
return ""
|
|
126
|
+
}
|
|
127
|
+
return `height: ${headerHeight + visibleRowCount * rowHeight}px;`
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const getGridStyle = (fields, schema, showEditColumn) => {
|
|
131
|
+
let style = "grid-template-columns:"
|
|
132
|
+
if (showEditColumn) {
|
|
133
|
+
style += " auto"
|
|
134
|
+
}
|
|
135
|
+
fields?.forEach(field => {
|
|
136
|
+
const fieldSchema = schema[field]
|
|
137
|
+
if (fieldSchema.width) {
|
|
138
|
+
style += ` ${fieldSchema.width}`
|
|
139
|
+
} else {
|
|
140
|
+
style += " minmax(auto, 1fr)"
|
|
141
|
+
}
|
|
142
|
+
})
|
|
143
|
+
style += ";"
|
|
144
|
+
return style
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const sortRows = (rows, sortColumn, sortOrder) => {
|
|
148
|
+
if (!sortColumn || !sortOrder || disableSorting) {
|
|
149
|
+
return rows
|
|
150
|
+
}
|
|
151
|
+
return rows.slice().sort((a, b) => {
|
|
152
|
+
const colA = a[sortColumn]
|
|
153
|
+
const colB = b[sortColumn]
|
|
154
|
+
if (sortOrder === "Descending") {
|
|
155
|
+
return colA > colB ? -1 : 1
|
|
156
|
+
} else {
|
|
157
|
+
return colA > colB ? 1 : -1
|
|
158
|
+
}
|
|
159
|
+
})
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const sortBy = fieldSchema => {
|
|
163
|
+
if (fieldSchema.sortable === false) {
|
|
164
|
+
return
|
|
165
|
+
}
|
|
166
|
+
if (fieldSchema.name === sortColumn) {
|
|
167
|
+
sortOrder = sortOrder === "Descending" ? "Ascending" : "Descending"
|
|
168
|
+
} else {
|
|
169
|
+
sortColumn = fieldSchema.name
|
|
170
|
+
sortOrder = "Descending"
|
|
171
|
+
}
|
|
172
|
+
dispatch("sort", { column: sortColumn, order: sortOrder })
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const getDisplayName = schema => {
|
|
176
|
+
let name = schema?.displayName
|
|
177
|
+
if (schema && name === undefined) {
|
|
178
|
+
name = schema.name
|
|
179
|
+
}
|
|
180
|
+
return name || ""
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const getFields = (schema, showAutoColumns, autoSortColumns) => {
|
|
184
|
+
let columns = []
|
|
185
|
+
let autoColumns = []
|
|
186
|
+
Object.entries(schema || {}).forEach(([field, fieldSchema]) => {
|
|
187
|
+
if (!field || !fieldSchema) {
|
|
188
|
+
return
|
|
189
|
+
}
|
|
190
|
+
if (!autoSortColumns || !fieldSchema?.autocolumn) {
|
|
191
|
+
columns.push(fieldSchema)
|
|
192
|
+
} else if (showAutoColumns) {
|
|
193
|
+
autoColumns.push(fieldSchema)
|
|
194
|
+
}
|
|
195
|
+
})
|
|
196
|
+
return columns
|
|
197
|
+
.sort((a, b) => {
|
|
198
|
+
const orderA = a.order || Number.MAX_SAFE_INTEGER
|
|
199
|
+
const orderB = b.order || Number.MAX_SAFE_INTEGER
|
|
200
|
+
const nameA = getDisplayName(a)
|
|
201
|
+
const nameB = getDisplayName(b)
|
|
202
|
+
if (orderA !== orderB) {
|
|
203
|
+
return orderA < orderB ? orderA : orderB
|
|
204
|
+
}
|
|
205
|
+
return nameA < nameB ? a : b
|
|
206
|
+
})
|
|
207
|
+
.concat(autoColumns)
|
|
208
|
+
.map(column => column.name)
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const editColumn = (e, field) => {
|
|
212
|
+
e.stopPropagation()
|
|
213
|
+
dispatch("editcolumn", field)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const editRow = (e, row) => {
|
|
217
|
+
e.stopPropagation()
|
|
218
|
+
dispatch("editrow", cloneDeep(row))
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const toggleSelectRow = row => {
|
|
222
|
+
if (!allowSelectRows) {
|
|
223
|
+
return
|
|
224
|
+
}
|
|
225
|
+
if (selectedRows.some(selectedRow => selectedRow._id === row._id)) {
|
|
226
|
+
selectedRows = selectedRows.filter(
|
|
227
|
+
selectedRow => selectedRow._id !== row._id
|
|
228
|
+
)
|
|
229
|
+
} else {
|
|
230
|
+
selectedRows = [...selectedRows, row]
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const toggleSelectAll = e => {
|
|
235
|
+
const select = !!e.detail
|
|
236
|
+
if (select) {
|
|
237
|
+
// Add any rows which are not already in selected rows
|
|
238
|
+
rows.forEach(row => {
|
|
239
|
+
if (selectedRows.findIndex(x => x._id === row._id) === -1) {
|
|
240
|
+
selectedRows.push(row)
|
|
241
|
+
}
|
|
242
|
+
})
|
|
243
|
+
} else {
|
|
244
|
+
// Remove any rows from selected rows that are in the current data set
|
|
245
|
+
selectedRows = selectedRows.filter(el =>
|
|
246
|
+
rows.every(f => f._id !== el._id)
|
|
247
|
+
)
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const computeCellStyles = schema => {
|
|
252
|
+
let styles = {}
|
|
253
|
+
Object.keys(schema || {}).forEach(field => {
|
|
254
|
+
styles[field] = ""
|
|
255
|
+
if (schema[field].color) {
|
|
256
|
+
styles[field] += `color: ${schema[field].color};`
|
|
257
|
+
}
|
|
258
|
+
if (schema[field].background) {
|
|
259
|
+
styles[field] += `background-color: ${schema[field].background};`
|
|
260
|
+
}
|
|
261
|
+
if (schema[field].align === "Center") {
|
|
262
|
+
styles[field] += "justify-content: center; text-align: center;"
|
|
263
|
+
}
|
|
264
|
+
if (schema[field].align === "Right") {
|
|
265
|
+
styles[field] += "justify-content: flex-end; text-align: right;"
|
|
266
|
+
}
|
|
267
|
+
})
|
|
268
|
+
return styles
|
|
269
|
+
}
|
|
270
|
+
</script>
|
|
271
|
+
|
|
272
|
+
<div
|
|
273
|
+
class="wrapper"
|
|
274
|
+
class:wrapper--quiet={quiet}
|
|
275
|
+
class:wrapper--compact={compact}
|
|
276
|
+
bind:offsetHeight={height}
|
|
277
|
+
style={`--row-height: ${rowHeight}px; --header-height: ${headerHeight}px;`}
|
|
278
|
+
>
|
|
279
|
+
{#if !loaded}
|
|
280
|
+
<div class="loading" style={heightStyle}>
|
|
281
|
+
<ProgressCircle />
|
|
282
|
+
</div>
|
|
283
|
+
{:else}
|
|
284
|
+
<div class="spectrum-Table" style={`${heightStyle}${gridStyle}`}>
|
|
285
|
+
{#if fields.length}
|
|
286
|
+
<div class="spectrum-Table-head">
|
|
287
|
+
{#if showEditColumn}
|
|
288
|
+
<div
|
|
289
|
+
class="spectrum-Table-headCell spectrum-Table-headCell--divider spectrum-Table-headCell--edit"
|
|
290
|
+
>
|
|
291
|
+
{#if allowSelectRows}
|
|
292
|
+
<Checkbox
|
|
293
|
+
bind:value={checkboxStatus}
|
|
294
|
+
on:change={toggleSelectAll}
|
|
295
|
+
/>
|
|
296
|
+
{:else}
|
|
297
|
+
Edit
|
|
298
|
+
{/if}
|
|
299
|
+
</div>
|
|
300
|
+
{/if}
|
|
301
|
+
{#each fields as field}
|
|
302
|
+
<div
|
|
303
|
+
class="spectrum-Table-headCell"
|
|
304
|
+
class:spectrum-Table-headCell--alignCenter={schema[field]
|
|
305
|
+
.align === "Center"}
|
|
306
|
+
class:spectrum-Table-headCell--alignRight={schema[field].align ===
|
|
307
|
+
"Right"}
|
|
308
|
+
class:is-sortable={schema[field].sortable !== false}
|
|
309
|
+
class:is-sorted-desc={sortColumn === field &&
|
|
310
|
+
sortOrder === "Descending"}
|
|
311
|
+
class:is-sorted-asc={sortColumn === field &&
|
|
312
|
+
sortOrder === "Ascending"}
|
|
313
|
+
on:click={() => sortBy(schema[field])}
|
|
314
|
+
>
|
|
315
|
+
<div class="title">{getDisplayName(schema[field])}</div>
|
|
316
|
+
{#if schema[field]?.autocolumn}
|
|
317
|
+
<svg
|
|
318
|
+
class="spectrum-Icon spectrum-Table-autoIcon"
|
|
319
|
+
focusable="false"
|
|
320
|
+
>
|
|
321
|
+
<use xlink:href="#spectrum-icon-18-MagicWand" />
|
|
322
|
+
</svg>
|
|
323
|
+
{/if}
|
|
324
|
+
{#if sortColumn === field}
|
|
325
|
+
<svg
|
|
326
|
+
class="spectrum-Icon spectrum-UIIcon-ArrowDown100 spectrum-Table-sortedIcon"
|
|
327
|
+
focusable="false"
|
|
328
|
+
aria-hidden="true"
|
|
329
|
+
>
|
|
330
|
+
<use xlink:href="#spectrum-css-icon-Arrow100" />
|
|
331
|
+
</svg>
|
|
332
|
+
{/if}
|
|
333
|
+
{#if allowEditColumns && schema[field]?.editable !== false}
|
|
334
|
+
<svg
|
|
335
|
+
class="spectrum-Icon spectrum-Table-editIcon"
|
|
336
|
+
focusable="false"
|
|
337
|
+
on:click={e => editColumn(e, field)}
|
|
338
|
+
>
|
|
339
|
+
<use xlink:href="#spectrum-icon-18-Edit" />
|
|
340
|
+
</svg>
|
|
341
|
+
{/if}
|
|
342
|
+
</div>
|
|
343
|
+
{/each}
|
|
344
|
+
</div>
|
|
345
|
+
{/if}
|
|
346
|
+
{#if sortedRows?.length}
|
|
347
|
+
{#each sortedRows as row, idx}
|
|
348
|
+
<div class="spectrum-Table-row">
|
|
349
|
+
{#if showEditColumn}
|
|
350
|
+
<div
|
|
351
|
+
class="spectrum-Table-cell spectrum-Table-cell--divider spectrum-Table-cell--edit"
|
|
352
|
+
on:click={e => {
|
|
353
|
+
toggleSelectRow(row)
|
|
354
|
+
e.stopPropagation()
|
|
355
|
+
}}
|
|
356
|
+
>
|
|
357
|
+
<SelectEditRenderer
|
|
358
|
+
data={row}
|
|
359
|
+
selected={selectedRows.findIndex(
|
|
360
|
+
selectedRow => selectedRow._id === row._id
|
|
361
|
+
) !== -1}
|
|
362
|
+
onEdit={e => editRow(e, row)}
|
|
363
|
+
{allowSelectRows}
|
|
364
|
+
{allowEditRows}
|
|
365
|
+
/>
|
|
366
|
+
</div>
|
|
367
|
+
{/if}
|
|
368
|
+
{#each fields as field}
|
|
369
|
+
<div
|
|
370
|
+
class="spectrum-Table-cell"
|
|
371
|
+
class:spectrum-Table-cell--divider={!!schema[field].divider}
|
|
372
|
+
style={cellStyles[field]}
|
|
373
|
+
on:click={() => {
|
|
374
|
+
if (!schema[field]?.preventSelectRow) {
|
|
375
|
+
dispatch("click", row)
|
|
376
|
+
toggleSelectRow(row)
|
|
377
|
+
}
|
|
378
|
+
}}
|
|
379
|
+
>
|
|
380
|
+
<CellRenderer
|
|
381
|
+
{customRenderers}
|
|
382
|
+
{row}
|
|
383
|
+
schema={schema[field]}
|
|
384
|
+
value={deepGet(row, field)}
|
|
385
|
+
on:clickrelationship
|
|
386
|
+
>
|
|
387
|
+
<slot />
|
|
388
|
+
</CellRenderer>
|
|
389
|
+
</div>
|
|
390
|
+
{/each}
|
|
391
|
+
</div>
|
|
392
|
+
{/each}
|
|
393
|
+
{:else}
|
|
394
|
+
<div
|
|
395
|
+
class="placeholder"
|
|
396
|
+
class:placeholder--custom={customPlaceholder}
|
|
397
|
+
class:placeholder--no-fields={!fields?.length}
|
|
398
|
+
>
|
|
399
|
+
{#if customPlaceholder}
|
|
400
|
+
<slot name="placeholder" />
|
|
401
|
+
{:else}
|
|
402
|
+
<div class="placeholder-content">
|
|
403
|
+
<svg
|
|
404
|
+
class="spectrum-Icon spectrum-Icon--sizeXXL"
|
|
405
|
+
focusable="false"
|
|
406
|
+
>
|
|
407
|
+
<use xlink:href="#spectrum-icon-18-Table" />
|
|
408
|
+
</svg>
|
|
409
|
+
<div>{placeholderText}</div>
|
|
410
|
+
</div>
|
|
411
|
+
{/if}
|
|
412
|
+
</div>
|
|
413
|
+
{/if}
|
|
414
|
+
</div>
|
|
415
|
+
{/if}
|
|
416
|
+
</div>
|
|
417
|
+
|
|
418
|
+
<style>
|
|
419
|
+
/* Wrapper */
|
|
420
|
+
.wrapper {
|
|
421
|
+
position: relative;
|
|
422
|
+
z-index: 0;
|
|
423
|
+
--table-bg: var(--spectrum-global-color-gray-50);
|
|
424
|
+
--table-border: 1px solid var(--spectrum-alias-border-color-mid);
|
|
425
|
+
--cell-padding: var(--spectrum-global-dimension-size-250);
|
|
426
|
+
}
|
|
427
|
+
.wrapper--quiet {
|
|
428
|
+
--table-bg: var(--spectrum-alias-background-color-transparent);
|
|
429
|
+
}
|
|
430
|
+
.wrapper--compact {
|
|
431
|
+
--cell-padding: var(--spectrum-global-dimension-size-150);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/* Loading */
|
|
435
|
+
.loading {
|
|
436
|
+
display: grid;
|
|
437
|
+
place-items: center;
|
|
438
|
+
min-height: 100px;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/* Table */
|
|
442
|
+
.spectrum-Table {
|
|
443
|
+
width: 100%;
|
|
444
|
+
border-radius: 0;
|
|
445
|
+
display: grid;
|
|
446
|
+
overflow: auto;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/* Header */
|
|
450
|
+
.spectrum-Table-head {
|
|
451
|
+
display: contents;
|
|
452
|
+
}
|
|
453
|
+
.spectrum-Table-head > :first-child {
|
|
454
|
+
border-left: 1px solid transparent;
|
|
455
|
+
padding-left: var(--cell-padding);
|
|
456
|
+
}
|
|
457
|
+
.spectrum-Table-head > :last-child {
|
|
458
|
+
border-right: 1px solid transparent;
|
|
459
|
+
padding-right: var(--cell-padding);
|
|
460
|
+
}
|
|
461
|
+
.spectrum-Table-headCell {
|
|
462
|
+
height: var(--header-height);
|
|
463
|
+
position: sticky;
|
|
464
|
+
top: 0;
|
|
465
|
+
text-overflow: ellipsis;
|
|
466
|
+
white-space: nowrap;
|
|
467
|
+
background-color: var(--spectrum-alias-background-color-secondary);
|
|
468
|
+
z-index: 2;
|
|
469
|
+
border-bottom: var(--table-border);
|
|
470
|
+
padding: 0 calc(var(--cell-padding) / 1.33);
|
|
471
|
+
display: flex;
|
|
472
|
+
flex-direction: row;
|
|
473
|
+
justify-content: flex-start;
|
|
474
|
+
align-items: center;
|
|
475
|
+
user-select: none;
|
|
476
|
+
border-top: var(--table-border);
|
|
477
|
+
}
|
|
478
|
+
.spectrum-Table-headCell:first-of-type {
|
|
479
|
+
border-left: var(--table-border);
|
|
480
|
+
}
|
|
481
|
+
.spectrum-Table-headCell:last-of-type {
|
|
482
|
+
border-right: var(--table-border);
|
|
483
|
+
}
|
|
484
|
+
.spectrum-Table-headCell--alignCenter {
|
|
485
|
+
justify-content: center;
|
|
486
|
+
}
|
|
487
|
+
.spectrum-Table-headCell--alignRight {
|
|
488
|
+
justify-content: flex-end;
|
|
489
|
+
}
|
|
490
|
+
.spectrum-Table-headCell--divider {
|
|
491
|
+
padding-right: var(--cell-padding);
|
|
492
|
+
}
|
|
493
|
+
.spectrum-Table-headCell--divider + .spectrum-Table-headCell {
|
|
494
|
+
padding-left: var(--cell-padding);
|
|
495
|
+
}
|
|
496
|
+
.spectrum-Table-headCell--edit {
|
|
497
|
+
position: sticky;
|
|
498
|
+
left: 0;
|
|
499
|
+
z-index: 3;
|
|
500
|
+
}
|
|
501
|
+
.spectrum-Table-headCell .title {
|
|
502
|
+
overflow: hidden;
|
|
503
|
+
text-overflow: ellipsis;
|
|
504
|
+
}
|
|
505
|
+
.spectrum-Table-headCell:hover .spectrum-Table-editIcon {
|
|
506
|
+
opacity: 1;
|
|
507
|
+
transition: opacity 0.2s ease;
|
|
508
|
+
}
|
|
509
|
+
.spectrum-Table-headCell .spectrum-Icon {
|
|
510
|
+
pointer-events: all;
|
|
511
|
+
margin-left: var(
|
|
512
|
+
--spectrum-table-header-sort-icon-gap,
|
|
513
|
+
var(--spectrum-global-dimension-size-125)
|
|
514
|
+
);
|
|
515
|
+
}
|
|
516
|
+
.spectrum-Table-editIcon,
|
|
517
|
+
.spectrum-Table-autoIcon {
|
|
518
|
+
width: var(--spectrum-global-dimension-size-150);
|
|
519
|
+
height: var(--spectrum-global-dimension-size-150);
|
|
520
|
+
}
|
|
521
|
+
.spectrum-Table-editIcon {
|
|
522
|
+
opacity: 0;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/* Table rows */
|
|
526
|
+
.spectrum-Table-row {
|
|
527
|
+
display: contents;
|
|
528
|
+
}
|
|
529
|
+
.spectrum-Table-row:hover .spectrum-Table-cell {
|
|
530
|
+
/*background-color: var(--hover-bg) !important;*/
|
|
531
|
+
}
|
|
532
|
+
.spectrum-Table-row:hover .spectrum-Table-cell:after {
|
|
533
|
+
background-color: var(--spectrum-alias-highlight-hover);
|
|
534
|
+
}
|
|
535
|
+
.wrapper--quiet .spectrum-Table-row {
|
|
536
|
+
border-left: none;
|
|
537
|
+
border-right: none;
|
|
538
|
+
}
|
|
539
|
+
.spectrum-Table-row > :first-child {
|
|
540
|
+
border-left: var(--table-border);
|
|
541
|
+
padding-left: var(--cell-padding);
|
|
542
|
+
}
|
|
543
|
+
.spectrum-Table-row > :last-child {
|
|
544
|
+
border-right: var(--table-border);
|
|
545
|
+
padding-right: var(--cell-padding);
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
/* Table cells */
|
|
549
|
+
.spectrum-Table-cell {
|
|
550
|
+
flex: 1 1 auto;
|
|
551
|
+
padding: 0 calc(var(--cell-padding) / 1.33);
|
|
552
|
+
border-top: none;
|
|
553
|
+
border-bottom: none;
|
|
554
|
+
border-radius: 0;
|
|
555
|
+
text-overflow: ellipsis;
|
|
556
|
+
white-space: nowrap;
|
|
557
|
+
height: var(--row-height);
|
|
558
|
+
display: flex;
|
|
559
|
+
flex-direction: row;
|
|
560
|
+
justify-content: flex-start;
|
|
561
|
+
align-items: center;
|
|
562
|
+
gap: 4px;
|
|
563
|
+
border-bottom: 1px solid var(--spectrum-alias-border-color-mid);
|
|
564
|
+
background-color: var(--table-bg);
|
|
565
|
+
z-index: 1;
|
|
566
|
+
}
|
|
567
|
+
.spectrum-Table-cell--divider {
|
|
568
|
+
padding-right: var(--cell-padding);
|
|
569
|
+
}
|
|
570
|
+
.spectrum-Table-cell--divider + .spectrum-Table-cell {
|
|
571
|
+
padding-left: var(--cell-padding);
|
|
572
|
+
}
|
|
573
|
+
.spectrum-Table-cell--edit {
|
|
574
|
+
position: sticky;
|
|
575
|
+
left: 0;
|
|
576
|
+
z-index: 2;
|
|
577
|
+
}
|
|
578
|
+
.spectrum-Table-cell:after {
|
|
579
|
+
content: "";
|
|
580
|
+
position: absolute;
|
|
581
|
+
width: 100%;
|
|
582
|
+
height: 100%;
|
|
583
|
+
background-color: transparent;
|
|
584
|
+
top: 0;
|
|
585
|
+
left: 0;
|
|
586
|
+
pointer-events: none;
|
|
587
|
+
transition: background-color
|
|
588
|
+
var(--spectrum-global-animation-duration-100, 0.13s) ease-in-out;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
/* Placeholder */
|
|
592
|
+
.placeholder {
|
|
593
|
+
display: flex;
|
|
594
|
+
flex-direction: row;
|
|
595
|
+
justify-content: center;
|
|
596
|
+
align-items: center;
|
|
597
|
+
border: var(--table-border);
|
|
598
|
+
border-top: none;
|
|
599
|
+
grid-column: 1 / -1;
|
|
600
|
+
background-color: var(--table-bg);
|
|
601
|
+
padding: 40px;
|
|
602
|
+
}
|
|
603
|
+
.placeholder--no-fields {
|
|
604
|
+
border-top: var(--table-border);
|
|
605
|
+
}
|
|
606
|
+
.placeholder--custom {
|
|
607
|
+
justify-content: flex-start;
|
|
608
|
+
}
|
|
609
|
+
.wrapper--quiet .placeholder {
|
|
610
|
+
border-left: none;
|
|
611
|
+
border-right: none;
|
|
612
|
+
}
|
|
613
|
+
.placeholder-content {
|
|
614
|
+
display: flex;
|
|
615
|
+
flex-direction: column;
|
|
616
|
+
justify-content: center;
|
|
617
|
+
align-items: center;
|
|
618
|
+
color: var(
|
|
619
|
+
--spectrum-table-cell-text-color,
|
|
620
|
+
var(--spectrum-alias-text-color)
|
|
621
|
+
);
|
|
622
|
+
}
|
|
623
|
+
.placeholder-content div {
|
|
624
|
+
margin-top: 10px;
|
|
625
|
+
font-size: var(
|
|
626
|
+
--spectrum-table-cell-text-size,
|
|
627
|
+
var(--spectrum-alias-font-size-default)
|
|
628
|
+
);
|
|
629
|
+
text-align: center;
|
|
630
|
+
}
|
|
631
|
+
</style>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Table } from "./Table.svelte"
|
|
@@ -0,0 +1,88 @@
|
|
|
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
|
+
let selected = getContext("tab")
|
|
9
|
+
let tab_internal
|
|
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_internal?.getBoundingClientRect()
|
|
20
|
+
if (tabInfo && $selected.title === title) {
|
|
21
|
+
$selected.info = tabInfo
|
|
22
|
+
}
|
|
23
|
+
}, 0)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
onMount(() => {
|
|
27
|
+
setTabInfo()
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
//Ensure that the underline is in the correct location
|
|
31
|
+
$: {
|
|
32
|
+
if ($selected.title === title && tab_internal) {
|
|
33
|
+
if ($selected.info?.left !== tab_internal.getBoundingClientRect().left) {
|
|
34
|
+
$selected = {
|
|
35
|
+
...$selected,
|
|
36
|
+
info: tab_internal.getBoundingClientRect(),
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const onClick = () => {
|
|
43
|
+
$selected = {
|
|
44
|
+
...$selected,
|
|
45
|
+
title,
|
|
46
|
+
info: tab_internal.getBoundingClientRect(),
|
|
47
|
+
}
|
|
48
|
+
dispatch("click")
|
|
49
|
+
}
|
|
50
|
+
</script>
|
|
51
|
+
|
|
52
|
+
<div
|
|
53
|
+
bind:this={tab_internal}
|
|
54
|
+
on:click={onClick}
|
|
55
|
+
class:is-selected={$selected.title === title}
|
|
56
|
+
class="spectrum-Tabs-item"
|
|
57
|
+
class:emphasized={$selected.title === title && $selected.emphasized}
|
|
58
|
+
tabindex="0"
|
|
59
|
+
>
|
|
60
|
+
{#if icon}
|
|
61
|
+
<svg
|
|
62
|
+
class="spectrum-Icon spectrum-Icon--sizeM"
|
|
63
|
+
focusable="false"
|
|
64
|
+
aria-hidden="true"
|
|
65
|
+
aria-label="Folder"
|
|
66
|
+
>
|
|
67
|
+
<use xlink:href="#spectrum-icon-18-{icon}" />
|
|
68
|
+
</svg>
|
|
69
|
+
{/if}
|
|
70
|
+
<span class="spectrum-Tabs-itemLabel">{title}</span>
|
|
71
|
+
</div>
|
|
72
|
+
{#if $selected.title === title}
|
|
73
|
+
<Portal target=".spectrum-Tabs-content-{$selected.id}">
|
|
74
|
+
<slot />
|
|
75
|
+
</Portal>
|
|
76
|
+
{/if}
|
|
77
|
+
|
|
78
|
+
<style>
|
|
79
|
+
.emphasized {
|
|
80
|
+
color: var(--spectrum-global-color-blue-600);
|
|
81
|
+
}
|
|
82
|
+
.spectrum-Tabs-item {
|
|
83
|
+
color: var(--spectrum-global-color-gray-600);
|
|
84
|
+
}
|
|
85
|
+
.spectrum-Tabs-item.is-selected {
|
|
86
|
+
color: var(--spectrum-global-color-gray-900);
|
|
87
|
+
}
|
|
88
|
+
</style>
|