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

WIP: add the Riot.js addon #18672

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions app/riot/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
{
"name": "@storybook/riot",
"version": "6.5.0-rc.1",
"description": "Storybook for Riot.js: Develop Riot Component in isolation with Hot Reloading.",
"keywords": [
"storybook"
],
"homepage": "https://github.com/storybookjs/storybook/tree/main/app/riot",
"bugs": {
"url": "https://github.com/storybookjs/storybook/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/storybookjs/storybook.git",
"directory": "app/riot"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/storybook"
},
"license": "MIT",
"main": "dist/cjs/client/index.js",
"module": "dist/esm/client/index.js",
"types": "dist/ts3.9/client/index.d.ts",
"typesVersions": {
"<3.8": {
"dist/ts3.9/*": [
"dist/ts3.4/*"
]
}
},
"bin": {
"build-storybook": "./bin/build.js",
"start-storybook": "./bin/index.js",
"storybook-server": "./bin/index.js"
},
"files": [
"bin/**/*",
"dist/**/*",
"templates/**/*",
"README.md",
"*.js",
"*.d.ts"
],
"scripts": {
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "6.5.0-rc.1",
"@storybook/client-logger": "6.5.0-rc.1",
"@storybook/core": "6.5.0-rc.1",
"@storybook/core-common": "6.5.0-rc.1",
"@storybook/csf": "0.0.2--canary.4566f4d.1",
"@storybook/docs-tools": "6.5.0-rc.1",
"@storybook/node-logger": "6.5.0-rc.1",
"@storybook/store": "6.5.0-rc.1",
"core-js": "^3.8.2",
"global": "^4.4.0",
"loader-utils": "^2.0.0",
"react": "16.14.0",
"react-dom": "16.14.0",
"read-pkg-up": "^7.0.1",
"regenerator-runtime": "^0.13.7",
"ts-dedent": "^2.0.0",
"webpack": ">=4.0.0 <6.0.0"
},
"devDependencies": {
"@types/loader-utils": "^2.0.0",
"@types/webpack-env": "^1.16.0",
"riot": "^6.1.2",
"@riotjs/compiler": "^6.3.0",
"webpack": "4"
},
"peerDependencies": {
"@babel/core": "*",
"riot": "^6.1.2",
"@riotjs/compiler": "^6.3.0",
"@riotjs/webpack-loader": "^6.0.0"
},
"engines": {
"node": ">=10.13.0"
},
"publishConfig": {
"access": "public"
},
"gitHead": "3f09d4e6b0c655a092dc812488ef2c7ed3808401",
"sbmodern": "dist/modern/client/index.js"
}
1 change: 1 addition & 0 deletions app/riot/preset.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./dist/cjs/server/preset');
18 changes: 18 additions & 0 deletions app/riot/src/client/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export {
storiesOf,
setAddon,
addDecorator,
addParameters,
configure,
getStorybook,
forceReRender,
raw,
app,
activeStoryComponent,
} from './preview';

export * from './preview/types-6-0';

if (module && module.hot && module.hot.decline) {
module.hot.decline();
}
4 changes: 4 additions & 0 deletions app/riot/src/client/preview/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export { render, renderToDOM } from './render';
export { decorateStory as applyDecorators } from './decorateStory';

export const parameters = { framework: 'riot' };
58 changes: 58 additions & 0 deletions app/riot/src/client/preview/decorateStory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import type {DecoratorFunction, StoryContext, LegacyStoryFn} from '@storybook/csf';
import {RiotComponent} from 'riot'
import {sanitizeStoryContextUpdate} from '@storybook/store';

import type {RiotFramework} from './types-6-0';
import {StoryFnRiotReturnType} from './types'

function prepare(
rawStory: RiotFramework['storyResult'],
innerStory?: StoryFnRiotReturnType
): StoryFnRiotReturnType | null {
const story = rawStory as Partial<RiotComponent>;

if (story == null) {
return null;
}

if (innerStory) {
return {
components: {
...(story.components || {}),
story: innerStory
},
template: story.template
};
}

return {
template: story
};
}

export function decorateStory(
storyFn: LegacyStoryFn<RiotFramework>,
decorators: DecoratorFunction<RiotFramework>[]
): LegacyStoryFn<RiotFramework> {
return decorators.reduce(
(decorated: LegacyStoryFn<RiotFramework>, decorator) => (context: StoryContext<RiotFramework>) => {
let story: RiotFramework['storyResult'];

const decoratedStory: RiotFramework['storyResult'] = decorator((update) => {
story = decorated({...context, ...sanitizeStoryContextUpdate(update)});
return story;
}, context);

if (!story) {
story = decorated(context);
}

if (decoratedStory === story) {
return story;
}

return prepare(decoratedStory, story) as RiotFramework['storyResult'];
},
(context) => prepare(storyFn(context)) as LegacyStoryFn<RiotFramework>
);
}
6 changes: 6 additions & 0 deletions app/riot/src/client/preview/globals.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import global from 'global';

const { window: globalWindow } = global;

