diff --git a/.specs/field-switch-block.md b/.specs/field-switch-block.md index 6d5549b5d..f1ea4008c 100644 --- a/.specs/field-switch-block.md +++ b/.specs/field-switch-block.md @@ -3,11 +3,11 @@ name: field-switch-block category: inputs structure: monolithic status: implemented -spec_version: 1 +spec_version: 2 figma: url: https://www.figma.com/design/t97pXRs7xME3SJDs5iZ5RF/Webkit?node-id=2027-7168 node_id: 2027:7168 -checksum: 87064b25e5372edfbcc9cde6a5457e986ff36bf7ff44f0c7c501356d2a76de15 +checksum: 965dc1e0cd016509d084cecf490f39571beb3adc7a1dfe2d8b15553d0e6bf51e created: 2026-05-23 last_updated: 2026-05-23 --- @@ -22,11 +22,8 @@ Card-style boolean toggle with switch, label, description, and optional disabled | Prop | Type | Default | Required | JSDoc | | ------------- | --------- | ----------- | -------- | ------------------------------------------------- | -| `modelValue` | `boolean` | `undefined` | no | Selected value for v-model. | -| `trueValue` | `boolean` | `true` | no | Value emitted when toggled on. | -| `falseValue` | `boolean` | `false` | no | Value emitted when toggled off. | +| `modelValue` | `boolean` | `false` | no | Selected value for v-model. | | `disabled` | `boolean` | `false` | no | Disables interaction and applies disabled tokens. | -| `inputId` | `string` | `undefined` | no | id for the switch button; links label to control. | | `label` | `string` | `''` | no | Primary label text. | | `description` | `string` | `''` | no | Secondary description. | | `helperText` | `string` | `''` | no | Helper badge text shown when disabled. | @@ -81,9 +78,9 @@ Card-style boolean toggle with switch, label, description, and optional disabled ## Accessibility (WCAG 2.1 AA) -- Visible focus: delegated to nested InputSwitch. +- Visible focus: delegated to nested Switch. - Keyboard map: `Tab` focuses switch; `Space` / `Enter` toggles. -- ARIA: label associated via `for` / `inputId`. +- ARIA: label associated via `for` pointing to an internally generated `id` injected on the `Switch` button. - Contrast ≥4.5:1 (text) / ≥3:1 (large + icons), including disabled state. - Touch target ≥40×40 px via card hit area. diff --git a/.specs/field-switch.md b/.specs/field-switch.md index 5fe728a61..b8b1244ff 100644 --- a/.specs/field-switch.md +++ b/.specs/field-switch.md @@ -3,13 +3,13 @@ name: field-switch category: inputs structure: monolithic status: implemented -spec_version: 1 +spec_version: 2 figma: url: https://www.figma.com/design/t97pXRs7xME3SJDs5iZ5RF/Webkit?node-id=542-105 node_id: 542:105 -checksum: 4e4186ce0355f5ccf2dedf95daa1efd33eeea62a8691b7e60c525bf863375831 +checksum: 0160b5d891f05729ce6c642d05b2dc662c675387306a4c6679bbde1b9fdffb3a created: 2026-05-23 -last_updated: 2026-05-23 +last_updated: 2026-06-23 --- # Field Switch — Component Spec @@ -22,11 +22,8 @@ Inline boolean toggle with switch on the leading edge, label, optional descripti | Prop | Type | Default | Required | JSDoc | | ------------- | --------- | ----------- | -------- | ------------------------------------------------- | -| `modelValue` | `boolean` | `undefined` | no | Selected value for v-model. | -| `trueValue` | `boolean` | `true` | no | Value emitted when toggled on. | -| `falseValue` | `boolean` | `false` | no | Value emitted when toggled off. | +| `modelValue` | `boolean` | `false` | no | Selected value for v-model. | | `disabled` | `boolean` | `false` | no | Disables interaction and applies disabled tokens. | -| `inputId` | `string` | `undefined` | no | id for the switch button; links label to control. | | `label` | `string` | `''` | no | Primary label text. | | `description` | `string` | `''` | no | Secondary description. | | `helperText` | `string` | `''` | no | Helper badge text shown when disabled. | @@ -74,15 +71,16 @@ _none_ ## Accessibility (WCAG 2.1 AA) -- Visible focus: delegated to nested InputSwitch. +- Visible focus: delegated to nested Switch. - Keyboard map: `Tab` focuses switch; `Space` / `Enter` toggles. -- ARIA: label associated via `for` / `inputId`. +- ARIA: label associated to the switch via `for` bound to an internally generated id (`useId`). - Contrast ≥4.5:1 (text) / ≥3:1 (large + icons), including disabled state. - Touch target ≥40×40 px via label hit area. ## Stories (Storybook) - Default +- States - Disabled ## Constraints — DO NOT diff --git a/.specs/input-switch.md b/.specs/switch.md similarity index 50% rename from .specs/input-switch.md rename to .specs/switch.md index a03d98bb2..124b3459d 100644 --- a/.specs/input-switch.md +++ b/.specs/switch.md @@ -1,37 +1,51 @@ --- -name: input-switch +name: switch category: inputs structure: monolithic status: implemented -spec_version: 2 +spec_version: 8 figma: url: https://www.figma.com/design/t97pXRs7xME3SJDs5iZ5RF/Webkit?node-id=2027-1247 node_id: 2027:1247 -checksum: aa1341a65323b931b7e05f8da735f05933747534396ce03a1f29b8aaf029642b +checksum: f3a6b7a531a51f6488909ebd407d38f712555152c9290529608f41b6b038cecb created: 2026-05-22 -last_updated: 2026-05-23 +last_updated: 2026-06-23 --- -# Input Switch — Component Spec + +# Switch — Component Spec ## Purpose -Control only — the pill toggle from Figma `_Switch` (36×20 px). No label or description. Use `FieldSwitch` or `FieldSwitchBlock` for labeled layouts. +Control-only pill toggle `Switch` (36×20 px). Two visual types: `default` (plain handle) and `privacy` (handle carries a `pi-lock` / `pi-lock-open` icon mirroring the toggled state). No label or description — use `FieldSwitch` / `FieldSwitchBlock` for labeled layouts. + +## Usage + +```vue + + + +``` ## Props | Prop | Type | Default | Required | JSDoc | |---|---|---|---|---| -| `modelValue` | `boolean` | `undefined` | no | Selected value for v-model. | -| `trueValue` | `boolean` | `true` | no | Value emitted when toggled on. | -| `falseValue` | `boolean` | `false` | no | Value emitted when toggled off. | -| `disabled` | `boolean` | `false` | no | Disables interaction and applies disabled tokens. | -| `inputId` | `string` | `undefined` | no | id for the switch button; associate an external label via htmlFor. | +| `isToggled` | `boolean` | `false` | no | Toggled-on state. Bind with `v-model:isToggled="value"`. Mirrors the Figma `isToggled` variant. | +| `type` | `'default' \| 'privacy'` | `'default'` | no | Visual variant. `privacy` renders a lock icon inside the handle (closed when off, open when on). | +| `isFocused` | `boolean` | `false` | no | Forces the focused visual state regardless of keyboard focus. Mirrors the Figma `isFocused` variant. | ## Events | Event | Payload | Notes | |---|---|---| -| `update:modelValue` | `boolean` | v-model. | +| `update:isToggled` | `boolean` | Emitted when the user toggles the switch. Paired with `v-model:isToggled`. | ## Slots @@ -39,45 +53,53 @@ Control only — the pill toggle from Figma `_Switch` (36×20 px). No label or d ## States -- Visual states: `default`, `hover`, `focus-visible`, `active`, `disabled`, `checked` -- `data-disabled` mirrors the `disabled` prop -- `data-checked` mirrors toggled-on state +- Visual states: `default`, `hover`, `focus-visible`, `active`, `checked` +- `data-checked` mirrors the `isToggled` prop (toggled-on state) +- `data-focused` mirrors the `isFocused` prop and applies the same ring tokens as `:focus-visible` +- `data-type` mirrors the `type` prop (`default` | `privacy`) +- Hover applies an inset `var(--bg-hover)` overlay on both off and on tracks ## Motion & Animations -| Trigger | Animation / Transition | Token | Reduced-motion fallback | +| Trigger | Animation / Transition | Token (see `.claude/docs/DESIGN.md` § Animations) | Reduced-motion fallback | |---|---|---|---| -| state change | `transition-colors duration-150 ease-out` | inline | `motion-reduce:transition-none` | -| handle move | `transition-transform duration-150 ease-out` | inline | `motion-reduce:transition-none` | +| track color change | `transition-colors duration-150 ease-out` | inline (matches catalog) | `motion-reduce:transition-none` | +| handle slide | `transition-transform duration-150 ease-out` | inline (matches catalog) | `motion-reduce:transition-none motion-reduce:transform-none` | ## Tokens | Region | Token (DESIGN.md) | |---|---| -| track (off) | `var(--bg-disabled)` | -| track (on) | `var(--primary)` | -| handle | `var(--bg-surface)` | -| ring | `var(--ring-color)` | +| track (off) — background | `var(--bg-surface)` | +| track (off) — border | `var(--border-default)` | +| track (on) — background | `var(--success-contrast)` | +| track (hover) — overlay | `var(--bg-hover)` (applies to both off and on tracks) | +| focus-visible / `data-focused` ring | `var(--ring-color)` | +| shape | `rounded-full` (Tailwind native; pill — DESIGN.md § Shapes does not gate `rounded-full`) | ## Theme gaps | Figma variable | Temporary primitive | Follow-up | |---|---|---| -| _none_ | — | — | +| handle fill (off) — Figma `--surface-300` (#b2b2b2) | inline `bg-[var(--text-muted)]` (closest semantic) | `TODO: introduce semantic --fg-handle (or equivalent) in DESIGN.md` | +| handle fill (on) — dark contrast over `--success-contrast` | inline `bg-[var(--bg-canvas)]` (closest semantic) | `TODO: introduce semantic --fg-handle-on in DESIGN.md` | ## Accessibility (WCAG 2.1 AA) -- Visible focus: `focus-visible:ring-2 focus-visible:ring-[var(--ring-color)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--bg-canvas)]` +- Visible focus: `focus-visible:ring-2 focus-visible:ring-[var(--ring-color)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--bg-canvas)]`. The same ring is applied when `isFocused` is `true` (`data-[focused]` mirror). - Keyboard map: `Tab` focuses; `Space` / `Enter` toggles. -- ARIA: `role="switch"` with `aria-checked`. -- Contrast ≥4.5:1 (text) / ≥3:1 (large + icons), including disabled state. +- ARIA: `role="switch"` on the root; `aria-checked` mirrors `data-checked`. The lock icon in `type="privacy"` is decorative — `aria-hidden="true"`. +- Contrast ≥4.5:1 (text) / ≥3:1 (large + icons). - `motion-reduce:transition-none motion-reduce:transform-none` on animated states. -- Touch target ≥40×40 px where the control is interactive. +- Touch target: the control itself is 36×20 — the consumer is responsible for placing it inside a ≥40×40 hit area (typically via `FieldSwitch`). The component still exposes a clickable root. ## Stories (Storybook) - Default -- Disabled +- Types — composite story rendering `type='default'` and `type='privacy'` side-by-side, each in both off and on states. + + + ## Constraints — DO NOT @@ -94,7 +116,8 @@ Control only — the pill toggle from Figma `_Switch` (36×20 px). No label or d - Do not inherit artifacts as-is from another design system, Figma file, library, or pre-existing `CONTRACT.md` / `README.md`. Rewrite to our conventions. See `.claude/rules/migration.md`. - Do not add Figma references to Storybook stories. No `parameters.design`, no `parameters.figma`, no Figma URLs in `docs.description.*`, no `@storybook/addon-designs` import. The Figma link is owned by `.figma.ts` (Code Connect). See `.claude/docs/COMPONENT_REQUIREMENTS.md`. - Do not use `parameters.actions.argTypesRegex` (deprecated in Storybook 8 and silently misroutes Vue 3 emits) or `parameters.actions.handles` (DOM-only). Declare every event explicitly in `argTypes` with a camelCase `on` key and `{ action: '' }`. Do not use the legacy CSF2 `Name.args = {...}` form — always object-style CSF3. -- Do not add bespoke Storybook stories beyond Default + per `kind` + per `size` + Disabled, unless the spec's "Stories (Storybook)" section explicitly justifies the addition. +- Do not add bespoke Storybook stories beyond Default + Types + Sizes + state stories (`Loading`, `Disabled`) for the props the component actually declares, unless the spec's "Stories (Storybook)" section explicitly justifies the addition. Do not split Types/Sizes into one-story-per-variant — the composite stories are the canonical pattern. +- Do not duplicate the `## Usage` block from the spec inside the Storybook story body. The block is injected once into `parameters.docs.description.component` by the storybook-write skill; copy it nowhere else. - Do not edit `.claude/docs/DESIGN.md`, `.claude/docs/COMPONENT_REQUIREMENTS.md`, or `.claude/docs/PRIMEVUE_ABSTRACTION.md`. - Do not edit the root `package.json` or `.github/workflows/*`. - Do not change `structure` after `status: approved`. To change structure, bump `spec_version` and re-author the spec. diff --git a/apps/storybook/src/stories/components/inputs/FieldSwitch.stories.js b/apps/storybook/src/stories/components/inputs/FieldSwitch.stories.js index 99f7f9a0a..c1f99a346 100644 --- a/apps/storybook/src/stories/components/inputs/FieldSwitch.stories.js +++ b/apps/storybook/src/stories/components/inputs/FieldSwitch.stories.js @@ -2,6 +2,22 @@ import { ref } from 'vue' import FieldSwitch from '@aziontech/webkit/field-switch' +const CORE_IMPORT = "import FieldSwitch from '@aziontech/webkit/field-switch'" + +const basicSource = ({ initial = 'false', bind = '' } = {}) => + [ + '', + '', + '' + ].join('\n') + /** @type {import('@storybook/vue3').Meta} */ const meta = { title: 'Components/Inputs/Field Switch', @@ -20,8 +36,35 @@ const meta = { }, docs: { description: { - component: - 'Inline boolean toggle with switch on the leading edge, label, optional description, and optional disabled helper badge.' + component: [ + 'Inline boolean toggle with switch on the leading edge, label, optional description, and optional disabled helper badge.', + '', + '## Usage', + '', + '```vue', + '', + '', + '', + '```' + ].join('\n') + }, + source: { + type: 'dynamic', + excludeDecorators: true + }, + canvas: { + sourceState: 'shown' } } }, @@ -58,14 +101,42 @@ const meta = { } }, args: { + modelValue: false, label: 'Switch label', - description: 'Switch description' + description: 'Switch description', + helperText: '', + disabled: false } } export default meta export const Default = { + render: (args) => ({ + components: { FieldSwitch }, + setup() { + const model = ref(args.modelValue) + return { args, model } + }, + template: ` + + ` + }), + parameters: { + docs: { + source: { + code: basicSource({ + bind: 'label="Switch label" description="Switch description"' + }) + } + } + } +} + +export const States = { render: () => ({ components: { FieldSwitch }, setup() { @@ -79,35 +150,72 @@ export const Default = { v-model="off" label="Switch label" description="Switch description" - input-id="webkit-field-switch-off" /> ` - }) + }), + parameters: { + docs: { + source: { + code: [ + '', + '', + '' + ].join('\n') + } + } + } } export const Disabled = { - render: () => ({ + args: { + modelValue: true, + helperText: 'Helper Text', + disabled: true + }, + render: (args) => ({ components: { FieldSwitch }, setup() { - const value = ref(true) - return { value } + const model = ref(args.modelValue) + return { args, model } }, template: ` ` - }) + }), + parameters: { + docs: { + source: { + code: basicSource({ + initial: 'true', + bind: 'label="Switch label" description="Switch description" helperText="Helper Text" disabled' + }) + } + } + } } diff --git a/apps/storybook/src/stories/components/inputs/FieldSwitchBlock.stories.js b/apps/storybook/src/stories/components/inputs/FieldSwitchBlock.stories.js index 42196218c..eb07ec474 100644 --- a/apps/storybook/src/stories/components/inputs/FieldSwitchBlock.stories.js +++ b/apps/storybook/src/stories/components/inputs/FieldSwitchBlock.stories.js @@ -79,13 +79,11 @@ export const Default = { v-model="off" label="Switch label" description="Switch description" - input-id="webkit-field-switch-block-off" /> ` @@ -106,7 +104,6 @@ export const Disabled = { description="Switch description" helper-text="Helper Text" disabled - input-id="webkit-field-switch-block-disabled" /> ` }) diff --git a/apps/storybook/src/stories/components/inputs/InputSwitch.stories.js b/apps/storybook/src/stories/components/inputs/InputSwitch.stories.js deleted file mode 100644 index 5a65bad13..000000000 --- a/apps/storybook/src/stories/components/inputs/InputSwitch.stories.js +++ /dev/null @@ -1,106 +0,0 @@ -import { ref } from 'vue' - -import InputSwitch from '@aziontech/webkit/input-switch' - -/** @type {import('@storybook/vue3').Meta} */ -const meta = { - title: 'Components/Inputs/Input Switch', - component: InputSwitch, - tags: ['autodocs'], - parameters: { - layout: 'padded', - backgrounds: { default: 'dark' }, - a11y: { - config: { - rules: [ - { id: 'color-contrast', enabled: true }, - { id: 'focus-order-semantics', enabled: true } - ] - } - }, - docs: { - description: { - component: - 'Control only — the pill toggle with no label or description. Use FieldSwitch or FieldSwitchBlock for built-in text.' - } - } - }, - argTypes: { - modelValue: { - control: 'boolean', - description: 'Selected value for v-model.', - table: { type: { summary: 'boolean' }, category: 'props' } - }, - trueValue: { - control: 'boolean', - description: 'Value emitted when toggled on.', - table: { type: { summary: 'boolean' }, defaultValue: { summary: 'true' }, category: 'props' } - }, - falseValue: { - control: 'boolean', - description: 'Value emitted when toggled off.', - table: { type: { summary: 'boolean' }, defaultValue: { summary: 'false' }, category: 'props' } - }, - disabled: { - control: 'boolean', - description: 'Disables interaction and applies disabled tokens.', - table: { type: { summary: 'boolean' }, defaultValue: { summary: 'false' }, category: 'props' } - }, - inputId: { - control: 'text', - description: 'id for the switch button; associate an external label via htmlFor.', - table: { type: { summary: 'string' }, category: 'props' } - }, - 'onUpdate:modelValue': { - action: 'update:modelValue', - description: 'Emitted when the selected value changes.', - table: { type: { summary: 'boolean' }, category: 'events' } - } - } -} - -export default meta - -export const Default = { - render: () => ({ - components: { InputSwitch }, - setup() { - const value = ref(false) - return { value } - }, - template: ` - - ` - }) -} - -export const Disabled = { - render: () => ({ - components: { InputSwitch }, - setup() { - const on = ref(true) - const off = ref(false) - return { on, off } - }, - template: ` -
- - -
- ` - }) -} diff --git a/apps/storybook/src/stories/components/inputs/Switch.stories.js b/apps/storybook/src/stories/components/inputs/Switch.stories.js new file mode 100644 index 000000000..35febef4e --- /dev/null +++ b/apps/storybook/src/stories/components/inputs/Switch.stories.js @@ -0,0 +1,175 @@ +import { ref } from 'vue' + +import Switch from '@aziontech/webkit/switch' + +const CORE_IMPORT = "import Switch from '@aziontech/webkit/switch'" + +const basicSource = ({ initial = 'false', bind = '' } = {}) => + [ + '', + '', + '' + ].join('\n') + +/** @type {import('@storybook/vue3').Meta} */ +const meta = { + title: 'Components/Inputs/Switch', + component: Switch, + tags: ['autodocs'], + parameters: { + layout: 'padded', + backgrounds: { default: 'dark' }, + a11y: { + config: { + rules: [ + { id: 'color-contrast', enabled: true }, + { id: 'focus-order-semantics', enabled: true } + ] + } + }, + docs: { + description: { + component: [ + 'Control-only pill toggle `Switch` (36×20 px). Two visual types: `default` (plain handle) and `privacy` (handle carries a lock icon mirroring the toggled state). No label or description — use `FieldSwitch` / `FieldSwitchBlock` for labeled layouts.', + '', + '## Usage', + '', + '```vue', + '', + '', + '', + '```' + ].join('\n') + }, + source: { + type: 'dynamic', + excludeDecorators: true + }, + canvas: { + sourceState: 'shown' + } + } + }, + argTypes: { + isToggled: { + control: 'boolean', + description: 'Toggled-on state. Bind with `v-model:isToggled="value"`.', + table: { type: { summary: 'boolean' }, defaultValue: { summary: 'false' }, category: 'props' } + }, + type: { + control: 'select', + options: ['default', 'privacy'], + description: 'Visual variant. Privacy renders a lock icon inside the handle.', + table: { + type: { summary: "'default' | 'privacy'" }, + defaultValue: { summary: "'default'" }, + category: 'props' + } + }, + isFocused: { + control: 'boolean', + description: 'Forces the focused visual state regardless of keyboard focus.', + table: { type: { summary: 'boolean' }, defaultValue: { summary: 'false' }, category: 'props' } + }, + 'onUpdate:isToggled': { + action: 'update:isToggled', + description: 'Emitted when the user toggles the switch.', + table: { type: { summary: 'boolean' }, category: 'events' } + } + } +} + +export default meta + +/** @type {import('@storybook/vue3').StoryObj} */ +export const Default = { + args: { + isToggled: false, + type: 'default', + isFocused: false + }, + render: (args) => ({ + components: { Switch }, + setup() { + return { args } + }, + template: ` + + ` + }), + parameters: { + docs: { + description: { story: 'Default switch. Use the Controls panel to flip isToggled, type, and isFocused.' }, + source: { code: basicSource() } + } + } +} + +/** @type {import('@storybook/vue3').StoryObj} */ +export const Types = { + render: () => ({ + components: { Switch }, + setup() { + const defaultOff = ref(false) + const defaultOn = ref(true) + const privacyOff = ref(false) + const privacyOn = ref(true) + return { defaultOff, defaultOn, privacyOff, privacyOn } + }, + template: ` +
+ + + + +
+ ` + }), + parameters: { + docs: { + description: { + story: + 'Both type variants in off and on states. Privacy adds a lock (off) / lock-open (on) icon inside the handle.' + }, + source: { + code: [ + '', + '', + '' + ].join('\n') + } + } + } +} diff --git a/packages/webkit/AGENTS.md b/packages/webkit/AGENTS.md index 3bff52e3a..48d2b0817 100644 --- a/packages/webkit/AGENTS.md +++ b/packages/webkit/AGENTS.md @@ -12,7 +12,7 @@ packages/webkit/src/ │ │ ├── content/ avatar, card-box, card-pricing, currency, tag │ │ ├── data/ (empty, ready to receive) │ │ ├── feedback/ message, status-indicator -│ │ ├── inputs/ checkbox, dropdown, input-switch, input-text, radio-button +│ │ ├── inputs/ checkbox, dropdown, switch, input-text, radio-button │ │ ├── layout/ global-header, scroll-area, sidebar │ │ ├── navigation/ link, menu-item, navigation-menu, tab-view │ │ ├── overlay/ dialog, drawer, panel diff --git a/packages/webkit/package.json b/packages/webkit/package.json index 842925304..73b712e39 100644 --- a/packages/webkit/package.json +++ b/packages/webkit/package.json @@ -110,7 +110,7 @@ "./field-switch": "./src/components/inputs/field-switch/field-switch.vue", "./field-switch-block": "./src/components/inputs/field-switch-block/field-switch-block.vue", "./radio-button": "./src/components/inputs/radio-button/radio-button.vue", - "./input-switch": "./src/components/inputs/input-switch/input-switch.vue", + "./switch": "./src/components/inputs/switch/switch.vue", "./textarea": "./src/components/inputs/textarea/textarea.vue", "./field-textarea": "./src/components/inputs/field-textarea/field-textarea.vue", "./dropdown": "./src/components/inputs/dropdown/dropdown.vue", diff --git a/packages/webkit/src/components/inputs/field-switch-block/field-switch-block.vue b/packages/webkit/src/components/inputs/field-switch-block/field-switch-block.vue index 193f14d7d..41f891d6c 100644 --- a/packages/webkit/src/components/inputs/field-switch-block/field-switch-block.vue +++ b/packages/webkit/src/components/inputs/field-switch-block/field-switch-block.vue @@ -2,8 +2,8 @@ import { computed, useAttrs, useId } from 'vue' import { cn } from '../../../utils/cn' - import InputSwitch from '../input-switch/input-switch.vue' import { selectableBlockCardClasses } from '../presets/interactive-states' + import Switch from '../switch/switch.vue' defineOptions({ name: 'FieldSwitchBlock', @@ -13,14 +13,8 @@ interface Props { /** Selected value for v-model. */ modelValue?: boolean - /** Value emitted when toggled on. */ - trueValue?: boolean - /** Value emitted when toggled off. */ - falseValue?: boolean /** Disables interaction and applies disabled tokens. */ disabled?: boolean - /** id for the switch button; links label to control. */ - inputId?: string /** Primary label text. */ label?: string /** Secondary description. */ @@ -30,11 +24,8 @@ } const props = withDefaults(defineProps(), { - modelValue: undefined, - trueValue: true, - falseValue: false, + modelValue: false, disabled: false, - inputId: undefined, label: '', description: '', helperText: '' @@ -51,9 +42,7 @@ () => (attrs['data-testid'] as string | undefined) ?? 'input-field-switch-block' ) - const resolvedInputId = computed(() => props.inputId ?? generatedId) - - const isChecked = computed(() => props.modelValue === props.trueValue) + const isChecked = computed(() => props.modelValue === true) const isHighlighted = computed( () => (isChecked.value && !props.disabled) || (!isChecked.value && props.disabled) @@ -61,7 +50,7 @@ const model = computed({ get: () => props.modelValue, - set: (next) => emit('update:modelValue', next ?? props.falseValue) + set: (next) => emit('update:modelValue', next ?? false) }) const sharedClasses = 'block data-[disabled]:cursor-not-allowed' @@ -88,7 +77,7 @@