Add support for multiselect type
This commit is contained in:
parent
654c348e4e
commit
e26163e274
|
@ -0,0 +1,5 @@
|
||||||
|
<script>
|
||||||
|
import OptionsCell from "./OptionsCell.svelte"
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<OptionsCell {...$$props} multi />
|
|
@ -5,12 +5,14 @@
|
||||||
export let schema
|
export let schema
|
||||||
export let selected = false
|
export let selected = false
|
||||||
export let onChange
|
export let onChange
|
||||||
|
export let multi = false
|
||||||
|
|
||||||
const options = schema?.constraints?.inclusion || []
|
const options = schema?.constraints?.inclusion || []
|
||||||
|
|
||||||
let open = false
|
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
|
// Close when deselected
|
||||||
if (!selected) {
|
if (!selected) {
|
||||||
|
@ -26,44 +28,59 @@
|
||||||
return `hsla(${((index + 1) * 222) % 360}, 90%, 75%, 0.3)`
|
return `hsla(${((index + 1) * 222) % 360}, 90%, 75%, 0.3)`
|
||||||
}
|
}
|
||||||
|
|
||||||
const toggle = () => {
|
const toggleOption = option => {
|
||||||
open = !open
|
if (!multi) {
|
||||||
|
onChange(option)
|
||||||
|
} else {
|
||||||
|
if (values.includes(option)) {
|
||||||
|
onChange(values.filter(x => x !== option))
|
||||||
|
} else {
|
||||||
|
onChange([...values, option])
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="container"
|
class="container"
|
||||||
|
class:multi
|
||||||
class:selected
|
class:selected
|
||||||
class:open
|
class:open
|
||||||
on:click={selected ? toggle : null}
|
on:click={selected ? () => (open = true) : null}
|
||||||
>
|
>
|
||||||
|
<div class="values">
|
||||||
|
{#each values as val (val)}
|
||||||
|
{@const color = getColor(val)}
|
||||||
{#if color}
|
{#if color}
|
||||||
<div class="badge text" style="--color: {color}">
|
<div class="badge text" style="--color: {color}">
|
||||||
{value}
|
{val}
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="text">
|
<div class="text">
|
||||||
{value || ""}
|
{val || ""}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
{#if selected}
|
{#if selected}
|
||||||
<Icon name="ChevronDown" />
|
<Icon name="ChevronDown" />
|
||||||
{/if}
|
{/if}
|
||||||
{#if open}
|
{#if open}
|
||||||
<div class="options">
|
<div class="options">
|
||||||
{#if value}
|
{#each values as val (val)}
|
||||||
<div class="option">
|
{@const color = getColor(val)}
|
||||||
|
<div class="option" on:click={() => toggleOption(val)}>
|
||||||
<div class="badge text" style="--color: {color}">
|
<div class="badge text" style="--color: {color}">
|
||||||
{value}
|
{val}
|
||||||
</div>
|
</div>
|
||||||
<Icon
|
<Icon
|
||||||
name="Checkmark"
|
name="Checkmark"
|
||||||
color="var(--spectrum-global-color-blue-400)"
|
color="var(--spectrum-global-color-blue-400)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/each}
|
||||||
{#each options.filter(x => x !== value) as option}
|
{#each unselectedOptions as option (option)}
|
||||||
<div class="option" on:click={() => onChange(option)}>
|
<div class="option" on:click={() => toggleOption(option)}>
|
||||||
<div class="badge text" style="--color: {getColor(option)}">
|
<div class="badge text" style="--color: {getColor(option)}">
|
||||||
{option}
|
{option}
|
||||||
</div>
|
</div>
|
||||||
|
@ -87,11 +104,24 @@
|
||||||
.container.selected:hover {
|
.container.selected:hover {
|
||||||
cursor: pointer;
|
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 {
|
.text {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
.multi .text {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
.badge {
|
.badge {
|
||||||
padding: 2px 8px;
|
padding: 2px 8px;
|
||||||
background: var(--color);
|
background: var(--color);
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
import TextCell from "./TextCell.svelte"
|
import TextCell from "./TextCell.svelte"
|
||||||
import OptionsCell from "./OptionsCell.svelte"
|
import OptionsCell from "./OptionsCell.svelte"
|
||||||
import DateCell from "./DateCell.svelte"
|
import DateCell from "./DateCell.svelte"
|
||||||
|
import MultiSelectCell from "./MultiSelectCell.svelte"
|
||||||
|
|
||||||
export let table
|
export let table
|
||||||
export let filter
|
export let filter
|
||||||
|
@ -15,7 +16,7 @@
|
||||||
getContext("sdk")
|
getContext("sdk")
|
||||||
const component = getContext("component")
|
const component = getContext("component")
|
||||||
const limit = 100
|
const limit = 100
|
||||||
const defaultWidth = 200
|
const defaultWidth = 160
|
||||||
const minWidth = 100
|
const minWidth = 100
|
||||||
|
|
||||||
let widths
|
let widths
|
||||||
|
@ -36,7 +37,6 @@
|
||||||
})
|
})
|
||||||
$: fields = Object.keys($fetch.schema || {})
|
$: fields = Object.keys($fetch.schema || {})
|
||||||
$: initWidths(fields)
|
$: initWidths(fields)
|
||||||
$: sliderPositions = getSliderPositions(widths)
|
|
||||||
$: gridStyles = getGridStyles(widths)
|
$: gridStyles = getGridStyles(widths)
|
||||||
$: schema = $fetch.schema
|
$: schema = $fetch.schema
|
||||||
$: rowCount = $fetch.rows?.length || 0
|
$: rowCount = $fetch.rows?.length || 0
|
||||||
|
@ -65,14 +65,7 @@
|
||||||
if (!widths?.length) {
|
if (!widths?.length) {
|
||||||
return "--grid: 1fr;"
|
return "--grid: 1fr;"
|
||||||
}
|
}
|
||||||
return `--grid: 50px ${widths.map(x => `${x}px`).join(" ")} 180px;`
|
return `--grid: 40px ${widths.map(x => `${x}px`).join(" ")} 180px;`
|
||||||
}
|
|
||||||
|
|
||||||
const getSliderPositions = widths => {
|
|
||||||
let offset = 50
|
|
||||||
return widths.map(width => {
|
|
||||||
return (offset += width)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleScroll = e => {
|
const handleScroll = e => {
|
||||||
|
@ -88,6 +81,8 @@
|
||||||
return OptionsCell
|
return OptionsCell
|
||||||
} else if (type === "datetime") {
|
} else if (type === "datetime") {
|
||||||
return DateCell
|
return DateCell
|
||||||
|
} else if (type === "array") {
|
||||||
|
return MultiSelectCell
|
||||||
}
|
}
|
||||||
return TextCell
|
return TextCell
|
||||||
}
|
}
|
||||||
|
@ -262,20 +257,12 @@
|
||||||
<span>
|
<span>
|
||||||
{field}
|
{field}
|
||||||
</span>
|
</span>
|
||||||
|
<div class="slider" on:mousedown={e => startResizing(fieldIdx, e)} />
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
<!-- Horizontal spacer -->
|
<!-- Horizontal spacer -->
|
||||||
<div />
|
<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 -->
|
<!-- All real rows -->
|
||||||
{#each rows as row, rowIdx (row._id)}
|
{#each rows as row, rowIdx (row._id)}
|
||||||
{@const rowSelected = !!selectedRows[row._id]}
|
{@const rowSelected = !!selectedRows[row._id]}
|
||||||
|
@ -368,7 +355,7 @@
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
max-height: 800px;
|
max-height: 600px;
|
||||||
position: relative;
|
position: relative;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
@ -444,7 +431,7 @@
|
||||||
}
|
}
|
||||||
.cell.sticky {
|
.cell.sticky {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
left: 50px;
|
left: 40px;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
.cell.sticky.selected {
|
.cell.sticky.selected {
|
||||||
|
@ -479,25 +466,28 @@
|
||||||
/* Column resizing */
|
/* Column resizing */
|
||||||
.slider {
|
.slider {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 5;
|
|
||||||
left: var(--left);
|
|
||||||
top: 0;
|
top: 0;
|
||||||
|
right: 0;
|
||||||
width: 16px;
|
width: 16px;
|
||||||
height: 32px;
|
height: 100%;
|
||||||
transform: translateX(-50%);
|
|
||||||
}
|
}
|
||||||
.slider:hover:after {
|
.slider:after {
|
||||||
|
opacity: 0;
|
||||||
content: " ";
|
content: " ";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 2px;
|
width: 4px;
|
||||||
left: 50%;
|
right: 0;
|
||||||
|
top: 0;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: var(--spectrum-global-color-blue-400);
|
background: var(--spectrum-global-color-gray-600);
|
||||||
transform: translateX(-50%);
|
transition: opacity 130ms ease-out;
|
||||||
}
|
}
|
||||||
.slider:hover {
|
.slider:hover {
|
||||||
cursor: col-resize;
|
cursor: col-resize;
|
||||||
}
|
}
|
||||||
|
.slider:hover:after {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.sticky.shadow:after {
|
.sticky.shadow:after {
|
||||||
content: " ";
|
content: " ";
|
||||||
|
|
Loading…
Reference in New Issue