@budibase/bbui 3.3.1 → 3.3.3
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/dist/bbui.mjs +781 -709
- package/package.json +2 -2
- package/src/Actions/{position_dropdown.js → position_dropdown.ts} +81 -54
- package/src/Form/Core/Checkbox.svelte +8 -7
- package/src/Form/Core/CheckboxGroup.svelte +13 -8
- package/src/Form/Core/Combobox.svelte +22 -11
- package/src/Popover/Popover.svelte +21 -16
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@budibase/bbui",
|
|
3
3
|
"description": "A UI solution used in the different Budibase projects.",
|
|
4
|
-
"version": "3.3.
|
|
4
|
+
"version": "3.3.3",
|
|
5
5
|
"license": "MPL-2.0",
|
|
6
6
|
"svelte": "src/index.ts",
|
|
7
7
|
"module": "dist/bbui.mjs",
|
|
@@ -99,5 +99,5 @@
|
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
101
|
},
|
|
102
|
-
"gitHead": "
|
|
102
|
+
"gitHead": "d74dae4e31f56f7a43589fd8d6c8070ed1156cd3"
|
|
103
103
|
}
|
|
@@ -8,27 +8,52 @@
|
|
|
8
8
|
|
|
9
9
|
// Strategies are defined as [Popover]To[Anchor].
|
|
10
10
|
// They can apply for both horizontal and vertical alignment.
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
11
|
+
type Strategy =
|
|
12
|
+
| "StartToStart"
|
|
13
|
+
| "EndToEnd"
|
|
14
|
+
| "StartToEnd"
|
|
15
|
+
| "EndToStart"
|
|
16
|
+
| "MidPoint"
|
|
17
|
+
| "ScreenEdge"
|
|
18
|
+
|
|
19
|
+
export interface Styles {
|
|
20
|
+
maxHeight?: number
|
|
21
|
+
minWidth?: number
|
|
22
|
+
maxWidth?: number
|
|
23
|
+
offset?: number
|
|
24
|
+
left: number
|
|
25
|
+
top: number
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export type UpdateHandler = (
|
|
29
|
+
anchorBounds: DOMRect,
|
|
30
|
+
elementBounds: DOMRect,
|
|
31
|
+
styles: Styles
|
|
32
|
+
) => Styles
|
|
33
|
+
|
|
34
|
+
interface Opts {
|
|
35
|
+
anchor?: HTMLElement
|
|
36
|
+
align: string
|
|
37
|
+
maxHeight?: number
|
|
38
|
+
maxWidth?: number
|
|
39
|
+
minWidth?: number
|
|
40
|
+
useAnchorWidth: boolean
|
|
41
|
+
offset: number
|
|
42
|
+
customUpdate?: UpdateHandler
|
|
43
|
+
resizable: boolean
|
|
44
|
+
wrap: boolean
|
|
18
45
|
}
|
|
19
46
|
|
|
20
|
-
export default function positionDropdown(element, opts) {
|
|
21
|
-
let resizeObserver
|
|
47
|
+
export default function positionDropdown(element: HTMLElement, opts: Opts) {
|
|
48
|
+
let resizeObserver: ResizeObserver
|
|
22
49
|
let latestOpts = opts
|
|
23
50
|
|
|
24
51
|
// We need a static reference to this function so that we can properly
|
|
25
52
|
// clean up the scroll listener.
|
|
26
|
-
const scrollUpdate = () =>
|
|
27
|
-
updatePosition(latestOpts)
|
|
28
|
-
}
|
|
53
|
+
const scrollUpdate = () => updatePosition(latestOpts)
|
|
29
54
|
|
|
30
55
|
// Updates the position of the dropdown
|
|
31
|
-
const updatePosition = opts => {
|
|
56
|
+
const updatePosition = (opts: Opts) => {
|
|
32
57
|
const {
|
|
33
58
|
anchor,
|
|
34
59
|
align,
|
|
@@ -51,12 +76,12 @@ export default function positionDropdown(element, opts) {
|
|
|
51
76
|
const winWidth = window.innerWidth
|
|
52
77
|
const winHeight = window.innerHeight
|
|
53
78
|
const screenOffset = 8
|
|
54
|
-
let styles = {
|
|
79
|
+
let styles: Styles = {
|
|
55
80
|
maxHeight,
|
|
56
81
|
minWidth: useAnchorWidth ? anchorBounds.width : minWidth,
|
|
57
82
|
maxWidth: useAnchorWidth ? anchorBounds.width : maxWidth,
|
|
58
|
-
left:
|
|
59
|
-
top:
|
|
83
|
+
left: 0,
|
|
84
|
+
top: 0,
|
|
60
85
|
}
|
|
61
86
|
|
|
62
87
|
// Ignore all our logic for custom logic
|
|
@@ -81,67 +106,67 @@ export default function positionDropdown(element, opts) {
|
|
|
81
106
|
}
|
|
82
107
|
|
|
83
108
|
// Applies a dynamic max height constraint if appropriate
|
|
84
|
-
const applyMaxHeight = height => {
|
|
109
|
+
const applyMaxHeight = (height: number) => {
|
|
85
110
|
if (!styles.maxHeight && resizable) {
|
|
86
111
|
styles.maxHeight = height
|
|
87
112
|
}
|
|
88
113
|
}
|
|
89
114
|
|
|
90
115
|
// Applies the X strategy to our styles
|
|
91
|
-
const applyXStrategy = strategy => {
|
|
116
|
+
const applyXStrategy = (strategy: Strategy) => {
|
|
92
117
|
switch (strategy) {
|
|
93
|
-
case
|
|
118
|
+
case "StartToStart":
|
|
94
119
|
default:
|
|
95
120
|
styles.left = anchorBounds.left
|
|
96
121
|
break
|
|
97
|
-
case
|
|
122
|
+
case "EndToEnd":
|
|
98
123
|
styles.left = anchorBounds.right - elementBounds.width
|
|
99
124
|
break
|
|
100
|
-
case
|
|
125
|
+
case "StartToEnd":
|
|
101
126
|
styles.left = anchorBounds.right + offset
|
|
102
127
|
break
|
|
103
|
-
case
|
|
128
|
+
case "EndToStart":
|
|
104
129
|
styles.left = anchorBounds.left - elementBounds.width - offset
|
|
105
130
|
break
|
|
106
|
-
case
|
|
131
|
+
case "MidPoint":
|
|
107
132
|
styles.left =
|
|
108
133
|
anchorBounds.left +
|
|
109
134
|
anchorBounds.width / 2 -
|
|
110
135
|
elementBounds.width / 2
|
|
111
136
|
break
|
|
112
|
-
case
|
|
137
|
+
case "ScreenEdge":
|
|
113
138
|
styles.left = winWidth - elementBounds.width - screenOffset
|
|
114
139
|
break
|
|
115
140
|
}
|
|
116
141
|
}
|
|
117
142
|
|
|
118
143
|
// Applies the Y strategy to our styles
|
|
119
|
-
const applyYStrategy = strategy => {
|
|
144
|
+
const applyYStrategy = (strategy: Strategy) => {
|
|
120
145
|
switch (strategy) {
|
|
121
|
-
case
|
|
146
|
+
case "StartToStart":
|
|
122
147
|
styles.top = anchorBounds.top
|
|
123
148
|
applyMaxHeight(winHeight - anchorBounds.top - screenOffset)
|
|
124
149
|
break
|
|
125
|
-
case
|
|
150
|
+
case "EndToEnd":
|
|
126
151
|
styles.top = anchorBounds.bottom - elementBounds.height
|
|
127
152
|
applyMaxHeight(anchorBounds.bottom - screenOffset)
|
|
128
153
|
break
|
|
129
|
-
case
|
|
154
|
+
case "StartToEnd":
|
|
130
155
|
default:
|
|
131
156
|
styles.top = anchorBounds.bottom + offset
|
|
132
157
|
applyMaxHeight(winHeight - anchorBounds.bottom - screenOffset)
|
|
133
158
|
break
|
|
134
|
-
case
|
|
159
|
+
case "EndToStart":
|
|
135
160
|
styles.top = anchorBounds.top - elementBounds.height - offset
|
|
136
161
|
applyMaxHeight(anchorBounds.top - screenOffset)
|
|
137
162
|
break
|
|
138
|
-
case
|
|
163
|
+
case "MidPoint":
|
|
139
164
|
styles.top =
|
|
140
165
|
anchorBounds.top +
|
|
141
166
|
anchorBounds.height / 2 -
|
|
142
167
|
elementBounds.height / 2
|
|
143
168
|
break
|
|
144
|
-
case
|
|
169
|
+
case "ScreenEdge":
|
|
145
170
|
styles.top = winHeight - elementBounds.height - screenOffset
|
|
146
171
|
applyMaxHeight(winHeight - 2 * screenOffset)
|
|
147
172
|
break
|
|
@@ -150,81 +175,83 @@ export default function positionDropdown(element, opts) {
|
|
|
150
175
|
|
|
151
176
|
// Determine X strategy
|
|
152
177
|
if (align === "right") {
|
|
153
|
-
applyXStrategy(
|
|
178
|
+
applyXStrategy("EndToEnd")
|
|
154
179
|
} else if (align === "right-outside" || align === "right-context-menu") {
|
|
155
|
-
applyXStrategy(
|
|
180
|
+
applyXStrategy("StartToEnd")
|
|
156
181
|
} else if (align === "left-outside" || align === "left-context-menu") {
|
|
157
|
-
applyXStrategy(
|
|
182
|
+
applyXStrategy("EndToStart")
|
|
158
183
|
} else if (align === "center") {
|
|
159
|
-
applyXStrategy(
|
|
184
|
+
applyXStrategy("MidPoint")
|
|
160
185
|
} else {
|
|
161
|
-
applyXStrategy(
|
|
186
|
+
applyXStrategy("StartToStart")
|
|
162
187
|
}
|
|
163
188
|
|
|
164
189
|
// Determine Y strategy
|
|
165
190
|
if (align === "right-outside" || align === "left-outside") {
|
|
166
|
-
applyYStrategy(
|
|
191
|
+
applyYStrategy("MidPoint")
|
|
167
192
|
} else if (
|
|
168
193
|
align === "right-context-menu" ||
|
|
169
194
|
align === "left-context-menu"
|
|
170
195
|
) {
|
|
171
|
-
applyYStrategy(
|
|
172
|
-
styles.top
|
|
196
|
+
applyYStrategy("StartToStart")
|
|
197
|
+
if (styles.top) {
|
|
198
|
+
styles.top -= 5 // Manual adjustment for action menu padding
|
|
199
|
+
}
|
|
173
200
|
} else {
|
|
174
|
-
applyYStrategy(
|
|
201
|
+
applyYStrategy("StartToEnd")
|
|
175
202
|
}
|
|
176
203
|
|
|
177
204
|
// Handle screen overflow
|
|
178
205
|
if (doesXOverflow()) {
|
|
179
206
|
// Swap left to right
|
|
180
207
|
if (align === "left") {
|
|
181
|
-
applyXStrategy(
|
|
208
|
+
applyXStrategy("EndToEnd")
|
|
182
209
|
}
|
|
183
210
|
// Swap right-outside to left-outside
|
|
184
211
|
else if (align === "right-outside") {
|
|
185
|
-
applyXStrategy(
|
|
212
|
+
applyXStrategy("EndToStart")
|
|
186
213
|
}
|
|
187
214
|
}
|
|
188
215
|
if (doesYOverflow()) {
|
|
189
216
|
// If wrapping, lock to the bottom of the screen and also reposition to
|
|
190
217
|
// the side to not block the anchor
|
|
191
218
|
if (wrap) {
|
|
192
|
-
applyYStrategy(
|
|
219
|
+
applyYStrategy("MidPoint")
|
|
193
220
|
if (doesYOverflow()) {
|
|
194
|
-
applyYStrategy(
|
|
221
|
+
applyYStrategy("ScreenEdge")
|
|
195
222
|
}
|
|
196
|
-
applyXStrategy(
|
|
223
|
+
applyXStrategy("StartToEnd")
|
|
197
224
|
if (doesXOverflow()) {
|
|
198
|
-
applyXStrategy(
|
|
225
|
+
applyXStrategy("EndToStart")
|
|
199
226
|
}
|
|
200
227
|
}
|
|
201
228
|
// Othewise invert as normal
|
|
202
229
|
else {
|
|
203
230
|
// If using an outside strategy then lock to the bottom of the screen
|
|
204
231
|
if (align === "left-outside" || align === "right-outside") {
|
|
205
|
-
applyYStrategy(
|
|
232
|
+
applyYStrategy("ScreenEdge")
|
|
206
233
|
}
|
|
207
234
|
// Otherwise flip above
|
|
208
235
|
else {
|
|
209
|
-
applyYStrategy(
|
|
236
|
+
applyYStrategy("EndToStart")
|
|
210
237
|
}
|
|
211
238
|
}
|
|
212
239
|
}
|
|
213
240
|
}
|
|
214
241
|
|
|
215
|
-
|
|
216
|
-
|
|
242
|
+
for (const [key, value] of Object.entries(styles)) {
|
|
243
|
+
const name = key as keyof Styles
|
|
217
244
|
if (value != null) {
|
|
218
|
-
element.style[
|
|
245
|
+
element.style[name] = `${value}px`
|
|
219
246
|
} else {
|
|
220
|
-
element.style[
|
|
247
|
+
element.style[name] = ""
|
|
221
248
|
}
|
|
222
|
-
}
|
|
249
|
+
}
|
|
223
250
|
}
|
|
224
251
|
|
|
225
252
|
// The actual svelte action callback which creates observers on the relevant
|
|
226
253
|
// DOM elements
|
|
227
|
-
const update = newOpts => {
|
|
254
|
+
const update = (newOpts: Opts) => {
|
|
228
255
|
latestOpts = newOpts
|
|
229
256
|
|
|
230
257
|
// Cleanup old state
|
|
@@ -1,22 +1,23 @@
|
|
|
1
|
-
<script>
|
|
1
|
+
<script lang="ts">
|
|
2
2
|
import "@spectrum-css/checkbox/dist/index-vars.css"
|
|
3
3
|
import "@spectrum-css/fieldgroup/dist/index-vars.css"
|
|
4
4
|
import { createEventDispatcher } from "svelte"
|
|
5
|
+
import type { ChangeEventHandler } from "svelte/elements"
|
|
5
6
|
|
|
6
7
|
export let value = false
|
|
7
|
-
export let id =
|
|
8
|
-
export let text =
|
|
8
|
+
export let id: string | undefined = undefined
|
|
9
|
+
export let text: string | undefined = undefined
|
|
9
10
|
export let disabled = false
|
|
10
11
|
export let readonly = false
|
|
11
|
-
export let size
|
|
12
|
+
export let size: "S" | "M" | "L" | "XL" = "M"
|
|
12
13
|
export let indeterminate = false
|
|
13
14
|
|
|
14
15
|
const dispatch = createEventDispatcher()
|
|
15
|
-
const onChange = event => {
|
|
16
|
-
dispatch("change", event.
|
|
16
|
+
const onChange: ChangeEventHandler<HTMLInputElement> = event => {
|
|
17
|
+
dispatch("change", event.currentTarget.checked)
|
|
17
18
|
}
|
|
18
19
|
|
|
19
|
-
$: sizeClass = `spectrum-Checkbox--size${size
|
|
20
|
+
$: sizeClass = `spectrum-Checkbox--size${size}`
|
|
20
21
|
</script>
|
|
21
22
|
|
|
22
23
|
<label
|
|
@@ -1,19 +1,24 @@
|
|
|
1
|
-
<script>
|
|
1
|
+
<script lang="ts" context="module">
|
|
2
|
+
type O = any
|
|
3
|
+
type V = any
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<script lang="ts" generics="O, V">
|
|
2
7
|
import "@spectrum-css/fieldgroup/dist/index-vars.css"
|
|
3
8
|
import "@spectrum-css/radio/dist/index-vars.css"
|
|
4
9
|
import { createEventDispatcher } from "svelte"
|
|
5
10
|
|
|
6
|
-
export let direction = "vertical"
|
|
7
|
-
export let value = []
|
|
8
|
-
export let options = []
|
|
11
|
+
export let direction: "horizontal" | "vertical" = "vertical"
|
|
12
|
+
export let value: V[] = []
|
|
13
|
+
export let options: O[] = []
|
|
9
14
|
export let disabled = false
|
|
10
15
|
export let readonly = false
|
|
11
|
-
export let getOptionLabel = option => option
|
|
12
|
-
export let getOptionValue = option => option
|
|
16
|
+
export let getOptionLabel = (option: O) => `${option}`
|
|
17
|
+
export let getOptionValue = (option: O) => option as unknown as V
|
|
13
18
|
|
|
14
|
-
const dispatch = createEventDispatcher()
|
|
19
|
+
const dispatch = createEventDispatcher<{ change: V[] }>()
|
|
15
20
|
|
|
16
|
-
const onChange = optionValue => {
|
|
21
|
+
const onChange = (optionValue: V) => {
|
|
17
22
|
if (!value.includes(optionValue)) {
|
|
18
23
|
dispatch("change", [...value, optionValue])
|
|
19
24
|
} else {
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
<script>
|
|
1
|
+
<script lang="ts" context="module">
|
|
2
|
+
type O = any
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<script lang="ts" generics="O">
|
|
6
|
+
import type { ChangeEventHandler } from "svelte/elements"
|
|
7
|
+
|
|
2
8
|
import "@spectrum-css/inputgroup/dist/index-vars.css"
|
|
3
9
|
import "@spectrum-css/popover/dist/index-vars.css"
|
|
4
10
|
import "@spectrum-css/menu/dist/index-vars.css"
|
|
@@ -6,33 +12,38 @@
|
|
|
6
12
|
import clickOutside from "../../Actions/click_outside"
|
|
7
13
|
import Popover from "../../Popover/Popover.svelte"
|
|
8
14
|
|
|
9
|
-
export let value =
|
|
10
|
-
export let id =
|
|
15
|
+
export let value: string | undefined = undefined
|
|
16
|
+
export let id: string | undefined = undefined
|
|
11
17
|
export let placeholder = "Choose an option or type"
|
|
12
18
|
export let disabled = false
|
|
13
19
|
export let readonly = false
|
|
14
|
-
export let options = []
|
|
15
|
-
export let getOptionLabel = option => option
|
|
16
|
-
export let getOptionValue = option => option
|
|
20
|
+
export let options: O[] = []
|
|
21
|
+
export let getOptionLabel = (option: O) => `${option}`
|
|
22
|
+
export let getOptionValue = (option: O) => `${option}`
|
|
17
23
|
|
|
18
|
-
const dispatch = createEventDispatcher
|
|
24
|
+
const dispatch = createEventDispatcher<{
|
|
25
|
+
change: string
|
|
26
|
+
blur: void
|
|
27
|
+
type: string
|
|
28
|
+
pick: string
|
|
29
|
+
}>()
|
|
19
30
|
|
|
20
31
|
let open = false
|
|
21
32
|
let focus = false
|
|
22
33
|
let anchor
|
|
23
34
|
|
|
24
|
-
const selectOption = value => {
|
|
35
|
+
const selectOption = (value: string) => {
|
|
25
36
|
dispatch("change", value)
|
|
26
37
|
open = false
|
|
27
38
|
}
|
|
28
39
|
|
|
29
|
-
const onType = e => {
|
|
30
|
-
const value = e.
|
|
40
|
+
const onType: ChangeEventHandler<HTMLInputElement> = e => {
|
|
41
|
+
const value = e.currentTarget.value
|
|
31
42
|
dispatch("type", value)
|
|
32
43
|
selectOption(value)
|
|
33
44
|
}
|
|
34
45
|
|
|
35
|
-
const onPick = value => {
|
|
46
|
+
const onPick = (value: string) => {
|
|
36
47
|
dispatch("pick", value)
|
|
37
48
|
selectOption(value)
|
|
38
49
|
}
|
|
@@ -1,28 +1,33 @@
|
|
|
1
|
-
<script>
|
|
1
|
+
<script lang="ts">
|
|
2
2
|
import "@spectrum-css/popover/dist/index-vars.css"
|
|
3
|
+
// @ts-expect-error no types for the version of svelte-portal we're on.
|
|
3
4
|
import Portal from "svelte-portal"
|
|
4
5
|
import { createEventDispatcher, getContext, onDestroy } from "svelte"
|
|
5
|
-
import positionDropdown
|
|
6
|
+
import positionDropdown, {
|
|
7
|
+
type UpdateHandler,
|
|
8
|
+
} from "../Actions/position_dropdown"
|
|
6
9
|
import clickOutside from "../Actions/click_outside"
|
|
7
10
|
import { fly } from "svelte/transition"
|
|
8
11
|
import Context from "../context"
|
|
12
|
+
import type { KeyboardEventHandler } from "svelte/elements"
|
|
9
13
|
|
|
10
|
-
const dispatch = createEventDispatcher()
|
|
14
|
+
const dispatch = createEventDispatcher<{ open: void; close: void }>()
|
|
11
15
|
|
|
12
|
-
export let anchor
|
|
13
|
-
export let align
|
|
14
|
-
|
|
15
|
-
export let
|
|
16
|
-
export let
|
|
17
|
-
export let
|
|
16
|
+
export let anchor: HTMLElement
|
|
17
|
+
export let align: "left" | "right" | "left-outside" | "right-outside" =
|
|
18
|
+
"right"
|
|
19
|
+
export let portalTarget: string | undefined = undefined
|
|
20
|
+
export let minWidth: number | undefined = undefined
|
|
21
|
+
export let maxWidth: number | undefined = undefined
|
|
22
|
+
export let maxHeight: number | undefined = undefined
|
|
18
23
|
export let open = false
|
|
19
24
|
export let useAnchorWidth = false
|
|
20
25
|
export let dismissible = true
|
|
21
26
|
export let offset = 4
|
|
22
|
-
export let customHeight
|
|
27
|
+
export let customHeight: string | undefined = undefined
|
|
23
28
|
export let animate = true
|
|
24
|
-
export let customZindex
|
|
25
|
-
export let handlePostionUpdate
|
|
29
|
+
export let customZindex: string | undefined = undefined
|
|
30
|
+
export let handlePostionUpdate: UpdateHandler | undefined = undefined
|
|
26
31
|
export let showPopover = true
|
|
27
32
|
export let clickOutsideOverride = false
|
|
28
33
|
export let resizable = true
|
|
@@ -30,7 +35,7 @@
|
|
|
30
35
|
|
|
31
36
|
const animationDuration = 260
|
|
32
37
|
|
|
33
|
-
let timeout
|
|
38
|
+
let timeout: ReturnType<typeof setTimeout>
|
|
34
39
|
let blockPointerEvents = false
|
|
35
40
|
|
|
36
41
|
$: target = portalTarget || getContext(Context.PopoverRoot) || ".spectrum"
|
|
@@ -65,13 +70,13 @@
|
|
|
65
70
|
}
|
|
66
71
|
}
|
|
67
72
|
|
|
68
|
-
const handleOutsideClick = e => {
|
|
73
|
+
const handleOutsideClick = (e: MouseEvent) => {
|
|
69
74
|
if (clickOutsideOverride) {
|
|
70
75
|
return
|
|
71
76
|
}
|
|
72
77
|
if (open) {
|
|
73
78
|
// Stop propagation if the source is the anchor
|
|
74
|
-
let node = e.target
|
|
79
|
+
let node = e.target as Node | null
|
|
75
80
|
let fromAnchor = false
|
|
76
81
|
while (!fromAnchor && node && node.parentNode) {
|
|
77
82
|
fromAnchor = node === anchor
|
|
@@ -86,7 +91,7 @@
|
|
|
86
91
|
}
|
|
87
92
|
}
|
|
88
93
|
|
|
89
|
-
|
|
94
|
+
const handleEscape: KeyboardEventHandler<HTMLDivElement> = e => {
|
|
90
95
|
if (!clickOutsideOverride) {
|
|
91
96
|
return
|
|
92
97
|
}
|