@budibase/bbui 0.0.1
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 +42 -0
- package/dist/bbui.es.js +8 -0
- package/dist/bbui.es.js.map +1 -0
- package/package.json +94 -0
- package/src/Accordion/Accordion.svelte +58 -0
- package/src/ActionButton/ActionButton.svelte +132 -0
- package/src/ActionGroup/ActionGroup.svelte +26 -0
- package/src/ActionMenu/ActionMenu.svelte +43 -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 +76 -0
- package/src/Actions/position_dropdown.js +116 -0
- package/src/Avatar/Avatar.svelte +63 -0
- package/src/Badge/Badge.svelte +42 -0
- package/src/Banner/Banner.svelte +72 -0
- package/src/Banner/BannerDisplay.svelte +41 -0
- package/src/Button/Button.svelte +118 -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 +304 -0
- package/src/DetailSummary/DetailSummary.svelte +92 -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 +45 -0
- package/src/FancyForm/FancyButton.svelte +30 -0
- package/src/FancyForm/FancyButtonRadio.svelte +70 -0
- package/src/FancyForm/FancyCheckbox.svelte +53 -0
- package/src/FancyForm/FancyField.svelte +126 -0
- package/src/FancyForm/FancyFieldLabel.svelte +25 -0
- package/src/FancyForm/FancyForm.svelte +40 -0
- package/src/FancyForm/FancyInput.svelte +109 -0
- package/src/FancyForm/FancySelect.svelte +147 -0
- package/src/FancyForm/index.js +6 -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 +265 -0
- package/src/Form/Core/Dropzone.svelte +482 -0
- package/src/Form/Core/EnvDropdown.svelte +276 -0
- package/src/Form/Core/File.svelte +115 -0
- package/src/Form/Core/InputDropdown.svelte +235 -0
- package/src/Form/Core/Multiselect.svelte +99 -0
- package/src/Form/Core/Picker.svelte +314 -0
- package/src/Form/Core/PickerDropdown.svelte +431 -0
- package/src/Form/Core/RadioGroup.svelte +65 -0
- package/src/Form/Core/RichTextField.svelte +42 -0
- package/src/Form/Core/Search.svelte +105 -0
- package/src/Form/Core/Select.svelte +90 -0
- package/src/Form/Core/Slider.svelte +86 -0
- package/src/Form/Core/Stepper.svelte +172 -0
- package/src/Form/Core/Switch.svelte +35 -0
- package/src/Form/Core/TextArea.svelte +78 -0
- package/src/Form/Core/TextField.svelte +115 -0
- package/src/Form/Core/index.js +16 -0
- package/src/Form/DatePicker.svelte +46 -0
- package/src/Form/Dropzone.svelte +44 -0
- package/src/Form/EnvDropdown.svelte +50 -0
- package/src/Form/Field.svelte +42 -0
- package/src/Form/FieldLabel.svelte +32 -0
- package/src/Form/File.svelte +37 -0
- package/src/Form/Input.svelte +45 -0
- package/src/Form/InputDropdown.svelte +53 -0
- package/src/Form/Multiselect.svelte +49 -0
- package/src/Form/PickerDropdown.svelte +131 -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 +67 -0
- package/src/Form/Slider.svelte +24 -0
- package/src/Form/Stepper.svelte +45 -0
- package/src/Form/TextArea.svelte +34 -0
- package/src/Form/Toggle.svelte +22 -0
- package/src/Icon/Icon.svelte +94 -0
- package/src/Icon/IconAvatar.svelte +61 -0
- package/src/IconPicker/IconPicker.svelte +184 -0
- package/src/IconSideNav/IconSideNav.svelte +14 -0
- package/src/IconSideNav/IconSideNavItem.svelte +56 -0
- package/src/InlineAlert/InlineAlert.svelte +63 -0
- package/src/Input/CopyInput.svelte +59 -0
- package/src/Label/Label.svelte +31 -0
- package/src/Layout/Layout.svelte +94 -0
- package/src/Layout/Page.svelte +101 -0
- package/src/Link/Link.svelte +27 -0
- package/src/List/List.svelte +28 -0
- package/src/List/ListItem.svelte +93 -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 +94 -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 +37 -0
- package/src/Modal/Modal.svelte +178 -0
- package/src/Modal/Modal.svench +116 -0
- package/src/Modal/ModalContent.svelte +190 -0
- package/src/Modal/QuizModal.svelte +53 -0
- package/src/Notification/Notification.svelte +74 -0
- package/src/Notification/NotificationDisplay.svelte +43 -0
- package/src/Pagination/Pagination.svelte +57 -0
- package/src/Popover/Popover.svelte +95 -0
- package/src/Popover/Popover.svench +120 -0
- package/src/ProgressBar/ProgressBar.svelte +67 -0
- package/src/ProgressCircle/ProgressCircle.svelte +62 -0
- package/src/SideNavigation/Item.svelte +59 -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 +18 -0
- package/src/Table/AttachmentRenderer.svelte +73 -0
- package/src/Table/BoldRenderer.svelte +15 -0
- package/src/Table/BooleanRenderer.svelte +42 -0
- package/src/Table/CellRenderer.svelte +70 -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 +35 -0
- package/src/Table/SelectEditRenderer.svelte +28 -0
- package/src/Table/StringRenderer.svelte +22 -0
- package/src/Table/Table.svelte +657 -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 +17 -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 +22 -0
- package/src/Typography/Code.svelte +10 -0
- package/src/Typography/Detail.svelte +19 -0
- package/src/Typography/Heading.svelte +24 -0
- package/src/bbui.css +118 -0
- package/src/context.js +4 -0
- package/src/helpers.js +116 -0
- package/src/index.js +109 -0
- package/src/spectrum-icons-rollup.js +31 -0
- package/src/spectrum-icons-vite.js +31 -0
package/package.json
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@budibase/bbui",
|
|
3
|
+
"description": "A UI solution used in the different Budibase projects.",
|
|
4
|
+
"version": "0.0.1",
|
|
5
|
+
"license": "MPL-2.0",
|
|
6
|
+
"svelte": "src/index.js",
|
|
7
|
+
"module": "dist/bbui.es.js",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/bbui.es.js"
|
|
11
|
+
},
|
|
12
|
+
"./package.json": "./package.json",
|
|
13
|
+
"./spectrum-icons-rollup.js": "./src/spectrum-icons-rollup.js",
|
|
14
|
+
"./spectrum-icons-vite.js": "./src/spectrum-icons-vite.js"
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "rollup -c"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@rollup/plugin-commonjs": "^16.0.0",
|
|
21
|
+
"@rollup/plugin-json": "^4.1.0",
|
|
22
|
+
"@rollup/plugin-node-resolve": "^11.2.1",
|
|
23
|
+
"cross-env": "^7.0.2",
|
|
24
|
+
"nollup": "^0.14.1",
|
|
25
|
+
"postcss": "^8.2.9",
|
|
26
|
+
"rollup": "^2.45.2",
|
|
27
|
+
"rollup-plugin-postcss": "^4.0.0",
|
|
28
|
+
"rollup-plugin-svelte": "^7.1.0",
|
|
29
|
+
"rollup-plugin-terser": "^7.0.2",
|
|
30
|
+
"svelte": "^3.38.2"
|
|
31
|
+
},
|
|
32
|
+
"keywords": [
|
|
33
|
+
"svelte"
|
|
34
|
+
],
|
|
35
|
+
"files": [
|
|
36
|
+
"src",
|
|
37
|
+
"dist"
|
|
38
|
+
],
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@adobe/spectrum-css-workflow-icons": "1.2.1",
|
|
41
|
+
"@budibase/shared-core": "0.0.1",
|
|
42
|
+
"@budibase/string-templates": "0.0.1",
|
|
43
|
+
"@spectrum-css/accordion": "3.0.24",
|
|
44
|
+
"@spectrum-css/actionbutton": "1.0.1",
|
|
45
|
+
"@spectrum-css/actiongroup": "1.0.1",
|
|
46
|
+
"@spectrum-css/avatar": "3.0.2",
|
|
47
|
+
"@spectrum-css/button": "3.0.1",
|
|
48
|
+
"@spectrum-css/buttongroup": "3.0.2",
|
|
49
|
+
"@spectrum-css/checkbox": "3.0.2",
|
|
50
|
+
"@spectrum-css/dialog": "3.0.1",
|
|
51
|
+
"@spectrum-css/divider": "1.0.3",
|
|
52
|
+
"@spectrum-css/dropzone": "3.0.2",
|
|
53
|
+
"@spectrum-css/fieldgroup": "3.0.2",
|
|
54
|
+
"@spectrum-css/fieldlabel": "3.0.1",
|
|
55
|
+
"@spectrum-css/icon": "3.0.1",
|
|
56
|
+
"@spectrum-css/illustratedmessage": "3.0.2",
|
|
57
|
+
"@spectrum-css/inlinealert": "2.0.1",
|
|
58
|
+
"@spectrum-css/inputgroup": "3.0.2",
|
|
59
|
+
"@spectrum-css/label": "2.0.10",
|
|
60
|
+
"@spectrum-css/link": "3.1.1",
|
|
61
|
+
"@spectrum-css/menu": "3.0.1",
|
|
62
|
+
"@spectrum-css/modal": "3.0.1",
|
|
63
|
+
"@spectrum-css/pagination": "3.0.3",
|
|
64
|
+
"@spectrum-css/picker": "1.0.1",
|
|
65
|
+
"@spectrum-css/popover": "3.0.1",
|
|
66
|
+
"@spectrum-css/progressbar": "1.0.2",
|
|
67
|
+
"@spectrum-css/progresscircle": "1.0.2",
|
|
68
|
+
"@spectrum-css/radio": "3.0.2",
|
|
69
|
+
"@spectrum-css/search": "3.0.2",
|
|
70
|
+
"@spectrum-css/sidenav": "3.0.2",
|
|
71
|
+
"@spectrum-css/slider": "3.0.1",
|
|
72
|
+
"@spectrum-css/statuslight": "3.0.2",
|
|
73
|
+
"@spectrum-css/stepper": "3.0.3",
|
|
74
|
+
"@spectrum-css/switch": "1.0.2",
|
|
75
|
+
"@spectrum-css/table": "3.0.1",
|
|
76
|
+
"@spectrum-css/tabs": "3.2.12",
|
|
77
|
+
"@spectrum-css/tags": "3.0.2",
|
|
78
|
+
"@spectrum-css/textfield": "3.0.1",
|
|
79
|
+
"@spectrum-css/toast": "3.0.1",
|
|
80
|
+
"@spectrum-css/tooltip": "3.0.3",
|
|
81
|
+
"@spectrum-css/treeview": "3.0.2",
|
|
82
|
+
"@spectrum-css/typography": "3.0.1",
|
|
83
|
+
"@spectrum-css/underlay": "2.0.9",
|
|
84
|
+
"@spectrum-css/vars": "3.0.1",
|
|
85
|
+
"dayjs": "^1.10.4",
|
|
86
|
+
"easymde": "^2.16.1",
|
|
87
|
+
"svelte-flatpickr": "^3.3.2",
|
|
88
|
+
"svelte-portal": "^1.0.0"
|
|
89
|
+
},
|
|
90
|
+
"resolutions": {
|
|
91
|
+
"loader-utils": "1.4.1"
|
|
92
|
+
},
|
|
93
|
+
"gitHead": "365911a77f6365818fd82fe8e2fe7e2b5d9fc1b3"
|
|
94
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import "@spectrum-css/accordion"
|
|
3
|
+
|
|
4
|
+
export let itemName
|
|
5
|
+
export let initialOpen
|
|
6
|
+
export let header
|
|
7
|
+
|
|
8
|
+
let isOpen
|
|
9
|
+
|
|
10
|
+
function getOpenClass(isOpen) {
|
|
11
|
+
if (isOpen === undefined) {
|
|
12
|
+
isOpen = initialOpen
|
|
13
|
+
}
|
|
14
|
+
return isOpen ? "is-open" : ""
|
|
15
|
+
}
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<div class="spectrum-Accordion" role={itemName}>
|
|
19
|
+
<div class="spectrum-Accordion-item {getOpenClass(isOpen)}">
|
|
20
|
+
<h3 class="spectrum-Accordion-itemHeading">
|
|
21
|
+
<button
|
|
22
|
+
class="spectrum-Accordion-itemHeader"
|
|
23
|
+
type="button"
|
|
24
|
+
on:click={() => (isOpen = !isOpen)}
|
|
25
|
+
>
|
|
26
|
+
{header}
|
|
27
|
+
</button>
|
|
28
|
+
<svg
|
|
29
|
+
class="spectrum-Icon spectrum-UIIcon-ChevronRight100 spectrum-Accordion-itemIndicator"
|
|
30
|
+
focusable="false"
|
|
31
|
+
aria-hidden="true"
|
|
32
|
+
>
|
|
33
|
+
<use xlink:href="#spectrum-css-icon-Chevron100" />
|
|
34
|
+
</svg>
|
|
35
|
+
</h3>
|
|
36
|
+
<div class="spectrum-Accordion-itemContent" role={itemName}>
|
|
37
|
+
<slot />
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
<style>
|
|
43
|
+
.spectrum-Accordion {
|
|
44
|
+
margin-left: -20px;
|
|
45
|
+
}
|
|
46
|
+
.spectrum-Accordion-item {
|
|
47
|
+
border: none;
|
|
48
|
+
}
|
|
49
|
+
.spectrum-Accordion-itemContent {
|
|
50
|
+
width: 97%;
|
|
51
|
+
padding-left: 30px;
|
|
52
|
+
}
|
|
53
|
+
.spectrum-Accordion-itemHeader {
|
|
54
|
+
text-transform: none;
|
|
55
|
+
font-weight: bold;
|
|
56
|
+
font-size: 0.875rem;
|
|
57
|
+
}
|
|
58
|
+
</style>
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import "@spectrum-css/actionbutton/dist/index-vars.css"
|
|
3
|
+
import { createEventDispatcher } from "svelte"
|
|
4
|
+
import Tooltip from "../Tooltip/Tooltip.svelte"
|
|
5
|
+
import { fade } from "svelte/transition"
|
|
6
|
+
|
|
7
|
+
const dispatch = createEventDispatcher()
|
|
8
|
+
|
|
9
|
+
export let quiet = false
|
|
10
|
+
export let emphasized = false
|
|
11
|
+
export let selected = false
|
|
12
|
+
export let longPressable = false
|
|
13
|
+
export let disabled = false
|
|
14
|
+
export let icon = ""
|
|
15
|
+
export let size = "M"
|
|
16
|
+
export let active = false
|
|
17
|
+
export let fullWidth = false
|
|
18
|
+
export let noPadding = false
|
|
19
|
+
export let tooltip = ""
|
|
20
|
+
|
|
21
|
+
let showTooltip = false
|
|
22
|
+
|
|
23
|
+
function longPress(element) {
|
|
24
|
+
if (!longPressable) return
|
|
25
|
+
let timer
|
|
26
|
+
|
|
27
|
+
const listener = () => {
|
|
28
|
+
timer = setTimeout(() => {
|
|
29
|
+
dispatch("longpress")
|
|
30
|
+
}, 700)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
element.addEventListener("pointerdown", listener)
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
destroy() {
|
|
37
|
+
clearTimeout(timer)
|
|
38
|
+
element.removeEventListener("pointerdown", longPress)
|
|
39
|
+
},
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
</script>
|
|
43
|
+
|
|
44
|
+
<span
|
|
45
|
+
class="btn-wrap"
|
|
46
|
+
on:mouseover={() => (showTooltip = true)}
|
|
47
|
+
on:mouseleave={() => (showTooltip = false)}
|
|
48
|
+
on:focus={() => (showTooltip = true)}
|
|
49
|
+
>
|
|
50
|
+
<button
|
|
51
|
+
use:longPress
|
|
52
|
+
class:spectrum-ActionButton--quiet={quiet}
|
|
53
|
+
class:spectrum-ActionButton--emphasized={emphasized}
|
|
54
|
+
class:is-selected={selected}
|
|
55
|
+
class:noPadding
|
|
56
|
+
class:fullWidth
|
|
57
|
+
class="spectrum-ActionButton spectrum-ActionButton--size{size}"
|
|
58
|
+
class:active
|
|
59
|
+
{disabled}
|
|
60
|
+
on:longPress
|
|
61
|
+
on:click|preventDefault
|
|
62
|
+
>
|
|
63
|
+
{#if longPressable}
|
|
64
|
+
<svg
|
|
65
|
+
class="spectrum-Icon spectrum-UIIcon-CornerTriangle100 spectrum-ActionButton-hold"
|
|
66
|
+
focusable="false"
|
|
67
|
+
aria-hidden="true"
|
|
68
|
+
>
|
|
69
|
+
<use xlink:href="#spectrum-css-icon-CornerTriangle100" />
|
|
70
|
+
</svg>
|
|
71
|
+
{/if}
|
|
72
|
+
{#if icon}
|
|
73
|
+
<svg
|
|
74
|
+
class="spectrum-Icon spectrum-Icon--sizeS"
|
|
75
|
+
focusable="false"
|
|
76
|
+
aria-hidden="true"
|
|
77
|
+
aria-label={icon}
|
|
78
|
+
>
|
|
79
|
+
<use xlink:href="#spectrum-icon-18-{icon}" />
|
|
80
|
+
</svg>
|
|
81
|
+
{/if}
|
|
82
|
+
{#if $$slots}
|
|
83
|
+
<span class="spectrum-ActionButton-label"><slot /></span>
|
|
84
|
+
{/if}
|
|
85
|
+
{#if tooltip && showTooltip}
|
|
86
|
+
<div class="tooltip" in:fade={{ duration: 130, delay: 250 }}>
|
|
87
|
+
<Tooltip textWrapping direction="bottom" text={tooltip} />
|
|
88
|
+
</div>
|
|
89
|
+
{/if}
|
|
90
|
+
</button>
|
|
91
|
+
</span>
|
|
92
|
+
|
|
93
|
+
<style>
|
|
94
|
+
.fullWidth {
|
|
95
|
+
width: 100%;
|
|
96
|
+
}
|
|
97
|
+
.active,
|
|
98
|
+
.active svg {
|
|
99
|
+
color: var(--spectrum-global-color-blue-600);
|
|
100
|
+
}
|
|
101
|
+
:global([dir="ltr"] .spectrum-ActionButton .spectrum-Icon) {
|
|
102
|
+
margin-left: 0;
|
|
103
|
+
transition: color ease-out 130ms;
|
|
104
|
+
}
|
|
105
|
+
.is-selected:not(.spectrum-ActionButton--emphasized):not(.spectrum-ActionButton--quiet) {
|
|
106
|
+
background: var(--spectrum-global-color-gray-300);
|
|
107
|
+
border-color: var(--spectrum-global-color-gray-500);
|
|
108
|
+
}
|
|
109
|
+
.noPadding {
|
|
110
|
+
padding: 0;
|
|
111
|
+
min-width: 0;
|
|
112
|
+
}
|
|
113
|
+
.spectrum-ActionButton--quiet {
|
|
114
|
+
padding: 0 8px;
|
|
115
|
+
}
|
|
116
|
+
.spectrum-ActionButton--quiet.is-selected {
|
|
117
|
+
color: var(--spectrum-global-color-gray-900);
|
|
118
|
+
}
|
|
119
|
+
.is-selected:not(.emphasized) .spectrum-Icon {
|
|
120
|
+
color: var(--spectrum-global-color-gray-900);
|
|
121
|
+
}
|
|
122
|
+
.tooltip {
|
|
123
|
+
position: absolute;
|
|
124
|
+
pointer-events: none;
|
|
125
|
+
left: 50%;
|
|
126
|
+
top: calc(100% + 4px);
|
|
127
|
+
width: 100vw;
|
|
128
|
+
max-width: 150px;
|
|
129
|
+
transform: translateX(-50%);
|
|
130
|
+
text-align: center;
|
|
131
|
+
}
|
|
132
|
+
</style>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import "@spectrum-css/actiongroup/dist/index-vars.css"
|
|
3
|
+
export let vertical = false
|
|
4
|
+
export let justified = false
|
|
5
|
+
export let quiet = false
|
|
6
|
+
export let compact = false
|
|
7
|
+
|
|
8
|
+
// Attaches a spectrum-ActionGroup-item class to buttons inside the div
|
|
9
|
+
function group(element) {
|
|
10
|
+
const buttons = Array.from(element.getElementsByTagName("button"))
|
|
11
|
+
buttons.forEach(button => {
|
|
12
|
+
button.classList.add("spectrum-ActionGroup-item")
|
|
13
|
+
})
|
|
14
|
+
}
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<div
|
|
18
|
+
use:group
|
|
19
|
+
class:spectrum-ActionGroup--vertical={vertical}
|
|
20
|
+
class:spectrum-ActionGroup--justified={justified}
|
|
21
|
+
class:spectrum-ActionGroup--quiet={quiet}
|
|
22
|
+
class:spectrum-ActionGroup--compact={compact}
|
|
23
|
+
class="spectrum-ActionGroup"
|
|
24
|
+
>
|
|
25
|
+
<slot />
|
|
26
|
+
</div>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { setContext } from "svelte"
|
|
3
|
+
import Popover from "../Popover/Popover.svelte"
|
|
4
|
+
import Menu from "../Menu/Menu.svelte"
|
|
5
|
+
|
|
6
|
+
export let disabled = false
|
|
7
|
+
export let align = "left"
|
|
8
|
+
export let portalTarget
|
|
9
|
+
|
|
10
|
+
let anchor
|
|
11
|
+
let dropdown
|
|
12
|
+
|
|
13
|
+
// This is needed because display: contents is considered "invisible".
|
|
14
|
+
// It should only ever be an action button, so should be fine.
|
|
15
|
+
function getAnchor(node) {
|
|
16
|
+
anchor = node.firstChild
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const hide = () => {
|
|
20
|
+
dropdown.hide()
|
|
21
|
+
}
|
|
22
|
+
export const show = () => {
|
|
23
|
+
dropdown.show()
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const openMenu = event => {
|
|
27
|
+
if (!disabled) {
|
|
28
|
+
event.stopPropagation()
|
|
29
|
+
show()
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
setContext("actionMenu", { show, hide })
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<div use:getAnchor on:click={openMenu}>
|
|
37
|
+
<slot name="control" />
|
|
38
|
+
</div>
|
|
39
|
+
<Popover bind:this={dropdown} {anchor} {align} {portalTarget}>
|
|
40
|
+
<Menu>
|
|
41
|
+
<slot />
|
|
42
|
+
</Menu>
|
|
43
|
+
</Popover>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { View } from "svench";
|
|
3
|
+
import Multiselect from "../Form/Multiselect.svelte";
|
|
4
|
+
import DropdownMenu from "../DropdownMenu/DropdownMenu.svelte";
|
|
5
|
+
import Button from "../Button/Button.svelte";
|
|
6
|
+
import Icon from "../Icons/Icon.svelte";
|
|
7
|
+
|
|
8
|
+
const options = ["Red", "Blue", "Yellow", "Green", "Pink", "Very long color name to show text wrapping"];
|
|
9
|
+
|
|
10
|
+
let anchorLeft;
|
|
11
|
+
let dropdownLeft;
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
### Click Outside Action
|
|
15
|
+
|
|
16
|
+
This action can be used to listen for when you want to call a function whenever a user clicks outside of the element it is applied toString.
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
```html
|
|
20
|
+
<script>
|
|
21
|
+
import { clickOutside } from '@budibase/bbui'
|
|
22
|
+
const someFunction = () => {
|
|
23
|
+
// Some logic to close a dropdown or stop the user from doing something without saving?
|
|
24
|
+
}
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
<button use:clickOutside={someFunction} class="multiselect" bind:this={anchor}>
|
|
28
|
+
Clicking this opens the
|
|
29
|
+
</button>
|
|
30
|
+
```
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { View } from "svench";
|
|
3
|
+
import Multiselect from "../Form/Multiselect.svelte";
|
|
4
|
+
import DropdownMenu from "../DropdownMenu/DropdownMenu.svelte";
|
|
5
|
+
import Button from "../Button/Button.svelte";
|
|
6
|
+
import Icon from "../Icons/Icon.svelte";
|
|
7
|
+
|
|
8
|
+
const options = ["Red", "Blue", "Yellow", "Green", "Pink", "Very long color name to show text wrapping"];
|
|
9
|
+
|
|
10
|
+
let anchorLeft;
|
|
11
|
+
let dropdownLeft;
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
### Position Dropdown Action
|
|
15
|
+
|
|
16
|
+
This action positions an element close to it's anchor, either above or below it, depending on the amount of space that exists. There's also an option to align the dropdown to the right instead of the left of the anchor. An example of how to use it follows:
|
|
17
|
+
|
|
18
|
+
```html
|
|
19
|
+
<script>
|
|
20
|
+
let visible = false;
|
|
21
|
+
let anchor;
|
|
22
|
+
let align = 'right';
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
<button on:click={() => visible = !visible} class="multiselect" bind:this={anchor}>
|
|
26
|
+
Clicking this opens the
|
|
27
|
+
</button>
|
|
28
|
+
|
|
29
|
+
{#if visible}
|
|
30
|
+
<Portal>
|
|
31
|
+
<div use:positionDropdown={{anchor, align}}>
|
|
32
|
+
Some content here.
|
|
33
|
+
</div>
|
|
34
|
+
</Portal>
|
|
35
|
+
{/if}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Here are some components that currently use this action:
|
|
39
|
+
|
|
40
|
+
<View name="Multiselect Example">
|
|
41
|
+
<Multiselect name="Test" label="Colours" placeholder="Choose some colours">
|
|
42
|
+
{#each options as option}
|
|
43
|
+
<option value={option}>{option}</option>
|
|
44
|
+
{/each}
|
|
45
|
+
</Multiselect>
|
|
46
|
+
</View>
|
|
47
|
+
|
|
48
|
+
<View name="Dropdown on close event example">
|
|
49
|
+
<div bind:this={anchorLeft}>
|
|
50
|
+
<Button primary on:click={dropdownLeft.show}>
|
|
51
|
+
Field Name
|
|
52
|
+
<Icon name="arrowdown" />
|
|
53
|
+
</Button>
|
|
54
|
+
</div>
|
|
55
|
+
<DropdownMenu
|
|
56
|
+
on:close={() => alert('Closed!')}
|
|
57
|
+
bind:this={dropdownLeft}
|
|
58
|
+
width="175px"
|
|
59
|
+
borderColor="#d1d1d1ff"
|
|
60
|
+
anchor={anchorLeft}
|
|
61
|
+
align="left">
|
|
62
|
+
<ul>
|
|
63
|
+
<li>
|
|
64
|
+
<Icon name="edit" />
|
|
65
|
+
Edit
|
|
66
|
+
</li>
|
|
67
|
+
<li>
|
|
68
|
+
<Icon name="delete" />
|
|
69
|
+
Delete
|
|
70
|
+
</li>
|
|
71
|
+
<li>
|
|
72
|
+
<Icon name="sortascending" />
|
|
73
|
+
Sort A - Z
|
|
74
|
+
</li>
|
|
75
|
+
<li>
|
|
76
|
+
<Icon name="sortdescending" />
|
|
77
|
+
Sort Z - A
|
|
78
|
+
</li>
|
|
79
|
+
</ul>
|
|
80
|
+
</DropdownMenu>
|
|
81
|
+
</View>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
function resize({ target }) {
|
|
2
|
+
target.style.height = "1px"
|
|
3
|
+
target.style.height = +target.scrollHeight + "px"
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export default function text_area_resize(el) {
|
|
7
|
+
resize({ target: el })
|
|
8
|
+
el.style.overflow = "hidden"
|
|
9
|
+
el.addEventListener("input", resize)
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
destroy: () => el.removeEventListener("input", resize),
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
const ignoredClasses = [".flatpickr-calendar", ".spectrum-Popover"]
|
|
2
|
+
let clickHandlers = []
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Handle a body click event
|
|
6
|
+
*/
|
|
7
|
+
const handleClick = event => {
|
|
8
|
+
// Ignore click if this is an ignored class
|
|
9
|
+
if (event.target.closest('[data-ignore-click-outside="true"]')) {
|
|
10
|
+
return
|
|
11
|
+
}
|
|
12
|
+
for (let className of ignoredClasses) {
|
|
13
|
+
if (event.target.closest(className)) {
|
|
14
|
+
return
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Process handlers
|
|
19
|
+
clickHandlers.forEach(handler => {
|
|
20
|
+
if (handler.element.contains(event.target)) {
|
|
21
|
+
return
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Ignore clicks for modals, unless the handler is registered from a modal
|
|
25
|
+
const sourceInModal = handler.anchor.closest(".spectrum-Modal") != null
|
|
26
|
+
const clickInModal = event.target.closest(".spectrum-Modal") != null
|
|
27
|
+
if (clickInModal && !sourceInModal) {
|
|
28
|
+
return
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
handler.callback?.(event)
|
|
32
|
+
})
|
|
33
|
+
}
|
|
34
|
+
document.documentElement.addEventListener("click", handleClick, true)
|
|
35
|
+
document.documentElement.addEventListener("contextmenu", handleClick, true)
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Adds or updates a click handler
|
|
39
|
+
*/
|
|
40
|
+
const updateHandler = (id, element, anchor, callback) => {
|
|
41
|
+
let existingHandler = clickHandlers.find(x => x.id === id)
|
|
42
|
+
if (!existingHandler) {
|
|
43
|
+
clickHandlers.push({ id, element, anchor, callback })
|
|
44
|
+
} else {
|
|
45
|
+
existingHandler.callback = callback
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Removes a click handler
|
|
51
|
+
*/
|
|
52
|
+
const removeHandler = id => {
|
|
53
|
+
clickHandlers = clickHandlers.filter(x => x.id !== id)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Svelte action to apply a click outside handler for a certain element
|
|
58
|
+
* opts.anchor is an optional param specifying the real root source of the
|
|
59
|
+
* component being observed. This is required for things like popovers, where
|
|
60
|
+
* the element using the clickoutside action is the popover, but the popover is
|
|
61
|
+
* rendered at the root of the DOM somewhere, whereas the popover anchor is the
|
|
62
|
+
* element we actually want to consider when determining the source component.
|
|
63
|
+
*/
|
|
64
|
+
export default (element, opts) => {
|
|
65
|
+
const id = Math.random()
|
|
66
|
+
const update = newOpts => {
|
|
67
|
+
const callback = newOpts?.callback || newOpts
|
|
68
|
+
const anchor = newOpts?.anchor || element
|
|
69
|
+
updateHandler(id, element, anchor, callback)
|
|
70
|
+
}
|
|
71
|
+
update(opts)
|
|
72
|
+
return {
|
|
73
|
+
update,
|
|
74
|
+
destroy: () => removeHandler(id),
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
export default function positionDropdown(element, opts) {
|
|
2
|
+
let resizeObserver
|
|
3
|
+
let latestOpts = opts
|
|
4
|
+
|
|
5
|
+
// We need a static reference to this function so that we can properly
|
|
6
|
+
// clean up the scroll listener.
|
|
7
|
+
const scrollUpdate = () => {
|
|
8
|
+
updatePosition(latestOpts)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// Updates the position of the dropdown
|
|
12
|
+
const updatePosition = opts => {
|
|
13
|
+
const {
|
|
14
|
+
anchor,
|
|
15
|
+
align,
|
|
16
|
+
maxHeight,
|
|
17
|
+
maxWidth,
|
|
18
|
+
useAnchorWidth,
|
|
19
|
+
offset = 5,
|
|
20
|
+
} = opts
|
|
21
|
+
if (!anchor) {
|
|
22
|
+
return
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Compute bounds
|
|
26
|
+
const anchorBounds = anchor.getBoundingClientRect()
|
|
27
|
+
const elementBounds = element.getBoundingClientRect()
|
|
28
|
+
let styles = {
|
|
29
|
+
maxHeight: null,
|
|
30
|
+
minWidth: null,
|
|
31
|
+
maxWidth,
|
|
32
|
+
left: null,
|
|
33
|
+
top: null,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Determine vertical styles
|
|
37
|
+
if (align === "right-outside") {
|
|
38
|
+
styles.top = anchorBounds.top
|
|
39
|
+
} else if (window.innerHeight - anchorBounds.bottom < 100) {
|
|
40
|
+
styles.top = anchorBounds.top - elementBounds.height - offset
|
|
41
|
+
styles.maxHeight = maxHeight || 240
|
|
42
|
+
} else {
|
|
43
|
+
styles.top = anchorBounds.bottom + offset
|
|
44
|
+
styles.maxHeight =
|
|
45
|
+
maxHeight || window.innerHeight - anchorBounds.bottom - 20
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Determine horizontal styles
|
|
49
|
+
if (!maxWidth && useAnchorWidth) {
|
|
50
|
+
styles.maxWidth = anchorBounds.width
|
|
51
|
+
}
|
|
52
|
+
if (useAnchorWidth) {
|
|
53
|
+
styles.minWidth = anchorBounds.width
|
|
54
|
+
}
|
|
55
|
+
if (align === "right") {
|
|
56
|
+
styles.left = anchorBounds.left + anchorBounds.width - elementBounds.width
|
|
57
|
+
} else if (align === "right-outside") {
|
|
58
|
+
styles.left = anchorBounds.right + offset
|
|
59
|
+
} else {
|
|
60
|
+
styles.left = anchorBounds.left
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Apply styles
|
|
64
|
+
Object.entries(styles).forEach(([style, value]) => {
|
|
65
|
+
if (value) {
|
|
66
|
+
element.style[style] = `${value.toFixed(0)}px`
|
|
67
|
+
} else {
|
|
68
|
+
element.style[style] = null
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// The actual svelte action callback which creates observers on the relevant
|
|
74
|
+
// DOM elements
|
|
75
|
+
const update = newOpts => {
|
|
76
|
+
latestOpts = newOpts
|
|
77
|
+
|
|
78
|
+
// Cleanup old state
|
|
79
|
+
if (resizeObserver) {
|
|
80
|
+
resizeObserver.disconnect()
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Do nothing if no anchor
|
|
84
|
+
const { anchor } = newOpts
|
|
85
|
+
if (!anchor) {
|
|
86
|
+
return
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Observe both anchor and element and resize the popover as appropriate
|
|
90
|
+
resizeObserver = new ResizeObserver(() => updatePosition(newOpts))
|
|
91
|
+
resizeObserver.observe(anchor)
|
|
92
|
+
resizeObserver.observe(element)
|
|
93
|
+
resizeObserver.observe(document.body)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Apply initial styles which don't need to change
|
|
97
|
+
element.style.position = "absolute"
|
|
98
|
+
element.style.zIndex = "9999"
|
|
99
|
+
|
|
100
|
+
// Set up a scroll listener
|
|
101
|
+
document.addEventListener("scroll", scrollUpdate, true)
|
|
102
|
+
|
|
103
|
+
// Perform initial update
|
|
104
|
+
update(opts)
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
update,
|
|
108
|
+
destroy() {
|
|
109
|
+
// Cleanup
|
|
110
|
+
if (resizeObserver) {
|
|
111
|
+
resizeObserver.disconnect()
|
|
112
|
+
}
|
|
113
|
+
document.removeEventListener("scroll", scrollUpdate, true)
|
|
114
|
+
},
|
|
115
|
+
}
|
|
116
|
+
}
|