* chore(root): reat-aria packages updated (#2889)

* chore(storybook): common colors enabled (#2902)

* fix(range-calendar): hide only dates outside the month (#2906)

* fix(range-calendar): hide only dates outside the month #2890

* fix(range-calendar): corrected spelling mistake in changeset description

* fix(range-calendar): corrected capitalization in changeset description

* chore(changeset): patch @nextui-org/theme

---------

Co-authored-by: shrinidhi.upadhyaya <shrinidhi.upadhyaya@stud.uni-bamberg.de>
Co-authored-by: աɨռɢӄաօռɢ <wingkwong.code@gmail.com>

* fix(date-picker): keep date picker style consistent for different variants (#2908)

* fix: add missing TableRowProps export (#2866)

* fix: add missing TableRowProps export

* feat(changeset): add changeset for PR2866

* chore(changeset): revise changeset message

---------

Co-authored-by: աɨռɢӄաօռɢ <wingkwong.code@gmail.com>

* fix(input): correct label margin for RTL required inputs (#2781)

* fix(input): correct label margin for RTL required inputs

* fix(theme): add changeset fr theme

* docs(core): add storybook and canary release info (#2914)

* Cn utility refactor (#2915)

* refactor(core): cn utility adjusted and moved to the theme package

* chore(root): changeset

* fix(storybook): stories that used cn

* docs(date-picker): change to jsx instead (#2919)

* fix(switch): support uncontrolled switch in react-hook-form (#2924)

* feat(switch): add @nextui-org/use-safe-layout-effect

* chore(deps): add @nextui-org/use-safe-layout-effect

* fix(switch): react-hook-form uncontrolled switch component

* fix(switch): react-hook-form uncontrolled switch component

* feat(switch): add rect-hook-form in dev dep

* feat(switch): add WithReactHookFormTemplate

* refactor(root): react aria packages fixed (#2944)

* feat(docs): docs changes (#2868)

* feat(docs): add example how to set locale (#2867)

* docs(guide): add an explanation for the installation guide (#2769)

* docs(guide): add an explanation for the installation guide

* docs(guide): add an explanation for the cli guide

* docs(guide): add support for cli output

* fix: change sort priority - cmdk (#2873)

* docs: remove unsupported props in range calendar and date range picker (#2881)

* chore(calendar): remove showMonthAndYearPickers from range calendar story

* docs(date-range-picker): remove showMonthAndYearPickers info

* docs(range-calendar): remove unsupported props

* docs: refactor typing in form.ts (#2882)

* chore(docs): supplement errorMessage behaviour in input (#2892)

* refactor(docs): revise NextUI Provider structure

* chore(docs): add updated tag

---------

Co-authored-by: Nozomi-Hijikata <116155762+Nozomi-Hijikata@users.noreply.github.com>
Co-authored-by: HaRuki <soccer_haruki15@me.com>
Co-authored-by: Kaben <carnoxen@gmail.com>

* fix(slider): missing marks when hideThumb is true & revise slider styles (#2883)

* chore(slider): include marks in hideThumb

* fix(slider): revise slider styles

* feat(changeset): add changeset

* feat(slider): add tests with marks and hideThumb

* feat(test): react hook form tests & stories (#2931)

* feat(input): add Input with React Hook Form tests

* refactor(input): add missing types

* feat(checkbox): add checkbox with React Hook Form tests

* feat(select): add react-hook-form to dev dep

* feat(select): add react hook form story

* feat(select): react hook form tests

* fix(select): incorrect button reference

* feat(deps): add react-hook-form to dev dep in autocomplete

* feat(autocomplete): react hook form story

* feat(autocomplete): react hook form tests

* fix(autocomplete): rollback wrapper type

* feat(switch): add react hook form tests

* refactor(stories): reorder stories items

* fix: update accordion item heading tag to be customizable (#2265)

* fix: update accordion item heading tag to be customizable

* Update .changeset/heavy-hairs-join.md

Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>

* Update .changeset/heavy-hairs-join.md

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* chore(accordion): lint

* chore(changeset): add issue number

* feat(docs): add HeadingComponent prop

---------

Co-authored-by: Shawn Dong <shawn.dong@flybuys.com.au>
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: աɨռɢӄաօռɢ <wingkwong.code@gmail.com>

* fix(theme): add pointer-events-none to skeleton base (#2972)

* feat(tabs): add `destroyInactiveTabPanel` prop for Tabs component (#2973)

* feat(tabs): add destroyInactiveTabPanel and set default to false

* feat(tabs): integrate with destroyInactiveTabPanel

* feat(theme): hidden inert tab panel

* feat(changeset): add changeset

* chore(changeset): add issue number

* feat(docs): add `destroyInactiveTabPanel` prop to tabs page

* chore(docs): set destroyInactiveTabPanel to true by default

* chore(tabs): set destroyInactiveTabPanel to true by default

* chore(tabs): revise destroyInactiveTabPanel logic

* feat(tabs): add tests for destroyInactiveTabPanel

* chore(tabs): change the default value of destroyInactiveTabPanel to true

* refactor: add support for disabling the animation globally (#2929)

* refactor: add support for disabling the animation globally

* chore(docs): disableAnimation removed from global provider

* feat(docs): nextui provider api updated, storybook preview adjusted

* chore(theme): button is scalable when disabled, tooltip animation improved

* fix(theme): remove origin-bottom from button (#2990)

* fix(skeleton): overflow issue in skeleton (#2986)

* fix(theme): set overflow visible after skeleton loaded

* feat(changeset): add changeset

* fix(table): v2 input/textarea don't allow spaces inside a table (#3020)

* fix(table): set onKeyDownCapture to undefined

* feat(changeset): add changeset

* fix(slider): calculate the correct value on mark click (#3017)

* fix(slider): calculate the correct value on mark click

* refactor(slider): remove the tests inside describe block

* feat(slider): add tests for thumb move on mark click

* refactor(slider): use val instead of pos

* fix(theme): revise input isInvalid styles (#3010)

* fix(theme): revise isInvalid input styles

* feat(changeset): add changeset

* feat(date-picker): add missing ref to input wrapper (#3011)

* fix(date-picker): add missing ref to input wrapper

* feat(changeset): add changeset

* fix(core): incorrect tailwind classnames (#3018)

* fix(dropdown): focus behaviour on press / enter keydown (#2970)

* fix(dropdown): set focus on the first item

* feat(dropdown): add keyboard interactions tests

* feat(changeset): add changeset

* fix(dropdown): use fireEvent.keyDown instead

* chore(deps): add @nextui-org/test-utils to dropdown

* refactor(dropdown): pass onKeyDown to menu trigger and don't hardcode autoFocus

* chore(dropdown): remove autoFocus

* fix(menu): pass userMenuProps to useTreeState and useAriaMenu and remove from getListProps

* chore(changeset): add menu package

* fix(component): update type definition to prevent primitive values as items (#2953)

* fix: update type definition to prevent primitive values as items

* fix: typecheck

* fix(select): onSelectionChange can handle number (#2937)

* fix: onSelectionChange type for dynamic items in Select component

* docs: remove unnecessary properties

* docs: update highlightedLines

* chore: add changeset

* fix(calendar): scrolling is hidden when changing the month (#2949)

* fix(calendar): scrolling is hidden when changing the month

* chore(changeset): correct package name

---------

Co-authored-by: Poli Sour <polisour.work@gmail.com>
Co-authored-by: WK Wong <wingkwong.code@gmail.com>

* fix: make VisuallyHidden's element type as span when it's inside phrasing element (#3013)

* fix(checkbox): make VisuallyHidden's element type as span

* feat(changeset): add changeset

* fix(radio): make the VisuallyHidden element type as span

* fix(switch): make the VisuallyHidden element type as span

* fix(select): make the VisuallyHidden element type as span

* feat(changeset): replace changeset

* chore: fix formatting

* docs: sync nextui-cli  api (#3035)

* docs: sync nextui-cli  api

* docs: update

* chore: update routes.json with new path and set updated flag

---------

Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>

* feat: switch default validationBehavior to aria and allow switching via props (#2987)

* chore: add support validationBehavior aria

* chore: add validationBehavior to Provider

* chore: add autocomplete validation test

* chore: add checkbox validation test

* fix(input): require condition

* docs: add description of validationBehavior props

* chore: add support validationBehavior props for date components

* docs(dates): add description of validationBehavior props

* chore: add changeset

* chore: format

* chore: fix test

* fix: select validationBehavior is not support yet

* fix: select validationBehavior not supported yet

* chore(docs): validation behavior prop added to nextui-provider

---------

Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>

* fix: popover-based focus behaviour (#2854)

* fix(autocomplete): autocomplete focus behaviour

* feat(autocomplete): add test case for catching blur cases

* refactor(autocomplete): use isOpen instead

* feat(autocomplete): add "should focus when clicking autocomplete" test case

* feat(autocomplete): add should set the input after selection

* fix(autocomplete): remove shouldUseVirtualFocus

* fix(autocomplete): uncomment blur logic

* refactor(autocomplete): remove state as it is in getPopoverProps

* refactor(autocomplete): remove unnecessary blur

* refactor(select): remove unncessary props

* fix(popover): use domRef instead

* fix(popover): revise isNonModal and isDismissable

* fix(popover): use dialogRef back

* fix(popover): rollback

* fix(autocomplete): onFocus logic

* feat(popover): set disableFocusManagement to overlay

* feat(modal): set disableFocusManagement to overlay

* fix(autocomplete): set disableFocusManagement for autocomplete

* feat(popover): include disableFocusManagement prop

* refactor(autocomplete): revise type in selectorButton

* fix(autocomplete): revise focus logic

* feat(autocomplete): add internal focus state and add shouldCloseOnInteractOutside

* feat(autocomplete): handle selectedItem change

* feat(autocomplete): add clear button test

* feat(changeset): add changeset

* refactor(components): use the original order

* refactor(autocomplete): add more comments

* fix(autocomplete): revise focus behaviours

* refactor(autocomplete): rename to listbox

* chore(popover): remove disableFocusManagement from popover

* chore(autocomplete): remove disableFocusManagement from autocomplete

* chore(changeset): add issue number

* fix(popover): don't set default value to transformOrigin

* fix(autocomplete): revise shouldCloseOnInteractOutside logic

* feat(autocomplete): should close listbox by clicking another autocomplete

* fix(popover): add disableFocusManagement to overlay

* refactor(autocomplete): revise comments and refactor shouldCloseOnInteractOutside

* feat(changeset): add issue number

* fix(autocomplete): merge with selectorButtonProps.onClick

* refactor(autocomplete): remove extra line

* refactor(autocomplete): revise comment

* feat(select): add shouldCloseOnInteractOutside

* feat(dropdown): add shouldCloseOnInteractOutside

* feat(date-picker): add shouldCloseOnInteractOutside

* feat(changeset): add dropdown and date-picker

* fix(popover): revise shouldCloseOnInteractOutside

* feat(date-picker): integrate with ariaShouldCloseOnInteractOutside

* feat(select): integrate with ariaShouldCloseOnInteractOutside

* feat(dropdown): integrate with ariaShouldCloseOnInteractOutside

* feat(popover): integrate with ariaShouldCloseOnInteractOutside

* feat(aria-utils): ariaShouldCloseOnInteractOutside

* chore(deps): update pnpm-lock.yaml

* feat(autocomplete): integrate with ariaShouldCloseOnInteractOutside

* feat(aria-utils): handle setShouldFocus logic

* feat(changeset): add @nextui-org/aria-utils

* chore(autocomplete): put the test into correct group

* feat(select): should close listbox by clicking another select

* feat(dropdown): should close listbox by clicking another dropdown

* feat(popover): should close listbox by clicking another popover

* feat(date-picker): should close listbox by clicking another datepicker

* chore(changeset): add issue numbers and revise changeset message

* refactor(autocomplete): change to useRef instead

* refactor(autocomplete): change to useRef instead

* refactor(aria-utils): revise comments and format code

* chore(changeset): add issue number

* chore: take popoverProps.shouldCloseOnInteractOutside first

* refactor(autocomplete): remove unnecessary logic

* refactor(autocomplete): focus management logic

* fix(components): Fix 'Tap to click' behavior on macOS with Edge/Chrome for Accordion and Tab (#2725)

* fix(components): fix 'Tap to click' behavior on macOS

* Add change file for accordion, menu, and tabs

* Remove 'fix(components)' from the .changeset file

* fix(components): undo dropdown change now that it's no longer applicable

* fix(components): update changeset file now that we are no longer modifying the dropdown component

* fix(date-picker): corrected inert value for true condition (#3054)

* fix(date-picker): corrected inert value for true condition #3044

* refactor(calendar): add todo comment

* feat(changeset): add changeset

---------

Co-authored-by: shrinidhi.upadhyaya <shrinidhi.upadhyaya@stud.uni-bamberg.de>
Co-authored-by: WK Wong <wingkwong.code@gmail.com>

* fix(hooks): resolve type error in onKeyDown event handler (#3064)

* fix(hooks): resolve type error in onKeyDown event handler

* chore(changeset): revise changeset

---------

Co-authored-by: WK Wong <wingkwong.code@gmail.com>

* Update dependency array on setPage useCallback hook (#3029)

Changes:
Add the onChangeActivePage function to the dependency array of the setPage useCallback hook to ensure it always reflects the latest state.

Impact:
This fix ensures that the pagination component accurately reflects the current state when triggering onChangeActivePage.

* fix: error peerDep in pkg (#3014)

* fix: error peerDep in pkg

* docs: changeset

* Fix DatePicker Time Input (#2845)

* fix(date-picker): set `isCalendarHeaderExpanded` to `false` when DatePicker is closed

* fix(date-picker): calendar header controlled state on DatePicker

* chore(date-picker): update test

* chore(date-picker): remove unnecessary `async` in test

* Update packages/components/date-picker/__tests__/date-picker.test.tsx

---------

Co-authored-by: WK Wong <wingkwong.code@gmail.com>
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>

* fix(date-picker): test

* fix(hooks): optimize useScrollPosition with useCallback and useRef (#3049)

* fix(hooks): optimize useScrollPosition with useCallback and useRef

* Update .changeset/lucky-cobras-jog.md

* Update packages/hooks/use-scroll-position/src/index.ts

* Update packages/hooks/use-scroll-position/src/index.ts

---------

Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>

* fix(select): placeholder text display for controlled component (#3081)

* fix: return placeholder when selectedItems is empty

* chore: add test and changeset

* chore(docs): v2.4.0 (#3084)

* chore(docs): v2.4.0

* chore(docs): v2.4.0 blog

* chore(docs): revise typos based on coderabbitai

* chore(docs): adjust navbar

---------

Co-authored-by: WK Wong <wingkwong.code@gmail.com>

* chore(changese): update @nextui-org/react dependency to minor version

* docs: update cli docs (#3096)

* ci(changesets): version packages (#2903)

Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>

---------

Co-authored-by: Shrinidhi Upadhyaya <shrinidhiupadhyaya1195@gmail.com>
Co-authored-by: shrinidhi.upadhyaya <shrinidhi.upadhyaya@stud.uni-bamberg.de>
Co-authored-by: աɨռɢӄաօռɢ <wingkwong.code@gmail.com>
Co-authored-by: Paul Tiedtke <PaulTiedtke@web.de>
Co-authored-by: Mohammad Reza Badri <85818966+mrbadri@users.noreply.github.com>
Co-authored-by: Nozomi-Hijikata <116155762+Nozomi-Hijikata@users.noreply.github.com>
Co-authored-by: HaRuki <soccer_haruki15@me.com>
Co-authored-by: Kaben <carnoxen@gmail.com>
Co-authored-by: Shawn Dong <dsknight@live.com.au>
Co-authored-by: Shawn Dong <shawn.dong@flybuys.com.au>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Ryo Matsukawa <76232929+ryo-manba@users.noreply.github.com>
Co-authored-by: Poli Sour <57824881+novsource@users.noreply.github.com>
Co-authored-by: Poli Sour <polisour.work@gmail.com>
Co-authored-by: Artem Pitikin <git@kosmotema.dev>
Co-authored-by: winches <329487092@qq.com>
Co-authored-by: Eric Abreu <ericfabreu@gmail.com>
Co-authored-by: Minsu <52266597+Gaic4o@users.noreply.github.com>
Co-authored-by: Jesus Perdomo Lampignano <38929969+jesuzon@users.noreply.github.com>
Co-authored-by: chirokas <157580465+chirokas@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This commit is contained in:
Junior Garcia 2024-05-27 19:51:30 -03:00 committed by GitHub
parent a3bf209171
commit 67347d8713
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
337 changed files with 6075 additions and 2489 deletions

View File

@ -154,6 +154,16 @@ export const Cmdk: FC<{}> = () => {
}
};
const prioritizeFirstLevelItems = (a: SearchResultItem, b: SearchResultItem) => {
if (a.type === "lvl1") {
return -1;
} else if (b.type === "lvl1") {
return 1;
}
return 0;
};
const results = useMemo<SearchResultItem[]>(
function getResults() {
if (query.length < 2) return [];
@ -165,12 +175,22 @@ export const Cmdk: FC<{}> = () => {
if (words.length === 1) {
return matchSorter(data, query, {
keys: MATCH_KEYS,
sorter: (matches) => {
matches.sort((a, b) => prioritizeFirstLevelItems(a.item, b.item));
return matches;
},
}).slice(0, MAX_RESULTS);
}
const matchesForEachWord = words.map((word) =>
matchSorter(data, word, {
keys: MATCH_KEYS,
sorter: (matches) => {
matches.sort((a, b) => prioritizeFirstLevelItems(a.item, b.item));
return matches;
},
}),
);

View File

@ -35,11 +35,11 @@ export const Hero = () => {
color="default"
href="/blog/v2.3.0"
variant="dot"
onClick={() => handlePressAnnouncement("Introducing v2.3.0", "/blog/v2.3.0")}
onClick={() => handlePressAnnouncement("New version v2.4.0", "/blog/v2.4.0")}
>
Introducing v2.3.0&nbsp;
<span aria-label="tada emoji" role="img">
🎉
New version v2.4.0&nbsp;
<span aria-label="emoji" role="img">
🚀
</span>
</Chip>
</div>

View File

@ -312,13 +312,13 @@ export const Navbar: FC<NavbarProps> = ({children, routes, mobileRoutes = [], sl
as={NextLink}
className="bg-default-100/50 hover:bg-default-100 border-default-200/80 dark:border-default-100/80 transition-colors cursor-pointer"
color="default"
href="/blog/v2.3.0"
href="/blog/v2.4.0"
variant="dot"
onClick={() => handlePressNavbarItem("Introducing v2.3.0", "/blog/v2.3.0")}
onClick={() => handlePressNavbarItem("New version v2.4.0", "/blog/v2.4.0")}
>
Introducing v2.3.0&nbsp;
<span aria-label="tada emoji" role="img">
🎉
New version v2.4.0&nbsp;
<span aria-label="emoji" role="img">
🚀
</span>
</Chip>
</NavbarItem>

View File

@ -154,7 +154,8 @@
"key": "badge",
"title": "Badge",
"keywords": "badge, markers, status indication, count display",
"path": "/docs/components/badge.mdx"
"path": "/docs/components/badge.mdx",
"updated": true
},
{
"key": "button",
@ -334,7 +335,8 @@
"key": "skeleton",
"title": "Skeleton",
"keywords": "skeleton, loading state, placeholder, content preview",
"path": "/docs/components/skeleton.mdx"
"path": "/docs/components/skeleton.mdx",
"updated": true
},
{
"key": "snippet",
@ -415,13 +417,15 @@
"key": "cli-api",
"title": "NextUI CLI",
"keywords": "api references, nextui, api, cli",
"path": "/docs/api-references/cli-api.mdx"
"path": "/docs/api-references/cli-api.mdx",
"updated": true
},
{
"key": "nextui-provider",
"title": "NextUI Provider",
"keywords": "api references, nextui, api, nextui provider",
"path": "/docs/api-references/nextui-provider.mdx"
"path": "/docs/api-references/nextui-provider.mdx",
"updated": true
}
]
}

View File

@ -0,0 +1,333 @@
---
title: "Introducing v2.4.0"
description: "NextUI v2.4.0 is here! includes tons of bug fixes, the possibility to globally disable the animations and improvements."
date: "2024-05-27"
image: "/blog/v2.4.0.jpg"
tags: ["nextui", "v2.4.0", "release", "bug fixes", "improvements", "animations"]
author:
name: "WK Wong"
username: "@wingkwong"
link: "https://github.com/wingkwong"
avatar: "https://avatars.githubusercontent.com/u/35857179?v=4"
---
<img
src="/blog/v2.4.0_2x.jpg"
width={700}
height={350}
alt="NextUI v2.4.0"
className="w-full border border-transparent dark:border-default-200/50 object-fit rounded-xl shadow-lg"
/>
We are excited to announce the latest update to NextUI, version **2.4.0**! This release introduces 60+ bug fixes, dependencies upgrades, improvements in API and CLI and more.
## What's New in v2.4.0?
- [Disable Animations Globally](#disable-animations-globally) - Allows users to disable animation globally via NextUIProvider
- [API Improvements](#api-improvements) - Includes several props like `disableRipple`, `skipFramerMotionAnimations` and `validationBehavior`
- [CLI Improvements](#cli-improvements) - Includes new command options and optimizes performance
- [React Aria Packages Upgrades](#react-aria-packages-upgrades) - Upgrades and fixes the exact versions of React Aria
- [Other Changes](#other-changes) - Includes styling improvements, accessibility, usability enhancements and over 60 bug fixes across different component packages
<Spacer y={4} />
Upgrade today by running one of the following commands:
<Spacer y={4} />
<PackageManagers
commands={{
cli: "nextui upgrade",
npm: "npx nextui-cli@latest upgrade",
}}
/>
<Spacer y={4} />
## Disable Animations Globally
NextUI components are animated by default and can be disabled by setting the prop `disableAnimation` individually. Since v2.4.0, you can globally disable the animation by setting `disableAnimation` to `NextUIProvider`.
```tsx
"use client";
import {type ReactNode} from "react";
import {NextUIProvider} from "@nextui-org/react";
export function AppProvider(props: AppProviderProps) {
const {children, className} = props;
return (
<NextUIProvider className={className} disableAnimation>
{children}
</NextUIProvider>
);
}
interface AppProviderProps {
children: ReactNode;
className?: string;
}
```
<Spacer y={4} />
## API Improvements
### disableRipple
By default, there is a ripple effect on press in Button and Card component and can be disabled by setting the prop `disableRipple` individually. Since v2.4.0, it can be disabled globally by setting `disableRipple` to `NextUIProvider`.
```tsx
"use client";
import {type ReactNode} from "react";
import {NextUIProvider} from "@nextui-org/react";
export function AppProvider(props: AppProviderProps) {
const {children, className} = props;
return (
<NextUIProvider className={className} disableRipple>
{children}
</NextUIProvider>
);
}
interface AppProviderProps {
children: ReactNode;
className?: string;
}
```
### skipFramerMotionAnimations
We can control whether `framer-motion` animations are skipped within the application. This property is automatically enabled (`true`) when the `disableAnimation` prop is set to `true`, effectively skipping all `framer-motion` animations. To retain `framer-motion` animations while using the `disableAnimation` prop for other purposes, set this to `false`. However, note that animations in NextUI Components are still omitted if the `disableAnimation` prop is `true`.
```tsx
"use client";
import {type ReactNode} from "react";
import {NextUIProvider} from "@nextui-org/react";
export function AppProvider(props: AppProviderProps) {
const {children, className} = props;
return (
<NextUIProvider className={className} skipFramerMotionAnimations>
{children}
</NextUIProvider>
);
}
interface AppProviderProps {
children: ReactNode;
className?: string;
}
```
### validationBehavior
We can set `validationBehavior` to either `native` or `aria` to control whether to use native HTML form validation to prevent form submission when the value is missing or invalid, or mark the field as required or invalid via ARIA. If it is not specified, `aria` will be used by default.
```tsx
"use client";
import {type ReactNode} from "react";
import {NextUIProvider} from "@nextui-org/react";
export function AppProvider(props: AppProviderProps) {
const {children, className} = props;
return (
<NextUIProvider className={className} validationBehavior="native">
{children}
</NextUIProvider>
);
}
interface AppProviderProps {
children: ReactNode;
className?: string;
}
```
<Spacer y={4} />
## CLI Improvements
### Refactor Init Flow View
We've refactored the init flow view to provide a better user experience.
The latest flow view output:
```bash
┌ Create a new project
◇ Select a template (Enter to select)
│ ● App (A Next.js 14 with app directory template pre-configured with NextUI (v2) and Tailwind CSS.)
│ ○ Pages (A Next.js 14 with pages directory template pre-configured with NextUI (v2) and Tailwind CSS.)
│ ○ Vite (A Vite template pre-configured with NextUI (v2) and Tailwind CSS.)
◇ New project name (Enter to skip with default name)
│ my-nextui-app
◇ Select a package manager (Enter to select)
│ ● npm
│ ○ yarn
│ ○ pnpm
│ ○ bun
◇ Template created successfully!
◇ Next steps ───────╮
│ │
│ cd my-nextui-app │
│ npm install │
│ │
├────────────────────╯
└ 🚀 Get started with npm run dev
```
### Add Vite Template
We've introduced a new Vite template pre-configured with NextUI v2 and TailwindCSS. The following command is to initialize a new Vite project named `my-vite-app`.
```bash
nextui init my-vite-app -t vite
```
### Package Manager Flag
We've introduced a new flag `-p` (or `--package`) to init command to allow users to choose the package manager to use for the new project. By default, `npm` is used. For example, the following command will initialize a new NextUI project with the app template named my-nextui-app using pnpm package manager.
```bash
nextui init my-nextui-app -t app -p pnpm
```
### no-cache Flag
We've introduced a new flag `--no-cache` to allow users to disable the cache. By default, the data will be cached for 30 mins after the first request. It is useful when the data is cached, and you wish to upgrade to the new version just released after the first request. In this way, you can run the following command
```bash
nextui --no-cache upgrade
```
### Upgrade Version Output
You can now run the upgrade command and see the summary version of the package you are upgrading to.
![image](https://github.com/nextui-org/nextui-cli/assets/96854855/2a5945dd-5187-4e20-81b8-4136e9791dde)
### Upgrade And Remove Select View Optimization
The disabled option(s) will be displayed in the bottom of the list.
![image](https://github.com/nextui-org/nextui-cli/assets/96854855/c7ddf9e4-3054-4bf1-b8e3-dc2f6226091a)
### Doctor Command add peerDependencies check
The `doctor` command now checks for peerDependencies and displays the incorrect peerDependencies, relation: [nextui-org/nextui#2954](https://github.com/nextui-org/nextui/issues/2954).
<Spacer y={4} />
## React Aria Packages Upgrades
We've upgraded and fixed React Aria packages dependencies across our components. This update focuses on enhancing accessibility, ensuring better compatibility with the latest versions of React Aria, and resolving previously reported bugs.
<Spacer y={4} />
## Breaking Changes
### Export improved `cn` utility
> If you are using it from `@nextui-org/react`, no changes are required.
The new `cn` utility exported from the `@nextui-org/theme` package includes `tailwind-merge` to avoid conflicts between tailwindcss classes overrides and includes the config for NextUI custom classes.
If you are using the `cn` utility from the `@nextui-org/system`,
```diff-tsx
-import {cn} from "@nextui-org/system"
```
or `@nextui-org/system-rsc` package,
```diff-tsx
-import {cn} from "@nextui-org/system-rsc"
```
you need to update the import as follows:
```diff-tsx
+ import {cn} from "@nextui-org/theme"
```
<Spacer y={4} />
## Other Changes
**Bug Fixes**:
- Fixed popover-based focus behaviours. [PR](https://github.com/nextui-org/nextui/pull/2889) - [@wingkwong](https://github.com/wingkwong)
- Fixed missing ref to input wrapper. [PR](https://github.com/nextui-org/nextui/pull/3008) - [@wingkwong](https://github.com/wingkwong)
- Fixed react-hook-form uncontrolled switch component. [PR](https://github.com/nextui-org/nextui/pull/3008) - [@wingkwong](https://github.com/wingkwong)
- Fixed focus on the first item when pressing Space / Enter key on dropdown menu open. [PR](https://github.com/nextui-org/nextui/pull/2970) - [@wingkwong](https://github.com/wingkwong)
- Fixed inputting spaces in textarea inside a Table row. [PR](https://github.com/nextui-org/nextui/pull/3020) - [@wingkwong](https://github.com/wingkwong)
- Fixed incorrect tailwind classnames. [PR](https://github.com/nextui-org/nextui/pull/3018) - [@wingkwong](https://github.com/wingkwong)
- Fixed onSelectionChange can handle number [PR](https://github.com/nextui-org/nextui/pull/2937) - [@ryo-manba](https://github.com/ryo-manba)
- Fixed update type definition to prevent primitive values as items [PR](https://github.com/nextui-org/nextui/pull/2938) - [@ryo-manba](https://github.com/ryo-manba)
- Fixed display placeholder text when unselected for controlled. [PR](https://github.com/nextui-org/nextui/pull/3081) - [@ryo-manba](https://github.com/ryo-manba)
- Fixed the inert attribute in `CalendarMonth` and `CalendarPicker`. [PR](https://github.com/nextui-org/nextui/pull/3054) - [@ShrinidhiUpadhyaya](https://github.com/ShrinidhiUpadhyaya)
- Fixed hiding of unavailable dates in RangeCalendar. [PR](https://github.com/nextui-org/nextui/pull/3054) - [@ShrinidhiUpadhyaya](https://github.com/ShrinidhiUpadhyaya)
- Fixed calendar header controlled state on DatePicker. [PR](https://github.com/nextui-org/nextui/pull/2845) - [@chirokas](https://github.com/chirokas)
- Fixed 'Tap to click' behavior on macOS for Accordion and Tab. [PR](https://github.com/nextui-org/nextui/pull/2725) - [@ericfabreu](https://github.com/ericfabreu)
- Fixed incorrect margin on labels for RTL required inputs. [PR](https://github.com/nextui-org/nextui/pull/2781) - [@mrbadri](https://github.com/mrbadri)
- Fixed a type error in the onKeyDown event handler for the menu component. [PR](https://github.com/nextui-org/nextui/pull/3064) - [@Gaic4o](https://github.com/Gaic4o)
**Improvements**
- Added `destroyInactiveTabPanel` prop for Tabs component. [PR](https://github.com/nextui-org/nextui/pull/2973) - [@wingkwong](https://github.com/wingkwong)
- Added pointer-events-none to skeleton base. [PR](https://github.com/nextui-org/nextui/pull/2972) - [@wingkwong](https://github.com/wingkwong)
- Revised isInvalid input styles. [PR](https://github.com/nextui-org/nextui/pull/3010) - [@wingkwong](https://github.com/wingkwong)
- Revised slider styles. [PR](https://github.com/nextui-org/nextui/pull/2883) - [@wingkwong](https://github.com/wingkwong)
- Removed unnecessary origin-bottom in button. [PR](https://github.com/nextui-org/nextui/pull/2990) - [@wingkwong](https://github.com/wingkwong)
- Set overflow visible after skeleton loaded. [PR](https://github.com/nextui-org/nextui/pull/2986) - [@wingkwong](https://github.com/wingkwong)
- Kept date picker style consistent for different variants. [PR](https://github.com/nextui-org/nextui/pull/2901) - [@wingkwong](https://github.com/wingkwong)
- Calculated the correct value on mark click. [PR](https://github.com/nextui-org/nextui/pull/3017) - [@wingkwong](https://github.com/wingkwong)
- Removed scrolling display during month change animation. [PR](https://github.com/nextui-org/nextui/pull/2949) - [@novsource](https://github.com/novsource)
- Added the correct peerDep version [PR](https://github.com/nextui-org/nextui/pull/3014) - [@winchesHe](https://github.com/winchesHe)
- Added missing export of TableRowProps type. [PR](https://github.com/nextui-org/nextui/pull/2866) - [@sapkra](https://github.com/sapkra)
- Changed validationBehavior from native to aria by default, with the option to change via props. [PR](https://github.com/nextui-org/nextui/pull/2987) - [@ryo-manba](https://github.com/ryo-manba)
- Made the VisuallyHidden elementType as span when the default parent element accepts only phrasing elements. [PR](https://github.com/nextui-org/nextui/pull/3013) - [@kosmotema](https://github.com/kosmotema)
- Refactored the useScrollPosition hook to improve performance and stability by using useCallback for the handler function and useRef for throttleTimeout. [PR](https://github.com/nextui-org/nextui/pull/3049) - [@Gaic4o](https://github.com/Gaic4o)
**Documentation**:
- Updated documentation to reflect the new features and changes in the components, API references, and CLI.
Special thanks to NextUI Team members [@kuri-sun](https://github.com/kuri-sun), [@ryo-manba](https://github.com/ryo-manba),
[@sudongyuer](https://github.com/sudongyuer), [@winchesHe](https://github.com/winchesHe), [@wingkwong](https://github.com/wingkwong),
[@tianenpang](https://github.com/tianenpang), [@smultar](https://github.com/smultar) and contributors for their contributions to this release.
For a full list of changes, please refer to the [release notes](https://github.com/nextui-org/nextui/releases/tag/%40nextui-org%2Freact%402.4.0).
<Spacer y={6} />
Thanks for reading and happy coding! 🚀
---
## Community
We're excited to see the community adopt NextUI, raise issues, and provide feedback.
Whether it's a feature request, bug report, or a project to showcase, please get involved!
<Community />
## Contributing
PR's on NextUI are always welcome, please see our [contribution guidelines](https://github.com/nextui-org/nextui/blob/main/CONTRIBUTING.md) to learn how you can contribute to this project.

View File

@ -1,4 +1,4 @@
const AppTs = `import {DatePicker} from "@nextui-org/react";
const App = `import {DatePicker} from "@nextui-org/react";
import {parseZonedDateTime, parseAbsoluteToLocal} from "@internationalized/date";
export default function App() {
@ -21,7 +21,7 @@ export default function App() {
}`;
const react = {
"/App.tsx": AppTs,
"/App.jsx": App,
};
export default {

View File

@ -19,7 +19,7 @@ export default function App() {
variant="bordered"
isInvalid={isInvalid}
color={isInvalid ? "danger" : "success"}
errorMessage={isInvalid && "Please enter a valid email"}
errorMessage="Please enter a valid email"
onValueChange={setValue}
className="max-w-xs"
/>

View File

@ -1,29 +1,17 @@
const data = `export const animals = [
{label: "Cat", value: "cat", description: "The second most popular pet in the world"},
{label: "Dog", value: "dog", description: "The most popular pet in the world"},
{label: "Elephant", value: "elephant", description: "The largest land animal"},
{label: "Lion", value: "lion", description: "The king of the jungle"},
{label: "Tiger", value: "tiger", description: "The largest cat species"},
{label: "Giraffe", value: "giraffe", description: "The tallest land animal"},
{
label: "Dolphin",
value: "dolphin",
description: "A widely distributed and diverse group of aquatic mammals",
},
{label: "Penguin", value: "penguin", description: "A group of aquatic flightless birds"},
{label: "Zebra", value: "zebra", description: "A several species of African equids"},
{
label: "Shark",
value: "shark",
description: "A group of elasmobranch fish characterized by a cartilaginous skeleton",
},
{
label: "Whale",
value: "whale",
description: "Diverse group of fully aquatic placental marine mammals",
},
{label: "Otter", value: "otter", description: "A carnivorous mammal in the subfamily Lutrinae"},
{label: "Crocodile", value: "crocodile", description: "A large semiaquatic reptile"},
{key: "cat", label: "Cat"},
{key: "dog", label: "Dog"},
{key: "elephant", label: "Elephant"},
{key: "lion", label: "Lion"},
{key: "tiger", label: "Tiger"},
{key: "giraffe", label: "Giraffe"},
{key: "dolphin", label: "Dolphin"},
{key: "penguin", label: "Penguin"},
{key: "zebra", label: "Zebra"},
{key: "shark", label: "Shark"},
{key: "whale", label: "Whale"},
{key: "otter", label: "Otter"},
{key: "crocodile", label: "Crocodile"}
];`;
const App = `import {Select, SelectItem} from "@nextui-org/react";
@ -51,7 +39,7 @@ export default function App() {
className="max-w-xs"
>
{animals.map((animal) => (
<SelectItem key={animal.value} value={animal.value}>
<SelectItem key={animal.key}>
{animal.label}
</SelectItem>
))}

View File

@ -1,29 +1,17 @@
const data = `export const animals = [
{label: "Cat", value: "cat", description: "The second most popular pet in the world"},
{label: "Dog", value: "dog", description: "The most popular pet in the world"},
{label: "Elephant", value: "elephant", description: "The largest land animal"},
{label: "Lion", value: "lion", description: "The king of the jungle"},
{label: "Tiger", value: "tiger", description: "The largest cat species"},
{label: "Giraffe", value: "giraffe", description: "The tallest land animal"},
{
label: "Dolphin",
value: "dolphin",
description: "A widely distributed and diverse group of aquatic mammals",
},
{label: "Penguin", value: "penguin", description: "A group of aquatic flightless birds"},
{label: "Zebra", value: "zebra", description: "A several species of African equids"},
{
label: "Shark",
value: "shark",
description: "A group of elasmobranch fish characterized by a cartilaginous skeleton",
},
{
label: "Whale",
value: "whale",
description: "Diverse group of fully aquatic placental marine mammals",
},
{label: "Otter", value: "otter", description: "A carnivorous mammal in the subfamily Lutrinae"},
{label: "Crocodile", value: "crocodile", description: "A large semiaquatic reptile"},
{key: "cat", label: "Cat"},
{key: "dog", label: "Dog"},
{key: "elephant", label: "Elephant"},
{key: "lion", label: "Lion"},
{key: "tiger", label: "Tiger"},
{key: "giraffe", label: "Giraffe"},
{key: "dolphin", label: "Dolphin"},
{key: "penguin", label: "Penguin"},
{key: "zebra", label: "Zebra"},
{key: "shark", label: "Shark"},
{key: "whale", label: "Whale"},
{key: "otter", label: "Otter"},
{key: "crocodile", label: "Crocodile"}
];`;
const SelectorIcon = `export const SelectorIcon = (props) => (
@ -62,7 +50,7 @@ export default function App() {
selectorIcon={<SelectorIcon />}
>
{animals.map((animal) => (
<SelectItem key={animal.value} value={animal.value}>
<SelectItem key={animal.key}>
{animal.label}
</SelectItem>
))}

View File

@ -1,29 +1,17 @@
const data = `export const animals = [
{label: "Cat", value: "cat", description: "The second most popular pet in the world"},
{label: "Dog", value: "dog", description: "The most popular pet in the world"},
{label: "Elephant", value: "elephant", description: "The largest land animal"},
{label: "Lion", value: "lion", description: "The king of the jungle"},
{label: "Tiger", value: "tiger", description: "The largest cat species"},
{label: "Giraffe", value: "giraffe", description: "The tallest land animal"},
{
label: "Dolphin",
value: "dolphin",
description: "A widely distributed and diverse group of aquatic mammals",
},
{label: "Penguin", value: "penguin", description: "A group of aquatic flightless birds"},
{label: "Zebra", value: "zebra", description: "A several species of African equids"},
{
label: "Shark",
value: "shark",
description: "A group of elasmobranch fish characterized by a cartilaginous skeleton",
},
{
label: "Whale",
value: "whale",
description: "Diverse group of fully aquatic placental marine mammals",
},
{label: "Otter", value: "otter", description: "A carnivorous mammal in the subfamily Lutrinae"},
{label: "Crocodile", value: "crocodile", description: "A large semiaquatic reptile"},
{key: "cat", label: "Cat"},
{key: "dog", label: "Dog"},
{key: "elephant", label: "Elephant"},
{key: "lion", label: "Lion"},
{key: "tiger", label: "Tiger"},
{key: "giraffe", label: "Giraffe"},
{key: "dolphin", label: "Dolphin"},
{key: "penguin", label: "Penguin"},
{key: "zebra", label: "Zebra"},
{key: "shark", label: "Shark"},
{key: "whale", label: "Whale"},
{key: "otter", label: "Otter"},
{key: "crocodile", label: "Crocodile"}
];`;
const App = `import {Select, SelectItem} from "@nextui-org/react";
@ -39,7 +27,7 @@ export default function App() {
className="max-w-xs"
>
{animals.map((animal) => (
<SelectItem key={animal.value} value={animal.value}>
<SelectItem key={animal.key}>
{animal.label}
</SelectItem>
))}

View File

@ -1,29 +1,17 @@
const data = `export const animals = [
{label: "Cat", value: "cat", description: "The second most popular pet in the world"},
{label: "Dog", value: "dog", description: "The most popular pet in the world"},
{label: "Elephant", value: "elephant", description: "The largest land animal"},
{label: "Lion", value: "lion", description: "The king of the jungle"},
{label: "Tiger", value: "tiger", description: "The largest cat species"},
{label: "Giraffe", value: "giraffe", description: "The tallest land animal"},
{
label: "Dolphin",
value: "dolphin",
description: "A widely distributed and diverse group of aquatic mammals",
},
{label: "Penguin", value: "penguin", description: "A group of aquatic flightless birds"},
{label: "Zebra", value: "zebra", description: "A several species of African equids"},
{
label: "Shark",
value: "shark",
description: "A group of elasmobranch fish characterized by a cartilaginous skeleton",
},
{
label: "Whale",
value: "whale",
description: "Diverse group of fully aquatic placental marine mammals",
},
{label: "Otter", value: "otter", description: "A carnivorous mammal in the subfamily Lutrinae"},
{label: "Crocodile", value: "crocodile", description: "A large semiaquatic reptile"},
{key: "cat", label: "Cat"},
{key: "dog", label: "Dog"},
{key: "elephant", label: "Elephant"},
{key: "lion", label: "Lion"},
{key: "tiger", label: "Tiger"},
{key: "giraffe", label: "Giraffe"},
{key: "dolphin", label: "Dolphin"},
{key: "penguin", label: "Penguin"},
{key: "zebra", label: "Zebra"},
{key: "shark", label: "Shark"},
{key: "whale", label: "Whale"},
{key: "otter", label: "Otter"},
{key: "crocodile", label: "Crocodile"}
];`;
const App = `import {Select, SelectItem} from "@nextui-org/react";
@ -38,7 +26,7 @@ export default function App() {
className="max-w-xs"
>
{animals.map((animal) => (
<SelectItem key={animal.value} value={animal.value}>
<SelectItem key={animal.key}>
{animal.label}
</SelectItem>
))}

View File

@ -1,29 +1,17 @@
const data = `export const animals = [
{label: "Cat", value: "cat", description: "The second most popular pet in the world"},
{label: "Dog", value: "dog", description: "The most popular pet in the world"},
{label: "Elephant", value: "elephant", description: "The largest land animal"},
{label: "Lion", value: "lion", description: "The king of the jungle"},
{label: "Tiger", value: "tiger", description: "The largest cat species"},
{label: "Giraffe", value: "giraffe", description: "The tallest land animal"},
{
label: "Dolphin",
value: "dolphin",
description: "A widely distributed and diverse group of aquatic mammals",
},
{label: "Penguin", value: "penguin", description: "A group of aquatic flightless birds"},
{label: "Zebra", value: "zebra", description: "A several species of African equids"},
{
label: "Shark",
value: "shark",
description: "A group of elasmobranch fish characterized by a cartilaginous skeleton",
},
{
label: "Whale",
value: "whale",
description: "Diverse group of fully aquatic placental marine mammals",
},
{label: "Otter", value: "otter", description: "A carnivorous mammal in the subfamily Lutrinae"},
{label: "Crocodile", value: "crocodile", description: "A large semiaquatic reptile"},
{key: "cat", label: "Cat"},
{key: "dog", label: "Dog"},
{key: "elephant", label: "Elephant"},
{key: "lion", label: "Lion"},
{key: "tiger", label: "Tiger"},
{key: "giraffe", label: "Giraffe"},
{key: "dolphin", label: "Dolphin"},
{key: "penguin", label: "Penguin"},
{key: "zebra", label: "Zebra"},
{key: "shark", label: "Shark"},
{key: "whale", label: "Whale"},
{key: "otter", label: "Otter"},
{key: "crocodile", label: "Crocodile"}
];`;
const App = `import {Select, SelectItem} from "@nextui-org/react";
@ -39,7 +27,7 @@ export default function App() {
className="max-w-xs"
>
{animals.map((animal) => (
<SelectItem key={animal.value} value={animal.value}>
<SelectItem key={animal.key}>
{animal.label}
</SelectItem>
))}

View File

@ -1,29 +1,17 @@
const data = `export const animals = [
{label: "Cat", value: "cat", description: "The second most popular pet in the world"},
{label: "Dog", value: "dog", description: "The most popular pet in the world"},
{label: "Elephant", value: "elephant", description: "The largest land animal"},
{label: "Lion", value: "lion", description: "The king of the jungle"},
{label: "Tiger", value: "tiger", description: "The largest cat species"},
{label: "Giraffe", value: "giraffe", description: "The tallest land animal"},
{
label: "Dolphin",
value: "dolphin",
description: "A widely distributed and diverse group of aquatic mammals",
},
{label: "Penguin", value: "penguin", description: "A group of aquatic flightless birds"},
{label: "Zebra", value: "zebra", description: "A several species of African equids"},
{
label: "Shark",
value: "shark",
description: "A group of elasmobranch fish characterized by a cartilaginous skeleton",
},
{
label: "Whale",
value: "whale",
description: "Diverse group of fully aquatic placental marine mammals",
},
{label: "Otter", value: "otter", description: "A carnivorous mammal in the subfamily Lutrinae"},
{label: "Crocodile", value: "crocodile", description: "A large semiaquatic reptile"},
{key: "cat", label: "Cat"},
{key: "dog", label: "Dog"},
{key: "elephant", label: "Elephant"},
{key: "lion", label: "Lion"},
{key: "tiger", label: "Tiger"},
{key: "giraffe", label: "Giraffe"},
{key: "dolphin", label: "Dolphin"},
{key: "penguin", label: "Penguin"},
{key: "zebra", label: "Zebra"},
{key: "shark", label: "Shark"},
{key: "whale", label: "Whale"},
{key: "otter", label: "Otter"},
{key: "crocodile", label: "Crocodile"}
];`;
const App = `import {Select, SelectItem} from "@nextui-org/react";
@ -37,7 +25,7 @@ export default function App() {
placeholder="Select an animal"
className="max-w-xs"
>
{(animal) => <SelectItem key={animal.value}>{animal.label}</SelectItem>}
{(animal) => <SelectItem>{animal.label}</SelectItem>}
</Select>
);
}`;

View File

@ -1,29 +1,17 @@
const data = `export const animals = [
{label: "Cat", value: "cat", description: "The second most popular pet in the world"},
{label: "Dog", value: "dog", description: "The most popular pet in the world"},
{label: "Elephant", value: "elephant", description: "The largest land animal"},
{label: "Lion", value: "lion", description: "The king of the jungle"},
{label: "Tiger", value: "tiger", description: "The largest cat species"},
{label: "Giraffe", value: "giraffe", description: "The tallest land animal"},
{
label: "Dolphin",
value: "dolphin",
description: "A widely distributed and diverse group of aquatic mammals",
},
{label: "Penguin", value: "penguin", description: "A group of aquatic flightless birds"},
{label: "Zebra", value: "zebra", description: "A several species of African equids"},
{
label: "Shark",
value: "shark",
description: "A group of elasmobranch fish characterized by a cartilaginous skeleton",
},
{
label: "Whale",
value: "whale",
description: "Diverse group of fully aquatic placental marine mammals",
},
{label: "Otter", value: "otter", description: "A carnivorous mammal in the subfamily Lutrinae"},
{label: "Crocodile", value: "crocodile", description: "A large semiaquatic reptile"},
{key: "cat", label: "Cat"},
{key: "dog", label: "Dog"},
{key: "elephant", label: "Elephant"},
{key: "lion", label: "Lion"},
{key: "tiger", label: "Tiger"},
{key: "giraffe", label: "Giraffe"},
{key: "dolphin", label: "Dolphin"},
{key: "penguin", label: "Penguin"},
{key: "zebra", label: "Zebra"},
{key: "shark", label: "Shark"},
{key: "whale", label: "Whale"},
{key: "otter", label: "Otter"},
{key: "crocodile", label: "Crocodile"}
];`;
const App = `import {Select, SelectItem} from "@nextui-org/react";
@ -49,7 +37,7 @@ export default function App() {
onClose={() => setTouched(true)}
>
{animals.map((animal) => (
<SelectItem key={animal.value} value={animal.value}>
<SelectItem key={animal.key}>
{animal.label}
</SelectItem>
))}

View File

@ -1,29 +1,17 @@
const data = `export const animals = [
{label: "Cat", value: "cat", description: "The second most popular pet in the world"},
{label: "Dog", value: "dog", description: "The most popular pet in the world"},
{label: "Elephant", value: "elephant", description: "The largest land animal"},
{label: "Lion", value: "lion", description: "The king of the jungle"},
{label: "Tiger", value: "tiger", description: "The largest cat species"},
{label: "Giraffe", value: "giraffe", description: "The tallest land animal"},
{
label: "Dolphin",
value: "dolphin",
description: "A widely distributed and diverse group of aquatic mammals",
},
{label: "Penguin", value: "penguin", description: "A group of aquatic flightless birds"},
{label: "Zebra", value: "zebra", description: "A several species of African equids"},
{
label: "Shark",
value: "shark",
description: "A group of elasmobranch fish characterized by a cartilaginous skeleton",
},
{
label: "Whale",
value: "whale",
description: "Diverse group of fully aquatic placental marine mammals",
},
{label: "Otter", value: "otter", description: "A carnivorous mammal in the subfamily Lutrinae"},
{label: "Crocodile", value: "crocodile", description: "A large semiaquatic reptile"},
{key: "cat", label: "Cat"},
{key: "dog", label: "Dog"},
{key: "elephant", label: "Elephant"},
{key: "lion", label: "Lion"},
{key: "tiger", label: "Tiger"},
{key: "giraffe", label: "Giraffe"},
{key: "dolphin", label: "Dolphin"},
{key: "penguin", label: "Penguin"},
{key: "zebra", label: "Zebra"},
{key: "shark", label: "Shark"},
{key: "whale", label: "Whale"},
{key: "otter", label: "Otter"},
{key: "crocodile", label: "Crocodile"}
];`;
const App = `import {Select, SelectItem} from "@nextui-org/react";
@ -48,7 +36,7 @@ export default function App() {
className="max-w-xs"
>
{animals.map((animal) => (
<SelectItem key={animal.value} value={animal.value}>
<SelectItem key={animal.key}>
{animal.label}
</SelectItem>
))}
@ -67,7 +55,7 @@ export default function App() {
className="max-w-xs"
>
{animals.map((animal) => (
<SelectItem key={animal.value} value={animal.value}>
<SelectItem key={animal.key}>
{animal.label}
</SelectItem>
))}

View File

@ -1,29 +1,17 @@
const data = `export const animals = [
{label: "Cat", value: "cat", description: "The second most popular pet in the world"},
{label: "Dog", value: "dog", description: "The most popular pet in the world"},
{label: "Elephant", value: "elephant", description: "The largest land animal"},
{label: "Lion", value: "lion", description: "The king of the jungle"},
{label: "Tiger", value: "tiger", description: "The largest cat species"},
{label: "Giraffe", value: "giraffe", description: "The tallest land animal"},
{
label: "Dolphin",
value: "dolphin",
description: "A widely distributed and diverse group of aquatic mammals",
},
{label: "Penguin", value: "penguin", description: "A group of aquatic flightless birds"},
{label: "Zebra", value: "zebra", description: "A several species of African equids"},
{
label: "Shark",
value: "shark",
description: "A group of elasmobranch fish characterized by a cartilaginous skeleton",
},
{
label: "Whale",
value: "whale",
description: "Diverse group of fully aquatic placental marine mammals",
},
{label: "Otter", value: "otter", description: "A carnivorous mammal in the subfamily Lutrinae"},
{label: "Crocodile", value: "crocodile", description: "A large semiaquatic reptile"},
{key: "cat", label: "Cat"},
{key: "dog", label: "Dog"},
{key: "elephant", label: "Elephant"},
{key: "lion", label: "Lion"},
{key: "tiger", label: "Tiger"},
{key: "giraffe", label: "Giraffe"},
{key: "dolphin", label: "Dolphin"},
{key: "penguin", label: "Penguin"},
{key: "zebra", label: "Zebra"},
{key: "shark", label: "Shark"},
{key: "whale", label: "Whale"},
{key: "otter", label: "Otter"},
{key: "crocodile", label: "Crocodile"}
];`;
const App = `import {Select, SelectItem} from "@nextui-org/react";
@ -47,7 +35,7 @@ export default function App() {
onChange={handleSelectionChange}
>
{animals.map((animal) => (
<SelectItem key={animal.value} value={animal.value}>
<SelectItem key={animal.key}>
{animal.label}
</SelectItem>
))}
@ -78,7 +66,7 @@ export default function App() {
onChange={handleSelectionChange}
>
{animals.map((animal) => (
<SelectItem key={animal.value} value={animal.value}>
<SelectItem key={animal.key}>
{animal.label}
</SelectItem>
))}

View File

@ -1,29 +1,17 @@
const data = `export const animals = [
{label: "Cat", value: "cat", description: "The second most popular pet in the world"},
{label: "Dog", value: "dog", description: "The most popular pet in the world"},
{label: "Elephant", value: "elephant", description: "The largest land animal"},
{label: "Lion", value: "lion", description: "The king of the jungle"},
{label: "Tiger", value: "tiger", description: "The largest cat species"},
{label: "Giraffe", value: "giraffe", description: "The tallest land animal"},
{
label: "Dolphin",
value: "dolphin",
description: "A widely distributed and diverse group of aquatic mammals",
},
{label: "Penguin", value: "penguin", description: "A group of aquatic flightless birds"},
{label: "Zebra", value: "zebra", description: "A several species of African equids"},
{
label: "Shark",
value: "shark",
description: "A group of elasmobranch fish characterized by a cartilaginous skeleton",
},
{
label: "Whale",
value: "whale",
description: "Diverse group of fully aquatic placental marine mammals",
},
{label: "Otter", value: "otter", description: "A carnivorous mammal in the subfamily Lutrinae"},
{label: "Crocodile", value: "crocodile", description: "A large semiaquatic reptile"},
{key: "cat", label: "Cat"},
{key: "dog", label: "Dog"},
{key: "elephant", label: "Elephant"},
{key: "lion", label: "Lion"},
{key: "tiger", label: "Tiger"},
{key: "giraffe", label: "Giraffe"},
{key: "dolphin", label: "Dolphin"},
{key: "penguin", label: "Penguin"},
{key: "zebra", label: "Zebra"},
{key: "shark", label: "Shark"},
{key: "whale", label: "Whale"},
{key: "otter", label: "Otter"},
{key: "crocodile", label: "Crocodile"}
];`;
const App = `import {Select, SelectItem} from "@nextui-org/react";
@ -43,7 +31,7 @@ export default function App() {
onSelectionChange={setValues}
>
{animals.map((animal) => (
<SelectItem key={animal.value} value={animal.value}>
<SelectItem key={animal.key}>
{animal.label}
</SelectItem>
))}
@ -70,7 +58,7 @@ export default function App() {
onSelectionChange={setValues}
>
{animals.map((animal) => (
<SelectItem key={animal.value} value={animal.value}>
<SelectItem key={animal.key}>
{animal.label}
</SelectItem>
))}

View File

@ -1,29 +1,17 @@
const data = `export const animals = [
{label: "Cat", value: "cat", description: "The second most popular pet in the world"},
{label: "Dog", value: "dog", description: "The most popular pet in the world"},
{label: "Elephant", value: "elephant", description: "The largest land animal"},
{label: "Lion", value: "lion", description: "The king of the jungle"},
{label: "Tiger", value: "tiger", description: "The largest cat species"},
{label: "Giraffe", value: "giraffe", description: "The tallest land animal"},
{
label: "Dolphin",
value: "dolphin",
description: "A widely distributed and diverse group of aquatic mammals",
},
{label: "Penguin", value: "penguin", description: "A group of aquatic flightless birds"},
{label: "Zebra", value: "zebra", description: "A several species of African equids"},
{
label: "Shark",
value: "shark",
description: "A group of elasmobranch fish characterized by a cartilaginous skeleton",
},
{
label: "Whale",
value: "whale",
description: "Diverse group of fully aquatic placental marine mammals",
},
{label: "Otter", value: "otter", description: "A carnivorous mammal in the subfamily Lutrinae"},
{label: "Crocodile", value: "crocodile", description: "A large semiaquatic reptile"},
{key: "cat", label: "Cat"},
{key: "dog", label: "Dog"},
{key: "elephant", label: "Elephant"},
{key: "lion", label: "Lion"},
{key: "tiger", label: "Tiger"},
{key: "giraffe", label: "Giraffe"},
{key: "dolphin", label: "Dolphin"},
{key: "penguin", label: "Penguin"},
{key: "zebra", label: "Zebra"},
{key: "shark", label: "Shark"},
{key: "whale", label: "Whale"},
{key: "otter", label: "Otter"},
{key: "crocodile", label: "Crocodile"}
];`;
const App = `import {Select, SelectItem} from "@nextui-org/react";
@ -38,7 +26,7 @@ export default function App() {
className="max-w-xs"
>
{animals.map((animal) => (
<SelectItem key={animal.value} value={animal.value}>
<SelectItem key={animal.key}>
{animal.label}
</SelectItem>
))}

View File

@ -1,29 +1,17 @@
const data = `export const animals = [
{label: "Cat", value: "cat", description: "The second most popular pet in the world"},
{label: "Dog", value: "dog", description: "The most popular pet in the world"},
{label: "Elephant", value: "elephant", description: "The largest land animal"},
{label: "Lion", value: "lion", description: "The king of the jungle"},
{label: "Tiger", value: "tiger", description: "The largest cat species"},
{label: "Giraffe", value: "giraffe", description: "The tallest land animal"},
{
label: "Dolphin",
value: "dolphin",
description: "A widely distributed and diverse group of aquatic mammals",
},
{label: "Penguin", value: "penguin", description: "A group of aquatic flightless birds"},
{label: "Zebra", value: "zebra", description: "A several species of African equids"},
{
label: "Shark",
value: "shark",
description: "A group of elasmobranch fish characterized by a cartilaginous skeleton",
},
{
label: "Whale",
value: "whale",
description: "Diverse group of fully aquatic placental marine mammals",
},
{label: "Otter", value: "otter", description: "A carnivorous mammal in the subfamily Lutrinae"},
{label: "Crocodile", value: "crocodile", description: "A large semiaquatic reptile"},
{key: "cat", label: "Cat"},
{key: "dog", label: "Dog"},
{key: "elephant", label: "Elephant"},
{key: "lion", label: "Lion"},
{key: "tiger", label: "Tiger"},
{key: "giraffe", label: "Giraffe"},
{key: "dolphin", label: "Dolphin"},
{key: "penguin", label: "Penguin"},
{key: "zebra", label: "Zebra"},
{key: "shark", label: "Shark"},
{key: "whale", label: "Whale"},
{key: "otter", label: "Otter"},
{key: "crocodile", label: "Crocodile"}
];`;
const App = `import {Select, SelectItem, Button} from "@nextui-org/react";
@ -43,7 +31,7 @@ export default function App() {
className="max-w-xs"
>
{animals.map((animal) => (
<SelectItem key={animal.value} value={animal.value}>
<SelectItem key={animal.key}>
{animal.label}
</SelectItem>
))}

View File

@ -1,29 +1,17 @@
const data = `export const animals = [
{label: "Cat", value: "cat", description: "The second most popular pet in the world"},
{label: "Dog", value: "dog", description: "The most popular pet in the world"},
{label: "Elephant", value: "elephant", description: "The largest land animal"},
{label: "Lion", value: "lion", description: "The king of the jungle"},
{label: "Tiger", value: "tiger", description: "The largest cat species"},
{label: "Giraffe", value: "giraffe", description: "The tallest land animal"},
{
label: "Dolphin",
value: "dolphin",
description: "A widely distributed and diverse group of aquatic mammals",
},
{label: "Penguin", value: "penguin", description: "A group of aquatic flightless birds"},
{label: "Zebra", value: "zebra", description: "A several species of African equids"},
{
label: "Shark",
value: "shark",
description: "A group of elasmobranch fish characterized by a cartilaginous skeleton",
},
{
label: "Whale",
value: "whale",
description: "Diverse group of fully aquatic placental marine mammals",
},
{label: "Otter", value: "otter", description: "A carnivorous mammal in the subfamily Lutrinae"},
{label: "Crocodile", value: "crocodile", description: "A large semiaquatic reptile"},
{key: "cat", label: "Cat"},
{key: "dog", label: "Dog"},
{key: "elephant", label: "Elephant"},
{key: "lion", label: "Lion"},
{key: "tiger", label: "Tiger"},
{key: "giraffe", label: "Giraffe"},
{key: "dolphin", label: "Dolphin"},
{key: "penguin", label: "Penguin"},
{key: "zebra", label: "Zebra"},
{key: "shark", label: "Shark"},
{key: "whale", label: "Whale"},
{key: "otter", label: "Otter"},
{key: "crocodile", label: "Crocodile"}
];`;
const App = `import {Select, SelectItem} from "@nextui-org/react";
@ -50,7 +38,7 @@ export default function App() {
className="max-w-[45%]"
>
{animals.map((animal) => (
<SelectItem key={animal.value} value={animal.value}>
<SelectItem key={animal.key}>
{animal.label}
</SelectItem>
))}

View File

@ -1,29 +1,17 @@
const data = `export const animals = [
{label: "Cat", value: "cat", description: "The second most popular pet in the world"},
{label: "Dog", value: "dog", description: "The most popular pet in the world"},
{label: "Elephant", value: "elephant", description: "The largest land animal"},
{label: "Lion", value: "lion", description: "The king of the jungle"},
{label: "Tiger", value: "tiger", description: "The largest cat species"},
{label: "Giraffe", value: "giraffe", description: "The tallest land animal"},
{
label: "Dolphin",
value: "dolphin",
description: "A widely distributed and diverse group of aquatic mammals",
},
{label: "Penguin", value: "penguin", description: "A group of aquatic flightless birds"},
{label: "Zebra", value: "zebra", description: "A several species of African equids"},
{
label: "Shark",
value: "shark",
description: "A group of elasmobranch fish characterized by a cartilaginous skeleton",
},
{
label: "Whale",
value: "whale",
description: "Diverse group of fully aquatic placental marine mammals",
},
{label: "Otter", value: "otter", description: "A carnivorous mammal in the subfamily Lutrinae"},
{label: "Crocodile", value: "crocodile", description: "A large semiaquatic reptile"},
{key: "cat", label: "Cat"},
{key: "dog", label: "Dog"},
{key: "elephant", label: "Elephant"},
{key: "lion", label: "Lion"},
{key: "tiger", label: "Tiger"},
{key: "giraffe", label: "Giraffe"},
{key: "dolphin", label: "Dolphin"},
{key: "penguin", label: "Penguin"},
{key: "zebra", label: "Zebra"},
{key: "shark", label: "Shark"},
{key: "whale", label: "Whale"},
{key: "otter", label: "Otter"},
{key: "crocodile", label: "Crocodile"}
];`;
const App = `import {Select, SelectItem} from "@nextui-org/react";
@ -39,7 +27,7 @@ export default function App() {
className="max-w-xs"
>
{animals.map((animal) => (
<SelectItem key={animal.value} value={animal.value}>
<SelectItem key={animal.key}>
{animal.label}
</SelectItem>
))}

View File

@ -1,29 +1,17 @@
const data = `export const animals = [
{label: "Cat", value: "cat", description: "The second most popular pet in the world"},
{label: "Dog", value: "dog", description: "The most popular pet in the world"},
{label: "Elephant", value: "elephant", description: "The largest land animal"},
{label: "Lion", value: "lion", description: "The king of the jungle"},
{label: "Tiger", value: "tiger", description: "The largest cat species"},
{label: "Giraffe", value: "giraffe", description: "The tallest land animal"},
{
label: "Dolphin",
value: "dolphin",
description: "A widely distributed and diverse group of aquatic mammals",
},
{label: "Penguin", value: "penguin", description: "A group of aquatic flightless birds"},
{label: "Zebra", value: "zebra", description: "A several species of African equids"},
{
label: "Shark",
value: "shark",
description: "A group of elasmobranch fish characterized by a cartilaginous skeleton",
},
{
label: "Whale",
value: "whale",
description: "Diverse group of fully aquatic placental marine mammals",
},
{label: "Otter", value: "otter", description: "A carnivorous mammal in the subfamily Lutrinae"},
{label: "Crocodile", value: "crocodile", description: "A large semiaquatic reptile"},
{key: "cat", label: "Cat"},
{key: "dog", label: "Dog"},
{key: "elephant", label: "Elephant"},
{key: "lion", label: "Lion"},
{key: "tiger", label: "Tiger"},
{key: "giraffe", label: "Giraffe"},
{key: "dolphin", label: "Dolphin"},
{key: "penguin", label: "Penguin"},
{key: "zebra", label: "Zebra"},
{key: "shark", label: "Shark"},
{key: "whale", label: "Whale"},
{key: "otter", label: "Otter"},
{key: "crocodile", label: "Crocodile"}
];`;
const App = `import {Select, SelectItem} from "@nextui-org/react";
@ -47,7 +35,7 @@ export default function App() {
onChange={handleSelectionChange}
>
{animals.map((animal) => (
<SelectItem key={animal.value} value={animal.value}>
<SelectItem key={animal.key}>
{animal.label}
</SelectItem>
))}
@ -78,7 +66,7 @@ export default function App() {
onChange={handleSelectionChange}
>
{animals.map((animal) => (
<SelectItem key={animal.value} value={animal.value}>
<SelectItem key={animal.key}>
{animal.label}
</SelectItem>
))}

View File

@ -1,29 +1,17 @@
const data = `export const animals = [
{label: "Cat", value: "cat", description: "The second most popular pet in the world"},
{label: "Dog", value: "dog", description: "The most popular pet in the world"},
{label: "Elephant", value: "elephant", description: "The largest land animal"},
{label: "Lion", value: "lion", description: "The king of the jungle"},
{label: "Tiger", value: "tiger", description: "The largest cat species"},
{label: "Giraffe", value: "giraffe", description: "The tallest land animal"},
{
label: "Dolphin",
value: "dolphin",
description: "A widely distributed and diverse group of aquatic mammals",
},
{label: "Penguin", value: "penguin", description: "A group of aquatic flightless birds"},
{label: "Zebra", value: "zebra", description: "A several species of African equids"},
{
label: "Shark",
value: "shark",
description: "A group of elasmobranch fish characterized by a cartilaginous skeleton",
},
{
label: "Whale",
value: "whale",
description: "Diverse group of fully aquatic placental marine mammals",
},
{label: "Otter", value: "otter", description: "A carnivorous mammal in the subfamily Lutrinae"},
{label: "Crocodile", value: "crocodile", description: "A large semiaquatic reptile"},
{key: "cat", label: "Cat"},
{key: "dog", label: "Dog"},
{key: "elephant", label: "Elephant"},
{key: "lion", label: "Lion"},
{key: "tiger", label: "Tiger"},
{key: "giraffe", label: "Giraffe"},
{key: "dolphin", label: "Dolphin"},
{key: "penguin", label: "Penguin"},
{key: "zebra", label: "Zebra"},
{key: "shark", label: "Shark"},
{key: "whale", label: "Whale"},
{key: "otter", label: "Otter"},
{key: "crocodile", label: "Crocodile"}
];`;
const AppTs = `import {Select, SelectItem, Selection} from "@nextui-org/react";
@ -43,7 +31,7 @@ export default function App() {
onSelectionChange={setValue}
>
{animals.map((animal) => (
<SelectItem key={animal.value} value={animal.value}>
<SelectItem key={animal.key}>
{animal.label}
</SelectItem>
))}
@ -70,7 +58,7 @@ export default function App() {
onSelectionChange={setValue}
>
{animals.map((animal) => (
<SelectItem key={animal.value} value={animal.value}>
<SelectItem key={animal.key}>
{animal.label}
</SelectItem>
))}

View File

@ -1,29 +1,17 @@
const data = `export const animals = [
{label: "Cat", value: "cat", description: "The second most popular pet in the world"},
{label: "Dog", value: "dog", description: "The most popular pet in the world"},
{label: "Elephant", value: "elephant", description: "The largest land animal"},
{label: "Lion", value: "lion", description: "The king of the jungle"},
{label: "Tiger", value: "tiger", description: "The largest cat species"},
{label: "Giraffe", value: "giraffe", description: "The tallest land animal"},
{
label: "Dolphin",
value: "dolphin",
description: "A widely distributed and diverse group of aquatic mammals",
},
{label: "Penguin", value: "penguin", description: "A group of aquatic flightless birds"},
{label: "Zebra", value: "zebra", description: "A several species of African equids"},
{
label: "Shark",
value: "shark",
description: "A group of elasmobranch fish characterized by a cartilaginous skeleton",
},
{
label: "Whale",
value: "whale",
description: "Diverse group of fully aquatic placental marine mammals",
},
{label: "Otter", value: "otter", description: "A carnivorous mammal in the subfamily Lutrinae"},
{label: "Crocodile", value: "crocodile", description: "A large semiaquatic reptile"},
{key: "cat", label: "Cat"},
{key: "dog", label: "Dog"},
{key: "elephant", label: "Elephant"},
{key: "lion", label: "Lion"},
{key: "tiger", label: "Tiger"},
{key: "giraffe", label: "Giraffe"},
{key: "dolphin", label: "Dolphin"},
{key: "penguin", label: "Penguin"},
{key: "zebra", label: "Zebra"},
{key: "shark", label: "Shark"},
{key: "whale", label: "Whale"},
{key: "otter", label: "Otter"},
{key: "crocodile", label: "Crocodile"}
];`;
const App = `import {Select, SelectItem} from "@nextui-org/react";
@ -42,7 +30,7 @@ export default function App() {
className="max-w-xs"
>
{animals.map((animal) => (
<SelectItem key={animal.value} value={animal.value}>
<SelectItem key={animal.key}>
{animal.label}
</SelectItem>
))}
@ -54,7 +42,7 @@ export default function App() {
className="max-w-xs"
>
{animals.map((animal) => (
<SelectItem key={animal.value} value={animal.value}>
<SelectItem key={animal.key}>
{animal.label}
</SelectItem>
))}

View File

@ -1,29 +1,17 @@
const data = `export const animals = [
{label: "Cat", value: "cat", description: "The second most popular pet in the world"},
{label: "Dog", value: "dog", description: "The most popular pet in the world"},
{label: "Elephant", value: "elephant", description: "The largest land animal"},
{label: "Lion", value: "lion", description: "The king of the jungle"},
{label: "Tiger", value: "tiger", description: "The largest cat species"},
{label: "Giraffe", value: "giraffe", description: "The tallest land animal"},
{
label: "Dolphin",
value: "dolphin",
description: "A widely distributed and diverse group of aquatic mammals",
},
{label: "Penguin", value: "penguin", description: "A group of aquatic flightless birds"},
{label: "Zebra", value: "zebra", description: "A several species of African equids"},
{
label: "Shark",
value: "shark",
description: "A group of elasmobranch fish characterized by a cartilaginous skeleton",
},
{
label: "Whale",
value: "whale",
description: "Diverse group of fully aquatic placental marine mammals",
},
{label: "Otter", value: "otter", description: "A carnivorous mammal in the subfamily Lutrinae"},
{label: "Crocodile", value: "crocodile", description: "A large semiaquatic reptile"},
{key: "cat", label: "Cat"},
{key: "dog", label: "Dog"},
{key: "elephant", label: "Elephant"},
{key: "lion", label: "Lion"},
{key: "tiger", label: "Tiger"},
{key: "giraffe", label: "Giraffe"},
{key: "dolphin", label: "Dolphin"},
{key: "penguin", label: "Penguin"},
{key: "zebra", label: "Zebra"},
{key: "shark", label: "Shark"},
{key: "whale", label: "Whale"},
{key: "otter", label: "Otter"},
{key: "crocodile", label: "Crocodile"}
];`;
const PetIcon = `export const PetIcon = (props) => (
@ -67,20 +55,19 @@ import {animals} from "./data";
export default function App() {
return (
<Select
className="max-w-xs"
defaultSelectedKeys={["cat"]}
label="Favorite Animal"
placeholder="Select an animal"
startContent={<PetIcon />}
defaultSelectedKeys={["cat"]}
className="max-w-xs"
>
{animals.map((animal) => (
<SelectItem key={animal.value} value={animal.value}>
{animal.label}
</SelectItem>
<SelectItem key={animal.key}>{animal.label}</SelectItem>
))}
</Select>
);
}`;
}
`;
const react = {
"/App.jsx": App,

View File

@ -1,29 +1,17 @@
const data = `export const animals = [
{label: "Cat", value: "cat", description: "The second most popular pet in the world"},
{label: "Dog", value: "dog", description: "The most popular pet in the world"},
{label: "Elephant", value: "elephant", description: "The largest land animal"},
{label: "Lion", value: "lion", description: "The king of the jungle"},
{label: "Tiger", value: "tiger", description: "The largest cat species"},
{label: "Giraffe", value: "giraffe", description: "The tallest land animal"},
{
label: "Dolphin",
value: "dolphin",
description: "A widely distributed and diverse group of aquatic mammals",
},
{label: "Penguin", value: "penguin", description: "A group of aquatic flightless birds"},
{label: "Zebra", value: "zebra", description: "A several species of African equids"},
{
label: "Shark",
value: "shark",
description: "A group of elasmobranch fish characterized by a cartilaginous skeleton",
},
{
label: "Whale",
value: "whale",
description: "Diverse group of fully aquatic placental marine mammals",
},
{label: "Otter", value: "otter", description: "A carnivorous mammal in the subfamily Lutrinae"},
{label: "Crocodile", value: "crocodile", description: "A large semiaquatic reptile"},
{key: "cat", label: "Cat"},
{key: "dog", label: "Dog"},
{key: "elephant", label: "Elephant"},
{key: "lion", label: "Lion"},
{key: "tiger", label: "Tiger"},
{key: "giraffe", label: "Giraffe"},
{key: "dolphin", label: "Dolphin"},
{key: "penguin", label: "Penguin"},
{key: "zebra", label: "Zebra"},
{key: "shark", label: "Shark"},
{key: "whale", label: "Whale"},
{key: "otter", label: "Otter"},
{key: "crocodile", label: "Crocodile"}
];`;
const App = `import {Select, SelectItem} from "@nextui-org/react";
@ -37,7 +25,7 @@ export default function App() {
className="max-w-xs"
>
{animals.map((animal) => (
<SelectItem key={animal.value} value={animal.value}>
<SelectItem key={animal.key}>
{animal.label}
</SelectItem>
))}
@ -48,7 +36,7 @@ export default function App() {
className="max-w-xs"
>
{animals.map((animal) => (
<SelectItem key={animal.value} value={animal.value}>
<SelectItem key={animal.key}>
{animal.label}
</SelectItem>
))}

View File

@ -1,29 +1,17 @@
const data = `export const animals = [
{label: "Cat", value: "cat", description: "The second most popular pet in the world"},
{label: "Dog", value: "dog", description: "The most popular pet in the world"},
{label: "Elephant", value: "elephant", description: "The largest land animal"},
{label: "Lion", value: "lion", description: "The king of the jungle"},
{label: "Tiger", value: "tiger", description: "The largest cat species"},
{label: "Giraffe", value: "giraffe", description: "The tallest land animal"},
{
label: "Dolphin",
value: "dolphin",
description: "A widely distributed and diverse group of aquatic mammals",
},
{label: "Penguin", value: "penguin", description: "A group of aquatic flightless birds"},
{label: "Zebra", value: "zebra", description: "A several species of African equids"},
{
label: "Shark",
value: "shark",
description: "A group of elasmobranch fish characterized by a cartilaginous skeleton",
},
{
label: "Whale",
value: "whale",
description: "Diverse group of fully aquatic placental marine mammals",
},
{label: "Otter", value: "otter", description: "A carnivorous mammal in the subfamily Lutrinae"},
{label: "Crocodile", value: "crocodile", description: "A large semiaquatic reptile"},
{key: "cat", label: "Cat"},
{key: "dog", label: "Dog"},
{key: "elephant", label: "Elephant"},
{key: "lion", label: "Lion"},
{key: "tiger", label: "Tiger"},
{key: "giraffe", label: "Giraffe"},
{key: "dolphin", label: "Dolphin"},
{key: "penguin", label: "Penguin"},
{key: "zebra", label: "Zebra"},
{key: "shark", label: "Shark"},
{key: "whale", label: "Whale"},
{key: "otter", label: "Otter"},
{key: "crocodile", label: "Crocodile"}
];`;
const App = `import {Select, SelectItem} from "@nextui-org/react";
@ -42,7 +30,7 @@ export default function App() {
className="max-w-xs"
>
{animals.map((animal) => (
<SelectItem key={animal.value} value={animal.value}>
<SelectItem key={animal.key}>
{animal.label}
</SelectItem>
))}
@ -54,7 +42,7 @@ export default function App() {
className="max-w-xs"
>
{animals.map((animal) => (
<SelectItem key={animal.value} value={animal.value}>
<SelectItem key={animal.key}>
{animal.label}
</SelectItem>
))}

View File

@ -1,29 +1,17 @@
const data = `export const animals = [
{label: "Cat", value: "cat", description: "The second most popular pet in the world"},
{label: "Dog", value: "dog", description: "The most popular pet in the world"},
{label: "Elephant", value: "elephant", description: "The largest land animal"},
{label: "Lion", value: "lion", description: "The king of the jungle"},
{label: "Tiger", value: "tiger", description: "The largest cat species"},
{label: "Giraffe", value: "giraffe", description: "The tallest land animal"},
{
label: "Dolphin",
value: "dolphin",
description: "A widely distributed and diverse group of aquatic mammals",
},
{label: "Penguin", value: "penguin", description: "A group of aquatic flightless birds"},
{label: "Zebra", value: "zebra", description: "A several species of African equids"},
{
label: "Shark",
value: "shark",
description: "A group of elasmobranch fish characterized by a cartilaginous skeleton",
},
{
label: "Whale",
value: "whale",
description: "Diverse group of fully aquatic placental marine mammals",
},
{label: "Otter", value: "otter", description: "A carnivorous mammal in the subfamily Lutrinae"},
{label: "Crocodile", value: "crocodile", description: "A large semiaquatic reptile"},
{key: "cat", label: "Cat"},
{key: "dog", label: "Dog"},
{key: "elephant", label: "Elephant"},
{key: "lion", label: "Lion"},
{key: "tiger", label: "Tiger"},
{key: "giraffe", label: "Giraffe"},
{key: "dolphin", label: "Dolphin"},
{key: "penguin", label: "Penguin"},
{key: "zebra", label: "Zebra"},
{key: "shark", label: "Shark"},
{key: "whale", label: "Whale"},
{key: "otter", label: "Otter"},
{key: "crocodile", label: "Crocodile"}
];`;
const App = `import {Select, SelectItem} from "@nextui-org/react";
@ -41,7 +29,7 @@ export default function App() {
}}
>
{animals.map((animal) => (
<SelectItem key={animal.value} value={animal.value}>
<SelectItem key={animal.key}>
{animal.label}
</SelectItem>
))}

View File

@ -69,7 +69,7 @@ export default function App() {
const AppTs = `import {Tabs, Tab, Input, Link, Button, Card, CardBody, CardHeader} from "@nextui-org/react";
export default function App() {
const [selected, setSelected] = React.useState<string | number>("login");
const [selected, setSelected] = React.useState<React.Key>("login");
return (
<div className="flex flex-col w-full">

View File

@ -28,6 +28,7 @@ Usage: nextui [command]
Options:
-v, --version Show the version number
--no-cache Disable cache, by default data will be cached for 30m after the first request
-h, --help Display help for commands
Commands:
@ -51,6 +52,7 @@ nextui init [projectName] [options]
### Options
- `-t --template [string]` The template to use for the new project e.g. app, pages
- `-p --package [string]` The package manager to use for the new project (default: `npm`)
### Example
@ -58,6 +60,39 @@ nextui init [projectName] [options]
nextui init my-nextui-app -t app
```
output:
```codeBlock bash
NextUI CLI v0.2.1
┌ Create a new project
◇ Select a template (Enter to select)
│ ● App (A Next.js 14 with app directory template pre-configured with NextUI (v2) and Tailwind CSS.)
│ ○ Pages (A Next.js 14 with pages directory template pre-configured with NextUI (v2) and Tailwind CSS.)
│ ○ Vite (A Vite template pre-configured with NextUI (v2) and Tailwind CSS.)
◇ New project name (Enter to skip with default name)
│ my-nextui-app
◇ Select a package manager (Enter to select)
│ ● npm
│ ○ yarn
│ ○ pnpm
│ ○ bun
◇ Template created successfully!
◇ Next steps ───────╮
│ │
│ cd my-nextui-app │
│ npm install │
│ │
├────────────────────╯
└ 🚀 Get started with npm run dev
```
## add
> 1. Auto add the missing required `dependencies` to your project
@ -79,7 +114,6 @@ nextui add [components...] [options]
- `--prettier` [boolean] Add prettier format in the add content which required installed prettier - (default: false)
- `--addApp` [boolean] Add App.tsx file content which required provider (default: `false`)
### Example
Without setting a specific component, the `add` command will show a list of available components.
@ -91,27 +125,22 @@ nextui add
Output:
```codeBlock bash
NextUI CLI v0.1.2
NextUI CLI v0.2.1
? Which components would you like to add? - Space to select. Return to submit
Instructions:
↑/↓: Highlight option
←/→/[space]: Toggle selection
[a,b,c]/delete: Filter choices
enter/return: Complete answer
? Which components would you like to add? - Space to select. Return to submit
Filtered results for: Enter something to filter
accordion
◯ autocomplete
◯ avatar
◯ badge
◯ breadcrumbs
◯ button
◯ card
checkbox
chip
code
◯ accordion
◯ autocomplete
avatar
badge
breadcrumbs
button
calendar
card
checkbox
↓ chip
```
If you want to add a specific component, you can specify the component name.
@ -123,7 +152,7 @@ nextui add button input
Output:
```bash
NextUI CLI v0.1.2
NextUI CLI v0.2.1
Adding the required dependencies: @nextui-org/button
@ -142,7 +171,6 @@ Tailwind CSS settings have been updated in: /project-path/tailwind.config.js
✅ Components added successfully
```
## upgrade
Upgrade the NextUI components to the latest version.
@ -157,27 +185,33 @@ nextui upgrade [components...] [options]
- `-a --all` [boolean] Upgrade all the NextUI components (default: `false`).
- `-h, --help` Display help for commands.
### Example
```codeBlock bash
nextui upgrade button
```
Output:
```bash
NextUI CLI v0.1.2
NextUI CLI v0.2.1
╭───────────────────────── Component ─────────────────────────╮
│ @nextui-org/button ^2.0.11 -> ^2.0.31 │
╰─────────────────────────────────────────────────────────────╯
Required min version: @nextui-org/theme>=2.1.0, tailwindcss>=3.4.0
╭───────────────────── PeerDependencies ─────────────────────╮
│ @nextui-org/theme 2.0.1 -> 2.1.0 │
│ tailwindcss ^3.2.3 -> ^3.4.0 │
╰────────────────────────────────────────────────────────────╯
2 minor, 1 patch
╭───────────────────────────────────────────────────────────╮
│ @nextui-org/button 2.0.24 -> 2.0.27 │
╰───────────────────────────────────────────────────────────╯
? Would you like to proceed with the upgrade? - Use arrow-keys. Return to submit.
Yes
No
pnpm add @nextui-org/button@2.0.27
pnpm add @nextui-org/button@2.0.31 @nextui-org/theme@2.1.0 tailwindcss@3.4.0
Already up to date
Progress: resolved 474, reused 465, downloaded 0, added 0, done
Done in 2.9s
@ -195,7 +229,6 @@ Remove NextUI components from your project.
nextui remove [components...] [options]
```
### Options
- `-p --packagePath` [string] The path to the package.json file.
@ -213,7 +246,7 @@ nextui remove button
Output:
```bash
NextUI CLI v0.1.2
NextUI CLI v0.2.1
❗️ Components slated for removal:
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
@ -249,8 +282,8 @@ nextui list [options]
### Options
- `-p --packagePath` [string] The path to the package.json file.
- `-c --current` List the current installed components.
- `-p --packagePath` [string] The path to the package.json file
- `-r --remote` List all components available remotely
### Example
@ -261,7 +294,7 @@ nextui list
Output:
```codeBlock bash
NextUI CLI v0.1.2
NextUI CLI v0.2.1
Current installed components:
@ -283,6 +316,7 @@ Diagnose problems in your project.
> 2. Check whether the NextUI components `required dependencies are installed` in the project
> 3. Check the required `tailwind.config.js` file and the content is correct
> 4. Check `.npmrc` is correct when using `pnpm`
> 5. Check `peerDependencies with required version` are installed in the project
```codeBlock bash
nextui doctor [options]
@ -310,7 +344,7 @@ Output:
If there is a problem in your project, the `doctor` command will display the problem information.
```codeBlock bash
NextUI CLI v0.1.2
NextUI CLI v0.2.1
NextUI CLI: ❌ Your project has 1 issue that require attention
@ -322,7 +356,7 @@ Missing tailwind.config.(j|t)s file. To set up, visit: https://nextui.org/docs/g
Otherwise, the `doctor` command will display the following message.
```codeBlock bash
NextUI CLI v0.1.2
NextUI CLI v0.2.1
✅ Your project has no detected issues.
```
@ -348,7 +382,7 @@ nextui env
Output:
```codeBlock bash
NextUI CLI 0.1.0
NextUI CLI 0.2.1
Current installed components:

View File

@ -5,80 +5,176 @@ description: API References for NextUI Provider
# NextUI Provider
API reference for the `NextUIProvider`.
------
Here's the API reference for the `NextUIProvider`.
## Import
## Props
<ImportTabs
commands={{
main: 'import {NextUIProvider} from "@nextui-org/react";',
individual: 'import {NextUIProvider} from "@nextui-org/system";',
}}
/>
### navigate
## Usage
`navigate` provides a client side router to all nested components such as Link, Menu, Tabs, Table, etc.
```jsx
import * as React from "react";
import {NextUIProvider} from "@nextui-org/react";
**type**: `((path: string) => void) | undefined`
### locale
The locale to apply to the children. The [BCP47](https://www.ietf.org/rfc/bcp/bcp47.txt) language code for the locale. By default, It is `en-US`.
**type**: `string | undefined`
### defaultDates
The default dates range that can be selected in the calendar.
**type**: `{ minDate?: CalendarDate | undefined; maxDate?: CalendarDate | undefined; }`
- minDate
The minimum date that can be selected in the calendar.
**type**: `CalendarDate | undefined`
**default**: `new CalendarDate(1900, 1, 1)`
- maxDate
The maximum date that can be selected in the calendar.
**type**: `CalendarDate | undefined`
**default**: `new CalendarDate(2099, 12, 31)`
### createCalendar
This function helps to reduce the bundle size by providing a custom calendar system.
By default, this includes all calendar systems supported by `@internationalized/date`. However,
if your application supports a more limited set of regions, or you know you will only be picking dates
in a certain calendar system, you can reduce your bundle size by providing your own implementation
of `createCalendar` that includes a subset of these Calendar implementations.
For example, if your application only supports Gregorian dates, you could implement a `createCalendar`
function like this:
```tsx
import {GregorianCalendar} from '@internationalized/date';
function createCalendar(identifier) {
switch (identifier) {
case 'gregory':
return new GregorianCalendar();
default:
throw new Error(`Unsupported calendar ${identifier}`);
}
function App() {
return (
<NextUIProvider>
<YourApplication />
</NextUIProvider>
);
}
```
This way, only GregorianCalendar is imported, and the other calendar implementations can be tree-shaken.
## Props
**type**: `((calendar: SupportedCalendars) => Calendar | null) | undefined`
<Spacer y={6}/>
`navigate`
- **Description**: Provides a client side router to all nested components such as Link, Menu, Tabs, Table, etc.
- **Type**: `((path: string) => void) | undefined`
<Spacer y={2}/>
`locale`
- **Description**: The locale to apply to the children.
- **Type**: `string | undefined`
- **Default**: `en-US`
Here's the supported locales. By default, It is `en-US`.
```tsx
const localeValues = [
'fr-FR', 'fr-CA', 'de-DE', 'en-US', 'en-GB', 'ja-JP',
'da-DK', 'nl-NL', 'fi-FI', 'it-IT', 'nb-NO', 'es-ES',
'sv-SE', 'pt-BR', 'zh-CN', 'zh-TW', 'ko-KR', 'bg-BG',
'hr-HR', 'cs-CZ', 'et-EE', 'hu-HU', 'lv-LV', 'lt-LT',
'pl-PL', 'ro-RO', 'ru-RU', 'sr-SP', 'sk-SK', 'sl-SI',
'tr-TR', 'uk-UA', 'ar-AE', 'ar-DZ', 'AR-EG', 'ar-SA',
'el-GR', 'he-IL', 'fa-AF', 'am-ET', 'hi-IN', 'th-TH'
];
```
Here's an example to set a Spanish locale.
```tsx
"use client";
import {type ReactNode} from "react";
import {NextUIProvider} from "@nextui-org/react";
export function AppProvider(props: AppProviderProps) {
const {children, className} = props;
return (
<NextUIProvider locale="es-ES" className={className}>
{children}
</NextUIProvider>
);
}
interface AppProviderProps {
children: ReactNode;
className?: string;
}
```
<Spacer y={2}/>
`defaultDates`
- **Description**: The default dates range that can be selected in the calendar.
- **Type**: `{ minDate?: CalendarDate | undefined; maxDate?: CalendarDate | undefined; }`
- **Default**: `{ minDate: new CalendarDate(1900, 1, 1), maxDate: new CalendarDate(2099, 12, 31) }`
<Spacer y={2}/>
`createCalendar`
- **Description**:
This function helps to reduce the bundle size by providing a custom calendar system.
By default, this includes all calendar systems supported by `@internationalized/date`. However,
if your application supports a more limited set of regions, or you know you will only be picking dates
in a certain calendar system, you can reduce your bundle size by providing your own implementation
of `createCalendar` that includes a subset of these Calendar implementations.
For example, if your application only supports Gregorian dates, you could implement a `createCalendar`
function like this:
```tsx
import {GregorianCalendar} from '@internationalized/date';
function createCalendar(identifier) {
switch (identifier) {
case 'gregory':
return new GregorianCalendar();
default:
throw new Error(`Unsupported calendar ${identifier}`);
}
}
```
This way, only GregorianCalendar is imported, and the other calendar implementations can be tree-shaken.
- **Type**: `((calendar: SupportedCalendars) => Calendar | null) | undefined`
<Spacer y={2}/>
`disableAnimation`
- **Description**: Disables animations globally. This will also avoid `framer-motion` features to be loaded in the bundle which can potentially reduce the bundle size.
- **Type**: `boolean`
- **Default**: `false`
<Spacer y={2}/>
`disableRipple`
- **Description**: Disables ripple effect globally.
- **Type**: `boolean`
- **Default**: `false`
<Spacer y={2}/>
`skipFramerMotionAnimations`
- **Description**:
Controls whether `framer-motion` animations are skipped within the application.
This property is automatically enabled (`true`) when the `disableAnimation` prop is set to `true`,
effectively skipping all `framer-motion` animations. To retain `framer-motion` animations while
using the `disableAnimation` prop for other purposes, set this to `false`. However, note that
animations in NextUI Components are still omitted if the `disableAnimation` prop is `true`.
- **Type**: `boolean`
- **Default**: Same as `disableAnimation`
<Spacer y={2}/>
`validationBehavior`
- **Description**: Whether to use native HTML form validation to prevent form submission when the value is missing or invalid,
or mark the field as required or invalid via ARIA.
- **Type**: `native | aria`
- **Default**: `aria`
---
## Types
### CalendarDate
`CalendarDate`
A [CalendarDate](https://react-spectrum.adobe.com/internationalized/date/CalendarDate.html) represents a date without any time components in a specific calendar system from `@internationalized/date`.
- **Description**: A [CalendarDate](https://react-spectrum.adobe.com/internationalized/date/CalendarDate.html) represents a date without any time components in a specific calendar system from `@internationalized/date`.
- **Type**: `import {CalendarDate} from '@internationalized/date';`
### SupportedCalendars

View File

@ -219,21 +219,22 @@ Here's an example of how to customize the accordion styles:
### Accordion Item Props
| Attribute | Type | Description | Default |
| ------------------------- | ------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | ------- |
| children | `ReactNode` \| `string` | The content of the component. | |
| title | `ReactNode` \| `string` | The accordion item title. | |
| subtitle | `ReactNode` \| `string` | The accordion item subtitle. | |
| indicator | [IndicatorProps](#accordion-item-indicator-props) | The accordion item `expanded` indicator, usually an arrow icon. | |
| startContent | `ReactNode` | The accordion item start content, usually an icon or avatar. | |
| motionProps | [MotionProps](#motion-props) | The props to modify the framer motion animation. Use the `variants` API to create your own animation. | |
| isCompact | `boolean` | Whether the AccordionItem is compact. | `false` |
| isDisabled | `boolean` | The current disabled status. | `false` |
| keepContentMounted | `boolean` | Whether the AccordionItem content is kept mounted when closed. | `false` |
| hideIndicator | `boolean` | Whether the AccordionItem indicator is hidden. | `false` |
| disableAnimation | `boolean` | Whether the AccordionItem animation is disabled. | `false` |
| disableIndicatorAnimation | `boolean` | Whether the AccordionItem indicator animation is disabled. | `false` |
| classNames | [Classnames](#accordion-item-classnames) | Allows to set custom class names for the accordion item slots. | - |
| Attribute | Type | Description | Default |
|---------------------------|---------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------|---------|
| children | `ReactNode` \| `string` | The content of the component. | |
| title | `ReactNode` \| `string` | The accordion item title. | |
| subtitle | `ReactNode` \| `string` | The accordion item subtitle. | |
| indicator | [IndicatorProps](#accordion-item-indicator-props) | The accordion item `expanded` indicator, usually an arrow icon. | |
| startContent | `ReactNode` | The accordion item start content, usually an icon or avatar. | |
| motionProps | [MotionProps](#motion-props) | The props to modify the framer motion animation. Use the `variants` API to create your own animation. | |
| isCompact | `boolean` | Whether the AccordionItem is compact. | `false` |
| isDisabled | `boolean` | The current disabled status. | `false` |
| keepContentMounted | `boolean` | Whether the AccordionItem content is kept mounted when closed. | `false` |
| hideIndicator | `boolean` | Whether the AccordionItem indicator is hidden. | `false` |
| disableAnimation | `boolean` | Whether the AccordionItem animation is disabled. | `false` |
| disableIndicatorAnimation | `boolean` | Whether the AccordionItem indicator animation is disabled. | `false` |
| HeadingComponent | `React.ElementType` | Customizable heading tag for Web accessibility. Use headings to describe content and use them consistently and semantically. | `h2` |
| classNames | [Classnames](#accordion-item-classnames) | Allows to set custom class names for the accordion item slots. | - |
### Accordion Item Events

View File

@ -428,6 +428,7 @@ properties to customize the popover, listbox and input components.
| disabledKeys | `all` \| `React.Key[]` | The item keys that are disabled. These items cannot be selected, focused, or otherwise interacted with. | - |
| errorMessage | `ReactNode` \| `((v: ValidationResult) => ReactNode)` | An error message to display below the field. | - |
| validate | `(value: { inputValue: string, selectedKey: React.Key }) => ValidationError true null undefined` | Validate input values when committing (e.g. on blur), and return error messages for invalid values. | - |
| validationBehavior | `native` \| `aria` | Whether to use native HTML form validation to prevent form submission when the value is missing or invalid, or mark the field as required or invalid via ARIA.| `aria` |
| startContent | `ReactNode` | Element to be rendered in the left side of the Autocomplete. | - |
| endContent | `ReactNode` | Element to be rendered in the right side of the Autocomplete. | - |
| autoFocus | `boolean` | Whether the Autocomplete should be focused on render. | `false` |

View File

@ -9,7 +9,7 @@ import {badgeContent} from "@/content/components/badge";
Badges are used as a small numerical value or status descriptor for UI elements.
<ComponentLinks component="badge" rscCompatible />
<ComponentLinks component="badge" />
---

View File

@ -226,10 +226,9 @@ Here's the example to customize `topContent` and `bottomContent` to have some pr
| isDateUnavailable | `(date: DateValue) => boolean` | Callback that is called for each date of the calendar. If it returns true, then the date is unavailable. | - |
| createCalendar | `(calendar: SupportedCalendars) => Calendar \| null` | This function helps to reduce the bundle size by providing a custom calendar system. You can also use the NextUIProvider to provide the createCalendar function to all nested components. | `all<br> calendars` |
| errorMessage | `ReactNode \| (v: ValidationResult) => ReactNode` | An error message for the field. | - |
| validate | `(value: { inputValue: string, selectedKey: React.Key }) => ValidationError true null undefined` | Validate time input values when committing (e.g. on blur), and return error messages for invalid values. | - |
| hideDisabledDates | `boolean` | Whether to hide the disabled or invalid dates. | `false` |
| disableAnimation | `boolean` | Whether to disable the animation of the calendar. | `false` |
| classNames | `Record<"base" "prevButton" "nextButton" "headerWrapper" \| "header" \| "title" \| "content" \| "gridWrapper" \| "grid" \| "gridHeader" \| "gridHeaderRow" \| "gridHeaderCell" \| "gridBody" \| "gridBodyRow" \| "cell" \| "cellButton" \| "pickerWrapper" \| "pickerMonthList" \| "pickerYearList" \| "pickerHighlight" \| "pickerItem" \| "helperWrapper" \| "errorMessage", string>` | Allows to set custom class names for the calendar slots. | - |
| classNames | `Record<"base" "prevButton" "nextButton" "headerWrapper" \| "header" \| "title" \| "content" \| "gridWrapper" \| "grid" \| "gridHeader" \| "gridHeaderRow" \| "gridHeaderCell" \| "gridBody" \| "gridBodyRow" \| "cell" \| "cellButton" \| "pickerWrapper" \| "pickerMonthList" \| "pickerYearList" \| "pickerHighlight" \| "pickerItem" \| "helperWrapper" \| "errorMessage", string>` | Allows to set custom class names for the calendar slots. | - |
### Calendar Events

View File

@ -93,28 +93,29 @@ 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. | - |
| label | `string` | The label of the CheckboxGroup. | - |
| 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` \| `((v: ValidationResult) => ReactNode)` | The checkbox group error message. | - |
| validate | `(value: string[]) => ValidationError true null undefined` | Validate input values when committing (e.g. on blur), and return error messages for invalid values. | - |
| 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. | - |
| label | `string` | The label of the CheckboxGroup. | - |
| 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` \| `((v: ValidationResult) => ReactNode)` | The checkbox group error message. | - |
| validate | `(value: string[]) => ValidationError true null undefined` | Validate input values when committing (e.g. on blur), and return error messages for invalid values. | - |
| validationBehavior | `native` \| `aria` | Whether to use native HTML form validation to prevent form submission when the value is missing or invalid, or mark the field as required or invalid via ARIA.| `aria` |
| 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

@ -284,39 +284,40 @@ import {parseZonedDateTime} from "@internationalized/date";
### DateInput Props
| Attribute | Type | Description | Default |
| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | --------- |
| label | `ReactNode` | The content to display as the label. | - |
| value | `DateValue` | The current value of the date input (controlled). | - |
| defaultValue | `DateValue` | The default value of the date input (uncontrolled). | - |
| variant | `flat` \| `bordered` \| `faded` \| `underlined` | The variant of the date input. | `flat` |
| color | `default` \| `primary` \| `secondary` \| `success` \| `warning` \| `danger` | The color of the date input. | `default` |
| size | `sm` \| `md` \| `lg` | The size of the date input. | `md` |
| radius | `none` \| `sm` \| `md` \| `lg` \| `full` | The radius of the date input. | - |
| placeholderValue | `DateValue` | A placeholder time that influences the format of the placeholder shown when no value is selected. Defaults current date at midnight. | - |
| minValue | `DateValue` | The minimum allowed date that a user may select. | - |
| maxValue | `DateValue` | The maximum allowed date that a user may select. | - |
| locale | `string` | The locale to display and edit the value according to. | - |
| description | `ReactNode` | A description for the date input. Provides a hint such as specific requirements for what to choose. | - |
| errorMessage | `ReactNode \| (v: ValidationResult) => ReactNode` | An error message for the date input. | - |
| startContent | `ReactNode` | Element to be rendered in the left side of the date input. | - |
| endContent | `ReactNode` | Element to be rendered in the right side of the date input. | - |
| labelPlacement | `inside` \| `outside` \| `outside-left` | The position of the label. | `inside` |
| 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 value is invalid. | `false` |
| inputRef | `ReactRef<HTMLInputElement \| null>` | A ref for the hidden input element for HTML form submission. | - |
| validate | `(value: { inputValue: string, selectedKey: React.Key }) => ValidationError true null undefined` | Validate input values when committing (e.g., on blur), and return error messages for invalid values. | - |
| createCalendar | `(name: string) => Calendar` | A function that creates a Calendar object for a given calendar identifier. | - |
| isDateUnavailable | `(date: DateValue) => boolean` | Callback that is called for each date of the calendar. If it returns true, then the date is unavailable. | - |
| autoFocus | `boolean` | Whether the element should receive focus on render. | `false` |
| hourCycle | `12` \| `24` | Whether to display the time in 12 or 24 hour format. This is determined by the user's locale. | - |
| granularity | `day` \| `hour` \| `minute` \| `second` | Determines the smallest unit that is displayed in the date picker. Typically "day" for dates. | - |
| hideTimeZone | `boolean` | Whether to hide the time zone abbreviation. | `false` |
| shouldForceLeadingZeros | `boolean` | Whether to always show leading zeros in the month, day, and hour fields. | `true` |
| disableAnimation | `boolean` | Whether to disable animations. | `false` |
| classNames | `Record<"base" "label" "inputWrapper" "innerWrapper" "input" "helperWrapper" "description" "errorMessage", string>` | Allows to set custom class names for the date input slots. | - |
| Attribute | Type | Description | Default |
| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- |
| label | `ReactNode` | The content to display as the label. | - |
| value | `DateValue` | The current value of the date input (controlled). | - |
| defaultValue | `DateValue` | The default value of the date input (uncontrolled). | - |
| variant | `flat` \| `bordered` \| `faded` \| `underlined` | The variant of the date input. | `flat` |
| color | `default` \| `primary` \| `secondary` \| `success` \| `warning` \| `danger` | The color of the date input. | `default` |
| size | `sm` \| `md` \| `lg` | The size of the date input. | `md` |
| radius | `none` \| `sm` \| `md` \| `lg` \| `full` | The radius of the date input. | - |
| placeholderValue | `DateValue` | A placeholder time that influences the format of the placeholder shown when no value is selected. Defaults current date at midnight. | - |
| minValue | `DateValue` | The minimum allowed date that a user may select. | - |
| maxValue | `DateValue` | The maximum allowed date that a user may select. | - |
| locale | `string` | The locale to display and edit the value according to. | - |
| description | `ReactNode` | A description for the date input. Provides a hint such as specific requirements for what to choose. | - |
| errorMessage | `ReactNode \| (v: ValidationResult) => ReactNode` | An error message for the date input. | - |
| validate | `(value: MappedDateValue<DateValue>) => ValidationError true null undefined` | Validate input values when committing (e.g., on blur), and return error messages for invalid values. | - |
| validationBehavior | `native` \| `aria` | Whether to use native HTML form validation to prevent form submission when the value is missing or invalid, or mark the field as required or invalid via ARIA.| `aria` |
| startContent | `ReactNode` | Element to be rendered in the left side of the date input. | - |
| endContent | `ReactNode` | Element to be rendered in the right side of the date input. | - |
| labelPlacement | `inside` \| `outside` \| `outside-left` | The position of the label. | `inside` |
| 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 value is invalid. | `false` |
| inputRef | `ReactRef<HTMLInputElement \| null>` | A ref for the hidden input element for HTML form submission. | - |
| createCalendar | `(name: string) => Calendar` | A function that creates a Calendar object for a given calendar identifier. | - |
| isDateUnavailable | `(date: DateValue) => boolean` | Callback that is called for each date of the calendar. If it returns true, then the date is unavailable. | - |
| autoFocus | `boolean` | Whether the element should receive focus on render. | `false` |
| hourCycle | `12` \| `24` | Whether to display the time in 12 or 24 hour format. This is determined by the user's locale. | - |
| granularity | `day` \| `hour` \| `minute` \| `second` | Determines the smallest unit that is displayed in the date picker. Typically "day" for dates. | - |
| hideTimeZone | `boolean` | Whether to hide the time zone abbreviation. | `false` |
| shouldForceLeadingZeros | `boolean` | Whether to always show leading zeros in the month, day, and hour fields. | `true` |
| disableAnimation | `boolean` | Whether to disable animations. | `false` |
| classNames | `Record<"base" "label" "inputWrapper" "innerWrapper" "input" "helperWrapper" "description" "errorMessage", string>` | Allows to set custom class names for the date input slots. | - |
### DateInput Events

View File

@ -301,46 +301,47 @@ import {I18nProvider} from "@react-aria/i18n";
### DatePicker Props
| Attribute | Type | Description | Default |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
| label | `ReactNode` | The content to display as the label. | - |
| value | `ZonedDateTime` \| `CalendarDate` \| `CalendarDateTime` \| `undefined` \| `null` | The current value of the date-picker (controlled). | - |
| variant | `flat` \| `bordered` \| `faded` \| `underlined` | The variant of the date input. | `flat` |
| color | `default` \| `primary` \| `secondary` \| `success` \| `warning` \| `danger` | The color of the date input. | `default` |
| size | `sm` \| `md` \| `lg` | The size of the date input. | `md` |
| radius | `none` \| `sm` \| `md` \| `lg` \| `full` | The radius of the date input. | - |
| defaultValue | `string` \| undefined | The default value of the date-picker (uncontrolled). | - |
| placeholderValue | `ZonedDateTime` \| `CalendarDate` \| `CalendarDateTime` \| `undefined` \| `null` | The placeholder of the date-picker. | - |
| description | `ReactNode` | A description for the date-picker. Provides a hint such as specific requirements for what to choose. | - |
| errorMessage | `ReactNode \| (v: ValidationResult) => ReactNode` | An error message for the date input. | - |
| startContent | `ReactNode` | Element to be rendered in the left side of the date-picker. | - |
| endContent | `ReactNode` | Element to be rendered in the right side of the date-picker. | - |
| labelPlacement | `inside` \| `outside` \| `outside-left` | The position of the label. | `inside` |
| isRequired | `boolean` | Whether user input is required on the date-picker before form submission. | `false` |
| isReadOnly | `boolean` | Whether the date-picker can be selected but not changed by the user. | |
| isDisabled | `boolean` | Whether the date-picker is disabled. | `false` |
| isInvalid | `boolean` | Whether the date-picker is invalid. | `false` |
| visibleMonths | `number` \| `undefined` | The number of months to display at once. Up to 3 months are supported. Passing a number greater than 1 will disable the `showMonthAndYearPickers` prop. | `1` |
| selectorIcon | `ReactNode` | The icon to toggle the date picker popover. Usually a calendar icon. | |
| pageBehavior | `PageBehavior` \| `undefined` | Controls the behavior of paging. Pagination either works by advancing the visible page by visibleDuration (default) or one unit of visibleDuration. | `visible` |
| visibleMonths | `number` \| `undefined` | The number of months to display at once. Up to 3 months are supported. Passing a number greater than 1 will disable the `showMonthAndYearPickers` prop. | `1` |
| calendarWidth | `number` | The width to be applied to the calendar component. | `256` |
| CalendarTopContent | `ReactNode` | Top content to be rendered in the calendar component. | |
| validate | `(value: { inputValue: string, selectedKey: React.Key }) => ValidationError true null undefined` | Validate input values when committing (e.g., on blur), and return error messages for invalid values. | - |
| isDateUnavailable | `((date: DateValue) => boolean)` \| `undefined` | Callback that is called for each date of the calendar. If it returns true, then the date is unavailable. |
| autoFocus | `boolean` | Whether the element should receive focus on render. | `false` |
| hourCycle | `12` \| `24` | Whether to display the time in 12 or 24 hour format. This is determined by the user's locale. | - |
| granularity | `day` \| `hour` \| `minute` \| `second` | Determines the smallest unit that is displayed in the date picker. Typically "day" for dates. | - |
| hideTimeZone | `boolean` | Whether to hide the time zone abbreviation. | `false` |
| shouldForceLeadingZeros | `boolean` | Whether to always show leading zeros in the month, day, and hour fields. | `true` |
| CalendarBottomContent | `ReactNode` | Bottom content to be rendered in the calendar component. | |
| showMonthAndYearPickers | `boolean` \| `undefined` | Whether the calendar should show month and year pickers. | false |
| popoverProps | `PopoverProps` \| `undefined` | Props to be passed to the popover component. | `{ placement: "bottom", triggerScaleOnOpen: false, offset: 13 }` |
| selectorButtonProps | `ButtonProps` \| `undefined` | Props to be passed to the selector button component. | `{ size: "sm", variant: "light", radius: "full", isIconOnly: true }` |
| calendarProps | `CalendarProps` \| `undefined` | Props to be passed to the selector button component. | `{ size: "sm", variant: "light", radius: "full", isIconOnly: true }` |
| timeInputProps | `TimeInputProps` | Props to be passed to the time input component. | `{ size: "sm", variant: "light", radius: "full", isIconOnly: true }` |
| disableAnimation | `boolean` | Whether to disable all animations in the date picker. Including the DateInput, Button, Calendar, and Popover. | `false` |
| classNames | `Record<"base" \| "selectorButton" \| "selectorIcon" \| "popoverContent" \| "calendar" \| "calendarContent" \| "timeInputLabel" \| "timeInput", string>` | Allows to set custom class names for the date-picker slots. | - |
| Attribute | Type | Description | Default |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
| label | `ReactNode` | The content to display as the label. | - |
| value | `ZonedDateTime` \| `CalendarDate` \| `CalendarDateTime` \| `undefined` \| `null` | The current value of the date-picker (controlled). | - |
| variant | `flat` \| `bordered` \| `faded` \| `underlined` | The variant of the date input. | `flat` |
| color | `default` \| `primary` \| `secondary` \| `success` \| `warning` \| `danger` | The color of the date input. | `default` |
| size | `sm` \| `md` \| `lg` | The size of the date input. | `md` |
| radius | `none` \| `sm` \| `md` \| `lg` \| `full` | The radius of the date input. | - |
| defaultValue | `string` \| undefined | The default value of the date-picker (uncontrolled). | - |
| placeholderValue | `ZonedDateTime` \| `CalendarDate` \| `CalendarDateTime` \| `undefined` \| `null` | The placeholder of the date-picker. | - |
| description | `ReactNode` | A description for the date-picker. Provides a hint such as specific requirements for what to choose. | - |
| errorMessage | `ReactNode \| (v: ValidationResult) => ReactNode` | An error message for the date input. | - |
| validate | `(value: MappedDateValue<DateValue>) => ValidationError true null undefined` | Validate input values when committing (e.g., on blur), and return error messages for invalid values. | - |
| validationBehavior | `native` \| `aria` | Whether to use native HTML form validation to prevent form submission when the value is missing or invalid, or mark the field as required or invalid via ARIA.| `aria` |
| startContent | `ReactNode` | Element to be rendered in the left side of the date-picker. | - |
| endContent | `ReactNode` | Element to be rendered in the right side of the date-picker. | - |
| labelPlacement | `inside` \| `outside` \| `outside-left` | The position of the label. | `inside` |
| isRequired | `boolean` | Whether user input is required on the date-picker before form submission. | `false` |
| isReadOnly | `boolean` | Whether the date-picker can be selected but not changed by the user. | |
| isDisabled | `boolean` | Whether the date-picker is disabled. | `false` |
| isInvalid | `boolean` | Whether the date-picker is invalid. | `false` |
| visibleMonths | `number` \| `undefined` | The number of months to display at once. Up to 3 months are supported. Passing a number greater than 1 will disable the `showMonthAndYearPickers` prop. | `1` |
| selectorIcon | `ReactNode` | The icon to toggle the date picker popover. Usually a calendar icon. | |
| pageBehavior | `PageBehavior` \| `undefined` | Controls the behavior of paging. Pagination either works by advancing the visible page by visibleDuration (default) or one unit of visibleDuration. | `visible` |
| visibleMonths | `number` \| `undefined` | The number of months to display at once. Up to 3 months are supported. Passing a number greater than 1 will disable the `showMonthAndYearPickers` prop. | `1` |
| calendarWidth | `number` | The width to be applied to the calendar component. | `256` |
| CalendarTopContent | `ReactNode` | Top content to be rendered in the calendar component. | |
| isDateUnavailable | `((date: DateValue) => boolean)` \| `undefined` | Callback that is called for each date of the calendar. If it returns true, then the date is unavailable. |
| autoFocus | `boolean` | Whether the element should receive focus on render. | `false` |
| hourCycle | `12` \| `24` | Whether to display the time in 12 or 24 hour format. This is determined by the user's locale. | - |
| granularity | `day` \| `hour` \| `minute` \| `second` | Determines the smallest unit that is displayed in the date picker. Typically "day" for dates. | - |
| hideTimeZone | `boolean` | Whether to hide the time zone abbreviation. | `false` |
| shouldForceLeadingZeros | `boolean` | Whether to always show leading zeros in the month, day, and hour fields. | `true` |
| CalendarBottomContent | `ReactNode` | Bottom content to be rendered in the calendar component. | |
| showMonthAndYearPickers | `boolean` \| `undefined` | Whether the calendar should show month and year pickers. | false |
| popoverProps | `PopoverProps` \| `undefined` | Props to be passed to the popover component. | `{ placement: "bottom", triggerScaleOnOpen: false, offset: 13 }` |
| selectorButtonProps | `ButtonProps` \| `undefined` | Props to be passed to the selector button component. | `{ size: "sm", variant: "light", radius: "full", isIconOnly: true }` |
| calendarProps | `CalendarProps` \| `undefined` | Props to be passed to the selector button component. | `{ size: "sm", variant: "light", radius: "full", isIconOnly: true }` |
| timeInputProps | `TimeInputProps` | Props to be passed to the time input component. | `{ size: "sm", variant: "light", radius: "full", isIconOnly: true }` |
| disableAnimation | `boolean` | Whether to disable all animations in the date picker. Including the DateInput, Button, Calendar, and Popover. | `false` |
| classNames | `Record<"base" \| "selectorButton" \| "selectorIcon" \| "popoverContent" \| "calendar" \| "calendarContent" \| "timeInputLabel" \| "timeInput", string>` | Allows to set custom class names for the date-picker slots. | - |
### DatePicker Events

View File

@ -341,7 +341,7 @@ import {I18nProvider} from "@react-aria/i18n";
### DateRangePicker Props
| Attribute | Type | Description | Default |
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
|---------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------|
| label | `ReactNode` | The content to display as the label. | - |
| value | `RangeValue<CalendarDate \| CalendarDateTime \| ZonedDateTime>` \| `undefined` \| `null` | The current value of the date-range-picker (controlled). | - |
| variant | `flat` \| `bordered` \| `faded` \| `underlined` | The variant of the date input. | `flat` |
@ -354,6 +354,8 @@ import {I18nProvider} from "@react-aria/i18n";
| placeholderValue | `ZonedDateTime` \| `CalendarDate` \| `CalendarDateTime` \| `undefined` \| `null` | The placeholder of the date-range-picker. | - |
| description | `ReactNode` | A description for the date-range-picker. Provides a hint such as specific requirements for what to choose. | - |
| errorMessage | `ReactNode \| (v: ValidationResult) => ReactNode` | An error message for the date input. | - |
| validate | `(value: RangeValue<MappedDateValue<DateValue>>) => ValidationError true null undefined` | Validate input values when committing (e.g., on blur), and return error messages for invalid values. | - |
| validationBehavior | `native` \| `aria` | Whether to use native HTML form validation to prevent form submission when the value is missing or invalid, or mark the field as required or invalid via ARIA. | `aria` |
| startContent | `ReactNode` | Element to be rendered in the left side of the date-range-picker. | - |
| endContent | `ReactNode` | Element to be rendered in the right side of the date-range-picker. | - |
| startName | `string` | The name of the start date input element, used when submitting an HTML form. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefname) | - |
@ -367,8 +369,7 @@ import {I18nProvider} from "@react-aria/i18n";
| isInvalid | `boolean` | Whether the date-range-picker is invalid. | `false` |
| selectorIcon | `ReactNode` | The icon to toggle the date picker popover. Usually a calendar icon. | |
| pageBehavior | `single` \| `visible` | Controls the behavior of paging. Pagination either works by advancing the visible page by visibleDuration (default) or one unit of visibleDuration. | `visible` |
| validate | `(value: { inputValue: string, selectedKey: React.Key }) => ValidationError true null undefined` | Validate input values when committing (e.g., on blur), and return error messages for invalid values. | - |
| visibleMonths | `number` | The number of months to display at once. Up to 3 months are supported. Passing a number greater than 1 will disable the `showMonthAndYearPickers` prop. | `1` |
| visibleMonths | `number` | The number of months to display at once. Up to 3 months are supported. | `1` |
| autoFocus | `boolean` | Whether the element should receive focus on render. | `false` |
| hourCycle | `12` \| `24` | Whether to display the time in 12 or 24 hour format. This is determined by the user's locale. | - |
| granularity | `day` \| `hour` \| `minute` \| `second` | Determines the smallest unit that is displayed in the date picker. Typically "day" for dates. | - |

View File

@ -108,7 +108,7 @@ You can add a description to the input by passing the `description` property.
### With Error Message
You can combine the `isInvalid` and `errorMessage` properties to show an invalid input.
You can combine the `isInvalid` and `errorMessage` properties to show an invalid input. `errorMessage` is only shown when `isInvalid` is set to `true`.
<CodeDemo title="With Error Message" files={inputContent.errorMessage} />
@ -194,33 +194,34 @@ 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` \| `((v: ValidationResult) => ReactNode)` | An error message for the input. | - |
| validate | `(value: string) => ValidationError true null undefined` | Validate input values when committing (e.g. on blur), and return error messages for invalid values. | - |
| 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` |
| baseRef | `RefObject<HTMLDivElement>` | The ref to the base element. | - |
| 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 Input 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` \| `((v: ValidationResult) => ReactNode)` | An error message for the input. It is only shown when `isInvalid` is set to `true` | - |
| validate | `(value: string) => ValidationError true null undefined` | Validate input values when committing (e.g. on blur), and return error messages for invalid values. | - |
| validationBehavior | `native` \| `aria` | Whether to use native HTML form validation to prevent form submission when the value is missing or invalid, or mark the field as required or invalid via ARIA.| `aria` |
| 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` |
| baseRef | `RefObject<HTMLDivElement>` | The ref to the base element. | - |
| 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 Input slots. | - |
### Input Events

View File

@ -147,26 +147,27 @@ In case you need to customize the radio group even further, you can use the `use
### RadioGroup Props
| Attribute | Type | Description | Default |
| ---------------- | --------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
| children | `ReactNode` \| `ReactNode[]` | The list of radio elements. | - |
| label | `ReactNode` | The label of the radio group. | - |
| size | `sm` \| `md` \| `lg` | The size of the radios. | `md` |
| color | `default` \| `primary` \| `secondary` \| `success` \| `warning` \| `danger` | The color of the radios. | `primary` |
| orientation | `horizontal` \| `vertical` | The orientation of the radio group. | `vertical` |
| 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). | - |
| description | `ReactNode` | Radio group description . | - |
| errorMessage | `ReactNode` \| `((v: ValidationResult) => ReactNode)` | Radio group error message. | - |
| validate | `(value: string) => ValidationError true null undefined` | Validate input values when committing (e.g. on blur), and return error messages for invalid values. | - |
| 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. | - |
| Attribute | Type | Description | Default |
| ------------------ | --------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
| children | `ReactNode` \| `ReactNode[]` | The list of radio elements. | - |
| label | `ReactNode` | The label of the radio group. | - |
| size | `sm` \| `md` \| `lg` | The size of the radios. | `md` |
| color | `default` \| `primary` \| `secondary` \| `success` \| `warning` \| `danger` | The color of the radios. | `primary` |
| orientation | `horizontal` \| `vertical` | The orientation of the radio group. | `vertical` |
| 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). | - |
| description | `ReactNode` | Radio group description . | - |
| errorMessage | `ReactNode` \| `((v: ValidationResult) => ReactNode)` | Radio group error message. | - |
| validate | `(value: string) => ValidationError true null undefined` | Validate input values when committing (e.g. on blur), and return error messages for invalid values. | - |
| validationBehavior | `native` \| `aria` | Whether to use native HTML form validation to prevent form submission when the value is missing or invalid, or mark the field as required or invalid via ARIA.| `aria` |
| 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. | - |
### RadioGroup Events

View File

@ -201,38 +201,35 @@ Here's the example to customize `topContent` and `bottomContent` to have some pr
### RangeCalendar Props
| Attribute | Type | Description | Default | |
| ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | --- |
| value | `RangeValue | null` | The current value (controlled). | - |
| defaultValue | `RangeValue | null` | The default value (uncontrolled). | - |
| minValue | `DateValue` | The minimum allowed date that a user may select. | - | |
| maxValue | `DateValue` | The maximum allowed date that a user may select. | - | |
| color | `default` \| `primary` \| `secondary` \| `success` \| `warning` \| `danger` | The color of the time input. | `default` |
| visibleMonths | `number` | The number of months to display at once. Up to 3 months are supported. Passing a number greater than 1 will disable the `showMonthAndYearPickers` prop | `1` | |
| focusedValue | `DateValue` | Controls the currently focused date within the calendar. | - | |
| defaultFocusedValue | `DateValue` | The date that is focused when the calendar first mounts (uncountrolled). | - | |
| calendarWidth | `number` \| `string` | The width to be applied to the calendar component. This value is multiplied by the `visibleMonths` number to determine the total width of the calendar. | `256` |
| pageBehavior | `PageBehavior` | Controls the behavior of paging. Pagination either works by advancing the visible page by visibleDuration (default) or one unit of visibleDuration. | `visible` | |
| weekdayStyle | `"narrow" \|"short" \| "long" \| undefined` | The style of weekday names to display in the calendar grid header, e.g. single letter, abbreviation, or full day name. | `narrow` | |
| allowsNonContiguousRanges | `boolean` | When combined with `isDateUnavailable`, determines whether non-contiguous ranges, i.e. ranges containing unavailable dates, may be selected. | `false` | |
| showMonthAndYearPickers | `boolean` | Whether the label should be crossed out. | `false` | |
| isDisabled | `boolean` | Whether the calendar is disabled. | `false` | |
| isReadOnly | `boolean` | Whether the calendar value is immutable. | `false` | |
| isInvalid | `boolean` | Whether the current selection is invalid according to application logic. | - | |
| autoFocus | `boolean` | Whether to automatically focus the calendar when it mounts. | `false` | |
| showHelper | `boolean` | Whether to show the description or error message. | `false` | |
| showShadow | `boolean` | Whether to show the shadow in the selected dates. | `false` |
| isHeaderExpanded | `boolean` | Whether the calendar header is expanded. This is only available if the `showMonthAndYearPickers` prop is set to `true`. | `false` | |
| isHeaderDefaultExpanded | `boolean` | Whether the calendar header should be expanded by default.This is only available if the `showMonthAndYearPickers` prop is set to `true`. | `false` | |
| topContent | `ReactNode` | Custom content to be included in the top of the calendar. | - | |
| bottomContent | `ReactNode` | Custom content to be included in the bottom of the calendar. | - | |
| isDateUnavailable | `(date: DateValue) => boolean` | Callback that is called for each date of the calendar. If it returns true, then the date is unavailable. | - | |
| createCalendar | `(calendar: SupportedCalendars) => Calendar \| null` | This function helps to reduce the bundle size by providing a custom calendar system. You can also use the NextUIProvider to provide the createCalendar function to all nested components. | `all<br> calendars` | |
| errorMessage | `ReactNode \| (v: ValidationResult) => ReactNode` | An error message for the field. | - |
| validate | `(value: { inputValue: string, selectedKey: React.Key }) => ValidationError true null undefined` | Validate time input values when committing (e.g. on blur), and return error messages for invalid values. | - |
| hideDisabledDates | `boolean` | Whether to hide the disabled or invalid dates. | `false` |
| disableAnimation | `boolean` | Whether to disable the animation of the calendar. | `false` |
| classNames | `Record<"base" "prevButton" "nextButton" "headerWrapper" \| "header" \| "title" \| "content" \| "gridWrapper" \| "grid" \| "gridHeader" \| "gridHeaderRow" \| "gridHeaderCell" \| "gridBody" \| "gridBodyRow" \| "cell" \| "cellButton" \| "pickerWrapper" \| "pickerMonthList" \| "pickerYearList" \| "pickerHighlight" \| "pickerItem" \| "helperWrapper" \| "errorMessage", string>` | Allows to set custom class names for the calendar slots. | - | |
| Attribute | Type | Description | Default | |
|---------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------|---|
| value | `RangeValue | null` | The current value (controlled). | - |
| defaultValue | `RangeValue | null` | The default value (uncontrolled). | - |
| minValue | `DateValue` | The minimum allowed date that a user may select. | - | |
| maxValue | `DateValue` | The maximum allowed date that a user may select. | - | |
| color | `default` \| `primary` \| `secondary` \| `success` \| `warning` \| `danger` | The color of the time input. | `default` | |
| visibleMonths | `number` | The number of months to display at once. Up to 3 months are supported. | `1` | |
| focusedValue | `DateValue` | Controls the currently focused date within the calendar. | - | |
| defaultFocusedValue | `DateValue` | The date that is focused when the calendar first mounts (uncountrolled). | - | |
| calendarWidth | `number` \| `string` | The width to be applied to the calendar component. This value is multiplied by the `visibleMonths` number to determine the total width of the calendar. | `256` | |
| pageBehavior | `PageBehavior` | Controls the behavior of paging. Pagination either works by advancing the visible page by visibleDuration (default) or one unit of visibleDuration. | `visible` | |
| weekdayStyle | `"narrow" \|"short" \| "long" \| undefined` | The style of weekday names to display in the calendar grid header, e.g. single letter, abbreviation, or full day name. | `narrow` | |
| allowsNonContiguousRanges | `boolean` | When combined with `isDateUnavailable`, determines whether non-contiguous ranges, i.e. ranges containing unavailable dates, may be selected. | `false` | |
| isDisabled | `boolean` | Whether the calendar is disabled. | `false` | |
| isReadOnly | `boolean` | Whether the calendar value is immutable. | `false` | |
| isInvalid | `boolean` | Whether the current selection is invalid according to application logic. | - | |
| autoFocus | `boolean` | Whether to automatically focus the calendar when it mounts. | `false` | |
| showHelper | `boolean` | Whether to show the description or error message. | `false` | |
| showShadow | `boolean` | Whether to show the shadow in the selected dates. | `false` | |
| topContent | `ReactNode` | Custom content to be included in the top of the calendar. | - | |
| bottomContent | `ReactNode` | Custom content to be included in the bottom of the calendar. | - | |
| isDateUnavailable | `(date: DateValue) => boolean` | Callback that is called for each date of the calendar. If it returns true, then the date is unavailable. | - | |
| createCalendar | `(calendar: SupportedCalendars) => Calendar \| null` | This function helps to reduce the bundle size by providing a custom calendar system. You can also use the NextUIProvider to provide the createCalendar function to all nested components. | `all<br> calendars` | |
| errorMessage | `ReactNode \| (v: ValidationResult) => ReactNode` | An error message for the field. | - | |
| validate | `(value: { inputValue: string, selectedKey: React.Key }) => ValidationError true null undefined` | Validate time input values when committing (e.g. on blur), and return error messages for invalid values. | - | |
| hideDisabledDates | `boolean` | Whether to hide the disabled or invalid dates. | `false` | |
| disableAnimation | `boolean` | Whether to disable the animation of the calendar. | `false` | |
| classNames | `Record<"base" "prevButton" "nextButton" "headerWrapper" \| "header" \| "title" \| "content" \| "gridWrapper" \| "grid" \| "gridHeader" \| "gridHeaderRow" \| "gridHeaderCell" \| "gridBody" \| "gridBodyRow" \| "cell" \| "cellButton" \| "pickerWrapper" \| "pickerMonthList" \| "pickerYearList" \| "pickerHighlight" \| "pickerItem" \| "helperWrapper" \| "errorMessage", string>` | Allows to set custom class names for the calendar slots. | - | |
### RangeCalendar Events
@ -240,7 +237,6 @@ Here's the example to customize `topContent` and `bottomContent` to have some pr
| ---------------------- | ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| onFocusChange | `(date: CalendarDate) => void` | Handler that is called when the focused date changes. |
| onChange | `(value: RangeValue>) => void` | Handler that is called when the value changes. |
| onHeaderExpandedChange | `(isExpanded: boolean) => void` | The event handler for the calendar header expanded state. This is only available if the `showMonthAndYearPickers` prop is set to `true`. |
#### Supported Calendars

View File

@ -70,7 +70,7 @@ You can use the `selectionMode="multiple"` property to allow multiple selection.
You can disable specific items by using the `disabledKeys` property.
<CodeDemo title="Disabled Items" highlightedLines="8" files={selectContent.disabledItems} />
<CodeDemo title="Disabled Items" highlightedLines="10" files={selectContent.disabledItems} />
### Required
@ -81,7 +81,7 @@ the end of the label and the select will be required.
### Sizes
<CodeDemo title="Sizes" highlightedLines="13,26" files={selectContent.sizes} />
<CodeDemo title="Sizes" highlightedLines="13,24" files={selectContent.sizes} />
### Colors
@ -99,7 +99,7 @@ the end of the label and the select will be required.
You can change the position of the label by setting the `labelPlacement` property to `inside`, `outside` or `outside-left`.
<CodeDemo title="Label Placements" highlightedLines="20,37" files={selectContent.labelPlacements} />
<CodeDemo title="Label Placements" highlightedLines="19,37" files={selectContent.labelPlacements} />
> **Note**: If the `label` is not passed, the `labelPlacement` property will be `outside` by default.
@ -108,7 +108,7 @@ You can change the position of the label by setting the `labelPlacement` propert
You can use the `startContent` and `endContent` properties to add content to the start and end of
the select.
<CodeDemo title="Start Content" highlightedLines="9" files={selectContent.startContent} />
<CodeDemo title="Start Content" highlightedLines="13" files={selectContent.startContent} />
### Item Start & End Content

View File

@ -9,7 +9,7 @@ import {skeletonContent} from "@/content/components/skeleton";
Skeleton is a placeholder to show a loading state and the expected shape of a component.
<ComponentLinks component="skeleton" rscCompatible />
<ComponentLinks component="skeleton" />
---

View File

@ -274,18 +274,19 @@ You can customize the `Tabs` component by passing custom Tailwind CSS classes to
### Tab Props
| Attribute | Type | Description | Default |
| --------------------- | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
| children\* | `ReactNode` | The content of the tab. | - |
| title | `ReactNode` | The title of the tab. | - |
| titleValue | `string` | A string representation of the item's contents. Use this when the `title` is not readable. | - |
| href | `string` | A URL to link to. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#href). | - |
| target | `HTMLAttributeAnchorTarget` | The target window for the link. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#target). | - |
| rel | `string` | The relationship between the linked resource and the current page. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel). | - |
| download | `boolean` \| `string` | Causes the browser to download the linked URL. A string may be provided to suggest a file name. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#download). | - |
| ping | `string` | A space-separated list of URLs to ping when the link is followed. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#ping). | - |
| referrerPolicy | `HTMLAttributeReferrerPolicy` | How much of the referrer to send when following the link. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#referrerpolicy). | - |
| shouldSelectOnPressUp | `boolean` | Whether the tab selection should occur on press up instead of press down. | - |
| Attribute | Type | Description | Default |
|-------------------------|-------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|
| children\* | `ReactNode` | The content of the tab. | - |
| title | `ReactNode` | The title of the tab. | - |
| titleValue | `string` | A string representation of the item's contents. Use this when the `title` is not readable. | - |
| href | `string` | A URL to link to. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#href). | - |
| target | `HTMLAttributeAnchorTarget` | The target window for the link. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#target). | - |
| rel | `string` | The relationship between the linked resource and the current page. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel). | - |
| download | `boolean` \| `string` | Causes the browser to download the linked URL. A string may be provided to suggest a file name. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#download). | - |
| ping | `string` | A space-separated list of URLs to ping when the link is followed. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#ping). | - |
| referrerPolicy | `HTMLAttributeReferrerPolicy` | How much of the referrer to send when following the link. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#referrerpolicy). | - |
| shouldSelectOnPressUp | `boolean` | Whether the tab selection should occur on press up instead of press down. | - |
| destroyInactiveTabPanel | `boolean` | Whether to destroy inactive tab panel when switching tabs. Inactive tab panels are inert and cannot be interacted with. | `true` |
#### Motion Props

View File

@ -139,35 +139,36 @@ 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. | - |
| 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. | - |
| description | `ReactNode` | A description for the textarea. Provides a hint such as specific requirements for what to choose. | - |
| errorMessage | `ReactNode` \| `((v: ValidationResult) => ReactNode)` | An error message for the textarea. | - |
| validate | `(value: string) => ValidationError true null undefined` | Validate input values when committing (e.g. on blur), and return error messages for invalid values. | - |
| 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. | - |
| disableAutosize | `boolean` | Whether the textarea auto vertically resize should be disabled. | `false` |
| disableAnimation | `boolean` | Whether the textarea should be animated. | `false` |
| classNames | `Record<"base" "label" "inputWrapper" "innerWrapper" "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. | - |
| 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. | - |
| description | `ReactNode` | A description for the textarea. Provides a hint such as specific requirements for what to choose. | - |
| errorMessage | `ReactNode` \| `((v: ValidationResult) => ReactNode)` | An error message for the textarea. | - |
| validate | `(value: string) => ValidationError true null undefined` | Validate input values when committing (e.g. on blur), and return error messages for invalid values. | - |
| validationBehavior | `native` \| `aria` | Whether to use native HTML form validation to prevent form submission when the value is missing or invalid, or mark the field as required or invalid via ARIA.| `aria` |
| 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. | - |
| disableAutosize | `boolean` | Whether the textarea auto vertically resize should be disabled. | `false` |
| disableAnimation | `boolean` | Whether the textarea should be animated. | `false` |
| classNames | `Record<"base" "label" "inputWrapper" "innerWrapper" "input" "description" "errorMessage", string>` | Allows to set custom class names for the checkbox slots. | - |
### Input Events

View File

@ -223,9 +223,10 @@ By default, `TimeInput` displays times in either 12 or 24 hour hour format depen
| autoFocus | `boolean` | Whether the element should receive focus on render. | - |
| description | `ReactNode` | A description for the field. Provides a hint such as specific requirements for what to choose. | - |
| errorMessage | `ReactNode \| (v: ValidationResult) => ReactNode` | An error message for the field. | - |
| validate | `(value: { inputValue: string, selectedKey: React.Key }) => ValidationError true null undefined` | Validate time input values when committing (e.g. on blur), and return error messages for invalid values. | - |
| validate | `(value: MappedTimeValue<TimeValue>) => ValidationError true null undefined` | Validate time input values when committing (e.g. on blur), and return error messages for invalid values. | - |
| validationBehavior | `native` \| `aria` | Whether to use native HTML form validation to prevent form submission when the value is missing or invalid, or mark the field as required or invalid via ARIA. | `aria` |
| disableAnimation | `boolean` | Whether to disable the animation of the time input. | - |
| classNames | `Record<"base" "label" "inputWrapper" "innerWrapper" "segment" "helperWrapper" "input" "description" "errorMessage", string>` | Allows to set custom class names for the time input slots. | - |
| classNames | `Record<"base" "label" "inputWrapper" "innerWrapper" "segment" "helperWrapper" "input" "description" "errorMessage", string>` | Allows to set custom class names for the time input slots. | - |
### TimeInput Events

View File

@ -57,6 +57,7 @@ Usage: nextui [command]
Options:
-v, --version Show the version number
--no-cache Disable cache, by default data will be cached for 30m after the first request
-h, --help Display help for commands
Commands:
@ -75,7 +76,7 @@ Commands:
Initialize a new NextUI project using the `init` command. This sets up your project with the necessary configurations.
```codeBlock bash
nextui init [my-nextui-app-name]
nextui init my-nextui-app
```
<Spacer y={4} />
@ -83,11 +84,44 @@ nextui init [my-nextui-app-name]
You will be prompted to configure your project:
```codeBlock bash
? Select a template - Use arrow-keys. Return to submit.
App
A Next.js 13 with app directory template pre-configured with NextUI (v2) and Tailwind CSS.
Pages
A Next.js 13 with pages directory template pre-configured with NextUI (v2) and Tailwind CSS.
┌ Create a new project
◇ Select a template (Enter to select)
│ ● App (A Next.js 14 with app directory template pre-configured with NextUI (v2) and Tailwind CSS.)
│ ○ Pages (A Next.js 14 with pages directory template pre-configured with NextUI (v2) and Tailwind CSS.)
│ ○ Vite (A Vite template pre-configured with NextUI (v2) and Tailwind CSS.)
◇ New project name (Enter to skip with default name)
│ my-nextui-app
◇ Select a package manager (Enter to select)
│ ● npm
│ ○ yarn
│ ○ pnpm
│ ○ bun
◇ Template created successfully!
◇ Next steps ───────╮
│ │
│ cd my-nextui-app │
│ npm install │
│ │
├────────────────────╯
└ 🚀 Get started with npm run dev
```
Install the dependencies to start the local server:
```codeBlock bash
cd my-nextui-app && npm install
```
Start the local server:
```codeBlock bash
npm run dev
```
## add
@ -154,9 +188,16 @@ You will be asked to confirm the upgrade:
```codeBlock bash
╭───────────────────────────────────────────────────────────╮
│ @nextui-org/button 2.0.24 -> 2.0.27 │
╰───────────────────────────────────────────────────────────╯
╭───────────────────────── Component ─────────────────────────╮
│ @nextui-org/button ^2.0.11 -> ^2.0.31 │
╰─────────────────────────────────────────────────────────────╯
Required min version: @nextui-org/theme>=2.1.0, tailwindcss>=3.4.0
╭───────────────────── PeerDependencies ─────────────────────╮
│ @nextui-org/theme 2.0.1 -> 2.1.0 │
│ tailwindcss ^3.2.3 -> ^3.4.0 │
╰────────────────────────────────────────────────────────────╯
2 minor, 1 patch
? Would you like to proceed with the upgrade? - Use arrow-keys. Return to submit.
Yes

View File

@ -39,7 +39,17 @@ You will be prompted to configure your project:
A Next.js 13 with pages directory template pre-configured with NextUI (v2) and Tailwind CSS.
```
Once your NextUI project is initialized, you can add individual components using the CLI. For example, to add a button component:
Install the dependencies to start the local server:
```codeBlock bash
cd my-nextui-app && npm install
```
Start the local server:
```codeBlock bash
npm run dev
```
Once your NextUI project is ready to develop, you can add individual components using the CLI. For example, to add a button component:
```codeBlock bash
nextui add button

View File

@ -37,25 +37,25 @@
"@nextui-org/use-infinite-scroll": "workspace:*",
"@nextui-org/use-is-mobile": "workspace:*",
"@radix-ui/react-scroll-area": "^1.0.5",
"@react-aria/focus": "^3.14.3",
"@react-aria/i18n": "^3.8.4",
"@react-aria/interactions": "^3.19.1",
"@react-aria/selection": "^3.17.1",
"@react-aria/ssr": "^3.8.0",
"@react-aria/utils": "^3.21.1",
"@react-aria/virtualizer": "^3.9.4",
"@react-aria/visually-hidden": "^3.8.6",
"@react-stately/data": "^3.10.3",
"@react-stately/layout": "^3.13.3",
"@react-stately/tree": "^3.7.3",
"@react-aria/focus": "^3.16.2",
"@react-aria/i18n": "^3.10.2",
"@react-aria/interactions": "^3.21.1",
"@react-aria/selection": "^3.17.5",
"@react-aria/ssr": "^3.9.2",
"@react-aria/utils": "^3.23.2",
"@react-aria/virtualizer": "^3.9.10",
"@react-aria/visually-hidden": "^3.8.10",
"@react-stately/data": "^3.11.2",
"@react-stately/layout": "^3.13.7",
"@react-stately/tree": "^3.7.6",
"@rehooks/local-storage": "^2.4.5",
"@vercel/analytics": "^1.1.1",
"canvas-confetti": "^1.9.0",
"@vercel/analytics": "^1.2.2",
"canvas-confetti": "^1.9.2",
"cmdk": "^0.2.0",
"color2k": "^2.0.2",
"contentlayer": "^0.3.4",
"date-fns": "^2.30.0",
"framer-motion": "^11.0.22",
"framer-motion": "^11.1.7",
"github-slugger": "^2.0.0",
"gray-matter": "^4.0.3",
"hast-util-to-html": "7.1.2",
@ -101,7 +101,7 @@
"@docusaurus/utils": "2.0.0-beta.3",
"@next/bundle-analyzer": "^13.4.6",
"@next/env": "^13.4.12",
"@react-types/shared": "^3.22.0",
"@react-types/shared": "^3.22.1",
"@tailwindcss/typography": "^0.5.9",
"@types/canvas-confetti": "^1.4.2",
"@types/lodash": "^4.14.194",

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

View File

@ -32,6 +32,7 @@
"lint:fix": "eslint --fix -c .eslintrc.json ./packages/**/**/*.{ts,tsx}",
"lint:docs-fix": "eslint --fix -c .eslintrc.json ./apps/docs/**/*.{ts,tsx}",
"check:rap": "tsx scripts/check-rap-updates.ts",
"fix:rap": "tsx scripts/fix-rap.ts",
"format:check": "prettier --check packages/**/**/src --cache",
"format:write": "prettier --write packages/**/**/src --cache",
"turbo:clean": "turbo clean && rimraf ./node_modules/.cache/turbo",
@ -67,7 +68,7 @@
"@commitlint/config-conventional": "^17.2.0",
"@react-bootstrap/babel-preset": "^2.1.0",
"@react-types/link": "^3.4.4",
"@react-types/shared": "^3.22.0",
"@react-types/shared": "^3.22.1",
"@swc-node/jest": "^1.5.2",
"@swc/core": "^1.3.35",
"@swc/jest": "^0.2.24",

View File

@ -1,5 +1,20 @@
# @nextui-org/accordion
## 2.0.33
### Patch Changes
- [#2265](https://github.com/nextui-org/nextui/pull/2265) [`10497f1a9`](https://github.com/nextui-org/nextui/commit/10497f1a97c0ecfec1cf699a1cd407be48553754) Thanks [@outputboy](https://github.com/outputboy)! - Make the accordion item heading tag customizable to satisfy a11y needs. Headings on web pages need to be consistent and semantic; this will help all users better find the content they are looking for. (#2950)
- [#2929](https://github.com/nextui-org/nextui/pull/2929) [`422770cc6`](https://github.com/nextui-org/nextui/commit/422770cc6bcdd1d4c51257654ab718f3c19d6cb2) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - Add support for disabling the animations globally.
- [#2725](https://github.com/nextui-org/nextui/pull/2725) [`8048dcc0c`](https://github.com/nextui-org/nextui/commit/8048dcc0c37455d2574c93d6f9fa505a936aedb5) Thanks [@ericfabreu](https://github.com/ericfabreu)! - Fix 'Tap to click' behavior on macOS for Accordion and Tab
- Updated dependencies [[`3b14c21e0`](https://github.com/nextui-org/nextui/commit/3b14c21e02fedf15d7d22e911109dac60c4e780e), [`422770cc6`](https://github.com/nextui-org/nextui/commit/422770cc6bcdd1d4c51257654ab718f3c19d6cb2)]:
- @nextui-org/aria-utils@2.0.19
- @nextui-org/framer-utils@2.0.19
- @nextui-org/divider@2.0.28
## 2.0.32
### Patch Changes

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/accordion",
"version": "2.0.32",
"version": "2.0.33",
"description": "Collapse display a list of high-level options that can expand/collapse to reveal more information.",
"keywords": [
"react",
@ -42,7 +42,7 @@
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18",
"framer-motion": ">=4.0.0",
"framer-motion": ">=10.17.0",
"@nextui-org/theme": ">=2.1.0",
"@nextui-org/system": ">=2.0.0"
},
@ -54,13 +54,13 @@
"@nextui-org/framer-utils": "workspace:*",
"@nextui-org/divider": "workspace:*",
"@nextui-org/use-aria-accordion": "workspace:*",
"@react-aria/interactions": "^3.21.1",
"@react-aria/focus": "^3.16.2",
"@react-aria/utils": "^3.23.2",
"@react-stately/tree": "^3.7.6",
"@react-aria/button": "^3.9.3",
"@react-aria/interactions": "3.21.1",
"@react-aria/focus": "3.16.2",
"@react-aria/utils": "3.23.2",
"@react-stately/tree": "3.7.6",
"@react-aria/button": "3.9.3",
"@react-types/accordion": "3.0.0-alpha.19",
"@react-types/shared": "^3.22.1"
"@react-types/shared": "3.22.1"
},
"devDependencies": {
"@nextui-org/theme": "workspace:*",
@ -75,4 +75,4 @@
"react-dom": "^18.0.0"
},
"clean-package": "../../../clean-package.config.json"
}
}

View File

@ -11,6 +11,7 @@ export interface AccordionItemProps extends UseAccordionItemProps {}
const AccordionItem = forwardRef<"button", AccordionItemProps>((props, ref) => {
const {
Component,
HeadingComponent,
classNames,
slots,
indicator,
@ -89,7 +90,7 @@ const AccordionItem = forwardRef<"button", AccordionItemProps>((props, ref) => {
return (
<Component {...getBaseProps()}>
<h2 {...getHeadingProps()}>
<HeadingComponent {...getHeadingProps()}>
<button {...getButtonProps()}>
{startContent && (
<div className={slots.startContent({class: classNames?.startContent})}>
@ -104,7 +105,7 @@ const AccordionItem = forwardRef<"button", AccordionItemProps>((props, ref) => {
<span {...getIndicatorProps()}>{indicatorComponent}</span>
)}
</button>
</h2>
</HeadingComponent>
{content}
</Component>
);

View File

@ -4,6 +4,7 @@ import type {
SlotsToClasses,
} from "@nextui-org/theme";
import {As} from "@nextui-org/system";
import {ItemProps, BaseItem} from "@nextui-org/aria-utils";
import {FocusableProps, PressEvents} from "@react-types/shared";
import {ReactNode, MouseEventHandler} from "react";
@ -85,6 +86,12 @@ export interface Props<T extends object = {}>
* ```
*/
classNames?: SlotsToClasses<AccordionItemSlots>;
/**
* Customizable heading tag for Web accessibility:
* use headings to describe content and use them consistently and semantically.
* This will help all users to better find the content they are looking for.
*/
HeadingComponent?: As;
}
export type AccordionItemBaseProps<T extends object = {}> = Props<T> & AccordionItemVariantProps;

View File

@ -1,4 +1,4 @@
import {HTMLNextUIProps, PropGetter} from "@nextui-org/system";
import {HTMLNextUIProps, PropGetter, useProviderContext} from "@nextui-org/system";
import {useFocusRing} from "@react-aria/focus";
import {accordionItem} from "@nextui-org/theme";
import {clsx, callAllHandlers, dataAttr, objectToDeps} from "@nextui-org/shared-utils";
@ -39,6 +39,8 @@ export type UseAccordionItemProps<T extends object = {}> = Props<T> &
Omit<AccordionItemBaseProps, "onFocusChange">;
export function useAccordionItem<T extends object = {}>(props: UseAccordionItemProps<T>) {
const globalContext = useProviderContext();
const {ref, as, item, onFocusChange} = props;
const {
@ -55,9 +57,10 @@ export function useAccordionItem<T extends object = {}>(props: UseAccordionItemP
classNames: classNamesProp = {},
isDisabled: isDisabledProp = false,
hideIndicator = false,
disableAnimation = false,
disableAnimation = globalContext?.disableAnimation ?? false,
keepContentMounted = false,
disableIndicatorAnimation = false,
HeadingComponent = as || "h2",
onPress,
onPressStart,
onPressEnd,
@ -169,8 +172,9 @@ export function useAccordionItem<T extends object = {}>(props: UseAccordionItemP
otherProps.onBlur,
item.props?.onBlur,
),
...mergeProps(buttonProps, hoverProps, pressProps, props),
onClick: chain(pressProps.onClick, onClick),
...mergeProps(buttonProps, hoverProps, pressProps, props, {
onClick: chain(pressProps.onClick, onClick),
}),
};
};
@ -237,6 +241,7 @@ export function useAccordionItem<T extends object = {}>(props: UseAccordionItemP
return {
Component,
HeadingComponent,
item,
slots,
classNames,

View File

@ -1,8 +1,8 @@
import type {HTMLNextUIProps, PropGetter} from "@nextui-org/system";
import type {SelectionBehavior, MultipleSelection} from "@react-types/shared";
import type {AriaAccordionProps} from "@react-types/accordion";
import type {AccordionGroupVariantProps} from "@nextui-org/theme";
import {useProviderContext, type HTMLNextUIProps, type PropGetter} from "@nextui-org/system";
import {ReactRef, filterDOMProps} from "@nextui-org/react-utils";
import React, {Key, useCallback} from "react";
import {TreeState, useTreeState} from "@react-stately/tree";
@ -73,6 +73,8 @@ export type ValuesType<T extends object = {}> = {
};
export function useAccordion<T extends object>(props: UseAccordionProps<T>) {
const globalContext = useProviderContext();
const {
ref,
as,
@ -97,7 +99,7 @@ export function useAccordion<T extends object>(props: UseAccordionProps<T>) {
isDisabled = false,
showDivider = true,
hideIndicator = false,
disableAnimation = false,
disableAnimation = globalContext?.disableAnimation ?? false,
disableIndicatorAnimation = false,
itemClasses,
...otherProps

View File

@ -1,5 +1,30 @@
# @nextui-org/autocomplete
## 2.1.0
### Minor Changes
- [#2987](https://github.com/nextui-org/nextui/pull/2987) [`540aa2124`](https://github.com/nextui-org/nextui/commit/540aa2124b45b65a40e73f5aea2b90405fe1fe9a) Thanks [@ryo-manba](https://github.com/ryo-manba)! - Change validationBehavior from native to aria by default, with the option to change via props.
### Patch Changes
- [#2889](https://github.com/nextui-org/nextui/pull/2889) [`aba1716ed`](https://github.com/nextui-org/nextui/commit/aba1716edc2a85c94e6baeb4acc481f67589d002) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - Update React Aria packages
- [#2854](https://github.com/nextui-org/nextui/pull/2854) [`3b14c21e0`](https://github.com/nextui-org/nextui/commit/3b14c21e02fedf15d7d22e911109dac60c4e780e) Thanks [@wingkwong](https://github.com/wingkwong)! - Revise popover-based focus behaviours (#2849, #2834, #2779, #2962, #2872, #2974, #1920, #1287, #3060)
- [#2953](https://github.com/nextui-org/nextui/pull/2953) [`c8f792ccd`](https://github.com/nextui-org/nextui/commit/c8f792ccd78a80000e6f5b15e6f22cac947fd531) Thanks [@ryo-manba](https://github.com/ryo-manba)! - Fix update type definition to prevent primitive values as items (#2938)
- [#2929](https://github.com/nextui-org/nextui/pull/2929) [`422770cc6`](https://github.com/nextui-org/nextui/commit/422770cc6bcdd1d4c51257654ab718f3c19d6cb2) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - Add support for disabling the animations globally.
- Updated dependencies [[`3b14c21e0`](https://github.com/nextui-org/nextui/commit/3b14c21e02fedf15d7d22e911109dac60c4e780e), [`c8f792ccd`](https://github.com/nextui-org/nextui/commit/c8f792ccd78a80000e6f5b15e6f22cac947fd531), [`422770cc6`](https://github.com/nextui-org/nextui/commit/422770cc6bcdd1d4c51257654ab718f3c19d6cb2), [`540aa2124`](https://github.com/nextui-org/nextui/commit/540aa2124b45b65a40e73f5aea2b90405fe1fe9a)]:
- @nextui-org/popover@2.1.22
- @nextui-org/aria-utils@2.0.19
- @nextui-org/listbox@2.1.20
- @nextui-org/button@2.0.32
- @nextui-org/input@2.2.0
- @nextui-org/scroll-shadow@2.1.16
- @nextui-org/spinner@2.0.29
## 2.0.16
### Patch Changes

View File

@ -1,8 +1,9 @@
import * as React from "react";
import {act, render} from "@testing-library/react";
import {within, render, renderHook, act} from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import {useForm} from "react-hook-form";
import {Autocomplete, AutocompleteItem, AutocompleteSection} from "../src";
import {Autocomplete, AutocompleteItem, AutocompleteProps, AutocompleteSection} from "../src";
import {Modal, ModalContent, ModalBody, ModalHeader, ModalFooter} from "../../modal/src";
type Item = {
@ -47,21 +48,23 @@ const itemsSectionData = [
},
];
const AutocompleteExample = (props: Partial<AutocompleteProps> = {}) => (
<Autocomplete label="Favorite Animal" {...props}>
<AutocompleteItem key="penguin" value="penguin">
Penguin
</AutocompleteItem>
<AutocompleteItem key="zebra" value="zebra">
Zebra
</AutocompleteItem>
<AutocompleteItem key="shark" value="shark">
Shark
</AutocompleteItem>
</Autocomplete>
);
describe("Autocomplete", () => {
it("should render correctly", () => {
const wrapper = render(
<Autocomplete aria-label="Favorite Animal" label="Favorite Animal">
<AutocompleteItem key="penguin" value="penguin">
Penguin
</AutocompleteItem>
<AutocompleteItem key="zebra" value="zebra">
Zebra
</AutocompleteItem>
<AutocompleteItem key="shark" value="shark">
Shark
</AutocompleteItem>
</Autocomplete>,
);
const wrapper = render(<AutocompleteExample />);
expect(() => wrapper.unmount()).not.toThrow();
});
@ -82,6 +85,7 @@ describe("Autocomplete", () => {
</AutocompleteItem>
</Autocomplete>,
);
expect(ref.current).not.toBeNull();
});
@ -136,7 +140,136 @@ describe("Autocomplete", () => {
expect(() => wrapper.unmount()).not.toThrow();
});
it("should close dropdown when clicking outside autocomplete", async () => {
it("should focus when clicking autocomplete", async () => {
const wrapper = render(
<Autocomplete aria-label="Favorite Animal" data-testid="autocomplete" label="Favorite Animal">
<AutocompleteItem key="penguin" value="penguin">
Penguin
</AutocompleteItem>
<AutocompleteItem key="zebra" value="zebra">
Zebra
</AutocompleteItem>
<AutocompleteItem key="shark" value="shark">
Shark
</AutocompleteItem>
</Autocomplete>,
);
const autocomplete = wrapper.getByTestId("autocomplete");
// open the select listbox
await act(async () => {
await userEvent.click(autocomplete);
});
// assert that the autocomplete listbox is open
expect(autocomplete).toHaveAttribute("aria-expanded", "true");
// assert that input is focused
expect(autocomplete).toHaveFocus();
});
it("should clear value after clicking clear button", async () => {
const wrapper = render(
<Autocomplete aria-label="Favorite Animal" data-testid="autocomplete" label="Favorite Animal">
<AutocompleteItem key="penguin" value="penguin">
Penguin
</AutocompleteItem>
<AutocompleteItem key="zebra" value="zebra">
Zebra
</AutocompleteItem>
<AutocompleteItem key="shark" value="shark">
Shark
</AutocompleteItem>
</Autocomplete>,
);
const autocomplete = wrapper.getByTestId("autocomplete");
// open the select listbox
await act(async () => {
await userEvent.click(autocomplete);
});
// assert that the autocomplete listbox is open
expect(autocomplete).toHaveAttribute("aria-expanded", "true");
let options = wrapper.getAllByRole("option");
// select the target item
await act(async () => {
await userEvent.click(options[0]);
});
const {container} = wrapper;
const clearButton = container.querySelector(
"[data-slot='inner-wrapper'] button:nth-of-type(1)",
)!;
expect(clearButton).not.toBeNull();
// select the target item
await act(async () => {
await userEvent.click(clearButton);
});
// assert that the input has empty value
expect(autocomplete).toHaveValue("");
// assert that input is focused
expect(autocomplete).toHaveFocus();
});
it("should open and close listbox by clicking selector button", async () => {
const wrapper = render(
<Autocomplete aria-label="Favorite Animal" data-testid="autocomplete" label="Favorite Animal">
<AutocompleteItem key="penguin" value="penguin">
Penguin
</AutocompleteItem>
<AutocompleteItem key="zebra" value="zebra">
Zebra
</AutocompleteItem>
<AutocompleteItem key="shark" value="shark">
Shark
</AutocompleteItem>
</Autocomplete>,
);
const {container} = wrapper;
const selectorButton = container.querySelector(
"[data-slot='inner-wrapper'] button:nth-of-type(2)",
)!;
expect(selectorButton).not.toBeNull();
const autocomplete = wrapper.getByTestId("autocomplete");
// open the select listbox by clicking selector button
await act(async () => {
await userEvent.click(selectorButton);
});
// assert that the autocomplete listbox is open
expect(autocomplete).toHaveAttribute("aria-expanded", "true");
// assert that input is focused
expect(autocomplete).toHaveFocus();
// close the select listbox by clicking selector button again
await act(async () => {
await userEvent.click(selectorButton);
});
// assert that the autocomplete listbox is closed
expect(autocomplete).toHaveAttribute("aria-expanded", "false");
// assert that input is still focused
expect(autocomplete).toHaveFocus();
});
it("should close listbox when clicking outside autocomplete", async () => {
const wrapper = render(
<Autocomplete
aria-label="Favorite Animal"
@ -157,12 +290,12 @@ describe("Autocomplete", () => {
const autocomplete = wrapper.getByTestId("close-when-clicking-outside-test");
// open the select dropdown
// open the select listbox
await act(async () => {
await userEvent.click(autocomplete);
});
// assert that the autocomplete dropdown is open
// assert that the autocomplete listbox is open
expect(autocomplete).toHaveAttribute("aria-expanded", "true");
// click outside the autocomplete component
@ -172,9 +305,12 @@ describe("Autocomplete", () => {
// assert that the autocomplete is closed
expect(autocomplete).toHaveAttribute("aria-expanded", "false");
// assert that input is not focused
expect(autocomplete).not.toHaveFocus();
});
it("should close dropdown when clicking outside autocomplete with modal open", async () => {
it("should close listbox when clicking outside autocomplete with modal open", async () => {
const wrapper = render(
<Modal isOpen>
<ModalContent>
@ -203,12 +339,12 @@ describe("Autocomplete", () => {
const autocomplete = wrapper.getByTestId("close-when-clicking-outside-test");
// open the autocomplete dropdown
// open the autocomplete listbox
await act(async () => {
await userEvent.click(autocomplete);
});
// assert that the autocomplete dropdown is open
// assert that the autocomplete listbox is open
expect(autocomplete).toHaveAttribute("aria-expanded", "true");
// click outside the autocomplete component
@ -216,7 +352,313 @@ describe("Autocomplete", () => {
await userEvent.click(document.body);
});
// assert that the autocomplete dropdown is closed
// assert that the autocomplete listbox is closed
expect(autocomplete).toHaveAttribute("aria-expanded", "false");
// assert that input is not focused
expect(autocomplete).not.toHaveFocus();
});
it("should set the input after selection", async () => {
const wrapper = render(
<Autocomplete aria-label="Favorite Animal" data-testid="autocomplete" label="Favorite Animal">
<AutocompleteItem key="penguin" value="penguin">
Penguin
</AutocompleteItem>
<AutocompleteItem key="zebra" value="zebra">
Zebra
</AutocompleteItem>
<AutocompleteItem key="shark" value="shark">
Shark
</AutocompleteItem>
</Autocomplete>,
);
const autocomplete = wrapper.getByTestId("autocomplete");
// open the listbox
await act(async () => {
await userEvent.click(autocomplete);
});
// assert that the autocomplete listbox is open
expect(autocomplete).toHaveAttribute("aria-expanded", "true");
// assert that input is focused
expect(autocomplete).toHaveFocus();
let options = wrapper.getAllByRole("option");
expect(options.length).toBe(3);
// select the target item
await act(async () => {
await userEvent.click(options[0]);
});
// assert that the input has target selection
expect(autocomplete).toHaveValue("Penguin");
});
it("should close listbox by clicking another autocomplete", async () => {
const wrapper = render(
<>
<Autocomplete
aria-label="Favorite Animal"
data-testid="autocomplete"
label="Favorite Animal"
>
<AutocompleteItem key="penguin" value="penguin">
Penguin
</AutocompleteItem>
<AutocompleteItem key="zebra" value="zebra">
Zebra
</AutocompleteItem>
<AutocompleteItem key="shark" value="shark">
Shark
</AutocompleteItem>
</Autocomplete>
<Autocomplete
aria-label="Favorite Animal"
data-testid="autocomplete2"
label="Favorite Animal"
>
<AutocompleteItem key="penguin" value="penguin">
Penguin
</AutocompleteItem>
<AutocompleteItem key="zebra" value="zebra">
Zebra
</AutocompleteItem>
<AutocompleteItem key="shark" value="shark">
Shark
</AutocompleteItem>
</Autocomplete>
</>,
);
const {container} = wrapper;
const autocomplete = wrapper.getByTestId("autocomplete");
const autocomplete2 = wrapper.getByTestId("autocomplete2");
const innerWrappers = container.querySelectorAll("[data-slot='inner-wrapper']");
const selectorButton = innerWrappers[0].querySelector("button:nth-of-type(2)")!;
const selectorButton2 = innerWrappers[1].querySelector("button:nth-of-type(2)")!;
expect(selectorButton).not.toBeNull();
expect(selectorButton2).not.toBeNull();
// open the select listbox by clicking selector button in the first autocomplete
await act(async () => {
await userEvent.click(selectorButton);
});
// assert that the first autocomplete listbox is open
expect(autocomplete).toHaveAttribute("aria-expanded", "true");
// assert that input is focused
expect(autocomplete).toHaveFocus();
// close the select listbox by clicking the second autocomplete
await act(async () => {
await userEvent.click(selectorButton2);
});
// assert that the first autocomplete listbox is closed
expect(autocomplete).toHaveAttribute("aria-expanded", "false");
// assert that the second autocomplete listbox is open
expect(autocomplete2).toHaveAttribute("aria-expanded", "true");
// assert that the first autocomplete is not focused
expect(autocomplete).not.toHaveFocus();
// assert that the second autocomplete is focused
expect(autocomplete2).toHaveFocus();
});
describe("validation", () => {
let user;
beforeAll(() => {
user = userEvent.setup();
});
describe("validationBehavior=native", () => {
it("supports isRequired", async () => {
const {getByTestId, getByRole, findByRole} = render(
<form data-testid="form">
<AutocompleteExample isRequired validationBehavior="native" />
</form>,
);
const input = getByRole("combobox") as HTMLInputElement;
expect(input).toHaveAttribute("required");
expect(input).not.toHaveAttribute("aria-required");
expect(input).not.toHaveAttribute("aria-describedby");
expect(input.validity.valid).toBe(false);
act(() => {
(getByTestId("form") as HTMLFormElement).checkValidity();
});
expect(input).toHaveAttribute("aria-describedby");
expect(document.getElementById(input.getAttribute("aria-describedby")!)).toHaveTextContent(
"Constraints not satisfied",
);
await user.click(input);
await user.keyboard("pe");
const listbox = await findByRole("listbox");
const items = within(listbox).getAllByRole("option");
await user.click(items[0]);
expect(input).toHaveAttribute("aria-describedby");
});
});
describe("validationBehavior=aria", () => {
it("supports validate function", async () => {
let {getByRole, findByRole} = render(
<form data-testid="form">
<AutocompleteExample
defaultInputValue="Penguin"
validate={(v) => (v === "Penguin" ? "Invalid value" : null)}
validationBehavior="aria"
/>
</form>,
);
const input = getByRole("combobox") as HTMLInputElement;
expect(input).toHaveAttribute("aria-describedby");
expect(input).toHaveAttribute("aria-invalid", "true");
expect(document.getElementById(input.getAttribute("aria-describedby")!)).toHaveTextContent(
"Invalid value",
);
expect(input.validity.valid).toBe(true);
await user.tab();
await user.click();
// open the select dropdown
await user.keyboard("{ArrowDown}");
const listbox = await findByRole("listbox");
const item = within(listbox).getByRole("option", {name: "Zebra"});
await user.click(item);
expect(input).not.toHaveAttribute("aria-describedby");
expect(input).not.toHaveAttribute("aria-invalid");
});
});
});
});
describe("Autocomplete with React Hook Form", () => {
let autocomplete1: HTMLInputElement;
let autocomplete2: HTMLInputElement;
let autocomplete3: HTMLInputElement;
let submitButton: HTMLButtonElement;
let wrapper: any;
let onSubmit: () => void;
beforeEach(() => {
const {result} = renderHook(() =>
useForm({
defaultValues: {
withDefaultValue: "cat",
withoutDefaultValue: "",
requiredField: "",
},
}),
);
const {
handleSubmit,
register,
formState: {errors},
} = result.current;
onSubmit = jest.fn();
wrapper = render(
<form className="flex w-full max-w-xs flex-col gap-2" onSubmit={handleSubmit(onSubmit)}>
<Autocomplete
data-testid="autocomplete-1"
{...register("withDefaultValue")}
aria-label="Favorite Animal"
items={itemsData}
label="Favorite Animal"
>
{(item) => <AutocompleteItem key={item.value}>{item.label}</AutocompleteItem>}
</Autocomplete>
<Autocomplete
data-testid="autocomplete-2"
{...register("withoutDefaultValue")}
aria-label="Favorite Animal"
items={itemsData}
label="Favorite Animal"
>
{(item) => <AutocompleteItem key={item.value}>{item.label}</AutocompleteItem>}
</Autocomplete>
<Autocomplete
data-testid="autocomplete-3"
{...register("requiredField", {required: true})}
aria-label="Favorite Animal"
items={itemsData}
label="Favorite Animal"
>
{(item) => <AutocompleteItem key={item.value}>{item.label}</AutocompleteItem>}
</Autocomplete>
{errors.requiredField && <span className="text-danger">This field is required</span>}
<button data-testid="submit-button" type="submit">
Submit
</button>
</form>,
);
autocomplete1 = wrapper.getByTestId("autocomplete-1");
autocomplete2 = wrapper.getByTestId("autocomplete-2");
autocomplete3 = wrapper.getByTestId("autocomplete-3");
submitButton = wrapper.getByTestId("submit-button");
});
it("should work with defaultValues", () => {
expect(autocomplete1).toHaveValue("Cat");
expect(autocomplete2).toHaveValue("");
expect(autocomplete3).toHaveValue("");
});
it("should not submit form when required field is empty", async () => {
const user = userEvent.setup();
await user.click(submitButton);
expect(onSubmit).toHaveBeenCalledTimes(0);
});
it("should submit form when required field is not empty", async () => {
const user = userEvent.setup();
await user.click(autocomplete3);
expect(autocomplete3).toHaveAttribute("aria-expanded", "true");
let listboxItems = wrapper.getAllByRole("option");
await user.click(listboxItems[1]);
expect(autocomplete3).toHaveValue("Dog");
await user.click(submitButton);
expect(onSubmit).toHaveBeenCalledTimes(1);
});
});

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/autocomplete",
"version": "2.0.16",
"version": "2.1.0",
"description": "An autocomplete combines a text input with a listbox, allowing users to filter a list of options to items matching a query.",
"keywords": [
"autocomplete"
@ -36,7 +36,7 @@
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18",
"framer-motion": ">=4.0.0",
"framer-motion": ">=10.17.0",
"@nextui-org/theme": ">=2.1.0",
"@nextui-org/system": ">=2.0.0"
},
@ -53,15 +53,15 @@
"@nextui-org/use-aria-button": "workspace:*",
"@nextui-org/shared-icons": "workspace:*",
"@nextui-org/use-safe-layout-effect": "workspace:*",
"@react-aria/combobox": "^3.8.4",
"@react-aria/focus": "^3.16.2",
"@react-aria/i18n": "^3.10.2",
"@react-aria/interactions": "^3.21.1",
"@react-aria/utils": "^3.23.2",
"@react-aria/visually-hidden": "^3.8.10",
"@react-stately/combobox": "^3.8.2",
"@react-types/combobox": "^3.10.1",
"@react-types/shared": "^3.22.1"
"@react-aria/combobox": "3.8.4",
"@react-aria/focus": "3.16.2",
"@react-aria/i18n": "3.10.2",
"@react-aria/interactions": "3.21.1",
"@react-aria/utils": "3.23.2",
"@react-aria/visually-hidden": "3.8.10",
"@react-stately/combobox": "3.8.2",
"@react-types/combobox": "3.10.1",
"@react-types/shared": "3.22.1"
},
"devDependencies": {
"@nextui-org/theme": "workspace:*",
@ -70,11 +70,12 @@
"@nextui-org/chip": "workspace:*",
"@nextui-org/stories-utils": "workspace:*",
"@nextui-org/use-infinite-scroll": "workspace:*",
"@react-stately/data": "^3.11.0",
"@react-stately/data": "3.11.2",
"framer-motion": "^11.0.28",
"clean-package": "2.2.0",
"react": "^18.0.0",
"react-dom": "^18.0.0"
"react-dom": "^18.0.0",
"react-hook-form": "^7.51.3"
},
"clean-package": "../../../clean-package.config.json"
}
}

View File

@ -15,7 +15,6 @@ interface Props<T> extends UseAutocompleteProps<T> {}
function Autocomplete<T extends object>(props: Props<T>, ref: ForwardedRef<HTMLInputElement>) {
const {
Component,
state,
isOpen,
disableAnimation,
selectorIcon = <ChevronDownIcon />,
@ -33,7 +32,7 @@ function Autocomplete<T extends object>(props: Props<T>, ref: ForwardedRef<HTMLI
} = useAutocomplete<T>({...props, ref});
const popoverContent = isOpen ? (
<FreeSoloPopover {...getPopoverProps()} state={state}>
<FreeSoloPopover {...getPopoverProps()}>
<ScrollShadow {...getListBoxWrapperProps()}>
<Listbox {...getListBoxProps()} />
</ScrollShadow>
@ -58,10 +57,10 @@ function Autocomplete<T extends object>(props: Props<T>, ref: ForwardedRef<HTMLI
);
}
export type AutocompleteProps<T = object> = Props<T> & {ref?: Ref<HTMLElement>};
export type AutocompleteProps<T extends object = object> = Props<T> & {ref?: Ref<HTMLElement>};
// forwardRef doesn't support generic parameters, so cast the result to the correct type
export default forwardRef(Autocomplete) as <T = object>(
export default forwardRef(Autocomplete) as <T extends object>(
props: AutocompleteProps<T>,
) => ReactElement;

View File

@ -1,6 +1,7 @@
import type {AutocompleteVariantProps, SlotsToClasses, AutocompleteSlots} from "@nextui-org/theme";
import type {DOMAttributes, HTMLNextUIProps, PropGetter} from "@nextui-org/system";
import {DOMAttributes, HTMLNextUIProps, mapPropsVariants, PropGetter} from "@nextui-org/system";
import {mapPropsVariants, useProviderContext} from "@nextui-org/system";
import {useSafeLayoutEffect} from "@nextui-org/use-safe-layout-effect";
import {autocomplete} from "@nextui-org/theme";
import {useFilter} from "@react-aria/i18n";
@ -17,6 +18,7 @@ import {chain, mergeProps} from "@react-aria/utils";
import {ButtonProps} from "@nextui-org/button";
import {AsyncLoadable, PressEvent} from "@react-types/shared";
import {useComboBox} from "@react-aria/combobox";
import {ariaShouldCloseOnInteractOutside} from "@nextui-org/aria-utils";
interface Props<T> extends Omit<HTMLNextUIProps<"input">, keyof ComboBoxProps<T>> {
/**
@ -111,17 +113,17 @@ interface Props<T> extends Omit<HTMLNextUIProps<"input">, keyof ComboBoxProps<T>
}
export type UseAutocompleteProps<T> = Props<T> &
Omit<
InputProps,
"children" | "value" | "isClearable" | "defaultValue" | "classNames" | "validationBehavior"
> &
Omit<ComboBoxProps<T>, "validationBehavior"> &
Omit<InputProps, "children" | "value" | "isClearable" | "defaultValue" | "classNames"> &
ComboBoxProps<T> &
AsyncLoadable &
AutocompleteVariantProps;
export function useAutocomplete<T extends object>(originalProps: UseAutocompleteProps<T>) {
const globalContext = useProviderContext();
const [props, variantProps] = mapPropsVariants(originalProps, autocomplete.variantKeys);
const disableAnimation = originalProps.disableAnimation ?? false;
const disableAnimation =
originalProps.disableAnimation ?? globalContext?.disableAnimation ?? false;
// TODO: Remove disableClearable prop in the next minor release.
const isClearable =
@ -156,6 +158,7 @@ export function useAutocomplete<T extends object>(originalProps: UseAutocomplete
clearButtonProps = {},
showScrollIndicators = true,
allowsCustomValue = false,
validationBehavior = globalContext?.validationBehavior ?? "aria",
className,
classNames,
errorMessage,
@ -172,7 +175,7 @@ export function useAutocomplete<T extends object>(originalProps: UseAutocomplete
...originalProps,
children,
menuTrigger,
validationBehavior: "native",
validationBehavior,
shouldCloseOnBlur,
allowsEmptyCollection,
defaultFilter: defaultFilter && typeof defaultFilter === "function" ? defaultFilter : contains,
@ -199,6 +202,9 @@ export function useAutocomplete<T extends object>(originalProps: UseAutocomplete
const inputRef = useDOMRef<HTMLInputElement>(ref);
const scrollShadowRef = useDOMRef<HTMLElement>(scrollRefProp);
// control the input focus behaviours internally
const shouldFocus = useRef(false);
const {
buttonProps,
inputProps,
@ -208,7 +214,7 @@ export function useAutocomplete<T extends object>(originalProps: UseAutocomplete
validationErrors,
} = useComboBox(
{
validationBehavior: "native",
validationBehavior,
...originalProps,
inputRef,
buttonRef,
@ -325,12 +331,14 @@ export function useAutocomplete<T extends object>(originalProps: UseAutocomplete
}
}, [isOpen]);
// unfocus the input when the popover closes & there's no selected item & no allows custom value
// react aria has different focus strategies internally
// hence, handle focus behaviours on our side for better flexibilty
useEffect(() => {
if (!isOpen && !state.selectedItem && inputRef.current && !allowsCustomValue) {
inputRef.current.blur();
}
}, [isOpen, allowsCustomValue]);
const action = shouldFocus.current || isOpen ? "focus" : "blur";
inputRef?.current?.[action]();
if (action === "blur") shouldFocus.current = false;
}, [shouldFocus.current, isOpen]);
// to prevent the error message:
// stopPropagation is now the default behavior for events in React Spectrum.
@ -363,6 +371,7 @@ export function useAutocomplete<T extends object>(originalProps: UseAutocomplete
const onClear = useCallback(() => {
state.setInputValue("");
state.setSelectedKey(null);
state.close();
}, [state]);
const onFocus = useCallback(
@ -392,17 +401,20 @@ export function useAutocomplete<T extends object>(originalProps: UseAutocomplete
const getClearButtonProps = () =>
({
...mergeProps(buttonProps, slotsProps.clearButtonProps),
// disable original focus and state toggle from react aria
onPressStart: () => {},
onPress: (e: PressEvent) => {
slotsProps.clearButtonProps?.onPress?.(e);
if (state.selectedItem) {
onClear();
} else {
const inputFocused = inputRef.current === document.activeElement;
allowsCustomValue && state.setInputValue("");
!inputFocused && onFocus(true);
if (allowsCustomValue) {
state.setInputValue("");
state.close();
}
}
inputRef?.current?.focus();
},
"data-visible": !!state.selectedItem || state.inputValue?.length > 0,
className: slots.clearButton({
@ -416,6 +428,7 @@ export function useAutocomplete<T extends object>(originalProps: UseAutocomplete
...inputProps,
...slotsProps.inputProps,
isInvalid,
validationBehavior,
errorMessage:
typeof errorMessage === "function"
? errorMessage({isInvalid, validationErrors, validationDetails})
@ -429,18 +442,19 @@ export function useAutocomplete<T extends object>(originalProps: UseAutocomplete
ref: listBoxRef,
...mergeProps(slotsProps.listboxProps, listBoxProps, {
shouldHighlightOnFocus: true,
shouldUseVirtualFocus: false,
}),
} as ListboxProps);
const getPopoverProps = (props: DOMAttributes = {}) => {
const popoverProps = mergeProps(slotsProps.popoverProps, props);
return {
state,
ref: popoverRef,
triggerRef: inputWrapperRef,
scrollRef: listBoxRef,
triggerType: "listbox",
...mergeProps(slotsProps.popoverProps, props),
...popoverProps,
classNames: {
content: slots.popoverContent({
class: clsx(
@ -450,6 +464,10 @@ export function useAutocomplete<T extends object>(originalProps: UseAutocomplete
),
}),
},
shouldCloseOnInteractOutside: popoverProps?.shouldCloseOnInteractOutside
? popoverProps.shouldCloseOnInteractOutside
: (element: Element) =>
ariaShouldCloseOnInteractOutside(element, inputWrapperRef, state, shouldFocus),
} as unknown as PopoverProps;
};

View File

@ -2,6 +2,7 @@ import type {ValidationResult} from "@react-types/shared";
import React, {Key} from "react";
import {Meta} from "@storybook/react";
import {useForm} from "react-hook-form";
import {autocomplete, input, button} from "@nextui-org/theme";
import {
Pokemon,
@ -63,6 +64,12 @@ export default {
type: "boolean",
},
},
validationBehavior: {
control: {
type: "select",
},
options: ["aria", "native"],
},
},
decorators: [
(Story) => (
@ -686,6 +693,45 @@ const CustomStylesWithCustomItemsTemplate = ({color, ...args}: AutocompleteProps
);
};
const WithReactHookFormTemplate = (args: AutocompleteProps) => {
const {
register,
formState: {errors},
handleSubmit,
} = useForm({
defaultValues: {
withDefaultValue: "cat",
withoutDefaultValue: "",
requiredField: "",
},
});
const onSubmit = (data: any) => {
// eslint-disable-next-line no-console
console.log(data);
alert("Submitted value: " + JSON.stringify(data));
};
return (
<form className="flex w-full max-w-xs flex-col gap-2" onSubmit={handleSubmit(onSubmit)}>
<Autocomplete {...args} {...register("withDefaultValue")}>
{items}
</Autocomplete>
<Autocomplete {...args} {...register("withoutDefaultValue")}>
{items}
</Autocomplete>
<Autocomplete {...args} {...register("requiredField", {required: true})}>
{items}
</Autocomplete>
{errors.requiredField && <span className="text-danger">This field is required</span>}
<button className={button({class: "w-fit"})} type="submit">
Submit
</button>
</form>
);
};
export const Default = {
render: Template,
args: {
@ -733,15 +779,6 @@ export const DisabledOptions = {
},
};
export const WithDescription = {
render: MirrorTemplate,
args: {
...defaultProps,
description: "Select your favorite animal",
},
};
export const LabelPlacement = {
render: LabelPlacementTemplate,
@ -782,6 +819,27 @@ export const EndContent = {
},
};
export const IsInvalid = {
render: Template,
args: {
...defaultProps,
isInvalid: true,
variant: "bordered",
defaultSelectedKey: "dog",
errorMessage: "Please select a valid animal",
},
};
export const WithDescription = {
render: MirrorTemplate,
args: {
...defaultProps,
description: "Select your favorite animal",
},
};
export const WithoutScrollShadow = {
render: Template,
@ -838,53 +896,17 @@ export const WithValidation = {
args: {
...defaultProps,
isRequired: true,
label: "Select Cat or Dog",
validate: (value) => {
if (value.inputValue === "Cat" || value.selectedKey === "dog") {
return "Please select a valid animal";
if (value.selectedKey == null || value.selectedKey === "cat" || value.selectedKey === "dog") {
return;
}
return "Please select a valid animal";
},
},
};
export const IsInvalid = {
render: Template,
args: {
...defaultProps,
isInvalid: true,
variant: "bordered",
defaultSelectedKey: "dog",
errorMessage: "Please select a valid animal",
},
};
export const Controlled = {
render: ControlledTemplate,
args: {
...defaultProps,
},
};
export const CustomSelectorIcon = {
render: Template,
args: {
...defaultProps,
disableSelectorIconRotation: true,
selectorIcon: <SelectorIcon />,
},
};
export const CustomItems = {
render: CustomItemsTemplate,
args: {
...defaultProps,
},
};
export const WithSections = {
render: WithSectionsTemplate,
@ -911,6 +933,40 @@ export const WithAriaLabel = {
},
};
export const WithReactHookForm = {
render: WithReactHookFormTemplate,
args: {
...defaultProps,
},
};
export const Controlled = {
render: ControlledTemplate,
args: {
...defaultProps,
},
};
export const CustomSelectorIcon = {
render: Template,
args: {
...defaultProps,
disableSelectorIconRotation: true,
selectorIcon: <SelectorIcon />,
},
};
export const CustomItems = {
render: CustomItemsTemplate,
args: {
...defaultProps,
},
};
export const CustomStyles = {
render: CustomStylesTemplate,

View File

@ -1,5 +1,11 @@
# @nextui-org/avatar
## 2.0.28
### Patch Changes
- [#2929](https://github.com/nextui-org/nextui/pull/2929) [`422770cc6`](https://github.com/nextui-org/nextui/commit/422770cc6bcdd1d4c51257654ab718f3c19d6cb2) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - Add support for disabling the animations globally.
## 2.0.27
### Patch Changes

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/avatar",
"version": "2.0.27",
"version": "2.0.28",
"description": "The Avatar component is used to represent a user, and displays the profile picture, initials or fallback icon.",
"keywords": [
"avatar"
@ -43,9 +43,9 @@
"@nextui-org/shared-utils": "workspace:*",
"@nextui-org/react-utils": "workspace:*",
"@nextui-org/use-image": "workspace:*",
"@react-aria/interactions": "^3.21.1",
"@react-aria/focus": "^3.16.2",
"@react-aria/utils": "^3.23.2"
"@react-aria/interactions": "3.21.1",
"@react-aria/focus": "3.16.2",
"@react-aria/utils": "3.23.2"
},
"devDependencies": {
"@nextui-org/theme": "workspace:*",
@ -57,4 +57,4 @@
"react-dom": "^18.0.0"
},
"clean-package": "../../../clean-package.config.json"
}
}

View File

@ -1,7 +1,7 @@
import type {AvatarSlots, AvatarVariantProps, SlotsToClasses} from "@nextui-org/theme";
import {avatar} from "@nextui-org/theme";
import {HTMLNextUIProps, PropGetter} from "@nextui-org/system";
import {HTMLNextUIProps, PropGetter, useProviderContext} from "@nextui-org/system";
import {mergeProps} from "@react-aria/utils";
import {useDOMRef} from "@nextui-org/react-utils";
import {clsx, safeText, dataAttr} from "@nextui-org/shared-utils";
@ -96,7 +96,8 @@ interface Props extends HTMLNextUIProps<"span"> {
export type UseAvatarProps = Props &
Omit<AvatarVariantProps, "children" | "isInGroup" | "isInGridGroup">;
export function useAvatar(props: UseAvatarProps = {}) {
export function useAvatar(originalProps: UseAvatarProps = {}) {
const globalContext = useProviderContext();
const groupContext = useAvatarGroupContext();
const isInGroup = !!groupContext;
@ -124,7 +125,7 @@ export function useAvatar(props: UseAvatarProps = {}) {
className,
onError,
...otherProps
} = props;
} = originalProps;
const Component = as || "span";
@ -133,6 +134,8 @@ export function useAvatar(props: UseAvatarProps = {}) {
const {isFocusVisible, isFocused, focusProps} = useFocusRing();
const {isHovered, hoverProps} = useHover({isDisabled});
const disableAnimation =
originalProps.disableAnimation ?? globalContext?.disableAnimation ?? false;
const imageStatus = useImage({src, onError, ignoreFallback});
@ -156,9 +159,19 @@ export function useAvatar(props: UseAvatarProps = {}) {
isBordered,
isDisabled,
isInGroup,
disableAnimation,
isInGridGroup: groupContext?.isGrid ?? false,
}),
[color, radius, size, isBordered, isDisabled, isInGroup, groupContext?.isGrid],
[
color,
radius,
size,
isBordered,
isDisabled,
disableAnimation,
isInGroup,
groupContext?.isGrid,
],
);
const baseStyles = clsx(classNames?.base, className);
@ -186,11 +199,12 @@ export function useAvatar(props: UseAvatarProps = {}) {
(props = {}) => ({
ref: imgRef,
src: src,
disableAnimation,
"data-loaded": dataAttr(isImgLoaded),
className: slots.img({class: classNames?.img}),
...mergeProps(imgProps, props),
}),
[slots, isImgLoaded, imgProps, src, imgRef],
[slots, isImgLoaded, imgProps, disableAnimation, src, imgRef],
);
return {

View File

@ -1,5 +1,11 @@
# @nextui-org/badge
## 2.0.28
### Patch Changes
- [#2929](https://github.com/nextui-org/nextui/pull/2929) [`422770cc6`](https://github.com/nextui-org/nextui/commit/422770cc6bcdd1d4c51257654ab718f3c19d6cb2) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - Add support for disabling the animations globally.
## 2.0.27
### Patch Changes

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/badge",
"version": "2.0.27",
"version": "2.0.28",
"description": "Badges are used as a small numerical value or status descriptor for UI elements.",
"keywords": [
"badge"
@ -36,14 +36,15 @@
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18",
"@nextui-org/theme": ">=2.1.0"
"@nextui-org/theme": ">=2.1.0",
"@nextui-org/system": ">=2.0.0"
},
"dependencies": {
"@nextui-org/system-rsc": "workspace:*",
"@nextui-org/shared-utils": "workspace:*",
"@nextui-org/react-utils": "workspace:*"
},
"devDependencies": {
"@nextui-org/system": "workspace:*",
"@nextui-org/theme": "workspace:*",
"@nextui-org/avatar": "workspace:*",
"@nextui-org/shared-icons": "workspace:*",
@ -53,4 +54,4 @@
"react-dom": "^18.0.0"
},
"clean-package": "../../../clean-package.config.json"
}
}

View File

@ -1,4 +1,4 @@
import {forwardRef} from "@nextui-org/system-rsc";
import {forwardRef} from "@nextui-org/system";
import {UseBadgeProps, useBadge} from "./use-badge";

View File

@ -1,9 +1,9 @@
import type {BadgeSlots, BadgeVariantProps, SlotsToClasses} from "@nextui-org/theme";
import type {ReactNode} from "react";
import type {HTMLNextUIProps, PropGetter} from "@nextui-org/system-rsc";
import type {HTMLNextUIProps, PropGetter} from "@nextui-org/system";
import {badge} from "@nextui-org/theme";
import {mapPropsVariants} from "@nextui-org/system-rsc";
import {mapPropsVariants, useProviderContext} from "@nextui-org/system";
import {clsx, objectToDeps} from "@nextui-org/shared-utils";
import {ReactRef} from "@nextui-org/react-utils";
import {useMemo} from "react";
@ -45,6 +45,10 @@ interface Props extends HTMLNextUIProps<"span", "content"> {
export type UseBadgeProps = Props & BadgeVariantProps;
export function useBadge(originalProps: UseBadgeProps) {
const globalContext = useProviderContext();
const disableAnimation =
originalProps?.disableAnimation ?? globalContext?.disableAnimation ?? false;
const [props, variantProps] = mapPropsVariants(originalProps, badge.variantKeys);
const {as, children, className, content, classNames, ...otherProps} = props;
@ -87,7 +91,7 @@ export function useBadge(originalProps: UseBadgeProps) {
content,
slots,
classNames,
disableAnimation: originalProps?.disableAnimation,
disableAnimation,
isInvisible: originalProps?.isInvisible,
getBadgeProps,
};

View File

@ -4,4 +4,5 @@ export default defineConfig({
clean: true,
target: "es2019",
format: ["cjs", "esm"],
banner: {js: '"use client";'},
});

View File

@ -1,5 +1,11 @@
# @nextui-org/breadcrumbs
## 2.0.8
### Patch Changes
- [#2929](https://github.com/nextui-org/nextui/pull/2929) [`422770cc6`](https://github.com/nextui-org/nextui/commit/422770cc6bcdd1d4c51257654ab718f3c19d6cb2) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - Add support for disabling the animations globally.
## 2.0.7
### Patch Changes

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/breadcrumbs",
"version": "2.0.7",
"version": "2.0.8",
"description": "Breadcrumbs display a hierarchy of links to the current page or resource in an application.",
"keywords": [
"breadcrumbs"
@ -43,11 +43,11 @@
"@nextui-org/react-utils": "workspace:*",
"@nextui-org/shared-utils": "workspace:*",
"@nextui-org/shared-icons": "workspace:*",
"@react-aria/focus": "^3.16.2",
"@react-aria/breadcrumbs": "^3.5.11",
"@react-aria/utils": "^3.23.2",
"@react-types/breadcrumbs": "^3.7.3",
"@react-types/shared": "^3.22.1"
"@react-aria/focus": "3.16.2",
"@react-aria/breadcrumbs": "3.5.11",
"@react-aria/utils": "3.23.2",
"@react-types/breadcrumbs": "3.7.3",
"@react-types/shared": "3.22.1"
},
"devDependencies": {
"@nextui-org/theme": "workspace:*",
@ -60,4 +60,4 @@
"react-dom": "^18.0.0"
},
"clean-package": "../../../clean-package.config.json"
}
}

View File

@ -2,7 +2,12 @@ import type {BreadcrumbsVariantProps, SlotsToClasses, BreadcrumbsSlots} from "@n
import type {AriaBreadcrumbsProps} from "@react-types/breadcrumbs";
import {Children, ReactNode, Key, ReactElement} from "react";
import {HTMLNextUIProps, mapPropsVariants, PropGetter} from "@nextui-org/system";
import {
HTMLNextUIProps,
mapPropsVariants,
PropGetter,
useProviderContext,
} from "@nextui-org/system";
import {breadcrumbs} from "@nextui-org/theme";
import {filterDOMProps, pickChildren, ReactRef, useDOMRef} from "@nextui-org/react-utils";
import {mergeProps} from "@react-aria/utils";
@ -103,6 +108,11 @@ export type UseBreadcrumbsProps = Props &
>;
export function useBreadcrumbs(originalProps: UseBreadcrumbsProps) {
const globalContext = useProviderContext();
const disableAnimation =
originalProps?.disableAnimation ?? globalContext?.disableAnimation ?? false;
const [props, variantProps] = mapPropsVariants(originalProps, breadcrumbs.variantKeys);
const {
@ -117,7 +127,6 @@ export function useBreadcrumbs(originalProps: UseBreadcrumbsProps) {
itemsAfterCollapse = 2,
maxItems = 8,
hideSeparator,
disableAnimation,
renderEllipsis,
className,
classNames,

View File

@ -1,5 +1,15 @@
# @nextui-org/button
## 2.0.32
### Patch Changes
- [#2929](https://github.com/nextui-org/nextui/pull/2929) [`422770cc6`](https://github.com/nextui-org/nextui/commit/422770cc6bcdd1d4c51257654ab718f3c19d6cb2) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - Add support for disabling the animations globally.
- Updated dependencies [[`422770cc6`](https://github.com/nextui-org/nextui/commit/422770cc6bcdd1d4c51257654ab718f3c19d6cb2)]:
- @nextui-org/ripple@2.0.29
- @nextui-org/spinner@2.0.29
## 2.0.31
### Patch Changes

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/button",
"version": "2.0.31",
"version": "2.0.32",
"description": "Buttons allow users to perform actions and choose with a single tap.",
"keywords": [
"button"
@ -36,7 +36,7 @@
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18",
"framer-motion": ">=4.0.0",
"framer-motion": ">=10.17.0",
"@nextui-org/theme": ">=2.1.0",
"@nextui-org/system": ">=2.0.0"
},
@ -46,12 +46,12 @@
"@nextui-org/use-aria-button": "workspace:*",
"@nextui-org/ripple": "workspace:*",
"@nextui-org/spinner": "workspace:*",
"@react-aria/button": "^3.9.3",
"@react-aria/interactions": "^3.21.1",
"@react-aria/utils": "^3.23.2",
"@react-aria/focus": "^3.16.2",
"@react-types/shared": "^3.22.1",
"@react-types/button": "^3.9.2"
"@react-aria/button": "3.9.3",
"@react-aria/interactions": "3.21.1",
"@react-aria/utils": "3.23.2",
"@react-aria/focus": "3.16.2",
"@react-types/shared": "3.22.1",
"@react-types/button": "3.9.2"
},
"devDependencies": {
"@nextui-org/theme": "workspace:*",
@ -62,4 +62,4 @@
"react-dom": "^18.0.0"
},
"clean-package": "../../../clean-package.config.json"
}
}

View File

@ -3,7 +3,12 @@ import type {ReactRef} from "@nextui-org/react-utils";
import type {ButtonGroupVariantProps} from "@nextui-org/theme";
import {buttonGroup} from "@nextui-org/theme";
import {HTMLNextUIProps, PropGetter, mapPropsVariants} from "@nextui-org/system";
import {
HTMLNextUIProps,
PropGetter,
mapPropsVariants,
useProviderContext,
} from "@nextui-org/system";
import {useDOMRef} from "@nextui-org/react-utils";
import {useMemo, useCallback} from "react";
import {objectToDeps} from "@nextui-org/shared-utils";
@ -40,6 +45,7 @@ export type UseButtonGroupProps = Props &
>;
export function useButtonGroup(originalProps: UseButtonGroupProps) {
const globalContext = useProviderContext();
const [props, variantProps] = mapPropsVariants(originalProps, buttonGroup.variantKeys);
const {
@ -51,9 +57,9 @@ export function useButtonGroup(originalProps: UseButtonGroupProps) {
variant = "solid",
radius,
isDisabled = false,
disableAnimation = false,
disableRipple = false,
isIconOnly = false,
disableRipple = globalContext?.disableRipple ?? false,
disableAnimation = globalContext?.disableAnimation ?? false,
className,
...otherProps
} = props;

View File

@ -1,9 +1,9 @@
import type {ButtonVariantProps} from "@nextui-org/theme";
import type {AriaButtonProps} from "@nextui-org/use-aria-button";
import type {HTMLNextUIProps, PropGetter} from "@nextui-org/system";
import type {ReactNode} from "react";
import type {RippleProps} from "@nextui-org/ripple";
import {useProviderContext, type HTMLNextUIProps, type PropGetter} from "@nextui-org/system";
import {dataAttr} from "@nextui-org/shared-utils";
import {ReactRef} from "@nextui-org/react-utils";
import {MouseEventHandler, useCallback} from "react";
@ -65,6 +65,7 @@ export type UseButtonProps = Props &
export function useButton(props: UseButtonProps) {
const groupContext = useButtonGroupContext();
const globalContext = useProviderContext();
const isInGroup = !!groupContext;
const {
@ -76,16 +77,16 @@ export function useButton(props: UseButtonProps) {
autoFocus,
className,
spinner,
isLoading = false,
disableRipple: disableRippleProp = false,
fullWidth = groupContext?.fullWidth ?? false,
radius = groupContext?.radius,
size = groupContext?.size ?? "md",
color = groupContext?.color ?? "default",
variant = groupContext?.variant ?? "solid",
disableAnimation = groupContext?.disableAnimation ?? false,
radius = groupContext?.radius,
disableRipple = groupContext?.disableRipple ?? false,
disableAnimation = groupContext?.disableAnimation ?? globalContext?.disableAnimation ?? false,
isDisabled: isDisabledProp = groupContext?.isDisabled ?? false,
isIconOnly = groupContext?.isIconOnly ?? false,
isLoading = false,
spinnerPlacement = "start",
onPress,
onClick,
@ -97,6 +98,8 @@ export function useButton(props: UseButtonProps) {
const domRef = useDOMRef(ref);
const disableRipple = (disableRippleProp || globalContext?.disableRipple) ?? disableAnimation;
const {isFocusVisible, isFocused, focusProps} = useFocusRing({
autoFocus,
});

View File

@ -1,5 +1,23 @@
# @nextui-org/calendar
## 2.0.5
### Patch Changes
- [#2889](https://github.com/nextui-org/nextui/pull/2889) [`aba1716ed`](https://github.com/nextui-org/nextui/commit/aba1716edc2a85c94e6baeb4acc481f67589d002) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - Update React Aria packages
- [#3054](https://github.com/nextui-org/nextui/pull/3054) [`bf68c91b9`](https://github.com/nextui-org/nextui/commit/bf68c91b9a5be2014830859b0be2127d657ba90f) Thanks [@ShrinidhiUpadhyaya](https://github.com/ShrinidhiUpadhyaya)! - revise the inert attribute in `CalendarMonth` and `CalendarPicker`
- [#2906](https://github.com/nextui-org/nextui/pull/2906) [`c83ff382b`](https://github.com/nextui-org/nextui/commit/c83ff382b9e5deaa08ed7e64eee484cc4904704d) Thanks [@ShrinidhiUpadhyaya](https://github.com/ShrinidhiUpadhyaya)! - Fixed hiding of unavailable dates in RangeCalendar (#2890)
- [#2929](https://github.com/nextui-org/nextui/pull/2929) [`422770cc6`](https://github.com/nextui-org/nextui/commit/422770cc6bcdd1d4c51257654ab718f3c19d6cb2) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - Add support for disabling the animations globally.
- [#3014](https://github.com/nextui-org/nextui/pull/3014) [`20ba81948`](https://github.com/nextui-org/nextui/commit/20ba81948d86ccc7ea4269cceb06e04899903b0e) Thanks [@winchesHe](https://github.com/winchesHe)! - add the correct peerDep version
- Updated dependencies [[`422770cc6`](https://github.com/nextui-org/nextui/commit/422770cc6bcdd1d4c51257654ab718f3c19d6cb2)]:
- @nextui-org/button@2.0.32
- @nextui-org/framer-utils@2.0.19
## 2.0.4
### Patch Changes

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/calendar",
"version": "2.0.4",
"version": "2.0.5",
"description": "A calendar displays one or more date grids and allows users to select a single date.",
"keywords": [
"calendar"
@ -34,8 +34,8 @@
"postpack": "clean-package restore"
},
"peerDependencies": {
"@nextui-org/system": ">=2.0.0",
"@nextui-org/theme": ">=2.0.0",
"@nextui-org/system": ">=2.1.0",
"@nextui-org/theme": ">=2.2.0",
"react": ">=18",
"react-dom": ">=18"
},
@ -48,17 +48,17 @@
"@nextui-org/button": "workspace:*",
"lodash.debounce": "^4.0.8",
"@internationalized/date": "^3.5.2",
"@react-aria/calendar": "3.5.1",
"@react-aria/focus": "^3.14.3",
"@react-aria/i18n": "^3.8.4",
"@react-stately/calendar": "3.4.1",
"@react-types/button": "^3.9.0",
"@react-aria/visually-hidden": "^3.8.6",
"@react-aria/utils": "^3.21.1",
"@react-stately/utils": "^3.8.0",
"@react-types/calendar": "3.4.1",
"@react-aria/interactions": "^3.19.1",
"@react-types/shared": "3.21.0",
"@react-aria/calendar": "3.5.6",
"@react-aria/focus": "3.16.2",
"@react-aria/i18n": "3.10.2",
"@react-stately/calendar": "3.4.4",
"@react-types/button": "3.9.2",
"@react-aria/visually-hidden": "3.8.10",
"@react-aria/utils": "3.23.2",
"@react-stately/utils": "3.9.1",
"@react-types/calendar": "3.4.4",
"@react-aria/interactions": "3.21.1",
"@react-types/shared": "3.22.1",
"scroll-into-view-if-needed": "3.0.10",
"@types/lodash.debounce": "^4.0.7"
},
@ -73,4 +73,4 @@
"react-dom": "^18.0.0"
},
"clean-package": "../../../clean-package.config.json"
}
}

View File

@ -42,7 +42,7 @@ export function CalendarCell(originalProps: CalendarCellProps) {
ref,
);
const isUnavailable = state.isCellUnavailable(props.date) && !isDisabled;
const isUnavailable = state.isCellUnavailable(props.date);
const isLastSelectedBeforeDisabled =
!isDisabled && !isInvalid && state.isCellUnavailable(props.date.add({days: 1}));
const isFirstSelectedAfterDisabled =

View File

@ -40,8 +40,9 @@ export function CalendarMonth(props: CalendarMonthProps) {
className={slots?.gridBodyRow({class: classNames?.gridBodyRow})}
data-slot="grid-body-row"
// makes the browser ignore the element and its children when tabbing
// TODO: invert inert when switching to React 19 (ref: https://github.com/facebook/react/issues/17157)
// @ts-ignore
inert={isHeaderExpanded ? true : undefined}
inert={isHeaderExpanded ? "" : undefined}
>
{state
.getDatesInWeek(weekIndex, startDate)

View File

@ -66,8 +66,9 @@ export function CalendarPicker(props: CalendarPickerProps) {
})}
data-slot="picker-wrapper"
// makes the browser ignore the element and its children when tabbing
// TODO: invert inert when switching to React 19 (ref: https://github.com/facebook/react/issues/17157)
// @ts-ignore
inert={isHeaderExpanded ? true : undefined}
inert={isHeaderExpanded ? undefined : ""}
>
<div
ref={highlightRef}

View File

@ -10,7 +10,7 @@ import type {CalendarState, RangeCalendarState} from "@react-stately/calendar";
import type {RefObject, ReactNode} from "react";
import {Calendar, CalendarDate} from "@internationalized/date";
import {mapPropsVariants} from "@nextui-org/system";
import {mapPropsVariants, useProviderContext} from "@nextui-org/system";
import {useCallback, useMemo} from "react";
import {calendar} from "@nextui-org/theme";
import {useControlledState} from "@react-stately/utils";
@ -18,7 +18,6 @@ import {ReactRef, useDOMRef} from "@nextui-org/react-utils";
import {useLocale} from "@react-aria/i18n";
import {clamp, dataAttr, objectToDeps} from "@nextui-org/shared-utils";
import {mergeProps} from "@react-aria/utils";
import {useProviderContext} from "@nextui-org/system";
type NextUIBaseProps = Omit<HTMLNextUIProps<"div">, keyof AriaCalendarPropsBase | "onChange">;
@ -182,7 +181,7 @@ export type ContextType<T extends CalendarState | RangeCalendarState> = {
export function useCalendarBase(originalProps: UseCalendarBasePropsComplete) {
const [props, variantProps] = mapPropsVariants(originalProps, calendar.variantKeys);
const providerContext = useProviderContext();
const globalContext = useProviderContext();
const {
ref,
@ -199,9 +198,9 @@ export function useCalendarBase(originalProps: UseCalendarBasePropsComplete) {
isHeaderExpanded: isHeaderExpandedProp,
isHeaderDefaultExpanded,
onHeaderExpandedChange = () => {},
minValue = providerContext?.defaultDates?.minDate ?? new CalendarDate(1900, 1, 1),
maxValue = providerContext?.defaultDates?.maxDate ?? new CalendarDate(2099, 12, 31),
createCalendar: createCalendarProp = providerContext?.createCalendar ?? null,
minValue = globalContext?.defaultDates?.minDate ?? new CalendarDate(1900, 1, 1),
maxValue = globalContext?.defaultDates?.maxDate ?? new CalendarDate(2099, 12, 31),
createCalendar: createCalendarProp = globalContext?.createCalendar ?? null,
prevButtonProps: prevButtonPropsProp,
nextButtonProps: nextButtonPropsProp,
errorMessage,
@ -254,7 +253,8 @@ export function useCalendarBase(originalProps: UseCalendarBasePropsComplete) {
[objectToDeps(variantProps), showMonthAndYearPickers, isHeaderExpanded, className],
);
const disableAnimation = originalProps.disableAnimation ?? false;
const disableAnimation =
originalProps.disableAnimation ?? globalContext?.disableAnimation ?? false;
const commonButtonProps: ButtonProps = {
size: "sm",
@ -317,6 +317,7 @@ export function useCalendarBase(originalProps: UseCalendarBasePropsComplete) {
shouldFilterDOMProps,
isHeaderExpanded,
showMonthAndYearPickers,
disableAnimation,
createCalendar: createCalendarProp,
getPrevButtonProps,
getNextButtonProps,

View File

@ -39,6 +39,7 @@ export function useCalendar<T extends DateValue>({
weekdayStyle,
visibleDuration,
baseProps,
disableAnimation,
shouldFilterDOMProps,
isHeaderExpanded,
visibleMonths,
@ -73,7 +74,6 @@ export function useCalendar<T extends DateValue>({
useAriaCalendar(originalProps, state);
const baseStyles = clsx(classNames?.base, className);
const disableAnimation = originalProps.disableAnimation ?? false;
const buttonPickerProps: ButtonProps = {
...buttonPickerPropsProp,

View File

@ -39,6 +39,7 @@ export function useRangeCalendar<T extends DateValue>({
shouldFilterDOMProps,
isHeaderExpanded,
visibleMonths,
disableAnimation,
createCalendar: createCalendarProp,
baseProps,
getPrevButtonProps,
@ -70,7 +71,6 @@ export function useRangeCalendar<T extends DateValue>({
useAriaRangeCalendar(originalProps, state, domRef);
const baseStyles = clsx(classNames?.base, className);
const disableAnimation = originalProps.disableAnimation ?? false;
const getBaseCalendarProps = (props = {}): CalendarBaseProps => {
return {

View File

@ -12,7 +12,7 @@ import {
import {I18nProvider, useLocale} from "@react-aria/i18n";
import {Button, ButtonGroup} from "@nextui-org/button";
import {Radio, RadioGroup} from "@nextui-org/radio";
import {cn} from "@nextui-org/system";
import {cn} from "@nextui-org/theme";
import {Calendar, CalendarProps, DateValue} from "../src";

View File

@ -16,7 +16,7 @@ import {
import {I18nProvider, useLocale} from "@react-aria/i18n";
import {Button, ButtonGroup} from "@nextui-org/button";
import {Radio, RadioGroup} from "@nextui-org/radio";
import {cn} from "@nextui-org/system";
import {cn} from "@nextui-org/theme";
import {RangeCalendar, RangeCalendarProps} from "../src";
@ -382,7 +382,6 @@ export const InternationalCalendars = {
render: InternationalCalendarsTemplate,
args: {
...defaultProps,
showMonthAndYearPickers: true,
},
};

View File

@ -1,5 +1,14 @@
# @nextui-org/card
## 2.0.29
### Patch Changes
- [#2929](https://github.com/nextui-org/nextui/pull/2929) [`422770cc6`](https://github.com/nextui-org/nextui/commit/422770cc6bcdd1d4c51257654ab718f3c19d6cb2) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - Add support for disabling the animations globally.
- Updated dependencies [[`422770cc6`](https://github.com/nextui-org/nextui/commit/422770cc6bcdd1d4c51257654ab718f3c19d6cb2)]:
- @nextui-org/ripple@2.0.29
## 2.0.28
### Patch Changes

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/card",
"version": "2.0.28",
"version": "2.0.29",
"description": "Card is a container for text, photos, and actions in the context of a single subject.",
"keywords": [
"card"
@ -36,7 +36,7 @@
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18",
"framer-motion": ">=4.0.0",
"framer-motion": ">=10.17.0",
"@nextui-org/theme": ">=2.1.0",
"@nextui-org/system": ">=2.0.0"
},
@ -45,11 +45,11 @@
"@nextui-org/react-utils": "workspace:*",
"@nextui-org/use-aria-button": "workspace:*",
"@nextui-org/ripple": "workspace:*",
"@react-aria/focus": "^3.16.2",
"@react-aria/utils": "^3.23.2",
"@react-aria/interactions": "^3.21.1",
"@react-aria/button": "^3.9.3",
"@react-types/shared": "^3.22.1"
"@react-aria/focus": "3.16.2",
"@react-aria/utils": "3.23.2",
"@react-aria/interactions": "3.21.1",
"@react-aria/button": "3.9.3",
"@react-types/shared": "3.22.1"
},
"devDependencies": {
"@nextui-org/theme": "workspace:*",
@ -64,4 +64,4 @@
"react-dom": "^18.0.0"
},
"clean-package": "../../../clean-package.config.json"
}
}

View File

@ -9,7 +9,12 @@ import {chain, mergeProps} from "@react-aria/utils";
import {useFocusRing} from "@react-aria/focus";
import {useHover} from "@react-aria/interactions";
import {useAriaButton} from "@nextui-org/use-aria-button";
import {HTMLNextUIProps, mapPropsVariants, PropGetter} from "@nextui-org/system";
import {
HTMLNextUIProps,
mapPropsVariants,
PropGetter,
useProviderContext,
} from "@nextui-org/system";
import {clsx, dataAttr, objectToDeps} from "@nextui-org/shared-utils";
import {ReactRef, filterDOMProps} from "@nextui-org/react-utils";
import {useDOMRef} from "@nextui-org/react-utils";
@ -64,13 +69,14 @@ export type ContextType = {
};
export function useCard(originalProps: UseCardProps) {
const globalContext = useProviderContext();
const [props, variantProps] = mapPropsVariants(originalProps, card.variantKeys);
const {
ref,
as,
children,
disableRipple = false,
onClick,
onPress,
autoFocus,
@ -84,12 +90,16 @@ export function useCard(originalProps: UseCardProps) {
const Component = as || (originalProps.isPressable ? "button" : "div");
const shouldFilterDOMProps = typeof Component === "string";
const disableAnimation =
originalProps.disableAnimation ?? globalContext?.disableAnimation ?? false;
const disableRipple = originalProps.disableRipple ?? globalContext?.disableRipple ?? false;
const baseStyles = clsx(classNames?.base, className);
const {onClick: onRippleClickHandler, onClear: onClearRipple, ripples} = useRipple();
const handleClick = (e: MouseEvent<HTMLDivElement>) => {
if (!originalProps.disableAnimation && !disableRipple && domRef.current) {
if (!disableAnimation && !disableRipple && domRef.current) {
onRippleClickHandler(e);
}
};
@ -119,25 +129,26 @@ export function useCard(originalProps: UseCardProps) {
() =>
card({
...variantProps,
disableAnimation,
}),
[objectToDeps(variantProps)],
[objectToDeps(variantProps), disableAnimation],
);
const context = useMemo<ContextType>(
() => ({
isDisabled: originalProps.isDisabled,
isFooterBlurred: originalProps.isFooterBlurred,
disableAnimation: originalProps.disableAnimation,
fullWidth: originalProps.fullWidth,
slots,
classNames,
disableAnimation,
isDisabled: originalProps.isDisabled,
isFooterBlurred: originalProps.isFooterBlurred,
fullWidth: originalProps.fullWidth,
}),
[
slots,
classNames,
originalProps.isDisabled,
originalProps.isFooterBlurred,
originalProps.disableAnimation,
disableAnimation,
originalProps.fullWidth,
],
);
@ -194,9 +205,9 @@ export function useCard(originalProps: UseCardProps) {
children,
isHovered,
isPressed,
disableAnimation,
isPressable: originalProps.isPressable,
isHoverable: originalProps.isHoverable,
disableAnimation: originalProps.disableAnimation,
disableRipple,
handleClick,
isFocusVisible,

View File

@ -1,5 +1,17 @@
# @nextui-org/checkbox
## 2.1.0
### Minor Changes
- [#2987](https://github.com/nextui-org/nextui/pull/2987) [`540aa2124`](https://github.com/nextui-org/nextui/commit/540aa2124b45b65a40e73f5aea2b90405fe1fe9a) Thanks [@ryo-manba](https://github.com/ryo-manba)! - Change validationBehavior from native to aria by default, with the option to change via props.
### Patch Changes
- [#2929](https://github.com/nextui-org/nextui/pull/2929) [`422770cc6`](https://github.com/nextui-org/nextui/commit/422770cc6bcdd1d4c51257654ab718f3c19d6cb2) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - Add support for disabling the animations globally.
- [#3013](https://github.com/nextui-org/nextui/pull/3013) [`06ecd213c`](https://github.com/nextui-org/nextui/commit/06ecd213cf85db2dfaa5fc26c1fed62dcb5fbc85) Thanks [@kosmotema](https://github.com/kosmotema)! - make the VisuallyHidden `elementType` as span when the default parent element accepts only phrasing elements
## 2.0.29
### Patch Changes

View File

@ -139,11 +139,11 @@ describe("Checkbox.Group", () => {
beforeAll(() => {
user = userEvent.setup();
});
describe("validationBehavior=native (default)", () => {
describe("validationBehavior=native", () => {
it("supports group level isRequired", async () => {
let {getAllByRole, getByRole, getByTestId} = render(
<form data-testid="form">
<CheckboxGroup isRequired label="Agree to the following">
<CheckboxGroup isRequired label="Agree to the following" validationBehavior="native">
<Checkbox value="terms">Terms and conditions</Checkbox>
<Checkbox value="cookies">Cookies</Checkbox>
<Checkbox value="privacy">Privacy policy</Checkbox>
@ -181,6 +181,148 @@ describe("Checkbox.Group", () => {
expect(group).not.toHaveAttribute("aria-describedby");
});
it("supports checkbox level isRequired", async () => {
let {getAllByRole, getByRole, getByTestId} = render(
<form data-testid="form">
<CheckboxGroup label="Agree to the following" validationBehavior="native">
<Checkbox isRequired value="terms">
Terms and conditions
</Checkbox>
<Checkbox isRequired value="cookies">
Cookies
</Checkbox>
<Checkbox value="privacy">Privacy policy</Checkbox>
</CheckboxGroup>
</form>,
);
let group = getByRole("group");
expect(group).not.toHaveAttribute("aria-describedby");
let checkboxes = getAllByRole("checkbox") as HTMLInputElement[];
for (let input of checkboxes.slice(0, 2)) {
expect(input).toHaveAttribute("required");
expect(input).not.toHaveAttribute("aria-required");
expect(input.validity.valid).toBe(false);
}
expect(checkboxes[2]).not.toHaveAttribute("required");
expect(checkboxes[2]).not.toHaveAttribute("aria-required");
expect(checkboxes[2].validity.valid).toBe(true);
act(() => {
(getByTestId("form") as HTMLFormElement).checkValidity();
});
expect(group).toHaveAttribute("aria-describedby");
expect(document.getElementById(group.getAttribute("aria-describedby")!)).toHaveTextContent(
"Constraints not satisfied",
);
expect(document.activeElement).toBe(checkboxes[0]);
await user.click(checkboxes[0]);
await user.click(checkboxes[1]);
expect(checkboxes[0].validity.valid).toBe(true);
expect(checkboxes[1].validity.valid).toBe(true);
expect(group).not.toHaveAttribute("aria-describedby");
});
it("supports group level validate function", async () => {
let {getAllByRole, getByRole, getByTestId} = render(
<form data-testid="form">
<CheckboxGroup
label="Agree to the following"
validate={(v) => (v.length < 3 ? "You must accept all terms" : null)}
validationBehavior="native"
>
<Checkbox value="terms">Terms and conditions</Checkbox>
<Checkbox value="cookies">Cookies</Checkbox>
<Checkbox value="privacy">Privacy policy</Checkbox>
</CheckboxGroup>
</form>,
);
let group = getByRole("group");
expect(group).not.toHaveAttribute("aria-describedby");
let checkboxes = getAllByRole("checkbox") as HTMLInputElement[];
for (let input of checkboxes) {
expect(input).not.toHaveAttribute("required");
expect(input).not.toHaveAttribute("aria-required");
expect(input.validity.valid).toBe(false);
}
act(() => {
(getByTestId("form") as HTMLFormElement).checkValidity();
});
expect(group).toHaveAttribute("aria-describedby");
expect(document.getElementById(group.getAttribute("aria-describedby")!)).toHaveTextContent(
"You must accept all terms",
);
expect(document.activeElement).toBe(checkboxes[0]);
await user.click(checkboxes[0]);
expect(group).toHaveAttribute("aria-describedby");
for (let input of checkboxes) {
expect(input.validity.valid).toBe(false);
}
await user.click(checkboxes[1]);
expect(group).toHaveAttribute("aria-describedby");
for (let input of checkboxes) {
expect(input.validity.valid).toBe(false);
}
await user.click(checkboxes[2]);
expect(group).not.toHaveAttribute("aria-describedby");
for (let input of checkboxes) {
expect(input.validity.valid).toBe(true);
}
});
});
describe("validationBehavior=aria", () => {
it("supports group level validate function", async () => {
let {getAllByRole, getByRole} = render(
<CheckboxGroup
label="Agree to the following"
validate={(v) => (v.length < 3 ? "You must accept all terms" : null)}
validationBehavior="aria"
>
<Checkbox value="terms">Terms and conditions</Checkbox>
<Checkbox value="cookies">Cookies</Checkbox>
<Checkbox value="privacy">Privacy policy</Checkbox>
</CheckboxGroup>,
);
let group = getByRole("group");
expect(group).toHaveAttribute("aria-describedby");
expect(document.getElementById(group.getAttribute("aria-describedby")!)).toHaveTextContent(
"You must accept all terms",
);
let checkboxes = getAllByRole("checkbox") as HTMLInputElement[];
for (let input of checkboxes) {
expect(input).toHaveAttribute("aria-invalid", "true");
expect(input.validity.valid).toBe(true);
}
await user.click(checkboxes[0]);
expect(group).toHaveAttribute("aria-describedby");
await user.click(checkboxes[1]);
expect(group).toHaveAttribute("aria-describedby");
await user.click(checkboxes[2]);
expect(group).toHaveAttribute("aria-describedby");
});
});
});
});

View File

@ -1,6 +1,7 @@
import * as React from "react";
import {render, act} from "@testing-library/react";
import {render, renderHook, act} from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import {useForm} from "react-hook-form";
import {Checkbox, CheckboxProps} from "../src";
@ -89,10 +90,26 @@ describe("Checkbox", () => {
expect(onFocus).toBeCalled();
});
it('should work correctly with "isRequired" prop', () => {
const {container} = render(<Checkbox isRequired>Option</Checkbox>);
it("should have required attribute when isRequired with native validationBehavior", () => {
const {container} = render(
<Checkbox isRequired validationBehavior="native">
Option
</Checkbox>,
);
expect(container.querySelector("input")?.required).toBe(true);
expect(container.querySelector("input")).toHaveAttribute("required");
expect(container.querySelector("input")).not.toHaveAttribute("aria-required");
});
it("should have aria-required attribute when isRequired with aria validationBehavior", () => {
const {container} = render(
<Checkbox isRequired validationBehavior="aria">
Option
</Checkbox>,
);
expect(container.querySelector("input")).not.toHaveAttribute("required");
expect(container.querySelector("input")).toHaveAttribute("aria-required", "true");
});
it("should work correctly with controlled value", () => {
@ -127,4 +144,129 @@ describe("Checkbox", () => {
expect(onChange).toBeCalled();
});
describe("validation", () => {
let user;
beforeEach(() => {
user = userEvent.setup();
});
describe("validationBehavior=native", () => {
it("supports isRequired", async () => {
const {getByRole, getByTestId} = render(
<form data-testid="form">
<Checkbox isRequired validationBehavior="native">
Terms and conditions
</Checkbox>
</form>,
);
const checkbox = getByRole("checkbox") as HTMLInputElement;
expect(checkbox).toHaveAttribute("required");
expect(checkbox).not.toHaveAttribute("aria-required");
expect(checkbox.validity.valid).toBe(false);
act(() => {
(getByTestId("form") as HTMLFormElement).checkValidity();
});
await user.click(checkbox);
expect(checkbox.validity.valid).toBe(true);
});
});
describe("validationBehavior=aria", () => {
it("supports validate function", async () => {
const {getByRole} = render(
<Checkbox
validate={(v) => (!v ? "You must accept the terms." : null)}
validationBehavior="aria"
value="terms"
>
Terms and conditions
</Checkbox>,
);
const checkbox = getByRole("checkbox") as HTMLInputElement;
expect(checkbox.validity.valid).toBe(true);
await user.click(checkbox);
expect(checkbox.validity.valid).toBe(true);
});
});
});
});
describe("Checkbox with React Hook Form", () => {
let checkbox1: HTMLInputElement;
let checkbox2: HTMLInputElement;
let checkbox3: HTMLInputElement;
let submitButton: HTMLButtonElement;
let onSubmit: () => void;
beforeEach(() => {
const {result} = renderHook(() =>
useForm({
defaultValues: {
withDefaultValue: true,
withoutDefaultValue: false,
requiredField: false,
},
}),
);
const {
handleSubmit,
register,
formState: {errors},
} = result.current;
onSubmit = jest.fn();
render(
<form className="flex flex-col gap-4" onSubmit={handleSubmit(onSubmit)}>
<Checkbox {...register("withDefaultValue")} />
<Checkbox {...register("withoutDefaultValue")} />
<Checkbox {...register("requiredField", {required: true})} />
{errors.requiredField && <span className="text-danger">This field is required</span>}
<button type="submit">Submit</button>
</form>,
);
checkbox1 = document.querySelector("input[name=withDefaultValue]")!;
checkbox2 = document.querySelector("input[name=withoutDefaultValue]")!;
checkbox3 = document.querySelector("input[name=requiredField]")!;
submitButton = document.querySelector("button")!;
});
it("should work with defaultValues", () => {
expect(checkbox1.checked).toBe(true);
expect(checkbox2.checked).toBe(false);
expect(checkbox3.checked).toBe(false);
});
it("should not submit form when required field is empty", async () => {
const user = userEvent.setup();
await user.click(submitButton);
expect(onSubmit).toHaveBeenCalledTimes(0);
});
it("should submit form when required field is not empty", async () => {
act(() => {
checkbox3.click();
});
expect(checkbox3.checked).toBe(true);
const user = userEvent.setup();
await user.click(submitButton);
expect(onSubmit).toHaveBeenCalledTimes(1);
});
});

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/checkbox",
"version": "2.0.29",
"version": "2.1.0",
"description": "Checkboxes allow users to select multiple items from a list of individual items, or to mark one individual item as selected.",
"keywords": [
"checkbox"
@ -44,15 +44,15 @@
"@nextui-org/shared-utils": "workspace:*",
"@nextui-org/use-callback-ref": "workspace:*",
"@nextui-org/use-safe-layout-effect": "workspace:*",
"@react-aria/checkbox": "^3.14.1",
"@react-aria/focus": "^3.16.2",
"@react-aria/interactions": "^3.21.1",
"@react-aria/utils": "^3.23.2",
"@react-aria/visually-hidden": "^3.8.10",
"@react-stately/checkbox": "^3.6.3",
"@react-stately/toggle": "^3.7.2",
"@react-types/checkbox": "^3.7.1",
"@react-types/shared": "^3.22.1"
"@react-aria/checkbox": "3.14.1",
"@react-aria/focus": "3.16.2",
"@react-aria/interactions": "3.21.1",
"@react-aria/utils": "3.23.2",
"@react-aria/visually-hidden": "3.8.10",
"@react-stately/checkbox": "3.6.3",
"@react-stately/toggle": "3.7.2",
"@react-types/checkbox": "3.7.1",
"@react-types/shared": "3.22.1"
},
"devDependencies": {
"@nextui-org/chip": "workspace:*",
@ -67,4 +67,4 @@
"react-hook-form": "^7.51.3"
},
"clean-package": "../../../clean-package.config.json"
}
}

View File

@ -26,7 +26,7 @@ const Checkbox = forwardRef<"input", CheckboxProps>((props, ref) => {
return (
<Component {...getBaseProps()}>
<VisuallyHidden>
<VisuallyHidden elementType="span">
<input {...getInputProps()} />
</VisuallyHidden>
<span {...getWrapperProps()}>{clonedIcon}</span>

View File

@ -1,10 +1,10 @@
import type {CheckboxGroupSlots, SlotsToClasses} from "@nextui-org/theme";
import type {AriaCheckboxGroupProps} from "@react-types/checkbox";
import type {Orientation} from "@react-types/shared";
import type {HTMLNextUIProps, PropGetter} from "@nextui-org/system";
import type {ReactRef} from "@nextui-org/react-utils";
import type {CheckboxGroupProps} from "@react-types/checkbox";
import {useProviderContext, type HTMLNextUIProps, type PropGetter} from "@nextui-org/system";
import {useCallback, useMemo} from "react";
import {chain, mergeProps} from "@react-aria/utils";
import {checkboxGroup} from "@nextui-org/theme";
@ -48,7 +48,7 @@ interface Props extends HTMLNextUIProps<"div"> {
}
export type UseCheckboxGroupProps = Omit<Props, "onChange"> &
Omit<AriaCheckboxGroupProps, "validationBehavior"> &
AriaCheckboxGroupProps &
Partial<
Pick<
CheckboxProps,
@ -65,9 +65,12 @@ export type ContextType = {
lineThrough?: CheckboxProps["lineThrough"];
isDisabled?: CheckboxProps["isDisabled"];
disableAnimation?: CheckboxProps["disableAnimation"];
validationBehavior?: CheckboxProps["validationBehavior"];
};
export function useCheckboxGroup(props: UseCheckboxGroupProps) {
const globalContext = useProviderContext();
const {
as,
ref,
@ -85,7 +88,8 @@ export function useCheckboxGroup(props: UseCheckboxGroupProps) {
orientation = "vertical",
lineThrough = false,
isDisabled = false,
disableAnimation = false,
validationBehavior = globalContext?.validationBehavior ?? "aria",
disableAnimation = globalContext?.disableAnimation ?? false,
isReadOnly,
isRequired,
onValueChange,
@ -110,7 +114,7 @@ export function useCheckboxGroup(props: UseCheckboxGroupProps) {
isRequired,
isReadOnly,
orientation,
validationBehavior: "native",
validationBehavior,
isInvalid: validationState === "invalid" || isInvalidProp,
onChange: chain(props.onChange, onValueChange),
};
@ -125,6 +129,7 @@ export function useCheckboxGroup(props: UseCheckboxGroupProps) {
onValueChange,
isInvalidProp,
validationState,
validationBehavior,
otherProps["aria-label"],
otherProps,
]);
@ -136,22 +141,20 @@ export function useCheckboxGroup(props: UseCheckboxGroupProps) {
groupProps,
descriptionProps,
errorMessageProps,
isInvalid: isAriaInvalid,
validationErrors,
validationDetails,
} = useReactAriaCheckboxGroup(checkboxGroupProps, groupState);
let isInvalid = checkboxGroupProps.isInvalid || isAriaInvalid;
const context = useMemo<ContextType>(
() => ({
size,
color,
radius,
lineThrough,
isInvalid,
isInvalid: groupState.isInvalid,
isDisabled,
disableAnimation,
validationBehavior,
groupState,
}),
[
@ -161,18 +164,18 @@ export function useCheckboxGroup(props: UseCheckboxGroupProps) {
lineThrough,
isDisabled,
disableAnimation,
isInvalid,
groupState?.value,
groupState?.isDisabled,
groupState?.isReadOnly,
groupState?.isInvalid,
groupState?.isSelected,
validationBehavior,
groupState.value,
groupState.isDisabled,
groupState.isReadOnly,
groupState.isInvalid,
groupState.isSelected,
],
);
const slots = useMemo(
() => checkboxGroup({isRequired, isInvalid, disableAnimation}),
[isRequired, isInvalid, disableAnimation],
() => checkboxGroup({isRequired, isInvalid: groupState.isInvalid, disableAnimation}),
[isRequired, groupState.isInvalid, , disableAnimation],
);
const baseStyles = clsx(classNames?.base, className);
@ -233,10 +236,10 @@ export function useCheckboxGroup(props: UseCheckboxGroupProps) {
label,
context,
description,
isInvalid,
isInvalid: groupState.isInvalid,
errorMessage:
typeof errorMessage === "function"
? errorMessage({isInvalid, validationErrors, validationDetails})
? errorMessage({isInvalid: groupState.isInvalid, validationErrors, validationDetails})
: errorMessage || validationErrors?.join(" "),
getGroupProps,
getLabelProps,

View File

@ -1,7 +1,7 @@
import type {CheckboxVariantProps, CheckboxSlots, SlotsToClasses} from "@nextui-org/theme";
import type {AriaCheckboxProps} from "@react-types/checkbox";
import type {HTMLNextUIProps, PropGetter} from "@nextui-org/system";
import {useProviderContext, type HTMLNextUIProps, type PropGetter} from "@nextui-org/system";
import {ReactNode, Ref, useCallback, useId, useState} from "react";
import {useMemo, useRef} from "react";
import {useToggleState} from "@react-stately/toggle";
@ -68,10 +68,11 @@ interface Props extends Omit<HTMLNextUIProps<"input">, keyof CheckboxVariantProp
}
export type UseCheckboxProps = Omit<Props, "defaultChecked"> &
Omit<AriaCheckboxProps, keyof CheckboxVariantProps | "onChange" | "validationBehavior"> &
Omit<AriaCheckboxProps, keyof CheckboxVariantProps | "onChange"> &
CheckboxVariantProps;
export function useCheckbox(props: UseCheckboxProps = {}) {
const globalContext = useProviderContext();
const groupContext = useCheckboxGroupContext();
const isInGroup = !!groupContext;
@ -86,15 +87,16 @@ 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,
disableAnimation = groupContext?.disableAnimation ?? globalContext?.disableAnimation ?? false,
validationState,
isInvalid = validationState ? validationState === "invalid" : groupContext?.isInvalid ?? false,
isIndeterminate = false,
validationBehavior = groupContext?.validationBehavior ?? "aria",
defaultSelected,
classNames,
className,
@ -144,6 +146,7 @@ export function useCheckbox(props: UseCheckboxProps = {}) {
children,
autoFocus,
defaultSelected,
validationBehavior,
isIndeterminate,
isRequired,
isInvalid,
@ -166,6 +169,7 @@ export function useCheckbox(props: UseCheckboxProps = {}) {
isReadOnlyProp,
isSelectedProp,
defaultSelected,
validationBehavior,
otherProps["aria-label"],
otherProps["aria-labelledby"],
onValueChange,
@ -181,22 +185,9 @@ export function useCheckbox(props: UseCheckboxProps = {}) {
isPressed: isPressedKeyboard,
} = isInGroup
? // eslint-disable-next-line
useReactAriaCheckboxGroupItem(
{
...ariaCheckboxProps,
isInvalid,
validationBehavior: "native",
},
groupContext.groupState,
inputRef,
)
useReactAriaCheckboxGroupItem({...ariaCheckboxProps}, groupContext.groupState, inputRef)
: // eslint-disable-next-line
useReactAriaCheckbox(
{...ariaCheckboxProps, validationBehavior: "native"},
// eslint-disable-next-line
toggleState,
inputRef,
);
useReactAriaCheckbox({...ariaCheckboxProps}, toggleState, inputRef);
const isInteractionDisabled = isDisabled || isReadOnly;
@ -219,10 +210,6 @@ export function useCheckbox(props: UseCheckboxProps = {}) {
const pressed = isInteractionDisabled ? false : isPressed || isPressedKeyboard;
if (isRequired) {
inputProps.required = true;
}
const {hoverProps, isHovered} = useHover({
isDisabled: inputProps.disabled,
});
@ -334,9 +321,9 @@ export function useCheckbox(props: UseCheckboxProps = {}) {
const getIconProps = useCallback(
() =>
({
isSelected: isSelected,
isIndeterminate: !!isIndeterminate,
disableAnimation: !!disableAnimation,
isSelected,
isIndeterminate,
disableAnimation,
className: slots.icon({class: classNames?.icon}),
} as CheckboxIconProps),
[slots, classNames?.icon, isSelected, isIndeterminate, disableAnimation],

Some files were not shown because too many files have changed in this diff Show More