diff --git a/code/ui/.storybook/preview.tsx b/code/ui/.storybook/preview.tsx index 1054d62a5d59..34d955269f75 100644 --- a/code/ui/.storybook/preview.tsx +++ b/code/ui/.storybook/preview.tsx @@ -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 }), diff --git a/code/ui/blocks/src/controls/Object.stories.tsx b/code/ui/blocks/src/controls/Object.stories.tsx index d96844e51646..22aed6df6629 100644 --- a/code/ui/blocks/src/controls/Object.stories.tsx +++ b/code/ui/blocks/src/controls/Object.stories.tsx @@ -1,5 +1,6 @@ import type { Meta, StoryObj } from '@storybook/react'; import { ObjectControl } from './Object'; +import { fn } from '@storybook/test'; export default { component: ObjectControl, @@ -53,3 +54,34 @@ export const Undefined: StoryObj = { 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 = { + 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 = { + args: { + value: fn(), + }, +}; diff --git a/code/ui/blocks/src/controls/Object.tsx b/code/ui/blocks/src/controls/Object.tsx index d6c4d2328af0..f6c782164534 100644 --- a/code/ui/blocks/src/controls/Object.tsx +++ b/code/ui/blocks/src/controls/Object.tsx @@ -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'; @@ -247,7 +247,6 @@ export const ObjectControl: FC = ({ 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(null); const updateRaw: (raw: string) => void = useCallback( @@ -294,9 +293,12 @@ export const ObjectControl: FC = ({ name, value, onChange }) => { /> ); + const isObjectOrArray = + Array.isArray(value) || (typeof value === 'object' && value?.constructor === Object); + return ( - {['Object', 'Array'].includes(getObjectType(data)) && ( + {isObjectOrArray && ( { e.preventDefault(); @@ -309,6 +311,8 @@ export const ObjectControl: FC = ({ name, value, onChange }) => { )} {!showRaw ? ( !isObjectOrArray} data={data} rootName={name} onFullyUpdate={onChange}