From fbb88021e3e323aacd5179e62d6f3b697c22ffee Mon Sep 17 00:00:00 2001 From: Gert Hengeveld Date: Tue, 23 Dec 2025 16:09:05 +0100 Subject: [PATCH 1/7] Synchronize vision simulator state with globals and apply vision filters in the preview rather than on the manager's preview iframe --- .../a11y/src/components/ColorFilters.tsx | 57 ---------- .../a11y/src/components/VisionSimulator.tsx | 76 ++++--------- code/addons/a11y/src/constants.ts | 1 + code/addons/a11y/src/preview.tsx | 4 + .../addons/a11y/src/visionSimulatorFilters.ts | 100 ++++++++++++++++++ code/addons/a11y/src/withVisionSimulator.ts | 36 +++++++ 6 files changed, 159 insertions(+), 115 deletions(-) delete mode 100644 code/addons/a11y/src/components/ColorFilters.tsx create mode 100644 code/addons/a11y/src/visionSimulatorFilters.ts create mode 100644 code/addons/a11y/src/withVisionSimulator.ts diff --git a/code/addons/a11y/src/components/ColorFilters.tsx b/code/addons/a11y/src/components/ColorFilters.tsx deleted file mode 100644 index 24c82e9f95cb..000000000000 --- a/code/addons/a11y/src/components/ColorFilters.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import * as React from 'react'; - -export const Filters: React.FC> = (props) => ( - - - - - - - - - - - - - - - - - - - - - - - - - -); diff --git a/code/addons/a11y/src/components/VisionSimulator.tsx b/code/addons/a11y/src/components/VisionSimulator.tsx index c029abe20332..195e47ecd9d3 100644 --- a/code/addons/a11y/src/components/VisionSimulator.tsx +++ b/code/addons/a11y/src/components/VisionSimulator.tsx @@ -1,47 +1,20 @@ -import React, { useState } from 'react'; +import React from 'react'; import { Select } from 'storybook/internal/components'; import { AccessibilityIcon } from '@storybook/icons'; -import { Global, styled } from 'storybook/theming'; +import { useGlobals } from 'storybook/manager-api'; +import { styled } from 'storybook/theming'; -import { Filters } from './ColorFilters'; - -const iframeId = 'storybook-preview-iframe'; +import { VISION_GLOBAL_KEY } from '../constants'; +import { filterDefs, filters } from '../visionSimulatorFilters'; interface Option { name: string; percentage?: number; } -export const baseList = [ - { name: 'blurred vision', percentage: 22.9 }, - { name: 'deuteranomaly', percentage: 2.7 }, - { name: 'deuteranopia', percentage: 0.56 }, - { name: 'protanomaly', percentage: 0.66 }, - { name: 'protanopia', percentage: 0.59 }, - { name: 'tritanomaly', percentage: 0.01 }, - { name: 'tritanopia', percentage: 0.016 }, - { name: 'achromatopsia', percentage: 0.0001 }, - { name: 'grayscale' }, -] as Option[]; - -type Filter = Option | null; - -const getFilter = (filterName: string) => { - if (!filterName) { - return 'none'; - } - if (filterName === 'blurred vision') { - return 'blur(2px)'; - } - if (filterName === 'grayscale') { - return 'grayscale(100%)'; - } - return `url('#${filterName}')`; -}; - const Hidden = styled.div({ '&, & svg': { position: 'absolute', @@ -59,7 +32,7 @@ const ColorIcon = styled.span<{ $filter: string }>( width: '1rem', }, ({ $filter }) => ({ - filter: getFilter($filter), + filter: filters[$filter as keyof typeof filters].filter || 'none', }), ({ theme }) => ({ boxShadow: `${theme.appBorderColor} 0 0 0 1px inset`, @@ -67,41 +40,28 @@ const ColorIcon = styled.span<{ $filter: string }>( ); export const VisionSimulator = () => { - const [filter, setFilter] = useState(null); + const [globals, updateGlobals] = useGlobals(); + const value = globals[VISION_GLOBAL_KEY]; - const options = baseList.map(({ name, percentage }) => { - const description = percentage !== undefined ? `${percentage}% of users` : undefined; - return { - title: name, - description, - icon: , - value: name, - }; - }); + const options = Object.entries(filters).map(([key, { label, percentage }]) => ({ + title: label, + description: percentage ? `${percentage}% of users` : undefined, + icon: , + value: key, + })); return ( <> - {filter && ( - - )}