Skip to content

Commit

Permalink
Merge pull request #23635 from storybookjs/charles-update-controls-addon
Browse files Browse the repository at this point in the history
UI: Improve controls addon
  • Loading branch information
JReinhold authored Aug 2, 2023
2 parents a70dcab + b22fd14 commit 0005430
Show file tree
Hide file tree
Showing 26 changed files with 1,069 additions and 363 deletions.
1 change: 1 addition & 0 deletions code/addons/controls/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
"@storybook/client-logger": "workspace:*",
"@storybook/components": "workspace:*",
"@storybook/core-common": "workspace:*",
"@storybook/core-events": "workspace:*",
"@storybook/manager-api": "workspace:*",
"@storybook/node-logger": "workspace:*",
"@storybook/preview-api": "workspace:*",
Expand Down
57 changes: 25 additions & 32 deletions code/addons/controls/src/ControlsPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
import type { FC } from 'react';
import React from 'react';
import React, { useEffect, useState } from 'react';
import {
useArgs,
useGlobals,
useArgTypes,
useParameter,
useStorybookState,
} from '@storybook/manager-api';
import {
PureArgsTable as ArgsTable,
NoControlsWarning,
type PresetColor,
type SortType,
} from '@storybook/blocks';
import { PureArgsTable as ArgsTable, type PresetColor, type SortType } from '@storybook/blocks';

import type { ArgTypes } from '@storybook/types';
import { PARAM_KEY } from './constants';
Expand All @@ -21,24 +16,26 @@ interface ControlsParameters {
sort?: SortType;
expanded?: boolean;
presetColors?: PresetColor[];

/** @deprecated No longer used, will be removed in Storybook 8.0 */
hideNoControlsWarning?: boolean;
}

