@budibase/frontend-core 2.7.34-alpha.4 → 2.7.34-alpha.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/package.json +4 -4
  2. package/src/api/analytics.js +2 -2
  3. package/src/api/index.js +16 -2
  4. package/src/api/rows.js +3 -1
  5. package/src/components/grid/cells/AttachmentCell.svelte +3 -1
  6. package/src/components/grid/cells/GridCell.svelte +1 -1
  7. package/src/components/grid/cells/GutterCell.svelte +9 -14
  8. package/src/components/grid/cells/HeaderCell.svelte +7 -5
  9. package/src/components/grid/cells/LongFormCell.svelte +1 -1
  10. package/src/components/grid/cells/OptionsCell.svelte +4 -5
  11. package/src/components/grid/cells/RelationshipCell.svelte +22 -11
  12. package/src/components/grid/controls/AddColumnButton.svelte +1 -1
  13. package/src/components/grid/controls/BulkDeleteHandler.svelte +2 -8
  14. package/src/components/grid/controls/HideColumnsButton.svelte +9 -4
  15. package/src/components/grid/controls/SizeButton.svelte +135 -0
  16. package/src/components/grid/controls/SortButton.svelte +3 -4
  17. package/src/components/grid/layout/Grid.svelte +66 -59
  18. package/src/components/grid/layout/GridBody.svelte +3 -2
  19. package/src/components/grid/layout/GridRow.svelte +3 -2
  20. package/src/components/grid/layout/GridScrollWrapper.svelte +6 -0
  21. package/src/components/grid/layout/HeaderRow.svelte +3 -3
  22. package/src/components/grid/layout/NewRow.svelte +37 -5
  23. package/src/components/grid/layout/StickyColumn.svelte +10 -8
  24. package/src/components/grid/lib/constants.js +4 -3
  25. package/src/components/grid/lib/websocket.js +3 -2
  26. package/src/components/grid/overlays/KeyboardManager.svelte +6 -0
  27. package/src/components/grid/overlays/MenuOverlay.svelte +3 -1
  28. package/src/components/grid/overlays/ReorderOverlay.svelte +1 -1
  29. package/src/components/grid/overlays/ResizeOverlay.svelte +1 -1
  30. package/src/components/grid/overlays/ScrollOverlay.svelte +25 -2
  31. package/src/components/grid/stores/columns.js +37 -6
  32. package/src/components/grid/stores/config.js +27 -0
  33. package/src/components/grid/stores/filter.js +19 -0
  34. package/src/components/grid/stores/index.js +6 -0
  35. package/src/components/grid/stores/menu.js +15 -9
  36. package/src/components/grid/stores/rows.js +18 -16
  37. package/src/components/grid/stores/scroll.js +5 -7
  38. package/src/components/grid/stores/sort.js +27 -0
  39. package/src/components/grid/stores/ui.js +19 -4
  40. package/src/components/grid/stores/viewport.js +17 -6
  41. package/src/fetch/DataFetch.js +4 -2
  42. package/src/utils/index.js +1 -0
  43. package/src/utils/memo.js +43 -0
  44. package/src/components/grid/controls/ColumnWidthButton.svelte +0 -92
  45. package/src/components/grid/controls/RowHeightButton.svelte +0 -71
@@ -46,7 +46,7 @@ export const createStores = () => {
46
46
  }
47
47
 
48
48
  export const deriveStores = context => {
49
- const { table, columns, stickyColumn, API, dispatch } = context
49
+ const { table, columns, stickyColumn, API, dispatch, config } = context
50
50
 
51
51
  // Updates the tables primary display column
52
52
  const changePrimaryDisplay = async column => {
@@ -56,6 +56,23 @@ export const deriveStores = context => {
56
56
  })
57
57
  }
58
58
 
