mirror of
https://github.com/nextui-org/nextui.git
synced 2025-12-08 19:26:11 +00:00
refactor: optimisations (#3523)
* refactor: replace lodash with native approaches
* refactor(deps): update framer-motion versions
* feat(utilities): add @nextui-org/dom-animation
* refactor(components): load domAnimation dynamically
* refactor(deps): add @nextui-org/dom-animation
* fix(utilities): relocate index.ts
* feat(changeset): framer motion optimization
* chore(deps): bump framer-motion version
* fix(docs): conflict issue
* refactor(hooks): remove the unnecessary this aliasing
* refactor(utilities): remove the unnecessary this aliasing
* chore(docs): remove {} so that it won't be true all the time
* chore(dom-animation): end with new line
* refactor(hooks): use debounce from `@nextui-org/shared-utils`
* chore(deps): add `@nextui-org/shared-utils`
* refactor: move mapKeys logic to `@nextui-org/shared-utils`
* refactor: use `get` from `@nextui-org/shared-utils`
* refactor(docs): use `get` from `@nextui-org/shared-utils`
* refactor(shared-utils): mapKeys
* chore(deps): bump framer-motion version
* chore(deps): remove lodash
* refactor(docs): use intersectionBy from shared-utils
* feat(shared-utils): add intersectionBy
* chore(dom-animation): remove extra blank line
* refactor(shared-utils): revise intersectionBy
* fix(modal): add willChange
* refactor(shared-utils): add comments
* fix: build & tests
---------
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
This commit is contained in:
parent
58a77cb6b9
commit
3f0d81b560
8
.changeset/mean-mangos-occur.md
Normal file
8
.changeset/mean-mangos-occur.md
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
"@nextui-org/calendar": patch
|
||||
"@nextui-org/theme": patch
|
||||
"@nextui-org/use-infinite-scroll": patch
|
||||
"@nextui-org/shared-utils": patch
|
||||
---
|
||||
|
||||
replaced lodash with native approaches
|
||||
15
.changeset/swift-news-complain.md
Normal file
15
.changeset/swift-news-complain.md
Normal file
@ -0,0 +1,15 @@
|
||||
---
|
||||
"@nextui-org/accordion": patch
|
||||
"@nextui-org/calendar": patch
|
||||
"@nextui-org/modal": patch
|
||||
"@nextui-org/navbar": patch
|
||||
"@nextui-org/popover": patch
|
||||
"@nextui-org/ripple": patch
|
||||
"@nextui-org/tooltip": patch
|
||||
"@nextui-org/theme": patch
|
||||
"@nextui-org/use-infinite-scroll": patch
|
||||
"@nextui-org/dom-animation": patch
|
||||
"@nextui-org/shared-utils": patch
|
||||
---
|
||||
|
||||
framer motion optimization (#3340)
|
||||
20
.changeset/thirty-cheetahs-guess.md
Normal file
20
.changeset/thirty-cheetahs-guess.md
Normal file
@ -0,0 +1,20 @@
|
||||
---
|
||||
"@nextui-org/accordion": patch
|
||||
"@nextui-org/autocomplete": patch
|
||||
"@nextui-org/button": patch
|
||||
"@nextui-org/calendar": patch
|
||||
"@nextui-org/card": patch
|
||||
"@nextui-org/dropdown": patch
|
||||
"@nextui-org/modal": patch
|
||||
"@nextui-org/navbar": patch
|
||||
"@nextui-org/popover": patch
|
||||
"@nextui-org/ripple": patch
|
||||
"@nextui-org/select": patch
|
||||
"@nextui-org/snippet": patch
|
||||
"@nextui-org/tabs": patch
|
||||
"@nextui-org/tooltip": patch
|
||||
"@nextui-org/system": patch
|
||||
"@nextui-org/framer-utils": patch
|
||||
---
|
||||
|
||||
update `framer-motion` versions
|
||||
@ -23,7 +23,7 @@ import {
|
||||
} from "@nextui-org/react";
|
||||
import {ChevronDownIcon, SearchIcon} from "@nextui-org/shared-icons";
|
||||
import {useCallback, useMemo, useState} from "react";
|
||||
import {capitalize} from "lodash";
|
||||
import {capitalize} from "@nextui-org/shared-utils";
|
||||
|
||||
import {PlusLinearIcon} from "@/components/icons";
|
||||
import {VerticalDotsIcon} from "@/components/icons/vertical-dots";
|
||||
|
||||
@ -23,7 +23,7 @@ import {
|
||||
} from "@nextui-org/react";
|
||||
import {ChevronDownIcon, SearchIcon} from "@nextui-org/shared-icons";
|
||||
import {useCallback, useMemo, useState} from "react";
|
||||
import {capitalize} from "lodash";
|
||||
import {capitalize} from "@nextui-org/shared-utils";
|
||||
|
||||
import {PlusLinearIcon} from "@/components/icons";
|
||||
import {VerticalDotsIcon} from "@/components/icons/vertical-dots";
|
||||
|
||||
@ -13,7 +13,7 @@ import {clsx} from "@nextui-org/shared-utils";
|
||||
import scrollIntoView from "scroll-into-view-if-needed";
|
||||
import {isAppleDevice, isWebKit} from "@react-aria/utils";
|
||||
import {create} from "zustand";
|
||||
import {intersectionBy, isEmpty} from "lodash";
|
||||
import {isEmpty, intersectionBy} from "@nextui-org/shared-utils";
|
||||
import {writeStorage, useLocalStorage} from "@rehooks/local-storage";
|
||||
|
||||
import {
|
||||
|
||||
@ -12,7 +12,6 @@ import {
|
||||
Skeleton,
|
||||
} from "@nextui-org/react";
|
||||
import Link from "next/link";
|
||||
import {toLower} from "lodash";
|
||||
|
||||
import {CodeWindow} from "@/components/code-window";
|
||||
import {useIsMobile} from "@/hooks/use-media-query";
|
||||
@ -30,8 +29,8 @@ export const DemoCodeModal: FC<DemoCodeModalProps> = ({isOpen, code, title, subt
|
||||
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const lowerTitle = toLower(title);
|
||||
const fileName = `${toLower(lowerTitle)}.tsx`;
|
||||
const lowerTitle = title.toLowerCase();
|
||||
const fileName = `${lowerTitle}.tsx`;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
|
||||
@ -1,17 +1,19 @@
|
||||
import {get} from "lodash";
|
||||
|
||||
import {FileCode} from "./types";
|
||||
|
||||
const importRegex = /^(import)\s(?!type(of\s|\s)(?!from)).*?$/gm;
|
||||
|
||||
const exportDefaultRegex = /export\s+default\s+function\s+\w+\s*\(\s*\)\s*\{/;
|
||||
|
||||
export const transformCode = (code: string, imports = {}, compName = "App") => {
|
||||
export const transformCode = (
|
||||
code: string,
|
||||
imports: {[key: string]: any} = {},
|
||||
compName = "App",
|
||||
) => {
|
||||
let cleanedCode = code
|
||||
.replace(importRegex, (match) => {
|
||||
// get component name from the match ex. "import { Table } from '@nextui-org/react'"
|
||||
const componentName = match.match(/\w+/g)?.[1] || "";
|
||||
const matchingImport = get(imports, componentName);
|
||||
const matchingImport = imports[componentName];
|
||||
|
||||
if (matchingImport) {
|
||||
// remove the matching import
|
||||
|
||||
@ -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, omit} from "lodash";
|
||||
import {debounce, omit} from "@nextui-org/shared-utils";
|
||||
|
||||
import defaultTheme from "@/libs/prism-theme";
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@ import {commonColors, semanticColors} from "@nextui-org/theme";
|
||||
import {useClipboard} from "@nextui-org/use-clipboard";
|
||||
import {useState} from "react";
|
||||
import {useTheme} from "next-themes";
|
||||
import {get, isEmpty} from "lodash";
|
||||
import {get, isEmpty} from "@nextui-org/shared-utils";
|
||||
|
||||
type ColorsItem = {
|
||||
color: string;
|
||||
@ -106,7 +106,7 @@ const SemanticSwatch = ({
|
||||
let value: string = "";
|
||||
const [colorName, colorScale] = color.split("-");
|
||||
|
||||
let currentPalette = get(semanticColors, theme ?? "", {});
|
||||
const currentPalette = get(semanticColors, theme ?? "", {});
|
||||
|
||||
if (!colorScale) {
|
||||
value = get(currentPalette, `${colorName}.DEFAULT`, "");
|
||||
|
||||
@ -18,7 +18,7 @@ import {
|
||||
dataFocusVisibleClasses,
|
||||
} from "@nextui-org/react";
|
||||
import Link from "next/link";
|
||||
import {isEmpty} from "lodash";
|
||||
import {isEmpty} from "@nextui-org/shared-utils";
|
||||
import {usePathname, useRouter} from "next/navigation";
|
||||
|
||||
import {ScrollArea} from "../scroll-area";
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
/* eslint-disable react/display-name */
|
||||
import {useMemo, useState} from "react";
|
||||
import {Tabs, Tab, Card, CardBody, Image, Button, RadioGroup, Radio} from "@nextui-org/react";
|
||||
import get from "lodash/get";
|
||||
import NextLink from "next/link";
|
||||
import NextImage from "next/image";
|
||||
|
||||
@ -238,7 +237,7 @@ export const CustomThemes = () => {
|
||||
<CodeWindow
|
||||
showWindowIcons
|
||||
className="max-h-[440px] min-h-[390px]"
|
||||
highlightLines={get(codeHighlights, selectedTheme)}
|
||||
highlightLines={codeHighlights[selectedTheme]}
|
||||
isScrollable={false}
|
||||
language="jsx"
|
||||
title="tailwind.config.js"
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
import {FC, useMemo, useRef} from "react";
|
||||
import {Avatar, AvatarProps, Button, Spacer, Tooltip} from "@nextui-org/react";
|
||||
import {clamp, get} from "lodash";
|
||||
import {clamp} from "@nextui-org/shared-utils";
|
||||
|
||||
import {sectionWrapper, titleWrapper, title, subtitle} from "../primitives";
|
||||
|
||||
@ -132,9 +132,7 @@ export const Support: FC<SupportProps> = ({sponsors = []}) => {
|
||||
size={getSponsorSize(sponsor, isMobile)}
|
||||
src={sponsor.image}
|
||||
style={getSponsorAvatarStyles(index, sponsors)}
|
||||
onClick={() =>
|
||||
handleExternalLinkClick(get(sponsor, "website") || get(sponsor, "profile"))
|
||||
}
|
||||
onClick={() => handleExternalLinkClick(sponsor["website"] || sponsor["profile"])}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@ -24,7 +24,6 @@ import {isAppleDevice} from "@react-aria/utils";
|
||||
import {clsx} from "@nextui-org/shared-utils";
|
||||
import NextLink from "next/link";
|
||||
import {usePathname} from "next/navigation";
|
||||
import {includes} from "lodash";
|
||||
import {motion, AnimatePresence} from "framer-motion";
|
||||
import {useEffect} from "react";
|
||||
import {usePress} from "@react-aria/interactions";
|
||||
@ -197,7 +196,7 @@ export const Navbar: FC<NavbarProps> = ({children, routes, mobileRoutes = [], sl
|
||||
<NextLink
|
||||
className={navLinkClasses}
|
||||
color="foreground"
|
||||
data-active={includes(docsPaths, pathname)}
|
||||
data-active={docsPaths.includes(pathname)}
|
||||
href="/docs/guide/introduction"
|
||||
onClick={() => handlePressNavbarItem("Docs", "/docs/guide/introduction")}
|
||||
>
|
||||
@ -208,7 +207,7 @@ export const Navbar: FC<NavbarProps> = ({children, routes, mobileRoutes = [], sl
|
||||
<NextLink
|
||||
className={navLinkClasses}
|
||||
color="foreground"
|
||||
data-active={includes(pathname, "components")}
|
||||
data-active={pathname.includes("components")}
|
||||
href="/docs/components/accordion"
|
||||
onClick={() => handlePressNavbarItem("Components", "/docs/components/accordion")}
|
||||
>
|
||||
@ -219,7 +218,7 @@ export const Navbar: FC<NavbarProps> = ({children, routes, mobileRoutes = [], sl
|
||||
<NextLink
|
||||
className={navLinkClasses}
|
||||
color="foreground"
|
||||
data-active={includes(pathname, "blog")}
|
||||
data-active={pathname.includes("blog")}
|
||||
href="/blog"
|
||||
onClick={() => handlePressNavbarItem("Blog", "/blog")}
|
||||
>
|
||||
@ -230,7 +229,7 @@ export const Navbar: FC<NavbarProps> = ({children, routes, mobileRoutes = [], sl
|
||||
<NextLink
|
||||
className={navLinkClasses}
|
||||
color="foreground"
|
||||
data-active={includes(pathname, "figma")}
|
||||
data-active={pathname.includes("figma")}
|
||||
href="/figma"
|
||||
onClick={() => handlePressNavbarItem("Figma", "/figma")}
|
||||
>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import React from "react";
|
||||
import {usePathname} from "next/navigation";
|
||||
import {Tooltip, Button} from "@nextui-org/react";
|
||||
import {capitalize, last} from "lodash";
|
||||
import {capitalize} from "@nextui-org/shared-utils";
|
||||
|
||||
import {BugIcon} from "@/components/icons";
|
||||
import {ISSUE_REPORT_URL} from "@/libs/github/constants";
|
||||
@ -9,7 +9,7 @@ import {ISSUE_REPORT_URL} from "@/libs/github/constants";
|
||||
export const BugReportButton = () => {
|
||||
const pathname = usePathname();
|
||||
|
||||
const componentTitle = capitalize(last(pathname?.split("/")));
|
||||
const componentTitle = capitalize(pathname?.split("/")?.at(-1) ?? "");
|
||||
|
||||
const handlePress = () => {
|
||||
window.open(`${ISSUE_REPORT_URL}${componentTitle}`, "_blank");
|
||||
|
||||
@ -70,7 +70,7 @@ export const useSandpack = ({
|
||||
}, {});
|
||||
|
||||
let dependencies = {
|
||||
"framer-motion": "11.0.22",
|
||||
"framer-motion": "11.9.0",
|
||||
"@nextui-org/react": "latest",
|
||||
};
|
||||
|
||||
@ -143,7 +143,7 @@ export const useSandpack = ({
|
||||
|
||||
// const dependencies = useMemo(() => {
|
||||
// let deps = {
|
||||
// "framer-motion": "11.0.22",
|
||||
// "framer-motion": "11.9.0",
|
||||
// };
|
||||
|
||||
// if (hasComponents) {
|
||||
|
||||
@ -220,8 +220,8 @@ const users = [
|
||||
|
||||
export {columns, users, statusOptions};`;
|
||||
|
||||
const utils = `export function capitalize(str) {
|
||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||
const utils = `export function capitalize(s) {
|
||||
return s ? s.charAt(0).toUpperCase() + s.slice(1).toLowerCase() : "";
|
||||
}`;
|
||||
|
||||
const PlusIcon = `export const PlusIcon = ({size = 24, width, height, ...props}) => (
|
||||
|
||||
@ -448,8 +448,8 @@ export type IconSvgProps = SVGProps<SVGSVGElement> & {
|
||||
size?: number;
|
||||
};`;
|
||||
|
||||
const utils = `export function capitalize(str) {
|
||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||
const utils = `export function capitalize(s) {
|
||||
return s ? s.charAt(0).toUpperCase() + s.slice(1).toLowerCase() : "";
|
||||
}`;
|
||||
|
||||
const PlusIcon = `export const PlusIcon = ({size = 24, width, height, ...props}) => (
|
||||
@ -544,8 +544,8 @@ const ChevronDownIcon = `export const ChevronDownIcon = ({strokeWidth = 1.5, ...
|
||||
</svg>
|
||||
);`;
|
||||
|
||||
const utilsTs = `export function capitalize(str: string) {
|
||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||
const utilsTs = `export function capitalize(s: string) {
|
||||
return s ? s.charAt(0).toUpperCase() + s.slice(1).toLowerCase() : "";
|
||||
}`;
|
||||
|
||||
const PlusIconTs = `import {IconSvgProps} from "./types";
|
||||
|
||||
@ -55,11 +55,10 @@
|
||||
"color2k": "^2.0.2",
|
||||
"contentlayer2": "^0.5.1",
|
||||
"date-fns": "^2.30.0",
|
||||
"framer-motion": "^11.1.7",
|
||||
"framer-motion": "11.9.0",
|
||||
"github-slugger": "^2.0.0",
|
||||
"gray-matter": "^4.0.3",
|
||||
"hast-util-to-html": "9.0.3",
|
||||
"lodash": "^4.17.21",
|
||||
"marked": "^5.1.0",
|
||||
"match-sorter": "^6.3.1",
|
||||
"mini-svg-data-uri": "^1.4.3",
|
||||
@ -102,7 +101,6 @@
|
||||
"@react-types/shared": "3.24.1",
|
||||
"@tailwindcss/typography": "^0.5.9",
|
||||
"@types/canvas-confetti": "^1.4.2",
|
||||
"@types/lodash": "^4.14.194",
|
||||
"@types/marked": "^5.0.0",
|
||||
"@types/mdx": "^2.0.5",
|
||||
"@types/node": "20.2.5",
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import {uniqBy} from "lodash";
|
||||
import {uniqBy} from "@nextui-org/shared-utils";
|
||||
import fetch from "node-fetch";
|
||||
|
||||
import {__PROD__} from "./env";
|
||||
|
||||
@ -42,7 +42,7 @@
|
||||
"peerDependencies": {
|
||||
"react": ">=18",
|
||||
"react-dom": ">=18",
|
||||
"framer-motion": ">=10.17.0",
|
||||
"framer-motion": ">=11.5.6",
|
||||
"@nextui-org/theme": ">=2.1.0",
|
||||
"@nextui-org/system": ">=2.0.0"
|
||||
},
|
||||
@ -54,6 +54,7 @@
|
||||
"@nextui-org/framer-utils": "workspace:*",
|
||||
"@nextui-org/divider": "workspace:*",
|
||||
"@nextui-org/use-aria-accordion": "workspace:*",
|
||||
"@nextui-org/dom-animation": "workspace:*",
|
||||
"@react-aria/interactions": "3.22.2",
|
||||
"@react-aria/focus": "3.18.2",
|
||||
"@react-aria/utils": "3.25.2",
|
||||
@ -69,7 +70,7 @@
|
||||
"@nextui-org/avatar": "workspace:*",
|
||||
"@nextui-org/input": "workspace:*",
|
||||
"@nextui-org/test-utils": "workspace:*",
|
||||
"framer-motion": "^11.0.22",
|
||||
"framer-motion": "11.9.0",
|
||||
"clean-package": "2.2.0",
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0"
|
||||
|
||||
@ -3,13 +3,15 @@ import type {Variants} from "framer-motion";
|
||||
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 {AnimatePresence, LazyMotion, m, useWillChange} from "framer-motion";
|
||||
import {TRANSITION_VARIANTS} from "@nextui-org/framer-utils";
|
||||
|
||||
import {UseAccordionItemProps, useAccordionItem} from "./use-accordion-item";
|
||||
|
||||
export interface AccordionItemProps extends UseAccordionItemProps {}
|
||||
|
||||
const domAnimation = () => import("@nextui-org/dom-animation").then((res) => res.default);
|
||||
|
||||
const AccordionItem = forwardRef<"button", AccordionItemProps>((props, ref) => {
|
||||
const {
|
||||
Component,
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
"peerDependencies": {
|
||||
"@nextui-org/system": ">=2.0.0",
|
||||
"@nextui-org/theme": ">=2.1.0",
|
||||
"framer-motion": ">=10.17.0",
|
||||
"framer-motion": ">=11.5.6",
|
||||
"react": ">=18",
|
||||
"react-dom": ">=18"
|
||||
},
|
||||
@ -72,7 +72,7 @@
|
||||
"@nextui-org/use-infinite-scroll": "workspace:*",
|
||||
"@react-stately/data": "3.11.6",
|
||||
"clean-package": "2.2.0",
|
||||
"framer-motion": "^11.0.28",
|
||||
"framer-motion": "11.9.0",
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0",
|
||||
"react-hook-form": "^7.51.3"
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
"peerDependencies": {
|
||||
"react": ">=18",
|
||||
"react-dom": ">=18",
|
||||
"framer-motion": ">=10.17.0",
|
||||
"framer-motion": ">=11.5.6",
|
||||
"@nextui-org/theme": ">=2.1.0",
|
||||
"@nextui-org/system": ">=2.0.0"
|
||||
},
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
"@nextui-org/framer-utils": "workspace:*",
|
||||
"@nextui-org/use-aria-button": "workspace:*",
|
||||
"@nextui-org/button": "workspace:*",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"@nextui-org/dom-animation": "workspace:*",
|
||||
"@internationalized/date": "3.5.5",
|
||||
"@react-aria/calendar": "3.5.11",
|
||||
"@react-aria/focus": "3.18.2",
|
||||
@ -67,7 +67,7 @@
|
||||
"@nextui-org/theme": "workspace:*",
|
||||
"@nextui-org/radio": "workspace:*",
|
||||
"@nextui-org/test-utils": "workspace:*",
|
||||
"framer-motion": "^10.16.4",
|
||||
"framer-motion": "11.9.0",
|
||||
"clean-package": "2.2.0",
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0"
|
||||
|
||||
@ -3,12 +3,11 @@ 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 {Fragment, useState} from "react";
|
||||
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 {AnimatePresence, LazyMotion, MotionConfig} from "framer-motion";
|
||||
import {ResizablePanel} from "@nextui-org/framer-utils";
|
||||
|
||||
import {ChevronLeftIcon} from "./chevron-left";
|
||||
@ -19,6 +18,8 @@ import {CalendarHeader} from "./calendar-header";
|
||||
import {CalendarPicker} from "./calendar-picker";
|
||||
import {useCalendarContext} from "./calendar-context";
|
||||
|
||||
const domAnimation = () => import("@nextui-org/dom-animation").then((res) => res.default);
|
||||
|
||||
export interface CalendarBaseProps extends HTMLNextUIProps<"div"> {
|
||||
Component?: As;
|
||||
showHelper?: boolean;
|
||||
|
||||
@ -4,7 +4,7 @@ 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 {debounce} from "@nextui-org/shared-utils";
|
||||
import {areRectsIntersecting} from "@nextui-org/react-utils";
|
||||
import scrollIntoView from "scroll-into-view-if-needed";
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
"peerDependencies": {
|
||||
"react": ">=18",
|
||||
"react-dom": ">=18",
|
||||
"framer-motion": ">=10.17.0",
|
||||
"framer-motion": ">=11.5.6",
|
||||
"@nextui-org/theme": ">=2.1.0",
|
||||
"@nextui-org/system": ">=2.0.0"
|
||||
},
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
"peerDependencies": {
|
||||
"@nextui-org/system": ">=2.0.0",
|
||||
"@nextui-org/theme": ">=2.1.0",
|
||||
"framer-motion": ">=10.17.0",
|
||||
"framer-motion": ">=11.5.6",
|
||||
"react": ">=18",
|
||||
"react-dom": ">=18"
|
||||
},
|
||||
@ -62,7 +62,7 @@
|
||||
"@nextui-org/theme": "workspace:*",
|
||||
"@nextui-org/user": "workspace:*",
|
||||
"clean-package": "2.2.0",
|
||||
"framer-motion": "^11.0.22",
|
||||
"framer-motion": "11.9.0",
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0"
|
||||
},
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
"peerDependencies": {
|
||||
"react": ">=18",
|
||||
"react-dom": ">=18",
|
||||
"framer-motion": ">=10.17.0",
|
||||
"framer-motion": ">=11.5.6",
|
||||
"@nextui-org/theme": ">=2.1.0",
|
||||
"@nextui-org/system": ">=2.0.0"
|
||||
},
|
||||
@ -49,6 +49,7 @@
|
||||
"@nextui-org/react-utils": "workspace:*",
|
||||
"@nextui-org/shared-icons": "workspace:*",
|
||||
"@nextui-org/use-aria-modal-overlay": "workspace:*",
|
||||
"@nextui-org/dom-animation": "workspace:*",
|
||||
"@react-aria/dialog": "3.5.17",
|
||||
"@react-aria/focus": "3.18.2",
|
||||
"@react-aria/interactions": "3.22.2",
|
||||
@ -66,7 +67,7 @@
|
||||
"@nextui-org/link": "workspace:*",
|
||||
"@nextui-org/switch": "workspace:*",
|
||||
"react-lorem-component": "0.13.0",
|
||||
"framer-motion": "^11.0.22",
|
||||
"framer-motion": "11.9.0",
|
||||
"clean-package": "2.2.0",
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0"
|
||||
|
||||
@ -6,7 +6,7 @@ import {forwardRef} from "@nextui-org/system";
|
||||
import {DismissButton} from "@react-aria/overlays";
|
||||
import {TRANSITION_VARIANTS} from "@nextui-org/framer-utils";
|
||||
import {CloseIcon} from "@nextui-org/shared-icons";
|
||||
import {domAnimation, LazyMotion, m} from "framer-motion";
|
||||
import {LazyMotion, m} from "framer-motion";
|
||||
import {useDialog} from "@react-aria/dialog";
|
||||
import {chain, mergeProps, useViewportSize} from "@react-aria/utils";
|
||||
import {HTMLNextUIProps} from "@nextui-org/system";
|
||||
@ -21,6 +21,8 @@ export interface ModalContentProps extends AriaDialogProps, HTMLNextUIProps<"div
|
||||
children: ReactNode | ((onClose: () => void) => ReactNode);
|
||||
}
|
||||
|
||||
const domAnimation = () => import("@nextui-org/dom-animation").then((res) => res.default);
|
||||
|
||||
const ModalContent = forwardRef<"div", ModalContentProps, KeysToOmit>((props, _) => {
|
||||
const {as, children, role = "dialog", ...otherProps} = props;
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@ export const scaleInOut = {
|
||||
scale: "var(--scale-enter)",
|
||||
y: "var(--slide-enter)",
|
||||
opacity: 1,
|
||||
willChange: "auto",
|
||||
transition: {
|
||||
scale: {
|
||||
duration: 0.4,
|
||||
@ -25,6 +26,7 @@ export const scaleInOut = {
|
||||
scale: "var(--scale-exit)",
|
||||
y: "var(--slide-exit)",
|
||||
opacity: 0,
|
||||
willChange: "transform",
|
||||
transition: {
|
||||
duration: 0.3,
|
||||
ease: TRANSITION_EASINGS.ease,
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
"peerDependencies": {
|
||||
"react": ">=18",
|
||||
"react-dom": ">=18",
|
||||
"framer-motion": ">=10.17.0",
|
||||
"framer-motion": ">=11.5.6",
|
||||
"@nextui-org/theme": ">=2.1.0",
|
||||
"@nextui-org/system": ">=2.0.0"
|
||||
},
|
||||
@ -46,6 +46,7 @@
|
||||
"@nextui-org/framer-utils": "workspace:*",
|
||||
"@nextui-org/use-aria-toggle-button": "workspace:*",
|
||||
"@nextui-org/use-scroll-position": "workspace:*",
|
||||
"@nextui-org/dom-animation": "workspace:*",
|
||||
"@react-aria/focus": "3.18.2",
|
||||
"@react-aria/interactions": "3.22.2",
|
||||
"@react-aria/overlays": "3.23.2",
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import {forwardRef, HTMLNextUIProps} from "@nextui-org/system";
|
||||
import {useDOMRef} from "@nextui-org/react-utils";
|
||||
import {clsx, dataAttr} from "@nextui-org/shared-utils";
|
||||
import {AnimatePresence, domAnimation, HTMLMotionProps, LazyMotion, m} from "framer-motion";
|
||||
import {AnimatePresence, HTMLMotionProps, LazyMotion, m} from "framer-motion";
|
||||
import {mergeProps} from "@react-aria/utils";
|
||||
import {ReactElement, useCallback} from "react";
|
||||
import {RemoveScroll} from "react-remove-scroll";
|
||||
@ -23,6 +23,8 @@ export interface NavbarMenuProps extends HTMLNextUIProps<"ul"> {
|
||||
motionProps?: HTMLMotionProps<"ul">;
|
||||
}
|
||||
|
||||
const domAnimation = () => import("@nextui-org/dom-animation").then((res) => res.default);
|
||||
|
||||
const NavbarMenu = forwardRef<"ul", NavbarMenuProps>((props, ref) => {
|
||||
const {className, children, portalContainer, motionProps, style, ...otherProps} = props;
|
||||
const domRef = useDOMRef(ref);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import {forwardRef} from "@nextui-org/system";
|
||||
import {pickChildren} from "@nextui-org/react-utils";
|
||||
import {LazyMotion, domAnimation, m} from "framer-motion";
|
||||
import {LazyMotion, m} from "framer-motion";
|
||||
import {mergeProps} from "@react-aria/utils";
|
||||
|
||||
import {hideOnScrollVariants} from "./navbar-transitions";
|
||||
@ -12,6 +12,8 @@ export interface NavbarProps extends Omit<UseNavbarProps, "hideOnScroll"> {
|
||||
children?: React.ReactNode | React.ReactNode[];
|
||||
}
|
||||
|
||||
const domAnimation = () => import("@nextui-org/dom-animation").then((res) => res.default);
|
||||
|
||||
const Navbar = forwardRef<"div", NavbarProps>((props, ref) => {
|
||||
const {children, ...otherProps} = props;
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
"peerDependencies": {
|
||||
"@nextui-org/system": ">=2.0.0",
|
||||
"@nextui-org/theme": ">=2.1.0",
|
||||
"framer-motion": ">=10.17.0",
|
||||
"framer-motion": ">=11.5.6",
|
||||
"react": ">=18",
|
||||
"react-dom": ">=18"
|
||||
},
|
||||
@ -48,6 +48,7 @@
|
||||
"@nextui-org/shared-utils": "workspace:*",
|
||||
"@nextui-org/use-aria-button": "workspace:*",
|
||||
"@nextui-org/use-safe-layout-effect": "workspace:*",
|
||||
"@nextui-org/dom-animation": "workspace:*",
|
||||
"@react-aria/dialog": "3.5.17",
|
||||
"@react-aria/focus": "3.18.2",
|
||||
"@react-aria/interactions": "3.22.2",
|
||||
@ -64,7 +65,7 @@
|
||||
"@nextui-org/system": "workspace:*",
|
||||
"@nextui-org/theme": "workspace:*",
|
||||
"clean-package": "2.2.0",
|
||||
"framer-motion": "^11.0.22",
|
||||
"framer-motion": "11.9.0",
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0"
|
||||
},
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
import * as React from "react";
|
||||
import {DismissButton, Overlay} from "@react-aria/overlays";
|
||||
import {forwardRef} from "@nextui-org/system";
|
||||
import {domAnimation, HTMLMotionProps, LazyMotion, m} from "framer-motion";
|
||||
import {HTMLMotionProps, LazyMotion, m} from "framer-motion";
|
||||
import {mergeProps} from "@react-aria/utils";
|
||||
import {getTransformOrigins} from "@nextui-org/aria-utils";
|
||||
import {TRANSITION_VARIANTS} from "@nextui-org/framer-utils";
|
||||
@ -18,6 +18,8 @@ import {useDialog} from "@react-aria/dialog";
|
||||
|
||||
import {usePopover, UsePopoverProps, UsePopoverReturn} from "./use-popover";
|
||||
|
||||
const domAnimation = () => import("@nextui-org/dom-animation").then((res) => res.default);
|
||||
|
||||
export interface FreeSoloPopoverProps extends Omit<UsePopoverProps, "children"> {
|
||||
children: React.ReactNode | ((titleProps: React.DOMAttributes<HTMLElement>) => React.ReactNode);
|
||||
transformOrigin?: {
|
||||
|
||||
@ -6,7 +6,7 @@ import {forwardRef} from "@nextui-org/system";
|
||||
import {RemoveScroll} from "react-remove-scroll";
|
||||
import {DismissButton} from "@react-aria/overlays";
|
||||
import {TRANSITION_VARIANTS} from "@nextui-org/framer-utils";
|
||||
import {m, domAnimation, LazyMotion} from "framer-motion";
|
||||
import {m, LazyMotion} from "framer-motion";
|
||||
import {HTMLNextUIProps} from "@nextui-org/system";
|
||||
import {getTransformOrigins} from "@nextui-org/aria-utils";
|
||||
import {useDialog} from "@react-aria/dialog";
|
||||
@ -19,6 +19,8 @@ export interface PopoverContentProps
|
||||
children: ReactNode | ((titleProps: DOMAttributes<HTMLElement>) => ReactNode);
|
||||
}
|
||||
|
||||
const domAnimation = () => import("@nextui-org/dom-animation").then((res) => res.default);
|
||||
|
||||
const PopoverContent = forwardRef<"div", PopoverContentProps>((props, _) => {
|
||||
const {as, children, className, ...otherProps} = props;
|
||||
|
||||
|
||||
@ -36,19 +36,20 @@
|
||||
"peerDependencies": {
|
||||
"react": ">=18",
|
||||
"react-dom": ">=18",
|
||||
"framer-motion": ">=10.17.0",
|
||||
"framer-motion": ">=11.5.6",
|
||||
"@nextui-org/theme": ">=2.1.0",
|
||||
"@nextui-org/system": ">=2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nextui-org/shared-utils": "workspace:*",
|
||||
"@nextui-org/react-utils": "workspace:*"
|
||||
"@nextui-org/react-utils": "workspace:*",
|
||||
"@nextui-org/dom-animation": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nextui-org/theme": "workspace:*",
|
||||
"@nextui-org/system": "workspace:*",
|
||||
"clean-package": "2.2.0",
|
||||
"framer-motion": "^11.0.22",
|
||||
"framer-motion": "11.9.0",
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0"
|
||||
},
|
||||
|
||||
@ -3,7 +3,7 @@ import type {FC} from "react";
|
||||
import type {HTMLMotionProps} from "framer-motion";
|
||||
import type {HTMLNextUIProps} from "@nextui-org/system";
|
||||
|
||||
import {AnimatePresence, m, LazyMotion, domAnimation} from "framer-motion";
|
||||
import {AnimatePresence, m, LazyMotion} from "framer-motion";
|
||||
import {clamp} from "@nextui-org/shared-utils";
|
||||
|
||||
export interface RippleProps extends HTMLNextUIProps<"span"> {
|
||||
@ -14,6 +14,8 @@ export interface RippleProps extends HTMLNextUIProps<"span"> {
|
||||
onClear: (key: React.Key) => void;
|
||||
}
|
||||
|
||||
const domAnimation = () => import("@nextui-org/dom-animation").then((res) => res.default);
|
||||
|
||||
const Ripple: FC<RippleProps> = (props) => {
|
||||
const {ripples = [], motionProps, color = "currentColor", style, onClear} = props;
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
"peerDependencies": {
|
||||
"@nextui-org/system": ">=2.0.0",
|
||||
"@nextui-org/theme": ">=2.1.0",
|
||||
"framer-motion": ">=10.17.0",
|
||||
"framer-motion": ">=11.5.6",
|
||||
"react": ">=18",
|
||||
"react-dom": ">=18"
|
||||
},
|
||||
@ -71,7 +71,7 @@
|
||||
"@react-aria/i18n": "3.12.2",
|
||||
"@react-stately/data": "3.11.6",
|
||||
"clean-package": "2.2.0",
|
||||
"framer-motion": "^11.0.28",
|
||||
"framer-motion": "11.9.0",
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0",
|
||||
"react-hook-form": "^7.51.3"
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
"peerDependencies": {
|
||||
"react": ">=18",
|
||||
"react-dom": ">=18",
|
||||
"framer-motion": ">=10.17.0",
|
||||
"framer-motion": ">=11.5.6",
|
||||
"@nextui-org/theme": ">=2.1.0",
|
||||
"@nextui-org/system": ">=2.0.0"
|
||||
},
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
"peerDependencies": {
|
||||
"react": ">=18",
|
||||
"react-dom": ">=18",
|
||||
"framer-motion": ">=10.17.0",
|
||||
"framer-motion": ">=11.5.6",
|
||||
"@nextui-org/theme": ">=2.1.0",
|
||||
"@nextui-org/system": ">=2.0.0"
|
||||
},
|
||||
@ -59,7 +59,7 @@
|
||||
"devDependencies": {
|
||||
"@nextui-org/theme": "workspace:*",
|
||||
"@nextui-org/system": "workspace:*",
|
||||
"framer-motion": "^11.0.22",
|
||||
"framer-motion": "11.9.0",
|
||||
"react-lorem-component": "0.13.0",
|
||||
"@nextui-org/card": "workspace:*",
|
||||
"@nextui-org/input": "workspace:*",
|
||||
|
||||
@ -123,6 +123,8 @@ const Tab = forwardRef<"button", TabItemProps>((props, ref) => {
|
||||
type={Component === "button" ? "button" : undefined}
|
||||
>
|
||||
{isSelected && !disableAnimation && !disableCursorAnimation && isMounted ? (
|
||||
// use synchronous loading for domMax here
|
||||
// since lazy loading produces different behaviour
|
||||
<LazyMotion features={domMax}>
|
||||
<m.span
|
||||
className={slots.cursor({class: classNames?.cursor})}
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
"peerDependencies": {
|
||||
"react": ">=18",
|
||||
"react-dom": ">=18",
|
||||
"framer-motion": ">=10.17.0",
|
||||
"framer-motion": ">=11.5.6",
|
||||
"@nextui-org/theme": ">=2.1.0",
|
||||
"@nextui-org/system": ">=2.0.0"
|
||||
},
|
||||
@ -46,6 +46,7 @@
|
||||
"@nextui-org/aria-utils": "workspace:*",
|
||||
"@nextui-org/framer-utils": "workspace:*",
|
||||
"@nextui-org/use-safe-layout-effect": "workspace:*",
|
||||
"@nextui-org/dom-animation": "workspace:*",
|
||||
"@react-aria/interactions": "3.22.2",
|
||||
"@react-aria/overlays": "3.23.2",
|
||||
"@react-aria/tooltip": "3.7.7",
|
||||
@ -59,7 +60,7 @@
|
||||
"@nextui-org/system": "workspace:*",
|
||||
"@nextui-org/theme": "workspace:*",
|
||||
"clean-package": "2.2.0",
|
||||
"framer-motion": "^11.0.28",
|
||||
"framer-motion": "11.9.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
},
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import {forwardRef} from "@nextui-org/system";
|
||||
import {OverlayContainer} from "@react-aria/overlays";
|
||||
import {AnimatePresence, m, LazyMotion, domAnimation} from "framer-motion";
|
||||
import {AnimatePresence, m, LazyMotion} from "framer-motion";
|
||||
import {TRANSITION_VARIANTS} from "@nextui-org/framer-utils";
|
||||
import {warn} from "@nextui-org/shared-utils";
|
||||
import {Children, cloneElement, isValidElement} from "react";
|
||||
@ -11,6 +11,8 @@ import {UseTooltipProps, useTooltip} from "./use-tooltip";
|
||||
|
||||
export interface TooltipProps extends Omit<UseTooltipProps, "disableTriggerFocus" | "backdrop"> {}
|
||||
|
||||
const domAnimation = () => import("@nextui-org/dom-animation").then((res) => res.default);
|
||||
|
||||
const Tooltip = forwardRef<"div", TooltipProps>((props, ref) => {
|
||||
const {
|
||||
Component,
|
||||
|
||||
@ -91,7 +91,7 @@
|
||||
"peerDependencies": {
|
||||
"react": ">=18",
|
||||
"react-dom": ">=18",
|
||||
"framer-motion": ">=10.17.0"
|
||||
"framer-motion": ">=11.5.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"react": "^18.0.0",
|
||||
|
||||
@ -34,13 +34,13 @@
|
||||
"postpack": "clean-package restore"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"framer-motion": ">=10.17.0",
|
||||
"framer-motion": ">=11.5.6",
|
||||
"react": ">=18",
|
||||
"react-dom": ">=18"
|
||||
},
|
||||
"devDependencies": {
|
||||
"clean-package": "2.2.0",
|
||||
"framer-motion": "^11.0.22",
|
||||
"framer-motion": "11.9.0",
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0"
|
||||
},
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import {getContrast} from "color2k";
|
||||
import get from "lodash.get";
|
||||
import {get} from "@nextui-org/shared-utils";
|
||||
|
||||
import {semanticColors} from "../src/colors/semantic";
|
||||
|
||||
|
||||
@ -50,14 +50,10 @@
|
||||
"color2k": "^2.0.2",
|
||||
"deepmerge": "4.3.1",
|
||||
"flat": "^5.0.2",
|
||||
"lodash.foreach": "^4.5.0",
|
||||
"lodash.get": "^4.4.2",
|
||||
"lodash.kebabcase": "^4.1.1",
|
||||
"lodash.mapkeys": "^4.6.0",
|
||||
"lodash.omit": "^4.5.0",
|
||||
"clsx": "^1.2.1",
|
||||
"tailwind-variants": "^0.1.20",
|
||||
"tailwind-merge": "^2.5.2"
|
||||
"tailwind-merge": "^2.5.2",
|
||||
"@nextui-org/shared-utils": "workspace:*"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"tailwindcss": ">=3.4.0"
|
||||
@ -65,11 +61,6 @@
|
||||
"devDependencies": {
|
||||
"@types/color": "^3.0.3",
|
||||
"@types/flat": "^5.0.2",
|
||||
"@types/lodash.foreach": "^4.5.7",
|
||||
"@types/lodash.get": "^4.4.7",
|
||||
"@types/lodash.kebabcase": "^4.1.7",
|
||||
"@types/lodash.mapkeys": "^4.6.7",
|
||||
"@types/lodash.omit": "^4.5.7",
|
||||
"tailwindcss": "^3.4.0",
|
||||
"clean-package": "2.2.0"
|
||||
},
|
||||
|
||||
@ -5,12 +5,8 @@
|
||||
|
||||
import Color from "color";
|
||||
import plugin from "tailwindcss/plugin.js";
|
||||
import get from "lodash.get";
|
||||
import omit from "lodash.omit";
|
||||
import forEach from "lodash.foreach";
|
||||
import mapKeys from "lodash.mapkeys";
|
||||
import kebabCase from "lodash.kebabcase";
|
||||
import deepMerge from "deepmerge";
|
||||
import {omit, kebabCase, mapKeys} from "@nextui-org/shared-utils";
|
||||
|
||||
import {semanticColors, commonColors} from "./colors";
|
||||
import {animations} from "./animations";
|
||||
@ -63,7 +59,7 @@ const resolveConfig = (
|
||||
// flatten color definitions
|
||||
const flatColors = flattenThemeObject(colors) as Record<string, string>;
|
||||
|
||||
const flatLayout = layout ? mapKeys(layout, (value, key) => kebabCase(key)) : {};
|
||||
const flatLayout = layout ? mapKeys(layout, (_, key) => kebabCase(key)) : {};
|
||||
|
||||
// resolved.variants
|
||||
resolved.variants.push({
|
||||
@ -246,8 +242,8 @@ export const nextui = (config: NextUIPluginConfig = {}): ReturnType<typeof plugi
|
||||
addCommonColors = false,
|
||||
} = config;
|
||||
|
||||
const userLightColors = get(themeObject, "light.colors", {});
|
||||
const userDarkColors = get(themeObject, "dark.colors", {});
|
||||
const userLightColors = themeObject?.light?.colors || {};
|
||||
const userDarkColors = themeObject?.dark?.colors || {};
|
||||
|
||||
const defaultLayoutObj =
|
||||
userLayout && typeof userLayout === "object"
|
||||
@ -268,7 +264,7 @@ export const nextui = (config: NextUIPluginConfig = {}): ReturnType<typeof plugi
|
||||
// get other themes from the config different from light and dark
|
||||
let otherThemes = omit(themeObject, ["light", "dark"]) || {};
|
||||
|
||||
forEach(otherThemes, ({extend, colors, layout}, themeName) => {
|
||||
Object.entries(otherThemes).forEach(([themeName, {extend, colors, layout}]) => {
|
||||
const baseTheme = extend && isBaseTheme(extend) ? extend : defaultExtendTheme;
|
||||
|
||||
if (colors && typeof colors === "object") {
|
||||
@ -283,12 +279,12 @@ export const nextui = (config: NextUIPluginConfig = {}): ReturnType<typeof plugi
|
||||
});
|
||||
|
||||
const light: ConfigTheme = {
|
||||
layout: deepMerge(baseLayouts.light, get(themeObject, "light.layout", {})),
|
||||
layout: deepMerge(baseLayouts.light, themeObject?.light?.layout || {}),
|
||||
colors: deepMerge(semanticColors.light, userLightColors),
|
||||
};
|
||||
|
||||
const dark = {
|
||||
layout: deepMerge(baseLayouts.dark, get(themeObject, "dark.layout", {})),
|
||||
layout: deepMerge(baseLayouts.dark, themeObject?.dark?.layout || {}),
|
||||
colors: deepMerge(semanticColors.dark, userDarkColors),
|
||||
};
|
||||
|
||||
|
||||
@ -33,13 +33,12 @@
|
||||
"prepack": "clean-package",
|
||||
"postpack": "clean-package restore"
|
||||
},
|
||||
"dependencies": {
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"@types/lodash.debounce": "^4.0.7"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=18"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nextui-org/shared-utils": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"clean-package": "2.2.0",
|
||||
"react": "^18.0.0"
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import debounce from "lodash.debounce";
|
||||
import {useLayoutEffect, useRef, useCallback} from "react";
|
||||
import {debounce} from "@nextui-org/shared-utils";
|
||||
|
||||
export interface UseInfiniteScrollProps {
|
||||
/**
|
||||
|
||||
23
packages/utilities/dom-animation/README.md
Normal file
23
packages/utilities/dom-animation/README.md
Normal file
@ -0,0 +1,23 @@
|
||||
# @nextui-org/dom-animation
|
||||
|
||||
A Quick description of the component
|
||||
|
||||
> This is an internal utility, not intended for public usage.
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
yarn add @nextui-org/dom-animation
|
||||
# or
|
||||
npm i @nextui-org/dom-animation
|
||||
```
|
||||
|
||||
## 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).
|
||||
44
packages/utilities/dom-animation/package.json
Normal file
44
packages/utilities/dom-animation/package.json
Normal file
@ -0,0 +1,44 @@
|
||||
{
|
||||
"name": "@nextui-org/dom-animation",
|
||||
"version": "2.0.0",
|
||||
"description": "Dom Animation from Framer Motion for dynamic import",
|
||||
"keywords": [
|
||||
"dom-animation"
|
||||
],
|
||||
"author": "WK Wong <wingkwong.code@gmail.com>",
|
||||
"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/utilities/dom-animation"
|
||||
},
|
||||
"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": {
|
||||
"framer-motion": ">=11.5.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"clean-package": "2.2.0",
|
||||
"framer-motion": "11.9.0"
|
||||
},
|
||||
"clean-package": "../../../clean-package.config.json"
|
||||
}
|
||||
3
packages/utilities/dom-animation/src/index.ts
Normal file
3
packages/utilities/dom-animation/src/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import {domAnimation} from "framer-motion";
|
||||
|
||||
export default domAnimation;
|
||||
4
packages/utilities/dom-animation/tsconfig.json
Normal file
4
packages/utilities/dom-animation/tsconfig.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"include": ["src", "index.ts"]
|
||||
}
|
||||
8
packages/utilities/dom-animation/tsup.config.ts
Normal file
8
packages/utilities/dom-animation/tsup.config.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import {defineConfig} from "tsup";
|
||||
|
||||
export default defineConfig({
|
||||
clean: true,
|
||||
target: "es2019",
|
||||
format: ["cjs", "esm"],
|
||||
banner: {js: '"use client";'},
|
||||
});
|
||||
@ -36,7 +36,7 @@
|
||||
"peerDependencies": {
|
||||
"react": ">=18",
|
||||
"react-dom": ">=18",
|
||||
"framer-motion": ">=10.17.0"
|
||||
"framer-motion": ">=11.5.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nextui-org/system": "workspace:*",
|
||||
@ -47,7 +47,7 @@
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0",
|
||||
"clean-package": "2.2.0",
|
||||
"framer-motion": "^11.0.22"
|
||||
"framer-motion": "11.9.0"
|
||||
},
|
||||
"clean-package": "../../../clean-package.config.json"
|
||||
}
|
||||
@ -8,15 +8,37 @@ type Extractable =
|
||||
}
|
||||
| undefined;
|
||||
|
||||
type Iteratee<T> = ((value: T) => any) | keyof T;
|
||||
|
||||
/**
|
||||
* Capitalizes the first letter of a string
|
||||
* @param {string} text
|
||||
* @returns {string}
|
||||
* Capitalizes the first character of a string and converts the rest of the string to lowercase.
|
||||
*
|
||||
* @param s - The string to capitalize.
|
||||
* @returns The capitalized string, or an empty string if the input is falsy.
|
||||
*
|
||||
* @example
|
||||
* capitalize('hello'); // returns 'Hello'
|
||||
* capitalize(''); // returns ''
|
||||
*/
|
||||
export const capitalize = (text: string) => {
|
||||
return text.charAt(0).toUpperCase() + text.slice(1);
|
||||
export const capitalize = (s: string) => {
|
||||
return s ? s.charAt(0).toUpperCase() + s.slice(1).toLowerCase() : "";
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a function that invokes each provided function with the same argument, until
|
||||
* one of the functions calls `event.preventDefault()`.
|
||||
*
|
||||
* @param fns - An array of functions that may or may not be defined.
|
||||
* @returns A function that takes an event and invokes each handler with this event.
|
||||
*
|
||||
* @typeParam T - A function type that takes an event-like argument.
|
||||
*
|
||||
* @example
|
||||
* const handler1 = event => console.log('Handled by first', event.type);
|
||||
* const handler2 = event => event.preventDefault();
|
||||
* const allHandlers = callAllHandlers(handler1, handler2);
|
||||
* allHandlers({ type: 'click' });
|
||||
*/
|
||||
export function callAllHandlers<T extends (event: any) => void>(...fns: (T | undefined)[]) {
|
||||
return function func(event: Args<T>[0]) {
|
||||
fns.some((fn) => {
|
||||
@ -27,6 +49,20 @@ export function callAllHandlers<T extends (event: any) => void>(...fns: (T | und
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a function that invokes each provided function with the same argument.
|
||||
*
|
||||
* @param fns - An array of functions that may or may not be defined.
|
||||
* @returns A function that takes one argument and invokes all provided functions with it.
|
||||
*
|
||||
* @typeParam T - A function type that takes any argument.
|
||||
*
|
||||
* @example
|
||||
* const greet = name => console.log(`Hello, ${name}!`);
|
||||
* const bye = name => console.log(`Goodbye, ${name}!`);
|
||||
* const greetAndBye = callAll(greet, bye);
|
||||
* greetAndBye('Alice');
|
||||
*/
|
||||
export function callAll<T extends AnyFunction>(...fns: (T | undefined)[]) {
|
||||
return function mergedFn(arg: Args<T>[0]) {
|
||||
fns.forEach((fn) => {
|
||||
@ -35,6 +71,21 @@ export function callAll<T extends AnyFunction>(...fns: (T | undefined)[]) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts a property from a list of objects, returning the first found non-falsy value or a default value.
|
||||
*
|
||||
* @param key - The key of the property to extract.
|
||||
* @param defaultValue - The default value to return if no non-falsy property value is found.
|
||||
* @param objs - An array of objects to search.
|
||||
* @returns The value of the extracted property or the default value.
|
||||
*
|
||||
* @typeParam K - The type of the key.
|
||||
* @typeParam D - The type of the default value.
|
||||
*
|
||||
* @example
|
||||
* extractProperty('name', 'Unknown', { name: 'Alice' }, { name: 'Bob' }); // returns 'Alice'
|
||||
* extractProperty('age', 18, { name: 'Alice' }); // returns 18
|
||||
*/
|
||||
export function extractProperty<K extends keyof Extractable, D extends keyof Extractable>(
|
||||
key: K | string,
|
||||
defaultValue: D | string | boolean,
|
||||
@ -51,12 +102,27 @@ export function extractProperty<K extends keyof Extractable, D extends keyof Ext
|
||||
return result as Extractable[K] | D | string | boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a unique identifier using a specified prefix and a random number.
|
||||
*
|
||||
* @param prefix - The prefix to prepend to the unique identifier.
|
||||
* @returns A string that combines the prefix and a random number.
|
||||
*
|
||||
* @example
|
||||
* getUniqueID('btn'); // returns 'btn-123456'
|
||||
*/
|
||||
export function getUniqueID(prefix: string) {
|
||||
return `${prefix}-${Math.floor(Math.random() * 1000000)}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function removes all event handlers from an object.
|
||||
* Removes all properties from an object that start with 'on', which are typically event handlers.
|
||||
*
|
||||
* @param input - The object from which to remove event properties.
|
||||
* @returns The same object with event properties removed.
|
||||
*
|
||||
* @example
|
||||
* removeEvents({ onClick: () => {}, onChange: () => {}, value: 10 }); // returns { value: 10 }
|
||||
*/
|
||||
export function removeEvents(input: {[key: string]: any}) {
|
||||
for (const key in input) {
|
||||
@ -68,6 +134,18 @@ export function removeEvents(input: {[key: string]: any}) {
|
||||
return input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an object into a JSON string. Returns an empty string if the object
|
||||
* is not extractable or if a circular reference is detected during stringification.
|
||||
*
|
||||
* @param obj - The object to convert into a dependency string.
|
||||
*
|
||||
* @returns A JSON string representation of the object or an empty string if conversion fails.
|
||||
*
|
||||
* @example
|
||||
* objectToDeps({ key: 'value' }); // returns '{"key":"value"}'
|
||||
* objectToDeps(undefined); // returns ""
|
||||
*/
|
||||
export function objectToDeps(obj: Extractable) {
|
||||
if (!obj || typeof obj !== "object") {
|
||||
return "";
|
||||
@ -79,3 +157,235 @@ export function objectToDeps(obj: Extractable) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a debounced function that delays invoking `func` until after `waitMilliseconds` have elapsed
|
||||
* since the last time the debounced function was invoked. The debounced function has the
|
||||
* same `this` context and arguments as the original function.
|
||||
*
|
||||
* @param func - The function to debounce.
|
||||
* @param waitMilliseconds - The number of milliseconds to delay; defaults to 0.
|
||||
*
|
||||
* @returns A new debounced function.
|
||||
*
|
||||
* @typeParam F - The type of the function to debounce.
|
||||
*
|
||||
* @example
|
||||
* const save = debounce(() => console.log('Saved!'), 300);
|
||||
* save(); // Will log 'Saved!' after 300ms, subsequent calls within 300ms will reset the timer.
|
||||
*/
|
||||
|
||||
export function debounce<F extends (...args: any[]) => void>(
|
||||
func: F,
|
||||
waitMilliseconds: number = 0,
|
||||
) {
|
||||
let timeout: ReturnType<typeof setTimeout> | undefined;
|
||||
|
||||
return function (this: ThisParameterType<F>, ...args: Parameters<F>) {
|
||||
const later = () => {
|
||||
timeout = undefined;
|
||||
func.apply(this, args);
|
||||
};
|
||||
|
||||
if (timeout !== undefined) {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
|
||||
timeout = setTimeout(later, waitMilliseconds);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new array of unique elements from the given array, where the uniqueness is determined by the specified iteratee.
|
||||
*
|
||||
* @param arr - The array to process.
|
||||
* @param iteratee - The iteratee invoked per element to generate the criterion by which uniqueness is computed.
|
||||
* This can be a function or the string key of the object properties.
|
||||
*
|
||||
* @returns A new array of elements that are unique based on the iteratee function.
|
||||
*
|
||||
* @typeParam T - The type of elements in the input array.
|
||||
*
|
||||
* @example
|
||||
* uniqBy([{ id: 1 }, { id: 2 }, { id: 1 }], 'id'); // returns [{ id: 1 }, { id: 2 }]
|
||||
*/
|
||||
export function uniqBy<T>(arr: T[], iteratee: any) {
|
||||
if (typeof iteratee === "string") {
|
||||
iteratee = (item: T) => item[iteratee as keyof T];
|
||||
}
|
||||
|
||||
return arr.filter((x, i, self) => i === self.findIndex((y) => iteratee(x) === iteratee(y)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an object composed of the own and inherited enumerable property paths of `obj` that are not omitted.
|
||||
*
|
||||
* @param obj - The source object.
|
||||
* @param keys - The property keys to omit.
|
||||
*
|
||||
* @returns A new object with the keys specified omitted.
|
||||
*
|
||||
* @typeParam Obj - The type of the object.
|
||||
* @typeParam Keys - The type of the keys to omit.
|
||||
*
|
||||
* @example
|
||||
* omit({ a: 1, b: '2', c: 3 }, ['a', 'c']); // returns { b: '2' }
|
||||
*/
|
||||
export const omit = <Obj, Keys extends keyof Obj>(obj: Obj, keys: Keys[]): Omit<Obj, Keys> => {
|
||||
const res = Object.assign({}, obj);
|
||||
|
||||
keys.forEach((key) => {
|
||||
delete res[key];
|
||||
});
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a string to kebab-case.
|
||||
*
|
||||
* @param s - The string to convert.
|
||||
*
|
||||
* @returns The kebab-case version of the string.
|
||||
*
|
||||
* @example
|
||||
* kebabCase('fooBar'); // returns 'foo-bar'
|
||||
*/
|
||||
export const kebabCase = (s: string) => {
|
||||
return s.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an object with keys transformed using provided `iteratee` function, which takes each value and the corresponding key.
|
||||
*
|
||||
* @param obj - The source object.
|
||||
* @param iteratee - The function invoked per iteration to transform the keys.
|
||||
*
|
||||
* @returns A new object with keys transformed by `iteratee`.
|
||||
*
|
||||
* @example
|
||||
* mapKeys({ a: 1, b: 2 }, (value, key) => key + value); // returns { a1: 1, b2: 2 }
|
||||
*/
|
||||
export const mapKeys = (
|
||||
obj: Record<string, any>,
|
||||
iteratee: (value: any, key: string) => any,
|
||||
): Record<string, any> => {
|
||||
return Object.fromEntries(
|
||||
Object.entries(obj).map(([key, value]) => [iteratee(value, key), value]),
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the value at a given path of a provided object safely. If the path does not exist,
|
||||
* the function returns a default value, if provided.
|
||||
*
|
||||
* @param object - The object from which to retrieve the property.
|
||||
* @param path - A dot notation string or an array of strings and numbers indicating the path of the property in the object.
|
||||
* Dot notation can also include array indices in bracket notation (e.g., 'a.b[0].c').
|
||||
* @param defaultValue - The value to return if the resolved value is `undefined`. This parameter is optional.
|
||||
*
|
||||
* @returns The value from the object at the specified path, or the default value if the path is not resolved.
|
||||
*
|
||||
* @example
|
||||
* const obj = { a: { b: [{ c: 3 }] } };
|
||||
*
|
||||
* // Using string path with dot and bracket notation
|
||||
* get(obj, 'a.b[0].c'); // returns 3
|
||||
*
|
||||
* // Using array path
|
||||
* get(obj, ['a', 'b', 0, 'c']); // returns 3
|
||||
*
|
||||
* // Using default value for non-existent path
|
||||
* get(obj, 'a.b[1].c', 'not found'); // returns 'not found'
|
||||
*/
|
||||
export const get = (
|
||||
object: Record<string, any>,
|
||||
path: string | (string | number)[],
|
||||
defaultValue?: any,
|
||||
): any => {
|
||||
const keys = Array.isArray(path) ? path : path.replace(/\[(\d+)\]/g, ".$1").split(".");
|
||||
|
||||
let res: any = object;
|
||||
|
||||
for (const key of keys) {
|
||||
res = res?.[key];
|
||||
|
||||
if (res === undefined) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
/**
|
||||
* Computes the list of values that are the intersection of all provided arrays,
|
||||
* with each element being transformed by the given iteratee, which can be a function or property name.
|
||||
*
|
||||
* @param args - A rest parameter that collects all arrays to intersect followed by an iteratee.
|
||||
* The last element in `args` is the iteratee, which can be either a function or a property name string.
|
||||
* The rest are arrays of elements of type T.
|
||||
*
|
||||
* @returns An array of elements of type T that exist in all arrays after being transformed by the iteratee.
|
||||
*
|
||||
* @throws {Error} If less than two arguments are provided or if the iteratee is not a function or a valid property string.
|
||||
*
|
||||
* @typeParam T - The type of elements in the input arrays.
|
||||
*
|
||||
* @example
|
||||
* // Using a function as an iteratee
|
||||
* intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor); // returns [2.1]
|
||||
*
|
||||
* // Using a property name as an iteratee
|
||||
* intersectionBy([{ x: 1 }, { x: 2 }], [{ x: 1 }], 'x'); // returns [{ x: 1 }]
|
||||
*/
|
||||
export const intersectionBy = <T>(...args: [...arrays: T[][], iteratee: Iteratee<T>]): T[] => {
|
||||
if (args.length < 2) {
|
||||
throw new Error("intersectionBy requires at least two arrays and an iteratee");
|
||||
}
|
||||
|
||||
const iteratee = args[args.length - 1];
|
||||
const arrays = args.slice(0, -1) as T[][];
|
||||
|
||||
if (arrays.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const getIterateeValue = (item: T): unknown => {
|
||||
if (typeof iteratee === "function") {
|
||||
return (iteratee as (value: T) => any)(item);
|
||||
} else if (typeof iteratee === "string") {
|
||||
return (item as any)[iteratee];
|
||||
} else {
|
||||
throw new Error("Iteratee must be a function or a string key of the array elements");
|
||||
}
|
||||
};
|
||||
|
||||
const [first, ...rest] = arrays;
|
||||
const transformedFirst = first.map((item) => getIterateeValue(item));
|
||||
|
||||
const transformedSets: Set<unknown>[] = rest.map(
|
||||
(array) => new Set(array.map((item) => getIterateeValue(item))),
|
||||
);
|
||||
|
||||
const res: T[] = [];
|
||||
const seen = new Set<unknown>();
|
||||
|
||||
for (let i = 0; i < first.length; i++) {
|
||||
const item = first[i];
|
||||
const transformed = transformedFirst[i];
|
||||
|
||||
if (seen.has(transformed)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const existsInAll = transformedSets.every((set) => set.has(transformed));
|
||||
|
||||
if (existsInAll) {
|
||||
res.push(item);
|
||||
seen.add(transformed);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
493
pnpm-lock.yaml
generated
493
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user