fix(packages): validation state deprecated, isInvalid prop adjusted (#1631)

This commit is contained in:
Junior Garcia 2023-09-16 18:16:32 -03:00 committed by GitHub
parent a5a1ea5ade
commit 425a034bca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 435 additions and 169 deletions

View File

@ -0,0 +1,9 @@
---
"@nextui-org/checkbox": patch
"@nextui-org/select": patch
"@nextui-org/input": patch
"@nextui-org/radio": patch
"@nextui-org/theme": patch
---
validationState prop deprecated, "isInvalid" prop adjusted, invalid checkbox and radios state improved

View File

@ -4,6 +4,7 @@ import horizontal from "./horizontal";
import controlled from "./controlled";
import customStyles from "./custom-styles";
import customImplementation from "./custom-implementation";
import invalid from "./invalid";
export const checkboxGroupContent = {
usage,
@ -11,5 +12,6 @@ export const checkboxGroupContent = {
horizontal,
controlled,
customStyles,
invalid,
customImplementation,
};

View File

@ -0,0 +1,31 @@
const App = `import {CheckboxGroup, Checkbox} from "@nextui-org/react";
export default function App() {
const [isInvalid, setIsInvalid] = React.useState(true);
return (
<CheckboxGroup
isRequired
description="Select the cities you want to visit"
isInvalid={isInvalid}
label="Select cities"
onValueChange={(value) => {
setIsInvalid(value.length < 1);
}}
>
<Checkbox value="buenos-aires">Buenos Aires</Checkbox>
<Checkbox value="sydney">Sydney</Checkbox>
<Checkbox value="san-francisco">San Francisco</Checkbox>
<Checkbox value="london">London</Checkbox>
<Checkbox value="tokyo">Tokyo</Checkbox>
</CheckboxGroup>
);
}`;
const react = {
"/App.jsx": App,
};
export default {
...react,
};

View File

@ -7,7 +7,7 @@ export default function App() {
label="Email"
variant="bordered"
defaultValue="junior2nextui.org"
validationState="invalid"
isInvalid={true}
errorMessage="Please enter a valid email"
className="max-w-xs"
/>

View File

@ -5,10 +5,10 @@ export default function App() {
const validateEmail = (value) => value.match(/^[A-Z0-9._%+-]+@[A-Z0-9.-]+.[A-Z]{2,4}$/i);
const validationState = React.useMemo(() => {
if (value === "") return undefined;
const isInvalid = React.useMemo(() => {
if (value === "") return false;
return validateEmail(value) ? "valid" : "invalid";
return validateEmail(value) ? false : true;
}, [value]);
return (
@ -17,9 +17,9 @@ export default function App() {
type="email"
label="Email"
variant="bordered"
color={validationState === "invalid" ? "danger" : "success"}
errorMessage={validationState === "invalid" && "Please enter a valid email"}
validationState={validationState}
isInvalid={isInvalid}
color={isInvalid ? "danger" : "success"}
errorMessage={isInvalid && "Please enter a valid email"}
onValueChange={setValue}
className="max-w-xs"
/>

View File

@ -6,12 +6,14 @@ import defaultValue from "./default-value";
import withDescription from "./with-description";
import customStyles from "./custom-styles";
import customImpl from "./custom-impl";
import invalid from "./invalid";
export const radioGroupContent = {
usage,
disabled,
horizontal,
controlled,
invalid,
defaultValue,
withDescription,
customStyles,

View File

@ -0,0 +1,35 @@
const App = `import {RadioGroup, Radio} from "@nextui-org/react";
export default function App() {
const [selected, setSelected] = React.useState("london");
const validOptions = ["buenos-aires", "san-francisco", "tokyo"];
const isInvalid = !validOptions.includes(selected);
return (
<div className="flex flex-col gap-3">
<RadioGroup
label="Select your favorite city"
value={selected}
isInvalid={isInvalid}
onValueChange={setSelected}
>
<Radio value="buenos-aires">Buenos Aires</Radio>
<Radio value="sydney">Sydney</Radio>
<Radio value="san-francisco">San Francisco</Radio>
<Radio value="london">London</Radio>
<Radio value="tokyo">Tokyo</Radio>
</RadioGroup>
<p className="text-default-500 text-small">Selected: {selected}</p>
</div>
);
}`;
const react = {
"/App.jsx": App,
};
export default {
...react,
};

View File

@ -42,7 +42,7 @@ export default function App() {
placeholder="Select an animal"
description="The second most popular pet in the world"
errorMessage={isValid || !touched ? "" : "You must select a cat"}
validationState={isValid || !touched ? "valid" : "invalid"}
isInvalid={isValid || !touched ? false : true}
selectedKeys={value}
className="max-w-xs"
onSelectionChange={setValue}

View File

@ -3,12 +3,12 @@ const App = `import {Textarea} from "@nextui-org/react";
export default function App() {
return (
<Textarea
isInvalid={true}
variant="bordered"
label="Description"
labelPlacement="outside"
placeholder="Enter your description"
defaultValue="NextUI is a React UI library with..."
validationState="invalid"
errorMessage="The description should be at least 255 characters long."
className="max-w-xs"
/>

View File

@ -13,7 +13,7 @@ A CheckboxGroup allows users to select one or more items from a list of choices.
---
<CarbonAd/>
<CarbonAd />
## Import
@ -47,6 +47,10 @@ You can use the `value` and `onValueChange` properties to control the checkbox i
<CodeDemo title="Controlled" files={checkboxGroupContent.controlled} />
### Invalid
<CodeDemo title="Invalid" files={checkboxGroupContent.invalid} />
## Slots
- **base**: Checkbox group root wrapper, it wraps the label and the wrapper.
@ -57,7 +61,6 @@ You can use the `value` and `onValueChange` properties to control the checkbox i
### Custom Styles
You can customize the `CheckboxGroup` component by passing custom Tailwind CSS classes to the component slots.
<CodeDemo title="Custom Styles" files={checkboxGroupContent.customStyles} />
@ -76,25 +79,26 @@ In case you need to customize the checkbox even further, you can use the `useChe
### Checkbox Group Props
| Attribute | Type | Description | Default |
| ---------------- | --------------------------------------------------------------------------- | -------------------------------------------------------------------------- | ---------- |
| children | `ReactNode[]` \| `ReactNode[]` | The checkboxes items. | - |
| orientation | `vertical` \| `horizontal` | The axis the checkbox group items should align with. | `vertical` |
| color | `default` \| `primary` \| `secondary` \| `success` \| `warning` \| `danger` | The color of the checkboxes. | `primary` |
| size | `xs` \| `sm` \| `md` \| `lg` \| `xl` | The size of the checkboxes. | `md` |
| radius | `none` \| `base` \| `xs` \| `sm` \| `md` \| `lg` \| `xl` \| `full` | The radius of the checkboxes. | `md` |
| name | `string` | The name of the CheckboxGroup, used when submitting an HTML form. | - |
| value | `string[]` | The current selected values. (controlled). | - |
| lineThrough | `boolean` | Whether the checkboxes label should be crossed out. | `false` |
| defaultValue | `string[]` | The default selected values. (uncontrolled). | - |
| validationState | `valid` \| `invalid` | Whether the inputs should display its "valid" or "invalid" visual styling. | `false` |
| description | `ReactNode` | The checkbox group description. | - |
| errorMessage | `ReactNode` | The checkbox group error message. | - |
| isDisabled | `boolean` | Whether the checkbox group is disabled. | `false` |
| isRequired | `boolean` | Whether user checkboxes are required on the input before form submission. | `false` |
| isReadOnly | `boolean` | Whether the checkboxes can be selected but not changed by the user. | - |
| disableAnimation | `boolean` | Whether the animation should be disabled. | `false` |
| classNames | `Record<"base" "wrapper" "label", string>` | Allows to set custom class names for the checkbox group slots. | - |
| Attribute | Type | Description | Default |
| ---------------- | --------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | ---------- |
| children | `ReactNode[]` \| `ReactNode[]` | The checkboxes items. | - |
| orientation | `vertical` \| `horizontal` | The axis the checkbox group items should align with. | `vertical` |
| color | `default` \| `primary` \| `secondary` \| `success` \| `warning` \| `danger` | The color of the checkboxes. | `primary` |
| size | `xs` \| `sm` \| `md` \| `lg` \| `xl` | The size of the checkboxes. | `md` |
| radius | `none` \| `base` \| `xs` \| `sm` \| `md` \| `lg` \| `xl` \| `full` | The radius of the checkboxes. | `md` |
| name | `string` | The name of the CheckboxGroup, used when submitting an HTML form. | - |
| value | `string[]` | The current selected values. (controlled). | - |
| lineThrough | `boolean` | Whether the checkboxes label should be crossed out. | `false` |
| defaultValue | `string[]` | The default selected values. (uncontrolled). | - |
| isInvalid | `boolean` | Whether the checkbox group is invalid. | `false` |
| validationState | `valid` \| `invalid` | Whether the inputs should display its "valid" or "invalid" visual styling. (**Deprecated**) use **isInvalid** instead. | - |
| description | `ReactNode` | The checkbox group description. | - |
| errorMessage | `ReactNode` | The checkbox group error message. | - |
| isDisabled | `boolean` | Whether the checkbox group is disabled. | `false` |
| isRequired | `boolean` | Whether user checkboxes are required on the input before form submission. | `false` |
| isReadOnly | `boolean` | Whether the checkboxes can be selected but not changed by the user. | - |
| disableAnimation | `boolean` | Whether the animation should be disabled. | `false` |
| classNames | `Record<"base" "wrapper" "label", string>` | Allows to set custom class names for the checkbox group slots. | - |
### Checkbox Group Events

View File

@ -13,7 +13,7 @@ Checkboxes allow users to select multiple items from a list of individual items,
---
<CarbonAd/>
<CarbonAd />
## Import
@ -134,19 +134,20 @@ In case you need to customize the checkbox even further, you can use the `useChe
| ---------------- | --------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | --------- |
| children | `ReactNode` | The label of the checkbox. | - |
| icon | [CheckboxIconProps](#checkbox-icon-props) | The icon to be displayed when the checkbox is checked. | - |
| value | `string` | The value of the input element, used when submitting an HTML form. | |
| name | `string` | The name of the input element, used when submitting an HTML form. | |
| value | `string` | The value of the checkbox element, used when submitting an HTML form. | |
| name | `string` | The name of the checkbox element, used when submitting an HTML form. | |
| size | `sm` \| `md` \| `lg` | The size of the checkbox. | `md` |
| color | `default` \| `primary` \| `secondary` \| `success` \| `warning` \| `danger` | The color of the checkbox. | `primary` |
| radius | `none` \| `sm` \| `md` \| `lg` \| `full` | The radius of the checkbox. | - |
| lineThrough | `boolean` | Whether the label should be crossed out. | `false` |
| isSelected | `boolean` | Whether the element should be selected (controlled). | |
| defaultSelected | `boolean` | Whether the element should be selected (uncontrolled). | |
| validationState | `valid` \| `invalid` | Whether the input should display its "valid" or "invalid" visual styling. | - |
| isRequired | `boolean` | Whether user input is required on the input before form submission. | `false` |
| isReadOnly | `boolean` | Whether the input can be selected but not changed by the user. | |
| isRequired | `boolean` | Whether user checkbox is required on the checkbox before form submission. | `false` |
| isReadOnly | `boolean` | Whether the checkbox can be selected but not changed by the user. | |
| isDisabled | `boolean` | Whether the checkbox is disabled. | `false` |
| isIndeterminate | `boolean` | Indeterminism is presentational only. The indeterminate visual representation remains regardless of user interaction. | |
| isInvalid | `boolean` | Whether the checkbox is invalid. | `false` |
| validationState | `valid` \| `invalid` | Whether the checkbox should display its "valid" or "invalid" visual styling. (**Deprecated**) use **isInvalid** instead. | - |
| disableAnimation | `boolean` | Whether the animation should be disabled. | `false` |
| classNames | `Record<"base" "wrapper" "icon" "label", string>` | Allows to set custom class names for the checkbox slots. | - |

View File

@ -13,7 +13,7 @@ Input is a component that allows users to enter text. It can be used to get user
---
<CarbonAd/>
<CarbonAd />
## Import
@ -180,30 +180,31 @@ In case you need to customize the input even further, you can use the `useInput`
### Input Props
| Attribute | Type | Description | Default |
| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | --------- |
| children | `ReactNode` | The content of the input. | - |
| variant | `flat` \| `bordered` \| `faded` \| `underlined` | The variant of the input. | `flat` |
| color | `default` \| `primary` \| `secondary` \| `success` \| `warning` \| `danger` | The color of the input. | `default` |
| size | `sm` \| `md` \| `lg` | The size of the input. | `md` |
| radius | `none` \| `sm` \| `md` \| `lg` \| `full` | The radius of the input. | - |
| label | `ReactNode` | The content to display as the label. | - |
| value | `string` | The current value of the input (controlled). | - |
| defaultValue | `string` | The default value of the input (uncontrolled). | - |
| placeholder | `string` | The placeholder of the input. | - |
| description | `ReactNode` | A description for the input. Provides a hint such as specific requirements for what to choose. | - |
| errorMessage | `ReactNode` | An error message for the input. | - |
| labelPlacement | `inside` \| `outside` \| `outside-left` | The position of the label. | `inside` |
| fullWidth | `boolean` | Whether the input should take up the width of its parent. | `true` |
| validationState | `valid` \| `invalid` | Whether the input should display its "valid" or "invalid" visual styling. | - |
| isClearable | `boolean` | Whether the input should have a clear button. | `false` |
| isRequired | `boolean` | Whether user input is required on the input before form submission. | `false` |
| isReadOnly | `boolean` | Whether the input can be selected but not changed by the user. | |
| isDisabled | `boolean` | Whether the input is disabled. | `false` |
| startContent | `ReactNode` | Element to be rendered in the left side of the input. | - |
| endContent | `ReactNode` | Element to be rendered in the right side of the input. | - |
| disableAnimation | `boolean` | Whether the input should be animated. | `false` |
| classNames | `Record<"base" "label" "inputWrapper" "innerWrapper" "mainWrapper" "input" "clearButton" "helperWrapper" "description" "errorMessage", string>` | Allows to set custom class names for the checkbox slots. | - |
| Attribute | Type | Description | Default |
| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | --------- |
| children | `ReactNode` | The content of the input. | - |
| variant | `flat` \| `bordered` \| `faded` \| `underlined` | The variant of the input. | `flat` |
| color | `default` \| `primary` \| `secondary` \| `success` \| `warning` \| `danger` | The color of the input. | `default` |
| size | `sm` \| `md` \| `lg` | The size of the input. | `md` |
| radius | `none` \| `sm` \| `md` \| `lg` \| `full` | The radius of the input. | - |
| label | `ReactNode` | The content to display as the label. | - |
| value | `string` | The current value of the input (controlled). | - |
| defaultValue | `string` | The default value of the input (uncontrolled). | - |
| placeholder | `string` | The placeholder of the input. | - |
| description | `ReactNode` | A description for the input. Provides a hint such as specific requirements for what to choose. | - |
| errorMessage | `ReactNode` | An error message for the input. | - |
| startContent | `ReactNode` | Element to be rendered in the left side of the input. | - |
| endContent | `ReactNode` | Element to be rendered in the right side of the input. | - |
| labelPlacement | `inside` \| `outside` \| `outside-left` | The position of the label. | `inside` |
| fullWidth | `boolean` | Whether the input should take up the width of its parent. | `true` |
| isClearable | `boolean` | Whether the input should have a clear button. | `false` |
| isRequired | `boolean` | Whether user input is required on the input before form submission. | `false` |
| isReadOnly | `boolean` | Whether the input can be selected but not changed by the user. | |
| isDisabled | `boolean` | Whether the input is disabled. | `false` |
| isInvalid | `boolean` | Whether the input is invalid. | `false` |
| validationState | `valid` \| `invalid` | Whether the input should display its "valid" or "invalid" visual styling. (**Deprecated**) use **isInvalid** instead. | - |
| disableAnimation | `boolean` | Whether the input should be animated. | `false` |
| classNames | `Record<"base" "label" "inputWrapper" "innerWrapper" "mainWrapper" "input" "clearButton" "helperWrapper" "description" "errorMessage", string>` | Allows to set custom class names for the checkbox slots. | - |
### Input Events

View File

@ -13,7 +13,7 @@ Radio Group allow users to select a single option from a list of mutually exclus
---
<CarbonAd/>
<CarbonAd />
## Import
@ -53,6 +53,10 @@ You can use the `value` and `onValueChange` properties to control the radio inpu
> **Note**: NextUI `Radio` also supports native events like `onChange`, useful for form libraries
> such as [Formik](https://formik.org/) and [React Hook Form](https://react-hook-form.com/).
### Invalid
<CodeDemo title="Invalid" files={radioGroupContent.invalid} />
## Slots
- RadioGroup Slots
@ -140,12 +144,13 @@ In case you need to customize the radio group even further, you can use the `use
| name | `string` | The name of the RadioGroup, used when submitting an HTML form. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#name_and_radio_buttons). | - |
| value | `string[]` | The current selected value. (controlled). | - |
| defaultValue | `string[]` | The default selected value. (uncontrolled). | - |
| validationState | `valid` \| `invalid` | Whether the inputs should display its "valid" or "invalid" visual styling. | `false` |
| description | `ReactNode` | Radio group description . | - |
| errorMessage | `ReactNode` | Radio group error message. | - |
| isDisabled | `boolean` | Whether the radio group is disabled. | `false` |
| isRequired | `boolean` | Whether user checkboxes are required on the input before form submission. | `false` |
| isReadOnly | `boolean` | Whether the checkboxes can be selected but not changed by the user. | - |
| isInvalid | `boolean` | Whether the radio group is invalid. | `false` |
| validationState | `valid` \| `invalid` | Whether the inputs should display its "valid" or "invalid" visual styling. (**Deprecated**) use **isInvalid** instead. | `false` |
| disableAnimation | `boolean` | Whether the animation should be disabled. | `false` |
| classNames | `Record<"base" "wrapper" "label", string>` | Allows to set custom class names for the radio group slots. | - |

View File

@ -333,44 +333,45 @@ the popover and listbox components.
### Select Props
| Attribute | Type | Description | Default |
| ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | ------------------ |
| children\* | `ReactNode[]` | The children to render. Usually a list of `SelectItem` and `SelectSection` elements. | - |
| items | [`Iterable<T>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) | Item objects in the select. (dynamic) | - |
| selectionMode | `single` \| `multiple` | The type of selection that is allowed in the collection. | - |
| selectedKeys | `all` \| `React.Key[]` | The currently selected keys in the collection (controlled). | - |
| disabledKeys | `all` \| `React.Key[]` | The item keys that are disabled. These items cannot be selected, focused, or otherwise interacted with. | - |
| defaultSelectedKeys | `all` \| `React.Key[]` | The initial selected keys in the collection (uncontrolled). | - |
| variant | `flat` \| `bordered` \| `faded` \| `underlined` | The variant of the select. | `flat` |
| color | `default` \| `primary` \| `secondary` \| `success` \| `warning` \| `danger` | The color of the select. | `default` |
| size | `sm` \| `md` \| `lg` | The size of the select. | `md` |
| radius | `none` \| `sm` \| `md` \| `lg` \| `full` | The radius of the select. | - |
| placeholder | `string` | The placeholder of the select. | `Select an option` |
| labelPlacement | `inside` \| `outside` \| `outside-left` | The position of the label. | `inside` |
| validationState | `valid` \| `invalid` | Whether the select should display its "valid" or "invalid" visual styling. | - |
| label | `ReactNode` | The content to display as the label. | - |
| description | `ReactNode` | A description for the select. Provides a hint such as specific requirements for what to choose. | - |
| errorMessage | `ReactNode` | An error message for the select. | - |
| startContent | `ReactNode` | Element to be rendered in the left side of the select. | - |
| endContent | `ReactNode` | Element to be rendered in the right side of the select. | - |
| selectorIcon | `ReactNode` | Element to be rendered as the selector icon. | - |
| scrollRef | `React.RefObject<HTMLElement>` | A ref to the scrollable element. | - |
| spinnerRef | `React.RefObject<HTMLElement>` | A ref to the spinner element. | - |
| fullWidth | `boolean` | Whether the select should take up the width of its parent. | `true` |
| isOpen | `boolean` | Whether the select is open by default (controlled). | - |
| defaultOpen | `boolean` | Whether the select is open by default (uncontrolled). | - |
| isRequired | `boolean` | Whether user select is required on the select before form submission. | `false` |
| isDisabled | `boolean` | Whether the select is disabled. | `false` |
| isMultiline | `boolean` | Whether the select should allow multiple lines of text. | `false` |
| showScrollIndicators | `boolean` | Whether the select should show scroll indicators when the listbox is scrollable. | `true` |
| autoFocus | `boolean` | Whether the select should be focused on the first mount. | `false` |
| disallowEmptySelection | `boolean` | Whether the collection allows empty selection. | `false` |
| disableAnimation | `boolean` | Whether the select should be animated. | `true` |
| disableSelectionIconRotation | `boolean` | Whether the select should disable the rotation of the selector icon. | `false` |
| popoverProps | [PopoverProps](/docs/components/popover#api) | Props to be passed to the popover component. | - |
| listboxProps | [ListboxProps](/docs/components/listbox#api) | Props to be passed to the listbox component. | - |
| scrollShadowProps | [ScrollShadowProps](/docs/components/scroll-shadow#api) | Props to be passed to the scroll shadow component. | - |
| classNames | `Record<"base" "label" "trigger" "mainWrapper" "innerWrapper" "selectorIcon" "value" "listboxWrapper" "listbox" "popover" "helperWrapper" "description" "errorMessage", string>` | Allows to set custom class names for the dropdown item slots. | - |
| Attribute | Type | Description | Default |
| ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | ------------------ |
| children\* | `ReactNode[]` | The children to render. Usually a list of `SelectItem` and `SelectSection` elements. | - |
| items | [`Iterable<T>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) | Item objects in the select. (dynamic) | - |
| selectionMode | `single` \| `multiple` | The type of selection that is allowed in the collection. | - |
| selectedKeys | `all` \| `React.Key[]` | The currently selected keys in the collection (controlled). | - |
| disabledKeys | `all` \| `React.Key[]` | The item keys that are disabled. These items cannot be selected, focused, or otherwise interacted with. | - |
| defaultSelectedKeys | `all` \| `React.Key[]` | The initial selected keys in the collection (uncontrolled). | - |
| variant | `flat` \| `bordered` \| `faded` \| `underlined` | The variant of the select. | `flat` |
| color | `default` \| `primary` \| `secondary` \| `success` \| `warning` \| `danger` | The color of the select. | `default` |
| size | `sm` \| `md` \| `lg` | The size of the select. | `md` |
| radius | `none` \| `sm` \| `md` \| `lg` \| `full` | The radius of the select. | - |
| placeholder | `string` | The placeholder of the select. | `Select an option` |
| labelPlacement | `inside` \| `outside` \| `outside-left` | The position of the label. | `inside` |
| label | `ReactNode` | The content to display as the label. | - |
| description | `ReactNode` | A description for the select. Provides a hint such as specific requirements for what to choose. | - |
| errorMessage | `ReactNode` | An error message for the select. | - |
| startContent | `ReactNode` | Element to be rendered in the left side of the select. | - |
| endContent | `ReactNode` | Element to be rendered in the right side of the select. | - |
| selectorIcon | `ReactNode` | Element to be rendered as the selector icon. | - |
| scrollRef | `React.RefObject<HTMLElement>` | A ref to the scrollable element. | - |
| spinnerRef | `React.RefObject<HTMLElement>` | A ref to the spinner element. | - |
| fullWidth | `boolean` | Whether the select should take up the width of its parent. | `true` |
| isOpen | `boolean` | Whether the select is open by default (controlled). | - |
| defaultOpen | `boolean` | Whether the select is open by default (uncontrolled). | - |
| isRequired | `boolean` | Whether user select is required on the select before form submission. | `false` |
| isDisabled | `boolean` | Whether the select is disabled. | `false` |
| isMultiline | `boolean` | Whether the select should allow multiple lines of text. | `false` |
| isInvalid | `boolean` | Whether the select is invalid. | `false` |
| validationState | `valid` \| `invalid` | Whether the select should display its "valid" or "invalid" visual styling. (**Deprecated**) use **isInvalid** instead. | - |
| showScrollIndicators | `boolean` | Whether the select should show scroll indicators when the listbox is scrollable. | `true` |
| autoFocus | `boolean` | Whether the select should be focused on the first mount. | `false` |
| disallowEmptySelection | `boolean` | Whether the collection allows empty selection. | `false` |
| disableAnimation | `boolean` | Whether the select should be animated. | `true` |
| disableSelectionIconRotation | `boolean` | Whether the select should disable the rotation of the selector icon. | `false` |
| popoverProps | [PopoverProps](/docs/components/popover#api) | Props to be passed to the popover component. | - |
| listboxProps | [ListboxProps](/docs/components/listbox#api) | Props to be passed to the listbox component. | - |
| scrollShadowProps | [ScrollShadowProps](/docs/components/scroll-shadow#api) | Props to be passed to the scroll shadow component. | - |
| classNames | `Record<"base" "label" "trigger" "mainWrapper" "innerWrapper" "selectorIcon" "value" "listboxWrapper" "listbox" "popover" "helperWrapper" "description" "errorMessage", string>` | Allows to set custom class names for the dropdown item slots. | - |
### Select Events

View File

@ -13,7 +13,7 @@ Textarea component is a multi-line Input which allows you to write large texts.
---
<CarbonAd/>
<CarbonAd />
## Import
@ -119,30 +119,31 @@ You can use the `value` and `onValueChange` properties to control the input valu
### Textarea Props
| Attribute | Type | Description | Default |
| ----------------- | ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------- | --------- |
| children | `ReactNode` | The content of the textarea. | - |
| minRows | `number` | The minimum number of rows to display. | `3` |
| maxRows | `number` | Maximum number of rows up to which the textarea can grow. | `8` |
| cacheMeasurements | `boolean` | Reuse previously computed measurements when computing height of textarea. | `false` |
| variant | `flat` \| `bordered` \| `faded` \| `underlined` | The variant of the textarea. | `flat` |
| color | `default` \| `primary` \| `secondary` \| `success` \| `warning` \| `danger` | The color of the textarea. | `default` |
| size | `sm`\|`md`\|`lg` | The size of the textarea. | `md` |
| radius | `none` \| `sm` \| `md` \| `lg` \| `full` | The radius of the textarea. | - |
| label | `ReactNode` | The content to display as the label. | - |
| value | `string` | The current value of the textarea (controlled). | - |
| defaultValue | `string` | The default value of the textarea (uncontrolled). | - |
| placeholder | `string` | The placeholder of the textarea. | - |
| description | `ReactNode` | A description for the textarea. Provides a hint such as specific requirements for what to choose. | - |
| errorMessage | `ReactNode` | An error message for the textarea. | - |
| labelPlacement | `inside` \| `outside` \| `outside-left` | The position of the label. | `inside` |
| fullWidth | `boolean` | Whether the textarea should take up the width of its parent. | `true` |
| validationState | `valid` \| `invalid` | Whether the textarea should display its "valid" or "invalid" visual styling. | - |
| isRequired | `boolean` | Whether user input is required on the textarea before form submission. | `false` |
| isReadOnly | `boolean` | Whether the textarea can be selected but not changed by the user. | |
| isDisabled | `boolean` | Whether the textarea is disabled. | `false` |
| disableAnimation | `boolean` | Whether the textarea should be animated. | `false` |
| classNames | `Record<"base" "label" "inputWrapper" "input" "description" "errorMessage", string>` | Allows to set custom class names for the checkbox slots. | - |
| Attribute | Type | Description | Default |
| ----------------- | ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------ | --------- |
| children | `ReactNode` | The content of the textarea. | - |
| minRows | `number` | The minimum number of rows to display. | `3` |
| maxRows | `number` | Maximum number of rows up to which the textarea can grow. | `8` |
| cacheMeasurements | `boolean` | Reuse previously computed measurements when computing height of textarea. | `false` |
| variant | `flat` \| `bordered` \| `faded` \| `underlined` | The variant of the textarea. | `flat` |
| color | `default` \| `primary` \| `secondary` \| `success` \| `warning` \| `danger` | The color of the textarea. | `default` |
| size | `sm`\|`md`\|`lg` | The size of the textarea. | `md` |
| radius | `none` \| `sm` \| `md` \| `lg` \| `full` | The radius of the textarea. | - |
| label | `ReactNode` | The content to display as the label. | - |
| value | `string` | The current value of the textarea (controlled). | - |
| defaultValue | `string` | The default value of the textarea (uncontrolled). | - |
| placeholder | `string` | The placeholder of the textarea. | - |
| description | `ReactNode` | A description for the textarea. Provides a hint such as specific requirements for what to choose. | - |
| errorMessage | `ReactNode` | An error message for the textarea. | - |
| labelPlacement | `inside` \| `outside` \| `outside-left` | The position of the label. | `inside` |
| fullWidth | `boolean` | Whether the textarea should take up the width of its parent. | `true` |
| isRequired | `boolean` | Whether user input is required on the textarea before form submission. | `false` |
| isReadOnly | `boolean` | Whether the textarea can be selected but not changed by the user. | |
| isDisabled | `boolean` | Whether the textarea is disabled. | `false` |
| isInvalid | `boolean` | Whether the textarea is invalid. | `false` |
| validationState | `valid` \| `invalid` | Whether the textarea should display its "valid" or "invalid" visual styling. (**Deprecated**) use **isInvalid** instead. | - |
| disableAnimation | `boolean` | Whether the textarea should be animated. | `false` |
| classNames | `Record<"base" "label" "inputWrapper" "input" "description" "errorMessage", string>` | Allows to set custom class names for the checkbox slots. | - |
### Input Events

View File

@ -105,7 +105,7 @@ describe("Checkbox", () => {
<Checkbox
{...props}
isSelected={value}
onChange={(checked) => {
onValueChange={(checked) => {
act(() => {
setValue(checked);
onChange(checked);

View File

@ -60,6 +60,7 @@ export type ContextType = {
color?: CheckboxProps["color"];
size?: CheckboxProps["size"];
radius?: CheckboxProps["radius"];
isInvalid?: UseCheckboxGroupProps["isInvalid"];
lineThrough?: CheckboxProps["lineThrough"];
isDisabled?: CheckboxProps["isDisabled"];
disableAnimation?: CheckboxProps["disableAnimation"];
@ -83,6 +84,7 @@ export function useCheckboxGroup(props: UseCheckboxGroupProps) {
isDisabled = false,
disableAnimation = false,
validationState,
isInvalid = validationState === "invalid",
isReadOnly,
isRequired,
onValueChange,
@ -103,10 +105,10 @@ export function useCheckboxGroup(props: UseCheckboxGroupProps) {
"aria-label": safeAriaLabel(otherProps["aria-label"], label),
defaultValue,
isRequired,
isInvalid,
isReadOnly,
orientation,
onChange: onValueChange,
validationState,
...otherProps,
}),
[
@ -116,9 +118,9 @@ export function useCheckboxGroup(props: UseCheckboxGroupProps) {
defaultValue,
isRequired,
isReadOnly,
isInvalid,
orientation,
onValueChange,
validationState,
otherProps["aria-label"],
otherProps,
],
@ -137,6 +139,7 @@ export function useCheckboxGroup(props: UseCheckboxGroupProps) {
color,
radius,
lineThrough,
isInvalid,
isDisabled,
disableAnimation,
groupState,
@ -148,15 +151,19 @@ export function useCheckboxGroup(props: UseCheckboxGroupProps) {
lineThrough,
isDisabled,
disableAnimation,
isInvalid,
groupState?.value,
groupState?.isDisabled,
groupState?.isReadOnly,
groupState?.validationState,
groupState?.isInvalid,
groupState?.isSelected,
],
);
const slots = useMemo(() => checkboxGroup(), []);
const slots = useMemo(
() => checkboxGroup({isRequired, isInvalid, disableAnimation}),
[isRequired, isInvalid, disableAnimation],
);
const baseStyles = clsx(classNames?.base, className);

View File

@ -85,14 +85,15 @@ export function useCheckbox(props: UseCheckboxProps = {}) {
isReadOnly: isReadOnlyProp = false,
autoFocus = false,
isSelected: isSelectedProp,
validationState,
size = groupContext?.size ?? "md",
color = groupContext?.color ?? "primary",
radius = groupContext?.radius,
lineThrough = groupContext?.lineThrough ?? false,
isDisabled: isDisabledProp = groupContext?.isDisabled ?? false,
disableAnimation = groupContext?.disableAnimation ?? false,
isInvalid = validationState ? validationState === "invalid" : groupContext?.isInvalid ?? false,
isIndeterminate = false,
validationState,
defaultSelected,
classNames,
onChange,
@ -132,10 +133,10 @@ export function useCheckbox(props: UseCheckboxProps = {}) {
defaultSelected,
isIndeterminate,
isRequired,
isInvalid,
isSelected: isSelectedProp,
isDisabled: isDisabledProp,
isReadOnly: isReadOnlyProp,
validationState,
"aria-label": safeAriaLabel(otherProps["aria-label"], children),
"aria-labelledby": otherProps["aria-labelledby"] || labelId,
onChange: onValueChange,
@ -146,12 +147,12 @@ export function useCheckbox(props: UseCheckboxProps = {}) {
labelId,
children,
autoFocus,
isInvalid,
isIndeterminate,
isDisabledProp,
isReadOnlyProp,
isSelectedProp,
defaultSelected,
validationState,
otherProps["aria-label"],
otherProps["aria-labelledby"],
onValueChange,
@ -168,14 +169,13 @@ export function useCheckbox(props: UseCheckboxProps = {}) {
useReactAriaCheckboxGroupItem(
{
...ariaCheckboxProps,
validationState,
isInvalid,
},
groupContext.groupState,
inputRef,
)
: useReactAriaCheckbox(ariaCheckboxProps, useToggleState(ariaCheckboxProps), inputRef); // eslint-disable-line
const isInvalid = useMemo(() => validationState === "invalid", [validationState]);
const isInteractionDisabled = isDisabled || isReadOnly;
// Handle press state for full label. Keyboard press state is returned by useCheckbox
@ -215,11 +215,12 @@ export function useCheckbox(props: UseCheckboxProps = {}) {
color,
size,
radius,
isInvalid,
lineThrough,
isDisabled,
disableAnimation,
}),
[color, size, radius, lineThrough, isDisabled, disableAnimation],
[color, size, radius, isInvalid, lineThrough, isDisabled, disableAnimation],
);
const baseStyles = clsx(classNames?.base, className);

View File

@ -53,6 +53,31 @@ const Template = (args: CheckboxGroupProps) => (
</CheckboxGroup>
);
const InvalidTemplate = (args: CheckboxGroupProps) => {
const [isInvalid, setIsInvalid] = React.useState(true);
return (
<>
<CheckboxGroup
{...args}
isRequired
description="Select the cities you want to visit"
isInvalid={isInvalid}
label="Select cities"
onValueChange={(value) => {
setIsInvalid(value.length < 1);
}}
>
<Checkbox value="buenos-aires">Buenos Aires</Checkbox>
<Checkbox value="sydney">Sydney</Checkbox>
<Checkbox value="san-francisco">San Francisco</Checkbox>
<Checkbox value="london">London</Checkbox>
<Checkbox value="tokyo">Tokyo</Checkbox>
</CheckboxGroup>
</>
);
};
export const Default = {
render: Template,
@ -115,12 +140,11 @@ export const WithDescription = {
},
};
export const Invalid = {
render: Template,
export const IsInvalid = {
render: InvalidTemplate,
args: {
...defaultProps,
validationState: "invalid",
},
};
@ -129,7 +153,6 @@ export const WithErrorMessage = {
args: {
...defaultProps,
validationState: "invalid",
errorMessage: "The selected cities cannot be visited at the same time",
},
};

View File

@ -18,7 +18,7 @@ describe("Input", () => {
});
it("should have aria-invalid when invalid", () => {
const {container} = render(<Input label="test input" validationState="invalid" />);
const {container} = render(<Input isInvalid={true} label="test input" />);
expect(container.querySelector("input")).toHaveAttribute("aria-invalid", "true");
});

View File

@ -82,6 +82,7 @@ export function useInput<T extends HTMLInputElement | HTMLTextAreaElement = HTML
endContent,
onClear,
onChange,
validationState,
onValueChange = () => {},
...otherProps
} = props;
@ -151,7 +152,7 @@ export function useInput<T extends HTMLInputElement | HTMLTextAreaElement = HTML
onPress: handleClear,
});
const isInvalid = props.validationState === "invalid";
const isInvalid = validationState === "invalid" || originalProps.isInvalid;
const labelPlacement = useMemo<InputVariantProps["labelPlacement"]>(() => {
if ((!originalProps.labelPlacement || originalProps.labelPlacement === "inside") && !label) {

View File

@ -563,14 +563,14 @@ export const WithErrorMessage = {
},
};
export const InvalidValidationState = {
export const IsInvalid = {
render: Template,
args: {
...defaultProps,
variant: "bordered",
isInvalid: true,
defaultValue: "invalid@email.com",
validationState: "invalid",
placeholder: "Enter your email",
errorMessage: "Please enter a valid email address",
},

View File

@ -147,12 +147,12 @@ export const WithErrorMessage = {
},
};
export const InvalidValidationState = {
export const IsInvalid = {
render: Template,
args: {
...defaultProps,
validationState: "invalid",
isInvalid: true,
defaultValue: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
errorMessage: "Please enter a valid description",
},

View File

@ -53,7 +53,7 @@ export type UseRadioGroupProps = Omit<Props, "defaultChecked"> &
export type ContextType = {
groupState: RadioGroupState;
isRequired?: UseRadioGroupProps["isRequired"];
validationState?: UseRadioGroupProps["validationState"];
isInvalid?: UseRadioGroupProps["isInvalid"];
color?: RadioProps["color"];
size?: RadioProps["size"];
isDisabled?: RadioProps["isDisabled"];
@ -76,10 +76,11 @@ export function useRadioGroup(props: UseRadioGroupProps) {
disableAnimation = false,
orientation = "vertical",
isRequired = false,
validationState,
isInvalid = validationState === "invalid",
isReadOnly,
errorMessage,
description,
validationState,
className,
onChange,
onValueChange,
@ -98,10 +99,21 @@ export function useRadioGroup(props: UseRadioGroupProps) {
"aria-label": safeAriaLabel(otherProps["aria-label"], label),
isRequired,
isReadOnly,
isInvalid,
orientation,
onChange: onValueChange,
};
}, [otherProps, value, name, label, isRequired, isReadOnly, orientation, onValueChange]);
}, [
otherProps,
value,
name,
label,
isRequired,
isReadOnly,
isInvalid,
orientation,
onValueChange,
]);
const groupState = useRadioGroupState(otherPropsWithOrientation);
@ -118,7 +130,7 @@ export function useRadioGroup(props: UseRadioGroupProps) {
color,
groupState,
isRequired,
validationState,
isInvalid,
isDisabled,
disableAnimation,
onChange,
@ -128,19 +140,22 @@ export function useRadioGroup(props: UseRadioGroupProps) {
color,
isRequired,
isDisabled,
disableAnimation,
isInvalid,
onChange,
disableAnimation,
groupState.name,
groupState?.isDisabled,
groupState?.isReadOnly,
groupState?.isRequired,
groupState?.selectedValue,
groupState?.validationState,
groupState?.lastFocusedValue,
],
);
const slots = useMemo(() => radioGroup(), []);
const slots = useMemo(
() => radioGroup({isRequired, isInvalid, disableAnimation}),
[isInvalid, isRequired, disableAnimation],
);
const baseStyles = clsx(classNames?.base, className);

View File

@ -88,10 +88,7 @@ export function useRadio(props: UseRadioProps) {
const labelId = useId();
const isRequired = useMemo(() => groupContext.isRequired ?? false, [groupContext.isRequired]);
const isInvalid = useMemo(
() => groupContext.validationState === "invalid",
[groupContext.validationState],
);
const isInvalid = groupContext.isInvalid;
const ariaRadioProps = useMemo(() => {
const ariaLabel =

View File

@ -101,6 +101,74 @@ const Template = (args: RadioGroupProps) => {
);
};
const InvalidTemplate = (args: RadioGroupProps) => {
const [isInvalid, setIsInvalid] = React.useState<boolean>(true);
const radioProps = args.description
? {
a: {
description: "Description for Option A",
},
b: {
description: "Description for Option B",
},
c: {
description: "Description for Option C",
},
d: {
description: "Description for Option D",
},
}
: {
a: {},
b: {},
c: {},
d: {},
};
const items = (
<>
<Radio value="A" {...radioProps.a}>
Option A
</Radio>
<Radio value="B" {...radioProps.b}>
Option B
</Radio>
<Radio value="C" {...radioProps.c}>
Option C
</Radio>
<Radio value="D" {...radioProps.d}>
Option D
</Radio>
</>
);
const validOptions = ["C", "B"];
return args.isRequired ? (
<form
className="flex flex-col items-start gap-4"
onSubmit={(e) => {
e.preventDefault();
alert("Submitted!");
}}
>
<RadioGroup
{...args}
isInvalid={isInvalid}
onValueChange={(value) => setIsInvalid(!validOptions.includes(value))}
>
{items}
</RadioGroup>
<button className={button({color: "primary"})} type="submit">
Submit
</button>
</form>
) : (
<RadioGroup {...args}>{items}</RadioGroup>
);
};
const ControlledTemplate = (args: RadioGroupProps) => {
const [selectedItem, setSelectedItem] = React.useState<string>("london");
@ -171,12 +239,13 @@ export const WithDescription = {
},
};
export const Invalid = {
render: Template,
export const IsInvalid = {
render: InvalidTemplate,
args: {
...defaultProps,
validationState: "invalid",
isRequired: true,
description: "Please select an option",
},
};
@ -185,6 +254,7 @@ export const WithErrorMessage = {
args: {
...defaultProps,
isRequired: true,
validationState: "invalid",
errorMessage: "The selected option is invalid",
},

View File

@ -156,6 +156,7 @@ export function useSelect<T extends object>(originalProps: UseSelectProps<T>) {
popoverProps: userPopoverProps,
scrollShadowProps: userScrollShadowProps,
listboxProps: userListboxProps,
validationState,
spinnerProps,
onChange,
onClose,
@ -256,7 +257,7 @@ export function useSelect<T extends object>(originalProps: UseSelectProps<T>) {
const hasHelper = !!description || !!errorMessage;
const hasPlaceholder = !!placeholder;
const isInvalid = props.validationState === "invalid";
const isInvalid = validationState === "invalid" || originalProps.isInvalid;
const shouldLabelBeOutside =
labelPlacement === "outside-left" || (labelPlacement === "outside" && hasPlaceholder);
const shouldLabelBeInside = labelPlacement === "inside";

View File

@ -923,14 +923,14 @@ export const WithErrorMessage = {
},
};
export const InvalidValidationState = {
export const IsInvalid = {
render: Template,
args: {
...defaultProps,
isInvalid: true,
variant: "bordered",
defaultSelectedKeys: ["dog"],
validationState: "invalid",
errorMessage: "Please select a valid animal",
},
};

View File

@ -157,6 +157,12 @@ const checkbox = tv({
base: "opacity-disabled pointer-events-none",
},
},
isInvalid: {
true: {
wrapper: "before:border-danger",
label: "text-danger",
},
},
disableAnimation: {
true: {
wrapper: "transition-none",
@ -165,15 +171,16 @@ const checkbox = tv({
},
false: {
wrapper: [
"before:transition-background",
"before:transition-colors",
"group-data-[pressed=true]:scale-95",
"transition-transform",
"after:transition-transform-opacity",
"after:!ease-linear",
"after:!duration-200",
"motion-reduce:transition-none",
],
icon: "transition-opacity",
label: "transition-opacity before:transition-width",
icon: "transition-opacity motion-reduce:transition-none",
label: "transition-colors-opacity before:transition-width motion-reduce:transition-none",
},
},
},
@ -207,6 +214,29 @@ const checkboxGroup = tv({
description: "text-small text-foreground-400",
errorMessage: "text-small text-danger",
},
variants: {
isRequired: {
true: {
label: "after:content-['*'] after:text-danger after:ml-0.5",
},
},
isInvalid: {
true: {
description: "text-danger",
},
},
disableAnimation: {
true: {},
false: {
description: "transition-colors !duration-150 motion-reduce:transition-none",
},
},
},
defaultVariants: {
isInvalid: false,
isRequired: false,
disableAnimation: false,
},
});
export type CheckboxGroupSlots = keyof ReturnType<typeof checkboxGroup>;

View File

@ -125,8 +125,14 @@ const radio = tv({
disableAnimation: {
true: {},
false: {
wrapper: ["group-data-[pressed=true]:scale-95", "transition-transform-background"],
control: "transition-transform-opacity",
wrapper: [
"group-data-[pressed=true]:scale-95",
"transition-transform-colors",
"motion-reduce:transition-none",
],
control: "transition-transform-opacity motion-reduce:transition-none",
label: "transition-colors motion-reduce:transition-none",
description: "transition-colors motion-reduce:transition-none",
},
},
},
@ -160,6 +166,29 @@ const radioGroup = tv({
description: "text-tiny text-foreground-400",
errorMessage: "text-tiny text-danger",
},
variants: {
isRequired: {
true: {
label: "after:content-['*'] after:text-danger after:ml-0.5",
},
},
isInvalid: {
true: {
description: "text-danger",
},
},
disableAnimation: {
true: {},
false: {
description: "transition-colors !duration-150 motion-reduce:transition-none",
},
},
},
defaultVariants: {
isInvalid: false,
isRequired: false,
disableAnimation: false,
},
});
export type RadioGroupSlots = keyof ReturnType<typeof radioGroup>;