@budibase/frontend-core 2.23.11 → 2.24.0
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 +5 -5
- package/src/api/backups.js +0 -3
- package/src/components/grid/cells/AttachmentCell.svelte +27 -28
- package/src/components/grid/cells/BBReferenceCell.svelte +6 -3
- package/src/components/grid/cells/DateCell.svelte +90 -60
- package/src/components/grid/cells/GridCell.svelte +3 -0
- package/src/components/grid/cells/HeaderCell.svelte +99 -102
- package/src/components/grid/cells/LongFormCell.svelte +30 -34
- package/src/components/grid/cells/OptionsCell.svelte +20 -35
- package/src/components/grid/cells/RelationshipCell.svelte +17 -64
- package/src/components/grid/controls/HideColumnsButton.svelte +1 -0
- package/src/components/grid/controls/MigrationModal.svelte +7 -3
- package/src/components/grid/layout/Grid.svelte +13 -7
- package/src/components/grid/layout/GridScrollWrapper.svelte +4 -0
- package/src/components/grid/layout/NewColumnButton.svelte +23 -21
- package/src/components/grid/layout/NewRow.svelte +6 -1
- package/src/components/grid/lib/constants.js +9 -4
- package/src/components/grid/lib/utils.js +7 -0
- package/src/components/grid/overlays/GridPopover.svelte +71 -0
- package/src/components/grid/overlays/KeyboardManager.svelte +1 -0
- package/src/components/grid/overlays/MenuOverlay.svelte +68 -66
- package/src/components/grid/overlays/PopoverOverlay.svelte +9 -0
- package/src/components/grid/overlays/ResizeOverlay.svelte +2 -0
- package/src/components/grid/overlays/ScrollOverlay.svelte +10 -14
- package/src/components/grid/stores/columns.js +44 -20
- package/src/components/grid/stores/menu.js +2 -2
- package/src/components/grid/stores/reorder.js +26 -16
- package/src/components/grid/stores/resize.js +13 -2
- package/src/components/grid/stores/rows.js +41 -8
- package/src/components/grid/stores/ui.js +1 -1
- package/src/components/grid/stores/viewport.js +4 -5
- package/src/constants.js +3 -3
- package/src/utils/rows.js +4 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import { onMount, tick } from "svelte"
|
|
3
3
|
import { clickOutside } from "@budibase/bbui"
|
|
4
|
+
import GridPopover from "../overlays/GridPopover.svelte"
|
|
4
5
|
|
|
5
6
|
export let value
|
|
6
7
|
export let focused = false
|
|
@@ -8,10 +9,10 @@
|
|
|
8
9
|
export let readonly = false
|
|
9
10
|
export let api
|
|
10
11
|
export let invertX = false
|
|
11
|
-
export let invertY = false
|
|
12
12
|
|
|
13
13
|
let textarea
|
|
14
14
|
let isOpen = false
|
|
15
|
+
let anchor
|
|
15
16
|
|
|
16
17
|
$: editable = focused && !readonly
|
|
17
18
|
$: {
|
|
@@ -52,25 +53,30 @@
|
|
|
52
53
|
})
|
|
53
54
|
</script>
|
|
54
55
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
/>
|
|
66
|
-
{:else}
|
|
67
|
-
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
|
68
|
-
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
69
|
-
<div class="long-form-cell" on:click={editable ? open : null} class:editable>
|
|
70
|
-
<div class="value">
|
|
71
|
-
{value || ""}
|
|
72
|
-
</div>
|
|
56
|
+
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
|
57
|
+
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
58
|
+
<div
|
|
59
|
+
class="long-form-cell"
|
|
60
|
+
on:click={editable ? open : null}
|
|
61
|
+
class:editable
|
|
62
|
+
bind:this={anchor}
|
|
63
|
+
>
|
|
64
|
+
<div class="value">
|
|
65
|
+
{value || ""}
|
|
73
66
|
</div>
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
{#if isOpen}
|
|
70
|
+
<GridPopover {anchor} {invertX} on:close={close}>
|
|
71
|
+
<textarea
|
|
72
|
+
bind:this={textarea}
|
|
73
|
+
value={value || ""}
|
|
74
|
+
on:change={handleChange}
|
|
75
|
+
on:wheel|stopPropagation
|
|
76
|
+
spellcheck="false"
|
|
77
|
+
use:clickOutside={close}
|
|
78
|
+
/>
|
|
79
|
+
</GridPopover>
|
|
74
80
|
{/if}
|
|
75
81
|
|
|
76
82
|
<style>
|
|
@@ -93,30 +99,20 @@
|
|
|
93
99
|
line-height: 20px;
|
|
94
100
|
}
|
|
95
101
|
textarea {
|
|
102
|
+
border: none;
|
|
103
|
+
width: 320px;
|
|
104
|
+
flex: 1 1 auto;
|
|
105
|
+
height: var(--max-cell-render-overflow);
|
|
96
106
|
padding: var(--cell-padding);
|
|
97
107
|
margin: 0;
|
|
98
|
-
border: 2px solid var(--cell-color);
|
|
99
108
|
background: var(--cell-background);
|
|
100
109
|
font-size: var(--cell-font-size);
|
|
101
110
|
font-family: var(--font-sans);
|
|
102
111
|
color: inherit;
|
|
103
|
-
position: absolute;
|
|
104
|
-
top: 0;
|
|
105
|
-
left: 0;
|
|
106
|
-
width: calc(100% + var(--max-cell-render-width-overflow));
|
|
107
|
-
height: calc(var(--row-height) + var(--max-cell-render-height));
|
|
108
112
|
z-index: 1;
|
|
109
|
-
border-radius: 2px;
|
|
110
113
|
resize: none;
|
|
111
114
|
line-height: 20px;
|
|
112
|
-
|
|
113
|
-
textarea.invertX {
|
|
114
|
-
left: auto;
|
|
115
|
-
right: 0;
|
|
116
|
-
}
|
|
117
|
-
textarea.invertY {
|
|
118
|
-
transform: translateY(-100%);
|
|
119
|
-
top: calc(100% + 1px);
|
|
115
|
+
overflow: auto;
|
|
120
116
|
}
|
|
121
117
|
textarea:focus {
|
|
122
118
|
outline: none;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
<script>
|
|
2
|
-
import { Icon
|
|
2
|
+
import { Icon } from "@budibase/bbui"
|
|
3
3
|
import { getColor } from "../lib/utils"
|
|
4
4
|
import { onMount } from "svelte"
|
|
5
|
+
import GridPopover from "../overlays/GridPopover.svelte"
|
|
5
6
|
|
|
6
7
|
export let value
|
|
7
8
|
export let schema
|
|
@@ -10,12 +11,12 @@
|
|
|
10
11
|
export let multi = false
|
|
11
12
|
export let readonly = false
|
|
12
13
|
export let api
|
|
13
|
-
export let invertX
|
|
14
|
-
export let invertY = false
|
|
14
|
+
export let invertX
|
|
15
15
|
export let contentLines = 1
|
|
16
16
|
|
|
17
17
|
let isOpen = false
|
|
18
18
|
let focusedOptionIdx = null
|
|
19
|
+
let anchor
|
|
19
20
|
|
|
20
21
|
$: options = schema?.constraints?.inclusion || []
|
|
21
22
|
$: optionColors = schema?.optionColors || {}
|
|
@@ -23,7 +24,7 @@
|
|
|
23
24
|
$: values = Array.isArray(value) ? value : [value].filter(x => x != null)
|
|
24
25
|
$: {
|
|
25
26
|
// Close when deselected
|
|
26
|
-
if (!focused) {
|
|
27
|
+
if (!focused && isOpen) {
|
|
27
28
|
close()
|
|
28
29
|
}
|
|
29
30
|
}
|
|
@@ -89,6 +90,7 @@
|
|
|
89
90
|
class:editable
|
|
90
91
|
class:open
|
|
91
92
|
on:click|self={editable ? open : null}
|
|
93
|
+
bind:this={anchor}
|
|
92
94
|
>
|
|
93
95
|
<div
|
|
94
96
|
class="values"
|
|
@@ -115,16 +117,15 @@
|
|
|
115
117
|
<Icon name="ChevronDown" />
|
|
116
118
|
</div>
|
|
117
119
|
{/if}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
on:wheel={e => e.stopPropagation()}
|
|
124
|
-
use:clickOutside={close}
|
|
125
|
-
>
|
|
120
|
+
</div>
|
|
121
|
+
|
|
122
|
+
{#if isOpen}
|
|
123
|
+
<GridPopover {anchor} {invertX} on:close={close}>
|
|
124
|
+
<div class="options">
|
|
126
125
|
{#each options as option, idx}
|
|
127
126
|
{@const color = optionColors[option] || getOptionColor(option)}
|
|
127
|
+
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
|
128
|
+
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
128
129
|
<div
|
|
129
130
|
class="option"
|
|
130
131
|
on:click={() => toggleOption(option)}
|
|
@@ -132,7 +133,9 @@
|
|
|
132
133
|
on:mouseenter={() => (focusedOptionIdx = idx)}
|
|
133
134
|
>
|
|
134
135
|
<div class="badge text" style="--color: {color}">
|
|
135
|
-
|
|
136
|
+
<span>
|
|
137
|
+
{option}
|
|
138
|
+
</span>
|
|
136
139
|
</div>
|
|
137
140
|
{#if values.includes(option)}
|
|
138
141
|
<Icon name="Checkmark" color="var(--accent-color)" />
|
|
@@ -140,8 +143,8 @@
|
|
|
140
143
|
</div>
|
|
141
144
|
{/each}
|
|
142
145
|
</div>
|
|
143
|
-
|
|
144
|
-
|
|
146
|
+
</GridPopover>
|
|
147
|
+
{/if}
|
|
145
148
|
|
|
146
149
|
<style>
|
|
147
150
|
.container {
|
|
@@ -211,28 +214,10 @@
|
|
|
211
214
|
);
|
|
212
215
|
}
|
|
213
216
|
.options {
|
|
214
|
-
min-width: calc(100% + 2px);
|
|
215
|
-
position: absolute;
|
|
216
|
-
top: 100%;
|
|
217
|
-
left: -1px;
|
|
218
217
|
display: flex;
|
|
219
218
|
flex-direction: column;
|
|
220
219
|
justify-content: flex-start;
|
|
221
220
|
align-items: stretch;
|
|
222
|
-
max-height: var(--max-cell-render-height);
|
|
223
|
-
overflow-y: auto;
|
|
224
|
-
border: var(--cell-border);
|
|
225
|
-
box-shadow: 0 0 20px -4px rgba(0, 0, 0, 0.15);
|
|
226
|
-
border-bottom-left-radius: 2px;
|
|
227
|
-
border-bottom-right-radius: 2px;
|
|
228
|
-
}
|
|
229
|
-
.options.invertX {
|
|
230
|
-
left: auto;
|
|
231
|
-
right: 0;
|
|
232
|
-
}
|
|
233
|
-
.options.invertY {
|
|
234
|
-
transform: translateY(-100%);
|
|
235
|
-
top: 0;
|
|
236
221
|
}
|
|
237
222
|
.option {
|
|
238
223
|
flex: 0 0 var(--default-row-height);
|
|
@@ -242,10 +227,10 @@
|
|
|
242
227
|
justify-content: space-between;
|
|
243
228
|
align-items: center;
|
|
244
229
|
gap: var(--cell-spacing);
|
|
245
|
-
background-color: var(--grid-background-alt);
|
|
246
230
|
}
|
|
247
231
|
.option:hover,
|
|
248
232
|
.option.focused {
|
|
249
|
-
background-color: var(--
|
|
233
|
+
background-color: var(--grid-background-alt);
|
|
234
|
+
cursor: pointer;
|
|
250
235
|
}
|
|
251
236
|
</style>
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import { getColor } from "../lib/utils"
|
|
3
3
|
import { onMount, getContext } from "svelte"
|
|
4
|
-
import { Icon, Input, ProgressCircle
|
|
4
|
+
import { Icon, Input, ProgressCircle } from "@budibase/bbui"
|
|
5
5
|
import { debounce } from "../../../utils/utils"
|
|
6
|
+
import GridPopover from "../overlays/GridPopover.svelte"
|
|
6
7
|
|
|
7
|
-
const { API,
|
|
8
|
+
const { API, cache } = getContext("grid")
|
|
8
9
|
|
|
9
10
|
export let value
|
|
10
11
|
export let api
|
|
@@ -13,7 +14,6 @@
|
|
|
13
14
|
export let schema
|
|
14
15
|
export let onChange
|
|
15
16
|
export let invertX = false
|
|
16
|
-
export let invertY = false
|
|
17
17
|
export let contentLines = 1
|
|
18
18
|
export let searchFunction = API.searchTable
|
|
19
19
|
export let primaryDisplay
|
|
@@ -27,15 +27,15 @@
|
|
|
27
27
|
let candidateIndex
|
|
28
28
|
let lastSearchId
|
|
29
29
|
let searching = false
|
|
30
|
-
let valuesHeight = 0
|
|
31
30
|
let container
|
|
31
|
+
let anchor
|
|
32
32
|
|
|
33
33
|
$: oneRowOnly = schema?.relationshipType === "one-to-many"
|
|
34
34
|
$: editable = focused && !readonly
|
|
35
35
|
$: lookupMap = buildLookupMap(value, isOpen)
|
|
36
36
|
$: debouncedSearch(searchString)
|
|
37
37
|
$: {
|
|
38
|
-
if (!focused) {
|
|
38
|
+
if (!focused && isOpen) {
|
|
39
39
|
close()
|
|
40
40
|
}
|
|
41
41
|
}
|
|
@@ -125,7 +125,6 @@
|
|
|
125
125
|
|
|
126
126
|
const open = async () => {
|
|
127
127
|
isOpen = true
|
|
128
|
-
valuesHeight = container.getBoundingClientRect().height
|
|
129
128
|
|
|
130
129
|
// Find the primary display for the related table
|
|
131
130
|
if (!primaryDisplay) {
|
|
@@ -204,14 +203,6 @@
|
|
|
204
203
|
close()
|
|
205
204
|
}
|
|
206
205
|
|
|
207
|
-
const showRelationship = async id => {
|
|
208
|
-
const relatedRow = await API.fetchRow({
|
|
209
|
-
tableId: schema.tableId,
|
|
210
|
-
rowId: id,
|
|
211
|
-
})
|
|
212
|
-
dispatch("edit-row", relatedRow)
|
|
213
|
-
}
|
|
214
|
-
|
|
215
206
|
const readable = value => {
|
|
216
207
|
if (value == null) {
|
|
217
208
|
return ""
|
|
@@ -238,8 +229,8 @@
|
|
|
238
229
|
class="wrapper"
|
|
239
230
|
class:editable
|
|
240
231
|
class:focused
|
|
241
|
-
class:invertY
|
|
242
232
|
style="--color:{color};"
|
|
233
|
+
bind:this={anchor}
|
|
243
234
|
>
|
|
244
235
|
<div class="container" bind:this={container}>
|
|
245
236
|
<div
|
|
@@ -250,11 +241,7 @@
|
|
|
250
241
|
{#each value || [] as relationship}
|
|
251
242
|
{#if relationship[primaryDisplay] || relationship.primaryDisplay}
|
|
252
243
|
<div class="badge">
|
|
253
|
-
<span
|
|
254
|
-
on:click={editable
|
|
255
|
-
? () => showRelationship(relationship._id)
|
|
256
|
-
: null}
|
|
257
|
-
>
|
|
244
|
+
<span>
|
|
258
245
|
{readable(
|
|
259
246
|
relationship[primaryDisplay] || relationship.primaryDisplay
|
|
260
247
|
)}
|
|
@@ -282,16 +269,13 @@
|
|
|
282
269
|
</div>
|
|
283
270
|
{/if}
|
|
284
271
|
</div>
|
|
272
|
+
</div>
|
|
285
273
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
on:wheel|stopPropagation
|
|
292
|
-
use:clickOutside={close}
|
|
293
|
-
style="--values-height:{valuesHeight}px;"
|
|
294
|
-
>
|
|
274
|
+
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
|
275
|
+
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
276
|
+
{#if isOpen}
|
|
277
|
+
<GridPopover open={isOpen} {anchor} {invertX} on:close={close}>
|
|
278
|
+
<div class="dropdown" on:wheel|stopPropagation>
|
|
295
279
|
<div class="search">
|
|
296
280
|
<Input
|
|
297
281
|
autofocus
|
|
@@ -327,8 +311,8 @@
|
|
|
327
311
|
</div>
|
|
328
312
|
{/if}
|
|
329
313
|
</div>
|
|
330
|
-
|
|
331
|
-
|
|
314
|
+
</GridPopover>
|
|
315
|
+
{/if}
|
|
332
316
|
|
|
333
317
|
<style>
|
|
334
318
|
.wrapper {
|
|
@@ -337,7 +321,6 @@
|
|
|
337
321
|
min-height: var(--row-height);
|
|
338
322
|
max-height: var(--row-height);
|
|
339
323
|
overflow: hidden;
|
|
340
|
-
--max-relationship-height: 96px;
|
|
341
324
|
}
|
|
342
325
|
.wrapper.focused {
|
|
343
326
|
position: absolute;
|
|
@@ -349,10 +332,6 @@
|
|
|
349
332
|
max-height: none;
|
|
350
333
|
overflow: visible;
|
|
351
334
|
}
|
|
352
|
-
.wrapper.invertY {
|
|
353
|
-
top: auto;
|
|
354
|
-
bottom: 0;
|
|
355
|
-
}
|
|
356
335
|
|
|
357
336
|
.container {
|
|
358
337
|
min-height: var(--row-height);
|
|
@@ -363,7 +342,6 @@
|
|
|
363
342
|
.focused .container {
|
|
364
343
|
overflow-y: auto;
|
|
365
344
|
border-radius: 2px;
|
|
366
|
-
max-height: var(--max-relationship-height);
|
|
367
345
|
}
|
|
368
346
|
.focused .container:after {
|
|
369
347
|
content: " ";
|
|
@@ -426,10 +404,6 @@
|
|
|
426
404
|
white-space: nowrap;
|
|
427
405
|
text-overflow: ellipsis;
|
|
428
406
|
}
|
|
429
|
-
.editable .values .badge span:hover {
|
|
430
|
-
cursor: pointer;
|
|
431
|
-
text-decoration: underline;
|
|
432
|
-
}
|
|
433
407
|
|
|
434
408
|
.add {
|
|
435
409
|
background: var(--spectrum-global-color-gray-200);
|
|
@@ -446,30 +420,9 @@
|
|
|
446
420
|
}
|
|
447
421
|
|
|
448
422
|
.dropdown {
|
|
449
|
-
position: absolute;
|
|
450
|
-
top: 100%;
|
|
451
|
-
left: 0;
|
|
452
|
-
width: 100%;
|
|
453
|
-
max-height: calc(
|
|
454
|
-
var(--max-cell-render-height) + var(--row-height) - var(--values-height)
|
|
455
|
-
);
|
|
456
|
-
background: var(--grid-background-alt);
|
|
457
|
-
border: var(--cell-border);
|
|
458
|
-
box-shadow: 0 0 20px -4px rgba(0, 0, 0, 0.15);
|
|
459
423
|
display: flex;
|
|
460
424
|
flex-direction: column;
|
|
461
425
|
align-items: stretch;
|
|
462
|
-
padding: 0 0 8px 0;
|
|
463
|
-
border-bottom-left-radius: 2px;
|
|
464
|
-
border-bottom-right-radius: 2px;
|
|
465
|
-
}
|
|
466
|
-
.dropdown.invertY {
|
|
467
|
-
transform: translateY(-100%);
|
|
468
|
-
top: -1px;
|
|
469
|
-
}
|
|
470
|
-
.dropdown.invertX {
|
|
471
|
-
left: auto;
|
|
472
|
-
right: 0;
|
|
473
426
|
}
|
|
474
427
|
|
|
475
428
|
.searching {
|
|
@@ -497,7 +450,8 @@
|
|
|
497
450
|
cursor: pointer;
|
|
498
451
|
}
|
|
499
452
|
.result .badge {
|
|
500
|
-
|
|
453
|
+
flex: 1 1 auto;
|
|
454
|
+
overflow: hidden;
|
|
501
455
|
}
|
|
502
456
|
|
|
503
457
|
.search {
|
|
@@ -505,7 +459,6 @@
|
|
|
505
459
|
display: flex;
|
|
506
460
|
align-items: center;
|
|
507
461
|
margin: 4px var(--cell-padding);
|
|
508
|
-
width: calc(100% - 2 * var(--cell-padding));
|
|
509
462
|
}
|
|
510
463
|
.search :global(.spectrum-Textfield) {
|
|
511
464
|
min-width: 0;
|
|
@@ -7,7 +7,11 @@
|
|
|
7
7
|
} from "@budibase/bbui"
|
|
8
8
|
import { getContext } from "svelte"
|
|
9
9
|
import { ValidColumnNameRegex } from "@budibase/shared-core"
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
BBReferenceFieldSubType,
|
|
12
|
+
FieldType,
|
|
13
|
+
RelationshipType,
|
|
14
|
+
} from "@budibase/types"
|
|
11
15
|
|
|
12
16
|
const { API, definition, rows } = getContext("grid")
|
|
13
17
|
|
|
@@ -29,9 +33,9 @@
|
|
|
29
33
|
}
|
|
30
34
|
|
|
31
35
|
const migrateUserColumn = async () => {
|
|
32
|
-
let subtype =
|
|
36
|
+
let subtype = BBReferenceFieldSubType.USERS
|
|
33
37
|
if (column.schema.relationshipType === RelationshipType.ONE_TO_MANY) {
|
|
34
|
-
subtype =
|
|
38
|
+
subtype = BBReferenceFieldSubType.USER
|
|
35
39
|
}
|
|
36
40
|
|
|
37
41
|
try {
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import GridBody from "./GridBody.svelte"
|
|
11
11
|
import ResizeOverlay from "../overlays/ResizeOverlay.svelte"
|
|
12
12
|
import ReorderOverlay from "../overlays/ReorderOverlay.svelte"
|
|
13
|
+
import PopoverOverlay from "../overlays/PopoverOverlay.svelte"
|
|
13
14
|
import HeaderRow from "./HeaderRow.svelte"
|
|
14
15
|
import ScrollOverlay from "../overlays/ScrollOverlay.svelte"
|
|
15
16
|
import MenuOverlay from "../overlays/MenuOverlay.svelte"
|
|
@@ -22,10 +23,12 @@
|
|
|
22
23
|
import NewRow from "./NewRow.svelte"
|
|
23
24
|
import { createGridWebsocket } from "../lib/websocket"
|
|
24
25
|
import {
|
|
25
|
-
|
|
26
|
-
MaxCellRenderWidthOverflow,
|
|
26
|
+
MaxCellRenderOverflow,
|
|
27
27
|
GutterWidth,
|
|
28
28
|
DefaultRowHeight,
|
|
29
|
+
Padding,
|
|
30
|
+
SmallRowHeight,
|
|
31
|
+
ControlsHeight,
|
|
29
32
|
} from "../lib/constants"
|
|
30
33
|
|
|
31
34
|
export let API = null
|
|
@@ -52,7 +55,7 @@
|
|
|
52
55
|
export let buttons = null
|
|
53
56
|
|
|
54
57
|
// Unique identifier for DOM nodes inside this instance
|
|
55
|
-
const
|
|
58
|
+
const gridID = `grid-${Math.random().toString().slice(2)}`
|
|
56
59
|
|
|
57
60
|
// Store props in a store for reference in other stores
|
|
58
61
|
const props = writable($$props)
|
|
@@ -60,7 +63,7 @@
|
|
|
60
63
|
// Build up context
|
|
61
64
|
let context = {
|
|
62
65
|
API: API || createAPIClient(),
|
|
63
|
-
|
|
66
|
+
gridID,
|
|
64
67
|
props,
|
|
65
68
|
}
|
|
66
69
|
context = { ...context, ...createEventManagers() }
|
|
@@ -104,6 +107,8 @@
|
|
|
104
107
|
notifyError,
|
|
105
108
|
buttons,
|
|
106
109
|
})
|
|
110
|
+
$: minHeight =
|
|
111
|
+
Padding + SmallRowHeight + $rowHeight + (showControls ? ControlsHeight : 0)
|
|
107
112
|
|
|
108
113
|
// Set context for children to consume
|
|
109
114
|
setContext("grid", context)
|
|
@@ -122,14 +127,14 @@
|
|
|
122
127
|
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
|
123
128
|
<div
|
|
124
129
|
class="grid"
|
|
125
|
-
id=
|
|
130
|
+
id={gridID}
|
|
126
131
|
class:is-resizing={$isResizing}
|
|
127
132
|
class:is-reordering={$isReordering}
|
|
128
133
|
class:stripe={stripeRows}
|
|
129
134
|
class:quiet
|
|
130
135
|
on:mouseenter={() => gridFocused.set(true)}
|
|
131
136
|
on:mouseleave={() => gridFocused.set(false)}
|
|
132
|
-
style="--row-height:{$rowHeight}px; --default-row-height:{DefaultRowHeight}px; --gutter-width:{GutterWidth}px; --max-cell-render-
|
|
137
|
+
style="--row-height:{$rowHeight}px; --default-row-height:{DefaultRowHeight}px; --gutter-width:{GutterWidth}px; --max-cell-render-overflow:{MaxCellRenderOverflow}px; --content-lines:{$contentLines}; --min-height:{minHeight}px; --controls-height:{ControlsHeight}px;"
|
|
133
138
|
>
|
|
134
139
|
{#if showControls}
|
|
135
140
|
<div class="controls">
|
|
@@ -181,6 +186,7 @@
|
|
|
181
186
|
<ReorderOverlay />
|
|
182
187
|
<ScrollOverlay />
|
|
183
188
|
<MenuOverlay />
|
|
189
|
+
<PopoverOverlay />
|
|
184
190
|
</div>
|
|
185
191
|
</div>
|
|
186
192
|
</div>
|
|
@@ -210,7 +216,6 @@
|
|
|
210
216
|
--cell-spacing: 4px;
|
|
211
217
|
--cell-border: 1px solid var(--spectrum-global-color-gray-200);
|
|
212
218
|
--cell-font-size: 14px;
|
|
213
|
-
--controls-height: 50px;
|
|
214
219
|
flex: 1 1 auto;
|
|
215
220
|
display: flex;
|
|
216
221
|
flex-direction: column;
|
|
@@ -219,6 +224,7 @@
|
|
|
219
224
|
position: relative;
|
|
220
225
|
overflow: hidden;
|
|
221
226
|
background: var(--grid-background);
|
|
227
|
+
min-height: var(--min-height);
|
|
222
228
|
}
|
|
223
229
|
.grid,
|
|
224
230
|
.grid :global(*) {
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
bounds,
|
|
13
13
|
hoveredRowId,
|
|
14
14
|
menu,
|
|
15
|
+
focusedCellAPI,
|
|
15
16
|
} = getContext("grid")
|
|
16
17
|
|
|
17
18
|
export let scrollVertically = false
|
|
@@ -35,6 +36,9 @@
|
|
|
35
36
|
e.preventDefault()
|
|
36
37
|
updateScroll(e.deltaX, e.deltaY, e.clientY)
|
|
37
38
|
|
|
39
|
+
// Close any open popovers when scrolling
|
|
40
|
+
$focusedCellAPI?.blur()
|
|
41
|
+
|
|
38
42
|
// If a context menu was visible, hide it
|
|
39
43
|
if ($menu.visible) {
|
|
40
44
|
menu.actions.close()
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import { getContext, onMount } from "svelte"
|
|
3
|
-
import { Icon
|
|
3
|
+
import { Icon } from "@budibase/bbui"
|
|
4
|
+
import GridPopover from "../overlays/GridPopover.svelte"
|
|
4
5
|
|
|
5
|
-
const { visibleColumns, scroll, width, subscribe } = getContext("grid")
|
|
6
|
+
const { visibleColumns, scroll, width, subscribe, ui } = getContext("grid")
|
|
6
7
|
|
|
7
8
|
let anchor
|
|
8
|
-
let
|
|
9
|
+
let isOpen = false
|
|
9
10
|
|
|
10
11
|
$: columnsWidth = $visibleColumns.reduce(
|
|
11
12
|
(total, col) => (total += col.width),
|
|
@@ -14,8 +15,13 @@
|
|
|
14
15
|
$: end = columnsWidth - 1 - $scroll.left
|
|
15
16
|
$: left = Math.min($width - 40, end)
|
|
16
17
|
|
|
18
|
+
const open = () => {
|
|
19
|
+
ui.actions.blur()
|
|
20
|
+
isOpen = true
|
|
21
|
+
}
|
|
22
|
+
|
|
17
23
|
const close = () => {
|
|
18
|
-
|
|
24
|
+
isOpen = false
|
|
19
25
|
}
|
|
20
26
|
|
|
21
27
|
onMount(() => subscribe("close-edit-column", close))
|
|
@@ -28,27 +34,23 @@
|
|
|
28
34
|
bind:this={anchor}
|
|
29
35
|
class="add"
|
|
30
36
|
style="left:{left}px"
|
|
31
|
-
on:click={
|
|
37
|
+
on:click={open}
|
|
32
38
|
>
|
|
33
39
|
<Icon name="Add" />
|
|
34
40
|
</div>
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
>
|
|
43
|
-
<div
|
|
44
|
-
use:clickOutside={() => {
|
|
45
|
-
open = false
|
|
46
|
-
}}
|
|
47
|
-
class="content"
|
|
41
|
+
{#if isOpen}
|
|
42
|
+
<GridPopover
|
|
43
|
+
{anchor}
|
|
44
|
+
align={$visibleColumns.length ? "right" : "left"}
|
|
45
|
+
on:close={close}
|
|
46
|
+
maxHeight={null}
|
|
47
|
+
resizable
|
|
48
48
|
>
|
|
49
|
-
<
|
|
50
|
-
|
|
51
|
-
</
|
|
49
|
+
<div class="content">
|
|
50
|
+
<slot />
|
|
51
|
+
</div>
|
|
52
|
+
</GridPopover>
|
|
53
|
+
{/if}
|
|
52
54
|
|
|
53
55
|
<style>
|
|
54
56
|
.add {
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
refreshing,
|
|
31
31
|
config,
|
|
32
32
|
filter,
|
|
33
|
+
inlineFilters,
|
|
33
34
|
columnRenderMap,
|
|
34
35
|
} = getContext("grid")
|
|
35
36
|
|
|
@@ -157,7 +158,11 @@
|
|
|
157
158
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
158
159
|
<TempTooltip
|
|
159
160
|
text="Click here to create your first row"
|
|
160
|
-
condition={hasNoRows &&
|
|
161
|
+
condition={hasNoRows &&
|
|
162
|
+
$loaded &&
|
|
163
|
+
!$filter?.length &&
|
|
164
|
+
!$inlineFilters?.length &&
|
|
165
|
+
!$refreshing}
|
|
161
166
|
type={TooltipType.Info}
|
|
162
167
|
>
|
|
163
168
|
{#if !visible && !selectedRowCount && $config.canAddRows}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
export const Padding =
|
|
2
|
-
export const MaxCellRenderHeight = 222
|
|
1
|
+
export const Padding = 100
|
|
3
2
|
export const ScrollBarSize = 8
|
|
4
3
|
export const GutterWidth = 72
|
|
5
4
|
export const DefaultColumnWidth = 200
|
|
@@ -11,5 +10,11 @@ export const DefaultRowHeight = SmallRowHeight
|
|
|
11
10
|
export const NewRowID = "new"
|
|
12
11
|
export const BlankRowID = "blank"
|
|
13
12
|
export const RowPageSize = 100
|
|
14
|
-
export const FocusedCellMinOffset =
|
|
15
|
-
export const
|
|
13
|
+
export const FocusedCellMinOffset = ScrollBarSize * 3
|
|
14
|
+
export const ControlsHeight = 50
|
|
15
|
+
|
|
16
|
+
// Popovers
|
|
17
|
+
export const PopoverMinWidth = 200
|
|
18
|
+
export const PopoverMaxWidth = 400
|
|
19
|
+
export const PopoverMaxHeight = 236
|
|
20
|
+
export const MaxCellRenderOverflow = 222
|