-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Separate out control concerns from renderer concerns
- Loading branch information
1 parent
6e6ea42
commit ba8c728
Showing
5 changed files
with
152 additions
and
146 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,108 +1,57 @@ | ||
import { ControlProps, RendererProps } from "@jsonforms/core" | ||
import { Col, Form, InputNumber, Slider } from "antd" | ||
import { coerceToNumber, coerceToInteger, decimalToPercentage } from "../utils" | ||
import { Col, Form } from "antd" | ||
import { NumericInput } from "../../renderers/NumericInput" | ||
import { NumericSlider } from "../../renderers/NumericSlider" | ||
import { coerceToInteger, coerceToNumber } from "../utils" | ||
|
||
|
||
export function NumericSliderControl({ | ||
data, | ||
handleChange, | ||
path, | ||
required, | ||
label, | ||
visible, | ||
id, | ||
schema, | ||
uischema, | ||
}: ControlProps & RendererProps) { | ||
if (!visible) return null | ||
export const NumericSliderControl = (props: ControlProps & RendererProps) => { | ||
if (!props.visible) return null | ||
|
||
const arialLabelWithFallback = label || schema.description || "Value" | ||
const schema = props.schema | ||
|
||
const minimum = schema.properties?.minimum as number | ||
const maximum = schema.properties?.maximum as number | ||
const step = schema.properties?.multipleOf as number | ||
const initialValue = typeof schema.default === "number" ? schema.default : undefined | ||
|
||
const defaultValue = typeof schema?.default === "number" ? schema.default : minimum | ||
const isEmptyObj = typeof data === "object" && data !== undefined && data !== null ? Object.keys(data as object).length === 0 : false | ||
const value = data === undefined || isEmptyObj ? defaultValue : data as number | null | ||
|
||
const addonAfter = uischema.options?.addonAfter as string | undefined | ||
const addonBefore = uischema.options?.addonBefore as string | undefined | ||
const isPercentage = addonAfter?.trim() === "%" | ||
|
||
const numberType = schema.properties?.type as string | ||
const numberType = props.schema.properties?.type as string | ||
const minimum = props.schema.properties?.minimum as number | undefined | ||
const maximum = props.schema.properties?.maximum as number | undefined | ||
const onChange = (value: number | null) => { | ||
if (value !== null && value >= minimum && value <= maximum) { | ||
if (value !== null && (minimum && value >= minimum) && (maximum && value <= maximum)) { | ||
if (numberType === "integer") { | ||
handleChange(path, value !== null ? coerceToInteger(value) : value) | ||
} else { | ||
handleChange(path, value !== null ? coerceToNumber(value) : value) | ||
} | ||
} | ||
} | ||
|
||
const style = { marginLeft: 16, width: "100%" } | ||
const formatter = ((value?: number) => { | ||
if (typeof value !== "undefined") { | ||
if (isPercentage) { | ||
return decimalToPercentage(value) | ||
props.handleChange(props.path, value !== null ? coerceToInteger(value) : value) | ||
} else { | ||
return value.toString() | ||
props.handleChange(props.path, value !== null ? coerceToNumber(value) : value) | ||
} | ||
} | ||
return "" | ||
}) | ||
|
||
const numberInput = ( | ||
<InputNumber | ||
aria-label={arialLabelWithFallback} | ||
defaultValue={defaultValue} | ||
value={value} | ||
onChange={onChange} | ||
min={minimum} | ||
max={maximum} | ||
addonBefore={addonBefore} | ||
addonAfter={addonAfter} | ||
formatter={formatter} | ||
style={style} | ||
controls={false} | ||
/> | ||
) | ||
|
||
const tooltip = { | ||
formatter: (value?: number) => { | ||
const tooltipValue = value !== undefined ? value : defaultValue | ||
const formattedTooltipValue = isPercentage ? decimalToPercentage(tooltipValue) : tooltipValue | ||
return `${addonBefore ? addonBefore : ""}${formattedTooltipValue}${addonAfter ? addonAfter : ""}` | ||
} | ||
} | ||
|
||
const slider = <Slider | ||
defaultValue={defaultValue} | ||
value={value === null ? defaultValue : value} | ||
disabled={defaultValue === null} | ||
onChange={onChange} | ||
min={minimum} | ||
max={maximum} | ||
step={step} | ||
tooltip={tooltip} | ||
/> | ||
|
||
const rules = [ | ||
{ required, message: required ? `${label} is required` : "" }, | ||
{ message: props.required ? `${props.label} is required` : "" }, | ||
] | ||
|
||
const numericSliderProps = { | ||
...props, | ||
...onChange, | ||
} | ||
const numericSlider = NumericSlider(numericSliderProps) | ||
|
||
const numericInputProps = { | ||
...numericSliderProps, | ||
"aria-label": props.label || schema.description || "Value", | ||
} | ||
const numericInput = NumericInput(numericInputProps) | ||
|
||
return ( | ||
<Form.Item | ||
label={label} | ||
id={id} | ||
name={path} | ||
required={required} | ||
initialValue={defaultValue} | ||
label={props.label} | ||
id={props.id} | ||
name={props.path} | ||
required={props.required} | ||
initialValue={initialValue} | ||
rules={rules} | ||
validateTrigger={["onBlur"]} | ||
> | ||
<Col span={8}>{slider}</Col><Col span={7}>{numberInput}</Col> | ||
<Col span={8}>{numericSlider}</Col><Col span={7}>{numericInput}</Col> | ||
</Form.Item> | ||
) | ||
} |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { ReactElement } from "react" | ||
import { RendererProps } from "@jsonforms/core" | ||
import { InputNumber } from "antd" | ||
import { decimalToPercentage } from "../controls/utils" | ||
|
||
type NumericInput = ReactElement<typeof InputNumber> | ||
type NumericInputProps = RendererProps & React.ComponentProps<typeof InputNumber> | ||
|
||
export const NumericInput = (props: NumericInputProps): NumericInput => { | ||
const schema = props.schema | ||
|
||
const min = schema.properties?.minimum as number | undefined | ||
const max = schema.properties?.maximum as number | undefined | ||
|
||
const defaultValue = typeof schema?.default === "number" ? schema.default : undefined | ||
|
||
const isNonNullObject = typeof props.data === "object" && props.data !== undefined && props.data !== null | ||
const isEmptyObj = isNonNullObject ? Object.keys(props.data as object).length === 0 : false | ||
const value = props.data === undefined || isEmptyObj ? defaultValue : props.data as number | null | ||
|
||
const addonAfter = props.uischema.options?.addonAfter as string | undefined | ||
const addonBefore = props.uischema.options?.addonBefore as string | undefined | ||
const isPercentage = addonAfter?.trim() === "%" | ||
|
||
const style = { marginLeft: 0, width: "100%" } | ||
const formatter = ((value?: number) => { | ||
if (typeof value !== "undefined") { | ||
if (isPercentage) { | ||
return decimalToPercentage(value) | ||
} else { | ||
return value.toString() | ||
} | ||
} | ||
return "" | ||
}) | ||
|
||
return <InputNumber | ||
aria-label={props["aria-label"]} | ||
defaultValue={defaultValue} | ||
value={value} | ||
onChange={props.onChange} | ||
min={min} | ||
max={max} | ||
addonBefore={addonBefore} | ||
addonAfter={addonAfter} | ||
formatter={formatter} | ||
style={style} | ||
controls={false} | ||
/> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import { ReactElement } from "react" | ||
import { RendererProps } from "@jsonforms/core" | ||
import { Slider } from "antd" | ||
import { decimalToPercentage } from "../controls/utils" | ||
|
||
type NumericSlider = ReactElement<typeof Slider> | ||
type NumericSliderProps = RendererProps & React.ComponentProps<typeof Slider> | ||
|
||
export const NumericSlider = (props: NumericSliderProps): NumericSlider => { | ||
const schema = props.schema | ||
|
||
const min = schema.properties?.minimum as number | undefined | ||
const max = schema.properties?.maximum as number | undefined | ||
const step = schema.properties?.multipleOf as number | undefined | ||
|
||
const defaultValue = typeof schema?.default === "number" ? schema.default : min | ||
|
||
const isNonNullObject = typeof props.data === "object" && props.data !== undefined && props.data !== null | ||
const isEmptyObj = isNonNullObject ? Object.keys(props.data as object).length === 0 : false | ||
const value = props.data === undefined || isEmptyObj ? defaultValue : props.data as number | null | ||
|
||
const addonAfter = props.uischema.options?.addonAfter as string | undefined | ||
const addonBefore = props.uischema.options?.addonBefore as string | undefined | ||
const isPercentage = addonAfter?.trim() === "%" | ||
|
||
const tooltip = { | ||
formatter: (value?: number) => { | ||
const tooltipValue = value !== undefined ? value : defaultValue | ||
const formattedTooltipValue = isPercentage ? decimalToPercentage(tooltipValue) : tooltipValue | ||
return `${addonBefore ? addonBefore : ""}${formattedTooltipValue}${addonAfter ? addonAfter : ""}` | ||
} | ||
} | ||
|
||
return <Slider | ||
defaultValue={defaultValue} | ||
value={value === null ? defaultValue : value} | ||
disabled={defaultValue === null} | ||
onChange={props.onChange as (value: number) => void} | ||
min={min} | ||
max={max} | ||
step={step} | ||
tooltip={tooltip} | ||
range={false} | ||
/> | ||
} |