Compare commits

...

107 Commits

Author SHA1 Message Date
WK Wong 15a4d783bf chore: release v2.8.11
Release / Publish (push) Has been cancelled
2026-06-19 16:24:22 +08:00
WK Wong 8ab40003aa refactor(workflows): avoid full build 2026-06-19 16:12:46 +08:00
WK Wong 17a3f16992 feat(workflows): add release.yml 2026-06-19 16:03:15 +08:00
WK Wong 34d44335cd fix: build issues 2026-06-19 14:11:16 +08:00
WK Wong 8b010373f2 chore(docs): update meta info 2026-06-19 13:40:08 +08:00
WK 2ccc89ed1c chore(deps): react aria upgrade (v1.19.0) (#6659) 2026-06-19 13:35:45 +08:00
WK 3c7231a837 chore(deps): bump react-aria dependencies (v2) (#6438)
* chore(deps): bump react-aria dependencies

* chore(deps): bump react-aria dependencies
2026-06-18 17:33:02 +08:00
WK e7cf794f31 chore(docs): update site url (#6439)
* chore(docs): update site url

* chore(docs): update SITE_URL

* chore(docs): update site url

* chore(docs): update site url
2026-04-17 15:06:57 +08:00
WK e0649e12bc refactor(release): replace changesets with bumpp (#6365) 2026-03-29 06:37:02 -07:00
Junior 62ea97055b chore(docs): update deprecation message to recommend v3
Replace deprecation notice with a friendlier message announcing v3
and noting that v2 will continue to receive patches and critical fixes.

Made-with: Cursor
2026-03-22 18:09:10 -03:00
Junior 9f74710ae5 chore: remove pro banners 2026-03-21 10:17:29 -03:00
WK c2252c2bd4 fix: remove duplicate DOM props from base wrapper element (#6316)
* fix(menu): remove duplicate DOM props from base wrapper element

* fix(listbox): remove duplicate DOM props from base wrapper element

* chore(changeset): add changeset
2026-03-16 21:45:28 +08:00
Junior Garcia 46e1f1f78e Merge pull request #6296 from heroui-inc/canary 2026-03-13 00:32:30 -03:00
WK bd476eec11 chore(docs): remove roadmap link (#6308) 2026-03-13 00:31:02 -03:00
github-actions[bot] 29f5837def ci(changesets): version packages (#6288)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2026-03-07 23:53:23 +08:00
WK 499cae095d fix(docs): broken example in autocomplete (#6292) 2026-03-07 23:47:56 +08:00
paksi 7175182244 fix(docs): typo in AutocompleteItem (#6247) 2026-03-07 22:35:05 +08:00
WK 7437888182 chore(deps): bump react-aria versions (release v1.16.0) (#6281)
* chore(deps): bump react-aria versions (release v1.16.0)

* fix(autocomplete): deprecate usage

* refactor(autocomplete): update examples with new prop changes

* chore(docs): update examples

* chore(docs): update props

* chore: add changeset

* chore(select): remove unused dependency
2026-03-07 00:06:53 +08:00
Deepansh Bhargava 2db2ac726a fix(select): scroll to selected item when reopening dropdown (#6269)
* fix: select default opening position

* chore(select): do not set focus key

---------

Co-authored-by: WK Wong <wingkwong.code@gmail.com>
2026-03-06 20:51:39 +08:00
WK 66d29cff0f fix(use-draggable): persist transform position across renders (#6287) 2026-03-06 17:17:12 +08:00
WK Wong 87fe3819e6 feat(docs): include v3 link in version dropdown 2026-02-21 20:00:28 -08:00
Junior b88758a76f Merge branch 'main' of github.com:heroui-inc/heroui into canary 2026-02-18 09:22:54 -03:00
WK 3adfef7466 v2.8.9 (#6228)
* fix(theme): hide password reveal button (#5990)

* fix(link): link overriding role (#5999)

* fix(link): allow overriding role

* chore(link): changeset

* chore(deps): upgrade react-aria (v1.14.0) (#5996)

* chore(deps): upgrade react-aria (v1.14.0)

* refactor(react): group client components

* fix(dropdown): keyDown test cases

* chore(react): rollback

* fix(theme): default transition-duration (#6011)

* fix(theme): default transitionDuration

* chore(deps): bump @heroui/theme peer dep

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

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

* fix(use-image): resolve race condition with cached images on Firefox/Safari (#6041)

* fix(use-image): resolve race condition with cached images on Firefox/Safari

The bug occurred because event handlers (onload/onerror) were attached
AFTER setting the image src. For cached images, browsers fire onload
synchronously when src is set, causing the event to be missed and
images to remain stuck at opacity-0.

Changes:
- Attach handlers BEFORE setting src to catch synchronous callbacks
- Check both naturalWidth AND naturalHeight (per CodeRabbit review on #4523)
- Handle synchronous error callbacks for failed cached images
- Add comprehensive test coverage (15 tests) including:
  - Synchronous cached image success (Firefox/Safari race condition)
  - Synchronous cached image error
  - Dynamic src changes
  - All props (crossOrigin, srcSet, sizes, loading)
  - Callback invocation verification

Reproduction and investigation performed using Claude Opus 4.5.

Fixes #4534, #2259

* fix(use-image): add ignoreFallback to useCallback dependencies

Address CodeRabbit review feedback: the `ignoreFallback` prop was used
inside the `load` callback (line 104) but was missing from the dependency
array, creating a stale closure bug.

Without this fix, if `ignoreFallback` changes from `true` to `false`
dynamically, the `load` callback would retain the stale `true` value,
preventing the image from ever loading.

Changes:
- Add `ignoreFallback` to useCallback dependency array
- Add tests for dynamic `ignoreFallback` changes (both directions)
- Update changeset to document this fix

Verification performed using Claude Opus 4.5.

---------

Co-authored-by: Brian Meek <brian@current.space>

* fix(docs): broken links in Form page (#6077)

* fix(pagination): improve layout for large page counts (#6034)

* fix(pagination): improve layout for large page counts/style of paagination compnents

* fix(pagination): refine item sizing to balance small and large page numbers

* ci(changesets): add pagination sizing changeset

* fix(pagination): ensure cursor fully covers button without changing radius

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

---------

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

* fix(date-picker): open date-picker when clicking border (#6084)

* fix(date-picker): add pointer interaction to open date picker on wrapper click

* chore: add changeset

* chore(changeset): add issue number

---------

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

* fix(accordion): click behaviour for dynamically generated accordion items (#6133)

* fix(accordion): add collection state

* chore: add changeset

* fix: update change set

* refactor(theme): remove flat dependency (#6157)

* chore(deps): remove flat library

* refactor(theme): replace flatten from flat

* chore: add changeset

* fix(listbox): prevent option focus from start/end content slots (#6060)

* fix(listbox): prevent option focus from start/end content slots

* test: add test code about when clicking
non-interactive slot content, and prevented focus leakage from interactive
start/end content such as buttons.

* docs: add changeset

* chore(changeset): add issue number

---------

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

* fix(system-rsc): extendVariants & compound variants types (#5847)

* fix(extendVariants): return component type error

* fix(CompoundVariants): correct type inference for extended/compound variants and composition

* test: cover compound/extend inference; enforce CP required props

* fix(types): correct CompoundVariants class value inference

Replaces the conditional ClassProp logic with a simpler,
consistent form to fix incorrect slot value inference.

Before:
  ClassProp<S extends undefined ? ClassValue : ClassValue | SlotsClassValue<S>>

After:
  ClassProp<ClassValue | GetSuggestedValues<S>>

This ensures GetSuggestedValues<S> is used for slot-aware variants
and avoids duplicated conditional branches for undefined slots.

* fix(system-rsc): correct slot detection in getSlots()

* fix(types): make ExtendVariants props optional and guard V[key] with NonNullable

Simplifies the return type of ExtendVariants to ensure no required props
are enforced at the HOC level. This aligns with the intended API contract
where extended components expose all props as optional.

- All keys (CP ∪ V) are optional
- Preserve CP type hints and booleanized V values
- Added NonNullable<V[key]> guard to prevent undefined indexing

* test(extendVariants): add compoundVariants integration test

* fix(system-rsc): getSlots() brief JSDoc comment added

* test(extendVariants):  new styles - extended & fixed styles - original tests for slots component

* test(extendVariants): fixed slot component variant styles extended test

* fix(types): avoid leaking React internals by removing PropsWithoutRef

Replace PropsWithoutRef with explicit Exclude<'ref'> in mapped keys and
intersect with RefAttributes<InferRef<C>>. This prevents @types/react’s
internal UNDEFINED_VOID_ONLY from leaking into the public .d.ts and fixes
declaration emit for components like extended Autocomplete.

* chore(changeset): add patch for extendVariants and CompoundVariants type fix

* chore(system-rsc): add changeset for getSlots() slot detection fix

* refactor(types): unify slot value inference via GetSuggestedValues<S> for consistent variant typing

* fix(extendVariants): improved as-prop handling and exclude classNames from SuggestedVariants

* fix(system-rsc): add polymorphic 'as' prop support to extendVariants

* chore(system-rsc): add missing tests

---------

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

* chore(docs): update meta (#6168)

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

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

* fix(system-rsc): extendVariants rendering behavior with as (#6215)

* fix(system-rsc): fix components rendering with 'as' prop

* fix(system-rsc): fix compoundVariants and slots inheritance in extendVariants

* fix(system-rsc): extendVariants test file cleaned

* chore(deps): bump RA dependencies (#6221)

* chore(deps): bump RA dependencies

* chore(date-picker): revise test cases

* fix(button): correct disableRipple prop precedence (#6199)

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

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

---------

Co-authored-by: Hayato Hasegawa <hase1225hayato@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
Co-authored-by: brianatdetections <brian@detections.ai>
Co-authored-by: Brian Meek <brian@current.space>
Co-authored-by: Dominik Hryshaiev <domhryshaiev@gmail.com>
Co-authored-by: creative-atish <149860680+atishkr25@users.noreply.github.com>
Co-authored-by: KyZy7 <29321162+KyZy7@users.noreply.github.com>
Co-authored-by: Deepansh Bhargava <deepansh940@gmail.com>
Co-authored-by: KumJungMin <37934668+KumJungMin@users.noreply.github.com>
Co-authored-by: Bohdan Kulinchenko <35272606+ITBoomBKStudio@users.noreply.github.com>
Co-authored-by: doki- <1335902682@qq.com>
Co-authored-by: Chris Nowak <krzysztofmareknowak@gmail.com>
2026-02-18 04:22:15 -08:00
github-actions[bot] 2a604c4461 ci(changesets): version packages (#6227)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2026-02-13 21:39:38 +08:00
Chris Nowak c92543ba79 fix(button): correct disableRipple prop precedence (#6199) 2026-02-13 20:59:29 +08:00
WK 4ac203c63f chore(deps): bump RA dependencies (#6221)
* chore(deps): bump RA dependencies

* chore(date-picker): revise test cases
2026-02-13 20:49:59 +08:00
Bohdan Kulinchenko e1b34537eb fix(system-rsc): extendVariants rendering behavior with as (#6215)
* fix(system-rsc): fix components rendering with 'as' prop

* fix(system-rsc): fix compoundVariants and slots inheritance in extendVariants

* fix(system-rsc): extendVariants test file cleaned
2026-02-13 20:39:04 +08:00
Junior 35e2138b0f Merge branch 'main' of github.com:heroui-inc/heroui into canary 2026-02-10 11:50:35 -03:00
WK a252e72210 v2.8.8 (#6173)
* fix(theme): hide password reveal button (#5990)

* fix(link): link overriding role (#5999)

* fix(link): allow overriding role

* chore(link): changeset

* chore(deps): upgrade react-aria (v1.14.0) (#5996)

* chore(deps): upgrade react-aria (v1.14.0)

* refactor(react): group client components

* fix(dropdown): keyDown test cases

* chore(react): rollback

* fix(theme): default transition-duration (#6011)

* fix(theme): default transitionDuration

* chore(deps): bump @heroui/theme peer dep

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

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

* fix(use-image): resolve race condition with cached images on Firefox/Safari (#6041)

* fix(use-image): resolve race condition with cached images on Firefox/Safari

The bug occurred because event handlers (onload/onerror) were attached
AFTER setting the image src. For cached images, browsers fire onload
synchronously when src is set, causing the event to be missed and
images to remain stuck at opacity-0.

Changes:
- Attach handlers BEFORE setting src to catch synchronous callbacks
- Check both naturalWidth AND naturalHeight (per CodeRabbit review on #4523)
- Handle synchronous error callbacks for failed cached images
- Add comprehensive test coverage (15 tests) including:
  - Synchronous cached image success (Firefox/Safari race condition)
  - Synchronous cached image error
  - Dynamic src changes
  - All props (crossOrigin, srcSet, sizes, loading)
  - Callback invocation verification

Reproduction and investigation performed using Claude Opus 4.5.

Fixes #4534, #2259

* fix(use-image): add ignoreFallback to useCallback dependencies

Address CodeRabbit review feedback: the `ignoreFallback` prop was used
inside the `load` callback (line 104) but was missing from the dependency
array, creating a stale closure bug.

Without this fix, if `ignoreFallback` changes from `true` to `false`
dynamically, the `load` callback would retain the stale `true` value,
preventing the image from ever loading.

Changes:
- Add `ignoreFallback` to useCallback dependency array
- Add tests for dynamic `ignoreFallback` changes (both directions)
- Update changeset to document this fix

Verification performed using Claude Opus 4.5.

---------

Co-authored-by: Brian Meek <brian@current.space>

* fix(docs): broken links in Form page (#6077)

* fix(pagination): improve layout for large page counts (#6034)

* fix(pagination): improve layout for large page counts/style of paagination compnents

* fix(pagination): refine item sizing to balance small and large page numbers

* ci(changesets): add pagination sizing changeset

* fix(pagination): ensure cursor fully covers button without changing radius

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

---------

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

* fix(date-picker): open date-picker when clicking border (#6084)

* fix(date-picker): add pointer interaction to open date picker on wrapper click

* chore: add changeset

* chore(changeset): add issue number

---------

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

* fix(accordion): click behaviour for dynamically generated accordion items (#6133)

* fix(accordion): add collection state

* chore: add changeset

* fix: update change set

* refactor(theme): remove flat dependency (#6157)

* chore(deps): remove flat library

* refactor(theme): replace flatten from flat

* chore: add changeset

* fix(listbox): prevent option focus from start/end content slots (#6060)

* fix(listbox): prevent option focus from start/end content slots

* test: add test code about when clicking
non-interactive slot content, and prevented focus leakage from interactive
start/end content such as buttons.

* docs: add changeset

* chore(changeset): add issue number

---------

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

* fix(system-rsc): extendVariants & compound variants types (#5847)

* fix(extendVariants): return component type error

* fix(CompoundVariants): correct type inference for extended/compound variants and composition

* test: cover compound/extend inference; enforce CP required props

* fix(types): correct CompoundVariants class value inference

Replaces the conditional ClassProp logic with a simpler,
consistent form to fix incorrect slot value inference.

Before:
  ClassProp<S extends undefined ? ClassValue : ClassValue | SlotsClassValue<S>>

After:
  ClassProp<ClassValue | GetSuggestedValues<S>>

This ensures GetSuggestedValues<S> is used for slot-aware variants
and avoids duplicated conditional branches for undefined slots.

* fix(system-rsc): correct slot detection in getSlots()

* fix(types): make ExtendVariants props optional and guard V[key] with NonNullable

Simplifies the return type of ExtendVariants to ensure no required props
are enforced at the HOC level. This aligns with the intended API contract
where extended components expose all props as optional.

- All keys (CP ∪ V) are optional
- Preserve CP type hints and booleanized V values
- Added NonNullable<V[key]> guard to prevent undefined indexing

* test(extendVariants): add compoundVariants integration test

* fix(system-rsc): getSlots() brief JSDoc comment added

* test(extendVariants):  new styles - extended & fixed styles - original tests for slots component

* test(extendVariants): fixed slot component variant styles extended test

* fix(types): avoid leaking React internals by removing PropsWithoutRef

Replace PropsWithoutRef with explicit Exclude<'ref'> in mapped keys and
intersect with RefAttributes<InferRef<C>>. This prevents @types/react’s
internal UNDEFINED_VOID_ONLY from leaking into the public .d.ts and fixes
declaration emit for components like extended Autocomplete.

* chore(changeset): add patch for extendVariants and CompoundVariants type fix

* chore(system-rsc): add changeset for getSlots() slot detection fix

* refactor(types): unify slot value inference via GetSuggestedValues<S> for consistent variant typing

* fix(extendVariants): improved as-prop handling and exclude classNames from SuggestedVariants

* fix(system-rsc): add polymorphic 'as' prop support to extendVariants

* chore(system-rsc): add missing tests

---------

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

* chore(docs): update meta (#6168)

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

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

---------

Co-authored-by: Hayato Hasegawa <hase1225hayato@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
Co-authored-by: brianatdetections <brian@detections.ai>
Co-authored-by: Brian Meek <brian@current.space>
Co-authored-by: Dominik Hryshaiev <domhryshaiev@gmail.com>
Co-authored-by: creative-atish <149860680+atishkr25@users.noreply.github.com>
Co-authored-by: KyZy7 <29321162+KyZy7@users.noreply.github.com>
Co-authored-by: Deepansh Bhargava <deepansh940@gmail.com>
Co-authored-by: KumJungMin <37934668+KumJungMin@users.noreply.github.com>
Co-authored-by: Bohdan Kulinchenko <35272606+ITBoomBKStudio@users.noreply.github.com>
Co-authored-by: doki- <1335902682@qq.com>
2026-02-10 06:50:04 -08:00
github-actions[bot] f37e108588 ci(changesets): version packages (#6059)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2026-01-29 23:41:54 +08:00
WK 63c12e5359 chore(docs): update meta (#6168) 2026-01-29 00:20:06 +08:00
Bohdan Kulinchenko 1a2635beda fix(system-rsc): extendVariants & compound variants types (#5847)
* fix(extendVariants): return component type error

* fix(CompoundVariants): correct type inference for extended/compound variants and composition

* test: cover compound/extend inference; enforce CP required props

* fix(types): correct CompoundVariants class value inference

Replaces the conditional ClassProp logic with a simpler,
consistent form to fix incorrect slot value inference.

Before:
  ClassProp<S extends undefined ? ClassValue : ClassValue | SlotsClassValue<S>>

After:
  ClassProp<ClassValue | GetSuggestedValues<S>>

This ensures GetSuggestedValues<S> is used for slot-aware variants
and avoids duplicated conditional branches for undefined slots.

* fix(system-rsc): correct slot detection in getSlots()

* fix(types): make ExtendVariants props optional and guard V[key] with NonNullable

Simplifies the return type of ExtendVariants to ensure no required props
are enforced at the HOC level. This aligns with the intended API contract
where extended components expose all props as optional.

- All keys (CP ∪ V) are optional
- Preserve CP type hints and booleanized V values
- Added NonNullable<V[key]> guard to prevent undefined indexing

* test(extendVariants): add compoundVariants integration test

* fix(system-rsc): getSlots() brief JSDoc comment added

* test(extendVariants):  new styles - extended & fixed styles - original tests for slots component

* test(extendVariants): fixed slot component variant styles extended test

* fix(types): avoid leaking React internals by removing PropsWithoutRef

Replace PropsWithoutRef with explicit Exclude<'ref'> in mapped keys and
intersect with RefAttributes<InferRef<C>>. This prevents @types/react’s
internal UNDEFINED_VOID_ONLY from leaking into the public .d.ts and fixes
declaration emit for components like extended Autocomplete.

* chore(changeset): add patch for extendVariants and CompoundVariants type fix

* chore(system-rsc): add changeset for getSlots() slot detection fix

* refactor(types): unify slot value inference via GetSuggestedValues<S> for consistent variant typing

* fix(extendVariants): improved as-prop handling and exclude classNames from SuggestedVariants

* fix(system-rsc): add polymorphic 'as' prop support to extendVariants

* chore(system-rsc): add missing tests

---------

Co-authored-by: doki- <1335902682@qq.com>
Co-authored-by: WK Wong <wingkwong.code@gmail.com>
2026-01-28 23:52:36 +08:00
KumJungMin 7814df7cea fix(listbox): prevent option focus from start/end content slots (#6060)
* fix(listbox): prevent option focus from start/end content slots

* test: add test code about when clicking
non-interactive slot content, and prevented focus leakage from interactive
start/end content such as buttons.

* docs: add changeset

* chore(changeset): add issue number

---------

Co-authored-by: WK <wingkwong.code@gmail.com>
2026-01-28 23:45:15 +08:00
WK 5549167041 refactor(theme): remove flat dependency (#6157)
* chore(deps): remove flat library

* refactor(theme): replace flatten from flat

* chore: add changeset
2026-01-28 20:48:02 +08:00
Deepansh Bhargava 96b1f498cf fix(accordion): click behaviour for dynamically generated accordion items (#6133)
* fix(accordion): add collection state

* chore: add changeset

* fix: update change set
2026-01-27 17:52:34 +08:00
WK 3933b347b7 chore(docs): sync cli updates (#6099)
* chore(docs): sync cli api doc

* chore(docs): update versions
2026-01-11 11:13:37 -08:00
Junior 4add7525a0 Merge branch 'main' of github.com:heroui-inc/heroui into canary 2026-01-07 12:07:37 -03:00
KyZy7 d5a5c77ed6 fix(date-picker): open date-picker when clicking border (#6084)
* fix(date-picker): add pointer interaction to open date picker on wrapper click

* chore: add changeset

* chore(changeset): add issue number

---------

Co-authored-by: WK <wingkwong.code@gmail.com>
2026-01-07 00:39:08 +08:00
creative-atish 1f085061ed fix(pagination): improve layout for large page counts (#6034)
* fix(pagination): improve layout for large page counts/style of paagination compnents

* fix(pagination): refine item sizing to balance small and large page numbers

* ci(changesets): add pagination sizing changeset

* fix(pagination): ensure cursor fully covers button without changing radius

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

---------

Co-authored-by: WK Wong <wingkwong.code@gmail.com>
2026-01-04 22:27:47 +08:00
Dominik Hryshaiev df6610cd98 fix(docs): broken links in Form page (#6077) 2026-01-02 20:22:26 +08:00
brianatdetections 5ec842b1cf fix(use-image): resolve race condition with cached images on Firefox/Safari (#6041)
* fix(use-image): resolve race condition with cached images on Firefox/Safari

The bug occurred because event handlers (onload/onerror) were attached
AFTER setting the image src. For cached images, browsers fire onload
synchronously when src is set, causing the event to be missed and
images to remain stuck at opacity-0.

Changes:
- Attach handlers BEFORE setting src to catch synchronous callbacks
- Check both naturalWidth AND naturalHeight (per CodeRabbit review on #4523)
- Handle synchronous error callbacks for failed cached images
- Add comprehensive test coverage (15 tests) including:
  - Synchronous cached image success (Firefox/Safari race condition)
  - Synchronous cached image error
  - Dynamic src changes
  - All props (crossOrigin, srcSet, sizes, loading)
  - Callback invocation verification

Reproduction and investigation performed using Claude Opus 4.5.

Fixes #4534, #2259

* fix(use-image): add ignoreFallback to useCallback dependencies

Address CodeRabbit review feedback: the `ignoreFallback` prop was used
inside the `load` callback (line 104) but was missing from the dependency
array, creating a stale closure bug.

Without this fix, if `ignoreFallback` changes from `true` to `false`
dynamically, the `load` callback would retain the stale `true` value,
preventing the image from ever loading.

Changes:
- Add `ignoreFallback` to useCallback dependency array
- Add tests for dynamic `ignoreFallback` changes (both directions)
- Update changeset to document this fix

Verification performed using Claude Opus 4.5.

---------

Co-authored-by: Brian Meek <brian@current.space>
2025-12-27 14:24:27 +08:00
Junior 65702817c2 refactor(docs): remove Sponsors component from Home page 2025-12-25 11:42:04 -03:00
Junior 436e0d8278 Merge branch 'main' of github.com:heroui-inc/heroui into canary 2025-12-25 11:41:09 -03:00
WK 2d693f732c v2.8.7 (#6022)
* fix(theme): hide password reveal button (#5990)

* fix(link): link overriding role (#5999)

* fix(link): allow overriding role

* chore(link): changeset

* chore(deps): upgrade react-aria (v1.14.0) (#5996)

* chore(deps): upgrade react-aria (v1.14.0)

* refactor(react): group client components

* fix(dropdown): keyDown test cases

* chore(react): rollback

* fix(theme): default transition-duration (#6011)

* fix(theme): default transitionDuration

* chore(deps): bump @heroui/theme peer dep

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

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

---------

Co-authored-by: Hayato Hasegawa <hase1225hayato@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2025-12-25 06:40:03 -08:00
github-actions[bot] d5131d77a3 ci(changesets): version packages (#5991)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2025-12-20 22:17:53 +08:00
WK 086f6a1c44 fix(theme): default transition-duration (#6011)
* fix(theme): default transitionDuration

* chore(deps): bump @heroui/theme peer dep
2025-12-20 22:01:47 +08:00
WK e07c969c4c chore(deps): upgrade react-aria (v1.14.0) (#5996)
* chore(deps): upgrade react-aria (v1.14.0)

* refactor(react): group client components

* fix(dropdown): keyDown test cases

* chore(react): rollback
2025-12-18 19:52:56 +08:00
Hayato Hasegawa 090b151a5b fix(link): link overriding role (#5999)
* fix(link): allow overriding role

* chore(link): changeset
2025-12-18 18:42:22 +08:00
WK acc74d1e8f fix(theme): hide password reveal button (#5990) 2025-12-16 14:20:58 +08:00
Junior Garcia 41fc673586 Merge pull request #5983 from heroui-inc/canary
v2.8.6
2025-12-14 18:30:02 -08:00
github-actions[bot] c76c68ad7e ci(changesets): version packages (#5820)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2025-12-14 15:44:29 +08:00
WK 2148a2ee3b chore(docs): refresh meta (#5980) 2025-12-14 14:04:48 +08:00
mojtaba 53e27bb6f8 fix(system-rsc): respect defaultVariants.className in extendVariants (#5940)
* fix(system-rsc): respect defaultVariants.className in extendVariants

- Fix getClassNamesWithProps to merge defaultVariants.className with result and props.className
- Add tests to verify defaultVariants.className is respected and merged correctly

* chore(changeset): add changeset

* refactor(system-rsc): cn with newProps.className

* chore(system-rsc): revise merge order

---------

Co-authored-by: hassanzadeh-mj <hassanzadeh-mj@users.noreply.github.com>
Co-authored-by: WK <wingkwong.code@gmail.com>
2025-12-14 14:04:21 +08:00
WK 467b497156 chore(deps): bump next version (#5978) 2025-12-12 19:34:05 +08:00
WK 799bc5bab8 fix(toast): long text exceeds wrapper (#5977) 2025-12-11 22:55:12 +08:00
Deepansh Bhargava a37912e17f fix(slots): extendVariants fn to support slots (#5895)
* fix: extendVariants fn to support slots

* chore(docs): undo changes

* chore(changeset): add changeset

* chore(docs): new line

---------

Co-authored-by: WK Wong <wingkwong.code@gmail.com>
2025-12-11 20:43:40 +08:00
doki- 4c435348ec fix(theme): incorrect label position of the select component (#5799)
* fix(theme): incorrect label position of the select component

* fix(theme): incorrect label position of select component
2025-12-11 20:15:49 +08:00
Hayato Hasegawa 8d07922c68 feat: add support for "outside-top" label placement (#5964)
* feat(number-input): add support for "outside-top" label placement

* chore: changeset

* fix(number-input): correct label positioning for "outside-top" placement

* feat: add `outside-top` label placement support for inputs and provider

* chore: update changeset

* chore(docs): update docs to include `outside-top` label placement

* test: add tests for `HeroUIProvider` label placement inheritance

* test(date-picker): remove tests for `HeroUIProvider` label placement inheritance

* test: add comprehensive tests for `HeroUIProvider` label placement outside-top

* chore(deps): bump theme in peerDependencies

* chore(docs): update examples and descriptions to include `outside-top` label placement

* chore(docs): update autocomplete label placement type to include `outside-top`

---------

Co-authored-by: WK Wong <wingkwong.code@gmail.com>
2025-12-11 20:10:43 +08:00
WK ecf2857c90 refactor: tailwind-variants (#5930)
* chore(deps): bump tailwind-variants

* chore(changeset): add changeset

* refactor(theme): use cnMerge from tailwind-variants

* refactor: replace clsx by cn

* chore(deps): remove clsx

* chore: rollback clsx for mergeProps

* fix(theme): incorrect syntax

* refactor: remove outer cn

* chore(docs): type issues

* fix(radio): duplicate import

* chore(deps): bump peerDependencies for theme package

* chore(changeset): update changeset
2025-12-11 13:04:09 +08:00
WK a81212d6e7 fix(deps): next version (#5968)
* fix(deps): nextjs version

* chore(deps): bump next version
2025-12-06 21:15:23 +08:00
WK a7655ad2c9 chore(docs): remove chat linkage (#5959)
* chore: remove unused globalEnv

* chore(docs): remove chat links
2025-12-04 16:59:57 -03:00
WK b89ba08ae0 fix(table): virtualized table in firefox by replacing Spacer with css (#5963)
* chore(deps): remove spacer and bump theme peer dependency

* refactor(table): remove spacer

* fix(theme): replace spacer by css

* chore(changeset): add changeset

* chore(changeset): update changeset message
2025-12-04 23:13:46 +08:00
WK f08dfb8dd9 fix(table): column props not recognized (#5950)
* fix(table): width, minWidth, and maxWidth

* refactor(docs): revise table examples

* chore(changeset): add changeset
2025-12-04 21:42:04 +08:00
WK 0f165a36c8 fix(components): typos (#5958) 2025-12-03 01:18:40 +08:00
WK 9520b3f850 fix(docs): typos (#5957) 2025-12-03 00:29:37 +08:00
Stybo ecad199b09 fix(docs): typos in calendar and range-calendar page (#5956)
* Fix typo in calendar component documentation

* Fix typo in range-calendar documentation
2025-12-03 00:16:26 +08:00
Adam Björnberg a819f2a95a fix(tabs): responsive resize cursor to match selected tab (#5846)
* fix(tabs): responsive resize cursor to match selected tab

* Move css to theme

* Update changeset

* use explicit true for data-initialized

* disable animation when variant changes

* make not disappear when toggling animation

* disable animation when isVertical changes

* refactor for readability

* fix blinking when toggling variant or isVertical

* disable animation when changing placement

* chore(changeset): add issue number

---------

Co-authored-by: WK Wong <wingkwong.code@gmail.com>
2025-12-02 18:39:10 +08:00
Hayato Hasegawa b4cfb408e9 fix(autocomplete): show popover when emptyContent is provided with allowsCustomValue (#5951)
* fix(autocomplete): show popover when emptyContent is provided with allowsCustomValue

* chore(autocomplete): remove deprecated story with custom emptyContent and allowsCustomValue

* chore: add changeset
2025-12-01 00:12:59 +08:00
Hayato Hasegawa 66ef76e823 fix(link): resolve issue where useHref is not working correctly (#5933)
* fix(link): correct props merge order in use-link to apply useHref

* chore(link): add changeset

* test(link): adjust href assertion to use getAttribute for compatibility

* fix(link): use routerLinkProps.href in handleLinkClick for consistency

* fix(link): process href with useHref before passing to useLinkProps

* test(link): comment out useHref provider test

* Revert "test(link): comment out useHref provider test"

This reverts commit de053f835fa57becf6e807a64c17339fc61d8689.

* Revert "fix(link): process href with useHref before passing to useLinkProps"

This reverts commit 81e5f7b8d1ea7002b9718cf521b5c6f2af79ac42.

* fix(provider): add `useHref` to provider context and integrate with `useLink`

* test(link): comment out useHref provider test

* fix(link): correct href handling in link component and update tests

* fix(link): simplify props handling by removing resolvedProps logic and reorder mergeProps usage

* fix(provider): remove `useHref` from provider context and related logic

* refactor(link): add spacing

* chore(changeset): add issue numbers

---------

Co-authored-by: WK Wong <wingkwong.code@gmail.com>
2025-11-28 18:34:17 +08:00
WK 0825f88cd2 fix(spinner): cater global spinner variant (#5948)
* fix(spinner): cater global spinner variant

* feat(spinner): add spinner test cases

* chore(changeset): add changeset
2025-11-26 16:46:34 +08:00
WK ce0c298785 fix(number-input): lable position for empty percent format (#5945)
* fix(number-input): lable position for empty percent format

* chore(changeset): fix typo
2025-11-26 13:56:48 +08:00
WK 4fa54534b2 fix(radio): handle props styles in getBaseProps (#5944)
* fix(radio): handle props styles in getBaseProps

* refactor(radio): examples
2025-11-26 13:55:37 +08:00
WK 4e3098a512 chore(docs): add deprecation message (#5946) 2025-11-25 14:57:35 -03:00
WK 484212712c chore(deps): bump posthog-js (#5937) 2025-11-25 10:41:59 +08:00
WK 217e88d58e fix(docs): incorrect date value type in api (#5936)
* fix(docs): incorrect date value type in api

* chore(docs): revise types
2025-11-25 01:23:45 +08:00
Hayato Hasegawa 8b2ec9fa46 fix(table): use controlled sorting in table test (#5904) 2025-11-23 01:16:09 +08:00
Hayato Hasegawa 5d9a05be01 fix(tabs): vertical tabs support for accessible navigation and aria-orientation (#5924) 2025-11-22 10:56:26 +08:00
Hayato Hasegawa bc4c982609 fix(skeleton): fixed shimmer animation still plays when disableAnimation is true (#5916)
* fix(skeleton): restore shimmer animation for background transition

* chore: changeset

* chore(skeleton): bump theme peer dep

* chore(skeleton): pass args to first skeleton

* chore(changeset): bump skeleton

---------

Co-authored-by: WK Wong <wingkwong.code@gmail.com>
2025-11-21 15:18:27 +08:00
Hayato Hasegawa 8921dc4361 fix(theme): safari autofill styling for dark mode readability in Input component (#5909)
* fix: add Safari autofill styling for dark mode readability in NumberInput & Input components

* chore: add changeset for Safari autofill dark mode fix in NumberInput & Input components
2025-11-19 21:51:21 +08:00
Hayato Hasegawa fd9dd2a20c fix(theme): bordered focus styles take precedence over hover (#5893)
* fix(theme): bordered focus styles take precedence over hover

* chore(theme): update component focus styles to fix hover override

* chore: bump @heroui/theme peer deps

---------

Co-authored-by: WK Wong <wingkwong.code@gmail.com>
2025-11-16 22:20:17 +08:00
Hayato Hasegawa 91e010fe3b fix(ripple): resolve misalignment in RTL layouts by using transform (#5891)
* fix(ripple): resolve misalignment in RTL layouts by using transform translate

* chore(ripple): add changeset for ripple RTL layout fix

* chore: add issue number

---------

Co-authored-by: WK Wong <wingkwong.code@gmail.com>
2025-11-15 22:36:40 +08:00
WK 0bf225abf5 fix(docs): layoutColor.overlay (#5782) 2025-11-15 22:00:58 +08:00
Junior Garcia 83b8fc1e7c chore: v3 beta release banner 2025-11-06 17:12:46 -03:00
Mahdi Mohammadi 0344123c13 fix(docs): submenu selected item indicator (#5868)
Co-authored-by: Mahdi <mahdiprog81@gmail.com>
2025-11-04 00:39:34 +08:00
Anusha Chaturvedi 6a3b02773d fix(docs): increase sidebar text contrast to meet WCAG AA accessibility (#5819) 2025-11-03 12:59:52 +08:00
KumJungMin bdd37b4b08 fix(number-input): include labelPlacement in dependency array (#5866)
* fix(number-input): include labelPlacement in dependency array for useNumberInput

* test(number-input): add tests for labelPlacement with HeroUIProvider context

* test(number-input): ensure labelPlacement prop takes precedence over HeroUIProvider context

* docs(number-input): add changeset

* chore(changeset): add issue number

---------

Co-authored-by: WK <wingkwong.code@gmail.com>
2025-11-02 20:51:42 +08:00
Vilas Chauvhan 27fec2db3c fix(docs): codeblock flickering issue (#5849)
* fix: updated codeblock component to prevent flicker when scrolling

* fix(codeblock): revert className and style handling

* fix(codeblock): clean up className handling and remove unnecessary styles

* chore(docs): format

---------

Co-authored-by: WK Wong <wingkwong.code@gmail.com>
2025-11-01 18:33:02 +08:00
Vishesh Verma 1782961859 fix(spinner): spinner animation (#5815)
* fix(components/spinner): restore linear rotation (fix #5794)

* fix(spinner): add patch changeset for spinner delay fix

* fix(spinner): restore linear rotation for spinner variant (fix #5794)

* chore: apply Prettier and ESLint fixes to animation util

* chore(theme): lint

* chore(changeset): update msg & add issue number

* chore(changeset): include theme package

* chore(spinner): bump theme peerDependencies

---------

Co-authored-by: WK <wingkwong.code@gmail.com>
2025-10-28 01:59:58 +08:00
WK 680b68bc83 chore(docs): update nav banner (#5835) 2025-10-21 10:02:06 -03:00
Nikhil Shrivastava 328c57d8ea fix(heroui-table): update virtualization examples to use @heroui/react imports (#5833) 2025-10-21 00:03:12 -03:00
WK 2922b35644 fix(autocomplete): close button display on mobile (#5827)
* fix(autocomplete): close button display on mobile

* refactor(autocomplete): disable isClearable if isDisabled is true
2025-10-19 11:35:18 +08:00
WK b38a2cfb58 fix(theme): tab cursor (#5816)
* fix(theme): remove inset-0 for tab cursor

* chore(deps): bump theme peerDep

* chore: add changeset
2025-10-17 10:41:49 +08:00
Junior Garcia acd5f1dfb5 Merge pull request #5772 from heroui-inc/canary 2025-10-04 11:03:28 -03:00
github-actions[bot] 37378704f1 ci(changesets): version packages (#5755)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2025-10-04 21:39:38 +08:00
WK ed76faacd4 fix(toast): trigger onClose after timeout (#5771) 2025-10-04 21:25:04 +08:00
WK 812f7939d9 fix(tabs): tab cursor (#5769) 2025-10-04 17:42:05 +08:00
WK 1f17962932 chore(docs): update meta info (#5767) 2025-10-04 13:45:41 +08:00
WK 6eba109a7f fix(tabs): tabs in modal (#5705)
* fix(tabs): tabs in modal

* refactor(tabs): revise tabs cursor

* refactor(theme): remove unused styles

* fix(tabs): revise cursor rendering logic

* chore(docs): remove motionProps

* refactor(tabs): cursor styles

* refactor(tabs): cursor styles

* fix(tabs): avoid transition on variant change

* refactor(theme): cursor styles

* chore(changeset): include theme package

* chore(tabs): bump peerDeps on theme pkg

* fix(tabs): revise underlined cursor styles
2025-10-04 13:39:20 +08:00
WK 7537226b54 fix(system-rsc): incorrect typing (#5765) 2025-10-04 10:48:58 +08:00
WK 136bdf66b1 chore(deps): bump react-aria versions (#5761)
* chore(deps): bump react-aria versions

* chore: add changeset

* chore(docs): add selectionAlignment
2025-10-04 10:17:31 +08:00
WK 736293b8a6 fix(number-input): backspace behavior with formatted numbers (#5719)
* fix(number-input): backspace behavior with formatted numbers

* refactor(number-input): handle locale separator

* fix(number-input): set number input value logic
2025-10-04 10:16:56 +08:00
WK f13c6875db fix(number-input): ignore name prop in getNumberInputProps (#5762)
* fix(number-input): ignore name prop in getNumberInputProps

* fix(number-input): react-hook-form test case

* chore(number-input): assert no duplicate name attribute
2025-10-04 10:16:21 +08:00
doki- 0d95d7faa0 fix(avatar): add the safeInitials function to get the initials name (#5677)
* fix(Avatar): fix getInitials

* chore: update test

* chore(user): revise example

---------

Co-authored-by: WK Wong <wingkwong.code@gmail.com>
2025-10-04 01:14:00 +08:00
WK 7b7190e222 fix(autocomplete): duplicate id in clear & selector button (#5750) 2025-10-04 01:10:37 +08:00
WK c3224113de fix(theme): broken --visual-viewport-height (#5752) 2025-10-01 10:56:08 +08:00
Rodrigo Victor 7c215f289e docs(popover): update shouldCloseOnScroll default to true (#5736) 2025-09-30 20:31:46 +08:00
Junior Garcia a88f98a14b Merge pull request #5679 from heroui-inc/canary 2025-09-09 15:51:27 -03:00
416 changed files with 10532 additions and 5902 deletions
-8
View File
@@ -1,8 +0,0 @@
# Changesets
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
with multi-package repos, or single-package repos to help you version and publish your code. You can
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
We have a quick list of common questions to get you started engaging with this project in
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
-20
View File
@@ -1,20 +0,0 @@
{
"$schema": "https://unpkg.com/@changesets/config@2.3.0/schema.json",
"changelog": [
"@changesets/changelog-github",
{ "repo": "heroui-inc/heroui" }
],
"commit": false,
"fixed": [],
"linked": [],
"access": "public",
"baseBranch": "canary",
"updateInternalDependencies": "patch",
"___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": {
"onlyUpdatePeerDependentsWhenOutOfRange": true
},
"ignore": [
"@heroui/docs",
"@heroui/storybook"
]
}
-2
View File
@@ -10,11 +10,9 @@ reviews:
ignore_title_keywords:
- "WIP"
- "DO NOT MERGE"
- 'ci(changesets)'
drafts: false
base_branches:
- "main"
- "canary"
- "fix/.*"
- "chore/.*"
- "feat/.*"
@@ -1,35 +0,0 @@
name: Enter pre-release mode
on: workflow_dispatch
jobs:
enter-pre-release-mode:
if: ${{ github.ref == 'refs/heads/beta/release-next' || github.ref == 'refs/heads/canary' }}
runs-on: heroui-runner
permissions:
contents: write
pull-requests: write
id-token: write
steps:
- name: Checkout branch
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install
uses: ./.github/common-actions/install
- name: Enter pre-release mode
id: enter-pre-release-mode
env:
GITHUB_TOKEN: ${{ secrets.GA_ACCESS_TOKEN }}
run: |
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git config user.name "github-actions[bot]"
if [ ${{ github.ref }} == 'refs/heads/canary' ]; then
pnpm changeset:canary
else
pnpm changeset:beta
fi
git add -A
git commit -m 'chore(pre-release): enter pre-release mode'
git push
@@ -1,39 +0,0 @@
name: Exit pre-release mode
on: workflow_dispatch
jobs:
exit-pre-release-mode:
if: ${{ github.ref == 'refs/heads/beta/release-next' || github.ref == 'refs/heads/canary' }}
name: exit pre-release mode
runs-on: heroui-runner
permissions:
contents: write
pull-requests: write
id-token: write
steps:
- name: Checkout branch
uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.branch }}
fetch-depth: 0
- name: Install
uses: ./.github/common-actions/install
- name: remove pre.json
# we only remove .changeset/pre.json here
# since we want to keep the changeset files introduced in beta/release-next or canary branch
# once we merge it to canary / main, those files will be removed in version PR in canary
# and converted to corresponding changelogs
run: npx rimraf .changeset/pre.json
- name: Commit and push changes
env:
GITHUB_TOKEN: ${{ secrets.GA_ACCESS_TOKEN }}
run: |
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git config user.name "github-actions[bot]"
git add -A
git commit -m "ci(changesets): exit pre-release mode"
git push
-81
View File
@@ -1,81 +0,0 @@
name: Pre-release
on:
push:
paths:
- ".changeset/**"
- "packages/**"
branches:
- "beta/release-next"
concurrency: ${{ github.workflow }}-${{ github.ref }}
jobs:
prerelease:
name: changesets pre-release
runs-on: heroui-runner
timeout-minutes: 30
permissions:
contents: write
pull-requests: write
id-token: write
steps:
- name: Checkout branch
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install
uses: ./.github/common-actions/install
- name: Check if pre.json exists
id: check_if_pre_json_exists
uses: andstor/file-existence-action@v3.0.0
with:
files: ".changeset/pre.json"
- name: Debug condition values
run: |
echo "pre.json exists: ${{ steps.check_if_pre_json_exists.outputs.files_exists }}"
echo "Commit message: ${{ github.event.head_commit.message }}"
echo "Contains version packages: ${{ contains(github.event.head_commit.message, 'ci(changesets): version packages') }}"
echo "Full condition would be: ${{ steps.check_if_pre_json_exists.outputs.files_exists == 'true' && contains(github.event.head_commit.message, 'ci(changesets): version packages') }}"
- name: Get pre-release changesets
id: get-pre-release-changesets
uses: notiz-dev/github-action-json-property@release
with:
path: ".changeset/pre.json"
prop_path: "changesets"
- name: Create pre-release PR
id: create-pre-release-pr
if: "${{ steps.check_if_pre_json_exists.outputs.files_exists == 'true' && !startsWith(github.event.head_commit.message, 'ci(changesets): version packages') }}"
uses: changesets/action@v1
with:
version: pnpm run version
title: "ci(changesets): :package: version packages"
commit: "ci(changesets): version packages"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Tests
if: "${{ steps.check_if_pre_json_exists.outputs.files_exists == 'true' && contains(github.event.head_commit.message, 'ci(changesets): version packages') }}"
run: pnpm test
- name: Build
if: "${{ steps.check_if_pre_json_exists.outputs.files_exists == 'true' && contains(github.event.head_commit.message, 'ci(changesets): version packages') }}"
run: pnpm build
env:
NODE_OPTIONS: "--max-old-space-size=4096"
- name: Publish to NPM
id: publish-to-npm
if: "${{ steps.check_if_pre_json_exists.outputs.files_exists == 'true' && contains(github.event.head_commit.message, 'ci(changesets): version packages') }}"
uses: changesets/action@v1
with:
publish: pnpm run release
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-63
View File
@@ -1,63 +0,0 @@
name: Release
on:
push:
paths:
- ".changeset/**"
- "packages/**"
branches:
- canary
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
jobs:
release:
name: Release
runs-on: heroui-runner
timeout-minutes: 30
steps:
- name: Checkout branch
uses: actions/checkout@v4
- name: Install
uses: ./.github/common-actions/install
- name: Tests
run: pnpm test
- name: Build
id: build
continue-on-error: false
# Custom turbo build failure information
run: |
pnpm build || {
echo "Turbo build failed with exit code $?"
exit 1
}
- name: Create Release Pull Request or Publish to NPM
# Run only if the build is successful
if: steps.build.outcome == 'success'
id: changesets
uses: changesets/action@v1
with:
publish: pnpm release
title: "ci(changesets): :package: version packages"
commit: "ci(changesets): version packages"
setupGitUser: false
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Create canary release
if: steps.build.outcome == 'success' && steps.changesets.outputs.published != 'true'
timeout-minutes: 15
run: |
git checkout canary
pnpm version:canary
pnpm release:canary
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+51
View File
@@ -0,0 +1,51 @@
name: Release
on:
push:
tags:
- "@heroui/**"
concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false
jobs:
publish:
name: Publish
if: github.repository == 'heroui-inc/heroui'
runs-on: ubuntu-latest
environment: npm-publish
timeout-minutes: 15
permissions:
contents: write
id-token: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install
uses: ./.github/common-actions/install
- name: Parse tag
id: tag
shell: bash
run: |
REF="${GITHUB_REF_NAME}"
# tag format: @scope/name@version -> split on the LAST "@"
PKG_NAME="${REF%@*}"
PKG_VERSION="${REF##*@}"
echo "name=$PKG_NAME" >> "$GITHUB_OUTPUT"
echo "version=$PKG_VERSION" >> "$GITHUB_OUTPUT"
echo "Publishing $PKG_NAME@$PKG_VERSION"
- name: Build packages
run: pnpm --filter "${{ steps.tag.outputs.name }}" build
- name: Ensure npm supports trusted publishing
run: npm install -g npm@11
- name: Publish to npm
run: pnpm --filter "${{ steps.tag.outputs.name }}" publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
-1
View File
@@ -2,7 +2,6 @@ dist
node_modules
plop
coverage
.changeset
.next
build
scripts
+5 -15
View File
@@ -19,8 +19,7 @@ Hello!, I am very excited that you are interested in contributing with HeroUI. H
testing
- [Testing Library](https://testing-library.com/) for testing components and
hooks
- [Changeset](https://github.com/atlassian/changesets) for changes
documentation, changelog generation, and release management.
- [bumpp](https://github.com/antfu/bumpp) for version bumping and release management.
### Commit Convention
@@ -85,19 +84,10 @@ https://www.conventionalcommits.org/ or check out the
> To know more about the `--filter` option, please check the turborepo [docs](https://turborepo.org/docs/core-concepts/filtering).
4. Run `pnpm changeset` to create a detailed description of your changes. This
will be used to generate a changelog when we publish an update.
[Learn more about Changeset](https://github.com/atlassian/changesets/tree/master/packages/cli).
Please note that you might have to run `git fetch origin main:master` (where
origin will be your fork on GitHub) before `pnpm changeset` works.
5. Also, if you provide `jsx` snippets to the changeset, please turn off the
live preview by doing the following at the beginning of the snippet:
` ```jsx live=false`
> If you made minor changes like CI config, prettier, etc, you can run
> `pnpm changeset add --empty` to generate an empty changeset file to document
> your changes.
4. Version bumping is handled by maintainers using `pnpm version:bump` which
uses [bumpp](https://github.com/antfu/bumpp) to interactively bump the
version, create a git commit, and push a tag that triggers the release CI.
## Development Setup
After cloning the repository, execute the following commands in the root folder:
-5
View File
@@ -22,8 +22,3 @@ NEXT_PUBLIC_FB_FEEDBACK_URL=
# PostHog
NEXT_PUBLIC_POSTHOG_KEY=your-posthog-key
NEXT_PUBLIC_POSTHOG_HOST=your-posthog-host
# Chat
IMPORT_API_KEY=your-import-api-key
CHAT_API_URL=
CHAT_URL=
-100
View File
@@ -1,100 +0,0 @@
"use server";
import {toKebabCase, toPascalCase} from "@/components/docs/components/code-demo/utils";
const importReact = 'import React from "react";';
export const openInChat = async ({
component,
title,
content,
dependencies,
useWrapper,
}: {
component: string;
title?: string;
content: string;
dependencies: {name: string; version: string}[];
useWrapper: boolean;
}) => {
try {
// Check if the file content includes 'React' import statements, if not, add it
if (
content.includes("React.") &&
!content.includes("from 'react'") &&
!content.includes('from "react"')
) {
content = `${importReact}\n${content}\n`;
}
let files: Record<string, string> = {
"src/App.tsx": content,
};
const fullName = `${component.charAt(0).toUpperCase() + component.slice(1)} - ${title}`;
if (useWrapper) {
files = getFilesWithWrapper(fullName, content);
}
const response = await fetch(`${process.env.CHAT_API_URL}/import`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.IMPORT_API_KEY}`,
},
body: JSON.stringify({
title: `${component.charAt(0).toUpperCase() + component.slice(1)} - ${title}`,
files,
dependencies,
}),
});
const result = await response.json();
if (result.error || !result.path) {
return {
error: result.error ?? "Unknown error",
data: null,
};
}
return {
error: null,
data: `${process.env.CHAT_URL}${
result.path
}&utm_source=heroui.com&utm_medium=open-in-chat&utm_content=${encodeURIComponent(
title ?? "unknown",
)}`,
};
} catch (error) {
return {error: error, data: null};
}
};
const getFilesWithWrapper = (name: string, content: string) => {
const pascalName = toPascalCase(name);
const kebabName = toKebabCase(name);
// Replace the export default function name
const updatedContent = content.replace(
"export default function App()",
`export default function ${pascalName}()`,
);
const wrapperContent = `import ${pascalName} from "./components/${kebabName}";
export default function App() {
return (
<div className="flex min-h-screen items-center justify-center p-6">
<${pascalName} />
</div>
);
}
`;
return {
[`src/components/${kebabName}.tsx`]: updatedContent,
[`src/App.tsx`]: wrapperContent,
};
};
@@ -35,7 +35,7 @@ const animals = [
];
type FieldState = {
selectedKey: React.Key | null;
value: React.Key | null;
inputValue: string;
items: typeof animals;
};
@@ -44,7 +44,7 @@ export default function Page() {
// Store ComboBox input value, selected option, open state, and items
// in a state tracker
const [fieldState, setFieldState] = React.useState<FieldState>({
selectedKey: "",
value: "",
inputValue: "",
items: animals,
});
@@ -55,13 +55,13 @@ export default function Page() {
// Specify how each of the Autocomplete values should change when an
// option is selected from the list box
const onSelectionChange = (key: React.Key | null) => {
const onChange = (key: React.Key | null) => {
setFieldState((prevState) => {
let selectedItem = prevState.items.find((option) => option.value === key);
return {
inputValue: selectedItem?.label || "",
selectedKey: key,
value: key,
items: animals.filter((item) => startsWith(item.label, selectedItem?.label || "")),
};
});
@@ -72,7 +72,7 @@ export default function Page() {
const onInputChange = (value: string) => {
setFieldState((prevState) => ({
inputValue: value,
selectedKey: value === "" ? null : prevState.selectedKey,
value: value === "" ? null : prevState.value,
items: animals.filter((item) => startsWith(item.label, value)),
}));
};
@@ -82,7 +82,7 @@ export default function Page() {
if (menuTrigger === "manual" && isOpen) {
setFieldState((prevState) => ({
inputValue: prevState.inputValue,
selectedKey: prevState.selectedKey,
value: prevState.value,
items: animals,
}));
}
@@ -96,11 +96,11 @@ export default function Page() {
items={fieldState.items}
label="Favorite Animal"
placeholder="Select an animal"
selectedKey={fieldState.selectedKey}
value={fieldState.value}
variant="bordered"
onChange={onChange}
onInputChange={onInputChange}
onOpenChange={onOpenChange}
onSelectionChange={onSelectionChange}
>
{(item) => <AutocompleteItem key={item.value}>{item.label}</AutocompleteItem>}
</Autocomplete>
@@ -350,20 +350,18 @@ export default function Page() {
);
case "actions":
return (
<div className="relative flex justify-end items-center gap-2">
<Dropdown className="bg-background border-1 border-default-200">
<DropdownTrigger>
<Button isIconOnly radius="full" size="sm" variant="light">
<VerticalDotsIcon className="text-default-400" />
</Button>
</DropdownTrigger>
<DropdownMenu>
<DropdownItem key="view">View</DropdownItem>
<DropdownItem key="edit">Edit</DropdownItem>
<DropdownItem key="delete">Delete</DropdownItem>
</DropdownMenu>
</Dropdown>
</div>
<Dropdown className="bg-background border-1 border-default-200">
<DropdownTrigger>
<Button isIconOnly radius="full" size="sm" variant="light">
<VerticalDotsIcon className="text-default-400" />
</Button>
</DropdownTrigger>
<DropdownMenu>
<DropdownItem key="view">View</DropdownItem>
<DropdownItem key="edit">Edit</DropdownItem>
<DropdownItem key="delete">Delete</DropdownItem>
</DropdownMenu>
</Dropdown>
);
default:
return cellValue;
+12 -14
View File
@@ -342,20 +342,18 @@ export default function Page() {
);
case "actions":
return (
<div className="relative flex justify-end items-center gap-2">
<Dropdown>
<DropdownTrigger>
<Button isIconOnly size="sm" variant="light">
<VerticalDotsIcon className="text-default-300" />
</Button>
</DropdownTrigger>
<DropdownMenu>
<DropdownItem key="view">View</DropdownItem>
<DropdownItem key="edit">Edit</DropdownItem>
<DropdownItem key="delete">Delete</DropdownItem>
</DropdownMenu>
</Dropdown>
</div>
<Dropdown>
<DropdownTrigger>
<Button isIconOnly size="sm" variant="light">
<VerticalDotsIcon className="text-default-300" />
</Button>
</DropdownTrigger>
<DropdownMenu>
<DropdownItem key="view">View</DropdownItem>
<DropdownItem key="edit">Edit</DropdownItem>
<DropdownItem key="delete">Delete</DropdownItem>
</DropdownMenu>
</Dropdown>
);
default:
return cellValue;
+4 -6
View File
@@ -2,7 +2,7 @@ import "@/styles/globals.css";
import "@/styles/sandpack.css";
import type {Metadata, Viewport} from "next";
import {clsx} from "@heroui/shared-utils";
import {cn} from "@heroui/theme";
import {Analytics} from "@vercel/analytics/next";
import {Providers} from "./providers";
@@ -13,7 +13,6 @@ import {siteConfig} from "@/config/site";
import {fonts} from "@/config/fonts";
import {Navbar} from "@/components/navbar";
import {Footer} from "@/components/footer";
import {RandomBanner} from "@/components/random-banner";
export const metadata: Metadata = {
title: {
@@ -52,9 +51,9 @@ export const metadata: Metadata = {
],
creator: "heroui-inc",
alternates: {
canonical: "https://heroui.com",
canonical: "https://v2.heroui.com",
types: {
"application/rss+xml": [{url: "https://heroui.com/feed.xml", title: "HeroUI RSS Feed"}],
"application/rss+xml": [{url: "https://v2.heroui.com/feed.xml", title: "HeroUI RSS Feed"}],
},
},
};
@@ -75,7 +74,7 @@ export default function RootLayout({children}: {children: React.ReactNode}) {
<html suppressHydrationWarning dir="ltr" lang="en">
<head />
<body
className={clsx(
className={cn(
"min-h-screen text-foreground bg-background font-sans antialiased",
fonts.sans.variable,
fonts.mono.variable,
@@ -83,7 +82,6 @@ export default function RootLayout({children}: {children: React.ReactNode}) {
>
<Providers themeProps={{attribute: "class", defaultTheme: "dark"}}>
<div className="relative flex flex-col" id="app-container">
<RandomBanner />
<Navbar mobileRoutes={manifest.mobileRoutes} routes={manifest.routes} />
{children}
<Analytics mode="production" />
-2
View File
@@ -12,7 +12,6 @@ import {InstallBanner} from "@/components/marketing/install-banner";
import {Community} from "@/components/marketing/community";
import Support from "@/components/marketing/support";
import landingContent from "@/content/landing";
import {Sponsors} from "@/components/marketing/sponsors";
import {HeroUIProSection} from "@/components/marketing/heroui-pro-section";
export default async function Home() {
@@ -21,7 +20,6 @@ export default async function Home() {
<section className="flex flex-col items-center justify-center">
<Hero />
<FeaturesGrid features={landingContent.topFeatures} />
<Sponsors />
<CustomThemes />
<A11yOtb />
<DarkMode />
+3 -3
View File
@@ -1,6 +1,6 @@
import type {ReactNode, FC} from "react";
import {clsx} from "@heroui/shared-utils";
import {cn} from "@heroui/theme";
export interface BgGridContainerProps {
showGradient?: boolean;
children?: ReactNode;
@@ -14,7 +14,7 @@ export const BgGridContainer: FC<BgGridContainerProps> = ({
}) => {
return (
<div
className={clsx(
className={cn(
"relative overflow-y-hidden flex items-center border border-default-200 dark:border-default-100 px-2 py-4 rounded-lg",
"overflow-hidden",
// blur effect
@@ -35,7 +35,7 @@ export const BgGridContainer: FC<BgGridContainerProps> = ({
{children}
</div>
{/* <div
className={clsx(
className={cn(
"hidden md:block absolute z-[-1] inset-0 bg-grid-zinc-300/25 [mask-image:linear-gradient(0deg,rgba(255,255,255,0.1),rgba(255,255,255,0.6))]",
"dark:bg-grid-zinc-500/25 dark:[mask-image:linear-gradient(0deg,rgba(255,255,255,0.1),rgba(255,255,255,0.5))]",
)}
+2 -2
View File
@@ -12,7 +12,7 @@ import {CloseIcon} from "@heroui/shared-icons";
import {tv} from "tailwind-variants";
import {usePathname, useRouter} from "next/navigation";
import MultiRef from "react-multi-ref";
import {clsx} from "@heroui/shared-utils";
import {cn} from "@heroui/theme";
import scrollIntoView from "scroll-into-view-if-needed";
import {isAppleDevice, isWebKit} from "@react-aria/utils";
import {create} from "zustand";
@@ -323,7 +323,7 @@ export const Cmdk: FC<{}> = () => {
return (
<Button
isIconOnly
className={clsx(
className={cn(
"border data-[hover=true]:bg-content2 border-default-400 dark:border-default-100",
className,
)}
@@ -8,7 +8,7 @@ import css from "refractor/lang/css";
import diff from "refractor/lang/diff";
import {toHtml} from "hast-util-to-html";
import rangeParser from "parse-numeric-range";
import {clsx} from "@heroui/shared-utils";
import {cn} from "@heroui/theme";
import {Pre} from "./pre";
import {WindowActions} from "./window-actions";
@@ -141,7 +141,7 @@ const CodeBlock = React.forwardRef<HTMLPreElement, CodeBlockProps>((_props, forw
// TODO reset theme
const classes = `language-${language}`;
const codeClasses = clsx("absolute w-full px-4 pb-6", showWindowIcons ? "top-10" : "top-0");
const codeClasses = cn("absolute w-full px-4 pb-6", showWindowIcons ? "top-10" : "top-0");
if (mode === "typewriter") {
return <CodeTypewriter className={classes} css={css} value={result} {...props} />;
@@ -150,12 +150,12 @@ const CodeBlock = React.forwardRef<HTMLPreElement, CodeBlockProps>((_props, forw
return (
<Pre
ref={forwardedRef}
className={clsx("code-block", classes, className)}
className={cn("code-block", classes, className)}
data-line-numbers={showLineNumbers}
{...props}
>
{showWindowIcons && <WindowActions title={title} />}
<code dangerouslySetInnerHTML={{__html: result}} className={clsx(classes, codeClasses)} />
<code dangerouslySetInnerHTML={{__html: result}} className={cn(classes, codeClasses)} />
</Pre>
);
});
+2 -2
View File
@@ -1,5 +1,5 @@
import {forwardRef} from "react";
import {clsx} from "@heroui/shared-utils";
import {cn} from "@heroui/theme";
export interface PreProps {
className?: string;
@@ -14,7 +14,7 @@ export const Pre = forwardRef<HTMLPreElement, PreProps>(
return (
<pre
ref={forwardedRef}
className={clsx(
className={cn(
"relative w-full h-full box-border shadow-md text-white/80 leading-5 whitespace-pre text-sm font-mono bg-code-background rounded-xl [&>code]:transition-transform",
scrollClass,
className,
@@ -1,6 +1,6 @@
import React from "react";
import {tv} from "tailwind-variants";
import {clsx} from "@heroui/shared-utils";
import {cn} from "@heroui/theme";
export type WindowActionsProps = {
title?: string;
@@ -21,7 +21,7 @@ const windowIconStyles = tv({
export const WindowActions: React.FC<WindowActionsProps> = ({title, className, ...props}) => {
return (
<div
className={clsx(
className={cn(
"flex items-center sticky top-0 left-0 px-4 z-10 justify-between h-8 bg-code-background w-full",
className,
)}
+2 -2
View File
@@ -5,7 +5,7 @@ import type {FC} from "react";
import {Card, CardBody, Button, Image, Slider} from "@heroui/react";
import {useState} from "react";
import {clsx} from "@heroui/shared-utils";
import {cn} from "@heroui/theme";
import NextImage from "next/image";
import {
@@ -25,7 +25,7 @@ export const MusicPlayer: FC<MusicPlayerProps> = ({className, ...otherProps}) =>
return (
<Card
isBlurred
className={clsx("border-none bg-background/60 dark:bg-default-100/50", className)}
className={cn("border-none bg-background/60 dark:bg-default-100/50", className)}
shadow="sm"
{...otherProps}
>
@@ -2,7 +2,7 @@
import {useState} from "react";
import {Card, CardHeader, Button, Avatar, CardBody, CardFooter} from "@heroui/react";
import {clsx} from "@heroui/shared-utils";
import {cn} from "@heroui/theme";
interface UserTwitterCardProps {
className?: string;
@@ -12,7 +12,7 @@ export const UserTwitterCard = ({className}: UserTwitterCardProps) => {
const [isFollowed, setIsFollowed] = useState(false);
return (
<Card className={clsx("max-w-[300px]", className)}>
<Card className={cn("max-w-[300px]", className)}>
<CardHeader className="justify-between">
<div className="flex gap-5">
<Avatar
@@ -4,18 +4,13 @@ import type {UseCodeDemoProps} from "./use-code-demo";
import type {WindowResizerProps} from "./window-resizer";
import type {GradientBoxProps} from "@/components/gradient-box";
import React, {useCallback, useMemo, useRef, useState} from "react";
import React, {useCallback, useMemo, useRef} from "react";
import dynamic from "next/dynamic";
import {addToast, Button, Skeleton, Spinner, Tab, Tabs} from "@heroui/react";
import {Skeleton, Tab, Tabs} from "@heroui/react";
import {useInView} from "framer-motion";
import {usePostHog} from "posthog-js/react";
import {usePathname} from "next/navigation";
import {useCodeDemo} from "./use-code-demo";
import WindowResizer from "./window-resizer";
import {parseDependencies} from "./parse-dependencies";
import {openInChat} from "@/actions/open-in-chat";
const DynamicReactLiveDemo = dynamic(
() => import("./react-live-demo").then((m) => m.ReactLiveDemo),
@@ -82,11 +77,6 @@ export const CodeDemo: React.FC<CodeDemoProps> = ({
margin: "600px",
});
const pathname = usePathname();
const posthog = usePostHog();
const [isLoading, setIsLoading] = useState(false);
const {noInline, code} = useCodeDemo({
files,
});
@@ -178,64 +168,6 @@ export const CodeDemo: React.FC<CodeDemoProps> = ({
return true;
}, [showTabs, showPreview, showEditor]);
const isComponentsPage = pathname.includes("/components/");
const handleOpenInChat = useCallback(async () => {
setIsLoading(true);
// assume doc demo files are all App.jsx
const content = files["/App.jsx"];
if (!content || typeof content !== "string") {
addToast({
title: "Error",
description: "Invalid demo content",
color: "danger",
});
return;
}
const component = pathname.split("/components/")[1];
const dependencies = parseDependencies(content);
posthog.capture("CodeDemo - Open in Chat", {
component,
demo: title,
});
const newTab = window.open(undefined, "_blank");
const {data, error} = await openInChat({
component,
title,
content,
dependencies,
useWrapper: !asIframe,
});
setIsLoading(false);
if (error || !data) {
if (newTab) newTab.close();
posthog.capture("CodeDemo - Open in Chat Error", {
component,
demo: title,
error: error ?? "Unknown error",
});
addToast({
title: "Error",
description: error ?? "Unknown error",
color: "danger",
});
return;
}
if (newTab) newTab.location.href = data;
}, [pathname, title, files, posthog]);
return (
<div ref={ref} className="flex flex-col gap-2 relative">
{shouldRenderTabs ? (
@@ -255,26 +187,6 @@ export const CodeDemo: React.FC<CodeDemoProps> = ({
{editorContent}
</Tab>
</Tabs>
{isComponentsPage && (
<Button
disableRipple
className="absolute rounded-[9px] right-1 top-1 border-1 border-default-200 dark:border-default-100 data-[hover=true]:bg-default-50/80"
isDisabled={isLoading}
size="sm"
variant="bordered"
onPress={handleOpenInChat}
>
Open in Chat{" "}
{isLoading ? (
<Spinner
classNames={{wrapper: "h-4 w-4"}}
color="current"
size="sm"
variant="simple"
/>
) : null}
</Button>
)}
</>
) : (
<>
@@ -52,6 +52,6 @@ export const parseDependencies = (content: string) => {
};
const fixedVersions = {
"@internationalized/date": "3.9.0",
"@react-aria/i18n": "3.12.12",
"@internationalized/date": "3.12.2",
"@react-aria/i18n": "3.13.1",
};
@@ -3,7 +3,7 @@ import type {GradientBoxProps} from "@/components/gradient-box";
import React from "react";
import {LivePreview, LiveProvider, LiveError} from "react-live";
import {clsx} from "@heroui/shared-utils";
import {cn} from "@heroui/theme";
import * as HeroUI from "@heroui/react";
import * as intlDateUtils from "@internationalized/date";
import * as reactAriaI18n from "@react-aria/i18n";
@@ -73,7 +73,7 @@ export const ReactLiveDemo: React.FC<ReactLiveDemoProps> = ({
</div>
)}
<LivePreview
className={clsx("live-preview flex h-full w-full not-prose ", {
className={cn("live-preview flex h-full w-full not-prose ", {
"justify-center items-center": isCentered,
})}
style={{height}}
@@ -87,7 +87,7 @@ export const ReactLiveDemo: React.FC<ReactLiveDemoProps> = ({
{isGradientBox ? (
<GradientBox
isCentered
className={clsx(
className={cn(
className,
"relative overflow-y-hidden flex items-center border border-default-200 dark:border-default-100 px-2 py-4 rounded-lg overflow-hidden",
)}
@@ -99,7 +99,7 @@ export const ReactLiveDemo: React.FC<ReactLiveDemoProps> = ({
</div>
</GradientBox>
) : (
<BgGridContainer className={clsx(className, "group/code-demo")}>{content}</BgGridContainer>
<BgGridContainer className={cn(className, "group/code-demo")}>{content}</BgGridContainer>
)}
</LiveProvider>
);
@@ -4,7 +4,7 @@ import type {Language, PrismTheme} from "prism-react-renderer";
import {useIntersectionObserver} from "usehooks-ts";
import React, {forwardRef, useEffect} from "react";
import {clsx, dataAttr, getUniqueID} from "@heroui/shared-utils";
import {dataAttr, getUniqueID} from "@heroui/shared-utils";
import BaseHighlight, {defaultProps} from "prism-react-renderer";
import {debounce, omit} from "@heroui/shared-utils";
import {cn} from "@heroui/react";
@@ -124,16 +124,10 @@ const CodeBlockHighlight = ({
preRef.current = element;
}
}}
className={clsx(
className,
classNameProp,
`language-${codeLang}`,
"max-w-full contents",
{
"flex-col": isMultiLine,
"overflow-x-scroll scrollbar-hide": hideScrollBar,
},
)}
className={cn(className, classNameProp, `language-${codeLang}`, "max-w-full", {
"flex-col": isMultiLine,
"overflow-x-scroll scrollbar-hide": hideScrollBar,
})}
data-language={language}
style={style}
>
@@ -144,7 +138,7 @@ const CodeBlockHighlight = ({
<div
{...omit(lineProps, ["key"])}
key={`${i}-${getUniqueID("line-wrapper")}`}
className={clsx(
className={cn(
lineProps.className,
removeIndent ? "pr-4" : "px-4",
"relative [&>span]:relative [&>span]:z-10",
@@ -202,7 +196,7 @@ const CodeBlockHighlight = ({
)}
</BaseHighlight>
) : (
<div className={clsx(classNameProp, "w-full bg-code-background rounded-lg")} />
<div className={cn(classNameProp, "w-full bg-code-background rounded-lg")} />
)}
</div>
);
@@ -0,0 +1,15 @@
"use client";
import {Blockquote} from "./components/blockquote";
export const DeprecationMessage = () => {
return (
<Blockquote color="warning">
<b>HeroUI v3 is here!</b> We recommend starting new projects with{" "}
<a className="underline" href="https://heroui.com/" rel="noopener noreferrer" target="_blank">
<b>HeroUI v3</b>
</a>
. v2 will continue to receive patches and critical fixes.
</Blockquote>
);
};
+1
View File
@@ -2,3 +2,4 @@ export * from "./sidebar";
export * from "./toc";
export * from "./pager";
export * from "./components/code-demo";
export * from "./deprecation-message";
+9 -9
View File
@@ -20,8 +20,8 @@ import {useFocusRing} from "@react-aria/focus";
import {useTreeState} from "@react-stately/tree";
import {useSelectableCollection} from "@react-aria/selection";
import {usePress} from "@react-aria/interactions";
import {clsx, dataAttr, debounce, isEmpty} from "@heroui/shared-utils";
import {Spacer, Link as HeroUILink, Chip, dataFocusVisibleClasses} from "@heroui/react";
import {dataAttr, debounce, isEmpty} from "@heroui/shared-utils";
import {Spacer, Link as HeroUILink, Chip, dataFocusVisibleClasses, cn} from "@heroui/react";
import Link from "next/link";
import {usePathname, useRouter} from "next/navigation";
@@ -89,7 +89,7 @@ function TreeItem<T>(props: TreeItemProps<T>) {
const Component = hasChildNodes ? "ul" : "li";
const cn = clsx(
const classNames = cn(
"w-full",
"font-normal",
"before:mr-4",
@@ -125,7 +125,7 @@ function TreeItem<T>(props: TreeItemProps<T>) {
<span className="flex items-center gap-3">
<span className="font-medium sm:text-sm">{rendered}</span>
<ChevronIcon
className={clsx("transition-transform", {
className={cn("transition-transform", {
"-rotate-90": isExpanded,
})}
/>
@@ -136,14 +136,14 @@ function TreeItem<T>(props: TreeItemProps<T>) {
return (
<HeroUILink
as={item.props?.comingSoon ? "div" : Link}
className={clsx(cn, {
className={cn(classNames, {
"pointer-events-none": item.props?.comingSoon,
})}
color="foreground"
href={item.props?.comingSoon ? "#" : paths.pathname}
>
<span
className={clsx(
className={cn(
"sm:text-sm",
isSelected
? "text-primary font-medium dark:text-foreground"
@@ -195,7 +195,7 @@ function TreeItem<T>(props: TreeItemProps<T>) {
ref={ref}
aria-expanded={dataAttr(hasChildNodes ? isExpanded : undefined)}
aria-selected={dataAttr(isSelected)}
className={clsx(
className={cn(
"flex flex-col outline-solid outline-transparent w-full tap-highlight-transparent",
hasChildNodes ? "mb-4" : "first:mt-4",
// focus ring
@@ -206,7 +206,7 @@ function TreeItem<T>(props: TreeItemProps<T>) {
role="treeitem"
>
<div
className={clsx("flex items-center gap-3 cursor-pointer", {
className={cn("flex items-center gap-3 cursor-pointer", {
"pointer-events-none": item.props?.comingSoon,
})}
{...(item.props?.comingSoon ? {} : pressProps)}
@@ -349,7 +349,7 @@ export const DocsSidebar: FC<DocsSidebarProps> = ({routes, slug, tag, className}
return (
<div
className={clsx(
className={cn(
"lg:fixed mt-2 z-0 lg:h-[calc(100vh-121px)]",
isProBannerVisible ? "lg:top-32" : "lg:top-20",
className,
+5 -7
View File
@@ -4,13 +4,11 @@ import type {FC} from "react";
import type {Heading} from "@/libs/docs/utils";
import {useRef, useEffect, useState} from "react";
import {clsx} from "@heroui/shared-utils";
import {cn} from "@heroui/theme";
import {Divider, Spacer} from "@heroui/react";
import {ChevronCircleTopLinearIcon} from "@heroui/shared-icons";
import scrollIntoView from "scroll-into-view-if-needed";
import {HeroUIProCallout} from "./heroui-pro-callout";
import {useScrollSpy} from "@/hooks/use-scroll-spy";
import {useScrollPosition} from "@/hooks/use-scroll-position";
import emitter from "@/libs/emitter";
@@ -69,7 +67,7 @@ export const DocsToc: FC<DocsTocProps> = ({headings}) => {
}, []);
return (
<div className={clsx("fixed", isProBannerVisible ? "top-32" : "top-20")}>
<div className={cn("fixed", isProBannerVisible ? "top-32" : "top-20")}>
<div
ref={tocRef}
className="w-full max-w-[12rem] max-h-[calc(100vh-500px)] flex flex-col gap-4 text-left pb-16 scrollbar-hide overflow-y-scroll"
@@ -86,10 +84,11 @@ export const DocsToc: FC<DocsTocProps> = ({headings}) => {
heading.level > 1 && (
<li
key={i}
className={clsx(
className={cn(
"relative",
"transition-colors",
"font-normal",
"flex items-center text-tiny font-normal text-default-500 dark:text-default-300",
"flex items-center text-tiny font-normal text-default-500",
"data-[active=true]:text-foreground",
"dark:data-[active=true]:text-foreground",
"before:content-['']",
@@ -126,7 +125,6 @@ export const DocsToc: FC<DocsTocProps> = ({headings}) => {
</li>
</ul>
</div>
<HeroUIProCallout />
</div>
);
};
@@ -4,7 +4,7 @@ import NextLink from "next/link";
import {usePostHog} from "posthog-js/react";
import arrowRightUpIcon from "@iconify/icons-solar/arrow-right-up-linear";
import {Icon} from "@iconify/react/dist/offline";
import {clsx} from "@heroui/shared-utils";
import {cn} from "@heroui/theme";
type Props = {
className?: string;
@@ -24,13 +24,13 @@ export const FbRoadmapLink = ({className, innerClassName}: Props) => {
return (
<NextLink
className={clsx("inline-flex items-center", className)}
className={cn("inline-flex items-center", className)}
color="foreground"
href={`${process.env.NEXT_PUBLIC_FB_FEEDBACK_URL}/roadmap`}
target="_blank"
onClick={fbLinkOnClick}
>
<div className={clsx("relative", innerClassName)}>
<div className={cn("relative", innerClassName)}>
Roadmap
<Icon
className="absolute right-[-10px] top-0 outline-solid outline-transparent transition-transform group-data-[hover=true]:translate-y-0.5 [&>path]:stroke-[2.5px]"
@@ -1,92 +0,0 @@
"use client";
import {Icon} from "@iconify/react/dist/offline";
import arrowRightIcon from "@iconify/icons-solar/arrow-right-linear";
import {usePathname} from "next/navigation";
import {useEffect} from "react";
import {usePostHog} from "posthog-js/react";
import emitter from "@/libs/emitter";
const hideOnPaths = ["examples"];
export const HeroUIChatBanner = () => {
const posthog = usePostHog();
const handleClick = () => {
posthog.capture("HeroUI Chat Banner", {
action: "click",
category: "landing-page",
});
};
const pathname = usePathname();
const shouldBeVisible = !hideOnPaths.some((path) => pathname.includes(path));
useEffect(() => {
if (!shouldBeVisible) return;
// listen to scroll event, dispatch an event when scroll is at the top < 48 px
const handleScroll = () => {
if (window.scrollY < 48) {
emitter.emit("proBannerVisibilityChange", "visible");
} else {
emitter.emit("proBannerVisibilityChange", "hidden");
}
};
window.addEventListener("scroll", handleScroll);
return () => {
window.removeEventListener("scroll", handleScroll);
};
}, [shouldBeVisible]);
if (!shouldBeVisible) return null;
return (
<div className="relative z-50 isolate flex items-center gap-x-6 overflow-hidden bg-background border-b-1 border-divider px-6 py-2 sm:px-3.5 sm:before:flex-1">
<div className="flex w-full items-center justify-between md:justify-center gap-x-3">
<a
className="text-small flex items-end sm:text-[0.93rem] text-foreground hover:opacity-80 transition-opacity"
href="https://heroui.chat?utm_source=heroui.com&utm_medium=top-banner"
rel="noopener noreferrer"
target="_blank"
onClick={handleClick}
>
<span aria-label="rocket" className="hidden md:block" role="img">
🚀
</span>
<span
className="inline-flex md:ml-1 animate-text-gradient font-medium bg-clip-text text-transparent bg-[linear-gradient(90deg,#27272A_0%,#52525B_50%,#52525B_100%)] dark:bg-[linear-gradient(90deg,#E5E5E5_0%,#A1A1AA_50%,#E5E5E5_100%)]"
style={{
fontSize: "inherit",
backgroundSize: "200%",
backgroundClip: "text",
WebkitBackgroundClip: "text",
color: "transparent",
}}
>
Generate, edit and deploy beautiful apps
</span>
</a>
<a
className="flex group min-w-[120px] items-center font-semibold text-background bg-foreground shadow-sm gap-1.5 relative overflow-hidden rounded-full p-[1px] focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary"
href="https://heroui.chat?utm_source=heroui.com&utm_medium=top-banner"
rel="noopener noreferrer"
onClick={handleClick}
>
<div className="inline-flex h-full w-full cursor-pointer items-center justify-center rounded-full bg-foreground group-hover:bg-foreground/70 transition-background px-3 py-1 text-sm font-medium text-background">
HeroUI Chat
<Icon
aria-hidden="true"
className="outline-solid outline-transparent transition-transform group-hover:translate-x-0.5 [&>path]:stroke-[2px]"
icon={arrowRightIcon}
width={16}
/>
</div>
</a>
</div>
</div>
);
};
+2 -2
View File
@@ -11,7 +11,7 @@ import {
Tooltip,
} from "@heroui/react";
import {useInView} from "framer-motion";
import {clsx} from "@heroui/shared-utils";
import {cn} from "@heroui/theme";
import {
AddNoteBulkIcon,
CopyDocumentBulkIcon,
@@ -217,7 +217,7 @@ export const A11yOtb = () => {
description="Permanently delete the file"
shortcut="⌘⇧D"
startContent={
<DeleteDocumentBulkIcon className={clsx(iconClasses, "text-danger!")} />
<DeleteDocumentBulkIcon className={cn(iconClasses, "text-danger!")} />
}
>
Delete file
@@ -1,6 +1,6 @@
"use client";
import {clsx} from "@heroui/shared-utils";
import {cn} from "@heroui/theme";
import {useIsMounted} from "@/hooks/use-is-mounted";
@@ -9,7 +9,7 @@ export const BgLooper = () => {
return (
<div
className={clsx(
className={cn(
"absolute -top-20 lg:top-10 w-screen h-screen z-0 opacity-0 overflow-hidden",
"data-[mounted=true]:opacity-100 transition-opacity",
"bg-left bg-no-repeat bg-[url('/gradients/looper-pattern.svg')]",
+4 -27
View File
@@ -1,12 +1,13 @@
"use client";
import NextLink from "next/link";
import {Button, Link, Chip, Snippet} from "@heroui/react";
import {Button, Link, Snippet} from "@heroui/react";
import {ArrowRightIcon} from "@heroui/shared-icons";
import dynamic from "next/dynamic";
import {usePostHog} from "posthog-js/react";
import {FloatingComponents} from "./floating-components";
import {V3ReleaseBanner} from "./v3-release-banner";
import {GithubIcon} from "@/components/icons";
import {title, subtitle} from "@/components/primitives";
@@ -19,35 +20,11 @@ const BgLooper = dynamic(() => import("./bg-looper").then((mod) => mod.BgLooper)
export const Hero = () => {
const posthog = usePostHog();
const handlePressAnnouncement = (name: string, url: string) => {
posthog.capture("NavbarItem", {
name,
action: "press",
category: "home - hero",
data: url,
});
};
return (
<section className="flex relative overflow-hidden lg:overflow-visible w-full flex-nowrap justify-between items-center h-[calc(100vh_-_64px)] 2xl:h-[calc(84vh_-_64px)]">
<div className="relative z-20 flex flex-col w-full gap-6 lg:w-1/2 xl:mt-10">
<div className="flex justify-center w-full md:hidden">
<Chip
as={NextLink}
className="bg-default-200/50 border-1 hover:bg-default-200/80 border-default-400/50 cursor-pointer"
classNames={{
content: "font-semibold text-foreground text-xs ",
}}
color="primary"
href="/blog/v2.8.0"
variant="flat"
onClick={() => handlePressAnnouncement("HeroUI v2.8.0", "/blog/v2.8.0")}
>
HeroUI v2.8.0&nbsp;
<span aria-label="emoji" role="img">
🔥
</span>
</Chip>
<div className="w-full flex justify-center md:justify-start">
<V3ReleaseBanner />
</div>
<div className="leading-8 text-center md:leading-10 md:text-left">
<div className="inline-block">
@@ -0,0 +1,46 @@
"use client";
import {Chip} from "@heroui/react";
import {Icon} from "@iconify/react/dist/offline";
import arrowRightUpIcon from "@iconify/icons-solar/arrow-right-up-linear";
const releaseInfo = {
title: "HeroUI v3.0.0 is here!",
href: "https://heroui.com?ref=heroui-v2",
emoji: "🔥",
};
export function V3ReleaseBanner() {
return (
<Chip
as="a"
classNames={{
base: "relative transition-colors hover:bg-default-700/10 border-1 border-default-700/10 backdrop-blur-lg bg-transparent",
content: "relative flex items-center font-medium text-default-900 pr-[14px]",
}}
href={releaseInfo.href}
rel="noopener noreferrer"
target="_blank"
variant="flat"
>
<span className="mr-1 text-sm">{releaseInfo.emoji}</span>
<span
className="animate-text-gradient inline-flex bg-clip-text font-medium text-transparent bg-[linear-gradient(90deg,#0485f7_0%,#BA8BF6_50%,#0485f7_100%)] dark:bg-[linear-gradient(90deg,#0485f7_0%,#BA8BF6_50%,#0485f7_100%)]"
style={{
fontSize: "inherit",
backgroundSize: "200%",
backgroundClip: "text",
WebkitBackgroundClip: "text",
color: "transparent",
}}
>
{releaseInfo.title}
</span>
<Icon
className="absolute right-[2px] top-1/2 -translate-y-1/2 text-default-500/60 outline-solid outline-transparent transition-transform group-data-[hover=true]:translate-y-0.5 [&>path]:stroke-[2.5px]"
icon={arrowRightUpIcon}
width={10}
/>
</Chip>
);
}
@@ -1,5 +1,5 @@
import {memo} from "react";
import clsx from "clsx";
import {cn} from "@heroui/theme";
import {sectionWrapper, title, titleWrapper, subtitle} from "../../primitives";
import Marquee from "../marquee";
@@ -94,7 +94,7 @@ export const HeroUIProSection = () => {
<HeroUIProImage />
</Marquee>
<div
className={clsx(
className={cn(
"absolute inset-0 pointer-events-none z-20 bg-white dark:bg-black",
"[-webkit-mask-image:radial-gradient(at_70%_50%,_rgba(255,255,255,0)_20%,_rgba(255,255,255,0.8)_40%,_rgba(0,0,0,1)_60%)]",
)}
@@ -2,7 +2,7 @@
import {Button, Link} from "@heroui/react";
import {ArrowRightIcon} from "@heroui/shared-icons";
import {clsx} from "@heroui/shared-utils";
import {cn} from "@heroui/theme";
import NextLink from "next/link";
import {Code} from "@heroui/react";
import {usePostHog} from "posthog-js/react";
@@ -114,7 +114,7 @@ export const InstallBanner = () => {
</div>
</div>
<div
className={clsx(
className={cn(
"absolute -top-20 lg:top-10 -translate-y-1/2 w-screen h-screen -z-50 opacity-0",
"data-[mounted=true]:opacity-100 transition-opacity",
"bg-left bg-no-repeat bg-[url('/gradients/looper-pattern.svg')]",
+8 -6
View File
@@ -1,6 +1,6 @@
import type {Language} from "prism-react-renderer";
import {clsx} from "@heroui/shared-utils";
import {cn} from "@heroui/theme";
import * as Components from "@heroui/react";
import NextImage from "next/image";
import {usePostHog} from "posthog-js/react";
@@ -14,6 +14,7 @@ import {CarbonAd} from "@/components/ads/carbon-ad";
import * as DocsComponents from "@/components/docs/components";
import * as BlogComponents from "@/components/blog/components";
import {Codeblock} from "@/components/docs/components";
import {DeprecationMessage} from "@/components/docs/deprecation-message";
import {VirtualAnchor, virtualAnchorEncode} from "@/components/virtual-anchor";
import {
Table as StaticTable,
@@ -36,7 +37,7 @@ const Table: React.FC<{children?: React.ReactNode}> = ({children}) => {
const Thead: React.FC<{children?: React.ReactNode}> = ({children}) => {
return (
<thead
className={clsx(
className={cn(
"[&>tr]:h-12",
"[&>tr>th]:py-0",
"[&>tr>th]:align-middle",
@@ -94,7 +95,7 @@ const LinkedHeading: React.FC<LinkedHeadingProps> = ({
return (
<Component
className={clsx({"linked-heading": linked}, linked ? {} : className)}
className={cn({"linked-heading": linked}, linked ? {} : className)}
data-id={id}
data-level={level}
data-name={props.children}
@@ -117,7 +118,7 @@ const List: React.FC<{children?: React.ReactNode}> = ({children}) => {
const InlineCode = ({children, className}: {children?: React.ReactNode; className?: string}) => {
return (
<Components.Code
className={clsx(
className={cn(
'p-0 relative before:content-["`"] after:content-["`"] font-semibold font-mono text-small rounded-md text-default-900 dark:text-default-500 bg-transparent',
className,
)}
@@ -151,7 +152,7 @@ const Code = ({
fullWidth
hideSymbol
classNames={{
base: clsx(
base: cn(
"px-0 bg-code-background text-code-foreground",
{
"items-start": isMultiLine,
@@ -219,7 +220,7 @@ const InlineCodeChip = ({
}) => {
return (
<InlineCode
className={clsx(
className={cn(
"before:hidden after:hidden text-tiny rounded-md text-default-600 bg-default-100 dark:bg-default-100/80 px-1.5 py-0.5",
className,
)}
@@ -362,6 +363,7 @@ export const MDXComponents = {
tr: Trow,
td: Tcol,
CarbonAd,
DeprecationMessage,
code: Code,
ul: List,
a: (props: React.HTMLAttributes<HTMLAnchorElement>) => <Link {...props} />,
+58 -31
View File
@@ -1,6 +1,6 @@
"use client";
import type {FC, ReactNode} from "react";
import type {FC, Key, ReactNode} from "react";
import type {Route} from "@/libs/docs/page";
import {useRef, useState, useMemo, useCallback} from "react";
@@ -15,12 +15,16 @@ import {
Link,
Button,
Kbd,
Chip,
Dropdown,
DropdownMenu,
DropdownItem,
DropdownTrigger,
Divider,
} from "@heroui/react";
import {dataFocusVisibleClasses} from "@heroui/theme";
import {ChevronDownIcon, LinkIcon} from "@heroui/shared-icons";
import {isAppleDevice} from "@react-aria/utils";
import {clsx} from "@heroui/shared-utils";
import {cn} from "@heroui/theme";
import NextLink from "next/link";
import {usePathname} from "next/navigation";
import {motion, AnimatePresence} from "framer-motion";
@@ -29,8 +33,6 @@ import {usePress} from "@react-aria/interactions";
import {useFocusRing} from "@react-aria/focus";
import {usePostHog} from "posthog-js/react";
import {FbRoadmapLink} from "./featurebase/fb-roadmap-link";
import {currentVersion} from "@/utils/version";
import {siteConfig} from "@/config/site";
import {Logo, ThemeSwitch} from "@/components";
@@ -91,11 +93,23 @@ export const Navbar: FC<NavbarProps> = ({children, routes, mobileRoutes = [], sl
"/docs/guide/upgrade-to-v2",
];
const navLinkClasses = clsx(
const navLinkClasses = cn(
link({color: "foreground"}),
"data-[active=true]:text-primary data-[active=true]:font-semibold",
);
const handleVersionChange = useCallback((key: Key) => {
if (key === "v3") {
const newWindow = window.open(
"https://v3.heroui.com?ref=heroui-v2",
"_blank",
"noopener,noreferrer",
);
if (newWindow) newWindow.opener = null;
}
}, []);
const handlePressNavbarItem = useCallback(
(name: string, url: string) => {
posthog.capture("NavbarItem", {
@@ -134,24 +148,40 @@ export const Navbar: FC<NavbarProps> = ({children, routes, mobileRoutes = [], sl
</Button>
);
const versionChip = useMemo(() => {
const versionDropdown = useMemo(() => {
return ref.current ? (
<AnimatePresence>
{isMounted && (
<motion.div animate={{opacity: 1}} exit={{opacity: 0}} initial={{opacity: 0}}>
<Chip
className="max-w-[44px] hidden h-6 w-[44px] py-1 min-w-fit sm:flex gap-0.5 bg-default-400/20 dark:bg-default-500/20"
classNames={{
content: "font-medium text-default-500 text-xs",
}}
>
v{currentVersion}
</Chip>
</motion.div>
)}
</AnimatePresence>
<Dropdown placement="bottom-start" portalContainer={ref.current}>
<AnimatePresence>
{isMounted && (
<motion.div animate={{opacity: 1}} exit={{opacity: 0}} initial={{opacity: 0}}>
<DropdownTrigger>
<Button
className="min-w-[74px] max-w-[74px] hidden font-medium text-default-500 text-xs h-6 w-[74px] py-1 min-w-fit sm:flex gap-0.5 bg-default-400/20 dark:bg-default-500/20"
endContent={<ChevronDownIcon className="text-tiny" />}
radius="full"
size="sm"
variant="flat"
>
v{currentVersion}
</Button>
</DropdownTrigger>
</motion.div>
)}
</AnimatePresence>
<DropdownMenu
aria-label="HeroUI versions"
defaultSelectedKeys={["v2"]}
selectionMode="single"
onAction={handleVersionChange}
>
<DropdownItem key="v2">v{currentVersion}</DropdownItem>
<DropdownItem key="v3" endContent={<LinkIcon />}>
v3.0.0
</DropdownItem>
</DropdownMenu>
</Dropdown>
) : (
<div className="w-[44px]" />
<div className="w-[74px]" />
);
}, [ref.current, isMounted]);
@@ -162,7 +192,7 @@ export const Navbar: FC<NavbarProps> = ({children, routes, mobileRoutes = [], sl
return (
<HeroUINavbar
ref={ref}
className={clsx({
className={cn({
"z-100001": isMenuOpen,
})}
classNames={{
@@ -184,8 +214,8 @@ export const Navbar: FC<NavbarProps> = ({children, routes, mobileRoutes = [], sl
>
<Logo className="h-6" />
</NextLink>
{versionChip}
<Chip
{versionDropdown}
{/* <Chip
as={NextLink}
className="hidden sm:flex bg-default-200/50 border-1 hover:bg-default-200/80 border-default-400/50 cursor-pointer"
classNames={{
@@ -200,7 +230,7 @@ export const Navbar: FC<NavbarProps> = ({children, routes, mobileRoutes = [], sl
<span aria-label="emoji" role="img">
🔥
</span>
</Chip>
</Chip> */}
</NavbarBrand>
</NavbarContent>
@@ -225,7 +255,7 @@ export const Navbar: FC<NavbarProps> = ({children, routes, mobileRoutes = [], sl
</NavbarItem>
<NavbarItem className="flex h-full items-center">
<button
className={clsx(
className={cn(
"transition-opacity p-1 hover:opacity-80 rounded-full cursor-pointer outline-solid outline-transparent",
// focus ring
...dataFocusVisibleClasses,
@@ -269,7 +299,7 @@ export const Navbar: FC<NavbarProps> = ({children, routes, mobileRoutes = [], sl
Components
</NextLink>
</NavbarItem>
{/*
{/*
// TODO: add playground
<NavbarItem>
<NextLink
@@ -316,9 +346,6 @@ export const Navbar: FC<NavbarProps> = ({children, routes, mobileRoutes = [], sl
Theme
</NextLink>
</NavbarItem>
<NavbarItem>
<FbRoadmapLink className={navLinkClasses} />
</NavbarItem>
</ul>
<Divider className="h-7 hidden lg:flex" orientation="vertical" />
<NavbarItem className="hidden sm:flex gap-2">
+2 -2
View File
@@ -2,7 +2,7 @@ import type {ButtonProps} from "@heroui/react";
import {forwardRef} from "react";
import {Button} from "@heroui/react";
import {clsx} from "@heroui/shared-utils";
import {cn} from "@heroui/theme";
export interface PreviewButtonProps extends ButtonProps {
icon: React.ReactNode;
@@ -16,7 +16,7 @@ export const PreviewButton = forwardRef<HTMLButtonElement | null, PreviewButtonP
<Button
ref={ref}
isIconOnly
className={clsx(
className={cn(
"relative z-50 text-zinc-300 top-8 border-1 border-transparent bg-transparent before:bg-white/10 before:content-[''] before:block before:z-[-1] before:absolute before:inset-0 before:backdrop-blur-md before:backdrop-saturate-100 before:rounded-lg",
className,
)}
-26
View File
@@ -1,26 +0,0 @@
"use client";
import {useState, useEffect} from "react";
import {HeroUIChatBanner} from "@/components/heroui-chat-banner";
import {ProBanner} from "@/components/pro-banner";
export const RandomBanner = () => {
const [showChatBanner, setShowChatBanner] = useState<boolean | null>(null);
useEffect(() => {
const bannerCount = parseInt(sessionStorage.getItem("bannerCount") || "0", 10);
const shouldShowChat = bannerCount % 2 === 0;
setShowChatBanner(shouldShowChat);
sessionStorage.setItem("bannerCount", String(bannerCount + 1));
}, []);
if (showChatBanner === null) {
return <div className="h-[47px] border-b border-divider" />;
}
return showChatBanner ? <HeroUIChatBanner /> : <ProBanner />;
};
@@ -1,6 +1,6 @@
import * as React from "react";
import {useSandpackNavigation} from "@codesandbox/sandpack-react";
import {clsx} from "@heroui/shared-utils";
import {cn} from "@heroui/theme";
import {RotateRightLinearIcon} from "@/components/icons";
@@ -16,7 +16,7 @@ export const RefreshButton = ({clientId}: RefreshButtonProps): JSX.Element => {
return (
<button
className={clsx("sp-button", "sp-icon-standalone")}
className={cn("sp-button", "sp-icon-standalone")}
title="Refresh Sandpack"
type="button"
onClick={refresh}
+2 -2
View File
@@ -2,7 +2,7 @@ import type {FC, ReactNode} from "react";
import {useMemo} from "react";
import {parseToRgba} from "color2k";
import {clsx} from "@heroui/shared-utils";
import {cn} from "@heroui/theme";
import {useIsSSR} from "@react-aria/ssr";
export interface SonarPulseProps {
children: ReactNode;
@@ -49,7 +49,7 @@ export const SonarPulse: FC<SonarPulseProps> = ({
circles.push(
<div
key={i}
className={clsx("circle", `circle-${i}`, "absolute", {
className={cn("circle", `circle-${i}`, "absolute", {
"animate-expand-opacity": playState === "running",
})}
style={{
+3 -3
View File
@@ -6,7 +6,7 @@ import type {SwitchProps} from "@heroui/react";
import {VisuallyHidden} from "@react-aria/visually-hidden";
import {useSwitch} from "@heroui/react";
import {useTheme} from "next-themes";
import {clsx} from "@heroui/shared-utils";
import {cn} from "@heroui/theme";
import {useIsSSR} from "@react-aria/ssr";
import {usePostHog} from "posthog-js/react";
@@ -50,7 +50,7 @@ export const ThemeSwitch: FC<ThemeSwitchProps> = ({className, classNames}) => {
return (
<Component
{...getBaseProps({
className: clsx(
className: cn(
"p-1 w-8 h-8 transition-opacity hover:opacity-80 cursor-pointer",
className,
classNames?.base,
@@ -69,7 +69,7 @@ export const ThemeSwitch: FC<ThemeSwitchProps> = ({className, classNames}) => {
<div
{...getWrapperProps()}
className={slots.wrapper({
class: clsx(
class: cn(
[
"w-auto h-auto",
"bg-transparent",
@@ -6,7 +6,7 @@ import {HexColorInput, HexColorPicker} from "react-colorful";
import Values from "values.js";
import {readableColor} from "color2k";
import {useTheme} from "next-themes";
import {clsx} from "@heroui/shared-utils";
import {cn} from "@heroui/theme";
import {colorValuesToRgb, getColorWeight} from "../utils/colors";
@@ -49,7 +49,7 @@ export function ColorPicker({hexColor, type, onChange, onClose}: ColorPickerProp
<Button
fullWidth
aria-label={`Change ${type} color`}
className={clsx(
className={cn(
getColor(type),
"rounded-lg min-w-9 w-9 h-9",
"border border-black/10 dark:border-white/10",
@@ -1,5 +1,5 @@
import {Tooltip} from "@heroui/react";
import {clsx} from "@heroui/shared-utils";
import {cn} from "@heroui/theme";
import {CircleInfo} from "@/components/icons";
@@ -35,7 +35,7 @@ export function ConfigSection({
</Tooltip>
)}
</div>
<div className={clsx("flex flex-wrap gap-2 mt-3")}>{children}</div>
<div className={cn("flex flex-wrap gap-2 mt-3")}>{children}</div>
</div>
);
}
@@ -1,5 +1,5 @@
import {Button} from "@heroui/react";
import {clsx} from "@heroui/shared-utils";
import {cn} from "@heroui/theme";
interface EditableButtonProps {
title: any;
@@ -11,7 +11,7 @@ interface EditableButtonProps {
const EditableButton = ({title, className, value, setValue}: EditableButtonProps) => {
return (
<Button
className={clsx(
className={cn(
"group h-auto py-4 flex flex-col justify-between gap-y-2 min-w-auto w-auto border-black/20 dark:border-white/20",
value === title ? "border-black/60 dark:border-white/60" : "",
)}
@@ -21,7 +21,7 @@ const EditableButton = ({title, className, value, setValue}: EditableButtonProps
}}
>
<div
className={clsx(
className={cn(
"h-7 w-7 border-t-2 border-l-2 border-blue-400 bg-gradient-to-b from-[#0077ff1A] to-[#92c5ff00]",
className,
)}
@@ -1,7 +1,7 @@
import type {FontName, FontType} from "../../types";
import {Button} from "@heroui/react";
import {clsx} from "@heroui/shared-utils";
import {cn} from "@heroui/theme";
interface FontButtonProps {
title: FontName;
@@ -38,7 +38,7 @@ const FontButton = ({title, value, setValue}: FontButtonProps) => {
return (
<Button
className={clsx(
className={cn(
"group h-24 flex flex-col justify-center items-center gap-y-2 px-0 border-black/20 dark:border-white/20",
value === title ? "border-black/60 dark:border-white/60" : "",
)}
@@ -19,7 +19,6 @@ import {useLocalStorage} from "usehooks-ts";
import {Icon} from "@iconify/react/dist/offline";
import LinkSquareIcon from "@iconify/icons-solar/link-square-linear";
import {ArrowLeftIcon, ChevronIcon, ChevronUpIcon, CloseIcon} from "@heroui/shared-icons";
import {clsx} from "@heroui/shared-utils";
import {useThemeBuilder} from "../../provider";
import {configKey, syncThemesKey, initialConfig} from "../../constants";
@@ -234,7 +233,7 @@ export default function Configuration() {
return (
<div key={template.name} className="flex flex-col items-center">
<Button
className={clsx(
className={cn(
"p-0 min-w-0 w-auto h-10 border border-black/5 gap-0 rounded-sm overflow-hidden m-[3px]",
templateTheme === template.name
? "outline-1 outline-foreground-800"
@@ -1,6 +1,6 @@
import type {ConfigColors} from "../../types";
import {clsx} from "@heroui/shared-utils";
import {cn} from "@heroui/theme";
interface SwatchProps {
colors: {background: string} & ConfigColors["baseColor"];
@@ -10,9 +10,9 @@ interface SwatchProps {
export default function Swatch({colors, className, innerClassName}: SwatchProps) {
return (
<div className={clsx("flex h-6", className)}>
<div className={cn("flex h-6", className)}>
{Object.entries(colors).map(([key, value]) => (
<div key={key} className={clsx("w-2 h-full", innerClassName)} style={{background: value}} />
<div key={key} className={cn("w-2 h-full", innerClassName)} style={{background: value}} />
))}
</div>
);
@@ -1,5 +1,5 @@
import {Button} from "@heroui/react";
import {clsx} from "@heroui/shared-utils";
import {cn} from "@heroui/theme";
interface ValueButtonProps<T extends string | number> {
currentValue: T;
@@ -19,7 +19,7 @@ const ValueButton = ({
isIconOnly
aria-checked={value === currentValue}
aria-label={`Select ${value}${endContent ?? ""}`}
className={clsx(
className={cn(
"group h-auto w-auto rounded-md p-0.5 px-1 text-sm font-normal border-black/20 dark:border-white/20",
value === currentValue ? "border-black/60 dark:border-white/60" : "",
)}
@@ -3,7 +3,7 @@ import type {Border, HeroUIScaling} from "../../types";
import {cloneElement} from "react";
import {Avatar as HeroUIAvatar} from "@heroui/react";
import {clsx} from "@heroui/shared-utils";
import {cn} from "@heroui/theme";
import {ShowcaseComponent} from "../showcase-component";
import {useThemeBuilder} from "../../provider";
@@ -55,23 +55,23 @@ const Section = ({
switch (scaling) {
case 90: {
className = clsx("h-6 w-6", borderClassName);
className = cn("h-6 w-6", borderClassName) as string;
break;
}
case 95: {
className = clsx("h-8 w-8", borderClassName);
className = cn("h-8 w-8", borderClassName) as string;
break;
}
case 100: {
className = clsx("h-10 w-10", borderClassName);
className = cn("h-10 w-10", borderClassName) as string;
break;
}
case 105: {
className = clsx("h-12 w-12", borderClassName);
className = cn("h-12 w-12", borderClassName) as string;
break;
}
case 110: {
className = clsx("h-14 w-14", borderClassName);
className = cn("h-14 w-14", borderClassName) as string;
break;
}
}
@@ -3,7 +3,7 @@ import type {Border} from "../../types";
import {cloneElement} from "react";
import {Button as HeroUIButton} from "@heroui/react";
import {clsx} from "@heroui/shared-utils";
import {cn} from "@heroui/theme";
import {ShowcaseComponent} from "../showcase-component";
import {useThemeBuilder} from "../../provider";
@@ -28,7 +28,7 @@ const SectionBase = ({
return (
<HeroUIButton
key={color}
className={clsx(className, "capitalize")}
className={cn(className, "capitalize")}
color={color}
isDisabled={isDisabled}
radius={radius}
@@ -74,7 +74,7 @@ const Section = ({
{variants.map((variant) => (
<SectionBase
key={variant}
className={clsx(
className={cn(
className,
variant === "bordered" || variant === "faded" || variant === "ghost" ? borderClass : "",
)}
@@ -3,7 +3,7 @@ import type {Border, HeroUIScaling} from "../../types";
import {cloneElement} from "react";
import {Chip as HeroUIChip} from "@heroui/react";
import {clsx} from "@heroui/shared-utils";
import {cn} from "@heroui/theme";
import {ShowcaseComponent} from "../showcase-component";
import {useThemeBuilder} from "../../provider";
@@ -28,7 +28,7 @@ const SectionBase = ({
return (
<HeroUIChip
key={radius}
className={clsx(className, "capitalize")}
className={cn(className, "capitalize")}
color={color}
isDisabled={isDisabled}
radius={radius}
@@ -90,7 +90,7 @@ const Section = ({
{variants.map((variant, idx) =>
cloneElement(<SectionBase key={idx} />, {
color,
className: clsx(
className: cn(
className,
variant === "bordered" || variant === "faded" ? borderClass : "",
),
@@ -2,7 +2,7 @@ import type {InputProps} from "@heroui/react";
import type {Border, HeroUIScaling} from "../../types";
import {Input} from "@heroui/react";
import {clsx} from "@heroui/shared-utils";
import {cn} from "@heroui/theme";
import {ShowcaseComponent} from "../showcase-component";
import {useThemeBuilder} from "../../provider";
@@ -88,7 +88,7 @@ const Section = ({
key={idx}
classNames={{
...classNames,
inputWrapper: clsx(clsx(variant === "bordered" && borderClass)),
inputWrapper: cn(cn(variant === "bordered" && borderClass)),
}}
color={color}
isDisabled={false}
+2 -2
View File
@@ -39,7 +39,7 @@ export const initialLightTheme: ConfigColors = {
foreground: colors.black,
background: colors.white,
focus: colors.blue[500],
overlay: colors.black,
overlay: colors.white,
},
contentColor: {
content1: colors.white,
@@ -64,7 +64,7 @@ export const initialDarkTheme: ConfigColors = {
foreground: colors.white,
background: colors.black,
focus: colors.blue[500],
overlay: colors.white,
overlay: colors.black,
},
contentColor: {
content1: colors.zinc[900],
@@ -1,8 +1,6 @@
import type {Config} from "../types";
import {colors} from "@heroui/theme";
import {initialLayout} from "../constants";
import {initialDarkTheme, initialLayout, initialLightTheme} from "../constants";
export const coffee: Config = {
name: "coffee",
@@ -20,7 +18,7 @@ export const coffee: Config = {
layoutColor: {
foreground: "#a27225",
background: "#fffbf6",
overlay: colors.black,
overlay: initialLightTheme.layoutColor.overlay,
focus: "#db924b",
},
contentColor: {
@@ -45,7 +43,7 @@ export const coffee: Config = {
foreground: "#c59f60",
background: "#20161F",
focus: "#db924b",
overlay: colors.white,
overlay: initialDarkTheme.layoutColor.overlay,
},
contentColor: {
content1: "#2c1f2b",
@@ -1,8 +1,6 @@
import type {Config} from "../types";
import {colors} from "@heroui/theme";
import {initialLayout} from "../constants";
import {initialDarkTheme, initialLayout, initialLightTheme} from "../constants";
export const elegant: Config = {
name: "elegant",
@@ -20,7 +18,7 @@ export const elegant: Config = {
layoutColor: {
foreground: "#4a4a4a",
background: "#ffffff",
overlay: colors.black,
overlay: initialLightTheme.layoutColor.overlay,
focus: "#db924b",
},
contentColor: {
@@ -44,7 +42,7 @@ export const elegant: Config = {
layoutColor: {
foreground: "#b0b0b0",
background: "#000000",
overlay: colors.white,
overlay: initialDarkTheme.layoutColor.overlay,
focus: "#000000",
},
contentColor: {
@@ -1,8 +1,6 @@
import type {Config} from "../types";
import {colors} from "@heroui/theme";
import {initialLayout} from "../constants";
import {initialDarkTheme, initialLayout, initialLightTheme} from "../constants";
export const modern: Config = {
name: "modern",
@@ -20,7 +18,7 @@ export const modern: Config = {
layoutColor: {
foreground: "#4a3d77",
background: "#f9f7fd",
overlay: colors.black,
overlay: initialLightTheme.layoutColor.overlay,
focus: "#7828c8",
},
contentColor: {
@@ -44,7 +42,7 @@ export const modern: Config = {
layoutColor: {
foreground: "#d0aaff",
background: "#1b1526",
overlay: colors.white,
overlay: initialDarkTheme.layoutColor.overlay,
focus: "#9353d3",
},
contentColor: {
@@ -1,8 +1,6 @@
import type {Config} from "../types";
import {colors} from "@heroui/theme";
import {initialLayout} from "../constants";
import {initialDarkTheme, initialLayout, initialLightTheme} from "../constants";
export const retro: Config = {
name: "retro",
@@ -20,7 +18,7 @@ export const retro: Config = {
layoutColor: {
foreground: "#5A4A42",
background: "#F4E8D1",
overlay: colors.black,
overlay: initialLightTheme.layoutColor.overlay,
focus: "#FFD34E",
},
contentColor: {
@@ -44,7 +42,7 @@ export const retro: Config = {
layoutColor: {
foreground: "#000000",
background: "#E1CA9E",
overlay: colors.white,
overlay: initialDarkTheme.layoutColor.overlay,
focus: "#FFD34E",
},
contentColor: {
+4 -4
View File
@@ -1,6 +1,6 @@
{
"stars": { "raw": 24951, "formatted": "25K" },
"forks": 1852,
"subscribers": 90,
"openIssues": 242
"stars": { "raw": 29656, "formatted": "29.7K" },
"forks": 2163,
"subscribers": 89,
"openIssues": 41
}
+2 -7
View File
@@ -473,7 +473,8 @@
"key": "cli-api",
"title": "HeroUI CLI",
"keywords": "api references, heroui, api, cli",
"path": "/docs/api-references/cli-api.mdx"
"path": "/docs/api-references/cli-api.mdx",
"updated": true
},
{
"key": "heroui-provider",
@@ -514,12 +515,6 @@
"title": "Figma",
"keywords": "figma, heroui, design, ui kit",
"path": "/docs/guide/figma.mdx"
},
{
"key": "roadmap",
"title": "Roadmap",
"keywords": "roadmap, heroui",
"path": "#"
}
]
}
File diff suppressed because it is too large Load Diff
+6 -6
View File
@@ -3,20 +3,20 @@ export type SiteConfig = typeof siteConfig;
export const siteConfig = {
name: "HeroUI (Previously NextUI) - Beautiful, fast and modern React UI Library",
description: "Make beautiful websites regardless of your design experience.",
ogImage: "https://heroui.com/heroui.jpg",
ogImage: "https://v2.heroui.com/heroui.jpg",
author: "Junior Garcia",
email: "jrgarciadev@gmail.com",
siteUrl: "https://heroui.com",
siteUrl: "https://v2.heroui.com",
creator: "@hero_ui",
openGraph: {
type: "website",
locale: "en_US",
url: "https://heroui.com",
url: "https://v2.heroui.com",
siteName: "HeroUI (Previously NextUI)",
description: "Beautiful, fast and modern React UI Library",
images: [
{
url: "https://heroui.com/heroui.jpg",
url: "https://v2.heroui.com/heroui.jpg",
width: 1200,
height: 630,
alt: "HeroUI (Previously NextUI)",
@@ -27,13 +27,13 @@ export const siteConfig = {
card: "summary_large_image",
title: "HeroUI (Previously NextUI) - Beautiful, fast and modern React UI Library",
description: "Make beautiful websites regardless of your design experience.",
image: "https://heroui.com/heroui.jpg",
image: "https://v2.heroui.com/heroui.jpg",
creator: "@hero_ui",
},
links: {
github: "https://github.com/heroui-inc/heroui",
twitter: "https://x.com/hero_ui",
docs: "https://heroui.com",
docs: "https://v2.heroui.com",
discord: "https://discord.gg/9b6yyZKmH4",
sponsor: "https://patreon.com/jrgarciadev",
portfolio: "https://jrgarciadev.com",
+1 -1
View File
@@ -144,7 +144,7 @@ nextui add --all
<Spacer y={4} />
> The CLI is currentl in `Alpha` stage, we're working on adding more features and improvements. If you find any issues or have any suggestions, please let us know by [opening an issue](https://github.com/heroui-inc/heroui-cli/issues/new).
> The CLI is currently in `Alpha` stage, we're working on adding more features and improvements. If you find any issues or have any suggestions, please let us know by [opening an issue](https://github.com/heroui-inc/heroui-cli/issues/new).
To learn more about the CLI and its commands, please refer to the [CLI documentation](/docs/guide/cli) and the [CLI API reference](/docs/api-references/cli-api).
+1 -1
View File
@@ -93,7 +93,7 @@ The new `outside-top` option ensures that labels are consistently displayed at t
### Select
Two new properties `isClearable` and `onClear` have been introduced in the Select component. A clear button is visible when a value is slected and a callback function triggered upon clearing the selection for custom handling.
Two new properties `isClearable` and `onClear` have been introduced in the Select component. A clear button is visible when a value is selected and a callback function triggered upon clearing the selection for custom handling.
<CodeDemo title="Clearable" files={selectIsClearable} />
@@ -29,23 +29,24 @@ export const animals = [
];
export default function App() {
const colors = ["default", "primary", "secondary", "success", "warning", "danger"];
const [value, setValue] = React.useState("cat");
const onChange = (key) => {
setValue(key);
};
return (
<div className="w-full flex flex-row flex-wrap gap-4">
{colors.map((color) => (
<Autocomplete
key={color}
className="max-w-xs"
color={color}
defaultItems={animals}
defaultSelectedKey={"cat"}
label="Favorite Animal"
placeholder="Search an animal"
>
{(item) => <AutocompleteItem key={item.key}>{item.label}</AutocompleteItem>}
</Autocomplete>
))}
<div className="flex w-full max-w-xs flex-col gap-2">
<Autocomplete
fullWidth
defaultItems={animals}
label="Favorite Animal"
value={value}
onChange={onChange}
>
{(item) => <AutocompleteItem key={item.key}>{item.label}</AutocompleteItem>}
</Autocomplete>
<p className="text-default-500">Selected: {value}</p>
</div>
);
}
@@ -41,7 +41,7 @@ export default function App() {
placeholder="Search an animal"
selectedKey={key}
variant="bordered"
onSelectionChange={setValue}
onChange={setValue}
>
{(item) => <AutocompleteItem key={item.key}>{item.label}</AutocompleteItem>}
</Autocomplete>
@@ -45,8 +45,8 @@ export default function App() {
placeholder="Search an animal"
selectedKey={key}
variant="bordered"
onChange={setValue}
onClose={() => setTouched(true)}
onSelectionChange={setValue}
>
{(item) => <AutocompleteItem key={item.key}>{item.label}</AutocompleteItem>}
</Autocomplete>
@@ -32,7 +32,7 @@ export default function App() {
const [value, setValue] = React.useState("");
const [selectedKey, setSelectedKey] = React.useState(null);
const onSelectionChange = (id) => {
const onChange = (id) => {
setSelectedKey(id);
};
@@ -48,8 +48,8 @@ export default function App() {
defaultItems={animals}
label="Search an animal"
variant="bordered"
onChange={onChange}
onInputChange={onInputChange}
onSelectionChange={onSelectionChange}
>
{(item) => <AutocompleteItem key={item.key}>{item.label}</AutocompleteItem>}
</Autocomplete>
@@ -33,7 +33,7 @@ export default function App() {
const [value, setValue] = React.useState<string>("");
const [selectedKey, setSelectedKey] = React.useState<React.Key | null>(null);
const onSelectionChange = (key: React.Key | null) => {
const onChange = (key: React.Key | null) => {
setSelectedKey(key);
};
@@ -49,8 +49,8 @@ export default function App() {
defaultItems={animals}
label="Search an animal"
variant="underlined"
onChange={onChange}
onInputChange={onInputChange}
onSelectionChange={onSelectionChange}
>
{(item) => <AutocompleteItem key={item.key}>{item.label}</AutocompleteItem>}
</Autocomplete>
@@ -44,7 +44,7 @@ export default function App() {
// Specify how each of the Autocomplete values should change when an
// option is selected from the list box
const onSelectionChange = (key) => {
const onChange = (key) => {
setFieldState((prevState) => {
let selectedItem = prevState.items.find((option) => option.value === key);
@@ -86,9 +86,9 @@ export default function App() {
placeholder="Search an animal"
selectedKey={fieldState.selectedKey}
variant="bordered"
onChange={onChange}
onInputChange={onInputChange}
onOpenChange={onOpenChange}
onSelectionChange={onSelectionChange}
>
{(item) => <AutocompleteItem key={item.key}>{item.label}</AutocompleteItem>}
</Autocomplete>
@@ -53,7 +53,7 @@ export default function App() {
// Specify how each of the Autocomplete values should change when an
// option is selected from the list box
const onSelectionChange = (key: React.Key | null) => {
const onChange = (key: React.Key | null) => {
setFieldState((prevState) => {
let selectedItem = prevState.items.find((option) => option.key === key);
@@ -95,9 +95,9 @@ export default function App() {
placeholder="Search an animal"
selectedKey={fieldState.selectedKey}
variant="bordered"
onChange={onChange}
onInputChange={onInputChange}
onOpenChange={onOpenChange}
onSelectionChange={onSelectionChange}
>
{(item) => <AutocompleteItem key={item.key}>{item.label}</AutocompleteItem>}
</Autocomplete>
@@ -29,13 +29,13 @@ export const animals = [
];
export default function App() {
const placements = ["inside", "outside", "outside-left"];
const placements = ["inside", "outside", "outside-left", "outside-top"];
return (
<div className="w-full flex flex-col gap-4">
<div className="flex flex-col gap-2">
<div className="w-full grid grid-cols-1 md:grid-cols-2 gap-8">
<div className="flex flex-col gap-4">
<h3 className="text-default-500 text-small">Without placeholder</h3>
<div className="flex w-full flex-wrap items-end md:flex-nowrap mb-6 md:mb-0 gap-4">
<div className="flex flex-col gap-4">
{placements.map((placement) => (
<Autocomplete
key={placement}
@@ -49,9 +49,9 @@ export default function App() {
))}
</div>
</div>
<div className="flex flex-col gap-2">
<div className="flex flex-col gap-4">
<h3 className="text-default-500 text-small">With placeholder</h3>
<div className="flex w-full flex-wrap items-end md:flex-nowrap mb-6 md:mb-0 gap-4">
<div className="flex flex-col gap-4">
{placements.map((placement) => (
<Autocomplete
key={placement}
@@ -2,7 +2,7 @@ import {DateInput} from "@heroui/react";
import {CalendarDate} from "@internationalized/date";
export default function App() {
const placements = ["inside", "outside", "outside-left"];
const placements = ["inside", "outside", "outside-left", "outside-top"];
return (
<div className="w-full flex flex-col max-w-sm gap-4">
@@ -1,7 +1,7 @@
import {DatePicker} from "@heroui/react";
export default function App() {
const placements = ["inside", "outside", "outside-left"];
const placements = ["inside", "outside", "outside-left", "outside-top"];
return (
<div className="flex flex-col gap-4">
@@ -19,7 +19,7 @@ import unavailableDates from "./unavailable-dates";
import visibleMonth from "./visible-month";
import firstDayOfWeek from "./first-day-of-week";
import pageBehavior from "./page-behavior";
import nonContigous from "./non-contiguous";
import nonContiguous from "./non-contiguous";
import presets from "./presets";
import withMonthAndYearPickers from "./with-month-and-year-pickers";
import customStyles from "./custom-styles";
@@ -46,7 +46,7 @@ export const dateRangePickerContent = {
visibleMonth,
firstDayOfWeek,
pageBehavior,
nonContigous,
nonContiguous,
presets,
withMonthAndYearPickers,
customStyles,
@@ -1,7 +1,7 @@
import {DateRangePicker} from "@heroui/react";
export default function App() {
const placements = ["inside", "outside", "outside-left"];
const placements = ["inside", "outside", "outside-left", "outside-top"];
return (
<div className="flex flex-col gap-4">
@@ -1,13 +1,13 @@
import {NumberInput} from "@heroui/react";
export default function App() {
const placements = ["inside", "outside", "outside-left"];
const placements = ["inside", "outside", "outside-left", "outside-top"];
return (
<div className="flex flex-col gap-4">
<div className="flex flex-col gap-2">
<div className="flex flex-col gap-8 md:grid md:grid-cols-2">
<div className="flex flex-col gap-4">
<h3 className="text-default-500 text-small">Without placeholder</h3>
<div className="flex w-full flex-wrap items-end md:flex-nowrap mb-6 md:mb-0 gap-4">
<div className="flex flex-col gap-4">
{placements.map((placement) => (
<NumberInput
key={placement}
@@ -18,9 +18,9 @@ export default function App() {
))}
</div>
</div>
<div className="flex flex-col gap-2">
<div className="flex flex-col gap-4">
<h3 className="text-default-500 text-small">With placeholder</h3>
<div className="flex w-full flex-wrap items-end md:flex-nowrap mb-6 md:mb-0 gap-4">
<div className="flex flex-col gap-4">
{placements.map((placement) => (
<NumberInput
key={placement}
@@ -15,12 +15,13 @@ export const CustomRadio = (props) => {
return (
<Component
{...getBaseProps()}
className={cn(
"group inline-flex items-center hover:opacity-70 active:opacity-50 justify-between flex-row-reverse tap-highlight-transparent",
"max-w-[300px] cursor-pointer border-2 border-default rounded-lg gap-4 p-4",
"data-[selected=true]:border-primary",
)}
{...getBaseProps({
className: cn(
"group inline-flex items-center hover:opacity-70 active:opacity-50 justify-between flex-row-reverse tap-highlight-transparent m-0",
"max-w-[300px] cursor-pointer border-2 border-default rounded-lg gap-4 p-4",
"data-[selected=true]:border-primary",
),
})}
>
<VisuallyHidden>
<input {...getInputProps()} />
@@ -18,12 +18,13 @@ export const CustomRadio = (props: RadioProps) => {
return (
<Component
{...getBaseProps()}
className={cn(
"group inline-flex items-center justify-between hover:bg-content2 flex-row-reverse",
"max-w-[300px] cursor-pointer border-2 border-default rounded-lg gap-4 p-4",
"data-[selected=true]:border-primary",
)}
{...getBaseProps({
className: cn(
"group inline-flex items-center hover:opacity-70 active:opacity-50 justify-between flex-row-reverse tap-highlight-transparent m-0",
"max-w-[300px] cursor-pointer border-2 border-default rounded-lg gap-4 p-4",
"data-[selected=true]:border-primary",
),
})}
>
<VisuallyHidden>
<input {...getInputProps()} />
@@ -17,13 +17,13 @@ export const animals = [
];
export default function App() {
const placements = ["inside", "outside", "outside-left"];
const placements = ["inside", "outside", "outside-left", "outside-top"];
return (
<div className="w-full flex flex-col gap-4">
<div className="flex flex-col gap-2">
<div className="w-full grid grid-cols-1 md:grid-cols-2 gap-8">
<div className="flex flex-col gap-4">
<h3 className="text-default-500 text-small">Without placeholder</h3>
<div className="flex w-full flex-wrap items-end md:flex-nowrap mb-6 md:mb-0 gap-4">
<div className="flex flex-col gap-4">
{placements.map((placement) => (
<Select
key={placement}
@@ -38,9 +38,9 @@ export default function App() {
))}
</div>
</div>
<div className="flex flex-col gap-2">
<div className="flex flex-col gap-4">
<h3 className="text-default-500 text-small">With placeholder</h3>
<div className="flex w-full flex-wrap items-end md:flex-nowrap mb-6 md:mb-0 gap-4">
<div className="flex flex-col gap-4">
{placements.map((placement) => (
<Select
key={placement}
@@ -441,20 +441,18 @@ export default function App() {
);
case "actions":
return (
<div className="relative flex justify-end items-center gap-2">
<Dropdown className="bg-background border-1 border-default-200">
<DropdownTrigger>
<Button isIconOnly radius="full" size="sm" variant="light">
<VerticalDotsIcon className="text-default-400" />
</Button>
</DropdownTrigger>
<DropdownMenu>
<DropdownItem key="view">View</DropdownItem>
<DropdownItem key="edit">Edit</DropdownItem>
<DropdownItem key="delete">Delete</DropdownItem>
</DropdownMenu>
</Dropdown>
</div>
<Dropdown className="bg-background border-1 border-default-200">
<DropdownTrigger>
<Button isIconOnly radius="full" size="sm" variant="light">
<VerticalDotsIcon className="text-default-400" />
</Button>
</DropdownTrigger>
<DropdownMenu>
<DropdownItem key="view">View</DropdownItem>
<DropdownItem key="edit">Edit</DropdownItem>
<DropdownItem key="delete">Delete</DropdownItem>
</DropdownMenu>
</Dropdown>
);
default:
return cellValue;
@@ -453,20 +453,18 @@ export default function App() {
);
case "actions":
return (
<div className="relative flex justify-end items-center gap-2">
<Dropdown className="bg-background border-1 border-default-200">
<DropdownTrigger>
<Button isIconOnly radius="full" size="sm" variant="light">
<VerticalDotsIcon className="text-default-400" />
</Button>
</DropdownTrigger>
<DropdownMenu>
<DropdownItem key="view">View</DropdownItem>
<DropdownItem key="edit">Edit</DropdownItem>
<DropdownItem key="delete">Delete</DropdownItem>
</DropdownMenu>
</Dropdown>
</div>
<Dropdown className="bg-background border-1 border-default-200">
<DropdownTrigger>
<Button isIconOnly radius="full" size="sm" variant="light">
<VerticalDotsIcon className="text-default-400" />
</Button>
</DropdownTrigger>
<DropdownMenu>
<DropdownItem key="view">View</DropdownItem>
<DropdownItem key="edit">Edit</DropdownItem>
<DropdownItem key="delete">Delete</DropdownItem>
</DropdownMenu>
</Dropdown>
);
default:
return cellValue;
@@ -433,20 +433,18 @@ export default function App() {
);
case "actions":
return (
<div className="relative flex justify-end items-center gap-2">
<Dropdown>
<DropdownTrigger>
<Button isIconOnly size="sm" variant="light">
<VerticalDotsIcon className="text-default-300" />
</Button>
</DropdownTrigger>
<DropdownMenu>
<DropdownItem key="view">View</DropdownItem>
<DropdownItem key="edit">Edit</DropdownItem>
<DropdownItem key="delete">Delete</DropdownItem>
</DropdownMenu>
</Dropdown>
</div>
<Dropdown>
<DropdownTrigger>
<Button isIconOnly size="sm" variant="light">
<VerticalDotsIcon className="text-default-300" />
</Button>
</DropdownTrigger>
<DropdownMenu>
<DropdownItem key="view">View</DropdownItem>
<DropdownItem key="edit">Edit</DropdownItem>
<DropdownItem key="delete">Delete</DropdownItem>
</DropdownMenu>
</Dropdown>
);
default:
return cellValue;
@@ -446,20 +446,18 @@ export default function App() {
);
case "actions":
return (
<div className="relative flex justify-end items-center gap-2">
<Dropdown>
<DropdownTrigger>
<Button isIconOnly size="sm" variant="light">
<VerticalDotsIcon className="text-default-300" />
</Button>
</DropdownTrigger>
<DropdownMenu>
<DropdownItem key="view">View</DropdownItem>
<DropdownItem key="edit">Edit</DropdownItem>
<DropdownItem key="delete">Delete</DropdownItem>
</DropdownMenu>
</Dropdown>
</div>
<Dropdown>
<DropdownTrigger>
<Button isIconOnly size="sm" variant="light">
<VerticalDotsIcon className="text-default-300" />
</Button>
</DropdownTrigger>
<DropdownMenu>
<DropdownItem key="view">View</DropdownItem>
<DropdownItem key="edit">Edit</DropdownItem>
<DropdownItem key="delete">Delete</DropdownItem>
</DropdownMenu>
</Dropdown>
);
default:
return cellValue;
@@ -1,4 +1,4 @@
import {Table, TableBody, TableCell, TableColumn, TableHeader, TableRow} from "@nextui-org/react";
import {Table, TableBody, TableCell, TableColumn, TableHeader, TableRow} from "@heroui/react";
function generateRows(count) {
return Array.from({length: count}, (_, index) => ({
@@ -1,4 +1,4 @@
import {Table, TableBody, TableCell, TableColumn, TableHeader, TableRow} from "@nextui-org/react";
import {Table, TableBody, TableCell, TableColumn, TableHeader, TableRow} from "@heroui/react";
function generateRows(count) {
return Array.from({length: count}, (_, index) => ({
@@ -1,4 +1,4 @@
import {Table, TableBody, TableCell, TableColumn, TableHeader, TableRow} from "@nextui-org/react";
import {Table, TableBody, TableCell, TableColumn, TableHeader, TableRow} from "@heroui/react";
function generateRows(count) {
return Array.from({length: count}, (_, index) => ({
@@ -1,4 +1,4 @@
import {Table, TableBody, TableCell, TableColumn, TableHeader, TableRow} from "@nextui-org/react";
import {Table, TableBody, TableCell, TableColumn, TableHeader, TableRow} from "@heroui/react";
function generateRows(count) {
return Array.from({length: count}, (_, index) => ({
@@ -22,6 +22,12 @@ export default function App() {
label="Event Time"
labelPlacement="outside-left"
/>
<TimeInput
defaultValue={new Time(11, 45)}
description="outside-top"
label="Event Time"
labelPlacement="outside-top"
/>
</div>
);
}
@@ -74,7 +74,7 @@ heroui init my-heroui-app -t app
output:
```codeBlock bash
HeroUI CLI v0.2.1
HeroUI CLI <version>
┌ Create a new project
@@ -114,9 +114,8 @@ HeroUI CLI v0.2.1
#### Features
> 1. Auto add the missing required `dependencies` to your project
> 2. Auto add the required `tailwindcss.config.js` configuration to your project
> 3. Detect whether using pnpm, if so, add the required configuration to your `.npmrc` file
> 4. Add HeroUI Chat codebase to your project
> 2. Detect whether using pnpm, if so, add the required configuration to your `.npmrc` file
> 3. Add HeroUI Chat codebase to your project
```codeBlock bash
heroui add [targets...] [options]
@@ -126,8 +125,8 @@ heroui add [targets...] [options]
- `-a --all` [boolean] Add all components (default: `false`)
- `-p --packagePath` [string] The path to the package.json file
- `-tw --tailwindPath` [string] The path to the tailwind.config file file
- `-app --appPath` [string] The path to the App.tsx file
- `--tw --tailwindPath` [string] The path to the tailwind.config file (for backward compatibility)
- `--app --appPath` [string] The path to the App.tsx file
- `--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`)
- `-b --beta` [boolean] Add beta components (default: `false`)
@@ -144,7 +143,7 @@ heroui add
Output:
```codeBlock bash
HeroUI CLI v0.2.1
HeroUI CLI <version>
? Which components would you like to add? - Space to select. Return to submit
Instructions:
@@ -176,7 +175,7 @@ heroui add button
Output:
```codeBlock bash
HeroUI CLI v0.2.1
HeroUI CLI <version>
Adding the required dependencies: @heroui/button
@@ -222,15 +221,15 @@ heroui upgrade button
Output:
```codeBlock bash
HeroUI CLI v0.2.1
HeroUI CLI <version>
╭───────────────────────── Component ─────────────────────────╮
│ @heroui/button ^2.0.11 -> ^2.0.31 │
│ @heroui/button ^2.0.11 -> ^2.0.31
╰─────────────────────────────────────────────────────────────╯
Required min version: @heroui/theme>=2.1.0, tailwindcss>=3.4.0, react>=18.3.1, react-dom>=18.3.1
╭───────────────────── PeerDependencies ─────────────────────╮
│ @heroui/theme 2.0.1 -> 2.1.0 │
│ @heroui/theme 2.0.1 -> 2.1.0 │
│ tailwindcss ^3.2.3 -> ^3.4.0 │
│ react Missing -> 18.3.1 │
│ react-dom Missing -> 18.3.1 │
@@ -268,7 +267,7 @@ heroui remove [components...] [options]
- `-p --packagePath` [string] The path to the package.json file
- `-a --all` [boolean] Remove all the HeroUI components (default: `false`)
- `-tw --tailwindPath` [string] The path to the tailwind.config file file
- `--tw --tailwindPath` [string] The path to the tailwind.config file (for backward compatibility)
- `--prettier` [boolean] Add prettier format in the add content which required installed prettier - (default: `false`)
##### Example
@@ -282,13 +281,13 @@ heroui remove button
Output:
```codeBlock bash
HeroUI CLI v0.2.1
HeroUI CLI <version>
❗️ Components slated for removal:
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Package │ Version │ Status │ Docs │
│ Package │ Version │ Status │ Docs
│──────────────────────────────────────────────────────────────────────────────────────────────────────────────│
│ @heroui/button │ 2.0.27 🚀latest │ stable │ https://heroui.com/docs/components/button │
│ @heroui/button │ 2.0.27 🚀latest │ stable │ https://heroui.com/docs/components/button
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
? Confirm removal of these components: - Use arrow-keys. Return to submit.
Yes
@@ -330,17 +329,17 @@ heroui list
Output:
```codeBlock bash
HeroUI CLI v0.2.1
HeroUI CLI <version>
Current installed components:
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Package │ Version │ Status │ Docs │
│ Package │ Version │ Status │ Docs
│───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────│
│ @heroui/autocomplete │ 2.0.10 🚀latest │ stable │ https://heroui.com/docs/components/autocomplete │
│ @heroui/badge │ 2.0.24 🚀latest │ stable │ https://heroui.com/docs/components/badge │
│ @heroui/button │ 2.0.27 🚀latest │ stable │ https://heroui.com/docs/components/button │
│ @heroui/chip │ 2.0.25 🚀latest │ stable │ https://heroui.com/docs/components/chip │
│ @heroui/autocomplete │ 2.0.10 🚀latest │ stable │ https://heroui.com/docs/components/autocomplete
│ @heroui/badge │ 2.0.24 🚀latest │ stable │ https://heroui.com/docs/components/badge
│ @heroui/button │ 2.0.27 🚀latest │ stable │ https://heroui.com/docs/components/button
│ @heroui/chip │ 2.0.25 🚀latest │ stable │ https://heroui.com/docs/components/chip
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
```
@@ -356,18 +355,18 @@ heroui doctor [options]
> 1. Check whether have `redundant dependencies` in the project
> 2. Check whether the HeroUI components `required dependencies are installed` in the project
> 3. Check the required `tailwind.config.js` file and the content is correct
> 3. Check the content of `tailwind.config.js` is correct (if it exists)
> 4. Check `.npmrc` is correct when using `pnpm`
> 5. Check `peerDependencies with required version` are installed in the project
#### Doctor Options
- `-p` `--packagePath` [string] The path to the package.json file
- `-tw` `--tailwindPath` [string] The path to the tailwind.config file file
- `-app` `--appPath` [string] The path to the App.tsx file
- `-ca` `--checkApp` [boolean] Open check App (default: `true`)
- `-ct` `--checkTailwind` [boolean] Open check tailwind.config file (default: `true`)
- `-cp` `--checkPnpm` [boolean] Open check Pnpm (default: `true`)
- `--tw` `--tailwindPath` [string] The path to the tailwind.config file (for backward compatibility)
- `--app` `--appPath` [string] The path to the App.tsx file
- `--ca` `--checkApp` [boolean] Open check App (default: `true`)
- `--ct` `--checkTailwind` [boolean] Open check tailwind.config file (default: `true` if it exists)
- `--cp` `--checkPnpm` [boolean] Open check Pnpm (default: `true`)
#### Example
@@ -380,19 +379,24 @@ Output:
If there is a problem in your project, the `doctor` command will display the problem information.
```codeBlock bash
HeroUI CLI v0.2.1
HeroUI CLI <version>
HeroUI CLI: ❌ Your project has 1 issue that require attention
❗️Issue 1: missingTailwind
❗️Issue 1: missingDependencies
Missing tailwind.config.(j|t)s file. To set up, visit: https://heroui.com/docs/guide/installation#tailwind-css-setup
You have not installed the required dependencies
The required dependencies are:
- @heroui/theme@2.4.25
See more info here: https://heroui.com/docs/guide/installation#global-installation
```
Otherwise, the `doctor` command will display the following message.
```codeBlock bash
HeroUI CLI v0.2.1
HeroUI CLI <version>
✅ Your project has no detected issues.
```
@@ -420,17 +424,17 @@ heroui env
Output:
```codeBlock bash
HeroUI CLI v0.2.1
HeroUI CLI <version>
Current installed components:
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Package │ Version │ Status │ Docs │
│ Package │ Version │ Status │ Docs
│───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────│
│ @heroui/autocomplete │ 2.0.10 🚀latest │ stable │ https://heroui.com/docs/components/autocomplete │
│ @heroui/badge │ 2.0.24 🚀latest │ stable │ https://heroui.com/docs/components/badge │
│ @heroui/button │ 2.0.27 🚀latest │ stable │ https://heroui.com/docs/components/button │
│ @heroui/chip │ 2.0.25 🚀latest │ stable │ https://heroui.com/docs/components/chip │
│ @heroui/autocomplete │ 2.0.10 🚀latest │ stable │ https://heroui.com/docs/components/autocomplete
│ @heroui/badge │ 2.0.24 🚀latest │ stable │ https://heroui.com/docs/components/badge
│ @heroui/button │ 2.0.27 🚀latest │ stable │ https://heroui.com/docs/components/button
│ @heroui/chip │ 2.0.25 🚀latest │ stable │ https://heroui.com/docs/components/chip
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
Environment Info:
@@ -438,5 +442,5 @@ Environment Info:
OS: darwin
CPU: arm64
Binaries:
Node: v18.18.2
Node: v24.3.0
```
@@ -147,9 +147,9 @@ interface AppProviderProps {
`labelPlacement`
- **Description**: Determines the position where label should appear, such as inside, outside or outside-left of the component.
- **Description**: Determines the position where label should appear, such as inside, outside, outside-left or outside-top of the component.
- **Type**: `string` | `undefined`
- **Possible Values**: `inside` | `outside` | `outside-left` | `undefined`
- **Possible Values**: `inside` | `outside` | `outside-left` | `outside-top` | `undefined`
- **Default**: `undefined`
<Spacer y={2}/>
@@ -34,7 +34,7 @@ HeroUI exports 3 autocomplete-related components:
- **Autocomplete**: The main component, which is a wrapper for the other components.
- **AutocompleteSection**: The component that contains a group of autocomplete items.
- **AutocompleteItem**: The component that represents a autocomplete item.
- **AutocompleteItem**: The component that represents an autocomplete item.
<ImportTabs
commands={{
@@ -102,7 +102,7 @@ all available options, but users won't be able to select any of the listed optio
### Label Placements
You can change the position of the label by setting the `labelPlacement` property to `inside`, `outside` or `outside-left`.
You can change the position of the label by setting the `labelPlacement` property to `inside`, `outside`, `outside-left` or `outside-top`.
<CodeDemo
title="Label Placements"
@@ -176,30 +176,30 @@ You can combine the `isInvalid` and `errorMessage` properties to show an invalid
### Events
The `Autocomplete` component supports selection via mouse, keyboard, and touch. You can handle all of these
via the `onSelectionChange` prop. `Autocomplete` will pass the selected key to the onSelectionChange handler.
via the `onChange` prop. `Autocomplete` will pass the selected key to the onChange handler.
Additionally, ComboBox accepts an `onInputChange` prop which is triggered whenever the value is edited by the user,
whether through typing or option selection.
The example below uses `onSelectionChange` and `onInputChange` to update the selection and input value stored in
The example below uses `onChange` and `onInputChange` to update the selection and input value stored in
React state.
<CodeDemo title="Events" files={autocompleteContent.events} />
### Controlled
You can use the `selectedKey` and `onSelectionChange` properties to control the select value.
You can use the `value` and `onChange` properties to control the select value.
<CodeDemo
title="Controlled with onSelectionChange"
title="Controlled with onChange"
files={autocompleteContent.controlled}
/>
### Fully Controlled
By passing in `inputValue`, `selectedKey`, and `items` to the `Autocomplete` you can control exactly what your `Autocomplete` should display.
By passing in `inputValue`, `value`, and `items` to the `Autocomplete` you can control exactly what your `Autocomplete` should display.
The following example shows how you would create a controlled `Autocomplete`, controlling everything from the selected value
`selectedKey` to the combobox options `items`.
`value` to the combobox options `items`.
We recommend using the `useFilter` hook from [@react-aria/i18n](https://react-spectrum.adobe.com/react-aria/useFilter.html#usefilter) to manage the filtering of the items.
@@ -224,7 +224,7 @@ import {useFilter} from "@react-aria/i18n";
files={autocompleteContent.fullyControlled}
/>
> **Note**: It is important to note that you don't have to control every single aspect of a `Autocomplete`. If you decide to only control a single property of the `Autocomplete`, be sure to provide the change handler for that prop as well e.g. controlling `selectedKey` would require `onSelectionChange`.
> **Note**: It is important to note that you don't have to control every single aspect of a `Autocomplete`. If you decide to only control a single property of the `Autocomplete`, be sure to provide the change handler for that prop as well e.g. controlling `value` would require `onChange`.
### Custom Items
@@ -395,7 +395,7 @@ properties to customize the popover, listbox and input components.
- **data-disabled**:
When the autocomplete item is disabled. Based on autocomplete `disabledKeys` prop.
- **data-selected**:
When the autocomplete item is selected. Based on autocomplete `selectedKey` prop.
When the autocomplete item is selected. Based on autocomplete `value` prop.
- **data-hover**:
When the autocomplete item is being hovered. Based on [useHover](https://react-spectrum.adobe.com/react-aria/useHover.html)
- **data-pressed**:
@@ -542,18 +542,18 @@ properties to customize the popover, listbox and input components.
},
{
attribute: "labelPlacement",
type: "inside | outside | outside-left",
type: "inside | outside | outside-left | outside-top",
description: "The position of the label.",
default: "inside"
},
{
attribute: "selectedKey",
attribute: "value",
type: "React.Key",
description: "The currently selected key in the collection (controlled).",
default: "-"
},
{
attribute: "defaultSelectedKey",
attribute: "defaultValue",
type: "React.Key",
description: "The initial selected key in the collection (uncontrolled).",
default: "-"
@@ -572,7 +572,7 @@ properties to customize the popover, listbox and input components.
},
{
attribute: "validate",
type: "(value: { inputValue: string, selectedKey: React.Key }) => ValidationError | true | null | undefined",
type: "(value: { inputValue: string, value: React.Key }) => ValidationError | true | null | undefined",
description: "Validate input values when committing (e.g. on blur), and return error messages for invalid values.",
default: "-"
},
@@ -764,7 +764,7 @@ properties to customize the popover, listbox and input components.
default: "-"
},
{
attribute: "onSelectionChange",
attribute: "onChange",
type: "(key: React.Key) => void",
description: "Handler that is called when the Autocomplete selection changes.",
default: "-"
@@ -249,6 +249,12 @@ Here's the example to customize `topContent` and `bottomContent` to have some pr
description: "The day that starts the week.",
default: "-"
},
{
attribute: "selectionAlignment",
type: "start | center | end",
description: "Determines the alignment of the visible months on initial render based on the current selection or current date if there is no selection.",
default: "center"
},
{
attribute: "focusedValue",
type: "DateValue",
@@ -258,7 +264,7 @@ Here's the example to customize `topContent` and `bottomContent` to have some pr
{
attribute: "defaultFocusedValue",
type: "DateValue",
description: "The date that is focused when the calendar first mounts (uncountrolled).",
description: "The date that is focused when the calendar first mounts (uncontrolled).",
default: "-"
},
{
@@ -60,7 +60,7 @@ Each part of a date value is displayed in an individually editable segment.
### Label Placements
You can change the position of the label by setting the `labelPlacement` property to `inside`, `outside` or `outside-left`.
You can change the position of the label by setting the `labelPlacement` property to `inside`, `outside`, `outside-left` or `outside-top`.
<CodeDemo title="Label Placements" files={dateInputContent.labelPlacements} />
@@ -104,9 +104,9 @@ in multiple formats into `ZonedDateTime` objects.
<PackageManagers
commands={{
npm: "npm install @internationalized/date@3.9.0",
yarn: "yarn add @internationalized/date@3.9.0",
pnpm: "pnpm add @internationalized/date@3.9.0",
npm: "npm install @internationalized/date@3.12.2",
yarn: "yarn add @internationalized/date@3.12.2",
pnpm: "pnpm add @internationalized/date@3.12.2",
}}
/>
@@ -129,9 +129,9 @@ in multiple formats into `ZonedDateTime` objects.
<PackageManagers
commands={{
npm: "npm install @internationalized/date@3.9.0 @react-aria/i18n@3.12.12",
yarn: "yarn add @internationalized/date@3.9.0 @react-aria/i18n@3.12.12",
pnpm: "pnpm add @internationalized/date@3.9.0 @react-aria/i18n@3.12.12",
npm: "npm install @internationalized/date@3.12.2 @react-aria/i18n@3.13.1",
yarn: "yarn add @internationalized/date@3.12.2 @react-aria/i18n@3.13.1",
pnpm: "pnpm add @internationalized/date@3.12.2 @react-aria/i18n@3.13.1",
}}
/>
@@ -153,9 +153,9 @@ in multiple formats into `ZonedDateTime` objects.
<PackageManagers
commands={{
npm: "npm install @internationalized/date@3.9.0",
yarn: "yarn add @internationalized/date@3.9.0",
pnpm: "pnpm add @internationalized/date@3.9.0",
npm: "npm install @internationalized/date@3.12.2",
yarn: "yarn add @internationalized/date@3.12.2",
pnpm: "pnpm add @internationalized/date@3.12.2",
}}
/>
@@ -177,9 +177,9 @@ in multiple formats into `ZonedDateTime` objects.
<PackageManagers
commands={{
npm: "npm install @internationalized/date@3.9.0 @react-aria/i18n@3.12.12",
yarn: "yarn add @internationalized/date@3.9.0 @react-aria/i18n@3.12.12",
pnpm: "pnpm add @internationalized/date@3.9.0 @react-aria/i18n@3.12.12",
npm: "npm install @internationalized/date@3.12.2 @react-aria/i18n@3.13.1",
yarn: "yarn add @internationalized/date@3.12.2 @react-aria/i18n@3.13.1",
pnpm: "pnpm add @internationalized/date@3.12.2 @react-aria/i18n@3.13.1",
}}
/>
@@ -200,9 +200,9 @@ in multiple formats into `ZonedDateTime` objects.
<PackageManagers
commands={{
npm: "npm install @internationalized/date@3.9.0",
yarn: "yarn add @internationalized/date@3.9.0",
pnpm: "pnpm add @internationalized/date@3.9.0",
npm: "npm install @internationalized/date@3.12.2",
yarn: "yarn add @internationalized/date@3.12.2",
pnpm: "pnpm add @internationalized/date@3.12.2",
}}
/>
@@ -223,9 +223,9 @@ in multiple formats into `ZonedDateTime` objects.
<PackageManagers
commands={{
npm: "npm install @internationalized/date@3.9.0",
yarn: "yarn add @internationalized/date@3.9.0",
pnpm: "pnpm add @internationalized/date@3.9.0",
npm: "npm install @internationalized/date@3.12.2",
yarn: "yarn add @internationalized/date@3.12.2",
pnpm: "pnpm add @internationalized/date@3.12.2",
}}
/>
@@ -370,7 +370,7 @@ import {parseZonedDateTime} from "@internationalized/date";
},
{
attribute: "labelPlacement",
type: "inside | outside | outside-left",
type: "inside | outside | outside-left | outside-top",
description: "The position of the label.",
default: "inside"
},
@@ -59,7 +59,7 @@ DatePickers combine a DateInput and a Calendar popover to allow users to enter o
### Label Placements
You can change the position of the label by setting the `labelPlacement` property to `inside`, `outside` or `outside-left`.
You can change the position of the label by setting the `labelPlacement` property to `inside`, `outside`, `outside-left` or `outside-top`.
<CodeDemo title="Label Placements" files={datePickerContent.labelPlacements} />
@@ -119,9 +119,9 @@ in multiple formats into `ZonedDateTime` objects.
<PackageManagers
commands={{
npm: "npm install @internationalized/date@3.9.0",
yarn: "yarn add @internationalized/date@3.9.0",
pnpm: "pnpm add @internationalized/date@3.9.0",
npm: "npm install @internationalized/date@3.12.2",
yarn: "yarn add @internationalized/date@3.12.2",
pnpm: "pnpm add @internationalized/date@3.12.2",
}}
/>
@@ -144,9 +144,9 @@ in multiple formats into `ZonedDateTime` objects.
<PackageManagers
commands={{
npm: "npm install @internationalized/date@3.9.0 @react-aria/i18n@3.12.12",
yarn: "yarn add @internationalized/date@3.9.0 @react-aria/i18n@3.12.12",
pnpm: "pnpm add @internationalized/date@3.9.0 @react-aria/i18n@3.12.12",
npm: "npm install @internationalized/date@3.12.2 @react-aria/i18n@3.13.1",
yarn: "yarn add @internationalized/date@3.12.2 @react-aria/i18n@3.13.1",
pnpm: "pnpm add @internationalized/date@3.12.2 @react-aria/i18n@3.13.1",
}}
/>
@@ -168,9 +168,9 @@ in multiple formats into `ZonedDateTime` objects.
<PackageManagers
commands={{
npm: "npm install @internationalized/date@3.9.0",
yarn: "yarn add @internationalized/date@3.9.0",
pnpm: "pnpm add @internationalized/date@3.9.0",
npm: "npm install @internationalized/date@3.12.2",
yarn: "yarn add @internationalized/date@3.12.2",
pnpm: "pnpm add @internationalized/date@3.12.2",
}}
/>
@@ -192,9 +192,9 @@ in multiple formats into `ZonedDateTime` objects.
<PackageManagers
commands={{
npm: "npm install @internationalized/date@3.9.0 @react-aria/i18n@3.12.12",
yarn: "yarn add @internationalized/date@3.9.0 @react-aria/i18n@3.12.12",
pnpm: "pnpm add @internationalized/date@3.9.0 @react-aria/i18n@3.12.12",
npm: "npm install @internationalized/date@3.12.2 @react-aria/i18n@3.13.1",
yarn: "yarn add @internationalized/date@3.12.2 @react-aria/i18n@3.13.1",
pnpm: "pnpm add @internationalized/date@3.12.2 @react-aria/i18n@3.13.1",
}}
/>
@@ -214,9 +214,9 @@ in multiple formats into `ZonedDateTime` objects.
<PackageManagers
commands={{
npm: "npm install @internationalized/date@3.9.0 @react-aria/i18n@3.12.12",
yarn: "yarn add @internationalized/date@3.9.0 @react-aria/i18n@3.12.12",
pnpm: "pnpm add @internationalized/date@3.9.0 @react-aria/i18n@3.12.12",
npm: "npm install @internationalized/date@3.12.2 @react-aria/i18n@3.13.1",
yarn: "yarn add @internationalized/date@3.12.2 @react-aria/i18n@3.13.1",
pnpm: "pnpm add @internationalized/date@3.12.2 @react-aria/i18n@3.13.1",
}}
/>
@@ -252,9 +252,9 @@ in multiple formats into `ZonedDateTime` objects.
<PackageManagers
commands={{
npm: "npm install @internationalized/date@3.9.0 @react-aria/i18n@3.12.12",
yarn: "yarn add @internationalized/date@3.9.0 @react-aria/i18n@3.12.12",
pnpm: "pnpm add @internationalized/date@3.9.0 @react-aria/i18n@3.12.12",
npm: "npm install @internationalized/date@3.12.2 @react-aria/i18n@3.13.1",
yarn: "yarn add @internationalized/date@3.12.2 @react-aria/i18n@3.13.1",
pnpm: "pnpm add @internationalized/date@3.12.2 @react-aria/i18n@3.13.1",
}}
/>
@@ -329,7 +329,7 @@ import {I18nProvider} from "@react-aria/i18n";
},
{
attribute: "value",
type: "ZonedDateTime | CalendarDate | CalendarDateTime | undefined | null",
type: "DateValue | null",
description: "The current value of the date-picker (controlled).",
default: "-"
},
@@ -359,13 +359,13 @@ import {I18nProvider} from "@react-aria/i18n";
},
{
attribute: "defaultValue",
type: "string",
type: "DateValue | null",
description: "The default value of the date-picker (uncontrolled).",
default: "-"
},
{
attribute: "placeholderValue",
type: "ZonedDateTime | CalendarDate | CalendarDateTime | undefined | null",
type: "DateValue | null",
description: "The placeholder of the date-picker.",
default: "-"
},
@@ -407,7 +407,7 @@ import {I18nProvider} from "@react-aria/i18n";
},
{
attribute: "labelPlacement",
type: "inside | outside | outside-left",
type: "inside | outside | outside-left | outside-top",
description: "The position of the label.",
default: "inside"
},
@@ -447,6 +447,12 @@ import {I18nProvider} from "@react-aria/i18n";
description: "The day that starts the week.",
default: "-"
},
{
attribute: "selectionAlignment",
type: "start | center | end",
description: "Determines the alignment of the visible months on initial render based on the current selection or current date if there is no selection.",
default: "center"
},
{
attribute: "selectorIcon",
type: "ReactNode",

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