budibase/packages/client/src/components/app/spreadsheet/OptionsCell.svelte

164 lines
3.5 KiB
Svelte

<script>
import { Icon } from "@budibase/bbui"
export let value
export let schema
export let onChange
export let selected = false
export let multi = false
export let readonly = false
const options = schema?.constraints?.inclusion || []
let open = false
$: editable = selected && !readonly
$: values = Array.isArray(value) ? value : [value].filter(x => x != null)
$: unselectedOptions = options.filter(x => !values.includes(x))
$: {
// Close when deselected
if (!selected) {
open = false
}
}
const getColor = value => {
const index = options.indexOf(value)
if (!value || index === -1) {
return null
}
return `hsla(${((index + 1) * 222) % 360}, 90%, 75%, 0.3)`
}
const toggleOption = option => {
if (!multi) {
onChange(option)
} else {
if (values.includes(option)) {
onChange(values.filter(x => x !== option))
} else {
onChange([...values, option])
}
}
}
</script>
<div
class="container"
class:multi
class:editable
class:open
on:click={editable ? () => (open = true) : null}
>
<div class="values">
{#each values as val (val)}
{@const color = getColor(val)}
{#if color}
<div class="badge text" style="--color: {color}">
{val}
</div>
{:else}
<div class="text">
{val || ""}
</div>
{/if}
{/each}
</div>
{#if editable}
<Icon name="ChevronDown" />
{/if}
{#if open}
<div class="options">
{#each values as val (val)}
{@const color = getColor(val)}
<div class="option" on:click={() => toggleOption(val)}>
<div class="badge text" style="--color: {color}">
{val}
</div>
<Icon
name="Checkmark"
color="var(--spectrum-global-color-blue-400)"
/>
</div>
{/each}
{#each unselectedOptions as option (option)}
<div class="option" on:click={() => toggleOption(option)}>
<div class="badge text" style="--color: {getColor(option)}">
{option}
</div>
</div>
{/each}
</div>
{/if}
</div>
<style>
.container {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
padding: 0 8px;
flex: 1 1 auto;
overflow: hidden;
gap: 4px;
}
.container.editable:hover {
cursor: pointer;
}
.values {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
flex: 1 1 auto;
width: 0;
gap: 4px;
overflow: hidden;
}
.text {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.multi .text {
flex: 0 0 auto;
}
.badge {
padding: 2px 8px;
background: var(--color);
border-radius: 8px;
user-select: none;
}
.options {
min-width: 100%;
position: absolute;
top: 0;
left: 0;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
box-shadow: 0 0 8px 4px rgba(0, 0, 0, 0.15);
max-height: 191px;
overflow-y: auto;
z-index: 1;
}
.option {
flex: 0 0 32px;
padding: 0 8px;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
gap: 4px;
background-color: var(--spectrum-global-color-gray-50);
}
.option:first-child {
flex: 0 0 31px;
}
.option:hover {
background-color: var(--spectrum-global-color-gray-100);
}
</style>