Skip to content

Commit

Permalink
feat: add "add" and "remove" buttons for infinite arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
KaiVolland committed Jun 19, 2024
1 parent e84536a commit 6744581
Show file tree
Hide file tree
Showing 12 changed files with 188 additions and 104 deletions.
10 changes: 7 additions & 3 deletions src/Component/FunctionUI/CaseInput/CaseInput.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import React, { useCallback } from 'react';
import { Expression, FCaseParameter } from 'geostyler-style';
import { Input } from 'antd';
import BooleanExpressionInput from '../../ExpressionInput/BooleanExpressionInput/BooleanExpressionInput';
import './CaseInput.less';
import { Type } from '../FunctionUI';
import UnknownInput from '../UnknownInput/UnknownInput';

export type CaseInputProps = {
value?: FCaseParameter;
onChange: (newValue: FCaseParameter) => void;
type?: Type;
};

export const CaseInput: React.FC<CaseInputProps> = ({
value,
onChange
onChange,
type
}) => {

const onCaseChange = useCallback((newCase: Expression<boolean>) => {
Expand All @@ -35,7 +38,8 @@ export const CaseInput: React.FC<CaseInputProps> = ({
onCancel={() => onChange(undefined)}
value={value?.case}
/>
<Input
<UnknownInput
forcedType={type}
onChange={onValueChange}
value={value?.value as any}
/>
Expand Down
4 changes: 4 additions & 0 deletions src/Component/FunctionUI/FunctionUI.less
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@
flex: 1;
}

.remove-argument-button {
flex: unset;
}

.tree-icon {
width: 28px;
background-image: linear-gradient(grey, grey), linear-gradient(grey, grey);
Expand Down
221 changes: 127 additions & 94 deletions src/Component/FunctionUI/FunctionUI.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,11 @@ import { FunctionConfig, functionConfigs } from './functionConfigs';
import CaseInput from './CaseInput/CaseInput';
import UnknownInput from './UnknownInput/UnknownInput';
import StepInput from './StepInput/StepInput';
import { Button, Tooltip } from 'antd';
import { useGeoStylerLocale } from '../../context/GeoStylerContext/GeoStylerContext';
import { MinusOutlined, PlusOutlined } from '@ant-design/icons';

type Type = 'string' | 'number' | 'boolean' | 'unknown';
export type Type = 'string' | 'number' | 'boolean' | 'unknown';

export interface FunctionUIProps<T extends GeoStylerFunction> {
type: Type;
Expand All @@ -62,6 +65,7 @@ export const FunctionUI = <T extends GeoStylerFunction>({
onCancel
}: FunctionUIProps<T>) => {

const locale = useGeoStylerLocale('FunctionUI');
const name = value?.name;

const getKey = useCallback((key: string) => {
Expand Down Expand Up @@ -90,114 +94,124 @@ export const FunctionUI = <T extends GeoStylerFunction>({
}

const key = getKey(func.name);
let comp = (
<UnknownInput
forcedType={type}
value={functionArgs?.[index]}
onChange={(val) => {
updateFunctionArg(val, index);
}}
/>
);

if (cfg.type === 'case') {
return (
<div className='gs-function-arg' key={`${key}${index}`}>
<i className='tree-icon' />
<CaseInput
value={functionArgs?.[index]}
onChange={(val) => {
updateFunctionArg(val, index);
}}
/>
</div>
comp = (
<CaseInput
value={functionArgs?.[index]}
onChange={(val) => {
updateFunctionArg(val, index);
}}
/>
);
}
if (cfg.type === 'step') {
return (
<div className='gs-function-arg' key={`${key}${index}`}>
<i className='tree-icon' />
<StepInput
value={functionArgs?.[index]}
onChange={(val) => {
updateFunctionArg(val, index);
}}
/>
</div>
} else if (cfg.type === 'step') {
comp = (
<StepInput
type={type}
value={functionArgs?.[index]}
onChange={(val) => {
updateFunctionArg(val, index);
}}
/>
);
}
if (cfg.type === 'unknown') {
return (
<div className='gs-function-arg' key={`${key}${index}`}>
<i className='tree-icon' /><UnknownInput
value={functionArgs?.[index]}
onChange={(val) => {
updateFunctionArg(val, index);
}}
/>
</div>
} else if (cfg.type === 'unknown') {
comp = (
<UnknownInput
forcedType={type}
value={functionArgs?.[index]}
onChange={(val) => {
updateFunctionArg(val, index);
}}
/>
);
}

if (isGeoStylerFunction(functionArgs?.[index])) {
return (
<div className='gs-function-arg' key={`${key}${index}`}>
<i className='tree-icon' />
<FunctionUI
type={cfg.type}
value={functionArgs[index]}
parentKey={key+''+index}
onChange={(val) => {
updateFunctionArg(val, index);
}}
onCancel={t => {
updateFunctionArg(undefined, index);
}}
/>
</div>
} else if (isGeoStylerFunction(functionArgs?.[index])) {
comp = (
<FunctionUI
type={cfg.type}
value={functionArgs[index]}
parentKey={key+''+index}
onChange={(val) => {
updateFunctionArg(val, index);
}}
onCancel={t => {
updateFunctionArg(undefined, index);
}}
/>
);
} else if (cfg.type === 'number') {
return (
<div className='gs-function-arg' key={`${key}${index}`}>
<i className='tree-icon' />
<NumberExpressionInput
value={functionArgs?.[index]}
onChange={(val) => {
updateFunctionArg(val, index);
}}
inputProps={{
placeholder: cfg.placeholder
}}
/>
</div>
comp = (
<NumberExpressionInput
value={functionArgs?.[index]}
onChange={(val) => {
updateFunctionArg(val, index);
}}
inputProps={{
placeholder: cfg.placeholder
}}
/>
);
} else if (cfg.type === 'string') {
return (
<div className='gs-function-arg' key={`${key}${index}`}>
<i className='tree-icon' />
<StringExpressionInput
value={functionArgs?.[index]}
onChange={(val) => {
updateFunctionArg(val, index);
}}
inputProps={{
placeholder: cfg.placeholder
}}
/>
</div>
comp = (
<StringExpressionInput
value={functionArgs?.[index]}
onChange={(val) => {
updateFunctionArg(val, index);
}}
inputProps={{
placeholder: cfg.placeholder
}}
/>
);
} else if (cfg.type === 'boolean') {
return (
<div className='gs-function-arg' key={`${key}${index}`}>
<i className='tree-icon' />
<BooleanExpressionInput
value={functionArgs?.[index]}
onChange={(val) => {
updateFunctionArg(val, index);
}}
labelOn={cfg.label}
labelOff={cfg.label}
/>
</div>
comp = (
<BooleanExpressionInput
value={functionArgs?.[index]}
onChange={(val) => {
updateFunctionArg(val, index);
}}
labelOn={cfg.label}
labelOff={cfg.label}
/>
);
}

return (
<div className='gs-function-arg' key={`${key}${index}`}>
{functionArgs?.[index]?.toString()}
<i className='tree-icon' />
{comp}
{
cfg.infinite &&
<Tooltip title={locale.remove}>
<Button
type="text"
className="remove-argument-button"
icon={<MinusOutlined />}
onClick={() => {
if (value.name === 'pi' || value.name === 'random') {
return;
}
const newArgs = structuredClone(value.args);
newArgs.splice(index, 1);
onChange?.({
...value,
args: newArgs
});
}}
/>
</Tooltip>
}
</div>
);
}, [getKey, updateFunctionArg]);
}, [getKey, updateFunctionArg, type, locale, onChange, value]);

const getUiForFunction = useCallback((func: GeoStylerFunction) => {
const config = functionConfigs.find(cfg => cfg.name === func.name);
Expand All @@ -216,7 +230,26 @@ export const FunctionUI = <T extends GeoStylerFunction>({
for (let i = 0; i < amountOfInfiniteArgs; i++) {
argUIs.push(getUiForArg(arg, index + i, func));
}
// TODO: add an "add" button to add more infinite args
argUIs.push(
<div className='gs-function-arg' key={`remove-argument-${index}`}>
<i className='tree-icon' />
<Tooltip title={locale.add}>
<Button
icon={<PlusOutlined />}
onClick={() => {
const clonedArg = structuredClone(value.args[value.args.length - 1]);
onChange({
...value,
args: [
...value.args,
clonedArg
]
});
}}
/>
</Tooltip>
</div>
);
}
});
} else {
Expand All @@ -228,7 +261,7 @@ export const FunctionUI = <T extends GeoStylerFunction>({
{argUIs}
</div>
);
}, [value, getUiForArg]);
}, [value, getUiForArg, locale, onChange]);

function updateFunctionName(functionName: GeoStylerFunction['name']) {
const newValue = structuredClone(value);
Expand Down
6 changes: 5 additions & 1 deletion src/Component/FunctionUI/StepInput/StepInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@ import { Expression, FStepParameter } from 'geostyler-style';
import './StepInput.less';
import NumberExpressionInput from '../../ExpressionInput/NumberExpressionInput/NumberExpressionInput';
import UnknownInput from '../UnknownInput/UnknownInput';
import { Type } from '../FunctionUI';

export type StepInputProps = {
value?: FStepParameter;
onChange: (newValue: FStepParameter) => void;
type?: Type;
};

export const StepInput: React.FC<StepInputProps> = ({
value,
onChange
onChange,
type
}) => {

const onBoundaryChante = useCallback((newBoundary: Expression<number>) => {
Expand All @@ -36,6 +39,7 @@ export const StepInput: React.FC<StepInputProps> = ({
value={value?.boundary}
/>
<UnknownInput
forcedType={type}
onChange={onValueChange}
value={value?.value as any}
/>
Expand Down
Loading

0 comments on commit 6744581

Please sign in to comment.