Compare commits

...

48 Commits

Author SHA1 Message Date
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
476 changed files with 26505 additions and 6929 deletions
+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>
);
}
+301 -1
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";
@@ -178,13 +185,297 @@ const MyButton2 = extendVariants(Button, {
defaultVariants: {},
});
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>("");
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
@@ -254,6 +545,15 @@ export default function NextUIPerf() {
<Button>Click Me!</Button>
<MyButton2 color="foreground">Press Me!</MyButton2>
<Pagination
showControls
initialPage={page ?? 1}
renderItem={({page, ...itemProps}) => {
return <PaginationItem href={`/examples/perf?page=${page}`} {...itemProps} />;
}}
total={10}
/>
</div>
);
}
+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>
);
+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>
@@ -32,7 +32,6 @@ interface CodeDemoProps extends UseCodeDemoProps, WindowResizerProps {
showSandpackPreview?: boolean;
initialEditorOpen?: boolean;
enableResize?: boolean;
showTabs?: boolean;
showPreview?: boolean;
hideWindowActions?: boolean;
showOpenInCodeSandbox?: boolean;
@@ -54,6 +53,7 @@ export const CodeDemo: React.FC<CodeDemoProps> = ({
showEditor = true,
showPreview = true,
asIframe = false,
showTabs = true,
resizeEnabled = true,
hideWindowActions = false,
showSandpackPreview = false,
@@ -66,7 +66,6 @@ export const CodeDemo: React.FC<CodeDemoProps> = ({
previewHeight = "auto",
overflow = "visible",
displayMode = "always",
showTabs = true,
gradientColor,
highlightedLines,
iframeInitialWidth,
@@ -1,5 +1,5 @@
import React, {forwardRef, useEffect} from "react";
import {clsx, getUniqueID} from "@nextui-org/shared-utils";
import {clsx, dataAttr, getUniqueID} from "@nextui-org/shared-utils";
import BaseHighlight, {Language, PrismTheme, defaultProps} from "prism-react-renderer";
import {debounce} from "lodash";
@@ -11,13 +11,15 @@ interface CodeblockProps {
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) => {
@@ -64,6 +66,32 @@ const Codeblock = forwardRef<HTMLPreElement, CodeblockProps>(
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;
@@ -105,7 +133,7 @@ const Codeblock = forwardRef<HTMLPreElement, CodeblockProps>(
<BaseHighlight
{...defaultProps}
code={codeString}
language={language}
language={codeLang}
theme={theme}
{...props}
>
@@ -138,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>
@@ -72,7 +72,9 @@ export const ComponentLinks = ({
return (
<div className="flex flex-wrap gap-3 mt-6">
<ButtonLink
href={`https://storybook.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
@@ -1,4 +1,6 @@
import {Tabs, Tab, Snippet} from "@nextui-org/react";
import {Key} from "react";
import {useLocalStorage} from "usehooks-ts";
import Codeblock from "./codeblock";
@@ -32,6 +34,22 @@ export interface PackageManagersProps {
}
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"
@@ -39,15 +57,9 @@ export const PackageManagers = ({commands}: PackageManagersProps) => {
base: "group mt-4",
tabList: "h-10",
}}
selectedKey={selectedManager}
variant="underlined"
onSelectionChange={(tabKey) => {
trackEvent("PackageManagers - Selection", {
name: tabKey as string,
action: "tabChange",
category: "docs",
data: commands[tabKey as unknown as PackageManagerName] ?? "",
});
}}
onSelectionChange={handleSelectionChange}
>
{packageManagers.map(({name, icon}) => {
if (!commands[name]) return null;
+25 -16
View File
@@ -21,11 +21,12 @@ 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 {
@@ -69,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 =
@@ -108,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,
)}
@@ -156,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">
@@ -196,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
@@ -213,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") {
@@ -231,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 -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";
@@ -16,9 +16,33 @@ const BgLooper = dynamic(() => import("./bg-looper").then((mod) => mod.BgLooper)
});
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>
+1 -1
View File
@@ -229,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}
/>
),
+5 -5
View File
@@ -247,13 +247,13 @@ export const Navbar: FC<NavbarProps> = ({children, routes, mobileRoutes = [], sl
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.1.0"
href="/blog/v2.2.0"
variant="dot"
onClick={() => handlePressNavbarItem("New components v2.1.0", "/blog/v2.1.0")}
onClick={() => handlePressNavbarItem("Introducing v2.2.0", "/blog/v2.2.0")}
>
New components v2.1.0&nbsp;
<span aria-label="party emoji" role="img">
🎉
Introducing v2.2.0&nbsp;
<span aria-label="rocket emoji" role="img">
🚀
</span>
</Chip>
</NavbarItem>
+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",
@@ -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;
+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} */
@@ -1,12 +1,11 @@
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;
@@ -16,7 +15,6 @@ export interface UseSandpackProps {
}
const importReact = 'import React from "react";';
const importAllReact = 'import * as React from "react";';
export const useSandpack = ({
files = {},
@@ -102,8 +100,8 @@ 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)) {
fileContent = `${importReact}\n\n${fileContent}\n`;
if (!fileContent.includes("from 'react'") && !fileContent.includes('from "react"')) {
fileContent = `${importReact}\n${fileContent}\n`;
}
// Check if file content includes any other dependencies, if yes, add it to dependencies
@@ -186,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};
+39 -9
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",
@@ -188,7 +209,8 @@
"key": "dropdown",
"title": "Dropdown",
"keywords": "dropdown, menu, selection, option list",
"path": "/docs/components/dropdown.mdx"
"path": "/docs/components/dropdown.mdx",
"updated": true
},
{
"key": "image",
@@ -212,14 +234,15 @@
"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",
"newPost": true
"updated": true
},
{
"key": "modal",
@@ -261,8 +284,7 @@
"key": "select",
"title": "Select",
"keywords": "select, selection, option list, multiple choice",
"path": "/docs/components/select.mdx",
"newPost": true
"path": "/docs/components/select.mdx"
},
{
"key": "skeleton",
@@ -280,8 +302,7 @@
"key": "scroll-shadow",
"title": "Scroll Shadow",
"keywords": "scroll shadow, scroll indicator, scroll bar, scroll position",
"path": "/docs/components/scroll-shadow.mdx",
"newPost": true
"path": "/docs/components/scroll-shadow.mdx"
},
{
"key": "spacer",
@@ -301,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",
@@ -311,13 +339,15 @@
"key": "tabs",
"title": "Tabs",
"keywords": "tabs, section navigation, categorized content, tabbed interface",
"path": "/docs/components/tabs.mdx"
"path": "/docs/components/tabs.mdx",
"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",
File diff suppressed because it is too large Load Diff
+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,
};
@@ -0,0 +1,86 @@
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 placements = [
"inside",
"outside",
"outside-left",
];
return (
<div className="w-full flex flex-col gap-4">
<div className="flex flex-col gap-2">
<h3 className="text-default-500 text-small">Without placeholder</h3>
<div className="flex w-full flex-wrap items-end md:flex-nowrap mb-6 md:mb-0 gap-4">
{placements.map((placement) => (
<Autocomplete
defaultItems={animals}
labelPlacement={placement}
label="Favorite Animal"
className="max-w-xs"
>
{(item) => <AutocompleteItem key={item.value}>{item.label}</AutocompleteItem>}
</Autocomplete>
))}
</div>
</div>
<div className="flex flex-col gap-2">
<h3 className="text-default-500 text-small">With placeholder</h3>
<div className="flex w-full flex-wrap items-end md:flex-nowrap mb-6 md:mb-0 gap-4">
{placements.map((placement) => (
<Autocomplete
labelPlacement={placement}
label="Favorite Animal"
placeholder="Search an animal"
className="max-w-xs"
>
{animals.map((animal) => (
<AutocompleteItem key={animal.value} value={animal.value}>
{animal.label}
</AutocompleteItem>
))}
</Autocomplete>
))}
</div>
</div>
</div>
);
}`;
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
isRequired
label="Favorite Animal"
defaultItems={animals}
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,40 @@
const App = `import {Autocomplete, AutocompleteItem, AutocompleteSection} from "@nextui-org/react";
export default function App() {
return (
<Autocomplete
label="Favorite Animal"
placeholder="Search an animal"
className="max-w-xs"
>
<AutocompleteSection showDivider title="Mammals">
<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">
<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,69 @@
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 sizes = ["sm", "md", "lg"];
return (
<div className="w-full flex flex-col gap-4">
{sizes.map((size) => (
<div key={size} className="flex w-full flex-wrap md:flex-nowrap mb-6 md:mb-0 gap-4">
<Autocomplete
size={size}
defaultItems={animals}
label="Select an animal"
className="max-w-xs"
>
{(item) => <AutocompleteItem key={item.value}>{item.label}</AutocompleteItem>}
</Autocomplete>
<Autocomplete
size={size}
defaultItems={animals}
label="Favorite Animal"
placeholder="Search an animal"
className="max-w-xs"
>
{(item) => <AutocompleteItem key={item.value}>{item.label}</AutocompleteItem>}
</Autocomplete>
</div>
))}
</div>
);
}`;
const react = {
"/App.jsx": App,
"/data.js": data,
};
export default {
...react,
};
@@ -0,0 +1,91 @@
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 PetIcon = `export const PetIcon = (props) => (
<svg
aria-hidden="true"
fill="none"
focusable="false"
height="1em"
role="presentation"
viewBox="0 0 24 24"
width="1em"
{...props}
>
<path
d="M19.0803 15.7203C18.4903 12.1903 15.1003 9.32031 11.5203 9.32031C7.63028 9.32031 4.21028 12.4703 3.88028 16.3503C3.75028 17.8503 4.23028 19.2703 5.22028 20.3403C6.20028 21.4103 7.58028 22.0003 9.08028 22.0003H13.7603C15.4503 22.0003 16.9303 21.3403 17.9403 20.1503C18.9503 18.9603 19.3503 17.3803 19.0803 15.7203Z"
fill="currentColor"
/>
<path
d="M10.2796 7.86C11.8978 7.86 13.2096 6.54819 13.2096 4.93C13.2096 3.31181 11.8978 2 10.2796 2C8.66141 2 7.34961 3.31181 7.34961 4.93C7.34961 6.54819 8.66141 7.86 10.2796 7.86Z"
fill="currentColor"
/>
<path
d="M16.94 9.02844C18.2876 9.02844 19.38 7.93601 19.38 6.58844C19.38 5.24086 18.2876 4.14844 16.94 4.14844C15.5924 4.14844 14.5 5.24086 14.5 6.58844C14.5 7.93601 15.5924 9.02844 16.94 9.02844Z"
fill="currentColor"
/>
<path
d="M20.5496 12.9313C21.6266 12.9313 22.4996 12.0582 22.4996 10.9812C22.4996 9.90429 21.6266 9.03125 20.5496 9.03125C19.4727 9.03125 18.5996 9.90429 18.5996 10.9812C18.5996 12.0582 19.4727 12.9313 20.5496 12.9313Z"
fill="currentColor"
/>
<path
d="M3.94 10.9816C5.28757 10.9816 6.38 9.88914 6.38 8.54156C6.38 7.19399 5.28757 6.10156 3.94 6.10156C2.59243 6.10156 1.5 7.19399 1.5 8.54156C1.5 9.88914 2.59243 10.9816 3.94 10.9816Z"
fill="currentColor"
/>
</svg>
);`;
const App = `import {Autocomplete, AutocompleteItem} from "@nextui-org/react";
import {PetIcon} from "./PetIcon";
import {animals} from "./data";
export default function App() {
return (
<Autocomplete
label="Favorite Animal"
placeholder="Search an animal"
variant="bordered"
defaultItems={animals}
startContent={<PetIcon className="text-xl" />}
defaultSelectedKey="cat"
className="max-w-xs"
>
{(item) => <AutocompleteItem key={item.value}>{item.label}</AutocompleteItem>}
</Autocomplete>
);
}`;
const react = {
"/App.jsx": App,
"/PetIcon.jsx": PetIcon,
"/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() {
return (
<div className="flex w-full flex-wrap md:flex-nowrap gap-4">
<Autocomplete
label="Select an animal"
className="max-w-xs"
>
{animals.map((animal) => (
<AutocompleteItem key={animal.value} value={animal.value}>
{animal.label}
</AutocompleteItem>
))}
</Autocomplete>
<Autocomplete
label="Favorite Animal"
placeholder="Search an animal"
className="max-w-xs"
defaultItems={animals}
>
{(item) => <AutocompleteItem key={item.value}>{item.label}</AutocompleteItem>}
</Autocomplete>
</div>
);
}`;
const react = {
"/App.jsx": App,
"/data.js": data,
};
export default {
...react,
};
@@ -0,0 +1,72 @@
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 variants = ["flat", "bordered", "underlined", "faded"];
return (
<div className="w-full flex flex-col gap-4">
{variants.map((variant) => (
<div key={variant} className="flex w-full flex-wrap md:flex-nowrap mb-6 md:mb-0 gap-4">
<Autocomplete
variant={variant}
defaultItems={animals}
label="Select an animal"
className="max-w-xs"
>
{(item) => <AutocompleteItem key={item.value}>{item.label}</AutocompleteItem>}
</Autocomplete>
<Autocomplete
variant={variant}
label="Favorite Animal"
placeholder="Search an animal"
className="max-w-xs"
>
{animals.map((animal) => (
<AutocompleteItem key={animal.value} value={animal.value}>
{animal.label}
</AutocompleteItem>
))}
</Autocomplete>
</div>
))}
</div>
);
}`;
const react = {
"/App.jsx": App,
"/data.js": data,
};
export default {
...react,
};
@@ -0,0 +1,56 @@
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"
defaultSelectedKey="cat"
defaultItems={animals}
className="max-w-xs"
scrollShadowProps={{
isEnabled: false
}}
>
{(item) => <AutocompleteItem key={item.value}>{item.label}</AutocompleteItem>}
</Autocomplete>
);
}`;
const react = {
"/App.jsx": App,
"/data.js": data,
};
export default {
...react,
};
@@ -1,4 +1,4 @@
const App = `import {Avatar} from "@nextui-org/react
const App = `import {Avatar} from "@nextui-org/react";
export default function App() {
return (
@@ -1,4 +1,4 @@
const App = `import {Avatar} from "@nextui-org/react
const App = `import {Avatar} from "@nextui-org/react";
export default function App() {
return (
@@ -18,7 +18,7 @@ const CameraIcon = `export const CameraIcon = ({fill, size, height, width, ...pr
);
};`;
const App = `import {Avatar} from "@nextui-org/react
const App = `import {Avatar} from "@nextui-org/react";
import {CameraIcon} from './CameraIcon';
export default function App() {
@@ -1,4 +1,4 @@
const App = `import {Avatar} from "@nextui-org/react
const App = `import {Avatar} from "@nextui-org/react";
export default function App() {
return (
@@ -7,7 +7,7 @@ export default function App() {
max={3}
total={10}
renderCount={(count) => (
<p className="text-small text-foreground font-medium ml-2">+{count} others</p>
<p className="text-small text-foreground font-medium ms-2">+{count} others</p>
)}
>
<Avatar src="https://i.pravatar.cc/150?u=a042581f4e29026024d" />
@@ -1,4 +1,4 @@
const App = `import {Avatar} from "@nextui-org/react
const App = `import {Avatar} from "@nextui-org/react";
export default function App() {
return (
+2 -2
View File
@@ -6,7 +6,7 @@ import placements from "./placements";
import shapes from "./shapes";
import visibility from "./visibility";
import contentExamples from "./content-examples";
import disableOutline from "./disable-outline";
import showOutline from "./show-outline";
import a11y from "./a11y";
export const badgeContent = {
@@ -18,6 +18,6 @@ export const badgeContent = {
shapes,
visibility,
contentExamples,
disableOutline,
showOutline,
a11y,
};
@@ -3,14 +3,14 @@ const App = `import {Badge, Avatar} from "@nextui-org/react";
export default function App() {
return (
<div className="flex gap-4 items-center">
<Badge content="5" color="danger" shape="rectangle" disableOutline>
<Badge content="5" color="danger" shape="rectangle" showOutline={false}>
<Avatar
isBordered
radius="md"
src="https://i.pravatar.cc/150?u=a042f81f4e29026024d"
/>
</Badge>
<Badge content="5" color="danger" shape="circle" disableOutline>
<Badge content="5" color="danger" shape="circle" showOutline={false}>
<Avatar
isBordered
radius="full"
@@ -0,0 +1,21 @@
const App = `import {Breadcrumbs, BreadcrumbItem} from "@nextui-org/react";
export default function App() {
return (
<Breadcrumbs maxItems={3} itemsBeforeCollapse={1} itemsAfterCollapse={2}>
<BreadcrumbItem href="#home">Home</BreadcrumbItem>
<BreadcrumbItem href="#music">Music</BreadcrumbItem>
<BreadcrumbItem href="#artist">Artist</BreadcrumbItem>
<BreadcrumbItem href="#album">Album</BreadcrumbItem>
<BreadcrumbItem href="#song">Song</BreadcrumbItem>
</Breadcrumbs>
);
}`;
const react = {
"/App.jsx": App,
};
export default {
...react,
};
@@ -0,0 +1,27 @@
const App = `import {Breadcrumbs, BreadcrumbItem} from "@nextui-org/react";
export default function App() {
const colors = ["foreground", "primary", "secondary", "success", "warning", "danger"];
return (
<div className="flex flex-col flex-wrap gap-4">
{colors.map((color) => (
<Breadcrumbs key={color} color={color}>
<BreadcrumbItem>Home</BreadcrumbItem>
<BreadcrumbItem>Music</BreadcrumbItem>
<BreadcrumbItem>Artist</BreadcrumbItem>
<BreadcrumbItem>Album</BreadcrumbItem>
<BreadcrumbItem>Song</BreadcrumbItem>
</Breadcrumbs>
))}
</div>
);
}`;
const react = {
"/App.jsx": App,
};
export default {
...react,
};
@@ -0,0 +1,64 @@
const App = `import {Breadcrumbs, BreadcrumbItem} from "@nextui-org/react";
export default function App() {
const [currentPage, setCurrentPage] = React.useState("song");
return (
<Breadcrumbs underline="active" onAction={(key) => setCurrentPage(key)}>
<BreadcrumbItem key="home" isCurrent={currentPage === "home"}>
Home
</BreadcrumbItem>
<BreadcrumbItem key="music" isCurrent={currentPage === "music"}>
Music
</BreadcrumbItem>
<BreadcrumbItem key="artist" isCurrent={currentPage === "artist"}>
Artist
</BreadcrumbItem>
<BreadcrumbItem key="album" isCurrent={currentPage === "album"}>
Album
</BreadcrumbItem>
<BreadcrumbItem key="song" isCurrent={currentPage === "song"}>
Song
</BreadcrumbItem>
</Breadcrumbs>
);
}`;
const AppTs = `import {Breadcrumbs, BreadcrumbItem} from "@nextui-org/react";
export default function App() {
const [currentPage, setCurrentPage] = React.useState<React.Key>("song");
return (
<Breadcrumbs underline="active" onAction={(key) => setCurrentPage(key)}>
<BreadcrumbItem key="home" isCurrent={currentPage === "home"}>
Home
</BreadcrumbItem>
<BreadcrumbItem key="music" isCurrent={currentPage === "music"}>
Music
</BreadcrumbItem>
<BreadcrumbItem key="artist" isCurrent={currentPage === "artist"}>
Artist
</BreadcrumbItem>
<BreadcrumbItem key="album" isCurrent={currentPage === "album"}>
Album
</BreadcrumbItem>
<BreadcrumbItem key="song" isCurrent={currentPage === "song"}>
Song
</BreadcrumbItem>
</Breadcrumbs>
);
}`;
const react = {
"/App.jsx": App,
};
const reactTs = {
"/App.tsx": AppTs,
};
export default {
...react,
...reactTs,
};
@@ -0,0 +1,76 @@
const ChevronDownIcon = `export const ChevronDownIcon = (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="m6 9 6 6 6-6" />
</svg>
);`;
const App = `import {Breadcrumbs, BreadcrumbItem, Dropdown, DropdownTrigger, DropdownMenu, DropdownItem, Button} from "@nextui-org/react";
import {ChevronDownIcon} from "./ChevronDownIcon";
export default function App() {
return (
<Breadcrumbs
itemClasses={{
item: "px-2",
separator: "px-0",
}}
>
<BreadcrumbItem href="#home">Home</BreadcrumbItem>
<BreadcrumbItem href="#music">Music</BreadcrumbItem>
<BreadcrumbItem href="#artist">Artist</BreadcrumbItem>
<BreadcrumbItem href="#album">Album</BreadcrumbItem>
<BreadcrumbItem
classNames={{
item: "px-0",
}}
>
<Dropdown>
<DropdownTrigger>
<Button
className="h-6 pr-2 text-small"
endContent={<ChevronDownIcon className="text-default-500" />}
radius="full"
size="sm"
variant="light"
>
Songs
</Button>
</DropdownTrigger>
<DropdownMenu aria-label="Routes">
<DropdownItem href="#song-1">
Song 1
</DropdownItem>
<DropdownItem href="#song2">
Song 2
</DropdownItem>
<DropdownItem href="#song3">
Song 3
</DropdownItem>
</DropdownMenu>
</Dropdown>
</BreadcrumbItem>
</Breadcrumbs>
);
}`;
const react = {
"/App.jsx": App,
"/ChevronDownIcon.jsx": ChevronDownIcon,
};
export default {
...react,
};
@@ -0,0 +1,64 @@
const ShoppingCartIcon = `export const ShoppingCartIcon = (props) => (
<svg
aria-hidden="true"
fill="none"
focusable="false"
height="1em"
role="presentation"
viewBox="0 0 24 24"
width="1em"
{...props}
>
<path
d="M16.25 22.5C17.2165 22.5 18 21.7165 18 20.75C18 19.7835 17.2165 19 16.25 19C15.2835 19 14.5 19.7835 14.5 20.75C14.5 21.7165 15.2835 22.5 16.25 22.5Z"
fill="currentColor"
/>
<path
d="M8.25 22.5C9.2165 22.5 10 21.7165 10 20.75C10 19.7835 9.2165 19 8.25 19C7.2835 19 6.5 19.7835 6.5 20.75C6.5 21.7165 7.2835 22.5 8.25 22.5Z"
fill="currentColor"
/>
<path
d="M4.84 3.94L4.64 6.39C4.6 6.86 4.97 7.25 5.44 7.25H20.75C21.17 7.25 21.52 6.93 21.55 6.51C21.68 4.74 20.33 3.3 18.56 3.3H6.27C6.17 2.86 5.97 2.44 5.66 2.09C5.16 1.56 4.46 1.25 3.74 1.25H2C1.59 1.25 1.25 1.59 1.25 2C1.25 2.41 1.59 2.75 2 2.75H3.74C4.05 2.75 4.34 2.88 4.55 3.1C4.76 3.33 4.86 3.63 4.84 3.94Z"
fill="currentColor"
/>
<path
d="M20.5101 8.75H5.17005C4.75005 8.75 4.41005 9.07 4.37005 9.48L4.01005 13.83C3.87005 15.54 5.21005 17 6.92005 17H18.0401C19.5401 17 20.8601 15.77 20.9701 14.27L21.3001 9.6C21.3401 9.14 20.9801 8.75 20.5101 8.75Z"
fill="currentColor"
/>
</svg>
);`;
const App = `import {Breadcrumbs, BreadcrumbItem} from "@nextui-org/react";
import {ShoppingCartIcon} from "./ShoppingCartIcon";
export default function App() {
return (
<Breadcrumbs
underline="hover"
classNames={{
list: "bg-gradient-to-br from-violet-500 to-fuchsia-500 shadow-small",
}}
itemClasses={{
item: "text-white/60 data-[current=true]:text-white",
separator: "text-white/40",
}}
variant="solid"
>
<BreadcrumbItem href="#shopping-cart">
<ShoppingCartIcon />
</BreadcrumbItem>
<BreadcrumbItem href="#checkout">Checkout</BreadcrumbItem>
<BreadcrumbItem href="#payment">Payment</BreadcrumbItem>
<BreadcrumbItem href="#delivery-address">Delivery Address</BreadcrumbItem>
</Breadcrumbs>
);
}`;
const react = {
"/App.jsx": App,
"/ShoppingCartIcon.jsx": ShoppingCartIcon,
};
export default {
...react,
};
@@ -0,0 +1,50 @@
const App = `import {Breadcrumbs, BreadcrumbItem, Dropdown, DropdownTrigger, DropdownMenu, DropdownItem, Button} from "@nextui-org/react";
export default function App() {
return (
<Breadcrumbs
maxItems={3}
itemsBeforeCollapse={1}
itemsAfterCollapse={2}
renderEllipsis={({items, ellipsisIcon, separator}) => (
<div className="flex items-center">
<Dropdown>
<DropdownTrigger>
<Button
isIconOnly
className="min-w-unit-6 w-unit-6 h-unit-6"
size="sm"
variant="flat"
>
{ellipsisIcon}
</Button>
</DropdownTrigger>
<DropdownMenu aria-label="Routes">
{items.map((item, index) => (
<DropdownItem key={index} href={item.href}>
{item.children}
</DropdownItem>
))}
</DropdownMenu>
</Dropdown>
{separator}
</div>
)}
>
<BreadcrumbItem href="#home">Home</BreadcrumbItem>
<BreadcrumbItem href="#music">Music</BreadcrumbItem>
<BreadcrumbItem href="#artist">Artist</BreadcrumbItem>
<BreadcrumbItem href="#album">Album</BreadcrumbItem>
<BreadcrumbItem href="#featured">Featured</BreadcrumbItem>
<BreadcrumbItem href="#song">Song</BreadcrumbItem>
</Breadcrumbs>
);
}`;
const react = {
"/App.jsx": App,
};
export default {
...react,
};
@@ -0,0 +1,21 @@
const App = `import {Breadcrumbs, BreadcrumbItem} from "@nextui-org/react";
export default function App() {
return (
<Breadcrumbs isDisabled>
<BreadcrumbItem>Home</BreadcrumbItem>
<BreadcrumbItem>Music</BreadcrumbItem>
<BreadcrumbItem>Artist</BreadcrumbItem>
<BreadcrumbItem>Album</BreadcrumbItem>
<BreadcrumbItem>Song</BreadcrumbItem>
</Breadcrumbs>
);
}`;
const react = {
"/App.jsx": App,
};
export default {
...react,
};
@@ -0,0 +1,35 @@
import usage from "./usage";
import disabled from "./disabled";
import sizes from "./sizes";
import colors from "./colors";
import variants from "./variants";
import radius from "./radius";
import routing from "./routing";
import underlines from "./underlines";
import controlled from "./controlled";
import menuType from "./menu-type";
import startEndContent from "./start-end-content";
import separator from "./separator";
import customItems from "./custom-items";
import collapsingItems from "./collapsing-items";
import customizingEllipsis from "./customizing-ellipsis";
import customStyles from "./custom-styles";
export const breadcrumbsContent = {
usage,
disabled,
sizes,
colors,
variants,
radius,
routing,
underlines,
controlled,
menuType,
startEndContent,
separator,
customItems,
collapsingItems,
customizingEllipsis,
customStyles,
};
@@ -0,0 +1,91 @@
const App = `import {Breadcrumbs, BreadcrumbItem} from "@nextui-org/react";
export default function App() {
const [currentPage, setCurrentPage] = React.useState("music");
return (
<Breadcrumbs
size="sm"
onAction={(key) => setCurrentPage(key)}
classNames={{
list: "gap-2",
}}
itemClasses={{
item: [
"px-2 py-0.5 border-small border-default-400 rounded-small",
"data-[current=true]:border-foreground data-[current=true]:bg-foreground data-[current=true]:text-background transition-colors",
"data-[disabled=true]:border-default-400 data-[disabled=true]:bg-default-100",
],
separator: "hidden",
}}
>
<BreadcrumbItem key="home" isCurrent={currentPage === "home"}>
Home
</BreadcrumbItem>
<BreadcrumbItem key="music" isCurrent={currentPage === "music"}>
Music
</BreadcrumbItem>
<BreadcrumbItem key="artist" isCurrent={currentPage === "artist"}>
Artist
</BreadcrumbItem>
<BreadcrumbItem key="album" isCurrent={currentPage === "album"}>
Album
</BreadcrumbItem>
<BreadcrumbItem key="song" isDisabled isCurrent={currentPage === "song"}>
Song
</BreadcrumbItem>
</Breadcrumbs>
);
}`;
const AppTs = `import {Breadcrumbs, BreadcrumbItem} from "@nextui-org/react";
export default function App() {
const [currentPage, setCurrentPage] = React.useState<React.Key>("music");
return (
<Breadcrumbs
hideSeparator
onAction={(key) => setCurrentPage(key)}
classNames={{
list: "gap-2",
}}
itemClasses={{
item: [
"px-2 py-0.5 border-small border-default-400 rounded-small",
"data-[current=true]:border-default-800 data-[current=true]:bg-foreground data-[current=true]:text-background transition-colors",
"data-[disabled=true]:border-default-400 data-[disabled=true]:bg-default-100",
],
}}
>
<BreadcrumbItem key="home" isCurrent={currentPage === "home"}>
Home
</BreadcrumbItem>
<BreadcrumbItem key="music" isCurrent={currentPage === "music"}>
Music
</BreadcrumbItem>
<BreadcrumbItem key="artist" isCurrent={currentPage === "artist"}>
Artist
</BreadcrumbItem>
<BreadcrumbItem key="album" isCurrent={currentPage === "album"}>
Album
</BreadcrumbItem>
<BreadcrumbItem key="song" isDisabled isCurrent={currentPage === "song"}>
Song
</BreadcrumbItem>
</Breadcrumbs>
);
}`;
const react = {
"/App.jsx": App,
};
const reactTs = {
"/App.tsx": AppTs,
};
export default {
...react,
...reactTs,
};
@@ -0,0 +1,27 @@
const App = `import {Breadcrumbs, BreadcrumbItem} from "@nextui-org/react";
export default function App() {
const radius = [ "full", "lg", "md", "sm", "none"];
return (
<div className="flex flex-col flex-wrap gap-4">
{radius.map((r) => (
<Breadcrumbs key={r} radius={r} variant="solid">
<BreadcrumbItem>Home</BreadcrumbItem>
<BreadcrumbItem>Music</BreadcrumbItem>
<BreadcrumbItem>Artist</BreadcrumbItem>
<BreadcrumbItem>Album</BreadcrumbItem>
<BreadcrumbItem>Song</BreadcrumbItem>
</Breadcrumbs>
))}
</div>
);
}`;
const react = {
"/App.jsx": App,
};
export default {
...react,
};
@@ -0,0 +1,21 @@
const App = `import {Breadcrumbs, BreadcrumbItem} from "@nextui-org/react";
export default function App() {
return (
<Breadcrumbs>
<BreadcrumbItem href="/docs/components/button">Button</BreadcrumbItem>
<BreadcrumbItem href="/docs/components/breadcrumbs">Breadcrumbs</BreadcrumbItem>
<BreadcrumbItem href="/docs/components/card">Card</BreadcrumbItem>
<BreadcrumbItem href="/docs/components/checkbox">Checkbox</BreadcrumbItem>
<BreadcrumbItem href="/docs/components/code">Code</BreadcrumbItem>
</Breadcrumbs>
);
}`;
const react = {
"/App.jsx": App,
};
export default {
...react,
};
@@ -0,0 +1,26 @@
const App = `import {Breadcrumbs, BreadcrumbItem} from "@nextui-org/react";
export default function App() {
return (
<Breadcrumbs
separator="/"
itemClasses={{
separator: "px-2"
}}
>
<BreadcrumbItem>Home</BreadcrumbItem>
<BreadcrumbItem>Music</BreadcrumbItem>
<BreadcrumbItem>Artist</BreadcrumbItem>
<BreadcrumbItem>Album</BreadcrumbItem>
<BreadcrumbItem>Song</BreadcrumbItem>
</Breadcrumbs>
);
}`;
const react = {
"/App.jsx": App,
};
export default {
...react,
};
@@ -0,0 +1,27 @@
const App = `import {Breadcrumbs, BreadcrumbItem} from "@nextui-org/react";
export default function App() {
const sizes = ["sm", "md", "lg"];
return (
<div className="flex flex-col flex-wrap gap-4">
{sizes.map((size) => (
<Breadcrumbs key={size} size={size}>
<BreadcrumbItem>Home</BreadcrumbItem>
<BreadcrumbItem>Music</BreadcrumbItem>
<BreadcrumbItem>Artist</BreadcrumbItem>
<BreadcrumbItem>Album</BreadcrumbItem>
<BreadcrumbItem>Song</BreadcrumbItem>
</Breadcrumbs>
))}
</div>
);
}`;
const react = {
"/App.jsx": App,
};
export default {
...react,
};
@@ -0,0 +1,112 @@
const HomeIcon = `export const HomeIcon = (props) => (
<svg
aria-hidden="true"
fill="none"
focusable="false"
height="1em"
role="presentation"
viewBox="0 0 24 24"
width="1em"
{...props}
>
<path d="M20.0402 6.82165L14.2802 2.79165C12.7102 1.69165 10.3002 1.75165 8.79023 2.92165L3.78023 6.83165C2.78023 7.61165 1.99023 9.21165 1.99023 10.4716V17.3716C1.99023 19.9216 4.06023 22.0016 6.61023 22.0016H17.3902C19.9402 22.0016 22.0102 19.9316 22.0102 17.3816V10.6016C22.0102 9.25165 21.1402 7.59165 20.0402 6.82165ZM12.7502 18.0016C12.7502 18.4116 12.4102 18.7516 12.0002 18.7516C11.5902 18.7516 11.2502 18.4116 11.2502 18.0016V15.0016C11.2502 14.5916 11.5902 14.2516 12.0002 14.2516C12.4102 14.2516 12.7502 14.5916 12.7502 15.0016V18.0016Z" fill="currentColor"/>
</svg>
);`;
const MusicIcon = `export const MusicIcon = (props) => (
<svg
aria-hidden="true"
fill="none"
focusable="false"
height="1em"
role="presentation"
viewBox="0 0 24 24"
width="1em"
{...props}
>
<path d="M14.5406 13.6719C14.1806 13.6719 13.8906 13.9619 13.8906 14.3219C13.8906 14.6819 14.1806 14.9719 14.5406 14.9719C14.9006 14.9719 15.1906 14.6819 15.1906 14.3219C15.1806 13.9619 14.8906 13.6719 14.5406 13.6719Z" fill="currentColor"/>
<path d="M9.06016 14.6602C8.70016 14.6602 8.41016 14.9502 8.41016 15.3102C8.41016 15.6702 8.70016 15.9602 9.06016 15.9602C9.42016 15.9602 9.71016 15.6702 9.71016 15.3102C9.71016 14.9502 9.42016 14.6602 9.06016 14.6602Z" fill="currentColor"/>
<path d="M16.19 2H7.81C4.17 2 2 4.17 2 7.81V16.18C2 19.83 4.17 22 7.81 22H16.18C19.82 22 21.99 19.83 21.99 16.19V7.81C22 4.17 19.83 2 16.19 2ZM16.88 9.55V14.31C16.88 15.6 15.83 16.65 14.54 16.65C13.25 16.65 12.2 15.6 12.2 14.31C12.2 13.02 13.25 11.97 14.54 11.97C14.77 11.97 14.98 12.01 15.19 12.07V10.65L11.41 11.68V15.3C11.41 15.31 11.4 15.32 11.4 15.33C11.39 16.61 10.34 17.64 9.06 17.64C7.77 17.64 6.72 16.59 6.72 15.3C6.72 14.01 7.77 12.96 9.06 12.96C9.29 12.96 9.5 13 9.71 13.06V11.03V9.29C9.71 8.32 10.31 7.53 11.25 7.28L14.24 6.46C15.2 6.2 15.8 6.45 16.14 6.71C16.47 6.97 16.88 7.48 16.88 8.48V9.55Z" fill="currentColor"/>
</svg>
);`;
const ArtistIcon = `export const ArtistIcon = (props) => (
<svg
aria-hidden="true"
fill="none"
focusable="false"
height="1em"
role="presentation"
viewBox="0 0 24 24"
width="1em"
{...props}
>
<path d="M19.5119 5.85L13.5719 2.42C12.6019 1.86 11.4019 1.86 10.4219 2.42L4.49187 5.85C3.52187 6.41 2.92188 7.45 2.92188 8.58V15.42C2.92188 16.54 3.52187 17.58 4.49187 18.15L10.4319 21.58C11.4019 22.14 12.6019 22.14 13.5819 21.58L19.5219 18.15C20.4919 17.59 21.0919 16.55 21.0919 15.42V8.58C21.0819 7.45 20.4819 6.42 19.5119 5.85ZM12.0019 7.34C13.2919 7.34 14.3319 8.38 14.3319 9.67C14.3319 10.96 13.2919 12 12.0019 12C10.7119 12 9.67188 10.96 9.67188 9.67C9.67188 8.39 10.7119 7.34 12.0019 7.34ZM14.6819 16.66H9.32187C8.51187 16.66 8.04187 15.76 8.49187 15.09C9.17187 14.08 10.4919 13.4 12.0019 13.4C13.5119 13.4 14.8319 14.08 15.5119 15.09C15.9619 15.75 15.4819 16.66 14.6819 16.66Z" fill="currentColor"/>
</svg>
);`;
const AlbumIcon = `export const AlbumIcon = (props) => (
<svg
aria-hidden="true"
fill="none"
focusable="false"
height="1em"
role="presentation"
viewBox="0 0 24 24"
width="1em"
{...props}
>
<path d="M18 5.25H6C5.59 5.25 5.25 4.91 5.25 4.5C5.25 4.09 5.59 3.75 6 3.75H18C18.41 3.75 18.75 4.09 18.75 4.5C18.75 4.91 18.41 5.25 18 5.25Z" fill="currentColor"/>
<path d="M15 2.75H9C8.59 2.75 8.25 2.41 8.25 2C8.25 1.59 8.59 1.25 9 1.25H15C15.41 1.25 15.75 1.59 15.75 2C15.75 2.41 15.41 2.75 15 2.75Z" fill="currentColor"/>
<path d="M13.9091 16.2109C13.5691 16.2109 13.2891 16.4909 13.2891 16.8309C13.2891 17.1709 13.5691 17.4509 13.9091 17.4509C14.2491 17.4509 14.5291 17.1709 14.5291 16.8309C14.5291 16.4909 14.2491 16.2109 13.9091 16.2109Z" fill="currentColor"/>
<path d="M9.50953 17.7389C9.50953 17.3989 9.22953 17.1289 8.88953 17.1289C8.54953 17.1289 8.26953 17.4089 8.26953 17.7489C8.26953 18.0889 8.54953 18.3689 8.88953 18.3689C9.22953 18.3589 9.50953 18.0789 9.50953 17.7389Z" fill="currentColor"/>
<path d="M18 7H6C3.8 7 2 8.8 2 11V18C2 20.2 3.8 22 6 22H18C20.2 22 22 20.2 22 18V11C22 8.8 20.2 7 18 7ZM16.03 12.46V16.83C16.03 16.85 16.02 16.86 16.02 16.88C15.99 18.02 15.06 18.95 13.91 18.95C12.74 18.95 11.79 18 11.79 16.83C11.79 15.66 12.74 14.71 13.91 14.71C14.13 14.71 14.33 14.75 14.53 14.81V13.44L11.01 14.4V17.73V17.74C11.01 18.91 10.06 19.86 8.89 19.86C7.72 19.86 6.77 18.91 6.77 17.74C6.77 16.57 7.72 15.62 8.89 15.62C9.11 15.62 9.31 15.66 9.51 15.72V13.82V12.22C9.51 11.33 10.06 10.61 10.91 10.39L13.64 9.64C14.52 9.41 15.06 9.64 15.37 9.88C15.67 10.11 16.03 10.58 16.03 11.47V12.46Z" fill="currentColor"/>
</svg>
);`;
const SongIcon = `export const SongIcon = (props) => (
<svg
aria-hidden="true"
fill="none"
focusable="false"
height="1em"
role="presentation"
viewBox="0 0 24 24"
width="1em"
{...props}
>
<path d="M21.7188 6.27879V7.44879C21.7188 8.42879 21.3288 9.26879 20.6388 9.75879C20.2087 10.0788 19.6787 10.2288 19.1287 10.2288C18.7887 10.2288 18.4488 10.1788 18.0988 10.0588L12.7188 8.26879V17.9988C12.7188 20.6188 10.5887 22.7488 7.96875 22.7488C5.34875 22.7488 3.21875 20.6188 3.21875 17.9988C3.21875 15.3788 5.34875 13.2488 7.96875 13.2488C9.22875 13.2488 10.3688 13.7488 11.2188 14.5488V3.99879C11.2188 3.02879 11.6188 2.18879 12.3088 1.68879C12.9987 1.19879 13.9187 1.08879 14.8387 1.38879L19.2588 2.86879C20.6188 3.31879 21.7188 4.84879 21.7188 6.27879Z" fill="currentColor"/>
</svg>
);`;
const App = `import {Breadcrumbs, BreadcrumbItem} from "@nextui-org/react";
import {HomeIcon} from "./HomeIcon";
import {MusicIcon} from "./MusicIcon";
import {ArtistIcon} from "./ArtistIcon";
import {AlbumIcon} from "./AlbumIcon";
import {SongIcon} from "./SongIcon";
export default function App() {
return (
<Breadcrumbs>
<BreadcrumbItem startContent={<HomeIcon />}>Home</BreadcrumbItem>
<BreadcrumbItem startContent={<MusicIcon />}>Music</BreadcrumbItem>
<BreadcrumbItem startContent={<ArtistIcon />}>Artist</BreadcrumbItem>
<BreadcrumbItem startContent={<AlbumIcon />}>Album</BreadcrumbItem>
<BreadcrumbItem startContent={<SongIcon />}>Song</BreadcrumbItem>
</Breadcrumbs>
);
}`;
const react = {
"/App.jsx": App,
"/HomeIcon.jsx": HomeIcon,
"/MusicIcon.jsx": MusicIcon,
"/ArtistIcon.jsx": ArtistIcon,
"/AlbumIcon.jsx": AlbumIcon,
"/SongIcon.jsx": SongIcon,
};
export default {
...react,
};
@@ -0,0 +1,39 @@
const App = `import {Breadcrumbs, BreadcrumbItem} from "@nextui-org/react";
export default function App() {
const underlines = ["none", "hover", "always", "active", "focus"];
const descriptions = {
none: "No underline",
hover: "Underline on hover",
always: "Always underline",
active: "Underline on active",
focus: "Underline on focus",
}
return (
<div className="flex flex-col flex-wrap gap-4">
{underlines.map((u) => (
<div key={u}>
<p className="mb-1 text-small text-default-600 capitalize">
{descriptions[u]} ({u})
</p>
<Breadcrumbs underline={u}>
<BreadcrumbItem>Home</BreadcrumbItem>
<BreadcrumbItem>Music</BreadcrumbItem>
<BreadcrumbItem>Artist</BreadcrumbItem>
<BreadcrumbItem>Album</BreadcrumbItem>
<BreadcrumbItem>Song</BreadcrumbItem>
</Breadcrumbs>
</div>
))}
</div>
);
}`;
const react = {
"/App.jsx": App,
};
export default {
...react,
};
@@ -0,0 +1,21 @@
const App = `import {Breadcrumbs, BreadcrumbItem} from "@nextui-org/react";
export default function App() {
return (
<Breadcrumbs>
<BreadcrumbItem>Home</BreadcrumbItem>
<BreadcrumbItem>Music</BreadcrumbItem>
<BreadcrumbItem>Artist</BreadcrumbItem>
<BreadcrumbItem>Album</BreadcrumbItem>
<BreadcrumbItem>Song</BreadcrumbItem>
</Breadcrumbs>
);
}`;
const react = {
"/App.jsx": App,
};
export default {
...react,
};
@@ -0,0 +1,27 @@
const App = `import {Breadcrumbs, BreadcrumbItem} from "@nextui-org/react";
export default function App() {
const variants = ["solid", "bordered", "light"];
return (
<div className="flex flex-col flex-wrap gap-4">
{variants.map((variant) => (
<Breadcrumbs key={variant} variant={variant}>
<BreadcrumbItem>Home</BreadcrumbItem>
<BreadcrumbItem>Music</BreadcrumbItem>
<BreadcrumbItem>Artist</BreadcrumbItem>
<BreadcrumbItem>Album</BreadcrumbItem>
<BreadcrumbItem>Song</BreadcrumbItem>
</Breadcrumbs>
))}
</div>
);
}`;
const react = {
"/App.jsx": App,
};
export default {
...react,
};
+5 -5
View File
@@ -140,7 +140,7 @@ const ShuffleIcon = `export const ShuffleIcon = ({size = 24, width, height, ...p
</svg>
);`;
const App = `import {Card, CardBody, Image, Button, Progress} from "@nextui-org/react";
const App = `import {Card, CardBody, Image, Button, Slider} from "@nextui-org/react";
import {HeartIcon} from "./HeartIcon";
import {PauseCircleIcon} from "./PauseCircleIcon";
import {NextIcon} from "./NextIcon";
@@ -192,15 +192,15 @@ export default function App() {
</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-small">1:23</p>
+2 -2
View File
@@ -2,11 +2,11 @@ const App = `import {Code} from "@nextui-org/react";
export default function App() {
return (
<div className="flex gap-4">
<div className="flex flex-col gap-4">
<Code size="sm">npm install @nextui-org/react</Code>
<Code size="md">npm install @nextui-org/react</Code>
<Code size="lg">npm install @nextui-org/react</Code>
</div>
</div>
);
}`;
@@ -30,8 +30,8 @@ export default function App() {
showArrow
radius="sm"
classNames={{
base: "p-0 border-small border-divider bg-background",
arrow: "bg-default-200",
base: "before:bg-default-200", // change arrow background
content: "p-0 border-small border-divider bg-background",
}}
>
<DropdownTrigger>
@@ -113,8 +113,8 @@ export default function App() {
<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",
base: "before:bg-default-200", // change arrow background
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",
}}
>
<DropdownTrigger>
+1
View File
@@ -30,3 +30,4 @@ export * from "./pagination";
export * from "./dropdown";
export * from "./navbar";
export * from "./table";
export * from "./autocomplete";
@@ -45,8 +45,6 @@ const CloseFilledIcon = `export const CloseFilledIcon = (props) => (
const App = `import React, {forwardRef} from "react";
import {useInput} from "@nextui-org/react";
import {SearchIcon} from "./SearchIcon";
import {CloseFilledIcon} from "./CloseFilledIcon";
@@ -100,7 +98,7 @@ const MyInput = forwardRef((props, ref) => {
type: "search",
placeholder: "Type to search...",
startContent: (
<SearchIcon className="text-black/50 dark:text-white/90 text-slate-400 pointer-events-none flex-shrink-0" />
<SearchIcon className="text-black/50 mb-0.5 dark:text-white/90 text-slate-400 pointer-events-none flex-shrink-0" />
),
// custom styles
classNames: {
@@ -59,7 +59,7 @@ export default function App() {
}}
placeholder="Type to search..."
startContent={
<SearchIcon className="text-black/50 dark:text-white/90 text-slate-400 pointer-events-none flex-shrink-0" />
<SearchIcon className="text-black/50 mb-0.5 dark:text-white/90 text-slate-400 pointer-events-none flex-shrink-0" />
}
/>
</div>
@@ -72,7 +72,7 @@ const UsersIcon = `export const UsersIcon = (props) => (
</svg>
);`;
const WatchersIcon = `export const WatchersIcons = (props) => (
const WatchersIcon = `export const WatchersIcon = (props) => (
<svg height="1em" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg" {...props}>
<path
d="m21.977 13.783-2-9A1.002 1.002 0 0 0 19 4h-3v2h2.198l.961 4.326A4.467 4.467 0 0 0 17.5 10c-1.953 0-3.603 1.258-4.224 3h-2.553c-.621-1.742-2.271-3-4.224-3-.587 0-1.145.121-1.659.326L5.802 6H8V4H5a1 1 0 0 0-.976.783l-2 9 .047.011A4.552 4.552 0 0 0 2 14.5C2 16.981 4.019 19 6.5 19c2.31 0 4.197-1.756 4.449-4h2.102c.252 2.244 2.139 4 4.449 4 2.481 0 4.5-2.019 4.5-4.5 0-.242-.034-.475-.071-.706l.048-.011zM6.5 17C5.122 17 4 15.878 4 14.5S5.122 12 6.5 12 9 13.122 9 14.5 7.878 17 6.5 17zm11 0c-1.379 0-2.5-1.122-2.5-2.5s1.121-2.5 2.5-2.5 2.5 1.122 2.5 2.5-1.121 2.5-2.5 2.5z"
@@ -112,13 +112,13 @@ const ChevronRightIcon = `export const ChevronRightIcon = (props) => (
const IconWrapper = `import {cn} from "@nextui-org/react";
const IconWrapper = ({children, className}) => (
export const IconWrapper = ({children, className}) => (
<div className={cn(className, "flex items-center rounded-small justify-center w-7 h-7")}>
{children}
</div>
);`;
const ItemCounter = `const ItemCounter = ({number}) => (
const ItemCounter = `export const ItemCounter = ({number}) => (
<div className="flex items-center gap-1 text-default-400">
<span className="text-small">{number}</span>
<ChevronRightIcon className="text-xl" />
@@ -242,7 +242,7 @@ export default function App() {
endContent={<ItemCounter number={82} />}
startContent={
<IconWrapper className="bg-default/50 text-foreground">
<WatchersIcons />
<WatchersIcon />
</IconWrapper>
}
>
@@ -274,7 +274,7 @@ const react = {
"/LayoutIcon.jsx": LayoutIcon,
"/TagIcon.jsx": TagIcon,
"/UsersIcon.jsx": UsersIcon,
"/WatchersIcons.jsx": WatchersIcon,
"/WatchersIcon.jsx": WatchersIcon,
"/BookIcon.jsx": BookIcon,
"/ChevronRightIcon.jsx": ChevronRightIcon,
};
@@ -8,6 +8,7 @@ import icons from "./icons";
import description from "./description";
import sections from "./sections";
import customStyles from "./custom-styles";
import topContent from "./top-content";
export const listboxContent = {
usage,
@@ -20,4 +21,5 @@ export const listboxContent = {
description,
sections,
customStyles,
topContent,
};
@@ -0,0 +1,347 @@
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 ListboxWrapper = `export const ListboxWrapper = ({children}) => (
<div className="w-full max-w-[260px] border-small px-1 py-2 rounded-small border-default-200 dark:border-default-100">
{children}
</div>
);`;
const ListboxWrapperTs = `export const ListboxWrapper = ({children}: { children: React.ReactNode }) => (
<div className="w-full max-w-[260px] border-small px-1 py-2 rounded-small border-default-200 dark:border-default-100">
{children}
</div>
);`;
const App = `import {Listbox, ListboxItem, Chip, ScrollShadow, Avatar} from "@nextui-org/react";
import {ListboxWrapper} from "./ListboxWrapper";
import {users} from "./data";
export default function App() {
const [values, setValues] = React.useState(new Set(["1"]));
const arrayValues = Array.from(values);
const topContent = React.useMemo(() => {
if (!arrayValues.length) {
return null;
}
return (
<ScrollShadow
hideScrollBar
className="w-full flex py-0.5 px-2 gap-1"
orientation="horizontal"
>
{arrayValues.map((value) => (
<Chip key={value}>{users.find((user) => \`\${user.id}\` === \`\${value}\`).name}</Chip>
))}
</ScrollShadow>
);
}, [arrayValues.length]);
return (
<ListboxWrapper>
<Listbox
topContent={topContent}
classNames={{
base: "max-w-xs",
list: "max-h-[300px] overflow-scroll",
}}
defaultSelectedKeys={["1"]}
items={users}
label="Assigned to"
selectionMode="multiple"
onSelectionChange={setValues}
variant="flat"
>
{(item) => (
<ListboxItem 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>
</ListboxItem>
)}
</Listbox>
</ListboxWrapper>
);
}`;
const AppTs = `import {Listbox, ListboxItem, Chip, ScrollShadow, Avatar, Selection} from "@nextui-org/react";
import {ListboxWrapper} from "./ListboxWrapper";
import {users} from "./data";
export default function App() {
const [values, setValues] = React.useState<Selection>(new Set(["1"]));
const arrayValues = Array.from(values);
const topContent = React.useMemo(() => {
if (!arrayValues.length) {
return null;
}
return (
<ScrollShadow
hideScrollBar
className="w-full flex py-0.5 px-2 gap-1"
orientation="horizontal"
>
{arrayValues.map((value) => (
<Chip key={value}>{users.find((user) => \`\${user.id}\` === \`\${value}\`).name}</Chip>
))}
</ScrollShadow>
);
}, [arrayValues.length]);
return (
<ListboxWrapper>
<Listbox
topContent={topContent}
classNames={{
base: "max-w-xs",
list: "max-h-[300px] overflow-scroll",
}}
defaultSelectedKeys={["1"]}
items={users}
label="Assigned to"
selectionMode="multiple"
onSelectionChange={setValues}
variant="flat"
>
{(item) => (
<ListboxItem 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>
</ListboxItem>
)}
</Listbox>
</ListboxWrapper>
);
}`;
const react = {
"/App.jsx": App,
"/ListboxWrapper.jsx": ListboxWrapper,
"/data.js": data,
};
const reactTs = {
"/App.tsx": AppTs,
"/ListboxWrapper.tsx": ListboxWrapperTs,
"/data.ts": data,
};
export default {
...react,
...reactTs,
};
@@ -9,7 +9,7 @@ const AcmeLogo = `export const AcmeLogo = () => (
</svg>
);`;
const App = `import {Navbar, NavbarBrand, NavbarContent, NavbarItem, Link, Button} from "@nextui-org/react";
const App = `import {Navbar, NavbarBrand, NavbarMenuToggle, NavbarMenuItem, NavbarMenu, NavbarContent, NavbarItem, Link, Button} from "@nextui-org/react";
import {AcmeLogo} from "./AcmeLogo.jsx";
export default function App() {
@@ -52,6 +52,7 @@ import {ChevronIcon} from "./ChevronIcon";
export default function App() {
const renderItem = ({
ref,
key,
value,
isActive,
onNext,
@@ -61,7 +62,7 @@ export default function App() {
}: PaginationItemRenderProps<HTMLButtonElement>) => {
if (value === PaginationItemType.NEXT) {
return (
<button className={cn(className, "bg-default-200/50 min-w-8 w-8 h-8")} onClick={onNext}>
<button key={key} className={cn(className, "bg-default-200/50 min-w-8 w-8 h-8")} onClick={onNext}>
<ChevronIcon className="rotate-180" />
</button>
);
@@ -69,20 +70,21 @@ export default function App() {
if (value === PaginationItemType.PREV) {
return (
<button className={cn(className, "bg-default-200/50 min-w-8 w-8 h-8")} onClick={onPrevious}>
<button key={key} className={cn(className, "bg-default-200/50 min-w-8 w-8 h-8")} onClick={onPrevious}>
<ChevronIcon />
</button>
);
}
if (value === PaginationItemType.DOTS) {
return <button className={className}>...</button>;
return <button key={key} className={className}>...</button>;
}
// cursor is the default item
return (
<button
ref={ref}
key={key}
className={cn(
className,
isActive &&
@@ -115,6 +117,7 @@ import {ChevronIcon} from "./ChevronIcon";
export default function App() {
const renderItem = ({
ref,
key,
value,
isActive,
onNext,
@@ -124,7 +127,7 @@ export default function App() {
}) => {
if (value === PaginationItemType.NEXT) {
return (
<button className={cn(className, "bg-default-200/50 min-w-8 w-8 h-8")} onClick={onNext}>
<button key={key} className={cn(className, "bg-default-200/50 min-w-8 w-8 h-8")} onClick={onNext}>
<ChevronIcon className="rotate-180" />
</button>
);
@@ -132,19 +135,20 @@ export default function App() {
if (value === PaginationItemType.PREV) {
return (
<button className={cn(className, "bg-default-200/50 min-w-8 w-8 h-8")} onClick={onPrevious}>
<button key={key} className={cn(className, "bg-default-200/50 min-w-8 w-8 h-8")} onClick={onPrevious}>
<ChevronIcon />
</button>
);
}
if (value === PaginationItemType.DOTS) {
return <button className={className}>...</button>;
return <button key={key} className={className}>...</button>;
}
// cursor is the default item
return (
<button
key={key}
ref={ref}
className={cn(
className,
@@ -7,8 +7,15 @@ export default function App() {
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: [
// arrow color
"before:bg-default-200"
],
content: [
"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",
],
}}
>
<PopoverTrigger>
@@ -233,8 +233,8 @@ export default function App() {
}}
popoverProps={{
classNames: {
base: "p-0 border-small border-divider bg-background",
arrow: "bg-default-200",
base: "before:bg-default-200",
content: "p-0 border-small border-divider bg-background",
},
}}
renderValue={(items) => {
@@ -39,6 +39,7 @@ export default function App() {
label="Favorite Animal"
placeholder="Select an animal"
defaultSelectedKeys={["cat"]}
onOpenChange={(open) => open !== isOpen && setIsOpen(open)}
className="max-w-xs"
>
{animals.map((animal) => (
@@ -47,7 +48,7 @@ export default function App() {
</SelectItem>
))}
</Select>
<Button onPress={() => setIsOpen(!isOpen)}>
<Button aria-label="Open" aria-pressed={isOpen} onPress={() => setIsOpen(!isOpen)}>
{isOpen ? "Close" : "Open"}
</Button>
</div>
@@ -30,10 +30,10 @@ const App = `import {Select, SelectItem} from "@nextui-org/react";
import {animals} from "./data";
export default function App() {
const [value, setValue] = React.useState(new Set([]));
const [value, setValue] = React.useState("");
const handleSelectionChange = (e) => {
setValue(new Set([e.target.value]));
setValue(e.target.value);
};
return (
@@ -42,7 +42,7 @@ export default function App() {
label="Favorite Animal"
variant="bordered"
placeholder="Select an animal"
selectedKeys={value}
selectedKeys={[value]}
className="max-w-xs"
onChange={handleSelectionChange}
>
@@ -57,14 +57,14 @@ export default function App() {
);
}`;
const AppTs = `import {Select, SelectItem, Selection} from "@nextui-org/react";
const AppTs = `import {Select, SelectItem} from "@nextui-org/react";
import {animals} from "./data";
export default function App() {
const [value, setValue] = React.useState<Selection>(new Set([]));
const [value, setValue] = React.useState<string>("");
const handleSelectionChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
setValue(new Set([e.target.value]));
setValue(e.target.value);
};
return (
@@ -73,7 +73,7 @@ export default function App() {
label="Favorite Animal"
variant="bordered"
placeholder="Select an animal"
selectedKeys={value}
selectedKeys={[value]}
className="max-w-xs"
onChange={handleSelectionChange}
>
@@ -9,7 +9,7 @@ export default function App() {
return (
<div className="flex flex-col gap-3">
<Card className="w-[200px] space-y-5 p-4" radius="2xl">
<Card className="w-[200px] space-y-5 p-4" radius="lg">
<Skeleton isLoaded={isLoaded} className="rounded-lg">
<div className="h-24 rounded-lg bg-secondary"></div>
</Skeleton>
@@ -2,7 +2,7 @@ const App = `import {Card, Skeleton} from "@nextui-org/react";
export default function App() {
return (
<Card className="w-[200px] space-y-5 p-4" radius="2xl">
<Card className="w-[200px] space-y-5 p-4" radius="lg">
<Skeleton className="rounded-lg">
<div className="h-24 rounded-lg bg-default-300"></div>
</Skeleton>
@@ -0,0 +1,37 @@
const App = `import {Slider} from "@nextui-org/react";
export default function App() {
const colors = [
"foreground",
"primary",
"secondary",
"success",
"warning",
"danger",
];
return (
<div className="flex flex-col gap-6 w-full max-w-md">
{colors.map((color) => (
<Slider
key={color}
color={color}
step={0.01}
maxValue={1}
minValue={0}
defaultValue={0.7}
aria-label="Temperature"
className="max-w-md"
/>
))}
</div>
);
}`;
const react = {
"/App.jsx": App,
};
export default {
...react,
};
@@ -0,0 +1,51 @@
const App = `import {Slider} from "@nextui-org/react";
export default function App() {
const [value, setValue] = React.useState(25);
return (
<div className="flex flex-col gap-2 w-full h-full max-w-md items-start justify-center">
<Slider
aria-label="Volume"
size="lg"
color="secondary"
onChangeEnd={setValue}
className="max-w-md"
/>
<p className="text-default-500 font-medium text-small">Current volume: {value}</p>
</div>
);
}`;
const AppTs = `import {Slider, SliderValue} from "@nextui-org/react";
export default function App() {
const [value, setValue] = React.useState<SliderValue>(25);
return (
<div className="flex flex-col gap-2 w-full h-full max-w-md items-start justify-center">
<Slider
aria-label="Volume"
size="lg"
color="secondary"
defaultValue={70}
onChangeEnd={setValue}
className="max-w-md"
/>
<p className="text-default-500 font-medium text-small">Current volume: {value}</p>
</div>
);
}`;
const react = {
"/App.jsx": App,
};
const reactTs = {
"/App.tsx": AppTs,
};
export default {
...react,
...reactTs,
};
@@ -0,0 +1,60 @@
const App = `import {Slider} from "@nextui-org/react";
export default function App() {
const [value, setValue] = React.useState([100, 300]);
return (
<div className="flex flex-col gap-2 w-full h-full max-w-md items-start justify-center">
<Slider
label="Select a budget"
formatOptions={{style: "currency", currency: "USD"}}
step={10}
maxValue={1000}
minValue={0}
value={value}
onChange={setValue}
className="max-w-md"
/>
<p className="text-default-500 font-medium text-small">
Selected budget: {Array.isArray(value) && value.map((b) => \`$\${b}\`).join(" ")}
</p>
</div>
);
}`;
const AppTs = `import {Slider, SliderValue} from "@nextui-org/react";
export default function App() {
const [value, setValue] = React.useState<SliderValue>([100, 300]);
return (
<div className="flex flex-col gap-2 w-full h-full max-w-md items-start justify-center">
<Slider
label="Select a budget"
formatOptions={{style: "currency", currency: "USD"}}
step={10}
maxValue={1000}
minValue={0}
value={value}
onChange={setValue}
className="max-w-md"
/>
<p className="text-default-500 font-medium text-small">
Selected budget: {Array.isArray(value) && value.map((b) => \`$\${b}\`).join(" ")}
</p>
</div>
);
}`;
const react = {
"/App.jsx": App,
};
const reactTs = {
"/App.tsx": AppTs,
};
export default {
...react,
...reactTs,
};
@@ -0,0 +1,146 @@
const VolumeHighIcon = `export const VolumeHighIcon = (props) => (
<svg
aria-hidden="true"
fill="none"
focusable="false"
height="1em"
role="presentation"
viewBox="0 0 24 24"
width="1em"
{...props}
>
<path
d="M18.0003 16.7503C17.8403 16.7503 17.6903 16.7003 17.5503 16.6003C17.2203 16.3503 17.1503 15.8803 17.4003 15.5503C18.9703 13.4603 18.9703 10.5403 17.4003 8.45027C17.1503 8.12027 17.2203 7.65027 17.5503 7.40027C17.8803 7.15027 18.3503 7.22027 18.6003 7.55027C20.5603 10.1703 20.5603 13.8303 18.6003 16.4503C18.4503 16.6503 18.2303 16.7503 18.0003 16.7503Z"
fill="currentColor"
/>
<path
d="M19.8284 19.2503C19.6684 19.2503 19.5184 19.2003 19.3784 19.1003C19.0484 18.8503 18.9784 18.3803 19.2284 18.0503C21.8984 14.4903 21.8984 9.51027 19.2284 5.95027C18.9784 5.62027 19.0484 5.15027 19.3784 4.90027C19.7084 4.65027 20.1784 4.72027 20.4284 5.05027C23.4984 9.14027 23.4984 14.8603 20.4284 18.9503C20.2884 19.1503 20.0584 19.2503 19.8284 19.2503Z"
fill="currentColor"
/>
<path
d="M14.02 3.78168C12.9 3.16168 11.47 3.32168 10.01 4.23168L7.09 6.06168C6.89 6.18168 6.66 6.25168 6.43 6.25168H5.5H5C2.58 6.25168 1.25 7.58168 1.25 10.0017V14.0017C1.25 16.4217 2.58 17.7517 5 17.7517H5.5H6.43C6.66 17.7517 6.89 17.8217 7.09 17.9417L10.01 19.7717C10.89 20.3217 11.75 20.5917 12.55 20.5917C13.07 20.5917 13.57 20.4717 14.02 20.2217C15.13 19.6017 15.75 18.3117 15.75 16.5917V7.41168C15.75 5.69168 15.13 4.40168 14.02 3.78168Z"
fill="currentColor"
/>
</svg>
);`;
const VolumeLowIcon = `export const VolumeLowIcon = (props) => (
<svg
aria-hidden="true"
fill="none"
focusable="false"
height="1em"
role="presentation"
viewBox="0 0 24 24"
width="1em"
{...props}
>
<path
d="M19.3284 16.7503C19.1684 16.7503 19.0184 16.7003 18.8784 16.6003C18.5484 16.3503 18.4784 15.8803 18.7284 15.5503C20.2984 13.4603 20.2984 10.5403 18.7284 8.45027C18.4784 8.12027 18.5484 7.65027 18.8784 7.40027C19.2084 7.15027 19.6784 7.22027 19.9284 7.55027C21.8984 10.1703 21.8984 13.8303 19.9284 16.4503C19.7884 16.6503 19.5584 16.7503 19.3284 16.7503Z"
fill="currentColor"
/>
<path
d="M15.3481 3.78168C14.2281 3.16168 12.7981 3.32168 11.3381 4.23168L8.41813 6.06168C8.21813 6.18168 7.98813 6.25168 7.75813 6.25168H6.82812H6.32812C3.90812 6.25168 2.57812 7.58168 2.57812 10.0017V14.0017C2.57812 16.4217 3.90812 17.7517 6.32812 17.7517H6.82812H7.75813C7.98813 17.7517 8.21813 17.8217 8.41813 17.9417L11.3381 19.7717C12.2181 20.3217 13.0781 20.5917 13.8781 20.5917C14.3981 20.5917 14.8981 20.4717 15.3481 20.2217C16.4581 19.6017 17.0781 18.3117 17.0781 16.5917V7.41168C17.0781 5.69168 16.4581 4.40168 15.3481 3.78168Z"
fill="currentColor"
/>
</svg>
);`;
const App = `import {Slider, Button} from "@nextui-org/react";
import {VolumeLowIcon} from "./VolumeLowIcon";
import {VolumeHighIcon} from "./VolumeHighIcon";
export default function App() {
const [value, setValue] = React.useState(25);
return (
<div className="flex flex-col gap-2 w-full h-full max-w-md items-start justify-center">
<Slider
aria-label="Volume"
size="lg"
color="success"
value={value}
onChange={setValue}
startContent={
<Button
isIconOnly
radius="full"
variant="light"
onPress={() => setValue((prev) => prev >= 10 ? prev - 10 : 0)}
>
<VolumeLowIcon className="text-2xl" />
</Button>
}
endContent={
<Button
isIconOnly
radius="full"
variant="light"
onPress={() => setValue((prev) => prev <= 90 ? prev + 10 : 100)}
>
<VolumeHighIcon className="text-2xl" />
</Button>
}
className="max-w-md"
/>
<p className="text-default-500 font-medium text-small">Current volume: {value}</p>
</div>
);
}`;
const AppTs = `import {Slider, Button, SliderValue} from "@nextui-org/react";
import {VolumeLowIcon} from "./VolumeLowIcon";
import {VolumeHighIcon} from "./VolumeHighIcon";
export default function App() {
const [value, setValue] = React.useState<SliderValue>(25);
return (
<div className="flex flex-col gap-2 w-full h-full max-w-md items-start justify-center">
<Slider
aria-label="Volume"
size="lg"
color="success"
value={value}
onChange={setValue}
startContent={
<Button
isIconOnly
variant="light"
radius="full"
onPress={() => setValue((prev) => prev >= 10 ? prev - 10 : 0)}
>
<VolumeLowIcon className="text-2xl" />
</Button>
}
endContent={
<Button
isIconOnly
variant="light"
radius="full"
onPress={() => setValue((prev) => prev <= 90 ? prev + 10 : 100)}
>
<VolumeHighIcon className="text-2xl" />
</Button>
}
className="max-w-md"
/>
<p className="text-default-500 font-medium text-small">Current volume: {value}</p>
</div>
);
}`;
const react = {
"/App.jsx": App,
"/VolumeHighIcon.jsx": VolumeHighIcon,
"/VolumeLowIcon.jsx": VolumeLowIcon,
};
const reactTs = {
"/App.tsx": AppTs,
};
export default {
...react,
...reactTs,
};
@@ -0,0 +1,55 @@
const App = `import {Slider} from "@nextui-org/react";
export default function App() {
return (
<Slider
label="Price Range"
step={100}
maxValue={1000}
minValue={0}
defaultValue={[0, 800]}
showSteps={true}
showTooltip={true}
showOutline={true}
disableThumbScale={true}
formatOptions={{style: "currency", currency: "USD"}}
tooltipValueFormatOptions={{style: "currency", currency: "USD", maximumFractionDigits: 0}}
classNames={{
base: "max-w-md",
filler: "bg-gradient-to-r from-primary-500 to-secondary-400",
labelWrapper: "mb-2",
label: "font-medium text-default-700 text-medium",
value: "font-medium text-default-500 text-small",
thumb: [
"transition-size",
"bg-gradient-to-r from-secondary-400 to-primary-500",
"data-[dragging=true]:shadow-lg data-[dragging=true]:shadow-black/20",
"data-[dragging=true]:w-7 data-[dragging=true]:h-7 data-[dragging=true]:after:h-6 data-[dragging=true]:after:w-6"
],
step: "data-[in-range=true]:bg-black/30 dark:data-[in-range=true]:bg-white/50"
}}
tooltipProps={{
offset: 10,
placement: "bottom",
classNames: {
base: [
// arrow color
"before:bg-gradient-to-r before:from-secondary-400 before:to-primary-500",
],
content: [
"py-2 shadow-xl",
"text-white bg-gradient-to-r from-secondary-400 to-primary-500",
],
},
}}
/>
);
}`;
const react = {
"/App.jsx": App,
};
export default {
...react,
};
@@ -0,0 +1,49 @@
const App = `import {Slider} from "@nextui-org/react";
export default function App() {
return (
<div className="flex flex-col gap-6 w-full max-w-md">
<Slider
size="sm"
step={0.01}
maxValue={1}
minValue={0}
color="secondary"
disableThumbScale={true}
aria-label="Temperature"
defaultValue={0.2}
className="max-w-md"
/>
<Slider
size="md"
step={0.01}
maxValue={1}
minValue={0}
color="secondary"
disableThumbScale={true}
aria-label="Temperature"
defaultValue={0.4}
className="max-w-md"
/>
<Slider
size="lg"
step={0.01}
maxValue={1}
minValue={0}
color="secondary"
disableThumbScale={true}
aria-label="Temperature"
defaultValue={0.6}
className="max-w-md"
/>
</div>
);
}`;
const react = {
"/App.jsx": App,
};
export default {
...react,
};
@@ -0,0 +1,23 @@
const App = `import {Slider} from "@nextui-org/react";
export default function App() {
return (
<Slider
isDisabled
label="Temperature"
step={0.01}
maxValue={1}
minValue={0}
defaultValue={0.6}
className="max-w-md"
/>
);
}`;
const react = {
"/App.jsx": App,
};
export default {
...react,
};

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