@budibase/frontend-core 2.5.9 → 2.5.10-alpha.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 (68) hide show
  1. package/package.json +6 -4
  2. package/src/api/other.js +0 -9
  3. package/src/components/grid/cells/AttachmentCell.svelte +154 -0
  4. package/src/components/grid/cells/BooleanCell.svelte +44 -0
  5. package/src/components/grid/cells/DataCell.svelte +91 -0
  6. package/src/components/grid/cells/DateCell.svelte +77 -0
  7. package/src/components/grid/cells/FormulaCell.svelte +5 -0
  8. package/src/components/grid/cells/GridCell.svelte +165 -0
  9. package/src/components/grid/cells/GutterCell.svelte +127 -0
  10. package/src/components/grid/cells/HeaderCell.svelte +248 -0
  11. package/src/components/grid/cells/JSONCell.svelte +36 -0
  12. package/src/components/grid/cells/LongFormCell.svelte +122 -0
  13. package/src/components/grid/cells/MultiSelectCell.svelte +7 -0
  14. package/src/components/grid/cells/NumberCell.svelte +14 -0
  15. package/src/components/grid/cells/OptionsCell.svelte +249 -0
  16. package/src/components/grid/cells/RelationshipCell.svelte +518 -0
  17. package/src/components/grid/cells/TextCell.svelte +111 -0
  18. package/src/components/grid/controls/AddColumnButton.svelte +16 -0
  19. package/src/components/grid/controls/AddRowButton.svelte +18 -0
  20. package/src/components/grid/controls/BetaButton.svelte +46 -0
  21. package/src/components/grid/controls/ColumnWidthButton.svelte +91 -0
  22. package/src/components/grid/controls/DeleteButton.svelte +66 -0
  23. package/src/components/grid/controls/HideColumnsButton.svelte +95 -0
  24. package/src/components/grid/controls/RowHeightButton.svelte +70 -0
  25. package/src/components/grid/controls/SortButton.svelte +129 -0
  26. package/src/components/grid/index.js +1 -0
  27. package/src/components/grid/layout/Avatar.svelte +24 -0
  28. package/src/components/grid/layout/Grid.svelte +254 -0
  29. package/src/components/grid/layout/GridBody.svelte +73 -0
  30. package/src/components/grid/layout/GridRow.svelte +59 -0
  31. package/src/components/grid/layout/GridScrollWrapper.svelte +81 -0
  32. package/src/components/grid/layout/HeaderRow.svelte +62 -0
  33. package/src/components/grid/layout/KeyboardShortcut.svelte +53 -0
  34. package/src/components/grid/layout/NewRow.svelte +334 -0
  35. package/src/components/grid/layout/RowCount.svelte +9 -0
  36. package/src/components/grid/layout/StickyColumn.svelte +176 -0
  37. package/src/components/grid/layout/UserAvatars.svelte +20 -0
  38. package/src/components/grid/lib/constants.js +14 -0
  39. package/src/components/grid/lib/events.js +29 -0
  40. package/src/components/grid/lib/renderers.js +29 -0
  41. package/src/components/grid/lib/utils.js +26 -0
  42. package/src/components/grid/lib/websocket.js +63 -0
  43. package/src/components/grid/overlays/KeyboardManager.svelte +232 -0
  44. package/src/components/grid/overlays/MenuOverlay.svelte +96 -0
  45. package/src/components/grid/overlays/ReorderOverlay.svelte +63 -0
  46. package/src/components/grid/overlays/ResizeOverlay.svelte +70 -0
  47. package/src/components/grid/overlays/ScrollOverlay.svelte +121 -0
  48. package/src/components/grid/stores/bounds.js +16 -0
  49. package/src/components/grid/stores/clipboard.js +34 -0
  50. package/src/components/grid/stores/columns.js +206 -0
  51. package/src/components/grid/stores/index.js +48 -0
  52. package/src/components/grid/stores/menu.js +49 -0
  53. package/src/components/grid/stores/pagination.js +24 -0
  54. package/src/components/grid/stores/reorder.js +155 -0
  55. package/src/components/grid/stores/resize.js +124 -0
  56. package/src/components/grid/stores/rows.js +467 -0
  57. package/src/components/grid/stores/scroll.js +201 -0
  58. package/src/components/grid/stores/ui.js +159 -0
  59. package/src/components/grid/stores/users.js +115 -0
  60. package/src/components/grid/stores/validation.js +45 -0
  61. package/src/components/grid/stores/viewport.js +145 -0
  62. package/src/components/index.js +1 -0
  63. package/src/constants.js +1 -0
  64. package/src/fetch/DataFetch.js +27 -21
  65. package/src/fetch/QueryFetch.js +1 -1
  66. package/src/themes/midnight.css +3 -0
  67. package/src/themes/nord.css +3 -0
  68. package/src/utils/utils.js +20 -0
