├── docs ├── public │ ├── robots.txt │ ├── pug.jpg │ ├── favicon.ico │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── apple-touch-icon.png │ ├── android-chrome-192x192.png │ ├── android-chrome-512x512.png │ └── site.webmanifest ├── server │ └── tsconfig.json ├── app.config.ts ├── components │ ├── ui │ │ ├── separator │ │ │ ├── index.ts │ │ │ └── Separator.vue │ │ ├── scroll-area │ │ │ ├── index.ts │ │ │ ├── ScrollArea.vue │ │ │ └── ScrollBar.vue │ │ ├── collapsible │ │ │ ├── index.ts │ │ │ ├── CollapsibleTrigger.vue │ │ │ ├── CollapsibleContent.vue │ │ │ └── Collapsible.vue │ │ ├── tabs │ │ │ ├── index.ts │ │ │ ├── Tabs.vue │ │ │ ├── TabsList.vue │ │ │ ├── TabsContent.vue │ │ │ └── TabsTrigger.vue │ │ ├── tooltip │ │ │ ├── index.ts │ │ │ ├── TooltipTrigger.vue │ │ │ ├── TooltipProvider.vue │ │ │ └── Tooltip.vue │ │ ├── accordion │ │ │ ├── index.ts │ │ │ ├── Accordion.vue │ │ │ ├── AccordionItem.vue │ │ │ └── AccordionContent.vue │ │ ├── dialog │ │ │ ├── DialogClose.vue │ │ │ ├── DialogTrigger.vue │ │ │ ├── DialogHeader.vue │ │ │ ├── Dialog.vue │ │ │ ├── DialogFooter.vue │ │ │ ├── index.ts │ │ │ ├── DialogDescription.vue │ │ │ └── DialogTitle.vue │ │ ├── sheet │ │ │ ├── SheetClose.vue │ │ │ ├── SheetTrigger.vue │ │ │ ├── SheetHeader.vue │ │ │ ├── Sheet.vue │ │ │ ├── SheetFooter.vue │ │ │ ├── SheetTitle.vue │ │ │ └── SheetDescription.vue │ │ ├── navigation-menu │ │ │ ├── NavigationMenuItem.vue │ │ │ ├── NavigationMenuLink.vue │ │ │ ├── NavigationMenuList.vue │ │ │ ├── index.ts │ │ │ ├── NavigationMenuIndicator.vue │ │ │ ├── NavigationMenu.vue │ │ │ └── NavigationMenuTrigger.vue │ │ ├── breadcrumb │ │ │ ├── Breadcrumb.vue │ │ │ ├── BreadcrumbItem.vue │ │ │ ├── BreadcrumbList.vue │ │ │ ├── BreadcrumbPage.vue │ │ │ ├── index.ts │ │ │ ├── BreadcrumbSeparator.vue │ │ │ ├── BreadcrumbLink.vue │ │ │ └── BreadcrumbEllipsis.vue │ │ ├── card │ │ │ ├── CardContent.vue │ │ │ ├── CardFooter.vue │ │ │ ├── CardHeader.vue │ │ │ ├── index.ts │ │ │ ├── CardDescription.vue │ │ │ ├── CardTitle.vue │ │ │ └── Card.vue │ │ ├── alert │ │ │ ├── AlertDescription.vue │ │ │ ├── AlertTitle.vue │ │ │ ├── Alert.vue │ │ │ └── index.ts │ │ ├── drawer │ │ │ ├── DrawerFooter.vue │ │ │ ├── DrawerHeader.vue │ │ │ ├── index.ts │ │ │ ├── Drawer.vue │ │ │ ├── DrawerOverlay.vue │ │ │ ├── DrawerTitle.vue │ │ │ ├── DrawerDescription.vue │ │ │ └── DrawerContent.vue │ │ ├── command │ │ │ ├── CommandShortcut.vue │ │ │ ├── index.ts │ │ │ ├── CommandEmpty.vue │ │ │ ├── CommandSeparator.vue │ │ │ ├── Command.vue │ │ │ ├── CommandList.vue │ │ │ ├── CommandItem.vue │ │ │ ├── CommandDialog.vue │ │ │ ├── CommandGroup.vue │ │ │ └── CommandInput.vue │ │ └── badge │ │ │ ├── Badge.vue │ │ │ └── index.ts │ ├── content │ │ ├── ProseEm.vue │ │ ├── ProseHr.vue │ │ ├── ProseTbody.vue │ │ ├── LoadingData.vue │ │ ├── ProseLi.vue │ │ ├── ProseStrong.vue │ │ ├── ProseP.vue │ │ ├── FieldGroup.vue │ │ ├── ProseThead.vue │ │ ├── ProseTr.vue │ │ ├── CardGroup.vue │ │ ├── TeamCardGroup.vue │ │ ├── ProseBlockquote.vue │ │ ├── ProseTd.vue │ │ ├── ProseTh.vue │ │ ├── ProseUl.vue │ │ ├── ProseOl.vue │ │ ├── ProseTable.vue │ │ ├── Callout.vue │ │ ├── Stack.vue │ │ ├── ProseCodeInline.vue │ │ ├── ProseA.vue │ │ ├── Accordion.vue │ │ ├── CodeGroup.vue │ │ ├── Shortcut.vue │ │ ├── Kbd.vue │ │ ├── Steps.vue │ │ ├── Stackblitz.vue │ │ ├── ProseH1.vue │ │ ├── ProseH4.vue │ │ ├── ProseH5.vue │ │ ├── ProseH6.vue │ │ ├── PmX.vue │ │ ├── ProseH3.vue │ │ ├── PmRun.vue │ │ ├── ProseH2.vue │ │ ├── ReadMore.vue │ │ ├── AccordionItem.vue │ │ ├── PmInstall.vue │ │ ├── SmartIcon.vue │ │ ├── ButtonLink.vue │ │ ├── ProseImg.vue │ │ ├── ProsePre.vue │ │ └── Tabs.vue │ ├── layout │ │ ├── DocsFooter.vue │ │ ├── header │ │ │ ├── NavMobile.vue │ │ │ └── Logo.vue │ │ ├── PrevNext.vue │ │ ├── EditLink.vue │ │ ├── AsideTree.vue │ │ ├── AsideTreeItemButton.vue │ │ ├── Aside.vue │ │ └── Breadcrumb.vue │ └── demo │ │ ├── drag │ │ └── index.vue │ │ ├── hover │ │ └── index.vue │ │ ├── press │ │ └── index.vue │ │ ├── basic │ │ └── index.vue │ │ ├── use-spring │ │ └── index.vue │ │ ├── in-view │ │ └── index.vue │ │ ├── reorder-layout │ │ ├── array-utils.ts │ │ ├── AddIcon.vue │ │ └── ingredients.ts │ │ ├── drag-with-constraints │ │ └── index.vue │ │ ├── while-drag │ │ └── index.vue │ │ ├── keyframes │ │ └── index.vue │ │ ├── gestures │ │ └── index.vue │ │ ├── scroll-animate │ │ └── index.vue │ │ ├── use-animate │ │ └── index.vue │ │ ├── exit │ │ └── index.vue │ │ ├── html-content │ │ └── index.vue │ │ ├── shared-layout │ │ └── ingredients.ts │ │ ├── custom │ │ └── index.vue │ │ ├── reorder │ │ └── index.vue │ │ ├── variants │ │ └── index.vue │ │ ├── unwrap-element │ │ └── index.vue │ │ ├── layout-group │ │ └── ToggleContent.vue │ │ └── multiple │ │ └── index.vue ├── content │ ├── index.md │ ├── 5.hooks │ │ ├── _dir.yaml │ │ ├── 3.use-animate-frame.md │ │ └── 1.use-animate.md │ ├── 3.animation │ │ ├── _dir.yaml │ │ └── layout.md │ ├── 2.components │ │ ├── _dir.yaml │ │ └── 5.reorder.md │ ├── 1.getting-started │ │ ├── _dir.yml │ │ ├── 2.installation.md │ │ └── 1.introduction.md │ └── 4.motion-value │ │ ├── _dir.yaml │ │ ├── 2.use-motion-template.md │ │ ├── 7. use-velocity.md │ │ └── 6.use-transform.md ├── tsconfig.json ├── composables │ ├── useCollapsedMap.ts │ ├── useEditLink.ts │ └── useBreadcrumb.ts ├── lib │ ├── utils.ts │ └── motion.ts ├── .gitignore ├── components.json ├── pages │ └── index.vue └── README.md ├── playground ├── nuxt │ ├── public │ │ ├── robots.txt │ │ ├── pug.jpg │ │ └── favicon.ico │ ├── server │ │ └── tsconfig.json │ ├── pages │ │ ├── animate-variants │ │ │ └── Test.vue │ │ ├── child2.vue │ │ ├── use-test.ts │ │ ├── layout-id-tabs │ │ │ ├── array-utils.ts │ │ │ └── ingredients.ts │ │ ├── reorder-layout │ │ │ ├── array-utils.ts │ │ │ ├── AddIcon.vue │ │ │ └── ingredients.ts │ │ ├── motion-config │ │ │ └── index.vue │ │ ├── child.vue │ │ ├── number-counter │ │ │ └── AdditionIcon.vue │ │ ├── app-card │ │ │ └── card.ts │ │ ├── drag-to-reorder-lists │ │ │ └── index.vue │ │ ├── press.vue │ │ ├── animate-present-initial.vue │ │ ├── in-view.vue │ │ └── layout.vue │ ├── tsconfig.json │ ├── .gitignore │ ├── tailwind.config.js │ ├── components │ │ ├── sandbox │ │ │ └── content.vue │ │ └── sandbox.vue │ ├── assets │ │ └── css │ │ │ └── tailwind.css │ ├── package.json │ ├── nuxt.config.ts │ ├── MyTransition.vue │ └── demos │ │ ├── Animation.vue │ │ └── use-follow-pointer.ts └── vite │ ├── playwright.config.ts │ ├── src │ ├── views │ │ ├── Home.vue │ │ ├── dynamic-variant.vue │ │ └── [...404].vue │ ├── env.d.ts │ └── main.ts │ ├── postcss.config.js │ ├── tsconfig.node.json │ ├── vite.config.ts │ ├── index.html │ ├── package.json │ └── tsconfig.json ├── packages ├── motion │ ├── src │ │ ├── components │ │ │ ├── animate-presence │ │ │ │ ├── utils.ts │ │ │ │ ├── index.ts │ │ │ │ ├── types.ts │ │ │ │ └── use-presence.ts │ │ │ ├── reorder │ │ │ │ ├── types.ts │ │ │ │ ├── index.ts │ │ │ │ └── context.ts │ │ │ ├── motion-config │ │ │ │ ├── index.ts │ │ │ │ ├── context.ts │ │ │ │ └── types.ts │ │ │ ├── motion │ │ │ │ ├── m.ts │ │ │ │ ├── renderSlotFragments.ts │ │ │ │ └── index.ts │ │ │ ├── use-force-update.ts │ │ │ ├── index.ts │ │ │ ├── lazy-motion │ │ │ │ └── context.ts │ │ │ ├── LayoutGroup.vue │ │ │ ├── use-slot-change-index.ts │ │ │ ├── RowValue.vue │ │ │ ├── context.ts │ │ │ ├── __tests__ │ │ │ │ └── motion-config.test.tsx │ │ │ └── group.ts │ │ ├── state │ │ │ ├── index.ts │ │ │ ├── utils │ │ │ │ ├── is-variant-labels.ts │ │ │ │ └── is-present.ts │ │ │ ├── event.ts │ │ │ └── create-visual-element.ts │ │ ├── events │ │ │ ├── utils │ │ │ │ ├── index.ts │ │ │ │ └── is-primary-pointer.ts │ │ │ ├── types.ts │ │ │ ├── index.ts │ │ │ ├── add-dom-event.ts │ │ │ ├── add-pointer-event.ts │ │ │ └── event-info.ts │ │ ├── utils │ │ │ ├── is.ts │ │ │ ├── delay.ts │ │ │ ├── get-context-window.ts │ │ │ ├── index.ts │ │ │ ├── use-page-in-view.ts │ │ │ ├── use-dom-ref.ts │ │ │ └── use-animation-frame.ts │ │ ├── types │ │ │ ├── transform.ts │ │ │ ├── index.ts │ │ │ ├── common.ts │ │ │ └── framer-motion.ts │ │ ├── shared │ │ │ └── test.ts │ │ ├── vite-env.d.ts │ │ ├── features │ │ │ ├── gestures │ │ │ │ ├── index.ts │ │ │ │ ├── drag │ │ │ │ │ ├── utils │ │ │ │ │ │ └── is.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── pan │ │ │ │ │ └── types.ts │ │ │ │ ├── focus │ │ │ │ │ └── types.ts │ │ │ │ ├── hover │ │ │ │ │ └── types.ts │ │ │ │ ├── types.ts │ │ │ │ ├── press │ │ │ │ │ └── types.ts │ │ │ │ └── in-view │ │ │ │ │ └── types.ts │ │ │ ├── index.ts │ │ │ ├── feature.ts │ │ │ ├── layout │ │ │ │ ├── utils.ts │ │ │ │ ├── config.ts │ │ │ │ └── types.ts │ │ │ ├── animation │ │ │ │ ├── types.ts │ │ │ │ └── calc-child-stagger.ts │ │ │ ├── dom-animation.ts │ │ │ └── dom-max.ts │ │ ├── animation │ │ │ ├── index.ts │ │ │ ├── utils.ts │ │ │ └── hooks │ │ │ │ └── use-reduced-motion.ts │ │ ├── projection │ │ │ ├── geometry │ │ │ │ ├── delta-calc.ts │ │ │ │ ├── delta-apply.ts │ │ │ │ └── models.ts │ │ │ ├── utils │ │ │ │ ├── each-axis.ts │ │ │ │ └── measure.ts │ │ │ └── node │ │ │ │ └── types.ts │ │ ├── value │ │ │ ├── use-will-change │ │ │ │ ├── types.ts │ │ │ │ ├── is.ts │ │ │ │ └── add-will-change.ts │ │ │ ├── use-time.ts │ │ │ ├── index.ts │ │ │ ├── use-motion-value-event.ts │ │ │ ├── use-computed.ts │ │ │ ├── __tests__ │ │ │ │ └── use-transform.test.tsx │ │ │ └── use-velocity.ts │ │ ├── global.d.ts │ │ └── index.ts │ └── tsconfig.json └── plugins │ ├── package.json │ ├── src │ └── resolver │ │ └── index.ts │ ├── build.config.ts │ └── tsconfig.json ├── commitlint.config.js ├── pnpm-workspace.yaml ├── .github ├── FUNDING.yml ├── workflows │ └── release.yaml └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── tsconfig.json ├── playwright.config.ts ├── tests └── animate-presence.spec.ts ├── .gitignore └── LICENSE /docs/public/robots.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /playground/nuxt/public/robots.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /playground/vite/playwright.config.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /playground/vite/src/views/Home.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/motion/src/components/animate-presence/utils.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/motion/src/state/index.ts: -------------------------------------------------------------------------------- 1 | export * from './motion-state' 2 | -------------------------------------------------------------------------------- /packages/motion/src/events/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './is-primary-pointer' 2 | -------------------------------------------------------------------------------- /docs/server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../.nuxt/tsconfig.server.json" 3 | } 4 | -------------------------------------------------------------------------------- /packages/motion/src/utils/is.ts: -------------------------------------------------------------------------------- 1 | export const isSSR = typeof window === 'undefined' 2 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { extends: ['@commitlint/config-conventional'] }; 2 | -------------------------------------------------------------------------------- /docs/app.config.ts: -------------------------------------------------------------------------------- 1 | export default defineAppConfig({ 2 | docs: { 3 | 4 | }, 5 | }) 6 | -------------------------------------------------------------------------------- /docs/components/ui/separator/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Separator } from './Separator.vue' 2 | -------------------------------------------------------------------------------- /playground/nuxt/server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../.nuxt/tsconfig.server.json" 3 | } 4 | -------------------------------------------------------------------------------- /docs/public/pug.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motiondivision/motion-vue/HEAD/docs/public/pug.jpg -------------------------------------------------------------------------------- /packages/motion/src/types/transform.ts: -------------------------------------------------------------------------------- 1 | export type { TransformOptions } from 'framer-motion/dom' 2 | -------------------------------------------------------------------------------- /docs/components/content/ProseEm.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /docs/content/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Motion Vue 3 | navigation: false 4 | --- 5 | 6 | 7 | -------------------------------------------------------------------------------- /docs/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motiondivision/motion-vue/HEAD/docs/public/favicon.ico -------------------------------------------------------------------------------- /docs/components/content/ProseHr.vue: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /packages/motion/src/shared/test.ts: -------------------------------------------------------------------------------- 1 | export const delay = (ms: number) => new Promise(r => setTimeout(r, ms)) 2 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - 'packages/*' 3 | - 'playground/*' 4 | - 'docs' 5 | - 'new-docs' 6 | -------------------------------------------------------------------------------- /docs/components/content/ProseTbody.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /docs/public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motiondivision/motion-vue/HEAD/docs/public/favicon-16x16.png -------------------------------------------------------------------------------- /docs/public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motiondivision/motion-vue/HEAD/docs/public/favicon-32x32.png -------------------------------------------------------------------------------- /playground/nuxt/public/pug.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motiondivision/motion-vue/HEAD/playground/nuxt/public/pug.jpg -------------------------------------------------------------------------------- /docs/components/content/LoadingData.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | -------------------------------------------------------------------------------- /docs/content/5.hooks/_dir.yaml: -------------------------------------------------------------------------------- 1 | title: Hooks 2 | navigation.icon: 'lucide:hammer' 3 | navigation.redirect: /hooks/use-animate 4 | -------------------------------------------------------------------------------- /docs/public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motiondivision/motion-vue/HEAD/docs/public/apple-touch-icon.png -------------------------------------------------------------------------------- /docs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // https://nuxt.com/docs/guide/concepts/typescript 3 | "extends": "./.nuxt/tsconfig.json" 4 | } 5 | -------------------------------------------------------------------------------- /packages/motion/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /docs/content/3.animation/_dir.yaml: -------------------------------------------------------------------------------- 1 | title: Animation 2 | navigation.icon: 'lucide:move' 3 | navigation.redirect: /animation/layout 4 | -------------------------------------------------------------------------------- /playground/nuxt/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motiondivision/motion-vue/HEAD/playground/nuxt/public/favicon.ico -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [rick-hup] 4 | custom: ["https://motion.dev/plus"] 5 | -------------------------------------------------------------------------------- /docs/public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motiondivision/motion-vue/HEAD/docs/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /docs/public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motiondivision/motion-vue/HEAD/docs/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /playground/vite/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /docs/components/content/ProseLi.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /docs/components/content/ProseStrong.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /docs/content/2.components/_dir.yaml: -------------------------------------------------------------------------------- 1 | title: Components 2 | navigation.icon: 'lucide:component' 3 | navigation.redirect: /components/motion 4 | -------------------------------------------------------------------------------- /docs/components/content/ProseP.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /packages/motion/src/utils/delay.ts: -------------------------------------------------------------------------------- 1 | export function delay(fn: () => void) { 2 | return Promise.resolve().then(() => { 3 | fn() 4 | }) 5 | } 6 | -------------------------------------------------------------------------------- /docs/components/content/FieldGroup.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /docs/components/content/ProseThead.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /docs/content/1.getting-started/_dir.yml: -------------------------------------------------------------------------------- 1 | title: Getting started 2 | navigation.icon: 'lucide:rocket' 3 | navigation.redirect: /getting-started/introduction 4 | -------------------------------------------------------------------------------- /docs/content/4.motion-value/_dir.yaml: -------------------------------------------------------------------------------- 1 | title: Motion Value 2 | navigation.icon: 'lucide:grab' 3 | navigation.redirect: /motion-value/use-motion-value-event 4 | -------------------------------------------------------------------------------- /docs/components/content/ProseTr.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /docs/components/layout/DocsFooter.vue: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /docs/components/ui/scroll-area/index.ts: -------------------------------------------------------------------------------- 1 | export { default as ScrollArea } from './ScrollArea.vue' 2 | export { default as ScrollBar } from './ScrollBar.vue' 3 | -------------------------------------------------------------------------------- /packages/motion/src/features/gestures/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hover' 2 | export * from './press' 3 | export * from './in-view' 4 | export * from './drag' 5 | -------------------------------------------------------------------------------- /docs/composables/useCollapsedMap.ts: -------------------------------------------------------------------------------- 1 | export function useCollapsedMap() { 2 | return useState>('docs-collapsed-map', () => new Map()) 3 | } 4 | -------------------------------------------------------------------------------- /packages/motion/src/events/types.ts: -------------------------------------------------------------------------------- 1 | import type { Point } from 'framer-motion' 2 | 3 | /** @public */ 4 | export interface EventInfo { 5 | point: Point 6 | } 7 | -------------------------------------------------------------------------------- /packages/motion/src/components/reorder/types.ts: -------------------------------------------------------------------------------- 1 | import type { Axis } from 'framer-motion' 2 | 3 | export interface ItemData { 4 | value: T 5 | layout: Axis 6 | } 7 | -------------------------------------------------------------------------------- /docs/components/content/CardGroup.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /packages/motion/src/animation/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hooks/use-animate' 2 | export * from './hooks/use-animation-controls' 3 | export * from './hooks/use-reduced-motion' 4 | -------------------------------------------------------------------------------- /docs/components/content/TeamCardGroup.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /packages/motion/src/components/animate-presence/index.ts: -------------------------------------------------------------------------------- 1 | export { default as AnimatePresence } from './AnimatePresence.vue' 2 | export type { AnimatePresenceProps } from './types' 3 | -------------------------------------------------------------------------------- /docs/components/content/ProseBlockquote.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /packages/motion/src/components/motion-config/index.ts: -------------------------------------------------------------------------------- 1 | export { default as MotionConfig } from './MotionConfig.vue' 2 | export { provideMotionConfig, useMotionConfig } from './context' 3 | -------------------------------------------------------------------------------- /packages/motion/src/projection/geometry/delta-calc.ts: -------------------------------------------------------------------------------- 1 | import type { Axis } from 'framer-motion' 2 | 3 | export function calcLength(axis: Axis) { 4 | return axis.max - axis.min 5 | } 6 | -------------------------------------------------------------------------------- /packages/motion/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from './transform' 2 | export * from './framer-motion' 3 | export * from './motion-values' 4 | export * from './state' 5 | export * from './common' 6 | -------------------------------------------------------------------------------- /docs/components/content/ProseTd.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /packages/motion/src/events/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types' 2 | export * from './utils' 3 | export * from './add-pointer-event' 4 | export * from './event-info' 5 | export * from './add-dom-event' 6 | -------------------------------------------------------------------------------- /packages/motion/src/projection/utils/each-axis.ts: -------------------------------------------------------------------------------- 1 | type Callback = (axis: 'x' | 'y') => void 2 | 3 | export function eachAxis(callback: Callback) { 4 | return [callback('x'), callback('y')] 5 | } 6 | -------------------------------------------------------------------------------- /packages/motion/src/value/use-will-change/types.ts: -------------------------------------------------------------------------------- 1 | import type { MotionValue } from 'framer-motion' 2 | 3 | export interface WillChange extends MotionValue { 4 | add: (name: string) => void 5 | } 6 | -------------------------------------------------------------------------------- /playground/nuxt/pages/animate-variants/Test.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | -------------------------------------------------------------------------------- /docs/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { type ClassValue, clsx } from 'clsx' 2 | import { twMerge } from 'tailwind-merge' 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)) 6 | } 7 | -------------------------------------------------------------------------------- /docs/components/content/ProseTh.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /docs/components/content/ProseUl.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /packages/motion/src/features/gestures/drag/utils/is.ts: -------------------------------------------------------------------------------- 1 | export function isHTMLElement(value: any): value is HTMLElement { 2 | return typeof value === 'object' && value !== null && 'nodeType' in value 3 | } 4 | -------------------------------------------------------------------------------- /docs/components/content/ProseOl.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /playground/nuxt/pages/child2.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 11 | 12 | 15 | -------------------------------------------------------------------------------- /docs/components/content/ProseTable.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /playground/vite/src/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | declare module '*.vue' { 4 | import type { DefineComponent } from 'vue' 5 | 6 | const component: DefineComponent<{}, {}, any> 7 | export default component 8 | } 9 | -------------------------------------------------------------------------------- /docs/content/4.motion-value/2.use-motion-template.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: useMotionTemplate 3 | description: 4 | navigation.icon: 'lucide:rotate-3d' 5 | --- 6 | 7 | - [Motion React-useMotionTemplate](https://motion.dev/docs/react-use-motion-template) 8 | -------------------------------------------------------------------------------- /packages/motion/src/projection/geometry/delta-apply.ts: -------------------------------------------------------------------------------- 1 | import type { Axis } from 'framer-motion' 2 | 3 | export function translateAxis(axis: Axis, distance: number) { 4 | axis.min = axis.min + distance 5 | axis.max = axis.max + distance 6 | } 7 | -------------------------------------------------------------------------------- /packages/motion/src/utils/get-context-window.ts: -------------------------------------------------------------------------------- 1 | import type { VisualElement } from 'framer-motion' 2 | 3 | export function getContextWindow({ current }: VisualElement) { 4 | return current ? current.ownerDocument.defaultView : null 5 | } 6 | -------------------------------------------------------------------------------- /playground/vite/src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import { router } from './router' 3 | import App from './App.vue' 4 | 5 | import './style.css' 6 | 7 | const app = createApp(App) 8 | app.use(router) 9 | app.mount('#app') 10 | -------------------------------------------------------------------------------- /docs/components/ui/collapsible/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Collapsible } from './Collapsible.vue' 2 | export { default as CollapsibleContent } from './CollapsibleContent.vue' 3 | export { default as CollapsibleTrigger } from './CollapsibleTrigger.vue' 4 | -------------------------------------------------------------------------------- /packages/motion/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './createContext' 2 | export * from './use-in-view' 3 | export * from './use-animation-frame' 4 | export * from './get-context-window' 5 | export * from './use-dom-ref' 6 | export * from './use-page-in-view' 7 | -------------------------------------------------------------------------------- /docs/components/demo/drag/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 11 | -------------------------------------------------------------------------------- /docs/components/ui/tabs/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Tabs } from './Tabs.vue' 2 | export { default as TabsContent } from './TabsContent.vue' 3 | export { default as TabsList } from './TabsList.vue' 4 | export { default as TabsTrigger } from './TabsTrigger.vue' 5 | -------------------------------------------------------------------------------- /packages/motion/src/components/reorder/index.ts: -------------------------------------------------------------------------------- 1 | import Group from './Group.vue' 2 | import Item from './Item.vue' 3 | 4 | export const ReorderGroup = Group 5 | export const ReorderItem = Item 6 | export const Reorder = { 7 | Group, 8 | Item, 9 | } 10 | -------------------------------------------------------------------------------- /packages/motion/src/state/utils/is-variant-labels.ts: -------------------------------------------------------------------------------- 1 | import type { VariantLabels } from 'motion-dom' 2 | 3 | export function isVariantLabels(value: any): value is VariantLabels { 4 | return typeof value === 'string' || value === false || Array.isArray(value) 5 | } 6 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@vue/tsconfig/tsconfig.dom.json", 3 | "compilerOptions": { 4 | "composite": true, 5 | "baseUrl": ".", 6 | "types": ["node"] 7 | }, 8 | "include": ["./packages/**/*"], 9 | "exclude": ["node_modules"] 10 | } 11 | -------------------------------------------------------------------------------- /playground/nuxt/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // https://nuxt.com/docs/guide/concepts/typescript 3 | "extends": "./.nuxt/tsconfig.json", 4 | "compilerOptions": { 5 | "target": "ESNext", 6 | "module": "ESNext", 7 | "moduleResolution": "Node" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /docs/public/site.webmanifest: -------------------------------------------------------------------------------- 1 | {"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} -------------------------------------------------------------------------------- /packages/motion/src/global.d.ts: -------------------------------------------------------------------------------- 1 | import type { visualElementStore } from 'framer-motion' 2 | 3 | type VisualElementStore = typeof visualElementStore 4 | // @ts-ignore 5 | declare module 'framer-motion/dist/es/render/store.mjs' { 6 | export const visualElementStore: VisualElementStore 7 | } 8 | -------------------------------------------------------------------------------- /packages/motion/src/value/use-time.ts: -------------------------------------------------------------------------------- 1 | import { useAnimationFrame } from '@/utils/use-animation-frame' 2 | import { motionValue } from 'framer-motion/dom' 3 | 4 | export function useTime() { 5 | const time = motionValue(0) 6 | useAnimationFrame(t => time.set(t)) 7 | return time 8 | } 9 | -------------------------------------------------------------------------------- /playground/vite/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "ESNext", 5 | "moduleResolution": "bundler", 6 | "allowSyntheticDefaultImports": true, 7 | "skipLibCheck": true 8 | }, 9 | "include": ["vite.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /docs/components/ui/tooltip/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Tooltip } from './Tooltip.vue' 2 | export { default as TooltipContent } from './TooltipContent.vue' 3 | export { default as TooltipProvider } from './TooltipProvider.vue' 4 | export { default as TooltipTrigger } from './TooltipTrigger.vue' 5 | -------------------------------------------------------------------------------- /packages/motion/src/projection/geometry/models.ts: -------------------------------------------------------------------------------- 1 | import type { Axis, Box } from 'framer-motion' 2 | 3 | export const createAxis = (): Axis => ({ min: 0, max: 0 }) 4 | 5 | export function createBox(): Box { 6 | return { 7 | x: createAxis(), 8 | y: createAxis(), 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /docs/components/ui/accordion/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Accordion } from './Accordion.vue' 2 | export { default as AccordionContent } from './AccordionContent.vue' 3 | export { default as AccordionItem } from './AccordionItem.vue' 4 | export { default as AccordionTrigger } from './AccordionTrigger.vue' 5 | -------------------------------------------------------------------------------- /packages/motion/src/features/index.ts: -------------------------------------------------------------------------------- 1 | export * from './feature' 2 | export * from './gestures' 3 | export * from './layout/layout' 4 | export * from './gestures/pan' 5 | export * from './feature-manager' 6 | export * from './animation/animation' 7 | export * from './dom-max' 8 | export * from './dom-animation' 9 | -------------------------------------------------------------------------------- /packages/motion/src/state/utils/is-present.ts: -------------------------------------------------------------------------------- 1 | import { doneCallbacks } from '@/components/animate-presence/presence' 2 | import type { VisualElement } from 'framer-motion' 3 | 4 | export function isPresent(visualElement: VisualElement) { 5 | return !doneCallbacks.has(visualElement.current as Element) 6 | } 7 | -------------------------------------------------------------------------------- /packages/motion/src/components/motion/m.ts: -------------------------------------------------------------------------------- 1 | import type { MotionComponent } from '@/components/motion/types' 2 | import { createMotionComponentWithFeatures } from '@/components/motion/utils' 3 | 4 | export const m = createMotionComponentWithFeatures() 5 | export const M = m.create('div') as unknown as MotionComponent 6 | -------------------------------------------------------------------------------- /docs/components/ui/dialog/DialogClose.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /docs/components/ui/sheet/SheetClose.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /packages/motion/src/components/use-force-update.ts: -------------------------------------------------------------------------------- 1 | import type { Ref } from 'vue' 2 | import { ref } from 'vue' 3 | 4 | export function useForceUpdate(): [() => void, Ref] { 5 | const key = ref(0) 6 | function forceUpdate() { 7 | key.value++ 8 | } 9 | 10 | return [forceUpdate, key] 11 | } 12 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | # Nuxt dev/build outputs 2 | .output 3 | .data 4 | .nuxt 5 | .nitro 6 | .cache 7 | dist 8 | 9 | # Node dependencies 10 | node_modules 11 | 12 | # Logs 13 | logs 14 | *.log 15 | 16 | # Misc 17 | .DS_Store 18 | .fleet 19 | .idea 20 | 21 | # Local env files 22 | .env 23 | .env.* 24 | !.env.example 25 | -------------------------------------------------------------------------------- /packages/motion/src/animation/utils.ts: -------------------------------------------------------------------------------- 1 | import type { AnimationControls } from './types' 2 | 3 | export function isAnimationControls(v?: unknown): v is AnimationControls { 4 | return ( 5 | v !== null 6 | && typeof v === 'object' 7 | && typeof (v as AnimationControls).start === 'function' 8 | ) 9 | } 10 | -------------------------------------------------------------------------------- /docs/components/ui/sheet/SheetTrigger.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /docs/components/content/Callout.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 18 | -------------------------------------------------------------------------------- /docs/components/ui/dialog/DialogTrigger.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /playground/nuxt/.gitignore: -------------------------------------------------------------------------------- 1 | # Nuxt dev/build outputs 2 | .output 3 | .data 4 | .nuxt 5 | .nitro 6 | .cache 7 | dist 8 | 9 | # Node dependencies 10 | node_modules 11 | 12 | # Logs 13 | logs 14 | *.log 15 | 16 | # Misc 17 | .DS_Store 18 | .fleet 19 | .idea 20 | 21 | # Local env files 22 | .env 23 | .env.* 24 | !.env.example 25 | -------------------------------------------------------------------------------- /docs/components/ui/tooltip/TooltipTrigger.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /packages/motion/src/value/use-will-change/is.ts: -------------------------------------------------------------------------------- 1 | import type { WillChange } from '@/value/use-will-change/types' 2 | import { isMotionValue } from 'framer-motion/dom' 3 | 4 | export function isWillChangeMotionValue(value: any): value is WillChange { 5 | return Boolean(isMotionValue(value) && ((value as unknown) as WillChange).add) 6 | } 7 | -------------------------------------------------------------------------------- /docs/components/layout/header/NavMobile.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 15 | -------------------------------------------------------------------------------- /docs/components/ui/tooltip/TooltipProvider.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /packages/motion/src/state/event.ts: -------------------------------------------------------------------------------- 1 | import type { VariantType } from '@/types' 2 | 3 | export type MotionEventNames = 4 | | 'motionstart' 5 | | 'motioncomplete' 6 | 7 | export function motionEvent(name: MotionEventNames, target: VariantType, isExit?: boolean) { 8 | return new CustomEvent(name, { detail: { target, isExit } }) 9 | } 10 | -------------------------------------------------------------------------------- /docs/components/content/Stack.vue: -------------------------------------------------------------------------------- 1 | 14 | -------------------------------------------------------------------------------- /packages/motion/src/events/add-dom-event.ts: -------------------------------------------------------------------------------- 1 | export function addDomEvent( 2 | target: EventTarget, 3 | eventName: string, 4 | handler: EventListener, 5 | options: AddEventListenerOptions = { passive: true }, 6 | ) { 7 | target.addEventListener(eventName, handler, options) 8 | 9 | return () => target.removeEventListener(eventName, handler) 10 | } 11 | -------------------------------------------------------------------------------- /playground/vite/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | import jsx from '@vitejs/plugin-vue-jsx' 4 | 5 | export default defineConfig({ 6 | plugins: [vue(), jsx()], 7 | server: { 8 | port: 5173, 9 | }, 10 | resolve: { 11 | alias: { 12 | '@': '/src', 13 | }, 14 | }, 15 | }) 16 | -------------------------------------------------------------------------------- /docs/components/ui/collapsible/CollapsibleTrigger.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /docs/components/ui/navigation-menu/NavigationMenuItem.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /docs/lib/motion.ts: -------------------------------------------------------------------------------- 1 | import type { MotionProps } from 'motion-v' 2 | 3 | export const slideUp: Partial> = { 4 | variants: { 5 | hidden: { opacity: 0, y: 30, rotate: 3 }, 6 | visible: { opacity: 1, y: 0, rotate: 0 }, 7 | }, 8 | transition: { 9 | type: 'spring', 10 | stiffness: 260, 11 | damping: 50, 12 | }, 13 | } 14 | -------------------------------------------------------------------------------- /packages/motion/src/components/animate-presence/types.ts: -------------------------------------------------------------------------------- 1 | export interface AnimatePresenceProps { 2 | // 动画模式: wait(等待前一个完成), popLayout(弹出布局), sync(同步) 3 | mode?: 'wait' 4 | | 'popLayout' 5 | | 'sync' 6 | // 是否显示初始动画 7 | initial?: boolean 8 | as?: string 9 | custom?: any 10 | onExitComplete?: VoidFunction 11 | anchorX?: 'left' | 'right' 12 | } 13 | -------------------------------------------------------------------------------- /packages/motion/src/components/index.ts: -------------------------------------------------------------------------------- 1 | export { Motion, motion, type MotionProps } from './motion' 2 | export * from './animate-presence' 3 | export * from './motion-config' 4 | export * from './reorder' 5 | export { default as RowValue } from './RowValue.vue' 6 | export * from './lazy-motion' 7 | export * from './motion/m' 8 | export { mountedStates } from '@/state' 9 | -------------------------------------------------------------------------------- /packages/motion/src/value/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-computed' 2 | export * from './use-combine-values' 3 | export * from './use-transform' 4 | export * from './use-time' 5 | export * from './use-motion-template' 6 | export * from './use-motion-value-event' 7 | export * from './use-spring' 8 | export * from './use-scroll' 9 | export * from './use-velocity' 10 | -------------------------------------------------------------------------------- /docs/components/ui/breadcrumb/Breadcrumb.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 17 | -------------------------------------------------------------------------------- /docs/components/ui/card/CardContent.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 15 | -------------------------------------------------------------------------------- /docs/components/ui/card/CardFooter.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 15 | -------------------------------------------------------------------------------- /docs/components/ui/card/CardHeader.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 15 | -------------------------------------------------------------------------------- /docs/components/ui/card/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Card } from './Card.vue' 2 | export { default as CardContent } from './CardContent.vue' 3 | export { default as CardDescription } from './CardDescription.vue' 4 | export { default as CardFooter } from './CardFooter.vue' 5 | export { default as CardHeader } from './CardHeader.vue' 6 | export { default as CardTitle } from './CardTitle.vue' 7 | -------------------------------------------------------------------------------- /docs/components/demo/hover/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 15 | -------------------------------------------------------------------------------- /docs/components/ui/card/CardDescription.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 15 | -------------------------------------------------------------------------------- /docs/components/ui/alert/AlertDescription.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 15 | -------------------------------------------------------------------------------- /docs/components/ui/alert/AlertTitle.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 15 | -------------------------------------------------------------------------------- /docs/components/ui/drawer/DrawerFooter.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 15 | -------------------------------------------------------------------------------- /docs/components/ui/drawer/DrawerHeader.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 15 | -------------------------------------------------------------------------------- /docs/content/1.getting-started/2.installation.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Installation 3 | description: How to install motion-v in your app. 4 | navigation.icon: 'lucide:play' 5 | --- 6 | 7 | ### Installation 8 | 9 | :pm-install{name="motion-v"} 10 | 11 | ### Nuxt Module 12 | 13 | ```ts 14 | export default defineNuxtConfig({ 15 | modules: [ 16 | // ... 17 | 'motion-v/nuxt', 18 | ], 19 | }) 20 | ``` 21 | -------------------------------------------------------------------------------- /packages/motion/src/components/motion/renderSlotFragments.ts: -------------------------------------------------------------------------------- 1 | import { Fragment, type VNode } from 'vue' 2 | 3 | export function renderSlotFragments(children?: VNode[]): VNode[] { 4 | if (!children) 5 | return [] 6 | return children.flatMap((child) => { 7 | if (child.type === Fragment) 8 | return renderSlotFragments(child.children as VNode[]) 9 | 10 | return [child] 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /packages/motion/src/events/add-pointer-event.ts: -------------------------------------------------------------------------------- 1 | import { type EventListenerWithPointInfo, addDomEvent, addPointerInfo } from '@/events' 2 | 3 | export function addPointerEvent( 4 | target: EventTarget, 5 | eventName: string, 6 | handler: EventListenerWithPointInfo, 7 | options?: AddEventListenerOptions, 8 | ) { 9 | return addDomEvent(target, eventName, addPointerInfo(handler), options) 10 | } 11 | -------------------------------------------------------------------------------- /packages/motion/src/features/gestures/pan/types.ts: -------------------------------------------------------------------------------- 1 | import type { PanInfo } from '@/features/gestures/pan/PanSession' 2 | 3 | export interface PanProps { 4 | onPanSessionStart?: (event: PointerEvent, info: PanInfo) => void 5 | onPanStart?: (event: PointerEvent, info: PanInfo) => void 6 | onPan?: (event: PointerEvent, info: PanInfo) => void 7 | onPanEnd?: (event: PointerEvent, info: PanInfo) => void 8 | } 9 | -------------------------------------------------------------------------------- /docs/components/ui/breadcrumb/BreadcrumbItem.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 17 | -------------------------------------------------------------------------------- /packages/motion/src/components/lazy-motion/context.ts: -------------------------------------------------------------------------------- 1 | import type { Feature } from '@/features' 2 | import { createContext } from '@/utils' 3 | import type { Ref } from 'vue' 4 | 5 | export type LazyMotionContext = { 6 | features: Ref> 7 | strict: boolean 8 | } 9 | export const [useLazyMotionContext, lazyMotionContextProvider] = createContext('LazyMotionContext') 10 | -------------------------------------------------------------------------------- /packages/motion/src/components/motion/index.ts: -------------------------------------------------------------------------------- 1 | export { type MotionProps } from './types' 2 | import type { MotionComponent } from '@/components/motion/types' 3 | import { createMotionComponentWithFeatures } from './utils' 4 | import { domMax } from '@/features/dom-max' 5 | 6 | export const motion = createMotionComponentWithFeatures(domMax) 7 | export const Motion = motion.create('div') as unknown as MotionComponent 8 | -------------------------------------------------------------------------------- /docs/components/ui/command/CommandShortcut.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 15 | -------------------------------------------------------------------------------- /playground/nuxt/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: [ 4 | './components/**/*.{js,vue,ts}', 5 | './demos/**/*.{js,vue,ts}', 6 | './layouts/**/*.vue', 7 | './pages/**/*.vue', 8 | './plugins/**/*.{js,ts}', 9 | './app.vue', 10 | './error.vue', 11 | ], 12 | theme: { 13 | extend: {}, 14 | }, 15 | plugins: [], 16 | } 17 | -------------------------------------------------------------------------------- /docs/components/content/ProseCodeInline.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | -------------------------------------------------------------------------------- /docs/components/ui/dialog/DialogHeader.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 17 | -------------------------------------------------------------------------------- /docs/components/demo/press/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 16 | -------------------------------------------------------------------------------- /docs/components/ui/card/CardTitle.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 19 | -------------------------------------------------------------------------------- /docs/components/ui/sheet/SheetHeader.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 17 | -------------------------------------------------------------------------------- /docs/components/demo/basic/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 18 | -------------------------------------------------------------------------------- /packages/motion/src/features/feature.ts: -------------------------------------------------------------------------------- 1 | import type { MotionState } from '@/state/motion-state' 2 | 3 | export class Feature { 4 | state: MotionState 5 | 6 | constructor(state: MotionState) { 7 | this.state = state 8 | } 9 | 10 | beforeMount(): void {} 11 | 12 | mount(): void {} 13 | 14 | unmount(): void {} 15 | 16 | update?(): void {} 17 | 18 | beforeUpdate?(): void {} 19 | 20 | beforeUnmount?(): void {} 21 | } 22 | -------------------------------------------------------------------------------- /playground/vite/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Motion Vue Playground 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /playground/vite/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@motion-vue/playground-vite", 3 | "type": "module", 4 | "version": "0.0.0", 5 | "private": true, 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vue-tsc && vite build", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "motion-plus-vue": "0.1.0", 13 | "motion-v": "workspace:*", 14 | "vue": "^3.4.0", 15 | "vue-router": "^4.5.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/motion/src/components/LayoutGroup.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 16 | -------------------------------------------------------------------------------- /playground/nuxt/pages/use-test.ts: -------------------------------------------------------------------------------- 1 | import { type Slot, computed, useSlots } from 'vue' 2 | 3 | export function useSlotChangeIndex() { 4 | let prevSlots: ReturnType> | undefined 5 | let index = 0 6 | const slots = useSlots() 7 | return computed(() => { 8 | const newSlots = slots.default?.() 9 | if (prevSlots !== newSlots) { 10 | index++ 11 | prevSlots = newSlots 12 | } 13 | return index 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /docs/components/ui/sheet/Sheet.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 15 | -------------------------------------------------------------------------------- /docs/components/ui/breadcrumb/BreadcrumbList.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 17 | -------------------------------------------------------------------------------- /docs/components/ui/dialog/Dialog.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 15 | -------------------------------------------------------------------------------- /docs/components/ui/tabs/Tabs.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 16 | -------------------------------------------------------------------------------- /docs/components/ui/tooltip/Tooltip.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 15 | -------------------------------------------------------------------------------- /packages/motion/src/animation/hooks/use-reduced-motion.ts: -------------------------------------------------------------------------------- 1 | import { computed } from 'vue' 2 | import type { Ref } from 'vue' 3 | import { useMediaQuery } from '@vueuse/core' 4 | 5 | /** 6 | * Reactive prefers-reduced-motion. 7 | */ 8 | export function useReducedMotion(options: { window?: Window } = {}): Ref { 9 | const reducedMotion = useMediaQuery('(prefers-reduced-motion: reduce)', options) 10 | 11 | return computed(() => reducedMotion.value) 12 | } 13 | -------------------------------------------------------------------------------- /docs/components/content/ProseA.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 23 | -------------------------------------------------------------------------------- /docs/components/ui/badge/Badge.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 17 | -------------------------------------------------------------------------------- /docs/components/ui/card/Card.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 22 | -------------------------------------------------------------------------------- /docs/components/ui/sheet/SheetFooter.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 20 | -------------------------------------------------------------------------------- /packages/motion/src/components/use-slot-change-index.ts: -------------------------------------------------------------------------------- 1 | import { type Slot, computed, useSlots } from 'vue' 2 | 3 | export function useSlotChangeIndex() { 4 | let prevSlots: ReturnType> | undefined 5 | let index = 0 6 | const slots = useSlots() 7 | return computed(() => { 8 | const newSlots = slots.default?.() 9 | if (prevSlots !== newSlots) { 10 | index++ 11 | prevSlots = newSlots 12 | } 13 | return index 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /docs/components/ui/dialog/DialogFooter.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 20 | -------------------------------------------------------------------------------- /docs/components/content/Accordion.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 19 | -------------------------------------------------------------------------------- /docs/components/demo/use-spring/index.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 20 | -------------------------------------------------------------------------------- /docs/components/ui/breadcrumb/BreadcrumbPage.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 20 | -------------------------------------------------------------------------------- /docs/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://shadcn-vue.com/schema.json", 3 | "style": "new-york", 4 | "typescript": true, 5 | "tsConfigPath": ".nuxt/tsconfig.json", 6 | "tailwind": { 7 | "config": "tailwind.config.js", 8 | "css": "assets/css/tailwind.css", 9 | "baseColor": "slate", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "framework": "nuxt", 14 | "aliases": { 15 | "components": "@/components", 16 | "utils": "@/lib/utils" 17 | } 18 | } -------------------------------------------------------------------------------- /packages/motion/src/projection/node/types.ts: -------------------------------------------------------------------------------- 1 | import type { Box, Delta, ResolvedValues } from 'framer-motion' 2 | 3 | export interface Measurements { 4 | animationId: number 5 | measuredBox: Box 6 | layoutBox: Box 7 | latestValues: ResolvedValues 8 | source: number 9 | } 10 | export interface LayoutUpdateData { 11 | layout: Box 12 | snapshot: Measurements 13 | delta: Delta 14 | layoutDelta: Delta 15 | hasLayoutChanged: boolean 16 | hasRelativeTargetChanged: boolean 17 | } 18 | -------------------------------------------------------------------------------- /packages/motion/src/components/reorder/context.ts: -------------------------------------------------------------------------------- 1 | import { createContext } from '@/utils' 2 | import type { Box } from 'framer-motion' 3 | import type { Ref } from 'vue' 4 | 5 | export interface ReorderContextProps { 6 | axis?: Ref<'x' | 'y'> 7 | registerItem?: (item: T, layout: Box) => void 8 | updateOrder?: (item: T, offset: number, velocity: number) => void 9 | } 10 | 11 | export const [useReorderContext, reorderContextProvider] = createContext>('ReorderContext') 12 | -------------------------------------------------------------------------------- /packages/motion/src/features/gestures/focus/types.ts: -------------------------------------------------------------------------------- 1 | import type { VariantType } from '@/types' 2 | import type { VariantLabels } from 'motion-dom' 3 | 4 | export type FocusProps = { 5 | /** 6 | * @deprecated Use `whileFocus` instead. 7 | */ 8 | focus?: VariantLabels | VariantType 9 | /** 10 | * Variant to apply when the element is focused. 11 | */ 12 | whileFocus?: VariantLabels | VariantType 13 | onFocus?: (e: FocusEvent) => void 14 | onBlur?: (e: FocusEvent) => void 15 | } 16 | -------------------------------------------------------------------------------- /packages/motion/src/state/create-visual-element.ts: -------------------------------------------------------------------------------- 1 | import { isSVGElement } from '@/state/utils' 2 | import type { AsTag } from '@/types' 3 | import { HTMLVisualElement } from 'framer-motion/dist/es/render/html/HTMLVisualElement.mjs' 4 | import { SVGVisualElement } from 'framer-motion/dist/es/render/svg/SVGVisualElement.mjs' 5 | 6 | export function createVisualElement(Component: AsTag, options: any) { 7 | return isSVGElement(Component as any) ? new SVGVisualElement(options) : new HTMLVisualElement(options) 8 | } 9 | -------------------------------------------------------------------------------- /docs/components/demo/in-view/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 21 | -------------------------------------------------------------------------------- /docs/components/ui/collapsible/CollapsibleContent.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 15 | -------------------------------------------------------------------------------- /docs/components/demo/reorder-layout/array-utils.ts: -------------------------------------------------------------------------------- 1 | export function removeItem([...arr]: T[], item: T) { 2 | const index = arr.indexOf(item) 3 | index > -1 && arr.splice(index, 1) 4 | return arr 5 | } 6 | 7 | export function closestItem(arr: T[], item: T) { 8 | const index = arr.indexOf(item) 9 | if (index === -1) { 10 | return arr[0] 11 | } 12 | else if (index === arr.length - 1) { 13 | return arr[arr.length - 2] 14 | } 15 | else { 16 | return arr[index + 1] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /docs/components/ui/alert/Alert.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 20 | -------------------------------------------------------------------------------- /docs/components/ui/breadcrumb/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Breadcrumb } from './Breadcrumb.vue' 2 | export { default as BreadcrumbEllipsis } from './BreadcrumbEllipsis.vue' 3 | export { default as BreadcrumbItem } from './BreadcrumbItem.vue' 4 | export { default as BreadcrumbLink } from './BreadcrumbLink.vue' 5 | export { default as BreadcrumbList } from './BreadcrumbList.vue' 6 | export { default as BreadcrumbPage } from './BreadcrumbPage.vue' 7 | export { default as BreadcrumbSeparator } from './BreadcrumbSeparator.vue' 8 | -------------------------------------------------------------------------------- /playground/nuxt/pages/layout-id-tabs/array-utils.ts: -------------------------------------------------------------------------------- 1 | export function removeItem([...arr]: T[], item: T) { 2 | const index = arr.indexOf(item) 3 | index > -1 && arr.splice(index, 1) 4 | return arr 5 | } 6 | 7 | export function closestItem(arr: T[], item: T) { 8 | const index = arr.indexOf(item) 9 | if (index === -1) { 10 | return arr[0] 11 | } 12 | else if (index === arr.length - 1) { 13 | return arr[arr.length - 2] 14 | } 15 | else { 16 | return arr[index + 1] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /playground/nuxt/pages/reorder-layout/array-utils.ts: -------------------------------------------------------------------------------- 1 | export function removeItem([...arr]: T[], item: T) { 2 | const index = arr.indexOf(item) 3 | index > -1 && arr.splice(index, 1) 4 | return arr 5 | } 6 | 7 | export function closestItem(arr: T[], item: T) { 8 | const index = arr.indexOf(item) 9 | if (index === -1) { 10 | return arr[0] 11 | } 12 | else if (index === arr.length - 1) { 13 | return arr[arr.length - 2] 14 | } 15 | else { 16 | return arr[index + 1] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /docs/components/ui/accordion/Accordion.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 20 | -------------------------------------------------------------------------------- /packages/plugins/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "plugins", 3 | "version": "1.7.4", 4 | "private": true, 5 | "description": "", 6 | "author": "", 7 | "license": "ISC", 8 | "keywords": [], 9 | "scripts": { 10 | "build:plugins": "unbuild" 11 | }, 12 | "dependencies": { 13 | "@nuxt/kit": "^3.14.1592", 14 | "@nuxt/schema": "^3.14.1592", 15 | "motion-v": "workspace:*" 16 | }, 17 | "devDependencies": { 18 | "unbuild": "^2.0.0", 19 | "unplugin-vue-components": "^0.28.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /docs/components/layout/PrevNext.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 22 | -------------------------------------------------------------------------------- /docs/components/content/CodeGroup.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 27 | -------------------------------------------------------------------------------- /docs/components/demo/drag-with-constraints/index.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 20 | -------------------------------------------------------------------------------- /docs/components/demo/while-drag/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 18 | 19 | 22 | -------------------------------------------------------------------------------- /packages/motion/src/features/layout/utils.ts: -------------------------------------------------------------------------------- 1 | import type { IProjectionNode, VisualElement } from 'framer-motion' 2 | 3 | export function getClosestProjectingNode( 4 | visualElement?: VisualElement< 5 | unknown, 6 | unknown, 7 | { allowProjection?: boolean } 8 | >, 9 | ): IProjectionNode | undefined { 10 | if (!visualElement) 11 | return undefined 12 | 13 | return visualElement.options.allowProjection !== false 14 | ? visualElement.projection 15 | : getClosestProjectingNode(visualElement.parent) 16 | } 17 | -------------------------------------------------------------------------------- /docs/components/ui/drawer/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Drawer } from './Drawer.vue' 2 | export { default as DrawerContent } from './DrawerContent.vue' 3 | export { default as DrawerDescription } from './DrawerDescription.vue' 4 | export { default as DrawerFooter } from './DrawerFooter.vue' 5 | export { default as DrawerHeader } from './DrawerHeader.vue' 6 | export { default as DrawerOverlay } from './DrawerOverlay.vue' 7 | export { default as DrawerTitle } from './DrawerTitle.vue' 8 | export { DrawerClose, DrawerPortal, DrawerTrigger } from 'vaul-vue' 9 | -------------------------------------------------------------------------------- /docs/components/content/Shortcut.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 20 | -------------------------------------------------------------------------------- /docs/components/ui/breadcrumb/BreadcrumbSeparator.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 22 | -------------------------------------------------------------------------------- /playground/nuxt/pages/motion-config/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 18 | -------------------------------------------------------------------------------- /docs/components/demo/reorder-layout/AddIcon.vue: -------------------------------------------------------------------------------- 1 | 23 | -------------------------------------------------------------------------------- /docs/components/ui/navigation-menu/NavigationMenuLink.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 20 | -------------------------------------------------------------------------------- /packages/motion/src/components/animate-presence/use-presence.ts: -------------------------------------------------------------------------------- 1 | import { onMounted } from 'vue' 2 | import { useMotionElm } from '@/components/hooks/use-motion-elm' 3 | 4 | export const presenceMeasure = new Map() 5 | export function usePresence() { 6 | const motionElement = useMotionElm() 7 | onMounted(() => { 8 | presenceMeasure.set(motionElement.value, true) 9 | }) 10 | 11 | const safeToRemove = () => { 12 | if (motionElement.value) { 13 | presenceMeasure.delete(motionElement.value) 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /playground/nuxt/pages/reorder-layout/AddIcon.vue: -------------------------------------------------------------------------------- 1 | 23 | -------------------------------------------------------------------------------- /docs/components/demo/keyframes/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 22 | -------------------------------------------------------------------------------- /docs/components/ui/drawer/Drawer.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 20 | -------------------------------------------------------------------------------- /docs/components/content/Kbd.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 21 | -------------------------------------------------------------------------------- /docs/components/demo/gestures/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 23 | -------------------------------------------------------------------------------- /docs/components/layout/EditLink.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 24 | -------------------------------------------------------------------------------- /docs/components/ui/breadcrumb/BreadcrumbLink.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 20 | -------------------------------------------------------------------------------- /docs/components/ui/collapsible/Collapsible.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 19 | -------------------------------------------------------------------------------- /playground/nuxt/components/sandbox/content.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 25 | -------------------------------------------------------------------------------- /playground/nuxt/pages/child.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 20 | 21 | 29 | -------------------------------------------------------------------------------- /packages/plugins/src/resolver/index.ts: -------------------------------------------------------------------------------- 1 | import type { ComponentResolver } from 'unplugin-vue-components' 2 | 3 | const components = new Set([ 4 | 'Motion', 5 | 'AnimatePresence', 6 | 'LayoutGroup', 7 | 'MotionConfig', 8 | 'ReorderGroup', 9 | 'ReorderItem', 10 | 'M', 11 | ]) 12 | 13 | export default function (): ComponentResolver { 14 | return { 15 | type: 'component', 16 | resolve: (name: string) => { 17 | if (components.has(name)) { 18 | return { 19 | name, 20 | from: 'motion-v', 21 | } 22 | } 23 | }, 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /playground/nuxt/pages/number-counter/AdditionIcon.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 27 | -------------------------------------------------------------------------------- /docs/components/content/Steps.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 24 | -------------------------------------------------------------------------------- /docs/components/layout/AsideTree.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 26 | -------------------------------------------------------------------------------- /packages/motion/src/types/common.ts: -------------------------------------------------------------------------------- 1 | import type { Component, DefineComponent, ExtractPropTypes, ExtractPublicPropTypes, IntrinsicElementAttributes, MaybeRef } from 'vue' 2 | 3 | export type ComponentProps = T extends DefineComponent< 4 | ExtractPropTypes, 5 | any, 6 | any 7 | > 8 | ? ExtractPublicPropTypes 9 | : never 10 | 11 | export type ElementType = keyof IntrinsicElementAttributes 12 | export type AsTag = keyof IntrinsicElementAttributes | ({} & string) | Component // any other string 13 | 14 | export type ToRefs = { 15 | [K in keyof T]: MaybeRef 16 | } 17 | -------------------------------------------------------------------------------- /docs/components/ui/command/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Command } from './Command.vue' 2 | export { default as CommandDialog } from './CommandDialog.vue' 3 | export { default as CommandEmpty } from './CommandEmpty.vue' 4 | export { default as CommandGroup } from './CommandGroup.vue' 5 | export { default as CommandInput } from './CommandInput.vue' 6 | export { default as CommandItem } from './CommandItem.vue' 7 | export { default as CommandList } from './CommandList.vue' 8 | export { default as CommandSeparator } from './CommandSeparator.vue' 9 | export { default as CommandShortcut } from './CommandShortcut.vue' 10 | -------------------------------------------------------------------------------- /docs/pages/index.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 22 | -------------------------------------------------------------------------------- /packages/motion/src/components/RowValue.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 23 | -------------------------------------------------------------------------------- /packages/motion/src/value/use-will-change/add-will-change.ts: -------------------------------------------------------------------------------- 1 | import { isWillChangeMotionValue } from '@/value/use-will-change/is' 2 | import type { VisualElement } from 'framer-motion' 3 | 4 | export function addValueToWillChange( 5 | visualElement: VisualElement, 6 | key: string, 7 | ) { 8 | const willChange = visualElement.getValue('willChange') 9 | 10 | /** 11 | * It could be that a user has set willChange to a regular MotionValue, 12 | * in which case we can't add the value to it. 13 | */ 14 | if (isWillChangeMotionValue(willChange)) { 15 | return willChange.add(key) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/motion/src/features/gestures/hover/types.ts: -------------------------------------------------------------------------------- 1 | import type { VariantType } from '@/types' 2 | import type { EventInfo } from 'framer-motion' 3 | import type { VariantLabels } from 'motion-dom' 4 | 5 | export type HoverEvent = (event: MouseEvent, info: EventInfo) => void 6 | 7 | export interface HoverProps { 8 | /** 9 | * @deprecated Use `whileHover` instead. 10 | */ 11 | hover?: VariantLabels | VariantType 12 | /** 13 | * Variant to apply when the element is hovered. 14 | */ 15 | whileHover?: VariantLabels | VariantType 16 | onHoverStart?: HoverEvent 17 | onHoverEnd?: HoverEvent 18 | } 19 | -------------------------------------------------------------------------------- /docs/components/demo/scroll-animate/index.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 24 | -------------------------------------------------------------------------------- /docs/components/ui/dialog/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Dialog } from './Dialog.vue' 2 | export { default as DialogClose } from './DialogClose.vue' 3 | export { default as DialogContent } from './DialogContent.vue' 4 | export { default as DialogDescription } from './DialogDescription.vue' 5 | export { default as DialogFooter } from './DialogFooter.vue' 6 | export { default as DialogHeader } from './DialogHeader.vue' 7 | export { default as DialogScrollContent } from './DialogScrollContent.vue' 8 | export { default as DialogTitle } from './DialogTitle.vue' 9 | export { default as DialogTrigger } from './DialogTrigger.vue' 10 | -------------------------------------------------------------------------------- /packages/motion/src/utils/use-page-in-view.ts: -------------------------------------------------------------------------------- 1 | import { onMounted, onUnmounted, ref } from 'vue' 2 | 3 | export function usePageInView() { 4 | const isInView = ref(true) 5 | 6 | const handleVisibilityChange = () => { 7 | isInView.value = !document.hidden 8 | } 9 | 10 | onMounted(() => { 11 | if (document.hidden) { 12 | handleVisibilityChange() 13 | } 14 | document.addEventListener('visibilitychange', handleVisibilityChange) 15 | }) 16 | 17 | onUnmounted(() => { 18 | document.removeEventListener('visibilitychange', handleVisibilityChange) 19 | }) 20 | 21 | return isInView 22 | } 23 | -------------------------------------------------------------------------------- /.github/workflows/release.yaml: -------------------------------------------------------------------------------- 1 | # .github/workflows/release.yml 2 | name: Release 3 | 4 | permissions: 5 | contents: write 6 | 7 | on: 8 | push: 9 | tags: 10 | - 'v*' 11 | 12 | jobs: 13 | release: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Checkout repository 17 | uses: actions/checkout@v4 18 | 19 | - uses: actions/checkout@v4 20 | with: 21 | fetch-depth: 0 22 | 23 | - uses: actions/setup-node@v4 24 | with: 25 | node-version: 18.x 26 | 27 | - run: npx changelogithub 28 | env: 29 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 30 | -------------------------------------------------------------------------------- /docs/components/ui/breadcrumb/BreadcrumbEllipsis.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 23 | -------------------------------------------------------------------------------- /playground/nuxt/assets/css/tailwind.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | @layer components { 6 | .primary-button { 7 | @apply px-4 py-1 ml-auto text-black bg-white font-semibold rounded-md hover:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-400; 8 | } 9 | 10 | .secondary-button { 11 | @apply px-6 py-3 bg-green-500 text-white font-bold rounded-lg shadow-md hover:bg-green-600 focus:outline-none focus:ring-2 focus:ring-green-400; 12 | } 13 | 14 | .gradient-pink-violet { 15 | @apply bg-gradient-to-tr from-[#7b2ff7] to-[#f107a3]; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/motion/src/events/utils/is-primary-pointer.ts: -------------------------------------------------------------------------------- 1 | export function isPrimaryPointer(event: PointerEvent) { 2 | if (event.pointerType === 'mouse') { 3 | return typeof event.button !== 'number' || event.button <= 0 4 | } 5 | else { 6 | /** 7 | * isPrimary is true for all mice buttons, whereas every touch point 8 | * is regarded as its own input. So subsequent concurrent touch points 9 | * will be false. 10 | * 11 | * Specifically match against false here as incomplete versions of 12 | * PointerEvents in very old browser might have it set as undefined. 13 | */ 14 | return event.isPrimary !== false 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/motion/src/utils/use-dom-ref.ts: -------------------------------------------------------------------------------- 1 | import { getMotionElement } from '@/components/hooks/use-motion-elm' 2 | import { ref } from 'vue' 3 | 4 | export function useDomRef() { 5 | const dom = ref(null) 6 | const domProxy = new Proxy(dom, { 7 | get(target, key) { 8 | if (typeof key === 'string' || typeof key === 'symbol') { 9 | return Reflect.get(target, key) 10 | } 11 | return undefined 12 | }, 13 | set(target, key, value) { 14 | if (key === 'value') 15 | return Reflect.set(target, key, getMotionElement(value?.$el || value)) 16 | return true 17 | }, 18 | }) 19 | return domProxy 20 | } 21 | -------------------------------------------------------------------------------- /playground/nuxt/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "motion-playground", 3 | "type": "module", 4 | "private": true, 5 | "scripts": { 6 | "build": "nuxt build", 7 | "play": "nuxt dev --port 3001 --host", 8 | "generate": "nuxt generate", 9 | "preview": "nuxt preview" 10 | }, 11 | "dependencies": { 12 | "@number-flow/vue": "^0.3.2", 13 | "motion-number-vue": "latest", 14 | "motion-plus-vue": "0.1.0", 15 | "motion-v": "workspace:*", 16 | "nuxt": "3.19.0", 17 | "reka-ui": "^2.0.0", 18 | "vue": "latest", 19 | "vue-router": "latest" 20 | }, 21 | "devDependencies": { 22 | "@nuxtjs/tailwindcss": "^6.12.1" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /docs/components/ui/sheet/SheetTitle.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 23 | -------------------------------------------------------------------------------- /docs/components/content/Stackblitz.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 |