Junior Garcia 8f00708d03
v2.7.5 (#5007)
* chore: org name change (#4596)

* chore: update brand name (#4600)

* fix(calendar): function components cannot be given refs (#4614)

* docs(modal): fix small typos and add clarifying language (#4629)

* chore(deps): bump RA versions (#4611)

* chore(deps): bump RA versions

* chore(deps): bump @internationalized/date

* chore(docs): update RA versions

* chore(docs): update versions

* chore(docs): use string type

* chore(deps): update @react-types versions

* refactor(docs): undo version change since they will be removed in another PR

* feat: tailwind variants upgrade (#4386)

* feat: tailwind variants upgrade

* chore: restore npmrc

* chore: adjust pkgs

* fix: versions

* fix: lock file

* chore(changeset): update package name

* chore(deps): use fixed version

* fix(test): incorrect package name

---------

Co-authored-by: աӄա <wingkwong.code@gmail.com>

* feat: add fn win alt keys (#4638)

* feat: add new keys

* feat: add new keys

* chore: update docs & storybook as well

---------

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

* fix(use-image): load images after props change (#4523)

* fix(use-image): load image after props change

* chore(changeset): add changeset

* refactor(use-image): remove unused props

* feat(use-image): add test case

* fix(use-image): apply useCallback to load & remove status check

* chore(changeset): update package name

* feat: global labelPlacement prop (#4346)

* feat: adding the support for labelPlacement globally

* chore: reafctoring

* chore: updating the dependency

* chore(changeset): update package name

* chore: adding Marcus's suggestions

---------

Co-authored-by: աӄա <wingkwong.code@gmail.com>

* fix(form): use native as default validation behavior (#4425)

* fix(form): use native as default validation behavior

* docs(form): delete explicit validationBehavior=native

* test(form): adjusted form test validation behaviors

* chore(form): adjusted stories with forms

* chore(changeset): changed form default validation behavior to native

* chore(changeset): removed packages with only test changes

* chore(changeset): change to patch

* chore(changeset): update package name

* refactor(docs): update package name

* refactor(docs): update to heroui

---------

Co-authored-by: աӄա <wingkwong.code@gmail.com>

* feat(spinner): new spinner variants (#4555)

* refactor(spinner): add default variant

* feature(spinner): add gradient variant

* feature(spinner): add dots variant

* feature(spinner): add dots-blink variant

* feature(spinner): add spinner-bars

* chore(spinner): add variants storybook

* chore: adding variants to docs

* chore: simplyfying the styles and modifying docs

* chore: nits

* chore: updating the dots and dots-blink animation

* chore: nits

* chore: adding Marcus' suggestions

* chore: adding Marcus's suggestions

* chore: adding junior's suggestions

---------

Co-authored-by: Maharshi Alpesh <maharshialpesh@gmail.com>

* fix: rename wrapper to tab wrapper (#4636)

* fix: rename wrapper to tab wrapper

* docs: update

* docs: update

* docs: update

* fix: rename wrapper to tab wrapper

* refactor: remove feature request from issue template (#4661)

* refactor(.github): remove feature request template

* refactor(.github): add a link to redirect to discussion (feature request category)

* docs(table): include TS examples to show Selection type usage (#4793)

* fix(listbox): unexpected scrollShadow on virtualized listbox (#4784)

* fix(listbox): add scroll height & scroll top to listbox

* fix(use-data-scroll-overflow): handle scrollHeight & scrollTop in virtualization

* chore(changeset): add changeset

* refactor(theme): replace left & right by start & end to support RTL (#4782)

* fix(date-picker): deprecate dateInputClassNames (#4780)

* chore(date-picker): add missing slots comments

* fix(date-picker): remove dateInputClassNames

* fix(date-picker): use classNames instead of dateInputClassNames

* chore(docs): add missing attributes

* fix(date-picker): use classNames instead of dateInputClassNames

* feat(changeset): add changeset

* fix(docs): broken type

* refactor(navbar): remove dropdown menu width (#4757)

* refactor: remove dropdown menu width

* refactor: shorter description

* refactor: rename instances of NextUI to Hero UI (#4645)

* docs: use the correct org for `img.shields.io` license in README

* docs: update opencollective org name

* docs: use correct org name in site footer

* docs: update image urls for heroui pro sections

* docs: update laravel installation keywords in route config

* docs: add `heroui` tag to `Introducing HeroUI` blog post

* fix: use correct names in `plop/components/src` templates

* chore: add empty changeset

* fix: revert image urls back to `nextuipro.nyc3.cdn.digitaloceanspaces...`

* chore: undo footer change

* chore: update incorrect brand name

* chore(docs): nextui -> heroui

---------

Co-authored-by: աӄա <wingkwong.code@gmail.com>

* fix(input): missing clear button with file input type (#4599)

* fix(theme): sync with input theme on labelPlacement (#4597)

* fix(theme): sync with input theme on labelPlacement

* chore(select): revise width for labelPlacement

* chore(changeset): add changeset

* test(input): input interaction tests (#4579)

* test(input): user interaction tests

* test(input): missing act wrappers

---------

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

* fix(calendar): rtl navigation (#4565)

* fix(calendar): rtl navigation

* chore(changeset): fixed reverse behavior of NextButton and PrevButton in the RTL calendar

* chore(changeset): update package name

* refactor(calendar): prefer isRTL and use className in theme package instead

* chore(changeset): add theme package as well

* chore(calendar): add min theme package to 2.4.7

---------

Co-authored-by: աӄա <wingkwong.code@gmail.com>

* refactor: remove unnecessary className passing to tv and make naming consistent (#4558)

* refactor: remove unnecessary className passing to tv

* refactor(button): move styles to getButtonProps

* refactor: rename classNames to styles to keep the naming consistent

* fix: deprecation warning triggered by internal onClick  (#4557)

* fix(use-aria-link): onClick deprecation warning

* fix(use-aria-button): onClick deprecation warning

* feat(changeset): add changeset

* fix(use-aria-button): incorrect prop name

* chore(changeset): update package name

* ci: add pkg pr new (#4540)

* ci: add pkg pr new

* ci: add pkg pr new

* chore(workflow): update repo name

---------

Co-authored-by: աӄա <wingkwong.code@gmail.com>

* chore(docs): remove shouldBlockScroll prop in Tooltip page (#4539)

* fix(use-pagination): controlled page after delay (#4536)

* fix(use-pagination): add page to dependency for scrollTo

* feat(changeset): add changeset

* chore(changeset): update package name

* fix(tooltip): accessing element.ref was removed in React 19 issue (#4531)

* fix(tooltip): accessing element.ref was removed in React 19 issue

* chore(changeset): update package name

* fix: correctly dismissable default value (#4524)

* fix: correctly dismissable default value

* fix: correctly dismissable default value

* chore(changeset): update package name

---------

Co-authored-by: աӄա <wingkwong.code@gmail.com>

* fix(theme): input height in innerWrapper in Select (#4512)

* fix(select): fix input height #4321

* chore(select): changed package name in changeset to theme

* chore(select): updated changeset message

* chore(changeset): update package name

---------

Co-authored-by: աӄա <wingkwong.code@gmail.com>

* fix: inert value in next15 (#4491)

* feat: add post install

* feat: add postinstall

* feat: add postinstall

* fix: type

* fix: type

* fix: next version

* chore(changeset): update package name

---------

Co-authored-by: աӄա <wingkwong.code@gmail.com>

* refactor: remove cursor-hit in hiddenInputClasses (#4474)

* refactor: remove cursor-hit in hiddenInputClasses

* Create lazy-ants-exercise.md

* chore(changeset): update package name

---------

Co-authored-by: աӄա <wingkwong.code@gmail.com>

* feat(table): virtualization (#4285)

* feat: baseline virtualization for table

* merge branch canary

* fix: table layout

* fix: calc header height w layouteffect to offset padding

* Merge branch 'canary' into feat/eng-1633-virtualization-for-table

* chore: remove unused files and comments

* chore: add missing package

* feat: add shouldVirtualize conditional to render virtualized-table

* feat: update docs for table

* feat: use wrapper to support theme styles

* chore: add changeset

* chore(changeset): update package name

* chore(deps): pnpm-lock.yaml

* fix(table): outdated package name

* chore(changeset): add issue number

* fix(deps): keep the version consistent with other components

* fix(table): incorrect displayName

* refactor(table): use VirtualizedTemplate

* chore(deps): bump `@tanstack/react-virtua`

* chore(deps): typecheck issue

* fix(table): do not use any type

* chore: remove auto virtualization

---------

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

* feat(toast): introduce Toast component (#4437)

* feat: initial commit

* chore: adding the animation

* chore: nits

* chore: fixes and adding draft1 of stories

* chore: adding the docs draft

* chore: adding the swiping interaction for toast removal

* chore: adding the tests

* fix: improving the progress bar logix

* chore: refactoring and refining the animations

* fix: making the animations compatible with the positons

* chore: fixing the styles

* chore: modifying the animations

* chore: improving the animations

* chore: adding the decorator to the story-book

* chore: fixing the animations and positions

* fix: handle expand region on touch

* feat: adding the promises support

* chore: updating the styles

* chore: improving styles

* chore: styles correction

* fix: adding junior's suggestions

* chore: correcting styles

* fix: fixing the timer behavior

* chore: adding the spinner to the toast

* chore: full width for mobile

* chore: modifying styles

* chore: fixing the positions on smaller devices

* chore: adding story with description

* chore: adding credits for sonner

* fix: adding junior's suggestions

* chore: adding the exit animation

* fix: adding junior's suggestions

* chore: improving the swipe animations

* fix: fixing the swipe animations on touch

* chore: adding tests

* chore: adding swipe threshild and initial position variable

* fix: fixing autoclose in timeout

* chore: modifying the docs

* chore: fixing the conflict

* chore: adding marcus' suggestions

* chore: adding the bottom animations

* chore: modying docs

* chore: removing nextui references

* chore: adding info about the provider

* chore: updating the docs

* chore: versions in package.json

* chore: nits

* chore: adding junior's suggestions

* chore: nits

* fix: applying junior's suggestions

* chore: adding junior's suggestions

* chore: using domMax

* fix: adding Marcus's suggestions

* chore: add global toast props and custom close icon

* chore: adding the defaultTimout provider prop

* chore: modifying defaultTimeout

* chore: nits

* fix: adding Marcus' suggestions

* chore: fixing bg

* chore(deps): bump RA deps

* fix: fixing the color discrepancy due to the timer

* chore: moving the kapan ai to the left side

* refactor(toast): update author

* chore: nit

* chore: improvements

* chore: updating the solid variant

---------

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

* fix(docs): correct Tab usage example (#4821)

* chore(docs): add note itemHeight for virtualization (#4822)

* chore(docs): add note itemHeight for virtualization

* fix: format

* fix(docs): fix horizontal scrolling example in scroll-shadow (#4820)

* refactor: update author in package.json (#4800)

* feat(button): export PressEvent for onPress event typing   (#4819)

* fix(docs): failed to install dependencies in StackBlitz (#4639)

* chore(Docs): remove step 2 from "Using use-theme-hook" (#4797)

* fix(docs): incorrect code Modal placement (#4652)

* docs: update DatePicker example to remove "time" label as time selection is not supported in this example (#4443)

* feat(button): export PressEvent for onPress event typing

* revert unnecessary changes

* chore: format

---------

Co-authored-by: աӄա <wingkwong.code@gmail.com>
Co-authored-by: Praharsh Bhatt <30700808+praharshbhatt@users.noreply.github.com>

* fix(listbox): pass missing press events to usePress (#4812)

* fix(listbox): pass missing press events to usePress

* feat(listbox): add test case for press event

* chore(changeset): add changeset

* fix(checkbox): inherit stroke in CheckboxIcon (#4811)

* fix: `SelectItem`, `ListboxItem`, and `AutocompleteItem` not to accept `value` props (#4653)

* fix(select): `SelectItem` does not accept value props

* refactor: do not use the index as `key`

* Update .changeset/light-hairs-draw.md

* chore: remove unnecessary `value` props

* chore: update changeset

* refactor: remove unnecessary value prop

---------

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

* fix: pkg package scope (#4823)

* fix: pkg package scope

* fix: pkg package scope

* fix: pkg package scope

* fix(theme): border radius in Table when isMultiSelectable (#4808)

* fix(theme): border radius in Table when isMultiSelectable

* chore(theme): added changeset (#4807)

* chore: removing the kapa ai for toast doc page (#4833)

* fix(accordion): add data-slot attributes to accordion (#4832)

* fix(accordion): add data-slot attributes to accordion

* chore

---------

Co-authored-by: Hovannes Markarian <hovannes.markarian@socrate.fr>
Co-authored-by: աӄա <wingkwong.code@gmail.com>

* chore(docs): update versions (#4836)

* docs(themes): adding theme generator (#4626)

* chore: adding xylish's contributions + modifying styles

* chore: nextui to heroui

* chore: colors in theme generator

* chore: radiuses, disable-opacity

* chore: fixing the configuration box styles

* chore: adding the showcase elemtents

* chore: modifying styles

* chore: adding the fonts

* chore: adding the scaling

* chore: removing the calendar

* feat: adding the border-width

* chore: modifying style for mobile

* chore: modifying the styles

* chore: removing the NextUI references + small bug fix

* chore: adding coderabits reviews

* fix: borderWidth not getting applied on breadcrumbs and input

* chore: rebasing

* chore: modifying the styles

* chore: updating the styles for the smaller devices

* chore: refactoring

* chore: improvements

* chore: making the fonts workable

* chore: making the fonts workable

* chore: modifying the swatch according to the theme

* chore: adding the default selected template

* chore: modifying mobile styles

* chore: fixing the popover

* chore: nit

* fix: fixing the select styles

* chore: modifying the mobile styles

* chore: modifying the styles

* fix: adding junior's suggestions

* fix: fixing the breadcrumb

* fix: adding junior's suggestions

* feat: introduce NumberInput (#4475)

* feat(number-field): init structure

* feat(deps): add `@nextui-org/button` & `@react-types/button`

* feat(theme): export number-field

* feat(number-field): storybook init structure

* feat(number-field): add NumberFieldHorizontalStepper

* feat(number-field): add NumberFieldHorizontalStepper

* feat(theme): init number field theme

* feat(number-field): number-field draft

* refactor(number-field): revise stepper icons

* feat(shared-icons): add ChevronLeftIcon

* feat(theme): stepperButton styles

* feat(theme): number-field styles

* fix(number-field): label layout

* feat(number-field): vertical stepper wrapper

* feat(number-field): use-number-field (wip)

* feat(number-field): add data-direction

* feat(theme): center the text if it is horizontal stepper

* feat(number-field): add HorizontalStepper

* feat(number-field): add HideStepper

* chore(number-field): revise minValue & defaultValue

* feat(docs): init number field structure

* fix(theme): outside-left styles

* refactor(theme): remove labelPlacement styles

* refactor(number-field): remove labelContent logic

* refactor(number-field): remove labelPlacement args

* feat(number-field): helper text

* feat(number-field): revise number field stories

* feat(number-field): description

* refactor(number-field): revise number field stories

* feat(theme): numberFieldLabelClasses

* fix(number-field): incorrect button props

* fix(number-field): typing issue on stepper buttons

* chore(number-field): add aria-label

* refactor(number-field): merge props

* fix(number-field): pass originalProps instead

* chore(number-field): revise Required story args

* feat(number-field): add WithStepValue & WithWheelDisabled & revise stories

* chore(number-field): add label to Required

* feat(docs): number-field doc page

* fix(number-field): typing issue

* fix(number-field): test cases

* fix(number-field): user.keyboard & defaultValue

* fix(number-field): should work with defaultValues

* chore(number-field): add type: number

* chore(number-field): remove hidden related code

* fix(number-field): numeric value

* chore(changeset): add changeset

* feat(deps): add "@nextui-org/number-field" to docs

* feat(react): export `@nextui-org/number-field`

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

* feat(docs): number-field examples

* chore(number-field): use text instead

* refactor(number-field): remove unnecessary filled-within

* fix(number-field): test case

* chore(number-field): remove aria-label for stepper buttons

* feat(docs): add incrementAriaLabel & decrementAriaLabel to NumberField

* chore(number-field): reorder WithFormatOptions

* fix(deps): update number-field's peerDependencies & dependencies

* feat(number-field): hidden input for holding numeric vaule

* fix(docs): number field title

* feat(docs): add format options to number field

* chore(docs): revise number field content

* chore(number-field): add type to useDOMRef

* fix(number-field): clear button

* fix(theme): clear button styles

* refactor(theme): stepper button styles

* chore(number-field): accept stepperButton class

* fix(theme): helper wrapper padding

* feat(deps): add `@react-aria/i18n`

* fix(number-field): use locale from `@react-aria/i18n`

* fix(deps): dependency order

* fix(docs): incorrect command

* chore(docs): remove type=number

* chore(theme): add padding to stepper wrapper

* fix(number-field): avoid resetting value

* fix(number-field): storybook

* chore(docs): remove custom impl

* chore(docs): update docs code & content

* chore(number-field):  migrate to heroui

* chore(number-field): migrate to heroui

* chore(number-field): migrate to heroui

* chore: rename to number input

* fix(number-input): incorrect import

* chore(docs): rename to number input

* chore: change to number input

* refactor(number-input): change label to amount

* fix(docs): use heroui commands

* chore(changeset): update package name

* refactor(number-input): remove steps

* refactor: remove helper text

* feat(number-input): label placement

* refactor(number-input): rename stepper

* fix(theme): isClearable

* feat(docs): add label placements

* refactor(docs): update number-input content

* fix(docs): incorrect file

* feat(docs): add lablePlacement

* refactor(docs): remove labelPlacement & startContent

* refactor(docs): remove helperText

* refactor(docs): remove helperText

* refactor(docs): revise description

* feat(number-input): add data-slot for stepper-wrapper

* fix(number-input): test cases

* fix(docs): unexpected change

* refactor(number-input): update outdated info

* fix(docs): coderabbitai comments

* refactor: remove validationState

* fix(docs): typo

* chore(deps): remove unnecessary dep

* chore(deps): bump RA versions

* chore(number-input): apply latest labelPlacement change

* refactor(number-input): update author

* refactor(number-input): revise stepper wrapper alignment

* refactor(number-input): stepper button styles

* chore(number-input): add disableRipple

* fix(theme): increase stepper button click area

* fix(number-input): sync latest validationBehavior changes

* fix(number-input): pass validationBehavior to useAriaNumberInput

* chore(docs): add import react

* chore(number-input): remove HorizontalStepper story

* chore(number-input): enable ripple

* fix(number-input): remove number type

* refactor(theme): follow input clear button styles

* feat(theme): add color for stepperButton

* fix(theme): revise stepperButton size for outside & outside-left cases

* fix(number-input): typo

* chore(docs): update description for wheel

* chore(theme): change opacity when pressed

* chore(number-input): add disableRipple

* Update .changeset/witty-flies-reflect.md

* fix(theme): add hover opacity effect

---------

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

* chore(docs): revised tags in doc routes for 2.7.0 (#4777)

* chore(docs): remove last version update tags

* chore(docs): add updated tag for 2.7.0

* chore(docs): updated table

* chore(docs): update search meta

* chore(docs): update github info

* Merge branch 'canary' into docs/eng-2003

* chore(docs): update routes.json

* chore(docs): update meta info

* chore: improve theme builder

* v2.7.0

* chore: v2.7.0 combined changeset

* fix: changeset

* fix: peer deps

* feat: toast api improved

* chore: toast styles improved

* fix: toast styles

* chore: toast width style changed

* fix: changeset release

* fix: changeset peerdeps

* chore: toast styles improved

* refactor(pagination): rtl (#4843)

* refactor(pagination): rtl

* chore(changeset): add changeset

* feat: new spinner variant

* fix(docs): popover shouldBlockScroll default value (#4851)

* fix(select): select scroll content will close immediately when popover on click (#4849)

* chore(select): update select deps

* fix(select): select scroll content will close immediately when popover on click

* chore(select): add .changeset file

* chore(changeset): add issue number

---------

Co-authored-by: աӄա <wingkwong.code@gmail.com>

* feat(calendar): add firstDayOfWeek (#4852)

* feat(calendar): add firstDayOfWeek

* feat(docs): add firstDayOfWeek in Calendar docs

* feat(calendar): add firstDayOfWeek to range calendar

* feat(docs): add firstDayOfWeek to API table

* feat: add firstDayOfWeek to date picker & date range picker

* feat(docs): add firstDayOfWeek

* feat(changeset): add changeset

* feat: add firstDayOfWeek option in storybook

* feat(docs): export firstDayOfWeek

* chore(docs): update title

* chore: spinner variants updated

* feat: v2.7.0 blog

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

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

* chore: manual release

* fix(toast): fixing maxVisibleToasts, solid variant promise, promise timer (#4881)

* fix: maxVisibleToasts functionality

* chore: adding the changeset

* fix: starting the toast timer when the promise is resolved

* fix: spinner invisible in solid variants

* fix(toast): shouldShowTimeoutProgess typo (#4858)

* fix(toast): shouldShowTimeoutProgess typo

* fix(toast): shouldShowTimeoutProgess typo

* fix(select): pass form prop to hidden-select (#4854)

* fix(select): pass form prop to hidden-select

* chore(select): changeset

* fix(spinner): Attempted to call useProviderContext() from the server (#4904)

* fix(spinner): add banner in tsup.config.ts

* chore(changeset): add changeset

* chore(docs): update breaking changes in blog

* chore(docs): handled in PR4905

* fix(number-input): onChange event in number input (#4907)

* fix(number-input): onChange event in number input

* chore(number-input): remove duplicate test case

* fix(breadcrumb): broken start & end content (#4921) (#4922)

* refactor: build process (#4909)

* chore: update component description

* chore: exclude stories-utils & test-utils

* chore(utilities): remove unused info

* chore(deps): pnpm-lock.yaml

* fix: incorrect system & theme version in peerDependencies (#4901)

* fix: incorrect system & theme version in peerDependencies

* fix: incorrect system & theme version in peerDependencies

* chore(changeset): add changeset

* fix(changeset): remove `@heroui/stories-utils` and `@heroui/test-utils` from ignore list (#4939)

* fix(docs): include .npmrc in sandbox (#4951)

* fix(input): esc key to clear input value (#4892)

* chore: theme generator credits

* fix: blog date and spinner default variant

* fix: #4850
Solve Pressing ESC doesn't clear input value

* fix: #4850 code review change

* fix: undo changes in apps/docs/content/blog/v2.7.0.mdx and add a test case for my changes

* fix: run through the test cases successfully

* fix: change md content

* fix: using isClearable not clear the value

* fix: add number-input clearable esc clear

* fix: edit review problem

* fix: delete unless file

* chore(changeset): update changeset

* fix: add inputProps.onKeyDown

* fix: pressing ESC key in a read-only input not clear

---------

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

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

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

* v2.7.4

* chore(deps): bump turbo version (#4958)

* chore(deps): bump turbo version

* chore(root): update turbo.json

* fix(docs): typecheck errors

* fix(docs): typecheck errors

* fix(deps): bump react-aria versions (#4998)

* fix(deps): bump react-aria versions

* chore(changeset): add changeset

* chore(hooks): sync with RA's useButton

* fix(use-aria-button): support aria-current

* fix(docs): remove priority prop

* fix(toast): remove priority queue & animation

* fix(toast): remove deprecated logic

* fix(popover): avoid passing preventFocusOnPress to non heroui button

* fix: sync with UsePopover

* fix(popover): prevent submenus from closing on scroll

* fix(tests): test cases related to press refactoring

* fix(toast): toast should appear above overlay and adding regionProps to ToastProvider (#5001)

* fix: toast should be above the modal

* fix: renaming the loadingIcon to loadingComponent

* chore: adding changeset

* chore: fixing conflicts

* chore: adding the region props

* fix: adding Marcus' suggestions

* fix: marcus' suggestions

* Revert "fix: renaming the loadingIcon to loadingComponent"

This reverts commit 4c6bf32765542ba8fe4d862005e6f0ac75c5e49a.

* chore: adding marcus' suggestions

* fix(number-stepper): stepper button pseudo height (#4968)

* fix(progress): incorrect size in indeterminate storybook (#4967)

* fix: shouldShowTimeoutProgress typo (#4961)

* chore(workflows): update runner (#4960)

* fix: a small eye icon for password input in edge(#4927) (#4950)

* fix(progress): add RTL support to the progress component (#4911)

* fix(progress): add RTL support to the progress component (#4908)

* docs(progress): add changeset notes

* refactor: resolved code review notes

* refactor: removed unnecessary change

* refactor: undo unnecessary change

* fix: build

* fix(toast): unexpected toast animation (#5003)

* fix(deps): use RA beta toast

* chore(toast): remove non-existing wrapUpdate

* chore(changeset): add changeset

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

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

---------

Co-authored-by: աӄա <wingkwong.code@gmail.com>
Co-authored-by: millmason <jmsoper@protonmail.com>
Co-authored-by: winches <329487092@qq.com>
Co-authored-by: Maharshi Alpesh <maharshialpesh@gmail.com>
Co-authored-by: Peterl561 <76144929+Peterl561@users.noreply.github.com>
Co-authored-by: Paul Ebose <49006567+plbstl@users.noreply.github.com>
Co-authored-by: Zarin <thesharifi.maruf@gmail.com>
Co-authored-by: Shrinidhi Upadhyaya <shrinidhiupadhyaya1195@gmail.com>
Co-authored-by: Avan <layouwen@gmail.com>
Co-authored-by: Vincentius Roger Kuswara <vincentiusrkuswara@gmail.com>
Co-authored-by: Ryo Matsukawa <76232929+ryo-manba@users.noreply.github.com>
Co-authored-by: Praharsh Bhatt <30700808+praharshbhatt@users.noreply.github.com>
Co-authored-by: Adrian Szarapow <63786007+Adee1499@users.noreply.github.com>
Co-authored-by: Hova25 <75216176+Hova25@users.noreply.github.com>
Co-authored-by: Hovannes Markarian <hovannes.markarian@socrate.fr>
Co-authored-by: Tsuki <76603360+sudongyuer@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Steve Mosley <steve@starter4ten.com>
Co-authored-by: LinYongLu <88522000+linyonglu@users.noreply.github.com>
Co-authored-by: Waleed Asender <waleed.asender@mobasher.sa>
2025-03-08 16:13:01 -03:00

576 lines
17 KiB
TypeScript

import type {InputVariantProps, SlotsToClasses, InputSlots} from "@heroui/theme";
import type {AriaTextFieldOptions} from "@react-aria/textfield";
import {
HTMLHeroUIProps,
mapPropsVariants,
PropGetter,
useLabelPlacement,
useProviderContext,
} from "@heroui/system";
import {useSafeLayoutEffect} from "@heroui/use-safe-layout-effect";
import {AriaTextFieldProps} from "@react-types/textfield";
import {useFocusRing} from "@react-aria/focus";
import {input} from "@heroui/theme";
import {useDOMRef, filterDOMProps} from "@heroui/react-utils";
import {useFocusWithin, useHover, usePress} from "@react-aria/interactions";
import {clsx, dataAttr, isEmpty, objectToDeps, safeAriaLabel} from "@heroui/shared-utils";
import {useControlledState} from "@react-stately/utils";
import {useMemo, Ref, useCallback, useState} from "react";
import {chain, mergeProps} from "@react-aria/utils";
import {useTextField} from "@react-aria/textfield";
import {FormContext, useSlottedContext} from "@heroui/form";
export interface Props<T extends HTMLInputElement | HTMLTextAreaElement = HTMLInputElement>
extends Omit<HTMLHeroUIProps<"input">, keyof InputVariantProps> {
/**
* Ref to the DOM node.
*/
ref?: Ref<T>;
/**
* Ref to the container DOM node.
*/
baseRef?: Ref<HTMLDivElement>;
/**
* Ref to the input wrapper DOM node.
* This is the element that wraps the input label and the innerWrapper when the labelPlacement="inside"
* and the input has start/end content.
*/
wrapperRef?: Ref<HTMLDivElement>;
/**
* Ref to the input inner wrapper DOM node.
* This is the element that wraps the input and the start/end content when passed.
*/
innerWrapperRef?: Ref<HTMLDivElement>;
/**
* Element to be rendered in the left side of the input.
*/
startContent?: React.ReactNode;
/**
* Element to be rendered in the right side of the input.
* if you pass this prop and the `onClear` prop, the passed element
* will have the clear button props and it will be rendered instead of the
* default clear button.
*/
endContent?: React.ReactNode;
/**
* Classname or List of classes to change the classNames of the element.
* if `className` is passed, it will be added to the base slot.
*
* @example
* ```ts
* <Input classNames={{
* base:"base-classes",
* label: "label-classes",
* mainWrapper: "main-wrapper-classes",
* inputWrapper: "input-wrapper-classes",
* innerWrapper: "inner-wrapper-classes",
* input: "input-classes",
* clearButton: "clear-button-classes",
* helperWrapper: "helper-wrapper-classes",
* description: "description-classes",
* errorMessage: "error-message-classes",
* }} />
* ```
*/
classNames?: SlotsToClasses<InputSlots>;
/**
* Callback fired when the value is cleared.
* if you pass this prop, the clear button will be shown.
*/
onClear?: () => void;
/**
* React aria onChange event.
*/
onValueChange?: (value: string) => void;
}
type AutoCapitalize = AriaTextFieldOptions<"input">["autoCapitalize"];
export type UseInputProps<T extends HTMLInputElement | HTMLTextAreaElement = HTMLInputElement> =
Props<T> & Omit<AriaTextFieldProps, "onChange"> & InputVariantProps;
export function useInput<T extends HTMLInputElement | HTMLTextAreaElement = HTMLInputElement>(
originalProps: UseInputProps<T>,
) {
const globalContext = useProviderContext();
const {validationBehavior: formValidationBehavior} = useSlottedContext(FormContext) || {};
const [props, variantProps] = mapPropsVariants(originalProps, input.variantKeys);
const {
ref,
as,
type,
label,
baseRef,
wrapperRef,
description,
className,
classNames,
autoFocus,
startContent,
endContent,
onClear,
onChange,
validationState,
validationBehavior = formValidationBehavior ?? globalContext?.validationBehavior ?? "native",
innerWrapperRef: innerWrapperRefProp,
onValueChange = () => {},
...otherProps
} = props;
const handleValueChange = useCallback(
(value: string | undefined) => {
onValueChange(value ?? "");
},
[onValueChange],
);
const [isFocusWithin, setFocusWithin] = useState(false);
const Component = as || "div";
const disableAnimation =
originalProps.disableAnimation ?? globalContext?.disableAnimation ?? false;
const domRef = useDOMRef<T>(ref);
const baseDomRef = useDOMRef<HTMLDivElement>(baseRef);
const inputWrapperRef = useDOMRef<HTMLDivElement>(wrapperRef);
const innerWrapperRef = useDOMRef<HTMLDivElement>(innerWrapperRefProp);
const [inputValue, setInputValue] = useControlledState<string | undefined>(
props.value,
props.defaultValue ?? "",
handleValueChange,
);
const isFileTypeInput = type === "file";
const hasUploadedFiles = ((domRef?.current as HTMLInputElement)?.files?.length ?? 0) > 0;
const isFilledByDefault = ["date", "time", "month", "week", "range"].includes(type!);
const isFilled = !isEmpty(inputValue) || isFilledByDefault || hasUploadedFiles;
const isFilledWithin = isFilled || isFocusWithin;
const isHiddenType = type === "hidden";
const isMultiline = originalProps.isMultiline;
const baseStyles = clsx(classNames?.base, className, isFilled ? "is-filled" : "");
const handleClear = useCallback(() => {
if (isFileTypeInput) {
(domRef.current as HTMLInputElement).value = "";
} else {
setInputValue("");
}
onClear?.();
domRef.current?.focus();
}, [setInputValue, onClear, isFileTypeInput]);
// if we use `react-hook-form`, it will set the input value using the ref in register
// i.e. setting ref.current.value to something which is uncontrolled
// hence, sync the state with `ref.current.value`
useSafeLayoutEffect(() => {
if (!domRef.current) return;
setInputValue(domRef.current.value);
}, [domRef.current]);
const {
labelProps,
inputProps,
isInvalid: isAriaInvalid,
validationErrors,
validationDetails,
descriptionProps,
errorMessageProps,
} = useTextField<any>(
{
...originalProps,
validationBehavior,
autoCapitalize: originalProps.autoCapitalize as AutoCapitalize,
value: inputValue,
"aria-label": safeAriaLabel(
originalProps["aria-label"],
originalProps.label,
originalProps.placeholder,
),
inputElementType: isMultiline ? "textarea" : "input",
onChange: setInputValue,
},
domRef,
);
if (isFileTypeInput) {
// for input[type="file"], we don't need `value` and `onChange` from `useTextField`
// otherwise, the default value with empty string will block the first attempt of file upload
// hence, remove `value` and `onChange` attribute here
delete inputProps.value;
delete inputProps.onChange;
}
const {isFocusVisible, isFocused, focusProps} = useFocusRing({
autoFocus,
isTextInput: true,
});
const {isHovered, hoverProps} = useHover({isDisabled: !!originalProps?.isDisabled});
const {isHovered: isLabelHovered, hoverProps: labelHoverProps} = useHover({
isDisabled: !!originalProps?.isDisabled,
});
const {focusProps: clearFocusProps, isFocusVisible: isClearButtonFocusVisible} = useFocusRing();
const {focusWithinProps} = useFocusWithin({
onFocusWithinChange: setFocusWithin,
});
const {pressProps: clearPressProps} = usePress({
isDisabled: !!originalProps?.isDisabled || !!originalProps?.isReadOnly,
onPress: handleClear,
});
const isInvalid = validationState === "invalid" || isAriaInvalid;
const labelPlacement = useLabelPlacement({
labelPlacement: originalProps.labelPlacement,
label,
});
const errorMessage =
typeof props.errorMessage === "function"
? props.errorMessage({isInvalid, validationErrors, validationDetails})
: props.errorMessage || validationErrors?.join(" ");
const isClearable = !!onClear || originalProps.isClearable;
const hasElements = !!label || !!description || !!errorMessage;
const hasPlaceholder = !!props.placeholder;
const hasLabel = !!label;
const hasHelper = !!description || !!errorMessage;
const shouldLabelBeOutside = labelPlacement === "outside" || labelPlacement === "outside-left";
const shouldLabelBeInside = labelPlacement === "inside";
const isPlaceholderShown = domRef.current
? (!domRef.current.value || domRef.current.value === "" || !inputValue || inputValue === "") &&
hasPlaceholder
: false;
const isOutsideLeft = labelPlacement === "outside-left";
const hasStartContent = !!startContent;
const isLabelOutside = shouldLabelBeOutside
? labelPlacement === "outside-left" ||
hasPlaceholder ||
(labelPlacement === "outside" && hasStartContent)
: false;
const isLabelOutsideAsPlaceholder =
labelPlacement === "outside" && !hasPlaceholder && !hasStartContent;
const slots = useMemo(
() =>
input({
...variantProps,
isInvalid,
labelPlacement,
isClearable,
disableAnimation,
}),
[
objectToDeps(variantProps),
isInvalid,
labelPlacement,
isClearable,
hasStartContent,
disableAnimation,
],
);
const getBaseProps: PropGetter = useCallback(
(props = {}) => {
return {
ref: baseDomRef,
className: slots.base({class: baseStyles}),
"data-slot": "base",
"data-filled": dataAttr(
isFilled || hasPlaceholder || hasStartContent || isPlaceholderShown || isFileTypeInput,
),
"data-filled-within": dataAttr(
isFilledWithin ||
hasPlaceholder ||
hasStartContent ||
isPlaceholderShown ||
isFileTypeInput,
),
"data-focus-within": dataAttr(isFocusWithin),
"data-focus-visible": dataAttr(isFocusVisible),
"data-readonly": dataAttr(originalProps.isReadOnly),
"data-focus": dataAttr(isFocused),
"data-hover": dataAttr(isHovered || isLabelHovered),
"data-required": dataAttr(originalProps.isRequired),
"data-invalid": dataAttr(isInvalid),
"data-disabled": dataAttr(originalProps.isDisabled),
"data-has-elements": dataAttr(hasElements),
"data-has-helper": dataAttr(hasHelper),
"data-has-label": dataAttr(hasLabel),
"data-has-value": dataAttr(!isPlaceholderShown),
"data-hidden": dataAttr(isHiddenType),
...focusWithinProps,
...props,
};
},
[
slots,
baseStyles,
isFilled,
isFocused,
isHovered,
isLabelHovered,
isInvalid,
hasHelper,
hasLabel,
hasElements,
isPlaceholderShown,
hasStartContent,
isFocusWithin,
isFocusVisible,
isFilledWithin,
hasPlaceholder,
focusWithinProps,
isHiddenType,
originalProps.isReadOnly,
originalProps.isRequired,
originalProps.isDisabled,
],
);
const getLabelProps: PropGetter = useCallback(
(props = {}) => {
return {
"data-slot": "label",
className: slots.label({class: classNames?.label}),
...mergeProps(labelProps, labelHoverProps, props),
};
},
[slots, isLabelHovered, labelProps, classNames?.label],
);
const handleKeyDown = useCallback(
(e: React.KeyboardEvent<HTMLInputElement>) => {
if (
e.key === "Escape" &&
inputValue &&
(isClearable || onClear) &&
!originalProps.isReadOnly
) {
setInputValue("");
onClear?.();
}
},
[inputValue, setInputValue, onClear, isClearable, originalProps.isReadOnly],
);
const getInputProps: PropGetter = useCallback(
(props = {}) => {
return {
"data-slot": "input",
"data-filled": dataAttr(isFilled),
"data-filled-within": dataAttr(isFilledWithin),
"data-has-start-content": dataAttr(hasStartContent),
"data-has-end-content": dataAttr(!!endContent),
className: slots.input({
class: clsx(
classNames?.input,
isFilled ? "is-filled" : "",
isMultiline ? "pe-0" : "",
type === "password" ? "[&::-ms-reveal]:hidden" : "",
),
}),
...mergeProps(
focusProps,
inputProps,
filterDOMProps(otherProps, {
enabled: true,
labelable: true,
omitEventNames: new Set(Object.keys(inputProps)),
}),
props,
),
"aria-readonly": dataAttr(originalProps.isReadOnly),
onChange: chain(inputProps.onChange, onChange),
onKeyDown: chain(inputProps.onKeyDown, props.onKeyDown, handleKeyDown),
ref: domRef,
};
},
[
slots,
inputValue,
focusProps,
inputProps,
otherProps,
isFilled,
isFilledWithin,
hasStartContent,
endContent,
classNames?.input,
originalProps.isReadOnly,
originalProps.isRequired,
onChange,
handleKeyDown,
],
);
const getInputWrapperProps: PropGetter = useCallback(
(props = {}) => {
return {
ref: inputWrapperRef,
"data-slot": "input-wrapper",
"data-hover": dataAttr(isHovered || isLabelHovered),
"data-focus-visible": dataAttr(isFocusVisible),
"data-focus": dataAttr(isFocused),
className: slots.inputWrapper({
class: clsx(classNames?.inputWrapper, isFilled ? "is-filled" : ""),
}),
...mergeProps(props, hoverProps),
onClick: (e) => {
if (domRef.current && e.currentTarget === e.target) {
domRef.current.focus();
}
},
style: {
cursor: "text",
...props.style,
},
};
},
[
slots,
isHovered,
isLabelHovered,
isFocusVisible,
isFocused,
inputValue,
classNames?.inputWrapper,
],
);
const getInnerWrapperProps: PropGetter = useCallback(
(props = {}) => {
return {
...props,
ref: innerWrapperRef,
"data-slot": "inner-wrapper",
onClick: (e) => {
if (domRef.current && e.currentTarget === e.target) {
domRef.current.focus();
}
},
className: slots.innerWrapper({
class: clsx(classNames?.innerWrapper, props?.className),
}),
};
},
[slots, classNames?.innerWrapper],
);
const getMainWrapperProps: PropGetter = useCallback(
(props = {}) => {
return {
...props,
"data-slot": "main-wrapper",
className: slots.mainWrapper({
class: clsx(classNames?.mainWrapper, props?.className),
}),
};
},
[slots, classNames?.mainWrapper],
);
const getHelperWrapperProps: PropGetter = useCallback(
(props = {}) => {
return {
...props,
"data-slot": "helper-wrapper",
className: slots.helperWrapper({
class: clsx(classNames?.helperWrapper, props?.className),
}),
};
},
[slots, classNames?.helperWrapper],
);
const getDescriptionProps: PropGetter = useCallback(
(props = {}) => {
return {
...props,
...descriptionProps,
"data-slot": "description",
className: slots.description({class: clsx(classNames?.description, props?.className)}),
};
},
[slots, classNames?.description],
);
const getErrorMessageProps: PropGetter = useCallback(
(props = {}) => {
return {
...props,
...errorMessageProps,
"data-slot": "error-message",
className: slots.errorMessage({class: clsx(classNames?.errorMessage, props?.className)}),
};
},
[slots, errorMessageProps, classNames?.errorMessage],
);
const getClearButtonProps: PropGetter = useCallback(
(props = {}) => {
return {
...props,
type: "button",
tabIndex: -1,
disabled: originalProps.isDisabled,
"aria-label": "clear input",
"data-slot": "clear-button",
"data-focus-visible": dataAttr(isClearButtonFocusVisible),
className: slots.clearButton({
class: clsx(classNames?.clearButton, props?.className),
}),
...mergeProps(clearPressProps, clearFocusProps),
};
},
[slots, isClearButtonFocusVisible, clearPressProps, clearFocusProps, classNames?.clearButton],
);
return {
Component,
classNames,
domRef,
label,
description,
startContent,
endContent,
labelPlacement,
isClearable,
hasHelper,
hasStartContent,
isLabelOutside,
isOutsideLeft,
isLabelOutsideAsPlaceholder,
shouldLabelBeOutside,
shouldLabelBeInside,
hasPlaceholder,
isInvalid,
errorMessage,
getBaseProps,
getLabelProps,
getInputProps,
getMainWrapperProps,
getInputWrapperProps,
getInnerWrapperProps,
getHelperWrapperProps,
getDescriptionProps,
getErrorMessageProps,
getClearButtonProps,
};
}
export type UseInputReturn = ReturnType<typeof useInput>;