diff --git a/.changeset/chatty-singers-remember.md b/.changeset/chatty-singers-remember.md deleted file mode 100644 index 87d3f6c5ce..0000000000 --- a/.changeset/chatty-singers-remember.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@nextui-org/autocomplete": patch ---- - -Fixed empty items with allowCustomValue by avoiding null node in `ariaHideOutside` from `@react-aria/overlays` diff --git a/.changeset/chilled-horses-type.md b/.changeset/chilled-horses-type.md deleted file mode 100644 index 0cbd2d8508..0000000000 --- a/.changeset/chilled-horses-type.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@nextui-org/ripple": patch ---- - -Fixed LazyMotion forwardRef issue diff --git a/.changeset/clever-bugs-prove.md b/.changeset/clever-bugs-prove.md new file mode 100644 index 0000000000..4a9d4b1c20 --- /dev/null +++ b/.changeset/clever-bugs-prove.md @@ -0,0 +1,5 @@ +--- +"@nextui-org/table": patch +--- + +Add missing export of TableRowProps type diff --git a/.changeset/dirty-beans-repair.md b/.changeset/dirty-beans-repair.md deleted file mode 100644 index b0bc93ca8c..0000000000 --- a/.changeset/dirty-beans-repair.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@nextui-org/navbar": patch ---- - -fixed LazyMotion ForwardRef issue diff --git a/.changeset/eleven-maps-admire.md b/.changeset/eleven-maps-admire.md deleted file mode 100644 index 421f05c550..0000000000 --- a/.changeset/eleven-maps-admire.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@nextui-org/skeleton": patch -"@nextui-org/theme": patch ---- - -Fixed missing disableAnimation behavior in skeleton diff --git a/.changeset/empty-eels-compare.md b/.changeset/empty-eels-compare.md deleted file mode 100644 index d27f06ada6..0000000000 --- a/.changeset/empty-eels-compare.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@nextui-org/table": patch ---- - -Fixed an issue where the `Table` component incorrectly rendered cell contents beneath the stripe when multiple computed values were provided in a `td` (table cell) element. diff --git a/.changeset/famous-owls-kick.md b/.changeset/famous-owls-kick.md deleted file mode 100644 index b9b330cd98..0000000000 --- a/.changeset/famous-owls-kick.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@nextui-org/table": patch ---- - -Add RTL support to the table component. diff --git a/.changeset/four-turtles-move.md b/.changeset/four-turtles-move.md deleted file mode 100644 index b7eb8987b5..0000000000 --- a/.changeset/four-turtles-move.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@nextui-org/popover": patch ---- - -fixed popover closing issue in autocomplete with open modal (#2475, #2082, #1987) diff --git a/.changeset/four-walls-rescue.md b/.changeset/four-walls-rescue.md deleted file mode 100644 index b4d9486516..0000000000 --- a/.changeset/four-walls-rescue.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@nextui-org/select": patch ---- - -Fixed isFilled & hasValue logic for state.selectedItems in select diff --git a/.changeset/gentle-pigs-admire.md b/.changeset/gentle-pigs-admire.md new file mode 100644 index 0000000000..a974c8fda6 --- /dev/null +++ b/.changeset/gentle-pigs-admire.md @@ -0,0 +1,5 @@ +--- +"@nextui-org/date-picker": patch +--- + +Fixed missing aria labels in date range picker (#2804) diff --git a/.changeset/heavy-berries-sniff.md b/.changeset/heavy-berries-sniff.md deleted file mode 100644 index 4cc8ca043b..0000000000 --- a/.changeset/heavy-berries-sniff.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@nextui-org/checkbox": patch ---- - -Fixed incorrect onChange typing in Checkbox Group diff --git a/.changeset/hot-rivers-move.md b/.changeset/hot-rivers-move.md deleted file mode 100644 index 3015c3ca9e..0000000000 --- a/.changeset/hot-rivers-move.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@nextui-org/use-aria-multiselect": patch ---- - -Handle numeric selectedKeys in Select diff --git a/.changeset/large-dogs-sip.md b/.changeset/large-dogs-sip.md new file mode 100644 index 0000000000..82c3cd419f --- /dev/null +++ b/.changeset/large-dogs-sip.md @@ -0,0 +1,5 @@ +--- +"@nextui-org/use-aria-accordion": patch +--- + +Fixes ctrl+a keyboard shortcut enabled inside Accordion with `selectionMode="multiple"` (#2055) diff --git a/.changeset/lemon-kiwis-shop.md b/.changeset/lemon-kiwis-shop.md new file mode 100644 index 0000000000..401b87f4d8 --- /dev/null +++ b/.changeset/lemon-kiwis-shop.md @@ -0,0 +1,5 @@ +--- +"@nextui-org/theme": patch +--- + +Improved styling for radio button labels, including adjustments for different screen sizes and support for right-to-left (RTL) languages. (#2507) diff --git a/.changeset/long-mayflies-film.md b/.changeset/long-mayflies-film.md deleted file mode 100644 index f7d7892267..0000000000 --- a/.changeset/long-mayflies-film.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@nextui-org/autocomplete": patch -"@nextui-org/popover": patch -"@nextui-org/select": patch ---- - -revise shouldCloseOnInteractOutside for FreeSoloPopover diff --git a/.changeset/long-pets-matter.md b/.changeset/long-pets-matter.md new file mode 100644 index 0000000000..2244152de8 --- /dev/null +++ b/.changeset/long-pets-matter.md @@ -0,0 +1,5 @@ +--- +"@nextui-org/theme": patch +--- + +Fixed slider component vertical mark y position focus (#2658) diff --git a/.changeset/lovely-snakes-approve.md b/.changeset/lovely-snakes-approve.md deleted file mode 100644 index d780585257..0000000000 --- a/.changeset/lovely-snakes-approve.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@nextui-org/popover": patch -"@nextui-org/system-rsc": patch -"@nextui-org/theme": patch ---- - -Fixed unexpected props on a DOM element (#2474) diff --git a/.changeset/metal-peas-act.md b/.changeset/metal-peas-act.md deleted file mode 100644 index f9f8205ed3..0000000000 --- a/.changeset/metal-peas-act.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@nextui-org/react-rsc-utils": patch ---- - -include enterKeyHint in dom-props (#2432) diff --git a/.changeset/mighty-hornets-destroy.md b/.changeset/mighty-hornets-destroy.md deleted file mode 100644 index 1f4e92b609..0000000000 --- a/.changeset/mighty-hornets-destroy.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@nextui-org/table": patch ---- - -Fixed normal cursor to cursor-not-allowed for disabled rows in Table diff --git a/.changeset/nervous-geckos-visit.md b/.changeset/nervous-geckos-visit.md deleted file mode 100644 index 3cc441f7fa..0000000000 --- a/.changeset/nervous-geckos-visit.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@nextui-org/select": patch ---- - -Fixed Disabled Select Allows Changes Using Blur + Keyboard (#2345) diff --git a/.changeset/new-paws-remain.md b/.changeset/new-paws-remain.md deleted file mode 100644 index 5041ffc7b1..0000000000 --- a/.changeset/new-paws-remain.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@nextui-org/avatar": patch ---- - -Add RTL support to the avatar group component diff --git a/.changeset/nice-rockets-watch.md b/.changeset/nice-rockets-watch.md deleted file mode 100644 index 2e483b9e9e..0000000000 --- a/.changeset/nice-rockets-watch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@nextui-org/table": patch ---- - -fixed `Spinner` loading on top of columns instead of inside `Table` in case of `emptyContent` prop not passed to `Table` body diff --git a/.changeset/old-cameras-sip.md b/.changeset/old-cameras-sip.md deleted file mode 100644 index c871893a60..0000000000 --- a/.changeset/old-cameras-sip.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@nextui-org/modal": patch ---- - -Prevent IME input carryover in form fields when tabbing diff --git a/.changeset/poor-years-help.md b/.changeset/poor-years-help.md deleted file mode 100644 index 562f4c871e..0000000000 --- a/.changeset/poor-years-help.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@nextui-org/autocomplete": patch ---- - -Fix #1909 overwrite `onKeyDown` to prevent meaningless error msg diff --git a/.changeset/purple-keys-dance.md b/.changeset/purple-keys-dance.md deleted file mode 100644 index ae3ff368d9..0000000000 --- a/.changeset/purple-keys-dance.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@nextui-org/switch": patch ---- - -Add RTL support to the switch component diff --git a/.changeset/rare-ants-ring.md b/.changeset/rare-ants-ring.md deleted file mode 100644 index 9ecb63146c..0000000000 --- a/.changeset/rare-ants-ring.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@nextui-org/theme": patch ---- - -Fix: remove conflicting transition utilities (close #1502) - -See: https://tailwindcss.com/docs/transition-property \ No newline at end of file diff --git a/.changeset/rare-needles-study.md b/.changeset/rare-needles-study.md deleted file mode 100644 index 6db811425a..0000000000 --- a/.changeset/rare-needles-study.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@nextui-org/checkbox": patch ---- - -Add RTL support to the checkbox component diff --git a/.changeset/rare-plums-speak.md b/.changeset/rare-plums-speak.md deleted file mode 100644 index bfcb5315d0..0000000000 --- a/.changeset/rare-plums-speak.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@nextui-org/use-aria-multiselect": patch -"@nextui-org/stories-utils": patch ---- - -Fixed an issue where a warning was triggered in the Select component when `defaultSelectedKeys` were used and items were still loading (#2605). diff --git a/.changeset/real-parrots-act.md b/.changeset/real-parrots-act.md deleted file mode 100644 index 212a51ea16..0000000000 --- a/.changeset/real-parrots-act.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@nextui-org/theme": patch ---- - -Changed the HSL rounding to 2 decimal places (#2697) diff --git a/.changeset/serious-sheep-promise.md b/.changeset/serious-sheep-promise.md deleted file mode 100644 index 24dfa0b456..0000000000 --- a/.changeset/serious-sheep-promise.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@nextui-org/kbd": patch ---- - -Add RTL support to the kbd component diff --git a/.changeset/short-trainers-dance.md b/.changeset/short-trainers-dance.md new file mode 100644 index 0000000000..d1615b1097 --- /dev/null +++ b/.changeset/short-trainers-dance.md @@ -0,0 +1,5 @@ +--- +"@nextui-org/theme": patch +--- + +Fix custom slot styling with twMerge set to true (#2153) diff --git a/.changeset/silly-pants-type.md b/.changeset/silly-pants-type.md deleted file mode 100644 index 9821b7d852..0000000000 --- a/.changeset/silly-pants-type.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@nextui-org/autocomplete": patch ---- - -Removed unnecessary map after getting all collection keys diff --git a/.changeset/silly-seas-tie.md b/.changeset/silly-seas-tie.md deleted file mode 100644 index e917acdd43..0000000000 --- a/.changeset/silly-seas-tie.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@nextui-org/dropdown": patch ---- - -fixed getMenuTriggerProps mergeProps (#2448) diff --git a/.changeset/six-donuts-breathe.md b/.changeset/six-donuts-breathe.md deleted file mode 100644 index 88131c240b..0000000000 --- a/.changeset/six-donuts-breathe.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@nextui-org/input": patch ---- - -Add RTL support to the input component diff --git a/.changeset/six-seas-shout.md b/.changeset/six-seas-shout.md deleted file mode 100644 index 90522d08ca..0000000000 --- a/.changeset/six-seas-shout.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@nextui-org/autocomplete": patch ---- - -Fixes incorrect prop name in getEmptyPopoverProps (#2715) diff --git a/.changeset/slimy-panthers-swim.md b/.changeset/slimy-panthers-swim.md deleted file mode 100644 index da85c3f1b8..0000000000 --- a/.changeset/slimy-panthers-swim.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@nextui-org/accordion": patch ---- - -fixed remove dividers from hidden accordion items (#2210) diff --git a/.changeset/spicy-coats-exist.md b/.changeset/spicy-coats-exist.md deleted file mode 100644 index 8559535783..0000000000 --- a/.changeset/spicy-coats-exist.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@nextui-org/modal": patch -"@nextui-org/popover": patch ---- - -Fixed lazy motion forwardRef issue diff --git a/.changeset/spotty-pens-stare.md b/.changeset/spotty-pens-stare.md deleted file mode 100644 index b1e1761cae..0000000000 --- a/.changeset/spotty-pens-stare.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@nextui-org/tooltip": patch ---- - -Fix #1840 let Tooltip allow non-ReactElement children diff --git a/.changeset/thin-rice-smile.md b/.changeset/thin-rice-smile.md deleted file mode 100644 index e9161af597..0000000000 --- a/.changeset/thin-rice-smile.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@nextui-org/modal": patch -"@nextui-org/popover": patch ---- - -Fixed incorrect level of m.div diff --git a/.changeset/thirty-bugs-beg.md b/.changeset/thirty-bugs-beg.md deleted file mode 100644 index 80982defb3..0000000000 --- a/.changeset/thirty-bugs-beg.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@nextui-org/autocomplete": patch ---- - -fixed isReadOnly logic in Autocomplete (#2420) diff --git a/.changeset/three-tools-whisper.md b/.changeset/three-tools-whisper.md deleted file mode 100644 index 9ab86e8ef3..0000000000 --- a/.changeset/three-tools-whisper.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@nextui-org/badge": patch ---- - -Removing the `children` type from BadgeProps, as the already extended UseBadgeProps has a `children` prop. diff --git a/.changeset/tough-spies-tease.md b/.changeset/tough-spies-tease.md deleted file mode 100644 index 5be816c5e8..0000000000 --- a/.changeset/tough-spies-tease.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"@nextui-org/autocomplete": patch -"@nextui-org/dropdown": patch -"@nextui-org/popover": patch -"@nextui-org/tooltip": patch ---- - -fix(autocomplete): support isReadOnly for dynamic collections in Autocomplete diff --git a/.changeset/two-bananas-dance.md b/.changeset/two-bananas-dance.md new file mode 100644 index 0000000000..c7e37a2fe3 --- /dev/null +++ b/.changeset/two-bananas-dance.md @@ -0,0 +1,5 @@ +--- +"@nextui-org/input": patch +--- + +Fix #2069 keep input component's position steady diff --git a/.changeset/warm-zoos-fry.md b/.changeset/warm-zoos-fry.md deleted file mode 100644 index 63792b315f..0000000000 --- a/.changeset/warm-zoos-fry.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"@nextui-org/accordion": patch -"@nextui-org/modal": patch -"@nextui-org/navbar": patch -"@nextui-org/popover": patch -"@nextui-org/ripple": patch -"@nextui-org/tabs": patch -"@nextui-org/tooltip": patch ---- - -Changes the motion important to the more lightweight m component in framer motion to only load the required features. diff --git a/.changeset/wild-rockets-check.md b/.changeset/wild-rockets-check.md deleted file mode 100644 index f99da0c97f..0000000000 --- a/.changeset/wild-rockets-check.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@nextui-org/modal": patch ---- - -Add RTL support to the modal component. diff --git a/apps/docs/app/blog/[slug]/page.tsx b/apps/docs/app/blog/[slug]/page.tsx index 786a9f5867..f62a849e0d 100644 --- a/apps/docs/app/blog/[slug]/page.tsx +++ b/apps/docs/app/blog/[slug]/page.tsx @@ -7,6 +7,7 @@ import {format, parseISO} from "date-fns"; import NextLink from "next/link"; import {Balancer} from "react-wrap-balancer"; +import {__DEV__, __PREVIEW__} from "@/utils"; import {MDXContent} from "@/components/mdx-content"; import {siteConfig} from "@/config/site"; import {Route} from "@/libs/docs/page"; @@ -18,6 +19,8 @@ interface BlogPostProps { }; } +const isDraftVisible = __DEV__ || __PREVIEW__; + async function getBlogPostFromParams({params}: BlogPostProps) { const slug = params.slug || ""; const post = allBlogPosts.find((post) => post.slugAsParams === slug); @@ -78,7 +81,7 @@ export async function generateStaticParams(): Promise export default async function DocPage({params}: BlogPostProps) { const {post} = await getBlogPostFromParams({params}); - if (!post) { + if (!post || (post.draft && !isDraftVisible)) { notFound(); } @@ -96,6 +99,7 @@ export default async function DocPage({params}: BlogPostProps) { Back to blog + @@ -119,6 +123,7 @@ export default async function DocPage({params}: BlogPostProps) {

{post.title} + {post?.draft && " (Draft)"}

diff --git a/apps/docs/app/blog/page.tsx b/apps/docs/app/blog/page.tsx index 309386e9bb..4662e294a1 100644 --- a/apps/docs/app/blog/page.tsx +++ b/apps/docs/app/blog/page.tsx @@ -2,9 +2,20 @@ import {allBlogPosts} from "contentlayer/generated"; import {compareDesc} from "date-fns"; import {BlogPostList} from "@/components/blog-post"; +import {__DEV__, __PREVIEW__} from "@/utils"; + +const isDraftVisible = __DEV__ || __PREVIEW__; export default function Blog() { - const posts = allBlogPosts.sort((a, b) => compareDesc(new Date(a.date), new Date(b.date))); + const posts = allBlogPosts + .sort((a, b) => compareDesc(new Date(a.date), new Date(b.date))) + ?.filter((post) => { + if (post.draft && !isDraftVisible) { + return false; + } + + return true; + }); return (
diff --git a/apps/docs/app/examples/perf/page.tsx b/apps/docs/app/examples/perf/page.tsx index 2b6e10fd92..de9e89f43f 100644 --- a/apps/docs/app/examples/perf/page.tsx +++ b/apps/docs/app/examples/perf/page.tsx @@ -124,15 +124,15 @@ const MyInput = extendVariants(Input, { }, size: { xs: { - inputWrapper: "h-unit-6 min-h-unit-6 px-1", + inputWrapper: "h-6 min-h-6 px-1", input: "text-tiny", }, md: { - inputWrapper: "h-unit-10 min-h-unit-10", + inputWrapper: "h-10 min-h-10", input: "text-small", }, xl: { - inputWrapper: "h-unit-14 min-h-unit-14", + inputWrapper: "h-14 min-h-14", input: "text-medium", }, }, diff --git a/apps/docs/components/blog-post.tsx b/apps/docs/components/blog-post.tsx index 5c78301351..b73b67fe75 100644 --- a/apps/docs/components/blog-post.tsx +++ b/apps/docs/components/blog-post.tsx @@ -57,7 +57,7 @@ const BlogPostCard = (post: BlogPost) => { diff --git a/apps/docs/components/cmdk.tsx b/apps/docs/components/cmdk.tsx index 02853158d2..e259a641ec 100644 --- a/apps/docs/components/cmdk.tsx +++ b/apps/docs/components/cmdk.tsx @@ -410,8 +410,8 @@ export const Cmdk: FC<{}> = () => {
- {query.length > 0 && ( - + + {query.length > 0 && (

No results for "{query}"

@@ -424,8 +424,8 @@ export const Cmdk: FC<{}> = () => { )}
-
- )} + )} +
{isEmpty(query) && (isEmpty(recentSearches) ? ( diff --git a/apps/docs/components/docs/components/code-demo/react-live-demo.tsx b/apps/docs/components/docs/components/code-demo/react-live-demo.tsx index 2a6f0d6a28..2023d8aee6 100644 --- a/apps/docs/components/docs/components/code-demo/react-live-demo.tsx +++ b/apps/docs/components/docs/components/code-demo/react-live-demo.tsx @@ -2,6 +2,8 @@ import React from "react"; import {LivePreview, LiveProvider, LiveError} from "react-live"; import {clsx} from "@nextui-org/shared-utils"; import * as Components from "@nextui-org/react"; +import * as intlDateUtils from "@internationalized/date"; +import * as reactAriaI18n from "@react-aria/i18n"; import {BgGridContainer} from "@/components/bg-grid-container"; import {GradientBox, GradientBoxProps} from "@/components/gradient-box"; @@ -19,6 +21,8 @@ export interface ReactLiveDemoProps { export const scope = { ...Components, + ...intlDateUtils, + ...reactAriaI18n, } as Record; export const ReactLiveDemo: React.FC = ({ diff --git a/apps/docs/components/docs/components/codeblock.tsx b/apps/docs/components/docs/components/codeblock.tsx index b1cddaec95..6acdf53c31 100644 --- a/apps/docs/components/docs/components/codeblock.tsx +++ b/apps/docs/components/docs/components/codeblock.tsx @@ -1,7 +1,7 @@ import React, {forwardRef, useEffect} from "react"; import {clsx, dataAttr, getUniqueID} from "@nextui-org/shared-utils"; import BaseHighlight, {Language, PrismTheme, defaultProps} from "prism-react-renderer"; -import {debounce} from "lodash"; +import {debounce, omit} from "lodash"; import defaultTheme from "@/libs/prism-theme"; @@ -19,6 +19,17 @@ interface CodeblockProps { type HighlightStyle = "inserted" | "deleted" | undefined; +const nextuiCliCommand = [ + /^init$/, + /^add$/, + /^upgrade$/, + /^remove$/, + /^list$/, + /^env$/, + /^doctor$/, +]; + +const highlightStyleToken = ["bun", /nextui\s\w+(?=\s?)/, /^nextui$/, "Usage", ...nextuiCliCommand]; const RE = /{([\d,-]+)}/; const calculateLinesToHighlight = (meta?: string) => { @@ -145,8 +156,8 @@ const Codeblock = forwardRef( return (
( {showLines && ( {i + 1} )} - {line.map((token, key) => ( - - ))} + {line.map((token, key) => { + // Bun has no color style by default in the code block, so hack add in here + const props = getTokenProps({token, key}) || {}; + + return ( + { + const regex = t instanceof RegExp ? t : new RegExp(t); + + return regex.test(token.content.trim()); + }) + ? {color: "rgb(var(--code-function))"} + : {}), + }} + /> + ); + })}
); })} diff --git a/apps/docs/components/docs/components/package-managers.tsx b/apps/docs/components/docs/components/package-managers.tsx index 6d81399c41..076493861f 100644 --- a/apps/docs/components/docs/components/package-managers.tsx +++ b/apps/docs/components/docs/components/package-managers.tsx @@ -1,19 +1,24 @@ import {Tabs, Tab, Snippet} from "@nextui-org/react"; -import {Key} from "react"; -import {useLocalStorage} from "usehooks-ts"; +import {Key, useState} from "react"; import Codeblock from "./codeblock"; -import {YarnIcon, NpmSmallIcon, PnpmIcon, BunIcon} from "@/components/icons"; +import {YarnIcon, NpmSmallIcon, PnpmIcon, BunIcon, CLIBoldIcon} from "@/components/icons"; -type PackageManagerName = "npm" | "yarn" | "pnpm" | "bun"; +type PackageManagerName = "cli" | "npm" | "yarn" | "pnpm" | "bun"; type PackageManager = { icon: JSX.Element; + label?: string; name: PackageManagerName; }; const packageManagers: PackageManager[] = [ + { + name: "cli", + label: "CLI", + icon: , + }, { name: "npm", icon: , @@ -28,7 +33,7 @@ const packageManagers: PackageManager[] = [ }, { name: "bun", - icon: , + icon: , }, ]; @@ -37,9 +42,8 @@ export interface PackageManagersProps { } export const PackageManagers = ({commands}: PackageManagersProps) => { - const [selectedManager, setSelectedManager] = useLocalStorage( - "selectedPackageManager", - "npm", + const [selectedManager, setSelectedManager] = useState( + commands.cli ? "cli" : "npm", ); const handleSelectionChange = (tabKey: Key) => { @@ -57,7 +61,7 @@ export const PackageManagers = ({commands}: PackageManagersProps) => { variant="underlined" onSelectionChange={handleSelectionChange} > - {packageManagers.map(({name, icon}) => { + {packageManagers.map(({name, label, icon}) => { if (!commands[name]) return null; return ( @@ -66,7 +70,7 @@ export const PackageManagers = ({commands}: PackageManagersProps) => { title={
{icon} - {name} + {label || name}
} > diff --git a/apps/docs/components/icons/bold/cli.tsx b/apps/docs/components/icons/bold/cli.tsx new file mode 100644 index 0000000000..d57d58ae9e --- /dev/null +++ b/apps/docs/components/icons/bold/cli.tsx @@ -0,0 +1,22 @@ +import {IconSvgProps} from "@/types"; + +export const CLIBoldIcon = ({...props}: IconSvgProps) => ( + +); diff --git a/apps/docs/components/icons/bold/index.ts b/apps/docs/components/icons/bold/index.ts index 3ccd05df40..278cfbbaee 100644 --- a/apps/docs/components/icons/bold/index.ts +++ b/apps/docs/components/icons/bold/index.ts @@ -16,3 +16,4 @@ export * from "./hash"; export * from "./more-square"; export * from "./play"; export * from "./pause"; +export * from "./cli"; diff --git a/apps/docs/components/icons/linear/cli.tsx b/apps/docs/components/icons/linear/cli.tsx new file mode 100644 index 0000000000..dd999dfe14 --- /dev/null +++ b/apps/docs/components/icons/linear/cli.tsx @@ -0,0 +1,23 @@ +import {IconSvgProps} from "@/types"; + +export const CLILinearIcon = ({...props}: IconSvgProps) => ( + +); diff --git a/apps/docs/components/icons/linear/index.ts b/apps/docs/components/icons/linear/index.ts index 6a70c6e7ff..b0ef59aa03 100644 --- a/apps/docs/components/icons/linear/index.ts +++ b/apps/docs/components/icons/linear/index.ts @@ -20,3 +20,4 @@ export * from "./chevron-right"; export * from "./search"; export * from "./simple-grid"; export * from "./rotate-left"; +export * from "./cli"; diff --git a/apps/docs/components/marketing/hero/hero.tsx b/apps/docs/components/marketing/hero/hero.tsx index 1cdba969bf..6b7a144665 100644 --- a/apps/docs/components/marketing/hero/hero.tsx +++ b/apps/docs/components/marketing/hero/hero.tsx @@ -1,7 +1,7 @@ "use client"; import NextLink from "next/link"; -import {Button, Link} from "@nextui-org/react"; +import {Button, Link, Chip} from "@nextui-org/react"; import {ArrowRightIcon} from "@nextui-org/shared-icons"; import dynamic from "next/dynamic"; @@ -16,32 +16,32 @@ const BgLooper = dynamic(() => import("./bg-looper").then((mod) => mod.BgLooper) }); export const Hero = () => { - // const handlePressAnnouncement = (name: string, url: string) => { - // trackEvent("NavbarItem", { - // name, - // action: "press", - // category: "home - gero", - // data: url, - // }); - // }; + const handlePressAnnouncement = (name: string, url: string) => { + trackEvent("NavbarItem", { + name, + action: "press", + category: "home - gero", + data: url, + }); + }; return (
- {/* handlePressAnnouncement("Introducing v2.2.0", "/blog/v2.2.0")} + onClick={() => handlePressAnnouncement("Introducing v2.3.0", "/blog/v2.3.0")} > - Introducing v2.2.0  - - 🚀 + Introducing v2.3.0  + + 🎉 - */} +
diff --git a/apps/docs/components/mdx-components.tsx b/apps/docs/components/mdx-components.tsx index 565200bd1a..1071270d37 100644 --- a/apps/docs/components/mdx-components.tsx +++ b/apps/docs/components/mdx-components.tsx @@ -105,7 +105,7 @@ const List: React.FC<{children?: React.ReactNode}> = ({children}) => { const InlineCode = ({children}: {children?: React.ReactNode}) => { return ( - + {children} ); diff --git a/apps/docs/components/navbar.tsx b/apps/docs/components/navbar.tsx index d91b1431f3..19d70e3a40 100644 --- a/apps/docs/components/navbar.tsx +++ b/apps/docs/components/navbar.tsx @@ -16,6 +16,7 @@ import { DropdownMenu, DropdownItem, DropdownTrigger, + Chip, } from "@nextui-org/react"; import {dataFocusVisibleClasses} from "@nextui-org/theme"; import {ChevronDownIcon, LinkIcon} from "@nextui-org/shared-icons"; @@ -33,13 +34,7 @@ import {currentVersion} from "@/utils/version"; import {siteConfig} from "@/config/site"; import {Route} from "@/libs/docs/page"; import {LargeLogo, SmallLogo, ThemeSwitch} from "@/components"; -import { - TwitterIcon, - GithubIcon, - DiscordIcon, - HeartFilledIcon, - SearchLinearIcon, -} from "@/components/icons"; +import {TwitterIcon, GithubIcon, DiscordIcon, SearchLinearIcon} from "@/components/icons"; import {useIsMounted} from "@/hooks/use-is-mounted"; import {DocsSidebar} from "@/components/docs/sidebar"; import {useCmdkStore} from "@/components/cmdk"; @@ -312,6 +307,21 @@ export const Navbar: FC = ({children, routes, mobileRoutes = [], sl + + handlePressNavbarItem("Introducing v2.3.0", "/blog/v2.3.0")} + > + Introducing v2.3.0  + + 🎉 + + + = ({children, routes, mobileRoutes = [], sl {searchButton} - + {/* - + */} { // let deps = { - // "framer-motion": "10.12.16", + // "framer-motion": "11.0.22", // }; // if (hasComponents) { diff --git a/apps/docs/config/routes.json b/apps/docs/config/routes.json index 6d72ac7269..cdc90c4417 100644 --- a/apps/docs/config/routes.json +++ b/apps/docs/config/routes.json @@ -18,6 +18,13 @@ "keywords": "getting started, installation, start, nextui", "path": "/docs/guide/installation.mdx" }, + { + "key": "cli", + "title": "CLI", + "keywords": "cli, command line interface", + "path": "/docs/guide/cli.mdx", + "newPost": true + }, { "key": "design-principles", "title": "Design Principles", @@ -28,8 +35,7 @@ "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 + "path": "/docs/guide/routing.mdx" }, { "key": "upgrade-to-v2", @@ -85,7 +91,8 @@ { "key": "layout", "title": "Layout", - "path": "/docs/customization/layout.mdx" + "path": "/docs/customization/layout.mdx", + "updated": true }, { "key": "colors", @@ -141,8 +148,7 @@ "key": "autocomplete", "title": "Autocomplete", "keywords": "autocomplete, auto suggest, search, typeahead", - "path": "/docs/components/autocomplete.mdx", - "newPost": true + "path": "/docs/components/autocomplete.mdx" }, { "key": "badge", @@ -160,8 +166,7 @@ "key": "breadcrumbs", "title": "Breadcrumbs", "keywords": "breadcrumbs, navigation, path, trail, location", - "path": "/docs/components/breadcrumbs.mdx", - "newPost": true + "path": "/docs/components/breadcrumbs.mdx" }, { "key": "card", @@ -187,6 +192,32 @@ "keywords": "chip, tag, label, small actionable entity", "path": "/docs/components/chip.mdx" }, + { + "key": "code", + "title": "Code", + "keywords": "code, code snippet, inline code, coding", + "path": "/docs/components/code.mdx" + }, + { + "key": "input", + "title": "Input", + "keywords": "input, text box, form field, data entry", + "path": "/docs/components/input.mdx" + }, + { + "key": "date-input", + "title": "Date Input", + "keywords": "date-input, time, input, timezone", + "path": "/docs/components/date-input.mdx", + "newPost": true + }, + { + "key": "time-input", + "title": "Time Input", + "keywords": "timeinput, time, input, timezone", + "path": "/docs/components/time-input.mdx", + "newPost": true + }, { "key": "circular-progress", "title": "Circular Progress", @@ -194,10 +225,32 @@ "path": "/docs/components/circular-progress.mdx" }, { - "key": "code", - "title": "Code", - "keywords": "code, code snippet, inline code, coding", - "path": "/docs/components/code.mdx" + "key": "calendar", + "title": "Calendar", + "keywords": "calendar, date picker, month picker, year picker", + "path": "/docs/components/calendar.mdx", + "newPost": true + }, + { + "key": "range-calendar", + "title": "Range Calendar", + "keywords": "range calendar, date picker, month picker, year picker", + "path": "/docs/components/range-calendar.mdx", + "newPost": true + }, + { + "key": "date-picker", + "title": "Date Picker", + "keywords": "date-picker, time, input, timezone", + "path": "/docs/components/date-picker.mdx", + "newPost": true + }, + { + "key": "date-range-picker", + "title": "Date Range Picker", + "keywords": "date-range-picker, date-picker, time, input, timezone", + "path": "/docs/components/date-range-picker.mdx", + "newPost": true }, { "key": "divider", @@ -209,8 +262,7 @@ "key": "dropdown", "title": "Dropdown", "keywords": "dropdown, menu, selection, option list", - "path": "/docs/components/dropdown.mdx", - "updated": true + "path": "/docs/components/dropdown.mdx" }, { "key": "image", @@ -218,12 +270,6 @@ "keywords": "image, media, picture, photo, graphic display", "path": "/docs/components/image.mdx" }, - { - "key": "input", - "title": "Input", - "keywords": "input, text box, form field, data entry", - "path": "/docs/components/input.mdx" - }, { "key": "kbd", "title": "Kbd", @@ -234,15 +280,13 @@ "key": "link", "title": "Link", "keywords": "link, navigation, href, web page connection", - "path": "/docs/components/link.mdx", - "updated": true + "path": "/docs/components/link.mdx" }, { "key": "listbox", "title": "Listbox", "keywords": "listbox, selection, option list, multiple choice", - "path": "/docs/components/listbox.mdx", - "updated": true + "path": "/docs/components/listbox.mdx" }, { "key": "modal", @@ -326,8 +370,7 @@ "key": "slider", "title": "Slider", "keywords": "slider, range input, value selector, sliding control", - "path": "/docs/components/slider.mdx", - "newPost": true + "path": "/docs/components/slider.mdx" }, { "key": "table", @@ -346,8 +389,7 @@ "key": "textarea", "title": "Textarea", "keywords": "textarea, multi-line text input, large text field, form control", - "path": "/docs/components/textarea.mdx", - "updated": true + "path": "/docs/components/textarea.mdx" }, { "key": "tooltip", @@ -362,6 +404,26 @@ "path": "/docs/components/user.mdx" } ] + }, + { + "key": "api-references", + "title": "API References", + "defaultOpen": true, + "keywords": "api references, nextui, api", + "routes": [ + { + "key": "cli-api", + "title": "NextUI CLI", + "keywords": "api references, nextui, api, cli", + "path": "/docs/api-references/cli-api.mdx" + }, + { + "key": "nextui-provider", + "title": "NextUI Provider", + "keywords": "api references, nextui, api, nextui provider", + "path": "/docs/api-references/nextui-provider.mdx" + } + ] } ], "mobileRoutes": [ diff --git a/apps/docs/config/search-meta.json b/apps/docs/config/search-meta.json index d1d9c9a097..26bb62f6f1 100644 --- a/apps/docs/config/search-meta.json +++ b/apps/docs/config/search-meta.json @@ -1,28 +1,276 @@ [ + { + "content": "NextUI CLI", + "objectID": "e496f6b7-e82c-42af-88d0-5e528ec7bc71", + "type": "lvl1", + "url": "/docs/api-references/cli-api", + "hierarchy": { "lvl1": "NextUI CLI" } + }, + { + "content": "init", + "objectID": "c11c9112-be1f-4f9a-88a1-d75d11a772e8", + "type": "lvl2", + "url": "/docs/api-references/cli-api#init", + "hierarchy": { "lvl1": "NextUI CLI", "lvl2": "init", "lvl3": null } + }, + { + "content": "Options", + "objectID": "daef8085-7dd6-4ab4-aa1d-a47b85c06391", + "type": "lvl3", + "url": "/docs/api-references/cli-api#options", + "hierarchy": { "lvl1": "NextUI CLI", "lvl2": "init", "lvl3": "Options" } + }, + { + "content": "Example", + "objectID": "043bafe4-97d0-4747-b28d-1d8d8dd1ba0a", + "type": "lvl3", + "url": "/docs/api-references/cli-api#example", + "hierarchy": { "lvl1": "NextUI CLI", "lvl2": "Options", "lvl3": "Example" } + }, + { + "content": "add", + "objectID": "4c7e4e23-4cae-410f-bb66-941741ca793d", + "type": "lvl2", + "url": "/docs/api-references/cli-api#add", + "hierarchy": { "lvl1": "NextUI CLI", "lvl2": "add", "lvl3": null } + }, + { + "content": "Options", + "objectID": "099f14f5-63b7-4303-acf6-09747e555f5e", + "type": "lvl3", + "url": "/docs/api-references/cli-api#options-1", + "hierarchy": { "lvl1": "NextUI CLI", "lvl2": "add", "lvl3": "Options" } + }, + { + "content": "Example", + "objectID": "80df6ba1-999e-4190-8253-486a3cc92192", + "type": "lvl3", + "url": "/docs/api-references/cli-api#example-1", + "hierarchy": { "lvl1": "NextUI CLI", "lvl2": "Options", "lvl3": "Example" } + }, + { + "content": "upgrade", + "objectID": "7179cb51-eeda-45d6-bf5d-840d3e7480ee", + "type": "lvl2", + "url": "/docs/api-references/cli-api#upgrade", + "hierarchy": { "lvl1": "NextUI CLI", "lvl2": "upgrade", "lvl3": null } + }, + { + "content": "Options", + "objectID": "69b44c5f-6e9d-409b-b9f1-f7df39dde20d", + "type": "lvl3", + "url": "/docs/api-references/cli-api#options-2", + "hierarchy": { "lvl1": "NextUI CLI", "lvl2": "upgrade", "lvl3": "Options" } + }, + { + "content": "Example", + "objectID": "b5a9b381-6d4d-4d5f-96b9-e34fcfeb0bf1", + "type": "lvl3", + "url": "/docs/api-references/cli-api#example-2", + "hierarchy": { "lvl1": "NextUI CLI", "lvl2": "Options", "lvl3": "Example" } + }, + { + "content": "remove", + "objectID": "63ee5d85-d176-41c3-8613-c816a9f971c9", + "type": "lvl2", + "url": "/docs/api-references/cli-api#remove", + "hierarchy": { "lvl1": "NextUI CLI", "lvl2": "remove", "lvl3": null } + }, + { + "content": "Options", + "objectID": "958fc744-dd61-4103-b8d4-000dedd01975", + "type": "lvl3", + "url": "/docs/api-references/cli-api#options-3", + "hierarchy": { "lvl1": "NextUI CLI", "lvl2": "remove", "lvl3": "Options" } + }, + { + "content": "Example", + "objectID": "d3c7c402-0f1b-439f-9c91-a071579f685d", + "type": "lvl3", + "url": "/docs/api-references/cli-api#example-3", + "hierarchy": { "lvl1": "NextUI CLI", "lvl2": "Options", "lvl3": "Example" } + }, + { + "content": "list", + "objectID": "921c7c6d-3c11-4e96-a074-16e79c1d6f80", + "type": "lvl2", + "url": "/docs/api-references/cli-api#list", + "hierarchy": { "lvl1": "NextUI CLI", "lvl2": "list", "lvl3": null } + }, + { + "content": "Options", + "objectID": "7c395592-6c9b-4b93-a07a-039b4132527a", + "type": "lvl3", + "url": "/docs/api-references/cli-api#options-4", + "hierarchy": { "lvl1": "NextUI CLI", "lvl2": "list", "lvl3": "Options" } + }, + { + "content": "Example", + "objectID": "99e17560-4d9c-4b7f-850a-da58f22d9397", + "type": "lvl3", + "url": "/docs/api-references/cli-api#example-4", + "hierarchy": { "lvl1": "NextUI CLI", "lvl2": "Options", "lvl3": "Example" } + }, + { + "content": "doctor", + "objectID": "5a0406ce-ed0f-46fd-9cfd-088a7067d713", + "type": "lvl2", + "url": "/docs/api-references/cli-api#doctor", + "hierarchy": { "lvl1": "NextUI CLI", "lvl2": "doctor", "lvl3": null } + }, + { + "content": "Options", + "objectID": "14d04805-edd0-488b-b519-7e25e406fc3b", + "type": "lvl3", + "url": "/docs/api-references/cli-api#options-5", + "hierarchy": { "lvl1": "NextUI CLI", "lvl2": "doctor", "lvl3": "Options" } + }, + { + "content": "Example", + "objectID": "5c8339e9-7328-4db4-baf1-a8ffa0c07e3e", + "type": "lvl3", + "url": "/docs/api-references/cli-api#example-5", + "hierarchy": { "lvl1": "NextUI CLI", "lvl2": "Options", "lvl3": "Example" } + }, + { + "content": "env", + "objectID": "e00f8465-5ed6-4a1c-b4cf-88fd4b9a72e0", + "type": "lvl2", + "url": "/docs/api-references/cli-api#env", + "hierarchy": { "lvl1": "NextUI CLI", "lvl2": "env", "lvl3": null } + }, + { + "content": "Options", + "objectID": "52e1ceee-7848-4ef6-99ea-3b8aea2a9b72", + "type": "lvl3", + "url": "/docs/api-references/cli-api#options-6", + "hierarchy": { "lvl1": "NextUI CLI", "lvl2": "env", "lvl3": "Options" } + }, + { + "content": "Example", + "objectID": "2fa0f558-10f0-4408-aa27-facfd62a4582", + "type": "lvl3", + "url": "/docs/api-references/cli-api#example-6", + "hierarchy": { "lvl1": "NextUI CLI", "lvl2": "Options", "lvl3": "Example" } + }, + { + "content": "NextUI Provider", + "objectID": "c951ffe5-921a-4662-9bea-b10c848b1b25", + "type": "lvl1", + "url": "/docs/api-references/nextui-provider", + "hierarchy": { "lvl1": "NextUI Provider" } + }, + { + "content": "Props", + "objectID": "43f70803-76eb-457c-89f7-c2a70eb23b2c", + "type": "lvl2", + "url": "/docs/api-references/nextui-provider#props", + "hierarchy": { "lvl1": "NextUI Provider", "lvl2": "Props", "lvl3": null } + }, + { + "content": "navigate", + "objectID": "fffabecd-658a-4973-aaf1-103fa4b89b67", + "type": "lvl3", + "url": "/docs/api-references/nextui-provider#navigate", + "hierarchy": { + "lvl1": "NextUI Provider", + "lvl2": "Props", + "lvl3": "navigate" + } + }, + { + "content": "locale", + "objectID": "1aeb10df-e1f5-49c9-b5dd-5996cf566361", + "type": "lvl3", + "url": "/docs/api-references/nextui-provider#locale", + "hierarchy": { + "lvl1": "NextUI Provider", + "lvl2": "navigate", + "lvl3": "locale" + } + }, + { + "content": "defaultDates", + "objectID": "f3e72d3f-fe27-4d99-8c28-db8dbf3a86a2", + "type": "lvl3", + "url": "/docs/api-references/nextui-provider#defaultdates", + "hierarchy": { + "lvl1": "NextUI Provider", + "lvl2": "locale", + "lvl3": "defaultDates" + } + }, + { + "content": "createCalendar", + "objectID": "9418d25d-55de-447e-96c8-9a4366d31b95", + "type": "lvl3", + "url": "/docs/api-references/nextui-provider#createcalendar", + "hierarchy": { + "lvl1": "NextUI Provider", + "lvl2": "defaultDates", + "lvl3": "createCalendar" + } + }, + { + "content": "Types", + "objectID": "19f0447b-0f55-4030-ada2-2285d2da5573", + "type": "lvl2", + "url": "/docs/api-references/nextui-provider#types", + "hierarchy": { "lvl1": "NextUI Provider", "lvl2": "Types", "lvl3": null } + }, + { + "content": "CalendarDate", + "objectID": "f8a3e3e1-07c2-41ec-be47-96eb441258e0", + "type": "lvl3", + "url": "/docs/api-references/nextui-provider#calendardate", + "hierarchy": { + "lvl1": "NextUI Provider", + "lvl2": "Types", + "lvl3": "CalendarDate" + } + }, + { + "content": "SupportedCalendars", + "objectID": "fb9e685a-8680-4fe1-9876-23d1d129aaac", + "type": "lvl3", + "url": "/docs/api-references/nextui-provider#supportedcalendars", + "hierarchy": { + "lvl1": "NextUI Provider", + "lvl2": "CalendarDate", + "lvl3": "SupportedCalendars" + } + }, { "content": "Accordion", - "objectID": "a5af1508-c6cf-4ac0-9848-846ea8a4ed35", + "objectID": "86be0b63-96e6-4b54-a052-9b204eabf4f2", "type": "lvl1", "url": "/docs/components/accordion", "hierarchy": { "lvl1": "Accordion" } }, + { + "content": "Installation", + "objectID": "cd6e357d-6ff0-48da-af5e-91b1ac7b6fbb", + "type": "lvl2", + "url": "/docs/components/accordion#installation", + "hierarchy": { "lvl1": "Accordion", "lvl2": "Installation", "lvl3": null } + }, { "content": "Import", - "objectID": "5fce2822-a651-49f5-8a78-2877444766a0", + "objectID": "07ac69c7-c1a5-4e79-8c79-95c1361349cc", "type": "lvl2", "url": "/docs/components/accordion#import", "hierarchy": { "lvl1": "Accordion", "lvl2": "Import", "lvl3": null } }, { "content": "Usage", - "objectID": "daa9553c-6f06-460b-a3c1-cab492890f39", + "objectID": "21450940-ebc0-4ece-a50f-b944298392a9", "type": "lvl2", "url": "/docs/components/accordion#usage", "hierarchy": { "lvl1": "Accordion", "lvl2": "Usage", "lvl3": null } }, { "content": "With Subtitle", - "objectID": "057680f3-c38c-4f18-a3f9-22d13d1dcc1c", + "objectID": "5a757a24-2d44-4973-9424-9bd5d83abc44", "type": "lvl3", "url": "/docs/components/accordion#with-subtitle", "hierarchy": { @@ -33,7 +281,7 @@ }, { "content": "Expand multiple items", - "objectID": "06e11bdc-8b7f-41bb-ad9e-e107cc47892b", + "objectID": "f125892e-96eb-4363-bb86-b8356deaf68d", "type": "lvl3", "url": "/docs/components/accordion#expand-multiple-items", "hierarchy": { @@ -44,7 +292,7 @@ }, { "content": "Compact", - "objectID": "a62d5476-65cc-4a48-8c48-61c6dbbf726c", + "objectID": "8b274b03-924d-403f-a2fa-7f165bd2749c", "type": "lvl3", "url": "/docs/components/accordion#compact", "hierarchy": { @@ -55,35 +303,35 @@ }, { "content": "Variants", - "objectID": "fcb9e164-5c26-41ae-aa87-30ebdd0453f0", + "objectID": "027a8f0a-8213-41f4-b4ab-dc95f18477af", "type": "lvl3", "url": "/docs/components/accordion#variants", "hierarchy": { "lvl1": "Accordion", "lvl2": "Compact", "lvl3": "Variants" } }, { "content": "Light variant", - "objectID": "f427757d-5643-4110-bcfe-b9cf36a5ab56", + "objectID": "888c3b26-c866-4427-86de-14906a371348", "type": "lvl4", "url": "/docs/components/accordion#light-variant", "hierarchy": { "lvl1": "Accordion", "lvl2": "Variants", "lvl3": null } }, { "content": "Shadow variant", - "objectID": "2feaca14-6c40-4ae1-9c12-7ee9755d9c50", + "objectID": "e409cbaf-a7a3-4369-b4ed-d1971bf6b3aa", "type": "lvl4", "url": "/docs/components/accordion#shadow-variant", "hierarchy": { "lvl1": "Accordion", "lvl2": "Light variant", "lvl3": null } }, { "content": "Bordered variant", - "objectID": "e4a8476d-e70d-4c4d-8c75-8e0b8415b0c1", + "objectID": "fd1726b1-50f8-4d5a-b1c2-0bc98b3ada4d", "type": "lvl4", "url": "/docs/components/accordion#bordered-variant", "hierarchy": { "lvl1": "Accordion", "lvl2": "Shadow variant", "lvl3": null } }, { "content": "Splitted variant", - "objectID": "5fb16c63-162f-4024-bf42-3be5283faf8b", + "objectID": "d6e6ddb6-f6eb-46c0-bac4-34d8e5d54b2b", "type": "lvl4", "url": "/docs/components/accordion#splitted-variant", "hierarchy": { @@ -94,7 +342,7 @@ }, { "content": "Default expanded keys", - "objectID": "b56c82a9-56f2-42f7-9e16-50b37f241780", + "objectID": "6ff232b4-7d41-4615-bea2-6565213905da", "type": "lvl3", "url": "/docs/components/accordion#default-expanded-keys", "hierarchy": { @@ -105,7 +353,7 @@ }, { "content": "Disabled keys", - "objectID": "c65ef31c-14e8-4876-9d15-0aeba5f59c59", + "objectID": "9816e00a-a992-4686-a5ce-e1677afb27df", "type": "lvl3", "url": "/docs/components/accordion#disabled-keys", "hierarchy": { @@ -116,7 +364,7 @@ }, { "content": "Start content", - "objectID": "2c1ca688-83bd-48be-9ddf-89b9fa513a82", + "objectID": "0ef7b942-efb5-40bc-a1c7-c55781d43047", "type": "lvl3", "url": "/docs/components/accordion#start-content", "hierarchy": { @@ -127,7 +375,7 @@ }, { "content": "Custom Indicator", - "objectID": "3dae1ea8-9cea-484e-9b61-d1bf864649c3", + "objectID": "461a0f16-7401-4401-b08f-391271a92365", "type": "lvl3", "url": "/docs/components/accordion#custom-indicator", "hierarchy": { @@ -138,7 +386,7 @@ }, { "content": "Custom Motion", - "objectID": "90afee3a-b0f5-4351-b813-1251f5d0102d", + "objectID": "2a5dc7d5-7355-4902-998b-e5de1639e78d", "type": "lvl3", "url": "/docs/components/accordion#custom-motion", "hierarchy": { @@ -149,7 +397,7 @@ }, { "content": "Controlled", - "objectID": "ef485d8e-1967-4f88-ba2b-954fd1179d78", + "objectID": "c335e125-2356-4b59-8f07-af00a861af1c", "type": "lvl3", "url": "/docs/components/accordion#controlled", "hierarchy": { @@ -160,7 +408,7 @@ }, { "content": "Accordion Item Slots", - "objectID": "9d410eed-9e50-4a9d-ba7e-c8befdd4f48c", + "objectID": "f7f95af2-a4a6-4802-9823-c28dd933952c", "type": "lvl2", "url": "/docs/components/accordion#accordion-item-slots", "hierarchy": { @@ -171,7 +419,7 @@ }, { "content": "Custom Accordion Styles", - "objectID": "0ff45cd3-0318-4355-ba36-95b3a5365bd9", + "objectID": "b2dbef14-c2ca-4a3b-93df-d839c2afee20", "type": "lvl3", "url": "/docs/components/accordion#custom-accordion-styles", "hierarchy": { @@ -182,7 +430,7 @@ }, { "content": "Data Attributes", - "objectID": "b6143e1d-465c-4584-a1f1-9f7a0122a125", + "objectID": "7318af55-3ea0-4312-9cc1-522c98b8b91f", "type": "lvl2", "url": "/docs/components/accordion#data-attributes", "hierarchy": { @@ -193,21 +441,21 @@ }, { "content": "Accessibility", - "objectID": "d53ef652-6949-48bc-8113-02a157619b15", + "objectID": "a348fc15-f115-42c1-98ca-0c0015cfc575", "type": "lvl2", "url": "/docs/components/accordion#accessibility", "hierarchy": { "lvl1": "Accordion", "lvl2": "Accessibility", "lvl3": null } }, { "content": "API", - "objectID": "4b9b5255-2bdb-4f63-a448-2a458b3d5bc3", + "objectID": "e44c37be-6396-4eb6-ab23-468e1063a358", "type": "lvl2", "url": "/docs/components/accordion#api", "hierarchy": { "lvl1": "Accordion", "lvl2": "API", "lvl3": null } }, { "content": "Accordion Props", - "objectID": "4840e3b7-da2f-4384-8bc1-1f67166957ba", + "objectID": "ef63d82f-4813-4466-a881-4d101a901d7e", "type": "lvl3", "url": "/docs/components/accordion#accordion-props", "hierarchy": { @@ -218,7 +466,7 @@ }, { "content": "Accordion Events", - "objectID": "6973f2c0-2f23-4e55-844a-75e0e9cfcc62", + "objectID": "61ebf045-128f-4937-8662-8b356a260b77", "type": "lvl3", "url": "/docs/components/accordion#accordion-events", "hierarchy": { @@ -229,7 +477,7 @@ }, { "content": "Accordion Item Props", - "objectID": "f3724cab-a678-4ed7-96e4-34a693c55ec5", + "objectID": "ecf19416-89d9-449f-ad11-8920a0bcaa5f", "type": "lvl3", "url": "/docs/components/accordion#accordion-item-props", "hierarchy": { @@ -240,7 +488,7 @@ }, { "content": "Accordion Item Events", - "objectID": "f19e73c0-d48e-4d9c-995c-df6a4b373885", + "objectID": "9cb509cf-e360-4974-a1e0-dcdb54edcf7a", "type": "lvl3", "url": "/docs/components/accordion#accordion-item-events", "hierarchy": { @@ -251,7 +499,7 @@ }, { "content": "Types", - "objectID": "0987d202-7b91-4535-8bce-c2104985bf52", + "objectID": "8109dccf-4008-4070-a769-49a5cc1b7d7f", "type": "lvl3", "url": "/docs/components/accordion#types", "hierarchy": { @@ -262,14 +510,14 @@ }, { "content": "Accordion Item Indicator Props", - "objectID": "be8e6f6e-3e7d-4ddd-8b8e-0c2ca58ff483", + "objectID": "8aacc034-5480-493f-b562-5fc19f276815", "type": "lvl4", "url": "/docs/components/accordion#accordion-item-indicator-props", "hierarchy": { "lvl1": "Accordion", "lvl2": "Types", "lvl3": null } }, { "content": "Accordion Item classNames", - "objectID": "bb0c17fa-f21d-40ff-9118-2fb0e4e62e20", + "objectID": "5fba150b-5b6b-41ac-a7aa-b5695905649f", "type": "lvl3", "url": "/docs/components/accordion#accordion-item-classnames", "hierarchy": { @@ -280,7 +528,7 @@ }, { "content": "Motion Props", - "objectID": "70d9c759-1e15-408d-8b19-e2951a73d371", + "objectID": "8e361e09-ceda-4494-9215-18465038946b", "type": "lvl4", "url": "/docs/components/accordion#motion-props", "hierarchy": { @@ -291,28 +539,39 @@ }, { "content": "Autocomplete", - "objectID": "d6fe40ed-8c5e-482f-849c-3df7294d8c05", + "objectID": "3becd62f-9d70-4cd0-abcd-7af2f64cb7a7", "type": "lvl1", "url": "/docs/components/autocomplete", "hierarchy": { "lvl1": "Autocomplete" } }, + { + "content": "Installation", + "objectID": "4621be9a-8e76-49e9-8efb-747e0dc40248", + "type": "lvl2", + "url": "/docs/components/autocomplete#installation", + "hierarchy": { + "lvl1": "Autocomplete", + "lvl2": "Installation", + "lvl3": null + } + }, { "content": "Import", - "objectID": "b0dcb6ef-b111-45f7-8735-cf61ee7df315", + "objectID": "644c1971-f7b0-4b99-8354-ad7f2900e92b", "type": "lvl2", "url": "/docs/components/autocomplete#import", "hierarchy": { "lvl1": "Autocomplete", "lvl2": "Import", "lvl3": null } }, { "content": "Usage", - "objectID": "1f09af5f-45fc-4a7c-8302-ee9ede54143c", + "objectID": "23b83c99-9f7d-4d51-b896-8d4b18418db1", "type": "lvl2", "url": "/docs/components/autocomplete#usage", "hierarchy": { "lvl1": "Autocomplete", "lvl2": "Usage", "lvl3": null } }, { "content": "Dynamic items", - "objectID": "1f0ff8a5-b017-4192-b9de-b8b49e6f7e84", + "objectID": "87a9494c-4de8-4a1d-beca-6ea76d131fcb", "type": "lvl3", "url": "/docs/components/autocomplete#dynamic-items", "hierarchy": { @@ -323,7 +582,7 @@ }, { "content": "Disabled", - "objectID": "89b47bae-53bb-4c31-bb63-35cd0ded4962", + "objectID": "ac4c838f-01aa-406a-b3ed-278df8b670ca", "type": "lvl3", "url": "/docs/components/autocomplete#disabled", "hierarchy": { @@ -334,7 +593,7 @@ }, { "content": "Disabled Items", - "objectID": "1ca51f2c-f643-46ac-b5a3-a15ebad18dda", + "objectID": "cfe2f0f6-04b2-4946-8359-e45d772e9b6d", "type": "lvl3", "url": "/docs/components/autocomplete#disabled-items", "hierarchy": { @@ -345,7 +604,7 @@ }, { "content": "Required", - "objectID": "c4fb9e69-0023-4606-ad78-89c8eb9ef7a1", + "objectID": "ae913601-c241-4c20-a695-f6488802a308", "type": "lvl3", "url": "/docs/components/autocomplete#required", "hierarchy": { @@ -356,21 +615,21 @@ }, { "content": "Sizes", - "objectID": "bd2a5f4d-1d64-4a44-89a2-0706b08d92e7", + "objectID": "914609ae-d437-422b-90f1-a415ff2e6c67", "type": "lvl3", "url": "/docs/components/autocomplete#sizes", "hierarchy": { "lvl1": "Autocomplete", "lvl2": "Required", "lvl3": "Sizes" } }, { "content": "Colors", - "objectID": "3f713357-d3f8-49ae-b58e-e784878a978f", + "objectID": "8462a655-c43a-45a9-ba0b-8abcdcc56246", "type": "lvl3", "url": "/docs/components/autocomplete#colors", "hierarchy": { "lvl1": "Autocomplete", "lvl2": "Sizes", "lvl3": "Colors" } }, { "content": "Variants", - "objectID": "81d92888-9033-4b9c-9595-a1e1c082aa30", + "objectID": "5fe3392e-d7d5-415f-85a0-a9252cafb8e6", "type": "lvl3", "url": "/docs/components/autocomplete#variants", "hierarchy": { @@ -381,7 +640,7 @@ }, { "content": "Label Placements", - "objectID": "62c1b598-2ebf-4a81-8cfc-0246c803e35e", + "objectID": "8b0774b1-5fa9-4b45-8bda-1c892c346693", "type": "lvl3", "url": "/docs/components/autocomplete#label-placements", "hierarchy": { @@ -392,7 +651,7 @@ }, { "content": "Start Content", - "objectID": "d98e918c-f530-4788-b2ed-0fc8047129a4", + "objectID": "7f4f6c39-c5a4-4120-9ed2-e7a34f2932e3", "type": "lvl3", "url": "/docs/components/autocomplete#start-content", "hierarchy": { @@ -403,7 +662,7 @@ }, { "content": "Item Start & End Content", - "objectID": "f859f2b8-c0e1-491a-bf90-807d7e7fcd97", + "objectID": "f4ca4433-3988-4468-aaea-4a6eac268434", "type": "lvl3", "url": "/docs/components/autocomplete#item-start--end-content", "hierarchy": { @@ -414,7 +673,7 @@ }, { "content": "Custom Value", - "objectID": "00c353ff-0fff-47b8-83b6-e4b04c84289c", + "objectID": "df83129f-e8ad-4441-92c1-bbb3386b7bf5", "type": "lvl3", "url": "/docs/components/autocomplete#custom-value", "hierarchy": { @@ -425,7 +684,7 @@ }, { "content": "Custom Selector Icon", - "objectID": "89f286ac-08f2-45a1-b238-1cecf9c35470", + "objectID": "df5b4cb9-f863-4059-a711-ee18c448d71e", "type": "lvl3", "url": "/docs/components/autocomplete#custom-selector-icon", "hierarchy": { @@ -436,7 +695,7 @@ }, { "content": "Without Scroll Shadow", - "objectID": "71ded82e-4e25-4288-a339-0d66e1276fc1", + "objectID": "64b0d65b-b40e-4ab6-8cf9-937849a41d08", "type": "lvl3", "url": "/docs/components/autocomplete#without-scroll-shadow", "hierarchy": { @@ -447,7 +706,7 @@ }, { "content": "With Description", - "objectID": "95df78c0-e529-451b-97e6-1bdf67630d07", + "objectID": "db55ccd8-d8d7-4575-8517-d914ed95ad24", "type": "lvl3", "url": "/docs/components/autocomplete#with-description", "hierarchy": { @@ -458,7 +717,7 @@ }, { "content": "With Error Message", - "objectID": "b1d37371-c82a-4748-81de-00b96ecdae06", + "objectID": "6ec8d383-ee94-4989-9cdd-d659d2367978", "type": "lvl3", "url": "/docs/components/autocomplete#with-error-message", "hierarchy": { @@ -469,7 +728,7 @@ }, { "content": "Events", - "objectID": "98cbf94c-c78f-4af6-a000-b3e3230e043d", + "objectID": "1de6fad9-f41d-4c10-b3dc-e20d3f713da0", "type": "lvl3", "url": "/docs/components/autocomplete#events", "hierarchy": { @@ -480,7 +739,7 @@ }, { "content": "Controlled", - "objectID": "6bd5b4cf-604f-4348-a4fe-7f6ed4bf9fd8", + "objectID": "3b7af639-4ce6-475c-900d-bc35d3c5a405", "type": "lvl3", "url": "/docs/components/autocomplete#controlled", "hierarchy": { @@ -491,7 +750,7 @@ }, { "content": "Fully Controlled", - "objectID": "4512af97-a38c-4da7-85f5-fc0d82ff630b", + "objectID": "2f0e5117-4dc9-4fd0-85fd-a49254c3c2ef", "type": "lvl3", "url": "/docs/components/autocomplete#fully-controlled", "hierarchy": { @@ -502,7 +761,7 @@ }, { "content": "Custom Items", - "objectID": "f9487e85-ca3b-431a-a3ab-451e0ac0c1ee", + "objectID": "df92cd1e-aa96-4652-a73d-7dba6427e2b8", "type": "lvl3", "url": "/docs/components/autocomplete#custom-items", "hierarchy": { @@ -513,7 +772,7 @@ }, { "content": "Custom Filtering", - "objectID": "1eac825f-024f-42ce-b28c-f02ec62b1c63", + "objectID": "00bc06dc-9b5e-432f-8734-830aedaaecb9", "type": "lvl3", "url": "/docs/components/autocomplete#custom-filtering", "hierarchy": { @@ -524,7 +783,7 @@ }, { "content": "Asynchronous Filtering", - "objectID": "01902765-2129-493c-8235-afd3486ab4c6", + "objectID": "70d420e2-167a-4089-b229-b0cafe2320a1", "type": "lvl3", "url": "/docs/components/autocomplete#asynchronous-filtering", "hierarchy": { @@ -535,7 +794,7 @@ }, { "content": "Asynchronous Loading", - "objectID": "4e6ce752-7227-45e7-8dc7-6164b8be8add", + "objectID": "d1dc3946-853e-47ac-88e6-d11141a93db0", "type": "lvl3", "url": "/docs/components/autocomplete#asynchronous-loading", "hierarchy": { @@ -546,7 +805,7 @@ }, { "content": "With Sections", - "objectID": "0c555b4d-1854-4318-9f76-629cb455b2e2", + "objectID": "e5c8af81-4fb7-400c-be37-6379f50f955b", "type": "lvl3", "url": "/docs/components/autocomplete#with-sections", "hierarchy": { @@ -557,7 +816,7 @@ }, { "content": "Custom Sections Style", - "objectID": "2f6440de-ddac-4067-84a7-05c660fa62eb", + "objectID": "c36945d3-9656-4ea8-b2ec-a4f4b7b0d9b6", "type": "lvl3", "url": "/docs/components/autocomplete#custom-sections-style", "hierarchy": { @@ -568,7 +827,7 @@ }, { "content": "Customizing the Autocomplete", - "objectID": "db02db3a-7132-4136-b721-cd44a8e12cd0", + "objectID": "8c67a5ce-65f0-49fc-8ed2-2cb0648a91db", "type": "lvl3", "url": "/docs/components/autocomplete#customizing-the-autocomplete", "hierarchy": { @@ -579,14 +838,14 @@ }, { "content": "Slots", - "objectID": "90702fad-555b-41fa-aa9e-ed9cc172207c", + "objectID": "ae3d4a3d-28cd-4f55-8e29-588c2d637425", "type": "lvl2", "url": "/docs/components/autocomplete#slots", "hierarchy": { "lvl1": "Autocomplete", "lvl2": "Slots", "lvl3": null } }, { "content": "Data Attributes", - "objectID": "a16e08d4-5cb2-46b8-9267-dcf0dc7b35d5", + "objectID": "2591a995-1059-4996-b743-06cb2e5cf684", "type": "lvl2", "url": "/docs/components/autocomplete#data-attributes", "hierarchy": { @@ -597,7 +856,7 @@ }, { "content": "Accessibility", - "objectID": "7189de21-cf2f-4bea-b5f6-b068b9a2873e", + "objectID": "cd6820ad-4a40-4a65-8fc0-1f80208a515f", "type": "lvl2", "url": "/docs/components/autocomplete#accessibility", "hierarchy": { @@ -608,14 +867,14 @@ }, { "content": "API", - "objectID": "01845dbc-9129-4d30-9288-3e544b5d6f43", + "objectID": "4607a4f8-0967-49f6-9f91-630c2ef3aa19", "type": "lvl2", "url": "/docs/components/autocomplete#api", "hierarchy": { "lvl1": "Autocomplete", "lvl2": "API", "lvl3": null } }, { "content": "Autocomplete Props", - "objectID": "97a024b4-c825-4075-8306-f67eda1a5fc7", + "objectID": "75c5d4f4-822e-4de8-8950-cdf242294761", "type": "lvl3", "url": "/docs/components/autocomplete#autocomplete-props", "hierarchy": { @@ -626,7 +885,7 @@ }, { "content": "Autocomplete Events", - "objectID": "b28ed05f-df76-4478-92dd-861a2f960fb9", + "objectID": "363af6c5-c4e3-4798-becb-e949ed005b9a", "type": "lvl3", "url": "/docs/components/autocomplete#autocomplete-events", "hierarchy": { @@ -637,7 +896,7 @@ }, { "content": "AutocompleteItem Props", - "objectID": "6c009b2c-f8e0-4c4b-9170-ca3f3a3e358e", + "objectID": "224f3b6b-ef2a-4df4-b1df-790c87b45b3b", "type": "lvl3", "url": "/docs/components/autocomplete#autocompleteitem-props", "hierarchy": { @@ -648,7 +907,7 @@ }, { "content": "AutocompleteItem Events", - "objectID": "97b26921-4290-4107-b774-2981da7c4de9", + "objectID": "80885383-ed85-49fd-b985-611e38299d9d", "type": "lvl3", "url": "/docs/components/autocomplete#autocompleteitem-events", "hierarchy": { @@ -659,7 +918,7 @@ }, { "content": "AutocompleteSection Props", - "objectID": "ef363c29-e1e9-45d0-976b-79bc78b73878", + "objectID": "245b3ad9-70f5-43a2-9748-2518e516a858", "type": "lvl3", "url": "/docs/components/autocomplete#autocompletesection-props", "hierarchy": { @@ -670,7 +929,7 @@ }, { "content": "Types", - "objectID": "f2f995ea-591e-4c80-a1aa-b77cd0cb5227", + "objectID": "496986c0-9694-4cce-b15a-6ac1c84cbedc", "type": "lvl3", "url": "/docs/components/autocomplete#types", "hierarchy": { @@ -681,70 +940,77 @@ }, { "content": "Menu Trigger Action", - "objectID": "fa9a8da0-3a48-4c1a-bd08-46b668d5fea7", + "objectID": "61a66fd8-ae17-4339-8b4a-ade6b942283b", "type": "lvl4", "url": "/docs/components/autocomplete#menu-trigger-action", "hierarchy": { "lvl1": "Autocomplete", "lvl2": "Types", "lvl3": null } }, { "content": "Avatar", - "objectID": "a73ceedc-07be-400b-ac35-586a665c14ae", + "objectID": "29c38e92-affc-47af-964f-b229d2583e0a", "type": "lvl1", "url": "/docs/components/avatar", "hierarchy": { "lvl1": "Avatar" } }, + { + "content": "Installation", + "objectID": "0f433b11-15af-4242-aefe-02b5c17212ce", + "type": "lvl2", + "url": "/docs/components/avatar#installation", + "hierarchy": { "lvl1": "Avatar", "lvl2": "Installation", "lvl3": null } + }, { "content": "Import", - "objectID": "e4e860be-4c38-4dd4-aa0e-c6d0bb441abe", + "objectID": "89787991-5d9a-4ad7-9276-7b27ad85232b", "type": "lvl2", "url": "/docs/components/avatar#import", "hierarchy": { "lvl1": "Avatar", "lvl2": "Import", "lvl3": null } }, { "content": "Usage", - "objectID": "fab6063b-2f48-4416-ae99-38cdd1c6de63", + "objectID": "cdf01bae-0daf-48c4-96b6-49c794a54d55", "type": "lvl2", "url": "/docs/components/avatar#usage", "hierarchy": { "lvl1": "Avatar", "lvl2": "Usage", "lvl3": null } }, { "content": "Sizes", - "objectID": "5927cb9c-a8c1-4165-ab15-c241c069a8cc", + "objectID": "fb4f4754-a55f-4520-8823-7dc9b6119500", "type": "lvl3", "url": "/docs/components/avatar#sizes", "hierarchy": { "lvl1": "Avatar", "lvl2": "Usage", "lvl3": "Sizes" } }, { "content": "Disabled", - "objectID": "7da4e3fb-3515-4b8b-9c0c-426d90a71b2b", + "objectID": "a20290e1-9b1e-45a6-93df-c2a1e011b534", "type": "lvl3", "url": "/docs/components/avatar#disabled", "hierarchy": { "lvl1": "Avatar", "lvl2": "Sizes", "lvl3": "Disabled" } }, { "content": "Bordered", - "objectID": "bd0e27f2-78c2-4cf4-b99a-8ccf70285550", + "objectID": "8ab0e93a-d8b0-487e-a31e-dfcbe81a2466", "type": "lvl3", "url": "/docs/components/avatar#bordered", "hierarchy": { "lvl1": "Avatar", "lvl2": "Disabled", "lvl3": "Bordered" } }, { "content": "Radius", - "objectID": "41732ce6-bae6-4fed-a8db-9aebb6c70b4d", + "objectID": "d67eba4a-41d4-402c-9ae2-90723cfb8e7c", "type": "lvl3", "url": "/docs/components/avatar#radius", "hierarchy": { "lvl1": "Avatar", "lvl2": "Bordered", "lvl3": "Radius" } }, { "content": "Colors", - "objectID": "96e17399-99a3-4b5e-8541-290cb5e61881", + "objectID": "5f5a8c69-e7c4-43e1-9d72-2aecaa99193b", "type": "lvl3", "url": "/docs/components/avatar#colors", "hierarchy": { "lvl1": "Avatar", "lvl2": "Radius", "lvl3": "Colors" } }, { "content": "Avatar Fallbacks", - "objectID": "5b2f18b2-1ecd-4d05-8416-8613f9f9f890", + "objectID": "0b5b1cb8-c741-43de-9be8-2fedcce85054", "type": "lvl3", "url": "/docs/components/avatar#avatar-fallbacks", "hierarchy": { @@ -755,7 +1021,7 @@ }, { "content": "Custom Fallback", - "objectID": "d2e9df08-4f64-46d0-a159-69b7b79899e7", + "objectID": "912816be-48e9-449c-9f7b-0ea5e55a0b94", "type": "lvl3", "url": "/docs/components/avatar#custom-fallback", "hierarchy": { @@ -766,7 +1032,7 @@ }, { "content": "Custom Implementation", - "objectID": "c1767375-2ea0-4dc2-bd8a-d5d7c929ee6c", + "objectID": "12238cc8-a0e8-42e7-971d-79cbed64e996", "type": "lvl3", "url": "/docs/components/avatar#custom-implementation", "hierarchy": { @@ -777,7 +1043,7 @@ }, { "content": "Custom initials logic", - "objectID": "2e3b1cd3-ec57-4653-8ca5-7d668f50bccd", + "objectID": "5c9cc76c-9850-4abb-8f97-ff8a4002e8f2", "type": "lvl3", "url": "/docs/components/avatar#custom-initials-logic", "hierarchy": { @@ -788,14 +1054,14 @@ }, { "content": "Avatar Group", - "objectID": "961ded72-8882-4c58-b4f5-1e19e26f1862", + "objectID": "68cf3750-7d1f-4d32-8418-ee85ee55b645", "type": "lvl2", "url": "/docs/components/avatar#avatar-group", "hierarchy": { "lvl1": "Avatar", "lvl2": "Avatar Group", "lvl3": null } }, { "content": "Group Disabled", - "objectID": "43296cab-5fcd-438d-8466-9d97448a0abd", + "objectID": "b02c35ee-1077-458d-9cbb-560c382c6974", "type": "lvl3", "url": "/docs/components/avatar#group-disabled", "hierarchy": { @@ -806,7 +1072,7 @@ }, { "content": "Group Max Count", - "objectID": "3aa09015-0c7a-48f0-810d-f22f4d8a1fcc", + "objectID": "acfd54d6-0d84-4221-859d-a6ced2e6ef65", "type": "lvl3", "url": "/docs/components/avatar#group-max-count", "hierarchy": { @@ -817,7 +1083,7 @@ }, { "content": "Group Total Count", - "objectID": "0b5aea8c-052b-4cf0-b965-7e9dc3e2f903", + "objectID": "0d1de79a-0ee3-454a-bb75-095ecfa3e1d7", "type": "lvl3", "url": "/docs/components/avatar#group-total-count", "hierarchy": { @@ -828,7 +1094,7 @@ }, { "content": "Group Custom count", - "objectID": "07df838f-34a4-4492-9055-fedb60b8fa60", + "objectID": "3212264b-7e6a-4f43-86ae-db08e94ff10b", "type": "lvl3", "url": "/docs/components/avatar#group-custom-count", "hierarchy": { @@ -839,7 +1105,7 @@ }, { "content": "Group Grid", - "objectID": "9ddd44a2-f097-4bce-b29c-131fa407ea8c", + "objectID": "d9181be8-fe17-4291-b61b-dca47d098078", "type": "lvl3", "url": "/docs/components/avatar#group-grid", "hierarchy": { @@ -850,7 +1116,7 @@ }, { "content": "Group Custom Implementation", - "objectID": "2f233a47-5a10-4e3b-aa86-fa3b6ea6aee9", + "objectID": "aac1a453-7281-4aa9-b38e-a19b55ccd05e", "type": "lvl3", "url": "/docs/components/avatar#group-custom-implementation", "hierarchy": { @@ -861,14 +1127,14 @@ }, { "content": "Slots", - "objectID": "a56ff6e2-550b-405e-ad16-45f0e2eea0ec", + "objectID": "21d2ec8b-6e7d-405f-853f-303ba19fede0", "type": "lvl2", "url": "/docs/components/avatar#slots", "hierarchy": { "lvl1": "Avatar", "lvl2": "Slots", "lvl3": null } }, { "content": "Custom Avatar Styles", - "objectID": "1c66c248-0d61-429c-b205-36cb480b5ec1", + "objectID": "cb632837-936f-4a83-87e8-cc769b689869", "type": "lvl3", "url": "/docs/components/avatar#custom-avatar-styles", "hierarchy": { @@ -879,28 +1145,28 @@ }, { "content": "Data Attributes", - "objectID": "11f78bc8-52a4-4ff2-97f6-34fe058adf0e", + "objectID": "61e79aae-02af-4b97-805f-97a56f27294c", "type": "lvl2", "url": "/docs/components/avatar#data-attributes", "hierarchy": { "lvl1": "Avatar", "lvl2": "Data Attributes", "lvl3": null } }, { "content": "API", - "objectID": "b3cf89cc-d85f-45ec-90a4-f6f57a6ecc27", + "objectID": "28db8d80-6266-46dc-bb37-0d87af0ef818", "type": "lvl2", "url": "/docs/components/avatar#api", "hierarchy": { "lvl1": "Avatar", "lvl2": "API", "lvl3": null } }, { "content": "Avatar Props", - "objectID": "e33b4a3b-2445-4c75-966b-88eedd0b8e63", + "objectID": "541ad6af-0f7c-4795-b31e-916768abf9f3", "type": "lvl3", "url": "/docs/components/avatar#avatar-props", "hierarchy": { "lvl1": "Avatar", "lvl2": "API", "lvl3": "Avatar Props" } }, { "content": "Avatar Group Props", - "objectID": "f572dcdd-70e2-417a-9582-d2b3f593a126", + "objectID": "f120402b-f717-4169-94b9-3e420963ebe4", "type": "lvl3", "url": "/docs/components/avatar#avatar-group-props", "hierarchy": { @@ -911,63 +1177,70 @@ }, { "content": "Badge", - "objectID": "6442a2df-3119-458d-83e0-71f0b81e621d", + "objectID": "c6bd7149-6d6d-4bec-87e2-aa24334c3b65", "type": "lvl1", "url": "/docs/components/badge", "hierarchy": { "lvl1": "Badge" } }, + { + "content": "Installation", + "objectID": "0ee5a964-142a-44fa-8ff3-c5a6730f4ed9", + "type": "lvl2", + "url": "/docs/components/badge#installation", + "hierarchy": { "lvl1": "Badge", "lvl2": "Installation", "lvl3": null } + }, { "content": "Import", - "objectID": "3867f3f1-7f56-43c5-8864-ae3b0c359eae", + "objectID": "424ff614-c517-4d88-afef-5a71b6a04396", "type": "lvl2", "url": "/docs/components/badge#import", "hierarchy": { "lvl1": "Badge", "lvl2": "Import", "lvl3": null } }, { "content": "Usage", - "objectID": "a61dd52e-d607-4c12-a8d5-649543eb1ae3", + "objectID": "19a476a0-8492-47df-8f29-e1557a1323c4", "type": "lvl2", "url": "/docs/components/badge#usage", "hierarchy": { "lvl1": "Badge", "lvl2": "Usage", "lvl3": null } }, { "content": "Sizes", - "objectID": "a844d22b-ff96-4372-93ec-a9e1f315b97d", + "objectID": "bcd7368f-a676-4b57-8827-cb4610a9fa32", "type": "lvl3", "url": "/docs/components/badge#sizes", "hierarchy": { "lvl1": "Badge", "lvl2": "Usage", "lvl3": "Sizes" } }, { "content": "Colors", - "objectID": "b8de9aa3-dce8-465e-93f8-935aaac38a6d", + "objectID": "9f55ca14-05c3-4e86-80ad-d41badcfc6e1", "type": "lvl3", "url": "/docs/components/badge#colors", "hierarchy": { "lvl1": "Badge", "lvl2": "Sizes", "lvl3": "Colors" } }, { "content": "Variants", - "objectID": "d1bdf081-90c5-441b-afb7-8639b9668cb9", + "objectID": "8a346ab2-8d5a-4d9f-afcd-d0bc9cb4d509", "type": "lvl3", "url": "/docs/components/badge#variants", "hierarchy": { "lvl1": "Badge", "lvl2": "Colors", "lvl3": "Variants" } }, { "content": "Placements", - "objectID": "e69a1b63-50e5-4472-bd35-57c3bca501e9", + "objectID": "8e249dc4-29ef-4f1a-85b6-96a8524cb40d", "type": "lvl3", "url": "/docs/components/badge#placements", "hierarchy": { "lvl1": "Badge", "lvl2": "Variants", "lvl3": "Placements" } }, { "content": "Shapes", - "objectID": "21832d47-6814-4625-9fed-ea8b90a9d052", + "objectID": "6dc02a23-cb26-4bee-ad09-debc29ba2aef", "type": "lvl3", "url": "/docs/components/badge#shapes", "hierarchy": { "lvl1": "Badge", "lvl2": "Placements", "lvl3": "Shapes" } }, { "content": "Badge Visibility", - "objectID": "e71b3bb1-a839-4c4e-9e71-e6323b76b146", + "objectID": "7e874620-6128-41ac-9ec3-8ab9069aaf00", "type": "lvl3", "url": "/docs/components/badge#badge-visibility", "hierarchy": { @@ -978,7 +1251,7 @@ }, { "content": "Content Examples", - "objectID": "38668a92-d967-462a-81ac-7b1e2b043914", + "objectID": "1e1671df-b667-45c6-9e14-f5f7d2a530c4", "type": "lvl3", "url": "/docs/components/badge#content-examples", "hierarchy": { @@ -989,7 +1262,7 @@ }, { "content": "Disable Outline", - "objectID": "914191e3-3186-4f0d-ae8f-91b2276751bf", + "objectID": "cdb30d8e-e258-4857-8539-3c76a8eefdba", "type": "lvl3", "url": "/docs/components/badge#disable-outline", "hierarchy": { @@ -1000,7 +1273,7 @@ }, { "content": "Accessibility", - "objectID": "a4865ab9-0b70-4f7a-a564-fa44db08c1ee", + "objectID": "1ec6d74c-78ad-4fec-b341-ee866c54696b", "type": "lvl3", "url": "/docs/components/badge#accessibility", "hierarchy": { @@ -1011,70 +1284,77 @@ }, { "content": "API", - "objectID": "d89b5984-0cff-4826-aa65-8e6804de298f", + "objectID": "abbeb08c-f657-4196-a8fe-205c2bba1dde", "type": "lvl2", "url": "/docs/components/badge#api", "hierarchy": { "lvl1": "Badge", "lvl2": "API", "lvl3": null } }, { "content": "Badge Props", - "objectID": "85d3cfc0-bcec-42a4-bd8d-2de4cfdf012a", + "objectID": "39ba3755-ec3b-487f-aa06-9fa68a117373", "type": "lvl3", "url": "/docs/components/badge#badge-props", "hierarchy": { "lvl1": "Badge", "lvl2": "API", "lvl3": "Badge Props" } }, { "content": "Breadcrumbs", - "objectID": "29d1931f-e081-46b1-9ffd-2dc6fdb91153", + "objectID": "31d24f70-b4fc-4eb2-b646-dd52e170e683", "type": "lvl1", "url": "/docs/components/breadcrumbs", "hierarchy": { "lvl1": "Breadcrumbs" } }, + { + "content": "Installation", + "objectID": "87729cc3-041c-4b73-8555-0ea2d69bb4ea", + "type": "lvl2", + "url": "/docs/components/breadcrumbs#installation", + "hierarchy": { "lvl1": "Breadcrumbs", "lvl2": "Installation", "lvl3": null } + }, { "content": "Import", - "objectID": "269cc17a-e5bf-4792-a8f1-f342b20a9dfd", + "objectID": "fc76a010-4058-4c26-8f41-6bacdb22f821", "type": "lvl2", "url": "/docs/components/breadcrumbs#import", "hierarchy": { "lvl1": "Breadcrumbs", "lvl2": "Import", "lvl3": null } }, { "content": "Usage", - "objectID": "121296e9-bcdd-4970-b0b1-ddf2ca7b747e", + "objectID": "30ae577d-dc96-45a4-ab31-d2a2f6afb227", "type": "lvl2", "url": "/docs/components/breadcrumbs#usage", "hierarchy": { "lvl1": "Breadcrumbs", "lvl2": "Usage", "lvl3": null } }, { "content": "Disabled", - "objectID": "08093047-9ef5-4ec7-a45a-4e81d62343e3", + "objectID": "8b0669f2-e4ff-4a3c-8d7f-e9500391f3b1", "type": "lvl3", "url": "/docs/components/breadcrumbs#disabled", "hierarchy": { "lvl1": "Breadcrumbs", "lvl2": "Usage", "lvl3": "Disabled" } }, { "content": "Sizes", - "objectID": "385c37f9-6f74-45ec-ab20-1b95ca17b371", + "objectID": "0a91f09c-e94e-4f5e-81cb-2d51d8d91de0", "type": "lvl3", "url": "/docs/components/breadcrumbs#sizes", "hierarchy": { "lvl1": "Breadcrumbs", "lvl2": "Disabled", "lvl3": "Sizes" } }, { "content": "Colors", - "objectID": "1607e3c8-8ccb-435b-9d1c-3700c8a67e28", + "objectID": "5254ef8e-f823-40bf-863b-08b521045037", "type": "lvl3", "url": "/docs/components/breadcrumbs#colors", "hierarchy": { "lvl1": "Breadcrumbs", "lvl2": "Sizes", "lvl3": "Colors" } }, { "content": "Variants", - "objectID": "c19b41fc-02f5-4833-bcb6-ed849406c5a7", + "objectID": "312dfa2d-a480-4329-917c-d8863a8d8def", "type": "lvl3", "url": "/docs/components/breadcrumbs#variants", "hierarchy": { "lvl1": "Breadcrumbs", "lvl2": "Colors", "lvl3": "Variants" } }, { "content": "Underlines", - "objectID": "44b54596-7572-4ff7-b38c-80598937e650", + "objectID": "449d8a81-1870-4c1e-af9f-f9a162d8ed00", "type": "lvl3", "url": "/docs/components/breadcrumbs#underlines", "hierarchy": { @@ -1085,7 +1365,7 @@ }, { "content": "Radius", - "objectID": "f04140d9-e6cc-4653-8fde-4ca8af6d41ca", + "objectID": "fcc06440-08db-4603-bf55-89970188fcc4", "type": "lvl3", "url": "/docs/components/breadcrumbs#radius", "hierarchy": { @@ -1096,14 +1376,14 @@ }, { "content": "Routing", - "objectID": "2f848ad4-7df3-4b44-b0a9-caff1f3523e0", + "objectID": "61dcddac-bb4f-4a0b-a555-1f6ea5cebab3", "type": "lvl3", "url": "/docs/components/breadcrumbs#routing", "hierarchy": { "lvl1": "Breadcrumbs", "lvl2": "Radius", "lvl3": "Routing" } }, { "content": "Controlled", - "objectID": "9459b621-4ce4-43d3-a526-5fb4729e8e5f", + "objectID": "3dd72a59-0f23-4f09-ae16-64c9dd83e4d6", "type": "lvl3", "url": "/docs/components/breadcrumbs#controlled", "hierarchy": { @@ -1114,7 +1394,7 @@ }, { "content": "Menu Type", - "objectID": "1c97a249-4147-4354-b230-2822c9c9a59a", + "objectID": "a0ea123e-dee9-4051-9e85-7a1bdef9c9cc", "type": "lvl3", "url": "/docs/components/breadcrumbs#menu-type", "hierarchy": { @@ -1125,7 +1405,7 @@ }, { "content": "Start & End Content", - "objectID": "8c6c29a5-4761-4859-bc10-3a676ef8c2a8", + "objectID": "a04a0931-2ec5-4ffe-ad86-40a24ca9f1fb", "type": "lvl3", "url": "/docs/components/breadcrumbs#start--end-content", "hierarchy": { @@ -1136,7 +1416,7 @@ }, { "content": "Custom Separator", - "objectID": "6b4193f2-2769-41e6-a086-2b3d2055fbf8", + "objectID": "755d3896-dec8-455f-8dd0-daa7621ca219", "type": "lvl3", "url": "/docs/components/breadcrumbs#custom-separator", "hierarchy": { @@ -1147,7 +1427,7 @@ }, { "content": "Custom Items", - "objectID": "76369dc5-92c3-4cf7-b391-e768c9658f8c", + "objectID": "b79c2457-c8ce-439b-bbb1-7452bdc0b9cc", "type": "lvl3", "url": "/docs/components/breadcrumbs#custom-items", "hierarchy": { @@ -1158,7 +1438,7 @@ }, { "content": "Collapsing Items", - "objectID": "f2e9b5f3-26a0-4944-8c87-9b0ec68c89e1", + "objectID": "3b3d4775-5947-431f-8250-ec7959a86a14", "type": "lvl3", "url": "/docs/components/breadcrumbs#collapsing-items", "hierarchy": { @@ -1169,7 +1449,7 @@ }, { "content": "Customizing the Ellipsis Item", - "objectID": "280d4fbd-fb26-41d0-ba31-ec5614ac0cd5", + "objectID": "a17f0daf-f976-4840-8081-9aa7b6834fc7", "type": "lvl3", "url": "/docs/components/breadcrumbs#customizing-the-ellipsis-item", "hierarchy": { @@ -1180,14 +1460,14 @@ }, { "content": "Slots", - "objectID": "cff002fb-710c-4c96-be2f-5de05a061592", + "objectID": "6a49a9ed-f061-43f5-9f85-1beef6a74ff9", "type": "lvl2", "url": "/docs/components/breadcrumbs#slots", "hierarchy": { "lvl1": "Breadcrumbs", "lvl2": "Slots", "lvl3": null } }, { "content": "Customizing the Breadcrumbs Styles", - "objectID": "db5619d8-ab1d-4f84-a41e-d4fc992ef6fe", + "objectID": "7d409a2b-cc95-49f7-ac3f-0b17c167db90", "type": "lvl3", "url": "/docs/components/breadcrumbs#customizing-the-breadcrumbs-styles", "hierarchy": { @@ -1198,7 +1478,7 @@ }, { "content": "Data Attributes", - "objectID": "3e3a1535-ac62-4155-8ae3-50965c5ef73e", + "objectID": "23082180-90b8-444a-b8fa-20900fc9f19f", "type": "lvl2", "url": "/docs/components/breadcrumbs#data-attributes", "hierarchy": { @@ -1209,7 +1489,7 @@ }, { "content": "Accessibility", - "objectID": "c3110d17-b69d-4962-b7b2-34deb3abedbf", + "objectID": "cf79374d-1bcb-4667-8143-2ecd8d2aefb1", "type": "lvl2", "url": "/docs/components/breadcrumbs#accessibility", "hierarchy": { @@ -1220,14 +1500,14 @@ }, { "content": "API", - "objectID": "7b400fb7-0e3b-4d62-9d82-ffeb275e1923", + "objectID": "e41e6fd5-3932-4dbc-a5ec-9f7c555d4405", "type": "lvl2", "url": "/docs/components/breadcrumbs#api", "hierarchy": { "lvl1": "Breadcrumbs", "lvl2": "API", "lvl3": null } }, { "content": "Breadcrumbs Props", - "objectID": "0d0c4bee-42c1-4883-b8b0-7442f3149464", + "objectID": "ff69f356-baae-45b1-be2d-520b214dbc9e", "type": "lvl3", "url": "/docs/components/breadcrumbs#breadcrumbs-props", "hierarchy": { @@ -1238,7 +1518,7 @@ }, { "content": "Breadcrumbs Functions", - "objectID": "e8b81e6c-c104-4c47-9f24-18c4a62c873c", + "objectID": "a141cbcd-3750-45da-8f96-a2a972f878f7", "type": "lvl3", "url": "/docs/components/breadcrumbs#breadcrumbs-functions", "hierarchy": { @@ -1249,7 +1529,7 @@ }, { "content": "Breadcrumbs Events", - "objectID": "e26695f4-011c-4b1d-9ae4-6c026234e95e", + "objectID": "54b79833-58c4-4b30-becd-5c07e2c0899a", "type": "lvl3", "url": "/docs/components/breadcrumbs#breadcrumbs-events", "hierarchy": { @@ -1260,7 +1540,7 @@ }, { "content": "BreadcrumbItem Props", - "objectID": "33b53e42-a979-4903-95d1-4be734b6ce36", + "objectID": "4098ed22-c411-4e38-b996-ad64ccdc1580", "type": "lvl3", "url": "/docs/components/breadcrumbs#breadcrumbitem-props", "hierarchy": { @@ -1271,7 +1551,7 @@ }, { "content": "BreadcrumbItem Events", - "objectID": "45593a77-fbc4-4350-a018-f6d293e4764d", + "objectID": "298e0ad0-01b8-4281-86c2-1ad1d8d27635", "type": "lvl3", "url": "/docs/components/breadcrumbs#breadcrumbitem-events", "hierarchy": { @@ -1282,7 +1562,7 @@ }, { "content": "Types", - "objectID": "e77b263c-7197-4efb-abb3-752382e8e427", + "objectID": "ac99d7b0-ad53-4c23-a1c6-f200521620a9", "type": "lvl3", "url": "/docs/components/breadcrumbs#types", "hierarchy": { @@ -1293,91 +1573,98 @@ }, { "content": "Render Ellipsis Function", - "objectID": "4405070c-e3d3-439f-987f-6914db620403", + "objectID": "30585ddf-fdd4-47fc-bf15-99d0416816e9", "type": "lvl4", "url": "/docs/components/breadcrumbs#render-ellipsis-function", "hierarchy": { "lvl1": "Breadcrumbs", "lvl2": "Types", "lvl3": null } }, { "content": "Button", - "objectID": "c15ea824-380d-4200-a9b9-5b379019755e", + "objectID": "6db7cf1d-8716-4eb9-b879-628354350158", "type": "lvl1", "url": "/docs/components/button", "hierarchy": { "lvl1": "Button" } }, + { + "content": "Installation", + "objectID": "3b28b4fd-e846-41b3-8d84-05e73fec8c6a", + "type": "lvl2", + "url": "/docs/components/button#installation", + "hierarchy": { "lvl1": "Button", "lvl2": "Installation", "lvl3": null } + }, { "content": "Import", - "objectID": "f26a0f2a-d231-42a7-9c27-42c528064a28", + "objectID": "e4dd5376-184b-47d7-a8b8-548e82d47731", "type": "lvl2", "url": "/docs/components/button#import", "hierarchy": { "lvl1": "Button", "lvl2": "Import", "lvl3": null } }, { "content": "Usage", - "objectID": "0fc5bc34-7f8a-4ef2-af0e-9bb9ed00cbc1", + "objectID": "46b290c7-261c-45a7-af76-27fc581d8ead", "type": "lvl2", "url": "/docs/components/button#usage", "hierarchy": { "lvl1": "Button", "lvl2": "Usage", "lvl3": null } }, { "content": "Disabled", - "objectID": "db7489fa-5593-4342-a976-7787f660d60a", + "objectID": "10344fe1-7e2d-4126-91f2-7ca91124ae2a", "type": "lvl3", "url": "/docs/components/button#disabled", "hierarchy": { "lvl1": "Button", "lvl2": "Usage", "lvl3": "Disabled" } }, { "content": "Sizes", - "objectID": "e96e4e29-df8f-4383-b867-2dd9c86d4f67", + "objectID": "3030123d-d408-4e71-a58a-86d2fa8248ad", "type": "lvl3", "url": "/docs/components/button#sizes", "hierarchy": { "lvl1": "Button", "lvl2": "Disabled", "lvl3": "Sizes" } }, { "content": "Radius", - "objectID": "a1895a93-c3a9-4ad7-a314-a89557042254", + "objectID": "e976ea13-792a-40c1-9a1c-63810c89b64a", "type": "lvl3", "url": "/docs/components/button#radius", "hierarchy": { "lvl1": "Button", "lvl2": "Sizes", "lvl3": "Radius" } }, { "content": "Colors", - "objectID": "c7d17b63-dc6e-4fcf-975c-b088e95e03d5", + "objectID": "d32dbfcc-9e0e-4051-99c9-f872bd69e1fc", "type": "lvl3", "url": "/docs/components/button#colors", "hierarchy": { "lvl1": "Button", "lvl2": "Radius", "lvl3": "Colors" } }, { "content": "Variants", - "objectID": "8f3f9a8e-4b0f-4679-a001-a221b79fbbe3", + "objectID": "aa4571ed-9611-4e11-bb93-ccc46274a319", "type": "lvl3", "url": "/docs/components/button#variants", "hierarchy": { "lvl1": "Button", "lvl2": "Colors", "lvl3": "Variants" } }, { "content": "Loading", - "objectID": "651dae03-0eed-44f9-a1e3-9529f4e76553", + "objectID": "6ee0b6aa-963a-43d4-ad4e-5f22c3403461", "type": "lvl3", "url": "/docs/components/button#loading", "hierarchy": { "lvl1": "Button", "lvl2": "Variants", "lvl3": "Loading" } }, { "content": "With Icons", - "objectID": "d42e9439-c320-47ad-898e-2081b2aba3ca", + "objectID": "a69ea901-990b-4732-b20e-cb3c524ac8d9", "type": "lvl3", "url": "/docs/components/button#with-icons", "hierarchy": { "lvl1": "Button", "lvl2": "Loading", "lvl3": "With Icons" } }, { "content": "Icon Only", - "objectID": "5a036bbd-d21d-4665-ade5-1b88fa3c0f45", + "objectID": "f0abccf7-5968-499a-9e95-af3e5400e79b", "type": "lvl3", "url": "/docs/components/button#icon-only", "hierarchy": { "lvl1": "Button", "lvl2": "With Icons", "lvl3": "Icon Only" } }, { "content": "Custom Styles", - "objectID": "5c8331e6-523c-43b4-a04d-0e20b998629d", + "objectID": "cb40731c-ee91-4c1a-a653-bfa8a0461098", "type": "lvl3", "url": "/docs/components/button#custom-styles", "hierarchy": { @@ -1388,7 +1675,7 @@ }, { "content": "Custom Implementation", - "objectID": "5f1845dd-3b95-4c86-b864-ec316f8fa945", + "objectID": "341f02f4-f8b9-4513-aed1-ba9ec5b6d095", "type": "lvl3", "url": "/docs/components/button#custom-implementation", "hierarchy": { @@ -1399,14 +1686,14 @@ }, { "content": "Button Group", - "objectID": "1ea292eb-2b99-43cc-b9ea-b30be99411fe", + "objectID": "92bfba55-edba-4696-8b47-55ddb07659a1", "type": "lvl2", "url": "/docs/components/button#button-group", "hierarchy": { "lvl1": "Button", "lvl2": "Button Group", "lvl3": null } }, { "content": "Group Disabled", - "objectID": "b7584ad0-abc2-4ce0-b6f2-447a988fd297", + "objectID": "385c3fa1-916b-47e6-b499-de1450c6e645", "type": "lvl3", "url": "/docs/components/button#group-disabled", "hierarchy": { @@ -1417,7 +1704,7 @@ }, { "content": "Group Use case", - "objectID": "073c2c7e-63e6-4abd-9c1e-3996b0f4dd2a", + "objectID": "508b4924-4314-42c1-bd93-81e7ac3f5362", "type": "lvl3", "url": "/docs/components/button#group-use-case", "hierarchy": { @@ -1428,35 +1715,35 @@ }, { "content": "Data Attributes", - "objectID": "caa86bf2-7174-4724-ac57-f6943f220e77", + "objectID": "74666d0e-4f18-4eed-a144-db77b6cf0d4c", "type": "lvl2", "url": "/docs/components/button#data-attributes", "hierarchy": { "lvl1": "Button", "lvl2": "Data Attributes", "lvl3": null } }, { "content": "Accessibility", - "objectID": "75a390f2-66f2-44db-8de3-81f2415ace70", + "objectID": "973d858e-14bb-4014-8606-29113089bef8", "type": "lvl2", "url": "/docs/components/button#accessibility", "hierarchy": { "lvl1": "Button", "lvl2": "Accessibility", "lvl3": null } }, { "content": "API", - "objectID": "b2c12e15-49c3-4ea4-a36c-a68dbf82e2cb", + "objectID": "5a5c45e8-9cda-4063-aa62-d62fc2f4bc54", "type": "lvl2", "url": "/docs/components/button#api", "hierarchy": { "lvl1": "Button", "lvl2": "API", "lvl3": null } }, { "content": "Button Props", - "objectID": "2fea9adb-e147-4d4b-bd9c-21e95ff139a4", + "objectID": "7891959d-a3cd-4ea5-afcf-48eae2a22186", "type": "lvl3", "url": "/docs/components/button#button-props", "hierarchy": { "lvl1": "Button", "lvl2": "API", "lvl3": "Button Props" } }, { "content": "Button Events", - "objectID": "2af0f998-52ea-4921-94ef-a5933cbd49fe", + "objectID": "ec9d1e73-7279-4c24-af1f-786fb33a9f30", "type": "lvl3", "url": "/docs/components/button#button-events", "hierarchy": { @@ -1467,7 +1754,7 @@ }, { "content": "Button Group Props", - "objectID": "ffffabbf-2daf-4586-acca-db50752be882", + "objectID": "5e4f13c7-f053-4346-9778-e60dc1e49e8c", "type": "lvl3", "url": "/docs/components/button#button-group-props", "hierarchy": { @@ -1477,202 +1764,447 @@ } }, { - "content": "Card", - "objectID": "94a42868-d310-4274-9ae1-c60e62b84fa8", + "content": "Calendar", + "objectID": "08d9580e-ff81-472a-8f41-620173fbc21f", "type": "lvl1", - "url": "/docs/components/card", - "hierarchy": { "lvl1": "Card" } + "url": "/docs/components/calendar", + "hierarchy": { "lvl1": "Calendar" } + }, + { + "content": "Installation", + "objectID": "a00ed2b0-1fe7-4d47-80fc-7279cd7ab3b7", + "type": "lvl2", + "url": "/docs/components/calendar#installation", + "hierarchy": { "lvl1": "Calendar", "lvl2": "Installation", "lvl3": null } }, { "content": "Import", - "objectID": "b48bede9-81c8-4218-bc0d-1f3ff8ba6b3b", + "objectID": "feddc778-7487-41f5-bf55-d2c3592bf67e", "type": "lvl2", - "url": "/docs/components/card#import", - "hierarchy": { "lvl1": "Card", "lvl2": "Import", "lvl3": null } + "url": "/docs/components/calendar#import", + "hierarchy": { "lvl1": "Calendar", "lvl2": "Import", "lvl3": null } }, { "content": "Usage", - "objectID": "7507b1cd-a4f7-44b2-9418-edae34ce3982", + "objectID": "cf8440b3-44d2-437d-89a7-2908b7b37111", "type": "lvl2", - "url": "/docs/components/card#usage", - "hierarchy": { "lvl1": "Card", "lvl2": "Usage", "lvl3": null } + "url": "/docs/components/calendar#usage", + "hierarchy": { "lvl1": "Calendar", "lvl2": "Usage", "lvl3": null } }, { - "content": "With Divider", - "objectID": "1752952e-639a-40c1-97c1-4734d0696ca6", + "content": "Disabled", + "objectID": "edf1c479-ad59-47c3-a7a2-fccc325db1aa", "type": "lvl3", - "url": "/docs/components/card#with-divider", - "hierarchy": { "lvl1": "Card", "lvl2": "Usage", "lvl3": "With Divider" } + "url": "/docs/components/calendar#disabled", + "hierarchy": { "lvl1": "Calendar", "lvl2": "Usage", "lvl3": "Disabled" } }, { - "content": "With Image", - "objectID": "a29bc106-024e-4961-9f72-b54a542431c0", + "content": "Read Only", + "objectID": "94eeddbb-8423-4ed3-bb44-37ec1a2bf89a", "type": "lvl3", - "url": "/docs/components/card#with-image", - "hierarchy": { - "lvl1": "Card", - "lvl2": "With Divider", - "lvl3": "With Image" - } + "url": "/docs/components/calendar#read-only", + "hierarchy": { "lvl1": "Calendar", "lvl2": "Disabled", "lvl3": "Read Only" } }, { - "content": "Blurred Footer", - "objectID": "6b0536d9-1d7f-4a0c-826e-05f342a2a5d1", + "content": "Controlled", + "objectID": "de3fbb6e-a71e-4fac-b571-a26225b4fdd3", "type": "lvl3", - "url": "/docs/components/card#blurred-footer", + "url": "/docs/components/calendar#controlled", "hierarchy": { - "lvl1": "Card", - "lvl2": "With Image", - "lvl3": "Blurred Footer" + "lvl1": "Calendar", + "lvl2": "Read Only", + "lvl3": "Controlled" } }, { - "content": "Composition", - "objectID": "4105fd74-3e96-4b8f-9fed-e23b3fdbe3dc", + "content": "Min Date Value", + "objectID": "d5b2d561-de56-49df-a2c1-2d14b8bd90af", "type": "lvl3", - "url": "/docs/components/card#composition", + "url": "/docs/components/calendar#min-date-value", "hierarchy": { - "lvl1": "Card", - "lvl2": "Blurred Footer", - "lvl3": "Composition" + "lvl1": "Calendar", + "lvl2": "Controlled", + "lvl3": "Min Date Value" } }, { - "content": "Blurred Card", - "objectID": "e7bca9cd-8344-4046-9a7c-26ace8776fa0", + "content": "Max Date Value", + "objectID": "6dfa5957-c31d-4144-bb2f-555bd563626d", "type": "lvl3", - "url": "/docs/components/card#blurred-card", + "url": "/docs/components/calendar#max-date-value", "hierarchy": { - "lvl1": "Card", - "lvl2": "Composition", - "lvl3": "Blurred Card" + "lvl1": "Calendar", + "lvl2": "Min Date Value", + "lvl3": "Max Date Value" } }, { - "content": "Primary Action", - "objectID": "5769bd3f-f477-4b60-a237-5b989ef0db3f", + "content": "Unavailable Dates", + "objectID": "43c2fe13-10f6-4f7f-b02f-20402122248f", "type": "lvl3", - "url": "/docs/components/card#primary-action", + "url": "/docs/components/calendar#unavailable-dates", "hierarchy": { - "lvl1": "Card", - "lvl2": "Blurred Card", - "lvl3": "Primary Action" + "lvl1": "Calendar", + "lvl2": "Max Date Value", + "lvl3": "Unavailable Dates" } }, { - "content": "Cover Image", - "objectID": "6b26f333-b78c-44df-9538-e60bc40fa25f", + "content": "Controlled Focused Value", + "objectID": "0cf55a42-d7b3-4670-bb12-217e432603cc", "type": "lvl3", - "url": "/docs/components/card#cover-image", + "url": "/docs/components/calendar#controlled-focused-value", "hierarchy": { - "lvl1": "Card", - "lvl2": "Primary Action", - "lvl3": "Cover Image" + "lvl1": "Calendar", + "lvl2": "Unavailable Dates", + "lvl3": "Controlled Focused Value" } }, { - "content": "Data Attributes", - "objectID": "fe76f942-4179-45f5-ba67-3f69a8410f80", - "type": "lvl2", - "url": "/docs/components/card#data-attributes", - "hierarchy": { "lvl1": "Card", "lvl2": "Data Attributes", "lvl3": null } - }, - { - "content": "API", - "objectID": "ccad2a68-0f59-4c85-8ecd-d3604aa26436", - "type": "lvl2", - "url": "/docs/components/card#api", - "hierarchy": { "lvl1": "Card", "lvl2": "API", "lvl3": null } - }, - { - "content": "Card Props", - "objectID": "72a3557b-f4b4-439a-9ebc-9f160f6872dd", + "content": "Invalid Date", + "objectID": "caf868df-7378-4e1e-b7fc-24121d3b135e", "type": "lvl3", - "url": "/docs/components/card#card-props", - "hierarchy": { "lvl1": "Card", "lvl2": "API", "lvl3": "Card Props" } + "url": "/docs/components/calendar#invalid-date", + "hierarchy": { + "lvl1": "Calendar", + "lvl2": "Controlled Focused Value", + "lvl3": "Invalid Date" + } }, { - "content": "Card Events", - "objectID": "d63790fb-e8d2-447a-8c8b-89d44a541f9a", + "content": "With Month And Year Picker", + "objectID": "85fd5900-989c-426d-add6-a6ffe081acd6", "type": "lvl3", - "url": "/docs/components/card#card-events", - "hierarchy": { "lvl1": "Card", "lvl2": "Card Props", "lvl3": "Card Events" } - }, - { - "content": "Checkbox Group", - "objectID": "b0d8dc53-18a5-401e-93ff-e0ab653652c7", - "type": "lvl1", - "url": "/docs/components/checkbox-group", - "hierarchy": { "lvl1": "Checkbox Group" } - }, - { - "content": "Import", - "objectID": "bf5f34c3-b67b-43d0-8530-7dd6e33af552", - "type": "lvl2", - "url": "/docs/components/checkbox-group#import", - "hierarchy": { "lvl1": "Checkbox Group", "lvl2": "Import", "lvl3": null } - }, - { - "content": "Usage", - "objectID": "2837aefe-d0cb-4717-9803-040d3cc6d085", - "type": "lvl2", - "url": "/docs/components/checkbox-group#usage", - "hierarchy": { "lvl1": "Checkbox Group", "lvl2": "Usage", "lvl3": null } + "url": "/docs/components/calendar#with-month-and-year-picker", + "hierarchy": { + "lvl1": "Calendar", + "lvl2": "Invalid Date", + "lvl3": "With Month And Year Picker" + } }, { - "content": "Disabled", - "objectID": "a3ee2f62-34ad-40e8-836e-699cfaae6e71", + "content": "International Calendars", + "objectID": "de2379e1-e006-402f-9074-295fe3ca0211", "type": "lvl3", - "url": "/docs/components/checkbox-group#disabled", + "url": "/docs/components/calendar#international-calendars", "hierarchy": { - "lvl1": "Checkbox Group", - "lvl2": "Usage", - "lvl3": "Disabled" + "lvl1": "Calendar", + "lvl2": "With Month And Year Picker", + "lvl3": "International Calendars" } }, { - "content": "Horizontal", - "objectID": "772c9989-94c5-471e-8c16-ca1674029875", + "content": "Visible Months", + "objectID": "b1a8b6bb-f07d-494c-bdca-2ea71cf07514", "type": "lvl3", - "url": "/docs/components/checkbox-group#horizontal", + "url": "/docs/components/calendar#visible-months", "hierarchy": { - "lvl1": "Checkbox Group", - "lvl2": "Disabled", - "lvl3": "Horizontal" + "lvl1": "Calendar", + "lvl2": "International Calendars", + "lvl3": "Visible Months" } }, { - "content": "Controlled", - "objectID": "fb7d055e-66e7-4c51-a308-d20aa5a33809", + "content": "Page Behaviour", + "objectID": "f8c503d5-d932-4b3d-b1af-d75e30700edd", "type": "lvl3", - "url": "/docs/components/checkbox-group#controlled", + "url": "/docs/components/calendar#page-behaviour", "hierarchy": { - "lvl1": "Checkbox Group", - "lvl2": "Horizontal", - "lvl3": "Controlled" + "lvl1": "Calendar", + "lvl2": "Visible Months", + "lvl3": "Page Behaviour" } }, { - "content": "Invalid", - "objectID": "449cee94-2b3b-49a7-b659-2057306eea52", + "content": "Presets", + "objectID": "1b287826-4171-4bb5-b6c0-8ce43d5c3344", "type": "lvl3", - "url": "/docs/components/checkbox-group#invalid", + "url": "/docs/components/calendar#presets", "hierarchy": { - "lvl1": "Checkbox Group", - "lvl2": "Controlled", - "lvl3": "Invalid" + "lvl1": "Calendar", + "lvl2": "Page Behaviour", + "lvl3": "Presets" } }, { "content": "Slots", - "objectID": "dee5db72-55a2-4f4c-8e6d-5058ce81ff4c", + "objectID": "428a879e-e9ad-4ca7-a65d-f747d69d6d20", "type": "lvl2", - "url": "/docs/components/checkbox-group#slots", - "hierarchy": { "lvl1": "Checkbox Group", "lvl2": "Slots", "lvl3": null } + "url": "/docs/components/calendar#slots", + "hierarchy": { "lvl1": "Calendar", "lvl2": "Slots", "lvl3": null } + }, + { + "content": "Data Attributes", + "objectID": "78fdc89e-ffd3-415f-8b08-61d912c42c48", + "type": "lvl2", + "url": "/docs/components/calendar#data-attributes", + "hierarchy": { "lvl1": "Calendar", "lvl2": "Data Attributes", "lvl3": null } + }, + { + "content": "Accessibility", + "objectID": "7473a49c-84ea-448b-b4b8-0a1a9a7c8e26", + "type": "lvl2", + "url": "/docs/components/calendar#accessibility", + "hierarchy": { "lvl1": "Calendar", "lvl2": "Accessibility", "lvl3": null } + }, + { + "content": "API", + "objectID": "183e1c06-3f1d-4559-9d00-fc921b038f5f", + "type": "lvl2", + "url": "/docs/components/calendar#api", + "hierarchy": { "lvl1": "Calendar", "lvl2": "API", "lvl3": null } + }, + { + "content": "Calendar Props", + "objectID": "c38322dc-82e5-446c-8ce4-093b788778a4", + "type": "lvl3", + "url": "/docs/components/calendar#calendar-props", + "hierarchy": { "lvl1": "Calendar", "lvl2": "API", "lvl3": "Calendar Props" } + }, + { + "content": "Calendar Events", + "objectID": "82d1a0c6-c084-4987-ab2e-c2314a3ba502", + "type": "lvl3", + "url": "/docs/components/calendar#calendar-events", + "hierarchy": { + "lvl1": "Calendar", + "lvl2": "Calendar Props", + "lvl3": "Calendar Events" + } + }, + { + "content": "Types", + "objectID": "dda236e2-e609-435a-bb15-148be5de1419", + "type": "lvl3", + "url": "/docs/components/calendar#types", + "hierarchy": { + "lvl1": "Calendar", + "lvl2": "Calendar Events", + "lvl3": "Types" + } + }, + { + "content": "Supported Calendars", + "objectID": "ac6fb8e9-c34a-4a04-bb35-021ce2e063e4", + "type": "lvl4", + "url": "/docs/components/calendar#supported-calendars", + "hierarchy": { "lvl1": "Calendar", "lvl2": "Types", "lvl3": null } + }, + { + "content": "Card", + "objectID": "8db2081c-8a06-4752-a78e-c9489928e735", + "type": "lvl1", + "url": "/docs/components/card", + "hierarchy": { "lvl1": "Card" } + }, + { + "content": "Installation", + "objectID": "dfcb5301-8583-4c85-b174-3fbc3209c0f4", + "type": "lvl2", + "url": "/docs/components/card#installation", + "hierarchy": { "lvl1": "Card", "lvl2": "Installation", "lvl3": null } + }, + { + "content": "Import", + "objectID": "c0b1fd2c-b66c-4143-a47c-5f0226b53ec5", + "type": "lvl2", + "url": "/docs/components/card#import", + "hierarchy": { "lvl1": "Card", "lvl2": "Import", "lvl3": null } + }, + { + "content": "Usage", + "objectID": "21958cae-772c-4cac-b297-33f535d28aea", + "type": "lvl2", + "url": "/docs/components/card#usage", + "hierarchy": { "lvl1": "Card", "lvl2": "Usage", "lvl3": null } + }, + { + "content": "With Divider", + "objectID": "e8785df0-d2f1-4b53-8f0a-46db1a73928d", + "type": "lvl3", + "url": "/docs/components/card#with-divider", + "hierarchy": { "lvl1": "Card", "lvl2": "Usage", "lvl3": "With Divider" } + }, + { + "content": "With Image", + "objectID": "ae4ec132-2ef5-4b8f-9fbb-eb85cd1d4e78", + "type": "lvl3", + "url": "/docs/components/card#with-image", + "hierarchy": { + "lvl1": "Card", + "lvl2": "With Divider", + "lvl3": "With Image" + } + }, + { + "content": "Blurred Footer", + "objectID": "9a51cbd8-7f61-4c6b-addd-d88c646cf953", + "type": "lvl3", + "url": "/docs/components/card#blurred-footer", + "hierarchy": { + "lvl1": "Card", + "lvl2": "With Image", + "lvl3": "Blurred Footer" + } + }, + { + "content": "Composition", + "objectID": "f0a66483-0969-42ab-a831-142eb028d64e", + "type": "lvl3", + "url": "/docs/components/card#composition", + "hierarchy": { + "lvl1": "Card", + "lvl2": "Blurred Footer", + "lvl3": "Composition" + } + }, + { + "content": "Blurred Card", + "objectID": "041732bf-3839-41b0-9c77-0ef15246b188", + "type": "lvl3", + "url": "/docs/components/card#blurred-card", + "hierarchy": { + "lvl1": "Card", + "lvl2": "Composition", + "lvl3": "Blurred Card" + } + }, + { + "content": "Primary Action", + "objectID": "91a4a281-f3f5-4da9-8d6e-2b9af355313c", + "type": "lvl3", + "url": "/docs/components/card#primary-action", + "hierarchy": { + "lvl1": "Card", + "lvl2": "Blurred Card", + "lvl3": "Primary Action" + } + }, + { + "content": "Cover Image", + "objectID": "cbb1dc01-976c-4658-8371-01c548ecf37b", + "type": "lvl3", + "url": "/docs/components/card#cover-image", + "hierarchy": { + "lvl1": "Card", + "lvl2": "Primary Action", + "lvl3": "Cover Image" + } + }, + { + "content": "Data Attributes", + "objectID": "b1774a3f-dcae-4415-9ac7-cae725ca6a8b", + "type": "lvl2", + "url": "/docs/components/card#data-attributes", + "hierarchy": { "lvl1": "Card", "lvl2": "Data Attributes", "lvl3": null } + }, + { + "content": "API", + "objectID": "ef6242b4-fa97-4e70-b603-401f9c8597c0", + "type": "lvl2", + "url": "/docs/components/card#api", + "hierarchy": { "lvl1": "Card", "lvl2": "API", "lvl3": null } + }, + { + "content": "Card Props", + "objectID": "50adfd3e-a5ad-44d1-813d-09121dc68e83", + "type": "lvl3", + "url": "/docs/components/card#card-props", + "hierarchy": { "lvl1": "Card", "lvl2": "API", "lvl3": "Card Props" } + }, + { + "content": "Card Events", + "objectID": "b33a320b-1492-48d6-bdf8-6dc0e091ae85", + "type": "lvl3", + "url": "/docs/components/card#card-events", + "hierarchy": { "lvl1": "Card", "lvl2": "Card Props", "lvl3": "Card Events" } + }, + { + "content": "Checkbox Group", + "objectID": "e2335476-4a3a-4eda-a03d-1112a0d233a8", + "type": "lvl1", + "url": "/docs/components/checkbox-group", + "hierarchy": { "lvl1": "Checkbox Group" } + }, + { + "content": "Installation", + "objectID": "950621d3-263a-4d3d-b3b4-ff804349cc09", + "type": "lvl2", + "url": "/docs/components/checkbox-group#installation", + "hierarchy": { + "lvl1": "Checkbox Group", + "lvl2": "Installation", + "lvl3": null + } + }, + { + "content": "Import", + "objectID": "d72bf6c2-1e06-428b-8c37-d85dc151834a", + "type": "lvl2", + "url": "/docs/components/checkbox-group#import", + "hierarchy": { "lvl1": "Checkbox Group", "lvl2": "Import", "lvl3": null } + }, + { + "content": "Usage", + "objectID": "160a4d16-03c2-4f38-95c8-621aeb00e889", + "type": "lvl2", + "url": "/docs/components/checkbox-group#usage", + "hierarchy": { "lvl1": "Checkbox Group", "lvl2": "Usage", "lvl3": null } + }, + { + "content": "Disabled", + "objectID": "fafae1ab-cac4-4fcc-9a70-69176072baed", + "type": "lvl3", + "url": "/docs/components/checkbox-group#disabled", + "hierarchy": { + "lvl1": "Checkbox Group", + "lvl2": "Usage", + "lvl3": "Disabled" + } + }, + { + "content": "Horizontal", + "objectID": "2d74c57d-a358-45d3-8a65-9e95269c0bbd", + "type": "lvl3", + "url": "/docs/components/checkbox-group#horizontal", + "hierarchy": { + "lvl1": "Checkbox Group", + "lvl2": "Disabled", + "lvl3": "Horizontal" + } + }, + { + "content": "Controlled", + "objectID": "5b8a5443-1c81-4d04-9773-25675c01b09f", + "type": "lvl3", + "url": "/docs/components/checkbox-group#controlled", + "hierarchy": { + "lvl1": "Checkbox Group", + "lvl2": "Horizontal", + "lvl3": "Controlled" + } + }, + { + "content": "Invalid", + "objectID": "3293465d-20cc-4489-bce5-42f98b73b340", + "type": "lvl3", + "url": "/docs/components/checkbox-group#invalid", + "hierarchy": { + "lvl1": "Checkbox Group", + "lvl2": "Controlled", + "lvl3": "Invalid" + } + }, + { + "content": "Slots", + "objectID": "fdabe32a-9aeb-4e32-802a-5272bcfe8975", + "type": "lvl2", + "url": "/docs/components/checkbox-group#slots", + "hierarchy": { "lvl1": "Checkbox Group", "lvl2": "Slots", "lvl3": null } }, { "content": "Custom Styles", - "objectID": "fe6052a3-6529-43d5-ab52-2a8a9e92fdd8", + "objectID": "7a25de41-2134-4ac4-9c46-c5f3b0dea9d4", "type": "lvl3", "url": "/docs/components/checkbox-group#custom-styles", "hierarchy": { @@ -1683,7 +2215,7 @@ }, { "content": "Custom Implementation", - "objectID": "67788c2d-4d0c-4095-9e7a-e5ac869c7891", + "objectID": "2e3c4b68-cd33-4b9f-885b-cde1e1c48971", "type": "lvl3", "url": "/docs/components/checkbox-group#custom-implementation", "hierarchy": { @@ -1694,14 +2226,14 @@ }, { "content": "API", - "objectID": "55b0440b-d9ac-4ecc-8188-d03413fdce85", + "objectID": "f02185e2-2204-4504-a9e1-0cf6cc4fca49", "type": "lvl2", "url": "/docs/components/checkbox-group#api", "hierarchy": { "lvl1": "Checkbox Group", "lvl2": "API", "lvl3": null } }, { "content": "Checkbox Group Props", - "objectID": "4ffae55d-c55c-4853-b840-08654b56373a", + "objectID": "4b389503-a290-4835-ae3c-41e3eb0acb3b", "type": "lvl3", "url": "/docs/components/checkbox-group#checkbox-group-props", "hierarchy": { @@ -1712,7 +2244,7 @@ }, { "content": "Checkbox Group Events", - "objectID": "2e7c276f-c155-404f-9a31-d0b99400c6d9", + "objectID": "15238198-0c19-4c46-8790-7d698b967716", "type": "lvl3", "url": "/docs/components/checkbox-group#checkbox-group-events", "hierarchy": { @@ -1723,56 +2255,63 @@ }, { "content": "Checkbox", - "objectID": "2de5cfbc-b7a1-44d5-87ea-c5948a6346a6", + "objectID": "48c7cbb7-2eaf-41b1-bb29-d0d4d3c02f7f", "type": "lvl1", "url": "/docs/components/checkbox", "hierarchy": { "lvl1": "Checkbox" } }, + { + "content": "Installation", + "objectID": "e8001f6d-91e5-4b96-8ac0-1627c57a6870", + "type": "lvl2", + "url": "/docs/components/checkbox#installation", + "hierarchy": { "lvl1": "Checkbox", "lvl2": "Installation", "lvl3": null } + }, { "content": "Import", - "objectID": "7b7d7cfa-f836-4c79-8e00-788e40acd681", + "objectID": "b1809ae6-8943-46bc-a960-788b0876a790", "type": "lvl2", "url": "/docs/components/checkbox#import", "hierarchy": { "lvl1": "Checkbox", "lvl2": "Import", "lvl3": null } }, { "content": "Usage", - "objectID": "92458d4d-9b68-4d1f-9238-f826fc1c233e", + "objectID": "1de45680-f4d7-4cc7-a9cd-58ea1eaf963e", "type": "lvl2", "url": "/docs/components/checkbox#usage", "hierarchy": { "lvl1": "Checkbox", "lvl2": "Usage", "lvl3": null } }, { "content": "Disabled", - "objectID": "1c0b1b49-40b6-42c5-a5ea-ed6611c4508c", + "objectID": "9943cbe3-a11f-4c9d-a2da-364c80857b50", "type": "lvl3", "url": "/docs/components/checkbox#disabled", "hierarchy": { "lvl1": "Checkbox", "lvl2": "Usage", "lvl3": "Disabled" } }, { "content": "Sizes", - "objectID": "ad558dcb-80d7-4722-a5da-0924bd81fa8b", + "objectID": "24c208bb-1d0a-4f71-ac92-a710ac4e984e", "type": "lvl3", "url": "/docs/components/checkbox#sizes", "hierarchy": { "lvl1": "Checkbox", "lvl2": "Disabled", "lvl3": "Sizes" } }, { "content": "Colors", - "objectID": "02f4e1f5-c4fd-4b93-a59b-972d32aa5eeb", + "objectID": "b3f9b5e0-a38d-48ae-8442-10347e76fd7b", "type": "lvl3", "url": "/docs/components/checkbox#colors", "hierarchy": { "lvl1": "Checkbox", "lvl2": "Sizes", "lvl3": "Colors" } }, { "content": "Radius", - "objectID": "034f123f-c0b0-4e40-92a1-a034108267dc", + "objectID": "5fe42b38-f90e-47b3-8b7c-5cbbb1bec4a5", "type": "lvl3", "url": "/docs/components/checkbox#radius", "hierarchy": { "lvl1": "Checkbox", "lvl2": "Colors", "lvl3": "Radius" } }, { "content": "Indeterminate", - "objectID": "869c44a5-7ddc-4c55-aa64-213fbe8a5b43", + "objectID": "0cd5e149-d2af-4eb8-b652-e9a83e96127a", "type": "lvl3", "url": "/docs/components/checkbox#indeterminate", "hierarchy": { @@ -1783,7 +2322,7 @@ }, { "content": "Line Through", - "objectID": "94bbe93e-2e50-4694-a4bf-ecf12214ea02", + "objectID": "c400b72e-ba56-4b61-b7b1-690618b64d92", "type": "lvl3", "url": "/docs/components/checkbox#line-through", "hierarchy": { @@ -1794,7 +2333,7 @@ }, { "content": "Custom Check Icon", - "objectID": "3250015a-97f6-4e0f-a21f-f65c8b38dcf3", + "objectID": "c6ce858a-a34b-4d3a-a0ae-d96a524b4b5d", "type": "lvl3", "url": "/docs/components/checkbox#custom-check-icon", "hierarchy": { @@ -1805,7 +2344,7 @@ }, { "content": "Controlled", - "objectID": "6bfd68df-c0b4-4203-880f-92b94fd8d2a3", + "objectID": "4c5b7ec2-a0a4-42fc-bbfb-74397c087150", "type": "lvl3", "url": "/docs/components/checkbox#controlled", "hierarchy": { @@ -1816,14 +2355,14 @@ }, { "content": "Slots", - "objectID": "35c2c186-9b3f-43fb-aa2b-4559bd9cb856", + "objectID": "1255c432-45db-41d9-ac52-bdb28d23bf8b", "type": "lvl2", "url": "/docs/components/checkbox#slots", "hierarchy": { "lvl1": "Checkbox", "lvl2": "Slots", "lvl3": null } }, { "content": "Custom Styles", - "objectID": "09674ff7-2510-4166-8891-64fc9c3f7820", + "objectID": "83cf1ad4-b0fc-4236-a490-a231b6b7c7e3", "type": "lvl3", "url": "/docs/components/checkbox#custom-styles", "hierarchy": { @@ -1834,7 +2373,7 @@ }, { "content": "Custom Implementation", - "objectID": "79c13af6-ce8b-4135-acb1-e2740571988f", + "objectID": "0063df0b-3c34-4ff0-b350-418d411b5d99", "type": "lvl3", "url": "/docs/components/checkbox#custom-implementation", "hierarchy": { @@ -1845,35 +2384,35 @@ }, { "content": "Data Attributes", - "objectID": "375c2e70-3028-4aed-b7c5-3e178d7d2ac5", + "objectID": "09c934f2-f090-44ae-8aba-8a58015951a4", "type": "lvl2", "url": "/docs/components/checkbox#data-attributes", "hierarchy": { "lvl1": "Checkbox", "lvl2": "Data Attributes", "lvl3": null } }, { "content": "Accessibility", - "objectID": "8989c89e-e6d8-4180-955c-ae298e03bd70", + "objectID": "63f68dcf-4621-4baa-ad48-f3357afef864", "type": "lvl2", "url": "/docs/components/checkbox#accessibility", "hierarchy": { "lvl1": "Checkbox", "lvl2": "Accessibility", "lvl3": null } }, { "content": "API", - "objectID": "cafaa1cc-c726-4b48-b6a5-716f432a13aa", + "objectID": "42b7b8b3-92b2-4bf7-a5ef-c04d12531f33", "type": "lvl2", "url": "/docs/components/checkbox#api", "hierarchy": { "lvl1": "Checkbox", "lvl2": "API", "lvl3": null } }, { "content": "Checkbox Props", - "objectID": "80897a73-ae67-47d5-8eb4-aa38167bf438", + "objectID": "ddaac5be-d104-4481-8829-613111d142e3", "type": "lvl3", "url": "/docs/components/checkbox#checkbox-props", "hierarchy": { "lvl1": "Checkbox", "lvl2": "API", "lvl3": "Checkbox Props" } }, { "content": "Checkbox Events", - "objectID": "a1ef87c2-3ee6-46f7-894a-57b85e810f13", + "objectID": "ed81d821-a9e6-4559-8e8a-cf0831e80ff9", "type": "lvl3", "url": "/docs/components/checkbox#checkbox-events", "hierarchy": { @@ -1884,7 +2423,7 @@ }, { "content": "Types", - "objectID": "3369fc2d-02c3-4acd-9278-b40c57e169a8", + "objectID": "d9f073d6-2e18-4dec-b6cc-755218b73c60", "type": "lvl3", "url": "/docs/components/checkbox#types", "hierarchy": { @@ -1895,70 +2434,77 @@ }, { "content": "Checkbox Icon Props", - "objectID": "3daf0263-d3e6-4f57-9e6a-ba1c1ef08cac", + "objectID": "fe2fc0d3-225d-4291-b2f9-83cfe7042bfd", "type": "lvl4", "url": "/docs/components/checkbox#checkbox-icon-props", "hierarchy": { "lvl1": "Checkbox", "lvl2": "Types", "lvl3": null } }, { "content": "Chip", - "objectID": "a873ad0b-d6cd-4524-a643-2e984d707c8e", + "objectID": "d97b98b8-c51c-4679-81e8-5a8e3abbc008", "type": "lvl1", "url": "/docs/components/chip", "hierarchy": { "lvl1": "Chip" } }, + { + "content": "Installation", + "objectID": "564c5559-afc6-47d2-98d2-8bb793ca2d6f", + "type": "lvl2", + "url": "/docs/components/chip#installation", + "hierarchy": { "lvl1": "Chip", "lvl2": "Installation", "lvl3": null } + }, { "content": "Import", - "objectID": "ca05f451-f787-4524-b56b-516e680e86fa", + "objectID": "7f15650b-cc82-4bec-bca0-08fd6b0141fc", "type": "lvl2", "url": "/docs/components/chip#import", "hierarchy": { "lvl1": "Chip", "lvl2": "Import", "lvl3": null } }, { "content": "Usage", - "objectID": "1a117764-cf7a-41b8-9dac-5532e2438e7b", + "objectID": "a56618d1-dc95-4dd5-af03-b730e3217753", "type": "lvl2", "url": "/docs/components/chip#usage", "hierarchy": { "lvl1": "Chip", "lvl2": "Usage", "lvl3": null } }, { "content": "Disabled", - "objectID": "b3755ee1-357c-45e5-acb7-de4524221f3f", + "objectID": "4aa3f019-8d62-41e3-afc0-f3e79ce524e7", "type": "lvl3", "url": "/docs/components/chip#disabled", "hierarchy": { "lvl1": "Chip", "lvl2": "Usage", "lvl3": "Disabled" } }, { "content": "Sizes", - "objectID": "9ea53914-03b2-444a-bc61-fe9c206a897a", + "objectID": "e5d19732-6362-4a1d-ab93-c977b84b19b4", "type": "lvl3", "url": "/docs/components/chip#sizes", "hierarchy": { "lvl1": "Chip", "lvl2": "Disabled", "lvl3": "Sizes" } }, { "content": "Colors", - "objectID": "8e9eed3b-ada0-413a-a0ef-d6fa3345f7e2", + "objectID": "7daaf942-5f56-4116-b129-1f3ef785755f", "type": "lvl3", "url": "/docs/components/chip#colors", "hierarchy": { "lvl1": "Chip", "lvl2": "Sizes", "lvl3": "Colors" } }, { "content": "Radius", - "objectID": "54f5de69-ed84-4394-abfa-106c3e71781e", + "objectID": "ec1d3326-2331-42ad-95a7-04e7ffc9d4b0", "type": "lvl3", "url": "/docs/components/chip#radius", "hierarchy": { "lvl1": "Chip", "lvl2": "Colors", "lvl3": "Radius" } }, { "content": "Variants", - "objectID": "522f4287-bf9b-491f-8bd8-a47e27ae1708", + "objectID": "7408324b-6838-4caf-871d-e4f52085b424", "type": "lvl3", "url": "/docs/components/chip#variants", "hierarchy": { "lvl1": "Chip", "lvl2": "Radius", "lvl3": "Variants" } }, { "content": "Start & End Content", - "objectID": "a2161d8a-35c9-471a-8c05-4aad5effda2d", + "objectID": "e35479ef-4384-40d8-a897-9d022516765b", "type": "lvl3", "url": "/docs/components/chip#start--end-content", "hierarchy": { @@ -1969,7 +2515,7 @@ }, { "content": "With Close Button", - "objectID": "f5798cfb-b142-4f86-91cf-f521e76a411c", + "objectID": "f6f1a533-534a-420c-9f29-f7b65af1b1fc", "type": "lvl3", "url": "/docs/components/chip#with-close-button", "hierarchy": { @@ -1980,7 +2526,7 @@ }, { "content": "With Avatar", - "objectID": "f4776dc3-37ec-48a7-a2e0-2d11312453f3", + "objectID": "9b04a404-bc7c-42cb-96df-ff118b18c33e", "type": "lvl3", "url": "/docs/components/chip#with-avatar", "hierarchy": { @@ -1991,7 +2537,7 @@ }, { "content": "List of Chips", - "objectID": "7220d2dd-1e6b-4aee-a349-d17438579534", + "objectID": "6d004b09-ad8a-406c-b6b8-61a63bada6e5", "type": "lvl3", "url": "/docs/components/chip#list-of-chips", "hierarchy": { @@ -2002,63 +2548,74 @@ }, { "content": "Slots", - "objectID": "9fb0f810-8d1b-485e-8ef5-7eb964c093f1", + "objectID": "ae2c74d4-47b0-471b-819d-ee6e3e4d00e0", "type": "lvl2", "url": "/docs/components/chip#slots", "hierarchy": { "lvl1": "Chip", "lvl2": "Slots", "lvl3": null } }, { "content": "Custom Styles", - "objectID": "592a9095-00a3-4b85-9abe-dadaad606a1d", + "objectID": "908a98d8-2cb8-4075-8f30-ab32ba02fdc0", "type": "lvl3", "url": "/docs/components/chip#custom-styles", "hierarchy": { "lvl1": "Chip", "lvl2": "Slots", "lvl3": "Custom Styles" } }, { "content": "API", - "objectID": "ad1635a8-328b-46e6-afc5-7749fe46ded9", + "objectID": "01033136-2cb3-403c-8cd1-fa1bbb0ad8b3", "type": "lvl2", "url": "/docs/components/chip#api", "hierarchy": { "lvl1": "Chip", "lvl2": "API", "lvl3": null } }, { "content": "Chip Props", - "objectID": "f3577f7f-724d-4d71-a886-b9dd42f9db1b", + "objectID": "c199dcf6-7b67-4aea-b7ce-681189b9ee0a", "type": "lvl3", "url": "/docs/components/chip#chip-props", "hierarchy": { "lvl1": "Chip", "lvl2": "API", "lvl3": "Chip Props" } }, { "content": "Chip Events", - "objectID": "91cf9210-8383-47dc-b1cc-062edeed7884", + "objectID": "a1d8e1f7-455e-48ec-a900-8af579cc1e7e", "type": "lvl3", "url": "/docs/components/chip#chip-events", "hierarchy": { "lvl1": "Chip", "lvl2": "Chip Props", "lvl3": "Chip Events" } }, { "content": "Circular Progress", - "objectID": "e2171b2a-89bb-49c4-8ce8-1888b6c00c44", + "objectID": "c0607e80-d672-4fc1-8060-a6df6c189bcb", "type": "lvl1", "url": "/docs/components/circular-progress", "hierarchy": { "lvl1": "Circular Progress" } }, + { + "content": "Installation", + "objectID": "30a09286-aded-4140-84ca-9e4c1e38cec3", + "type": "lvl2", + "url": "/docs/components/circular-progress#installation", + "hierarchy": { + "lvl1": "Circular Progress", + "lvl2": "Installation", + "lvl3": null + } + }, { "content": "Import", - "objectID": "7bdf911f-25e2-479e-b795-8c5eae14531b", + "objectID": "4bd8452b-9ee0-4547-ade9-907f4fe4a0a1", "type": "lvl2", "url": "/docs/components/circular-progress#import", "hierarchy": { "lvl1": "Circular Progress", "lvl2": "Import", "lvl3": null } }, { "content": "Usage", - "objectID": "c17fbc25-1182-45b0-851e-05a57165ec6e", + "objectID": "59b1bbaa-1ee4-45ca-9e66-8ef327f6a82d", "type": "lvl2", "url": "/docs/components/circular-progress#usage", "hierarchy": { "lvl1": "Circular Progress", "lvl2": "Usage", "lvl3": null } }, { "content": "Sizes", - "objectID": "f23b7eaa-95ac-4121-b061-e42727b2147f", + "objectID": "30c8db81-5997-439b-8d2e-ed604ca0978d", "type": "lvl3", "url": "/docs/components/circular-progress#sizes", "hierarchy": { @@ -2069,7 +2626,7 @@ }, { "content": "Colors", - "objectID": "9bde6395-649d-416e-89dc-a688a172abcd", + "objectID": "85f8d788-7cdd-431d-9fac-77110d2613c0", "type": "lvl3", "url": "/docs/components/circular-progress#colors", "hierarchy": { @@ -2080,7 +2637,7 @@ }, { "content": "With Label", - "objectID": "8d37bdf4-16c1-4ca7-8aac-5842e3ae508e", + "objectID": "a82ffe55-1bec-49ca-b0dd-324802cab1da", "type": "lvl3", "url": "/docs/components/circular-progress#with-label", "hierarchy": { @@ -2091,7 +2648,7 @@ }, { "content": "With Value", - "objectID": "b3ec9e1e-85a6-4b6d-a3f3-a630b52eeac3", + "objectID": "4fb88960-5bca-43e6-9f01-09ef9412b8dd", "type": "lvl3", "url": "/docs/components/circular-progress#with-value", "hierarchy": { @@ -2102,7 +2659,7 @@ }, { "content": "Value Formatting", - "objectID": "a8376809-3424-4ee3-b123-2d249f1350bf", + "objectID": "9ea8134d-205d-4cd4-a4cf-40096ee88af1", "type": "lvl3", "url": "/docs/components/circular-progress#value-formatting", "hierarchy": { @@ -2113,14 +2670,14 @@ }, { "content": "Slots", - "objectID": "6984c3b5-3a47-41e4-b4e2-549098ee633f", + "objectID": "57922dbd-f9f1-4871-9506-9302ff4b2ed0", "type": "lvl2", "url": "/docs/components/circular-progress#slots", "hierarchy": { "lvl1": "Circular Progress", "lvl2": "Slots", "lvl3": null } }, { "content": "Custom Styles", - "objectID": "efac96e7-7abc-40ee-b2c1-19212f0dfbd4", + "objectID": "004a464d-9009-4f9b-b7f6-a5770ee14bb4", "type": "lvl3", "url": "/docs/components/circular-progress#custom-styles", "hierarchy": { @@ -2131,166 +2688,1001 @@ }, { "content": "Data Attributes", - "objectID": "d155e0c9-f2ad-4eea-88e6-98d153159236", + "objectID": "f9ba9b7a-0def-47ba-9cb6-8e7c23cc5f41", + "type": "lvl2", + "url": "/docs/components/circular-progress#data-attributes", + "hierarchy": { + "lvl1": "Circular Progress", + "lvl2": "Data Attributes", + "lvl3": null + } + }, + { + "content": "Accessibility", + "objectID": "a94bb28a-72df-4fb6-aac5-7a0bae6113da", + "type": "lvl2", + "url": "/docs/components/circular-progress#accessibility", + "hierarchy": { + "lvl1": "Circular Progress", + "lvl2": "Accessibility", + "lvl3": null + } + }, + { + "content": "API", + "objectID": "b44d543a-537b-4253-9fde-e9f95bed9340", + "type": "lvl2", + "url": "/docs/components/circular-progress#api", + "hierarchy": { "lvl1": "Circular Progress", "lvl2": "API", "lvl3": null } + }, + { + "content": "Circular Progress Props", + "objectID": "0210e5b9-a76f-4a91-8a01-529ce3870bd8", + "type": "lvl3", + "url": "/docs/components/circular-progress#circular-progress-props", + "hierarchy": { + "lvl1": "Circular Progress", + "lvl2": "API", + "lvl3": "Circular Progress Props" + } + }, + { + "content": "Code", + "objectID": "cf07fd4e-6c7e-4890-a704-69fb6d7bb8f1", + "type": "lvl1", + "url": "/docs/components/code", + "hierarchy": { "lvl1": "Code" } + }, + { + "content": "Installation", + "objectID": "ec660c98-25fe-43d2-a2c2-cfc8eaf6db7c", + "type": "lvl2", + "url": "/docs/components/code#installation", + "hierarchy": { "lvl1": "Code", "lvl2": "Installation", "lvl3": null } + }, + { + "content": "Import", + "objectID": "7587d40c-2349-486a-8cc7-99936165f93a", + "type": "lvl2", + "url": "/docs/components/code#import", + "hierarchy": { "lvl1": "Code", "lvl2": "Import", "lvl3": null } + }, + { + "content": "Usage", + "objectID": "d38ca906-712e-4940-ae31-6dfd57b16705", + "type": "lvl2", + "url": "/docs/components/code#usage", + "hierarchy": { "lvl1": "Code", "lvl2": "Usage", "lvl3": null } + }, + { + "content": "Sizes", + "objectID": "e710681f-26e1-4b82-b32c-c5a7ce7c9092", + "type": "lvl3", + "url": "/docs/components/code#sizes", + "hierarchy": { "lvl1": "Code", "lvl2": "Usage", "lvl3": "Sizes" } + }, + { + "content": "Colors", + "objectID": "6ac8f63b-1f2e-448a-8db5-e8937dff1743", + "type": "lvl3", + "url": "/docs/components/code#colors", + "hierarchy": { "lvl1": "Code", "lvl2": "Sizes", "lvl3": "Colors" } + }, + { + "content": "API", + "objectID": "cedfd15b-a490-422a-b076-4d3064968ddd", + "type": "lvl2", + "url": "/docs/components/code#api", + "hierarchy": { "lvl1": "Code", "lvl2": "API", "lvl3": null } + }, + { + "content": "Code Props", + "objectID": "0b61944c-44f8-4692-8524-70cfce5dacc7", + "type": "lvl3", + "url": "/docs/components/code#code-props", + "hierarchy": { "lvl1": "Code", "lvl2": "API", "lvl3": "Code Props" } + }, + { + "content": "DateInput", + "objectID": "8c80aedb-d84d-4b5b-aea0-6b64aab4b6d3", + "type": "lvl1", + "url": "/docs/components/date-input", + "hierarchy": { "lvl1": "DateInput" } + }, + { + "content": "Installation", + "objectID": "1e90ebdb-9846-45d8-9cbc-2d78af13185a", + "type": "lvl2", + "url": "/docs/components/date-input#installation", + "hierarchy": { "lvl1": "DateInput", "lvl2": "Installation", "lvl3": null } + }, + { + "content": "Import", + "objectID": "b9ba2757-8a07-46b9-9042-39dc9b36e677", + "type": "lvl2", + "url": "/docs/components/date-input#import", + "hierarchy": { "lvl1": "DateInput", "lvl2": "Import", "lvl3": null } + }, + { + "content": "Usage", + "objectID": "62badf7b-5fd3-4f62-8012-48339e6199e6", + "type": "lvl2", + "url": "/docs/components/date-input#usage", + "hierarchy": { "lvl1": "DateInput", "lvl2": "Usage", "lvl3": null } + }, + { + "content": "Disabled", + "objectID": "a193089f-ade7-4338-b306-3b35e1d9231c", + "type": "lvl3", + "url": "/docs/components/date-input#disabled", + "hierarchy": { "lvl1": "DateInput", "lvl2": "Usage", "lvl3": "Disabled" } + }, + { + "content": "Read Only", + "objectID": "c94392f7-0dc0-413b-b357-30c86d7270f5", + "type": "lvl3", + "url": "/docs/components/date-input#read-only", + "hierarchy": { + "lvl1": "DateInput", + "lvl2": "Disabled", + "lvl3": "Read Only" + } + }, + { + "content": "Required", + "objectID": "374fae73-7b13-4269-aadb-45e0ca94d3a3", + "type": "lvl3", + "url": "/docs/components/date-input#required", + "hierarchy": { + "lvl1": "DateInput", + "lvl2": "Read Only", + "lvl3": "Required" + } + }, + { + "content": "Variants", + "objectID": "f1cde3e6-78b8-4e73-a310-404cff60372e", + "type": "lvl3", + "url": "/docs/components/date-input#variants", + "hierarchy": { "lvl1": "DateInput", "lvl2": "Required", "lvl3": "Variants" } + }, + { + "content": "Label Placements", + "objectID": "9fbef8a5-425a-49aa-a2e5-3b03e0a7bd92", + "type": "lvl3", + "url": "/docs/components/date-input#label-placements", + "hierarchy": { + "lvl1": "DateInput", + "lvl2": "Variants", + "lvl3": "Label Placements" + } + }, + { + "content": "Start & End Content", + "objectID": "e0807aec-05b6-48dc-a738-841e94012873", + "type": "lvl3", + "url": "/docs/components/date-input#start--end-content", + "hierarchy": { + "lvl1": "DateInput", + "lvl2": "Label Placements", + "lvl3": "Start & End Content" + } + }, + { + "content": "With Description", + "objectID": "2ddbcebc-2400-47f9-83d2-2c46b15cb4ef", + "type": "lvl3", + "url": "/docs/components/date-input#with-description", + "hierarchy": { + "lvl1": "DateInput", + "lvl2": "Start & End Content", + "lvl3": "With Description" + } + }, + { + "content": "With Error Message", + "objectID": "48df5e3d-9386-4a0a-984d-2e587991438d", + "type": "lvl3", + "url": "/docs/components/date-input#with-error-message", + "hierarchy": { + "lvl1": "DateInput", + "lvl2": "With Description", + "lvl3": "With Error Message" + } + }, + { + "content": "Controlled", + "objectID": "632f4ff4-7a55-49e1-a71c-be1eefdbfba8", + "type": "lvl3", + "url": "/docs/components/date-input#controlled", + "hierarchy": { + "lvl1": "DateInput", + "lvl2": "With Error Message", + "lvl3": "Controlled" + } + }, + { + "content": "Time Zones", + "objectID": "9c608e5a-4d0c-43f0-ab21-f9e3241062c5", + "type": "lvl3", + "url": "/docs/components/date-input#time-zones", + "hierarchy": { + "lvl1": "DateInput", + "lvl2": "Controlled", + "lvl3": "Time Zones" + } + }, + { + "content": "Granularity", + "objectID": "87217e3a-0689-4b21-a531-7c54b83db4da", + "type": "lvl3", + "url": "/docs/components/date-input#granularity", + "hierarchy": { + "lvl1": "DateInput", + "lvl2": "Time Zones", + "lvl3": "Granularity" + } + }, + { + "content": "Min Date And Max Date", + "objectID": "7ecbe533-2ad4-4a07-a2ce-e93507878b8c", + "type": "lvl3", + "url": "/docs/components/date-input#min-date-and-max-date", + "hierarchy": { + "lvl1": "DateInput", + "lvl2": "Granularity", + "lvl3": "Min Date And Max Date" + } + }, + { + "content": "International Calendar", + "objectID": "5373a630-4e8b-475a-a2ee-4d3bf9cb76e1", + "type": "lvl3", + "url": "/docs/components/date-input#international-calendar", + "hierarchy": { + "lvl1": "DateInput", + "lvl2": "Min Date And Max Date", + "lvl3": "International Calendar" + } + }, + { + "content": "Hide Time Zone", + "objectID": "32a33adb-6ec4-4572-b49d-d7e3dc39426e", + "type": "lvl3", + "url": "/docs/components/date-input#hide-time-zone", + "hierarchy": { + "lvl1": "DateInput", + "lvl2": "International Calendar", + "lvl3": "Hide Time Zone" + } + }, + { + "content": "Hourly Cycle", + "objectID": "3ba902a5-e0fc-4ceb-8589-9282d6dfcc65", + "type": "lvl3", + "url": "/docs/components/date-input#hourly-cycle", + "hierarchy": { + "lvl1": "DateInput", + "lvl2": "Hide Time Zone", + "lvl3": "Hourly Cycle" + } + }, + { + "content": "Slots", + "objectID": "230d2f81-fcd5-41dd-88a3-066755e0f22a", + "type": "lvl2", + "url": "/docs/components/date-input#slots", + "hierarchy": { "lvl1": "DateInput", "lvl2": "Slots", "lvl3": null } + }, + { + "content": "Data Attributes", + "objectID": "863d2f50-d3da-430e-9357-90e61af97919", + "type": "lvl2", + "url": "/docs/components/date-input#data-attributes", + "hierarchy": { + "lvl1": "DateInput", + "lvl2": "Data Attributes", + "lvl3": null + } + }, + { + "content": "Accessibility", + "objectID": "45c2315f-7655-4dbf-882b-7f55e685e6fd", + "type": "lvl2", + "url": "/docs/components/date-input#accessibility", + "hierarchy": { "lvl1": "DateInput", "lvl2": "Accessibility", "lvl3": null } + }, + { + "content": "API", + "objectID": "e0def356-d55e-428a-b5b2-7db62f45c7a5", + "type": "lvl2", + "url": "/docs/components/date-input#api", + "hierarchy": { "lvl1": "DateInput", "lvl2": "API", "lvl3": null } + }, + { + "content": "DateInput Props", + "objectID": "ace3d888-f0f0-4536-8d1b-a2e91d19e4f5", + "type": "lvl3", + "url": "/docs/components/date-input#dateinput-props", + "hierarchy": { + "lvl1": "DateInput", + "lvl2": "API", + "lvl3": "DateInput Props" + } + }, + { + "content": "DateInput Events", + "objectID": "7f5d3562-5dfc-472d-bb60-a427b00f3ea9", + "type": "lvl3", + "url": "/docs/components/date-input#dateinput-events", + "hierarchy": { + "lvl1": "DateInput", + "lvl2": "DateInput Props", + "lvl3": "DateInput Events" + } + }, + { + "content": "DatePicker", + "objectID": "f24a3dcc-4c61-4ac9-b693-81850c0dd97b", + "type": "lvl1", + "url": "/docs/components/date-picker", + "hierarchy": { "lvl1": "DatePicker" } + }, + { + "content": "Installation", + "objectID": "51284fdb-ebe7-4b66-9a30-20bfc6753c54", + "type": "lvl2", + "url": "/docs/components/date-picker#installation", + "hierarchy": { "lvl1": "DatePicker", "lvl2": "Installation", "lvl3": null } + }, + { + "content": "Import", + "objectID": "5ff7efbb-5c6d-48b1-91bb-02bf3dc6c2e1", + "type": "lvl2", + "url": "/docs/components/date-picker#import", + "hierarchy": { "lvl1": "DatePicker", "lvl2": "Import", "lvl3": null } + }, + { + "content": "Usage", + "objectID": "58cd41f3-b17c-491d-89a5-0ca03551aa88", + "type": "lvl2", + "url": "/docs/components/date-picker#usage", + "hierarchy": { "lvl1": "DatePicker", "lvl2": "Usage", "lvl3": null } + }, + { + "content": "Disabled", + "objectID": "30a7c9d5-06e8-406b-beb3-65b857239d77", + "type": "lvl3", + "url": "/docs/components/date-picker#disabled", + "hierarchy": { "lvl1": "DatePicker", "lvl2": "Usage", "lvl3": "Disabled" } + }, + { + "content": "Read Only", + "objectID": "cf052b54-6a72-47d0-bad6-47afcdd70e9e", + "type": "lvl3", + "url": "/docs/components/date-picker#read-only", + "hierarchy": { + "lvl1": "DatePicker", + "lvl2": "Disabled", + "lvl3": "Read Only" + } + }, + { + "content": "Required", + "objectID": "25a97ead-92a1-47d3-a74d-40e9c0d993c5", + "type": "lvl3", + "url": "/docs/components/date-picker#required", + "hierarchy": { + "lvl1": "DatePicker", + "lvl2": "Read Only", + "lvl3": "Required" + } + }, + { + "content": "Variants", + "objectID": "8d98cfa0-b3c4-4456-b940-ae1f9e88eeda", + "type": "lvl3", + "url": "/docs/components/date-picker#variants", + "hierarchy": { + "lvl1": "DatePicker", + "lvl2": "Required", + "lvl3": "Variants" + } + }, + { + "content": "Label Placements", + "objectID": "ec726d03-fe3e-4d25-a6a0-4ebc3a1a8460", + "type": "lvl3", + "url": "/docs/components/date-picker#label-placements", + "hierarchy": { + "lvl1": "DatePicker", + "lvl2": "Variants", + "lvl3": "Label Placements" + } + }, + { + "content": "With Description", + "objectID": "f039e32b-578c-4b51-9295-04767433f4ae", + "type": "lvl3", + "url": "/docs/components/date-picker#with-description", + "hierarchy": { + "lvl1": "DatePicker", + "lvl2": "Label Placements", + "lvl3": "With Description" + } + }, + { + "content": "With Error Message", + "objectID": "ae1b99bf-19c4-4a1f-90fd-2cc8421cd183", + "type": "lvl3", + "url": "/docs/components/date-picker#with-error-message", + "hierarchy": { + "lvl1": "DatePicker", + "lvl2": "With Description", + "lvl3": "With Error Message" + } + }, + { + "content": "With Month and Year Pickers", + "objectID": "cdc2ef17-cef1-4452-bcd7-9591775384a3", + "type": "lvl3", + "url": "/docs/components/date-picker#with-month-and-year-pickers", + "hierarchy": { + "lvl1": "DatePicker", + "lvl2": "With Error Message", + "lvl3": "With Month and Year Pickers" + } + }, + { + "content": "With Time Fields", + "objectID": "2ddf5e77-4cde-4aae-8c84-7347ae88bd06", + "type": "lvl3", + "url": "/docs/components/date-picker#with-time-fields", + "hierarchy": { + "lvl1": "DatePicker", + "lvl2": "With Month and Year Pickers", + "lvl3": "With Time Fields" + } + }, + { + "content": "Selector Icon", + "objectID": "457269e3-4341-4af8-9f76-68a68e9a7205", + "type": "lvl3", + "url": "/docs/components/date-picker#selector-icon", + "hierarchy": { + "lvl1": "DatePicker", + "lvl2": "With Time Fields", + "lvl3": "Selector Icon" + } + }, + { + "content": "Controlled", + "objectID": "5cc80a7d-f237-4822-ab22-2ebf1d53a0a8", + "type": "lvl3", + "url": "/docs/components/date-picker#controlled", + "hierarchy": { + "lvl1": "DatePicker", + "lvl2": "Selector Icon", + "lvl3": "Controlled" + } + }, + { + "content": "Time Zones", + "objectID": "d2a12639-3b66-4fe8-8e31-fe8a1f4363eb", + "type": "lvl3", + "url": "/docs/components/date-picker#time-zones", + "hierarchy": { + "lvl1": "DatePicker", + "lvl2": "Controlled", + "lvl3": "Time Zones" + } + }, + { + "content": "Granularity", + "objectID": "9e0ea0d4-7e21-4bc4-adc5-35d6b2c41ba9", + "type": "lvl3", + "url": "/docs/components/date-picker#granularity", + "hierarchy": { + "lvl1": "DatePicker", + "lvl2": "Time Zones", + "lvl3": "Granularity" + } + }, + { + "content": "Min Date And Max Date", + "objectID": "49768cfd-891c-4205-8a1b-429b502d310d", + "type": "lvl3", + "url": "/docs/components/date-picker#min-date-and-max-date", + "hierarchy": { + "lvl1": "DatePicker", + "lvl2": "Granularity", + "lvl3": "Min Date And Max Date" + } + }, + { + "content": "International Calendar", + "objectID": "c3b2fc1b-9de0-4356-9852-00432d3c0bb7", + "type": "lvl3", + "url": "/docs/components/date-picker#international-calendar", + "hierarchy": { + "lvl1": "DatePicker", + "lvl2": "Min Date And Max Date", + "lvl3": "International Calendar" + } + }, + { + "content": "Unavailable Dates", + "objectID": "84e23f4a-cac7-4bf8-8e21-8607bc5654a2", + "type": "lvl3", + "url": "/docs/components/date-picker#unavailable-dates", + "hierarchy": { + "lvl1": "DatePicker", + "lvl2": "International Calendar", + "lvl3": "Unavailable Dates" + } + }, + { + "content": "Visible Months", + "objectID": "71b452fd-cd81-4d67-a31f-31ec7cae803b", + "type": "lvl3", + "url": "/docs/components/date-picker#visible-months", + "hierarchy": { + "lvl1": "DatePicker", + "lvl2": "Unavailable Dates", + "lvl3": "Visible Months" + } + }, + { + "content": "Page Behavior", + "objectID": "64f81eff-7262-4c81-889c-c9c9bd84cba8", + "type": "lvl3", + "url": "/docs/components/date-picker#page-behavior", + "hierarchy": { + "lvl1": "DatePicker", + "lvl2": "Visible Months", + "lvl3": "Page Behavior" + } + }, + { + "content": "Preset", + "objectID": "47ea7a28-4f9c-4ef7-a580-8001cbfe09cf", + "type": "lvl3", + "url": "/docs/components/date-picker#preset", + "hierarchy": { + "lvl1": "DatePicker", + "lvl2": "Page Behavior", + "lvl3": "Preset" + } + }, + { + "content": "Slots", + "objectID": "47d4cbce-8081-49e6-9e4c-92cd293ab869", + "type": "lvl2", + "url": "/docs/components/date-picker#slots", + "hierarchy": { "lvl1": "DatePicker", "lvl2": "Slots", "lvl3": null } + }, + { + "content": "Data Attributes", + "objectID": "faf9a3cc-bb72-42b5-9d23-af0b9c1e9ef3", + "type": "lvl2", + "url": "/docs/components/date-picker#data-attributes", + "hierarchy": { + "lvl1": "DatePicker", + "lvl2": "Data Attributes", + "lvl3": null + } + }, + { + "content": "Accessibility", + "objectID": "d3bb9d7b-c6d9-4d29-816b-b583ac162bd7", + "type": "lvl2", + "url": "/docs/components/date-picker#accessibility", + "hierarchy": { "lvl1": "DatePicker", "lvl2": "Accessibility", "lvl3": null } + }, + { + "content": "API", + "objectID": "c5e5a12e-0497-4089-91c1-486f85357ff6", + "type": "lvl2", + "url": "/docs/components/date-picker#api", + "hierarchy": { "lvl1": "DatePicker", "lvl2": "API", "lvl3": null } + }, + { + "content": "DatePicker Props", + "objectID": "8b6c51df-fded-4572-9bff-1140fd6061d7", + "type": "lvl3", + "url": "/docs/components/date-picker#datepicker-props", + "hierarchy": { + "lvl1": "DatePicker", + "lvl2": "API", + "lvl3": "DatePicker Props" + } + }, + { + "content": "DatePicker Events", + "objectID": "9a091269-8130-43ec-9619-18d5a5db1bf1", + "type": "lvl3", + "url": "/docs/components/date-picker#datepicker-events", + "hierarchy": { + "lvl1": "DatePicker", + "lvl2": "DatePicker Props", + "lvl3": "DatePicker Events" + } + }, + { + "content": "Date Range Picker", + "objectID": "9475d30d-832a-4ce5-bc21-34d278195f1b", + "type": "lvl1", + "url": "/docs/components/date-range-picker", + "hierarchy": { "lvl1": "Date Range Picker" } + }, + { + "content": "Import", + "objectID": "c97ec6f2-e0da-4ae1-af47-149db1b734dd", + "type": "lvl2", + "url": "/docs/components/date-range-picker#import", + "hierarchy": { "lvl1": "Date Range Picker", "lvl2": "Import", "lvl3": null } + }, + { + "content": "Usage", + "objectID": "03c1198c-e7a5-4227-9429-f13f59d76050", + "type": "lvl2", + "url": "/docs/components/date-range-picker#usage", + "hierarchy": { "lvl1": "Date Range Picker", "lvl2": "Usage", "lvl3": null } + }, + { + "content": "Disabled", + "objectID": "72e932e6-1fc9-4512-bb06-3cf51e62a69d", + "type": "lvl3", + "url": "/docs/components/date-range-picker#disabled", + "hierarchy": { + "lvl1": "Date Range Picker", + "lvl2": "Usage", + "lvl3": "Disabled" + } + }, + { + "content": "Read Only", + "objectID": "62c8ca62-bc88-40bc-92e8-446328938a0b", + "type": "lvl3", + "url": "/docs/components/date-range-picker#read-only", + "hierarchy": { + "lvl1": "Date Range Picker", + "lvl2": "Disabled", + "lvl3": "Read Only" + } + }, + { + "content": "Required", + "objectID": "47eca5ba-10b4-4b31-a3da-15470b7690cc", + "type": "lvl3", + "url": "/docs/components/date-range-picker#required", + "hierarchy": { + "lvl1": "Date Range Picker", + "lvl2": "Read Only", + "lvl3": "Required" + } + }, + { + "content": "Variants", + "objectID": "8e79bfe0-08e0-466c-abbe-c18e72674c04", + "type": "lvl3", + "url": "/docs/components/date-range-picker#variants", + "hierarchy": { + "lvl1": "Date Range Picker", + "lvl2": "Required", + "lvl3": "Variants" + } + }, + { + "content": "Label Placements", + "objectID": "d924aca1-f449-465f-bfef-9e284b252173", + "type": "lvl3", + "url": "/docs/components/date-range-picker#label-placements", + "hierarchy": { + "lvl1": "Date Range Picker", + "lvl2": "Variants", + "lvl3": "Label Placements" + } + }, + { + "content": "With Description", + "objectID": "fd39c7e6-e4bb-4638-944c-7bdb8479bd43", + "type": "lvl3", + "url": "/docs/components/date-range-picker#with-description", + "hierarchy": { + "lvl1": "Date Range Picker", + "lvl2": "Label Placements", + "lvl3": "With Description" + } + }, + { + "content": "With Error Message", + "objectID": "b06b5f6a-68b6-4b8b-9dbe-c0d7335a606f", + "type": "lvl3", + "url": "/docs/components/date-range-picker#with-error-message", + "hierarchy": { + "lvl1": "Date Range Picker", + "lvl2": "With Description", + "lvl3": "With Error Message" + } + }, + { + "content": "With Time Fields", + "objectID": "ed328851-bc6a-4e19-add4-f71adf1c57f3", + "type": "lvl3", + "url": "/docs/components/date-range-picker#with-time-fields", + "hierarchy": { + "lvl1": "Date Range Picker", + "lvl2": "With Error Message", + "lvl3": "With Time Fields" + } + }, + { + "content": "Selector Icon", + "objectID": "ae51ba93-ca4f-4212-b5ce-8df3d4c8b79f", + "type": "lvl3", + "url": "/docs/components/date-range-picker#selector-icon", + "hierarchy": { + "lvl1": "Date Range Picker", + "lvl2": "With Time Fields", + "lvl3": "Selector Icon" + } + }, + { + "content": "Controlled", + "objectID": "ead1c015-c6f2-4af0-a81b-3e4d3c0bde3a", + "type": "lvl3", + "url": "/docs/components/date-range-picker#controlled", + "hierarchy": { + "lvl1": "Date Range Picker", + "lvl2": "Selector Icon", + "lvl3": "Controlled" + } + }, + { + "content": "Time Zones", + "objectID": "990f65f0-192c-4edd-8eff-dc33e93487dc", + "type": "lvl3", + "url": "/docs/components/date-range-picker#time-zones", + "hierarchy": { + "lvl1": "Date Range Picker", + "lvl2": "Controlled", + "lvl3": "Time Zones" + } + }, + { + "content": "Granularity", + "objectID": "5d8b6708-46f2-48d0-a7a9-bad993641ab1", + "type": "lvl3", + "url": "/docs/components/date-range-picker#granularity", + "hierarchy": { + "lvl1": "Date Range Picker", + "lvl2": "Time Zones", + "lvl3": "Granularity" + } + }, + { + "content": "Min Date And Max Date", + "objectID": "499635b7-561b-4e3d-b115-fab677e6b32f", + "type": "lvl3", + "url": "/docs/components/date-range-picker#min-date-and-max-date", + "hierarchy": { + "lvl1": "Date Range Picker", + "lvl2": "Granularity", + "lvl3": "Min Date And Max Date" + } + }, + { + "content": "International Calendar", + "objectID": "c4b18b61-fbd8-490e-b7a8-c9e78bc56e56", + "type": "lvl3", + "url": "/docs/components/date-range-picker#international-calendar", + "hierarchy": { + "lvl1": "Date Range Picker", + "lvl2": "Min Date And Max Date", + "lvl3": "International Calendar" + } + }, + { + "content": "Unavailable Dates", + "objectID": "a235fa13-2985-48f8-80d2-1cee8d94d31d", + "type": "lvl3", + "url": "/docs/components/date-range-picker#unavailable-dates", + "hierarchy": { + "lvl1": "Date Range Picker", + "lvl2": "International Calendar", + "lvl3": "Unavailable Dates" + } + }, + { + "content": "Non Contiguous", + "objectID": "2de67aa5-5de4-434e-947d-3d158a6f9e55", + "type": "lvl3", + "url": "/docs/components/date-range-picker#non-contiguous", + "hierarchy": { + "lvl1": "Date Range Picker", + "lvl2": "Unavailable Dates", + "lvl3": "Non Contiguous" + } + }, + { + "content": "Visible Months", + "objectID": "3c72a958-b816-46d0-b4a7-aa9db8f428f7", + "type": "lvl3", + "url": "/docs/components/date-range-picker#visible-months", + "hierarchy": { + "lvl1": "Date Range Picker", + "lvl2": "Non Contiguous", + "lvl3": "Visible Months" + } + }, + { + "content": "Page Behavior", + "objectID": "d7f0af72-2ac2-49b8-9b2d-8a75faaabac4", + "type": "lvl3", + "url": "/docs/components/date-range-picker#page-behavior", + "hierarchy": { + "lvl1": "Date Range Picker", + "lvl2": "Visible Months", + "lvl3": "Page Behavior" + } + }, + { + "content": "Presets", + "objectID": "6d1bdc43-1471-459c-a64b-9e0c2b7b584f", + "type": "lvl3", + "url": "/docs/components/date-range-picker#presets", + "hierarchy": { + "lvl1": "Date Range Picker", + "lvl2": "Page Behavior", + "lvl3": "Presets" + } + }, + { + "content": "Slots", + "objectID": "30b609f2-a752-44c2-90de-d6f217f165af", + "type": "lvl2", + "url": "/docs/components/date-range-picker#slots", + "hierarchy": { "lvl1": "Date Range Picker", "lvl2": "Slots", "lvl3": null } + }, + { + "content": "Data Attributes", + "objectID": "64a21bd9-8449-4e02-a9e5-c8524d5654a1", "type": "lvl2", - "url": "/docs/components/circular-progress#data-attributes", + "url": "/docs/components/date-range-picker#data-attributes", "hierarchy": { - "lvl1": "Circular Progress", + "lvl1": "Date Range Picker", "lvl2": "Data Attributes", "lvl3": null } }, { "content": "Accessibility", - "objectID": "535b4eb3-322a-401b-b5d7-51b11d51fe1c", + "objectID": "42526581-20e6-4c63-86d7-0c3f27c00ad0", "type": "lvl2", - "url": "/docs/components/circular-progress#accessibility", + "url": "/docs/components/date-range-picker#accessibility", "hierarchy": { - "lvl1": "Circular Progress", + "lvl1": "Date Range Picker", "lvl2": "Accessibility", "lvl3": null } }, { "content": "API", - "objectID": "dd63eeea-ade4-4d44-9134-dc63153e1ac5", + "objectID": "dc33ac42-aa9d-4e91-a9b4-ea9c203f83ac", "type": "lvl2", - "url": "/docs/components/circular-progress#api", - "hierarchy": { "lvl1": "Circular Progress", "lvl2": "API", "lvl3": null } + "url": "/docs/components/date-range-picker#api", + "hierarchy": { "lvl1": "Date Range Picker", "lvl2": "API", "lvl3": null } }, { - "content": "Circular Progress Props", - "objectID": "8ae86ccb-62cf-465a-adb2-21164eb7f33c", + "content": "DateRangePicker Props", + "objectID": "cf869298-811d-4ed3-a89c-dd1924615b06", "type": "lvl3", - "url": "/docs/components/circular-progress#circular-progress-props", + "url": "/docs/components/date-range-picker#daterangepicker-props", "hierarchy": { - "lvl1": "Circular Progress", + "lvl1": "Date Range Picker", "lvl2": "API", - "lvl3": "Circular Progress Props" + "lvl3": "DateRangePicker Props" } }, { - "content": "Code", - "objectID": "12600dc6-2e83-42a6-b590-a32e26e3eec2", - "type": "lvl1", - "url": "/docs/components/code", - "hierarchy": { "lvl1": "Code" } - }, - { - "content": "Import", - "objectID": "f3d01ba7-c666-4649-84bd-2db6e2a0feac", - "type": "lvl2", - "url": "/docs/components/code#import", - "hierarchy": { "lvl1": "Code", "lvl2": "Import", "lvl3": null } - }, - { - "content": "Usage", - "objectID": "a9feab92-a1f2-4e1d-a925-3eb1e2e03144", - "type": "lvl2", - "url": "/docs/components/code#usage", - "hierarchy": { "lvl1": "Code", "lvl2": "Usage", "lvl3": null } - }, - { - "content": "Sizes", - "objectID": "e813baf8-6a7a-4a05-86cc-51b81dc5efc3", - "type": "lvl3", - "url": "/docs/components/code#sizes", - "hierarchy": { "lvl1": "Code", "lvl2": "Usage", "lvl3": "Sizes" } - }, - { - "content": "Colors", - "objectID": "200eb54f-ad8f-473e-b154-b642e8c7d849", - "type": "lvl3", - "url": "/docs/components/code#colors", - "hierarchy": { "lvl1": "Code", "lvl2": "Sizes", "lvl3": "Colors" } - }, - { - "content": "API", - "objectID": "1364ea88-9c19-43cb-ad2d-70effa81d56f", - "type": "lvl2", - "url": "/docs/components/code#api", - "hierarchy": { "lvl1": "Code", "lvl2": "API", "lvl3": null } - }, - { - "content": "Code Props", - "objectID": "8391d88a-246f-447b-9c28-8330cf3b1fd6", + "content": "DateRangePicker Events", + "objectID": "3b78ff5a-bbb2-41ad-9c6f-1a5a20197114", "type": "lvl3", - "url": "/docs/components/code#code-props", - "hierarchy": { "lvl1": "Code", "lvl2": "API", "lvl3": "Code Props" } + "url": "/docs/components/date-range-picker#daterangepicker-events", + "hierarchy": { + "lvl1": "Date Range Picker", + "lvl2": "DateRangePicker Props", + "lvl3": "DateRangePicker Events" + } }, { "content": "Divider", - "objectID": "c8413f05-1dbc-4160-992b-2215e40c817f", + "objectID": "06607d44-a408-4d2f-8113-5e538e1d0038", "type": "lvl1", "url": "/docs/components/divider", "hierarchy": { "lvl1": "Divider" } }, + { + "content": "Installation", + "objectID": "b5eb5595-ce15-4e5a-abe9-886e774bea7f", + "type": "lvl2", + "url": "/docs/components/divider#installation", + "hierarchy": { "lvl1": "Divider", "lvl2": "Installation", "lvl3": null } + }, { "content": "Import", - "objectID": "875d5b39-f276-4192-bfd5-5dbba82fadca", + "objectID": "94febf42-11a2-47ae-a13c-6eef8f138d32", "type": "lvl2", "url": "/docs/components/divider#import", "hierarchy": { "lvl1": "Divider", "lvl2": "Import", "lvl3": null } }, { "content": "Usage", - "objectID": "9ed1926c-7cfd-4f5b-a918-396a3bf23f63", + "objectID": "6d11988d-2619-4b98-9e73-34402d452ce5", "type": "lvl2", "url": "/docs/components/divider#usage", "hierarchy": { "lvl1": "Divider", "lvl2": "Usage", "lvl3": null } }, { "content": "Data Attributes", - "objectID": "9635ea1d-b940-47f1-a74b-cb51ab44cf64", + "objectID": "443a46fd-38d8-4022-812f-3f798dff8e2e", "type": "lvl2", "url": "/docs/components/divider#data-attributes", "hierarchy": { "lvl1": "Divider", "lvl2": "Data Attributes", "lvl3": null } }, { "content": "Accessibility", - "objectID": "f9b72d28-a282-4ccd-8742-a4b005024ab4", + "objectID": "085da30c-642e-4e83-9ccc-b74a6876beb6", "type": "lvl2", "url": "/docs/components/divider#accessibility", "hierarchy": { "lvl1": "Divider", "lvl2": "Accessibility", "lvl3": null } }, { "content": "API", - "objectID": "36837667-c905-44ef-beda-8bb857bdb7ec", + "objectID": "f013c11b-14d2-4190-a833-15634e28d06f", "type": "lvl2", "url": "/docs/components/divider#api", "hierarchy": { "lvl1": "Divider", "lvl2": "API", "lvl3": null } }, { "content": "Divider Props", - "objectID": "319b43ca-d65e-462f-ac2a-244192ff7559", + "objectID": "180f296d-2661-44ad-a12d-43508d59431c", "type": "lvl3", "url": "/docs/components/divider#divider-props", "hierarchy": { "lvl1": "Divider", "lvl2": "API", "lvl3": "Divider Props" } }, { "content": "Dropdown", - "objectID": "4d3586ad-70a8-4eea-a1cf-cfc43d5d9b3c", + "objectID": "a4b6187a-ad4a-4e68-9d27-ecb4045f0e8e", "type": "lvl1", "url": "/docs/components/dropdown", "hierarchy": { "lvl1": "Dropdown" } }, + { + "content": "Installation", + "objectID": "e830d76c-c551-4067-af1f-ffeaeeb103a7", + "type": "lvl2", + "url": "/docs/components/dropdown#installation", + "hierarchy": { "lvl1": "Dropdown", "lvl2": "Installation", "lvl3": null } + }, { "content": "Import", - "objectID": "f5025557-1440-4fd3-8815-6fc2ecf13839", + "objectID": "49011ef6-a8f4-443a-816e-735beefb2d61", "type": "lvl2", "url": "/docs/components/dropdown#import", "hierarchy": { "lvl1": "Dropdown", "lvl2": "Import", "lvl3": null } }, { "content": "Usage", - "objectID": "8e79edb7-dfef-47cd-b7ee-5a566ed94f71", + "objectID": "76b3bda6-f400-4fc4-84b3-672077b7850a", "type": "lvl2", "url": "/docs/components/dropdown#usage", "hierarchy": { "lvl1": "Dropdown", "lvl2": "Usage", "lvl3": null } }, { "content": "Dynamic items", - "objectID": "c7626454-265e-4597-8371-abba91f1a233", + "objectID": "4054f685-3c0d-4e58-89ec-948415ab2864", "type": "lvl3", "url": "/docs/components/dropdown#dynamic-items", "hierarchy": { @@ -2301,7 +3693,7 @@ }, { "content": "Disabled Keys", - "objectID": "c5f0f094-36ac-4a50-aea4-2601a8b055cf", + "objectID": "8b128ff1-158e-4441-b9ca-1e6533c40f91", "type": "lvl3", "url": "/docs/components/dropdown#disabled-keys", "hierarchy": { @@ -2312,7 +3704,7 @@ }, { "content": "Action event", - "objectID": "f6baf6f0-e831-4501-a2ef-3548d1023f84", + "objectID": "f1c20e40-9122-41ad-99ac-d2c0bc35629b", "type": "lvl3", "url": "/docs/components/dropdown#action-event", "hierarchy": { @@ -2323,7 +3715,7 @@ }, { "content": "Variants", - "objectID": "fe7da893-f077-4465-8c86-b9c9dfde838b", + "objectID": "66650e65-41de-432e-a4a1-e6d1668a5372", "type": "lvl3", "url": "/docs/components/dropdown#variants", "hierarchy": { @@ -2334,7 +3726,7 @@ }, { "content": "Single Selection", - "objectID": "d38052c2-5196-4be0-9ba5-f03282626926", + "objectID": "1bc80e7e-379a-408f-b63a-7193a47319e9", "type": "lvl3", "url": "/docs/components/dropdown#single-selection", "hierarchy": { @@ -2345,7 +3737,7 @@ }, { "content": "Multiple Selection", - "objectID": "e1551a1d-0d1e-49c7-a943-052ff2e02077", + "objectID": "7942f93e-45f6-4c20-9417-22ecac2187d1", "type": "lvl3", "url": "/docs/components/dropdown#multiple-selection", "hierarchy": { @@ -2356,7 +3748,7 @@ }, { "content": "With Shortcut", - "objectID": "03e98952-139c-4213-96c3-d59c294ea2ff", + "objectID": "7aa7d961-b794-49d2-b31c-913ca30f2373", "type": "lvl3", "url": "/docs/components/dropdown#with-shortcut", "hierarchy": { @@ -2367,7 +3759,7 @@ }, { "content": "With Icons", - "objectID": "75fc4d34-988c-417e-99dc-c92e1f123dc6", + "objectID": "731b0b86-21cd-405a-947d-db4418d7bacd", "type": "lvl3", "url": "/docs/components/dropdown#with-icons", "hierarchy": { @@ -2378,7 +3770,7 @@ }, { "content": "With Description", - "objectID": "c4c0c4d9-85c7-4950-9135-bfc13835279b", + "objectID": "8a4c791a-ad10-47ef-883e-72af180724e0", "type": "lvl3", "url": "/docs/components/dropdown#with-description", "hierarchy": { @@ -2389,7 +3781,7 @@ }, { "content": "With Sections", - "objectID": "2046f5e6-f148-4259-b370-46116c20fb32", + "objectID": "c8cd23f9-f8a7-4eca-89e8-a3492ff6243c", "type": "lvl3", "url": "/docs/components/dropdown#with-sections", "hierarchy": { @@ -2400,7 +3792,7 @@ }, { "content": "Custom Trigger", - "objectID": "e335e8c0-eaba-4797-83bc-d84bf7bee49b", + "objectID": "bca79e3b-1f31-4b4f-a9b7-2f578a12fc4c", "type": "lvl3", "url": "/docs/components/dropdown#custom-trigger", "hierarchy": { @@ -2411,7 +3803,7 @@ }, { "content": "Changing the backdrop", - "objectID": "dae9c8fb-8cb2-487a-b25b-86ef07d263a7", + "objectID": "b5d94f90-1757-4f30-93b6-5974543fe6cf", "type": "lvl3", "url": "/docs/components/dropdown#changing-the-backdrop", "hierarchy": { @@ -2422,7 +3814,7 @@ }, { "content": "Routing", - "objectID": "c8fe2e3a-38e3-4f39-b762-92f3b3d349a2", + "objectID": "49522ae7-2c50-4779-9c31-004fd3709b55", "type": "lvl3", "url": "/docs/components/dropdown#routing", "hierarchy": { @@ -2433,21 +3825,21 @@ }, { "content": "Slots", - "objectID": "0f073d24-e6b3-4e43-a3fd-b50cb3e3268f", + "objectID": "9089bac8-9de3-4908-9f26-c0d6d30b13af", "type": "lvl2", "url": "/docs/components/dropdown#slots", "hierarchy": { "lvl1": "Dropdown", "lvl2": "Slots", "lvl3": null } }, { "content": "DropdownMenu", - "objectID": "8e200741-409e-4337-9c6f-adbbc36e3f0a", + "objectID": "eb60c3b0-7ee0-4470-8f13-20900cda3b9e", "type": "lvl3", "url": "/docs/components/dropdown#dropdownmenu", "hierarchy": { "lvl1": "Dropdown", "lvl2": "Slots", "lvl3": "DropdownMenu" } }, { "content": "DropdownItem", - "objectID": "b5dcd585-adfd-4a6c-acc3-b43dde11a82e", + "objectID": "21f72b16-4cef-4c7b-8a69-4031c05ee17c", "type": "lvl3", "url": "/docs/components/dropdown#dropdownitem", "hierarchy": { @@ -2458,7 +3850,7 @@ }, { "content": "DropdownSection", - "objectID": "6add0925-33c9-4fa8-9a1a-be084f023308", + "objectID": "b88e9a82-5586-411a-8d27-3babcad1b78e", "type": "lvl3", "url": "/docs/components/dropdown#dropdownsection", "hierarchy": { @@ -2469,7 +3861,7 @@ }, { "content": "Customizing the dropdown popover", - "objectID": "96baccac-55f4-4020-9c34-4d94e4a5cbef", + "objectID": "416295a6-fe3c-4a29-8d7b-828c777f1c94", "type": "lvl3", "url": "/docs/components/dropdown#customizing-the-dropdown-popover", "hierarchy": { @@ -2480,7 +3872,7 @@ }, { "content": "Customizing the dropdown items style", - "objectID": "0cdff792-b074-42a9-8b08-71233eb782aa", + "objectID": "18695ba8-f012-4d2e-a590-a10f7291fb78", "type": "lvl3", "url": "/docs/components/dropdown#customizing-the-dropdown-items-style", "hierarchy": { @@ -2491,7 +3883,7 @@ }, { "content": "Keyboard Interactions", - "objectID": "e1838720-986c-445b-8a50-93922c49a9ed", + "objectID": "7f524a16-3b2f-4945-80af-eadb8b4c2023", "type": "lvl3", "url": "/docs/components/dropdown#keyboard-interactions", "hierarchy": { @@ -2502,35 +3894,35 @@ }, { "content": "Data Attributes", - "objectID": "b3585514-869d-4990-be52-fb7925265141", + "objectID": "9775ec88-0651-4352-a090-0a00f12a79fe", "type": "lvl2", "url": "/docs/components/dropdown#data-attributes", "hierarchy": { "lvl1": "Dropdown", "lvl2": "Data Attributes", "lvl3": null } }, { "content": "Accessibility", - "objectID": "06eac837-6d42-4411-93a3-9a61a03ac04a", + "objectID": "6a62fdc4-cbb4-48a5-b6d3-4c436e8d25bb", "type": "lvl2", "url": "/docs/components/dropdown#accessibility", "hierarchy": { "lvl1": "Dropdown", "lvl2": "Accessibility", "lvl3": null } }, { "content": "API", - "objectID": "aa5155ea-8c83-4707-b024-3aa9de84a70d", + "objectID": "9bcbf1f9-706b-43b0-b46a-b8d19cd118ae", "type": "lvl2", "url": "/docs/components/dropdown#api", "hierarchy": { "lvl1": "Dropdown", "lvl2": "API", "lvl3": null } }, { "content": "Dropdown Props", - "objectID": "f489e9e8-b110-443e-a2b3-f5ebc733a08e", + "objectID": "8588f87c-e162-4f53-9f5b-3d925b9590dd", "type": "lvl3", "url": "/docs/components/dropdown#dropdown-props", "hierarchy": { "lvl1": "Dropdown", "lvl2": "API", "lvl3": "Dropdown Props" } }, { "content": "Dropdown Events", - "objectID": "207fec4a-0646-4e4f-ac31-77992ee941af", + "objectID": "b1f2e40a-32e8-41f7-8589-565d8241a113", "type": "lvl3", "url": "/docs/components/dropdown#dropdown-events", "hierarchy": { @@ -2541,7 +3933,7 @@ }, { "content": "DropdownTrigger Props", - "objectID": "c9836064-f400-4cbb-8862-3686c0c0540f", + "objectID": "fb1bfea1-d6e0-405f-8013-81593a915f3e", "type": "lvl3", "url": "/docs/components/dropdown#dropdowntrigger-props", "hierarchy": { @@ -2552,7 +3944,7 @@ }, { "content": "DropdownMenu Props", - "objectID": "c97b4f50-6cd0-4369-a14b-510c8a0ff67f", + "objectID": "f57b27c8-1293-4817-a416-2b9fda186fae", "type": "lvl3", "url": "/docs/components/dropdown#dropdownmenu-props", "hierarchy": { @@ -2563,7 +3955,7 @@ }, { "content": "DropdownMenu Events", - "objectID": "0265e653-a4c2-4f83-a025-8bf29fb6347a", + "objectID": "76c24eae-b5be-44d8-a313-475c5e9e5d3e", "type": "lvl3", "url": "/docs/components/dropdown#dropdownmenu-events", "hierarchy": { @@ -2574,7 +3966,7 @@ }, { "content": "DropdownSection Props", - "objectID": "4fa504f3-abf7-41f2-96e0-d1ded5358443", + "objectID": "dd0901d9-c4df-46a8-95ec-aab08f39f181", "type": "lvl3", "url": "/docs/components/dropdown#dropdownsection-props", "hierarchy": { @@ -2585,7 +3977,7 @@ }, { "content": "DropdownItem Props", - "objectID": "b0f95781-9406-4008-8316-93dabe9afac3", + "objectID": "e85157c7-2c46-400b-a3a5-bd7645190949", "type": "lvl3", "url": "/docs/components/dropdown#dropdownitem-props", "hierarchy": { @@ -2596,7 +3988,7 @@ }, { "content": "DropdownItem Events", - "objectID": "c6602918-81bd-4b75-a915-985a2982831e", + "objectID": "f62db7b9-800d-4be2-8861-564fea64e7cf", "type": "lvl3", "url": "/docs/components/dropdown#dropdownitem-events", "hierarchy": { @@ -2607,7 +3999,7 @@ }, { "content": "Types", - "objectID": "c60e7b89-9c87-492c-8685-a628e32be5ae", + "objectID": "d07ada1b-34b9-4d63-997c-38f810e75ed6", "type": "lvl3", "url": "/docs/components/dropdown#types", "hierarchy": { @@ -2618,49 +4010,56 @@ }, { "content": "Dropdown Item Selected Icon Props", - "objectID": "75b65722-9d69-4f50-be45-c15ff2a20d4c", + "objectID": "0fef4b44-82d1-4aa6-ae34-79733bf02c81", "type": "lvl4", "url": "/docs/components/dropdown#dropdown-item-selected-icon-props", "hierarchy": { "lvl1": "Dropdown", "lvl2": "Types", "lvl3": null } }, { "content": "Image", - "objectID": "b4b04fe0-3095-4dc0-b4c7-22c1a544485c", + "objectID": "db393f83-454a-4c0b-8aba-a3656bd3765a", "type": "lvl1", "url": "/docs/components/image", "hierarchy": { "lvl1": "Image" } }, + { + "content": "Installation", + "objectID": "5601668c-75e9-467f-bd83-85c802cd16a1", + "type": "lvl2", + "url": "/docs/components/image#installation", + "hierarchy": { "lvl1": "Image", "lvl2": "Installation", "lvl3": null } + }, { "content": "Import", - "objectID": "9a8c4727-72fa-4f3e-8501-cf694a1ae8ca", + "objectID": "978b014b-bfdf-4004-98d9-a9401457c613", "type": "lvl2", "url": "/docs/components/image#import", "hierarchy": { "lvl1": "Image", "lvl2": "Import", "lvl3": null } }, { "content": "Usage", - "objectID": "2c50d64d-12a2-42bf-a6a6-4048e931df06", + "objectID": "53547032-6c47-456f-87a9-88794308c887", "type": "lvl2", "url": "/docs/components/image#usage", "hierarchy": { "lvl1": "Image", "lvl2": "Usage", "lvl3": null } }, { "content": "Blurred", - "objectID": "11e22687-b004-48f8-b283-71d3a246a3fd", + "objectID": "53d16a73-6e61-4fd5-9026-9d105787e75b", "type": "lvl3", "url": "/docs/components/image#blurred", "hierarchy": { "lvl1": "Image", "lvl2": "Usage", "lvl3": "Blurred" } }, { "content": "Zoomed", - "objectID": "dfb1dbf2-5481-4746-8177-d9a0ccf4af05", + "objectID": "9ab0efc1-3795-4cf8-84da-3b88186d6dab", "type": "lvl3", "url": "/docs/components/image#zoomed", "hierarchy": { "lvl1": "Image", "lvl2": "Blurred", "lvl3": "Zoomed" } }, { "content": "Animated Loading", - "objectID": "c488faa7-32b1-4abd-86ce-885ea552d0f5", + "objectID": "31f61340-74f3-45ee-b2ce-4104e8b5a3f6", "type": "lvl3", "url": "/docs/components/image#animated-loading", "hierarchy": { @@ -2671,7 +4070,7 @@ }, { "content": "Image with fallback", - "objectID": "572f8c92-3abe-4da8-9c2f-f4b6809fb1b8", + "objectID": "f052a010-57dd-4644-b040-7962a2bcd5f5", "type": "lvl3", "url": "/docs/components/image#image-with-fallback", "hierarchy": { @@ -2682,7 +4081,7 @@ }, { "content": "With Next.js Image", - "objectID": "28a08a43-8f7f-462f-942a-7e07b952e066", + "objectID": "83cd7f8a-bcc6-4373-a40b-1949c9f0325d", "type": "lvl3", "url": "/docs/components/image#with-nextjs-image", "hierarchy": { @@ -2693,28 +4092,28 @@ }, { "content": "Slots", - "objectID": "0ce77f89-b5a4-4083-b730-70393c899d44", + "objectID": "a3d50d56-3af2-4f20-9fd6-b96c52a6dfe3", "type": "lvl2", "url": "/docs/components/image#slots", "hierarchy": { "lvl1": "Image", "lvl2": "Slots", "lvl3": null } }, { "content": "API", - "objectID": "05cc492e-c981-48ce-a0cf-d5c94dd2ef45", + "objectID": "81966505-6573-4a86-97ad-c160931f2a0c", "type": "lvl2", "url": "/docs/components/image#api", "hierarchy": { "lvl1": "Image", "lvl2": "API", "lvl3": null } }, { "content": "Image Props", - "objectID": "e1fc7469-665a-4216-b77b-97569a9fff1d", + "objectID": "46ceddc8-3334-4668-b256-8d692d71f28d", "type": "lvl3", "url": "/docs/components/image#image-props", "hierarchy": { "lvl1": "Image", "lvl2": "API", "lvl3": "Image Props" } }, { "content": "Image Events", - "objectID": "1f57851b-23da-41b6-bfc2-0e1b57ae32c7", + "objectID": "70aa1f57-06ab-4f05-9de3-140acff04b2e", "type": "lvl3", "url": "/docs/components/image#image-events", "hierarchy": { @@ -2725,77 +4124,84 @@ }, { "content": "Input", - "objectID": "5dc0e561-cc8f-4ac0-9e72-0d0880b3da3f", + "objectID": "4526ccad-ad0f-4f09-a851-8c7f70dee1ec", "type": "lvl1", "url": "/docs/components/input", "hierarchy": { "lvl1": "Input" } }, + { + "content": "Installation", + "objectID": "157764be-da0e-43f7-8f0c-3cd810e16b56", + "type": "lvl2", + "url": "/docs/components/input#installation", + "hierarchy": { "lvl1": "Input", "lvl2": "Installation", "lvl3": null } + }, { "content": "Import", - "objectID": "81fa64c0-0c3e-41b1-a4b1-e0bce4739262", + "objectID": "72a2390f-e47d-40bd-81c5-f5202f6424ab", "type": "lvl2", "url": "/docs/components/input#import", "hierarchy": { "lvl1": "Input", "lvl2": "Import", "lvl3": null } }, { "content": "Usage", - "objectID": "6b58e6fc-5cb0-4944-876f-477773d4c4ed", + "objectID": "b61e597a-e243-4374-8ff2-35cef0e64832", "type": "lvl2", "url": "/docs/components/input#usage", "hierarchy": { "lvl1": "Input", "lvl2": "Usage", "lvl3": null } }, { "content": "Disabled", - "objectID": "b8926935-e41f-4897-907b-5f836d49254f", + "objectID": "ae969dc2-775b-4de0-b778-abd5b34a1fcb", "type": "lvl3", "url": "/docs/components/input#disabled", "hierarchy": { "lvl1": "Input", "lvl2": "Usage", "lvl3": "Disabled" } }, { "content": "Read Only", - "objectID": "3bbbb7ef-a744-4591-aee9-a06a30e70a3d", + "objectID": "e7451a99-b5c5-4cd2-8006-cbfd8e5258db", "type": "lvl3", "url": "/docs/components/input#read-only", "hierarchy": { "lvl1": "Input", "lvl2": "Disabled", "lvl3": "Read Only" } }, { "content": "Required", - "objectID": "6d8ce5cf-7223-4a47-bd3b-9149f48b216d", + "objectID": "82ea373d-4956-4001-9b34-5048bef031f5", "type": "lvl3", "url": "/docs/components/input#required", "hierarchy": { "lvl1": "Input", "lvl2": "Read Only", "lvl3": "Required" } }, { "content": "Sizes", - "objectID": "ba24a394-cc51-42e7-b198-b562a5e888db", + "objectID": "08e71517-fd42-4e44-ba04-79d6f7d7cd59", "type": "lvl3", "url": "/docs/components/input#sizes", "hierarchy": { "lvl1": "Input", "lvl2": "Required", "lvl3": "Sizes" } }, { "content": "Colors", - "objectID": "c1ec64e0-136e-4616-847f-3600e482eca3", + "objectID": "f8b41d9a-48c8-4504-8ab1-3200461379d4", "type": "lvl3", "url": "/docs/components/input#colors", "hierarchy": { "lvl1": "Input", "lvl2": "Sizes", "lvl3": "Colors" } }, { "content": "Variants", - "objectID": "69581663-db62-4023-b886-274c5c09f281", + "objectID": "457a78aa-7bd5-4d5d-be61-f90066daa497", "type": "lvl3", "url": "/docs/components/input#variants", "hierarchy": { "lvl1": "Input", "lvl2": "Colors", "lvl3": "Variants" } }, { "content": "Radius", - "objectID": "90b5516b-43ff-4ba1-8899-970e0175a95f", + "objectID": "4010c6b9-0c94-4bf9-b386-22b057984ba8", "type": "lvl3", "url": "/docs/components/input#radius", "hierarchy": { "lvl1": "Input", "lvl2": "Variants", "lvl3": "Radius" } }, { "content": "Label Placements", - "objectID": "46464fbc-db22-470d-b753-adc1ebcc3e0f", + "objectID": "6a23951d-abc3-4d52-9a52-d7d4e2384d51", "type": "lvl3", "url": "/docs/components/input#label-placements", "hierarchy": { @@ -2806,7 +4212,7 @@ }, { "content": "Password Input", - "objectID": "97b3d81d-4f7b-485a-840c-b7338e040586", + "objectID": "211792be-737d-41f9-bb60-aad97ea913dd", "type": "lvl3", "url": "/docs/components/input#password-input", "hierarchy": { @@ -2817,7 +4223,7 @@ }, { "content": "Clear Button", - "objectID": "548e32d5-47f6-4aa7-bb0e-3cb268901aca", + "objectID": "24e13461-080d-4bf1-bfd8-e12234f4a91d", "type": "lvl3", "url": "/docs/components/input#clear-button", "hierarchy": { @@ -2828,7 +4234,7 @@ }, { "content": "Start & End Content", - "objectID": "5a854584-2610-440c-862f-44df38caf2ac", + "objectID": "c5ec0dac-d44b-4860-99d1-7802c3706a61", "type": "lvl3", "url": "/docs/components/input#start--end-content", "hierarchy": { @@ -2839,7 +4245,7 @@ }, { "content": "With Description", - "objectID": "11c4dcf1-f55a-45b2-9e72-6023b0715346", + "objectID": "6c72bae1-9289-495a-9012-bbf1ecf5fbad", "type": "lvl3", "url": "/docs/components/input#with-description", "hierarchy": { @@ -2850,7 +4256,7 @@ }, { "content": "With Error Message", - "objectID": "3692a73d-5e39-4433-a848-cf392866c923", + "objectID": "6b167ef4-7bce-45fd-87e3-f957cf810cf9", "type": "lvl3", "url": "/docs/components/input#with-error-message", "hierarchy": { @@ -2861,7 +4267,7 @@ }, { "content": "Controlled", - "objectID": "0837d445-7122-4c61-a264-0a35fcdbdcd0", + "objectID": "5a2fa4eb-84fb-40e8-b6bd-e2484a8aa427", "type": "lvl3", "url": "/docs/components/input#controlled", "hierarchy": { @@ -2872,21 +4278,21 @@ }, { "content": "Slots", - "objectID": "e0a967c1-7c1b-4ee4-a004-761b77214a7e", + "objectID": "a3b74c28-79e0-4c9e-a3fe-adf37c1c53a4", "type": "lvl2", "url": "/docs/components/input#slots", "hierarchy": { "lvl1": "Input", "lvl2": "Slots", "lvl3": null } }, { "content": "Custom Styles", - "objectID": "416f25dc-2202-4a92-83cc-0d1de7418654", + "objectID": "cf5be42c-c0f3-4641-be33-ca50a6dcbe45", "type": "lvl3", "url": "/docs/components/input#custom-styles", "hierarchy": { "lvl1": "Input", "lvl2": "Slots", "lvl3": "Custom Styles" } }, { "content": "Custom Implementation", - "objectID": "45297b77-df79-4643-90bb-2c07ead3a330", + "objectID": "b10f0a92-1c7c-45f2-91d5-9161d2555462", "type": "lvl3", "url": "/docs/components/input#custom-implementation", "hierarchy": { @@ -2897,35 +4303,35 @@ }, { "content": "Data Attributes", - "objectID": "a515a8b6-64fe-4626-af60-a4a9d0c21091", + "objectID": "3e87c41f-570a-4917-9895-320c2fa7a9ea", "type": "lvl2", "url": "/docs/components/input#data-attributes", "hierarchy": { "lvl1": "Input", "lvl2": "Data Attributes", "lvl3": null } }, { "content": "Accessibility", - "objectID": "e005e9da-8e06-476f-a5e3-9087ad38dd32", + "objectID": "c9650296-b7ce-4fcf-8c31-6c71e892af48", "type": "lvl2", "url": "/docs/components/input#accessibility", "hierarchy": { "lvl1": "Input", "lvl2": "Accessibility", "lvl3": null } }, { "content": "API", - "objectID": "480e6129-9786-4531-a6f6-d08084a53345", + "objectID": "9807dbcc-45cd-4e9d-8149-c4a37d5bd14a", "type": "lvl2", "url": "/docs/components/input#api", "hierarchy": { "lvl1": "Input", "lvl2": "API", "lvl3": null } }, { "content": "Input Props", - "objectID": "b7485713-ca9f-4bf8-9aa8-2618f542dba3", + "objectID": "3044a951-a67e-4980-bbed-8e2ed15cefc9", "type": "lvl3", "url": "/docs/components/input#input-props", "hierarchy": { "lvl1": "Input", "lvl2": "API", "lvl3": "Input Props" } }, { "content": "Input Events", - "objectID": "85086db6-6b66-4e86-8892-fbc7478e5815", + "objectID": "3bc30494-d099-4297-ac17-7f7a93cf8956", "type": "lvl3", "url": "/docs/components/input#input-events", "hierarchy": { @@ -2936,42 +4342,53 @@ }, { "content": "Keyboard Key", - "objectID": "8a22e579-fb2c-4265-96aa-f1bf4dd4cd76", + "objectID": "06699f1a-3c91-4222-b548-9bd7865bfa50", "type": "lvl1", "url": "/docs/components/kbd", "hierarchy": { "lvl1": "Keyboard Key" } }, + { + "content": "Installation", + "objectID": "fd672ca4-a74e-409c-ad9c-28d50f89fe15", + "type": "lvl2", + "url": "/docs/components/kbd#installation", + "hierarchy": { + "lvl1": "Keyboard Key", + "lvl2": "Installation", + "lvl3": null + } + }, { "content": "Import", - "objectID": "f0e586ac-dbaf-4d36-9eaf-3d833beb28f2", + "objectID": "80141571-6899-4080-bceb-5ac70c974633", "type": "lvl2", "url": "/docs/components/kbd#import", "hierarchy": { "lvl1": "Keyboard Key", "lvl2": "Import", "lvl3": null } }, { "content": "Usage", - "objectID": "b98fe342-f8ab-434b-a397-10a5183d9d40", + "objectID": "41b1ebf5-1b79-480f-bd1a-3d7be072e8a4", "type": "lvl2", "url": "/docs/components/kbd#usage", "hierarchy": { "lvl1": "Keyboard Key", "lvl2": "Usage", "lvl3": null } }, { "content": "Keys", - "objectID": "e53ccb46-d0ea-42bf-92f2-5727551d4f79", + "objectID": "6f4e8340-11ca-4226-a577-6655a1c6c550", "type": "lvl3", "url": "/docs/components/kbd#keys", "hierarchy": { "lvl1": "Keyboard Key", "lvl2": "Usage", "lvl3": "Keys" } }, { "content": "Slots", - "objectID": "c9205e4b-a69a-4489-8899-622951f97dc7", + "objectID": "395affd6-085b-4a41-8df2-a5d082f46f34", "type": "lvl2", "url": "/docs/components/kbd#slots", "hierarchy": { "lvl1": "Keyboard Key", "lvl2": "Slots", "lvl3": null } }, { "content": "Accessibility", - "objectID": "822adf85-b0b7-461a-b51d-57884aa352c7", + "objectID": "32f77aa1-2986-486e-b73c-8a95eff7b9d4", "type": "lvl2", "url": "/docs/components/kbd#accessibility", "hierarchy": { @@ -2982,14 +4399,14 @@ }, { "content": "API", - "objectID": "8a00c1e0-9ec5-4a48-8cd7-dc840b678d86", + "objectID": "c3c3a4b3-d630-4cf2-b8cd-78a2689d8ce2", "type": "lvl2", "url": "/docs/components/kbd#api", "hierarchy": { "lvl1": "Keyboard Key", "lvl2": "API", "lvl3": null } }, { "content": "Keyboard Key Props", - "objectID": "6da3bddf-6f13-4ec3-8592-994849a34bd1", + "objectID": "3445b1fd-157f-494a-9829-f006b2099be5", "type": "lvl3", "url": "/docs/components/kbd#keyboard-key-props", "hierarchy": { @@ -3000,7 +4417,7 @@ }, { "content": "Keyboard Keys", - "objectID": "23f3b3c0-2b93-4d92-a95b-c5de92e29c57", + "objectID": "9c17f2b4-768f-4bea-855f-86705c5f61e0", "type": "lvl3", "url": "/docs/components/kbd#keyboard-keys", "hierarchy": { @@ -3011,63 +4428,70 @@ }, { "content": "Link", - "objectID": "8b3b1bce-a9ab-4968-bde5-1789495db63d", + "objectID": "a6449b2c-b955-499b-8d57-b33c18930359", "type": "lvl1", "url": "/docs/components/link", "hierarchy": { "lvl1": "Link" } }, + { + "content": "Installation", + "objectID": "b6b397c9-1740-42a7-8378-991efff4b440", + "type": "lvl2", + "url": "/docs/components/link#installation", + "hierarchy": { "lvl1": "Link", "lvl2": "Installation", "lvl3": null } + }, { "content": "Import", - "objectID": "605f88b2-5972-4942-8b4b-edb3b59b109b", + "objectID": "19f28e7f-f4ce-458a-b57c-e2d37ed24c6c", "type": "lvl2", "url": "/docs/components/link#import", "hierarchy": { "lvl1": "Link", "lvl2": "Import", "lvl3": null } }, { "content": "Usage", - "objectID": "d476852d-e73a-4f23-a4f8-0df0573d4234", + "objectID": "1814a50c-1cd1-464c-a058-ef65c1e3584f", "type": "lvl2", "url": "/docs/components/link#usage", "hierarchy": { "lvl1": "Link", "lvl2": "Usage", "lvl3": null } }, { "content": "Disabled", - "objectID": "cf28db1b-1fee-4d69-8c73-1df269472452", + "objectID": "b8dd67ad-6e01-4087-b68c-b55c94264a34", "type": "lvl3", "url": "/docs/components/link#disabled", "hierarchy": { "lvl1": "Link", "lvl2": "Usage", "lvl3": "Disabled" } }, { "content": "Sizes", - "objectID": "8ac762cf-add8-41c6-ad03-b6949a2b0916", + "objectID": "544bc1a1-b9ab-46e8-b616-cf65b95b5f76", "type": "lvl3", "url": "/docs/components/link#sizes", "hierarchy": { "lvl1": "Link", "lvl2": "Disabled", "lvl3": "Sizes" } }, { "content": "Colors", - "objectID": "9e5b445a-5dac-4225-8ce6-3e29bed3fe02", + "objectID": "3208030f-88b0-4f09-85a1-1d6c092995a2", "type": "lvl3", "url": "/docs/components/link#colors", "hierarchy": { "lvl1": "Link", "lvl2": "Sizes", "lvl3": "Colors" } }, { "content": "Underline", - "objectID": "815643a9-b8dd-408d-b06d-bbe54c47c488", + "objectID": "1e76d87f-4143-4b0c-9eef-7045ae718364", "type": "lvl3", "url": "/docs/components/link#underline", "hierarchy": { "lvl1": "Link", "lvl2": "Colors", "lvl3": "Underline" } }, { "content": "External", - "objectID": "c227b725-0ef2-43d4-925c-3849418219b4", + "objectID": "cd32f4bd-fcdf-492a-9fb0-c288c2be6cd7", "type": "lvl3", "url": "/docs/components/link#external", "hierarchy": { "lvl1": "Link", "lvl2": "Underline", "lvl3": "External" } }, { "content": "Custom Anchor Icon", - "objectID": "736a367c-d3af-4e7e-a745-f7ecb36fd040", + "objectID": "4d969bea-6e7d-4c0a-b45a-ec4e33f3f862", "type": "lvl3", "url": "/docs/components/link#custom-anchor-icon", "hierarchy": { @@ -3078,7 +4502,7 @@ }, { "content": "Block Link", - "objectID": "aece4793-97f8-48ca-9821-5e04d6715fa6", + "objectID": "622eae9a-be3e-45e7-990a-ba5226721981", "type": "lvl3", "url": "/docs/components/link#block-link", "hierarchy": { @@ -3089,7 +4513,7 @@ }, { "content": "Polymorphic Component", - "objectID": "3885d5af-862d-4619-8637-4e25eacbb920", + "objectID": "db7b4c4c-be7f-4d5e-b018-2f9b98255bdc", "type": "lvl3", "url": "/docs/components/link#polymorphic-component", "hierarchy": { @@ -3100,7 +4524,7 @@ }, { "content": "Routing", - "objectID": "d7e5dbdf-06f9-400b-b7d0-b0b7a6f28de8", + "objectID": "9aa63c7a-ed70-4b81-bd5e-0258345bb02a", "type": "lvl3", "url": "/docs/components/link#routing", "hierarchy": { @@ -3111,7 +4535,7 @@ }, { "content": "Custom Implementation", - "objectID": "199b65ab-3b9c-4de0-9471-d807551f8898", + "objectID": "862ecd5c-d761-49af-9603-fb2d975c1d1e", "type": "lvl3", "url": "/docs/components/link#custom-implementation", "hierarchy": { @@ -3122,70 +4546,77 @@ }, { "content": "Data Attributes", - "objectID": "2abfd8ab-57cc-4776-ac9b-b6e4de2b4e82", + "objectID": "a0518983-e02b-41bb-a197-a0dd890de0d6", "type": "lvl2", "url": "/docs/components/link#data-attributes", "hierarchy": { "lvl1": "Link", "lvl2": "Data Attributes", "lvl3": null } }, { "content": "Accessibility", - "objectID": "a0703d2c-6b66-4cdb-9fd5-e4e56d3138d7", + "objectID": "172db110-8aeb-4225-80cd-dabb518e506c", "type": "lvl2", "url": "/docs/components/link#accessibility", "hierarchy": { "lvl1": "Link", "lvl2": "Accessibility", "lvl3": null } }, { "content": "API", - "objectID": "2480cc94-09ff-47f9-8ffa-0c0e1ee69f84", + "objectID": "5b732df2-0785-4bea-b5ad-0c895995a0c2", "type": "lvl2", "url": "/docs/components/link#api", "hierarchy": { "lvl1": "Link", "lvl2": "API", "lvl3": null } }, { "content": "Link Props", - "objectID": "5b231ae0-c99a-4418-b5c4-4988b67ff482", + "objectID": "7582f3f6-53b6-41b2-bf2e-cee12ffe60ee", "type": "lvl3", "url": "/docs/components/link#link-props", "hierarchy": { "lvl1": "Link", "lvl2": "API", "lvl3": "Link Props" } }, { "content": "Link Events", - "objectID": "68715c2c-aab4-4afc-ad05-3812338bb79f", + "objectID": "0354ab38-beed-4e2e-a8c6-85c296a4e781", "type": "lvl3", "url": "/docs/components/link#link-events", "hierarchy": { "lvl1": "Link", "lvl2": "Link Props", "lvl3": "Link Events" } }, { "content": "Listbox", - "objectID": "42d65689-852f-4528-932e-458b66830636", + "objectID": "f0ae33e5-1d56-4210-87cc-054a06d284b9", "type": "lvl1", "url": "/docs/components/listbox", "hierarchy": { "lvl1": "Listbox" } }, + { + "content": "Installation", + "objectID": "0852c4b5-52ee-4211-bc11-426bcf177901", + "type": "lvl2", + "url": "/docs/components/listbox#installation", + "hierarchy": { "lvl1": "Listbox", "lvl2": "Installation", "lvl3": null } + }, { "content": "Import", - "objectID": "934a7707-ca38-4696-be82-fd5d6dd4552f", + "objectID": "f2888326-5609-4412-b49e-404c702b53b0", "type": "lvl2", "url": "/docs/components/listbox#import", "hierarchy": { "lvl1": "Listbox", "lvl2": "Import", "lvl3": null } }, { "content": "Usage", - "objectID": "df0a1e97-5a72-4d28-bdde-c5572d0b2d7b", + "objectID": "8ad9a049-badd-421c-95a3-05215fcbe1ff", "type": "lvl2", "url": "/docs/components/listbox#usage", "hierarchy": { "lvl1": "Listbox", "lvl2": "Usage", "lvl3": null } }, { "content": "Dynamic items", - "objectID": "2ec85a98-8d7a-4134-82b9-dda6bcce285a", + "objectID": "f8c9672c-05ff-4eca-bd1c-4ea6554bdf37", "type": "lvl3", "url": "/docs/components/listbox#dynamic-items", "hierarchy": { "lvl1": "Listbox", "lvl2": "Usage", "lvl3": "Dynamic items" } }, { "content": "Disabled Keys", - "objectID": "9677cb03-e8d5-40e7-8a20-99872783b7c7", + "objectID": "669e9531-92b7-47d1-8f70-f40f053cb8ab", "type": "lvl3", "url": "/docs/components/listbox#disabled-keys", "hierarchy": { @@ -3196,7 +4627,7 @@ }, { "content": "Variants", - "objectID": "a96a1d59-2188-489c-a1cc-902804f8bd02", + "objectID": "e6c43360-ecac-4be8-8954-3338abe5fd58", "type": "lvl3", "url": "/docs/components/listbox#variants", "hierarchy": { @@ -3207,7 +4638,7 @@ }, { "content": "Single Selection", - "objectID": "97d7c7bb-1f57-4dce-a6e7-96678df25e47", + "objectID": "4cb1dc68-b961-4c68-8d5c-0bb0ad1edc10", "type": "lvl3", "url": "/docs/components/listbox#single-selection", "hierarchy": { @@ -3218,7 +4649,7 @@ }, { "content": "Multiple Selection", - "objectID": "2b36268c-0ded-442d-afc6-f5d8dc4e7554", + "objectID": "3246a240-6a26-40f6-842e-f7f3a872eb55", "type": "lvl3", "url": "/docs/components/listbox#multiple-selection", "hierarchy": { @@ -3229,7 +4660,7 @@ }, { "content": "With Icons", - "objectID": "c2140427-3c7f-48eb-a9f3-33498e9b3aa4", + "objectID": "81dc55ba-d926-4196-8cc8-334c9d0f1a2b", "type": "lvl3", "url": "/docs/components/listbox#with-icons", "hierarchy": { @@ -3240,7 +4671,7 @@ }, { "content": "With Description", - "objectID": "db7a394b-f1c9-46e2-8bd1-5fa7baeb4688", + "objectID": "ae4f4815-2b4f-467c-bd66-93bcb03fdd47", "type": "lvl3", "url": "/docs/components/listbox#with-description", "hierarchy": { @@ -3251,7 +4682,7 @@ }, { "content": "With Top & Bottom Content", - "objectID": "8bc849e0-b842-4538-8f5b-58cfa755b7bb", + "objectID": "04d2b17b-065b-4970-8fbd-0cf4f2507258", "type": "lvl3", "url": "/docs/components/listbox#with-top--bottom-content", "hierarchy": { @@ -3262,7 +4693,7 @@ }, { "content": "With Sections", - "objectID": "0c8ff457-f523-4d34-ae23-17ae96a0f51e", + "objectID": "f30c9abf-162b-4326-b34c-7638fa66223a", "type": "lvl3", "url": "/docs/components/listbox#with-sections", "hierarchy": { @@ -3273,7 +4704,7 @@ }, { "content": "Routing", - "objectID": "57a83b49-e125-4d0f-b713-ac8668d8bd40", + "objectID": "cdae32ae-45c4-4df9-8f12-369b117e6075", "type": "lvl3", "url": "/docs/components/listbox#routing", "hierarchy": { @@ -3284,21 +4715,21 @@ }, { "content": "Slots", - "objectID": "27a1d3bb-e94f-4cf6-9b98-e1a5dab73ab0", + "objectID": "e7c1bcec-f94f-40d4-a72e-f1ac51913c0a", "type": "lvl2", "url": "/docs/components/listbox#slots", "hierarchy": { "lvl1": "Listbox", "lvl2": "Slots", "lvl3": null } }, { "content": "ListboxItem", - "objectID": "ea89eb98-49f7-4d6c-acb3-4c382de0dc6a", + "objectID": "ce4b851f-2030-4893-8b14-a37f761002ae", "type": "lvl3", "url": "/docs/components/listbox#listboxitem", "hierarchy": { "lvl1": "Listbox", "lvl2": "Listbox", "lvl3": "ListboxItem" } }, { "content": "ListboxSection", - "objectID": "3c394a3e-12d7-445f-bffd-cc3d45c23acb", + "objectID": "a98ec201-bda4-43f2-86f6-c768d7623977", "type": "lvl3", "url": "/docs/components/listbox#listboxsection", "hierarchy": { @@ -3309,7 +4740,7 @@ }, { "content": "Customizing the listbox", - "objectID": "8e7bc847-1776-4b55-9ebe-e347b9e19be0", + "objectID": "9862bdec-535f-47e2-9d27-912571b710ec", "type": "lvl3", "url": "/docs/components/listbox#customizing-the-listbox", "hierarchy": { @@ -3320,7 +4751,7 @@ }, { "content": "Keyboard Interactions", - "objectID": "0e0998b9-5c5c-4ff4-8cd5-6603f2bd67e8", + "objectID": "25dffbca-7526-4c4d-b495-2f9794f53bf0", "type": "lvl3", "url": "/docs/components/listbox#keyboard-interactions", "hierarchy": { @@ -3331,35 +4762,35 @@ }, { "content": "Data Attributes", - "objectID": "3abf0f37-a812-4a8f-bfd0-22a620c1eb1f", + "objectID": "8712fb40-8400-47c8-86ff-98df06bb4d07", "type": "lvl2", "url": "/docs/components/listbox#data-attributes", "hierarchy": { "lvl1": "Listbox", "lvl2": "Data Attributes", "lvl3": null } }, { "content": "Accessibility", - "objectID": "3c979649-697f-4002-8150-560bdf3b73cf", + "objectID": "0ace1672-c695-43d6-8135-7e01a21e8b27", "type": "lvl2", "url": "/docs/components/listbox#accessibility", "hierarchy": { "lvl1": "Listbox", "lvl2": "Accessibility", "lvl3": null } }, { "content": "API", - "objectID": "2e8bdc64-f03c-4966-ad5b-0306482ace6d", + "objectID": "4b9c29b2-02b0-417a-8048-ae3674d59775", "type": "lvl2", "url": "/docs/components/listbox#api", "hierarchy": { "lvl1": "Listbox", "lvl2": "API", "lvl3": null } }, { "content": "Listbox Props", - "objectID": "d8ec6e16-e5eb-4342-998d-4d8e3c15b425", + "objectID": "683a9286-3ee8-4b32-9656-cf710d57d4d8", "type": "lvl3", "url": "/docs/components/listbox#listbox-props", "hierarchy": { "lvl1": "Listbox", "lvl2": "API", "lvl3": "Listbox Props" } }, { "content": "Listbox Events", - "objectID": "8846c80f-135c-4bd1-b53e-aac5da6eb1bd", + "objectID": "8947068f-131e-4ff5-83f3-68ecf3e38ac5", "type": "lvl3", "url": "/docs/components/listbox#listbox-events", "hierarchy": { @@ -3370,7 +4801,7 @@ }, { "content": "ListboxSection Props", - "objectID": "d571e35b-ec4a-4917-8ce9-bb10898e4d92", + "objectID": "ad973a6a-d0aa-4536-af06-8daa36aae4a2", "type": "lvl3", "url": "/docs/components/listbox#listboxsection-props", "hierarchy": { @@ -3381,7 +4812,7 @@ }, { "content": "ListboxItem Props", - "objectID": "a14b4809-5bef-4332-819d-edb6927333b1", + "objectID": "9f8a54c6-eab7-4fb3-82d0-319b4ba3c741", "type": "lvl3", "url": "/docs/components/listbox#listboxitem-props", "hierarchy": { @@ -3392,7 +4823,7 @@ }, { "content": "ListboxItem Events", - "objectID": "7e7c6a83-ad4a-4cb4-b84a-555e2affc4e4", + "objectID": "e74bfc02-0290-4fb7-95e4-a79bf8c53ca2", "type": "lvl3", "url": "/docs/components/listbox#listboxitem-events", "hierarchy": { @@ -3403,7 +4834,7 @@ }, { "content": "Types", - "objectID": "dfbb952e-1d2b-4fc9-b6c2-55ca207f6ec8", + "objectID": "bba2468e-92f6-4cc0-aa67-a4176734377f", "type": "lvl3", "url": "/docs/components/listbox#types", "hierarchy": { @@ -3414,42 +4845,49 @@ }, { "content": "Listbox Item Selected Icon Props", - "objectID": "b7380fc1-fe37-4c47-b317-9a0e320365a0", + "objectID": "c28fa923-edbd-420a-a8ce-cbd401cc35de", "type": "lvl4", "url": "/docs/components/listbox#listbox-item-selected-icon-props", "hierarchy": { "lvl1": "Listbox", "lvl2": "Types", "lvl3": null } }, { "content": "Modal", - "objectID": "5386a712-ec66-4004-9262-450181310525", + "objectID": "b391f01c-2381-4046-a78c-3f9d7a69ed2f", "type": "lvl1", "url": "/docs/components/modal", "hierarchy": { "lvl1": "Modal" } }, + { + "content": "Installation", + "objectID": "e957562f-de5b-4f7e-b5da-273cedc22027", + "type": "lvl2", + "url": "/docs/components/modal#installation", + "hierarchy": { "lvl1": "Modal", "lvl2": "Installation", "lvl3": null } + }, { "content": "Import", - "objectID": "70edef9c-c979-4062-8591-af77d09eb047", + "objectID": "c8ad78f7-83bd-44b4-87d9-f1cf0c3429b6", "type": "lvl2", "url": "/docs/components/modal#import", "hierarchy": { "lvl1": "Modal", "lvl2": "Import", "lvl3": null } }, { "content": "Usage", - "objectID": "6a685425-fee3-454c-9738-5f808d6175b1", + "objectID": "7fab825f-61bf-4523-9968-3c945fa60270", "type": "lvl2", "url": "/docs/components/modal#usage", "hierarchy": { "lvl1": "Modal", "lvl2": "Usage", "lvl3": null } }, { "content": "Sizes", - "objectID": "d03de017-ba2e-4f95-aa09-5fca26f6d7d1", + "objectID": "2e10db5d-eb66-44fd-b758-e932f3d41848", "type": "lvl3", "url": "/docs/components/modal#sizes", "hierarchy": { "lvl1": "Modal", "lvl2": "Usage", "lvl3": "Sizes" } }, { "content": "Non-dissmissable", - "objectID": "39e650e8-90cd-4948-ba26-81d31a2c4aaa", + "objectID": "34fea277-5750-49ec-b681-06e1830e933e", "type": "lvl3", "url": "/docs/components/modal#non-dissmissable", "hierarchy": { @@ -3460,7 +4898,7 @@ }, { "content": "Modal placement", - "objectID": "4b6831ed-57fe-4969-beb8-ca0a88b0d2f5", + "objectID": "044c55fd-3509-4014-8ba4-2e3ed51c6a6b", "type": "lvl3", "url": "/docs/components/modal#modal-placement", "hierarchy": { @@ -3471,7 +4909,7 @@ }, { "content": "Overflow scroll", - "objectID": "d1071225-24ea-462e-8d54-6cf848157c2e", + "objectID": "784780be-b36d-4b00-8501-a4b9b6a9b7b1", "type": "lvl3", "url": "/docs/components/modal#overflow-scroll", "hierarchy": { @@ -3482,7 +4920,7 @@ }, { "content": "With Form", - "objectID": "5d9528e6-a27e-43bf-a636-0e51cc7de05a", + "objectID": "4ef4977d-f95f-42ba-993d-553d5e5cdf9b", "type": "lvl3", "url": "/docs/components/modal#with-form", "hierarchy": { @@ -3493,14 +4931,14 @@ }, { "content": "Backdrop", - "objectID": "7ee74d53-16d6-485f-8a2f-5dc24d9a4898", + "objectID": "64b4c2a1-e905-4b14-95b8-9723a0634fbf", "type": "lvl3", "url": "/docs/components/modal#backdrop", "hierarchy": { "lvl1": "Modal", "lvl2": "With Form", "lvl3": "Backdrop" } }, { "content": "Custom Backdrop", - "objectID": "7b9b9b32-eea9-4bd7-a371-985037caa4b3", + "objectID": "b8c8ebef-7207-4a27-910e-9b16a6938f10", "type": "lvl3", "url": "/docs/components/modal#custom-backdrop", "hierarchy": { @@ -3511,7 +4949,7 @@ }, { "content": "Custom Motion", - "objectID": "038443bf-0213-4391-82fd-6a4b11faa685", + "objectID": "53bdd81a-3737-4dfc-a392-d85c277f1677", "type": "lvl3", "url": "/docs/components/modal#custom-motion", "hierarchy": { @@ -3522,49 +4960,49 @@ }, { "content": "Slots", - "objectID": "47d95970-6e11-42b2-95f9-d8c53a0f0c07", + "objectID": "42322dcf-4fe4-4c8b-b5e5-0890e265a78f", "type": "lvl2", "url": "/docs/components/modal#slots", "hierarchy": { "lvl1": "Modal", "lvl2": "Slots", "lvl3": null } }, { "content": "Custom Styles", - "objectID": "02a3c0ee-9887-4247-adac-97fed0eaf000", + "objectID": "86cc4b17-87ce-4882-ab0e-1d21a6aad12f", "type": "lvl3", "url": "/docs/components/modal#custom-styles", "hierarchy": { "lvl1": "Modal", "lvl2": "Slots", "lvl3": "Custom Styles" } }, { "content": "Data Attributes", - "objectID": "c4b6644c-dfc9-40e2-87f5-ed6863275bec", + "objectID": "335d7a33-f029-4a30-8035-73e1aa99e33d", "type": "lvl2", "url": "/docs/components/modal#data-attributes", "hierarchy": { "lvl1": "Modal", "lvl2": "Data Attributes", "lvl3": null } }, { "content": "Accessibility", - "objectID": "bc503cb4-4020-4c77-9e19-269a88d7583d", + "objectID": "a6962672-55de-478a-b357-d4c967a7cdbe", "type": "lvl2", "url": "/docs/components/modal#accessibility", "hierarchy": { "lvl1": "Modal", "lvl2": "Accessibility", "lvl3": null } }, { "content": "API", - "objectID": "8d9b9d74-9487-419b-bf29-41fe0610ddd2", + "objectID": "4bc96210-699d-429d-8f2b-8d3f02f937c9", "type": "lvl2", "url": "/docs/components/modal#api", "hierarchy": { "lvl1": "Modal", "lvl2": "API", "lvl3": null } }, { "content": "Modal Props", - "objectID": "9836bb1e-5093-4c2c-a490-b77833659e68", + "objectID": "bbc1337b-17e6-49ec-be1c-dd5360b40400", "type": "lvl3", "url": "/docs/components/modal#modal-props", "hierarchy": { "lvl1": "Modal", "lvl2": "API", "lvl3": "Modal Props" } }, { "content": "Modal Events", - "objectID": "89189d24-1317-446c-8bc9-fc1595a4f8c9", + "objectID": "68066ba6-85ad-47fd-8c75-77b7cbe98b2d", "type": "lvl3", "url": "/docs/components/modal#modal-events", "hierarchy": { @@ -3575,7 +5013,7 @@ }, { "content": "Modal types", - "objectID": "8979a97a-3c69-4fb1-a805-a1400bb8205d", + "objectID": "5fb75f85-f375-46c7-a345-c1388b4a2a1a", "type": "lvl3", "url": "/docs/components/modal#modal-types", "hierarchy": { @@ -3586,42 +5024,49 @@ }, { "content": "Motion Props", - "objectID": "9d3f1e89-7d66-4a20-9468-a56a58917683", + "objectID": "a7b424dc-2164-4717-812f-a45956929fad", "type": "lvl4", "url": "/docs/components/modal#motion-props", "hierarchy": { "lvl1": "Modal", "lvl2": "Modal types", "lvl3": null } }, { "content": "Navbar", - "objectID": "c77f99b1-54d3-4dc4-a675-8f6d2b38025b", + "objectID": "185aad11-c7a9-4f81-ae2e-d196da99ebee", "type": "lvl1", "url": "/docs/components/navbar", "hierarchy": { "lvl1": "Navbar" } }, + { + "content": "Installation", + "objectID": "e1cd622f-d928-49bc-8b60-c09e22994b99", + "type": "lvl2", + "url": "/docs/components/navbar#installation", + "hierarchy": { "lvl1": "Navbar", "lvl2": "Installation", "lvl3": null } + }, { "content": "Import", - "objectID": "09d29dcb-e462-4e30-bc38-4003c7993b2e", + "objectID": "1c8aa9ea-04ad-4c38-9b36-ddfc48ae5781", "type": "lvl2", "url": "/docs/components/navbar#import", "hierarchy": { "lvl1": "Navbar", "lvl2": "Import", "lvl3": null } }, { "content": "Usage", - "objectID": "188190de-1d8f-4aba-881d-2753d5622e0a", + "objectID": "412b7778-0211-4203-ade5-f6cfe5117c94", "type": "lvl2", "url": "/docs/components/navbar#usage", "hierarchy": { "lvl1": "Navbar", "lvl2": "Usage", "lvl3": null } }, { "content": "Static", - "objectID": "c030c33c-c30c-40ae-87c0-7496a955bf0a", + "objectID": "bb0107e9-8094-4f31-b3a7-13f7ecacf57a", "type": "lvl3", "url": "/docs/components/navbar#static", "hierarchy": { "lvl1": "Navbar", "lvl2": "Usage", "lvl3": "Static" } }, { "content": "Hide on scroll", - "objectID": "c7684596-b0d4-4cca-87d2-9b6b65153fb2", + "objectID": "ae8dbc09-2a2f-47bc-a2bb-6e7c8b7e2aac", "type": "lvl3", "url": "/docs/components/navbar#hide-on-scroll", "hierarchy": { @@ -3632,7 +5077,7 @@ }, { "content": "With Menu", - "objectID": "9397aef5-3e04-4b2f-ad49-50fc9a74e1b8", + "objectID": "07a7ab11-a084-4318-ae12-29aefa3e2492", "type": "lvl3", "url": "/docs/components/navbar#with-menu", "hierarchy": { @@ -3643,7 +5088,7 @@ }, { "content": "Controlled Menu", - "objectID": "c2dcd539-4cb0-491a-94bf-eff4dd6fb5cc", + "objectID": "d974a3a0-dadb-4c7e-ad7c-7c3d0f3c085a", "type": "lvl3", "url": "/docs/components/navbar#controlled-menu", "hierarchy": { @@ -3654,7 +5099,7 @@ }, { "content": "With Border", - "objectID": "25bdf663-f8ac-4c03-90ff-1b3536e2017f", + "objectID": "db3d0665-678d-42fa-ba03-73e32aa2b8af", "type": "lvl3", "url": "/docs/components/navbar#with-border", "hierarchy": { @@ -3665,7 +5110,7 @@ }, { "content": "Disabling Blur", - "objectID": "68b6761a-581e-43de-a529-a151b6c0189f", + "objectID": "972a9229-69f3-4ac8-b682-e43973d544d8", "type": "lvl3", "url": "/docs/components/navbar#disabling-blur", "hierarchy": { @@ -3676,7 +5121,7 @@ }, { "content": "With Dropdown Menu", - "objectID": "fda70dba-490a-491f-a86d-65f70baaa482", + "objectID": "607dabdd-1e00-47cb-b4ff-c97b27055bfb", "type": "lvl3", "url": "/docs/components/navbar#with-dropdown-menu", "hierarchy": { @@ -3687,7 +5132,7 @@ }, { "content": "With Avatar", - "objectID": "43884ead-7d47-4a2d-846f-fe993d49a85d", + "objectID": "c666459b-8244-4b18-9b45-a3d42e4fe3cb", "type": "lvl3", "url": "/docs/components/navbar#with-avatar", "hierarchy": { @@ -3698,7 +5143,7 @@ }, { "content": "With Search Input", - "objectID": "678c3743-dfb6-411a-a1ca-558e86b378fa", + "objectID": "870f4656-d6c8-43c3-a105-a5cb9f2cfc10", "type": "lvl3", "url": "/docs/components/navbar#with-search-input", "hierarchy": { @@ -3709,7 +5154,7 @@ }, { "content": "Customizing the active item", - "objectID": "1de41b5c-e43b-400c-acfe-0596ff0d0017", + "objectID": "2c2d0cab-7c2c-4633-ac8f-cc8cd8f891da", "type": "lvl3", "url": "/docs/components/navbar#customizing-the-active-item", "hierarchy": { @@ -3720,35 +5165,35 @@ }, { "content": "Slots", - "objectID": "e0684659-a713-4c19-99d5-633be23b2911", + "objectID": "9a8a9175-2ccc-452b-a845-ce27cc7acd50", "type": "lvl2", "url": "/docs/components/navbar#slots", "hierarchy": { "lvl1": "Navbar", "lvl2": "Slots", "lvl3": null } }, { "content": "Data Attributes", - "objectID": "3e76bdae-cc13-4531-904a-d21cac439e4d", + "objectID": "e16351ee-4ae4-495f-a205-af0ec1e1ef53", "type": "lvl2", "url": "/docs/components/navbar#data-attributes", "hierarchy": { "lvl1": "Navbar", "lvl2": "Data Attributes", "lvl3": null } }, { "content": "API", - "objectID": "0735f091-5951-44da-96c6-34d4f585235f", + "objectID": "bc6fc83f-1617-4647-b5bc-b2f2f2685806", "type": "lvl2", "url": "/docs/components/navbar#api", "hierarchy": { "lvl1": "Navbar", "lvl2": "API", "lvl3": null } }, { "content": "Navbar Props", - "objectID": "f4fa0e33-cdc3-46e5-b051-c0e88f82a8d4", + "objectID": "6d5e9b42-19a2-4f8d-8cfb-7cef8bdd9a57", "type": "lvl3", "url": "/docs/components/navbar#navbar-props", "hierarchy": { "lvl1": "Navbar", "lvl2": "API", "lvl3": "Navbar Props" } }, { "content": "Navbar Events", - "objectID": "8a58e9f0-be73-4165-b37b-bf5a10c999ad", + "objectID": "f719424b-a629-4aa8-b8da-e311f289750e", "type": "lvl3", "url": "/docs/components/navbar#navbar-events", "hierarchy": { @@ -3759,7 +5204,7 @@ }, { "content": "NavbarContent Props", - "objectID": "516dc76a-0613-4aa5-899b-de4fd8cc0d1a", + "objectID": "457514af-d65d-451b-85c4-9af5813432c5", "type": "lvl3", "url": "/docs/components/navbar#navbarcontent-props", "hierarchy": { @@ -3770,7 +5215,7 @@ }, { "content": "NavbarItem Props", - "objectID": "82f64b89-55e0-4df1-9949-ce3cce0c7eff", + "objectID": "0e55e2ef-26b1-4560-a7f0-6e99b6c8686b", "type": "lvl3", "url": "/docs/components/navbar#navbaritem-props", "hierarchy": { @@ -3781,7 +5226,7 @@ }, { "content": "NavbarMenuToggle Props", - "objectID": "75c951bf-ff6d-46b0-8a45-09abdb865a2e", + "objectID": "21a8a4fa-10d0-4542-9b3e-711b07b48290", "type": "lvl3", "url": "/docs/components/navbar#navbarmenutoggle-props", "hierarchy": { @@ -3792,7 +5237,7 @@ }, { "content": "NavbarMenuToggle Events", - "objectID": "82c63781-653f-4588-8a26-97cf23020042", + "objectID": "31d57cf5-83af-4962-b6b0-235e0dc4761b", "type": "lvl3", "url": "/docs/components/navbar#navbarmenutoggle-events", "hierarchy": { @@ -3803,7 +5248,7 @@ }, { "content": "NavbarMenu Props", - "objectID": "073619f9-762b-44a2-be12-3cda27e90f92", + "objectID": "b24405e9-26b0-4692-b8a1-6740cde364ff", "type": "lvl3", "url": "/docs/components/navbar#navbarmenu-props", "hierarchy": { @@ -3814,7 +5259,7 @@ }, { "content": "NavbarMenuItem Props", - "objectID": "4d6210d6-08a1-4f75-8ebe-f8c8b753340c", + "objectID": "f573d365-65a1-445e-a63f-351b1ab7d3dc", "type": "lvl3", "url": "/docs/components/navbar#navbarmenuitem-props", "hierarchy": { @@ -3825,7 +5270,7 @@ }, { "content": "Navbar types", - "objectID": "b450085b-84ef-4434-a678-9bb9378dd96d", + "objectID": "92369b1e-d126-45ef-b9ff-0176545aba86", "type": "lvl3", "url": "/docs/components/navbar#navbar-types", "hierarchy": { @@ -3836,63 +5281,70 @@ }, { "content": "Motion Props", - "objectID": "fbbd5851-1440-4624-ab57-ba575b058b4a", + "objectID": "c19a553a-3dbd-4898-afe2-4971aac89208", "type": "lvl4", "url": "/docs/components/navbar#motion-props", "hierarchy": { "lvl1": "Navbar", "lvl2": "Navbar types", "lvl3": null } }, { "content": "Pagination", - "objectID": "debbe04e-1553-4469-a769-7bad08a9791f", + "objectID": "0e79acaa-f3ab-4200-8a17-015e4919a595", "type": "lvl1", "url": "/docs/components/pagination", "hierarchy": { "lvl1": "Pagination" } }, + { + "content": "Installation", + "objectID": "398013fb-9517-4533-ab6f-fe5974b9e3e5", + "type": "lvl2", + "url": "/docs/components/pagination#installation", + "hierarchy": { "lvl1": "Pagination", "lvl2": "Installation", "lvl3": null } + }, { "content": "Import", - "objectID": "7ea59626-9e72-4f69-adb4-91a296d23070", + "objectID": "84745104-93ab-4f20-ab8c-4fec65582603", "type": "lvl2", "url": "/docs/components/pagination#import", "hierarchy": { "lvl1": "Pagination", "lvl2": "Import", "lvl3": null } }, { "content": "Usage", - "objectID": "9edab8c6-a02d-4475-9c1c-538bbc3c623a", + "objectID": "8afc9e3a-5621-47f3-8457-b6753264515d", "type": "lvl2", "url": "/docs/components/pagination#usage", "hierarchy": { "lvl1": "Pagination", "lvl2": "Usage", "lvl3": null } }, { "content": "Disabled", - "objectID": "b0fac9c0-dd36-4126-ac94-bc837fec8151", + "objectID": "17a1bb3a-56ee-47c0-923e-0de13143e9f4", "type": "lvl3", "url": "/docs/components/pagination#disabled", "hierarchy": { "lvl1": "Pagination", "lvl2": "Usage", "lvl3": "Disabled" } }, { "content": "Sizes", - "objectID": "00766260-2ae4-4544-9ece-d09642bf83f3", + "objectID": "a0f28ee4-a80a-4941-830a-4b4f8fa52a3e", "type": "lvl3", "url": "/docs/components/pagination#sizes", "hierarchy": { "lvl1": "Pagination", "lvl2": "Disabled", "lvl3": "Sizes" } }, { "content": "Colors", - "objectID": "236fcd08-6102-4402-99de-78823d96fcdb", + "objectID": "baea06ea-1489-48db-9db4-93756727bcc7", "type": "lvl3", "url": "/docs/components/pagination#colors", "hierarchy": { "lvl1": "Pagination", "lvl2": "Sizes", "lvl3": "Colors" } }, { "content": "Variants", - "objectID": "76a561e8-1113-461a-8c7c-8755024381fc", + "objectID": "45d062c3-9c63-4cad-9543-af4731100321", "type": "lvl3", "url": "/docs/components/pagination#variants", "hierarchy": { "lvl1": "Pagination", "lvl2": "Colors", "lvl3": "Variants" } }, { "content": "With Controls", - "objectID": "d42d497d-ee65-40eb-b9ed-90d3f302a9bb", + "objectID": "45f7fed0-991d-4d83-ba6d-4dc0fb48e0da", "type": "lvl3", "url": "/docs/components/pagination#with-controls", "hierarchy": { @@ -3903,7 +5355,7 @@ }, { "content": "Pagination Loop", - "objectID": "e18803dd-4909-4289-8529-7b569586a345", + "objectID": "33336743-e055-45f0-8101-5fcf9a298049", "type": "lvl3", "url": "/docs/components/pagination#pagination-loop", "hierarchy": { @@ -3914,7 +5366,7 @@ }, { "content": "Changing the initial page", - "objectID": "967670d8-017d-4125-8747-8e8d4335b3d8", + "objectID": "c6d353c8-002d-469d-9baa-746bc76a7bbc", "type": "lvl3", "url": "/docs/components/pagination#changing-the-initial-page", "hierarchy": { @@ -3925,7 +5377,7 @@ }, { "content": "Compact Pagination", - "objectID": "54b1af7c-9ed3-4cff-8ef6-4c307ba78e36", + "objectID": "0ba4e34e-5053-44b5-b9ac-8741977a7afe", "type": "lvl3", "url": "/docs/components/pagination#compact-pagination", "hierarchy": { @@ -3936,7 +5388,7 @@ }, { "content": "With Shadow", - "objectID": "6f68da25-4489-4c3d-be1f-33e2d2d55a77", + "objectID": "4d2e8cc5-7569-4d6b-b8c2-78410bceb81c", "type": "lvl3", "url": "/docs/components/pagination#with-shadow", "hierarchy": { @@ -3947,7 +5399,7 @@ }, { "content": "Controlled", - "objectID": "f2ac411e-41e2-4b09-bfa4-5dc19b6958b9", + "objectID": "e49defd8-cfec-4334-9a66-1b9fb3ec6e39", "type": "lvl3", "url": "/docs/components/pagination#controlled", "hierarchy": { @@ -3958,7 +5410,7 @@ }, { "content": "Siblings", - "objectID": "def72c5e-4910-4bff-9fff-d69c71a04913", + "objectID": "442da795-8ed7-4b16-8970-b9d094b7f8f8", "type": "lvl3", "url": "/docs/components/pagination#siblings", "hierarchy": { @@ -3969,7 +5421,7 @@ }, { "content": "Boundaries", - "objectID": "0f494a15-046d-4314-85e1-2d43e00d64c4", + "objectID": "49835710-44da-4237-b1db-3eddba2b2b23", "type": "lvl3", "url": "/docs/components/pagination#boundaries", "hierarchy": { @@ -3980,7 +5432,7 @@ }, { "content": "Custom items", - "objectID": "2fbb68c8-7f67-46b0-aeae-8f1ff54f7043", + "objectID": "b00a38f0-9a93-4616-a168-78385c3a2da2", "type": "lvl3", "url": "/docs/components/pagination#custom-items", "hierarchy": { @@ -3991,14 +5443,14 @@ }, { "content": "Slots", - "objectID": "14e16e7f-3702-4170-9818-5d96193de4b4", + "objectID": "96e50019-97f2-4e85-9346-b2082eaccfa1", "type": "lvl2", "url": "/docs/components/pagination#slots", "hierarchy": { "lvl1": "Pagination", "lvl2": "Slots", "lvl3": null } }, { "content": "Custom Styles", - "objectID": "b76549af-6a1a-42e9-b7de-49d42ab7538a", + "objectID": "a6c85b2c-e74d-467e-9fe5-9640c1ef62b9", "type": "lvl3", "url": "/docs/components/pagination#custom-styles", "hierarchy": { @@ -4009,7 +5461,7 @@ }, { "content": "Custom Implementation", - "objectID": "831fb56b-d605-44b4-904c-7287b4404b50", + "objectID": "e0f36e97-a338-4c0b-819c-ef000c89e183", "type": "lvl3", "url": "/docs/components/pagination#custom-implementation", "hierarchy": { @@ -4020,7 +5472,7 @@ }, { "content": "Data Attributes", - "objectID": "af0b8520-561c-4dc6-9be2-916b3a5cc19f", + "objectID": "6502db5d-4ed1-4b01-ae9d-68c5c8994aa8", "type": "lvl2", "url": "/docs/components/pagination#data-attributes", "hierarchy": { @@ -4031,21 +5483,21 @@ }, { "content": "Accessibility", - "objectID": "3b3c7dc1-dabd-4b72-9ba4-a1dfaae6e0b4", + "objectID": "1332808d-d7e0-4c22-bbb7-ec24384e5b0d", "type": "lvl2", "url": "/docs/components/pagination#accessibility", "hierarchy": { "lvl1": "Pagination", "lvl2": "Accessibility", "lvl3": null } }, { "content": "API", - "objectID": "45f21873-fd4d-4701-ae4d-23cd053a7063", + "objectID": "0f022438-bfb4-4c71-9d72-78931ab2bb1d", "type": "lvl2", "url": "/docs/components/pagination#api", "hierarchy": { "lvl1": "Pagination", "lvl2": "API", "lvl3": null } }, { "content": "Pagination Props", - "objectID": "6084c4af-d759-49e6-89bc-e43662480052", + "objectID": "75add0e6-21ee-4e1a-838f-c261974ee702", "type": "lvl3", "url": "/docs/components/pagination#pagination-props", "hierarchy": { @@ -4056,7 +5508,7 @@ }, { "content": "Pagination Events", - "objectID": "8ef3a315-b98e-4b19-adb4-edc5ec2f895b", + "objectID": "b9eda79a-8f6e-4b6e-8e74-8eff29c5f86d", "type": "lvl3", "url": "/docs/components/pagination#pagination-events", "hierarchy": { @@ -4067,7 +5519,7 @@ }, { "content": "Types", - "objectID": "72f32a6e-ee4f-40de-a7f1-117bd002fb9e", + "objectID": "302b83b4-b4f2-4691-8a1e-7471791e5c1e", "type": "lvl3", "url": "/docs/components/pagination#types", "hierarchy": { @@ -4078,70 +5530,77 @@ }, { "content": "Pagination Item Props", - "objectID": "1b22a80d-424e-48d8-915f-66c34fe0bb26", + "objectID": "8c24652f-fca1-4dab-9b8b-c00de8f591d2", "type": "lvl4", "url": "/docs/components/pagination#pagination-item-props", "hierarchy": { "lvl1": "Pagination", "lvl2": "Types", "lvl3": null } }, { "content": "Popover", - "objectID": "9a63e557-196f-40c4-b890-9242333b99c3", + "objectID": "9cf0871c-af84-4fd1-8e43-50bf70572d65", "type": "lvl1", "url": "/docs/components/popover", "hierarchy": { "lvl1": "Popover" } }, + { + "content": "Installation", + "objectID": "f17fad02-5213-497f-a511-698bb6c1badb", + "type": "lvl2", + "url": "/docs/components/popover#installation", + "hierarchy": { "lvl1": "Popover", "lvl2": "Installation", "lvl3": null } + }, { "content": "Import", - "objectID": "fa682b2e-21b9-442d-8fce-59526267cd92", + "objectID": "9164a526-18a5-45b1-965a-a5ac439365aa", "type": "lvl2", "url": "/docs/components/popover#import", "hierarchy": { "lvl1": "Popover", "lvl2": "Import", "lvl3": null } }, { "content": "Usage", - "objectID": "cc795508-3646-419b-b99f-4b412c82c0ba", + "objectID": "fc47d13d-2bd2-4f79-97f2-6f6a760d351c", "type": "lvl2", "url": "/docs/components/popover#usage", "hierarchy": { "lvl1": "Popover", "lvl2": "Usage", "lvl3": null } }, { "content": "With Arrow", - "objectID": "9672cf7e-7d25-48bf-a05c-60215f885193", + "objectID": "fb0cf880-0278-4e21-9e1b-52e42e22d6cd", "type": "lvl3", "url": "/docs/components/popover#with-arrow", "hierarchy": { "lvl1": "Popover", "lvl2": "Usage", "lvl3": "With Arrow" } }, { "content": "Colors", - "objectID": "3ab82446-2e4f-46e0-89df-c8afc6802ee4", + "objectID": "f8a9d3ed-e61b-432d-a1d3-41b121c55d2f", "type": "lvl3", "url": "/docs/components/popover#colors", "hierarchy": { "lvl1": "Popover", "lvl2": "With Arrow", "lvl3": "Colors" } }, { "content": "Placements", - "objectID": "a9d9dd79-e649-47f0-a812-6708b5d83464", + "objectID": "959028df-4dc7-480f-9b1c-97905be95e9b", "type": "lvl3", "url": "/docs/components/popover#placements", "hierarchy": { "lvl1": "Popover", "lvl2": "Colors", "lvl3": "Placements" } }, { "content": "Offset", - "objectID": "787e2e1d-16a0-4c40-b7a0-7c04b8e6d0b6", + "objectID": "eb23c384-cf53-481e-b1df-6aa1eadc8b6c", "type": "lvl3", "url": "/docs/components/popover#offset", "hierarchy": { "lvl1": "Popover", "lvl2": "Placements", "lvl3": "Offset" } }, { "content": "Controlled", - "objectID": "1717f86b-2d69-46e2-9187-770bc456023e", + "objectID": "116c0653-ca20-4a01-9848-134eee4971f5", "type": "lvl3", "url": "/docs/components/popover#controlled", "hierarchy": { "lvl1": "Popover", "lvl2": "Offset", "lvl3": "Controlled" } }, { "content": "Title Props", - "objectID": "2557d0c6-9bf1-4397-990d-3fab4c07f2bb", + "objectID": "abd1328c-d123-47cb-ac7e-1d8b2df39ccf", "type": "lvl3", "url": "/docs/components/popover#title-props", "hierarchy": { @@ -4152,7 +5611,7 @@ }, { "content": "With Form", - "objectID": "b0f2ac80-d4e1-4633-a903-299decebd6a4", + "objectID": "3255c0ff-3aec-4566-a265-757330f7acf8", "type": "lvl3", "url": "/docs/components/popover#with-form", "hierarchy": { @@ -4163,14 +5622,14 @@ }, { "content": "Backdrop", - "objectID": "c0e7f2d2-f472-4367-8cbe-4aac578a6d69", + "objectID": "d2b6d0b3-0430-4a78-95f0-596c6d31659a", "type": "lvl3", "url": "/docs/components/popover#backdrop", "hierarchy": { "lvl1": "Popover", "lvl2": "With Form", "lvl3": "Backdrop" } }, { "content": "Custom Motion", - "objectID": "59e5b92c-a520-4c81-9664-d30e54128fa2", + "objectID": "32676dc7-81a0-40f8-ad8e-f69aacd38c25", "type": "lvl3", "url": "/docs/components/popover#custom-motion", "hierarchy": { @@ -4181,7 +5640,7 @@ }, { "content": "Custom Trigger", - "objectID": "96f759fb-94ec-4359-9b8c-ba79c0d8ded4", + "objectID": "5a9366d2-5c65-4ee3-9167-cc3a8f6750ec", "type": "lvl3", "url": "/docs/components/popover#custom-trigger", "hierarchy": { @@ -4192,49 +5651,49 @@ }, { "content": "Slots", - "objectID": "9cef360b-d811-4275-9d57-4124c2d3c01a", + "objectID": "67464e25-7471-413e-a161-577ead1a0f20", "type": "lvl2", "url": "/docs/components/popover#slots", "hierarchy": { "lvl1": "Popover", "lvl2": "Slots", "lvl3": null } }, { "content": "Custom Styles", - "objectID": "e6330233-38af-406e-9ccf-e029394952e1", + "objectID": "e4b3ad67-b176-4b69-9046-c938f58b3030", "type": "lvl3", "url": "/docs/components/popover#custom-styles", "hierarchy": { "lvl1": "Popover", "lvl2": "Slots", "lvl3": "Custom Styles" } }, { "content": "Data Attributes", - "objectID": "4d6fafb6-d494-41d4-80bd-953a1e14f105", + "objectID": "95313bdd-1383-4c31-9b62-9d2b415e7c1b", "type": "lvl2", "url": "/docs/components/popover#data-attributes", "hierarchy": { "lvl1": "Popover", "lvl2": "Data Attributes", "lvl3": null } }, { "content": "Accessibility", - "objectID": "22758d0b-ebc8-44af-ac06-2748b7dc642b", + "objectID": "12f829af-e805-44b5-82d3-4effdef49035", "type": "lvl2", "url": "/docs/components/popover#accessibility", "hierarchy": { "lvl1": "Popover", "lvl2": "Accessibility", "lvl3": null } }, { "content": "API", - "objectID": "dc7e2a1d-da70-4908-aa84-d1935f379d29", + "objectID": "97208632-4716-4912-90e8-3c95c0ac4f02", "type": "lvl2", "url": "/docs/components/popover#api", "hierarchy": { "lvl1": "Popover", "lvl2": "API", "lvl3": null } }, { "content": "Popover Props", - "objectID": "599d9637-0604-4fd6-88ac-4ad6e457ec5a", + "objectID": "24eebe0a-bb78-41fb-af7a-19bc95eeca2c", "type": "lvl3", "url": "/docs/components/popover#popover-props", "hierarchy": { "lvl1": "Popover", "lvl2": "API", "lvl3": "Popover Props" } }, { "content": "Popover Events", - "objectID": "67dec2ab-719e-47a1-a64c-17ed5987c24c", + "objectID": "a8ac643f-ef5a-4621-8ddb-b59dfd988655", "type": "lvl3", "url": "/docs/components/popover#popover-events", "hierarchy": { @@ -4245,7 +5704,7 @@ }, { "content": "PopoverTrigger Props", - "objectID": "a6a65f8f-b72e-4e3c-b680-5bac6efb99f3", + "objectID": "6691a008-de01-4eab-863e-df0cc6e750b7", "type": "lvl3", "url": "/docs/components/popover#popovertrigger-props", "hierarchy": { @@ -4256,7 +5715,7 @@ }, { "content": "PopoverContent Props", - "objectID": "3453d554-d987-4968-ac67-f612e35c5def", + "objectID": "eaea5de2-f817-4c61-bc33-a58f087c10ae", "type": "lvl3", "url": "/docs/components/popover#popovercontent-props", "hierarchy": { @@ -4267,7 +5726,7 @@ }, { "content": "Popover types", - "objectID": "3963d859-2bfa-4e8f-8f41-27921f6418b0", + "objectID": "fda20f86-b441-45de-8a82-9fb69473616e", "type": "lvl3", "url": "/docs/components/popover#popover-types", "hierarchy": { @@ -4278,14 +5737,14 @@ }, { "content": "Popover Placement", - "objectID": "bbc2b13d-1341-43d7-8192-13a246eb3c8d", + "objectID": "9e4978f9-11db-494e-bc83-8c3822cb520a", "type": "lvl4", "url": "/docs/components/popover#popover-placement", "hierarchy": { "lvl1": "Popover", "lvl2": "Popover types", "lvl3": null } }, { "content": "Motion Props", - "objectID": "2e42e5ae-a0f1-4570-ab4d-0f1ad17f3315", + "objectID": "f73e3c2e-811e-4f83-8d4e-189fccc5d89d", "type": "lvl4", "url": "/docs/components/popover#motion-props", "hierarchy": { @@ -4296,42 +5755,49 @@ }, { "content": "Progress", - "objectID": "c2aa12b8-c2fb-4bb3-97b8-79ceb10ae515", + "objectID": "2edb930c-0d00-44ad-ae8d-7a918cc71240", "type": "lvl1", "url": "/docs/components/progress", "hierarchy": { "lvl1": "Progress" } }, + { + "content": "Installation", + "objectID": "7b545a75-6cdd-47e3-8ad1-22f587368e08", + "type": "lvl2", + "url": "/docs/components/progress#installation", + "hierarchy": { "lvl1": "Progress", "lvl2": "Installation", "lvl3": null } + }, { "content": "Import", - "objectID": "59d1af74-77d4-4468-b522-2c429c91dd27", + "objectID": "c4f3bf70-4434-4a50-8541-8961dfadf159", "type": "lvl2", "url": "/docs/components/progress#import", "hierarchy": { "lvl1": "Progress", "lvl2": "Import", "lvl3": null } }, { "content": "Usage", - "objectID": "77894cc2-6cc8-4915-913d-1b5d67f23b71", + "objectID": "84d7a90f-bbed-4cf5-95c9-e924adf25d65", "type": "lvl2", "url": "/docs/components/progress#usage", "hierarchy": { "lvl1": "Progress", "lvl2": "Usage", "lvl3": null } }, { "content": "Sizes", - "objectID": "9bf1d2a4-f02c-40ee-955b-423faa041773", + "objectID": "198c4009-6cf0-42ac-ae83-9d04e541ba34", "type": "lvl3", "url": "/docs/components/progress#sizes", "hierarchy": { "lvl1": "Progress", "lvl2": "Usage", "lvl3": "Sizes" } }, { "content": "Colors", - "objectID": "217594e2-e207-4ece-8e86-b736d53f7a2b", + "objectID": "4c825735-8d24-4f4b-9e13-0d22679266ac", "type": "lvl3", "url": "/docs/components/progress#colors", "hierarchy": { "lvl1": "Progress", "lvl2": "Sizes", "lvl3": "Colors" } }, { "content": "Indeterminate", - "objectID": "fe05d150-b982-48fd-b30f-ca3736050fbf", + "objectID": "536c2f7f-d71c-4fad-957f-78554973b31f", "type": "lvl3", "url": "/docs/components/progress#indeterminate", "hierarchy": { @@ -4342,7 +5808,7 @@ }, { "content": "Striped", - "objectID": "e6497a8c-b259-4c90-a5d4-592f8168e9d1", + "objectID": "845fd249-5358-4f3d-b999-3039208c9529", "type": "lvl3", "url": "/docs/components/progress#striped", "hierarchy": { @@ -4353,14 +5819,14 @@ }, { "content": "With Label", - "objectID": "5407855e-c11e-451c-b90a-deb858257e55", + "objectID": "2beebf9e-f546-4846-af5c-5aeddf8cf4d3", "type": "lvl3", "url": "/docs/components/progress#with-label", "hierarchy": { "lvl1": "Progress", "lvl2": "Striped", "lvl3": "With Label" } }, { "content": "With Value", - "objectID": "859cac19-ff0e-4dbd-b1b1-99c3951b6d1b", + "objectID": "17a471e3-ff56-40da-b87c-401fefa73285", "type": "lvl3", "url": "/docs/components/progress#with-value", "hierarchy": { @@ -4371,7 +5837,7 @@ }, { "content": "Value Formatting", - "objectID": "8ceb9cc2-9bb8-4471-b4f6-2088e34d357b", + "objectID": "81a372b3-dfb2-4fa3-847f-035e80b2f187", "type": "lvl3", "url": "/docs/components/progress#value-formatting", "hierarchy": { @@ -4382,14 +5848,14 @@ }, { "content": "Slots", - "objectID": "f3bd91a4-decb-4241-93a4-955a83d96219", + "objectID": "5d202539-96a4-4f6d-951d-12d7cc715b08", "type": "lvl2", "url": "/docs/components/progress#slots", "hierarchy": { "lvl1": "Progress", "lvl2": "Slots", "lvl3": null } }, { "content": "Custom Styles", - "objectID": "08c69b2c-63d0-451b-b449-eadefabb5656", + "objectID": "2836bc0c-3d1f-477b-9726-580edd156bf1", "type": "lvl3", "url": "/docs/components/progress#custom-styles", "hierarchy": { @@ -4400,70 +5866,77 @@ }, { "content": "Data Attributes", - "objectID": "089694ea-a7b2-4ce0-ac79-f86feef537b0", + "objectID": "b0b33c73-50a4-4600-b7e0-972f99528d7e", "type": "lvl2", "url": "/docs/components/progress#data-attributes", "hierarchy": { "lvl1": "Progress", "lvl2": "Data Attributes", "lvl3": null } }, { "content": "Accessibility", - "objectID": "f1cd833b-52a0-4370-8794-d1339974d0b8", + "objectID": "f86b7330-ac6e-4c7a-ba13-7590fceb6a05", "type": "lvl2", "url": "/docs/components/progress#accessibility", "hierarchy": { "lvl1": "Progress", "lvl2": "Accessibility", "lvl3": null } }, { "content": "API", - "objectID": "4bb15152-40c9-49d8-8c71-53aefa61ee99", + "objectID": "12c3af23-ad7c-4c24-9247-0cd29023b81b", "type": "lvl2", "url": "/docs/components/progress#api", "hierarchy": { "lvl1": "Progress", "lvl2": "API", "lvl3": null } }, { "content": "Progress Props", - "objectID": "129bf2ba-7a5f-41d9-9bbf-27a81487dcef", + "objectID": "7e70e29c-7976-4858-9af3-45f7fec877dd", "type": "lvl3", "url": "/docs/components/progress#progress-props", "hierarchy": { "lvl1": "Progress", "lvl2": "API", "lvl3": "Progress Props" } }, { "content": "Radio", - "objectID": "9de9483a-5361-47fb-baeb-2a2a6a8043b8", + "objectID": "f95fa054-d89a-4a65-83c6-c4d4205c1681", "type": "lvl1", "url": "/docs/components/radio-group", "hierarchy": { "lvl1": "Radio" } }, { "content": "Radio group", - "objectID": "e00b9bf4-d407-4837-808d-df164f273a43", + "objectID": "d22e774f-5979-4042-8b35-d7aab58f6065", "type": "lvl1", "url": "/docs/components/radio-group#radio-group", "hierarchy": { "lvl1": "Radio", "lvl2": null, "lvl3": null } }, + { + "content": "Installation", + "objectID": "fd8eff22-a973-489e-8f13-1c67885e634e", + "type": "lvl2", + "url": "/docs/components/radio-group#installation", + "hierarchy": { "lvl1": "Radio", "lvl2": "Installation", "lvl3": null } + }, { "content": "Import", - "objectID": "e23800c4-3cc3-46af-9925-0ee5878a32d2", + "objectID": "3f3c0574-41f6-4c40-89aa-1b8e8150563c", "type": "lvl2", "url": "/docs/components/radio-group#import", "hierarchy": { "lvl1": "Radio", "lvl2": "Import", "lvl3": null } }, { "content": "Usage", - "objectID": "6d39f23e-4c4d-41a4-80ca-f6e605ae1010", + "objectID": "8ba6608e-f0d7-4bcb-ab70-8253a8156b8c", "type": "lvl2", "url": "/docs/components/radio-group#usage", "hierarchy": { "lvl1": "Radio", "lvl2": "Usage", "lvl3": null } }, { "content": "Disabled", - "objectID": "6406a2f7-76d0-467b-8b53-92a05698e366", + "objectID": "f29fa08f-97c7-4ee3-b8e5-6eb4d25112b6", "type": "lvl3", "url": "/docs/components/radio-group#disabled", "hierarchy": { "lvl1": "Radio", "lvl2": "Usage", "lvl3": "Disabled" } }, { "content": "Default Value", - "objectID": "fa304931-c4b9-4029-bb93-d447a95df004", + "objectID": "396ea819-34e6-4b1f-a665-6b28453d0476", "type": "lvl3", "url": "/docs/components/radio-group#default-value", "hierarchy": { @@ -4474,7 +5947,7 @@ }, { "content": "With Description", - "objectID": "da535006-f34b-42d3-a9e6-64f8844ec136", + "objectID": "98e06f3d-db8e-4ca8-96ee-adae15899562", "type": "lvl3", "url": "/docs/components/radio-group#with-description", "hierarchy": { @@ -4485,7 +5958,7 @@ }, { "content": "Horizontal", - "objectID": "a8041a60-73c9-4986-a386-a80b19568d69", + "objectID": "12e6ce83-1926-4278-a83c-820f2c443028", "type": "lvl3", "url": "/docs/components/radio-group#horizontal", "hierarchy": { @@ -4496,35 +5969,35 @@ }, { "content": "Controlled", - "objectID": "078cfe3a-647b-47fe-bd65-60865ff9b471", + "objectID": "dd967ea5-431e-4568-b5d6-35bd4e4389c9", "type": "lvl3", "url": "/docs/components/radio-group#controlled", "hierarchy": { "lvl1": "Radio", "lvl2": "Horizontal", "lvl3": "Controlled" } }, { "content": "Invalid", - "objectID": "bcded225-1a98-4f72-91cf-68977cd57e14", + "objectID": "9d0d9958-e765-4c53-9ec1-4acbf1a342eb", "type": "lvl3", "url": "/docs/components/radio-group#invalid", "hierarchy": { "lvl1": "Radio", "lvl2": "Controlled", "lvl3": "Invalid" } }, { "content": "Slots", - "objectID": "1db63060-5053-4550-a236-a416d1f6914d", + "objectID": "244b2e5e-df72-4d4c-8f57-8ce53315e55a", "type": "lvl2", "url": "/docs/components/radio-group#slots", "hierarchy": { "lvl1": "Radio", "lvl2": "Slots", "lvl3": null } }, { "content": "Custom Styles", - "objectID": "f3e11c39-1515-44b3-b21d-7ca7722b439c", + "objectID": "534a3814-8d62-48ea-b637-f7fac071b1f1", "type": "lvl3", "url": "/docs/components/radio-group#custom-styles", "hierarchy": { "lvl1": "Radio", "lvl2": "Slots", "lvl3": "Custom Styles" } }, { "content": "Custom Implementation", - "objectID": "a81cb18b-eff1-46b9-b7be-e055fa1e170e", + "objectID": "36ed5523-36b8-426c-a2ef-b3981c5ee198", "type": "lvl3", "url": "/docs/components/radio-group#custom-implementation", "hierarchy": { @@ -4535,35 +6008,35 @@ }, { "content": "Data Attributes", - "objectID": "5702e40a-84d0-43ca-993a-dca970a914b8", + "objectID": "d16bab9d-f869-44cc-b8e4-acaf93a5ae85", "type": "lvl2", "url": "/docs/components/radio-group#data-attributes", "hierarchy": { "lvl1": "Radio", "lvl2": "Data Attributes", "lvl3": null } }, { "content": "Accessibility", - "objectID": "4b179a92-3269-4821-9759-c773457d5913", + "objectID": "d80b26da-ec78-4af6-a0d6-62aab513410e", "type": "lvl2", "url": "/docs/components/radio-group#accessibility", "hierarchy": { "lvl1": "Radio", "lvl2": "Accessibility", "lvl3": null } }, { "content": "API", - "objectID": "ad72d9a7-19ba-4e00-9548-9fa8075d6759", + "objectID": "f805c6fd-e492-4822-ae66-ac5e38acd679", "type": "lvl2", "url": "/docs/components/radio-group#api", "hierarchy": { "lvl1": "Radio", "lvl2": "API", "lvl3": null } }, { "content": "RadioGroup Props", - "objectID": "4d9e9604-1fc3-4b97-b7f6-637219cb4488", + "objectID": "2c73a8b3-fac0-4310-8e65-1fb22791370b", "type": "lvl3", "url": "/docs/components/radio-group#radiogroup-props", "hierarchy": { "lvl1": "Radio", "lvl2": "API", "lvl3": "RadioGroup Props" } }, { "content": "RadioGroup Events", - "objectID": "3c648de3-b2c9-4794-bbad-b24556c9dd57", + "objectID": "ebee0599-a3ce-4000-8575-d14120bc8807", "type": "lvl3", "url": "/docs/components/radio-group#radiogroup-events", "hierarchy": { @@ -4574,7 +6047,7 @@ }, { "content": "Radio Props", - "objectID": "3ae0468b-dd33-47e6-ad77-a86068641db6", + "objectID": "bc06c184-c736-4d5a-ad0d-067d4c8a2cf5", "type": "lvl3", "url": "/docs/components/radio-group#radio-props", "hierarchy": { @@ -4583,30 +6056,285 @@ "lvl3": "Radio Props" } }, + { + "content": "Range Calendar", + "objectID": "575b4208-82a6-4199-8ba8-f72cc0bd6029", + "type": "lvl1", + "url": "/docs/components/range-calendar", + "hierarchy": { "lvl1": "Range Calendar" } + }, + { + "content": "Installation", + "objectID": "5171b3ca-2720-4f59-8362-bd1a41ada909", + "type": "lvl2", + "url": "/docs/components/range-calendar#installation", + "hierarchy": { + "lvl1": "Range Calendar", + "lvl2": "Installation", + "lvl3": null + } + }, + { + "content": "Import", + "objectID": "b10ceadc-c38c-48db-b7e7-4a9be01f526e", + "type": "lvl2", + "url": "/docs/components/range-calendar#import", + "hierarchy": { "lvl1": "Range Calendar", "lvl2": "Import", "lvl3": null } + }, + { + "content": "Usage", + "objectID": "3757f9e8-4a5f-41d0-9b8e-3ef3fb8e91ea", + "type": "lvl2", + "url": "/docs/components/range-calendar#usage", + "hierarchy": { "lvl1": "Range Calendar", "lvl2": "Usage", "lvl3": null } + }, + { + "content": "Disabled", + "objectID": "2f2eec83-43b9-47d1-a1cb-b0d3b6246c4c", + "type": "lvl3", + "url": "/docs/components/range-calendar#disabled", + "hierarchy": { + "lvl1": "Range Calendar", + "lvl2": "Usage", + "lvl3": "Disabled" + } + }, + { + "content": "Read Only", + "objectID": "b257157b-1e7a-4623-b789-b2ed7b6f8042", + "type": "lvl3", + "url": "/docs/components/range-calendar#read-only", + "hierarchy": { + "lvl1": "Range Calendar", + "lvl2": "Disabled", + "lvl3": "Read Only" + } + }, + { + "content": "Controlled", + "objectID": "03b5e8f0-1582-406a-8761-198ddda0aa4f", + "type": "lvl3", + "url": "/docs/components/range-calendar#controlled", + "hierarchy": { + "lvl1": "Range Calendar", + "lvl2": "Read Only", + "lvl3": "Controlled" + } + }, + { + "content": "Min Date Value", + "objectID": "0b2e3317-1b75-4995-ae0b-7ffe0167c42e", + "type": "lvl3", + "url": "/docs/components/range-calendar#min-date-value", + "hierarchy": { + "lvl1": "Range Calendar", + "lvl2": "Controlled", + "lvl3": "Min Date Value" + } + }, + { + "content": "Max Date Value", + "objectID": "c0686577-e125-4138-a9f4-df1ba8db0172", + "type": "lvl3", + "url": "/docs/components/range-calendar#max-date-value", + "hierarchy": { + "lvl1": "Range Calendar", + "lvl2": "Min Date Value", + "lvl3": "Max Date Value" + } + }, + { + "content": "Unavailable Dates", + "objectID": "7ea06775-592e-4113-b861-a70f5d7663b2", + "type": "lvl3", + "url": "/docs/components/range-calendar#unavailable-dates", + "hierarchy": { + "lvl1": "Range Calendar", + "lvl2": "Max Date Value", + "lvl3": "Unavailable Dates" + } + }, + { + "content": "Non-Contiguous Ranges", + "objectID": "08c6a5ee-8a31-4746-88e1-0047078ff5a5", + "type": "lvl3", + "url": "/docs/components/range-calendar#non-contiguous-ranges", + "hierarchy": { + "lvl1": "Range Calendar", + "lvl2": "Unavailable Dates", + "lvl3": "Non-Contiguous Ranges" + } + }, + { + "content": "Controlled Focused Value", + "objectID": "5f1c671a-567b-4d82-aa1e-58b24220e04a", + "type": "lvl3", + "url": "/docs/components/range-calendar#controlled-focused-value", + "hierarchy": { + "lvl1": "Range Calendar", + "lvl2": "Non-Contiguous Ranges", + "lvl3": "Controlled Focused Value" + } + }, + { + "content": "Invalid Date", + "objectID": "443b9320-3601-4940-a207-608c15cfd9b1", + "type": "lvl3", + "url": "/docs/components/range-calendar#invalid-date", + "hierarchy": { + "lvl1": "Range Calendar", + "lvl2": "Controlled Focused Value", + "lvl3": "Invalid Date" + } + }, + { + "content": "International Calendars", + "objectID": "f1bed985-c572-4e19-9994-3893758a7765", + "type": "lvl3", + "url": "/docs/components/range-calendar#international-calendars", + "hierarchy": { + "lvl1": "Range Calendar", + "lvl2": "Invalid Date", + "lvl3": "International Calendars" + } + }, + { + "content": "Visible Months", + "objectID": "9c1efca8-7784-4b79-9644-8246386a6b0d", + "type": "lvl3", + "url": "/docs/components/range-calendar#visible-months", + "hierarchy": { + "lvl1": "Range Calendar", + "lvl2": "International Calendars", + "lvl3": "Visible Months" + } + }, + { + "content": "Page Behaviour", + "objectID": "c1361748-b47d-481d-a21c-1d161afdfac5", + "type": "lvl3", + "url": "/docs/components/range-calendar#page-behaviour", + "hierarchy": { + "lvl1": "Range Calendar", + "lvl2": "Visible Months", + "lvl3": "Page Behaviour" + } + }, + { + "content": "Presets", + "objectID": "067298ea-4134-477e-a319-9c7345b068c8", + "type": "lvl3", + "url": "/docs/components/range-calendar#presets", + "hierarchy": { + "lvl1": "Range Calendar", + "lvl2": "Page Behaviour", + "lvl3": "Presets" + } + }, + { + "content": "Slots", + "objectID": "354b9d1e-478f-47ab-975b-f35f79dd1764", + "type": "lvl2", + "url": "/docs/components/range-calendar#slots", + "hierarchy": { "lvl1": "Range Calendar", "lvl2": "Slots", "lvl3": null } + }, + { + "content": "Data Attributes", + "objectID": "d109ba05-49d3-49ce-bb9d-543cca303714", + "type": "lvl2", + "url": "/docs/components/range-calendar#data-attributes", + "hierarchy": { + "lvl1": "Range Calendar", + "lvl2": "Data Attributes", + "lvl3": null + } + }, + { + "content": "Accessibility", + "objectID": "7e144382-35c9-44dd-bb82-49922035f3f9", + "type": "lvl2", + "url": "/docs/components/range-calendar#accessibility", + "hierarchy": { + "lvl1": "Range Calendar", + "lvl2": "Accessibility", + "lvl3": null + } + }, + { + "content": "API", + "objectID": "0a5d9ab2-8b14-4880-ada1-5c1218f4572a", + "type": "lvl2", + "url": "/docs/components/range-calendar#api", + "hierarchy": { "lvl1": "Range Calendar", "lvl2": "API", "lvl3": null } + }, + { + "content": "RangeCalendar Props", + "objectID": "bb37b537-2af4-40c4-99a8-0d5860eb23b2", + "type": "lvl3", + "url": "/docs/components/range-calendar#rangecalendar-props", + "hierarchy": { + "lvl1": "Range Calendar", + "lvl2": "API", + "lvl3": "RangeCalendar Props" + } + }, + { + "content": "RangeCalendar Events", + "objectID": "bd5db4f1-7916-4e31-90a4-f3daee516365", + "type": "lvl3", + "url": "/docs/components/range-calendar#rangecalendar-events", + "hierarchy": { + "lvl1": "Range Calendar", + "lvl2": "RangeCalendar Props", + "lvl3": "RangeCalendar Events" + } + }, + { + "content": "Supported Calendars", + "objectID": "b76d7cb4-41ca-4b07-a865-411b3da7331a", + "type": "lvl4", + "url": "/docs/components/range-calendar#supported-calendars", + "hierarchy": { + "lvl1": "Range Calendar", + "lvl2": "RangeCalendar Events", + "lvl3": null + } + }, { "content": "Scroll Shadow", - "objectID": "149568e3-6684-4e68-b07a-e7df680fcf62", + "objectID": "6415610f-00bc-4e41-9ad4-12f190de39fd", "type": "lvl1", "url": "/docs/components/scroll-shadow", "hierarchy": { "lvl1": "Scroll Shadow" } }, + { + "content": "Installation", + "objectID": "234192b9-1801-4ac7-ba43-30aca28d5f94", + "type": "lvl2", + "url": "/docs/components/scroll-shadow#installation", + "hierarchy": { + "lvl1": "Scroll Shadow", + "lvl2": "Installation", + "lvl3": null + } + }, { "content": "Import", - "objectID": "a2a19af4-f305-4569-88bf-c81bf215653b", + "objectID": "b6f9c927-6535-49d9-bd18-2c482acf5308", "type": "lvl2", "url": "/docs/components/scroll-shadow#import", "hierarchy": { "lvl1": "Scroll Shadow", "lvl2": "Import", "lvl3": null } }, { "content": "Usage", - "objectID": "a71cd987-969e-4712-9b80-7ff83858a3ac", + "objectID": "0641120f-b5cd-4132-809e-b394941a5377", "type": "lvl2", "url": "/docs/components/scroll-shadow#usage", "hierarchy": { "lvl1": "Scroll Shadow", "lvl2": "Usage", "lvl3": null } }, { "content": "Hide Scrollbar", - "objectID": "9d8cf5da-cff2-4a9c-891b-a27ae76be3b8", + "objectID": "34dc8fad-d89e-4994-bcab-67107d36c115", "type": "lvl3", "url": "/docs/components/scroll-shadow#hide-scrollbar", "hierarchy": { @@ -4617,7 +6345,7 @@ }, { "content": "Custom Shadow Size", - "objectID": "243cd484-3682-4ab7-a1fa-554a4deac07c", + "objectID": "b29c948b-8756-4cb9-815c-119175a984a7", "type": "lvl3", "url": "/docs/components/scroll-shadow#custom-shadow-size", "hierarchy": { @@ -4628,7 +6356,7 @@ }, { "content": "Horizontal Orientation", - "objectID": "5d7da130-ae10-4313-8608-fc85d133060c", + "objectID": "5dc6799e-965e-408b-81c5-f7e68ad58f44", "type": "lvl3", "url": "/docs/components/scroll-shadow#horizontal-orientation", "hierarchy": { @@ -4639,7 +6367,7 @@ }, { "content": "Shadow Offset", - "objectID": "381a2efa-e15d-4e61-9e43-4d7f2302ae0d", + "objectID": "7969ba33-8aa8-444b-a3e4-103474c79bcc", "type": "lvl3", "url": "/docs/components/scroll-shadow#shadow-offset", "hierarchy": { @@ -4650,14 +6378,14 @@ }, { "content": "API", - "objectID": "bc3cbb46-e327-4923-ba87-c68acd360bfa", + "objectID": "74936381-2725-40a5-a61d-bf51362c86dd", "type": "lvl2", "url": "/docs/components/scroll-shadow#api", "hierarchy": { "lvl1": "Scroll Shadow", "lvl2": "API", "lvl3": null } }, { "content": "ShadowScroll Props", - "objectID": "29c0c708-9fa0-452b-a3d2-6409af70e76c", + "objectID": "92568995-0103-41b7-b7bf-8b4bd41ea901", "type": "lvl3", "url": "/docs/components/scroll-shadow#shadowscroll-props", "hierarchy": { @@ -4668,7 +6396,7 @@ }, { "content": "ShadowScroll Events", - "objectID": "502b735e-2482-4fe1-a4c3-9a3c0ec12c7b", + "objectID": "9b91093f-07b8-4e25-88fc-241fac366aba", "type": "lvl3", "url": "/docs/components/scroll-shadow#shadowscroll-events", "hierarchy": { @@ -4679,7 +6407,7 @@ }, { "content": "Types", - "objectID": "a0e94c87-749b-4276-b926-fa698ed33562", + "objectID": "2b768f8f-9a31-48f1-a147-fa8db81da0e8", "type": "lvl3", "url": "/docs/components/scroll-shadow#types", "hierarchy": { @@ -4690,42 +6418,49 @@ }, { "content": "Scroll Shadow Visibility", - "objectID": "e1cc888a-ee1a-4ef3-b96a-e29f58551593", + "objectID": "9d05097d-7e19-48bd-b188-d3d36c7c2404", "type": "lvl4", "url": "/docs/components/scroll-shadow#scroll-shadow-visibility", "hierarchy": { "lvl1": "Scroll Shadow", "lvl2": "Types", "lvl3": null } }, { "content": "Select", - "objectID": "52e411be-7a08-4d4a-9ed2-5b0642b3d8bb", + "objectID": "661b5e81-d086-4957-a3c1-59f24c50e7e6", "type": "lvl1", "url": "/docs/components/select", "hierarchy": { "lvl1": "Select" } }, + { + "content": "Installation", + "objectID": "d9a5db7c-861f-4f75-94bb-a777b6d18f5c", + "type": "lvl2", + "url": "/docs/components/select#installation", + "hierarchy": { "lvl1": "Select", "lvl2": "Installation", "lvl3": null } + }, { "content": "Import", - "objectID": "7d85a5cf-bbcc-4855-8fb9-45fcf3334776", + "objectID": "6f43ab6b-0614-4345-a707-2bac22454674", "type": "lvl2", "url": "/docs/components/select#import", "hierarchy": { "lvl1": "Select", "lvl2": "Import", "lvl3": null } }, { "content": "Usage", - "objectID": "f605591f-6ad2-485a-8fae-a3383527c574", + "objectID": "9067705a-36a8-4fb2-b550-780515f0100b", "type": "lvl2", "url": "/docs/components/select#usage", "hierarchy": { "lvl1": "Select", "lvl2": "Usage", "lvl3": null } }, { "content": "Dynamic items", - "objectID": "b0c3e5e5-b9a7-4d12-bbec-753ff81ed40c", + "objectID": "872085c6-b056-49c1-9266-03637cd3c761", "type": "lvl3", "url": "/docs/components/select#dynamic-items", "hierarchy": { "lvl1": "Select", "lvl2": "Usage", "lvl3": "Dynamic items" } }, { "content": "Multiple Selection", - "objectID": "280d0bc9-16c3-4e45-b3f2-eff9c6fdca85", + "objectID": "d55ef4be-b244-4b36-8be3-afa060fa8383", "type": "lvl3", "url": "/docs/components/select#multiple-selection", "hierarchy": { @@ -4736,7 +6471,7 @@ }, { "content": "Disabled", - "objectID": "cf1ff64f-642b-4a64-a81e-1c3cf5fa9692", + "objectID": "a012af18-98da-4642-8135-3144000706ef", "type": "lvl3", "url": "/docs/components/select#disabled", "hierarchy": { @@ -4747,7 +6482,7 @@ }, { "content": "Disabled Items", - "objectID": "0f2c1f25-571b-4e09-add6-aeb6d3386880", + "objectID": "5b8f95fd-0672-46e5-aa8f-a3fc16f4e006", "type": "lvl3", "url": "/docs/components/select#disabled-items", "hierarchy": { @@ -4758,7 +6493,7 @@ }, { "content": "Required", - "objectID": "5913108b-1d87-4810-bea5-c8064ae42607", + "objectID": "a4f548e2-714a-4401-9852-6b7968e179ea", "type": "lvl3", "url": "/docs/components/select#required", "hierarchy": { @@ -4769,35 +6504,35 @@ }, { "content": "Sizes", - "objectID": "1f283453-93f4-455e-aca4-ae8c5c42f999", + "objectID": "c3da8a3b-bdd9-4fa4-aeec-59fc97488cbf", "type": "lvl3", "url": "/docs/components/select#sizes", "hierarchy": { "lvl1": "Select", "lvl2": "Required", "lvl3": "Sizes" } }, { "content": "Colors", - "objectID": "0963b117-cb1d-43fb-9a99-88edced557d9", + "objectID": "6be3bfec-26c9-40c2-bcf1-639322562f0b", "type": "lvl3", "url": "/docs/components/select#colors", "hierarchy": { "lvl1": "Select", "lvl2": "Sizes", "lvl3": "Colors" } }, { "content": "Variants", - "objectID": "14d16ae1-6eb9-49cf-8652-9d8859ef39b9", + "objectID": "302deef0-258b-42ab-a1b7-67d1c1aa8b83", "type": "lvl3", "url": "/docs/components/select#variants", "hierarchy": { "lvl1": "Select", "lvl2": "Colors", "lvl3": "Variants" } }, { "content": "Radius", - "objectID": "01cfba10-98f2-4a82-9dec-d9ec3f1d67cc", + "objectID": "3657e491-11f5-42d0-9936-a4ba31daa74b", "type": "lvl3", "url": "/docs/components/select#radius", "hierarchy": { "lvl1": "Select", "lvl2": "Variants", "lvl3": "Radius" } }, { "content": "Label Placements", - "objectID": "92e8b2b9-b2b4-4e86-a522-62634b89766d", + "objectID": "d3f4e095-c056-4aee-a015-c79fa972cc59", "type": "lvl3", "url": "/docs/components/select#label-placements", "hierarchy": { @@ -4808,7 +6543,7 @@ }, { "content": "Start Content", - "objectID": "1a41c291-3fe5-4b94-86e2-913448c42fd9", + "objectID": "7642a28d-99ea-41d6-8b3b-848b2c6e20bd", "type": "lvl3", "url": "/docs/components/select#start-content", "hierarchy": { @@ -4819,7 +6554,7 @@ }, { "content": "Item Start & End Content", - "objectID": "74824901-2345-45c7-ab6a-fe591a7d56c4", + "objectID": "85ea50e4-cc71-4669-95f8-bf42217d9ed9", "type": "lvl3", "url": "/docs/components/select#item-start--end-content", "hierarchy": { @@ -4830,7 +6565,7 @@ }, { "content": "Custom Selector Icon", - "objectID": "9806ecd9-6e15-43fe-827b-bf8b7de4c7cb", + "objectID": "553fb2eb-f714-411f-9a56-4fc185342e1e", "type": "lvl3", "url": "/docs/components/select#custom-selector-icon", "hierarchy": { @@ -4841,7 +6576,7 @@ }, { "content": "Without Scroll Shadow", - "objectID": "3d4d390b-2e09-4741-82f5-c3efb4d099cc", + "objectID": "9faecd41-302b-45c9-91b8-11d0f2cf6f43", "type": "lvl3", "url": "/docs/components/select#without-scroll-shadow", "hierarchy": { @@ -4852,7 +6587,7 @@ }, { "content": "With Description", - "objectID": "7f266319-b2d0-4f4f-aa77-0cd4cfa03b02", + "objectID": "ddeebb05-48f1-4954-a90e-669851c934c2", "type": "lvl3", "url": "/docs/components/select#with-description", "hierarchy": { @@ -4863,7 +6598,7 @@ }, { "content": "With Error Message", - "objectID": "9c0e9b97-c6ce-4a33-a01f-5fc021408a7a", + "objectID": "99cdfb7f-105f-46cf-99f2-68520719989b", "type": "lvl3", "url": "/docs/components/select#with-error-message", "hierarchy": { @@ -4874,7 +6609,7 @@ }, { "content": "Controlled", - "objectID": "6063e979-2931-45f8-8268-6de2045a485e", + "objectID": "595a2a38-27af-414b-b29b-b242c9d0adca", "type": "lvl3", "url": "/docs/components/select#controlled", "hierarchy": { @@ -4885,7 +6620,7 @@ }, { "content": "Controlling the open state", - "objectID": "5af38747-d62f-4e23-b323-fd884bf0b028", + "objectID": "72287d33-431e-4edc-b272-0149f02de871", "type": "lvl3", "url": "/docs/components/select#controlling-the-open-state", "hierarchy": { @@ -4896,7 +6631,7 @@ }, { "content": "Custom Items", - "objectID": "8d2151ef-204d-48db-8565-c02883b3960e", + "objectID": "bce334e0-f04d-417a-b142-015a86d8afb4", "type": "lvl3", "url": "/docs/components/select#custom-items", "hierarchy": { @@ -4907,7 +6642,7 @@ }, { "content": "Custom Render Value", - "objectID": "287647f5-117a-43ac-82e9-de6860710d63", + "objectID": "4ab8edf8-1142-4ff9-ab9b-c8b38f9a5e7d", "type": "lvl3", "url": "/docs/components/select#custom-render-value", "hierarchy": { @@ -4918,7 +6653,7 @@ }, { "content": "Asynchronous Loading", - "objectID": "85093b86-9fb6-4d84-a8c3-b6f354aa80ba", + "objectID": "b91f42d6-1b21-43db-ab4a-786431cf6ef1", "type": "lvl3", "url": "/docs/components/select#asynchronous-loading", "hierarchy": { @@ -4929,7 +6664,7 @@ }, { "content": "With Sections", - "objectID": "0c883adb-0d73-4d2a-a30e-c1ac72e0bc59", + "objectID": "1e349d6f-6a3d-4c4b-9eb7-32f114c71a01", "type": "lvl3", "url": "/docs/components/select#with-sections", "hierarchy": { @@ -4940,7 +6675,7 @@ }, { "content": "Custom Sections Style", - "objectID": "1a584d15-65df-4252-9bf7-f6113648138a", + "objectID": "3f41be36-8a11-45ac-95ba-f66de51afcab", "type": "lvl3", "url": "/docs/components/select#custom-sections-style", "hierarchy": { @@ -4951,7 +6686,7 @@ }, { "content": "Multiple Select Controlled", - "objectID": "56ededdb-dd24-4702-927b-e60b1bbd717a", + "objectID": "f220c717-0acc-4717-88bb-7b5e6b35a958", "type": "lvl3", "url": "/docs/components/select#multiple-select-controlled", "hierarchy": { @@ -4962,7 +6697,7 @@ }, { "content": "Multiple With Chips", - "objectID": "cba12364-c3c3-4d40-b63f-aec74ba62af2", + "objectID": "73b43178-7a05-4fe8-b093-f8e1cfd0a14b", "type": "lvl3", "url": "/docs/components/select#multiple-with-chips", "hierarchy": { @@ -4973,7 +6708,7 @@ }, { "content": "Customizing the select", - "objectID": "06b19c48-745c-474d-941f-a791e91c3104", + "objectID": "b0570b60-26d2-404c-9b65-6c4a508d4245", "type": "lvl3", "url": "/docs/components/select#customizing-the-select", "hierarchy": { @@ -4984,42 +6719,42 @@ }, { "content": "Slots", - "objectID": "12620d2f-6c1d-408e-87f4-f3ecd894d930", + "objectID": "b24a13ae-619a-4b5b-a503-f0c251d50426", "type": "lvl2", "url": "/docs/components/select#slots", "hierarchy": { "lvl1": "Select", "lvl2": "Slots", "lvl3": null } }, { "content": "Data Attributes", - "objectID": "be63e5b5-baef-48f4-84c6-c812fba4d2be", + "objectID": "b5036f9f-46e0-4f60-bc0a-80f4a4732eba", "type": "lvl2", "url": "/docs/components/select#data-attributes", "hierarchy": { "lvl1": "Select", "lvl2": "Data Attributes", "lvl3": null } }, { "content": "Accessibility", - "objectID": "b4813afa-3ca2-49bb-b11d-ef9207a73fea", + "objectID": "7069a68c-4af0-4c6c-89b1-2719ee526080", "type": "lvl2", "url": "/docs/components/select#accessibility", "hierarchy": { "lvl1": "Select", "lvl2": "Accessibility", "lvl3": null } }, { "content": "API", - "objectID": "ff344140-3cf0-42bc-b0be-9b5fc2b53ae2", + "objectID": "c7140990-b375-4bfd-8fc1-79ceabcb5dff", "type": "lvl2", "url": "/docs/components/select#api", "hierarchy": { "lvl1": "Select", "lvl2": "API", "lvl3": null } }, { "content": "Select Props", - "objectID": "d865fe72-66b7-470f-8533-a2557cde6a8b", + "objectID": "afd77683-5012-411c-a6d9-a81d1ce0bf2f", "type": "lvl3", "url": "/docs/components/select#select-props", "hierarchy": { "lvl1": "Select", "lvl2": "API", "lvl3": "Select Props" } }, { "content": "Select Events", - "objectID": "1285375b-3bed-4fec-acc1-3c36d1eb5a7e", + "objectID": "c1ee0904-3379-42d4-9d09-5973ccbb4777", "type": "lvl3", "url": "/docs/components/select#select-events", "hierarchy": { @@ -5030,7 +6765,7 @@ }, { "content": "SelectItem Props", - "objectID": "0e11c598-21ca-499c-9b77-441540699ec2", + "objectID": "29319f8d-b2ef-4528-8c12-1f948238779a", "type": "lvl3", "url": "/docs/components/select#selectitem-props", "hierarchy": { @@ -5041,7 +6776,7 @@ }, { "content": "SelectItem Events", - "objectID": "2e058be7-24f4-4745-acb4-0d06dbb5b4d0", + "objectID": "41952559-9c34-4728-8bc4-e35fbf5e8e64", "type": "lvl3", "url": "/docs/components/select#selectitem-events", "hierarchy": { @@ -5052,7 +6787,7 @@ }, { "content": "SelectSection Props", - "objectID": "424dcfc3-3cba-4165-941f-5b7ba6cbbf0a", + "objectID": "5de9e266-8efe-48d0-b1e7-ddfa89aac0a0", "type": "lvl3", "url": "/docs/components/select#selectsection-props", "hierarchy": { @@ -5063,7 +6798,7 @@ }, { "content": "Types", - "objectID": "49f0f10e-248c-420b-9bc3-c8234c81d8f7", + "objectID": "812e6951-b960-439f-8bed-efc4266f1d34", "type": "lvl3", "url": "/docs/components/select#types", "hierarchy": { @@ -5074,42 +6809,49 @@ }, { "content": "Render Value Function", - "objectID": "feb120b2-c4ef-475c-8389-e1fd125043a3", + "objectID": "4ebd6928-d685-49ad-9895-2f63ea5f591c", "type": "lvl4", "url": "/docs/components/select#render-value-function", "hierarchy": { "lvl1": "Select", "lvl2": "Types", "lvl3": null } }, { "content": "Skeleton", - "objectID": "b7b2c5c8-9714-4bc6-94e4-01fba11a3fac", + "objectID": "2caa6f4d-c368-40b2-b891-0be13e995fe5", "type": "lvl1", "url": "/docs/components/skeleton", "hierarchy": { "lvl1": "Skeleton" } }, + { + "content": "Installation", + "objectID": "13e74764-1828-41c4-b70f-05c6b0e0f45f", + "type": "lvl2", + "url": "/docs/components/skeleton#installation", + "hierarchy": { "lvl1": "Skeleton", "lvl2": "Installation", "lvl3": null } + }, { "content": "Import", - "objectID": "8028e6ce-fb2f-48e7-b75e-72de17efa0e8", + "objectID": "398635ad-bc3b-4a58-b2cf-33c058f140a7", "type": "lvl2", "url": "/docs/components/skeleton#import", "hierarchy": { "lvl1": "Skeleton", "lvl2": "Import", "lvl3": null } }, { "content": "Usage", - "objectID": "7e68d9e0-bd46-4a77-b570-d97ffc62d3bb", + "objectID": "3fd3a776-b9dd-4049-bd8f-8c9dc3c74854", "type": "lvl2", "url": "/docs/components/skeleton#usage", "hierarchy": { "lvl1": "Skeleton", "lvl2": "Usage", "lvl3": null } }, { "content": "Standalone", - "objectID": "6a77ca7b-b78d-4244-af29-375bcc536810", + "objectID": "048dd124-5beb-4670-8175-013db97f2271", "type": "lvl3", "url": "/docs/components/skeleton#standalone", "hierarchy": { "lvl1": "Skeleton", "lvl2": "Usage", "lvl3": "Standalone" } }, { "content": "Loaded State", - "objectID": "fd0c8e3b-1b9a-4e26-abe0-462d46aea4db", + "objectID": "dd6da424-7fd0-48b7-af00-96b070fffeb6", "type": "lvl3", "url": "/docs/components/skeleton#loaded-state", "hierarchy": { @@ -5120,84 +6862,91 @@ }, { "content": "Slots", - "objectID": "2993479e-6ac5-4a5d-97ce-90a59d0428c9", + "objectID": "20aee778-918a-4759-9345-56b40718359f", "type": "lvl2", "url": "/docs/components/skeleton#slots", "hierarchy": { "lvl1": "Skeleton", "lvl2": "Slots", "lvl3": null } }, { "content": "Data Attributes", - "objectID": "39e6d484-519f-472e-8ae2-3b2955d3b279", + "objectID": "d84ace43-6755-4914-8f72-f4f0ebff8be2", "type": "lvl2", "url": "/docs/components/skeleton#data-attributes", "hierarchy": { "lvl1": "Skeleton", "lvl2": "Data Attributes", "lvl3": null } }, { "content": "API", - "objectID": "7ef3c97a-2ac6-422b-ae05-18dec26faf15", + "objectID": "f59ca7c4-6dc4-447a-bd67-5daee2cda38b", "type": "lvl2", "url": "/docs/components/skeleton#api", "hierarchy": { "lvl1": "Skeleton", "lvl2": "API", "lvl3": null } }, { "content": "Skeleton Props", - "objectID": "4329ec9d-bd29-48fd-ac96-f869867196ee", + "objectID": "2fe62658-f403-4c20-a811-99a3a3df1fd2", "type": "lvl3", "url": "/docs/components/skeleton#skeleton-props", "hierarchy": { "lvl1": "Skeleton", "lvl2": "API", "lvl3": "Skeleton Props" } }, { "content": "Slider", - "objectID": "5b20728a-40d7-441b-abca-771e407afaf6", + "objectID": "735e9931-cee3-4283-8f13-a924f5246009", "type": "lvl1", "url": "/docs/components/slider", "hierarchy": { "lvl1": "Slider" } }, + { + "content": "Installation", + "objectID": "539757b9-b666-4092-a62d-4c584f5d1ad6", + "type": "lvl2", + "url": "/docs/components/slider#installation", + "hierarchy": { "lvl1": "Slider", "lvl2": "Installation", "lvl3": null } + }, { "content": "Import", - "objectID": "26fe1808-f690-4a9c-b118-18d4bb37b35e", + "objectID": "f360b5b6-3994-42dc-96ee-0f70c97114ae", "type": "lvl2", "url": "/docs/components/slider#import", "hierarchy": { "lvl1": "Slider", "lvl2": "Import", "lvl3": null } }, { "content": "Usage", - "objectID": "e0057ae7-2550-4a23-bf43-e1694f9c06d3", + "objectID": "08da30f3-2080-476e-a8bf-909f949a3a93", "type": "lvl2", "url": "/docs/components/slider#usage", "hierarchy": { "lvl1": "Slider", "lvl2": "Usage", "lvl3": null } }, { "content": "Disabled", - "objectID": "14bd5f1d-e070-41c5-aabb-e052d2d5bd4e", + "objectID": "08b2ba2f-fc35-408a-a56c-dd0de9127f8b", "type": "lvl3", "url": "/docs/components/slider#disabled", "hierarchy": { "lvl1": "Slider", "lvl2": "Usage", "lvl3": "Disabled" } }, { "content": "Sizes", - "objectID": "46745639-7f60-4933-b3b6-e8986272f371", + "objectID": "7731d2a7-c1d9-4a90-8318-ce3f1daa8099", "type": "lvl3", "url": "/docs/components/slider#sizes", "hierarchy": { "lvl1": "Slider", "lvl2": "Disabled", "lvl3": "Sizes" } }, { "content": "Radius", - "objectID": "3b5af1ab-9616-45fa-ab71-a2a2636860de", + "objectID": "8bebab13-de32-4386-89d0-19ca952d2bf1", "type": "lvl3", "url": "/docs/components/slider#radius", "hierarchy": { "lvl1": "Slider", "lvl2": "Sizes", "lvl3": "Radius" } }, { "content": "Colors", - "objectID": "7bcd04f4-28a9-441d-b9a7-c35a90a0e934", + "objectID": "287f7004-0d5a-4c8f-8ec6-6e4a2ed6858b", "type": "lvl3", "url": "/docs/components/slider#colors", "hierarchy": { "lvl1": "Slider", "lvl2": "Radius", "lvl3": "Colors" } }, { "content": "Vertical Slider", - "objectID": "1f4f6ed0-4cdc-4c76-8d9d-329260796f40", + "objectID": "3f0c4151-0417-4456-88f5-87a2cb28afa5", "type": "lvl3", "url": "/docs/components/slider#vertical-slider", "hierarchy": { @@ -5208,7 +6957,7 @@ }, { "content": "With Visible Steps", - "objectID": "08c93902-7bb3-45aa-9524-c0f0be752fc6", + "objectID": "54408376-0623-4ec2-8faa-222eb4c3244a", "type": "lvl3", "url": "/docs/components/slider#with-visible-steps", "hierarchy": { @@ -5219,7 +6968,7 @@ }, { "content": "With Marks", - "objectID": "9d443ed8-bb8e-4824-b151-66aa056d406f", + "objectID": "e654cff0-5e22-4e54-b0b4-6b3dae57d7d7", "type": "lvl3", "url": "/docs/components/slider#with-marks", "hierarchy": { @@ -5230,7 +6979,7 @@ }, { "content": "Range Slider", - "objectID": "975045b9-1bc0-4209-92af-bdec0ac0be3e", + "objectID": "3065a8a9-1ed1-45c5-8079-27d8dea4f4fc", "type": "lvl3", "url": "/docs/components/slider#range-slider", "hierarchy": { @@ -5241,7 +6990,7 @@ }, { "content": "Fill Offset", - "objectID": "2d6830db-70a8-4028-b71d-94c2bb768f40", + "objectID": "86809b15-3fd5-42cb-96d3-d81ce0016562", "type": "lvl3", "url": "/docs/components/slider#fill-offset", "hierarchy": { @@ -5252,7 +7001,7 @@ }, { "content": "With Tooltip", - "objectID": "b6169fa0-f85c-4db3-9914-6e72db4adef1", + "objectID": "2f920936-a843-4859-b89e-386adc1c978e", "type": "lvl3", "url": "/docs/components/slider#with-tooltip", "hierarchy": { @@ -5263,7 +7012,7 @@ }, { "content": "With Outline", - "objectID": "92d83711-7850-4bcf-aaba-45b62192b1fa", + "objectID": "3b7e2d16-dfdf-4b46-9d73-0b3b638b1454", "type": "lvl3", "url": "/docs/components/slider#with-outline", "hierarchy": { @@ -5274,7 +7023,7 @@ }, { "content": "Start & End Content", - "objectID": "1f13342b-501a-4c31-bf29-be5011b7136c", + "objectID": "584ecc51-584b-44fd-8520-87d0cd8903a4", "type": "lvl3", "url": "/docs/components/slider#start--end-content", "hierarchy": { @@ -5285,7 +7034,7 @@ }, { "content": "Value Formatting", - "objectID": "4d9fce6d-ec0a-4842-b932-c35cf29db840", + "objectID": "0d2e3fd8-bc5b-4829-a026-4214bce5cd8c", "type": "lvl3", "url": "/docs/components/slider#value-formatting", "hierarchy": { @@ -5296,7 +7045,7 @@ }, { "content": "Hiding the Value", - "objectID": "c39e4e78-4e59-49b5-a574-41a8483e18d8", + "objectID": "937d4f04-1846-4079-bf11-f57e61e00fb1", "type": "lvl3", "url": "/docs/components/slider#hiding-the-value", "hierarchy": { @@ -5307,7 +7056,7 @@ }, { "content": "Hiding the Thumbs", - "objectID": "9563063e-95a4-4a0b-9d86-5e1aa046b2a7", + "objectID": "c957de7a-7550-4089-a42c-717282749aa4", "type": "lvl3", "url": "/docs/components/slider#hiding-the-thumbs", "hierarchy": { @@ -5318,7 +7067,7 @@ }, { "content": "Controlled", - "objectID": "ed09f23e-04e8-45d1-a820-a6c4fd4103e5", + "objectID": "0e5df990-022c-4968-8706-02d46df08c1e", "type": "lvl3", "url": "/docs/components/slider#controlled", "hierarchy": { @@ -5329,7 +7078,7 @@ }, { "content": "Controlled Range", - "objectID": "8eb076b8-175a-40c2-a311-332e8db83d49", + "objectID": "74bbf8fc-9351-4028-939e-cacff5a1ebe0", "type": "lvl3", "url": "/docs/components/slider#controlled-range", "hierarchy": { @@ -5340,7 +7089,7 @@ }, { "content": "Custom Thumb", - "objectID": "a67b65d4-9ef1-4aa5-8e50-2a98bfd004ff", + "objectID": "055a3f2b-720f-4b8e-b93f-345a12e5d956", "type": "lvl3", "url": "/docs/components/slider#custom-thumb", "hierarchy": { @@ -5351,7 +7100,7 @@ }, { "content": "Custom Range Thumbs", - "objectID": "0f0e2f5b-1686-4685-9164-e2226b879acf", + "objectID": "3ee56536-e99d-406c-92ef-732ac3030b28", "type": "lvl3", "url": "/docs/components/slider#custom-range-thumbs", "hierarchy": { @@ -5362,7 +7111,7 @@ }, { "content": "Custom Label", - "objectID": "81e820c1-1a2d-4288-8e93-a6a0d64912bd", + "objectID": "24ae56f3-3efd-428f-88ba-c002df3ea5ad", "type": "lvl3", "url": "/docs/components/slider#custom-label", "hierarchy": { @@ -5373,7 +7122,7 @@ }, { "content": "Custom Value", - "objectID": "6eeadc33-28f4-4c66-bb1b-e04a2ed37685", + "objectID": "fa8b1383-4616-419b-9852-0d54bd39a30f", "type": "lvl3", "url": "/docs/components/slider#custom-value", "hierarchy": { @@ -5384,7 +7133,7 @@ }, { "content": "Disabling Thumb Scale", - "objectID": "44a6402c-146c-4081-939e-23e97867c423", + "objectID": "ec04bcec-9fbc-4496-94f7-13cec660497d", "type": "lvl3", "url": "/docs/components/slider#disabling-thumb-scale", "hierarchy": { @@ -5395,49 +7144,49 @@ }, { "content": "Slots", - "objectID": "2acbf2ff-1c28-4af8-a9f2-51d5b842df07", + "objectID": "ead9ecc4-0d6a-41e0-8f9a-dece3449c38c", "type": "lvl2", "url": "/docs/components/slider#slots", "hierarchy": { "lvl1": "Slider", "lvl2": "Slots", "lvl3": null } }, { "content": "Custom Styles", - "objectID": "7a7ce287-648e-4daf-a7f6-900a5798dd85", + "objectID": "d2220cc6-0c42-4e3e-bd82-04fe8f1c419e", "type": "lvl3", "url": "/docs/components/slider#custom-styles", "hierarchy": { "lvl1": "Slider", "lvl2": "Slots", "lvl3": "Custom Styles" } }, { "content": "Data Attributes", - "objectID": "921b8448-7b0b-44e7-b1cd-35af8aba3902", + "objectID": "a0ce58d4-ecd4-4a1b-b8bb-f66ea8a39596", "type": "lvl2", "url": "/docs/components/slider#data-attributes", "hierarchy": { "lvl1": "Slider", "lvl2": "Data Attributes", "lvl3": null } }, { "content": "Accessibility", - "objectID": "3693e842-971f-4ef4-b2b4-2b9e456c363b", + "objectID": "4a2fae05-181e-4e8d-b9da-d4c8540f9ecc", "type": "lvl2", "url": "/docs/components/slider#accessibility", "hierarchy": { "lvl1": "Slider", "lvl2": "Accessibility", "lvl3": null } }, { "content": "API", - "objectID": "415a5c4d-0892-4ef8-80b7-d035ffb170e7", + "objectID": "b3d5b4b4-7b01-4550-9ec6-37664cd78bda", "type": "lvl2", "url": "/docs/components/slider#api", "hierarchy": { "lvl1": "Slider", "lvl2": "API", "lvl3": null } }, { "content": "Slider Props", - "objectID": "855afe7e-c6bb-49d1-a4e2-b2a42d5eed6e", + "objectID": "a64f19f3-74bb-4f08-b4aa-235ee68e35f9", "type": "lvl3", "url": "/docs/components/slider#slider-props", "hierarchy": { "lvl1": "Slider", "lvl2": "API", "lvl3": "Slider Props" } }, { "content": "Slider Functions", - "objectID": "33ba5af0-0f84-4055-a905-f470811f1e76", + "objectID": "73b9289d-93d7-4aa3-8529-93bb0aaa541c", "type": "lvl3", "url": "/docs/components/slider#slider-functions", "hierarchy": { @@ -5448,7 +7197,7 @@ }, { "content": "Slider Events", - "objectID": "4c78d57d-406f-4592-a8e0-477b60d826f4", + "objectID": "00e3a15c-8e61-4f54-a0c4-66acc2f36528", "type": "lvl3", "url": "/docs/components/slider#slider-events", "hierarchy": { @@ -5459,70 +7208,77 @@ }, { "content": "Types", - "objectID": "0c69ed47-5a2c-487f-addd-be96fce8bfb2", + "objectID": "4c3187ab-92b1-43e2-9179-ea9cc454f108", "type": "lvl3", "url": "/docs/components/slider#types", "hierarchy": { "lvl1": "Slider", "lvl2": "Slider Events", "lvl3": "Types" } }, { "content": "Slider Value", - "objectID": "78dc3b4b-8df7-4508-beaf-bb711c78155d", + "objectID": "4427a830-08b9-46e5-907f-da92ab356bf2", "type": "lvl4", "url": "/docs/components/slider#slider-value", "hierarchy": { "lvl1": "Slider", "lvl2": "Types", "lvl3": null } }, { "content": "Slider Step Marks", - "objectID": "afb86bb0-fc46-42cd-93c1-b86f0ef029ae", + "objectID": "6d8a132a-c100-4f0b-91fe-7cf737fcf1cf", "type": "lvl4", "url": "/docs/components/slider#slider-step-marks", "hierarchy": { "lvl1": "Slider", "lvl2": "Slider Value", "lvl3": null } }, { "content": "Snippet", - "objectID": "05430f79-03dc-484a-a777-aa52b51765cd", + "objectID": "dac683e2-3c3b-4d65-87b4-5ee32122ecbe", "type": "lvl1", "url": "/docs/components/snippet", "hierarchy": { "lvl1": "Snippet" } }, + { + "content": "Installation", + "objectID": "119664ef-0074-4400-8b0c-c7551ecad9b3", + "type": "lvl2", + "url": "/docs/components/snippet#installation", + "hierarchy": { "lvl1": "Snippet", "lvl2": "Installation", "lvl3": null } + }, { "content": "Import", - "objectID": "2a21126e-acb7-4cf8-a5d8-e046bd3b1c35", + "objectID": "a7c1a761-6023-4f9f-8117-dff183855e80", "type": "lvl2", "url": "/docs/components/snippet#import", "hierarchy": { "lvl1": "Snippet", "lvl2": "Import", "lvl3": null } }, { "content": "Usage", - "objectID": "9f0f9623-91c4-4882-b14b-ce9534cb4f96", + "objectID": "7158e21a-e4b1-4420-9697-a48400623acd", "type": "lvl2", "url": "/docs/components/snippet#usage", "hierarchy": { "lvl1": "Snippet", "lvl2": "Usage", "lvl3": null } }, { "content": "Sizes", - "objectID": "40f999d6-fd66-4c36-8950-4d565ddebd1d", + "objectID": "2fb82161-433e-4708-aa03-6d3597fcd94f", "type": "lvl3", "url": "/docs/components/snippet#sizes", "hierarchy": { "lvl1": "Snippet", "lvl2": "Usage", "lvl3": "Sizes" } }, { "content": "Colors", - "objectID": "bb0cae77-c1c7-467f-9fd7-df16923201dc", + "objectID": "fc9f2fda-c760-44f5-abe4-1ed8ca391b36", "type": "lvl3", "url": "/docs/components/snippet#colors", "hierarchy": { "lvl1": "Snippet", "lvl2": "Sizes", "lvl3": "Colors" } }, { "content": "Variants", - "objectID": "8ea8b396-44ea-48c6-8456-ab3ae183e962", + "objectID": "8d891111-bc60-4982-bf5a-f23a465485e4", "type": "lvl3", "url": "/docs/components/snippet#variants", "hierarchy": { "lvl1": "Snippet", "lvl2": "Colors", "lvl3": "Variants" } }, { "content": "Custom Symbol", - "objectID": "2f9fd828-8e47-49b7-b08d-ea957b0db1a1", + "objectID": "753fd420-97fe-46a1-b300-d204bc1498fc", "type": "lvl3", "url": "/docs/components/snippet#custom-symbol", "hierarchy": { @@ -5533,7 +7289,7 @@ }, { "content": "Without Copy", - "objectID": "4fa843d0-ba14-49dc-a284-e944946e7743", + "objectID": "3eb18fe7-9a43-4d74-8a0a-f25852edb83b", "type": "lvl3", "url": "/docs/components/snippet#without-copy", "hierarchy": { @@ -5544,7 +7300,7 @@ }, { "content": "Custom Tooltip", - "objectID": "7a853190-dad9-40ce-904a-72bacb105f3c", + "objectID": "6307e491-1c31-4ead-81a3-3fdaf1e1161a", "type": "lvl3", "url": "/docs/components/snippet#custom-tooltip", "hierarchy": { @@ -5555,7 +7311,7 @@ }, { "content": "Multiline", - "objectID": "fd773bf7-76aa-4177-9fa0-5b8c7fa8aa35", + "objectID": "02a16042-ece8-44e7-99a7-633ff3718594", "type": "lvl3", "url": "/docs/components/snippet#multiline", "hierarchy": { @@ -5566,7 +7322,7 @@ }, { "content": "Custom Icons", - "objectID": "fabea34a-5e88-4065-97cb-d0fc7a817904", + "objectID": "6a22e244-567e-48a3-b3e0-2915de3cd100", "type": "lvl3", "url": "/docs/components/snippet#custom-icons", "hierarchy": { @@ -5577,28 +7333,28 @@ }, { "content": "Slots", - "objectID": "16e0d531-cdfc-4291-b3b5-8ed870bbe7b6", + "objectID": "8c47312b-ffee-4bc7-8640-50d53774f8dc", "type": "lvl2", "url": "/docs/components/snippet#slots", "hierarchy": { "lvl1": "Snippet", "lvl2": "Slots", "lvl3": null } }, { "content": "API", - "objectID": "8903b26d-7ec0-4cc4-8961-0d234faf1a03", + "objectID": "f6782ab0-f3c6-4d0f-b423-e99834e196cc", "type": "lvl2", "url": "/docs/components/snippet#api", "hierarchy": { "lvl1": "Snippet", "lvl2": "API", "lvl3": null } }, { "content": "Snippet Props", - "objectID": "af420c5f-9334-4f56-bb78-9ec860de304d", + "objectID": "6f44e456-09ef-4942-9a47-da4bc964245d", "type": "lvl3", "url": "/docs/components/snippet#snippet-props", "hierarchy": { "lvl1": "Snippet", "lvl2": "API", "lvl3": "Snippet Props" } }, { "content": "Snippet Events", - "objectID": "00cd5c4c-f351-4362-b98a-1ae07d1a8b45", + "objectID": "65003c89-90e5-4ba1-8a15-1abbc546d04c", "type": "lvl3", "url": "/docs/components/snippet#snippet-events", "hierarchy": { @@ -5609,91 +7365,105 @@ }, { "content": "Spacer", - "objectID": "23c9a6b6-0881-4774-8563-dc2dbf7b936e", + "objectID": "b68cf98d-42fa-4481-9eb1-712e930e5b9f", "type": "lvl1", "url": "/docs/components/spacer", "hierarchy": { "lvl1": "Spacer" } }, + { + "content": "Installation", + "objectID": "541e6499-2fad-412d-971d-457cb50bc29f", + "type": "lvl2", + "url": "/docs/components/spacer#installation", + "hierarchy": { "lvl1": "Spacer", "lvl2": "Installation", "lvl3": null } + }, { "content": "Import", - "objectID": "b4f383fc-41b1-44b4-b10b-3e4c2286fc6c", + "objectID": "7868b391-9c29-49b4-97f7-1aa9e47aaf13", "type": "lvl2", "url": "/docs/components/spacer#import", "hierarchy": { "lvl1": "Spacer", "lvl2": "Import", "lvl3": null } }, { "content": "Usage", - "objectID": "a9b1a325-0f1a-4607-80e8-3a4beb05b1cf", + "objectID": "a35d6ac5-d82f-493f-83a6-d68357e548f0", "type": "lvl2", "url": "/docs/components/spacer#usage", "hierarchy": { "lvl1": "Spacer", "lvl2": "Usage", "lvl3": null } }, { "content": "API", - "objectID": "97f08ec9-ea73-46df-b546-c88bdcb2a140", + "objectID": "534f6f11-55ee-48dd-ab97-d4002092cba2", "type": "lvl2", "url": "/docs/components/spacer#api", "hierarchy": { "lvl1": "Spacer", "lvl2": "API", "lvl3": null } }, { "content": "Spacer Props", - "objectID": "e49367e5-0ed5-4d2e-b7ad-2debbe761e92", + "objectID": "0e8c2ab3-d790-45a4-bfb9-ce7a80194311", "type": "lvl3", "url": "/docs/components/spacer#spacer-props", "hierarchy": { "lvl1": "Spacer", "lvl2": "API", "lvl3": "Spacer Props" } }, { "content": "Spaces", - "objectID": "ca27f0ea-3d70-4fdd-823d-3a26e907874c", + "objectID": "6e61c939-7856-4a53-ba22-9cc52c58ac27", "type": "lvl3", "url": "/docs/components/spacer#spaces", "hierarchy": { "lvl1": "Spacer", "lvl2": "Spacer Props", "lvl3": "Spaces" } }, { "content": "Spinner", - "objectID": "4fb48b66-5f8a-40a1-81ee-fffc8411ed18", + "objectID": "d9ed8731-fdb0-4d87-8f75-d4a4d2a32578", "type": "lvl1", "url": "/docs/components/spinner", "hierarchy": { "lvl1": "Spinner" } }, + { + "content": "Installation", + "objectID": "cbfae7b4-cf80-46da-bd6c-5884e9ec3f6f", + "type": "lvl2", + "url": "/docs/components/spinner#installation", + "hierarchy": { "lvl1": "Spinner", "lvl2": "Installation", "lvl3": null } + }, { "content": "Import", - "objectID": "be2c1700-da47-417e-b22e-fe8d2aa3a7d8", + "objectID": "0e11adc4-84e1-4731-9c81-fca5f5d1f69f", "type": "lvl2", "url": "/docs/components/spinner#import", "hierarchy": { "lvl1": "Spinner", "lvl2": "Import", "lvl3": null } }, { "content": "Usage", - "objectID": "549fec53-6952-464c-be0d-be7177902b47", + "objectID": "ec5e023f-bb00-43d6-afad-88fc8bfd0109", "type": "lvl2", "url": "/docs/components/spinner#usage", "hierarchy": { "lvl1": "Spinner", "lvl2": "Usage", "lvl3": null } }, { "content": "Sizes", - "objectID": "41e0c931-5dbc-4ead-86be-6162636d7a80", + "objectID": "7af1ecf5-bac9-479d-a691-c3869218107f", "type": "lvl3", "url": "/docs/components/spinner#sizes", "hierarchy": { "lvl1": "Spinner", "lvl2": "Usage", "lvl3": "Sizes" } }, { "content": "Colors", - "objectID": "f53dcbec-aace-4bc9-8c95-d6c12f8a3a28", + "objectID": "2ea404a0-100d-4cd7-a20d-77728d821fab", "type": "lvl3", "url": "/docs/components/spinner#colors", "hierarchy": { "lvl1": "Spinner", "lvl2": "Sizes", "lvl3": "Colors" } }, { "content": "With Label", - "objectID": "4169122b-9da7-42e9-b322-0993ebd87e95", + "objectID": "ae7df134-7344-4701-8e40-0ce1857c3b85", "type": "lvl3", "url": "/docs/components/spinner#with-label", "hierarchy": { "lvl1": "Spinner", "lvl2": "Colors", "lvl3": "With Label" } }, { "content": "Label colors", - "objectID": "80a52af3-6a2e-4f05-8a5c-db05cb8dff4b", + "objectID": "91b8e3c0-5675-4580-a8a0-6cb40dbb27bc", "type": "lvl3", "url": "/docs/components/spinner#label-colors", "hierarchy": { @@ -5704,21 +7474,21 @@ }, { "content": "Slots", - "objectID": "016a37a1-1b61-490e-bee0-6a4692e2a699", + "objectID": "f564dcff-101e-410b-b1dc-f587c0f949b9", "type": "lvl2", "url": "/docs/components/spinner#slots", "hierarchy": { "lvl1": "Spinner", "lvl2": "Slots", "lvl3": null } }, { "content": "API", - "objectID": "a2bf18fb-15c5-4eaf-a144-f37e6b3179d3", + "objectID": "f8b87065-666e-45f6-aec0-ea44a3e02682", "type": "lvl2", "url": "/docs/components/spinner#api", "hierarchy": { "lvl1": "Spinner", "lvl2": "API", "lvl3": null } }, { "content": "Circular Progress Props", - "objectID": "51889ce1-eac8-49f4-8168-9dc1b973c123", + "objectID": "b0dc7f97-e9fd-4c79-8942-3b96836c5509", "type": "lvl3", "url": "/docs/components/spinner#circular-progress-props", "hierarchy": { @@ -5729,56 +7499,63 @@ }, { "content": "Switch", - "objectID": "3d984d6b-89bd-4718-9a70-bc34c2588e7a", + "objectID": "bd6aa00b-459e-41c6-ae92-52a14d8952c1", "type": "lvl1", "url": "/docs/components/switch", "hierarchy": { "lvl1": "Switch" } }, + { + "content": "Installation", + "objectID": "487e8d57-173d-4887-ae9f-2e4f305f54e0", + "type": "lvl2", + "url": "/docs/components/switch#installation", + "hierarchy": { "lvl1": "Switch", "lvl2": "Installation", "lvl3": null } + }, { "content": "Import", - "objectID": "0aaefda7-15a4-4376-b1b0-19f023c4227a", + "objectID": "40624e21-18b0-4258-85fc-736e1469b97b", "type": "lvl2", "url": "/docs/components/switch#import", "hierarchy": { "lvl1": "Switch", "lvl2": "Import", "lvl3": null } }, { "content": "Usage", - "objectID": "50bf78a0-6c92-413b-a0d5-2549dbae9cc7", + "objectID": "79c4c27a-aa16-4a1c-94f5-428e5645a14b", "type": "lvl2", "url": "/docs/components/switch#usage", "hierarchy": { "lvl1": "Switch", "lvl2": "Usage", "lvl3": null } }, { "content": "With Label", - "objectID": "abc47843-5872-4b0e-ae1a-677daff6357d", + "objectID": "051d34e0-a24a-48bb-8b3f-c4f6c3b490c8", "type": "lvl3", "url": "/docs/components/switch#with-label", "hierarchy": { "lvl1": "Switch", "lvl2": "Usage", "lvl3": "With Label" } }, { "content": "Disabled", - "objectID": "9fe6c72d-8355-4976-b611-4e80395ac172", + "objectID": "6ac3e626-85f3-45d7-9149-2a6d1c6b8835", "type": "lvl3", "url": "/docs/components/switch#disabled", "hierarchy": { "lvl1": "Switch", "lvl2": "With Label", "lvl3": "Disabled" } }, { "content": "Sizes", - "objectID": "b8dd25be-395a-45b3-b829-604cfded3935", + "objectID": "045d8a4c-80a4-4eab-bf8c-f6cab49db471", "type": "lvl3", "url": "/docs/components/switch#sizes", "hierarchy": { "lvl1": "Switch", "lvl2": "Disabled", "lvl3": "Sizes" } }, { "content": "Colors", - "objectID": "42d3eafd-a7d7-4cfb-ac20-f609a1175709", + "objectID": "68a285d8-3f6a-427b-8bed-1afa40fae081", "type": "lvl3", "url": "/docs/components/switch#colors", "hierarchy": { "lvl1": "Switch", "lvl2": "Sizes", "lvl3": "Colors" } }, { "content": "With Thumb Icon", - "objectID": "0d7d0edf-9b20-44b4-b043-3ee00870bdd6", + "objectID": "522e550e-23b8-4e8e-b0cb-016f9b9c8df6", "type": "lvl3", "url": "/docs/components/switch#with-thumb-icon", "hierarchy": { @@ -5789,7 +7566,7 @@ }, { "content": "With Icons", - "objectID": "445defda-5250-456f-a80c-a8c199a7261d", + "objectID": "18565276-269a-43b7-a4b4-f92a5c2fceeb", "type": "lvl3", "url": "/docs/components/switch#with-icons", "hierarchy": { @@ -5800,7 +7577,7 @@ }, { "content": "Controlled", - "objectID": "40c93e33-c806-46d7-996a-01b577d73935", + "objectID": "1caa6d71-7b6c-4c39-8eb2-a4aa79096f47", "type": "lvl3", "url": "/docs/components/switch#controlled", "hierarchy": { @@ -5811,21 +7588,21 @@ }, { "content": "Slots", - "objectID": "c598efbb-fdb9-493f-b5b2-680f3ba78a66", + "objectID": "37aa7968-3328-4c05-bac7-2835a9cd775b", "type": "lvl2", "url": "/docs/components/switch#slots", "hierarchy": { "lvl1": "Switch", "lvl2": "Slots", "lvl3": null } }, { "content": "Custom Styles", - "objectID": "6e437847-dc98-4cee-b9ab-e80c5d6cbb19", + "objectID": "f911d789-4396-4c9a-8bcd-3fb5abfab699", "type": "lvl3", "url": "/docs/components/switch#custom-styles", "hierarchy": { "lvl1": "Switch", "lvl2": "Slots", "lvl3": "Custom Styles" } }, { "content": "Custom Implementation", - "objectID": "75f2eb66-adfd-496f-8f18-3c63ac0e5f58", + "objectID": "c512e8c2-9059-40bd-b52b-7db4c4555d97", "type": "lvl3", "url": "/docs/components/switch#custom-implementation", "hierarchy": { @@ -5836,35 +7613,35 @@ }, { "content": "Data Attributes", - "objectID": "dde97e06-7222-4b41-a5a3-0d0601887495", + "objectID": "eb4a76c8-d719-4ab1-a5e8-8fe6c916beab", "type": "lvl2", "url": "/docs/components/switch#data-attributes", "hierarchy": { "lvl1": "Switch", "lvl2": "Data Attributes", "lvl3": null } }, { "content": "Accessibility", - "objectID": "6e012a08-f30b-4407-a1f0-bbda61e3031b", + "objectID": "7f600ce2-9cd7-4b69-afa8-5b5bedd6eafe", "type": "lvl2", "url": "/docs/components/switch#accessibility", "hierarchy": { "lvl1": "Switch", "lvl2": "Accessibility", "lvl3": null } }, { "content": "API", - "objectID": "0d8b3de2-de2f-41fb-a3ef-f1033dbe81fc", + "objectID": "b2faba5b-2331-4a63-ac81-13a2a23d26e8", "type": "lvl2", "url": "/docs/components/switch#api", "hierarchy": { "lvl1": "Switch", "lvl2": "API", "lvl3": null } }, { "content": "Switch Props", - "objectID": "eb3c6013-828a-4547-b94e-07ea3547338b", + "objectID": "15b2b060-cdf9-4acd-aff2-dce9b6c03736", "type": "lvl3", "url": "/docs/components/switch#switch-props", "hierarchy": { "lvl1": "Switch", "lvl2": "API", "lvl3": "Switch Props" } }, { "content": "Switch Events", - "objectID": "f87a1040-d976-41ba-8b87-3392a66e630d", + "objectID": "45e585a9-13e6-43f8-a570-c8fb52355075", "type": "lvl3", "url": "/docs/components/switch#switch-events", "hierarchy": { @@ -5875,56 +7652,63 @@ }, { "content": "Types", - "objectID": "d35fa2d7-531b-43cf-af22-0a4676a427e4", + "objectID": "ac5d9af6-7780-4201-80b4-7c0ec06b7046", "type": "lvl3", "url": "/docs/components/switch#types", "hierarchy": { "lvl1": "Switch", "lvl2": "Switch Events", "lvl3": "Types" } }, { "content": "Switch Icon Props", - "objectID": "068b0b9a-9dad-4a3b-9f7d-3c66b1924d4e", + "objectID": "f399c458-ea88-4ff8-a73b-851e59425f09", "type": "lvl4", "url": "/docs/components/switch#switch-icon-props", "hierarchy": { "lvl1": "Switch", "lvl2": "Types", "lvl3": null } }, { "content": "Table", - "objectID": "7670a394-3747-43b5-a99d-b7e31c49de71", + "objectID": "677dfb1a-0e6f-4f37-b893-6bee2283114d", "type": "lvl1", "url": "/docs/components/table", "hierarchy": { "lvl1": "Table" } }, + { + "content": "Installation", + "objectID": "8bad65b6-f4ae-4eee-acbf-36c5c719f6bb", + "type": "lvl2", + "url": "/docs/components/table#installation", + "hierarchy": { "lvl1": "Table", "lvl2": "Installation", "lvl3": null } + }, { "content": "Import", - "objectID": "85918cdf-23ab-4c54-a0d0-14ec9e55994f", + "objectID": "3cde986c-5c31-40e2-b20a-928819d89b52", "type": "lvl2", "url": "/docs/components/table#import", "hierarchy": { "lvl1": "Table", "lvl2": "Import", "lvl3": null } }, { "content": "Usage", - "objectID": "47be7643-23cb-470a-b034-f84965a3c126", + "objectID": "03d108cd-c800-4878-b2dc-4656d9512127", "type": "lvl2", "url": "/docs/components/table#usage", "hierarchy": { "lvl1": "Table", "lvl2": "Usage", "lvl3": null } }, { "content": "Dynamic", - "objectID": "a8f02b2c-5382-401c-80ff-f6ff2541c875", + "objectID": "b673db16-07f6-4aff-b883-5e21df9ef331", "type": "lvl3", "url": "/docs/components/table#dynamic", "hierarchy": { "lvl1": "Table", "lvl2": "Usage", "lvl3": "Dynamic" } }, { "content": "Why not array map?", - "objectID": "cbdf1f57-972f-4887-bb06-c16995ad5109", + "objectID": "d3a928c4-c333-4451-ac10-14f41a5c35b4", "type": "lvl4", "url": "/docs/components/table#why-not-array-map", "hierarchy": { "lvl1": "Table", "lvl2": "Dynamic", "lvl3": null } }, { "content": "Empty State", - "objectID": "d057570d-d5bc-48c3-acd7-ac87baa1f908", + "objectID": "177477da-5332-459c-af59-667e00bbd16e", "type": "lvl3", "url": "/docs/components/table#empty-state", "hierarchy": { @@ -5935,7 +7719,7 @@ }, { "content": "Without Header", - "objectID": "132da903-f55f-4840-894c-d9c7fa63a08f", + "objectID": "dc3bc215-732d-44df-a135-4558f04b4c52", "type": "lvl3", "url": "/docs/components/table#without-header", "hierarchy": { @@ -5946,7 +7730,7 @@ }, { "content": "Without Wrapper", - "objectID": "f3dae48f-218f-4fb2-a700-0fc790c3cdd0", + "objectID": "dc4d2b18-6b1e-44af-8aa9-549b593d1752", "type": "lvl3", "url": "/docs/components/table#without-wrapper", "hierarchy": { @@ -5957,7 +7741,7 @@ }, { "content": "Custom Cells", - "objectID": "313366e4-9a75-4d28-961e-2062d94a381f", + "objectID": "7b399c2d-ffe3-4944-9ac5-ad975f9efd6a", "type": "lvl3", "url": "/docs/components/table#custom-cells", "hierarchy": { @@ -5968,7 +7752,7 @@ }, { "content": "Striped Rows", - "objectID": "b1c4c0e5-f0e1-4f4d-98c0-0ae84a1fd15a", + "objectID": "ab4efe61-7320-4bcd-8853-ae33b50d93fb", "type": "lvl3", "url": "/docs/components/table#striped-rows", "hierarchy": { @@ -5979,7 +7763,7 @@ }, { "content": "Single Row Selection", - "objectID": "d1a1b2c7-c672-4263-9df3-877c881735f8", + "objectID": "54a470f4-0e16-4fa9-b41c-82ad577ff101", "type": "lvl3", "url": "/docs/components/table#single-row-selection", "hierarchy": { @@ -5990,7 +7774,7 @@ }, { "content": "Multiple Row Selection", - "objectID": "e0d92bd9-4e4a-49cc-9e13-0d744e4a582a", + "objectID": "e6671cb9-6e49-44bb-be87-c25a029e22ad", "type": "lvl3", "url": "/docs/components/table#multiple-row-selection", "hierarchy": { @@ -6001,7 +7785,7 @@ }, { "content": "Disallow Empty Selection", - "objectID": "514c03ad-e7b9-47b8-b567-593608bc286c", + "objectID": "67e59cb2-291b-491b-a369-ef5643045e41", "type": "lvl3", "url": "/docs/components/table#disallow-empty-selection", "hierarchy": { @@ -6012,7 +7796,7 @@ }, { "content": "Controlled Selection", - "objectID": "a4d30502-bba4-42d3-90c7-e301e41f1910", + "objectID": "4600bd88-4f77-44ce-876f-9bbe8855aa71", "type": "lvl3", "url": "/docs/components/table#controlled-selection", "hierarchy": { @@ -6023,7 +7807,7 @@ }, { "content": "Disabled Rows", - "objectID": "0bd536be-dcfb-40ef-b429-e5b2ca48cd01", + "objectID": "0142e36a-4690-480e-8e0f-132418823fef", "type": "lvl3", "url": "/docs/components/table#disabled-rows", "hierarchy": { @@ -6034,7 +7818,7 @@ }, { "content": "Selection Behavior", - "objectID": "259cf868-4e10-48fb-bafc-41681d954117", + "objectID": "a2195029-27ab-4854-a8ab-e8d605b89c48", "type": "lvl3", "url": "/docs/components/table#selection-behavior", "hierarchy": { @@ -6045,7 +7829,7 @@ }, { "content": "Rows Actions", - "objectID": "77897fb7-6f28-43d2-8b88-ffea33259c62", + "objectID": "c897d762-3644-4014-8832-320240dd3ffd", "type": "lvl3", "url": "/docs/components/table#rows-actions", "hierarchy": { @@ -6056,7 +7840,7 @@ }, { "content": "Sorting Rows", - "objectID": "86e8e485-7b3e-4142-9b50-f23076c2832b", + "objectID": "b444bdd5-a456-4349-8a47-af63a72f8169", "type": "lvl3", "url": "/docs/components/table#sorting-rows", "hierarchy": { @@ -6067,7 +7851,7 @@ }, { "content": "Loading more data", - "objectID": "fd78a353-0df7-4979-afec-5c7f7613d2c9", + "objectID": "39d0605e-120c-4b0b-832c-d03cddd10565", "type": "lvl3", "url": "/docs/components/table#loading-more-data", "hierarchy": { @@ -6078,7 +7862,7 @@ }, { "content": "Paginated Table", - "objectID": "e3e1e741-6258-4bc2-a7fc-1c02fbee33f6", + "objectID": "cc39617e-53cc-4659-bdfa-697c2ab2a875", "type": "lvl3", "url": "/docs/components/table#paginated-table", "hierarchy": { @@ -6089,7 +7873,7 @@ }, { "content": "Async Pagination", - "objectID": "6963084b-0caf-439f-8b17-e622ff2aaa9a", + "objectID": "f3a14d39-7037-44c4-8c2c-600027be8250", "type": "lvl3", "url": "/docs/components/table#async-pagination", "hierarchy": { @@ -6100,7 +7884,7 @@ }, { "content": "Infinite Pagination", - "objectID": "7e0c339f-6e0d-48b5-896f-891899f1a4a5", + "objectID": "4c4bb5b3-82c9-4586-8111-d9adcb36a9d0", "type": "lvl3", "url": "/docs/components/table#infinite-pagination", "hierarchy": { @@ -6111,7 +7895,7 @@ }, { "content": "Use Case Example", - "objectID": "ef6b761a-97ec-4fd7-b5e9-a966d7c3f776", + "objectID": "7b42af99-f367-4040-934a-f948c0063d03", "type": "lvl3", "url": "/docs/components/table#use-case-example", "hierarchy": { @@ -6122,49 +7906,49 @@ }, { "content": "Slots", - "objectID": "f9308a5b-127b-4e89-9e46-1adf744ebb0c", + "objectID": "9851726a-4e10-44e7-9b7f-8399ee8114b2", "type": "lvl2", "url": "/docs/components/table#slots", "hierarchy": { "lvl1": "Table", "lvl2": "Slots", "lvl3": null } }, { "content": "Custom Styles", - "objectID": "c6ae09c5-6764-4e4a-9461-c7288d1016d3", + "objectID": "4a13e875-17b4-4142-a742-495a4d5dfd69", "type": "lvl3", "url": "/docs/components/table#custom-styles", "hierarchy": { "lvl1": "Table", "lvl2": "Slots", "lvl3": "Custom Styles" } }, { "content": "Data Attributes", - "objectID": "ec34f5bd-5f98-4024-bba5-4d575d80682f", + "objectID": "e21dd8cf-e10f-4a4c-ac33-3db9cd72f3c9", "type": "lvl2", "url": "/docs/components/table#data-attributes", "hierarchy": { "lvl1": "Table", "lvl2": "Data Attributes", "lvl3": null } }, { "content": "Accessibility", - "objectID": "684cb92e-1512-477e-ab45-8404473d365d", + "objectID": "e2194e60-548a-424f-a8f2-0d8613dc3464", "type": "lvl2", "url": "/docs/components/table#accessibility", "hierarchy": { "lvl1": "Table", "lvl2": "Accessibility", "lvl3": null } }, { "content": "API", - "objectID": "414933fc-a7a4-4c7e-b239-389a1ca76680", + "objectID": "95dcdf77-01e8-4ff4-ae4d-3a66bdc32d97", "type": "lvl2", "url": "/docs/components/table#api", "hierarchy": { "lvl1": "Table", "lvl2": "API", "lvl3": null } }, { "content": "Table Props", - "objectID": "7f765527-c436-42b2-a2fd-f9c416a11599", + "objectID": "c9ea83db-9497-43ee-9dff-e51219610df9", "type": "lvl3", "url": "/docs/components/table#table-props", "hierarchy": { "lvl1": "Table", "lvl2": "API", "lvl3": "Table Props" } }, { "content": "Table Events", - "objectID": "a2ab5b0d-2468-4acb-af1c-1d945484805a", + "objectID": "8f2286b1-7088-4876-b323-a234a14da54d", "type": "lvl3", "url": "/docs/components/table#table-events", "hierarchy": { @@ -6175,28 +7959,28 @@ }, { "content": "TableHeader Props", - "objectID": "dd28806f-5b89-421d-8f64-c614e0edbd8e", + "objectID": "4f4c6374-ec27-4b61-830f-38dfe947018c", "type": "lvl4", "url": "/docs/components/table#tableheader-props", "hierarchy": { "lvl1": "Table", "lvl2": "Table Events", "lvl3": null } }, { "content": "TableColumn Props", - "objectID": "d0371f85-7743-4827-ba79-2409bd9955de", + "objectID": "d6abb840-0417-49f0-aa68-a07f38858b46", "type": "lvl4", "url": "/docs/components/table#tablecolumn-props", "hierarchy": { "lvl1": "Table", "lvl2": "TableHeader Props", "lvl3": null } }, { "content": "TableBody Props", - "objectID": "b2fd91b9-25f5-4cde-9493-cdb42fc5dacf", + "objectID": "1741203b-6c5c-4491-85df-9263e5666a63", "type": "lvl4", "url": "/docs/components/table#tablebody-props", "hierarchy": { "lvl1": "Table", "lvl2": "TableColumn Props", "lvl3": null } }, { "content": "TableBody Events", - "objectID": "1597c6be-5727-4e93-876b-ceec40c3dc1c", + "objectID": "1f68f3e1-91f7-4a5d-ad1c-7967cc450427", "type": "lvl3", "url": "/docs/components/table#tablebody-events", "hierarchy": { @@ -6207,21 +7991,21 @@ }, { "content": "TableRow Props", - "objectID": "2e827194-be75-4f2f-b4c7-eac72f989de7", + "objectID": "bbc75998-7beb-4474-80ed-24d166fb5cb3", "type": "lvl4", "url": "/docs/components/table#tablerow-props", "hierarchy": { "lvl1": "Table", "lvl2": "TableBody Events", "lvl3": null } }, { "content": "TableCell Props", - "objectID": "a216b7a9-dae0-4a1c-a7c0-ae77497047e2", + "objectID": "ebe48aef-c409-4cec-9744-20f7dacb8fe2", "type": "lvl4", "url": "/docs/components/table#tablecell-props", "hierarchy": { "lvl1": "Table", "lvl2": "TableRow Props", "lvl3": null } }, { "content": "Table types", - "objectID": "5997d007-eaaf-4c4f-9514-c463d2aae688", + "objectID": "7cfe40a2-18c5-41a4-9f3c-29258312dff6", "type": "lvl3", "url": "/docs/components/table#table-types", "hierarchy": { @@ -6232,259 +8016,288 @@ }, { "content": "Sort descriptor", - "objectID": "33be9c2c-a92a-495f-adf8-da72b101994c", + "objectID": "affe518e-b52f-4e7e-a007-8053200ccaa7", "type": "lvl4", "url": "/docs/components/table#sort-descriptor", "hierarchy": { "lvl1": "Table", "lvl2": "Table types", "lvl3": null } }, { "content": "Selection", - "objectID": "eafcc00a-f8c8-4f77-bb07-4e216ab63a6d", + "objectID": "db8bee89-4aeb-4e4d-8782-22676f41503f", "type": "lvl4", "url": "/docs/components/table#selection", "hierarchy": { "lvl1": "Table", "lvl2": "Sort descriptor", "lvl3": null } }, { "content": "Loading state", - "objectID": "082d837f-2f1d-414f-9cb1-3c49ef54a5ca", + "objectID": "ddac624c-d2bb-4998-8028-dc9ab05ec3fb", "type": "lvl4", "url": "/docs/components/table#loading-state", "hierarchy": { "lvl1": "Table", "lvl2": "Selection", "lvl3": null } }, { "content": "Tabs", - "objectID": "c18cc06e-edea-4b76-91ef-1c4601a7688d", + "objectID": "c7831eef-186b-45ac-990e-8d88ddb31898", "type": "lvl1", "url": "/docs/components/tabs", "hierarchy": { "lvl1": "Tabs" } }, + { + "content": "Installation", + "objectID": "fe090659-f85d-4769-8979-858c05bb2663", + "type": "lvl2", + "url": "/docs/components/tabs#installation", + "hierarchy": { "lvl1": "Tabs", "lvl2": "Installation", "lvl3": null } + }, { "content": "Import", - "objectID": "4cd64df5-d593-4c7f-9834-278ac8659780", + "objectID": "6bf070f6-2199-4fd2-950c-638b89d4b825", "type": "lvl2", "url": "/docs/components/tabs#import", "hierarchy": { "lvl1": "Tabs", "lvl2": "Import", "lvl3": null } }, { "content": "Usage", - "objectID": "33c2e02b-fb57-43e2-b396-329c24d7909f", + "objectID": "b9236751-c727-458b-b800-027f78401a77", "type": "lvl2", "url": "/docs/components/tabs#usage", "hierarchy": { "lvl1": "Tabs", "lvl2": "Usage", "lvl3": null } }, { "content": "Dynamic", - "objectID": "9243df8e-70f7-4249-9fce-cf31ad459031", + "objectID": "e90831e5-e014-4cb7-b7e6-d27d5ff4c2e7", "type": "lvl3", "url": "/docs/components/tabs#dynamic", "hierarchy": { "lvl1": "Tabs", "lvl2": "Usage", "lvl3": "Dynamic" } }, { "content": "Disabled", - "objectID": "fb4f17fa-de8c-4de5-a51e-653bf5d885fc", + "objectID": "f31956b3-1c59-496d-86c6-4553288ac62f", "type": "lvl3", "url": "/docs/components/tabs#disabled", "hierarchy": { "lvl1": "Tabs", "lvl2": "Dynamic", "lvl3": "Disabled" } }, { "content": "Disabled Item", - "objectID": "1f278415-f1f6-4254-aac0-5cf65d701b5d", + "objectID": "ad593f4f-0941-45f6-9332-679c1da51db1", "type": "lvl3", "url": "/docs/components/tabs#disabled-item", "hierarchy": { "lvl1": "Tabs", "lvl2": "Disabled", "lvl3": "Disabled Item" } }, { "content": "Sizes", - "objectID": "cdbd3bde-0466-4aa7-a206-5823320a1f38", + "objectID": "2b1f142a-7782-45b3-8749-cc5ca6f2ac64", "type": "lvl3", "url": "/docs/components/tabs#sizes", "hierarchy": { "lvl1": "Tabs", "lvl2": "Disabled Item", "lvl3": "Sizes" } }, { "content": "Radius", - "objectID": "a9db1e8b-f05e-4d5a-89e1-742535865c1d", + "objectID": "136c74c5-b00c-4d45-8072-539ec535fcca", "type": "lvl3", "url": "/docs/components/tabs#radius", "hierarchy": { "lvl1": "Tabs", "lvl2": "Sizes", "lvl3": "Radius" } }, { "content": "Colors", - "objectID": "f89e9bed-8779-4496-81bf-6887329a4313", + "objectID": "39c4838c-da9b-40da-85ae-380d75ed9646", "type": "lvl3", "url": "/docs/components/tabs#colors", "hierarchy": { "lvl1": "Tabs", "lvl2": "Radius", "lvl3": "Colors" } }, { "content": "Variants", - "objectID": "1846c6b0-9265-443b-bd10-29dbf6d4ae02", + "objectID": "e7b2abf9-2903-4f9e-9bc6-9cb193ed5494", "type": "lvl3", "url": "/docs/components/tabs#variants", "hierarchy": { "lvl1": "Tabs", "lvl2": "Colors", "lvl3": "Variants" } }, { "content": "With Icons", - "objectID": "2fd4326b-2d1e-4499-80b3-0ac173c0c6c4", + "objectID": "adb8ccaf-bfaf-44ed-9a27-6c1f83ebc5d4", "type": "lvl3", "url": "/docs/components/tabs#with-icons", "hierarchy": { "lvl1": "Tabs", "lvl2": "Variants", "lvl3": "With Icons" } }, { "content": "Controlled", - "objectID": "7d3cf9a8-c22b-4203-806c-cf0b8e36eb06", + "objectID": "5c176c2f-2cd4-42b9-9c7a-a5841e868678", "type": "lvl3", "url": "/docs/components/tabs#controlled", "hierarchy": { "lvl1": "Tabs", "lvl2": "With Icons", "lvl3": "Controlled" } }, { "content": "Links", - "objectID": "cf17abb3-4fd7-48bd-a1f7-af33279d1bd8", + "objectID": "b18bbc1d-b487-4ecd-a57c-a6387f661537", "type": "lvl3", "url": "/docs/components/tabs#links", "hierarchy": { "lvl1": "Tabs", "lvl2": "Controlled", "lvl3": "Links" } }, { "content": "Next.js", - "objectID": "d2653361-fa33-4a2b-8c38-5545b03be152", + "objectID": "4b15c58a-426f-4e7e-8ef4-811fb57f6cd8", "type": "lvl4", "url": "/docs/components/tabs#nextjs", "hierarchy": { "lvl1": "Tabs", "lvl2": "Links", "lvl3": null } }, { "content": "React Router", - "objectID": "565436ad-187f-4f83-944f-9c5eae5948f0", + "objectID": "3221f6d3-b72c-4fe1-ae5e-126fe2e8dac3", "type": "lvl4", "url": "/docs/components/tabs#react-router", "hierarchy": { "lvl1": "Tabs", "lvl2": "Next.js", "lvl3": null } }, { "content": "With Form", - "objectID": "f77c0a0f-3a0c-4fe5-a273-23e03a498b2c", + "objectID": "c54993e5-d773-4b9d-9fb3-c79d63ab9110", "type": "lvl3", "url": "/docs/components/tabs#with-form", "hierarchy": { "lvl1": "Tabs", "lvl2": "React Router", "lvl3": "With Form" } }, { "content": "Slots", - "objectID": "8f5ab661-9e03-4ccb-94d0-0bc637efb31b", + "objectID": "ec16fc3a-e678-44eb-8dc9-53f97dca362e", "type": "lvl2", "url": "/docs/components/tabs#slots", "hierarchy": { "lvl1": "Tabs", "lvl2": "Slots", "lvl3": null } }, { "content": "Custom Styles", - "objectID": "c02e48ef-7bbe-4b28-b79c-a01463a7c9f1", + "objectID": "e2c0efa0-42c6-42af-b392-ea64837abe7d", "type": "lvl3", "url": "/docs/components/tabs#custom-styles", "hierarchy": { "lvl1": "Tabs", "lvl2": "Slots", "lvl3": "Custom Styles" } }, { "content": "Data Attributes", - "objectID": "2f3949d1-c831-413c-8075-ee8910ca507d", + "objectID": "a99edbbf-5091-41cc-875f-86c57109ef27", "type": "lvl2", "url": "/docs/components/tabs#data-attributes", "hierarchy": { "lvl1": "Tabs", "lvl2": "Data Attributes", "lvl3": null } }, { "content": "Accessibility", - "objectID": "c639c427-51bb-4cda-afc8-7f7897ecec4d", + "objectID": "3353c418-e0e3-4ce8-8cf0-904645302e71", "type": "lvl2", "url": "/docs/components/tabs#accessibility", "hierarchy": { "lvl1": "Tabs", "lvl2": "Accessibility", "lvl3": null } }, { "content": "API", - "objectID": "3aa38a01-a117-40ff-a427-8d5ddac99b87", + "objectID": "b01a3abf-4c66-46b7-ac62-d628aedaacee", "type": "lvl2", "url": "/docs/components/tabs#api", "hierarchy": { "lvl1": "Tabs", "lvl2": "API", "lvl3": null } }, { "content": "Tabs Props", - "objectID": "fdbb2ecb-a14a-452f-ab1e-a06a5bb6f152", + "objectID": "ec96a70b-a562-41c8-97bc-6d6ef502594a", "type": "lvl3", "url": "/docs/components/tabs#tabs-props", "hierarchy": { "lvl1": "Tabs", "lvl2": "API", "lvl3": "Tabs Props" } }, { "content": "Tabs Events", - "objectID": "e4a70140-efb8-4d33-8b29-a86114d672a7", + "objectID": "86963df3-dab4-4558-9d14-0845a3f69229", "type": "lvl3", "url": "/docs/components/tabs#tabs-events", "hierarchy": { "lvl1": "Tabs", "lvl2": "Tabs Props", "lvl3": "Tabs Events" } }, { "content": "Tab Props", - "objectID": "ce85b289-6262-4aad-aadc-01816381e08e", + "objectID": "7c42e43d-1e8f-4ea2-9ce8-14abd2dd3db8", "type": "lvl3", "url": "/docs/components/tabs#tab-props", "hierarchy": { "lvl1": "Tabs", "lvl2": "Tabs Events", "lvl3": "Tab Props" } }, { "content": "Motion Props", - "objectID": "3b16c805-d52f-4dcb-8757-10f4bf9f41f7", + "objectID": "706541d9-6975-48e9-a506-11f45c339fa7", "type": "lvl4", "url": "/docs/components/tabs#motion-props", "hierarchy": { "lvl1": "Tabs", "lvl2": "Tab Props", "lvl3": null } }, { "content": "Textarea", - "objectID": "30f79401-0f77-427f-b3a4-2b851af62678", + "objectID": "98a4dacf-06de-4ba9-946d-9db57e07bf6c", "type": "lvl1", "url": "/docs/components/textarea", "hierarchy": { "lvl1": "Textarea" } }, + { + "content": "Installation", + "objectID": "8130f00f-108e-4d04-9fb2-cdc483ee736d", + "type": "lvl2", + "url": "/docs/components/textarea#installation", + "hierarchy": { "lvl1": "Textarea", "lvl2": "Installation", "lvl3": null } + }, { "content": "Import", - "objectID": "796e75ed-46b1-4d32-8c00-50488b5abc05", + "objectID": "44164e8c-cc40-4379-9e00-3c62ac125941", "type": "lvl2", "url": "/docs/components/textarea#import", "hierarchy": { "lvl1": "Textarea", "lvl2": "Import", "lvl3": null } }, { "content": "Usage", - "objectID": "ea1f9eed-be63-4947-bdfb-ba540dd9d7a1", + "objectID": "8b281b25-9c89-4a49-a91e-d33cb15229ae", "type": "lvl2", "url": "/docs/components/textarea#usage", "hierarchy": { "lvl1": "Textarea", "lvl2": "Usage", "lvl3": null } }, { "content": "Disabled", - "objectID": "8ecf9c7f-a176-475b-abcc-a0c8b3128a00", + "objectID": "3b20655a-322d-4f98-bd0d-33c6cd635d3f", "type": "lvl3", "url": "/docs/components/textarea#disabled", "hierarchy": { "lvl1": "Textarea", "lvl2": "Usage", "lvl3": "Disabled" } }, { "content": "Read Only", - "objectID": "6a577add-aad3-498d-8f29-64a179f6e64f", + "objectID": "63613fd7-0b60-414e-9c9b-f456aee5b030", "type": "lvl3", "url": "/docs/components/textarea#read-only", "hierarchy": { "lvl1": "Textarea", "lvl2": "Disabled", "lvl3": "Read Only" } }, { "content": "Required", - "objectID": "0f107894-a98f-42ba-b29d-5da382f3a758", + "objectID": "93ef8dc4-80d0-405c-9a45-e77c615f3994", "type": "lvl3", "url": "/docs/components/textarea#required", "hierarchy": { "lvl1": "Textarea", "lvl2": "Read Only", "lvl3": "Required" } }, { "content": "Autosize", - "objectID": "c70fe1d7-ef80-455b-a89b-e552d26e4e94", + "objectID": "e08a472a-a781-49e7-a3f1-4ba95c790df2", "type": "lvl3", "url": "/docs/components/textarea#autosize", "hierarchy": { "lvl1": "Textarea", "lvl2": "Required", "lvl3": "Autosize" } }, + { + "content": "Without Autosize", + "objectID": "b08664ec-8cc0-421a-8f1c-7cc3fd47e229", + "type": "lvl3", + "url": "/docs/components/textarea#without-autosize", + "hierarchy": { + "lvl1": "Textarea", + "lvl2": "Autosize", + "lvl3": "Without Autosize" + } + }, { "content": "Variants", - "objectID": "11abc31b-2316-4100-a8f5-66b93cd2bb99", + "objectID": "45aa9ecf-5e04-4004-980f-dc7d4ea6bab9", "type": "lvl3", "url": "/docs/components/textarea#variants", - "hierarchy": { "lvl1": "Textarea", "lvl2": "Autosize", "lvl3": "Variants" } + "hierarchy": { + "lvl1": "Textarea", + "lvl2": "Without Autosize", + "lvl3": "Variants" + } }, { "content": "With Error Message", - "objectID": "f2e3dcc3-7c53-4d94-807d-b7e27cc67496", + "objectID": "d04cbd67-524a-4ae1-8b00-76216a4282f5", "type": "lvl3", "url": "/docs/components/textarea#with-error-message", "hierarchy": { @@ -6495,7 +8308,7 @@ }, { "content": "Description", - "objectID": "131e972c-979c-4073-b887-ac37cef4a264", + "objectID": "1601b27a-9182-4cf7-ad64-0ec9f5bb6f00", "type": "lvl3", "url": "/docs/components/textarea#description", "hierarchy": { @@ -6506,7 +8319,7 @@ }, { "content": "Controlled", - "objectID": "7b4da62e-c499-4980-8d07-f6a382b8781d", + "objectID": "a8770db9-7854-4506-89bc-030840c3243f", "type": "lvl3", "url": "/docs/components/textarea#controlled", "hierarchy": { @@ -6517,42 +8330,42 @@ }, { "content": "Slots", - "objectID": "7525095c-77b0-4425-96da-c2add6c64f86", + "objectID": "213fc14f-5286-4c47-8b72-a3c92388a61a", "type": "lvl2", "url": "/docs/components/textarea#slots", "hierarchy": { "lvl1": "Textarea", "lvl2": "Slots", "lvl3": null } }, { "content": "Data Attributes", - "objectID": "c6352133-479f-4bcf-89e5-4c7cc6cd35c1", + "objectID": "3283ce2d-9197-4f5a-96dc-940833b87dc3", "type": "lvl2", "url": "/docs/components/textarea#data-attributes", "hierarchy": { "lvl1": "Textarea", "lvl2": "Data Attributes", "lvl3": null } }, { "content": "Accessibility", - "objectID": "38371431-118d-4fab-b470-9bccfb11fcfd", + "objectID": "c4e97734-414b-4579-b085-ee45d79bc284", "type": "lvl2", "url": "/docs/components/textarea#accessibility", "hierarchy": { "lvl1": "Textarea", "lvl2": "Accessibility", "lvl3": null } }, { "content": "API", - "objectID": "b06bb260-b741-4022-906a-ad74c79da01c", + "objectID": "726ef6f0-f48a-45b6-9aaf-88ba219e3ef4", "type": "lvl2", "url": "/docs/components/textarea#api", "hierarchy": { "lvl1": "Textarea", "lvl2": "API", "lvl3": null } }, { "content": "Textarea Props", - "objectID": "381e2319-cad0-4638-bb04-ac7a72e75745", + "objectID": "ca19fbb8-dd98-435d-acfe-a08946d5e801", "type": "lvl3", "url": "/docs/components/textarea#textarea-props", "hierarchy": { "lvl1": "Textarea", "lvl2": "API", "lvl3": "Textarea Props" } }, { "content": "Input Events", - "objectID": "872be997-f65c-470c-b415-23c8df998eb7", + "objectID": "3fc1cc36-f43e-4aaf-b265-6d28c720c1c4", "type": "lvl3", "url": "/docs/components/textarea#input-events", "hierarchy": { @@ -6561,65 +8374,326 @@ "lvl3": "Input Events" } }, + { + "content": "Time Input", + "objectID": "9be0ccb0-0cab-40a5-8b74-703635ca1782", + "type": "lvl1", + "url": "/docs/components/time-input", + "hierarchy": { "lvl1": "Time Input" } + }, + { + "content": "Installation", + "objectID": "4cc65423-714b-4978-ab48-fff8e754a33c", + "type": "lvl2", + "url": "/docs/components/time-input#installation", + "hierarchy": { "lvl1": "Time Input", "lvl2": "Installation", "lvl3": null } + }, + { + "content": "Import", + "objectID": "16d1f2e8-0e24-4643-a54c-5bce405a9d74", + "type": "lvl2", + "url": "/docs/components/time-input#import", + "hierarchy": { "lvl1": "Time Input", "lvl2": "Import", "lvl3": null } + }, + { + "content": "Usage", + "objectID": "d1d11cf4-04c3-483f-9bae-0c8c43b5cd7c", + "type": "lvl2", + "url": "/docs/components/time-input#usage", + "hierarchy": { "lvl1": "Time Input", "lvl2": "Usage", "lvl3": null } + }, + { + "content": "Required", + "objectID": "7aa62f52-182c-42a5-bf9b-d351f1723ef0", + "type": "lvl3", + "url": "/docs/components/time-input#required", + "hierarchy": { "lvl1": "Time Input", "lvl2": "Usage", "lvl3": "Required" } + }, + { + "content": "Disabled", + "objectID": "eb0361f8-d030-423c-9d75-3e48862bd0cb", + "type": "lvl3", + "url": "/docs/components/time-input#disabled", + "hierarchy": { + "lvl1": "Time Input", + "lvl2": "Required", + "lvl3": "Disabled" + } + }, + { + "content": "Read Only", + "objectID": "f0e56a21-aa8b-4361-bd51-76692ab7d9d8", + "type": "lvl3", + "url": "/docs/components/time-input#read-only", + "hierarchy": { + "lvl1": "Time Input", + "lvl2": "Disabled", + "lvl3": "Read Only" + } + }, + { + "content": "Without Label", + "objectID": "33cbbb13-90b5-4b84-8f6e-2afa807674ce", + "type": "lvl3", + "url": "/docs/components/time-input#without-label", + "hierarchy": { + "lvl1": "Time Input", + "lvl2": "Read Only", + "lvl3": "Without Label" + } + }, + { + "content": "With Description", + "objectID": "2c8a8854-b5a5-4518-aad1-264a003d0741", + "type": "lvl3", + "url": "/docs/components/time-input#with-description", + "hierarchy": { + "lvl1": "Time Input", + "lvl2": "Without Label", + "lvl3": "With Description" + } + }, + { + "content": "Label Placement", + "objectID": "1a210d76-67ca-4fb1-a749-4a95ca145638", + "type": "lvl3", + "url": "/docs/components/time-input#label-placement", + "hierarchy": { + "lvl1": "Time Input", + "lvl2": "With Description", + "lvl3": "Label Placement" + } + }, + { + "content": "Start Content", + "objectID": "284537ce-8693-44c5-828c-0d769be7faaf", + "type": "lvl3", + "url": "/docs/components/time-input#start-content", + "hierarchy": { + "lvl1": "Time Input", + "lvl2": "Label Placement", + "lvl3": "Start Content" + } + }, + { + "content": "End Content", + "objectID": "d1ca1a35-6110-44c6-ab47-7c034cfaf2e2", + "type": "lvl3", + "url": "/docs/components/time-input#end-content", + "hierarchy": { + "lvl1": "Time Input", + "lvl2": "Start Content", + "lvl3": "End Content" + } + }, + { + "content": "Controlled", + "objectID": "950c584f-02f3-4fc0-815a-087448dbc4cc", + "type": "lvl3", + "url": "/docs/components/time-input#controlled", + "hierarchy": { + "lvl1": "Time Input", + "lvl2": "End Content", + "lvl3": "Controlled" + } + }, + { + "content": "Time Zones", + "objectID": "85994211-8b05-46e7-b026-5065496065d0", + "type": "lvl3", + "url": "/docs/components/time-input#time-zones", + "hierarchy": { + "lvl1": "Time Input", + "lvl2": "Controlled", + "lvl3": "Time Zones" + } + }, + { + "content": "Granularity", + "objectID": "863cfdad-072d-4de3-a2d6-c96e8ee16c94", + "type": "lvl3", + "url": "/docs/components/time-input#granularity", + "hierarchy": { + "lvl1": "Time Input", + "lvl2": "Time Zones", + "lvl3": "Granularity" + } + }, + { + "content": "Min Time Value", + "objectID": "57dea82e-3511-4f8a-9b6d-1a632ecfdd07", + "type": "lvl3", + "url": "/docs/components/time-input#min-time-value", + "hierarchy": { + "lvl1": "Time Input", + "lvl2": "Granularity", + "lvl3": "Min Time Value" + } + }, + { + "content": "Max Time Value", + "objectID": "45cb5ac5-2b10-46ea-ac9e-916531880511", + "type": "lvl3", + "url": "/docs/components/time-input#max-time-value", + "hierarchy": { + "lvl1": "Time Input", + "lvl2": "Min Time Value", + "lvl3": "Max Time Value" + } + }, + { + "content": "Placeholder Value", + "objectID": "958a2d63-62c6-4763-b142-c43284b719a3", + "type": "lvl3", + "url": "/docs/components/time-input#placeholder-value", + "hierarchy": { + "lvl1": "Time Input", + "lvl2": "Max Time Value", + "lvl3": "Placeholder Value" + } + }, + { + "content": "Hide Time Zone", + "objectID": "d3d64481-0fd0-4184-bfce-7884f22efd7a", + "type": "lvl3", + "url": "/docs/components/time-input#hide-time-zone", + "hierarchy": { + "lvl1": "Time Input", + "lvl2": "Placeholder Value", + "lvl3": "Hide Time Zone" + } + }, + { + "content": "Hour Cycle", + "objectID": "7342c456-71db-43c2-852d-c19c32e08bb5", + "type": "lvl3", + "url": "/docs/components/time-input#hour-cycle", + "hierarchy": { + "lvl1": "Time Input", + "lvl2": "Hide Time Zone", + "lvl3": "Hour Cycle" + } + }, + { + "content": "Slots", + "objectID": "9bd422c4-7d31-461a-9b35-c83b4d3f877b", + "type": "lvl2", + "url": "/docs/components/time-input#slots", + "hierarchy": { "lvl1": "Time Input", "lvl2": "Slots", "lvl3": null } + }, + { + "content": "Data Attributes", + "objectID": "b3b8a3fa-f7e9-451b-bbc8-e98d17340f88", + "type": "lvl2", + "url": "/docs/components/time-input#data-attributes", + "hierarchy": { + "lvl1": "Time Input", + "lvl2": "Data Attributes", + "lvl3": null + } + }, + { + "content": "Accessibility", + "objectID": "7daccbce-b1e9-4356-b839-efcd1b025c6d", + "type": "lvl2", + "url": "/docs/components/time-input#accessibility", + "hierarchy": { "lvl1": "Time Input", "lvl2": "Accessibility", "lvl3": null } + }, + { + "content": "API", + "objectID": "ff12fd5b-839e-4495-b720-84d66f033991", + "type": "lvl2", + "url": "/docs/components/time-input#api", + "hierarchy": { "lvl1": "Time Input", "lvl2": "API", "lvl3": null } + }, + { + "content": "TimeInput Props", + "objectID": "4bedb2a6-3a39-4ab0-8534-0575eeffed01", + "type": "lvl3", + "url": "/docs/components/time-input#timeinput-props", + "hierarchy": { + "lvl1": "Time Input", + "lvl2": "API", + "lvl3": "TimeInput Props" + } + }, + { + "content": "TimeInput Events", + "objectID": "ad1d9a5b-2541-45ca-81c8-49640b2f042c", + "type": "lvl3", + "url": "/docs/components/time-input#timeinput-events", + "hierarchy": { + "lvl1": "Time Input", + "lvl2": "TimeInput Props", + "lvl3": "TimeInput Events" + } + }, { "content": "Tooltip", - "objectID": "e86e0121-fb2c-4cc9-899f-1264aac01140", + "objectID": "499d0bf5-039a-4a59-8ae3-00f06abfe79f", "type": "lvl1", "url": "/docs/components/tooltip", "hierarchy": { "lvl1": "Tooltip" } }, + { + "content": "Installation", + "objectID": "b67d408c-6736-440a-ab37-f320299d2eab", + "type": "lvl2", + "url": "/docs/components/tooltip#installation", + "hierarchy": { "lvl1": "Tooltip", "lvl2": "Installation", "lvl3": null } + }, { "content": "Import", - "objectID": "cedba5c3-a716-4aa0-a036-6a4153c62647", + "objectID": "c518c678-b176-4447-a2ff-3c8c516348a4", "type": "lvl2", "url": "/docs/components/tooltip#import", "hierarchy": { "lvl1": "Tooltip", "lvl2": "Import", "lvl3": null } }, { "content": "Usage", - "objectID": "d3509eac-afed-43a0-8d23-e94ea9cae3b5", + "objectID": "d780e922-8291-4d2c-9e9e-d89bffbdda6d", "type": "lvl2", "url": "/docs/components/tooltip#usage", "hierarchy": { "lvl1": "Tooltip", "lvl2": "Usage", "lvl3": null } }, { "content": "With Arrow", - "objectID": "461540c4-e059-4c87-b363-098e54f1568c", + "objectID": "99eb1012-9963-49c0-a2a0-f479689ac481", "type": "lvl3", "url": "/docs/components/tooltip#with-arrow", "hierarchy": { "lvl1": "Tooltip", "lvl2": "Usage", "lvl3": "With Arrow" } }, { "content": "Colors", - "objectID": "153f34d5-cd7b-4730-97fa-c11fa4c29fb5", + "objectID": "f9e90f62-a9ea-4ff8-a336-725a850de94a", "type": "lvl3", "url": "/docs/components/tooltip#colors", "hierarchy": { "lvl1": "Tooltip", "lvl2": "With Arrow", "lvl3": "Colors" } }, { "content": "Placements", - "objectID": "0832ebf7-15e4-4e35-8a38-f08b46b04d8e", + "objectID": "13bd8478-048f-4ee9-8ad0-491f32f64aec", "type": "lvl3", "url": "/docs/components/tooltip#placements", "hierarchy": { "lvl1": "Tooltip", "lvl2": "Colors", "lvl3": "Placements" } }, { "content": "Offset", - "objectID": "6fe0f204-2ebc-41eb-8b9b-22963fc6f64b", + "objectID": "c6021482-b1f8-4b6b-84f1-5dcd1eb60b3f", "type": "lvl3", "url": "/docs/components/tooltip#offset", "hierarchy": { "lvl1": "Tooltip", "lvl2": "Placements", "lvl3": "Offset" } }, { "content": "Controlled", - "objectID": "26fb5489-28a5-4536-b8d6-f6f8591c2b5f", + "objectID": "a2102014-2f0a-4d9f-8e92-5c570a6ae1dd", "type": "lvl3", "url": "/docs/components/tooltip#controlled", "hierarchy": { "lvl1": "Tooltip", "lvl2": "Offset", "lvl3": "Controlled" } }, { "content": "With Delay", - "objectID": "3b35a76d-f7f6-4295-afe3-1934151543e4", + "objectID": "4144f99b-2dd1-400f-bd94-3ef9090aa3ca", "type": "lvl3", "url": "/docs/components/tooltip#with-delay", "hierarchy": { @@ -6630,7 +8704,7 @@ }, { "content": "Custom Content", - "objectID": "3ea61c41-eedb-4eaa-8bae-8b930d2790ec", + "objectID": "668f13ab-677e-45c4-930f-442e376e9238", "type": "lvl3", "url": "/docs/components/tooltip#custom-content", "hierarchy": { @@ -6641,7 +8715,7 @@ }, { "content": "Custom Motion", - "objectID": "58f2735a-8d4b-49f3-919a-d89bd0bcb1ab", + "objectID": "db834566-cd7c-4545-97e7-75a77f541e1d", "type": "lvl3", "url": "/docs/components/tooltip#custom-motion", "hierarchy": { @@ -6652,49 +8726,49 @@ }, { "content": "Slots", - "objectID": "0869d567-e774-4922-815a-3f2f564c5c94", + "objectID": "064d5ab7-f30c-4a08-a273-497c6625bded", "type": "lvl2", "url": "/docs/components/tooltip#slots", "hierarchy": { "lvl1": "Tooltip", "lvl2": "Slots", "lvl3": null } }, { "content": "Custom Styles", - "objectID": "92f82224-9de6-49fa-8f94-32158e0ad6a6", + "objectID": "9a865fda-e4e4-4b4e-89b6-ecb6979ad415", "type": "lvl3", "url": "/docs/components/tooltip#custom-styles", "hierarchy": { "lvl1": "Tooltip", "lvl2": "Slots", "lvl3": "Custom Styles" } }, { "content": "Data Attributes", - "objectID": "f794d987-5fd8-408e-8ee4-dc960dcd8dc4", + "objectID": "e6092030-ea83-4ce1-b775-e746308a7346", "type": "lvl2", "url": "/docs/components/tooltip#data-attributes", "hierarchy": { "lvl1": "Tooltip", "lvl2": "Data Attributes", "lvl3": null } }, { "content": "Accessibility", - "objectID": "3859795e-3709-4f80-878a-e3afa94a8475", + "objectID": "5da6ac8b-4f90-45fd-8aa4-6a039cefa358", "type": "lvl2", "url": "/docs/components/tooltip#accessibility", "hierarchy": { "lvl1": "Tooltip", "lvl2": "Accessibility", "lvl3": null } }, { "content": "API", - "objectID": "bbeee95d-1df8-4ae0-acdf-c8b7781c0302", + "objectID": "4250a9b3-0edb-4ec3-86fb-d611657e0579", "type": "lvl2", "url": "/docs/components/tooltip#api", "hierarchy": { "lvl1": "Tooltip", "lvl2": "API", "lvl3": null } }, { "content": "Tooltip Props", - "objectID": "4dc84bfb-20e9-4200-b91c-3b010ec7a7ce", + "objectID": "997f1021-447e-4d0c-8323-a104efe20b68", "type": "lvl3", "url": "/docs/components/tooltip#tooltip-props", "hierarchy": { "lvl1": "Tooltip", "lvl2": "API", "lvl3": "Tooltip Props" } }, { "content": "Tooltip Events", - "objectID": "86e2a8d3-2423-4e1a-9728-52ebd25c8ebf", + "objectID": "a11f598f-8f83-4f1c-85be-36962223c7bc", "type": "lvl3", "url": "/docs/components/tooltip#tooltip-events", "hierarchy": { @@ -6705,7 +8779,7 @@ }, { "content": "Tooltip types", - "objectID": "f5ea9d7b-e94d-4f62-bfbd-8c8f32faa3f0", + "objectID": "cca125e8-376d-44e9-bd74-507dab0cc4ac", "type": "lvl3", "url": "/docs/components/tooltip#tooltip-types", "hierarchy": { @@ -6716,14 +8790,14 @@ }, { "content": "Tooltip Placement", - "objectID": "cc10a28c-2e7e-4b2c-a6a6-115e6424ca9a", + "objectID": "599e2fde-d937-4f50-a54c-4fc038467e48", "type": "lvl4", "url": "/docs/components/tooltip#tooltip-placement", "hierarchy": { "lvl1": "Tooltip", "lvl2": "Tooltip types", "lvl3": null } }, { "content": "Motion Props", - "objectID": "69e73018-a8d1-4a14-bc8b-34f3d487b625", + "objectID": "e76e8877-2532-491d-91be-c19b53027516", "type": "lvl4", "url": "/docs/components/tooltip#motion-props", "hierarchy": { @@ -6734,77 +8808,84 @@ }, { "content": "User", - "objectID": "d4f1b70d-8661-4375-8d6f-b0c03356d720", + "objectID": "13f95675-4fae-4d92-ab3a-904972996c11", "type": "lvl1", "url": "/docs/components/user", "hierarchy": { "lvl1": "User" } }, + { + "content": "Installation", + "objectID": "92344799-34ef-47ed-9102-492395be81f6", + "type": "lvl2", + "url": "/docs/components/user#installation", + "hierarchy": { "lvl1": "User", "lvl2": "Installation", "lvl3": null } + }, { "content": "Import", - "objectID": "5acb935a-8d91-4f3a-a0b1-105d5bc585b8", + "objectID": "6aa47e64-ac07-4ae1-b158-71d640fc5179", "type": "lvl2", "url": "/docs/components/user#import", "hierarchy": { "lvl1": "User", "lvl2": "Import", "lvl3": null } }, { "content": "Usage", - "objectID": "24a997e1-4114-42f0-b2a0-2c154d0d1a41", + "objectID": "117b9726-927e-49e7-b67b-15cc9348dd9e", "type": "lvl2", "url": "/docs/components/user#usage", "hierarchy": { "lvl1": "User", "lvl2": "Usage", "lvl3": null } }, { "content": "Link Description", - "objectID": "69fa8a07-a922-400a-b462-5bfcd3157f10", + "objectID": "b9a43dd4-05db-4f70-a2fb-09e1fcc6c957", "type": "lvl3", "url": "/docs/components/user#link-description", "hierarchy": { "lvl1": "User", "lvl2": "Usage", "lvl3": "Link Description" } }, { "content": "Slots", - "objectID": "f07ab22d-a072-40d3-b35e-1fe7cac64d02", + "objectID": "7f665614-0353-46e2-a8d8-bc426518a497", "type": "lvl2", "url": "/docs/components/user#slots", "hierarchy": { "lvl1": "User", "lvl2": "Slots", "lvl3": null } }, { "content": "Data Attributes", - "objectID": "a61f3698-982b-466f-ac72-808c0ad68bff", + "objectID": "1e710d5b-455c-421e-a8e7-f2f495168239", "type": "lvl2", "url": "/docs/components/user#data-attributes", "hierarchy": { "lvl1": "User", "lvl2": "Data Attributes", "lvl3": null } }, { "content": "API", - "objectID": "85af4ed5-ed07-4634-841e-094d4f80da3e", + "objectID": "b9cc8114-782b-492b-926b-00fe9b60a813", "type": "lvl2", "url": "/docs/components/user#api", "hierarchy": { "lvl1": "User", "lvl2": "API", "lvl3": null } }, { "content": "User Props", - "objectID": "9b73757e-ead7-4f95-bc18-fbb8042960b8", + "objectID": "9f6a5f46-f438-4526-8e59-6cda1b23ddf5", "type": "lvl3", "url": "/docs/components/user#user-props", "hierarchy": { "lvl1": "User", "lvl2": "API", "lvl3": "User Props" } }, { "content": "Colors", - "objectID": "70cf83c0-c960-43c0-ae3b-208f35fb9099", + "objectID": "6aee69dd-7924-4329-957d-072a6fc6d8de", "type": "lvl1", "url": "/docs/customization/colors", "hierarchy": { "lvl1": "Colors" } }, { "content": "Default Colors", - "objectID": "f42df785-c09f-4ce2-a6e5-4e69ff7464c9", + "objectID": "1f3b99a4-9c27-4e3d-abf9-6bfb42590fd5", "type": "lvl2", "url": "/docs/customization/colors#default-colors", "hierarchy": { "lvl1": "Colors", "lvl2": "Default Colors", "lvl3": null } }, { "content": "Common Colors", - "objectID": "ccdcd742-4b38-46db-8c89-006d69daa9df", + "objectID": "cb7b78ee-6ff2-4807-83eb-d8406e68c409", "type": "lvl3", "url": "/docs/customization/colors#common-colors", "hierarchy": { @@ -6815,7 +8896,7 @@ }, { "content": "Semantic Colors", - "objectID": "ee071bfb-3e38-4125-8527-017f8cdbffeb", + "objectID": "5941b37b-4bc4-49ac-a49c-66a642c5be92", "type": "lvl3", "url": "/docs/customization/colors#semantic-colors", "hierarchy": { @@ -6826,7 +8907,7 @@ }, { "content": "Using Semantic Colors", - "objectID": "d355335b-ee17-4149-8a06-4fc2a9ef8e52", + "objectID": "2e9d8080-91b0-44c3-bc54-45963c893ee8", "type": "lvl3", "url": "/docs/customization/colors#using-semantic-colors", "hierarchy": { @@ -6837,7 +8918,7 @@ }, { "content": "Javascript Variables", - "objectID": "d07eeb78-3d6d-4596-8963-db57e676b282", + "objectID": "d19bee01-91e1-49fe-9458-bbde92d0e483", "type": "lvl3", "url": "/docs/customization/colors#javascript-variables", "hierarchy": { @@ -6848,7 +8929,7 @@ }, { "content": "CSS Variables", - "objectID": "4abdbccf-0deb-415b-883b-b7888de6bc51", + "objectID": "7cdaad4b-dcc6-48a4-a96f-eb4119208837", "type": "lvl3", "url": "/docs/customization/colors#css-variables", "hierarchy": { @@ -6859,14 +8940,14 @@ }, { "content": "Create theme", - "objectID": "9c14c65f-d077-44f0-a1d2-166e7171b871", + "objectID": "2b640ba3-b0f3-40a8-bdf4-da50811c303d", "type": "lvl1", "url": "/docs/customization/create-theme", "hierarchy": { "lvl1": "Create theme" } }, { "content": "Add the new theme to the plugin", - "objectID": "7038355e-f6f3-461c-8e5d-bbb252ec1be7", + "objectID": "12ce54f5-71b4-440d-a7fb-bf7d0cc1f17e", "type": "lvl3", "url": "/docs/customization/create-theme#add-the-new-theme-to-the-plugin", "hierarchy": { @@ -6877,7 +8958,7 @@ }, { "content": "Apply the new theme", - "objectID": "23663776-d3c4-4f97-b92f-36f0f17fe6b7", + "objectID": "ea6e813f-17f3-4b98-8dc9-39640fd9607b", "type": "lvl3", "url": "/docs/customization/create-theme#apply-the-new-theme", "hierarchy": { @@ -6888,7 +8969,7 @@ }, { "content": "Use the new theme", - "objectID": "277f3929-f9a1-4e32-9b97-fdbc0f5e6dfd", + "objectID": "959c9332-e116-4bff-83d4-8784a7128aab", "type": "lvl3", "url": "/docs/customization/create-theme#use-the-new-theme", "hierarchy": { @@ -6899,14 +8980,14 @@ }, { "content": "Custom Variants", - "objectID": "aac1d03d-05d7-4c2f-a500-8615a5dcf25c", + "objectID": "e322422c-fb43-4b5f-a288-1d7e2a96e88a", "type": "lvl1", "url": "/docs/customization/custom-variants", "hierarchy": { "lvl1": "Custom Variants" } }, { "content": "Creating new variants for non-slots components", - "objectID": "6918e7d5-f636-4a8f-8425-7930019ab5b6", + "objectID": "363e5591-ec99-45f2-b630-07a86b4ed65d", "type": "lvl2", "url": "/docs/customization/custom-variants#creating-new-variants-for-non-slots-components", "hierarchy": { @@ -6917,7 +8998,7 @@ }, { "content": "Extend the original component variants", - "objectID": "14d83265-4948-475c-a6fc-e767b7749266", + "objectID": "cc75a155-9e69-4965-b7d4-61ab8b8b4eb8", "type": "lvl3", "url": "/docs/customization/custom-variants#extend-the-original-component-variants", "hierarchy": { @@ -6928,7 +9009,7 @@ }, { "content": "Use your custom component in your application", - "objectID": "4f76dfaa-67ba-424c-9dd4-f7125e39bd6d", + "objectID": "92e4eb3b-377d-482b-94a6-80e6cd8a2232", "type": "lvl3", "url": "/docs/customization/custom-variants#use-your-custom-component-in-your-application", "hierarchy": { @@ -6939,7 +9020,7 @@ }, { "content": "Creating new variants for slots components", - "objectID": "fae3edf3-63cb-4de4-a7c5-a6a8cca778d4", + "objectID": "e776fba9-0025-40b7-acbe-12fabc48b30b", "type": "lvl2", "url": "/docs/customization/custom-variants#creating-new-variants-for-slots-components", "hierarchy": { @@ -6950,7 +9031,7 @@ }, { "content": "Extend the original component variants", - "objectID": "48a60920-7f54-4746-b9e7-28fa5aa468c0", + "objectID": "fee47f3c-8a82-4062-9acc-76d3081e26df", "type": "lvl3", "url": "/docs/customization/custom-variants#extend-the-original-component-variants-1", "hierarchy": { @@ -6961,7 +9042,7 @@ }, { "content": "Use your custom component in your application", - "objectID": "4e43f3d0-6a67-4c91-bc6c-14fe08018657", + "objectID": "20a9cc4b-5451-40f5-974e-40d997d1d97c", "type": "lvl3", "url": "/docs/customization/custom-variants#use-your-custom-component-in-your-application-1", "hierarchy": { @@ -6972,7 +9053,7 @@ }, { "content": "Types", - "objectID": "aa25809f-b839-4cb3-83eb-06debb32744c", + "objectID": "a2af75e0-0304-4880-b345-1f672df72191", "type": "lvl3", "url": "/docs/customization/custom-variants#types", "hierarchy": { @@ -6983,7 +9064,7 @@ }, { "content": "Main Function", - "objectID": "f83dc4b7-409f-4b07-91d8-096f1e887504", + "objectID": "3e8ac366-ce36-4e0c-9354-6b7f44f8263f", "type": "lvl3", "url": "/docs/customization/custom-variants#main-function", "hierarchy": { @@ -6994,7 +9075,7 @@ }, { "content": "Options", - "objectID": "e06ab5a9-fb25-4622-9dbc-7d4211aefc25", + "objectID": "43aa0bf2-e173-44ee-bf4c-e81d68be347c", "type": "lvl3", "url": "/docs/customization/custom-variants#options", "hierarchy": { @@ -7005,7 +9086,7 @@ }, { "content": "Config", - "objectID": "bbd3e715-7a26-4297-8fb8-4b8cec6b1138", + "objectID": "3f6595c4-0b7e-4b63-8222-eca4c2fb488c", "type": "lvl3", "url": "/docs/customization/custom-variants#config", "hierarchy": { @@ -7016,14 +9097,14 @@ }, { "content": "Customize theme", - "objectID": "a25e4604-3b4e-45c7-9fb1-da5630b6425f", + "objectID": "4937fee8-a3e1-4a6f-bd5c-6c37e4f86fa1", "type": "lvl1", "url": "/docs/customization/customize-theme", "hierarchy": { "lvl1": "Customize theme" } }, { "content": "Customizing Layout", - "objectID": "83d80cbd-fdf2-40d3-bbc7-33ac63b46988", + "objectID": "ce60283a-93bb-423d-8964-cfe5c40ad8a1", "type": "lvl2", "url": "/docs/customization/customize-theme#customizing-layout", "hierarchy": { @@ -7034,7 +9115,7 @@ }, { "content": "Global Layout Customization", - "objectID": "4b1a5ec4-cf0a-4f61-96cf-f3cd730e28e1", + "objectID": "930e8116-8180-4c25-9a5d-25642a421a4f", "type": "lvl3", "url": "/docs/customization/customize-theme#global-layout-customization", "hierarchy": { @@ -7045,7 +9126,7 @@ }, { "content": "Customizing Colors", - "objectID": "1e1069e9-b796-4000-9488-4a1fa198f115", + "objectID": "937aa1e4-8bfd-48db-a5f1-dd9a4f0941f9", "type": "lvl3", "url": "/docs/customization/customize-theme#customizing-colors", "hierarchy": { @@ -7056,14 +9137,14 @@ }, { "content": "Dark mode", - "objectID": "ca42ba2d-727d-4bc8-b368-3d2bf074040b", + "objectID": "16e1c3c9-c767-42ab-bbb3-352c561c8edb", "type": "lvl1", "url": "/docs/customization/dark-mode", "hierarchy": { "lvl1": "Dark mode" } }, { "content": "Using next-themes", - "objectID": "49a64cd5-7fcb-429b-85af-980ee8679879", + "objectID": "96936e9c-8c8e-45b0-9ee2-69457ed7a99d", "type": "lvl2", "url": "/docs/customization/dark-mode#using-next-themes", "hierarchy": { @@ -7074,7 +9155,7 @@ }, { "content": "Next.js App Directory Setup", - "objectID": "407eaba7-b590-45d3-b122-34892a1cecef", + "objectID": "af94bb5c-1a3b-4948-a07f-a74d4a54dc79", "type": "lvl3", "url": "/docs/customization/dark-mode#nextjs-app-directory-setup", "hierarchy": { @@ -7085,7 +9166,7 @@ }, { "content": "Install next-themes", - "objectID": "7acd9dc2-de35-4c02-a4be-c4c74c2e7cb8", + "objectID": "56a1f640-2e49-4ea2-8c6e-9f8ab9843f13", "type": "lvl3", "url": "/docs/customization/dark-mode#install-next-themes", "hierarchy": { @@ -7096,7 +9177,7 @@ }, { "content": "Add next-themes provider", - "objectID": "adc95d62-0d2b-4f6a-978d-0e9ba73093a1", + "objectID": "3b734a59-5d37-4844-871b-f403b5d4dbce", "type": "lvl3", "url": "/docs/customization/dark-mode#add-next-themes-provider", "hierarchy": { @@ -7107,7 +9188,7 @@ }, { "content": "Add the theme switcher", - "objectID": "53d02fa5-a6e4-49ad-8ede-d0e0eb8ec131", + "objectID": "bf114fb2-75b1-4c84-8763-dfadb7a8bee2", "type": "lvl3", "url": "/docs/customization/dark-mode#add-the-theme-switcher", "hierarchy": { @@ -7118,7 +9199,7 @@ }, { "content": "Next.js Pages Directory Setup", - "objectID": "7f7081f4-1217-4426-92ae-12be82efd621", + "objectID": "3684a12c-84ed-4ce2-bb58-493da05ef238", "type": "lvl3", "url": "/docs/customization/dark-mode#nextjs-pages-directory-setup", "hierarchy": { @@ -7129,7 +9210,7 @@ }, { "content": "Install next-themes", - "objectID": "746894c5-7af2-4f04-a2cb-3b83db1d9522", + "objectID": "7920d68a-0dd3-4e81-86d5-4a0dd21ba66d", "type": "lvl3", "url": "/docs/customization/dark-mode#install-next-themes-1", "hierarchy": { @@ -7140,7 +9221,7 @@ }, { "content": "Add next-themes provider", - "objectID": "405331ac-153e-48b3-a05e-e9d282cc53b5", + "objectID": "1fc7fc0a-0370-42a5-a80e-7fef1619edcd", "type": "lvl3", "url": "/docs/customization/dark-mode#add-next-themes-provider-1", "hierarchy": { @@ -7151,7 +9232,7 @@ }, { "content": "Add the theme switcher", - "objectID": "366ed332-4bdb-4803-aded-dddf6b6b15ab", + "objectID": "23f17b56-efa3-47fe-a3fc-78d2032dd2a8", "type": "lvl3", "url": "/docs/customization/dark-mode#add-the-theme-switcher-1", "hierarchy": { @@ -7162,7 +9243,7 @@ }, { "content": "Using use-dark-mode hook", - "objectID": "4202e412-7647-4155-9f63-6b5b0eb2c0ba", + "objectID": "6b53af1a-bb13-4785-8951-dfc420515b93", "type": "lvl2", "url": "/docs/customization/dark-mode#using-use-dark-mode-hook", "hierarchy": { @@ -7173,7 +9254,7 @@ }, { "content": "Install use-dark-mode", - "objectID": "566f0872-06f0-489e-99b1-ab61632e6e4d", + "objectID": "ebd22023-3cbd-47de-8d65-17f558e78977", "type": "lvl3", "url": "/docs/customization/dark-mode#install-use-dark-mode", "hierarchy": { @@ -7184,7 +9265,7 @@ }, { "content": "Add the current theme to the main element", - "objectID": "d89069e0-e74a-4ef6-a434-e6c51b3aa355", + "objectID": "44d5c3a1-555c-47c2-837e-6fafacff79ee", "type": "lvl3", "url": "/docs/customization/dark-mode#add-the-current-theme-to-the-main-element", "hierarchy": { @@ -7195,7 +9276,7 @@ }, { "content": "Add the theme switcher", - "objectID": "c87fa969-b7d4-40c5-b26d-53407bf947ae", + "objectID": "9da03204-574b-4062-b9ff-8d33ea8f3e59", "type": "lvl3", "url": "/docs/customization/dark-mode#add-the-theme-switcher-2", "hierarchy": { @@ -7206,96 +9287,82 @@ }, { "content": "Layout", - "objectID": "b57db2f1-7a14-46c3-ae94-01469dab4a36", + "objectID": "f7e5d93a-f7d8-4e36-83d5-53a65936eef2", "type": "lvl1", "url": "/docs/customization/layout", "hierarchy": { "lvl1": "Layout" } }, { "content": "Default Layout", - "objectID": "77b51b8d-76ee-4ab2-876c-d8aa3d043914", + "objectID": "b02ca2e2-0a66-464c-8db2-37d9cbe54877", "type": "lvl2", "url": "/docs/customization/layout#default-layout", "hierarchy": { "lvl1": "Layout", "lvl2": "Default Layout", "lvl3": null } }, - { - "content": "Units", - "objectID": "eacf8902-d701-470b-aaa2-0c2b691200cd", - "type": "lvl2", - "url": "/docs/customization/layout#units", - "hierarchy": { "lvl1": "Layout", "lvl2": "Units", "lvl3": null } - }, - { - "content": "Using Units", - "objectID": "42cf030a-fa8d-4251-9262-64b7b01253b1", - "type": "lvl3", - "url": "/docs/customization/layout#using-units", - "hierarchy": { "lvl1": "Layout", "lvl2": "Units", "lvl3": "Using Units" } - }, { "content": "CSS Variables", - "objectID": "c4721bda-4205-4c32-957f-3795aaebe38d", + "objectID": "b0407691-0ae7-49c1-800a-ff471849b2ab", "type": "lvl3", "url": "/docs/customization/layout#css-variables", "hierarchy": { "lvl1": "Layout", - "lvl2": "Using Units", + "lvl2": "Default Layout", "lvl3": "CSS Variables" } }, { "content": "API Reference", - "objectID": "67fef8ba-e1de-4632-8c16-b5d1950e4467", + "objectID": "cd97d635-2208-48a4-8e12-038270ed2974", "type": "lvl4", "url": "/docs/customization/layout#api-reference", "hierarchy": { "lvl1": "Layout", "lvl2": "CSS Variables", "lvl3": null } }, { "content": "BaseThemeUnit", - "objectID": "f02efc1d-910d-4569-86c1-697b3a13e594", + "objectID": "96aceb7f-9485-4de5-b4ca-7cfb335e54be", "type": "lvl4", "url": "/docs/customization/layout#basethemeunit", "hierarchy": { "lvl1": "Layout", "lvl2": "API Reference", "lvl3": null } }, { "content": "FontThemeUnit", - "objectID": "32bd84c3-2df9-4dc5-8222-e05ac8cd4bcd", + "objectID": "dd5fe394-d6f0-4434-9b4f-9327e502328a", "type": "lvl4", "url": "/docs/customization/layout#fontthemeunit", "hierarchy": { "lvl1": "Layout", "lvl2": "BaseThemeUnit", "lvl3": null } }, { "content": "Override styles", - "objectID": "4ace9541-84af-4c92-8ecc-a52a4fc1ea7d", + "objectID": "240a18dc-cec9-4cd8-8a87-73498023587d", "type": "lvl1", "url": "/docs/customization/override-styles", "hierarchy": { "lvl1": "Override styles" } }, { - "content": "What's is a Slot?", - "objectID": "e6394430-e0d6-4129-8258-2ed788a20e1c", + "content": "What is a Slot?", + "objectID": "a9cd709e-0417-4eea-b835-6ae5181f42ec", "type": "lvl3", - "url": "/docs/customization/override-styles#whats-is-a-slot", + "url": "/docs/customization/override-styles#what-is-a-slot", "hierarchy": { "lvl1": "Override styles", "lvl2": "Override styles", - "lvl3": "What's is a Slot?" + "lvl3": "What is a Slot?" } }, { "content": "Overriding a component", - "objectID": "dbb4547f-609f-47f3-aed4-3946e24df8f4", + "objectID": "5604d628-fc4f-4942-8b28-da7cb0e0ca00", "type": "lvl3", "url": "/docs/customization/override-styles#overriding-a-component", "hierarchy": { "lvl1": "Override styles", - "lvl2": "What's is a Slot?", + "lvl2": "What is a Slot?", "lvl3": "Overriding a component" } }, { "content": "Components with slots", - "objectID": "e49081b7-792a-41b3-9523-8fb707fbe2c5", + "objectID": "a029a7bb-0c52-4053-b0d3-327df61005bd", "type": "lvl3", "url": "/docs/customization/override-styles#components-with-slots", "hierarchy": { @@ -7306,7 +9373,7 @@ }, { "content": "CSS Modules", - "objectID": "1c3fac12-ff90-46f5-8e72-dab113fc7e33", + "objectID": "0eca5ae4-541d-4772-b4e1-ae6187ffcd8b", "type": "lvl3", "url": "/docs/customization/override-styles#css-modules", "hierarchy": { @@ -7317,7 +9384,7 @@ }, { "content": "CSS-in-JS", - "objectID": "61c701ae-027a-45c9-9f29-56dd90bf67e7", + "objectID": "6fe5b8c2-e890-49b6-8894-fe16be8af73f", "type": "lvl3", "url": "/docs/customization/override-styles#css-in-js", "hierarchy": { @@ -7328,35 +9395,35 @@ }, { "content": "Theme", - "objectID": "6a0f836f-df81-4c6d-b211-f5533af8708f", + "objectID": "b8a872f3-e30d-410e-a858-230d883228d9", "type": "lvl1", "url": "/docs/customization/theme", "hierarchy": { "lvl1": "Theme" } }, { "content": "What is a Theme?", - "objectID": "a3cf7493-8c49-4883-a885-6540c1120562", + "objectID": "5946744e-74af-4303-8723-cc57fff64d89", "type": "lvl2", "url": "/docs/customization/theme#what-is-a-theme", "hierarchy": { "lvl1": "Theme", "lvl2": "What is a Theme?", "lvl3": null } }, { "content": "Setup", - "objectID": "9cf0fb25-4731-4b13-b089-1e8b3b399570", + "objectID": "4cff343b-39da-4781-9ec5-47a2d123c36b", "type": "lvl2", "url": "/docs/customization/theme#setup", "hierarchy": { "lvl1": "Theme", "lvl2": "Setup", "lvl3": null } }, { "content": "Usage", - "objectID": "15390a91-5e77-477f-9a12-14f3629fe61d", + "objectID": "be9bad0e-8350-4af3-b296-a9c7a8702f24", "type": "lvl3", "url": "/docs/customization/theme#usage", "hierarchy": { "lvl1": "Theme", "lvl2": "Setup", "lvl3": "Usage" } }, { "content": "Default Plugin Options", - "objectID": "827b40d5-0243-4c6c-aa5d-16f9b0a31bfc", + "objectID": "6c65e59d-a307-49b1-aa0c-318534ec2063", "type": "lvl3", "url": "/docs/customization/theme#default-plugin-options", "hierarchy": { @@ -7367,7 +9434,7 @@ }, { "content": "Themes Options", - "objectID": "42b7dc9e-3208-4e89-a004-9c11e614b7a1", + "objectID": "62099c7b-c164-4f98-8a8f-cf95b6ca2684", "type": "lvl3", "url": "/docs/customization/theme#themes-options", "hierarchy": { @@ -7378,7 +9445,7 @@ }, { "content": "Nested themes", - "objectID": "b6c4512e-5f29-4829-b4b8-e62027d20251", + "objectID": "0ad4bc3c-19b1-4fa0-a040-8e680e137785", "type": "lvl3", "url": "/docs/customization/theme#nested-themes", "hierarchy": { @@ -7389,7 +9456,7 @@ }, { "content": "Theme based variants", - "objectID": "0a583733-5d3e-4fda-8410-1130fa8f1a98", + "objectID": "fed97433-a16b-4c7a-8715-7a15adab9734", "type": "lvl3", "url": "/docs/customization/theme#theme-based-variants", "hierarchy": { @@ -7400,7 +9467,7 @@ }, { "content": "API Reference", - "objectID": "77be834d-04d9-4ef4-b25f-c4946a08c0ea", + "objectID": "ebeaeee6-4def-45b6-907d-1020897cf9cf", "type": "lvl3", "url": "/docs/customization/theme#api-reference", "hierarchy": { @@ -7411,60 +9478,71 @@ }, { "content": "Types", - "objectID": "fc303165-0624-4f42-9ae2-f9fcb5f50f2f", + "objectID": "2ce526c3-ebb3-4379-8278-ef1a0adcd0ec", "type": "lvl3", "url": "/docs/customization/theme#types", "hierarchy": { "lvl1": "Theme", "lvl2": "API Reference", "lvl3": "Types" } }, { "content": "ConfigThemes", - "objectID": "666c6082-9cd2-4cb5-b950-5f5d2cb74499", + "objectID": "53770714-fa82-4f4b-9b09-440f05fdc5da", "type": "lvl4", "url": "/docs/customization/theme#configthemes", "hierarchy": { "lvl1": "Theme", "lvl2": "Types", "lvl3": null } }, { "content": "LayoutTheme", - "objectID": "b31a1a42-5658-4529-9bfc-8e8c8e81b55d", + "objectID": "a17f4238-39f5-40b2-a537-54c7d147eaee", "type": "lvl4", "url": "/docs/customization/theme#layouttheme", "hierarchy": { "lvl1": "Theme", "lvl2": "ConfigThemes", "lvl3": null } }, { "content": "ThemeColors", - "objectID": "dc0deb98-5d16-4899-8f1a-007549182762", + "objectID": "e07a7eff-e295-4f2b-829f-d19d12344082", "type": "lvl4", "url": "/docs/customization/theme#themecolors", "hierarchy": { "lvl1": "Theme", "lvl2": "LayoutTheme", "lvl3": null } }, { "content": "Astro", - "objectID": "1841e69c-e448-4052-a831-644c0ebc0071", + "objectID": "dbcaa228-7276-4d9a-a76e-f1e1ba11f32d", "type": "lvl1", "url": "/docs/frameworks/astro", "hierarchy": { "lvl1": "Astro" } }, { - "content": "Installation", - "objectID": "4f625b5b-f6cf-4d1f-882c-bb13773a4748", + "content": "Install React", + "objectID": "54513975-4203-4050-acd0-6119ca83fe7a", + "type": "lvl3", + "url": "/docs/frameworks/astro#install-react", + "hierarchy": { "lvl1": "Astro", "lvl2": "Astro", "lvl3": "Install React" } + }, + { + "content": "Install NextUI", + "objectID": "7b5c3c91-945f-45cd-bd8c-99493101da76", "type": "lvl3", - "url": "/docs/frameworks/astro#installation", - "hierarchy": { "lvl1": "Astro", "lvl2": "Astro", "lvl3": "Installation" } + "url": "/docs/frameworks/astro#install-nextui", + "hierarchy": { + "lvl1": "Astro", + "lvl2": "Install React", + "lvl3": "Install NextUI" + } }, { "content": "Tailwind CSS Setup", - "objectID": "99fc8d5f-4ece-4285-a8af-48f029eb0c3b", + "objectID": "1038d3c1-80e9-4cd0-8eb2-3cfd91e51ea9", "type": "lvl3", "url": "/docs/frameworks/astro#tailwind-css-setup", "hierarchy": { "lvl1": "Astro", - "lvl2": "Installation", + "lvl2": "Install NextUI", "lvl3": "Tailwind CSS Setup" } }, { "content": "Usage", - "objectID": "d398050b-a7a3-4dd1-a332-7c4363b555cb", + "objectID": "83f1be6d-2072-49ee-b90e-8e146cdd170a", "type": "lvl3", "url": "/docs/frameworks/astro#usage", "hierarchy": { @@ -7475,7 +9553,7 @@ }, { "content": "Setup pnpm (optional)", - "objectID": "490b6121-d9fe-4699-839d-aab1cf5b52f8", + "objectID": "c169f150-8d79-4b2b-96ec-80ec050ab1c4", "type": "lvl3", "url": "/docs/frameworks/astro#setup-pnpm-optional", "hierarchy": { @@ -7486,14 +9564,14 @@ }, { "content": "Next.js", - "objectID": "a1e25827-a0b1-4f0d-ae61-5d295d304262", + "objectID": "371e7d07-9c56-40ad-8fd5-fd7ba215a1da", "type": "lvl1", "url": "/docs/frameworks/nextjs", "hierarchy": { "lvl1": "Next.js" } }, { "content": "App Directory Setup", - "objectID": "f6682fde-5b5b-41e5-aff7-ada9b8749b79", + "objectID": "d16d8e86-3cf5-42ef-8de2-e791d98797f1", "type": "lvl2", "url": "/docs/frameworks/nextjs#app-directory-setup", "hierarchy": { @@ -7504,7 +9582,7 @@ }, { "content": "create-next-app", - "objectID": "da458031-ad2c-4ca5-8851-8c9309c9271d", + "objectID": "e84c05fb-4e7d-4697-891c-8b3371ea88ff", "type": "lvl3", "url": "/docs/frameworks/nextjs#create-next-app", "hierarchy": { @@ -7515,7 +9593,7 @@ }, { "content": "Manual Installation", - "objectID": "372a146f-2e26-4f6e-b1d7-1b33ad3ccc56", + "objectID": "4a420b79-c568-47d0-a972-80bc0cc78854", "type": "lvl3", "url": "/docs/frameworks/nextjs#manual-installation", "hierarchy": { @@ -7526,7 +9604,7 @@ }, { "content": "Add dependencies", - "objectID": "1b420b24-714a-401d-a387-139331c3437f", + "objectID": "a7d0e05c-eb49-4200-b653-aa3018b4838d", "type": "lvl3", "url": "/docs/frameworks/nextjs#add-dependencies", "hierarchy": { @@ -7537,7 +9615,7 @@ }, { "content": "Tailwind CSS Setup", - "objectID": "9ec149f0-ac4d-44fe-a714-d1325b11cc23", + "objectID": "a40b5586-3782-488e-aff1-04dcf4dc6190", "type": "lvl3", "url": "/docs/frameworks/nextjs#tailwind-css-setup", "hierarchy": { @@ -7548,7 +9626,7 @@ }, { "content": "Setup Provider", - "objectID": "76f810db-7a3b-4d24-b043-10fd4b31506b", + "objectID": "b9f2cf98-0aa9-45e1-8a62-4fd5e9fe9735", "type": "lvl3", "url": "/docs/frameworks/nextjs#setup-provider", "hierarchy": { @@ -7559,7 +9637,7 @@ }, { "content": "Add Provider to Root", - "objectID": "ed84bd52-7ab4-4c20-a3dd-691179b2a73c", + "objectID": "39264186-b774-477a-b1be-e303b07b2096", "type": "lvl3", "url": "/docs/frameworks/nextjs#add-provider-to-root", "hierarchy": { @@ -7570,7 +9648,7 @@ }, { "content": "Use NextUI Components", - "objectID": "9ed24a2e-7a06-4105-9af6-300ce5e2c9b4", + "objectID": "ca1ff622-1dd4-4516-8e83-ddfbc53bf9b9", "type": "lvl3", "url": "/docs/frameworks/nextjs#use-nextui-components", "hierarchy": { @@ -7581,7 +9659,7 @@ }, { "content": "Setup pnpm (optional)", - "objectID": "4f5f7047-87a9-43df-922e-eac87a181dfc", + "objectID": "08353322-61bf-413f-9044-1b5e7c365513", "type": "lvl3", "url": "/docs/frameworks/nextjs#setup-pnpm-optional", "hierarchy": { @@ -7592,7 +9670,7 @@ }, { "content": "Pages Directory Setup", - "objectID": "c1d9f94d-b2bd-4c44-883b-14940dac813b", + "objectID": "c8fa1984-93ea-49ce-bd0b-d8f39bec3604", "type": "lvl2", "url": "/docs/frameworks/nextjs#pages-directory-setup", "hierarchy": { @@ -7603,7 +9681,7 @@ }, { "content": "create-next-app", - "objectID": "3d027e6f-d36e-4bce-a485-748fdaf98ecf", + "objectID": "86c706f7-6b43-4fea-95c9-ae62ce195083", "type": "lvl3", "url": "/docs/frameworks/nextjs#create-next-app-1", "hierarchy": { @@ -7614,7 +9692,7 @@ }, { "content": "Manual Installation", - "objectID": "91ec8894-2dca-497f-8ba0-d1576cc917d7", + "objectID": "97529e46-9904-4559-ac5a-530935e96ec6", "type": "lvl3", "url": "/docs/frameworks/nextjs#manual-installation-1", "hierarchy": { @@ -7625,7 +9703,7 @@ }, { "content": "Add dependencies", - "objectID": "715bc3e3-6761-45cf-9411-04921af83cc1", + "objectID": "df276926-d10f-460e-ab9f-6e0fcdb63ff7", "type": "lvl3", "url": "/docs/frameworks/nextjs#add-dependencies-1", "hierarchy": { @@ -7636,7 +9714,7 @@ }, { "content": "Tailwind CSS Setup", - "objectID": "25c96150-7c86-464f-9b44-8125b92ccb0b", + "objectID": "e32bc1df-bdc9-4515-aff4-d4351df17566", "type": "lvl3", "url": "/docs/frameworks/nextjs#tailwind-css-setup-1", "hierarchy": { @@ -7647,7 +9725,7 @@ }, { "content": "Setup Provider", - "objectID": "f8658bf3-fcc3-45e2-8752-cde7b6a5fc58", + "objectID": "3433e852-fd91-4138-a9a2-eb5521a09629", "type": "lvl3", "url": "/docs/frameworks/nextjs#setup-provider-1", "hierarchy": { @@ -7658,7 +9736,7 @@ }, { "content": "Use NextUI Components", - "objectID": "e8a271d3-be30-40d5-87c7-850a0a613b4e", + "objectID": "2ad9d04c-bbd3-45fc-8e13-6463b9af0ef2", "type": "lvl3", "url": "/docs/frameworks/nextjs#use-nextui-components-1", "hierarchy": { @@ -7669,7 +9747,7 @@ }, { "content": "Setup pnpm (optional)", - "objectID": "6f1b247f-2273-48e8-8448-d5a97df2976b", + "objectID": "83a70487-5be5-4bfc-bfca-0346d4a122e4", "type": "lvl3", "url": "/docs/frameworks/nextjs#setup-pnpm-optional-1", "hierarchy": { @@ -7680,21 +9758,21 @@ }, { "content": "Remix", - "objectID": "038cde06-b73e-494c-b4dc-68d392c59f0c", + "objectID": "d7de75fd-7f7d-4ab4-88a4-1d8e712e3361", "type": "lvl1", "url": "/docs/frameworks/remix", "hierarchy": { "lvl1": "Remix" } }, { "content": "Installation", - "objectID": "2a924143-ccf3-4777-ba53-6b610dca6e7f", + "objectID": "0a4e7007-2995-4f2b-8f9a-cfa9f21de847", "type": "lvl3", "url": "/docs/frameworks/remix#installation", "hierarchy": { "lvl1": "Remix", "lvl2": "Remix", "lvl3": "Installation" } }, { "content": "Tailwind CSS Setup", - "objectID": "8b9c137f-d3d3-4aca-adda-4064566e45b1", + "objectID": "5e273b40-0e69-46f7-bf32-70335c795c18", "type": "lvl3", "url": "/docs/frameworks/remix#tailwind-css-setup", "hierarchy": { @@ -7705,7 +9783,7 @@ }, { "content": "Provider Setup", - "objectID": "510e71be-628c-4b6c-b351-b9683ced6ca7", + "objectID": "7e88d907-0424-439b-b163-151d6d2970a3", "type": "lvl3", "url": "/docs/frameworks/remix#provider-setup", "hierarchy": { @@ -7716,7 +9794,7 @@ }, { "content": "Setup pnpm (optional)", - "objectID": "5f257611-0fd9-4a1e-a741-a6bf5b46fe2a", + "objectID": "f218e3b6-085a-4391-b9b0-32450cd1c3f1", "type": "lvl3", "url": "/docs/frameworks/remix#setup-pnpm-optional", "hierarchy": { @@ -7727,21 +9805,21 @@ }, { "content": "Vite", - "objectID": "52fff8bf-7513-4920-a0e8-1ecab1b38ebb", + "objectID": "229e501d-1c0b-4d62-be17-f30871492dd6", "type": "lvl1", "url": "/docs/frameworks/vite", "hierarchy": { "lvl1": "Vite" } }, { "content": "Installation", - "objectID": "51af17d2-97b4-4761-8562-f0782bf4eb66", + "objectID": "b970b86e-7443-4f42-834a-b8a5926249d3", "type": "lvl3", "url": "/docs/frameworks/vite#installation", "hierarchy": { "lvl1": "Vite", "lvl2": "Vite", "lvl3": "Installation" } }, { "content": "Tailwind CSS Setup", - "objectID": "c2a169a8-b8fd-4206-b378-3bedc2192e52", + "objectID": "3a18e35c-2c86-45f8-811c-d46a3dcdaf90", "type": "lvl3", "url": "/docs/frameworks/vite#tailwind-css-setup", "hierarchy": { @@ -7752,7 +9830,7 @@ }, { "content": "Provider Setup", - "objectID": "a4aa979f-a3e2-46fa-b2ec-90dc3470962a", + "objectID": "109d591d-0a36-4470-965a-90fb7842523a", "type": "lvl3", "url": "/docs/frameworks/vite#provider-setup", "hierarchy": { @@ -7763,7 +9841,7 @@ }, { "content": "Setup pnpm (optional)", - "objectID": "ff0d1c77-4159-41c8-8269-5e48dc5c212c", + "objectID": "4549e5b8-4f8d-4f5a-9f60-c31b089c90e8", "type": "lvl3", "url": "/docs/frameworks/vite#setup-pnpm-optional", "hierarchy": { @@ -7772,16 +9850,115 @@ "lvl3": "Setup pnpm (optional)" } }, + { + "content": "CLI", + "objectID": "ffa5982f-dc27-44b7-89dc-75b09f875227", + "type": "lvl1", + "url": "/docs/guide/cli", + "hierarchy": { "lvl1": "CLI" } + }, + { + "content": "Installation", + "objectID": "0416167b-56e1-4b28-825c-8a4dcaf0e0dc", + "type": "lvl2", + "url": "/docs/guide/cli#installation", + "hierarchy": { "lvl1": "CLI", "lvl2": "Installation", "lvl3": null } + }, + { + "content": "Global Installation", + "objectID": "8102d40d-48d2-4ee4-9787-4041b43952c3", + "type": "lvl3", + "url": "/docs/guide/cli#global-installation", + "hierarchy": { + "lvl1": "CLI", + "lvl2": "Installation", + "lvl3": "Global Installation" + } + }, + { + "content": "Without Installation", + "objectID": "b9d3adb4-ca78-4dda-b20b-75b9e8bf6c9e", + "type": "lvl3", + "url": "/docs/guide/cli#without-installation", + "hierarchy": { + "lvl1": "CLI", + "lvl2": "Global Installation", + "lvl3": "Without Installation" + } + }, + { + "content": "Quick Start", + "objectID": "124dc15e-4857-44df-9798-01c4698e3072", + "type": "lvl2", + "url": "/docs/guide/cli#quick-start", + "hierarchy": { "lvl1": "CLI", "lvl2": "Quick Start", "lvl3": null } + }, + { + "content": "init", + "objectID": "dd521705-4bbc-4796-8c20-9a73ee282445", + "type": "lvl2", + "url": "/docs/guide/cli#init", + "hierarchy": { "lvl1": "CLI", "lvl2": "init", "lvl3": null } + }, + { + "content": "add", + "objectID": "e744d82b-854a-4403-ab56-5af9514a5bc0", + "type": "lvl2", + "url": "/docs/guide/cli#add", + "hierarchy": { "lvl1": "CLI", "lvl2": "add", "lvl3": null } + }, + { + "content": "upgrade", + "objectID": "c3384948-7ac0-4e43-8f65-207b9b88b624", + "type": "lvl2", + "url": "/docs/guide/cli#upgrade", + "hierarchy": { "lvl1": "CLI", "lvl2": "upgrade", "lvl3": null } + }, + { + "content": "remove", + "objectID": "c1f931a4-565c-49e1-9941-f79b51e9fc3d", + "type": "lvl2", + "url": "/docs/guide/cli#remove", + "hierarchy": { "lvl1": "CLI", "lvl2": "remove", "lvl3": null } + }, + { + "content": "list", + "objectID": "39791e14-37ad-4d68-910c-4b60e56d6b66", + "type": "lvl2", + "url": "/docs/guide/cli#list", + "hierarchy": { "lvl1": "CLI", "lvl2": "list", "lvl3": null } + }, + { + "content": "doctor", + "objectID": "de6ef608-71d1-46a4-969a-0b67688db646", + "type": "lvl2", + "url": "/docs/guide/cli#doctor", + "hierarchy": { "lvl1": "CLI", "lvl2": "doctor", "lvl3": null } + }, + { + "content": "env", + "objectID": "d01d8cec-b3c2-49fc-a43b-5d31c7f3960e", + "type": "lvl2", + "url": "/docs/guide/cli#env", + "hierarchy": { "lvl1": "CLI", "lvl2": "env", "lvl3": null } + }, + { + "content": "API Reference", + "objectID": "af546d3e-1741-4601-ae9f-8b4b0ece08e2", + "type": "lvl2", + "url": "/docs/guide/cli#api-reference", + "hierarchy": { "lvl1": "CLI", "lvl2": "API Reference", "lvl3": null } + }, { "content": "Design Principles", - "objectID": "a829d46e-79e3-40a6-a0db-8cbf2339db33", + "objectID": "6bcba7eb-9905-4b34-8c7c-d8031c93802d", "type": "lvl1", "url": "/docs/guide/design-principles", "hierarchy": { "lvl1": "Design Principles" } }, { "content": "Simplicity and Usability", - "objectID": "006fae5c-4b3d-4a49-9e38-b8db31c6b3cb", + "objectID": "1d407aee-bb43-4611-b0b1-b0f9166c5a92", "type": "lvl3", "url": "/docs/guide/design-principles#simplicity-and-usability", "hierarchy": { @@ -7792,7 +9969,7 @@ }, { "content": "Modular Design", - "objectID": "501b69d9-6b7c-444a-bc5a-6b04d38b2df7", + "objectID": "ebc253fc-865b-4afb-8d91-9d1a024cc32f", "type": "lvl3", "url": "/docs/guide/design-principles#modular-design", "hierarchy": { @@ -7803,7 +9980,7 @@ }, { "content": "Customization and Flexibility", - "objectID": "d0c63420-b54f-49f9-8c19-229c3242cad8", + "objectID": "4f38b2dc-71ec-46e6-883b-3078ebfe3050", "type": "lvl3", "url": "/docs/guide/design-principles#customization-and-flexibility", "hierarchy": { @@ -7814,7 +9991,7 @@ }, { "content": "Consistent API", - "objectID": "21fc2b7e-752f-4747-b6b6-5c68f0560e9c", + "objectID": "d410f115-b379-48b7-a275-df778ed53def", "type": "lvl3", "url": "/docs/guide/design-principles#consistent-api", "hierarchy": { @@ -7825,7 +10002,7 @@ }, { "content": "Accessibility", - "objectID": "bc6897b5-30c4-43f1-9796-ffebbdeffe2a", + "objectID": "7b604ac7-d313-4393-af9f-7afca4689269", "type": "lvl3", "url": "/docs/guide/design-principles#accessibility", "hierarchy": { @@ -7836,7 +10013,7 @@ }, { "content": "Component Slots", - "objectID": "1ab307b2-1860-417f-a00c-638167e196d9", + "objectID": "482c145d-b235-4816-aab7-8fb8186a4ab9", "type": "lvl3", "url": "/docs/guide/design-principles#component-slots", "hierarchy": { @@ -7847,14 +10024,14 @@ }, { "content": "Installation", - "objectID": "5021422f-7023-4045-98de-88a33385bc5a", + "objectID": "86d0638f-b6e2-4b4a-9f85-530e556c177d", "type": "lvl1", "url": "/docs/guide/installation", "hierarchy": { "lvl1": "Installation" } }, { "content": "Global Installation", - "objectID": "dfd05c3d-b3b3-4169-a1a1-8c2ec883ce89", + "objectID": "1aad2d73-b120-4898-b9ac-cf99f8bc9245", "type": "lvl2", "url": "/docs/guide/installation#global-installation", "hierarchy": { @@ -7865,7 +10042,7 @@ }, { "content": "Install Packages", - "objectID": "aa0cf633-b370-4cfc-b79f-11a960a02978", + "objectID": "2b7e67ad-16a2-4b3f-870a-8350ebc5888f", "type": "lvl3", "url": "/docs/guide/installation#install-packages", "hierarchy": { @@ -7876,7 +10053,7 @@ }, { "content": "Tailwind CSS Setup", - "objectID": "062711ff-9dc3-46c3-9187-c755c0df13f8", + "objectID": "b47baf88-b923-4870-8664-a8a0e950fb1f", "type": "lvl3", "url": "/docs/guide/installation#tailwind-css-setup", "hierarchy": { @@ -7887,7 +10064,7 @@ }, { "content": "Provider Setup", - "objectID": "d0230301-dc3d-4768-a628-51a14891f999", + "objectID": "a8db5af4-ff8f-4462-a75d-9fa6ca9849da", "type": "lvl3", "url": "/docs/guide/installation#provider-setup", "hierarchy": { @@ -7898,7 +10075,7 @@ }, { "content": "Setup pnpm (optional)", - "objectID": "11fc563b-dad3-4af3-bf1d-d7ef683bb5d1", + "objectID": "14b04154-6b79-4a17-ba80-c73a95ae8d94", "type": "lvl3", "url": "/docs/guide/installation#setup-pnpm-optional", "hierarchy": { @@ -7909,7 +10086,7 @@ }, { "content": "Individual Installation", - "objectID": "c9e412cf-3ec0-4769-93fa-357473479c13", + "objectID": "00035beb-676b-45d5-8a73-fae0e178d9eb", "type": "lvl2", "url": "/docs/guide/installation#individual-installation", "hierarchy": { @@ -7920,7 +10097,7 @@ }, { "content": "Install Core Packages", - "objectID": "6de346ee-481d-487a-84a0-f4b55ed2957e", + "objectID": "87cf9e93-e806-499c-a3dd-d32698256d48", "type": "lvl3", "url": "/docs/guide/installation#install-core-packages", "hierarchy": { @@ -7931,7 +10108,7 @@ }, { "content": "Install Component", - "objectID": "41df0be2-e6ca-4262-9535-9dd904e01811", + "objectID": "484025cf-4366-4554-abe0-88e44a5409ad", "type": "lvl3", "url": "/docs/guide/installation#install-component", "hierarchy": { @@ -7942,7 +10119,7 @@ }, { "content": "Tailwind CSS Setup", - "objectID": "c753c65d-7c3b-4ad5-be4b-59e9f37d2536", + "objectID": "1c2ba3ab-a673-4a42-ad5f-9207d0e2f9be", "type": "lvl3", "url": "/docs/guide/installation#tailwind-css-setup-1", "hierarchy": { @@ -7953,7 +10130,7 @@ }, { "content": "Provider Setup", - "objectID": "71796c02-a7a2-49ff-a1ef-4406f6718fe1", + "objectID": "ef77311c-24c7-411d-b7ea-49bb65b3461f", "type": "lvl3", "url": "/docs/guide/installation#provider-setup-1", "hierarchy": { @@ -7964,7 +10141,7 @@ }, { "content": "Use the Component", - "objectID": "ce051c37-9de1-4c3b-8042-7007bbe2d273", + "objectID": "65c3aad1-2483-475a-9d50-b52cebd48465", "type": "lvl3", "url": "/docs/guide/installation#use-the-component", "hierarchy": { @@ -7975,7 +10152,7 @@ }, { "content": "Setup pnpm (optional)", - "objectID": "fbdc8bce-17f7-4433-88fd-029cbeefa6c3", + "objectID": "6e11bd66-1af9-4602-9e52-b3d10ade18ca", "type": "lvl3", "url": "/docs/guide/installation#setup-pnpm-optional-1", "hierarchy": { @@ -7986,7 +10163,7 @@ }, { "content": "Framework Guides", - "objectID": "3ea8e23f-21c8-4ffa-a93d-4c48e57cf936", + "objectID": "a08e064b-cee7-4ce8-8d7b-5235dec1a8cb", "type": "lvl2", "url": "/docs/guide/installation#framework-guides", "hierarchy": { @@ -7997,14 +10174,14 @@ }, { "content": "Introduction", - "objectID": "30557206-47bd-4347-ba91-908027473672", + "objectID": "54640cd0-2b9c-4038-91b3-22553ce3ed75", "type": "lvl1", "url": "/docs/guide/introduction", "hierarchy": { "lvl1": "Introduction" } }, { "content": "What is NextUI?", - "objectID": "1b056bf9-e80d-4585-a338-5f7ec0e7d34d", + "objectID": "920861b3-24ff-45f7-8953-785399e18db4", "type": "lvl2", "url": "/docs/guide/introduction#what-is-nextui", "hierarchy": { @@ -8015,14 +10192,14 @@ }, { "content": "FAQ", - "objectID": "767a3ffb-9c98-408b-b0e9-4b3f681faf29", + "objectID": "8b1586d0-3331-4402-8612-46bf7aaa65ab", "type": "lvl2", "url": "/docs/guide/introduction#faq", "hierarchy": { "lvl1": "Introduction", "lvl2": "FAQ", "lvl3": null } }, { "content": "Is NextUI a Vercel related project?", - "objectID": "78fdc213-271c-4909-a842-3fda85d19e44", + "objectID": "d9a32a9c-9857-4448-90c9-7651ffbd202c", "type": "lvl3", "url": "/docs/guide/introduction#is-nextui-a-vercel-related-project", "hierarchy": { @@ -8033,7 +10210,7 @@ }, { "content": "How is NextUI different from TailwindCSS?", - "objectID": "d4c31e84-4b5f-4a74-bf05-55281468f0a1", + "objectID": "46140a4e-0194-4a17-b210-dc82142a0811", "type": "lvl3", "url": "/docs/guide/introduction#how-is-nextui-different-from-tailwindcss", "hierarchy": { @@ -8044,7 +10221,7 @@ }, { "content": "How is NextUI different from TailwindCSS components libraries?", - "objectID": "cd306189-26b3-4820-93fc-8b23d6120f57", + "objectID": "69e8ad8a-28f4-44dd-acdd-12b19bdde7a5", "type": "lvl3", "url": "/docs/guide/introduction#how-is-nextui-different-from-tailwindcss-components-libraries", "hierarchy": { @@ -8055,7 +10232,7 @@ }, { "content": "How NextUI deals with TailwindCSS classes conflicts?", - "objectID": "eaea6c95-bc17-4a2b-969b-c43ea134c1c4", + "objectID": "6c6355a3-5ca6-4cb8-bd2d-e4352c7eb290", "type": "lvl3", "url": "/docs/guide/introduction#how-nextui-deals-with-tailwindcss-classes-conflicts", "hierarchy": { @@ -8066,7 +10243,7 @@ }, { "content": "Does NextUI use runtime CSS?", - "objectID": "15274277-e377-4294-9151-0c3ac9b1f566", + "objectID": "61345ad2-1f49-459a-a785-5ca93dab4f2c", "type": "lvl3", "url": "/docs/guide/introduction#does-nextui-use-runtime-css", "hierarchy": { @@ -8077,7 +10254,7 @@ }, { "content": "Does NextUI support TypeScript?", - "objectID": "52f3454b-620f-4c72-98eb-2f91ff8828ca", + "objectID": "7582c9ed-a83c-4dd5-822c-524fad99e0cf", "type": "lvl3", "url": "/docs/guide/introduction#does-nextui-support-typescript", "hierarchy": { @@ -8088,7 +10265,7 @@ }, { "content": "Can I use NextUI with other front-end frameworks or libraries, such as Vue or Angular?", - "objectID": "5db21ede-c294-4629-b351-0a63607a80a2", + "objectID": "7941b131-48de-4280-bb17-294e1809e947", "type": "lvl3", "url": "/docs/guide/introduction#can-i-use-nextui-with-other-front-end-frameworks-or-libraries-such-as-vue-or-angular", "hierarchy": { @@ -8099,7 +10276,7 @@ }, { "content": "Why NextUI uses Framer Motion?", - "objectID": "55090f13-5963-47e9-bca3-23aea9f10a29", + "objectID": "15e1fcc9-407c-4312-9139-f01cbcd32df6", "type": "lvl3", "url": "/docs/guide/introduction#why-nextui-uses-framer-motion", "hierarchy": { @@ -8110,14 +10287,14 @@ }, { "content": "Community", - "objectID": "25cf0872-4b93-497f-b773-89b7a8722b47", + "objectID": "c133e6a4-e43c-438b-a043-fefd8bd7f266", "type": "lvl2", "url": "/docs/guide/introduction#community", "hierarchy": { "lvl1": "Introduction", "lvl2": "Community", "lvl3": null } }, { "content": "Contributing", - "objectID": "de36ddd4-d448-459f-a885-699e7d5fb794", + "objectID": "a2044d56-b279-4bb9-9c3d-82f583206cfc", "type": "lvl2", "url": "/docs/guide/introduction#contributing", "hierarchy": { @@ -8128,21 +10305,21 @@ }, { "content": "Routing", - "objectID": "5177af1d-4d58-4baa-8691-5efc527924ed", + "objectID": "0404cabb-386c-4653-bdb3-07633b1d603a", "type": "lvl1", "url": "/docs/guide/routing", "hierarchy": { "lvl1": "Routing" } }, { "content": "Introduction", - "objectID": "42e2f4dd-ca10-4373-a2ed-8d87ee1bbd2a", + "objectID": "d81aecea-e129-4fd3-ba43-46ccf9313f8f", "type": "lvl2", "url": "/docs/guide/routing#introduction", "hierarchy": { "lvl1": "Routing", "lvl2": "Introduction", "lvl3": null } }, { "content": "NextUIProvider Setup", - "objectID": "b23a5eae-58bf-4c10-8672-55a2fb42bb54", + "objectID": "c3cb7137-58df-4e4b-80d4-1c4c6b9e1560", "type": "lvl3", "url": "/docs/guide/routing#nextuiprovider-setup", "hierarchy": { @@ -8153,7 +10330,7 @@ }, { "content": "Next.js", - "objectID": "f0194654-eee4-4c4f-8a12-b9c4aa0601a9", + "objectID": "4a84e80f-0f22-4ab1-871d-00d1ae7b65bf", "type": "lvl3", "url": "/docs/guide/routing#nextjs", "hierarchy": { @@ -8164,21 +10341,21 @@ }, { "content": "App Router", - "objectID": "1b6946c1-38c9-445d-b68f-94f051f1cff0", + "objectID": "d61d5850-5e6f-47f9-81e7-a4cf6f25d899", "type": "lvl4", "url": "/docs/guide/routing#app-router", "hierarchy": { "lvl1": "Routing", "lvl2": "Next.js", "lvl3": null } }, { "content": "Add the `useRouter`", - "objectID": "93a3ef33-0c30-478f-8ec7-8b52e6973331", + "objectID": "a1e51f32-71a2-4929-89b8-9d235cceef31", "type": "lvl4", "url": "/docs/guide/routing#add-the-userouter", "hierarchy": { "lvl1": "Routing", "lvl2": "App Router", "lvl3": null } }, { "content": "Add Provider to Root", - "objectID": "3c6b1b8e-32e2-4c32-8f2f-e61adf0b27aa", + "objectID": "7a5c9aa4-1e39-455a-9734-cb3170c34763", "type": "lvl4", "url": "/docs/guide/routing#add-provider-to-root", "hierarchy": { @@ -8189,7 +10366,7 @@ }, { "content": "Pages Router", - "objectID": "f7e885be-632d-4601-85f0-f56dcdfb0383", + "objectID": "56a30ee3-c206-4b1c-bf8b-15f77a04b536", "type": "lvl4", "url": "/docs/guide/routing#pages-router", "hierarchy": { @@ -8200,7 +10377,7 @@ }, { "content": "React Router", - "objectID": "4cba8296-fc50-4dd9-b570-96cc937054df", + "objectID": "a52d4a9c-109e-455c-8a5f-bb4fb9d17ca7", "type": "lvl3", "url": "/docs/guide/routing#react-router", "hierarchy": { @@ -8211,14 +10388,14 @@ }, { "content": "Remix", - "objectID": "0b110e9c-4442-48f4-ae9d-41caa0571a2d", + "objectID": "dd0caa40-b646-46f2-91fd-684c388b81f4", "type": "lvl3", "url": "/docs/guide/routing#remix", "hierarchy": { "lvl1": "Routing", "lvl2": "React Router", "lvl3": "Remix" } }, { "content": "Usage examples", - "objectID": "571739ac-f428-4775-a02c-2e7f0262aa5d", + "objectID": "73dab319-8b4c-47bb-92ab-3ddea402590c", "type": "lvl3", "url": "/docs/guide/routing#usage-examples", "hierarchy": { @@ -8229,14 +10406,14 @@ }, { "content": "Upgrade to v2", - "objectID": "ed9d9494-abff-4eea-a374-8271ac2c3783", + "objectID": "c995a668-cd77-49e6-ad9b-35179678bd69", "type": "lvl1", "url": "/docs/guide/upgrade-to-v2", "hierarchy": { "lvl1": "Upgrade to v2" } }, { "content": "Next.js upgrade steps", - "objectID": "501d28cd-3179-4ad5-9576-7d3713cb5d42", + "objectID": "990fbe8d-3644-4449-8f10-b4449dd5eb7d", "type": "lvl2", "url": "/docs/guide/upgrade-to-v2#nextjs-upgrade-steps", "hierarchy": { @@ -8247,7 +10424,7 @@ }, { "content": "App directory Setup", - "objectID": "061dbe84-4220-4c5f-ac19-9f21d73951de", + "objectID": "ede8cbcc-1175-4b9f-86e2-087282f44cd9", "type": "lvl2", "url": "/docs/guide/upgrade-to-v2#app-directory-setup", "hierarchy": { @@ -8258,7 +10435,7 @@ }, { "content": "Installation", - "objectID": "eafd20ab-eddb-4a54-8a82-49f943ae2f8d", + "objectID": "809746e7-dfcd-4d7a-8061-9761b4e96880", "type": "lvl3", "url": "/docs/guide/upgrade-to-v2#installation", "hierarchy": { @@ -8269,7 +10446,7 @@ }, { "content": "Tailwind CSS Setup", - "objectID": "26f63cbd-a681-49dd-8207-2cd5df3c20cd", + "objectID": "71aa081d-d480-4dc5-bece-6784ae184633", "type": "lvl3", "url": "/docs/guide/upgrade-to-v2#tailwind-css-setup", "hierarchy": { @@ -8280,7 +10457,7 @@ }, { "content": "Setup Provider", - "objectID": "56e9f302-1b60-433e-8ed8-fa2f2edbb7e4", + "objectID": "523c7541-2fb1-42b9-b40f-425aa111f29b", "type": "lvl3", "url": "/docs/guide/upgrade-to-v2#setup-provider", "hierarchy": { @@ -8291,7 +10468,7 @@ }, { "content": "Add Provider to Root", - "objectID": "9bf782e7-cf27-439d-aac3-56a05c58a83a", + "objectID": "cabbdfe7-7783-43c5-938a-a672ff29d9c1", "type": "lvl3", "url": "/docs/guide/upgrade-to-v2#add-provider-to-root", "hierarchy": { @@ -8302,7 +10479,7 @@ }, { "content": "Use NextUI Components", - "objectID": "e9c278a1-a594-4961-85e5-2ddda9293c9f", + "objectID": "d8f45caf-2c1f-4ae3-8208-2eab83e00c70", "type": "lvl3", "url": "/docs/guide/upgrade-to-v2#use-nextui-components", "hierarchy": { @@ -8313,7 +10490,7 @@ }, { "content": "Setup pnpm (optional)", - "objectID": "9c983a59-b551-4225-8fb8-8bb0dc8fce37", + "objectID": "f2d71f65-a7ff-4955-985d-feecf9ef5c96", "type": "lvl3", "url": "/docs/guide/upgrade-to-v2#setup-pnpm-optional", "hierarchy": { @@ -8324,7 +10501,7 @@ }, { "content": "Pages Directory Setup", - "objectID": "7c223dae-66cf-4534-8a06-60fec98f4106", + "objectID": "bfa5e760-b183-4ecb-97e7-c7d7c9302590", "type": "lvl2", "url": "/docs/guide/upgrade-to-v2#pages-directory-setup", "hierarchy": { @@ -8335,7 +10512,7 @@ }, { "content": "Installation", - "objectID": "426f194d-637b-4b60-818c-5cb1e758ebb5", + "objectID": "95ebaa82-2423-4e38-8e45-54bca8f23fc7", "type": "lvl3", "url": "/docs/guide/upgrade-to-v2#installation-1", "hierarchy": { @@ -8346,7 +10523,7 @@ }, { "content": "Tailwind CSS Setup", - "objectID": "b5e168bb-b7e2-4292-9d86-d79fe15f35e9", + "objectID": "bfa27f3f-542c-4f0a-85d2-a35ea605e32a", "type": "lvl3", "url": "/docs/guide/upgrade-to-v2#tailwind-css-setup-1", "hierarchy": { @@ -8357,7 +10534,7 @@ }, { "content": "Setup Provider", - "objectID": "441b35f3-9582-440f-b018-9defd3654ea6", + "objectID": "61aad957-f7eb-4dcc-9f01-0b5c839e116f", "type": "lvl3", "url": "/docs/guide/upgrade-to-v2#setup-provider-1", "hierarchy": { @@ -8368,7 +10545,7 @@ }, { "content": "Use NextUI Components", - "objectID": "dcd8eb18-4961-4fbf-a749-5b088c0f7860", + "objectID": "5b5a1e07-4ea4-40ed-a8ae-d683596eb562", "type": "lvl3", "url": "/docs/guide/upgrade-to-v2#use-nextui-components-1", "hierarchy": { @@ -8379,7 +10556,7 @@ }, { "content": "Setup pnpm (optional)", - "objectID": "e2827dc7-8139-4270-b96f-846ea43f33fa", + "objectID": "d7c1e4f9-bec8-4657-af00-ced36009ab66", "type": "lvl3", "url": "/docs/guide/upgrade-to-v2#setup-pnpm-optional-1", "hierarchy": { @@ -8390,7 +10567,7 @@ }, { "content": "React upgrade steps", - "objectID": "67b33c4d-bd47-4c33-a39e-92e17d669055", + "objectID": "cbd9597e-ee2b-4ebc-94bf-3b76adc925e0", "type": "lvl2", "url": "/docs/guide/upgrade-to-v2#react-upgrade-steps", "hierarchy": { @@ -8401,7 +10578,7 @@ }, { "content": "Upgrade React version", - "objectID": "c1406a8e-c97e-405b-8f84-38e913b1d7f0", + "objectID": "e245df9c-5db1-438d-bed9-d76eae317f3f", "type": "lvl3", "url": "/docs/guide/upgrade-to-v2#upgrade-react-version", "hierarchy": { @@ -8412,7 +10589,7 @@ }, { "content": "Install Framer motion", - "objectID": "2f39ba49-6c29-4eb0-95b5-8b2259cc896e", + "objectID": "44da2fdc-50c8-4a28-9205-434f8f670d5a", "type": "lvl3", "url": "/docs/guide/upgrade-to-v2#install-framer-motion", "hierarchy": { @@ -8423,7 +10600,7 @@ }, { "content": "TailwindCSS Setup", - "objectID": "0c9df702-7d58-4600-b47d-7e296ec1118f", + "objectID": "c699d2b0-8d70-420b-959c-f79516fac368", "type": "lvl3", "url": "/docs/guide/upgrade-to-v2#tailwindcss-setup", "hierarchy": { @@ -8434,7 +10611,7 @@ }, { "content": "Provider Setup", - "objectID": "b7a7fded-64a2-408c-8fb7-964a4e48da71", + "objectID": "d329cbc7-7c8f-4a65-b217-59eb64cbe1e3", "type": "lvl3", "url": "/docs/guide/upgrade-to-v2#provider-setup", "hierarchy": { @@ -8445,7 +10622,7 @@ }, { "content": "Use NextUI Components", - "objectID": "060edb9d-07a8-40f2-aae3-fcd3aeac501a", + "objectID": "68a0680e-be28-4345-96aa-4cc6d56561db", "type": "lvl3", "url": "/docs/guide/upgrade-to-v2#use-nextui-components-2", "hierarchy": { @@ -8456,7 +10633,7 @@ }, { "content": "Setup pnpm (optional)", - "objectID": "3dedd929-6ad8-4ad3-a869-05ad8c56086b", + "objectID": "fb78381b-8294-436d-8440-0e67d4a1e812", "type": "lvl3", "url": "/docs/guide/upgrade-to-v2#setup-pnpm-optional-2", "hierarchy": { diff --git a/apps/docs/content/blog/v2.3.0.mdx b/apps/docs/content/blog/v2.3.0.mdx new file mode 100644 index 0000000000..1e2d1ca4ef --- /dev/null +++ b/apps/docs/content/blog/v2.3.0.mdx @@ -0,0 +1,406 @@ +--- +title: "Introducing v2.3.0 🎉" +description: "NextUI v2.3.0 is here! includes six new components, NextUI CLI, bug fixes, React Aria, and a TailwindCSS upgrade, among other enhancements." +date: "2024-04-16" +image: "/blog/v2.3.0.jpg" +tags: ["nextui", "cli", "date picker", "time input", "date input", "calendar"] +author: + name: "Junior Garcia" + username: "@jrgarciadev" + link: "https://twitter.com/jrgarciadev" + avatar: "/avatars/junior-garcia.jpeg" +--- + +import {dateInputContent} from "@/content/components/date-input"; +import {timeInputContent} from "@/content/components/time-input"; +import {calendarContent} from "@/content/components/calendar"; +import {rangeCalendarContent} from "@/content/components/range-calendar"; +import {datePickerContent} from "@/content/components/date-picker"; +import {dateRangePickerContent} from "@/content/components/date-range-picker"; + +NextUI v2.3.0 + +We are excited to announce the latest update to NextUI, version **2.3.0**! This release introduces 6 new components, +our new CLI, and several enhancements and bug fixes. + +## What's New in v2.3.0? + +- [NextUI CLI](/docs/guide/cli) - A command-line interface for creating and managing NextUI projects. +- [DateInput](/docs/components/date-input) - Allows users to enter and edit date and time values using a keyboard. +- [TimeInput](/docs/components/time-input) - Allows users to enter and edit time values using a keyboard. +- [Calendar](/docs/components/calendar) - Displays a calendar for selecting dates and times. +- [RangeCalendar](/docs/components/range-calendar) - Displays a calendar for selecting date ranges. +- [DatePicker](/docs/components/date-picker) - Allows users to select a date from a calendar. +- [DateRangePicker](/docs/components/date-range-picker) - Allows users to select a date range from a calendar. +- [Other Changes](#other-changes) - Includes styling improvements, accessibility and usability enhancements. + + + +Requirements: + +- [Tailwind CSS 3.4](https://tailwindcss.com/) or later + +Upgrade today by running one of the following commands: + + + + + + + +## NextUI CLI + +We are thrilled to introduce the [NextUI CLI](https://github.com/nextui-org/nextui-cli), a command-line interface, It offers a comprehensive suite +of commands to initialize, manage, and improve your NextUI projects. It enables you to `add`, `remove`, or +`upgrade` individual components, assess the health of your project, and more. + +### Installation + +To install the CLI globally, execute one of the following commands in your terminal: + + + +Alternatively, you can use the CLI without a global installation by employing `npx`: + +```bash +npx nextui-cli@latest +``` + +### Usage + +Once the CLI is installed, run the following command to display available commands: + +```bash +nextui +``` + +NextUI CLI can help you create new projects, add components, upgrade components, remove components, detect issues in +you setup, know your environment, and more. + + + +To initialize a new project, you can simply run: + +```bash +nextui init my-nextui-app +``` + + + +You will be prompted to configure your project: + +```codeBlock bash +? Select a template › - Use arrow-keys. Return to submit. +❯ App + A Next.js 13 with app directory template pre-configured with NextUI (v2) and Tailwind CSS. + Pages + A Next.js 13 with pages directory template pre-configured with NextUI (v2) and Tailwind CSS. +``` + +Select the template you want to use and the CLI will create a new project for you. + +> We're working on adding more templates to the CLI, so stay tuned for updates! + + + +If you already have a NextUI project, you can add components to it using the `add` command: + +```bash +nextui add date-input +``` + +It will automatically detect the required dependencies, modify your `tailwind.config.(js|ts)` file, +detect whether using `pnpm` if so, add the required configuration to your `.npmrc` file and add the component to your project. + +If instead of installing a single component you want to install multiple components, you can do so by separating them with a space: + +```bash +nextui add date-input time-input calendar +``` + +You can alternatively install the `main` package which includes all the components by passing the `--all` flag: + +```bash +nextui add --all +``` + + + +> The CLI is currentl in `Alpha` stage, we're working on adding more features and improvements. If you find any issues or have any suggestions, please let us know by [opening an issue](https://github.com/nextui-org/nextui-cli/issues/new). + +To learn more about the CLI and its commands, please refer to the [CLI documentation](/docs/guide/cli) and the [CLI API reference](/docs/api-references/cli-api). + +## New Components + +Since the beginning of NextUI, devs have been asking for date and time input components. After +months of iteration and development, we are excited to introduce the following new components: + +### DateInput + +DateInput is a component that allows users to enter and edit date and time values using a keyboard. +Each part of a date value is displayed in an individually editable segment. + + + +Go to the [DateInput documentation](/docs/components/date-input) to learn more about the component. + +### TimeInput + +The `TimeInput` component consists of a label, and a group of segments representing each unit of a time (e.g. hours, minutes, and seconds). Each segment is individually focusable and editable by the user, by typing or using the arrow keys to increment and decrement the value. This approach allows values to be formatted and parsed correctly regardless of the locale or time format, and offers an easy and error-free way to edit times using the keyboard. + + + +Go to the [TimeInput documentation](/docs/components/time-input) to learn more about the component. + +### Calendar + +A Calendar consists of a grouping element containing one or more date grids (e.g. months), and a previous and next button for navigating between date ranges. Each calendar grid consists of cells containing button elements that can be pressed and navigated to using the arrow keys to select a date. + + + +The calendar also supports selecting years and months for rapid selection. + + + +Go to the [Calendar documentation](/docs/components/calendar) to learn more about the component. + +### RangeCalendar + +A Range calendar consists of a grouping element containing one or more date grids (e.g. months), and a previous and next button for navigating through time. Each calendar grid consists of cells containing button elements that can be pressed and navigated to using the arrow keys to select a date range. Once a start date is selected, the user can navigate to another date using the keyboard or by hovering over it, and clicking it or pressing the Enter key commits the selected date range. + + + +Go to the [RangeCalendar documentation](/docs/components/range-calendar) to learn more about the component. + +### DatePicker + +A Date Picker combines a DateInput and a Calendar popover to allow users to enter or select a date and time value. + + + +Go to the [DatePicker documentation](/docs/components/date-picker) to learn more about the component. + +### DateRangePicker + +Date Range Picker combines two DateInputs and a RangeCalendar popover to allow users to enter or select a date and time range. + + + +Go to the [DateRangePicker documentation](/docs/components/date-range-picker) to learn more about the component. + + +### Calendar Presets + +`Calendar` and `RangeCalendar` components support adding custom content at the top and bottom of the calendar, this is useful for adding presets or +custom actions to the calendar. + +Here's an example of how to add presets to the `Calendar` component: + + + +### Internationalization + +These new components have built-in internationalization, time zones and granularity support, they supports selecting dates +in many calendar systems used around the world, including `Gregorian`, `Hebrew`, `Indian`, `Islamic`, `Buddhist`, and more. + +Dates are automatically displayed in the appropriate calendar system for the user's locale this is possible thanks to [@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/) package, which +includes functions for parsing strings in multiple formats into `ZonedDateTime` objects. + +Here's and example using the `Indian` calendar system: + + + +Alternatively you can set the `locale` globally by using the `NextUIProvider` component: + +```jsx +// Next.js App Router example +"use client"; + +import {NextUIProvider} from "@nextui-org/react"; + +export interface ProvidersProps { + children: React.ReactNode; +} + +export function Providers({children}: ProvidersProps) { + const router = useRouter(); + + return {children}; +} +``` + +If no `locale` is provided, it will extract the locale from the browser. + +### NextUI Provider + +The `NextUIProvider` component was updated to include the `createCalendar` function, which allows you to create a calendar instance with the specified locale and time zone, +and the `defaultDates` object which allows you to set global minimum and maximum dates for the components. + +```jsx +// Next.js App Router example +"use client"; + +import {NextUIProvider, SupportedCalendars} from "@nextui-org/react"; +import {CalendarDate, GregorianCalendar} from "@internationalized/date"; + +export interface ProvidersProps { + children: React.ReactNode; +} + +function createCalendar(identifier: SupportedCalendars) { + switch (identifier) { + case "gregory": + return new GregorianCalendar(); + default: + throw new Error(`Unsupported calendar ${identifier}`); + } +} + +export function Providers({children}: ProvidersProps) { + const router = useRouter(); + + return ( + + {children} + + ); +} +``` + + + + +## Breaking Changes + +In order to improve the performance and reduce the bundle size, we have removed the `units` creation from the +`nextui` plugin. [TailwindCSS v3.4](https://tailwindcss.com/blog/tailwindcss-v3-4) added support for `min-h-*` and `min-w-*` classes, so it is no longer needed. + +How to upgrade: + +1. Upgrade TailwindCSS to version 3.4 or later (if you haven't already). You can do this by running: + +```bash +npm install tailwindcss@latest +``` + +2. Remove the `spacingUnit` configuration from your `tailwind.config.(js|ts)` file (if you have it): + +```diff-js + plugins: [ + nextui({ + layout: { +- spacingUnit: 4, + }, + }), + ], +``` + +3. Find all `-unit` classes in your project and replace them with a `-` separator. For example, replace `p-unit-4` with `p-4`. + +```diff-jsx +import {Button} from "@nextui-org/react"; + +export const MyButton = () => { + return ( +- + ); +}; +``` + +That's it! Your project should now be using the latest version of TailwindCSS and NextUI. + + + + + +## Other Changes + +**Bug Fixes**: + +- Fixed an HSL color rounding issue in the theme settings to ensure accurate color representation. [PR](https://github.com/nextui-org/nextui/pull/2702) - [@wingkwong](https://github.com/wingkwong) +- Removed conflicting transition definitions affecting CSS classes. [PR](https://github.com/nextui-org/nextui/pull/2677) - [@u3u](https://github.com/u3u) +- Patched the "@nextui-org/autocomplete" package to fix an issue where empty items with `allowCustomValue` would not render properly due to a null node problem. [PR](https://github.com/nextui-org/nextui/pull/2674) - [@wingkwong](https://github.com/wingkwong) +- Implemented a fix in modal components to prevent carryover of IME (Input Method Editor) input when switching fields using the Tab key. [PR](https://github.com/nextui-org/nextui/pull/2709) - [@ryo-manba](https://github.com/ryo-manba) +- Enhanced accessibility by handling Tab key press event in the `ModalContent` component. [PR](https://github.com/nextui-org/nextui/pull/2709) - [@ryo-manba](https://github.com/ryo-manba) +- Fixed an issue where disabled select components could still be changed using blur and keyboard shortcuts. [PR](https://github.com/nextui-org/nextui/pull/2649) - [@wingkwong](https://github.com/wingkwong) +- Patched issues in "@nextui-org/use-aria-multiselect" and "@nextui-org/stories-utils" packages to fix a warning about `SELECT defaultSelectedKeys`. [PR](https://github.com/nextui-org/nextui/pull/2648) - [@wingkwong](https://github.com/wingkwong) +- Fixed an issue with incorrect `onChange` typing in Checkbox Group, ensuring it now correctly handles an array of strings as values. [PR](https://github.com/nextui-org/nextui/pull/2595) - [@wingkwong](https://github.com/wingkwong) +- Fixed the `label` placement issue in `Select` component if a `description` prop is used [PR](https://github.com/nextui-org/nextui/pull/2553) - [@novsource](https://github.com/novsource) +- Fixed the `originalProps` spread issue in the `Dropdown` component. [PR](https://github.com/nextui-org/nextui/pull/2450) - [@wingkwong](https://github.com/wingkwong) + +**Improvements** +- Framer Motion was updated to the latest version, improving performance and reducing bundle size. [Docs](https://www.framer.com/motion/guide-reduce-bundle-size/) [PR](https://github.com/nextui-org/nextui/pull/2464) - [@mezotv](https://github.com/mezotv) +- `LazyMotion` was added to all components that use Framer Motion, improving performance by only loading the required motion components. +- We removed the custom `units` creation from the `nextui` plugin, it is no longer needed with TailwindCSS v3.4 and above. [PR](https://github.com/nextui-org/nextui/pull/2713) - [@jrgarciadev](https://github.com/jrgarciadev) +- Updated `framer-motion` package across various components and utilities to version `11.0.22` for enhanced performance and consistency. [PR](https://github.com/nextui-org/nextui/pull/2596) - [@wingkwong](https://github.com/wingkwong) +- Ensured compatibility with `react@18.2.0` and `react-dom@18.2.0` across the board. [PR](https://github.com/nextui-org/nextui/pull/2596) - [@wingkwong](https://github.com/wingkwong) +- Introduced patches for NextUI components to improve animations, including support for keyframes with spring and inertia animations. [PR](https://github.com/nextui-org/nextui/pull/2596) - [@wingkwong](https://github.com/wingkwong) +- Improved handling of numeric keys in the multi-select component to ensure consistent behavior. [PR](https://github.com/nextui-org/nextui/pull/2589) - [@wingkwong](https://github.com/wingkwong) +- Updated the version of react-aria to include the latest changes as detailed in the [2024-02-13 release](https://react-spectrum.adobe.com/releases/2024-02-13.html). [PR](https://github.com/nextui-org/nextui/pull/2561) - [@ryo-manba](https://github.com/ryo-manba) +- Added support for custom class names in the `AvatarGroup` component, enhancing flexibility in styling. [PR](https://github.com/nextui-org/nextui/pull/2669) - [@wingkwong](https://github.com/wingkwong) +- Introduced a `count` slot to the `AvatarGroup` for more customized rendering. [PR](https://github.com/nextui-org/nextui/pull/2669) - [@wingkwong](https://github.com/wingkwong) +- Improved the `AvatarGroup` component's count rendering logic for better performance and flexibility. [PR](https://github.com/nextui-org/nextui/pull/2669) - [@wingkwong](https://github.com/wingkwong) +- Add RTL support to the kbd component. [PR](https://github.com/nextui-org/nextui/pull/2482) - [@mrbadri](https://github.com/mrbadri) +- Add RTL support to the Select component. [PR](https://github.com/nextui-org/nextui/pull/2485) - [@mrbadri](https://github.com/mrbadri) +- Add RTL support to the avatar group componen. [PR](https://github.com/nextui-org/nextui/pull/2498) - [@mrbadri](https://github.com/mrbadri) +- Add RTL support to the Table component. [PR](https://github.com/nextui-org/nextui/pull/2472) - [@mrbadri](https://github.com/mrbadri) + +**Documentation**: +- Updated documentation to reflect the new features and changes in the `AvatarGroup` component. +- Added support for the "bun" package manager across documentation and components. [PR](https://github.com/nextui-org/nextui/pull/2625) - [@sudongyuer](https://github.com/sudongyuer) +- [Kapa.ai](https://www.kapa.ai/) widget was added to the documentation to provide AI support for users. [PR](https://github.com/nextui-org/nextui/pull/2428) - [@wingkwong](https://github.com/sudongyuer) +- Layout docs updated to remove the `units` configuration from the `tailwind.config.(js|ts)` file. + + +Special thanks to NextUI Team members [@kuri-sun](https://github.com/kuri-sun), [@ryo-manba](https://github.com/ryo-manba), +[@sudongyuer](https://github.com/sudongyuer), [@winchesHe](https://github.com/winchesHe), [@wingkwong](https://github.com/wingkwong), +[@tianenpang](https://github.com/tianenpang), [@smultar](https://github.com/smultar) and contributors for their contributions to this release. + +For a full list of changes, please refer to the [release notes](https://github.com/nextui-org/nextui/releases/tag/%40nextui-org%2Freact%402.3.0). + + + +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! + + + +## 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. diff --git a/apps/docs/content/components/autocomplete/index.ts b/apps/docs/content/components/autocomplete/index.ts index 1e809cdf14..b54d80e6d4 100644 --- a/apps/docs/content/components/autocomplete/index.ts +++ b/apps/docs/content/components/autocomplete/index.ts @@ -24,6 +24,7 @@ import asyncLoadingItems from "./async-loading-items"; import sections from "./sections"; import customSectionsStyle from "./custom-sections-style"; import customStyles from "./custom-styles"; +import readOnly from "./read-only"; export const autocompleteContent = { usage, @@ -52,4 +53,5 @@ export const autocompleteContent = { sections, customSectionsStyle, customStyles, + readOnly, }; diff --git a/apps/docs/content/components/autocomplete/read-only.ts b/apps/docs/content/components/autocomplete/read-only.ts new file mode 100644 index 0000000000..006d69b118 --- /dev/null +++ b/apps/docs/content/components/autocomplete/read-only.ts @@ -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 ( + + {(item) => {item.label}} + + ); +}`; + +const react = { + "/App.jsx": App, + "/data.js": data, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/breadcrumbs/customizing-ellipsis.ts b/apps/docs/content/components/breadcrumbs/customizing-ellipsis.ts index 37c916d0ce..e76ab23afc 100644 --- a/apps/docs/content/components/breadcrumbs/customizing-ellipsis.ts +++ b/apps/docs/content/components/breadcrumbs/customizing-ellipsis.ts @@ -12,7 +12,7 @@ export default function App() { + + + + } + value={value} + onChange={setValue} + onFocusChange={setValue} + /> +
+ ); +}`; + +const AppTs = `import {Calendar, Radio, RadioGroup, Button, ButtonGroup, cn} from "@nextui-org/react"; +import type {DateValue} from "@react-types/calendar"; +import {today, getLocalTimeZone, startOfWeek, startOfMonth} from "@internationalized/date"; +import {useLocale} from "@react-aria/i18n"; + +export default function App() { + let defaultDate = today(getLocalTimeZone()); + let [value, setValue] = React.useState(defaultDate); + let {locale} = useLocale(); + + let now = today(getLocalTimeZone()); + let nextWeek = startOfWeek(now.add({weeks: 1}), locale); + let nextMonth = startOfMonth(now.add({months: 1})); + + const CustomRadio = (props) => { + const {children, ...otherProps} = props; + + return ( + + {children} + + ); + }; + + return ( +
+ + Exact dates + 1 day + 2 days + 3 days + 7 days + 14 days + + } + classNames={{ + content: "w-full", + }} + focusedValue={value} + nextButtonProps={{ + variant: "bordered", + }} + prevButtonProps={{ + variant: "bordered", + }} + topContent={ + + + + + + } + value={value} + onChange={setValue} + onFocusChange={setValue} + /> +
+ ); +}`; + +const react = { + "/App.jsx": App, + "/App.tsx": AppTs, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/calendar/read-only.ts b/apps/docs/content/components/calendar/read-only.ts new file mode 100644 index 0000000000..6fffcd20a6 --- /dev/null +++ b/apps/docs/content/components/calendar/read-only.ts @@ -0,0 +1,20 @@ +const App = `import {Calendar} from "@nextui-org/react"; +import {today, getLocalTimeZone} from "@internationalized/date"; + +export default function App() { + return ( + + ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/calendar/unavailable-dates.ts b/apps/docs/content/components/calendar/unavailable-dates.ts new file mode 100644 index 0000000000..9a884fb2a9 --- /dev/null +++ b/apps/docs/content/components/calendar/unavailable-dates.ts @@ -0,0 +1,37 @@ +const App = `import {Calendar} from "@nextui-org/react"; +import {today, getLocalTimeZone, isWeekend} from "@internationalized/date"; +import {useLocale} from "@react-aria/i18n"; + + +export default function App() { + let now = today(getLocalTimeZone()); + + let disabledRanges = [ + [now, now.add({days: 5})], + [now.add({days: 14}), now.add({days: 16})], + [now.add({days: 23}), now.add({days: 24})], + ]; + + let {locale} = useLocale(); + + let isDateUnavailable = (date) => + isWeekend(date, locale) || + disabledRanges.some( + (interval) => date.compare(interval[0]) >= 0 && date.compare(interval[1]) <= 0, + ); + + return ( + + ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/calendar/usage.ts b/apps/docs/content/components/calendar/usage.ts new file mode 100644 index 0000000000..0a97b863cd --- /dev/null +++ b/apps/docs/content/components/calendar/usage.ts @@ -0,0 +1,19 @@ +const App = `import {Calendar} from "@nextui-org/react"; +import {parseDate} from '@internationalized/date'; + +export default function App() { + return ( +
+ + +
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/calendar/visible-months.ts b/apps/docs/content/components/calendar/visible-months.ts new file mode 100644 index 0000000000..796fc6d9b8 --- /dev/null +++ b/apps/docs/content/components/calendar/visible-months.ts @@ -0,0 +1,18 @@ +const App = `import {Calendar} from "@nextui-org/react"; + +export default function App() { + return ( + + ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/calendar/with-month-and-year-picker.ts b/apps/docs/content/components/calendar/with-month-and-year-picker.ts new file mode 100644 index 0000000000..1774984501 --- /dev/null +++ b/apps/docs/content/components/calendar/with-month-and-year-picker.ts @@ -0,0 +1,18 @@ +const App = `import {Calendar} from "@nextui-org/react"; + +export default function App() { + return ( + + ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-input/controlled.ts b/apps/docs/content/components/date-input/controlled.ts new file mode 100644 index 0000000000..cc8ce5a7b1 --- /dev/null +++ b/apps/docs/content/components/date-input/controlled.ts @@ -0,0 +1,50 @@ +const App = `import {DateInput} from "@nextui-org/react"; +import {parseDate, getLocalTimeZone} from "@internationalized/date"; +import {useDateFormatter} from "@react-aria/i18n"; + +export default function App() { + const [value, setValue] = React.useState(parseDate("2024-04-04")); + + let formatter = useDateFormatter({dateStyle: "full"}); + + return ( +
+
+ +

+ Selected date: {value ? formatter.format(value.toDate(getLocalTimeZone())) : "--"} +

+
+
+ ); +}`; + +const AppTs = `import {DateInput} from "@nextui-org/react"; +import {DateValue, parseDate, getLocalTimeZone} from "@internationalized/date"; +import {useDateFormatter} from "@react-aria/i18n"; + +export default function App() { + const [value, setValue] = React.useState(parseDate("2024-04-04")); + + let formatter = useDateFormatter({dateStyle: "full"}); + + return ( +
+
+ +

+ Selected date: {value ? formatter.format(value.toDate(getLocalTimeZone())) : "--"} +

+
+
+ ); +}`; + +const react = { + "/App.jsx": App, + "/App.tsx": AppTs, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-input/description.ts b/apps/docs/content/components/date-input/description.ts new file mode 100644 index 0000000000..344087e325 --- /dev/null +++ b/apps/docs/content/components/date-input/description.ts @@ -0,0 +1,22 @@ +const App = `import {DateInput} from "@nextui-org/react"; +import {CalendarDate} from "@internationalized/date"; + +export default function App() { + return ( +
+ +
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-input/disabled.ts b/apps/docs/content/components/date-input/disabled.ts new file mode 100644 index 0000000000..b61e928461 --- /dev/null +++ b/apps/docs/content/components/date-input/disabled.ts @@ -0,0 +1,23 @@ +const App = `import {DateInput} from "@nextui-org/react"; +import {CalendarDate, parseDate} from "@internationalized/date"; + +export default function App() { + return ( +
+ +
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-input/error-message.ts b/apps/docs/content/components/date-input/error-message.ts new file mode 100644 index 0000000000..a76208e779 --- /dev/null +++ b/apps/docs/content/components/date-input/error-message.ts @@ -0,0 +1,26 @@ +const App = `import {DateInput} from "@nextui-org/react"; +import {CalendarDate, parseDate} from "@internationalized/date"; + +export default function App() { + return ( +
+ +
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-input/granularity.ts b/apps/docs/content/components/date-input/granularity.ts new file mode 100644 index 0000000000..936bcddffa --- /dev/null +++ b/apps/docs/content/components/date-input/granularity.ts @@ -0,0 +1,60 @@ +const App = `import {DateInput} from "@nextui-org/react"; +import {now, parseAbsoluteToLocal} from "@internationalized/date"; +import {useDateFormatter} from "@react-aria/i18n"; + +export default function App() { + let [date, setDate] = React.useState(parseAbsoluteToLocal("2021-04-07T18:45:22Z")); + + return ( +
+ + + + +
+ ); +}`; + +const AppTs = `import {DateInput} from "@nextui-org/react"; +import {DateValue, now, parseAbsoluteToLocal} from "@internationalized/date"; +import {useDateFormatter} from "@react-aria/i18n"; + +export default function App() { + let [date, setDate] = React.useState(parseAbsoluteToLocal("2021-04-07T18:45:22Z")); + + return ( +
+ + + + +
+ ); +}`; + +const react = { + "/App.jsx": App, + "/App.tsx": AppTs, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-input/hide-timezone.ts b/apps/docs/content/components/date-input/hide-timezone.ts new file mode 100644 index 0000000000..cde093363e --- /dev/null +++ b/apps/docs/content/components/date-input/hide-timezone.ts @@ -0,0 +1,22 @@ +const App = `import {DateInput} from "@nextui-org/react"; +import {parseZonedDateTime} from "@internationalized/date"; + +export default function App() { + return ( +
+ +
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-input/hourly-cycle.ts b/apps/docs/content/components/date-input/hourly-cycle.ts new file mode 100644 index 0000000000..0336f7ea19 --- /dev/null +++ b/apps/docs/content/components/date-input/hourly-cycle.ts @@ -0,0 +1,23 @@ +const App = `import {DateInput} from "@nextui-org/react"; +import {parseZonedDateTime} from "@internationalized/date"; + +export default function App() { + return ( +
+ +
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-input/index.ts b/apps/docs/content/components/date-input/index.ts new file mode 100644 index 0000000000..663e66615c --- /dev/null +++ b/apps/docs/content/components/date-input/index.ts @@ -0,0 +1,35 @@ +import usage from "./usage"; +import disabled from "./disabled"; +import readOnly from "./readonly"; +import required from "./required"; +import variants from "./variants"; +import labelPlacements from "./label-placements"; +import description from "./description"; +import startEndContent from "./start-end-content"; +import errorMessage from "./error-message"; +import controlled from "./controlled"; +import timeZones from "./time-zones"; +import granularity from "./granularity"; +import minAndMaxDate from "./min-and-max-date"; +import internationalCalendar from "./international-calendar"; +import hideTimeZone from "./hide-timezone"; +import hourlyCycle from "./hourly-cycle"; + +export const dateInputContent = { + usage, + disabled, + readOnly, + required, + variants, + labelPlacements, + description, + startEndContent, + errorMessage, + controlled, + timeZones, + granularity, + minAndMaxDate, + internationalCalendar, + hideTimeZone, + hourlyCycle, +}; diff --git a/apps/docs/content/components/date-input/international-calendar.ts b/apps/docs/content/components/date-input/international-calendar.ts new file mode 100644 index 0000000000..20f9064feb --- /dev/null +++ b/apps/docs/content/components/date-input/international-calendar.ts @@ -0,0 +1,40 @@ +const App = `import {DateInput} from "@nextui-org/react"; +import {now, parseAbsoluteToLocal} from "@internationalized/date"; +import {I18nProvider} from "@react-aria/i18n"; + +export default function App() { + const [date, setDate] = React.useState(parseAbsoluteToLocal("2021-04-07T18:45:22Z")); + + return ( +
+ + + +
+ ); +}`; + +const AppTs = `import {DateInput} from "@nextui-org/react"; +import {DateValue, now, parseAbsoluteToLocal} from "@internationalized/date"; +import {I18nProvider} from "@react-aria/i18n"; + +export default function App() { + const [date, setDate] = React.useState(parseAbsoluteToLocal("2021-04-07T18:45:22Z")); + + return ( +
+ + + +
+ ); +}`; + +const react = { + "/App.jsx": App, + "/App.tsx": AppTs, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-input/label-placements.ts b/apps/docs/content/components/date-input/label-placements.ts new file mode 100644 index 0000000000..df3d59c5ff --- /dev/null +++ b/apps/docs/content/components/date-input/label-placements.ts @@ -0,0 +1,31 @@ +const App = `import {DateInput} from "@nextui-org/react"; +import {CalendarDate} from "@internationalized/date"; + +export default function App() { + const placements = [ + "inside", + "outside", + "outside-left", + ]; + + return ( +
+ {placements.map((placement) => ( + + ))} +
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-input/min-and-max-date.ts b/apps/docs/content/components/date-input/min-and-max-date.ts new file mode 100644 index 0000000000..5d59cb9f4a --- /dev/null +++ b/apps/docs/content/components/date-input/min-and-max-date.ts @@ -0,0 +1,33 @@ +const App = `import {DateInput} from "@nextui-org/react"; +import {getLocalTimeZone, parseDate, today} from "@internationalized/date"; + +export default function App() { + return ( +
+
+

Min date

+ +
+
+

Max date

+ +
+
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-input/readonly.ts b/apps/docs/content/components/date-input/readonly.ts new file mode 100644 index 0000000000..ddd06f00bb --- /dev/null +++ b/apps/docs/content/components/date-input/readonly.ts @@ -0,0 +1,23 @@ +const App = `import {DateInput} from "@nextui-org/react"; +import {CalendarDate, parseDate} from "@internationalized/date"; + +export default function App() { + return ( +
+ +
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-input/required.ts b/apps/docs/content/components/date-input/required.ts new file mode 100644 index 0000000000..7e064fec4b --- /dev/null +++ b/apps/docs/content/components/date-input/required.ts @@ -0,0 +1,23 @@ +const App = `import {DateInput} from "@nextui-org/react"; +import {CalendarDate, parseDate} from "@internationalized/date"; + +export default function App() { + return ( +
+ +
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-input/start-end-content.ts b/apps/docs/content/components/date-input/start-end-content.ts new file mode 100644 index 0000000000..182305c868 --- /dev/null +++ b/apps/docs/content/components/date-input/start-end-content.ts @@ -0,0 +1,63 @@ +const CalendarIcon = `export const CalendarIcon = (props) => ( + +);`; + +const App = `import {DateInput} from "@nextui-org/react"; +import {CalendarDate, parseDate} from "@internationalized/date"; +import {CalendarIcon} from './CalendarIcon'; + +export default function App() { + return ( +
+
+ + } + /> + + } + /> +
+
+ ); +}`; + +const react = { + "/App.jsx": App, + "/CalendarIcon.jsx": CalendarIcon, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-input/time-zones.ts b/apps/docs/content/components/date-input/time-zones.ts new file mode 100644 index 0000000000..65b11c09c1 --- /dev/null +++ b/apps/docs/content/components/date-input/time-zones.ts @@ -0,0 +1,27 @@ +const App = `import {DateInput} from "@nextui-org/react"; +import {parseZonedDateTime, parseAbsoluteToLocal} from "@internationalized/date"; + +export default function App() { + return ( +
+ + +
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-input/usage.ts b/apps/docs/content/components/date-input/usage.ts new file mode 100644 index 0000000000..eed0992112 --- /dev/null +++ b/apps/docs/content/components/date-input/usage.ts @@ -0,0 +1,18 @@ +const App = `import {DateInput} from "@nextui-org/react"; +import {CalendarDate} from "@internationalized/date"; + +export default function App() { + return ( +
+ +
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-input/variants.ts b/apps/docs/content/components/date-input/variants.ts new file mode 100644 index 0000000000..5d37e4d194 --- /dev/null +++ b/apps/docs/content/components/date-input/variants.ts @@ -0,0 +1,24 @@ +const App = `import {DateInput} from "@nextui-org/react"; +import {CalendarDate} from "@internationalized/date"; + +export default function App() { + const variants = ["flat", "bordered", "underlined", "faded"]; + + return ( +
+ {variants.map((variant) => ( +
+ +
+ ))} +
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-picker/controlled.ts b/apps/docs/content/components/date-picker/controlled.ts new file mode 100644 index 0000000000..fdbcded26b --- /dev/null +++ b/apps/docs/content/components/date-picker/controlled.ts @@ -0,0 +1,52 @@ +const App = `import {DatePicker} from "@nextui-org/react"; +import {parseDate, getLocalTimeZone} from "@internationalized/date"; +import {useDateFormatter} from "@react-aria/i18n"; + +export default function App() { + const [value, setValue] = React.useState(parseDate("2024-04-04")); + + let formatter = useDateFormatter({dateStyle: "full"}); + + return ( +
+
+ +

+ Selected date: {value ? formatter.format(value.toDate(getLocalTimeZone())) : "--"} +

+
+ +
+ ); +}`; + +const AppTs = `import {DatePicker} from "@nextui-org/react"; +import {DateValue, parseDate, getLocalTimeZone} from "@internationalized/date"; +import {useDateFormatter} from "@react-aria/i18n"; + +export default function App() { + const [value, setValue] = React.useState(parseDate("2024-04-04")); + + let formatter = useDateFormatter({dateStyle: "full"}); + + return ( +
+
+ +

+ Selected date: {value ? formatter.format(value.toDate(getLocalTimeZone())) : "--"} +

+
+ +
+ ); +}`; + +const react = { + "/App.jsx": App, + "/App.tsx": AppTs, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-picker/description.ts b/apps/docs/content/components/date-picker/description.ts new file mode 100644 index 0000000000..79b1239ba7 --- /dev/null +++ b/apps/docs/content/components/date-picker/description.ts @@ -0,0 +1,21 @@ +const App = `import {DatePicker} from "@nextui-org/react"; + +export default function App() { + return ( +
+ +
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-picker/disabled.ts b/apps/docs/content/components/date-picker/disabled.ts new file mode 100644 index 0000000000..35ac2d8809 --- /dev/null +++ b/apps/docs/content/components/date-picker/disabled.ts @@ -0,0 +1,21 @@ +const App = `import {DatePicker} from "@nextui-org/react"; + +export default function App() { + return ( +
+ +
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-picker/error-message.ts b/apps/docs/content/components/date-picker/error-message.ts new file mode 100644 index 0000000000..d1c85629ae --- /dev/null +++ b/apps/docs/content/components/date-picker/error-message.ts @@ -0,0 +1,22 @@ +const App = `import {DatePicker} from "@nextui-org/react"; + +export default function App() { + return ( +
+ +
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-picker/granularity.ts b/apps/docs/content/components/date-picker/granularity.ts new file mode 100644 index 0000000000..8f74d37aed --- /dev/null +++ b/apps/docs/content/components/date-picker/granularity.ts @@ -0,0 +1,76 @@ +const App = `import {DatePicker} from "@nextui-org/react"; +import {now, parseAbsoluteToLocal} from "@internationalized/date"; +import {useDateFormatter} from "@react-aria/i18n"; + +export default function App() { + let [date, setDate] = React.useState(parseAbsoluteToLocal("2021-04-07T18:45:22Z")); + + return ( +
+ + + + +
+ ); +}`; + +const AppTs = `import {DatePicker} from "@nextui-org/react"; +import {DateValue, now, parseAbsoluteToLocal} from "@internationalized/date"; +import {useDateFormatter} from "@react-aria/i18n"; + +export default function App() { + let [date, setDate] = React.useState(parseAbsoluteToLocal("2021-04-07T18:45:22Z")); + + return ( +
+ + + + +
+ ); +}`; + +const react = { + "/App.jsx": App, + "/App.tsx": AppTs, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-picker/index.ts b/apps/docs/content/components/date-picker/index.ts new file mode 100644 index 0000000000..f46ee40879 --- /dev/null +++ b/apps/docs/content/components/date-picker/index.ts @@ -0,0 +1,43 @@ +import usage from "./usage"; +import disabled from "./disabled"; +import readOnly from "./readonly"; +import required from "./required"; +import variants from "./variants"; +import labelPlacements from "./label-placements"; +import description from "./description"; +import errorMessage from "./error-message"; +import withMonthAndYearPickers from "./with-month-and-year-pickers"; +import withTimeField from "./with-time-field"; +import selectorIcon from "./selector-icon"; +import controlled from "./controlled"; +import timeZones from "./time-zones"; +import granularity from "./granularity"; +import minAndMaxDate from "./min-and-max-date"; +import internationalCalendar from "./international-calendar"; +import unavailableDates from "./unavailable-dates"; +import visibleMonth from "./visible-month"; +import pageBehavior from "./page-behavior"; +import preset from "./preset"; + +export const datePickerContent = { + usage, + disabled, + readOnly, + required, + variants, + labelPlacements, + description, + errorMessage, + withMonthAndYearPickers, + withTimeField, + selectorIcon, + controlled, + timeZones, + granularity, + minAndMaxDate, + internationalCalendar, + unavailableDates, + visibleMonth, + pageBehavior, + preset, +}; diff --git a/apps/docs/content/components/date-picker/international-calendar.ts b/apps/docs/content/components/date-picker/international-calendar.ts new file mode 100644 index 0000000000..ba86ec20fd --- /dev/null +++ b/apps/docs/content/components/date-picker/international-calendar.ts @@ -0,0 +1,54 @@ +const App = `import {DatePicker} from "@nextui-org/react"; +import {now, parseAbsoluteToLocal} from "@internationalized/date"; +import {I18nProvider} from "@react-aria/i18n"; + +export default function App() { + let [date, setDate] = React.useState(parseAbsoluteToLocal("2021-04-07T18:45:22Z")); + + return ( +
+ + + +
+ ); +}`; + +const AppTs = `import {DatePicker} from "@nextui-org/react"; +import {DateValue, now, parseAbsoluteToLocal} from "@internationalized/date"; +import {I18nProvider} from "@react-aria/i18n"; + +export default function App() { + let [date, setDate] = React.useState(parseAbsoluteToLocal("2021-04-07T18:45:22Z")); + + return ( +
+ + + +
+ ); +}`; + +const react = { + "/App.jsx": App, + "/App.tsx": AppTs, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-picker/label-placements.ts b/apps/docs/content/components/date-picker/label-placements.ts new file mode 100644 index 0000000000..abd21541dd --- /dev/null +++ b/apps/docs/content/components/date-picker/label-placements.ts @@ -0,0 +1,34 @@ +const App = `import {DatePicker} from "@nextui-org/react"; + +export default function App() { + const placements = [ + "inside", + "outside", + "outside-left", + ]; + + return ( +
+
+
+ {placements.map((placement) => ( + + ))} +
+
+
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-picker/min-and-max-date.ts b/apps/docs/content/components/date-picker/min-and-max-date.ts new file mode 100644 index 0000000000..bdd9992138 --- /dev/null +++ b/apps/docs/content/components/date-picker/min-and-max-date.ts @@ -0,0 +1,33 @@ +const App = `import {DatePicker} from "@nextui-org/react"; +import {getLocalTimeZone, today} from "@internationalized/date"; + +export default function App() { + return ( +
+
+

Min date

+ +
+
+

Max date

+ +
+
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-picker/page-behavior.ts b/apps/docs/content/components/date-picker/page-behavior.ts new file mode 100644 index 0000000000..dda732673a --- /dev/null +++ b/apps/docs/content/components/date-picker/page-behavior.ts @@ -0,0 +1,21 @@ +const App = `import {DatePicker} from "@nextui-org/react"; + +export default function App() { + return ( +
+ +
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-picker/preset.ts b/apps/docs/content/components/date-picker/preset.ts new file mode 100644 index 0000000000..2de4aecb6e --- /dev/null +++ b/apps/docs/content/components/date-picker/preset.ts @@ -0,0 +1,194 @@ +const App = `import {DatePicker} from "@nextui-org/react"; +import {now, useLocale, startOfWeek, startOfMonth, useDateFormatter, getLocalTimeZone} from "@internationalized/date"; +import {I18nProvider} from "@react-aria/i18n"; + +export default function App() { + let defaultDate = today(getLocalTimeZone()); + + const [value, setValue] = React.useState(defaultDate); + + let {locale} = useLocale(); + let formatter = useDateFormatter({dateStyle: "full"}); + + let now = today(getLocalTimeZone()); + let nextWeek = startOfWeek(now.add({weeks: 1}), locale); + let nextMonth = startOfMonth(now.add({months: 1})); + + const CustomRadio = (props) => { + const {children, ...otherProps} = props; + + return ( + + {children} + + ); + }; + + return ( +
+ + Exact dates + 1 day + 2 days + 3 days + 7 days + 14 days + + } + CalendarTopContent={ + + + + + + } + calendarProps={{ + focusedValue: value, + onFocusChange: setValue, + nextButtonProps: { + variant: "bordered", + }, + prevButtonProps: { + variant: "bordered", + }, + }} + value={value} + onChange={setValue} + label="Event date" + /> +

+ Selected date: {value ? formatter.format(value.toDate(getLocalTimeZone())) : "--"} +

+
+ ); +}`; + +const AppTs = `import {DatePicker} from "@nextui-org/react"; +import {DateValue, now, useLocale, startOfWeek, startOfMonth, useDateFormatter, getLocalTimeZone} from "@internationalized/date"; +import {I18nProvider} from "@react-aria/i18n"; + +export default function App() { + let defaultDate = today(getLocalTimeZone()); + + const [value, setValue] = React.useState(defaultDate); + + let {locale} = useLocale(); + let formatter = useDateFormatter({dateStyle: "full"}); + + let now = today(getLocalTimeZone()); + let nextWeek = startOfWeek(now.add({weeks: 1}), locale); + let nextMonth = startOfMonth(now.add({months: 1})); + + const CustomRadio = (props) => { + const {children, ...otherProps} = props; + + return ( + + {children} + + ); + }; + + return ( +
+ + Exact dates + 1 day + 2 days + 3 days + 7 days + 14 days + + } + CalendarTopContent={ + + + + + + } + calendarProps={{ + focusedValue: value, + onFocusChange: setValue, + nextButtonProps: { + variant: "bordered", + }, + prevButtonProps: { + variant: "bordered", + }, + }} + value={value} + onChange={setValue} + label="Event date" + /> +

+ Selected date: {value ? formatter.format(value.toDate(getLocalTimeZone())) : "--"} +

+
+ ); +}`; + +const react = { + "/App.jsx": App, + "/App.tsx": AppTs, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-picker/readonly.ts b/apps/docs/content/components/date-picker/readonly.ts new file mode 100644 index 0000000000..35ac2d8809 --- /dev/null +++ b/apps/docs/content/components/date-picker/readonly.ts @@ -0,0 +1,21 @@ +const App = `import {DatePicker} from "@nextui-org/react"; + +export default function App() { + return ( +
+ +
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-picker/required.ts b/apps/docs/content/components/date-picker/required.ts new file mode 100644 index 0000000000..c5746bef43 --- /dev/null +++ b/apps/docs/content/components/date-picker/required.ts @@ -0,0 +1,21 @@ +const App = `import {DatePicker} from "@nextui-org/react"; + +export default function App() { + return ( +
+ +
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-picker/selector-icon.ts b/apps/docs/content/components/date-picker/selector-icon.ts new file mode 100644 index 0000000000..b7fd8509eb --- /dev/null +++ b/apps/docs/content/components/date-picker/selector-icon.ts @@ -0,0 +1,38 @@ +const SelectorIcon = `export const SelectorIcon = () => ( + + + + + + + +);`; + +const App = `import {DatePicker} from "@nextui-org/react"; +import {SelectorIcon} from './SelectorIcon'; + +export default function App() { + return ( +
+ } + /> +
+ ); +}`; + +const react = { + "/App.jsx": App, + "/SelectorIcon.jsx": SelectorIcon, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-picker/time-zones.ts b/apps/docs/content/components/date-picker/time-zones.ts new file mode 100644 index 0000000000..354ca45d28 --- /dev/null +++ b/apps/docs/content/components/date-picker/time-zones.ts @@ -0,0 +1,29 @@ +const AppTs = `import {DatePicker} from "@nextui-org/react"; +import {parseZonedDateTime} from "@internationalized/date"; + +export default function App() { + return ( +
+ + +
+ ); +}`; + +const react = { + "/App.tsx": AppTs, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-picker/unavailable-dates.ts b/apps/docs/content/components/date-picker/unavailable-dates.ts new file mode 100644 index 0000000000..93e0606772 --- /dev/null +++ b/apps/docs/content/components/date-picker/unavailable-dates.ts @@ -0,0 +1,38 @@ +const App = `import {DatePicker} from "@nextui-org/react"; +import {today, isWeekend, getLocalTimeZone} from "@internationalized/date"; +import {useLocale} from "@react-aria/i18n"; + +export default function App() { + let now = today(getLocalTimeZone()); + + let disabledRanges = [ + [now, now.add({days: 5})], + [now.add({days: 14}), now.add({days: 16})], + [now.add({days: 23}), now.add({days: 24})], + ]; + + let {locale} = useLocale(); + + let isDateUnavailable = (date) => + isWeekend(date, locale) || + disabledRanges.some( + (interval) => date.compare(interval[0]) >= 0 && date.compare(interval[1]) <= 0, + ); + + return ( + + ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-picker/usage.ts b/apps/docs/content/components/date-picker/usage.ts new file mode 100644 index 0000000000..2f3a5d5ca4 --- /dev/null +++ b/apps/docs/content/components/date-picker/usage.ts @@ -0,0 +1,15 @@ +const App = `import {DatePicker} from "@nextui-org/react"; + +export default function App() { + return ( + + ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-picker/variants.ts b/apps/docs/content/components/date-picker/variants.ts new file mode 100644 index 0000000000..b31ec23aeb --- /dev/null +++ b/apps/docs/content/components/date-picker/variants.ts @@ -0,0 +1,23 @@ +const App = `import {DatePicker} from "@nextui-org/react"; + +export default function App() { + const variants = ["flat", "bordered", "underlined", "faded"]; + + return ( +
+ {variants.map((variant) => ( +
+ +
+ ))} +
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-picker/visible-month.ts b/apps/docs/content/components/date-picker/visible-month.ts new file mode 100644 index 0000000000..2e9f01b039 --- /dev/null +++ b/apps/docs/content/components/date-picker/visible-month.ts @@ -0,0 +1,20 @@ +const App = `import {DatePicker} from "@nextui-org/react"; + +export default function App() { + return ( +
+ +
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-picker/with-month-and-year-pickers.ts b/apps/docs/content/components/date-picker/with-month-and-year-pickers.ts new file mode 100644 index 0000000000..eeb8ae32a1 --- /dev/null +++ b/apps/docs/content/components/date-picker/with-month-and-year-pickers.ts @@ -0,0 +1,21 @@ +const App = `import {DatePicker} from "@nextui-org/react"; + +export default function App() { + return ( +
+ +
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-picker/with-time-field.ts b/apps/docs/content/components/date-picker/with-time-field.ts new file mode 100644 index 0000000000..ef42b982ce --- /dev/null +++ b/apps/docs/content/components/date-picker/with-time-field.ts @@ -0,0 +1,23 @@ +const App = `import {DatePicker} from "@nextui-org/react"; + +export default function App() { + return ( +
+ +
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-range-picker/controlled.ts b/apps/docs/content/components/date-range-picker/controlled.ts new file mode 100644 index 0000000000..12f5e4d8ae --- /dev/null +++ b/apps/docs/content/components/date-range-picker/controlled.ts @@ -0,0 +1,96 @@ +const App = `import {DateRangePicker} from "@nextui-org/react"; +import {parseDate, getLocalTimeZone} from "@internationalized/date"; +import {useDateFormatter} from "@react-aria/i18n"; + +export default function App() { + const [value, setValue] = React.useState({ + start: parseDate("2024-04-01"), + end: parseDate("2024-04-08"), + }); + + let formatter = useDateFormatter({dateStyle: "long"}); + + return ( +
+
+ +

+ Selected date:{" "} + {value + ? formatter.formatRange( + value.start.toDate(getLocalTimeZone()), + value.end.toDate(getLocalTimeZone()), + ) + : "--"} +

+
+ +
+ ); +}`; + +const AppTs = `import {DateRangePicker} from "@nextui-org/react"; +import {parseDate, getLocalTimeZone} from "@internationalized/date"; +import {useDateFormatter} from "@react-aria/i18n"; +import {RangeValue} from "@react-types/shared"; +import {DateValue} from "@react-types/datepicker"; + +export default function App() { + const [value, setValue] = React.useState>({ + start: parseDate("2024-04-01"), + end: parseDate("2024-04-08"), + }); + + let formatter = useDateFormatter({dateStyle: "long"}); + + return ( +
+
+ +

+ Selected date:{" "} + {value + ? formatter.formatRange( + value.start.toDate(getLocalTimeZone()), + value.end.toDate(getLocalTimeZone()), + ) + : "--"} +

+
+ +
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +const reactTs = { + "/App.tsx": AppTs, +}; + +export default { + ...react, + ...reactTs, +}; diff --git a/apps/docs/content/components/date-range-picker/description.ts b/apps/docs/content/components/date-range-picker/description.ts new file mode 100644 index 0000000000..a81889d1bd --- /dev/null +++ b/apps/docs/content/components/date-range-picker/description.ts @@ -0,0 +1,19 @@ +const App = `import {DateRangePicker} from "@nextui-org/react"; + +export default function App() { + return ( + + ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-range-picker/disabled.ts b/apps/docs/content/components/date-range-picker/disabled.ts new file mode 100644 index 0000000000..ea2ff51167 --- /dev/null +++ b/apps/docs/content/components/date-range-picker/disabled.ts @@ -0,0 +1,24 @@ +const App = `import {DateRangePicker} from "@nextui-org/react"; +import {parseDate} from "@internationalized/date"; + +export default function App() { + return ( + + ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-range-picker/error-message.ts b/apps/docs/content/components/date-range-picker/error-message.ts new file mode 100644 index 0000000000..ed0abd8ab5 --- /dev/null +++ b/apps/docs/content/components/date-range-picker/error-message.ts @@ -0,0 +1,26 @@ +const App = `import {DateRangePicker} from "@nextui-org/react"; +import {parseDate} from "@internationalized/date"; + +export default function App() { + return ( + + ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-range-picker/granularity.ts b/apps/docs/content/components/date-range-picker/granularity.ts new file mode 100644 index 0000000000..10094d839a --- /dev/null +++ b/apps/docs/content/components/date-range-picker/granularity.ts @@ -0,0 +1,67 @@ +const App = `import {DateRangePicker} from "@nextui-org/react"; +import {parseAbsoluteToLocal} from "@internationalized/date"; + +export default function App() { + let [date, setDate] = React.useState({ + start: parseAbsoluteToLocal("2024-04-01T18:45:22Z"), + end: parseAbsoluteToLocal("2024-04-08T19:15:22Z"), + }); + + return ( +
+ + +
+ ); +}`; + +const AppTs = `import {DateRangePicker} from "@nextui-org/react"; +import {DateValue, parseAbsoluteToLocal} from "@internationalized/date"; +import {RangeValue} from "@react-types/shared"; + +export default function App() { + let [date, setDate] = React.useState>({ + start: parseAbsoluteToLocal("2024-04-01T18:45:22Z"), + end: parseAbsoluteToLocal("2024-04-08T19:15:22Z"), + }); + + return ( +
+ + +
+ ); +}`; + +const react = { + "/App.jsx": App, + "/App.tsx": AppTs, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-range-picker/index.ts b/apps/docs/content/components/date-range-picker/index.ts new file mode 100644 index 0000000000..b4496b2651 --- /dev/null +++ b/apps/docs/content/components/date-range-picker/index.ts @@ -0,0 +1,43 @@ +import usage from "./usage"; +import disabled from "./disabled"; +import readOnly from "./readonly"; +import required from "./required"; +import variants from "./variants"; +import labelPlacements from "./label-placements"; +import description from "./description"; +import errorMessage from "./error-message"; +import withTimeField from "./with-time-field"; +import selectorIcon from "./selector-icon"; +import controlled from "./controlled"; +import timeZones from "./time-zones"; +import granularity from "./granularity"; +import minAndMaxDate from "./min-and-max-date"; +import internationalCalendar from "./international-calendar"; +import unavailableDates from "./unavailable-dates"; +import visibleMonth from "./visible-month"; +import pageBehavior from "./page-behavior"; +import nonContigous from "./non-contiguous"; +import presets from "./presets"; + +export const dateRangePickerContent = { + usage, + disabled, + readOnly, + required, + variants, + labelPlacements, + description, + errorMessage, + withTimeField, + selectorIcon, + controlled, + timeZones, + granularity, + minAndMaxDate, + internationalCalendar, + unavailableDates, + visibleMonth, + pageBehavior, + nonContigous, + presets, +}; diff --git a/apps/docs/content/components/date-range-picker/international-calendar.ts b/apps/docs/content/components/date-range-picker/international-calendar.ts new file mode 100644 index 0000000000..e28d31e8ea --- /dev/null +++ b/apps/docs/content/components/date-range-picker/international-calendar.ts @@ -0,0 +1,47 @@ +const App = `import {DateRangePicker} from "@nextui-org/react"; +import {parseAbsoluteToLocal} from "@internationalized/date"; +import {I18nProvider} from "@react-aria/i18n"; + +export default function App() { + let [date, setDate] = React.useState({ + start: parseAbsoluteToLocal("2021-04-01T18:45:22Z"), + end: parseAbsoluteToLocal("2021-04-14T19:15:22Z"), + }); + + return ( +
+ + + +
+ ); +}`; + +const AppTs = `import {DateRangePicker} from "@nextui-org/react"; +import {DateValue, parseAbsoluteToLocal} from "@internationalized/date"; +import {RangeValue} from "@react-types/shared"; +import {I18nProvider} from "@react-aria/i18n"; + +export default function App() { + let [date, setDate] = React.useState>({ + start: parseAbsoluteToLocal("2021-04-01T18:45:22Z"), + end: parseAbsoluteToLocal("2021-04-14T19:15:22Z"), + }); + + return ( +
+ + + +
+ ); +}`; + +const react = { + "/App.jsx": App, + "/App.tsx": AppTs, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-range-picker/label-placements.ts b/apps/docs/content/components/date-range-picker/label-placements.ts new file mode 100644 index 0000000000..ae0d8f4c5b --- /dev/null +++ b/apps/docs/content/components/date-range-picker/label-placements.ts @@ -0,0 +1,32 @@ +const App = `import {DateRangePicker} from "@nextui-org/react"; + +export default function App() { + const placements = [ + "inside", + "outside", + "outside-left", + ]; + + return ( +
+
+ {placements.map((placement) => ( + + ))} +
+
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-range-picker/min-and-max-date.ts b/apps/docs/content/components/date-range-picker/min-and-max-date.ts new file mode 100644 index 0000000000..a1db8afe8f --- /dev/null +++ b/apps/docs/content/components/date-range-picker/min-and-max-date.ts @@ -0,0 +1,39 @@ +const App = `import {DateRangePicker} from "@nextui-org/react"; +import {getLocalTimeZone, parseDate, today} from "@internationalized/date"; + +export default function App() { + return ( +
+
+

Min date

+ +
+
+

Max date

+ +
+
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-range-picker/non-contiguous.ts b/apps/docs/content/components/date-range-picker/non-contiguous.ts new file mode 100644 index 0000000000..a85e7f570e --- /dev/null +++ b/apps/docs/content/components/date-range-picker/non-contiguous.ts @@ -0,0 +1,25 @@ +const App = `import {DateRangePicker} from "@nextui-org/react"; +import {isWeekend, today, getLocalTimeZone} from "@internationalized/date"; +import {useLocale} from "@react-aria/i18n"; + +export default function App() { + let {locale} = useLocale(); + + return ( + isWeekend(date, locale)} + label="Time off request" + minValue={today(getLocalTimeZone())} + visibleMonths={2} + /> + ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-range-picker/page-behavior.ts b/apps/docs/content/components/date-range-picker/page-behavior.ts new file mode 100644 index 0000000000..49d92881d7 --- /dev/null +++ b/apps/docs/content/components/date-range-picker/page-behavior.ts @@ -0,0 +1,21 @@ +const App = `import {DateRangePicker} from "@nextui-org/react"; + +export default function App() { + return ( +
+ +
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-range-picker/presets.ts b/apps/docs/content/components/date-range-picker/presets.ts new file mode 100644 index 0000000000..6189a7b04d --- /dev/null +++ b/apps/docs/content/components/date-range-picker/presets.ts @@ -0,0 +1,243 @@ +const App = `import {DateRangePicker, Radio, RadioGroup, Button, ButtonGroup, cn} from "@nextui-org/react"; +import {today, startOfWeek, startOfMonth, endOfWeek, endOfMonth, useDateFormatter, getLocalTimeZone} from "@internationalized/date"; +import {useLocale} from "@react-aria/i18n"; + +export default function App() { + let defaultDate = { + start: today(getLocalTimeZone()), + end: today(getLocalTimeZone()).add({days: 7}), + }; + let [value, setValue] = React.useState(defaultDate); + + let {locale} = useLocale(); + let formatter = useDateFormatter({dateStyle: "full"}); + let now = today(getLocalTimeZone()); + let nextWeek = { + start: startOfWeek(now.add({weeks: 1}), locale), + end: endOfWeek(now.add({weeks: 1}), locale), + }; + let nextMonth = { + start: startOfMonth(now.add({months: 1})), + end: endOfMonth(now.add({months: 1})), + }; + + const CustomRadio = (props) => { + const {children, ...otherProps} = props; + + return ( + + {children} + + ); + }; + + return ( +
+ + Exact dates + 1 day + 2 days + 3 days + 7 days + 14 days + + } + CalendarTopContent={ + + + + + + } + calendarProps={{ + focusedValue: value.start, + onFocusChange: (val) => setValue({...value, start: val}), + nextButtonProps: { + variant: "bordered", + }, + prevButtonProps: { + variant: "bordered", + }, + }} + value={value} + onChange={setValue} + label="Event date" + /> +

+ Selected date:{" "} + {value + ? formatter.formatRange( + value.start.toDate(getLocalTimeZone()), + value.end.toDate(getLocalTimeZone()), + ) + : "--"} +

+
+ ); +}`; + +// const AppTs = `import {DateRangePicker} from "@nextui-org/react"; +// import {now, today, startOfWeek, startOfMonth, useDateFormatter, getLocalTimeZone} from "@internationalized/date"; +// import {useLocale} from "@react-aria/i18n"; +// import {RangeValue} from "@react-types/shared"; + +// export default function App() { +// let defaultDate = { +// start: today(getLocalTimeZone()), +// end: today(getLocalTimeZone()).add({days: 7}), +// }; + +// const [value, setValue] = React.useState>(defaultDate); + +// let {locale} = useLocale(); +// let formatter = useDateFormatter({dateStyle: "full"}); + +// let now = today(getLocalTimeZone()); +// let nextWeek = { +// start: startOfWeek(now.add({weeks: 1}), locale), +// end: endOfWeek(now.add({weeks: 1}), locale), +// }; +// let nextMonth = { +// start: startOfMonth(now.add({months: 1})), +// end: endOfMonth(now.add({months: 1})), +// }; + +// const CustomRadio = (props) => { +// const {children, ...otherProps} = props; + +// return ( +// +// {children} +// +// ); +// }; + +// return ( +//
+// +// Exact dates +// 1 day +// 2 days +// 3 days +// 7 days +// 14 days +// +// } +// CalendarTopContent={ +// +// +// +// +// +// } +// calendarProps={{ +// focusedValue: value.start, +// onFocusChange: (val) => setValue({...value, start: val}), +// nextButtonProps: { +// variant: "bordered", +// }, +// prevButtonProps: { +// variant: "bordered", +// }, +// }} +// value={value} +// onChange={setValue} +// label="Event date" +// /> +//

+// Selected date:{" "} +// {value +// ? formatter.formatRange( +// value.start.toDate(getLocalTimeZone()), +// value.end.toDate(getLocalTimeZone()), +// ) +// : "--"} +//

+//
+// ); +// }`; + +const react = { + "/App.jsx": App, + // "/App.tsx": AppTs, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-range-picker/readonly.ts b/apps/docs/content/components/date-range-picker/readonly.ts new file mode 100644 index 0000000000..4ac98ed8b4 --- /dev/null +++ b/apps/docs/content/components/date-range-picker/readonly.ts @@ -0,0 +1,24 @@ +const App = `import {DateRangePicker} from "@nextui-org/react"; +import {parseDate} from "@internationalized/date"; + +export default function App() { + return ( + + ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-range-picker/required.ts b/apps/docs/content/components/date-range-picker/required.ts new file mode 100644 index 0000000000..c3c9e0bbd1 --- /dev/null +++ b/apps/docs/content/components/date-range-picker/required.ts @@ -0,0 +1,24 @@ +const App = `import {DateRangePicker} from "@nextui-org/react"; +import {parseDate} from "@internationalized/date"; + +export default function App() { + return ( + + ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-range-picker/selector-icon.ts b/apps/docs/content/components/date-range-picker/selector-icon.ts new file mode 100644 index 0000000000..10e4eeb89d --- /dev/null +++ b/apps/docs/content/components/date-range-picker/selector-icon.ts @@ -0,0 +1,37 @@ +const SelectorIcon = `export const SelectorIcon = (props) => ( + + + + + + + +);`; + +const App = `import {DateRangePicker} from "@nextui-org/react"; +import {SelectorIcon} from './SelectorIcon'; +export default function App() { + return ( +
+ } + /> +
+ ); +}`; + +const react = { + "/App.jsx": App, + "/SelectorIcon.jsx": SelectorIcon, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-range-picker/time-zones.ts b/apps/docs/content/components/date-range-picker/time-zones.ts new file mode 100644 index 0000000000..ac08becc56 --- /dev/null +++ b/apps/docs/content/components/date-range-picker/time-zones.ts @@ -0,0 +1,33 @@ +const App = `import {DateRangePicker} from "@nextui-org/react"; +import {parseZonedDateTime, parseAbsoluteToLocal} from "@internationalized/date"; + +export default function App() { + return ( +
+ + +
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-range-picker/unavailable-dates.ts b/apps/docs/content/components/date-range-picker/unavailable-dates.ts new file mode 100644 index 0000000000..c300b5fc5b --- /dev/null +++ b/apps/docs/content/components/date-range-picker/unavailable-dates.ts @@ -0,0 +1,41 @@ +const App = `import {DateRangePicker} from "@nextui-org/react"; +import {today, getLocalTimeZone} from "@internationalized/date"; + +export default function App() { + let now = today(getLocalTimeZone()); + + let disabledRanges = [ + [now, now.add({days: 5})], + [now.add({days: 14}), now.add({days: 16})], + [now.add({days: 23}), now.add({days: 24})], + ]; + + return ( + + disabledRanges.some( + (interval) => date.compare(interval[0]) >= 0 && date.compare(interval[1]) <= 0, + ) + } + minValue={today(getLocalTimeZone())} + validate={(value) => + disabledRanges.some( + (interval) => + value && value.end.compare(interval[0]) >= 0 && value.start.compare(interval[1]) <= 0, + ) + ? "Selected date range may not include unavailable dates." + : null + } + validationBehavior="native" + /> + ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-range-picker/usage.ts b/apps/docs/content/components/date-range-picker/usage.ts new file mode 100644 index 0000000000..b83666a5cb --- /dev/null +++ b/apps/docs/content/components/date-range-picker/usage.ts @@ -0,0 +1,18 @@ +const App = `import {DateRangePicker} from "@nextui-org/react"; + +export default function App() { + return ( + + ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-range-picker/variants.ts b/apps/docs/content/components/date-range-picker/variants.ts new file mode 100644 index 0000000000..668f9c83fe --- /dev/null +++ b/apps/docs/content/components/date-range-picker/variants.ts @@ -0,0 +1,27 @@ +const App = `import {DateRangePicker} from "@nextui-org/react"; + +export default function App() { + const variants = ["flat", "bordered", "underlined", "faded"]; + + return ( +
+ {variants.map((variant) => ( +
+ +
+ ))} +
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-range-picker/visible-month.ts b/apps/docs/content/components/date-range-picker/visible-month.ts new file mode 100644 index 0000000000..0f30be2412 --- /dev/null +++ b/apps/docs/content/components/date-range-picker/visible-month.ts @@ -0,0 +1,20 @@ +const App = `import {DateRangePicker} from "@nextui-org/react"; + +export default function App() { + return ( +
+ +
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/date-range-picker/with-time-field.ts b/apps/docs/content/components/date-range-picker/with-time-field.ts new file mode 100644 index 0000000000..318f9f3770 --- /dev/null +++ b/apps/docs/content/components/date-range-picker/with-time-field.ts @@ -0,0 +1,26 @@ +const App = `import {DateRangePicker} from "@nextui-org/react"; +import {parseZonedDateTime} from "@internationalized/date"; + +export default function App() { + return ( +
+ +
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/popover/placements.ts b/apps/docs/content/components/popover/placements.ts index d5b2442ffa..2ec2ca6021 100644 --- a/apps/docs/content/components/popover/placements.ts +++ b/apps/docs/content/components/popover/placements.ts @@ -17,21 +17,21 @@ export default function App() { "bottom-start", "bottom", "bottom-end", - "left-start", - "left", - "left-end", "right-start", "right", "right-end", + "left-start", + "left", + "left-end", ]; return (
{placements.map((placement) => ( - + - {content} diff --git a/apps/docs/content/components/range-calendar/controlled-focused-value.ts b/apps/docs/content/components/range-calendar/controlled-focused-value.ts new file mode 100644 index 0000000000..94014c4cd2 --- /dev/null +++ b/apps/docs/content/components/range-calendar/controlled-focused-value.ts @@ -0,0 +1,23 @@ +const App = `import {RangeCalendar} from "@nextui-org/react"; +import {today, getLocalTimeZone} from "@internationalized/date"; + +export default function App() { + let defaultDate = today(getLocalTimeZone()); + let [focusedDate, setFocusedDate] = React.useState(defaultDate); + + return ( + + ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/range-calendar/controlled.ts b/apps/docs/content/components/range-calendar/controlled.ts new file mode 100644 index 0000000000..2544a02634 --- /dev/null +++ b/apps/docs/content/components/range-calendar/controlled.ts @@ -0,0 +1,46 @@ +const App = `import {RangeCalendar} from "@nextui-org/react"; +import {today, getLocalTimeZone} from "@internationalized/date"; + +export default function App() { + let [value, setValue] = React.useState({ + start: today(getLocalTimeZone()), + end: today(getLocalTimeZone()).add({weeks: 1}), + }); + + return ( + + ); +}`; + +const AppTs = `import {RangeCalendar} from "@nextui-org/react"; +import type {DateValue} from "@react-types/calendar"; +import type {RangeValue} from "@react-types/shared"; +import {today, getLocalTimeZone} from "@internationalized/date"; + +export default function App() { + let [value, setValue] = React.useState>({ + start: today(getLocalTimeZone()), + end: today(getLocalTimeZone()).add({weeks: 1}), + }); + + return ( + + ); +}`; + +const react = { + "/App.jsx": App, + "/App.tsx": AppTs, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/range-calendar/disabled.ts b/apps/docs/content/components/range-calendar/disabled.ts new file mode 100644 index 0000000000..80f5d578ec --- /dev/null +++ b/apps/docs/content/components/range-calendar/disabled.ts @@ -0,0 +1,15 @@ +const App = `import {RangeCalendar} from "@nextui-org/react"; + +export default function App() { + return ( + + ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/range-calendar/index.ts b/apps/docs/content/components/range-calendar/index.ts new file mode 100644 index 0000000000..9b92f64465 --- /dev/null +++ b/apps/docs/content/components/range-calendar/index.ts @@ -0,0 +1,31 @@ +import usage from "./usage"; +import disabled from "./disabled"; +import readonly from "./read-only"; +import controlled from "./controlled"; +import minDateValue from "./min-date-value"; +import maxDateValue from "./max-date-value"; +import unavailableDates from "./unavailable-dates"; +import controlledFocusedValue from "./controlled-focused-value"; +import invalidDate from "./invalid-date"; +import nonContiguousRanges from "./non-contiguous-ranges"; +import internationalCalendars from "./international-calendars"; +import visibleMonths from "./visible-months"; +import pageBehaviour from "./page-behaviour"; +import presets from "./presets"; + +export const rangeCalendarContent = { + usage, + disabled, + readonly, + controlled, + minDateValue, + maxDateValue, + unavailableDates, + controlledFocusedValue, + invalidDate, + nonContiguousRanges, + internationalCalendars, + visibleMonths, + pageBehaviour, + presets, +}; diff --git a/apps/docs/content/components/range-calendar/international-calendars.ts b/apps/docs/content/components/range-calendar/international-calendars.ts new file mode 100644 index 0000000000..bd4fac3ffc --- /dev/null +++ b/apps/docs/content/components/range-calendar/international-calendars.ts @@ -0,0 +1,18 @@ +const App = `import {RangeCalendar} from "@nextui-org/react"; +import {I18nProvider} from "@react-aria/i18n"; + +export default function App() { + return ( + + + + ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/range-calendar/invalid-date.ts b/apps/docs/content/components/range-calendar/invalid-date.ts new file mode 100644 index 0000000000..4e053c0658 --- /dev/null +++ b/apps/docs/content/components/range-calendar/invalid-date.ts @@ -0,0 +1,58 @@ +const App = `import {RangeCalendar} from "@nextui-org/react"; +import {today, getLocalTimeZone, isWeekend} from "@internationalized/date"; +import {useLocale} from "@react-aria/i18n"; + + +export default function App() { + let [date, setDate] = React.useState({ + start: today(getLocalTimeZone()), + end: today(getLocalTimeZone()).add({weeks: 1}), + }); + let {locale} = useLocale(); + let isInvalid = isWeekend(date.start, locale) || isWeekend(date.end, locale); + + return ( + + ); +}`; + +const AppTs = `import {RangeCalendar} from "@nextui-org/react"; +import type {DateValue} from "@react-types/calendar"; +import type {RangeValue} from "@react-types/shared"; +import {today, getLocalTimeZone, isWeekend} from "@internationalized/date"; +import {useLocale} from "@react-aria/i18n"; + + +export default function App() { + let [date, setDate] = React.useState>({ + start: today(getLocalTimeZone()), + end: today(getLocalTimeZone()).add({weeks: 1}), + }); + let {locale} = useLocale(); + let isInvalid = isWeekend(date.start, locale) || isWeekend(date.end, locale); + + return ( + + ); +}`; + +const react = { + "/App.jsx": App, + "/App.tsx": AppTs, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/range-calendar/max-date-value.ts b/apps/docs/content/components/range-calendar/max-date-value.ts new file mode 100644 index 0000000000..32c1359e13 --- /dev/null +++ b/apps/docs/content/components/range-calendar/max-date-value.ts @@ -0,0 +1,19 @@ +const App = `import {RangeCalendar} from "@nextui-org/react"; +import {today, getLocalTimeZone} from "@internationalized/date"; + +export default function App() { + return ( + + ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/range-calendar/min-date-value.ts b/apps/docs/content/components/range-calendar/min-date-value.ts new file mode 100644 index 0000000000..602cb5d6a1 --- /dev/null +++ b/apps/docs/content/components/range-calendar/min-date-value.ts @@ -0,0 +1,19 @@ +const App = `import {RangeCalendar} from "@nextui-org/react"; +import {today, getLocalTimeZone} from "@internationalized/date"; + +export default function App() { + return ( + + ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/range-calendar/non-contiguous-ranges.ts b/apps/docs/content/components/range-calendar/non-contiguous-ranges.ts new file mode 100644 index 0000000000..15c294adb7 --- /dev/null +++ b/apps/docs/content/components/range-calendar/non-contiguous-ranges.ts @@ -0,0 +1,23 @@ +const App = `import {RangeCalendar} from "@nextui-org/react"; +import {isWeekend} from "@internationalized/date"; +import {useLocale} from "@react-aria/i18n"; + +export default function App() { + let {locale} = useLocale(); + + return ( + isWeekend(date, locale)} + /> + ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/range-calendar/page-behaviour.ts b/apps/docs/content/components/range-calendar/page-behaviour.ts new file mode 100644 index 0000000000..3408f23cc9 --- /dev/null +++ b/apps/docs/content/components/range-calendar/page-behaviour.ts @@ -0,0 +1,18 @@ +const App = `import {RangeCalendar} from "@nextui-org/react"; + +export default function App() { + return ( + + ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/range-calendar/presets.ts b/apps/docs/content/components/range-calendar/presets.ts new file mode 100644 index 0000000000..a6157ae288 --- /dev/null +++ b/apps/docs/content/components/range-calendar/presets.ts @@ -0,0 +1,248 @@ +const App = `import {RangeCalendar, Radio, RadioGroup, Button, ButtonGroup, cn} from "@nextui-org/react"; +import {today, getLocalTimeZone, startOfWeek, startOfMonth} from "@internationalized/date"; +import {useLocale} from "@react-aria/i18n"; + +export default function App() { + let [value, setValue] = React.useState({ + start: today(getLocalTimeZone()), + end: today(getLocalTimeZone()).add({weeks: 1, days: 3}), + }); + let [focusedValue, setFocusedValue] = React.useState(today(getLocalTimeZone())); + + let {locale} = useLocale(); + + let now = today(getLocalTimeZone()); + let nextMonth = now.add({months: 1}); + + let nextWeek = { + start: startOfWeek(now.add({weeks: 1}), locale), + end: endOfWeek(now.add({weeks: 1}), locale), + }; + let thisMonth = {start: startOfMonth(now), end: endOfMonth(now)}; + let nextMonthValue = {start: startOfMonth(nextMonth), end: endOfMonth(nextMonth)}; + + + const CustomRadio = (props) => { + const {children, ...otherProps} = props; + + return ( + + {children} + + ); + }; + + return ( +
+ + Exact dates + 1 day + 2 days + 3 days + 7 days + 14 days + + } + classNames={{ + content: "w-full", + }} + focusedValue={focusedValue} + nextButtonProps={{ + variant: "bordered", + }} + prevButtonProps={{ + variant: "bordered", + }} + topContent={ + + + + + + } + value={value} + onChange={setValue} + onFocusChange={setFocusedValue} + /> +
+ ); +}`; + +const AppTs = `import {RangeCalendar, Radio, RadioGroup, Button, ButtonGroup, cn} from "@nextui-org/react"; +import type {DateValue} from "@react-types/calendar"; +import type {RangeValue} from "@react-types/shared"; +import {today, getLocalTimeZone, startOfWeek, startOfMonth} from "@internationalized/date"; +import {useLocale} from "@react-aria/i18n"; + +export default function App() { + let [value, setValue] = React.useState>({ + start: today(getLocalTimeZone()), + end: today(getLocalTimeZone()).add({weeks: 1, days: 3}), + }); + + let [focusedValue, setFocusedValue] = React.useState(today(getLocalTimeZone())); + + let {locale} = useLocale(); + + let now = today(getLocalTimeZone()); + let nextMonth = now.add({months: 1}); + + let nextWeek = { + start: startOfWeek(now.add({weeks: 1}), locale), + end: endOfWeek(now.add({weeks: 1}), locale), + }; + let thisMonth = {start: startOfMonth(now), end: endOfMonth(now)}; + let nextMonthValue = {start: startOfMonth(nextMonth), end: endOfMonth(nextMonth)}; + + + const CustomRadio = (props) => { + const {children, ...otherProps} = props; + + return ( + + {children} + + ); + }; + + return ( +
+ + Exact dates + 1 day + 2 days + 3 days + 7 days + 14 days + + } + focusedValue={focusedValue} + nextButtonProps={{ + variant: "bordered", + }} + prevButtonProps={{ + variant: "bordered", + }} + topContent={ + + + + + + } + value={value} + onChange={setValue} + onFocusChange={setFocusedValue} + /> +
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +const reactTs = { + "/App.tsx": AppTs, +}; + +export default { + ...react, + ...reactTs, +}; diff --git a/apps/docs/content/components/range-calendar/read-only.ts b/apps/docs/content/components/range-calendar/read-only.ts new file mode 100644 index 0000000000..1badad0004 --- /dev/null +++ b/apps/docs/content/components/range-calendar/read-only.ts @@ -0,0 +1,23 @@ +const App = `import {RangeCalendar} from "@nextui-org/react"; +import {today, getLocalTimeZone} from "@internationalized/date"; + +export default function App() { + return ( + + ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/range-calendar/unavailable-dates.ts b/apps/docs/content/components/range-calendar/unavailable-dates.ts new file mode 100644 index 0000000000..6d656ff8f3 --- /dev/null +++ b/apps/docs/content/components/range-calendar/unavailable-dates.ts @@ -0,0 +1,37 @@ +const App = `import {RangeCalendar} from "@nextui-org/react"; +import {today, getLocalTimeZone, isWeekend} from "@internationalized/date"; +import {useLocale} from "@react-aria/i18n"; + + +export default function App() { + let now = today(getLocalTimeZone()); + + let disabledRanges = [ + [now, now.add({days: 5})], + [now.add({days: 14}), now.add({days: 16})], + [now.add({days: 23}), now.add({days: 24})], + ]; + + let {locale} = useLocale(); + + let isDateUnavailable = (date) => + isWeekend(date, locale) || + disabledRanges.some( + (interval) => date.compare(interval[0]) >= 0 && date.compare(interval[1]) <= 0, + ); + + return ( + + ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/range-calendar/usage.ts b/apps/docs/content/components/range-calendar/usage.ts new file mode 100644 index 0000000000..7cbaeec6e0 --- /dev/null +++ b/apps/docs/content/components/range-calendar/usage.ts @@ -0,0 +1,25 @@ +const App = `import {RangeCalendar} from "@nextui-org/react"; +import {today, getLocalTimeZone} from '@internationalized/date'; + +export default function App() { + return ( +
+ + +
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/range-calendar/visible-months.ts b/apps/docs/content/components/range-calendar/visible-months.ts new file mode 100644 index 0000000000..a669107921 --- /dev/null +++ b/apps/docs/content/components/range-calendar/visible-months.ts @@ -0,0 +1,18 @@ +const App = `import {RangeCalendar} from "@nextui-org/react"; + +export default function App() { + return ( + + ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/select/custom-styles.ts b/apps/docs/content/components/select/custom-styles.ts index 57307ab618..d4e080e1d6 100644 --- a/apps/docs/content/components/select/custom-styles.ts +++ b/apps/docs/content/components/select/custom-styles.ts @@ -213,7 +213,7 @@ export default function App() { variant="bordered" classNames={{ label: "group-data-[filled=true]:-translate-y-5", - trigger: "min-h-unit-16", + trigger: "min-h-16", listboxWrapper: "max-h-[400px]", }} listboxProps={{ diff --git a/apps/docs/content/components/select/multiple-chips.ts b/apps/docs/content/components/select/multiple-chips.ts index 9cf2a3c78f..d8e695c0b5 100644 --- a/apps/docs/content/components/select/multiple-chips.ts +++ b/apps/docs/content/components/select/multiple-chips.ts @@ -216,7 +216,7 @@ export default function App() { labelPlacement="outside" classNames={{ base: "max-w-xs", - trigger: "min-h-unit-12 py-2", + trigger: "min-h-12 py-2", }} renderValue={(items) => { return ( @@ -269,7 +269,7 @@ export default function App() { labelPlacement="outside" classNames={{ base: "max-w-xs", - trigger: "min-h-unit-12 py-2", + trigger: "min-h-12 py-2", }} renderValue={(items: SelectedItems) => { return ( diff --git a/apps/docs/content/components/tabs/index.ts b/apps/docs/content/components/tabs/index.ts index ada7d55342..62c77733c7 100644 --- a/apps/docs/content/components/tabs/index.ts +++ b/apps/docs/content/components/tabs/index.ts @@ -10,6 +10,8 @@ import icons from "./icons"; import form from "./form"; import controlled from "./controlled"; import customStyles from "./custom-styles"; +import placement from "./placement"; +import vertical from "./vertical"; export const tabsContent = { usage, @@ -24,4 +26,6 @@ export const tabsContent = { form, controlled, customStyles, + placement, + vertical, }; diff --git a/apps/docs/content/components/tabs/placement.ts b/apps/docs/content/components/tabs/placement.ts new file mode 100644 index 0000000000..7f720ac41b --- /dev/null +++ b/apps/docs/content/components/tabs/placement.ts @@ -0,0 +1,54 @@ +const App = `import {Tabs, Tab, Card, CardBody, RadioGroup, Radio} from "@nextui-org/react"; + +export default function App() { + const [placement, setPlacement] = React.useState("top"); + return ( +
+ setPlacement(value)} + > + top + bottom + start + end + +
+ + + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. + + + + + + + Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. + + + + + + + Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. + + + + +
+
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/tabs/vertical.ts b/apps/docs/content/components/tabs/vertical.ts new file mode 100644 index 0000000000..7487c22bb1 --- /dev/null +++ b/apps/docs/content/components/tabs/vertical.ts @@ -0,0 +1,45 @@ +const App = `import {Tabs, Tab, Card, CardBody, Switch} from "@nextui-org/react"; + +export default function App() { + const [isVertical, setIsVertical] = React.useState(true); + return ( +
+ + Vertical + +
+ + + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. + + + + + + + Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. + + + + + + + Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. + + + + +
+
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/time-input/controlled.ts b/apps/docs/content/components/time-input/controlled.ts new file mode 100644 index 0000000000..edde086089 --- /dev/null +++ b/apps/docs/content/components/time-input/controlled.ts @@ -0,0 +1,63 @@ +const App = `import {TimeInput} from "@nextui-org/react"; +import {parseAbsoluteToLocal, Time, ZonedDateTime} from "@internationalized/date"; +import {useDateFormatter} from "@react-aria/i18n"; + +export default function App() { + let [value, setValue] = React.useState(parseAbsoluteToLocal("2024-04-08T18:45:22Z")); + + let formatter = useDateFormatter({dateStyle: "short", timeStyle: "long"}); + + return ( +
+
+ +

+ {value instanceof ZonedDateTime + ? (value.toDate && formatter.format(value.toDate())) || + (value && value.toString()) || + "--" + : ""} +

+
+ + +
+ ); +}`; + +const AppTs = `import {TimeInput} from "@nextui-org/react"; +import type {TimeValue} from "@react-types/datepicker"; +import {parseAbsoluteToLocal, Time, ZonedDateTime} from "@internationalized/date"; +import {useDateFormatter} from "@react-aria/i18n"; + +export default function App() { + let [value, setValue] = React.useState(parseAbsoluteToLocal("2024-04-08T18:45:22Z")); + + let formatter = useDateFormatter({dateStyle: "short", timeStyle: "long"}); + + return ( +
+
+ +

+ {value instanceof ZonedDateTime + ? (value.toDate && formatter.format(value.toDate())) || + (value && value.toString()) || + "--" + : ""} +

+
+ + +
+ ); +}`; + +const react = { + "/App.jsx": App, + "/App.tsx": AppTs, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/time-input/disabled.ts b/apps/docs/content/components/time-input/disabled.ts new file mode 100644 index 0000000000..c9b3cccae9 --- /dev/null +++ b/apps/docs/content/components/time-input/disabled.ts @@ -0,0 +1,20 @@ +const App = `import {TimeInput} from "@nextui-org/react"; +import {Time} from "@internationalized/date"; + +export default function App() { + return ( + + ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/time-input/end-content.ts b/apps/docs/content/components/time-input/end-content.ts new file mode 100644 index 0000000000..a97f942a07 --- /dev/null +++ b/apps/docs/content/components/time-input/end-content.ts @@ -0,0 +1,43 @@ +const ClockCircleLinearIcon = `export const ClockCircleLinearIcon = (props) => ( + +);`; + +const App = `import {TimeInput} from "@nextui-org/react"; +import {ClockCircleLinearIcon} from './ClockCircleLinearIcon'; +import {Time} from "@internationalized/date"; + +export default function App() { + return ( + + )} + /> + ); +}`; + +const react = { + "/App.jsx": App, + "/ClockCircleLinearIcon.jsx": ClockCircleLinearIcon, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/time-input/granularity.ts b/apps/docs/content/components/time-input/granularity.ts new file mode 100644 index 0000000000..e7d333d1bb --- /dev/null +++ b/apps/docs/content/components/time-input/granularity.ts @@ -0,0 +1,39 @@ +const App = `import {TimeInput} from "@nextui-org/react"; +import {Time, parseAbsoluteToLocal} from "@internationalized/date"; + +export default function App() { + let [date, setDate] = React.useState(parseAbsoluteToLocal("2021-04-07T18:45:22Z")); + + return ( +
+ + + +
+ ); +}`; + +const AppTs = `import {TimeInput} from "@nextui-org/react"; +import type {TimeValue} from "@react-types/datepicker"; +import {Time, parseAbsoluteToLocal} from "@internationalized/date"; + +export default function App() { + let [date, setDate] = React.useState(parseAbsoluteToLocal("2021-04-07T18:45:22Z")); + + return ( +
+ + + +
+ ); +}`; + +const react = { + "/App.jsx": App, + "/App.tsx": AppTs, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/time-input/hide-timezone.ts b/apps/docs/content/components/time-input/hide-timezone.ts new file mode 100644 index 0000000000..3f40c75747 --- /dev/null +++ b/apps/docs/content/components/time-input/hide-timezone.ts @@ -0,0 +1,20 @@ +const App = `import {TimeInput} from "@nextui-org/react"; +import {parseZonedDateTime} from "@internationalized/date"; + +export default function App() { + return ( + + ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/time-input/hour-cycle.ts b/apps/docs/content/components/time-input/hour-cycle.ts new file mode 100644 index 0000000000..2eb449f7cc --- /dev/null +++ b/apps/docs/content/components/time-input/hour-cycle.ts @@ -0,0 +1,21 @@ +const App = `import {TimeInput} from "@nextui-org/react"; +import {Time, parseZonedDateTime} from "@internationalized/date"; + +export default function App() { + return ( + + ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/time-input/index.ts b/apps/docs/content/components/time-input/index.ts new file mode 100644 index 0000000000..de077dbed2 --- /dev/null +++ b/apps/docs/content/components/time-input/index.ts @@ -0,0 +1,37 @@ +import usage from "./usage"; +import required from "./required"; +import disabled from "./disabled"; +import readonly from "./read-only"; +import withoutLabel from "./without-label"; +import withDescription from "./with-description"; +import labelPlacement from "./label-placement"; +import startContent from "./start-content"; +import endContent from "./end-content"; +import controlled from "./controlled"; +import timezones from "./timezones"; +import granularity from "./granularity"; +import minTimeValue from "./min-time-value"; +import maxTimeValue from "./max-time-value"; +import placeholderValue from "./placeholder-value"; +import hideTimeZone from "./hide-timezone"; +import hourCycle from "./hour-cycle"; + +export const timeInputContent = { + usage, + required, + disabled, + readonly, + withoutLabel, + withDescription, + labelPlacement, + startContent, + endContent, + controlled, + timezones, + granularity, + minTimeValue, + maxTimeValue, + placeholderValue, + hideTimeZone, + hourCycle, +}; diff --git a/apps/docs/content/components/time-input/label-placement.ts b/apps/docs/content/components/time-input/label-placement.ts new file mode 100644 index 0000000000..d76a98f8e9 --- /dev/null +++ b/apps/docs/content/components/time-input/label-placement.ts @@ -0,0 +1,35 @@ +const App = `import {TimeInput} from "@nextui-org/react"; +import {Time} from "@internationalized/date"; + +export default function App() { + return ( +
+ + + +
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/time-input/max-time-value.ts b/apps/docs/content/components/time-input/max-time-value.ts new file mode 100644 index 0000000000..711a1d7268 --- /dev/null +++ b/apps/docs/content/components/time-input/max-time-value.ts @@ -0,0 +1,19 @@ +const App = `import {TimeInput} from "@nextui-org/react"; +import {Time} from "@internationalized/date"; + +export default function App() { + return ( + + ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/time-input/min-time-value.ts b/apps/docs/content/components/time-input/min-time-value.ts new file mode 100644 index 0000000000..be780a3fbf --- /dev/null +++ b/apps/docs/content/components/time-input/min-time-value.ts @@ -0,0 +1,19 @@ +const App = `import {TimeInput} from "@nextui-org/react"; +import {Time} from "@internationalized/date"; + +export default function App() { + return ( + + ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/time-input/placeholder-value.ts b/apps/docs/content/components/time-input/placeholder-value.ts new file mode 100644 index 0000000000..7f329f9470 --- /dev/null +++ b/apps/docs/content/components/time-input/placeholder-value.ts @@ -0,0 +1,19 @@ +const App = `import {TimeInput} from "@nextui-org/react"; +import {Time} from "@internationalized/date"; + +export default function App() { + return ( + + ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/time-input/read-only.ts b/apps/docs/content/components/time-input/read-only.ts new file mode 100644 index 0000000000..15d54d38fb --- /dev/null +++ b/apps/docs/content/components/time-input/read-only.ts @@ -0,0 +1,20 @@ +const App = `import {TimeInput} from "@nextui-org/react"; +import {Time} from "@internationalized/date"; + +export default function App() { + return ( + + ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/time-input/required.ts b/apps/docs/content/components/time-input/required.ts new file mode 100644 index 0000000000..33a1e7e0ac --- /dev/null +++ b/apps/docs/content/components/time-input/required.ts @@ -0,0 +1,18 @@ +const App = `import {TimeInput} from "@nextui-org/react"; + +export default function App() { + return ( + + ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/time-input/start-content.ts b/apps/docs/content/components/time-input/start-content.ts new file mode 100644 index 0000000000..bf5c488177 --- /dev/null +++ b/apps/docs/content/components/time-input/start-content.ts @@ -0,0 +1,43 @@ +const ClockCircleLinearIcon = `export const ClockCircleLinearIcon = (props) => ( + +);`; + +const App = `import {TimeInput} from "@nextui-org/react"; +import {ClockCircleLinearIcon} from './ClockCircleLinearIcon'; +import {Time} from "@internationalized/date"; + +export default function App() { + return ( + + )} + /> + ); +}`; + +const react = { + "/App.jsx": App, + "/ClockCircleLinearIcon.jsx": ClockCircleLinearIcon, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/time-input/timezones.ts b/apps/docs/content/components/time-input/timezones.ts new file mode 100644 index 0000000000..7faa8d00c7 --- /dev/null +++ b/apps/docs/content/components/time-input/timezones.ts @@ -0,0 +1,25 @@ +const App = `import {TimeInput} from "@nextui-org/react"; +import {Time, parseZonedDateTime, parseAbsoluteToLocal} from "@internationalized/date"; + +export default function App() { + return ( +
+ + +
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/time-input/usage.ts b/apps/docs/content/components/time-input/usage.ts new file mode 100644 index 0000000000..4953e39fde --- /dev/null +++ b/apps/docs/content/components/time-input/usage.ts @@ -0,0 +1,19 @@ +const App = `import {TimeInput} from "@nextui-org/react"; +import {Time} from "@internationalized/date"; + +export default function App() { + return ( +
+ + +
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/time-input/with-description.ts b/apps/docs/content/components/time-input/with-description.ts new file mode 100644 index 0000000000..faf8b757aa --- /dev/null +++ b/apps/docs/content/components/time-input/with-description.ts @@ -0,0 +1,18 @@ +const App = `import {TimeInput} from "@nextui-org/react"; + +export default function App() { + return ( + + ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/components/time-input/without-label.ts b/apps/docs/content/components/time-input/without-label.ts new file mode 100644 index 0000000000..88f073e25e --- /dev/null +++ b/apps/docs/content/components/time-input/without-label.ts @@ -0,0 +1,16 @@ +const App = `import {TimeInput} from "@nextui-org/react"; +import {Time} from "@internationalized/date"; + +export default function App() { + return ( + + ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/customization/colors/semantic-colors.ts b/apps/docs/content/customization/colors/semantic-colors.ts index f2b253bb47..090451e040 100644 --- a/apps/docs/content/customization/colors/semantic-colors.ts +++ b/apps/docs/content/customization/colors/semantic-colors.ts @@ -1,6 +1,6 @@ const App = `export default function App() { return ( -
+
This is a primary color box
); diff --git a/apps/docs/content/customization/custom-variants/no-slots-component.ts b/apps/docs/content/customization/custom-variants/no-slots-component.ts index a7b72a9ef5..041c11321a 100644 --- a/apps/docs/content/customization/custom-variants/no-slots-component.ts +++ b/apps/docs/content/customization/custom-variants/no-slots-component.ts @@ -11,9 +11,9 @@ const MyButton = extendVariants(Button, { true: "bg-[#eaeaea] text-[#000] opacity-50 cursor-not-allowed", }, size: { - xs: "px-unit-2 min-w-unit-12 h-unit-6 text-tiny gap-unit-1 rounded-small", - md: "px-unit-4 min-w-unit-20 h-unit-10 text-small gap-unit-2 rounded-small", - xl: "px-unit-8 min-w-unit-28 h-unit-14 text-large gap-unit-4 rounded-medium", + xs: "px-2 min-w-12 h-6 text-tiny gap-1 rounded-small", + md: "px-4 min-w-20 h-10 text-small gap-2 rounded-small", + xl: "px-8 min-w-28 h-14 text-large gap-4 rounded-medium", }, }, defaultVariants: { diff --git a/apps/docs/content/customization/custom-variants/slots-component.ts b/apps/docs/content/customization/custom-variants/slots-component.ts index 3e670ad287..c1fd3c86cd 100644 --- a/apps/docs/content/customization/custom-variants/slots-component.ts +++ b/apps/docs/content/customization/custom-variants/slots-component.ts @@ -63,15 +63,15 @@ const MyInput = extendVariants(Input, { }, size: { xs: { - inputWrapper: "h-unit-6 min-h-unit-6 px-1", + inputWrapper: "h-6 min-h-6 px-1", input: "text-tiny", }, md: { - inputWrapper: "h-unit-10 min-h-unit-10", + inputWrapper: "h-10 min-h-10", input: "text-small", }, xl: { - inputWrapper: "h-unit-14 min-h-unit-14", + inputWrapper: "h-14 min-h-14", input: "text-medium", }, }, diff --git a/apps/docs/content/docs/api-references/cli-api.mdx b/apps/docs/content/docs/api-references/cli-api.mdx new file mode 100644 index 0000000000..8e4b283fbd --- /dev/null +++ b/apps/docs/content/docs/api-references/cli-api.mdx @@ -0,0 +1,370 @@ +--- +title: NextUI CLI +description: API References for NextUI CLI +--- + +# NextUI CLI + +------ + +Here's the API reference for the `NextUI CLI`. + +Once the `CLI` is installed, run the following command to display available commands: + +To get a list of the available CLI commands, run the following command inside your project directory: + +```codeBlock bash +nextui -h +``` + +This will produce the following help output: + +```codeBlock bash +NextUI CLI + +A command line tool for seamless integration with NextUI + +Usage: nextui [command] + +Options: + -v, --version Show the version number + -h, --help Display help for commands + +Commands: + init [options] [projectName] Start a new NextUI project + add [options] [components...] Add NextUI components to your project + upgrade [options] [components...] Update NextUI components to the latest versions + remove [options] [components...] Remove NextUI components from your project + list [options] Show details of installed components + env [options] Display debug information about the local environment + doctor [options] Diagnose problems in your project + help [command] Get help on a specific command +``` + +## init + +To start a new project, use the init command: + +```codeBlock bash +nextui init [projectName] [options] +``` +### Options + +- `-t --template [string]` The template to use for the new project e.g. app, pages + +### Example + +```codeBlock bash +nextui init my-nextui-app -t app +``` + +## add + +> 1. Auto add the missing required `dependencies` to your project +> 2. Auto add the required `tailwindcss.config.js` configuration to your project +> 3. Detect whether using pnpm, if so, add the required configuration to your `.npmrc` file + +To add components to your project, use the add command: + +```codeBlock bash +nextui add [components...] [options] +``` + +### Options + +- `-a --all` [boolean] Add all the NextUI components (default: `false`) +- `-p --packagePath` [string] The path to the package.json file +- `-tw --tailwindPath` [string] The path to the tailwind.config file file +- `-app --appPath` [string] The path to the App.tsx file +- `--prettier` [boolean] Add prettier format in the add content which required installed prettier - (default: false) +- `--addApp` [boolean] Add App.tsx file content which required provider (default: `false`) + + +### Example + +Without setting a specific component, the `add` command will show a list of available components. + +```codeBlock bash +nextui add +``` + +Output: + +```codeBlock bash +NextUI CLI v0.1.2 + +? Which components would you like to add? › - Space to select. Return to submit +Instructions: + ↑/↓: Highlight option + ←/→/[space]: Toggle selection + [a,b,c]/delete: Filter choices + enter/return: Complete answer + +Filtered results for: Enter something to filter + +◉ accordion +◯ autocomplete +◯ avatar +◯ badge +◯ breadcrumbs +◯ button +◯ card +◯ checkbox +◯ chip +◯ code +``` + +If you want to add a specific component, you can specify the component name. + +```codeBlock bash +nextui add button input +``` + +Output: + +```bash +NextUI CLI v0.1.2 + +Adding the required dependencies: @nextui-org/button + +pnpm add @nextui-org/button +Packages: +1 ++ +Progress: resolved 470, reused 462, downloaded 0, added 0, done + +dependencies: ++ @nextui-org/button 2.0.24 + +Done in 3.4s + +Tailwind CSS settings have been updated in: /project-path/tailwind.config.js + +✅ Components added successfully +``` + + +## upgrade + +Upgrade the NextUI components to the latest version. + +```codeBlock bash +nextui upgrade [components...] [options] +``` + +### Options + +- `-p --packagePath` [string] The path to the package.json file. +- `-a --all` [boolean] Upgrade all the NextUI components (default: `false`). +- `-h, --help` Display help for commands. + + +### Example + +```codeBlock bash +nextui upgrade button +``` + + +Output: + +```bash +NextUI CLI v0.1.2 + +╭───────────────────────────────────────────────────────────╮ +│ @nextui-org/button 2.0.24 -> 2.0.27 │ +╰───────────────────────────────────────────────────────────╯ +? Would you like to proceed with the upgrade? › - Use arrow-keys. Return to submit. +❯ Yes + No + +pnpm add @nextui-org/button@2.0.27 +Already up to date +Progress: resolved 474, reused 465, downloaded 0, added 0, done +Done in 2.9s + +✅ Upgrade complete. All components are up to date. +``` + +## remove + +Remove NextUI components from your project. + +> **Note**: If there are no NextUI components after removing, the required content will also be removed._createMdxContent + + ```codeBlock bash + nextui remove [components...] [options] + ``` + + +### Options + +- `-p --packagePath` [string] The path to the package.json file. +- `-a --all` [boolean] Remove all the NextUI components (default: `false`). +- `-tw --tailwindPath` [string] The path to the tailwind.config file file. +- `--prettier` [boolean] Add prettier format in the add content which required installed prettier - (default: false). + + +### Example + +```codeBlock bash +nextui remove button +``` + +Output: + +```bash +NextUI CLI v0.1.2 + +❗️ Components slated for removal: +╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ +│ Package │ Version │ Status │ Docs │ +│──────────────────────────────────────────────────────────────────────────────────────────────────────────────│ +│ @nextui-org/button │ 2.0.27 🚀latest │ stable │ https://nextui.org/docs/components/button │ +╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ +? Confirm removal of these components: › - Use arrow-keys. Return to submit. +❯ Yes + No + +pnpm remove @nextui-org/button +Already up to date +Progress: resolved 474, reused 465, downloaded 0, added 0, done + +dependencies: +- @nextui-org/button 2.0.27 + +Done in 2.1s + +Remove the removed components tailwind content in file:/project-path/tailwind.config.js + +✅ Successfully removed the specified NextUI components: @nextui-org/button +``` + +## list + +Show details of installed components. + +```codeBlock bash +nextui list [options] +``` + +### Options + +- `-p --packagePath` [string] The path to the package.json file. +- `-c --current` List the current installed components. + +### Example + +```codeBlock bash +nextui list +``` + +Output: + +```codeBlock bash +NextUI CLI v0.1.2 + +Current installed components: + +╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ +│ Package │ Version │ Status │ Docs │ +│───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────│ +│ @nextui-org/autocomplete │ 2.0.10 🚀latest │ newPost │ https://nextui.org/docs/components/autocomplete │ +│ @nextui-org/badge │ 2.0.24 🚀latest │ stable │ https://nextui.org/docs/components/badge │ +│ @nextui-org/button │ 2.0.27 🚀latest │ stable │ https://nextui.org/docs/components/button │ +│ @nextui-org/chip │ 2.0.25 🚀latest │ stable │ https://nextui.org/docs/components/chip │ +╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ +``` + +## doctor + +Diagnose problems in your project. + +> 1. Check whether have `redundant dependencies` in the project +> 2. Check whether the NextUI components `required dependencies are installed` in the project +> 3. Check the required `tailwind.config.js` file and the content is correct +> 4. Check `.npmrc` is correct when using `pnpm` + +```codeBlock bash +nextui doctor [options] +``` + +### Options + +- `-p` `--packagePath` [string] The path to the package.json file +- `-tw` `--tailwindPath` [string] The path to the tailwind.config file file +- `-app` `--appPath` [string] The path to the App.tsx file +- `-ca` `--checkApp` [boolean] Open check App (default: `true`) +- `-ct` `--checkTailwind` [boolean] Open check tailwind.config file (default: `true`) +- `-cp` `--checkPnpm` [boolean] Open check Pnpm (default: `true`) + + +### Example + +```codeBlock bash +nextui doctor +``` + +Output: + + +If there is a problem in your project, the `doctor` command will display the problem information. + +```codeBlock bash +NextUI CLI v0.1.2 + +NextUI CLI: ❌ Your project has 1 issue that require attention + +❗️Issue 1: missingTailwind + +Missing tailwind.config.(j|t)s file. To set up, visit: https://nextui.org/docs/guide/installation#tailwind-css-setup +``` + +Otherwise, the `doctor` command will display the following message. + +```codeBlock bash +NextUI CLI v0.1.2 + +✅ Your project has no detected issues. +``` + +## env + +Display debug information about the local environment. + +```codeBlock bash +nextui env [options] +``` + +### Options +- `-p --packagePath` [string] The path to the package.json file + + +### Example + +```codeBlock bash +nextui env +``` + +Output: + +```codeBlock bash +NextUI CLI 0.1.0 + +Current installed components: + +╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ +│ Package │ Version │ Status │ Docs │ +│───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────│ +│ @nextui-org/autocomplete │ 2.0.10 🚀latest │ newPost │ https://nextui.org/docs/components/autocomplete │ +│ @nextui-org/badge │ 2.0.24 🚀latest │ stable │ https://nextui.org/docs/components/badge │ +│ @nextui-org/button │ 2.0.27 🚀latest │ stable │ https://nextui.org/docs/components/button │ +│ @nextui-org/chip │ 2.0.25 🚀latest │ stable │ https://nextui.org/docs/components/chip │ +╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ + +Environment Info: + System: + OS: darwin + CPU: arm64 + Binaries: + Node: v18.18.2 +``` \ No newline at end of file diff --git a/apps/docs/content/docs/api-references/nextui-provider.mdx b/apps/docs/content/docs/api-references/nextui-provider.mdx new file mode 100644 index 0000000000..063ca19891 --- /dev/null +++ b/apps/docs/content/docs/api-references/nextui-provider.mdx @@ -0,0 +1,102 @@ +--- +title: NextUI Provider +description: API References for NextUI Provider +--- + +# NextUI Provider + +------ + +Here's the API reference for the `NextUIProvider`. + +## Props + +### navigate + +`navigate` provides a client side router to all nested components such as Link, Menu, Tabs, Table, etc. + +**type**: `((path: string) => void) | undefined` + +### locale + +The locale to apply to the children. The [BCP47](https://www.ietf.org/rfc/bcp/bcp47.txt) language code for the locale. By default, It is `en-US`. + +**type**: `string | undefined` + +### defaultDates + +The default dates range that can be selected in the calendar. + +**type**: `{ minDate?: CalendarDate | undefined; maxDate?: CalendarDate | undefined; }` + +- minDate + + The minimum date that can be selected in the calendar. + + **type**: `CalendarDate | undefined` + + **default**: `new CalendarDate(1900, 1, 1)` + +- maxDate + + The maximum date that can be selected in the calendar. + + **type**: `CalendarDate | undefined` + + **default**: `new CalendarDate(2099, 12, 31)` + +### createCalendar + +This function helps to reduce the bundle size by providing a custom calendar system. + +By default, this includes all calendar systems supported by `@internationalized/date`. However, +if your application supports a more limited set of regions, or you know you will only be picking dates +in a certain calendar system, you can reduce your bundle size by providing your own implementation +of `createCalendar` that includes a subset of these Calendar implementations. + +For example, if your application only supports Gregorian dates, you could implement a `createCalendar` +function like this: + +```tsx +import {GregorianCalendar} from '@internationalized/date'; + +function createCalendar(identifier) { + switch (identifier) { + case 'gregory': + return new GregorianCalendar(); + default: + throw new Error(`Unsupported calendar ${identifier}`); + } +} +``` + +This way, only GregorianCalendar is imported, and the other calendar implementations can be tree-shaken. + +**type**: `((calendar: SupportedCalendars) => Calendar | null) | undefined` + +## Types + +### CalendarDate + +A [CalendarDate](https://react-spectrum.adobe.com/internationalized/date/CalendarDate.html) represents a date without any time components in a specific calendar system from `@internationalized/date`. + +### SupportedCalendars + +Supported react-aria i18n calendars. + +```tsx +type SupportedCalendars = + | "buddhist" + | "ethiopic" + | "ethioaa" + | "coptic" + | "hebrew" + | "indian" + | "islamic-civil" + | "islamic-tbla" + | "islamic-umalqura" + | "japanese" + | "persian" + | "roc" + | "gregory"; +``` \ No newline at end of file diff --git a/apps/docs/content/docs/components/accordion.mdx b/apps/docs/content/docs/components/accordion.mdx index d121f47a62..e3e63c79f2 100644 --- a/apps/docs/content/docs/components/accordion.mdx +++ b/apps/docs/content/docs/components/accordion.mdx @@ -15,6 +15,18 @@ Accordion display a list of high-level options that can expand/collapse to revea +## Installation + + + ## Import NextUI exports 2 accordion-related components: diff --git a/apps/docs/content/docs/components/autocomplete.mdx b/apps/docs/content/docs/components/autocomplete.mdx index 435dfa31a7..290e2b3a60 100644 --- a/apps/docs/content/docs/components/autocomplete.mdx +++ b/apps/docs/content/docs/components/autocomplete.mdx @@ -15,6 +15,19 @@ An autocomplete combines a text input with a listbox, allowing users to filter a +## Installation + + + + ## Import NextUI exports 3 autocomplete-related components: @@ -68,6 +81,13 @@ the end of the label and the autocomplete will be required. +### Read Only + +If you pass the `isReadOnly` property to the Autocomplete, the Listbox will open to display +all available options, but users won't be able to select any of the listed options. + + + ### Sizes @@ -405,7 +425,8 @@ properties to customize the popover, listbox and input components. | selectedKey | `React.Key` | The currently selected key in the collection (controlled). | - | | defaultSelectedKey | `React.Key` | The initial selected key in the collection (uncontrolled). | - | | disabledKeys | `all` \| `React.Key[]` | The item keys that are disabled. These items cannot be selected, focused, or otherwise interacted with. | - | -| errorMessage | `ReactNode` | An error message to display below the field. | - | +| errorMessage | `ReactNode` \| `((v: ValidationResult) => ReactNode)` | An error message to display below the field. | - | +| validate | `(value: { inputValue: string, selectedKey: React.Key }) => ValidationError | true | null | undefined` | Validate input values when committing (e.g. on blur), and return error messages for invalid values. | - | | startContent | `ReactNode` | Element to be rendered in the left side of the Autocomplete. | - | | endContent | `ReactNode` | Element to be rendered in the right side of the Autocomplete. | - | | autoFocus | `boolean` | Whether the Autocomplete should be focused on render. | `false` | diff --git a/apps/docs/content/docs/components/avatar.mdx b/apps/docs/content/docs/components/avatar.mdx index ad8105f1f0..715d0e9d45 100644 --- a/apps/docs/content/docs/components/avatar.mdx +++ b/apps/docs/content/docs/components/avatar.mdx @@ -16,6 +16,19 @@ The Avatar component is used to represent a user, and displays the profile pictu +## Installation + + + + ## Import NextUI exports 3 avatar-related components: @@ -174,14 +187,15 @@ You can customize any part of the avatar by using the `classNames` prop, each `s ### Avatar Group Props -| Attribute | Type | Description | Default | -| ----------- | ------------------------------ | --------------------------------------------------- | ------- | -| max | `number` | The maximum number of visible avatars | `5` | -| total | `number` | Control the number of avatar not visible | - | -| size | `AvatarProps['size']` | Size of the avatars | - | -| color | `AvatarProps['color']` | Color of the avatars | - | -| radius | `AvatarProps['radius']` | Radius of the avatars | - | -| isGrid | `boolean` | Whether the avatars should be displayed in a grid | `false` | -| isDisabled | `boolean` | Whether the avatars are disabled | - | -| isBordered | `boolean` | Whether the avatars have a border | - | -| renderCount | `(count: number) => ReactNode` | This allows you to render a custom count component. | - | +| Attribute | Type | Description | Default | +| ----------- | ---------------------------------- | --------------------------------------------------- | ------- | +| max | `number` | The maximum number of visible avatars | `5` | +| total | `number` | Control the number of avatar not visible | - | +| size | `AvatarProps['size']` | Size of the avatars | - | +| color | `AvatarProps['color']` | Color of the avatars | - | +| radius | `AvatarProps['radius']` | Radius of the avatars | - | +| isGrid | `boolean` | Whether the avatars should be displayed in a grid | `false` | +| isDisabled | `boolean` | Whether the avatars are disabled | - | +| isBordered | `boolean` | Whether the avatars have a border | - | +| renderCount | `(count: number) => ReactNode` | This allows you to render a custom count component. | - | +| classNames | `Record<"base"| "count", string>` | Allows to set custom class names for the avatar group slots. | - | diff --git a/apps/docs/content/docs/components/badge.mdx b/apps/docs/content/docs/components/badge.mdx index 181b5ea1c9..5c4f6f300e 100644 --- a/apps/docs/content/docs/components/badge.mdx +++ b/apps/docs/content/docs/components/badge.mdx @@ -15,6 +15,19 @@ Badges are used as a small numerical value or status descriptor for UI elements. +## Installation + + + + ## Import +## Installation + + + + ## Import NextUI exports 2 breadcrumb-related components: diff --git a/apps/docs/content/docs/components/button.mdx b/apps/docs/content/docs/components/button.mdx index 69787e0b02..a8adab6004 100644 --- a/apps/docs/content/docs/components/button.mdx +++ b/apps/docs/content/docs/components/button.mdx @@ -15,6 +15,18 @@ Buttons allow users to perform actions and choose with a single tap. +## Installation + + + ## Import NextUI exports 2 button-related components: diff --git a/apps/docs/content/docs/components/calendar.mdx b/apps/docs/content/docs/components/calendar.mdx new file mode 100644 index 0000000000..2de2f607fe --- /dev/null +++ b/apps/docs/content/docs/components/calendar.mdx @@ -0,0 +1,263 @@ +--- +title: "Calendar" +description: "The Calendar component is used to display one or more date grids and allows users to select a single date." +--- + +import {calendarContent} from "@/content/components/calendar"; + +# Calendar + +A calendar consists of a grouping element containing one or more date grids (e.g. months), and a previous and next button for navigating between date ranges. Each calendar grid consists of cells containing button elements that can be pressed and navigated to using the arrow keys to select a date. + + + +--- + + + +## Installation + + + +## Import + + + +## Usage + +A Calendar has no selection by default. An initial, uncontrolled value can be provided to the Calendar using the `defaultValue` prop. Alternatively, a controlled value can be provided using the `value` prop. + +Date values are provided using objects in the [@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/) package. This library handles correct international date manipulation across calendars, time zones, and other localization concerns. + + + +### Disabled + +The `isDisabled` boolean prop makes the Calendar disabled. Cells cannot be focused or selected. + + + +### Read Only + +The `isReadOnly` boolean prop makes the Calendar's value immutable. Unlike `isDisabled`, the Calendar remains focusable. + + + +### Controlled + +A Calendar has no selection by default. An initial, uncontrolled value can be provided to the Calendar using the `defaultValue` prop. Alternatively, a controlled value can be provided using the value prop. + + + +### Min Date Value + +By default, Calendar allows selecting any date. The `minValue` can also be used to prevent the user from selecting dates outside a certain range. + +This example only accepts dates after today. + + + +### Max Date Value + +By default, Calendar allows selecting any date. The `maxValue` can also be used to prevent the user from selecting dates outside a certain range. + +This example only accepts dates before today. + + + +### Unavailable Dates + +Calendar supports marking certain dates as unavailable. These dates remain focusable with the keyboard so that navigation is consistent, but cannot be selected by the user. In this example, they are displayed in red. The `isDateUnavailable` prop accepts a callback that is called to evaluate whether each visible date is unavailable. + + + +### Controlled Focused Value + +Calendar tries to avoid allowing the user to select invalid dates in the first place. However, if according to application logic a selected date is invalid, the isInvalid prop can be set. This alerts assistive technology users that the selection is invalid, and can be used for styling purposes as well. In addition, the errorMessage slot may be used to help the user fix the issue. + +By default, the selected date is focused when a Calendar first mounts. If no `value` or `defaultValue` prop is provided, then the current date is focused. However, Calendar supports controlling which date is focused using the `focusedValue` and `onFocusChange` props. This also determines which month is visible. The `defaultFocusedValue` prop allows setting the initial focused date when the Calendar first mounts, without controlling it. + + + +### Invalid Date + +This example validates that the selected date is a weekday and not a weekend according to the current locale. + + + +### With Month And Year Picker + +Calendar supports month and year picker for rapid selection. + + + +### International Calendars + +Calendar supports selecting dates in many calendar systems used around the world, including Gregorian, Hebrew, Indian, Islamic, Buddhist, and more. Dates are automatically displayed in the appropriate calendar system for the user's locale. The calendar system can be overridden using the [Unicode calendar locale extension](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/calendar#adding_a_calendar_in_the_locale_string), passed to the `Provider` component. + + + +### Visible Months + +By default, the Calendar displays a single month. The `visibleMonths` prop allows displaying up to 3 months at a time. + + + +### Page Behaviour + +By default, when pressing the next or previous buttons, pagination will advance by the `visibleMonths` value. This behavior can be changed to page by single months instead, by setting `pageBehavior` to `single`. + + + +### Presets + +Here's the example to customize `topContent` and `bottomContent` to have some preset values. + + + +## Slots + +- **base**: Calendar wrapper, it handles alignment, placement, and general appearance. +- **prevButton**: The previous button of the calendar. +- **nextButton**: The next button of the calendar. +- **headerWrapper**: Wraps the picker (month / year). +- **header**: The header element. +- **title**: A description of the visible date range, for use in the calendar title. +- **gridWrapper**: The wrapper for the calendar grid. +- **grid**: The date grid element (e.g. ``). +- **gridHeader**: The date grid header element (e.g. ``). +- **gridHeaderCell**: The date grid header cell element (e.g. ``). +- **gridBodyRow**: The date grid body row element (e.g. ``). +- **cell**: The date grid cell element (e.g. `
`). +- **gridHeaderRow**: The date grid header row element (e.g. `
`). +- **gridBody**: The date grid body element (e.g. `
`). +- **cellButton**: The button element within the cell. +- **pickerWrapper**: The wrapper for the picker +- **pickerMonthList**: The month list picker. +- **pickerYearList**: The year list picker. +- **pickerHighlight**: The highlighted item of the picker. +- **pickerItem**: The item of the picker. +- **helperWrapper**: The helper message of the calendar. +- **errorMessage**: The error message of the calendar. + + + +## Data Attributes + +`Calendar` has the following attributes on the `CalendarCell` element: + +- **data-focused**: + Whether the cell is focused. +- **data-hovered**: + Whether the cell is currently hovered with a mouse. +- **data-pressed**: + Whether the cell is currently being pressed. +- **data-unavailable**: + Whether the cell is unavailable, according to the calendar's `isDateUnavailable` prop. Unavailable dates remain focusable, but cannot be selected by the user. They should be displayed with a visual affordance to indicate they are unavailable, such as a different color or a strikethrough. +- **data-disabled**: + Whether the cell is disabled, according to the calendar's `minValue`, `maxValue`, and `isDisabled` props. +- **data-focus-visible**: + Whether the cell is keyboard focused. +- **data-outside-visible-range**: + Whether the cell is outside the visible range of the calendar. +- **data-outside-month**: + Whether the cell is outside the current month. +- **data-selected**: + Whether the cell is selected. +- **data-selected-start**: + Whether the cell is the first date in a range selection. +- **data-selected-end**: + Whether the cell is the last date in a range selection. +- **data-invalid**: + Whether the cell is part of an invalid selection. + + + +## Accessibility + +- Display one or more months at once, or a custom time range for use cases like a week view. Minimum and maximum values, unavailable dates, and non-contiguous selections are supported as well. +- Support for 13 calendar systems used around the world, including Gregorian, Buddhist, Islamic, Persian, and more. Locale-specific formatting, number systems, and right-to-left support are available as well. +- Calendar cells can be navigated and selected using the keyboard, and localized screen reader messages are included to announce when the selection and visible date range change. + + + +## API + +### Calendar Props + +| Attribute | Type | Description | Default | +| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- | +| value | `DateValue \| null` | The current value (controlled). | - | +| defaultValue | `DateValue \| null` | The default value (uncontrolled). | - | +| minValue | `DateValue` | The minimum allowed date that a user may select. | - | +| maxValue | `DateValue` | The maximum allowed date that a user may select. | - | +| color | `default` \| `primary` \| `secondary` \| `success` \| `warning` \| `danger` | The color of the time input. | `default` | +| visibleMonths | `number` | The number of months to display at once. Up to 3 months are supported. Passing a number greater than 1 will disable the `showMonthAndYearPickers` prop | `1` | +| focusedValue | `DateValue` | Controls the currently focused date within the calendar. | - | +| defaultFocusedValue | `DateValue` | The date that is focused when the calendar first mounts (uncountrolled). | - | +| calendarWidth | `number` \| `string` | The width to be applied to the calendar component. This value is multiplied by the `visibleMonths` number to determine the total width of the calendar. | `256` | +| pageBehavior | `single` \| `visible` | Controls the behavior of paging. Pagination either works by advancing the visible page by visibleDuration (default) or one unit of visibleDuration. | `visible` | +| weekdayStyle | `narrow` \|`short` \| `long` \| `undefined` | The style of weekday names to display in the calendar grid header, e.g. single letter, abbreviation, or full day name. | `narrow` | +| showMonthAndYearPickers | `boolean` | Whether the label should be crossed out. | `false` | +| isDisabled | `boolean` | Whether the calendar is disabled. | `false` | +| isReadOnly | `boolean` | Whether the calendar value is immutable. | `false` | +| isInvalid | `boolean` | Whether the current selection is invalid according to application logic. | - | +| autoFocus | `boolean` | Whether to automatically focus the calendar when it mounts. | `false` | +| showHelper | `boolean` | Whether to show the description or error message. | `false` | +| showShadow | `boolean` | Whether to show the shadow in the selected date. | `false` | +| isHeaderExpanded | `boolean` | Whether the calendar header is expanded. This is only available if the `showMonthAndYearPickers` prop is set to `true`. | `false` | +| isHeaderDefaultExpanded | `boolean` | Whether the calendar header should be expanded by default.This is only available if the `showMonthAndYearPickers` prop is set to `true`. | `false` | +| topContent | `ReactNode` | Custom content to be included in the top of the calendar. | - | +| bottomContent | `ReactNode` | Custom content to be included in the bottom of the calendar. | - | +| isDateUnavailable | `(date: DateValue) => boolean` | Callback that is called for each date of the calendar. If it returns true, then the date is unavailable. | - | +| createCalendar | `(calendar: SupportedCalendars) => Calendar \| null` | This function helps to reduce the bundle size by providing a custom calendar system. You can also use the NextUIProvider to provide the createCalendar function to all nested components. | `all
calendars` | +| errorMessage | `ReactNode \| (v: ValidationResult) => ReactNode` | An error message for the field. | - | +| validate | `(value: { inputValue: string, selectedKey: React.Key }) => ValidationError | true | null | undefined` | Validate time input values when committing (e.g. on blur), and return error messages for invalid values. | - | +| hideDisabledDates | `boolean` | Whether to hide the disabled or invalid dates. | `false` | +| disableAnimation | `boolean` | Whether to disable the animation of the calendar. | `false` | +| classNames | `Record<"base"| "prevButton"| "nextButton"| "headerWrapper" \| "header" \| "title" \| "content" \| "gridWrapper" \| "grid" \| "gridHeader" \| "gridHeaderRow" \| "gridHeaderCell" \| "gridBody" \| "gridBodyRow" \| "cell" \| "cellButton" \| "pickerWrapper" \| "pickerMonthList" \| "pickerYearList" \| "pickerHighlight" \| "pickerItem" \| "helperWrapper" \| "errorMessage", string>` | Allows to set custom class names for the calendar slots. | - | + +### Calendar Events + +| Attribute | Type | Description | +| ---------------------- | ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | +| onChange | `(value: MappedDateValue) => void` | Handler that is called when the value changes. | +| onFocusChange | `(date: CalendarDate) => void` | Handler that is called when the focused date changes. | +| onHeaderExpandedChange | `(isExpanded: boolean) => void` | The event handler for the calendar header expanded state. This is only available if the `showMonthAndYearPickers` prop is set to `true`. | + +### Types + +#### Supported Calendars + +```ts +/** + * Supported react-aria i18n calendars. + */ +export type SupportedCalendars = + | "buddhist" + | "ethiopic" + | "ethioaa" + | "coptic" + | "hebrew" + | "indian" + | "islamic-civil" + | "islamic-tbla" + | "islamic-umalqura" + | "japanese" + | "persian" + | "roc" + | "gregory"; +``` diff --git a/apps/docs/content/docs/components/card.mdx b/apps/docs/content/docs/components/card.mdx index 9dae965177..5fbfcefa7c 100644 --- a/apps/docs/content/docs/components/card.mdx +++ b/apps/docs/content/docs/components/card.mdx @@ -15,6 +15,19 @@ Card is a container for text, photos, and actions in the context of a single sub +## Installation + + + + ## Import NextUI exports 4 card-related components: diff --git a/apps/docs/content/docs/components/checkbox-group.mdx b/apps/docs/content/docs/components/checkbox-group.mdx index f6facbdcd3..ff5bddf731 100644 --- a/apps/docs/content/docs/components/checkbox-group.mdx +++ b/apps/docs/content/docs/components/checkbox-group.mdx @@ -15,6 +15,19 @@ A CheckboxGroup allows users to select one or more items from a list of choices. +## Installation + + + + ## Import NextUI exports 2 checkbox-related components: @@ -87,14 +100,15 @@ In case you need to customize the checkbox even further, you can use the `useChe | size | `xs` \| `sm` \| `md` \| `lg` \| `xl` | The size of the checkboxes. | `md` | | radius | `none` \| `base` \| `xs` \| `sm` \| `md` \| `lg` \| `xl` \| `full` | The radius of the checkboxes. | `md` | | name | `string` | The name of the CheckboxGroup, used when submitting an HTML form. | - | -| label | `string` | The label of the CheckboxGroup. | - | +| label | `string` | The label of the CheckboxGroup. | - | | value | `string[]` | The current selected values. (controlled). | - | | lineThrough | `boolean` | Whether the checkboxes label should be crossed out. | `false` | | defaultValue | `string[]` | The default selected values. (uncontrolled). | - | | isInvalid | `boolean` | Whether the checkbox group is invalid. | `false` | | validationState | `valid` \| `invalid` | Whether the inputs should display its "valid" or "invalid" visual styling. (**Deprecated**) use **isInvalid** instead. | - | | description | `ReactNode` | The checkbox group description. | - | -| errorMessage | `ReactNode` | The checkbox group error message. | - | +| errorMessage | `ReactNode` \| `((v: ValidationResult) => ReactNode)` | The checkbox group error message. | - | +| validate | `(value: string[]) => ValidationError | true | null | undefined` | Validate input values when committing (e.g. on blur), and return error messages for invalid values. | - | | isDisabled | `boolean` | Whether the checkbox group is disabled. | `false` | | isRequired | `boolean` | Whether user checkboxes are required on the input before form submission. | `false` | | isReadOnly | `boolean` | Whether the checkboxes can be selected but not changed by the user. | - | @@ -103,6 +117,6 @@ In case you need to customize the checkbox even further, you can use the `useChe ### Checkbox Group Events -| Attribute | Type | Description | -| --------- | ----------------------------- | ---------------------------------------------- | -| onChange | `((value: string[]) => void)` | Handler that is called when the value changes. | +| Attribute | Type | Description | +| --------- | --------------------------- | ---------------------------------------------- | +| onChange | `(value: string[]) => void` | Handler that is called when the value changes. | diff --git a/apps/docs/content/docs/components/checkbox.mdx b/apps/docs/content/docs/components/checkbox.mdx index 7af0d2822e..ba56b2d0af 100644 --- a/apps/docs/content/docs/components/checkbox.mdx +++ b/apps/docs/content/docs/components/checkbox.mdx @@ -15,6 +15,19 @@ Checkboxes allow users to select multiple items from a list of individual items, +## Installation + + + + ## Import +## Installation + + + ## Import +## Installation + + + + ## Import +## Installation + + + + ## Import + +--- + + + +## Installation + + + +## Import + + + +## Usage + + + +### Disabled + + + +### Read Only + + + +### Required + + + +### Variants + + + +### Label Placements + +You can change the position of the label by setting the `labelPlacement` property to `inside`, `outside` or `outside-left`. + + + +> **Note**: If the `label` is not passed, the `labelPlacement` property will be `outside` by default. + +### Start & End Content + +You can use the `startContent` and `endContent` properties to add content to the start and end of the `DateInput`. + + + +### With Description + +You can add a description to the input by passing the `description` property. + + + +### With Error Message + +You can combine the `isInvalid` and `errorMessage` properties to show an invalid input. + + + +### Controlled + +You can use the `value` and `onChange` properties to control the input value. + + + +### Time Zones + +DateInput is time zone aware when a `ZonedDateTime` object is provided as the value. In this case, the time zone abbreviation is displayed, +and time zone concerns such as daylight saving time are taken into account when the value is manipulated. + +[@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/) includes functions for parsing strings +in multiple formats into `ZonedDateTime` objects. + + + +```jsx +import {parseZonedDateTime} from "@internationalized/date"; +``` + + + + + +### Granularity + +The granularity prop allows you to control the smallest unit that is displayed by DateInput By default, +the value is displayed with "day" granularity (year, month, and day), +and `CalendarDateTime` and `ZonedDateTime` values are displayed with "minute" granularity. + +[@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/) includes functions for parsing strings +in multiple formats into `ZonedDateTime` objects. + + + +```jsx +import {DateValue, now, parseAbsoluteToLocal} from "@internationalized/date"; +import {useDateFormatter} from "@react-aria/i18n"; +``` + + + + + +### Min Date And Max Date + +The minValue and maxValue props can also be used to ensure the value is within a specific range. + +[@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/) includes functions for parsing strings +in multiple formats into `ZonedDateTime` objects. + + + +```jsx +import {getLocalTimeZone, parseDate, today} from "@internationalized/date"; +``` + + + +### International Calendar + +DateInput supports selecting dates in many calendar systems used around the world, including Gregorian, Hebrew, Indian, Islamic, Buddhist, and more. +Dates are automatically displayed in the appropriate calendar system for the user's locale. +The calendar system can be overridden using the [Unicode calendar locale extension](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/calendar#adding_a_calendar_in_the_locale_string), +passed to the [I18nProvider](https://react-spectrum.adobe.com/react-aria/I18nProvider.html) component. + +[@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/) includes functions for parsing strings +in multiple formats into `ZonedDateTime` objects. + + + +```jsx +import {DateValue, now, parseAbsoluteToLocal} from "@internationalized/date"; +import {I18nProvider} from "@react-aria/i18n"; +``` + + + +### Hide Time Zone + +When a `ZonedDateTime` object is provided as the value to DateInput, the time zone abbreviation is displayed by default. +However, if this is displayed elsewhere or implicit based on the usecase, it can be hidden using the hideTimeZone option. + +[@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/) includes functions for parsing strings +in multiple formats into `ZonedDateTime` objects. + + + +```jsx +import {parseZonedDateTime} from "@internationalized/date"; +``` + + + +### Hourly Cycle + +By default, DateInput displays times in either 12 or 24 hour hour format depending on the user's locale. +However, this can be overridden using the `hourCycle` prop if needed for a specific usecase. +This example forces DateInput to use 24-hour time, regardless of the locale. + +[@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/) includes functions for parsing strings +in multiple formats into `ZonedDateTime` objects. + + + +```jsx +import {parseZonedDateTime} from "@internationalized/date"; +``` + + + +## Slots + +- **base**: Input wrapper, it handles alignment, placement, and general appearance. +- **label**: Label of the date-input, it is the one that is displayed above, inside or left of the date-input. +- **inputWrapper**: Wraps the `label` (when it is inside) and the `innerWrapper`. +- **input**: The date-input element. +- **innerWrapper**: Wraps the `input`, the `startContent` and the `endContent`. +- **clearButton**: The clear button, it is at the end of the input. +- **helperWrapper**: Wraps the `description` and the `errorMessage`. +- **description**: The description of the date-input. +- **errorMessage**: The error message of the date-input. + +{" "} + +## Data Attributes + +`DateInput` has the following attributes on the `base` element: + +- **data-slot**: + All slots have this prop. which slot the element represents(e.g. `slot`). +- **data-invalid**: + When the date-input is invalid. Based on `isInvalid` prop. +- **data-required**: + When the date-input is required. Based on `isRequired` prop. +- **data-readonly**: + When the date-input is readonly. Based on `isReadOnly` prop. +- **data-disabled**: + When the date-input is disabled. Based on `isDisabled` prop. +- **data-has-helper**: + When the date-input has helper text(`errorMessage` or `description`). Base on those two props. +- **data-has-start-content**: + When the date-input has a start content. Base on those `startContent` prop. +- **data-has-end-content**: + When the date-input has a end content. Base on those `endContent` prop. + + + +## Accessibility + +- Built with a native `` element. +- Visual and ARIA labeling support. +- Change, clipboard, composition, selection, and input event support. +- Required and invalid states exposed to assistive technology via ARIA. +- Support for description and error message help text linked to the input via ARIA. +- Each date and time unit is displayed as an individually focusable and editable segment, which allows users an easy way to edit dates using the keyboard, in any date format and locale. +- Date segments are editable using an easy to use numeric keypad, and all interactions are accessible using touch-based screen readers. + + + +## API + +### DateInput Props + +| Attribute | Type | Description | Default | +| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | --------- | +| label | `ReactNode` | The content to display as the label. | - | +| value | `DateValue` | The current value of the date input (controlled). | - | +| defaultValue | `DateValue` | The default value of the date input (uncontrolled). | - | +| variant | `flat` \| `bordered` \| `faded` \| `underlined` | The variant of the date input. | `flat` | +| color | `default` \| `primary` \| `secondary` \| `success` \| `warning` \| `danger` | The color of the date input. | `default` | +| size | `sm` \| `md` \| `lg` | The size of the date input. | `md` | +| radius | `none` \| `sm` \| `md` \| `lg` \| `full` | The radius of the date input. | - | +| placeholderValue | `DateValue` | A placeholder time that influences the format of the placeholder shown when no value is selected. Defaults current date at midnight. | - | +| minValue | `DateValue` | The minimum allowed date that a user may select. | - | +| maxValue | `DateValue` | The maximum allowed date that a user may select. | - | +| locale | `string` | The locale to display and edit the value according to. | - | +| description | `ReactNode` | A description for the date input. Provides a hint such as specific requirements for what to choose. | - | +| errorMessage | `ReactNode \| (v: ValidationResult) => ReactNode` | An error message for the date input. | - | +| startContent | `ReactNode` | Element to be rendered in the left side of the date input. | - | +| endContent | `ReactNode` | Element to be rendered in the right side of the date input. | - | +| labelPlacement | `inside` \| `outside` \| `outside-left` | The position of the label. | `inside` | +| isRequired | `boolean` | Whether user input is required on the input before form submission. | `false` | +| isReadOnly | `boolean` | Whether the input can be selected but not changed by the user. | - | +| isDisabled | `boolean` | Whether the input is disabled. | `false` | +| isInvalid | `boolean` | Whether the input value is invalid. | `false` | +| inputRef | `ReactRef` | A ref for the hidden input element for HTML form submission. | - | +| validate | `(value: { inputValue: string, selectedKey: React.Key }) => ValidationError | true | null | undefined` | Validate input values when committing (e.g., on blur), and return error messages for invalid values. | - | +| createCalendar | `(name: string) => Calendar` | A function that creates a Calendar object for a given calendar identifier. | - | +| isDateUnavailable | `(date: DateValue) => boolean` | Callback that is called for each date of the calendar. If it returns true, then the date is unavailable. | - | +| autoFocus | `boolean` | Whether the element should receive focus on render. | `false` | +| hourCycle | `12` \| `24` | Whether to display the time in 12 or 24 hour format. This is determined by the user's locale. | - | +| granularity | `day` \| `hour` \| `minute` \| `second` | Determines the smallest unit that is displayed in the date picker. Typically "day" for dates. | - | +| hideTimeZone | `boolean` | Whether to hide the time zone abbreviation. | `false` | +| shouldForceLeadingZeros | `boolean` | Whether to always show leading zeros in the month, day, and hour fields. | `true` | +| disableAnimation | `boolean` | Whether to disable animations. | `false` | +| classNames | `Record<"base"| "label"| "inputWrapper"| "innerWrapper"| "input"| "helperWrapper"| "description"| "errorMessage", string>` | Allows to set custom class names for the date input slots. | - | + +### DateInput Events + +| Attribute | Type | Description | | +| ------------- | ---------------------------------------------------------------------- | --------------------------------------------------------------- | --- | +| onChange | `((value: ZonedDateTime \| CalendarDate \| CalendarDateTime) => void)` | Handler that is called when the date-input's value changes. | - | +| onFocus | `(e: FocusEvent) => void` | Handler that is called when the element receives focus. | - | +| onBlur | `(e: FocusEvent) => void` | Handler that is called when the element loses focus. | - | +| onFocusChange | `(isFocused: boolean) => void` | Handler that is called when the element's focus status changes. | - | +| onKeyDown | `(e: KeyboardEvent) => void` | Handler that is called when a key is pressed. | - | +| onKeyUp | `(e: KeyboardEvent) => void` | Handler that is called when a key is released. | - | diff --git a/apps/docs/content/docs/components/date-picker.mdx b/apps/docs/content/docs/components/date-picker.mdx new file mode 100644 index 0000000000..47862b7826 --- /dev/null +++ b/apps/docs/content/docs/components/date-picker.mdx @@ -0,0 +1,353 @@ +--- +title: "DatePicker" +description: "DatePickers combine a DateInput and a Calendar popover to allow users to enter or select a date and time value." +--- + +import {datePickerContent} from "@/content/components/date-picker"; + +# DatePicker + +DatePickers combine a DateInput and a Calendar popover to allow users to enter or select a date and time value. + + + +--- + + + +## Installation + + + +## Import + + + +## Usage + + + +### Disabled + + + +### Read Only + + + +### Required + + + +### Variants + + + +### Label Placements + +You can change the position of the label by setting the `labelPlacement` property to `inside`, `outside` or `outside-left`. + + + +> **Note**: If the `label` is not passed, the `labelPlacement` property will be `outside` by default. + +### With Description + +You can add a description to the date-picker by passing the `description` property. + + + +### With Error Message + +You can combine the `isInvalid` and `errorMessage` properties to show an invalid input. + + + +### With Month and Year Pickers + + + +### With Time Fields + + + +### Selector Icon + +You can use the `selector` to add content to the start and end of the date-picker. + + + +### Controlled + +You can use the `value` and `onChange` properties to control the input value. + + + +### Time Zones + +DatePicker is time zone aware when a `ZonedDateTime` object is provided as the value. In this case, the time zone abbreviation is displayed, +and time zone concerns such as daylight saving time are taken into account when the value is manipulated. + +[@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/) includes functions for parsing strings +in multiple formats into `ZonedDateTime` objects. + + + +```jsx +import {parseZonedDateTime} from "@internationalized/date"; +``` + + + + + +### Granularity + +The granularity prop allows you to control the smallest unit that is displayed by DatePicker By default, +the value is displayed with "day" granularity (year, month, and day), +and `CalendarDateTime` and `ZonedDateTime` values are displayed with "minute" granularity. + +[@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/) includes functions for parsing strings +in multiple formats into `ZonedDateTime` objects. + + + +```jsx +import {DateValue, now, parseAbsoluteToLocal} from "@internationalized/date"; +import {useDateFormatter} from "@react-aria/i18n"; +``` + + + + + +### Min Date And Max Date + +The minValue and maxValue props can also be used to ensure the value is within a specific range. + +[@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/) includes functions for parsing strings +in multiple formats into `ZonedDateTime` objects. + + + +```jsx +import {getLocalTimeZone, parseDate, today} from "@internationalized/date"; +``` + + + +### International Calendar + +DatePicker supports selecting dates in many calendar systems used around the world, including Gregorian, Hebrew, Indian, Islamic, Buddhist, and more. +Dates are automatically displayed in the appropriate calendar system for the user's locale. +The calendar system can be overridden using the [Unicode calendar locale extension](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/calendar#adding_a_calendar_in_the_locale_string), +passed to the [I18nProvider](https://react-spectrum.adobe.com/react-aria/I18nProvider.html) component. + +[@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/) includes functions for parsing strings +in multiple formats into `ZonedDateTime` objects. + + + +```jsx +import {DateValue, now, parseAbsoluteToLocal} from "@internationalized/date"; +import {I18nProvider} from "@react-aria/i18n"; +``` + + + +### Unavailable Dates + +DatePicker supports marking certain dates as unavailable. These dates cannot be selected by the user and are displayed with a crossed out appearance in the calendar. In the date field, an invalid state is displayed if a user enters an unavailable date. + +[@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/) includes functions for parsing strings +in multiple formats into `ZonedDateTime` objects. + + + +```jsx +import {today, isWeekend, getLocalTimeZone} from "@internationalized/date"; +import {useLocale} from "@react-aria/i18n"; +``` + + + +### Visible Months + +By default, the calendar popover displays a single month. The `visibleMonths` prop allows displaying up to 3 months at a time, if screen space permits. + + + +### Page Behavior + +By default, when pressing the next or previous buttons, pagination will advance by the `visibleMonths` value. This behavior can be changed to page by single months instead, by setting `pageBehavior` to `single`. + + + +### Preset + +[@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/) includes functions for parsing strings +in multiple formats into `ZonedDateTime` objects. + + + +```jsx +import { + DateValue, + now, + useLocale, + startOfWeek, + startOfMonth, + useDateFormatter, + getLocalTimeZone, +} from "@internationalized/date"; +import {I18nProvider} from "@react-aria/i18n"; +``` + + + +## Slots + +- **base**: Input wrapper, it handles alignment, placement, and general appearance. +- **selectorButton**: Selector button element. +- **selectorIcon**: Selector icon element. +- **popoverContent**: The calendar popover element. +- **calendar**: The calendar element. +- **calendarContent**: The calendar's content element. +- **timeInputLabel**: The time-input component's label element. +- **timeInput**: The time-input component element. + +{" "} + +## Data Attributes + +`DatePicker` has the following attributes on the `base` element: + +- **data-slot**: + All slots have this prop. which slot the element represents(e.g. `canlendar`). +- **data-open**: + Indicates if the calendar popover is open. +- **data-invalid**: + When the date-picker is invalid. Based on `isInvalid` prop. +- **data-required**: + When the date-picker is required. Based on `isRequired` prop. +- **data-readonly**: + When the date-picker is readonly. Based on `isReadOnly` prop. +- **data-disabled**: + When the date-picker is disabled. Based on `isDisabled` prop. + +{" "} + +## Accessibility + +- Each date and time unit is displayed as an individually focusable and editable segment, which allows users an easy way to edit dates using the keyboard, in any date format and locale. +- Users can also open a calendar popover to select dates in a standard month grid. +- Localized screen reader messages are included to announce when the selection and visible date range change. +- Date segments are editable using an easy to use numeric keypad, and all interactions are accessible using touch-based screen readers. +- Integrates with HTML forms, supporting required, minimum and maximum values, unavailable dates, custom validation functions, realtime validation, and server-side validation errors + +{" "} + +## API + +### DatePicker Props + +| Attribute | Type | Description | Default | +| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | +| label | `ReactNode` | The content to display as the label. | - | +| value | `ZonedDateTime` \| `CalendarDate` \| `CalendarDateTime` \| `undefined` \| `null` | The current value of the date-picker (controlled). | - | +| variant | `flat` \| `bordered` \| `faded` \| `underlined` | The variant of the date input. | `flat` | +| color | `default` \| `primary` \| `secondary` \| `success` \| `warning` \| `danger` | The color of the date input. | `default` | +| size | `sm` \| `md` \| `lg` | The size of the date input. | `md` | +| radius | `none` \| `sm` \| `md` \| `lg` \| `full` | The radius of the date input. | - | +| defaultValue | `string` \| undefined | The default value of the date-picker (uncontrolled). | - | +| placeholderValue | `ZonedDateTime` \| `CalendarDate` \| `CalendarDateTime` \| `undefined` \| `null` | The placeholder of the date-picker. | - | +| description | `ReactNode` | A description for the date-picker. Provides a hint such as specific requirements for what to choose. | - | +| errorMessage | `ReactNode \| (v: ValidationResult) => ReactNode` | An error message for the date input. | - | +| startContent | `ReactNode` | Element to be rendered in the left side of the date-picker. | - | +| endContent | `ReactNode` | Element to be rendered in the right side of the date-picker. | - | +| labelPlacement | `inside` \| `outside` \| `outside-left` | The position of the label. | `inside` | +| isRequired | `boolean` | Whether user input is required on the date-picker before form submission. | `false` | +| isReadOnly | `boolean` | Whether the date-picker can be selected but not changed by the user. | | +| isDisabled | `boolean` | Whether the date-picker is disabled. | `false` | +| isInvalid | `boolean` | Whether the date-picker is invalid. | `false` | +| visibleMonths | `number` \| `undefined` | The number of months to display at once. Up to 3 months are supported. Passing a number greater than 1 will disable the `showMonthAndYearPickers` prop. | `1` | +| selectorIcon | `ReactNode` | The icon to toggle the date picker popover. Usually a calendar icon. | | +| pageBehavior | `PageBehavior` \| `undefined` | Controls the behavior of paging. Pagination either works by advancing the visible page by visibleDuration (default) or one unit of visibleDuration. | `visible` | +| visibleMonths | `number` \| `undefined` | The number of months to display at once. Up to 3 months are supported. Passing a number greater than 1 will disable the `showMonthAndYearPickers` prop. | `1` | +| calendarWidth | `number` | The width to be applied to the calendar component. | `256` | +| CalendarTopContent | `ReactNode` | Top content to be rendered in the calendar component. | | +| validate | `(value: { inputValue: string, selectedKey: React.Key }) => ValidationError | true | null | undefined` | Validate input values when committing (e.g., on blur), and return error messages for invalid values. | - | +| isDateUnavailable | `((date: DateValue) => boolean)` \| `undefined` | Callback that is called for each date of the calendar. If it returns true, then the date is unavailable. | +| autoFocus | `boolean` | Whether the element should receive focus on render. | `false` | +| hourCycle | `12` \| `24` | Whether to display the time in 12 or 24 hour format. This is determined by the user's locale. | - | +| granularity | `day` \| `hour` \| `minute` \| `second` | Determines the smallest unit that is displayed in the date picker. Typically "day" for dates. | - | +| hideTimeZone | `boolean` | Whether to hide the time zone abbreviation. | `false` | +| shouldForceLeadingZeros | `boolean` | Whether to always show leading zeros in the month, day, and hour fields. | `true` | +| CalendarBottomContent | `ReactNode` | Bottom content to be rendered in the calendar component. | | +| showMonthAndYearPickers | `boolean` \| `undefined` | Whether the calendar should show month and year pickers. | false | +| popoverProps | `PopoverProps` \| `undefined` | Props to be passed to the popover component. | `{ placement: "bottom", triggerScaleOnOpen: false, offset: 13 }` | +| selectorButtonProps | `ButtonProps` \| `undefined` | Props to be passed to the selector button component. | `{ size: "sm", variant: "light", radius: "full", isIconOnly: true }` | +| calendarProps | `CalendarProps` \| `undefined` | Props to be passed to the selector button component. | `{ size: "sm", variant: "light", radius: "full", isIconOnly: true }` | +| timeInputProps | `TimeInputProps` | Props to be passed to the time input component. | `{ size: "sm", variant: "light", radius: "full", isIconOnly: true }` | +| disableAnimation | `boolean` | Whether to disable all animations in the date picker. Including the DateInput, Button, Calendar, and Popover. | `false` | +| classNames | `Record<"base" \| "selectorButton" \| "selectorIcon" \| "popoverContent" \| "calendar" \| "calendarContent" \| "timeInputLabel" \| "timeInput", string>` | Allows to set custom class names for the date-picker slots. | - | + +### DatePicker Events + +| Attribute | Type | Description | | +| ------------- | ------------------------------------------------------------------------------------ | --------------------------------------------------------------- | --- | +| onChange | `((value: ZonedDateTime \| CalendarDate \| CalendarDateTime) => void)` \| undefined | Handler that is called when the date-picker's value changes. | - | +| onFocus | `(e: FocusEvent) => void` | Handler that is called when the element receives focus. | - | +| onBlur | `(e: FocusEvent) => void` | Handler that is called when the element loses focus. | - | +| onFocusChange | `(isFocused: boolean) => void` | Handler that is called when the element's focus status changes. | - | +| onKeyDown | `(e: KeyboardEvent) => void` | Handler that is called when a key is pressed. | - | +| onKeyUp | `(e: KeyboardEvent) => void` | Handler that is called when a key is released. | - | diff --git a/apps/docs/content/docs/components/date-range-picker.mdx b/apps/docs/content/docs/components/date-range-picker.mdx new file mode 100644 index 0000000000..fe73390510 --- /dev/null +++ b/apps/docs/content/docs/components/date-range-picker.mdx @@ -0,0 +1,398 @@ +--- +title: "Date Range Picker" +description: "DateRangePicker combines two DateInputs and a RangeCalendar popover to allow users to enter or select a date and time range." +--- + +import {dateRangePickerContent} from "@/content/components/date-range-picker"; + +# Date Range Picker + +Date Range Picker combines two DateInputs and a RangeCalendar popover to allow users to enter or select a date and time range. + + + +--- + + + +## Installation + + + +## Import + + + +## Usage + + + +### Disabled + + + +### Read Only + + + +### Required + +If you pass the `isRequired` property to the input, it will have a `danger` asterisk at +the end of the label and the input will be required. + + + +### Variants + + + +### Visible Months + +By default, the calendar popover displays a single month. The `visibleMonths` prop allows displaying up to 3 months at a time, if screen space permits. + + + +### Page Behavior + +By default, when pressing the next or previous buttons, pagination will advance by the `visibleMonths` value. This behavior can be changed to page by single months instead, by setting `pageBehavior` to `single`. + + + +### Label Placements + +You can change the position of the label by setting the `labelPlacement` property to `inside`, `outside` or `outside-left`. + + + +> **Note**: If the `label` is not passed, the `labelPlacement` property will be `outside` by default. + +### With Description + +You can add a description to the input by passing the `description` property. + + + +### With Error Message + +You can combine the `isInvalid` and `errorMessage` properties to show an invalid input. + + + +### With Time Fields + +DateRangePicker automatically includes time fields when a `CalendarDateTime` or `ZonedDateTime` object is provided as the value. + + + +### Selector Icon + +You can use the `selector` to add content to the start and end of the date-range-picker. + + + +### Controlled + +You can use the `value` and `onChange` properties to control the input value. + + + +### Time Zones + +DateRangePicker is time zone aware when a `ZonedDateTime` object is provided as the value. In this case, the time zone abbreviation is displayed, +and time zone concerns such as daylight saving time are taken into account when the value is manipulated. + +[@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/) includes functions for parsing strings +in multiple formats into `ZonedDateTime` objects. + + + +```jsx +import {parseZonedDateTime} from "@internationalized/date"; +``` + + + + + +### Granularity + +The granularity prop allows you to control the smallest unit that is displayed by DateRangePicker By default, +the value is displayed with "day" granularity (year, month, and day), +and `CalendarDateTime` and `ZonedDateTime` values are displayed with "minute" granularity. + +[@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/) includes functions for parsing strings +in multiple formats into `ZonedDateTime` objects. + + + +```jsx +import {DateValue, now, parseAbsoluteToLocal} from "@internationalized/date"; +import {useDateFormatter} from "@react-aria/i18n"; +``` + + + + + +### Min Date And Max Date + +The minValue and maxValue props can also be used to ensure the value is within a specific range. + +[@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/) includes functions for parsing strings +in multiple formats into `ZonedDateTime` objects. + + + +```jsx +import {getLocalTimeZone, parseDate, today} from "@internationalized/date"; +``` + + + +### International Calendar + +DateRangePicker supports selecting dates in many calendar systems used around the world, including Gregorian, Hebrew, Indian, Islamic, Buddhist, and more. +Dates are automatically displayed in the appropriate calendar system for the user's locale. +The calendar system can be overridden using the [Unicode calendar locale extension](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/calendar#adding_a_calendar_in_the_locale_string), +passed to the [I18nProvider](https://react-spectrum.adobe.com/react-aria/I18nProvider.html) component. + +[@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/) includes functions for parsing strings +in multiple formats into `ZonedDateTime` objects. + + + +```jsx +import {DateValue, now, parseAbsoluteToLocal} from "@internationalized/date"; +import {I18nProvider} from "@react-aria/i18n"; +``` + + + +### Unavailable Dates + +DateRangePicker supports marking certain dates as unavailable. These dates cannot be selected by the user and are displayed with a crossed out appearance in the calendar. In the date field, an invalid state is displayed if a user enters an unavailable date. + +[@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/) includes functions for parsing strings +in multiple formats into `ZonedDateTime` objects. + + + +```jsx +import {today, isWeekend, getLocalTimeZone} from "@internationalized/date"; +import {useLocale} from "@react-aria/i18n"; +``` + + + +### Non Contiguous + +The allowsNonContiguousRanges prop enables a range to be selected even if there are unavailable dates in the middle. +The value emitted in the onChange event will still be a single range with a start and end property, +but unavailable dates will not be displayed as selected. +It is up to applications to split the full selected range into multiple as needed for business logic. + +[@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/) includes functions for parsing strings +in multiple formats into `ZonedDateTime` objects. + + + +```jsx +import {today, isWeekend, getLocalTimeZone} from "@internationalized/date"; +import {useLocale} from "@react-aria/i18n"; +``` + + + +### Presets + +[@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/) includes functions for parsing strings +in multiple formats into `ZonedDateTime` objects. + + + +```jsx +import { + DateValue, + now, + useLocale, + startOfWeek, + startOfMonth, + useDateFormatter, + getLocalTimeZone, +} from "@internationalized/date"; +import {I18nProvider} from "@react-aria/i18n"; +``` + + + +## Slots + +- **base**: base element. it handles alignment, placement, and general appearance. +- **label**: Label of the date-range-picker, it is the one that is displayed above, inside or left of the date-input. +- **calendar**: The calendar element. +- **selectorButton**: Selector button element. +- **selectorIcon**: Selector icon element. +- **popoverContent**: The calendar popover element. +- **calendarContent**: The calendar's content element. +- **inputWrapper**: Wraps the `label` (when it is inside) and the `innerWrapper`. +- **input**: The input element. +- **segment**: The segment element. +- **separator**: The separator element. +- **bottomContent**: The bottom content element. +- **timeInputWrapper**: The wrapper element for the input element. +- **helperWrapper**: Wraps the `description` and the `errorMessage`. +- **description**: The description of the date-input. +- **errorMessage**: The error message of the date-input. + + + +## Data Attributes + +`DateRangePicker` has the following attributes on the `base` element: + +- **data-slot**: + All slots have this prop. which slot the element represents(e.g. `canlendar`). +- **data-open**: + Indicates if the calendar popover is open. +- **data-invalid**: + When the date-range-picker is invalid. Based on `isInvalid` prop. +- **data-required**: + When the date-range-picker is required. Based on `isRequired` prop. +- **data-readonly**: + When the date-range-picker is readonly. Based on `isReadOnly` prop. +- **data-disabled**: + When the date-range-picker is disabled. Based on `isDisabled` prop. +- **data-has-start-content**: + When the date-range-picker has a start content. Base on those `startContent` prop. +- **data-has-end-content**: + When the date-range-picker has a end content. Base on those `endContent` prop. +- **data-has-multiple-months**: + When the date-range-picker's `visibleMonth` is more than 2. + + + +## Accessibility + +- Each date and time unit is displayed as an individually focusable and editable segment, which allows users an easy way to edit dates using the keyboard, in any date format and locale +- Users can also open a calendar popover to select date ranges in a standard month grid. Localized screen reader messages are included to announce when the selection and visible date range change. +- Date segments are editable using an easy to use numeric keypad, date ranges can be selected by dragging over dates in the calendar using a touch screen, and all interactions are accessible using touch-based screen readers. +- Integrates with HTML forms, supporting required, minimum and maximum values, unavailable dates, custom validation functions, realtime validation, and server-side validation errors + + + +## API + +### DateRangePicker Props + +| Attribute | Type | Description | Default | +| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | +| label | `ReactNode` | The content to display as the label. | - | +| value | `RangeValue` \| `undefined` \| `null` | The current value of the date-range-picker (controlled). | - | +| variant | `flat` \| `bordered` \| `faded` \| `underlined` | The variant of the date input. | `flat` | +| color | `default` \| `primary` \| `secondary` \| `success` \| `warning` \| `danger` | The color of the date input. | `default` | +| size | `sm` \| `md` \| `lg` | The size of the date input. | `md` | +| radius | `none` \| `sm` \| `md` \| `lg` \| `full` | The radius of the date input. | - | +| minValue | `RangeValue` \| `undefined` \| `null` | The minimum value of the date-range-picker. | - | +| maxValue | `RangeValue` \| `undefined` \| `null` | The maximum value of the date-range-picker. | - | +| defaultValue | `string` \| undefined | The default value of the date-range-picker (uncontrolled). | - | +| placeholderValue | `ZonedDateTime` \| `CalendarDate` \| `CalendarDateTime` \| `undefined` \| `null` | The placeholder of the date-range-picker. | - | +| description | `ReactNode` | A description for the date-range-picker. Provides a hint such as specific requirements for what to choose. | - | +| errorMessage | `ReactNode \| (v: ValidationResult) => ReactNode` | An error message for the date input. | - | +| startContent | `ReactNode` | Element to be rendered in the left side of the date-range-picker. | - | +| endContent | `ReactNode` | Element to be rendered in the right side of the date-range-picker. | - | +| startName | `string` | The name of the start date input element, used when submitting an HTML form. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefname) | - | +| endName | `string` | The name of the end date input element, used when submitting an HTML form. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefname) | - | +| labelPlacement | `inside` \| `outside` \| `outside-left` | The position of the label. | `inside` | +| isOpen | `boolean` | Whether the date picker popover is open. | - | +| defaultOpen | `boolean` | Whether the date picker popover is open by default. | `false` | +| isRequired | `boolean` | Whether user input is required on the date-range-picker before form submission. | `false` | +| isReadOnly | `boolean` | Whether the date-range-picker can be selected but not changed by the user. | | +| isDisabled | `boolean` | Whether the date-range-picker is disabled. | `false` | +| isInvalid | `boolean` | Whether the date-range-picker is invalid. | `false` | +| selectorIcon | `ReactNode` | The icon to toggle the date picker popover. Usually a calendar icon. | | +| pageBehavior | `single` \| `visible` | Controls the behavior of paging. Pagination either works by advancing the visible page by visibleDuration (default) or one unit of visibleDuration. | `visible` | +| validate | `(value: { inputValue: string, selectedKey: React.Key }) => ValidationError | true | null | undefined` | Validate input values when committing (e.g., on blur), and return error messages for invalid values. | - | +| visibleMonths | `number` | The number of months to display at once. Up to 3 months are supported. Passing a number greater than 1 will disable the `showMonthAndYearPickers` prop. | `1` | +| autoFocus | `boolean` | Whether the element should receive focus on render. | `false` | +| hourCycle | `12` \| `24` | Whether to display the time in 12 or 24 hour format. This is determined by the user's locale. | - | +| granularity | `day` \| `hour` \| `minute` \| `second` | Determines the smallest unit that is displayed in the date picker. Typically "day" for dates. | - | +| hideTimeZone | `boolean` | Whether to hide the time zone abbreviation. | `false` | +| allowsNonContiguousRanges | `boolean` | When combined with `isDateUnavailable`, determines whether non-contiguous ranges, i.e. ranges containing unavailable dates, may be selected. | false | +| shouldForceLeadingZeros | `boolean` | Whether to always show leading zeros in the month, day, and hour fields. | `true` | +| calendarWidth | `number` | The width to be applied to the calendar component. | `256` | +| CalendarTopContent | `ReactNode` | Top content to be rendered in the calendar component. | | +| CalendarBottomContent | `ReactNode` | Bottom content to be rendered in the calendar component. | | +| allowsNonContiguousRanges | `boolean` | enables a range to be selected even if there are unavailable dates in the middle | false | +| popoverProps | `PopoverProps` | Props to be passed to the popover component. | `{ placement: "bottom", triggerScaleOnOpen: false, offset: 13 }` | +| selectorButtonProps | `ButtonProps` | Props to be passed to the selector button component. | `{ size: "sm", variant: "light", radius: "full", isIconOnly: true }` | +| calendarProps | `CalendarProps` | Props to be passed to the selector button component. | `{ size: "sm", variant: "light", radius: "full", isIconOnly: true }` | +| timeInputProps | `TimeInputProps` | Props to be passed to the time input component. | `{ size: "sm", variant: "light", radius: "full", isIconOnly: true }` | +| disableAnimation | `boolean` | Whether to disable all animations in the date picker. Including the DateInput, Button, Calendar, and Popover. | `false` | +| classNames | `Record<"base" \| "selectorButton" \| "selectorIcon" \| "popoverContent" \| "calendar" \| "calendarContent" \| "timeInputLabel" \| "timeInput", string>` | Allows to set custom class names for the date-range-picker slots. | - | + +### DateRangePicker Events + +| Attribute | Type | Description | | +| ------------- | ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ | --- | +| onChange | `((value: RangeValue) => void)` \| undefined | Handler that is called when the date-range-picker's value changes. | - | +| onOpenChange | `(isOpen: boolean) => void` | Handler that is called when the date picker popover is opened or closed. | - | +| onFocus | `(e: FocusEvent) => void` | Handler that is called when the element receives focus. | - | +| onBlur | `(e: FocusEvent) => void` | Handler that is called when the element loses focus. | - | +| onFocusChange | `(isFocused: boolean) => void` | Handler that is called when the element's focus status changes. | - | +| onKeyDown | `(e: KeyboardEvent) => void` | Handler that is called when a key is pressed. | - | +| onKeyUp | `(e: KeyboardEvent) => void` | Handler that is called when a key is released. | - | diff --git a/apps/docs/content/docs/components/divider.mdx b/apps/docs/content/docs/components/divider.mdx index d95b9db240..464b00af44 100644 --- a/apps/docs/content/docs/components/divider.mdx +++ b/apps/docs/content/docs/components/divider.mdx @@ -15,6 +15,19 @@ Divider is a component that separates content in a page. +## Installation + + + + ## Import +## Installation + + + + ## Import NextUI exports 5 dropdown-related components: diff --git a/apps/docs/content/docs/components/image.mdx b/apps/docs/content/docs/components/image.mdx index 18d1f3cab8..17b10281e2 100644 --- a/apps/docs/content/docs/components/image.mdx +++ b/apps/docs/content/docs/components/image.mdx @@ -15,6 +15,19 @@ The Image component is used to display images with support for fallback. +## Installation + + + + ## Import +## Installation + + + + ## Import ReactNode)` | An error message for the input. | - | +| validate | `(value: string) => ValidationError | true | null | undefined` | Validate input values when committing (e.g. on blur), and return error messages for invalid values. | - | | startContent | `ReactNode` | Element to be rendered in the left side of the input. | - | | endContent | `ReactNode` | Element to be rendered in the right side of the input. | - | | labelPlacement | `inside` \| `outside` \| `outside-left` | The position of the label. | `inside` | diff --git a/apps/docs/content/docs/components/kbd.mdx b/apps/docs/content/docs/components/kbd.mdx index 3a918df838..9495f077a4 100644 --- a/apps/docs/content/docs/components/kbd.mdx +++ b/apps/docs/content/docs/components/kbd.mdx @@ -15,6 +15,18 @@ Keyboard key is a component to display which key or combination of keys performs +## Installation + + + ## Import +## Installation + + + ## Import +## Installation + + + ## Import NextUI exports 3 listbox-related components: diff --git a/apps/docs/content/docs/components/modal.mdx b/apps/docs/content/docs/components/modal.mdx index 6ed55edec9..e7d2c86b29 100644 --- a/apps/docs/content/docs/components/modal.mdx +++ b/apps/docs/content/docs/components/modal.mdx @@ -15,6 +15,19 @@ Displays a dialog with a custom content that requires attention or provides addi +## Installation + + + + ## Import NextUI exports 5 modal-related components: diff --git a/apps/docs/content/docs/components/navbar.mdx b/apps/docs/content/docs/components/navbar.mdx index 769fc849f6..7997c68278 100644 --- a/apps/docs/content/docs/components/navbar.mdx +++ b/apps/docs/content/docs/components/navbar.mdx @@ -15,6 +15,19 @@ A responsive navigation header positioned on top side of your page that includes +## Installation + + + + ## Import NextUI exports 7 navbar-related components: diff --git a/apps/docs/content/docs/components/pagination.mdx b/apps/docs/content/docs/components/pagination.mdx index e2f89eeaf7..e1524a2dac 100644 --- a/apps/docs/content/docs/components/pagination.mdx +++ b/apps/docs/content/docs/components/pagination.mdx @@ -15,6 +15,18 @@ The Pagination component allows you to display active page and navigate between +## Installation + + + ## Import NextUI exports 3 pagination-related components: diff --git a/apps/docs/content/docs/components/popover.mdx b/apps/docs/content/docs/components/popover.mdx index c09e10c5c1..447ce4684e 100644 --- a/apps/docs/content/docs/components/popover.mdx +++ b/apps/docs/content/docs/components/popover.mdx @@ -16,6 +16,18 @@ additional rich content on top of something. +## Installation + + + ## Import NextUI exports 3 popover-related components: diff --git a/apps/docs/content/docs/components/progress.mdx b/apps/docs/content/docs/components/progress.mdx index 2d94b6be10..2de6bea2e8 100644 --- a/apps/docs/content/docs/components/progress.mdx +++ b/apps/docs/content/docs/components/progress.mdx @@ -15,6 +15,18 @@ The Progress component allows you to view the progress of any activity. +## Installation + + + ## Import +## Installation + + + ## Import ReactNode)` | Radio group error message. | - | +| validate | `(value: string) => ValidationError | true | null | undefined` | Validate input values when committing (e.g. on blur), and return error messages for invalid values. | - | | isDisabled | `boolean` | Whether the radio group is disabled. | `false` | | isRequired | `boolean` | Whether user checkboxes are required on the input before form submission. | `false` | | isReadOnly | `boolean` | Whether the checkboxes can be selected but not changed by the user. | - | diff --git a/apps/docs/content/docs/components/range-calendar.mdx b/apps/docs/content/docs/components/range-calendar.mdx new file mode 100644 index 0000000000..8349f85a50 --- /dev/null +++ b/apps/docs/content/docs/components/range-calendar.mdx @@ -0,0 +1,264 @@ +--- +title: "Range Calendar" +description: "The Range Calendar component is used to display one or more date grids and allows users to select a contiguous range of dates." +--- + +import {rangeCalendarContent} from "@/content/components/range-calendar"; + +# Range Calendar + +A range calendar consists of a grouping element containing one or more date grids (e.g. months), and a previous and next button for navigating through time. Each calendar grid consists of cells containing button elements that can be pressed and navigated to using the arrow keys to select a date range. Once a start date is selected, the user can navigate to another date using the keyboard or by hovering over it, and clicking it or pressing the Enter key commits the selected date range. + + + +--- + + + +## Installation + + + +## Import + + + +## Usage + +A RangeCalendar has no selection by default. An initial, uncontrolled value can be provided to the RangeCalendar using the `defaultValue` prop. Alternatively, a controlled value can be provided using the `value` prop. + +Date values are provided using objects in the [@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/) package. This library handles correct international date manipulation across calendars, time zones, and other localization concerns. + + + +### Disabled + +The `isDisabled` boolean prop makes the Calendar disabled. Cells cannot be focused or selected. + + + +### Read Only + +The `isReadOnly` boolean prop makes the Calendar's value immutable. Unlike `isDisabled`, the Calendar remains focusable. + + + +### Controlled + +A Calendar has no selection by default. An initial, uncontrolled value can be provided to the Calendar using the `defaultValue` prop. Alternatively, a controlled value can be provided using the value prop. + + + +### Min Date Value + +By default, Calendar allows selecting any date. The `minValue` can also be used to prevent the user from selecting dates outside a certain range. + +This example only accepts dates after today. + + + +### Max Date Value + +By default, Calendar allows selecting any date. The `maxValue` can also be used to prevent the user from selecting dates outside a certain range. + +This example only accepts dates before today. + + + +### Unavailable Dates + +Calendar supports marking certain dates as unavailable. These dates remain focusable with the keyboard so that navigation is consistent, but cannot be selected by the user. In this example, they are displayed in red. The `isDateUnavailable` prop accepts a callback that is called to evaluate whether each visible date is unavailable. + + + +### Non-Contiguous Ranges + +The `allowsNonContiguousRanges` prop enables a range to be selected even if there are unavailable dates in the middle. The value emitted in the onChange event will still be a single range with a start and end property, but unavailable dates will not be displayed as selected. It is up to applications to split the full selected range into multiple as needed for business logic. + +This example prevents selecting weekends, but allows selecting ranges that span multiple weeks. + + + +### Controlled Focused Value + +Calendar tries to avoid allowing the user to select invalid dates in the first place. However, if according to application logic a selected date is invalid, the isInvalid prop can be set. This alerts assistive technology users that the selection is invalid, and can be used for styling purposes as well. In addition, the errorMessage slot may be used to help the user fix the issue. + +By default, the selected date is focused when a Calendar first mounts. If no `value` or `defaultValue` prop is provided, then the current date is focused. However, Calendar supports controlling which date is focused using the `focusedValue` and `onFocusChange` props. This also determines which month is visible. The `defaultFocusedValue` prop allows setting the initial focused date when the Calendar first mounts, without controlling it. + + + +### Invalid Date + +This example validates that the selected date is a weekday and not a weekend according to the current locale. + + + +### International Calendars + +Calendar supports selecting dates in many calendar systems used around the world, including Gregorian, Hebrew, Indian, Islamic, Buddhist, and more. Dates are automatically displayed in the appropriate calendar system for the user's locale. The calendar system can be overridden using the [Unicode calendar locale extension](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/calendar#adding_a_calendar_in_the_locale_string), passed to the `Provider` component. + + + +### Visible Months + +By default, the Calendar displays a single month. The `visibleMonths` prop allows displaying up to 3 months at a time. + + + +### Page Behaviour + +By default, when pressing the next or previous buttons, pagination will advance by the `visibleMonths` value. This behavior can be changed to page by single months instead, by setting `pageBehavior` to `single`. + + + +### Presets + +Here's the example to customize `topContent` and `bottomContent` to have some preset values. + + + +## Slots + +- **base**: Calendar wrapper, it handles alignment, placement, and general appearance. +- **prevButton**: The previous button of the calendar. +- **nextButton**: The next button of the calendar. +- **headerWrapper**: Wraps the picker (month / year). +- **header**: The header element. +- **title**: A description of the visible date range, for use in the calendar title. +- **gridWrapper**: The wrapper for the calendar grid. +- **grid**: The date grid element (e.g. ``). +- **gridHeader**: The date grid header element (e.g. ``). +- **gridHeaderCell**: The date grid header cell element (e.g. ``). +- **gridBodyRow**: The date grid body row element (e.g. ``). +- **cell**: The date grid cell element (e.g. ` + ); +} diff --git a/packages/components/calendar/src/calendar-context.ts b/packages/components/calendar/src/calendar-context.ts new file mode 100644 index 0000000000..474799e91d --- /dev/null +++ b/packages/components/calendar/src/calendar-context.ts @@ -0,0 +1,13 @@ +import type {ContextType} from "./use-calendar-base"; +import type {CalendarState, RangeCalendarState} from "@react-stately/calendar"; + +import {createContext} from "@nextui-org/react-utils"; + +export const [CalendarProvider, useCalendarContext] = createContext< + ContextType +>({ + name: "CalendarContext", + strict: true, + errorMessage: + "useContext: `context` is undefined. Seems you forgot to wrap component within the CalendarProvider", +}); diff --git a/packages/components/calendar/src/calendar-header.tsx b/packages/components/calendar/src/calendar-header.tsx new file mode 100644 index 0000000000..7e04926dd1 --- /dev/null +++ b/packages/components/calendar/src/calendar-header.tsx @@ -0,0 +1,112 @@ +import type {ButtonProps} from "@nextui-org/button"; +import type {CalendarDate} from "@internationalized/date"; + +import {HTMLNextUIProps} from "@nextui-org/system"; +import {useDateFormatter} from "@react-aria/i18n"; +import {m} from "framer-motion"; +import {Button} from "@nextui-org/button"; +import {useCallback} from "react"; + +import {slideVariants} from "./calendar-transitions"; +import {ChevronDownIcon} from "./chevron-down"; +import {useCalendarContext} from "./calendar-context"; + +export interface CalendarHeaderProps extends HTMLNextUIProps<"header"> { + direction: number; + date: CalendarDate; + currentMonth: CalendarDate; + buttonPickerProps?: ButtonProps; +} + +export function CalendarHeader(props: CalendarHeaderProps) { + const {direction, date, currentMonth, buttonPickerProps} = props; + + const { + state, + slots, + headerRef, + showMonthAndYearPickers, + isHeaderExpanded, + setIsHeaderExpanded, + disableAnimation, + classNames, + } = useCalendarContext(); + + const monthAndYearDateFormatter = useDateFormatter({ + month: "long", + era: + currentMonth.calendar.identifier === "gregory" && currentMonth.era === "BC" + ? "short" + : undefined, + calendar: currentMonth.calendar.identifier, + timeZone: state.timeZone, + year: "numeric", + }); + + const monthDateContent = monthAndYearDateFormatter.format(date.toDate(state.timeZone)); + + const headerTitle = ( + <> + {/* // We have a visually hidden heading describing the entire visible range, + // and the calendar itself describes the individual month + // so we don't need to repeat that here for screen reader users. */} + {disableAnimation ? ( + + {monthDateContent} + + ) : ( + + {monthDateContent} + + )} + + ); + + const headerProps = { + ref: headerRef, + className: slots?.header({class: classNames?.header}), + "data-slot": "header", + }; + + const handleKeyDown = useCallback( + (e: React.KeyboardEvent) => { + // Escape key + if (e.key === "Escape") { + e.preventDefault(); + e.stopPropagation(); + // Close the month and year pickers + setIsHeaderExpanded?.(false); + } + }, + [setIsHeaderExpanded], + ); + + return showMonthAndYearPickers ? ( + + ) : ( +
{headerTitle}
+ ); +} diff --git a/packages/components/calendar/src/calendar-month.tsx b/packages/components/calendar/src/calendar-month.tsx new file mode 100644 index 0000000000..7c7968fa40 --- /dev/null +++ b/packages/components/calendar/src/calendar-month.tsx @@ -0,0 +1,143 @@ +import type {CalendarState, RangeCalendarState} from "@react-stately/calendar"; + +import {CalendarDate, endOfMonth, getWeeksInMonth} from "@internationalized/date"; +import {CalendarPropsBase} from "@react-types/calendar"; +import {HTMLNextUIProps} from "@nextui-org/system"; +import {useLocale} from "@react-aria/i18n"; +import {useCalendarGrid} from "@react-aria/calendar"; +import {m} from "framer-motion"; +import {dataAttr} from "@nextui-org/shared-utils"; +import {useEffect, useState} from "react"; + +import {CalendarCell} from "./calendar-cell"; +import {slideVariants} from "./calendar-transitions"; +import {useCalendarContext} from "./calendar-context"; + +export interface CalendarMonthProps extends HTMLNextUIProps<"table">, CalendarPropsBase { + startDate: CalendarDate; + currentMonth: number; + direction: number; +} + +export function CalendarMonth(props: CalendarMonthProps) { + const {startDate, direction, currentMonth} = props; + + const {locale} = useLocale(); + const weeksInMonth = getWeeksInMonth(startDate, locale); + + const { + state: stateProp, + slots, + weekdayStyle, + isHeaderExpanded, + disableAnimation, + classNames, + } = useCalendarContext(); + + // Self-controlled state + const [state, setState] = useState(() => stateProp); + + /** + * This avoid focusing the date cell when navigating through the picker' + * months/years with the keyboard. + */ + useEffect(() => { + if (isHeaderExpanded) { + return; + } + + setState(stateProp); + }, [stateProp, isHeaderExpanded]); + + const {gridProps, headerProps, weekDays} = useCalendarGrid( + { + ...props, + weekdayStyle, + endDate: endOfMonth(startDate), + }, + state, + ); + + const bodyContent = [...new Array(weeksInMonth).keys()].map((weekIndex) => ( +
+ {state + .getDatesInWeek(weekIndex, startDate) + .map((date, i) => + date ? ( + + ) : ( + + )); + + return ( +
`). +- **gridHeaderRow**: The date grid header row element (e.g. `
`). +- **gridBody**: The date grid body element (e.g. `
`). +- **cellButton**: The button element within the cell. +- **pickerWrapper**: The wrapper for the picker +- **pickerMonthList**: The month list picker. +- **pickerYearList**: The year list picker. +- **pickerHighlight**: The highlighted item of the picker. +- **pickerItem**: The item of the picker. +- **helperWrapper**: The helper message of the calendar. +- **errorMessage**: The error message of the calendar. + + + +## Data Attributes + +`Calendar` has the following attributes on the `CalendarCell` element: + +- **data-focused**: + Whether the cell is focused. +- **data-hovered**: + Whether the cell is currently hovered with a mouse. +- **data-pressed**: + Whether the cell is currently being pressed. +- **data-unavailable**: + Whether the cell is unavailable, according to the calendar's `isDateUnavailable` prop. Unavailable dates remain focusable, but cannot be selected by the user. They should be displayed with a visual affordance to indicate they are unavailable, such as a different color or a strikethrough. +- **data-disabled**: + Whether the cell is disabled, according to the calendar's `minValue`, `maxValue`, and `isDisabled` props. +- **data-focus-visible**: + Whether the cell is keyboard focused. +- **data-outside-visible-range**: + Whether the cell is outside the visible range of the calendar. +- **data-outside-month**: + Whether the cell is outside the current month. +- **data-selected**: + Whether the cell is selected. +- **data-selected-start**: + Whether the cell is the first date in a range selection. +- **data-selected-end**: + Whether the cell is the last date in a range selection. +- **data-invalid**: + Whether the cell is part of an invalid selection. + + + +## Accessibility + +- Display one or more months at once, or a custom time range for use cases like a week view. Minimum and maximum values, unavailable dates, and non-contiguous selections are supported as well. +- Support for 13 calendar systems used around the world, including Gregorian, Buddhist, Islamic, Persian, and more. Locale-specific formatting, number systems, and right-to-left support are available as well. +- Calendar cells can be navigated and selected using the keyboard, and localized screen reader messages are included to announce when the selection and visible date range change. + + + +## API + +### RangeCalendar Props + +| Attribute | Type | Description | Default | | +| ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | --- | +| value | `RangeValue | null` | The current value (controlled). | - | +| defaultValue | `RangeValue | null` | The default value (uncontrolled). | - | +| minValue | `DateValue` | The minimum allowed date that a user may select. | - | | +| maxValue | `DateValue` | The maximum allowed date that a user may select. | - | | +| color | `default` \| `primary` \| `secondary` \| `success` \| `warning` \| `danger` | The color of the time input. | `default` | +| visibleMonths | `number` | The number of months to display at once. Up to 3 months are supported. Passing a number greater than 1 will disable the `showMonthAndYearPickers` prop | `1` | | +| focusedValue | `DateValue` | Controls the currently focused date within the calendar. | - | | +| defaultFocusedValue | `DateValue` | The date that is focused when the calendar first mounts (uncountrolled). | - | | +| calendarWidth | `number` \| `string` | The width to be applied to the calendar component. This value is multiplied by the `visibleMonths` number to determine the total width of the calendar. | `256` | +| pageBehavior | `PageBehavior` | Controls the behavior of paging. Pagination either works by advancing the visible page by visibleDuration (default) or one unit of visibleDuration. | `visible` | | +| weekdayStyle | `"narrow" \|"short" \| "long" \| undefined` | The style of weekday names to display in the calendar grid header, e.g. single letter, abbreviation, or full day name. | `narrow` | | +| allowsNonContiguousRanges | `boolean` | When combined with `isDateUnavailable`, determines whether non-contiguous ranges, i.e. ranges containing unavailable dates, may be selected. | `false` | | +| showMonthAndYearPickers | `boolean` | Whether the label should be crossed out. | `false` | | +| isDisabled | `boolean` | Whether the calendar is disabled. | `false` | | +| isReadOnly | `boolean` | Whether the calendar value is immutable. | `false` | | +| isInvalid | `boolean` | Whether the current selection is invalid according to application logic. | - | | +| autoFocus | `boolean` | Whether to automatically focus the calendar when it mounts. | `false` | | +| showHelper | `boolean` | Whether to show the description or error message. | `false` | | +| showShadow | `boolean` | Whether to show the shadow in the selected dates. | `false` | +| isHeaderExpanded | `boolean` | Whether the calendar header is expanded. This is only available if the `showMonthAndYearPickers` prop is set to `true`. | `false` | | +| isHeaderDefaultExpanded | `boolean` | Whether the calendar header should be expanded by default.This is only available if the `showMonthAndYearPickers` prop is set to `true`. | `false` | | +| topContent | `ReactNode` | Custom content to be included in the top of the calendar. | - | | +| bottomContent | `ReactNode` | Custom content to be included in the bottom of the calendar. | - | | +| isDateUnavailable | `(date: DateValue) => boolean` | Callback that is called for each date of the calendar. If it returns true, then the date is unavailable. | - | | +| createCalendar | `(calendar: SupportedCalendars) => Calendar \| null` | This function helps to reduce the bundle size by providing a custom calendar system. You can also use the NextUIProvider to provide the createCalendar function to all nested components. | `all
calendars` | | +| errorMessage | `ReactNode \| (v: ValidationResult) => ReactNode` | An error message for the field. | - | +| validate | `(value: { inputValue: string, selectedKey: React.Key }) => ValidationError | true | null | undefined` | Validate time input values when committing (e.g. on blur), and return error messages for invalid values. | - | +| hideDisabledDates | `boolean` | Whether to hide the disabled or invalid dates. | `false` | +| disableAnimation | `boolean` | Whether to disable the animation of the calendar. | `false` | +| classNames | `Record<"base"| "prevButton"| "nextButton"| "headerWrapper" \| "header" \| "title" \| "content" \| "gridWrapper" \| "grid" \| "gridHeader" \| "gridHeaderRow" \| "gridHeaderCell" \| "gridBody" \| "gridBodyRow" \| "cell" \| "cellButton" \| "pickerWrapper" \| "pickerMonthList" \| "pickerYearList" \| "pickerHighlight" \| "pickerItem" \| "helperWrapper" \| "errorMessage", string>` | Allows to set custom class names for the calendar slots. | - | | + +### RangeCalendar Events + +| Attribute | Type | Description | +| ---------------------- | ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | +| onFocusChange | `(date: CalendarDate) => void` | Handler that is called when the focused date changes. | +| onChange | `(value: RangeValue>) => void` | Handler that is called when the value changes. | +| onHeaderExpandedChange | `(isExpanded: boolean) => void` | The event handler for the calendar header expanded state. This is only available if the `showMonthAndYearPickers` prop is set to `true`. | + +#### Supported Calendars + +```ts +/** + * Supported react-aria i18n calendars. + */ +export type SupportedCalendars = + | "buddhist" + | "ethiopic" + | "ethioaa" + | "coptic" + | "hebrew" + | "indian" + | "islamic-civil" + | "islamic-tbla" + | "islamic-umalqura" + | "japanese" + | "persian" + | "roc" + | "gregory"; +``` diff --git a/apps/docs/content/docs/components/scroll-shadow.mdx b/apps/docs/content/docs/components/scroll-shadow.mdx index 952e227271..61e5b1844a 100644 --- a/apps/docs/content/docs/components/scroll-shadow.mdx +++ b/apps/docs/content/docs/components/scroll-shadow.mdx @@ -15,6 +15,18 @@ Applies top and bottom shadows when content overflows on scroll. +## Installation + + + ## Import +## Installation + + + ## Import NextUI exports 3 select-related components: @@ -349,7 +361,7 @@ the popover and listbox components. | labelPlacement | `inside` \| `outside` \| `outside-left` | The position of the label. | `inside` | | label | `ReactNode` | The content to display as the label. | - | | description | `ReactNode` | A description for the select. Provides a hint such as specific requirements for what to choose. | - | -| errorMessage | `ReactNode` | An error message for the select. | - | +| errorMessage | `ReactNode` \| `((v: ValidationResult) => ReactNode)` | An error message for the select. | - | | startContent | `ReactNode` | Element to be rendered in the left side of the select. | - | | endContent | `ReactNode` | Element to be rendered in the right side of the select. | - | | selectorIcon | `ReactNode` | Element to be rendered as the selector icon. | - | diff --git a/apps/docs/content/docs/components/skeleton.mdx b/apps/docs/content/docs/components/skeleton.mdx index c0bb7ec4a8..dbf755a63f 100644 --- a/apps/docs/content/docs/components/skeleton.mdx +++ b/apps/docs/content/docs/components/skeleton.mdx @@ -15,6 +15,18 @@ Skeleton is a placeholder to show a loading state and the expected shape of a co +## Installation + + + ## Import +## Installation + + + ## Import +## Installation + + + + ## Import +## Installation + + + + ## Import +## Installation + + + + ## Import +## Installation + + + + ## Import +## Installation + + + + ## Import NextUI exports 6 table-related components: diff --git a/apps/docs/content/docs/components/tabs.mdx b/apps/docs/content/docs/components/tabs.mdx index b927dda7b8..e47fbb4afb 100644 --- a/apps/docs/content/docs/components/tabs.mdx +++ b/apps/docs/content/docs/components/tabs.mdx @@ -15,6 +15,18 @@ Tabs organize content into multiple sections and allow users to navigate between +## Installation + + + ## Import NextUI exports 2 tabs-related components: @@ -73,6 +85,18 @@ You can use the `onSelectionChange` and `selectedKey` props to control the selec +### Placement + +You can change the position of the tabs by using the `placement` prop. The default value is `top`. + + + +### Vertical + +Change the orientation of the tabs it will invalidate the placement prop when the value is `true`. + + + ### Links Tabs items can be rendered as links by passing the `href` prop to the `Tab` component. By @@ -237,7 +261,9 @@ You can customize the `Tabs` component by passing custom Tailwind CSS classes to | disableCursorAnimation | `boolean` | Whether the cursor should be hidden. | `false` | | isDisabled | `boolean` | Whether the tab list should be disabled. | `false` | | disableAnimation | `boolean` | Whether the tab list should be animated. | `false` | -| classNames | `Record<"base"| "tabList"| "tab"| "tabContent"| "cursor" | "panel", string>` | Allows to set custom class names for the card slots. | - | +| classNames | `Record<"base"| "tabList"| "tab"| "tabContent"| "cursor" | "panel", string>` | Allows to set custom class names for the card slots. | - | +| placement | `top` \| `bottom` \| `start` \| `end` | The position of the tabs. | `top` | +| isVertical | `boolean` | Whether the tabs are vertical. | `false` | ### Tabs Events diff --git a/apps/docs/content/docs/components/textarea.mdx b/apps/docs/content/docs/components/textarea.mdx index 738b3befff..96f2f7c113 100644 --- a/apps/docs/content/docs/components/textarea.mdx +++ b/apps/docs/content/docs/components/textarea.mdx @@ -15,6 +15,19 @@ Textarea component is a multi-line Input which allows you to write large texts. +## Installation + + + + ## Import ReactNode)` | An error message for the textarea. | - | +| validate | `(value: string) => ValidationError | true | null | undefined` | Validate input values when committing (e.g. on blur), and return error messages for invalid values. | - | | labelPlacement | `inside` \| `outside` \| `outside-left` | The position of the label. | `inside` | | fullWidth | `boolean` | Whether the textarea should take up the width of its parent. | `true` | | isRequired | `boolean` | Whether user input is required on the textarea before form submission. | `false` | @@ -152,7 +166,7 @@ You can use the `value` and `onValueChange` properties to control the input valu | validationState | `valid` \| `invalid` | Whether the textarea should display its "valid" or "invalid" visual styling. (**Deprecated**) use **isInvalid** instead. | - | | disableAutosize | `boolean` | Whether the textarea auto vertically resize should be disabled. | `false` | | disableAnimation | `boolean` | Whether the textarea should be animated. | `false` | -| classNames | `Record<"base"| "label"| "inputWrapper"| "innerWrapper" | "input" | "description" | "errorMessage", string>` | Allows to set custom class names for the checkbox slots. | - | +| classNames | `Record<"base"| "label"| "inputWrapper"| "innerWrapper" | "input" | "description" | "errorMessage", string>` | Allows to set custom class names for the checkbox slots. | - | ### Input Events diff --git a/apps/docs/content/docs/components/time-input.mdx b/apps/docs/content/docs/components/time-input.mdx new file mode 100644 index 0000000000..e973d72797 --- /dev/null +++ b/apps/docs/content/docs/components/time-input.mdx @@ -0,0 +1,238 @@ +--- +title: "Time Input" +description: "A time input allows users to enter and edit time values using a keyboard. Each part of a time value is displayed in an individually editable segment." +--- + +import {timeInputContent} from "@/content/components/time-input"; + +# Time Input + +The `TimeInput` component consists of a label, and a group of segments representing each unit of a time (e.g. hours, minutes, and seconds). Each segment is individually focusable and editable by the user, by typing or using the arrow keys to increment and decrement the value. This approach allows values to be formatted and parsed correctly regardless of the locale or time format, and offers an easy and error-free way to edit times using the keyboard. + + + +--- + + + +## Installation + + + + +## Import + + + +## Usage + +A `TimeInput` displays a placeholder by default. An initial, uncontrolled value can be provided to the TimeField using the defaultValue prop. Alternatively, a controlled value can be provided using the value prop. + +Time values are provided using objects in the `@internationalized/date` package. This library handles correct international date and time manipulation across calendars, time zones, and other localization concerns. + +`TimeInput` only supports selecting times, but values with date components are also accepted. By default, `TimeInput` will emit `Time` objects in the onChange event, but if a `CalendarDateTime` or `ZonedDateTime` object is passed as the `value` or `defaultValue`, values of that type will be emitted, changing only the time and preserving the date components. + + + +### Required + +`TimeInput` supports the `isRequired` prop to ensure the user enters a value, as well as minimum and maximum values, and custom client and server-side validation. + + + +### Disabled + +The `isDisabled` boolean prop makes `TimeInput` disabled. Inputs cannot be focused or selected. + + + +### Read Only + +The `isReadOnly` boolean prop makes `TimeInput`'s value immutable. Unlike `isDisabled`, `TimeInput` remains focusable. + + + +### Without Label + +`TimeInput` supports the `label` prop to show or not show the label. + + + +### With Description + +A description for the field. Provides a hint such as specific requirements for what to choose. + + + +### Label Placement + +The label's overall position relative to the element it is labeling. + + + +### Start Content + +If you want to display some content before the time inputs, you can set the `startContent` property. + + + +### End Content + +If you want to display some content after the time inputs, you can set the `endContent` property. + + + +### Controlled + +An initial, uncontrolled value can be provided to the `TimeInput` using the `defaultValue` prop. A controlled value can be provided using the `value` prop. + + + +### Time Zones + +`TimeInput` is time zone aware when a `ZonedDateTime` object is provided as the value. In this case, the time zone abbreviation is displayed, and time zone concerns such as daylight saving time are taken into account when the value is manipulated. + +In most cases, your data will come from and be sent to a server as an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) formatted string. [@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/) includes functions for parsing strings in multiple formats into ZonedDateTime objects. Which format you use will depend on what information you need to store. + +- `parseZonedDateTime` – This function parses a date with an explicit time zone and optional UTC offset attached (e.g. `2021-11-07T00:45[America/Los_Angeles]` or `2021-11-07T00:45-07:00[America/Los_Angeles]`). This format preserves the maximum amount of information. If the exact local time and time zone that a user selected is important, use this format. Storing the time zone and offset that was selected rather than converting to UTC ensures that the local time is correct regardless of daylight saving rule changes (e.g. if a locale abolishes DST). Examples where this applies include calendar events, reminders, and other times that occur in a particular location. +- `parseAbsolute` – This function parses an absolute date and time that occurs at the same instant at all locations on Earth. It can be represented in UTC (e.g. `2021-11-07T07:45:00Z`), or stored with a particular offset (e.g. `2021-11-07T07:45:00-07:00`). A time zone identifier, e.g. America/Los_Angeles, must be passed, and the result will be converted into that time zone. Absolute times are the best way to represent events that occurred in the past, or future events where an exact time is needed, regardless of time zone. +- `parseAbsoluteToLocal` – This function parses an absolute date and time into the current user's local time zone. It is a shortcut for parseAbsolute, and accepts the same formats. + + + +### Granularity + +The `granularity` prop allows you to control the smallest unit that is displayed by TimeInput. By default, times are displayed with "minute" granularity. More granular time values can be displayed by setting the granularity prop to "second". + + + +### Min Time Value + +The `minValue` prop allows you to validate time value before a certain time. + + + +### Max Time Value + +The `maxValue` prop allows you to validate time value before a certain time. + + + +### Placeholder Value + +When no value is set, a placeholder is shown. The format of the placeholder is influenced by the `granularity` and `placeholderValue` props. placeholderValue also controls the default values of each segment when the user first interacts with them, e.g. using the up and down arrow keys. By default, the placeholderValue is midnight, but you can set it to a more appropriate value if needed. + + + +### Hide Time Zone + +When a `ZonedDateTime` object is provided as the value to `TimeInput`, the time zone abbreviation is displayed by default. However, if this is displayed elsewhere or implicit based on the usecase, it can be hidden using the `hideTimeZone` option. + + + +### Hour Cycle + +By default, `TimeInput` displays times in either 12 or 24 hour hour format depending on the user's locale. However, this can be overridden using the `hourCycle` prop if needed for a specific usecase. This example forces `TimeInput` to use 24-hour time, regardless of the locale. + + + +## Slots + +- **base**: Input wrapper, it handles alignment, placement, and general appearance. +- **label**: Label of the time input, it is the one that is displayed above, inside or left of the time input. +- **inputWrapper**: Wraps the `label` (when it is inside) and the `innerWrapper`. +- **input**: The time input element. +- **innerWrapper**: Wraps the segments, the `startContent` and the `endContent`. +- **segment**: The segment of input elements. +- **helperWrapper**: The wrapper of the helper text. This wraps the helper text and the error message. +- **description**: The description of the time input. +- **errorMessage**: The error message of the time input. + + + +## Data Attributes + +`TimeInput` has the following attributes on the `base` element: + +- **data-has-helper**: + When the time input has description or error message. Based on `description` or `errorMessage` props. +- **data-required**: + When the time input is required. Based on `isRequired` prop. +- **data-disabled**: + When the time input is disabled. Based on `isDisabled` prop. +- **data-readonly**: + When the time input is readonly. Based on `isReadOnly` prop. +- **data-invalid**: + When the time input is invalid. Based on `isInvalid` prop. +- **data-has-start-content**: + When the time input has start content. Based on `startContent` prop. +- **data-has-end-content**: + When the time input has end content. Based on `endContent` prop. + + + +## Accessibility + +- Support for locale-specific formatting, number systems, hour cycles, and right-to-left layout. +- Times can optionally include a time zone. All modifications follow time zone rules such as daylight saving time. +- Each time unit is displayed as an individually focusable and editable segment, which allows users an easy way to edit times using the keyboard, in any format and locale. +- Time segments are editable using an easy to use numeric keypad, and all interactions are accessible using touch-based screen readers. + + + +## API + +### TimeInput Props + +| Attribute | Type | Description | Default | +| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------- | +| label | `ReactNode` | The content to display as the label. | - | +| name | `string` | The name of the time input element, used when submitting an HTML form. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefname). | - | +| value | `TimeValue \| null` | The current value (controlled). | - | +| defaultValue | `TimeValue \| null` | The default value (uncontrolled). | - | +| variant | `flat` \| `bordered` \| `faded` \| `underlined` | The variant of the time input. | `flat` | +| color | `default` \| `primary` \| `secondary` \| `success` \| `warning` \| `danger` | The color of the time input. | `default` | +| size | `sm` \| `md` \| `lg` | The size of the time input. | `md` | +| radius | `none` \| `sm` \| `md` \| `lg` \| `full` | The radius of the time input. | - | +| hourCycle | `12 \| 24` | Whether to display the time in 12 or 24 hour format. By default, this is determined by the user's locale. | - | +| granularity | `'hour' \| 'minute' \| 'second'` | Determines the smallest unit that is displayed in the time picker. | `minute` | +| hideTimeZone | `boolean` | Whether to hide the time zone abbreviation. | - | +| labelPlacement | `inside` \| `outside` \| `outside-left` | The position of the label. | `inside` | +| shouldForceLeadingZeros | `boolean` | Whether to always show leading zeros in the hour field. By default, this is determined by the user's locale. | `true` | +| placeholderValue | `TimeValue` | A placeholder time that influences the format of the placeholder shown when no value is selected. Defaults to 12:00 AM or 00:00 depending on the hour cycle. | - | +| minValue | `TimeValue` | The minimum allowed time that a user may select. | - | +| maxValue | `TimeValue` | The maximum allowed time that a user may select. | - | +| isDisabled | `boolean` | Whether the time input is disabled. | - | +| isReadOnly | `boolean` | Whether the time input can be selected but not changed by the user. | - | +| isRequired | `boolean` | Whether user time input is required on the time input before form submission. | - | +| isInvalid | `boolean` | Whether the time input is invalid. | - | +| autoFocus | `boolean` | Whether the element should receive focus on render. | - | +| description | `ReactNode` | A description for the field. Provides a hint such as specific requirements for what to choose. | - | +| errorMessage | `ReactNode \| (v: ValidationResult) => ReactNode` | An error message for the field. | - | +| validate | `(value: { inputValue: string, selectedKey: React.Key }) => ValidationError | true | null | undefined` | Validate time input values when committing (e.g. on blur), and return error messages for invalid values. | - | +| disableAnimation | `boolean` | Whether to disable the animation of the time input. | - | +| classNames | `Record<"base"| "label"| "inputWrapper"| "innerWrapper" | "segment" | "helperWrapper" | "input" | "description" | "errorMessage", string>` | Allows to set custom class names for the time input slots. | - | + +### TimeInput Events + +| Attribute | Type | Description | +| ------------- | --------------------------------------------- | --------------------------------------------------------------- | +| onFocus | `(e: FocusEvent) => void` | Handler that is called when the element receives focus. | +| onBlur | `(e: FocusEvent) => void` | Handler that is called when the element loses focus. | +| onFocusChange | `(isFocused: boolean) => void` | Handler that is called when the element's focus status changes. | +| onKeyDown | `(e: KeyboardEvent) => void` | Handler that is called when a key is pressed. | +| onKeyUp | `(e: KeyboardEvent) => void` | Handler that is called when a key is released. | +| onChange | `(value: MappedTimeValue) => void` | Handler that is called when the value changes. | diff --git a/apps/docs/content/docs/components/tooltip.mdx b/apps/docs/content/docs/components/tooltip.mdx index c5e883ecdb..d9723e5730 100644 --- a/apps/docs/content/docs/components/tooltip.mdx +++ b/apps/docs/content/docs/components/tooltip.mdx @@ -15,6 +15,19 @@ Tooltips display a brief, informative message that appears when a user interacts +## Installation + + + + ## Import +## Installation + + + + ## Import +
This is a primary color box
``` @@ -169,8 +169,6 @@ import semanticColorsExample from "@/content/customization/colors/semantic-color -> **Note**: To know more about units see the [Layout Units](/docs/customization/layout#using-units) section. - ### Javascript Variables Import semantic and common colors into your JavaScript files as follows: @@ -205,10 +203,10 @@ Then you can use the CSS variables in your CSS files. ```css /* With default prefix */ .my-component { - background-color: var(--nextui-primary-500); + background-color: hsl(var(--nextui-primary-500)); } /* With custom prefix */ .my-component { - background-color: var(--myapp-primary-500); + background-color: hsl(var(--myapp-primary-500)); } ``` diff --git a/apps/docs/content/docs/customization/custom-variants.mdx b/apps/docs/content/docs/customization/custom-variants.mdx index 0059e2e879..84a05d1c4a 100644 --- a/apps/docs/content/docs/customization/custom-variants.mdx +++ b/apps/docs/content/docs/customization/custom-variants.mdx @@ -47,9 +47,9 @@ export const MyButton = extendVariants(Button, { true: "bg-[#eaeaea] text-[#000] opacity-50 cursor-not-allowed", }, size: { - xs: "px-unit-2 min-w-unit-12 h-unit-6 text-tiny gap-unit-1 rounded-small", - md: "px-unit-4 min-w-unit-20 h-unit-10 text-small gap-unit-2 rounded-small", - xl: "px-unit-8 min-w-unit-28 h-unit-14 text-large gap-unit-4 rounded-medium", + xs: "px-2 min-w-12 h-6 text-tiny gap-1 rounded-small", + md: "px-4 min-w-20 h-10 text-small gap-2 rounded-small", + xl: "px-8 min-w-28 h-14 text-large gap-4 rounded-medium", }, }, defaultVariants: { // <- modify/add default variants @@ -151,15 +151,15 @@ const MyInput = extendVariants(Input, { }, size: { xs: { - inputWrapper: "h-unit-6 min-h-unit-6 px-1", + inputWrapper: "h-6 min-h-6 px-1", input: "text-tiny", }, md: { - inputWrapper: "h-unit-10 min-h-unit-10", + inputWrapper: "h-10 min-h-10", input: "text-small", }, xl: { - inputWrapper: "h-unit-14 min-h-unit-14", + inputWrapper: "h-14 min-h-14", input: "text-medium", }, }, diff --git a/apps/docs/content/docs/customization/layout.mdx b/apps/docs/content/docs/customization/layout.mdx index 430e8eb445..903c25185c 100644 --- a/apps/docs/content/docs/customization/layout.mdx +++ b/apps/docs/content/docs/customization/layout.mdx @@ -46,9 +46,8 @@ module.exports = { plugins: [ nextui({ layout: { - spacingUnit: 4, // in px - disabledOpacity: 0.5, // this value is applied as opacity-[value] when the component is disabled dividerWeight: "1px", // h-divider the default height applied to the divider component + disabledOpacity: 0.5, // this value is applied as opacity-[value] when the component is disabled fontSize: { tiny: "0.75rem", // text-tiny small: "0.875rem", // text-small @@ -111,84 +110,6 @@ module.exports = { }; ``` -## Units - -Units tokens define consistent spacing, padding, margin, gap and sizes across the components. Based on the -`spacingUnit` token (default 4px), NextUI auto-generates the following units: - -```ts -// spacingUnit = 4px -{ - 'unit-xs': '8px', // 2 * spacingUnit - 'unit-sm': '12px', // 3 * spacingUnit - 'unit-md': '16px', // 4 * spacingUnit - 'unit-lg': '22px', // 5.5 * spacingUnit - 'unit-xl': '36px', // 9 * spacingUnit - 'unit-2xl': '48px', // 12 * spacingUnit - 'unit-3xl': '80px', // 20 * spacingUnit - 'unit-4xl': '120px', // 30 * spacingUnit - 'unit-5xl': '224px', // 56 * spacingUnit - 'unit-6xl': '288px', // 72 * spacingUnit - 'unit-7xl': '384px', // 96 * spacingUnit - 'unit-8xl': '512px', // 128 * spacingUnit - 'unit-9xl': '640px', // 160 * spacingUnit - 'unit-0': '0px', // 0 * spacingUnit - 'unit-1': '4px', // 1 * spacingUnit - 'unit-2': '8px', // 2 * spacingUnit - 'unit-3': '12px', // 3 * spacingUnit - 'unit-3_5': '14px' // 3.5 * spacingUnit - 'unit-4': '16px', // 4 * spacingUnit - 'unit-5': '20px', // 5 * spacingUnit - 'unit-6': '24px', // 6 * spacingUnit - 'unit-7': '28px', // 7 * spacingUnit - 'unit-8': '32px', // 8 * spacingUnit - 'unit-9': '36px', // 9 * spacingUnit - 'unit-10': '40px', // 10 * spacingUnit - 'unit-11': '44px', // 11 * spacingUnit - 'unit-12': '48px', // 12 * spacingUnit - 'unit-13': '52px', // 13 * spacingUnit - 'unit-14': '56px', // 14 * spacingUnit - 'unit-15': '60px', // 15 * spacingUnit - 'unit-16': '64px', // 16 * spacingUnit - 'unit-17': '68px', // 17 * spacingUnit - 'unit-18': '72px', // 18 * spacingUnit - 'unit-20': '80px', // 20 * spacingUnit - 'unit-24': '96px', // 24 * spacingUnit - 'unit-28': '112px', // 28 * spacingUnit - 'unit-32': '128px', // 32 * spacingUnit - 'unit-36': '144px', // 36 * spacingUnit - 'unit-40': '160px', // 40 * spacingUnit - 'unit-44': '176px', // 44 * spacingUnit - 'unit-48': '192px', // 48 * spacingUnit - 'unit-52': '208px', // 52 * spacingUnit - 'unit-56': '224px', // 56 * spacingUnit - 'unit-60': '240px', // 60 * spacingUnit - 'unit-64': '256px', // 64 * spacingUnit - 'unit-72': '288px', // 72 * spacingUnit - 'unit-80': '320px', // 80 * spacingUnit - 'unit-96': '384px', // 96 * spacingUnit -} -``` - -### Using Units - -NextUI units behave like [Tailwind CSS spacing](https://tailwindcss.com/docs/customizing-spacing#default-spacing-scale) units. You can use them in the `margin`, `padding`, -`width`, `height`, `min-width`, `min-height`, `gap`, `top`, `right`, `bottom`, and `left` properties. - -```jsx {5} -import {Button} from "@nextui-org/react"; - -export const MyButton = () => { - return ( - - ); -}; -``` - -> **Remember**: Any changes to the `spacingUnit` token will automatically update the units. - ### CSS Variables NextUI creates CSS variables using the format `--prefix-prop-name-scale` for each layout token. By @@ -209,14 +130,13 @@ Then you can use the CSS variables in your CSS files. ```css /* With default prefix */ .my-button { - padding: var(--nextui-spacing-unit-4); font-size: var(--nextui-font-size-small); line-height: var(--nextui-line-height-small); border-radius: var(--nextui-radius-medium); } + /* With custom prefix */ .my-component { - padding: var(--myapp-spacing-unit-4); font-size: var(--myapp-font-size-small); line-height: var(--myapp-line-height-small); border-radius: var(--myapp-radius-medium); @@ -227,9 +147,8 @@ Then you can use the CSS variables in your CSS files. | Attribute | Type | Description | | --------------- | ------------------------------- | ------------------------------------------------------------------------------------------- | -| spacingUnit | number | Base unit token that defines a consistent spacing scale across the components. | -| disabledOpacity | string, number | A number between 0 and 1 that is applied as opacity-[value] when the component is disabled. | | hoverOpacity | string, number | A number between 0 and 1 that is applied as opacity-[value] when the component is hovered. | +| disabledOpacity | string, number | A number between 0 and 1 that is applied as opacity-[value] when the component is disabled. | | dividerWeight | string | The default height applied to the divider component. We recommend to use `px` units. | | fontSize | [FontThemeUnit](#fontthemeunit) | The default font size applied across the components. | | lineHeight | [FontThemeUnit](#fontthemeunit) | The default line height applied across the components. | @@ -256,4 +175,4 @@ export type FontThemeUnit = { large?: string; tiny?: string; }; -``` +``` \ No newline at end of file diff --git a/apps/docs/content/docs/customization/theme.mdx b/apps/docs/content/docs/customization/theme.mdx index 4b8a0c0b20..efc8ad6284 100644 --- a/apps/docs/content/docs/customization/theme.mdx +++ b/apps/docs/content/docs/customization/theme.mdx @@ -210,11 +210,6 @@ type FontThemeUnit = { }; interface LayoutTheme { - /** - * Base unit token that defines a consistent spacing scale across - * the components. - */ - spacingUnit?: number; /** * The default font size applied across the components. */ diff --git a/apps/docs/content/docs/frameworks/astro.mdx b/apps/docs/content/docs/frameworks/astro.mdx index b78a47fb54..ac979c821e 100644 --- a/apps/docs/content/docs/frameworks/astro.mdx +++ b/apps/docs/content/docs/frameworks/astro.mdx @@ -8,7 +8,7 @@ description: How to use NextUI with Astro Requirements: - [React 18](https://reactjs.org/) or later -- [Tailwind CSS 3](https://tailwindcss.com/docs/guides/astro) or later +- [Tailwind CSS 3.4](https://tailwindcss.com/docs/guides/astro) or later - [Framer Motion 4](https://www.framer.com/motion/) or later ------ diff --git a/apps/docs/content/docs/frameworks/nextjs.mdx b/apps/docs/content/docs/frameworks/nextjs.mdx index f7867846e6..0590f42879 100644 --- a/apps/docs/content/docs/frameworks/nextjs.mdx +++ b/apps/docs/content/docs/frameworks/nextjs.mdx @@ -10,7 +10,7 @@ Requirements: - [Next.js 12](https://nextjs.org/) or later - [React 18](https://reactjs.org/) or later -- [Tailwind CSS 3](https://tailwindcss.com/docs/guides/nextjs) or later +- [Tailwind CSS 3.4](https://tailwindcss.com/docs/guides/nextjs) or later - [Framer Motion 4](https://www.framer.com/motion/) or later ------ @@ -25,6 +25,20 @@ Next.js 13 introduces a new `app/` directory structure. By default it uses Serve As NextUI components use React hooks, we added the `use client;` at build time, so you can import them directly in your React Server Components (RSC). +## NextUI CLI (recommended) + +If you are starting a new project, you can use the NextUI CLI to create a new project with NextUI pre-configured: + +```bash +npm install -g nextui-cli +``` + + + +```bash +nextui init -t app +``` + ### create-next-app If you are starting a new project, you can run one of the following commands to create a Next.js project pre-configured with NextUI: @@ -37,6 +51,88 @@ If you are starting a new project, you can run one of the following commands to }} /> + +## Automatic Installation + +You can add individual components using the CLI. For example, to add a button component: + +```codeBlock bash +nextui add button +``` + +This command adds the Button component to your project and manages all related dependencies. + +You can also add multiple components at once: + +```codeBlock bash +nextui add button input +``` + +Or you can add the main library `@nextui-org/react` by running the following command: + +```codeBlock bash +nextui add --all +``` + +If you leave out the component name, the CLI will prompt you to select the components you want to add. + +```codeBlock bash +? Which components would you like to add? › - Space to select. Return to submit +Instructions: + ↑/↓: Highlight option + ←/→/[space]: Toggle selection + [a,b,c]/delete: Filter choices + enter/return: Complete answer + +Filtered results for: Enter something to filter + +◯ accordion +◯ autocomplete +◯ avatar +◯ badge +◯ breadcrumbs +◉ button +◯ card +◯ checkbox +◯ chip +◯ code +``` + +You still need to add the provider to your app manually (we are working on automating this step). + +```jsx +// app/providers.tsx + +import {NextUIProvider} from '@nextui-org/react' + +export function Providers({children}: { children: React.ReactNode }) { + return ( + + {children} + + ) +} +``` + +```jsx +// app/layout.tsx + +import {Providers} from "./providers"; + +export default function RootLayout({children}: { children: React.ReactNode }) { + return ( + + + + {children} + + + + ); +} +``` + + ### Manual Installation @@ -153,13 +249,26 @@ public-hoist-pattern[]=*@nextui-org/* After modifying the `.npmrc` file, you need to run `pnpm install` again to ensure that the dependencies are installed correctly. - ## Pages Directory Setup +### NextUI CLI (recommended) + +If you are starting a new project, you can use the NextUI CLI to create a new project with NextUI pre-configured: + +```bash +npm install -g nextui-cli +``` + + + +```bash +nextui init -t pages +``` + If you are using the `/pages` Next.js project structure, you need to follow the steps below. ### create-next-app @@ -174,6 +283,86 @@ If you are starting a new project, you can run one of the following commands to }} /> +### Automatic Installation + +You can add individual components using the CLI. For example, to add a button component: + +```codeBlock bash +nextui add button +``` + +This command adds the Button component to your project and manages all related dependencies. + +You can also add multiple components at once: + +```codeBlock bash +nextui add button input +``` + +Or you can add the main library `@nextui-org/react` by running the following command: + +```codeBlock bash +nextui add --all +``` + +If you leave out the component name, the CLI will prompt you to select the components you want to add. + +```codeBlock bash +? Which components would you like to add? › - Space to select. Return to submit +Instructions: + ↑/↓: Highlight option + ←/→/[space]: Toggle selection + [a,b,c]/delete: Filter choices + enter/return: Complete answer + +Filtered results for: Enter something to filter + +◯ accordion +◯ autocomplete +◯ avatar +◯ badge +◯ breadcrumbs +◉ button +◯ card +◯ checkbox +◯ chip +◯ code +``` + +You still need to add the provider to your app manually (we are working on automating this step). + +```jsx +// app/providers.tsx + +import {NextUIProvider} from '@nextui-org/react' + +export function Providers({children}: { children: React.ReactNode }) { + return ( + + {children} + + ) +} +``` + +```jsx +// app/layout.tsx + +import {Providers} from "./providers"; + +export default function RootLayout({children}: { children: React.ReactNode }) { + return ( + + + + {children} + + + + ); +} +``` + ### Manual Installation diff --git a/apps/docs/content/docs/frameworks/remix.mdx b/apps/docs/content/docs/frameworks/remix.mdx index 776d112b85..3462f11ca9 100644 --- a/apps/docs/content/docs/frameworks/remix.mdx +++ b/apps/docs/content/docs/frameworks/remix.mdx @@ -8,7 +8,7 @@ description: How to use NextUI with Remix Requirements: - [React 18](https://reactjs.org/) or later -- [Tailwind CSS 3](https://tailwindcss.com/docs/guides/remix) or later +- [Tailwind CSS 3.4](https://tailwindcss.com/docs/guides/remix) or later - [Framer Motion 4](https://www.framer.com/motion/) or later ------ diff --git a/apps/docs/content/docs/frameworks/vite.mdx b/apps/docs/content/docs/frameworks/vite.mdx index e937914efb..718828a346 100644 --- a/apps/docs/content/docs/frameworks/vite.mdx +++ b/apps/docs/content/docs/frameworks/vite.mdx @@ -9,7 +9,7 @@ Requirements: - [Vite 2](https://vitejs.dev/) or later - [React 18](https://reactjs.org/) or later -- [Tailwind CSS 3](https://tailwindcss.com/docs/guides/vite#react) or later +- [Tailwind CSS 3.4](https://tailwindcss.com/docs/guides/vite#react) or later - [Framer Motion 4](https://www.framer.com/motion/) or later ------ diff --git a/apps/docs/content/docs/guide/cli.mdx b/apps/docs/content/docs/guide/cli.mdx new file mode 100644 index 0000000000..cba3fd1f54 --- /dev/null +++ b/apps/docs/content/docs/guide/cli.mdx @@ -0,0 +1,279 @@ +--- +title: CLI +description: Use the CLI to manage and enhance your NextUI project components. +--- + +# CLI + +The CLI offers a comprehensive suite of commands to initialize, manage, and improve your NextUI projects. It enables you to `add`, `remove`, or `upgrade` individual components, assess the health of your project, and more. + +## Installation + +Requirements: + +- [Node.js version 18.17.x or later](https://nodejs.org/en/) + + + +### Global Installation + +To install the `CLI` globally, execute one of the following commands in your terminal: + + + +### Without Installation + +Alternatively, you can use the `CLI` without a global installation by employing `npx`: + +```bash +npx nextui-cli@latest +``` + + + +## Quick Start + +Once the `CLI` is installed, run the following command to display available commands: + +```codeBlock bash +nextui +``` + +This will produce the following help output: + +```codeBlock bash +NextUI CLI + +A command line tool for seamless integration with NextUI + +Usage: nextui [command] + +Options: + -v, --version Show the version number + -h, --help Display help for commands + +Commands: + init [options] [projectName] Start a new NextUI project + add [options] [components...] Add NextUI components to your project + upgrade [options] [components...] Update NextUI components to the latest versions + remove [options] [components...] Remove NextUI components from your project + list [options] Show details of installed components + env [options] Display debug information about the local environment + doctor [options] Diagnose problems in your project + help [command] Get help on a specific command +``` + +## init + +Initialize a new NextUI project using the `init` command. This sets up your project with the necessary configurations. + +```codeBlock bash +nextui init [my-nextui-app-name] +``` + + + +You will be prompted to configure your project: + +```codeBlock bash +? Select a template › - Use arrow-keys. Return to submit. +❯ App + A Next.js 13 with app directory template pre-configured with NextUI (v2) and Tailwind CSS. + Pages + A Next.js 13 with pages directory template pre-configured with NextUI (v2) and Tailwind CSS. +``` + +## add + +Add components to your NextUI project with the add command. This command manages component dependencies and updates your project configurations. + +Without specifying a specific component: + +```codeBlock bash +nextui add +``` + + + +You will be prompted to select the components you wish to add: + +```codeBlock bash +? Which components would you like to add? › - Space to select. Return to submit +Instructions: + ↑/↓: Highlight option + ←/→/[space]: Toggle selection + [a,b,c]/delete: Filter choices + enter/return: Complete answer + +Filtered results for: Enter something to filter + +◯ accordion +◯ autocomplete +◯ avatar +◯ badge +◯ breadcrumbs +◉ button +◯ card +◯ checkbox +◯ chip +◯ code +``` + +To add a specific component: + +```codeBlock bash +nextui add button +``` + +You will see an output confirming the addition of the component: + +```codeBlock bash +Adding the required dependencies: @nextui-org/button + +Tailwind CSS settings have been updated in: /project-path/tailwind.config.js + +✅ Components added successfully +``` + +## upgrade + +Upgrade specific NextUI components within your project using the upgrade command to ensure they are up to date. + +```codeBlock bash +nextui upgrade button +``` + +You will be asked to confirm the upgrade: + +```codeBlock bash + +╭───────────────────────────────────────────────────────────╮ +│ @nextui-org/button 2.0.24 -> 2.0.27 │ +╰───────────────────────────────────────────────────────────╯ + +? Would you like to proceed with the upgrade? › - Use arrow-keys. Return to submit. +❯ Yes + No +``` + +Upon confirmation, the command will execute and provide an output similar to: + +```codeBlock bash +✅ Upgrade complete. All components are up to date. +``` + +## remove + +Remove components from your NextUI project with the remove command. This helps in managing the project's +component structure and dependencies. + +```codeBlock bash +nextui remove button +``` + +A confirmation prompt will be displayed: + +```codeBlock bash +❗️ Components slated for removal: +╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ +│ Package │ Version │ Status │ Docs │ +│──────────────────────────────────────────────────────────────────────────────────────────────────────────────│ +│ @nextui-org/button │ 2.0.27 🚀latest │ stable │ https://nextui.org/docs/components/button │ +╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ + +? Confirm removal of these components: › - Use arrow-keys. Return to submit. +❯ Yes + No +``` + +Following confirmation, the output will indicate successful removal: + +```codeBlock bash +✅ Successfully removed the specified NextUI components: @nextui-org/button +``` + +## list + +List all installed NextUI components in your project with the list command. This provides a clear overview of what is currently included in your project. + +```codeBlock bash +nextui list +``` + +The output will detail each component: + +```codeBlock bash +Current installed components: + +╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ +│ Package │ Version │ Status │ Docs │ +│───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────│ +│ @nextui-org/autocomplete │ 2.0.10 🚀latest │ newPost │ https://nextui.org/docs/components/autocomplete │ +│ @nextui-org/badge │ 2.0.24 🚀latest │ stable │ https://nextui.org/docs/components/badge │ +│ @nextui-org/button │ 2.0.27 🚀latest │ stable │ https://nextui.org/docs/components/button │ +│ @nextui-org/chip │ 2.0.25 🚀latest │ stable │ https://nextui.org/docs/components/chip │ +╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ +``` + +## doctor + +Diagnose and resolve issues within your project using the doctor command. This ensures your project's health and proper configuration. + +```codeBlock bash +nextui doctor +``` + +Depending on your project's status, you might see: + +```codeBlock bash +✅ Your project has no detected issues. +``` + +Or, if issues are detected: + +```codeBlock bash +❌ Your project has 1 issue that requires attention +``` + +## env + +Display detailed information about your project's environment settings using the env command. This includes system, dependencies, and configuration details. + +```codeBlock bash +nextui env +``` + +The output will reflect your current environment setup: + +```codeBlock bash +Current installed components: + +╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ +│ Package │ Version │ Status │ Docs │ +│───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────│ +│ @nextui-org/autocomplete │ 2.0.10 🚀latest │ newPost │ https://nextui.org/docs/components/autocomplete │ +│ @nextui-org/badge │ 2.0.24 🚀latest │ stable │ https://nextui.org/docs/components/badge │ +│ @nextui-org/button │ 2.0.27 🚀latest │ stable │ https://nextui.org/docs/components/button │ +│ @nextui-org/chip │ 2.0.25 🚀latest │ stable │ https://nextui.org/docs/components/chip │ +╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ + +Environment Info: + System: + OS: darwin + CPU: arm64 + Binaries: + Node: v18.18.2 +``` + +## API Reference + +Explore the complete CLI commands and features in the [API References](/docs/api-references/cli-api). + +For updates and source code, visit the [GitHub Repository](https://github.com/nextui-org/nextui-cli). diff --git a/apps/docs/content/docs/guide/installation.mdx b/apps/docs/content/docs/guide/installation.mdx index 165cec9e2c..763f21b5c0 100644 --- a/apps/docs/content/docs/guide/installation.mdx +++ b/apps/docs/content/docs/guide/installation.mdx @@ -8,16 +8,86 @@ description: Get started with NextUI in the official documentation, and learn mo Requirements: - [React 18](https://reactjs.org/) or later -- [Tailwind CSS 3](https://tailwindcss.com/) or later +- [Tailwind CSS 3.4](https://tailwindcss.com/) or later - [Framer Motion 4](https://www.framer.com/motion/) or later --- -To use NextUI in your project, you need to follow the following steps: +## Automatic Installation -## Global Installation +Using the CLI is now the easiest way to start a NextUI project. You can initialize your project and add components directly via the CLI: + +```codeBlock bash +npm install -g nextui-cli +``` + + + +```codeBlock bash +nextui init my-nextui-app +``` + +You will be prompted to configure your project: + +```codeBlock bash +? Select a template › - Use arrow-keys. Return to submit. +❯ App + A Next.js 13 with app directory template pre-configured with NextUI (v2) and Tailwind CSS. + Pages + A Next.js 13 with pages directory template pre-configured with NextUI (v2) and Tailwind CSS. +``` + +Once your NextUI project is initialized, you can add individual components using the CLI. For example, to add a button component: + +```codeBlock bash +nextui add button +``` + +This command adds the Button component to your project and manages all related dependencies. + +You can also add multiple components at once: + +```codeBlock bash +nextui add button input +``` + +Or you can add the main library `@nextui-org/react` by running the following command: + +```codeBlock bash +nextui add --all +``` + +If you leave out the component name, the CLI will prompt you to select the components you want to add. + +```codeBlock bash +? Which components would you like to add? › - Space to select. Return to submit +Instructions: + ↑/↓: Highlight option + ←/→/[space]: Toggle selection + [a,b,c]/delete: Filter choices + enter/return: Complete answer + +Filtered results for: Enter something to filter + +◯ accordion +◯ autocomplete +◯ avatar +◯ badge +◯ breadcrumbs +◉ button +◯ card +◯ checkbox +◯ chip +◯ code +``` + +## Manual Installation + +If you prefer not to use the CLI, follow these steps to manually set up NextUI in your project: + +### Global Installation The easiest way to get started with NextUI is to use the global installation. Which means that all the components are imported from a single package. @@ -26,20 +96,20 @@ Follow the steps below to install all NextUI components: -### Install Packages +#### Install Packages To install NextUI, run one of the following commands in your terminal: -### Tailwind CSS Setup +#### Tailwind CSS Setup NextUI is built on top of Tailwind CSS, so you need to install Tailwind CSS first. You can follow the official [installation guide](https://tailwindcss.com/docs/installation) to install Tailwind CSS. Then you need to add @@ -63,7 +133,7 @@ module.exports = { }; ``` -### Provider Setup +#### Provider Setup It is essential to add the `NextUIProvider` at the `root` of your application. @@ -83,7 +153,7 @@ function App() { } ``` -### Setup pnpm (optional) +#### Setup pnpm (optional) If you are using pnpm, you need to add the following code to your `.npmrc` file: @@ -95,7 +165,7 @@ After modifying the `.npmrc` file, you need to run `pnpm install` again to ensur -## Individual Installation +### Individual Installation NextUI is also available as individual packages. You can install each package separately. This is useful if you want to reduce the size of your CSS bundle as it will only include styles for the components @@ -107,7 +177,7 @@ Follow the steps below to install each package separately: -### Install Core Packages +#### Install Core Packages Although you can install each package separately, you need to install the core packages first to ensure that all components work correctly. @@ -116,14 +186,14 @@ Run one of the following commands in your terminal to install the core packages: {" "} +/> -### Install Component +#### Install Component Now, let's install the component you want to use. For example, if you want to use the [Button](/docs/components/button) component, you need to run one of the following commands @@ -131,17 +201,17 @@ in your terminal: -### Tailwind CSS Setup +#### Tailwind CSS Setup TailwindCSS setup changes a bit when you use individual packages. You only need to add the -styles of the components your using to your `tailwind.config.js` file. For example, for the +styles of the components you're using to your `tailwind.config.js` file. For example, for the [Button](/docs/components/button) component, you need to add the following code to your `tailwind.config.js` file: @@ -165,7 +235,7 @@ module.exports = { }; ``` -### Provider Setup +#### Provider Setup It is essential to add the `NextUIProvider` at the `root` of your application. @@ -185,7 +255,7 @@ function App() { } ``` -### Use the Component +#### Use the Component Now, you can use the component you installed in your application: @@ -201,7 +271,7 @@ function App() { ``` -### Setup pnpm (optional) +#### Setup pnpm (optional) If you are using pnpm, you need to add the following code to your `.npmrc` file: diff --git a/apps/docs/content/docs/guide/introduction.mdx b/apps/docs/content/docs/guide/introduction.mdx index c36ff96bb0..5e92213bc1 100644 --- a/apps/docs/content/docs/guide/introduction.mdx +++ b/apps/docs/content/docs/guide/introduction.mdx @@ -95,7 +95,7 @@ NextUI's primary goal is to streamline the development process, offering a beaut can still use the NextUI components styling part with other frameworks or libraries. -### Why NextUI uses Framer Motion? +### Why does NextUI use Framer Motion?
We use Framer Motion to animate some components due to diff --git a/apps/docs/content/docs/guide/upgrade-to-v2.mdx b/apps/docs/content/docs/guide/upgrade-to-v2.mdx index d9a39e2d02..199fbaa84a 100644 --- a/apps/docs/content/docs/guide/upgrade-to-v2.mdx +++ b/apps/docs/content/docs/guide/upgrade-to-v2.mdx @@ -9,7 +9,7 @@ description: Upgrade from NextUI v1 to v2 Requirements: - [React 18](https://reactjs.org/) or later -- [Tailwind CSS 3](https://tailwindcss.com/) or later +- [Tailwind CSS 3.4](https://tailwindcss.com/) or later - [Framer Motion 4](https://www.framer.com/motion/) or later ----- diff --git a/apps/docs/contentlayer.config.js b/apps/docs/contentlayer.config.js index 3b19f312a8..59331a3d6a 100644 --- a/apps/docs/contentlayer.config.js +++ b/apps/docs/contentlayer.config.js @@ -2,6 +2,7 @@ import {defineDocumentType, defineNestedType, makeSource} from "contentlayer/sou import remarkGfm from "remark-gfm"; import rehypeSlug from "rehype-slug"; import {visit} from "unist-util-visit"; +import pluginCodeBlock from "./plugins/codeBlock"; /** @type {import('contentlayer/source-files').ComputedFields} */ const computedFields = { @@ -48,6 +49,7 @@ export const BlogPost = defineDocumentType(() => ({ title: {type: "string", required: true}, description: {type: "string", required: true}, date: {type: "date", required: true}, + draft: {type: "boolean", required: false}, tags: { type: 'list', of: { type: 'string' } }, author: {type: "nested",of: AuthorProperties, required: false}, image: {type: "string", required: false}, @@ -80,7 +82,7 @@ export default makeSource({ contentDirPath: "./content", documentTypes: [Doc, BlogPost], mdx: { - remarkPlugins: [remarkGfm], + remarkPlugins: [remarkGfm, pluginCodeBlock], rehypePlugins: [ rehypeSlug, () => (tree) => { diff --git a/apps/docs/package.json b/apps/docs/package.json index 992bac1691..d4ab2d7f03 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -18,6 +18,7 @@ "@codesandbox/sandpack-react": "^2.6.4", "@iconify/icons-solar": "^1.2.3", "@iconify/react": "^4.1.1", + "@internationalized/date": "^3.5.2", "@mapbox/rehype-prism": "^0.6.0", "@nextui-org/aria-utils": "workspace:*", "@nextui-org/badge": "workspace:*", @@ -54,7 +55,7 @@ "color2k": "^2.0.2", "contentlayer": "^0.3.4", "date-fns": "^2.30.0", - "framer-motion": "^10.16.4", + "framer-motion": "^11.0.22", "github-slugger": "^2.0.0", "gray-matter": "^4.0.3", "hast-util-to-html": "7.1.2", @@ -90,7 +91,7 @@ "sharp": "^0.32.1", "shelljs": "^0.8.4", "swr": "^2.2.1", - "tailwind-variants": "^0.1.18", + "tailwind-variants": "^0.1.20", "unified": "^9.2.2", "unist-util-visit": "^4.1.2", "usehooks-ts": "^2.9.1", @@ -100,7 +101,7 @@ "@docusaurus/utils": "2.0.0-beta.3", "@next/bundle-analyzer": "^13.4.6", "@next/env": "^13.4.12", - "@react-types/shared": "^3.19.0", + "@react-types/shared": "^3.22.0", "@tailwindcss/typography": "^0.5.9", "@types/canvas-confetti": "^1.4.2", "@types/lodash": "^4.14.194", diff --git a/apps/docs/plugins/codeBlock.ts b/apps/docs/plugins/codeBlock.ts new file mode 100644 index 0000000000..4b662cc229 --- /dev/null +++ b/apps/docs/plugins/codeBlock.ts @@ -0,0 +1,138 @@ +import {visit} from "unist-util-visit"; + +function remarkCodePlugin() { + return (tree: any) => { + visit(tree, "code", (node) => { + if (node.lang === "codeBlock") { + const meta = node.meta || ""; + const value = node.value || ""; + + if (!meta || !value) { + return; + } + + // Use Snippet to render code block + Object.assign(node, { + type: "mdxJsxFlowElement", + name: "Snippet", + attributes: [ + { + type: "mdxJsxAttribute", + name: "disableTooltip", + value: true, + }, + { + type: "mdxJsxAttribute", + name: "fullWidth", + value: true, + }, + { + type: "mdxJsxAttribute", + name: "hideSymbol", + value: true, + }, + { + type: "mdxJsxAttribute", + name: "classNames", + value: { + type: "mdxJsxAttributeValueExpression", + value: + "{base: 'bg-code-background text-code-foreground' , pre: 'font-light text-base', copyButton: 'text-lg text-zinc-500 mr-2'}", + data: { + estree: { + type: "Program", + body: [ + { + type: "ExpressionStatement", + expression: { + type: "ObjectExpression", + properties: [ + { + type: "Property", + method: false, + shorthand: false, + computed: false, + key: { + type: "Identifier", + name: "base", + }, + value: { + type: "Literal", + value: "bg-code-background text-code-foreground", + raw: "'bg-code-background text-code-foreground'", + }, + kind: "init", + }, + { + type: "Property", + method: false, + shorthand: false, + computed: false, + key: { + type: "Identifier", + name: "pre", + }, + value: { + type: "Literal", + value: "font-light text-base", + raw: "'font-light text-base'", + }, + kind: "init", + }, + { + type: "Property", + method: false, + shorthand: false, + computed: false, + key: { + type: "Identifier", + name: "copyButton", + }, + value: { + type: "Literal", + value: "text-lg text-zinc-500 mr-2", + raw: "'text-lg text-zinc-500 mr-2'", + }, + kind: "init", + }, + ], + }, + }, + ], + sourceType: "module", + comments: [], + }, + }, + }, + }, + ], + children: [ + { + type: "mdxJsxFlowElement", + name: "Codeblock", + attributes: [ + { + type: "mdxJsxAttribute", + name: "removeIndent", + value: true, + }, + { + type: "mdxJsxAttribute", + name: "language", + value: meta, + }, + { + type: "mdxJsxAttribute", + name: "codeString", + value: value, + }, + ], + }, + ], + }); + } + }); + }; +} + +export default remarkCodePlugin; diff --git a/apps/docs/public/blog/v2.3.0.jpg b/apps/docs/public/blog/v2.3.0.jpg new file mode 100644 index 0000000000..de7ac42259 Binary files /dev/null and b/apps/docs/public/blog/v2.3.0.jpg differ diff --git a/apps/docs/public/blog/v2.3.0_2x.jpg b/apps/docs/public/blog/v2.3.0_2x.jpg new file mode 100644 index 0000000000..96f9d306e5 Binary files /dev/null and b/apps/docs/public/blog/v2.3.0_2x.jpg differ diff --git a/apps/docs/tailwind.config.js b/apps/docs/tailwind.config.js index 452cd774ff..d3a3b8df21 100644 --- a/apps/docs/tailwind.config.js +++ b/apps/docs/tailwind.config.js @@ -147,7 +147,7 @@ module.exports = { fontWeight: "inherit", }, strong: { - color: theme("colors.cyan.600"), + color: "hsl(var(--nextui-strong))", fontWeight: theme("fontWeight.semibold"), }, "a strong": { @@ -210,6 +210,12 @@ module.exports = { fontWeight: theme("fontWeight.normal"), fontStyle: "font-normal", }, + "code::before": { + content: "", + }, + "code::after": { + content: "", + }, "blockquote p:first-of-type::before": { content: "", }, @@ -222,7 +228,7 @@ module.exports = { css: { color: "hsl(var(--nextui-default-700))", strong: { - color: theme("colors.pink.500"), + color: "hsl(var(--nextui-cyan-500))", }, }, }, @@ -327,11 +333,13 @@ module.exports = { light: { colors: { "code-background": "#363449", + strong: "#ff4ecd", "code-mdx": "#ff4ecd", }, }, dark: { colors: { + strong: "#06B7DB", "code-background": "#0D0B0B", "code-mdx": "#06B7DB", }, diff --git a/package.json b/package.json index c314ec0e00..3291758976 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "@commitlint/config-conventional": "^17.2.0", "@react-bootstrap/babel-preset": "^2.1.0", "@react-types/link": "^3.4.4", - "@react-types/shared": "^3.19.0", + "@react-types/shared": "^3.22.0", "@swc-node/jest": "^1.5.2", "@swc/core": "^1.3.35", "@swc/jest": "^0.2.24", diff --git a/packages/components/accordion/CHANGELOG.md b/packages/components/accordion/CHANGELOG.md index ace82ba4cd..33f229f818 100644 --- a/packages/components/accordion/CHANGELOG.md +++ b/packages/components/accordion/CHANGELOG.md @@ -1,5 +1,55 @@ # @nextui-org/accordion +## 2.0.31 + +### Patch Changes + +- Updated dependencies [[`eccc2f2f3`](https://github.com/nextui-org/nextui/commit/eccc2f2f3d856eefb2cc7c07b94e1c4cefd4d7d0)]: + - @nextui-org/aria-utils@2.0.18 + - @nextui-org/framer-utils@2.0.18 + - @nextui-org/react-utils@2.0.13 + - @nextui-org/divider@2.0.27 + +## 2.0.30 + +### Patch Changes + +- Updated dependencies []: + - @nextui-org/aria-utils@2.0.17 + - @nextui-org/framer-utils@2.0.17 + - @nextui-org/divider@2.0.27 + - @nextui-org/react-utils@2.0.12 + +## 2.0.29 + +### Patch Changes + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - v2.3.0 + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - Fixed the issue where only two keyframes were supported with spring and inertia animations. + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - - Calendar component added + + - objectToDeps function applied all across components + - `useMeasure` hook added + - `useIntersectionObserver` hook added + - `framer-transitions` renamed to `framer-utils` + - `ResizablePanel` component added to `framer-utils` + - `test-utils` updated + +- [#2219](https://github.com/nextui-org/nextui/pull/2219) [`2c3be59df`](https://github.com/nextui-org/nextui/commit/2c3be59dfb22a0059b814c63116606d5ec7345a0) Thanks [@ryo-manba](https://github.com/ryo-manba)! - fixed remove dividers from hidden accordion items (#2210) + +- [#2464](https://github.com/nextui-org/nextui/pull/2464) [`2894aecca`](https://github.com/nextui-org/nextui/commit/2894aecca1a2ef0dfb3066b9b8df24ce48c99dae) Thanks [@mezotv](https://github.com/mezotv)! - Changes the motion important to the more lightweight m component in framer motion to only load the required features. + +- Updated dependencies [[`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14), [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14)]: + - @nextui-org/divider@2.0.26 + - @nextui-org/use-aria-accordion@2.0.3 + - @nextui-org/aria-utils@2.0.16 + - @nextui-org/framer-utils@2.0.16 + - @nextui-org/react-utils@2.0.11 + - @nextui-org/shared-icons@2.0.7 + - @nextui-org/shared-utils@2.0.5 + ## 2.0.28 ### Patch Changes @@ -7,7 +57,7 @@ - Updated dependencies []: - @nextui-org/divider@2.0.25 - @nextui-org/aria-utils@2.0.15 - - @nextui-org/framer-transitions@2.0.15 + - @nextui-org/framer-utils@2.0.15 ## 2.0.27 @@ -17,7 +67,7 @@ - @nextui-org/shared-icons@2.0.6 - @nextui-org/divider@2.0.24 - @nextui-org/aria-utils@2.0.14 - - @nextui-org/framer-transitions@2.0.14 + - @nextui-org/framer-utils@2.0.14 ## 2.0.26 @@ -28,7 +78,7 @@ - Updated dependencies [[`44ed1056e`](https://github.com/nextui-org/nextui/commit/44ed1056e717c56633f60cf289f78e9c7b83b648)]: - @nextui-org/divider@2.0.23 - @nextui-org/aria-utils@2.0.13 - - @nextui-org/framer-transitions@2.0.13 + - @nextui-org/framer-utils@2.0.13 ## 2.0.25 @@ -40,7 +90,7 @@ - @nextui-org/divider@2.0.22 - @nextui-org/system@2.0.12 - @nextui-org/aria-utils@2.0.12 - - @nextui-org/framer-transitions@2.0.12 + - @nextui-org/framer-utils@2.0.12 ## 2.0.24 @@ -55,7 +105,7 @@ - @nextui-org/use-aria-accordion@2.0.2 - @nextui-org/use-aria-press@2.0.1 - @nextui-org/aria-utils@2.0.11 - - @nextui-org/framer-transitions@2.0.11 + - @nextui-org/framer-utils@2.0.11 - @nextui-org/react-utils@2.0.10 - @nextui-org/shared-icons@2.0.5 - @nextui-org/shared-utils@2.0.4 @@ -75,7 +125,7 @@ - @nextui-org/system@2.0.10 - @nextui-org/react-utils@2.0.9 - @nextui-org/aria-utils@2.0.10 - - @nextui-org/framer-transitions@2.0.10 + - @nextui-org/framer-utils@2.0.10 ## 2.0.22 @@ -89,7 +139,7 @@ - @nextui-org/theme@2.1.8 - @nextui-org/use-aria-accordion-item@2.0.5 - @nextui-org/aria-utils@2.0.9 - - @nextui-org/framer-transitions@2.0.9 + - @nextui-org/framer-utils@2.0.9 - @nextui-org/react-utils@2.0.8 - @nextui-org/shared-icons@2.0.4 - @nextui-org/shared-utils@2.0.3 @@ -106,7 +156,7 @@ - @nextui-org/aria-utils@2.0.8 - @nextui-org/divider@2.0.18 - @nextui-org/system@2.0.8 - - @nextui-org/framer-transitions@2.0.8 + - @nextui-org/framer-utils@2.0.8 ## 2.0.20 @@ -125,7 +175,7 @@ - @nextui-org/divider@2.0.16 - @nextui-org/system@2.0.7 - @nextui-org/aria-utils@2.0.7 - - @nextui-org/framer-transitions@2.0.7 + - @nextui-org/framer-utils@2.0.7 ## 2.0.18 @@ -136,7 +186,7 @@ - @nextui-org/system@2.0.6 - @nextui-org/divider@2.0.15 - @nextui-org/aria-utils@2.0.6 - - @nextui-org/framer-transitions@2.0.6 + - @nextui-org/framer-utils@2.0.6 ## 2.0.17 @@ -228,7 +278,7 @@ - Updated dependencies [[`a30cec48`](https://github.com/nextui-org/nextui/commit/a30cec4810988fb1962f3a61e0fc0362de08b171)]: - @nextui-org/use-aria-accordion-item@2.0.3 - - @nextui-org/framer-transitions@2.0.5 + - @nextui-org/framer-utils@2.0.5 - @nextui-org/aria-utils@2.0.5 - @nextui-org/divider@2.0.7 - @nextui-org/system@2.0.5 @@ -240,7 +290,7 @@ - Updated dependencies [[`710395f3`](https://github.com/nextui-org/nextui/commit/710395f3a2ca44238332237a49e948c933abe63d)]: - @nextui-org/system@2.0.4 - @nextui-org/aria-utils@2.0.4 - - @nextui-org/framer-transitions@2.0.4 + - @nextui-org/framer-utils@2.0.4 ## 2.0.6 @@ -290,7 +340,7 @@ - @nextui-org/theme@2.0.3 - @nextui-org/use-aria-accordion-item@2.0.2 - @nextui-org/aria-utils@2.0.3 - - @nextui-org/framer-transitions@2.0.3 + - @nextui-org/framer-utils@2.0.3 - @nextui-org/shared-icons@2.0.2 - @nextui-org/shared-utils@2.0.2 @@ -303,7 +353,7 @@ - @nextui-org/divider@2.0.2 - @nextui-org/system@2.0.2 - @nextui-org/aria-utils@2.0.2 - - @nextui-org/framer-transitions@2.0.2 + - @nextui-org/framer-utils@2.0.2 ## 2.0.1 @@ -315,7 +365,7 @@ - Updated dependencies [[`e940ec06`](https://github.com/nextui-org/nextui/commit/e940ec06ac5e46340d5956fb7c455a6ab3de3140), [`e940ec06`](https://github.com/nextui-org/nextui/commit/e940ec06ac5e46340d5956fb7c455a6ab3de3140)]: - @nextui-org/use-aria-accordion-item@2.0.1 - - @nextui-org/framer-transitions@2.0.1 + - @nextui-org/framer-utils@2.0.1 - @nextui-org/shared-icons@2.0.1 - @nextui-org/shared-utils@2.0.1 - @nextui-org/react-utils@2.0.1 diff --git a/packages/components/accordion/package.json b/packages/components/accordion/package.json index c959c1c24c..5b31572da4 100644 --- a/packages/components/accordion/package.json +++ b/packages/components/accordion/package.json @@ -1,6 +1,6 @@ { "name": "@nextui-org/accordion", - "version": "2.0.28", + "version": "2.0.31", "description": "Collapse display a list of high-level options that can expand/collapse to reveal more information.", "keywords": [ "react", @@ -51,17 +51,16 @@ "@nextui-org/shared-icons": "workspace:*", "@nextui-org/shared-utils": "workspace:*", "@nextui-org/react-utils": "workspace:*", - "@nextui-org/framer-transitions": "workspace:*", + "@nextui-org/framer-utils": "workspace:*", "@nextui-org/divider": "workspace:*", "@nextui-org/use-aria-accordion": "workspace:*", - "@nextui-org/use-aria-press": "workspace:*", - "@react-aria/interactions": "^3.19.1", - "@react-aria/focus": "^3.14.3", - "@react-aria/utils": "^3.21.1", - "@react-stately/tree": "^3.7.3", - "@react-aria/button": "^3.8.4", - "@react-types/accordion": "3.0.0-alpha.17", - "@react-types/shared": "^3.21.0" + "@react-aria/interactions": "^3.21.1", + "@react-aria/focus": "^3.16.2", + "@react-aria/utils": "^3.23.2", + "@react-stately/tree": "^3.7.6", + "@react-aria/button": "^3.9.3", + "@react-types/accordion": "3.0.0-alpha.19", + "@react-types/shared": "^3.22.1" }, "devDependencies": { "@nextui-org/theme": "workspace:*", @@ -70,7 +69,7 @@ "@nextui-org/avatar": "workspace:*", "@nextui-org/input": "workspace:*", "@nextui-org/test-utils": "workspace:*", - "framer-motion": "^10.16.4", + "framer-motion": "^11.0.22", "clean-package": "2.2.0", "react": "^18.0.0", "react-dom": "^18.0.0" diff --git a/packages/components/accordion/src/accordion-item.tsx b/packages/components/accordion/src/accordion-item.tsx index 48990afab1..21fb94a93d 100644 --- a/packages/components/accordion/src/accordion-item.tsx +++ b/packages/components/accordion/src/accordion-item.tsx @@ -2,7 +2,7 @@ import {forwardRef} from "@nextui-org/system"; import {useMemo, ReactNode} from "react"; import {ChevronIcon} from "@nextui-org/shared-icons"; import {AnimatePresence, LazyMotion, domAnimation, m, useWillChange} from "framer-motion"; -import {TRANSITION_VARIANTS} from "@nextui-org/framer-transitions"; +import {TRANSITION_VARIANTS} from "@nextui-org/framer-utils"; import {UseAccordionItemProps, useAccordionItem} from "./use-accordion-item"; diff --git a/packages/components/accordion/src/use-accordion-item.ts b/packages/components/accordion/src/use-accordion-item.ts index 82befdc7dc..1b1322ba29 100644 --- a/packages/components/accordion/src/use-accordion-item.ts +++ b/packages/components/accordion/src/use-accordion-item.ts @@ -1,14 +1,13 @@ import {HTMLNextUIProps, PropGetter} from "@nextui-org/system"; import {useFocusRing} from "@react-aria/focus"; import {accordionItem} from "@nextui-org/theme"; -import {clsx, callAllHandlers, dataAttr} from "@nextui-org/shared-utils"; +import {clsx, callAllHandlers, dataAttr, objectToDeps} from "@nextui-org/shared-utils"; import {ReactRef, useDOMRef, filterDOMProps} from "@nextui-org/react-utils"; import {NodeWithProps} from "@nextui-org/aria-utils"; import {useReactAriaAccordionItem} from "@nextui-org/use-aria-accordion"; import {useCallback, useMemo} from "react"; import {chain, mergeProps} from "@react-aria/utils"; -import {useHover} from "@react-aria/interactions"; -import {usePress} from "@nextui-org/use-aria-press"; +import {useHover, usePress} from "@react-aria/interactions"; import {TreeState} from "@react-stately/tree"; import {AccordionItemBaseProps} from "./base/accordion-item-base"; @@ -112,7 +111,7 @@ export function useAccordionItem(props: UseAccordionItemP () => ({ ...classNamesProp, }), - [...Object.values(classNamesProp)], + [objectToDeps(classNamesProp)], ); const slots = useMemo( diff --git a/packages/components/autocomplete/CHANGELOG.md b/packages/components/autocomplete/CHANGELOG.md index e99023f410..70a8a7970f 100644 --- a/packages/components/autocomplete/CHANGELOG.md +++ b/packages/components/autocomplete/CHANGELOG.md @@ -1,5 +1,96 @@ # @nextui-org/autocomplete +## 2.0.15 + +### Patch Changes + +- Updated dependencies [[`183a4a6cf`](https://github.com/nextui-org/nextui/commit/183a4a6cfda193a076a4a30550ab93b72d51002d), [`eccc2f2f3`](https://github.com/nextui-org/nextui/commit/eccc2f2f3d856eefb2cc7c07b94e1c4cefd4d7d0)]: + - @nextui-org/popover@2.1.20 + - @nextui-org/aria-utils@2.0.18 + - @nextui-org/react-utils@2.0.13 + - @nextui-org/button@2.0.30 + - @nextui-org/input@2.1.20 + - @nextui-org/listbox@2.1.19 + - @nextui-org/scroll-shadow@2.1.16 + - @nextui-org/spinner@2.0.28 + +## 2.0.14 + +### Patch Changes + +- Updated dependencies [[`9e5dd8ce3`](https://github.com/nextui-org/nextui/commit/9e5dd8ce37c94c9ca1ba7b2049a6e55f1803fee9)]: + - @nextui-org/popover@2.1.19 + +## 2.0.13 + +### Patch Changes + +- Updated dependencies [[`f89356691`](https://github.com/nextui-org/nextui/commit/f89356691cecb8e54f5f820b2b4491537e7c11f3)]: + - @nextui-org/popover@2.1.18 + +## 2.0.12 + +### Patch Changes + +- Updated dependencies []: + - @nextui-org/button@2.0.29 + - @nextui-org/input@2.1.19 + - @nextui-org/listbox@2.1.18 + - @nextui-org/popover@2.1.17 + - @nextui-org/scroll-shadow@2.1.15 + - @nextui-org/aria-utils@2.0.17 + - @nextui-org/spinner@2.0.27 + - @nextui-org/react-utils@2.0.12 + +## 2.0.11 + +### Patch Changes + +- [#2674](https://github.com/nextui-org/nextui/pull/2674) [`86a78c9b9`](https://github.com/nextui-org/nextui/commit/86a78c9b91042f871a60a9a2d6e3e3acc636637d) Thanks [@wingkwong](https://github.com/wingkwong)! - Fixed empty items with allowCustomValue by avoiding null node in `ariaHideOutside` from `@react-aria/overlays` + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - v2.3.0 + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - Fixed the issue where only two keyframes were supported with spring and inertia animations. + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - - Calendar component added + + - objectToDeps function applied all across components + - `useMeasure` hook added + - `useIntersectionObserver` hook added + - `framer-transitions` renamed to `framer-utils` + - `ResizablePanel` component added to `framer-utils` + - `test-utils` updated + +- [#2536](https://github.com/nextui-org/nextui/pull/2536) [`2b9f89023`](https://github.com/nextui-org/nextui/commit/2b9f89023ac087016083dcc205703ae1b2bc9cb8) Thanks [@wingkwong](https://github.com/wingkwong)! - revise shouldCloseOnInteractOutside for FreeSoloPopover + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - Fixed react-hook-form uncontrolled components (#1969) + +- [#2100](https://github.com/nextui-org/nextui/pull/2100) [`af877f7dd`](https://github.com/nextui-org/nextui/commit/af877f7ddbfd0de5b2e025be077f22155762e93d) Thanks [@black197](https://github.com/black197)! - Fix #1909 overwrite `onKeyDown` to prevent meaningless error msg + +- [#2654](https://github.com/nextui-org/nextui/pull/2654) [`a1c112431`](https://github.com/nextui-org/nextui/commit/a1c112431f211bb0417443e771a67bdd912f4d66) Thanks [@wingkwong](https://github.com/wingkwong)! - Removed unnecessary map after getting all collection keys + +- [#2716](https://github.com/nextui-org/nextui/pull/2716) [`25640e42f`](https://github.com/nextui-org/nextui/commit/25640e42ff2656440f0fc33b9b75150005b9086d) Thanks [@wingkwong](https://github.com/wingkwong)! - Fixes incorrect prop name in getEmptyPopoverProps (#2715) + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - Fixed autocomplete listbox keyboard navigation (#2680) + +- [#2429](https://github.com/nextui-org/nextui/pull/2429) [`bae544d19`](https://github.com/nextui-org/nextui/commit/bae544d1985dc093aedfa652578acdfcdae83983) Thanks [@wingkwong](https://github.com/wingkwong)! - fixed isReadOnly logic in Autocomplete (#2420) + +- [#2458](https://github.com/nextui-org/nextui/pull/2458) [`7263daca0`](https://github.com/nextui-org/nextui/commit/7263daca08674338eb28529315070337ba0dfc17) Thanks [@wingkwong](https://github.com/wingkwong)! - fix(autocomplete): support isReadOnly for dynamic collections in Autocomplete + +- Updated dependencies [[`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14), [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14), [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14), [`a05aef0ac`](https://github.com/nextui-org/nextui/commit/a05aef0acb5a7b000c8131e8ba4f50f0adec01e5), [`2b9f89023`](https://github.com/nextui-org/nextui/commit/2b9f89023ac087016083dcc205703ae1b2bc9cb8), [`c5049edfd`](https://github.com/nextui-org/nextui/commit/c5049edfde7edaee2081d70e581739be9dcae2f9), [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14), [`52dafd08f`](https://github.com/nextui-org/nextui/commit/52dafd08f178483e79dc847b61d1c761af26eb8e), [`8761168d3`](https://github.com/nextui-org/nextui/commit/8761168d3459cd83ce571f4e65eb8ea6db8516ef), [`eb51bf226`](https://github.com/nextui-org/nextui/commit/eb51bf226170e4bb37ae30990d1c3aa26d8c504b), [`7263daca0`](https://github.com/nextui-org/nextui/commit/7263daca08674338eb28529315070337ba0dfc17), [`2894aecca`](https://github.com/nextui-org/nextui/commit/2894aecca1a2ef0dfb3066b9b8df24ce48c99dae)]: + - @nextui-org/button@2.0.28 + - @nextui-org/input@2.1.18 + - @nextui-org/listbox@2.1.17 + - @nextui-org/popover@2.1.16 + - @nextui-org/scroll-shadow@2.1.14 + - @nextui-org/spinner@2.0.26 + - @nextui-org/use-aria-button@2.0.7 + - @nextui-org/aria-utils@2.0.16 + - @nextui-org/react-utils@2.0.11 + - @nextui-org/shared-icons@2.0.7 + - @nextui-org/shared-utils@2.0.5 + - @nextui-org/use-safe-layout-effect@2.0.5 + ## 2.0.10 ### Patch Changes diff --git a/packages/components/autocomplete/package.json b/packages/components/autocomplete/package.json index e7e45c0163..a7ace9f7ad 100644 --- a/packages/components/autocomplete/package.json +++ b/packages/components/autocomplete/package.json @@ -1,6 +1,6 @@ { "name": "@nextui-org/autocomplete", - "version": "2.0.10", + "version": "2.0.15", "description": "An autocomplete combines a text input with a listbox, allowing users to filter a list of options to items matching a query.", "keywords": [ "autocomplete" @@ -52,15 +52,16 @@ "@nextui-org/button": "workspace:*", "@nextui-org/use-aria-button": "workspace:*", "@nextui-org/shared-icons": "workspace:*", - "@react-aria/combobox": "^3.7.1", - "@react-aria/focus": "^3.14.3", - "@react-aria/i18n": "^3.8.4", - "@react-aria/interactions": "^3.19.1", - "@react-aria/utils": "^3.21.1", - "@react-aria/visually-hidden": "^3.8.6", - "@react-stately/combobox": "^3.7.1", - "@react-types/combobox": "^3.8.1", - "@react-types/shared": "^3.21.0" + "@nextui-org/use-safe-layout-effect": "workspace:*", + "@react-aria/combobox": "^3.8.4", + "@react-aria/focus": "^3.16.2", + "@react-aria/i18n": "^3.10.2", + "@react-aria/interactions": "^3.21.1", + "@react-aria/utils": "^3.23.2", + "@react-aria/visually-hidden": "^3.8.10", + "@react-stately/combobox": "^3.8.2", + "@react-types/combobox": "^3.10.1", + "@react-types/shared": "^3.22.1" }, "devDependencies": { "@nextui-org/theme": "workspace:*", @@ -69,8 +70,8 @@ "@nextui-org/chip": "workspace:*", "@nextui-org/stories-utils": "workspace:*", "@nextui-org/use-infinite-scroll": "workspace:*", - "@react-stately/data": "^3.10.3", - "framer-motion": "^10.16.4", + "@react-stately/data": "^3.11.0", + "framer-motion": "^11.0.28", "clean-package": "2.2.0", "react": "^18.0.0", "react-dom": "^18.0.0" diff --git a/packages/components/autocomplete/src/autocomplete.tsx b/packages/components/autocomplete/src/autocomplete.tsx index c5f107be2f..7da035b20f 100644 --- a/packages/components/autocomplete/src/autocomplete.tsx +++ b/packages/components/autocomplete/src/autocomplete.tsx @@ -33,12 +33,7 @@ function Autocomplete(props: Props, ref: ForwardedRef({...props, ref}); const popoverContent = isOpen ? ( - false} - state={state} - > + diff --git a/packages/components/autocomplete/src/use-autocomplete.ts b/packages/components/autocomplete/src/use-autocomplete.ts index cd63d61166..33ee107577 100644 --- a/packages/components/autocomplete/src/use-autocomplete.ts +++ b/packages/components/autocomplete/src/use-autocomplete.ts @@ -1,9 +1,9 @@ import type {AutocompleteVariantProps, SlotsToClasses, AutocompleteSlots} from "@nextui-org/theme"; import {DOMAttributes, HTMLNextUIProps, mapPropsVariants, PropGetter} from "@nextui-org/system"; +import {useSafeLayoutEffect} from "@nextui-org/use-safe-layout-effect"; import {autocomplete} from "@nextui-org/theme"; import {useFilter} from "@react-aria/i18n"; -import {useComboBox} from "@react-aria/combobox"; import {FilterFn, useComboBoxState} from "@react-stately/combobox"; import {ReactRef, useDOMRef} from "@nextui-org/react-utils"; import {ReactNode, useCallback, useEffect, useMemo, useRef} from "react"; @@ -11,11 +11,12 @@ import {ComboBoxProps} from "@react-types/combobox"; import {PopoverProps} from "@nextui-org/popover"; import {ListboxProps} from "@nextui-org/listbox"; import {InputProps} from "@nextui-org/input"; -import {clsx, dataAttr} from "@nextui-org/shared-utils"; +import {clsx, dataAttr, objectToDeps} from "@nextui-org/shared-utils"; import {ScrollShadowProps} from "@nextui-org/scroll-shadow"; import {chain, mergeProps} from "@react-aria/utils"; import {ButtonProps} from "@nextui-org/button"; import {AsyncLoadable, PressEvent} from "@react-types/shared"; +import {useComboBox} from "@react-aria/combobox"; interface Props extends Omit, keyof ComboBoxProps> { /** @@ -110,8 +111,11 @@ interface Props extends Omit, keyof ComboBoxProps } export type UseAutocompleteProps = Props & - Omit & - ComboBoxProps & + Omit< + InputProps, + "children" | "value" | "isClearable" | "defaultValue" | "classNames" | "validationBehavior" + > & + Omit, "validationBehavior"> & AsyncLoadable & AutocompleteVariantProps; @@ -154,6 +158,7 @@ export function useAutocomplete(originalProps: UseAutocomplete allowsCustomValue = false, className, classNames, + errorMessage, onOpenChange, onClose, isReadOnly = false, @@ -167,6 +172,7 @@ export function useAutocomplete(originalProps: UseAutocomplete ...originalProps, children, menuTrigger, + validationBehavior: "native", shouldCloseOnBlur, allowsEmptyCollection, defaultFilter: defaultFilter && typeof defaultFilter === "function" ? defaultFilter : contains, @@ -193,6 +199,27 @@ export function useAutocomplete(originalProps: UseAutocomplete const inputRef = useDOMRef(ref); const scrollShadowRef = useDOMRef(scrollRefProp); + const { + buttonProps, + inputProps, + listBoxProps, + isInvalid: isAriaInvalid, + validationDetails, + validationErrors, + } = useComboBox( + { + validationBehavior: "native", + ...originalProps, + inputRef, + buttonRef, + listBoxRef, + popoverRef, + }, + state, + ); + + const isInvalid = originalProps.isInvalid || isAriaInvalid; + const slotsProps: { inputProps: InputProps; popoverProps: UseAutocompleteProps["popoverProps"]; @@ -248,7 +275,7 @@ export function useAutocomplete(originalProps: UseAutocomplete size: "sm", variant: "light", radius: "full", - color: originalProps?.isInvalid ? "danger" : originalProps?.color, + color: isInvalid ? "danger" : originalProps?.color, isIconOnly: true, disableAnimation, }, @@ -259,7 +286,7 @@ export function useAutocomplete(originalProps: UseAutocomplete size: "sm", variant: "light", radius: "full", - color: originalProps?.isInvalid ? "danger" : originalProps?.color, + color: isInvalid ? "danger" : originalProps?.color, isIconOnly: true, disableAnimation, }, @@ -272,6 +299,21 @@ export function useAutocomplete(originalProps: UseAutocomplete ? state.isOpen && !!state.collection.size : state.isOpen; + // if we use `react-hook-form`, it will set the native input value using the ref in register + // i.e. setting ref.current.value to something which is uncontrolled + // hence, sync the state with `ref.current.value` + useSafeLayoutEffect(() => { + if (!inputRef.current) return; + + const key = inputRef.current.value; + const item = state.collection.getItem(key); + + if (item) { + state.setSelectedKey(key); + state.setInputValue(item.textValue); + } + }, [inputRef.current, state]); + // apply the same with to the popover as the select useEffect(() => { if (isOpen && popoverRef.current && inputWrapperRef.current) { @@ -290,17 +332,6 @@ export function useAutocomplete(originalProps: UseAutocomplete } }, [isOpen, allowsCustomValue]); - const {buttonProps, inputProps, listBoxProps} = useComboBox( - { - ...originalProps, - inputRef, - buttonRef, - listBoxRef, - popoverRef, - }, - state, - ); - // to prevent the error message: // stopPropagation is now the default behavior for events in React Spectrum. // You can use continuePropagation() to revert this behavior. @@ -326,7 +357,7 @@ export function useAutocomplete(originalProps: UseAutocomplete disableAnimation, className, }), - [...Object.values(variantProps), isClearable, disableAnimation, className], + [objectToDeps(variantProps), isClearable, disableAnimation, className], ); const onClear = useCallback(() => { @@ -343,7 +374,7 @@ export function useAutocomplete(originalProps: UseAutocomplete ); const getBaseProps: PropGetter = () => ({ - "data-invalid": dataAttr(originalProps?.isInvalid), + "data-invalid": dataAttr(isInvalid), "data-open": dataAttr(state.isOpen), className: slots.base({class: baseStyles}), }); @@ -384,6 +415,11 @@ export function useAutocomplete(originalProps: UseAutocomplete ...otherProps, ...inputProps, ...slotsProps.inputProps, + isInvalid, + errorMessage: + typeof errorMessage === "function" + ? errorMessage({isInvalid, validationErrors, validationDetails}) + : errorMessage || validationErrors?.join(" "), onClick: chain(slotsProps.inputProps.onClick, otherProps.onClick), } as unknown as InputProps); @@ -391,8 +427,10 @@ export function useAutocomplete(originalProps: UseAutocomplete ({ state, ref: listBoxRef, - shouldHighlightOnFocus: true, - ...mergeProps(slotsProps.listboxProps, listBoxProps), + ...mergeProps(slotsProps.listboxProps, listBoxProps, { + shouldHighlightOnFocus: true, + shouldUseVirtualFocus: false, + }), } as ListboxProps); const getPopoverProps = (props: DOMAttributes = {}) => { diff --git a/packages/components/autocomplete/stories/autocomplete.stories.tsx b/packages/components/autocomplete/stories/autocomplete.stories.tsx index a9bbdd2944..a3b422bbcc 100644 --- a/packages/components/autocomplete/stories/autocomplete.stories.tsx +++ b/packages/components/autocomplete/stories/autocomplete.stories.tsx @@ -1,3 +1,5 @@ +import type {ValidationResult} from "@react-types/shared"; + import React, {Key} from "react"; import {Meta} from "@storybook/react"; import {autocomplete, input, button} from "@nextui-org/theme"; @@ -127,7 +129,7 @@ const DynamicTemplate = ({color, variant, ...args}: AutocompleteProps) = ); -const RequiredTemplate = ({color, variant, ...args}: AutocompleteProps) => { +const FormTemplate = ({color, variant, ...args}: AutocompleteProps) => { return (
{ }} > { + if (value.validationDetails.valueMissing) { + return "Value is required"; + } + }, + }, +}; + +export const WithValidation = { + render: FormTemplate, + + args: { + ...defaultProps, + isRequired: true, + validate: (value) => { + if (value.inputValue === "Cat" || value.selectedKey === "dog") { + return "Please select a valid animal"; + } + }, + }, +}; + export const IsInvalid = { render: Template, diff --git a/packages/components/avatar/CHANGELOG.md b/packages/components/avatar/CHANGELOG.md index d02a97ea9a..c93386fb1f 100644 --- a/packages/components/avatar/CHANGELOG.md +++ b/packages/components/avatar/CHANGELOG.md @@ -1,5 +1,43 @@ # @nextui-org/avatar +## 2.0.27 + +### Patch Changes + +- Updated dependencies [[`eccc2f2f3`](https://github.com/nextui-org/nextui/commit/eccc2f2f3d856eefb2cc7c07b94e1c4cefd4d7d0)]: + - @nextui-org/react-utils@2.0.13 + +## 2.0.26 + +### Patch Changes + +- Updated dependencies []: + - @nextui-org/react-utils@2.0.12 + +## 2.0.25 + +### Patch Changes + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - v2.3.0 + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - - Calendar component added + + - objectToDeps function applied all across components + - `useMeasure` hook added + - `useIntersectionObserver` hook added + - `framer-transitions` renamed to `framer-utils` + - `ResizablePanel` component added to `framer-utils` + - `test-utils` updated + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - Support slots in AvatarGroup + +- [#2498](https://github.com/nextui-org/nextui/pull/2498) [`5d84634c0`](https://github.com/nextui-org/nextui/commit/5d84634c0af3a5a66622d188950f2bcacde7c2e4) Thanks [@mrbadri](https://github.com/mrbadri)! - Add RTL support to the avatar group component + +- Updated dependencies [[`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14), [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14)]: + - @nextui-org/react-utils@2.0.11 + - @nextui-org/shared-utils@2.0.5 + - @nextui-org/use-image@2.0.5 + ## 2.0.24 ### Patch Changes diff --git a/packages/components/avatar/package.json b/packages/components/avatar/package.json index 0fda1762b2..0b691c8188 100644 --- a/packages/components/avatar/package.json +++ b/packages/components/avatar/package.json @@ -1,6 +1,6 @@ { "name": "@nextui-org/avatar", - "version": "2.0.24", + "version": "2.0.27", "description": "The Avatar component is used to represent a user, and displays the profile picture, initials or fallback icon.", "keywords": [ "avatar" @@ -43,9 +43,9 @@ "@nextui-org/shared-utils": "workspace:*", "@nextui-org/react-utils": "workspace:*", "@nextui-org/use-image": "workspace:*", - "@react-aria/interactions": "^3.19.1", - "@react-aria/focus": "^3.14.3", - "@react-aria/utils": "^3.21.1" + "@react-aria/interactions": "^3.21.1", + "@react-aria/focus": "^3.16.2", + "@react-aria/utils": "^3.23.2" }, "devDependencies": { "@nextui-org/theme": "workspace:*", diff --git a/packages/components/avatar/src/avatar-group.tsx b/packages/components/avatar/src/avatar-group.tsx index f164e70b68..1106703f57 100644 --- a/packages/components/avatar/src/avatar-group.tsx +++ b/packages/components/avatar/src/avatar-group.tsx @@ -12,8 +12,9 @@ const AvatarGroup = forwardRef<"div", AvatarGroupProps>((props, ref) => { clones, context, remainingCount, - renderCount = (count) => , + getAvatarGroupCountProps, getAvatarGroupProps, + renderCount = (count) => , } = useAvatarGroup({ ...props, ref, diff --git a/packages/components/avatar/src/use-avatar-group.ts b/packages/components/avatar/src/use-avatar-group.ts index 461e902508..c8bc27b48b 100644 --- a/packages/components/avatar/src/use-avatar-group.ts +++ b/packages/components/avatar/src/use-avatar-group.ts @@ -1,4 +1,5 @@ import type {ReactNode} from "react"; +import type {SlotsToClasses, AvatarGroupSlots, AvatarGroupVariantProps} from "@nextui-org/theme"; import {avatarGroup} from "@nextui-org/theme"; import {HTMLNextUIProps, PropGetter} from "@nextui-org/system"; @@ -31,9 +32,23 @@ interface Props extends HTMLNextUIProps<"div"> { * This allows you to render a custom count component. */ renderCount?: (count: number) => ReactNode; + /** + * Classname or List of classes to change the classNames of the avatar group. + * if `className` is passed, it will be added to the base slot. + * + * @example + * ```ts + * + * ``` + */ + classNames?: SlotsToClasses; } export type UseAvatarGroupProps = Props & + Omit & Partial>; export type ContextType = { @@ -60,6 +75,7 @@ export function useAvatarGroup(props: UseAvatarGroupProps = {}) { isGrid, renderCount, className, + classNames, ...otherProps } = props; @@ -78,7 +94,7 @@ export function useAvatarGroup(props: UseAvatarGroupProps = {}) { }), [size, color, radius, isGrid, isBordered, isDisabled], ); - const classNames = useMemo(() => avatarGroup({className, isGrid}), [className, isGrid]); + const slots = useMemo(() => avatarGroup({className, isGrid}), [className, isGrid]); const validChildren = getValidChildren(children); const childrenWithinMax = max ? validChildren.slice(0, max) : validChildren; @@ -102,12 +118,22 @@ export function useAvatarGroup(props: UseAvatarGroupProps = {}) { const getAvatarGroupProps: PropGetter = () => { return { ref: domRef, - className: classNames, + className: slots.base({ + class: clsx(classNames?.base, className), + }), role: "group", ...otherProps, }; }; + const getAvatarGroupCountProps = () => { + return { + className: slots.count({ + class: classNames?.count, + }), + } as AvatarProps; + }; + return { Component, context, @@ -115,6 +141,7 @@ export function useAvatarGroup(props: UseAvatarGroupProps = {}) { clones, renderCount, getAvatarGroupProps, + getAvatarGroupCountProps, }; } diff --git a/packages/components/avatar/stories/avatar-group.stories.tsx b/packages/components/avatar/stories/avatar-group.stories.tsx index cb0e632469..2b5e75fc85 100644 --- a/packages/components/avatar/stories/avatar-group.stories.tsx +++ b/packages/components/avatar/stories/avatar-group.stories.tsx @@ -42,6 +42,47 @@ const Template = (args: AvatarGroupProps) => ( ); +const CustomSlotsTemplate = (args: AvatarGroupProps) => ( + + + + + + + + +); + export const Default = { render: Template, @@ -106,3 +147,14 @@ export const CustomCount = { ), }, }; + +export const CustomSlots = { + render: CustomSlotsTemplate, + + args: { + classNames: {count: "border-2 border-yellow-400"}, + max: 3, + radius: "sm", + size: "sm", + }, +}; diff --git a/packages/components/badge/CHANGELOG.md b/packages/components/badge/CHANGELOG.md index 8476a15272..3c7e97a8eb 100644 --- a/packages/components/badge/CHANGELOG.md +++ b/packages/components/badge/CHANGELOG.md @@ -1,5 +1,43 @@ # @nextui-org/badge +## 2.0.27 + +### Patch Changes + +- Updated dependencies [[`eccc2f2f3`](https://github.com/nextui-org/nextui/commit/eccc2f2f3d856eefb2cc7c07b94e1c4cefd4d7d0)]: + - @nextui-org/react-utils@2.0.13 + - @nextui-org/system-rsc@2.1.1 + +## 2.0.26 + +### Patch Changes + +- Updated dependencies [[`74eda3128`](https://github.com/nextui-org/nextui/commit/74eda312883b2e17df26f71442aba9fb3cd240be)]: + - @nextui-org/system-rsc@2.1.1 + - @nextui-org/react-utils@2.0.12 + +## 2.0.25 + +### Patch Changes + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - v2.3.0 + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - - Calendar component added + + - objectToDeps function applied all across components + - `useMeasure` hook added + - `useIntersectionObserver` hook added + - `framer-transitions` renamed to `framer-utils` + - `ResizablePanel` component added to `framer-utils` + - `test-utils` updated + +- [#2541](https://github.com/nextui-org/nextui/pull/2541) [`26a3a7d2c`](https://github.com/nextui-org/nextui/commit/26a3a7d2c6433c3bdd2aa6e6200077a57fdd94f4) Thanks [@withden](https://github.com/withden)! - Removing the `children` type from BadgeProps, as the already extended UseBadgeProps has a `children` prop. + +- Updated dependencies [[`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14), [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14), [`c5049edfd`](https://github.com/nextui-org/nextui/commit/c5049edfde7edaee2081d70e581739be9dcae2f9)]: + - @nextui-org/system-rsc@2.1.0 + - @nextui-org/react-utils@2.0.11 + - @nextui-org/shared-utils@2.0.5 + ## 2.0.24 ### Patch Changes diff --git a/packages/components/badge/package.json b/packages/components/badge/package.json index 4f99047127..d47acaa993 100644 --- a/packages/components/badge/package.json +++ b/packages/components/badge/package.json @@ -1,6 +1,6 @@ { "name": "@nextui-org/badge", - "version": "2.0.24", + "version": "2.0.27", "description": "Badges are used as a small numerical value or status descriptor for UI elements.", "keywords": [ "badge" diff --git a/packages/components/badge/src/use-badge.ts b/packages/components/badge/src/use-badge.ts index f7dffc28d2..db304c3733 100644 --- a/packages/components/badge/src/use-badge.ts +++ b/packages/components/badge/src/use-badge.ts @@ -4,7 +4,7 @@ import type {HTMLNextUIProps, PropGetter} from "@nextui-org/system-rsc"; import {badge} from "@nextui-org/theme"; import {mapPropsVariants} from "@nextui-org/system-rsc"; -import {clsx} from "@nextui-org/shared-utils"; +import {clsx, objectToDeps} from "@nextui-org/shared-utils"; import {ReactRef} from "@nextui-org/react-utils"; import {useMemo} from "react"; @@ -70,7 +70,7 @@ export function useBadge(originalProps: UseBadgeProps) { isOneChar, isDot, }), - [...Object.values(variantProps), isOneChar, isDot], + [objectToDeps(variantProps), isOneChar, isDot], ); const getBadgeProps: PropGetter = () => { diff --git a/packages/components/breadcrumbs/CHANGELOG.md b/packages/components/breadcrumbs/CHANGELOG.md index 208dc2933e..d40dd8fcc0 100644 --- a/packages/components/breadcrumbs/CHANGELOG.md +++ b/packages/components/breadcrumbs/CHANGELOG.md @@ -1,5 +1,37 @@ # @nextui-org/breadcrumbs +## 2.0.7 + +### Patch Changes + +- Updated dependencies [[`eccc2f2f3`](https://github.com/nextui-org/nextui/commit/eccc2f2f3d856eefb2cc7c07b94e1c4cefd4d7d0)]: + - @nextui-org/react-utils@2.0.13 + +## 2.0.6 + +### Patch Changes + +- Updated dependencies []: + - @nextui-org/react-utils@2.0.12 + +## 2.0.5 + +### Patch Changes + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - v2.3.0 + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - - Calendar component added + - objectToDeps function applied all across components + - `useMeasure` hook added + - `useIntersectionObserver` hook added + - `framer-transitions` renamed to `framer-utils` + - `ResizablePanel` component added to `framer-utils` + - `test-utils` updated +- Updated dependencies [[`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14), [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14)]: + - @nextui-org/react-utils@2.0.11 + - @nextui-org/shared-icons@2.0.7 + - @nextui-org/shared-utils@2.0.5 + ## 2.0.4 ### Patch Changes diff --git a/packages/components/breadcrumbs/package.json b/packages/components/breadcrumbs/package.json index 41a5f9e086..162cec659f 100644 --- a/packages/components/breadcrumbs/package.json +++ b/packages/components/breadcrumbs/package.json @@ -1,6 +1,6 @@ { "name": "@nextui-org/breadcrumbs", - "version": "2.0.4", + "version": "2.0.7", "description": "Breadcrumbs display a hierarchy of links to the current page or resource in an application.", "keywords": [ "breadcrumbs" @@ -43,11 +43,11 @@ "@nextui-org/react-utils": "workspace:*", "@nextui-org/shared-utils": "workspace:*", "@nextui-org/shared-icons": "workspace:*", - "@react-aria/focus": "^3.14.3", - "@react-aria/breadcrumbs": "^3.5.7", - "@react-aria/utils": "^3.21.1", - "@react-types/breadcrumbs": "^3.7.1", - "@react-types/shared": "^3.21.0" + "@react-aria/focus": "^3.16.2", + "@react-aria/breadcrumbs": "^3.5.11", + "@react-aria/utils": "^3.23.2", + "@react-types/breadcrumbs": "^3.7.3", + "@react-types/shared": "^3.22.1" }, "devDependencies": { "@nextui-org/theme": "workspace:*", diff --git a/packages/components/breadcrumbs/src/use-breadcrumb-item.ts b/packages/components/breadcrumbs/src/use-breadcrumb-item.ts index 3136bd452a..8c28a5515e 100644 --- a/packages/components/breadcrumbs/src/use-breadcrumb-item.ts +++ b/packages/components/breadcrumbs/src/use-breadcrumb-item.ts @@ -11,7 +11,7 @@ import {useFocusRing} from "@react-aria/focus"; import {breadcrumbItem} from "@nextui-org/theme"; import {filterDOMProps, ReactRef, useDOMRef} from "@nextui-org/react-utils"; import {useBreadcrumbItem as useAriaBreadcrumbItem} from "@react-aria/breadcrumbs"; -import {clsx, dataAttr} from "@nextui-org/shared-utils"; +import {clsx, dataAttr, objectToDeps} from "@nextui-org/shared-utils"; import {useMemo} from "react"; import {mergeProps} from "@react-aria/utils"; @@ -94,7 +94,7 @@ export function useBreadcrumbItem(originalProps: UseBreadcrumbItemProps) { originalProps?.underline !== undefined && !isCurrent ? originalProps?.underline : "none", className, }), - [...Object.values(variantProps), isCurrent, className], + [objectToDeps(variantProps), isCurrent, className], ); const baseStyles = clsx(classNames?.base, className); diff --git a/packages/components/breadcrumbs/src/use-breadcrumbs.ts b/packages/components/breadcrumbs/src/use-breadcrumbs.ts index 327f0060d5..ca99103b6f 100644 --- a/packages/components/breadcrumbs/src/use-breadcrumbs.ts +++ b/packages/components/breadcrumbs/src/use-breadcrumbs.ts @@ -8,7 +8,7 @@ import {filterDOMProps, pickChildren, ReactRef, useDOMRef} from "@nextui-org/rea import {mergeProps} from "@react-aria/utils"; import {useBreadcrumbs as useAriaBreadcrumbs} from "@react-aria/breadcrumbs"; import {useMemo} from "react"; -import {clsx, dataAttr} from "@nextui-org/shared-utils"; +import {clsx, dataAttr, objectToDeps} from "@nextui-org/shared-utils"; import BreadcrumbItem, {BreadcrumbItemProps} from "./breadcrumb-item"; @@ -143,7 +143,7 @@ export function useBreadcrumbs(originalProps: UseBreadcrumbsProps) { ...variantProps, className, }), - [...Object.values(variantProps), className], + [objectToDeps(variantProps), className], ); const baseStyles = clsx(classNames?.base, className); diff --git a/packages/components/breadcrumbs/stories/breadcrumbs.stories.tsx b/packages/components/breadcrumbs/stories/breadcrumbs.stories.tsx index 787eb0152c..c902dbb59e 100644 --- a/packages/components/breadcrumbs/stories/breadcrumbs.stories.tsx +++ b/packages/components/breadcrumbs/stories/breadcrumbs.stories.tsx @@ -237,7 +237,7 @@ const WithDropdownEllipsisTemplate = (args: BreadcrumbsProps & {page: number}) =
- diff --git a/packages/components/button/CHANGELOG.md b/packages/components/button/CHANGELOG.md index 7537219e82..9efd7efe7a 100644 --- a/packages/components/button/CHANGELOG.md +++ b/packages/components/button/CHANGELOG.md @@ -1,5 +1,43 @@ # @nextui-org/button +## 2.0.30 + +### Patch Changes + +- Updated dependencies [[`eccc2f2f3`](https://github.com/nextui-org/nextui/commit/eccc2f2f3d856eefb2cc7c07b94e1c4cefd4d7d0)]: + - @nextui-org/react-utils@2.0.13 + - @nextui-org/ripple@2.0.27 + - @nextui-org/spinner@2.0.28 + +## 2.0.29 + +### Patch Changes + +- Updated dependencies []: + - @nextui-org/ripple@2.0.26 + - @nextui-org/spinner@2.0.27 + - @nextui-org/react-utils@2.0.12 + +## 2.0.28 + +### Patch Changes + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - v2.3.0 + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - - Calendar component added + - objectToDeps function applied all across components + - `useMeasure` hook added + - `useIntersectionObserver` hook added + - `framer-transitions` renamed to `framer-utils` + - `ResizablePanel` component added to `framer-utils` + - `test-utils` updated +- Updated dependencies [[`2e49e0831`](https://github.com/nextui-org/nextui/commit/2e49e0831533350808e0fcbd48585f910981b39a), [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14), [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14), [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14), [`2894aecca`](https://github.com/nextui-org/nextui/commit/2894aecca1a2ef0dfb3066b9b8df24ce48c99dae)]: + - @nextui-org/ripple@2.0.25 + - @nextui-org/spinner@2.0.26 + - @nextui-org/use-aria-button@2.0.7 + - @nextui-org/react-utils@2.0.11 + - @nextui-org/shared-utils@2.0.5 + ## 2.0.27 ### Patch Changes diff --git a/packages/components/button/package.json b/packages/components/button/package.json index 97cb501a7a..0c8f131e7f 100644 --- a/packages/components/button/package.json +++ b/packages/components/button/package.json @@ -1,6 +1,6 @@ { "name": "@nextui-org/button", - "version": "2.0.27", + "version": "2.0.30", "description": "Buttons allow users to perform actions and choose with a single tap.", "keywords": [ "button" @@ -46,12 +46,12 @@ "@nextui-org/use-aria-button": "workspace:*", "@nextui-org/ripple": "workspace:*", "@nextui-org/spinner": "workspace:*", - "@react-aria/button": "^3.8.4", - "@react-aria/interactions": "^3.19.1", - "@react-aria/utils": "^3.21.1", - "@react-aria/focus": "^3.14.3", - "@react-types/shared": "^3.21.0", - "@react-types/button": "^3.9.0" + "@react-aria/button": "^3.9.3", + "@react-aria/interactions": "^3.21.1", + "@react-aria/utils": "^3.23.2", + "@react-aria/focus": "^3.16.2", + "@react-types/shared": "^3.22.1", + "@react-types/button": "^3.9.2" }, "devDependencies": { "@nextui-org/theme": "workspace:*", diff --git a/packages/components/button/src/use-button-group.ts b/packages/components/button/src/use-button-group.ts index c11fc46a5e..fb7a785a59 100644 --- a/packages/components/button/src/use-button-group.ts +++ b/packages/components/button/src/use-button-group.ts @@ -6,6 +6,7 @@ import {buttonGroup} from "@nextui-org/theme"; import {HTMLNextUIProps, PropGetter, mapPropsVariants} from "@nextui-org/system"; import {useDOMRef} from "@nextui-org/react-utils"; import {useMemo, useCallback} from "react"; +import {objectToDeps} from "@nextui-org/shared-utils"; interface Props extends HTMLNextUIProps, ButtonGroupVariantProps { /** * Ref to the DOM node. @@ -67,7 +68,7 @@ export function useButtonGroup(originalProps: UseButtonGroupProps) { ...variantProps, className, }), - [...Object.values(variantProps), className], + [objectToDeps(variantProps), className], ); const context = useMemo( diff --git a/packages/components/calendar/CHANGELOG.md b/packages/components/calendar/CHANGELOG.md new file mode 100644 index 0000000000..ea24ed5a29 --- /dev/null +++ b/packages/components/calendar/CHANGELOG.md @@ -0,0 +1,42 @@ +# @nextui-org/calendar + +## 2.0.3 + +### Patch Changes + +- Updated dependencies [[`eccc2f2f3`](https://github.com/nextui-org/nextui/commit/eccc2f2f3d856eefb2cc7c07b94e1c4cefd4d7d0)]: + - @nextui-org/framer-utils@2.0.18 + - @nextui-org/react-utils@2.0.13 + - @nextui-org/button@2.0.30 + +## 2.0.2 + +### Patch Changes + +- [#2744](https://github.com/nextui-org/nextui/pull/2744) [`158c2aa00`](https://github.com/nextui-org/nextui/commit/158c2aa004f0080449321f84b0efd37762e8adc0) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - Refactor calendar cell tab index, add calendar default width + +- Updated dependencies []: + - @nextui-org/button@2.0.29 + - @nextui-org/framer-utils@2.0.17 + - @nextui-org/react-utils@2.0.12 + +## 2.0.1 + +### Patch Changes + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - v2.3.0 + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - - Calendar component added + - objectToDeps function applied all across components + - `useMeasure` hook added + - `useIntersectionObserver` hook added + - `framer-transitions` renamed to `framer-utils` + - `ResizablePanel` component added to `framer-utils` + - `test-utils` updated +- Updated dependencies [[`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14), [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14)]: + - @nextui-org/button@2.0.28 + - @nextui-org/use-aria-button@2.0.7 + - @nextui-org/framer-utils@2.0.16 + - @nextui-org/react-utils@2.0.11 + - @nextui-org/shared-icons@2.0.7 + - @nextui-org/shared-utils@2.0.5 diff --git a/packages/components/calendar/README.md b/packages/components/calendar/README.md new file mode 100644 index 0000000000..4f58436918 --- /dev/null +++ b/packages/components/calendar/README.md @@ -0,0 +1,24 @@ +# @nextui-org/calendar + +A calendar displays one or more date grids and allows users to select a single date. + +Please refer to the [documentation](https://nextui.org/docs/components/calendar) for more information. + +## Installation + +```sh +yarn add @nextui-org/calendar +# or +npm i @nextui-org/calendar +``` + +## Contribution + +Yes please! See the +[contributing guidelines](https://github.com/nextui-org/nextui/blob/master/CONTRIBUTING.md) +for details. + +## License + +This project is licensed under the terms of the +[MIT license](https://github.com/nextui-org/nextui/blob/master/LICENSE). diff --git a/packages/components/calendar/__tests__/calendar.test.tsx b/packages/components/calendar/__tests__/calendar.test.tsx new file mode 100644 index 0000000000..30b26442d3 --- /dev/null +++ b/packages/components/calendar/__tests__/calendar.test.tsx @@ -0,0 +1,422 @@ +/* eslint-disable jsx-a11y/no-autofocus */ +import * as React from "react"; +import {render, act, fireEvent} from "@testing-library/react"; +import {CalendarDate, isWeekend} from "@internationalized/date"; +import {triggerPress, keyCodes} from "@nextui-org/test-utils"; +import {useLocale} from "@react-aria/i18n"; + +import {Calendar as CalendarBase, CalendarProps} from "../src"; + +/** + * Custom calendar to disable animations and avoid issues with react-motion and jest + */ +const Calendar = React.forwardRef((props: CalendarProps, ref: React.Ref) => { + return ; +}); + +Calendar.displayName = "Calendar"; + +describe("Calendar", () => { + beforeAll(() => { + jest.useFakeTimers(); + }); + afterEach(() => { + act(() => { + jest.runAllTimers(); + }); + }); + + describe("Basics", () => { + it("should render correctly", () => { + const wrapper = render(); + + expect(() => wrapper.unmount()).not.toThrow(); + }); + + it("ref should be forwarded", () => { + const ref = React.createRef(); + + render(); + expect(ref.current).not.toBeNull(); + }); + + it("should render with defaultValue", () => { + const wrapper = render(); + + const heading = wrapper.getByRole("heading"); + + expect(heading).toHaveTextContent("March 2024"); + + const gridCells = wrapper + .getAllByRole("gridcell") + ?.filter((cell) => cell.getAttribute("aria-disabled") !== "true"); + + expect(gridCells).toHaveLength(31); + + const selectedDate = wrapper.getByLabelText("Selected", {exact: false}); + + expect(selectedDate.parentElement).toHaveAttribute("role", "gridcell"); + expect(selectedDate.parentElement).toHaveAttribute("aria-selected", "true"); + expect(selectedDate).toHaveAttribute("aria-label", "Sunday, March 31, 2024 selected"); + }); + + it("should render with a value", () => { + const wrapper = render(); + + const heading = wrapper.getByRole("heading"); + + expect(heading).toHaveTextContent("March 2024"); + + const gridCells = wrapper + .getAllByRole("gridcell") + ?.filter((cell) => cell.getAttribute("aria-disabled") !== "true"); + + expect(gridCells).toHaveLength(31); + + const selectedDate = wrapper.getByLabelText("Selected", {exact: false}); + + expect(selectedDate.parentElement).toHaveAttribute("role", "gridcell"); + expect(selectedDate.parentElement).toHaveAttribute("aria-selected", "true"); + expect(selectedDate).toHaveAttribute("aria-label", "Sunday, March 31, 2024 selected"); + }); + + it("should focus the selected date if autoFocus is set", () => { + // eslint-disable-next-line jsx-a11y/no-autofocus + const wrapper = render(); + + const selectedDate = wrapper.getByLabelText("Selected", {exact: false}); + + const grid = wrapper.getByRole("grid"); + + expect(selectedDate.parentElement).toHaveAttribute("role", "gridcell"); + expect(selectedDate.parentElement).toHaveAttribute("aria-selected", "true"); + expect(selectedDate).toHaveFocus(); + expect(grid).not.toHaveAttribute("aria-activedescendant"); + }); + + it("should center the selected date if multiple months are visible", () => { + let {getAllByRole, getByLabelText} = render( + , + ); + + const grids = getAllByRole("grid"); + + expect(grids).toHaveLength(3); + + const selectedDate = getByLabelText("selected", {exact: false}); + + expect(grids[1].contains(selectedDate)).toBe(true); + }); + + it("should constrain the visible region depending on the minValue", () => { + const {getAllByRole, getByLabelText} = render( + , + ); + + const grids = getAllByRole("grid"); + + expect(grids).toHaveLength(3); + + const selectedDate = getByLabelText("selected", {exact: false}); + + expect(grids[0].contains(selectedDate)).toBe(true); + }); + }); + + describe("Keyboard interactions", () => { + it("should select a date on keyDown Enter/Space (uncontrolled)", () => { + const onChange = jest.fn(); + + const wrapper = render( + , + ); + + const grid = wrapper.getByRole("grid"); + let selectedDate = wrapper.getByLabelText("Selected", {exact: false}); + + expect(selectedDate.textContent).toBe("31"); + + // Select a new date + fireEvent.keyDown(grid, {key: "ArrowLeft", keyCode: keyCodes.ArrowLeft}); + fireEvent.keyDown(grid, {key: "Enter", keyCode: keyCodes.Enter}); + + selectedDate = wrapper.getByLabelText("Selected", {exact: false}); + + expect(selectedDate.textContent).toBe("30"); + expect(onChange).toHaveBeenCalledTimes(1); + expect(onChange.mock.calls[0][0]).toEqual(new CalendarDate(2024, 3, 30)); + + // Select a new date + fireEvent.keyDown(grid, {key: "ArrowLeft", keyCode: keyCodes.ArrowLeft}); + fireEvent.keyDown(grid, {key: " ", keyCode: keyCodes[" "]}); + + selectedDate = wrapper.getByLabelText("Selected", {exact: false}); + + expect(selectedDate.textContent).toBe("29"); + expect(onChange).toHaveBeenCalledTimes(2); + expect(onChange.mock.calls[1][0]).toEqual(new CalendarDate(2024, 3, 29)); + }); + + it("should select a date on keyDown Enter/Space (controlled)", () => { + let onChange = jest.fn(); + let value = new CalendarDate(2024, 3, 31); + + let wrapper = render(); + + let grid = wrapper.getByRole("grid"); + let selectedDate = wrapper.getByLabelText("Selected", {exact: false}); + + expect(selectedDate.textContent).toBe("31"); + + // Select a new date + fireEvent.keyDown(grid, {key: "ArrowLeft", keyCode: keyCodes.ArrowLeft}); + fireEvent.keyDown(grid, {key: "Enter", keyCode: keyCodes.Enter}); + + selectedDate = wrapper.getByLabelText("Selected", {exact: false}); + + expect(selectedDate.textContent).toBe("31"); // controlled (value didn't change) + expect(onChange).toHaveBeenCalledTimes(1); + expect(onChange.mock.calls[0][0]).toEqual(new CalendarDate(2024, 3, 30)); + + // Select a new date + fireEvent.keyDown(grid, {key: "ArrowLeft", keyCode: keyCodes.ArrowLeft}); + fireEvent.keyDown(grid, {key: " ", keyCode: keyCodes[" "]}); + + selectedDate = wrapper.getByLabelText("Selected", {exact: false}); + + expect(selectedDate.textContent).toBe("31"); // controlled (value didn't change) + expect(onChange).toHaveBeenCalledTimes(2); + expect(onChange.mock.calls[1][0]).toEqual(new CalendarDate(2024, 3, 29)); + }); + + it("should not select a date on keyDown Enter/Space if isReadOnly", () => { + const onChange = jest.fn(); + + const wrapper = render( + , + ); + + const grid = wrapper.getByRole("grid"); + let selectedDate = wrapper.getByLabelText("Selected", {exact: false}); + + expect(selectedDate.textContent).toBe("31"); + + // Select a new date + fireEvent.keyDown(grid, {key: "ArrowLeft", keyCode: keyCodes.ArrowLeft}); + fireEvent.keyDown(grid, {key: "Enter", keyCode: keyCodes.Enter}); + + selectedDate = wrapper.getByLabelText("Selected", {exact: false}); + + expect(selectedDate.textContent).toBe("31"); + expect(onChange).not.toHaveBeenCalled(); + }); + + it("should select a date on click (uncontrolled)", () => { + let onChange = jest.fn(); + let {getByLabelText, getByText} = render( + , + ); + + let newDate = getByText("17"); + + triggerPress(newDate); + + let selectedDate = getByLabelText("selected", {exact: false}); + + expect(selectedDate.textContent).toBe("31"); + expect(onChange).toHaveBeenCalledTimes(1); + expect(onChange.mock.calls[0][0]).toEqual(new CalendarDate(2024, 3, 17)); + }); + + it("should not select a date on click if isDisabled", () => { + let onChange = jest.fn(); + let {getAllByLabelText, getByText} = render( + , + ); + + let newDate = getByText("17"); + + triggerPress(newDate); + + expect(() => { + getAllByLabelText("Selected", {exact: false}); + }).toThrow(); + + expect(onChange).not.toHaveBeenCalled(); + }); + + it("should not select a date on click if isReadOnly", () => { + let onChange = jest.fn(); + let {getByLabelText, getByText} = render( + , + ); + + let newDate = getByText("17"); + + triggerPress(newDate); + + let selectedDate = getByLabelText("Selected", {exact: false}); + + expect(selectedDate.textContent).toBe("31"); + expect(onChange).not.toHaveBeenCalled(); + }); + + it("should not select a date on click if outside the valid date range", () => { + let onChange = jest.fn(); + let {getByLabelText} = render( + , + ); + + triggerPress(getByLabelText("Sunday, February 3, 2019")); + + let selectedDate = getByLabelText("Selected", {exact: false}); + + expect(selectedDate.textContent).toBe("8"); + expect(onChange).not.toHaveBeenCalled(); + + triggerPress(getByLabelText("Sunday, February 17, 2019")); + + selectedDate = getByLabelText("Selected", {exact: false}); + expect(selectedDate.textContent).toBe("8"); + expect(onChange).not.toHaveBeenCalled(); + + triggerPress(getByLabelText("Tuesday, February 5, 2019, First available date")); + + selectedDate = getByLabelText("Selected", {exact: false}); + expect(selectedDate.textContent).toBe("5"); + expect(onChange).toHaveBeenCalledTimes(1); + + triggerPress(getByLabelText("Friday, February 15, 2019, Last available date")); + + selectedDate = getByLabelText("Selected", {exact: false}); + expect(selectedDate.textContent).toBe("15"); + expect(onChange).toHaveBeenCalledTimes(2); + }); + + it("should support invalid state", () => { + let {getByRole} = render(); + + let cell = getByRole("button", { + name: "Friday, March 11, 2022 selected", + }) as HTMLButtonElement; + + expect(cell).toHaveAttribute("aria-invalid", "true"); + expect(cell.parentElement).toHaveAttribute("aria-selected", "true"); + expect(cell.parentElement).toHaveAttribute("aria-invalid", "true"); + + let description = cell.getAttribute("aria-describedby"); + + if (description) { + description = description + .split(" ") + .map((id) => document.getElementById(id)?.textContent) + .join(" "); + } + + expect(description).toBe("Selected date unavailable."); + }); + + it("should support custom error message", () => { + let {getByRole} = render( + , + ); + + let cell = getByRole("button", { + name: "Friday, March 11, 2022 selected", + }) as HTMLButtonElement; + + expect(cell).toHaveAttribute("aria-invalid", "true"); + expect(cell.parentElement).toHaveAttribute("aria-selected", "true"); + expect(cell.parentElement).toHaveAttribute("aria-invalid", "true"); + + let description = cell.getAttribute("aria-describedby"); + + if (description) { + description = description + .split(" ") + .map((id) => document.getElementById(id)?.textContent) + .join(" "); + } + + expect(description).toBe("This is a custom error message"); + }); + + it("should not show error message without isInvalid", () => { + let {getByRole} = render( + , + ); + + let cell = getByRole("button", { + name: "Friday, March 11, 2022 selected", + }) as HTMLButtonElement; + + expect(cell).not.toHaveAttribute("aria-invalid"); + expect(cell.parentElement).toHaveAttribute("aria-selected", "true"); + expect(cell.parentElement).not.toHaveAttribute("aria-invalid"); + + let description = cell.getAttribute("aria-describedby"); + + if (description) { + description = description + .split(" ") + .map((id) => document.getElementById(id)?.textContent) + .join(" "); + } + + expect(description).toBeNull(); + }); + + it("should automatically marks selection as invalid using isDateUnavailable", () => { + function Example() { + let {locale} = useLocale(); + + return ( + isWeekend(date, locale)} + /> + ); + } + + let {getByRole} = render(); + + let cell = getByRole("button", {name: "Saturday, March 5, 2022 selected"}); + + expect(cell).toHaveAttribute("aria-invalid", "true"); + expect(cell.parentElement).toHaveAttribute("aria-selected", "true"); + expect(cell.parentElement).toHaveAttribute("aria-invalid", "true"); + + let description = cell.getAttribute("aria-describedby"); + + if (description) { + description = description + .split(" ") + .map((id) => document.getElementById(id)?.textContent) + .join(" "); + } + + expect(description).toBe("Selected date unavailable."); + }); + }); +}); diff --git a/packages/components/calendar/__tests__/range-calendar.test.tsx b/packages/components/calendar/__tests__/range-calendar.test.tsx new file mode 100644 index 0000000000..c1ac49944e --- /dev/null +++ b/packages/components/calendar/__tests__/range-calendar.test.tsx @@ -0,0 +1,751 @@ +/* eslint-disable jsx-a11y/no-autofocus */ +import * as React from "react"; +import {render, act, fireEvent} from "@testing-library/react"; +import {CalendarDate} from "@internationalized/date"; +import {keyCodes, triggerPress, type} from "@nextui-org/test-utils"; + +import {RangeCalendar as RangeCalendarCalendarBase, RangeCalendarProps} from "../src"; + +let cellFormatter = new Intl.DateTimeFormat("en-US", { + weekday: "long", + day: "numeric", + month: "long", + year: "numeric", +}); + +/** + * Custom range-calendar to disable animations and avoid issues with react-motion and jest + */ +const RangeCalendar = React.forwardRef( + (props: RangeCalendarProps, ref: React.Ref) => { + return ; + }, +); + +RangeCalendar.displayName = "RangeCalendar"; + +describe("RangeCalendar", () => { + beforeAll(() => { + jest.useFakeTimers(); + }); + afterEach(() => { + act(() => { + jest.runAllTimers(); + }); + }); + + describe("Basics", () => { + it("should render correctly", () => { + const wrapper = render(); + + expect(() => wrapper.unmount()).not.toThrow(); + }); + + it("ref should be forwarded", () => { + const ref = React.createRef(); + + render(); + expect(ref.current).not.toBeNull(); + }); + + it("should render with defaultValue", () => { + let {getAllByLabelText, getByRole, getAllByRole} = render( + , + ); + + let heading = getByRole("heading"); + + expect(heading).toHaveTextContent("June 2019"); + + let gridCells = getAllByRole("gridcell").filter( + (cell) => cell.getAttribute("aria-disabled") !== "true", + ); + + expect(gridCells.length).toBe(30); + + let selectedDates = getAllByLabelText("Selected", {exact: false}); + let labels = [ + "Selected Range: Wednesday, June 5 to Monday, June 10, 2019, Wednesday, June 5, 2019 selected", + "Thursday, June 6, 2019 selected", + "Friday, June 7, 2019 selected", + "Saturday, June 8, 2019 selected", + "Sunday, June 9, 2019 selected", + "Selected Range: Wednesday, June 5 to Monday, June 10, 2019, Monday, June 10, 2019 selected", + ]; + + expect(selectedDates.length).toBe(6); + + let i = 0; + + for (let cell of selectedDates) { + expect(cell.parentElement).toHaveAttribute("role", "gridcell"); + expect(cell.parentElement).toHaveAttribute("aria-selected", "true"); + expect(cell).toHaveAttribute("aria-label", labels[i++]); + } + }); + + it("should render with value", () => { + let {getAllByLabelText, getByRole, getAllByRole} = render( + , + ); + + let heading = getByRole("heading"); + + expect(heading).toHaveTextContent("June 2019"); + + let gridCells = getAllByRole("gridcell").filter( + (cell) => cell.getAttribute("aria-disabled") !== "true", + ); + + expect(gridCells.length).toBe(30); + + let selectedDates = getAllByLabelText("Selected", {exact: false}); + let labels = [ + "Selected Range: Wednesday, June 5 to Monday, June 10, 2019, Wednesday, June 5, 2019 selected", + "Thursday, June 6, 2019 selected", + "Friday, June 7, 2019 selected", + "Saturday, June 8, 2019 selected", + "Sunday, June 9, 2019 selected", + "Selected Range: Wednesday, June 5 to Monday, June 10, 2019, Monday, June 10, 2019 selected", + ]; + + expect(selectedDates.length).toBe(6); + + let i = 0; + + for (let cell of selectedDates) { + expect(cell.parentElement).toHaveAttribute("role", "gridcell"); + expect(cell.parentElement).toHaveAttribute("aria-selected", "true"); + expect(cell).toHaveAttribute("aria-label", labels[i++]); + } + }); + + it("should focus the first selected date if autoFocus is set", () => { + let {getByRole, getAllByLabelText} = render( + , + ); + + let cells = getAllByLabelText("selected", {exact: false}); + let grid = getByRole("grid"); + + expect(cells[0].parentElement).toHaveAttribute("role", "gridcell"); + expect(cells[0].parentElement).toHaveAttribute("aria-selected", "true"); + expect(cells[0]).toHaveFocus(); + expect(grid).not.toHaveAttribute("aria-activedescendant"); + }); + + it("should show selected dates across multiple months", async () => { + let {getByRole, getByTestId, getAllByLabelText, getAllByRole} = render( + , + ); + + let heading = getByRole("heading"); + + expect(heading).toHaveTextContent("June 2019"); + + let gridCells = getAllByRole("gridcell").filter( + (cell) => cell.getAttribute("aria-disabled") !== "true", + ); + + expect(gridCells.length).toBe(30); + + let selected = getAllByLabelText("selected", {exact: false}).filter( + (cell) => cell.getAttribute("aria-disabled") !== "true", + ); + + expect(selected.length).toBe(11); + + let juneLabels = [ + "Selected Range: Thursday, June 20 to Wednesday, July 10, 2019, Thursday, June 20, 2019 selected", + "Friday, June 21, 2019 selected", + "Saturday, June 22, 2019 selected", + "Sunday, June 23, 2019 selected", + "Monday, June 24, 2019 selected", + "Tuesday, June 25, 2019 selected", + "Wednesday, June 26, 2019 selected", + "Thursday, June 27, 2019 selected", + "Friday, June 28, 2019 selected", + "Saturday, June 29, 2019 selected", + "Sunday, June 30, 2019 selected", + ]; + + let i = 0; + + for (let cell of selected) { + expect(cell.parentElement).toHaveAttribute("aria-selected", "true"); + expect(cell).toHaveAttribute("aria-label", juneLabels[i++]); + } + + let nextButton = getByTestId("next-button"); + + triggerPress(nextButton); + + selected = getAllByLabelText("selected", {exact: false}).filter( + (cell) => cell.getAttribute("aria-disabled") !== "true", + ); + + expect(selected.length).toBe(10); + + let julyLabels = [ + "Monday, July 1, 2019 selected", + "Tuesday, July 2, 2019 selected", + "Wednesday, July 3, 2019 selected", + "Thursday, July 4, 2019 selected", + "Friday, July 5, 2019 selected", + "Saturday, July 6, 2019 selected", + "Sunday, July 7, 2019 selected", + "Monday, July 8, 2019 selected", + "Tuesday, July 9, 2019 selected", + "Selected Range: Thursday, June 20 to Wednesday, July 10, 2019, Wednesday, July 10, 2019 selected", + ]; + + i = 0; + for (let cell of selected) { + expect(cell.parentElement).toHaveAttribute("aria-selected", "true"); + expect(cell).toHaveAttribute("aria-label", julyLabels[i++]); + } + + expect(heading).toHaveTextContent("July 2019"); + gridCells = getAllByRole("gridcell").filter( + (cell) => cell.getAttribute("aria-disabled") !== "true", + ); + expect(gridCells.length).toBe(31); + + expect(nextButton).toHaveFocus(); + + let prevButton = getByTestId("prev-button"); + + triggerPress(prevButton); + + expect(heading).toHaveTextContent("June 2019"); + gridCells = getAllByRole("gridcell").filter( + (cell) => cell.getAttribute("aria-disabled") !== "true", + ); + expect(gridCells.length).toBe(30); + + selected = getAllByLabelText("selected", {exact: false}).filter( + (cell) => cell.getAttribute("aria-disabled") !== "true", + ); + expect(selected.length).toBe(11); + i = 0; + for (let cell of selected) { + expect(cell.parentElement).toHaveAttribute("aria-selected", "true"); + expect(cell).toHaveAttribute("aria-label", juneLabels[i++]); + } + + expect(prevButton).toHaveFocus(); + }); + + it("should center the selected range if multiple months are visible", () => { + let {getAllByRole, getAllByLabelText} = render( + , + ); + + let grids = getAllByRole("grid"); + + expect(grids).toHaveLength(3); + + let cells = getAllByLabelText("selected", {exact: false}); + + expect(cells.every((cell) => grids[1].contains(cell))).toBe(true); + }); + + it("should constrain the visible region depending on the minValue", () => { + let {getAllByRole, getAllByLabelText} = render( + , + ); + + let grids = getAllByRole("grid"); + + expect(grids).toHaveLength(3); + + let cells = getAllByLabelText("selected", {exact: false}); + + expect(cells.every((cell) => grids[0].contains(cell))).toBe(true); + }); + + it("should start align the selected range if it would go out of view when centered", () => { + let {getAllByRole, getAllByLabelText} = render( + , + ); + + let grids = getAllByRole("grid"); + + expect(grids).toHaveLength(3); + + let cells = getAllByLabelText("selected", {exact: false}); + + expect(grids[0].contains(cells[0])).toBe(true); + }); + }); + + describe("Keyboard interactions", () => { + it("should add a range selection prompt to the focused cell", () => { + let {getByRole, getByLabelText} = render(); + + let grid = getByRole("grid"); + let cell = getByLabelText("today", {exact: false}); + + expect(grid).not.toHaveAttribute("aria-activedescendant"); + expect(cell).toHaveAttribute("aria-label", `Today, ${cellFormatter.format(new Date())}`); + expect(cell).toHaveAttribute("aria-describedby"); + + const cellDescBy = cell.getAttribute("aria-describedby"); + + if (cellDescBy) { + expect(document.getElementById(cellDescBy)).toHaveTextContent( + "Click to start selecting date range", + ); + } + + // enter selection mode + fireEvent.keyDown(grid, {key: "Enter", keyCode: keyCodes.Enter}); + expect(grid).not.toHaveAttribute("aria-activedescendant"); + expect(cell.parentElement).toHaveAttribute("aria-selected"); + expect(cell).toHaveAttribute( + "aria-label", + `Today, ${cellFormatter.format(new Date())} selected`, + ); + expect(cell).toHaveAttribute("aria-describedby"); + + const cellDescBySelected = cell.getAttribute("aria-describedby"); + + if (cellDescBySelected) { + expect(document.getElementById(cellDescBySelected)).toHaveTextContent( + "Click to finish selecting date range", + ); + } + }); + + it("should select a range with the keyboard (uncontrolled)", () => { + let onChange = jest.fn(); + + let {getAllByLabelText} = render( + , + ); + + let selectedDates = getAllByLabelText("Selected", {exact: false}); + + expect(selectedDates[0].textContent).toBe("5"); + expect(selectedDates[selectedDates.length - 1].textContent).toBe("10"); + + // Select a new date + type("ArrowLeft"); + + // Begin selecting + type("Enter"); + + // Auto advances by one day + selectedDates = getAllByLabelText("Selected", {exact: false}); + expect(selectedDates[0].textContent).toBe("4"); + expect(selectedDates[selectedDates.length - 1].textContent).toBe("5"); + expect(onChange).toHaveBeenCalledTimes(0); + + // Move focus + type("ArrowRight"); + type("ArrowRight"); + type("ArrowRight"); + type("ArrowRight"); + + selectedDates = getAllByLabelText("Selected", {exact: false}); + expect(selectedDates[0].textContent).toBe("4"); + expect(selectedDates[selectedDates.length - 1].textContent).toBe("9"); + expect(onChange).toHaveBeenCalledTimes(0); + + // End selection + type(" "); + selectedDates = getAllByLabelText("Selected", {exact: false}); + expect(selectedDates[0].textContent).toBe("4"); // uncontrolled + expect(selectedDates[selectedDates.length - 1].textContent).toBe("9"); + expect(onChange).toHaveBeenCalledTimes(1); + + let {start, end} = onChange.mock.calls[0][0]; + + expect(start).toEqual(new CalendarDate(2019, 6, 4)); + expect(end).toEqual(new CalendarDate(2019, 6, 9)); + }); + + it("select a range with the keyboard (controlled)", () => { + let onChange = jest.fn(); + let {getAllByLabelText} = render( + , + ); + + let selectedDates = getAllByLabelText("selected", {exact: false}); + + expect(selectedDates[0].textContent).toBe("5"); + expect(selectedDates[selectedDates.length - 1].textContent).toBe("10"); + + // Select a new date + type("ArrowLeft"); + + // Begin selecting + type("Enter"); + + // Auto advances by one day + selectedDates = getAllByLabelText("selected", {exact: false}); + expect(selectedDates[0].textContent).toBe("4"); + expect(selectedDates[selectedDates.length - 1].textContent).toBe("5"); + expect(onChange).toHaveBeenCalledTimes(0); + + // Move focus + type("ArrowRight"); + type("ArrowRight"); + type("ArrowRight"); + type("ArrowRight"); + + selectedDates = getAllByLabelText("selected", {exact: false}); + expect(selectedDates[0].textContent).toBe("4"); + expect(selectedDates[selectedDates.length - 1].textContent).toBe("9"); + expect(onChange).toHaveBeenCalledTimes(0); + + // End selection + type(" "); + selectedDates = getAllByLabelText("selected", {exact: false}); + expect(selectedDates[0].textContent).toBe("5"); // controlled + expect(selectedDates[selectedDates.length - 1].textContent).toBe("10"); + expect(onChange).toHaveBeenCalledTimes(1); + + let {start, end} = onChange.mock.calls[0][0]; + + expect(start).toEqual(new CalendarDate(2019, 6, 4)); + expect(end).toEqual(new CalendarDate(2019, 6, 9)); + }); + + it("should not enter selection mode with the keyboard if isReadOnly", () => { + let {getByRole, getByLabelText} = render(); + + let grid = getByRole("grid"); + let cell = getByLabelText("today", {exact: false}); + + expect(grid).not.toHaveAttribute("aria-activedescendant"); + expect(cell).toHaveAttribute("aria-label", `Today, ${cellFormatter.format(new Date())}`); + expect(document.activeElement).toBe(cell); + + // try to enter selection mode + fireEvent.keyDown(grid, {key: "Enter", keyCode: keyCodes.Enter}); + expect(grid).not.toHaveAttribute("aria-activedescendant"); + expect(cell.parentElement).not.toHaveAttribute("aria-selected"); + expect(cell).toHaveAttribute("aria-label", `Today, ${cellFormatter.format(new Date())}`); + expect(document.activeElement).toBe(cell); + }); + + it("should select a range with the mouse (uncontrolled)", () => { + let onChange = jest.fn(); + let {getAllByLabelText, getByText} = render( + , + ); + + triggerPress(getByText("17")); + + let selectedDates = getAllByLabelText("selected", {exact: false}); + + expect(selectedDates[0].textContent).toBe("17"); + expect(selectedDates[selectedDates.length - 1].textContent).toBe("17"); + expect(onChange).toHaveBeenCalledTimes(0); + + // hovering updates the highlighted dates + // @ts-ignore + fireEvent.pointerEnter(getByText("10").parentElement); + selectedDates = getAllByLabelText("selected", {exact: false}); + expect(selectedDates[0].textContent).toBe("10"); + expect(selectedDates[selectedDates.length - 1].textContent).toBe("17"); + expect(onChange).toHaveBeenCalledTimes(0); + + // @ts-ignore + fireEvent.pointerEnter(getByText("7").parentElement); + triggerPress(getByText("7")); + + selectedDates = getAllByLabelText("selected", {exact: false}); + expect(selectedDates[0].textContent).toBe("7"); // uncontrolled + expect(selectedDates[selectedDates.length - 1].textContent).toBe("17"); + expect(onChange).toHaveBeenCalledTimes(1); + + let {start, end} = onChange.mock.calls[0][0]; + + expect(start).toEqual(new CalendarDate(2019, 6, 7)); + expect(end).toEqual(new CalendarDate(2019, 6, 17)); + }); + + it("should select a range with the mouse (controlled)", () => { + let onChange = jest.fn(); + let {getAllByLabelText, getByText} = render( + , + ); + + triggerPress(getByText("17")); + + let selectedDates = getAllByLabelText("selected", {exact: false}); + + expect(selectedDates[0].textContent).toBe("17"); + expect(selectedDates[selectedDates.length - 1].textContent).toBe("17"); + expect(onChange).toHaveBeenCalledTimes(0); + + // hovering updates the highlighted dates + fireEvent.pointerEnter(getByText("10")); + selectedDates = getAllByLabelText("selected", {exact: false}); + expect(selectedDates[0].textContent).toBe("10"); + expect(selectedDates[selectedDates.length - 1].textContent).toBe("17"); + expect(onChange).toHaveBeenCalledTimes(0); + + fireEvent.pointerEnter(getByText("7")); + triggerPress(getByText("7")); + + selectedDates = getAllByLabelText("selected", {exact: false}); + expect(selectedDates[0].textContent).toBe("5"); // controlled + expect(selectedDates[selectedDates.length - 1].textContent).toBe("10"); + expect(onChange).toHaveBeenCalledTimes(1); + + let {start, end} = onChange.mock.calls[0][0]; + + expect(start).toEqual(new CalendarDate(2019, 6, 7)); + expect(end).toEqual(new CalendarDate(2019, 6, 17)); + }); + + it("selects by dragging with the mouse", () => { + let onChange = jest.fn(); + let {getAllByLabelText, getByText} = render( + , + ); + + fireEvent.mouseDown(getByText("17"), {detail: 1}); + + let selectedDates = getAllByLabelText("selected", {exact: false}); + + expect(selectedDates[0].textContent).toBe("17"); + expect(selectedDates[selectedDates.length - 1].textContent).toBe("17"); + expect(onChange).toHaveBeenCalledTimes(0); + + // dragging updates the highlighted dates + fireEvent.pointerEnter(getByText("18")); + selectedDates = getAllByLabelText("selected", {exact: false}); + expect(selectedDates[0].textContent).toBe("17"); + expect(selectedDates[selectedDates.length - 1].textContent).toBe("18"); + expect(onChange).toHaveBeenCalledTimes(0); + + fireEvent.pointerEnter(getByText("23")); + selectedDates = getAllByLabelText("selected", {exact: false}); + expect(selectedDates[0].textContent).toBe("17"); + expect(selectedDates[selectedDates.length - 1].textContent).toBe("23"); + expect(onChange).toHaveBeenCalledTimes(0); + + fireEvent.mouseUp(getByText("23"), {detail: 1}); + + selectedDates = getAllByLabelText("selected", {exact: false}); + expect(selectedDates[0].textContent).toBe("17"); + expect(selectedDates[selectedDates.length - 1].textContent).toBe("23"); + expect(onChange).toHaveBeenCalledTimes(1); + + let {start, end} = onChange.mock.calls[0][0]; + + expect(start).toEqual(new CalendarDate(2019, 6, 17)); + expect(end).toEqual(new CalendarDate(2019, 6, 23)); + }); + + it("allows dragging the start of the highlighted range to modify it", () => { + let onChange = jest.fn(); + let {getAllByLabelText, getByText} = render( + , + ); + + fireEvent.mouseDown(getByText("10"), {detail: 1}); + + // mouse down on a range end should not reset it + let selectedDates = getAllByLabelText("selected", {exact: false}); + + expect(selectedDates[0].textContent).toBe("10"); + expect(selectedDates[selectedDates.length - 1].textContent).toBe("20"); + expect(onChange).toHaveBeenCalledTimes(0); + + // dragging updates the highlighted dates + fireEvent.pointerEnter(getByText("11")); + selectedDates = getAllByLabelText("selected", {exact: false}); + expect(selectedDates[0].textContent).toBe("11"); + expect(selectedDates[selectedDates.length - 1].textContent).toBe("20"); + expect(onChange).toHaveBeenCalledTimes(0); + + fireEvent.pointerEnter(getByText("8")); + selectedDates = getAllByLabelText("selected", {exact: false}); + expect(selectedDates[0].textContent).toBe("8"); + expect(selectedDates[selectedDates.length - 1].textContent).toBe("20"); + expect(onChange).toHaveBeenCalledTimes(0); + + fireEvent.mouseUp(getByText("8"), {detail: 1}); + + selectedDates = getAllByLabelText("selected", {exact: false}); + expect(selectedDates[0].textContent).toBe("8"); + expect(selectedDates[selectedDates.length - 1].textContent).toBe("20"); + expect(onChange).toHaveBeenCalledTimes(1); + + let {start, end} = onChange.mock.calls[0][0]; + + expect(start).toEqual(new CalendarDate(2019, 6, 8)); + expect(end).toEqual(new CalendarDate(2019, 6, 20)); + }); + + it("allows dragging the end of the highlighted range to modify it", () => { + let onChange = jest.fn(); + let {getAllByLabelText, getByText} = render( + , + ); + + fireEvent.mouseDown(getByText("20"), {detail: 1}); + + // mouse down on a range end should not reset it + let selectedDates = getAllByLabelText("selected", {exact: false}); + + expect(selectedDates[0].textContent).toBe("10"); + expect(selectedDates[selectedDates.length - 1].textContent).toBe("20"); + expect(onChange).toHaveBeenCalledTimes(0); + + // dragging updates the highlighted dates + fireEvent.pointerEnter(getByText("21")); + selectedDates = getAllByLabelText("selected", {exact: false}); + expect(selectedDates[0].textContent).toBe("10"); + expect(selectedDates[selectedDates.length - 1].textContent).toBe("21"); + expect(onChange).toHaveBeenCalledTimes(0); + + fireEvent.pointerEnter(getByText("19")); + selectedDates = getAllByLabelText("selected", {exact: false}); + expect(selectedDates[0].textContent).toBe("10"); + expect(selectedDates[selectedDates.length - 1].textContent).toBe("19"); + expect(onChange).toHaveBeenCalledTimes(0); + + fireEvent.mouseUp(getByText("19"), {detail: 1}); + + selectedDates = getAllByLabelText("selected", {exact: false}); + expect(selectedDates[0].textContent).toBe("10"); + expect(selectedDates[selectedDates.length - 1].textContent).toBe("19"); + expect(onChange).toHaveBeenCalledTimes(1); + + let {start, end} = onChange.mock.calls[0][0]; + + expect(start).toEqual(new CalendarDate(2019, 6, 10)); + expect(end).toEqual(new CalendarDate(2019, 6, 19)); + }); + + it("releasing drag outside calendar commits it", () => { + let onChange = jest.fn(); + let {getAllByLabelText, getByText} = render( + , + ); + + fireEvent.mouseDown(getByText("22"), {detail: 1}); + + let selectedDates = getAllByLabelText("selected", {exact: false}); + + expect(selectedDates[0].textContent).toBe("22"); + expect(selectedDates[selectedDates.length - 1].textContent).toBe("22"); + expect(onChange).toHaveBeenCalledTimes(0); + + // dragging updates the highlighted dates + fireEvent.pointerEnter(getByText("25")); + selectedDates = getAllByLabelText("selected", {exact: false}); + expect(selectedDates[0].textContent).toBe("22"); + expect(selectedDates[selectedDates.length - 1].textContent).toBe("25"); + expect(onChange).toHaveBeenCalledTimes(0); + + fireEvent.pointerUp(document.body); + + selectedDates = getAllByLabelText("selected", {exact: false}); + expect(selectedDates[0].textContent).toBe("22"); + expect(selectedDates[selectedDates.length - 1].textContent).toBe("25"); + expect(onChange).toHaveBeenCalledTimes(1); + + let {start, end} = onChange.mock.calls[0][0]; + + expect(start).toEqual(new CalendarDate(2019, 6, 22)); + expect(end).toEqual(new CalendarDate(2019, 6, 25)); + }); + + it("releasing drag outside calendar commits it", () => { + let onChange = jest.fn(); + let {getAllByLabelText, getByText} = render( + , + ); + + fireEvent.mouseDown(getByText("22"), {detail: 1}); + + let selectedDates = getAllByLabelText("selected", {exact: false}); + + expect(selectedDates[0].textContent).toBe("22"); + expect(selectedDates[selectedDates.length - 1].textContent).toBe("22"); + expect(onChange).toHaveBeenCalledTimes(0); + + // dragging updates the highlighted dates + fireEvent.pointerEnter(getByText("25")); + selectedDates = getAllByLabelText("selected", {exact: false}); + expect(selectedDates[0].textContent).toBe("22"); + expect(selectedDates[selectedDates.length - 1].textContent).toBe("25"); + expect(onChange).toHaveBeenCalledTimes(0); + + fireEvent.pointerUp(document.body); + + selectedDates = getAllByLabelText("selected", {exact: false}); + expect(selectedDates[0].textContent).toBe("22"); + expect(selectedDates[selectedDates.length - 1].textContent).toBe("25"); + expect(onChange).toHaveBeenCalledTimes(1); + + let {start, end} = onChange.mock.calls[0][0]; + + expect(start).toEqual(new CalendarDate(2019, 6, 22)); + expect(end).toEqual(new CalendarDate(2019, 6, 25)); + }); + }); +}); diff --git a/packages/components/calendar/package.json b/packages/components/calendar/package.json new file mode 100644 index 0000000000..2e0410520a --- /dev/null +++ b/packages/components/calendar/package.json @@ -0,0 +1,76 @@ +{ + "name": "@nextui-org/calendar", + "version": "2.0.3", + "description": "A calendar displays one or more date grids and allows users to select a single date.", + "keywords": [ + "calendar" + ], + "author": "Junior Garcia ", + "homepage": "https://nextui.org", + "license": "MIT", + "main": "src/index.ts", + "sideEffects": false, + "files": [ + "dist" + ], + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/nextui-org/nextui.git", + "directory": "packages/components/calendar" + }, + "bugs": { + "url": "https://github.com/nextui-org/nextui/issues" + }, + "scripts": { + "build": "tsup src --dts", + "build:fast": "tsup src", + "dev": "pnpm build:fast --watch", + "clean": "rimraf dist .turbo", + "typecheck": "tsc --noEmit", + "prepack": "clean-package", + "postpack": "clean-package restore" + }, + "peerDependencies": { + "@nextui-org/system": ">=2.0.0", + "@nextui-org/theme": ">=2.0.0", + "react": ">=18", + "react-dom": ">=18" + }, + "dependencies": { + "@nextui-org/react-utils": "workspace:*", + "@nextui-org/shared-utils": "workspace:*", + "@nextui-org/shared-icons": "workspace:*", + "@nextui-org/framer-utils": "workspace:*", + "@nextui-org/use-aria-button": "workspace:*", + "@nextui-org/button": "workspace:*", + "lodash.debounce": "^4.0.8", + "@internationalized/date": "^3.5.2", + "@react-aria/calendar": "3.5.1", + "@react-aria/focus": "^3.14.3", + "@react-aria/i18n": "^3.8.4", + "@react-stately/calendar": "3.4.1", + "@react-types/button": "^3.9.0", + "@react-aria/visually-hidden": "^3.8.6", + "@react-aria/utils": "^3.21.1", + "@react-stately/utils": "^3.8.0", + "@react-types/calendar": "3.4.1", + "@react-aria/interactions": "^3.19.1", + "@react-types/shared": "3.21.0", + "scroll-into-view-if-needed": "3.0.10", + "@types/lodash.debounce": "^4.0.7" + }, + "devDependencies": { + "@nextui-org/system": "workspace:*", + "@nextui-org/theme": "workspace:*", + "@nextui-org/radio": "workspace:*", + "@nextui-org/test-utils": "workspace:*", + "framer-motion": "^10.16.4", + "clean-package": "2.2.0", + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "clean-package": "../../../clean-package.config.json" +} diff --git a/packages/components/calendar/src/calendar-base.tsx b/packages/components/calendar/src/calendar-base.tsx new file mode 100644 index 0000000000..0d5def77b1 --- /dev/null +++ b/packages/components/calendar/src/calendar-base.tsx @@ -0,0 +1,193 @@ +import type {AriaButtonProps} from "@react-types/button"; +import type {As, HTMLNextUIProps} from "@nextui-org/system"; +import type {ButtonProps} from "@nextui-org/button"; +import type {HTMLAttributes, ReactNode, RefObject} from "react"; + +import {Fragment} from "react"; +import {useState} from "react"; +import {useLocale} from "@react-aria/i18n"; +import {VisuallyHidden} from "@react-aria/visually-hidden"; +import {Button} from "@nextui-org/button"; +import {chain, mergeProps} from "@react-aria/utils"; +import {AnimatePresence, LazyMotion, domAnimation, MotionConfig} from "framer-motion"; +import {ResizablePanel} from "@nextui-org/framer-utils"; + +import {ChevronLeftIcon} from "./chevron-left"; +import {ChevronRightIcon} from "./chevron-right"; +import {CalendarMonth} from "./calendar-month"; +import {transition} from "./calendar-transitions"; +import {CalendarHeader} from "./calendar-header"; +import {CalendarPicker} from "./calendar-picker"; +import {useCalendarContext} from "./calendar-context"; + +export interface CalendarBaseProps extends HTMLNextUIProps<"div"> { + Component?: As; + showHelper?: boolean; + topContent?: ReactNode; + bottomContent?: ReactNode; + calendarProps: HTMLAttributes; + nextButtonProps: AriaButtonProps; + prevButtonProps: AriaButtonProps; + buttonPickerProps?: ButtonProps; + errorMessageProps: HTMLAttributes; + calendarRef: RefObject; + errorMessage?: ReactNode; +} + +export function CalendarBase(props: CalendarBaseProps) { + const { + Component = "div", + showHelper, + topContent, + bottomContent, + calendarProps, + nextButtonProps, + prevButtonProps, + buttonPickerProps, + errorMessageProps, + calendarRef: ref, + errorMessage, + ...otherProps + } = props; + + const {state, slots, visibleMonths, showMonthAndYearPickers, disableAnimation, classNames} = + useCalendarContext(); + + const [direction, setDirection] = useState(0); + + const {direction: rtlDirection} = useLocale(); + + const currentMonth = state.visibleRange.start; + + const headers = []; + const calendars = []; + + for (let i = 0; i < visibleMonths; i++) { + let d = currentMonth.add({months: i}); + + headers.push( + + {i === 0 && ( + + )} + + {i === visibleMonths - 1 && ( + + )} + , + ); + + const calendarMonthContent = ( + + ); + + calendars.push( + showMonthAndYearPickers ? ( + + {calendarMonthContent} + + + ) : ( + calendarMonthContent + ), + ); + } + + const calendarContent = ( + <> +
+ {headers} +
+
+ {calendars} +
+ + ); + + return ( + + {topContent} + {/* Add a screen reader only description of the entire visible range rather than + * a separate heading above each month grid. This is placed first in the DOM order + * so that it is the first thing a touch screen reader user encounters. + * In addition, VoiceOver on iOS does not announce the aria-label of the grid + * elements, so the aria-label of the Calendar is included here as well. */} + +

{calendarProps["aria-label"]}

+
+ {disableAnimation ? ( +
+ {calendarContent} +
+ ) : ( + + + <> + + {calendarContent} + + + + + )} + {/* For touch screen readers, add a visually hidden next button after the month grid + * so it's easy to navigate after reaching the end without going all the way + * back to the start of the month. */} + +
+ + {formattedDate} + +
+ ), + )} +
+ + + {weekDays.map((day, index) => ( + + ))} + + + {disableAnimation ? ( + + {bodyContent} + + ) : ( + + {bodyContent} + + )} +
+ {day} +
+ ); +} diff --git a/packages/components/calendar/src/calendar-picker-item.tsx b/packages/components/calendar/src/calendar-picker-item.tsx new file mode 100644 index 0000000000..0708e7b568 --- /dev/null +++ b/packages/components/calendar/src/calendar-picker-item.tsx @@ -0,0 +1,57 @@ +import type {AriaButtonProps} from "@nextui-org/use-aria-button"; + +import {HTMLNextUIProps} from "@nextui-org/system"; +import {useAriaButton} from "@nextui-org/use-aria-button"; +import {useHover} from "@react-aria/interactions"; +import {useFocusRing} from "@react-aria/focus"; +import {forwardRef} from "react"; +import {useDOMRef, filterDOMProps} from "@nextui-org/react-utils"; +import {dataAttr} from "@nextui-org/shared-utils"; +import {mergeProps} from "@react-aria/utils"; + +const CalendarPickerItem = forwardRef< + HTMLButtonElement, + HTMLNextUIProps<"button"> & AriaButtonProps +>(({children, autoFocus, isDisabled, onKeyDown, ...otherProps}, ref) => { + const domRef = useDOMRef(ref); + + const {buttonProps: ariaButtonProps, isPressed} = useAriaButton( + { + elementType: "button", + isDisabled, + onKeyDown, + ...otherProps, + } as AriaButtonProps, + domRef, + ); + + const {isFocusVisible, isFocused, focusProps} = useFocusRing({ + autoFocus, + }); + + const {isHovered, hoverProps} = useHover({isDisabled}); + + return ( + + ); +}); + +CalendarPickerItem.displayName = "CalendarPickerItem"; + +export {CalendarPickerItem}; diff --git a/packages/components/calendar/src/calendar-picker.tsx b/packages/components/calendar/src/calendar-picker.tsx new file mode 100644 index 0000000000..575b665f77 --- /dev/null +++ b/packages/components/calendar/src/calendar-picker.tsx @@ -0,0 +1,121 @@ +import type {CalendarPickerProps} from "./use-calendar-picker"; + +import {HTMLNextUIProps} from "@nextui-org/system"; +import {useCallback} from "react"; + +import {CalendarPickerItem} from "./calendar-picker-item"; +import {useCalendarPicker} from "./use-calendar-picker"; + +export type PickerValue = { + value: string; + label: string; +}; + +const EMPTY_ITEMS_OFFSET = 3; + +export function CalendarPicker(props: CalendarPickerProps) { + const { + state, + slots, + months, + years, + highlightRef, + monthsListRef, + yearsListRef, + classNames, + getItemRef, + isHeaderExpanded, + onPickerItemPressed, + onPickerItemKeyDown, + } = useCalendarPicker(props); + + const EmptyItem = useCallback( + (props: HTMLNextUIProps<"div">) => ( + + ), + [slots, classNames?.pickerItem], + ); + + const PickerItemWrapper = useCallback( + ({children}: HTMLNextUIProps<"div">) => ( + <> + {Array.from({length: EMPTY_ITEMS_OFFSET}, (_, i) => ( + + ))} + {children} + {Array.from({length: EMPTY_ITEMS_OFFSET}, (_, i) => ( + + ))} + + ), + [EmptyItem], + ); + + return ( +
+
+
+ + {months.map((month) => ( + getItemRef(node, month.value, "months")} + className={slots?.pickerItem({class: classNames?.pickerItem})} + data-value={month.value} + tabIndex={!isHeaderExpanded || state.focusedDate?.month !== month.value ? -1 : 0} + onKeyDown={(e) => onPickerItemKeyDown(e, month.value, "months")} + onPress={(e) => onPickerItemPressed(e, "months")} + > + {month.label} + + ))} + +
+
+ + {years.map((year) => ( + getItemRef(node, year.value, "years")} + className={slots?.pickerItem({class: classNames?.pickerItem})} + data-value={year.value} + tabIndex={!isHeaderExpanded || state.focusedDate?.year !== year.value ? -1 : 0} + onKeyDown={(e) => onPickerItemKeyDown(e, year.value, "years")} + onPress={(e) => onPickerItemPressed(e, "years")} + > + {year.label} + + ))} + +
+
+ ); +} diff --git a/packages/components/calendar/src/calendar-transitions.ts b/packages/components/calendar/src/calendar-transitions.ts new file mode 100644 index 0000000000..a827cf2c33 --- /dev/null +++ b/packages/components/calendar/src/calendar-transitions.ts @@ -0,0 +1,19 @@ +import {Variants} from "framer-motion"; + +export const transition = { + type: "spring", + bounce: 0, + duration: 0.3, +}; + +export const slideVariants: Variants = { + enter: (direction: number) => ({ + x: `${direction * 100}%`, + }), + center: { + x: "0%", + }, + exit: (direction: number) => ({ + x: `${direction * -100}%`, + }), +}; diff --git a/packages/components/calendar/src/calendar.tsx b/packages/components/calendar/src/calendar.tsx new file mode 100644 index 0000000000..6b1eee3f76 --- /dev/null +++ b/packages/components/calendar/src/calendar.tsx @@ -0,0 +1,29 @@ +import type {DateValue} from "@internationalized/date"; +import type {ForwardedRef, ReactElement, Ref} from "react"; + +import {forwardRef} from "@nextui-org/system"; + +import {UseCalendarProps, useCalendar} from "./use-calendar"; +import {CalendarProvider} from "./calendar-context"; +import {CalendarBase} from "./calendar-base"; + +interface Props extends Omit, "isHeaderWrapperExpanded"> {} + +function Calendar(props: Props, ref: ForwardedRef) { + const {context, getBaseCalendarProps} = useCalendar({...props, ref}); + + return ( + + + + ); +} + +Calendar.displayName = "NextUI.Calendar"; + +export type CalendarProps = Props & {ref?: Ref}; + +// forwardRef doesn't support generic parameters, so cast the result to the correct type +export default forwardRef(Calendar) as ( + props: CalendarProps, +) => ReactElement; diff --git a/packages/components/calendar/src/chevron-down.tsx b/packages/components/calendar/src/chevron-down.tsx new file mode 100644 index 0000000000..3abbe826ba --- /dev/null +++ b/packages/components/calendar/src/chevron-down.tsx @@ -0,0 +1,22 @@ +import type {IconSvgProps} from "@nextui-org/shared-icons"; + +export const ChevronDownIcon = (props: IconSvgProps) => ( + +); diff --git a/packages/components/calendar/src/chevron-left.tsx b/packages/components/calendar/src/chevron-left.tsx new file mode 100644 index 0000000000..9722d6f6da --- /dev/null +++ b/packages/components/calendar/src/chevron-left.tsx @@ -0,0 +1,22 @@ +import type {IconSvgProps} from "@nextui-org/shared-icons"; + +export const ChevronLeftIcon = (props: IconSvgProps) => ( + +); diff --git a/packages/components/calendar/src/chevron-right.tsx b/packages/components/calendar/src/chevron-right.tsx new file mode 100644 index 0000000000..c454e52c51 --- /dev/null +++ b/packages/components/calendar/src/chevron-right.tsx @@ -0,0 +1,22 @@ +import type {IconSvgProps} from "@nextui-org/shared-icons"; + +export const ChevronRightIcon = (props: IconSvgProps) => ( + +); diff --git a/packages/components/calendar/src/index.ts b/packages/components/calendar/src/index.ts new file mode 100644 index 0000000000..f34634627c --- /dev/null +++ b/packages/components/calendar/src/index.ts @@ -0,0 +1,19 @@ +import Calendar from "./calendar"; +import RangeCalendar from "./range-calendar"; + +// export types +export type {CalendarProps} from "./calendar"; +export type {RangeCalendarProps} from "./range-calendar"; +export type {CalendarDate} from "@internationalized/date"; +export type {DateValue} from "@react-types/calendar"; +export type {RangeValue} from "@react-types/shared"; + +// export hooks +export {useCalendar} from "./use-calendar"; +export {useRangeCalendar} from "./use-range-calendar"; + +// export context +export {CalendarProvider, useCalendarContext} from "./calendar-context"; + +// export component +export {Calendar, RangeCalendar}; diff --git a/packages/components/calendar/src/range-calendar.tsx b/packages/components/calendar/src/range-calendar.tsx new file mode 100644 index 0000000000..a245f012dc --- /dev/null +++ b/packages/components/calendar/src/range-calendar.tsx @@ -0,0 +1,38 @@ +import type {DateValue} from "@internationalized/date"; +import type {ForwardedRef, ReactElement, Ref} from "react"; + +import {forwardRef} from "@nextui-org/system"; + +import {UseRangeCalendarProps, useRangeCalendar} from "./use-range-calendar"; +import {CalendarProvider} from "./calendar-context"; +import {CalendarBase} from "./calendar-base"; + +interface Props + extends Omit< + UseRangeCalendarProps, + | "isHeaderExpanded" + | "onHeaderExpandedChange" + | "isHeaderWrapperExpanded" + | "showMonthAndYearPickers" + > {} + +function RangeCalendar(props: Props, ref: ForwardedRef) { + const {context, getBaseCalendarProps} = useRangeCalendar({...props, ref}); + + return ( + + + + ); +} + +RangeCalendar.displayName = "NextUI.RangeCalendar"; + +export type RangeCalendarProps = Props & { + ref?: Ref; +}; + +// forwardRef doesn't support generic parameters, so cast the result to the correct type +export default forwardRef(RangeCalendar) as ( + props: RangeCalendarProps, +) => ReactElement; diff --git a/packages/components/calendar/src/use-calendar-base.ts b/packages/components/calendar/src/use-calendar-base.ts new file mode 100644 index 0000000000..9ec4201a10 --- /dev/null +++ b/packages/components/calendar/src/use-calendar-base.ts @@ -0,0 +1,333 @@ +import type {CalendarReturnType, CalendarVariantProps} from "@nextui-org/theme"; +import type {CalendarPropsBase as AriaCalendarPropsBase} from "@react-types/calendar"; +import type {CalendarSlots, SlotsToClasses} from "@nextui-org/theme"; +import type {AriaCalendarGridProps} from "@react-aria/calendar"; +import type {AriaButtonProps} from "@react-types/button"; +import type {HTMLNextUIProps, PropGetter} from "@nextui-org/system"; +import type {ButtonProps} from "@nextui-org/button"; +import type {SupportedCalendars} from "@nextui-org/system"; +import type {CalendarState, RangeCalendarState} from "@react-stately/calendar"; +import type {RefObject, ReactNode} from "react"; + +import {Calendar, CalendarDate} from "@internationalized/date"; +import {mapPropsVariants} from "@nextui-org/system"; +import {useCallback, useMemo} from "react"; +import {calendar} from "@nextui-org/theme"; +import {useControlledState} from "@react-stately/utils"; +import {ReactRef, useDOMRef} from "@nextui-org/react-utils"; +import {useLocale} from "@react-aria/i18n"; +import {clamp, dataAttr, objectToDeps} from "@nextui-org/shared-utils"; +import {mergeProps} from "@react-aria/utils"; +import {useProviderContext} from "@nextui-org/system"; + +type NextUIBaseProps = Omit, keyof AriaCalendarPropsBase | "onChange">; + +interface Props extends NextUIBaseProps { + /** + * Ref to the DOM node. + */ + ref?: ReactRef; + /** + * Custom content to be included in the top of the calendar. + */ + topContent?: ReactNode; + /** + * Custom content to be included in the bottom of the calendar. + */ + bottomContent?: ReactNode; + /** + * The number of months to display at once. Up to 3 months are supported. + * Passing a number greater than 1 will disable the `showMonthAndYearPickers` prop. + * + * @default 1 + */ + visibleMonths?: number; + /** + * The width to be applied to the calendar component. This value is multiplied by the number + * of visible months to determine the total width of the calendar. + * + * @default 256 + */ + calendarWidth?: number | string; + /** + * Props for the navigation button, prev button and next button. + */ + navButtonProps?: ButtonProps; + /** + * Props for the previous button. + */ + prevButtonProps?: ButtonProps; + /** + * Props for the next button. + */ + nextButtonProps?: ButtonProps; + /** + * Whether to show the description or error message. + * @default true + */ + showHelper?: boolean; + /** + * Whether the calendar header is expanded. This is only available if the `showMonthAndYearPickers` prop is set to `true`. + * @default false + */ + isHeaderExpanded?: boolean; + /** + * Whether the calendar header should be expanded by default.This is only available if the `showMonthAndYearPickers` prop is set to `true`. + * @default false + */ + isHeaderDefaultExpanded?: boolean; + /** + * The event handler for the calendar header expanded state. This is only available if the `showMonthAndYearPickers` prop is set to `true`. + * @param isExpanded boolean + * @returns void + */ + onHeaderExpandedChange?: (isExpanded: boolean) => void; + /** + * This function helps to reduce the bundle size by providing a custom calendar system. + * + * In the example above, the createCalendar function from the `@internationalized/date` package + * is passed to the useCalendarState hook. This function receives a calendar identifier string, + * and provides Calendar instances to React Stately, which are used to implement date manipulation. + * + * By default, this includes all calendar systems supported by @internationalized/date. However, + * if your application supports a more limited set of regions, or you know you will only be picking dates + * in a certain calendar system, you can reduce your bundle size by providing your own implementation + * of `createCalendar` that includes a subset of these Calendar implementations. + * + * For example, if your application only supports Gregorian dates, you could implement a `createCalendar` + * function like this: + * + * @example + * + * import {GregorianCalendar} from '@internationalized/date'; + * + * function createCalendar(identifier) { + * switch (identifier) { + * case 'gregory': + * return new GregorianCalendar(); + * default: + * throw new Error(`Unsupported calendar ${identifier}`); + * } + * } + * + * This way, only GregorianCalendar is imported, and the other calendar implementations can be tree-shaken. + * + * You can also use the NextUIProvider to provide the createCalendar function to all nested components. + * + * @default all calendars + */ + createCalendar?: (calendar: SupportedCalendars) => Calendar | null; + /** + * The style of weekday names to display in the calendar grid header, + * e.g. single letter, abbreviation, or full day name. + * @default "narrow" + */ + weekdayStyle?: AriaCalendarGridProps["weekdayStyle"]; + /** + * Classname or List of classes to change the classNames of the element. + * if `className` is passed, it will be added to the base slot. + * + * @example + * ```ts + * + * Component: Calendar, RangeCalendar + * + * + * ``` + */ + classNames?: SlotsToClasses; +} + +export type UseCalendarBasePropsComplete = Props & CalendarVariantProps & AriaCalendarPropsBase; + +// Omit internal props +export type UseCalendarBaseProps = Omit; + +export type ContextType = { + state: T; + visibleMonths: number; + headerRef?: RefObject; + slots?: CalendarReturnType; + weekdayStyle?: AriaCalendarGridProps["weekdayStyle"]; + isHeaderExpanded?: boolean; + showMonthAndYearPickers?: boolean; + setIsHeaderExpanded?: (isExpanded: boolean) => void; + classNames?: SlotsToClasses; + disableAnimation?: boolean; +}; + +export function useCalendarBase(originalProps: UseCalendarBasePropsComplete) { + const [props, variantProps] = mapPropsVariants(originalProps, calendar.variantKeys); + + const providerContext = useProviderContext(); + + const { + ref, + as, + children, + className, + topContent, + bottomContent, + showHelper = true, + calendarWidth = 256, + visibleMonths: visibleMonthsProp = 1, + weekdayStyle = "narrow", + navButtonProps = {}, + isHeaderExpanded: isHeaderExpandedProp, + isHeaderDefaultExpanded, + onHeaderExpandedChange = () => {}, + minValue = providerContext?.defaultDates?.minDate ?? new CalendarDate(1900, 1, 1), + maxValue = providerContext?.defaultDates?.maxDate ?? new CalendarDate(2099, 12, 31), + createCalendar: createCalendarProp = providerContext?.createCalendar ?? null, + prevButtonProps: prevButtonPropsProp, + nextButtonProps: nextButtonPropsProp, + errorMessage, + classNames, + ...otherProps + } = props; + + const Component = as || "div"; + const visibleMonths = clamp(visibleMonthsProp, 1, 3); + + /** + * Determines whether to show the month and year pickers. + * The pickers are shown if `showMonthAndYearPickers` is true, + * there is only one visible month (`visibleMonths === 1`), + * and it's not a range calendar (`!isRange`). + */ + const showMonthAndYearPickers = + originalProps.showMonthAndYearPickers && visibleMonths === 1 && !originalProps?.isRange; + + const domRef = useDOMRef(ref); + + const handleHeaderExpandedChange = useCallback( + (isExpanded: boolean | undefined) => { + onHeaderExpandedChange(isExpanded || false); + }, + [onHeaderExpandedChange], + ); + + const [isHeaderExpanded, setIsHeaderExpanded] = useControlledState( + isHeaderExpandedProp, + isHeaderDefaultExpanded ?? false, + handleHeaderExpandedChange, + ); + + const visibleDuration = useMemo(() => ({months: visibleMonths}), [visibleMonths]); + const hasMultipleMonths = visibleMonths > 1; + const shouldFilterDOMProps = typeof Component === "string"; + + const {locale} = useLocale(); + + const slots = useMemo( + () => + calendar({ + ...variantProps, + showMonthAndYearPickers, + isRange: !!originalProps.isRange, + isHeaderWrapperExpanded: isHeaderExpanded, + className, + }), + [objectToDeps(variantProps), showMonthAndYearPickers, isHeaderExpanded, className], + ); + + const disableAnimation = originalProps.disableAnimation ?? false; + + const commonButtonProps: ButtonProps = { + size: "sm", + variant: "light", + radius: "full", + isIconOnly: true, + disableAnimation, + ...navButtonProps, + }; + + const baseProps = { + "data-slot": "base", + "data-has-multiple-months": dataAttr(hasMultipleMonths), + style: { + // @ts-ignore + "--visible-months": visibleMonths, + "--calendar-width": calendarWidth, + } as React.CSSProperties, + }; + + const getPrevButtonProps = (props = {}) => { + return { + "data-slot": "prev-button", + tabIndex: isHeaderExpanded ? -1 : 0, + className: slots.prevButton({class: classNames?.prevButton}), + ...mergeProps(commonButtonProps, prevButtonPropsProp, props), + } as AriaButtonProps; + }; + + const getNextButtonProps = (props = {}) => { + return { + "data-slot": "next-button", + tabIndex: isHeaderExpanded ? -1 : 0, + className: slots.nextButton({class: classNames?.nextButton}), + ...mergeProps(commonButtonProps, nextButtonPropsProp, props), + } as AriaButtonProps; + }; + + const getErrorMessageProps: PropGetter = (props = {}) => { + return { + "data-slot": "error-message", + className: slots.errorMessage({class: classNames?.errorMessage}), + ...props, + }; + }; + + return { + Component, + children, + domRef, + slots, + locale, + minValue, + maxValue, + baseProps, + showHelper, + weekdayStyle, + visibleMonths, + visibleDuration, + shouldFilterDOMProps, + isHeaderExpanded, + showMonthAndYearPickers, + createCalendar: createCalendarProp, + getPrevButtonProps, + getNextButtonProps, + getErrorMessageProps, + setIsHeaderExpanded, + topContent, + bottomContent, + errorMessage, + classNames, + otherProps, + }; +} + +export type UseCalendarBaseReturn = ReturnType; diff --git a/packages/components/calendar/src/use-calendar-picker.ts b/packages/components/calendar/src/use-calendar-picker.ts new file mode 100644 index 0000000000..ff9dce3109 --- /dev/null +++ b/packages/components/calendar/src/use-calendar-picker.ts @@ -0,0 +1,243 @@ +import type {CalendarDate} from "@internationalized/date"; +import type {PressEvent} from "@react-types/shared"; + +import {useDateFormatter} from "@react-aria/i18n"; +import {HTMLNextUIProps} from "@nextui-org/system"; +import {useCallback, useRef, useEffect} from "react"; +import debounce from "lodash.debounce"; +import {areRectsIntersecting} from "@nextui-org/react-utils"; +import scrollIntoView from "scroll-into-view-if-needed"; + +import {getMonthsInYear, getYearRange} from "./utils"; +import {useCalendarContext} from "./calendar-context"; + +export type PickerValue = { + value: string; + label: string; +}; +export interface CalendarPickerProps extends HTMLNextUIProps<"div"> { + date: CalendarDate; + currentMonth: CalendarDate; +} + +type ItemsRefMap = Map; +type CalendarPickerListType = "months" | "years"; + +const SCROLL_DEBOUNCE_TIME = 200; + +export function useCalendarPicker(props: CalendarPickerProps) { + const {date, currentMonth} = props; + + const {slots, state, headerRef, isHeaderExpanded, setIsHeaderExpanded, classNames} = + useCalendarContext(); + + const highlightRef = useRef(null); + const yearsListRef = useRef(null); + const monthsListRef = useRef(null); + + const monthsItemsRef = useRef(); + const yearsItemsRef = useRef(); + + const monthDateFormatter = useDateFormatter({ + month: "long", + era: + currentMonth.calendar.identifier === "gregory" && currentMonth.era === "BC" + ? "short" + : undefined, + calendar: currentMonth.calendar.identifier, + timeZone: state.timeZone, + }); + + const yearDateFormatter = useDateFormatter({ + year: "numeric", + timeZone: state.timeZone, + }); + + // Used for the year/month pickers + const years = getYearRange(state.minValue, state.maxValue)?.map((y) => ({ + value: y.year, + label: yearDateFormatter.format(y.toDate(state.timeZone)), + })); + + const months = getMonthsInYear(date).map((m) => ({ + value: m.month, + label: monthDateFormatter.format(m.toDate(state.timeZone)), + })); + + function getItemsRefMap(itemsRef: React.MutableRefObject) { + if (!itemsRef.current) { + // Initialize the Map on first usage. + itemsRef.current = new Map(); + } + + return itemsRef.current; + } + + function getItemRef(node: HTMLElement | null, value: number, list: CalendarPickerListType) { + const map = getItemsRefMap(list === "months" ? monthsItemsRef : yearsItemsRef); + + if (node) { + map.set(value, node); + } else { + map.delete(value); + } + } + + const handleListScroll = useCallback( + (e: Event, highlightEl: HTMLElement | null, list: CalendarPickerListType) => { + if (!(e.target instanceof HTMLElement)) return; + + const map = getItemsRefMap(list === "months" ? monthsItemsRef : yearsItemsRef); + + const items = Array.from(map.values()); + + const item = items.find((itemEl) => { + const rect1 = itemEl.getBoundingClientRect(); + const rect2 = highlightEl?.getBoundingClientRect(); + + if (!rect2) { + return false; + } + + return areRectsIntersecting(rect1, rect2); + }); + + const itemValue = Number(item?.getAttribute("data-value")); + + if (!itemValue) return; + + let date = state.focusedDate.set(list === "months" ? {month: itemValue} : {year: itemValue}); + + state.setFocusedDate(date); + }, + [state, isHeaderExpanded], + ); + + // scroll to the selected month/year when the component is mounted/opened/closed + useEffect(() => { + scrollTo(date.month, "months", false); + scrollTo(date.year, "years", false); + }, [isHeaderExpanded]); + + useEffect(() => { + // add scroll event listener to monthsListRef + const monthsList = monthsListRef.current; + const yearsList = yearsListRef.current; + const highlightEl = highlightRef.current; + + if (!highlightEl) return; + + const debouncedHandleMonthsScroll = debounce( + (e: Event) => handleListScroll(e, highlightEl, "months"), + SCROLL_DEBOUNCE_TIME, + ); + const debouncedHandleYearsScroll = debounce( + (e: Event) => handleListScroll(e, highlightEl, "years"), + SCROLL_DEBOUNCE_TIME, + ); + + monthsList?.addEventListener("scroll", debouncedHandleMonthsScroll); + yearsList?.addEventListener("scroll", debouncedHandleYearsScroll); + + return () => { + if (debouncedHandleMonthsScroll) { + monthsList?.removeEventListener("scroll", debouncedHandleMonthsScroll); + } + if (debouncedHandleYearsScroll) { + yearsList?.removeEventListener("scroll", debouncedHandleYearsScroll); + } + }; + }, [handleListScroll]); + + function scrollTo(value: number, list: CalendarPickerListType, smooth = true) { + const mapListRef = list === "months" ? monthsItemsRef : yearsItemsRef; + const listRef = list === "months" ? monthsListRef : yearsListRef; + + const map = getItemsRefMap(mapListRef); + + const node = map.get(value); + + if (!node) return; + + // scroll picker list to the selected item + scrollIntoView(node, { + scrollMode: "always", + behavior: smooth ? "smooth" : "auto", + boundary: listRef.current, + }); + } + + const onPickerItemPressed = useCallback( + (e: PressEvent, list: CalendarPickerListType) => { + const target = e.target as HTMLElement; + const value = Number(target.getAttribute("data-value")); + + if (!value) return; + + scrollTo(value, list); + }, + [state], + ); + + const onPickerItemKeyDown = useCallback( + (e: React.KeyboardEvent, value: number, list: CalendarPickerListType) => { + const map = getItemsRefMap(list === "months" ? monthsItemsRef : yearsItemsRef); + + const node = map.get(value); + + if (!node) return; + + let nextValue = value; + + switch (e.key) { + case "ArrowDown": + nextValue = value + 1; + break; + case "ArrowUp": + nextValue = value - 1; + break; + case "Home": + nextValue = 0; + break; + case "End": + nextValue = months.length - 1; + break; + case "PageUp": + nextValue = value - 3; + break; + case "PageDown": + nextValue = value + 3; + break; + case "Escape": + case "Enter": + case " ": + setIsHeaderExpanded?.(false); + headerRef?.current?.focus(); + + return; + } + + const nextItem = map.get(nextValue); + + nextItem?.focus(); + }, + [state], + ); + + return { + state, + slots, + classNames, + years, + months, + highlightRef, + monthsListRef, + yearsListRef, + getItemRef, + isHeaderExpanded, + onPickerItemPressed, + onPickerItemKeyDown, + }; +} + +export type UseCalendarPickerReturn = ReturnType; diff --git a/packages/components/calendar/src/use-calendar.ts b/packages/components/calendar/src/use-calendar.ts new file mode 100644 index 0000000000..5776d8601c --- /dev/null +++ b/packages/components/calendar/src/use-calendar.ts @@ -0,0 +1,144 @@ +import type {DateValue, AriaCalendarProps} from "@react-types/calendar"; +import type {ButtonProps} from "@nextui-org/button"; +import type {CalendarState} from "@react-stately/calendar"; + +import {useMemo, useRef} from "react"; +import {filterDOMProps} from "@nextui-org/react-utils"; +import {useCalendar as useAriaCalendar} from "@react-aria/calendar"; +import {useCalendarState} from "@react-stately/calendar"; +import {createCalendar} from "@internationalized/date"; +import {clsx} from "@nextui-org/shared-utils"; +import {chain} from "@react-aria/utils"; + +import {ContextType, useCalendarBase, UseCalendarBaseProps} from "./use-calendar-base"; +import {CalendarBaseProps} from "./calendar-base"; + +interface Props extends UseCalendarBaseProps { + /** + * Props for the button picker, which is used to select the month, year and expand the header. + */ + buttonPickerProps?: ButtonProps; +} + +export type UseCalendarProps = Props & AriaCalendarProps; + +export function useCalendar({ + buttonPickerProps: buttonPickerPropsProp, + className, + ...originalProps +}: UseCalendarProps) { + const { + Component, + slots, + children, + domRef, + locale, + minValue, + maxValue, + showHelper, + weekdayStyle, + visibleDuration, + baseProps, + shouldFilterDOMProps, + isHeaderExpanded, + visibleMonths, + createCalendar: createCalendarProp, + showMonthAndYearPickers, + getPrevButtonProps, + getNextButtonProps, + getErrorMessageProps, + setIsHeaderExpanded, + topContent, + bottomContent, + errorMessage, + classNames, + otherProps, + } = useCalendarBase(originalProps); + + const headerRef = useRef(null); + + const state = useCalendarState({ + ...originalProps, + locale, + minValue, + maxValue, + visibleDuration, + createCalendar: + !createCalendarProp || typeof createCalendarProp !== "function" + ? createCalendar + : (createCalendarProp as typeof createCalendar), + }); + + const {title, calendarProps, prevButtonProps, nextButtonProps, errorMessageProps} = + useAriaCalendar(originalProps, state); + + const baseStyles = clsx(classNames?.base, className); + const disableAnimation = originalProps.disableAnimation ?? false; + + const buttonPickerProps: ButtonProps = { + ...buttonPickerPropsProp, + onPress: chain(buttonPickerPropsProp?.onPress, () => setIsHeaderExpanded(!isHeaderExpanded)), + }; + + const getBaseCalendarProps = (props = {}): CalendarBaseProps => { + return { + ...baseProps, + Component, + showHelper, + topContent, + bottomContent, + buttonPickerProps, + calendarRef: domRef, + calendarProps: calendarProps, + prevButtonProps: getPrevButtonProps(prevButtonProps), + nextButtonProps: getNextButtonProps(nextButtonProps), + errorMessageProps: getErrorMessageProps(errorMessageProps), + className: slots.base({class: baseStyles}), + errorMessage, + ...filterDOMProps(otherProps, { + enabled: shouldFilterDOMProps, + }), + ...props, + }; + }; + + const context = useMemo>( + () => ({ + state, + slots, + headerRef, + weekdayStyle, + isHeaderExpanded, + setIsHeaderExpanded, + visibleMonths, + classNames, + showMonthAndYearPickers, + disableAnimation, + }), + [ + state, + slots, + classNames, + weekdayStyle, + isHeaderExpanded, + setIsHeaderExpanded, + visibleMonths, + disableAnimation, + showMonthAndYearPickers, + ], + ); + + return { + Component, + children, + domRef, + context, + state, + slots, + title, + classNames, + getBaseCalendarProps, + }; +} + +export type UseCalendarReturn = ReturnType; diff --git a/packages/components/calendar/src/use-range-calendar.ts b/packages/components/calendar/src/use-range-calendar.ts new file mode 100644 index 0000000000..da6e4be0af --- /dev/null +++ b/packages/components/calendar/src/use-range-calendar.ts @@ -0,0 +1,133 @@ +import type {DateValue, AriaRangeCalendarProps} from "@react-types/calendar"; +import type {HTMLNextUIProps} from "@nextui-org/system"; +import type {RangeCalendarState} from "@react-stately/calendar"; + +import {useMemo, useRef} from "react"; +import {filterDOMProps} from "@nextui-org/react-utils"; +import {useRangeCalendar as useAriaRangeCalendar} from "@react-aria/calendar"; +import {useRangeCalendarState} from "@react-stately/calendar"; +import {createCalendar} from "@internationalized/date"; +import {clsx} from "@nextui-org/shared-utils"; + +import {ContextType, useCalendarBase, UseCalendarBaseProps} from "./use-calendar-base"; +import {CalendarBaseProps} from "./calendar-base"; + +type NextUIBaseProps = Omit< + HTMLNextUIProps<"div">, + keyof AriaRangeCalendarProps +>; + +interface Props extends UseCalendarBaseProps, NextUIBaseProps {} + +export type UseRangeCalendarProps = Props & AriaRangeCalendarProps; + +export function useRangeCalendar({ + className, + ...originalProps +}: UseRangeCalendarProps) { + const { + Component, + slots, + children, + domRef, + locale, + showHelper, + minValue, + maxValue, + weekdayStyle, + visibleDuration, + shouldFilterDOMProps, + isHeaderExpanded, + visibleMonths, + createCalendar: createCalendarProp, + baseProps, + getPrevButtonProps, + getNextButtonProps, + getErrorMessageProps, + setIsHeaderExpanded, + topContent, + bottomContent, + errorMessage, + classNames, + otherProps, + } = useCalendarBase({...originalProps, isRange: true}); + + const headerRef = useRef(null); + + const state = useRangeCalendarState({ + ...originalProps, + locale, + minValue, + maxValue, + visibleDuration, + createCalendar: + !createCalendarProp || typeof createCalendarProp !== "function" + ? createCalendar + : (createCalendarProp as typeof createCalendar), + }); + + const {title, calendarProps, prevButtonProps, nextButtonProps, errorMessageProps} = + useAriaRangeCalendar(originalProps, state, domRef); + + const baseStyles = clsx(classNames?.base, className); + const disableAnimation = originalProps.disableAnimation ?? false; + + const getBaseCalendarProps = (props = {}): CalendarBaseProps => { + return { + ...baseProps, + Component, + showHelper, + topContent, + bottomContent, + calendarRef: domRef, + calendarProps: calendarProps, + prevButtonProps: getPrevButtonProps(prevButtonProps), + nextButtonProps: getNextButtonProps(nextButtonProps), + errorMessageProps: getErrorMessageProps(errorMessageProps), + className: slots.base({class: baseStyles}), + errorMessage, + ...filterDOMProps(otherProps, { + enabled: shouldFilterDOMProps, + }), + ...props, + }; + }; + + const context = useMemo>( + () => ({ + state, + slots, + headerRef, + weekdayStyle, + isHeaderExpanded, + setIsHeaderExpanded, + visibleMonths, + classNames, + disableAnimation, + }), + [ + state, + slots, + classNames, + weekdayStyle, + isHeaderExpanded, + setIsHeaderExpanded, + visibleMonths, + disableAnimation, + ], + ); + + return { + Component, + children, + domRef, + context, + state, + slots, + title, + classNames, + getBaseCalendarProps, + }; +} + +export type UseRangeCalendarReturn = ReturnType; diff --git a/packages/components/calendar/src/utils.ts b/packages/components/calendar/src/utils.ts new file mode 100644 index 0000000000..1e6683d5cf --- /dev/null +++ b/packages/components/calendar/src/utils.ts @@ -0,0 +1,36 @@ +import {DateValue, startOfYear} from "@internationalized/date"; + +export function getYearRange(start?: DateValue, end?: DateValue): DateValue[] { + const years: DateValue[] = []; + + if (!start || !end) { + return years; + } + + let current = startOfYear(start); + + while (current.compare(end) <= 0) { + years.push(current); + // Move to the first day of the next year + current = startOfYear(current.add({years: 1})); + } + + return years; +} + +export function addMonths(date: DateValue, months: number): DateValue { + return date.add({months}); +} + +export function getMonthsInYear(year: DateValue) { + const firstMonth = startOfYear(year); + const months = [firstMonth]; + + while (months.length < 12) { + const prevMonth = months[months.length - 1]; + + months.push(addMonths(prevMonth, 1)); + } + + return months; +} diff --git a/packages/components/calendar/stories/calendar.stories.tsx b/packages/components/calendar/stories/calendar.stories.tsx new file mode 100644 index 0000000000..e9a70b1c56 --- /dev/null +++ b/packages/components/calendar/stories/calendar.stories.tsx @@ -0,0 +1,350 @@ +import React from "react"; +import {Meta} from "@storybook/react"; +import {calendar} from "@nextui-org/theme"; +import { + today, + parseDate, + getLocalTimeZone, + isWeekend, + startOfWeek, + startOfMonth, +} from "@internationalized/date"; +import {I18nProvider, useLocale} from "@react-aria/i18n"; +import {Button, ButtonGroup} from "@nextui-org/button"; +import {Radio, RadioGroup} from "@nextui-org/radio"; +import {cn} from "@nextui-org/system"; + +import {Calendar, CalendarProps, DateValue} from "../src"; + +export default { + title: "Components/Calendar", + component: Calendar, + parameters: { + layout: "centered", + }, + argTypes: { + visibleMonths: { + control: {type: "number", min: 1, max: 3}, + }, + color: { + control: { + type: "select", + }, + options: ["foreground", "primary", "secondary", "success", "warning", "danger"], + }, + weekdayStyle: { + control: { + type: "select", + }, + options: ["narrow", "short", "long"], + }, + }, +} as Meta; + +const defaultProps = { + ...calendar.defaultVariants, + visibleMonths: 1, +}; + +const Template = (args: CalendarProps) => ; + +const ControlledTemplate = (args: CalendarProps) => { + let [value, setValue] = React.useState(parseDate("2024-03-07")); + + return ( +
+
+

Date (uncontrolled)

+ +
+
+

Date (controlled)

+ +
+
+ ); +}; + +const UnavailableDatesTemplate = (args: CalendarProps) => { + let now = today(getLocalTimeZone()); + + let disabledRanges = [ + [now, now.add({days: 5})], + [now.add({days: 14}), now.add({days: 16})], + [now.add({days: 23}), now.add({days: 24})], + ]; + + let {locale} = useLocale(); + + let isDateUnavailable = (date) => + isWeekend(date, locale) || + disabledRanges.some( + (interval) => date.compare(interval[0]) >= 0 && date.compare(interval[1]) <= 0, + ); + + return ( + + ); +}; + +const ControlledFocusedValueTemplate = (args: CalendarProps) => { + let defaultDate = today(getLocalTimeZone()); + let [focusedDate, setFocusedDate] = React.useState(defaultDate); + + return ( +
+ + +
+ ); +}; + +const InvalidDateTemplate = (args: CalendarProps) => { + let [date, setDate] = React.useState(today(getLocalTimeZone())); + let {locale} = useLocale(); + let isInvalid = isWeekend(date, locale); + + return ( + + ); +}; + +const InternationalCalendarsTemplate = (args: CalendarProps) => { + return ( +
+ + + +
+ ); +}; + +const PresetsTemplate = (args: CalendarProps) => { + let defaultDate = today(getLocalTimeZone()); + let [value, setValue] = React.useState(defaultDate); + let {locale} = useLocale(); + + let now = today(getLocalTimeZone()); + let nextWeek = startOfWeek(now.add({weeks: 1}), locale); + let nextMonth = startOfMonth(now.add({months: 1})); + + const CustomRadio = (props) => { + const {children, ...otherProps} = props; + + return ( + + {children} + + ); + }; + + return ( +
+ + Exact dates + 1 day + 2 days + 3 days + 7 days + 14 days + + } + classNames={{ + content: "w-full", + }} + focusedValue={value} + nextButtonProps={{ + variant: "bordered", + }} + prevButtonProps={{ + variant: "bordered", + }} + topContent={ + + + + + + } + value={value} + onChange={setValue} + onFocusChange={setValue} + {...args} + /> +
+ ); +}; + +export const Default = { + render: Template, + args: { + ...defaultProps, + }, +}; + +export const Disabled = { + render: Template, + args: { + ...defaultProps, + isDisabled: true, + }, +}; + +export const ReadOnly = { + render: Template, + args: { + ...defaultProps, + value: today(getLocalTimeZone()), + isReadOnly: true, + }, +}; + +export const Controlled = { + render: ControlledTemplate, + args: { + ...defaultProps, + }, +}; + +export const MinDateValue = { + render: Template, + args: { + ...defaultProps, + defaultValue: today(getLocalTimeZone()), + minValue: today(getLocalTimeZone()), + }, +}; + +export const MaxDateValue = { + render: Template, + args: { + ...defaultProps, + defaultValue: today(getLocalTimeZone()), + maxValue: today(getLocalTimeZone()), + }, +}; + +export const UnavailableDates = { + render: UnavailableDatesTemplate, + args: { + ...defaultProps, + defaultValue: today(getLocalTimeZone()), + unavailableDates: [today(getLocalTimeZone())], + }, +}; + +export const ControlledFocusedValue = { + render: ControlledFocusedValueTemplate, + args: { + ...defaultProps, + }, +}; + +export const InvalidDate = { + render: InvalidDateTemplate, + args: { + ...defaultProps, + }, +}; + +export const WithMonthAndYearPickers = { + render: Template, + args: { + ...defaultProps, + showMonthAndYearPickers: true, + }, +}; + +export const InternationalCalendars = { + render: InternationalCalendarsTemplate, + args: { + ...defaultProps, + showMonthAndYearPickers: true, + }, +}; + +export const VisibleMonths = { + render: Template, + args: { + ...defaultProps, + visibleMonths: 3, + }, +}; + +export const PageBehavior = { + render: Template, + args: { + ...defaultProps, + visibleMonths: 3, + pageBehavior: "single", + }, +}; + +export const Presets = { + render: PresetsTemplate, + args: { + ...defaultProps, + }, +}; diff --git a/packages/components/calendar/stories/range-calendar.stories.tsx b/packages/components/calendar/stories/range-calendar.stories.tsx new file mode 100644 index 0000000000..2a4ed35373 --- /dev/null +++ b/packages/components/calendar/stories/range-calendar.stories.tsx @@ -0,0 +1,411 @@ +import type {RangeValue, DateValue} from "../src"; + +import React from "react"; +import {Meta} from "@storybook/react"; +import {calendar} from "@nextui-org/theme"; +import { + today, + getLocalTimeZone, + isWeekend, + CalendarDate, + startOfMonth, + startOfWeek, + endOfMonth, + endOfWeek, +} from "@internationalized/date"; +import {I18nProvider, useLocale} from "@react-aria/i18n"; +import {Button, ButtonGroup} from "@nextui-org/button"; +import {Radio, RadioGroup} from "@nextui-org/radio"; +import {cn} from "@nextui-org/system"; + +import {RangeCalendar, RangeCalendarProps} from "../src"; + +export default { + title: "Components/RangeCalendar", + component: RangeCalendar, + parameters: { + layout: "centered", + }, + argTypes: { + visibleMonths: { + control: {type: "number", min: 1, max: 3}, + }, + color: { + control: { + type: "select", + }, + options: ["foreground", "primary", "secondary", "success", "warning", "danger"], + }, + weekdayStyle: { + control: { + type: "select", + }, + options: ["narrow", "short", "long"], + }, + }, +} as Meta; + +delete calendar.defaultVariants?.showMonthAndYearPickers; + +const defaultProps = { + ...calendar.defaultVariants, + visibleMonths: 1, +}; + +const Template = (args: RangeCalendarProps) => ; + +const ControlledTemplate = (args: RangeCalendarProps) => { + const defaultValue = { + start: today(getLocalTimeZone()), + end: today(getLocalTimeZone()).add({weeks: 1}), + }; + + let [value, setValue] = React.useState>(defaultValue); + + return ( +
+
+

Date (uncontrolled)

+ +
+
+

Date (controlled)

+ +
+
+ ); +}; + +const UnavailableDatesTemplate = (args: RangeCalendarProps) => { + let now = today(getLocalTimeZone()); + + let disabledRanges = [ + [now, now.add({days: 5})], + [now.add({days: 14}), now.add({days: 16})], + [now.add({days: 23}), now.add({days: 24})], + ]; + + let isDateUnavailable = (date) => + disabledRanges.some( + (interval) => date.compare(interval[0]) >= 0 && date.compare(interval[1]) <= 0, + ); + + return ( + + ); +}; + +const NonContiguousRangesTemplate = (args: RangeCalendarProps) => { + let {locale} = useLocale(); + + return ( + isWeekend(date, locale)} + {...args} + /> + ); +}; + +const ControlledFocusedValueTemplate = (args: RangeCalendarProps) => { + let defaultDate = new CalendarDate(2024, 3, 1); + let [focusedDate, setFocusedDate] = React.useState(defaultDate); + + return ( +
+ + +
+ ); +}; + +const InvalidDatesTemplate = (args: RangeCalendarProps) => { + let [date, setDate] = React.useState>({ + start: today(getLocalTimeZone()), + end: today(getLocalTimeZone()).add({weeks: 1}), + }); + + let {locale} = useLocale(); + let isInvalid = isWeekend(date.start, locale) || isWeekend(date.end, locale); + + return ( + + ); +}; + +const InternationalCalendarsTemplate = (args: RangeCalendarProps) => { + return ( +
+ + + +
+ ); +}; + +const PresetsTemplate = (args: RangeCalendarProps) => { + let [value, setValue] = React.useState>({ + start: today(getLocalTimeZone()), + end: today(getLocalTimeZone()).add({weeks: 1, days: 3}), + }); + + let [focusedValue, setFocusedValue] = React.useState(today(getLocalTimeZone())); + + let {locale} = useLocale(); + + let now = today(getLocalTimeZone()); + let nextMonth = now.add({months: 1}); + + let nextWeek = { + start: startOfWeek(now.add({weeks: 1}), locale), + end: endOfWeek(now.add({weeks: 1}), locale), + }; + let thisMonth = {start: startOfMonth(now), end: endOfMonth(now)}; + let nextMonthValue = {start: startOfMonth(nextMonth), end: endOfMonth(nextMonth)}; + + const CustomRadio = (props) => { + const {children, ...otherProps} = props; + + return ( + + {children} + + ); + }; + + return ( +
+ + Exact dates + 1 day + 2 days + 3 days + 7 days + 14 days + + } + classNames={{ + content: "w-full", + }} + focusedValue={focusedValue} + nextButtonProps={{ + variant: "bordered", + }} + prevButtonProps={{ + variant: "bordered", + }} + topContent={ + + + + + + } + value={value} + onChange={setValue} + onFocusChange={setFocusedValue} + {...args} + /> +
+ ); +}; + +export const Default = { + render: Template, + args: { + ...defaultProps, + }, +}; + +export const Disabled = { + render: Template, + args: { + ...defaultProps, + isDisabled: true, + }, +}; + +export const ReadOnly = { + render: Template, + args: { + ...defaultProps, + value: { + start: today(getLocalTimeZone()), + end: today(getLocalTimeZone()).add({weeks: 1}), + }, + isReadOnly: true, + }, +}; + +export const Controlled = { + render: ControlledTemplate, + args: { + ...defaultProps, + }, +}; + +export const MinDateValue = { + render: Template, + args: { + ...defaultProps, + defaultValue: { + start: today(getLocalTimeZone()), + end: today(getLocalTimeZone()).add({weeks: 1}), + }, + minValue: today(getLocalTimeZone()), + }, +}; + +export const MaxDateValue = { + render: Template, + args: { + ...defaultProps, + defaultValue: { + start: today(getLocalTimeZone()).subtract({weeks: 1}), + end: today(getLocalTimeZone()), + }, + maxValue: today(getLocalTimeZone()), + }, +}; + +export const UnavailableDates = { + render: UnavailableDatesTemplate, + args: { + ...defaultProps, + defaultValue: { + start: today(getLocalTimeZone()), + end: today(getLocalTimeZone()).add({weeks: 1}), + }, + }, +}; + +export const NonContiguousRanges = { + render: NonContiguousRangesTemplate, + args: { + ...defaultProps, + }, +}; + +export const ControlledFocusedValue = { + render: ControlledFocusedValueTemplate, + args: { + ...defaultProps, + }, +}; + +export const InvalidDates = { + render: InvalidDatesTemplate, + args: { + ...defaultProps, + }, +}; + +export const InternationalCalendars = { + render: InternationalCalendarsTemplate, + args: { + ...defaultProps, + showMonthAndYearPickers: true, + }, +}; + +export const VisibleMonths = { + render: Template, + args: { + ...defaultProps, + visibleMonths: 3, + }, +}; + +export const PageBehavior = { + render: Template, + args: { + ...defaultProps, + visibleMonths: 3, + pageBehavior: "single", + }, +}; + +export const Presets = { + render: PresetsTemplate, + args: { + ...defaultProps, + }, +}; diff --git a/packages/components/calendar/tsconfig.json b/packages/components/calendar/tsconfig.json new file mode 100644 index 0000000000..5d012f6e61 --- /dev/null +++ b/packages/components/calendar/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "tailwind-variants": ["../../../node_modules/tailwind-variants"] + }, + }, + "include": ["src", "index.ts"] +} diff --git a/packages/utilities/framer-transitions/tsup.config.ts b/packages/components/calendar/tsup.config.ts similarity index 100% rename from packages/utilities/framer-transitions/tsup.config.ts rename to packages/components/calendar/tsup.config.ts diff --git a/packages/components/card/CHANGELOG.md b/packages/components/card/CHANGELOG.md index 1515ea9441..724e944db8 100644 --- a/packages/components/card/CHANGELOG.md +++ b/packages/components/card/CHANGELOG.md @@ -1,5 +1,40 @@ # @nextui-org/card +## 2.0.27 + +### Patch Changes + +- Updated dependencies [[`eccc2f2f3`](https://github.com/nextui-org/nextui/commit/eccc2f2f3d856eefb2cc7c07b94e1c4cefd4d7d0)]: + - @nextui-org/react-utils@2.0.13 + - @nextui-org/ripple@2.0.27 + +## 2.0.26 + +### Patch Changes + +- Updated dependencies []: + - @nextui-org/ripple@2.0.26 + - @nextui-org/react-utils@2.0.12 + +## 2.0.25 + +### Patch Changes + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - v2.3.0 + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - - Calendar component added + - objectToDeps function applied all across components + - `useMeasure` hook added + - `useIntersectionObserver` hook added + - `framer-transitions` renamed to `framer-utils` + - `ResizablePanel` component added to `framer-utils` + - `test-utils` updated +- Updated dependencies [[`2e49e0831`](https://github.com/nextui-org/nextui/commit/2e49e0831533350808e0fcbd48585f910981b39a), [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14), [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14), [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14), [`2894aecca`](https://github.com/nextui-org/nextui/commit/2894aecca1a2ef0dfb3066b9b8df24ce48c99dae)]: + - @nextui-org/ripple@2.0.25 + - @nextui-org/use-aria-button@2.0.7 + - @nextui-org/react-utils@2.0.11 + - @nextui-org/shared-utils@2.0.5 + ## 2.0.24 ### Patch Changes diff --git a/packages/components/card/package.json b/packages/components/card/package.json index 45ee954b0f..187c585e88 100644 --- a/packages/components/card/package.json +++ b/packages/components/card/package.json @@ -1,6 +1,6 @@ { "name": "@nextui-org/card", - "version": "2.0.24", + "version": "2.0.27", "description": "Card is a container for text, photos, and actions in the context of a single subject.", "keywords": [ "card" @@ -45,11 +45,11 @@ "@nextui-org/react-utils": "workspace:*", "@nextui-org/use-aria-button": "workspace:*", "@nextui-org/ripple": "workspace:*", - "@react-aria/focus": "^3.14.3", - "@react-aria/utils": "^3.21.1", - "@react-aria/interactions": "^3.19.1", - "@react-aria/button": "^3.8.4", - "@react-types/shared": "^3.21.0" + "@react-aria/focus": "^3.16.2", + "@react-aria/utils": "^3.23.2", + "@react-aria/interactions": "^3.21.1", + "@react-aria/button": "^3.9.3", + "@react-types/shared": "^3.22.1" }, "devDependencies": { "@nextui-org/theme": "workspace:*", diff --git a/packages/components/card/src/use-card.ts b/packages/components/card/src/use-card.ts index ce697f9225..45e7c0b985 100644 --- a/packages/components/card/src/use-card.ts +++ b/packages/components/card/src/use-card.ts @@ -10,7 +10,7 @@ import {useFocusRing} from "@react-aria/focus"; import {useHover} from "@react-aria/interactions"; import {useAriaButton} from "@nextui-org/use-aria-button"; import {HTMLNextUIProps, mapPropsVariants, PropGetter} from "@nextui-org/system"; -import {clsx, dataAttr} from "@nextui-org/shared-utils"; +import {clsx, dataAttr, objectToDeps} from "@nextui-org/shared-utils"; import {ReactRef, filterDOMProps} from "@nextui-org/react-utils"; import {useDOMRef} from "@nextui-org/react-utils"; import {useRipple} from "@nextui-org/ripple"; @@ -120,7 +120,7 @@ export function useCard(originalProps: UseCardProps) { card({ ...variantProps, }), - [...Object.values(variantProps)], + [objectToDeps(variantProps)], ); const context = useMemo( diff --git a/packages/components/checkbox/CHANGELOG.md b/packages/components/checkbox/CHANGELOG.md index 99ae164bc3..6d2f322d4c 100644 --- a/packages/components/checkbox/CHANGELOG.md +++ b/packages/components/checkbox/CHANGELOG.md @@ -1,5 +1,53 @@ # @nextui-org/checkbox +## 2.0.29 + +### Patch Changes + +- Updated dependencies [[`eccc2f2f3`](https://github.com/nextui-org/nextui/commit/eccc2f2f3d856eefb2cc7c07b94e1c4cefd4d7d0)]: + - @nextui-org/react-utils@2.0.13 + +## 2.0.28 + +### Patch Changes + +- [#2772](https://github.com/nextui-org/nextui/pull/2772) [`69f713cb0`](https://github.com/nextui-org/nextui/commit/69f713cb056d1d39db510b75bdd53eb29c459b19) Thanks [@chirokas](https://github.com/chirokas)! - Fix non-react props omitted from checkbox group component + +## 2.0.27 + +### Patch Changes + +- [#2754](https://github.com/nextui-org/nextui/pull/2754) [`cadbb30cf`](https://github.com/nextui-org/nextui/commit/cadbb30cfb786d2b54e1cb46ea9319d4cb9ce590) Thanks [@wingkwong](https://github.com/wingkwong)! - Fixes checkbox controlled state (#2752) + +- Updated dependencies []: + - @nextui-org/react-utils@2.0.12 + +## 2.0.26 + +### Patch Changes + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - v2.3.0 + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - - Calendar component added + + - objectToDeps function applied all across components + - `useMeasure` hook added + - `useIntersectionObserver` hook added + - `framer-transitions` renamed to `framer-utils` + - `ResizablePanel` component added to `framer-utils` + - `test-utils` updated + +- [#2595](https://github.com/nextui-org/nextui/pull/2595) [`ef6ea6c1f`](https://github.com/nextui-org/nextui/commit/ef6ea6c1ffb57cd30f8994143a48b70f8ad2adeb) Thanks [@wingkwong](https://github.com/wingkwong)! - Fixed incorrect onChange typing in Checkbox Group + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - Fixed react-hook-form uncontrolled components (#1969) + +- [#2466](https://github.com/nextui-org/nextui/pull/2466) [`e4b3c7d1a`](https://github.com/nextui-org/nextui/commit/e4b3c7d1a19bc31c1f69c90a5b467bf8310602dc) Thanks [@mrbadri](https://github.com/mrbadri)! - Add RTL support to the checkbox component + +- Updated dependencies [[`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14), [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14)]: + - @nextui-org/react-utils@2.0.11 + - @nextui-org/shared-utils@2.0.5 + - @nextui-org/use-safe-layout-effect@2.0.5 + ## 2.0.25 ### Patch Changes diff --git a/packages/components/checkbox/__tests__/checkbox-group.test.tsx b/packages/components/checkbox/__tests__/checkbox-group.test.tsx index 4fb861df73..cef6cdd5b1 100644 --- a/packages/components/checkbox/__tests__/checkbox-group.test.tsx +++ b/packages/components/checkbox/__tests__/checkbox-group.test.tsx @@ -54,7 +54,7 @@ describe("Checkbox.Group", () => { act(() => (value = val))} + onChange={(val) => act(() => (value = val as string[]))} > Sydney @@ -132,4 +132,55 @@ describe("Checkbox.Group", () => { expect(onChange).toHaveBeenCalledTimes(1); expect(checked).toEqual(["sydney", "buenos-aires"]); }); + + describe("validation", () => { + let user = userEvent.setup(); + + beforeAll(() => { + user = userEvent.setup(); + }); + describe("validationBehavior=native (default)", () => { + it("supports group level isRequired", async () => { + let {getAllByRole, getByRole, getByTestId} = render( + + + Terms and conditions + Cookies + Privacy policy + + , + ); + + let group = getByRole("group"); + + expect(group).not.toHaveAttribute("aria-describedby"); + + let checkboxes = getAllByRole("checkbox") as HTMLInputElement[]; + + for (let input of checkboxes) { + expect(input).toHaveAttribute("required"); + expect(input).not.toHaveAttribute("aria-required"); + expect(input.validity.valid).toBe(false); + } + + act(() => { + (getByTestId("form") as HTMLFormElement).checkValidity(); + }); + + expect(group).toHaveAttribute("aria-describedby"); + expect(document.getElementById(group.getAttribute("aria-describedby")!)).toHaveTextContent( + "Constraints not satisfied", + ); + + await user.click(checkboxes[0]); + for (let input of checkboxes) { + expect(input).not.toHaveAttribute("required"); + expect(input).not.toHaveAttribute("aria-required"); + expect(input.validity.valid).toBe(true); + } + + expect(group).not.toHaveAttribute("aria-describedby"); + }); + }); + }); }); diff --git a/packages/components/checkbox/__tests__/checkbox.test.tsx b/packages/components/checkbox/__tests__/checkbox.test.tsx index ee7bf6a643..c3e7308b74 100644 --- a/packages/components/checkbox/__tests__/checkbox.test.tsx +++ b/packages/components/checkbox/__tests__/checkbox.test.tsx @@ -12,7 +12,7 @@ describe("Checkbox", () => { }); it("ref should be forwarded", () => { - const ref = React.createRef(); + const ref = React.createRef(); render(Option); expect(ref.current).not.toBeNull(); diff --git a/packages/components/checkbox/package.json b/packages/components/checkbox/package.json index 57af20cecc..c3672373e3 100644 --- a/packages/components/checkbox/package.json +++ b/packages/components/checkbox/package.json @@ -1,6 +1,6 @@ { "name": "@nextui-org/checkbox", - "version": "2.0.25", + "version": "2.0.29", "description": "Checkboxes allow users to select multiple items from a list of individual items, or to mark one individual item as selected.", "keywords": [ "checkbox" @@ -34,35 +34,37 @@ "postpack": "clean-package restore" }, "peerDependencies": { - "react": ">=18", - "react-dom": ">=18", + "@nextui-org/system": ">=2.0.0", "@nextui-org/theme": ">=2.1.0", - "@nextui-org/system": ">=2.0.0" + "react": ">=18", + "react-dom": ">=18" }, "dependencies": { - "@nextui-org/shared-utils": "workspace:*", "@nextui-org/react-utils": "workspace:*", - "@nextui-org/use-aria-press": "workspace:*", - "@react-aria/checkbox": "^3.11.2", - "@react-aria/focus": "^3.14.3", - "@react-aria/interactions": "^3.19.1", - "@react-aria/visually-hidden": "^3.8.6", - "@react-stately/checkbox": "^3.5.1", - "@react-stately/toggle": "^3.6.3", - "@react-aria/utils": "^3.21.1", - "@react-types/checkbox": "^3.5.2", - "@react-types/shared": "^3.21.0" + "@nextui-org/shared-utils": "workspace:*", + "@nextui-org/use-callback-ref": "workspace:*", + "@nextui-org/use-safe-layout-effect": "workspace:*", + "@react-aria/checkbox": "^3.14.1", + "@react-aria/focus": "^3.16.2", + "@react-aria/interactions": "^3.21.1", + "@react-aria/utils": "^3.23.2", + "@react-aria/visually-hidden": "^3.8.10", + "@react-stately/checkbox": "^3.6.3", + "@react-stately/toggle": "^3.7.2", + "@react-types/checkbox": "^3.7.1", + "@react-types/shared": "^3.22.1" }, "devDependencies": { - "@nextui-org/theme": "workspace:*", - "@nextui-org/system": "workspace:*", - "@nextui-org/shared-icons": "workspace:*", "@nextui-org/chip": "workspace:*", - "@nextui-org/user": "workspace:*", "@nextui-org/link": "workspace:*", + "@nextui-org/shared-icons": "workspace:*", + "@nextui-org/system": "workspace:*", + "@nextui-org/theme": "workspace:*", + "@nextui-org/user": "workspace:*", "clean-package": "2.2.0", "react": "^18.0.0", - "react-dom": "^18.0.0" + "react-dom": "^18.0.0", + "react-hook-form": "^7.51.3" }, "clean-package": "../../../clean-package.config.json" } diff --git a/packages/components/checkbox/src/checkbox-group.tsx b/packages/components/checkbox/src/checkbox-group.tsx index c03fc669c6..5f4aec3dbd 100644 --- a/packages/components/checkbox/src/checkbox-group.tsx +++ b/packages/components/checkbox/src/checkbox-group.tsx @@ -1,4 +1,5 @@ import {forwardRef} from "@nextui-org/system"; +import {useMemo} from "react"; import {CheckboxGroupProvider} from "./checkbox-group-context"; import {UseCheckboxGroupProps, useCheckboxGroup} from "./use-checkbox-group"; @@ -11,6 +12,7 @@ const CheckboxGroup = forwardRef<"div", CheckboxGroupProps>((props, ref) => { context, label, description, + isInvalid, errorMessage, getGroupProps, getLabelProps, @@ -19,14 +21,16 @@ const CheckboxGroup = forwardRef<"div", CheckboxGroupProps>((props, ref) => { getErrorMessageProps, } = useCheckboxGroup({...props, ref}); + const errorMessageContent = useMemo(() => errorMessage, [isInvalid]); + return (
{label && {label}}
{children}
- {errorMessage ? ( -
{errorMessage}
+ {isInvalid && errorMessageContent ? ( +
{errorMessageContent}
) : description ? (
{description}
) : null} diff --git a/packages/components/checkbox/src/checkbox.tsx b/packages/components/checkbox/src/checkbox.tsx index b9c9a7f475..dea6db536e 100644 --- a/packages/components/checkbox/src/checkbox.tsx +++ b/packages/components/checkbox/src/checkbox.tsx @@ -17,10 +17,7 @@ const Checkbox = forwardRef<"input", CheckboxProps>((props, ref) => { getInputProps, getIconProps, getLabelProps, - } = useCheckbox({ - ...props, - ref, - }); + } = useCheckbox({...props, ref}); const clonedIcon = typeof icon === "function" diff --git a/packages/components/checkbox/src/use-checkbox-group.ts b/packages/components/checkbox/src/use-checkbox-group.ts index a29e3c96b7..93ac34d013 100644 --- a/packages/components/checkbox/src/use-checkbox-group.ts +++ b/packages/components/checkbox/src/use-checkbox-group.ts @@ -3,13 +3,14 @@ import type {AriaCheckboxGroupProps} from "@react-types/checkbox"; import type {Orientation} from "@react-types/shared"; import type {HTMLNextUIProps, PropGetter} from "@nextui-org/system"; import type {ReactRef} from "@nextui-org/react-utils"; +import type {CheckboxGroupProps} from "@react-types/checkbox"; import {useCallback, useMemo} from "react"; -import {mergeProps} from "@react-aria/utils"; +import {chain, mergeProps} from "@react-aria/utils"; import {checkboxGroup} from "@nextui-org/theme"; import {useCheckboxGroup as useReactAriaCheckboxGroup} from "@react-aria/checkbox"; import {CheckboxGroupState, useCheckboxGroupState} from "@react-stately/checkbox"; -import {useDOMRef} from "@nextui-org/react-utils"; +import {filterDOMProps, useDOMRef} from "@nextui-org/react-utils"; import {clsx, safeAriaLabel} from "@nextui-org/shared-utils"; import {CheckboxProps} from "./index"; @@ -47,7 +48,7 @@ interface Props extends HTMLNextUIProps<"div"> { } export type UseCheckboxGroupProps = Omit & - AriaCheckboxGroupProps & + Omit & Partial< Pick< CheckboxProps, @@ -77,14 +78,14 @@ export function useCheckboxGroup(props: UseCheckboxGroupProps) { value, name, defaultValue, + isInvalid: isInvalidProp, + validationState, size = "md", color = "primary", orientation = "vertical", lineThrough = false, isDisabled = false, disableAnimation = false, - validationState, - isInvalid = validationState === "invalid", isReadOnly, isRequired, onValueChange, @@ -95,43 +96,52 @@ export function useCheckboxGroup(props: UseCheckboxGroupProps) { } = props; const Component = as || "div"; + const shouldFilterDOMProps = typeof Component === "string"; const domRef = useDOMRef(ref); - const checkboxGroupProps = useMemo( - () => ({ - value, - name, - "aria-label": safeAriaLabel(otherProps["aria-label"], label), - defaultValue, - isRequired, - isInvalid, - isReadOnly, - orientation, - onChange: onValueChange, + const checkboxGroupProps = useMemo(() => { + return { ...otherProps, - }), - [ value, name, - label, + "aria-label": safeAriaLabel(otherProps["aria-label"], label), defaultValue, isRequired, isReadOnly, - isInvalid, orientation, - onValueChange, - otherProps["aria-label"], - otherProps, - ], - ); + validationBehavior: "native", + isInvalid: validationState === "invalid" || isInvalidProp, + onChange: chain(props.onChange, onValueChange), + }; + }, [ + value, + name, + label, + defaultValue, + isRequired, + isReadOnly, + orientation, + onValueChange, + isInvalidProp, + validationState, + otherProps["aria-label"], + otherProps, + ]); const groupState = useCheckboxGroupState(checkboxGroupProps); - const {labelProps, groupProps, descriptionProps, errorMessageProps} = useReactAriaCheckboxGroup( - checkboxGroupProps, - groupState, - ); + const { + labelProps, + groupProps, + descriptionProps, + errorMessageProps, + isInvalid: isAriaInvalid, + validationErrors, + validationDetails, + } = useReactAriaCheckboxGroup(checkboxGroupProps, groupState); + + let isInvalid = checkboxGroupProps.isInvalid || isAriaInvalid; const context = useMemo( () => ({ @@ -171,7 +181,12 @@ export function useCheckboxGroup(props: UseCheckboxGroupProps) { return { ref: domRef, className: slots.base({class: baseStyles}), - ...mergeProps(groupProps, otherProps), + ...mergeProps( + groupProps, + filterDOMProps(otherProps, { + enabled: shouldFilterDOMProps, + }), + ), }; }, [slots, domRef, baseStyles, groupProps, otherProps]); @@ -218,7 +233,11 @@ export function useCheckboxGroup(props: UseCheckboxGroupProps) { label, context, description, - errorMessage, + isInvalid, + errorMessage: + typeof errorMessage === "function" + ? errorMessage({isInvalid, validationErrors, validationDetails}) + : errorMessage || validationErrors?.join(" "), getGroupProps, getLabelProps, getWrapperProps, diff --git a/packages/components/checkbox/src/use-checkbox.ts b/packages/components/checkbox/src/use-checkbox.ts index 77b7697611..b5e0171d5b 100644 --- a/packages/components/checkbox/src/use-checkbox.ts +++ b/packages/components/checkbox/src/use-checkbox.ts @@ -6,17 +6,17 @@ import {ReactNode, Ref, useCallback, useId, useState} from "react"; import {useMemo, useRef} from "react"; import {useToggleState} from "@react-stately/toggle"; import {checkbox} from "@nextui-org/theme"; -import {useHover} from "@react-aria/interactions"; -import {usePress} from "@nextui-org/use-aria-press"; +import {useCallbackRef} from "@nextui-org/use-callback-ref"; +import {useHover, usePress} from "@react-aria/interactions"; import {useFocusRing} from "@react-aria/focus"; -import {chain, mergeProps} from "@react-aria/utils"; -import {useFocusableRef} from "@nextui-org/react-utils"; +import {mergeProps, chain} from "@react-aria/utils"; import {__DEV__, warn, clsx, dataAttr, safeAriaLabel} from "@nextui-org/shared-utils"; import { useCheckbox as useReactAriaCheckbox, useCheckboxGroupItem as useReactAriaCheckboxGroupItem, } from "@react-aria/checkbox"; -import {FocusableRef} from "@react-types/shared"; +import {useSafeLayoutEffect} from "@nextui-org/use-safe-layout-effect"; +import {mergeRefs} from "@nextui-org/react-utils"; import {useCheckboxGroupContext} from "./checkbox-group-context"; @@ -32,7 +32,7 @@ interface Props extends Omit, keyof CheckboxVariantProp /** * Ref to the DOM node. */ - ref?: Ref; + ref?: Ref; /** * The label of the checkbox. */ @@ -68,7 +68,7 @@ interface Props extends Omit, keyof CheckboxVariantProp } export type UseCheckboxProps = Omit & - Omit & + Omit & CheckboxVariantProps; export function useCheckbox(props: UseCheckboxProps = {}) { @@ -82,7 +82,7 @@ export function useCheckbox(props: UseCheckboxProps = {}) { children, icon, name, - isRequired = false, + isRequired, isReadOnly: isReadOnlyProp = false, autoFocus = false, isSelected: isSelectedProp, @@ -97,7 +97,6 @@ export function useCheckbox(props: UseCheckboxProps = {}) { isIndeterminate = false, defaultSelected, classNames, - onChange, className, onValueChange, ...otherProps @@ -120,8 +119,21 @@ export function useCheckbox(props: UseCheckboxProps = {}) { const Component = as || "label"; - const inputRef = useRef(null); - const domRef = useFocusableRef(ref as FocusableRef, inputRef); + const domRef = useRef(null); + + const inputRef = useRef(null); + + // This workaround might become unnecessary once the following issue is resolved + // https://github.com/adobe/react-spectrum/issues/5693 + let onChange = props.onChange; + + if (isInGroup) { + const dispatch = () => { + groupContext.groupState.resetValidation(); + }; + + onChange = chain(dispatch, onChange); + } const labelId = useId(); @@ -159,6 +171,8 @@ export function useCheckbox(props: UseCheckboxProps = {}) { onValueChange, ]); + const toggleState = useToggleState(ariaCheckboxProps); + const { inputProps, isSelected, @@ -171,11 +185,18 @@ export function useCheckbox(props: UseCheckboxProps = {}) { { ...ariaCheckboxProps, isInvalid, + validationBehavior: "native", }, groupContext.groupState, inputRef, ) - : useReactAriaCheckbox(ariaCheckboxProps, useToggleState(ariaCheckboxProps), inputRef); // eslint-disable-line + : // eslint-disable-next-line + useReactAriaCheckbox( + {...ariaCheckboxProps, validationBehavior: "native"}, + // eslint-disable-next-line + toggleState, + inputRef, + ); const isInteractionDisabled = isDisabled || isReadOnly; @@ -224,6 +245,31 @@ export function useCheckbox(props: UseCheckboxProps = {}) { [color, size, radius, isInvalid, lineThrough, isDisabled, disableAnimation], ); + // if we use `react-hook-form`, it will set the checkbox value using the ref in register + // i.e. setting ref.current.checked to true or false which is uncontrolled + // hence, sync the state with `ref.current.checked` + useSafeLayoutEffect(() => { + if (!inputRef.current) return; + const isInputRefChecked = !!inputRef.current.checked; + + toggleState.setSelected(isInputRefChecked); + }, [inputRef.current]); + + const onChangeProp = useCallbackRef(onChange); + + const handleCheckboxChange = useCallback( + (event: React.ChangeEvent) => { + if (isReadOnly || isDisabled) { + event.preventDefault(); + + return; + } + + onChangeProp?.(event); + }, + [isReadOnly, isDisabled, onChangeProp], + ); + const baseStyles = clsx(classNames?.base, className); const getBaseProps: PropGetter = useCallback(() => { @@ -271,11 +317,11 @@ export function useCheckbox(props: UseCheckboxProps = {}) { const getInputProps: PropGetter = useCallback(() => { return { - ref: inputRef, + ref: mergeRefs(inputRef, ref), ...mergeProps(inputProps, focusProps), - onChange: chain(inputProps.onChange, onChange), + onChange: chain(inputProps.onChange, handleCheckboxChange), }; - }, [inputProps, focusProps, onChange]); + }, [inputProps, focusProps, handleCheckboxChange]); const getLabelProps: PropGetter = useCallback( () => ({ diff --git a/packages/components/checkbox/stories/checkbox-group.stories.tsx b/packages/components/checkbox/stories/checkbox-group.stories.tsx index 310d43456c..131e8ee342 100644 --- a/packages/components/checkbox/stories/checkbox-group.stories.tsx +++ b/packages/components/checkbox/stories/checkbox-group.stories.tsx @@ -1,6 +1,9 @@ +import type {ValidationResult} from "@react-types/shared"; + import React from "react"; import {Meta} from "@storybook/react"; import {checkbox} from "@nextui-org/theme"; +import {button} from "@nextui-org/theme"; import {CheckboxGroup, Checkbox, CheckboxGroupProps} from "../src"; @@ -78,6 +81,54 @@ const InvalidTemplate = (args: CheckboxGroupProps) => { ); }; +const FormTemplate = (args: CheckboxGroupProps) => { + return ( +
{ + const formData = new FormData(e.currentTarget); + const selectedCities = formData.getAll("favorite-cities"); + + alert(`Submitted values: ${selectedCities.join(", ")}`); + e.preventDefault(); + }} + > + + Buenos Aires + Sydney + San Francisco + London + Tokyo + + +
+ ); +}; + +const ControlledTemplate = (args: CheckboxGroupProps) => { + const [selected, setSelected] = React.useState(["buenos-aires"]); + + React.useEffect(() => { + // eslint-disable-next-line no-console + console.log("Checkbox ", selected); + }, [selected]); + + return ( +
+ + Buenos Aires + Sydney + San Francisco + London + Tokyo + +

Selected: {selected.join(", ")}

+
+ ); +}; + export const Default = { render: Template, @@ -104,6 +155,14 @@ export const DefaultValue = { }, }; +export const Controlled = { + render: ControlledTemplate, + + args: { + ...defaultProps, + }, +}; + export const Horizontal = { render: Template, @@ -153,10 +212,41 @@ export const WithErrorMessage = { args: { ...defaultProps, + isInvalid: true, errorMessage: "The selected cities cannot be visited at the same time", }, }; +export const WithErrorMessageFunction = { + render: FormTemplate, + + args: { + ...defaultProps, + isRequired: true, + errorMessage: (value: ValidationResult) => { + if (value.validationDetails.valueMissing) { + return "At least one option must be selected"; + } + }, + }, +}; + +export const WithValidation = { + render: FormTemplate, + + args: { + ...defaultProps, + description: "Please select at least 2 options", + validate: (value: string[]) => { + if (value.length < 2) { + return "You must select at least 2 options"; + } + + return null; + }, + }, +}; + export const DisableAnimation = { render: Template, @@ -165,3 +255,12 @@ export const DisableAnimation = { disableAnimation: true, }, }; + +export const IsRequired = { + render: FormTemplate, + + args: { + ...defaultProps, + isRequired: true, + }, +}; diff --git a/packages/components/checkbox/stories/checkbox.stories.tsx b/packages/components/checkbox/stories/checkbox.stories.tsx index 7ac01baec0..abd840770b 100644 --- a/packages/components/checkbox/stories/checkbox.stories.tsx +++ b/packages/components/checkbox/stories/checkbox.stories.tsx @@ -2,6 +2,8 @@ import React from "react"; import {Meta} from "@storybook/react"; import {checkbox} from "@nextui-org/theme"; import {CloseIcon} from "@nextui-org/shared-icons"; +import {button} from "@nextui-org/theme"; +import {useForm} from "react-hook-form"; import {Checkbox, CheckboxIconProps, CheckboxProps} from "../src"; @@ -59,10 +61,87 @@ const ControlledTemplate = (args: CheckboxProps) => { Subscribe (controlled)

Selected: {selected ? "true" : "false"}

+
); }; +const FormTemplate = (args: CheckboxProps) => { + return ( +
{ + alert(`Submitted value: ${e.target["check"].value}`); + e.preventDefault(); + }} + > + + Check + + +
+ ); +}; + +const GroupTemplate = (args: CheckboxProps) => { + const items = ["Apple", "Banana", "Orange", "Mango"]; + + const [selectedItems, setSelectedItems] = React.useState([]); + + const isSelected = (value: string) => { + return selectedItems.some((selected) => selected === value); + }; + + const handleValueChange = (value: string) => { + setSelectedItems([value]); + }; + + return ( +
+

List of Fruits

+ + {items.map((item, index) => ( + handleValueChange(item)} + > + {item} {isSelected(item) ? "/ state: true" : "/ state: false"} + + ))} +
+ ); +}; + +const WithReactHookFormTemplate = (args: CheckboxProps) => { + const { + register, + formState: {errors}, + handleSubmit, + } = useForm(); + + const onSubmit = (data: any) => { + // eslint-disable-next-line no-console + console.log(data); + alert("Submitted value: " + data.example); + }; + + return ( +
+ + {errors.example && This field is required} + + + ); +}; + export const Default = { args: { ...defaultProps, @@ -90,6 +169,22 @@ export const CustomIconNode = { }, }; +export const Group = { + render: GroupTemplate, + + args: { + ...defaultProps, + }, +}; + +export const WithReactHookForm = { + render: WithReactHookFormTemplate, + + args: { + ...defaultProps, + }, +}; + export const CustomIconFunction = { args: { ...defaultProps, @@ -133,3 +228,12 @@ export const Controlled = { ...defaultProps, }, }; + +export const Required = { + render: FormTemplate, + + args: { + ...defaultProps, + isRequired: true, + }, +}; diff --git a/packages/components/chip/CHANGELOG.md b/packages/components/chip/CHANGELOG.md index 8c7438e047..666b87651b 100644 --- a/packages/components/chip/CHANGELOG.md +++ b/packages/components/chip/CHANGELOG.md @@ -1,5 +1,37 @@ # @nextui-org/chip +## 2.0.28 + +### Patch Changes + +- Updated dependencies [[`eccc2f2f3`](https://github.com/nextui-org/nextui/commit/eccc2f2f3d856eefb2cc7c07b94e1c4cefd4d7d0)]: + - @nextui-org/react-utils@2.0.13 + +## 2.0.27 + +### Patch Changes + +- Updated dependencies []: + - @nextui-org/react-utils@2.0.12 + +## 2.0.26 + +### Patch Changes + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - v2.3.0 + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - - Calendar component added + - objectToDeps function applied all across components + - `useMeasure` hook added + - `useIntersectionObserver` hook added + - `framer-transitions` renamed to `framer-utils` + - `ResizablePanel` component added to `framer-utils` + - `test-utils` updated +- Updated dependencies [[`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14), [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14)]: + - @nextui-org/react-utils@2.0.11 + - @nextui-org/shared-icons@2.0.7 + - @nextui-org/shared-utils@2.0.5 + ## 2.0.25 ### Patch Changes diff --git a/packages/components/chip/package.json b/packages/components/chip/package.json index 0de2778cf7..9a2575f325 100644 --- a/packages/components/chip/package.json +++ b/packages/components/chip/package.json @@ -1,6 +1,6 @@ { "name": "@nextui-org/chip", - "version": "2.0.25", + "version": "2.0.28", "description": "Chips help people enter information, make selections, filter content, or trigger actions.", "keywords": [ "chip" @@ -43,11 +43,10 @@ "@nextui-org/shared-icons": "workspace:*", "@nextui-org/shared-utils": "workspace:*", "@nextui-org/react-utils": "workspace:*", - "@nextui-org/use-aria-press": "workspace:*", - "@react-aria/focus": "^3.14.3", - "@react-aria/interactions": "^3.19.1", - "@react-aria/utils": "^3.21.1", - "@react-types/checkbox": "^3.5.2" + "@react-aria/focus": "^3.16.2", + "@react-aria/interactions": "^3.21.1", + "@react-aria/utils": "^3.23.2", + "@react-types/checkbox": "^3.7.1" }, "devDependencies": { "@nextui-org/theme": "workspace:*", diff --git a/packages/components/chip/src/use-chip.ts b/packages/components/chip/src/use-chip.ts index 2a7e2d11d2..53eaa07db4 100644 --- a/packages/components/chip/src/use-chip.ts +++ b/packages/components/chip/src/use-chip.ts @@ -3,11 +3,11 @@ import type {ReactNode} from "react"; import {HTMLNextUIProps, mapPropsVariants, PropGetter} from "@nextui-org/system"; import {mergeProps} from "@react-aria/utils"; -import {usePress} from "@nextui-org/use-aria-press"; +import {usePress} from "@react-aria/interactions"; import {useFocusRing} from "@react-aria/focus"; import {chip} from "@nextui-org/theme"; import {useDOMRef} from "@nextui-org/react-utils"; -import {clsx} from "@nextui-org/shared-utils"; +import {clsx, objectToDeps} from "@nextui-org/shared-utils"; import {ReactRef} from "@nextui-org/react-utils"; import {useMemo, isValidElement, cloneElement} from "react"; import {PressEvent} from "@react-types/shared"; @@ -103,7 +103,7 @@ export function useChip(originalProps: UseChipProps) { isCloseButtonFocusVisible, }), [ - ...Object.values(variantProps), + objectToDeps(variantProps), isCloseButtonFocusVisible, hasStartContent, hasEndContent, diff --git a/packages/components/code/CHANGELOG.md b/packages/components/code/CHANGELOG.md index 144a47e462..a21ad53be4 100644 --- a/packages/components/code/CHANGELOG.md +++ b/packages/components/code/CHANGELOG.md @@ -1,5 +1,39 @@ # @nextui-org/code +## 2.0.27 + +### Patch Changes + +- Updated dependencies [[`eccc2f2f3`](https://github.com/nextui-org/nextui/commit/eccc2f2f3d856eefb2cc7c07b94e1c4cefd4d7d0)]: + - @nextui-org/react-utils@2.0.13 + - @nextui-org/system-rsc@2.1.1 + +## 2.0.26 + +### Patch Changes + +- Updated dependencies [[`74eda3128`](https://github.com/nextui-org/nextui/commit/74eda312883b2e17df26f71442aba9fb3cd240be)]: + - @nextui-org/system-rsc@2.1.1 + - @nextui-org/react-utils@2.0.12 + +## 2.0.25 + +### Patch Changes + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - v2.3.0 + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - - Calendar component added + - objectToDeps function applied all across components + - `useMeasure` hook added + - `useIntersectionObserver` hook added + - `framer-transitions` renamed to `framer-utils` + - `ResizablePanel` component added to `framer-utils` + - `test-utils` updated +- Updated dependencies [[`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14), [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14), [`c5049edfd`](https://github.com/nextui-org/nextui/commit/c5049edfde7edaee2081d70e581739be9dcae2f9)]: + - @nextui-org/system-rsc@2.1.0 + - @nextui-org/react-utils@2.0.11 + - @nextui-org/shared-utils@2.0.5 + ## 2.0.24 ### Patch Changes diff --git a/packages/components/code/package.json b/packages/components/code/package.json index 0f471bc37a..4e2e5d2542 100644 --- a/packages/components/code/package.json +++ b/packages/components/code/package.json @@ -1,6 +1,6 @@ { "name": "@nextui-org/code", - "version": "2.0.24", + "version": "2.0.27", "description": "Code is a component used to display inline code.", "keywords": [ "code" diff --git a/packages/components/code/src/use-code.ts b/packages/components/code/src/use-code.ts index a4c4e329e5..7075416aeb 100644 --- a/packages/components/code/src/use-code.ts +++ b/packages/components/code/src/use-code.ts @@ -5,6 +5,7 @@ import {code} from "@nextui-org/theme"; import {mapPropsVariants} from "@nextui-org/system-rsc"; import {ReactRef} from "@nextui-org/react-utils"; import {useMemo} from "react"; +import {objectToDeps} from "@nextui-org/shared-utils"; export interface UseCodeProps extends HTMLNextUIProps<"code">, CodeVariantProps { /** @@ -26,7 +27,7 @@ export function useCode(originalProps: UseCodeProps) { ...variantProps, className, }), - [...Object.values(variantProps), className], + [objectToDeps(variantProps), className], ); const getCodeProps: PropGetter = () => { diff --git a/packages/components/date-input/CHANGELOG.md b/packages/components/date-input/CHANGELOG.md new file mode 100644 index 0000000000..3c6eb212ec --- /dev/null +++ b/packages/components/date-input/CHANGELOG.md @@ -0,0 +1,25 @@ +# @nextui-org/date-input + +## 2.0.3 + +### Patch Changes + +- Updated dependencies [[`eccc2f2f3`](https://github.com/nextui-org/nextui/commit/eccc2f2f3d856eefb2cc7c07b94e1c4cefd4d7d0)]: + - @nextui-org/react-utils@2.0.13 + +## 2.0.2 + +### Patch Changes + +- Updated dependencies []: + - @nextui-org/react-utils@2.0.12 + +## 2.0.1 + +### Patch Changes + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - v2.3.0 + +- Updated dependencies [[`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14), [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14)]: + - @nextui-org/react-utils@2.0.11 + - @nextui-org/shared-utils@2.0.5 diff --git a/packages/components/date-input/README.md b/packages/components/date-input/README.md new file mode 100644 index 0000000000..aae96a1319 --- /dev/null +++ b/packages/components/date-input/README.md @@ -0,0 +1,22 @@ +# @nextui-org/date-input + +A date input allows users to enter and edit date and time values using a keyboard. + +## Installation + +```sh +yarn add @nextui-org/date-input +# or +npm i @nextui-org/date-input +``` + +## Contribution + +Yes please! See the +[contributing guidelines](https://github.com/nextui-org/nextui/blob/master/CONTRIBUTING.md) +for details. + +## License + +This project is licensed under the terms of the +[MIT license](https://github.com/nextui-org/nextui/blob/master/LICENSE). diff --git a/packages/components/date-input/__tests__/date-input.test.tsx b/packages/components/date-input/__tests__/date-input.test.tsx new file mode 100644 index 0000000000..aa48657e87 --- /dev/null +++ b/packages/components/date-input/__tests__/date-input.test.tsx @@ -0,0 +1,355 @@ +/* eslint-disable jsx-a11y/no-autofocus */ +import * as React from "react"; +import {act, fireEvent, render} from "@testing-library/react"; +import {CalendarDate, CalendarDateTime, DateValue, ZonedDateTime} from "@internationalized/date"; +import {pointerMap, triggerPress} from "@nextui-org/test-utils"; +import userEvent from "@testing-library/user-event"; + +import {DateInput as DateInputBase, DateInputProps} from "../src"; + +/** + * Custom date-input to disable animations and avoid issues with react-motion and jest + */ +const DateInput = React.forwardRef((props: DateInputProps, ref: React.Ref) => { + return ; +}); + +DateInput.displayName = "DateInput"; + +describe("DateInput", () => { + let user; + + beforeAll(() => { + user = userEvent.setup({delay: null, pointerMap}); + jest.useFakeTimers(); + }); + + describe("Basics", () => { + it("should render correctly", () => { + const wrapper = render(); + + expect(() => wrapper.unmount()).not.toThrow(); + }); + + it("ref should be forwarded", () => { + const ref = React.createRef(); + + render(); + expect(ref.current).not.toBeNull(); + }); + + it("should support autoFocus", function () { + let {getAllByRole} = render(); + + expect(document.activeElement).toBe(getAllByRole("spinbutton")[0]); + }); + + it("should pass through data attributes", function () { + let {getByTestId} = render(); + + const input = getByTestId("foo"); + + expect(input).toHaveAttribute("role", "group"); + }); + + it("should show as invalid if an unavailable date is given", async function () { + let tree = render( + { + return ( + date.compare(new CalendarDate(1980, 1, 1)) >= 0 && + date.compare(new CalendarDate(1980, 1, 8)) <= 0 + ); + }} + />, + ); + + await act(async () => { + await user.tab(); + }); + + await act(async () => { + await user.keyboard("01011980"); + }); + + expect(tree.getByText("Date unavailable.")).toBeInTheDocument(); + }); + }); + + describe("Labelling", () => { + it("should support labeling", function () { + let {getAllByRole, getByText} = render(); + + let label = getByText("Date"); + + let combobox = getAllByRole("group")[0]; + + expect(combobox).toHaveAttribute("aria-labelledby", label.id); + + let segments = getAllByRole("spinbutton"); + + for (let segment of segments) { + expect(segment).toHaveAttribute("id"); + let segmentId = segment.getAttribute("id"); + + expect(segment).toHaveAttribute("aria-labelledby", `${segmentId} ${label.id}`); + } + }); + + it("should support labeling with aria-label", function () { + let {getByRole} = render(); + + let field = getByRole("group"); + + expect(field).toHaveAttribute("aria-label", "Birth date"); + expect(field).toHaveAttribute("id"); + }); + + it("should support labeling with aria-labelledby", function () { + let {getByRole, getAllByRole} = render(); + + let combobox = getByRole("group"); + + expect(combobox).not.toHaveAttribute("aria-label"); + expect(combobox).toHaveAttribute("aria-labelledby", "foo"); + + let segments = getAllByRole("spinbutton"); + + for (let segment of segments) { + expect(segment).toHaveAttribute("id"); + let segmentId = segment.getAttribute("id"); + + expect(segment).toHaveAttribute("aria-labelledby", `${segmentId} foo`); + } + }); + + it("should support help text description", function () { + let {getByRole, getAllByRole} = render(); + + let group = getByRole("group"); + + expect(group).toHaveAttribute("aria-describedby"); + + const descById = group.getAttribute("aria-describedby"); + + let description = descById && document.getElementById(descById); + + expect(description).toHaveTextContent("Help text"); + + let segments = getAllByRole("spinbutton"); + + expect(segments[0]).toHaveAttribute( + "aria-describedby", + group.getAttribute("aria-describedby"), + ); + + for (let segment of segments.slice(1)) { + expect(segment).not.toHaveAttribute("aria-describedby"); + } + }); + + it("should support error message", function () { + let {getByRole, getAllByRole} = render( + , + ); + + let group = getByRole("group"); + + expect(group).toHaveAttribute("aria-describedby"); + + if (group) { + let descById = group.getAttribute("aria-describedby"); + let description = descById && document.getElementById(descById); + + expect(description).toHaveTextContent("Error message"); + + let segments = getAllByRole("spinbutton"); + + for (let segment of segments) { + expect(segment).toHaveAttribute( + "aria-describedby", + group.getAttribute("aria-describedby"), + ); + } + } + }); + }); + + describe("Events", function () { + let onBlurSpy = jest.fn(); + let onFocusChangeSpy = jest.fn(); + let onFocusSpy = jest.fn(); + let onKeyDownSpy = jest.fn(); + let onKeyUpSpy = jest.fn(); + + afterEach(() => { + onBlurSpy.mockClear(); + onFocusChangeSpy.mockClear(); + onFocusSpy.mockClear(); + onKeyDownSpy.mockClear(); + onKeyUpSpy.mockClear(); + }); + + it("should focus field and switching segments via tab does not change focus", async function () { + let {getAllByRole} = render( + , + ); + let segments = getAllByRole("spinbutton"); + + expect(onBlurSpy).not.toHaveBeenCalled(); + expect(onFocusChangeSpy).not.toHaveBeenCalled(); + expect(onFocusSpy).not.toHaveBeenCalled(); + await act(async () => { + await user.tab(); + }); + expect(segments[0]).toHaveFocus(); + + expect(onBlurSpy).not.toHaveBeenCalled(); + expect(onFocusChangeSpy).toHaveBeenCalledTimes(1); + expect(onFocusSpy).toHaveBeenCalledTimes(1); + await act(async () => { + await user.tab(); + }); + expect(segments[1]).toHaveFocus(); + expect(onBlurSpy).not.toHaveBeenCalled(); + expect(onFocusChangeSpy).toHaveBeenCalledTimes(1); + expect(onFocusSpy).toHaveBeenCalledTimes(1); + }); + + it("should call blur when focus leaves", async function () { + let {getAllByRole} = render( + , + ); + let segments = getAllByRole("spinbutton"); + + expect(onBlurSpy).not.toHaveBeenCalled(); + expect(onFocusChangeSpy).not.toHaveBeenCalled(); + expect(onFocusSpy).not.toHaveBeenCalled(); + await act(async () => { + await user.tab(); + }); + expect(segments[0]).toHaveFocus(); + await act(async () => { + await user.tab(); + }); + expect(segments[1]).toHaveFocus(); + await act(async () => { + await user.tab(); + }); + expect(segments[2]).toHaveFocus(); + expect(onBlurSpy).toHaveBeenCalledTimes(0); + await act(async () => { + await user.tab(); + }); + expect(onBlurSpy).toHaveBeenCalledTimes(1); + expect(onFocusChangeSpy).toHaveBeenCalledTimes(2); + expect(onFocusSpy).toHaveBeenCalledTimes(1); + }); + + it("should trigger right arrow key event for segment navigation", async function () { + let {getAllByRole} = render( + , + ); + let segments = getAllByRole("spinbutton"); + + expect(onKeyDownSpy).not.toHaveBeenCalled(); + expect(onKeyUpSpy).not.toHaveBeenCalled(); + + await act(() => { + user.tab(); + }); + + expect(segments[0]).toHaveFocus(); + expect(onKeyDownSpy).not.toHaveBeenCalled(); + expect(onKeyUpSpy).toHaveBeenCalledTimes(1); + + if (document.activeElement) { + fireEvent.keyDown(document.activeElement, {key: "ArrowRight"}); + fireEvent.keyUp(document.activeElement, {key: "ArrowRight"}); + } + expect(segments[1]).toHaveFocus(); + expect(onKeyDownSpy).toHaveBeenCalledTimes(1); + expect(onKeyUpSpy).toHaveBeenCalledTimes(2); + }); + }); + + describe("Forms", () => { + it("supports form values", () => { + let {rerender} = render( + , + ); + let input = document.querySelector("input[name=date]"); + + expect(input).toHaveValue("2020-02-03"); + + rerender( + , + ); + expect(input).toHaveValue("2020-02-03T08:30:00"); + + rerender( + , + ); + expect(input).toHaveValue("2020-02-03T12:24:45-08:00[America/Los_Angeles]"); + }); + + it("supports form reset", async () => { + function Test() { + let [value, setValue] = React.useState(new CalendarDate(2020, 2, 3)); + + return ( +
+ + + + ); + } + + let {getByTestId, getByRole, getAllByRole} = render(); + let group = getByRole("group"); + let input = document.querySelector("input[name=date]"); + let segments = getAllByRole("spinbutton"); + + let getDescription = () => + // @ts-ignore + group + .getAttribute("aria-describedby") + .split(" ") + // @ts-ignore + .map((d) => document.getElementById(d).textContent) + .join(" "); + + expect(getDescription()).toBe("Selected Date: February 03, 2020"); + + expect(input).toHaveValue("2020-02-03"); + expect(input).toHaveAttribute("name", "date"); + fireEvent.keyDown(segments[0], {key: "ArrowUp"}); + fireEvent.keyUp(segments[0], {key: "ArrowUp"}); + expect(getDescription()).toBe("Selected Date: March 03, 2020"); + expect(input).toHaveValue("2020-03-03"); + + let button = getByTestId("reset"); + + triggerPress(button); + + expect(getDescription()).toBe("Selected Date: February 03, 2020"); + expect(input).toHaveValue("2020-02-03"); + }); + }); +}); diff --git a/packages/components/date-input/__tests__/time-input.test.tsx b/packages/components/date-input/__tests__/time-input.test.tsx new file mode 100644 index 0000000000..d6bf5036a7 --- /dev/null +++ b/packages/components/date-input/__tests__/time-input.test.tsx @@ -0,0 +1,357 @@ +/* eslint-disable jsx-a11y/no-autofocus */ +import * as React from "react"; +import {act, fireEvent, render} from "@testing-library/react"; +import {Time, ZonedDateTime} from "@internationalized/date"; +import {TimeValue} from "@react-types/datepicker"; +import {pointerMap, triggerPress} from "@nextui-org/test-utils"; +import userEvent from "@testing-library/user-event"; + +import {TimeInput as TimeInputBase, TimeInputProps} from "../src"; + +/** + * Custom date-input to disable animations and avoid issues with react-motion and jest + */ +const TimeInput = React.forwardRef((props: TimeInputProps, ref: React.Ref) => { + return ; +}); + +TimeInput.displayName = "TimeInput"; + +describe("TimeInput", () => { + let user; + + beforeAll(() => { + user = userEvent.setup({delay: null, pointerMap}); + jest.useFakeTimers(); + }); + + describe("Basics", () => { + it("should render correctly", () => { + const wrapper = render(); + + expect(() => wrapper.unmount()).not.toThrow(); + }); + + it("ref should be forwarded", () => { + const ref = React.createRef(); + + render(); + expect(ref.current).not.toBeNull(); + }); + + it("should support autoFocus", function () { + let {getAllByRole} = render(); + + expect(document.activeElement).toBe(getAllByRole("spinbutton")[0]); + }); + + it("should pass through data attributes", function () { + let {getByTestId} = render(); + + const input = getByTestId("foo"); + + expect(input).toHaveAttribute("role", "group"); + }); + + it("should include a selected value description", function () { + let {getByRole, getAllByRole} = render(); + + let group = getByRole("group"); + + expect(group).toHaveAttribute("aria-describedby"); + + // @ts-ignore + let description = group + .getAttribute("aria-describedby") + .split(" ") + // @ts-ignore + .map((d) => document.getElementById(d).textContent) + .join(" "); + + expect(description).toBe("Selected Time: 8:45 AM"); + + let segments = getAllByRole("spinbutton"); + + expect(segments[0]).toHaveAttribute( + "aria-describedby", + group.getAttribute("aria-describedby"), + ); + + for (let segment of segments.slice(1)) { + expect(segment).not.toHaveAttribute("aria-describedby"); + } + }); + }); + + describe("Labelling", () => { + it("should support labeling", function () { + let {getAllByRole, getByText} = render(); + + let label = getByText("Time"); + + let combobox = getAllByRole("group")[0]; + + expect(combobox).toHaveAttribute("aria-labelledby", label.id); + + let segments = getAllByRole("spinbutton"); + + for (let segment of segments) { + expect(segment).toHaveAttribute("id"); + let segmentId = segment.getAttribute("id"); + + expect(segment).toHaveAttribute("aria-labelledby", `${segmentId} ${label.id}`); + } + }); + + it("should support labeling with aria-label", function () { + let {getByRole} = render(); + + let field = getByRole("group"); + + expect(field).toHaveAttribute("aria-label", "Event time"); + expect(field).toHaveAttribute("id"); + }); + + it("should support labeling with aria-labelledby", function () { + let {getByRole, getAllByRole} = render(); + + let combobox = getByRole("group"); + + expect(combobox).not.toHaveAttribute("aria-label"); + expect(combobox).toHaveAttribute("aria-labelledby", "foo"); + + let segments = getAllByRole("spinbutton"); + + for (let segment of segments) { + expect(segment).toHaveAttribute("id"); + let segmentId = segment.getAttribute("id"); + + expect(segment).toHaveAttribute("aria-labelledby", `${segmentId} foo`); + } + }); + + it("should support help text description", function () { + let {getByRole, getAllByRole} = render(); + + let group = getByRole("group"); + + expect(group).toHaveAttribute("aria-describedby"); + + const descById = group.getAttribute("aria-describedby"); + + let description = descById && document.getElementById(descById); + + expect(description).toHaveTextContent("Help text"); + + let segments = getAllByRole("spinbutton"); + + expect(segments[0]).toHaveAttribute( + "aria-describedby", + group.getAttribute("aria-describedby"), + ); + + for (let segment of segments.slice(1)) { + expect(segment).not.toHaveAttribute("aria-describedby"); + } + }); + + it("should support error message", function () { + let {getByRole, getAllByRole} = render( + , + ); + + let group = getByRole("group"); + + expect(group).toHaveAttribute("aria-describedby"); + + if (group) { + let descById = group.getAttribute("aria-describedby"); + let description = descById && document.getElementById(descById); + + expect(description).toHaveTextContent("Error message"); + + let segments = getAllByRole("spinbutton"); + + for (let segment of segments) { + expect(segment).toHaveAttribute( + "aria-describedby", + group.getAttribute("aria-describedby"), + ); + } + } + }); + }); + + describe("Events", function () { + let onBlurSpy = jest.fn(); + let onFocusChangeSpy = jest.fn(); + let onFocusSpy = jest.fn(); + let onKeyDownSpy = jest.fn(); + let onKeyUpSpy = jest.fn(); + + afterEach(() => { + onBlurSpy.mockClear(); + onFocusChangeSpy.mockClear(); + onFocusSpy.mockClear(); + onKeyDownSpy.mockClear(); + onKeyUpSpy.mockClear(); + }); + + it("should focus field and switching segments via tab does not change focus", async function () { + let {getAllByRole} = render( + , + ); + let segments = getAllByRole("spinbutton"); + + expect(onBlurSpy).not.toHaveBeenCalled(); + expect(onFocusChangeSpy).not.toHaveBeenCalled(); + expect(onFocusSpy).not.toHaveBeenCalled(); + await act(async () => { + await user.tab(); + }); + expect(segments[0]).toHaveFocus(); + + expect(onBlurSpy).not.toHaveBeenCalled(); + expect(onFocusChangeSpy).toHaveBeenCalledTimes(1); + expect(onFocusSpy).toHaveBeenCalledTimes(1); + await act(async () => { + await user.tab(); + }); + expect(segments[1]).toHaveFocus(); + expect(onBlurSpy).not.toHaveBeenCalled(); + expect(onFocusChangeSpy).toHaveBeenCalledTimes(1); + expect(onFocusSpy).toHaveBeenCalledTimes(1); + }); + + it("should call blur when focus leaves", async function () { + let {getAllByRole} = render( + , + ); + let segments = getAllByRole("spinbutton"); + + expect(onBlurSpy).not.toHaveBeenCalled(); + expect(onFocusChangeSpy).not.toHaveBeenCalled(); + expect(onFocusSpy).not.toHaveBeenCalled(); + await act(async () => { + await user.tab(); + }); + expect(segments[0]).toHaveFocus(); + await act(async () => { + await user.tab(); + }); + expect(segments[1]).toHaveFocus(); + await act(async () => { + await user.tab(); + }); + expect(segments[2]).toHaveFocus(); + expect(onBlurSpy).toHaveBeenCalledTimes(0); + await act(async () => { + await user.tab(); + }); + expect(onBlurSpy).toHaveBeenCalledTimes(1); + expect(onFocusChangeSpy).toHaveBeenCalledTimes(2); + expect(onFocusSpy).toHaveBeenCalledTimes(1); + }); + + it("should trigger right arrow key event for segment navigation", async function () { + let {getAllByRole} = render( + , + ); + let segments = getAllByRole("spinbutton"); + + expect(onKeyDownSpy).not.toHaveBeenCalled(); + expect(onKeyUpSpy).not.toHaveBeenCalled(); + + await act(() => { + user.tab(); + }); + + expect(segments[0]).toHaveFocus(); + expect(onKeyDownSpy).not.toHaveBeenCalled(); + expect(onKeyUpSpy).toHaveBeenCalledTimes(1); + + if (document.activeElement) { + fireEvent.keyDown(document.activeElement, {key: "ArrowRight"}); + fireEvent.keyUp(document.activeElement, {key: "ArrowRight"}); + } + expect(segments[1]).toHaveFocus(); + expect(onKeyDownSpy).toHaveBeenCalledTimes(1); + expect(onKeyUpSpy).toHaveBeenCalledTimes(2); + }); + }); + + describe("Forms", () => { + it("supports form values", () => { + let {rerender} = render(); + let input = document.querySelector("input[name=time]"); + + expect(input).toHaveValue("08:30:00"); + + rerender(); + expect(input).toHaveValue("12:24:45"); + + rerender( + , + ); + + expect(input).toHaveValue("12:24:45"); + }); + + it("supports form reset", async () => { + function Test() { + let [value, setValue] = React.useState(new Time(8, 30)); + + return ( +
+ + + + ); + } + + let {getByTestId, getByRole, getAllByRole} = render(); + let group = getByRole("group"); + let input = document.querySelector("input[name=time]"); + let segments = getAllByRole("spinbutton"); + + let getDescription = () => + // @ts-ignore + group + .getAttribute("aria-describedby") + .split(" ") + // @ts-ignore + .map((d) => document.getElementById(d).textContent) + .join(" "); + + expect(getDescription()).toBe("Selected Time: 8:30 AM"); + + expect(input).toHaveValue("08:30:00"); + expect(input).toHaveAttribute("name", "time"); + fireEvent.keyDown(segments[0], {key: "ArrowUp"}); + fireEvent.keyUp(segments[0], {key: "ArrowUp"}); + expect(getDescription()).toBe("Selected Time: 9:30 AM"); + expect(input).toHaveValue("09:30:00"); + + let button = getByTestId("reset"); + + triggerPress(button); + + expect(getDescription()).toBe("Selected Time: 8:30 AM"); + expect(input).toHaveValue("08:30:00"); + }); + }); +}); diff --git a/packages/components/date-input/package.json b/packages/components/date-input/package.json new file mode 100644 index 0000000000..ac708f65b6 --- /dev/null +++ b/packages/components/date-input/package.json @@ -0,0 +1,63 @@ +{ + "name": "@nextui-org/date-input", + "version": "2.0.3", + "description": "A date input allows users to enter and edit date and time values using a keyboard.", + "keywords": [ + "date-field" + ], + "author": "Junior Garcia ", + "homepage": "https://nextui.org", + "license": "MIT", + "main": "src/index.ts", + "sideEffects": false, + "files": [ + "dist" + ], + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/nextui-org/nextui.git", + "directory": "packages/components/date-input" + }, + "bugs": { + "url": "https://github.com/nextui-org/nextui/issues" + }, + "scripts": { + "build": "tsup src --dts", + "build:fast": "tsup src", + "dev": "pnpm build:fast --watch", + "clean": "rimraf dist .turbo", + "typecheck": "tsc --noEmit", + "prepack": "clean-package", + "postpack": "clean-package restore" + }, + "peerDependencies": { + "@nextui-org/system": ">=2.0.0", + "@nextui-org/theme": ">=2.0.0", + "react": ">=18", + "react-dom": ">=18" + }, + "dependencies": { + "@nextui-org/react-utils": "workspace:*", + "@nextui-org/shared-utils": "workspace:*", + "@internationalized/date": "^3.5.2", + "@react-aria/datepicker": "^3.9.3", + "@react-aria/i18n": "^3.8.4", + "@react-stately/datepicker": "^3.9.2", + "@react-types/datepicker": "^3.7.2", + "@react-types/shared": "3.21.0", + "@react-aria/utils": "^3.21.1" + }, + "devDependencies": { + "@nextui-org/system": "workspace:*", + "@nextui-org/theme": "workspace:*", + "@nextui-org/shared-icons": "workspace:*", + "@nextui-org/test-utils": "workspace:*", + "clean-package": "2.2.0", + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "clean-package": "../../../clean-package.config.json" +} diff --git a/packages/components/date-input/src/date-input-field.tsx b/packages/components/date-input/src/date-input-field.tsx new file mode 100644 index 0000000000..67982209f8 --- /dev/null +++ b/packages/components/date-input/src/date-input-field.tsx @@ -0,0 +1,45 @@ +import type {InputHTMLAttributes} from "react"; +import type {GroupDOMAttributes} from "@react-types/shared"; +import type {DateInputReturnType, DateInputSlots, SlotsToClasses} from "@nextui-org/theme"; +import type {DateFieldState} from "@react-stately/datepicker"; +import type {HTMLNextUIProps} from "@nextui-org/system"; + +import {forwardRef} from "react"; + +import {DateInputSegment} from "./date-input-segment"; + +type NextUIBaseProps = Omit, keyof GroupDOMAttributes | "onChange">; + +export interface DateInputFieldProps extends NextUIBaseProps, GroupDOMAttributes { + /** State for the date field. */ + state: DateFieldState; + /** Props for the hidden input element for HTML form submission. */ + inputProps: InputHTMLAttributes; + /** DateInput classes slots. */ + slots: DateInputReturnType; + /** DateInput classes. */ + classNames?: SlotsToClasses; +} + +export const DateInputField = forwardRef<"div", DateInputFieldProps>((props, ref) => { + const {as, state, slots, inputProps, classNames, ...otherProps} = props; + + const Component = as || "div"; + + return ( + + {state.segments.map((segment, i) => ( + + ))} + + + ); +}); + +DateInputField.displayName = "NextUI.DateInputField"; diff --git a/packages/components/date-input/src/date-input-group.tsx b/packages/components/date-input/src/date-input-group.tsx new file mode 100644 index 0000000000..f87c2b731d --- /dev/null +++ b/packages/components/date-input/src/date-input-group.tsx @@ -0,0 +1,111 @@ +import type {HTMLAttributes, ReactElement, ReactNode} from "react"; +import type {GroupDOMAttributes} from "@react-types/shared"; + +import {useMemo} from "react"; +import {forwardRef} from "@nextui-org/system"; +import {dataAttr} from "@nextui-org/shared-utils"; + +// TODO: Use HelpTextProps from "@react-types/shared"; once we upgrade react-aria packages to the latest version. +export interface ValidationResult { + /** Whether the input value is invalid. */ + isInvalid: boolean; + /** The current error messages for the input if it is invalid, otherwise an empty array. */ + validationErrors: string[]; + /** The native validation details for the input. */ + validationDetails: ValidityState; +} + +export interface DateInputGroupProps extends ValidationResult { + children?: ReactElement | ReactElement[]; + shouldLabelBeOutside?: boolean; + label?: ReactNode; + startContent?: React.ReactNode; + endContent?: React.ReactNode; + groupProps?: GroupDOMAttributes; + wrapperProps?: HTMLAttributes; // <- inner wrapper props + helperWrapperProps?: HTMLAttributes; + labelProps?: HTMLAttributes; + descriptionProps?: HTMLAttributes; + errorMessageProps?: HTMLAttributes; + /** A description for the field. Provides a hint such as specific requirements for what to choose. */ + description?: ReactNode; + /** An error message for the field. */ + errorMessage?: ReactNode | ((v: ValidationResult) => ReactNode); +} + +export const DateInputGroup = forwardRef<"div", DateInputGroupProps>((props, ref) => { + const { + as, + label, + children, + description, + startContent, + endContent, + errorMessage: errorMessageProp, + shouldLabelBeOutside, + isInvalid, + groupProps, + labelProps, + wrapperProps, + helperWrapperProps, + errorMessageProps, + descriptionProps, + validationErrors, + validationDetails, + ...otherProps + } = props; + + const Component = as || "div"; + + const labelContent = label ? {label} : null; + + const errorMessage = + typeof errorMessageProp === "function" + ? errorMessageProp({ + isInvalid, + validationErrors, + validationDetails, + }) + : errorMessageProp || validationErrors?.join(" "); + + const hasHelper = !!description || !!errorMessage; + + const helperWrapper = useMemo(() => { + if (!hasHelper) return null; + + return ( +
+ {errorMessage ? ( +
{errorMessage}
+ ) : description ? ( +
{description}
+ ) : null} +
+ ); + }, [ + hasHelper, + errorMessage, + description, + helperWrapperProps, + errorMessageProps, + descriptionProps, + ]); + + return ( + + {shouldLabelBeOutside ? labelContent : null} +
+ {!shouldLabelBeOutside ? labelContent : null} +
+ {startContent} + {children} + {endContent} +
+ {shouldLabelBeOutside ? helperWrapper : null} +
+ {!shouldLabelBeOutside ? helperWrapper : null} +
+ ); +}); + +DateInputGroup.displayName = "NextUI.DateInputGroup"; diff --git a/packages/components/date-input/src/date-input-segment.tsx b/packages/components/date-input/src/date-input-segment.tsx new file mode 100644 index 0000000000..ddb153c018 --- /dev/null +++ b/packages/components/date-input/src/date-input-segment.tsx @@ -0,0 +1,47 @@ +import type {DateInputReturnType, DateInputSlots, SlotsToClasses} from "@nextui-org/theme"; + +import {HTMLNextUIProps} from "@nextui-org/system"; +import {useDateSegment} from "@react-aria/datepicker"; +import {DateFieldState, DateSegment} from "@react-stately/datepicker"; +import {mergeProps} from "@react-aria/utils"; +import {useRef} from "react"; +import {dataAttr} from "@nextui-org/shared-utils"; + +export interface DateInputSegmentProps extends HTMLNextUIProps<"div"> { + state: DateFieldState; + segment: DateSegment; + slots: DateInputReturnType; + classNames?: SlotsToClasses; +} + +export const DateInputSegment: React.FC = ({ + state, + segment, + slots, + classNames, + ...otherProps +}) => { + const ref = useRef(null); + + let {segmentProps} = useDateSegment(segment, state, ref); + + return ( +
+ {segment.text} +
+ ); +}; diff --git a/packages/components/date-input/src/date-input.tsx b/packages/components/date-input/src/date-input.tsx new file mode 100644 index 0000000000..daa549d115 --- /dev/null +++ b/packages/components/date-input/src/date-input.tsx @@ -0,0 +1,39 @@ +import type {DateValue} from "@internationalized/date"; +import type {ForwardedRef, ReactElement, Ref} from "react"; + +import {forwardRef} from "@nextui-org/system"; + +import {UseDateInputProps, useDateInput} from "./use-date-input"; +import {DateInputGroup} from "./date-input-group"; +import {DateInputField} from "./date-input-field"; + +export interface Props extends UseDateInputProps {} + +function DateInput(props: Props, ref: ForwardedRef) { + const {state, slots, classNames, getBaseGroupProps, getInputProps, getFieldProps} = + useDateInput({ + ...props, + ref, + }); + + return ( + + + + ); +} + +DateInput.displayName = "NextUI.DateInput"; + +export type DateInputProps = Props & {ref?: Ref}; + +// forwardRef doesn't support generic parameters, so cast the result to the correct type +export default forwardRef(DateInput) as ( + props: DateInputProps, +) => ReactElement; diff --git a/packages/components/date-input/src/index.ts b/packages/components/date-input/src/index.ts new file mode 100644 index 0000000000..63409e3734 --- /dev/null +++ b/packages/components/date-input/src/index.ts @@ -0,0 +1,20 @@ +import DateInput from "./date-input"; +import TimeInput from "./time-input"; + +// export types +export type {DateInputProps} from "./date-input"; +export type {TimeInputProps} from "./time-input"; +export type {DateValue as DateInputValue} from "@react-types/datepicker"; +export type {TimeValue as TimeInputValue} from "@react-types/datepicker"; +export type {DateInputGroupProps} from "./date-input-group"; +export type {DateInputFieldProps} from "./date-input-field"; + +// export hooks +export {useDateInput} from "./use-date-input"; +export {useTimeInput} from "./use-time-input"; + +// export components +export {DateInputGroup} from "./date-input-group"; +export {DateInputField} from "./date-input-field"; +export {DateInputSegment} from "./date-input-segment"; +export {DateInput, TimeInput}; diff --git a/packages/components/date-input/src/time-input.tsx b/packages/components/date-input/src/time-input.tsx new file mode 100644 index 0000000000..a393fc7a17 --- /dev/null +++ b/packages/components/date-input/src/time-input.tsx @@ -0,0 +1,39 @@ +import type {TimeValue} from "@react-types/datepicker"; +import type {ForwardedRef, ReactElement, Ref} from "react"; + +import {forwardRef} from "@nextui-org/system"; + +import {UseTimeInputProps, useTimeInput} from "./use-time-input"; +import {DateInputField} from "./date-input-field"; +import {DateInputGroup} from "./date-input-group"; + +export interface Props extends UseTimeInputProps {} + +function TimeInput(props: Props, ref: ForwardedRef) { + const {state, slots, classNames, getBaseGroupProps, getInputProps, getFieldProps} = + useTimeInput({ + ...props, + ref, + }); + + return ( + + + + ); +} + +TimeInput.displayName = "NextUI.TimeInput"; + +export type TimeInputProps = Props & {ref?: Ref}; + +// forwardRef doesn't support generic parameters, so cast the result to the correct type +export default forwardRef(TimeInput) as ( + props: TimeInputProps, +) => ReactElement; diff --git a/packages/components/date-input/src/use-date-input.ts b/packages/components/date-input/src/use-date-input.ts new file mode 100644 index 0000000000..f250153eb7 --- /dev/null +++ b/packages/components/date-input/src/use-date-input.ts @@ -0,0 +1,320 @@ +import type {DateInputVariantProps, DateInputSlots, SlotsToClasses} from "@nextui-org/theme"; +import type {AriaDateFieldProps} from "@react-types/datepicker"; +import type {SupportedCalendars} from "@nextui-org/system"; +import type {DateValue, Calendar} from "@internationalized/date"; +import type {ReactRef} from "@nextui-org/react-utils"; +import type {DOMAttributes, GroupDOMAttributes} from "@react-types/shared"; +import type {DateInputGroupProps} from "./date-input-group"; + +import {useLocale} from "@react-aria/i18n"; +import {CalendarDate} from "@internationalized/date"; +import {mergeProps} from "@react-aria/utils"; +import {PropGetter, useProviderContext} from "@nextui-org/system"; +import {HTMLNextUIProps, mapPropsVariants} from "@nextui-org/system"; +import {useDOMRef} from "@nextui-org/react-utils"; +import {useDateField as useAriaDateField} from "@react-aria/datepicker"; +import {useDateFieldState} from "@react-stately/datepicker"; +import {createCalendar} from "@internationalized/date"; +import {objectToDeps, clsx, dataAttr} from "@nextui-org/shared-utils"; +import {dateInput} from "@nextui-org/theme"; +import {useMemo} from "react"; + +type NextUIBaseProps = Omit< + HTMLNextUIProps<"div">, + keyof AriaDateFieldProps | "onChange" +>; + +interface Props extends NextUIBaseProps { + /** + * Ref to the DOM node. + */ + ref?: ReactRef; + /** Props for the grouping element containing the date field and button. */ + groupProps?: GroupDOMAttributes; + /** Props for the date picker's visible label element, if any. */ + labelProps?: DOMAttributes; + /** Props for the date field. */ + fieldProps?: DOMAttributes; + /** Props for the description element, if any. */ + descriptionProps?: DOMAttributes; + /** Props for the error message element, if any. */ + errorMessageProps?: DOMAttributes; + /** + * The value of the hidden input. + */ + inputRef?: ReactRef; + /** + * Element to be rendered in the left side of the input. + */ + startContent?: React.ReactNode; + /** + * Element to be rendered in the right side of the input. + */ + endContent?: React.ReactNode; + /** + * This function helps to reduce the bundle size by providing a custom calendar system. + * + * In the example above, the createCalendar function from the `@internationalized/date` package + * is passed to the useCalendarState hook. This function receives a calendar identifier string, + * and provides Calendar instances to React Stately, which are used to implement date manipulation. + * + * By default, this includes all calendar systems supported by @internationalized/date. However, + * if your application supports a more limited set of regions, or you know you will only be picking dates + * in a certain calendar system, you can reduce your bundle size by providing your own implementation + * of `createCalendar` that includes a subset of these Calendar implementations. + * + * For example, if your application only supports Gregorian dates, you could implement a `createCalendar` + * function like this: + * + * @example + * + * import {GregorianCalendar} from '@internationalized/date'; + * + * function createCalendar(identifier) { + * switch (identifier) { + * case 'gregory': + * return new GregorianCalendar(); + * default: + * throw new Error(`Unsupported calendar ${identifier}`); + * } + * } + * + * This way, only GregorianCalendar is imported, and the other calendar implementations can be tree-shaken. + * + * You can also use the NextUIProvider to provide the createCalendar function to all nested components. + * + * @default all calendars + */ + createCalendar?: (calendar: SupportedCalendars) => Calendar | null; + /** + * Classname or List of classes to change the classNames of the element. + * if `className` is passed, it will be added to the base slot. + * + * @example + * ```ts + * + * ``` + */ + classNames?: SlotsToClasses; +} + +export type UseDateInputProps = Props & + DateInputVariantProps & + AriaDateFieldProps; + +export function useDateInput(originalProps: UseDateInputProps) { + const [props, variantProps] = mapPropsVariants(originalProps, dateInput.variantKeys); + + const providerContext = useProviderContext(); + + const { + ref, + as, + label, + inputRef: inputRefProp, + description, + startContent, + endContent, + className, + classNames, + validationState, + groupProps = {}, + labelProps: labelPropsProp, + fieldProps: fieldPropsProp, + errorMessageProps: errorMessagePropsProp, + descriptionProps: descriptionPropsProp, + validationBehavior, + shouldForceLeadingZeros = true, + minValue = providerContext?.defaultDates?.minDate ?? new CalendarDate(1900, 1, 1), + maxValue = providerContext?.defaultDates?.maxDate ?? new CalendarDate(2099, 12, 31), + createCalendar: createCalendarProp = providerContext?.createCalendar ?? null, + isInvalid: isInvalidProp = validationState ? validationState === "invalid" : false, + errorMessage, + } = props; + + const domRef = useDOMRef(ref); + const inputRef = useDOMRef(inputRefProp); + + const {locale} = useLocale(); + + const state = useDateFieldState({ + ...originalProps, + label, + locale, + minValue, + maxValue, + validationBehavior, + isInvalid: isInvalidProp, + shouldForceLeadingZeros, + createCalendar: + !createCalendarProp || typeof createCalendarProp !== "function" + ? createCalendar + : (createCalendarProp as typeof createCalendar), + }); + + const { + labelProps, + fieldProps, + inputProps, + validationErrors, + validationDetails, + descriptionProps, + errorMessageProps, + isInvalid: ariaIsInvalid, + } = useAriaDateField({...originalProps, label, validationBehavior, inputRef}, state, domRef); + + const baseStyles = clsx(classNames?.base, className); + + const isInvalid = isInvalidProp || ariaIsInvalid; + + const labelPlacement = useMemo(() => { + if ( + (!originalProps.labelPlacement || originalProps.labelPlacement === "inside") && + !props.label + ) { + return "outside"; + } + + return originalProps.labelPlacement ?? "inside"; + }, [originalProps.labelPlacement, props.label]); + + const shouldLabelBeOutside = labelPlacement === "outside" || labelPlacement === "outside-left"; + + const slots = useMemo( + () => + dateInput({ + ...variantProps, + labelPlacement, + className, + }), + [objectToDeps(variantProps), labelPlacement, className], + ); + + const getLabelProps: PropGetter = (props) => { + return { + ...mergeProps(labelProps, labelPropsProp, props), + "data-slot": "label", + className: slots.label({ + class: clsx(classNames?.label, props?.className), + }), + }; + }; + + const getInputProps: PropGetter = (props) => { + return { + ...props, + ...inputProps, + ref: inputRef, + }; + }; + + const getFieldProps = (props: DOMAttributes = {}) => { + return { + ref: domRef, + "data-slot": "input-field", + ...mergeProps(fieldProps, fieldPropsProp, props), + className: slots.input({ + class: clsx(classNames?.input, props?.className), + }), + } as GroupDOMAttributes; + }; + + const getInputWrapperProps = (props = {}) => { + return { + ...props, + ...groupProps, + "data-slot": "input-wrapper", + className: slots.inputWrapper({ + class: classNames?.inputWrapper, + }), + onClick: fieldProps.onClick, + } as GroupDOMAttributes; + }; + + const getInnerWrapperProps: PropGetter = (props) => { + return { + ...props, + "data-slot": "inner-wrapper", + className: slots.innerWrapper({ + class: classNames?.innerWrapper, + }), + }; + }; + + const getHelperWrapperProps: PropGetter = (props) => { + return { + ...props, + "data-slot": "helper-wrapper", + className: slots.helperWrapper({ + class: clsx(classNames?.helperWrapper, props?.className), + }), + }; + }; + + const getErrorMessageProps: PropGetter = (props = {}) => { + return { + ...mergeProps(errorMessageProps, errorMessagePropsProp, props), + "data-slot": "error-message", + className: slots.errorMessage({class: clsx(classNames?.errorMessage, props?.className)}), + }; + }; + + const getDescriptionProps: PropGetter = (props = {}) => { + return { + ...mergeProps(descriptionProps, descriptionPropsProp, props), + "data-slot": "description", + className: slots.description({class: clsx(classNames?.description, props?.className)}), + }; + }; + + const getBaseGroupProps = () => { + return { + as, + label, + description, + endContent, + errorMessage, + isInvalid, + startContent, + validationDetails, + validationErrors, + shouldLabelBeOutside, + "data-slot": "base", + "data-required": dataAttr(originalProps.isRequired), + "data-disabled": dataAttr(originalProps.isDisabled), + "data-readonly": dataAttr(originalProps.isReadOnly), + "data-invalid": dataAttr(isInvalid), + "data-has-start-content": dataAttr(!!startContent), + "data-has-end-content": dataAttr(!!endContent), + descriptionProps: getDescriptionProps(), + errorMessageProps: getErrorMessageProps(), + groupProps: getInputWrapperProps(), + helperWrapperProps: getHelperWrapperProps(), + labelProps: getLabelProps(), + wrapperProps: getInnerWrapperProps(), + className: slots.base({class: baseStyles}), + } as DateInputGroupProps; + }; + + return { + state, + domRef, + slots, + classNames, + labelPlacement, + getBaseGroupProps, + getFieldProps, + getInputProps, + }; +} + +export type UseDateInputReturn = ReturnType; diff --git a/packages/components/date-input/src/use-time-input.ts b/packages/components/date-input/src/use-time-input.ts new file mode 100644 index 0000000000..4f15ec5723 --- /dev/null +++ b/packages/components/date-input/src/use-time-input.ts @@ -0,0 +1,277 @@ +import type {DateInputVariantProps, DateInputSlots, SlotsToClasses} from "@nextui-org/theme"; +import type {AriaTimeFieldProps, TimeValue} from "@react-types/datepicker"; +import type {ReactRef} from "@nextui-org/react-utils"; +import type {DOMAttributes, GroupDOMAttributes} from "@react-types/shared"; +import type {DateInputGroupProps} from "./date-input-group"; + +import {useLocale} from "@react-aria/i18n"; +import {mergeProps} from "@react-aria/utils"; +import {PropGetter} from "@nextui-org/system"; +import {HTMLNextUIProps, mapPropsVariants} from "@nextui-org/system"; +import {useDOMRef} from "@nextui-org/react-utils"; +import {useTimeField as useAriaTimeField} from "@react-aria/datepicker"; +import {useTimeFieldState} from "@react-stately/datepicker"; +import {objectToDeps, clsx, dataAttr} from "@nextui-org/shared-utils"; +import {dateInput} from "@nextui-org/theme"; +import {useMemo} from "react"; + +type NextUIBaseProps = Omit< + HTMLNextUIProps<"div">, + keyof AriaTimeFieldProps | "onChange" +>; + +interface Props extends NextUIBaseProps { + /** + * Ref to the DOM node. + */ + ref?: ReactRef; + /** Props for the grouping element containing the date field and button. */ + groupProps?: GroupDOMAttributes; + /** Props for the date picker's visible label element, if any. */ + labelProps?: DOMAttributes; + /** Props for the date field. */ + fieldProps?: DOMAttributes; + /** Props for the description element, if any. */ + descriptionProps?: DOMAttributes; + /** Props for the error message element, if any. */ + errorMessageProps?: DOMAttributes; + /** + * The value of the hidden input. + */ + inputRef?: ReactRef; + /** + * Element to be rendered in the left side of the input. + */ + startContent?: React.ReactNode; + /** + * Element to be rendered in the right side of the input. + */ + endContent?: React.ReactNode; + /** + * Classname or List of classes to change the classNames of the element. + * if `className` is passed, it will be added to the base slot. + * + * @example + * ```ts + * + * ``` + */ + classNames?: SlotsToClasses; +} + +export type UseTimeInputProps = Props & + DateInputVariantProps & + Omit, "validationBehavior">; + +export function useTimeInput(originalProps: UseTimeInputProps) { + const [props, variantProps] = mapPropsVariants(originalProps, dateInput.variantKeys); + + const { + ref, + as, + label, + inputRef: inputRefProp, + description, + startContent, + endContent, + className, + classNames, + validationState, + groupProps = {}, + labelProps: labelPropsProp, + fieldProps: fieldPropsProp, + errorMessageProps: errorMessagePropsProp, + descriptionProps: descriptionPropsProp, + // validationBehavior = "native", TODO: Uncomment this one we support `native` and `aria` validations + shouldForceLeadingZeros = true, + minValue, + maxValue, + isInvalid: isInvalidProp = validationState ? validationState === "invalid" : false, + errorMessage, + } = props; + + const domRef = useDOMRef(ref); + const inputRef = useDOMRef(inputRefProp); + + const {locale} = useLocale(); + + const state = useTimeFieldState({ + ...originalProps, + label, + locale, + minValue, + maxValue, + isInvalid: isInvalidProp, + shouldForceLeadingZeros, + }); + + const { + labelProps, + fieldProps, + inputProps, + validationErrors, + validationDetails, + descriptionProps, + errorMessageProps, + isInvalid: ariaIsInvalid, + } = useAriaTimeField( + {...originalProps, label, validationBehavior: "native", inputRef}, + state, + domRef, + ); + + const baseStyles = clsx(classNames?.base, className); + + const isInvalid = isInvalidProp || ariaIsInvalid; + + const labelPlacement = useMemo(() => { + if ( + (!originalProps.labelPlacement || originalProps.labelPlacement === "inside") && + !props.label + ) { + return "outside"; + } + + return originalProps.labelPlacement ?? "inside"; + }, [originalProps.labelPlacement, props.label]); + + const shouldLabelBeOutside = labelPlacement === "outside" || labelPlacement === "outside-left"; + + const slots = useMemo( + () => + dateInput({ + ...variantProps, + labelPlacement, + className, + }), + [objectToDeps(variantProps), labelPlacement, className], + ); + + const getLabelProps: PropGetter = (props) => { + return { + ...mergeProps(labelProps, labelPropsProp, props), + "data-slot": "label", + className: slots.label({ + class: clsx(classNames?.label, props?.className), + }), + }; + }; + + const getInputProps: PropGetter = (props) => { + return { + ...props, + ...inputProps, + ref: inputRef, + }; + }; + + const getFieldProps = (props: DOMAttributes = {}) => { + return { + ref: domRef, + "data-slot": "input", + ...mergeProps(fieldProps, fieldPropsProp, props), + className: slots.input({ + class: clsx(classNames?.input, props?.className), + }), + } as GroupDOMAttributes; + }; + + const getInputWrapperProps = (props = {}) => { + return { + ...props, + ...groupProps, + "data-slot": "input-wrapper", + className: slots.inputWrapper({ + class: classNames?.inputWrapper, + }), + onClick: fieldProps.onClick, + } as GroupDOMAttributes; + }; + + const getInnerWrapperProps: PropGetter = (props) => { + return { + ...props, + "data-slot": "inner-wrapper", + className: slots.innerWrapper({ + class: classNames?.innerWrapper, + }), + }; + }; + + const getHelperWrapperProps: PropGetter = (props) => { + return { + ...props, + "data-slot": "helper-wrapper", + className: slots.helperWrapper({ + class: clsx(classNames?.helperWrapper, props?.className), + }), + }; + }; + + const getErrorMessageProps: PropGetter = (props = {}) => { + return { + ...mergeProps(errorMessageProps, errorMessagePropsProp, props), + "data-slot": "error-message", + className: slots.errorMessage({class: clsx(classNames?.errorMessage, props?.className)}), + }; + }; + + const getDescriptionProps: PropGetter = (props = {}) => { + return { + ...mergeProps(descriptionProps, descriptionPropsProp, props), + "data-slot": "description", + className: slots.description({class: clsx(classNames?.description, props?.className)}), + }; + }; + + const getBaseGroupProps = () => { + return { + as, + label, + description, + endContent, + errorMessage, + isInvalid, + startContent, + validationDetails, + validationErrors, + shouldLabelBeOutside, + "data-slot": "base", + "data-required": dataAttr(originalProps.isRequired), + "data-disabled": dataAttr(originalProps.isDisabled), + "data-readonly": dataAttr(originalProps.isReadOnly), + "data-invalid": dataAttr(isInvalid), + "data-has-start-content": dataAttr(!!startContent), + "data-has-end-content": dataAttr(!!endContent), + descriptionProps: getDescriptionProps(), + errorMessageProps: getErrorMessageProps(), + groupProps: getInputWrapperProps(), + helperWrapperProps: getHelperWrapperProps(), + labelProps: getLabelProps(), + wrapperProps: getInnerWrapperProps(), + className: slots.base({class: baseStyles}), + } as DateInputGroupProps; + }; + + return { + state, + domRef, + slots, + classNames, + labelPlacement, + getBaseGroupProps, + getFieldProps, + getInputProps, + }; +} + +export type UseTimeInputReturn = ReturnType; diff --git a/packages/components/date-input/stories/date-input.stories.tsx b/packages/components/date-input/stories/date-input.stories.tsx new file mode 100644 index 0000000000..a23e4e211b --- /dev/null +++ b/packages/components/date-input/stories/date-input.stories.tsx @@ -0,0 +1,339 @@ +import React from "react"; +import {Meta} from "@storybook/react"; +import {dateInput} from "@nextui-org/theme"; +import { + CalendarDate, + DateValue, + getLocalTimeZone, + now, + parseAbsoluteToLocal, + parseDate, + parseZonedDateTime, + today, +} from "@internationalized/date"; +import {CalendarBoldIcon} from "@nextui-org/shared-icons"; +import {useDateFormatter, I18nProvider} from "@react-aria/i18n"; + +import {DateInput, DateInputProps} from "../src"; + +export default { + title: "Components/DateInput", + component: DateInput, + argTypes: { + variant: { + control: { + type: "select", + }, + options: ["flat", "faded", "bordered", "underlined"], + }, + color: { + control: { + type: "select", + }, + options: ["default", "primary", "secondary", "success", "warning", "danger"], + }, + radius: { + control: { + type: "select", + }, + options: ["none", "sm", "md", "lg", "full"], + }, + size: { + control: { + type: "select", + }, + options: ["sm", "md", "lg"], + }, + labelPlacement: { + control: { + type: "select", + }, + options: ["inside", "outside", "outside-left"], + }, + isDisabled: { + control: { + type: "boolean", + }, + }, + }, +} as Meta; + +const defaultProps = { + label: "Birth date", + ...dateInput.defaultVariants, +}; + +const Template = (args: DateInputProps) => ( + +); + +const LabelPlacementTemplate = (args: DateInputProps) => ( +
+ + + +
+); + +const ControlledTemplate = (args: DateInputProps) => { + const [value, setValue] = React.useState(parseDate("2024-04-04")); + + let formatter = useDateFormatter({dateStyle: "full"}); + + return ( +
+
+ +

+ Selected date: {value ? formatter.format(value.toDate(getLocalTimeZone())) : "--"} +

+
+ +
+ ); +}; + +const TimeZonesTemplate = (args: DateInputProps) => ( +
+ + +
+); + +const GranularityTemplate = (args: DateInputProps) => { + let [date, setDate] = React.useState(parseAbsoluteToLocal("2021-04-07T18:45:22Z")); + + return ( +
+ + + + +
+ ); +}; + +const InternationalCalendarsTemplate = (args: DateInputProps) => { + let [date, setDate] = React.useState(parseAbsoluteToLocal("2021-04-07T18:45:22Z")); + + return ( +
+ + + +
+ ); +}; + +export const Default = { + render: Template, + args: { + ...defaultProps, + }, +}; + +export const Required = { + render: Template, + args: { + ...defaultProps, + isRequired: true, + }, +}; + +export const Disabled = { + render: Template, + args: { + ...defaultProps, + isDisabled: true, + defaultValue: parseDate("2024-04-04"), + }, +}; + +export const ReadOnly = { + render: Template, + args: { + ...defaultProps, + isReadOnly: true, + defaultValue: parseDate("2024-04-04"), + }, +}; + +export const WithoutLabel = { + render: Template, + + args: { + ...defaultProps, + label: null, + "aria-label": "Birth date", + }, +}; + +export const WithDescription = { + render: Template, + + args: { + ...defaultProps, + description: "Please enter your birth date", + }, +}; + +export const LabelPlacement = { + render: LabelPlacementTemplate, + + args: { + ...defaultProps, + }, +}; + +export const StartContent = { + render: Template, + + args: { + ...defaultProps, + labelPlacement: "outside", + startContent: ( + + ), + }, +}; + +export const EndContent = { + render: Template, + + args: { + ...defaultProps, + labelPlacement: "outside", + endContent: ( + + ), + }, +}; + +export const WithErrorMessage = { + render: Template, + + args: { + ...defaultProps, + errorMessage: "Please enter a valid date", + }, +}; + +export const IsInvalid = { + render: Template, + + args: { + ...defaultProps, + variant: "bordered", + isInvalid: true, + defaultValue: parseDate("2024-04-04"), + errorMessage: "Please enter a valid date", + }, +}; + +export const Controlled = { + render: ControlledTemplate, + + args: { + ...defaultProps, + variant: "bordered", + }, +}; + +export const TimeZones = { + render: TimeZonesTemplate, + + args: { + ...defaultProps, + label: "Event date", + defaultValue: parseZonedDateTime("2022-11-07T00:45[America/Los_Angeles]"), + }, +}; + +export const Granularity = { + render: GranularityTemplate, + + args: { + ...defaultProps, + }, +}; + +export const InternationalCalendars = { + render: InternationalCalendarsTemplate, + + args: { + ...defaultProps, + }, +}; + +export const MinDateValue = { + render: Template, + + args: { + ...defaultProps, + minValue: today(getLocalTimeZone()), + defaultValue: parseDate("2024-04-03"), + }, +}; + +export const MaxDateValue = { + render: Template, + + args: { + ...defaultProps, + maxValue: today(getLocalTimeZone()), + defaultValue: today(getLocalTimeZone()).add({days: 1}), + }, +}; + +export const PlaceholderValue = { + render: Template, + + args: { + ...defaultProps, + label: "Appointment time", + defaultValue: today(getLocalTimeZone()), + placeholderValue: new CalendarDate(1995, 11, 6), + }, +}; + +export const HideTimeZone = { + render: Template, + + args: { + ...defaultProps, + label: "Appointment time", + hideTimeZone: true, + defaultValue: parseZonedDateTime("2022-11-07T00:45[America/Los_Angeles]"), + }, +}; + +export const HourCycle = { + render: Template, + + args: { + ...defaultProps, + label: "Appointment time", + hourCycle: 24, + defaultValue: parseZonedDateTime("2022-11-07T00:45[America/Los_Angeles]"), + granularity: "minute", + }, +}; diff --git a/packages/components/date-input/stories/time-input.stories.tsx b/packages/components/date-input/stories/time-input.stories.tsx new file mode 100644 index 0000000000..86ba657bdc --- /dev/null +++ b/packages/components/date-input/stories/time-input.stories.tsx @@ -0,0 +1,284 @@ +import React from "react"; +import {Meta} from "@storybook/react"; +import {dateInput} from "@nextui-org/theme"; +import {ClockCircleLinearIcon} from "@nextui-org/shared-icons"; +import { + parseAbsoluteToLocal, + parseZonedDateTime, + Time, + ZonedDateTime, +} from "@internationalized/date"; +import {useDateFormatter} from "@react-aria/i18n"; + +import {TimeInput, TimeInputProps, TimeInputValue as TimeValue} from "../src"; + +export default { + title: "Components/TimeInput", + component: TimeInput, + argTypes: { + variant: { + control: { + type: "select", + }, + options: ["flat", "faded", "bordered", "underlined"], + }, + color: { + control: { + type: "select", + }, + options: ["default", "primary", "secondary", "success", "warning", "danger"], + }, + radius: { + control: { + type: "select", + }, + options: ["none", "sm", "md", "lg", "full"], + }, + size: { + control: { + type: "select", + }, + options: ["sm", "md", "lg"], + }, + labelPlacement: { + control: { + type: "select", + }, + options: ["inside", "outside", "outside-left"], + }, + isDisabled: { + control: { + type: "boolean", + }, + }, + }, +} as Meta; + +const defaultProps = { + label: "Event Time", + ...dateInput.defaultVariants, +}; + +const Template = (args: TimeInputProps) => ; + +export const Default = { + render: Template, + args: { + ...defaultProps, + }, +}; + +const LabelPlacementTemplate = (args: TimeInputProps) => ( +
+ + + +
+); + +const ControlledTemplate = (args: TimeInputProps) => { + let [value, setValue] = React.useState(parseAbsoluteToLocal("2024-04-08T18:45:22Z")); + + let formatter = useDateFormatter({dateStyle: "short", timeStyle: "long"}); + + return ( +
+
+ +

+ {value instanceof ZonedDateTime + ? (value?.toDate && formatter.format(value.toDate())) || + (value && value.toString()) || + "--" + : ""} +

+
+ + +
+ ); +}; + +const TimeZonesTemplate = (args: TimeInputProps) => ( +
+ + +
+); + +const GranularityTemplate = (args: TimeInputProps) => { + let [date, setDate] = React.useState(parseAbsoluteToLocal("2021-04-07T18:45:22Z")); + + return ( +
+ + + +
+ ); +}; + +export const Required = { + render: Template, + args: { + ...defaultProps, + isRequired: true, + }, +}; + +export const Disabled = { + render: Template, + args: { + ...defaultProps, + isDisabled: true, + defaultValue: new Time(11, 45), + }, +}; + +export const ReadOnly = { + render: Template, + args: { + ...defaultProps, + isReadOnly: true, + defaultValue: new Time(11, 45), + }, +}; + +export const WithoutLabel = { + render: Template, + + args: { + ...defaultProps, + label: null, + "aria-label": "Event Time", + }, +}; + +export const WithDescription = { + render: Template, + + args: { + ...defaultProps, + description: "Please enter your meeting time", + }, +}; + +export const LabelPlacement = { + render: LabelPlacementTemplate, + + args: { + ...defaultProps, + }, +}; + +export const StartContent = { + render: Template, + + args: { + ...defaultProps, + labelPlacement: "outside", + startContent: ( + + ), + }, +}; + +export const EndContent = { + render: Template, + + args: { + ...defaultProps, + labelPlacement: "outside", + endContent: ( + + ), + }, +}; + +export const Controlled = { + render: ControlledTemplate, + + args: { + ...defaultProps, + variant: "bordered", + }, +}; + +export const TimeZones = { + render: TimeZonesTemplate, + + args: { + ...defaultProps, + label: "Event time", + defaultValue: parseZonedDateTime("2022-11-07T00:45[America/Los_Angeles]"), + }, +}; + +export const Granularity = { + render: GranularityTemplate, + + args: { + ...defaultProps, + }, +}; + +export const MinTimeValue = { + render: Template, + + args: { + ...defaultProps, + minValue: new Time(9), + defaultValue: new Time(8), + }, +}; + +export const MaxTimeValue = { + render: Template, + + args: { + ...defaultProps, + maxValue: new Time(17), + defaultValue: new Time(18), + }, +}; + +export const PlaceholderValue = { + render: Template, + + args: { + ...defaultProps, + label: "Meeting time", + placeholderValue: new Time(9), + }, +}; + +export const HideTimeZone = { + render: Template, + + args: { + ...defaultProps, + label: "Meeting time", + hideTimeZone: true, + defaultValue: parseZonedDateTime("2022-11-07T10:45[America/Los_Angeles]"), + }, +}; + +export const HourCycle = { + render: Template, + + args: { + ...defaultProps, + label: "Meeting time", + hourCycle: 24, + defaultValue: parseZonedDateTime("2022-11-07T00:45[America/Los_Angeles]"), + granularity: "minute", + }, +}; diff --git a/packages/components/date-input/tsconfig.json b/packages/components/date-input/tsconfig.json new file mode 100644 index 0000000000..5d012f6e61 --- /dev/null +++ b/packages/components/date-input/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "tailwind-variants": ["../../../node_modules/tailwind-variants"] + }, + }, + "include": ["src", "index.ts"] +} diff --git a/packages/components/date-input/tsup.config.ts b/packages/components/date-input/tsup.config.ts new file mode 100644 index 0000000000..3e2bcff6cc --- /dev/null +++ b/packages/components/date-input/tsup.config.ts @@ -0,0 +1,8 @@ +import {defineConfig} from "tsup"; + +export default defineConfig({ + clean: true, + target: "es2019", + format: ["cjs", "esm"], + banner: {js: '"use client";'}, +}); diff --git a/packages/components/date-picker/CHANGELOG.md b/packages/components/date-picker/CHANGELOG.md new file mode 100644 index 0000000000..443e811476 --- /dev/null +++ b/packages/components/date-picker/CHANGELOG.md @@ -0,0 +1,60 @@ +# @nextui-org/date-picker + +## 2.0.6 + +### Patch Changes + +- Updated dependencies [[`183a4a6cf`](https://github.com/nextui-org/nextui/commit/183a4a6cfda193a076a4a30550ab93b72d51002d), [`eccc2f2f3`](https://github.com/nextui-org/nextui/commit/eccc2f2f3d856eefb2cc7c07b94e1c4cefd4d7d0)]: + - @nextui-org/popover@2.1.20 + - @nextui-org/react-utils@2.0.13 + - @nextui-org/button@2.0.30 + - @nextui-org/calendar@2.0.3 + - @nextui-org/date-input@2.0.3 + +## 2.0.5 + +### Patch Changes + +- Updated dependencies [[`9e5dd8ce3`](https://github.com/nextui-org/nextui/commit/9e5dd8ce37c94c9ca1ba7b2049a6e55f1803fee9)]: + - @nextui-org/popover@2.1.19 + +## 2.0.4 + +### Patch Changes + +- Updated dependencies [[`f89356691`](https://github.com/nextui-org/nextui/commit/f89356691cecb8e54f5f820b2b4491537e7c11f3)]: + - @nextui-org/popover@2.1.18 + +## 2.0.3 + +### Patch Changes + +- [#2744](https://github.com/nextui-org/nextui/pull/2744) [`158c2aa00`](https://github.com/nextui-org/nextui/commit/158c2aa004f0080449321f84b0efd37762e8adc0) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - Refactor calendar cell tab index, add calendar default width + +- Updated dependencies [[`158c2aa00`](https://github.com/nextui-org/nextui/commit/158c2aa004f0080449321f84b0efd37762e8adc0)]: + - @nextui-org/calendar@2.0.2 + - @nextui-org/button@2.0.29 + - @nextui-org/date-input@2.0.2 + - @nextui-org/popover@2.1.17 + - @nextui-org/react-utils@2.0.12 + +## 2.0.2 + +### Patch Changes + +- [#2737](https://github.com/nextui-org/nextui/pull/2737) [`fdbfa1f29`](https://github.com/nextui-org/nextui/commit/fdbfa1f2999e3a6304c7cf36fd73ce5e4ef3fe50) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - Static props removed from date range input picker field + +## 2.0.1 + +### Patch Changes + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - v2.3.0 + +- Updated dependencies [[`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14), [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14), [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14), [`a05aef0ac`](https://github.com/nextui-org/nextui/commit/a05aef0acb5a7b000c8131e8ba4f50f0adec01e5), [`2b9f89023`](https://github.com/nextui-org/nextui/commit/2b9f89023ac087016083dcc205703ae1b2bc9cb8), [`c5049edfd`](https://github.com/nextui-org/nextui/commit/c5049edfde7edaee2081d70e581739be9dcae2f9), [`8761168d3`](https://github.com/nextui-org/nextui/commit/8761168d3459cd83ce571f4e65eb8ea6db8516ef), [`eb51bf226`](https://github.com/nextui-org/nextui/commit/eb51bf226170e4bb37ae30990d1c3aa26d8c504b), [`7263daca0`](https://github.com/nextui-org/nextui/commit/7263daca08674338eb28529315070337ba0dfc17), [`2894aecca`](https://github.com/nextui-org/nextui/commit/2894aecca1a2ef0dfb3066b9b8df24ce48c99dae)]: + - @nextui-org/button@2.0.28 + - @nextui-org/calendar@2.0.1 + - @nextui-org/date-input@2.0.1 + - @nextui-org/popover@2.1.16 + - @nextui-org/react-utils@2.0.11 + - @nextui-org/shared-icons@2.0.7 + - @nextui-org/shared-utils@2.0.5 diff --git a/packages/components/date-picker/README.md b/packages/components/date-picker/README.md new file mode 100644 index 0000000000..1ad9b0f3fd --- /dev/null +++ b/packages/components/date-picker/README.md @@ -0,0 +1,22 @@ +# @nextui-org/date-picker + +A date picker combines a DateInput and a Calendar popover to allow users to enter or select a date and time value. + +## Installation + +```sh +yarn add @nextui-org/date-picker +# or +npm i @nextui-org/date-picker +``` + +## Contribution + +Yes please! See the +[contributing guidelines](https://github.com/nextui-org/nextui/blob/master/CONTRIBUTING.md) +for details. + +## License + +This project is licensed under the terms of the +[MIT license](https://github.com/nextui-org/nextui/blob/master/LICENSE). diff --git a/packages/components/date-picker/__tests__/date-picker.test.tsx b/packages/components/date-picker/__tests__/date-picker.test.tsx new file mode 100644 index 0000000000..9a8e39e247 --- /dev/null +++ b/packages/components/date-picker/__tests__/date-picker.test.tsx @@ -0,0 +1,447 @@ +/* eslint-disable jsx-a11y/no-autofocus */ +import * as React from "react"; +import {render, act, fireEvent, waitFor} from "@testing-library/react"; +import {pointerMap, triggerPress} from "@nextui-org/test-utils"; +import userEvent from "@testing-library/user-event"; +import {CalendarDate, CalendarDateTime} from "@internationalized/date"; + +import {DatePicker as DatePickerBase, DatePickerProps} from "../src"; + +/** + * Custom date-picker to disable animations and avoid issues with react-motion and jest + */ +const DatePicker = React.forwardRef((props: DatePickerProps, ref: React.Ref) => { + return ( + + ); +}); + +DatePicker.displayName = "DatePicker"; + +function getTextValue(el: any) { + if ( + el.className?.includes?.("DatePicker-placeholder") && + el.attributes?.getNamedItem("data-placeholder")?.value === "true" + ) { + return ""; + } + + return [...el.childNodes] + .map((el) => (el.nodeType === 3 ? el.textContent : getTextValue(el))) + .join(""); +} + +describe("DatePicker", () => { + let user; + + beforeAll(() => { + user = userEvent.setup({delay: null, pointerMap}); + jest.useFakeTimers(); + }); + afterEach(() => { + act(() => { + jest.runAllTimers(); + }); + }); + + describe("Basics", () => { + it("should render correctly", () => { + const wrapper = render(); + + expect(() => wrapper.unmount()).not.toThrow(); + }); + + it("ref should be forwarded", () => { + const ref = React.createRef(); + + render(); + expect(ref.current).not.toBeNull(); + }); + + it("should render a datepicker with a specified date", function () { + let {getAllByRole} = render(); + + let combobox = getAllByRole("group")[0]; + + expect(combobox).toBeVisible(); + expect(combobox).not.toHaveAttribute("aria-disabled"); + expect(combobox).not.toHaveAttribute("aria-invalid"); + + let segments = getAllByRole("spinbutton"); + + expect(segments.length).toBe(3); + + expect(getTextValue(segments[0])).toBe("2"); + expect(segments[0].getAttribute("aria-label")).toBe("month, "); + expect(segments[0].getAttribute("aria-valuenow")).toBe("2"); + expect(segments[0].getAttribute("aria-valuetext")).toBe("2 – February"); + expect(segments[0].getAttribute("aria-valuemin")).toBe("1"); + expect(segments[0].getAttribute("aria-valuemax")).toBe("12"); + + expect(getTextValue(segments[1])).toBe("3"); + expect(segments[1].getAttribute("aria-label")).toBe("day, "); + expect(segments[1].getAttribute("aria-valuenow")).toBe("3"); + expect(segments[1].getAttribute("aria-valuetext")).toBe("3"); + expect(segments[1].getAttribute("aria-valuemin")).toBe("1"); + expect(segments[1].getAttribute("aria-valuemax")).toBe("28"); + + expect(getTextValue(segments[2])).toBe("2019"); + expect(segments[2].getAttribute("aria-label")).toBe("year, "); + expect(segments[2].getAttribute("aria-valuenow")).toBe("2019"); + expect(segments[2].getAttribute("aria-valuetext")).toBe("2019"); + expect(segments[2].getAttribute("aria-valuemin")).toBe("1"); + expect(segments[2].getAttribute("aria-valuemax")).toBe("9999"); + }); + + it('should render a datepicker with granularity="second"', function () { + let {getAllByRole} = render( + , + ); + + let combobox = getAllByRole("group")[0]; + + expect(combobox).toBeVisible(); + expect(combobox).not.toHaveAttribute("aria-disabled"); + expect(combobox).not.toHaveAttribute("aria-invalid"); + + let segments = getAllByRole("spinbutton"); + + expect(segments.length).toBe(7); + + expect(getTextValue(segments[0])).toBe("2"); + expect(segments[0].getAttribute("aria-label")).toBe("month, "); + expect(segments[0].getAttribute("aria-valuenow")).toBe("2"); + expect(segments[0].getAttribute("aria-valuetext")).toBe("2 – February"); + expect(segments[0].getAttribute("aria-valuemin")).toBe("1"); + expect(segments[0].getAttribute("aria-valuemax")).toBe("12"); + + expect(getTextValue(segments[1])).toBe("3"); + expect(segments[1].getAttribute("aria-label")).toBe("day, "); + expect(segments[1].getAttribute("aria-valuenow")).toBe("3"); + expect(segments[1].getAttribute("aria-valuetext")).toBe("3"); + expect(segments[1].getAttribute("aria-valuemin")).toBe("1"); + expect(segments[1].getAttribute("aria-valuemax")).toBe("28"); + + expect(getTextValue(segments[2])).toBe("2019"); + expect(segments[2].getAttribute("aria-label")).toBe("year, "); + expect(segments[2].getAttribute("aria-valuenow")).toBe("2019"); + expect(segments[2].getAttribute("aria-valuetext")).toBe("2019"); + expect(segments[2].getAttribute("aria-valuemin")).toBe("1"); + expect(segments[2].getAttribute("aria-valuemax")).toBe("9999"); + + expect(getTextValue(segments[3])).toBe("12"); + expect(segments[3].getAttribute("aria-label")).toBe("hour, "); + expect(segments[3].getAttribute("aria-valuenow")).toBe("0"); + expect(segments[3].getAttribute("aria-valuetext")).toBe("12 AM"); + expect(segments[3].getAttribute("aria-valuemin")).toBe("0"); + expect(segments[3].getAttribute("aria-valuemax")).toBe("11"); + + expect(getTextValue(segments[4])).toBe("00"); + expect(segments[4].getAttribute("aria-label")).toBe("minute, "); + expect(segments[4].getAttribute("aria-valuenow")).toBe("0"); + expect(segments[4].getAttribute("aria-valuetext")).toBe("00"); + expect(segments[4].getAttribute("aria-valuemin")).toBe("0"); + expect(segments[4].getAttribute("aria-valuemax")).toBe("59"); + + expect(getTextValue(segments[5])).toBe("00"); + expect(segments[5].getAttribute("aria-label")).toBe("second, "); + expect(segments[5].getAttribute("aria-valuenow")).toBe("0"); + expect(segments[5].getAttribute("aria-valuetext")).toBe("00"); + expect(segments[5].getAttribute("aria-valuemin")).toBe("0"); + expect(segments[5].getAttribute("aria-valuemax")).toBe("59"); + + expect(getTextValue(segments[6])).toBe("AM"); + expect(segments[6].getAttribute("aria-label")).toBe("AM/PM, "); + expect(segments[6].getAttribute("aria-valuetext")).toBe("AM"); + }); + + it("should support autoFocus", function () { + let {getAllByRole} = render(); + + expect(document.activeElement).toBe(getAllByRole("spinbutton")[0]); + }); + + it("should pass through data attributes", function () { + let {getByTestId} = render(); + + expect(getByTestId("foo")).toHaveAttribute("role", "group"); + }); + }); + + describe("Events", () => { + let onBlurSpy = jest.fn(); + let onFocusChangeSpy = jest.fn(); + let onFocusSpy = jest.fn(); + let onKeyDownSpy = jest.fn(); + let onKeyUpSpy = jest.fn(); + + afterEach(() => { + onBlurSpy.mockClear(); + onFocusChangeSpy.mockClear(); + onFocusSpy.mockClear(); + onKeyDownSpy.mockClear(); + onKeyUpSpy.mockClear(); + }); + + it("should focus field, move a segment, and open popover and does not blur", async function () { + let {getByRole, getAllByRole} = render( + , + ); + let segments = getAllByRole("spinbutton"); + let button = getByRole("button"); + + expect(onBlurSpy).not.toHaveBeenCalled(); + expect(onFocusChangeSpy).not.toHaveBeenCalled(); + expect(onFocusSpy).not.toHaveBeenCalled(); + + await act(async () => { + await user.tab(); + }); + + expect(segments[0]).toHaveFocus(); + expect(onBlurSpy).not.toHaveBeenCalled(); + expect(onFocusChangeSpy).toHaveBeenCalledTimes(1); + expect(onFocusSpy).toHaveBeenCalledTimes(1); + + await act(async () => { + await user.tab(); + }); + + expect(segments[1]).toHaveFocus(); + expect(onBlurSpy).not.toHaveBeenCalled(); + expect(onFocusChangeSpy).toHaveBeenCalledTimes(1); + expect(onFocusSpy).toHaveBeenCalledTimes(1); + + triggerPress(button); + + act(() => jest.runAllTimers()); + + let dialog = getByRole("dialog"); + + expect(dialog).toBeVisible(); + }); + + it("should focus field and leave to blur", async function () { + let {getAllByRole} = render( + , + ); + let segments = getAllByRole("spinbutton"); + + expect(onBlurSpy).not.toHaveBeenCalled(); + expect(onFocusChangeSpy).not.toHaveBeenCalled(); + expect(onFocusSpy).not.toHaveBeenCalled(); + + await act(async () => { + await user.tab(); + }); + + expect(segments[0]).toHaveFocus(); + expect(onBlurSpy).not.toHaveBeenCalled(); + expect(onFocusChangeSpy).toHaveBeenCalledTimes(1); + expect(onFocusSpy).toHaveBeenCalledTimes(1); + + await act(() => { + user.click(document.body); + }); + + expect(document.body).toHaveFocus(); + expect(onBlurSpy).toHaveBeenCalledTimes(1); + expect(onFocusChangeSpy).toHaveBeenCalledTimes(2); + expect(onFocusSpy).toHaveBeenCalledTimes(1); + }); + + it("should open popover and call picker onFocus", function () { + let {getByRole} = render( + , + ); + + let button = getByRole("button"); + + expect(onBlurSpy).not.toHaveBeenCalled(); + expect(onFocusChangeSpy).not.toHaveBeenCalled(); + expect(onFocusSpy).not.toHaveBeenCalled(); + + triggerPress(button); + + act(() => jest.runAllTimers()); + + let dialog = getByRole("dialog"); + + expect(dialog).toBeVisible(); + expect(onBlurSpy).not.toHaveBeenCalled(); + }); + + it("should open and close popover and only call blur when focus leaves picker", async function () { + let {getByRole} = render( + , + ); + let button = getByRole("button"); + + expect(onBlurSpy).not.toHaveBeenCalled(); + expect(onFocusChangeSpy).not.toHaveBeenCalled(); + expect(onFocusSpy).not.toHaveBeenCalled(); + + triggerPress(button); + act(() => jest.runAllTimers()); + + let dialog = getByRole("dialog"); + + expect(dialog).toBeVisible(); + + //@ts-ignore + fireEvent.keyDown(document.activeElement, {key: "Escape"}); + //@ts-ignore + fireEvent.keyUp(document.activeElement, {key: "Escape"}); + + act(() => jest.runAllTimers()); + + await waitFor(() => { + expect(dialog).not.toBeInTheDocument(); + }); // wait for animation + + // now that it's been unmounted, run the raf callback + act(() => { + jest.runAllTimers(); + }); + + expect(dialog).not.toBeInTheDocument(); + expect(document.activeElement).toBe(button); + expect(button).toHaveFocus(); + + await act(async () => { + await user.tab(); + }); + + expect(document.body).toHaveFocus(); + }); + + it("should trigger right arrow key event for segment navigation", async function () { + let {getAllByRole} = render( + , + ); + let segments = getAllByRole("spinbutton"); + + expect(onKeyDownSpy).not.toHaveBeenCalled(); + expect(onKeyUpSpy).not.toHaveBeenCalled(); + + await act(async () => { + await user.tab(); + }); + + expect(segments[0]).toHaveFocus(); + expect(onKeyDownSpy).not.toHaveBeenCalled(); + expect(onKeyUpSpy).toHaveBeenCalledTimes(1); + + // @ts-ignore + fireEvent.keyDown(document.activeElement, {key: "ArrowRight"}); + // @ts-ignore + fireEvent.keyUp(document.activeElement, {key: "ArrowRight"}); + + expect(segments[1]).toHaveFocus(); + expect(onKeyDownSpy).toHaveBeenCalledTimes(1); + expect(onKeyUpSpy).toHaveBeenCalledTimes(2); + }); + }); + + describe("Calendar popover", function () { + it("should emit onChange when selecting a date in the calendar in controlled mode", function () { + let onChange = jest.fn(); + let {getByRole, getAllByRole, queryByLabelText} = render( + , + ); + + let combobox = getAllByRole("group")[0]; + + expect(getTextValue(combobox)).toBe("2/3/2019"); + + let button = getByRole("button"); + + triggerPress(button); + + let dialog = getByRole("dialog"); + + expect(dialog).toBeVisible(); + + expect(queryByLabelText("Time")).toBeNull(); + + let cells = getAllByRole("gridcell"); + let selected = cells.find((cell) => cell.getAttribute("aria-selected") === "true"); + + // @ts-ignore + expect(selected.children[0]).toHaveAttribute( + "aria-label", + "Sunday, February 3, 2019 selected", + ); + + // @ts-ignore + triggerPress(selected.nextSibling.children[0]); + + expect(dialog).not.toBeInTheDocument(); + expect(onChange).toHaveBeenCalledTimes(1); + expect(onChange).toHaveBeenCalledWith(new CalendarDate(2019, 2, 4)); + expect(getTextValue(combobox)).toBe("2/3/2019"); // controlled + }); + + it("should emit onChange when selecting a date in the calendar in uncontrolled mode", function () { + let onChange = jest.fn(); + let {getByRole, getAllByRole} = render( + , + ); + + let combobox = getAllByRole("group")[0]; + + expect(getTextValue(combobox)).toBe("2/3/2019"); + + let button = getByRole("button"); + + triggerPress(button); + + let dialog = getByRole("dialog"); + + expect(dialog).toBeVisible(); + + let cells = getAllByRole("gridcell"); + let selected = cells.find((cell) => cell.getAttribute("aria-selected") === "true"); + + // @ts-ignore + expect(selected.children[0]).toHaveAttribute( + "aria-label", + "Sunday, February 3, 2019 selected", + ); + + // @ts-ignore + triggerPress(selected.nextSibling.children[0]); + + expect(dialog).not.toBeInTheDocument(); + expect(onChange).toHaveBeenCalledTimes(1); + expect(onChange).toHaveBeenCalledWith(new CalendarDate(2019, 2, 4)); + expect(getTextValue(combobox)).toBe("2/4/2019"); // uncontrolled + }); + }); +}); diff --git a/packages/components/date-picker/intl/messages.ts b/packages/components/date-picker/intl/messages.ts new file mode 100644 index 0000000000..9f789606ad --- /dev/null +++ b/packages/components/date-picker/intl/messages.ts @@ -0,0 +1,173 @@ +export default { + "ar-AE": { + endTime: "وقت الانتهاء", + startTime: "وقت البدء", + time: "الوقت", + }, + "bg-BG": { + endTime: "Краен час", + startTime: "Начален час", + time: "Време", + }, + "cs-CZ": { + endTime: "Konečný čas", + startTime: "Počáteční čas", + time: "Čas", + }, + + "da-DK": { + endTime: "Sluttidspunkt", + startTime: "Starttidspunkt", + time: "Klokkeslæt", + }, + "de-DE": { + endTime: "Endzeit", + startTime: "Startzeit", + time: "Uhrzeit", + }, + "el-GR": { + endTime: "Χρόνος λήξης", + startTime: "Ώρα έναρξης", + time: "Χρόνος", + }, + "en-US": { + time: "Time", + startTime: "Start time", + endTime: "End time", + }, + "es-ES": { + endTime: "Hora de finalización", + startTime: "Hora de inicio", + time: "Hora", + }, + "et-EE": { + endTime: "Lõpuaeg", + startTime: "Algusaeg", + time: "Aeg", + }, + "fi-FI": { + endTime: "Päättymisaika", + startTime: "Alkamisaika", + time: "Aika", + }, + "fr-FR": { + endTime: "Heure de fin", + startTime: "Heure de début", + time: "Heure", + }, + "he-IL": { + endTime: "שעת סיום", + startTime: "שעת התחלה", + time: "זמן", + }, + "hr-HR": { + endTime: "Vrijeme završetka", + startTime: "Vrijeme početka", + time: "Vrijeme", + }, + "hu-HU": { + endTime: "Befejezés ideje", + startTime: "Kezdés ideje", + time: "Idő", + }, + "it-IT": { + endTime: "Ora di fine", + startTime: "Ora di inizio", + time: "Ora", + }, + "ja-JP": { + endTime: "終了時刻", + startTime: "開始時刻", + time: "時刻", + }, + "ko-KR": { + endTime: "종료 시간", + startTime: "시작 시간", + time: "시간", + }, + "it-LT": { + endTime: "Pabaigos laikas", + startTime: "Pradžios laikas", + time: "Laikas", + }, + "lv-LV": { + endTime: "Beigu laiks", + startTime: "Sākuma laiks", + time: "Laiks", + }, + "nb-NO": { + endTime: "Sluttid", + startTime: "Starttid", + time: "Tid", + }, + "nl-NL": { + endTime: "Eindtijd", + startTime: "Starttijd", + time: "Tijd", + }, + "pl-PL": { + endTime: "Godzina końcowa", + startTime: "Godzina początkowa", + time: "Godzina", + }, + "pt-BR": { + endTime: "Hora final", + startTime: "Hora inicial", + time: "Hora", + }, + "pt-PT": { + endTime: "Terminar tempo", + startTime: "Iniciar tempo", + time: "Tempo", + }, + "ro-RO": { + endTime: "Ora de sfârșit", + startTime: "Ora de început", + time: "Ora", + }, + "ru-RU": { + endTime: "Время окончания", + startTime: "Время начала", + time: "Время", + }, + "sk-SK": { + endTime: "Čas ukončenia", + startTime: "Čas začiatku", + time: "Čas", + }, + "sl-SI": { + endTime: "Končni čas", + startTime: "Začetni čas", + time: "Čas", + }, + "sr-SP": { + endTime: "Završno vreme", + startTime: "Početno vreme", + time: "Vreme", + }, + "sv-SE": { + endTime: "Sluttid", + startTime: "Starttid", + time: "Tid", + }, + "tr-TR": { + endTime: "Bitiş saati", + startTime: "Başlangıç saati", + time: "Saat", + }, + "uk-UA": { + endTime: "Час завершення", + startTime: "Час початку", + time: "Час", + }, + "zh-CN": { + endTime: "结束时间", + startTime: "开始时间", + time: "时间", + }, + "zh-TW": { + endTime: "結束時間", + startTime: "開始時間", + time: "時間", + }, +}; diff --git a/packages/components/date-picker/package.json b/packages/components/date-picker/package.json new file mode 100644 index 0000000000..e91e0336f6 --- /dev/null +++ b/packages/components/date-picker/package.json @@ -0,0 +1,70 @@ +{ + "name": "@nextui-org/date-picker", + "version": "2.0.6", + "description": "A date picker combines a DateInput and a Calendar popover to allow users to enter or select a date and time value.", + "keywords": [ + "date-picker" + ], + "author": "Junior Garcia ", + "homepage": "https://nextui.org", + "license": "MIT", + "main": "src/index.ts", + "sideEffects": false, + "files": [ + "dist" + ], + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/nextui-org/nextui.git", + "directory": "packages/components/date-picker" + }, + "bugs": { + "url": "https://github.com/nextui-org/nextui/issues" + }, + "scripts": { + "build": "tsup src --dts", + "build:fast": "tsup src", + "dev": "pnpm build:fast --watch", + "clean": "rimraf dist .turbo", + "typecheck": "tsc --noEmit", + "prepack": "clean-package", + "postpack": "clean-package restore" + }, + "peerDependencies": { + "@nextui-org/system": ">=2.0.0", + "@nextui-org/theme": ">=2.0.0", + "react": ">=18", + "react-dom": ">=18" + }, + "dependencies": { + "@nextui-org/react-utils": "workspace:*", + "@nextui-org/shared-utils": "workspace:*", + "@nextui-org/popover": "workspace:*", + "@nextui-org/calendar": "workspace:*", + "@nextui-org/button": "workspace:*", + "@nextui-org/date-input": "workspace:*", + "@nextui-org/shared-icons": "workspace:*", + "@react-stately/overlays": "^3.6.3", + "@react-stately/utils": "^3.8.0", + "@internationalized/date": "^3.5.2", + "@react-aria/datepicker": "^3.9.3", + "@react-aria/i18n": "^3.8.4", + "@react-stately/datepicker": "^3.9.2", + "@react-types/datepicker": "^3.7.2", + "@react-types/shared": "3.21.0", + "@react-aria/utils": "^3.21.1" + }, + "devDependencies": { + "@nextui-org/system": "workspace:*", + "@nextui-org/theme": "workspace:*", + "@nextui-org/radio": "workspace:*", + "@nextui-org/test-utils": "workspace:*", + "clean-package": "2.2.0", + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "clean-package": "../../../clean-package.config.json" +} diff --git a/packages/components/date-picker/src/date-picker.tsx b/packages/components/date-picker/src/date-picker.tsx new file mode 100644 index 0000000000..eed11494ec --- /dev/null +++ b/packages/components/date-picker/src/date-picker.tsx @@ -0,0 +1,88 @@ +import type {DateValue} from "@internationalized/date"; + +import {ForwardedRef, ReactElement, Ref, useMemo} from "react"; +import {cloneElement, isValidElement} from "react"; +import {forwardRef} from "@nextui-org/system"; +import {Button} from "@nextui-org/button"; +import {DateInput, TimeInput} from "@nextui-org/date-input"; +import {FreeSoloPopover} from "@nextui-org/popover"; +import {Calendar} from "@nextui-org/calendar"; +import {AnimatePresence} from "framer-motion"; +import {CalendarBoldIcon} from "@nextui-org/shared-icons"; + +import {UseDatePickerProps, useDatePicker} from "./use-date-picker"; + +export interface Props extends UseDatePickerProps {} + +function DatePicker(props: Props, ref: ForwardedRef) { + const { + state, + endContent, + selectorIcon, + showTimeField, + disableAnimation, + isCalendarHeaderExpanded, + getDateInputProps, + getPopoverProps, + getTimeInputProps, + getSelectorButtonProps, + getSelectorIconProps, + getCalendarProps, + CalendarTopContent, + CalendarBottomContent, + } = useDatePicker({...props, ref}); + + const selectorContent = isValidElement(selectorIcon) ? ( + cloneElement(selectorIcon, getSelectorIconProps()) + ) : ( + + ); + + const calendarBottomContent = useMemo(() => { + if (isCalendarHeaderExpanded) return null; + + return showTimeField ? ( + <> + + {CalendarBottomContent} + + ) : ( + CalendarBottomContent + ); + }, [state, showTimeField, CalendarBottomContent, isCalendarHeaderExpanded]); + + const calendarTopContent = useMemo(() => { + if (isCalendarHeaderExpanded) return null; + + return CalendarTopContent; + }, [showTimeField, CalendarTopContent, isCalendarHeaderExpanded]); + + const popoverContent = state.isOpen ? ( + + + + ) : null; + + return ( + <> + {endContent || selectorContent}} + /> + {disableAnimation ? popoverContent : {popoverContent}} + + ); +} + +DatePicker.displayName = "NextUI.DatePicker"; + +export type DatePickerProps = Props & {ref?: Ref}; + +// forwardRef doesn't support generic parameters, so cast the result to the correct type +export default forwardRef(DatePicker) as ( + props: DatePickerProps, +) => ReactElement; diff --git a/packages/components/date-picker/src/date-range-picker-field.tsx b/packages/components/date-picker/src/date-range-picker-field.tsx new file mode 100644 index 0000000000..7e9ee28c53 --- /dev/null +++ b/packages/components/date-picker/src/date-range-picker-field.tsx @@ -0,0 +1,91 @@ +import type {DateInputReturnType, DateInputSlots, SlotsToClasses} from "@nextui-org/theme"; +import type {AriaDatePickerProps} from "@react-types/datepicker"; +import type {HTMLNextUIProps} from "@nextui-org/system"; +import type {DateInputProps} from "@nextui-org/date-input"; + +import {createCalendar} from "@internationalized/date"; +import {forwardRef, useRef} from "react"; +import {DateValue} from "@react-types/datepicker"; +import {useDateField as useAriaDateField} from "@react-aria/datepicker"; +import {ForwardedRef, ReactElement, Ref} from "react"; +import {useDateFieldState} from "@react-stately/datepicker"; +import {DateInputSegment} from "@nextui-org/date-input"; +import {filterDOMProps, useDOMRef} from "@nextui-org/react-utils"; +import {useLocale} from "@react-aria/i18n"; +import {mergeProps} from "@react-aria/utils"; + +type NextUIBaseProps = Omit< + HTMLNextUIProps<"div">, + keyof AriaDatePickerProps | "onChange" +>; + +export interface Props + extends NextUIBaseProps, + AriaDatePickerProps, + Pick { + /** DateInput classes slots. */ + slots: DateInputReturnType; + /** DateInput classes. */ + classNames?: SlotsToClasses; +} + +function DateRangePickerField( + props: Props, + ref: ForwardedRef, +) { + const {as, slots, createCalendar: createCalendarProp, classNames, ...otherProps} = props; + + const Component = as || "div"; + + const domRef = useDOMRef(ref); + + const {locale} = useLocale(); + + let state = useDateFieldState({ + ...otherProps, + locale, + validationBehavior: "native", + createCalendar: + !createCalendarProp || typeof createCalendarProp !== "function" + ? createCalendar + : (createCalendarProp as typeof createCalendar), + }); + + const inputRef = useRef(null); + + const { + fieldProps, + inputProps, + isInvalid: ariaIsInvalid, + } = useAriaDateField({...otherProps, inputRef}, state, domRef); + + const isInvalid = props.isInvalid || ariaIsInvalid; + + state.isInvalid = isInvalid; + + return ( + + {state.segments.map((segment, i) => ( + + ))} + + + ); +} + +DateRangePickerField.displayName = "NextUI.DateRangePickerField"; + +export type DateRangePickerFieldProps = Props & { + ref?: Ref; +}; + +// forwardRef doesn't support generic parameters, so cast the result to the correct type +export default forwardRef(DateRangePickerField) as ( + props: DateRangePickerFieldProps, +) => ReactElement; diff --git a/packages/components/date-picker/src/date-range-picker.tsx b/packages/components/date-picker/src/date-range-picker.tsx new file mode 100644 index 0000000000..67cfe846b8 --- /dev/null +++ b/packages/components/date-picker/src/date-range-picker.tsx @@ -0,0 +1,107 @@ +import type {DateValue} from "@internationalized/date"; + +import {ForwardedRef, ReactElement, Ref, useMemo} from "react"; +import {cloneElement, isValidElement} from "react"; +import {forwardRef} from "@nextui-org/system"; +import {Button} from "@nextui-org/button"; +import {TimeInput, DateInputGroup} from "@nextui-org/date-input"; +import {FreeSoloPopover} from "@nextui-org/popover"; +import {RangeCalendar} from "@nextui-org/calendar"; +import {AnimatePresence} from "framer-motion"; +import {CalendarBoldIcon} from "@nextui-org/shared-icons"; + +import DateRangePickerField from "./date-range-picker-field"; +import {UseDateRangePickerProps, useDateRangePicker} from "./use-date-range-picker"; + +export interface Props extends UseDateRangePickerProps {} + +function DateRangePicker(props: Props, ref: ForwardedRef) { + const { + state, + slots, + endContent, + selectorIcon, + showTimeField, + classNames, + disableAnimation, + isCalendarHeaderExpanded, + getDateInputGroupProps, + getStartDateInputProps, + getEndDateInputProps, + getPopoverProps, + getSeparatorProps, + getStartTimeInputProps, + getEndTimeInputProps, + getSelectorButtonProps, + getSelectorIconProps, + getCalendarProps, + CalendarTopContent, + CalendarBottomContent, + } = useDateRangePicker({...props, ref}); + + const selectorContent = isValidElement(selectorIcon) ? ( + cloneElement(selectorIcon, getSelectorIconProps()) + ) : ( + + ); + + const calendarBottomContent = useMemo(() => { + if (isCalendarHeaderExpanded) return null; + + return showTimeField ? ( +
+
+ + +
+ {CalendarBottomContent} +
+ ) : ( + CalendarBottomContent + ); + }, [state, showTimeField, CalendarBottomContent, isCalendarHeaderExpanded]); + + const calendarTopContent = useMemo(() => { + if (isCalendarHeaderExpanded) return null; + + return CalendarTopContent; + }, [showTimeField, CalendarTopContent, isCalendarHeaderExpanded]); + + const popoverContent = state.isOpen ? ( + + + + ) : null; + + return ( + <> + {endContent || selectorContent}} + > + + + + + + {disableAnimation ? popoverContent : {popoverContent}} + + ); +} + +DateRangePicker.displayName = "NextUI.DateRangePicker"; + +export type DateRangePickerProps = Props & { + ref?: Ref; +}; + +// forwardRef doesn't support generic parameters, so cast the result to the correct type +export default forwardRef(DateRangePicker) as ( + props: DateRangePickerProps, +) => ReactElement; diff --git a/packages/components/date-picker/src/index.ts b/packages/components/date-picker/src/index.ts new file mode 100644 index 0000000000..dbf3d49e4e --- /dev/null +++ b/packages/components/date-picker/src/index.ts @@ -0,0 +1,14 @@ +import DatePicker from "./date-picker"; +import DateRangePicker from "./date-range-picker"; +import DateRangePickerField from "./date-range-picker-field"; + +// export types +export type {DatePickerProps} from "./date-picker"; +export type {DateRangePickerProps} from "./date-range-picker"; + +// export hooks +export {useDatePicker} from "./use-date-picker"; +export {useDateRangePicker} from "./use-date-range-picker"; + +// export components +export {DatePicker, DateRangePicker, DateRangePickerField}; diff --git a/packages/components/date-picker/src/use-date-picker-base.ts b/packages/components/date-picker/src/use-date-picker-base.ts new file mode 100644 index 0000000000..355397534e --- /dev/null +++ b/packages/components/date-picker/src/use-date-picker-base.ts @@ -0,0 +1,278 @@ +import type {DateValue} from "@internationalized/date"; +import type {AriaDatePickerBaseProps} from "@react-types/datepicker"; +import type {DateInputProps, TimeInputProps} from "@nextui-org/date-input"; +import type {ButtonProps} from "@nextui-org/button"; +import type {CalendarProps} from "@nextui-org/calendar"; +import type {PopoverProps} from "@nextui-org/popover"; +import type {ReactNode} from "react"; +import type {ValueBase} from "@react-types/shared"; + +import {dateInput, DatePickerVariantProps} from "@nextui-org/theme"; +import {useState} from "react"; +import {HTMLNextUIProps, mapPropsVariants} from "@nextui-org/system"; +import {mergeProps} from "@react-aria/utils"; +import {useDOMRef} from "@nextui-org/react-utils"; +import {dataAttr} from "@nextui-org/shared-utils"; +import {useLocalizedStringFormatter} from "@react-aria/i18n"; + +import intlMessages from "../intl/messages"; + +type NextUIBaseProps = Omit< + HTMLNextUIProps<"div">, + keyof AriaDatePickerBaseProps | "onChange" +>; + +interface Props extends NextUIBaseProps { + /** + * The icon to toggle the date picker popover. Usually a calendar icon. + */ + selectorIcon?: ReactNode; + /** + * Controls the behavior of paging. Pagination either works by advancing the visible page by visibleDuration (default) or one unit of visibleDuration. + * @default visible + */ + pageBehavior?: CalendarProps["pageBehavior"]; + /** + * The number of months to display at once. Up to 3 months are supported. + * Passing a number greater than 1 will disable the `showMonthAndYearPickers` prop. + * + * @default 1 + */ + visibleMonths?: CalendarProps["visibleMonths"]; + /** + * The width to be applied to the calendar component. + * + * @default 256 + */ + calendarWidth?: number; + /** + * Top content to be rendered in the calendar component. + */ + CalendarTopContent?: CalendarProps["topContent"]; + /** + * Bottom content to be rendered in the calendar component. + */ + CalendarBottomContent?: CalendarProps["bottomContent"]; + /** + * Whether the calendar should show month and year pickers. + * + * @default false + */ + showMonthAndYearPickers?: CalendarProps["showMonthAndYearPickers"]; + /** + * Props to be passed to the popover component. + * + * @default { placement: "bottom", triggerScaleOnOpen: false, offset: 13 } + */ + popoverProps?: Partial; + /** + * Props to be passed to the selector button component. + * @default { size: "sm", variant: "light", radius: "full", isIconOnly: true } + */ + selectorButtonProps?: Partial; + /** + * Props to be passed to the calendar component. + * @default {} + */ + calendarProps?: Partial>; + /** + * Props to be passed to the time input component. + * + * @default {} + */ + timeInputProps?: TimeInputProps; + /** + * Callback that is called for each date of the calendar. If it returns true, then the date is unavailable. + */ + isDateUnavailable?: CalendarProps["isDateUnavailable"]; + /** + * Whether to disable all animations in the date picker. Including the DateInput, Button, Calendar, and Popover. + * + * @default false + */ + disableAnimation?: boolean; +} + +type Variants = + | "color" + | "size" + | "isDisabled" + | "disableAnimation" + | "variant" + | "radius" + | "labelPlacement" + | "fullWidth"; + +export type UseDatePickerBaseProps = Props & + DatePickerVariantProps & + Pick< + DateInputProps, + Variants | "ref" | "createCalendar" | "startContent" | "endContent" | "inputRef" + > & + Omit, keyof ValueBase | "validate" | "validationBehavior">; + +export function useDatePickerBase(originalProps: UseDatePickerBaseProps) { + const [props, variantProps] = mapPropsVariants(originalProps, dateInput.variantKeys); + + const [isCalendarHeaderExpanded, setIsCalendarHeaderExpanded] = useState(false); + + const { + as, + ref, + label, + endContent, + selectorIcon, + inputRef, + isInvalid, + errorMessage, + description, + startContent, + validationState, + // validationBehavior, TODO: Uncomment this one we support `native` and `aria` validations + visibleMonths = 1, + pageBehavior = "visible", + calendarWidth = 256, + isDateUnavailable, + shouldForceLeadingZeros, + showMonthAndYearPickers = false, + selectorButtonProps: userSelectorButtonProps = {}, + popoverProps: userPopoverProps = {}, + timeInputProps: userTimeInputProps = {}, + calendarProps: userCalendarProps = {}, + CalendarTopContent, + CalendarBottomContent, + createCalendar, + } = props; + + const domRef = useDOMRef(ref); + const disableAnimation = originalProps.disableAnimation ?? false; + + let stringFormatter = useLocalizedStringFormatter(intlMessages) as any; + + const isDefaultColor = originalProps.color === "default" || !originalProps.color; + const hasMultipleMonths = visibleMonths > 1; + + // Time field values + const placeholder = originalProps?.placeholderValue; + const timePlaceholder = placeholder && "hour" in placeholder ? placeholder : null; + const timeMinValue = + originalProps.minValue && "hour" in originalProps.minValue ? originalProps.minValue : null; + const timeMaxValue = + originalProps.maxValue && "hour" in originalProps.maxValue ? originalProps.maxValue : null; + + const slotsProps: { + popoverProps: UseDatePickerBaseProps["popoverProps"]; + selectorButtonProps: ButtonProps; + calendarProps: CalendarProps; + } = { + popoverProps: mergeProps( + { + offset: 13, + placement: "bottom", + triggerScaleOnOpen: false, + disableAnimation, + }, + userPopoverProps, + ), + selectorButtonProps: mergeProps( + { + isIconOnly: true, + radius: "full", + size: "sm", + variant: "light", + disableAnimation, + }, + userSelectorButtonProps, + ), + calendarProps: mergeProps( + { + showHelper: false, + visibleMonths, + pageBehavior, + isDateUnavailable, + showMonthAndYearPickers, + onHeaderExpandedChange: setIsCalendarHeaderExpanded, + color: + (originalProps.variant === "bordered" || originalProps.variant === "underlined") && + isDefaultColor + ? "foreground" + : isDefaultColor + ? "primary" + : originalProps.color, + disableAnimation, + }, + userCalendarProps, + ), + }; + + const dateInputProps = { + as, + label, + ref: domRef, + inputRef, + description, + startContent, + validationState, + shouldForceLeadingZeros, + isInvalid, + errorMessage, + "data-invalid": dataAttr(originalProps?.isInvalid), + } as DateInputProps; + + const timeInputProps = { + ...userTimeInputProps, + size: "sm", + labelPlacement: "outside-left", + label: userTimeInputProps?.label || stringFormatter.format("time"), + placeholderValue: timePlaceholder, + hourCycle: props.hourCycle, + hideTimeZone: props.hideTimeZone, + } as TimeInputProps; + + const popoverProps = { + ...mergeProps(slotsProps.popoverProps, props), + triggerRef: domRef, + } as PopoverProps; + + const calendarProps = { + ...slotsProps.calendarProps, + calendarWidth, + "data-slot": "calendar", + } as CalendarProps; + + const selectorButtonProps = { + ...slotsProps.selectorButtonProps, + "data-slot": "selector-button", + } as ButtonProps; + + const selectorIconProps = { + "data-slot": "selector-icon", + }; + + return { + domRef, + endContent, + selectorIcon, + createCalendar, + stringFormatter, + hasMultipleMonths, + slotsProps, + timeMinValue, + timeMaxValue, + visibleMonths, + isCalendarHeaderExpanded, + disableAnimation, + CalendarTopContent, + CalendarBottomContent, + variantProps, + dateInputProps, + timeInputProps, + popoverProps, + calendarProps, + userTimeInputProps, + selectorButtonProps, + selectorIconProps, + }; +} + +export type UseDatePickerBaseReturn = ReturnType; diff --git a/packages/components/date-picker/src/use-date-picker.ts b/packages/components/date-picker/src/use-date-picker.ts new file mode 100644 index 0000000000..2bd0c154d1 --- /dev/null +++ b/packages/components/date-picker/src/use-date-picker.ts @@ -0,0 +1,217 @@ +import type {DateValue} from "@internationalized/date"; +import type {DateInputProps, TimeInputProps} from "@nextui-org/date-input"; +import type {DatePickerState} from "@react-stately/datepicker"; +import type {ButtonProps} from "@nextui-org/button"; +import type {CalendarProps} from "@nextui-org/calendar"; +import type {PopoverProps} from "@nextui-org/popover"; +import type {UseDatePickerBaseProps} from "./use-date-picker-base"; +import type {DOMAttributes} from "@nextui-org/system"; +import type {DatePickerSlots, SlotsToClasses} from "@nextui-org/theme"; + +import {useMemo} from "react"; +import {datePicker} from "@nextui-org/theme"; +import {useDatePickerState} from "@react-stately/datepicker"; +import {AriaDatePickerProps, useDatePicker as useAriaDatePicker} from "@react-aria/datepicker"; +import {clsx, dataAttr, objectToDeps} from "@nextui-org/shared-utils"; +import {mergeProps} from "@react-aria/utils"; + +import {useDatePickerBase} from "./use-date-picker-base"; + +interface Props extends UseDatePickerBaseProps {} + +interface Props + extends Omit, keyof AriaDatePickerProps> { + /** + * Classname or List of classes to change the classNames of the element. + * if `className` is passed, it will be added to the base slot. + * + * @example + * ```ts + * + * ``` + */ + classNames?: SlotsToClasses & DateInputProps["classNames"]; +} + +export type UseDatePickerProps = Props & AriaDatePickerProps; + +export function useDatePicker({ + className, + classNames, + ...originalProps +}: UseDatePickerProps) { + const { + domRef, + endContent, + selectorIcon, + createCalendar, + isCalendarHeaderExpanded, + disableAnimation, + CalendarTopContent, + slotsProps, + timeMinValue, + timeMaxValue, + CalendarBottomContent, + dateInputProps, + timeInputProps, + popoverProps, + calendarProps, + variantProps, + userTimeInputProps, + selectorButtonProps, + selectorIconProps, + } = useDatePickerBase(originalProps); + + let state: DatePickerState = useDatePickerState({ + ...originalProps, + shouldCloseOnSelect: () => !state.hasTime, + }); + + const baseStyles = clsx(classNames?.base, className); + + const slots = useMemo( + () => + datePicker({ + ...variantProps, + className, + }), + [objectToDeps(variantProps), className], + ); + + let { + groupProps, + labelProps, + fieldProps, + buttonProps, + dialogProps, + calendarProps: ariaCalendarProps, + descriptionProps, + errorMessageProps, + } = useAriaDatePicker(originalProps, state, domRef); + + // Time field values + originalProps.maxValue && "hour" in originalProps.maxValue ? originalProps.maxValue : null; + const timeGranularity = + state.granularity === "hour" || state.granularity === "minute" || state.granularity === "second" + ? state.granularity + : null; + + const showTimeField = !!timeGranularity; + + const getDateInputProps = () => { + return { + ...dateInputProps, + groupProps, + labelProps, + createCalendar, + errorMessageProps, + descriptionProps, + ...mergeProps(variantProps, fieldProps, { + minValue: originalProps.minValue, + maxValue: originalProps.maxValue, + fullWidth: true, + disableAnimation, + }), + className: slots.base({class: baseStyles}), + "data-open": dataAttr(state.isOpen), + } as DateInputProps; + }; + + const getTimeInputProps = () => { + if (!showTimeField) return {}; + + return { + ...timeInputProps, + value: state.timeValue, + onChange: state.setTimeValue, + granularity: timeGranularity, + minValue: timeMinValue, + maxValue: timeMaxValue, + classNames: { + base: slots.timeInput({ + class: clsx(classNames?.timeInput, userTimeInputProps?.classNames?.base), + }), + label: slots.timeInputLabel({ + class: clsx(classNames?.timeInputLabel, userTimeInputProps?.classNames?.label), + }), + }, + } as TimeInputProps; + }; + + const getPopoverProps = (props: DOMAttributes = {}) => { + return { + state, + dialogProps, + ...popoverProps, + ...props, + classNames: { + content: slots.popoverContent({ + class: clsx( + classNames?.popoverContent, + slotsProps.popoverProps?.classNames?.["content"], + props.className, + ), + }), + }, + } as PopoverProps; + }; + + const getCalendarProps = () => { + return { + ...ariaCalendarProps, + ...calendarProps, + classNames: { + base: slots.calendar({class: classNames?.calendar}), + content: slots.calendarContent({class: classNames?.calendarContent}), + }, + } as CalendarProps; + }; + + const getSelectorButtonProps = () => { + return { + ...buttonProps, + ...selectorButtonProps, + className: slots.selectorButton({class: classNames?.selectorButton}), + } as ButtonProps; + }; + + const getSelectorIconProps = () => { + return { + ...selectorIconProps, + className: slots.selectorIcon({class: classNames?.selectorIcon}), + }; + }; + + return { + state, + endContent, + selectorIcon, + showTimeField, + isCalendarHeaderExpanded, + disableAnimation, + CalendarTopContent, + CalendarBottomContent, + getDateInputProps, + getPopoverProps, + getSelectorButtonProps, + getCalendarProps, + getTimeInputProps, + getSelectorIconProps, + }; +} + +export type UseDatePickerReturn = ReturnType; diff --git a/packages/components/date-picker/src/use-date-range-picker.ts b/packages/components/date-picker/src/use-date-range-picker.ts new file mode 100644 index 0000000000..7851b31a77 --- /dev/null +++ b/packages/components/date-picker/src/use-date-range-picker.ts @@ -0,0 +1,426 @@ +import type {DateValue} from "@internationalized/date"; +import type {DateInputVariantProps} from "@nextui-org/theme"; +import type {TimeInputProps} from "@nextui-org/date-input"; +import type {ButtonProps} from "@nextui-org/button"; +import type {RangeCalendarProps} from "@nextui-org/calendar"; +import type {PopoverProps} from "@nextui-org/popover"; +import type {DOMAttributes, GroupDOMAttributes} from "@react-types/shared"; +import type {AriaDateRangePickerProps} from "@react-types/datepicker"; +import type {DateRangePickerState} from "@react-stately/datepicker"; +import type {UseDatePickerBaseProps} from "./use-date-picker-base"; +import type {PropGetter} from "@nextui-org/system"; +import type {DateRangePickerFieldProps} from "./date-range-picker-field"; +import type {DateInputGroupProps} from "@nextui-org/date-input"; +import type {DateRangePickerSlots, SlotsToClasses} from "@nextui-org/theme"; +import type {DateInputProps} from "@nextui-org/date-input"; + +import {useMemo, useRef} from "react"; +import {useDateRangePickerState} from "@react-stately/datepicker"; +import {useDateRangePicker as useAriaDateRangePicker} from "@react-aria/datepicker"; +import {clsx, dataAttr, objectToDeps} from "@nextui-org/shared-utils"; +import {mergeProps} from "@react-aria/utils"; +import {dateRangePicker, dateInput} from "@nextui-org/theme"; + +import {useDatePickerBase} from "./use-date-picker-base"; +interface Props + extends Omit, keyof AriaDateRangePickerProps> { + /** + * Classname or List of classes to change the classNames of the element. + * if `className` is passed, it will be added to the base slot. + * + * @example + * ```ts + * + * ``` + */ + classNames?: SlotsToClasses & DateInputProps["classNames"]; +} + +export type UseDateRangePickerProps = Props & AriaDateRangePickerProps; + +export function useDateRangePicker({ + as, + isInvalid, + description, + startContent, + endContent, + selectorIcon, + errorMessage, + className, + classNames, + ...originalProps +}: UseDateRangePickerProps) { + const { + domRef, + slotsProps, + createCalendar, + stringFormatter, + timeMinValue, + timeMaxValue, + isCalendarHeaderExpanded, + disableAnimation, + CalendarTopContent, + CalendarBottomContent, + timeInputProps, + popoverProps, + calendarProps, + variantProps, + userTimeInputProps, + hasMultipleMonths, + selectorButtonProps, + selectorIconProps, + } = useDatePickerBase(originalProps); + + let state: DateRangePickerState = useDateRangePickerState({ + ...originalProps, + shouldCloseOnSelect: () => !state.hasTime, + }); + + const popoverTriggerRef = useRef(null); + + let { + groupProps, + labelProps, + startFieldProps, + endFieldProps, + buttonProps, + dialogProps, + calendarProps: ariaCalendarProps, + validationDetails, + validationErrors, + descriptionProps, + errorMessageProps, + } = useAriaDateRangePicker(originalProps, state, domRef); + + const slots = useMemo( + () => + dateRangePicker({ + ...variantProps, + className, + }), + [objectToDeps(variantProps), className], + ); + + // Time field values + + const timeGranularity = + state.granularity === "hour" || state.granularity === "minute" || state.granularity === "second" + ? state.granularity + : null; + + const showTimeField = !!timeGranularity; + + const labelPlacement = useMemo(() => { + if ( + (!originalProps.labelPlacement || originalProps.labelPlacement === "inside") && + !originalProps.label + ) { + return "outside"; + } + + return originalProps.labelPlacement ?? "inside"; + }, [originalProps.labelPlacement, originalProps.label]); + + const shouldLabelBeOutside = labelPlacement === "outside" || labelPlacement === "outside-left"; + + /** + * ------------------------------ + * DateRangePicker Props + * ------------------------------ + */ + const getStartTimeInputProps = () => { + if (!showTimeField) return {}; + + return { + ...timeInputProps, + label: stringFormatter.format("startTime"), + value: state.timeRange?.start || null, + onChange: (v) => state.setTime("start", v), + granularity: timeGranularity, + minValue: timeMinValue, + maxValue: timeMaxValue, + classNames: { + base: slots.timeInput({ + class: clsx(classNames?.timeInput, userTimeInputProps?.classNames?.base), + }), + label: slots.timeInputLabel({ + class: clsx(classNames?.timeInputLabel, userTimeInputProps?.classNames?.label), + }), + }, + } as TimeInputProps; + }; + + const getEndTimeInputProps = () => { + if (!showTimeField) return {}; + + return { + ...timeInputProps, + label: stringFormatter.format("endTime"), + value: state.timeRange?.end || null, + onChange: (v) => state.setTime("end", v), + granularity: timeGranularity, + minValue: timeMinValue, + maxValue: timeMaxValue, + classNames: { + base: slots.timeInput({ + class: clsx(classNames?.timeInput, userTimeInputProps?.classNames?.base), + }), + label: slots.timeInputLabel({ + class: clsx(classNames?.timeInputLabel, userTimeInputProps?.classNames?.label), + }), + }, + } as TimeInputProps; + }; + + const getPopoverProps = (props: DOMAttributes = {}) => { + return { + state, + dialogProps, + ...props, + ...popoverProps, + triggerRef: popoverTriggerRef, + classNames: { + content: slots.popoverContent({ + class: clsx( + classNames?.popoverContent, + slotsProps.popoverProps?.classNames?.["content"], + props.className, + ), + }), + }, + } as PopoverProps; + }; + + const getCalendarProps = () => { + return { + ...ariaCalendarProps, + ...calendarProps, + classNames: { + base: slots.calendar({class: classNames?.calendar}), + content: slots.calendarContent({class: classNames?.calendarContent}), + }, + } as RangeCalendarProps; + }; + + const getSelectorButtonProps = () => { + return { + ...buttonProps, + ...selectorButtonProps, + onPress: state.toggle, + className: slots.selectorButton({class: classNames?.selectorButton}), + } as ButtonProps; + }; + + const getSeparatorProps = () => { + return { + "data-slot": "separator", + className: slots.separator({class: classNames?.separator}), + }; + }; + + const getSelectorIconProps = () => { + return { + ...selectorIconProps, + className: slots.selectorIcon({class: classNames?.selectorIcon}), + }; + }; + + /** + * ------------------------------ + * DateInput Props + * ------------------------------ + */ + + const baseStyles = clsx(classNames?.base, className); + + const dateInputSlots = useMemo( + () => + dateInput({ + ...variantProps, + labelPlacement, + className, + }), + [objectToDeps(variantProps), className], + ); + + const getStartDateInputProps = (props: DOMAttributes = {}) => { + return { + ...startFieldProps, + isInvalid, + "data-slot": "start-input", + slots: dateInputSlots, + createCalendar, + ...mergeProps(variantProps, startFieldProps, { + fullWidth: true, + disableAnimation, + }), + "data-open": dataAttr(state.isOpen), + classNames, + style: { + ...props.style, + maxWidth: "fit-content", + }, + className: dateInputSlots.input({ + class: clsx(classNames?.input, props?.className), + }), + } as DateRangePickerFieldProps; + }; + + const getEndDateInputProps = (props: DOMAttributes = {}) => { + return { + ...endFieldProps, + isInvalid, + "data-slot": "end-input", + slots: dateInputSlots, + createCalendar, + ...mergeProps(variantProps, endFieldProps, { + fullWidth: true, + disableAnimation, + }), + "data-open": dataAttr(state.isOpen), + classNames, + className: dateInputSlots.input({ + class: clsx(classNames?.input, props?.className), + }), + } as DateRangePickerFieldProps; + }; + + const getLabelProps: PropGetter = (props) => { + return { + ...props, + ...labelProps, + "data-slot": "label", + className: dateInputSlots.label({ + class: clsx(classNames?.label, props?.className), + }), + }; + }; + + const getInputWrapperProps = (props = {}) => { + return { + ...props, + ...groupProps, + "data-slot": "input-wrapper", + className: dateInputSlots.inputWrapper({ + class: classNames?.inputWrapper, + }), + onClick: labelProps.onClick, + } as GroupDOMAttributes; + }; + + const getInnerWrapperProps: PropGetter = (props) => { + return { + ...props, + ref: popoverTriggerRef, + "data-slot": "inner-wrapper", + className: dateInputSlots.innerWrapper({ + class: classNames?.innerWrapper, + }), + }; + }; + + const getHelperWrapperProps: PropGetter = (props) => { + return { + ...props, + "data-slot": "helper-wrapper", + className: dateInputSlots.helperWrapper({ + class: clsx(classNames?.helperWrapper, props?.className), + }), + }; + }; + + const getErrorMessageProps: PropGetter = (props = {}) => { + return { + ...props, + ...errorMessageProps, + "data-slot": "error-message", + className: dateInputSlots.errorMessage({ + class: clsx(classNames?.errorMessage, props?.className), + }), + }; + }; + + const getDescriptionProps: PropGetter = (props = {}) => { + return { + ...props, + ...descriptionProps, + "data-slot": "description", + className: dateInputSlots.description({ + class: clsx(classNames?.description, props?.className), + }), + }; + }; + + const getDateInputGroupProps = () => { + return { + as, + label: originalProps.label, + description, + endContent, + errorMessage, + isInvalid, + startContent, + validationDetails, + validationErrors, + shouldLabelBeOutside, + "data-slot": "base", + "data-required": dataAttr(originalProps.isRequired), + "data-disabled": dataAttr(originalProps.isDisabled), + "data-readonly": dataAttr(originalProps.isReadOnly), + "data-invalid": dataAttr(isInvalid), + "data-has-start-content": dataAttr(!!startContent), + "data-has-multiple-months": dataAttr(hasMultipleMonths), + "data-has-end-content": dataAttr(!!endContent), + descriptionProps: getDescriptionProps(), + errorMessageProps: getErrorMessageProps(), + groupProps: getInputWrapperProps(), + helperWrapperProps: getHelperWrapperProps(), + labelProps: getLabelProps(), + wrapperProps: getInnerWrapperProps(), + className: dateInputSlots.base({class: baseStyles}), + } as DateInputGroupProps; + }; + + return { + state, + label: originalProps.label, + slots, + classNames, + endContent, + selectorIcon, + showTimeField, + isCalendarHeaderExpanded, + disableAnimation, + CalendarTopContent, + CalendarBottomContent, + getStartDateInputProps, + getEndDateInputProps, + getStartTimeInputProps, + getEndTimeInputProps, + getPopoverProps, + getSelectorButtonProps, + getCalendarProps, + getSeparatorProps, + getSelectorIconProps, + getDateInputGroupProps, + }; +} + +export type UseDateRangePickerReturn = ReturnType; diff --git a/packages/components/date-picker/stories/date-picker.stories.tsx b/packages/components/date-picker/stories/date-picker.stories.tsx new file mode 100644 index 0000000000..0db7446cd8 --- /dev/null +++ b/packages/components/date-picker/stories/date-picker.stories.tsx @@ -0,0 +1,501 @@ +import React from "react"; +import {Meta} from "@storybook/react"; +import {dateInput} from "@nextui-org/theme"; +import { + DateValue, + getLocalTimeZone, + isWeekend, + now, + parseAbsoluteToLocal, + parseDate, + parseZonedDateTime, + startOfMonth, + startOfWeek, + today, +} from "@internationalized/date"; +import {I18nProvider, useDateFormatter, useLocale} from "@react-aria/i18n"; +import {Button, ButtonGroup} from "@nextui-org/button"; +import {Radio, RadioGroup} from "@nextui-org/radio"; +import {cn} from "@nextui-org/system"; + +import {DatePicker, DatePickerProps} from "../src"; + +export default { + title: "Components/DatePicker", + component: DatePicker, + argTypes: { + variant: { + control: { + type: "select", + }, + options: ["flat", "faded", "bordered", "underlined"], + }, + color: { + control: { + type: "select", + }, + options: ["default", "primary", "secondary", "success", "warning", "danger"], + }, + radius: { + control: { + type: "select", + }, + options: ["none", "sm", "md", "lg", "full"], + }, + size: { + control: { + type: "select", + }, + options: ["sm", "md", "lg"], + }, + labelPlacement: { + control: { + type: "select", + }, + options: ["inside", "outside", "outside-left"], + }, + isDisabled: { + control: { + type: "boolean", + }, + }, + }, + decorators: [ + (Story) => ( +
+ +
+ ), + ], +} as Meta; + +const defaultProps = { + label: "Birth Date", + className: "max-w-[256px]", + ...dateInput.defaultVariants, +}; + +const Template = (args: DatePickerProps) => ; + +const LabelPlacementTemplate = (args: DatePickerProps) => ( +
+ + + +
+); + +const ControlledTemplate = (args: DatePickerProps) => { + const [value, setValue] = React.useState(parseDate("2024-04-04")); + + let formatter = useDateFormatter({dateStyle: "full"}); + + return ( +
+
+ +

+ Selected date: {value ? formatter.format(value.toDate(getLocalTimeZone())) : "--"} +

+
+ +
+ ); +}; + +const TimeZonesTemplate = (args: DatePickerProps) => ( +
+ + +
+); + +const GranularityTemplate = (args: DatePickerProps) => { + let [date, setDate] = React.useState(parseAbsoluteToLocal("2021-04-07T18:45:22Z")); + + return ( +
+ + + + +
+ ); +}; + +const InternationalCalendarsTemplate = (args: DatePickerProps) => { + let [date, setDate] = React.useState(parseAbsoluteToLocal("2021-04-07T18:45:22Z")); + + return ( +
+ + + +
+ ); +}; + +const PresetsTemplate = (args: DatePickerProps) => { + let defaultDate = today(getLocalTimeZone()); + + const [value, setValue] = React.useState(defaultDate); + + let {locale} = useLocale(); + let formatter = useDateFormatter({dateStyle: "full"}); + + let now = today(getLocalTimeZone()); + let nextWeek = startOfWeek(now.add({weeks: 1}), locale); + let nextMonth = startOfMonth(now.add({months: 1})); + + const CustomRadio = (props) => { + const {children, ...otherProps} = props; + + return ( + + {children} + + ); + }; + + return ( +
+ + Exact dates + 1 day + 2 days + 3 days + 7 days + 14 days + + } + CalendarTopContent={ + + + + + + } + calendarProps={{ + focusedValue: value, + onFocusChange: setValue, + nextButtonProps: { + variant: "bordered", + }, + prevButtonProps: { + variant: "bordered", + }, + }} + value={value} + onChange={setValue} + {...args} + label="Event date" + /> +

+ Selected date: {value ? formatter.format(value.toDate(getLocalTimeZone())) : "--"} +

+
+ ); +}; + +const UnavailableDatesTemplate = (args: DatePickerProps) => { + let now = today(getLocalTimeZone()); + + let disabledRanges = [ + [now, now.add({days: 5})], + [now.add({days: 14}), now.add({days: 16})], + [now.add({days: 23}), now.add({days: 24})], + ]; + + let {locale} = useLocale(); + + let isDateUnavailable = (date) => + isWeekend(date, locale) || + disabledRanges.some( + (interval) => date.compare(interval[0]) >= 0 && date.compare(interval[1]) <= 0, + ); + + return ( + + ); +}; + +export const Default = { + render: Template, + args: { + ...defaultProps, + }, +}; + +export const WithMonthAndYearPickers = { + render: Template, + args: { + ...defaultProps, + variant: "bordered", + showMonthAndYearPickers: true, + }, +}; + +export const WithTimeField = { + render: Template, + args: { + ...defaultProps, + label: "Event date", + hideTimeZone: true, + showMonthAndYearPickers: true, + defaultValue: now(getLocalTimeZone()), + }, +}; + +export const LabelPlacement = { + render: LabelPlacementTemplate, + + args: { + ...defaultProps, + }, +}; + +export const Controlled = { + render: ControlledTemplate, + args: { + ...defaultProps, + }, +}; + +export const Required = { + render: Template, + args: { + ...defaultProps, + isRequired: true, + }, +}; + +export const Disabled = { + render: Template, + args: { + ...defaultProps, + isDisabled: true, + defaultValue: parseDate("2024-04-04"), + }, +}; + +export const ReadOnly = { + render: Template, + args: { + ...defaultProps, + isReadOnly: true, + defaultValue: parseDate("2024-04-04"), + }, +}; + +export const WithoutLabel = { + render: Template, + + args: { + ...defaultProps, + label: null, + "aria-label": "Birth date", + }, +}; + +export const WithDescription = { + render: Template, + + args: { + ...defaultProps, + description: "Please enter your birth date", + }, +}; + +export const SelectorIcon = { + render: Template, + + args: { + ...defaultProps, + selectorIcon: ( + + + + + + + + ), + }, +}; + +export const WithErrorMessage = { + render: Template, + + args: { + ...defaultProps, + errorMessage: "Please enter a valid date", + }, +}; + +export const IsInvalid = { + render: Template, + + args: { + ...defaultProps, + variant: "bordered", + isInvalid: true, + defaultValue: parseDate("2024-04-04"), + errorMessage: "Please enter a valid date", + }, +}; + +export const TimeZones = { + render: TimeZonesTemplate, + + args: { + ...defaultProps, + label: "Event date", + defaultValue: parseZonedDateTime("2022-11-07T00:45[America/Los_Angeles]"), + }, +}; + +export const Granularity = { + render: GranularityTemplate, + + args: { + ...defaultProps, + }, +}; + +export const InternationalCalendars = { + render: InternationalCalendarsTemplate, + + args: { + ...defaultProps, + showMonthAndYearPickers: true, + }, +}; + +export const MinDateValue = { + render: Template, + + args: { + ...defaultProps, + minValue: today(getLocalTimeZone()), + defaultValue: parseDate("2024-04-03"), + }, +}; + +export const MaxDateValue = { + render: Template, + + args: { + ...defaultProps, + maxValue: today(getLocalTimeZone()), + defaultValue: parseDate("2024-04-05"), + }, +}; + +export const UnavailableDates = { + render: UnavailableDatesTemplate, + args: { + ...defaultProps, + defaultValue: today(getLocalTimeZone()), + unavailableDates: [today(getLocalTimeZone())], + }, +}; + +export const VisibleMonths = { + render: Template, + + args: { + ...defaultProps, + visibleMonths: 2, + }, +}; + +export const PageBehavior = { + render: Template, + args: { + ...defaultProps, + visibleMonths: 2, + pageBehavior: "single", + }, +}; + +export const Presets = { + render: PresetsTemplate, + args: { + ...defaultProps, + }, +}; diff --git a/packages/components/date-picker/stories/date-range-picker.stories.tsx b/packages/components/date-picker/stories/date-range-picker.stories.tsx new file mode 100644 index 0000000000..89464e22a6 --- /dev/null +++ b/packages/components/date-picker/stories/date-range-picker.stories.tsx @@ -0,0 +1,581 @@ +import React from "react"; +import {Meta} from "@storybook/react"; +import {dateInput} from "@nextui-org/theme"; +import { + endOfMonth, + endOfWeek, + getLocalTimeZone, + isWeekend, + parseAbsoluteToLocal, + parseDate, + parseZonedDateTime, + startOfMonth, + startOfWeek, + today, +} from "@internationalized/date"; +import {RangeValue} from "@react-types/shared"; +import {DateValue} from "@react-types/datepicker"; +import {I18nProvider, useDateFormatter, useLocale} from "@react-aria/i18n"; +import {Button, ButtonGroup} from "@nextui-org/button"; +import {Radio, RadioGroup} from "@nextui-org/radio"; +import {cn} from "@nextui-org/system"; + +import {DateRangePicker, DateRangePickerProps} from "../src"; + +export default { + title: "Components/DateRangePicker", + component: DateRangePicker, + argTypes: { + variant: { + control: { + type: "select", + }, + options: ["flat", "faded", "bordered", "underlined"], + }, + color: { + control: { + type: "select", + }, + options: ["default", "primary", "secondary", "success", "warning", "danger"], + }, + radius: { + control: { + type: "select", + }, + options: ["none", "sm", "md", "lg", "full"], + }, + size: { + control: { + type: "select", + }, + options: ["sm", "md", "lg"], + }, + labelPlacement: { + control: { + type: "select", + }, + options: ["inside", "outside", "outside-left"], + }, + isDisabled: { + control: { + type: "boolean", + }, + }, + }, + decorators: [ + (Story) => ( +
+ +
+ ), + ], +} as Meta; + +const defaultProps = { + label: "Stay duration", + ...dateInput.defaultVariants, +}; + +const Template = (args: DateRangePickerProps) => ; + +const LabelPlacementTemplate = (args: DateRangePickerProps) => ( +
+ + + +
+); + +const ControlledTemplate = (args: DateRangePickerProps) => { + const [value, setValue] = React.useState>({ + start: parseDate("2024-04-01"), + end: parseDate("2024-04-08"), + }); + + let formatter = useDateFormatter({dateStyle: "long"}); + + return ( +
+
+ +

+ Selected date:{" "} + {value + ? formatter.formatRange( + value.start.toDate(getLocalTimeZone()), + value.end.toDate(getLocalTimeZone()), + ) + : "--"} +

+
+ +
+ ); +}; + +const TimeZonesTemplate = (args: DateRangePickerProps) => ( +
+ + +
+); + +const GranularityTemplate = (args: DateRangePickerProps) => { + let [date, setDate] = React.useState>({ + start: parseAbsoluteToLocal("2024-04-01T18:45:22Z"), + end: parseAbsoluteToLocal("2024-04-08T19:15:22Z"), + }); + + return ( +
+ + +
+ ); +}; + +const InternationalCalendarsTemplate = (args: DateRangePickerProps) => { + let [date, setDate] = React.useState>({ + start: parseAbsoluteToLocal("2021-04-01T18:45:22Z"), + end: parseAbsoluteToLocal("2021-04-14T19:15:22Z"), + }); + + return ( +
+ + + +
+ ); +}; + +const UnavailableDatesTemplate = (args: DateRangePickerProps) => { + let now = today(getLocalTimeZone()); + + let disabledRanges = [ + [now, now.add({days: 5})], + [now.add({days: 14}), now.add({days: 16})], + [now.add({days: 23}), now.add({days: 24})], + ]; + + return ( + + disabledRanges.some( + (interval) => date.compare(interval[0]) >= 0 && date.compare(interval[1]) <= 0, + ) + } + minValue={today(getLocalTimeZone())} + validate={(value) => + disabledRanges.some( + (interval) => + value && value.end.compare(interval[0]) >= 0 && value.start.compare(interval[1]) <= 0, + ) + ? "Selected date range may not include unavailable dates." + : null + } + {...args} + /> + ); +}; + +const NonContiguousRangesTemplate = (args: DateRangePickerProps) => { + let {locale} = useLocale(); + + return ( + isWeekend(date, locale)} + label="Time off request" + minValue={today(getLocalTimeZone())} + visibleMonths={2} + /> + ); +}; + +const PresetsTemplate = (args: DateRangePickerProps) => { + let defaultDate = { + start: today(getLocalTimeZone()), + end: today(getLocalTimeZone()).add({days: 7}), + }; + + const [value, setValue] = React.useState>(defaultDate); + + let {locale} = useLocale(); + let formatter = useDateFormatter({dateStyle: "full"}); + + let now = today(getLocalTimeZone()); + let nextWeek = { + start: startOfWeek(now.add({weeks: 1}), locale), + end: endOfWeek(now.add({weeks: 1}), locale), + }; + let nextMonth = { + start: startOfMonth(now.add({months: 1})), + end: endOfMonth(now.add({months: 1})), + }; + + const CustomRadio = (props) => { + const {children, ...otherProps} = props; + + return ( + + {children} + + ); + }; + + return ( +
+ + Exact dates + 1 day + 2 days + 3 days + 7 days + 14 days + + } + CalendarTopContent={ + + + + + + } + calendarProps={{ + focusedValue: value.start, + onFocusChange: (val) => setValue({...value, start: val}), + nextButtonProps: { + variant: "bordered", + }, + prevButtonProps: { + variant: "bordered", + }, + }} + value={value} + onChange={setValue} + {...args} + label="Event date" + /> +

+ Selected date:{" "} + {value + ? formatter.formatRange( + value.start.toDate(getLocalTimeZone()), + value.end.toDate(getLocalTimeZone()), + ) + : "--"} +

+
+ ); +}; + +export const Default = { + render: Template, + args: { + ...defaultProps, + }, +}; + +export const VisibleMonths = { + render: Template, + args: { + ...defaultProps, + visibleMonths: 2, + }, +}; + +export const LabelPlacement = { + render: LabelPlacementTemplate, + + args: { + ...defaultProps, + }, +}; + +export const WithTimeField = { + render: Template, + args: { + ...defaultProps, + label: "Event duration", + hideTimeZone: true, + visibleMonths: 2, + defaultValue: { + start: parseZonedDateTime("2024-04-01T00:45[America/Los_Angeles]"), + end: parseZonedDateTime("2024-04-08T11:15[America/Los_Angeles]"), + }, + }, +}; + +export const Controlled = { + render: ControlledTemplate, + args: { + ...defaultProps, + }, +}; + +export const Required = { + render: Template, + args: { + ...defaultProps, + isRequired: true, + }, +}; + +export const Disabled = { + render: Template, + args: { + ...defaultProps, + isDisabled: true, + defaultValue: { + start: parseDate("2024-04-01"), + end: parseDate("2024-04-08"), + }, + }, +}; + +export const ReadOnly = { + render: Template, + args: { + ...defaultProps, + isReadOnly: true, + defaultValue: { + start: parseDate("2024-04-01"), + end: parseDate("2024-04-08"), + }, + }, +}; + +export const WithoutLabel = { + render: Template, + + args: { + ...defaultProps, + label: null, + "aria-label": "Stay duration", + }, +}; + +export const WithDescription = { + render: Template, + + args: { + ...defaultProps, + description: "Please enter your stay duration", + }, +}; + +export const SelectorIcon = { + render: Template, + + args: { + ...defaultProps, + selectorIcon: ( + + + + + + + + ), + }, +}; + +export const WithErrorMessage = { + render: Template, + + args: { + ...defaultProps, + errorMessage: "Please enter your stay duration", + }, +}; + +export const IsInvalid = { + render: Template, + + args: { + ...defaultProps, + variant: "bordered", + isInvalid: true, + defaultValue: { + start: parseDate("2024-04-01"), + end: parseDate("2024-04-08"), + }, + errorMessage: "Please enter a valid date", + }, +}; + +export const TimeZones = { + render: TimeZonesTemplate, + + args: { + ...defaultProps, + label: "Event date", + defaultValue: parseZonedDateTime("2022-11-07T00:45[America/Los_Angeles]"), + }, +}; + +export const Granularity = { + render: GranularityTemplate, + + args: { + ...defaultProps, + visibleMonths: 2, + }, +}; + +export const InternationalCalendars = { + render: InternationalCalendarsTemplate, + + args: { + ...defaultProps, + hideTimeZone: true, + }, +}; + +export const MinDateValue = { + render: Template, + + args: { + ...defaultProps, + minValue: today(getLocalTimeZone()), + defaultValue: { + start: today(getLocalTimeZone()).subtract({days: 1}), + end: parseDate("2024-04-08"), + }, + }, +}; + +export const MaxDateValue = { + render: Template, + + args: { + ...defaultProps, + maxValue: today(getLocalTimeZone()), + defaultValue: { + start: parseDate("2024-04-01"), + end: today(getLocalTimeZone()).add({days: 1}), + }, + }, +}; + +export const UnavailableDates = { + render: UnavailableDatesTemplate, + args: { + ...defaultProps, + }, +}; + +export const PageBehavior = { + render: Template, + args: { + ...defaultProps, + visibleMonths: 2, + pageBehavior: "single", + }, +}; + +export const NonContiguous = { + render: NonContiguousRangesTemplate, + args: { + ...defaultProps, + }, +}; + +export const Presets = { + render: PresetsTemplate, + args: { + ...defaultProps, + visibleMonths: 2, + }, +}; diff --git a/packages/components/date-picker/tsconfig.json b/packages/components/date-picker/tsconfig.json new file mode 100644 index 0000000000..5d012f6e61 --- /dev/null +++ b/packages/components/date-picker/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "tailwind-variants": ["../../../node_modules/tailwind-variants"] + }, + }, + "include": ["src", "index.ts"] +} diff --git a/packages/components/date-picker/tsup.config.ts b/packages/components/date-picker/tsup.config.ts new file mode 100644 index 0000000000..3e2bcff6cc --- /dev/null +++ b/packages/components/date-picker/tsup.config.ts @@ -0,0 +1,8 @@ +import {defineConfig} from "tsup"; + +export default defineConfig({ + clean: true, + target: "es2019", + format: ["cjs", "esm"], + banner: {js: '"use client";'}, +}); diff --git a/packages/components/divider/CHANGELOG.md b/packages/components/divider/CHANGELOG.md index 7288b7df0b..e4d3f1b777 100644 --- a/packages/components/divider/CHANGELOG.md +++ b/packages/components/divider/CHANGELOG.md @@ -1,5 +1,31 @@ # @nextui-org/divider +## 2.0.27 + +### Patch Changes + +- Updated dependencies [[`74eda3128`](https://github.com/nextui-org/nextui/commit/74eda312883b2e17df26f71442aba9fb3cd240be)]: + - @nextui-org/system-rsc@2.1.1 + - @nextui-org/react-rsc-utils@2.0.12 + +## 2.0.26 + +### Patch Changes + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - v2.3.0 + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - - Calendar component added + - objectToDeps function applied all across components + - `useMeasure` hook added + - `useIntersectionObserver` hook added + - `framer-transitions` renamed to `framer-utils` + - `ResizablePanel` component added to `framer-utils` + - `test-utils` updated +- Updated dependencies [[`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14), [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14), [`c5049edfd`](https://github.com/nextui-org/nextui/commit/c5049edfde7edaee2081d70e581739be9dcae2f9), [`f864dc397`](https://github.com/nextui-org/nextui/commit/f864dc3974993b29ea5048483d7e0e998e8bef56)]: + - @nextui-org/system-rsc@2.1.0 + - @nextui-org/react-rsc-utils@2.0.11 + - @nextui-org/shared-utils@2.0.5 + ## 2.0.25 ### Patch Changes diff --git a/packages/components/divider/package.json b/packages/components/divider/package.json index 4d09a77cb4..b92d921405 100644 --- a/packages/components/divider/package.json +++ b/packages/components/divider/package.json @@ -1,6 +1,6 @@ { "name": "@nextui-org/divider", - "version": "2.0.25", + "version": "2.0.27", "description": ". A separator is a visual divider between two groups of content", "keywords": [ "divider" @@ -42,7 +42,7 @@ "@nextui-org/shared-utils": "workspace:*", "@nextui-org/react-rsc-utils": "workspace:*", "@nextui-org/system-rsc": "workspace:*", - "@react-types/shared": "^3.21.0" + "@react-types/shared": "^3.22.1" }, "devDependencies": { "@nextui-org/theme": "workspace:*", diff --git a/packages/components/divider/stories/divider.stories.tsx b/packages/components/divider/stories/divider.stories.tsx index fd23de075c..748c958041 100644 --- a/packages/components/divider/stories/divider.stories.tsx +++ b/packages/components/divider/stories/divider.stories.tsx @@ -35,7 +35,7 @@ const Template = (args: DividerProps) => (

Beautiful, fast and modern React UI library.

-
+
Blog
Docs
diff --git a/packages/components/dropdown/CHANGELOG.md b/packages/components/dropdown/CHANGELOG.md index a36931b53b..6929a3f4c9 100644 --- a/packages/components/dropdown/CHANGELOG.md +++ b/packages/components/dropdown/CHANGELOG.md @@ -1,5 +1,69 @@ # @nextui-org/dropdown +## 2.1.22 + +### Patch Changes + +- [#2784](https://github.com/nextui-org/nextui/pull/2784) [`183a4a6cf`](https://github.com/nextui-org/nextui/commit/183a4a6cfda193a076a4a30550ab93b72d51002d) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - Fix `isDisabled` prop warning on NextUI components that don't support this property, it is also fixed for non-NextUI components. + +- Updated dependencies [[`183a4a6cf`](https://github.com/nextui-org/nextui/commit/183a4a6cfda193a076a4a30550ab93b72d51002d), [`eccc2f2f3`](https://github.com/nextui-org/nextui/commit/eccc2f2f3d856eefb2cc7c07b94e1c4cefd4d7d0)]: + - @nextui-org/popover@2.1.20 + - @nextui-org/react-utils@2.0.13 + - @nextui-org/menu@2.0.21 + +## 2.1.21 + +### Patch Changes + +- Updated dependencies [[`9e5dd8ce3`](https://github.com/nextui-org/nextui/commit/9e5dd8ce37c94c9ca1ba7b2049a6e55f1803fee9)]: + - @nextui-org/popover@2.1.19 + +## 2.1.20 + +### Patch Changes + +- [#2746](https://github.com/nextui-org/nextui/pull/2746) [`6b56e43a3`](https://github.com/nextui-org/nextui/commit/6b56e43a350d045c36eb9983c7f48ba61db7cdd2) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - Fix #2743 #2751 internal react-aria use-menu hooks implemented to pass down the press events and control the pressUp one + +- Updated dependencies [[`6b56e43a3`](https://github.com/nextui-org/nextui/commit/6b56e43a350d045c36eb9983c7f48ba61db7cdd2), [`f89356691`](https://github.com/nextui-org/nextui/commit/f89356691cecb8e54f5f820b2b4491537e7c11f3)]: + - @nextui-org/menu@2.0.20 + - @nextui-org/popover@2.1.18 + +## 2.1.19 + +### Patch Changes + +- Updated dependencies []: + - @nextui-org/menu@2.0.19 + - @nextui-org/popover@2.1.17 + - @nextui-org/react-utils@2.0.12 + +## 2.1.18 + +### Patch Changes + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - v2.3.0 + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - Fixed the issue where only two keyframes were supported with spring and inertia animations. + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - - Calendar component added + + - objectToDeps function applied all across components + - `useMeasure` hook added + - `useIntersectionObserver` hook added + - `framer-transitions` renamed to `framer-utils` + - `ResizablePanel` component added to `framer-utils` + - `test-utils` updated + +- [#2450](https://github.com/nextui-org/nextui/pull/2450) [`0a9982d3e`](https://github.com/nextui-org/nextui/commit/0a9982d3efe6ac8dfc25438f21598c8fe53de4db) Thanks [@wingkwong](https://github.com/wingkwong)! - fixed getMenuTriggerProps mergeProps (#2448) + +- [#2458](https://github.com/nextui-org/nextui/pull/2458) [`7263daca0`](https://github.com/nextui-org/nextui/commit/7263daca08674338eb28529315070337ba0dfc17) Thanks [@wingkwong](https://github.com/wingkwong)! - fix(autocomplete): support isReadOnly for dynamic collections in Autocomplete + +- Updated dependencies [[`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14), [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14), [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14), [`a05aef0ac`](https://github.com/nextui-org/nextui/commit/a05aef0acb5a7b000c8131e8ba4f50f0adec01e5), [`2b9f89023`](https://github.com/nextui-org/nextui/commit/2b9f89023ac087016083dcc205703ae1b2bc9cb8), [`c5049edfd`](https://github.com/nextui-org/nextui/commit/c5049edfde7edaee2081d70e581739be9dcae2f9), [`8761168d3`](https://github.com/nextui-org/nextui/commit/8761168d3459cd83ce571f4e65eb8ea6db8516ef), [`eb51bf226`](https://github.com/nextui-org/nextui/commit/eb51bf226170e4bb37ae30990d1c3aa26d8c504b), [`7263daca0`](https://github.com/nextui-org/nextui/commit/7263daca08674338eb28529315070337ba0dfc17), [`2894aecca`](https://github.com/nextui-org/nextui/commit/2894aecca1a2ef0dfb3066b9b8df24ce48c99dae)]: + - @nextui-org/menu@2.0.18 + - @nextui-org/popover@2.1.16 + - @nextui-org/react-utils@2.0.11 + - @nextui-org/shared-utils@2.0.5 + ## 2.1.17 ### Patch Changes diff --git a/packages/components/dropdown/__tests__/dropdown.test.tsx b/packages/components/dropdown/__tests__/dropdown.test.tsx index 1f3b6d57a7..3080321f5b 100644 --- a/packages/components/dropdown/__tests__/dropdown.test.tsx +++ b/packages/components/dropdown/__tests__/dropdown.test.tsx @@ -3,6 +3,8 @@ import {act, render} from "@testing-library/react"; import {Button} from "@nextui-org/button"; import userEvent from "@testing-library/user-event"; import {User} from "@nextui-org/user"; +import {Image} from "@nextui-org/image"; +import {Avatar} from "@nextui-org/avatar"; import {Dropdown, DropdownTrigger, DropdownMenu, DropdownItem, DropdownSection} from "../src"; @@ -109,6 +111,7 @@ describe("Dropdown", () => { items={section.children} title={section.title} > + {/* @ts-ignore */} {(item: any) => {item.name}} )} @@ -145,6 +148,10 @@ describe("Dropdown", () => { }); expect(spy).toBeCalledTimes(0); + + let menu = wrapper.queryByRole("menu"); + + expect(menu).toBeTruthy(); }); it("should work with single selection (controlled)", async () => { @@ -454,14 +461,11 @@ describe("Dropdown", () => { expect(onSelectionChange).toBeCalledTimes(0); }); - it("should render without error (custom trigger + isDisabled)", async () => { + it("should render without error (custom trigger with isDisabled)", async () => { const spy = jest.spyOn(console, "error").mockImplementation(() => {}); - render( - - -
Trigger
-
+ const renderDropdownMenu = () => { + return ( New file Copy link @@ -470,6 +474,16 @@ describe("Dropdown", () => { Delete file + ); + }; + + // Non Next UI Element in DropdownTrigger + render( + + +
Trigger
+
+ {renderDropdownMenu()}
, ); @@ -477,19 +491,45 @@ describe("Dropdown", () => { spy.mockRestore(); + // Next UI Element in DropdownTrigger render( - - New file - Copy link - Edit file - - Delete file - - + {renderDropdownMenu()} + , + ); + + expect(spy).toBeCalledTimes(0); + + spy.mockRestore(); + + // NextUI Element that supports isDisabled prop in DropdownTrigger + render( + + + + + {renderDropdownMenu()} + , + ); + + expect(spy).toBeCalledTimes(0); + + spy.mockRestore(); + + // NextUI Element that doesn't support isDisabled prop in DropdownTrigger + render( + + + NextUI hero Image + + {renderDropdownMenu()} , ); diff --git a/packages/components/dropdown/package.json b/packages/components/dropdown/package.json index d4d3bf619f..fcf44fb42a 100644 --- a/packages/components/dropdown/package.json +++ b/packages/components/dropdown/package.json @@ -1,6 +1,6 @@ { "name": "@nextui-org/dropdown", - "version": "2.1.17", + "version": "2.1.22", "description": "A dropdown displays a list of actions or options that a user can choose.", "keywords": [ "dropdown" @@ -45,11 +45,11 @@ "@nextui-org/popover": "workspace:*", "@nextui-org/shared-utils": "workspace:*", "@nextui-org/react-utils": "workspace:*", - "@react-aria/menu": "^3.11.1", - "@react-aria/utils": "^3.21.1", - "@react-stately/menu": "^3.5.6", - "@react-aria/focus": "^3.14.3", - "@react-types/menu": "^3.9.5" + "@react-aria/menu": "^3.13.1", + "@react-aria/utils": "^3.23.2", + "@react-stately/menu": "^3.6.1", + "@react-aria/focus": "^3.16.2", + "@react-types/menu": "^3.9.7" }, "devDependencies": { "@nextui-org/theme": "workspace:*", @@ -57,8 +57,9 @@ "@nextui-org/button": "workspace:*", "@nextui-org/avatar": "workspace:*", "@nextui-org/user": "workspace:*", + "@nextui-org/image": "workspace:*", "@nextui-org/shared-icons": "workspace:*", - "framer-motion": "^10.16.4", + "framer-motion": "^11.0.22", "clean-package": "2.2.0", "react": "^18.0.0", "react-dom": "^18.0.0" diff --git a/packages/components/dropdown/src/use-dropdown.ts b/packages/components/dropdown/src/use-dropdown.ts index d71afed1d1..55fb9071b1 100644 --- a/packages/components/dropdown/src/use-dropdown.ts +++ b/packages/components/dropdown/src/use-dropdown.ts @@ -47,10 +47,10 @@ export function useDropdown(props: UseDropdownProps) { isOpen, defaultOpen, onOpenChange, + isDisabled, type = "menu", trigger = "press", placement = "bottom", - isDisabled = false, closeOnSelect = true, shouldBlockScroll = true, classNames: classNamesProp, @@ -139,7 +139,11 @@ export function useDropdown(props: UseDropdownProps) { return { ref: mergeRefs(_ref, menuRef), menuProps, - ...mergeProps(props, {onAction: () => onMenuAction(props?.closeOnSelect)}), + closeOnSelect, + ...mergeProps(props, { + onAction: () => onMenuAction(props?.closeOnSelect), + onClose: state.close, + }), } as MenuProps; }; diff --git a/packages/components/dropdown/stories/dropdown.stories.tsx b/packages/components/dropdown/stories/dropdown.stories.tsx index 95ab23cc83..7a74ef096a 100644 --- a/packages/components/dropdown/stories/dropdown.stories.tsx +++ b/packages/components/dropdown/stories/dropdown.stories.tsx @@ -84,6 +84,11 @@ export default { type: "boolean", }, }, + isDisabled: { + control: { + type: "boolean", + }, + }, disableAnimation: { control: { type: "boolean", @@ -109,6 +114,7 @@ const defaultProps = { ...dropdown.defaultVariants, placement: "bottom", offset: 7, + isDisabled: false, defaultOpen: false, disableAnimation: false, }; @@ -137,7 +143,7 @@ const Template = ({color, variant, ...args}: DropdownProps & DropdownMenuProps) - + New file Copy link Edit file @@ -569,6 +575,24 @@ const CustomTriggerTemplate = ({variant, ...args}) => { ); }; +const CustomHTMLTrigger = ({variant, ...args}) => { + return ( + + + Profile + + + New file + Copy link + Edit file + + Delete file + + + + ); +}; + export const Default = { render: Template, @@ -695,6 +719,16 @@ export const WithCustomTrigger = { }, }; +export const WithCustomHTMLTrigger = { + render: CustomHTMLTrigger, + + args: { + ...defaultProps, + variant: "flat", + offset: 14, + }, +}; + export const DisableAnimation = { render: WithStartContentTemplate, diff --git a/packages/components/image/CHANGELOG.md b/packages/components/image/CHANGELOG.md index 3056e018a1..76ba8c67b6 100644 --- a/packages/components/image/CHANGELOG.md +++ b/packages/components/image/CHANGELOG.md @@ -1,5 +1,37 @@ # @nextui-org/image +## 2.0.27 + +### Patch Changes + +- Updated dependencies [[`eccc2f2f3`](https://github.com/nextui-org/nextui/commit/eccc2f2f3d856eefb2cc7c07b94e1c4cefd4d7d0)]: + - @nextui-org/react-utils@2.0.13 + +## 2.0.26 + +### Patch Changes + +- Updated dependencies []: + - @nextui-org/react-utils@2.0.12 + +## 2.0.25 + +### Patch Changes + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - v2.3.0 + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - - Calendar component added + - objectToDeps function applied all across components + - `useMeasure` hook added + - `useIntersectionObserver` hook added + - `framer-transitions` renamed to `framer-utils` + - `ResizablePanel` component added to `framer-utils` + - `test-utils` updated +- Updated dependencies [[`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14), [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14)]: + - @nextui-org/react-utils@2.0.11 + - @nextui-org/shared-utils@2.0.5 + - @nextui-org/use-image@2.0.5 + ## 2.0.24 ### Patch Changes diff --git a/packages/components/image/package.json b/packages/components/image/package.json index 5669a29154..9ed834d9fe 100644 --- a/packages/components/image/package.json +++ b/packages/components/image/package.json @@ -1,6 +1,6 @@ { "name": "@nextui-org/image", - "version": "2.0.24", + "version": "2.0.27", "description": "A simple image component", "keywords": [ "image" diff --git a/packages/components/image/src/use-image.ts b/packages/components/image/src/use-image.ts index 3ef8ee1f36..7e516d9823 100644 --- a/packages/components/image/src/use-image.ts +++ b/packages/components/image/src/use-image.ts @@ -4,7 +4,7 @@ import {ImgHTMLAttributes, useCallback} from "react"; import {HTMLNextUIProps, mapPropsVariants, PropGetter} from "@nextui-org/system"; import {image} from "@nextui-org/theme"; import {useDOMRef} from "@nextui-org/react-utils"; -import {clsx, dataAttr} from "@nextui-org/shared-utils"; +import {clsx, dataAttr, objectToDeps} from "@nextui-org/shared-utils"; import {ReactRef} from "@nextui-org/react-utils"; import {useImage as useImageBase} from "@nextui-org/use-image"; import {useMemo} from "react"; @@ -130,7 +130,7 @@ export function useImage(originalProps: UseImageProps) { ...variantProps, showSkeleton, }), - [...Object.values(variantProps), showSkeleton], + [objectToDeps(variantProps), showSkeleton], ); const baseStyles = clsx(className, classNames?.img); diff --git a/packages/components/input/CHANGELOG.md b/packages/components/input/CHANGELOG.md index 55eb602264..bd7e850149 100644 --- a/packages/components/input/CHANGELOG.md +++ b/packages/components/input/CHANGELOG.md @@ -1,5 +1,43 @@ # @nextui-org/input +## 2.1.20 + +### Patch Changes + +- Updated dependencies [[`eccc2f2f3`](https://github.com/nextui-org/nextui/commit/eccc2f2f3d856eefb2cc7c07b94e1c4cefd4d7d0)]: + - @nextui-org/react-utils@2.0.13 + +## 2.1.19 + +### Patch Changes + +- Updated dependencies []: + - @nextui-org/react-utils@2.0.12 + +## 2.1.18 + +### Patch Changes + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - v2.3.0 + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - - Calendar component added + + - objectToDeps function applied all across components + - `useMeasure` hook added + - `useIntersectionObserver` hook added + - `framer-transitions` renamed to `framer-utils` + - `ResizablePanel` component added to `framer-utils` + - `test-utils` updated + +- [#2618](https://github.com/nextui-org/nextui/pull/2618) [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - Fixed react-hook-form uncontrolled components (#1969) + +- [#2316](https://github.com/nextui-org/nextui/pull/2316) [`52dafd08f`](https://github.com/nextui-org/nextui/commit/52dafd08f178483e79dc847b61d1c761af26eb8e) Thanks [@mrbadri](https://github.com/mrbadri)! - Add RTL support to the input component + +- Updated dependencies [[`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14), [`dc0bcf13a`](https://github.com/nextui-org/nextui/commit/dc0bcf13a5e9aa0450938bcca47cd4c696066f14)]: + - @nextui-org/react-utils@2.0.11 + - @nextui-org/shared-icons@2.0.7 + - @nextui-org/shared-utils@2.0.5 + ## 2.1.17 ### Patch Changes diff --git a/packages/components/input/__tests__/input.test.tsx b/packages/components/input/__tests__/input.test.tsx index 4a594f7a36..d00bd400c0 100644 --- a/packages/components/input/__tests__/input.test.tsx +++ b/packages/components/input/__tests__/input.test.tsx @@ -1,5 +1,5 @@ import * as React from "react"; -import {render, waitFor} from "@testing-library/react"; +import {render} from "@testing-library/react"; import {Input} from "../src"; @@ -49,7 +49,7 @@ describe("Input", () => { }); it("should have aria-describedby when errorMessage is provided", () => { - const {container} = render(); + const {container} = render(); expect(container.querySelector("input")).toHaveAttribute("aria-describedby"); }); @@ -99,7 +99,8 @@ describe("Input", () => { expect(onFocus).toHaveBeenCalledTimes(1); }); - it("ref should update the value", async () => { + + it("ref should update the value", () => { const ref = React.createRef(); const {container} = render(); @@ -113,11 +114,6 @@ describe("Input", () => { container.querySelector("input")?.focus(); - await waitFor(() => { - return expect(ref.current?.value)?.toBe(value); - }); - await waitFor(() => { - return expect(ref.current?.value)?.toBe(value); - }); + expect(ref.current?.value)?.toBe(value); }); }); diff --git a/packages/components/input/package.json b/packages/components/input/package.json index fb9f46eb06..0f1f42c7de 100644 --- a/packages/components/input/package.json +++ b/packages/components/input/package.json @@ -1,6 +1,6 @@ { "name": "@nextui-org/input", - "version": "2.1.17", + "version": "2.1.20", "description": "The input component is designed for capturing user input within a text field.", "keywords": [ "input" @@ -43,14 +43,14 @@ "@nextui-org/react-utils": "workspace:*", "@nextui-org/shared-icons": "workspace:*", "@nextui-org/shared-utils": "workspace:*", - "@react-aria/focus": "^3.14.3", - "@react-aria/interactions": "^3.19.1", - "@react-aria/textfield": "^3.12.2", - "@react-aria/utils": "^3.21.1", - "@react-stately/utils": "^3.8.0", - "@react-types/shared": "^3.21.0", - "@react-types/textfield": "^3.8.1", - "react-textarea-autosize": "^8.5.2" + "@react-aria/focus": "^3.16.2", + "@react-aria/interactions": "^3.21.1", + "@react-aria/textfield": "^3.14.3", + "@react-aria/utils": "^3.23.2", + "@react-stately/utils": "^3.9.1", + "@react-types/shared": "^3.22.1", + "@react-types/textfield": "^3.9.1", + "react-textarea-autosize": "^8.5.3" }, "devDependencies": { "@nextui-org/theme": "workspace:*", diff --git a/packages/components/input/src/input.tsx b/packages/components/input/src/input.tsx index 67c4fd6df1..9414472494 100644 --- a/packages/components/input/src/input.tsx +++ b/packages/components/input/src/input.tsx @@ -19,6 +19,7 @@ const Input = forwardRef<"input", InputProps>((props, ref) => { isOutsideLeft, shouldLabelBeOutside, errorMessage, + isInvalid, getBaseProps, getLabelProps, getInputProps, @@ -46,7 +47,7 @@ const Input = forwardRef<"input", InputProps>((props, ref) => { return (
- {errorMessage ? ( + {isInvalid && errorMessage ? (
{errorMessage}
) : description ? (
{description}
@@ -55,6 +56,7 @@ const Input = forwardRef<"input", InputProps>((props, ref) => { ); }, [ hasHelper, + isInvalid, errorMessage, description, getHelperWrapperProps, @@ -63,19 +65,11 @@ const Input = forwardRef<"input", InputProps>((props, ref) => { ]); const innerWrapper = useMemo(() => { - if (startContent || end) { - return ( -
- {startContent} - - {end} -
- ); - } - return (
+ {startContent} + {end}
); }, [startContent, end, getInputProps, getInnerWrapperProps]); diff --git a/packages/components/input/src/textarea.tsx b/packages/components/input/src/textarea.tsx index 60ad2d0b74..ace8ae4b53 100644 --- a/packages/components/input/src/textarea.tsx +++ b/packages/components/input/src/textarea.tsx @@ -78,6 +78,7 @@ const Textarea = forwardRef<"textarea", TextAreaProps>( hasHelper, shouldLabelBeOutside, shouldLabelBeInside, + isInvalid, errorMessage, getBaseProps, getLabelProps, @@ -144,7 +145,7 @@ const Textarea = forwardRef<"textarea", TextAreaProps>(
{hasHelper ? (
- {errorMessage ? ( + {isInvalid && errorMessage ? (
{errorMessage}
) : description ? (
{description}
diff --git a/packages/components/input/src/use-input.ts b/packages/components/input/src/use-input.ts index c523a1350d..b3704f485a 100644 --- a/packages/components/input/src/use-input.ts +++ b/packages/components/input/src/use-input.ts @@ -1,4 +1,5 @@ import type {InputVariantProps, SlotsToClasses, InputSlots} from "@nextui-org/theme"; +import type {AriaTextFieldOptions} from "@react-aria/textfield"; import {HTMLNextUIProps, mapPropsVariants, PropGetter} from "@nextui-org/system"; import {AriaTextFieldProps} from "@react-types/textfield"; @@ -6,7 +7,7 @@ import {useFocusRing} from "@react-aria/focus"; import {input} from "@nextui-org/theme"; import {useDOMRef, filterDOMProps} from "@nextui-org/react-utils"; import {useFocusWithin, useHover, usePress} from "@react-aria/interactions"; -import {clsx, dataAttr, isEmpty, safeAriaLabel} from "@nextui-org/shared-utils"; +import {clsx, dataAttr, isEmpty, objectToDeps, safeAriaLabel} from "@nextui-org/shared-utils"; import {useControlledState} from "@react-stately/utils"; import {useMemo, Ref, useCallback, useState} from "react"; import {chain, mergeProps} from "@react-aria/utils"; @@ -76,8 +77,10 @@ export interface Props void; } +type AutoCapitalize = AriaTextFieldOptions<"input">["autoCapitalize"]; + export type UseInputProps = - Props & Omit & InputVariantProps; + Props & Omit & InputVariantProps; export function useInput( originalProps: UseInputProps, @@ -92,7 +95,6 @@ export function useInput(ref); + const baseDomRef = useDOMRef(baseRef); + const inputWrapperRef = useDOMRef(wrapperRef); + const innerWrapperRef = useDOMRef(innerWrapperRefProp); + const [inputValue, setInputValue] = useControlledState( props.value, - props.defaultValue, + props.defaultValue ?? "", handleValueChange, ); - const [isFocusWithin, setFocusWithin] = useState(false); - - const Component = as || "div"; - const isFilledByDefault = ["date", "time", "month", "week", "range"].includes(type!); const isFilled = !isEmpty(inputValue) || isFilledByDefault; const isFilledWithin = isFilled || isFocusWithin; const baseStyles = clsx(classNames?.base, className, isFilled ? "is-filled" : ""); const isMultiline = originalProps.isMultiline; - const domRef = useDOMRef(ref); - const baseDomRef = useDOMRef(baseRef); - const inputWrapperRef = useDOMRef(wrapperRef); - const innerWrapperRef = useDOMRef(innerWrapperRefProp); - const handleClear = useCallback(() => { setInputValue(""); @@ -141,10 +143,20 @@ export function useInput(() => { if ((!originalProps.labelPlacement || originalProps.labelPlacement === "inside") && !label) { @@ -184,6 +196,10 @@ export function useInput (
); +const FormTemplate = (args) => ( +
{ + alert(`Submitted value: ${e.target["example"].value}`); + e.preventDefault(); + }} + > + + +
+); + const PasswordTemplate = (args) => { const [isPasswordVisible, setIsPasswordVisible] = React.useState(false); @@ -465,7 +483,7 @@ export const Default = { }; export const Required = { - render: MirrorTemplate, + render: FormTemplate, args: { ...defaultProps, @@ -581,10 +599,53 @@ export const WithErrorMessage = { args: { ...defaultProps, + isInvalid: true, errorMessage: "Please enter a valid email address", }, }; +export const WithErrorMessageFunction = { + render: FormTemplate, + + args: { + ...defaultProps, + min: "0", + max: "100", + type: "number", + isRequired: true, + label: "Number", + placeholder: "Enter a number(0-100)", + errorMessage: (value: ValidationResult) => { + if (value.validationDetails.rangeOverflow) { + return "Value is too high"; + } + if (value.validationDetails.rangeUnderflow) { + return "Value is too low"; + } + if (value.validationDetails.valueMissing) { + return "Value is required"; + } + }, + }, +}; + +export const WithValidation = { + render: FormTemplate, + + args: { + ...defaultProps, + type: "number", + validate: (value) => { + if (value < 0 || value > 100) { + return "Value must be between 0 and 100"; + } + }, + isRequired: true, + label: "Number", + placeholder: "Enter a number(0-100)", + }, +}; + export const IsInvalid = { render: Template, diff --git a/packages/components/input/stories/textarea.stories.tsx b/packages/components/input/stories/textarea.stories.tsx index cddfb8df34..9c75c2445d 100644 --- a/packages/components/input/stories/textarea.stories.tsx +++ b/packages/components/input/stories/textarea.stories.tsx @@ -1,7 +1,10 @@ +import type {ValidationResult} from "@react-types/shared"; + import React from "react"; import {Meta} from "@storybook/react"; import {input} from "@nextui-org/theme"; import {SendFilledIcon, PlusFilledIcon} from "@nextui-org/shared-icons"; +import {button} from "@nextui-org/theme"; import {Textarea, TextAreaProps} from "../src"; @@ -99,6 +102,24 @@ const MaxRowsTemplate = (args: TextAreaProps) => (
); +const FormTemplate = (args: TextAreaProps) => ( +
{ + alert(`Submitted value: ${e.target["textarea"].value}`); + e.preventDefault(); + }} + > +
+