diff --git a/core/specification/src/stories.ts b/core/specification/src/stories.ts index 366a2bcbc..c19622894 100644 --- a/core/specification/src/stories.ts +++ b/core/specification/src/stories.ts @@ -111,7 +111,9 @@ export interface Story { /** * multiple components option */ - subcomponents?: string[] | object[]; + subcomponents?: { + [key: string]: string | object; + }; /** * object of key/value pairs specifying the controls for the story diff --git a/integrations/storybook/src/blocks/ComponentSource.tsx b/integrations/storybook/src/blocks/ComponentSource.tsx index 18d2fff29..6921bfa45 100644 --- a/integrations/storybook/src/blocks/ComponentSource.tsx +++ b/integrations/storybook/src/blocks/ComponentSource.tsx @@ -1,14 +1,14 @@ import React, { FC } from 'react'; import { - ComponentSource as BaseComponentSource, - ComponentSourceProps, + BlockComponentSource, + BlockComponentSourceProps, } from '@component-controls/blocks'; import { ThemeProvider } from '../shared/ThemeProvider'; -export const ComponentSource: FC = props => { +export const ComponentSource: FC = props => { return ( - + ); }; diff --git a/integrations/storybook/src/blocks/ControlsTable.tsx b/integrations/storybook/src/blocks/ControlsTable.tsx index 43a9793ad..ff1dd8dca 100644 --- a/integrations/storybook/src/blocks/ControlsTable.tsx +++ b/integrations/storybook/src/blocks/ControlsTable.tsx @@ -7,15 +7,14 @@ import { } from '@component-controls/specification'; import { mergeControlValues } from '@component-controls/core'; import { - ControlsTable as BaseControlsTable, - ControlsTableProps as BaseControlsTableProps, + BlockControlsTable, + BlockControlsTableProps, useStoryContext, - StoryInputProps, } from '@component-controls/blocks'; import { SET_DATA_MSG } from '../shared/shared'; import { ThemeProvider } from '../shared/ThemeProvider'; -export type ControlsTableProps = StoryInputProps & BaseControlsTableProps; +export type ControlsTableProps = BlockControlsTableProps; export const ControlsTable: FC = ({ id: propId, @@ -62,9 +61,8 @@ export const ControlsTable: FC = ({ return id ? ( - = ({ diff --git a/integrations/storybook/src/preview/PreviewPanel.tsx b/integrations/storybook/src/preview/PreviewPanel.tsx index 5b260b0e2..d96cd1b2e 100644 --- a/integrations/storybook/src/preview/PreviewPanel.tsx +++ b/integrations/storybook/src/preview/PreviewPanel.tsx @@ -9,35 +9,29 @@ export const createControlsPanel = ({ context: any; }): any | null => { // @ts-ignore - const { storyStore, clientApi: api } = context; - const data = storyStore.fromId(storyId); + const { clientApi: api } = context; const name = 'controls'; - if (data && data.controls && Object.keys(data.controls).length) { - const { setControlValue, clickControl } = api; - const { controls } = data; - return (expanded: any): any => { - switch (true) { - case expanded === name: { - return { - node: ( - - ), - title: `Hide ${name}`, - }; - } - default: { - return { - node: null, - title: `Show ${name}`, - }; - } + const { setControlValue, clickControl } = api; + return (expanded: any): any => { + switch (true) { + case expanded === name: { + return { + node: ( + + ), + title: `Hide ${name}`, + }; } - }; - } - return null; + default: { + return { + node: null, + title: `Show ${name}`, + }; + } + } + }; }; diff --git a/ui/blocks/README.md b/ui/blocks/README.md index 1843fd31e..f64a8cc84 100644 --- a/ui/blocks/README.md +++ b/ui/blocks/README.md @@ -3,7 +3,9 @@ - [Overview](#overview) - [@component-controls/blocks](#component-controlsblocks) - [List of components](#list-of-components) + - [BlockComponentSource](#insblockcomponentsourceins) - [ComponentSource](#inscomponentsourceins) + - [BlockControlsTable](#insblockcontrolstableins) - [ControlsTable](#inscontrolstableins) - [SingleControlsTable](#inssinglecontrolstableins) - [Description](#insdescriptionins) @@ -22,10 +24,12 @@ A collection of core block components - intended to be displayed on the document Some of the guiding design goals for this library: -- Most components should have a 'plain' and a 'block' version, where the block versions adds a collapsible ox with a title. -- There are two main categories of components: components that display story data (i.e. story source, story render) and component(s) data (i.e. prop tables, component sources) -- All components accept a list of custom ActionItems to be extended. -- The compnents that deal with source code (sotory or component) display actions to visit the repositories. +- Most components should have a 'plain' and a 'block' version, where the block version adds a collapsible Box with a title. +- There are two main categories of components: + - that display story data (i.e. story source, story render) + - that display component(s) data (i.e. prop tables, component sources) +- Components accept a list of custom ActionItems to be extended. +- Compnents that deal with source code (story or component source) display actions to browse their respective repositories. # List of components @@ -33,13 +37,53 @@ Some of the guiding design goals for this library: +## BlockComponentSource + +Displays import statement for a component as well as the component file source code +Optionally also displays some repository information from the component's package.json + +_BlockComponentSource [source code](https:/github.com/ccontrols/component-controls/blob/master/ui/blocks/src/ComponentSource/block/BlockComponentSource.tsx)_ + +**Properties:** + +- **of**? : _any_ + + Specify the component(s), for which to have information displayed. + 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. +- **actions**? : _ActionItem\[]_ + + optional actions provided to the component +- **theme**? : _PrismTheme_ + + optional `PrismTheme` theme provided to the component. Themes can be imported from `prism-react-renderer/themes`. +- **language**? : _Language_ + + source lnguage used, by default "jsx". +- **renderFn**? : _(props: RenderProps, other: { theme: PrismTheme; }) => ReactNode_ + + custom function to render the source code. +- **dark**? : _boolean_ + + used to specify a "dark" color theme - applcable only if no custom theme prop is provided. + if dark: true, duotoneDark theme is used. + if dark: false, duotoneLight theme is used. +- **style**? : _any_ + + css styles for the container. +- **as**? : _any_ + + syntax container as element. Can be used as `div` or `span`. +- **title**? : _string_ + + optional section title for the block + ## ComponentSource Displays import statement for a component as well as the component file source code Optionally also displays some repository information from the component's package.json -Under the hood, uses [prism-react-renderer](https://github.com/FormidableLabs/prism-react-renderer) for syntax highlighting -_ComponentSource [source code](https:/github.com/ccontrols/component-controls/blob/master/ui/blocks/src/ComponentSource/ComponentSource.tsx)_ +_ComponentSource [source code](https:/github.com/ccontrols/component-controls/blob/master/ui/blocks/src/ComponentSource/plain/ComponentSource.tsx)_ **Properties:** @@ -71,35 +115,73 @@ _ComponentSource [source code](https:/github.com/ccontrols/component-controls/bl - **as**? : _any_ syntax container as element. Can be used as `div` or `span`. + +## BlockControlsTable + +Table block component to display a story's controls and their editors + +_BlockControlsTable [source code](https:/github.com/ccontrols/component-controls/blob/master/ui/blocks/src/ControlsTable/block/BlockControlsTable.tsx)_ + +**Properties:** + +- **setControlValue**? : _SetControlValueFn_ + + generic function to update the values of component controls. +- **clickControl**? : _ClickControlFn_ + + generic function to propagate a click event for component controls. +- **id**? : _string_ + + id of the story +- **name**? : _string_ + + or - name of the story if in an external file + will be used to find the story - **title**? : _string_ optional section title for the block ## ControlsTable -Table component to display a story's controls and their editors +Table component to display a story's controls and their editors. +Can adapt to multiple groups of controls, displaying them in their own tabs. -_ControlsTable [source code](https:/github.com/ccontrols/component-controls/blob/master/ui/blocks/src/ControlsTable/ControlsTable.tsx)_ +_ControlsTable [source code](https:/github.com/ccontrols/component-controls/blob/master/ui/blocks/src/ControlsTable/plain/ControlsTable.tsx)_ **Properties:** -- **title**? : _string_ -- **storyId**? : _string_ -- **controls**? : _LoadedComponentControls_ - **setControlValue**? : _SetControlValueFn_ + + generic function to update the values of component controls. - **clickControl**? : _ClickControlFn_ + generic function to propagate a click event for component controls. +- **id**? : _string_ + + id of the story +- **name**? : _string_ + + or - name of the story if in an external file + will be used to find the story + ## SingleControlsTable -_SingleControlsTable [source code](https:/github.com/ccontrols/component-controls/blob/master/ui/blocks/src/ControlsTable/SingleControlsTable.tsx)_ +Single table of controls, without specific handliong of groups. +The controls and storyId are already set in priops; + +_SingleControlsTable [source code](https:/github.com/ccontrols/component-controls/blob/master/ui/blocks/src/ControlsTable/plain/SingleControlsTable.tsx)_ **Properties:** -- **title**? : _string_ +- **controls**? : _ComponentControls_ + + componnet controls to display in the table. - **storyId**? : _string_ -- **controls**? : _LoadedComponentControls_ + + storyId, will be used to update the values of the controls - **setControlValue**? : _SetControlValueFn_ -- **clickControl**? : _ClickControlFn_ + + generic function to update the values of component controls. ## Description diff --git a/ui/blocks/src/ComponentSource/ComponentSource.stories.tsx b/ui/blocks/src/ComponentSource/ComponentSource.stories.tsx deleted file mode 100644 index da941edd3..000000000 --- a/ui/blocks/src/ComponentSource/ComponentSource.stories.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react'; -import { ComponentSource } from './ComponentSource'; -import { MockContext } from '../test/MockContext'; - -export default { - title: 'Blocks/Core/ComponentSource', - component: ComponentSource, -}; - -export const simple = () => ( - - - -); - -export const withTitle = () => ( - - - -); diff --git a/ui/blocks/src/ComponentSource/ComponentSource.tsx b/ui/blocks/src/ComponentSource/ComponentSource.tsx deleted file mode 100644 index 532866e98..000000000 --- a/ui/blocks/src/ComponentSource/ComponentSource.tsx +++ /dev/null @@ -1,80 +0,0 @@ -import React, { FC } from 'react'; -import { ActionItem } from '@component-controls/components'; -import { ComponentsContainer } from '../context/components/ComponentsContainer'; -import { ComponentInputProps } from '../context/components/ComponentsContext'; -import { - ThemeContext, - Source, - SourceProps, - BlockContainer, - BlockContainerProps, -} from '@component-controls/components'; -import { repositoryActions } from '../utils/repositoryActions'; - -export type ComponentSourceProps = ComponentInputProps & - Omit & - BlockContainerProps; - -/** - * Displays import statement for a component as well as the component file source code - * Optionally also displays some repository information from the component's package.json - * Under the hood, uses [prism-react-renderer](https://github.com/FormidableLabs/prism-react-renderer) for syntax highlighting - */ - -export const ComponentSource: FC = ({ - of, - actions, - title, - ...rest -}) => { - return ( - - - {component => { - let source; - const { from, importedName, name: componentName, repository } = - component || {}; - const importFrom = - repository && repository.name ? repository.name : from; - if (importFrom) { - source = - importedName !== 'default' && importedName !== 'namespace' - ? `import { ${componentName} } from '${importFrom}';` - : `import ${componentName} from '${importFrom}';`; - } - - if (!source) { - return null; - } - const { dark } = React.useContext(ThemeContext); - const [showFileSource, setShowFileSource] = React.useState( - false, - ); - - const onShowFileSource = () => setShowFileSource(!showFileSource); - const allActions: ActionItem[] = []; - - if (component && component.source) { - allActions.push({ - title: showFileSource ? 'import' : 'component', - onClick: onShowFileSource, - }); - } - const repositoryItems = - component && repositoryActions(component?.repository); - if (repositoryItems) { - allActions.push.apply(allActions, repositoryItems); - } - if (actions) { - allActions.push.apply(allActions, actions); - } - return ( - - {showFileSource ? component?.source ?? '' : source} - - ); - }} - - - ); -}; diff --git a/ui/blocks/src/ComponentSource/block/BlockComponentSource.stories.tsx b/ui/blocks/src/ComponentSource/block/BlockComponentSource.stories.tsx new file mode 100644 index 000000000..ad91d861e --- /dev/null +++ b/ui/blocks/src/ComponentSource/block/BlockComponentSource.stories.tsx @@ -0,0 +1,20 @@ +import React from 'react'; +import { BlockComponentSource } from './BlockComponentSource'; +import { MockContext } from '../../test/MockContext'; + +export default { + title: 'Blocks/Core/ComponentSource/block', + component: BlockComponentSource, +}; + +export const overview = () => ( + + + +); + +export const withTitle = () => ( + + + +); diff --git a/ui/blocks/src/ComponentSource/block/BlockComponentSource.tsx b/ui/blocks/src/ComponentSource/block/BlockComponentSource.tsx new file mode 100644 index 000000000..4ac59a071 --- /dev/null +++ b/ui/blocks/src/ComponentSource/block/BlockComponentSource.tsx @@ -0,0 +1,28 @@ +import React, { FC } from 'react'; +import { + BlockContainer, + BlockContainerProps, +} from '@component-controls/components'; +import { + ComponentSource, + ComponentSourceProps, +} from '../plain/ComponentSource'; + +export type BlockComponentSourceProps = ComponentSourceProps & + BlockContainerProps; + +/** + * Displays import statement for a component as well as the component file source code + * Optionally also displays some repository information from the component's package.json + */ + +export const BlockComponentSource: FC = ({ + title, + ...rest +}) => { + return ( + + + + ); +}; diff --git a/ui/blocks/src/ComponentSource/block/index.ts b/ui/blocks/src/ComponentSource/block/index.ts new file mode 100644 index 000000000..775207a46 --- /dev/null +++ b/ui/blocks/src/ComponentSource/block/index.ts @@ -0,0 +1 @@ +export * from './BlockComponentSource'; diff --git a/ui/blocks/src/ComponentSource/index.ts b/ui/blocks/src/ComponentSource/index.ts index b4103e639..54806845b 100644 --- a/ui/blocks/src/ComponentSource/index.ts +++ b/ui/blocks/src/ComponentSource/index.ts @@ -1 +1,2 @@ -export * from './ComponentSource'; +export * from './block'; +export * from './plain'; diff --git a/ui/blocks/src/ComponentSource/plain/ComponentSource.stories.tsx b/ui/blocks/src/ComponentSource/plain/ComponentSource.stories.tsx new file mode 100644 index 000000000..b89673488 --- /dev/null +++ b/ui/blocks/src/ComponentSource/plain/ComponentSource.stories.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import { ComponentSource } from './ComponentSource'; +import { MockContext } from '../../test/MockContext'; + +export default { + title: 'Blocks/Core/ComponentSource/plain', + component: ComponentSource, +}; + +export const overview = () => ( + + + +); diff --git a/ui/blocks/src/ComponentSource/plain/ComponentSource.tsx b/ui/blocks/src/ComponentSource/plain/ComponentSource.tsx new file mode 100644 index 000000000..31f9fac41 --- /dev/null +++ b/ui/blocks/src/ComponentSource/plain/ComponentSource.tsx @@ -0,0 +1,73 @@ +import React, { FC } from 'react'; +import { ActionItem } from '@component-controls/components'; +import { ComponentsContainer } from '../../context/components/ComponentsContainer'; +import { ComponentInputProps } from '../../context/components/ComponentsContext'; +import { + ThemeContext, + Source, + SourceProps, +} from '@component-controls/components'; +import { repositoryActions } from '../../utils/repositoryActions'; + +export type ComponentSourceProps = ComponentInputProps & + Omit; + +/** + * Displays import statement for a component as well as the component file source code + * Optionally also displays some repository information from the component's package.json + */ + +export const ComponentSource: FC = ({ + of, + actions, + ...rest +}) => { + return ( + + {component => { + let source; + const { from, importedName, name: componentName, repository } = + component || {}; + const importFrom = + repository && repository.name ? repository.name : from; + if (importFrom) { + source = + importedName !== 'default' && importedName !== 'namespace' + ? `import { ${componentName} } from '${importFrom}';` + : `import ${componentName} from '${importFrom}';`; + } + + if (!source) { + return null; + } + const { dark } = React.useContext(ThemeContext); + const [showFileSource, setShowFileSource] = React.useState( + false, + ); + + const onShowFileSource = () => setShowFileSource(!showFileSource); + const allActions: ActionItem[] = []; + + if (component && component.source) { + allActions.push({ + title: showFileSource ? 'import' : 'component', + onClick: onShowFileSource, + }); + } + const repositoryItems = + component && repositoryActions(component?.repository); + if (repositoryItems) { + allActions.push.apply(allActions, repositoryItems); + } + if (actions) { + allActions.push.apply(allActions, actions); + } + return ( + + {showFileSource ? component?.source ?? '' : source} + + ); + }} + + ); +}; diff --git a/ui/blocks/src/ComponentSource/plain/index.ts b/ui/blocks/src/ComponentSource/plain/index.ts new file mode 100644 index 000000000..b4103e639 --- /dev/null +++ b/ui/blocks/src/ComponentSource/plain/index.ts @@ -0,0 +1 @@ +export * from './ComponentSource'; diff --git a/ui/blocks/src/ControlsTable/ControlsTableProps.ts b/ui/blocks/src/ControlsTable/ControlsTableProps.ts deleted file mode 100644 index 5ee964683..000000000 --- a/ui/blocks/src/ControlsTable/ControlsTableProps.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { - SetControlValueFn, - ClickControlFn, -} from '@component-controls/specification'; -import { LoadedComponentControls } from '@component-controls/core'; - -export interface ControlsTableProps { - title?: string; - storyId?: string; - controls?: LoadedComponentControls; - setControlValue?: SetControlValueFn; - clickControl?: ClickControlFn; -} diff --git a/ui/blocks/src/ControlsTable/block/BlockControlsTable.stories.tsx b/ui/blocks/src/ControlsTable/block/BlockControlsTable.stories.tsx new file mode 100644 index 000000000..9d0febe11 --- /dev/null +++ b/ui/blocks/src/ControlsTable/block/BlockControlsTable.stories.tsx @@ -0,0 +1,54 @@ +import React from 'react'; +import { ControlTypes } from '@component-controls/specification'; +import { + LoadedComponentControls, + mergeControlValues, +} from '@component-controls/core'; +import { MockContext } from '../../test/MockContext'; +import { BlockControlsTable } from './BlockControlsTable'; + +export default { + title: 'Blocks/Core/ControlsTable/block', + component: BlockControlsTable, +}; + +export const overview = () => { + const [controls, setControls] = React.useState({ + name: { + type: ControlTypes.TEXT, + label: 'Name', + value: 'Mark', + defaultValue: 'Mark', + }, + age: { + type: ControlTypes.NUMBER, + label: 'Age', + value: 19, + defaultValue: 19, + }, + }); + + return ( + +

{`Hello, my name is ${controls.name.value}, and I am ${controls.age.value} years old.`}

+ + setControls(mergeControlValues(controls, name, value)) + } + clickControl={() => + setControls( + mergeControlValues( + controls, + 'age', + typeof controls.age.value === 'string' + ? parseInt(controls.age.value, 10) + 1 + : 19, + ), + ) + } + /> +
+ ); +}; diff --git a/ui/blocks/src/ControlsTable/block/BlockControlsTable.tsx b/ui/blocks/src/ControlsTable/block/BlockControlsTable.tsx new file mode 100644 index 000000000..f30cb8151 --- /dev/null +++ b/ui/blocks/src/ControlsTable/block/BlockControlsTable.tsx @@ -0,0 +1,22 @@ +import React, { FC } from 'react'; +import { + BlockContainer, + BlockContainerProps, +} from '@component-controls/components'; +import { ControlsTable, ControlsTableProps } from '../plain/ControlsTable'; + +export type BlockControlsTableProps = ControlsTableProps & BlockContainerProps; + +/** + * Table block component to display a story's controls and their editors + */ +export const BlockControlsTable: FC = ({ + title, + ...rest +}) => { + return ( + + + + ); +}; diff --git a/ui/blocks/src/ControlsTable/block/index.ts b/ui/blocks/src/ControlsTable/block/index.ts new file mode 100644 index 000000000..98c8a47fb --- /dev/null +++ b/ui/blocks/src/ControlsTable/block/index.ts @@ -0,0 +1 @@ +export * from './BlockControlsTable'; diff --git a/ui/blocks/src/ControlsTable/index.ts b/ui/blocks/src/ControlsTable/index.ts index 060797e64..54806845b 100644 --- a/ui/blocks/src/ControlsTable/index.ts +++ b/ui/blocks/src/ControlsTable/index.ts @@ -1,2 +1,2 @@ -export { ControlsTable } from './ControlsTable'; -export { ControlsTableProps } from './ControlsTableProps'; +export * from './block'; +export * from './plain'; diff --git a/ui/blocks/src/ControlsTable/ControlsTable.stories.tsx b/ui/blocks/src/ControlsTable/plain/ControlsTable.stories.tsx similarity index 93% rename from ui/blocks/src/ControlsTable/ControlsTable.stories.tsx rename to ui/blocks/src/ControlsTable/plain/ControlsTable.stories.tsx index f66044c77..4ca6fc08b 100644 --- a/ui/blocks/src/ControlsTable/ControlsTable.stories.tsx +++ b/ui/blocks/src/ControlsTable/plain/ControlsTable.stories.tsx @@ -6,15 +6,15 @@ import { getControlValues, loadControls, } from '@component-controls/core'; - import { ControlsTable } from './ControlsTable'; +import { MockContext } from '../../test/MockContext'; export default { - title: 'Blocks/Core/ControlsTable', + title: 'Blocks/Core/ControlsTable/plain', component: ControlsTable, }; -export const simple = () => { +export const overview = () => { const [controls, setControls] = React.useState({ name: { type: ControlTypes.TEXT, @@ -28,20 +28,13 @@ export const simple = () => { value: 19, defaultValue: 19, }, - clickMe: { - type: ControlTypes.BUTTON, - label: '+1', - onClick: () => {}, - }, }); return ( - <> +

{`Hello, my name is ${controls.name.value}, and I am ${controls.age.value} years old.`}

setControls(mergeControlValues(controls, name, value)) } @@ -57,7 +50,7 @@ export const simple = () => { ) } /> - +
); }; @@ -231,7 +224,7 @@ export const advanced = () => { }; return ( - <> +

{intro}

@@ -251,13 +244,11 @@ export const advanced = () => {

setControls(mergeControlValues(controls, name, value)) } /> - +
); }; diff --git a/ui/blocks/src/ControlsTable/ControlsTable.tsx b/ui/blocks/src/ControlsTable/plain/ControlsTable.tsx similarity index 51% rename from ui/blocks/src/ControlsTable/ControlsTable.tsx rename to ui/blocks/src/ControlsTable/plain/ControlsTable.tsx index 39b8fd1e2..9b44c9cee 100644 --- a/ui/blocks/src/ControlsTable/ControlsTable.tsx +++ b/ui/blocks/src/ControlsTable/plain/ControlsTable.tsx @@ -4,6 +4,10 @@ import React, { FC, MouseEvent } from 'react'; import { window, document } from 'global'; import qs from 'qs'; import copy from 'copy-to-clipboard'; +import { + SetControlValueFn, + ClickControlFn, +} from '@component-controls/specification'; import { resetControlValues, getControlValues, @@ -12,16 +16,32 @@ import { randomizeData, } from '@component-controls/core'; import { - BlockContainer, ActionContainer, Tab, Tabs, TabList, TabPanel, } from '@component-controls/components'; -import { ControlsTableProps } from './ControlsTableProps'; +import { useStoryContext } from '../../context/story/StoryContext'; + import { SingleControlsTable } from './SingleControlsTable'; +import { StoryInputProps } from '../../context/story/StoryContext'; + +export interface ControlsTableOwnProps { + /** + * generic function to update the values of component controls. + */ + setControlValue?: SetControlValueFn; + + /** + * generic function to propagate a click event for component controls. + */ + clickControl?: ClickControlFn; +} + +export type ControlsTableProps = ControlsTableOwnProps & StoryInputProps; + const DEFAULT_GROUP_ID = 'Other'; interface GroupedControlsType { @@ -29,13 +49,21 @@ interface GroupedControlsType { } /** - * Table component to display a story's controls and their editors + * Table component to display a story's controls and their editors. + * Can adapt to multiple groups of controls, displaying them in their own tabs. */ -export const ControlsTable: FC = props => { +export const ControlsTable: FC = ({ + id, + name, + ...rest +}) => { const [copied, setCopied] = React.useState(false); - const { controls, title, storyId, setControlValue } = props; + const { story, id: storyId } = useStoryContext({ + id, + name, + }); + const { controls } = story || {}; + const { setControlValue } = rest; if (controls && Object.keys(controls).length) { const onReset = (e: MouseEvent) => { e.preventDefault(); @@ -82,51 +110,62 @@ export const ControlsTable: FC { - if (state.setControlValue && state.controls && state.storyId) { - state.setControlValue( - state.storyId, - undefined, - randomizeData(state.controls), - ); + onClick: () => { + if (setControlValue && controls && storyId) { + setControlValue(storyId, undefined, randomizeData(controls)); } }, + id: 'randomize', + 'aria-label': 'generate random values for the component controls', }, ]; return ( - - - - {groupedItems.length === 1 ? ( - - ) : ( - - - {groupedItems.map(item => ( - {item.label} - ))} - + + + {groupedItems.length === 1 ? ( + + ) : ( + + {groupedItems.map(item => ( - - - + {item.label} ))} - - )} - - - + + {groupedItems.map(item => ( + + + + ))} + + )} + + ); } return null; diff --git a/ui/blocks/src/ControlsTable/SingleControlsTable.tsx b/ui/blocks/src/ControlsTable/plain/SingleControlsTable.tsx similarity index 74% rename from ui/blocks/src/ControlsTable/SingleControlsTable.tsx rename to ui/blocks/src/ControlsTable/plain/SingleControlsTable.tsx index 52183fc5b..89f001f25 100644 --- a/ui/blocks/src/ControlsTable/SingleControlsTable.tsx +++ b/ui/blocks/src/ControlsTable/plain/SingleControlsTable.tsx @@ -1,13 +1,40 @@ /* eslint-disable react/display-name */ import React, { FC } from 'react'; +import { + SetControlValueFn, + ClickControlFn, + ComponentControls, +} from '@component-controls/specification'; import { getPropertyEditor, PropertyEditor } from '@component-controls/editors'; import { Table } from '@component-controls/components'; import { Flex } from 'theme-ui'; -import { ControlsTableProps } from './ControlsTableProps'; const InvalidType = () => Invalid Type; -export const SingleControlsTable: FC = ({ +export interface SingleControlsTableProps { + /** + * componnet controls to display in the table. + */ + controls?: ComponentControls; + /** + * storyId, will be used to update the values of the controls + */ + storyId?: string; + /** + * generic function to update the values of component controls. + */ + setControlValue?: SetControlValueFn; + + /** + * generic function to propagate a click event for component controls. + */ +} + +/** + * Single table of controls, without specific handliong of groups. + * The controls and storyId are already set in priops; + */ +export const SingleControlsTable: FC = ({ controls, storyId, setControlValue, diff --git a/ui/blocks/src/ControlsTable/plain/index.ts b/ui/blocks/src/ControlsTable/plain/index.ts new file mode 100644 index 000000000..3ac2ee715 --- /dev/null +++ b/ui/blocks/src/ControlsTable/plain/index.ts @@ -0,0 +1 @@ +export * from './ControlsTable'; diff --git a/ui/blocks/src/StorySource/StorySource.tsx b/ui/blocks/src/StorySource/StorySource.tsx index 55c2f6d42..2531f157a 100644 --- a/ui/blocks/src/StorySource/StorySource.tsx +++ b/ui/blocks/src/StorySource/StorySource.tsx @@ -34,7 +34,7 @@ export const StorySource: FC = ({ actions={allActions} {...rest} > - {source} + {source ?? ''} ); }; diff --git a/ui/blocks/src/test/MockContext.tsx b/ui/blocks/src/test/MockContext.tsx index b031bbf29..0a4744e48 100644 --- a/ui/blocks/src/test/MockContext.tsx +++ b/ui/blocks/src/test/MockContext.tsx @@ -1,20 +1,29 @@ import React from 'react'; import { BlockContext } from '../context'; import { storyStore } from './storyStore'; +import { Story } from '@component-controls/specification'; export interface MockContexProps { storyId?: string; component?: React.ComponentType; + [key: string]: any; } export const MockContext: React.FC = ({ children, storyId = 'story', + ...rest }) => ( {children} diff --git a/ui/blocks/src/test/storyStore.ts b/ui/blocks/src/test/storyStore.ts index 436536fc4..b7649c7bd 100644 --- a/ui/blocks/src/test/storyStore.ts +++ b/ui/blocks/src/test/storyStore.ts @@ -1,4 +1,6 @@ -export const storyStore = { +import { StoriesStore } from '@component-controls/specification'; + +export const storyStore: StoriesStore = { components: { '/Users/atanasster/component-controls/core/instrument/test/fixtures/components/button-default-arrow-func.js': { from: '../../components/button-default-arrow-func', @@ -50,5 +52,22 @@ export const storyStore = { componentSubtitle: 'story subtitle', }, }, + controls: { + arguments: [], + kind: 'Story', + component: 'ArrowButton', + loc: { + end: { + column: 34, + line: 8, + }, + start: { + column: 21, + line: 8, + }, + }, + name: 'story', + source: "() => 'hello'", + }, }, }; diff --git a/ui/blocks/src/utils/repositoryActions.tsx b/ui/blocks/src/utils/repositoryActions.tsx index 4e2d387c5..ae0db9764 100644 --- a/ui/blocks/src/utils/repositoryActions.tsx +++ b/ui/blocks/src/utils/repositoryActions.tsx @@ -11,17 +11,32 @@ export const repositoryActions = ( const actions: ActionItem[] = []; if (browse) { actions.push({ - title: browse, + title: ( + + browse + + ), + id: 'browse', }); } if (docs) { actions.push({ - title: docs, + title: ( + + docs + + ), + id: 'docs', }); } if (issues) { actions.push({ - title: issues, + title: ( + + issues + + ), + id: 'issues', }); } return actions; diff --git a/ui/components/README.md b/ui/components/README.md index ec13bb19e..54c793263 100644 --- a/ui/components/README.md +++ b/ui/components/README.md @@ -44,7 +44,7 @@ Third-libraries used in no particular order: - [react-popper-tooltip](https://react-popper-tooltip.netlify.com) for popups and tooltips. - [react-animate-height](https://muffinman.io/react-animate-height/) for collapsible components. - [@theme-ui/presets](https://theme-ui.com/packages/presets/) for custom theming. -- [react-switch](https://github.com/markusenglund/react-switch) for toggle editor +- [react-switch](https://github.com/markusenglund/react-switch) for toggle/boolean inputs. # List of components