From e97030a7ae103f4c9145cc7ddce5af4d96ae5c0e Mon Sep 17 00:00:00 2001 From: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com> Date: Thu, 5 Feb 2026 12:09:27 +0100 Subject: [PATCH] fix: make switch labels properly clickable (#25898) --- pnpm-lock.yaml | 35 ++++++++++++++----- web/package.json | 2 +- .../settings/setting-switch.spec.ts | 23 ++++++++++++ .../settings/setting-switch.svelte | 6 ++-- 4 files changed, 53 insertions(+), 13 deletions(-) create mode 100644 web/src/lib/components/shared-components/settings/setting-switch.spec.ts diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9b9f7fcaf5..2030bbc08c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -741,8 +741,8 @@ importers: specifier: file:../open-api/typescript-sdk version: link:../open-api/typescript-sdk '@immich/ui': - specifier: ^0.59.0 - version: 0.59.0(@sveltejs/kit@2.49.5(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.48.0)(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.48.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.48.0) + specifier: ^0.61.3 + version: 0.61.3(@sveltejs/kit@2.49.5(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.48.0)(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.48.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.48.0) '@mapbox/mapbox-gl-rtl-text': specifier: 0.2.3 version: 0.2.3(mapbox-gl@1.13.3) @@ -3126,13 +3126,13 @@ packages: '@immich/justified-layout-wasm@0.4.3': resolution: {integrity: sha512-fpcQ7zPhP3Cp1bEXhONVYSUeIANa2uzaQFGKufUZQo5FO7aFT77szTVChhlCy4XaVy5R4ZvgSkA/1TJmeORz7Q==} - '@immich/svelte-markdown-preprocess@0.1.0': - resolution: {integrity: sha512-jgSOJEGLPKEXQCNRI4r4YUayeM2b0ZYLdzgKGl891jZBhOQIetlY7rU44kPpV1AA3/8wGDwNFKduIQZZ/qJYzg==} + '@immich/svelte-markdown-preprocess@0.2.1': + resolution: {integrity: sha512-mbr/g75lO8Zh+ELCuYrZP0XB4gf2UbK8rJcGYMYxFJJzMMunV+sm9FqtV1dbwW2dpXzCZGz1XPCEZ6oo526TbA==} peerDependencies: svelte: ^5.0.0 - '@immich/ui@0.59.0': - resolution: {integrity: sha512-7yxvyhhd99T0AHhjMakp7c/U4n0jGAmRO5xpncsRASRvqZve/LAibjr6N5FJc5IAd222DROTMLn6imsxVfqfvg==} + '@immich/ui@0.61.3': + resolution: {integrity: sha512-9cz/7kc/CSmJ37gH5nIZNiHxw5OlBCGbdlSGkCOtaMJ458wmcdUFVmF5arjGioaOa4NMwseOVyln7rMhkNU7ww==} peerDependencies: svelte: ^5.0.0 @@ -7802,6 +7802,9 @@ packages: resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} engines: {node: '>= 0.8'} + front-matter@4.0.2: + resolution: {integrity: sha512-I8ZuJ/qG92NWX8i5x1Y8qyj3vizhXS31OxjKDu3LKP+7/qBgfIKValiZIEwoVoJKUHlhWtYrktkxV1XsX+pPlg==} + fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} @@ -9081,6 +9084,11 @@ packages: engines: {node: '>= 20'} hasBin: true + marked@17.0.1: + resolution: {integrity: sha512-boeBdiS0ghpWcSwoNm/jJBwdpFaMnZWRzjA6SkUMYb40SVaN1x7mmfGKp0jvexGcx+7y2La5zRZsYFZI6Qpypg==} + engines: {node: '>= 20'} + hasBin: true + math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} @@ -15747,13 +15755,16 @@ snapshots: '@immich/justified-layout-wasm@0.4.3': {} - '@immich/svelte-markdown-preprocess@0.1.0(svelte@5.48.0)': + '@immich/svelte-markdown-preprocess@0.2.1(svelte@5.48.0)': dependencies: + front-matter: 4.0.2 + marked: 17.0.1 + node-emoji: 2.2.0 svelte: 5.48.0 - '@immich/ui@0.59.0(@sveltejs/kit@2.49.5(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.48.0)(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.48.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.48.0)': + '@immich/ui@0.61.3(@sveltejs/kit@2.49.5(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.48.0)(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.48.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.48.0)': dependencies: - '@immich/svelte-markdown-preprocess': 0.1.0(svelte@5.48.0) + '@immich/svelte-markdown-preprocess': 0.2.1(svelte@5.48.0) '@internationalized/date': 3.10.0 '@mdi/js': 7.4.47 bits-ui: 2.14.4(@internationalized/date@3.10.0)(@sveltejs/kit@2.49.5(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.48.0)(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.48.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.48.0) @@ -21100,6 +21111,10 @@ snapshots: fresh@2.0.0: {} + front-matter@4.0.2: + dependencies: + js-yaml: 3.14.2 + fs-constants@1.0.0: {} fs-extra@10.1.0: @@ -22570,6 +22585,8 @@ snapshots: marked@16.4.2: {} + marked@17.0.1: {} + math-intrinsics@1.1.0: {} mdast-util-directive@3.1.0: diff --git a/web/package.json b/web/package.json index dd6924b675..b820ada917 100644 --- a/web/package.json +++ b/web/package.json @@ -27,7 +27,7 @@ "@formatjs/icu-messageformat-parser": "^3.0.0", "@immich/justified-layout-wasm": "^0.4.3", "@immich/sdk": "file:../open-api/typescript-sdk", - "@immich/ui": "^0.59.0", + "@immich/ui": "^0.61.3", "@mapbox/mapbox-gl-rtl-text": "0.2.3", "@mdi/js": "^7.4.47", "@photo-sphere-viewer/core": "^5.14.0", diff --git a/web/src/lib/components/shared-components/settings/setting-switch.spec.ts b/web/src/lib/components/shared-components/settings/setting-switch.spec.ts new file mode 100644 index 0000000000..7bd657a3a4 --- /dev/null +++ b/web/src/lib/components/shared-components/settings/setting-switch.spec.ts @@ -0,0 +1,23 @@ +import { render } from '@testing-library/svelte'; +import SettingSwitch from './setting-switch.svelte'; + +describe('SettingSwitch component', () => { + it('links switch and subtitle ids on the switch', () => { + const { getByText } = render(SettingSwitch, { + props: { + title: 'Enable feature', + subtitle: 'Controls the feature state.', + }, + }); + + const label = getByText('Enable feature') as HTMLLabelElement; + const subtitle = getByText('Controls the feature state.'); + const subtitleId = subtitle.getAttribute('id'); + const switchElement = document.querySelector(`#${label.htmlFor}`); + + expect(subtitleId).not.toBeNull(); + expect(label.htmlFor).not.toBe(''); + expect(switchElement).not.toBeNull(); + expect(switchElement?.getAttribute('aria-describedby')).toBe(subtitleId); + }); +}); diff --git a/web/src/lib/components/shared-components/settings/setting-switch.svelte b/web/src/lib/components/shared-components/settings/setting-switch.svelte index 42dc952010..4062c60b77 100644 --- a/web/src/lib/components/shared-components/settings/setting-switch.svelte +++ b/web/src/lib/components/shared-components/settings/setting-switch.svelte @@ -28,14 +28,14 @@ let id: string = generateId(); - let sliderId = $derived(`${id}-slider`); + let switchId = $derived(`input-${id}`); let subtitleId = $derived(subtitle ? `${id}-subtitle` : undefined);
-
- +