nextui/packages/components/input/stories/input.stories.tsx
Junior Garcia 47c6228649
v2.4.2 (#3256)
* 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>

* fix(radio): remove required attribute for Radio with validationBehavior="aria" (#3110)

* fix(theme): add missing pointer event after data loaded (#3126)

* fix(system): listbox href issue (experimental) (#3119)

* fix(system): @react-aria/utils

* feat(hooks): include routerLinkProps

* feat(changeset): add changeset

* chore(deps): bump @react-aria/utils to 3.24.1

* fix(hooks): missing arguments

* chore(deps): bump @react-types/link

* chore(link): bump @react-aria/link to 3.7.1

* chore(link): use @react-aria/link instead

* chore(changeset): revise changeset

* chore(hooks): undo use-aria-link changes

* chore(deps): undo use-aria-link changes

* chore(deps): bump `@react-aria/utils` to `3.24.1`

* chore(deps): bump `@react-types/shared`

* feat: add missing router.open parameters due to router change

* chore(changeset): add new line

* chore(deps): bump `@react-types/shared` to `3.23.1`

* fix(avatar): avoid passing `disableAnimation` prop to a DOM element (#3111)

* fix(avatar): avoid passing `disableAnimation` prop to a DOM element

* refactor(avatar): use filterDOMProps approach

* chore(avatar): remove to type import

* chore(avatar): change to shouldFilterDOMProps

* fix(docs): removed unused import & corrected prop for disabled DatePicker (#3136)

Co-authored-by: shrinidhi.upadhyaya <shrinidhi.upadhyaya@stud.uni-bamberg.de>

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

* fix(pagination): missing animation (#3144)

* fix tsup domain (#3158)

* chore(docs): remove destroyInactiveTabPanel from Tab due to merge conflict (#3155)

* fix(autocomplete): maximum update depth exceeded in autocomplete (#3175)

* chore(checkbox): avoid passing non-DOM attributes to svg  (#3199)

* chore(docs): avoid passing non-DOM attributes to svg

* chore(utilities): avoid passing non-DOM attributes to svg

* feat(changeset): add changeset

* fix(docs): fix typo in autocomplete documentation page (#3182)

* fix(select): add missing data-invalid in select and add missing data attributes in docs (#3177)

* fix(select): add missing data-invalid attribute

* chore(docs): add missing data attributes for select base

* fix(tabs): destroyInactiveTabPanel unmounts inactive tabs' content (#3164)

* fix(tabs): incorrect content in tab panel

* feat(tabs): revise destroyInactiveTabPanel test cases

* fix(select): unset form value after unselecting an item (#3157)

* fix(select): set empty string instead of undefined for unsetting value

* feat(selet): should unset form value

* fix(tabs): set tab panel id correctly (#3246)

* docs(tooltip): supplement correct style path (#3183)

* docs(tooltip): supplement correct style path

* chore(docs): move the note below import tabs

* fix(use-aria-menu): link logic in useMenuItem (#3229)

* chore(deps): bump @internationalized/date version (#3230)

* fix(input): input display with hidden type (#3174)

* fix(input): input display with hidden type

* chore(input): add isHiddenType to dependency

* refactor(input): move the styles to theme and change hidden to data attr

* feat(theme): add isHiddenType to input

* chore(changeset): include theme package

* chore(input): revise input test

* fix(theme): remove isHiddenType from variants and use data-hidden prop instead

* fix(theme): remove isHiddenType from defaultVariants

* fix(input): remove isHiddenType passing to input

* feat(date-picker): add support for DatePicker to apply styles to DateInput (#3146)

* feat(date-picker): add support for DatePicker to apply styles to DateInput

* chore: update changeset

* docs(date-picker): add dateInputClassNames props

* refactor(date): updated errorMessage story and modified to import props (#3112)

* refactor(date): updated errorMessage story and modified to import props

* docs(date): add errorMessageFunction examples

* chore: add changeset

* fix: remove unnecessary props

* fix: typo

* Update regex-validation.ts (#3123)

* Update regex-validation.ts

Fix email regex

* Update email regex input.stories.tsx

* fix(autocomplete): controlled state logic (#2969)

* fix(autocomplete): autocomplete controlled state (#2955)

* chore(autocomplete): add changeset

* Update packages/components/autocomplete/__tests__/autocomplete.test.tsx

---------

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

* fix(utilities): resolve assignRef TypeScript ref assignment issue (#3098)

* fix(utilities): resolve assignRef TypeScript ref assignment issue

* chore(changeset): revise changeset message

---------

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

* fix(table): table-column align prop (#2900)

* fix(navbar): fixed the height of navbar menu (#1805)

* fix(navbar): fixed the height of navbar menu

* fix(navbar): refactored the css of navbar

* fix(navbar): fix redundant expression

* fix(navbar): fixed unnecessary changes

* fix(navbar): adjust viewport

* fix: RA dependencies bump (#3240)

* fix(popover): popover focus issue (#3187)

* fix(popover): move useDialog to popover-content

* fix(popover): move useDialog to free-solo-popover

* refactor(popover): use const instead

* feat(changset): add changeset

* feat(popover): popover focus test

* refactor(popover): getDialogProps

* fix: interactions with popover & focus issues (#3137)

* fix(aria-utils): handle click on listbox

* fix(popover): move useDialog to popover-content

* fix(popover): move useDialog to free-solo-popover

* refactor(popover): use const instead

* feat(changset): add changeset

* feat(popover): popover focus test

* refactor(popover): getDialogProps

* chore(utilities): remove ariaShouldCloseOnInteractOutside

* chore(deps): pnpm-lock.yaml

* fix(popover): remove disableFocusManagement

* fix(modal): remove disableFocusManagement

* fix(autocomplete): remove custom focus logic and remove ariaShouldCloseOnInteractOutside

* fix(popover): rewrite shouldCloseOnInteractOutside logic

* chore(utilities): remove ariaShouldCloseOnInteractOutside

* chore(deps): bump react-aria dependencies

* chore(autocomplete): change back to focus

* feat(changeset): update changeset

* chore(docs): update type in onSelectionChange

* fix(popover): revise popover test case

* chore(deps): add @nextui-org/aria-utils

* fix(autocomplete): add ariaShouldCloseOnInteractOutside

* fix(date-picker): add ariaShouldCloseOnInteractOutside

* fix(select): add ariaShouldCloseOnInteractOutside

* chore(deps): add @nextui-org/aria-utils

* fix(dropdown): add ariaShouldCloseOnInteractOutside

* feat(utilities): rewrite ariaShouldCloseOnInteractOutside

* fix(popover): use ariaShouldCloseOnInteractOutside

* fix(autocomplete): add back shouldFocus

* fix(utilities): include shouldFocus logic

* chore(utilities): remove !

* refactor(aria-utils): add more comments

* chore(changeset): update packages

* refactor(aria-utils): add more comments

* feat(popover): add test

* fix: dropdown onPress issue (#3211)

* fix(popover): move useDialog to popover-content

* fix(popover): move useDialog to free-solo-popover

* refactor(popover): use const instead

* feat(changset): add changeset

* feat(popover): popover focus test

* refactor(popover): getDialogProps

* fix(popover): dropdown onPress blocking issue

* fix(dropdown): incorrect keyCodes

* feat(dropdown): add keyboard onPress test cases

* chore(deps): keep all @react-aria/overlays version consistent

* chore(deps): sync dependencies

* chore(deps): sync dependencies

* refactor(aria-utils): remove shouldFocus logic

* refactor(autocomplete): remove shouldFocus logic and set input focus when open

* chore(deps): bump dependencies

* chore(deps): fix react aria dependencies

* fix(autocomplete): move popover style width inside isOpen true block

* fix(autocomplete): focus back to trigger

* feat(changeset): add changeset

* chore(deps): bump react-aria dependencies

* refactor(autocomplete): revise comment

* refactor(dropdown): revise logSpy and trigger mockRestore

* refactor(popover): remove debug className

* fix(date-input): avoid setting isInvalid in useDateFieldState

* fix(autocomplete): use ComboBoxValidationValue

* feat(use-aria-menu): add deprecate message

* feat(changeset): add missing packages

* refactor(use-aria-menu): remove isLink since it is included in useLinkProps

* Update packages/hooks/use-aria-menu/src/use-menu-item.ts

---------

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

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

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>
Co-authored-by: EGOIST <0x142857@gmail.com>
Co-authored-by: Damien Leroy <10438692+ShiiFu@users.noreply.github.com>
Co-authored-by: Christian Abele <manufaktur@christian-abele.de>
Co-authored-by: Nozomi Hijikata <121233810+nozomemein@users.noreply.github.com>
2024-06-15 12:57:09 -03:00

756 lines
18 KiB
TypeScript

/* eslint-disable jsx-a11y/interactive-supports-focus */
/* eslint-disable jsx-a11y/click-events-have-key-events */
import type {ValidationResult} from "@react-types/shared";
import React from "react";
import {Meta} from "@storybook/react";
import {input} from "@nextui-org/theme";
import {
MailFilledIcon,
EyeFilledIcon,
EyeSlashFilledIcon,
SearchIcon,
CloseFilledIcon,
} from "@nextui-org/shared-icons";
import {button} from "@nextui-org/theme";
import {useForm} from "react-hook-form";
import {Input, InputProps, useInput} from "../src";
export default {
title: "Components/Input",
component: Input,
argTypes: {
variant: {
control: {
type: "select",
},
options: ["flat", "faded", "bordered", "underlined"],
},
color: {
control: {
type: "select",
},
options: ["default", "primary", "secondary", "success", "warning", "danger"],
},
radius: {
control: {
type: "select",
},
options: ["none", "sm", "md", "lg", "full"],
},
size: {
control: {
type: "select",
},
options: ["sm", "md", "lg"],
},
labelPlacement: {
control: {
type: "select",
},
options: ["inside", "outside", "outside-left"],
},
isDisabled: {
control: {
type: "boolean",
},
},
validationBehavior: {
control: {
type: "select",
},
options: ["aria", "native"],
},
},
decorators: [
(Story) => (
<div className="flex items-center justify-center w-screen h-screen">
<Story />
</div>
),
],
} as Meta<typeof Input>;
const defaultProps = {
...input.defaultVariants,
label: "Email",
};
const Template = (args) => (
<div className="w-full max-w-[240px]">
<Input {...args} />
</div>
);
const MirrorTemplate = (args) => (
<div className="w-full max-w-xl flex flex-row items-end gap-4">
<Input {...args} />
<Input {...args} placeholder="Enter your email" />
</div>
);
const FormTemplate = (args) => (
<form
className="w-full max-w-xl flex flex-row items-end gap-4"
onSubmit={(e) => {
alert(`Submitted value: ${e.target["example"].value}`);
e.preventDefault();
}}
>
<Input {...args} name="example" />
<button className={button({color: "primary"})} type="submit">
Submit
</button>
</form>
);
const PasswordTemplate = (args) => {
const [isPasswordVisible, setIsPasswordVisible] = React.useState(false);
const togglePasswordVisibility = () => setIsPasswordVisible(!isPasswordVisible);
return (
<div className="w-full max-w-[240px]">
<Input
{...args}
endContent={
<button
aria-label="show password"
aria-pressed={isPasswordVisible}
type="button"
onClick={togglePasswordVisibility}
>
{isPasswordVisible ? (
<EyeSlashFilledIcon className="text-2xl text-default-400 pointer-events-none" />
) : (
<EyeFilledIcon className="text-2xl text-default-400 pointer-events-none" />
)}
</button>
}
type={isPasswordVisible ? "text" : "password"}
/>
</div>
);
};
const RegexValidationTemplate = (args) => {
const [value, setValue] = React.useState("");
const validateEmail = (value) => value.match(/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i);
const validationState = React.useMemo(() => {
if (value === "") return undefined;
return validateEmail(value) ? "valid" : "invalid";
}, [value]);
return (
<div className="w-full max-w-[240px]">
<Input
{...args}
errorMessage={validationState === "invalid" && "Please enter a valid email"}
placeholder="Enter your email"
validationState={validationState}
value={value}
onValueChange={setValue}
/>
</div>
);
};
const ControlledTemplate = (args) => {
const [value, setValue] = React.useState("");
return (
<div className="w-full flex flex-col gap-2 max-w-[240px]">
<Input {...args} placeholder="Enter your email" value={value} onValueChange={setValue} />
<p className="text-default-500 text-sm">Input value: {value}</p>
</div>
);
};
const LabelPlacementTemplate = (args) => (
<div className="w-full flex flex-col items-center gap-12">
<div className="flex flex-col gap-3">
<h3>Without placeholder</h3>
<div className="w-full max-w-xl flex flex-row items-end gap-4">
<Input {...args} description="inside" />
<Input {...args} description="outside" labelPlacement="outside" />
<Input {...args} description="outside-left" labelPlacement="outside-left" />
</div>
</div>
<div className="flex flex-col gap-3">
<h3>With placeholder</h3>
<div className="w-full max-w-xl flex flex-row items-end gap-4">
<Input {...args} description="inside" placeholder="Enter your email" />
<Input
{...args}
description="outside"
labelPlacement="outside"
placeholder="Enter your email"
/>
<Input
{...args}
description="outside-left"
labelPlacement="outside-left"
placeholder="Enter your email"
/>
</div>
</div>
</div>
);
const StartContentTemplate = (args) => (
<div className="w-full max-w-xl flex flex-row items-end gap-4">
<Input
{...args}
// placeholder="you@example.com"
startContent={
<MailFilledIcon className="text-2xl text-default-400 pointer-events-none flex-shrink-0" />
}
/>
<Input
{...args}
label="Price"
placeholder="0.00"
startContent={
<div className="pointer-events-none flex items-center">
<span className="text-default-400 text-sm">$</span>
</div>
}
type="number"
/>
<Input
{...args}
label="Website"
placeholder="nextui.org"
startContent={
<div className="pointer-events-none flex items-center">
<span className="text-default-400 text-sm">https://</span>
</div>
}
type="url"
/>
</div>
);
const EndContentTemplate = (args) => (
<div className="w-full max-w-xl flex flex-row items-end gap-4">
<Input
{...args}
endContent={
<MailFilledIcon className="text-2xl text-default-400 pointer-events-none flex-shrink-0" />
}
placeholder="you@example.com"
/>
<Input
{...args}
endContent={
<div className="pointer-events-none flex items-center">
<span className="text-default-400 text-sm">$</span>
</div>
}
label="Price"
placeholder="0.00"
type="number"
/>
<Input
{...args}
endContent={
<div className="pointer-events-none flex items-center">
<span className="text-default-400 text-sm">.org/</span>
</div>
}
label="Website"
placeholder="nextui"
type="url"
/>
</div>
);
const StartAndEndContentTemplate = (args) => (
<div className="w-full max-w-xs flex flex-col items-end gap-4">
<Input
{...args}
endContent={
<div className="pointer-events-none flex items-center">
<span className="text-default-400 text-sm">@gmail.com</span>
</div>
}
placeholder="nextui"
startContent={
<MailFilledIcon className="text-xl text-default-400 pointer-events-none flex-shrink-0" />
}
/>
<Input
{...args}
endContent={
<div className="flex items-center">
<label className="sr-only" htmlFor="currency">
Currency
</label>
<select
className="outline-none border-0 bg-transparent text-default-400 text-sm"
id="currency"
name="currency"
>
<option>USD</option>
<option>ARS</option>
<option>EUR</option>
</select>
</div>
}
label="Price"
placeholder="0.00"
startContent={
<div className="pointer-events-none flex items-center">
<span className="text-default-400 text-sm">$</span>
</div>
}
type="number"
/>
<Input
{...args}
endContent={
<div className="pointer-events-none flex items-center">
<span className="text-default-400 text-sm">.org</span>
</div>
}
label="Website"
placeholder="nextui"
startContent={
<div className="pointer-events-none flex items-center">
<span className="text-default-400 text-sm">https://</span>
</div>
}
type="url"
/>
</div>
);
const InputTypesTemplate = (args) => (
<div className="grid grid-cols-3 gap-4">
<Input {...args} label="Text" placeholder="Enter your text" />
<Input {...args} label="Number" placeholder="Enter your number" type="number" />
<Input {...args} label="Password" placeholder="Enter your password" type="password" />
<Input {...args} label="Email" placeholder="Enter your email" type="email" />
<Input {...args} label="URL" placeholder="Enter your url" type="url" />
<Input {...args} label="Search" placeholder="Enter your search" type="search" />
<Input {...args} label="Tel" placeholder="Enter your phone" type="tel" />
<Input {...args} label="Date" placeholder="Enter your date" type="date" />
<Input {...args} label="Time" placeholder="Enter your time" type="time" />
<Input {...args} label="Month" placeholder="Enter your month" type="month" />
<Input {...args} label="Week" placeholder="Enter your week" type="week" />
<Input {...args} label="Range" placeholder="Enter your range" type="range" />
</div>
);
const CustomWithClassNamesTemplate = (args) => (
<div className="w-full max-w-[340px]">
<Input
{...args}
classNames={{
label: "hidden",
inputWrapper: [
"bg-slate-100",
"border",
"shadow",
"hover:bg-slate-200",
"focus-within:!bg-slate-100",
"dark:bg-slate-900",
"dark:hover:bg-slate-800",
"dark:border-slate-800",
"dark:focus-within:!bg-slate-900",
],
innerWrapper: "gap-3",
input: [
"text-base",
"text-slate-500",
"placeholder:text-slate-500",
"dark:text-slate-400",
"dark:placeholder:text-slate-400",
],
}}
endContent={
<div className="pointer-events-none flex items-center">
<kbd className="font-sans font-semibold text-slate-400">
<abbr className="no-underline" title="Command">
</abbr>
&nbsp;K
</kbd>
</div>
}
labelPlacement="outside"
placeholder="Quick search..."
startContent={
<SearchIcon className="text-xl text-slate-400 pointer-events-none flex-shrink-0" />
}
/>
</div>
);
const CustomWithHooksTemplate = (args: InputProps) => {
const {
Component,
label,
domRef,
description,
isClearable,
startContent,
endContent,
shouldLabelBeOutside,
shouldLabelBeInside,
errorMessage,
getBaseProps,
getLabelProps,
getInputProps,
getInnerWrapperProps,
getInputWrapperProps,
getDescriptionProps,
getErrorMessageProps,
getClearButtonProps,
} = useInput({
...args,
classNames: {
label: "text-black/50 dark:text-white/90",
input: [
"bg-transparent",
"text-black/90 dark:text-white/90",
"placeholder:text-default-700/50 dark:placeholder:text-white/60",
],
innerWrapper: "bg-transparent",
inputWrapper: [
"shadow-xl",
"bg-default-200/50",
"dark:bg-default/60",
"backdrop-blur-xl",
"backdrop-saturate-200",
"hover:bg-default-200/70",
"focus-within:!bg-default-200/50",
"dark:hover:bg-default/70",
"dark:focus-within:!bg-default/60",
"!cursor-text",
],
},
});
const labelContent = <label {...getLabelProps()}>{label}</label>;
const end = React.useMemo(() => {
if (isClearable) {
return <span {...getClearButtonProps()}>{endContent || <CloseFilledIcon />}</span>;
}
return endContent;
}, [isClearable, getClearButtonProps]);
const innerWrapper = React.useMemo(() => {
if (startContent || end) {
return (
<div {...getInnerWrapperProps()}>
{startContent}
<input {...getInputProps()} />
{end}
</div>
);
}
return <input {...getInputProps()} />;
}, [startContent, end, getInputProps, getInnerWrapperProps]);
return (
<div className="w-[340px] h-[300px] px-8 rounded-2xl flex justify-center items-center bg-gradient-to-tr from-pink-500 to-yellow-500 text-white shadow-lg">
<Component {...getBaseProps()}>
{shouldLabelBeOutside ? labelContent : null}
<div
{...getInputWrapperProps()}
role="button"
onClick={() => {
domRef.current?.focus();
}}
>
{shouldLabelBeInside ? labelContent : null}
{innerWrapper}
</div>
{description && <div {...getDescriptionProps()}>{description}</div>}
{errorMessage && <div {...getErrorMessageProps()}>{errorMessage}</div>}
</Component>
</div>
);
};
const WithReactHookFormTemplate = (args: InputProps) => {
const {
register,
formState: {errors},
handleSubmit,
} = useForm({
defaultValues: {
withDefaultValue: "wkw",
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 flex-col gap-4" onSubmit={handleSubmit(onSubmit)}>
<Input isClearable label="With default value" {...register("withDefaultValue")} />
<Input {...args} label="Without default value" {...register("withoutDefaultValue")} />
<Input {...args} label="Required" {...register("requiredField", {required: true})} />
{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: MirrorTemplate,
args: {
...defaultProps,
},
};
export const Required = {
render: FormTemplate,
args: {
...defaultProps,
isRequired: true,
},
};
export const Disabled = {
render: Template,
args: {
...defaultProps,
defaultValue: "junior@nextui.org",
variant: "faded",
isDisabled: true,
},
};
export const ReadOnly = {
render: Template,
args: {
...defaultProps,
defaultValue: "junior@nextui.org",
variant: "bordered",
isReadOnly: true,
},
};
export const WithoutLabel = {
render: Template,
args: {
...defaultProps,
label: null,
"aria-label": "Email",
placeholder: "Enter your email",
},
};
export const WithDescription = {
render: MirrorTemplate,
args: {
...defaultProps,
description: "We'll never share your email with anyone else.",
},
};
export const Password = {
render: PasswordTemplate,
args: {
...defaultProps,
label: "Password",
placeholder: "Enter your password",
variant: "bordered",
},
};
export const LabelPlacement = {
render: LabelPlacementTemplate,
args: {
...defaultProps,
},
};
export const Clearable = {
render: Template,
args: {
...defaultProps,
variant: "bordered",
placeholder: "Enter your email",
defaultValue: "junior@nextui.org",
// eslint-disable-next-line no-console
onClear: () => console.log("input cleared"),
},
};
export const StartContent = {
render: StartContentTemplate,
args: {
...defaultProps,
labelPlacement: "outside",
},
};
export const EndContent = {
render: EndContentTemplate,
args: {
...defaultProps,
variant: "bordered",
labelPlacement: "outside",
},
};
export const StartAndEndContent = {
render: StartAndEndContentTemplate,
args: {
...defaultProps,
variant: "bordered",
labelPlacement: "outside",
},
};
export const WithErrorMessage = {
render: Template,
args: {
...defaultProps,
isInvalid: true,
errorMessage: "Please enter a valid email address",
},
};
export const WithErrorMessageFunction = {
render: FormTemplate,
args: {
...defaultProps,
min: "0",
max: "100",
type: "number",
isRequired: true,
label: "Number",
placeholder: "Enter a number(0-100)",
errorMessage: (value: ValidationResult) => {
if (value.validationDetails.rangeOverflow) {
return "Value is too high";
}
if (value.validationDetails.rangeUnderflow) {
return "Value is too low";
}
if (value.validationDetails.valueMissing) {
return "Value is required";
}
},
},
};
export const WithValidation = {
render: FormTemplate,
args: {
...defaultProps,
type: "number",
validate: (value) => {
if (value < 0 || value > 100) {
return "Value must be between 0 and 100";
}
},
isRequired: true,
label: "Number",
placeholder: "Enter a number(0-100)",
},
};
export const IsInvalid = {
render: Template,
args: {
...defaultProps,
variant: "bordered",
isInvalid: true,
defaultValue: "invalid@email.com",
placeholder: "Enter your email",
errorMessage: "Please enter a valid email address",
},
};
export const RegexValidation = {
render: RegexValidationTemplate,
args: {
...defaultProps,
variant: "faded",
},
};
export const InputTypes = {
render: InputTypesTemplate,
args: {
...defaultProps,
},
};
export const Controlled = {
render: ControlledTemplate,
args: {
...defaultProps,
variant: "bordered",
},
};
export const CustomWithClassNames = {
render: CustomWithClassNamesTemplate,
args: {
...defaultProps,
},
};
export const CustomWithHooks = {
render: CustomWithHooksTemplate,
args: {
...defaultProps,
label: "Search",
type: "search",
placeholder: "Type to search...",
startContent: (
<SearchIcon className="text-black/50 mb-0.5 dark:text-white/90 text-slate-400 pointer-events-none flex-shrink-0" />
),
},
};
export const WithReactHookForm = {
render: WithReactHookFormTemplate,
args: {
...defaultProps,
},
};