@budibase/bbui 2.2.12-alpha.32 → 2.2.12-alpha.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bbui.es.js +3 -3
- package/dist/bbui.es.js.map +1 -1
- package/package.json +4 -3
- package/src/Accordion/Accordion.svelte +58 -0
- package/src/ActionButton/ActionButton.svelte +1 -0
- package/src/FancyForm/FancyButton.svelte +29 -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 +63 -0
- package/src/FancyForm/FancySelect.svelte +135 -0
- package/src/FancyForm/index.js +6 -0
- package/src/Form/Core/Select.svelte +3 -0
- package/src/Layout/Page.svelte +7 -1
- package/src/Link/Link.svelte +4 -1
- package/src/index.js +4 -0
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": "2.2.12-alpha.
|
|
4
|
+
"version": "2.2.12-alpha.34",
|
|
5
5
|
"license": "MPL-2.0",
|
|
6
6
|
"svelte": "src/index.js",
|
|
7
7
|
"module": "dist/bbui.es.js",
|
|
@@ -38,7 +38,8 @@
|
|
|
38
38
|
],
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@adobe/spectrum-css-workflow-icons": "1.2.1",
|
|
41
|
-
"@budibase/string-templates": "2.2.12-alpha.
|
|
41
|
+
"@budibase/string-templates": "2.2.12-alpha.34",
|
|
42
|
+
"@spectrum-css/accordion": "3.0.24",
|
|
42
43
|
"@spectrum-css/actionbutton": "1.0.1",
|
|
43
44
|
"@spectrum-css/actiongroup": "1.0.1",
|
|
44
45
|
"@spectrum-css/avatar": "3.0.2",
|
|
@@ -88,5 +89,5 @@
|
|
|
88
89
|
"resolutions": {
|
|
89
90
|
"loader-utils": "1.4.1"
|
|
90
91
|
},
|
|
91
|
-
"gitHead": "
|
|
92
|
+
"gitHead": "b439583224d6a88cbcc11ba4202f9a91f0852b06"
|
|
92
93
|
}
|
|
@@ -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,29 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import Icon from "../Icon/Icon.svelte"
|
|
3
|
+
import FancyField from "./FancyField.svelte"
|
|
4
|
+
|
|
5
|
+
export let icon
|
|
6
|
+
export let disabled
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<FancyField on:click clickable {disabled}>
|
|
10
|
+
{#if icon}
|
|
11
|
+
{#if icon.includes("/")}
|
|
12
|
+
<img src={icon} alt="button" />
|
|
13
|
+
{:else}
|
|
14
|
+
<Icon name={icon} />
|
|
15
|
+
{/if}
|
|
16
|
+
{/if}
|
|
17
|
+
<div>
|
|
18
|
+
<slot />
|
|
19
|
+
</div>
|
|
20
|
+
</FancyField>
|
|
21
|
+
|
|
22
|
+
<style>
|
|
23
|
+
img {
|
|
24
|
+
width: 22px;
|
|
25
|
+
}
|
|
26
|
+
div {
|
|
27
|
+
font-size: var(--font-size-l);
|
|
28
|
+
}
|
|
29
|
+
</style>
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { createEventDispatcher } from "svelte"
|
|
3
|
+
import FancyField from "./FancyField.svelte"
|
|
4
|
+
import FancyFieldLabel from "./FancyFieldLabel.svelte"
|
|
5
|
+
import ActionButton from "../ActionButton/ActionButton.svelte"
|
|
6
|
+
|
|
7
|
+
export let label
|
|
8
|
+
export let value
|
|
9
|
+
export let disabled = false
|
|
10
|
+
export let error = null
|
|
11
|
+
export let validate = null
|
|
12
|
+
export let options = []
|
|
13
|
+
export let getOptionLabel = option => extractProperty(option, "label")
|
|
14
|
+
export let getOptionValue = option => extractProperty(option, "value")
|
|
15
|
+
|
|
16
|
+
const dispatch = createEventDispatcher()
|
|
17
|
+
|
|
18
|
+
$: placeholder = !value
|
|
19
|
+
|
|
20
|
+
const extractProperty = (value, property) => {
|
|
21
|
+
if (value && typeof value === "object") {
|
|
22
|
+
return value[property]
|
|
23
|
+
}
|
|
24
|
+
return value
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const onChange = newValue => {
|
|
28
|
+
dispatch("change", newValue)
|
|
29
|
+
value = newValue
|
|
30
|
+
if (validate) {
|
|
31
|
+
error = validate(newValue)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<FancyField {error} {value} {validate} {disabled} autoHeight>
|
|
37
|
+
{#if label}
|
|
38
|
+
<FancyFieldLabel placeholder={false}>{label}</FancyFieldLabel>
|
|
39
|
+
{/if}
|
|
40
|
+
|
|
41
|
+
<div class="options">
|
|
42
|
+
{#each options as option}
|
|
43
|
+
<ActionButton
|
|
44
|
+
selected={getOptionValue(option) === value}
|
|
45
|
+
on:click={() => onChange(getOptionValue(option))}
|
|
46
|
+
>
|
|
47
|
+
{getOptionLabel(option)}
|
|
48
|
+
</ActionButton>
|
|
49
|
+
{/each}
|
|
50
|
+
</div>
|
|
51
|
+
</FancyField>
|
|
52
|
+
|
|
53
|
+
<style>
|
|
54
|
+
.options {
|
|
55
|
+
margin-top: 34px;
|
|
56
|
+
margin-bottom: 14px;
|
|
57
|
+
display: flex;
|
|
58
|
+
flex-direction: row;
|
|
59
|
+
justify-content: flex-start;
|
|
60
|
+
align-items: center;
|
|
61
|
+
gap: 6px;
|
|
62
|
+
flex-wrap: wrap;
|
|
63
|
+
}
|
|
64
|
+
.options :global(.spectrum-ActionButton) {
|
|
65
|
+
font-size: 15px;
|
|
66
|
+
line-height: 17px;
|
|
67
|
+
height: auto;
|
|
68
|
+
padding: 6px 10px;
|
|
69
|
+
}
|
|
70
|
+
</style>
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { createEventDispatcher } from "svelte"
|
|
3
|
+
import FancyField from "./FancyField.svelte"
|
|
4
|
+
import Checkbox from "../Form/Core/Checkbox.svelte"
|
|
5
|
+
|
|
6
|
+
export let value
|
|
7
|
+
export let text
|
|
8
|
+
export let disabled = false
|
|
9
|
+
export let error = null
|
|
10
|
+
export let validate = null
|
|
11
|
+
|
|
12
|
+
const dispatch = createEventDispatcher()
|
|
13
|
+
|
|
14
|
+
const onChange = () => {
|
|
15
|
+
const newValue = !value
|
|
16
|
+
dispatch("change", newValue)
|
|
17
|
+
value = newValue
|
|
18
|
+
if (validate) {
|
|
19
|
+
error = validate(newValue)
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<FancyField {error} {value} {validate} {disabled} clickable on:click={onChange}>
|
|
25
|
+
<span>
|
|
26
|
+
<Checkbox {disabled} {value} />
|
|
27
|
+
</span>
|
|
28
|
+
<div class="text">
|
|
29
|
+
{#if text}
|
|
30
|
+
{text}
|
|
31
|
+
{/if}
|
|
32
|
+
<slot />
|
|
33
|
+
</div>
|
|
34
|
+
</FancyField>
|
|
35
|
+
|
|
36
|
+
<style>
|
|
37
|
+
span {
|
|
38
|
+
pointer-events: none;
|
|
39
|
+
}
|
|
40
|
+
.text {
|
|
41
|
+
font-size: 15px;
|
|
42
|
+
line-height: 17px;
|
|
43
|
+
overflow: hidden;
|
|
44
|
+
text-overflow: ellipsis;
|
|
45
|
+
display: -webkit-box;
|
|
46
|
+
-webkit-line-clamp: 2;
|
|
47
|
+
line-clamp: 2;
|
|
48
|
+
-webkit-box-orient: vertical;
|
|
49
|
+
}
|
|
50
|
+
.text > :global(*) {
|
|
51
|
+
font-size: inherit !important;
|
|
52
|
+
}
|
|
53
|
+
</style>
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import Icon from "../Icon/Icon.svelte"
|
|
3
|
+
import { getContext, onMount } from "svelte"
|
|
4
|
+
import { slide } from "svelte/transition"
|
|
5
|
+
|
|
6
|
+
export let disabled = false
|
|
7
|
+
export let error = null
|
|
8
|
+
export let focused = false
|
|
9
|
+
export let clickable = false
|
|
10
|
+
export let validate
|
|
11
|
+
export let value
|
|
12
|
+
export let ref
|
|
13
|
+
export let autoHeight
|
|
14
|
+
|
|
15
|
+
const formContext = getContext("fancy-form")
|
|
16
|
+
const id = Math.random()
|
|
17
|
+
const API = {
|
|
18
|
+
validate: () => {
|
|
19
|
+
if (validate) {
|
|
20
|
+
error = validate(value)
|
|
21
|
+
}
|
|
22
|
+
return !error
|
|
23
|
+
},
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
onMount(() => {
|
|
27
|
+
if (formContext) {
|
|
28
|
+
formContext.registerField(id, API)
|
|
29
|
+
}
|
|
30
|
+
return () => {
|
|
31
|
+
if (formContext) {
|
|
32
|
+
formContext.unregisterField(id)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
})
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<div
|
|
39
|
+
bind:this={ref}
|
|
40
|
+
class="fancy-field"
|
|
41
|
+
class:error
|
|
42
|
+
class:disabled
|
|
43
|
+
class:focused
|
|
44
|
+
class:clickable
|
|
45
|
+
class:auto-height={autoHeight}
|
|
46
|
+
>
|
|
47
|
+
<div class="content" on:click>
|
|
48
|
+
<div class="field">
|
|
49
|
+
<slot />
|
|
50
|
+
</div>
|
|
51
|
+
{#if error}
|
|
52
|
+
<div class="error-icon">
|
|
53
|
+
<Icon name="Alert" />
|
|
54
|
+
</div>
|
|
55
|
+
{/if}
|
|
56
|
+
</div>
|
|
57
|
+
{#if error}
|
|
58
|
+
<div transition:slide|local={{ duration: 130 }} class="error-message">
|
|
59
|
+
{error}
|
|
60
|
+
</div>
|
|
61
|
+
{/if}
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
<style>
|
|
65
|
+
.fancy-field {
|
|
66
|
+
max-width: 400px;
|
|
67
|
+
background: var(--spectrum-global-color-gray-75);
|
|
68
|
+
border: 1px solid var(--spectrum-global-color-gray-300);
|
|
69
|
+
border-radius: 4px;
|
|
70
|
+
box-sizing: border-box;
|
|
71
|
+
transition: border-color 130ms ease-out, background 130ms ease-out,
|
|
72
|
+
background 130ms ease-out;
|
|
73
|
+
color: var(--spectrum-global-color-gray-800);
|
|
74
|
+
}
|
|
75
|
+
.fancy-field:hover {
|
|
76
|
+
border-color: var(--spectrum-global-color-gray-400);
|
|
77
|
+
}
|
|
78
|
+
.fancy-field.clickable:hover {
|
|
79
|
+
background: var(--spectrum-global-color-gray-200);
|
|
80
|
+
cursor: pointer;
|
|
81
|
+
}
|
|
82
|
+
.fancy-field.focused {
|
|
83
|
+
border-color: var(--spectrum-global-color-blue-400);
|
|
84
|
+
}
|
|
85
|
+
.fancy-field.error {
|
|
86
|
+
border-color: var(--spectrum-global-color-red-400);
|
|
87
|
+
}
|
|
88
|
+
.fancy-field.disabled {
|
|
89
|
+
background: var(--spectrum-global-color-gray-200);
|
|
90
|
+
color: var(--spectrum-global-color-gray-400);
|
|
91
|
+
border: 1px solid var(--spectrum-global-color-gray-300);
|
|
92
|
+
pointer-events: none;
|
|
93
|
+
}
|
|
94
|
+
.content {
|
|
95
|
+
position: relative;
|
|
96
|
+
height: 64px;
|
|
97
|
+
padding: 0 16px;
|
|
98
|
+
}
|
|
99
|
+
.fancy-field.auto-height .content {
|
|
100
|
+
height: auto;
|
|
101
|
+
}
|
|
102
|
+
.content,
|
|
103
|
+
.field {
|
|
104
|
+
display: flex;
|
|
105
|
+
flex-direction: row;
|
|
106
|
+
justify-content: flex-start;
|
|
107
|
+
align-items: center;
|
|
108
|
+
gap: 16px;
|
|
109
|
+
}
|
|
110
|
+
.field {
|
|
111
|
+
flex: 1 1 auto;
|
|
112
|
+
}
|
|
113
|
+
.error-message {
|
|
114
|
+
background: var(--spectrum-global-color-red-400);
|
|
115
|
+
color: white;
|
|
116
|
+
font-size: 14px;
|
|
117
|
+
padding: 6px 16px;
|
|
118
|
+
font-weight: 500;
|
|
119
|
+
}
|
|
120
|
+
.error-icon {
|
|
121
|
+
flex: 0 0 auto;
|
|
122
|
+
}
|
|
123
|
+
.error-icon :global(.spectrum-Icon) {
|
|
124
|
+
fill: var(--spectrum-global-color-red-400);
|
|
125
|
+
}
|
|
126
|
+
</style>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
export let placeholder = true
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<div class:placeholder>
|
|
6
|
+
<slot />
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
<style>
|
|
10
|
+
div {
|
|
11
|
+
font-size: 14px;
|
|
12
|
+
line-height: 15px;
|
|
13
|
+
font-weight: 500;
|
|
14
|
+
position: absolute;
|
|
15
|
+
top: 10px;
|
|
16
|
+
color: var(--spectrum-global-color-gray-600);
|
|
17
|
+
transition: font-size 130ms ease-out, top 130ms ease-out,
|
|
18
|
+
transform 130ms ease-out;
|
|
19
|
+
}
|
|
20
|
+
div.placeholder {
|
|
21
|
+
top: 50%;
|
|
22
|
+
font-size: 15px;
|
|
23
|
+
transform: translateY(-50%);
|
|
24
|
+
}
|
|
25
|
+
</style>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { setContext } from "svelte"
|
|
3
|
+
|
|
4
|
+
let fields = {}
|
|
5
|
+
|
|
6
|
+
setContext("fancy-form", {
|
|
7
|
+
registerField: (id, api) => {
|
|
8
|
+
fields = { ...fields, [id]: api }
|
|
9
|
+
},
|
|
10
|
+
unregisterField: id => {
|
|
11
|
+
delete fields[id]
|
|
12
|
+
fields = fields
|
|
13
|
+
},
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
export const validate = () => {
|
|
17
|
+
let valid = true
|
|
18
|
+
Object.values(fields).forEach(api => {
|
|
19
|
+
if (!api.validate()) {
|
|
20
|
+
valid = false
|
|
21
|
+
}
|
|
22
|
+
})
|
|
23
|
+
return valid
|
|
24
|
+
}
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
<div class="fancy-form">
|
|
28
|
+
<slot />
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<style>
|
|
32
|
+
.fancy-form :global(.fancy-field:not(:first-of-type)) {
|
|
33
|
+
border-top-left-radius: 0;
|
|
34
|
+
border-top-right-radius: 0;
|
|
35
|
+
}
|
|
36
|
+
.fancy-form :global(.fancy-field:not(:last-of-type)) {
|
|
37
|
+
border-bottom-left-radius: 0;
|
|
38
|
+
border-bottom-right-radius: 0;
|
|
39
|
+
}
|
|
40
|
+
</style>
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { createEventDispatcher } from "svelte"
|
|
3
|
+
import FancyField from "./FancyField.svelte"
|
|
4
|
+
import FancyFieldLabel from "./FancyFieldLabel.svelte"
|
|
5
|
+
|
|
6
|
+
export let label
|
|
7
|
+
export let value
|
|
8
|
+
export let type = "text"
|
|
9
|
+
export let disabled = false
|
|
10
|
+
export let error = null
|
|
11
|
+
export let validate = null
|
|
12
|
+
|
|
13
|
+
const dispatch = createEventDispatcher()
|
|
14
|
+
|
|
15
|
+
let focused = false
|
|
16
|
+
$: placeholder = !focused && !value
|
|
17
|
+
|
|
18
|
+
const onChange = e => {
|
|
19
|
+
const newValue = e.target.value
|
|
20
|
+
dispatch("change", newValue)
|
|
21
|
+
value = newValue
|
|
22
|
+
if (validate) {
|
|
23
|
+
error = validate(newValue)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<FancyField {error} {value} {validate} {disabled} {focused}>
|
|
29
|
+
{#if label}
|
|
30
|
+
<FancyFieldLabel {placeholder}>{label}</FancyFieldLabel>
|
|
31
|
+
{/if}
|
|
32
|
+
<input
|
|
33
|
+
{disabled}
|
|
34
|
+
value={value || ""}
|
|
35
|
+
type={type || "text"}
|
|
36
|
+
on:input={onChange}
|
|
37
|
+
on:focus={() => (focused = true)}
|
|
38
|
+
on:blur={() => (focused = false)}
|
|
39
|
+
class:placeholder
|
|
40
|
+
/>
|
|
41
|
+
</FancyField>
|
|
42
|
+
|
|
43
|
+
<style>
|
|
44
|
+
input {
|
|
45
|
+
width: 100%;
|
|
46
|
+
transition: transform 130ms ease-out;
|
|
47
|
+
transform: translateY(9px);
|
|
48
|
+
background: transparent;
|
|
49
|
+
font-size: 15px;
|
|
50
|
+
line-height: 17px;
|
|
51
|
+
font-family: var(--font-sans);
|
|
52
|
+
color: var(--spectrum-global-color-gray-900);
|
|
53
|
+
outline: none;
|
|
54
|
+
border: none;
|
|
55
|
+
}
|
|
56
|
+
input.placeholder {
|
|
57
|
+
transform: translateY(0);
|
|
58
|
+
position: absolute;
|
|
59
|
+
top: 0;
|
|
60
|
+
left: 0;
|
|
61
|
+
height: 100%;
|
|
62
|
+
}
|
|
63
|
+
</style>
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { createEventDispatcher } from "svelte"
|
|
3
|
+
import FancyField from "./FancyField.svelte"
|
|
4
|
+
import Icon from "../Icon/Icon.svelte"
|
|
5
|
+
import Popover from "../Popover/Popover.svelte"
|
|
6
|
+
import FancyFieldLabel from "./FancyFieldLabel.svelte"
|
|
7
|
+
|
|
8
|
+
export let label
|
|
9
|
+
export let value
|
|
10
|
+
export let disabled = false
|
|
11
|
+
export let error = null
|
|
12
|
+
export let validate = null
|
|
13
|
+
export let options = []
|
|
14
|
+
export let getOptionLabel = option => extractProperty(option, "label")
|
|
15
|
+
export let getOptionValue = option => extractProperty(option, "value")
|
|
16
|
+
|
|
17
|
+
const dispatch = createEventDispatcher()
|
|
18
|
+
|
|
19
|
+
let open = false
|
|
20
|
+
let popover
|
|
21
|
+
let wrapper
|
|
22
|
+
|
|
23
|
+
$: placeholder = !value
|
|
24
|
+
|
|
25
|
+
const extractProperty = (value, property) => {
|
|
26
|
+
if (value && typeof value === "object") {
|
|
27
|
+
return value[property]
|
|
28
|
+
}
|
|
29
|
+
return value
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const onChange = newValue => {
|
|
33
|
+
dispatch("change", newValue)
|
|
34
|
+
value = newValue
|
|
35
|
+
if (validate) {
|
|
36
|
+
error = validate(newValue)
|
|
37
|
+
}
|
|
38
|
+
open = false
|
|
39
|
+
}
|
|
40
|
+
</script>
|
|
41
|
+
|
|
42
|
+
<FancyField
|
|
43
|
+
bind:ref={wrapper}
|
|
44
|
+
{error}
|
|
45
|
+
{value}
|
|
46
|
+
{validate}
|
|
47
|
+
{disabled}
|
|
48
|
+
clickable
|
|
49
|
+
on:click={() => (open = true)}
|
|
50
|
+
>
|
|
51
|
+
{#if label}
|
|
52
|
+
<FancyFieldLabel {placeholder}>{label}</FancyFieldLabel>
|
|
53
|
+
{/if}
|
|
54
|
+
|
|
55
|
+
<div class="value" class:placeholder>
|
|
56
|
+
{value || ""}
|
|
57
|
+
</div>
|
|
58
|
+
|
|
59
|
+
<div class="arrow">
|
|
60
|
+
<Icon name="ChevronDown" />
|
|
61
|
+
</div>
|
|
62
|
+
</FancyField>
|
|
63
|
+
|
|
64
|
+
<Popover
|
|
65
|
+
anchor={wrapper}
|
|
66
|
+
align="left"
|
|
67
|
+
portalTarget={document.documentElement}
|
|
68
|
+
bind:this={popover}
|
|
69
|
+
{open}
|
|
70
|
+
on:close={() => (open = false)}
|
|
71
|
+
useAnchorWidth={true}
|
|
72
|
+
maxWidth={null}
|
|
73
|
+
>
|
|
74
|
+
<div class="popover-content">
|
|
75
|
+
{#if options.length}
|
|
76
|
+
{#each options as option, idx}
|
|
77
|
+
<div
|
|
78
|
+
class="popover-option"
|
|
79
|
+
tabindex="0"
|
|
80
|
+
on:click={() => onChange(getOptionValue(option, idx))}
|
|
81
|
+
>
|
|
82
|
+
<span class="option-text">
|
|
83
|
+
{getOptionLabel(option, idx)}
|
|
84
|
+
</span>
|
|
85
|
+
{#if value === getOptionValue(option, idx)}
|
|
86
|
+
<Icon name="Checkmark" />
|
|
87
|
+
{/if}
|
|
88
|
+
</div>
|
|
89
|
+
{/each}
|
|
90
|
+
{/if}
|
|
91
|
+
</div>
|
|
92
|
+
</Popover>
|
|
93
|
+
|
|
94
|
+
<style>
|
|
95
|
+
.value {
|
|
96
|
+
display: block;
|
|
97
|
+
flex: 1 1 auto;
|
|
98
|
+
font-size: 15px;
|
|
99
|
+
line-height: 17px;
|
|
100
|
+
color: var(--spectrum-global-color-gray-900);
|
|
101
|
+
transition: transform 130ms ease-out, opacity 130ms ease-out;
|
|
102
|
+
opacity: 1;
|
|
103
|
+
white-space: nowrap;
|
|
104
|
+
text-overflow: ellipsis;
|
|
105
|
+
overflow: hidden;
|
|
106
|
+
width: 0;
|
|
107
|
+
transform: translateY(9px);
|
|
108
|
+
}
|
|
109
|
+
.value.placeholder {
|
|
110
|
+
transform: translateY(0);
|
|
111
|
+
opacity: 0;
|
|
112
|
+
pointer-events: none;
|
|
113
|
+
margin-top: 0;
|
|
114
|
+
}
|
|
115
|
+
.popover-content {
|
|
116
|
+
display: flex;
|
|
117
|
+
flex-direction: column;
|
|
118
|
+
justify-content: flex-start;
|
|
119
|
+
align-items: stretch;
|
|
120
|
+
padding: 7px 0;
|
|
121
|
+
}
|
|
122
|
+
.popover-option {
|
|
123
|
+
display: flex;
|
|
124
|
+
flex-direction: row;
|
|
125
|
+
justify-content: space-between;
|
|
126
|
+
align-items: center;
|
|
127
|
+
padding: 7px 16px;
|
|
128
|
+
transition: background 130ms ease-out;
|
|
129
|
+
font-size: 15px;
|
|
130
|
+
}
|
|
131
|
+
.popover-option:hover {
|
|
132
|
+
background: var(--spectrum-global-color-gray-200);
|
|
133
|
+
cursor: pointer;
|
|
134
|
+
}
|
|
135
|
+
</style>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { default as FancyInput } from "./FancyInput.svelte"
|
|
2
|
+
export { default as FancyCheckbox } from "./FancyCheckbox.svelte"
|
|
3
|
+
export { default as FancySelect } from "./FancySelect.svelte"
|
|
4
|
+
export { default as FancyButton } from "./FancyButton.svelte"
|
|
5
|
+
export { default as FancyForm } from "./FancyForm.svelte"
|
|
6
|
+
export { default as FancyButtonRadio } from "./FancyButtonRadio.svelte"
|
|
@@ -18,8 +18,11 @@
|
|
|
18
18
|
export let autoWidth = false
|
|
19
19
|
export let autocomplete = false
|
|
20
20
|
export let sort = false
|
|
21
|
+
|
|
21
22
|
const dispatch = createEventDispatcher()
|
|
23
|
+
|
|
22
24
|
let open = false
|
|
25
|
+
|
|
23
26
|
$: fieldText = getFieldText(value, options, placeholder)
|
|
24
27
|
$: fieldIcon = getFieldAttribute(getOptionIcon, value, options)
|
|
25
28
|
$: fieldColour = getFieldAttribute(getOptionColour, value, options)
|
package/src/Layout/Page.svelte
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
<div class="main">
|
|
19
19
|
<div class="content" class:wide class:noPadding class:narrow>
|
|
20
20
|
<slot />
|
|
21
|
+
<div class="fix-scroll-padding" />
|
|
21
22
|
</div>
|
|
22
23
|
</div>
|
|
23
24
|
<div
|
|
@@ -55,9 +56,14 @@
|
|
|
55
56
|
max-width: 1080px;
|
|
56
57
|
margin: 0 auto;
|
|
57
58
|
flex: 1 1 auto;
|
|
58
|
-
padding: 50px;
|
|
59
|
+
padding: 50px 50px 0 50px;
|
|
59
60
|
z-index: 1;
|
|
60
61
|
}
|
|
62
|
+
.fix-scroll-padding {
|
|
63
|
+
content: "";
|
|
64
|
+
display: block;
|
|
65
|
+
flex: 0 0 50px;
|
|
66
|
+
}
|
|
61
67
|
.content.wide {
|
|
62
68
|
max-width: none;
|
|
63
69
|
}
|
package/src/Link/Link.svelte
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import "@spectrum-css/link/dist/index-vars.css"
|
|
3
|
+
import { createEventDispatcher } from "svelte"
|
|
3
4
|
|
|
4
5
|
export let href = "#"
|
|
5
6
|
export let size = "M"
|
|
@@ -9,10 +10,12 @@
|
|
|
9
10
|
export let overBackground = false
|
|
10
11
|
export let target
|
|
11
12
|
export let download
|
|
13
|
+
|
|
14
|
+
const dispatch = createEventDispatcher()
|
|
12
15
|
</script>
|
|
13
16
|
|
|
14
17
|
<a
|
|
15
|
-
on:click
|
|
18
|
+
on:click={e => dispatch("click") && e.stopPropagation()}
|
|
16
19
|
{href}
|
|
17
20
|
{target}
|
|
18
21
|
{download}
|