@budibase/bbui 1.2.1 → 1.2.4

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.
Files changed (152) hide show
  1. package/LICENSE +375 -0
  2. package/README.md +19 -17
  3. package/dist/bbui.es.js +210 -0
  4. package/dist/bbui.es.js.map +1 -0
  5. package/package.json +71 -26
  6. package/src/ActionButton/ActionButton.svelte +102 -0
  7. package/src/ActionGroup/ActionGroup.svelte +26 -0
  8. package/src/ActionMenu/ActionMenu.svelte +44 -0
  9. package/src/Actions/ClickOutside.svench.svx +30 -0
  10. package/src/Actions/PositionDropdown.svench.svx +81 -0
  11. package/src/Actions/autoresize_textarea.js +14 -0
  12. package/src/Actions/click_outside.js +18 -0
  13. package/src/Actions/position_dropdown.js +66 -0
  14. package/src/Avatar/Avatar.svelte +62 -0
  15. package/src/Badge/Badge.svelte +29 -0
  16. package/src/Banner/Banner.svelte +72 -0
  17. package/src/Banner/BannerDisplay.svelte +31 -0
  18. package/src/Button/Button.svelte +114 -0
  19. package/src/Button/Button.svench +138 -0
  20. package/src/ButtonGroup/ButtonGroup.svelte +30 -0
  21. package/src/ClearButton/ClearButton.svelte +19 -0
  22. package/src/ColorPicker/ColorPicker.svelte +297 -0
  23. package/src/DetailSummary/DetailSummary.svelte +83 -0
  24. package/src/Divider/Divider.svelte +28 -0
  25. package/src/Drawer/Drawer.svelte +113 -0
  26. package/src/Drawer/Drawer.svench +42 -0
  27. package/src/Drawer/DrawerContent.svelte +46 -0
  28. package/src/Form/Checkbox.svelte +23 -0
  29. package/src/Form/Combobox.svelte +45 -0
  30. package/src/Form/Core/Checkbox.svelte +69 -0
  31. package/src/Form/Core/CheckboxGroup.svelte +68 -0
  32. package/src/Form/Core/Combobox.svelte +142 -0
  33. package/src/Form/Core/DatePicker.svelte +242 -0
  34. package/src/Form/Core/Dropzone.svelte +438 -0
  35. package/src/Form/Core/InputDropdown.svelte +228 -0
  36. package/src/Form/Core/Multiselect.svelte +90 -0
  37. package/src/Form/Core/Picker.svelte +259 -0
  38. package/src/Form/Core/PickerDropdown.svelte +436 -0
  39. package/src/Form/Core/RadioGroup.svelte +47 -0
  40. package/src/Form/Core/RichTextField.svelte +42 -0
  41. package/src/Form/Core/Search.svelte +105 -0
  42. package/src/Form/Core/Select.svelte +75 -0
  43. package/src/Form/Core/Slider.svelte +86 -0
  44. package/src/Form/Core/Stepper.svelte +172 -0
  45. package/src/Form/Core/Switch.svelte +37 -0
  46. package/src/Form/Core/TextArea.svelte +78 -0
  47. package/src/Form/Core/TextField.svelte +119 -0
  48. package/src/Form/Core/index.js +15 -0
  49. package/src/Form/DatePicker.svelte +37 -0
  50. package/src/Form/Dropzone.svelte +40 -0
  51. package/src/Form/Field.svelte +42 -0
  52. package/src/Form/FieldLabel.svelte +32 -0
  53. package/src/Form/Input.svelte +40 -45
  54. package/src/Form/InputDropdown.svelte +55 -0
  55. package/src/Form/Multiselect.svelte +40 -0
  56. package/src/Form/PickerDropdown.svelte +132 -0
  57. package/src/Form/RadioGroup.svelte +40 -0
  58. package/src/Form/RichTextField.svelte +36 -0
  59. package/src/Form/Search.svelte +36 -0
  60. package/src/Form/Select.svelte +48 -43
  61. package/src/Form/Slider.svelte +24 -0
  62. package/src/Form/Stepper.svelte +45 -0
  63. package/src/Form/TextArea.svelte +29 -44
  64. package/src/Form/Toggle.svelte +23 -0
  65. package/src/Icon/Icon.svelte +86 -0
  66. package/src/IconPicker/IconPicker.svelte +177 -0
  67. package/src/IconSideNav/IconSideNav.svelte +14 -0
  68. package/src/IconSideNav/IconSideNavItem.svelte +56 -0
  69. package/src/InlineAlert/InlineAlert.svelte +56 -0
  70. package/src/Label/Label.svelte +20 -0
  71. package/src/Layout/Layout.svelte +94 -0
  72. package/src/Layout/Page.svelte +32 -0
  73. package/src/Link/Link.svelte +22 -0
  74. package/src/List/List.svelte +28 -0
  75. package/src/List/ListItem.svelte +92 -0
  76. package/src/Markdown/MarkdownEditor.svelte +60 -0
  77. package/src/Markdown/MarkdownViewer.svelte +70 -0
  78. package/src/Markdown/SpectrumMDE.svelte +184 -0
  79. package/src/Menu/Item.svelte +45 -0
  80. package/src/Menu/Menu.svelte +7 -0
  81. package/src/Menu/Menu.svench +19 -0
  82. package/src/Menu/Section.svelte +10 -0
  83. package/src/Menu/Separator.svelte +1 -0
  84. package/src/Modal/Content.svelte +6 -0
  85. package/src/Modal/CustomContent.svelte +38 -0
  86. package/src/Modal/Modal.svelte +142 -0
  87. package/src/Modal/Modal.svench +117 -0
  88. package/src/Modal/ModalContent.svelte +190 -0
  89. package/src/Modal/QuizModal.svelte +54 -0
  90. package/src/Notification/Notification.svelte +70 -0
  91. package/src/Notification/NotificationDisplay.svelte +43 -0
  92. package/src/Pagination/Pagination.svelte +57 -0
  93. package/src/Popover/Popover.svelte +77 -0
  94. package/src/Popover/Popover.svench +121 -0
  95. package/src/ProgressBar/ProgressBar.svelte +54 -0
  96. package/src/ProgressCircle/ProgressCircle.svelte +62 -0
  97. package/src/SideNavigation/Item.svelte +47 -0
  98. package/src/SideNavigation/Navigation.svelte +12 -0
  99. package/src/StatusLight/StatusLight.svelte +80 -0
  100. package/src/Stores/Notifications.svench.svx +78 -0
  101. package/src/Stores/banner.js +37 -0
  102. package/src/Stores/notifications.js +84 -0
  103. package/src/Table/ArrayRenderer.svelte +17 -0
  104. package/src/Table/AttachmentRenderer.svelte +57 -0
  105. package/src/Table/BoldRenderer.svelte +15 -0
  106. package/src/Table/BooleanRenderer.svelte +42 -0
  107. package/src/Table/CellRenderer.svelte +69 -0
  108. package/src/Table/CodeRenderer.svelte +14 -0
  109. package/src/Table/DateTimeRenderer.svelte +29 -0
  110. package/src/Table/InternalRenderer.svelte +24 -0
  111. package/src/Table/RelationshipRenderer.svelte +40 -0
  112. package/src/Table/SelectEditRenderer.svelte +28 -0
  113. package/src/Table/StringRenderer.svelte +14 -0
  114. package/src/Table/Table.svelte +648 -0
  115. package/src/Table/index.js +1 -0
  116. package/src/Tabs/Tab.svelte +88 -0
  117. package/src/Tabs/Tabs.svelte +125 -0
  118. package/src/Tags/Tag.svelte +43 -0
  119. package/src/Tags/Tags.svelte +7 -0
  120. package/src/Tooltip/Tooltip.svelte +34 -0
  121. package/src/Tooltip/TooltipWrapper.svelte +60 -0
  122. package/src/TreeView/Item.svelte +41 -0
  123. package/src/TreeView/Tree.svelte +16 -0
  124. package/src/Typography/Body.svelte +21 -0
  125. package/src/Typography/Code.svelte +10 -0
  126. package/src/Typography/Detail.svelte +19 -0
  127. package/src/Typography/Heading.svelte +17 -0
  128. package/src/bbui.css +96 -0
  129. package/src/context.js +3 -0
  130. package/src/helpers.js +134 -0
  131. package/src/index.js +97 -11
  132. package/src/spectrum-icons-rollup.js +31 -0
  133. package/src/spectrum-icons-vite.js +31 -0
  134. package/dist/bundle.css +0 -7
  135. package/dist/bundle.css.map +0 -20
  136. package/dist/index.js +0 -1100
  137. package/dist/index.mjs +0 -1086
  138. package/src/Branding/Budibase-logo.svelte +0 -68
  139. package/src/Branding/Logo.svelte +0 -16
  140. package/src/Branding/Logo.svench +0 -8
  141. package/src/Form/Button.svelte +0 -131
  142. package/src/Form/Button.svench +0 -49
  143. package/src/Form/Input.svench +0 -8
  144. package/src/Form/Select.svench +0 -8
  145. package/src/Form/TextArea.svench +0 -8
  146. package/src/Links/Home.svelte +0 -49
  147. package/src/Links/Home.svench +0 -19
  148. package/src/List/Items/DetailSummary.svelte +0 -66
  149. package/src/List/Items/DetailSummary.svench +0 -15
  150. package/src/actions/autoresize_textarea.js +0 -14
  151. package/src/icons/Contribution.svelte +0 -14
  152. package/src/index.svench.svx +0 -35
