fix: bits-ui component type mismatches with exactOptionalPropertyTypes

- Select.svelte: Use conditional spreading for optional `disabled` prop and `value` prop
- Switch.svelte: Conditionally spread `name` and `value` props
- Segment/RepSegment: Remove HTMLButtonAttributes extension and handle disabled prop properly
- Replace inline `import('svelte').Snippet` with proper import statements

Fixes type errors where bits-ui prop types don't include explicit `undefined` for optional properties, which conflicts with `exactOptionalPropertyTypes: true`.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Justin Edmund 2025-11-28 18:05:27 -08:00
parent 67eb624bfc
commit a4b9e0e30a
5 changed files with 46 additions and 16 deletions

View file

@ -92,7 +92,13 @@
</Label.Root>
{/if}
<SelectPrimitive.Root type="single" value={value !== undefined && value !== null ? String(value) : undefined} onValueChange={handleValueChange} {disabled} items={stringOptions}>
<SelectPrimitive.Root
type="single"
{...(value !== undefined && value !== null ? { value: String(value) } : {})}
onValueChange={handleValueChange}
{disabled}
items={stringOptions}
>
<SelectPrimitive.Trigger class={selectClasses} data-placeholder={!selected}>
{#if selected?.image}
<img src={selected.image} alt={selected.label} class="image" />
@ -104,7 +110,11 @@
<SelectPrimitive.Content class="content">
<SelectPrimitive.Viewport>
{#each options as option}
<SelectPrimitive.Item value={String(option.value)} disabled={option.disabled} class="item">
<SelectPrimitive.Item
value={String(option.value)}
{...(option.disabled !== undefined ? { disabled: option.disabled } : {})}
class="item"
>
{#snippet children({ selected })}
{#if option.image}
<img src={option.image} alt={option.label} class="image" />
@ -127,7 +137,14 @@
{/if}
</fieldset>
{:else}
<SelectPrimitive.Root type="single" value={value !== undefined && value !== null ? String(value) : undefined} onValueChange={handleValueChange} {disabled} items={stringOptions} class={className}>
<SelectPrimitive.Root
type="single"
{...(value !== undefined && value !== null ? { value: String(value) } : {})}
onValueChange={handleValueChange}
{disabled}
items={stringOptions}
class={className}
>
<SelectPrimitive.Trigger class={selectClasses} data-placeholder={!selected}>
{#if selected?.image}
<img src={selected.image} alt={selected.label} class="image" />
@ -139,7 +156,11 @@
<SelectPrimitive.Content class="content">
<SelectPrimitive.Viewport>
{#each options as option}
<SelectPrimitive.Item value={String(option.value)} disabled={option.disabled} class="item">
<SelectPrimitive.Item
value={String(option.value)}
{...(option.disabled !== undefined ? { disabled: option.disabled } : {})}
class="item"
>
{#snippet children({ selected })}
{#if option.image}
<img src={option.image} alt={option.label} class="image" />

View file

@ -3,14 +3,16 @@
<script lang="ts">
import { RadioGroup as RadioGroupPrimitive } from 'bits-ui'
import type { Snippet } from 'svelte'
import styles from './rep-segment.module.scss'
import type { HTMLButtonAttributes } from 'svelte/elements'
interface Props extends Omit<HTMLButtonAttributes, 'value'> {
interface Props {
value: string
label: string
class?: string
selected?: boolean
disabled?: boolean
children?: Snippet
}
let {
@ -18,15 +20,15 @@
label,
class: className,
selected = false,
children: content,
...restProps
disabled,
children: content
}: Props = $props()
</script>
<RadioGroupPrimitive.Item
{value}
{...(disabled !== undefined ? { disabled } : {})}
class={`${styles.repSegment} ${selected ? styles.selected : ''} ${className || ''}`}
{...restProps}
>
{#snippet children({ checked })}
{#if checked}

View file

@ -4,16 +4,18 @@
<script lang="ts">
import { RadioGroup as RadioGroupPrimitive } from 'bits-ui'
import { getContext } from 'svelte'
import type { Snippet } from 'svelte'
import styles from './segment.module.scss'
import type { HTMLButtonAttributes } from 'svelte/elements'
import type { SegmentedControlVariant } from './SegmentedControl.svelte'
interface Props extends Omit<HTMLButtonAttributes, 'value'> {
interface Props {
value: string
class?: string
disabled?: boolean
children?: Snippet
}
let { value, class: className, children: content, ...restProps }: Props = $props()
let { value, class: className, disabled, children: content }: Props = $props()
// Get variant from parent context
const variant = getContext<SegmentedControlVariant>('segmented-control-variant') || 'default'
@ -36,7 +38,11 @@
)
</script>
<RadioGroupPrimitive.Item {value} class={segmentClass} {...restProps}>
<RadioGroupPrimitive.Item
{value}
{...(disabled !== undefined ? { disabled } : {})}
class={segmentClass}
>
{#snippet children({ checked })}
{#if checked}
<div class={styles.indicator}></div>

View file

@ -4,6 +4,7 @@
<script lang="ts">
import { RadioGroup as RadioGroupPrimitive } from 'bits-ui'
import { setContext } from 'svelte'
import type { Snippet } from 'svelte'
import styles from './segmented-control.module.scss'
import type { HTMLAttributes } from 'svelte/elements'
@ -18,7 +19,7 @@
gap?: boolean
class?: string
wrapperClass?: string
children?: import('svelte').Snippet
children?: Snippet
}
let {

View file

@ -36,8 +36,8 @@
bind:checked
{disabled}
{required}
{name}
{value}
{...(name !== undefined ? { name } : {})}
{...(value !== undefined ? { value } : {})}
class="switch {className || ''}"
>
<SwitchPrimitive.Thumb class="thumb {thumbClass || ''}" />