59
+ // Updates the width of all columns
60
+ const changeAllColumnWidths = async width => {
61
+ columns.update(state => {
62
+ return state.map(col => ({
63
+ ...col,
64
+ width,
65
+ }))
66
+ })
67
+ if (get(stickyColumn)) {
68
+ stickyColumn.update(state => ({
69
+ ...state,
70
+ width,
71
+ }))
72
+ }
73
+ await saveChanges()
74
+ }
75
+
59
76
  // Persists column changes by saving metadata against table schema
60
77
  const saveChanges = async () => {
61
78
  const $columns = get(columns)
@@ -91,7 +108,9 @@ export const deriveStores = context => {
91
108
  table.set(newTable)
92
109
 
93
110
  // Update server
94
- await API.saveTable(newTable)
111
+ if (get(config).allowSchemaChanges) {
112
+ await API.saveTable(newTable)
113
+ }
95
114
 
96
115
  // Broadcast change to external state can be updated, as this change
97
116
  // will not be received by the builder websocket because we caused it ourselves
@@ -105,17 +124,19 @@ export const deriveStores = context => {
105
124
  saveChanges,
106
125
  saveTable,
107
126
  changePrimaryDisplay,
127
+ changeAllColumnWidths,
108
128
  },
109
129
  },
110
130
  }
111
131
  }
112
132
 
113
133
  export const initialise = context => {
114
- const { table, columns, stickyColumn, schemaOverrides } = context
134
+ const { table, columns, stickyColumn, schemaOverrides, columnWhitelist } =
135
+ context
115
136
 
116
137
  const schema = derived(
117
- [table, schemaOverrides],
118
- ([$table, $schemaOverrides]) => {
138
+ [table, schemaOverrides, columnWhitelist],
139
+ ([$table, $schemaOverrides, $columnWhitelist]) => {
119
140
  if (!$table?.schema) {
120
141
  return null
121
142
  }
@@ -142,6 +163,16 @@ export const initialise = context => {
142
163
  }
143
164
  }
144
165
  })
166
+
167
+ // Apply whitelist if specified
168
+ if ($columnWhitelist?.length) {
169
+ Object.keys(newSchema).forEach(key => {
170
+ if (!$columnWhitelist.includes(key)) {
171
+ delete newSchema[key]
172
+ }
173
+ })
174
+ }
175
+
145
176
  return newSchema
146
177
  }
147
178
  )
@@ -209,7 +240,7 @@ export const initialise = context => {
209
240
  }
