update picker to allow only popover

This commit is contained in:
Peter Clement 2023-08-29 14:41:34 +01:00
parent ac2389c445
commit e88efe2d1a
2 changed files with 116 additions and 101 deletions

View File

@ -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>

View File

@ -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);
} }