refactor: remove type assertions in component props

- create proper UncapStarProps and TranscendenceStarProps interfaces
- use discriminated union for StarRender type
- add function overloads for createStarProps with type safety
- remove 'as any' casts from star component spreading
- remove optionalProps workaround in SegmentedControl
- stop spreading HTMLAttributes to RadioGroupPrimitive (not supported)
This commit is contained in:
Justin Edmund 2025-11-28 21:40:08 -08:00
parent 654eabbeba
commit ca16ca145b
2 changed files with 50 additions and 16 deletions

View file

@ -7,7 +7,6 @@
import type { Snippet } from 'svelte' import type { Snippet } from 'svelte'
import styles from './segmented-control.module.scss' import styles from './segmented-control.module.scss'
import type { HTMLAttributes } from 'svelte/elements' import type { HTMLAttributes } from 'svelte/elements'
import { optionalProps } from '$lib/utils/typeShims'
export type SegmentedControlVariant = 'default' | 'blended' | 'background' export type SegmentedControlVariant = 'default' | 'blended' | 'background'
@ -32,8 +31,7 @@
gap = false, gap = false,
class: className, class: className,
wrapperClass, wrapperClass,
children, children
...restProps
}: Props = $props() }: Props = $props()
// Provide variant to child segments via context // Provide variant to child segments via context
@ -85,7 +83,7 @@
</script> </script>
<div class={wrapperClassList}> <div class={wrapperClassList}>
<RadioGroupPrimitive.Root bind:value class={classList} {...(optionalProps(restProps) as any)}> <RadioGroupPrimitive.Root bind:value class={classList}>
{@render children?.()} {@render children?.()}
</RadioGroupPrimitive.Root> </RadioGroupPrimitive.Root>
</div> </div>

View file

@ -19,15 +19,34 @@
updateTranscendence?: ((index: number) => void) | undefined updateTranscendence?: ((index: number) => void) | undefined
} }
interface StarRender { // Props for UncapStar component
type: 'uncap' | 'transcendence' interface UncapStarProps {
props: { empty?: boolean
index?: number special?: boolean
onStarClick?: (index: number, empty: boolean) => void flb?: boolean
[key: string]: any ulb?: boolean
} index: number
tabindex?: number
onStarClick: (index: number, empty: boolean) => void
} }
// Props for TranscendenceStar component
interface TranscendenceStarProps {
className?: string
stage?: number
type?: 'character' | 'weapon' | 'summon'
editable?: boolean
interactive?: boolean
tabindex?: number
onStarClick?: () => void
onFragmentClick?: (newStage: number) => void
onFragmentHover?: (newStage: number) => void
}
type StarRender =
| { type: 'uncap'; props: UncapStarProps }
| { type: 'transcendence'; props: TranscendenceStarProps }
let { let {
type, type,
rarity, rarity,
@ -77,13 +96,26 @@
} }
} }
// Options for creating uncap star props
interface UncapStarOptions {
index: number
flb?: boolean
ulb?: boolean
special?: boolean
}
// Helper function to create star props // Helper function to create star props
const createStarProps = (starType: 'uncap' | 'transcendence', options: any = {}): StarRender => { function createStarProps(starType: 'transcendence'): StarRender
function createStarProps(starType: 'uncap', options: UncapStarOptions): StarRender
function createStarProps(
starType: 'uncap' | 'transcendence',
options?: UncapStarOptions
): StarRender {
if (starType === 'transcendence') { if (starType === 'transcendence') {
return { return {
type: 'transcendence', type: 'transcendence',
props: { props: {
stage: transcendenceStage, stage: transcendenceStage ?? 0,
type, type,
editable, editable,
interactive: editable, interactive: editable,
@ -92,6 +124,10 @@
} }
} }
if (!options) {
throw new Error('Options required for uncap star')
}
return { return {
type: 'uncap', type: 'uncap',
props: { props: {
@ -100,7 +136,7 @@
flb: options.flb, flb: options.flb,
ulb: options.ulb, ulb: options.ulb,
special: options.special, special: options.special,
tabIndex: editable ? 0 : undefined, tabindex: editable ? 0 : undefined,
onStarClick: editable ? toggleStar : () => {} onStarClick: editable ? toggleStar : () => {}
} }
} }
@ -164,9 +200,9 @@
{@const star = renderStar(i)} {@const star = renderStar(i)}
{#if star} {#if star}
{#if star.type === 'transcendence'} {#if star.type === 'transcendence'}
<TranscendenceStar {...(star.props as any)} /> <TranscendenceStar {...star.props} />
{:else} {:else}
<UncapStar {...(star.props as any)} /> <UncapStar {...star.props} />
{/if} {/if}
{/if} {/if}
{/each} {/each}