@@ -0,0 +1,159 @@
1
+ import { writable, get, derived } from "svelte/store"
2
+ import { tick } from "svelte"
3
+ import {
4
+ DefaultRowHeight,
5
+ LargeRowHeight,
6
+ MediumRowHeight,
7
+ NewRowID,
8
+ } from "../lib/constants"
9
+
10
+ export const createStores = () => {
11
+ const focusedCellId = writable(null)
12
+ const focusedCellAPI = writable(null)
13
+ const selectedRows = writable({})
14
+ const hoveredRowId = writable(null)
15
+ const rowHeight = writable(DefaultRowHeight)
16
+ const previousFocusedRowId = writable(null)
17
+
18
+ // Derive the current focused row ID
19
+ const focusedRowId = derived(
20
+ focusedCellId,
21
+ $focusedCellId => {
22
+ return $focusedCellId?.split("-")[0]
23
+ },
24
+ null
25
+ )
26
+
27
+ return {
28
+ focusedCellId,
29
+ focusedCellAPI,
30
+ focusedRowId,
31
+ previousFocusedRowId,
32
+ selectedRows,
33
+ hoveredRowId,
34
+ rowHeight,
35
+ }
36
+ }
37
+
38
+ export const deriveStores = context => {
39
+ const {
40
+ focusedCellId,
41
+ selectedRows,
42
+ hoveredRowId,
43
+ enrichedRows,
44
+ rowLookupMap,
45
+ rowHeight,
46
+ } = context
47
+
48
+ // Derive the row that contains the selected cell
49
+ const focusedRow = derived(
50
+ [focusedCellId, rowLookupMap, enrichedRows],
51
+ ([$focusedCellId, $rowLookupMap, $enrichedRows]) => {
52
+ const rowId = $focusedCellId?.split("-")[0]
53
+
54
+ // Edge case for new rows
55
+ if (rowId === NewRowID) {
56
+ return { _id: NewRowID }
57
+ }
58
+
59
+ // All normal rows
60
+ const index = $rowLookupMap[rowId]
61
+ return $enrichedRows[index]
62
+ },
63
+ null
64
+ )
65
+
66
+ // Callback when leaving the grid, deselecting all focussed or selected items
67
+ const blur = () => {
68
+ focusedCellId.set(null)
69
+ selectedRows.set({})
70
+ hoveredRowId.set(null)
71
+ }
72
+
73
+ const contentLines = derived(rowHeight, $rowHeight => {
74
+ if ($rowHeight === LargeRowHeight) {
75
+ return 3
76
+ } else if ($rowHeight === MediumRowHeight) {
77
+ return 2
78
+ }
79
+ return 1
80
+ })
81
+
82
+ return {
83
+ focusedRow,
84
+ contentLines,
85
+ ui: {
86
+ actions: {
87
+ blur,
88
+ },
89
+ },
90
+ }
91
+ }
92
+
93
+ export const initialise = context => {
94
+ const {
95
+ focusedRowId,
96
+ previousFocusedRowId,
97
+ rows,
98
+ focusedCellId,
99
+ selectedRows,
100
+ hoveredRowId,
101
+ table,
102
+ rowHeight,
103
+ } = context
104
+
105
+ // Ensure we clear invalid rows from state if they disappear
106
+ rows.subscribe(async () => {
107
+ // We tick here to ensure other derived stores have properly updated.
108
+ // We depend on the row lookup map which is a derived store,
109
+ await tick()
110
+ const $focusedCellId = get(focusedCellId)
111
+ const $selectedRows = get(selectedRows)
112
+ const $hoveredRowId = get(hoveredRowId)
113
+ const hasRow = rows.actions.hasRow
114
+
115
+ // Check selected cell
116
+ const selectedRowId = $focusedCellId?.split("-")[0]
117
+ if (selectedRowId && !hasRow(selectedRowId)) {
118
+ focusedCellId.set(null)
119
+ }
120
+
121
+ // Check hovered row
122
+ if ($hoveredRowId && !hasRow($hoveredRowId)) {
123
+ hoveredRowId.set(null)
124
+ }
125
+
126
+ // Check selected rows
127
+ let newSelectedRows = { ...$selectedRows }
128
+ let selectedRowsNeedsUpdate = false
129
+ const selectedIds = Object.keys($selectedRows)
130
+ for (let i = 0; i < selectedIds.length; i++) {
131
+ if (!hasRow(selectedIds[i])) {
132
+ delete newSelectedRows[selectedIds[i]]
133
+ selectedRowsNeedsUpdate = true
134
+ }
135
+ }
136
+ if (selectedRowsNeedsUpdate) {
137
+ selectedRows.set(newSelectedRows)
138
+ }
139
+ })
140
+
141
+ // Remember the last focused row ID so that we can store the previous one
142
+ let lastFocusedRowId = null
143
+ focusedRowId.subscribe(id => {
144
+ previousFocusedRowId.set(lastFocusedRowId)
145
+ lastFocusedRowId = id
146
+ })
147
+
148
+ // Remove hovered row when a cell is selected
149
+ focusedCellId.subscribe(cell => {
150
+ if (cell && get(hoveredRowId)) {
151
+ hoveredRowId.set(null)
152
+ }
153
+ })
154
+
155
+ // Pull row height from table
156
+ table.subscribe($table => {
157
+ rowHeight.set($table?.rowHeight || DefaultRowHeight)
158
+ })
159
+ }
@@ -0,0 +1,115 @@
1
+ import { writable, get, derived } from "svelte/store"
2
+
3
+ export const createStores = () => {
4
+ const users = writable([])
5
+ const userId = writable(null)
6
+
7
+ // Enrich users with unique colours
8
+ const enrichedUsers = derived(
9
+ [users, userId],
10
+ ([$users, $userId]) => {
11
+ return (
12
+ $users
13
+ .slice()
14
+ // Place current user first
15
+ .sort((a, b) => {
16
+ if (a.id === $userId) {
17
+ return -1
18
+ } else if (b.id === $userId) {
19
+ return 1
20
+ } else {
21
+ return 0
22
+ }
23
+ })
24
+ // Enrich users with colors
25
+ .map((user, idx) => {
26
+ // Generate random colour hue
27
+ let hue = 1
28
+ for (let i = 0; i < user.email.length && i < 5; i++) {
29
+ hue *= user.email.charCodeAt(i + 1)
30
+ hue /= 17
31
+ }
32
+ hue = hue % 360
33
+ const color =
34
+ idx === 0
35
+ ? "var(--spectrum-global-color-blue-400)"
36
+ : `hsl(${hue}, 50%, 40%)`
37
+
38
+ // Generate friendly label
39
+ let label = user.email
40
+ if (user.firstName) {
41
+ label = user.firstName
42
+ if (user.lastName) {
43
+ label += ` ${user.lastName}`
44
+ }
45
+ }
46
+
47
+ return {
48
+ ...user,
49
+ color,
50
+ label,
51
+ }
52
+ })
53
+ )
54
+ },
55
+ []
56
+ )
57
+
58
+ return {
59
+ users: {
60
+ ...users,
61
+ subscribe: enrichedUsers.subscribe,
62
+ },
63
+ userId,
64
+ }
65
+ }
66
+
67
+ export const deriveStores = context => {
68
+ const { users, userId } = context
69
+
70
+ // Generate a lookup map of cell ID to the user that has it selected, to make
71
+ // lookups inside cells extremely fast
72
+ const selectedCellMap = derived(
73
+ [users, userId],
74
+ ([$enrichedUsers, $userId]) => {
75
+ let map = {}
76
+ $enrichedUsers.forEach(user => {
77
+ if (user.focusedCellId && user.id !== $userId) {
78
+ map[user.focusedCellId] = user
79
+ }
80
+ })
81
+ return map
82
+ },
83
+ {}
84
+ )
85
+
86
+ const updateUser = user => {
87
+ const $users = get(users)
88
+ const index = $users.findIndex(x => x.id === user.id)
89
+ if (index === -1) {
90
+ users.set([...$users, user])
91
+ } else {
92
+ users.update(state => {
93
+ state[index] = user
94
+ return state.slice()
95
+ })
96
+ }
97
+ }
98
+
99
+ const removeUser = user => {
100
+ users.update(state => {
101
+ return state.filter(x => x.id !== user.id)
102
+ })
103
+ }
104
+
105
+ return {
106
+ users: {
107
+ ...users,
108
+ actions: {
109
+ updateUser,
110
+ removeUser,
111
+ },
112
+ },
113
+ selectedCellMap,
114
+ }
115
+ }
@@ -0,0 +1,45 @@
1
+ import { writable, get } from "svelte/store"
2
+
3
+ export const createStores = () => {
4
+ const validation = writable({})
5
+
6
+ const setError = (cellId, error) => {
7
+ if (!cellId) {
8
+ return
9
+ }
10
+ validation.update(state => ({
11
+ ...state,
12
+ [cellId]: error,
13
+ }))
14
+ }
15
+
16
+ return {
17
+ validation: {
18
+ ...validation,
19
+ actions: {
20
+ setError,
21
+ },
22
+ },
23
+ }
24
+ }
25
+
26
+ export const initialise = context => {
27
+ const { validation, previousFocusedRowId, columns, stickyColumn } = context
28
+
29
+ // Remove validation errors from previous focused row
30
+ previousFocusedRowId.subscribe(id => {
31
+ if (id) {
32
+ const $columns = get(columns)
33
+ const $stickyColumn = get(stickyColumn)
34
+ validation.update(state => {
35
+ $columns.forEach(column => {
36
+ state[`${id}-${column.name}`] = null
37
+ })
38
+ if ($stickyColumn) {
39
+ state[`${id}-${$stickyColumn.name}`] = null
40
+ }
41
+ return state
42
+ })
43
+ }
44
+ })
45
+ }
@@ -0,0 +1,145 @@
1
+ import { derived, get } from "svelte/store"
2
+ import {
3
+ MaxCellRenderHeight,
4
+ MaxCellRenderWidthOverflow,
5
+ MinColumnWidth,
6
+ ScrollBarSize,
7
+ } from "../lib/constants"
8
+
9
+ export const deriveStores = context => {
10
+ const {
11
+ rowHeight,
12
+ visibleColumns,
13
+ enrichedRows,
14
+ scrollTop,
15
+ scrollLeft,
16
+ width,
17
+ height,
18
+ } = context
19
+
20
+ // Derive visible rows
21
+ // Split into multiple stores containing primitives to optimise invalidation
22
+ // as much as possible
23
+ const scrolledRowCount = derived(
24
+ [scrollTop, rowHeight],
25
+ ([$scrollTop, $rowHeight]) => {
26
+ return Math.floor($scrollTop / $rowHeight)
27
+ },
28
+ 0
29
+ )
30
+ const visualRowCapacity = derived(
31
+ [height, rowHeight],
32
+ ([$height, $rowHeight]) => {
33
+ return Math.ceil($height / $rowHeight) + 1
34
+ },
35
+ 0
36
+ )
37
+ const renderedRows = derived(
38
+ [enrichedRows, scrolledRowCount, visualRowCapacity],
39
+ ([$enrichedRows, $scrolledRowCount, $visualRowCapacity]) => {
40
+ return $enrichedRows.slice(
41
+ $scrolledRowCount,
42
+ $scrolledRowCount + $visualRowCapacity
43
+ )
44
+ },
45
+ []
46
+ )
47
+
48
+ // Derive visible columns
49
+ const scrollLeftRounded = derived(scrollLeft, $scrollLeft => {
50
+ const interval = MinColumnWidth
51
+ return Math.round($scrollLeft / interval) * interval
52
+ })
53
+ const renderedColumns = derived(
54
+ [visibleColumns, scrollLeftRounded, width],
55
+ ([$visibleColumns, $scrollLeft, $width], set) => {
56
+ if (!$visibleColumns.length) {
57
+ set([])
58
+ return
59
+ }
60
+ let startColIdx = 0
61
+ let rightEdge = $visibleColumns[0].width
62
+ while (
63
+ rightEdge < $scrollLeft &&
64
+ startColIdx < $visibleColumns.length - 1
65
+ ) {
66
+ startColIdx++
67
+ rightEdge += $visibleColumns[startColIdx].width
68
+ }
69
+ let endColIdx = startColIdx + 1
70
+ let leftEdge = rightEdge
71
+ while (
72
+ leftEdge < $width + $scrollLeft &&
73
+ endColIdx < $visibleColumns.length
74
+ ) {
75
+ leftEdge += $visibleColumns[endColIdx].width
76
+ endColIdx++
77
+ }
78
+ // Render an additional column on either side to account for
79
+ // debounce column updates based on scroll position
80
+ const next = $visibleColumns.slice(
81
+ Math.max(0, startColIdx - 1),
82
+ endColIdx + 1
83
+ )
84
+ const current = get(renderedColumns)
85
+ if (JSON.stringify(next) !== JSON.stringify(current)) {
86
+ set(next)
87
+ }
88
+ }
89
+ )
90
+
91
+ const hiddenColumnsWidth = derived(
92
+ [renderedColumns, visibleColumns],
93
+ ([$renderedColumns, $visibleColumns]) => {
94
+ const idx = $visibleColumns.findIndex(
95
+ col => col.name === $renderedColumns[0]?.name
96
+ )
97
+ let width = 0
98
+ if (idx > 0) {
99
+ for (let i = 0; i < idx; i++) {
100
+ width += $visibleColumns[i].width
101
+ }
102
+ }
103
+ return width
104
+ },
105
+ 0
106
+ )
107
+
108
+ // Determine the row index at which we should start vertically inverting cell
109
+ // dropdowns
110
+ const rowVerticalInversionIndex = derived(
111
+ [visualRowCapacity, rowHeight],
112
+ ([$visualRowCapacity, $rowHeight]) => {
113
+ return (
114
+ $visualRowCapacity - Math.ceil(MaxCellRenderHeight / $rowHeight) - 2
115
+ )
116
+ }
117
+ )
118
+
119
+ // Determine the column index at which we should start horizontally inverting
120
+ // cell dropdowns
121
+ const columnHorizontalInversionIndex = derived(
122
+ [renderedColumns, scrollLeft, width],
123
+ ([$renderedColumns, $scrollLeft, $width]) => {
124
+ const cutoff = $width + $scrollLeft - ScrollBarSize * 3
125
+ let inversionIdx = $renderedColumns.length
126
+ for (let i = $renderedColumns.length - 1; i >= 0; i--, inversionIdx--) {
127
+ const rightEdge = $renderedColumns[i].left + $renderedColumns[i].width
128
+ if (rightEdge + MaxCellRenderWidthOverflow < cutoff) {
129
+ break
130
+ }
131
+ }
132
+ return inversionIdx
133
+ }
134
+ )
135
+
136
+ return {
137
+ scrolledRowCount,
138
+ visualRowCapacity,
139
+ renderedRows,
140
+ renderedColumns,
141
+ hiddenColumnsWidth,
142
+ rowVerticalInversionIndex,
143
+ columnHorizontalInversionIndex,
144
+ }
145
+ }
@@ -1,2 +1,3 @@
1
1
  export { default as SplitPage } from "./SplitPage.svelte"
