Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Core: Disable sidebar and don't load refs when singleStory=true #15201

Merged
merged 7 commits into from
Jun 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion lib/api/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ class ManagerProvider extends Component<ManagerProviderProps, State> {
path,
refId,
viewMode = props.docsMode ? 'docs' : 'story',
singleStory,
storyId,
docsMode,
navigate,
Expand All @@ -168,7 +169,7 @@ class ManagerProvider extends Component<ManagerProviderProps, State> {
setState: (stateChange: Partial<State>, callback) => this.setState(stateChange, callback),
});

const routeData = { location, path, viewMode, storyId, refId };
const routeData = { location, path, viewMode, singleStory, storyId, refId };

// Initialize the state to be the initial (persisted) state of the store.
// This gives the modules the chance to read the persisted state, apply their defaults
Expand Down
9 changes: 6 additions & 3 deletions lib/api/src/modules/layout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export const focusableUIElements = {
storyPanelRoot: 'storybook-panel-root',
};

export const init: ModuleFn = ({ store, provider }) => {
export const init: ModuleFn = ({ store, provider, singleStory }) => {
const api = {
toggleFullscreen(toggled?: boolean) {
return store.setState(
Expand All @@ -98,7 +98,7 @@ export const init: ModuleFn = ({ store, provider }) => {
layout: {
...state.layout,
isFullscreen: value,
showNav: shouldShowNav ? true : showNav,
showNav: !singleStory && shouldShowNav ? true : showNav,
},
};
},
Expand Down Expand Up @@ -153,8 +153,9 @@ export const init: ModuleFn = ({ store, provider }) => {
toggleNav(toggled?: boolean) {
return store.setState(
(state: State) => {
const { showPanel, isFullscreen } = state.layout;
if (singleStory) return { layout: state.layout };

const { showPanel, isFullscreen } = state.layout;
const value = typeof toggled !== 'undefined' ? toggled : !state.layout.showNav;
const shouldToggleFullScreen = showPanel === false && value === false;

Expand Down Expand Up @@ -221,6 +222,7 @@ export const init: ModuleFn = ({ store, provider }) => {
layout: {
...defaultState.layout,
...pick(options, Object.keys(defaultState.layout)),
...(singleStory && { showNav: false }),
},
ui: {
...defaultState.ui,
Expand All @@ -238,6 +240,7 @@ export const init: ModuleFn = ({ store, provider }) => {
const updatedLayout = {
...layout,
...pick(options, Object.keys(layout)),
...(singleStory && { showNav: false }),
};

const updatedUi = {
Expand Down
5 changes: 3 additions & 2 deletions lib/api/src/modules/refs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ const map = (
return input;
};

export const init: ModuleFn = ({ store, provider, fullAPI }, { runCheck = true } = {}) => {
export const init: ModuleFn = ({ store, provider, singleStory }, { runCheck = true } = {}) => {
const api: SubAPI = {
findRef: (source) => {
const refs = api.getRefs();
Expand Down Expand Up @@ -210,6 +210,7 @@ export const init: ModuleFn = ({ store, provider, fullAPI }, { runCheck = true }
},

setRef: (id, { stories, ...rest }, ready = false) => {
if (singleStory) return;
const { storyMapper = defaultStoryMapper } = provider.getConfig();
const ref = api.getRefs()[id];
const after = stories
Expand All @@ -233,7 +234,7 @@ export const init: ModuleFn = ({ store, provider, fullAPI }, { runCheck = true }
},
};

const refs = provider.getConfig().refs || {};
const refs = (!singleStory && provider.getConfig().refs) || {};

const initialState: SubState['refs'] = refs;

Expand Down
43 changes: 18 additions & 25 deletions lib/api/src/modules/url.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ export interface SubState {
customQueryParams: QueryParams;
}

const parseBoolean = (value: string) => {
if (value === 'true' || value === '1') return true;
if (value === 'false' || value === '0') return false;
return undefined;
};

// 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
Expand All @@ -34,12 +40,8 @@ export interface SubState {
let prevParams: ReturnType<typeof queryFromLocation>;
const initialUrlSupport = ({
state: { location, path, viewMode, storyId: storyIdFromUrl },
singleStory,
}: ModuleArgs) => {
const layout: Partial<Layout> = {};
const ui: Partial<UI> = {};
const query = queryFromLocation(location);
let selectedPanel;

const {
full,
panel,
Expand All @@ -53,27 +55,18 @@ const initialUrlSupport = ({
selectedStory, // deprecated
path: queryPath,
...otherParams // the rest gets passed to the iframe
} = query;
} = queryFromLocation(location);

if (full === 'true' || full === '1') {
layout.isFullscreen = true;
}
if (panel) {
if (['right', 'bottom'].includes(panel)) {
layout.panelPosition = panel;
} else if (panel === 'false' || panel === '0') {
layout.showPanel = false;
}
}
if (nav === 'false' || nav === '0') {
layout.showNav = false;
}
if (shortcuts === 'false' || shortcuts === '0') {
ui.enableShortcuts = false;
}
if (addonPanel) {
selectedPanel = addonPanel;
}
const layout: Partial<Layout> = {
isFullscreen: parseBoolean(full),
showNav: !singleStory && parseBoolean(nav),
showPanel: parseBoolean(panel),
panelPosition: ['right', 'bottom'].includes(panel) ? panel : undefined,
};
const ui: Partial<UI> = {
enableShortcuts: parseBoolean(shortcuts),
};
const selectedPanel = addonPanel || undefined;

// @deprecated Superceded by `panel=false`, to be removed in 7.0
if (addons === '0') {
Expand Down
139 changes: 113 additions & 26 deletions lib/api/src/tests/layout.test.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,127 @@
import { themes } from '@storybook/theming';
import { init as initLayout } from '../modules/layout';

let layoutApi;
let store;
let provider;
let currentState;

beforeEach(() => {
currentState = {
ui: {
enableShortcuts: true,
docsMode: false,
},
layout: {
isToolshown: true,
isFullscreen: false,
showPanel: true,
showNav: true,
panelPosition: 'bottom',
},
selectedPanel: 'storybook/actions/panel',
theme: themes.light,
};
store = {
getState: () => currentState,
setState: jest.fn((patch) => {
currentState = {
...currentState,
...(typeof patch === 'function' ? patch(currentState) : patch),
};
}),
};
provider = { getConfig: jest.fn(() => ({})) };
layoutApi = initLayout({ store, provider }).api;
});

describe('layout API', () => {
describe('setOptions', () => {
let layoutApi;
let store;
let currentState;
describe('toggleFullscreen', () => {
it('should toggle isFullscreen', () => {
currentState.layout.isFullscreen = false;
layoutApi.toggleFullscreen();
expect(currentState.layout.isFullscreen).toBe(true);
layoutApi.toggleFullscreen();
expect(currentState.layout.isFullscreen).toBe(false);
layoutApi.toggleFullscreen(false);
expect(currentState.layout.isFullscreen).toBe(false);
layoutApi.toggleFullscreen(true);
expect(currentState.layout.isFullscreen).toBe(true);
});

const getLastSetStateArgs = () => {
const { calls } = store.setState.mock;
return calls[calls.length - 1];
};
it('should not affect nav or panel state when enabling fullscreen', () => {
currentState.layout.isFullscreen = false;
layoutApi.toggleFullscreen();
expect(currentState.layout.showNav).toBe(true);
expect(currentState.layout.showNav).toBe(true);
});

beforeEach(() => {
currentState = {
ui: {
enableShortcuts: true,
docsMode: false,
},
layout: {
isToolshown: true,
it('should enable nav when exiting fullscreen', () => {
currentState.layout.isFullscreen = true;
currentState.layout.showNav = false;
layoutApi.toggleFullscreen();
expect(currentState.layout).toEqual(
expect.objectContaining({
isFullscreen: false,
showPanel: true,
showNav: true,
panelPosition: 'bottom',
},
selectedPanel: 'storybook/actions/panel',
theme: themes.light,
};
store = {
getState: () => currentState,
setState: jest.fn(),
};
layoutApi = initLayout({ store, provider: { getConfig: jest.fn(() => ({})) } }).api;
})
);
});

describe('singleStory=true', () => {
beforeEach(() => {
layoutApi = initLayout({ store, provider, singleStory: true }).api;
});

it('should NOT enable nav when exiting fullscreen', () => {
currentState.layout.showNav = false;
layoutApi.toggleFullscreen();
expect(currentState.layout).toEqual(
expect.objectContaining({
isFullscreen: true,
showPanel: true,
showNav: false,
})
);
});
});
});

describe('toggleNav', () => {
it('should toggle showNav', () => {
currentState.layout.showNav = true;
layoutApi.toggleNav();
expect(currentState.layout.showNav).toBe(false);
layoutApi.toggleNav();
expect(currentState.layout.showNav).toBe(true);
layoutApi.toggleNav(true);
expect(currentState.layout.showNav).toBe(true);
layoutApi.toggleNav(false);
expect(currentState.layout.showNav).toBe(false);
});

describe('singleStory=true', () => {
beforeEach(() => {
layoutApi = initLayout({ store, provider, singleStory: true }).api;
});

it('should NOT toggle showNav', () => {
currentState.layout.showNav = false;
layoutApi.toggleNav();
expect(currentState.layout.showNav).toBe(false);
layoutApi.toggleNav(true);
expect(currentState.layout.showNav).toBe(false);
});
});
});

describe('setOptions', () => {
const getLastSetStateArgs = () => {
const { calls } = store.setState.mock;
return calls[calls.length - 1];
};

it('should not change selectedPanel if it is undefined in the options', () => {
layoutApi.setOptions({});

Expand Down
30 changes: 6 additions & 24 deletions lib/api/src/tests/url.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,27 +76,23 @@ describe('initial state', () => {
});
});

describe('legacy query parameters', () => {
const defaultLegacyParameters = {
describe('deprecated query parameters', () => {
const defaultDeprecatedParameters = {
selectedKind: 'kind',
selectedStory: 'story',
full: '0',
addons: '1',
stories: '1',
panelRight: '0',
addonPanel: 'storybook%2Factions%2Factions-panel',
};

it('sets sensible storyId for selectedKind/Story', () => {
const location = { search: qs.stringify(defaultLegacyParameters) };
const location = { search: qs.stringify(defaultDeprecatedParameters) };
const {
state: { layout, selectedPanel, storyId },
state: { layout, storyId },
} = initURL({ state: { location, viewMode } });

// Nothing unexpected in layout
expect(layout).toEqual({});
// TODO: at the very least this should be unescaped
expect(selectedPanel).toEqual('storybook%2Factions%2Factions-panel');
expect(storyId).toEqual('kind--story');
});

Expand All @@ -109,24 +105,10 @@ describe('initial state', () => {
expect(storyId).toEqual('kind');
});

it('handles full parameter', () => {
const location = {
search: qs.stringify({
...defaultLegacyParameters,
full: '1',
}),
};
const {
state: { layout },
} = initURL({ state: { location } });

expect(layout).toEqual({ isFullscreen: true });
});

it('handles addons and stories parameters', () => {
const location = {
search: qs.stringify({
...defaultLegacyParameters,
...defaultDeprecatedParameters,
addons: '0',
stories: '0',
}),
Expand All @@ -141,7 +123,7 @@ describe('initial state', () => {
it('handles panelRight parameter', () => {
const location = {
search: qs.stringify({
...defaultLegacyParameters,
...defaultDeprecatedParameters,
panelRight: '1',
}),
};
Expand Down