210
241
  stickyColumn.set({
211
242
  name: primaryDisplay,
212
- label: $schema[primaryDisplay].name || primaryDisplay,
243
+ label: $schema[primaryDisplay].displayName || primaryDisplay,
213
244
  schema: $schema[primaryDisplay],
214
245
  width: $schema[primaryDisplay].width || DefaultColumnWidth,
215
246
  visible: true,
@@ -0,0 +1,27 @@
1
+ import { writable } from "svelte/store"
2
+ import { derivedMemo } from "../../../utils"
3
+
4
+ export const createStores = context => {
5
+ const config = writable(context.props)
6
+ const getProp = prop => derivedMemo(config, $config => $config[prop])
7
+
8
+ // Derive and memoize some props so that we can react to them in isolation
9
+ const tableId = getProp("tableId")
10
+ const initialSortColumn = getProp("initialSortColumn")
11
+ const initialSortOrder = getProp("initialSortOrder")
12
+ const initialFilter = getProp("initialFilter")
13
+ const initialRowHeight = getProp("initialRowHeight")
14
+ const schemaOverrides = getProp("schemaOverrides")
15
+ const columnWhitelist = getProp("columnWhitelist")
16
+
17
+ return {
18
+ config,
19
+ tableId,
20
+ initialSortColumn,
21
+ initialSortOrder,
22
+ initialFilter,
23
+ initialRowHeight,
24
+ schemaOverrides,
25
+ columnWhitelist,
26
+ }
27
+ }
@@ -0,0 +1,19 @@
1
+ import { writable } from "svelte/store"
2
+
3
+ export const createStores = context => {
4
+ const { props } = context
5
+
6
+ // Initialise to default props
7
+ const filter = writable(props.initialFilter)
8
+
9
+ return {
10
+ filter,
11
+ }
12
+ }
13
+
14
+ export const initialise = context => {
15
+ const { filter, initialFilter } = context
16
+
17
+ // Reset filter when initial filter prop changes
18
+ initialFilter.subscribe(filter.set)
19
+ }
@@ -11,8 +11,14 @@ import * as Users from "./users"
11
11
  import * as Validation from "./validation"
12
12
  import * as Viewport from "./viewport"
13
13
  import * as Clipboard from "./clipboard"
14
+ import * as Config from "./config"
15
+ import * as Sort from "./sort"
16
+ import * as Filter from "./filter"
14
17
 
15
18
  const DependencyOrderedStores = [
19
+ Config,
20
+ Sort,
21
+ Filter,
16
22
  Bounds,
17
23
  Scroll,
18
24
  Rows,
@@ -1,5 +1,4 @@
1
- import { writable, get } from "svelte/store"
2
- import { GutterWidth } from "../lib/constants"
1
+ import { writable } from "svelte/store"
3
2
 
4
3
  export const createStores = () => {
5
4
  const menu = writable({
@@ -14,18 +13,25 @@ export const createStores = () => {
14
13
  }
15
14
 
16
15
  export const deriveStores = context => {
17
- const { menu, bounds, focusedCellId, stickyColumn, rowHeight } = context
16
+ const { menu, focusedCellId, rand } = context
18
17
 
19
18
  const open = (cellId, e) => {
20
- const $bounds = get(bounds)
21
- const $stickyColumn = get(stickyColumn)
22
- const $rowHeight = get(rowHeight)
23
19
  e.preventDefault()
20
+
21
+ // Get DOM node for grid data wrapper to compute relative position to
22
+ const gridNode = document.getElementById(`grid-${rand}`)
23
+ const dataNode = gridNode?.getElementsByClassName("grid-data-outer")?.[0]
24
+ if (!dataNode) {
25
+ return
26
+ }
27
+
28
+ // Compute bounds of cell relative to outer data node
29
+ const targetBounds = e.target.getBoundingClientRect()
30
+ const dataBounds = dataNode.getBoundingClientRect()
24
31
  focusedCellId.set(cellId)
25
32
  menu.set({
26
- left:
27
- e.clientX - $bounds.left + GutterWidth + ($stickyColumn?.width || 0),
28
- top: e.clientY - $bounds.top + $rowHeight,
33
+ left: targetBounds.left - dataBounds.left + e.offsetX,
34
+ top: targetBounds.top - dataBounds.top + e.offsetY,
29
35
  visible: true,
30
36
  })
31
37
  }
@@ -4,18 +4,13 @@ import { notifications } from "@budibase/bbui"
4
4
  import { NewRowID, RowPageSize } from "../lib/constants"
5
5
  import { tick } from "svelte"
6
6
 
7
- const initialSortState = {
8
- column: null,
9
- order: "ascending",
10
- }
7
+ const SuppressErrors = true
11
8
 
12
9
  export const createStores = () => {
13
10
  const rows = writable([])
14
11
  const table = writable(null)
15
- const filter = writable([])
16
12
  const loading = writable(false)
17
13
  const loaded = writable(false)
18
- const sort = writable(initialSortState)
19
14
  const rowChangeCache = writable({})
20
15
  const inProgressChanges = writable({})
21
16
  const hasNextPage = writable(false)
@@ -47,10 +42,8 @@ export const createStores = () => {
47
42
  rows,
48
43
  rowLookupMap,
49
44
  table,
50
- filter,
51
45
  loaded,
52
46
  loading,
53
- sort,
54
47
  rowChangeCache,
55
48
  inProgressChanges,
56
49
  hasNextPage,
@@ -98,15 +91,18 @@ export const deriveStores = context => {
98
91
  // Reset everything when table ID changes
99
92
  let unsubscribe = null
100
93
  let lastResetKey = null
101
- tableId.subscribe($tableId => {
94
+ tableId.subscribe(async $tableId => {
102
95
  // Unsub from previous fetch if one exists
103
96
  unsubscribe?.()
104
97
  fetch.set(null)
105
98
  instanceLoaded.set(false)
106
99
  loading.set(true)
107
100
 
108
- // Reset state
109
- filter.set([])
101
+ // Tick to allow other reactive logic to update stores when table ID changes
102
+ // before proceeding. This allows us to wipe filters etc if needed.
103
+ await tick()
104
+ const $filter = get(filter)
105
+ const $sort = get(sort)
110
106
 
111
107
  // Create new fetch model
112
108
  const newFetch = fetchData({
@@ -116,9 +112,9 @@ export const deriveStores = context => {
116
112
  tableId: $tableId,
117
113
  },
118
114
  options: {
119
- filter: [],
120
- sortColumn: initialSortState.column,
121
- sortOrder: initialSortState.order,
115
+ filter: $filter,
116
+ sortColumn: $sort.column,
117
+ sortOrder: $sort.order,
122
118
  limit: RowPageSize,
123
119
  paginate: true,
124
120
  },
@@ -224,7 +220,10 @@ export const deriveStores = context => {
224
220
  const addRow = async (row, idx, bubble = false) => {
225
221
  try {
226
222
  // Create row
227
- const newRow = await API.saveRow({ ...row, tableId: get(tableId) })
223
+ const newRow = await API.saveRow(
224
+ { ...row, tableId: get(tableId) },
225
+ SuppressErrors
226
+ )
228
227
 
229
228
  // Update state
230
229
  if (idx != null) {
@@ -351,7 +350,10 @@ export const deriveStores = context => {
351
350
  ...state,
352
351
  [rowId]: true,
353
352
  }))
354
- const saved = await API.saveRow({ ...row, ...get(rowChangeCache)[rowId] })
353
+ const saved = await API.saveRow(
354
+ { ...row, ...get(rowChangeCache)[rowId] },
355
+ SuppressErrors
356
+ )
355
357
 
356
358
  // Update state after a successful change
357
359
  if (saved?._id) {
@@ -1,6 +1,6 @@
1
1
  import { writable, derived, get } from "svelte/store"
2
2
  import { tick } from "svelte"
3
- import { Padding, GutterWidth } from "../lib/constants"
3
+ import { Padding, GutterWidth, FocusedCellMinOffset } from "../lib/constants"
4
4
 
5
5
  export const createStores = () => {
6
6
  const scroll = writable({
@@ -138,14 +138,13 @@ export const initialise = context => {
138
138
  const $scroll = get(scroll)
139
139
  const $bounds = get(bounds)
140
140
  const $rowHeight = get(rowHeight)
141
- const verticalOffset = 60
142
141
 
143
142
  // Ensure vertical position is viewable
144
143
  if ($focusedRow) {
145
144
  // Ensure row is not below bottom of screen
146
145
  const rowYPos = $focusedRow.__idx * $rowHeight
147
146
  const bottomCutoff =
148
- $scroll.top + $bounds.height - $rowHeight - verticalOffset
147
+ $scroll.top + $bounds.height - $rowHeight - FocusedCellMinOffset
149
148
  let delta = rowYPos - bottomCutoff
150
149
  if (delta > 0) {
151
150
  scroll.update(state => ({
@@ -156,7 +155,7 @@ export const initialise = context => {
156
155
 
157
156
  // Ensure row is not above top of screen
158
157
  else {
159
- const delta = $scroll.top - rowYPos + verticalOffset
158
+ const delta = $scroll.top - rowYPos + FocusedCellMinOffset
160
159
  if (delta > 0) {
161
160
  scroll.update(state => ({
162
161
  ...state,
@@ -171,13 +170,12 @@ export const initialise = context => {
171
170
  const $visibleColumns = get(visibleColumns)
172
171
  const columnName = $focusedCellId?.split("-")[1]
173
172
  const column = $visibleColumns.find(col => col.name === columnName)
174
- const horizontalOffset = 50
175
173
  if (!column) {
176
174
  return
177
175
  }
178
176
 
179
177
  // Ensure column is not cutoff on left edge
180
- let delta = $scroll.left - column.left + horizontalOffset
178
+ let delta = $scroll.left - column.left + FocusedCellMinOffset
181
179
  if (delta > 0) {
182
180
  scroll.update(state => ({
183
181
  ...state,
@@ -188,7 +186,7 @@ export const initialise = context => {
188
186
  // Ensure column is not cutoff on right edge
189
187
  else {
190
188
  const rightEdge = column.left + column.width
191
- const rightBound = $bounds.width + $scroll.left - horizontalOffset
189
+ const rightBound = $bounds.width + $scroll.left - FocusedCellMinOffset
192
190
  delta = rightEdge - rightBound
193
191
  if (delta > 0) {
194
192
  scroll.update(state => ({
@@ -0,0 +1,27 @@
1
+ import { writable } from "svelte/store"
2
+
3
+ export const createStores = context => {
4
+ const { props } = context
5
+
6
+ // Initialise to default props
7
+ const sort = writable({
8
+ column: props.initialSortColumn,
9
+ order: props.initialSortOrder || "ascending",
10
+ })
11
+
12
+ return {
13
+ sort,
14
+ }
15
+ }
16
+
17
+ export const initialise = context => {
18
+ const { sort, initialSortColumn, initialSortOrder } = context
19
+
20
+ // Reset sort when initial sort props change
21
+ initialSortColumn.subscribe(newSortColumn => {
22
+ sort.update(state => ({ ...state, column: newSortColumn }))
23
+ })
24
+ initialSortOrder.subscribe(newSortOrder => {
25
+ sort.update(state => ({ ...state, order: newSortOrder }))
26
+ })
27
+ }
@@ -8,13 +8,16 @@ import {
8
8
  NewRowID,
9
9
  } from "../lib/constants"
10
10
 
11
- export const createStores = () => {
11
+ export const createStores = context => {
12
+ const { props } = context
12
13
  const focusedCellId = writable(null)
13
14
  const focusedCellAPI = writable(null)
14
15
  const selectedRows = writable({})
15
16
  const hoveredRowId = writable(null)
16
- const rowHeight = writable(DefaultRowHeight)
17
+ const rowHeight = writable(props.initialRowHeight || DefaultRowHeight)
17
18
  const previousFocusedRowId = writable(null)
19
+ const gridFocused = writable(false)
20
+ const isDragging = writable(false)
18
21
 
19
22
  // Derive the current focused row ID
20
23
  const focusedRowId = derived(
@@ -46,6 +49,8 @@ export const createStores = () => {
46
49
  previousFocusedRowId,
47
50
  hoveredRowId,
48
51
  rowHeight,
52
+ gridFocused,
53
+ isDragging,
49
54
  selectedRows: {
50
55
  ...selectedRows,
51
56
  actions: {
@@ -94,9 +99,9 @@ export const deriveStores = context => {
94
99
 
95
100
  // Derive the amount of content lines to show in cells depending on row height
96
101
  const contentLines = derived(rowHeight, $rowHeight => {
97
- if ($rowHeight === LargeRowHeight) {
102
+ if ($rowHeight >= LargeRowHeight) {
98
103
  return 3
99
- } else if ($rowHeight === MediumRowHeight) {
104
+ } else if ($rowHeight >= MediumRowHeight) {
100
105
  return 2
101
106
  }
102
107
  return 1
@@ -129,6 +134,7 @@ export const initialise = context => {
129
134
  hoveredRowId,
130
135
  table,
131
136
  rowHeight,
137
+ initialRowHeight,
132
138
  } = context
133
139
 
134
140
  // Ensure we clear invalid rows from state if they disappear
@@ -185,4 +191,13 @@ export const initialise = context => {
185
191
  table.subscribe($table => {
186
192
  rowHeight.set($table?.rowHeight || DefaultRowHeight)
187
193
  })
194
+
195
+ // Reset row height when initial row height prop changes
196
+ initialRowHeight.subscribe(height => {
197
+ if (height) {
198
+ rowHeight.set(height)
199
+ } else {
200
+ rowHeight.set(get(table)?.rowHeight || DefaultRowHeight)
201
+ }
202
+ })
188
203
  }
@@ -108,11 +108,22 @@ export const deriveStores = context => {
108
108
  // Determine the row index at which we should start vertically inverting cell
109
109
  // dropdowns
110
110
  const rowVerticalInversionIndex = derived(
111
- [visualRowCapacity, rowHeight],
112
- ([$visualRowCapacity, $rowHeight]) => {
113
- return (
114
- $visualRowCapacity - Math.ceil(MaxCellRenderHeight / $rowHeight) - 2
115
- )
111
+ [height, rowHeight, scrollTop],
112
+ ([$height, $rowHeight, $scrollTop]) => {
113
+ const offset = $scrollTop % $rowHeight
114
+
115
+ // Compute the last row index with space to render popovers below it
116
+ const minBottom =
117
+ $height - ScrollBarSize * 3 - MaxCellRenderHeight + offset
118
+ const lastIdx = Math.floor(minBottom / $rowHeight)
119
+
120
+ // Compute the first row index with space to render popovers above it
121
+ const minTop = MaxCellRenderHeight + offset
122
+ const firstIdx = Math.ceil(minTop / $rowHeight)
123
+
124
+ // Use the greater of the two indices so that we prefer content below,
125
+ // unless there is room to render the entire popover above
126
+ return Math.max(lastIdx, firstIdx)
116
127
  }
117
128
  )
118
129
 
@@ -125,7 +136,7 @@ export const deriveStores = context => {
125
136
  let inversionIdx = $renderedColumns.length
126
137
  for (let i = $renderedColumns.length - 1; i >= 0; i--, inversionIdx--) {
127
138
  const rightEdge = $renderedColumns[i].left + $renderedColumns[i].width
128
- if (rightEdge + MaxCellRenderWidthOverflow < cutoff) {
139
+ if (rightEdge + MaxCellRenderWidthOverflow <= cutoff) {
129
140
  break
130
141
  }
131
142
  }
@@ -136,8 +136,10 @@ export default class DataFetch {
136
136
  this.options.sortOrder = "ascending"
137
137
  }
138
138
 
139
- // If no sort column, use the primary display and fallback to first column
140
- if (!this.options.sortColumn) {
139
+ // If no sort column, or an invalid sort column is provided, use the primary
140
+ // display and fallback to first column
141
+ const sortValid = this.options.sortColumn && schema[this.options.sortColumn]
142
+ if (!sortValid) {
141
143
  let newSortColumn
142
144
  if (definition?.primaryDisplay && schema[definition.primaryDisplay]) {
143
145
  newSortColumn = definition.primaryDisplay
@@ -3,4 +3,5 @@ export * as JSONUtils from "./json"
3
3
  export * as CookieUtils from "./cookies"
4
4
  export * as RoleUtils from "./roles"
5
5
  export * as Utils from "./utils"
6
+ export { memo, derivedMemo } from "./memo"
6
7
  export { createWebsocket } from "./websocket"
@@ -0,0 +1,43 @@
1
+ import { writable, get, derived } from "svelte/store"
2
+
3
+ // A simple svelte store which deeply compares all changes and ensures that
4
+ // subscribed children will only fire when a new value is actually set
5
+ export const memo = initialValue => {
6
+ const store = writable(initialValue)
7
+
8
+ const tryUpdateValue = (newValue, currentValue) => {
9
+ // Sanity check for primitive equality
10
+ if (currentValue === newValue) {
11
+ return
12
+ }
13
+
14
+ // Otherwise deep compare via JSON stringify
15
+ const currentString = JSON.stringify(currentValue)
16
+ const newString = JSON.stringify(newValue)
17
+ if (currentString !== newString) {
18
+ store.set(newValue)
19
+ }
20
+ }
21
+
22
+ return {
23
+ subscribe: store.subscribe,
24
+ set: newValue => {
25
+ const currentValue = get(store)
26
+ tryUpdateValue(newValue, currentValue)
27
+ },
28
+ update: updateFn => {
29
+ const currentValue = get(store)
30
+ let mutableCurrentValue = JSON.parse(JSON.stringify(currentValue))
31
+ const newValue = updateFn(mutableCurrentValue)
32
+ tryUpdateValue(newValue, currentValue)
33
+ },
34
+ }
35
+ }
36
+
37
+ // Enriched version of svelte's derived store which returns a memo
38
+ export const derivedMemo = (store, derivation) => {
39
+ const derivedStore = derived(store, derivation)
40
+ const memoStore = memo(get(derivedStore))
41
+ derivedStore.subscribe(memoStore.set)
42
+ return memoStore
43
+ }
@@ -1,92 +0,0 @@
1
- <script>
2
- import { getContext } from "svelte"
3
- import { ActionButton, Popover } from "@budibase/bbui"
4
- import { DefaultColumnWidth } from "../lib/constants"
5
-
6
- const { stickyColumn, columns, compact } = getContext("grid")
7
- const smallSize = 120
8
- const mediumSize = DefaultColumnWidth
9
- const largeSize = DefaultColumnWidth * 1.5
10
-
11
- let open = false
12
- let anchor
13
-
14
- $: allCols = $columns.concat($stickyColumn ? [$stickyColumn] : [])
15
- $: allSmall = allCols.every(col => col.width === smallSize)
16
- $: allMedium = allCols.every(col => col.width === mediumSize)
17
- $: allLarge = allCols.every(col => col.width === largeSize)
18
- $: custom = !allSmall && !allMedium && !allLarge
19
- $: sizeOptions = [
20
- {
21
- label: "Small",
22
- size: smallSize,
23
- selected: allSmall,
24
- },
25
- {
26
- label: "Medium",
27
- size: mediumSize,
28
- selected: allMedium,
29
- },
30
- {
31
- label: "Large",
32
- size: largeSize,
33
- selected: allLarge,
34
- },
35
- ]
36
-
37
- const changeColumnWidth = async width => {
38
- columns.update(state => {
39
- state.forEach(column => {
40
- column.width = width
41
- })
42
- return state
43
- })
44
- if ($stickyColumn) {
45
- stickyColumn.update(state => ({
46
- ...state,
47
- width,
48
- }))
49
- }
50
- await columns.actions.saveChanges()
51
- }
52
- </script>
53
-
54
- <div bind:this={anchor}>
55
- <ActionButton
56
- icon="MoveLeftRight"
57
- quiet
58
- size="M"
59
- on:click={() => (open = !open)}
60
- selected={open}
61
- disabled={!allCols.length}
62
- tooltip={$compact ? "Width" : null}
63
- >
64
- {$compact ? "" : "Width"}
65
- </ActionButton>
66
- </div>
67
-
68
- <Popover bind:open {anchor} align={$compact ? "right" : "left"}>
69
- <div class="content">
70
- {#each sizeOptions as option}
71
- <ActionButton
72
- quiet
73
- on:click={() => changeColumnWidth(option.size)}
74
- selected={option.selected}
75
- >
76
- {option.label}
77
- </ActionButton>
78
- {/each}
79
- {#if custom}
80
- <ActionButton selected={custom} quiet>Custom</ActionButton>
81
- {/if}
82
- </div>
83
- </Popover>
84
-
85
- <style>
86
- .content {
87
- padding: 12px;
88
- display: flex;
89
- align-items: center;
90
- gap: 8px;
91
- }
92
- </style>