component LanguageSwitcher { outputs { change(payload: { locale: string }) } props { locales: unknown[] = [] current: string = "en" label: string = "Language" placeholder: string = "Choose language" helperText: string = "" variant: string = "select" compact: boolean = false responsive: boolean = true fullWidth: boolean = false showLabel: boolean = true showHelper: boolean = true icon: string = "icon-[lucide--languages]" color: string = "primary" size: string = "md" class: string = "" } functions { client function changed(sourceEvent) { output.change({ locale: sourceEvent.currentTarget.value }) } client function selected(locale, sourceEvent) { output.change({ locale: locale }) } } view {
{#if variant == "segmented"}
{#if showLabel}{label}{/if}
{#each locales as locale} {/each}
{#if showHelper && helperText}{helperText}{/if}
{/if} {#if variant != "segmented"} {/if}
} style { .wire-language-switcher { min-width: 13rem; color: var(--wire-color-text); } .wire-language-switcher--full, .wire-language-switcher--full .wire-language-switcher__field { width: 100%; } .wire-language-switcher__field, .wire-language-switcher__fieldset { display: flex; margin: 0; padding: 0; border: 0; flex-direction: column; gap: .4rem; } .wire-language-switcher__label { padding: 0; font-size: .8125rem; line-height: 1.2; font-weight: 650; color: var(--wire-color-text); } .wire-language-switcher__control { position: relative; display: flex; align-items: center; } .wire-language-switcher__select { width: 100%; min-height: 2.75rem; appearance: none; border: 1px solid var(--wire-color-border); border-radius: var(--wire-radius-lg); background: var(--wire-color-surface); padding: .65rem 2.5rem .65rem 2.35rem; color: var(--wire-color-text); font: inherit; font-size: .875rem; font-weight: 550; box-shadow: 0 1px 2px color-mix(in srgb, var(--wire-color-text) 7%, transparent); outline: none; transition: border-color .16s ease, box-shadow .16s ease, background .16s ease; } .wire-language-switcher__select:hover { border-color: color-mix(in srgb, var(--wire-color-primary) 45%, var(--wire-color-border)); } .wire-language-switcher__select:focus-visible { border-color: var(--wire-color-primary); box-shadow: 0 0 0 3px color-mix(in srgb, var(--wire-color-primary) 18%, transparent); } .wire-language-switcher__icon, .wire-language-switcher__chevron { position: absolute; z-index: 1; width: 1rem; height: 1rem; pointer-events: none; color: var(--wire-color-muted); } .wire-language-switcher__icon { left: .8rem; } .wire-language-switcher__chevron { right: .8rem; } .wire-language-switcher__helper { font-size: .72rem; line-height: 1.35; color: var(--wire-color-muted); } .wire-language-switcher--compact { min-width: 0; } .wire-language-switcher--compact .wire-language-switcher__label, .wire-language-switcher--compact .wire-language-switcher__helper { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; } .wire-language-switcher--compact .wire-language-switcher__select { min-height: 2.25rem; border-radius: 999px; padding-top: .4rem; padding-bottom: .4rem; } .wire-language-switcher__segments { display: inline-flex; flex-wrap: wrap; gap: .25rem; border: 1px solid var(--wire-color-border); border-radius: var(--wire-radius-xl); background: var(--wire-color-surface-2); padding: .25rem; } .wire-language-switcher__segment { min-height: 2.25rem; border: 0; border-radius: var(--wire-radius-lg); background: transparent; padding: .45rem .8rem; color: var(--wire-color-muted); font: inherit; font-size: .8125rem; font-weight: 650; cursor: pointer; transition: color .16s ease, background .16s ease, box-shadow .16s ease; } .wire-language-switcher__segment:hover { color: var(--wire-color-text); } .wire-language-switcher__segment[aria-pressed="true"] { background: var(--wire-color-surface); color: var(--wire-color-primary); box-shadow: 0 1px 3px color-mix(in srgb, var(--wire-color-text) 12%, transparent); } .wire-language-switcher__segment:focus-visible { outline: 2px solid var(--wire-color-primary); outline-offset: 2px; } .wire-language-switcher__short-label { display: none; } @media (max-width: 640px) { .wire-language-switcher--responsive { width: 100%; min-width: 0; } .wire-language-switcher--responsive .wire-language-switcher__segments { display: grid; width: 100%; grid-template-columns: repeat(auto-fit, minmax(3.5rem, 1fr)); } .wire-language-switcher--responsive .wire-language-switcher__long-label { display: none; } .wire-language-switcher--responsive .wire-language-switcher__short-label { display: inline; } } @media (prefers-reduced-motion: reduce) { .wire-language-switcher__select, .wire-language-switcher__segment { transition: none; } } } }