From 5f0dce2545cd8af5e8173cc9f6034a99d281c6dc Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Thu, 21 Oct 2021 15:57:44 +0200 Subject: [PATCH 01/11] migrate router to react-router --- lib/api/package.json | 2 - lib/api/src/index.tsx | 2 +- lib/api/src/modules/addons.ts | 6 +- lib/api/src/modules/url.ts | 27 ++++--- lib/router/README.md | 2 +- lib/router/package.json | 5 +- lib/router/src/router.tsx | 78 +++++++++++-------- lib/router/src/utils.ts | 2 +- lib/ui/src/app.stories.tsx | 9 +-- .../components/preview/preview.stories.tsx | 16 ++-- lib/ui/src/components/preview/toolbar.tsx | 2 +- lib/ui/src/index.tsx | 76 ++++++++++-------- yarn.lock | 39 +++++++++- 13 files changed, 158 insertions(+), 108 deletions(-) diff --git a/lib/api/package.json b/lib/api/package.json index 384c5f74b5ac..a3022ab2aa5a 100644 --- a/lib/api/package.json +++ b/lib/api/package.json @@ -38,7 +38,6 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@reach/router": "^1.3.4", "@storybook/channels": "6.4.0-beta.15", "@storybook/client-logger": "6.4.0-beta.15", "@storybook/core-events": "6.4.0-beta.15", @@ -46,7 +45,6 @@ "@storybook/router": "6.4.0-beta.15", "@storybook/semver": "^7.3.2", "@storybook/theming": "6.4.0-beta.15", - "@types/reach__router": "^1.3.7", "core-js": "^3.8.2", "fast-deep-equal": "^3.1.3", "global": "^4.4.0", diff --git a/lib/api/src/index.tsx b/lib/api/src/index.tsx index 5cc04a324247..8ad74a916a32 100644 --- a/lib/api/src/index.tsx +++ b/lib/api/src/index.tsx @@ -18,7 +18,7 @@ import { SHARED_STATE_SET, SET_STORIES, } from '@storybook/core-events'; -import { RenderData as RouterData } from '@storybook/router'; +import { RouterData } from '@storybook/router'; import { Listener } from '@storybook/channels'; import { createContext } from './context'; diff --git a/lib/api/src/modules/addons.ts b/lib/api/src/modules/addons.ts index a74a007da24f..7dbab9bd19c7 100644 --- a/lib/api/src/modules/addons.ts +++ b/lib/api/src/modules/addons.ts @@ -1,5 +1,5 @@ import { ReactElement } from 'react'; -import { WindowLocation } from '@reach/router'; +import type { RenderData } from '@storybook/router'; import deprecate from 'util-deprecate'; import dedent from 'ts-dedent'; @@ -35,13 +35,13 @@ export interface RenderOptions { export interface RouteOptions { storyId: string; viewMode: ViewMode; - location: WindowLocation; + location: RenderData['location']; path: string; } export interface MatchOptions { storyId: string; viewMode: ViewMode; - location: WindowLocation; + location: RenderData['location']; path: string; } diff --git a/lib/api/src/modules/url.ts b/lib/api/src/modules/url.ts index 59d057cf5a63..7062acd9883b 100644 --- a/lib/api/src/modules/url.ts +++ b/lib/api/src/modules/url.ts @@ -1,4 +1,3 @@ -import { navigate as navigateRouter, NavigateOptions } from '@reach/router'; import { once } from '@storybook/client-logger'; import { NAVIGATE_URL, @@ -6,7 +5,7 @@ import { SET_CURRENT_STORY, GLOBALS_UPDATED, } from '@storybook/core-events'; -import { queryFromLocation, navigate as queryNavigate, buildArgsParam } from '@storybook/router'; +import { queryFromLocation, buildArgsParam, NavigateOptions } from '@storybook/router'; import { toId, sanitize } from '@storybook/csf'; import deepEqual from 'fast-deep-equal'; import global from 'global'; @@ -28,15 +27,6 @@ const parseBoolean = (value: string) => { return undefined; }; -const navigateTo = (path: string, queryParams: Record = {}, options = {}) => { - const params = Object.entries(queryParams) - .filter(([, v]) => v) - .sort(([a], [b]) => (a < b ? -1 : 1)) - .map(([k, v]) => `${k}=${v}`); - const to = [path, ...params].join('&'); - return queryNavigate(to, options); -}; - // Initialize the state based on the URL. // NOTE: // Although we don't change the URL when you change the state, we do support setting initial state @@ -130,7 +120,7 @@ export interface QueryParams { } export interface SubAPI { - navigateUrl: (url: string, options: NavigateOptions<{}>) => void; + navigateUrl: (url: string, options: NavigateOptions) => void; getQueryParam: (key: string) => string | undefined; getUrlState: () => { queryParams: QueryParams; @@ -143,6 +133,15 @@ export interface SubAPI { } export const init: ModuleFn = ({ store, navigate, state, provider, fullAPI, ...rest }) => { + const navigateTo = (path: string, queryParams: Record = {}, options = {}) => { + const params = Object.entries(queryParams) + .filter(([, v]) => v) + .sort(([a], [b]) => (a < b ? -1 : 1)) + .map(([k, v]) => `${k}=${v}`); + const to = [path, ...params].join('&'); + return navigate(to, options); + }; + const api: SubAPI = { getQueryParam(key) { const { customQueryParams } = store.getState(); @@ -167,8 +166,8 @@ export const init: ModuleFn = ({ store, navigate, state, provider, fullAPI, ...r const equal = deepEqual(customQueryParams, update); if (!equal) store.setState({ customQueryParams: update }); }, - navigateUrl(url: string, options: NavigateOptions<{}>) { - navigateRouter(url, options); + navigateUrl(url, options) { + navigate(url, { ...options, plain: true }); }, }; diff --git a/lib/router/README.md b/lib/router/README.md index e356bd469fe7..d820bd39f10c 100644 --- a/lib/router/README.md +++ b/lib/router/README.md @@ -1,5 +1,5 @@ # Storybook Router -Storybook Router is a wrapper library for reach/router. +Storybook Router is a wrapper library for react-router. It ensures a single version of the router is used everywhere. It also includes some ready to use utils to read the path, query, viewMode and storyId from location. diff --git a/lib/router/package.json b/lib/router/package.json index 288aee90445e..0cbecba46f9f 100644 --- a/lib/router/package.json +++ b/lib/router/package.json @@ -40,15 +40,16 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@reach/router": "^1.3.4", "@storybook/client-logger": "6.4.0-beta.15", - "@types/reach__router": "^1.3.7", "core-js": "^3.8.2", "fast-deep-equal": "^3.1.3", "global": "^4.4.0", + "history": "^5.0.1", "lodash": "^4.17.20", "memoizerific": "^1.11.3", "qs": "^6.10.0", + "react-router": "^6.0.0-beta.7", + "react-router-dom": "^6.0.0-beta.7", "ts-dedent": "^2.0.0" }, "peerDependencies": { diff --git a/lib/router/src/router.tsx b/lib/router/src/router.tsx index 8ee8e1b85bc9..d6a06a0c1f2d 100644 --- a/lib/router/src/router.tsx +++ b/lib/router/src/router.tsx @@ -1,17 +1,7 @@ import global from 'global'; -import React, { ReactNode } from 'react'; - -import { - Link, - Location, - navigate, - LocationProvider, - RouteComponentProps, - LocationContext, - NavigateFn, - NavigateOptions, - History, -} from '@reach/router'; +import React, { ReactNode, useCallback } from 'react'; + +import { Link, BrowserRouter, useNavigate, useLocation, NavigateOptions } from 'react-router-dom'; import { ToggleVisibility } from './visibility'; import { queryFromString, parsePath, getMatch, StoryData } from './utils'; @@ -22,9 +12,12 @@ interface Other extends StoryData { singleStory?: boolean; } -export type RenderData = Pick & - Partial> & - Other; +export type RouterData = { + location: Partial; + navigate: ReturnType; +} & Other; + +export type RenderData = Pick & Other; interface MatchingData { match: null | { path: string }; @@ -52,8 +45,26 @@ export interface QueryLinkProps { const getBase = () => `${document.location.pathname}?`; -const queryNavigate: NavigateFn = (to: string | number, options?: NavigateOptions<{}>) => - typeof to === 'number' ? navigate(to) : navigate(`${getBase()}path=${to}`, options); +type ExpandedNavigateOptions = NavigateOptions & { plain?: boolean }; + +// const queryNavigate: NavigateFn = (to: string | number, options?: NavigateOptions<{}>) => +// typeof to === 'number' ? navigate(to) : navigate(`${getBase()}path=${to}`, options); + +const useQueryNavigate = () => { + const navigate = useNavigate(); + + return useCallback((to: string | number, options?: ExpandedNavigateOptions) => { + if (typeof to === 'string') { + const target = options?.plain ? to : `?path=${to}`; + return navigate(target, options); + } + if (typeof to === 'number') { + return navigate(to); + } + + return undefined; + }, []); +}; // A component that will navigate to a new location/path when clicked const QueryLink = ({ to, children, ...rest }: QueryLinkProps) => ( @@ -65,24 +76,24 @@ QueryLink.displayName = 'QueryLink'; // A render-prop component where children is called with a location // and will be called whenever it changes when it changes -const QueryLocation = ({ children }: QueryLocationProps) => ( - - {({ location }: RouteComponentProps): ReactNode => { - const { path, singleStory } = queryFromString(location.search); - const { viewMode, storyId, refId } = parsePath(path); +const QueryLocation = ({ children }: QueryLocationProps) => { + const location = useLocation(); + const { path, singleStory } = queryFromString(location.search); + const { viewMode, storyId, refId } = parsePath(path); - return children({ + return ( + <> + {children({ path, location, - navigate: queryNavigate, viewMode, storyId, refId, singleStory: singleStory === 'true', - }); - }} - -); + })} + + ); +}; QueryLocation.displayName = 'QueryLocation'; // A render-prop component for rendering when a certain path is hit. @@ -117,6 +128,9 @@ export { QueryLink as Link }; export { QueryMatch as Match }; export { QueryLocation as Location }; export { Route }; -export { queryNavigate as navigate }; -export { LocationProvider }; -export type { History }; +export { useQueryNavigate as useNavigate }; +export { BrowserRouter as LocationProvider }; +export { useNavigate as usePlainNavigate }; + +// eslint-disable-next-line no-undef +export type { ExpandedNavigateOptions as NavigateOptions }; diff --git a/lib/router/src/utils.ts b/lib/router/src/utils.ts index 0831485f8e04..47d1e81f0f4f 100644 --- a/lib/router/src/utils.ts +++ b/lib/router/src/utils.ts @@ -139,7 +139,7 @@ interface Query { export const queryFromString = memoize(1000)( (s: string): Query => qs.parse(s, { ignoreQueryPrefix: true }) ); -export const queryFromLocation = (location: { search: string }) => queryFromString(location.search); +export const queryFromLocation = (location: Partial) => queryFromString(location.search); export const stringifyQuery = (query: Query) => qs.stringify(query, { addQueryPrefix: true, encode: false }); diff --git a/lib/ui/src/app.stories.tsx b/lib/ui/src/app.stories.tsx index dcede85e012b..08ccb333f071 100644 --- a/lib/ui/src/app.stories.tsx +++ b/lib/ui/src/app.stories.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import { createMemorySource, createHistory } from '@reach/router'; import { Root as App } from './index'; import { PrettyFakeProvider, FakeProvider } from './FakeProvider'; @@ -13,12 +12,8 @@ export default { }, }; -const history = createHistory(createMemorySource('/?path=/story/story--id')); - -export const Default = () => ( - -); +export const Default = () => ; export const LoadingState = () => ( - + ); diff --git a/lib/ui/src/components/preview/preview.stories.tsx b/lib/ui/src/components/preview/preview.stories.tsx index 5a856c027211..bd3602759b98 100644 --- a/lib/ui/src/components/preview/preview.stories.tsx +++ b/lib/ui/src/components/preview/preview.stories.tsx @@ -1,8 +1,8 @@ import React from 'react'; import { Provider as ManagerProvider, Combo, Consumer } from '@storybook/api'; -import { createMemorySource, createHistory } from '@reach/router'; import { Location, LocationProvider } from '@storybook/router'; + import { ThemeProvider, ensure as ensureTheme, themes } from '@storybook/theming'; import { DecoratorFn } from '@storybook/react'; @@ -18,13 +18,17 @@ export default { component: Preview, decorators: [ ((StoryFn, c) => ( - + {(locationData) => ( - + {}} + > diff --git a/lib/ui/src/components/preview/toolbar.tsx b/lib/ui/src/components/preview/toolbar.tsx index bdf60c1fe2b9..f67d9afa4af6 100644 --- a/lib/ui/src/components/preview/toolbar.tsx +++ b/lib/ui/src/components/preview/toolbar.tsx @@ -7,7 +7,7 @@ import { Consumer, Combo, API, Story, Group, State, merge } from '@storybook/api import { shortcutToHumanString } from '@storybook/api/shortcut'; import { addons, Addon, types } from '@storybook/addons'; -import { Location, RenderData } from '@storybook/router'; +import { Location, RenderData, useNavigate } from '@storybook/router'; import { zoomTool } from './tools/zoom'; import * as S from './utils/components'; diff --git a/lib/ui/src/index.tsx b/lib/ui/src/index.tsx index 1ea275af269c..3ce49b2c55ed 100644 --- a/lib/ui/src/index.tsx +++ b/lib/ui/src/index.tsx @@ -1,8 +1,8 @@ import global from 'global'; -import React, { FunctionComponent } from 'react'; +import React, { FC, FunctionComponent } from 'react'; import ReactDOM from 'react-dom'; -import { Location, LocationProvider, History } from '@storybook/router'; +import { Location, LocationProvider, useNavigate } from '@storybook/router'; import { Provider as ManagerProvider, Combo } from '@storybook/api'; import { ThemeProvider, ensure as ensureTheme } from '@storybook/theming'; import { HelmetProvider } from 'react-helmet-async'; @@ -33,45 +33,53 @@ export interface RootProps { history?: History; } -export const Root: FunctionComponent = ({ provider, history }) => ( +export const Root: FunctionComponent = ({ provider }) => ( - - - {(locationData) => ( - - {({ state, api }: Combo) => { - const panelCount = Object.keys(api.getPanels()).length; - const story = api.getData(state.storyId, state.refId); - const isLoading = story - ? !!state.refs[state.refId] && !state.refs[state.refId].ready - : !state.storiesFailed && !state.storiesConfigured; - - return ( - - - - ); - }} - - )} - + +
); +const Main: FC<{ provider: Provider }> = ({ provider }) => { + const navigate = useNavigate(); + return ( + + {(locationData) => ( + + {({ state, api }: Combo) => { + const panelCount = Object.keys(api.getPanels()).length; + const story = api.getData(state.storyId, state.refId); + const isLoading = story + ? !!state.refs[state.refId] && !state.refs[state.refId].ready + : !state.storiesFailed && !state.storiesConfigured; + + return ( + + + + ); + }} + + )} + + ); +}; + function renderStorybookUI(domNode: HTMLElement, provider: Provider) { if (!(provider instanceof Provider)) { throw new Error('provider is not extended from the base Provider'); diff --git a/yarn.lock b/yarn.lock index d12ccd388685..f88c41339a37 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7586,7 +7586,6 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/api@workspace:lib/api" dependencies: - "@reach/router": ^1.3.4 "@storybook/channels": 6.4.0-beta.15 "@storybook/client-logger": 6.4.0-beta.15 "@storybook/core-events": 6.4.0-beta.15 @@ -7595,7 +7594,6 @@ __metadata: "@storybook/semver": ^7.3.2 "@storybook/theming": 6.4.0-beta.15 "@types/lodash": ^4.14.167 - "@types/reach__router": ^1.3.7 "@types/semver": ^7.3.4 core-js: ^3.8.2 fast-deep-equal: ^3.1.3 @@ -9021,15 +9019,16 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/router@workspace:lib/router" dependencies: - "@reach/router": ^1.3.4 "@storybook/client-logger": 6.4.0-beta.15 - "@types/reach__router": ^1.3.7 core-js: ^3.8.2 fast-deep-equal: ^3.1.3 global: ^4.4.0 + history: ^5.0.1 lodash: ^4.17.20 memoizerific: ^1.11.3 qs: ^6.10.0 + react-router: ^6.0.0-beta.7 + react-router-dom: ^6.0.0-beta.7 ts-dedent: ^2.0.0 peerDependencies: react: ^16.8.0 || ^17.0.0 @@ -25346,6 +25345,15 @@ fsevents@^1.2.7: languageName: node linkType: hard +"history@npm:^5.0.1": + version: 5.0.1 + resolution: "history@npm:5.0.1" + dependencies: + "@babel/runtime": ^7.7.6 + checksum: a36e20f3513acf5c3bd2c0edd5790cbf8ef6befb754595a7c99ee70b07afd6eef07396ec2f90f50e0602b580e4fbe6fe5950e812e4bb08fa541e296f9434a566 + languageName: node + linkType: hard + "hmac-drbg@npm:^1.0.1": version: 1.0.1 resolution: "hmac-drbg@npm:1.0.1" @@ -37953,6 +37961,29 @@ fsevents@^1.2.7: languageName: node linkType: hard +"react-router-dom@npm:^6.0.0-beta.7": + version: 6.0.0-beta.7 + resolution: "react-router-dom@npm:6.0.0-beta.7" + dependencies: + react-router: 6.0.0-beta.7 + peerDependencies: + history: ">=5" + react: ">=16.8" + react-dom: ">=16.8" + checksum: baf821316e5b1bb6f82f986e2a603123e5300264a036ea9ddeef4687c77daa4dd8a1fade4f890b6b1e5241745bc98791107cf8193596473e42be873ae6674dcc + languageName: node + linkType: hard + +"react-router@npm:6.0.0-beta.7, react-router@npm:^6.0.0-beta.7": + version: 6.0.0-beta.7 + resolution: "react-router@npm:6.0.0-beta.7" + peerDependencies: + history: ">=5" + react: ">=16.8" + checksum: f28071978b9329d3c3c998dd86a2e2ef59bfded6fa62976705959ffbfe6e0cb2b739f8dc364cd0deac69968444a3218c3cd94f48a4ed7753db91967321eeb9f1 + languageName: node + linkType: hard + "react-scripts@npm:3.4.4": version: 3.4.4 resolution: "react-scripts@npm:3.4.4" From b582c4fabba99fb7e70747c6aa3ab778743df826 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Thu, 21 Oct 2021 16:25:50 +0200 Subject: [PATCH 02/11] fix test --- lib/api/src/tests/url.test.js | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/lib/api/src/tests/url.test.js b/lib/api/src/tests/url.test.js index 7ea83c84bd7e..f8cbda652ef9 100644 --- a/lib/api/src/tests/url.test.js +++ b/lib/api/src/tests/url.test.js @@ -1,12 +1,10 @@ import qs from 'qs'; import { SET_CURRENT_STORY, GLOBALS_UPDATED } from '@storybook/core-events'; -import { navigate as reachNavigate } from '@reach/router'; import { init as initURL } from '../modules/url'; jest.mock('@storybook/client-logger'); -jest.mock('@reach/router'); jest.useFakeTimers(); describe('initial state', () => { @@ -193,7 +191,9 @@ describe('initModule', () => { it('updates args param on SET_CURRENT_STORY', async () => { store.setState(storyState('test--story')); - const { api, init } = initURL({ store, state: { location: {} }, fullAPI }); + const navigate = jest.fn(); + + const { api, init } = initURL({ store, state: { location: {} }, navigate, fullAPI }); Object.assign(fullAPI, api, { getCurrentStoryData: () => ({ args: { a: 1, b: 2 }, @@ -204,7 +204,7 @@ describe('initModule', () => { init(); fullAPI.emit(SET_CURRENT_STORY); - expect(reachNavigate).toHaveBeenCalledWith( + expect(navigate).toHaveBeenCalledWith( '/?path=/story/test--story&args=b:2', expect.objectContaining({ replace: true }) ); @@ -214,12 +214,14 @@ describe('initModule', () => { it('updates globals param on GLOBALS_UPDATED', async () => { store.setState(storyState('test--story')); - const { api, init } = initURL({ store, state: { location: {} }, fullAPI }); + const navigate = jest.fn(); + + const { api, init } = initURL({ store, state: { location: {} }, navigate, fullAPI }); Object.assign(fullAPI, api); init(); fullAPI.emit(GLOBALS_UPDATED, { globals: { a: 2 }, initialGlobals: { a: 1, b: 1 } }); - expect(reachNavigate).toHaveBeenCalledWith( + expect(navigate).toHaveBeenCalledWith( '/?path=/story/test--story&globals=a:2;b:!undefined', expect.objectContaining({ replace: true }) ); @@ -228,21 +230,22 @@ describe('initModule', () => { it('adds url params alphabetically', async () => { store.setState({ ...storyState('test--story'), customQueryParams: { full: 1 } }); + const navigate = jest.fn(); - const { api, init } = initURL({ store, state: { location: {} }, fullAPI }); + const { api, init } = initURL({ store, state: { location: {} }, navigate, fullAPI }); Object.assign(fullAPI, api, { getCurrentStoryData: () => ({ args: { a: 1 }, isLeaf: true }), }); init(); fullAPI.emit(GLOBALS_UPDATED, { globals: { g: 2 } }); - expect(reachNavigate).toHaveBeenCalledWith( + expect(navigate).toHaveBeenCalledWith( '/?path=/story/test--story&full=1&globals=g:2', expect.objectContaining({ replace: true }) ); fullAPI.emit(SET_CURRENT_STORY); - expect(reachNavigate).toHaveBeenCalledWith( + expect(navigate).toHaveBeenCalledWith( '/?path=/story/test--story&args=a:1&full=1&globals=g:2', expect.objectContaining({ replace: true }) ); From 5406ce2f3673080d90743dbb6e3593b4bd300f55 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Thu, 21 Oct 2021 16:30:50 +0200 Subject: [PATCH 03/11] cleanup --- lib/api/package.json | 1 + lib/ui/src/components/preview/toolbar.tsx | 2 +- yarn.lock | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/api/package.json b/lib/api/package.json index f71a39063b3b..cf8179c79410 100644 --- a/lib/api/package.json +++ b/lib/api/package.json @@ -45,6 +45,7 @@ "@storybook/router": "6.4.0-beta.18", "@storybook/semver": "^7.3.2", "@storybook/theming": "6.4.0-beta.18", + "fast-deep-equal": "^3.1.3", "global": "^4.4.0", "lodash": "^4.17.20", "memoizerific": "^1.11.3", diff --git a/lib/ui/src/components/preview/toolbar.tsx b/lib/ui/src/components/preview/toolbar.tsx index f67d9afa4af6..bdf60c1fe2b9 100644 --- a/lib/ui/src/components/preview/toolbar.tsx +++ b/lib/ui/src/components/preview/toolbar.tsx @@ -7,7 +7,7 @@ import { Consumer, Combo, API, Story, Group, State, merge } from '@storybook/api import { shortcutToHumanString } from '@storybook/api/shortcut'; import { addons, Addon, types } from '@storybook/addons'; -import { Location, RenderData, useNavigate } from '@storybook/router'; +import { Location, RenderData } from '@storybook/router'; import { zoomTool } from './tools/zoom'; import * as S from './utils/components'; diff --git a/yarn.lock b/yarn.lock index b1f6511c8099..7cf3a3e00363 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7595,6 +7595,7 @@ __metadata: "@storybook/theming": 6.4.0-beta.18 "@types/lodash": ^4.14.167 "@types/semver": ^7.3.4 + fast-deep-equal: ^3.1.3 flush-promises: ^1.0.2 global: ^4.4.0 lodash: ^4.17.20 From 007a7d1d2f636d19824c29312e5147ff9c305a5a Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Thu, 21 Oct 2021 18:00:55 +0200 Subject: [PATCH 04/11] fix tests --- lib/api/src/tests/url.test.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/api/src/tests/url.test.js b/lib/api/src/tests/url.test.js index f8cbda652ef9..e3b863eef7df 100644 --- a/lib/api/src/tests/url.test.js +++ b/lib/api/src/tests/url.test.js @@ -205,7 +205,7 @@ describe('initModule', () => { fullAPI.emit(SET_CURRENT_STORY); expect(navigate).toHaveBeenCalledWith( - '/?path=/story/test--story&args=b:2', + '/story/test--story&args=b:2', expect.objectContaining({ replace: true }) ); expect(store.getState().customQueryParams).toEqual({ args: 'b:2' }); @@ -222,7 +222,7 @@ describe('initModule', () => { fullAPI.emit(GLOBALS_UPDATED, { globals: { a: 2 }, initialGlobals: { a: 1, b: 1 } }); expect(navigate).toHaveBeenCalledWith( - '/?path=/story/test--story&globals=a:2;b:!undefined', + '/story/test--story&globals=a:2;b:!undefined', expect.objectContaining({ replace: true }) ); expect(store.getState().customQueryParams).toEqual({ globals: 'a:2;b:!undefined' }); @@ -240,13 +240,13 @@ describe('initModule', () => { fullAPI.emit(GLOBALS_UPDATED, { globals: { g: 2 } }); expect(navigate).toHaveBeenCalledWith( - '/?path=/story/test--story&full=1&globals=g:2', + '/story/test--story&full=1&globals=g:2', expect.objectContaining({ replace: true }) ); fullAPI.emit(SET_CURRENT_STORY); expect(navigate).toHaveBeenCalledWith( - '/?path=/story/test--story&args=a:1&full=1&globals=g:2', + '/story/test--story&args=a:1&full=1&globals=g:2', expect.objectContaining({ replace: true }) ); }); From 2adf602df8575301892ee19d43e9dc274434b8d1 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Fri, 22 Oct 2021 12:58:21 +0200 Subject: [PATCH 05/11] add location provider around stories in official storybook, as that's required in react-router --- examples/official-storybook/package.json | 1 + examples/official-storybook/preview.js | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/examples/official-storybook/package.json b/examples/official-storybook/package.json index d6fda70c4ff4..ca460e05209a 100644 --- a/examples/official-storybook/package.json +++ b/examples/official-storybook/package.json @@ -35,6 +35,7 @@ "@storybook/jest": "0.0.0-alpha.5", "@storybook/node-logger": "6.4.0-beta.19", "@storybook/react": "6.4.0-beta.19", + "@storybook/router": "6.4.0-beta.19", "@storybook/source-loader": "6.4.0-beta.19", "@storybook/testing-library": "0.0.0-alpha.3", "@storybook/theming": "6.4.0-beta.19", diff --git a/examples/official-storybook/preview.js b/examples/official-storybook/preview.js index c5c2ff77a69f..e1e3abbc8e83 100644 --- a/examples/official-storybook/preview.js +++ b/examples/official-storybook/preview.js @@ -11,6 +11,7 @@ import { useTheme, } from '@storybook/theming'; import { Symbols } from '@storybook/components'; +import { LocationProvider } from '@storybook/router'; import addHeadWarning from './head-warning'; @@ -87,6 +88,11 @@ const ThemedSetRoot = () => { }; export const decorators = [ + (StoryFn) => ( + + + + ), (StoryFn, { globals, parameters }) => { const theme = globals.theme || parameters.theme || (isChromatic() ? 'stacked' : 'light'); From 1c11d3b8b8e5ef6c5f3ec872fe3ce7f7b1d6c8f5 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Fri, 22 Oct 2021 13:00:41 +0200 Subject: [PATCH 06/11] do not wrap everything, just the components that need it --- examples/official-storybook/preview.js | 6 ------ .../notifications/NotificationItem.stories.js | 10 +++++++++- .../notifications/NotificationList.stories.js | 7 +++++++ 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/examples/official-storybook/preview.js b/examples/official-storybook/preview.js index e1e3abbc8e83..c5c2ff77a69f 100644 --- a/examples/official-storybook/preview.js +++ b/examples/official-storybook/preview.js @@ -11,7 +11,6 @@ import { useTheme, } from '@storybook/theming'; import { Symbols } from '@storybook/components'; -import { LocationProvider } from '@storybook/router'; import addHeadWarning from './head-warning'; @@ -88,11 +87,6 @@ const ThemedSetRoot = () => { }; export const decorators = [ - (StoryFn) => ( - - - - ), (StoryFn, { globals, parameters }) => { const theme = globals.theme || parameters.theme || (isChromatic() ? 'stacked' : 'light'); diff --git a/lib/ui/src/components/notifications/NotificationItem.stories.js b/lib/ui/src/components/notifications/NotificationItem.stories.js index 2fc9ac07bcb0..6c7ca43bb251 100644 --- a/lib/ui/src/components/notifications/NotificationItem.stories.js +++ b/lib/ui/src/components/notifications/NotificationItem.stories.js @@ -1,10 +1,18 @@ import React from 'react'; +import { LocationProvider } from '@storybook/router'; import NotificationItem from './NotificationItem'; export default { component: NotificationItem, title: 'UI/Notifications/NotificationItem', - decorators: [(storyFn) =>
{storyFn()}
], + decorators: [ + (StoryFn) => ( + + + + ), + (storyFn) =>
{storyFn()}
, + ], excludeStories: /.*Data$/, }; diff --git a/lib/ui/src/components/notifications/NotificationList.stories.js b/lib/ui/src/components/notifications/NotificationList.stories.js index 943ab0f985d1..87f2b8bf2769 100644 --- a/lib/ui/src/components/notifications/NotificationList.stories.js +++ b/lib/ui/src/components/notifications/NotificationList.stories.js @@ -1,4 +1,5 @@ import React from 'react'; +import { LocationProvider } from '@storybook/router'; import NotificationList from './NotificationList'; import itemMeta, * as itemStories from './NotificationItem.stories'; @@ -7,6 +8,12 @@ export default { component: NotificationList, title: 'UI/Notifications/NotificationList', decorators: [ + (StoryFn) => ( + + + + ), + (storyFn) => (
{storyFn()} From 2716baeb635f1744815a80f6d7a900812af411ec Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Fri, 22 Oct 2021 15:51:26 +0200 Subject: [PATCH 07/11] change the app component story --- lib/ui/src/app.stories.tsx | 67 +++++++++++++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 4 deletions(-) diff --git a/lib/ui/src/app.stories.tsx b/lib/ui/src/app.stories.tsx index 08ccb333f071..cb98577ee080 100644 --- a/lib/ui/src/app.stories.tsx +++ b/lib/ui/src/app.stories.tsx @@ -1,8 +1,10 @@ import React from 'react'; -import { Root as App } from './index'; +import { Provider as ManagerProvider } from '@storybook/api'; +import { LocationProvider } from '@storybook/router'; +import { HelmetProvider } from 'react-helmet-async'; +import App from './app'; import { PrettyFakeProvider, FakeProvider } from './FakeProvider'; -import Provider from './provider'; export default { title: 'UI/App', @@ -10,10 +12,67 @@ export default { parameters: { layout: 'fullscreen', }, + decorators: [ + (StoryFn) => ( + + + + + + ), + ], }; -export const Default = () => ; +export const Default = () => ( + {}} + docsMode={false} + > + + +); export const LoadingState = () => ( - + {}} + docsMode={false} + > + + ); From ea0fbfcf2cf27a64043689808ebde966f856b841 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Fri, 22 Oct 2021 16:06:22 +0200 Subject: [PATCH 08/11] fix lockfile --- yarn.lock | 1 + 1 file changed, 1 insertion(+) diff --git a/yarn.lock b/yarn.lock index ab97d44e5d7f..e1d6593ccfc8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -33487,6 +33487,7 @@ fsevents@^1.2.7: "@storybook/jest": 0.0.0-alpha.5 "@storybook/node-logger": 6.4.0-beta.19 "@storybook/react": 6.4.0-beta.19 + "@storybook/router": 6.4.0-beta.19 "@storybook/source-loader": 6.4.0-beta.19 "@storybook/testing-library": 0.0.0-alpha.3 "@storybook/theming": 6.4.0-beta.19 From 60925de313a119269b112e926b12b84f1fadeff3 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Fri, 22 Oct 2021 16:27:24 +0200 Subject: [PATCH 09/11] no panel in app story --- lib/ui/src/app.stories.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ui/src/app.stories.tsx b/lib/ui/src/app.stories.tsx index cb98577ee080..29cce7d842b4 100644 --- a/lib/ui/src/app.stories.tsx +++ b/lib/ui/src/app.stories.tsx @@ -44,7 +44,7 @@ export const Default = () => ( showNav: true, showPanel: true, }} - panelCount={1} + panelCount={0} docsOnly={false} /> @@ -71,7 +71,7 @@ export const LoadingState = () => ( showNav: true, showPanel: true, }} - panelCount={1} + panelCount={0} docsOnly={false} /> From c04e6ad20db58c2351102b78a9539160095ce93a Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Fri, 22 Oct 2021 16:28:30 +0200 Subject: [PATCH 10/11] add a storyId to preview stories --- lib/ui/src/components/preview/preview.stories.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ui/src/components/preview/preview.stories.tsx b/lib/ui/src/components/preview/preview.stories.tsx index bd3602759b98..bc3224a69faf 100644 --- a/lib/ui/src/components/preview/preview.stories.tsx +++ b/lib/ui/src/components/preview/preview.stories.tsx @@ -27,6 +27,7 @@ export default { {...locationData} docsMode={false} path="/story/story--id" + storyId="story--id" navigate={() => {}} > From 680e71753f7e0a33a67d79af7704b402919ee26a Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Mon, 25 Oct 2021 12:28:21 +0200 Subject: [PATCH 11/11] fix stories --- lib/router/src/router.tsx | 10 ++- .../components/preview/preview.stories.tsx | 78 +++++++++++++------ 2 files changed, 65 insertions(+), 23 deletions(-) diff --git a/lib/router/src/router.tsx b/lib/router/src/router.tsx index d6a06a0c1f2d..d6cf9bcc8aa1 100644 --- a/lib/router/src/router.tsx +++ b/lib/router/src/router.tsx @@ -1,7 +1,14 @@ import global from 'global'; import React, { ReactNode, useCallback } from 'react'; -import { Link, BrowserRouter, useNavigate, useLocation, NavigateOptions } from 'react-router-dom'; +import { + Link, + BrowserRouter, + useNavigate, + useLocation, + NavigateOptions, + Router, +} from 'react-router-dom'; import { ToggleVisibility } from './visibility'; import { queryFromString, parsePath, getMatch, StoryData } from './utils'; @@ -130,6 +137,7 @@ export { QueryLocation as Location }; export { Route }; export { useQueryNavigate as useNavigate }; export { BrowserRouter as LocationProvider }; +export { Router as BaseLocationProvider }; export { useNavigate as usePlainNavigate }; // eslint-disable-next-line no-undef diff --git a/lib/ui/src/components/preview/preview.stories.tsx b/lib/ui/src/components/preview/preview.stories.tsx index bc3224a69faf..5c41c8142b8c 100644 --- a/lib/ui/src/components/preview/preview.stories.tsx +++ b/lib/ui/src/components/preview/preview.stories.tsx @@ -1,7 +1,8 @@ import React from 'react'; +import { parsePath, createPath } from 'history'; import { Provider as ManagerProvider, Combo, Consumer } from '@storybook/api'; -import { Location, LocationProvider } from '@storybook/router'; +import { Location, BaseLocationProvider } from '@storybook/router'; import { ThemeProvider, ensure as ensureTheme, themes } from '@storybook/theming'; @@ -12,32 +13,65 @@ import { PrettyFakeProvider } from '../../FakeProvider'; import { previewProps } from './preview.mockdata'; const provider = new PrettyFakeProvider(); +const staticNavigator = { + createHref(to) { + return typeof to === 'string' ? to : createPath(to); + }, + + push() {}, + + replace() {}, + + go() {}, + + back() {}, + + forward() {}, +}; export default { title: 'UI/Preview', component: Preview, decorators: [ - ((StoryFn, c) => ( - - - {(locationData) => ( - {}} - > - - - - - )} - - - )) as DecoratorFn, + ((StoryFn, c) => { + const locationProp = parsePath('/?path=/story/story--id'); + + const location = { + pathname: locationProp.pathname || '/', + search: locationProp.search || '', + hash: locationProp.hash || '', + state: null, + key: 'default', + }; + + return ( + + + {(locationData) => ( + {}} + > + + + + + )} + + + ); + }) as DecoratorFn, ], };