@budibase/bbui 3.3.6 → 3.4.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/dist/bbui.mjs +4689 -4700
- package/package.json +3 -3
- package/src/Actions/{click_outside.js → click_outside.ts} +66 -20
- package/src/Actions/position_dropdown.ts +26 -20
- package/src/Form/Core/Combobox.svelte +8 -2
- package/src/Form/Core/Picker.svelte +68 -41
- package/src/Form/Core/Search.svelte +8 -8
- package/src/Form/Core/Select.svelte +46 -31
- package/src/Form/Core/TextField.svelte +18 -11
- package/src/Form/Field.svelte +7 -7
- package/src/Form/Input.svelte +9 -10
- package/src/Form/Select.svelte +38 -30
- package/src/Icon/Icon.svelte +3 -17
- package/src/Link/Link.svelte +2 -2
- package/src/Popover/Popover.svelte +22 -13
- package/src/StatusLight/StatusLight.svelte +20 -20
- package/src/Tooltip/AbsTooltip.svelte +15 -29
- package/src/constants.ts +23 -0
- package/src/index.ts +4 -4
- package/src/Popover/Popover.svench +0 -120
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.
|
|
4
|
+
"version": "3.4.0",
|
|
5
5
|
"license": "MPL-2.0",
|
|
6
6
|
"svelte": "src/index.ts",
|
|
7
7
|
"module": "dist/bbui.mjs",
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"dayjs": "^1.10.8",
|
|
81
81
|
"easymde": "^2.16.1",
|
|
82
82
|
"svelte-dnd-action": "^0.9.8",
|
|
83
|
-
"svelte-portal": "^
|
|
83
|
+
"svelte-portal": "^2.2.1"
|
|
84
84
|
},
|
|
85
85
|
"resolutions": {
|
|
86
86
|
"loader-utils": "1.4.1"
|
|
@@ -99,5 +99,5 @@
|
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
101
|
},
|
|
102
|
-
"gitHead": "
|
|
102
|
+
"gitHead": "079956852a2be6d40f7d1e3b19335271cfff2d7f"
|
|
103
103
|
}
|
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
type ClickOutsideCallback = (event: MouseEvent) => void | undefined
|
|
2
|
+
|
|
3
|
+
interface ClickOutsideOpts {
|
|
4
|
+
callback?: ClickOutsideCallback
|
|
5
|
+
anchor?: HTMLElement
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
interface Handler {
|
|
9
|
+
id: number
|
|
10
|
+
element: HTMLElement
|
|
11
|
+
anchor: HTMLElement
|
|
12
|
+
callback?: ClickOutsideCallback
|
|
13
|
+
}
|
|
14
|
+
|
|
1
15
|
// These class names will never trigger a callback if clicked, no matter what
|
|
2
16
|
const ignoredClasses = [
|
|
3
17
|
".download-js-link",
|
|
@@ -14,18 +28,20 @@ const conditionallyIgnoredClasses = [
|
|
|
14
28
|
".drawer-wrapper",
|
|
15
29
|
".spectrum-Popover",
|
|
16
30
|
]
|
|
17
|
-
let clickHandlers = []
|
|
18
|
-
let candidateTarget
|
|
31
|
+
let clickHandlers: Handler[] = []
|
|
32
|
+
let candidateTarget: HTMLElement | undefined
|
|
19
33
|
|
|
20
34
|
// Processes a "click outside" event and invokes callbacks if our source element
|
|
21
35
|
// is valid
|
|
22
|
-
const handleClick =
|
|
36
|
+
const handleClick = (e: MouseEvent) => {
|
|
37
|
+
const target = e.target as HTMLElement
|
|
38
|
+
|
|
23
39
|
// Ignore click if this is an ignored class
|
|
24
|
-
if (
|
|
40
|
+
if (target.closest('[data-ignore-click-outside="true"]')) {
|
|
25
41
|
return
|
|
26
42
|
}
|
|
27
43
|
for (let className of ignoredClasses) {
|
|
28
|
-
if (
|
|
44
|
+
if (target.closest(className)) {
|
|
29
45
|
return
|
|
30
46
|
}
|
|
31
47
|
}
|
|
@@ -33,41 +49,41 @@ const handleClick = event => {
|
|
|
33
49
|
// Process handlers
|
|
34
50
|
clickHandlers.forEach(handler => {
|
|
35
51
|
// Check that the click isn't inside the target
|
|
36
|
-
if (handler.element.contains(
|
|
52
|
+
if (handler.element.contains(target)) {
|
|
37
53
|
return
|
|
38
54
|
}
|
|
39
55
|
|
|
40
56
|
// Ignore clicks for certain classes unless we're nested inside them
|
|
41
57
|
for (let className of conditionallyIgnoredClasses) {
|
|
42
58
|
const sourceInside = handler.anchor.closest(className) != null
|
|
43
|
-
const clickInside =
|
|
59
|
+
const clickInside = target.closest(className) != null
|
|
44
60
|
if (clickInside && !sourceInside) {
|
|
45
61
|
return
|
|
46
62
|
}
|
|
47
63
|
}
|
|
48
64
|
|
|
49
|
-
handler.callback?.(
|
|
65
|
+
handler.callback?.(e)
|
|
50
66
|
})
|
|
51
67
|
}
|
|
52
68
|
|
|
53
69
|
// On mouse up we only trigger a "click outside" callback if we targetted the
|
|
54
70
|
// same element that we did on mouse down. This fixes all sorts of issues where
|
|
55
71
|
// we get annoying callbacks firing when we drag to select text.
|
|
56
|
-
const handleMouseUp = e => {
|
|
72
|
+
const handleMouseUp = (e: MouseEvent) => {
|
|
57
73
|
if (candidateTarget === e.target) {
|
|
58
74
|
handleClick(e)
|
|
59
75
|
}
|
|
60
|
-
candidateTarget =
|
|
76
|
+
candidateTarget = undefined
|
|
61
77
|
}
|
|
62
78
|
|
|
63
79
|
// On mouse down we store which element was targetted for comparison later
|
|
64
|
-
const handleMouseDown = e => {
|
|
80
|
+
const handleMouseDown = (e: MouseEvent) => {
|
|
65
81
|
// Only handle the primary mouse button here.
|
|
66
82
|
// We handle context menu (right click) events in another handler.
|
|
67
83
|
if (e.button !== 0) {
|
|
68
84
|
return
|
|
69
85
|
}
|
|
70
|
-
candidateTarget = e.target
|
|
86
|
+
candidateTarget = e.target as HTMLElement
|
|
71
87
|
|
|
72
88
|
// Clear any previous listeners in case of multiple down events, and register
|
|
73
89
|
// a single mouse up listener
|
|
@@ -82,7 +98,12 @@ document.addEventListener("contextmenu", handleClick)
|
|
|
82
98
|
/**
|
|
83
99
|
* Adds or updates a click handler
|
|
84
100
|
*/
|
|
85
|
-
const updateHandler = (
|
|
101
|
+
const updateHandler = (
|
|
102
|
+
id: number,
|
|
103
|
+
element: HTMLElement,
|
|
104
|
+
anchor: HTMLElement,
|
|
105
|
+
callback: ClickOutsideCallback | undefined
|
|
106
|
+
) => {
|
|
86
107
|
let existingHandler = clickHandlers.find(x => x.id === id)
|
|
87
108
|
if (!existingHandler) {
|
|
88
109
|
clickHandlers.push({ id, element, anchor, callback })
|
|
@@ -94,27 +115,52 @@ const updateHandler = (id, element, anchor, callback) => {
|
|
|
94
115
|
/**
|
|
95
116
|
* Removes a click handler
|
|
96
117
|
*/
|
|
97
|
-
const removeHandler = id => {
|
|
118
|
+
const removeHandler = (id: number) => {
|
|
98
119
|
clickHandlers = clickHandlers.filter(x => x.id !== id)
|
|
99
120
|
}
|
|
100
121
|
|
|
101
122
|
/**
|
|
102
|
-
* Svelte action to apply a click outside handler for a certain element
|
|
123
|
+
* Svelte action to apply a click outside handler for a certain element.
|
|
103
124
|
* opts.anchor is an optional param specifying the real root source of the
|
|
104
125
|
* component being observed. This is required for things like popovers, where
|
|
105
126
|
* the element using the clickoutside action is the popover, but the popover is
|
|
106
127
|
* rendered at the root of the DOM somewhere, whereas the popover anchor is the
|
|
107
128
|
* element we actually want to consider when determining the source component.
|
|
108
129
|
*/
|
|
109
|
-
export default (
|
|
130
|
+
export default (
|
|
131
|
+
element: HTMLElement,
|
|
132
|
+
opts?: ClickOutsideOpts | ClickOutsideCallback
|
|
133
|
+
) => {
|
|
110
134
|
const id = Math.random()
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
135
|
+
|
|
136
|
+
const isCallback = (
|
|
137
|
+
opts?: ClickOutsideOpts | ClickOutsideCallback
|
|
138
|
+
): opts is ClickOutsideCallback => {
|
|
139
|
+
return typeof opts === "function"
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const isOpts = (
|
|
143
|
+
opts?: ClickOutsideOpts | ClickOutsideCallback
|
|
144
|
+
): opts is ClickOutsideOpts => {
|
|
145
|
+
return opts != null && typeof opts === "object"
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const update = (newOpts?: ClickOutsideOpts | ClickOutsideCallback) => {
|
|
149
|
+
let callback: ClickOutsideCallback | undefined
|
|
150
|
+
let anchor = element
|
|
151
|
+
if (isCallback(newOpts)) {
|
|
152
|
+
callback = newOpts
|
|
153
|
+
} else if (isOpts(newOpts)) {
|
|
154
|
+
callback = newOpts.callback
|
|
155
|
+
if (newOpts.anchor) {
|
|
156
|
+
anchor = newOpts.anchor
|
|
157
|
+
}
|
|
158
|
+
}
|
|
115
159
|
updateHandler(id, element, anchor, callback)
|
|
116
160
|
}
|
|
161
|
+
|
|
117
162
|
update(opts)
|
|
163
|
+
|
|
118
164
|
return {
|
|
119
165
|
update,
|
|
120
166
|
destroy: () => removeHandler(id),
|
|
@@ -1,13 +1,7 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Valid alignment options are
|
|
3
|
-
* - left
|
|
4
|
-
* - right
|
|
5
|
-
* - left-outside
|
|
6
|
-
* - right-outside
|
|
7
|
-
**/
|
|
8
|
-
|
|
9
1
|
// Strategies are defined as [Popover]To[Anchor].
|
|
10
2
|
// They can apply for both horizontal and vertical alignment.
|
|
3
|
+
import { PopoverAlignment } from "../constants"
|
|
4
|
+
|
|
11
5
|
type Strategy =
|
|
12
6
|
| "StartToStart"
|
|
13
7
|
| "EndToEnd"
|
|
@@ -33,7 +27,7 @@ export type UpdateHandler = (
|
|
|
33
27
|
|
|
34
28
|
interface Opts {
|
|
35
29
|
anchor?: HTMLElement
|
|
36
|
-
align:
|
|
30
|
+
align: PopoverAlignment
|
|
37
31
|
maxHeight?: number
|
|
38
32
|
maxWidth?: number
|
|
39
33
|
minWidth?: number
|
|
@@ -174,24 +168,33 @@ export default function positionDropdown(element: HTMLElement, opts: Opts) {
|
|
|
174
168
|
}
|
|
175
169
|
|
|
176
170
|
// Determine X strategy
|
|
177
|
-
if (align ===
|
|
171
|
+
if (align === PopoverAlignment.Right) {
|
|
178
172
|
applyXStrategy("EndToEnd")
|
|
179
|
-
} else if (
|
|
173
|
+
} else if (
|
|
174
|
+
align === PopoverAlignment.RightOutside ||
|
|
175
|
+
align === PopoverAlignment.RightContextMenu
|
|
176
|
+
) {
|
|
180
177
|
applyXStrategy("StartToEnd")
|
|
181
|
-
} else if (
|
|
178
|
+
} else if (
|
|
179
|
+
align === PopoverAlignment.LeftOutside ||
|
|
180
|
+
align === PopoverAlignment.LeftContextMenu
|
|
181
|
+
) {
|
|
182
182
|
applyXStrategy("EndToStart")
|
|
183
|
-
} else if (align ===
|
|
183
|
+
} else if (align === PopoverAlignment.Center) {
|
|
184
184
|
applyXStrategy("MidPoint")
|
|
185
185
|
} else {
|
|
186
186
|
applyXStrategy("StartToStart")
|
|
187
187
|
}
|
|
188
188
|
|
|
189
189
|
// Determine Y strategy
|
|
190
|
-
if (
|
|
190
|
+
if (
|
|
191
|
+
align === PopoverAlignment.RightOutside ||
|
|
192
|
+
align === PopoverAlignment.LeftOutside
|
|
193
|
+
) {
|
|
191
194
|
applyYStrategy("MidPoint")
|
|
192
195
|
} else if (
|
|
193
|
-
align ===
|
|
194
|
-
align ===
|
|
196
|
+
align === PopoverAlignment.RightContextMenu ||
|
|
197
|
+
align === PopoverAlignment.LeftContextMenu
|
|
195
198
|
) {
|
|
196
199
|
applyYStrategy("StartToStart")
|
|
197
200
|
if (styles.top) {
|
|
@@ -204,11 +207,11 @@ export default function positionDropdown(element: HTMLElement, opts: Opts) {
|
|
|
204
207
|
// Handle screen overflow
|
|
205
208
|
if (doesXOverflow()) {
|
|
206
209
|
// Swap left to right
|
|
207
|
-
if (align ===
|
|
210
|
+
if (align === PopoverAlignment.Left) {
|
|
208
211
|
applyXStrategy("EndToEnd")
|
|
209
212
|
}
|
|
210
213
|
// Swap right-outside to left-outside
|
|
211
|
-
else if (align ===
|
|
214
|
+
else if (align === PopoverAlignment.RightOutside) {
|
|
212
215
|
applyXStrategy("EndToStart")
|
|
213
216
|
}
|
|
214
217
|
}
|
|
@@ -225,10 +228,13 @@ export default function positionDropdown(element: HTMLElement, opts: Opts) {
|
|
|
225
228
|
applyXStrategy("EndToStart")
|
|
226
229
|
}
|
|
227
230
|
}
|
|
228
|
-
//
|
|
231
|
+
// Otherwise invert as normal
|
|
229
232
|
else {
|
|
230
233
|
// If using an outside strategy then lock to the bottom of the screen
|
|
231
|
-
if (
|
|
234
|
+
if (
|
|
235
|
+
align === PopoverAlignment.LeftOutside ||
|
|
236
|
+
align === PopoverAlignment.RightOutside
|
|
237
|
+
) {
|
|
232
238
|
applyYStrategy("ScreenEdge")
|
|
233
239
|
}
|
|
234
240
|
// Otherwise flip above
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
import { createEventDispatcher } from "svelte"
|
|
12
12
|
import clickOutside from "../../Actions/click_outside"
|
|
13
13
|
import Popover from "../../Popover/Popover.svelte"
|
|
14
|
+
import { PopoverAlignment } from "../../constants"
|
|
14
15
|
|
|
15
16
|
export let value: string | undefined = undefined
|
|
16
17
|
export let id: string | undefined = undefined
|
|
@@ -97,11 +98,16 @@
|
|
|
97
98
|
<Popover
|
|
98
99
|
{anchor}
|
|
99
100
|
{open}
|
|
100
|
-
align=
|
|
101
|
+
align={PopoverAlignment.Left}
|
|
101
102
|
on:close={() => (open = false)}
|
|
102
103
|
useAnchorWidth
|
|
103
104
|
>
|
|
104
|
-
<div
|
|
105
|
+
<div
|
|
106
|
+
class="popover-content"
|
|
107
|
+
use:clickOutside={() => {
|
|
108
|
+
open = false
|
|
109
|
+
}}
|
|
110
|
+
>
|
|
105
111
|
<ul class="spectrum-Menu" role="listbox">
|
|
106
112
|
{#if options && Array.isArray(options)}
|
|
107
113
|
{#each options as option}
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
<script>
|
|
1
|
+
<script lang="ts" context="module">
|
|
2
|
+
type O = any
|
|
3
|
+
type V = any
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<script lang="ts">
|
|
2
7
|
import "@spectrum-css/picker/dist/index-vars.css"
|
|
3
8
|
import "@spectrum-css/popover/dist/index-vars.css"
|
|
4
9
|
import "@spectrum-css/menu/dist/index-vars.css"
|
|
@@ -11,43 +16,55 @@
|
|
|
11
16
|
import Tags from "../../Tags/Tags.svelte"
|
|
12
17
|
import Tag from "../../Tags/Tag.svelte"
|
|
13
18
|
import ProgressCircle from "../../ProgressCircle/ProgressCircle.svelte"
|
|
19
|
+
import { PopoverAlignment } from "../../constants"
|
|
14
20
|
|
|
15
|
-
export let id =
|
|
16
|
-
export let disabled = false
|
|
17
|
-
export let fieldText = ""
|
|
18
|
-
export let fieldIcon = ""
|
|
19
|
-
export let fieldColour = ""
|
|
20
|
-
export let isPlaceholder = false
|
|
21
|
-
export let placeholderOption =
|
|
22
|
-
export let options = []
|
|
23
|
-
export let isOptionSelected = () =>
|
|
24
|
-
export let isOptionEnabled = () =>
|
|
25
|
-
|
|
26
|
-
export let
|
|
27
|
-
export let
|
|
28
|
-
export let
|
|
21
|
+
export let id: string | undefined = undefined
|
|
22
|
+
export let disabled: boolean = false
|
|
23
|
+
export let fieldText: string = ""
|
|
24
|
+
export let fieldIcon: string = ""
|
|
25
|
+
export let fieldColour: string = ""
|
|
26
|
+
export let isPlaceholder: boolean = false
|
|
27
|
+
export let placeholderOption: string | undefined | boolean = undefined
|
|
28
|
+
export let options: O[] = []
|
|
29
|
+
export let isOptionSelected = (option: O) => option as unknown as boolean
|
|
30
|
+
export let isOptionEnabled = (option: O, _index?: number) =>
|
|
31
|
+
option as unknown as boolean
|
|
32
|
+
export let onSelectOption: (_value: V) => void = () => {}
|
|
33
|
+
export let getOptionLabel = (option: O, _index?: number) => `${option}`
|
|
34
|
+
export let getOptionValue = (option: O, _index?: number) =>
|
|
35
|
+
option as unknown as V
|
|
36
|
+
export let getOptionIcon = (option: O, _index?: number) =>
|
|
37
|
+
option as unknown as O
|
|
29
38
|
export let useOptionIconImage = false
|
|
30
|
-
export let getOptionColour = () =>
|
|
31
|
-
|
|
32
|
-
export let
|
|
33
|
-
|
|
34
|
-
export let
|
|
35
|
-
export let
|
|
36
|
-
export let
|
|
37
|
-
export let
|
|
38
|
-
export let
|
|
39
|
-
export let
|
|
40
|
-
export let
|
|
41
|
-
export let
|
|
42
|
-
export let
|
|
43
|
-
export let
|
|
44
|
-
export let
|
|
45
|
-
export let
|
|
39
|
+
export let getOptionColour = (option: O, _index?: number) =>
|
|
40
|
+
option as unknown as O
|
|
41
|
+
export let getOptionSubtitle = (option: O, _index?: number) =>
|
|
42
|
+
option as unknown as O
|
|
43
|
+
export let open: boolean = false
|
|
44
|
+
export let readonly: boolean = false
|
|
45
|
+
export let quiet: boolean = false
|
|
46
|
+
export let autoWidth: boolean | undefined = false
|
|
47
|
+
export let autocomplete: boolean = false
|
|
48
|
+
export let sort: boolean = false
|
|
49
|
+
export let searchTerm: string | null = null
|
|
50
|
+
export let customPopoverHeight: string | undefined = undefined
|
|
51
|
+
export let align: PopoverAlignment | undefined = PopoverAlignment.Left
|
|
52
|
+
export let footer: string | undefined = undefined
|
|
53
|
+
export let customAnchor: HTMLElement | undefined = undefined
|
|
54
|
+
export let loading: boolean = false
|
|
55
|
+
export let onOptionMouseenter: (
|
|
56
|
+
_e: MouseEvent,
|
|
57
|
+
_option: any
|
|
58
|
+
) => void = () => {}
|
|
59
|
+
export let onOptionMouseleave: (
|
|
60
|
+
_e: MouseEvent,
|
|
61
|
+
_option: any
|
|
62
|
+
) => void = () => {}
|
|
46
63
|
|
|
47
64
|
const dispatch = createEventDispatcher()
|
|
48
65
|
|
|
49
|
-
let button
|
|
50
|
-
let component
|
|
66
|
+
let button: any
|
|
67
|
+
let component: any
|
|
51
68
|
|
|
52
69
|
$: sortedOptions = getSortedOptions(options, getOptionLabel, sort)
|
|
53
70
|
$: filteredOptions = getFilteredOptions(
|
|
@@ -56,7 +73,7 @@
|
|
|
56
73
|
getOptionLabel
|
|
57
74
|
)
|
|
58
75
|
|
|
59
|
-
const onClick = e => {
|
|
76
|
+
const onClick = (e: MouseEvent) => {
|
|
60
77
|
e.preventDefault()
|
|
61
78
|
e.stopPropagation()
|
|
62
79
|
dispatch("click")
|
|
@@ -67,7 +84,11 @@
|
|
|
67
84
|
open = !open
|
|
68
85
|
}
|
|
69
86
|
|
|
70
|
-
const getSortedOptions = (
|
|
87
|
+
const getSortedOptions = (
|
|
88
|
+
options: any[],
|
|
89
|
+
getLabel: (_option: any) => string,
|
|
90
|
+
sort: boolean
|
|
91
|
+
) => {
|
|
71
92
|
if (!options?.length || !Array.isArray(options)) {
|
|
72
93
|
return []
|
|
73
94
|
}
|
|
@@ -81,17 +102,21 @@
|
|
|
81
102
|
})
|
|
82
103
|
}
|
|
83
104
|
|
|
84
|
-
const getFilteredOptions = (
|
|
105
|
+
const getFilteredOptions = (
|
|
106
|
+
options: any[],
|
|
107
|
+
term: string | null,
|
|
108
|
+
getLabel: (_option: any) => string
|
|
109
|
+
) => {
|
|
85
110
|
if (autocomplete && term) {
|
|
86
111
|
const lowerCaseTerm = term.toLowerCase()
|
|
87
|
-
return options.filter(option => {
|
|
112
|
+
return options.filter((option: any) => {
|
|
88
113
|
return `${getLabel(option)}`.toLowerCase().includes(lowerCaseTerm)
|
|
89
114
|
})
|
|
90
115
|
}
|
|
91
116
|
return options
|
|
92
117
|
}
|
|
93
118
|
|
|
94
|
-
const onScroll = e => {
|
|
119
|
+
const onScroll = (e: any) => {
|
|
95
120
|
const scrollPxThreshold = 100
|
|
96
121
|
const scrollPositionFromBottom =
|
|
97
122
|
e.target.scrollHeight - e.target.clientHeight - e.target.scrollTop
|
|
@@ -151,18 +176,20 @@
|
|
|
151
176
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
152
177
|
<Popover
|
|
153
178
|
anchor={customAnchor ? customAnchor : button}
|
|
154
|
-
align={align ||
|
|
179
|
+
align={align || PopoverAlignment.Left}
|
|
155
180
|
{open}
|
|
156
181
|
on:close={() => (open = false)}
|
|
157
182
|
useAnchorWidth={!autoWidth}
|
|
158
|
-
maxWidth={autoWidth ? 400 :
|
|
183
|
+
maxWidth={autoWidth ? 400 : undefined}
|
|
159
184
|
customHeight={customPopoverHeight}
|
|
160
185
|
maxHeight={360}
|
|
161
186
|
>
|
|
162
187
|
<div
|
|
163
188
|
class="popover-content"
|
|
164
189
|
class:auto-width={autoWidth}
|
|
165
|
-
use:clickOutside={() =>
|
|
190
|
+
use:clickOutside={() => {
|
|
191
|
+
open = false
|
|
192
|
+
}}
|
|
166
193
|
>
|
|
167
194
|
{#if autocomplete}
|
|
168
195
|
<Search
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
<script>
|
|
1
|
+
<script lang="ts">
|
|
2
2
|
import "@spectrum-css/search/dist/index-vars.css"
|
|
3
3
|
import { createEventDispatcher } from "svelte"
|
|
4
4
|
|
|
5
|
-
export let value = null
|
|
6
|
-
export let placeholder =
|
|
5
|
+
export let value: any = null
|
|
6
|
+
export let placeholder: string | undefined = undefined
|
|
7
7
|
export let disabled = false
|
|
8
8
|
export let id = null
|
|
9
9
|
export let updateOnChange = true
|
|
10
10
|
export let quiet = false
|
|
11
|
-
export let inputRef
|
|
11
|
+
export let inputRef: HTMLElement | undefined = undefined
|
|
12
12
|
|
|
13
13
|
const dispatch = createEventDispatcher()
|
|
14
14
|
let focus = false
|
|
15
15
|
|
|
16
|
-
const updateValue = value => {
|
|
16
|
+
const updateValue = (value: any) => {
|
|
17
17
|
dispatch("change", value)
|
|
18
18
|
}
|
|
19
19
|
|
|
@@ -21,19 +21,19 @@
|
|
|
21
21
|
focus = true
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
const onBlur = event => {
|
|
24
|
+
const onBlur = (event: any) => {
|
|
25
25
|
focus = false
|
|
26
26
|
updateValue(event.target.value)
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
const onInput = event => {
|
|
29
|
+
const onInput = (event: any) => {
|
|
30
30
|
if (!updateOnChange) {
|
|
31
31
|
return
|
|
32
32
|
}
|
|
33
33
|
updateValue(event.target.value)
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
const updateValueOnEnter = event => {
|
|
36
|
+
const updateValueOnEnter = (event: any) => {
|
|
37
37
|
if (event.key === "Enter") {
|
|
38
38
|
updateValue(event.target.value)
|
|
39
39
|
}
|
|
@@ -1,33 +1,44 @@
|
|
|
1
|
-
<script>
|
|
1
|
+
<script lang="ts" context="module">
|
|
2
|
+
type O = any
|
|
3
|
+
type V = any
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<script lang="ts">
|
|
2
7
|
import { createEventDispatcher } from "svelte"
|
|
3
8
|
import Picker from "./Picker.svelte"
|
|
9
|
+
import { PopoverAlignment } from "../../constants"
|
|
4
10
|
|
|
5
|
-
export let value = null
|
|
6
|
-
export let id =
|
|
7
|
-
export let placeholder = "Choose an option"
|
|
8
|
-
export let disabled = false
|
|
9
|
-
export let options = []
|
|
10
|
-
export let getOptionLabel = option => option
|
|
11
|
-
export let getOptionValue = option =>
|
|
12
|
-
|
|
13
|
-
export let
|
|
14
|
-
|
|
15
|
-
export let
|
|
11
|
+
export let value: V | null = null
|
|
12
|
+
export let id: string | undefined = undefined
|
|
13
|
+
export let placeholder: string | boolean = "Choose an option"
|
|
14
|
+
export let disabled: boolean = false
|
|
15
|
+
export let options: O[] = []
|
|
16
|
+
export let getOptionLabel = (option: O, _index?: number) => `${option}`
|
|
17
|
+
export let getOptionValue = (option: O, _index?: number) =>
|
|
18
|
+
option as unknown as V
|
|
19
|
+
export let getOptionIcon = (option: O, _index?: number) =>
|
|
20
|
+
option as unknown as string
|
|
21
|
+
export let getOptionColour = (option: O, _index?: number) =>
|
|
22
|
+
option as unknown as string
|
|
23
|
+
export let getOptionSubtitle = (option: O, _index?: number) =>
|
|
24
|
+
option as unknown as string
|
|
25
|
+
export let compare = (option: O, value: V) => option === value
|
|
16
26
|
export let useOptionIconImage = false
|
|
17
|
-
export let isOptionEnabled
|
|
18
|
-
|
|
19
|
-
export let
|
|
20
|
-
export let
|
|
21
|
-
export let
|
|
22
|
-
export let
|
|
23
|
-
export let
|
|
24
|
-
export let
|
|
25
|
-
export let
|
|
26
|
-
export let
|
|
27
|
-
export let searchTerm =
|
|
28
|
-
export let loading
|
|
27
|
+
export let isOptionEnabled = (option: O, _index?: number) =>
|
|
28
|
+
option as unknown as boolean
|
|
29
|
+
export let readonly: boolean = false
|
|
30
|
+
export let quiet: boolean = false
|
|
31
|
+
export let autoWidth: boolean = false
|
|
32
|
+
export let autocomplete: boolean = false
|
|
33
|
+
export let sort: boolean = false
|
|
34
|
+
export let align: PopoverAlignment | undefined = PopoverAlignment.Left
|
|
35
|
+
export let footer: string | undefined = undefined
|
|
36
|
+
export let open: boolean = false
|
|
37
|
+
export let searchTerm: string | undefined = undefined
|
|
38
|
+
export let loading: boolean | undefined = undefined
|
|
29
39
|
export let onOptionMouseenter = () => {}
|
|
30
40
|
export let onOptionMouseleave = () => {}
|
|
41
|
+
export let customPopoverHeight: string | undefined = undefined
|
|
31
42
|
|
|
32
43
|
const dispatch = createEventDispatcher()
|
|
33
44
|
|
|
@@ -35,24 +46,28 @@
|
|
|
35
46
|
$: fieldIcon = getFieldAttribute(getOptionIcon, value, options)
|
|
36
47
|
$: fieldColour = getFieldAttribute(getOptionColour, value, options)
|
|
37
48
|
|
|
38
|
-
function compareOptionAndValue(option, value) {
|
|
49
|
+
function compareOptionAndValue(option: O, value: V) {
|
|
39
50
|
return typeof compare === "function"
|
|
40
51
|
? compare(option, value)
|
|
41
52
|
: option === value
|
|
42
53
|
}
|
|
43
54
|
|
|
44
|
-
const getFieldAttribute = (getAttribute, value, options) => {
|
|
55
|
+
const getFieldAttribute = (getAttribute: any, value: V[], options: O[]) => {
|
|
45
56
|
// Wait for options to load if there is a value but no options
|
|
46
57
|
if (!options?.length) {
|
|
47
58
|
return ""
|
|
48
59
|
}
|
|
49
|
-
const index = options.findIndex((option, idx) =>
|
|
60
|
+
const index = options.findIndex((option: any, idx: number) =>
|
|
50
61
|
compareOptionAndValue(getOptionValue(option, idx), value)
|
|
51
62
|
)
|
|
52
63
|
return index !== -1 ? getAttribute(options[index], index) : null
|
|
53
64
|
}
|
|
54
65
|
|
|
55
|
-
const getFieldText = (
|
|
66
|
+
const getFieldText = (
|
|
67
|
+
value: any,
|
|
68
|
+
options: any,
|
|
69
|
+
placeholder: boolean | string
|
|
70
|
+
) => {
|
|
56
71
|
if (value == null || value === "") {
|
|
57
72
|
// Explicit false means use no placeholder and allow an empty fields
|
|
58
73
|
if (placeholder === false) {
|
|
@@ -67,7 +82,7 @@
|
|
|
67
82
|
)
|
|
68
83
|
}
|
|
69
84
|
|
|
70
|
-
const selectOption = value => {
|
|
85
|
+
const selectOption = (value: V) => {
|
|
71
86
|
dispatch("change", value)
|
|
72
87
|
open = false
|
|
73
88
|
}
|
|
@@ -98,14 +113,14 @@
|
|
|
98
113
|
{isOptionEnabled}
|
|
99
114
|
{autocomplete}
|
|
100
115
|
{sort}
|
|
101
|
-
{tag}
|
|
102
116
|
{onOptionMouseenter}
|
|
103
117
|
{onOptionMouseleave}
|
|
104
118
|
isPlaceholder={value == null || value === ""}
|
|
105
119
|
placeholderOption={placeholder === false
|
|
106
|
-
?
|
|
120
|
+
? undefined
|
|
107
121
|
: placeholder || "Choose an option"}
|
|
108
122
|
isOptionSelected={option => compareOptionAndValue(option, value)}
|
|
109
123
|
onSelectOption={selectOption}
|
|
110
124
|
{loading}
|
|
125
|
+
{customPopoverHeight}
|
|
111
126
|
/>
|