Compare commits

...

300 Commits

Author SHA1 Message Date
github-actions[bot] 2f87b8d644 ci(changesets): version packages (#1924)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-11-08 11:29:59 -03:00
Junior Garcia 6ecdc278ab fix(system): extend variants fuction adapted (#1927) 2023-11-08 11:15:10 -03:00
Junior Garcia 9189b3fbf2 fix(textarea): styles issues and start/end content props added (#1923)
* fix(textarea): styles issues and start/end content props added

* chore(textarea): multiple rows prop renamed
2023-11-08 10:33:00 -03:00
github-actions[bot] 1149345cae ci(changesets): version packages (#1916)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-11-07 10:35:29 -03:00
Junior Garcia 135cc21e6f fix(menu): add hideSelectedIcon prop to menu and listbox (#1915)
sections
2023-11-07 10:16:02 -03:00
Junior Garcia 7f6218b978 fix(select): multiline styles (#1914) 2023-11-07 10:06:35 -03:00
github-actions[bot] 0eb9f1e3fe ci(changesets): version packages (#1903)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-11-06 17:12:38 -03:00
Junior Garcia 11ef4365da refactor(theme): update input and select component styles (#1905) 2023-11-06 17:00:38 -03:00
Junior Garcia 85a820eeff fix(autocomplete): endContent prop (#1902) 2023-11-06 16:25:00 -03:00
Junior Garcia 6a6d426b10 fix(input): label position and styles (#1901)
* fix(input): label position and styles

* fix(textarea): invalid state
2023-11-06 15:45:05 -03:00
github-actions[bot] a3cbb5997b ci(changesets): version packages (#1878)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-11-06 08:39:24 -03:00
Junior Garcia a5cc42bf80 refactor(docs): routing and add folder routes (#1892)
* refactor(docs): routing and add folder routes

* chore(docs): permanent redirect enabled
2023-11-06 08:22:03 -03:00
Junior Garcia e728a8967b fix(theme): update input and select styling and add data attribute for (#1891)
value
2023-11-06 08:20:02 -03:00
Junior Garcia acba2cf8f5 Fix/input select helper position (#1884)
* fix(input): fix input and select component styles

* chore(root): changeset
2023-11-05 20:00:48 -03:00
Junior Garcia 049db57bb2 fix(docs): fix typo in routing guide link 2023-11-05 18:47:49 -03:00
Dawson 5296d9b84d Typo fix (#1882) 2023-11-05 18:45:24 -03:00
Simon He 1619a35cf9 docs(pagination): fix dotsJump type 2023-11-05 12:20:47 -03:00
Simon He 8106629dab docs(radio-group): fix typo 2023-11-05 12:19:44 -03:00
Junior Garcia d55f52cc35 Merge pull request #1877 from nextui-org/fix/changeset-peer-deps-config 2023-11-05 10:57:39 -03:00
Junior Garcia 78198c32be Merge branch 'main' of github.com:nextui-org/nextui into fix/changeset-peer-deps-config 2023-11-05 10:44:00 -03:00
Junior Garcia 71807e8831 chore(theme): changeset 2023-11-05 10:43:37 -03:00
Junior Garcia 9af6174dcf refactor(theme): refactor theme plugin to improve performance and
readability
2023-11-05 10:43:37 -03:00
Junior Garcia 1a129db6fe chore: merge branch main 2023-11-05 10:30:55 -03:00
Junior Garcia 44ed1056e7 chore(root): changeset added 2023-11-05 10:24:48 -03:00
Junior Garcia db0e26a003 ci(changesets): version packages 2023-11-05 10:02:18 -03:00
Junior Garcia 38af48faf5 fix(core): update peer dependencies for several packages 2023-11-05 09:53:57 -03:00
Junior Garcia 5b60840751 chore(root): main conflicts merge fixed 2023-11-05 09:28:58 -03:00
Junior Garcia 4c56839db0 fix(root): changeset message 2023-11-05 09:27:56 -03:00
Junior Garcia ef61a3fe09 Revert "fix(root): peer dependecies update only when out of range"
This reverts commit bc4927c901.
2023-11-05 09:25:52 -03:00
Junior Garcia bc4927c901 fix(root): peer dependecies update only when out of range 2023-11-05 09:23:28 -03:00
Junior Garcia 4191feab2a fix(docs): update hoverOpacity in layout theme 2023-11-05 09:03:39 -03:00
Junior Garcia fe8647bd1d fix(docs): router import added to the routing next.js app docs 2023-11-05 08:59:16 -03:00
Junior Garcia 23992572ea fix(select): add button component and update select component 2023-11-05 08:52:33 -03:00
Junior Garcia e7a4711d9b ci(changesets): version packages 2023-11-04 16:44:59 -03:00
Junior Garcia e84158db62 chore: changeset 2023-11-04 16:38:57 -03:00
Junior Garcia f59e8f6bac fix(select): without label and input helperWrapper relative 2023-11-04 16:38:57 -03:00
Junior Garcia 73dfb7fc93 feat(docs): add package manager selection and usehooks-ts
dependency
2023-11-04 10:17:00 -03:00
Junior Garcia df9f6f5f58 ci(changesets): version packages 2023-11-03 19:38:47 -03:00
Junior Garcia 1fd5049f5a fix(select): multiline label (#1865) 2023-11-03 19:28:23 -03:00
Junior Garcia a386e1cadd chore(blog): card body padding change added 2023-11-03 17:08:03 -03:00
Junior Garcia 3172a803e3 feat(docs): blog post announcement added to mobile resolutions 2023-11-03 16:55:43 -03:00
Junior Garcia dfc8bdc7af chore(docs): v2.2.0 post date fixed, search meta updated 2023-11-03 16:48:25 -03:00
Junior Garcia 67ce4beb28 Feat/v2 blog (#1858)
* feat: Slider Component (#1686)

* feat(slider): initial structure

* chore(slider): readme improved

* fix: fixed border color of slider track

* docs: added range story

* feat: added rtl support to slider

* feat: improved value label formatting

* feat: refactor styling and add colors support to slider

* chore: improved thumb color

* docs: improved slider stories

* chore(slider): default color changed by foreground

* Update packages/core/theme/src/components/slider.ts

Co-authored-by: Jakob Guddas <github@jguddas.de>

* feat: added fillOffset prop

* Update packages/components/slider/src/use-slider.ts

* fix(slider): animation

* Update packages/components/slider/src/use-slider.ts

* Update packages/core/theme/src/components/slider.ts

* feat: slider steps

* refactor: renamed variables

* feat: improved slider step styling

* fix: hide infinite steps

* fix: fixed step transparency issue

* fix: fixed thumb focus issue

* Update packages/components/slider/src/use-slider.ts

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

* feat(slider): vertical orientation added, start & end content, bug fixes

* chore(slider): tests added

* fix(docs): scrollbar added to the sidebar (#1743)

* feat(slider): marks added

* chore(slider): example ts-doc changed

* feat(slider): vertical marks support

* feat(core): slider tooltip support added, popover modified (#1746)

* Feat/slider custom styles (#1751)

* feat(slider): custom styles story added

* fix(slider): custom styles on different sizes

* Fix/slider tooltip android position (#1753)

* feat(slider): custom styles story added

* fix(slider): tooltip update position dependecies added

* fix(popover): arrow placements improved

* feat(slider): docs started, custom thumb and custom output stories added

* feat(slider): render function added to custom render the slider parts

* feat(slider): docs in progress, new properties and examples added

* fix(slider): some issues fixed, output renamed to value, documentation improved

* feat(slider): docs done

* chore: changeset

---------

Co-authored-by: Jakob Guddas <github@jguddas.de>

* Client side routing (#1764)

* feat(slider): initial structure

* chore(slider): readme improved

* fix: fixed border color of slider track

* docs: added range story

* feat: added rtl support to slider

* feat: improved value label formatting

* feat: refactor styling and add colors support to slider

* chore: improved thumb color

* docs: improved slider stories

* chore(slider): default color changed by foreground

* Update packages/core/theme/src/components/slider.ts

Co-authored-by: Jakob Guddas <github@jguddas.de>

* feat: added fillOffset prop

* Update packages/components/slider/src/use-slider.ts

* fix(slider): animation

* Update packages/components/slider/src/use-slider.ts

* Update packages/core/theme/src/components/slider.ts

* feat: slider steps

* refactor: renamed variables

* feat: improved slider step styling

* fix: hide infinite steps

* fix: fixed step transparency issue

* fix: fixed thumb focus issue

* Update packages/components/slider/src/use-slider.ts

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

* feat(slider): vertical orientation added, start & end content, bug fixes

* chore(slider): tests added

* feat(slider): marks added

* chore(slider): example ts-doc changed

* feat(slider): vertical marks support

* feat(core): slider tooltip support added, popover modified (#1746)

* Feat/slider custom styles (#1751)

* feat(slider): custom styles story added

* fix(slider): custom styles on different sizes

* Fix/slider tooltip android position (#1753)

* feat(slider): custom styles story added

* fix(slider): tooltip update position dependecies added

* fix(popover): arrow placements improved

* feat(slider): docs started, custom thumb and custom output stories added

* feat(slider): render function added to custom render the slider parts

* feat(slider): docs in progress, new properties and examples added

* fix(slider): some issues fixed, output renamed to value, documentation improved

* feat(slider): docs done

* chore: changeset

* chore: react aria packages upgraded

* feat(system): router provider added

* feat: client side routing support added to items components

* chore(docs): routing docs started

* chore: changeset

* feat(docs): client side routing documented

* feat(pagination): client router support added to pagination

* fix(link): csr added

---------

Co-authored-by: Jakob Guddas <github@jguddas.de>

* feat: added RTL support to accordion component (#1725)

* feat: added RTL support to accordion component

* Create healthy-cobras-crash.md

* feat: added RTL support to avatar and avatar group component (#1727)

* feat: added RTL support to avatar and avatar group components

* Create tender-penguins-love.md

* Update tender-penguins-love.md

* feat: added RTL support to button group component (#1726)

* feat: added RTL support to button component

* feat: added RTL support to button component

* Create orange-bobcats-kneel.md

* Update button.ts

* refactor(root): styles refactor (#1688)

* refactor(root): styles refactor

* chore(tabs): remove needless type extends

* fix(tabs): typecheck

* Breadcrumbs component (#1794)

* feat(components): breadcrumbs initial structure

* feat(breadcrumbs): tests and examples added

* feat(docs): breadcrumbs documentation done

* feat(docs): breadcrumbs docs done

* chore(breadcrumbs): readme changed

* fix(slider): Place last dragged slider handle over the other handle (#1778)

* Set `data-focused` in handle

* Style focused handle on top

* Add tests

* fix(core): tests and build

* fix(button): show only spinner if button isLoading & isIconOnly (#1800)

* fix(button): show only spinner if button isLoading & isIconOnly

* chore: add changeset

* fix(button): remove repeating code

* Fix blur/opaque Popover (#1812)

* fix(popover): double underlay click

* chore: use ref instead of a state

* Feat/controlled scroll shadow (#1819)

* feat(scroll-shadow): logic improved, controlled support added

* feat(scroll-shadow): controlled visibility

* fix(scroll-shadow): visibility tests

* Autocomplete component (Single Selection) (#1797)

* feat(autocomplete): initial structure

* feat(core): use press custom hook implemented, autocomplete improved, input and select animations fixed

* chore(button): add console.log on press

* feat(core): select & input label position, autocomplete improvements, listbox and menu empty state

* chore: tailwind-variants upgraded

* chore: autocomplete stories in progress

* fix: input and select label placement

* fix(autocomplete): popover trigger

* chore(root): react-aria pkgs and framer-motion upgraded

* fix(input,select): outside label scale removed

* feat(autocomplete): more stories and use cases supported

* fix(core): custom items support on collection-based comps, menu generic items support added

* chore(core): tailwind-variants upgraded, custom tv function adapted

* chore(docs): select on-change controlled e.g. changed, sandpack theme fixed

* chore(autocomplete): docs started, tests added

* chore: in progress

* feat(menu): top and end content added, autocomplete docs improved

* feat(docs): autocomplete documentation almost done

* fix(input): outside styles

* feat(docs): autocomplete async filtering added

* chore(docs): autocomplete highlighted lines added

* feat(docs): autocomplete a11y and slots added

* feat(docs): autocomplete a11y and slots added

* feat(docs): autocomplete docs done

* fix(root): peer dependencies (#1848)

* Fix/small issues (#1851)

* fix(input): visible outline

* fix(button): button group radius prop

* chore(navbar): menu item active status added

* fix(docs): pagination missing keys custom items

* fix(core): extendVariants support added to collection-based components

* fix(theme): card body padding

* chore(theme): transition added to menu/listbox items

* fix(input): textarea styles fixed, new prop added

* chore(input): textarea height animated

* feat(button): hover opacity added

* chore(textarea): hide scroll when the limit hasn't been reached

* chore(docs): updated badge added to textarea

* feat(docs): blog v2.2.0 image and entry added

* fix(avatar): ring primary color

* chore(docs): tabs added again, autocomplete iframes removed

* chore: v2 blog post

---------

Co-authored-by: Jakob Guddas <github@jguddas.de>
Co-authored-by: Maurici Abad Gutierrez <hello@mauriciabad.com>
Co-authored-by: Ivan Kucher <dev.kucher@gmail.com>
2023-11-03 12:35:36 -03:00
github-actions[bot] 5a4a60be65 ci(changesets): version packages (#1860)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-11-03 12:21:01 -03:00
Junior Garcia 25e86fb417 chore(changeset): updated 2023-11-03 12:08:29 -03:00
Junior Garcia a95bd6558d chore(core): system pkg theme dependecy moved to peer 2023-11-03 12:07:12 -03:00
Junior Garcia 080718e265 fix(root): changeset 2023-11-03 11:31:30 -03:00
Junior Garcia 8217639fd4 chore(root): v2.2.0 changeset 2023-11-03 11:17:44 -03:00
Junior Garcia 7abd68941a v2.2.0 🕹️ (#1777)
* feat: Slider Component (#1686)

* feat(slider): initial structure

* chore(slider): readme improved

* fix: fixed border color of slider track

* docs: added range story

* feat: added rtl support to slider

* feat: improved value label formatting

* feat: refactor styling and add colors support to slider

* chore: improved thumb color

* docs: improved slider stories

* chore(slider): default color changed by foreground

* Update packages/core/theme/src/components/slider.ts

Co-authored-by: Jakob Guddas <github@jguddas.de>

* feat: added fillOffset prop

* Update packages/components/slider/src/use-slider.ts

* fix(slider): animation

* Update packages/components/slider/src/use-slider.ts

* Update packages/core/theme/src/components/slider.ts

* feat: slider steps

* refactor: renamed variables

* feat: improved slider step styling

* fix: hide infinite steps

* fix: fixed step transparency issue

* fix: fixed thumb focus issue

* Update packages/components/slider/src/use-slider.ts

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

* feat(slider): vertical orientation added, start & end content, bug fixes

* chore(slider): tests added

* fix(docs): scrollbar added to the sidebar (#1743)

* feat(slider): marks added

* chore(slider): example ts-doc changed

* feat(slider): vertical marks support

* feat(core): slider tooltip support added, popover modified (#1746)

* Feat/slider custom styles (#1751)

* feat(slider): custom styles story added

* fix(slider): custom styles on different sizes

* Fix/slider tooltip android position (#1753)

* feat(slider): custom styles story added

* fix(slider): tooltip update position dependecies added

* fix(popover): arrow placements improved

* feat(slider): docs started, custom thumb and custom output stories added

* feat(slider): render function added to custom render the slider parts

* feat(slider): docs in progress, new properties and examples added

* fix(slider): some issues fixed, output renamed to value, documentation improved

* feat(slider): docs done

* chore: changeset

---------

Co-authored-by: Jakob Guddas <github@jguddas.de>

* Client side routing (#1764)

* feat(slider): initial structure

* chore(slider): readme improved

* fix: fixed border color of slider track

* docs: added range story

* feat: added rtl support to slider

* feat: improved value label formatting

* feat: refactor styling and add colors support to slider

* chore: improved thumb color

* docs: improved slider stories

* chore(slider): default color changed by foreground

* Update packages/core/theme/src/components/slider.ts

Co-authored-by: Jakob Guddas <github@jguddas.de>

* feat: added fillOffset prop

* Update packages/components/slider/src/use-slider.ts

* fix(slider): animation

* Update packages/components/slider/src/use-slider.ts

* Update packages/core/theme/src/components/slider.ts

* feat: slider steps

* refactor: renamed variables

* feat: improved slider step styling

* fix: hide infinite steps

* fix: fixed step transparency issue

* fix: fixed thumb focus issue

* Update packages/components/slider/src/use-slider.ts

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

* feat(slider): vertical orientation added, start & end content, bug fixes

* chore(slider): tests added

* feat(slider): marks added

* chore(slider): example ts-doc changed

* feat(slider): vertical marks support

* feat(core): slider tooltip support added, popover modified (#1746)

* Feat/slider custom styles (#1751)

* feat(slider): custom styles story added

* fix(slider): custom styles on different sizes

* Fix/slider tooltip android position (#1753)

* feat(slider): custom styles story added

* fix(slider): tooltip update position dependecies added

* fix(popover): arrow placements improved

* feat(slider): docs started, custom thumb and custom output stories added

* feat(slider): render function added to custom render the slider parts

* feat(slider): docs in progress, new properties and examples added

* fix(slider): some issues fixed, output renamed to value, documentation improved

* feat(slider): docs done

* chore: changeset

* chore: react aria packages upgraded

* feat(system): router provider added

* feat: client side routing support added to items components

* chore(docs): routing docs started

* chore: changeset

* feat(docs): client side routing documented

* feat(pagination): client router support added to pagination

* fix(link): csr added

---------

Co-authored-by: Jakob Guddas <github@jguddas.de>

* feat: added RTL support to accordion component (#1725)

* feat: added RTL support to accordion component

* Create healthy-cobras-crash.md

* feat: added RTL support to avatar and avatar group component (#1727)

* feat: added RTL support to avatar and avatar group components

* Create tender-penguins-love.md

* Update tender-penguins-love.md

* feat: added RTL support to button group component (#1726)

* feat: added RTL support to button component

* feat: added RTL support to button component

* Create orange-bobcats-kneel.md

* Update button.ts

* refactor(root): styles refactor (#1688)

* refactor(root): styles refactor

* chore(tabs): remove needless type extends

* fix(tabs): typecheck

* Breadcrumbs component (#1794)

* feat(components): breadcrumbs initial structure

* feat(breadcrumbs): tests and examples added

* feat(docs): breadcrumbs documentation done

* feat(docs): breadcrumbs docs done

* chore(breadcrumbs): readme changed

* fix(slider): Place last dragged slider handle over the other handle (#1778)

* Set `data-focused` in handle

* Style focused handle on top

* Add tests

* fix(core): tests and build

* fix(button): show only spinner if button isLoading & isIconOnly (#1800)

* fix(button): show only spinner if button isLoading & isIconOnly

* chore: add changeset

* fix(button): remove repeating code

* Fix blur/opaque Popover (#1812)

* fix(popover): double underlay click

* chore: use ref instead of a state

* Feat/controlled scroll shadow (#1819)

* feat(scroll-shadow): logic improved, controlled support added

* feat(scroll-shadow): controlled visibility

* fix(scroll-shadow): visibility tests

* Autocomplete component (Single Selection) (#1797)

* feat(autocomplete): initial structure

* feat(core): use press custom hook implemented, autocomplete improved, input and select animations fixed

* chore(button): add console.log on press

* feat(core): select & input label position, autocomplete improvements, listbox and menu empty state

* chore: tailwind-variants upgraded

* chore: autocomplete stories in progress

* fix: input and select label placement

* fix(autocomplete): popover trigger

* chore(root): react-aria pkgs and framer-motion upgraded

* fix(input,select): outside label scale removed

* feat(autocomplete): more stories and use cases supported

* fix(core): custom items support on collection-based comps, menu generic items support added

* chore(core): tailwind-variants upgraded, custom tv function adapted

* chore(docs): select on-change controlled e.g. changed, sandpack theme fixed

* chore(autocomplete): docs started, tests added

* chore: in progress

* feat(menu): top and end content added, autocomplete docs improved

* feat(docs): autocomplete documentation almost done

* fix(input): outside styles

* feat(docs): autocomplete async filtering added

* chore(docs): autocomplete highlighted lines added

* feat(docs): autocomplete a11y and slots added

* feat(docs): autocomplete a11y and slots added

* feat(docs): autocomplete docs done

* fix(root): peer dependencies (#1848)

* Fix/small issues (#1851)

* fix(input): visible outline

* fix(button): button group radius prop

* chore(navbar): menu item active status added

* fix(docs): pagination missing keys custom items

* fix(core): extendVariants support added to collection-based components

* fix(theme): card body padding

* chore(theme): transition added to menu/listbox items

* fix(input): textarea styles fixed, new prop added

* chore(input): textarea height animated

* feat(button): hover opacity added

* chore(textarea): hide scroll when the limit hasn't been reached

* chore(docs): updated badge added to textarea

* feat(docs): blog v2.2.0 image and entry added

* fix(avatar): ring primary color

* chore(docs): tabs added again, autocomplete iframes removed

---------

Co-authored-by: Jakob Guddas <github@jguddas.de>
Co-authored-by: Maurici Abad Gutierrez <hello@mauriciabad.com>
Co-authored-by: Ivan Kucher <dev.kucher@gmail.com>
2023-11-03 11:05:16 -03:00
Danny Nemer c3f762563b docs: Fix typos in frameworks/nextjs.mdx (#1849) 2023-11-02 11:02:39 -03:00
Sandro Huber 8d2192183b Fix typo in table component doc (#1850) 2023-11-02 11:01:27 -03:00
Ajith 8b86f83802 Fix typo (#1835)
t he => the
2023-10-30 10:35:53 -03:00
Soohyun, Chae f38059aa44 Update tabs.mdx (#1781) 2023-10-21 13:01:27 +00:00
navedqb 311ceb0c3a Added missing imports to navbar (#1771) 2023-10-16 18:34:41 +00:00
Jakob Guddas 50a9bf54d4 fix: pagination issues second try (#1584)
* fix: pagination issues second try

* Create red-hairs-thank.md
2023-10-16 13:42:27 +00:00
KyungJi Kim 99d4d296d7 docs: fix storybook link in ComponentLinks (#1757) 2023-10-09 23:07:26 -03:00
Jakob Guddas 9245384ac3 docs: accessible toggle button in examples (#1749) 2023-10-07 11:54:16 +00:00
Junior Garcia 5af4b10114 fix(docs): scrollbar added to the sidebar (#1743) 2023-10-05 19:45:37 +00:00
Junior Garcia 8de357cfac fix(docs): sandpack hook react addition validation fixed (#1740) 2023-10-05 15:17:27 +00:00
Junior Garcia 655599982d fix(card): stories 2023-10-05 12:01:02 -03:00
POPO He 3aac9bac26 fix: resolved border collapse issue #1626 when border variants are mixed in button group (#1637)
* fix(button-group): radius not work

* fix(button): not show the correct borders

* fix(changeset): button issue

* fix(changeset): fix typo

* fix(changeset): tweak changeset message

* fix(button-groups): add miss undefined radius

* fix: make changeset clearly

* test(button-group): add variant button

* refactor: button-group variant handling in button-group.stories.tsx

* test: update button variant to 'bordered'

* refactor: rename isIsolate to isIsolated

* Revert "fix(button-group): radius not work"

This reverts commit 6233690d8acd96664c48d4f721c481bcb4095be4.

* fix: remove isIsolate because using a negative value for the margin will always cover the neighbor

* fix(changeset): remove radius part for another PR

* test: add multiple variant buttons on storybook

* fix: remove unused attribute

* feat: use adjacent selector to remove doubles border

* test: make variantButtons theme consistency

* refactor: use collapseAdjacentVariantBorders to wrap an adjacent selector

* Added RTL support.

---------

Co-authored-by: Jakob Guddas <github@jguddas.de>
2023-10-04 19:54:15 +00:00
markyong 95c8fdaa2e fix(select): add placeholder dep for renderSelectedItem (#1682) 2023-10-04 14:54:15 +00:00
Junior Garcia c0706acbca Fix/1609 (#1736)
* feat: storybook upgraded

* fix(skeleton): loading state

* chore(skeleton): changeset
2023-10-04 14:49:18 +00:00
Junior Garcia 9d4c7ed9cf fix(ripple): clear ripples on animation complete (#1681) 2023-09-23 13:18:13 +00:00
Sung Ye In 9ebaae083d fix: add peer dependencies (#1651)
* fix: add peer dependencies

* fix: update pnpm lock
2023-09-23 13:02:06 +00:00
Ansh Mourya c9c5564c58 fix: #1648 (#1655) 2023-09-23 09:36:55 -03:00
Bobby Chan d79808dbe1 fix(radio): correct the style of radio in invalid and selected states (#1668)
* fix(radio): correct the style of radio in invalid and selected states

* Update hot-otters-laugh.md
2023-09-22 13:59:11 +00:00
cosine 5a9b78d234 fix doc: Fixed some errors in the Listbox Component documentation. (#1665)
* fix doc: export IconWrapper and ItemCounter

* fix doc: fix WatcherIcons -> WatcherIcon at everywhere
2023-09-22 13:57:25 +00:00
Chewy 9f4bdf352d docs: add missing semicolon (#1663) 2023-09-20 17:38:14 +00:00
Junior Garcia d62feb08dc chore(docs): next.js upgraded 2023-09-20 01:45:07 -03:00
lijianan 62d307117a docs: fix code Sizes demo overflow (#1644) 2023-09-17 15:00:08 +00:00
Jakob Guddas 01a27293eb docs: updated isInvalid documentation (#1646)
* Update input.mdx

* Update textarea.mdx

* Update select.mdx
2023-09-17 14:54:38 +00:00
github-actions[bot] a53e274d5b ci(changesets): version packages (#1615)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-09-16 21:25:10 +00:00
Junior Garcia 425a034bca fix(packages): validation state deprecated, isInvalid prop adjusted (#1631) 2023-09-16 21:16:32 +00:00
lijianan a5a1ea5ade fix(docs): button custom implement (#1643) 2023-09-16 21:12:14 +00:00
Junior Garcia f6531c5f60 fix(core): extend variants function, destructuring order changed (#1642)
* fix(core): extend variants function, destructuring order changed

* chore(core): changeset added
2023-09-16 21:06:16 +00:00
Junior Garcia 37d5f12162 fix(docs): button custom implementation (#1641) 2023-09-16 20:28:52 +00:00
lijianan dd97fc3c4f fix: fix eslint warning (#1640) 2023-09-16 20:23:26 +00:00
lijianan ceddd0d1d9 refactor: optimize the time of ripple destroy (#1635)
* refactor: optimize the time of ripple destroy

* Update packages/components/button/src/use-button.ts

Co-authored-by: Jakob Guddas <github@jguddas.de>

* fix: fix

* Update packages/components/button/src/button.tsx

Co-authored-by: Jakob Guddas <github@jguddas.de>

* Update packages/components/card/src/card.tsx

Co-authored-by: Jakob Guddas <github@jguddas.de>

* Update packages/components/button/src/button.tsx

Co-authored-by: Jakob Guddas <github@jguddas.de>

* Update packages/components/card/src/card.tsx

Co-authored-by: Jakob Guddas <github@jguddas.de>

* Update packages/components/card/src/use-card.ts

Co-authored-by: Jakob Guddas <github@jguddas.de>

* Update packages/components/card/src/use-card.ts

Co-authored-by: Jakob Guddas <github@jguddas.de>

* fix: fix

* chore: revert

* Create fresh-cameras-provide.md

* Update packages/components/button/src/button.tsx

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

* Update packages/components/button/src/button.tsx

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

* Update packages/components/button/src/use-button.ts

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

* Update packages/components/card/src/card.tsx

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

* Update packages/components/card/src/card.tsx

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

* fix: fix

* feat: add getUniqueID

---------

Co-authored-by: Jakob Guddas <github@jguddas.de>
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-09-16 20:11:04 +00:00
Junior Garcia bb8ed58749 fix(accordion): selectedKeys added to the values memo function (#1639) 2023-09-16 20:01:39 +00:00
markyong bbbdcbdfdf chore(root): update contributing.md note (#1638) 2023-09-16 19:17:59 +00:00
Junior Garcia bc424948c7 fix(accordion): accordion is no longer preventing spacebar (#1630) 2023-09-15 20:42:02 +00:00
Junior Garcia cdc30db14c fix(utils): filterDomProps fixed (#1629) 2023-09-14 22:49:58 -03:00
Junior Garcia 3aa86423aa Fix/1625 (#1628)
* fix(listbox): item classNames prop, listbox wrapper export

* chore(listbox): changesets
2023-09-15 00:53:26 +00:00
Junior Garcia 59ed34b3de fix(docs): table use case example fixed, sandpack tabs padding added (#1627) 2023-09-15 00:30:17 +00:00
Chong Ruei He f58fc9bb69 fix(docs): add scrollbehavior ts support (#1618) 2023-09-14 20:13:07 +00:00
Junior Garcia 9a478b6c1f chore(docs): hero events 2023-09-13 09:16:48 -03:00
Junior Garcia 7fd0327657 chore(docs): va events added 2023-09-13 08:39:58 -03:00
Bobby Chan 05c966e8a4 fix(card): corrected footerStyles in card footer (#1611) 2023-09-12 13:20:09 -03:00
Nahuel Alejandro Cabrera 5b014b76ff Update explanation in layout.mdx (#1601) 2023-09-12 13:19:10 -03:00
Koen Verheyen cf32b5ae8b Update standalone.ts (#1614) 2023-09-12 13:18:47 -03:00
github-actions[bot] 4452ed66c0 ci(changesets): version packages (#1599)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-09-10 20:32:13 +00:00
Junior Garcia b1b30b7976 chore(root): fix changesets deploy (#1600) 2023-09-10 20:20:19 +00:00
github-actions[bot] 97ef2d7250 ci(changesets): version packages (#1565)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-09-10 19:58:22 +00:00
Junior Garcia 8b39989090 chore(root): changesets 2023-09-10 16:46:31 -03:00
Chongyi Zheng 8363a3ecfc fix: avoid src in import path (#1596)
* fix: avoid `src` in import path

* fix: export `RippleType`
2023-09-10 19:42:55 +00:00
Jakob Guddas 5c30e04811 fix: set nowrap in chip (#1590)
* fix: set nowrap in chip

* Create early-garlics-deliver.md
2023-09-10 19:16:06 +00:00
Adrian 8606fbe0b9 fix(links): corrected typo in accordion link (#1594) 2023-09-10 01:10:46 +00:00
Junior Garcia 1612532eee chore: react-aria packages upgraded (#1589) 2023-09-09 13:50:21 +00:00
Junior Garcia a3be419cb3 Fix/1561 (#1563)
* fix(select): bottom space

* chore(select): changeset
2023-09-03 13:19:17 +00:00
github-actions[bot] 72a7f71377 ci(changesets): version packages (#1559)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-09-02 21:38:53 +00:00
Junior Garcia 7c8341035d fix(pagination): changeset (#1558) 2023-09-02 21:28:41 +00:00
github-actions[bot] 6ca0ce309a ci(changesets): version packages (#1557)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-09-02 21:20:10 +00:00
Junior Garcia acc2ff3913 Merge branch 'main' of github.com:nextui-org/nextui 2023-09-02 18:07:05 -03:00
Junior Garcia 4db10a47e9 chore: changeset pagination revert 2023-09-02 18:06:51 -03:00
Junior Garcia a9c4fab011 chore: pagination changes changeset removed (#1556) 2023-09-02 20:53:55 +00:00
Junior Garcia d61428d9e6 Revert "ci(changesets): version packages (#1550)" (#1555)
This reverts commit 43906f639e.
2023-09-02 20:52:36 +00:00
Junior Garcia 455b788924 fix(docs): missing pagination docs added 2023-09-02 17:48:31 -03:00
Junior Garcia 79cfdbd8ff Revert "fix: resolved cursor issues in pagination (#1222)" (#1554)
This reverts commit 28477447d3.
2023-09-02 20:46:01 +00:00
Junior Garcia 7d294e3a04 Revert "fix: fixed pagination scale animation (#1552)" (#1553)
This reverts commit 8fcc8b3767.
2023-09-02 20:45:49 +00:00
github-actions[bot] 43906f639e ci(changesets): version packages (#1550)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-09-02 20:40:07 +00:00
Jakob Guddas 8fcc8b3767 fix: fixed pagination scale animation (#1552) 2023-09-02 15:45:27 -03:00
Jakob Guddas 28477447d3 fix: resolved cursor issues in pagination (#1222)
* fix: resolved cursor issues in pagination

* chore: added comment

* kick: trigger ci

* Create eighty-knives-heal.md
2023-09-02 18:01:38 +00:00
Junior Garcia fc3c6b9431 chore(root): tailwind variants upgraded (#1551)
* chore(root): tailwind variants upgraded

* fix(theme): prettier
2023-09-02 17:46:36 +00:00
Junior Garcia 59fda3772f fix(navbar-menu): dismiss buttons removed to fix the scroll (#1549) 2023-09-02 15:41:38 +00:00
Troye d8d2b87cb8 fix(docs): table async pagination (#1491)
* fix(docs): change to swr

* chore(table): change to swr

* fix(table): keep the pagination when switching pages

* chore(repo): pnpm lockfile updated
2023-09-02 12:56:39 +00:00
github-actions[bot] 64571e468c ci(changesets): version packages (#1514)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-09-01 21:09:05 +00:00
Junior Garcia faf26acd23 fix(snippet): invalid props (#1546) 2023-09-01 20:52:16 +00:00
Junior Garcia cac56faf29 chore(docs): hero tooltip arrow removed (#1547) 2023-09-01 20:45:41 +00:00
Junior Garcia 09fe1d3141 Fix/1531 (#1545)
* fix(tabs): title prop was being passed to html element

* chore(tabs): changeset
2023-09-01 20:44:46 +00:00
Junior Garcia a9e324b351 fix(listbox): dynamic items types (#1544) 2023-09-01 20:42:20 +00:00
Junior Garcia 043b8420cf Fix/1492 (#1543)
* fix(select): select & input styles fixed

* chore(input): extra data attr added to input wrapper
2023-09-01 20:42:15 +00:00
Junior Garcia 57909accde Fix/1298 (#1542)
* fix(modal): focus trap added

* chore(navbar): changeset added
2023-09-01 20:42:08 +00:00
Vansh Shah 7a17256268 Solved error in Listbox Component (#1530) 2023-08-31 14:06:13 -03:00
MisterHims bf2bc265ee feat: adding some adjustements on listbox and dropdown doc pages (#1520)
* fix: some typo and renamed use infinite scroll call on async section of select docpage

* fix(listbox-docpage): note doublon from the with icons section

* fix(switch-docpage): add a missing whitespace

* fix(dropdown-docpage): remove note doublon

* fix(dropdown-docpage): adding DropdownSection dependencu into the with-section code

* fix(dropdown-docpage): do not need Button component on custom-trigger section code

* fix(dropdown-docpage): fixed typo missing letter on dropdown-item list

* fix(dropdown-section): add missing comma
2023-08-29 18:05:55 +00:00
MisterHims cf6bf749a1 feat: adding some ajustements on listbox and dropdown doc pages (#1518) 2023-08-29 13:20:51 -03:00
Tianen Pang 641bf0885b feat(system): extend props for nextui provider (#1513) 2023-08-28 13:00:24 -03:00
MisterHims 40b42001f9 fix: some typo and renamed use infinite scroll call on async section of select docpage (#1509) 2023-08-27 19:30:49 -03:00
github-actions[bot] 789a7209a2 ci(changesets): version packages (#1500)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-08-26 14:57:11 +00:00
Junior Garcia 021aa16d96 chore(docs): inter font applied to tailwind config 2023-08-26 11:30:06 -03:00
Junior Garcia eb8a1fcc01 chore(docs): font family chnaged to inter 2023-08-26 11:24:28 -03:00
Junior Garcia 9b42a2fca1 fix(docs): select typo 2023-08-26 11:15:15 -03:00
Junior Garcia 5702287e56 fix(popover): arrow color (#1501) 2023-08-26 14:13:04 +00:00
Jakob Guddas 290cce15be fix: show focus ring when table row is focused in read mode (#1303)
* fix: show focus ring when table row is focused in read mode

* Create witty-trees-buy.md
2023-08-26 13:41:35 +00:00
github-actions[bot] 27bde30839 ci(changesets): version packages (#1499)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-08-26 13:39:00 +00:00
Junior Garcia 6be3bc3516 fix(docs): textarea readonly typo 2023-08-26 10:30:13 -03:00
T/once e4113b05ce fix(navbar): unable to Close NavbarMenu (#1496)
* add mode wait to AnimatePresence

* add changeset
2023-08-26 13:29:27 +00:00
Junior Garcia a3a95e7196 Merge branch 'main' of github.com:nextui-org/nextui 2023-08-26 10:27:22 -03:00
Junior Garcia 8731159702 fix(docs): font family 2023-08-26 10:27:08 -03:00
Hyuuh b6adb2ae8c docs(components): 📝 change to the new rsc link (#1493)
The new docs for Next.js RSC has been moved to a new section.
2023-08-25 17:29:00 +00:00
github-actions[bot] cd2d9b70a9 ci(changesets): version packages (#1477)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-08-23 03:26:47 +00:00
Junior Garcia a371e1a5fa Fix/tooltip arrow position (#1474)
* feat(blog): rss auto-discovery added

* fix(blog): feed.xml author name

* fix(tooltip): arrow position

* chore(tooltip): changeset
2023-08-23 03:11:15 +00:00
github-actions[bot] 5cdc4d1d87 ci(changesets): version packages (#1475)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-08-23 03:11:05 +00:00
Junior Garcia 22c6e070dd Fix/1469 (#1476)
* feat(blog): rss auto-discovery added

* fix(blog): feed.xml author name

* fix(docs): sandpack files filter
2023-08-23 03:10:41 +00:00
Junior Garcia 0714192838 Merge branch 'main' of github.com:nextui-org/nextui 2023-08-23 00:02:41 -03:00
Junior Garcia ae9f300d45 Fix/1468 (#1472)
* feat(blog): rss auto-discovery added

* fix(blog): feed.xml author name

* fix(select): size prop

* chore(root): changeset
2023-08-23 02:59:03 +00:00
Junior Garcia a16dac04c8 Merge branch 'main' of github.com:nextui-org/nextui 2023-08-22 23:49:47 -03:00
Junior Garcia 94db001961 Chore/docs improvemements (#1473)
* feat(blog): rss auto-discovery added

* fix(blog): feed.xml author name

* chore(docs): pnpm script modified
2023-08-23 02:46:37 +00:00
Junior Garcia d77cf7658b Feat/add rss auto discovery (#1471)
* feat(blog): rss auto-discovery added

* fix(blog): feed.xml author name
2023-08-23 02:43:58 +00:00
Junior Garcia 46c47f7e6e fix(blog): feed.xml author name 2023-08-22 12:37:26 -03:00
Junior Garcia 35b9741663 feat(blog): rss auto-discovery added 2023-08-22 12:34:35 -03:00
github-actions[bot] 2b82ba86eb ci(changesets): version packages (#1465)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-08-21 22:15:21 +00:00
Junior Garcia 904f538779 Chore/update react aria packages (#1463)
* fix(dropdown): popover and dropdown fixes

* fix(popover): arrow animation, shouldCloseOnInteractOutside function usage fixed

* chore(root): changeset

* chore(root): react-aria utils pkg updated

* fix(root): changesets

* fix(root): changeset
2023-08-21 22:06:36 +00:00
nirmalkumar 609e9f4c11 fix -( Image-Tag issue in Cover-image.ts ) (#1462) 2023-08-21 21:16:33 +00:00
github-actions[bot] e3dabac9f5 ci(changesets): version packages (#1461) 2023-08-21 12:28:39 -03:00
Junior Garcia 4e94c11528 fix(dropdown): popover and dropdown fixes (#1458) 2023-08-21 12:07:28 -03:00
João Vitor a17b6c7502 docs(tooltip): decrease zIndex so it doesn't overlap other elements (#1454)
* fix(navbar): z-index issue on desktop

* Revert "fix(navbar): z-index issue on desktop"

This reverts commit 227b79e5c6493084ee31a62fd5b13079c8a4a2e4.

* docs(tooltip): decrease the zIndex
2023-08-21 14:29:03 +00:00
github-actions[bot] bd72301b01 ci(changesets): version packages (#1456)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-08-21 13:40:21 +00:00
Junior Garcia cc839cdd1f Fix/select label closes the popover (#1455)
* fix(select): label pointer events removed

* chore(select): changeset
2023-08-21 13:29:49 +00:00
Yannik Hewlik c9e5c2ef7f docs: correct default value for popover radius (#1451)
* Update popover.mdx

* Update apps/docs/content/docs/components/popover.mdx

Co-authored-by: Jakob Guddas <github@jguddas.de>

---------

Co-authored-by: Jakob Guddas <github@jguddas.de>
2023-08-21 13:22:50 +00:00
Junior Garcia e8f5264cf8 fix(blog): v2.1.0 date 2023-08-21 10:11:10 -03:00
Junior Garcia df7f773f3d fix(blog): async typo 2023-08-21 09:49:59 -03:00
github-actions[bot] af925d56d1 ci(changesets): version packages (#1453)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-08-21 12:41:43 +00:00
Junior Garcia baec55029d Feat/select component (#1313)
* chore(root): menu and select components in progress

* chore(root): merged with main

* feat(menu): stories created

* feat(dropdown): menu migrated to menu component

* feat(select): base implementation in progress

* feat(select): listbox implemented

* feat(select): scroll overflow and auto scroll added

* feat(select): colors & variants improved, inside placement complete, outside pending

* feat(scroll-shadow): new component in progress

* feat(select): scroll shadow integrated

* fix(select): popover implementation, more scroll shadow stories added

* feat(listbox): custom styles example added to stories

* chore(listbox): overflow hidden removed

* feat(select): variants and styles completed

* chore(select): description story added

* feat(select): more stories added

* fix(select): dynamic collections inference, styles improved, more stories added

* fix(select): auto scroll to selected item, scroll padding added

* chore(select): scroll behavior changed to nearest

* feat(select): custom item story added

* fix(select): autoscroll fixed

* feat(select): multi select support added

* feat(select): more examples added, clean-package modified to remove dev packages

* chore(modal): useImperativeHandle removed

* feat(select): render value story improved

* feat(docs): listbox & scroll shadow docs done

* feat(docs): select documentation in progress

* fix: select aria label (#1425)

* feat(docs): more examples added

* feat(docs): select multiple added, storybook favicon changed

* fix: added value to aria label of select (#1431)

* feat(select): more examples added, storybook favicon changed

* fix(popover): dialog role removed

* feat(select): api added, async loading exampled added

* fix: fixed list box on click not working with sr click (#1439)

* feat(select): async items loading support added and documented

* feat(root): input styles updated to be as the select ones

* chore(root): listbox and scroll shadow readme updated

* feat(select): ts examples added, banner updated

* fix(popover): voiceover closes when focusing an item fixed

* chore(select): focus scope removed

* fix(popover): free solo popover added to use without a trigger

* feat(select): blog post added

* chore(docs): search meta generated, multi controlled onchange example fixed

* chore(root): changeset added

---------

Co-authored-by: Jakob Guddas <github@jguddas.de>
2023-08-21 12:28:01 +00:00
Gaurav Pandey ea2868e58e updated doc handling hydration mismatch error (#1449)
Co-authored-by: btsb78 <gaurav.pandey@kratikal.com>
2023-08-20 20:42:01 +00:00
Junior Garcia 691f380dff fix(docs): client directive added to next app examples on dark mode page 2023-08-20 11:45:23 -03:00
Junior Garcia ac8afec964 fix(modal): docs issues 2023-08-19 18:33:51 -03:00
Loïc GREFFIER 5fe5521a7c fix(docs): replaced ghost by dot in chip variants (#1436) 2023-08-18 20:49:36 -03:00
github-actions[bot] 15403bc67e ci(changesets): version packages (#1435) 2023-08-18 18:16:55 -03:00
Junior Garcia c186f37c98 fix(accordion): hide indicator prop in accordion item (#1433) 2023-08-18 20:59:49 +00:00
github-actions[bot] 1bc2a50e2c ci(changesets): version packages (#1434)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-08-18 20:57:44 +00:00
Junior Garcia 453f792a7a fix(link): warning onClick removed (#1432) 2023-08-18 20:50:13 +00:00
Junior Garcia 3f6fd48eee fix(docs): modal mail icon imports (#1421) 2023-08-17 12:48:06 +00:00
github-actions[bot] d7c6c79f38 ci(changesets): version packages (#1414)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-08-15 20:35:07 -03:00
Junior Garcia f068552774 refactor(tooltip): style prop merged with the passed one (#1413) 2023-08-15 20:28:23 -03:00
Cesar Leonardo Insuasty Moreno 6d7372ede1 fix: Import CardFooter in the card component doc (#1412) 2023-08-15 18:52:16 -03:00
github-actions[bot] 1487219a1c ci(changesets): version packages (#1411)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-08-15 18:30:06 -03:00
Junior Garcia 6e7e834c2d fix(popover): allow pass custom z-index (#1410) 2023-08-15 18:22:08 -03:00
Victor Bejas 80a8f7e94c fix/add import CardFooter at Card component composition (#1408) 2023-08-15 16:19:39 -03:00
github-actions[bot] fae7467b64 ci(changesets): version packages (#1407)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-08-15 14:41:45 -03:00
Tommaso De Rossi 4e7789c1f6 fix(input): don't always use controlled mode (#1406)
* fix(input): don't always use controlled mode

* fix(input): don't pass value to useTextField

* test(input): added test for mutating input via ref

* chore(input): changelog
2023-08-15 14:24:55 -03:00
Junior Garcia 6694b934e6 fix(docs): accordion item isOpen prop removed 2023-08-14 10:06:07 -03:00
github-actions[bot] 4d341081e3 ci(changesets): version packages (#1393)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-08-13 22:07:15 -03:00
github-actions[bot] df562449fb ci(changesets): version packages (#1392)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-08-13 21:50:12 -03:00
Junior Garcia 4063362699 fix(popover): use layout effect on the server warning 2023-08-13 21:42:57 -03:00
Junior Garcia 94d65df533 fix(root): filter dom props function fixed, slot prop added (#1391)
* fix(root): filter dom props function fixed, slot prop added

* chore(root): changeset added
2023-08-13 21:41:42 -03:00
Junior Garcia 8f66c6b564 fix(docs): individual installation highlights 2023-08-13 15:32:22 -03:00
Junior Garcia 4a19a3c906 Merge branch 'main' of github.com:nextui-org/nextui 2023-08-13 15:25:03 -03:00
Junior Garcia 0be398ade9 fix(docs): individual components styles 2023-08-13 15:24:48 -03:00
github-actions[bot] 50d23e5378 ci(changesets): version packages (#1385)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-08-13 00:03:39 -03:00
Junior Garcia d0341020e6 fix(docs): navbar with search input example (#1384) 2023-08-12 23:53:22 -03:00
github-actions[bot] 4170ecdc76 ci(changesets): version packages (#1383)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-08-12 23:33:09 -03:00
Junior Garcia e2b0076b53 chore(root): version field moved to bug report template 2023-08-12 23:27:55 -03:00
Junior Garcia e2b0497b07 fix(root): checkbox and radio onChange event types fixed (#1381) 2023-08-12 23:26:07 -03:00
Junior Garcia df3b309542 Merge branch 'main' of github.com:nextui-org/nextui 2023-08-12 22:56:11 -03:00
Junior Garcia 6c35a502fe chore(root): feature request template updated, version added 2023-08-12 22:55:37 -03:00
github-actions[bot] a629f8c088 ci(changesets): version packages (#1378)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-08-12 11:40:59 -03:00
Junior Garcia fd4e01dcfa fix(dropdown): spread key warning (#1377) 2023-08-12 11:33:13 -03:00
github-actions[bot] e9c08abd55 ci(changesets): version packages (#1374)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-08-11 21:10:32 -03:00
Junior Garcia 3e263aa882 fix(table): layout property (#1372) 2023-08-11 20:58:57 -03:00
Junior Garcia 9add9aba97 chore(docs): current version added to navbar dropdown (#1373) 2023-08-11 20:48:00 -03:00
Tudor Comparan 0311ae43f1 individual instalation, tailwind setup, require correct nextui package (#1371) 2023-08-11 16:07:23 -03:00
github-actions[bot] 79c5fb9a94 ci(changesets): version packages (#1370)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-08-11 15:02:25 -03:00
Junior Garcia abe1ba58de Fix/input undefined value (#1369)
* fix(input): undefined value uncontrolled

* fix(input): undefined value uncontrolled
2023-08-11 14:54:29 -03:00
Jakob Guddas e6c3747153 chore: added custom title for release PRs (#1368) 2023-08-11 14:12:11 -03:00
github-actions[bot] d15b16ecab ci(changesets): version packages (#1366)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-08-11 12:20:17 -03:00
Junior Garcia fe03c42fa1 fix(tooltip): filter dom props function fixed (#1365)
* fix(tooltip): filter dom props function fixed

* fix(root): react types pkg updated
2023-08-11 12:06:47 -03:00
navedqb 25a918d146 Fixed incorrect import in card component (#1364) 2023-08-11 09:04:17 -03:00
github-actions[bot] 87918ac5b4 ci(changesets): version packages (#1360)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-08-10 23:47:40 -03:00
Junior Garcia a30cec4810 chore(root): react-aria packages upgraded (#1359) 2023-08-10 23:25:24 -03:00
github-actions[bot] 1b0653c97a ci(changesets): version packages (#1353)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-08-10 17:35:26 -03:00
Junior Garcia 710395f3a2 Refactor/remove needless exports system (#1350)
* fix(root): filter dom props func, accordion keep content mounted, navbaropen menu callbacks

* refactor(system): needeless exports removed

* refactor(system): needeless exports removed
2023-08-10 17:27:53 -03:00
github-actions[bot] e7e58e854a ci(changesets): version packages (#1352)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-08-10 17:19:51 -03:00
Junior Garcia d13a14facc Fix/events and props issues (#1351)
* fix(root): filter dom props func, accordion keep content mounted, navbaropen menu callbacks

* fix(docs): examples keys
2023-08-10 17:10:53 -03:00
Junior Garcia cef7235c4b fix(docs): compound variants typo 2023-08-10 08:54:38 -03:00
Junior Garcia fcff1a1d36 Merge branch 'main' of github.com:nextui-org/nextui 2023-08-09 23:39:57 -03:00
Junior Garcia c7ba9e1508 fix(docs): customize theme button example, color added 2023-08-09 23:39:44 -03:00
github-actions[bot] 1d8dc4b9d8 ci(changesets): version packages (#1339)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-08-09 21:51:25 -03:00
github-actions[bot] ea5e0fb096 ci(changesets): version packages (#1338)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-08-09 21:42:53 -03:00
Junior Garcia 26f64d043d fix(storybook): padding 2023-08-09 21:40:54 -03:00
Jakob Guddas a078c3dcd2 chore: storybook improvements (#1335) 2023-08-09 21:36:54 -03:00
Jakob Guddas 5a50390e3f fix: moved sr only modal close buttons to not show unnecessary scroll bar (#1333)
* fix: moved sr only modal close buttons to not show unnecessary scroll bar

* Create sour-lizards-allow.md
2023-08-09 21:36:14 -03:00
Tianen Pang 894d85d059 docs(table): use case example (#1326) 2023-08-08 14:43:40 -03:00
github-actions[bot] 0ef41d27e7 ci(changesets): version packages (#1324)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-08-08 12:28:30 -03:00
Tianen Pang 4200164712 fix(input): duplicate triggering of input events (#1323)
* feat(utils): support for omit-names

* fix(input): exclude duplicate event props

* fix(input): exclude duplicate event fn only

* test(input): event fn call count

* chore(changeset): changeset added
2023-08-08 12:19:08 -03:00
Tianen Pang 6d4c6980d5 fix(docs): typo in the loading more data section (#1319) 2023-08-08 09:10:10 -03:00
github-actions[bot] f3f36a7146 ci(changesets): version packages (#1316)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-08-08 01:04:01 -03:00
Junior Garcia 8de209bff7 feat(root): new changeset 2023-08-08 00:56:56 -03:00
Junior Garcia e9d01be74d chore(root): eslint and prettier ignore updated 2023-08-08 00:45:14 -03:00
Junior Garcia 66ac2e67ae feat(root): new changeset 2023-08-08 00:44:58 -03:00
Junior Garcia 7ed88f39c1 chore(pagination): fix prettier 2023-08-08 00:41:58 -03:00
vaynevayne 32d18bfd41 Update pagination-item.tsx (#1315) 2023-08-08 00:41:09 -03:00
vaynevayne a1b32c1ceb Update use-pagination.ts (#1314) 2023-08-08 00:39:01 -03:00
Junior Garcia 9e683b32ba Merge branch 'main' of github.com:nextui-org/nextui 2023-08-08 00:12:35 -03:00
Junior Garcia b7c947805d feat(storybook): logo adapted to light/dark theme, favicon added 2023-08-08 00:12:21 -03:00
github-actions[bot] a76fdfa774 ci(changesets): version packages (#1310)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-08-07 23:40:34 -03:00
Junior Garcia ac605eb71f Fix/1307 input on value change (#1309)
* fix(input): inner event handler implemented

* chore(root): changeset added
2023-08-07 23:31:16 -03:00
Junior Garcia 5b343b6181 chore(root): storybook static files removed 2023-08-06 15:56:24 -03:00
Junior Garcia 05562dcf90 feat(root): storybook v7 2023-08-06 15:41:25 -03:00
github-actions[bot] 0a60388258 ci(changesets): version packages (#1302)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-08-06 15:23:26 -03:00
Junior Garcia d794225cb7 Pr/1224 (#1301)
* chore: storybook migration

* chore: storybook migration

* chore: storybook migration

* fix: moved options in arg types out of control

* fix: fixed type issues

* fix: renamed sb:start script to start

* chore: migrate csf 2 to csf 3

* fix: removed storybook build from root build script

* chore: kick

* chore(root): pnpm lock updated

* chore(root): new changeset

---------

Co-authored-by: Jakob Guddas <github@jguddas.de>
2023-08-06 15:04:26 -03:00
Junior Garcia ec2ed200f5 fix(docs): navbar imports 2023-08-06 14:53:19 -03:00
Junior Garcia 2f7703ec8e fix(docs): navbar imports 2023-08-06 14:53:12 -03:00
Junior Garcia 25cbe1146f chore(root): qa action parallelized again 2023-08-06 12:06:57 -03:00
Junior Garcia 3db9b6248e chore(root): qa action parallelized again 2023-08-06 11:59:43 -03:00
github-actions[bot] b1b5eda15b ci(changesets): version packages (#1293)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-08-06 00:02:27 -03:00
Junior Garcia e3e13a095f chore(root): new changeset 2023-08-05 23:49:42 -03:00
Junior Garcia 86f921d098 Feat/server components (#1291)
* feat(root): rsc components added, packages modified, filter dom props function adapted

* fix(root): eslint/prettier issues

* feat(root): exports changed to named, new pkg for system rsc compatible functions
2023-08-05 23:35:28 -03:00
Junior Garcia eefda8d6e2 feat(root): RSC components added, packages modified, filter dom props function adapted (#1289)
* feat(root): rsc components added, packages modified, filter dom props function adapted

* fix(root): eslint/prettier issues
2023-08-05 18:53:34 -03:00
Junior Garcia 2e4ce7bcee chore(root): all qa processes joined into a single one 2023-08-05 18:40:08 -03:00
Junior Garcia 5a4c4f498d chore(root): build step added to tests QA 2023-08-05 18:34:17 -03:00
Junior Garcia ec30a9adbd refactor(root): sotybook build folder added to repo 2023-08-05 11:14:27 -03:00
Junior Garcia a6954c4156 Merge branch 'main' of github.com:nextui-org/nextui 2023-08-05 11:13:53 -03:00
Junior Garcia b887a2f503 refactor(root): sotybook build folder added to repo 2023-08-05 11:13:37 -03:00
github-actions[bot] edc2bc741e ci(changesets): version packages (#1284)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-08-05 10:54:54 -03:00
Tianen Pang a1a02dc0db fix(tooltip): behavior of tooltip trigger with delay (#1278)
* fix(tooltip): use trigger-props instead of custom on-pointer events

* chore(changeset): add tooltip changeset
2023-08-05 10:46:01 -03:00
github-actions[bot] cd1dc8b469 ci(changesets): version packages (#1277)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-08-04 23:31:33 -03:00
Junior Garcia 459ac5ed45 chore: new changeset w/o minor version on theme 2 2023-08-04 23:20:00 -03:00
Junior Garcia 9c4bb22e87 chore: new changeset w/o minor version on theme 2023-08-04 23:03:21 -03:00
Junior Garcia 7fa5459381 feat(root): new changeset 2023-08-04 22:45:21 -03:00
Junior Garcia b77b8fa9d7 fix(modal): content placement changed on mobile when outside scroll (#1275) 2023-08-04 22:37:01 -03:00
Junior Garcia c6c4a4d6a1 fix(dropdown): item keys taken out from the itemProps (#1274) 2023-08-04 22:35:49 -03:00
Junior Garcia e96b1dbab0 fix(docs): radio & checkbox custom styles (#1273) 2023-08-04 22:34:37 -03:00
Junior Garcia 1b55d27645 fix(docs): remove autoFocus on webkit (#1272) 2023-08-04 22:33:41 -03:00
Junior Garcia bdc246a8a4 fix(table): ts use-case example, page state added (#1271) 2023-08-04 22:32:53 -03:00
Tianen Pang 5064bfe4e4 fix(docs): navbar examples (#1269)
* fix(navbar): use button tag and correctly pass props with child

* chore(navbar): sync example and code snippet
2023-08-04 14:41:54 -03:00
brick.ninja 36ddbff557 fix: typo navbar.tsx (#1264) 2023-08-03 18:13:55 -03:00
Junior Garcia 043b42c895 chore(docs): ea perc increased 2023-08-03 09:54:44 -03:00
Junior Garcia c8330b8106 Merge branch 'main' of github.com:nextui-org/nextui 2023-08-03 09:52:30 -03:00
Junior Garcia 7f20346423 chore(docs): ea perc increased 2023-08-03 09:51:01 -03:00
Ikko Eltociear Ashimine 85b3fd7269 fix(docs): typo in dropdown.mdx (#1255)
TThe -> The
2023-08-03 09:45:55 -03:00
Junior Garcia 649204ceac fix(root): qa action 2023-08-03 09:45:40 -03:00
Junior Garcia c7a1376872 fix(docs): poster added to blog videos, play/pause button added 2023-08-02 23:50:38 -03:00
Junior Garcia 3323592211 fix(blog): s3 url replaced by cloudfront 2023-08-02 22:57:16 -03:00
Junior Garcia fb570a372d feat(root): qa github action added 2023-08-02 22:33:37 -03:00
Junior Garcia 184d3a9c49 fix(root): changelog commands removed 2023-08-01 22:51:16 -03:00
github-actions[bot] 849eff5715 ci(changesets): version packages (#1234)
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
2023-08-01 18:10:12 -03:00
Junior Garcia b400f3ee6d chore(input): readme changed 2023-08-01 17:54:44 -03:00
Junior Garcia dedede0be0 feat(root): new release pipeline 2023-08-01 17:38:47 -03:00
Junior Garcia e96a23c8a3 Merge branch 'main' of github.com:nextui-org/nextui 2023-08-01 17:25:40 -03:00
Kwesi Ansah 7efd6c97e4 fix: fixes tab submitting form on click (#1233) 2023-08-01 17:25:20 -03:00
Junior Garcia 43e5e4fb26 chore(docs): announcement chip alpha border 2023-08-01 17:09:32 -03:00
Tianen Pang 39da69cf81 fix(docs): custom variants link (#1232) 2023-08-01 15:39:29 -03:00
Junior Garcia 8743a6c6b6 fix(blog): typo 2023-08-01 11:49:31 -03:00
Junior Garcia c635c951d6 fix(blog): typo 2023-08-01 11:44:18 -03:00
Junior Garcia cb05342a4a fix(docs): v1 redirect 2023-08-01 11:33:22 -03:00
Junior Garcia 59ef7bc6b6 feat(blog): rss added 2023-08-01 11:16:50 -03:00
Junior Garcia cfd19415ea fix(docs): v2 blog toc 2023-08-01 10:54:50 -03:00
Junior Garcia 39ca892b4e chore(root): changeset changelogs enabled 2023-07-31 23:40:30 -03:00
Junior Garcia fc2dad8b39 chore(docs): navbar announcement chip border color changed
Tagged Release / Tagged Release (push) Has been cancelled
2023-07-31 23:22:25 -03:00
Junior Garcia d9bbd2e45f feat(docs): next.js updated, sitemap generation added 2023-07-31 23:16:28 -03:00
Junior Garcia 75bc039b4b feat(root): storybook updated, custom variants docs format fixed 2023-07-31 22:58:55 -03:00
Junior Garcia e79bd0fa4c chore(docs): storybook links updated to v2 2023-07-31 22:50:46 -03:00
Junior Garcia 65c5af4f63 chore(core): ci/cd badge removed 2023-07-31 22:46:53 -03:00
Junior Garcia f58c8a7d99 feat(docs): missing resources added 2023-07-31 22:45:39 -03:00
Junior Garcia 9da06aaa50 chore(docs): remove dev-v2 tag from main package 2023-07-31 22:27:45 -03:00
Junior Garcia 508f11e968 chore(docs): v1 link added to navbar 2023-07-31 22:26:31 -03:00
Junior Garcia 2812f61f4f refactor(docs): nextui v2 blog date changed 2023-07-31 22:18:23 -03:00
Junior Garcia 0ee0e95678 fix(docs): invalid redirect 2023-07-31 22:14:28 -03:00
Junior Garcia e940ec06ac feat(root): v2 published 2023-07-31 22:10:19 -03:00
894 changed files with 63017 additions and 16509 deletions
+7 -1
View File
@@ -1,12 +1,18 @@
{
"$schema": "https://unpkg.com/@changesets/config@2.3.0/schema.json",
"changelog": false,
"changelog": [
"@changesets/changelog-github",
{ "repo": "nextui-org/nextui" }
],
"commit": false,
"fixed": [],
"linked": [],
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": {
"onlyUpdatePeerDependentsWhenOutOfRange": true
},
"ignore": [
"@nextui-org/docs",
"@nextui-org/storybook"
+1
View File
@@ -1,6 +1,7 @@
.now/*
.next/*
*.css
.changeset
dist
esm/*
public/*
+10
View File
@@ -21,6 +21,16 @@ body:
- NextUI's [Discussions tab](https://github.com/nextui-org/nextui/discussions)
The more information you fill in, the better the community can help you.
- type: input
id: version
attributes:
label: NextUI Version
description: |
Please provide the version of NextUI you are using.
You can find the version number in the package.json file.
placeholder: ex. 2.0.10
validations:
required: true
- type: textarea
id: description
attributes:
+27
View File
@@ -0,0 +1,27 @@
name: "Install"
description: "Sets up Node.js and runs install"
runs:
using: composite
steps:
- name: Install dependencies
uses: pnpm/action-setup@v2.2.4
with:
version: 8
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version-file: ".nvmrc"
registry-url: "https://registry.npmjs.org"
cache: "pnpm"
- name: Setup Git User
shell: bash
run: |
git config --global user.email "jrgarciadev@gmail.com"
git config --global user.name "Junior Garcia"
- name: Install dependencies
shell: bash
run: pnpm install
+72
View File
@@ -0,0 +1,72 @@
name: QA
on:
pull_request:
branches:
- main
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Checkout branch
uses: actions/checkout@v3
- name: Install
uses: ./.github/common-actions/install
- name: Build packages
run: pnpm build
tests:
name: Tests
runs-on: ubuntu-latest
steps:
- name: Checkout branch
uses: actions/checkout@v3
- name: Install
uses: ./.github/common-actions/install
- name: Run tests
run: pnpm test
eslint:
name: ESLint
runs-on: ubuntu-latest
steps:
- name: Checkout branch
uses: actions/checkout@v3
- name: Install
uses: ./.github/common-actions/install
- name: Run ESLint
run: pnpm lint
types:
name: TypeScript
runs-on: ubuntu-latest
steps:
- name: Checkout branch
uses: actions/checkout@v3
- name: Install
uses: ./.github/common-actions/install
- name: Run typecheck
run: pnpm typecheck
prettier:
name: Prettier
runs-on: ubuntu-latest
steps:
- name: Checkout branch
uses: actions/checkout@v3
- name: Install
uses: ./.github/common-actions/install
- name: Run prettier
run: pnpm format:check
-128
View File
@@ -1,128 +0,0 @@
name: CI/CD
on:
push:
branches: [main]
paths-ignore: ['**/README.md']
pull_request:
branches: [main]
types: [opened, synchronize]
paths-ignore: ['**/README.md']
jobs:
avoid_reduncy:
runs-on: ubuntu-20.04
if: ${{ github.event_name == 'push' }}
steps:
- name: Cancel Previous Redundant Builds
uses: styfle/cancel-workflow-action@0.9.1
with:
access_token: ${{ github.token }}
lint:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-node@v3
with:
cache: 'yarn'
node-version: '16'
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Lint
run: yarn lint
build:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-node@v3
with:
cache: 'yarn'
node-version: '16'
- name: Install dependencies
run: yarn install --frozen-lockfile
- uses: actions/cache@v3
with:
path: ${{ github.workspace }}/.next/cache
# Generate a new cache whenever packages or source files change.
key: ${{ runner.os }}-nextjs-${{ hashFiles('**/yarn.lock') }}-${{ hashFiles('**.[jt]s', '**.[jt]sx') }}
# If source files changed but packages didn't, rebuild from a prior cache.
restore-keys: |
${{ runner.os }}-nextjs-${{ hashFiles('**/yarn.lock') }}-
- name: Build
run: yarn build
tests:
needs: [lint, build]
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-node@v3
with:
cache: 'yarn'
node-version: '16'
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Test
run: yarn coverage:update
- uses: codecov/codecov-action@v2
with:
directory: './packages/react'
publish:
needs: [build, tests]
runs-on: ubuntu-20.04
if: ${{ github.event_name == 'push' }}
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
cache: 'yarn'
node-version: '16'
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Pre puiblish NextUI package
run: yarn pre-publish:nextui
- uses: JS-DevTools/npm-publish@v1
with:
token: ${{ secrets.NPM_TOKEN }}
package: './packages/react/lib/package.json'
- name: Show published version
if: steps.publish.outputs.type != 'none'
run: |
echo "Version changed: ${{ steps.publish.outputs.old-version }} => ${{ steps.publish.outputs.version }}"
- name: Tag new version
if: steps.publish.outputs.type != 'none'
uses: Klemensas/action-autotag@stable
with:
GITHUB_TOKEN: ${{ github.token }}
tag_prefix: "v"
package_root: "./packages/react"
update_algolia_index:
needs: [publish]
runs-on: ubuntu-20.04
if: ${{ github.event_name == 'push' }}
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-node@v3
with:
cache: 'yarn'
node-version: '16'
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Upload docs on Algolia
run: yarn build:docs-meta
env:
ALGOLIA_APP_ID: ${{ secrets.ALGOLIA_APP_ID }}
ALGOLIA_ADMIN_API_KEY: ${{ secrets.ALGOLIA_ADMIN_API_KEY }}
ALGOLIA_SEARCH_API_KEY: ${{ secrets.ALGOLIA_SEARCH_API_KEY }}
+45 -10
View File
@@ -1,17 +1,52 @@
name: Tagged Release
name: Release
on:
push:
tags:
- "v*"
paths:
- ".changeset/**"
- "packages/**"
branches:
- main
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
jobs:
tagged-release:
name: Tagged Release
runs-on: ubuntu-18.04
release:
name: Release
runs-on: ubuntu-latest
steps:
- uses: "marvinpinto/action-automatic-releases@latest"
- name: Checkout branch
uses: actions/checkout@v3
- name: Install
uses: ./.github/common-actions/install
- name: Build
run: pnpm build
- name: Tests
run: pnpm test
- name: Create Release Pull Request or Publish to NPM
id: changesets
uses: changesets/action@v1
with:
repo_token: "${{ github.token }}"
prerelease: false
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 @dev release
if: steps.changesets.outputs.published != 'true'
run: |
git checkout main
pnpm version:dev
pnpm release:dev
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+1
View File
@@ -20,6 +20,7 @@ coverage
dist/
storybook-static
/packages/storybook/public/tailwind.css
# misc
.DS_Store
.env
+2 -2
View File
@@ -13,12 +13,12 @@ const removeIgnoredFiles = async (files) => {
};
module.exports = {
"**/*.{cjs,mjs,js,ts,jsx,tsx}": async (files) => {
"**/*.{js,ts,jsx,tsx}": async (files) => {
const filesToLint = await removeIgnoredFiles(files);
return [`eslint -c .eslintrc.json --max-warnings=0 --fix ${filesToLint}`];
},
"**/*.{css,json,md}": async (files) => {
"**/*.css": async (files) => {
const filesToLint = await removeIgnoredFiles(files);
return [`prettier --config .prettierrc.json --ignore-path --write ${filesToLint}`];
+1
View File
@@ -2,6 +2,7 @@ dist
node_modules
plop
coverage
.changeset
.next
build
scripts
+1 -1
View File
@@ -182,7 +182,7 @@ pnpm test:update src/button # or npm run test:update src/button
pnpm build # or npm run build
```
> Note: ensure your version of Node is 14 or higher to run scripts
> Note: ensure your version of Node is 16 or higher to run scripts
6. Send your pull request:
+1 -2
View File
@@ -11,7 +11,6 @@ import {MDXContent} from "@/components/mdx-content";
import {siteConfig} from "@/config/site";
import {Route} from "@/libs/docs/page";
import {ChevronRightLinearIcon} from "@/components/icons";
import {__PROD__} from "@/utils";
interface BlogPostProps {
params: {
@@ -79,7 +78,7 @@ export async function generateStaticParams(): Promise<BlogPostProps["params"][]>
export default async function DocPage({params}: BlogPostProps) {
const {post} = await getBlogPostFromParams({params});
if (!post || __PROD__) {
if (!post) {
notFound();
}
-5
View File
@@ -2,15 +2,10 @@ import {allBlogPosts} from "contentlayer/generated";
import {compareDesc} from "date-fns";
import {BlogPostList} from "@/components/blog-post";
import {__PROD__} from "@/utils";
export default function Blog() {
const posts = allBlogPosts.sort((a, b) => compareDesc(new Date(a.date), new Date(b.date)));
if (__PROD__) {
return null;
}
return (
<div className="w-full lg:px-16 mt-12">
<div className="text-center">
+1 -1
View File
@@ -12,7 +12,7 @@ export default function DocsLayout({children}: DocsLayoutProps) {
<>
<main className="relative container mx-auto max-w-7xl z-10 px-6 min-h-[calc(100vh_-_64px_-_108px)] mb-12 flex-grow">
<div className="grid grid-cols-12">
<div className="hidden relative z-10 lg:block lg:col-span-2 mt-8 pr-4">
<div className="hidden overflow-visible relative z-10 lg:block lg:col-span-2 mt-8 pr-4">
<DocsSidebar routes={manifest.routes} />
</div>
{children}
@@ -0,0 +1,47 @@
/* eslint-disable no-console */
"use client";
import * as React from "react";
import {Autocomplete, AutocompleteItem} from "@nextui-org/react";
import {useAsyncList} from "@react-stately/data";
type SWCharacter = {
name: string;
height: string;
mass: string;
birth_year: string;
};
export default function Page() {
let list = useAsyncList<SWCharacter>({
async load({signal, filterText}) {
let res = await fetch(`https://swapi.py4e.com/api/people/?search=${filterText}`, {signal});
let json = await res.json();
return {
items: json.results,
};
},
});
return (
<div className="p-6">
<Autocomplete
className="max-w-xs"
inputValue={list.filterText}
isLoading={list.isLoading}
items={list.items}
label="Select a character"
placeholder="Type to search..."
variant="bordered"
onInputChange={list.setFilterText}
>
{(item) => (
<AutocompleteItem key={item.name} className="capitalize">
{item.name}
</AutocompleteItem>
)}
</Autocomplete>
</div>
);
}
@@ -0,0 +1,113 @@
/* eslint-disable no-console */
"use client";
import * as React from "react";
import {Autocomplete, AutocompleteItem} from "@nextui-org/react";
import {useInfiniteScroll} from "@nextui-org/use-infinite-scroll";
type Pokemon = {
name: string;
url: string;
};
type UsePokemonListProps = {
/** Delay to wait before fetching more items */
fetchDelay?: number;
};
function usePokemonList({fetchDelay = 0}: UsePokemonListProps = {}) {
const [items, setItems] = React.useState<Pokemon[]>([]);
const [hasMore, setHasMore] = React.useState(true);
const [isLoading, setIsLoading] = React.useState(false);
const [offset, setOffset] = React.useState(0);
const limit = 10; // Number of items per page, adjust as necessary
const loadPokemon = async (currentOffset: number) => {
const controller = new AbortController();
const {signal} = controller;
try {
setIsLoading(true);
if (offset > 0) {
// Delay to simulate network latency
await new Promise((resolve) => setTimeout(resolve, fetchDelay));
}
let res = await fetch(
`https://pokeapi.co/api/v2/pokemon?offset=${currentOffset}&limit=${limit}`,
{signal},
);
if (!res.ok) {
throw new Error("Network response was not ok");
}
let json = await res.json();
setHasMore(json.next !== null);
// Append new results to existing ones
setItems((prevItems) => [...prevItems, ...json.results]);
} catch (error) {
// @ts-ignore
if (error.name === "AbortError") {
console.log("Fetch aborted");
} else {
console.error("There was an error with the fetch operation:", error);
}
} finally {
setIsLoading(false);
}
};
React.useEffect(() => {
loadPokemon(offset);
}, []);
const onLoadMore = () => {
const newOffset = offset + limit;
setOffset(newOffset);
loadPokemon(newOffset);
};
return {
items,
hasMore,
isLoading,
onLoadMore,
};
}
export default function Page() {
const [isOpen, setIsOpen] = React.useState(false);
const {items, hasMore, isLoading, onLoadMore} = usePokemonList({fetchDelay: 1500});
const [, scrollerRef] = useInfiniteScroll({
hasMore,
isEnabled: isOpen,
shouldUseLoader: false, // We don't want to show the loader at the bottom of the list
onLoadMore,
});
return (
<div className="p-6">
<Autocomplete
className="max-w-xs"
defaultItems={items}
isLoading={isLoading}
label="Pick a Pokemon"
placeholder="Select a Pokemon"
scrollRef={scrollerRef}
variant="bordered"
onOpenChange={setIsOpen}
>
{(item) => (
<AutocompleteItem key={item.name} className="capitalize">
{item.name}
</AutocompleteItem>
)}
</Autocomplete>
</div>
);
}
@@ -0,0 +1,107 @@
"use client";
import * as React from "react";
import {Autocomplete, AutocompleteItem, MenuTriggerAction} from "@nextui-org/react";
import {useFilter} from "@react-aria/i18n";
const animals = [
{label: "Cat", value: "cat", description: "The second most popular pet in the world"},
{label: "Dog", value: "dog", description: "The most popular pet in the world"},
{label: "Elephant", value: "elephant", description: "The largest land animal"},
{label: "Lion", value: "lion", description: "The king of the jungle"},
{label: "Tiger", value: "tiger", description: "The largest cat species"},
{label: "Giraffe", value: "giraffe", description: "The tallest land animal"},
{
label: "Dolphin",
value: "dolphin",
description: "A widely distributed and diverse group of aquatic mammals",
},
{label: "Penguin", value: "penguin", description: "A group of aquatic flightless birds"},
{label: "Zebra", value: "zebra", description: "A several species of African equids"},
{
label: "Shark",
value: "shark",
description: "A group of elasmobranch fish characterized by a cartilaginous skeleton",
},
{
label: "Whale",
value: "whale",
description: "Diverse group of fully aquatic placental marine mammals",
},
{label: "Otter", value: "otter", description: "A carnivorous mammal in the subfamily Lutrinae"},
{label: "Crocodile", value: "crocodile", description: "A large semiaquatic reptile"},
];
type FieldState = {
selectedKey: React.Key | null;
inputValue: string;
items: typeof animals;
};
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: "",
inputValue: "",
items: animals,
});
// Implement custom filtering logic and control what items are
// available to the Autocomplete.
const {startsWith} = useFilter({sensitivity: "base"});
// Specify how each of the Autocomplete values should change when an
// option is selected from the list box
const onSelectionChange = (key: React.Key) => {
setFieldState((prevState) => {
let selectedItem = prevState.items.find((option) => option.value === key);
return {
inputValue: selectedItem?.label || "",
selectedKey: key,
items: animals.filter((item) => startsWith(item.label, selectedItem?.label || "")),
};
});
};
// Specify how each of the Autocomplete values should change when the input
// field is altered by the user
const onInputChange = (value: string) => {
setFieldState((prevState) => ({
inputValue: value,
selectedKey: value === "" ? null : prevState.selectedKey,
items: animals.filter((item) => startsWith(item.label, value)),
}));
};
// Show entire list if user opens the menu manually
const onOpenChange = (isOpen: boolean, menuTrigger: MenuTriggerAction) => {
if (menuTrigger === "manual" && isOpen) {
setFieldState((prevState) => ({
inputValue: prevState.inputValue,
selectedKey: prevState.selectedKey,
items: animals,
}));
}
};
return (
<div className="p-6">
<Autocomplete
className="max-w-xs"
inputValue={fieldState.inputValue}
items={fieldState.items}
label="Favorite Animal"
placeholder="Select an animal"
selectedKey={fieldState.selectedKey}
variant="bordered"
onInputChange={onInputChange}
onOpenChange={onOpenChange}
onSelectionChange={onSelectionChange}
>
{(item) => <AutocompleteItem key={item.value}>{item.label}</AutocompleteItem>}
</Autocomplete>
</div>
);
}
@@ -16,7 +16,7 @@ import {useState} from "react";
export default function Page() {
const {isOpen, onOpen, onOpenChange} = useDisclosure();
const [modalPlacement, setModalPlacement] = useState<ModalProps["placement"]>("auto");
const [modalPlacement, setModalPlacement] = useState("auto");
return (
<div className="flex px-10 min-h-[80vh] justify-center items-center flex-col gap-4">
@@ -36,7 +36,11 @@ export default function Page() {
<Radio value="top-center">top-center</Radio>
<Radio value="bottom-center">bottom-center</Radio>
</RadioGroup>
<Modal isOpen={isOpen} placement={modalPlacement} onOpenChange={onOpenChange}>
<Modal
isOpen={isOpen}
placement={modalPlacement as ModalProps["placement"]}
onOpenChange={onOpenChange}
>
<ModalContent>
{(onClose) => (
<>
@@ -8,7 +8,7 @@ import {
NavbarMenu,
NavbarMenuItem,
NavbarMenuToggle,
Avatar,
Button,
Link as NextUiLink,
LinkProps,
} from "@nextui-org/react";
@@ -79,16 +79,13 @@ export default function Page() {
</NavbarContent>
<NavbarContent justify="end">
<NavbarItem className="hidden lg:flex">
<Link href="#">Login</Link>
</NavbarItem>
<NavbarItem>
<Avatar
isBordered
as="button"
className="transition-transform"
color="warning"
name="Jane Lee"
size="sm"
src="https://i.pravatar.cc/150?u=a042581f4e29026704d"
/>
<Button as={Link} color="warning" href="#" variant="flat">
Sign Up
</Button>
</NavbarItem>
</NavbarContent>
@@ -51,22 +51,19 @@ export default function Page() {
</Link>
</NavbarItem>
</NavbarContent>
<NavbarContent justify="end">
<NavbarContent as="div" justify="end">
<Dropdown placement="bottom-end">
<NavbarItem>
<DropdownTrigger>
<Avatar
isBordered
as={Link}
className="transition-transform"
color="secondary"
href="#"
name="Jason Hughes"
size="sm"
src="https://i.pravatar.cc/150?u=a042581f4e29026704d"
/>
</DropdownTrigger>
</NavbarItem>
<DropdownTrigger>
<Avatar
isBordered
as="button"
className="transition-transform"
color="secondary"
name="Jason Hughes"
size="sm"
src="https://i.pravatar.cc/150?u=a042581f4e29026704d"
/>
</DropdownTrigger>
<DropdownMenu aria-label="Profile Actions" variant="flat">
<DropdownItem key="profile" className="h-14 gap-2">
<p className="font-semibold">Signed in as</p>
@@ -56,12 +56,13 @@ export default function Page() {
</NavbarItem>
</NavbarContent>
</NavbarContent>
<NavbarContent className="items-center" justify="end">
<NavbarContent as="div" className="items-center" justify="end">
<Input
classNames={{
base: "max-w-full sm:max-w-[10rem] h-10",
input: "text-small",
inputWrapper: "font-normal text-default-500 bg-default-400/20 dark:bg-default-500/20",
inputWrapper:
"h-full font-normal text-default-500 bg-default-400/20 dark:bg-default-500/20",
}}
placeholder="Type to search..."
startContent={<SearchLinearIcon size={18} />}
@@ -72,10 +73,9 @@ export default function Page() {
<DropdownTrigger>
<Avatar
isBordered
as={Link}
as="button"
className="transition-transform"
color="secondary"
href="#"
name="Jason Hughes"
size="sm"
src="https://i.pravatar.cc/150?u=a042581f4e29026704d"
+308 -6
View File
@@ -9,10 +9,17 @@ import {
Textarea,
Input,
Tab,
Avatar,
Select,
SelectItem,
AccordionItem,
Pagination,
extendVariants,
PaginationItem,
} from "@nextui-org/react";
import {useState} from "react";
import {useFilter} from "@react-aria/i18n";
import {useEffect, useMemo, useRef, useState} from "react";
import {useSearchParams} from "next/navigation";
import {SearchLinearIcon} from "@/components/icons";
@@ -175,16 +182,302 @@ const MyButton2 = extendVariants(Button, {
xl: "px-12 py-6 text-xl",
},
},
defaultVariants: {},
defaultVariants: {
color: "foreground",
},
});
const usersData = [
{
id: 1,
name: "Tony Reichert",
role: "CEO",
team: "Management",
status: "active",
age: "29",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/1.png",
email: "tony.reichert@example.com",
},
{
id: 2,
name: "Zoey Lang",
role: "Tech Lead",
team: "Development",
status: "paused",
age: "25",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/1.png",
email: "zoey.lang@example.com",
},
{
id: 3,
name: "Jane Fisher",
role: "Sr. Dev",
team: "Development",
status: "active",
age: "22",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/2.png",
email: "jane.fisher@example.com",
},
{
id: 4,
name: "William Howard",
role: "C.M.",
team: "Marketing",
status: "vacation",
age: "28",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/2.png",
email: "william.howard@example.com",
},
{
id: 5,
name: "Kristen Copper",
role: "S. Manager",
team: "Sales",
status: "active",
age: "24",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/3.png",
email: "kristen.cooper@example.com",
},
{
id: 6,
name: "Brian Kim",
role: "P. Manager",
team: "Management",
age: "29",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/3.png",
email: "brian.kim@example.com",
status: "Active",
},
{
id: 7,
name: "Michael Hunt",
role: "Designer",
team: "Design",
status: "paused",
age: "27",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/4.png",
email: "michael.hunt@example.com",
},
{
id: 8,
name: "Samantha Brooks",
role: "HR Manager",
team: "HR",
status: "active",
age: "31",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/4.png",
email: "samantha.brooks@example.com",
},
{
id: 9,
name: "Frank Harrison",
role: "F. Manager",
team: "Finance",
status: "vacation",
age: "33",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/5.png",
email: "frank.harrison@example.com",
},
{
id: 10,
name: "Emma Adams",
role: "Ops Manager",
team: "Operations",
status: "active",
age: "35",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/5.png",
email: "emma.adams@example.com",
},
{
id: 11,
name: "Brandon Stevens",
role: "Jr. Dev",
team: "Development",
status: "active",
age: "22",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/7.png",
email: "brandon.stevens@example.com",
},
{
id: 12,
name: "Megan Richards",
role: "P. Manager",
team: "Product",
status: "paused",
age: "28",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/7.png",
email: "megan.richards@example.com",
},
{
id: 13,
name: "Oliver Scott",
role: "S. Manager",
team: "Security",
status: "active",
age: "37",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/8.png",
email: "oliver.scott@example.com",
},
{
id: 14,
name: "Grace Allen",
role: "M. Specialist",
team: "Marketing",
status: "active",
age: "30",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/8.png",
email: "grace.allen@example.com",
},
{
id: 15,
name: "Noah Carter",
role: "IT Specialist",
team: "I. Technology",
status: "paused",
age: "31",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/9.png",
email: "noah.carter@example.com",
},
{
id: 16,
name: "Ava Perez",
role: "Manager",
team: "Sales",
status: "active",
age: "29",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/9.png",
email: "ava.perez@example.com",
},
{
id: 17,
name: "Liam Johnson",
role: "Data Analyst",
team: "Analysis",
status: "active",
age: "28",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/11.png",
email: "liam.johnson@example.com",
},
{
id: 18,
name: "Sophia Taylor",
role: "QA Analyst",
team: "Testing",
status: "active",
age: "27",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/11.png",
email: "sophia.taylor@example.com",
},
{
id: 19,
name: "Lucas Harris",
role: "Administrator",
team: "Information Technology",
status: "paused",
age: "32",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/12.png",
email: "lucas.harris@example.com",
},
{
id: 20,
name: "Mia Robinson",
role: "Coordinator",
team: "Operations",
status: "active",
age: "26",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/12.png",
email: "mia.robinson@example.com",
},
];
export default function NextUIPerf() {
const [textA, setTextA] = useState<string | undefined>("");
const [textB, setTextB] = useState<string | undefined>("");
const [textC, setTextC] = useState<string | undefined>("");
const [textA, setTextA] = useState<string>("");
const [textB, setTextB] = useState<string>("");
const [textC, setTextC] = useState<string>("");
const [isOpen, setIsOpen] = useState<boolean>(false);
const [inputValue, setInputValue] = useState<string>();
const [selectedKey, setSelectedKey] = useState<string>("");
const searchParams = useSearchParams();
const page = Number(searchParams.get("page"));
let {startsWith} = useFilter({sensitivity: "base"});
const filteredItems = inputValue
? usersData.filter((item) => startsWith(item.name, inputValue))
: usersData;
const inputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
isOpen && inputRef?.current?.focus();
}, [isOpen]);
const handleSelectionChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
setSelectedKey(e.target.value);
};
const topContent = useMemo(() => {
return (
<Input
ref={inputRef}
isClearable
aria-activedescendant={selectedKey}
aria-expanded={isOpen}
aria-label="Search user"
autoComplete="off"
autoCorrect="off"
className="z-10 sticky top-1"
placeholder="Search..."
spellCheck={false}
startContent={<SearchLinearIcon className="text-default-400" size={18} strokeWidth="2" />}
type="text"
onValueChange={setInputValue}
/>
);
}, [inputRef, selectedKey, isOpen]);
return (
<div className="w-full p-24 gap-4 flex flex-col">
<Select
classNames={{
base: "max-w-xs",
listboxWrapper: "scroll-pb-6 scroll-pt-28",
}}
items={filteredItems}
label="Assigned to"
labelPlacement="outside"
listboxProps={{
topContent,
variant: "flat",
classNames: {
base: [
"before:content-[''] before:rounded-t-medium before:fixed before:w-full before:h-14 before:z-10",
"before:top-0 before:left-0 before:bg-gradient-to-b before:from-default-50",
],
},
}}
placeholder="Select a user"
selectedKeys={[selectedKey]}
showScrollIndicators={false}
variant="flat"
onChange={handleSelectionChange}
onOpenChange={setIsOpen}
>
{(item) => (
<SelectItem key={item.id} textValue={item.name}>
<div className="flex gap-2 items-center">
<Avatar alt={item.name} className="flex-shrink-0" size="sm" src={item.avatar} />
<div className="flex flex-col">
<span className="text-small">{item.name}</span>
<span className="text-tiny text-default-400">{item.email}</span>
</div>
</div>
</SelectItem>
)}
</Select>
<Accordion>
<AccordionItem key="1" aria-label="Accordion 1" title="Accordion 1">
Non est aliqua tempor occaecat laborum. Lorem culpa minim irure mollit. Est qui
@@ -253,7 +546,16 @@ export default function NextUIPerf() {
<Button>Click Me!</Button>
<MyButton2 color="foreground">Press Me!</MyButton2>
<MyButton2 color="primary">Press Me!</MyButton2>
<Pagination
showControls
initialPage={page ?? 1}
renderItem={({page, ...itemProps}) => {
return <PaginationItem href={`/examples/perf?page=${page}`} {...itemProps} />;
}}
total={10}
/>
</div>
);
}
@@ -0,0 +1,113 @@
/* eslint-disable no-console */
"use client";
import {Select, SelectItem} from "@nextui-org/react";
import {useEffect, useState} from "react";
import {useInfiniteScroll} from "@nextui-org/use-infinite-scroll";
type Pokemon = {
name: string;
url: string;
};
type UsePokemonListProps = {
/** Delay to wait before fetching more items */
fetchDelay?: number;
};
function usePokemonList({fetchDelay = 0}: UsePokemonListProps = {}) {
const [items, setItems] = useState<Pokemon[]>([]);
const [hasMore, setHasMore] = useState(true);
const [isLoading, setIsLoading] = useState(false);
const [offset, setOffset] = useState(0);
const limit = 10; // Number of items per page, adjust as necessary
const loadPokemon = async (currentOffset: number) => {
const controller = new AbortController();
const {signal} = controller;
try {
setIsLoading(true);
if (offset > 0) {
// Delay to simulate network latency
await new Promise((resolve) => setTimeout(resolve, fetchDelay));
}
let res = await fetch(
`https://pokeapi.co/api/v2/pokemon?offset=${currentOffset}&limit=${limit}`,
{signal},
);
if (!res.ok) {
throw new Error("Network response was not ok");
}
let json = await res.json();
setHasMore(json.next !== null);
// Append new results to existing ones
setItems((prevItems) => [...prevItems, ...json.results]);
} catch (error) {
// @ts-ignore
if (error.name === "AbortError") {
console.log("Fetch aborted");
} else {
console.error("There was an error with the fetch operation:", error);
}
} finally {
setIsLoading(false);
}
};
useEffect(() => {
loadPokemon(offset);
}, []);
const onLoadMore = () => {
const newOffset = offset + limit;
setOffset(newOffset);
loadPokemon(newOffset);
};
return {
items,
hasMore,
isLoading,
onLoadMore,
};
}
export default function Page() {
const [isOpen, setIsOpen] = useState(false);
const {items, hasMore, isLoading, onLoadMore} = usePokemonList({fetchDelay: 1500});
const [, scrollerRef] = useInfiniteScroll({
hasMore,
isEnabled: isOpen,
shouldUseLoader: false, // We don't want to show the loader at the bottom of the list
onLoadMore,
});
return (
<div className="p-6">
<Select
className="max-w-xs"
isLoading={isLoading}
items={items}
label="Pick a Pokemon"
placeholder="Select a Pokemon"
scrollRef={scrollerRef}
selectionMode="single"
onOpenChange={setIsOpen}
>
{(item) => (
<SelectItem key={item.name} className="capitalize">
{item.name}
</SelectItem>
)}
</Select>
</div>
);
}
@@ -11,8 +11,8 @@ import {
Spinner,
Pagination,
} from "@nextui-org/react";
import {useAsyncList} from "@react-stately/data";
import {useCallback, useMemo, useState} from "react";
import {useMemo, useState} from "react";
import useSWR from "swr";
type SWCharacter = {
name: string;
@@ -21,50 +21,23 @@ type SWCharacter = {
birth_year: string;
};
const fetcher = (...args: Parameters<typeof fetch>) => fetch(...args).then((res) => res.json());
export default function Page() {
const [page, setPage] = useState(1);
const [total, setTotal] = useState(0);
const [isLoading, setIsLoading] = useState(true);
const {data, isLoading} = useSWR<{
count: number;
results: SWCharacter[];
}>(`https://swapi.py4e.com/api/people?page=${page}`, fetcher, {
keepPreviousData: true,
});
const rowsPerPage = 10;
let list = useAsyncList<SWCharacter>({
async load({signal, cursor}) {
// If no cursor is available, then we're loading the first page.
// Otherwise, the cursor is the next URL to load, as returned from the previous page.
const res = await fetch(cursor || "https://swapi.py4e.com/api/people/?search=", {signal});
let json = await res.json();
setTotal(json.count);
setIsLoading(false);
return {
items: json.results,
cursor: json.next,
};
},
});
const pages = Math.ceil(total / rowsPerPage);
const items = useMemo(() => {
const start = (page - 1) * rowsPerPage;
const end = start + rowsPerPage;
return list.items.slice(start, end);
}, [page, list.items?.length]);
const onPaginationChange = useCallback(
(page: number) => {
setIsLoading(true);
if (page >= list.items.length / rowsPerPage) {
list.loadMore();
}
setPage(page);
},
[list.items.length],
);
const pages = useMemo(() => {
return data?.count ? Math.ceil(data.count / rowsPerPage) : 0;
}, [data?.count, rowsPerPage]);
return (
<div className="p-6">
@@ -80,7 +53,7 @@ export default function Page() {
color="primary"
page={page}
total={pages}
onChange={onPaginationChange}
onChange={(page) => setPage(page)}
/>
</div>
) : null
@@ -96,8 +69,8 @@ export default function Page() {
<TableColumn key="birth_year">Birth year</TableColumn>
</TableHeader>
<TableBody
isLoading={isLoading && !items.length}
items={items}
isLoading={isLoading || data?.results.length === 0}
items={data?.results ?? []}
loadingContent={<Spinner />}
>
{(item) => (
@@ -105,7 +105,7 @@ const users = [
email: "kristen.cooper@example.com",
},
{
key: 6,
id: 6,
name: "Brian Kim",
role: "P. Manager",
team: "Management",
@@ -256,7 +256,7 @@ const users = [
},
];
type User = typeof users[0];
type User = (typeof users)[number];
export default function Page() {
const [filterValue, setFilterValue] = useState("");
+13 -9
View File
@@ -105,7 +105,7 @@ const users = [
email: "kristen.cooper@example.com",
},
{
key: 6,
id: 6,
name: "Brian Kim",
role: "P. Manager",
team: "Management",
@@ -256,7 +256,7 @@ const users = [
},
];
type User = typeof users[0];
type User = (typeof users)[number];
export default function Page() {
const [filterValue, setFilterValue] = useState("");
@@ -271,8 +271,6 @@ export default function Page() {
const [page, setPage] = useState(1);
const pages = Math.ceil(users.length / rowsPerPage);
const hasSearchFilter = Boolean(filterValue);
const headerColumns = useMemo(() => {
@@ -298,6 +296,8 @@ export default function Page() {
return filteredUsers;
}, [users, filterValue, statusFilter]);
const pages = Math.ceil(filteredItems.length / rowsPerPage);
const items = useMemo(() => {
const start = (page - 1) * rowsPerPage;
const end = start + rowsPerPage;
@@ -390,6 +390,11 @@ export default function Page() {
}
}, []);
const onClear = useCallback(() => {
setFilterValue("");
setPage(1);
}, []);
const topContent = useMemo(() => {
return (
<div className="flex flex-col gap-4">
@@ -400,7 +405,7 @@ export default function Page() {
placeholder="Search by name..."
startContent={<SearchIcon />}
value={filterValue}
onClear={() => setFilterValue("")}
onClear={() => onClear()}
onValueChange={onSearchChange}
/>
<div className="flex gap-3">
@@ -483,23 +488,22 @@ export default function Page() {
<span className="w-[30%] text-small text-default-400">
{selectedKeys === "all"
? "All items selected"
: `${selectedKeys.size} of ${items.length} selected`}
: `${selectedKeys.size} of ${filteredItems.length} selected`}
</span>
<Pagination
isCompact
showControls
showShadow
color="primary"
isDisabled={hasSearchFilter}
page={page}
total={pages}
onChange={setPage}
/>
<div className="hidden sm:flex w-[30%] justify-end gap-2">
<Button isDisabled={hasSearchFilter} size="sm" variant="flat" onPress={onPreviousPage}>
<Button isDisabled={pages === 1} size="sm" variant="flat" onPress={onPreviousPage}>
Previous
</Button>
<Button isDisabled={hasSearchFilter} size="sm" variant="flat" onPress={onNextPage}>
<Button isDisabled={pages === 1} size="sm" variant="flat" onPress={onNextPage}>
Next
</Button>
</div>
+38
View File
@@ -0,0 +1,38 @@
import Rss from "rss";
import {allBlogPosts} from "contentlayer/generated";
import {siteConfig} from "@/config/site";
import {allCoreContent} from "@/libs/contentlayer";
export async function GET() {
const feed = new Rss({
title: siteConfig.name,
description: siteConfig.description,
feed_url: `${siteConfig.siteUrl}/feed.xml`,
site_url: siteConfig.siteUrl,
webMaster: `${siteConfig.author} <${siteConfig.email}>`,
managingEditor: `${siteConfig.author} <${siteConfig.email}>`,
language: "en-US",
});
allCoreContent(allBlogPosts).forEach((post) => {
const author = post.author ? post.author : siteConfig.author;
feed.item({
title: post.title,
description: post.description ?? "",
url: `${siteConfig.siteUrl}/blog/${post.slug}`,
guid: `${siteConfig.siteUrl}/blog/${post.slug}`,
date: post.date,
// @ts-ignore - name does exist
author: `${author.name} <${siteConfig.email}>`,
categories: post.tags ?? [],
});
});
return new Response(feed.xml(), {
headers: {
"Content-Type": "application/xml",
},
});
}
+48
View File
@@ -0,0 +1,48 @@
import {Image} from "@nextui-org/react";
import {Blockquote} from "@/components/docs/components/blockquote";
import {FigmaButton} from "@/components/figma-button";
export default function FigmaPage() {
return (
<>
<main className="relative container mx-auto max-w-7xl z-10 px-6 min-h-[calc(100vh_-_64px_-_108px)] mb-12 flex-grow">
<section className="w-full flex flex-col items-center lg:px-16 mt-12 gap-6">
<div className="text-center max-w-xl">
<h1 className="mb-2 font-bold text-4xl">NextUI Figma Kit</h1>
<h5 className="text-default-500 text-lg">
A Figma file that contains the basis of the NextUI design system to help you design
your applications.
</h5>
</div>
<iframe
className="aspect-video w-full border border-transparent dark:border-default-200/50 object-fit rounded-xl shadow-lg"
height="600"
src="https://embed.figma.com/file/1267584376234254760/hf_embed?community_viewer=true&embed_host=nextui"
title="NextUI Figma Kit"
width="800"
/>
<div className="text-center max-w-2xl m-auto">
<FigmaButton />
<Blockquote color="warning">
This file is still in development and will be continuously updated.
</Blockquote>
</div>
</section>
</main>
<div
aria-hidden="true"
className="fixed hidden dark:md:block dark:opacity-70 -bottom-[40%] -left-[20%] z-0"
>
<Image removeWrapper alt="docs left background" src="/gradients/docs-left.png" />
</div>
<div
aria-hidden="true"
className="fixed hidden dark:md:block dark:opacity-70 -top-[80%] -right-[60%] 2xl:-top-[60%] 2xl:-right-[45%] z-0 rotate-12"
>
<Image removeWrapper alt="docs right background" src="/gradients/docs-right.png" />
</div>
</>
);
}
+8 -2
View File
@@ -40,7 +40,7 @@ export const metadata: Metadata = {
],
icons: {
icon: "/favicon.ico",
shortcut: "/favicon-16x16.png",
shortcut: "/favicon-32x32.png",
apple: "/apple-touch-icon.png",
},
manifest: "/manifest.json",
@@ -53,6 +53,12 @@ export const metadata: Metadata = {
},
],
creator: "jrgarciadev",
alternates: {
canonical: "https://nextui.org",
types: {
"application/rss+xml": [{url: "https://nextui.org/feed.xml", title: "NextUI RSS Feed"}],
},
},
viewport:
"viewport-fit=cover, width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0",
};
@@ -64,7 +70,7 @@ export default function RootLayout({children}: {children: React.ReactNode}) {
<body className={clsx("min-h-screen bg-background font-sans antialiased", fontSans.variable)}>
<Providers themeProps={{attribute: "class", defaultTheme: "dark"}}>
<div className="relative flex flex-col" id="app-container">
<Navbar routes={manifest.routes} />
<Navbar mobileRoutes={manifest.mobileRoutes} routes={manifest.routes} />
{children}
<Footer />
</div>
+1 -1
View File
@@ -1,4 +1,4 @@
import {Spacer} from "@nextui-org/react";
import {Spacer} from "@nextui-org/spacer";
import {Hero} from "@/components/marketing/hero";
import {FeaturesGrid} from "@/components/marketing/features-grid";
+4 -1
View File
@@ -4,6 +4,7 @@ import * as React from "react";
import {NextUIProvider} from "@nextui-org/react";
import {ThemeProvider as NextThemesProvider} from "next-themes";
import {ThemeProviderProps} from "next-themes/dist/types";
import {useRouter} from "next/navigation";
export interface ProvidersProps {
children: React.ReactNode;
@@ -11,8 +12,10 @@ export interface ProvidersProps {
}
export function Providers({children, themeProps}: ProvidersProps) {
const router = useRouter();
return (
<NextUIProvider>
<NextUIProvider navigate={router.push}>
<NextThemesProvider {...themeProps}>{children}</NextThemesProvider>
</NextUIProvider>
);
@@ -0,0 +1,116 @@
import React, {useCallback, useEffect} from "react";
import Script from "next/script";
import carbonOptimize from "./carbon-optimize";
import {loadScript} from "@/utils/scripts";
import {useIsMounted} from "@/hooks/use-is-mounted";
import {__PROD__} from "@/utils";
const EA_PROVIDER_RATIO = 0.85;
export const CarbonAd: React.FC<unknown> = () => {
const carbonRef = React.useRef(null);
const [showEthicalAds, setShowEthicalAds] = React.useState(false);
const isMounted = useIsMounted();
const loadEthicalAds = useCallback(() => {
return new Promise((resolve) => {
const script = document.createElement("script");
script.src = "https://media.ethicalads.io/media/client/ethicalads.min.js";
script.async = true;
script.onload = () => {
// @ts-ignore
resolve(window.ethicalads);
};
script.onerror = () => {
resolve(null);
};
document.body.appendChild(script);
return () => {
document.body.removeChild(script);
};
});
}, []);
useEffect(() => {
const shouldShowEthicalAds = Math.random() < EA_PROVIDER_RATIO;
let loadCarbon: any = null;
const loadCarbonAds = () => {
setShowEthicalAds(false);
// The isolation logic of carbonads is flawed.
// Once the script starts loading, it will asynchronous resolve, with no way to stop it.
// This leads to duplication of the ad. To solve the issue, we debounce the load action.
loadCarbon =
isMounted &&
setTimeout(() => {
const script = loadScript(
"https://cdn.carbonads.com/carbon.js?serve=CESIC53Y&placement=nextuiorg",
carbonRef.current,
);
script.id = "_carbonads_js";
carbonOptimize.init();
});
};
const loadAdProvider = async () => {
if (shouldShowEthicalAds) {
try {
const ethicalads = await loadEthicalAds();
if (!ethicalads) {
loadCarbonAds();
return;
}
// @ts-ignore
ethicalads.wait.then((placements) => {
if (!placements.length) {
loadCarbonAds();
} else {
setShowEthicalAds(true);
}
});
} catch (error) {
loadCarbonAds();
}
} else {
loadCarbonAds();
}
};
loadAdProvider();
return () => {
loadCarbon && clearTimeout(loadCarbon);
};
}, [isMounted]);
if (!__PROD__) return null;
return (
<>
<>
<Script async src="https://media.ethicalads.io/media/client/ethicalads.min.js" />
<div
className="ea-container horizontal"
data-ea-campaign-types="paid|publisher-house|community"
data-ea-publisher="nextuiorg"
data-ea-type="image"
style={{display: showEthicalAds ? "block" : "none"}}
/>
</>
<div className="carbon-ad-container" style={{display: showEthicalAds ? "none" : "block"}}>
<span ref={carbonRef} id="carbon-ad" />
</div>
</>
);
};
@@ -0,0 +1,64 @@
export default {
isRefreshAble: function () {
return !(
typeof document.addEventListener === "undefined" || this.browserSupport().hidden === undefined
);
},
browserSupport: function () {
let hidden;
let visibilityChange;
if (typeof document.hidden !== "undefined") {
// Opera 12.10 and Firefox 18 and later support
hidden = "hidden";
visibilityChange = "visibilitychange";
} else if (typeof document.msHidden !== "undefined") {
hidden = "msHidden";
visibilityChange = "msvisibilitychange";
} else if (typeof document.webkitHidden !== "undefined") {
hidden = "webkitHidden";
visibilityChange = "webkitvisibilitychange";
}
return {
hidden: hidden,
visibilityChange: visibilityChange,
};
},
handleVisibilityChange: function () {
const isElementInViewport = function (el) {
let element = document.querySelector(el);
let bounding = element.getBoundingClientRect();
let isVisible;
if (
bounding.top >= 0 &&
bounding.left >= 0 &&
bounding.right <= window.innerWidth &&
bounding.bottom <= window.innerHeight
) {
isVisible = true;
} else {
isVisible = false;
}
return isVisible;
};
if (!document.hidden) {
if (typeof _carbonads !== "undefined" && isElementInViewport("#carbonads")) {
// eslint-disable-next-line no-undef
_carbonads.refresh();
}
}
},
init: function () {
if (this.isRefreshAble()) {
document.addEventListener(
this.browserSupport().visibilityChange,
this.handleVisibilityChange,
false,
);
}
},
};
@@ -0,0 +1 @@
export * from "./carbon-ad";
+20 -9
View File
@@ -1,21 +1,31 @@
"use client";
import {BlogPost} from "contentlayer/generated";
import {Card, CardFooter, CardBody, CardHeader, Link, Avatar} from "@nextui-org/react";
import {Card, CardFooter, CardBody, CardHeader, Link, Avatar, Image} from "@nextui-org/react";
import Balancer from "react-wrap-balancer";
import {format, parseISO} from "date-fns";
import NextLink from "next/link";
import {AnimatePresence, motion} from "framer-motion";
import {useIsMounted} from "@/hooks/use-is-mounted";
import {trackEvent} from "@/utils/va";
const BlogPostCard = (post: BlogPost) => {
const isMounted = useIsMounted();
const handlePress = () => {
trackEvent("BlogPostCard - Selection", {
name: post.title,
action: "click",
category: "blog",
data: post.url ?? "",
});
};
return (
<AnimatePresence>
{isMounted && (
<motion.div
<motion.article
animate={{opacity: 1, y: 0}}
exit={{opacity: 0, y: 5}}
initial={{opacity: 0, y: 5}}
@@ -24,9 +34,10 @@ const BlogPostCard = (post: BlogPost) => {
<Card
isBlurred
as={NextLink}
className="p-2 border-transparent text-start bg-white/5 dark:bg-default-400/10 backdrop-blur-lg backdrop-saturate-[1.8]"
className="p-2 h-full border-transparent text-start bg-white/5 dark:bg-default-400/10 backdrop-blur-lg backdrop-saturate-[1.8]"
href={post.url}
isPressable={!!post.url}
onPress={handlePress}
>
<CardHeader>
<Link
@@ -35,14 +46,14 @@ const BlogPostCard = (post: BlogPost) => {
href={post.url}
size="lg"
underline="hover"
onPress={handlePress}
>
<Balancer>{post.title}</Balancer>
</Link>
</CardHeader>
<CardBody className="px-3 pt-0 pb-1">
<p className="font-normal text-default-600">
<Balancer>{post.description}</Balancer>
</p>
<CardBody className="pt-0 px-2 pb-1">
<Image className="mb-4" src={post.image} />
<p className="font-normal w-full text-default-600">{post.description}</p>
</CardBody>
<CardFooter className="flex justify-between items-center">
<time className="block text-small text-default-500" dateTime={post.date}>
@@ -51,7 +62,7 @@ const BlogPostCard = (post: BlogPost) => {
<Avatar size="sm" src={post.author?.avatar} />
</CardFooter>
</Card>
</motion.div>
</motion.article>
)}
</AnimatePresence>
);
@@ -59,7 +70,7 @@ const BlogPostCard = (post: BlogPost) => {
export const BlogPostList = ({posts}: {posts: BlogPost[]}) => {
return (
<div className="mt-10 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<div className="mt-10 grid gap-4 grid-cols-[repeat(auto-fill,minmax(300px,1fr))]">
{posts.map((post, idx) => (
<BlogPostCard key={idx} {...post} />
))}
+67 -7
View File
@@ -5,11 +5,14 @@ import {useInView} from "framer-motion";
import {useRef, FC, useEffect, useState, useCallback} from "react";
import {Button, cn, Spinner, Tooltip} from "@nextui-org/react";
import {PlayBoldIcon, PauseBoldIcon} from "@/components/icons";
import {RotateLeftLinearIcon} from "@/components/icons";
interface VideoInViewProps {
src: string;
playMode?: "auto" | "manual";
autoPlay?: boolean;
poster?: string;
width?: number;
height?: number;
controls?: boolean;
@@ -20,18 +23,25 @@ export const VideoInView: FC<VideoInViewProps> = ({
src,
width,
height,
poster,
autoPlay = true,
playMode = "manual",
controls = false,
className,
}) => {
const [isLoading, setIsLoading] = useState(true);
const [isPlaying, setIsPlaying] = useState(false);
const videoRef = useRef<HTMLVideoElement>(null);
const isVisible = useInView(videoRef);
// play video when it is visible
// play video when it is visible and playMode is auto
useEffect(() => {
if (playMode !== "auto") {
return;
}
if (isVisible) {
videoRef.current?.play();
} else {
@@ -39,19 +49,53 @@ export const VideoInView: FC<VideoInViewProps> = ({
}
}, [isVisible]);
const handleCanPlayThrough = useCallback(() => {
const handleCanPlay = useCallback(() => {
setIsLoading(false);
}, []);
useEffect(() => {
const videoEl = videoRef.current;
if (videoEl) {
if (videoEl.readyState > 3) {
// HAVE_FUTURE_DATA: enough data to start playing
handleCanPlay();
} else {
videoEl.addEventListener("canplaythrough", handleCanPlay);
}
// Cleanup the event listener
return () => {
videoEl.removeEventListener("canplaythrough", handleCanPlay);
};
}
}, []);
const onRestart = useCallback(() => {
if (videoRef.current) {
videoRef.current.currentTime = 0;
videoRef.current.play();
setIsPlaying(true);
}
}, []);
const onTogglePlay = useCallback(() => {
if (videoRef.current) {
if (!isPlaying) {
videoRef.current.play();
} else {
videoRef.current.pause();
}
setIsPlaying((v) => !v);
}
}, [isPlaying]);
return (
<div className="relative">
<div
className="relative data-[playing=true]:after:opacity-0 data-[playing=true]:after:z-[-1] after:content-[''] after:absolute after:inset-0 after:bg-black/30 after:z-20 after:transition-opacity"
data-playing={isPlaying}
>
{isLoading && (
<Spinner
className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2"
@@ -59,6 +103,22 @@ export const VideoInView: FC<VideoInViewProps> = ({
size="lg"
/>
)}
<Tooltip content={isPlaying ? "Pause" : "Play"} delay={1000}>
<Button
isIconOnly
className="absolute z-50 right-12 top-3 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"
size="sm"
variant="bordered"
onPress={onTogglePlay}
>
{isPlaying ? (
<PauseBoldIcon className="text-white" size={16} />
) : (
<PlayBoldIcon className="text-white" size={16} />
)}
</Button>
</Tooltip>
<Tooltip content="Restart" delay={1000}>
<Button
isIconOnly
@@ -67,24 +127,24 @@ export const VideoInView: FC<VideoInViewProps> = ({
variant="bordered"
onPress={onRestart}
>
<RotateLeftLinearIcon size={16} />
<RotateLeftLinearIcon className="text-white" size={16} />
</Button>
</Tooltip>
<video
ref={videoRef}
loop
muted
autoPlay={autoPlay}
autoPlay={autoPlay && playMode === "auto"}
className={cn(
"w-full border border-transparent dark:border-default-200/50 object-fit rounded-xl shadow-lg",
className,
)}
controls={controls}
height={height}
poster={poster}
src={src}
width={width}
onCanPlayThrough={handleCanPlayThrough}
onPlaying={() => setIsLoading(false)}
onCanPlay={handleCanPlay}
/>
</div>
);
+28 -4
View File
@@ -11,7 +11,7 @@ import {usePathname, useRouter} from "next/navigation";
import MultiRef from "react-multi-ref";
import {clsx} from "@nextui-org/shared-utils";
import scrollIntoView from "scroll-into-view-if-needed";
import {isAppleDevice} from "@react-aria/utils";
import {isAppleDevice, isWebKit} from "@react-aria/utils";
import {create} from "zustand";
import {intersectionBy, isEmpty} from "lodash";
import {writeStorage, useLocalStorage} from "@rehooks/local-storage";
@@ -25,6 +25,7 @@ import {
import searchData from "@/config/search-meta.json";
import {useUpdateEffect} from "@/hooks/use-update-effect";
import {trackEvent} from "@/utils/va";
const hideOnPaths = ["examples"];
@@ -175,6 +176,13 @@ export const Cmdk: FC<{}> = () => {
const matches = intersectionBy(...matchesForEachWord, "objectID").slice(0, MAX_RESULTS);
trackEvent("Cmdk - Search", {
name: "cmdk - search",
action: "search",
category: "cmdk",
data: {query, words, matches: matches?.map((match) => match.url).join(", ")},
});
return matches;
},
[query],
@@ -190,12 +198,21 @@ export const Cmdk: FC<{}> = () => {
if (e?.key?.toLowerCase() === "k" && e[hotkey]) {
e.preventDefault();
isOpen ? onClose() : onOpen();
trackEvent("Cmdk - Open/Close", {
name: "cmdk - open/close",
action: "keydown",
category: "cmdk",
data: isOpen ? "close" : "open",
});
}
};
document.addEventListener("keydown", onKeyDown);
return () => document.removeEventListener("keydown", onKeyDown);
return () => {
document.removeEventListener("keydown", onKeyDown);
};
}, [isOpen]);
const onItemSelect = useCallback(
@@ -203,6 +220,13 @@ export const Cmdk: FC<{}> = () => {
onClose();
router.push(item.url);
addToRecentSearches(item);
trackEvent("Cmdk - ItemSelect", {
name: item.content,
action: "click",
category: "cmdk",
data: item.url,
});
},
[router, recentSearches],
);
@@ -366,14 +390,14 @@ export const Cmdk: FC<{}> = () => {
placement="top-center"
scrollBehavior="inside"
size="xl"
onClose={onClose}
onClose={() => onClose()}
>
<ModalContent>
<Command className={slots.base()} label="Quick search command" shouldFilter={false}>
<div className={slots.header()}>
<SearchLinearIcon className={slots.searchIcon()} strokeWidth={2} />
<Command.Input
autoFocus
autoFocus={!isWebKit()}
className={slots.input()}
placeholder="Search documentation"
value={query}
@@ -108,9 +108,9 @@ function CodeTypewriter({value, className, css, ...props}: any) {
return (
<Pre className={className} css={css} {...props}>
<code
dangerouslySetInnerHTML={{__html: value}}
ref={wrapperRef}
className={className}
dangerouslySetInnerHTML={{__html: value}}
style={{opacity: 0}}
/>
</Pre>
@@ -155,7 +155,7 @@ const CodeBlock = React.forwardRef<HTMLPreElement, CodeBlockProps>((_props, forw
{...props}
>
{showWindowIcons && <WindowActions title={title} />}
<code className={clsx(classes, codeClasses)} dangerouslySetInnerHTML={{__html: result}} />
<code dangerouslySetInnerHTML={{__html: result}} className={clsx(classes, codeClasses)} />
</Pre>
);
});
@@ -3,6 +3,8 @@
import {useRef} from "react";
import {Button} from "@nextui-org/react";
import {trackEvent} from "@/utils/va";
export const CustomButton = () => {
const buttonRef = useRef<HTMLButtonElement | null>(null);
@@ -26,6 +28,11 @@ export const CustomButton = () => {
x: targetCenterX / clientWidth,
},
});
trackEvent("LandingPage - Confetti Button", {
action: "press",
category: "landing-page",
});
};
return (
+5 -5
View File
@@ -1,6 +1,6 @@
"use client";
import {Card, CardBody, Button, Image, Progress, CardProps} from "@nextui-org/react";
import {Card, CardBody, Button, Image, Slider, CardProps} from "@nextui-org/react";
import {useState, FC} from "react";
import {clsx} from "@nextui-org/shared-utils";
import NextImage from "next/image";
@@ -63,15 +63,15 @@ export const MusicPlayer: FC<MusicPlayerProps> = ({className, ...otherProps}) =>
</div>
<div className="flex flex-col mt-3 gap-1">
<Progress
<Slider
aria-label="Music progress"
classNames={{
indicator: "bg-default-800 dark:bg-white",
track: "bg-default-500/30",
thumb: "w-2 h-2 after:w-2 after:h-2 after:bg-foreground",
}}
color="default"
color="foreground"
defaultValue={33}
size="sm"
value={33}
/>
<div className="flex justify-between">
<p className="text-sm">1:23</p>
@@ -1,8 +1,10 @@
"use client";
import {FC} from "react";
import {tv, VariantProps} from "tailwind-variants";
const blockquoteStyles = tv({
base: "border pl-4 bg-default-50 my-6 py-3 rounded-xl [&>p]:m-0",
base: "border px-4 bg-default-50 my-6 py-3 rounded-xl [&>p]:m-0",
variants: {
color: {
default: "border-default-200 dark:border-default-100 bg-default-200/20",
@@ -9,6 +9,7 @@ import {useCodeDemo, UseCodeDemoProps} from "./use-code-demo";
import WindowResizer, {WindowResizerProps} from "./window-resizer";
import {GradientBoxProps} from "@/components/gradient-box";
import {trackEvent} from "@/utils/va";
const DynamicReactLiveDemo = dynamic(
() => import("./react-live-demo").then((m) => m.ReactLiveDemo),
@@ -31,11 +32,12 @@ interface CodeDemoProps extends UseCodeDemoProps, WindowResizerProps {
showSandpackPreview?: boolean;
initialEditorOpen?: boolean;
enableResize?: boolean;
showTabs?: boolean;
showPreview?: boolean;
hideWindowActions?: boolean;
showOpenInCodeSandbox?: boolean;
isPreviewCentered?: boolean;
resizeEnabled?: boolean;
typescriptStrict?: boolean;
displayMode?: "always" | "visible";
isGradientBox?: boolean;
gradientColor?: GradientBoxProps["color"];
@@ -51,16 +53,19 @@ export const CodeDemo: React.FC<CodeDemoProps> = ({
showEditor = true,
showPreview = true,
asIframe = false,
showTabs = true,
resizeEnabled = true,
hideWindowActions = false,
showSandpackPreview = false,
isPreviewCentered = false,
// when false .js files will be used
typescriptStrict = false,
showOpenInCodeSandbox,
isGradientBox = false,
defaultExpanded = false,
previewHeight = "auto",
overflow = "visible",
displayMode = "always",
showTabs = true,
gradientColor,
highlightedLines,
iframeInitialWidth,
@@ -96,6 +101,7 @@ export const CodeDemo: React.FC<CodeDemoProps> = ({
const content = asIframe ? (
<WindowResizer
hideWindowActions={hideWindowActions}
iframeHeight={previewHeight}
iframeInitialWidth={iframeInitialWidth}
iframeSrc={iframeSrc}
@@ -121,6 +127,7 @@ export const CodeDemo: React.FC<CodeDemoProps> = ({
isGradientBox,
gradientColor,
previewHeight,
hideWindowActions,
asIframe,
showPreview,
isInView,
@@ -138,6 +145,7 @@ export const CodeDemo: React.FC<CodeDemoProps> = ({
showEditor={showEditor}
showOpenInCodeSandbox={showOpenInCodeSandbox || showPreview}
showPreview={showSandpackPreview}
typescriptStrict={typescriptStrict}
/>
);
@@ -172,6 +180,14 @@ export const CodeDemo: React.FC<CodeDemoProps> = ({
panel: "pt-0",
}}
variant="underlined"
onSelectionChange={(tabKey) => {
trackEvent("CodeDemo - Selection", {
name: tabKey as string,
action: "tabChange",
category: "docs",
data: tabKey ?? "",
});
}}
>
<Tab key="preview" title="Preview">
{previewContent}
@@ -49,6 +49,7 @@ const resizer = tv({
export interface WindowResizerProps {
resizeEnabled?: boolean;
hideWindowActions?: boolean;
iframeHeight?: string | number;
iframeMinWidth?: number;
iframeSrc?: string;
@@ -70,6 +71,7 @@ const WindowResizer: React.FC<WindowResizerProps> = (props) => {
iframeSrc,
iframeTitle,
resizeEnabled,
hideWindowActions = false,
iframeHeight: height = "420px",
iframeInitialWidth,
iframeMinWidth: minWidth = MIN_WIDTH,
@@ -120,7 +122,7 @@ const WindowResizer: React.FC<WindowResizerProps> = (props) => {
width: isMobile ? "100%" : browserWidth,
}}
>
<WindowActions className="bg-default-100 dark:bg-default-50" />
{!hideWindowActions && <WindowActions className="bg-default-100 dark:bg-default-50" />}
<motion.iframe ref={iframeRef} className={iframe()} src={iframeSrc} title={iframeTitle} />
</motion.div>
{resizeEnabled && (
@@ -1,21 +1,25 @@
import React, {forwardRef} from "react";
import {clsx, getUniqueID} from "@nextui-org/shared-utils";
import React, {forwardRef, useEffect} from "react";
import {clsx, dataAttr, getUniqueID} from "@nextui-org/shared-utils";
import BaseHighlight, {Language, PrismTheme, defaultProps} from "prism-react-renderer";
import {debounce} from "lodash";
import defaultTheme from "@/libs/prism-theme";
import {trackEvent} from "@/utils/va";
interface CodeblockProps {
language: Language;
codeString: string;
metastring?: string;
theme?: PrismTheme;
children?: React.ReactNode;
showLines?: boolean;
removeIndent?: boolean;
hideScrollBar?: boolean;
className?: string;
children?: (props: any) => React.ReactNode;
}
type HighlightStyle = "inserted" | "deleted" | undefined;
const RE = /{([\d,-]+)}/;
const calculateLinesToHighlight = (meta?: string) => {
@@ -60,11 +64,76 @@ const Codeblock = forwardRef<HTMLPreElement, CodeblockProps>(
const shouldHighlightLine = calculateLinesToHighlight(metastring);
const isMultiLine = codeString.split("\n").length > 2;
const lastSelectionText = React.useRef<string | null>(null);
const isDiff = language.includes("diff");
const codeLang = isDiff ? (language.split("-")[1] as Language) : language;
let highlightStyle: HighlightStyle[] = [];
if (isDiff) {
let code: string[] = [];
highlightStyle = codeString.split?.("\n").map((line) => {
if (line.startsWith("+")) {
code.push(line.substr(1));
return "inserted";
}
if (line.startsWith("-")) {
code.push(line.substr(1));
return "deleted";
}
code.push(line);
});
codeString = code.join("\n");
}
useEffect(() => {
const handleSelectionChange = () => {
if (!window.getSelection) return;
const el = window.getSelection()?.anchorNode?.parentNode;
if (!el) return;
const selectionText = window.getSelection()?.toString();
if (!selectionText) return;
if (
!selectionText ||
selectionText === lastSelectionText.current ||
!codeString.includes(selectionText)
)
return;
lastSelectionText.current = selectionText;
trackEvent("Codeblock - Selection", {
action: "selectText",
category: "docs",
data: selectionText,
});
};
const debouncedHandleSelectionChange = debounce(handleSelectionChange, 1000);
document.addEventListener("selectionchange", debouncedHandleSelectionChange);
return () => {
document.removeEventListener("selectionchange", debouncedHandleSelectionChange);
};
}, []);
return (
<BaseHighlight
{...defaultProps}
code={codeString}
language={language}
language={codeLang}
theme={theme}
{...props}
>
@@ -97,6 +166,8 @@ const Codeblock = forwardRef<HTMLPreElement, CodeblockProps>(
shouldHighlightLine(i),
},
)}
data-deleted={dataAttr(highlightStyle?.[i] === "deleted")}
data-inserted={dataAttr(highlightStyle?.[i] === "inserted")}
>
{showLines && (
<span className="select-none text-xs mr-6 opacity-30">{i + 1}</span>
@@ -1,12 +1,16 @@
import {Button, ButtonProps, Link} from "@nextui-org/react";
import {Button, ButtonProps, Code, Link, Tooltip} from "@nextui-org/react";
import {ReactNode} from "react";
import Balancer from "react-wrap-balancer";
import {GithubIcon, NpmIcon, AdobeIcon, StorybookIcon} from "@/components/icons";
import {GithubIcon, NpmIcon, AdobeIcon, StorybookIcon, NextJsIcon} from "@/components/icons";
import {COMPONENT_PATH, COMPONENT_THEME_PATH} from "@/libs/github/constants";
import {trackEvent} from "@/utils/va";
export interface ComponentLinksProps {
component: string;
styles?: string;
storybook?: string;
rscCompatible?: boolean;
reactAriaHook?: string;
}
@@ -14,27 +18,51 @@ const ButtonLink = ({
children,
href,
startContent,
tooltip,
...props
}: ButtonProps & {
href: string;
}) => (
<Button
isExternal
as={Link}
className="!text-small py-4 bg-default-100 dark:bg-default-50 text-default-700"
href={href}
size="sm"
startContent={startContent}
{...props}
>
{children}
</Button>
);
tooltip?: string | ReactNode;
}) => {
const handlePress = () => {
if (!href) return;
trackEvent("ComponentLinks - Click", {
category: "docs",
action: "click",
data: href || "",
});
};
const button = (
<Button
isExternal
as={Link}
className="!text-small py-4 bg-default-100 dark:bg-default-50 text-default-700"
href={href}
size="sm"
startContent={startContent}
onPress={handlePress}
{...props}
>
{children}
</Button>
);
return tooltip ? (
<Tooltip className="max-w-[230px]" content={tooltip}>
{button}
</Tooltip>
) : (
button
);
};
export const ComponentLinks = ({
component,
storybook,
styles,
rscCompatible,
reactAriaHook,
}: ComponentLinksProps) => {
if (!component) {
@@ -44,7 +72,9 @@ export const ComponentLinks = ({
return (
<div className="flex flex-wrap gap-3 mt-6">
<ButtonLink
href={`https://storiesv2.nextui.org/?path=/story/components-${storybook || component}`}
href={`https://storybook.nextui.org/?path=/story/components-${
storybook || component
}--default`}
startContent={<StorybookIcon className="text-lg text-[#ff4785]" />}
>
Storybook
@@ -63,6 +93,26 @@ export const ComponentLinks = ({
React Aria
</ButtonLink>
)}
{rscCompatible && (
<ButtonLink
href="https://nextjs.org/docs/app/building-your-application/rendering/server-components"
startContent={<NextJsIcon size={18} />}
tooltip={
<p>
<Balancer>
This component doesn&apos;t use the
<Code className="font-normal bg-transparent px-0 py-0 text-code-mdx">
`use client;`
</Code>
directive making it compatible with RSC.
</Balancer>
</p>
}
>
Server component
</ButtonLink>
)}
<ButtonLink href={`${COMPONENT_PATH}/${component}`} startContent={<GithubIcon size={20} />}>
Source
</ButtonLink>
@@ -2,6 +2,8 @@ import {Tabs, Tab, Snippet} from "@nextui-org/react";
import Codeblock from "./codeblock";
import {trackEvent} from "@/utils/va";
type PackageManager = {
key: string;
name: string;
@@ -32,6 +34,14 @@ export const ImportTabs = ({commands}: ImportTabsProps) => {
tabList: "relative h-10",
}}
variant="underlined"
onSelectionChange={(tabKey) => {
trackEvent("ImportTabs - Selection", {
name: tabKey as string,
action: "tabChange",
category: "docs",
data: commands[tabKey] ?? "",
});
}}
>
{importTabs.map(({key, name}) => {
if (!commands[key]) return null;
@@ -47,6 +57,14 @@ export const ImportTabs = ({commands}: ImportTabsProps) => {
pre: "font-light text-base",
copyButton: "text-lg text-default-400",
}}
onCopy={() => {
trackEvent("ImportTabs - Copy", {
name,
action: "copyInstallScript",
category: "docs",
data: commands[name] ?? "",
});
}}
>
<Codeblock
hideScrollBar
@@ -1,8 +1,11 @@
import {Tabs, Tab, Snippet} from "@nextui-org/react";
import {Key} from "react";
import {useLocalStorage} from "usehooks-ts";
import Codeblock from "./codeblock";
import {YarnIcon, NpmSmallIcon, PnpmIcon} from "@/components/icons";
import {trackEvent} from "@/utils/va";
type PackageManagerName = "npm" | "yarn" | "pnpm";
@@ -27,10 +30,26 @@ const packageManagers: PackageManager[] = [
];
export interface PackageManagersProps {
commands: Partial<Record<PackageManagerName, string>>;
commands: Partial<Record<PackageManagerName, React.Key>>;
}
export const PackageManagers = ({commands}: PackageManagersProps) => {
const [selectedManager, setSelectedManager] = useLocalStorage<PackageManagerName>(
"selectedPackageManager",
"npm",
);
const handleSelectionChange = (tabKey: Key) => {
trackEvent("PackageManagers - Selection", {
name: `${tabKey}`,
action: "tabChange",
category: "docs",
data: commands[tabKey as unknown as PackageManagerName] ?? "",
});
setSelectedManager(tabKey as PackageManagerName);
};
return (
<Tabs
aria-label="NextUI installation commands"
@@ -38,7 +57,9 @@ export const PackageManagers = ({commands}: PackageManagersProps) => {
base: "group mt-4",
tabList: "h-10",
}}
selectedKey={selectedManager}
variant="underlined"
onSelectionChange={handleSelectionChange}
>
{packageManagers.map(({name, icon}) => {
if (!commands[name]) return null;
@@ -62,6 +83,14 @@ export const PackageManagers = ({commands}: PackageManagersProps) => {
pre: "font-light text-base",
copyButton: "text-lg text-zinc-500 mr-2",
}}
onCopy={() => {
trackEvent("PackageManagers - Copy", {
name,
action: "copyScript",
category: "docs",
data: commands[name] ?? "",
});
}}
>
<Codeblock removeIndent codeString={commands[name] as string} language="bash" />
</Snippet>
+18 -7
View File
@@ -1,31 +1,43 @@
"use client";
import * as React from "react";
import NextLink from "next/link";
import {Link} from "@nextui-org/react";
import {useRouter} from "next/navigation";
import {ChevronIcon} from "@nextui-org/shared-icons";
import manifest from "@/config/routes.json";
import {removeFromLast} from "@/utils";
import {Route} from "@/libs/docs/page";
import {useDocsRoute} from "@/hooks/use-docs-route";
import {trackEvent} from "@/utils/va";
export interface FooterNavProps {
currentRoute?: Route;
}
export const DocsPager: React.FC<FooterNavProps> = ({currentRoute}) => {
const router = useRouter();
const {prevRoute, nextRoute} = useDocsRoute(manifest.routes, currentRoute);
const handlePress = (path: string) => {
trackEvent("DocsPager - Click", {
category: "docs",
action: "click",
data: path || "",
});
router.push(removeFromLast(path || "", "."));
};
return (
<div className="flex w-full justify-between py-20">
{prevRoute ? (
<Link
isBlock
as={NextLink}
className="flex gap-2"
className="cursor-pointer flex gap-2"
color="foreground"
href={removeFromLast(prevRoute.path || "", ".")}
onPress={() => handlePress(prevRoute.path || "")}
>
<ChevronIcon className="text-primary" height={20} width={20} />
{prevRoute.title}
@@ -36,10 +48,9 @@ export const DocsPager: React.FC<FooterNavProps> = ({currentRoute}) => {
{nextRoute && (
<Link
isBlock
as={NextLink}
className="flex gap-1 items-center"
className="cursor-pointer flex gap-1 items-center"
color="foreground"
href={removeFromLast(nextRoute.path || "", ".")}
onPress={() => handlePress(nextRoute.path || "")}
>
{nextRoute.title}
<ChevronIcon className="rotate-180 text-primary" height={20} width={20} />
+32 -16
View File
@@ -21,11 +21,13 @@ import Link from "next/link";
import {isEmpty} from "lodash";
import {usePathname, useRouter} from "next/navigation";
import {ScrollArea} from "../scroll-area";
import {getRoutePaths} from "./utils";
import {Route} from "@/libs/docs/page";
import {TreeKeyboardDelegate} from "@/utils/tree-keyboard-delegate";
import {useScrollPosition} from "@/hooks/use-scroll-position";
import {trackEvent} from "@/utils/va";
export interface Props<T> extends Omit<ItemProps<T>, "title">, Route {
slug?: string;
@@ -68,6 +70,7 @@ function TreeItem<T>(props: TreeItemProps<T>) {
};
const isNew = item.props?.newPost;
const isUpdated = item.props?.updated;
const isExpanded = state.expandedKeys.has(key);
const isSelected =
@@ -88,6 +91,12 @@ function TreeItem<T>(props: TreeItemProps<T>) {
state.toggleKey(item.key);
} else {
router.push(paths.pathname);
trackEvent("SidebarDocs", {
category: "docs",
action: "click",
data: paths.pathname || "",
});
}
},
});
@@ -101,7 +110,9 @@ function TreeItem<T>(props: TreeItemProps<T>) {
aria-expanded={dataAttr(hasChildNodes ? isExpanded : undefined)}
aria-selected={dataAttr(isSelected)}
className={clsx(
"flex flex-col gap-3 outline-none w-full tap-highlight-transparent",
"flex flex-col gap-3outline-none w-full tap-highlight-transparent",
hasChildNodes ? "mb-4" : "first:mt-4",
// focus ring
...dataFocusVisibleClasses,
)}
@@ -149,18 +160,30 @@ function TreeItem<T>(props: TreeItemProps<T>) {
>
{rendered}
</span>
{isUpdated && (
<Chip
className="ml-1 py-1 text-tiny text-default-400 bg-default-100/50"
color="default"
size="sm"
variant="flat"
>
Updated
</Chip>
)}
{isNew && (
<Chip className="ml-2" color="primary" size="sm" variant="flat">
<Chip className="ml-1 py-1 text-tiny" color="primary" size="sm" variant="flat">
New
</Chip>
)}
{item.props?.comingSoon && (
<Chip className="ml-2" color="default" size="sm" variant="flat">
<Chip className="ml-1 py-1 text-tiny" color="default" size="sm" variant="flat">
Coming soon
</Chip>
)}
</NextUILink>
)}
{/* Workaround to avoid scrollbar overlapping */}
<Spacer x={4} />
</div>
{isExpanded && hasChildNodes && (
<div className="flex flex-col gap-3 items-start" role="group">
@@ -189,9 +212,7 @@ function TreeHeading({item}: {item: any}) {
function Tree<T extends object>(props: CollectionBase<T> & Expandable & MultipleSelection) {
let state = useTreeState(props);
let ref = useRef<HTMLUListElement>(null);
const scrollPosition = useScrollPosition(ref);
let ref = useRef<HTMLDivElement>(null);
let keyboardDelegate = useMemo(
// @ts-expect-error
@@ -206,16 +227,11 @@ function Tree<T extends object>(props: CollectionBase<T> & Expandable & Multiple
});
return (
<ul
{...collectionProps}
<ScrollArea
ref={ref}
className="flex flex-col gap-4 scrollbar-hide lg:overflow-y-scroll lg:max-h-[calc(100vh_-_64px)] pb-28"
className="h-full lg:max-h-[calc(100vh_-_64px)]"
role="tree"
style={{
WebkitMaskImage: `linear-gradient(to top, transparent 0%, #000 100px, #000 ${
scrollPosition > 30 ? "90%" : "100%"
}, transparent 100%)`,
}}
{...collectionProps}
>
{[...state.collection].map((item) => {
if (item.type === "section") {
@@ -224,7 +240,7 @@ function Tree<T extends object>(props: CollectionBase<T> & Expandable & Multiple
return <TreeItem key={item.key} item={item} state={state} />;
})}
</ul>
</ScrollArea>
);
}
+25
View File
@@ -0,0 +1,25 @@
"use client";
import {Button, Link} from "@nextui-org/react";
import {trackEvent} from "@/utils/va";
export const FigmaButton = () => (
<Button
isExternal
showAnchorIcon
as={Link}
className="max-w-fit text-current"
color="default"
href="https://www.figma.com/community/file/1267584376234254760"
variant="bordered"
onPress={() => {
trackEvent("FigmaPage - Open Figma Link", {
action: "click",
category: "figma",
});
}}
>
Open in Figma
</Button>
);
+2
View File
@@ -14,3 +14,5 @@ export * from "./info";
export * from "./document-code";
export * from "./hash";
export * from "./more-square";
export * from "./play";
export * from "./pause";
+23
View File
@@ -0,0 +1,23 @@
import {IconSvgProps} from "@/types";
export const PauseBoldIcon = ({size = 24, width, height, ...props}: IconSvgProps) => (
<svg
aria-hidden="true"
fill="none"
focusable="false"
height={size || height}
role="presentation"
viewBox="0 0 24 24"
width={size || width}
{...props}
>
<path
d="M10.65 19.11V4.89C10.65 3.54 10.08 3 8.64 3H5.01C3.57 3 3 3.54 3 4.89V19.11C3 20.46 3.57 21 5.01 21H8.64C10.08 21 10.65 20.46 10.65 19.11Z"
fill="currentColor"
/>
<path
d="M21 19.11V4.89C21 3.54 20.43 3 18.99 3H15.36C13.93 3 13.35 3.54 13.35 4.89V19.11C13.35 20.46 13.92 21 15.36 21H18.99C20.43 21 21 20.46 21 19.11Z"
fill="currentColor"
/>
</svg>
);
+19
View File
@@ -0,0 +1,19 @@
import {IconSvgProps} from "@/types";
export const PlayBoldIcon = ({size = 24, width, height, ...props}: IconSvgProps) => (
<svg
aria-hidden="true"
fill="none"
focusable="false"
height={size || height}
role="presentation"
viewBox="0 0 24 24"
width={size || width}
{...props}
>
<path
d="M4 11.9999V8.43989C4 4.01989 7.13 2.2099 10.96 4.4199L14.05 6.1999L17.14 7.9799C20.97 10.1899 20.97 13.8099 17.14 16.0199L14.05 17.7999L10.96 19.5799C7.13 21.7899 4 19.9799 4 15.5599V11.9999Z"
fill="currentColor"
/>
</svg>
);
@@ -14,6 +14,7 @@ import {PaletteIcon, MagicIcon, GamingConsoleIcon, StarIcon} from "@/components/
import {NextUILogo, CodeWindow} from "@/components";
import landingContent from "@/content/landing";
import {useIsMobile} from "@/hooks/use-media-query";
import {trackEvent} from "@/utils/va";
const themesTabs = (isMobile: boolean) => [
{
@@ -87,6 +88,12 @@ const CustomThemesExample = ({
const onSelectionChange = (value: React.Key) => {
onChangeTheme(value as Theme);
trackEvent("CustomThemes - Selection", {
action: "change_theme",
category: "landing-page",
data: value,
});
};
return (
@@ -6,6 +6,8 @@ import {Card, CardHeader, CardBody, LinkProps, SlotsToClasses} from "@nextui-org
import {useRouter} from "next/navigation";
import {LinkIcon} from "@nextui-org/shared-icons";
import {trackEvent} from "@/utils/va";
const styles = tv({
slots: {
base: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4",
@@ -38,6 +40,13 @@ export const FeaturesGrid: React.FC<FeaturesGridProps> = ({features, classNames,
const slots = styles();
const handleClick = (feat: Feature) => {
trackEvent("FeaturesGrid - Click", {
name: feat.title,
action: "click",
category: "docs",
data: feat.href ?? "",
});
if (!feat.href) {
return;
}
@@ -105,12 +105,14 @@ export const FloatingComponents: React.FC<{}> = () => {
{isMounted && (
<Tooltip
showArrow
className="text-sm animate-[levitate_14s_ease_infinite]"
color="secondary"
content="Developers love Next.js"
isOpen={!isTablet}
placement="top"
style={{
zIndex: 39,
}}
>
<Button
className="absolute left-[200px] top-[160px] max-w-fit animate-[levitate_14s_ease_infinite_0.5s]"
+42 -1
View File
@@ -1,7 +1,7 @@
"use client";
import NextLink from "next/link";
import {Button, Link} from "@nextui-org/react";
import {Button, Link, Chip} from "@nextui-org/react";
import {ArrowRightIcon} from "@nextui-org/shared-icons";
import dynamic from "next/dynamic";
@@ -9,15 +9,40 @@ import {FloatingComponents} from "./floating-components";
import {title, subtitle} from "@/components/primitives";
import {GithubIcon} from "@/components/icons";
import {trackEvent} from "@/utils/va";
const BgLooper = dynamic(() => import("./bg-looper").then((mod) => mod.BgLooper), {
ssr: false,
});
export const Hero = () => {
const handlePressAnnouncement = (name: string, url: string) => {
trackEvent("NavbarItem", {
name,
action: "press",
category: "home - gero",
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="flex relative z-20 flex-col gap-6 w-full lg:w-1/2 xl:mt-10">
<div className="w-full flex justify-center md:hidden">
<Chip
as={NextLink}
className="w-full hover:bg-default-100 border-default-200/80 dark:border-default-100/80 transition-colors cursor-pointer"
color="secondary"
href="/blog/v2.2.0"
variant="dot"
onClick={() => handlePressAnnouncement("Introducing v2.2.0", "/blog/v2.2.0")}
>
Introducing v2.2.0&nbsp;
<span aria-label="rocket emoji" role="img">
🚀
</span>
</Chip>
</div>
<div className="text-center leading-8 md:leading-10 md:text-left">
<div className="inline-block">
<h1 className={title()}>Make&nbsp;</h1>
@@ -42,6 +67,14 @@ export const Hero = () => {
href="/docs/guide/introduction"
radius="full"
size="lg"
onPress={() => {
trackEvent("Hero - Get Started", {
name: "Get Started",
action: "click",
category: "landing-page",
data: "/docs/guide/introduction",
});
}}
>
Get Started
</Button>
@@ -56,6 +89,14 @@ export const Hero = () => {
size="lg"
startContent={<GithubIcon />}
variant="bordered"
onPress={() => {
trackEvent("Hero - Github", {
name: "Github",
action: "click",
category: "landing-page",
data: "https://github.com/nextui-org/nextui",
});
}}
>
Github
</Button>
@@ -11,6 +11,7 @@ import {FeaturesGrid} from "./features-grid";
import {sectionWrapper, subtitle, title} from "@/components/primitives";
import {GithubIcon, NoteLinearIcon, NextJsIcon} from "@/components/icons";
import {useIsMounted} from "@/hooks/use-is-mounted";
import {trackEvent} from "@/utils/va";
const bannerSuggestions = [
{
@@ -69,6 +70,13 @@ export const InstallBanner = () => {
href="/docs/guide/installation"
radius="full"
size="md"
onClick={() => {
trackEvent("InstallBanner - Get Started", {
action: "press",
category: "landing-page",
data: "/docs/guide/installation",
});
}}
>
Get Started
</Button>
@@ -81,6 +89,13 @@ export const InstallBanner = () => {
size="md"
startContent={<GithubIcon />}
variant="bordered"
onClick={() => {
trackEvent("InstallBanner - Github", {
action: "press",
category: "landing-page",
data: "https://github.com/nextui-org/nextui",
});
}}
>
Github
</Button>
+10 -1
View File
@@ -12,6 +12,7 @@ import {OpenCollectiveIcon, PatreonIcon, HeartBoldIcon, PlusLinearIcon} from "@/
import {Sponsor, SPONSOR_TIERS, SPONSOR_COLORS, getTier} from "@/libs/docs/sponsors";
import {SonarPulse} from "@/components/sonar-pulse";
import {useIsMobile} from "@/hooks/use-media-query";
import {trackEvent} from "@/utils/va";
export interface SupportProps {
sponsors: Sponsor[];
@@ -100,6 +101,14 @@ export const Support: FC<SupportProps> = ({sponsors = []}) => {
window.open(href, "_blank");
};
const handleBecomeSponsor = () => {
trackEvent("Support - Become a sponsor", {
action: "click",
category: "landing-page",
});
handleExternalLinkClick(supportAccounts[0].href);
};
const renderSponsors = useMemo(() => {
if (!sponsors.length) return null;
@@ -181,7 +190,7 @@ export const Support: FC<SupportProps> = ({sponsors = []}) => {
aria-label="Become a sponsor"
className="z-50 w-auto h-auto bg-gradient-to-b from-[#FF1CF7] to-[#7928CA]"
radius="full"
onPress={() => handleExternalLinkClick(supportAccounts[0].href)}
onPress={handleBecomeSponsor}
>
<PlusLinearIcon
className="flex items-center justify-center rounded-full text-white"
+25 -3
View File
@@ -7,10 +7,12 @@ import NextImage from "next/image";
import {ThemeSwitch} from "./theme-switch";
import {Sandpack} from "@/components/sandpack";
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 {VirtualAnchor, virtualAnchorEncode} from "@/components";
import {trackEvent} from "@/utils/va";
const Table: React.FC<{children?: React.ReactNode}> = ({children}) => {
return (
@@ -143,6 +145,13 @@ const Code = ({
copyButton: "text-lg text-zinc-500 mr-2",
}}
codeString={codeString}
onCopy={() => {
trackEvent("MDXComponents - Copy", {
category: "docs",
action: "copyCode",
data: codeString,
});
}}
>
<Codeblock codeString={codeString} language={language} metastring={meta} />
</Components.Snippet>
@@ -152,8 +161,21 @@ const Code = ({
const Link = ({href, children}: {href?: string; children?: React.ReactNode}) => {
const isExternal = href?.startsWith("http");
const handlePress = () => {
trackEvent("MDXComponents - Click", {
category: "docs",
action: "click",
data: href || "",
});
};
return (
<Components.Link href={href} isExternal={isExternal} showAnchorIcon={isExternal}>
<Components.Link
href={href}
isExternal={isExternal}
showAnchorIcon={isExternal}
onPress={handlePress}
>
{children}
</Components.Link>
);
@@ -195,7 +217,7 @@ export const MDXComponents = {
thead: Thead,
tr: Trow,
td: Tcol,
// CarbonAd,
CarbonAd,
code: Code,
ul: List,
a: (props: React.HTMLAttributes<HTMLAnchorElement>) => <Link {...props} />,
@@ -207,7 +229,7 @@ export const MDXComponents = {
),
Steps: ({...props}) => (
<div
className="[&>h3]:step [&>h3>a]:pt-0.5 mb-12 ml-4 relative border-l border-default-100 pl-[1.625rem] [counter-reset:step]"
className="[&>h3]:step [&>h3>a]:pt-0.5 [&>h4]:step [&>h4>a]:pt-0.5 mb-12 ml-4 relative border-l border-default-100 pl-[1.625rem] [counter-reset:step]"
{...props}
/>
),
+102 -32
View File
@@ -1,6 +1,6 @@
"use client";
import {useRef, useState, FC, ReactNode} from "react";
import {useRef, useState, FC, ReactNode, Key} from "react";
import {
link,
Navbar as NextUINavbar,
@@ -16,6 +16,7 @@ import {
DropdownMenu,
DropdownItem,
DropdownTrigger,
Chip,
} from "@nextui-org/react";
import {dataFocusVisibleClasses} from "@nextui-org/theme";
import {ChevronDownIcon, LinkIcon} from "@nextui-org/shared-icons";
@@ -29,6 +30,7 @@ import {useEffect} from "react";
import {usePress} from "@react-aria/interactions";
import {useFocusRing} from "@react-aria/focus";
import {currentVersion} from "@/utils/version";
import {siteConfig} from "@/config/site";
import {Route} from "@/libs/docs/page";
import {LargeLogo, SmallLogo, ThemeSwitch} from "@/components";
@@ -42,16 +44,17 @@ import {
import {useIsMounted} from "@/hooks/use-is-mounted";
import {DocsSidebar} from "@/components/docs/sidebar";
import {useCmdkStore} from "@/components/cmdk";
import {__PROD__} from "@/utils";
import {trackEvent} from "@/utils/va";
export interface NavbarProps {
routes: Route[];
mobileRoutes?: Route[];
tag?: string;
slug?: string;
children?: ReactNode;
}
export const Navbar: FC<NavbarProps> = ({children, routes, slug, tag}) => {
export const Navbar: FC<NavbarProps> = ({children, routes, mobileRoutes = [], slug, tag}) => {
const [isMenuOpen, setIsMenuOpen] = useState<boolean | undefined>(false);
const [commandKey, setCommandKey] = useState<"ctrl" | "command">("command");
@@ -60,7 +63,7 @@ export const Navbar: FC<NavbarProps> = ({children, routes, slug, tag}) => {
const pathname = usePathname();
const cmkdStore = useCmdkStore();
const cmdkStore = useCmdkStore();
useEffect(() => {
if (isMenuOpen) {
@@ -72,8 +75,17 @@ export const Navbar: FC<NavbarProps> = ({children, routes, slug, tag}) => {
setCommandKey(isAppleDevice() ? "command" : "ctrl");
}, []);
const handleOpenCmdk = () => {
cmdkStore.onOpen();
trackEvent("Navbar - Search", {
name: "navbar - search",
action: "press",
category: "cmdk",
});
};
const {pressProps} = usePress({
onPress: () => cmkdStore.onOpen(),
onPress: handleOpenCmdk,
});
const {focusProps, isFocusVisible} = useFocusRing();
@@ -99,7 +111,7 @@ export const Navbar: FC<NavbarProps> = ({children, routes, slug, tag}) => {
strokeWidth={2}
/>
}
onPress={() => cmkdStore.onOpen()}
onPress={handleOpenCmdk}
>
Quick Search...
</Button>
@@ -109,10 +121,24 @@ export const Navbar: FC<NavbarProps> = ({children, routes, slug, tag}) => {
return null;
}
const navLinkClasses = clsx(
link({color: "foreground"}),
"data-[active=true]:text-primary data-[active=true]:font-medium",
);
const navLinkClasses = clsx(link({color: "foreground"}), "data-[active=true]:text-primary");
const handleVersionChange = (key: Key) => {
if (key === "v1") {
const newWindow = window.open("https://v1.nextui.org", "_blank", "noopener,noreferrer");
if (newWindow) newWindow.opener = null;
}
};
const handlePressNavbarItem = (name: string, url: string) => {
trackEvent("NavbarItem", {
name,
action: "press",
category: "navbar",
data: url,
});
};
return (
<NextUINavbar
@@ -131,6 +157,7 @@ export const Navbar: FC<NavbarProps> = ({children, routes, slug, tag}) => {
aria-label="Home"
className="flex justify-start items-center gap-2 tap-highlight-transparent transition-opacity active:opacity-50"
href="/"
onClick={() => handlePressNavbarItem("Home", "/")}
>
<SmallLogo className="w-6 h-6 md:hidden" />
<LargeLogo className="h-5 md:h-6" />
@@ -148,7 +175,7 @@ export const Navbar: FC<NavbarProps> = ({children, routes, slug, tag}) => {
size="sm"
variant="flat"
>
v2.0.0
v{currentVersion}
</Button>
</DropdownTrigger>
</motion.div>
@@ -158,8 +185,9 @@ export const Navbar: FC<NavbarProps> = ({children, routes, slug, tag}) => {
aria-label="NextUI versions"
defaultSelectedKeys={["v2"]}
selectionMode="single"
onAction={handleVersionChange}
>
<DropdownItem key="v2">v2.0.0</DropdownItem>
<DropdownItem key="v2">v{currentVersion}</DropdownItem>
<DropdownItem key="v1" endContent={<LinkIcon />}>
v1.0.0
</DropdownItem>
@@ -169,13 +197,14 @@ export const Navbar: FC<NavbarProps> = ({children, routes, slug, tag}) => {
<div className="w-[74px]" />
)}
</NavbarBrand>
<ul className="hidden lg:flex gap-4 justify-start">
<ul className="hidden lg:flex gap-4 justify-start items-center">
<NavbarItem>
<NextLink
className={navLinkClasses}
color="foreground"
data-active={includes(docsPaths, pathname)}
href="/docs/guide/introduction"
onClick={() => handlePressNavbarItem("Docs", "/docs/guide/introduction")}
>
Docs
</NextLink>
@@ -186,32 +215,48 @@ export const Navbar: FC<NavbarProps> = ({children, routes, slug, tag}) => {
color="foreground"
data-active={includes(pathname, "components")}
href="/docs/components/avatar"
onClick={() => handlePressNavbarItem("Components", "/docs/components/avatar")}
>
Components
</NextLink>
</NavbarItem>
{!__PROD__ && (
<NavbarItem>
<NextLink
className={navLinkClasses}
color="foreground"
data-active={includes(pathname, "blog")}
href="/blog"
>
Blog
</NextLink>
</NavbarItem>
)}
<NavbarItem>
<NextLink
className={navLinkClasses}
color="foreground"
data-active={includes(pathname, "blog")}
href="/blog"
onClick={() => handlePressNavbarItem("Blog", "/blog")}
>
Blog
</NextLink>
</NavbarItem>
<NavbarItem>
<NextLink
className={navLinkClasses}
color="foreground"
data-active={includes(pathname, "figma")}
href="/figma"
onClick={() => handlePressNavbarItem("Figma", "/figma")}
>
Figma
</NextLink>
</NavbarItem>
<NavbarItem>
<Chip
as={NextLink}
className="hover:bg-default-100 border-default-200/80 dark:border-default-100/80 transition-colors cursor-pointer"
color="secondary"
href="/blog/v2.2.0"
variant="dot"
onClick={() => handlePressNavbarItem("Introducing v2.2.0", "/blog/v2.2.0")}
>
Introducing v2.2.0&nbsp;
<span aria-label="rocket emoji" role="img">
🚀
</span>
</Chip>
</NavbarItem>
</ul>
</NavbarContent>
@@ -222,6 +267,7 @@ export const Navbar: FC<NavbarProps> = ({children, routes, slug, tag}) => {
aria-label="Github"
className="p-1"
href="https://github.com/nextui-org/nextui"
onClick={() => handlePressNavbarItem("Github", "https://github.com/nextui-org/nextui")}
>
<GithubIcon className="text-default-600 dark:text-default-500" />
</Link>
@@ -243,18 +289,41 @@ export const Navbar: FC<NavbarProps> = ({children, routes, slug, tag}) => {
<SearchLinearIcon className="mt-px text-default-600 dark:text-default-500" size={20} />
</button>
</NavbarItem>
<NavbarMenuToggle aria-label={isMenuOpen ? "Close menu" : "Open menu"} className="ml-2" />
<NavbarItem className="w-10 h-full">
<NavbarMenuToggle
aria-label={isMenuOpen ? "Close menu" : "Open menu"}
className="w-full h-full pt-1"
/>
</NavbarItem>
</NavbarContent>
<NavbarContent className="hidden sm:flex basis-1/5 sm:basis-full" justify="end">
<NavbarItem className="hidden sm:flex">
<Link isExternal aria-label="Twitter" className="p-1" href={siteConfig.links.twitter}>
<Link
isExternal
aria-label="Twitter"
className="p-1"
href={siteConfig.links.twitter}
onPress={() => handlePressNavbarItem("Twitter", siteConfig.links.twitter)}
>
<TwitterIcon className="text-default-600 dark:text-default-500" />
</Link>
<Link isExternal aria-label="Discord" className="p-1" href={siteConfig.links.discord}>
<Link
isExternal
aria-label="Discord"
className="p-1"
href={siteConfig.links.discord}
onPress={() => handlePressNavbarItem("Discord", siteConfig.links.discord)}
>
<DiscordIcon className="text-default-600 dark:text-default-500" />
</Link>
<Link isExternal aria-label="Github" className="p-1" href={siteConfig.links.github}>
<Link
isExternal
aria-label="Github"
className="p-1"
href={siteConfig.links.github}
onPress={() => handlePressNavbarItem("Github", siteConfig.links.github)}
>
<GithubIcon className="text-default-600 dark:text-default-500" />
</Link>
<ThemeSwitch />
@@ -270,18 +339,19 @@ export const Navbar: FC<NavbarProps> = ({children, routes, slug, tag}) => {
<HeartFilledIcon className="text-danger group-data-[hover=true]:animate-heartbeat" />
}
variant="flat"
onPress={() => handlePressNavbarItem("Sponsor", siteConfig.links.sponsor)}
>
Sponsor
</Button>
</NavbarItem>{" "}
</NavbarItem>
<NavbarMenuToggle
aria-label={isMenuOpen ? "Close menu" : "Open menu"}
className="hidden sm:flex lg:hidden"
className="hidden sm:flex lg:hidden ml-4"
/>
</NavbarContent>
<NavbarMenu>
<DocsSidebar className="mt-4" routes={routes} slug={slug} tag={tag} />
<DocsSidebar className="mt-4" routes={[...mobileRoutes, ...routes]} slug={slug} tag={tag} />
{children}
</NavbarMenu>
</NextUINavbar>
+3 -3
View File
@@ -17,9 +17,9 @@ export const title = tv({
foreground: "dark:from-[#FFFFFF] dark:to-[#4B4B4B]",
},
size: {
sm: "text-3xl lg:text-4xl",
md: "text-[2.5rem] lg:text-5xl",
lg: "text-4xl lg:text-6xl",
sm: "text-2xl lg:text-4xl",
md: "text-[2.1rem] lg:text-5xl",
lg: "text-3xl lg:text-6xl",
},
fullWidth: {
true: "w-full block",
@@ -1,16 +1,28 @@
import React from "react";
import {usePathname} from "next/navigation";
import {Tooltip, Link, Button} from "@nextui-org/react";
import {Tooltip, Button} from "@nextui-org/react";
import {capitalize, last} from "lodash";
import {BugIcon} from "@/components/icons";
import {ISSUE_REPORT_URL} from "@/libs/github/constants";
import {trackEvent} from "@/utils/va";
export const BugReportButton = () => {
const pathname = usePathname();
const componentTitle = capitalize(last(pathname?.split("/")));
const handlePress = () => {
trackEvent("BugReportButton - Sandpack", {
name: "sandpack - bug report",
action: "press",
category: "docs",
data: `${ISSUE_REPORT_URL}${componentTitle}`,
});
window.open(`${ISSUE_REPORT_URL}${componentTitle}`, "_blank");
};
return (
<Tooltip
className="text-xs px-2"
@@ -19,15 +31,7 @@ export const BugReportButton = () => {
placement="top"
radius="md"
>
<Button
isExternal
isIconOnly
as={Link}
href={`${ISSUE_REPORT_URL}${componentTitle}`}
size="sm"
title="Report a bug"
variant="light"
>
<Button isIconOnly size="sm" title="Report a bug" variant="light" onPress={handlePress}>
<BugIcon className="text-white dark:text-zinc-500" height={16} width={16} />
</Button>
</Tooltip>
@@ -10,6 +10,7 @@ import {Language} from "prism-react-renderer";
import {HighlightedLines} from "./types";
import {Decorators} from "./types";
import {trackEvent} from "@/utils/va";
import {Codeblock} from "@/components/docs/components";
export interface CodeViewerProps {
@@ -83,6 +84,13 @@ export const SandpackCodeViewer = React.forwardRef<any, CodeViewerProps>(
const handleExpand = () => {
const nextIsExpanded = !isExpanded;
trackEvent("CodeViewer - Expand", {
name: activeFile,
action: "expand",
category: "docs",
data: nextIsExpanded ? "expanded" : "collapsed",
});
setIsExpanded(nextIsExpanded);
if (containerRef && containerRef?.current !== null) {
const container = containerRef?.current;
@@ -1,10 +1,14 @@
import React from "react";
import {UnstyledOpenInCodeSandboxButton} from "@codesandbox/sandpack-react";
import {Tooltip, Button} from "@nextui-org/react";
import {useSandpack} from "@codesandbox/sandpack-react";
import {CodeSandboxIcon} from "@/components/icons";
import {trackEvent} from "@/utils/va";
export const CodeSandboxButton = () => {
const {sandpack} = useSandpack();
return (
<Tooltip
className="text-xs px-2"
@@ -13,7 +17,20 @@ export const CodeSandboxButton = () => {
placement="top"
radius="md"
>
<Button isIconOnly as="span" size="sm" title="Open in CodeSandbox" variant="light">
<Button
isIconOnly
as="span"
size="sm"
title="Open in CodeSandbox"
variant="light"
onPress={() => {
trackEvent("CodeSandboxButton - Sandpack", {
action: "press",
category: "docs",
data: sandpack.files[sandpack.activeFile],
});
}}
>
<UnstyledOpenInCodeSandboxButton
style={{
width: "100%",
@@ -3,6 +3,7 @@ import {useSandpack} from "@codesandbox/sandpack-react";
import {Tooltip, Button} from "@nextui-org/react";
import {useClipboard} from "@nextui-org/use-clipboard";
import {trackEvent} from "@/utils/va";
import {CopyLinearIcon} from "@/components/icons";
export const CopyButton = () => {
@@ -14,6 +15,13 @@ export const CopyButton = () => {
const code = sandpack.files[sandpack.activeFile].code;
copy(code);
trackEvent("CopyButton - Sandpack", {
name: "sandpack - copy code",
action: "press",
category: "docs",
data: sandpack.activeFile,
});
};
return (
+15 -2
View File
@@ -1,4 +1,4 @@
export const getFileEntry = (theme: string) => `
export const rootFile = `
import React from "react";
import ReactDOM from "react-dom/client";
import { NextUIProvider } from "@nextui-org/react";
@@ -8,13 +8,26 @@ import "./styles.css";
ReactDOM.createRoot(document.getElementById("root")).render(
<React.StrictMode>
<NextUIProvider>
<div className="w-screen h-screen ${theme} text-foreground bg-background p-8 flex items-start justify-center">
<div className="w-screen h-screen p-8 flex items-start justify-center">
<App />
</div>
</NextUIProvider>
</React.StrictMode>
);`;
export const getHtmlFile = (theme: string, entryFile: string) => `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App</title>
</head>
<body class="${theme} text-foreground bg-background">
<div id="root"></div>
<script type="module" src="/${entryFile}"></script>
</body>
</html>`;
export const tailwindConfig = `const { nextui } = require("@nextui-org/react");
/** @type {import('tailwindcss').Config} */
@@ -3,6 +3,7 @@ import {Tabs, Tab} from "@nextui-org/react";
import {SandpackPredefinedTemplate} from "@codesandbox/sandpack-react";
import {TypescriptIcon, JavascriptIcon} from "@/components/icons";
import {trackEvent} from "@/utils/va";
interface Props {
template: SandpackPredefinedTemplate;
@@ -20,6 +21,12 @@ export const LanguageSelector: React.FC<LanguageSelectorProps> = ({template, onC
setSelectedTemplate(newTemplate);
setTimeout(() => {
trackEvent("LanguageSelector - Selection", {
name: "template",
action: "tabChange",
category: "docs",
data: newTemplate ?? "",
});
onChange?.(newTemplate);
}, 250);
}, [template, onChange]);
@@ -26,6 +26,7 @@ export const Sandpack: FC<SandpackProps> = ({
files: filesProp,
template,
highlightedLines,
typescriptStrict = false,
showPreview = false,
showEditor = true,
defaultExpanded = false,
@@ -41,6 +42,7 @@ export const Sandpack: FC<SandpackProps> = ({
useSandpack({
files: filesProp,
template,
typescriptStrict,
highlightedLines,
});
+1 -2
View File
@@ -30,8 +30,7 @@ export const nextuiTheme: SandpackTheme = {
},
font: {
body: "Inter var",
mono:
'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace',
mono: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace',
size: "14px",
lineHeight: "1.5rem",
},
+22 -7
View File
@@ -1,24 +1,24 @@
import {useMemo} from "react";
import {SandpackFiles, SandpackPredefinedTemplate} from "@codesandbox/sandpack-react";
import {useTheme} from "next-themes";
import {useLocalStorage} from "usehooks-ts";
import {HighlightedLines} from "./types";
import {getHighlightedLines, getFileName} from "./utils";
import {getFileEntry, stylesConfig, postcssConfig, tailwindConfig} from "./entries";
import {useLocalStorage} from "@/hooks/use-local-storage";
import {stylesConfig, postcssConfig, tailwindConfig, getHtmlFile, rootFile} from "./entries";
export interface UseSandpackProps {
files?: SandpackFiles;
typescriptStrict?: boolean;
template?: SandpackPredefinedTemplate;
highlightedLines?: HighlightedLines;
}
const importReact = 'import React from "react";';
const importAllReact = 'import * as React from "react";';
export const useSandpack = ({
files = {},
typescriptStrict = false,
template = "vite-react",
highlightedLines,
}: UseSandpackProps) => {
@@ -57,6 +57,12 @@ export const useSandpack = ({
if (key.includes("App") && !key.includes(mimeType)) {
return acc;
}
if (typescriptStrict && currentTemplate === "vite-react-ts" && key.includes(".js")) {
return acc;
}
if (currentTemplate === "vite-react" && key.includes(".ts")) {
return acc;
}
// @ts-ignore
acc[key] = files[key];
@@ -65,7 +71,7 @@ export const useSandpack = ({
let dependencies = {
"framer-motion": "10.12.16",
"@nextui-org/react": "dev-v2",
"@nextui-org/react": "latest",
};
// sort files by dependency
@@ -76,6 +82,11 @@ export const useSandpack = ({
const aName = getFileName(a);
const bName = getFileName(b);
// if bName includes "App" should be first
if (bName.includes("App")) {
return 1;
}
if (aFile?.includes(bName)) {
return -1;
}
@@ -89,7 +100,7 @@ export const useSandpack = ({
let fileContent = files[key] as string;
// Check if the file content includes 'React' import statements, if not, add it
if (!fileContent.includes(importReact) && !fileContent.includes(importAllReact)) {
if (!fileContent.includes("from 'react'") && !fileContent.includes('from "react"')) {
fileContent = `${importReact}\n${fileContent}\n`;
}
@@ -173,7 +184,11 @@ export const useSandpack = ({
files: {
...sortedFiles,
[entryFile]: {
code: getFileEntry(theme ?? "light"),
code: rootFile,
hidden: true,
},
"index.html": {
code: getHtmlFile(theme ?? "light", entryFile),
hidden: true,
},
"tailwind.config.js": {
+54
View File
@@ -0,0 +1,54 @@
"use client";
import * as React from "react";
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
import {cn} from "@nextui-org/react";
const ScrollArea = React.forwardRef<
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>
>(({className, children, ...props}, ref) => {
return (
<ScrollAreaPrimitive.Root
ref={ref}
className={cn("relative overflow-hidden", className)}
{...props}
>
<ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit] pb-28">
{children}
</ScrollAreaPrimitive.Viewport>
<ScrollBar />
<ScrollAreaPrimitive.Corner />
</ScrollAreaPrimitive.Root>
);
});
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName;
const ScrollBar = React.forwardRef<
React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>
>(({className, orientation = "vertical", ...props}, ref) => (
<ScrollAreaPrimitive.ScrollAreaScrollbar
ref={ref}
className={cn(
"flex touch-none select-none transition-colors",
orientation === "vertical" && "h-full w-2.5 border-l border-l-transparent p-[1px]",
orientation === "horizontal" && "h-2.5 border-t border-t-transparent p-[1px]",
className,
)}
orientation={orientation}
{...props}
>
<ScrollAreaPrimitive.ScrollAreaThumb
className={cn(
"relative rounded-full bg-default-400/50",
orientation === "vertical" && "flex-1",
)}
/>
</ScrollAreaPrimitive.ScrollAreaScrollbar>
));
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;
export {ScrollArea, ScrollBar};
+7
View File
@@ -8,6 +8,7 @@ import {clsx} from "@nextui-org/shared-utils";
import {useIsSSR} from "@react-aria/ssr";
import {SunFilledIcon, MoonFilledIcon} from "@/components/icons";
import {trackEvent} from "@/utils/va";
export interface ThemeSwitchProps {
className?: string;
@@ -20,6 +21,12 @@ export const ThemeSwitch: FC<ThemeSwitchProps> = ({className, classNames}) => {
const onChange = () => {
theme === "light" ? setTheme("dark") : setTheme("light");
trackEvent("ThemeChange", {
action: "click",
category: "theme",
data: theme === "light" ? "dark" : "light",
});
};
const {Component, slots, isSelected, getBaseProps, getInputProps, getWrapperProps} = useSwitch({
+10
View File
@@ -1,7 +1,10 @@
"use client";
import React from "react";
import {Link} from "@nextui-org/react";
import {VercelIcon} from "@/components/icons";
import {trackEvent} from "@/utils/va";
export const VercelCallout: React.FC<unknown> = () => {
return (
@@ -9,6 +12,13 @@ export const VercelCallout: React.FC<unknown> = () => {
isExternal
className="flex justify-end items-center gap-2 text-foreground"
href="https://www.vercel.com?utm_source=nextui&utm_marketing=oss"
onClick={() => {
trackEvent("VercelCallout", {
name: "vercel callout",
action: "click",
category: "footer",
});
}}
>
<p className="font-normal">Deployed on</p>
<VercelIcon className="text-black dark:text-white" height={18} />
+2 -2
View File
@@ -1,6 +1,6 @@
import {DM_Sans} from "next/font/google";
import {Inter} from "next/font/google";
export const fontSans = DM_Sans({
export const fontSans = Inter({
variable: "--font-sans",
adjustFontFallback: true,
display: "optional",
+93 -14
View File
@@ -24,6 +24,13 @@
"keywords": "design principles, nextui",
"path": "/docs/guide/design-principles.mdx"
},
{
"key": "routing",
"title": "Routing",
"keywords": "client side routing, routing, browser routing, nextui, next.js router, react router, remix router",
"path": "/docs/guide/routing.mdx",
"newPost": true
},
{
"key": "upgrade-to-v2",
"title": "Upgrade to v2",
@@ -130,6 +137,13 @@
"keywords": "accordion, collapse, expandable sections, content hiding",
"path": "/docs/components/accordion.mdx"
},
{
"key": "autocomplete",
"title": "Autocomplete",
"keywords": "autocomplete, auto suggest, search, typeahead",
"path": "/docs/components/autocomplete.mdx",
"newPost": true
},
{
"key": "badge",
"title": "Badge",
@@ -142,6 +156,13 @@
"keywords": "button, interactive, action trigger, click events",
"path": "/docs/components/button.mdx"
},
{
"key": "breadcrumbs",
"title": "Breadcrumbs",
"keywords": "breadcrumbs, navigation, path, trail, location",
"path": "/docs/components/breadcrumbs.mdx",
"newPost": true
},
{
"key": "card",
"title": "Card",
@@ -164,8 +185,7 @@
"key": "chip",
"title": "Chip",
"keywords": "chip, tag, label, small actionable entity",
"path": "/docs/components/chip.mdx",
"newPost": true
"path": "/docs/components/chip.mdx"
},
{
"key": "circular-progress",
@@ -183,14 +203,14 @@
"key": "divider",
"title": "Divider",
"keywords": "divider, boundary, separator, section divider",
"path": "/docs/components/divider.mdx",
"newPost": true
"path": "/docs/components/divider.mdx"
},
{
"key": "dropdown",
"title": "Dropdown",
"keywords": "dropdown, menu, selection, option list",
"path": "/docs/components/dropdown.mdx"
"path": "/docs/components/dropdown.mdx",
"updated": true
},
{
"key": "image",
@@ -208,14 +228,21 @@
"key": "kbd",
"title": "Kbd",
"keywords": "keyboard input, shortcut, keys, user input display",
"path": "/docs/components/kbd.mdx",
"newPost": true
"path": "/docs/components/kbd.mdx"
},
{
"key": "link",
"title": "Link",
"keywords": "link, navigation, href, web page connection",
"path": "/docs/components/link.mdx"
"path": "/docs/components/link.mdx",
"updated": true
},
{
"key": "listbox",
"title": "Listbox",
"keywords": "listbox, selection, option list, multiple choice",
"path": "/docs/components/listbox.mdx",
"updated": true
},
{
"key": "modal",
@@ -253,19 +280,29 @@
"keywords": "radio group, selection set, option selection, exclusive choices",
"path": "/docs/components/radio-group.mdx"
},
{
"key": "select",
"title": "Select",
"keywords": "select, selection, option list, multiple choice",
"path": "/docs/components/select.mdx"
},
{
"key": "skeleton",
"title": "Skeleton",
"keywords": "skeleton, loading state, placeholder, content preview",
"path": "/docs/components/skeleton.mdx",
"newPost": true
"path": "/docs/components/skeleton.mdx"
},
{
"key": "snippet",
"title": "Snippet",
"keywords": "snippet, code block, programming, code example",
"path": "/docs/components/snippet.mdx",
"newPost": true
"path": "/docs/components/snippet.mdx"
},
{
"key": "scroll-shadow",
"title": "Scroll Shadow",
"keywords": "scroll shadow, scroll indicator, scroll bar, scroll position",
"path": "/docs/components/scroll-shadow.mdx"
},
{
"key": "spacer",
@@ -285,6 +322,13 @@
"keywords": "switch, toggle, binary input, on/off control",
"path": "/docs/components/switch.mdx"
},
{
"key": "slider",
"title": "Slider",
"keywords": "slider, range input, value selector, sliding control",
"path": "/docs/components/slider.mdx",
"newPost": true
},
{
"key": "table",
"title": "Table",
@@ -296,13 +340,14 @@
"title": "Tabs",
"keywords": "tabs, section navigation, categorized content, tabbed interface",
"path": "/docs/components/tabs.mdx",
"newPost": true
"updated": true
},
{
"key": "textarea",
"title": "Textarea",
"keywords": "textarea, multi-line text input, large text field, form control",
"path": "/docs/components/textarea.mdx"
"path": "/docs/components/textarea.mdx",
"updated": true
},
{
"key": "tooltip",
@@ -318,5 +363,39 @@
}
]
}
],
"mobileRoutes": [
{
"key": "getting-started",
"title": "Getting Started",
"defaultOpen": true,
"keywords": "getting started, main routes, blog, docs, components, nextui",
"routes": [
{
"key": "docs",
"title": "Documentation",
"keywords": "documentation, guide, nextui",
"path": "/docs/guide/introduction.mdx"
},
{
"key": "components",
"title": "Components",
"keywords": "components, nextui",
"path": "/docs/components/avatar"
},
{
"key": "blog",
"title": "Blog",
"keywords": "blog, nextui, news, updates",
"path": "/blog"
},
{
"key": "figma",
"title": "Figma",
"keywords": "figma, nextui, design, ui kit",
"path": "/figma"
}
]
}
]
}
File diff suppressed because it is too large Load Diff
+3
View File
@@ -4,6 +4,9 @@ export const siteConfig = {
name: "NextUI - Beautiful, fast and modern React UI Library",
description: "Make beautiful websites regardless of your design experience.",
ogImage: "https://nextui.org/twitter-cards/nextui.jpeg",
author: "Junior Garcia",
email: "jrgarciadev@gmail.com",
siteUrl: "https://nextui.org",
creator: "@getnextui",
openGraph: {
type: "website",
+43 -19
View File
@@ -1,8 +1,9 @@
---
title: "Introducing NextUI Version 2"
description: "Discover NextUI v2. TailwindCSS integration, enhanced theming, improved animations, and more."
date: "2023-07-29"
title: "Introducing NextUI Version 2.0"
description: "Discover NextUI v2.0 TailwindCSS integration, enhanced theming, improved animations, and more."
date: "2023-07-31"
image: "/blog/nextuiv2.jpg"
tags: ["nextui", "tailwindcss", "react", "nextjs", "react-server-components"]
author:
name: "Junior Garcia"
username: "@jrgarciadev"
@@ -24,18 +25,18 @@ towards achieving that.
## Table of Contents
- [Transition to TailwindCSS](#transition-to-tailwindcss) - Our shift to TailwindCSS.
- [Transition to TailwindCSS](#transition-from-stitches-to-tailwindcss) - Our shift to TailwindCSS.
- [TailwindCSS Plugin](#tailwindcss-plugin) - Introducing theme customization plugin.
- [React Server Components](#react-server-components) - Enhanced performance with React Server Components.
- [Custom Themes, Layouts, Colors](#custom-themes-layouts-colors) - New customizability options.
- [React Server Components](#react-server-components-support) - Enhanced performance with React Server Components.
- [Custom Themes, Layouts, Colors](#custom-themes-layouts-and-colors) - New customizability options.
- [Enhanced Documentation](#enhanced-documentation) - A better navigation experience.
- [New Templates & Guides](#new-templates-guides) - Easier app creation process.
- [New Templates & Guides](#new-templates-and-guides) - Easier app creation process.
- [Custom Variants](#custom-variants) - Customization of components' variants.
- [Enhanced Styling Model](#enhanced-styling-model) - Effortless component styling.
- [Tailwind Variants](#tailwind-variants) - Our new library for better TailwindCSS handling.
- [Revamped Components](#revamped-components) - Rewritten components with react-aria hooks.
- [Optimized Animations](#optimized-animations) - Smoother app animations.
- [Individual Packages](#individual-packages) - Install only what you need.
- [Individual Packages](#individual-packages-support) - Install only what you need.
- [Dark Mode Support](#dark-mode-support) - Easier implementation of dark mode.
- [New Components](#new-components) - Six new components added.
- [Figma Community File](#figma-community-file) - Streamlining design-to-development process.
@@ -85,8 +86,8 @@ Thanks to the switch to TailwindCSS, **NextUI v2.0** now supports React Server C
improves performance and allows you to use it with the latest versions of [React](https://reactjs.org/) and
[Next.js](https://nextjs.org/).
NextUI components already inclue the `use client;` directive so you can import them
server components.
NextUI components already include the `use client;` directive so you can import them directly
in your React Server Components (RSC).
```jsx
// app/page.tsx
@@ -144,7 +145,8 @@ links at the top of each component documentation, such as the component storyboo
the source code and styles source code.
<VideoInView
src="https://nextui-public-resources.s3.amazonaws.com/new-docs.mp4"
src="https://d2u8k2ocievbld.cloudfront.net/new-docs.mp4"
poster="https://d2u8k2ocievbld.cloudfront.net/new-docs-poster.png"
width={700}
height={350}
/>
@@ -167,21 +169,23 @@ installation guides, are introduced to aid your app creation process.
We've added a new function, `extendVariants`, that allows you to customize any NextUI components's variants.
<VideoInView
src="https://nextui-public-resources.s3.amazonaws.com/custom-variants.mp4"
src="https://d2u8k2ocievbld.cloudfront.net/custom-variants.mp4"
poster="https://d2u8k2ocievbld.cloudfront.net/custom-variants-poster.png"
width={700}
height={350}
/>
You can create or override the component `variants`, `defaultVariants` and `componentVariants`.
You can create or override the component `variants`, `defaultVariants` and `compoundVariants`.
> Check out the [Custom Variants](/docs/customization/variants) documentation for more information.
> Check out the [Custom Variants](/docs/customization/custom-variants) documentation for more information.
### Enhanced Styling Model
With the new slots model, you can style every part of your components effortlessly.
<VideoInView
src="https://nextui-public-resources.s3.amazonaws.com/override-styles.mp4"
src="https://d2u8k2ocievbld.cloudfront.net/override-styles.mp4"
poster="https://d2u8k2ocievbld.cloudfront.net/override-styles-poster.png"
width={700}
height={350}
/>
@@ -206,7 +210,8 @@ Thanks to [framer-motion](https://www.framer.com/motion/), we've significantly i
app feel more fluid and smooth.
<VideoInView
src="https://nextui-public-resources.s3.amazonaws.com/dropdown-animation.mp4"
src="https://d2u8k2ocievbld.cloudfront.net/dropdown-animation.mp4"
poster="https://d2u8k2ocievbld.cloudfront.net/dropdown-animation-poster.png"
width={700}
height={350}
/>
@@ -251,7 +256,8 @@ ReactDOM.createRoot(document.getElementById("root")).render(
```
<VideoInView
src="https://nextui-public-resources.s3.amazonaws.com/dark-mode.mp4"
src="https://d2u8k2ocievbld.cloudfront.net/dark-mode.mp4"
poster="https://d2u8k2ocievbld.cloudfront.net/dark-mode-poster.png"
width={700}
height={350}
/>
@@ -280,7 +286,7 @@ file helps streamline the process of transforming design ideas into functioning
</Blockquote>
<iframe
height="450"
height="600"
width="800"
src="https://embed.figma.com/file/1267584376234254760/hf_embed?community_viewer=true&embed_host=nextui"
className="aspect-video w-full border border-transparent dark:border-default-200/50 object-fit rounded-xl shadow-lg"
@@ -289,7 +295,12 @@ file helps streamline the process of transforming design ideas into functioning
<Spacer y={10} />
<Button color="default" variant="bordered">
<Link isExternal className="text-current" href="https://www.figma.com/community/file/1267584376234254760">
<Link
isExternal
showAnchorIcon
className="text-current"
href="https://www.figma.com/community/file/1267584376234254760"
>
Open in Figma
</Link>
</Button>
@@ -299,3 +310,16 @@ file helps streamline the process of transforming design ideas into functioning
To start using **NextUI v2.0**, head over to our [installation guide](/docs/guide/installation).
We can't wait to see the amazing things you'll build with **NextUI v2.0**!
---
## Community
We're excited to see the community adopt NextUI, raise issues, and provide feedback.
Whether it's a feature request, bug report, or a project to showcase, please get involved!
<Community />
## Contributing
PR's on NextUI are always welcome, please see our [contribution guidelines](https://github.com/nextui-org/nextui/blob/main/CONTRIBUTING.MD) to learn how you can contribute to this project.
+167
View File
@@ -0,0 +1,167 @@
---
title: "New components v2.1.0 🎉"
description: "NextUI v2.1.0 is here with new components, Select, Listbox and ScrollShadow."
date: "2023-08-21"
image: "/blog/v2.1.0.jpg"
tags: ["nextui", "select", "listbox", "scroll-shadow", "multi-select"]
author:
name: "Junior Garcia"
username: "@jrgarciadev"
link: "https://twitter.com/jrgarciadev"
avatar: "/avatars/junior-garcia.jpeg"
---
import {selectContent} from "@/content/components/select";
import {listboxContent} from "@/content/components/listbox";
import {scrollShadowContent} from "@/content/components/scroll-shadow";
<img
src="/blog/v2.1.0.jpg"
width={700}
height={350}
alt="NextUI v2"
className="w-full border border-transparent dark:border-default-200/50 object-fit rounded-xl shadow-lg"
/>
We are thrilled to announce the latest update to NextUI, version **2.1.0**! This release introduces some game-changing
additions that many of you have eagerly been waiting for.
First on the list is the highly-anticipated **Select** component. Fully customizable and beautifully designed, supports both single and
multi-select modes and is accessible out of the box.
But that's not all. We're also rolling out two more incredible components **Listbox** and **ScrollShadow**. The new
**Listbox** allows you to make list manipulations more efficient and visually appealing. Meanwhile, the
**ScrollShadow** component adds an elegant shadow effect to scrollable areas, enhancing the UI aesthetics while
also improving usability.
## Select
Creating a select component that is both accessible and customizable is a challenging task. We've spent a lot of time
researching and testing different approaches to come up with a solution that works for everyone. The result is a
component that is easy to use, fully accessible, and highly customizable.
The new **Select** component includes:
- Support for selecting a single option.
- Support for selecting multiple options.
- Support for disabled options.
- Support for sections.
- Labeling support for accessibility.
- Exposed to assistive technology as a button with a listbox popup using ARIA (combined with [Listbox](/docs/components/listbox)).
- Support for description and error message help text linked to the input via ARIA.
- Support for mouse, touch, and keyboard interactions.
- Tab stop focus management.
- Asynchronous options loading.
- Keyboard support for opening the listbox using the arrow keys, including automatically focusing the first or last item accordingly.
- Typeahead to allow selecting options by typing text, even without opening the listbox.
- Browser autofill integration via a hidden native `<select>` element.
- Support for mobile form navigation via software keyboard.
- Mobile screen reader listbox dismissal support.
- And much more...
### Single Select
The single select component is used to select a single option from a list of options. It is a combination of a button
and a listbox. The button displays the currently selected option and the listbox displays the available options.
<CodeDemo title="Usage" files={selectContent.usage} />
### Multiple Select
The multiple select component can be used to select multiple options from a list of options.
You only need to pass the `selectionMode="multiple"` prop to the `Select` component.
<CodeDemo title="Multiple Selection" files={selectContent.multiple} />
### Multiple Variants
The select component comes with multiple variants.
<CodeDemo title="Variants" files={selectContent.variants} />
### Chips Support
The select component is flexible and allows you to render any component as an option and as a selected option.
<CodeDemo title="Multiple Selection with Chips" files={selectContent.multipleWithChips} />
### Customizable
The select component is highly customizable, you can customize the selected option, the options, the listbox,
the popover and the scrollable area.
<CodeDemo title="Custom Styles" files={selectContent.customStyles} />
Go to the [Select](/docs/components/select) component page to learn more about sizes, colors, and more.
## Listbox
The listbox component allows you to make list manipulations more efficient and visually appealing.
The new **Listbox** component includes:
- Support for single, multiple, or no selection.
- Exposed to assistive technology as a `listbox` using ARIA.
- Support for disabled items.
- Support for sections.
- Labeling support for accessibility.
- Support for mouse, touch, and keyboard interactions.
- Tab stop focus management.
- Keyboard navigation support including arrow keys, home/end, page up/down, select all, and clear.
- Automatic scrolling support during keyboard navigation.
- Typeahead to allow focusing options by typing text.
### Usage
<CodeDemo title="Usage" files={listboxContent.usage} />
### Custom Styles
The Listbox components offers multiple customization options.
<CodeDemo title="Custom Styles" files={listboxContent.customStyles} />
> **Note**: In the above example, we've utilized the [Boxicons](https://boxicons.com/) icons collection.
Go to the [Listbox](/docs/components/listbox) component page to learn more about it.
## ScrollShadow
The ScrollShadow component gives a nice shadow effect to scrollable areas. These shadows are handled by using
the CSS `mask-image` property, which makes the shadows adapt to the background color.
### Usage
<CodeDemo title="Usage" files={scrollShadowContent.usage} />
You can hide the scrollbars, customize the shadows size, change the orientation, and more.
Go to the [ScrollShadow](/docs/components/scroll-shadow) component page to learn more about it.
<Spacer y={6}/>
We hope you enjoy these new components and the new features. We're excited to see what you build with them!
Thanks for reading and happy coding! 🚀
---
## Community
We're excited to see the community adopt NextUI, raise issues, and provide feedback.
Whether it's a feature request, bug report, or a project to showcase, please get involved!
<Community />
## Contributing
PR's on NextUI are always welcome, please see our [contribution guidelines](https://github.com/nextui-org/nextui/blob/main/CONTRIBUTING.MD) to learn how you can contribute to this project.
+443
View File
@@ -0,0 +1,443 @@
---
title: "Introducing v2.2.0 🚀"
description: "NextUI v2.2.0 is here! Dive into client-side router support, discover 3 new components including the Autocomplete, and more."
date: "2023-11-03"
image: "/blog/v2.2.0.jpg"
tags: ["nextui", "autocomplete", "breadcrumbs", "client side router", "slider"]
author:
name: "Junior Garcia"
username: "@jrgarciadev"
link: "https://twitter.com/jrgarciadev"
avatar: "/avatars/junior-garcia.jpeg"
---
import {autocompleteContent} from "@/content/components/autocomplete";
import {sliderContent} from "@/content/components/slider";
import {breadcrumbsContent} from "@/content/components/breadcrumbs";
<img
src="/blog/v2.2.0_2x.jpg"
width={700}
height={350}
alt="NextUI v2.2.0"
className="w-full border border-transparent dark:border-default-200/50 object-fit rounded-xl shadow-lg"
/>
We are excited to announce the latest update to NextUI, version **2.2.0**! This release introduces 3 new components,
support for client-side routing, and more.
## What's New in v2.2.0?
- [Client Side Routing](#client-side-routing) - Allows you to seamlessly incorporate client-side routers.
- [Autocomplete](/docs/components/autocomplete) - Combines a text input with a listbox, allowing users to filter a list of options.
- [Slider](/docs/components/slider) - Allows users to make selections from a range of values.
- [Breadcrumbs](/docs/components/breadcrumbs) - Displays a hierarchy of links to the current page or resource in an application.
- [Other Changes](#other-changes) - Includes styling improvements, accessibility and usability enhancements.
<Spacer y={4} />
## Client Side Routing
By default, links perform native browser navigation when they are interacted with. However, many apps and
frameworks use client side routers to avoid a full page reload when navigating between pages.
NextUI now natively supports client-side routing in components such as [Link](/docs/components/link), [Tabs](/docs/components/tabs),
[Breadcrumbs](/docs/components/breadcrumbs), [Listbox](/docs/components/listbox), [Dropdown](/docs/components/dropdown) and many others offering
the flexibility to be rendered as HTML links, allowing you to seamlessly incorporate client-side routers. See the [Routing](/docs/guide/routing) guide to
learn how it set it up in your app.
The `NextUIProvider` component configures all NextUI components within it to navigate using the
client side router you provide.
> **Note**: Client side routing is based on [React Aria Routing](https://react-spectrum.adobe.com/react-aria/routing.html).
### Next.js Example
- App Router
Go to your `app/providers.tsx` or `app/providers.jsx` (create it if it doesn't exist) and add the
`useRouter` hook from `next/navigation`, it returns a router object that can be used to perform navigation.
```tsx
// app/providers.tsx
"use client";
import {NextUIProvider} from "@nextui-org/react";
export function Providers({children}: {children: React.ReactNode}) {
const router = useRouter();
return <NextUIProvider navigate={router.push}>{children}</NextUIProvider>;
}
```
- Pages Router
Go to pages`/_app.js` or `pages/_app.tsx` (create it if it doesn't exist) and add the`useRouter` hook
from `next/router`, it returns a router object that can be used to perform navigation.
```tsx
// pages/_app.tsx
import type {AppProps} from "next/app";
import {useRouter} from "next/router";
import {NextUIProvider} from "@nextui-org/react";
function MyApp({Component, pageProps}: AppProps) {
const router = useRouter();
return (
<NextUIProvider navigate={router.push}>
<Component {...pageProps} />
</NextUIProvider>
);
}
export default MyApp;
```
- Usage
Now that you have set up the `NextUIProvider` in your app, you can use the `href` prop in the `Tabs`,
`Listbox` and `Dropdown` items to navigate between pages.
The [Link](/docs/components/link) component will also use the `navigate` function from the
`NextUIProvider` to navigate between pages.
```jsx
import {
Tabs,
Tab,
Listbox,
ListboxItem,
Dropdown,
DropdownTrigger,
DropdownMenu,
DropdownItem,
Button,
Link,
} from "@nextui-org/react";
function App() {
return (
<>
<Tabs aria-label="Navigation">
<Tab key="home" href="/home">
Home
</Tab>
<Tab key="about" href="/about">
About
</Tab>
</Tabs>
<Listbox aria-label="Navigation">
<ListboxItem key="home" href="/home">
Home
</ListboxItem>
<ListboxItem key="about" href="/about">
About
</ListboxItem>
</Listbox>
<Dropdown>
<DropdownTrigger>
<Button>Open</Button>
</DropdownTrigger>
<DropdownMenu aria-label="Navigation">
<DropdownItem key="home" href="/home">
Home
</DropdownItem>
<DropdownItem key="about" href="/about">
About
</DropdownItem>
</DropdownMenu>
</Dropdown>
<Link href="/home">Home</Link>
<Link href="/about">About</Link>
</>
);
}
```
<Spacer y={4} />
## Autocomplete
Creating an autocomplete component that is both accessible and customizable is a challenging task. We've spent a lot of time
researching and testing different approaches to come up with a solution that works for everyone. The result is a
component that is easy to use, fully accessible, and highly customizable.
The new **Autocomplete** component includes:
- Support for selecting a single option.
- Support for disabled options.
- Support for groups of items in sections.
- Support for filtering a list of options by typing.
- Support for controlled and uncontrolled options, selection and input value.
- Support for custom filter functions.
- Async loading and infinite scrolling support.
- Required and invalid states exposed to assistive technology via ARIA.
- Support for description and error message help text linked to the input via ARIA.
- And much more...
We recommend to read this [Blog post](https://react-spectrum.adobe.com/blog/building-a-combobox.html) from [react-aria](https://react-spectrum.adobe.com/react-aria) team to learn more
about the Autocomplete component.
### Usage
<CodeDemo title="Usage" files={autocompleteContent.usage} />
### Custom Items
You can customize the autocomplete items by modifying the `AutocompleteItem` children.
<CodeDemo title="Custom Items" files={autocompleteContent.customItems} />
### Customizable
The autocomplete component is highly customizable, you can customize the popover, listbox and
input components.
<CodeDemo title="Custom Styles" files={autocompleteContent.customStyles} />
Go to the [Autocomplete](/docs/components/autocomplete) component page to learn more about it.
<Spacer y={4} />
## Slider
The **Slider** component allows users to make selections from a range of values. It is a great way to allow users to
select a value from a fixed range, such as volume or temperature, or to select a value from a range that changes
frequently, such as stock prices or budgets.
### Usage
<CodeDemo title="Usage" files={sliderContent.usage} />
### Range Support
If you pass an array of values to the `value` prop or to the `defaultValue` prop, the slider will become a range slider.
<CodeDemo title="Range Slider" files={sliderContent.range} />
### With Tooltip
The slider component also supports a tooltip to display the current value.
<CodeDemo title="With Tooltip" files={sliderContent.tooltip} />
### Slider steps
You can use the `showSteps` prop to display small dots on each step.
<CodeDemo title="With Visible Steps" files={sliderContent.visibleSteps} />
### Slider Custom Styles
You can customize the `Slider` component by passing custom Tailwind CSS classes to the component slots.
<CodeDemo title="Custom Styles" files={sliderContent.customStyles} />
Go to the [Slider](/docs/components/slider) component page to learn more about it.
<Spacer y={4} />
## Breadcrumbs
The **Breadcrumbs** is an essential component for navigating hierarchical content. It displays a hierarchy of links to the
current page or resource in an application.
### Usage
<CodeDemo title="Usage" files={breadcrumbsContent.usage} />
### Breadcrumbs as menu
It is possible to use the `Breadcrumbs` component as a horizontal menu. This is useful when you want to display a list
of possible navigations and let the user choose one of them.
<CodeDemo title="Menu Type" files={breadcrumbsContent.menuType} />
### Start & End Content support
You can add any element to the start or end of the breadcrumbs by using the `startContent` and `endContent` props. The
above example uses the `startContent` prop to add icons to the start of the breadcrumbs.
<CodeDemo title="Start & End Content" files={breadcrumbsContent.startEndContent} />
### Collapsing Items support
The `Breadcrumbs` component supports collapsing items, it is useful when you have a lot of items and you want to
collapse them into a dropdown menu.
<CodeDemo title="Customizing the Ellipsis Item" files={breadcrumbsContent.customizingEllipsis} />
### Apllying custom styles
You can customize the `Breadcrumbs` component by passing custom Tailwind CSS classes to the component slots.
<CodeDemo title="Custom Styles" files={breadcrumbsContent.customStyles} />
<Spacer y={4} />
Go to the [Breadcrumbs](/docs/components/breadcrumbs) component page to learn more about it.
## Other Changes
- Styling Improvements:
- Transitioned spacing units from pixels (px) to rem units to optimize mobile component sizing.
- Introduced a new `shouldSelectOnPressUp` property for `Tabs/Tab` with a default value of true, allowing tab selection on press-up instead of press-down.
- Updated Chip component's font size to text-tiny for the sm size variant.
- Enhanced the Button component to display only the spinner during loading when it contains an icon.
- Accessibility and Usability Enhancements:
- Resolved Popover component's open state issues for blur/opaque backdrops.
- Enhanced the ScrollShadow API, introducing visibility and onVisibilityChange properties to manage shadow visibility.
- Added `emptyContent`, `topContent`, and `bottomContent` properties to Listbox/Menu/Dropdown for customized content rendering.
- Introduced baseRef to the Input component, allowing control over the parent element's reference.
- Upgraded tailwind-variants to version `0.1.18`, incorporating slot props control.
- Right-to-Left (RTL) Support:
- Implemented RTL support for Accordion,
- Implemented RTL support for Accordion Avatar & AvatarGroup components,
- Implemented RTL support for ButtonGroup.
- Custom Implementations and Fixes:
- Implemented a custom `usePress` hook to address the corner press issue, with a corresponding pull request and issue submitted to the react-aria project.
- Applied the custom `usePress` across all NextUI interactive components for consistent behavior.
- Improved animations and positioning for Input & Select labels.
- Upgraded `react-aria` packages and `framer-motion` for enhanced performance.
- Enhanced TypeScript support for generic items in Menu and DropdownMenu.
- Streamlined package dependencies to exclude globally or individually installed packages, reducing bundle sizes.
- Visual and Interactive Tweaks:
- Removed the outline on Input focus-visible for a cleaner aesthetic.
- Fixed the radius property issue in `ButtonGroup`.
- Introduced the `isActive` prop for `NavbarMenuItem` for active state management.
- Corrected the Pagination custom-items example by adding the key prop.
- Enabled Collection Items support within the `extendVariants` function.
- Added transitions to menu/listbox items for smoother interaction.
- Added a `disableAutosize` property to `Textarea` to control auto-resizing.
- Resolved styling issues in Textarea and animated height adjustments for a fluid user experience.
- Included a `hoverOpacity` key in the themes object within the plugin for customized hover effects.
- Implemented a hover effect for the Button component to enhance user interaction feedback.
- The padding of the CardBody has been updated from `p-5` to `p-3` for consistency with the padding of other Card elements.
<Spacer y={4} />
## Breaking Changes
Unfortunately, we had to make some small styles breaking changes in this release to improve the [Popover](/docs/components/popover) arrow
dynamic positioning. Instead of having a specific slot for the popover arrow, we now use the `before` pseudo element, this allows the
popover to also move the arrow altogether.
This change impacts the Popover, Dropdown, Tooltip and Select implementations.
Popover changes:
```diff-jsx
<Popover
showArrow
backdrop="opaque"
placement="right"
classNames={{
- base: "py-3 px-4 border border-default-200 bg-gradient-to-br from-white to-default-300 dark:from-default-100 dark:to-default-50",
- arrow: "bg-default-200",
+ base: [
+ // the "before" pseudo element is now the popover' arrow
+ "before:bg-default-200"
+ ],
+ content: [ // now we need to use the "content" slot to actually modify the popover' content styles
+ "py-3 px-4 border border-default-200",
+ "bg-gradient-to-br from-white to-default-300",
+ "dark:from-default-100 dark:to-default-50",
],
}}
>
...
</Popover>
```
Tooltip changes:
```diff-jsx
<Tooltip
showArrow
placement="right"
content="I am a tooltip"
classNames={{
- base: "py-2 px-4 shadow-xl text-black bg-gradient-to-br from-white to-neutral-400",
- arrow: "bg-neutral-400 dark:bg-white",
+ base: [
+ // the "before" pseudo element is now the popover' arrow
+ "before:bg-neutral-400 dark:before:bg-white",
+ ],
+ content: [ // now we need to use the "content" slot to actually modify the popover' content styles
+ "py-2 px-4 shadow-xl",
+ "text-black bg-gradient-to-br from-white to-neutral-400",
+ ],
}}
>
<Button variant="flat">Hover me</Button>
</Tooltip>
```
Select changes:
```diff-jsx
<Select
items={users}
label="Assigned to"
className="max-w-xs"
variant="bordered"
popoverProps={{
classNames: {
- base: "p-0 border-small border-divider bg-background",
- arrow: "bg-default-200",
+ base: "before:bg-default-200", // the before pseudo element controls the popover's arrow
+ content: "p-0 border-small border-divider bg-background", // now instead of the "base" slot we use the "content" slot
},
}}
>
...
</Select>
);
}`;
```
Dropdown Changes
```diff-jsx
<Dropdown
showArrow
classNames={{
- base: "py-1 px-1 border border-default-200 bg-gradient-to-br from-white to-default-200 dark:from-default-50 dark:to-black",
- arrow: "bg-default-200",
+ content: "py-1 px-1 border border-default-200 bg-gradient-to-br from-white to-default-200 dark:from-default-50 dark:to-black", // now instead of the "base" slot we use the "content"
+ base: "before:bg-default-200", // the before pseudo element controls the popover's arrow
}}
>
...
</Dropdown>
```
<Spacer y={6} />
We hope you enjoy these new components and the new features. We're excited to see what you build with them!
Thanks for reading and happy coding! 🚀
---
## Community
We're excited to see the community adopt NextUI, raise issues, and provide feedback.
Whether it's a feature request, bug report, or a project to showcase, please get involved!
<Community />
## Contributing
PR's on NextUI are always welcome, please see our [contribution guidelines](https://github.com/nextui-org/nextui/blob/main/CONTRIBUTING.MD) to learn how you can contribute to this project.
@@ -0,0 +1,89 @@
const App = `import {Autocomplete, AutocompleteItem} from "@nextui-org/react";
import {useAsyncList} from "@react-stately/data";
export default function App() {
let list = useAsyncList({
async load({signal, filterText}) {
let res = await fetch(\`https://swapi.py4e.com/api/people/?search=\${filterText}\`, {signal});
let json = await res.json();
return {
items: json.results,
};
},
});
return (
<Autocomplete
className="max-w-xs"
inputValue={list.filterText}
isLoading={list.isLoading}
items={list.items}
label="Select a character"
placeholder="Type to search..."
variant="bordered"
onInputChange={list.setFilterText}
>
{(item) => (
<AutocompleteItem key={item.name} className="capitalize">
{item.name}
</AutocompleteItem>
)}
</Autocomplete>
);
}`;
const AppTs = `import {Autocomplete, AutocompleteItem} from "@nextui-org/react";
import {useAsyncList} from "@react-stately/data";
type SWCharacter = {
name: string;
height: string;
mass: string;
birth_year: string;
};
export default function App() {
let list = useAsyncList<SWCharacter>({
async load({signal, filterText}) {
let res = await fetch(\`https://swapi.py4e.com/api/people/?search=\${filterText}\`, {signal});
let json = await res.json();
return {
items: json.results,
};
},
});
return (
<Autocomplete
className="max-w-xs"
inputValue={list.filterText}
isLoading={list.isLoading}
items={list.items}
label="Select a character"
placeholder="Type to search..."
variant="bordered"
onInputChange={list.setFilterText}
>
{(item) => (
<AutocompleteItem key={item.name} className="capitalize">
{item.name}
</AutocompleteItem>
)}
</Autocomplete>
);
}`;
const react = {
"/App.jsx": App,
};
const reactTs = {
"/App.tsx": AppTs,
};
export default {
...react,
...reactTs,
};
@@ -0,0 +1,188 @@
const usePokemonListTs = `export type Pokemon = {
name: string;
url: string;
};
export type UsePokemonListProps = {
/** Delay to wait before fetching more items */
fetchDelay?: number;
};
export function usePokemonList({fetchDelay = 0}: UsePokemonListProps = {}) {
const [items, setItems] = React.useState<Pokemon[]>([]);
const [hasMore, setHasMore] = React.useState(true);
const [isLoading, setIsLoading] = React.useState(false);
const [offset, setOffset] = React.useState(0);
const limit = 10; // Number of items per page, adjust as necessary
const loadPokemon = async (currentOffset: number) => {
const controller = new AbortController();
const {signal} = controller;
try {
setIsLoading(true);
if (offset > 0) {
// Delay to simulate network latency
await new Promise((resolve) => setTimeout(resolve, fetchDelay));
}
let res = await fetch(
\`https://pokeapi.co/api/v2/pokemon?offset=\${currentOffset}&limit=\${limit}\`,
{signal},
);
if (!res.ok) {
throw new Error("Network response was not ok");
}
let json = await res.json();
setHasMore(json.next !== null);
// Append new results to existing ones
setItems((prevItems) => [...prevItems, ...json.results]);
} catch (error) {
if (error.name === "AbortError") {
console.log("Fetch aborted");
} else {
console.error("There was an error with the fetch operation:", error);
}
} finally {
setIsLoading(false);
}
};
React.useEffect(() => {
loadPokemon(offset);
}, []);
const onLoadMore = () => {
const newOffset = offset + limit;
setOffset(newOffset);
loadPokemon(newOffset);
};
return {
items,
hasMore,
isLoading,
onLoadMore,
};
}
`;
const usePokemonList = `export function usePokemonList({fetchDelay = 0} = {}) {
const [items, setItems] = React.useState([]);
const [hasMore, setHasMore] = React.useState(true);
const [isLoading, setIsLoading] = React.useState(false);
const [offset, setOffset] = React.useState(0);
const limit = 10; // Number of items per page, adjust as necessary
const loadPokemon = async (currentOffset) => {
const controller = new AbortController();
const {signal} = controller;
try {
setIsLoading(true);
if (offset > 0) {
// Delay to simulate network latency
await new Promise((resolve) => setTimeout(resolve, fetchDelay));
}
let res = await fetch(
\`https://pokeapi.co/api/v2/pokemon?offset=\${currentOffset}&limit=\${limit}\`,
{signal},
);
if (!res.ok) {
throw new Error("Network response was not ok");
}
let json = await res.json();
setHasMore(json.next !== null);
// Append new results to existing ones
setItems((prevItems) => [...prevItems, ...json.results]);
} catch (error) {
if (error.name === "AbortError") {
console.log("Fetch aborted");
} else {
console.error("There was an error with the fetch operation:", error);
}
} finally {
setIsLoading(false);
}
};
React.useEffect(() => {
loadPokemon(offset);
}, []);
const onLoadMore = () => {
const newOffset = offset + limit;
setOffset(newOffset);
loadPokemon(newOffset);
};
return {
items,
hasMore,
isLoading,
onLoadMore,
};
};`;
const App = `import {Autocomplete, AutocompleteItem} from "@nextui-org/react";
import {useInfiniteScroll} from "@nextui-org/use-infinite-scroll";
import {usePokemonList} from "./usePokemonList";
export default function App() {
const [isOpen, setIsOpen] = React.useState(false);
const {items, hasMore, isLoading, onLoadMore} = usePokemonList({fetchDelay: 1500});
const [, scrollerRef] = useInfiniteScroll({
hasMore,
isEnabled: isOpen,
shouldUseLoader: false, // We don't want to show the loader at the bottom of the list
onLoadMore,
});
return (
<Autocomplete
className="max-w-xs"
variant="bordered"
isLoading={isLoading}
defaultItems={items}
label="Pick a Pokemon"
placeholder="Select a Pokemon"
scrollRef={scrollerRef}
selectionMode="single"
onOpenChange={setIsOpen}
>
{(item) => (
<AutocompleteItem key={item.name} className="capitalize">
{item.name}
</AutocompleteItem>
)}
</Autocomplete>
);
}`;
const react = {
"/App.jsx": App,
"/usePokemonList.js": usePokemonList,
};
const reactTs = {
"/App.tsx": App,
"/usePokemonList.ts": usePokemonListTs,
};
export default {
...react,
...reactTs,
};
@@ -0,0 +1,68 @@
const data = `export const animals = [
{label: "Cat", value: "cat", description: "The second most popular pet in the world"},
{label: "Dog", value: "dog", description: "The most popular pet in the world"},
{label: "Elephant", value: "elephant", description: "The largest land animal"},
{label: "Lion", value: "lion", description: "The king of the jungle"},
{label: "Tiger", value: "tiger", description: "The largest cat species"},
{label: "Giraffe", value: "giraffe", description: "The tallest land animal"},
{
label: "Dolphin",
value: "dolphin",
description: "A widely distributed and diverse group of aquatic mammals",
},
{label: "Penguin", value: "penguin", description: "A group of aquatic flightless birds"},
{label: "Zebra", value: "zebra", description: "A several species of African equids"},
{
label: "Shark",
value: "shark",
description: "A group of elasmobranch fish characterized by a cartilaginous skeleton",
},
{
label: "Whale",
value: "whale",
description: "Diverse group of fully aquatic placental marine mammals",
},
{label: "Otter", value: "otter", description: "A carnivorous mammal in the subfamily Lutrinae"},
{label: "Crocodile", value: "crocodile", description: "A large semiaquatic reptile"},
];`;
const App = `import {Autocomplete, AutocompleteItem} from "@nextui-org/react";
import {animals} from "./data";
export default function App() {
const colors = [
"default",
"primary",
"secondary",
"success",
"warning",
"danger",
];
return (
<div className="w-full flex flex-row flex-wrap gap-4">
{colors.map((color) => (
<Autocomplete
key={color}
color={color}
defaultItems={animals}
label="Favorite Animal"
placeholder="Search an animal"
defaultSelectedKey={"cat"}
className="max-w-xs"
>
{(item) => <AutocompleteItem key={item.value}>{item.label}</AutocompleteItem>}
</Autocomplete>
))}
</div>
);
}`;
const react = {
"/App.jsx": App,
"/data.js": data,
};
export default {
...react,
};
@@ -0,0 +1,89 @@
const data = `export const animals = [
{label: "Cat", value: "cat", description: "The second most popular pet in the world"},
{label: "Dog", value: "dog", description: "The most popular pet in the world"},
{label: "Elephant", value: "elephant", description: "The largest land animal"},
{label: "Lion", value: "lion", description: "The king of the jungle"},
{label: "Tiger", value: "tiger", description: "The largest cat species"},
{label: "Giraffe", value: "giraffe", description: "The tallest land animal"},
{
label: "Dolphin",
value: "dolphin",
description: "A widely distributed and diverse group of aquatic mammals",
},
{label: "Penguin", value: "penguin", description: "A group of aquatic flightless birds"},
{label: "Zebra", value: "zebra", description: "A several species of African equids"},
{
label: "Shark",
value: "shark",
description: "A group of elasmobranch fish characterized by a cartilaginous skeleton",
},
{
label: "Whale",
value: "whale",
description: "Diverse group of fully aquatic placental marine mammals",
},
{label: "Otter", value: "otter", description: "A carnivorous mammal in the subfamily Lutrinae"},
{label: "Crocodile", value: "crocodile", description: "A large semiaquatic reptile"},
];`;
const AppTs = `import {Autocomplete, AutocompleteItem} from "@nextui-org/react";
import {animals} from "./data";
export default function App() {
const [value, setValue] = React.useState<React.Key>("cat");
return (
<div className="flex w-full max-w-xs flex-col gap-2">
<Autocomplete
label="Favorite Animal"
variant="bordered"
placeholder="Search an animal"
className="max-w-xs"
selectedKey={value}
onSelectionChange={setValue}
>
{(item) => <AutocompleteItem key={item.value}>{item.label}</AutocompleteItem>}
</Autocomplete>
<p className="text-default-500 text-small">Selected: {value}</p>
</div>
);
}`;
const App = `import {Autocomplete, AutocompleteItem} from "@nextui-org/react";
import {animals} from "./data";
export default function App() {
const [value, setValue] = React.useState("cat");
return (
<div className="flex w-full max-w-xs flex-col gap-2">
<Autocomplete
label="Favorite Animal"
variant="bordered"
defaultItems={animals}
placeholder="Search an animal"
className="max-w-xs"
selectedKey={value}
onSelectionChange={setValue}
>
{(item) => <AutocompleteItem key={item.value}>{item.label}</AutocompleteItem>}
</Autocomplete>
<p className="text-default-500 text-small">Selected: {value}</p>
</div>
);
}`;
const react = {
"/App.jsx": App,
"/data.js": data,
};
const reactTs = {
"/App.tsx": AppTs,
"/data.js": data,
};
export default {
...react,
...reactTs,
};
@@ -0,0 +1,102 @@
const data = `export const animals = [
{label: "Cat", value: "cat", description: "The second most popular pet in the world"},
{label: "Dog", value: "dog", description: "The most popular pet in the world"},
{label: "Elephant", value: "elephant", description: "The largest land animal"},
{label: "Lion", value: "lion", description: "The king of the jungle"},
{label: "Tiger", value: "tiger", description: "The largest cat species"},
{label: "Giraffe", value: "giraffe", description: "The tallest land animal"},
{
label: "Dolphin",
value: "dolphin",
description: "A widely distributed and diverse group of aquatic mammals",
},
{label: "Penguin", value: "penguin", description: "A group of aquatic flightless birds"},
{label: "Zebra", value: "zebra", description: "A several species of African equids"},
{
label: "Shark",
value: "shark",
description: "A group of elasmobranch fish characterized by a cartilaginous skeleton",
},
{
label: "Whale",
value: "whale",
description: "Diverse group of fully aquatic placental marine mammals",
},
{label: "Otter", value: "otter", description: "A carnivorous mammal in the subfamily Lutrinae"},
{label: "Crocodile", value: "crocodile", description: "A large semiaquatic reptile"},
];`;
const App = `import {Autocomplete, AutocompleteItem} from "@nextui-org/react";
import {animals} from "./data";
export default function App() {
const myFilter = (textValue, inputValue) => {
if (inputValue.length === 0) {
return true;
}
// Normalize both strings so we can slice safely
// take into account the ignorePunctuation option as well...
textValue = textValue.normalize("NFC").toLocaleLowerCase();
inputValue = inputValue.normalize("NFC").toLocaleLowerCase();
return textValue.slice(0, inputValue.length) === inputValue;
};
return (
<Autocomplete
allowsCustomValue
className="max-w-xs"
defaultFilter={myFilter}
defaultItems={animals}
label="Search an animal"
variant="bordered"
>
{(item) => <AutocompleteItem key={item.value}>{item.label}</AutocompleteItem>}
</Autocomplete>
);
}`;
const AppTs = `import {Autocomplete, AutocompleteItem} from "@nextui-org/react";
import {animals} from "./data";
export default function App() {
const myFilter = (textValue: string, inputValue: string) => {
if (inputValue.length === 0) {
return true;
}
// Normalize both strings so we can slice safely
// take into account the ignorePunctuation option as well...
textValue = textValue.normalize("NFC").toLocaleLowerCase();
inputValue = inputValue.normalize("NFC").toLocaleLowerCase();
return textValue.slice(0, inputValue.length) === inputValue;
};
return (
<Autocomplete
className="max-w-xs"
defaultFilter={myFilter}
defaultItems={animals}
label="Search an animal"
variant="bordered"
>
{(item) => <AutocompleteItem key={item.value}>{item.label}</AutocompleteItem>}
</Autocomplete>
);
}`;
const react = {
"/App.jsx": App,
"/data.js": data,
};
const reactTs = {
"/App.tsx": AppTs,
};
export default {
...react,
...reactTs,
};
@@ -0,0 +1,239 @@
const data = `export const users = [
{
id: 1,
name: "Tony Reichert",
role: "CEO",
team: "Management",
status: "active",
age: "29",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/1.png",
email: "tony.reichert@example.com",
},
{
id: 2,
name: "Zoey Lang",
role: "Tech Lead",
team: "Development",
status: "paused",
age: "25",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/1.png",
email: "zoey.lang@example.com",
},
{
id: 3,
name: "Jane Fisher",
role: "Sr. Dev",
team: "Development",
status: "active",
age: "22",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/2.png",
email: "jane.fisher@example.com",
},
{
id: 4,
name: "William Howard",
role: "C.M.",
team: "Marketing",
status: "vacation",
age: "28",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/2.png",
email: "william.howard@example.com",
},
{
id: 5,
name: "Kristen Copper",
role: "S. Manager",
team: "Sales",
status: "active",
age: "24",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/3.png",
email: "kristen.cooper@example.com",
},
{
id: 6,
name: "Brian Kim",
role: "P. Manager",
team: "Management",
age: "29",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/3.png",
email: "brian.kim@example.com",
status: "Active",
},
{
id: 7,
name: "Michael Hunt",
role: "Designer",
team: "Design",
status: "paused",
age: "27",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/4.png",
email: "michael.hunt@example.com",
},
{
id: 8,
name: "Samantha Brooks",
role: "HR Manager",
team: "HR",
status: "active",
age: "31",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/4.png",
email: "samantha.brooks@example.com",
},
{
id: 9,
name: "Frank Harrison",
role: "F. Manager",
team: "Finance",
status: "vacation",
age: "33",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/5.png",
email: "frank.harrison@example.com",
},
{
id: 10,
name: "Emma Adams",
role: "Ops Manager",
team: "Operations",
status: "active",
age: "35",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/5.png",
email: "emma.adams@example.com",
},
{
id: 11,
name: "Brandon Stevens",
role: "Jr. Dev",
team: "Development",
status: "active",
age: "22",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/7.png",
email: "brandon.stevens@example.com",
},
{
id: 12,
name: "Megan Richards",
role: "P. Manager",
team: "Product",
status: "paused",
age: "28",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/7.png",
email: "megan.richards@example.com",
},
{
id: 13,
name: "Oliver Scott",
role: "S. Manager",
team: "Security",
status: "active",
age: "37",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/8.png",
email: "oliver.scott@example.com",
},
{
id: 14,
name: "Grace Allen",
role: "M. Specialist",
team: "Marketing",
status: "active",
age: "30",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/8.png",
email: "grace.allen@example.com",
},
{
id: 15,
name: "Noah Carter",
role: "IT Specialist",
team: "I. Technology",
status: "paused",
age: "31",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/9.png",
email: "noah.carter@example.com",
},
{
id: 16,
name: "Ava Perez",
role: "Manager",
team: "Sales",
status: "active",
age: "29",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/9.png",
email: "ava.perez@example.com",
},
{
id: 17,
name: "Liam Johnson",
role: "Data Analyst",
team: "Analysis",
status: "active",
age: "28",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/11.png",
email: "liam.johnson@example.com",
},
{
id: 18,
name: "Sophia Taylor",
role: "QA Analyst",
team: "Testing",
status: "active",
age: "27",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/11.png",
email: "sophia.taylor@example.com",
},
{
id: 19,
name: "Lucas Harris",
role: "Administrator",
team: "Information Technology",
status: "paused",
age: "32",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/12.png",
email: "lucas.harris@example.com",
},
{
id: 20,
name: "Mia Robinson",
role: "Coordinator",
team: "Operations",
status: "active",
age: "26",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/12.png",
email: "mia.robinson@example.com",
},
];`;
const App = `import {Autocomplete, AutocompleteItem, Avatar} from "@nextui-org/react";
import {users} from "./data";
export default function App() {
return (
<Autocomplete
defaultItems={users}
variant="bordered"
label="Assigned to"
placeholder="Select a user"
labelPlacement="inside"
className="max-w-xs"
>
{(user) => (
<AutocompleteItem key={user.id} textValue={user.name}>
<div className="flex gap-2 items-center">
<Avatar alt={user.name} className="flex-shrink-0" size="sm" src={user.avatar} />
<div className="flex flex-col">
<span className="text-small">{user.name}</span>
<span className="text-tiny text-default-400">{user.email}</span>
</div>
</div>
</AutocompleteItem>
)}
</Autocomplete>
);
}`;
const react = {
"/App.jsx": App,
"/data.js": data,
};
export default {
...react,
};
@@ -0,0 +1,56 @@
const App = `import {Autocomplete, AutocompleteItem, AutocompleteSection} from "@nextui-org/react";
export default function App() {
const headingClasses = "flex w-full sticky top-1 z-20 py-1.5 px-2 bg-default-100 shadow-small rounded-small";
return (
<Autocomplete
label="Favorite Animal"
variant="bordered"
placeholder="Search an animal"
className="max-w-xs"
scrollShadowProps={{
isEnabled: false,
}}
>
<AutocompleteSection
title="Mammals"
classNames={{
heading: headingClasses,
}}
>
<AutocompleteItem key="Lion">Lion</AutocompleteItem>
<AutocompleteItem key="Tiger">Tiger</AutocompleteItem>
<AutocompleteItem key="Elephant">Elephant</AutocompleteItem>
<AutocompleteItem key="Kangaroo">Kangaroo</AutocompleteItem>
<AutocompleteItem key="Panda">Panda</AutocompleteItem>
<AutocompleteItem key="Giraffe">Giraffe</AutocompleteItem>
<AutocompleteItem key="Zebra">Zebra</AutocompleteItem>
<AutocompleteItem key="Cheetah">Cheetah</AutocompleteItem>
</AutocompleteSection>
<AutocompleteSection
title="Birds"
classNames={{
heading: headingClasses,
}}
>
<AutocompleteItem key="Eagle">Eagle</AutocompleteItem>
<AutocompleteItem key="Parrot">Parrot</AutocompleteItem>
<AutocompleteItem key="Penguin">Penguin</AutocompleteItem>
<AutocompleteItem key="Ostrich">Ostrich</AutocompleteItem>
<AutocompleteItem key="Peacock">Peacock</AutocompleteItem>
<AutocompleteItem key="Swan">Swan</AutocompleteItem>
<AutocompleteItem key="Falcon">Falcon</AutocompleteItem>
<AutocompleteItem key="Flamingo">Flamingo</AutocompleteItem>
</AutocompleteSection>
</Autocomplete>
);
}`;
const react = {
"/App.jsx": App,
};
export default {
...react,
};
@@ -0,0 +1,78 @@
const data = `export const animals = [
{label: "Cat", value: "cat", description: "The second most popular pet in the world"},
{label: "Dog", value: "dog", description: "The most popular pet in the world"},
{label: "Elephant", value: "elephant", description: "The largest land animal"},
{label: "Lion", value: "lion", description: "The king of the jungle"},
{label: "Tiger", value: "tiger", description: "The largest cat species"},
{label: "Giraffe", value: "giraffe", description: "The tallest land animal"},
{
label: "Dolphin",
value: "dolphin",
description: "A widely distributed and diverse group of aquatic mammals",
},
{label: "Penguin", value: "penguin", description: "A group of aquatic flightless birds"},
{label: "Zebra", value: "zebra", description: "A several species of African equids"},
{
label: "Shark",
value: "shark",
description: "A group of elasmobranch fish characterized by a cartilaginous skeleton",
},
{
label: "Whale",
value: "whale",
description: "Diverse group of fully aquatic placental marine mammals",
},
{label: "Otter", value: "otter", description: "A carnivorous mammal in the subfamily Lutrinae"},
{label: "Crocodile", value: "crocodile", description: "A large semiaquatic reptile"},
];`;
const SelectorIcon = `export const SelectorIcon = (props) => (
<svg
aria-hidden="true"
fill="none"
focusable="false"
height="1em"
role="presentation"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
viewBox="0 0 24 24"
width="1em"
{...props}
>
<path d="M0 0h24v24H0z" fill="none" stroke="none" />
<path d="M8 9l4 -4l4 4" />
<path d="M16 15l-4 4l-4 -4" />
</svg>
);`;
const App = `import {Autocomplete, AutocompleteItem} from "@nextui-org/react";
import {SelectorIcon} from "./SelectorIcon";
import {animals} from "./data";
export default function App() {
return (
<Autocomplete
label="Favorite Animal"
placeholder="Search an animal"
defaultItems={animals}
labelPlacement="outside"
className="max-w-xs"
disableSelectorIconRotation
selectorIcon={<SelectorIcon />}
>
{(item) => <AutocompleteItem key={item.value}>{item.label}</AutocompleteItem>}
</Autocomplete>
);
}`;
const react = {
"/App.jsx": App,
"/data.js": data,
"/SelectorIcon.jsx": SelectorIcon,
};
export default {
...react,
};
@@ -0,0 +1,319 @@
const data = `export const users = [
{
id: 1,
name: "Tony Reichert",
role: "CEO",
team: "Management",
status: "active",
age: "29",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/1.png",
email: "tony.reichert@example.com",
},
{
id: 2,
name: "Zoey Lang",
role: "Tech Lead",
team: "Development",
status: "paused",
age: "25",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/1.png",
email: "zoey.lang@example.com",
},
{
id: 3,
name: "Jane Fisher",
role: "Sr. Dev",
team: "Development",
status: "active",
age: "22",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/2.png",
email: "jane.fisher@example.com",
},
{
id: 4,
name: "William Howard",
role: "C.M.",
team: "Marketing",
status: "vacation",
age: "28",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/2.png",
email: "william.howard@example.com",
},
{
id: 5,
name: "Kristen Copper",
role: "S. Manager",
team: "Sales",
status: "active",
age: "24",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/3.png",
email: "kristen.cooper@example.com",
},
{
id: 6,
name: "Brian Kim",
role: "P. Manager",
team: "Management",
age: "29",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/3.png",
email: "brian.kim@example.com",
status: "Active",
},
{
id: 7,
name: "Michael Hunt",
role: "Designer",
team: "Design",
status: "paused",
age: "27",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/4.png",
email: "michael.hunt@example.com",
},
{
id: 8,
name: "Samantha Brooks",
role: "HR Manager",
team: "HR",
status: "active",
age: "31",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/4.png",
email: "samantha.brooks@example.com",
},
{
id: 9,
name: "Frank Harrison",
role: "F. Manager",
team: "Finance",
status: "vacation",
age: "33",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/5.png",
email: "frank.harrison@example.com",
},
{
id: 10,
name: "Emma Adams",
role: "Ops Manager",
team: "Operations",
status: "active",
age: "35",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/5.png",
email: "emma.adams@example.com",
},
{
id: 11,
name: "Brandon Stevens",
role: "Jr. Dev",
team: "Development",
status: "active",
age: "22",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/7.png",
email: "brandon.stevens@example.com",
},
{
id: 12,
name: "Megan Richards",
role: "P. Manager",
team: "Product",
status: "paused",
age: "28",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/7.png",
email: "megan.richards@example.com",
},
{
id: 13,
name: "Oliver Scott",
role: "S. Manager",
team: "Security",
status: "active",
age: "37",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/8.png",
email: "oliver.scott@example.com",
},
{
id: 14,
name: "Grace Allen",
role: "M. Specialist",
team: "Marketing",
status: "active",
age: "30",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/8.png",
email: "grace.allen@example.com",
},
{
id: 15,
name: "Noah Carter",
role: "IT Specialist",
team: "I. Technology",
status: "paused",
age: "31",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/9.png",
email: "noah.carter@example.com",
},
{
id: 16,
name: "Ava Perez",
role: "Manager",
team: "Sales",
status: "active",
age: "29",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/9.png",
email: "ava.perez@example.com",
},
{
id: 17,
name: "Liam Johnson",
role: "Data Analyst",
team: "Analysis",
status: "active",
age: "28",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/11.png",
email: "liam.johnson@example.com",
},
{
id: 18,
name: "Sophia Taylor",
role: "QA Analyst",
team: "Testing",
status: "active",
age: "27",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/11.png",
email: "sophia.taylor@example.com",
},
{
id: 19,
name: "Lucas Harris",
role: "Administrator",
team: "Information Technology",
status: "paused",
age: "32",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/12.png",
email: "lucas.harris@example.com",
},
{
id: 20,
name: "Mia Robinson",
role: "Coordinator",
team: "Operations",
status: "active",
age: "26",
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/12.png",
email: "mia.robinson@example.com",
},
];`;
const SearchIcon = `export const SearchIcon = ({
size = 24,
strokeWidth = 1.5,
width,
height,
...props
}) => (
<svg
aria-hidden="true"
fill="none"
focusable="false"
height={height || size}
role="presentation"
viewBox="0 0 24 24"
width={width || size}
{...props}
>
<path
d="M11.5 21C16.7467 21 21 16.7467 21 11.5C21 6.25329 16.7467 2 11.5 2C6.25329 2 2 6.25329 2 11.5C2 16.7467 6.25329 21 11.5 21Z"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={strokeWidth}
/>
<path
d="M22 22L20 20"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={strokeWidth}
/>
</svg>
);`;
const App = `import {Autocomplete, AutocompleteItem, Avatar, Button} from "@nextui-org/react";
import {SearchIcon} from "./SearchIcon";
import {users} from "./data";
export default function App() {
return (
<Autocomplete
classNames={{
base: "max-w-xs",
listboxWrapper: "max-h-[320px]",
selectorButton: "text-default-500"
}}
defaultItems={users}
inputProps={{
classNames: {
input: "ml-1",
inputWrapper: "h-[48px]",
},
}}
listboxProps={{
hideSelectedIcon: true,
itemClasses: {
base: [
"rounded-medium",
"text-default-500",
"transition-opacity",
"data-[hover=true]:text-foreground",
"dark:data-[hover=true]:bg-default-50",
"data-[pressed=true]:opacity-70",
"data-[hover=true]:bg-default-200",
"data-[selectable=true]:focus:bg-default-100",
"data-[focus-visible=true]:ring-default-500",
],
},
}}
aria-label="Select an employee"
placeholder="Enter employee name"
popoverProps={{
offset: 10,
classNames: {
base: "rounded-large",
content: "p-1 border-small border-default-100 bg-background",
},
}}
startContent={<SearchIcon className="text-default-400" strokeWidth={2.5} size={20} />}
radius="full"
variant="bordered"
>
{(item) => (
<AutocompleteItem key={item.id} textValue={item.name}>
<div className="flex justify-between items-center">
<div className="flex gap-2 items-center">
<Avatar alt={item.name} className="flex-shrink-0" size="sm" src={item.avatar} />
<div className="flex flex-col">
<span className="text-small">{item.name}</span>
<span className="text-tiny text-default-400">{item.team}</span>
</div>
</div>
<Button
className="border-small mr-0.5 font-medium shadow-small"
radius="full"
size="sm"
variant="bordered"
>
Add
</Button>
</div>
</AutocompleteItem>
)}
</Autocomplete>
);
}`;
const react = {
"/App.jsx": App,
"/SearchIcon.jsx": SearchIcon,
"/data.js": data,
};
export default {
...react,
};
@@ -0,0 +1,53 @@
const data = `export const animals = [
{label: "Cat", value: "cat", description: "The second most popular pet in the world"},
{label: "Dog", value: "dog", description: "The most popular pet in the world"},
{label: "Elephant", value: "elephant", description: "The largest land animal"},
{label: "Lion", value: "lion", description: "The king of the jungle"},
{label: "Tiger", value: "tiger", description: "The largest cat species"},
{label: "Giraffe", value: "giraffe", description: "The tallest land animal"},
{
label: "Dolphin",
value: "dolphin",
description: "A widely distributed and diverse group of aquatic mammals",
},
{label: "Penguin", value: "penguin", description: "A group of aquatic flightless birds"},
{label: "Zebra", value: "zebra", description: "A several species of African equids"},
{
label: "Shark",
value: "shark",
description: "A group of elasmobranch fish characterized by a cartilaginous skeleton",
},
{
label: "Whale",
value: "whale",
description: "Diverse group of fully aquatic placental marine mammals",
},
{label: "Otter", value: "otter", description: "A carnivorous mammal in the subfamily Lutrinae"},
{label: "Crocodile", value: "crocodile", description: "A large semiaquatic reptile"},
];`;
const App = `import {Autocomplete, AutocompleteItem} from "@nextui-org/react";
import {animals} from "./data";
export default function App() {
return (
<Autocomplete
allowsCustomValue
label="Search an animal"
variant="bordered"
className="max-w-xs"
defaultItems={animals}
>
{(item) => <AutocompleteItem key={item.value}>{item.label}</AutocompleteItem>}
</Autocomplete>
);
}`;
const react = {
"/App.jsx": App,
"/data.js": data,
};
export default {
...react,
};
@@ -0,0 +1,54 @@
const data = `export const animals = [
{label: "Cat", value: "cat", description: "The second most popular pet in the world"},
{label: "Dog", value: "dog", description: "The most popular pet in the world"},
{label: "Elephant", value: "elephant", description: "The largest land animal"},
{label: "Lion", value: "lion", description: "The king of the jungle"},
{label: "Tiger", value: "tiger", description: "The largest cat species"},
{label: "Giraffe", value: "giraffe", description: "The tallest land animal"},
{
label: "Dolphin",
value: "dolphin",
description: "A widely distributed and diverse group of aquatic mammals",
},
{label: "Penguin", value: "penguin", description: "A group of aquatic flightless birds"},
{label: "Zebra", value: "zebra", description: "A several species of African equids"},
{
label: "Shark",
value: "shark",
description: "A group of elasmobranch fish characterized by a cartilaginous skeleton",
},
{
label: "Whale",
value: "whale",
description: "Diverse group of fully aquatic placental marine mammals",
},
{label: "Otter", value: "otter", description: "A carnivorous mammal in the subfamily Lutrinae"},
{label: "Crocodile", value: "crocodile", description: "A large semiaquatic reptile"},
];`;
const App = `import {Autocomplete, AutocompleteItem} from "@nextui-org/react";
import {animals} from "./data";
export default function App() {
return (
<Autocomplete
label="Favorite Animal"
placeholder="Search an animal"
description="The second most popular pet in the world"
defaultItems={animals}
defaultSelectedKey="cat"
className="max-w-xs"
>
{(item) => <AutocompleteItem key={item.value}>{item.label}</AutocompleteItem>}
</Autocomplete>
);
}`;
const react = {
"/App.jsx": App,
"/data.js": data,
};
export default {
...react,
};
@@ -0,0 +1,53 @@
const data = `export const animals = [
{label: "Cat", value: "cat", description: "The second most popular pet in the world"},
{label: "Dog", value: "dog", description: "The most popular pet in the world"},
{label: "Elephant", value: "elephant", description: "The largest land animal"},
{label: "Lion", value: "lion", description: "The king of the jungle"},
{label: "Tiger", value: "tiger", description: "The largest cat species"},
{label: "Giraffe", value: "giraffe", description: "The tallest land animal"},
{
label: "Dolphin",
value: "dolphin",
description: "A widely distributed and diverse group of aquatic mammals",
},
{label: "Penguin", value: "penguin", description: "A group of aquatic flightless birds"},
{label: "Zebra", value: "zebra", description: "A several species of African equids"},
{
label: "Shark",
value: "shark",
description: "A group of elasmobranch fish characterized by a cartilaginous skeleton",
},
{
label: "Whale",
value: "whale",
description: "Diverse group of fully aquatic placental marine mammals",
},
{label: "Otter", value: "otter", description: "A carnivorous mammal in the subfamily Lutrinae"},
{label: "Crocodile", value: "crocodile", description: "A large semiaquatic reptile"},
];`;
const App = `import {Autocomplete, AutocompleteItem} from "@nextui-org/react";
import {animals} from "./data";
export default function App() {
return (
<Autocomplete
label="Favorite Animal"
placeholder="Search an animal"
defaultItems={animals}
disabledKeys={["zebra", "tiger", "lion", "elephant", "crocodile", "whale"]}
className="max-w-xs"
>
{(item) => <AutocompleteItem key={item.value}>{item.label}</AutocompleteItem>}
</Autocomplete>
);
}`;
const react = {
"/App.jsx": App,
"/data.js": data,
};
export default {
...react,
};
@@ -0,0 +1,54 @@
const data = `export const animals = [
{label: "Cat", value: "cat", description: "The second most popular pet in the world"},
{label: "Dog", value: "dog", description: "The most popular pet in the world"},
{label: "Elephant", value: "elephant", description: "The largest land animal"},
{label: "Lion", value: "lion", description: "The king of the jungle"},
{label: "Tiger", value: "tiger", description: "The largest cat species"},
{label: "Giraffe", value: "giraffe", description: "The tallest land animal"},
{
label: "Dolphin",
value: "dolphin",
description: "A widely distributed and diverse group of aquatic mammals",
},
{label: "Penguin", value: "penguin", description: "A group of aquatic flightless birds"},
{label: "Zebra", value: "zebra", description: "A several species of African equids"},
{
label: "Shark",
value: "shark",
description: "A group of elasmobranch fish characterized by a cartilaginous skeleton",
},
{
label: "Whale",
value: "whale",
description: "Diverse group of fully aquatic placental marine mammals",
},
{label: "Otter", value: "otter", description: "A carnivorous mammal in the subfamily Lutrinae"},
{label: "Crocodile", value: "crocodile", description: "A large semiaquatic reptile"},
];`;
const App = `import {Autocomplete, AutocompleteItem} from "@nextui-org/react";
import {animals} from "./data";
export default function App() {
return (
<Autocomplete
isDisabled
defaultItems={animals}
label="Favorite Animal"
placeholder="Search an animal"
defaultSelectedKey="cat"
className="max-w-xs"
>
{(item) => <AutocompleteItem key={item.value}>{item.label}</AutocompleteItem>}
</Autocomplete>
);
}`;
const react = {
"/App.jsx": App,
"/data.js": data,
};
export default {
...react,
};
@@ -0,0 +1,52 @@
const data = `export const animals = [
{label: "Cat", value: "cat", description: "The second most popular pet in the world"},
{label: "Dog", value: "dog", description: "The most popular pet in the world"},
{label: "Elephant", value: "elephant", description: "The largest land animal"},
{label: "Lion", value: "lion", description: "The king of the jungle"},
{label: "Tiger", value: "tiger", description: "The largest cat species"},
{label: "Giraffe", value: "giraffe", description: "The tallest land animal"},
{
label: "Dolphin",
value: "dolphin",
description: "A widely distributed and diverse group of aquatic mammals",
},
{label: "Penguin", value: "penguin", description: "A group of aquatic flightless birds"},
{label: "Zebra", value: "zebra", description: "A several species of African equids"},
{
label: "Shark",
value: "shark",
description: "A group of elasmobranch fish characterized by a cartilaginous skeleton",
},
{
label: "Whale",
value: "whale",
description: "Diverse group of fully aquatic placental marine mammals",
},
{label: "Otter", value: "otter", description: "A carnivorous mammal in the subfamily Lutrinae"},
{label: "Crocodile", value: "crocodile", description: "A large semiaquatic reptile"},
];`;
const App = `import {Autocomplete, AutocompleteItem} from "@nextui-org/react";
import {animals} from "./data";
export default function App() {
return (
<Autocomplete
defaultItems={animals}
label="Favorite Animal"
placeholder="Search an animal"
className="max-w-xs"
>
{(animal) => <AutocompleteItem key={animal.value}>{animal.label}</AutocompleteItem>}
</Autocomplete>
);
}`;
const react = {
"/App.jsx": App,
"/data.js": data,
};
export default {
...react,
};
@@ -0,0 +1,64 @@
const data = `export const animals = [
{label: "Cat", value: "cat", description: "The second most popular pet in the world"},
{label: "Dog", value: "dog", description: "The most popular pet in the world"},
{label: "Elephant", value: "elephant", description: "The largest land animal"},
{label: "Lion", value: "lion", description: "The king of the jungle"},
{label: "Tiger", value: "tiger", description: "The largest cat species"},
{label: "Giraffe", value: "giraffe", description: "The tallest land animal"},
{
label: "Dolphin",
value: "dolphin",
description: "A widely distributed and diverse group of aquatic mammals",
},
{label: "Penguin", value: "penguin", description: "A group of aquatic flightless birds"},
{label: "Zebra", value: "zebra", description: "A several species of African equids"},
{
label: "Shark",
value: "shark",
description: "A group of elasmobranch fish characterized by a cartilaginous skeleton",
},
{
label: "Whale",
value: "whale",
description: "Diverse group of fully aquatic placental marine mammals",
},
{label: "Otter", value: "otter", description: "A carnivorous mammal in the subfamily Lutrinae"},
{label: "Crocodile", value: "crocodile", description: "A large semiaquatic reptile"},
];`;
const App = `import {Autocomplete, AutocompleteItem} from "@nextui-org/react";
import {animals} from "./data";
export default function App() {
const [value, setValue] = React.useState("");
const [touched, setTouched] = React.useState(false);
const isValid = value === "cat";
return (
<Autocomplete
label="Favorite Animal"
variant="bordered"
placeholder="Search an animal"
description="The second most popular pet in the world"
errorMessage={isValid || !touched ? "" : "You must select a cat"}
isInvalid={isValid || !touched ? false : true}
defaultItems={animals}
selectedKey={value}
className="max-w-xs"
onSelectionChange={setValue}
onClose={() => setTouched(true)}
>
{(item) => <AutocompleteItem key={item.value}>{item.label}</AutocompleteItem>}
</Autocomplete>
);
}`;
const react = {
"/App.jsx": App,
"/data.js": data,
};
export default {
...react,
};
@@ -0,0 +1,110 @@
const data = `export const animals = [
{label: "Cat", value: "cat", description: "The second most popular pet in the world"},
{label: "Dog", value: "dog", description: "The most popular pet in the world"},
{label: "Elephant", value: "elephant", description: "The largest land animal"},
{label: "Lion", value: "lion", description: "The king of the jungle"},
{label: "Tiger", value: "tiger", description: "The largest cat species"},
{label: "Giraffe", value: "giraffe", description: "The tallest land animal"},
{
label: "Dolphin",
value: "dolphin",
description: "A widely distributed and diverse group of aquatic mammals",
},
{label: "Penguin", value: "penguin", description: "A group of aquatic flightless birds"},
{label: "Zebra", value: "zebra", description: "A several species of African equids"},
{
label: "Shark",
value: "shark",
description: "A group of elasmobranch fish characterized by a cartilaginous skeleton",
},
{
label: "Whale",
value: "whale",
description: "Diverse group of fully aquatic placental marine mammals",
},
{label: "Otter", value: "otter", description: "A carnivorous mammal in the subfamily Lutrinae"},
{label: "Crocodile", value: "crocodile", description: "A large semiaquatic reptile"},
];`;
const App = `import {Autocomplete, AutocompleteItem} from "@nextui-org/react";
import {animals} from "./data";
export default function App() {
const [value, setValue] = React.useState('');
const [selectedKey, setSelectedKey] = React.useState(null);
const onSelectionChange = (id) => {
setSelectedKey(id);
};
const onInputChange = (value) => {
setValue(value)
};
return (
<div className="flex w-full flex-col">
<Autocomplete
label="Search an animal"
variant="bordered"
defaultItems={animals}
className="max-w-xs"
allowsCustomValue={true}
onSelectionChange={onSelectionChange}
onInputChange={onInputChange}
>
{(item) => <AutocompleteItem key={item.value}>{item.label}</AutocompleteItem>}
</Autocomplete>
<p className="mt-1 text-small text-default-500">Current selected animal: {selectedKey}</p>
<p className="text-small text-default-500">Current input text: {value}</p>
</div>
);
}`;
const AppTs = `import {Autocomplete, AutocompleteItem} from "@nextui-org/react";
import {animals} from "./data";
export default function App() {
const [value, setValue] = React.useState<string>('');
const [selectedKey, setSelectedKey] = React.useState<React.Key | null>(null);
const onSelectionChange = (key: React.Key) => {
setSelectedKey(key);
};
const onInputChange = (value: string) => {
setValue(value)
};
return (
<div className="flex w-full flex-col">
<Autocomplete
label="Search an animal"
variant="underlined"
defaultItems={animals}
className="max-w-xs"
allowsCustomValue={true}
onSelectionChange={onSelectionChange}
onInputChange={onInputChange}
>
{(item) => <AutocompleteItem key={item.value}>{item.label}</AutocompleteItem>}
</Autocomplete>
<p className="mt-1 text-small text-default-500">Current selected animal: {selectedKey}</p>
<p className="text-small text-default-500">Current input text: {value}</p>
</div>
);
}`;
const react = {
"/App.jsx": App,
"/data.js": data,
};
const reactTs = {
"/App.tsx": AppTs,
};
export default {
...react,
...reactTs,
};
@@ -0,0 +1,187 @@
const data = `export const animals = [
{label: "Cat", value: "cat", description: "The second most popular pet in the world"},
{label: "Dog", value: "dog", description: "The most popular pet in the world"},
{label: "Elephant", value: "elephant", description: "The largest land animal"},
{label: "Lion", value: "lion", description: "The king of the jungle"},
{label: "Tiger", value: "tiger", description: "The largest cat species"},
{label: "Giraffe", value: "giraffe", description: "The tallest land animal"},
{
label: "Dolphin",
value: "dolphin",
description: "A widely distributed and diverse group of aquatic mammals",
},
{label: "Penguin", value: "penguin", description: "A group of aquatic flightless birds"},
{label: "Zebra", value: "zebra", description: "A several species of African equids"},
{
label: "Shark",
value: "shark",
description: "A group of elasmobranch fish characterized by a cartilaginous skeleton",
},
{
label: "Whale",
value: "whale",
description: "Diverse group of fully aquatic placental marine mammals",
},
{label: "Otter", value: "otter", description: "A carnivorous mammal in the subfamily Lutrinae"},
{label: "Crocodile", value: "crocodile", description: "A large semiaquatic reptile"},
];`;
const App = `import {Autocomplete, AutocompleteItem} from "@nextui-org/react";
import {useFilter} from "@react-aria/i18n";
import {animals} from "./data";
export default function App() {
// Store Autocomplete input value, selected option, open state, and items
// in a state tracker
const [fieldState, setFieldState] = React.useState({
selectedKey: "",
inputValue: "",
items: animals,
});
// Implement custom filtering logic and control what items are
// available to the Autocomplete.
const {startsWith} = useFilter({sensitivity: "base"});
// Specify how each of the Autocomplete values should change when an
// option is selected from the list box
const onSelectionChange = (key) => {
setFieldState((prevState) => {
let selectedItem = prevState.items.find((option) => option.value === key);
return {
inputValue: selectedItem?.label || "",
selectedKey: key,
items: animals.filter((item) => startsWith(item.label, selectedItem?.label || "")),
};
});
};
// Specify how each of the Autocomplete values should change when the input
// field is altered by the user
const onInputChange = (value) => {
setFieldState((prevState) => ({
inputValue: value,
selectedKey: value === "" ? null : prevState.selectedKey,
items: animals.filter((item) => startsWith(item.label, value)),
}));
};
// Show entire list if user opens the menu manually
const onOpenChange = (isOpen, menuTrigger) => {
if (menuTrigger === "manual" && isOpen) {
setFieldState((prevState) => ({
inputValue: prevState.inputValue,
selectedKey: prevState.selectedKey,
items: animals,
}));
}
};
return (
<Autocomplete
className="max-w-xs"
inputValue={fieldState.inputValue}
items={fieldState.items}
label="Favorite Animal"
placeholder="Search an animal"
selectedKey={fieldState.selectedKey}
variant="bordered"
onInputChange={onInputChange}
onOpenChange={onOpenChange}
onSelectionChange={onSelectionChange}
>
{(item) => <AutocompleteItem key={item.value}>{item.label}</AutocompleteItem>}
</Autocomplete>
);
}`;
const AppTs = `import {Autocomplete, AutocompleteItem, MenuTriggerAction} from "@nextui-org/react";
import {useFilter} from "@react-aria/i18n";
import {animals} from "./data";
type FieldState = {
selectedKey: React.Key | null;
inputValue: string;
items: typeof animals;
};
export default function App() {
// Store Autocomplete input value, selected option, open state, and items
// in a state tracker
const [fieldState, setFieldState] = React.useState<FieldState>({
selectedKey: "",
inputValue: "",
items: animals,
});
// Implement custom filtering logic and control what items are
// available to the Autocomplete.
const {startsWith} = useFilter({sensitivity: "base"});
// Specify how each of the Autocomplete values should change when an
// option is selected from the list box
const onSelectionChange = (key: React.Key) => {
setFieldState((prevState) => {
let selectedItem = prevState.items.find((option) => option.value === key);
return {
inputValue: selectedItem?.label || "",
selectedKey: key,
items: animals.filter((item) => startsWith(item.label, selectedItem?.label || "")),
};
});
};
// Specify how each of the Autocomplete values should change when the input
// field is altered by the user
const onInputChange = (value: string) => {
setFieldState((prevState) => ({
inputValue: value,
selectedKey: value === "" ? null : prevState.selectedKey,
items: animals.filter((item) => startsWith(item.label, value)),
}));
};
// Show entire list if user opens the menu manually
const onOpenChange = (isOpen: boolean, menuTrigger: MenuTriggerAction) => {
if (menuTrigger === "manual" && isOpen) {
setFieldState((prevState) => ({
inputValue: prevState.inputValue,
selectedKey: prevState.selectedKey,
items: animals,
}));
}
};
return (
<Autocomplete
className="max-w-xs"
inputValue={fieldState.inputValue}
items={fieldState.items}
label="Favorite Animal"
placeholder="Search an animal"
selectedKey={fieldState.selectedKey}
variant="bordered"
onInputChange={onInputChange}
onOpenChange={onOpenChange}
onSelectionChange={onSelectionChange}
>
{(item) => <AutocompleteItem key={item.value}>{item.label}</AutocompleteItem>}
</Autocomplete>
);
}`;
const react = {
"/App.jsx": App,
"/data.js": data,
};
const reactTs = {
"/App.tsx": AppTs,
};
export default {
...react,
...reactTs,
};
@@ -0,0 +1,55 @@
import usage from "./usage";
import dynamic from "./dynamic";
import disabled from "./disabled";
import disabledItems from "./disabled-items";
import required from "./required";
import sizes from "./sizes";
import colors from "./colors";
import variants from "./variants";
import labelPlacements from "./label-placements";
import startContent from "./start-content";
import itemStartContent from "./item-start-content";
import customValue from "./custom-value";
import customSelectorIcon from "./custom-selector-icon";
import withoutScrollShadow from "./without-scroll-shadow";
import description from "./description";
import errorMessage from "./error-message";
import events from "./events";
import controlled from "./controlled";
import fullyControlled from "./fully-controlled";
import customItems from "./custom-items";
import customFiltering from "./custom-filtering";
import asyncFiltering from "./async-filtering";
import asyncLoadingItems from "./async-loading-items";
import sections from "./sections";
import customSectionsStyle from "./custom-sections-style";
import customStyles from "./custom-styles";
export const autocompleteContent = {
usage,
dynamic,
disabled,
disabledItems,
required,
sizes,
colors,
variants,
labelPlacements,
startContent,
customValue,
itemStartContent,
customSelectorIcon,
withoutScrollShadow,
description,
errorMessage,
events,
controlled,
fullyControlled,
customItems,
customFiltering,
asyncFiltering,
asyncLoadingItems,
sections,
customSectionsStyle,
customStyles,
};
@@ -0,0 +1,75 @@
const App = `import {Autocomplete, AutocompleteItem, Avatar} from "@nextui-org/react";
export default function App() {
return (
<Autocomplete
className="max-w-xs"
label="Select country"
>
<AutocompleteItem
key="argentina"
startContent={<Avatar alt="Argentina" className="w-6 h-6" src="https://flagcdn.com/ar.svg" />}
>
Argentina
</AutocompleteItem>
<AutocompleteItem
key="venezuela"
startContent={<Avatar alt="Venezuela" className="w-6 h-6" src="https://flagcdn.com/ve.svg" />}
>
Venezuela
</AutocompleteItem>
<AutocompleteItem
key="brazil"
startContent={<Avatar alt="Brazil" className="w-6 h-6" src="https://flagcdn.com/br.svg" />}
>
Brazil
</AutocompleteItem>
<AutocompleteItem
key="switzerland"
startContent={
<Avatar alt="Switzerland" className="w-6 h-6" src="https://flagcdn.com/ch.svg" />
}
>
Switzerland
</AutocompleteItem>
<AutocompleteItem
key="germany"
startContent={<Avatar alt="Germany" className="w-6 h-6" src="https://flagcdn.com/de.svg" />}
>
Germany
</AutocompleteItem>
<AutocompleteItem
key="spain"
startContent={<Avatar alt="Spain" className="w-6 h-6" src="https://flagcdn.com/es.svg" />}
>
Spain
</AutocompleteItem>
<AutocompleteItem
key="france"
startContent={<Avatar alt="France" className="w-6 h-6" src="https://flagcdn.com/fr.svg" />}
>
France
</AutocompleteItem>
<AutocompleteItem
key="italy"
startContent={<Avatar alt="Italy" className="w-6 h-6" src="https://flagcdn.com/it.svg" />}
>
Italy
</AutocompleteItem>
<AutocompleteItem
key="mexico"
startContent={<Avatar alt="Mexico" className="w-6 h-6" src="https://flagcdn.com/mx.svg" />}
>
Mexico
</AutocompleteItem>
</Autocomplete>
);
}`;
const react = {
"/App.jsx": App,
};
export default {
...react,
};

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