2
2
  export { default as TestimonialPage } from "./TestimonialPage.svelte"
3
+ export { Grid } from "./grid"
package/src/constants.js CHANGED
@@ -69,6 +69,7 @@ export const Features = {
69
69
  AUDIT_LOGS: "auditLogs",
70
70
  ENFORCEABLE_SSO: "enforceableSSO",
71
71
  BRANDING: "branding",
72
+ SCIM: "scim",
72
73
  }
73
74
 
74
75
  // Role IDs
@@ -21,11 +21,11 @@ export default class DataFetch {
21
21
  this.API = null
22
22
 
23
23
  // Feature flags
24
- this.featureStore = writable({
24
+ this.features = {
25
25
  supportsSearch: false,
26
26
  supportsSort: false,
27
27
  supportsPagination: false,
28
- })
28
+ }
29
29
 
30
30
  // Config
31
31
  this.options = {
@@ -56,6 +56,7 @@ export default class DataFetch {
56
56
  pageNumber: 0,
57
57
  cursor: null,
58
58
  cursors: [],
59
+ resetKey: Math.random(),
59
60
  })
60
61
 
61
62
  // Merge options with their default values
@@ -81,17 +82,14 @@ export default class DataFetch {
81
82
  this.prevPage = this.prevPage.bind(this)
82
83
 
83
84
  // Derive certain properties to return
84
- this.derivedStore = derived(
85
- [this.store, this.featureStore],
86
- ([$store, $featureStore]) => {
87
- return {
88
- ...$store,
89
- ...$featureStore,
90
- hasNextPage: this.hasNextPage($store),
91
- hasPrevPage: this.hasPrevPage($store),
92
- }
85
+ this.derivedStore = derived(this.store, $store => {
86
+ return {
87
+ ...$store,
88
+ ...this.features,
89
+ hasNextPage: this.hasNextPage($store),
90
+ hasPrevPage: this.hasPrevPage($store),
93
91
  }
94
- )
92
+ })
95
93
 
96
94
  // Mark as loaded if we have no datasource
97
95
  if (!this.options.datasource) {
@@ -120,11 +118,11 @@ export default class DataFetch {
120
118
  // Fetch datasource definition and determine feature flags
121
119
  const definition = await this.getDefinition(datasource)
122
120
  const features = this.determineFeatureFlags(definition)
123
- this.featureStore.set({
121
+ this.features = {
124
122
  supportsSearch: !!features?.supportsSearch,
125
123
  supportsSort: !!features?.supportsSort,
126
124
  supportsPagination: paginate && !!features?.supportsPagination,
127
- })
125
+ }
128
126
 
129
127
  // Fetch and enrich schema
130
128
  let schema = this.getSchema(datasource, definition)
@@ -138,11 +136,17 @@ export default class DataFetch {
138
136
  this.options.sortOrder = "ascending"
139
137
  }
140
138
 
141
- // If no sort column, use the first field in the schema
139
+ // If no sort column, use the primary display and fallback to first column
142
140
  if (!this.options.sortColumn) {
143
- this.options.sortColumn = Object.keys(schema)[0]
141
+ let newSortColumn
142
+ if (definition?.primaryDisplay && schema[definition.primaryDisplay]) {
143
+ newSortColumn = definition.primaryDisplay
144
+ } else {
145
+ newSortColumn = Object.keys(schema)[0]
146
+ }
147
+ this.options.sortColumn = newSortColumn
144
148
  }
145
- const { sortColumn } = this.options
149
+ const { sortOrder, sortColumn } = this.options
146
150
 
147
151
  // Determine what sort type to use
148
152
  let sortType = "string"
@@ -167,6 +171,8 @@ export default class DataFetch {
167
171
  loading: true,
168
172
  cursors: [],
169
173
  cursor: null,
174
+ sortOrder,
175
+ sortColumn,
170
176
  }))
171
177
 
172
178
  // Actually fetch data
@@ -180,6 +186,7 @@ export default class DataFetch {
180
186
  info: page.info,
181
187
  cursors: paginate && page.hasNextPage ? [null, page.cursor] : [null],
182
188
  error: page.error,
189
+ resetKey: Math.random(),
183
190
  }))
184
191
  }
