diff --git a/CHANGELOG.md b/CHANGELOG.md index bc9fd2b3e316..d9486c6367e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## 10.1.12 + +- AddonVitest: Improve perf & fix loading incorrect `.env` file - [#33469](https://github.com/storybookjs/storybook/pull/33469), thanks @ndelangen! +- Core: Fix onboarding visual bugs, survey telemetry and modal dismissal - [#33326](https://github.com/storybookjs/storybook/pull/33326), thanks @ghengeveld! +- UI: Fix regression in select close handler focus - [#33470](https://github.com/storybookjs/storybook/pull/33470), thanks @Sidnioulz! +- UI: Improve landmark navigation - [#33457](https://github.com/storybookjs/storybook/pull/33457), thanks @Sidnioulz! + ## 10.1.11 - React: Fix several CSF factory bugs - [#33354](https://github.com/storybookjs/storybook/pull/33354), thanks @kasperpeulen! diff --git a/code/addons/docs/src/blocks/components/ArgsTable/ArgsTable.tsx b/code/addons/docs/src/blocks/components/ArgsTable/ArgsTable.tsx index b42c5a949b77..874edbc2ccc2 100644 --- a/code/addons/docs/src/blocks/components/ArgsTable/ArgsTable.tsx +++ b/code/addons/docs/src/blocks/components/ArgsTable/ArgsTable.tsx @@ -37,7 +37,7 @@ export const TableWrapper = styled.table<{ // End Resets fontSize: theme.typography.size.s2 - 1, - lineHeight: '20px', + lineHeight: '19px', textAlign: 'left', width: '100%', diff --git a/code/addons/onboarding/src/Onboarding.tsx b/code/addons/onboarding/src/Onboarding.tsx index 0c667320a118..f1b6250cd143 100644 --- a/code/addons/onboarding/src/Onboarding.tsx +++ b/code/addons/onboarding/src/Onboarding.tsx @@ -90,11 +90,7 @@ export default function Onboarding({ userAgent, }); } - // remove onboarding query parameter from current url - const url = new URL(window.location.href); - url.searchParams.set('onboarding', 'false'); - history.replaceState({}, '', url.href); - api.setQueryParams({ onboarding: 'false' }); + api.applyQueryParams({ onboarding: undefined }, { replace: true }); setEnabled(false); }, [api, setEnabled, userAgent] @@ -113,12 +109,23 @@ export default function Onboarding({ [api, selectStory, userAgent] ); + useEffect(() => { + if (step === '6:IntentSurvey' && !hasCompletedSurvey) { + api.emit(ADDON_ONBOARDING_CHANNEL, { + from: 'onboarding', + type: 'openSurvey', + userAgent, + }); + } + }, [api, hasCompletedSurvey, step, userAgent]); + useEffect(() => { api.setQueryParams({ onboarding: 'true' }); selectStory('example-button--primary'); api.togglePanel(true); api.togglePanelPosition('bottom'); api.setSelectedPanel(ADDON_CONTROLS_ID); + api.setSizes({ bottomPanelHeight: 300 }); }, [api, selectStory]); useEffect(() => { @@ -304,6 +311,7 @@ export default function Onboarding({ setStep('2:Controls')} /> ) : step === '6:IntentSurvey' ? ( disableOnboarding('6:IntentSurvey')} /> diff --git a/code/addons/onboarding/src/Survey.tsx b/code/addons/onboarding/src/Survey.tsx index 7bf5f4a43815..4e4bb94d83b9 100644 --- a/code/addons/onboarding/src/Survey.tsx +++ b/code/addons/onboarding/src/Survey.tsx @@ -1,4 +1,4 @@ -import React, { useCallback } from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; import { type API } from 'storybook/manager-api'; import { ThemeProvider, convert } from 'storybook/theming'; @@ -12,12 +12,19 @@ export default function Survey({ api }: { api: API }) { // eslint-disable-next-line compat/compat const userAgent = globalThis?.navigator?.userAgent; + const [isOpen, setIsOpen] = useState(true); + + useEffect(() => { + api.emit(ADDON_ONBOARDING_CHANNEL, { + from: 'guide', + type: 'openSurvey', + userAgent, + }); + }, [api, userAgent]); + const disableOnboarding = useCallback(() => { - // remove onboarding query parameter from current url - const url = new URL(window.location.href); - url.searchParams.set('onboarding', 'false'); - history.replaceState({}, '', url.href); - api.setQueryParams({ onboarding: 'false' }); + setIsOpen(false); + api.applyQueryParams({ onboarding: undefined }, { replace: true }); }, [api]); const complete = useCallback( @@ -41,7 +48,7 @@ export default function Survey({ api }: { api: API }) { return ( - + ); } diff --git a/code/addons/onboarding/src/features/IntentSurvey/IntentSurvey.stories.tsx b/code/addons/onboarding/src/features/IntentSurvey/IntentSurvey.stories.tsx index 3c98af8ad38c..2ec2107481e9 100644 --- a/code/addons/onboarding/src/features/IntentSurvey/IntentSurvey.stories.tsx +++ b/code/addons/onboarding/src/features/IntentSurvey/IntentSurvey.stories.tsx @@ -7,6 +7,7 @@ import { IntentSurvey } from './IntentSurvey'; const meta = { component: IntentSurvey, args: { + isOpen: true, onComplete: fn(), onDismiss: fn(), }, diff --git a/code/addons/onboarding/src/features/IntentSurvey/IntentSurvey.tsx b/code/addons/onboarding/src/features/IntentSurvey/IntentSurvey.tsx index 9f825a1b2e48..11780fd4c55d 100644 --- a/code/addons/onboarding/src/features/IntentSurvey/IntentSurvey.tsx +++ b/code/addons/onboarding/src/features/IntentSurvey/IntentSurvey.tsx @@ -65,9 +65,11 @@ const Checkbox = styled(Form.Checkbox)({ }); export const IntentSurvey = ({ + isOpen, onComplete, onDismiss, }: { + isOpen: boolean; onComplete: (formData: Record>) => void; onDismiss: () => void; }) => { @@ -172,7 +174,7 @@ export const IntentSurvey = ({ return ( { if (!isOpen) { diff --git a/code/core/src/components/components/Modal/Modal.styled.tsx b/code/core/src/components/components/Modal/Modal.styled.tsx index eb3ca76630e6..c5d31a4d8b5d 100644 --- a/code/core/src/components/components/Modal/Modal.styled.tsx +++ b/code/core/src/components/components/Modal/Modal.styled.tsx @@ -187,6 +187,7 @@ export const Close = ({ asChild, children, onClick, ...props }: CloseProps) => { return ( ), + play: async ({ canvas, step }) => { + const user = userEvent.setup(); + + await step('Open select and select an option', async () => { + const select = canvas.getByRole('button', { name: /Animal/i }); + await user.click(select); + + const listbox = await screen.findByRole('listbox'); + expect(listbox).toBeInTheDocument(); + + const option = within(listbox).getByRole('option', { name: 'Frog' }); + await user.click(option); + }); + + await step('Tab should land on sibling after select', async () => { + const select = canvas.getByRole('button', { name: /Frog/i }); + expect(select).toHaveFocus(); + + await user.tab(); + + const afterButton = canvas.getByRole('button', { name: 'After' }); + expect(afterButton).toHaveFocus(); + }); + + await step('Navigate back and reopen select', async () => { + await user.tab({ shift: true }); + + const select = canvas.getByRole('button', { name: /Frog/i }); + expect(select).toHaveFocus(); + + await user.keyboard('{Enter}'); + + const listbox = await screen.findByRole('listbox'); + expect(listbox).toBeInTheDocument(); + }); + + await step('Escape should return to select trigger', async () => { + await user.keyboard('{Escape}'); + + const select = canvas.getByRole('button', { name: /Frog/i }); + expect(select).toHaveFocus(); + }); + }, +}); + +export const WithSiblingsInToolbar = meta.story({ + name: 'With Siblings in Toolbar', + render: (args) => ( + + +