Skip to content

Commit

Permalink
Added basic Select component
Browse files Browse the repository at this point in the history
  • Loading branch information
sureshjoshi committed Dec 10, 2024
1 parent e60e510 commit bfc351c
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 1 deletion.
82 changes: 82 additions & 0 deletions src/lib/select/Select.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<script lang="ts">
import { type Component, type Snippet } from "svelte";
import { useId } from "$lib/internal/hooks/use-id";
import { useLabelledBy } from "$lib/label/LabelProvider.svelte";
import { useDisabled } from "$lib/internal/DisabledProvider.svelte";
type Props = {
/** The element or component the select should render as. */
as?: string | Component;
/** Whether or not the select should receive focus when first rendered. */
autofocus?: boolean;
/** Whether or not the select is disabled. */
disabled?: boolean;
/** Whether or not the select is invalid. */
invalid?: boolean;
children?: Snippet<[SnippetProps]>;
};
type SnippetProps = {
/** Whether or not the select is in an active or pressed state.*/
active?: boolean;
/** Whether or not the autofocus prop was set to true. */
autofocus?: boolean;
/** Whether or not the select is disabled. */
disabled?: boolean;
/** Whether or not the select is focused. */
focus?: boolean;
/** Whether or not the select is hovered. */
hover?: boolean;
/** Whether or not the select is invalid. */
invalid?: boolean;
};
let {
id = `headlessui-select-${useId()}`,
as = "select",
autofocus = false,
disabled = useDisabled() || false,
invalid = false,
children,
...theirProps
}: Props & Record<string, any> = $props();
let labelledBy = $derived(useLabelledBy());
let ourProps = $derived({
id,
autofocus,
disabled,
"aria-invalid": invalid, // ? "" : undefined,
"aria-labelledby": labelledBy?.[0],
// "aria-describedby": describedBy,
});
let snippetProps: SnippetProps = $derived({
autofocus,
disabled,
focus: false,
hover: false,
invalid,
});
// TODO: Utility function to create this
let dataAttributes: DataAttributes<SnippetProps> = $derived({
"data-autofocus": autofocus || undefined,
"data-disabled": disabled || undefined,
"data-focus": invalid || undefined,
"data-hover": invalid || undefined,
"data-invalid": invalid || undefined,
});
</script>

{#if typeof as === "string"}
<svelte:element this={as} {...theirProps} {...ourProps} {...dataAttributes}>
{@render children?.(snippetProps)}
</svelte:element>
{:else}
{@const AsComponent = as}
<AsComponent {...theirProps} {...ourProps} {...dataAttributes}>
{@render children?.(snippetProps)}
</AsComponent>
{/if}
18 changes: 18 additions & 0 deletions src/lib/select/select.dom.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import Select from "./Select.svelte";
import { getInput, getSelect } from "../../test-utils/accessibility-assertions";
import { focus, type, word } from "../../test-utils/interactions";
import {
commonControlScenarios,
commonFormScenarios,
commonRenderingScenarios,
} from "../../test-utils/scenarios.dom";

commonRenderingScenarios(Select, { getElement: getSelect });
commonControlScenarios(Select);
commonFormScenarios(Select, {
async performUserInteraction(control) {
if (control instanceof HTMLSelectElement) {
control.value = 'alice'
}
},
});
2 changes: 1 addition & 1 deletion src/routes/(main)/nav.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script lang="ts">
const components = ["button", "checkbox", "fieldset", "input", "switch", "textarea"];
const components = ["button", "checkbox", "fieldset", "input", "select", "switch", "textarea"];
</script>

<nav>
Expand Down
28 changes: 28 additions & 0 deletions src/routes/examples/select/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<script lang="ts">
// import Description from "$lib/description/Description.svelte";
import Field from "$lib/field/Field.svelte";
import Label from "$lib/label/Label.svelte";
import Select from "$lib/select/Select.svelte";
</script>

<div class="w-full max-w-md px-4">
<Field>
<Label class="text-sm/6 font-medium text-white">Project status</Label>
<!-- <Description class="text-sm/6 text-white/50">This will be visible to clients on the project.</Description> -->
<div class="relative">
<Select
class="mt-3 block w-full appearance-none rounded-lg border-none bg-white/5 py-1.5 px-3 text-sm/6 text-white focus:outline-none data-[focus]:outline-2 data-[focus]:-outline-offset-2 data-[focus]:outline-white/25 *:text-black"
>
<option value="active">Active</option>
<option value="paused">Paused</option>
<option value="delayed">Delayed</option>
<option value="canceled">Canceled</option>
</Select>

<!-- <ChevronDownIcon
class="group pointer-events-none absolute top-2.5 right-2.5 size-4 fill-white/60"
aria-hidden="true"
/> -->
</div>
</Field>
</div>

0 comments on commit bfc351c

Please sign in to comment.