diff --git a/src/controls/NumericControl/NumericControl.tsx b/src/controls/NumericControl/NumericControl.tsx index 99e0381..63a84a5 100644 --- a/src/controls/NumericControl/NumericControl.tsx +++ b/src/controls/NumericControl/NumericControl.tsx @@ -1,88 +1,50 @@ import { ControlProps, RendererProps } from "@jsonforms/core" -import { Col, Form, InputNumber } from "antd" -import { coerceToInteger, coerceToNumber, decimalToPercentage } from "../utils" +import { Col, Form } from "antd" +import { NumericInput } from "../../renderers/NumericInput" +import { coerceToInteger, coerceToNumber } from "../utils" -export const NumericControl = ({ - data, - handleChange, - path, - required, - label, - visible, - id, - schema, - uischema, -}: ControlProps & RendererProps) => { - if (!visible) return null +export const NumericControl = (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 defaultValue = typeof schema?.default === "number" ? schema.default : undefined - 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 ariaLabel = props.label || schema.description || "Value" + const initialValue = typeof schema.default === "number" ? schema.default : undefined const numberType = schema.properties?.type as string const onChange = (value: number | null) => { if (value !== null) { if (numberType === "integer") { - handleChange(path, value !== null ? coerceToInteger(value) : value) + props.handleChange(props.path, value !== null ? coerceToInteger(value) : value) } else { - handleChange(path, value !== null ? coerceToNumber(value) : value) + props.handleChange(props.path, value !== null ? coerceToNumber(value) : value) } } } - const style = { marginLeft: 0, width: "100%" } - const formatter = ((value?: number) => { - if (typeof value !== "undefined") { - if (isPercentage) { - return decimalToPercentage(value) - } else { - return value.toString() - } - } - return "" - }) - - const numberInput = ( - - ) - const rules = [ - { required, message: required ? `${label} is required` : "" }, + { message: props.required ? `${props.label} is required` : "" }, ] + const numericInputProps = { + ...props, + ...onChange, + "aria-label": ariaLabel, + } + const numericInput = NumericInput(numericInputProps) + return ( - {numberInput} + {numericInput} ) } diff --git a/src/controls/NumericControl/NumericSliderControl.tsx b/src/controls/NumericControl/NumericSliderControl.tsx index ca104e1..2e4212b 100644 --- a/src/controls/NumericControl/NumericSliderControl.tsx +++ b/src/controls/NumericControl/NumericSliderControl.tsx @@ -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 = ( - - ) - - 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 = - 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 ( - {slider}{numberInput} + {numericSlider}{numericInput} ) } diff --git a/src/controls/testerConditions.ts b/src/controls/testerConditions.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/renderers/NumericInput.tsx b/src/renderers/NumericInput.tsx new file mode 100644 index 0000000..af88c9d --- /dev/null +++ b/src/renderers/NumericInput.tsx @@ -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 +type NumericInputProps = RendererProps & React.ComponentProps + +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 +} diff --git a/src/renderers/NumericSlider.tsx b/src/renderers/NumericSlider.tsx new file mode 100644 index 0000000..90a0e9f --- /dev/null +++ b/src/renderers/NumericSlider.tsx @@ -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 +type NumericSliderProps = RendererProps & React.ComponentProps + +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 void} + min={min} + max={max} + step={step} + tooltip={tooltip} + range={false} + /> +}