add CheckboxGroup component for multiselect fields
This commit is contained in:
parent
f26d3e3883
commit
96f040a91b
2 changed files with 105 additions and 2 deletions
|
|
@ -5,6 +5,7 @@
|
||||||
import Input from './Input.svelte'
|
import Input from './Input.svelte'
|
||||||
import Select from './Select.svelte'
|
import Select from './Select.svelte'
|
||||||
import Checkbox from './checkbox/Checkbox.svelte'
|
import Checkbox from './checkbox/Checkbox.svelte'
|
||||||
|
import CheckboxGroup from './checkbox/CheckboxGroup.svelte'
|
||||||
import DatePicker from './DatePicker.svelte'
|
import DatePicker from './DatePicker.svelte'
|
||||||
|
|
||||||
interface SelectOption {
|
interface SelectOption {
|
||||||
|
|
@ -29,10 +30,10 @@
|
||||||
label: string
|
label: string
|
||||||
/** Secondary label displayed below the main label */
|
/** Secondary label displayed below the main label */
|
||||||
sublabel?: string
|
sublabel?: string
|
||||||
value?: string | number | boolean | null | undefined
|
value?: string | number | boolean | number[] | null | undefined
|
||||||
children?: Snippet
|
children?: Snippet
|
||||||
editable?: boolean
|
editable?: boolean
|
||||||
type?: 'text' | 'number' | 'select' | 'checkbox' | 'date'
|
type?: 'text' | 'number' | 'select' | 'checkbox' | 'date' | 'multiselect'
|
||||||
options?: SelectOption[]
|
options?: SelectOption[]
|
||||||
placeholder?: string
|
placeholder?: string
|
||||||
element?: 'wind' | 'fire' | 'water' | 'earth' | 'dark' | 'light'
|
element?: 'wind' | 'fire' | 'water' | 'earth' | 'dark' | 'light'
|
||||||
|
|
@ -70,6 +71,12 @@
|
||||||
size="medium"
|
size="medium"
|
||||||
contained
|
contained
|
||||||
/>
|
/>
|
||||||
|
{:else if type === 'multiselect' && options}
|
||||||
|
<CheckboxGroup
|
||||||
|
bind:value={value as number[]}
|
||||||
|
options={options as { value: number; label: string }[]}
|
||||||
|
{element}
|
||||||
|
/>
|
||||||
{:else if type === 'checkbox'}
|
{:else if type === 'checkbox'}
|
||||||
<Checkbox
|
<Checkbox
|
||||||
checked={checkboxValue}
|
checked={checkboxValue}
|
||||||
|
|
|
||||||
96
src/lib/components/ui/checkbox/CheckboxGroup.svelte
Normal file
96
src/lib/components/ui/checkbox/CheckboxGroup.svelte
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
<svelte:options runes={true} />
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import Checkbox from './Checkbox.svelte'
|
||||||
|
|
||||||
|
interface Option {
|
||||||
|
value: number
|
||||||
|
label: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
/** Array of selected values */
|
||||||
|
value?: number[]
|
||||||
|
/** Available options */
|
||||||
|
options: Option[]
|
||||||
|
/** Disable all checkboxes */
|
||||||
|
disabled?: boolean
|
||||||
|
/** Layout direction */
|
||||||
|
direction?: 'row' | 'column'
|
||||||
|
/** Element color theme for checked state */
|
||||||
|
element?: 'wind' | 'fire' | 'water' | 'earth' | 'dark' | 'light' | undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
let {
|
||||||
|
value = $bindable([]),
|
||||||
|
options,
|
||||||
|
disabled = false,
|
||||||
|
direction = 'row',
|
||||||
|
element
|
||||||
|
}: Props = $props()
|
||||||
|
|
||||||
|
function isChecked(optionValue: number): boolean {
|
||||||
|
return value.includes(optionValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleChange(optionValue: number, checked: boolean) {
|
||||||
|
if (checked) {
|
||||||
|
value = [...value, optionValue]
|
||||||
|
} else {
|
||||||
|
value = value.filter((v) => v !== optionValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="checkbox-group {direction}">
|
||||||
|
{#each options as option (option.value)}
|
||||||
|
<label class="checkbox-option">
|
||||||
|
<Checkbox
|
||||||
|
checked={isChecked(option.value)}
|
||||||
|
onCheckedChange={(checked) => handleChange(option.value, checked)}
|
||||||
|
{disabled}
|
||||||
|
{element}
|
||||||
|
size="small"
|
||||||
|
/>
|
||||||
|
<span class="option-label">{option.label}</span>
|
||||||
|
</label>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@use '$src/themes/spacing' as *;
|
||||||
|
@use '$src/themes/colors' as *;
|
||||||
|
@use '$src/themes/typography' as *;
|
||||||
|
|
||||||
|
.checkbox-group {
|
||||||
|
display: flex;
|
||||||
|
gap: $unit;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
&.column {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.row {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-option {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: $unit-half;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover .option-label {
|
||||||
|
color: $grey-30;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-label {
|
||||||
|
font-size: $font-small;
|
||||||
|
color: $grey-50;
|
||||||
|
user-select: none;
|
||||||
|
transition: color 0.15s ease;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Loading…
Reference in a new issue