@budibase/frontend-core 2.7.34-alpha.4 → 2.7.34-alpha.6
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/package.json +4 -4
- package/src/api/index.js +16 -2
- package/src/api/rows.js +3 -1
- package/src/components/grid/cells/AttachmentCell.svelte +3 -1
- package/src/components/grid/cells/GridCell.svelte +1 -1
- package/src/components/grid/cells/GutterCell.svelte +9 -14
- package/src/components/grid/cells/HeaderCell.svelte +7 -5
- package/src/components/grid/cells/LongFormCell.svelte +1 -1
- package/src/components/grid/cells/OptionsCell.svelte +4 -5
- package/src/components/grid/cells/RelationshipCell.svelte +22 -11
- package/src/components/grid/controls/AddColumnButton.svelte +1 -1
- package/src/components/grid/controls/BulkDeleteHandler.svelte +2 -8
- package/src/components/grid/controls/HideColumnsButton.svelte +9 -4
- package/src/components/grid/controls/SizeButton.svelte +135 -0
- package/src/components/grid/controls/SortButton.svelte +3 -4
- package/src/components/grid/layout/Grid.svelte +66 -59
- package/src/components/grid/layout/GridBody.svelte +3 -2
- package/src/components/grid/layout/GridRow.svelte +3 -2
- package/src/components/grid/layout/GridScrollWrapper.svelte +6 -0
- package/src/components/grid/layout/HeaderRow.svelte +3 -3
- package/src/components/grid/layout/NewRow.svelte +37 -5
- package/src/components/grid/layout/StickyColumn.svelte +10 -8
- package/src/components/grid/lib/constants.js +4 -3
- package/src/components/grid/lib/websocket.js +3 -2
- package/src/components/grid/overlays/KeyboardManager.svelte +6 -0
- package/src/components/grid/overlays/MenuOverlay.svelte +3 -1
- package/src/components/grid/overlays/ReorderOverlay.svelte +1 -1
- package/src/components/grid/overlays/ResizeOverlay.svelte +1 -1
- package/src/components/grid/overlays/ScrollOverlay.svelte +25 -2
- package/src/components/grid/stores/columns.js +37 -6
- package/src/components/grid/stores/config.js +27 -0
- package/src/components/grid/stores/filter.js +19 -0
- package/src/components/grid/stores/index.js +6 -0
- package/src/components/grid/stores/menu.js +15 -9
- package/src/components/grid/stores/rows.js +18 -16
- package/src/components/grid/stores/scroll.js +5 -7
- package/src/components/grid/stores/sort.js +27 -0
- package/src/components/grid/stores/ui.js +19 -4
- package/src/components/grid/stores/viewport.js +17 -6
- package/src/fetch/DataFetch.js +4 -2
- package/src/utils/index.js +1 -0
- package/src/utils/memo.js +43 -0
- package/src/components/grid/controls/ColumnWidthButton.svelte +0 -92
- package/src/components/grid/controls/RowHeightButton.svelte +0 -71
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import { setContext, onMount } from "svelte"
|
|
3
|
-
import { writable } from "svelte/store"
|
|
4
3
|
import { fade } from "svelte/transition"
|
|
5
4
|
import { clickOutside, ProgressCircle } from "@budibase/bbui"
|
|
6
5
|
import { createEventManagers } from "../lib/events"
|
|
@@ -17,11 +16,8 @@
|
|
|
17
16
|
import UserAvatars from "./UserAvatars.svelte"
|
|
18
17
|
import KeyboardManager from "../overlays/KeyboardManager.svelte"
|
|
19
18
|
import SortButton from "../controls/SortButton.svelte"
|
|
20
|
-
import AddColumnButton from "../controls/AddColumnButton.svelte"
|
|
21
19
|
import HideColumnsButton from "../controls/HideColumnsButton.svelte"
|
|
22
|
-
import
|
|
23
|
-
import RowHeightButton from "../controls/RowHeightButton.svelte"
|
|
24
|
-
import ColumnWidthButton from "../controls/ColumnWidthButton.svelte"
|
|
20
|
+
import SizeButton from "../controls/SizeButton.svelte"
|
|
25
21
|
import NewRow from "./NewRow.svelte"
|
|
26
22
|
import { createGridWebsocket } from "../lib/websocket"
|
|
27
23
|
import {
|
|
@@ -33,48 +29,37 @@
|
|
|
33
29
|
|
|
34
30
|
export let API = null
|
|
35
31
|
export let tableId = null
|
|
36
|
-
export let tableType = null
|
|
37
32
|
export let schemaOverrides = null
|
|
33
|
+
export let columnWhitelist = null
|
|
38
34
|
export let allowAddRows = true
|
|
39
|
-
export let allowAddColumns = true
|
|
40
|
-
export let allowEditColumns = true
|
|
41
35
|
export let allowExpandRows = true
|
|
42
36
|
export let allowEditRows = true
|
|
43
37
|
export let allowDeleteRows = true
|
|
38
|
+
export let allowSchemaChanges = true
|
|
44
39
|
export let stripeRows = false
|
|
45
40
|
export let collaboration = true
|
|
46
41
|
export let showAvatars = true
|
|
42
|
+
export let showControls = true
|
|
43
|
+
export let initialFilter = null
|
|
44
|
+
export let initialSortColumn = null
|
|
45
|
+
export let initialSortOrder = null
|
|
46
|
+
export let initialRowHeight = null
|
|
47
47
|
|
|
48
48
|
// Unique identifier for DOM nodes inside this instance
|
|
49
49
|
const rand = Math.random()
|
|
50
50
|
|
|
51
|
-
// State stores
|
|
52
|
-
const tableIdStore = writable(tableId)
|
|
53
|
-
const schemaOverridesStore = writable(schemaOverrides)
|
|
54
|
-
const config = writable({
|
|
55
|
-
allowAddRows,
|
|
56
|
-
allowAddColumns,
|
|
57
|
-
allowEditColumns,
|
|
58
|
-
allowExpandRows,
|
|
59
|
-
allowEditRows,
|
|
60
|
-
allowDeleteRows,
|
|
61
|
-
stripeRows,
|
|
62
|
-
})
|
|
63
|
-
|
|
64
51
|
// Build up context
|
|
65
52
|
let context = {
|
|
66
53
|
API: API || createAPIClient(),
|
|
67
54
|
rand,
|
|
68
|
-
|
|
69
|
-
tableId: tableIdStore,
|
|
70
|
-
tableType,
|
|
71
|
-
schemaOverrides: schemaOverridesStore,
|
|
55
|
+
props: $$props,
|
|
72
56
|
}
|
|
73
57
|
context = { ...context, ...createEventManagers() }
|
|
74
58
|
context = attachStores(context)
|
|
75
59
|
|
|
76
60
|
// Reference some stores for local use
|
|
77
61
|
const {
|
|
62
|
+
config,
|
|
78
63
|
isResizing,
|
|
79
64
|
isReordering,
|
|
80
65
|
ui,
|
|
@@ -82,19 +67,27 @@
|
|
|
82
67
|
loading,
|
|
83
68
|
rowHeight,
|
|
84
69
|
contentLines,
|
|
70
|
+
gridFocused,
|
|
85
71
|
} = context
|
|
86
72
|
|
|
87
|
-
// Keep
|
|
88
|
-
$: tableIdStore.set(tableId)
|
|
89
|
-
$: schemaOverridesStore.set(schemaOverrides)
|
|
73
|
+
// Keep config store up to date with props
|
|
90
74
|
$: config.set({
|
|
75
|
+
tableId,
|
|
76
|
+
schemaOverrides,
|
|
77
|
+
columnWhitelist,
|
|
91
78
|
allowAddRows,
|
|
92
|
-
allowAddColumns,
|
|
93
|
-
allowEditColumns,
|
|
94
79
|
allowExpandRows,
|
|
95
80
|
allowEditRows,
|
|
96
81
|
allowDeleteRows,
|
|
82
|
+
allowSchemaChanges,
|
|
97
83
|
stripeRows,
|
|
84
|
+
collaboration,
|
|
85
|
+
showAvatars,
|
|
86
|
+
showControls,
|
|
87
|
+
initialFilter,
|
|
88
|
+
initialSortColumn,
|
|
89
|
+
initialSortOrder,
|
|
90
|
+
initialRowHeight,
|
|
98
91
|
})
|
|
99
92
|
|
|
100
93
|
// Set context for children to consume
|
|
@@ -116,25 +109,27 @@
|
|
|
116
109
|
id="grid-{rand}"
|
|
117
110
|
class:is-resizing={$isResizing}
|
|
118
111
|
class:is-reordering={$isReordering}
|
|
119
|
-
class:stripe={
|
|
112
|
+
class:stripe={stripeRows}
|
|
113
|
+
on:mouseenter={() => gridFocused.set(true)}
|
|
114
|
+
on:mouseleave={() => gridFocused.set(false)}
|
|
120
115
|
style="--row-height:{$rowHeight}px; --default-row-height:{DefaultRowHeight}px; --gutter-width:{GutterWidth}px; --max-cell-render-height:{MaxCellRenderHeight}px; --max-cell-render-width-overflow:{MaxCellRenderWidthOverflow}px; --content-lines:{$contentLines};"
|
|
121
116
|
>
|
|
122
|
-
|
|
123
|
-
<div class="controls
|
|
124
|
-
<
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
117
|
+
{#if showControls}
|
|
118
|
+
<div class="controls">
|
|
119
|
+
<div class="controls-left">
|
|
120
|
+
<slot name="filter" />
|
|
121
|
+
<SortButton />
|
|
122
|
+
<HideColumnsButton />
|
|
123
|
+
<SizeButton />
|
|
124
|
+
<slot name="controls" />
|
|
125
|
+
</div>
|
|
126
|
+
<div class="controls-right">
|
|
127
|
+
{#if showAvatars}
|
|
128
|
+
<UserAvatars />
|
|
129
|
+
{/if}
|
|
130
|
+
</div>
|
|
136
131
|
</div>
|
|
137
|
-
|
|
132
|
+
{/if}
|
|
138
133
|
{#if $loaded}
|
|
139
134
|
<div class="grid-data-outer" use:clickOutside={ui.actions.blur}>
|
|
140
135
|
<div class="grid-data-inner">
|
|
@@ -167,25 +162,28 @@
|
|
|
167
162
|
</div>
|
|
168
163
|
|
|
169
164
|
<style>
|
|
165
|
+
/* Core grid */
|
|
170
166
|
.grid {
|
|
171
|
-
flex: 1 1 auto;
|
|
172
|
-
display: flex;
|
|
173
|
-
flex-direction: column;
|
|
174
|
-
justify-content: flex-start;
|
|
175
|
-
align-items: stretch;
|
|
176
|
-
position: relative;
|
|
177
|
-
overflow: hidden;
|
|
178
|
-
background: var(--cell-background);
|
|
179
|
-
|
|
180
167
|
/* Variables */
|
|
181
|
-
--
|
|
182
|
-
--
|
|
168
|
+
--accent-color: var(--primaryColor, var(--spectrum-global-color-blue-400));
|
|
169
|
+
--grid-background: var(--spectrum-global-color-gray-50);
|
|
170
|
+
--grid-background-alt: var(--spectrum-global-color-gray-100);
|
|
171
|
+
--cell-background: var(--grid-background);
|
|
172
|
+
--cell-background-hover: var(--grid-background-alt);
|
|
183
173
|
--cell-background-alt: var(--cell-background);
|
|
184
174
|
--cell-padding: 8px;
|
|
185
175
|
--cell-spacing: 4px;
|
|
186
176
|
--cell-border: 1px solid var(--spectrum-global-color-gray-200);
|
|
187
177
|
--cell-font-size: 14px;
|
|
188
178
|
--controls-height: 50px;
|
|
179
|
+
flex: 1 1 auto;
|
|
180
|
+
display: flex;
|
|
181
|
+
flex-direction: column;
|
|
182
|
+
justify-content: flex-start;
|
|
183
|
+
align-items: stretch;
|
|
184
|
+
position: relative;
|
|
185
|
+
overflow: hidden;
|
|
186
|
+
background: var(--grid-background);
|
|
189
187
|
}
|
|
190
188
|
.grid,
|
|
191
189
|
.grid :global(*) {
|
|
@@ -201,6 +199,7 @@
|
|
|
201
199
|
--cell-background-alt: var(--spectrum-global-color-gray-75);
|
|
202
200
|
}
|
|
203
201
|
|
|
202
|
+
/* Data layers */
|
|
204
203
|
.grid-data-outer,
|
|
205
204
|
.grid-data-inner {
|
|
206
205
|
flex: 1 1 auto;
|
|
@@ -234,7 +233,7 @@
|
|
|
234
233
|
border-bottom: 2px solid var(--spectrum-global-color-gray-200);
|
|
235
234
|
padding: var(--cell-padding);
|
|
236
235
|
gap: var(--cell-spacing);
|
|
237
|
-
background: var(--background);
|
|
236
|
+
background: var(--grid-background-alt);
|
|
238
237
|
z-index: 2;
|
|
239
238
|
}
|
|
240
239
|
.controls-left,
|
|
@@ -270,7 +269,15 @@
|
|
|
270
269
|
left: 0;
|
|
271
270
|
width: 100%;
|
|
272
271
|
height: 100%;
|
|
273
|
-
background: var(--background);
|
|
272
|
+
background: var(--grid-background-alt);
|
|
274
273
|
opacity: 0.6;
|
|
275
274
|
}
|
|
275
|
+
|
|
276
|
+
/* Disable checkbox animation anywhere in the grid data */
|
|
277
|
+
.grid-data-outer :global(.spectrum-Checkbox-box:before),
|
|
278
|
+
.grid-data-outer :global(.spectrum-Checkbox-box:after),
|
|
279
|
+
.grid-data-outer :global(.spectrum-Checkbox-checkmark),
|
|
280
|
+
.grid-data-outer :global(.spectrum-Checkbox-partialCheckmark) {
|
|
281
|
+
transition: none;
|
|
282
|
+
}
|
|
276
283
|
</style>
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
config,
|
|
13
13
|
hoveredRowId,
|
|
14
14
|
dispatch,
|
|
15
|
+
isDragging,
|
|
15
16
|
} = getContext("grid")
|
|
16
17
|
|
|
17
18
|
let body
|
|
@@ -47,8 +48,8 @@
|
|
|
47
48
|
class="blank"
|
|
48
49
|
class:highlighted={$hoveredRowId === BlankRowID}
|
|
49
50
|
style="width:{renderColumnsWidth}px"
|
|
50
|
-
on:mouseenter={() => ($hoveredRowId = BlankRowID)}
|
|
51
|
-
on:mouseleave={() => ($hoveredRowId = null)}
|
|
51
|
+
on:mouseenter={$isDragging ? null : () => ($hoveredRowId = BlankRowID)}
|
|
52
|
+
on:mouseleave={$isDragging ? null : () => ($hoveredRowId = null)}
|
|
52
53
|
on:click={() => dispatch("add-row-inline")}
|
|
53
54
|
/>
|
|
54
55
|
{/if}
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
focusedRow,
|
|
17
17
|
columnHorizontalInversionIndex,
|
|
18
18
|
contentLines,
|
|
19
|
+
isDragging,
|
|
19
20
|
} = getContext("grid")
|
|
20
21
|
|
|
21
22
|
$: rowSelected = !!$selectedRows[row._id]
|
|
@@ -27,8 +28,8 @@
|
|
|
27
28
|
<div
|
|
28
29
|
class="row"
|
|
29
30
|
on:focus
|
|
30
|
-
on:mouseenter={() => ($hoveredRowId = row._id)}
|
|
31
|
-
on:mouseleave={() => ($hoveredRowId = null)}
|
|
31
|
+
on:mouseenter={$isDragging ? null : () => ($hoveredRowId = row._id)}
|
|
32
|
+
on:mouseleave={$isDragging ? null : () => ($hoveredRowId = null)}
|
|
32
33
|
>
|
|
33
34
|
{#each $renderedColumns as column, columnIdx (column.name)}
|
|
34
35
|
{@const cellId = `${row._id}-${column.name}`}
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
bounds,
|
|
13
13
|
hoveredRowId,
|
|
14
14
|
hiddenColumnsWidth,
|
|
15
|
+
menu,
|
|
15
16
|
} = getContext("grid")
|
|
16
17
|
|
|
17
18
|
export let scrollVertically = false
|
|
@@ -30,6 +31,11 @@
|
|
|
30
31
|
const handleWheel = e => {
|
|
31
32
|
e.preventDefault()
|
|
32
33
|
debouncedHandleWheel(e.deltaX, e.deltaY, e.clientY)
|
|
34
|
+
|
|
35
|
+
// If a context menu was visible, hide it
|
|
36
|
+
if ($menu.visible) {
|
|
37
|
+
menu.actions.close()
|
|
38
|
+
}
|
|
33
39
|
}
|
|
34
40
|
const debouncedHandleWheel = domDebounce((deltaX, deltaY, clientY) => {
|
|
35
41
|
const { top, left } = $scroll
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
{/each}
|
|
30
30
|
</div>
|
|
31
31
|
</GridScrollWrapper>
|
|
32
|
-
{#if $config.
|
|
32
|
+
{#if $config.allowSchemaChanges}
|
|
33
33
|
<div
|
|
34
34
|
class="add"
|
|
35
35
|
style="left:{left}px"
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
|
|
43
43
|
<style>
|
|
44
44
|
.header {
|
|
45
|
-
background: var(--background);
|
|
45
|
+
background: var(--grid-background-alt);
|
|
46
46
|
border-bottom: var(--cell-border);
|
|
47
47
|
position: relative;
|
|
48
48
|
height: var(--default-row-height);
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
border-left: var(--cell-border);
|
|
61
61
|
border-right: var(--cell-border);
|
|
62
62
|
border-bottom: var(--cell-border);
|
|
63
|
-
background: var(--
|
|
63
|
+
background: var(--grid-background-alt);
|
|
64
64
|
z-index: 1;
|
|
65
65
|
}
|
|
66
66
|
.add:hover {
|
|
@@ -26,6 +26,8 @@
|
|
|
26
26
|
maxScrollTop,
|
|
27
27
|
rowVerticalInversionIndex,
|
|
28
28
|
columnHorizontalInversionIndex,
|
|
29
|
+
selectedRows,
|
|
30
|
+
config,
|
|
29
31
|
} = getContext("grid")
|
|
30
32
|
|
|
31
33
|
let visible = false
|
|
@@ -37,6 +39,7 @@
|
|
|
37
39
|
$: width = GutterWidth + ($stickyColumn?.width || 0)
|
|
38
40
|
$: $tableId, (visible = false)
|
|
39
41
|
$: invertY = shouldInvertY(offset, $rowVerticalInversionIndex, $renderedRows)
|
|
42
|
+
$: selectedRowCount = Object.values($selectedRows).length
|
|
40
43
|
|
|
41
44
|
const shouldInvertY = (offset, inversionIndex, rows) => {
|
|
42
45
|
if (offset === 0) {
|
|
@@ -75,7 +78,7 @@
|
|
|
75
78
|
}
|
|
76
79
|
|
|
77
80
|
const startAdding = async () => {
|
|
78
|
-
if (visible) {
|
|
81
|
+
if (visible || !firstColumn) {
|
|
79
82
|
return
|
|
80
83
|
}
|
|
81
84
|
|
|
@@ -129,9 +132,6 @@
|
|
|
129
132
|
e.preventDefault()
|
|
130
133
|
clear()
|
|
131
134
|
}
|
|
132
|
-
} else if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
|
|
133
|
-
e.preventDefault()
|
|
134
|
-
addRow()
|
|
135
135
|
}
|
|
136
136
|
}
|
|
137
137
|
|
|
@@ -141,6 +141,18 @@
|
|
|
141
141
|
})
|
|
142
142
|
</script>
|
|
143
143
|
|
|
144
|
+
<!-- New row FAB -->
|
|
145
|
+
{#if !visible && !selectedRowCount && $config.allowAddRows && firstColumn}
|
|
146
|
+
<div
|
|
147
|
+
class="new-row-fab"
|
|
148
|
+
on:click={() => dispatch("add-row-inline")}
|
|
149
|
+
transition:fade|local={{ duration: 130 }}
|
|
150
|
+
class:offset={!$stickyColumn}
|
|
151
|
+
>
|
|
152
|
+
<Icon name="Add" size="S" />
|
|
153
|
+
</div>
|
|
154
|
+
{/if}
|
|
155
|
+
|
|
144
156
|
<!-- Only show new row functionality if we have any columns -->
|
|
145
157
|
{#if visible}
|
|
146
158
|
<div
|
|
@@ -151,7 +163,7 @@
|
|
|
151
163
|
<div class="underlay sticky" transition:fade|local={{ duration: 130 }} />
|
|
152
164
|
<div class="underlay" transition:fade|local={{ duration: 130 }} />
|
|
153
165
|
<div class="sticky-column" transition:fade|local={{ duration: 130 }}>
|
|
154
|
-
<GutterCell on:expand={addViaModal} rowHovered>
|
|
166
|
+
<GutterCell expandable on:expand={addViaModal} rowHovered>
|
|
155
167
|
<Icon name="Add" color="var(--spectrum-global-color-gray-500)" />
|
|
156
168
|
{#if isAdding}
|
|
157
169
|
<div in:fade={{ duration: 130 }} class="loading-overlay" />
|
|
@@ -227,6 +239,26 @@
|
|
|
227
239
|
{/if}
|
|
228
240
|
|
|
229
241
|
<style>
|
|
242
|
+
/* New row FAB */
|
|
243
|
+
.new-row-fab {
|
|
244
|
+
position: absolute;
|
|
245
|
+
top: var(--default-row-height);
|
|
246
|
+
left: calc(var(--gutter-width) / 2);
|
|
247
|
+
transform: translateX(6px) translateY(-50%);
|
|
248
|
+
background: var(--cell-background);
|
|
249
|
+
padding: 4px;
|
|
250
|
+
border-radius: 50%;
|
|
251
|
+
border: var(--cell-border);
|
|
252
|
+
z-index: 10;
|
|
253
|
+
}
|
|
254
|
+
.new-row-fab:hover {
|
|
255
|
+
background: var(--cell-background-hover);
|
|
256
|
+
cursor: pointer;
|
|
257
|
+
}
|
|
258
|
+
.new-row-fab.offset {
|
|
259
|
+
margin-left: -6px;
|
|
260
|
+
}
|
|
261
|
+
|
|
230
262
|
.container {
|
|
231
263
|
position: absolute;
|
|
232
264
|
top: var(--default-row-height);
|
|
@@ -23,10 +23,11 @@
|
|
|
23
23
|
scrollLeft,
|
|
24
24
|
dispatch,
|
|
25
25
|
contentLines,
|
|
26
|
+
isDragging,
|
|
26
27
|
} = getContext("grid")
|
|
27
28
|
|
|
28
29
|
$: rowCount = $rows.length
|
|
29
|
-
$: selectedRowCount = Object.values($selectedRows).
|
|
30
|
+
$: selectedRowCount = Object.values($selectedRows).length
|
|
30
31
|
$: width = GutterWidth + ($stickyColumn?.width || 0)
|
|
31
32
|
|
|
32
33
|
const selectAll = () => {
|
|
@@ -50,7 +51,6 @@
|
|
|
50
51
|
>
|
|
51
52
|
<div class="header row">
|
|
52
53
|
<GutterCell
|
|
53
|
-
disableExpand
|
|
54
54
|
disableNumber
|
|
55
55
|
on:select={selectAll}
|
|
56
56
|
defaultHeight
|
|
@@ -71,8 +71,8 @@
|
|
|
71
71
|
{@const cellId = `${row._id}-${$stickyColumn?.name}`}
|
|
72
72
|
<div
|
|
73
73
|
class="row"
|
|
74
|
-
on:mouseenter={() => ($hoveredRowId = row._id)}
|
|
75
|
-
on:mouseleave={() => ($hoveredRowId = null)}
|
|
74
|
+
on:mouseenter={$isDragging ? null : () => ($hoveredRowId = row._id)}
|
|
75
|
+
on:mouseleave={$isDragging ? null : () => ($hoveredRowId = null)}
|
|
76
76
|
>
|
|
77
77
|
<GutterCell {row} {rowFocused} {rowHovered} {rowSelected} />
|
|
78
78
|
{#if $stickyColumn}
|
|
@@ -96,11 +96,13 @@
|
|
|
96
96
|
{#if $config.allowAddRows && ($renderedColumns.length || $stickyColumn)}
|
|
97
97
|
<div
|
|
98
98
|
class="row new"
|
|
99
|
-
on:mouseenter={
|
|
100
|
-
|
|
99
|
+
on:mouseenter={$isDragging
|
|
100
|
+
? null
|
|
101
|
+
: () => ($hoveredRowId = BlankRowID)}
|
|
102
|
+
on:mouseleave={$isDragging ? null : () => ($hoveredRowId = null)}
|
|
101
103
|
on:click={() => dispatch("add-row-inline")}
|
|
102
104
|
>
|
|
103
|
-
<GutterCell
|
|
105
|
+
<GutterCell rowHovered={$hoveredRowId === BlankRowID}>
|
|
104
106
|
<Icon name="Add" color="var(--spectrum-global-color-gray-500)" />
|
|
105
107
|
</GutterCell>
|
|
106
108
|
{#if $stickyColumn}
|
|
@@ -159,7 +161,7 @@
|
|
|
159
161
|
z-index: 1;
|
|
160
162
|
}
|
|
161
163
|
.header :global(.cell) {
|
|
162
|
-
background: var(--
|
|
164
|
+
background: var(--grid-background-alt);
|
|
163
165
|
}
|
|
164
166
|
.row {
|
|
165
167
|
display: flex;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
export const Padding =
|
|
2
|
-
export const MaxCellRenderHeight =
|
|
3
|
-
export const MaxCellRenderWidthOverflow = 200
|
|
1
|
+
export const Padding = 246
|
|
2
|
+
export const MaxCellRenderHeight = 222
|
|
4
3
|
export const ScrollBarSize = 8
|
|
5
4
|
export const GutterWidth = 72
|
|
6
5
|
export const DefaultColumnWidth = 200
|
|
@@ -12,3 +11,5 @@ export const DefaultRowHeight = SmallRowHeight
|
|
|
12
11
|
export const NewRowID = "new"
|
|
13
12
|
export const BlankRowID = "blank"
|
|
14
13
|
export const RowPageSize = 100
|
|
14
|
+
export const FocusedCellMinOffset = 48
|
|
15
|
+
export const MaxCellRenderWidthOverflow = Padding - 3 * ScrollBarSize
|
|
@@ -3,7 +3,7 @@ import { createWebsocket } from "../../../utils"
|
|
|
3
3
|
import { SocketEvent, GridSocketEvent } from "@budibase/shared-core"
|
|
4
4
|
|
|
5
5
|
export const createGridWebsocket = context => {
|
|
6
|
-
const { rows, tableId, users, focusedCellId, table } = context
|
|
6
|
+
const { rows, tableId, users, focusedCellId, table, API } = context
|
|
7
7
|
const socket = createWebsocket("/socket/grid")
|
|
8
8
|
|
|
9
9
|
const connectToTable = tableId => {
|
|
@@ -11,9 +11,10 @@ export const createGridWebsocket = context => {
|
|
|
11
11
|
return
|
|
12
12
|
}
|
|
13
13
|
// Identify which table we are editing
|
|
14
|
+
const appId = API.getAppID()
|
|
14
15
|
socket.emit(
|
|
15
16
|
GridSocketEvent.SelectTable,
|
|
16
|
-
{ tableId },
|
|
17
|
+
{ tableId, appId },
|
|
17
18
|
({ users: gridUsers }) => {
|
|
18
19
|
users.set(gridUsers)
|
|
19
20
|
}
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
selectedRows,
|
|
16
16
|
config,
|
|
17
17
|
menu,
|
|
18
|
+
gridFocused,
|
|
18
19
|
} = getContext("grid")
|
|
19
20
|
|
|
20
21
|
const ignoredOriginSelectors = [
|
|
@@ -24,6 +25,11 @@
|
|
|
24
25
|
|
|
25
26
|
// Global key listener which intercepts all key events
|
|
26
27
|
const handleKeyDown = e => {
|
|
28
|
+
// Ignore completely if the grid is not focused
|
|
29
|
+
if (!$gridFocused) {
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
|
|
27
33
|
// Avoid processing events sourced from certain origins
|
|
28
34
|
if (e.target?.closest) {
|
|
29
35
|
for (let selector of ignoredOriginSelectors) {
|
|
@@ -72,7 +72,9 @@
|
|
|
72
72
|
</MenuItem>
|
|
73
73
|
<MenuItem
|
|
74
74
|
icon="Maximize"
|
|
75
|
-
disabled={isNewRow ||
|
|
75
|
+
disabled={isNewRow ||
|
|
76
|
+
!$config.allowEditRows ||
|
|
77
|
+
!$config.allowExpandRows}
|
|
76
78
|
on:click={() => dispatch("edit-row", $focusedRow)}
|
|
77
79
|
on:click={menu.actions.close}
|
|
78
80
|
>
|
|
@@ -15,11 +15,18 @@
|
|
|
15
15
|
scrollLeft,
|
|
16
16
|
scrollTop,
|
|
17
17
|
height,
|
|
18
|
+
isDragging,
|
|
19
|
+
menu,
|
|
18
20
|
} = getContext("grid")
|
|
19
21
|
|
|
20
22
|
// State for dragging bars
|
|
21
23
|
let initialMouse
|
|
22
24
|
let initialScroll
|
|
25
|
+
let isDraggingV = false
|
|
26
|
+
let isDraggingH = false
|
|
27
|
+
|
|
28
|
+
// Update state to reflect if we are dragging
|
|
29
|
+
$: isDragging.set(isDraggingV || isDraggingH)
|
|
23
30
|
|
|
24
31
|
// Calculate V scrollbar size and offset
|
|
25
32
|
// Terminology is the same for both axes:
|
|
@@ -39,6 +46,13 @@
|
|
|
39
46
|
$: availWidth = renderWidth - barWidth
|
|
40
47
|
$: barLeft = ScrollBarSize + availWidth * ($scrollLeft / $maxScrollLeft)
|
|
41
48
|
|
|
49
|
+
// Helper to close the context menu if it's open
|
|
50
|
+
const closeMenu = () => {
|
|
51
|
+
if ($menu.visible) {
|
|
52
|
+
menu.actions.close()
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
42
56
|
// V scrollbar drag handlers
|
|
43
57
|
const startVDragging = e => {
|
|
44
58
|
e.preventDefault()
|
|
@@ -46,6 +60,8 @@
|
|
|
46
60
|
initialScroll = $scrollTop
|
|
47
61
|
document.addEventListener("mousemove", moveVDragging)
|
|
48
62
|
document.addEventListener("mouseup", stopVDragging)
|
|
63
|
+
isDraggingV = true
|
|
64
|
+
closeMenu()
|
|
49
65
|
}
|
|
50
66
|
const moveVDragging = domDebounce(e => {
|
|
51
67
|
const delta = e.clientY - initialMouse
|
|
@@ -59,6 +75,7 @@
|
|
|
59
75
|
const stopVDragging = () => {
|
|
60
76
|
document.removeEventListener("mousemove", moveVDragging)
|
|
61
77
|
document.removeEventListener("mouseup", stopVDragging)
|
|
78
|
+
isDraggingV = false
|
|
62
79
|
}
|
|
63
80
|
|
|
64
81
|
// H scrollbar drag handlers
|
|
@@ -68,6 +85,8 @@
|
|
|
68
85
|
initialScroll = $scrollLeft
|
|
69
86
|
document.addEventListener("mousemove", moveHDragging)
|
|
70
87
|
document.addEventListener("mouseup", stopHDragging)
|
|
88
|
+
isDraggingH = true
|
|
89
|
+
closeMenu()
|
|
71
90
|
}
|
|
72
91
|
const moveHDragging = domDebounce(e => {
|
|
73
92
|
const delta = e.clientX - initialMouse
|
|
@@ -81,6 +100,7 @@
|
|
|
81
100
|
const stopHDragging = () => {
|
|
82
101
|
document.removeEventListener("mousemove", moveHDragging)
|
|
83
102
|
document.removeEventListener("mouseup", stopHDragging)
|
|
103
|
+
isDraggingH = false
|
|
84
104
|
}
|
|
85
105
|
</script>
|
|
86
106
|
|
|
@@ -89,6 +109,7 @@
|
|
|
89
109
|
class="v-scrollbar"
|
|
90
110
|
style="--size:{ScrollBarSize}px; top:{barTop}px; height:{barHeight}px;"
|
|
91
111
|
on:mousedown={startVDragging}
|
|
112
|
+
class:dragging={isDraggingV}
|
|
92
113
|
/>
|
|
93
114
|
{/if}
|
|
94
115
|
{#if $showHScrollbar}
|
|
@@ -96,6 +117,7 @@
|
|
|
96
117
|
class="h-scrollbar"
|
|
97
118
|
style="--size:{ScrollBarSize}px; left:{barLeft}px; width:{barWidth}px;"
|
|
98
119
|
on:mousedown={startHDragging}
|
|
120
|
+
class:dragging={isDraggingH}
|
|
99
121
|
/>
|
|
100
122
|
{/if}
|
|
101
123
|
|
|
@@ -103,11 +125,12 @@
|
|
|
103
125
|
div {
|
|
104
126
|
position: absolute;
|
|
105
127
|
background: var(--spectrum-global-color-gray-500);
|
|
106
|
-
opacity: 0.
|
|
128
|
+
opacity: 0.5;
|
|
107
129
|
border-radius: 4px;
|
|
108
130
|
transition: opacity 130ms ease-out;
|
|
109
131
|
}
|
|
110
|
-
div:hover
|
|
132
|
+
div:hover,
|
|
133
|
+
div.dragging {
|
|
111
134
|
opacity: 1;
|
|
112
135
|
}
|
|
113
136
|
.v-scrollbar {
|