@khanacademy/wonder-blocks-form
Advanced tools
Comparing version 0.0.0-PR2358-20241113141724 to 0.0.0-PR2373-20250121234927
140
CHANGELOG.md
# @khanacademy/wonder-blocks-form | ||
## 0.0.0-PR2358-20241113141724 | ||
## 0.0.0-PR2373-20250121234927 | ||
### Major Changes | ||
- 8d26588f: Remove `light` variant from LabeledTextField, TextField and TextArea" | ||
### Patch Changes | ||
- Updated dependencies [e9644a13] | ||
- @khanacademy/wonder-blocks-icon@0.0.0-PR2358-20241113141724 | ||
- Updated dependencies [0de25cd8] | ||
- @khanacademy/wonder-blocks-tokens@0.0.0-PR2373-20250121234927 | ||
- @khanacademy/wonder-blocks-clickable@0.0.0-PR2373-20250121234927 | ||
- @khanacademy/wonder-blocks-layout@0.0.0-PR2373-20250121234927 | ||
## 6.0.6 | ||
### Patch Changes | ||
- d9bc865b: TextField and TextArea: Set `aria-required` if it is required | ||
- d9bc865b: TextField and TextArea validation: Always clear error message onChange if instantValidation=false so externally set error state can still be cleared | ||
## 6.0.5 | ||
### Patch Changes | ||
- Updated dependencies [7516b239] | ||
- @khanacademy/wonder-blocks-core@11.1.0 | ||
- @khanacademy/wonder-blocks-clickable@5.0.5 | ||
- @khanacademy/wonder-blocks-icon@5.0.5 | ||
- @khanacademy/wonder-blocks-layout@3.0.5 | ||
- @khanacademy/wonder-blocks-typography@3.0.5 | ||
## 6.0.4 | ||
### Patch Changes | ||
- 11a0f5c6: No functional changes. Adding prepublishOnly script. | ||
- Updated dependencies [11a0f5c6] | ||
- @khanacademy/wonder-blocks-typography@3.0.4 | ||
- @khanacademy/wonder-blocks-clickable@5.0.4 | ||
- @khanacademy/wonder-blocks-layout@3.0.4 | ||
- @khanacademy/wonder-blocks-tokens@3.0.1 | ||
- @khanacademy/wonder-blocks-core@11.0.1 | ||
- @khanacademy/wonder-blocks-icon@5.0.4 | ||
## 6.0.3 | ||
### Patch Changes | ||
- 53b41970: Adding more info about the legend change | ||
## 6.0.2 | ||
### Patch Changes | ||
- 361cb52b: Adds `width: 100%` to `legend` element to allow expanding it to fill the available space | ||
## 6.0.1 | ||
### Patch Changes | ||
- Updated dependencies [d23c9c5f] | ||
- @khanacademy/wonder-blocks-core@11.0.0 | ||
- @khanacademy/wonder-blocks-clickable@5.0.3 | ||
- @khanacademy/wonder-blocks-icon@5.0.3 | ||
- @khanacademy/wonder-blocks-layout@3.0.3 | ||
- @khanacademy/wonder-blocks-typography@3.0.3 | ||
## 6.0.0 | ||
### Major Changes | ||
- 56d961f1: - Migrate Wonder Blocks components off old id providers and onto new `Id` component | ||
### Patch Changes | ||
- b6009b77: Deprecate the ID provider and unique ID utilities | ||
- Updated dependencies [b6009b77] | ||
- Updated dependencies [897686bc] | ||
- Updated dependencies [56d961f1] | ||
- @khanacademy/wonder-blocks-core@10.0.0 | ||
- @khanacademy/wonder-blocks-clickable@5.0.2 | ||
- @khanacademy/wonder-blocks-icon@5.0.2 | ||
- @khanacademy/wonder-blocks-layout@3.0.2 | ||
- @khanacademy/wonder-blocks-typography@3.0.2 | ||
## 5.0.2 | ||
### Patch Changes | ||
- 2a9c2fa8: Remove i18n reference from unit tests | ||
## 5.0.1 | ||
### Patch Changes | ||
- Updated dependencies [f4abd572] | ||
- @khanacademy/wonder-blocks-core@9.0.0 | ||
- @khanacademy/wonder-blocks-clickable@5.0.1 | ||
- @khanacademy/wonder-blocks-icon@5.0.1 | ||
- @khanacademy/wonder-blocks-layout@3.0.1 | ||
- @khanacademy/wonder-blocks-typography@3.0.1 | ||
## 5.0.0 | ||
### Major Changes | ||
- e6abdd17: Upgrade to React 18 | ||
### Patch Changes | ||
- Updated dependencies [e6abdd17] | ||
- @khanacademy/wonder-blocks-core@8.0.0 | ||
- @khanacademy/wonder-blocks-clickable@5.0.0 | ||
- @khanacademy/wonder-blocks-icon@5.0.0 | ||
- @khanacademy/wonder-blocks-layout@3.0.0 | ||
- @khanacademy/wonder-blocks-tokens@3.0.0 | ||
- @khanacademy/wonder-blocks-typography@3.0.0 | ||
## 4.11.0 | ||
### Minor Changes | ||
- 9ed7bd5b: Adds `instantValidation` prop for TextArea | ||
- cdcfe1ba: - TextArea and TextField: Adds `error` prop so that the components can be put in an error state explicitly. This is useful for backend validation errors after a form has already been submitted. | ||
- 486c6a80: - `TextField` | ||
- Add `instantValidation` prop | ||
- No longer calls `validate` prop if the field is disabled during initialization and on change | ||
- `TextArea` | ||
- Validate the value during initialization if the field is not disabled | ||
### Patch Changes | ||
- 21f6779a: Refactor TextField from class component to function component | ||
## 4.10.3 | ||
### Patch Changes | ||
- Updated dependencies [c1110599] | ||
- @khanacademy/wonder-blocks-icon@4.2.0 | ||
## 4.10.2 | ||
@@ -11,0 +145,0 @@ |
@@ -7,3 +7,3 @@ import * as React from "react"; | ||
declare const CheckboxCore: React.ForwardRefExoticComponent<Readonly<import("@khanacademy/wonder-blocks-core").AriaAttributes> & Readonly<{ | ||
role?: import("@khanacademy/wonder-blocks-core").AriaRole | undefined; | ||
role?: import("@khanacademy/wonder-blocks-core").AriaRole; | ||
}> & { | ||
@@ -13,7 +13,7 @@ checked: Checked; | ||
error: boolean; | ||
groupName?: string | undefined; | ||
id?: string | undefined; | ||
testId?: string | undefined; | ||
groupName?: string; | ||
id?: string; | ||
testId?: string; | ||
onClick: () => void; | ||
} & React.RefAttributes<HTMLInputElement>>; | ||
export default CheckboxCore; |
@@ -26,3 +26,3 @@ import * as React from "react"; | ||
declare const Checkbox: React.ForwardRefExoticComponent<Readonly<import("@khanacademy/wonder-blocks-core").AriaAttributes> & Readonly<{ | ||
role?: import("@khanacademy/wonder-blocks-core").AriaRole | undefined; | ||
role?: import("@khanacademy/wonder-blocks-core").AriaRole; | ||
}> & { | ||
@@ -36,7 +36,7 @@ /** | ||
*/ | ||
disabled?: boolean | undefined; | ||
disabled?: boolean; | ||
/** | ||
* Whether this component should show an error state | ||
*/ | ||
error?: boolean | undefined; | ||
error?: boolean; | ||
/** | ||
@@ -60,3 +60,3 @@ * Callback when this component is selected. The newCheckedState is the | ||
*/ | ||
id?: string | undefined; | ||
id?: string; | ||
/** | ||
@@ -69,7 +69,7 @@ * Optional styling for the container. Does not style the component. | ||
*/ | ||
className?: string | undefined; | ||
className?: string; | ||
/** | ||
* Optional test ID for e2e testing | ||
*/ | ||
testId?: string | undefined; | ||
testId?: string; | ||
/** | ||
@@ -80,4 +80,4 @@ * Name for the checkbox or radio button group. Only applicable for group | ||
*/ | ||
groupName?: string | undefined; | ||
groupName?: string; | ||
} & React.RefAttributes<HTMLInputElement>>; | ||
export default Checkbox; |
@@ -11,3 +11,3 @@ import * as React from "react"; | ||
*/ declare const ChoiceInternal: React.ForwardRefExoticComponent<Readonly<import("@khanacademy/wonder-blocks-core").AriaAttributes> & Readonly<{ | ||
role?: import("@khanacademy/wonder-blocks-core").AriaRole | undefined; | ||
role?: import("@khanacademy/wonder-blocks-core").AriaRole; | ||
}> & { | ||
@@ -17,5 +17,5 @@ /** Whether this choice is checked. */ | ||
/** Whether this choice option is disabled. */ | ||
disabled?: boolean | undefined; | ||
disabled?: boolean; | ||
/** Whether this choice is in error mode. */ | ||
error?: boolean | undefined; | ||
error?: boolean; | ||
/** Returns the new checked state of the component. */ | ||
@@ -27,3 +27,3 @@ onChange: (newCheckedState: boolean) => unknown; | ||
*/ | ||
id?: string | undefined; | ||
id?: string; | ||
/** | ||
@@ -36,7 +36,7 @@ * Optional additional styling. | ||
*/ | ||
className?: string | undefined; | ||
className?: string; | ||
/** | ||
* Optional id for testing purposes. | ||
*/ | ||
testId?: string | undefined; | ||
testId?: string; | ||
/** | ||
@@ -49,3 +49,3 @@ * Label for the field. | ||
/** Auto-populated by parent's groupName prop if in a group. */ | ||
groupName?: string | undefined; | ||
groupName?: string; | ||
/** Takes either "radio" or "checkbox" value. */ | ||
@@ -52,0 +52,0 @@ variant: "radio" | "checkbox"; |
@@ -70,3 +70,3 @@ import * as React from "react"; | ||
declare const Choice: React.ForwardRefExoticComponent<Readonly<import("@khanacademy/wonder-blocks-core").AriaAttributes> & Readonly<{ | ||
role?: import("@khanacademy/wonder-blocks-core").AriaRole | undefined; | ||
role?: import("@khanacademy/wonder-blocks-core").AriaRole; | ||
}> & { | ||
@@ -80,5 +80,5 @@ /** User-defined. Label for the field. */ | ||
/** User-defined. Whether this choice option is disabled. Default false. */ | ||
disabled?: boolean | undefined; | ||
disabled?: boolean; | ||
/** User-defined. Optional id for testing purposes. */ | ||
testId?: string | undefined; | ||
testId?: string; | ||
/** User-defined. Optional additional styling. */ | ||
@@ -90,3 +90,3 @@ style?: StyleType; | ||
*/ | ||
checked?: boolean | undefined; | ||
checked?: boolean; | ||
/** | ||
@@ -97,3 +97,3 @@ * Auto-populated by parent. Whether this choice is in error mode (everything | ||
*/ | ||
error?: boolean | undefined; | ||
error?: boolean; | ||
/** | ||
@@ -104,3 +104,3 @@ * Auto-populated by parent. Used for accessibility purposes, where the label | ||
*/ | ||
id?: string | undefined; | ||
id?: string; | ||
/** | ||
@@ -110,3 +110,3 @@ * Auto-populated by parent's groupName prop. | ||
*/ | ||
groupName?: string | undefined; | ||
groupName?: string; | ||
/** | ||
@@ -116,3 +116,3 @@ * Auto-populated by parent. Returns the new checked state of the component. | ||
*/ | ||
onChange?: ((newCheckedState: boolean) => unknown) | undefined; | ||
onChange?: (newCheckedState: boolean) => unknown; | ||
/** | ||
@@ -122,4 +122,4 @@ * Auto-populated by parent. | ||
*/ | ||
variant?: "checkbox" | "radio" | undefined; | ||
variant?: "radio" | "checkbox"; | ||
} & React.RefAttributes<HTMLInputElement>>; | ||
export default Choice; |
@@ -39,6 +39,2 @@ import * as React from "react"; | ||
testId?: string; | ||
/** | ||
* Change the field’s sub-components to fit a dark background. | ||
*/ | ||
light?: boolean; | ||
}; | ||
@@ -45,0 +41,0 @@ /** |
@@ -95,6 +95,2 @@ import * as React from "react"; | ||
/** | ||
* Change the field’s sub-components to fit a dark background. | ||
*/ | ||
light: boolean; | ||
/** | ||
* Custom styles for the container. | ||
@@ -141,3 +137,2 @@ * | ||
disabled: PropsWithForwardRef["disabled"]; | ||
light: PropsWithForwardRef["light"]; | ||
}; | ||
@@ -144,0 +139,0 @@ type State = { |
@@ -6,3 +6,3 @@ import * as React from "react"; | ||
*/ declare const RadioCore: React.ForwardRefExoticComponent<Readonly<import("@khanacademy/wonder-blocks-core").AriaAttributes> & Readonly<{ | ||
role?: import("@khanacademy/wonder-blocks-core").AriaRole | undefined; | ||
role?: import("@khanacademy/wonder-blocks-core").AriaRole; | ||
}> & { | ||
@@ -12,7 +12,7 @@ checked: Checked; | ||
error: boolean; | ||
groupName?: string | undefined; | ||
id?: string | undefined; | ||
testId?: string | undefined; | ||
groupName?: string; | ||
id?: string; | ||
testId?: string; | ||
onClick: () => void; | ||
} & React.RefAttributes<HTMLInputElement>>; | ||
export default RadioCore; |
@@ -10,3 +10,3 @@ import * as React from "react"; | ||
*/ declare const Radio: React.ForwardRefExoticComponent<Readonly<import("@khanacademy/wonder-blocks-core").AriaAttributes> & Readonly<{ | ||
role?: import("@khanacademy/wonder-blocks-core").AriaRole | undefined; | ||
role?: import("@khanacademy/wonder-blocks-core").AriaRole; | ||
}> & { | ||
@@ -20,7 +20,7 @@ /** | ||
*/ | ||
disabled?: boolean | undefined; | ||
disabled?: boolean; | ||
/** | ||
* Whether this component should show an error state | ||
*/ | ||
error?: boolean | undefined; | ||
error?: boolean; | ||
/** | ||
@@ -44,3 +44,3 @@ * Callback when this component is selected. The newCheckedState is the | ||
*/ | ||
id?: string | undefined; | ||
id?: string; | ||
/** | ||
@@ -53,7 +53,7 @@ * Optional styling for the container. Does not style the component. | ||
*/ | ||
className?: string | undefined; | ||
className?: string; | ||
/** | ||
* Optional test ID for e2e testing | ||
*/ | ||
testId?: string | undefined; | ||
testId?: string; | ||
/** | ||
@@ -64,4 +64,4 @@ * Name for the checkbox or radio button group. Only applicable for group | ||
*/ | ||
groupName?: string | undefined; | ||
groupName?: string; | ||
} & React.RefAttributes<HTMLInputElement>>; | ||
export default Radio; |
import * as React from "react"; | ||
import { StyleType } from "@khanacademy/wonder-blocks-core"; | ||
declare const TextArea: React.ForwardRefExoticComponent<Readonly<import("@khanacademy/wonder-blocks-core").AriaAttributes> & Readonly<{ | ||
role?: import("@khanacademy/wonder-blocks-core").AriaRole | undefined; | ||
role?: import("@khanacademy/wonder-blocks-core").AriaRole; | ||
}> & { | ||
@@ -18,7 +18,7 @@ /** | ||
*/ | ||
id?: string | undefined; | ||
id?: string; | ||
/** | ||
* Optional test ID for e2e testing. | ||
*/ | ||
testId?: string | undefined; | ||
testId?: string; | ||
/** | ||
@@ -37,15 +37,15 @@ * Custom styles for the textarea element. | ||
*/ | ||
placeholder?: string | undefined; | ||
placeholder?: string; | ||
/** | ||
* Whether the text area should be disabled. | ||
*/ | ||
disabled?: boolean | undefined; | ||
disabled?: boolean; | ||
/** | ||
* Specifies if the text area is read-only. | ||
*/ | ||
readOnly?: boolean | undefined; | ||
readOnly?: boolean; | ||
/** | ||
* Specifies if the text area allows autocomplete. | ||
*/ | ||
autoComplete?: "off" | "on" | undefined; | ||
autoComplete?: "on" | "off"; | ||
/** | ||
@@ -55,11 +55,11 @@ * The name for the text area control. This is submitted along with | ||
*/ | ||
name?: string | undefined; | ||
name?: string; | ||
/** | ||
* CSS classes for the textarea element. It is recommended that the style prop is used instead where possible | ||
*/ | ||
className?: string | undefined; | ||
className?: string; | ||
/** | ||
* Whether this textarea should autofocus on page load. | ||
*/ | ||
autoFocus?: boolean | undefined; | ||
autoFocus?: boolean; | ||
/** | ||
@@ -71,3 +71,3 @@ * The number of visible lines of text for the textarea. | ||
*/ | ||
rows?: number | undefined; | ||
rows?: number; | ||
/** | ||
@@ -81,3 +81,3 @@ * Determines if the textarea should be checked for spelling by the browser/OS. | ||
*/ | ||
spellCheck?: boolean | undefined; | ||
spellCheck?: boolean; | ||
/** | ||
@@ -88,11 +88,11 @@ * How the control should wrap the value for form submission. If not provided, | ||
*/ | ||
wrap?: "off" | "hard" | "soft" | undefined; | ||
wrap?: "hard" | "soft" | "off"; | ||
/** | ||
* The minimum number of characters allowed in the textarea. | ||
*/ | ||
minLength?: number | undefined; | ||
minLength?: number; | ||
/** | ||
* The maximum number of characters allowed in the textarea. | ||
*/ | ||
maxLength?: number | undefined; | ||
maxLength?: number; | ||
/** | ||
@@ -102,3 +102,3 @@ * Called when the textarea is clicked. | ||
*/ | ||
onClick?: React.MouseEventHandler<HTMLTextAreaElement> | undefined; | ||
onClick?: React.MouseEventHandler<HTMLTextAreaElement>; | ||
/** | ||
@@ -108,3 +108,3 @@ * Called when a key is pressed. | ||
*/ | ||
onKeyDown?: React.KeyboardEventHandler<HTMLTextAreaElement> | undefined; | ||
onKeyDown?: React.KeyboardEventHandler<HTMLTextAreaElement>; | ||
/** | ||
@@ -114,3 +114,3 @@ * Called when a key is released. | ||
*/ | ||
onKeyUp?: React.KeyboardEventHandler<HTMLTextAreaElement> | undefined; | ||
onKeyUp?: React.KeyboardEventHandler<HTMLTextAreaElement>; | ||
/** | ||
@@ -120,3 +120,3 @@ * Called when the element has been focused. | ||
*/ | ||
onFocus?: React.FocusEventHandler<HTMLTextAreaElement> | undefined; | ||
onFocus?: React.FocusEventHandler<HTMLTextAreaElement>; | ||
/** | ||
@@ -126,13 +126,30 @@ * Called when the element has been focused. | ||
*/ | ||
onBlur?: React.FocusEventHandler<HTMLTextAreaElement> | undefined; | ||
onBlur?: React.FocusEventHandler<HTMLTextAreaElement>; | ||
/** | ||
* Provide a validation for the textarea value. | ||
* Return a string error message or null | void for a valid input. | ||
* | ||
* Use this for errors that are shown to the user while they are filling out | ||
* a form. | ||
*/ | ||
validate?: ((value: string) => string | null | void) | undefined; | ||
validate?: (value: string) => string | null | void; | ||
/** | ||
* Called right after the textarea is validated. | ||
*/ | ||
onValidate?: ((errorMessage?: string | null | undefined) => unknown) | undefined; | ||
onValidate?: (errorMessage?: string | null | undefined) => unknown; | ||
/** | ||
* If true, textarea is validated as the user types (onChange). If false, | ||
* it is validated when the user's focus moves out of the field (onBlur). | ||
* It is preferred that instantValidation is set to `false`, however, it | ||
* defaults to `true` for backwards compatibility with existing implementations. | ||
*/ | ||
instantValidation?: boolean; | ||
/** | ||
* Whether the textarea is in an error state. | ||
* | ||
* Use this for errors that are triggered by something external to the | ||
* component (example: an error after form submission). | ||
*/ | ||
error?: boolean; | ||
/** | ||
* Whether this textarea is required to continue, or the error message to | ||
@@ -159,3 +176,3 @@ * render if this textarea is left blank. | ||
*/ | ||
required?: string | boolean | undefined; | ||
required?: boolean | string; | ||
/** | ||
@@ -165,8 +182,4 @@ * Specifies the resizing behaviour for the textarea. Defaults to both | ||
*/ | ||
resizeType?: "none" | "both" | "horizontal" | "vertical" | undefined; | ||
/** | ||
* Change the default focus ring color to fit a dark background. | ||
*/ | ||
light?: boolean | undefined; | ||
resizeType?: "horizontal" | "vertical" | "both" | "none"; | ||
} & React.RefAttributes<HTMLTextAreaElement>>; | ||
export default TextArea; |
@@ -34,6 +34,9 @@ import * as React from "react"; | ||
*/ | ||
disabled: boolean; | ||
disabled?: boolean; | ||
/** | ||
* Provide a validation for the input value. | ||
* Return a string error message or null | void for a valid input. | ||
* | ||
* Use this for errors that are shown to the user while they are filling out | ||
* a form. | ||
*/ | ||
@@ -46,2 +49,9 @@ validate?: (value: string) => string | null | void; | ||
/** | ||
* If true, TextField is validated as the user types (onChange). If false, | ||
* it is validated when the user's focus moves out of the field (onBlur). | ||
* It is preferred that instantValidation is set to `false`, however, it | ||
* defaults to `true` for backwards compatibility with existing implementations. | ||
*/ | ||
instantValidation?: boolean; | ||
/** | ||
* Called when the value has changed. | ||
@@ -67,2 +77,9 @@ */ | ||
/** | ||
* Whether the input is in an error state. | ||
* | ||
* Use this for errors that are triggered by something external to the | ||
* component (example: an error after form submission). | ||
*/ | ||
error?: boolean; | ||
/** | ||
* Whether this field is required to to continue, or the error message to | ||
@@ -91,6 +108,2 @@ * render if this field is left blank. | ||
/** | ||
* Change the default focus ring color to fit a dark background. | ||
*/ | ||
light: boolean; | ||
/** | ||
* Custom styles for the input. | ||
@@ -117,3 +130,3 @@ */ | ||
type OtherInputProps = CommonProps & { | ||
type: "text" | "password" | "email" | "tel"; | ||
type?: "text" | "password" | "email" | "tel"; | ||
}; | ||
@@ -139,28 +152,6 @@ export type NumericInputProps = { | ||
type PropsWithForwardRef = Props & WithForwardRef; | ||
type DefaultProps = { | ||
type: PropsWithForwardRef["type"]; | ||
disabled: PropsWithForwardRef["disabled"]; | ||
light: PropsWithForwardRef["light"]; | ||
}; | ||
type State = { | ||
/** | ||
* Displayed when the validation fails. | ||
*/ | ||
error: string | null | undefined; | ||
}; | ||
/** | ||
* A TextField is an element used to accept a single line of text from the user. | ||
*/ | ||
declare class TextField extends React.Component<PropsWithForwardRef, State> { | ||
static defaultProps: DefaultProps; | ||
constructor(props: PropsWithForwardRef); | ||
state: State; | ||
componentDidMount(): void; | ||
maybeValidate: (newValue: string) => void; | ||
handleChange: (event: React.ChangeEvent<HTMLInputElement>) => unknown; | ||
handleFocus: (event: React.FocusEvent<HTMLInputElement>) => unknown; | ||
handleBlur: (event: React.FocusEvent<HTMLInputElement>) => unknown; | ||
getStyles: () => StyleType; | ||
render(): React.ReactNode; | ||
} | ||
declare const TextField: (props: PropsWithForwardRef) => React.JSX.Element; | ||
type ExportProps = OmitConstrained<JSX.LibraryManagedAttributes<typeof TextField, React.ComponentProps<typeof TextField>>, "forwardedRef">; | ||
@@ -167,0 +158,0 @@ /** |
import _extends from '@babel/runtime/helpers/extends'; | ||
import * as React from 'react'; | ||
import { useId } from 'react'; | ||
import _objectWithoutPropertiesLoose from '@babel/runtime/helpers/objectWithoutPropertiesLoose'; | ||
import { StyleSheet } from 'aphrodite'; | ||
import { addStyle, UniqueIDProvider, View, IDProvider, useUniqueIdWithMock, useOnMountEffect } from '@khanacademy/wonder-blocks-core'; | ||
import { addStyle, Id, View, useOnMountEffect } from '@khanacademy/wonder-blocks-core'; | ||
import { Strut } from '@khanacademy/wonder-blocks-layout'; | ||
@@ -371,8 +372,6 @@ import { spacing, mix, color, border, font } from '@khanacademy/wonder-blocks-tokens'; | ||
const ChoiceCore = getChoiceCoreComponent(); | ||
return React.createElement(UniqueIDProvider, { | ||
mockOnFirstRender: true, | ||
scope: "choice" | ||
}, ids => { | ||
const uniqueId = id || ids.get("main"); | ||
const descriptionId = description ? ids.get("description") : undefined; | ||
return React.createElement(Id, { | ||
id: id | ||
}, uniqueId => { | ||
const descriptionId = description ? `${uniqueId}-description` : undefined; | ||
return React.createElement(View, { | ||
@@ -478,3 +477,4 @@ style: style, | ||
legend: { | ||
padding: 0 | ||
padding: 0, | ||
width: "100%" | ||
}, | ||
@@ -595,131 +595,139 @@ description: { | ||
const _excluded$2 = ["id", "type", "value", "name", "disabled", "onKeyDown", "placeholder", "style", "testId", "readOnly", "autoFocus", "autoComplete", "forwardedRef", "light", "onFocus", "onBlur", "onValidate", "validate", "onChange", "required"]; | ||
const defaultErrorMessage$1 = "This field is required."; | ||
const StyledInput = addStyle("input"); | ||
class TextField extends React.Component { | ||
constructor(props) { | ||
super(props); | ||
this.state = { | ||
error: null | ||
}; | ||
this.maybeValidate = newValue => { | ||
const { | ||
validate, | ||
onValidate, | ||
required | ||
} = this.props; | ||
if (validate) { | ||
const maybeError = validate(newValue) || null; | ||
this.setState({ | ||
error: maybeError | ||
}, () => { | ||
if (onValidate) { | ||
onValidate(maybeError); | ||
} | ||
}); | ||
} else if (required) { | ||
const requiredString = typeof required === "string" ? required : defaultErrorMessage$1; | ||
const maybeError = newValue ? null : requiredString; | ||
this.setState({ | ||
error: maybeError | ||
}, () => { | ||
if (onValidate) { | ||
onValidate(maybeError); | ||
} | ||
}); | ||
const defaultErrorMessage = "This field is required."; | ||
const useFieldValidation = ({ | ||
value, | ||
disabled: _disabled = false, | ||
validate, | ||
onValidate, | ||
required: _required = false, | ||
instantValidation: _instantValidation = true | ||
}) => { | ||
const [errorMessage, setErrorMessage] = React.useState(() => validate && value !== "" && !_disabled && validate(value) || null); | ||
const onChangeValidation = newValue => { | ||
if (_instantValidation) { | ||
handleValidation(newValue); | ||
} else { | ||
setErrorMessage(null); | ||
if (onValidate) { | ||
onValidate(null); | ||
} | ||
}; | ||
this.handleChange = event => { | ||
const { | ||
onChange | ||
} = this.props; | ||
const newValue = event.target.value; | ||
this.maybeValidate(newValue); | ||
onChange(newValue); | ||
}; | ||
this.handleFocus = event => { | ||
const { | ||
onFocus | ||
} = this.props; | ||
if (onFocus) { | ||
onFocus(event); | ||
} | ||
}; | ||
const onBlurValidation = newValue => { | ||
if (!_instantValidation) { | ||
if (newValue || _required) { | ||
handleValidation(newValue); | ||
} | ||
}; | ||
this.handleBlur = event => { | ||
const { | ||
onBlur | ||
} = this.props; | ||
if (onBlur) { | ||
onBlur(event); | ||
} | ||
}; | ||
const handleValidation = newValue => { | ||
if (_disabled) { | ||
return; | ||
} | ||
if (validate) { | ||
const error = validate(newValue) || null; | ||
setErrorMessage(error); | ||
if (onValidate) { | ||
onValidate(error); | ||
} | ||
}; | ||
this.getStyles = () => { | ||
const { | ||
disabled, | ||
light | ||
} = this.props; | ||
const { | ||
error | ||
} = this.state; | ||
const baseStyles = [styles$2.input, styles$7.LabelMedium]; | ||
const defaultStyles = [styles$2.default, !disabled && styles$2.defaultFocus, disabled && styles$2.disabled, !!error && styles$2.error]; | ||
const lightStyles = [styles$2.light, !disabled && styles$2.lightFocus, disabled && styles$2.lightDisabled, !!error && styles$2.lightError]; | ||
return [...baseStyles, ...(light ? lightStyles : defaultStyles)]; | ||
}; | ||
if (props.validate && props.value !== "") { | ||
this.state.error = props.validate(props.value) || null; | ||
} else if (_required) { | ||
const requiredString = typeof _required === "string" ? _required : defaultErrorMessage; | ||
const error = newValue ? null : requiredString; | ||
setErrorMessage(error); | ||
if (onValidate) { | ||
onValidate(error); | ||
} | ||
} | ||
} | ||
componentDidMount() { | ||
if (this.props.value !== "") { | ||
this.maybeValidate(this.props.value); | ||
}; | ||
useOnMountEffect(() => { | ||
if (value !== "") { | ||
handleValidation(value); | ||
} | ||
} | ||
render() { | ||
const _this$props = this.props, | ||
{ | ||
id, | ||
type, | ||
value, | ||
name, | ||
disabled, | ||
onKeyDown, | ||
placeholder, | ||
style, | ||
testId, | ||
readOnly, | ||
autoFocus, | ||
autoComplete, | ||
forwardedRef | ||
} = _this$props, | ||
otherProps = _objectWithoutPropertiesLoose(_this$props, _excluded$2); | ||
return React.createElement(IDProvider, { | ||
id: id, | ||
scope: "text-field" | ||
}, uniqueId => React.createElement(StyledInput, _extends({ | ||
style: [this.getStyles(), style], | ||
id: uniqueId, | ||
type: type, | ||
placeholder: placeholder, | ||
value: value, | ||
name: name, | ||
"aria-disabled": disabled, | ||
onChange: this.handleChange, | ||
onKeyDown: disabled ? undefined : onKeyDown, | ||
onFocus: this.handleFocus, | ||
onBlur: this.handleBlur, | ||
"data-testid": testId, | ||
readOnly: readOnly || disabled, | ||
autoFocus: autoFocus, | ||
autoComplete: autoComplete, | ||
ref: forwardedRef, | ||
"aria-invalid": this.state.error ? "true" : "false" | ||
}, otherProps))); | ||
} | ||
} | ||
TextField.defaultProps = { | ||
type: "text", | ||
disabled: false, | ||
light: false | ||
}); | ||
return { | ||
errorMessage, | ||
onBlurValidation, | ||
onChangeValidation | ||
}; | ||
}; | ||
const _excluded$2 = ["id", "type", "value", "name", "disabled", "error", "validate", "onValidate", "required", "placeholder", "style", "testId", "readOnly", "autoFocus", "autoComplete", "forwardedRef", "instantValidation", "onKeyDown", "onChange", "onFocus", "onBlur"]; | ||
const StyledInput = addStyle("input"); | ||
const TextField = props => { | ||
const { | ||
id, | ||
type = "text", | ||
value, | ||
name, | ||
disabled = false, | ||
error, | ||
validate, | ||
onValidate, | ||
required, | ||
placeholder, | ||
style, | ||
testId, | ||
readOnly, | ||
autoFocus, | ||
autoComplete, | ||
forwardedRef, | ||
instantValidation = true, | ||
onKeyDown, | ||
onChange, | ||
onFocus, | ||
onBlur | ||
} = props, | ||
otherProps = _objectWithoutPropertiesLoose(props, _excluded$2); | ||
const { | ||
errorMessage, | ||
onBlurValidation, | ||
onChangeValidation | ||
} = useFieldValidation({ | ||
value, | ||
required, | ||
disabled, | ||
instantValidation, | ||
validate, | ||
onValidate | ||
}); | ||
const hasError = error || !!errorMessage; | ||
const handleChange = event => { | ||
const newValue = event.target.value; | ||
onChangeValidation(newValue); | ||
onChange(newValue); | ||
}; | ||
const handleFocus = event => { | ||
if (onFocus) { | ||
onFocus(event); | ||
} | ||
}; | ||
const handleBlur = event => { | ||
onBlurValidation(event.target.value); | ||
if (onBlur) { | ||
onBlur(event); | ||
} | ||
}; | ||
return React.createElement(Id, { | ||
id: id | ||
}, uniqueId => React.createElement(StyledInput, _extends({ | ||
style: [styles$2.input, styles$7.LabelMedium, styles$2.default, !disabled && styles$2.defaultFocus, disabled && styles$2.disabled, hasError && styles$2.error, style], | ||
id: uniqueId, | ||
type: type, | ||
placeholder: placeholder, | ||
value: value, | ||
name: name, | ||
"aria-disabled": disabled, | ||
"aria-required": !!required, | ||
onChange: handleChange, | ||
onKeyDown: disabled ? undefined : onKeyDown, | ||
onFocus: handleFocus, | ||
onBlur: handleBlur, | ||
"data-testid": testId, | ||
readOnly: readOnly || disabled, | ||
autoFocus: autoFocus, | ||
autoComplete: autoComplete, | ||
ref: forwardedRef, | ||
"aria-invalid": hasError | ||
}, otherProps))); | ||
}; | ||
const styles$2 = StyleSheet.create({ | ||
@@ -773,45 +781,2 @@ input: { | ||
} | ||
}, | ||
light: { | ||
background: color.white, | ||
border: `1px solid ${color.offBlack16}`, | ||
color: color.offBlack, | ||
"::placeholder": { | ||
color: color.offBlack64 | ||
} | ||
}, | ||
lightFocus: { | ||
":focus-visible": { | ||
outline: `3px solid ${color.blue}`, | ||
outlineOffset: "-4px", | ||
borderColor: color.white | ||
} | ||
}, | ||
lightDisabled: { | ||
backgroundColor: "transparent", | ||
border: `1px solid ${color.white32}`, | ||
color: color.white64, | ||
"::placeholder": { | ||
color: color.white64 | ||
}, | ||
cursor: "not-allowed", | ||
":focus-visible": { | ||
borderColor: mix(color.white32, color.blue), | ||
outline: `3px solid ${color.fadedBlue}`, | ||
outlineOffset: "-4px" | ||
} | ||
}, | ||
lightError: { | ||
background: color.fadedRed8, | ||
border: `1px solid ${color.white}`, | ||
outline: `2px solid ${color.red}`, | ||
outlineOffset: "-3px", | ||
color: color.offBlack, | ||
"::placeholder": { | ||
color: color.offBlack64 | ||
}, | ||
":focus-visible": { | ||
outline: `3px solid ${color.red}`, | ||
outlineOffset: "-4px" | ||
} | ||
} | ||
@@ -830,11 +795,10 @@ }); | ||
required, | ||
testId, | ||
light | ||
testId | ||
} = this.props; | ||
const requiredIcon = React.createElement(StyledSpan, { | ||
style: light ? styles$1.lightRequired : styles$1.required, | ||
style: styles$1.required, | ||
"aria-hidden": true | ||
}, " ", "*"); | ||
return React.createElement(React.Fragment, null, React.createElement(LabelMedium, { | ||
style: light ? styles$1.lightLabel : styles$1.label, | ||
style: styles$1.label, | ||
tag: "label", | ||
@@ -850,4 +814,3 @@ htmlFor: id && `${id}-field`, | ||
description, | ||
testId, | ||
light | ||
testId | ||
} = this.props; | ||
@@ -858,3 +821,3 @@ if (!description) { | ||
return React.createElement(React.Fragment, null, React.createElement(LabelSmall, { | ||
style: light ? styles$1.lightDescription : styles$1.description, | ||
style: styles$1.description, | ||
testId: testId && `${testId}-description` | ||
@@ -869,4 +832,3 @@ }, description), React.createElement(Strut, { | ||
id, | ||
testId, | ||
light | ||
testId | ||
} = this.props; | ||
@@ -879,3 +841,3 @@ if (!error) { | ||
}), React.createElement(LabelSmall, { | ||
style: light ? styles$1.lightError : styles$1.error, | ||
style: styles$1.error, | ||
role: "alert", | ||
@@ -902,26 +864,14 @@ id: id && `${id}-error`, | ||
}, | ||
lightLabel: { | ||
color: color.white | ||
}, | ||
description: { | ||
color: color.offBlack64 | ||
}, | ||
lightDescription: { | ||
color: color.white64 | ||
}, | ||
error: { | ||
color: color.red | ||
}, | ||
lightError: { | ||
color: color.fadedRed | ||
}, | ||
required: { | ||
color: color.red | ||
}, | ||
lightRequired: { | ||
color: color.fadedRed | ||
} | ||
}); | ||
const _excluded$1 = ["id", "type", "label", "description", "value", "disabled", "required", "validate", "onChange", "onKeyDown", "placeholder", "light", "style", "testId", "readOnly", "autoComplete", "forwardedRef", "ariaDescribedby", "name", "onValidate", "onFocus", "onBlur"]; | ||
const _excluded$1 = ["id", "type", "label", "description", "value", "disabled", "required", "validate", "onChange", "onKeyDown", "placeholder", "style", "testId", "readOnly", "autoComplete", "forwardedRef", "ariaDescribedby", "name", "onValidate", "onFocus", "onBlur"]; | ||
class LabeledTextField extends React.Component { | ||
@@ -985,3 +935,2 @@ constructor(props) { | ||
placeholder, | ||
light, | ||
style, | ||
@@ -996,5 +945,4 @@ testId, | ||
otherProps = _objectWithoutPropertiesLoose(_this$props, _excluded$1); | ||
return React.createElement(IDProvider, { | ||
id: id, | ||
scope: "labeled-text-field" | ||
return React.createElement(Id, { | ||
id: id | ||
}, uniqueId => React.createElement(FieldHeading, { | ||
@@ -1004,3 +952,2 @@ id: uniqueId, | ||
style: style, | ||
light: light, | ||
field: React.createElement(TextField$1, _extends({ | ||
@@ -1022,3 +969,2 @@ id: `${uniqueId}-field`, | ||
onBlur: this.handleBlur, | ||
light: light, | ||
readOnly: readOnly, | ||
@@ -1038,4 +984,3 @@ autoComplete: autoComplete, | ||
type: "text", | ||
disabled: false, | ||
light: false | ||
disabled: false | ||
}; | ||
@@ -1046,4 +991,3 @@ var labeledTextField = React.forwardRef((props, ref) => React.createElement(LabeledTextField, _extends({}, props, { | ||
const _excluded = ["onChange", "value", "placeholder", "disabled", "id", "testId", "style", "readOnly", "autoComplete", "name", "className", "autoFocus", "rows", "spellCheck", "wrap", "minLength", "maxLength", "onClick", "onKeyDown", "onKeyUp", "onFocus", "onBlur", "validate", "onValidate", "required", "resizeType", "light", "rootStyle"]; | ||
const defaultErrorMessage = "This field is required."; | ||
const _excluded = ["onChange", "value", "placeholder", "disabled", "id", "testId", "style", "readOnly", "autoComplete", "name", "className", "autoFocus", "rows", "spellCheck", "wrap", "minLength", "maxLength", "onClick", "onKeyDown", "onKeyUp", "onFocus", "onBlur", "validate", "onValidate", "required", "resizeType", "rootStyle", "error", "instantValidation"]; | ||
const StyledTextArea = addStyle("textarea"); | ||
@@ -1078,41 +1022,33 @@ const TextArea = React.forwardRef(function TextArea(props, ref) { | ||
resizeType, | ||
light, | ||
rootStyle | ||
rootStyle, | ||
error, | ||
instantValidation = true | ||
} = props, | ||
otherProps = _objectWithoutPropertiesLoose(props, _excluded); | ||
const [error, setError] = React.useState(null); | ||
const ids = useUniqueIdWithMock("text-area"); | ||
const uniqueId = id != null ? id : ids.get("id"); | ||
const { | ||
errorMessage, | ||
onBlurValidation, | ||
onChangeValidation | ||
} = useFieldValidation({ | ||
value, | ||
disabled, | ||
validate, | ||
onValidate, | ||
required, | ||
instantValidation | ||
}); | ||
const hasError = error || !!errorMessage; | ||
const generatedUniqueId = useId(); | ||
const uniqueId = id != null ? id : generatedUniqueId; | ||
const handleChange = event => { | ||
const newValue = event.target.value; | ||
onChangeValidation(newValue); | ||
onChange(newValue); | ||
handleValidation(newValue); | ||
}; | ||
const handleValidation = newValue => { | ||
if (validate) { | ||
const error = validate(newValue) || null; | ||
setError(error); | ||
if (onValidate) { | ||
onValidate(error); | ||
} | ||
} else if (required) { | ||
const requiredString = typeof required === "string" ? required : defaultErrorMessage; | ||
const error = newValue ? null : requiredString; | ||
setError(error); | ||
if (onValidate) { | ||
onValidate(error); | ||
} | ||
const handleBlur = event => { | ||
onBlurValidation(event.target.value); | ||
if (onBlur) { | ||
onBlur(event); | ||
} | ||
}; | ||
useOnMountEffect(() => { | ||
if (value !== "") { | ||
handleValidation(value); | ||
} | ||
}); | ||
const getStyles = () => { | ||
const baseStyles = [styles.textarea, styles$7.LabelMedium, resizeType && resizeStyles[resizeType]]; | ||
const defaultStyles = [styles.default, !disabled && styles.defaultFocus, disabled && styles.disabled, !!error && styles.error]; | ||
const lightStyles = [styles.light, !disabled && styles.lightFocus, disabled && styles.lightDisabled, !!error && styles.lightError]; | ||
return [...baseStyles, ...(light ? lightStyles : defaultStyles)]; | ||
}; | ||
return React.createElement(View, { | ||
@@ -1127,3 +1063,3 @@ style: [{ | ||
className: className, | ||
style: [getStyles(), style], | ||
style: [styles.textarea, styles$7.LabelMedium, resizeType && resizeStyles[resizeType], styles.default, !disabled && styles.defaultFocus, disabled && styles.disabled, hasError && styles.error, style], | ||
value: value, | ||
@@ -1142,2 +1078,3 @@ onChange: handleChange, | ||
maxLength: maxLength, | ||
"aria-required": !!required, | ||
onClick: disabled ? undefined : onClick, | ||
@@ -1147,6 +1084,6 @@ onKeyDown: disabled ? undefined : onKeyDown, | ||
onFocus: onFocus, | ||
onBlur: onBlur, | ||
onBlur: handleBlur, | ||
required: !!required | ||
}, otherProps, { | ||
"aria-invalid": !!error | ||
"aria-invalid": hasError | ||
}))); | ||
@@ -1201,45 +1138,2 @@ }); | ||
} | ||
}, | ||
light: { | ||
background: color.white, | ||
border: `1px solid ${color.offBlack16}`, | ||
color: color.offBlack, | ||
"::placeholder": { | ||
color: color.offBlack64 | ||
} | ||
}, | ||
lightFocus: { | ||
":focus-visible": { | ||
outline: `3px solid ${color.blue}`, | ||
outlineOffset: "-4px", | ||
borderColor: color.white | ||
} | ||
}, | ||
lightDisabled: { | ||
backgroundColor: "transparent", | ||
border: `1px solid ${color.white32}`, | ||
color: color.white64, | ||
"::placeholder": { | ||
color: color.white64 | ||
}, | ||
cursor: "not-allowed", | ||
":focus-visible": { | ||
borderColor: mix(color.white32, color.blue), | ||
outline: `3px solid ${color.fadedBlue}`, | ||
outlineOffset: "-4px" | ||
} | ||
}, | ||
lightError: { | ||
background: color.fadedRed8, | ||
border: `1px solid ${color.white}`, | ||
outline: `2px solid ${color.red}`, | ||
outlineOffset: "-3px", | ||
color: color.offBlack, | ||
"::placeholder": { | ||
color: color.offBlack64 | ||
}, | ||
":focus-visible": { | ||
outline: `3px solid ${color.red}`, | ||
outlineOffset: "-4px" | ||
} | ||
} | ||
@@ -1246,0 +1140,0 @@ }); |
@@ -401,8 +401,6 @@ 'use strict'; | ||
const ChoiceCore = getChoiceCoreComponent(); | ||
return React__namespace.createElement(wonderBlocksCore.UniqueIDProvider, { | ||
mockOnFirstRender: true, | ||
scope: "choice" | ||
}, ids => { | ||
const uniqueId = id || ids.get("main"); | ||
const descriptionId = description ? ids.get("description") : undefined; | ||
return React__namespace.createElement(wonderBlocksCore.Id, { | ||
id: id | ||
}, uniqueId => { | ||
const descriptionId = description ? `${uniqueId}-description` : undefined; | ||
return React__namespace.createElement(wonderBlocksCore.View, { | ||
@@ -508,3 +506,4 @@ style: style, | ||
legend: { | ||
padding: 0 | ||
padding: 0, | ||
width: "100%" | ||
}, | ||
@@ -625,131 +624,139 @@ description: { | ||
const _excluded$2 = ["id", "type", "value", "name", "disabled", "onKeyDown", "placeholder", "style", "testId", "readOnly", "autoFocus", "autoComplete", "forwardedRef", "light", "onFocus", "onBlur", "onValidate", "validate", "onChange", "required"]; | ||
const defaultErrorMessage$1 = "This field is required."; | ||
const StyledInput = wonderBlocksCore.addStyle("input"); | ||
class TextField extends React__namespace.Component { | ||
constructor(props) { | ||
super(props); | ||
this.state = { | ||
error: null | ||
}; | ||
this.maybeValidate = newValue => { | ||
const { | ||
validate, | ||
onValidate, | ||
required | ||
} = this.props; | ||
if (validate) { | ||
const maybeError = validate(newValue) || null; | ||
this.setState({ | ||
error: maybeError | ||
}, () => { | ||
if (onValidate) { | ||
onValidate(maybeError); | ||
} | ||
}); | ||
} else if (required) { | ||
const requiredString = typeof required === "string" ? required : defaultErrorMessage$1; | ||
const maybeError = newValue ? null : requiredString; | ||
this.setState({ | ||
error: maybeError | ||
}, () => { | ||
if (onValidate) { | ||
onValidate(maybeError); | ||
} | ||
}); | ||
const defaultErrorMessage = "This field is required."; | ||
const useFieldValidation = ({ | ||
value, | ||
disabled: _disabled = false, | ||
validate, | ||
onValidate, | ||
required: _required = false, | ||
instantValidation: _instantValidation = true | ||
}) => { | ||
const [errorMessage, setErrorMessage] = React__namespace.useState(() => validate && value !== "" && !_disabled && validate(value) || null); | ||
const onChangeValidation = newValue => { | ||
if (_instantValidation) { | ||
handleValidation(newValue); | ||
} else { | ||
setErrorMessage(null); | ||
if (onValidate) { | ||
onValidate(null); | ||
} | ||
}; | ||
this.handleChange = event => { | ||
const { | ||
onChange | ||
} = this.props; | ||
const newValue = event.target.value; | ||
this.maybeValidate(newValue); | ||
onChange(newValue); | ||
}; | ||
this.handleFocus = event => { | ||
const { | ||
onFocus | ||
} = this.props; | ||
if (onFocus) { | ||
onFocus(event); | ||
} | ||
}; | ||
const onBlurValidation = newValue => { | ||
if (!_instantValidation) { | ||
if (newValue || _required) { | ||
handleValidation(newValue); | ||
} | ||
}; | ||
this.handleBlur = event => { | ||
const { | ||
onBlur | ||
} = this.props; | ||
if (onBlur) { | ||
onBlur(event); | ||
} | ||
}; | ||
const handleValidation = newValue => { | ||
if (_disabled) { | ||
return; | ||
} | ||
if (validate) { | ||
const error = validate(newValue) || null; | ||
setErrorMessage(error); | ||
if (onValidate) { | ||
onValidate(error); | ||
} | ||
}; | ||
this.getStyles = () => { | ||
const { | ||
disabled, | ||
light | ||
} = this.props; | ||
const { | ||
error | ||
} = this.state; | ||
const baseStyles = [styles$2.input, wonderBlocksTypography.styles.LabelMedium]; | ||
const defaultStyles = [styles$2.default, !disabled && styles$2.defaultFocus, disabled && styles$2.disabled, !!error && styles$2.error]; | ||
const lightStyles = [styles$2.light, !disabled && styles$2.lightFocus, disabled && styles$2.lightDisabled, !!error && styles$2.lightError]; | ||
return [...baseStyles, ...(light ? lightStyles : defaultStyles)]; | ||
}; | ||
if (props.validate && props.value !== "") { | ||
this.state.error = props.validate(props.value) || null; | ||
} else if (_required) { | ||
const requiredString = typeof _required === "string" ? _required : defaultErrorMessage; | ||
const error = newValue ? null : requiredString; | ||
setErrorMessage(error); | ||
if (onValidate) { | ||
onValidate(error); | ||
} | ||
} | ||
} | ||
componentDidMount() { | ||
if (this.props.value !== "") { | ||
this.maybeValidate(this.props.value); | ||
}; | ||
wonderBlocksCore.useOnMountEffect(() => { | ||
if (value !== "") { | ||
handleValidation(value); | ||
} | ||
} | ||
render() { | ||
const _this$props = this.props, | ||
{ | ||
id, | ||
type, | ||
value, | ||
name, | ||
disabled, | ||
onKeyDown, | ||
placeholder, | ||
style, | ||
testId, | ||
readOnly, | ||
autoFocus, | ||
autoComplete, | ||
forwardedRef | ||
} = _this$props, | ||
otherProps = _objectWithoutPropertiesLoose__default["default"](_this$props, _excluded$2); | ||
return React__namespace.createElement(wonderBlocksCore.IDProvider, { | ||
id: id, | ||
scope: "text-field" | ||
}, uniqueId => React__namespace.createElement(StyledInput, _extends__default["default"]({ | ||
style: [this.getStyles(), style], | ||
id: uniqueId, | ||
type: type, | ||
placeholder: placeholder, | ||
value: value, | ||
name: name, | ||
"aria-disabled": disabled, | ||
onChange: this.handleChange, | ||
onKeyDown: disabled ? undefined : onKeyDown, | ||
onFocus: this.handleFocus, | ||
onBlur: this.handleBlur, | ||
"data-testid": testId, | ||
readOnly: readOnly || disabled, | ||
autoFocus: autoFocus, | ||
autoComplete: autoComplete, | ||
ref: forwardedRef, | ||
"aria-invalid": this.state.error ? "true" : "false" | ||
}, otherProps))); | ||
} | ||
} | ||
TextField.defaultProps = { | ||
type: "text", | ||
disabled: false, | ||
light: false | ||
}); | ||
return { | ||
errorMessage, | ||
onBlurValidation, | ||
onChangeValidation | ||
}; | ||
}; | ||
const _excluded$2 = ["id", "type", "value", "name", "disabled", "error", "validate", "onValidate", "required", "placeholder", "style", "testId", "readOnly", "autoFocus", "autoComplete", "forwardedRef", "instantValidation", "onKeyDown", "onChange", "onFocus", "onBlur"]; | ||
const StyledInput = wonderBlocksCore.addStyle("input"); | ||
const TextField = props => { | ||
const { | ||
id, | ||
type = "text", | ||
value, | ||
name, | ||
disabled = false, | ||
error, | ||
validate, | ||
onValidate, | ||
required, | ||
placeholder, | ||
style, | ||
testId, | ||
readOnly, | ||
autoFocus, | ||
autoComplete, | ||
forwardedRef, | ||
instantValidation = true, | ||
onKeyDown, | ||
onChange, | ||
onFocus, | ||
onBlur | ||
} = props, | ||
otherProps = _objectWithoutPropertiesLoose__default["default"](props, _excluded$2); | ||
const { | ||
errorMessage, | ||
onBlurValidation, | ||
onChangeValidation | ||
} = useFieldValidation({ | ||
value, | ||
required, | ||
disabled, | ||
instantValidation, | ||
validate, | ||
onValidate | ||
}); | ||
const hasError = error || !!errorMessage; | ||
const handleChange = event => { | ||
const newValue = event.target.value; | ||
onChangeValidation(newValue); | ||
onChange(newValue); | ||
}; | ||
const handleFocus = event => { | ||
if (onFocus) { | ||
onFocus(event); | ||
} | ||
}; | ||
const handleBlur = event => { | ||
onBlurValidation(event.target.value); | ||
if (onBlur) { | ||
onBlur(event); | ||
} | ||
}; | ||
return React__namespace.createElement(wonderBlocksCore.Id, { | ||
id: id | ||
}, uniqueId => React__namespace.createElement(StyledInput, _extends__default["default"]({ | ||
style: [styles$2.input, wonderBlocksTypography.styles.LabelMedium, styles$2.default, !disabled && styles$2.defaultFocus, disabled && styles$2.disabled, hasError && styles$2.error, style], | ||
id: uniqueId, | ||
type: type, | ||
placeholder: placeholder, | ||
value: value, | ||
name: name, | ||
"aria-disabled": disabled, | ||
"aria-required": !!required, | ||
onChange: handleChange, | ||
onKeyDown: disabled ? undefined : onKeyDown, | ||
onFocus: handleFocus, | ||
onBlur: handleBlur, | ||
"data-testid": testId, | ||
readOnly: readOnly || disabled, | ||
autoFocus: autoFocus, | ||
autoComplete: autoComplete, | ||
ref: forwardedRef, | ||
"aria-invalid": hasError | ||
}, otherProps))); | ||
}; | ||
const styles$2 = aphrodite.StyleSheet.create({ | ||
@@ -803,45 +810,2 @@ input: { | ||
} | ||
}, | ||
light: { | ||
background: wonderBlocksTokens.color.white, | ||
border: `1px solid ${wonderBlocksTokens.color.offBlack16}`, | ||
color: wonderBlocksTokens.color.offBlack, | ||
"::placeholder": { | ||
color: wonderBlocksTokens.color.offBlack64 | ||
} | ||
}, | ||
lightFocus: { | ||
":focus-visible": { | ||
outline: `3px solid ${wonderBlocksTokens.color.blue}`, | ||
outlineOffset: "-4px", | ||
borderColor: wonderBlocksTokens.color.white | ||
} | ||
}, | ||
lightDisabled: { | ||
backgroundColor: "transparent", | ||
border: `1px solid ${wonderBlocksTokens.color.white32}`, | ||
color: wonderBlocksTokens.color.white64, | ||
"::placeholder": { | ||
color: wonderBlocksTokens.color.white64 | ||
}, | ||
cursor: "not-allowed", | ||
":focus-visible": { | ||
borderColor: wonderBlocksTokens.mix(wonderBlocksTokens.color.white32, wonderBlocksTokens.color.blue), | ||
outline: `3px solid ${wonderBlocksTokens.color.fadedBlue}`, | ||
outlineOffset: "-4px" | ||
} | ||
}, | ||
lightError: { | ||
background: wonderBlocksTokens.color.fadedRed8, | ||
border: `1px solid ${wonderBlocksTokens.color.white}`, | ||
outline: `2px solid ${wonderBlocksTokens.color.red}`, | ||
outlineOffset: "-3px", | ||
color: wonderBlocksTokens.color.offBlack, | ||
"::placeholder": { | ||
color: wonderBlocksTokens.color.offBlack64 | ||
}, | ||
":focus-visible": { | ||
outline: `3px solid ${wonderBlocksTokens.color.red}`, | ||
outlineOffset: "-4px" | ||
} | ||
} | ||
@@ -860,11 +824,10 @@ }); | ||
required, | ||
testId, | ||
light | ||
testId | ||
} = this.props; | ||
const requiredIcon = React__namespace.createElement(StyledSpan, { | ||
style: light ? styles$1.lightRequired : styles$1.required, | ||
style: styles$1.required, | ||
"aria-hidden": true | ||
}, " ", "*"); | ||
return React__namespace.createElement(React__namespace.Fragment, null, React__namespace.createElement(wonderBlocksTypography.LabelMedium, { | ||
style: light ? styles$1.lightLabel : styles$1.label, | ||
style: styles$1.label, | ||
tag: "label", | ||
@@ -880,4 +843,3 @@ htmlFor: id && `${id}-field`, | ||
description, | ||
testId, | ||
light | ||
testId | ||
} = this.props; | ||
@@ -888,3 +850,3 @@ if (!description) { | ||
return React__namespace.createElement(React__namespace.Fragment, null, React__namespace.createElement(wonderBlocksTypography.LabelSmall, { | ||
style: light ? styles$1.lightDescription : styles$1.description, | ||
style: styles$1.description, | ||
testId: testId && `${testId}-description` | ||
@@ -899,4 +861,3 @@ }, description), React__namespace.createElement(wonderBlocksLayout.Strut, { | ||
id, | ||
testId, | ||
light | ||
testId | ||
} = this.props; | ||
@@ -909,3 +870,3 @@ if (!error) { | ||
}), React__namespace.createElement(wonderBlocksTypography.LabelSmall, { | ||
style: light ? styles$1.lightError : styles$1.error, | ||
style: styles$1.error, | ||
role: "alert", | ||
@@ -932,26 +893,14 @@ id: id && `${id}-error`, | ||
}, | ||
lightLabel: { | ||
color: wonderBlocksTokens.color.white | ||
}, | ||
description: { | ||
color: wonderBlocksTokens.color.offBlack64 | ||
}, | ||
lightDescription: { | ||
color: wonderBlocksTokens.color.white64 | ||
}, | ||
error: { | ||
color: wonderBlocksTokens.color.red | ||
}, | ||
lightError: { | ||
color: wonderBlocksTokens.color.fadedRed | ||
}, | ||
required: { | ||
color: wonderBlocksTokens.color.red | ||
}, | ||
lightRequired: { | ||
color: wonderBlocksTokens.color.fadedRed | ||
} | ||
}); | ||
const _excluded$1 = ["id", "type", "label", "description", "value", "disabled", "required", "validate", "onChange", "onKeyDown", "placeholder", "light", "style", "testId", "readOnly", "autoComplete", "forwardedRef", "ariaDescribedby", "name", "onValidate", "onFocus", "onBlur"]; | ||
const _excluded$1 = ["id", "type", "label", "description", "value", "disabled", "required", "validate", "onChange", "onKeyDown", "placeholder", "style", "testId", "readOnly", "autoComplete", "forwardedRef", "ariaDescribedby", "name", "onValidate", "onFocus", "onBlur"]; | ||
class LabeledTextField extends React__namespace.Component { | ||
@@ -1015,3 +964,2 @@ constructor(props) { | ||
placeholder, | ||
light, | ||
style, | ||
@@ -1026,5 +974,4 @@ testId, | ||
otherProps = _objectWithoutPropertiesLoose__default["default"](_this$props, _excluded$1); | ||
return React__namespace.createElement(wonderBlocksCore.IDProvider, { | ||
id: id, | ||
scope: "labeled-text-field" | ||
return React__namespace.createElement(wonderBlocksCore.Id, { | ||
id: id | ||
}, uniqueId => React__namespace.createElement(FieldHeading, { | ||
@@ -1034,3 +981,2 @@ id: uniqueId, | ||
style: style, | ||
light: light, | ||
field: React__namespace.createElement(TextField$1, _extends__default["default"]({ | ||
@@ -1052,3 +998,2 @@ id: `${uniqueId}-field`, | ||
onBlur: this.handleBlur, | ||
light: light, | ||
readOnly: readOnly, | ||
@@ -1068,4 +1013,3 @@ autoComplete: autoComplete, | ||
type: "text", | ||
disabled: false, | ||
light: false | ||
disabled: false | ||
}; | ||
@@ -1076,4 +1020,3 @@ var labeledTextField = React__namespace.forwardRef((props, ref) => React__namespace.createElement(LabeledTextField, _extends__default["default"]({}, props, { | ||
const _excluded = ["onChange", "value", "placeholder", "disabled", "id", "testId", "style", "readOnly", "autoComplete", "name", "className", "autoFocus", "rows", "spellCheck", "wrap", "minLength", "maxLength", "onClick", "onKeyDown", "onKeyUp", "onFocus", "onBlur", "validate", "onValidate", "required", "resizeType", "light", "rootStyle"]; | ||
const defaultErrorMessage = "This field is required."; | ||
const _excluded = ["onChange", "value", "placeholder", "disabled", "id", "testId", "style", "readOnly", "autoComplete", "name", "className", "autoFocus", "rows", "spellCheck", "wrap", "minLength", "maxLength", "onClick", "onKeyDown", "onKeyUp", "onFocus", "onBlur", "validate", "onValidate", "required", "resizeType", "rootStyle", "error", "instantValidation"]; | ||
const StyledTextArea = wonderBlocksCore.addStyle("textarea"); | ||
@@ -1108,41 +1051,33 @@ const TextArea = React__namespace.forwardRef(function TextArea(props, ref) { | ||
resizeType, | ||
light, | ||
rootStyle | ||
rootStyle, | ||
error, | ||
instantValidation = true | ||
} = props, | ||
otherProps = _objectWithoutPropertiesLoose__default["default"](props, _excluded); | ||
const [error, setError] = React__namespace.useState(null); | ||
const ids = wonderBlocksCore.useUniqueIdWithMock("text-area"); | ||
const uniqueId = id != null ? id : ids.get("id"); | ||
const { | ||
errorMessage, | ||
onBlurValidation, | ||
onChangeValidation | ||
} = useFieldValidation({ | ||
value, | ||
disabled, | ||
validate, | ||
onValidate, | ||
required, | ||
instantValidation | ||
}); | ||
const hasError = error || !!errorMessage; | ||
const generatedUniqueId = React.useId(); | ||
const uniqueId = id != null ? id : generatedUniqueId; | ||
const handleChange = event => { | ||
const newValue = event.target.value; | ||
onChangeValidation(newValue); | ||
onChange(newValue); | ||
handleValidation(newValue); | ||
}; | ||
const handleValidation = newValue => { | ||
if (validate) { | ||
const error = validate(newValue) || null; | ||
setError(error); | ||
if (onValidate) { | ||
onValidate(error); | ||
} | ||
} else if (required) { | ||
const requiredString = typeof required === "string" ? required : defaultErrorMessage; | ||
const error = newValue ? null : requiredString; | ||
setError(error); | ||
if (onValidate) { | ||
onValidate(error); | ||
} | ||
const handleBlur = event => { | ||
onBlurValidation(event.target.value); | ||
if (onBlur) { | ||
onBlur(event); | ||
} | ||
}; | ||
wonderBlocksCore.useOnMountEffect(() => { | ||
if (value !== "") { | ||
handleValidation(value); | ||
} | ||
}); | ||
const getStyles = () => { | ||
const baseStyles = [styles.textarea, wonderBlocksTypography.styles.LabelMedium, resizeType && resizeStyles[resizeType]]; | ||
const defaultStyles = [styles.default, !disabled && styles.defaultFocus, disabled && styles.disabled, !!error && styles.error]; | ||
const lightStyles = [styles.light, !disabled && styles.lightFocus, disabled && styles.lightDisabled, !!error && styles.lightError]; | ||
return [...baseStyles, ...(light ? lightStyles : defaultStyles)]; | ||
}; | ||
return React__namespace.createElement(wonderBlocksCore.View, { | ||
@@ -1157,3 +1092,3 @@ style: [{ | ||
className: className, | ||
style: [getStyles(), style], | ||
style: [styles.textarea, wonderBlocksTypography.styles.LabelMedium, resizeType && resizeStyles[resizeType], styles.default, !disabled && styles.defaultFocus, disabled && styles.disabled, hasError && styles.error, style], | ||
value: value, | ||
@@ -1172,2 +1107,3 @@ onChange: handleChange, | ||
maxLength: maxLength, | ||
"aria-required": !!required, | ||
onClick: disabled ? undefined : onClick, | ||
@@ -1177,6 +1113,6 @@ onKeyDown: disabled ? undefined : onKeyDown, | ||
onFocus: onFocus, | ||
onBlur: onBlur, | ||
onBlur: handleBlur, | ||
required: !!required | ||
}, otherProps, { | ||
"aria-invalid": !!error | ||
"aria-invalid": hasError | ||
}))); | ||
@@ -1231,45 +1167,2 @@ }); | ||
} | ||
}, | ||
light: { | ||
background: wonderBlocksTokens.color.white, | ||
border: `1px solid ${wonderBlocksTokens.color.offBlack16}`, | ||
color: wonderBlocksTokens.color.offBlack, | ||
"::placeholder": { | ||
color: wonderBlocksTokens.color.offBlack64 | ||
} | ||
}, | ||
lightFocus: { | ||
":focus-visible": { | ||
outline: `3px solid ${wonderBlocksTokens.color.blue}`, | ||
outlineOffset: "-4px", | ||
borderColor: wonderBlocksTokens.color.white | ||
} | ||
}, | ||
lightDisabled: { | ||
backgroundColor: "transparent", | ||
border: `1px solid ${wonderBlocksTokens.color.white32}`, | ||
color: wonderBlocksTokens.color.white64, | ||
"::placeholder": { | ||
color: wonderBlocksTokens.color.white64 | ||
}, | ||
cursor: "not-allowed", | ||
":focus-visible": { | ||
borderColor: wonderBlocksTokens.mix(wonderBlocksTokens.color.white32, wonderBlocksTokens.color.blue), | ||
outline: `3px solid ${wonderBlocksTokens.color.fadedBlue}`, | ||
outlineOffset: "-4px" | ||
} | ||
}, | ||
lightError: { | ||
background: wonderBlocksTokens.color.fadedRed8, | ||
border: `1px solid ${wonderBlocksTokens.color.white}`, | ||
outline: `2px solid ${wonderBlocksTokens.color.red}`, | ||
outlineOffset: "-3px", | ||
color: wonderBlocksTokens.color.offBlack, | ||
"::placeholder": { | ||
color: wonderBlocksTokens.color.offBlack64 | ||
}, | ||
":focus-visible": { | ||
outline: `3px solid ${wonderBlocksTokens.color.red}`, | ||
outlineOffset: "-4px" | ||
} | ||
} | ||
@@ -1276,0 +1169,0 @@ }); |
{ | ||
"name": "@khanacademy/wonder-blocks-form", | ||
"version": "0.0.0-PR2358-20241113141724", | ||
"version": "0.0.0-PR2373-20250121234927", | ||
"design": "v1", | ||
@@ -10,3 +10,4 @@ "description": "Form components for Wonder Blocks.", | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
"test": "echo \"Error: no test specified\" && exit 1", | ||
"prepublishOnly": "../../utils/publish/package-pre-publish-check.sh" | ||
}, | ||
@@ -20,16 +21,16 @@ "author": "", | ||
"@babel/runtime": "^7.18.6", | ||
"@khanacademy/wonder-blocks-clickable": "^4.2.9", | ||
"@khanacademy/wonder-blocks-core": "^7.0.1", | ||
"@khanacademy/wonder-blocks-icon": "0.0.0-PR2358-20241113141724", | ||
"@khanacademy/wonder-blocks-layout": "^2.2.2", | ||
"@khanacademy/wonder-blocks-tokens": "^2.1.0", | ||
"@khanacademy/wonder-blocks-typography": "^2.1.16" | ||
"@khanacademy/wonder-blocks-clickable": "0.0.0-PR2373-20250121234927", | ||
"@khanacademy/wonder-blocks-core": "^11.1.0", | ||
"@khanacademy/wonder-blocks-icon": "^5.0.5", | ||
"@khanacademy/wonder-blocks-layout": "0.0.0-PR2373-20250121234927", | ||
"@khanacademy/wonder-blocks-tokens": "0.0.0-PR2373-20250121234927", | ||
"@khanacademy/wonder-blocks-typography": "^3.0.5" | ||
}, | ||
"peerDependencies": { | ||
"aphrodite": "^1.2.5", | ||
"react": "16.14.0" | ||
"react": "18.2.0" | ||
}, | ||
"devDependencies": { | ||
"@khanacademy/wb-dev-build-settings": "^1.0.1" | ||
"@khanacademy/wb-dev-build-settings": "^2.0.0" | ||
} | ||
} |
20
138725
3492
+ Added@khanacademy/wonder-blocks-clickable@0.0.0-PR2373-20250121234927(transitive)
+ Added@khanacademy/wonder-blocks-core@11.1.012.1.1(transitive)
+ Added@khanacademy/wonder-blocks-icon@5.1.1(transitive)
+ Added@khanacademy/wonder-blocks-layout@0.0.0-PR2373-20250121234927(transitive)
+ Added@khanacademy/wonder-blocks-tokens@0.0.0-PR2373-20250121234927(transitive)
+ Added@khanacademy/wonder-blocks-typography@3.1.1(transitive)
+ Addedreact@18.2.0(transitive)
+ Addedreact-dom@18.2.0(transitive)
+ Addedreact-router@5.3.4(transitive)
+ Addedreact-router-dom@5.3.4(transitive)
+ Addedscheduler@0.23.2(transitive)
- Removed@khanacademy/wonder-blocks-clickable@4.2.9(transitive)
- Removed@khanacademy/wonder-blocks-core@7.0.1(transitive)
- Removed@khanacademy/wonder-blocks-icon@0.0.0-PR2358-20241113141724(transitive)
- Removed@khanacademy/wonder-blocks-layout@2.2.2(transitive)
- Removed@khanacademy/wonder-blocks-tokens@2.1.0(transitive)
- Removed@khanacademy/wonder-blocks-typography@2.1.16(transitive)
- Removedmini-create-react-context@0.4.1(transitive)
- Removedreact@16.14.0(transitive)
- Removedreact-dom@16.14.0(transitive)
- Removedreact-router@5.2.1(transitive)
- Removedreact-router-dom@5.3.0(transitive)
- Removedscheduler@0.19.1(transitive)
Updated@khanacademy/wonder-blocks-clickable@0.0.0-PR2373-20250121234927
Updated@khanacademy/wonder-blocks-layout@0.0.0-PR2373-20250121234927
Updated@khanacademy/wonder-blocks-tokens@0.0.0-PR2373-20250121234927