185
192
 
@@ -189,23 +196,22 @@ export default class DataFetch {
189
196
  async getPage() {
190
197
  const { sortColumn, sortOrder, sortType, limit } = this.options
191
198
  const { query } = get(this.store)
192
- const features = get(this.featureStore)
193
199
 
194
200
  // Get the actual data
195
201
  let { rows, info, hasNextPage, cursor, error } = await this.getData()
196
202
 
197
203
  // If we don't support searching, do a client search
198
- if (!features.supportsSearch) {
204
+ if (!this.features.supportsSearch) {
199
205
  rows = runLuceneQuery(rows, query)
200
206
  }
201
207
 
202
208
  // If we don't support sorting, do a client-side sort
203
- if (!features.supportsSort) {
209
+ if (!this.features.supportsSort) {
204
210
  rows = luceneSort(rows, sortColumn, sortOrder, sortType)
205
211
  }
206
212
 
207
213
  // If we don't support pagination, do a client-side limit
208
- if (!features.supportsPagination) {
214
+ if (!this.features.supportsPagination) {
209
215
  rows = luceneLimit(rows, limit)
210
216
  }
211
217
 
@@ -31,7 +31,7 @@ export default class QueryFetch extends DataFetch {
31
31
 
32
32
  async getData() {
33
33
  const { datasource, limit, paginate } = this.options
34
- const { supportsPagination } = get(this.featureStore)
34
+ const { supportsPagination } = this.features
35
35
  const { cursor, definition } = get(this.store)
36
36
  const type = definition?.fields?.pagination?.type
37
37
 
@@ -13,6 +13,9 @@
13
13
  --spectrum-global-color-gray-800: hsl(var(--hue), var(--sat), 85%);
14
14
  --spectrum-global-color-gray-900: hsl(var(--hue), var(--sat), 95%);
15
15
 
16
+ /* Custom additions */
16
17
  --modal-background: var(--spectrum-global-color-gray-50);
18
+ --drop-shadow: rgba(0, 0, 0, 0.25) !important;
19
+ --spectrum-global-color-blue-100: rgba(35, 40, 50) !important;
17
20
  }
18
21
 
@@ -46,5 +46,8 @@
46
46
  --spectrum-alias-highlight-active: rgba(169, 177, 193, 0.1);
47
47
  --spectrum-alias-background-color-hover-overlay: rgba(169, 177, 193, 0.1);
48
48
 
49
+ /* Custom additions */
49
50
  --modal-background: var(--spectrum-global-color-gray-50);
51
+ --drop-shadow: rgba(0, 0, 0, 0.15) !important;
52
+ --spectrum-global-color-blue-100: rgb(56, 65, 84) !important;
50
53
  }
@@ -86,3 +86,23 @@ export const throttle = (callback, minDelay = 1000) => {
86
86
  }
87
87
  return invoke
88
88
  }
89
+
90
+ /**
91
+ * Utility to debounce DOM activities using requestAnimationFrame
92
+ * @param callback the function to run
93
+ * @returns {Function}
94
+ */
95
+ export const domDebounce = callback => {
96
+ let active = false
97
+ let lastParams
98
+ return (...params) => {
99
+ lastParams = params
100
+ if (!active) {
101
+ active = true
102
+ requestAnimationFrame(() => {
103
+ callback(...lastParams)
104
+ active = false
105
+ })
106
+ }
107
+ }
108
+ }