mirror of
https://github.com/nextui-org/nextui.git
synced 2025-12-08 19:26:11 +00:00
fix(packages): validation state deprecated, isInvalid prop adjusted (#1631)
This commit is contained in:
parent
a5a1ea5ade
commit
425a034bca
9
.changeset/rotten-cats-search.md
Normal file
9
.changeset/rotten-cats-search.md
Normal 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
|
||||
@ -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,
|
||||
};
|
||||
|
||||
31
apps/docs/content/components/checkbox-group/invalid.ts
Normal file
31
apps/docs/content/components/checkbox-group/invalid.ts
Normal 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,
|
||||
};
|
||||
@ -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"
|
||||
/>
|
||||
|
||||
@ -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"
|
||||
/>
|
||||
|
||||
@ -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,
|
||||
|
||||
35
apps/docs/content/components/radio-group/invalid.ts
Normal file
35
apps/docs/content/components/radio-group/invalid.ts
Normal 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,
|
||||
};
|
||||
@ -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}
|
||||
|
||||
@ -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"
|
||||
/>
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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. | - |
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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. | - |
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -105,7 +105,7 @@ describe("Checkbox", () => {
|
||||
<Checkbox
|
||||
{...props}
|
||||
isSelected={value}
|
||||
onChange={(checked) => {
|
||||
onValueChange={(checked) => {
|
||||
act(() => {
|
||||
setValue(checked);
|
||||
onChange(checked);
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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",
|
||||
},
|
||||
};
|
||||
|
||||
@ -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");
|
||||
});
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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",
|
||||
},
|
||||
|
||||
@ -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",
|
||||
},
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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 =
|
||||
|
||||
@ -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",
|
||||
},
|
||||
|
||||
@ -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";
|
||||
|
||||
@ -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",
|
||||
},
|
||||
};
|
||||
|
||||
@ -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>;
|
||||
|
||||
@ -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>;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user