update picker to allow only popover
This commit is contained in:
parent
ac2389c445
commit
e88efe2d1a
|
@ -2,8 +2,9 @@
|
||||||
import { createEventDispatcher } from "svelte"
|
import { createEventDispatcher } from "svelte"
|
||||||
import FancyField from "./FancyField.svelte"
|
import FancyField from "./FancyField.svelte"
|
||||||
import Icon from "../Icon/Icon.svelte"
|
import Icon from "../Icon/Icon.svelte"
|
||||||
import Popover from "../Popover/Popover.svelte"
|
|
||||||
import FancyFieldLabel from "./FancyFieldLabel.svelte"
|
import FancyFieldLabel from "./FancyFieldLabel.svelte"
|
||||||
|
import StatusLight from "../StatusLight/StatusLight.svelte"
|
||||||
|
import Picker from "../Form/Core/Picker.svelte"
|
||||||
|
|
||||||
export let label
|
export let label
|
||||||
export let value
|
export let value
|
||||||
|
@ -11,18 +12,30 @@
|
||||||
export let error = null
|
export let error = null
|
||||||
export let validate = null
|
export let validate = null
|
||||||
export let options = []
|
export let options = []
|
||||||
|
export let isOptionEnabled = () => true
|
||||||
export let getOptionLabel = option => extractProperty(option, "label")
|
export let getOptionLabel = option => extractProperty(option, "label")
|
||||||
export let getOptionValue = option => extractProperty(option, "value")
|
export let getOptionValue = option => extractProperty(option, "value")
|
||||||
|
export let getOptionSubtitle = option => extractProperty(option, "subtitle")
|
||||||
|
export let getOptionColour = () => null
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
let open = false
|
let open = false
|
||||||
let popover
|
|
||||||
let wrapper
|
let wrapper
|
||||||
|
|
||||||
$: placeholder = !value
|
$: placeholder = !value
|
||||||
$: selectedLabel = getSelectedLabel(value)
|
$: selectedLabel = getSelectedLabel(value)
|
||||||
|
$: fieldColour = getFieldAttribute(getOptionColour, value, options)
|
||||||
|
|
||||||
|
const getFieldAttribute = (getAttribute, value, options) => {
|
||||||
|
// Wait for options to load if there is a value but no options
|
||||||
|
if (!options?.length) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
const index = options.findIndex(
|
||||||
|
(option, idx) => getOptionValue(option, idx) === value
|
||||||
|
)
|
||||||
|
return index !== -1 ? getAttribute(options[index], index) : null
|
||||||
|
}
|
||||||
const extractProperty = (value, property) => {
|
const extractProperty = (value, property) => {
|
||||||
if (value && typeof value === "object") {
|
if (value && typeof value === "object") {
|
||||||
return value[property]
|
return value[property]
|
||||||
|
@ -64,44 +77,38 @@
|
||||||
<FancyFieldLabel {placeholder}>{label}</FancyFieldLabel>
|
<FancyFieldLabel {placeholder}>{label}</FancyFieldLabel>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
{#if fieldColour}
|
||||||
|
<span class="align">
|
||||||
|
<StatusLight square color={fieldColour} />
|
||||||
|
</span>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<div class="value" class:placeholder>
|
<div class="value" class:placeholder>
|
||||||
{selectedLabel || ""}
|
{selectedLabel || ""}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="arrow">
|
<div class="align">
|
||||||
<Icon name="ChevronDown" />
|
<Icon name="ChevronDown" />
|
||||||
</div>
|
</div>
|
||||||
</FancyField>
|
</FancyField>
|
||||||
|
|
||||||
<Popover
|
<Picker
|
||||||
anchor={wrapper}
|
customAnchor={wrapper}
|
||||||
align="left"
|
onlyPopover={true}
|
||||||
portalTarget={document.documentElement}
|
bind:open
|
||||||
bind:this={popover}
|
{error}
|
||||||
{open}
|
{disabled}
|
||||||
on:close={() => (open = false)}
|
{options}
|
||||||
useAnchorWidth={true}
|
{getOptionLabel}
|
||||||
maxWidth={null}
|
{getOptionValue}
|
||||||
>
|
{getOptionSubtitle}
|
||||||
<div class="popover-content">
|
{getOptionColour}
|
||||||
{#if options.length}
|
{isOptionEnabled}
|
||||||
{#each options as option, idx}
|
isPlaceholder={value == null || value === ""}
|
||||||
<div
|
placeholderOption={placeholder === false ? null : placeholder}
|
||||||
class="popover-option"
|
onSelectOption={onChange}
|
||||||
tabindex="0"
|
isOptionSelected={option => option === value}
|
||||||
on:click={() => onChange(getOptionValue(option, idx))}
|
/>
|
||||||
>
|
|
||||||
<span class="option-text">
|
|
||||||
{getOptionLabel(option, idx)}
|
|
||||||
</span>
|
|
||||||
{#if value === getOptionValue(option, idx)}
|
|
||||||
<Icon name="Checkmark" />
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
{/each}
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
</Popover>
|
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.value {
|
.value {
|
||||||
|
@ -118,30 +125,19 @@
|
||||||
width: 0;
|
width: 0;
|
||||||
transform: translateY(9px);
|
transform: translateY(9px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.align {
|
||||||
|
display: block;
|
||||||
|
font-size: 15px;
|
||||||
|
line-height: 17px;
|
||||||
|
color: var(--spectrum-global-color-gray-900);
|
||||||
|
transition: transform 130ms ease-out, opacity 130ms ease-out;
|
||||||
|
transform: translateY(9px);
|
||||||
|
}
|
||||||
.value.placeholder {
|
.value.placeholder {
|
||||||
transform: translateY(0);
|
transform: translateY(0);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
.popover-content {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: flex-start;
|
|
||||||
align-items: stretch;
|
|
||||||
padding: 7px 0;
|
|
||||||
}
|
|
||||||
.popover-option {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
padding: 7px 16px;
|
|
||||||
transition: background 130ms ease-out;
|
|
||||||
font-size: 15px;
|
|
||||||
}
|
|
||||||
.popover-option:hover {
|
|
||||||
background: var(--spectrum-global-color-gray-200);
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
export let getOptionIcon = () => null
|
export let getOptionIcon = () => null
|
||||||
export let useOptionIconImage = false
|
export let useOptionIconImage = false
|
||||||
export let getOptionColour = () => null
|
export let getOptionColour = () => null
|
||||||
|
export let getOptionSubtitle = () => null
|
||||||
export let open = false
|
export let open = false
|
||||||
export let readonly = false
|
export let readonly = false
|
||||||
export let quiet = false
|
export let quiet = false
|
||||||
|
@ -39,8 +40,8 @@
|
||||||
export let customPopoverHeight
|
export let customPopoverHeight
|
||||||
export let align = "left"
|
export let align = "left"
|
||||||
export let footer = null
|
export let footer = null
|
||||||
export let tag = null
|
export let onlyPopover = false
|
||||||
|
export let customAnchor = null
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
let searchTerm = null
|
let searchTerm = null
|
||||||
|
@ -90,61 +91,62 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<button
|
{#if !onlyPopover}
|
||||||
{id}
|
<button
|
||||||
class="spectrum-Picker spectrum-Picker--sizeM"
|
{id}
|
||||||
class:spectrum-Picker--quiet={quiet}
|
class="spectrum-Picker spectrum-Picker--sizeM"
|
||||||
{disabled}
|
class:spectrum-Picker--quiet={quiet}
|
||||||
class:is-invalid={!!error}
|
{disabled}
|
||||||
class:is-open={open}
|
class:is-invalid={!!error}
|
||||||
aria-haspopup="listbox"
|
class:is-open={open}
|
||||||
on:click={onClick}
|
aria-haspopup="listbox"
|
||||||
bind:this={button}
|
on:click={onClick}
|
||||||
>
|
bind:this={button}
|
||||||
{#if fieldIcon}
|
>
|
||||||
{#if !useOptionIconImage}x
|
{#if fieldIcon}
|
||||||
<span class="option-extra icon">
|
{#if !useOptionIconImage}x
|
||||||
<Icon size="S" name={fieldIcon} />
|
<span class="option-extra icon">
|
||||||
</span>
|
<Icon size="S" name={fieldIcon} />
|
||||||
{:else}
|
</span>
|
||||||
<span class="option-extra icon field-icon">
|
{:else}
|
||||||
<img src={fieldIcon} alt="icon" width="15" height="15" />
|
<span class="option-extra icon field-icon">
|
||||||
|
<img src={fieldIcon} alt="icon" width="15" height="15" />
|
||||||
|
</span>
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
|
{#if fieldColour}
|
||||||
|
<span class="option-extra">
|
||||||
|
<StatusLight square color={fieldColour} />
|
||||||
</span>
|
</span>
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
<span
|
||||||
{#if fieldColour}
|
class="spectrum-Picker-label"
|
||||||
<span class="option-extra">
|
class:is-placeholder={isPlaceholder}
|
||||||
<StatusLight square color={fieldColour} />
|
class:auto-width={autoWidth}
|
||||||
|
>
|
||||||
|
{fieldText}
|
||||||
</span>
|
</span>
|
||||||
{/if}
|
{#if error}
|
||||||
<span
|
<svg
|
||||||
class="spectrum-Picker-label"
|
class="spectrum-Icon spectrum-Icon--sizeM spectrum-Picker-validationIcon"
|
||||||
class:is-placeholder={isPlaceholder}
|
focusable="false"
|
||||||
class:auto-width={autoWidth}
|
aria-hidden="true"
|
||||||
>
|
aria-label="Folder"
|
||||||
{fieldText}
|
>
|
||||||
</span>
|
<use xlink:href="#spectrum-icon-18-Alert" />
|
||||||
{#if error}
|
</svg>
|
||||||
|
{/if}
|
||||||
<svg
|
<svg
|
||||||
class="spectrum-Icon spectrum-Icon--sizeM spectrum-Picker-validationIcon"
|
class="spectrum-Icon spectrum-UIIcon-ChevronDown100 spectrum-Picker-menuIcon"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
aria-label="Folder"
|
|
||||||
>
|
>
|
||||||
<use xlink:href="#spectrum-icon-18-Alert" />
|
<use xlink:href="#spectrum-css-icon-Chevron100" />
|
||||||
</svg>
|
</svg>
|
||||||
{/if}
|
</button>
|
||||||
<svg
|
{/if}
|
||||||
class="spectrum-Icon spectrum-UIIcon-ChevronDown100 spectrum-Picker-menuIcon"
|
|
||||||
focusable="false"
|
|
||||||
aria-hidden="true"
|
|
||||||
>
|
|
||||||
<use xlink:href="#spectrum-css-icon-Chevron100" />
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<Popover
|
<Popover
|
||||||
anchor={button}
|
anchor={!onlyPopover ? button : customAnchor}
|
||||||
align={align || "left"}
|
align={align || "left"}
|
||||||
bind:this={popover}
|
bind:this={popover}
|
||||||
{open}
|
{open}
|
||||||
|
@ -218,6 +220,12 @@
|
||||||
</span>
|
</span>
|
||||||
{/if}
|
{/if}
|
||||||
<span class="spectrum-Menu-itemLabel">
|
<span class="spectrum-Menu-itemLabel">
|
||||||
|
{#if getOptionSubtitle(option, idx)}
|
||||||
|
<span class="subtitle-text"
|
||||||
|
>{getOptionSubtitle(option, idx)}</span
|
||||||
|
>
|
||||||
|
{/if}
|
||||||
|
|
||||||
{getOptionLabel(option, idx)}
|
{getOptionLabel(option, idx)}
|
||||||
</span>
|
</span>
|
||||||
{#if option.tag}
|
{#if option.tag}
|
||||||
|
@ -252,6 +260,17 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.subtitle-text {
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 15px;
|
||||||
|
font-weight: 500;
|
||||||
|
top: 10px;
|
||||||
|
color: var(--spectrum-global-color-gray-600);
|
||||||
|
display: block;
|
||||||
|
margin-bottom: var(--spacing-s);
|
||||||
|
}
|
||||||
|
|
||||||
.spectrum-Picker-label.auto-width {
|
.spectrum-Picker-label.auto-width {
|
||||||
margin-right: var(--spacing-xs);
|
margin-right: var(--spacing-xs);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue