forked from tsai/budibase
9 changed files with 311 additions and 91 deletions
@ -1 +1,107 @@ |
|||
Select |
|||
<script> |
|||
import "@spectrum-css/picker/dist/index-vars.css" |
|||
import "@spectrum-css/popover/dist/index-vars.css" |
|||
import "@spectrum-css/menu/dist/index-vars.css" |
|||
import { getContext } from "svelte" |
|||
import SpectrumField from "./SpectrumField.svelte" |
|||
|
|||
export let field |
|||
export let label |
|||
export let placeholder |
|||
|
|||
// Register this field with its form |
|||
const { formApi } = getContext("form") ?? {} |
|||
const formField = formApi?.registerField(field) ?? {} |
|||
const { fieldApi, fieldState, fieldSchema } = formField |
|||
|
|||
// Picker state |
|||
let open = false |
|||
$: options = fieldSchema?.constraints?.inclusion ?? [] |
|||
$: placeholderText = placeholder || "Choose an option" |
|||
$: isNull = $fieldState.value == null || $fieldState.value === "" |
|||
|
|||
// Update value on blur only |
|||
const selectOption = value => { |
|||
fieldApi.setValue(value) |
|||
open = false |
|||
} |
|||
</script> |
|||
|
|||
<SpectrumField {field} {label}> |
|||
<button |
|||
id={$fieldState.fieldId} |
|||
class="spectrum-Picker" |
|||
class:is-invalid={!$fieldState.valid} |
|||
class:is-open={open} |
|||
aria-haspopup="listbox" |
|||
on:click={() => (open = true)}> |
|||
<span class="spectrum-Picker-label" class:is-placeholder={isNull}> |
|||
{isNull ? placeholderText : $fieldState.value} |
|||
</span> |
|||
{#if !$fieldState.valid} |
|||
<svg |
|||
class="spectrum-Icon spectrum-Icon--sizeM spectrum-Picker-validationIcon" |
|||
focusable="false" |
|||
aria-hidden="true" |
|||
aria-label="Folder"> |
|||
<use xlink:href="#spectrum-icon-18-Alert" /> |
|||
</svg> |
|||
{/if} |
|||
<svg |
|||
class="spectrum-Icon spectrum-UIIcon-ChevronDown100 spectrum-Picker-menuIcon" |
|||
focusable="false" |
|||
aria-hidden="true"> |
|||
<use xlink:href="#spectrum-css-icon-Chevron100" /> |
|||
</svg> |
|||
</button> |
|||
<div |
|||
class="spectrum-Popover spectrum-Popover--bottom spectrum-Picker-popover" |
|||
class:is-open={open}> |
|||
<ul class="spectrum-Menu" role="listbox"> |
|||
<li |
|||
class="spectrum-Menu-item" |
|||
class:is-selected={isNull} |
|||
role="option" |
|||
aria-selected="true" |
|||
tabindex="0" |
|||
on:click={() => selectOption(null)}> |
|||
<span class="spectrum-Menu-itemLabel">{placeholderText}</span> |
|||
<svg |
|||
class="spectrum-Icon spectrum-UIIcon-Checkmark100 spectrum-Menu-checkmark spectrum-Menu-itemIcon" |
|||
focusable="false" |
|||
aria-hidden="true"> |
|||
<use xlink:href="#spectrum-css-icon-Checkmark100" /> |
|||
</svg> |
|||
</li> |
|||
{#each options as option} |
|||
<li |
|||
class="spectrum-Menu-item" |
|||
class:is-selected={option === $fieldState.value} |
|||
role="option" |
|||
aria-selected="true" |
|||
tabindex="0" |
|||
on:click={() => selectOption(option)}> |
|||
<span class="spectrum-Menu-itemLabel">{option}</span> |
|||
<svg |
|||
class="spectrum-Icon spectrum-UIIcon-Checkmark100 spectrum-Menu-checkmark spectrum-Menu-itemIcon" |
|||
focusable="false" |
|||
aria-hidden="true"> |
|||
<use xlink:href="#spectrum-css-icon-Checkmark100" /> |
|||
</svg> |
|||
</li> |
|||
{/each} |
|||
</ul> |
|||
</div> |
|||
{#if $fieldState.error} |
|||
<div class="error">{$fieldState.error}</div> |
|||
{/if} |
|||
</SpectrumField> |
|||
|
|||
<style> |
|||
.error { |
|||
color: var( |
|||
--spectrum-semantic-negative-color-default, |
|||
var(--spectrum-global-color-red-500) |
|||
) !important; |
|||
} |
|||
</style> |
|||
|
|||
@ -0,0 +1,36 @@ |
|||
<script> |
|||
import Placeholder from "./Placeholder.svelte" |
|||
import { getContext } from "svelte" |
|||
|
|||
export let label |
|||
export let field |
|||
|
|||
const formContext = getContext("form") |
|||
const { styleable } = getContext("sdk") |
|||
const component = getContext("component") |
|||
const { labelPosition, formApi } = formContext || {} |
|||
const formField = formApi?.registerField(field) ?? {} |
|||
const { fieldId } = formField |
|||
|
|||
$: labelPositionClass = |
|||
labelPosition === "top" ? "" : `spectrum-FieldLabel--${labelPosition}` |
|||
</script> |
|||
|
|||
{#if !fieldId} |
|||
<Placeholder>Add the Field setting to start using your component</Placeholder> |
|||
{:else if !formContext} |
|||
<Placeholder>Form components need to be wrapped in a Form</Placeholder> |
|||
{:else} |
|||
<div class="spectrum-Form-item" use:styleable={$component.styles}> |
|||
{#if label} |
|||
<label |
|||
for={fieldId} |
|||
class={`spectrum-FieldLabel spectrum-FieldLabel--sizeM spectrum-Form-itemLabel ${labelPositionClass}`}> |
|||
{label} |
|||
</label> |
|||
{/if} |
|||
<div class="spectrum-Form-itemField"> |
|||
<slot /> |
|||
</div> |
|||
</div> |
|||
{/if} |
|||
Loading…
Reference in new issue