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 type ComponentStory<
+ T extends keyof JSX.IntrinsicElements | JSXElementConstructor
+> = Story>;
diff --git a/app/rax/src/client/preview/types.ts b/app/rax/src/client/preview/types.ts
new file mode 100644
index 0000000000..5446c8820f
--- /dev/null
+++ b/app/rax/src/client/preview/types.ts
@@ -0,0 +1,22 @@
+import { RaxElement } from 'rax';
+
+// eslint-disable-next-line import/no-extraneous-dependencies
+export type { RenderContext } from '@storybook/client-api';
+export type { StoryContext } from '@storybook/addons';
+
+export interface ShowErrorArgs {
+ title: string;
+ description: string;
+}
+
+export type StoryFnReactReturnType = RaxElement;
+
+export interface IStorybookStory {
+ name: string;
+ render: () => any;
+}
+
+export interface IStorybookSection {
+ kind: string;
+ stories: IStorybookStory[];
+}
diff --git a/app/rax/src/server/framework-preset-rax.ts b/app/rax/src/server/framework-preset-rax.ts
index 73fb93058e..aa1ca99f40 100644
--- a/app/rax/src/server/framework-preset-rax.ts
+++ b/app/rax/src/server/framework-preset-rax.ts
@@ -1,4 +1,7 @@
+/* eslint-disable import/no-extraneous-dependencies */
import { TransformOptions } from '@babel/core';
+import { Configuration } from 'webpack';
+import MiniCssExtractPlugin from 'mini-css-extract-plugin';
export function babelDefault(config: TransformOptions) {
return {
@@ -10,5 +13,66 @@ export function babelDefault(config: TransformOptions) {
{ development: process.env.BABEL_ENV === 'development' },
],
],
+ plugins: [
+ ...config.plugins,
+ ['@babel/plugin-transform-react-jsx', { pragma: 'createElement' }],
+ 'babel-plugin-transform-jsx-list',
+ 'babel-plugin-transform-jsx-condition',
+ 'babel-plugin-transform-jsx-memo',
+ 'babel-plugin-transform-jsx-slot',
+ 'babel-plugin-transform-jsx-fragment',
+ 'babel-plugin-transform-jsx-class',
+ ['babel-plugin-transform-jsx-stylesheet', { retainClassName: true }],
+ ],
+ };
+}
+
+export function webpackFinal(config: Configuration) {
+ const cssRuleIndex = config.module.rules.findIndex(
+ (rule) => rule.test.toString() === '/\\.css$/'
+ );
+ if (cssRuleIndex) {
+ config.module.rules.splice(cssRuleIndex, 1);
+ }
+
+ const stylesLoaders = [
+ 'css-loader',
+ 'postcss-loader',
+ {
+ loader: 'webpack-rpx',
+ options: {
+ width: 750,
+ unit: 'rpx',
+ },
+ },
+ ];
+
+ const lessLoaders = [
+ MiniCssExtractPlugin.loader,
+ 'css-loader',
+ 'less-loader',
+ 'postcss-loader',
+ {
+ loader: 'webpack-rpx',
+ options: {
+ width: 750,
+ unit: 'rpx',
+ },
+ },
+ ];
+
+ config.module.rules.push({
+ test: /\.css$/,
+ use: stylesLoaders,
+ });
+
+ config.module.rules.push({
+ test: /\.less$/,
+ use: lessLoaders,
+ });
+
+ return {
+ ...config,
+ plugins: [...config.plugins, new MiniCssExtractPlugin()],
};
}
diff --git a/app/rax/src/server/options.ts b/app/rax/src/server/options.ts
index 105f645744..e218d14fd8 100644
--- a/app/rax/src/server/options.ts
+++ b/app/rax/src/server/options.ts
@@ -1,7 +1,10 @@
import { sync } from 'read-pkg-up';
+import { LoadOptions } from '@storybook/core-common';
export default {
packageJson: sync({ cwd: __dirname }).packageJson,
framework: 'rax',
- frameworkPresets: [require.resolve('./framework-preset-rax.js')],
-};
+ frameworkPresets: [
+ require.resolve('./framework-preset-rax.js'),
+ ],
+} as LoadOptions;
diff --git a/app/rax/src/typings.d.ts b/app/rax/src/typings.d.ts
index 2f4eb9cf4f..c93e316952 100644
--- a/app/rax/src/typings.d.ts
+++ b/app/rax/src/typings.d.ts
@@ -1 +1,2 @@
declare module 'global';
+declare module 'mini-css-extract-plugin'
\ No newline at end of file
diff --git a/examples/rax-kitchen-sink/src/stories/addon-a11y.stories.js b/examples/rax-kitchen-sink/src/stories/addon-a11y.stories.js
index 6016d0d016..18fd088d50 100644
--- a/examples/rax-kitchen-sink/src/stories/addon-a11y.stories.js
+++ b/examples/rax-kitchen-sink/src/stories/addon-a11y.stories.js
@@ -2,8 +2,19 @@ import { createElement } from 'rax';
import Text from 'rax-text';
import View from 'rax-view';
+
export default {
title: 'Addon/addon-a11y',
+ component: Text,
+ argTypes: {
+ propertyA: {
+ options: ['Item One', 'Item Two', 'Item Three'],
+ control: { type: 'select' } // Automatically inferred when 'options' is defined
+ },
+ propertyB: {
+ options: ['Another Item One', 'Another Item Two', 'Another Item Three'],
+ },
+ },
};
export const Basic = () => RAX TEXT NODE;
@@ -12,15 +23,22 @@ export const WithStyle = () => Sty
WithStyle.storyName = 'with style';
-export const WithMarkdown = () => (
-
-);
+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": {