diff --git a/app/rax/src/client/index.ts b/app/rax/src/client/index.ts index 21d3f4bf39..54de76c858 100644 --- a/app/rax/src/client/index.ts +++ b/app/rax/src/client/index.ts @@ -1,3 +1,4 @@ +export type { DecoratorFn } from './preview'; export { storiesOf, setAddon, @@ -5,6 +6,12 @@ export { addParameters, configure, getStorybook, - forceReRender, raw, + forceReRender, } from './preview'; + +export * from './preview/types-6-3'; + +if (module && module.hot && module.hot.decline) { + module.hot.decline(); +} diff --git a/app/rax/src/client/preview/index.ts b/app/rax/src/client/preview/index.ts deleted file mode 100644 index b198c52c60..0000000000 --- a/app/rax/src/client/preview/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { start } from '@storybook/core/client'; - -import './globals'; -import render from './render'; - -const { configure: coreConfigure, clientApi, forceReRender } = start(render); - -export const { - setAddon, - addDecorator, - addParameters, - clearDecorators, - getStorybook, - raw, -} = clientApi; - -const framework = 'rax'; -export const storiesOf = (kind: string, m: any) => - clientApi.storiesOf(kind, m).addParameters({ framework }); -export const configure = (loadable: any, m: any) => coreConfigure(framework, loadable, m); - -export { forceReRender }; diff --git a/app/rax/src/client/preview/index.tsx b/app/rax/src/client/preview/index.tsx new file mode 100644 index 0000000000..7d06738b36 --- /dev/null +++ b/app/rax/src/client/preview/index.tsx @@ -0,0 +1,66 @@ +/* eslint-disable prefer-destructuring */ +import React, { createElement } from 'rax'; +import { start } from '@storybook/core/client'; +// eslint-disable-next-line import/no-extraneous-dependencies +import { ClientStoryApi, Loadable } from '@storybook/addons'; +import { IStorybookSection, StoryFnReactReturnType } from './types'; +import { Story } from './types-6-3'; +import './globals'; +import render from './render'; + +const framework = 'rax'; + +// @ts-ignore +const globalRender: Story = (args, { parameters }) => { + const Component = parameters.component; + return ; +}; + +interface ClientApi extends ClientStoryApi { + setAddon(addon: any): void; + configure(loader: Loadable, module: NodeModule): void; + getStorybook(): IStorybookSection[]; + clearDecorators(): void; + forceReRender(): void; + raw: () => any; // todo add type +} + +const api = start(render); + +// @ts-ignore +api.clientApi.globalRender = globalRender; + +export const storiesOf: ClientApi['storiesOf'] = (kind, m) => { + return (api.clientApi.storiesOf(kind, m) as ReturnType).addParameters({ + framework, + }); +}; + +export const configure: ClientApi['configure'] = (...args) => api.configure(framework, ...args); +export const addDecorator: ClientApi['addDecorator'] = api.clientApi + .addDecorator as ClientApi['addDecorator']; +export type DecoratorFn = Parameters[0]; +export const addParameters: ClientApi['addParameters'] = api.clientApi + .addParameters as ClientApi['addParameters']; +export const clearDecorators: ClientApi['clearDecorators'] = api.clientApi.clearDecorators; +export const setAddon: ClientApi['setAddon'] = api.clientApi.setAddon; +export const forceReRender: ClientApi['forceReRender'] = api.forceReRender; +export const getStorybook: ClientApi['getStorybook'] = api.clientApi.getStorybook; +export const raw: ClientApi['raw'] = api.clientApi.raw; + +// const { configure: coreConfigure, clientApi, forceReRender } = start(render); + +// export const { +// setAddon, +// addDecorator, +// addParameters, +// clearDecorators, +// getStorybook, +// raw, +// } = clientApi; + +// export const storiesOf = (kind: string, m: any) => +// clientApi.storiesOf(kind, m).addParameters({ framework }); +// export const configure = (loadable: any, m: any) => coreConfigure(framework, loadable, m); + +// export { forceReRender }; diff --git a/app/rax/src/client/preview/render.ts b/app/rax/src/client/preview/render.ts deleted file mode 100644 index f791ccfff7..0000000000 --- a/app/rax/src/client/preview/render.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { createElement, render } from 'rax'; -import * as DriverDOM from 'driver-dom'; - -import { document } from 'global'; -import dedent from 'ts-dedent'; - -const rootElement = document ? document.getElementById('root') : null; - -export default function renderMain({ - storyFn, - kind, - name, - showMain, - showError, -}: { - storyFn: Function; - kind: string; - name: string; - showMain: () => any; - showError: (input: { title: string; description: string }) => void; -}) { - const Element = storyFn; - - if (!Element) { - showError({ - title: `Expecting a Rax element from the story: "${name}" of "${kind}".`, - description: dedent` - Did you forget to return the Rax element from the story? - Use "() => ()" or "() => { return ; }" when defining the story. - `, - }); - return; - } - - showMain(); - - // There is something miscellaneous here, for now, more precisely on L23, - // as we are using the storyFn directly and not calling it, so `Element` is a - // function but according to `createElement` types, there is no signature - // taking a function as input. - // @ts-expect-error - render(createElement(Element), rootElement, { - driver: DriverDOM, - }); -} diff --git a/app/rax/src/client/preview/render.tsx b/app/rax/src/client/preview/render.tsx new file mode 100644 index 0000000000..d80289e08b --- /dev/null +++ b/app/rax/src/client/preview/render.tsx @@ -0,0 +1,61 @@ +import { createElement, render, Component } from 'rax'; +import * as DriverDOM from 'driver-dom'; +import dedent from 'ts-dedent'; + +import { document } from 'global'; +import { RenderContext } from './types'; + +const rootElement = document ? document.getElementById('root') : null; + +const renderDom = (node: any, el: Element, driver: any) => +new Promise((resolve) => { + render(node, el, driver, resolve); +}); + +class ErrorBoundary extends Component<{ + showException: (err: Error) => void; + showMain: () => void; +}> { + state = { hasError: false }; + + static getDerivedStateFromError() { + return { hasError: true }; + } + + componentDidMount() { + const { hasError } = this.state; + const { showMain } = this.props; + if (!hasError) { + showMain(); + } + } + + componentDidCatch(err: Error) { + const { showException } = this.props; + // message partially duplicates stack, strip it + showException(err); + } + + render() { + const { hasError } = this.state; + const { children } = this.props; + + return hasError ? null : children; + } +} + +export default async function renderMain({ + args, + storyFn, + showMain, +}: RenderContext) { + showMain(); + + // There is something miscellaneous here, for now, more precisely on L23, + // as we are using the storyFn directly and not calling it, so `Element` is a + // function but according to `createElement` types, there is no signature + // taking a function as input. + await renderDom(createElement(storyFn, args), rootElement, { + driver: DriverDOM, + }); +} diff --git a/app/rax/src/client/preview/types-6-0.ts b/app/rax/src/client/preview/types-6-0.ts new file mode 100644 index 0000000000..1f103eba50 --- /dev/null +++ b/app/rax/src/client/preview/types-6-0.ts @@ -0,0 +1,24 @@ +import { ComponentType } from 'rax'; +import { Args as DefaultArgs, Annotations, BaseMeta, BaseStory } from '@storybook/addons'; +import { StoryFnReactReturnType } from './types'; + +export type { Args, ArgTypes, Parameters, StoryContext } from '@storybook/addons'; + +type ReactComponent = ComponentType; +type ReactReturnType = StoryFnReactReturnType; + +/** + * Metadata to configure the stories for a component. + * + * @see [Default export](https://storybook.js.org/docs/formats/component-story-format/#default-export) + */ +export type Meta = BaseMeta & + Annotations; + +/** + * Story function that represents a component example. + * + * @see [Named Story exports](https://storybook.js.org/docs/formats/component-story-format/#named-story-exports) + */ +export type Story = BaseStory & + Annotations; diff --git a/app/rax/src/client/preview/types-6-3.ts b/app/rax/src/client/preview/types-6-3.ts new file mode 100644 index 0000000000..edfa6cfa9a --- /dev/null +++ b/app/rax/src/client/preview/types-6-3.ts @@ -0,0 +1,26 @@ +import { ComponentProps, JSXElementConstructor } from 'rax'; +import type { Story, Meta } from './types-6-0'; + +export * from './types-6-0'; + +/** + * For the common case where a component's stories are simple components that receives args as props: + * + * ```tsx + * export default { ... } as ComponentMeta; + * ``` + */ +export type ComponentMeta< + T extends keyof JSX.IntrinsicElements | JSXElementConstructor +> = Meta>; + +/** + * For the common case where a story is a simple component that receives args as props: + * + * ```tsx + * const Template: ComponentStory = (args) => -); +export const WithMarkdown = (props) => { + console.log('props111:', props); + return ( + + ) +}; WithMarkdown.storyName = 'with markdown'; +WithMarkdown.args = { + type: 'button', + text: 'bbb' +} diff --git a/examples/rax-kitchen-sink/src/stories/index.less b/examples/rax-kitchen-sink/src/stories/index.less new file mode 100644 index 0000000000..79587e85f4 --- /dev/null +++ b/examples/rax-kitchen-sink/src/stories/index.less @@ -0,0 +1,4 @@ +.text { + display: block; + width: 100%; +} \ No newline at end of file diff --git a/examples/rax-kitchen-sink/src/stories/x-for.stories.js b/examples/rax-kitchen-sink/src/stories/x-for.stories.js new file mode 100644 index 0000000000..455eeb45e9 --- /dev/null +++ b/examples/rax-kitchen-sink/src/stories/x-for.stories.js @@ -0,0 +1,35 @@ +/* eslint-disable no-undef */ +import { createElement } from 'rax'; +import { withKnobs } from '@storybook/addon-knobs'; +import './index.less'; + +import Text from 'rax-text'; +import View from 'rax-view'; + +export default { + title: 'Rax/x-for', + decorators: [withKnobs], +}; + +export const WithAButton = () => { + const list = [ + { + name: 'test-1', + desc: 'desc-1', + }, + { + name: 'test-2', + desc: 'desc-2', + }, + ]; + + return ( + + + {item.name}-{item.desc} + + + ); +}; + +WithAButton.storyName = 'with a button'; diff --git a/package.json b/package.json index b02d47c1c9..05fb80fc59 100644 --- a/package.json +++ b/package.json @@ -194,6 +194,7 @@ "lerna": "^3.22.1", "lint-staged": "^10.5.4", "lodash": "^4.17.20", + "mini-css-extract-plugin": "^0.9.0", "mocha-list-tests": "^1.0.5", "node-cleanup": "^2.1.2", "node-fetch": "^2.6.1", @@ -223,6 +224,7 @@ "web-component-analyzer": "^1.1.6", "webpack": "4", "webpack-dev-middleware": "^3.7.3", + "webpack-rpx": "^1.0.0", "window-size": "^1.1.1" }, "optionalDependencies": {