Skip to content

Commit

Permalink
Support folder labels in the component API (#5651)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>

* reflatten types in utopia-api/src/helper-functions

* add folder to Matrix4ControlDescription too

---------

Co-authored-by: Federico Ruggi <[email protected]>
  • Loading branch information
bkrmendy and ruggi authored May 13, 2024
1 parent e99c9bc commit 0955622
Show file tree
Hide file tree
Showing 11 changed files with 271 additions and 379 deletions.
153 changes: 35 additions & 118 deletions editor/src/components/custom-code/internal-property-controls.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import type { CSSProperties } from 'react'
import type { ComponentInfo } from './code-file'

interface GenericControlProps<T> {
label?: string
folder?: string
visibleByDefault?: boolean
required?: boolean
defaultValue?: T
}

export type BaseControlType =
| 'checkbox'
| 'color'
Expand All @@ -21,22 +29,14 @@ export type BaseControlType =
| 'vector4'
| 'jsx'

export interface CheckboxControlDescription {
export interface CheckboxControlDescription extends GenericControlProps<unknown> {
control: 'checkbox'
label?: string
visibleByDefault?: boolean
disabledTitle?: string
enabledTitle?: string
required?: boolean
defaultValue?: unknown
}

export interface ColorControlDescription {
export interface ColorControlDescription extends GenericControlProps<unknown> {
control: 'color'
label?: string
visibleByDefault?: boolean
required?: boolean
defaultValue?: unknown
}

export type AllowedEnumType = string | boolean | number | undefined | null
Expand All @@ -48,13 +48,10 @@ export interface BasicControlOption<T> {

export type BasicControlOptions<T> = AllowedEnumType[] | BasicControlOption<T>[]

export interface PopUpListControlDescription {
export interface PopUpListControlDescription
extends GenericControlProps<AllowedEnumType | BasicControlOption<unknown>> {
control: 'popuplist'
label?: string
visibleByDefault?: boolean
options: BasicControlOptions<unknown>
required?: boolean
defaultValue?: AllowedEnumType | BasicControlOption<unknown>
}
export interface ImportType {
source: string
Expand All @@ -69,39 +66,24 @@ export interface ExpressionControlOption<T> {
requiredImport?: ImportType
}

export interface ExpressionPopUpListControlDescription {
export interface ExpressionPopUpListControlDescription extends GenericControlProps<unknown> {
control: 'expression-popuplist'
label?: string
visibleByDefault?: boolean
options: ExpressionControlOption<unknown>[]
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<unknown> {
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<Matrix3> {
control: 'matrix3'
label?: string
visibleByDefault?: boolean
required?: boolean
defaultValue?: Matrix3
}

export type Matrix4 = [
Expand All @@ -123,95 +105,57 @@ export type Matrix4 = [
number,
]

export interface Matrix4ControlDescription {
export interface Matrix4ControlDescription extends GenericControlProps<Matrix4> {
control: 'matrix4'
label?: string
visibleByDefault?: boolean
required?: boolean
defaultValue?: Matrix4
}

export interface NumberInputControlDescription {
export interface NumberInputControlDescription extends GenericControlProps<unknown> {
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<AllowedEnumType | BasicControlOption<unknown>> {
control: 'radio'
label?: string
visibleByDefault?: boolean
options: BasicControlOptions<unknown>
required?: boolean
defaultValue?: AllowedEnumType | BasicControlOption<unknown>
}

export interface ExpressionInputControlDescription {
export interface ExpressionInputControlDescription extends GenericControlProps<unknown> {
control: 'expression-input'
label?: string
visibleByDefault?: boolean
required?: boolean
defaultValue?: unknown
}

export interface StringInputControlDescription {
export interface StringInputControlDescription extends GenericControlProps<unknown> {
control: 'string-input'
label?: string
visibleByDefault?: boolean
placeholder?: string
obscured?: boolean
required?: boolean
defaultValue?: unknown
}

export interface HtmlInputControlDescription {
export interface HtmlInputControlDescription extends GenericControlProps<unknown> {
control: 'html-input'
label?: string
visibleByDefault?: boolean
placeholder?: string
obscured?: boolean
required?: boolean
defaultValue?: unknown
}

export interface StyleControlsControlDescription {
export interface StyleControlsControlDescription extends GenericControlProps<unknown> {
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 {
Expand All @@ -220,13 +164,9 @@ export interface PreferredChildComponentDescriptor {
variants: Array<ComponentInfo>
}

export interface JSXControlDescription {
export interface JSXControlDescription extends GenericControlProps<unknown> {
control: 'jsx'
label?: string
visibleByDefault?: boolean
preferredChildComponents: Array<PreferredChildComponentDescriptor>
required?: boolean
defaultValue?: unknown
}
export declare type BaseControlDescription =
| CheckboxControlDescription
Expand Down Expand Up @@ -254,49 +194,27 @@ export type RegularControlType = BaseControlType | HigherLevelControlType

export type ControlType = RegularControlType | 'folder'

export interface ArrayControlDescription {
export interface ArrayControlDescription extends GenericControlProps<unknown> {
control: 'array'
label?: string
visibleByDefault?: boolean
propertyControl: RegularControlDescription
maxCount?: number
required?: boolean
defaultValue?: unknown
}

export interface ObjectControlDescription {
export interface ObjectControlDescription extends GenericControlProps<unknown> {
control: 'object'
label?: string
visibleByDefault?: boolean
object: {
[prop: string]: RegularControlDescription
}
required?: boolean
defaultValue?: unknown
}

export interface UnionControlDescription {
export interface UnionControlDescription extends GenericControlProps<unknown> {
control: 'union'
label?: string
visibleByDefault?: boolean
controls: Array<RegularControlDescription>
required?: boolean
defaultValue?: unknown
}

export interface TupleControlDescription {
export interface TupleControlDescription extends GenericControlProps<unknown> {
control: 'tuple'
label?: string
visibleByDefault?: boolean
propertyControls: RegularControlDescription[]
required?: boolean
defaultValue?: unknown
}

export interface FolderControlDescription {
control: 'folder'
label?: string
controls: PropertyControls
}

export type HigherLevelControlDescription =
Expand All @@ -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
Expand Down Expand Up @@ -339,7 +257,6 @@ export function isBaseControlDescription(
case 'object':
case 'tuple':
case 'union':
case 'folder':
return false
default:
const _exhaustiveCheck: never = control
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand All @@ -20,39 +18,22 @@ type RowOrFolderWrapperProps = {
}

export const RowOrFolderWrapper = React.memo((props: RowOrFolderWrapperProps) => {
switch (props.controlDescription.control) {
case 'folder':
return (
<FolderSection
isRoot={false}
indentationLevel={props.indentationLevel}
propertyControls={props.controlDescription.controls}
setGlobalCursor={props.setGlobalCursor}
title={props.controlDescription.label ?? PP.toString(props.propPath)}
visibleEmptyControls={props.visibleEmptyControls}
unsetPropNames={props.unsetPropNames}
showHiddenControl={props.showHiddenControl}
detectedPropsAndValuesWithoutControls={{}}
/>
)
default:
return (
<UIGridRow
padded
tall={false}
style={{ paddingLeft: 0 }}
variant='<-------------1fr------------->'
>
<RowForControl
propPath={props.propPath}
controlDescription={props.controlDescription}
isScene={props.isScene}
setGlobalCursor={props.setGlobalCursor}
indentationLevel={props.indentationLevel}
focusOnMount={props.focusOnMount ?? false}
showHiddenControl={props.showHiddenControl}
/>
</UIGridRow>
)
}
return (
<UIGridRow
padded
tall={false}
style={{ paddingLeft: 0 }}
variant='<-------------1fr------------->'
>
<RowForControl
propPath={props.propPath}
controlDescription={props.controlDescription}
isScene={props.isScene}
setGlobalCursor={props.setGlobalCursor}
indentationLevel={props.indentationLevel}
focusOnMount={props.focusOnMount ?? false}
showHiddenControl={props.showHiddenControl}
/>
</UIGridRow>
)
})
Loading

0 comments on commit 0955622

Please sign in to comment.