Skip to content

Commit

Permalink
Drop second parameter, and read root element type off framework
Browse files Browse the repository at this point in the history
  • Loading branch information
tmeasday committed Nov 2, 2022
1 parent a7f29b7 commit 95da68c
Show file tree
Hide file tree
Showing 13 changed files with 89 additions and 117 deletions.
10 changes: 5 additions & 5 deletions code/lib/client-api/src/ClientApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import { StoryStoreFacade } from './StoryStoreFacade';

// ClientApi (and StoreStore) are really singletons. However they are not created until the
// relevant framework instanciates them via `start.js`. The good news is this happens right away.
let singleton: ClientApi<Framework, any>;
let singleton: ClientApi<Framework>;

const warningAlternatives = {
addDecorator: `Instead, use \`export const decorators = [];\` in your \`preview.js\`.`,
Expand Down Expand Up @@ -111,10 +111,10 @@ export const setGlobalRender = (render: StoryFn<Framework>) => {
};

const invalidStoryTypes = new Set(['string', 'number', 'boolean', 'symbol']);
export class ClientApi<TFramework extends Framework, TStorybookRoot = HTMLElement> {
facade: StoryStoreFacade<TFramework, TStorybookRoot>;
export class ClientApi<TFramework extends Framework> {
facade: StoryStoreFacade<TFramework>;

storyStore?: StoryStore<TFramework, TStorybookRoot>;
storyStore?: StoryStore<TFramework>;

private addons: Addon_ClientApiAddons<TFramework['storyResult']>;

Expand All @@ -124,7 +124,7 @@ export class ClientApi<TFramework extends Framework, TStorybookRoot = HTMLElemen
// just use numeric indexes
private lastFileName = 0;

constructor({ storyStore }: { storyStore?: StoryStore<TFramework, TStorybookRoot> } = {}) {
constructor({ storyStore }: { storyStore?: StoryStore<TFramework> } = {}) {
this.facade = new StoryStoreFacade();

this.addons = {};
Expand Down
6 changes: 3 additions & 3 deletions code/lib/client-api/src/StoryStoreFacade.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ import type { StoryStore } from '@storybook/store';
import { userOrAutoTitle, sortStoriesV6 } from '@storybook/store';
import { logger } from '@storybook/client-logger';

export class StoryStoreFacade<TFramework extends Framework, TStorybookRoot = HTMLElement> {
projectAnnotations: Store_NormalizedProjectAnnotations<TFramework, TStorybookRoot>;
export class StoryStoreFacade<TFramework extends Framework> {
projectAnnotations: Store_NormalizedProjectAnnotations<TFramework>;

entries: Record<StoryId, Addon_IndexEntry & { componentId?: ComponentId }>;

Expand Down Expand Up @@ -54,7 +54,7 @@ export class StoryStoreFacade<TFramework extends Framework, TStorybookRoot = HTM
});
}

getStoryIndex(store: StoryStore<TFramework, TStorybookRoot>) {
getStoryIndex(store: StoryStore<TFramework>) {
const fileNameOrder = Object.keys(this.csfExports);
const storySortParameter = this.projectAnnotations.parameters?.options?.storySort;

Expand Down
30 changes: 14 additions & 16 deletions code/lib/preview-web/src/Preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,18 @@ export type MaybePromise<T> = Promise<T> | T;
const renderToDOMDeprecated = deprecate(() => {},
`\`renderToDOM\` is deprecated, please rename to \`renderToRoot\``);

export class Preview<TFramework extends Framework, TStorybookRoot = HTMLElement> {
export class Preview<TFramework extends Framework> {
serverChannel?: Channel;

storyStore: StoryStore<TFramework, TStorybookRoot>;
storyStore: StoryStore<TFramework>;

getStoryIndex?: () => Store_StoryIndex;

importFn?: Store_ModuleImportFn;

renderToRoot?: RenderToRoot<TFramework, TStorybookRoot>;
renderToRoot?: RenderToRoot<TFramework>;

storyRenders: StoryRender<TFramework, TStorybookRoot>[] = [];
storyRenders: StoryRender<TFramework>[] = [];

previewEntryError?: Error;

Expand Down Expand Up @@ -83,7 +83,7 @@ export class Preview<TFramework extends Framework, TStorybookRoot = HTMLElement>
// getProjectAnnotations has been run, thus this slightly awkward approach
getStoryIndex?: () => Store_StoryIndex;
importFn: Store_ModuleImportFn;
getProjectAnnotations: () => MaybePromise<ProjectAnnotations<TFramework, TStorybookRoot>>;
getProjectAnnotations: () => MaybePromise<ProjectAnnotations<TFramework>>;
}) {
// We save these two on initialization in case `getProjectAnnotations` errors,
// in which case we may need them later when we recover.
Expand All @@ -108,8 +108,8 @@ export class Preview<TFramework extends Framework, TStorybookRoot = HTMLElement>
}

getProjectAnnotationsOrRenderError(
getProjectAnnotations: () => MaybePromise<ProjectAnnotations<TFramework, TStorybookRoot>>
): Store_PromiseLike<ProjectAnnotations<TFramework, TStorybookRoot>> {
getProjectAnnotations: () => MaybePromise<ProjectAnnotations<TFramework>>
): Store_PromiseLike<ProjectAnnotations<TFramework>> {
return SynchronousPromise.resolve()
.then(getProjectAnnotations)
.then((projectAnnotations) => {
Expand All @@ -136,9 +136,7 @@ export class Preview<TFramework extends Framework, TStorybookRoot = HTMLElement>
}

// If initialization gets as far as project annotations, this function runs.
initializeWithProjectAnnotations(
projectAnnotations: ProjectAnnotations<TFramework, TStorybookRoot>
) {
initializeWithProjectAnnotations(projectAnnotations: ProjectAnnotations<TFramework>) {
this.storyStore.setProjectAnnotations(projectAnnotations);

this.setInitialGlobals();
Expand Down Expand Up @@ -199,7 +197,7 @@ export class Preview<TFramework extends Framework, TStorybookRoot = HTMLElement>
async onGetProjectAnnotationsChanged({
getProjectAnnotations,
}: {
getProjectAnnotations: () => MaybePromise<ProjectAnnotations<TFramework, TStorybookRoot>>;
getProjectAnnotations: () => MaybePromise<ProjectAnnotations<TFramework>>;
}) {
delete this.previewEntryError;

Expand Down Expand Up @@ -311,11 +309,11 @@ export class Preview<TFramework extends Framework, TStorybookRoot = HTMLElement>
// main to be consistent with the previous behaviour. In the future,
// we will change it to go ahead and load the story, which will end up being
// "instant", although async.
renderStoryToElement(story: Store_Story<TFramework>, element: TStorybookRoot) {
renderStoryToElement(story: Store_Story<TFramework>, element: TFramework['rootElement']) {
if (!this.renderToRoot)
throw new Error(`Cannot call renderStoryToElement before initialization`);

const render = new StoryRender<TFramework, TStorybookRoot>(
const render = new StoryRender<TFramework>(
this.channel,
this.storyStore,
this.renderToRoot,
Expand All @@ -335,9 +333,9 @@ export class Preview<TFramework extends Framework, TStorybookRoot = HTMLElement>

async teardownRender(
render:
| StoryRender<TFramework, TStorybookRoot>
| TemplateDocsRender<TFramework, TStorybookRoot>
| StandaloneDocsRender<TFramework, TStorybookRoot>,
| StoryRender<TFramework>
| TemplateDocsRender<TFramework>
| StandaloneDocsRender<TFramework>,
{ viewModeChanged }: { viewModeChanged?: boolean } = {}
) {
this.storyRenders = this.storyRenders.filter((r) => r !== render);
Expand Down
55 changes: 21 additions & 34 deletions code/lib/preview-web/src/PreviewWeb.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,28 +50,25 @@ function focusInInput(event: Event) {
return /input|textarea/i.test(target.tagName) || target.getAttribute('contenteditable') !== null;
}

type PossibleRender<TFramework extends Framework, TStorybookRoot = HTMLElement> =
| StoryRender<TFramework, TStorybookRoot>
| TemplateDocsRender<TFramework, TStorybookRoot>
| StandaloneDocsRender<TFramework, TStorybookRoot>;

function isStoryRender<TFramework extends Framework, TStorybookRoot>(
r: PossibleRender<TFramework, TStorybookRoot>
): r is StoryRender<TFramework, TStorybookRoot> {
type PossibleRender<TFramework extends Framework> =
| StoryRender<TFramework>
| TemplateDocsRender<TFramework>
| StandaloneDocsRender<TFramework>;

function isStoryRender<TFramework extends Framework>(
r: PossibleRender<TFramework>
): r is StoryRender<TFramework> {
return r.type === 'story';
}

export class PreviewWeb<TFramework extends Framework, TStorybookRoot = HTMLElement> extends Preview<
TFramework,
TStorybookRoot
> {
export class PreviewWeb<TFramework extends Framework> extends Preview<TFramework> {
selectionStore: SelectionStore;

view: View<TStorybookRoot>;
view: View<TFramework['rootElement']>;

currentSelection?: Store_Selection;

currentRender?: PossibleRender<TFramework, TStorybookRoot>;
currentRender?: PossibleRender<TFramework>;

constructor({
// I'm not quite sure how to express this -- if you don't pass a view, you need to ensure
Expand All @@ -80,7 +77,7 @@ export class PreviewWeb<TFramework extends Framework, TStorybookRoot = HTMLEleme
view = new WebView() as any,
selectionStore = new UrlStore(),
}: {
view?: View<TStorybookRoot>;
view?: View<TFramework['rootElement']>;
selectionStore?: SelectionStore;
} = {}) {
super();
Expand All @@ -99,9 +96,7 @@ export class PreviewWeb<TFramework extends Framework, TStorybookRoot = HTMLEleme
this.channel.on(PRELOAD_ENTRIES, this.onPreloadStories.bind(this));
}

initializeWithProjectAnnotations(
projectAnnotations: ProjectAnnotations<TFramework, TStorybookRoot>
) {
initializeWithProjectAnnotations(projectAnnotations: ProjectAnnotations<TFramework>) {
return super
.initializeWithProjectAnnotations(projectAnnotations)
.then(() => this.setInitialGlobals());
Expand Down Expand Up @@ -182,7 +177,7 @@ export class PreviewWeb<TFramework extends Framework, TStorybookRoot = HTMLEleme
async onGetProjectAnnotationsChanged({
getProjectAnnotations,
}: {
getProjectAnnotations: () => MaybePromise<ProjectAnnotations<TFramework, TStorybookRoot>>;
getProjectAnnotations: () => MaybePromise<ProjectAnnotations<TFramework>>;
}) {
await super.onGetProjectAnnotationsChanged({ getProjectAnnotations });

Expand Down Expand Up @@ -302,9 +297,9 @@ export class PreviewWeb<TFramework extends Framework, TStorybookRoot = HTMLEleme
await this.teardownRender(this.currentRender);
}

let render: PossibleRender<TFramework, TStorybookRoot>;
let render: PossibleRender<TFramework>;
if (entry.type === 'story') {
render = new StoryRender<TFramework, TStorybookRoot>(
render = new StoryRender<TFramework>(
this.channel,
this.storyStore,
(...args: Parameters<typeof renderToRoot>) => {
Expand All @@ -317,17 +312,9 @@ export class PreviewWeb<TFramework extends Framework, TStorybookRoot = HTMLEleme
'story'
);
} else if (entry.standalone) {
render = new StandaloneDocsRender<TFramework, TStorybookRoot>(
this.channel,
this.storyStore,
entry
);
render = new StandaloneDocsRender<TFramework>(this.channel, this.storyStore, entry);
} else {
render = new TemplateDocsRender<TFramework, TStorybookRoot>(
this.channel,
this.storyStore,
entry
);
render = new TemplateDocsRender<TFramework>(this.channel, this.storyStore, entry);
}

// We need to store this right away, so if the story changes during
Expand Down Expand Up @@ -406,8 +393,8 @@ export class PreviewWeb<TFramework extends Framework, TStorybookRoot = HTMLEleme

if (isStoryRender(render)) {
if (!render.story) throw new Error('Render has not been prepared!');
this.storyRenders.push(render as StoryRender<TFramework, TStorybookRoot>);
(this.currentRender as StoryRender<TFramework, TStorybookRoot>).renderToElement(
this.storyRenders.push(render as StoryRender<TFramework>);
(this.currentRender as StoryRender<TFramework>).renderToElement(
this.view.prepareForStory(render.story)
);
} else {
Expand All @@ -420,7 +407,7 @@ export class PreviewWeb<TFramework extends Framework, TStorybookRoot = HTMLEleme
}

async teardownRender(
render: PossibleRender<TFramework, TStorybookRoot>,
render: PossibleRender<TFramework>,
{ viewModeChanged = false }: { viewModeChanged?: boolean } = {}
) {
this.storyRenders = this.storyRenders.filter((r) => r !== render);
Expand Down
6 changes: 2 additions & 4 deletions code/lib/preview-web/src/docs-context/DocsContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ import type { Channel } from '@storybook/channels';

import type { DocsContextProps } from './DocsContextProps';

export class DocsContext<TFramework extends Framework, TStorybookRoot = HTMLElement>
implements DocsContextProps<TFramework>
{
export class DocsContext<TFramework extends Framework> implements DocsContextProps<TFramework> {
private componentStoriesValue: Store_Story<TFramework>[];

private storyIdToCSFFile: Map<StoryId, Store_CSFFile<TFramework>>;
Expand All @@ -28,7 +26,7 @@ export class DocsContext<TFramework extends Framework, TStorybookRoot = HTMLElem

constructor(
public channel: Channel,
protected store: StoryStore<TFramework, TStorybookRoot>,
protected store: StoryStore<TFramework>,
public renderStoryToElement: DocsContextProps['renderStoryToElement'],
/** The CSF files known (via the index) to be refererenced by this docs file */
csfFiles: Store_CSFFile<TFramework>[],
Expand Down
9 changes: 6 additions & 3 deletions code/lib/preview-web/src/render/Render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,18 @@ export type RenderType = 'story' | 'docs';
* - Tracking the state of the rendering as it moves between preparing, rendering and tearing down.
* - Tracking what is rendered to know if a change requires re-rendering or teardown + recreation.
*/
export interface Render<TFramework extends Framework, TStorybookRoot = HTMLElement> {
export interface Render<TFramework extends Framework> {
type: RenderType;
id: StoryId;
isPreparing: () => boolean;
isEqual: (other: Render<TFramework, TStorybookRoot>) => boolean;
isEqual: (other: Render<TFramework>) => boolean;
disableKeyListeners: boolean;
teardown?: (options: { viewModeChanged: boolean }) => Promise<void>;
torndown: boolean;
renderToElement: (canvasElement: TStorybookRoot, renderStoryToElement?: any) => Promise<void>;
renderToElement: (
canvasElement: TFramework['rootElement'],
renderStoryToElement?: any
) => Promise<void>;
}

export const PREPARE_ABORTED = new Error('prepareAborted');
14 changes: 6 additions & 8 deletions code/lib/preview-web/src/render/StandaloneDocsRender.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ import { DocsContext } from '../docs-context/DocsContext';
* - *.mdx file that may or may not reference a specific CSF file with `<Meta of={} />`
*/

export class StandaloneDocsRender<TFramework extends Framework, TStorybookRoot = HTMLElement>
implements Render<TFramework, TStorybookRoot>
{
export class StandaloneDocsRender<TFramework extends Framework> implements Render<TFramework> {
public readonly type: RenderType = 'docs';

public readonly id: StoryId;
Expand All @@ -47,7 +45,7 @@ export class StandaloneDocsRender<TFramework extends Framework, TStorybookRoot =

constructor(
protected channel: Channel,
protected store: StoryStore<TFramework, TStorybookRoot>,
protected store: StoryStore<TFramework>,
public entry: Addon_IndexEntry
) {
this.id = entry.id;
Expand All @@ -68,22 +66,22 @@ export class StandaloneDocsRender<TFramework extends Framework, TStorybookRoot =
this.preparing = false;
}

isEqual(other: Render<TFramework, TStorybookRoot>): boolean {
isEqual(other: Render<TFramework>): boolean {
return !!(
this.id === other.id &&
this.exports &&
this.exports === (other as StandaloneDocsRender<TFramework, TStorybookRoot>).exports
this.exports === (other as StandaloneDocsRender<TFramework>).exports
);
}

async renderToElement(
canvasElement: TStorybookRoot,
canvasElement: TFramework['rootElement'],
renderStoryToElement: DocsContextProps['renderStoryToElement']
) {
if (!this.exports || !this.csfFiles || !this.store.projectAnnotations)
throw new Error('Cannot render docs before preparing');

const docsContext = new DocsContext<TFramework, TStorybookRoot>(
const docsContext = new DocsContext<TFramework>(
this.channel,
this.store,
renderStoryToElement,
Expand Down
Loading

0 comments on commit 95da68c

Please sign in to comment.