updated checkbox widget to use carbon and added tooltip options w/ burnettk (#466)
Co-authored-by: jasquat <jasquat@users.noreply.github.com>
This commit is contained in:
parent
f9e4cf577a
commit
69e2fef0b1
|
@ -1,4 +1,3 @@
|
|||
// @ts-ignore
|
||||
import { DatePicker, DatePickerInput, TextInput } from '@carbon/react';
|
||||
import {
|
||||
getInputProps,
|
||||
|
@ -11,6 +10,7 @@ import {
|
|||
import { useCallback } from 'react';
|
||||
import { DATE_FORMAT_CARBON, DATE_FORMAT_FOR_DISPLAY } from '../../../config';
|
||||
import { ymdDateStringToConfiguredFormat } from '../../../helpers';
|
||||
import { getCommonAttributes } from '../../helpers';
|
||||
|
||||
/** The `BaseInputTemplate` is the template to use to render the basic `<input>` component for the `core` theme.
|
||||
* It is used as the template for rendering many of the <input> based widgets that differ by `type` and callbacks only.
|
||||
|
@ -70,28 +70,12 @@ export default function BaseInputTemplate<
|
|||
[onFocus, id]
|
||||
);
|
||||
|
||||
let labelToUse = label;
|
||||
if (uiSchema && uiSchema['ui:title']) {
|
||||
labelToUse = uiSchema['ui:title'];
|
||||
} else if (schema && schema.title) {
|
||||
labelToUse = schema.title;
|
||||
}
|
||||
|
||||
let helperText = null;
|
||||
if (uiSchema && uiSchema['ui:help']) {
|
||||
helperText = uiSchema['ui:help'];
|
||||
}
|
||||
|
||||
let invalid = false;
|
||||
let errorMessageForField = null;
|
||||
if (rawErrors && rawErrors.length > 0) {
|
||||
invalid = true;
|
||||
if ('validationErrorMessage' in schema) {
|
||||
errorMessageForField = (schema as any).validationErrorMessage;
|
||||
} else {
|
||||
errorMessageForField = `${labelToUse.replace(/\*$/, '')} ${rawErrors[0]}`;
|
||||
}
|
||||
}
|
||||
const commonAttributes = getCommonAttributes(
|
||||
label,
|
||||
schema,
|
||||
uiSchema,
|
||||
rawErrors
|
||||
);
|
||||
|
||||
let component = null;
|
||||
if (type === 'date') {
|
||||
|
@ -118,15 +102,15 @@ export default function BaseInputTemplate<
|
|||
<DatePickerInput
|
||||
id={id}
|
||||
placeholder={DATE_FORMAT_FOR_DISPLAY}
|
||||
helperText={helperText}
|
||||
helperText={commonAttributes.helperText}
|
||||
type="text"
|
||||
size="md"
|
||||
value={dateValue}
|
||||
autocomplete="off"
|
||||
allowInput={false}
|
||||
onChange={_onChange}
|
||||
invalid={invalid}
|
||||
invalidText={errorMessageForField}
|
||||
invalid={commonAttributes.invalid}
|
||||
invalidText={commonAttributes.errorMessageForField}
|
||||
autoFocus={autofocus}
|
||||
disabled={disabled || readonly}
|
||||
onBlur={_onBlur}
|
||||
|
@ -141,9 +125,9 @@ export default function BaseInputTemplate<
|
|||
<TextInput
|
||||
id={id}
|
||||
className="text-input"
|
||||
helperText={helperText}
|
||||
invalid={invalid}
|
||||
invalidText={errorMessageForField}
|
||||
helperText={commonAttributes.helperText}
|
||||
invalid={commonAttributes.invalid}
|
||||
invalidText={commonAttributes.errorMessageForField}
|
||||
autoFocus={autofocus}
|
||||
disabled={disabled || readonly}
|
||||
value={value || value === 0 ? value : ''}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react';
|
||||
import Checkbox from '@mui/material/Checkbox';
|
||||
import FormControlLabel from '@mui/material/FormControlLabel';
|
||||
import { schemaRequiresTrueValue, WidgetProps } from '@rjsf/utils';
|
||||
import { Checkbox } from '@carbon/react';
|
||||
import { WidgetProps } from '@rjsf/utils';
|
||||
import { getCommonAttributes } from '../../helpers';
|
||||
|
||||
function CheckboxWidget(props: WidgetProps) {
|
||||
const {
|
||||
|
@ -15,13 +15,19 @@ function CheckboxWidget(props: WidgetProps) {
|
|||
onChange,
|
||||
onBlur,
|
||||
onFocus,
|
||||
uiSchema,
|
||||
rawErrors,
|
||||
required,
|
||||
} = props;
|
||||
// Because an unchecked checkbox will cause html5 validation to fail, only add
|
||||
// the "required" attribute if the field value must be "true", due to the
|
||||
// "const" or "enum" keywords
|
||||
const required = schemaRequiresTrueValue(schema);
|
||||
|
||||
const _onChange = (_: any, checked: boolean) => onChange(checked);
|
||||
const _onChange = (_: any, newValue: any) => {
|
||||
// if this field is required and it is not checked then change the value to undefined
|
||||
// otherwise rjsf will not flag this field as invalid
|
||||
if (required && !newValue.checked) {
|
||||
onChange(undefined);
|
||||
} else {
|
||||
onChange(newValue.checked);
|
||||
}
|
||||
};
|
||||
const _onBlur = ({
|
||||
target: { value },
|
||||
}: React.FocusEvent<HTMLButtonElement>) => onBlur(id, value);
|
||||
|
@ -29,22 +35,32 @@ function CheckboxWidget(props: WidgetProps) {
|
|||
target: { value },
|
||||
}: React.FocusEvent<HTMLButtonElement>) => onFocus(id, value);
|
||||
|
||||
const commonAttributes = getCommonAttributes(
|
||||
label,
|
||||
schema,
|
||||
uiSchema,
|
||||
rawErrors
|
||||
);
|
||||
|
||||
return (
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
id={id}
|
||||
name={id}
|
||||
checked={typeof value === 'undefined' ? false : Boolean(value)}
|
||||
required={required}
|
||||
disabled={disabled || readonly}
|
||||
autoFocus={autofocus}
|
||||
onChange={_onChange}
|
||||
onBlur={_onBlur}
|
||||
onFocus={_onFocus}
|
||||
/>
|
||||
<Checkbox
|
||||
id={id}
|
||||
name={id}
|
||||
checked={typeof value === 'undefined' ? false : Boolean(value)}
|
||||
disabled={disabled || readonly}
|
||||
title={commonAttributes.tooltipText}
|
||||
autoFocus={autofocus}
|
||||
invalid={commonAttributes.invalid}
|
||||
invalidText={commonAttributes.errorMessageForField}
|
||||
helperText={commonAttributes.helperText}
|
||||
labelText={
|
||||
required
|
||||
? commonAttributes.labelWithRequiredIndicator
|
||||
: commonAttributes.label
|
||||
}
|
||||
label={label || ''}
|
||||
onChange={_onChange}
|
||||
onBlur={_onBlur}
|
||||
onFocus={_onFocus}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { Select, SelectItem } from '@carbon/react';
|
||||
import { WidgetProps, processSelectValue } from '@rjsf/utils';
|
||||
import { getCommonAttributes } from '../../helpers';
|
||||
|
||||
function SelectWidget({
|
||||
schema,
|
||||
|
@ -35,30 +36,12 @@ function SelectWidget({
|
|||
}: React.FocusEvent<HTMLInputElement>) =>
|
||||
onFocus(id, processSelectValue(schema, value, options));
|
||||
|
||||
let labelToUse = label;
|
||||
if (uiSchema && uiSchema['ui:title']) {
|
||||
labelToUse = uiSchema['ui:title'];
|
||||
} else if (schema && schema.title) {
|
||||
labelToUse = schema.title;
|
||||
}
|
||||
let helperText = null;
|
||||
if (uiSchema && uiSchema['ui:help']) {
|
||||
helperText = uiSchema['ui:help'];
|
||||
}
|
||||
if (required) {
|
||||
labelToUse = `${labelToUse}*`;
|
||||
}
|
||||
|
||||
let invalid = false;
|
||||
let errorMessageForField = null;
|
||||
if (rawErrors && rawErrors.length > 0) {
|
||||
invalid = true;
|
||||
if ('validationErrorMessage' in schema) {
|
||||
errorMessageForField = (schema as any).validationErrorMessage;
|
||||
} else {
|
||||
errorMessageForField = rawErrors[0];
|
||||
}
|
||||
}
|
||||
const commonAttributes = getCommonAttributes(
|
||||
label,
|
||||
schema,
|
||||
uiSchema,
|
||||
rawErrors
|
||||
);
|
||||
|
||||
// ok. so in safari, the select widget showed the first option, whereas in chrome it forced you to select an option.
|
||||
// this change causes causes safari to act a little bit more like chrome, but it's different because we are actually adding
|
||||
|
@ -99,7 +82,7 @@ function SelectWidget({
|
|||
name={id}
|
||||
labelText=""
|
||||
select
|
||||
helperText={helperText}
|
||||
helperText={commonAttributes.helperText}
|
||||
value={typeof value === 'undefined' ? emptyValue : value}
|
||||
disabled={disabled || readonly}
|
||||
autoFocus={autofocus}
|
||||
|
@ -107,8 +90,8 @@ function SelectWidget({
|
|||
onChange={_onChange}
|
||||
onBlur={_onBlur}
|
||||
onFocus={_onFocus}
|
||||
invalid={invalid}
|
||||
invalidText={errorMessageForField}
|
||||
invalid={commonAttributes.invalid}
|
||||
invalidText={commonAttributes.errorMessageForField}
|
||||
InputLabelProps={{
|
||||
shrink: true,
|
||||
}}
|
||||
|
@ -116,7 +99,7 @@ function SelectWidget({
|
|||
multiple: typeof multiple === 'undefined' ? false : multiple,
|
||||
}}
|
||||
>
|
||||
{(enumOptions as any).map(({ value, label }: any, i: number) => {
|
||||
{(enumOptions as any).map(({ value, label }: any, _i: number) => {
|
||||
const disabled: any =
|
||||
enumDisabled && (enumDisabled as any).indexOf(value) != -1;
|
||||
return <SelectItem text={label} value={value} disabled={disabled} />;
|
||||
|
|
|
@ -7,6 +7,7 @@ import {
|
|||
StrictRJSFSchema,
|
||||
WidgetProps,
|
||||
} from '@rjsf/utils';
|
||||
import { getCommonAttributes } from '../../helpers';
|
||||
|
||||
/** The `TextareaWidget` is a widget for rendering input fields as textarea.
|
||||
*
|
||||
|
@ -51,34 +52,19 @@ function TextareaWidget<
|
|||
[id, onFocus]
|
||||
);
|
||||
|
||||
let labelToUse = label;
|
||||
if (uiSchema && uiSchema['ui:title']) {
|
||||
labelToUse = uiSchema['ui:title'];
|
||||
} else if (schema && schema.title) {
|
||||
labelToUse = schema.title;
|
||||
}
|
||||
if (required) {
|
||||
labelToUse = `${labelToUse}*`;
|
||||
}
|
||||
|
||||
let helperText = null;
|
||||
if (uiSchema && uiSchema['ui:help']) {
|
||||
helperText = uiSchema['ui:help'];
|
||||
}
|
||||
|
||||
let invalid = false;
|
||||
let errorMessageForField = null;
|
||||
if (rawErrors && rawErrors.length > 0) {
|
||||
invalid = true;
|
||||
errorMessageForField = rawErrors[0];
|
||||
}
|
||||
const commonAttributes = getCommonAttributes(
|
||||
label,
|
||||
schema,
|
||||
uiSchema,
|
||||
rawErrors
|
||||
);
|
||||
|
||||
return (
|
||||
<TextArea
|
||||
id={id}
|
||||
name={id}
|
||||
className="text-input"
|
||||
helperText={helperText}
|
||||
helperText={commonAttributes.helperText}
|
||||
value={value || ''}
|
||||
labelText=""
|
||||
placeholder={placeholder}
|
||||
|
@ -90,8 +76,8 @@ function TextareaWidget<
|
|||
onBlur={handleBlur}
|
||||
onFocus={handleFocus}
|
||||
onChange={handleChange}
|
||||
invalid={invalid}
|
||||
invalidText={errorMessageForField}
|
||||
invalid={commonAttributes.invalid}
|
||||
invalidText={commonAttributes.errorMessageForField}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -10,10 +10,12 @@ import {
|
|||
convertStringToDate,
|
||||
dateStringToYMDFormat,
|
||||
} from '../../../helpers';
|
||||
import { getCommonAttributes } from '../../helpers';
|
||||
|
||||
interface widgetArgs {
|
||||
id: string;
|
||||
value: any;
|
||||
label: string;
|
||||
schema?: any;
|
||||
uiSchema?: any;
|
||||
disabled?: boolean;
|
||||
|
@ -21,7 +23,6 @@ interface widgetArgs {
|
|||
rawErrors?: any;
|
||||
onChange?: any;
|
||||
autofocus?: any;
|
||||
label?: string;
|
||||
}
|
||||
|
||||
// NOTE: To properly validate that both start and end dates are specified
|
||||
|
@ -41,15 +42,12 @@ export default function DateRangePickerWidget({
|
|||
label,
|
||||
rawErrors = [],
|
||||
}: widgetArgs) {
|
||||
let invalid = false;
|
||||
let errorMessageForField = null;
|
||||
|
||||
let labelToUse = label;
|
||||
if (uiSchema && uiSchema['ui:title']) {
|
||||
labelToUse = uiSchema['ui:title'];
|
||||
} else if (schema && schema.title) {
|
||||
labelToUse = schema.title;
|
||||
}
|
||||
const commonAttributes = getCommonAttributes(
|
||||
label,
|
||||
schema,
|
||||
uiSchema,
|
||||
rawErrors
|
||||
);
|
||||
|
||||
const onChangeLocal = useCallback(
|
||||
(dateRange: Date[]) => {
|
||||
|
@ -69,22 +67,6 @@ export default function DateRangePickerWidget({
|
|||
[onChange]
|
||||
);
|
||||
|
||||
let helperText = null;
|
||||
if (uiSchema && uiSchema['ui:help']) {
|
||||
helperText = uiSchema['ui:help'];
|
||||
}
|
||||
|
||||
if (!invalid && rawErrors && rawErrors.length > 0) {
|
||||
invalid = true;
|
||||
if ('validationErrorMessage' in schema) {
|
||||
errorMessageForField = (schema as any).validationErrorMessage;
|
||||
} else {
|
||||
errorMessageForField = `${(labelToUse || '').replace(/\*$/, '')} ${
|
||||
rawErrors[0]
|
||||
}`;
|
||||
}
|
||||
}
|
||||
|
||||
let dateValue: (Date | null)[] | null = value;
|
||||
if (value) {
|
||||
const [startDateString, endDateString] = value.split(DATE_RANGE_DELIMITER);
|
||||
|
@ -113,12 +95,12 @@ export default function DateRangePickerWidget({
|
|||
<DatePickerInput
|
||||
id={`${id}-start`}
|
||||
placeholder={DATE_FORMAT_FOR_DISPLAY}
|
||||
helperText={helperText}
|
||||
helperText={commonAttributes.helperText}
|
||||
type="text"
|
||||
size="md"
|
||||
disabled={disabled || readonly}
|
||||
invalid={invalid}
|
||||
invalidText={errorMessageForField}
|
||||
invalid={commonAttributes.invalid}
|
||||
invalidText={commonAttributes.errorMessageForField}
|
||||
autoFocus={autofocus}
|
||||
pattern={null}
|
||||
/>
|
||||
|
@ -128,7 +110,7 @@ export default function DateRangePickerWidget({
|
|||
type="text"
|
||||
size="md"
|
||||
disabled={disabled || readonly}
|
||||
invalid={invalid}
|
||||
invalid={commonAttributes.invalid}
|
||||
autoFocus={autofocus}
|
||||
pattern={null}
|
||||
/>
|
||||
|
|
|
@ -1,19 +1,20 @@
|
|||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { ComboBox } from '@carbon/react';
|
||||
import HttpService from '../../../services/HttpService';
|
||||
import { getCommonAttributes } from '../../helpers';
|
||||
|
||||
interface typeaheadArgs {
|
||||
id: string;
|
||||
onChange: any;
|
||||
options: any;
|
||||
value: any;
|
||||
label: string;
|
||||
schema?: any;
|
||||
uiSchema?: any;
|
||||
disabled?: boolean;
|
||||
readonly?: boolean;
|
||||
rawErrors?: any;
|
||||
placeholder?: string;
|
||||
label?: string;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line sonarjs/cognitive-complexity
|
||||
|
@ -36,30 +37,23 @@ export default function TypeaheadWidget({
|
|||
const itemFormatRegex = /[^{}]+(?=})/g;
|
||||
|
||||
let itemFormatSubstitutions: string[] | null = null;
|
||||
let invalid = false;
|
||||
let errorMessageForField = null;
|
||||
|
||||
const commonAttributes = getCommonAttributes(
|
||||
label,
|
||||
schema,
|
||||
uiSchema,
|
||||
rawErrors
|
||||
);
|
||||
|
||||
if (itemFormat) {
|
||||
try {
|
||||
itemFormatSubstitutions = itemFormat.match(itemFormatRegex);
|
||||
} catch (e) {
|
||||
errorMessageForField = `itemFormat does not contain replacement keys in curly braces. It should be like: "{key1} ({key2} - {key3})"`;
|
||||
invalid = true;
|
||||
commonAttributes.errorMessageForField = `itemFormat does not contain replacement keys in curly braces. It should be like: "{key1} ({key2} - {key3})"`;
|
||||
commonAttributes.invalid = true;
|
||||
}
|
||||
}
|
||||
|
||||
let labelToUse = label;
|
||||
if (uiSchema && uiSchema['ui:title']) {
|
||||
labelToUse = uiSchema['ui:title'];
|
||||
} else if (schema && schema.title) {
|
||||
labelToUse = schema.title;
|
||||
}
|
||||
|
||||
if (!category) {
|
||||
errorMessageForField = `category is not set in the ui:options for this field: ${labelToUse}`;
|
||||
invalid = true;
|
||||
}
|
||||
|
||||
const typeaheadSearch = useCallback(
|
||||
(inputText: string) => {
|
||||
const pathForCategory = (text: string) => {
|
||||
|
@ -109,20 +103,9 @@ export default function TypeaheadWidget({
|
|||
placeholderText = placeholder;
|
||||
}
|
||||
|
||||
let helperText = null;
|
||||
if (uiSchema && uiSchema['ui:help']) {
|
||||
helperText = uiSchema['ui:help'];
|
||||
}
|
||||
|
||||
if (!invalid && rawErrors && rawErrors.length > 0) {
|
||||
invalid = true;
|
||||
if ('validationErrorMessage' in schema) {
|
||||
errorMessageForField = (schema as any).validationErrorMessage;
|
||||
} else {
|
||||
errorMessageForField = `${(labelToUse || '').replace(/\*$/, '')} ${
|
||||
rawErrors[0]
|
||||
}`;
|
||||
}
|
||||
if (!category) {
|
||||
commonAttributes.errorMessageForField = `category is not set in the ui:options for this field: ${commonAttributes.label}`;
|
||||
commonAttributes.invalid = true;
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -145,11 +128,11 @@ export default function TypeaheadWidget({
|
|||
itemToString={itemToString}
|
||||
placeholder={placeholderText}
|
||||
selectedItem={selectedItem}
|
||||
helperText={helperText}
|
||||
helperText={commonAttributes.helperText}
|
||||
disabled={disabled}
|
||||
readOnly={readonly}
|
||||
invalid={invalid}
|
||||
invalidText={errorMessageForField}
|
||||
invalid={commonAttributes.invalid}
|
||||
invalidText={commonAttributes.errorMessageForField}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
const REQUIRED_FIELD_SYMBOL = '*';
|
||||
export const getCommonAttributes = (
|
||||
label: string,
|
||||
schema: any,
|
||||
uiSchema: any,
|
||||
rawErrors: any
|
||||
) => {
|
||||
let labelToUse = label;
|
||||
if (uiSchema && uiSchema['ui:title']) {
|
||||
labelToUse = uiSchema['ui:title'];
|
||||
} else if (schema && schema.title) {
|
||||
labelToUse = schema.title;
|
||||
}
|
||||
|
||||
const labelWithRequiredIndicator = `${labelToUse}${REQUIRED_FIELD_SYMBOL}`;
|
||||
|
||||
let helperText = null;
|
||||
let tooltipText = null;
|
||||
if (uiSchema) {
|
||||
if (uiSchema['ui:help']) {
|
||||
helperText = uiSchema['ui:help'];
|
||||
}
|
||||
if (uiSchema['ui:tooltip']) {
|
||||
tooltipText = uiSchema['ui:tooltip'];
|
||||
}
|
||||
}
|
||||
|
||||
let invalid = false;
|
||||
let errorMessageForField = null;
|
||||
if (rawErrors && rawErrors.length > 0) {
|
||||
invalid = true;
|
||||
if ('validationErrorMessage' in schema) {
|
||||
errorMessageForField = (schema as any).validationErrorMessage;
|
||||
} else {
|
||||
errorMessageForField = `${labelToUse.replace(/\*$/, '')} ${rawErrors[0]}`;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
helperText,
|
||||
label: labelToUse,
|
||||
invalid,
|
||||
errorMessageForField,
|
||||
labelWithRequiredIndicator,
|
||||
tooltipText,
|
||||
};
|
||||
};
|
Loading…
Reference in New Issue