export const ControlsPanel: FC = () => {
const [isLoading, setIsLoading] = useState(true);
const [args, updateArgs, resetArgs] = useArgs();
const [globals] = useGlobals();
const rows = useArgTypes();
const isArgsStory = useParameter<boolean>('__isArgsStory', false);
const {
expanded,
sort,
presetColors,
hideNoControlsWarning = false,
} = useParameter<ControlsParameters>(PARAM_KEY, {});
const { path } = useStorybookState();
const { expanded, sort, presetColors } = useParameter<ControlsParameters>(PARAM_KEY, {});
const { path, previewInitialized } = useStorybookState();

// If the story is prepared, then show the args table
// and reset the loading states
useEffect(() => {
if (previewInitialized) setIsLoading(false);
}, [previewInitialized]);

const hasControls = Object.values(rows).some((arg) => arg?.control);
const showWarning = !(hasControls && isArgsStory) && !hideNoControlsWarning;

const withPresetColors = Object.entries(rows).reduce((acc, [key, arg]) => {
if (arg?.control?.type !== 'color' || arg?.control?.presetColors) acc[key] = arg;
Expand All @@ -47,21 +44,17 @@ export const ControlsPanel: FC = () => {
}, {} as ArgTypes);

return (
<>
{showWarning && <NoControlsWarning />}
<ArgsTable
{...{
key: path, // resets state when switching stories
compact: !expanded && hasControls,
rows: withPresetColors,
args,
globals,
updateArgs,
resetArgs,
inAddonPanel: true,
sort,
}}
/>
</>
<ArgsTable
key={path} // resets state when switching stories
compact={!expanded && hasControls}
rows={withPresetColors}
args={args}
globals={globals}
updateArgs={updateArgs}
resetArgs={resetArgs}
inAddonPanel
sort={sort}
isLoading={isLoading}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ const getAbsolutePath = <I extends string>(input: I): I =>
dirname(require.resolve(join(input, 'package.json'))) as any;

const storybookPaths: Record<string, string> = {
// this is a temporary hack to get webpack to alias this correctly
[`@storybook/components/experimental`]: `${getAbsolutePath(
`@storybook/components`
)}/dist/experimental`,
...[
// these packages are not pre-bundled because of react dependencies
'components',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ import { DocInjectableService } from './doc-injectable.service';

export default {
component: DocInjectableService,
parameters: {
controls: { hideNoControlsWarning: true },
},
};

const modules = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ import { DocPipe } from './doc-pipe.pipe';

export default {
component: DocPipe,
parameters: {
controls: { hideNoControlsWarning: true },
},
};

const modules = {
Expand Down
1 change: 0 additions & 1 deletion code/ui/blocks/src/blocks/Description.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ const meta: Meta<typeof Description> = {
parameters: {
controls: {
include: [],
hideNoControlsWarning: true,
},
// workaround for https://github.com/storybookjs/storybook/issues/20505
docs: { source: { type: 'code' } },
Expand Down
17 changes: 15 additions & 2 deletions code/ui/blocks/src/components/ArgsTable/ArgControl.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { FC } from 'react';
import React, { useCallback, useState, useEffect } from 'react';

import { Link } from '@storybook/components/experimental';
import {
BooleanControl,
ColorControl,
Expand All @@ -18,6 +19,7 @@ export interface ArgControlProps {
row: ArgType;
arg: any;
updateArgs: (args: Args) => void;
isHovered: boolean;
}

const Controls: Record<string, FC> = {
Expand All @@ -40,7 +42,7 @@ const Controls: Record<string, FC> = {

const NoControl = () => <>-</>;

export const ArgControl: FC<ArgControlProps> = ({ row, arg, updateArgs }) => {
export const ArgControl: FC<ArgControlProps> = ({ row, arg, updateArgs, isHovered }) => {
const { key, control } = row;

const [isFocused, setFocused] = useState(false);
Expand All @@ -63,7 +65,18 @@ export const ArgControl: FC<ArgControlProps> = ({ row, arg, updateArgs }) => {
const onBlur = useCallback(() => setFocused(false), []);
const onFocus = useCallback(() => setFocused(true), []);

if (!control || control.disable) return <NoControl />;
if (!control || control.disable)
return isHovered ? (
<Link
href="https://storybook.js.org/docs/react/essentials/controls"
target="_blank"
withArrow
>
Setup controls
</Link>
) : (
<NoControl />
);

// row.name is a display name and not a suitable DOM input id or name - i might contain whitespace etc.
// row.key is a hash key and therefore a much safer choice
Expand Down
7 changes: 4 additions & 3 deletions code/ui/blocks/src/components/ArgsTable/ArgRow.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { FC } from 'react';
import React from 'react';
import React, { useState } from 'react';
import Markdown from 'markdown-to-jsx';
import { transparentize } from 'polished';
import { styled } from '@storybook/theming';
Expand Down Expand Up @@ -76,6 +76,7 @@ const StyledTd = styled.td<{ expandable: boolean }>(({ theme, expandable }) => (
}));

export const ArgRow: FC<ArgRowProps> = (props) => {
const [isHovered, setIsHovered] = useState(false);
const { row, updateArgs, compact, expandable, initialExpandedArgs } = props;
const { name, description } = row;
const table = (row.table || {}) as TableAnnotation;
Expand All @@ -85,7 +86,7 @@ export const ArgRow: FC<ArgRowProps> = (props) => {
const hasDescription = description != null && description !== '';

return (
<tr>
<tr onMouseEnter={() => setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
<StyledTd expandable={expandable}>
<Name>{name}</Name>
{required ? <Required title="Required">*</Required> : null}
Expand Down Expand Up @@ -118,7 +119,7 @@ export const ArgRow: FC<ArgRowProps> = (props) => {
)}
{updateArgs ? (
<td>
<ArgControl {...(props as ArgControlProps)} />
<ArgControl {...(props as ArgControlProps)} isHovered={isHovered} />
</td>
) : null}
</tr>
Expand Down
23 changes: 11 additions & 12 deletions code/ui/blocks/src/components/ArgsTable/ArgsTable.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import React from 'react';
import { action } from '@storybook/addon-actions';
import { styled } from '@storybook/theming';
import { ArgsTable, ArgsTableError } from './ArgsTable';
import { NoControlsWarning } from './NoControlsWarning';
import * as ArgRow from './ArgRow.stories';

export default {
Expand Down Expand Up @@ -58,15 +57,14 @@ export const InAddonPanel = {
decorators: [(storyFn: any) => <AddonPanelLayout>{storyFn()}</AddonPanelLayout>],
};

export const InAddonPanelWithWarning = {
render: (args: any) => (
<>
<NoControlsWarning />
<ArgsTable {...args} />
</>
),
// @ts-expect-error (not strict)
args: { ...InAddonPanel.args, updateArgs: null },
export const InAddonPanelNoControls = {
render: (args: any) => <ArgsTable {...args} />,
args: {
rows: {
stringType: { ...stringType, control: false },
numberType: { ...numberType, control: false },
},
},
decorators: InAddonPanel.decorators,
};

Expand Down Expand Up @@ -141,8 +139,9 @@ export const Error = {
};

export const Empty = {
args: {
rows: {},
args: {},
parameters: {
layout: 'centered',
},
};

Expand Down
Loading

0 comments on commit 0005430

Please sign in to comment.