action select: add frameless, support custom button content

This commit is contained in:
Elijah Duffy
2025-07-11 14:06:46 -07:00
parent 56c5b90629
commit c99b1a2899
2 changed files with 41 additions and 15 deletions

View File

@@ -1,6 +1,5 @@
<script lang="ts" module> <script lang="ts" module>
export type ActionSelectOption = { export type ActionSelectOption = {
/** value is a convenience field, it has no internal use */
value?: string; value?: string;
icon?: IconDef | Snippet<[opt: ActionSelectOption]>; icon?: IconDef | Snippet<[opt: ActionSelectOption]>;
label: string | Snippet<[opt: ActionSelectOption]>; label: string | Snippet<[opt: ActionSelectOption]>;
@@ -19,6 +18,7 @@
import type { IconDef } from './util'; import type { IconDef } from './util';
interface Props { interface Props {
name?: string;
label?: string; label?: string;
placeholder?: string; placeholder?: string;
value?: ActionSelectOption; value?: ActionSelectOption;
@@ -27,10 +27,13 @@
sameWidth?: boolean; sameWidth?: boolean;
options: ActionSelectOption[]; options: ActionSelectOption[];
class?: ClassValue | null | undefined; class?: ClassValue | null | undefined;
frameless?: boolean;
onchange?: (value: ActionSelectOption | undefined) => void; onchange?: (value: ActionSelectOption | undefined) => void;
children?: Snippet;
} }
let { let {
name,
label, label,
placeholder = 'Choose an action', placeholder = 'Choose an action',
value = $bindable(undefined), value = $bindable(undefined),
@@ -39,7 +42,9 @@
sameWidth = true, sameWidth = true,
options, options,
class: classValue, class: classValue,
onchange frameless = false,
onchange,
children
}: Props = $props(); }: Props = $props();
const select = new Select<ActionSelectOption>({ const select = new Select<ActionSelectOption>({
@@ -84,12 +89,22 @@
<Label {...select.label}>{label}</Label> <Label {...select.label}>{label}</Label>
{/if} {/if}
{#if name}
<input type="hidden" {name} value={value?.value} />
{/if}
<Button <Button
bind:ref={buttonElement} 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} {...select.trigger}
{...!tabbable && { tabindex: -1 }} {...!tabbable && { tabindex: -1 }}
> >
{#if children}{@render children()}
{:else}
{#if stateless || !select.value} {#if stateless || !select.value}
{placeholder} {placeholder}
{:else} {:else}
@@ -102,6 +117,7 @@
size="1.1em" size="1.1em"
class={[select.open && '-scale-y-100', 'ml-auto transition-transform']} class={[select.open && '-scale-y-100', 'ml-auto transition-transform']}
/> />
{/if}
</Button> </Button>
<div <div
@@ -127,7 +143,7 @@
{@render optionIcon(option)} {@render optionIcon(option)}
{@render optionLabel(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']} /> <Check size="1.1em" weight="bold" class={['ml-auto']} />
{/if} {/if}
</div> </div>

View File

@@ -22,6 +22,7 @@
import { import {
ArrowUUpLeft, ArrowUUpLeft,
ArrowUUpRight, ArrowUUpRight,
DotsThreeOutlineVertical,
Plus, Plus,
TextB, TextB,
TextItalic, TextItalic,
@@ -76,7 +77,7 @@
</div> </div>
<div class="component"> <div class="component">
<p class="title">Button Select</p> <p class="title">Action Select</p>
<div class="flex gap-2"> <div class="flex gap-2">
<ActionSelect <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>
</div> </div>