Add support for multiselect type

This commit is contained in:
Andrew Kingston 2023-02-20 19:04:22 +00:00
parent 654c348e4e
commit e26163e274
3 changed files with 74 additions and 49 deletions

View File

@ -0,0 +1,5 @@
<script>
import OptionsCell from "./OptionsCell.svelte"
</script>
<OptionsCell {...$$props} multi />

View File

@ -5,12 +5,14 @@
export let schema
export let selected = false
export let onChange
export let multi = false
const options = schema?.constraints?.inclusion || []
let open = false
$: color = getColor(value)
$: values = Array.isArray(value) ? value : [value].filter(x => x != null)
$: unselectedOptions = options.filter(x => !values.includes(x))
$: {
// Close when deselected
if (!selected) {
@ -26,44 +28,59 @@
return `hsla(${((index + 1) * 222) % 360}, 90%, 75%, 0.3)`
}
const toggle = () => {
open = !open
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:selected
class:open
on:click={selected ? toggle : null}
on:click={selected ? () => (open = true) : null}
>
{#if color}
<div class="badge text" style="--color: {color}">
{value}
</div>
{:else}
<div class="text">
{value || ""}
</div>
{/if}
<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 selected}
<Icon name="ChevronDown" />
{/if}
{#if open}
<div class="options">
{#if value}
<div class="option">
{#each values as val (val)}
{@const color = getColor(val)}
<div class="option" on:click={() => toggleOption(val)}>
<div class="badge text" style="--color: {color}">
{value}
{val}
</div>
<Icon
name="Checkmark"
color="var(--spectrum-global-color-blue-400)"
/>
</div>
{/if}
{#each options.filter(x => x !== value) as option}
<div class="option" on:click={() => onChange(option)}>
{/each}
{#each unselectedOptions as option (option)}
<div class="option" on:click={() => toggleOption(option)}>
<div class="badge text" style="--color: {getColor(option)}">
{option}
</div>
@ -87,11 +104,24 @@
.container.selected: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);

View File

@ -5,6 +5,7 @@
import TextCell from "./TextCell.svelte"
import OptionsCell from "./OptionsCell.svelte"
import DateCell from "./DateCell.svelte"
import MultiSelectCell from "./MultiSelectCell.svelte"
export let table
export let filter
@ -15,7 +16,7 @@
getContext("sdk")
const component = getContext("component")
const limit = 100
const defaultWidth = 200
const defaultWidth = 160
const minWidth = 100
let widths
@ -36,7 +37,6 @@
})
$: fields = Object.keys($fetch.schema || {})
$: initWidths(fields)
$: sliderPositions = getSliderPositions(widths)
$: gridStyles = getGridStyles(widths)
$: schema = $fetch.schema
$: rowCount = $fetch.rows?.length || 0
@ -65,14 +65,7 @@
if (!widths?.length) {
return "--grid: 1fr;"
}
return `--grid: 50px ${widths.map(x => `${x}px`).join(" ")} 180px;`
}
const getSliderPositions = widths => {
let offset = 50
return widths.map(width => {
return (offset += width)
})
return `--grid: 40px ${widths.map(x => `${x}px`).join(" ")} 180px;`
}
const handleScroll = e => {
@ -88,6 +81,8 @@
return OptionsCell
} else if (type === "datetime") {
return DateCell
} else if (type === "array") {
return MultiSelectCell
}
return TextCell
}
@ -262,20 +257,12 @@
<span>
{field}
</span>
<div class="slider" on:mousedown={e => startResizing(fieldIdx, e)} />
</div>
{/each}
<!-- Horizontal spacer -->
<div />
<!-- Sliders for resizing columns -->
{#each sliderPositions as left, idx}
<div
class="slider"
on:mousedown={e => startResizing(idx, e)}
style="--left: {left}px"
/>
{/each}
<!-- All real rows -->
{#each rows as row, rowIdx (row._id)}
{@const rowSelected = !!selectedRows[row._id]}
@ -368,7 +355,7 @@
justify-content: flex-start;
align-items: stretch;
overflow: auto;
max-height: 800px;
max-height: 600px;
position: relative;
cursor: default;
}
@ -444,7 +431,7 @@
}
.cell.sticky {
position: sticky;
left: 50px;
left: 40px;
z-index: 2;
}
.cell.sticky.selected {
@ -479,25 +466,28 @@
/* Column resizing */
.slider {
position: absolute;
z-index: 5;
left: var(--left);
top: 0;
right: 0;
width: 16px;
height: 32px;
transform: translateX(-50%);
height: 100%;
}
.slider:hover:after {
.slider:after {
opacity: 0;
content: " ";
position: absolute;
width: 2px;
left: 50%;
width: 4px;
right: 0;
top: 0;
height: 100%;
background: var(--spectrum-global-color-blue-400);
transform: translateX(-50%);
background: var(--spectrum-global-color-gray-600);
transition: opacity 130ms ease-out;
}
.slider:hover {
cursor: col-resize;
}
.slider:hover:after {
opacity: 1;
}
.sticky.shadow:after {
content: " ";