mirror of
https://github.com/storybookjs/storybook.git
synced 2025-04-05 16:11:33 +08:00
MOVE event handlers into module init
This commit is contained in:
parent
36d4802d13
commit
ad8a245c85
@ -13,10 +13,8 @@ import React, {
|
||||
import {
|
||||
SET_STORIES,
|
||||
STORY_CHANGED,
|
||||
SELECT_STORY,
|
||||
SHARED_STATE_CHANGED,
|
||||
SHARED_STATE_SET,
|
||||
NAVIGATE_URL,
|
||||
} from '@storybook/core-events';
|
||||
import { RenderData as RouterData } from '@storybook/router';
|
||||
import { Listener } from '@storybook/channels';
|
||||
@ -33,16 +31,7 @@ import initNotifications, {
|
||||
SubAPI as NotificationAPI,
|
||||
} from './modules/notifications';
|
||||
import initStories, { SubState as StoriesSubState, SubAPI as StoriesAPI } from './modules/stories';
|
||||
import {
|
||||
StoriesRaw,
|
||||
StoriesHash,
|
||||
Story,
|
||||
Root,
|
||||
Group,
|
||||
isGroup,
|
||||
isRoot,
|
||||
isStory,
|
||||
} from './lib/stories';
|
||||
import { StoriesHash, Story, Root, Group, isGroup, isRoot, isStory } from './lib/stories';
|
||||
import initLayout, {
|
||||
ActiveTabs,
|
||||
SubState as LayoutSubState,
|
||||
@ -191,31 +180,6 @@ class ManagerProvider extends Component<ManagerProviderProps, State> {
|
||||
|
||||
initProviderApi({ provider, store, api });
|
||||
|
||||
api.on(STORY_CHANGED, (id: string) => {
|
||||
const options = api.getParameters(id, 'options');
|
||||
|
||||
if (options) {
|
||||
api.setOptions(options);
|
||||
}
|
||||
});
|
||||
|
||||
api.on(SET_STORIES, (data: { stories: StoriesRaw }) => {
|
||||
api.setStories(data.stories);
|
||||
const options = storyId
|
||||
? api.getParameters(storyId, 'options')
|
||||
: api.getParameters(Object.keys(data.stories)[0], 'options');
|
||||
api.setOptions(options);
|
||||
});
|
||||
api.on(
|
||||
SELECT_STORY,
|
||||
({ kind, story, ...rest }: { kind: string; story: string; [k: string]: any }) => {
|
||||
api.selectStory(kind, story, rest);
|
||||
}
|
||||
);
|
||||
api.on(NAVIGATE_URL, (url: string, options: { [k: string]: any }) => {
|
||||
api.navigateUrl(url, options);
|
||||
});
|
||||
|
||||
this.state = state;
|
||||
this.api = api;
|
||||
}
|
||||
@ -239,7 +203,7 @@ class ManagerProvider extends Component<ManagerProviderProps, State> {
|
||||
// a chance to do things that call other modules' APIs.
|
||||
this.modules.forEach(({ init }) => {
|
||||
if (init) {
|
||||
init({ api: this.api });
|
||||
init();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -24,8 +24,8 @@ export interface SubAPI {
|
||||
setShortcut(action: Action, value: KeyCollection): Promise<KeyCollection>;
|
||||
restoreAllDefaultShortcuts(): Promise<Shortcuts>;
|
||||
restoreDefaultShortcut(action: Action): Promise<KeyCollection>;
|
||||
handleKeydownEvent(api: API, event: Event): void;
|
||||
handleShortcutFeature(api: API, feature: Action): void;
|
||||
handleKeydownEvent(event: Event): void;
|
||||
handleShortcutFeature(feature: Action): void;
|
||||
}
|
||||
export type KeyCollection = string[];
|
||||
|
||||
@ -83,7 +83,14 @@ export interface Event extends KeyboardEvent {
|
||||
};
|
||||
}
|
||||
|
||||
export default function initShortcuts({ store }: Module) {
|
||||
function focusInInput(event: Event) {
|
||||
return (
|
||||
/input|textarea/i.test(event.target.tagName) ||
|
||||
event.target.getAttribute('contenteditable') !== null
|
||||
);
|
||||
}
|
||||
|
||||
export default function initShortcuts({ store, fullAPI }: Module) {
|
||||
const api: SubAPI = {
|
||||
// Getting and setting shortcuts
|
||||
getShortcutKeys(): Shortcuts {
|
||||
@ -107,7 +114,7 @@ export default function initShortcuts({ store }: Module) {
|
||||
},
|
||||
|
||||
// Listening to shortcut events
|
||||
handleKeydownEvent(fullApi, event) {
|
||||
handleKeydownEvent(event) {
|
||||
const shortcut = eventToShortcut(event);
|
||||
const shortcuts = api.getShortcutKeys();
|
||||
const actions = keys(shortcuts);
|
||||
@ -115,11 +122,11 @@ export default function initShortcuts({ store }: Module) {
|
||||
shortcutMatchesShortcut(shortcut, shortcuts[feature])
|
||||
);
|
||||
if (matchedFeature) {
|
||||
api.handleShortcutFeature(fullApi, matchedFeature);
|
||||
api.handleShortcutFeature(matchedFeature);
|
||||
}
|
||||
},
|
||||
|
||||
handleShortcutFeature(fullApi, feature) {
|
||||
handleShortcutFeature(feature) {
|
||||
const {
|
||||
layout: { isFullscreen, showNav, showPanel },
|
||||
ui: { enableShortcuts },
|
||||
@ -130,34 +137,34 @@ export default function initShortcuts({ store }: Module) {
|
||||
switch (feature) {
|
||||
case 'escape': {
|
||||
if (isFullscreen) {
|
||||
fullApi.toggleFullscreen();
|
||||
fullAPI.toggleFullscreen();
|
||||
} else if (!showNav) {
|
||||
fullApi.toggleNav();
|
||||
fullAPI.toggleNav();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'focusNav': {
|
||||
if (isFullscreen) {
|
||||
fullApi.toggleFullscreen();
|
||||
fullAPI.toggleFullscreen();
|
||||
}
|
||||
if (!showNav) {
|
||||
fullApi.toggleNav();
|
||||
fullAPI.toggleNav();
|
||||
}
|
||||
fullApi.focusOnUIElement(focusableUIElements.storyListMenu);
|
||||
fullAPI.focusOnUIElement(focusableUIElements.storyListMenu);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'search': {
|
||||
if (isFullscreen) {
|
||||
fullApi.toggleFullscreen();
|
||||
fullAPI.toggleFullscreen();
|
||||
}
|
||||
if (!showNav) {
|
||||
fullApi.toggleNav();
|
||||
fullAPI.toggleNav();
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
fullApi.focusOnUIElement(focusableUIElements.storySearchField);
|
||||
fullAPI.focusOnUIElement(focusableUIElements.storySearchField);
|
||||
}, 0);
|
||||
break;
|
||||
}
|
||||
@ -178,92 +185,92 @@ export default function initShortcuts({ store }: Module) {
|
||||
|
||||
case 'focusPanel': {
|
||||
if (isFullscreen) {
|
||||
fullApi.toggleFullscreen();
|
||||
fullAPI.toggleFullscreen();
|
||||
}
|
||||
if (!showPanel) {
|
||||
fullApi.togglePanel();
|
||||
fullAPI.togglePanel();
|
||||
}
|
||||
fullApi.focusOnUIElement(focusableUIElements.storyPanelRoot);
|
||||
fullAPI.focusOnUIElement(focusableUIElements.storyPanelRoot);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'nextStory': {
|
||||
fullApi.jumpToStory(1);
|
||||
fullAPI.jumpToStory(1);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'prevStory': {
|
||||
fullApi.jumpToStory(-1);
|
||||
fullAPI.jumpToStory(-1);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'nextComponent': {
|
||||
fullApi.jumpToComponent(1);
|
||||
fullAPI.jumpToComponent(1);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'prevComponent': {
|
||||
fullApi.jumpToComponent(-1);
|
||||
fullAPI.jumpToComponent(-1);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'fullScreen': {
|
||||
fullApi.toggleFullscreen();
|
||||
fullAPI.toggleFullscreen();
|
||||
break;
|
||||
}
|
||||
|
||||
case 'togglePanel': {
|
||||
if (isFullscreen) {
|
||||
fullApi.toggleFullscreen();
|
||||
fullApi.resetLayout();
|
||||
fullAPI.toggleFullscreen();
|
||||
fullAPI.resetLayout();
|
||||
}
|
||||
|
||||
fullApi.togglePanel();
|
||||
fullAPI.togglePanel();
|
||||
break;
|
||||
}
|
||||
|
||||
case 'toggleNav': {
|
||||
if (isFullscreen) {
|
||||
fullApi.toggleFullscreen();
|
||||
fullApi.resetLayout();
|
||||
fullAPI.toggleFullscreen();
|
||||
fullAPI.resetLayout();
|
||||
}
|
||||
|
||||
fullApi.toggleNav();
|
||||
fullAPI.toggleNav();
|
||||
break;
|
||||
}
|
||||
|
||||
case 'toolbar': {
|
||||
fullApi.toggleToolbar();
|
||||
fullAPI.toggleToolbar();
|
||||
break;
|
||||
}
|
||||
|
||||
case 'panelPosition': {
|
||||
if (isFullscreen) {
|
||||
fullApi.toggleFullscreen();
|
||||
fullAPI.toggleFullscreen();
|
||||
}
|
||||
if (!showPanel) {
|
||||
fullApi.togglePanel();
|
||||
fullAPI.togglePanel();
|
||||
}
|
||||
|
||||
fullApi.togglePanelPosition();
|
||||
fullAPI.togglePanelPosition();
|
||||
break;
|
||||
}
|
||||
|
||||
case 'aboutPage': {
|
||||
fullApi.navigate('/settings/about');
|
||||
fullAPI.navigate('/settings/about');
|
||||
break;
|
||||
}
|
||||
|
||||
case 'shortcutsPage': {
|
||||
fullApi.navigate('/settings/shortcuts');
|
||||
fullAPI.navigate('/settings/shortcuts');
|
||||
break;
|
||||
}
|
||||
case 'collapseAll': {
|
||||
fullApi.collapseAll();
|
||||
fullAPI.collapseAll();
|
||||
break;
|
||||
}
|
||||
case 'expandAll': {
|
||||
fullApi.expandAll();
|
||||
fullAPI.expandAll();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -281,26 +288,19 @@ export default function initShortcuts({ store }: Module) {
|
||||
),
|
||||
};
|
||||
|
||||
const init = ({ api: fullApi }: API) => {
|
||||
function focusInInput(event: Event) {
|
||||
return (
|
||||
/input|textarea/i.test(event.target.tagName) ||
|
||||
event.target.getAttribute('contenteditable') !== null
|
||||
);
|
||||
}
|
||||
const init = () => {
|
||||
// Listen for keydown events in the manager
|
||||
document.addEventListener('keydown', (event: Event) => {
|
||||
if (!focusInInput(event)) {
|
||||
fullApi.handleKeydownEvent(fullApi, event);
|
||||
fullAPI.handleKeydownEvent(event);
|
||||
}
|
||||
});
|
||||
|
||||
// Also listen to keydown events sent over the channel
|
||||
fullApi.on(PREVIEW_KEYDOWN, (data: { event: Event }) => {
|
||||
fullApi.handleKeydownEvent(fullApi, data.event);
|
||||
fullAPI.on(PREVIEW_KEYDOWN, (data: { event: Event }) => {
|
||||
fullAPI.handleKeydownEvent(data.event);
|
||||
});
|
||||
};
|
||||
const result = { api, state, init };
|
||||
|
||||
return result;
|
||||
return { api, state, init };
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { DOCS_MODE } from 'global';
|
||||
import { toId, sanitize } from '@storybook/csf';
|
||||
|
||||
import { STORY_CHANGED, SET_STORIES, SELECT_STORY } from '@storybook/core-events';
|
||||
import {
|
||||
transformStoriesRawToStoriesHash,
|
||||
StoriesHash,
|
||||
@ -40,6 +41,7 @@ export interface SubAPI {
|
||||
// When adding a group, also add all of its children, depth first
|
||||
|
||||
const initStoriesApi = ({
|
||||
fullAPI,
|
||||
store,
|
||||
navigate,
|
||||
provider,
|
||||
@ -146,6 +148,31 @@ const initStoriesApi = ({
|
||||
}
|
||||
};
|
||||
|
||||
const init = () => {
|
||||
fullAPI.on(STORY_CHANGED, (id: string) => {
|
||||
const options = fullAPI.getParameters(id, 'options');
|
||||
|
||||
if (options) {
|
||||
fullAPI.setOptions(options);
|
||||
}
|
||||
});
|
||||
|
||||
fullAPI.on(SET_STORIES, (data: { stories: StoriesRaw }) => {
|
||||
const { storyId } = store.getState();
|
||||
fullAPI.setStories(data.stories);
|
||||
const options = storyId
|
||||
? fullAPI.getParameters(storyId, 'options')
|
||||
: fullAPI.getParameters(Object.keys(data.stories)[0], 'options');
|
||||
fullAPI.setOptions(options);
|
||||
});
|
||||
fullAPI.on(
|
||||
SELECT_STORY,
|
||||
({ kind, story, ...rest }: { kind: string; story: string; [k: string]: any }) => {
|
||||
fullAPI.selectStory(kind, story, rest);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
// Recursively traverse storiesHash from the initial storyId until finding
|
||||
// the leaf story.
|
||||
const findLeafStoryId = (storiesHash: StoriesHash, storyId: string): string => {
|
||||
@ -253,6 +280,7 @@ const initStoriesApi = ({
|
||||
viewMode: initialViewMode,
|
||||
storiesConfigured: false,
|
||||
},
|
||||
init,
|
||||
};
|
||||
};
|
||||
export default initStoriesApi;
|
||||
|
@ -2,6 +2,7 @@ import { navigate as navigateRouter, NavigateOptions } from '@reach/router';
|
||||
import { queryFromLocation } from '@storybook/router';
|
||||
import { toId } from '@storybook/csf';
|
||||
|
||||
import { NAVIGATE_URL } from '@storybook/core-events';
|
||||
import { Module } from '../index';
|
||||
import { PanelPositions } from './layout';
|
||||
|
||||
@ -105,7 +106,7 @@ export interface SubAPI {
|
||||
setQueryParams: (input: QueryParams) => void;
|
||||
}
|
||||
|
||||
export default function({ store, navigate, state, provider, ...rest }: Module) {
|
||||
export default function({ store, navigate, state, provider, fullAPI, ...rest }: Module) {
|
||||
const api: SubAPI = {
|
||||
getQueryParam: key => {
|
||||
const { customQueryParams } = store.getState();
|
||||
@ -146,8 +147,15 @@ export default function({ store, navigate, state, provider, ...rest }: Module) {
|
||||
},
|
||||
};
|
||||
|
||||
const init = () => {
|
||||
fullAPI.on(NAVIGATE_URL, (url: string, options: { [k: string]: any }) => {
|
||||
fullAPI.navigateUrl(url, options);
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
api,
|
||||
state: initialUrlSupport({ store, navigate, state, provider, ...rest }),
|
||||
state: initialUrlSupport({ store, navigate, state, provider, fullAPI, ...rest }),
|
||||
init,
|
||||
};
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ export interface SubAPI {
|
||||
versionUpdateAvailable: () => boolean;
|
||||
}
|
||||
|
||||
export default function({ store, mode }: Module) {
|
||||
export default function({ store, mode, fullAPI }: Module) {
|
||||
const { dismissedVersionNotification } = store.getState();
|
||||
|
||||
const state = {
|
||||
@ -106,10 +106,11 @@ export default function({ store, mode }: Module) {
|
||||
};
|
||||
|
||||
// Grab versions from the server/local storage right away
|
||||
async function init({ api: fullApi }: API) {
|
||||
async function init() {
|
||||
const { versions = {} } = store.getState();
|
||||
|
||||
const { latest, next } = getVersionCheckData();
|
||||
|
||||
await store.setState({
|
||||
versions: { ...versions, latest, next },
|
||||
});
|
||||
@ -125,7 +126,7 @@ export default function({ store, mode }: Module) {
|
||||
!semver.prerelease(latestVersion) &&
|
||||
mode !== 'production'
|
||||
) {
|
||||
fullApi.addNotification({
|
||||
fullAPI.addNotification({
|
||||
id: 'update',
|
||||
link: '/settings/about',
|
||||
content: `🎉 Storybook ${latestVersion} is available!`,
|
||||
|
Loading…
x
Reference in New Issue
Block a user