feat(editor): Move Switch component to core design system (#27322)

This commit is contained in:
Rob Hough 2026-04-29 14:11:24 +01:00 committed by GitHub
parent 5361257a80
commit 758f89c9ef
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 33 additions and 24 deletions

View File

@ -5,7 +5,7 @@ import { ref } from 'vue';
import Switch from './Switch.vue';
const meta = {
title: 'Experimental/Switch',
title: 'Core/Switch',
component: Switch,
parameters: {
docs: {

View File

@ -3,7 +3,7 @@ import { render, waitFor } from '@testing-library/vue';
import Switch from './Switch.vue';
describe('v2/components/Switch', () => {
describe('components/N8nSwitch', () => {
describe('rendering', () => {
it('should render unchecked by default', () => {
const wrapper = render(Switch);

View File

@ -35,6 +35,8 @@ const rootAttrs = computed(() => reactiveOmit(attrs, ['class']));
:name="name"
:disabled="disabled"
:class="$style.switchRoot"
:aria-labelledby="label ? uuid : undefined"
:aria-label="!label && 'Toggle'"
>
<SwitchThumb :class="$style.switchThumb" />
</SwitchRoot>
@ -57,7 +59,7 @@ const rootAttrs = computed(() => reactiveOmit(attrs, ['class']));
flex-direction: row;
align-items: center;
gap: var(--spacing--2xs);
cursor: pointer;
cursor: default;
&[data-disabled] {
cursor: not-allowed;

View File

@ -2,7 +2,7 @@
A toggle control that allows users to switch between two states (on/off). The Switch component is ideal for binary choices where the effect is immediate, such as enabling or disabling a feature.
- **Component Name:** N8nSwitch2
- **Component Name:** N8nSwitch
- **Figma Component:** [Figma](https://www.figma.com/design/8zib7Trf2D2CHYXrEGPHkg/n8n-Design-System-V3?node-id=81-530&m=dev)
- **Reka UI Component:** [Switch](https://reka-ui.com/docs/components/switch)
@ -44,7 +44,7 @@ const isEnabled = ref(false)
</script>
<template>
<N8nSwitch2 v-model="isEnabled" label="Enable notifications" />
<N8nSwitch v-model="isEnabled" label="Enable notifications" />
</template>
```
@ -58,10 +58,10 @@ const timeout = ref(true)
<template>
<!-- Small size for parameters panel -->
<N8nSwitch2 v-model="sendBody" label="Send Body" size="small" />
<N8nSwitch v-model="sendBody" label="Send Body" size="small" />
<!-- Large size for settings -->
<N8nSwitch2 v-model="timeout" label="Timeout Workflow" size="large" />
<N8nSwitch v-model="timeout" label="Timeout Workflow" size="large" />
</template>
```
@ -73,10 +73,10 @@ const isAccepted = ref(false)
</script>
<template>
<N8nSwitch2 v-model="isAccepted">
<N8nSwitch v-model="isAccepted">
<template #label>
I accept the <a href="/terms">terms and conditions</a>
</template>
</N8nSwitch2>
</N8nSwitch>
</template>
```

View File

@ -0,0 +1,6 @@
import N8nSwitch from './Switch.vue';
export default N8nSwitch;
export { N8nSwitch };
export { N8nSwitch as N8nSwitch2 };
export type * from './Switch.types';

View File

@ -75,6 +75,7 @@ export { default as N8nSpinner } from './N8nSpinner';
export { default as N8nSticky } from './N8nSticky';
export { default as N8nResizeableSticky } from './N8nResizeableSticky';
export { default as N8nSuggestedActions } from './N8nSuggestedActions';
export { default as N8nSwitch } from './N8nSwitch';
export { default as N8nTabs } from './N8nTabs';
export { default as N8nTag } from './N8nTag';
export { default as N8nTags } from './N8nTags';

View File

@ -20,7 +20,7 @@ export { default as N8nInputNumber2 } from './v2/components/InputNumber/InputNum
export type * from './v2/components/InputNumber/InputNumber.types';
export { default as N8nDropdownMenu } from './v2/components/DropdownMenu/DropdownMenu.vue';
export type * from './v2/components/DropdownMenu/DropdownMenu.types';
export { default as N8nSwitch2 } from './v2/components/Switch/Switch.vue';
export type * from './v2/components/Switch/Switch.types';
export { default as N8nSwitch2 } from './components/N8nSwitch/Switch.vue';
export type * from './components/N8nSwitch/Switch.types';
export { createPasswordRules } from './components/N8nFormInput/validators';
export { locale };

View File

@ -1,2 +0,0 @@
export { default as N8nSwitch2 } from './Switch.vue';
export type * from './Switch.types';

View File

@ -5,7 +5,7 @@ import {
N8nHeading,
N8nIconButton,
N8nInputNumber,
N8nSwitch2,
N8nSwitch,
N8nText,
N8nTooltip,
} from '@n8n/design-system';
@ -263,7 +263,8 @@ watch(
:disabled="props.data.disabled"
placement="top"
>
<N8nSwitch2
<N8nSwitch
data-test-id="chat-provider-enabled-switch"
size="large"
:model-value="settings?.enabled ?? false"
:disabled="props.data.disabled || loadingSettings"
@ -316,7 +317,8 @@ watch(
:disabled="props.data.disabled"
placement="top"
>
<N8nSwitch2
<N8nSwitch
data-test-id="chat-provider-limit-models-switch"
size="large"
:model-value="limitModels"
:disabled="props.data.disabled || loadingSettings"
@ -353,7 +355,7 @@ watch(
<N8nText color="text-light" size="small">
{{ i18n.baseText('settings.chatHub.providers.modal.edit.responsesApi.description') }}
</N8nText>
<N8nSwitch2
<N8nSwitch
size="large"
:model-value="settings.responsesApiEnabled ?? true"
:disabled="props.data.disabled"

View File

@ -108,7 +108,7 @@ import {
N8nInputNumber,
N8nOption,
N8nSelect,
N8nSwitch2,
N8nSwitch,
} from '@n8n/design-system';
import { useCollectionOverhaul } from '@/app/composables/useCollectionOverhaul';
import { injectWorkflowDocumentStore } from '@/app/stores/workflowDocument.store';
@ -1989,7 +1989,7 @@ onUpdated(async () => {
class="switch-droppable-input"
>
<template #prefix>
<N8nSwitch2
<N8nSwitch
:model-value="Boolean(displayValue)"
:label="switchLabel"
:disabled="true"
@ -2006,7 +2006,7 @@ onUpdated(async () => {
:title="displayTitle"
/>
<N8nSwitch2
<N8nSwitch
v-else-if="parameter.type === 'boolean' && isCollectionOverhaulEnabled"
ref="inputField"
:class="{ 'ph-no-capture': shouldRedactValue }"

View File

@ -1,7 +1,7 @@
<script setup lang="ts">
import { ref } from 'vue';
import { useI18n } from '@n8n/i18n';
import { N8nSwitch2, N8nText } from '@n8n/design-system';
import { N8nSwitch, N8nText } from '@n8n/design-system';
import SetupPanelCards from '@/features/setupPanel/components/SetupPanelCards.vue';
const i18n = useI18n();
@ -15,7 +15,7 @@ const showCompleted = ref(true);
</div>
<footer :class="$style.footer" data-test-id="setup-panel-footer">
<N8nText :class="$style['toggle-label']" tag="label" size="small">
<N8nSwitch2 v-model="showCompleted" size="small" />
<N8nSwitch v-model="showCompleted" size="small" />
{{ i18n.baseText('setupPanel.showCompleted') }}
</N8nText>
</footer>

View File

@ -12,7 +12,7 @@ export class ChatHubProviderSettingsModal extends BaseModal {
}
getEnabledToggle(): Locator {
return this.root.getByLabel(/^Enable /).locator('..');
return this.root.getByTestId('chat-provider-enabled-switch');
}
getCredentialPicker(): Locator {
@ -24,7 +24,7 @@ export class ChatHubProviderSettingsModal extends BaseModal {
}
getLimitModelsToggle(): Locator {
return this.root.getByLabel('Limit models').locator('..');
return this.root.getByTestId('chat-provider-limit-models-switch');
}
getModelSelector(): Locator {