globalWindow.STORYBOOK_REACT_CLASSES = {};
globalWindow.STORYBOOK_ENV = 'riot';
38 changes: 38 additions & 0 deletions app/riot/src/client/preview/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/* eslint-disable prefer-destructuring */
import { start } from '@storybook/core';
import type { ClientStoryApi, Loadable } from '@storybook/addons';

import './globals';
import { renderToDOM } from './render';
import type { IStorybookSection } from './types';
import type { RiotComponent } from './types-6-0';

export interface ClientApi extends ClientStoryApi<RiotComponent['storyResult']> {
setAddon(addon: any): void;
configure(loader: Loadable, module: NodeModule): void;
getStorybook(): IStorybookSection[];
clearDecorators(): void;
forceReRender(): void;
raw: () => any; // todo add type
load: (...args: any[]) => void;
}

const framework = 'riot';
const api = start(renderToDOM);

export const storiesOf: ClientApi['storiesOf'] = (kind, m) => {
return (api.clientApi.storiesOf(kind, m) as ReturnType<ClientApi['storiesOf']>).addParameters({
framework,
});
};

export const configure: ClientApi['configure'] = (...args) => api.configure(framework, ...args);
export const addDecorator: ClientApi['addDecorator'] = api.clientApi
.addDecorator as ClientApi['addDecorator'];
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;
38 changes: 38 additions & 0 deletions app/riot/src/client/preview/render.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import dedent from 'ts-dedent';
import {component} from 'riot';
import {generateTemplateFunctionFromString} from '@riotjs/compiler'
import type {RenderContext} from '@storybook/store';

import {StoryFnRiotReturnType} from './types';
import {RiotFramework} from './types-6-0';

let currentComponent

export function renderToDOM(
{title, name, storyFn, showMain, showError, showException}: RenderContext<RiotFramework>,
domElement: HTMLElement
) {
const element: StoryFnRiotReturnType = storyFn();

if (!element) {
showError({
title: `Expecting a Riot component from the story: "${name}" of "${title}".`,
description: dedent`
Did you forget to return the Riot component from the story?
Use "() => ({ template: '<my-comp></my-comp>' })" or "() => ({ components: {MyComp}, template: '<my-comp></my-comp>' })" when defining the story.
`,
});
return;
}

showMain();

if (currentComponent) {
currentComponent.unmount()
}

currentComponent = component({
exports: element,
template: Function(generateTemplateFunctionFromString(element.template))()
})(domElement)
}
46 changes: 46 additions & 0 deletions app/riot/src/client/preview/types-6-0.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { RiotComponent } from 'riot';
import type {
Args,
ComponentAnnotations,
StoryAnnotations,
AnnotatedStoryFn,
} from '@storybook/csf';
import type { StoryFnRiotReturnType } from './types';

export type { Args, ArgTypes, Parameters, StoryContext } from '@storybook/csf';

export type RiotFramework = {
component: RiotComponent<any>;
storyResult: StoryFnRiotReturnType;
};

/**
* 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<TArgs = Args> = ComponentAnnotations<RiotFramework, TArgs>;

/**
* Story function that represents a CSFv2 component example.
*
* @see [Named Story exports](https://storybook.js.org/docs/formats/component-story-format/#named-story-exports)
*/
export type StoryFn<TArgs = Args> = AnnotatedStoryFn<RiotFramework, TArgs>;

/**
* Story function that represents a CSFv3 component example.
*
* @see [Named Story exports](https://storybook.js.org/docs/formats/component-story-format/#named-story-exports)
*/
export type StoryObj<TArgs = Args> = StoryAnnotations<RiotFramework, TArgs>;

/**
* Story function that represents a CSFv2 component example.
*
* @see [Named Story exports](https://storybook.js.org/docs/formats/component-story-format/#named-story-exports)
*
* NOTE that in Storybook 7.0, this type will be renamed to `StoryFn` and replaced by the current `StoryObj` type.
*
*/
export type Story<TArgs = Args> = StoryFn<TArgs>;
14 changes: 14 additions & 0 deletions app/riot/src/client/preview/types-7-0.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type { Args } from '@storybook/csf';

import type { StoryObj } from './types-6-0';

export type { StoryFn, StoryObj, Meta } from './types-6-0';

// NOTE these types are reversed from the way they are in types-6-0 and types-6-3

/**
* Story function that represents a CSFv3 component example.
*
* @see [Named Story exports](https://storybook.js.org/docs/formats/component-story-format/#named-story-exports)
*/
export type Story<TArgs = Args> = StoryObj<TArgs>;
22 changes: 22 additions & 0 deletions app/riot/src/client/preview/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { RiotComponent } from 'riot';

export type { RenderContext } from '@storybook/core';

export interface ShowErrorArgs {
title: string;
description: string;
}

export type StoryFnRiotReturnType = Partial<RiotComponent> & {
template?: string
}

export interface IStorybookStory {
name: string;
render: (context: any) => any;
}

export interface IStorybookSection {
kind: string;
stories: IStorybookStory[];
}
4 changes: 4 additions & 0 deletions app/riot/src/server/build.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { buildStatic } from '@storybook/core/server';
import options from './options';

buildStatic(options);
Loading