mirror of
https://github.com/nextui-org/nextui.git
synced 2025-12-08 19:26:11 +00:00
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>
This commit is contained in:
parent
c3f762563b
commit
7abd68941a
5
.changeset/chatty-tools-invent.md
Normal file
5
.changeset/chatty-tools-invent.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@nextui-org/button": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
The button with only the icon now displays only the spinner during loading
|
||||||
@ -1,2 +0,0 @@
|
|||||||
---
|
|
||||||
---
|
|
||||||
11
.changeset/fifty-snails-glow.md
Normal file
11
.changeset/fifty-snails-glow.md
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
"@nextui-org/listbox": patch
|
||||||
|
"@nextui-org/tabs": patch
|
||||||
|
"@nextui-org/theme": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Styles Changes
|
||||||
|
|
||||||
|
- Spacing units changed to from `px` to `rem` this improves the mobile components sizes
|
||||||
|
- Tabs/Tab new prop added `shouldSelectOnPressUp` which is enabled by default `true`, this prop defines whether the tabs selection should occur on press up instead of press down.
|
||||||
|
- Chip font size changed to `text-tiny` on `sm` size.
|
||||||
46
.changeset/flat-wasps-hug.md
Normal file
46
.changeset/flat-wasps-hug.md
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
---
|
||||||
|
"@nextui-org/use-aria-accordion-item": patch
|
||||||
|
"@nextui-org/use-aria-modal-overlay": patch
|
||||||
|
"@nextui-org/use-aria-toggle-button": patch
|
||||||
|
"@nextui-org/use-aria-multiselect": patch
|
||||||
|
"@nextui-org/react-rsc-utils": patch
|
||||||
|
"@nextui-org/use-aria-accordion": patch
|
||||||
|
"@nextui-org/shared-icons": patch
|
||||||
|
"@nextui-org/pagination": patch
|
||||||
|
"@nextui-org/use-aria-button": patch
|
||||||
|
"@nextui-org/accordion": patch
|
||||||
|
"@nextui-org/use-disclosure": patch
|
||||||
|
"@nextui-org/aria-utils": patch
|
||||||
|
"@nextui-org/checkbox": patch
|
||||||
|
"@nextui-org/dropdown": patch
|
||||||
|
"@nextui-org/progress": patch
|
||||||
|
"@nextui-org/use-aria-link": patch
|
||||||
|
"@nextui-org/divider": patch
|
||||||
|
"@nextui-org/listbox": patch
|
||||||
|
"@nextui-org/popover": patch
|
||||||
|
"@nextui-org/snippet": patch
|
||||||
|
"@nextui-org/tooltip": patch
|
||||||
|
"@nextui-org/avatar": patch
|
||||||
|
"@nextui-org/button": patch
|
||||||
|
"@nextui-org/navbar": patch
|
||||||
|
"@nextui-org/select": patch
|
||||||
|
"@nextui-org/slider": patch
|
||||||
|
"@nextui-org/switch": patch
|
||||||
|
"@nextui-org/badge": patch
|
||||||
|
"@nextui-org/input": patch
|
||||||
|
"@nextui-org/modal": patch
|
||||||
|
"@nextui-org/radio": patch
|
||||||
|
"@nextui-org/table": patch
|
||||||
|
"@nextui-org/card": patch
|
||||||
|
"@nextui-org/chip": patch
|
||||||
|
"@nextui-org/link": patch
|
||||||
|
"@nextui-org/menu": patch
|
||||||
|
"@nextui-org/tabs": patch
|
||||||
|
"@nextui-org/user": patch
|
||||||
|
"@nextui-org/kbd": patch
|
||||||
|
"@nextui-org/system": patch
|
||||||
|
"@nextui-org/react": patch
|
||||||
|
"@nextui-org/theme": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
React Aria Client side router provider added to NextUI Provider, it allows users to pass the router they're using to customize how components items should navigate, this is supported by Listbox items, tabs items, dropdown items and table rows.
|
||||||
6
.changeset/four-actors-give.md
Normal file
6
.changeset/four-actors-give.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
"@nextui-org/theme": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
- New variable added to the theme layout `hoverOpacity`
|
||||||
|
- Hover opacity added to button
|
||||||
47
.changeset/four-trainers-move.md
Normal file
47
.changeset/four-trainers-move.md
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
---
|
||||||
|
"@nextui-org/use-aria-accordion-item": patch
|
||||||
|
"@nextui-org/use-aria-modal-overlay": patch
|
||||||
|
"@nextui-org/use-aria-toggle-button": patch
|
||||||
|
"@nextui-org/use-aria-multiselect": patch
|
||||||
|
"@nextui-org/react-rsc-utils": patch
|
||||||
|
"@nextui-org/use-aria-accordion": patch
|
||||||
|
"@nextui-org/breadcrumbs": patch
|
||||||
|
"@nextui-org/shared-icons": patch
|
||||||
|
"@nextui-org/pagination": patch
|
||||||
|
"@nextui-org/use-aria-button": patch
|
||||||
|
"@nextui-org/accordion": patch
|
||||||
|
"@nextui-org/use-disclosure": patch
|
||||||
|
"@nextui-org/aria-utils": patch
|
||||||
|
"@nextui-org/checkbox": patch
|
||||||
|
"@nextui-org/dropdown": patch
|
||||||
|
"@nextui-org/progress": patch
|
||||||
|
"@nextui-org/use-aria-link": patch
|
||||||
|
"@nextui-org/divider": patch
|
||||||
|
"@nextui-org/listbox": patch
|
||||||
|
"@nextui-org/popover": patch
|
||||||
|
"@nextui-org/snippet": patch
|
||||||
|
"@nextui-org/tooltip": patch
|
||||||
|
"@nextui-org/avatar": patch
|
||||||
|
"@nextui-org/button": patch
|
||||||
|
"@nextui-org/navbar": patch
|
||||||
|
"@nextui-org/select": patch
|
||||||
|
"@nextui-org/slider": patch
|
||||||
|
"@nextui-org/switch": patch
|
||||||
|
"@nextui-org/badge": patch
|
||||||
|
"@nextui-org/input": patch
|
||||||
|
"@nextui-org/modal": patch
|
||||||
|
"@nextui-org/radio": patch
|
||||||
|
"@nextui-org/table": patch
|
||||||
|
"@nextui-org/card": patch
|
||||||
|
"@nextui-org/chip": patch
|
||||||
|
"@nextui-org/link": patch
|
||||||
|
"@nextui-org/menu": patch
|
||||||
|
"@nextui-org/tabs": patch
|
||||||
|
"@nextui-org/user": patch
|
||||||
|
"@nextui-org/kbd": patch
|
||||||
|
"@nextui-org/system": patch
|
||||||
|
"@nextui-org/react": patch
|
||||||
|
"@nextui-org/theme": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
New component: Breadcrumbs
|
||||||
53
.changeset/fresh-dolphins-pay.md
Normal file
53
.changeset/fresh-dolphins-pay.md
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
---
|
||||||
|
"@nextui-org/use-aria-accordion-item": patch
|
||||||
|
"@nextui-org/use-aria-modal-overlay": patch
|
||||||
|
"@nextui-org/use-aria-toggle-button": patch
|
||||||
|
"@nextui-org/framer-transitions": patch
|
||||||
|
"@nextui-org/use-aria-multiselect": patch
|
||||||
|
"@nextui-org/react-rsc-utils": patch
|
||||||
|
"@nextui-org/use-aria-accordion": patch
|
||||||
|
"@nextui-org/autocomplete": patch
|
||||||
|
"@nextui-org/breadcrumbs": patch
|
||||||
|
"@nextui-org/shared-icons": patch
|
||||||
|
"@nextui-org/pagination": patch
|
||||||
|
"@nextui-org/use-aria-button": patch
|
||||||
|
"@nextui-org/accordion": patch
|
||||||
|
"@nextui-org/use-aria-press": patch
|
||||||
|
"@nextui-org/use-disclosure": patch
|
||||||
|
"@nextui-org/aria-utils": patch
|
||||||
|
"@nextui-org/test-utils": patch
|
||||||
|
"@nextui-org/checkbox": patch
|
||||||
|
"@nextui-org/dropdown": patch
|
||||||
|
"@nextui-org/progress": patch
|
||||||
|
"@nextui-org/use-aria-link": patch
|
||||||
|
"@nextui-org/divider": patch
|
||||||
|
"@nextui-org/listbox": patch
|
||||||
|
"@nextui-org/popover": patch
|
||||||
|
"@nextui-org/snippet": patch
|
||||||
|
"@nextui-org/tooltip": patch
|
||||||
|
"@nextui-org/avatar": patch
|
||||||
|
"@nextui-org/button": patch
|
||||||
|
"@nextui-org/navbar": patch
|
||||||
|
"@nextui-org/ripple": patch
|
||||||
|
"@nextui-org/select": patch
|
||||||
|
"@nextui-org/slider": patch
|
||||||
|
"@nextui-org/switch": patch
|
||||||
|
"@nextui-org/badge": patch
|
||||||
|
"@nextui-org/input": patch
|
||||||
|
"@nextui-org/modal": patch
|
||||||
|
"@nextui-org/radio": patch
|
||||||
|
"@nextui-org/table": patch
|
||||||
|
"@nextui-org/card": patch
|
||||||
|
"@nextui-org/chip": patch
|
||||||
|
"@nextui-org/link": patch
|
||||||
|
"@nextui-org/menu": patch
|
||||||
|
"@nextui-org/tabs": patch
|
||||||
|
"@nextui-org/user": patch
|
||||||
|
"@nextui-org/system-rsc": patch
|
||||||
|
"@nextui-org/kbd": patch
|
||||||
|
"@nextui-org/system": patch
|
||||||
|
"@nextui-org/react": patch
|
||||||
|
"@nextui-org/theme": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
react-aria packages & framer-motion upgraded
|
||||||
61
.changeset/gentle-maps-lick.md
Normal file
61
.changeset/gentle-maps-lick.md
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
---
|
||||||
|
"@nextui-org/use-data-scroll-overflow": patch
|
||||||
|
"@nextui-org/use-aria-accordion-item": patch
|
||||||
|
"@nextui-org/use-aria-modal-overlay": patch
|
||||||
|
"@nextui-org/use-aria-toggle-button": patch
|
||||||
|
"@nextui-org/framer-transitions": patch
|
||||||
|
"@nextui-org/use-aria-multiselect": patch
|
||||||
|
"@nextui-org/react-rsc-utils": patch
|
||||||
|
"@nextui-org/scroll-shadow": patch
|
||||||
|
"@nextui-org/use-aria-accordion": patch
|
||||||
|
"@nextui-org/autocomplete": patch
|
||||||
|
"@nextui-org/stories-utils": patch
|
||||||
|
"@nextui-org/breadcrumbs": patch
|
||||||
|
"@nextui-org/shared-icons": patch
|
||||||
|
"@nextui-org/pagination": patch
|
||||||
|
"@nextui-org/use-aria-button": patch
|
||||||
|
"@nextui-org/accordion": patch
|
||||||
|
"@nextui-org/use-aria-press": patch
|
||||||
|
"@nextui-org/use-disclosure": patch
|
||||||
|
"@nextui-org/aria-utils": patch
|
||||||
|
"@nextui-org/test-utils": patch
|
||||||
|
"@nextui-org/checkbox": patch
|
||||||
|
"@nextui-org/dropdown": patch
|
||||||
|
"@nextui-org/progress": patch
|
||||||
|
"@nextui-org/skeleton": patch
|
||||||
|
"@nextui-org/use-aria-link": patch
|
||||||
|
"@nextui-org/divider": patch
|
||||||
|
"@nextui-org/listbox": patch
|
||||||
|
"@nextui-org/popover": patch
|
||||||
|
"@nextui-org/snippet": patch
|
||||||
|
"@nextui-org/spinner": patch
|
||||||
|
"@nextui-org/tooltip": patch
|
||||||
|
"@nextui-org/avatar": patch
|
||||||
|
"@nextui-org/button": patch
|
||||||
|
"@nextui-org/navbar": patch
|
||||||
|
"@nextui-org/ripple": patch
|
||||||
|
"@nextui-org/select": patch
|
||||||
|
"@nextui-org/slider": patch
|
||||||
|
"@nextui-org/spacer": patch
|
||||||
|
"@nextui-org/switch": patch
|
||||||
|
"@nextui-org/badge": patch
|
||||||
|
"@nextui-org/image": patch
|
||||||
|
"@nextui-org/input": patch
|
||||||
|
"@nextui-org/modal": patch
|
||||||
|
"@nextui-org/radio": patch
|
||||||
|
"@nextui-org/table": patch
|
||||||
|
"@nextui-org/card": patch
|
||||||
|
"@nextui-org/chip": patch
|
||||||
|
"@nextui-org/code": patch
|
||||||
|
"@nextui-org/link": patch
|
||||||
|
"@nextui-org/menu": patch
|
||||||
|
"@nextui-org/tabs": patch
|
||||||
|
"@nextui-org/user": patch
|
||||||
|
"@nextui-org/system-rsc": patch
|
||||||
|
"@nextui-org/kbd": patch
|
||||||
|
"@nextui-org/system": patch
|
||||||
|
"@nextui-org/react": patch
|
||||||
|
"@nextui-org/theme": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Peer dependencies fixed to not install depedencies that were already installed
|
||||||
5
.changeset/healthy-cobras-crash.md
Normal file
5
.changeset/healthy-cobras-crash.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@nextui-org/theme": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
feat: added RTL support to accordion component
|
||||||
147
.changeset/hip-years-sip.md
Normal file
147
.changeset/hip-years-sip.md
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
---
|
||||||
|
"@nextui-org/shared-icons": patch
|
||||||
|
"@nextui-org/popover": patch
|
||||||
|
"@nextui-org/tooltip": patch
|
||||||
|
"@nextui-org/select": patch
|
||||||
|
"@nextui-org/slider": patch
|
||||||
|
"@nextui-org/badge": patch
|
||||||
|
"@nextui-org/theme": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Changes
|
||||||
|
|
||||||
|
- Slider tooltip support added
|
||||||
|
|
||||||
|
Breaking Changes
|
||||||
|
|
||||||
|
- Popover API changed to improve the arrow implementation, arrow is now a pseudo element, this allows the popover to also move the arrow all-together, this change impacts the Popover, Tooltip and Select implementations.
|
||||||
|
|
||||||
|
Popover changes:
|
||||||
|
|
||||||
|
```diff
|
||||||
|
<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",
|
||||||
|
+ base: [
|
||||||
|
+ // the "before" pseudo element is now the popover' arrow
|
||||||
|
+ "before:bg-default-200"
|
||||||
|
+ ],
|
||||||
|
- arrow: "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",
|
||||||
|
],
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<PopoverTrigger>
|
||||||
|
<Button>Open Popover</Button>
|
||||||
|
</PopoverTrigger>
|
||||||
|
<PopoverContent>
|
||||||
|
{(titleProps) => (
|
||||||
|
<div className="px-1 py-2">
|
||||||
|
<h3 className="text-small font-bold" {...titleProps}>
|
||||||
|
Popover Content
|
||||||
|
</h3>
|
||||||
|
<div className="text-tiny">This is the popover content</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
|
```
|
||||||
|
|
||||||
|
Tooltip changes:
|
||||||
|
|
||||||
|
```diff
|
||||||
|
<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
|
||||||
|
<Select
|
||||||
|
items={users}
|
||||||
|
label="Assigned to"
|
||||||
|
className="max-w-xs"
|
||||||
|
variant="bordered"
|
||||||
|
classNames={{
|
||||||
|
label: "group-data-[filled=true]:-translate-y-5",
|
||||||
|
trigger: "min-h-unit-16",
|
||||||
|
listboxWrapper: "max-h-[400px]",
|
||||||
|
}}
|
||||||
|
listboxProps={{
|
||||||
|
itemClasses: {
|
||||||
|
base: [
|
||||||
|
"rounded-md",
|
||||||
|
"text-default-500",
|
||||||
|
"transition-opacity",
|
||||||
|
"data-[hover=true]:text-foreground",
|
||||||
|
"data-[hover=true]:bg-default-100",
|
||||||
|
"dark:data-[hover=true]:bg-default-50",
|
||||||
|
"data-[selectable=true]:focus:bg-default-50",
|
||||||
|
"data-[pressed=true]:opacity-70",
|
||||||
|
"data-[focus-visible=true]:ring-default-500",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
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
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
renderValue={(items) => {
|
||||||
|
return items.map((item) => (
|
||||||
|
<div key={item.key} className="flex items-center gap-2">
|
||||||
|
<Avatar
|
||||||
|
alt={item.data.name}
|
||||||
|
className="flex-shrink-0"
|
||||||
|
size="sm"
|
||||||
|
src={item.data.avatar}
|
||||||
|
/>
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<span>{item.data.name}</span>
|
||||||
|
<span className="text-default-500 text-tiny">({item.data.email})</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
));
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{(user) => (
|
||||||
|
<SelectItem 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>
|
||||||
|
</SelectItem>
|
||||||
|
)}
|
||||||
|
</Select>
|
||||||
|
);
|
||||||
|
}`;
|
||||||
|
```
|
||||||
7
.changeset/odd-impalas-swim.md
Normal file
7
.changeset/odd-impalas-swim.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
"@nextui-org/use-data-scroll-overflow": patch
|
||||||
|
"@nextui-org/scroll-shadow": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
- use-data-scroll-shadow hook logic improved
|
||||||
|
- controlled way to set the shadow visibility added to ScrollShadow
|
||||||
5
.changeset/orange-bobcats-kneel.md
Normal file
5
.changeset/orange-bobcats-kneel.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@nextui-org/theme": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
feat: added RTL support to button group component
|
||||||
5
.changeset/seven-buses-cry.md
Normal file
5
.changeset/seven-buses-cry.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@nextui-org/theme": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Transition animation added to Menu/Listbox items
|
||||||
9
.changeset/shy-camels-press.md
Normal file
9
.changeset/shy-camels-press.md
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
"@nextui-org/react-rsc-utils": patch
|
||||||
|
"@nextui-org/breadcrumbs": patch
|
||||||
|
"@nextui-org/shared-icons": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
- pickChildren function return type fixed
|
||||||
|
- new icon added to the shared icons
|
||||||
|
- breadcrumbs improvements
|
||||||
7
.changeset/shy-pans-juggle.md
Normal file
7
.changeset/shy-pans-juggle.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
"@nextui-org/input": patch
|
||||||
|
"@nextui-org/theme": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
- Textarea styles fixed
|
||||||
|
- New prop added to text area `disableAutosize` to preventthe resize
|
||||||
16
.changeset/stupid-experts-jam.md
Normal file
16
.changeset/stupid-experts-jam.md
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
"@nextui-org/react-rsc-utils": patch
|
||||||
|
"@nextui-org/shared-icons": patch
|
||||||
|
"@nextui-org/dropdown": patch
|
||||||
|
"@nextui-org/popover": patch
|
||||||
|
"@nextui-org/snippet": patch
|
||||||
|
"@nextui-org/tooltip": patch
|
||||||
|
"@nextui-org/select": patch
|
||||||
|
"@nextui-org/slider": patch
|
||||||
|
"@nextui-org/badge": patch
|
||||||
|
"@nextui-org/react": patch
|
||||||
|
"@nextui-org/theme": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
- New component: Slider
|
||||||
|
- Arrow removed from the popover styles and code as well as from related components such as Tooltip, Snippet and Select
|
||||||
6
.changeset/tender-penguins-love.md
Normal file
6
.changeset/tender-penguins-love.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
"@nextui-org/avatar": patch
|
||||||
|
"@nextui-org/theme": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
feat: added RTL support to avatar and avatar group component
|
||||||
10
.changeset/wise-apples-travel.md
Normal file
10
.changeset/wise-apples-travel.md
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
"@nextui-org/listbox": patch
|
||||||
|
"@nextui-org/table": patch
|
||||||
|
"@nextui-org/menu": patch
|
||||||
|
"@nextui-org/tabs": patch
|
||||||
|
"@nextui-org/system-rsc": patch
|
||||||
|
"@nextui-org/theme": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Collection-based components support on extendVariants function added, input focus-visible outline removed, collection item components "as" prop fixed
|
||||||
47
apps/docs/app/examples/autocomplete/async-filtering/page.tsx
Normal file
47
apps/docs/app/examples/autocomplete/async-filtering/page.tsx
Normal file
@ -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>
|
||||||
|
);
|
||||||
|
}
|
||||||
113
apps/docs/app/examples/autocomplete/async-items-loading/page.tsx
Normal file
113
apps/docs/app/examples/autocomplete/async-items-loading/page.tsx
Normal file
@ -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>
|
||||||
|
);
|
||||||
|
}
|
||||||
107
apps/docs/app/examples/autocomplete/fully-controlled/page.tsx
Normal file
107
apps/docs/app/examples/autocomplete/fully-controlled/page.tsx
Normal file
@ -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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -9,10 +9,17 @@ import {
|
|||||||
Textarea,
|
Textarea,
|
||||||
Input,
|
Input,
|
||||||
Tab,
|
Tab,
|
||||||
|
Avatar,
|
||||||
|
Select,
|
||||||
|
SelectItem,
|
||||||
AccordionItem,
|
AccordionItem,
|
||||||
|
Pagination,
|
||||||
extendVariants,
|
extendVariants,
|
||||||
|
PaginationItem,
|
||||||
} from "@nextui-org/react";
|
} 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";
|
import {SearchLinearIcon} from "@/components/icons";
|
||||||
|
|
||||||
@ -178,13 +185,297 @@ const MyButton2 = extendVariants(Button, {
|
|||||||
defaultVariants: {},
|
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() {
|
export default function NextUIPerf() {
|
||||||
const [textA, setTextA] = useState<string>("");
|
const [textA, setTextA] = useState<string>("");
|
||||||
const [textB, setTextB] = useState<string>("");
|
const [textB, setTextB] = useState<string>("");
|
||||||
const [textC, setTextC] = 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 (
|
return (
|
||||||
<div className="w-full p-24 gap-4 flex flex-col">
|
<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>
|
<Accordion>
|
||||||
<AccordionItem key="1" aria-label="Accordion 1" title="Accordion 1">
|
<AccordionItem key="1" aria-label="Accordion 1" title="Accordion 1">
|
||||||
Non est aliqua tempor occaecat laborum. Lorem culpa minim irure mollit. Est qui
|
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>
|
<Button>Click Me!</Button>
|
||||||
|
|
||||||
<MyButton2 color="foreground">Press Me!</MyButton2>
|
<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>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import * as React from "react";
|
|||||||
import {NextUIProvider} from "@nextui-org/react";
|
import {NextUIProvider} from "@nextui-org/react";
|
||||||
import {ThemeProvider as NextThemesProvider} from "next-themes";
|
import {ThemeProvider as NextThemesProvider} from "next-themes";
|
||||||
import {ThemeProviderProps} from "next-themes/dist/types";
|
import {ThemeProviderProps} from "next-themes/dist/types";
|
||||||
|
import {useRouter} from "next/navigation";
|
||||||
|
|
||||||
export interface ProvidersProps {
|
export interface ProvidersProps {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
@ -11,8 +12,10 @@ export interface ProvidersProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function Providers({children, themeProps}: ProvidersProps) {
|
export function Providers({children, themeProps}: ProvidersProps) {
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NextUIProvider>
|
<NextUIProvider navigate={router.push}>
|
||||||
<NextThemesProvider {...themeProps}>{children}</NextThemesProvider>
|
<NextThemesProvider {...themeProps}>{children}</NextThemesProvider>
|
||||||
</NextUIProvider>
|
</NextUIProvider>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"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 {useState, FC} from "react";
|
||||||
import {clsx} from "@nextui-org/shared-utils";
|
import {clsx} from "@nextui-org/shared-utils";
|
||||||
import NextImage from "next/image";
|
import NextImage from "next/image";
|
||||||
@ -63,15 +63,15 @@ export const MusicPlayer: FC<MusicPlayerProps> = ({className, ...otherProps}) =>
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-col mt-3 gap-1">
|
<div className="flex flex-col mt-3 gap-1">
|
||||||
<Progress
|
<Slider
|
||||||
aria-label="Music progress"
|
aria-label="Music progress"
|
||||||
classNames={{
|
classNames={{
|
||||||
indicator: "bg-default-800 dark:bg-white",
|
|
||||||
track: "bg-default-500/30",
|
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"
|
size="sm"
|
||||||
value={33}
|
|
||||||
/>
|
/>
|
||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
<p className="text-sm">1:23</p>
|
<p className="text-sm">1:23</p>
|
||||||
|
|||||||
@ -32,7 +32,6 @@ interface CodeDemoProps extends UseCodeDemoProps, WindowResizerProps {
|
|||||||
showSandpackPreview?: boolean;
|
showSandpackPreview?: boolean;
|
||||||
initialEditorOpen?: boolean;
|
initialEditorOpen?: boolean;
|
||||||
enableResize?: boolean;
|
enableResize?: boolean;
|
||||||
showTabs?: boolean;
|
|
||||||
showPreview?: boolean;
|
showPreview?: boolean;
|
||||||
hideWindowActions?: boolean;
|
hideWindowActions?: boolean;
|
||||||
showOpenInCodeSandbox?: boolean;
|
showOpenInCodeSandbox?: boolean;
|
||||||
@ -54,6 +53,7 @@ export const CodeDemo: React.FC<CodeDemoProps> = ({
|
|||||||
showEditor = true,
|
showEditor = true,
|
||||||
showPreview = true,
|
showPreview = true,
|
||||||
asIframe = false,
|
asIframe = false,
|
||||||
|
showTabs = true,
|
||||||
resizeEnabled = true,
|
resizeEnabled = true,
|
||||||
hideWindowActions = false,
|
hideWindowActions = false,
|
||||||
showSandpackPreview = false,
|
showSandpackPreview = false,
|
||||||
@ -66,7 +66,6 @@ export const CodeDemo: React.FC<CodeDemoProps> = ({
|
|||||||
previewHeight = "auto",
|
previewHeight = "auto",
|
||||||
overflow = "visible",
|
overflow = "visible",
|
||||||
displayMode = "always",
|
displayMode = "always",
|
||||||
showTabs = true,
|
|
||||||
gradientColor,
|
gradientColor,
|
||||||
highlightedLines,
|
highlightedLines,
|
||||||
iframeInitialWidth,
|
iframeInitialWidth,
|
||||||
|
|||||||
@ -70,6 +70,7 @@ function TreeItem<T>(props: TreeItemProps<T>) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const isNew = item.props?.newPost;
|
const isNew = item.props?.newPost;
|
||||||
|
const isUpdated = item.props?.updated;
|
||||||
|
|
||||||
const isExpanded = state.expandedKeys.has(key);
|
const isExpanded = state.expandedKeys.has(key);
|
||||||
const isSelected =
|
const isSelected =
|
||||||
@ -159,6 +160,16 @@ function TreeItem<T>(props: TreeItemProps<T>) {
|
|||||||
>
|
>
|
||||||
{rendered}
|
{rendered}
|
||||||
</span>
|
</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 && (
|
{isNew && (
|
||||||
<Chip className="ml-1 py-1 text-tiny" color="primary" size="sm" variant="flat">
|
<Chip className="ml-1 py-1 text-tiny" color="primary" size="sm" variant="flat">
|
||||||
New
|
New
|
||||||
|
|||||||
@ -229,7 +229,7 @@ export const MDXComponents = {
|
|||||||
),
|
),
|
||||||
Steps: ({...props}) => (
|
Steps: ({...props}) => (
|
||||||
<div
|
<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}
|
{...props}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
|
|||||||
@ -249,11 +249,11 @@ export const Navbar: FC<NavbarProps> = ({children, routes, mobileRoutes = [], sl
|
|||||||
color="secondary"
|
color="secondary"
|
||||||
href="/blog/v2.1.0"
|
href="/blog/v2.1.0"
|
||||||
variant="dot"
|
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
|
Introducing v2.2.0
|
||||||
<span aria-label="party emoji" role="img">
|
<span aria-label="rocket emoji" role="img">
|
||||||
🎉
|
🚀
|
||||||
</span>
|
</span>
|
||||||
</Chip>
|
</Chip>
|
||||||
</NavbarItem>
|
</NavbarItem>
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import {Language} from "prism-react-renderer";
|
|||||||
import {HighlightedLines} from "./types";
|
import {HighlightedLines} from "./types";
|
||||||
import {Decorators} from "./types";
|
import {Decorators} from "./types";
|
||||||
|
|
||||||
|
import {trackEvent} from "@/utils/va";
|
||||||
import {Codeblock} from "@/components/docs/components";
|
import {Codeblock} from "@/components/docs/components";
|
||||||
|
|
||||||
export interface CodeViewerProps {
|
export interface CodeViewerProps {
|
||||||
@ -83,6 +84,13 @@ export const SandpackCodeViewer = React.forwardRef<any, CodeViewerProps>(
|
|||||||
const handleExpand = () => {
|
const handleExpand = () => {
|
||||||
const nextIsExpanded = !isExpanded;
|
const nextIsExpanded = !isExpanded;
|
||||||
|
|
||||||
|
trackEvent("CodeViewer - Expand", {
|
||||||
|
name: activeFile,
|
||||||
|
action: "expand",
|
||||||
|
category: "docs",
|
||||||
|
data: nextIsExpanded ? "expanded" : "collapsed",
|
||||||
|
});
|
||||||
|
|
||||||
setIsExpanded(nextIsExpanded);
|
setIsExpanded(nextIsExpanded);
|
||||||
if (containerRef && containerRef?.current !== null) {
|
if (containerRef && containerRef?.current !== null) {
|
||||||
const container = containerRef?.current;
|
const container = containerRef?.current;
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
export const getFileEntry = (theme: string) => `
|
export const rootFile = `
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import ReactDOM from "react-dom/client";
|
import ReactDOM from "react-dom/client";
|
||||||
import { NextUIProvider } from "@nextui-org/react";
|
import { NextUIProvider } from "@nextui-org/react";
|
||||||
@ -8,13 +8,26 @@ import "./styles.css";
|
|||||||
ReactDOM.createRoot(document.getElementById("root")).render(
|
ReactDOM.createRoot(document.getElementById("root")).render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<NextUIProvider>
|
<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 />
|
<App />
|
||||||
</div>
|
</div>
|
||||||
</NextUIProvider>
|
</NextUIProvider>
|
||||||
</React.StrictMode>
|
</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");
|
export const tailwindConfig = `const { nextui } = require("@nextui-org/react");
|
||||||
|
|
||||||
/** @type {import('tailwindcss').Config} */
|
/** @type {import('tailwindcss').Config} */
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import {useTheme} from "next-themes";
|
|||||||
|
|
||||||
import {HighlightedLines} from "./types";
|
import {HighlightedLines} from "./types";
|
||||||
import {getHighlightedLines, getFileName} from "./utils";
|
import {getHighlightedLines, getFileName} from "./utils";
|
||||||
import {getFileEntry, stylesConfig, postcssConfig, tailwindConfig} from "./entries";
|
import {stylesConfig, postcssConfig, tailwindConfig, getHtmlFile, rootFile} from "./entries";
|
||||||
|
|
||||||
import {useLocalStorage} from "@/hooks/use-local-storage";
|
import {useLocalStorage} from "@/hooks/use-local-storage";
|
||||||
|
|
||||||
@ -185,7 +185,11 @@ export const useSandpack = ({
|
|||||||
files: {
|
files: {
|
||||||
...sortedFiles,
|
...sortedFiles,
|
||||||
[entryFile]: {
|
[entryFile]: {
|
||||||
code: getFileEntry(theme ?? "light"),
|
code: rootFile,
|
||||||
|
hidden: true,
|
||||||
|
},
|
||||||
|
"index.html": {
|
||||||
|
code: getHtmlFile(theme ?? "light", entryFile),
|
||||||
hidden: true,
|
hidden: true,
|
||||||
},
|
},
|
||||||
"tailwind.config.js": {
|
"tailwind.config.js": {
|
||||||
|
|||||||
@ -24,6 +24,13 @@
|
|||||||
"keywords": "design principles, nextui",
|
"keywords": "design principles, nextui",
|
||||||
"path": "/docs/guide/design-principles.mdx"
|
"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",
|
"key": "upgrade-to-v2",
|
||||||
"title": "Upgrade to v2",
|
"title": "Upgrade to v2",
|
||||||
@ -130,6 +137,13 @@
|
|||||||
"keywords": "accordion, collapse, expandable sections, content hiding",
|
"keywords": "accordion, collapse, expandable sections, content hiding",
|
||||||
"path": "/docs/components/accordion.mdx"
|
"path": "/docs/components/accordion.mdx"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"key": "autocomplete",
|
||||||
|
"title": "Autocomplete",
|
||||||
|
"keywords": "autocomplete, auto suggest, search, typeahead",
|
||||||
|
"path": "/docs/components/autocomplete.mdx",
|
||||||
|
"newPost": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"key": "badge",
|
"key": "badge",
|
||||||
"title": "Badge",
|
"title": "Badge",
|
||||||
@ -142,6 +156,13 @@
|
|||||||
"keywords": "button, interactive, action trigger, click events",
|
"keywords": "button, interactive, action trigger, click events",
|
||||||
"path": "/docs/components/button.mdx"
|
"path": "/docs/components/button.mdx"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"key": "breadcrumbs",
|
||||||
|
"title": "Breadcrumbs",
|
||||||
|
"keywords": "breadcrumbs, navigation, path, trail, location",
|
||||||
|
"path": "/docs/components/breadcrumbs.mdx",
|
||||||
|
"newPost": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"key": "card",
|
"key": "card",
|
||||||
"title": "Card",
|
"title": "Card",
|
||||||
@ -188,7 +209,8 @@
|
|||||||
"key": "dropdown",
|
"key": "dropdown",
|
||||||
"title": "Dropdown",
|
"title": "Dropdown",
|
||||||
"keywords": "dropdown, menu, selection, option list",
|
"keywords": "dropdown, menu, selection, option list",
|
||||||
"path": "/docs/components/dropdown.mdx"
|
"path": "/docs/components/dropdown.mdx",
|
||||||
|
"updated": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "image",
|
"key": "image",
|
||||||
@ -212,14 +234,15 @@
|
|||||||
"key": "link",
|
"key": "link",
|
||||||
"title": "Link",
|
"title": "Link",
|
||||||
"keywords": "link, navigation, href, web page connection",
|
"keywords": "link, navigation, href, web page connection",
|
||||||
"path": "/docs/components/link.mdx"
|
"path": "/docs/components/link.mdx",
|
||||||
|
"updated": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "listbox",
|
"key": "listbox",
|
||||||
"title": "Listbox",
|
"title": "Listbox",
|
||||||
"keywords": "listbox, selection, option list, multiple choice",
|
"keywords": "listbox, selection, option list, multiple choice",
|
||||||
"path": "/docs/components/listbox.mdx",
|
"path": "/docs/components/listbox.mdx",
|
||||||
"newPost": true
|
"updated": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "modal",
|
"key": "modal",
|
||||||
@ -261,8 +284,7 @@
|
|||||||
"key": "select",
|
"key": "select",
|
||||||
"title": "Select",
|
"title": "Select",
|
||||||
"keywords": "select, selection, option list, multiple choice",
|
"keywords": "select, selection, option list, multiple choice",
|
||||||
"path": "/docs/components/select.mdx",
|
"path": "/docs/components/select.mdx"
|
||||||
"newPost": true
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "skeleton",
|
"key": "skeleton",
|
||||||
@ -280,8 +302,7 @@
|
|||||||
"key": "scroll-shadow",
|
"key": "scroll-shadow",
|
||||||
"title": "Scroll Shadow",
|
"title": "Scroll Shadow",
|
||||||
"keywords": "scroll shadow, scroll indicator, scroll bar, scroll position",
|
"keywords": "scroll shadow, scroll indicator, scroll bar, scroll position",
|
||||||
"path": "/docs/components/scroll-shadow.mdx",
|
"path": "/docs/components/scroll-shadow.mdx"
|
||||||
"newPost": true
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "spacer",
|
"key": "spacer",
|
||||||
@ -301,6 +322,13 @@
|
|||||||
"keywords": "switch, toggle, binary input, on/off control",
|
"keywords": "switch, toggle, binary input, on/off control",
|
||||||
"path": "/docs/components/switch.mdx"
|
"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",
|
"key": "table",
|
||||||
"title": "Table",
|
"title": "Table",
|
||||||
@ -311,13 +339,15 @@
|
|||||||
"key": "tabs",
|
"key": "tabs",
|
||||||
"title": "Tabs",
|
"title": "Tabs",
|
||||||
"keywords": "tabs, section navigation, categorized content, tabbed interface",
|
"keywords": "tabs, section navigation, categorized content, tabbed interface",
|
||||||
"path": "/docs/components/tabs.mdx"
|
"path": "/docs/components/tabs.mdx",
|
||||||
|
"updated": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "textarea",
|
"key": "textarea",
|
||||||
"title": "Textarea",
|
"title": "Textarea",
|
||||||
"keywords": "textarea, multi-line text input, large text field, form control",
|
"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",
|
"key": "tooltip",
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
167
apps/docs/content/blog/v2.2.0.mdx
Normal file
167
apps/docs/content/blog/v2.2.0.mdx
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
---
|
||||||
|
title: "Introducing v2.2.0 🚀"
|
||||||
|
description: "NextUI v2.2.0 is here with Client side router support, 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 {selectContent} from "@/content/components/select";
|
||||||
|
import {listboxContent} from "@/content/components/listbox";
|
||||||
|
import {scrollShadowContent} from "@/content/components/scroll-shadow";
|
||||||
|
|
||||||
|
|
||||||
|
<img
|
||||||
|
src="/blog/v2.1.0.jpg"
|
||||||
|
width={700}
|
||||||
|
height={350}
|
||||||
|
alt="NextUI v2"
|
||||||
|
className="w-full border border-transparent dark:border-default-200/50 object-fit rounded-xl shadow-lg"
|
||||||
|
/>
|
||||||
|
|
||||||
|
We are thrilled to announce the latest update to NextUI, version **2.1.0**! This release introduces some game-changing
|
||||||
|
additions that many of you have eagerly been waiting for.
|
||||||
|
|
||||||
|
First on the list is the highly-anticipated **Select** component. Fully customizable and beautifully designed, supports both single and
|
||||||
|
multi-select modes and is accessible out of the box.
|
||||||
|
|
||||||
|
But that's not all. We're also rolling out two more incredible components **Listbox** and **ScrollShadow**. The new
|
||||||
|
**Listbox** allows you to make list manipulations more efficient and visually appealing. Meanwhile, the
|
||||||
|
**ScrollShadow** component adds an elegant shadow effect to scrollable areas, enhancing the UI aesthetics while
|
||||||
|
also improving usability.
|
||||||
|
|
||||||
|
## Select
|
||||||
|
|
||||||
|
Creating a select component that is both accessible and customizable is a challenging task. We've spent a lot of time
|
||||||
|
researching and testing different approaches to come up with a solution that works for everyone. The result is a
|
||||||
|
component that is easy to use, fully accessible, and highly customizable.
|
||||||
|
|
||||||
|
The new **Select** component includes:
|
||||||
|
|
||||||
|
- Support for selecting a single option.
|
||||||
|
- Support for selecting multiple options.
|
||||||
|
- Support for disabled options.
|
||||||
|
- Support for sections.
|
||||||
|
- Labeling support for accessibility.
|
||||||
|
- Exposed to assistive technology as a button with a listbox popup using ARIA (combined with [Listbox](/docs/components/listbox)).
|
||||||
|
- Support for description and error message help text linked to the input via ARIA.
|
||||||
|
- Support for mouse, touch, and keyboard interactions.
|
||||||
|
- Tab stop focus management.
|
||||||
|
- Asynchronous options loading.
|
||||||
|
- Keyboard support for opening the listbox using the arrow keys, including automatically focusing the first or last item accordingly.
|
||||||
|
- Typeahead to allow selecting options by typing text, even without opening the listbox.
|
||||||
|
- Browser autofill integration via a hidden native `<select>` element.
|
||||||
|
- Support for mobile form navigation via software keyboard.
|
||||||
|
- Mobile screen reader listbox dismissal support.
|
||||||
|
- And much more...
|
||||||
|
|
||||||
|
### Single Select
|
||||||
|
|
||||||
|
The single select component is used to select a single option from a list of options. It is a combination of a button
|
||||||
|
and a listbox. The button displays the currently selected option and the listbox displays the available options.
|
||||||
|
|
||||||
|
<CodeDemo title="Usage" files={selectContent.usage} />
|
||||||
|
|
||||||
|
### Multiple Select
|
||||||
|
|
||||||
|
The multiple select component can be used to select multiple options from a list of options.
|
||||||
|
|
||||||
|
You only need to pass the `selectionMode="multiple"` prop to the `Select` component.
|
||||||
|
|
||||||
|
<CodeDemo title="Multiple Selection" files={selectContent.multiple} />
|
||||||
|
|
||||||
|
### Multiple Variants
|
||||||
|
|
||||||
|
The select component comes with multiple variants.
|
||||||
|
|
||||||
|
<CodeDemo title="Variants" files={selectContent.variants} />
|
||||||
|
|
||||||
|
|
||||||
|
### Chips Support
|
||||||
|
|
||||||
|
The select component is flexible and allows you to render any component as an option and as a selected option.
|
||||||
|
|
||||||
|
<CodeDemo title="Multiple Selection with Chips" files={selectContent.multipleWithChips} />
|
||||||
|
|
||||||
|
|
||||||
|
### Customizable
|
||||||
|
|
||||||
|
The select component is highly customizable, you can customize the selected option, the options, the listbox,
|
||||||
|
the popover and the scrollable area.
|
||||||
|
|
||||||
|
<CodeDemo title="Custom Styles" files={selectContent.customStyles} />
|
||||||
|
|
||||||
|
|
||||||
|
Go to the [Select](/docs/components/select) component page to learn more about sizes, colors, and more.
|
||||||
|
|
||||||
|
|
||||||
|
## Listbox
|
||||||
|
|
||||||
|
The listbox component allows you to make list manipulations more efficient and visually appealing.
|
||||||
|
|
||||||
|
The new **Listbox** component includes:
|
||||||
|
|
||||||
|
- Support for single, multiple, or no selection.
|
||||||
|
- Exposed to assistive technology as a `listbox` using ARIA.
|
||||||
|
- Support for disabled items.
|
||||||
|
- Support for sections.
|
||||||
|
- Labeling support for accessibility.
|
||||||
|
- Support for mouse, touch, and keyboard interactions.
|
||||||
|
- Tab stop focus management.
|
||||||
|
- Keyboard navigation support including arrow keys, home/end, page up/down, select all, and clear.
|
||||||
|
- Automatic scrolling support during keyboard navigation.
|
||||||
|
- Typeahead to allow focusing options by typing text.
|
||||||
|
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
<CodeDemo title="Usage" files={listboxContent.usage} />
|
||||||
|
|
||||||
|
### Custom Styles
|
||||||
|
|
||||||
|
The Listbox components offers multiple customization options.
|
||||||
|
|
||||||
|
<CodeDemo title="Custom Styles" files={listboxContent.customStyles} />
|
||||||
|
|
||||||
|
> **Note**: In the above example, we've utilized the [Boxicons](https://boxicons.com/) icons collection.
|
||||||
|
|
||||||
|
Go to the [Listbox](/docs/components/listbox) component page to learn more about it.
|
||||||
|
|
||||||
|
|
||||||
|
## ScrollShadow
|
||||||
|
|
||||||
|
The ScrollShadow component gives a nice shadow effect to scrollable areas. These shadows are handled by using
|
||||||
|
the CSS `mask-image` property, which makes the shadows adapt to the background color.
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
<CodeDemo title="Usage" files={scrollShadowContent.usage} />
|
||||||
|
|
||||||
|
You can hide the scrollbars, customize the shadows size, change the orientation, and more.
|
||||||
|
|
||||||
|
Go to the [ScrollShadow](/docs/components/scroll-shadow) component page to learn more about it.
|
||||||
|
|
||||||
|
|
||||||
|
<Spacer y={6}/>
|
||||||
|
|
||||||
|
We hope you enjoy these new components and the new features. We're excited to see what you build with them!
|
||||||
|
|
||||||
|
Thanks for reading and happy coding! 🚀
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Community
|
||||||
|
|
||||||
|
We're excited to see the community adopt NextUI, raise issues, and provide feedback.
|
||||||
|
Whether it's a feature request, bug report, or a project to showcase, please get involved!
|
||||||
|
|
||||||
|
<Community />
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
PR's on NextUI are always welcome, please see our [contribution guidelines](https://github.com/nextui-org/nextui/blob/main/CONTRIBUTING.MD) to learn how you can contribute to this project.
|
||||||
89
apps/docs/content/components/autocomplete/async-filtering.ts
Normal file
89
apps/docs/content/components/autocomplete/async-filtering.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
188
apps/docs/content/components/autocomplete/async-loading-items.ts
Normal file
188
apps/docs/content/components/autocomplete/async-loading-items.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
68
apps/docs/content/components/autocomplete/colors.ts
Normal file
68
apps/docs/content/components/autocomplete/colors.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
89
apps/docs/content/components/autocomplete/controlled.ts
Normal file
89
apps/docs/content/components/autocomplete/controlled.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
102
apps/docs/content/components/autocomplete/custom-filtering.ts
Normal file
102
apps/docs/content/components/autocomplete/custom-filtering.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
239
apps/docs/content/components/autocomplete/custom-items.ts
Normal file
239
apps/docs/content/components/autocomplete/custom-items.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
319
apps/docs/content/components/autocomplete/custom-styles.ts
Normal file
319
apps/docs/content/components/autocomplete/custom-styles.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
53
apps/docs/content/components/autocomplete/custom-value.ts
Normal file
53
apps/docs/content/components/autocomplete/custom-value.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
54
apps/docs/content/components/autocomplete/description.ts
Normal file
54
apps/docs/content/components/autocomplete/description.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
53
apps/docs/content/components/autocomplete/disabled-items.ts
Normal file
53
apps/docs/content/components/autocomplete/disabled-items.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
54
apps/docs/content/components/autocomplete/disabled.ts
Normal file
54
apps/docs/content/components/autocomplete/disabled.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
52
apps/docs/content/components/autocomplete/dynamic.ts
Normal file
52
apps/docs/content/components/autocomplete/dynamic.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
64
apps/docs/content/components/autocomplete/error-message.ts
Normal file
64
apps/docs/content/components/autocomplete/error-message.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
110
apps/docs/content/components/autocomplete/events.ts
Normal file
110
apps/docs/content/components/autocomplete/events.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
187
apps/docs/content/components/autocomplete/fully-controlled.ts
Normal file
187
apps/docs/content/components/autocomplete/fully-controlled.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
55
apps/docs/content/components/autocomplete/index.ts
Normal file
55
apps/docs/content/components/autocomplete/index.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
54
apps/docs/content/components/autocomplete/required.ts
Normal file
54
apps/docs/content/components/autocomplete/required.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
40
apps/docs/content/components/autocomplete/sections.ts
Normal file
40
apps/docs/content/components/autocomplete/sections.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
69
apps/docs/content/components/autocomplete/sizes.ts
Normal file
69
apps/docs/content/components/autocomplete/sizes.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
91
apps/docs/content/components/autocomplete/start-content.ts
Normal file
91
apps/docs/content/components/autocomplete/start-content.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
64
apps/docs/content/components/autocomplete/usage.ts
Normal file
64
apps/docs/content/components/autocomplete/usage.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
72
apps/docs/content/components/autocomplete/variants.ts
Normal file
72
apps/docs/content/components/autocomplete/variants.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
@ -7,7 +7,7 @@ export default function App() {
|
|||||||
max={3}
|
max={3}
|
||||||
total={10}
|
total={10}
|
||||||
renderCount={(count) => (
|
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" />
|
<Avatar src="https://i.pravatar.cc/150?u=a042581f4e29026024d" />
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import placements from "./placements";
|
|||||||
import shapes from "./shapes";
|
import shapes from "./shapes";
|
||||||
import visibility from "./visibility";
|
import visibility from "./visibility";
|
||||||
import contentExamples from "./content-examples";
|
import contentExamples from "./content-examples";
|
||||||
import disableOutline from "./disable-outline";
|
import showOutline from "./show-outline";
|
||||||
import a11y from "./a11y";
|
import a11y from "./a11y";
|
||||||
|
|
||||||
export const badgeContent = {
|
export const badgeContent = {
|
||||||
@ -18,6 +18,6 @@ export const badgeContent = {
|
|||||||
shapes,
|
shapes,
|
||||||
visibility,
|
visibility,
|
||||||
contentExamples,
|
contentExamples,
|
||||||
disableOutline,
|
showOutline,
|
||||||
a11y,
|
a11y,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -3,14 +3,14 @@ const App = `import {Badge, Avatar} from "@nextui-org/react";
|
|||||||
export default function App() {
|
export default function App() {
|
||||||
return (
|
return (
|
||||||
<div className="flex gap-4 items-center">
|
<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
|
<Avatar
|
||||||
isBordered
|
isBordered
|
||||||
radius="md"
|
radius="md"
|
||||||
src="https://i.pravatar.cc/150?u=a042f81f4e29026024d"
|
src="https://i.pravatar.cc/150?u=a042f81f4e29026024d"
|
||||||
/>
|
/>
|
||||||
</Badge>
|
</Badge>
|
||||||
<Badge content="5" color="danger" shape="circle" disableOutline>
|
<Badge content="5" color="danger" shape="circle" showOutline={false}>
|
||||||
<Avatar
|
<Avatar
|
||||||
isBordered
|
isBordered
|
||||||
radius="full"
|
radius="full"
|
||||||
21
apps/docs/content/components/breadcrumbs/collapsing-items.ts
Normal file
21
apps/docs/content/components/breadcrumbs/collapsing-items.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
27
apps/docs/content/components/breadcrumbs/colors.ts
Normal file
27
apps/docs/content/components/breadcrumbs/colors.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
64
apps/docs/content/components/breadcrumbs/controlled.ts
Normal file
64
apps/docs/content/components/breadcrumbs/controlled.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
76
apps/docs/content/components/breadcrumbs/custom-items.ts
Normal file
76
apps/docs/content/components/breadcrumbs/custom-items.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
64
apps/docs/content/components/breadcrumbs/custom-styles.ts
Normal file
64
apps/docs/content/components/breadcrumbs/custom-styles.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
21
apps/docs/content/components/breadcrumbs/disabled.ts
Normal file
21
apps/docs/content/components/breadcrumbs/disabled.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
35
apps/docs/content/components/breadcrumbs/index.ts
Normal file
35
apps/docs/content/components/breadcrumbs/index.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
91
apps/docs/content/components/breadcrumbs/menu-type.ts
Normal file
91
apps/docs/content/components/breadcrumbs/menu-type.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
27
apps/docs/content/components/breadcrumbs/radius.ts
Normal file
27
apps/docs/content/components/breadcrumbs/radius.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
21
apps/docs/content/components/breadcrumbs/routing.ts
Normal file
21
apps/docs/content/components/breadcrumbs/routing.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
26
apps/docs/content/components/breadcrumbs/separator.ts
Normal file
26
apps/docs/content/components/breadcrumbs/separator.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
27
apps/docs/content/components/breadcrumbs/sizes.ts
Normal file
27
apps/docs/content/components/breadcrumbs/sizes.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
112
apps/docs/content/components/breadcrumbs/start-end-content.ts
Normal file
112
apps/docs/content/components/breadcrumbs/start-end-content.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
39
apps/docs/content/components/breadcrumbs/underlines.ts
Normal file
39
apps/docs/content/components/breadcrumbs/underlines.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
21
apps/docs/content/components/breadcrumbs/usage.ts
Normal file
21
apps/docs/content/components/breadcrumbs/usage.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
27
apps/docs/content/components/breadcrumbs/variants.ts
Normal file
27
apps/docs/content/components/breadcrumbs/variants.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
@ -140,7 +140,7 @@ const ShuffleIcon = `export const ShuffleIcon = ({size = 24, width, height, ...p
|
|||||||
</svg>
|
</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 {HeartIcon} from "./HeartIcon";
|
||||||
import {PauseCircleIcon} from "./PauseCircleIcon";
|
import {PauseCircleIcon} from "./PauseCircleIcon";
|
||||||
import {NextIcon} from "./NextIcon";
|
import {NextIcon} from "./NextIcon";
|
||||||
@ -192,15 +192,15 @@ export default function App() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-col mt-3 gap-1">
|
<div className="flex flex-col mt-3 gap-1">
|
||||||
<Progress
|
<Slider
|
||||||
aria-label="Music progress"
|
aria-label="Music progress"
|
||||||
classNames={{
|
classNames={{
|
||||||
indicator: "bg-default-800 dark:bg-white",
|
|
||||||
track: "bg-default-500/30",
|
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"
|
size="sm"
|
||||||
value={33}
|
|
||||||
/>
|
/>
|
||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
<p className="text-small">1:23</p>
|
<p className="text-small">1:23</p>
|
||||||
|
|||||||
@ -30,8 +30,8 @@ export default function App() {
|
|||||||
showArrow
|
showArrow
|
||||||
radius="sm"
|
radius="sm"
|
||||||
classNames={{
|
classNames={{
|
||||||
base: "p-0 border-small border-divider bg-background",
|
base: "before:bg-default-200", // change arrow background
|
||||||
arrow: "bg-default-200",
|
content: "p-0 border-small border-divider bg-background",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DropdownTrigger>
|
<DropdownTrigger>
|
||||||
|
|||||||
@ -113,8 +113,8 @@ export default function App() {
|
|||||||
<Dropdown
|
<Dropdown
|
||||||
showArrow
|
showArrow
|
||||||
classNames={{
|
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",
|
base: "before:bg-default-200", // change arrow background
|
||||||
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",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DropdownTrigger>
|
<DropdownTrigger>
|
||||||
|
|||||||
@ -30,3 +30,4 @@ export * from "./pagination";
|
|||||||
export * from "./dropdown";
|
export * from "./dropdown";
|
||||||
export * from "./navbar";
|
export * from "./navbar";
|
||||||
export * from "./table";
|
export * from "./table";
|
||||||
|
export * from "./autocomplete";
|
||||||
|
|||||||
@ -98,7 +98,7 @@ const MyInput = forwardRef((props, ref) => {
|
|||||||
type: "search",
|
type: "search",
|
||||||
placeholder: "Type to search...",
|
placeholder: "Type to search...",
|
||||||
startContent: (
|
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
|
// custom styles
|
||||||
classNames: {
|
classNames: {
|
||||||
|
|||||||
@ -59,7 +59,7 @@ export default function App() {
|
|||||||
}}
|
}}
|
||||||
placeholder="Type to search..."
|
placeholder="Type to search..."
|
||||||
startContent={
|
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>
|
</div>
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import icons from "./icons";
|
|||||||
import description from "./description";
|
import description from "./description";
|
||||||
import sections from "./sections";
|
import sections from "./sections";
|
||||||
import customStyles from "./custom-styles";
|
import customStyles from "./custom-styles";
|
||||||
|
import topContent from "./top-content";
|
||||||
|
|
||||||
export const listboxContent = {
|
export const listboxContent = {
|
||||||
usage,
|
usage,
|
||||||
@ -20,4 +21,5 @@ export const listboxContent = {
|
|||||||
description,
|
description,
|
||||||
sections,
|
sections,
|
||||||
customStyles,
|
customStyles,
|
||||||
|
topContent,
|
||||||
};
|
};
|
||||||
|
|||||||
347
apps/docs/content/components/listbox/top-content.ts
Normal file
347
apps/docs/content/components/listbox/top-content.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
@ -52,6 +52,7 @@ import {ChevronIcon} from "./ChevronIcon";
|
|||||||
export default function App() {
|
export default function App() {
|
||||||
const renderItem = ({
|
const renderItem = ({
|
||||||
ref,
|
ref,
|
||||||
|
key,
|
||||||
value,
|
value,
|
||||||
isActive,
|
isActive,
|
||||||
onNext,
|
onNext,
|
||||||
@ -61,7 +62,7 @@ export default function App() {
|
|||||||
}: PaginationItemRenderProps<HTMLButtonElement>) => {
|
}: PaginationItemRenderProps<HTMLButtonElement>) => {
|
||||||
if (value === PaginationItemType.NEXT) {
|
if (value === PaginationItemType.NEXT) {
|
||||||
return (
|
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" />
|
<ChevronIcon className="rotate-180" />
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
@ -69,20 +70,21 @@ export default function App() {
|
|||||||
|
|
||||||
if (value === PaginationItemType.PREV) {
|
if (value === PaginationItemType.PREV) {
|
||||||
return (
|
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 />
|
<ChevronIcon />
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value === PaginationItemType.DOTS) {
|
if (value === PaginationItemType.DOTS) {
|
||||||
return <button className={className}>...</button>;
|
return <button key={key} className={className}>...</button>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// cursor is the default item
|
// cursor is the default item
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
ref={ref}
|
ref={ref}
|
||||||
|
key={key}
|
||||||
className={cn(
|
className={cn(
|
||||||
className,
|
className,
|
||||||
isActive &&
|
isActive &&
|
||||||
@ -115,6 +117,7 @@ import {ChevronIcon} from "./ChevronIcon";
|
|||||||
export default function App() {
|
export default function App() {
|
||||||
const renderItem = ({
|
const renderItem = ({
|
||||||
ref,
|
ref,
|
||||||
|
key,
|
||||||
value,
|
value,
|
||||||
isActive,
|
isActive,
|
||||||
onNext,
|
onNext,
|
||||||
@ -124,7 +127,7 @@ export default function App() {
|
|||||||
}) => {
|
}) => {
|
||||||
if (value === PaginationItemType.NEXT) {
|
if (value === PaginationItemType.NEXT) {
|
||||||
return (
|
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" />
|
<ChevronIcon className="rotate-180" />
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
@ -132,19 +135,20 @@ export default function App() {
|
|||||||
|
|
||||||
if (value === PaginationItemType.PREV) {
|
if (value === PaginationItemType.PREV) {
|
||||||
return (
|
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 />
|
<ChevronIcon />
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value === PaginationItemType.DOTS) {
|
if (value === PaginationItemType.DOTS) {
|
||||||
return <button className={className}>...</button>;
|
return <button key={key} className={className}>...</button>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// cursor is the default item
|
// cursor is the default item
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
|
key={key}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
className,
|
className,
|
||||||
|
|||||||
@ -7,8 +7,15 @@ export default function App() {
|
|||||||
backdrop="opaque"
|
backdrop="opaque"
|
||||||
placement="right"
|
placement="right"
|
||||||
classNames={{
|
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",
|
base: [
|
||||||
arrow: "bg-default-200",
|
// 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>
|
<PopoverTrigger>
|
||||||
|
|||||||
@ -233,8 +233,8 @@ export default function App() {
|
|||||||
}}
|
}}
|
||||||
popoverProps={{
|
popoverProps={{
|
||||||
classNames: {
|
classNames: {
|
||||||
base: "p-0 border-small border-divider bg-background",
|
base: "before:bg-default-200",
|
||||||
arrow: "bg-default-200",
|
content: "p-0 border-small border-divider bg-background",
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
renderValue={(items) => {
|
renderValue={(items) => {
|
||||||
|
|||||||
@ -30,10 +30,10 @@ const App = `import {Select, SelectItem} from "@nextui-org/react";
|
|||||||
import {animals} from "./data";
|
import {animals} from "./data";
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
const [value, setValue] = React.useState(new Set([]));
|
const [value, setValue] = React.useState("");
|
||||||
|
|
||||||
const handleSelectionChange = (e) => {
|
const handleSelectionChange = (e) => {
|
||||||
setValue(new Set([e.target.value]));
|
setValue(e.target.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -42,7 +42,7 @@ export default function App() {
|
|||||||
label="Favorite Animal"
|
label="Favorite Animal"
|
||||||
variant="bordered"
|
variant="bordered"
|
||||||
placeholder="Select an animal"
|
placeholder="Select an animal"
|
||||||
selectedKeys={value}
|
selectedKeys={[value]}
|
||||||
className="max-w-xs"
|
className="max-w-xs"
|
||||||
onChange={handleSelectionChange}
|
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";
|
import {animals} from "./data";
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
const [value, setValue] = React.useState<Selection>(new Set([]));
|
const [value, setValue] = React.useState<string>("");
|
||||||
|
|
||||||
const handleSelectionChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
|
const handleSelectionChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
|
||||||
setValue(new Set([e.target.value]));
|
setValue(e.target.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -73,7 +73,7 @@ export default function App() {
|
|||||||
label="Favorite Animal"
|
label="Favorite Animal"
|
||||||
variant="bordered"
|
variant="bordered"
|
||||||
placeholder="Select an animal"
|
placeholder="Select an animal"
|
||||||
selectedKeys={value}
|
selectedKeys={[value]}
|
||||||
className="max-w-xs"
|
className="max-w-xs"
|
||||||
onChange={handleSelectionChange}
|
onChange={handleSelectionChange}
|
||||||
>
|
>
|
||||||
|
|||||||
37
apps/docs/content/components/slider/colors.ts
Normal file
37
apps/docs/content/components/slider/colors.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
51
apps/docs/content/components/slider/controlled-change-end.ts
Normal file
51
apps/docs/content/components/slider/controlled-change-end.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
60
apps/docs/content/components/slider/controlled-range.ts
Normal file
60
apps/docs/content/components/slider/controlled-range.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
146
apps/docs/content/components/slider/controlled.ts
Normal file
146
apps/docs/content/components/slider/controlled.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
55
apps/docs/content/components/slider/custom-styles.ts
Normal file
55
apps/docs/content/components/slider/custom-styles.ts
Normal file
@ -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={[100, 300]}
|
||||||
|
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,
|
||||||
|
};
|
||||||
49
apps/docs/content/components/slider/disable-thumb-scale.ts
Normal file
49
apps/docs/content/components/slider/disable-thumb-scale.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
23
apps/docs/content/components/slider/disabled.ts
Normal file
23
apps/docs/content/components/slider/disabled.ts
Normal file
@ -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
Loading…
x
Reference in New Issue
Block a user