@budibase/bbui 3.5.3 → 3.6.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/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.5.3",
4
+ "version": "3.6.0",
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": "0f586f33c25c04b35a7dc72b7217fdbaa3e843c0"
102
+ "gitHead": "fcc8291c1f2968ee7fd17bd47ee6ca19181a14a7"
103
103
  }
@@ -1,25 +1,26 @@
1
- <script>
1
+ <script lang="ts">
2
2
  import { setContext, getContext } from "svelte"
3
3
  import Popover from "../Popover/Popover.svelte"
4
4
  import Menu from "../Menu/Menu.svelte"
5
+ import type { PopoverAlignment } from "../constants"
5
6
 
6
- export let disabled = false
7
- export let align = "left"
8
- export let portalTarget
9
- export let openOnHover = false
10
- export let animate
11
- export let offset
7
+ export let disabled: boolean = false
8
+ export let align: `${PopoverAlignment}` = "left"
9
+ export let portalTarget: string | undefined = undefined
10
+ export let openOnHover: boolean = false
11
+ export let animate: boolean | undefined = true
12
+ export let offset: number | undefined = undefined
12
13
 
13
14
  const actionMenuContext = getContext("actionMenu")
14
15
 
15
- let anchor
16
- let dropdown
17
- let timeout
16
+ let anchor: HTMLElement | undefined
17
+ let dropdown: Popover
18
+ let timeout: ReturnType<typeof setTimeout>
18
19
 
19
20
  // This is needed because display: contents is considered "invisible".
20
21
  // It should only ever be an action button, so should be fine.
