From 0bf14aa65eb00aa86bec76a9da4209ef686faec0 Mon Sep 17 00:00:00 2001 From: ruru <142723369+ruru-m07@users.noreply.github.com> Date: Fri, 16 Aug 2024 13:42:25 +0530 Subject: [PATCH] feat(ui): add animations to components --- .github/FUNDING.yml | 1 + CONTRIBUTING.md | 41 ++++- apps/www/app/layout.tsx | 8 +- apps/www/components/animationToggle.tsx | 17 ++ apps/www/components/scroll-area.tsx | 48 +++++ apps/www/content/docs/components/tabs.mdx | 124 ++++++------- apps/www/package.json | 1 + .../public/registry/components/button.json | 2 +- .../public/registry/components/checkbox.json | 2 +- .../public/registry/components/select.json | 2 +- .../public/registry/components/switch.json | 2 +- apps/www/public/registry/components/tabs.json | 2 +- packages/cli/changelog.mdx | 20 +++ {.changeset => packages/ui}/changelog.mdx | 4 - packages/ui/package.json | 1 + packages/ui/src/components/button.tsx | 59 ++++--- packages/ui/src/components/checkbox.tsx | 165 +++++++++++------- packages/ui/src/components/select.tsx | 115 ++++++++++-- packages/ui/src/components/switch.tsx | 2 +- packages/ui/src/components/tabs.tsx | 94 +++++++++- packages/ui/src/interface/RuruContextType.ts | 15 +- .../ui/src/interface/RuruProviderProps.ts | 1 + packages/ui/src/provider/index.tsx | 7 +- packages/ui/src/provider/theme.tsx | 20 ++- pnpm-lock.yaml | 25 +++ 25 files changed, 571 insertions(+), 207 deletions(-) create mode 100644 .github/FUNDING.yml create mode 100644 apps/www/components/animationToggle.tsx create mode 100644 apps/www/components/scroll-area.tsx create mode 100644 packages/cli/changelog.mdx rename {.changeset => packages/ui}/changelog.mdx (99%) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..f47c979 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: ruru-m07 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6b0a303..e040b5b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,43 @@ -# Contribution Guidelines +## Contribution Guidelines -Welcome to our project! We appreciate your interest in contributing. Before you get started, please take a moment to review the following guidelines. +Thank you for your interest in contributing to this project! We're excited to have you collaborate with us. +Before you dive in, please take a moment to review these guidelines. + +### General Guidelines + +This project is organized as a monorepo and utilizes Turborepo, pnpm, and +[Changesets](https://github.com/changesets/changesets). + +#### Before You Submit + +- Ensure there are no existing pull requests (PRs) that address the same issue or feature. +- Format your code using `pnpm run prettier`. +- Document your changes by running `pnpm changeset` to create a changeset. +- Execute unit tests with `pnpm test` and update any snapshots as needed. + +#### Adding New Features + +If you plan to add a new feature, please open an issue first (Feature Request) with detailed information and justification for the feature. +Once the feature request is approved, feel free to proceed with your pull request. + +#### Fixing Bugs + +When fixing a bug, include a thorough description of the issue, along with a live demo if possible. +Alternatively, you can submit a bug report and reference it in your PR. + +#### Contributing to Documentation + +Improving documentation is always welcome. Please check for any typos or grammatical errors before submitting changes. + +### New to Open Source? + +A great way to start contributing is by working on documentation. +The documentation files can be found in `/apps/docs/content/docs`. + +To preview the documentation site in development mode, +first build the necessary dependencies using `pnpm run build --filter=./packages/*`, then start the development server with `pnpm run dev --filter=docs`. + +No extra environment variables are required to run this project. ## Code of Conduct diff --git a/apps/www/app/layout.tsx b/apps/www/app/layout.tsx index 371e4e5..e3b27f6 100644 --- a/apps/www/app/layout.tsx +++ b/apps/www/app/layout.tsx @@ -4,7 +4,9 @@ import { RootProvider } from "fumadocs-ui/provider"; import type { Viewport } from "next"; import { GeistSans } from "geist/font/sans"; import type { ReactNode } from "react"; +import { RuruProvider } from "ruru-ui/provider"; import "fumadocs-ui/style.css"; +import { ScrollArea } from "@/components/scroll-area"; export const metadata = createMetadata({ title: { @@ -27,7 +29,11 @@ export default function Layout({ children }: { children: ReactNode }) { return ( - {children} + + + {children} + + ); diff --git a/apps/www/components/animationToggle.tsx b/apps/www/components/animationToggle.tsx new file mode 100644 index 0000000..ef251f3 --- /dev/null +++ b/apps/www/components/animationToggle.tsx @@ -0,0 +1,17 @@ +"use client"; + +import React from "react"; +import { Switch } from "ruru-ui/components/switch"; +import { useRuru } from "ruru-ui/provider"; + +const AnimationToggle = () => { + const { setAnimation } = useRuru(); + return ( +
+ setAnimation(e)} id="toggle-animation" /> + +
+ ); +}; + +export default AnimationToggle; diff --git a/apps/www/components/scroll-area.tsx b/apps/www/components/scroll-area.tsx new file mode 100644 index 0000000..6a79f9c --- /dev/null +++ b/apps/www/components/scroll-area.tsx @@ -0,0 +1,48 @@ +"use client"; + +import * as React from "react"; +import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"; + +import { cn } from "@/utils/cn"; + +const ScrollArea = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + {children} + + + + +)); +ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName; + +const ScrollBar = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, orientation = "vertical", ...props }, ref) => ( + + + +)); +ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName; + +export { ScrollArea, ScrollBar }; diff --git a/apps/www/content/docs/components/tabs.mdx b/apps/www/content/docs/components/tabs.mdx index a01d37c..0289bff 100644 --- a/apps/www/content/docs/components/tabs.mdx +++ b/apps/www/content/docs/components/tabs.mdx @@ -57,22 +57,22 @@ import { Tabs, Tab } from "fumadocs-ui/components/tabs"; - ```tsx - import { Tabs, Tab } from "fumadocs-ui/components/tabs"; - - export function TabsDemo() { - return ( -
- - Apple - Orange - Mango - -
- ); - } - - ``` +```tsx +import { Tabs, Tab } from "ruru-ui/components/tabs"; + +export function TabsDemo() { + return ( +
+ + Apple + Orange + Mango + +
+ ); +} + +```
@@ -92,22 +92,22 @@ import { Tabs, Tab } from "fumadocs-ui/components/tabs"; - ```tsx - import { Tabs, Tab } from "fumadocs-ui/components/tabs"; - - export function DefaultTabsDemo() { - return ( -
- - Apple - Orange - Mango - -
- ); - } - - ``` +```tsx +import { Tabs, Tab } from "ruru-ui/components/tabs"; + +export function DefaultTabsDemo() { + return ( +
+ + Apple + Orange + Mango + +
+ ); +} + +```
@@ -125,21 +125,21 @@ import { Tabs, Tab } from "fumadocs-ui/components/tabs"; - ```tsx - import { Tabs, Tab } from "fumadocs-ui/components/tabs"; - - export function DisabledTabsDemo() { - return ( -
- - Apple - Orange - Mango - -
- ); - } - ``` +```tsx +import { Tabs, Tab } from "ruru-ui/components/tabs"; + +export function DisabledTabsDemo() { + return ( +
+ + Apple + Orange + Mango + +
+ ); +} +```
@@ -157,21 +157,21 @@ import { Tabs, Tab } from "fumadocs-ui/components/tabs"; - ```tsx - import { Tabs, Tab } from "fumadocs-ui/components/tabs"; - - export function DefaultIndexTabsDemo() { - return ( -
- - Apple - Orange - Mango - -
- ); - } - ``` +```tsx +import { Tabs, Tab } from "ruru-ui/components/tabs"; + +export function DefaultIndexTabsDemo() { + return ( +
+ + Apple + Orange + Mango + +
+ ); +} +```
diff --git a/apps/www/package.json b/apps/www/package.json index 0813ab3..229b2ee 100644 --- a/apps/www/package.json +++ b/apps/www/package.json @@ -11,6 +11,7 @@ }, "dependencies": { "@radix-ui/react-icons": "^1.3.0", + "@radix-ui/react-scroll-area": "^1.1.0", "fs": "0.0.1-security", "fumadocs-core": "12.4.2", "fumadocs-docgen": "^1.1.0", diff --git a/apps/www/public/registry/components/button.json b/apps/www/public/registry/components/button.json index e10b734..6dba07e 100644 --- a/apps/www/public/registry/components/button.json +++ b/apps/www/public/registry/components/button.json @@ -4,7 +4,7 @@ "files": [ { "name": "button.tsx", - "content": "\"use client\";\n\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport React from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { Spinner } from \"./spinner\";\n\nexport const buttonVariants = cva(\n \"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50\",\n {\n variants: {\n variant: {\n default:\n \"bg-primary text-primary-foreground shadow hover:bg-primary/85 hover:shadow-md\",\n secondary:\n \"border-input border-[1.5px] bg-primary-foreground hover:bg-[#f3f3f3] dark:hover:bg-[#202020]\",\n tertiary: \"text-primary hover:bg-[#f3f3f3] dark:hover:bg-[#202020]\",\n error: \"bg-[#d93036] hover:bg-[#ff6166]\",\n warning: \"bg-[#ff990a] text-primary-foreground hover:bg-[#d27504]\",\n },\n size: {\n default: \"h-9 px-4 py-2\",\n small: \"h-8 rounded-md px-3 text-xs\",\n large: \"h-10 rounded-md px-8\",\n icon: \"size-9\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n },\n);\n\nexport interface ButtonProps\n extends Omit<\n React.ButtonHTMLAttributes,\n \"prefix\" | \"suffix\"\n >,\n VariantProps {\n \n asChild?: boolean;\n \n prefix?: React.ReactNode;\n \n suffix?: React.ReactNode;\n \n disabled?: boolean;\n \n loading?: boolean;\n}\n\nexport const Button = React.forwardRef(\n (\n {\n className,\n variant = \"default\",\n size = \"default\",\n asChild = false,\n prefix,\n suffix,\n disabled = false,\n loading = false,\n ...props\n },\n ref,\n ) => {\n const Comp = asChild ? Slot : \"button\";\n\n return (\n
\n \n {loading ? : null}\n {prefix ? (\n \n {prefix}\n \n ) : null}\n {props.children}\n {suffix ? (\n \n {suffix}\n \n ) : null}\n \n
\n );\n },\n);\n\nButton.displayName = \"Button\";\n" + "content": "\"use client\";\n\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport React from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { Spinner } from \"./spinner\";\nimport { motion } from \"framer-motion\";\nimport { useRuru } from \"@/provider\";\n\nexport const buttonVariants = cva(\n \"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50\",\n {\n variants: {\n variant: {\n default:\n \"bg-primary text-primary-foreground shadow hover:bg-primary/85 hover:shadow-md\",\n secondary:\n \"border-input border-[1.5px] bg-primary-foreground hover:bg-[#f3f3f3] dark:hover:bg-[#202020]\",\n tertiary: \"text-primary hover:bg-[#f3f3f3] dark:hover:bg-[#202020]\",\n error: \"bg-[#d93036] hover:bg-[#ff6166]\",\n warning: \"bg-[#ff990a] text-primary-foreground hover:bg-[#d27504]\",\n },\n size: {\n default: \"h-9 px-4 py-2\",\n small: \"h-8 rounded-md px-3 text-xs\",\n large: \"h-10 rounded-md px-8\",\n icon: \"size-9\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n },\n);\n\nexport interface ButtonProps\n extends Omit<\n React.ButtonHTMLAttributes,\n \"prefix\" | \"suffix\"\n >,\n VariantProps {\n \n asChild?: boolean;\n \n prefix?: React.ReactNode;\n \n suffix?: React.ReactNode;\n \n disabled?: boolean;\n \n loading?: boolean;\n}\n\nexport const Button = React.forwardRef(\n (\n {\n className,\n variant = \"default\",\n size = \"default\",\n asChild = false,\n prefix,\n suffix,\n disabled = false,\n loading = false,\n ...props\n },\n ref,\n ) => {\n const { animation } = useRuru();\n\n const Comp = asChild ? Slot : \"button\";\n\n const buttonContent = (\n \n {loading ? : null}\n {prefix ? (\n \n {prefix}\n \n ) : null}\n {props.children}\n {suffix ? (\n \n {suffix}\n \n ) : null}\n \n );\n\n return (\n
\n {animation ? (\n {buttonContent}\n ) : (\n buttonContent\n )}\n
\n );\n },\n);\n\nButton.displayName = \"Button\";\n" } ], "type": "components:ui", diff --git a/apps/www/public/registry/components/checkbox.json b/apps/www/public/registry/components/checkbox.json index 12babbe..f13bbd6 100644 --- a/apps/www/public/registry/components/checkbox.json +++ b/apps/www/public/registry/components/checkbox.json @@ -4,7 +4,7 @@ "files": [ { "name": "checkbox.tsx", - "content": "import * as React from \"react\";\nimport * as CheckboxPrimitive from \"@radix-ui/react-checkbox\";\n\nimport { cn } from \"@/utils/cn\";\n\ntype CheckboxProps = React.ComponentPropsWithoutRef<\n typeof CheckboxPrimitive.Root\n> & {\n \n indeterminate?: boolean;\n};\n\nconst Checkbox = React.forwardRef<\n React.ElementRef,\n CheckboxProps\n>(({ className, indeterminate = false, ...props }, ref) => (\n \n {indeterminate ? (\n \n \n \n ) : (\n \n \n \n \n \n )}\n \n));\nCheckbox.displayName = CheckboxPrimitive.Root.displayName;\n\nexport { Checkbox };\n" + "content": "\"use client\";\n\nimport * as React from \"react\";\nimport * as CheckboxPrimitive from \"@radix-ui/react-checkbox\";\nimport { motion } from \"framer-motion\";\nimport { cn } from \"@/utils/cn\";\nimport { useRuru } from \"@/provider\";\n\ntype CheckboxProps = React.ComponentPropsWithoutRef<\n typeof CheckboxPrimitive.Root\n> & {\n indeterminate?: boolean;\n};\n\nconst Checkbox = React.forwardRef<\n React.ElementRef,\n CheckboxProps\n>(({ className, indeterminate = false, ...props }, ref) => {\n const { animation } = useRuru();\n\n return (\n \n {indeterminate ? (\n animation ? (\n \n \n \n ) : (\n \n \n \n )\n ) : (\n \n {animation ? (\n \n \n \n ) : (\n \n \n \n )}\n \n )}\n \n );\n});\nCheckbox.displayName = CheckboxPrimitive.Root.displayName;\n\nexport { Checkbox };\n" } ], "type": "components:ui" diff --git a/apps/www/public/registry/components/select.json b/apps/www/public/registry/components/select.json index f4d4c18..fd02b82 100644 --- a/apps/www/public/registry/components/select.json +++ b/apps/www/public/registry/components/select.json @@ -4,7 +4,7 @@ "files": [ { "name": "select.tsx", - "content": "\"use client\";\n\nimport * as React from \"react\";\nimport {\n CaretSortIcon,\n CheckIcon,\n ChevronDownIcon,\n ChevronUpIcon,\n} from \"@radix-ui/react-icons\";\nimport * as SelectPrimitive from \"@radix-ui/react-select\";\nimport { cn } from \"@/utils/cn\";\n\nconst Select = SelectPrimitive.Root;\nconst SelectGroup = SelectPrimitive.Group;\nconst SelectValue = SelectPrimitive.Value;\n\nconst SelectTrigger = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, children, ...props }, ref) => (\n span]:line-clamp-1\",\n className,\n )}\n {...props}\n >\n {children}\n \n \n \n \n));\nSelectTrigger.displayName = SelectPrimitive.Trigger.displayName;\n\nconst SelectScrollUpButton = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, ...props }, ref) => (\n \n \n \n));\nSelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;\n\nconst SelectScrollDownButton = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, ...props }, ref) => (\n \n \n \n));\nSelectScrollDownButton.displayName =\n SelectPrimitive.ScrollDownButton.displayName;\n\nconst SelectContent = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, children, position = \"popper\", ...props }, ref) => (\n \n \n \n \n {children}\n \n \n \n \n));\nSelectContent.displayName = SelectPrimitive.Content.displayName;\n\nconst SelectLabel = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, ...props }, ref) => (\n \n));\nSelectLabel.displayName = SelectPrimitive.Label.displayName;\n\nconst SelectItem = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, children, ...props }, ref) => (\n \n \n \n \n \n \n {children}\n \n));\nSelectItem.displayName = SelectPrimitive.Item.displayName;\n\nconst SelectSeparator = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, ...props }, ref) => (\n \n));\nSelectSeparator.displayName = SelectPrimitive.Separator.displayName;\n\nexport {\n Select,\n SelectGroup,\n SelectValue,\n SelectTrigger,\n SelectContent,\n SelectLabel,\n SelectItem,\n SelectSeparator,\n SelectScrollUpButton,\n SelectScrollDownButton,\n};\n" + "content": "\"use client\";\n\nimport * as React from \"react\";\nimport {\n CaretSortIcon,\n CheckIcon,\n ChevronDownIcon,\n ChevronUpIcon,\n} from \"@radix-ui/react-icons\";\nimport * as SelectPrimitive from \"@radix-ui/react-select\";\nimport { cn } from \"@/utils/cn\";\nimport { motion } from \"framer-motion\";\nimport { useRuru } from \"@/provider\";\n\nconst Select = SelectPrimitive.Root;\nconst SelectGroup = SelectPrimitive.Group;\nconst SelectValue = SelectPrimitive.Value;\n\nconst SelectTrigger = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, children, ...props }, ref) => {\n const { animation } = useRuru();\n return animation ? (\n \n span]:line-clamp-1\",\n className,\n )}\n {...props}\n >\n {children}\n \n \n \n \n \n ) : (\n span]:line-clamp-1\",\n className,\n )}\n {...props}\n >\n {children}\n \n \n \n \n );\n});\nSelectTrigger.displayName = SelectPrimitive.Trigger.displayName;\n\nconst SelectScrollUpButton = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, ...props }, ref) => (\n \n \n \n));\nSelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;\n\nconst SelectScrollDownButton = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, ...props }, ref) => (\n \n \n \n));\nSelectScrollDownButton.displayName =\n SelectPrimitive.ScrollDownButton.displayName;\n\n\nconst AnimatedSelectContent = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, children, position = \"popper\", ...props }, ref) => (\n \n \n \n \n \n {children}\n \n \n \n \n \n));\nAnimatedSelectContent.displayName = SelectPrimitive.Content.displayName;\n\n\nconst StaticSelectContent = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, children, position = \"popper\", ...props }, ref) => (\n \n \n \n \n {children}\n \n \n \n \n));\nStaticSelectContent.displayName = SelectPrimitive.Content.displayName;\n\nconst SelectContent = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>((props, ref) => {\n const { animation } = useRuru();\n return animation ? (\n \n ) : (\n \n );\n});\n\nSelectContent.displayName = \"SelectContent\";\n\nconst SelectLabel = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, ...props }, ref) => (\n \n));\nSelectLabel.displayName = SelectPrimitive.Label.displayName;\n\nconst SelectItem = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, children, ...props }, ref) => (\n \n \n \n \n \n \n {children}\n \n));\nSelectItem.displayName = SelectPrimitive.Item.displayName;\n\nconst SelectSeparator = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, ...props }, ref) => (\n \n));\nSelectSeparator.displayName = SelectPrimitive.Separator.displayName;\n\nexport {\n Select,\n SelectGroup,\n SelectValue,\n SelectTrigger,\n SelectContent,\n SelectLabel,\n SelectItem,\n SelectSeparator,\n SelectScrollUpButton,\n SelectScrollDownButton,\n};\n" } ], "type": "components:ui" diff --git a/apps/www/public/registry/components/switch.json b/apps/www/public/registry/components/switch.json index 2f278e9..24c2838 100644 --- a/apps/www/public/registry/components/switch.json +++ b/apps/www/public/registry/components/switch.json @@ -4,7 +4,7 @@ "files": [ { "name": "switch.tsx", - "content": "\"use client\";\n\nimport * as React from \"react\";\nimport * as SwitchPrimitives from \"@radix-ui/react-switch\";\n\nimport { cn } from \"@/utils/cn\";\n\nconst Switch = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, ...props }, ref) => (\n \n \n \n));\nSwitch.displayName = SwitchPrimitives.Root.displayName;\n\nexport { Switch };\n" + "content": "\n\nimport * as React from \"react\";\nimport * as SwitchPrimitives from \"@radix-ui/react-switch\";\n\nimport { cn } from \"@/utils/cn\";\n\nconst Switch = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, ...props }, ref) => (\n \n \n \n));\nSwitch.displayName = SwitchPrimitives.Root.displayName;\n\nexport { Switch };\n" } ], "type": "components:ui" diff --git a/apps/www/public/registry/components/tabs.json b/apps/www/public/registry/components/tabs.json index f5a5617..c6c8c8b 100644 --- a/apps/www/public/registry/components/tabs.json +++ b/apps/www/public/registry/components/tabs.json @@ -4,7 +4,7 @@ "files": [ { "name": "tabs.tsx", - "content": "\"use client\";\n\nimport type {\n TabsContentProps,\n TabsProps as BaseProps,\n} from \"@radix-ui/react-tabs\";\nimport * as TabsPrimitive from \"@radix-ui/react-tabs\";\nimport React, { useMemo, useState, useCallback, useLayoutEffect } from \"react\";\nimport { cn } from \"@/utils/cn\";\n\nconst TabsPrimitiveRoot = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>((props, ref) => {\n return (\n \n );\n});\n\nTabsPrimitiveRoot.displayName = \"TabsPrimitiveRoot\";\n\nconst TabsList = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>((props, ref) => (\n \n));\nTabsList.displayName = \"TabsList\";\n\nconst TabsTrigger = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>((props, ref) => (\n \n));\nTabsTrigger.displayName = \"TabsTrigger\";\n\nconst TabsContent = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>((props, ref) => (\n \n));\nTabsContent.displayName = \"TabsContent\";\n\ntype ChangeListener = (v: string) => void;\nconst listeners = new Map();\n\nfunction addChangeListener(id: string, listener: ChangeListener): void {\n const list = listeners.get(id) ?? [];\n list.push(listener);\n listeners.set(id, list);\n}\n\nfunction removeChangeListener(id: string, listener: ChangeListener): void {\n const list = listeners.get(id) ?? [];\n listeners.set(\n id,\n list.filter((item) => item !== listener),\n );\n}\n\nfunction update(id: string, v: string, persist: boolean): void {\n listeners.get(id)?.forEach((item) => {\n item(v);\n });\n\n if (persist) localStorage.setItem(id, v);\n else sessionStorage.setItem(id, v);\n}\n\nexport interface TabsProps extends BaseProps {\n \n groupId?: string;\n \n persist?: boolean;\n \n defaultIndex?: number;\n \n disabled?: boolean;\n \n items?: string[];\n}\n\nexport function Tabs({\n groupId,\n items = [],\n persist = false,\n defaultIndex = 0,\n disabled = false,\n ...props\n}: TabsProps): React.ReactElement {\n const values = useMemo(() => items.map((item) => toValue(item)), [items]);\n const [value, setValue] = useState(values[defaultIndex]);\n\n useLayoutEffect(() => {\n if (!groupId) return;\n\n const onUpdate: ChangeListener = (v) => {\n if (values.includes(v)) setValue(v);\n };\n\n const previous = persist\n ? localStorage.getItem(groupId)\n : sessionStorage.getItem(groupId);\n\n if (previous) onUpdate(previous);\n addChangeListener(groupId, onUpdate);\n return () => {\n removeChangeListener(groupId, onUpdate);\n };\n }, [groupId, persist, values]);\n\n const onValueChange = useCallback(\n (v: string) => {\n if (groupId) {\n update(groupId, v, persist);\n } else {\n setValue(v);\n }\n },\n [groupId, persist],\n );\n\n return (\n \n \n {values.map((v, i) => (\n \n {items[i]}\n \n ))}\n \n {props.children}\n \n );\n}\n\nfunction toValue(v: string): string {\n return v.toLowerCase().replace(/\\s/, \"-\");\n}\n\nexport function Tab({\n value,\n className,\n ...props\n}: TabsContentProps): React.ReactElement {\n return (\n figure:only-child]:-m-4 [&>figure:only-child]:rounded-none [&>figure:only-child]:border-none\",\n className,\n )}\n {...props}\n />\n );\n}\n\nexport { TabsList, TabsTrigger, TabsContent };\n" + "content": "\"use client\";\n\nimport type {\n TabsContentProps,\n TabsProps as BaseProps,\n} from \"@radix-ui/react-tabs\";\nimport * as TabsPrimitive from \"@radix-ui/react-tabs\";\nimport React, {\n useMemo,\n useState,\n useCallback,\n useLayoutEffect,\n useRef,\n} from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { motion } from \"framer-motion\";\nimport { useRuru } from \"@/provider\";\n\nconst TabsPrimitiveRoot = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>((props, ref) => {\n return (\n \n );\n});\n\nTabsPrimitiveRoot.displayName = \"TabsPrimitiveRoot\";\n\nconst AnimatedTabsList = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ children, ...props }, ref) => {\n \n const [activeIndex, setActiveIndex] = useState(0);\n const [indicatorProps, setIndicatorProps] = useState({\n width: 0,\n left: 0,\n });\n\n const listRef = useRef(null);\n\n useLayoutEffect(() => {\n if (!listRef.current) return;\n\n const activeTab = listRef.current.querySelector(\n '[data-state=\"active\"]',\n ) as HTMLButtonElement | null;\n\n if (activeTab) {\n setIndicatorProps({\n width: activeTab.offsetWidth,\n left: activeTab.offsetLeft,\n });\n }\n }, [activeIndex, children]);\n\n return (\n {\n listRef.current = node;\n if (typeof ref === \"function\") ref(node);\n else if (ref) ref.current = node;\n }}\n {...props}\n className={cn(\n \"relative flex flex-row items-end gap-4 overflow-x-auto px-4 border-b\",\n props.className,\n )}\n >\n {children}\n \n \n );\n});\nAnimatedTabsList.displayName = \"AnimatedTabsList\";\n\nconst TabsList = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>((props, ref) => (\n \n));\nTabsList.displayName = \"TabsList\";\n\nconst TabsTrigger = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>((props, ref) => (\n \n));\nTabsTrigger.displayName = \"TabsTrigger\";\n\nconst TabsContent = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>((props, ref) => (\n \n));\nTabsContent.displayName = \"TabsContent\";\n\ntype ChangeListener = (v: string) => void;\nconst listeners = new Map();\n\nfunction addChangeListener(id: string, listener: ChangeListener): void {\n const list = listeners.get(id) ?? [];\n list.push(listener);\n listeners.set(id, list);\n}\n\nfunction removeChangeListener(id: string, listener: ChangeListener): void {\n const list = listeners.get(id) ?? [];\n listeners.set(\n id,\n list.filter((item) => item !== listener),\n );\n}\n\nfunction update(id: string, v: string, persist: boolean): void {\n listeners.get(id)?.forEach((item) => {\n item(v);\n });\n\n if (persist) localStorage.setItem(id, v);\n else sessionStorage.setItem(id, v);\n}\n\nexport interface TabsProps extends BaseProps {\n \n groupId?: string;\n \n persist?: boolean;\n \n defaultIndex?: number;\n \n disabled?: boolean;\n \n items?: string[];\n}\n\nexport function Tabs({\n groupId,\n items = [],\n persist = false,\n defaultIndex = 0,\n disabled = false,\n ...props\n}: TabsProps): React.ReactElement {\n const { animation } = useRuru();\n const values = useMemo(() => items.map((item) => toValue(item)), [items]);\n const [value, setValue] = useState(values[defaultIndex]);\n\n useLayoutEffect(() => {\n if (!groupId) return;\n\n const onUpdate: ChangeListener = (v) => {\n if (values.includes(v)) setValue(v);\n };\n\n const previous = persist\n ? localStorage.getItem(groupId)\n : sessionStorage.getItem(groupId);\n\n if (previous) onUpdate(previous);\n addChangeListener(groupId, onUpdate);\n return () => {\n removeChangeListener(groupId, onUpdate);\n };\n }, [groupId, persist, values]);\n\n const onValueChange = useCallback(\n (v: string) => {\n if (groupId) {\n update(groupId, v, persist);\n } else {\n setValue(v);\n }\n },\n [groupId, persist],\n );\n\n return (\n \n {animation ? (\n \n {values.map((v, i) => (\n \n {items[i]}\n \n ))}\n \n ) : (\n \n {values.map((v, i) => (\n \n {items[i]}\n \n ))}\n \n )}\n {props.children}\n \n );\n}\n\nfunction toValue(v: string): string {\n return v.toLowerCase().replace(/\\s/, \"-\");\n}\n\nexport function Tab({\n value,\n className,\n ...props\n}: TabsContentProps): React.ReactElement {\n return (\n figure:only-child]:-m-4 [&>figure:only-child]:rounded-none [&>figure:only-child]:border-none\",\n className,\n )}\n {...props}\n />\n );\n}\n\nexport { TabsList, TabsTrigger, TabsContent };\n" } ], "type": "components:ui" diff --git a/packages/cli/changelog.mdx b/packages/cli/changelog.mdx new file mode 100644 index 0000000..46aaddf --- /dev/null +++ b/packages/cli/changelog.mdx @@ -0,0 +1,20 @@ +--- +title: Changelog +description: Latest updates and announcements about the project. +--- + +# ruru-ui-cli@0.0.2 + +### What's Changed +- fix(docs): make docs mobile responsive by [@ruru-m07](https://github.com/ruru-m07) in [#25](https://github.com/ruru-m07/ruru-ui/pull/25) +- feat(ui): implement registry system in www client by [@ruru-m07](https://github.com/ruru-m07) in [#26](https://github.com/ruru-m07/ruru-ui/pull/26) +- refactor(components): refactor components and fix bugs by [@ruru-m07](https://github.com/ruru-m07) in [#27](https://github.com/ruru-m07/ruru-ui/pull/27) + + +**Full Changelog**: [ruru-ui-cli@0.0.2](https://github.com/ruru-m07/ruru-ui/compare/ruru-ui@1.0.3...ruru-ui-cli@0.0.2) + +--- + +### Thank you + +I would like to express my gratitude to all the users of this project for their continuous support, valuable feedback, and contributions. Your involvement has been instrumental in making this project a success. Thank you all for your unwavering support and encouragement. 🙏 diff --git a/.changeset/changelog.mdx b/packages/ui/changelog.mdx similarity index 99% rename from .changeset/changelog.mdx rename to packages/ui/changelog.mdx index 8d5a7ee..97bcc04 100644 --- a/.changeset/changelog.mdx +++ b/packages/ui/changelog.mdx @@ -9,10 +9,6 @@ description: Latest updates and announcements about the project. - refactor(components): refactor components and fix bugs by [@ruru-m07](https://github.com/ruru-m07) in [#27](https://github.com/ruru-m07/ruru-ui/pull/27) -#### CLI relese - -- `ruru-ui-cli@0.0.2` - **Full Changelog**: [ruru-ui@2.0.1](https://github.com/ruru-m07/ruru-ui/compare/ruru-ui@2.0.0...ruru-ui@2.0.1) --- diff --git a/packages/ui/package.json b/packages/ui/package.json index 9ff0391..b3dc9e7 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -97,6 +97,7 @@ "@tailwindcss/typography": "^0.5.13", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", + "framer-motion": "^11.3.28", "next-themes": "^0.3.0", "react": "^18.2.0", "tailwind-merge": "^2.4.0", diff --git a/packages/ui/src/components/button.tsx b/packages/ui/src/components/button.tsx index 396a496..b5a09f3 100644 --- a/packages/ui/src/components/button.tsx +++ b/packages/ui/src/components/button.tsx @@ -5,6 +5,8 @@ import { cva, type VariantProps } from "class-variance-authority"; import React from "react"; import { cn } from "@/utils/cn"; import { Spinner } from "./spinner"; +import { motion } from "framer-motion"; +import { useRuru } from "@/provider"; export const buttonVariants = cva( "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50", @@ -130,32 +132,45 @@ export const Button = React.forwardRef( }, ref, ) => { + const { animation } = useRuru(); + const Comp = asChild ? Slot : "button"; + const buttonContent = ( + + {loading ? : null} + {prefix ? ( + + {prefix} + + ) : null} + {props.children} + {suffix ? ( + + {suffix} + + ) : null} + + ); + return (
- - {loading ? : null} - {prefix ? ( - - {prefix} - - ) : null} - {props.children} - {suffix ? ( - - {suffix} - - ) : null} - + {animation ? ( + {buttonContent} + ) : ( + buttonContent + )}
); }, diff --git a/packages/ui/src/components/checkbox.tsx b/packages/ui/src/components/checkbox.tsx index 9882c8d..65f81b1 100644 --- a/packages/ui/src/components/checkbox.tsx +++ b/packages/ui/src/components/checkbox.tsx @@ -1,78 +1,117 @@ +"use client"; + import * as React from "react"; import * as CheckboxPrimitive from "@radix-ui/react-checkbox"; - +import { motion } from "framer-motion"; import { cn } from "@/utils/cn"; -/** - * Type definition for Checkbox props, extending the properties of CheckboxPrimitive.Root - * and including an optional indeterminate property. - */ +import { useRuru } from "@/provider"; + type CheckboxProps = React.ComponentPropsWithoutRef< typeof CheckboxPrimitive.Root > & { - /** - * Indicates whether the checkbox is in an indeterminate state. - * @default false - */ indeterminate?: boolean; }; -/** - * Checkbox component wrapping around Radix UI's CheckboxPrimitive.Root. - * Provides additional functionality and styling for handling indeterminate state checkboxes. - */ + const Checkbox = React.forwardRef< React.ElementRef, CheckboxProps ->(({ className, indeterminate = false, ...props }, ref) => ( - - {indeterminate ? ( - - - - ) : ( - - (({ className, indeterminate = false, ...props }, ref) => { + const { animation } = useRuru(); + + return ( + + {indeterminate ? ( + animation ? ( + + + + ) : ( + + + + ) + ) : ( + - - - - )} - -)); + {animation ? ( + + + + ) : ( + + + + )} + + )} + + ); +}); Checkbox.displayName = CheckboxPrimitive.Root.displayName; export { Checkbox }; diff --git a/packages/ui/src/components/select.tsx b/packages/ui/src/components/select.tsx index 3fd6195..bb9c99f 100644 --- a/packages/ui/src/components/select.tsx +++ b/packages/ui/src/components/select.tsx @@ -9,6 +9,8 @@ import { } from "@radix-ui/react-icons"; import * as SelectPrimitive from "@radix-ui/react-select"; import { cn } from "@/utils/cn"; +import { motion } from "framer-motion"; +import { useRuru } from "@/provider"; const Select = SelectPrimitive.Root; const SelectGroup = SelectPrimitive.Group; @@ -17,21 +19,40 @@ const SelectValue = SelectPrimitive.Value; const SelectTrigger = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - span]:line-clamp-1", - className, - )} - {...props} - > - {children} - - - - -)); +>(({ className, children, ...props }, ref) => { + const { animation } = useRuru(); + return animation ? ( + + span]:line-clamp-1", + className, + )} + {...props} + > + {children} + + + + + + ) : ( + span]:line-clamp-1", + className, + )} + {...props} + > + {children} + + + + + ); +}); SelectTrigger.displayName = SelectPrimitive.Trigger.displayName; const SelectScrollUpButton = React.forwardRef< @@ -69,7 +90,53 @@ const SelectScrollDownButton = React.forwardRef< SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName; -const SelectContent = React.forwardRef< +// Animated SelectContent component +const AnimatedSelectContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, position = "popper", ...props }, ref) => ( + + + + + + {children} + + + + + +)); +AnimatedSelectContent.displayName = SelectPrimitive.Content.displayName; + +// Non-animated SelectContent component +const StaticSelectContent = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, children, position = "popper", ...props }, ref) => ( @@ -99,7 +166,21 @@ const SelectContent = React.forwardRef< )); -SelectContent.displayName = SelectPrimitive.Content.displayName; +StaticSelectContent.displayName = SelectPrimitive.Content.displayName; + +const SelectContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>((props, ref) => { + const { animation } = useRuru(); + return animation ? ( + + ) : ( + + ); +}); + +SelectContent.displayName = "SelectContent"; const SelectLabel = React.forwardRef< React.ElementRef, diff --git a/packages/ui/src/components/switch.tsx b/packages/ui/src/components/switch.tsx index f5be5c4..51a603d 100644 --- a/packages/ui/src/components/switch.tsx +++ b/packages/ui/src/components/switch.tsx @@ -1,4 +1,4 @@ -"use client"; +// "use client"; import * as React from "react"; import * as SwitchPrimitives from "@radix-ui/react-switch"; diff --git a/packages/ui/src/components/tabs.tsx b/packages/ui/src/components/tabs.tsx index e49a425..89f7235 100644 --- a/packages/ui/src/components/tabs.tsx +++ b/packages/ui/src/components/tabs.tsx @@ -5,8 +5,16 @@ import type { TabsProps as BaseProps, } from "@radix-ui/react-tabs"; import * as TabsPrimitive from "@radix-ui/react-tabs"; -import React, { useMemo, useState, useCallback, useLayoutEffect } from "react"; +import React, { + useMemo, + useState, + useCallback, + useLayoutEffect, + useRef, +} from "react"; import { cn } from "@/utils/cn"; +import { motion } from "framer-motion"; +import { useRuru } from "@/provider"; const TabsPrimitiveRoot = React.forwardRef< React.ElementRef, @@ -23,6 +31,58 @@ const TabsPrimitiveRoot = React.forwardRef< TabsPrimitiveRoot.displayName = "TabsPrimitiveRoot"; +const AnimatedTabsList = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ children, ...props }, ref) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const [activeIndex, setActiveIndex] = useState(0); + const [indicatorProps, setIndicatorProps] = useState({ + width: 0, + left: 0, + }); + + const listRef = useRef(null); + + useLayoutEffect(() => { + if (!listRef.current) return; + + const activeTab = listRef.current.querySelector( + '[data-state="active"]', + ) as HTMLButtonElement | null; + + if (activeTab) { + setIndicatorProps({ + width: activeTab.offsetWidth, + left: activeTab.offsetLeft, + }); + } + }, [activeIndex, children]); + + return ( + { + listRef.current = node; + if (typeof ref === "function") ref(node); + else if (ref) ref.current = node; + }} + {...props} + className={cn( + "relative flex flex-row items-end gap-4 overflow-x-auto px-4 border-b", + props.className, + )} + > + {children} + + + ); +}); +AnimatedTabsList.displayName = "AnimatedTabsList"; + const TabsList = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef @@ -46,7 +106,7 @@ const TabsTrigger = React.forwardRef< ref={ref} {...props} className={cn( - "whitespace-nowrap border-b border-transparent py-2 text-sm font-medium transition-colors hover:text-primary disabled:pointer-events-none disabled:opacity-50 data-[state=active]:border-primary data-[state=active]:text-primary text-muted-foreground mx-1", + "whitespace-nowrap border-b border-transparent py-2 text-sm font-medium transition-colors hover:text-primary disabled:pointer-events-none disabled:opacity-50 data-[state=active]:text-primary text-muted-foreground mx-1 data-[state=active]:border-primary", props.className, )} /> @@ -125,6 +185,7 @@ export function Tabs({ disabled = false, ...props }: TabsProps): React.ReactElement { + const { animation } = useRuru(); const values = useMemo(() => items.map((item) => toValue(item)), [items]); const [value, setValue] = useState(values[defaultIndex]); @@ -164,13 +225,28 @@ export function Tabs({ {...props} className={cn("my-4", props.className)} > - - {values.map((v, i) => ( - - {items[i]} - - ))} - + {animation ? ( + + {values.map((v, i) => ( + + {items[i]} + + ))} + + ) : ( + + {values.map((v, i) => ( + + {items[i]} + + ))} + + )} {props.children} ); diff --git a/packages/ui/src/interface/RuruContextType.ts b/packages/ui/src/interface/RuruContextType.ts index a3c79a0..276d7e2 100644 --- a/packages/ui/src/interface/RuruContextType.ts +++ b/packages/ui/src/interface/RuruContextType.ts @@ -2,16 +2,13 @@ * Context type for managing color state in the Ruru context. * * @interface RuruContextType - * @property {string} color - The current color value. - * @property {(color: string) => void} setColor - Function to update the color value. + * @property {boolean} disableAnimation - The current color. + * @property {boolean} Animation - The current color. + * @property {(Animation: boolean) => void} setAnimation - Function to set the color. * - * @example - * ```typescript - * const { color, setColor } = useRuru(); - * setColor("red"); - * ``` */ export interface RuruContextType { - color: string; - setColor: (color: string) => void; + disableAnimation: boolean; + animation: boolean; + setAnimation: (Animation: boolean) => void; } diff --git a/packages/ui/src/interface/RuruProviderProps.ts b/packages/ui/src/interface/RuruProviderProps.ts index 7c8da90..caf68a4 100644 --- a/packages/ui/src/interface/RuruProviderProps.ts +++ b/packages/ui/src/interface/RuruProviderProps.ts @@ -17,4 +17,5 @@ import { type ReactNode } from "react"; export interface RuruProviderProps { children: ReactNode; togleThemeAnimation?: boolean; + disableAnimation?: boolean; } diff --git a/packages/ui/src/provider/index.tsx b/packages/ui/src/provider/index.tsx index c9efcce..98ea0ca 100644 --- a/packages/ui/src/provider/index.tsx +++ b/packages/ui/src/provider/index.tsx @@ -11,13 +11,14 @@ const RuruContext = createContext(undefined); export const RuruProvider: React.FC = ({ children, togleThemeAnimation = false, + disableAnimation = false, }) => { - const [color, setColor] = useState("blue"); // Default color value + const [animation, setAnimation] = useState(!disableAnimation); return ( - + -
{children}
+ {children}
); diff --git a/packages/ui/src/provider/theme.tsx b/packages/ui/src/provider/theme.tsx index 1d44920..9915348 100644 --- a/packages/ui/src/provider/theme.tsx +++ b/packages/ui/src/provider/theme.tsx @@ -7,16 +7,18 @@ import { type RuruThemeProviderProps } from "@/interface/RuruThemeProviderProps" /** * A wrapper component to provide theme context using `next-themes`. * - * @param {React.ReactNode} children - The child elements to render within the theme provider. - * @param {string} [attribute="class"] - The attribute to use for the theme. - * @param {string} [defaultTheme="system"] - The default theme to apply. - * @param {boolean} [enableSystem=true] - Whether to enable the system theme detection. - * @param {boolean} [disableTransitionOnChange=true] - Whether to disable transitions when changing themes. - * + * @param {RuruThemeProviderProps} props - The component properties. + * @returns {React.ReactElement} - The theme provider component. * @example + * * ```tsx - * - * + * + * * * ``` */ @@ -34,7 +36,7 @@ export const RuruThemeProvider: React.FC = ({ enableSystem={enableSystem} disableTransitionOnChange={disableTransitionOnChange} > - {children} +
{children}
); }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cafd083..085051f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -127,6 +127,9 @@ importers: '@radix-ui/react-icons': specifier: ^1.3.0 version: 1.3.0(react@18.3.1) + '@radix-ui/react-scroll-area': + specifier: ^1.1.0 + version: 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) fs: specifier: 0.0.1-security version: 0.0.1-security @@ -345,6 +348,9 @@ importers: clsx: specifier: ^2.1.1 version: 2.1.1 + framer-motion: + specifier: ^11.3.28 + version: 11.3.28(react-dom@18.3.1)(react@18.3.1) next-themes: specifier: ^0.3.0 version: 0.3.0(react-dom@18.3.1)(react@18.3.1) @@ -5617,6 +5623,25 @@ packages: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} dev: true + /framer-motion@11.3.28(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-dqhoawipEAjqdv32zbv72sOMJZjol7dROWn7t/FOq23WXJ40O4OUybgnO2ldnuS+3YquSn8xO/KKRavZ+TBVOQ==} + peerDependencies: + '@emotion/is-prop-valid': '*' + react: ^18.0.0 + react-dom: ^18.0.0 + peerDependenciesMeta: + '@emotion/is-prop-valid': + optional: true + react: + optional: true + react-dom: + optional: true + dependencies: + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + tslib: 2.6.2 + dev: false + /fs-extra@10.1.0: resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} engines: {node: '>=12'}