Skip to content

Commit

Permalink
fix(FormElement): uniformize prop > context fallbacks
Browse files Browse the repository at this point in the history
chore: dedupe props & initial states
  • Loading branch information
zettca committed Nov 25, 2024
1 parent 46d5b14 commit 28461b5
Show file tree
Hide file tree
Showing 33 changed files with 249 additions and 529 deletions.
47 changes: 1 addition & 46 deletions packages/core/src/BaseCheckBox/BaseCheckBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@ export type HvBaseCheckBoxClasses = ExtractNames<typeof useClasses>;

export interface HvBaseCheckBoxProps
extends Omit<MuiCheckboxProps, "onChange" | "classes"> {
/**
* The input name.
*/
name?: string;
/**
* The value of the input.
*
Expand All @@ -29,32 +25,6 @@ export interface HvBaseCheckBoxProps
* The default value is "on".
*/
value?: any;
/**
* Indicates that the input is disabled.
*/
disabled?: boolean;
/**
* Indicates that the input is not editable.
*/
readOnly?: boolean;
/**
* Indicates that user input is required.
*/
required?: boolean;
/**
* If `true` the checkbox is selected, if set to `false` the checkbox is not selected.
*
* When defined the checkbox state becomes controlled.
*/
checked?: boolean;
/**
* When uncontrolled, defines the initial checked state.
*/
defaultChecked?: boolean;
/**
* If `true` the checkbox visually shows the indeterminate state.
*/
indeterminate?: boolean;
/**
* The callback fired when the checkbox is pressed.
*/
Expand All @@ -63,23 +33,8 @@ export interface HvBaseCheckBoxProps
checked: boolean,
value: any,
) => void;
/**
* Whether the selector should use semantic colors.
*/
/** Whether the selector should use semantic colors. */
semantic?: boolean;
/**
* Properties passed on to the input element.
*/
inputProps?: React.InputHTMLAttributes<HTMLInputElement>;
/**
* Callback fired when the component is focused with a keyboard.
* We trigger a `onFocus` callback too.
*/
onFocusVisible?: (event: React.FocusEvent<any>) => void;
/**
* Callback fired when the component is blurred.
*/
onBlur?: (event: React.FocusEvent<HTMLButtonElement>) => void;
/**
* A Jss Object used to override or extend the styles applied to the checkbox.
*/
Expand Down
16 changes: 3 additions & 13 deletions packages/core/src/BaseInput/BaseInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,26 +54,16 @@ const baseInputStyles = emotionCss({

export interface HvBaseInputProps
extends Omit<MuiInputProps, "onChange" | "classes" | "ref"> {
/** The input name. */
name?: string;
/** The value of the input, when controlled. */
value?: string;
/** The initial value of the input, when uncontrolled. */
defaultValue?: string;
/** If `true` the input is disabled. */
disabled?: boolean;
/** Indicates that the input is not editable. */
readOnly?: boolean;
/** If true, the input element will be required. */
required?: boolean;
/** The function that will be executed onChange, allows modification of the input,
* it receives the value. If a new value should be presented it must returned it. */
onChange?: (
event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
value: string,
) => void;
/** The input type. */
type?: string;
/** Label inside the input used to help user. */
placeholder?: string;
/** If true, a textarea element will be rendered. */
Expand Down Expand Up @@ -112,9 +102,9 @@ export const HvBaseInput = forwardRef<
onChange,
type = "text",
placeholder,
multiline = false,
resizable = false,
invalid = false,
multiline,
resizable,
invalid,
inputRef,
inputProps = {},
...others
Expand Down
20 changes: 5 additions & 15 deletions packages/core/src/BaseInput/validations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const computeValidationType = (type: React.HTMLInputTypeAttribute) => {
* Checks whether any integrated validation, native or not, is active.
*/
export const hasBuiltInValidations = (
required: boolean,
required: boolean | undefined,
validationType: React.HTMLInputTypeAttribute,
minCharQuantity: number | null | undefined,
maxCharQuantity: number | null | undefined,
Expand Down Expand Up @@ -119,7 +119,7 @@ export const computeValidationMessage = (
export const validateInput = (
input: HTMLInputElement | HTMLTextAreaElement | null,
value: string,
required: boolean,
required: boolean | undefined,
minCharQuantity: any,
maxCharQuantity: any,
validationType: string,
Expand Down Expand Up @@ -188,19 +188,9 @@ export const validateInput = (
return inputValidity;
};

export type HvInputValidity = {
valid?: boolean;
badInput?: boolean;
customError?: boolean;
patternMismatch?: boolean;
rangeOverflow?: boolean;
rangeUnderflow?: boolean;
stepMismatch?: boolean;
tooLong?: boolean;
tooShort?: boolean;
typeMismatch?: boolean;
valueMissing?: boolean;
};
type Mutable<T> = { -readonly [P in keyof T]: T[P] };

export interface HvInputValidity extends Partial<Mutable<ValidityState>> {}

export const DEFAULT_ERROR_MESSAGES = {
error: "Invalid value",
Expand Down
24 changes: 12 additions & 12 deletions packages/core/src/Calendar/Calendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,9 @@ export interface HvCalendarProps {
export const HvCalendar = (props: HvCalendarProps) => {
const {
classes: classesProp,
id,
id: idProp,
locale = "en-US",
value,
value: valueProp,
visibleMonth,
visibleYear,
rightVisibleMonth,
Expand All @@ -130,20 +130,20 @@ export const HvCalendar = (props: HvCalendarProps) => {
} = useDefaultProps("HvCalendar", props);
const { classes } = useClasses(classesProp);

const { elementId } = useContext(HvFormElementContext);
const context = useContext(HvFormElementContext);
const elementValue = useContext(HvFormElementValueContext);
const localValue = value ?? elementValue;
const localId = id ?? setId(elementId, "single-calendar");
const rangeMode = isRange(localValue);
const rightCalendarId = setId(localId, "single-calendar-right");
const value = valueProp ?? elementValue;
const id = idProp ?? setId(context.id, "single-calendar");
const rangeMode = isRange(value);
const rightCalendarId = setId(id, "single-calendar-right");
const clampedMonth =
visibleMonth && visibleMonth % 13 > 0 ? visibleMonth % 13 : 1;

const singleCalendar = (
<HvSingleCalendar
id={localId}
id={id}
locale={locale}
value={localValue}
value={value}
visibleMonth={clampedMonth}
visibleYear={visibleYear}
minimumDate={minimumDate}
Expand All @@ -162,9 +162,9 @@ export const HvCalendar = (props: HvCalendarProps) => {
<div className={classes.rangeCalendarContainer}>
<HvSingleCalendar
className={classes.singleCalendar}
id={localId}
id={id}
locale={locale}
value={localValue}
value={value}
visibleMonth={clampedMonth}
visibleYear={visibleYear}
minimumDate={minimumDate}
Expand All @@ -184,7 +184,7 @@ export const HvCalendar = (props: HvCalendarProps) => {
className={classes.singleCalendar}
id={rightCalendarId}
locale={locale}
value={localValue}
value={value}
visibleMonth={rightVisibleMonth}
visibleYear={rightVisibleYear}
minimumDate={minimumDate}
Expand Down
10 changes: 5 additions & 5 deletions packages/core/src/Calendar/CalendarHeader/CalendarHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ dayjs.extend(customParseFormat);

export const HvCalendarHeader = (props: HvCalendarHeaderProps) => {
const {
id,
id: idProp,
value,
locale = "en-US",
classes: classesProp,
Expand All @@ -44,7 +44,7 @@ export const HvCalendarHeader = (props: HvCalendarHeaderProps) => {

const { classes, cx } = useClasses(classesProp);

const { elementId } = useContext(HvFormElementContext);
const context = useContext(HvFormElementContext);
const elementValue = useContext(HvFormElementValueContext);
const { label } = useContext(HvFormElementDescriptorsContext);

Expand All @@ -61,7 +61,7 @@ export const HvCalendarHeader = (props: HvCalendarHeaderProps) => {
const [displayValue, setDisplayValue] = useState("");
const [weekdayDisplay, setWeekdayDisplay] = useState("");

const localId = id ?? setId(elementId, "calendarHeader");
const id = idProp ?? setId(context.id, "calendarHeader");

const inputValue = editedValue ?? displayValue;
const localeFormat = dayjs().locale(locale).localeData().longDateFormat("L");
Expand Down Expand Up @@ -151,7 +151,7 @@ export const HvCalendarHeader = (props: HvCalendarHeaderProps) => {
// In a new major there's no need for all these classes
return (
<div
id={localId}
id={id}
className={cx(classes.root, {
[classes.invalid]: isInvalid,
})}
Expand All @@ -163,7 +163,7 @@ export const HvCalendarHeader = (props: HvCalendarHeaderProps) => {
)}
<HvInput
type="text"
id={setId(localId, "header-input")}
id={setId(id, "header-input")}
className={classes.headerDate}
classes={{
input: classes.input,
Expand Down
10 changes: 5 additions & 5 deletions packages/core/src/CheckBox/CheckBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,11 @@ export const HvCheckBox = forwardRef<HTMLButtonElement, HvCheckBoxProps>(
labelProps,
inputProps,
value = "on",
required = false,
readOnly = false,
disabled = false,
semantic = false,
defaultChecked = false,
required,
readOnly,
disabled,
semantic,
defaultChecked,
"aria-label": ariaLabel,
"aria-labelledby": ariaLabelledBy,
"aria-describedby": ariaDescribedBy,
Expand Down
68 changes: 17 additions & 51 deletions packages/core/src/CheckBoxGroup/CheckBoxGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
import { HvCheckBox } from "../CheckBox";
import {
HvFormElement,
HvFormElementProps,
HvFormStatus,
HvInfoMessage,
HvLabel,
Expand Down Expand Up @@ -58,57 +59,22 @@ export { staticClasses as checkBoxGroupClasses };
export type HvCheckBoxGroupClasses = ExtractNames<typeof useClasses>;

export interface HvCheckBoxGroupProps
extends HvBaseProps<HTMLDivElement, "onChange"> {
/**
* The form element name.
*
* It is propagated to the children checkboxes, unless they already have one.
*/
name?: string;
/**
* The value of the form element. An array of values represented in the child checkboxes.
*
* When defined the checkbox group state becomes controlled.
*/
value?: any[];
extends Pick<
HvFormElementProps<any[]>,
| "name"
| "value"
| "label"
| "description"
| "disabled"
| "required"
| "readOnly"
| "status"
>,
HvBaseProps<HTMLDivElement, "onChange"> {
/**
* When uncontrolled, defines the initial value.
*/
defaultValue?: any[];
/**
* The label of the form element.
*
* The form element must be labeled for accessibility reasons.
* If not provided, an aria-label or aria-labelledby must be provided instead.
*/
label?: React.ReactNode;
/**
* Provide additional descriptive text for the form element.
*/
description?: React.ReactNode;
/**
* Indicates that the form element is disabled.
* If `true` the state is propagated to the children checkboxes.
*/
disabled?: boolean;
/**
* Indicates that the form element is not editable.
* If `true` the state is propagated to the children checkboxes.
*/
readOnly?: boolean;
/**
* Indicates that user input is required on the form element.
*/
required?: boolean;
/**
* The status of the form element.
*
* Valid is correct, invalid is incorrect and standBy means no validations have run.
*
* When uncontrolled and unspecified it will default to "standBy" and change to either "valid"
* or "invalid" after any change to the state.
*/
status?: HvFormStatus;
/**
* The error message to show when the validation status is "invalid".
*
Expand Down Expand Up @@ -160,10 +126,10 @@ export const HvCheckBoxGroup = forwardRef<HTMLDivElement, HvCheckBoxGroupProps>(
statusMessage,
defaultValue,
value: valueProp,
required = false,
readOnly = false,
disabled = false,
showSelectAll = false,
required,
readOnly,
disabled,
showSelectAll,
orientation = "vertical",
selectAllLabel = "All",
selectAllConjunctionLabel = "/",
Expand Down
Loading

0 comments on commit 28461b5

Please sign in to comment.