21
- function getAnchor(node) {
22
- anchor = node.firstChild
22
+ function getAnchor(node: HTMLDivElement) {
23
+ anchor = (node.firstChild as HTMLElement) ?? undefined
23
24
  }
24
25
 
25
26
  export const show = () => {
@@ -37,7 +38,7 @@
37
38
  actionMenuContext?.hide()
38
39
  }
39
40
 
40
- const openMenu = event => {
41
+ const openMenu = (event: Event) => {
41
42
  if (!disabled) {
42
43
  event.stopPropagation()
43
44
  show()
@@ -14,7 +14,7 @@
14
14
  export let url = ""
15
15
  export let disabled = false
16
16
  export let initials = "JD"
17
- export let color = null
17
+ export let color = ""
18
18
 
19
19
  const DefaultColor = "#3aab87"
20
20
 
@@ -1,4 +1,4 @@
1
- <script>
1
+ <script lang="ts">
2
2
  import Popover from "../Popover/Popover.svelte"
3
3
  import Layout from "../Layout/Layout.svelte"
4
4
  import { createEventDispatcher } from "svelte"
@@ -11,15 +11,17 @@
11
11
  getThemeClassNames,
12
12
  DefaultAppTheme,
13
13
  } from "@budibase/shared-core"
14
+ import type { Theme } from "@budibase/types"
15
+ import type { PopoverAlignment } from "../constants"
14
16
 
15
- export let value
16
- export let size = "M"
17
- export let spectrumTheme
18
- export let offset
19
- export let align
17
+ export let value: string | undefined = undefined
18
+ export let size: "S" | "M" | "L" = "M"
19
+ export let spectrumTheme: Theme | undefined = undefined
20
+ export let offset: number | undefined = undefined
21
+ export let align: PopoverAlignment | undefined = undefined
20
22
 
21
- let dropdown
22
- let preview
23
+ let dropdown: Popover | undefined
24
+ let preview: HTMLElement | undefined
23
25
 
24
26
  $: customValue = getCustomValue(value)
25
27
  $: checkColor = getCheckColor(value)
@@ -28,23 +30,7 @@
28
30
  const dispatch = createEventDispatcher()
29
31
  const categories = [
30
32
  {
31
- label: "Theme",
32
- colors: [
33
- "gray-50",
34
- "gray-75",
35
- "gray-100",
36
- "gray-200",
37
- "gray-300",
38
- "gray-400",
39
- "gray-500",
40
- "gray-600",
41
- "gray-700",
42
- "gray-800",
43
- "gray-900",
44
- ],
45
- },
46
- {
47
- label: "Colors",
33
+ label: "Theme colors",
48
34
  colors: [
49
35
  "red-100",
50
36
  "orange-100",
@@ -91,13 +77,56 @@
91
77
  "indigo-700",
92
78
  "magenta-700",
93
79
 
80
+ "gray-50",
81
+ "gray-75",
82
+ "gray-100",
83
+ "gray-200",
84
+ "gray-300",
85
+ "gray-400",
86
+ "gray-500",
87
+ "gray-600",
88
+ "gray-700",
89
+ "gray-800",
90
+ "gray-900",
91
+ ],
92
+ },
93
+ {
94
+ label: "Static colors",
95
+ colors: [
96
+ "static-red-400",
97
+ "static-orange-400",
98
+ "static-yellow-400",
99
+ "static-green-400",
100
+ "static-seafoam-400",
101
+ "static-blue-400",
102
+ "static-indigo-400",
103
+ "static-magenta-400",
104
+
105
+ "static-red-800",
106
+ "static-orange-800",
107
+ "static-yellow-800",
108
+ "static-green-800",
109
+ "static-seafoam-800",
110
+ "static-blue-800",
111
+ "static-indigo-800",
112
+ "static-magenta-800",
113
+
114
+ "static-red-1200",
115
+ "static-orange-1200",
116
+ "static-yellow-1200",
117
+ "static-green-1200",
118
+ "static-seafoam-1200",
119
+ "static-blue-1200",
120
+ "static-indigo-1200",
121
+ "static-magenta-1200",
122
+
94
123
  "static-white",
95
124
  "static-black",
96
125
  ],
97
126
  },
98
127
  ]
99
128
 
100
- const getThemeClasses = theme => {
129
+ const getThemeClasses = (theme: Theme | undefined) => {
101
130
  if (!theme) {
102
131
  return ""
103
132
  }
@@ -105,12 +134,12 @@
105
134
  return getThemeClassNames(theme)
106
135
  }
107
136
 
108
- const onChange = value => {
137
+ const onChange = (value: string | null) => {
109
138
  dispatch("change", value)
110
- dropdown.hide()
139
+ dropdown?.hide()
111
140
  }
112
141
 
113
- const getCustomValue = value => {
142
+ const getCustomValue = (value: string | undefined) => {
114
143
  if (!value) {
115
144
  return value
116
145
  }
@@ -125,11 +154,11 @@
125
154
  return found ? null : value
126
155
  }
127
156
 
128
- const prettyPrint = color => {
157
+ const prettyPrint = (color: string) => {
129
158
  return capitalise(color.split("-").join(" "))
130
159
  }
131
160
 
132
- const getCheckColor = value => {
161
+ const getCheckColor = (value: string | undefined) => {
133
162
  // Use dynamic color for theme grays
134
163
  if (value?.includes("-gray-")) {
135
164
  return /^.*(gray-(50|75|100|200|300|400|500))\)$/.test(value)
@@ -137,10 +166,13 @@
137
166
  : "var(--spectrum-global-color-gray-50)"
138
167
  }
139
168
 
140
- // Use contrasating check for the dim colours
169
+ // Use contrasting check for the dim colours
141
170
  if (value?.includes("-100")) {
142
171
  return "var(--spectrum-global-color-gray-900)"
143
172
  }
173
+ if (value?.includes("-1200") || value?.includes("-800")) {
174
+ return "var(--spectrum-global-color-static-gray-50)"
175
+ }
144
176
 
145
177
  // Use black check for static white
146
178
  if (value?.includes("static-black")) {
@@ -157,7 +189,7 @@
157
189
  bind:this={preview}
158
190
  class="preview size--{size || 'M'}"
159
191
  on:click={() => {
160
- dropdown.toggle()
192
+ dropdown?.toggle()
161
193
  }}
162
194
  >
163
195
  <div
@@ -169,7 +201,7 @@
169
201
 
170
202
  <!-- svelte-ignore a11y-no-static-element-interactions -->
171
203
  <!-- svelte-ignore a11y-click-events-have-key-events -->
172
- <Popover bind:this={dropdown} anchor={preview} maxHeight={320} {offset} {align}>
204
+ <Popover bind:this={dropdown} anchor={preview} maxHeight={350} {offset} {align}>
173
205
  <Layout paddingX="XL" paddingY="L">
174
206
  <div class="container">
175
207
  {#each categories as category}
@@ -1,43 +1,47 @@
1
- <script>
1
+ <script lang="ts">
2
2
  import ActionButton from "../../ActionButton/ActionButton.svelte"
3
3
  import { uuid } from "../../helpers"
4
4
  import Icon from "../../Icon/Icon.svelte"
5
5
  import { createEventDispatcher } from "svelte"
6
6
 
7
- export let value = null
8
- export let title = "Upload file"
9
- export let disabled = false
10
- export let allowClear = null
11
- export let extensions = null
12
- export let handleFileTooLarge = null
13
- export let fileSizeLimit = BYTES_IN_MB * 20
14
- export let id = null
15
- export let previewUrl = null
7
+ const BYTES_IN_MB = 1000000
8
+
9
+ export let value: File | undefined = undefined
10
+ export let title: string = "Upload file"
11
+ export let disabled: boolean = false
12
+ export let allowClear: boolean | undefined = undefined
13
+ export let extensions: string[] | undefined = undefined
14
+ export let handleFileTooLarge: ((_file: File) => void) | undefined = undefined
15
+ export let fileSizeLimit: number = BYTES_IN_MB * 20
16
+ export let id: string | undefined = undefined
17
+ export let previewUrl: string | undefined = undefined
16
18
 
17
19
  const fieldId = id || uuid()
18
20
  const BYTES_IN_KB = 1000
19
- const BYTES_IN_MB = 1000000
20
21
 
21
22
  const dispatch = createEventDispatcher()
22
23
 
23
- let fileInput
24
+ let fileInput: HTMLInputElement | undefined
24
25
 
25
26
  $: inputAccept = Array.isArray(extensions) ? extensions.join(",") : "*"
26
27
 
27
- async function processFile(targetFile) {
28
- if (handleFileTooLarge && targetFile?.size >= fileSizeLimit) {
29
- handleFileTooLarge(targetFile)
30
- return
28
+ async function processFile(targetFile: File | undefined) {
29
+ if (targetFile) {
30
+ if (handleFileTooLarge && targetFile.size >= fileSizeLimit) {
31
+ handleFileTooLarge(targetFile)
32
+ return
33
+ }
34
+ dispatch("change", targetFile)
31
35
  }
32
- dispatch("change", targetFile)
33
36
  }
34
37
 
35
- function handleFile(evt) {
36
- processFile(evt.target.files[0])
38
+ function handleFile(evt: Event) {
39
+ const target = evt.target as HTMLInputElement
40
+ processFile(target.files?.[0])
37
41
  }
38
42
 
39
43
  function clearFile() {
40
- dispatch("change", null)
44
+ dispatch("change", undefined)
41
45
  }
42
46
  </script>
43
47
 
@@ -75,7 +79,9 @@
75
79
  {/if}
76
80
  </div>
77
81
  {/if}
78
- <ActionButton {disabled} on:click={fileInput.click()}>{title}</ActionButton>
82
+ <ActionButton {disabled} on:click={() => fileInput?.click()}>
83
+ {title}
84
+ </ActionButton>
79
85
  </div>
80
86
 
81
87
  <style>
@@ -20,7 +20,7 @@
20
20
  export let searchTerm: string | null = null
21
21
  export let customPopoverHeight: string | undefined = undefined
22
22
  export let open: boolean = false
23
- export let loading: boolean
23
+ export let loading: boolean = false
24
24
  export let onOptionMouseenter = () => {}
25
25
  export let onOptionMouseleave = () => {}
26
26
 
@@ -1,24 +1,31 @@
1
1
  <script lang="ts">
2
2
  import "@spectrum-css/textfield/dist/index-vars.css"
3
3
  import { createEventDispatcher } from "svelte"
4
- import type { FocusEventHandler } from "svelte/elements"
5
4
 
6
- export let value: string | null = null
7
- export let placeholder: string | null = null
8
- export let disabled = false
9
- export let readonly = false
10
- export let id: string | null = null
11
- export let height: number | null = null
12
- export let minHeight: number | null = null
5
+ export let value: string | undefined = ""
6
+ export let placeholder: string | undefined = undefined
7
+ export let disabled: boolean = false
8
+ export let readonly: boolean = false
9
+ export let id: string | undefined = undefined
10
+ export let height: string | number | undefined = undefined
11
+ export let minHeight: string | number | undefined = undefined
13
12
  export let align = null
13
+ export let updateOnChange: boolean = false
14
+
15
+ export const getCaretPosition = () => ({
16
+ start: textarea.selectionStart,
17
+ end: textarea.selectionEnd,
18
+ })
19
+
20
+ const dispatch = createEventDispatcher()
14
21
 
15
22
  let isFocused = false
16
23
  let textarea: HTMLTextAreaElement
17
- const dispatch = createEventDispatcher<{ change: string }>()
18
- const onChange: FocusEventHandler<HTMLTextAreaElement> = event => {
19
- dispatch("change", event.currentTarget.value)
20
- isFocused = false
21
- }
24
+ let scrollable = false
25
+
26
+ $: heightString = getStyleString("height", height)
27
+ $: minHeightString = getStyleString("min-height", minHeight)
28
+ $: dispatch("scrollable", scrollable)
22
29
 
23
30
  export function focus() {
24
31
  textarea.focus()
@@ -28,18 +35,38 @@
28
35
  return textarea.value
29
36
  }
30
37
 
31
- const getStyleString = (attribute: string, value: number | null) => {
32
- if (!attribute || value == null) {
38
+ const onBlur = () => {
39
+ isFocused = false
40
+ updateValue()
41
+ }
42
+
43
+ const onChange = () => {
44
+ scrollable = textarea.clientHeight < textarea.scrollHeight
45
+ if (!updateOnChange) {
46
+ return
47
+ }
48
+ updateValue()
49
+ }
50
+
51
+ const updateValue = () => {
52
+ if (readonly || disabled) {
53
+ return
54
+ }
55
+ dispatch("change", textarea.value)
56
+ }
57
+
58
+ const getStyleString = (
59
+ attribute: string,
60
+ value: string | number | undefined
61
+ ) => {
62
+ if (value == null) {
33
63
  return ""
34
64
  }
35
- if (typeof value === "number" && isNaN(value)) {
65
+ if (typeof value !== "number" || isNaN(value)) {
36
66
  return `${attribute}:${value};`
37
67
  }
38
68
  return `${attribute}:${value}px;`
39
69
  }
40
-
41
- $: heightString = getStyleString("height", height)
42
- $: minHeightString = getStyleString("min-height", minHeight)
43
70
  </script>
44
71
 
45
72
  <div
@@ -57,8 +84,10 @@
57
84
  {disabled}
58
85
  {readonly}
59
86
  {id}
87
+ on:input={onChange}
60
88
  on:focus={() => (isFocused = true)}
61
- on:blur={onChange}
89
+ on:blur={onBlur}
90
+ on:blur
62
91
  on:keypress
63
92
  >{value || ""}</textarea>
64
93
  </div>
@@ -3,7 +3,7 @@
3
3
  import DatePicker from "./Core/DatePicker/DatePicker.svelte"
4
4
  import { createEventDispatcher } from "svelte"
5
5
 
6
- export let value = null
6
+ export let value = undefined
7
7
  export let label = null
8
8
  export let labelPosition = "above"
9
9
  export let disabled = false
@@ -1,23 +1,23 @@
1
- <script>
1
+ <script lang="ts">
2
2
  import Field from "./Field.svelte"
3
3
  import { CoreFile } from "./Core"
4
4
  import { createEventDispatcher } from "svelte"
5
5
 
6
- export let label = null
7
- export let labelPosition = "above"
8
- export let disabled = false
9
- export let allowClear = null
10
- export let handleFileTooLarge = () => {}
11
- export let previewUrl = null
12
- export let extensions = null
13
- export let error = null
14
- export let title = null
15
- export let value = null
16
- export let tooltip = null
17
- export let helpText = null
6
+ export let label: string | undefined = undefined
7
+ export let labelPosition: string = "above"
8
+ export let disabled: boolean = false
9
+ export let allowClear: boolean | undefined = undefined
10
+ export let handleFileTooLarge: (_file: File) => void = () => {}
11
+ export let previewUrl: string | undefined = undefined
12
+ export let extensions: string[] | undefined = undefined
13
+ export let error: string | undefined = undefined
14
+ export let title: string | undefined = undefined
15
+ export let value: File | undefined = undefined
16
+ export let tooltip: string | undefined = undefined
17
+ export let helpText: string | undefined = undefined
18
18
 
19
19
  const dispatch = createEventDispatcher()
20
- const onChange = e => {
20
+ const onChange = (e: CustomEvent) => {
21
21
  value = e.detail
22
22
  dispatch("change", e.detail)
23
23
  }
@@ -25,7 +25,6 @@
25
25
 
26
26
  <Field {helpText} {label} {labelPosition} {error} {tooltip}>
27
27
  <CoreFile
28
- {error}
29
28
  {disabled}
30
29
  {allowClear}
31
30
  {title}
@@ -1,29 +1,31 @@
1
- <script>
1
+ <script lang="ts" generics="Option">
2
2
  import { createEventDispatcher } from "svelte"
3
3
  import Multiselect from "./Core/Multiselect.svelte"
4
4
  import Field from "./Field.svelte"
5
5
 
6
- export let value = []
7
- export let label = null
6
+ export let value: string[] | string = []
7
+ export let label: string | undefined = undefined
8
8
  export let disabled = false
9
9
  export let readonly = false
10
10
  export let labelPosition = "above"
11
- export let error = null
12
- export let placeholder = null
13
- export let options = []
14
- export let getOptionLabel = option => option
15
- export let getOptionValue = option => option
11
+ export let error: string | undefined = undefined
12
+ export let placeholder: string | undefined = undefined
13
+ export let options: Option[] = []
14
+ export let getOptionLabel = (option: Option) => option
15
+ export let getOptionValue = (option: Option) => option
16
16
  export let sort = false
17
17
  export let autoWidth = false
18
18
  export let autocomplete = false
19
- export let searchTerm = null
20
- export let customPopoverHeight
21
- export let helpText = null
19
+ export let searchTerm: string | undefined = undefined
20
+ export let customPopoverHeight: string | undefined = undefined
21
+ export let helpText: string | undefined = undefined
22
22
  export let onOptionMouseenter = () => {}
23
23
  export let onOptionMouseleave = () => {}
24
24
 
25
+ $: arrayValue = value && !Array.isArray(value) ? [value] : (value as string[])
26
+
25
27
  const dispatch = createEventDispatcher()
26
- const onChange = e => {
28
+ const onChange = (e: any) => {
27
29
  value = e.detail
28
30
  dispatch("change", e.detail)
29
31
  }
@@ -31,10 +33,9 @@
31
33
 
32
34
  <Field {helpText} {label} {labelPosition} {error}>
33
35
  <Multiselect
34
- {error}
35
36
  {disabled}
36
37
  {readonly}
37
- {value}
38
+ bind:value={arrayValue}
38
39
  {options}
39
40
  {placeholder}
40
41
  {sort}
@@ -1,9 +1,4 @@
1
- <script lang="ts" context="module">
2
- type O = any
3
- type V = any
4
- </script>
5
-
6
- <script lang="ts">
1
+ <script lang="ts" generics="O extends any,V">
7
2
  import Field from "./Field.svelte"
8
3
  import Select from "./Core/Select.svelte"
9
4
  import { createEventDispatcher } from "svelte"
@@ -22,9 +17,11 @@
22
17
  export let getOptionValue = (option: O, _index?: number) =>
23
18
  extractProperty(option, "value")
24
19
  export let getOptionSubtitle = (option: O, _index?: number) =>
25
- option?.subtitle
26
- export let getOptionIcon = (option: O, _index?: number) => option?.icon
27
- export let getOptionColour = (option: O, _index?: number) => option?.colour
20
+ (option as any)?.subtitle
21
+ export let getOptionIcon = (option: O, _index?: number) =>
22
+ (option as any)?.icon
23
+ export let getOptionColour = (option: O, _index?: number) =>
24
+ (option as any)?.colour
28
25
  export let useOptionIconImage = false
29
26
  export let isOptionEnabled:
30
27
  | ((_option: O, _index?: number) => boolean)
@@ -3,10 +3,10 @@
3
3
  import Switch from "./Core/Switch.svelte"
4
4
  import { createEventDispatcher } from "svelte"
5
5
 
6
- export let value = null
6
+ export let value = undefined
7
7
  export let label = null
8
8
  export let labelPosition = "above"
9
- export let text = null
9
+ export let text = undefined
10
10
  export let disabled = false
11
11
  export let error = null
12
12
  export let helpText = null
@@ -89,7 +89,7 @@
89
89
  /* Selection is only meant for standalone list items (non stacked) so we just set a fixed border radius */
90
90
  .list-item.selected {
91
91
  background-color: var(--spectrum-global-color-blue-100);
92
- border-color: var(--spectrum-global-color-blue-100);
92
+ border: none;
93
93
  }
94
94
  .list-item.selected:after {
95
95
  content: "";
@@ -100,7 +100,7 @@
100
100
  pointer-events: none;
101
101
  top: 0;
102
102
  left: 0;
103
- border-radius: 4px;
103
+ border-radius: inherit;
104
104
  box-sizing: border-box;
105
105
  z-index: 1;
106
106
  opacity: 0.5;
@@ -1,8 +1,8 @@
1
1
  <script lang="ts">
2
2
  import SpectrumMDE from "./SpectrumMDE.svelte"
3
3
 
4
- export let value: string | null = null
5
- export let height: string | null = null
4
+ export let value: string | undefined = undefined
5
+ export let height: string | undefined = undefined
6
6
 
7
7
  let mde: any
8
8
 
@@ -40,6 +40,7 @@
40
40
  border: none;
41
41
  background: transparent;
42
42
  padding: 0;
43
+ color: inherit;
43
44
  }
44
45
  .markdown-viewer :global(.EasyMDEContainer) {
45
46
  background: transparent;
package/src/bbui.css CHANGED
@@ -11,6 +11,16 @@
11
11
  --bb-forest-green: #053835;
12
12
  --bb-beige: #f6efea;
13
13
 
14
+ /* Custom spectrum additions */
15
+ --spectrum-global-color-static-red-1200: #740000;
16
+ --spectrum-global-color-static-orange-1200: #612300;
17
+ --spectrum-global-color-static-yellow-1200: #483300;
18
+ --spectrum-global-color-static-green-1200: #053f27;
19
+ --spectrum-global-color-static-seafoam-1200: #123c3a;
20
+ --spectrum-global-color-static-blue-1200: #003571;
21
+ --spectrum-global-color-static-indigo-1200: #262986;
22
+ --spectrum-global-color-static-magenta-1200: #700037;
23
+
14
24
  --grey-1: #fafafa;
15
25
  --grey-2: #f5f5f5;
16
26
  --grey-3: #eeeeee;
@@ -0,0 +1,8 @@
1
+ import { ActionMenu } from "./types"
2
+
3
+ declare module "svelte" {
4
+ export function getContext(key: "actionMenu"): ActionMenu | undefined
5
+ }
6
+
7
+ export const Modal = "bbui-modal"
8
+ export const PopoverRoot = "bbui-popover-root"
@@ -0,0 +1,3 @@
1
+ export interface ActionMenu {
2
+ hide: () => void
3
+ }