action select: add frameless, support custom button content
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
<script lang="ts" module>
|
||||
export type ActionSelectOption = {
|
||||
/** value is a convenience field, it has no internal use */
|
||||
value?: string;
|
||||
icon?: IconDef | Snippet<[opt: ActionSelectOption]>;
|
||||
label: string | Snippet<[opt: ActionSelectOption]>;
|
||||
@@ -19,6 +18,7 @@
|
||||
import type { IconDef } from './util';
|
||||
|
||||
interface Props {
|
||||
name?: string;
|
||||
label?: string;
|
||||
placeholder?: string;
|
||||
value?: ActionSelectOption;
|
||||
@@ -27,10 +27,13 @@
|
||||
sameWidth?: boolean;
|
||||
options: ActionSelectOption[];
|
||||
class?: ClassValue | null | undefined;
|
||||
frameless?: boolean;
|
||||
onchange?: (value: ActionSelectOption | undefined) => void;
|
||||
children?: Snippet;
|
||||
}
|
||||
|
||||
let {
|
||||
name,
|
||||
label,
|
||||
placeholder = 'Choose an action',
|
||||
value = $bindable(undefined),
|
||||
@@ -39,7 +42,9 @@
|
||||
sameWidth = true,
|
||||
options,
|
||||
class: classValue,
|
||||
onchange
|
||||
frameless = false,
|
||||
onchange,
|
||||
children
|
||||
}: Props = $props();
|
||||
|
||||
const select = new Select<ActionSelectOption>({
|
||||
@@ -84,24 +89,35 @@
|
||||
<Label {...select.label}>{label}</Label>
|
||||
{/if}
|
||||
|
||||
{#if name}
|
||||
<input type="hidden" {name} value={value?.value} />
|
||||
{/if}
|
||||
|
||||
<Button
|
||||
bind:ref={buttonElement}
|
||||
class={['flex w-full items-center rounded-xl!']}
|
||||
class={[
|
||||
'flex w-full items-center rounded-xl!',
|
||||
frameless && 'hover:bg-sui-text-100/50 bg-transparent',
|
||||
frameless && select.open && 'bg-sui-text-100/50!'
|
||||
]}
|
||||
{...select.trigger}
|
||||
{...!tabbable && { tabindex: -1 }}
|
||||
>
|
||||
{#if stateless || !select.value}
|
||||
{placeholder}
|
||||
{#if children}{@render children()}
|
||||
{:else}
|
||||
{@render optionIcon(select.value)}
|
||||
{@render optionLabel(select.value)}
|
||||
{/if}
|
||||
{#if stateless || !select.value}
|
||||
{placeholder}
|
||||
{:else}
|
||||
{@render optionIcon(select.value)}
|
||||
{@render optionLabel(select.value)}
|
||||
{/if}
|
||||
|
||||
<CaretDown
|
||||
weight="bold"
|
||||
size="1.1em"
|
||||
class={[select.open && '-scale-y-100', 'ml-auto transition-transform']}
|
||||
/>
|
||||
<CaretDown
|
||||
weight="bold"
|
||||
size="1.1em"
|
||||
class={[select.open && '-scale-y-100', 'ml-auto transition-transform']}
|
||||
/>
|
||||
{/if}
|
||||
</Button>
|
||||
|
||||
<div
|
||||
@@ -127,7 +143,7 @@
|
||||
{@render optionIcon(option)}
|
||||
{@render optionLabel(option)}
|
||||
|
||||
{#if !stateless && select.isSelected(option)}
|
||||
{#if !stateless && select.value?.label === option.label}
|
||||
<Check size="1.1em" weight="bold" class={['ml-auto']} />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
import {
|
||||
ArrowUUpLeft,
|
||||
ArrowUUpRight,
|
||||
DotsThreeOutlineVertical,
|
||||
Plus,
|
||||
TextB,
|
||||
TextItalic,
|
||||
@@ -76,7 +77,7 @@
|
||||
</div>
|
||||
|
||||
<div class="component">
|
||||
<p class="title">Button Select</p>
|
||||
<p class="title">Action Select</p>
|
||||
|
||||
<div class="flex gap-2">
|
||||
<ActionSelect
|
||||
@@ -104,6 +105,15 @@
|
||||
}
|
||||
]}
|
||||
/>
|
||||
<ActionSelect
|
||||
class="mt-7"
|
||||
options={[{ label: 'Option 1' }, { label: 'Option 2' }, { label: 'Option 3' }]}
|
||||
sameWidth={false}
|
||||
frameless={true}
|
||||
stateless={true}
|
||||
>
|
||||
<DotsThreeOutlineVertical class="text-sui-text" size="1.2em" />
|
||||
</ActionSelect>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user