Update all design panel settings and styles to use new spectrum components
This commit is contained in:
parent
eeac45d3e7
commit
90bcd87d24
|
@ -43,7 +43,8 @@
|
||||||
use:clickOutside={hide}
|
use:clickOutside={hide}
|
||||||
style={menuStyle}
|
style={menuStyle}
|
||||||
on:keydown={handleEscape}
|
on:keydown={handleEscape}
|
||||||
class="spectrum-Popover is-open" role="presentation">
|
class="spectrum-Popover is-open"
|
||||||
|
role="presentation">
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</Portal>
|
</Portal>
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
import "@spectrum-css/popover/dist/index-vars.css"
|
import "@spectrum-css/popover/dist/index-vars.css"
|
||||||
import "@spectrum-css/menu/dist/index-vars.css"
|
import "@spectrum-css/menu/dist/index-vars.css"
|
||||||
import { fly } from "svelte/transition"
|
import { fly } from "svelte/transition"
|
||||||
|
import { createEventDispatcher } from "svelte"
|
||||||
|
|
||||||
export let id = null
|
export let id = null
|
||||||
export let disabled = false
|
export let disabled = false
|
||||||
|
@ -16,6 +17,16 @@
|
||||||
export let getOptionLabel = option => option
|
export let getOptionLabel = option => option
|
||||||
export let getOptionValue = option => option
|
export let getOptionValue = option => option
|
||||||
export let open = false
|
export let open = false
|
||||||
|
export let readonly = false
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
const onClick = () => {
|
||||||
|
dispatch("click")
|
||||||
|
if (readonly) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
open = true
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
|
@ -25,7 +36,7 @@
|
||||||
class:is-invalid={!!error}
|
class:is-invalid={!!error}
|
||||||
class:is-open={open}
|
class:is-open={open}
|
||||||
aria-haspopup="listbox"
|
aria-haspopup="listbox"
|
||||||
on:click={() => (open = true)}>
|
on:click={onClick}>
|
||||||
<span class="spectrum-Picker-label" class:is-placeholder={isPlaceholder}>
|
<span class="spectrum-Picker-label" class:is-placeholder={isPlaceholder}>
|
||||||
{fieldText}
|
{fieldText}
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
export let options = []
|
export let options = []
|
||||||
export let getOptionLabel = option => option
|
export let getOptionLabel = option => option
|
||||||
export let getOptionValue = option => option
|
export let getOptionValue = option => option
|
||||||
|
export let readonly = false
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
let open = false
|
let open = false
|
||||||
|
@ -38,10 +39,12 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Picker
|
<Picker
|
||||||
|
on:click
|
||||||
bind:open
|
bind:open
|
||||||
{id}
|
{id}
|
||||||
{error}
|
{error}
|
||||||
{disabled}
|
{disabled}
|
||||||
|
{readonly}
|
||||||
{fieldText}
|
{fieldText}
|
||||||
{options}
|
{options}
|
||||||
{getOptionLabel}
|
{getOptionLabel}
|
||||||
|
|
|
@ -8,11 +8,15 @@
|
||||||
export let disabled = false
|
export let disabled = false
|
||||||
export let error = null
|
export let error = null
|
||||||
export let id = null
|
export let id = null
|
||||||
|
export let readonly = false
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
let focus = false
|
let focus = false
|
||||||
|
|
||||||
const updateValue = value => {
|
const updateValue = value => {
|
||||||
|
if (readonly) {
|
||||||
|
return
|
||||||
|
}
|
||||||
if (type === "number") {
|
if (type === "number") {
|
||||||
const float = parseFloat(value)
|
const float = parseFloat(value)
|
||||||
value = isNaN(float) ? null : float
|
value = isNaN(float) ? null : float
|
||||||
|
@ -20,12 +24,25 @@
|
||||||
dispatch("change", value)
|
dispatch("change", value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onFocus = () => {
|
||||||
|
if (readonly) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
focus = true
|
||||||
|
}
|
||||||
|
|
||||||
const onBlur = event => {
|
const onBlur = event => {
|
||||||
|
if (readonly) {
|
||||||
|
return
|
||||||
|
}
|
||||||
focus = false
|
focus = false
|
||||||
updateValue(event.target.value)
|
updateValue(event.target.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateValueOnEnter = event => {
|
const updateValueOnEnter = event => {
|
||||||
|
if (readonly) {
|
||||||
|
return
|
||||||
|
}
|
||||||
if (event.key === "Enter") {
|
if (event.key === "Enter") {
|
||||||
updateValue(event.target.value)
|
updateValue(event.target.value)
|
||||||
}
|
}
|
||||||
|
@ -46,13 +63,15 @@
|
||||||
</svg>
|
</svg>
|
||||||
{/if}
|
{/if}
|
||||||
<input
|
<input
|
||||||
|
on:click
|
||||||
on:keyup={updateValueOnEnter}
|
on:keyup={updateValueOnEnter}
|
||||||
{disabled}
|
{disabled}
|
||||||
|
{readonly}
|
||||||
{id}
|
{id}
|
||||||
value={value || ''}
|
value={value || ''}
|
||||||
placeholder={placeholder || ''}
|
placeholder={placeholder || ''}
|
||||||
on:blur={onBlur}
|
on:blur={onBlur}
|
||||||
on:focus={() => (focus = true)}
|
on:focus={onFocus}
|
||||||
{type}
|
{type}
|
||||||
class="spectrum-Textfield-input" />
|
class="spectrum-Textfield-input" />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
export let placeholder = null
|
export let placeholder = null
|
||||||
export let type = "text"
|
export let type = "text"
|
||||||
export let disabled = false
|
export let disabled = false
|
||||||
|
export let readonly = false
|
||||||
export let error = null
|
export let error = null
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
|
@ -22,8 +23,10 @@
|
||||||
<TextField
|
<TextField
|
||||||
{error}
|
{error}
|
||||||
{disabled}
|
{disabled}
|
||||||
|
{readonly}
|
||||||
{value}
|
{value}
|
||||||
{placeholder}
|
{placeholder}
|
||||||
{type}
|
{type}
|
||||||
on:change={onChange} />
|
on:change={onChange}
|
||||||
|
on:click />
|
||||||
</Field>
|
</Field>
|
||||||
|
|
|
@ -3,9 +3,10 @@
|
||||||
import Multiselect from "./Core/Multiselect.svelte"
|
import Multiselect from "./Core/Multiselect.svelte"
|
||||||
import Field from "./Field.svelte"
|
import Field from "./Field.svelte"
|
||||||
|
|
||||||
export let value = null
|
export let value = []
|
||||||
export let label = []
|
export let label = null
|
||||||
export let disabled = false
|
export let disabled = false
|
||||||
|
export let readonly = false
|
||||||
export let labelPosition = "above"
|
export let labelPosition = "above"
|
||||||
export let error = null
|
export let error = null
|
||||||
export let placeholder = null
|
export let placeholder = null
|
||||||
|
@ -29,5 +30,6 @@
|
||||||
{placeholder}
|
{placeholder}
|
||||||
{getOptionLabel}
|
{getOptionLabel}
|
||||||
{getOptionValue}
|
{getOptionValue}
|
||||||
on:change={onChange} />
|
on:change={onChange}
|
||||||
|
on:click />
|
||||||
</Field>
|
</Field>
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
export let value = null
|
export let value = null
|
||||||
export let label = undefined
|
export let label = undefined
|
||||||
export let disabled = false
|
export let disabled = false
|
||||||
|
export let readonly = false
|
||||||
export let labelPosition = "above"
|
export let labelPosition = "above"
|
||||||
export let error = null
|
export let error = null
|
||||||
export let placeholder = "Choose an option"
|
export let placeholder = "Choose an option"
|
||||||
|
@ -30,10 +31,12 @@
|
||||||
<Select
|
<Select
|
||||||
{error}
|
{error}
|
||||||
{disabled}
|
{disabled}
|
||||||
|
{readonly}
|
||||||
{value}
|
{value}
|
||||||
{options}
|
{options}
|
||||||
{placeholder}
|
{placeholder}
|
||||||
{getOptionLabel}
|
{getOptionLabel}
|
||||||
{getOptionValue}
|
{getOptionValue}
|
||||||
on:change={onChange} />
|
on:change={onChange}
|
||||||
|
on:click />
|
||||||
</Field>
|
</Field>
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
Button,
|
Button,
|
||||||
Icon,
|
Icon,
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
|
Divider,
|
||||||
|
Select,
|
||||||
Spacer,
|
Spacer,
|
||||||
Heading,
|
Heading,
|
||||||
Drawer,
|
Drawer,
|
||||||
|
@ -27,6 +29,7 @@
|
||||||
export let otherSources
|
export let otherSources
|
||||||
export let showAllQueries
|
export let showAllQueries
|
||||||
|
|
||||||
|
$: text = value?.label ?? "Choose an option"
|
||||||
$: tables = $tablesStore.list.map(m => ({
|
$: tables = $tablesStore.list.map(m => ({
|
||||||
label: m.name,
|
label: m.name,
|
||||||
tableId: m._id,
|
tableId: m._id,
|
||||||
|
@ -92,14 +95,12 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="container">
|
<div class="container" bind:this={anchorRight}>
|
||||||
<div
|
<Select
|
||||||
class="dropdownbutton"
|
readonly
|
||||||
bind:this={anchorRight}
|
value={text}
|
||||||
on:click={dropdownRight.show}>
|
options={[text]}
|
||||||
<span>{value?.label ?? 'Choose option'}</span>
|
on:click={dropdownRight.show} />
|
||||||
<Icon name="arrowdown" />
|
|
||||||
</div>
|
|
||||||
{#if value?.type === 'query'}
|
{#if value?.type === 'query'}
|
||||||
<i class="ri-settings-5-line" on:click={drawer.show} />
|
<i class="ri-settings-5-line" on:click={drawer.show} />
|
||||||
<Drawer title={'Query Parameters'} bind:this={drawer}>
|
<Drawer title={'Query Parameters'} bind:this={drawer}>
|
||||||
|
@ -148,7 +149,7 @@
|
||||||
</li>
|
</li>
|
||||||
{/each}
|
{/each}
|
||||||
</ul>
|
</ul>
|
||||||
<hr />
|
<Divider s />
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<Heading xs h3>Views</Heading>
|
<Heading xs h3>Views</Heading>
|
||||||
</div>
|
</div>
|
||||||
|
@ -161,9 +162,9 @@
|
||||||
</li>
|
</li>
|
||||||
{/each}
|
{/each}
|
||||||
</ul>
|
</ul>
|
||||||
<hr />
|
<Divider s />
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<Heading extraSmall>Relationships</Heading>
|
<Heading xs h3>Relationships</Heading>
|
||||||
</div>
|
</div>
|
||||||
<ul>
|
<ul>
|
||||||
{#each links as link}
|
{#each links as link}
|
||||||
|
@ -174,10 +175,9 @@
|
||||||
</li>
|
</li>
|
||||||
{/each}
|
{/each}
|
||||||
</ul>
|
</ul>
|
||||||
|
<Divider s />
|
||||||
<hr />
|
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<Heading extraSmall>Queries</Heading>
|
<Heading xs h3>Queries</Heading>
|
||||||
</div>
|
</div>
|
||||||
<ul>
|
<ul>
|
||||||
{#each queries as query}
|
{#each queries as query}
|
||||||
|
@ -190,7 +190,7 @@
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
{#if otherSources?.length}
|
{#if otherSources?.length}
|
||||||
<hr />
|
<Divider s />
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<Heading extraSmall>Other</Heading>
|
<Heading extraSmall>Other</Heading>
|
||||||
</div>
|
</div>
|
||||||
|
@ -214,45 +214,16 @@
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
.container :global(:first-child) {
|
||||||
.dropdownbutton {
|
|
||||||
background-color: var(--grey-2);
|
|
||||||
border: var(--border-transparent);
|
|
||||||
padding: var(--spacing-s) var(--spacing-m);
|
|
||||||
border-radius: var(--border-radius-m);
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
overflow: hidden;
|
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
}
|
}
|
||||||
.dropdownbutton:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
background-color: var(--grey-3);
|
|
||||||
}
|
|
||||||
.dropdownbutton span {
|
|
||||||
white-space: nowrap;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
overflow: hidden;
|
|
||||||
flex: 1 1 auto;
|
|
||||||
text-align: left;
|
|
||||||
font-size: var(--font-size-xs);
|
|
||||||
}
|
|
||||||
.dropdownbutton :global(svg) {
|
|
||||||
margin: -4px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dropdown {
|
.dropdown {
|
||||||
padding: var(--spacing-m) 0;
|
padding: var(--spacing-m) 0;
|
||||||
z-index: 99999999;
|
z-index: 99999999;
|
||||||
}
|
}
|
||||||
.title {
|
.title {
|
||||||
padding: 0 var(--spacing-m) var(--spacing-xs) var(--spacing-m);
|
padding: 0 var(--spacing-m) var(--spacing-s) var(--spacing-m);
|
||||||
}
|
|
||||||
|
|
||||||
hr {
|
|
||||||
margin: var(--spacing-m) 0 var(--spacing-xl) 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
|
|
|
@ -1,25 +1,41 @@
|
||||||
<script>
|
<script>
|
||||||
import OptionSelect from "./OptionSelect.svelte"
|
import { Select } from "@budibase/bbui"
|
||||||
import MultiOptionSelect from "./MultiOptionSelect.svelte"
|
|
||||||
import {
|
import {
|
||||||
getDatasourceForProvider,
|
getDatasourceForProvider,
|
||||||
getSchemaForDatasource,
|
getSchemaForDatasource,
|
||||||
} from "builderStore/dataBinding"
|
} from "builderStore/dataBinding"
|
||||||
import { currentAsset } from "builderStore"
|
import { currentAsset } from "builderStore"
|
||||||
|
import { createEventDispatcher } from "svelte"
|
||||||
|
|
||||||
export let componentInstance = {}
|
export let componentInstance = {}
|
||||||
export let value = ""
|
export let value = ""
|
||||||
export let onChange = () => {}
|
|
||||||
export let multiselect = false
|
export let multiselect = false
|
||||||
export let placeholder
|
export let placeholder
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
$: datasource = getDatasourceForProvider($currentAsset, componentInstance)
|
$: datasource = getDatasourceForProvider($currentAsset, componentInstance)
|
||||||
$: schema = getSchemaForDatasource(datasource).schema
|
$: schema = getSchemaForDatasource(datasource).schema
|
||||||
$: options = Object.keys(schema || {})
|
$: options = Object.keys(schema || {})
|
||||||
|
$: boundValue = getValidValue(value, options)
|
||||||
|
|
||||||
|
const getValidValue = (value, options) => {
|
||||||
|
// Reset value if there aren't any options
|
||||||
|
if (!Array.isArray(options)) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset value if the value isn't found in the options
|
||||||
|
if (options.indexOf(value) === -1) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
const onChange = value => {
|
||||||
|
boundValue = getValidValue(value.detail, options)
|
||||||
|
dispatch("change", boundValue)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if multiselect}
|
<Select {placeholder} value={boundValue} on:change={onChange} {options} />
|
||||||
<MultiOptionSelect {value} {onChange} {options} {placeholder} />
|
|
||||||
{:else}
|
|
||||||
<OptionSelect {value} {onChange} {options} {placeholder} />
|
|
||||||
{/if}
|
|
||||||
|
|
|
@ -5,9 +5,9 @@
|
||||||
export let value
|
export let value
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Select bind:value extraThin secondary on:change>
|
<Select
|
||||||
<option value="">Choose an option</option>
|
bind:value
|
||||||
{#each $store.layouts as layout}
|
on:change
|
||||||
<option value={layout._id}>{layout.name}</option>
|
options={$store.layouts}
|
||||||
{/each}
|
getOptionLabel={layout => layout.name}
|
||||||
</Select>
|
getOptionValue={layout => layout._id} />
|
||||||
|
|
|
@ -1,5 +1,35 @@
|
||||||
<script>
|
<script>
|
||||||
import FieldSelect from "./FieldSelect.svelte"
|
import { Multiselect } from "@budibase/bbui"
|
||||||
|
import {
|
||||||
|
getDatasourceForProvider,
|
||||||
|
getSchemaForDatasource,
|
||||||
|
} from "builderStore/dataBinding"
|
||||||
|
import { currentAsset } from "builderStore"
|
||||||
|
import { createEventDispatcher } from "svelte"
|
||||||
|
|
||||||
|
export let componentInstance = {}
|
||||||
|
export let value = ""
|
||||||
|
export let multiselect = false
|
||||||
|
export let placeholder
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
$: datasource = getDatasourceForProvider($currentAsset, componentInstance)
|
||||||
|
$: schema = getSchemaForDatasource(datasource).schema
|
||||||
|
$: options = Object.keys(schema || {})
|
||||||
|
$: boundValue = getValidOptions(value, options)
|
||||||
|
|
||||||
|
const getValidOptions = (selectedOptions, allOptions) => {
|
||||||
|
// Fix the hardcoded default string value
|
||||||
|
if (!Array.isArray(selectedOptions)) {
|
||||||
|
selectedOptions = []
|
||||||
|
}
|
||||||
|
return selectedOptions.filter(val => allOptions.indexOf(val) !== -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
const setValue = value => {
|
||||||
|
boundValue = getValidOptions(value.detail, options)
|
||||||
|
dispatch("change", boundValue)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FieldSelect {...$$props} multiselect />
|
<Multiselect {placeholder} value={boundValue} on:change={setValue} {options} />
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
<script>
|
|
||||||
import { Multiselect } from "@budibase/bbui"
|
|
||||||
|
|
||||||
export let options = []
|
|
||||||
export let value = []
|
|
||||||
export let onChange = () => {}
|
|
||||||
export let placeholder
|
|
||||||
|
|
||||||
let boundValue = getValidOptions(value, options)
|
|
||||||
|
|
||||||
function getValidOptions(selectedOptions, allOptions) {
|
|
||||||
// Fix the hardcoded default string value
|
|
||||||
if (!Array.isArray(selectedOptions)) {
|
|
||||||
selectedOptions = []
|
|
||||||
}
|
|
||||||
return selectedOptions.filter(val => allOptions.indexOf(val) !== -1)
|
|
||||||
}
|
|
||||||
|
|
||||||
function setValue(value) {
|
|
||||||
boundValue = getValidOptions(value.detail, options)
|
|
||||||
onChange(boundValue)
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<Multiselect
|
|
||||||
align="right"
|
|
||||||
extraThin
|
|
||||||
secondary
|
|
||||||
{placeholder}
|
|
||||||
value={boundValue}
|
|
||||||
on:change={setValue}>
|
|
||||||
{#each options as option}
|
|
||||||
<option value={option}>{option}</option>
|
|
||||||
{/each}
|
|
||||||
</Multiselect>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
div {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,257 +0,0 @@
|
||||||
<script>
|
|
||||||
import { onMount } from "svelte"
|
|
||||||
import Portal from "svelte-portal"
|
|
||||||
import { buildStyle } from "../../../../helpers.js"
|
|
||||||
|
|
||||||
export let options = []
|
|
||||||
export let value = ""
|
|
||||||
export let styleBindingProperty
|
|
||||||
export let onChange = () => {}
|
|
||||||
export let placeholder
|
|
||||||
|
|
||||||
let open = null
|
|
||||||
let rotate = ""
|
|
||||||
let select
|
|
||||||
let selectMenu
|
|
||||||
let icon
|
|
||||||
let width = 0
|
|
||||||
|
|
||||||
let selectAnchor = null
|
|
||||||
let dimensions = { top: 0, bottom: 0, left: 0 }
|
|
||||||
|
|
||||||
let positionSide = "top"
|
|
||||||
let maxHeight = 0
|
|
||||||
let scrollTop = 0
|
|
||||||
let containerEl = null
|
|
||||||
|
|
||||||
const handleStyleBind = value =>
|
|
||||||
!!styleBindingProperty ? { style: `${styleBindingProperty}: ${value}` } : {}
|
|
||||||
|
|
||||||
onMount(() => {
|
|
||||||
if (select) {
|
|
||||||
select.addEventListener("keydown", handleEnter)
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
select.removeEventListener("keydown", handleEnter)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
function handleEscape(e) {
|
|
||||||
if (open && e.key === "Escape") {
|
|
||||||
toggleSelect(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getDimensions() {
|
|
||||||
const {
|
|
||||||
bottom,
|
|
||||||
top: spaceAbove,
|
|
||||||
left,
|
|
||||||
} = selectAnchor.getBoundingClientRect()
|
|
||||||
const spaceBelow = window.innerHeight - bottom
|
|
||||||
|
|
||||||
let y
|
|
||||||
|
|
||||||
if (spaceAbove > spaceBelow) {
|
|
||||||
positionSide = "bottom"
|
|
||||||
maxHeight = spaceAbove - 20
|
|
||||||
y = window.innerHeight - spaceAbove
|
|
||||||
} else {
|
|
||||||
positionSide = "top"
|
|
||||||
y = bottom
|
|
||||||
maxHeight = spaceBelow - 20
|
|
||||||
}
|
|
||||||
|
|
||||||
dimensions = { [positionSide]: y, left }
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleEnter(e) {
|
|
||||||
if (!open && e.key === "Enter") {
|
|
||||||
toggleSelect(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleSelect(isOpen) {
|
|
||||||
getDimensions()
|
|
||||||
if (isOpen) {
|
|
||||||
icon.style.transform = "rotate(180deg)"
|
|
||||||
} else {
|
|
||||||
icon.style.transform = "rotate(0deg)"
|
|
||||||
}
|
|
||||||
open = isOpen
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleClick(val) {
|
|
||||||
value = val
|
|
||||||
onChange(value)
|
|
||||||
toggleSelect(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
$: menuStyle = buildStyle({
|
|
||||||
"max-height": `${maxHeight.toFixed(0)}px`,
|
|
||||||
"transform-origin": `center ${positionSide}`,
|
|
||||||
[positionSide]: `${dimensions[positionSide]}px`,
|
|
||||||
left: `${dimensions.left.toFixed(0)}px`,
|
|
||||||
width: `${width}px`,
|
|
||||||
})
|
|
||||||
|
|
||||||
$: isOptionsObject = options.every(o => typeof o === "object")
|
|
||||||
|
|
||||||
$: selectedOption = isOptionsObject
|
|
||||||
? options.find(o => o.value === value || (o.value === "" && value == null))
|
|
||||||
: {}
|
|
||||||
|
|
||||||
$: if (open && selectMenu) {
|
|
||||||
selectMenu.focus()
|
|
||||||
}
|
|
||||||
|
|
||||||
$: displayLabel =
|
|
||||||
selectedOption && selectedOption.label
|
|
||||||
? selectedOption.label
|
|
||||||
: value || placeholder || "Choose option"
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div
|
|
||||||
bind:clientWidth={width}
|
|
||||||
tabindex="0"
|
|
||||||
bind:this={select}
|
|
||||||
class="bb-select-container"
|
|
||||||
on:click={() => toggleSelect(!open)}>
|
|
||||||
<div bind:this={selectAnchor} title={value} class="bb-select-anchor selected">
|
|
||||||
<span>{displayLabel}</span>
|
|
||||||
<i bind:this={icon} class="ri-arrow-down-s-fill" />
|
|
||||||
</div>
|
|
||||||
{#if open}
|
|
||||||
<Portal>
|
|
||||||
<div
|
|
||||||
tabindex="0"
|
|
||||||
class:open
|
|
||||||
bind:this={selectMenu}
|
|
||||||
style={menuStyle}
|
|
||||||
on:keydown={handleEscape}
|
|
||||||
class="bb-select-menu">
|
|
||||||
<ul>
|
|
||||||
<li
|
|
||||||
on:click|self={() => handleClick(null)}
|
|
||||||
class:selected={value == null || value === ''}>
|
|
||||||
Choose option
|
|
||||||
</li>
|
|
||||||
{#if isOptionsObject}
|
|
||||||
{#each options as { value: v, label }}
|
|
||||||
<li
|
|
||||||
{...handleStyleBind(v)}
|
|
||||||
on:click|self={() => handleClick(v)}
|
|
||||||
class:selected={value === v}>
|
|
||||||
{label}
|
|
||||||
</li>
|
|
||||||
{/each}
|
|
||||||
{:else}
|
|
||||||
{#each options as v}
|
|
||||||
<li
|
|
||||||
{...handleStyleBind(v)}
|
|
||||||
on:click|self={() => handleClick(v)}
|
|
||||||
class:selected={value === v}>
|
|
||||||
{v}
|
|
||||||
</li>
|
|
||||||
{/each}
|
|
||||||
{/if}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div on:click|self={() => toggleSelect(false)} class="overlay" />
|
|
||||||
</Portal>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.overlay {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
left: 0;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bb-select-container {
|
|
||||||
outline: none;
|
|
||||||
cursor: pointer;
|
|
||||||
overflow: hidden;
|
|
||||||
flex: 1 1 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bb-select-anchor {
|
|
||||||
cursor: pointer;
|
|
||||||
display: flex;
|
|
||||||
padding: var(--spacing-s) var(--spacing-m);
|
|
||||||
background-color: var(--grey-2);
|
|
||||||
border-radius: var(--border-radius-m);
|
|
||||||
align-items: center;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bb-select-anchor > span {
|
|
||||||
color: var(--ink);
|
|
||||||
font-weight: 400;
|
|
||||||
overflow-x: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
font-size: var(--font-size-xs);
|
|
||||||
flex: 1 1 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bb-select-anchor > i {
|
|
||||||
transition: transform 0.13s ease;
|
|
||||||
transform-origin: center;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.selected {
|
|
||||||
color: var(--ink);
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bb-select-menu {
|
|
||||||
position: absolute;
|
|
||||||
display: flex;
|
|
||||||
outline: none;
|
|
||||||
box-sizing: border-box;
|
|
||||||
flex-direction: column;
|
|
||||||
opacity: 0;
|
|
||||||
z-index: 2;
|
|
||||||
color: var(--ink);
|
|
||||||
font-weight: 400;
|
|
||||||
height: fit-content !important;
|
|
||||||
border-bottom-left-radius: 2px;
|
|
||||||
border-bottom-right-radius: 2px;
|
|
||||||
background-color: var(--grey-2);
|
|
||||||
transform: scale(0);
|
|
||||||
transition: opacity 0.13s linear, transform 0.12s cubic-bezier(0, 0, 0.2, 1);
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.open {
|
|
||||||
transform: scale(1);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul {
|
|
||||||
list-style-type: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: 5px 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
li {
|
|
||||||
height: auto;
|
|
||||||
padding: 5px 0px;
|
|
||||||
cursor: pointer;
|
|
||||||
padding-left: 10px;
|
|
||||||
font-size: var(--font-size-xs);
|
|
||||||
}
|
|
||||||
|
|
||||||
li:hover {
|
|
||||||
background-color: var(--grey-3);
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -5,9 +5,9 @@
|
||||||
export let value
|
export let value
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Select bind:value extraThin secondary on:change>
|
<Select
|
||||||
<option value="">Choose an option</option>
|
bind:value
|
||||||
{#each $roles as role}
|
on:change
|
||||||
<option value={role._id}>{role.name}</option>
|
options={$roles}
|
||||||
{/each}
|
getOptionLabel={role => role.name}
|
||||||
</Select>
|
getOptionValue={role => role._id} />
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
"settings": [
|
"settings": [
|
||||||
{
|
{
|
||||||
"type": "dataProvider",
|
"type": "dataProvider",
|
||||||
"label": "Data",
|
"label": "Provider",
|
||||||
"key": "dataProvider"
|
"key": "dataProvider"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -529,7 +529,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "dataProvider",
|
"type": "dataProvider",
|
||||||
"label": "Data",
|
"label": "Provider",
|
||||||
"key": "dataProvider"
|
"key": "dataProvider"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -629,7 +629,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "dataProvider",
|
"type": "dataProvider",
|
||||||
"label": "Data",
|
"label": "Provider",
|
||||||
"key": "dataProvider"
|
"key": "dataProvider"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -730,7 +730,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "dataProvider",
|
"type": "dataProvider",
|
||||||
"label": "Data",
|
"label": "Provider",
|
||||||
"key": "dataProvider"
|
"key": "dataProvider"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -843,7 +843,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "dataProvider",
|
"type": "dataProvider",
|
||||||
"label": "Data",
|
"label": "Provider",
|
||||||
"key": "dataProvider"
|
"key": "dataProvider"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -920,7 +920,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "dataProvider",
|
"type": "dataProvider",
|
||||||
"label": "Data",
|
"label": "Provider",
|
||||||
"key": "dataProvider"
|
"key": "dataProvider"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -997,7 +997,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "dataProvider",
|
"type": "dataProvider",
|
||||||
"label": "Data",
|
"label": "Provider",
|
||||||
"key": "dataProvider"
|
"key": "dataProvider"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1482,7 +1482,7 @@
|
||||||
"settings": [
|
"settings": [
|
||||||
{
|
{
|
||||||
"type": "dataProvider",
|
"type": "dataProvider",
|
||||||
"label": "Data Provider",
|
"label": "Provider",
|
||||||
"key": "dataProvider"
|
"key": "dataProvider"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue