Skip to content

Commit

Permalink
Only expand object control if data is plain object or array.
Browse files Browse the repository at this point in the history
  • Loading branch information
kasperpeulen committed Feb 21, 2024
1 parent 9605d69 commit f9b9958
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 4 deletions.
1 change: 0 additions & 1 deletion code/ui/.storybook/preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,6 @@ export const decorators = [
];

export const parameters = {
actions: { argTypesRegex: '^on.*' },
options: {
storySort: (a, b) =>
a.title === b.title ? 0 : a.id.localeCompare(b.id, undefined, { numeric: true }),
Expand Down
32 changes: 32 additions & 0 deletions code/ui/blocks/src/controls/Object.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Meta, StoryObj } from '@storybook/react';
import { ObjectControl } from './Object';
import { fn } from '@storybook/test';

export default {
component: ObjectControl,
Expand Down Expand Up @@ -53,3 +54,34 @@ export const Undefined: StoryObj<typeof ObjectControl> = {
value: undefined,
},
};

class Person {
constructor(
public firstName: string,
public lastName: string
) {}

fullName() {
return `${this.firstName} ${this.lastName}`;
}
}

/**
* We show a class collapsed as it might contain many methods.
* It is read-only as we can not construct the class.
*/
export const Class: StoryObj<typeof ObjectControl> = {
args: {
value: new Person('Kasper', 'Peulen'),
},
};

/**
* We show a function collapsed. Even if it is "object" like, such as "fn".
* It is read-only as we can not construct a function.
*/
export const Function: StoryObj<typeof ObjectControl> = {
args: {
value: fn(),
},
};
10 changes: 7 additions & 3 deletions code/ui/blocks/src/controls/Object.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import React, { useCallback, useMemo, useState, useEffect, useRef } from 'react'
import { styled, useTheme, type Theme } from '@storybook/theming';
import { Form, IconButton, Button } from '@storybook/components';
import { AddIcon, EyeCloseIcon, EyeIcon, SubtractIcon } from '@storybook/icons';
import { JsonTree, getObjectType } from './react-editable-json-tree';
import { JsonTree } from './react-editable-json-tree';
import { getControlId, getControlSetterButtonId } from './helpers';
import type { ControlProps, ObjectValue, ObjectConfig } from './types';

Expand Down Expand Up @@ -247,7 +247,6 @@ export const ObjectControl: FC<ObjectProps> = ({ name, value, onChange }) => {
const theme = useTheme();
const data = useMemo(() => value && cloneDeep(value), [value]);
const hasData = data !== null && data !== undefined;

const [showRaw, setShowRaw] = useState(!hasData);
const [parseError, setParseError] = useState<Error>(null);
const updateRaw: (raw: string) => void = useCallback(
Expand Down Expand Up @@ -294,9 +293,12 @@ export const ObjectControl: FC<ObjectProps> = ({ name, value, onChange }) => {
/>
);

const isObjectOrArray =
Array.isArray(value) || (typeof value === 'object' && value?.constructor === Object);

return (
<Wrapper>
{['Object', 'Array'].includes(getObjectType(data)) && (
{isObjectOrArray && (
<RawButton
onClick={(e: SyntheticEvent) => {
e.preventDefault();
Expand All @@ -309,6 +311,8 @@ export const ObjectControl: FC<ObjectProps> = ({ name, value, onChange }) => {
)}
{!showRaw ? (
<JsonTree
readOnly={!isObjectOrArray}
isCollapsed={() => !isObjectOrArray}
data={data}
rootName={name}
onFullyUpdate={onChange}
Expand Down

0 comments on commit f9b9958

Please sign in to comment.