@budibase/bbui 1.4.1 → 1.4.2
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/LICENSE +375 -0
- package/README.md +19 -17
- package/dist/bbui.es.js +14 -0
- package/dist/bbui.es.js.map +1 -0
- package/package.json +71 -26
- package/src/ActionButton/ActionButton.svelte +102 -0
- package/src/ActionGroup/ActionGroup.svelte +26 -0
- package/src/ActionMenu/ActionMenu.svelte +44 -0
- package/src/Actions/ClickOutside.svench.svx +30 -0
- package/src/Actions/PositionDropdown.svench.svx +81 -0
- package/src/Actions/autoresize_textarea.js +14 -0
- package/src/Actions/click_outside.js +18 -0
- package/src/Actions/position_dropdown.js +75 -0
- package/src/Avatar/Avatar.svelte +62 -0
- package/src/Badge/Badge.svelte +29 -0
- package/src/Banner/Banner.svelte +72 -0
- package/src/Banner/BannerDisplay.svelte +41 -0
- package/src/Button/Button.svelte +114 -0
- package/src/Button/Button.svench +138 -0
- package/src/ButtonGroup/ButtonGroup.svelte +30 -0
- package/src/ClearButton/ClearButton.svelte +19 -0
- package/src/ColorPicker/ColorPicker.svelte +297 -0
- package/src/DetailSummary/DetailSummary.svelte +83 -0
- package/src/Divider/Divider.svelte +28 -0
- package/src/Drawer/Drawer.svelte +113 -0
- package/src/Drawer/Drawer.svench +42 -0
- package/src/Drawer/DrawerContent.svelte +46 -0
- package/src/Form/Checkbox.svelte +23 -0
- package/src/Form/Combobox.svelte +45 -0
- package/src/Form/Core/Checkbox.svelte +69 -0
- package/src/Form/Core/CheckboxGroup.svelte +68 -0
- package/src/Form/Core/Combobox.svelte +142 -0
- package/src/Form/Core/DatePicker.svelte +257 -0
- package/src/Form/Core/Dropzone.svelte +450 -0
- package/src/Form/Core/InputDropdown.svelte +228 -0
- package/src/Form/Core/Multiselect.svelte +90 -0
- package/src/Form/Core/Picker.svelte +259 -0
- package/src/Form/Core/PickerDropdown.svelte +436 -0
- package/src/Form/Core/RadioGroup.svelte +48 -0
- package/src/Form/Core/RichTextField.svelte +42 -0
- package/src/Form/Core/Search.svelte +105 -0
- package/src/Form/Core/Select.svelte +75 -0
- package/src/Form/Core/Slider.svelte +86 -0
- package/src/Form/Core/Stepper.svelte +172 -0
- package/src/Form/Core/Switch.svelte +37 -0
- package/src/Form/Core/TextArea.svelte +78 -0
- package/src/Form/Core/TextField.svelte +119 -0
- package/src/Form/Core/index.js +15 -0
- package/src/Form/DatePicker.svelte +39 -0
- package/src/Form/Dropzone.svelte +42 -0
- package/src/Form/Field.svelte +42 -0
- package/src/Form/FieldLabel.svelte +32 -0
- package/src/Form/Input.svelte +40 -45
- package/src/Form/InputDropdown.svelte +55 -0
- package/src/Form/Multiselect.svelte +40 -0
- package/src/Form/PickerDropdown.svelte +134 -0
- package/src/Form/RadioGroup.svelte +42 -0
- package/src/Form/RichTextField.svelte +36 -0
- package/src/Form/Search.svelte +36 -0
- package/src/Form/Select.svelte +48 -43
- package/src/Form/Slider.svelte +24 -0
- package/src/Form/Stepper.svelte +45 -0
- package/src/Form/TextArea.svelte +29 -44
- package/src/Form/Toggle.svelte +23 -0
- package/src/Icon/Icon.svelte +91 -0
- package/src/IconPicker/IconPicker.svelte +177 -0
- package/src/IconSideNav/IconSideNav.svelte +14 -0
- package/src/IconSideNav/IconSideNavItem.svelte +56 -0
- package/src/InlineAlert/InlineAlert.svelte +60 -0
- package/src/Label/Label.svelte +29 -0
- package/src/Layout/Layout.svelte +94 -0
- package/src/Layout/Page.svelte +32 -0
- package/src/Link/Link.svelte +24 -0
- package/src/List/List.svelte +28 -0
- package/src/List/ListItem.svelte +98 -0
- package/src/Markdown/MarkdownEditor.svelte +60 -0
- package/src/Markdown/MarkdownViewer.svelte +70 -0
- package/src/Markdown/SpectrumMDE.svelte +184 -0
- package/src/Menu/Item.svelte +96 -0
- package/src/Menu/Menu.svelte +7 -0
- package/src/Menu/Menu.svench +19 -0
- package/src/Menu/Section.svelte +10 -0
- package/src/Menu/Separator.svelte +1 -0
- package/src/Modal/Content.svelte +6 -0
- package/src/Modal/CustomContent.svelte +38 -0
- package/src/Modal/Modal.svelte +165 -0
- package/src/Modal/Modal.svench +117 -0
- package/src/Modal/ModalContent.svelte +190 -0
- package/src/Modal/QuizModal.svelte +54 -0
- package/src/Notification/Notification.svelte +70 -0
- package/src/Notification/NotificationDisplay.svelte +43 -0
- package/src/Pagination/Pagination.svelte +57 -0
- package/src/Popover/Popover.svelte +78 -0
- package/src/Popover/Popover.svench +121 -0
- package/src/ProgressBar/ProgressBar.svelte +67 -0
- package/src/ProgressCircle/ProgressCircle.svelte +62 -0
- package/src/SideNavigation/Item.svelte +61 -0
- package/src/SideNavigation/Navigation.svelte +12 -0
- package/src/StatusLight/StatusLight.svelte +80 -0
- package/src/Stores/Notifications.svench.svx +78 -0
- package/src/Stores/banner.js +65 -0
- package/src/Stores/notifications.js +84 -0
- package/src/Table/ArrayRenderer.svelte +17 -0
- package/src/Table/AttachmentRenderer.svelte +67 -0
- package/src/Table/BoldRenderer.svelte +15 -0
- package/src/Table/BooleanRenderer.svelte +42 -0
- package/src/Table/CellRenderer.svelte +69 -0
- package/src/Table/CodeRenderer.svelte +14 -0
- package/src/Table/DateTimeRenderer.svelte +29 -0
- package/src/Table/InternalRenderer.svelte +24 -0
- package/src/Table/RelationshipRenderer.svelte +40 -0
- package/src/Table/SelectEditRenderer.svelte +28 -0
- package/src/Table/StringRenderer.svelte +14 -0
- package/src/Table/Table.svelte +635 -0
- package/src/Table/index.js +1 -0
- package/src/Tabs/Tab.svelte +88 -0
- package/src/Tabs/Tabs.svelte +130 -0
- package/src/Tags/Tag.svelte +43 -0
- package/src/Tags/Tags.svelte +7 -0
- package/src/Tooltip/Tooltip.svelte +34 -0
- package/src/Tooltip/TooltipWrapper.svelte +60 -0
- package/src/TreeView/Item.svelte +41 -0
- package/src/TreeView/Tree.svelte +16 -0
- package/src/Typography/Body.svelte +21 -0
- package/src/Typography/Code.svelte +10 -0
- package/src/Typography/Detail.svelte +19 -0
- package/src/Typography/Heading.svelte +17 -0
- package/src/bbui.css +96 -0
- package/src/context.js +3 -0
- package/src/helpers.js +134 -0
- package/src/index.js +98 -12
- package/src/spectrum-icons-rollup.js +31 -0
- package/src/spectrum-icons-vite.js +31 -0
- package/dist/bundle.css +0 -8
- package/dist/bundle.css.map +0 -22
- package/dist/index.js +0 -1275
- package/dist/index.mjs +0 -1260
- package/src/Branding/Budibase-logo.svelte +0 -68
- package/src/Branding/Logo.svelte +0 -16
- package/src/Branding/Logo.svench +0 -8
- package/src/Form/Button.svelte +0 -131
- package/src/Form/Button.svench +0 -49
- package/src/Form/Input.svench +0 -8
- package/src/Form/Select.svench +0 -8
- package/src/Form/TextArea.svench +0 -8
- package/src/Links/Home.svelte +0 -49
- package/src/Links/Home.svench +0 -19
- package/src/List/Items/DetailSummary.svelte +0 -66
- package/src/List/Items/DetailSummary.svench +0 -15
- package/src/Switcher/Switcher.svelte +0 -39
- package/src/Switcher/Switcher.svench +0 -25
- package/src/actions/autoresize_textarea.js +0 -14
- package/src/icons/Contribution.svelte +0 -14
- package/src/index.svench.svx +0 -35
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import "@spectrum-css/inputgroup/dist/index-vars.css"
|
|
3
|
+
import "@spectrum-css/popover/dist/index-vars.css"
|
|
4
|
+
import "@spectrum-css/menu/dist/index-vars.css"
|
|
5
|
+
import { fly } from "svelte/transition"
|
|
6
|
+
import { createEventDispatcher } from "svelte"
|
|
7
|
+
import clickOutside from "../../Actions/click_outside"
|
|
8
|
+
|
|
9
|
+
export let inputValue
|
|
10
|
+
export let dropdownValue
|
|
11
|
+
export let id = null
|
|
12
|
+
export let inputType = "text"
|
|
13
|
+
export let placeholder = "Choose an option or type"
|
|
14
|
+
export let disabled = false
|
|
15
|
+
export let readonly = false
|
|
16
|
+
export let updateOnChange = true
|
|
17
|
+
export let error = null
|
|
18
|
+
export let options = []
|
|
19
|
+
export let getOptionLabel = option => extractProperty(option, "label")
|
|
20
|
+
export let getOptionValue = option => extractProperty(option, "value")
|
|
21
|
+
|
|
22
|
+
export let isOptionSelected = () => false
|
|
23
|
+
|
|
24
|
+
const dispatch = createEventDispatcher()
|
|
25
|
+
let open = false
|
|
26
|
+
let focus = false
|
|
27
|
+
|
|
28
|
+
$: fieldText = getFieldText(dropdownValue, options, placeholder)
|
|
29
|
+
|
|
30
|
+
const getFieldText = (dropdownValue, options, placeholder) => {
|
|
31
|
+
// Always use placeholder if no value
|
|
32
|
+
if (dropdownValue == null || dropdownValue === "") {
|
|
33
|
+
return placeholder || "Choose an option or type"
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Wait for options to load if there is a value but no options
|
|
37
|
+
if (!options?.length) {
|
|
38
|
+
return ""
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Render the label if the selected option is found, otherwise raw value
|
|
42
|
+
const selected = options.find(
|
|
43
|
+
option => getOptionValue(option) === dropdownValue
|
|
44
|
+
)
|
|
45
|
+
return selected ? getOptionLabel(selected) : dropdownValue
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const updateValue = newValue => {
|
|
49
|
+
if (readonly) {
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
dispatch("change", newValue)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const onFocus = () => {
|
|
56
|
+
if (readonly) {
|
|
57
|
+
return
|
|
58
|
+
}
|
|
59
|
+
focus = true
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const onBlur = event => {
|
|
63
|
+
if (readonly) {
|
|
64
|
+
return
|
|
65
|
+
}
|
|
66
|
+
focus = false
|
|
67
|
+
updateValue(event.target.value)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const onInput = event => {
|
|
71
|
+
if (readonly || !updateOnChange) {
|
|
72
|
+
return
|
|
73
|
+
}
|
|
74
|
+
updateValue(event.target.value)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const updateValueOnEnter = event => {
|
|
78
|
+
if (readonly) {
|
|
79
|
+
return
|
|
80
|
+
}
|
|
81
|
+
if (event.key === "Enter") {
|
|
82
|
+
updateValue(event.target.value)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const onClick = () => {
|
|
87
|
+
dispatch("click")
|
|
88
|
+
if (readonly) {
|
|
89
|
+
return
|
|
90
|
+
}
|
|
91
|
+
open = true
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const onPick = newValue => {
|
|
95
|
+
dispatch("pick", newValue)
|
|
96
|
+
open = false
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const extractProperty = (value, property) => {
|
|
100
|
+
if (value && typeof value === "object") {
|
|
101
|
+
return value[property]
|
|
102
|
+
}
|
|
103
|
+
return value
|
|
104
|
+
}
|
|
105
|
+
</script>
|
|
106
|
+
|
|
107
|
+
<div
|
|
108
|
+
class="spectrum-InputGroup"
|
|
109
|
+
class:is-invalid={!!error}
|
|
110
|
+
class:is-disabled={disabled}
|
|
111
|
+
>
|
|
112
|
+
<div
|
|
113
|
+
class="spectrum-Textfield spectrum-InputGroup-textfield"
|
|
114
|
+
class:is-invalid={!!error}
|
|
115
|
+
class:is-disabled={disabled}
|
|
116
|
+
class:is-focused={focus}
|
|
117
|
+
>
|
|
118
|
+
{#if error}
|
|
119
|
+
<svg
|
|
120
|
+
class="spectrum-Icon spectrum-Icon--sizeM spectrum-Textfield-validationIcon"
|
|
121
|
+
focusable="false"
|
|
122
|
+
aria-hidden="true"
|
|
123
|
+
>
|
|
124
|
+
<use xlink:href="#spectrum-icon-18-Alert" />
|
|
125
|
+
</svg>
|
|
126
|
+
{/if}
|
|
127
|
+
|
|
128
|
+
<input
|
|
129
|
+
{id}
|
|
130
|
+
on:click
|
|
131
|
+
on:blur
|
|
132
|
+
on:focus
|
|
133
|
+
on:input
|
|
134
|
+
on:keyup
|
|
135
|
+
on:blur={onBlur}
|
|
136
|
+
on:focus={onFocus}
|
|
137
|
+
on:input={onInput}
|
|
138
|
+
on:keyup={updateValueOnEnter}
|
|
139
|
+
value={inputValue || ""}
|
|
140
|
+
placeholder={placeholder || ""}
|
|
141
|
+
{disabled}
|
|
142
|
+
{readonly}
|
|
143
|
+
{inputType}
|
|
144
|
+
class="spectrum-Textfield-input spectrum-InputGroup-input"
|
|
145
|
+
/>
|
|
146
|
+
</div>
|
|
147
|
+
<div style="width: 30%">
|
|
148
|
+
<button
|
|
149
|
+
{id}
|
|
150
|
+
class="spectrum-Picker spectrum-Picker--sizeM override-borders"
|
|
151
|
+
{disabled}
|
|
152
|
+
class:is-open={open}
|
|
153
|
+
aria-haspopup="listbox"
|
|
154
|
+
on:mousedown={onClick}
|
|
155
|
+
>
|
|
156
|
+
<span class="spectrum-Picker-label">
|
|
157
|
+
<div>
|
|
158
|
+
{fieldText}
|
|
159
|
+
</div></span
|
|
160
|
+
>
|
|
161
|
+
<svg
|
|
162
|
+
class="spectrum-Icon spectrum-UIIcon-ChevronDown100 spectrum-Picker-menuIcon"
|
|
163
|
+
focusable="false"
|
|
164
|
+
aria-hidden="true"
|
|
165
|
+
>
|
|
166
|
+
<use xlink:href="#spectrum-css-icon-Chevron100" />
|
|
167
|
+
</svg>
|
|
168
|
+
</button>
|
|
169
|
+
{#if open}
|
|
170
|
+
<div
|
|
171
|
+
use:clickOutside={() => (open = false)}
|
|
172
|
+
transition:fly|local={{ y: -20, duration: 200 }}
|
|
173
|
+
class="spectrum-Popover spectrum-Popover--bottom spectrum-Picker-popover is-open"
|
|
174
|
+
>
|
|
175
|
+
<ul class="spectrum-Menu" role="listbox">
|
|
176
|
+
{#each options as option, idx}
|
|
177
|
+
<li
|
|
178
|
+
class="spectrum-Menu-item"
|
|
179
|
+
class:is-selected={isOptionSelected(getOptionValue(option, idx))}
|
|
180
|
+
role="option"
|
|
181
|
+
aria-selected="true"
|
|
182
|
+
tabindex="0"
|
|
183
|
+
on:click={() => onPick(getOptionValue(option, idx))}
|
|
184
|
+
>
|
|
185
|
+
<span class="spectrum-Menu-itemLabel">
|
|
186
|
+
{getOptionLabel(option, idx)}
|
|
187
|
+
</span>
|
|
188
|
+
<svg
|
|
189
|
+
class="spectrum-Icon spectrum-UIIcon-Checkmark100 spectrum-Menu-checkmark spectrum-Menu-itemIcon"
|
|
190
|
+
focusable="false"
|
|
191
|
+
aria-hidden="true"
|
|
192
|
+
>
|
|
193
|
+
<use xlink:href="#spectrum-css-icon-Checkmark100" />
|
|
194
|
+
</svg>
|
|
195
|
+
</li>
|
|
196
|
+
{/each}
|
|
197
|
+
</ul>
|
|
198
|
+
</div>
|
|
199
|
+
{/if}
|
|
200
|
+
</div>
|
|
201
|
+
</div>
|
|
202
|
+
|
|
203
|
+
<style>
|
|
204
|
+
.spectrum-InputGroup {
|
|
205
|
+
min-width: 0;
|
|
206
|
+
width: 100%;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.spectrum-InputGroup-input {
|
|
210
|
+
border-right-width: 1px;
|
|
211
|
+
}
|
|
212
|
+
.spectrum-Textfield {
|
|
213
|
+
width: 100%;
|
|
214
|
+
}
|
|
215
|
+
.spectrum-Textfield-input {
|
|
216
|
+
width: 0;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.override-borders {
|
|
220
|
+
border-top-left-radius: 0px;
|
|
221
|
+
border-bottom-left-radius: 0px;
|
|
222
|
+
}
|
|
223
|
+
.spectrum-Popover {
|
|
224
|
+
max-height: 240px;
|
|
225
|
+
z-index: 999;
|
|
226
|
+
top: 100%;
|
|
227
|
+
}
|
|
228
|
+
</style>
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import Picker from "./Picker.svelte"
|
|
3
|
+
import { createEventDispatcher } from "svelte"
|
|
4
|
+
|
|
5
|
+
export let value = []
|
|
6
|
+
export let id = null
|
|
7
|
+
export let placeholder = null
|
|
8
|
+
export let disabled = false
|
|
9
|
+
export let error = null
|
|
10
|
+
export let options = []
|
|
11
|
+
export let getOptionLabel = option => option
|
|
12
|
+
export let getOptionValue = option => option
|
|
13
|
+
export let readonly = false
|
|
14
|
+
export let autocomplete = false
|
|
15
|
+
export let sort = false
|
|
16
|
+
export let autoWidth = false
|
|
17
|
+
|
|
18
|
+
const dispatch = createEventDispatcher()
|
|
19
|
+
$: selectedLookupMap = getSelectedLookupMap(value)
|
|
20
|
+
$: optionLookupMap = getOptionLookupMap(options)
|
|
21
|
+
$: fieldText = getFieldText(value, optionLookupMap, placeholder)
|
|
22
|
+
$: isOptionSelected = optionValue => selectedLookupMap[optionValue] === true
|
|
23
|
+
$: toggleOption = makeToggleOption(selectedLookupMap, value)
|
|
24
|
+
|
|
25
|
+
const getFieldText = (value, map, placeholder) => {
|
|
26
|
+
if (Array.isArray(value) && value.length > 0) {
|
|
27
|
+
if (!map) {
|
|
28
|
+
return ""
|
|
29
|
+
}
|
|
30
|
+
const vals = value.map(option => map[option] || option).join(", ")
|
|
31
|
+
return `(${value.length}) ${vals}`
|
|
32
|
+
} else {
|
|
33
|
+
return placeholder || "Choose some options"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const getSelectedLookupMap = value => {
|
|
38
|
+
let map = {}
|
|
39
|
+
if (Array.isArray(value) && value.length > 0) {
|
|
40
|
+
value.forEach(option => {
|
|
41
|
+
if (option) {
|
|
42
|
+
map[option] = true
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
return map
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const getOptionLookupMap = options => {
|
|
50
|
+
let map = null
|
|
51
|
+
if (options?.length) {
|
|
52
|
+
map = {}
|
|
53
|
+
options.forEach((option, idx) => {
|
|
54
|
+
const optionValue = getOptionValue(option, idx)
|
|
55
|
+
if (optionValue != null) {
|
|
56
|
+
map[optionValue] = getOptionLabel(option, idx) || ""
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
}
|
|
60
|
+
return map
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const makeToggleOption = (map, value) => {
|
|
64
|
+
return optionValue => {
|
|
65
|
+
if (map[optionValue]) {
|
|
66
|
+
const filtered = value.filter(option => option !== optionValue)
|
|
67
|
+
dispatch("change", filtered)
|
|
68
|
+
} else {
|
|
69
|
+
dispatch("change", [...value, optionValue])
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
</script>
|
|
74
|
+
|
|
75
|
+
<Picker
|
|
76
|
+
{id}
|
|
77
|
+
{error}
|
|
78
|
+
{disabled}
|
|
79
|
+
{readonly}
|
|
80
|
+
{fieldText}
|
|
81
|
+
{options}
|
|
82
|
+
isPlaceholder={!value?.length}
|
|
83
|
+
{autocomplete}
|
|
84
|
+
{isOptionSelected}
|
|
85
|
+
{getOptionLabel}
|
|
86
|
+
{getOptionValue}
|
|
87
|
+
onSelectOption={toggleOption}
|
|
88
|
+
{sort}
|
|
89
|
+
{autoWidth}
|
|
90
|
+
/>
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import "@spectrum-css/picker/dist/index-vars.css"
|
|
3
|
+
import "@spectrum-css/popover/dist/index-vars.css"
|
|
4
|
+
import "@spectrum-css/menu/dist/index-vars.css"
|
|
5
|
+
import { fly } from "svelte/transition"
|
|
6
|
+
import { createEventDispatcher } from "svelte"
|
|
7
|
+
import clickOutside from "../../Actions/click_outside"
|
|
8
|
+
import Search from "./Search.svelte"
|
|
9
|
+
import Icon from "../../Icon/Icon.svelte"
|
|
10
|
+
import StatusLight from "../../StatusLight/StatusLight.svelte"
|
|
11
|
+
|
|
12
|
+
export let id = null
|
|
13
|
+
export let disabled = false
|
|
14
|
+
export let error = null
|
|
15
|
+
export let fieldText = ""
|
|
16
|
+
export let fieldIcon = ""
|
|
17
|
+
export let fieldColour = ""
|
|
18
|
+
export let isPlaceholder = false
|
|
19
|
+
export let placeholderOption = null
|
|
20
|
+
export let options = []
|
|
21
|
+
export let isOptionSelected = () => false
|
|
22
|
+
export let onSelectOption = () => {}
|
|
23
|
+
export let getOptionLabel = option => option
|
|
24
|
+
export let getOptionValue = option => option
|
|
25
|
+
export let getOptionIcon = () => null
|
|
26
|
+
export let getOptionColour = () => null
|
|
27
|
+
export let open = false
|
|
28
|
+
export let readonly = false
|
|
29
|
+
export let quiet = false
|
|
30
|
+
export let autoWidth = false
|
|
31
|
+
export let autocomplete = false
|
|
32
|
+
export let sort = false
|
|
33
|
+
|
|
34
|
+
const dispatch = createEventDispatcher()
|
|
35
|
+
let searchTerm = null
|
|
36
|
+
|
|
37
|
+
$: sortedOptions = getSortedOptions(options, getOptionLabel, sort)
|
|
38
|
+
$: filteredOptions = getFilteredOptions(
|
|
39
|
+
sortedOptions,
|
|
40
|
+
searchTerm,
|
|
41
|
+
getOptionLabel
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
const onClick = () => {
|
|
45
|
+
dispatch("click")
|
|
46
|
+
if (readonly) {
|
|
47
|
+
return
|
|
48
|
+
}
|
|
49
|
+
searchTerm = null
|
|
50
|
+
open = !open
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const getSortedOptions = (options, getLabel, sort) => {
|
|
54
|
+
if (!options?.length || !Array.isArray(options)) {
|
|
55
|
+
return []
|
|
56
|
+
}
|
|
57
|
+
if (!sort) {
|
|
58
|
+
return options
|
|
59
|
+
}
|
|
60
|
+
return options.sort((a, b) => {
|
|
61
|
+
const labelA = getLabel(a)
|
|
62
|
+
const labelB = getLabel(b)
|
|
63
|
+
return labelA > labelB ? 1 : -1
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const getFilteredOptions = (options, term, getLabel) => {
|
|
68
|
+
if (autocomplete && term) {
|
|
69
|
+
const lowerCaseTerm = term.toLowerCase()
|
|
70
|
+
return options.filter(option => {
|
|
71
|
+
return `${getLabel(option)}`.toLowerCase().includes(lowerCaseTerm)
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
return options
|
|
75
|
+
}
|
|
76
|
+
</script>
|
|
77
|
+
|
|
78
|
+
<div use:clickOutside={() => (open = false)}>
|
|
79
|
+
<button
|
|
80
|
+
{id}
|
|
81
|
+
class="spectrum-Picker spectrum-Picker--sizeM"
|
|
82
|
+
class:spectrum-Picker--quiet={quiet}
|
|
83
|
+
{disabled}
|
|
84
|
+
class:is-invalid={!!error}
|
|
85
|
+
class:is-open={open}
|
|
86
|
+
aria-haspopup="listbox"
|
|
87
|
+
on:mousedown={onClick}
|
|
88
|
+
>
|
|
89
|
+
{#if fieldIcon}
|
|
90
|
+
<span class="option-extra">
|
|
91
|
+
<Icon name={fieldIcon} />
|
|
92
|
+
</span>
|
|
93
|
+
{/if}
|
|
94
|
+
{#if fieldColour}
|
|
95
|
+
<span class="option-extra">
|
|
96
|
+
<StatusLight square color={fieldColour} />
|
|
97
|
+
</span>
|
|
98
|
+
{/if}
|
|
99
|
+
<span
|
|
100
|
+
class="spectrum-Picker-label"
|
|
101
|
+
class:is-placeholder={isPlaceholder}
|
|
102
|
+
class:auto-width={autoWidth}
|
|
103
|
+
>
|
|
104
|
+
{fieldText}
|
|
105
|
+
</span>
|
|
106
|
+
{#if error}
|
|
107
|
+
<svg
|
|
108
|
+
class="spectrum-Icon spectrum-Icon--sizeM spectrum-Picker-validationIcon"
|
|
109
|
+
focusable="false"
|
|
110
|
+
aria-hidden="true"
|
|
111
|
+
aria-label="Folder"
|
|
112
|
+
>
|
|
113
|
+
<use xlink:href="#spectrum-icon-18-Alert" />
|
|
114
|
+
</svg>
|
|
115
|
+
{/if}
|
|
116
|
+
<svg
|
|
117
|
+
class="spectrum-Icon spectrum-UIIcon-ChevronDown100 spectrum-Picker-menuIcon"
|
|
118
|
+
focusable="false"
|
|
119
|
+
aria-hidden="true"
|
|
120
|
+
>
|
|
121
|
+
<use xlink:href="#spectrum-css-icon-Chevron100" />
|
|
122
|
+
</svg>
|
|
123
|
+
</button>
|
|
124
|
+
{#if open}
|
|
125
|
+
<div
|
|
126
|
+
transition:fly|local={{ y: -20, duration: 200 }}
|
|
127
|
+
class="spectrum-Popover spectrum-Popover--bottom spectrum-Picker-popover is-open"
|
|
128
|
+
class:auto-width={autoWidth}
|
|
129
|
+
>
|
|
130
|
+
{#if autocomplete}
|
|
131
|
+
<Search
|
|
132
|
+
value={searchTerm}
|
|
133
|
+
on:change={event => (searchTerm = event.detail)}
|
|
134
|
+
{disabled}
|
|
135
|
+
placeholder="Search"
|
|
136
|
+
/>
|
|
137
|
+
{/if}
|
|
138
|
+
<ul class="spectrum-Menu" role="listbox">
|
|
139
|
+
{#if placeholderOption}
|
|
140
|
+
<li
|
|
141
|
+
class="spectrum-Menu-item placeholder"
|
|
142
|
+
class:is-selected={isPlaceholder}
|
|
143
|
+
role="option"
|
|
144
|
+
aria-selected="true"
|
|
145
|
+
tabindex="0"
|
|
146
|
+
on:click={() => onSelectOption(null)}
|
|
147
|
+
>
|
|
148
|
+
<span class="spectrum-Menu-itemLabel">{placeholderOption}</span>
|
|
149
|
+
<svg
|
|
150
|
+
class="spectrum-Icon spectrum-UIIcon-Checkmark100 spectrum-Menu-checkmark spectrum-Menu-itemIcon"
|
|
151
|
+
focusable="false"
|
|
152
|
+
aria-hidden="true"
|
|
153
|
+
>
|
|
154
|
+
<use xlink:href="#spectrum-css-icon-Checkmark100" />
|
|
155
|
+
</svg>
|
|
156
|
+
</li>
|
|
157
|
+
{/if}
|
|
158
|
+
{#if filteredOptions.length}
|
|
159
|
+
{#each filteredOptions as option, idx}
|
|
160
|
+
<li
|
|
161
|
+
class="spectrum-Menu-item"
|
|
162
|
+
class:is-selected={isOptionSelected(getOptionValue(option, idx))}
|
|
163
|
+
role="option"
|
|
164
|
+
aria-selected="true"
|
|
165
|
+
tabindex="0"
|
|
166
|
+
on:click={() => onSelectOption(getOptionValue(option, idx))}
|
|
167
|
+
>
|
|
168
|
+
{#if getOptionIcon(option, idx)}
|
|
169
|
+
<span class="option-extra">
|
|
170
|
+
<Icon name={getOptionIcon(option, idx)} />
|
|
171
|
+
</span>
|
|
172
|
+
{/if}
|
|
173
|
+
{#if getOptionColour(option, idx)}
|
|
174
|
+
<span class="option-extra">
|
|
175
|
+
<StatusLight square color={getOptionColour(option, idx)} />
|
|
176
|
+
</span>
|
|
177
|
+
{/if}
|
|
178
|
+
<span class="spectrum-Menu-itemLabel">
|
|
179
|
+
{getOptionLabel(option, idx)}
|
|
180
|
+
</span>
|
|
181
|
+
<svg
|
|
182
|
+
class="spectrum-Icon spectrum-UIIcon-Checkmark100 spectrum-Menu-checkmark spectrum-Menu-itemIcon"
|
|
183
|
+
focusable="false"
|
|
184
|
+
aria-hidden="true"
|
|
185
|
+
>
|
|
186
|
+
<use xlink:href="#spectrum-css-icon-Checkmark100" />
|
|
187
|
+
</svg>
|
|
188
|
+
</li>
|
|
189
|
+
{/each}
|
|
190
|
+
{/if}
|
|
191
|
+
</ul>
|
|
192
|
+
</div>
|
|
193
|
+
{/if}
|
|
194
|
+
</div>
|
|
195
|
+
|
|
196
|
+
<style>
|
|
197
|
+
.spectrum-Popover {
|
|
198
|
+
max-height: 240px;
|
|
199
|
+
z-index: 999;
|
|
200
|
+
top: 100%;
|
|
201
|
+
}
|
|
202
|
+
.spectrum-Popover:not(.auto-width) {
|
|
203
|
+
width: 100%;
|
|
204
|
+
}
|
|
205
|
+
.spectrum-Popover.auto-width :global(.spectrum-Menu-itemLabel) {
|
|
206
|
+
white-space: nowrap;
|
|
207
|
+
}
|
|
208
|
+
.spectrum-Picker {
|
|
209
|
+
width: 100%;
|
|
210
|
+
box-shadow: none;
|
|
211
|
+
}
|
|
212
|
+
.spectrum-Picker-label.auto-width {
|
|
213
|
+
margin-right: var(--spacing-xs);
|
|
214
|
+
}
|
|
215
|
+
.spectrum-Picker-label:not(.auto-width) {
|
|
216
|
+
overflow: hidden;
|
|
217
|
+
text-overflow: ellipsis;
|
|
218
|
+
white-space: nowrap;
|
|
219
|
+
width: 0;
|
|
220
|
+
}
|
|
221
|
+
.placeholder {
|
|
222
|
+
font-style: italic;
|
|
223
|
+
}
|
|
224
|
+
.spectrum-Picker-label.auto-width.is-placeholder {
|
|
225
|
+
padding-right: 2px;
|
|
226
|
+
}
|
|
227
|
+
.auto-width .spectrum-Menu-item {
|
|
228
|
+
padding-right: var(--spacing-xl);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/* Icon and colour alignment */
|
|
232
|
+
.spectrum-Menu-checkmark {
|
|
233
|
+
align-self: center;
|
|
234
|
+
margin-top: 0;
|
|
235
|
+
}
|
|
236
|
+
.option-extra {
|
|
237
|
+
padding-right: 8px;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.spectrum-Popover :global(.spectrum-Search) {
|
|
241
|
+
margin-top: -1px;
|
|
242
|
+
margin-left: -1px;
|
|
243
|
+
width: calc(100% + 2px);
|
|
244
|
+
}
|
|
245
|
+
.spectrum-Popover :global(.spectrum-Search input) {
|
|
246
|
+
height: auto;
|
|
247
|
+
border-bottom-left-radius: 0;
|
|
248
|
+
border-bottom-right-radius: 0;
|
|
249
|
+
padding-top: var(--spectrum-global-dimension-size-100);
|
|
250
|
+
padding-bottom: var(--spectrum-global-dimension-size-100);
|
|
251
|
+
}
|
|
252
|
+
.spectrum-Popover :global(.spectrum-Search .spectrum-ClearButton) {
|
|
253
|
+
right: 1px;
|
|
254
|
+
top: 2px;
|
|
255
|
+
}
|
|
256
|
+
.spectrum-Popover :global(.spectrum-Search .spectrum-Textfield-icon) {
|
|
257
|
+
top: 9px;
|
|
258
|
+
}
|
|
259
|
+
</style>
|