@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/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.1",
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": "b4b42fa71fec8b50f97ef3662395b22d12571a46"
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
- const Strategies = {
12
- StartToStart: "StartToStart", // e.g. left alignment
13
- EndToEnd: "EndToEnd", // e.g. right alignment
14
- StartToEnd: "StartToEnd", // e.g. right-outside alignment
15
- EndToStart: "EndToStart", // e.g. left-outside alignment
16
- MidPoint: "MidPoint", // centers relative to midpoints
17
- ScreenEdge: "ScreenEdge", // locks to screen edge
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: null,
59
- top: null,
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 Strategies.StartToStart:
118
+ case "StartToStart":
94
119
  default:
95
120
  styles.left = anchorBounds.left
96
121
  break
97
- case Strategies.EndToEnd:
122
+ case "EndToEnd":
98
123
  styles.left = anchorBounds.right - elementBounds.width
99
124
  break
100
- case Strategies.StartToEnd:
125
+ case "StartToEnd":
101
126
  styles.left = anchorBounds.right + offset
102
127
  break
103
- case Strategies.EndToStart:
128
+ case "EndToStart":
104
129
  styles.left = anchorBounds.left - elementBounds.width - offset
105
130
  break
106
- case Strategies.MidPoint:
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 Strategies.ScreenEdge:
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 Strategies.StartToStart:
146
+ case "StartToStart":
122
147
  styles.top = anchorBounds.top
123
148
  applyMaxHeight(winHeight - anchorBounds.top - screenOffset)
124
149
  break
125
- case Strategies.EndToEnd:
150
+ case "EndToEnd":
126
151
  styles.top = anchorBounds.bottom - elementBounds.height
127
152
  applyMaxHeight(anchorBounds.bottom - screenOffset)
128
153
  break
129
- case Strategies.StartToEnd:
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 Strategies.EndToStart:
159
+ case "EndToStart":
135
160
  styles.top = anchorBounds.top - elementBounds.height - offset
136
161
  applyMaxHeight(anchorBounds.top - screenOffset)
137
162
  break
138
- case Strategies.MidPoint:
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 Strategies.ScreenEdge:
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(Strategies.EndToEnd)
178
+ applyXStrategy("EndToEnd")
154
179
  } else if (align === "right-outside" || align === "right-context-menu") {
155
- applyXStrategy(Strategies.StartToEnd)
180
+ applyXStrategy("StartToEnd")
156
181
  } else if (align === "left-outside" || align === "left-context-menu") {
157
- applyXStrategy(Strategies.EndToStart)
182
+ applyXStrategy("EndToStart")
158
183
  } else if (align === "center") {
159
- applyXStrategy(Strategies.MidPoint)
184
+ applyXStrategy("MidPoint")
160
185
  } else {
161
- applyXStrategy(Strategies.StartToStart)
186
+ applyXStrategy("StartToStart")
162
187
  }
163
188
 
164
189
  // Determine Y strategy
165
190
  if (align === "right-outside" || align === "left-outside") {
166
- applyYStrategy(Strategies.MidPoint)
191
+ applyYStrategy("MidPoint")
167
192
  } else if (
168
193
  align === "right-context-menu" ||
169
194
  align === "left-context-menu"
170
195
  ) {
171
- applyYStrategy(Strategies.StartToStart)
172
- styles.top -= 5 // Manual adjustment for action menu padding
196
+ applyYStrategy("StartToStart")
197
+ if (styles.top) {
198
+ styles.top -= 5 // Manual adjustment for action menu padding
199
+ }
173
200
  } else {
174
- applyYStrategy(Strategies.StartToEnd)
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(Strategies.EndToEnd)
208
+ applyXStrategy("EndToEnd")
182
209
  }
183
210
  // Swap right-outside to left-outside
184
211
  else if (align === "right-outside") {
185
- applyXStrategy(Strategies.EndToStart)
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(Strategies.MidPoint)
219
+ applyYStrategy("MidPoint")
193
220
  if (doesYOverflow()) {
194
- applyYStrategy(Strategies.ScreenEdge)
221
+ applyYStrategy("ScreenEdge")
195
222
  }
196
- applyXStrategy(Strategies.StartToEnd)
223
+ applyXStrategy("StartToEnd")
197
224
  if (doesXOverflow()) {
198
- applyXStrategy(Strategies.EndToStart)
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(Strategies.ScreenEdge)
232
+ applyYStrategy("ScreenEdge")
206
233
  }
207
234
  // Otherwise flip above
208
235
  else {
209
- applyYStrategy(Strategies.EndToStart)
236
+ applyYStrategy("EndToStart")
210
237
  }
211
238
  }
212
239
  }
213
240
  }
214
241
 
215
- // Apply styles
216
- Object.entries(styles).forEach(([style, value]) => {
242
+ for (const [key, value] of Object.entries(styles)) {
243
+ const name = key as keyof Styles
217
244
  if (value != null) {
218
- element.style[style] = `${value.toFixed(0)}px`
245
+ element.style[name] = `${value}px`
219
246
  } else {
220
- element.style[style] = null
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 = null
8
- export let text = null
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.target.checked)
16
+ const onChange: ChangeEventHandler<HTMLInputElement> = event => {
17
+ dispatch("change", event.currentTarget.checked)
17
18
  }
18
19
 
19
- $: sizeClass = `spectrum-Checkbox--size${size || "M"}`
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 = null
10
- export let id = null
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.target.value
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 from "../Actions/position_dropdown"
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 = "right"
14
- export let portalTarget
15
- export let minWidth
16
- export let maxWidth
17
- export let maxHeight
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
- function handleEscape(e) {
94
+ const handleEscape: KeyboardEventHandler<HTMLDivElement> = e => {
90
95
  if (!clickOutsideOverride) {
91
96
  return
92
97
  }