Merged PR 204: Implement Properties' categories

This commit is contained in:
Eric Nguyen 2022-10-03 13:58:45 +00:00
parent fa3246b725
commit 34c00d267c
4 changed files with 365 additions and 257 deletions

View file

@ -4,25 +4,29 @@ import { ICategory } from '../../Interfaces/ICategory';
import { TruncateString } from '../../utils/stringtools'; import { TruncateString } from '../../utils/stringtools';
interface ICategoryProps { interface ICategoryProps {
children: JSX.Element[] heightClass?: string
children?: JSX.Element[] | JSX.Element
category: ICategory category: ICategory
defaultIsOpen?: boolean
} }
export function Category(props: ICategoryProps): JSX.Element { export function Category(props: ICategoryProps): JSX.Element {
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(props.defaultIsOpen ?? false);
const categoryType: string = props.category.Type; const categoryType: string = props.category.Type;
const categoryDisplayedText: string = props.category.DisplayedText ?? categoryType; const categoryDisplayedText: string = props.category.DisplayedText ?? categoryType;
const heightClass = props.heightClass ?? 'h-16';
return ( return (
<div <div
className={` transition-all text-center ${isOpen ? 'overflow-hidden h-full' : 'overflow-visible h-16'}`} className={` transition-all text-center ${isOpen ? 'overflow-hidden h-full' : `overflow-visible ${heightClass}`}`}
key={categoryType} key={categoryType}
id={categoryType} id={categoryType}
title={categoryDisplayedText} title={categoryDisplayedText}
> >
<div <div
className={'flex flex-row group h-16 cursor-pointer'} className={`flex flex-row group cursor-pointer ${heightClass}`}
onClick={() => setIsOpen(!isOpen)} onClick={() => setIsOpen(!isOpen)}
> >
<span className={`transition-all flex-1 h-full justify-center sidebar-component-left ${isOpen ? 'rounded-b-none bg-slate-400/80 group-hover:bg-blue-600' : ''}`}> <span className={`transition-all flex-1 h-full justify-center sidebar-component-left ${isOpen ? 'rounded-b-none bg-slate-400/80 group-hover:bg-blue-600' : ''}`}>

View file

@ -12,6 +12,7 @@ import { PositionReferenceSelector } from '../RadioGroupButtons/PositionReferenc
import { OrientationSelector } from '../RadioGroupButtons/OrientationSelector'; import { OrientationSelector } from '../RadioGroupButtons/OrientationSelector';
import { OrientationCheckboxes } from '../CheckboxGroupButtons/OrientationCheckboxes'; import { OrientationCheckboxes } from '../CheckboxGroupButtons/OrientationCheckboxes';
import { PositionCheckboxes } from '../CheckboxGroupButtons/PositionCheckboxes'; import { PositionCheckboxes } from '../CheckboxGroupButtons/PositionCheckboxes';
import { Category } from '../Category/Category';
interface IContainerFormProps { interface IContainerFormProps {
properties: IContainerProperties properties: IContainerProperties
@ -28,8 +29,8 @@ function GetCSSInputs(properties: IContainerProperties,
id={key} id={key}
labelText={key} labelText={key}
inputKey={key} inputKey={key}
labelClassName='' labelClassName='col-span-2'
inputClassName='' inputClassName='col-span-3'
type='string' type='string'
value={(properties.style as any)[key]} value={(properties.style as any)[key]}
onChange={(value) => onChange(key, value, PropertyType.Style)} />); onChange={(value) => onChange(key, value, PropertyType.Style)} />);
@ -38,32 +39,9 @@ function GetCSSInputs(properties: IContainerProperties,
} }
export function ContainerForm(props: IContainerFormProps): JSX.Element { export function ContainerForm(props: IContainerFormProps): JSX.Element {
const categoryHeight = 'h-11';
return ( return (
<div className='grid grid-cols-1 md:grid-cols-2 gap-y-6 items-center'> <div className='grid grid-cols-1 gap-y-4 items-center'>
<InputGroup
labelText='Name'
inputKey='id'
labelClassName=''
inputClassName=''
type='string'
value={props.properties.id.toString()}
isDisabled={true} />
<InputGroup
labelText='Parent name'
inputKey='parentId'
labelClassName=''
inputClassName=''
type='string'
value={props.properties.parentId}
isDisabled={true} />
<InputGroup
labelText='Type'
inputKey='type'
labelClassName=''
inputClassName=''
type='string'
value={props.properties.type}
isDisabled={true} />
<TextInputGroup <TextInputGroup
id={`${props.properties.id}-displayedText`} id={`${props.properties.id}-displayedText`}
labelText='Displayed text' labelText='Displayed text'
@ -80,234 +58,356 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element {
value={props.properties.orientation} value={props.properties.orientation}
onChange={props.onChange} onChange={props.onChange}
/> />
<TextInputGroup
id={`${props.properties.id}-x`} <Category
labelText='x' category={{
inputKey='x' Type: 'Properties',
labelClassName='' DisplayedText: 'Properties'
inputClassName='' }}
type='number' heightClass={`${categoryHeight}`}
isDisabled={props.properties.linkedSymbolId !== ''} >
value={TransformX( <div className='grid grid-cols-1 gap-y-6 items-center prop-category-body'>
RemoveXMargin(props.properties.x, props.properties.margin.left), <div>
props.properties.width, <InputGroup
props.properties.positionReference labelText='Name'
).toString()} inputKey='id'
onChange={(value) => props.onChange( labelClassName=''
'x', inputClassName=''
ApplyXMargin( type='string'
RestoreX( value={props.properties.id.toString()}
Number(value), isDisabled={true} />
</div>
<div>
<InputGroup
labelText='Parent name'
inputKey='parentId'
labelClassName=''
inputClassName=''
type='string'
value={props.properties.parentId}
isDisabled={true} />
</div>
<div>
<InputGroup
labelText='Type'
inputKey='type'
labelClassName=''
inputClassName=''
type='string'
value={props.properties.type}
isDisabled={true} />
</div>
</div>
</Category>
<Category category={{
Type: 'Position',
DisplayedText: 'Position'
}}
defaultIsOpen={true}
heightClass={`${categoryHeight}`}
>
<div className='grid grid-cols-3 gap-y-2 items-center prop-category-body'>
<TextInputGroup
id={`${props.properties.id}-x`}
labelText='x'
inputKey='x'
labelClassName=''
inputClassName='col-span-2'
type='number'
isDisabled={props.properties.linkedSymbolId !== ''}
value={TransformX(
RemoveXMargin(props.properties.x, props.properties.margin.left),
props.properties.width, props.properties.width,
props.properties.positionReference props.properties.positionReference
), ).toString()}
props.properties.margin.left onChange={(value) => props.onChange(
) 'x',
)} /> ApplyXMargin(
<TextInputGroup RestoreX(
id={`${props.properties.id}-y`} Number(value),
labelText='y' props.properties.width,
inputKey='y' props.properties.positionReference
labelClassName='' ),
inputClassName='' props.properties.margin.left
type='number' )
value={TransformY( )} />
RemoveXMargin(props.properties.y, props.properties.margin.top), <TextInputGroup
props.properties.height, id={`${props.properties.id}-y`}
props.properties.positionReference labelText='y'
).toString()} inputKey='y'
onChange={(value) => props.onChange( labelClassName=''
'y', inputClassName='col-span-2'
ApplyXMargin( type='number'
RestoreY( value={TransformY(
Number(value), RemoveXMargin(props.properties.y, props.properties.margin.top),
props.properties.height, props.properties.height,
props.properties.positionReference props.properties.positionReference
), ).toString()}
props.properties.margin.top onChange={(value) => props.onChange(
) 'y',
)} /> ApplyXMargin(
<TextInputGroup RestoreY(
id={`${props.properties.id}-minWidth`} Number(value),
labelText='Minimum Width' props.properties.height,
inputKey='minWidth' props.properties.positionReference
labelClassName='' ),
inputClassName='' props.properties.margin.top
type='number' )
min={1} )} />
value={props.properties.minWidth.toString()} </div>
onChange={(value) => props.onChange('minWidth', Number(value))} /> </Category>
<TextInputGroup
id={`${props.properties.id}-maxWidth`} <Category category={{
labelText='Maximum Width' Type: 'Size',
inputKey='maxWidth' DisplayedText: 'Size'
labelClassName='' }}
inputClassName='' heightClass={`${categoryHeight}`}
type='number' >
min={1} <div className='grid grid-cols-5 gap-y-2 items-center prop-category-body'>
value={props.properties.maxWidth.toString()} <TextInputGroup
onChange={(value) => props.onChange('maxWidth', Number(value))} /> id={`${props.properties.id}-minWidth`}
<TextInputGroup labelText='Minimum Width'
id={`${props.properties.id}-width`} inputKey='minWidth'
labelText='Width' labelClassName='col-span-2'
inputKey='width' inputClassName='col-span-3'
labelClassName='' type='number'
inputClassName='' min={1}
type='number' value={props.properties.minWidth.toString()}
min={props.properties.minWidth} onChange={(value) => props.onChange('minWidth', Number(value))} />
max={props.properties.maxWidth} <TextInputGroup
value={(RemoveWidthMargin(props.properties.width, props.properties.margin.left, props.properties.margin.right)).toString()} id={`${props.properties.id}-width`}
onChange={(value) => props.onChange('width', ApplyWidthMargin(Number(value), props.properties.margin.left, props.properties.margin.right))} labelText='Width'
isDisabled={props.properties.isFlex} /> inputKey='width'
<TextInputGroup labelClassName='col-span-2'
id={`${props.properties.id}-minHeight`} inputClassName='col-span-3'
labelText='Minimum Height' type='number'
inputKey='minHeight' min={props.properties.minWidth}
labelClassName='' max={props.properties.maxWidth}
inputClassName='' value={(RemoveWidthMargin(props.properties.width, props.properties.margin.left, props.properties.margin.right)).toString()}
type='number' onChange={(value) => props.onChange('width', ApplyWidthMargin(Number(value), props.properties.margin.left, props.properties.margin.right))}
min={1} isDisabled={props.properties.isFlex} />
value={props.properties.minHeight.toString()} <TextInputGroup
onChange={(value) => props.onChange('minHeight', Number(value))} /> id={`${props.properties.id}-maxWidth`}
<TextInputGroup labelText='Maximum Width'
id={`${props.properties.id}-maxHeight`} inputKey='maxWidth'
labelText='Maximum Height' labelClassName='col-span-2'
inputKey='maxHeight' inputClassName='col-span-3'
labelClassName='' type='number'
inputClassName='' min={1}
type='number' value={props.properties.maxWidth.toString()}
min={1} onChange={(value) => props.onChange('maxWidth', Number(value))} />
value={props.properties.maxHeight.toString()} <div className='col-span-5 p-3'></div>
onChange={(value) => props.onChange('maxHeight', Number(value))} /> <TextInputGroup
<TextInputGroup id={`${props.properties.id}-minHeight`}
id={`${props.properties.id}-height`} labelText='Minimum Height'
labelText='Height' inputKey='minHeight'
inputKey='height' labelClassName='col-span-2'
labelClassName='' inputClassName='col-span-3'
inputClassName='' type='number'
type='number' min={1}
min={props.properties.minHeight} value={props.properties.minHeight.toString()}
max={props.properties.maxHeight} onChange={(value) => props.onChange('minHeight', Number(value))} />
value={(RemoveWidthMargin(props.properties.height, props.properties.margin.top, props.properties.margin.bottom)).toString()} <TextInputGroup
onChange={(value) => props.onChange('height', ApplyWidthMargin(Number(value), props.properties.margin.top, props.properties.margin.bottom))} id={`${props.properties.id}-height`}
isDisabled={props.properties.isFlex} labelText='Height'
/> inputKey='height'
<TextInputGroup labelClassName='col-span-2'
id={`${props.properties.id}-ml`} inputClassName='col-span-3'
labelText='Margin left' type='number'
inputKey='left' min={props.properties.minHeight}
labelClassName='' max={props.properties.maxHeight}
inputClassName='' value={(RemoveWidthMargin(props.properties.height, props.properties.margin.top, props.properties.margin.bottom)).toString()}
type='number' onChange={(value) => props.onChange('height', ApplyWidthMargin(Number(value), props.properties.margin.top, props.properties.margin.bottom))}
min={0} isDisabled={props.properties.isFlex}
value={(props.properties.margin.left ?? 0).toString()} />
onChange={(value) => props.onChange('left', Number(value), PropertyType.Margin)} /> <TextInputGroup
<TextInputGroup id={`${props.properties.id}-maxHeight`}
id={`${props.properties.id}-mb`} labelText='Maximum Height'
labelText='Margin bottom' inputKey='maxHeight'
inputKey='bottom' labelClassName='col-span-2'
labelClassName='' inputClassName='col-span-3'
inputClassName='' type='number'
type='number' min={1}
min={0} value={props.properties.maxHeight.toString()}
value={(props.properties.margin.bottom ?? 0).toString()} onChange={(value) => props.onChange('maxHeight', Number(value))} />
onChange={(value) => props.onChange('bottom', Number(value), PropertyType.Margin)} /> </div>
<TextInputGroup </Category>
id={`${props.properties.id}-mt`}
labelText='Margin top' <Category category={{
inputKey='top' Type: 'Margins',
labelClassName='' DisplayedText: 'Margins'
inputClassName='' }}
type='number' heightClass={`${categoryHeight}`}
min={0} >
value={(props.properties.margin.top ?? 0).toString()} <div className='grid grid-cols-2 items-center gap-y-2 prop-category-body'>
onChange={(value) => props.onChange('top', Number(value), PropertyType.Margin)} /> <TextInputGroup
<TextInputGroup id={`${props.properties.id}-ml`}
id={`${props.properties.id}-mr`} labelText='Margin left'
labelText='Margin right' inputKey='left'
inputKey='right' labelClassName=''
labelClassName='' inputClassName=''
inputClassName='' type='number'
type='number' min={0}
min={0} value={(props.properties.margin.left ?? 0).toString()}
value={(props.properties.margin.right ?? 0).toString()} onChange={(value) => props.onChange('left', Number(value), PropertyType.Margin)} />
onChange={(value) => props.onChange('right', Number(value), PropertyType.Margin)} /> <TextInputGroup
<ToggleButton id={`${props.properties.id}-mb`}
labelText='Flex' labelText='Margin bottom'
inputKey='isFlex' inputKey='bottom'
labelClassName='' labelClassName=''
inputClassName='' inputClassName=''
type={ToggleType.Full} type='number'
checked={props.properties.isFlex} min={0}
onChange={(event) => props.onChange('isFlex', event.target.checked)} value={(props.properties.margin.bottom ?? 0).toString()}
/> onChange={(value) => props.onChange('bottom', Number(value), PropertyType.Margin)} />
<ToggleButton <TextInputGroup
labelText='Anchor' id={`${props.properties.id}-mt`}
inputKey='isAnchor' labelText='Margin top'
labelClassName='' inputKey='top'
inputClassName='' labelClassName=''
type={ToggleType.Full} inputClassName=''
checked={props.properties.isAnchor} type='number'
onChange={(event) => props.onChange('isAnchor', event.target.checked)} /> min={0}
<PositionReferenceSelector value={(props.properties.margin.top ?? 0).toString()}
id='positionReference' onChange={(value) => props.onChange('top', Number(value), PropertyType.Margin)} />
name='PositionReference' <TextInputGroup
labelText='Alignment' id={`${props.properties.id}-mr`}
value={props.properties.positionReference} labelText='Margin right'
onChange={props.onChange} inputKey='right'
/> labelClassName=''
<Select inputClassName=''
inputKey='linkedSymbolId' type='number'
labelText='Align with symbol' min={0}
labelClassName='' value={(props.properties.margin.right ?? 0).toString()}
inputClassName='' onChange={(value) => props.onChange('right', Number(value), PropertyType.Margin)} />
inputs={[...props.symbols.values()].map(symbol => ({ </div>
key: symbol.id, </Category>
text: symbol.id,
value: symbol.id <Category category={{
}))} Type: 'Behaviors',
value={props.properties.linkedSymbolId ?? ''} DisplayedText: 'Behaviors'
onChange={(event) => props.onChange('linkedSymbolId', event.target.value)} /> }}
{GetCSSInputs(props.properties, props.onChange)} heightClass={`${categoryHeight}`}
{ >
SHOW_SELF_DIMENSIONS && <div className='grid grid-cols-2 items-center gap-y-2 prop-category-body'>
<PositionCheckboxes <ToggleButton
id='showSelfDimensions' labelText='Flex'
name='ShowSelfDimensions' inputKey='isFlex'
labelText='Show dimension' labelClassName=''
value={props.properties.showSelfDimensions} inputClassName='ml-auto mr-auto block'
onChange={props.onChange} type={ToggleType.Full}
/> checked={props.properties.isFlex}
} onChange={(event) => props.onChange('isFlex', event.target.checked)}
{ />
SHOW_CHILDREN_DIMENSIONS && <ToggleButton
<PositionCheckboxes labelText='Anchor'
id='showChildrenDimensions' inputKey='isAnchor'
name='ShowChildrenDimensions' labelClassName=''
labelText='Show overall dimension of its children' inputClassName='ml-auto mr-auto block'
value={props.properties.showChildrenDimensions} type={ToggleType.Full}
onChange={props.onChange} checked={props.properties.isAnchor}
/> onChange={(event) => props.onChange('isAnchor', event.target.checked)} />
} </div>
{ </Category>
SHOW_BORROWER_DIMENSIONS &&
<> <Category category={{
<OrientationCheckboxes Type: 'Alignment',
id='markPosition' DisplayedText: 'Alignment'
name='MarkPosition' }}
value={props.properties.markPosition} heightClass={`${categoryHeight}`}
labelText='Mark the position' >
onChange={props.onChange} <div className='prop-category-body'>
/> <PositionReferenceSelector
<PositionCheckboxes id='positionReference'
id='showDimensionWithMarks' name='PositionReference'
name='ShowDimensionWithMarks' labelText='Alignment'
labelText='Show dimension with marked children' value={props.properties.positionReference}
value={props.properties.showDimensionWithMarks} onChange={props.onChange}
onChange={props.onChange} />
/> <div className='p-3'></div>
</> <Select
} inputKey='linkedSymbolId'
labelText='Align with symbol'
labelClassName=''
inputClassName=''
inputs={[...props.symbols.values()].map(symbol => ({
key: symbol.id,
text: symbol.id,
value: symbol.id
}))}
value={props.properties.linkedSymbolId ?? ''}
onChange={(event) => props.onChange('linkedSymbolId', event.target.value)} />
</div>
</Category>
<Category category={{
Type: 'Dimensions',
DisplayedText: 'Dimensions'
}}
heightClass={`${categoryHeight}`}
>
<div className='grid grid-cols-1 gap-6 prop-category-body'>
{
SHOW_SELF_DIMENSIONS &&
<div className='grid grid-cols-1 gap-2'>
<PositionCheckboxes
id='showSelfDimensions'
name='ShowSelfDimensions'
labelText='Show dimension'
value={props.properties.showSelfDimensions}
onChange={props.onChange}
/>
</div>
}
{
SHOW_CHILDREN_DIMENSIONS &&
<div className='grid grid-cols-1 gap-2'>
<PositionCheckboxes
id='showChildrenDimensions'
name='ShowChildrenDimensions'
labelText='Show overall dimension of its children'
value={props.properties.showChildrenDimensions}
onChange={props.onChange}
/>
</div>
}
{
SHOW_BORROWER_DIMENSIONS &&
<>
<div className='grid grid-cols-1 gap-2'>
<OrientationCheckboxes
id='markPosition'
name='MarkPosition'
value={props.properties.markPosition}
labelText='Mark the position'
onChange={props.onChange}
/>
</div>
<div className='grid grid-cols-1 gap-2'>
<PositionCheckboxes
id='showDimensionWithMarks'
name='ShowDimensionWithMarks'
labelText='Show dimension with marked children'
value={props.properties.showDimensionWithMarks}
onChange={props.onChange}
/>
</div>
</>
}
</div>
</Category>
<Category category={{
Type: 'Style',
DisplayedText: 'Style'
}}
heightClass={`${categoryHeight}`}
>
<div className='grid grid-cols-5 gap-6 items-center prop-category-body'>
{GetCSSInputs(props.properties, props.onChange)}
</div>
</Category>
</div> </div>
); );
} }

View file

@ -35,7 +35,7 @@ export function ToggleButton(props: IToggleButtonProps): JSX.Element {
{ props.labelText } { props.labelText }
</label> </label>
<label <label
className="relative cursor-pointer" className={`relative cursor-pointer ${props.inputClassName}`}
htmlFor={props.inputKey} htmlFor={props.inputKey}
> >
<input <input

View file

@ -118,6 +118,10 @@
text-xs font-medium transition-all text-gray-800 mt-1 px-3 py-2 text-xs font-medium transition-all text-gray-800 mt-1 px-3 py-2
bg-white border-2 border-white rounded-lg placeholder-gray-800 bg-white border-2 border-white rounded-lg placeholder-gray-800
focus:outline-none focus:border-blue-500 focus:ring-1 focus:ring-blue-500 focus:outline-none focus:border-blue-500 focus:ring-1 focus:ring-blue-500
disabled:bg-slate-300 disabled:text-gray-500 disabled:border-slate-300 disabled:shadow-none; disabled:bg-slate-200 disabled:text-gray-500 disabled:border-slate-300 disabled:shadow-none;
}
.prop-category-body {
@apply rounded-lg bg-slate-300 p-3
} }
} }