@budibase/bbui 2.33.13 → 3.0.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/dist/bbui.es.js +1 -23
- package/dist/bbui.es.js.map +1 -1
- package/package.json +4 -4
- package/src/ActionButton/ActionButton.svelte +56 -71
- package/src/ActionMenu/ActionMenu.svelte +36 -5
- package/src/Actions/position_dropdown.js +9 -3
- package/src/Button/Button.svelte +14 -1
- package/src/ButtonGroup/CollapsedButtonGroup.svelte +57 -0
- package/src/Form/Core/Switch.svelte +1 -0
- package/src/Form/Core/TextField.svelte +6 -3
- package/src/Icon/Icon.svelte +3 -2
- package/src/InlineAlert/InlineAlert.svelte +1 -0
- package/src/List/ListItem.svelte +113 -45
- package/src/Menu/Item.svelte +4 -3
- package/src/Modal/ModalContent.svelte +6 -1
- package/src/Notification/Notification.svelte +1 -5
- package/src/Popover/Popover.svelte +33 -2
- package/src/helpers.js +10 -0
- package/src/index.js +2 -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": "
|
|
4
|
+
"version": "3.0.0",
|
|
5
5
|
"license": "MPL-2.0",
|
|
6
6
|
"svelte": "src/index.js",
|
|
7
7
|
"module": "dist/bbui.es.js",
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
],
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@adobe/spectrum-css-workflow-icons": "1.2.1",
|
|
38
|
-
"@budibase/shared-core": "
|
|
39
|
-
"@budibase/string-templates": "
|
|
38
|
+
"@budibase/shared-core": "3.0.0",
|
|
39
|
+
"@budibase/string-templates": "3.0.0",
|
|
40
40
|
"@spectrum-css/accordion": "3.0.24",
|
|
41
41
|
"@spectrum-css/actionbutton": "1.0.1",
|
|
42
42
|
"@spectrum-css/actiongroup": "1.0.1",
|
|
@@ -104,5 +104,5 @@
|
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
106
|
},
|
|
107
|
-
"gitHead": "
|
|
107
|
+
"gitHead": "1272ac91c894cc5036dd188e969c77f33ed41ced"
|
|
108
108
|
}
|
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import "@spectrum-css/actionbutton/dist/index-vars.css"
|
|
3
|
-
import { createEventDispatcher } from "svelte"
|
|
4
3
|
import Tooltip from "../Tooltip/Tooltip.svelte"
|
|
5
4
|
import { fade } from "svelte/transition"
|
|
6
|
-
|
|
7
|
-
const dispatch = createEventDispatcher()
|
|
5
|
+
import { hexToRGBA } from "../helpers"
|
|
8
6
|
|
|
9
7
|
export let quiet = false
|
|
10
|
-
export let emphasized = false
|
|
11
8
|
export let selected = false
|
|
12
|
-
export let longPressable = false
|
|
13
9
|
export let disabled = false
|
|
14
10
|
export let icon = ""
|
|
15
11
|
export let size = "M"
|
|
@@ -17,82 +13,64 @@
|
|
|
17
13
|
export let fullWidth = false
|
|
18
14
|
export let noPadding = false
|
|
19
15
|
export let tooltip = ""
|
|
16
|
+
export let accentColor = null
|
|
20
17
|
|
|
21
18
|
let showTooltip = false
|
|
22
19
|
|
|
23
|
-
|
|
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)
|
|
20
|
+
$: accentStyle = getAccentStyle(accentColor)
|
|
34
21
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
element.removeEventListener("pointerdown", longPress)
|
|
39
|
-
},
|
|
22
|
+
const getAccentStyle = color => {
|
|
23
|
+
if (!color) {
|
|
24
|
+
return ""
|
|
40
25
|
}
|
|
26
|
+
let style = ""
|
|
27
|
+
style += `--accent-bg-color:${hexToRGBA(color, 0.15)};`
|
|
28
|
+
style += `--accent-border-color:${hexToRGBA(color, 0.35)};`
|
|
29
|
+
return style
|
|
41
30
|
}
|
|
42
31
|
</script>
|
|
43
32
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
class=
|
|
33
|
+
<button
|
|
34
|
+
class="spectrum-ActionButton spectrum-ActionButton--size{size}"
|
|
35
|
+
class:spectrum-ActionButton--quiet={quiet}
|
|
36
|
+
class:is-selected={selected}
|
|
37
|
+
class:noPadding
|
|
38
|
+
class:fullWidth
|
|
39
|
+
class:active
|
|
40
|
+
class:disabled
|
|
41
|
+
class:accent={accentColor != null}
|
|
42
|
+
on:click|preventDefault
|
|
47
43
|
on:mouseover={() => (showTooltip = true)}
|
|
48
44
|
on:mouseleave={() => (showTooltip = false)}
|
|
49
45
|
on:focus={() => (showTooltip = true)}
|
|
46
|
+
{disabled}
|
|
47
|
+
style={accentStyle}
|
|
50
48
|
>
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
{
|
|
66
|
-
<
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
>
|
|
71
|
-
<use xlink:href="#spectrum-css-icon-CornerTriangle100" />
|
|
72
|
-
</svg>
|
|
73
|
-
{/if}
|
|
74
|
-
{#if icon}
|
|
75
|
-
<svg
|
|
76
|
-
class="spectrum-Icon spectrum-Icon--sizeS"
|
|
77
|
-
focusable="false"
|
|
78
|
-
aria-hidden="true"
|
|
79
|
-
aria-label={icon}
|
|
80
|
-
>
|
|
81
|
-
<use xlink:href="#spectrum-icon-18-{icon}" />
|
|
82
|
-
</svg>
|
|
83
|
-
{/if}
|
|
84
|
-
{#if $$slots}
|
|
85
|
-
<span class="spectrum-ActionButton-label"><slot /></span>
|
|
86
|
-
{/if}
|
|
87
|
-
{#if tooltip && showTooltip}
|
|
88
|
-
<div class="tooltip" in:fade={{ duration: 130, delay: 250 }}>
|
|
89
|
-
<Tooltip textWrapping direction="bottom" text={tooltip} />
|
|
90
|
-
</div>
|
|
91
|
-
{/if}
|
|
92
|
-
</button>
|
|
93
|
-
</span>
|
|
49
|
+
{#if icon}
|
|
50
|
+
<svg
|
|
51
|
+
class="spectrum-Icon spectrum-Icon--sizeS"
|
|
52
|
+
focusable="false"
|
|
53
|
+
aria-hidden="true"
|
|
54
|
+
aria-label={icon}
|
|
55
|
+
>
|
|
56
|
+
<use xlink:href="#spectrum-icon-18-{icon}" />
|
|
57
|
+
</svg>
|
|
58
|
+
{/if}
|
|
59
|
+
{#if $$slots}
|
|
60
|
+
<span class="spectrum-ActionButton-label"><slot /></span>
|
|
61
|
+
{/if}
|
|
62
|
+
{#if tooltip && showTooltip}
|
|
63
|
+
<div class="tooltip" in:fade={{ duration: 130, delay: 250 }}>
|
|
64
|
+
<Tooltip textWrapping direction="bottom" text={tooltip} />
|
|
65
|
+
</div>
|
|
66
|
+
{/if}
|
|
67
|
+
</button>
|
|
94
68
|
|
|
95
69
|
<style>
|
|
70
|
+
button {
|
|
71
|
+
transition: filter 130ms ease-out, background 130ms ease-out,
|
|
72
|
+
border 130ms ease-out, color 130ms ease-out;
|
|
73
|
+
}
|
|
96
74
|
.fullWidth {
|
|
97
75
|
width: 100%;
|
|
98
76
|
}
|
|
@@ -104,9 +82,7 @@
|
|
|
104
82
|
margin-left: 0;
|
|
105
83
|
transition: color ease-out 130ms;
|
|
106
84
|
}
|
|
107
|
-
.is-selected:not(.spectrum-ActionButton--
|
|
108
|
-
.spectrum-ActionButton--quiet
|
|
109
|
-
) {
|
|
85
|
+
.is-selected:not(.spectrum-ActionButton--quiet) {
|
|
110
86
|
background: var(--spectrum-global-color-gray-300);
|
|
111
87
|
border-color: var(--spectrum-global-color-gray-500);
|
|
112
88
|
}
|
|
@@ -115,12 +91,13 @@
|
|
|
115
91
|
}
|
|
116
92
|
.spectrum-ActionButton--quiet.is-selected {
|
|
117
93
|
color: var(--spectrum-global-color-gray-900);
|
|
94
|
+
background: var(--spectrum-global-color-gray-300);
|
|
118
95
|
}
|
|
119
96
|
.noPadding {
|
|
120
97
|
padding: 0;
|
|
121
98
|
min-width: 0;
|
|
122
99
|
}
|
|
123
|
-
.is-selected
|
|
100
|
+
.is-selected .spectrum-Icon {
|
|
124
101
|
color: var(--spectrum-global-color-gray-900);
|
|
125
102
|
}
|
|
126
103
|
.is-selected.disabled .spectrum-Icon {
|
|
@@ -137,4 +114,12 @@
|
|
|
137
114
|
text-align: center;
|
|
138
115
|
z-index: 1;
|
|
139
116
|
}
|
|
117
|
+
.accent.is-selected,
|
|
118
|
+
.accent:active {
|
|
119
|
+
border: 1px solid var(--accent-border-color);
|
|
120
|
+
background: var(--accent-bg-color);
|
|
121
|
+
}
|
|
122
|
+
.accent:hover {
|
|
123
|
+
filter: brightness(1.2);
|
|
124
|
+
}
|
|
140
125
|
</style>
|
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
<script>
|
|
2
|
-
import { setContext } from "svelte"
|
|
2
|
+
import { setContext, getContext } from "svelte"
|
|
3
3
|
import Popover from "../Popover/Popover.svelte"
|
|
4
4
|
import Menu from "../Menu/Menu.svelte"
|
|
5
5
|
|
|
6
6
|
export let disabled = false
|
|
7
7
|
export let align = "left"
|
|
8
8
|
export let portalTarget
|
|
9
|
+
export let openOnHover = false
|
|
10
|
+
export let animate
|
|
11
|
+
export let offset
|
|
12
|
+
|
|
13
|
+
const actionMenuContext = getContext("actionMenu")
|
|
9
14
|
|
|
10
15
|
let anchor
|
|
11
16
|
let dropdown
|
|
17
|
+
let timeout
|
|
12
18
|
|
|
13
19
|
// This is needed because display: contents is considered "invisible".
|
|
14
20
|
// It should only ever be an action button, so should be fine.
|
|
@@ -16,11 +22,19 @@
|
|
|
16
22
|
anchor = node.firstChild
|
|
17
23
|
}
|
|
18
24
|
|
|
25
|
+
export const show = () => {
|
|
26
|
+
cancelHide()
|
|
27
|
+
dropdown.show()
|
|
28
|
+
}
|
|
29
|
+
|
|
19
30
|
export const hide = () => {
|
|
20
31
|
dropdown.hide()
|
|
21
32
|
}
|
|
22
|
-
|
|
23
|
-
|
|
33
|
+
|
|
34
|
+
// Hides this menu and all parent menus
|
|
35
|
+
const hideAll = () => {
|
|
36
|
+
hide()
|
|
37
|
+
actionMenuContext?.hide()
|
|
24
38
|
}
|
|
25
39
|
|
|
26
40
|
const openMenu = event => {
|
|
@@ -30,12 +44,25 @@
|
|
|
30
44
|
}
|
|
31
45
|
}
|
|
32
46
|
|
|
33
|
-
|
|
47
|
+
const queueHide = () => {
|
|
48
|
+
timeout = setTimeout(hide, 10)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const cancelHide = () => {
|
|
52
|
+
clearTimeout(timeout)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
setContext("actionMenu", { show, hide, hideAll })
|
|
34
56
|
</script>
|
|
35
57
|
|
|
36
58
|
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
|
37
59
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
38
|
-
<div
|
|
60
|
+
<div
|
|
61
|
+
use:getAnchor
|
|
62
|
+
on:click={openOnHover ? null : openMenu}
|
|
63
|
+
on:mouseenter={openOnHover ? show : null}
|
|
64
|
+
on:mouseleave={openOnHover ? queueHide : null}
|
|
65
|
+
>
|
|
39
66
|
<slot name="control" />
|
|
40
67
|
</div>
|
|
41
68
|
<Popover
|
|
@@ -43,9 +70,13 @@
|
|
|
43
70
|
{anchor}
|
|
44
71
|
{align}
|
|
45
72
|
{portalTarget}
|
|
73
|
+
{animate}
|
|
74
|
+
{offset}
|
|
46
75
|
resizable={false}
|
|
47
76
|
on:open
|
|
48
77
|
on:close
|
|
78
|
+
on:mouseenter={openOnHover ? cancelHide : null}
|
|
79
|
+
on:mouseleave={openOnHover ? queueHide : null}
|
|
49
80
|
>
|
|
50
81
|
<Menu>
|
|
51
82
|
<slot />
|
|
@@ -151,9 +151,9 @@ export default function positionDropdown(element, opts) {
|
|
|
151
151
|
// Determine X strategy
|
|
152
152
|
if (align === "right") {
|
|
153
153
|
applyXStrategy(Strategies.EndToEnd)
|
|
154
|
-
} else if (align === "right-outside") {
|
|
154
|
+
} else if (align === "right-outside" || align === "right-context-menu") {
|
|
155
155
|
applyXStrategy(Strategies.StartToEnd)
|
|
156
|
-
} else if (align === "left-outside") {
|
|
156
|
+
} else if (align === "left-outside" || align === "left-context-menu") {
|
|
157
157
|
applyXStrategy(Strategies.EndToStart)
|
|
158
158
|
} else if (align === "center") {
|
|
159
159
|
applyXStrategy(Strategies.MidPoint)
|
|
@@ -164,6 +164,12 @@ export default function positionDropdown(element, opts) {
|
|
|
164
164
|
// Determine Y strategy
|
|
165
165
|
if (align === "right-outside" || align === "left-outside") {
|
|
166
166
|
applyYStrategy(Strategies.MidPoint)
|
|
167
|
+
} else if (
|
|
168
|
+
align === "right-context-menu" ||
|
|
169
|
+
align === "left-context-menu"
|
|
170
|
+
) {
|
|
171
|
+
applyYStrategy(Strategies.StartToStart)
|
|
172
|
+
styles.top -= 5 // Manual adjustment for action menu padding
|
|
167
173
|
} else {
|
|
168
174
|
applyYStrategy(Strategies.StartToEnd)
|
|
169
175
|
}
|
|
@@ -240,7 +246,7 @@ export default function positionDropdown(element, opts) {
|
|
|
240
246
|
}
|
|
241
247
|
|
|
242
248
|
// Apply initial styles which don't need to change
|
|
243
|
-
element.style.position = "
|
|
249
|
+
element.style.position = "fixed"
|
|
244
250
|
element.style.zIndex = "9999"
|
|
245
251
|
|
|
246
252
|
// Set up a scroll listener
|
package/src/Button/Button.svelte
CHANGED
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
export let tooltip = undefined
|
|
18
18
|
export let newStyles = true
|
|
19
19
|
export let id
|
|
20
|
+
export let ref
|
|
21
|
+
export let reverse = false
|
|
20
22
|
|
|
21
23
|
const dispatch = createEventDispatcher()
|
|
22
24
|
</script>
|
|
@@ -25,6 +27,7 @@
|
|
|
25
27
|
<button
|
|
26
28
|
{id}
|
|
27
29
|
{type}
|
|
30
|
+
bind:this={ref}
|
|
28
31
|
class:spectrum-Button--cta={cta}
|
|
29
32
|
class:spectrum-Button--primary={primary}
|
|
30
33
|
class:spectrum-Button--secondary={secondary}
|
|
@@ -41,6 +44,9 @@
|
|
|
41
44
|
}
|
|
42
45
|
}}
|
|
43
46
|
>
|
|
47
|
+
{#if $$slots && reverse}
|
|
48
|
+
<span class="spectrum-Button-label"><slot /></span>
|
|
49
|
+
{/if}
|
|
44
50
|
{#if icon}
|
|
45
51
|
<svg
|
|
46
52
|
class="spectrum-Icon spectrum-Icon--size{size.toUpperCase()}"
|
|
@@ -51,7 +57,7 @@
|
|
|
51
57
|
<use xlink:href="#spectrum-icon-18-{icon}" />
|
|
52
58
|
</svg>
|
|
53
59
|
{/if}
|
|
54
|
-
{#if $$slots}
|
|
60
|
+
{#if $$slots && !reverse}
|
|
55
61
|
<span class="spectrum-Button-label"><slot /></span>
|
|
56
62
|
{/if}
|
|
57
63
|
</button>
|
|
@@ -91,4 +97,11 @@
|
|
|
91
97
|
.spectrum-Button--secondary.new-styles.is-disabled {
|
|
92
98
|
color: var(--spectrum-global-color-gray-500);
|
|
93
99
|
}
|
|
100
|
+
.spectrum-Button .spectrum-Button-label + .spectrum-Icon {
|
|
101
|
+
margin-left: var(--spectrum-button-primary-icon-gap);
|
|
102
|
+
margin-right: calc(
|
|
103
|
+
-1 * (var(--spectrum-button-primary-textonly-padding-left-adjusted) -
|
|
104
|
+
var(--spectrum-button-primary-padding-left-adjusted))
|
|
105
|
+
);
|
|
106
|
+
}
|
|
94
107
|
</style>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import Button from "../Button/Button.svelte"
|
|
3
|
+
import Popover from "../Popover/Popover.svelte"
|
|
4
|
+
import Menu from "../Menu/Menu.svelte"
|
|
5
|
+
import MenuItem from "../Menu/Item.svelte"
|
|
6
|
+
|
|
7
|
+
export let buttons
|
|
8
|
+
export let text = "Action"
|
|
9
|
+
export let size = "M"
|
|
10
|
+
export let align = "left"
|
|
11
|
+
export let offset
|
|
12
|
+
export let animate
|
|
13
|
+
export let quiet = false
|
|
14
|
+
|
|
15
|
+
let anchor
|
|
16
|
+
let popover
|
|
17
|
+
|
|
18
|
+
const handleClick = async button => {
|
|
19
|
+
popover.hide()
|
|
20
|
+
await button.onClick?.()
|
|
21
|
+
}
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<Button
|
|
25
|
+
bind:ref={anchor}
|
|
26
|
+
{size}
|
|
27
|
+
icon="ChevronDown"
|
|
28
|
+
{quiet}
|
|
29
|
+
primary={quiet}
|
|
30
|
+
cta={!quiet}
|
|
31
|
+
newStyles={!quiet}
|
|
32
|
+
on:click={() => popover?.show()}
|
|
33
|
+
on:click
|
|
34
|
+
reverse
|
|
35
|
+
>
|
|
36
|
+
{text || "Action"}
|
|
37
|
+
</Button>
|
|
38
|
+
<Popover
|
|
39
|
+
bind:this={popover}
|
|
40
|
+
{align}
|
|
41
|
+
{anchor}
|
|
42
|
+
{offset}
|
|
43
|
+
{animate}
|
|
44
|
+
resizable={false}
|
|
45
|
+
on:close
|
|
46
|
+
on:open
|
|
47
|
+
on:mouseenter
|
|
48
|
+
on:mouseleave
|
|
49
|
+
>
|
|
50
|
+
<Menu>
|
|
51
|
+
{#each buttons as button}
|
|
52
|
+
<MenuItem on:click={() => handleClick(button)} disabled={button.disabled}>
|
|
53
|
+
{button.text || "Button"}
|
|
54
|
+
</MenuItem>
|
|
55
|
+
{/each}
|
|
56
|
+
</Menu>
|
|
57
|
+
</Popover>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import "@spectrum-css/textfield/dist/index-vars.css"
|
|
3
|
-
import { createEventDispatcher, onMount } from "svelte"
|
|
3
|
+
import { createEventDispatcher, onMount, tick } from "svelte"
|
|
4
4
|
|
|
5
5
|
export let value = null
|
|
6
6
|
export let placeholder = null
|
|
@@ -68,10 +68,13 @@
|
|
|
68
68
|
return type === "number" ? "decimal" : "text"
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
onMount(() => {
|
|
71
|
+
onMount(async () => {
|
|
72
72
|
if (disabled) return
|
|
73
73
|
focus = autofocus
|
|
74
|
-
if (focus)
|
|
74
|
+
if (focus) {
|
|
75
|
+
await tick()
|
|
76
|
+
field.focus()
|
|
77
|
+
}
|
|
75
78
|
})
|
|
76
79
|
</script>
|
|
77
80
|
|
package/src/Icon/Icon.svelte
CHANGED
|
@@ -60,10 +60,11 @@
|
|
|
60
60
|
.newStyles {
|
|
61
61
|
color: var(--spectrum-global-color-gray-700);
|
|
62
62
|
}
|
|
63
|
-
|
|
63
|
+
svg {
|
|
64
|
+
transition: color var(--spectrum-global-animation-duration-100, 130ms);
|
|
65
|
+
}
|
|
64
66
|
svg.hoverable {
|
|
65
67
|
pointer-events: all;
|
|
66
|
-
transition: color var(--spectrum-global-animation-duration-100, 130ms);
|
|
67
68
|
}
|
|
68
69
|
svg.hoverable:hover {
|
|
69
70
|
color: var(--hover-color) !important;
|
package/src/List/ListItem.svelte
CHANGED
|
@@ -1,55 +1,68 @@
|
|
|
1
1
|
<script>
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import Label from "../Label/Label.svelte"
|
|
5
|
-
import Avatar from "../Avatar/Avatar.svelte"
|
|
2
|
+
import Icon from "../Icon/Icon.svelte"
|
|
3
|
+
import StatusLight from "../StatusLight/StatusLight.svelte"
|
|
6
4
|
|
|
7
5
|
export let icon = null
|
|
8
|
-
export let iconBackground = null
|
|
9
6
|
export let iconColor = null
|
|
10
|
-
export let avatar = false
|
|
11
7
|
export let title = null
|
|
12
8
|
export let subtitle = null
|
|
9
|
+
export let url = null
|
|
13
10
|
export let hoverable = false
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
export let showArrow = false
|
|
12
|
+
export let selected = false
|
|
16
13
|
</script>
|
|
17
14
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
15
|
+
<a
|
|
16
|
+
href={url}
|
|
17
|
+
class="list-item"
|
|
18
|
+
class:hoverable={hoverable || url != null}
|
|
19
|
+
class:large={!!subtitle}
|
|
20
|
+
on:click
|
|
21
|
+
class:selected
|
|
22
|
+
>
|
|
23
|
+
<div class="list-item__left">
|
|
24
|
+
{#if icon === "StatusLight"}
|
|
25
|
+
<StatusLight square size="L" color={iconColor} />
|
|
26
|
+
{:else if icon}
|
|
27
|
+
<div class="list-item__icon">
|
|
28
|
+
<Icon name={icon} color={iconColor} size={subtitle ? "XL" : "M"} />
|
|
29
|
+
</div>
|
|
27
30
|
{/if}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
<div class="list-item__text">
|
|
32
|
+
{#if title}
|
|
33
|
+
<div class="list-item__title">
|
|
34
|
+
{title}
|
|
35
|
+
</div>
|
|
36
|
+
{/if}
|
|
37
|
+
{#if subtitle}
|
|
38
|
+
<div class="list-item__subtitle">
|
|
39
|
+
{subtitle}
|
|
40
|
+
</div>
|
|
41
|
+
{/if}
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
<div class="list-item__right">
|
|
45
|
+
<slot name="right" />
|
|
46
|
+
{#if showArrow}
|
|
47
|
+
<Icon name="ChevronRight" />
|
|
33
48
|
{/if}
|
|
34
49
|
</div>
|
|
35
|
-
|
|
36
|
-
<div class="right">
|
|
37
|
-
<slot />
|
|
38
|
-
</div>
|
|
39
|
-
{/if}
|
|
40
|
-
</div>
|
|
50
|
+
</a>
|
|
41
51
|
|
|
42
52
|
<style>
|
|
43
53
|
.list-item {
|
|
44
|
-
padding:
|
|
45
|
-
|
|
46
|
-
background: var(--spectrum-global-color-gray-50);
|
|
54
|
+
padding: var(--spacing-m) var(--spacing-l);
|
|
55
|
+
background: var(--spectrum-global-color-gray-75);
|
|
47
56
|
display: flex;
|
|
48
57
|
flex-direction: row;
|
|
49
58
|
justify-content: space-between;
|
|
50
59
|
border: 1px solid var(--spectrum-global-color-gray-300);
|
|
51
|
-
transition: background 130ms ease-out;
|
|
60
|
+
transition: background 130ms ease-out, border-color 130ms ease-out;
|
|
52
61
|
gap: var(--spacing-m);
|
|
62
|
+
color: var(--spectrum-global-color-gray-800);
|
|
63
|
+
cursor: pointer;
|
|
64
|
+
position: relative;
|
|
65
|
+
box-sizing: border-box;
|
|
53
66
|
}
|
|
54
67
|
.list-item:not(:first-child) {
|
|
55
68
|
border-top: none;
|
|
@@ -64,32 +77,87 @@
|
|
|
64
77
|
}
|
|
65
78
|
.hoverable:hover {
|
|
66
79
|
cursor: pointer;
|
|
67
|
-
background: var(--spectrum-global-color-gray-75);
|
|
68
80
|
}
|
|
69
|
-
.
|
|
70
|
-
|
|
81
|
+
.hoverable:not(.selected):hover {
|
|
82
|
+
background: var(--spectrum-global-color-gray-200);
|
|
83
|
+
border-color: var(--spectrum-global-color-gray-400);
|
|
84
|
+
}
|
|
85
|
+
.selected {
|
|
86
|
+
background: var(--spectrum-global-color-blue-100);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* Selection is only meant for standalone list items (non stacked) so we just set a fixed border radius */
|
|
90
|
+
.list-item.selected {
|
|
91
|
+
background-color: var(--spectrum-global-color-blue-100);
|
|
92
|
+
border-color: var(--spectrum-global-color-blue-100);
|
|
93
|
+
}
|
|
94
|
+
.list-item.selected:after {
|
|
95
|
+
content: "";
|
|
96
|
+
position: absolute;
|
|
97
|
+
height: 100%;
|
|
98
|
+
width: 100%;
|
|
99
|
+
border: 1px solid var(--spectrum-global-color-blue-400);
|
|
100
|
+
pointer-events: none;
|
|
101
|
+
top: 0;
|
|
102
|
+
left: 0;
|
|
103
|
+
border-radius: 4px;
|
|
104
|
+
box-sizing: border-box;
|
|
105
|
+
z-index: 1;
|
|
106
|
+
opacity: 0.5;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/* Large icons */
|
|
110
|
+
.list-item.large .list-item__icon {
|
|
111
|
+
background-color: var(--spectrum-global-color-gray-200);
|
|
112
|
+
padding: 4px;
|
|
113
|
+
border-radius: 4px;
|
|
114
|
+
border: 1px solid var(--spectrum-global-color-gray-300);
|
|
115
|
+
transition: background-color 130ms ease-out, border-color 130ms ease-out,
|
|
116
|
+
color 130ms ease-out;
|
|
117
|
+
}
|
|
118
|
+
.list-item.large.hoverable:not(.selected):hover .list-item__icon {
|
|
119
|
+
background-color: var(--spectrum-global-color-gray-300);
|
|
120
|
+
}
|
|
121
|
+
.list-item.large.selected .list-item__icon {
|
|
122
|
+
background-color: var(--spectrum-global-color-blue-400);
|
|
123
|
+
color: white;
|
|
124
|
+
border-color: var(--spectrum-global-color-blue-100);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/* Internal layout */
|
|
128
|
+
.list-item__left,
|
|
129
|
+
.list-item__right {
|
|
71
130
|
display: flex;
|
|
72
131
|
flex-direction: row;
|
|
73
132
|
align-items: center;
|
|
74
|
-
gap: var(--spacing-
|
|
133
|
+
gap: var(--spacing-m);
|
|
134
|
+
}
|
|
135
|
+
.list-item.large .list-item__left,
|
|
136
|
+
.list-item.large .list-item__right {
|
|
137
|
+
gap: var(--spacing-m);
|
|
75
138
|
}
|
|
76
|
-
.
|
|
139
|
+
.list-item__left {
|
|
77
140
|
width: 0;
|
|
78
141
|
flex: 1 1 auto;
|
|
79
142
|
}
|
|
80
|
-
.
|
|
81
|
-
flex: 0 0 auto;
|
|
82
|
-
}
|
|
83
|
-
.list-item :global(.spectrum-Icon),
|
|
84
|
-
.list-item :global(.spectrum-Avatar) {
|
|
143
|
+
.list-item__right {
|
|
85
144
|
flex: 0 0 auto;
|
|
145
|
+
color: var(--spectrum-global-color-gray-600);
|
|
86
146
|
}
|
|
87
|
-
|
|
88
|
-
|
|
147
|
+
|
|
148
|
+
/* Text */
|
|
149
|
+
.list-item__text {
|
|
150
|
+
flex: 1 1 auto;
|
|
151
|
+
width: 0;
|
|
89
152
|
}
|
|
90
|
-
.list-
|
|
153
|
+
.list-item__title,
|
|
154
|
+
.list-item__subtitle {
|
|
91
155
|
white-space: nowrap;
|
|
92
156
|
overflow: hidden;
|
|
93
157
|
text-overflow: ellipsis;
|
|
94
158
|
}
|
|
159
|
+
.list-item__subtitle {
|
|
160
|
+
color: var(--spectrum-global-color-gray-700);
|
|
161
|
+
font-size: 12px;
|
|
162
|
+
}
|
|
95
163
|
</style>
|