From f0512489881d09477e16437b79a51074ad41bfc8 Mon Sep 17 00:00:00 2001
From: atanasster
Date: Thu, 23 Apr 2020 01:25:06 -0400
Subject: [PATCH] feat: added props table panel
---
README.md | 7 +-
core/store/README.md | 37 ++++-----
core/store/src/index.ts | 67 +++++++---------
core/store/src/serialization/StoreStorage.ts | 78 +++++++++++++++++++
core/store/src/types.ts | 3 +-
core/webpack-rules/README.md | 22 +++++-
examples/storybook-6/.storybook/main.js | 8 +-
integrations/storybook/README.md | 52 ++++++++-----
integrations/storybook/rollup.config.js | 3 +-
.../storybook/src/panel/AddonPanel.tsx | 34 ++++++++
.../storybook/src/panel/ControlsPanel.tsx | 35 ++-------
.../storybook/src/panel/PropsTablePanel.tsx | 9 +++
integrations/storybook/src/panel/constants.ts | 4 +-
integrations/storybook/src/preset.ts | 16 ++--
...-panel.tsx => register-controls-panel.tsx} | 6 +-
.../storybook/src/register-props-panel.tsx | 14 ++++
integrations/storybook/src/types.ts | 11 ++-
misc/storybook-custom-docs/src/index.tsx | 8 +-
.../src/context/block/BlockDataContext.tsx | 2 +-
.../context/components/ComponentsContext.tsx | 3 +-
20 files changed, 286 insertions(+), 133 deletions(-)
create mode 100644 core/store/src/serialization/StoreStorage.ts
create mode 100644 integrations/storybook/src/panel/AddonPanel.tsx
create mode 100644 integrations/storybook/src/panel/PropsTablePanel.tsx
rename integrations/storybook/src/{register-panel.tsx => register-controls-panel.tsx} (67%)
create mode 100644 integrations/storybook/src/register-props-panel.tsx
diff --git a/README.md b/README.md
index 72f5e1996..72b64eb53 100644
--- a/README.md
+++ b/README.md
@@ -5,6 +5,7 @@
- [Roadmap](#roadmap)
- [Integrations](#integrations)
- [@component-controls/storybook](#component-controlsstorybook)
+ - [storybook integration of component-controls.](#storybook-integration-of-component-controls)
- [Motivation](#motivation-1)
- [Limitations](#limitations)
- [Core packages](#core-packages)
@@ -74,7 +75,11 @@ There are many developments that have contributed to the creation of `component-
Storybook Addon For live editing of component controls
-The Storybook]() integration of component-controls.
+### [storybook](https://storybook.js.org) integration of component-controls.
+
+
+
+
### Motivation
diff --git a/core/store/README.md b/core/store/README.md
index 1e8729b04..b81d3a137 100644
--- a/core/store/README.md
+++ b/core/store/README.md
@@ -31,25 +31,25 @@ $ npm install @component-controls/store --save-dev
Store class used to query the stories and exchange information between processes
-_defined in [@component-controls/store/src/index.ts](https://github.com/ccontrols/component-controls/tree/master/core/store/src/index.ts#L29)_
+_defined in [@component-controls/store/src/index.ts](https://github.com/ccontrols/component-controls/tree/master/core/store/src/index.ts#L33)_
### properties
-| Name | Type | Description |
-| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
-| `constructor*` | **function** constructor | create a store with options |
-| `addObserver*` | **function** addObserver(`observer`\*: [StoreObserver](#storeobserver)): number; | add observer callback function |
-| `getStore*` | **function** getStore(): [StoriesStore](#storiesstore); | returns an instance of the store |
-| `getStory*` | **function** getStory(`storyId`\*: string): [Story](#story); | given a story id return a story from the store |
-| `removeObserver*` | **function** removeObserver(`observer`\*: [StoreObserver](#storeobserver)): **function** (`storyId`: string): void;\[]; | remove installed observer callback function |
-| `setStore*` | **function** setStore(`store`: [StoriesStore](#storiesstore)): void; | internal set store, use for testing with mockup store. |
-| `updateStoryProp*` | **function** updateStoryProp(`storyId`\*: string, `propName`\*: string, `newVal`\*: any): [StoriesStore](#storiesstore) \| undefined; | modify story properties, for example controls values. will notify all installed store observers of the changed story. |
+| Name | Type | Description |
+| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
+| `constructor*` | **function** constructor | create a store with options |
+| `addObserver*` | **function** addObserver(`observer`\*: [StoreObserver](#storeobserver)): number; | add observer callback function |
+| `getStore*` | **function** getStore(): [StoriesStore](#storiesstore); | returns an instance of the store |
+| `getStory*` | **function** getStory(`storyId`\*: string): [Story](#story); | given a story id return a story from the store |
+| `removeObserver*` | **function** removeObserver(`observer`\*: [StoreObserver](#storeobserver)): **function** (`storyId`: string, `propName`: string): void;\[]; | remove installed observer callback function |
+| `setStore*` | **function** setStore(`store`: [StoriesStore](#storiesstore)): void; | internal set store, use for testing with mockup store. |
+| `updateStoryProp*` | **function** updateStoryProp(`storyId`\*: string, `propName`\*: string, `newValue`\*: any): [StoriesStore](#storiesstore) \| undefined; | modify story properties, for example controls values. will notify all installed store observers of the changed story. |
## StoreOptions
-_defined in [@component-controls/store/src/index.ts](https://github.com/ccontrols/component-controls/tree/master/core/store/src/index.ts#L16)_
+_defined in [@component-controls/store/src/index.ts](https://github.com/ccontrols/component-controls/tree/master/core/store/src/index.ts#L20)_
@@ -64,13 +64,13 @@ _defined in [@component-controls/store/src/index.ts](https://github.com/ccontrol
store variable, automatically filled with stories.
-_defined in [@component-controls/store/src/index.ts](https://github.com/ccontrols/component-controls/tree/master/core/store/src/index.ts#L148)_
+_defined in [@component-controls/store/src/index.ts](https://github.com/ccontrols/component-controls/tree/master/core/store/src/index.ts#L142)_
## stores
-_defined in [@component-controls/store/src/index.ts](https://github.com/ccontrols/component-controls/tree/master/core/store/src/index.ts#L150)_
+_defined in [@component-controls/store/src/index.ts](https://github.com/ccontrols/component-controls/tree/master/core/store/src/index.ts#L144)_
@@ -82,13 +82,14 @@ so they can re-load the stories
_defined in [@component-controls/store/src/types.ts](https://github.com/ccontrols/component-controls/tree/master/core/store/src/types.ts#L8)_
-**function** (`storyId`: string): void;
+**function** (`storyId`: string, `propName`: string): void;
### parameters
-| Name | Type | Description |
-| --------- | ------ | ----------- |
-| `storyId` | string | |
-| `returns` | void | |
+| Name | Type | Description |
+| ---------- | ------ | ----------- |
+| `storyId` | string | |
+| `propName` | string | |
+| `returns` | void | |
diff --git a/core/store/src/index.ts b/core/store/src/index.ts
index ad637e12c..1a3c9aaec 100644
--- a/core/store/src/index.ts
+++ b/core/store/src/index.ts
@@ -8,8 +8,12 @@ import {
StoryStore,
MessageType,
UPDATE_STORY_MSG,
- COMPONENT_CONTROLS_STORAGE,
} from './types';
+import {
+ saveStore,
+ readStore,
+ updateStory,
+} from './serialization/StoreStorage';
export { StoreObserver, StoryStore };
@@ -45,11 +49,11 @@ export class Store implements StoryStore {
type: 'localstorage',
});
this.observers = [];
- this.channel.onmessage = ({ storyId, moduleId }: MessageType) => {
+ this.channel.onmessage = ({ storyId, moduleId, propName }: MessageType) => {
if (storyId && moduleId) {
if (this.moduleId !== moduleId) {
- this.readData(storyId);
- this.notifyObservers(storyId);
+ this.readData(storyId, propName);
+ this.notifyObservers(storyId, propName);
}
}
};
@@ -65,9 +69,9 @@ export class Store implements StoryStore {
removeObserver = (observer: StoreObserver) =>
(this.observers = this.observers.filter(o => o !== observer));
- private notifyObservers = (storyId?: string) => {
+ private notifyObservers = (storyId?: string, propName?: string) => {
if (this.observers.length > 0) {
- this.observers.forEach(observer => observer(storyId));
+ this.observers.forEach(observer => observer(storyId, propName));
}
};
@@ -78,23 +82,10 @@ export class Store implements StoryStore {
this.loadedStore = store;
this.notifyObservers();
};
- private readData = (storyId?: string) => {
- const data = localStorage.getItem(COMPONENT_CONTROLS_STORAGE);
- if (data) {
- try {
- const newStore = JSON.parse(data) as StoriesStore;
-
- if (this.loadedStore && storyId) {
- this.loadedStore.stories[storyId] = {
- ...this.loadedStore.stories[storyId],
- controls: { ...newStore.stories[storyId].controls },
- };
- } else {
- this.loadedStore = newStore;
- }
- } catch (e) {}
- }
+ private readData = (storyId?: string, propName?: string) => {
+ this.loadedStore = readStore(this.loadedStore, storyId, propName);
};
+
/**
* returns an instance of the store
*/
@@ -122,22 +113,25 @@ export class Store implements StoryStore {
updateStoryProp = (
storyId: string,
propName: string,
- newVal: any,
+ newValue: any,
): StoriesStore | undefined => {
+ this.loadedStore = updateStory(
+ this.loadedStore,
+ storyId,
+ propName,
+ newValue,
+ this.updateLocalStorage,
+ );
if (this.loadedStore) {
- this.loadedStore.stories[storyId] = {
- ...this.loadedStore.stories[storyId],
- [propName]: newVal,
- };
if (this.updateLocalStorage) {
- localStorage.setItem(
- COMPONENT_CONTROLS_STORAGE,
- JSON.stringify(this.loadedStore),
- );
- const message: MessageType = { storyId, moduleId: this.moduleId };
+ const message: MessageType = {
+ storyId,
+ moduleId: this.moduleId,
+ propName,
+ };
this.channel.postMessage(message);
}
- this.notifyObservers(storyId);
+ this.notifyObservers(storyId, propName);
}
return this.loadedStore;
};
@@ -150,10 +144,5 @@ export const store = new Store();
const stores = loadStoryStore();
if (stores) {
store.setStore(stores);
- for (var key in localStorage) {
- if (key.indexOf(COMPONENT_CONTROLS_STORAGE) == 0) {
- localStorage.removeItem(key);
- }
- }
- localStorage.setItem(COMPONENT_CONTROLS_STORAGE, JSON.stringify(stores));
+ saveStore(stores);
}
diff --git a/core/store/src/serialization/StoreStorage.ts b/core/store/src/serialization/StoreStorage.ts
new file mode 100644
index 000000000..a2b85d894
--- /dev/null
+++ b/core/store/src/serialization/StoreStorage.ts
@@ -0,0 +1,78 @@
+import {
+ StoriesStore,
+ getComponentName,
+} from '@component-controls/specification';
+
+import { COMPONENT_CONTROLS_STORAGE } from '../types';
+
+const encodeFn = (name: string, val: any) => {
+ // convert RegExp to string
+ if (val && val.constructor === RegExp) {
+ return val.toString();
+ } else if (name === 'component') {
+ //serialize components as string of their name
+ const component = getComponentName(val);
+ return component ? component : val;
+ }
+ return val;
+};
+export const saveStore = (store: StoriesStore) => {
+ for (var key in localStorage) {
+ if (key.indexOf(COMPONENT_CONTROLS_STORAGE) == 0) {
+ localStorage.removeItem(key);
+ }
+ }
+ localStorage.setItem(
+ COMPONENT_CONTROLS_STORAGE,
+ JSON.stringify(store, encodeFn),
+ );
+};
+
+export const readStore = (
+ store?: StoriesStore,
+ storyId?: string,
+ propName?: string,
+): StoriesStore | undefined => {
+ const data = localStorage.getItem(COMPONENT_CONTROLS_STORAGE);
+ if (data) {
+ const newStore = JSON.parse(data) as StoriesStore;
+ if (store && storyId && propName) {
+ const newValue = (newStore.stories[storyId] as any)[propName];
+ store.stories = {
+ ...store.stories,
+ [storyId]: {
+ ...store.stories[storyId],
+ [propName]: newValue,
+ },
+ };
+ return store;
+ }
+ return newStore;
+ }
+ return store;
+};
+
+export const updateStory = (
+ store: StoriesStore | undefined,
+ storyId: string,
+ propName: string,
+ newValue: any,
+ updateLocalStorage?: boolean,
+): StoriesStore | undefined => {
+ if (store) {
+ store.stories = {
+ ...store.stories,
+ [storyId]: {
+ ...store.stories[storyId],
+ [propName]: newValue,
+ },
+ };
+ if (updateLocalStorage) {
+ localStorage.setItem(
+ COMPONENT_CONTROLS_STORAGE,
+ JSON.stringify(store, encodeFn),
+ );
+ }
+ }
+ return store;
+};
diff --git a/core/store/src/types.ts b/core/store/src/types.ts
index e8a4ca18d..b2c635b9f 100644
--- a/core/store/src/types.ts
+++ b/core/store/src/types.ts
@@ -5,7 +5,7 @@ import { StoriesStore, Story } from '@component-controls/specification';
* when updateStoryProp is called on the store, the store observers will be notified
* so they can re-load the stories
*/
-export type StoreObserver = (storyId?: string) => void;
+export type StoreObserver = (storyId?: string, propName?: string) => void;
export interface StoryStore {
getStore: () => StoriesStore | undefined;
@@ -25,4 +25,5 @@ export const COMPONENT_CONTROLS_STORAGE = 'component-controls-store-data';
export interface MessageType {
storyId: string;
moduleId: number;
+ propName: string;
}
diff --git a/core/webpack-rules/README.md b/core/webpack-rules/README.md
index 22efed325..a0b01ce9b 100644
--- a/core/webpack-rules/README.md
+++ b/core/webpack-rules/README.md
@@ -8,6 +8,7 @@
- [getRules](#getrules)
- [ruleMerge](#rulemerge)
- [rulesFactory](#rulesfactory)
+ - [RuleOptions](#ruleoptions)
- [RuleType](#ruletype)
- [RuleTypes](#ruletypes)
- [WebpackRule](#webpackrule)
@@ -55,7 +56,7 @@ _defined in [@component-controls/webpack-rules/src/index.ts](https://github.com/
expands the rules into webpack rules
-_defined in [@component-controls/webpack-rules/src/index.ts](https://github.com/ccontrols/component-controls/tree/master/core/webpack-rules/src/index.ts#L31)_
+_defined in [@component-controls/webpack-rules/src/index.ts](https://github.com/ccontrols/component-controls/tree/master/core/webpack-rules/src/index.ts#L33)_
**function** getRules(`rules`\*: [RuleType](#ruletype)\[]): [WebpackRules](#webpackrules);
@@ -94,15 +95,28 @@ _defined in [@component-controls/webpack-rules/src/index.ts](https://github.com/
| `react-docgen*` | [RuleSetRule](#rulesetrule)\[] | |
| `react-docgen-typescript*` | [RuleSetRule](#rulesetrule)\[] | |
-## RuleType
+## RuleOptions
_defined in [@component-controls/webpack-rules/src/types.ts](https://github.com/ccontrols/component-controls/tree/master/core/webpack-rules/src/types.ts#L6)_
-[WebpackRule](#webpackrule) | string | **options**: [WebpackRules](#webpackrules)**rules**: [RuleTypes](#ruletypes)
+
+
+### properties
+
+| Name | Type | Description |
+| -------- | ----------------------------- | ----------- |
+| `name*` | string | |
+| `rules*` | [WebpackRules](#webpackrules) | |
+
+## RuleType
+
+_defined in [@component-controls/webpack-rules/src/types.ts](https://github.com/ccontrols/component-controls/tree/master/core/webpack-rules/src/types.ts#L10)_
+
+[WebpackRule](#webpackrule) | string | [RuleOptions](#ruleoptions)
## RuleTypes
-_defined in [@component-controls/webpack-rules/src/types.ts](https://github.com/ccontrols/component-controls/tree/master/core/webpack-rules/src/types.ts#L14)_
+_defined in [@component-controls/webpack-rules/src/types.ts](https://github.com/ccontrols/component-controls/tree/master/core/webpack-rules/src/types.ts#L12)_
[RuleType](#ruletype)\[]
diff --git a/examples/storybook-6/.storybook/main.js b/examples/storybook-6/.storybook/main.js
index 9c965a526..2611f81f7 100644
--- a/examples/storybook-6/.storybook/main.js
+++ b/examples/storybook-6/.storybook/main.js
@@ -24,6 +24,12 @@ module.exports = {
configureJSX: true,
},
},
- '@component-controls/storybook',
+ {
+ name: '@component-controls/storybook',
+ options: {
+ controlsPanel: true,
+ propsPanel: true,
+ }
+ }
],
};
diff --git a/integrations/storybook/README.md b/integrations/storybook/README.md
index a98a6f998..4d4d5f50d 100644
--- a/integrations/storybook/README.md
+++ b/integrations/storybook/README.md
@@ -1,10 +1,9 @@
# Table of contents
- [Overview](#overview)
- - - [Motivation](#motivation)
+ - - [storybook integration of component-controls.](#storybook-integration-of-component-controls)
+ - [Motivation](#motivation)
- [Limitations](#limitations)
-- [Storybook](#storybook)
-- [Introduction](#introduction)
- [Getting Started](#getting-started)
- [Install](#install)
- [Configure](#configure)
@@ -19,10 +18,11 @@
- [Smart Controls Options](#smart-controls-options)
- [Testing with random data generators](#testing-with-random-data-generators)
- [Categories](#categories)
-- [Storybook Docs Block](#storybook-docs-block)
-- [Configuration options](#configuration-options)
+- [Advanced configuration options](#advanced-configuration-options)
+ - [Custom loader options](#custom-loader-options)
- [PresetOptions](#presetoptions)
- [defaultRules](#defaultrules)
+ - [Storybook addon panels](#storybook-addon-panels)
- [List of components](#list-of-components)
- [ComponentSource](#inscomponentsourceins)
- [ControlsTable](#inscontrolstableins)
@@ -41,14 +41,12 @@
# Overview
-### [storybook]() integration of component-controls.
+### [storybook](https://storybook.js.org) integration of component-controls.
-
-
### Motivation
- Allow adding component-controls in storybook DocsPage.
@@ -65,7 +63,6 @@
- Only handles the CSF and MDX stories format. The storeisOf API is not supported and there are currently no plans to support it.
- The Storybook MDX is a proprietary format that will be replaced in due time with a portable [frontmatter](https://www.gatsbyjs.org/docs/mdx/markdown-syntax/#frontmatter--mdx-example) stories format, similar to the CSF format.
-
# Getting Started
## Install
@@ -273,7 +270,6 @@ You can see Controls in separate tabs as shown below.
-
# Advanced configuration options
The storybook addon controls comes with pre-configured options that you can use for quick start, but you can also customise the options.
@@ -281,6 +277,7 @@ The storybook addon controls comes with pre-configured options that you can use
## Custom loader options
`.storybook/main.js`:
+
```js
addons: [
...
@@ -288,7 +285,7 @@ The storybook addon controls comes with pre-configured options that you can use
name: '@component-controls/storybook',
options: {
- addonPanel: false,
+ controlsPanel: false,
webpackRules: [{
name: 'react-docgen-typescript',
rules: [{
@@ -319,6 +316,7 @@ The storybook addon controls comes with pre-configured options that you can use
},
}],
```
+
For more information on [InstrumentOptions](../../core/instrument/README.md#instrumentoptions)
@@ -333,21 +331,39 @@ _defined in [@component-controls/storybook/src/types.ts](https://github.com/ccon
### properties
-| Name | Type | Description |
-| -------------- | ----------------------- | ------------------------------------------------------------------------------- |
-| `addonPanel` | boolean | whether to display the addon panel in storybook |
-| `docsPage` | boolean | whether to add a Page documentation page with a classic componnet-controls page |
-| `pages` | string\[] | additional custom documentation pages |
-| `webpackRules` | [RuleTypes](#ruletypes) | options that will be passed to the instrumenter. |
+| Name | Type | Description |
+| --------------- | ----------------------- | -------------------------------------------------------------------- |
+| `controlsPanel` | boolean | whether to display the controls table as an addon panel in storybook |
+| `pages` | string\[] | additional custom documentation pages |
+| `propsPanel` | boolean | whether to display the props table as an addon panel in storybook |
+| `webpackRules` | [RuleTypes](#ruletypes) | options that will be passed to the instrumenter. |
## defaultRules
-_defined in [@component-controls/storybook/src/types.ts](https://github.com/ccontrols/component-controls/tree/master/integrations/storybook/src/types.ts#L22)_
+_defined in [@component-controls/storybook/src/types.ts](https://github.com/ccontrols/component-controls/tree/master/integrations/storybook/src/types.ts#L25)_
+## Storybook addon panels
+
+The `component-controls` block components ahev been designed from the ground up to be able to be placed either on documentation pages or in addon tabs.
+
+You can turn on and off various panels:
+
+ {
+ name: '@component-controls/storybook',
+ options: {
+ controlsPanel: true,
+ propsPanel: true,
+ }
+ }
+
+
+
+
+
# List of components
diff --git a/integrations/storybook/rollup.config.js b/integrations/storybook/rollup.config.js
index e00778928..fe12c0d9a 100644
--- a/integrations/storybook/rollup.config.js
+++ b/integrations/storybook/rollup.config.js
@@ -5,7 +5,8 @@ export default config({
'./src/index.ts',
'./src/preset.ts',
'./src/config.tsx',
- './src/register-panel.tsx',
+ './src/register-controls-panel.tsx',
+ './src/register-props-panel.tsx',
'./src//docs-page/full-page.tsx',
],
});
diff --git a/integrations/storybook/src/panel/AddonPanel.tsx b/integrations/storybook/src/panel/AddonPanel.tsx
new file mode 100644
index 000000000..da7884fb0
--- /dev/null
+++ b/integrations/storybook/src/panel/AddonPanel.tsx
@@ -0,0 +1,34 @@
+import React from 'react';
+import { BlockContextProvider } from '@component-controls/blocks';
+import { API } from '@storybook/api';
+import { SET_CURRENT_STORY } from '@storybook/core-events';
+import { ThemeProvider } from '../context/ThemeProvider';
+
+export interface AddonPanelProps {
+ active?: boolean;
+ api: API;
+}
+export const AddonPanel: React.FC = ({
+ active,
+ api,
+ children,
+}) => {
+ const [storyId, setStoryId] = React.useState();
+
+ const channel = React.useMemo(() => api.getChannel(), []);
+ React.useEffect(() => {
+ const onChangeStory = (props: any) => {
+ setStoryId(props.storyId);
+ };
+ const { id } = api.getCurrentStoryData() || {};
+ setStoryId(id);
+ channel.on(SET_CURRENT_STORY, onChangeStory);
+ return () => channel.off(SET_CURRENT_STORY, onChangeStory);
+ });
+
+ return active && storyId ? (
+
+ {children}
+
+ ) : null;
+};
diff --git a/integrations/storybook/src/panel/ControlsPanel.tsx b/integrations/storybook/src/panel/ControlsPanel.tsx
index e03c65c42..06204a69c 100644
--- a/integrations/storybook/src/panel/ControlsPanel.tsx
+++ b/integrations/storybook/src/panel/ControlsPanel.tsx
@@ -1,30 +1,9 @@
import React from 'react';
-import { BlockContextProvider } from '@component-controls/blocks';
-import { API } from '@storybook/api';
-import { SET_CURRENT_STORY } from '@storybook/core-events';
-import { ControlsTable } from '../blocks/ControlsTable';
+import { ControlsTable } from '@component-controls/blocks';
+import { AddonPanel, AddonPanelProps } from './AddonPanel';
-export interface ControlsPanelProps {
- active?: boolean;
- api: API;
-}
-export const ControlsPanel: React.FC = ({
- active,
- api,
-}) => {
- const [storyId, setStoryId] = React.useState();
- const channel = React.useMemo(() => api.getChannel(), []);
- React.useEffect(() => {
- const onChangeStory = (props: any) => {
- setStoryId(props.storyId);
- };
- channel.on(SET_CURRENT_STORY, onChangeStory);
- return () => channel.off(SET_CURRENT_STORY, onChangeStory);
- });
-
- return active && storyId ? (
-
-
-
- ) : null;
-};
+export const ControlsPanel: React.FC = props => (
+
+
+
+);
diff --git a/integrations/storybook/src/panel/PropsTablePanel.tsx b/integrations/storybook/src/panel/PropsTablePanel.tsx
new file mode 100644
index 000000000..0b2218efe
--- /dev/null
+++ b/integrations/storybook/src/panel/PropsTablePanel.tsx
@@ -0,0 +1,9 @@
+import React from 'react';
+import { PropsTable } from '@component-controls/blocks';
+import { AddonPanel, AddonPanelProps } from './AddonPanel';
+
+export const PropsTablePanel: React.FC = props => (
+
+
+
+);
diff --git a/integrations/storybook/src/panel/constants.ts b/integrations/storybook/src/panel/constants.ts
index 0598aaf70..578462eab 100644
--- a/integrations/storybook/src/panel/constants.ts
+++ b/integrations/storybook/src/panel/constants.ts
@@ -1,2 +1,2 @@
-export const ADDON_ID = 'controls/panel';
-export const PANEL_ID = 'controls/panel/panel';
+export const CONTROLS_PANEL_ID = 'controls/panels/controls';
+export const PROPS_PANEL_ID = 'controls/panels/props';
diff --git a/integrations/storybook/src/preset.ts b/integrations/storybook/src/preset.ts
index 28eb8e69d..aeddf17e8 100644
--- a/integrations/storybook/src/preset.ts
+++ b/integrations/storybook/src/preset.ts
@@ -10,10 +10,8 @@ module.exports = {
return result;
},
addons: (entry: any = {}) => {
- const { pages: customPages = [], docsPage = true } = entry;
- const pages = docsPage
- ? [require.resolve('./full-page'), ...customPages]
- : customPages;
+ const { pages: customPages } = entry;
+ const pages = customPages || [require.resolve('./full-page')];
if (pages.length) {
return [
{
@@ -28,10 +26,14 @@ module.exports = {
},
managerEntries: (entry: any[] = [], options: PresetOptions = {}) => {
const result = [...entry];
- const { addonPanel = true } = options;
- if (addonPanel) {
- result.push(require.resolve('./register-panel'));
+ const { controlsPanel = true, propsPanel = false } = options;
+ if (controlsPanel) {
+ result.push(require.resolve('./register-controls-panel'));
}
+ if (propsPanel) {
+ result.push(require.resolve('./register-props-panel'));
+ }
+
return result;
},
webpackFinal: (config: any = {}, options: PresetOptions = {}) => {
diff --git a/integrations/storybook/src/register-panel.tsx b/integrations/storybook/src/register-controls-panel.tsx
similarity index 67%
rename from integrations/storybook/src/register-panel.tsx
rename to integrations/storybook/src/register-controls-panel.tsx
index 7c85b73dc..22df42af9 100644
--- a/integrations/storybook/src/register-panel.tsx
+++ b/integrations/storybook/src/register-controls-panel.tsx
@@ -2,10 +2,10 @@
import * as React from 'react';
import addons from '@storybook/addons';
import { ControlsPanel } from './panel/ControlsPanel';
-import { ADDON_ID, PANEL_ID } from './panel/constants';
+import { CONTROLS_PANEL_ID } from './panel/constants';
-addons.register(ADDON_ID, api => {
- addons.addPanel(PANEL_ID, {
+addons.register(CONTROLS_PANEL_ID, api => {
+ addons.addPanel(`${CONTROLS_PANEL_ID}_panel`, {
title: 'Controls',
render: ({ active, key }) => (
diff --git a/integrations/storybook/src/register-props-panel.tsx b/integrations/storybook/src/register-props-panel.tsx
new file mode 100644
index 000000000..c34fbe13d
--- /dev/null
+++ b/integrations/storybook/src/register-props-panel.tsx
@@ -0,0 +1,14 @@
+/* eslint-disable react/display-name */
+import * as React from 'react';
+import addons from '@storybook/addons';
+import { PropsTablePanel } from './panel/PropsTablePanel';
+import { PROPS_PANEL_ID } from './panel/constants';
+
+addons.register(PROPS_PANEL_ID, api => {
+ addons.addPanel(`${PROPS_PANEL_ID}_panel`, {
+ title: 'Props',
+ render: ({ active, key }) => (
+
+ ),
+ });
+});
diff --git a/integrations/storybook/src/types.ts b/integrations/storybook/src/types.ts
index a525eaa15..c947e1b57 100644
--- a/integrations/storybook/src/types.ts
+++ b/integrations/storybook/src/types.ts
@@ -2,13 +2,16 @@ import { RuleTypes } from '@component-controls/webpack-rules';
export interface PresetOptions {
/**
- * whether to display the addon panel in storybook
+ * whether to display the controls table as an addon panel in storybook
+ * @defaultValue true
*/
- addonPanel?: boolean;
+ controlsPanel?: boolean;
+
/**
- * whether to add a Page documentation page with a classic componnet-controls page
+ * whether to display the props table as an addon panel in storybook
*/
- docsPage?: boolean;
+ propsPanel?: boolean;
+
/**
* additional custom documentation pages
*/
diff --git a/misc/storybook-custom-docs/src/index.tsx b/misc/storybook-custom-docs/src/index.tsx
index 8faccb354..2cef749d8 100644
--- a/misc/storybook-custom-docs/src/index.tsx
+++ b/misc/storybook-custom-docs/src/index.tsx
@@ -1,6 +1,6 @@
import * as React from 'react';
import addons from '@storybook/addons';
-import { STORY_CHANGED } from '@storybook/core-events';
+import { SET_CURRENT_STORY } from '@storybook/core-events';
import { ConfigApi } from '@storybook/client-api';
export * from './types';
@@ -60,13 +60,13 @@ export const useStoryId = () => {
);
const channel = React.useMemo(() => addons.getChannel(), []);
React.useEffect(() => {
- const onStoryChange = (id: string) => {
+ const onStoryChange = ({ storyId: id }: { storyId: string }) => {
setStoryId(id);
};
- channel.on(STORY_CHANGED, onStoryChange);
+ channel.on(SET_CURRENT_STORY, onStoryChange);
return () => {
- channel.off(STORY_CHANGED, onStoryChange);
+ channel.off(SET_CURRENT_STORY, onStoryChange);
};
}, []);
return storyId;
diff --git a/ui/blocks/src/context/block/BlockDataContext.tsx b/ui/blocks/src/context/block/BlockDataContext.tsx
index 6d8ace814..f8f1407db 100644
--- a/ui/blocks/src/context/block/BlockDataContext.tsx
+++ b/ui/blocks/src/context/block/BlockDataContext.tsx
@@ -54,8 +54,8 @@ export const BlockDataContextProvider: React.FC = ({
store && story && story.kind ? store.kinds[story.kind] : undefined;
const storyComponent: any =
story && kind ? story.component || kind.component : undefined;
- const componentName = getComponentName(storyComponent);
+ const componentName = getComponentName(storyComponent);
const component =
store && componentName && kind && kind.components[componentName]
? store.components[kind.components[componentName]]
diff --git a/ui/blocks/src/context/components/ComponentsContext.tsx b/ui/blocks/src/context/components/ComponentsContext.tsx
index 595ab31f5..0a6fe0a6d 100644
--- a/ui/blocks/src/context/components/ComponentsContext.tsx
+++ b/ui/blocks/src/context/components/ComponentsContext.tsx
@@ -15,7 +15,7 @@ export interface ComponentInputProps {
* The default, a value of `"."` will indicate to display information for the current component (associated with the current Story).
* If an array of components is specified, each component will be displayed in a separate tab.
*/
- of?: '.' | any;
+ of?: typeof CURRENT_STORY | any;
}
export interface ComponentContextProps {
@@ -29,6 +29,7 @@ export const useComponentsContext = ({
}: ComponentInputProps): ComponentContextProps => {
const { getStoryData, getComponents } = React.useContext(BlockDataContext);
const { story, kind, component } = getStoryData();
+
if (!story) {
return {
components: {},