@@ -0,0 +1,242 @@
1
+ <script>
2
+ import Flatpickr from "svelte-flatpickr"
3
+ import "flatpickr/dist/flatpickr.css"
4
+ import "@spectrum-css/inputgroup/dist/index-vars.css"
5
+ import "@spectrum-css/textfield/dist/index-vars.css"
6
+ import "@spectrum-css/picker/dist/index-vars.css"
7
+ import { createEventDispatcher } from "svelte"
8
+ import { uuid } from "../../helpers"
9
+
10
+ export let id = null
11
+ export let disabled = false
12
+ export let error = null
13
+ export let enableTime = true
14
+ export let value = null
15
+ export let placeholder = null
16
+ export let appendTo = undefined
17
+ export let timeOnly = false
18
+ export let ignoreTimezones = false
19
+
20
+ const dispatch = createEventDispatcher()
21
+ const flatpickrId = `${uuid()}-wrapper`
22
+ let open = false
23
+ let flatpickr, flatpickrOptions
24
+
25
+ const resolveTimeStamp = timestamp => {
26
+ let maskedDate = new Date(`0-${timestamp}`)
27
+
28
+ if (maskedDate instanceof Date && !isNaN(maskedDate.getTime())) {
29
+ return maskedDate
30
+ } else {
31
+ return null
32
+ }
33
+ }
34
+
35
+ $: flatpickrOptions = {
36
+ element: `#${flatpickrId}`,
37
+ enableTime: timeOnly || enableTime || false,
38
+ noCalendar: timeOnly || false,
39
+ altInput: true,
40
+ altFormat: timeOnly ? "H:i" : enableTime ? "F j Y, H:i" : "F j, Y",
41
+ wrap: true,
42
+ appendTo,
43
+ disableMobile: "true",
44
+ onReady: () => {
45
+ let timestamp = resolveTimeStamp(value)
46
+ if (timeOnly && timestamp) {
47
+ dispatch("change", timestamp.toISOString())
48
+ }
49
+ },
50
+ }
51
+
52
+ const handleChange = event => {
53
+ const [dates] = event.detail
54
+ const noTimezone = enableTime && !timeOnly && ignoreTimezones
55
+ let newValue = dates[0]
56
+ if (newValue) {
57
+ newValue = newValue.toISOString()
58
+ }
59
+
60
+ // If time only set date component to 2000-01-01
61
+ if (timeOnly) {
62
+ newValue = `2000-01-01T${newValue.split("T")[1]}`
63
+ }
64
+
65
+ // For date-only fields, construct a manual timestamp string without a time
66
+ // or time zone
67
+ else if (!enableTime) {
68
+ const year = dates[0].getFullYear()
69
+ const month = `${dates[0].getMonth() + 1}`.padStart(2, "0")
70
+ const day = `${dates[0].getDate()}`.padStart(2, "0")
71
+ newValue = `${year}-${month}-${day}T00:00:00.000`
72
+ }
73
+
74
+ // For non-timezone-aware fields, create an ISO 8601 timestamp of the exact
75
+ // time picked, without timezone
76
+ else if (noTimezone) {
77
+ const offset = dates[0].getTimezoneOffset() * 60000
78
+ newValue = new Date(dates[0].getTime() - offset)
79
+ .toISOString()
80
+ .slice(0, -1)
81
+ }
82
+
83
+ dispatch("change", newValue)
84
+ }
85
+
86
+ const clearDateOnBackspace = event => {
87
+ if (["Backspace", "Clear", "Delete"].includes(event.key)) {
88
+ dispatch("change", null)
89
+ flatpickr.close()
90
+ }
91
+ }
92
+
93
+ const onOpen = () => {
94
+ open = true
95
+ document.addEventListener("keyup", clearDateOnBackspace)
96
+ }
97
+
98
+ const onClose = () => {
99
+ open = false
100
+ document.removeEventListener("keyup", clearDateOnBackspace)
101
+
102
+ // Manually blur all input fields since flatpickr creates a second
103
+ // duplicate input field.
104
+ // We need to blur both because the focus styling does not get properly
105
+ // applied.
106
+ const els = document.querySelectorAll(`#${flatpickrId} input`)
107
+ els.forEach(el => el.blur())
108
+ }
109
+
110
+ const parseDate = val => {
111
+ if (!val) {
112
+ return null
113
+ }
114
+ let date
115
+ let time
116
+
117
+ // it is a string like 00:00:00, just time
118
+ let ts = resolveTimeStamp(val)
119
+
120
+ if (timeOnly && ts) {
121
+ date = ts
122
+ } else if (val instanceof Date) {
123
+ // Use real date obj if already parsed
124
+ date = val
125
+ } else if (isNaN(val)) {
126
+ // Treat as date string of some sort
127
+ date = new Date(val)
128
+ } else {
129
+ // Treat as numerical timestamp
130
+ date = new Date(parseInt(val))
131
+ }
132
+
133
+ time = date.getTime()
134
+ if (isNaN(time)) {
135
+ return null
136
+ }
137
+
138
+ // By rounding to the nearest second we avoid locking up in an endless
139
+ // loop in the builder, caused by potentially enriching {{ now }} to every
140
+ // millisecond.
141
+ return new Date(Math.floor(time / 1000) * 1000)
142
+ }
143
+ </script>
144
+
145
+ {#key timeOnly}
146
+ <Flatpickr
147
+ bind:flatpickr
148
+ value={parseDate(value)}
149
+ on:open={onOpen}
150
+ on:close={onClose}
151
+ options={flatpickrOptions}
152
+ on:change={handleChange}
153
+ element={`#${flatpickrId}`}
154
+ >
155
+ <div
156
+ id={flatpickrId}
157
+ class:is-disabled={disabled}
158
+ class:is-invalid={!!error}
159
+ class="flatpickr spectrum-InputGroup spectrum-Datepicker"
160
+ class:is-focused={open}
161
+ aria-readonly="false"
162
+ aria-required="false"
163
+ aria-haspopup="true"
164
+ >
165
+ <div
166
+ on:click={flatpickr?.open}
167
+ class="spectrum-Textfield spectrum-InputGroup-textfield"
168
+ class:is-disabled={disabled}
169
+ class:is-invalid={!!error}
170
+ >
171
+ {#if !!error}
172
+ <svg
173
+ class="spectrum-Icon spectrum-Icon--sizeM spectrum-Textfield-validationIcon"
174
+ focusable="false"
175
+ aria-hidden="true"
176
+ >
177
+ <use xlink:href="#spectrum-icon-18-Alert" />
178
+ </svg>
179
+ {/if}
180
+ <input
181
+ data-input
182
+ type="text"
183
+ class="spectrum-Textfield-input spectrum-InputGroup-input"
184
+ class:is-disabled={disabled}
185
+ {placeholder}
186
+ {id}
187
+ {value}
188
+ />
189
+ </div>
190
+ <button
191
+ type="button"
192
+ class="spectrum-Picker spectrum-Picker--sizeM spectrum-InputGroup-button"
193
+ tabindex="-1"
194
+ class:is-disabled={disabled}
195
+ class:is-invalid={!!error}
196
+ on:click={flatpickr?.open}
197
+ >
198
+ <svg
199
+ class="spectrum-Icon spectrum-Icon--sizeM"
200
+ focusable="false"
201
+ aria-hidden="true"
202
+ aria-label="Calendar"
203
+ >
204
+ <use xlink:href="#spectrum-icon-18-Calendar" />
205
+ </svg>
206
+ </button>
207
+ </div>
208
+ </Flatpickr>
209
+ {/key}
210
+ {#if open}
211
+ <div class="overlay" on:mousedown|self={flatpickr?.close} />
212
+ {/if}
213
+
214
+ <style>
215
+ .spectrum-Textfield-input {
216
+ pointer-events: none;
217
+ }
218
+ .spectrum-Textfield:not(.is-disabled):hover {
219
+ cursor: pointer;
220
+ }
221
+ .flatpickr {
222
+ width: 100%;
223
+ overflow: hidden;
224
+ }
225
+ .flatpickr .spectrum-Textfield {
226
+ width: 100%;
227
+ }
228
+ .overlay {
229
+ position: fixed;
230
+ top: 0;
231
+ left: 0;
232
+ width: 100vw;
233
+ height: 100vh;
234
+ z-index: 999;
235
+ }
236
+ :global(.flatpickr-calendar) {
237
+ font-family: "Source Sans Pro", sans-serif;
238
+ }
239
+ .is-disabled {
240
+ pointer-events: none !important;
241
+ }
242
+ </style>
@@ -0,0 +1,438 @@
1
+ <script>
2
+ import "@spectrum-css/dropzone/dist/index-vars.css"
3
+ import "@spectrum-css/typography/dist/index-vars.css"
4
+ import "@spectrum-css/illustratedmessage/dist/index-vars.css"
5
+ import { createEventDispatcher } from "svelte"
6
+ import { uuid } from "../../helpers"
7
+ import Icon from "../../Icon/Icon.svelte"
8
+ import Link from "../../Link/Link.svelte"
9
+ import Tag from "../../Tags/Tag.svelte"
10
+ import Tags from "../../Tags/Tags.svelte"
11
+
12
+ const BYTES_IN_KB = 1000
13
+ const BYTES_IN_MB = 1000000
14
+
15
+ export let value = []
16
+ export let id = null
17
+ export let disabled = false
18
+ export let fileSizeLimit = BYTES_IN_MB * 20
19
+ export let processFiles = null
20
+ export let handleFileTooLarge = null
21
+ export let handleTooManyFiles = null
22
+ export let gallery = true
23
+ export let error = null
24
+ export let fileTags = []
25
+ export let maximum = null
26
+ export let extensions = "*"
27
+
28
+ const dispatch = createEventDispatcher()
29
+ const imageExtensions = [
30
+ "png",
31
+ "tiff",
32
+ "gif",
33
+ "raw",
34
+ "jpg",
35
+ "jpeg",
36
+ "svg",
37
+ "bmp",
38
+ "jfif",
39
+ ]
40
+
41
+ const fieldId = id || uuid()
42
+ let selectedImageIdx = 0
43
+ let fileDragged = false
44
+ let selectedUrl
45
+ $: selectedImage = value?.[selectedImageIdx] ?? null
46
+ $: fileCount = value?.length ?? 0
47
+ $: isImage =
48
+ imageExtensions.includes(selectedImage?.extension?.toLowerCase()) ||
49
+ selectedImage?.type?.startsWith("image")
50
+
51
+ $: {
52
+ if (selectedImage?.url) {
53
+ selectedUrl = selectedImage?.url
54
+ } else if (selectedImage) {
55
+ try {
56
+ let reader = new FileReader()
57
+ reader.readAsDataURL(selectedImage)
58
+ reader.onload = e => {
59
+ selectedUrl = e.target.result
60
+ }
61
+ } catch (error) {
62
+ selectedUrl = null
63
+ }
64
+ }
65
+ }
66
+
67
+ async function processFileList(fileList) {
68
+ if (
69
+ handleFileTooLarge &&
70
+ Array.from(fileList).some(file => file.size >= fileSizeLimit)
71
+ ) {
72
+ handleFileTooLarge(fileSizeLimit, value)
73
+ return
74
+ }
75
+
76
+ const fileCount = fileList.length + value.length
77
+ if (handleTooManyFiles && maximum && fileCount > maximum) {
78
+ handleTooManyFiles(maximum)
79
+ return
80
+ }
81
+
82
+ if (processFiles) {
83
+ const processedFiles = await processFiles(fileList)
84
+ const newValue = [...value, ...processedFiles]
85
+ dispatch("change", newValue)
86
+ selectedImageIdx = newValue.length - 1
87
+ } else {
88
+ dispatch("change", fileList)
89
+ }
90
+ }
91
+
92
+ async function removeFile() {
93
+ dispatch(
94
+ "change",
95
+ value.filter((x, idx) => idx !== selectedImageIdx)
96
+ )
97
+ selectedImageIdx = 0
98
+ }
99
+
100
+ function navigateLeft() {
101
+ selectedImageIdx -= 1
102
+ }
103
+
104
+ function navigateRight() {
105
+ selectedImageIdx += 1
106
+ }
107
+
108
+ function handleFile(evt) {
109
+ processFileList(evt.target.files)
110
+ }
111
+
112
+ function handleDragOver(evt) {
113
+ evt.preventDefault()
114
+ fileDragged = true
115
+ }
116
+
117
+ function handleDragLeave(evt) {
118
+ evt.preventDefault()
119
+ fileDragged = false
120
+ }
121
+
122
+ function handleDrop(evt) {
123
+ evt.preventDefault()
124
+ processFileList(evt.dataTransfer.files)
125
+ fileDragged = false
126
+ }
127
+ </script>
128
+
129
+ <div class="container">
130
+ {#if selectedImage}
131
+ {#if gallery}
132
+ <div class="gallery">
133
+ <div class="title">
134
+ <div class="filename">
135
+ {#if selectedUrl}
136
+ <Link href={selectedUrl}>{selectedImage.name}</Link>
137
+ {:else}
138
+ {selectedImage.name}
139
+ {/if}
140
+ </div>
141
+ {#if selectedImage.size}
142
+ <div class="filesize">
143
+ {#if selectedImage.size <= BYTES_IN_MB}
144
+ {`${selectedImage.size / BYTES_IN_KB} KB`}
145
+ {:else}{`${selectedImage.size / BYTES_IN_MB} MB`}{/if}
146
+ </div>
147
+ {/if}
148
+ {#if !disabled}
149
+ <div class="delete-button" on:click={removeFile}>
150
+ <Icon name="Close" />
151
+ </div>
152
+ {/if}
153
+ </div>
154
+ {#if isImage}
155
+ <img alt="preview" src={selectedUrl} />
156
+ {:else}
157
+ <div class="placeholder">
158
+ <div class="extension">
159
+ {selectedImage.name || "Unknown file"}
160
+ </div>
161
+ <div>Preview not supported</div>
162
+ </div>
163
+ {/if}
164
+ <div
165
+ class="nav left"
166
+ class:visible={selectedImageIdx > 0}
167
+ on:click={navigateLeft}
168
+ >
169
+ <Icon name="ChevronLeft" />
170
+ </div>
171
+ <div
172
+ class="nav right"
173
+ class:visible={selectedImageIdx < fileCount - 1}
174
+ on:click={navigateRight}
175
+ >
176
+ <Icon name="ChevronRight" />
177
+ </div>
178
+ <div class="footer">File {selectedImageIdx + 1} of {fileCount}</div>
179
+ </div>
180
+ {:else if value?.length}
181
+ {#each value as file}
182
+ <div class="gallery">
183
+ <div class="title">
184
+ <div class="filename">{file.name}</div>
185
+ {#if file.size}
186
+ <div class="filesize">
187
+ {#if file.size <= BYTES_IN_MB}
188
+ {`${file.size / BYTES_IN_KB} KB`}
189
+ {:else}{`${file.size / BYTES_IN_MB} MB`}{/if}
190
+ </div>
191
+ {/if}
192
+ {#if !disabled}
193
+ <div class="delete-button" on:click={removeFile}>
194
+ <Icon name="Close" />
195
+ </div>
196
+ {/if}
197
+ </div>
198
+ </div>
199
+ {/each}
200
+ {/if}
201
+ {/if}
202
+ {#if !maximum || (maximum && value?.length < maximum)}
203
+ <div
204
+ class="spectrum-Dropzone"
205
+ class:is-invalid={!!error}
206
+ class:disabled
207
+ role="region"
208
+ tabindex="0"
209
+ on:dragover={handleDragOver}
210
+ on:dragleave={handleDragLeave}
211
+ on:dragenter={handleDragOver}
212
+ on:drop={handleDrop}
213
+ class:is-dragged={fileDragged}
214
+ >
215
+ <div class="spectrum-IllustratedMessage spectrum-IllustratedMessage--cta">
216
+ <input
217
+ id={fieldId}
218
+ {disabled}
219
+ type="file"
220
+ multiple
221
+ accept={extensions}
222
+ on:change={handleFile}
223
+ />
224
+ <svg
225
+ class="spectrum-IllustratedMessage-illustration"
226
+ width="125"
227
+ height="60"
228
+ viewBox="0 0 199 97.7"
229
+ >
230
+ <defs>
231
+ <style>
232
+ .cls-1,
233
+ .cls-2 {
234
+ fill: none;
235
+ stroke-linecap: round;
236
+ stroke-linejoin: round;
237
+ }
238
+ .cls-1 {
239
+ stroke-width: 3px;
240
+ }
241
+ .cls-2 {
242
+ stroke-width: 2px;
243
+ }
244
+ </style>
245
+ </defs>
246
+ <path
247
+ class="cls-1"
248
+ d="M110.53,85.66,100.26,95.89a1.09,1.09,0,0,1-1.52,0L88.47,85.66"
249
+ />
250
+ <line class="cls-1" x1="99.5" y1="95.5" x2="99.5" y2="58.5" />
251
+ <path class="cls-1" d="M105.5,73.5h19a2,2,0,0,0,2-2v-43" />
252
+ <path
253
+ class="cls-1"
254
+ d="M126.5,22.5h-19a2,2,0,0,1-2-2V1.5h-31a2,2,0,0,0-2,2v68a2,2,0,0,0,2,2h19"
255
+ />
256
+ <line class="cls-1" x1="105.5" y1="1.5" x2="126.5" y2="22.5" />
257
+ <path
258
+ class="cls-2"
259
+ d="M47.93,50.49a5,5,0,1,0-4.83-5A4.93,4.93,0,0,0,47.93,50.49Z"
260
+ />
261
+ <path
262
+ class="cls-2"
263
+ d="M36.6,65.93,42.05,60A2.06,2.06,0,0,1,45,60l12.68,13.2"
264
+ />
265
+ <path
266
+ class="cls-2"
267
+ d="M3.14,73.23,22.42,53.76a1.65,1.65,0,0,1,2.38,0l19.05,19.7"
268
+ />
269
+ <path
270
+ class="cls-1"
271
+ d="M139.5,36.5H196A1.49,1.49,0,0,1,197.5,38V72A1.49,1.49,0,0,1,196,73.5H141A1.49,1.49,0,0,1,139.5,72V32A1.49,1.49,0,0,1,141,30.5H154a2.43,2.43,0,0,1,1.67.66l6,5.66"
272
+ />
273
+ <rect
274
+ class="cls-1"
275
+ x="1.5"
276
+ y="34.5"
277
+ width="58"
278
+ height="39"
279
+ rx="2"
280
+ ry="2"
281
+ />
282
+ </svg>
283
+ <h2
284
+ class="spectrum-Heading spectrum-Heading--sizeL spectrum-Heading--light spectrum-IllustratedMessage-heading"
285
+ >
286
+ Drag and drop your file
287
+ </h2>
288
+ {#if !disabled}
289
+ <p
290
+ class="spectrum-Body spectrum-Body--sizeS spectrum-IllustratedMessage-description"
291
+ >
292
+ <label for={fieldId} class="spectrum-Link">
293
+ Select a file to upload
294
+ </label>
295
+ <br />
296
+ from your computer
297
+ </p>
298
+ {#if fileTags.length}
299
+ <Tags>
300
+ <div class="tags">
301
+ {#each fileTags as tag}
302
+ <div class="tag">
303
+ <Tag>
304
+ {tag}
305
+ </Tag>
306
+ </div>
307
+ {/each}
308
+ </div>
309
+ </Tags>
310
+ {/if}
311
+ {/if}
312
+ </div>
313
+ </div>
314
+ {/if}
315
+ </div>
316
+
317
+ <style>
318
+ .container {
319
+ --spectrum-dropzone-padding: var(--spectrum-global-dimension-size-400);
320
+ --spectrum-heading-l-text-size: var(
321
+ --spectrum-global-dimension-font-size-400
322
+ );
323
+ }
324
+
325
+ .gallery,
326
+ .spectrum-Dropzone {
327
+ user-select: none;
328
+ }
329
+ .spectrum-Dropzone.is-invalid {
330
+ border-color: var(--spectrum-global-color-red-400);
331
+ }
332
+ input[type="file"] {
333
+ display: none;
334
+ }
335
+
336
+ .gallery {
337
+ display: flex;
338
+ flex-direction: column;
339
+ justify-content: flex-start;
340
+ align-items: stretch;
341
+ background-color: var(--spectrum-global-color-gray-50);
342
+ color: var(--spectrum-alias-text-color);
343
+ font-size: var(--spectrum-alias-item-text-size-m);
344
+ box-sizing: border-box;
345
+ border: var(--spectrum-alias-border-size-thin)
346
+ var(--spectrum-alias-border-color) solid;
347
+ border-radius: var(--spectrum-alias-border-radius-regular);
348
+ padding: 10px;
349
+ margin-bottom: 10px;
350
+ position: relative;
351
+ }
352
+ .placeholder,
353
+ img {
354
+ height: 120px;
355
+ max-width: 100%;
356
+ object-fit: contain;
357
+ margin: 20px 30px;
358
+ }
359
+ .title {
360
+ display: flex;
361
+ flex-direction: row;
362
+ justify-content: flex-start;
363
+ align-items: center;
364
+ }
365
+ .filename {
366
+ flex: 1 1 auto;
367
+ overflow: hidden;
368
+ text-overflow: ellipsis;
369
+ white-space: nowrap;
370
+ width: 0;
371
+ margin-right: 10px;
372
+ user-select: all;
373
+ }
374
+ .placeholder {
375
+ display: flex;
376
+ flex-direction: column;
377
+ justify-content: center;
378
+ align-items: center;
379
+ text-align: center;
380
+ }
381
+ .extension {
382
+ color: var(--spectrum-global-color-gray-600);
383
+ text-transform: uppercase;
384
+ font-weight: 600;
385
+ margin-bottom: 5px;
386
+ user-select: all;
387
+ }
388
+
389
+ .nav {
390
+ padding: var(--spacing-xs);
391
+ position: absolute;
392
+ top: 50%;
393
+ border-radius: 5px;
394
+ display: none;
395
+ transition: all 0.3s;
396
+ }
397
+ .nav.visible {
398
+ display: block;
399
+ }
400
+ .nav:hover {
401
+ cursor: pointer;
402
+ color: var(--blue);
403
+ }
404
+ .left {
405
+ left: 5px;
406
+ }
407
+ .right {
408
+ right: 5px;
409
+ }
410
+ .delete-button {
411
+ transition: all 0.3s;
412
+ margin-left: 10px;
413
+ display: flex;
414
+ }
415
+ .delete-button:hover {
416
+ cursor: pointer;
417
+ color: var(--red);
418
+ }
419
+
420
+ .spectrum-Dropzone.disabled {
421
+ pointer-events: none;
422
+ background-color: var(--spectrum-global-color-gray-200);
423
+ }
424
+ .disabled .spectrum-Heading--sizeL {
425
+ color: var(--spectrum-alias-text-color-disabled);
426
+ }
427
+
428
+ .tags {
429
+ margin-top: 20px;
430
+ display: flex;
431
+ flex-wrap: wrap;
432
+ justify-content: center;
433
+ }
434
+
435
+ .tag {
436
+ margin-top: 8px;
437
+ }
438
+ </style>