From 09556227092a0c6679bea0d8754e7ed400cd16a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bertalan=20K=C3=B6rmendy?= Date: Mon, 13 May 2024 14:46:49 +0200 Subject: [PATCH] Support folder labels in the component API (#5651) * make the folder control a thing of the past * remove folder control factory * folder prop on properties + GenericControlProps * get the folder control from the property description * Update editor/src/core/property-controls/property-controls-local.spec.tsx Co-authored-by: Federico Ruggi <1081051+ruggi@users.noreply.github.com> * reflatten types in utopia-api/src/helper-functions * add folder to Matrix4ControlDescription too --------- Co-authored-by: Federico Ruggi <1081051+ruggi@users.noreply.github.com> --- .../custom-code/internal-property-controls.ts | 153 +++-------- .../component-section/folder-section.tsx | 3 +- .../row-or-folder-wrapper.tsx | 55 ++-- .../package-manager/utopia-api-typings.ts | 11 +- .../property-control-values.ts | 27 +- .../property-controls-local.spec.tsx | 62 +++++ .../property-controls-local.ts | 18 +- .../property-controls-parser.spec.ts | 29 +- .../property-controls-parser.ts | 252 ++++++++---------- utopia-api/src/property-controls/factories.ts | 8 - .../property-controls/property-controls.ts | 32 ++- 11 files changed, 271 insertions(+), 379 deletions(-) diff --git a/editor/src/components/custom-code/internal-property-controls.ts b/editor/src/components/custom-code/internal-property-controls.ts index bab2d2d69cd6..d9f723f7594e 100644 --- a/editor/src/components/custom-code/internal-property-controls.ts +++ b/editor/src/components/custom-code/internal-property-controls.ts @@ -1,6 +1,14 @@ import type { CSSProperties } from 'react' import type { ComponentInfo } from './code-file' +interface GenericControlProps { + label?: string + folder?: string + visibleByDefault?: boolean + required?: boolean + defaultValue?: T +} + export type BaseControlType = | 'checkbox' | 'color' @@ -21,22 +29,14 @@ export type BaseControlType = | 'vector4' | 'jsx' -export interface CheckboxControlDescription { +export interface CheckboxControlDescription extends GenericControlProps { control: 'checkbox' - label?: string - visibleByDefault?: boolean disabledTitle?: string enabledTitle?: string - required?: boolean - defaultValue?: unknown } -export interface ColorControlDescription { +export interface ColorControlDescription extends GenericControlProps { control: 'color' - label?: string - visibleByDefault?: boolean - required?: boolean - defaultValue?: unknown } export type AllowedEnumType = string | boolean | number | undefined | null @@ -48,13 +48,10 @@ export interface BasicControlOption { export type BasicControlOptions = AllowedEnumType[] | BasicControlOption[] -export interface PopUpListControlDescription { +export interface PopUpListControlDescription + extends GenericControlProps> { control: 'popuplist' - label?: string - visibleByDefault?: boolean options: BasicControlOptions - required?: boolean - defaultValue?: AllowedEnumType | BasicControlOption } export interface ImportType { source: string @@ -69,39 +66,24 @@ export interface ExpressionControlOption { requiredImport?: ImportType } -export interface ExpressionPopUpListControlDescription { +export interface ExpressionPopUpListControlDescription extends GenericControlProps { control: 'expression-popuplist' - label?: string - visibleByDefault?: boolean options: ExpressionControlOption[] - required?: boolean - defaultValue?: unknown } -export interface EulerControlDescription { +export interface EulerControlDescription + extends GenericControlProps<[number, number, number, string]> { control: 'euler' - label?: string - visibleByDefault?: boolean - required?: boolean - defaultValue?: [number, number, number, string] } -export interface NoneControlDescription { +export interface NoneControlDescription extends GenericControlProps { control: 'none' - label?: string - visibleByDefault?: boolean - required?: boolean - defaultValue?: unknown } export type Matrix3 = [number, number, number, number, number, number, number, number, number] -export interface Matrix3ControlDescription { +export interface Matrix3ControlDescription extends GenericControlProps { control: 'matrix3' - label?: string - visibleByDefault?: boolean - required?: boolean - defaultValue?: Matrix3 } export type Matrix4 = [ @@ -123,95 +105,57 @@ export type Matrix4 = [ number, ] -export interface Matrix4ControlDescription { +export interface Matrix4ControlDescription extends GenericControlProps { control: 'matrix4' - label?: string - visibleByDefault?: boolean - required?: boolean - defaultValue?: Matrix4 } -export interface NumberInputControlDescription { +export interface NumberInputControlDescription extends GenericControlProps { control: 'number-input' - label?: string - visibleByDefault?: boolean max?: number min?: number unit?: string step?: number displayStepper?: boolean - required?: boolean - defaultValue?: unknown } -export interface RadioControlDescription { +export interface RadioControlDescription + extends GenericControlProps> { control: 'radio' - label?: string - visibleByDefault?: boolean options: BasicControlOptions - required?: boolean - defaultValue?: AllowedEnumType | BasicControlOption } -export interface ExpressionInputControlDescription { +export interface ExpressionInputControlDescription extends GenericControlProps { control: 'expression-input' - label?: string - visibleByDefault?: boolean - required?: boolean - defaultValue?: unknown } -export interface StringInputControlDescription { +export interface StringInputControlDescription extends GenericControlProps { control: 'string-input' - label?: string - visibleByDefault?: boolean placeholder?: string obscured?: boolean - required?: boolean - defaultValue?: unknown } -export interface HtmlInputControlDescription { +export interface HtmlInputControlDescription extends GenericControlProps { control: 'html-input' - label?: string - visibleByDefault?: boolean placeholder?: string obscured?: boolean - required?: boolean - defaultValue?: unknown } -export interface StyleControlsControlDescription { +export interface StyleControlsControlDescription extends GenericControlProps { control: 'style-controls' - label?: string - visibleByDefault?: boolean placeholder?: CSSProperties - required?: boolean - defaultValue?: unknown } -export interface Vector2ControlDescription { +export interface Vector2ControlDescription extends GenericControlProps<[number, number]> { control: 'vector2' - label?: string - visibleByDefault?: boolean - required?: boolean - defaultValue?: [number, number] } -export interface Vector3ControlDescription { +export interface Vector3ControlDescription extends GenericControlProps<[number, number, number]> { control: 'vector3' - label?: string - visibleByDefault?: boolean - required?: boolean - defaultValue?: [number, number, number] } -export interface Vector4ControlDescription { +export interface Vector4ControlDescription + extends GenericControlProps<[number, number, number, number]> { control: 'vector4' - label?: string - visibleByDefault?: boolean - required?: boolean - defaultValue?: [number, number, number, number] } export interface PreferredChildComponentDescriptor { @@ -220,13 +164,9 @@ export interface PreferredChildComponentDescriptor { variants: Array } -export interface JSXControlDescription { +export interface JSXControlDescription extends GenericControlProps { control: 'jsx' - label?: string - visibleByDefault?: boolean preferredChildComponents: Array - required?: boolean - defaultValue?: unknown } export declare type BaseControlDescription = | CheckboxControlDescription @@ -254,49 +194,27 @@ export type RegularControlType = BaseControlType | HigherLevelControlType export type ControlType = RegularControlType | 'folder' -export interface ArrayControlDescription { +export interface ArrayControlDescription extends GenericControlProps { control: 'array' - label?: string - visibleByDefault?: boolean propertyControl: RegularControlDescription maxCount?: number - required?: boolean - defaultValue?: unknown } -export interface ObjectControlDescription { +export interface ObjectControlDescription extends GenericControlProps { control: 'object' - label?: string - visibleByDefault?: boolean object: { [prop: string]: RegularControlDescription } - required?: boolean - defaultValue?: unknown } -export interface UnionControlDescription { +export interface UnionControlDescription extends GenericControlProps { control: 'union' - label?: string - visibleByDefault?: boolean controls: Array - required?: boolean - defaultValue?: unknown } -export interface TupleControlDescription { +export interface TupleControlDescription extends GenericControlProps { control: 'tuple' - label?: string - visibleByDefault?: boolean propertyControls: RegularControlDescription[] - required?: boolean - defaultValue?: unknown -} - -export interface FolderControlDescription { - control: 'folder' - label?: string - controls: PropertyControls } export type HigherLevelControlDescription = @@ -306,7 +224,7 @@ export type HigherLevelControlDescription = | UnionControlDescription export type RegularControlDescription = BaseControlDescription | HigherLevelControlDescription -export type ControlDescription = RegularControlDescription | FolderControlDescription +export type ControlDescription = RegularControlDescription export type PropertyControls = { [key: string]: ControlDescription @@ -339,7 +257,6 @@ export function isBaseControlDescription( case 'object': case 'tuple': case 'union': - case 'folder': return false default: const _exhaustiveCheck: never = control diff --git a/editor/src/components/inspector/sections/component-section/folder-section.tsx b/editor/src/components/inspector/sections/component-section/folder-section.tsx index 9acb7966dd3a..799797d4baf0 100644 --- a/editor/src/components/inspector/sections/component-section/folder-section.tsx +++ b/editor/src/components/inspector/sections/component-section/folder-section.tsx @@ -38,8 +38,7 @@ export const FolderSection = React.memo((props: FolderSectionProps) => { () => Object.keys(props.propertyControls).filter((prop) => { const control = props.propertyControls[prop] - const isVisibleByDefault = - control.control === 'folder' || (control.visibleByDefault ?? true) + const isVisibleByDefault = control.visibleByDefault ?? true return ( !isVisibleByDefault && props.unsetPropNames.includes(prop) && diff --git a/editor/src/components/inspector/sections/component-section/row-or-folder-wrapper.tsx b/editor/src/components/inspector/sections/component-section/row-or-folder-wrapper.tsx index 63ad82f5ea9e..c49373d16b50 100644 --- a/editor/src/components/inspector/sections/component-section/row-or-folder-wrapper.tsx +++ b/editor/src/components/inspector/sections/component-section/row-or-folder-wrapper.tsx @@ -3,8 +3,6 @@ import type { ControlDescription } from '../../../custom-code/internal-property- import type { PropertyPath } from '../../../../core/shared/project-file-types' import type { CSSCursor } from '../../../canvas/canvas-types' import { UIGridRow } from '../../widgets/ui-grid-row' -import { FolderSection } from './folder-section' -import * as PP from '../../../../core/shared/property-path' import { RowForControl } from './component-section' type RowOrFolderWrapperProps = { @@ -20,39 +18,22 @@ type RowOrFolderWrapperProps = { } export const RowOrFolderWrapper = React.memo((props: RowOrFolderWrapperProps) => { - switch (props.controlDescription.control) { - case 'folder': - return ( - - ) - default: - return ( - - - - ) - } + return ( + + + + ) }) diff --git a/editor/src/core/es-modules/package-manager/utopia-api-typings.ts b/editor/src/core/es-modules/package-manager/utopia-api-typings.ts index 682556330509..0ff2781b6c41 100644 --- a/editor/src/core/es-modules/package-manager/utopia-api-typings.ts +++ b/editor/src/core/es-modules/package-manager/utopia-api-typings.ts @@ -354,7 +354,7 @@ declare module 'utopia-api/primitives/view' { } declare module 'utopia-api/property-controls/factories' { - import { ArrayControlDescription, BasicControlOptions, CheckboxControlDescription, ColorControlDescription, EulerControlDescription, ExpressionControlOption, ExpressionInputControlDescription, ExpressionPopUpListControlDescription, FolderControlDescription, ImportType, Matrix3ControlDescription, Matrix4ControlDescription, NoneControlDescription, NumberInputControlDescription, ObjectControlDescription, PopUpListControlDescription, PropertyControls, RadioControlDescription, RegularControlDescription, StringInputControlDescription, StyleControlsControlDescription, TupleControlDescription, UnionControlDescription, Vector2ControlDescription, Vector3ControlDescription, Vector4ControlDescription } from 'utopia-api/property-controls/property-controls'; + import { ArrayControlDescription, BasicControlOptions, CheckboxControlDescription, ColorControlDescription, EulerControlDescription, ExpressionControlOption, ExpressionInputControlDescription, ExpressionPopUpListControlDescription, ImportType, Matrix3ControlDescription, Matrix4ControlDescription, NoneControlDescription, NumberInputControlDescription, ObjectControlDescription, PopUpListControlDescription, PropertyControls, RadioControlDescription, RegularControlDescription, StringInputControlDescription, StyleControlsControlDescription, TupleControlDescription, UnionControlDescription, Vector2ControlDescription, Vector3ControlDescription, Vector4ControlDescription } from 'utopia-api/property-controls/property-controls'; export function checkboxControl(): CheckboxControlDescription; export function colorControl(): ColorControlDescription; export function expressionControl(): ExpressionInputControlDescription; @@ -383,7 +383,6 @@ declare module 'utopia-api/property-controls/factories' { }): ObjectControlDescription; export function tupleControl(propertyControls: RegularControlDescription[]): TupleControlDescription; export function unionControl(controls: Array): UnionControlDescription; - export function folderControl(controls: PropertyControls): FolderControlDescription; } declare module 'utopia-api/property-controls/property-controls' { @@ -530,14 +529,10 @@ declare module 'utopia-api/property-controls/property-controls' { visibleByDefault?: boolean; propertyControls: RegularControlDescription[]; } - export interface FolderControlDescription { - control: 'folder'; - label?: string; - controls: PropertyControls; - } + export type HigherLevelControlDescription = ArrayControlDescription | ObjectControlDescription | TupleControlDescription | UnionControlDescription; export type RegularControlDescription = BaseControlDescription | HigherLevelControlDescription; - export type ControlDescription = RegularControlDescription | FolderControlDescription; + export type ControlDescription = RegularControlDescription; export function isBaseControlDescription(control: ControlDescription): control is BaseControlDescription; export function isHigherLevelControlDescription(control: ControlDescription): control is HigherLevelControlDescription; export type PropertyControls = { diff --git a/editor/src/core/property-controls/property-control-values.ts b/editor/src/core/property-controls/property-control-values.ts index ff1de9408808..3ba605ac9faf 100644 --- a/editor/src/core/property-controls/property-control-values.ts +++ b/editor/src/core/property-controls/property-control-values.ts @@ -17,7 +17,6 @@ import type { BaseControlDescription, ControlDescription, UnionControlDescription, - FolderControlDescription, PropertyControls, RegularControlDescription, } from '../../components/custom-code/internal-property-controls' @@ -384,30 +383,10 @@ export function walkRegularControlDescriptions( propertyControls: PropertyControls, walkWith: (propertyName: string, propertyControl: RegularControlDescription) => void, ): void { - function addPropertyControl( - propertyName: number | string, - propertyControl: ControlDescription, - ): void { - switch (propertyControl.control) { - case 'folder': - addFolder(propertyControl) - break - default: - if (typeof propertyName === 'string') { - walkWith(propertyName, propertyControl) - } - break - } - } - - function addFolder(folder: FolderControlDescription): void { - forEachValue((propertyControl, propertyName) => { - addPropertyControl(propertyName, propertyControl) - }, folder.controls) - } - forEachValue((propertyControl, propertyName) => { - addPropertyControl(propertyName, propertyControl) + if (typeof propertyName === 'string') { + walkWith(propertyName, propertyControl) + } }, propertyControls) } diff --git a/editor/src/core/property-controls/property-controls-local.spec.tsx b/editor/src/core/property-controls/property-controls-local.spec.tsx index dd9e4817ca23..97d451097bc0 100644 --- a/editor/src/core/property-controls/property-controls-local.spec.tsx +++ b/editor/src/core/property-controls/property-controls-local.spec.tsx @@ -1781,6 +1781,68 @@ describe('registered property controls', () => { `) }) }) + + describe('folders', () => { + it('can specify a folder prop', async () => { + const renderResult = await renderTestEditorWithModel( + project({ + ['/utopia/components.utopia.js']: `import { Card } from '../src/card' + + const Components = { + '/src/card': { + Card: { + component: Card, + properties: { + label: { + control: 'jsx', + }, + header: { + control: 'jsx', + folder: 'Header', + }, + footer: { + control: 'jsx', + folder: 'Footer', + } + } + }, + }, + } + + export default Components + `, + }), + 'await-first-dom-report', + ) + const editorState = renderResult.getEditorState().editor + + const cardRegistration = editorState.propertyControlsInfo['/src/card']['Card'] + expect(cardRegistration).not.toBeUndefined() + + const propsToCheck = pick(['properties'], cardRegistration) + + expect(propsToCheck).toMatchInlineSnapshot(` + Object { + "properties": Object { + "footer": Object { + "control": "jsx", + "folder": "Footer", + "preferredChildComponents": Array [], + }, + "header": Object { + "control": "jsx", + "folder": "Header", + "preferredChildComponents": Array [], + }, + "label": Object { + "control": "jsx", + "preferredChildComponents": Array [], + }, + }, + } + `) + }) + }) }) describe('Lifecycle management of registering components', () => { diff --git a/editor/src/core/property-controls/property-controls-local.ts b/editor/src/core/property-controls/property-controls-local.ts index d501fad7d48c..9d4ac5a71112 100644 --- a/editor/src/core/property-controls/property-controls-local.ts +++ b/editor/src/core/property-controls/property-controls-local.ts @@ -50,7 +50,6 @@ import { parseArray, parseConstant, parseEnum, - parseNumber, parseObject, parseString, } from '../../utils/value-parser-utils' @@ -67,7 +66,6 @@ import { right, sequenceEither, } from '../shared/either' -import { setOptionalProp } from '../shared/object-utils' import { assertNever } from '../shared/utils' import type { Imports, ParsedTextFile } from '../shared/project-file-types' import { @@ -770,19 +768,11 @@ async function makePropertyDescriptors( let result: PropertyControls = {} for await (const [propertyName, descriptor] of Object.entries(properties)) { - if (descriptor.control === 'folder') { - const parsedControlsInFolder = await makePropertyDescriptors(descriptor.controls, context) - if (isLeft(parsedControlsInFolder)) { - return parsedControlsInFolder - } - result['propertyName'] = { ...descriptor, controls: parsedControlsInFolder.value } - } else { - const parsedRegularControl = await makeRegularControlDescription(descriptor, context) - if (isLeft(parsedRegularControl)) { - return parsedRegularControl - } - result[propertyName] = parsedRegularControl.value + const parsedRegularControl = await makeRegularControlDescription(descriptor, context) + if (isLeft(parsedRegularControl)) { + return parsedRegularControl } + result[propertyName] = parsedRegularControl.value } return right(result) diff --git a/editor/src/core/property-controls/property-controls-parser.spec.ts b/editor/src/core/property-controls/property-controls-parser.spec.ts index b97c94b492fb..31c4f97a6af2 100644 --- a/editor/src/core/property-controls/property-controls-parser.spec.ts +++ b/editor/src/core/property-controls/property-controls-parser.spec.ts @@ -7,7 +7,6 @@ import type { ColorControlDescription, NoneControlDescription, StyleControlsControlDescription, - FolderControlDescription, ExpressionInputControlDescription, Vector2ControlDescription, Vector3ControlDescription, @@ -31,7 +30,6 @@ import { parsePropertyControls, parseNoneControlDescription, parseStyleControlsControlDescription, - parseFolderControlDescription, parseControlDescription, parseExpressionInputControlDescription, parseVector2ControlDescription, @@ -366,6 +364,7 @@ const validStringInputControlDescriptionValue: StringInputControlDescription = { placeholder: 'Enter text', obscured: true, visibleByDefault: true, + folder: 'String Input', } describe('parseStringInputControlDescription', () => { @@ -505,6 +504,7 @@ const validArrayControlDescriptionValue: ArrayControlDescription = { propertyControl: { control: 'string-input', }, + folder: 'Array Control', } describe('parseArrayControlDescription', () => { @@ -529,6 +529,7 @@ const validObjectControlDescriptionValue: ObjectControlDescription = { control: 'string-input', }, }, + folder: 'Object Control', } describe('parseObjectControlDescription', () => { @@ -565,25 +566,6 @@ describe('parseTupleControlDescription', () => { ) }) -const validFolderControlDescriptionValue: FolderControlDescription = { - control: 'folder', - controls: { - style: validStyleControlsControlDescriptionValue, - someSlider: validNumberInputControlDescriptionValue, - }, -} - -describe('parseFolderControlDescription', () => { - runBaseTestSuite( - validFolderControlDescriptionValue, - ['control', 'controls'], - parseFolderControlDescription, - 'Value was not folder.', - 'does-not-support-required', - [], - ) -}) - describe('parseControlDescription', () => { it('parses a number input description correctly', () => { expect(parseControlDescription(validNumberInputControlDescriptionValue)).toEqual( @@ -645,11 +627,6 @@ describe('parseControlDescription', () => { right(validTupleControlDescriptionValue), ) }) - it('parses a folder instance description correctly', () => { - expect(parseControlDescription(validFolderControlDescriptionValue)).toEqual( - right(validFolderControlDescriptionValue), - ) - }) it('parses a vector2 description correctly', () => { expect(parseControlDescription(validVector2ControlDescriptionValue)).toEqual( right(validVector2ControlDescriptionValue), diff --git a/editor/src/core/property-controls/property-controls-parser.ts b/editor/src/core/property-controls/property-controls-parser.ts index 8c37715f7337..3433f925666e 100644 --- a/editor/src/core/property-controls/property-controls-parser.ts +++ b/editor/src/core/property-controls/property-controls-parser.ts @@ -15,7 +15,6 @@ import type { Vector3ControlDescription, ExpressionPopUpListControlDescription, ImportType, - FolderControlDescription, PropertyControls, RegularControlDescription, ExpressionInputControlDescription, @@ -44,7 +43,9 @@ import { objectFieldNotPresentParseError, objectFieldParseError, objectKeyParser, + objectParser, optionalObjectKeyParser, + optionalProp, parseAlternative, parseAny, parseArray, @@ -92,49 +93,19 @@ import { const requiredFieldParser = optionalObjectKeyParser(parseBoolean, 'required') -export function parseNumberInputControlDescription( - value: unknown, -): ParseResult { - return applicative10Either( - ( - label, - control, - max, - min, - unit, - step, - displayStepper, - visibleByDefault, - required, - defaultValue, - ) => { - let numberInputControlDescription: NumberInputControlDescription = { - control: control, - } - setOptionalProp(numberInputControlDescription, 'label', label) - setOptionalProp(numberInputControlDescription, 'max', max) - setOptionalProp(numberInputControlDescription, 'min', min) - setOptionalProp(numberInputControlDescription, 'unit', unit) - setOptionalProp(numberInputControlDescription, 'step', step) - setOptionalProp(numberInputControlDescription, 'displayStepper', displayStepper) - setOptionalProp(numberInputControlDescription, 'visibleByDefault', visibleByDefault) - setOptionalProp(numberInputControlDescription, 'required', required) - setOptionalProp(numberInputControlDescription, 'defaultValue', defaultValue) - - return numberInputControlDescription - }, - optionalObjectKeyParser(parseString, 'label')(value), - objectKeyParser(parseConstant('number-input'), 'control')(value), - optionalObjectKeyParser(parseNumber, 'max')(value), - optionalObjectKeyParser(parseNumber, 'min')(value), - optionalObjectKeyParser(parseString, 'unit')(value), - optionalObjectKeyParser(parseNumber, 'step')(value), - optionalObjectKeyParser(parseBoolean, 'displayStepper')(value), - optionalObjectKeyParser(parseBoolean, 'visibleByDefault')(value), - requiredFieldParser(value), - optionalObjectKeyParser(parseNumber, 'defaultValue')(value), - ) -} +export const parseNumberInputControlDescription = objectParser({ + control: parseConstant('number-input'), + label: optionalProp(parseString), + folder: optionalProp(parseString), + max: optionalProp(parseNumber), + min: optionalProp(parseNumber), + unit: optionalProp(parseString), + step: optionalProp(parseNumber), + displayStepper: optionalProp(parseBoolean), + visibleByDefault: optionalProp(parseBoolean), + required: optionalProp(parseBoolean), + defaultValue: optionalProp(parseNumber), +}) function parseBasicControlOption(valueParser: Parser): Parser> { return (value: unknown) => { @@ -167,13 +138,14 @@ const parseEnumValueOrBasicControlOption: Parser { - return applicative6Either( - (label, control, options, visibleByDefault, required, defaultValue) => { + return applicative7Either( + (label, folder, control, options, visibleByDefault, required, defaultValue) => { let popupListControlDescription: PopUpListControlDescription = { control: control, options: options, } setOptionalProp(popupListControlDescription, 'label', label) + setOptionalProp(popupListControlDescription, 'folder', folder) setOptionalProp(popupListControlDescription, 'visibleByDefault', visibleByDefault) setOptionalProp(popupListControlDescription, 'required', required) setOptionalProp(popupListControlDescription, 'defaultValue', defaultValue) @@ -181,6 +153,7 @@ export function parsePopUpListControlDescription( return popupListControlDescription }, optionalObjectKeyParser(parseString, 'label')(value), + optionalObjectKeyParser(parseString, 'folder')(value), objectKeyParser(parseConstant('popuplist'), 'control')(value), objectKeyParser(parseBasicControlOptions, 'options')(value), optionalObjectKeyParser(parseBoolean, 'visibleByDefault')(value), @@ -192,13 +165,14 @@ export function parsePopUpListControlDescription( export function parseExpressionPopUpListControlDescription( value: unknown, ): ParseResult { - return applicative6Either( - (label, control, options, visibleByDefault, required, defaultValue) => { + return applicative7Either( + (label, folder, control, options, visibleByDefault, required, defaultValue) => { let enumControlDescription: ExpressionPopUpListControlDescription = { control: control, options: options, } setOptionalProp(enumControlDescription, 'label', label) + setOptionalProp(enumControlDescription, 'folder', folder) setOptionalProp(enumControlDescription, 'visibleByDefault', visibleByDefault) setOptionalProp(enumControlDescription, 'required', required) setOptionalProp(enumControlDescription, 'defaultValue', defaultValue) @@ -206,6 +180,7 @@ export function parseExpressionPopUpListControlDescription( return enumControlDescription }, optionalObjectKeyParser(parseString, 'label')(value), + optionalObjectKeyParser(parseString, 'folder')(value), objectKeyParser(parseConstant('expression-popuplist'), 'control')(value), objectKeyParser(parseArray(parseExpressionControlOption), 'options')(value), optionalObjectKeyParser(parseBoolean, 'visibleByDefault')(value), @@ -259,12 +234,22 @@ function parseExpressionControlOption( export function parseCheckboxControlDescription( value: unknown, ): ParseResult { - return applicative7Either( - (label, control, disabledTitle, enabledTitle, visibleByDefault, required, defaultValue) => { + return applicative8Either( + ( + label, + folder, + control, + disabledTitle, + enabledTitle, + visibleByDefault, + required, + defaultValue, + ) => { let checkboxControlDescription: CheckboxControlDescription = { control: control, } setOptionalProp(checkboxControlDescription, 'label', label) + setOptionalProp(checkboxControlDescription, 'folder', folder) setOptionalProp(checkboxControlDescription, 'disabledTitle', disabledTitle) setOptionalProp(checkboxControlDescription, 'enabledTitle', enabledTitle) setOptionalProp(checkboxControlDescription, 'visibleByDefault', visibleByDefault) @@ -274,6 +259,7 @@ export function parseCheckboxControlDescription( return checkboxControlDescription }, optionalObjectKeyParser(parseString, 'label')(value), + optionalObjectKeyParser(parseString, 'folder')(value), objectKeyParser(parseConstant('checkbox'), 'control')(value), optionalObjectKeyParser(parseString, 'disabledTitle')(value), optionalObjectKeyParser(parseString, 'enabledTitle')(value), @@ -286,12 +272,13 @@ export function parseCheckboxControlDescription( export function parseStringInputControlDescription( value: unknown, ): ParseResult { - return applicative7Either( - (label, control, placeholder, obscured, visibleByDefault, required, defaultValue) => { + return applicative8Either( + (label, folder, control, placeholder, obscured, visibleByDefault, required, defaultValue) => { let stringInputControlDescription: StringInputControlDescription = { control: control, } setOptionalProp(stringInputControlDescription, 'label', label) + setOptionalProp(stringInputControlDescription, 'folder', folder) setOptionalProp(stringInputControlDescription, 'placeholder', placeholder) setOptionalProp(stringInputControlDescription, 'obscured', obscured) setOptionalProp(stringInputControlDescription, 'visibleByDefault', visibleByDefault) @@ -301,6 +288,7 @@ export function parseStringInputControlDescription( return stringInputControlDescription }, optionalObjectKeyParser(parseString, 'label')(value), + optionalObjectKeyParser(parseString, 'folder')(value), objectKeyParser(parseConstant('string-input'), 'control')(value), optionalObjectKeyParser(parseString, 'placeholder')(value), optionalObjectKeyParser(parseBoolean, 'obscured')(value), @@ -313,12 +301,13 @@ export function parseStringInputControlDescription( export function parseHtmlInputControlDescription( value: unknown, ): ParseResult { - return applicative7Either( - (label, control, placeholder, obscured, visibleByDefault, required, defaultValue) => { + return applicative8Either( + (label, folder, control, placeholder, obscured, visibleByDefault, required, defaultValue) => { let htmlInputControlDescription: HtmlInputControlDescription = { control: control, } setOptionalProp(htmlInputControlDescription, 'label', label) + setOptionalProp(htmlInputControlDescription, 'folder', folder) setOptionalProp(htmlInputControlDescription, 'placeholder', placeholder) setOptionalProp(htmlInputControlDescription, 'obscured', obscured) setOptionalProp(htmlInputControlDescription, 'visibleByDefault', visibleByDefault) @@ -328,6 +317,7 @@ export function parseHtmlInputControlDescription( return htmlInputControlDescription }, optionalObjectKeyParser(parseString, 'label')(value), + optionalObjectKeyParser(parseString, 'folder')(value), objectKeyParser(parseConstant('html-input'), 'control')(value), optionalObjectKeyParser(parseString, 'placeholder')(value), optionalObjectKeyParser(parseBoolean, 'obscured')(value), @@ -338,13 +328,14 @@ export function parseHtmlInputControlDescription( } export function parseRadioControlDescription(value: unknown): ParseResult { - return applicative6Either( - (label, control, options, visibleByDefault, required, defaultValue) => { + return applicative7Either( + (label, folder, control, options, visibleByDefault, required, defaultValue) => { let radioControlDescription: RadioControlDescription = { control: control, options: options, } setOptionalProp(radioControlDescription, 'label', label) + setOptionalProp(radioControlDescription, 'folder', folder) setOptionalProp(radioControlDescription, 'visibleByDefault', visibleByDefault) setOptionalProp(radioControlDescription, 'required', required) setOptionalProp(radioControlDescription, 'defaultValue', defaultValue) @@ -352,6 +343,7 @@ export function parseRadioControlDescription(value: unknown): ParseResult } export function parseColorControlDescription(value: unknown): ParseResult { - return applicative5Either( - (label, control, visibleByDefault, required, defaultValue) => { + return applicative6Either( + (label, folder, control, visibleByDefault, required, defaultValue) => { let colorControlDescription: ColorControlDescription = { control: control, } setOptionalProp(colorControlDescription, 'label', label) + setOptionalProp(colorControlDescription, 'folder', folder) setOptionalProp(colorControlDescription, 'visibleByDefault', visibleByDefault) setOptionalProp(colorControlDescription, 'required', required) setOptionalProp(colorControlDescription, 'defaultValue', defaultValue) @@ -402,6 +395,7 @@ export function parseColorControlDescription(value: unknown): ParseResult { - return applicative5Either( - (label, control, visibleByDefault, required, defaultValue) => { + return applicative6Either( + (label, folder, control, visibleByDefault, required, defaultValue) => { let expressionInputControlDescription: ExpressionInputControlDescription = { control: control, } setOptionalProp(expressionInputControlDescription, 'label', label) + setOptionalProp(expressionInputControlDescription, 'folder', folder) setOptionalProp(expressionInputControlDescription, 'visibleByDefault', visibleByDefault) setOptionalProp(expressionInputControlDescription, 'required', required) setOptionalProp(expressionInputControlDescription, 'defaultValue', defaultValue) @@ -425,6 +420,7 @@ export function parseExpressionInputControlDescription( return expressionInputControlDescription }, optionalObjectKeyParser(parseString, 'label')(value), + optionalObjectKeyParser(parseString, 'folder')(value), objectKeyParser(parseConstant('expression-input'), 'control')(value), optionalObjectKeyParser(parseBoolean, 'visibleByDefault')(value), requiredFieldParser(value), @@ -433,18 +429,20 @@ export function parseExpressionInputControlDescription( } export function parseNoneControlDescription(value: unknown): ParseResult { - return applicative5Either( - (label, control, visibleByDefault, required, defaultValue) => { + return applicative6Either( + (label, folder, control, visibleByDefault, required, defaultValue) => { let noneControlDescription: NoneControlDescription = { control: control, } setOptionalProp(noneControlDescription, 'label', label) + setOptionalProp(noneControlDescription, 'folder', folder) setOptionalProp(noneControlDescription, 'visibleByDefault', visibleByDefault) setOptionalProp(noneControlDescription, 'required', required) setOptionalProp(noneControlDescription, 'defaultValue', defaultValue) return noneControlDescription }, optionalObjectKeyParser(parseString, 'label')(value), + optionalObjectKeyParser(parseString, 'folder')(value), objectKeyParser(parseConstant('none'), 'control')(value), optionalObjectKeyParser(parseBoolean, 'visibleByDefault')(value), requiredFieldParser(value), @@ -455,12 +453,13 @@ export function parseNoneControlDescription(value: unknown): ParseResult { - return applicative6Either( - (label, control, placeholder, visibleByDefault, required, defaultValue) => { + return applicative7Either( + (label, folder, control, placeholder, visibleByDefault, required, defaultValue) => { let styleControlsControlDescription: StyleControlsControlDescription = { control: control, } setOptionalProp(styleControlsControlDescription, 'label', label) + setOptionalProp(styleControlsControlDescription, 'folder', folder) setOptionalProp(styleControlsControlDescription, 'placeholder', placeholder) setOptionalProp(styleControlsControlDescription, 'visibleByDefault', visibleByDefault) setOptionalProp(styleControlsControlDescription, 'required', required) @@ -469,6 +468,7 @@ export function parseStyleControlsControlDescription( return styleControlsControlDescription }, optionalObjectKeyParser(parseString, 'label')(value), + optionalObjectKeyParser(parseString, 'folder')(value), objectKeyParser(parseConstant('style-controls'), 'control')(value), optionalObjectKeyParser(parseObject(parseAny), 'placeholder')(value), // FIXME optionalObjectKeyParser(parseBoolean, 'visibleByDefault')(value), @@ -478,13 +478,23 @@ export function parseStyleControlsControlDescription( } export function parseArrayControlDescription(value: unknown): ParseResult { - return applicative7Either( - (label, control, propertyControl, maxCount, visibleByDefault, required, defaultValue) => { + return applicative8Either( + ( + label, + folder, + control, + propertyControl, + maxCount, + visibleByDefault, + required, + defaultValue, + ) => { let arrayControlDescription: ArrayControlDescription = { control: control, propertyControl: propertyControl, } setOptionalProp(arrayControlDescription, 'label', label) + setOptionalProp(arrayControlDescription, 'folder', folder) setOptionalProp(arrayControlDescription, 'maxCount', maxCount) setOptionalProp(arrayControlDescription, 'visibleByDefault', visibleByDefault) setOptionalProp(arrayControlDescription, 'required', required) @@ -493,6 +503,7 @@ export function parseArrayControlDescription(value: unknown): ParseResult { - return applicative6Either( - (label, control, propertyControls, visibleByDefault, required, defaultValue) => { + return applicative7Either( + (label, folder, control, propertyControls, visibleByDefault, required, defaultValue) => { let tupleControlDescription: TupleControlDescription = { control: control, propertyControls: propertyControls, } setOptionalProp(tupleControlDescription, 'label', label) + setOptionalProp(tupleControlDescription, 'folder', folder) setOptionalProp(tupleControlDescription, 'visibleByDefault', visibleByDefault) setOptionalProp(tupleControlDescription, 'required', required) setOptionalProp(tupleControlDescription, 'defaultValue', defaultValue) @@ -517,6 +529,7 @@ export function parseTupleControlDescription(value: unknown): ParseResult { - return applicative6Either( - (label, control, object, visibleByDefault, required, defaultValue) => { + return applicative7Either( + (label, folder, control, object, visibleByDefault, required, defaultValue) => { let objectControlDescription: ObjectControlDescription = { control: control, object: object, } setOptionalProp(objectControlDescription, 'label', label) + setOptionalProp(objectControlDescription, 'folder', folder) setOptionalProp(objectControlDescription, 'visibleByDefault', visibleByDefault) setOptionalProp(objectControlDescription, 'required', required) setOptionalProp(objectControlDescription, 'defaultValue', defaultValue) @@ -542,6 +556,7 @@ export function parseObjectControlDescription( return objectControlDescription }, optionalObjectKeyParser(parseString, 'label')(value), + optionalObjectKeyParser(parseString, 'folder')(value), objectKeyParser(parseConstant('object'), 'control')(value), objectKeyParser(parseObject(parseRegularControlDescription), 'object')(value), optionalObjectKeyParser(parseBoolean, 'visibleByDefault')(value), @@ -551,19 +566,21 @@ export function parseObjectControlDescription( } export function parseUnionControlDescription(value: unknown): ParseResult { - return applicative6Either( - (label, control, controls, visibleByDefault, required, defaultValue) => { + return applicative7Either( + (label, folder, control, controls, visibleByDefault, required, defaultValue) => { let unionControlDescription: UnionControlDescription = { control: control, controls: controls, } setOptionalProp(unionControlDescription, 'label', label) + setOptionalProp(unionControlDescription, 'folder', folder) setOptionalProp(unionControlDescription, 'visibleByDefault', visibleByDefault) setOptionalProp(unionControlDescription, 'required', required) setOptionalProp(unionControlDescription, 'defaultValue', defaultValue) return unionControlDescription }, optionalObjectKeyParser(parseString, 'label')(value), + optionalObjectKeyParser(parseString, 'folder')(value), objectKeyParser(parseConstant('union'), 'control')(value), objectKeyParser(parseArray(parseRegularControlDescription), 'controls')(value), optionalObjectKeyParser(parseBoolean, 'visibleByDefault')(value), @@ -588,12 +605,13 @@ export const parseVector2 = flatMapParser, [number, number]>( export function parseVector2ControlDescription( value: unknown, ): ParseResult { - return applicative5Either( - (label, control, visibleByDefault, required, defaultValue) => { + return applicative6Either( + (label, folder, control, visibleByDefault, required, defaultValue) => { let controlDescription: Vector2ControlDescription = { control: control, } setOptionalProp(controlDescription, 'label', label) + setOptionalProp(controlDescription, 'folder', folder) setOptionalProp(controlDescription, 'visibleByDefault', visibleByDefault) setOptionalProp(controlDescription, 'required', required) setOptionalProp(controlDescription, 'defaultValue', defaultValue) @@ -601,6 +619,7 @@ export function parseVector2ControlDescription( return controlDescription }, optionalObjectKeyParser(parseString, 'label')(value), + optionalObjectKeyParser(parseString, 'folder')(value), objectKeyParser(parseConstant('vector2'), 'control')(value), optionalObjectKeyParser(parseBoolean, 'visibleByDefault')(value), requiredFieldParser(value), @@ -624,12 +643,13 @@ export const parseVector3 = flatMapParser, [number, number, number export function parseVector3ControlDescription( value: unknown, ): ParseResult { - return applicative5Either( - (label, control, visibleByDefault, required, defaultValue) => { + return applicative6Either( + (label, folder, control, visibleByDefault, required, defaultValue) => { let controlDescription: Vector3ControlDescription = { control: control, } setOptionalProp(controlDescription, 'label', label) + setOptionalProp(controlDescription, 'folder', folder) setOptionalProp(controlDescription, 'visibleByDefault', visibleByDefault) setOptionalProp(controlDescription, 'required', required) setOptionalProp(controlDescription, 'defaultValue', defaultValue) @@ -637,6 +657,7 @@ export function parseVector3ControlDescription( return controlDescription }, optionalObjectKeyParser(parseString, 'label')(value), + optionalObjectKeyParser(parseString, 'folder')(value), objectKeyParser(parseConstant('vector3'), 'control')(value), optionalObjectKeyParser(parseBoolean, 'visibleByDefault')(value), requiredFieldParser(value), @@ -660,12 +681,13 @@ export const parseVector4 = flatMapParser, [number, number, number export function parseVector4ControlDescription( value: unknown, ): ParseResult { - return applicative5Either( - (label, control, visibleByDefault, required, defaultValue) => { + return applicative6Either( + (label, folder, control, visibleByDefault, required, defaultValue) => { let controlDescription: Vector4ControlDescription = { control: control, } setOptionalProp(controlDescription, 'label', label) + setOptionalProp(controlDescription, 'folder', folder) setOptionalProp(controlDescription, 'visibleByDefault', visibleByDefault) setOptionalProp(controlDescription, 'required', required) setOptionalProp(controlDescription, 'defaultValue', defaultValue) @@ -673,6 +695,7 @@ export function parseVector4ControlDescription( return controlDescription }, optionalObjectKeyParser(parseString, 'label')(value), + optionalObjectKeyParser(parseString, 'folder')(value), objectKeyParser(parseConstant('vector4'), 'control')(value), optionalObjectKeyParser(parseBoolean, 'visibleByDefault')(value), requiredFieldParser(value), @@ -704,12 +727,13 @@ export const parseEuler = flatMapParser, [number, number, number, ) export function parseEulerControlDescription(value: unknown): ParseResult { - return applicative5Either( - (label, control, visibleByDefault, required, defaultValue) => { + return applicative6Either( + (label, folder, control, visibleByDefault, required, defaultValue) => { let controlDescription: EulerControlDescription = { control: control, } setOptionalProp(controlDescription, 'label', label) + setOptionalProp(controlDescription, 'folder', folder) setOptionalProp(controlDescription, 'visibleByDefault', visibleByDefault) setOptionalProp(controlDescription, 'required', required) setOptionalProp(controlDescription, 'defaultValue', defaultValue) @@ -717,6 +741,7 @@ export function parseEulerControlDescription(value: unknown): ParseResult, Matrix3>( export function parseMatrix3ControlDescription( value: unknown, ): ParseResult { - return applicative5Either( - (label, control, visibleByDefault, required, defaultValue) => { + return applicative6Either( + (label, folder, control, visibleByDefault, required, defaultValue) => { let controlDescription: Matrix3ControlDescription = { control: control, } setOptionalProp(controlDescription, 'label', label) + setOptionalProp(controlDescription, 'folder', folder) setOptionalProp(controlDescription, 'visibleByDefault', visibleByDefault) setOptionalProp(controlDescription, 'required', required) setOptionalProp(controlDescription, 'defaultValue', defaultValue) @@ -753,6 +779,7 @@ export function parseMatrix3ControlDescription( return controlDescription }, optionalObjectKeyParser(parseString, 'label')(value), + optionalObjectKeyParser(parseString, 'folder')(value), objectKeyParser(parseConstant('matrix3'), 'control')(value), optionalObjectKeyParser(parseBoolean, 'visibleByDefault')(value), requiredFieldParser(value), @@ -776,12 +803,13 @@ export const parseMatrix4 = flatMapParser, Matrix4>( export function parseMatrix4ControlDescription( value: unknown, ): ParseResult { - return applicative5Either( - (label, control, visibleByDefault, required, defaultValue) => { + return applicative6Either( + (label, folder, control, visibleByDefault, required, defaultValue) => { let controlDescription: Matrix4ControlDescription = { control: control, } setOptionalProp(controlDescription, 'label', label) + setOptionalProp(controlDescription, 'folder', folder) setOptionalProp(controlDescription, 'visibleByDefault', visibleByDefault) setOptionalProp(controlDescription, 'required', required) setOptionalProp(controlDescription, 'defaultValue', defaultValue) @@ -789,6 +817,7 @@ export function parseMatrix4ControlDescription( return controlDescription }, optionalObjectKeyParser(parseString, 'label')(value), + optionalObjectKeyParser(parseString, 'folder')(value), objectKeyParser(parseConstant('matrix4'), 'control')(value), optionalObjectKeyParser(parseBoolean, 'visibleByDefault')(value), requiredFieldParser(value), @@ -796,55 +825,14 @@ export function parseMatrix4ControlDescription( ) } -export function parseFolderControlDescription( - value: unknown, -): ParseResult { - // Results in parse errors within individual property names. - const propertiesResult = objectKeyParser((v) => parsePropertyControls(v), 'controls')(value) - // Flatten out the errors within each property. - const parsedControlDescriptions: ParseResult = flatMapEither( - (parsedControlResults) => { - let workingResult: PropertyControls = {} - for (const propertyName of Object.keys(parsedControlResults)) { - const propertyResult = parsedControlResults[propertyName] - if (isLeft(propertyResult)) { - return left( - objectFieldParseError( - 'controls', - objectFieldParseError(propertyName, propertyResult.value), - ), - ) - } else { - workingResult[propertyName] = propertyResult.value - } - } - return right(workingResult) - }, - propertiesResult, - ) - // Create the result on a success. - return applicative3Either( - (label, control, properties) => { - let controlDescription: FolderControlDescription = { - control: control, - controls: properties, - } - setOptionalProp(controlDescription, 'label', label) - return controlDescription - }, - optionalObjectKeyParser(parseString, 'label')(value), - objectKeyParser(parseConstant<'folder'>('folder'), 'control')(value), - parsedControlDescriptions, - ) -} - export function parseJSXControlDescription(value: unknown): ParseResult { - return applicative6Either( - (label, control, visibleByDefault, preferredContents, required, defaultValue) => { + return applicative7Either( + (label, folder, control, visibleByDefault, preferredContents, required, defaultValue) => { let jsxControlDescription: JSXControlDescription = { control: control, } setOptionalProp(jsxControlDescription, 'label', label) + setOptionalProp(jsxControlDescription, 'folder', folder) setOptionalProp(jsxControlDescription, 'visibleByDefault', visibleByDefault) setOptionalProp(jsxControlDescription, 'preferredContents', preferredContents) setOptionalProp(jsxControlDescription, 'required', required) @@ -853,6 +841,7 @@ export function parseJSXControlDescription(value: unknown): ParseResult { if (typeof value === 'object' && !Array.isArray(value) && value != null) { - switch ((value as any)['control']) { - case 'folder': - return parseFolderControlDescription(value) - default: - return parseRegularControlDescription(value) - } + return parseRegularControlDescription(value) } else { return left(descriptionParseError('Not an object.')) } diff --git a/utopia-api/src/property-controls/factories.ts b/utopia-api/src/property-controls/factories.ts index ddd3c85ff4d1..2cc0b493dde4 100644 --- a/utopia-api/src/property-controls/factories.ts +++ b/utopia-api/src/property-controls/factories.ts @@ -10,7 +10,6 @@ import type { ExpressionControlOption, ExpressionInputControlDescription, ExpressionPopUpListControlDescription, - FolderControlDescription, HtmlInputControlDescription, ImportType, JSXControlDescription, @@ -383,13 +382,6 @@ export function unionControl( return result } -export function folderControl(controls: PropertyControls): FolderControlDescription { - return { - control: 'folder', - controls: controls, - } -} - function mutateControlWithOptions>( control: U, options?: PropertyControlsOptions, diff --git a/utopia-api/src/property-controls/property-controls.ts b/utopia-api/src/property-controls/property-controls.ts index c1d411b61b02..cb1a93e40933 100644 --- a/utopia-api/src/property-controls/property-controls.ts +++ b/utopia-api/src/property-controls/property-controls.ts @@ -9,6 +9,7 @@ interface ControlBaseFields { visibleByDefault?: boolean required?: boolean defaultValue?: unknown + folder?: string } // Base Level Controls @@ -41,6 +42,7 @@ export interface CheckboxControlDescription { enabledTitle?: string required?: boolean defaultValue?: unknown + folder?: string } export interface ColorControlDescription { @@ -49,6 +51,7 @@ export interface ColorControlDescription { visibleByDefault?: boolean required?: boolean defaultValue?: unknown + folder?: string } export type AllowedEnumType = string | boolean | number | undefined | null @@ -66,6 +69,7 @@ export interface PopUpListControlDescription { options: BasicControlOptions required?: boolean defaultValue?: AllowedEnumType | BasicControlOption + folder?: string } export interface ImportType { @@ -88,6 +92,7 @@ export interface ExpressionPopUpListControlDescription { options: ExpressionControlOption[] required?: boolean defaultValue?: unknown + folder?: string } export interface EulerControlDescription { @@ -96,6 +101,7 @@ export interface EulerControlDescription { visibleByDefault?: boolean required?: boolean defaultValue?: [number, number, number, string] + folder?: string } export interface NoneControlDescription { @@ -104,6 +110,7 @@ export interface NoneControlDescription { visibleByDefault?: boolean required?: boolean defaultValue?: unknown + folder?: string } // prettier-ignore @@ -119,6 +126,7 @@ export interface Matrix3ControlDescription { visibleByDefault?: boolean required?: boolean defaultValue?: Matrix3 + folder?: string } // prettier-ignore @@ -135,6 +143,7 @@ export interface Matrix4ControlDescription { visibleByDefault?: boolean required?: boolean defaultValue?: Matrix4 + folder?: string } export interface NumberInputControlDescription { @@ -148,6 +157,7 @@ export interface NumberInputControlDescription { displayStepper?: boolean required?: boolean defaultValue?: unknown + folder?: string } export interface RadioControlDescription { @@ -157,6 +167,7 @@ export interface RadioControlDescription { options: BasicControlOptions required?: boolean defaultValue?: AllowedEnumType | BasicControlOption + folder?: string } export interface ExpressionInputControlDescription { @@ -165,6 +176,7 @@ export interface ExpressionInputControlDescription { visibleByDefault?: boolean required?: boolean defaultValue?: unknown + folder?: string } export interface StringInputControlDescription { @@ -175,6 +187,7 @@ export interface StringInputControlDescription { obscured?: boolean required?: boolean defaultValue?: unknown + folder?: string } export interface HtmlInputControlDescription { @@ -185,6 +198,7 @@ export interface HtmlInputControlDescription { obscured?: boolean required?: boolean defaultValue?: unknown + folder?: string } export interface StyleControlsControlDescription { @@ -194,6 +208,7 @@ export interface StyleControlsControlDescription { placeholder?: CSSProperties required?: boolean defaultValue?: unknown + folder?: string } export type Vector2 = [number, number] @@ -204,6 +219,7 @@ export interface Vector2ControlDescription { visibleByDefault?: boolean required?: boolean defaultValue?: Vector2 + folder?: string } export type Vector3 = [number, number, number] @@ -214,6 +230,7 @@ export interface Vector3ControlDescription { visibleByDefault?: boolean required?: boolean defaultValue?: Vector3 + folder?: string } export type Vector4 = [number, number, number, number] @@ -224,6 +241,7 @@ export interface Vector4ControlDescription { visibleByDefault?: boolean required?: boolean defaultValue?: Vector4 + folder?: string } export interface JSXControlDescription { @@ -233,6 +251,7 @@ export interface JSXControlDescription { preferredContents?: PreferredContents | PreferredContents[] required?: boolean defaultValue?: unknown + folder?: string } export type BaseControlDescription = @@ -271,6 +290,7 @@ export interface ArrayControlDescription { maxCount?: number required?: boolean defaultValue?: unknown + folder?: string } export interface ObjectControlDescription { @@ -280,6 +300,7 @@ export interface ObjectControlDescription { object: { [prop: string]: RegularControlDescription } required?: boolean defaultValue?: unknown + folder?: string } export interface UnionControlDescription { @@ -289,6 +310,7 @@ export interface UnionControlDescription { controls: Array required?: boolean defaultValue?: unknown + folder?: string } export interface TupleControlDescription { control: 'tuple' @@ -297,12 +319,7 @@ export interface TupleControlDescription { propertyControls: RegularControlDescription[] required?: boolean defaultValue?: unknown -} - -export interface FolderControlDescription { - control: 'folder' - label?: string - controls: PropertyControls + folder?: string } export type HigherLevelControlDescription = @@ -315,7 +332,7 @@ export type RegularControlDescription = BaseControlDescription | HigherLevelCont // Please ensure that `property-controls-utils.ts` is kept up to date // with any changes to this or the component types. -export type ControlDescription = RegularControlDescription | FolderControlDescription +export type ControlDescription = RegularControlDescription export function isBaseControlDescription( control: ControlDescription, @@ -344,7 +361,6 @@ export function isBaseControlDescription( case 'object': case 'tuple': case 'union': - case 'folder': return false default: const _exhaustiveCheck: never = control