@budibase/frontend-core 2.5.6-alpha.3 → 2.5.6-alpha.31
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 +6 -4
- package/src/api/other.js +0 -9
- package/src/components/grid/cells/AttachmentCell.svelte +154 -0
- package/src/components/grid/cells/BooleanCell.svelte +44 -0
- package/src/components/grid/cells/DataCell.svelte +88 -0
- package/src/components/grid/cells/DateCell.svelte +77 -0
- package/src/components/grid/cells/FormulaCell.svelte +5 -0
- package/src/components/grid/cells/GridCell.svelte +162 -0
- package/src/components/grid/cells/GutterCell.svelte +127 -0
- package/src/components/grid/cells/HeaderCell.svelte +246 -0
- package/src/components/grid/cells/JSONCell.svelte +36 -0
- package/src/components/grid/cells/LongFormCell.svelte +120 -0
- package/src/components/grid/cells/MultiSelectCell.svelte +7 -0
- package/src/components/grid/cells/NumberCell.svelte +7 -0
- package/src/components/grid/cells/OptionsCell.svelte +240 -0
- package/src/components/grid/cells/RelationshipCell.svelte +504 -0
- package/src/components/grid/cells/TextCell.svelte +111 -0
- package/src/components/grid/controls/AddColumnButton.svelte +16 -0
- package/src/components/grid/controls/AddRowButton.svelte +18 -0
- package/src/components/grid/controls/BetaButton.svelte +46 -0
- package/src/components/grid/controls/ColumnWidthButton.svelte +91 -0
- package/src/components/grid/controls/DeleteButton.svelte +66 -0
- package/src/components/grid/controls/HideColumnsButton.svelte +95 -0
- package/src/components/grid/controls/RowHeightButton.svelte +70 -0
- package/src/components/grid/controls/SortButton.svelte +116 -0
- package/src/components/grid/index.js +1 -0
- package/src/components/grid/layout/Avatar.svelte +24 -0
- package/src/components/grid/layout/Grid.svelte +254 -0
- package/src/components/grid/layout/GridBody.svelte +73 -0
- package/src/components/grid/layout/GridRow.svelte +57 -0
- package/src/components/grid/layout/GridScrollWrapper.svelte +81 -0
- package/src/components/grid/layout/HeaderRow.svelte +62 -0
- package/src/components/grid/layout/NewRow.svelte +265 -0
- package/src/components/grid/layout/RowCount.svelte +9 -0
- package/src/components/grid/layout/StickyColumn.svelte +171 -0
- package/src/components/grid/layout/UserAvatars.svelte +20 -0
- package/src/components/grid/lib/constants.js +14 -0
- package/src/components/grid/lib/events.js +29 -0
- package/src/components/grid/lib/renderers.js +29 -0
- package/src/components/grid/lib/utils.js +26 -0
- package/src/components/grid/lib/websocket.js +63 -0
- package/src/components/grid/overlays/KeyboardManager.svelte +223 -0
- package/src/components/grid/overlays/MenuOverlay.svelte +96 -0
- package/src/components/grid/overlays/ReorderOverlay.svelte +63 -0
- package/src/components/grid/overlays/ResizeOverlay.svelte +70 -0
- package/src/components/grid/overlays/ScrollOverlay.svelte +121 -0
- package/src/components/grid/stores/bounds.js +16 -0
- package/src/components/grid/stores/clipboard.js +34 -0
- package/src/components/grid/stores/columns.js +206 -0
- package/src/components/grid/stores/index.js +48 -0
- package/src/components/grid/stores/menu.js +49 -0
- package/src/components/grid/stores/pagination.js +24 -0
- package/src/components/grid/stores/reorder.js +155 -0
- package/src/components/grid/stores/resize.js +124 -0
- package/src/components/grid/stores/rows.js +467 -0
- package/src/components/grid/stores/scroll.js +201 -0
- package/src/components/grid/stores/ui.js +159 -0
- package/src/components/grid/stores/users.js +115 -0
- package/src/components/grid/stores/validation.js +45 -0
- package/src/components/grid/stores/viewport.js +145 -0
- package/src/components/index.js +1 -0
- package/src/fetch/DataFetch.js +27 -21
- package/src/fetch/QueryFetch.js +1 -1
- package/src/themes/midnight.css +3 -0
- package/src/themes/nord.css +3 -0
- package/src/utils/utils.js +20 -0
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { setContext } from "svelte"
|
|
3
|
+
import { writable } from "svelte/store"
|
|
4
|
+
import { fade } from "svelte/transition"
|
|
5
|
+
import { clickOutside, ProgressCircle } from "@budibase/bbui"
|
|
6
|
+
import { createEventManagers } from "../lib/events"
|
|
7
|
+
import { createAPIClient } from "../../../api"
|
|
8
|
+
import { attachStores } from "../stores"
|
|
9
|
+
import DeleteButton from "../controls/DeleteButton.svelte"
|
|
10
|
+
import BetaButton from "../controls/BetaButton.svelte"
|
|
11
|
+
import GridBody from "./GridBody.svelte"
|
|
12
|
+
import ResizeOverlay from "../overlays/ResizeOverlay.svelte"
|
|
13
|
+
import ReorderOverlay from "../overlays/ReorderOverlay.svelte"
|
|
14
|
+
import HeaderRow from "./HeaderRow.svelte"
|
|
15
|
+
import ScrollOverlay from "../overlays/ScrollOverlay.svelte"
|
|
16
|
+
import MenuOverlay from "../overlays/MenuOverlay.svelte"
|
|
17
|
+
import StickyColumn from "./StickyColumn.svelte"
|
|
18
|
+
import UserAvatars from "./UserAvatars.svelte"
|
|
19
|
+
import KeyboardManager from "../overlays/KeyboardManager.svelte"
|
|
20
|
+
import SortButton from "../controls/SortButton.svelte"
|
|
21
|
+
import AddColumnButton from "../controls/AddColumnButton.svelte"
|
|
22
|
+
import HideColumnsButton from "../controls/HideColumnsButton.svelte"
|
|
23
|
+
import AddRowButton from "../controls/AddRowButton.svelte"
|
|
24
|
+
import RowHeightButton from "../controls/RowHeightButton.svelte"
|
|
25
|
+
import ColumnWidthButton from "../controls/ColumnWidthButton.svelte"
|
|
26
|
+
import NewRow from "./NewRow.svelte"
|
|
27
|
+
import {
|
|
28
|
+
MaxCellRenderHeight,
|
|
29
|
+
MaxCellRenderWidthOverflow,
|
|
30
|
+
GutterWidth,
|
|
31
|
+
DefaultRowHeight,
|
|
32
|
+
} from "../lib/constants"
|
|
33
|
+
|
|
34
|
+
export let API = null
|
|
35
|
+
export let tableId = null
|
|
36
|
+
export let schemaOverrides = null
|
|
37
|
+
export let allowAddRows = true
|
|
38
|
+
export let allowAddColumns = true
|
|
39
|
+
export let allowEditColumns = true
|
|
40
|
+
export let allowExpandRows = true
|
|
41
|
+
export let allowEditRows = true
|
|
42
|
+
export let allowDeleteRows = true
|
|
43
|
+
|
|
44
|
+
// Unique identifier for DOM nodes inside this instance
|
|
45
|
+
const rand = Math.random()
|
|
46
|
+
|
|
47
|
+
// State stores
|
|
48
|
+
const tableIdStore = writable(tableId)
|
|
49
|
+
const schemaOverridesStore = writable(schemaOverrides)
|
|
50
|
+
const config = writable({
|
|
51
|
+
allowAddRows,
|
|
52
|
+
allowAddColumns,
|
|
53
|
+
allowEditColumns,
|
|
54
|
+
allowExpandRows,
|
|
55
|
+
allowEditRows,
|
|
56
|
+
allowDeleteRows,
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
// Build up context
|
|
60
|
+
let context = {
|
|
61
|
+
API: API || createAPIClient(),
|
|
62
|
+
rand,
|
|
63
|
+
config,
|
|
64
|
+
tableId: tableIdStore,
|
|
65
|
+
schemaOverrides: schemaOverridesStore,
|
|
66
|
+
}
|
|
67
|
+
context = { ...context, ...createEventManagers() }
|
|
68
|
+
context = attachStores(context)
|
|
69
|
+
|
|
70
|
+
// Reference some stores for local use
|
|
71
|
+
const {
|
|
72
|
+
isResizing,
|
|
73
|
+
isReordering,
|
|
74
|
+
ui,
|
|
75
|
+
loaded,
|
|
76
|
+
loading,
|
|
77
|
+
rowHeight,
|
|
78
|
+
contentLines,
|
|
79
|
+
} = context
|
|
80
|
+
|
|
81
|
+
// Keep stores up to date
|
|
82
|
+
$: tableIdStore.set(tableId)
|
|
83
|
+
$: schemaOverridesStore.set(schemaOverrides)
|
|
84
|
+
$: config.set({
|
|
85
|
+
allowAddRows,
|
|
86
|
+
allowAddColumns,
|
|
87
|
+
allowEditColumns,
|
|
88
|
+
allowExpandRows,
|
|
89
|
+
allowEditRows,
|
|
90
|
+
allowDeleteRows,
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
// Set context for children to consume
|
|
94
|
+
setContext("grid", context)
|
|
95
|
+
|
|
96
|
+
// Expose ability to retrieve context externally for external control
|
|
97
|
+
export const getContext = () => context
|
|
98
|
+
|
|
99
|
+
// Initialise websocket for multi-user
|
|
100
|
+
// onMount(() => createWebsocket(context))
|
|
101
|
+
</script>
|
|
102
|
+
|
|
103
|
+
<div
|
|
104
|
+
class="grid"
|
|
105
|
+
id="grid-{rand}"
|
|
106
|
+
class:is-resizing={$isResizing}
|
|
107
|
+
class:is-reordering={$isReordering}
|
|
108
|
+
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};"
|
|
109
|
+
>
|
|
110
|
+
<div class="controls">
|
|
111
|
+
<div class="controls-left">
|
|
112
|
+
<AddRowButton />
|
|
113
|
+
<AddColumnButton />
|
|
114
|
+
<slot name="controls" />
|
|
115
|
+
<ColumnWidthButton />
|
|
116
|
+
<RowHeightButton />
|
|
117
|
+
<HideColumnsButton />
|
|
118
|
+
<SortButton />
|
|
119
|
+
</div>
|
|
120
|
+
<div class="controls-right">
|
|
121
|
+
<DeleteButton />
|
|
122
|
+
<UserAvatars />
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
125
|
+
{#if $loaded}
|
|
126
|
+
<div class="grid-data-outer" use:clickOutside={ui.actions.blur}>
|
|
127
|
+
<div class="grid-data-inner">
|
|
128
|
+
<StickyColumn />
|
|
129
|
+
<div class="grid-data-content">
|
|
130
|
+
<HeaderRow />
|
|
131
|
+
<GridBody />
|
|
132
|
+
</div>
|
|
133
|
+
<BetaButton />
|
|
134
|
+
<NewRow />
|
|
135
|
+
<div class="overlays">
|
|
136
|
+
<ResizeOverlay />
|
|
137
|
+
<ReorderOverlay />
|
|
138
|
+
<ScrollOverlay />
|
|
139
|
+
<MenuOverlay />
|
|
140
|
+
</div>
|
|
141
|
+
</div>
|
|
142
|
+
</div>
|
|
143
|
+
{/if}
|
|
144
|
+
{#if $loading}
|
|
145
|
+
<div in:fade|local={{ duration: 130 }} class="grid-loading">
|
|
146
|
+
<ProgressCircle />
|
|
147
|
+
</div>
|
|
148
|
+
{/if}
|
|
149
|
+
<KeyboardManager />
|
|
150
|
+
</div>
|
|
151
|
+
|
|
152
|
+
<style>
|
|
153
|
+
.grid {
|
|
154
|
+
flex: 1 1 auto;
|
|
155
|
+
display: flex;
|
|
156
|
+
flex-direction: column;
|
|
157
|
+
justify-content: flex-start;
|
|
158
|
+
align-items: stretch;
|
|
159
|
+
position: relative;
|
|
160
|
+
overflow: hidden;
|
|
161
|
+
background: var(--cell-background);
|
|
162
|
+
|
|
163
|
+
/* Variables */
|
|
164
|
+
--cell-background: var(--spectrum-global-color-gray-50);
|
|
165
|
+
--cell-background-hover: var(--spectrum-global-color-gray-100);
|
|
166
|
+
--cell-padding: 8px;
|
|
167
|
+
--cell-spacing: 4px;
|
|
168
|
+
--cell-border: 1px solid var(--spectrum-global-color-gray-200);
|
|
169
|
+
--cell-font-size: 14px;
|
|
170
|
+
--controls-height: 50px;
|
|
171
|
+
}
|
|
172
|
+
.grid,
|
|
173
|
+
.grid :global(*) {
|
|
174
|
+
box-sizing: border-box;
|
|
175
|
+
}
|
|
176
|
+
.grid.is-resizing :global(*) {
|
|
177
|
+
cursor: col-resize !important;
|
|
178
|
+
}
|
|
179
|
+
.grid.is-reordering :global(*) {
|
|
180
|
+
cursor: grabbing !important;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.grid-data-outer,
|
|
184
|
+
.grid-data-inner {
|
|
185
|
+
flex: 1 1 auto;
|
|
186
|
+
display: flex;
|
|
187
|
+
justify-items: flex-start;
|
|
188
|
+
align-items: stretch;
|
|
189
|
+
overflow: hidden;
|
|
190
|
+
}
|
|
191
|
+
.grid-data-outer {
|
|
192
|
+
height: 0;
|
|
193
|
+
flex-direction: column;
|
|
194
|
+
}
|
|
195
|
+
.grid-data-inner {
|
|
196
|
+
flex-direction: row;
|
|
197
|
+
position: relative;
|
|
198
|
+
}
|
|
199
|
+
.grid-data-content {
|
|
200
|
+
flex: 1 1 auto;
|
|
201
|
+
overflow: hidden;
|
|
202
|
+
display: flex;
|
|
203
|
+
flex-direction: column;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/* Controls */
|
|
207
|
+
.controls {
|
|
208
|
+
height: var(--controls-height);
|
|
209
|
+
display: flex;
|
|
210
|
+
flex-direction: row;
|
|
211
|
+
justify-content: space-between;
|
|
212
|
+
align-items: center;
|
|
213
|
+
border-bottom: 2px solid var(--spectrum-global-color-gray-200);
|
|
214
|
+
padding: var(--cell-padding);
|
|
215
|
+
gap: var(--cell-spacing);
|
|
216
|
+
background: var(--background);
|
|
217
|
+
}
|
|
218
|
+
.controls-left,
|
|
219
|
+
.controls-right {
|
|
220
|
+
display: flex;
|
|
221
|
+
flex-direction: row;
|
|
222
|
+
justify-content: flex-start;
|
|
223
|
+
align-items: center;
|
|
224
|
+
gap: var(--cell-spacing);
|
|
225
|
+
}
|
|
226
|
+
.controls-right {
|
|
227
|
+
gap: 12px;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/* Overlays */
|
|
231
|
+
.overlays {
|
|
232
|
+
z-index: 10;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/* Loading */
|
|
236
|
+
.grid-loading {
|
|
237
|
+
position: absolute;
|
|
238
|
+
width: 100%;
|
|
239
|
+
height: 100%;
|
|
240
|
+
display: grid;
|
|
241
|
+
place-items: center;
|
|
242
|
+
z-index: 10;
|
|
243
|
+
}
|
|
244
|
+
.grid-loading:before {
|
|
245
|
+
content: "";
|
|
246
|
+
position: absolute;
|
|
247
|
+
top: 0;
|
|
248
|
+
left: 0;
|
|
249
|
+
width: 100%;
|
|
250
|
+
height: 100%;
|
|
251
|
+
background: var(--background);
|
|
252
|
+
opacity: 0.6;
|
|
253
|
+
}
|
|
254
|
+
</style>
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { getContext, onMount } from "svelte"
|
|
3
|
+
import GridScrollWrapper from "./GridScrollWrapper.svelte"
|
|
4
|
+
import GridRow from "./GridRow.svelte"
|
|
5
|
+
import { BlankRowID } from "../lib/constants"
|
|
6
|
+
|
|
7
|
+
const {
|
|
8
|
+
bounds,
|
|
9
|
+
renderedRows,
|
|
10
|
+
renderedColumns,
|
|
11
|
+
rowVerticalInversionIndex,
|
|
12
|
+
config,
|
|
13
|
+
hoveredRowId,
|
|
14
|
+
dispatch,
|
|
15
|
+
} = getContext("grid")
|
|
16
|
+
|
|
17
|
+
let body
|
|
18
|
+
|
|
19
|
+
$: renderColumnsWidth = $renderedColumns.reduce(
|
|
20
|
+
(total, col) => (total += col.width),
|
|
21
|
+
0
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
onMount(() => {
|
|
25
|
+
// Observe and record the height of the body
|
|
26
|
+
const observer = new ResizeObserver(() => {
|
|
27
|
+
bounds.set(body.getBoundingClientRect())
|
|
28
|
+
})
|
|
29
|
+
observer.observe(body)
|
|
30
|
+
return () => {
|
|
31
|
+
observer.disconnect()
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<div bind:this={body} class="grid-body">
|
|
37
|
+
<GridScrollWrapper scrollHorizontally scrollVertically wheelInteractive>
|
|
38
|
+
{#each $renderedRows as row, idx}
|
|
39
|
+
<GridRow {row} {idx} invertY={idx >= $rowVerticalInversionIndex} />
|
|
40
|
+
{/each}
|
|
41
|
+
{#if $config.allowAddRows && $renderedColumns.length}
|
|
42
|
+
<div
|
|
43
|
+
class="blank"
|
|
44
|
+
class:highlighted={$hoveredRowId === BlankRowID}
|
|
45
|
+
style="width:{renderColumnsWidth}px"
|
|
46
|
+
on:mouseenter={() => ($hoveredRowId = BlankRowID)}
|
|
47
|
+
on:mouseleave={() => ($hoveredRowId = null)}
|
|
48
|
+
on:click={() => dispatch("add-row-inline")}
|
|
49
|
+
/>
|
|
50
|
+
{/if}
|
|
51
|
+
</GridScrollWrapper>
|
|
52
|
+
</div>
|
|
53
|
+
|
|
54
|
+
<style>
|
|
55
|
+
.grid-body {
|
|
56
|
+
display: block;
|
|
57
|
+
position: relative;
|
|
58
|
+
cursor: default;
|
|
59
|
+
overflow: hidden;
|
|
60
|
+
flex: 1 1 auto;
|
|
61
|
+
}
|
|
62
|
+
.blank {
|
|
63
|
+
height: var(--row-height);
|
|
64
|
+
background: var(--cell-background);
|
|
65
|
+
border-bottom: var(--cell-border);
|
|
66
|
+
border-right: var(--cell-border);
|
|
67
|
+
position: absolute;
|
|
68
|
+
}
|
|
69
|
+
.blank.highlighted {
|
|
70
|
+
background: var(--cell-background-hover);
|
|
71
|
+
cursor: pointer;
|
|
72
|
+
}
|
|
73
|
+
</style>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { getContext } from "svelte"
|
|
3
|
+
import DataCell from "../cells/DataCell.svelte"
|
|
4
|
+
|
|
5
|
+
export let row
|
|
6
|
+
export let idx
|
|
7
|
+
export let invertY = false
|
|
8
|
+
|
|
9
|
+
const {
|
|
10
|
+
focusedCellId,
|
|
11
|
+
reorder,
|
|
12
|
+
selectedRows,
|
|
13
|
+
renderedColumns,
|
|
14
|
+
hoveredRowId,
|
|
15
|
+
selectedCellMap,
|
|
16
|
+
focusedRow,
|
|
17
|
+
columnHorizontalInversionIndex,
|
|
18
|
+
} = getContext("grid")
|
|
19
|
+
|
|
20
|
+
$: rowSelected = !!$selectedRows[row._id]
|
|
21
|
+
$: rowHovered = $hoveredRowId === row._id
|
|
22
|
+
$: rowFocused = $focusedRow?._id === row._id
|
|
23
|
+
$: reorderSource = $reorder.sourceColumn
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<div
|
|
27
|
+
class="row"
|
|
28
|
+
on:focus
|
|
29
|
+
on:mouseenter={() => ($hoveredRowId = row._id)}
|
|
30
|
+
on:mouseleave={() => ($hoveredRowId = null)}
|
|
31
|
+
>
|
|
32
|
+
{#each $renderedColumns as column, columnIdx (column.name)}
|
|
33
|
+
{@const cellId = `${row._id}-${column.name}`}
|
|
34
|
+
<DataCell
|
|
35
|
+
{cellId}
|
|
36
|
+
{column}
|
|
37
|
+
{row}
|
|
38
|
+
{invertY}
|
|
39
|
+
{rowFocused}
|
|
40
|
+
invertX={columnIdx >= $columnHorizontalInversionIndex}
|
|
41
|
+
highlighted={rowHovered || rowFocused || reorderSource === column.name}
|
|
42
|
+
selected={rowSelected}
|
|
43
|
+
rowIdx={idx}
|
|
44
|
+
focused={$focusedCellId === cellId}
|
|
45
|
+
selectedUser={$selectedCellMap[cellId]}
|
|
46
|
+
width={column.width}
|
|
47
|
+
/>
|
|
48
|
+
{/each}
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
<style>
|
|
52
|
+
.row {
|
|
53
|
+
width: 0;
|
|
54
|
+
display: flex;
|
|
55
|
+
height: var(--row-height);
|
|
56
|
+
}
|
|
57
|
+
</style>
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { getContext } from "svelte"
|
|
3
|
+
import { domDebounce } from "../../../utils/utils"
|
|
4
|
+
|
|
5
|
+
const {
|
|
6
|
+
rowHeight,
|
|
7
|
+
scroll,
|
|
8
|
+
focusedCellId,
|
|
9
|
+
renderedRows,
|
|
10
|
+
maxScrollTop,
|
|
11
|
+
maxScrollLeft,
|
|
12
|
+
bounds,
|
|
13
|
+
hoveredRowId,
|
|
14
|
+
hiddenColumnsWidth,
|
|
15
|
+
} = getContext("grid")
|
|
16
|
+
|
|
17
|
+
export let scrollVertically = false
|
|
18
|
+
export let scrollHorizontally = false
|
|
19
|
+
export let wheelInteractive = false
|
|
20
|
+
|
|
21
|
+
$: style = generateStyle($scroll, $rowHeight, $hiddenColumnsWidth)
|
|
22
|
+
|
|
23
|
+
const generateStyle = (scroll, rowHeight, hiddenWidths) => {
|
|
24
|
+
const offsetX = scrollHorizontally ? -1 * scroll.left + hiddenWidths : 0
|
|
25
|
+
const offsetY = scrollVertically ? -1 * (scroll.top % rowHeight) : 0
|
|
26
|
+
return `transform: translate3d(${offsetX}px, ${offsetY}px, 0);`
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Handles a wheel even and updates the scroll offsets
|
|
30
|
+
const handleWheel = e => {
|
|
31
|
+
e.preventDefault()
|
|
32
|
+
debouncedHandleWheel(e.deltaX, e.deltaY, e.clientY)
|
|
33
|
+
}
|
|
34
|
+
const debouncedHandleWheel = domDebounce((deltaX, deltaY, clientY) => {
|
|
35
|
+
const { top, left } = $scroll
|
|
36
|
+
|
|
37
|
+
// Calculate new scroll top
|
|
38
|
+
let newScrollTop = top + deltaY
|
|
39
|
+
newScrollTop = Math.max(0, Math.min(newScrollTop, $maxScrollTop))
|
|
40
|
+
|
|
41
|
+
// Calculate new scroll left
|
|
42
|
+
let newScrollLeft = left + deltaX
|
|
43
|
+
newScrollLeft = Math.max(0, Math.min(newScrollLeft, $maxScrollLeft))
|
|
44
|
+
|
|
45
|
+
// Update state
|
|
46
|
+
scroll.set({
|
|
47
|
+
left: scrollHorizontally ? newScrollLeft : left,
|
|
48
|
+
top: scrollVertically ? newScrollTop : top,
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
// Hover row under cursor
|
|
52
|
+
const y = clientY - $bounds.top + (newScrollTop % $rowHeight)
|
|
53
|
+
const hoveredRow = $renderedRows[Math.floor(y / $rowHeight)]
|
|
54
|
+
hoveredRowId.set(hoveredRow?._id)
|
|
55
|
+
})
|
|
56
|
+
</script>
|
|
57
|
+
|
|
58
|
+
<div
|
|
59
|
+
class="outer"
|
|
60
|
+
on:wheel={wheelInteractive ? handleWheel : null}
|
|
61
|
+
on:click|self={() => ($focusedCellId = null)}
|
|
62
|
+
>
|
|
63
|
+
<div {style} class="inner">
|
|
64
|
+
<slot />
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
<style>
|
|
69
|
+
.outer {
|
|
70
|
+
min-width: 100%;
|
|
71
|
+
min-height: 100%;
|
|
72
|
+
height: 100%;
|
|
73
|
+
width: 100%;
|
|
74
|
+
max-height: 100%;
|
|
75
|
+
max-width: 100%;
|
|
76
|
+
overflow: hidden;
|
|
77
|
+
}
|
|
78
|
+
.inner {
|
|
79
|
+
position: absolute;
|
|
80
|
+
}
|
|
81
|
+
</style>
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { getContext } from "svelte"
|
|
3
|
+
import GridScrollWrapper from "./GridScrollWrapper.svelte"
|
|
4
|
+
import HeaderCell from "../cells/HeaderCell.svelte"
|
|
5
|
+
import { Icon } from "@budibase/bbui"
|
|
6
|
+
|
|
7
|
+
const { renderedColumns, dispatch, scroll, hiddenColumnsWidth, width } =
|
|
8
|
+
getContext("grid")
|
|
9
|
+
|
|
10
|
+
$: columnsWidth = $renderedColumns.reduce(
|
|
11
|
+
(total, col) => (total += col.width),
|
|
12
|
+
0
|
|
13
|
+
)
|
|
14
|
+
$: end = $hiddenColumnsWidth + columnsWidth - 1 - $scroll.left
|
|
15
|
+
$: left = Math.min($width - 40, end)
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<div class="header">
|
|
19
|
+
<GridScrollWrapper scrollHorizontally>
|
|
20
|
+
<div class="row">
|
|
21
|
+
{#each $renderedColumns as column, idx}
|
|
22
|
+
<HeaderCell {column} {idx} />
|
|
23
|
+
{/each}
|
|
24
|
+
</div>
|
|
25
|
+
</GridScrollWrapper>
|
|
26
|
+
<div
|
|
27
|
+
class="add"
|
|
28
|
+
style="left:{left}px"
|
|
29
|
+
on:click={() => dispatch("add-column")}
|
|
30
|
+
>
|
|
31
|
+
<Icon name="Add" />
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
<style>
|
|
36
|
+
.header {
|
|
37
|
+
background: var(--background);
|
|
38
|
+
border-bottom: var(--cell-border);
|
|
39
|
+
position: relative;
|
|
40
|
+
height: var(--default-row-height);
|
|
41
|
+
z-index: 1;
|
|
42
|
+
}
|
|
43
|
+
.row {
|
|
44
|
+
display: flex;
|
|
45
|
+
}
|
|
46
|
+
.add {
|
|
47
|
+
height: var(--default-row-height);
|
|
48
|
+
display: grid;
|
|
49
|
+
place-items: center;
|
|
50
|
+
width: 40px;
|
|
51
|
+
position: absolute;
|
|
52
|
+
top: 0;
|
|
53
|
+
border-left: var(--cell-border);
|
|
54
|
+
border-right: var(--cell-border);
|
|
55
|
+
border-bottom: var(--cell-border);
|
|
56
|
+
background: var(--spectrum-global-color-gray-100);
|
|
57
|
+
}
|
|
58
|
+
.add:hover {
|
|
59
|
+
background: var(--spectrum-global-color-gray-200);
|
|
60
|
+
cursor: pointer;
|
|
61
|
+
}
|
|
62
|
+
</style>
|