├── site ├── static │ ├── manifest.json │ ├── images │ │ ├── icon.png │ │ ├── favicon.ico │ │ ├── favicon.png │ │ ├── bouncingball.mp4 │ │ ├── twitter-card.png │ │ ├── chat-with-hack.gif │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── low-power-mode.png │ │ ├── reddit-popover.png │ │ ├── sidebar-effect.gif │ │ ├── twitter-banner.png │ │ ├── twitter-card2.png │ │ ├── chat-without-hack.gif │ │ ├── pose-twitter-card.png │ │ ├── chrome-perf-hi-res.png │ │ ├── chrome-perf-low-res.png │ │ ├── facebook-messenger.jpg │ │ └── twitter-profile-picture.png │ ├── guides │ │ ├── flash-gordon.jpg │ │ ├── amiga-demoscene.gif │ │ ├── amiga-demoscene.png │ │ ├── drivetribe-bump.gif │ │ ├── drivetribe-unbump.gif │ │ ├── ease-out-example.png │ │ ├── ease-in-out-example.png │ │ ├── ease-linear-example.png │ │ └── drivetribe-bump-quick.gif │ └── videos │ │ ├── native-drag.mp4 │ │ ├── native-drag-x.mp4 │ │ ├── native-children.mp4 │ │ ├── native-drag-end.mp4 │ │ ├── native-drag-pose.mp4 │ │ ├── native-get-started.mp4 │ │ ├── native-passive-color.mp4 │ │ ├── native-passive-opacity.mp4 │ │ ├── native-custom-transition.mp4 │ │ ├── native-passive-children.mp4 │ │ ├── native-custom-transition-b.mp4 │ │ ├── native-custom-transition-c.mp4 │ │ ├── native-custom-transition-d.mp4 │ │ └── native-custom-transition-e.mp4 ├── data │ ├── site-names.json │ ├── section-names.json │ ├── route-paths.json │ ├── settings.json │ └── category-names.json ├── pages │ ├── pose │ │ ├── index.js │ │ └── api.js │ ├── index.js │ ├── blog.js │ ├── api.js │ ├── _error.js │ └── _document.js ├── components │ ├── examples │ │ ├── templates.js │ │ ├── Swatch.js │ │ ├── CodePen.js │ │ ├── Counter.js │ │ └── Ball.js │ ├── icons │ │ ├── BrandGradientDef.js │ │ ├── DropDownArrow.js │ │ ├── PopmotionIcon.js │ │ ├── Twitter.js │ │ ├── GitHub.js │ │ └── PoseLogo.js │ └── layout │ │ ├── Content.js │ │ ├── SiteLink.js │ │ └── grid.js ├── scripts │ ├── filename-operations.js │ ├── convert-date-format.js │ ├── build-next-config.js │ └── generate-content-page.js ├── utils │ └── string.js ├── templates │ ├── Popmotion │ │ ├── USPs │ │ │ ├── ExampleSection.js │ │ │ └── Example.js │ │ ├── FinalCTA │ │ │ ├── styled.js │ │ │ └── index.js │ │ ├── index.js │ │ ├── LiveExamples │ │ │ ├── track-visibility.js │ │ │ ├── Template.js │ │ │ ├── Pointer.js │ │ │ ├── Spring.js │ │ │ ├── Multitouch.js │ │ │ ├── Tween.js │ │ │ ├── Stepped.js │ │ │ └── Color.js │ │ └── Masthead │ │ │ └── index.js │ ├── global │ │ ├── Analytics.js │ │ ├── SocialLinks.js │ │ ├── grid.js │ │ └── SectionNav.js │ ├── Pose │ │ ├── index.js │ │ └── USPs │ │ │ ├── DeclarativeExample.js │ │ │ ├── ZeroConfigExample.js │ │ │ ├── DraggableExample.js │ │ │ └── PassiveExample.js │ └── content │ │ ├── styled.js │ │ └── MenuPage.js ├── styles │ ├── fonts.js │ ├── nprogress.js │ ├── syntax-highlighting.js │ └── vars.js └── .babelrc ├── packages ├── popmotion │ ├── .npmignore │ ├── docs │ │ ├── blog │ │ │ ├── draft-css-vs-js-animation.md │ │ │ └── draft-the-emerging-reality.md │ │ ├── api │ │ │ ├── compositors │ │ │ │ ├── delay.md │ │ │ │ ├── merge.md │ │ │ │ ├── chain.md │ │ │ │ ├── parallel.md │ │ │ │ ├── composite.md │ │ │ │ ├── crossfade.md │ │ │ │ ├── schedule.md │ │ │ │ └── stagger.md │ │ │ ├── animation │ │ │ │ └── every-frame.md │ │ │ └── plugins │ │ │ │ └── spinnable.md │ │ └── learn │ │ │ ├── basics │ │ │ └── install.md │ │ │ └── how-to │ │ │ └── rounded-values.md │ ├── src │ │ ├── global.ts │ │ ├── reactions │ │ │ ├── types.ts │ │ │ ├── multicast.ts │ │ │ ├── _tests │ │ │ │ ├── multicast.test.ts │ │ │ │ └── value.test.ts │ │ │ └── index.ts │ │ ├── chainable │ │ │ ├── types.ts │ │ │ └── index.ts │ │ ├── animations │ │ │ ├── decay │ │ │ │ ├── types.ts │ │ │ │ ├── _tests │ │ │ │ │ └── decay.test.ts │ │ │ │ └── index.ts │ │ │ ├── spring │ │ │ │ └── types.ts │ │ │ ├── every-frame │ │ │ │ ├── _tests │ │ │ │ │ └── every-frame.test.ts │ │ │ │ └── index.ts │ │ │ ├── keyframes │ │ │ │ └── types.ts │ │ │ ├── physics │ │ │ │ ├── types.ts │ │ │ │ └── _tests │ │ │ │ │ └── physics.test.ts │ │ │ ├── timeline │ │ │ │ └── types.ts │ │ │ └── tween │ │ │ │ ├── scrubber.ts │ │ │ │ └── types.ts │ │ ├── compositors │ │ │ ├── delay.ts │ │ │ ├── merge.ts │ │ │ ├── crossfade.ts │ │ │ ├── schedule.ts │ │ │ ├── chain.ts │ │ │ ├── stagger.ts │ │ │ ├── parallel.ts │ │ │ ├── composite.ts │ │ │ └── multi.ts │ │ ├── action │ │ │ ├── types.ts │ │ │ ├── index.ts │ │ │ └── _tests │ │ │ │ └── action.test.ts │ │ ├── input │ │ │ ├── listen │ │ │ │ ├── types.ts │ │ │ │ └── index.ts │ │ │ └── pointer │ │ │ │ ├── utils.ts │ │ │ │ ├── types.ts │ │ │ │ ├── index.ts │ │ │ │ └── mouse.ts │ │ ├── _tests │ │ │ └── ease.test.ts │ │ ├── global-xl.ts │ │ ├── observer │ │ │ ├── types.ts │ │ │ └── index.ts │ │ └── index.ts │ ├── .gitignore │ ├── tsconfig.json │ ├── README.md │ └── webpack.config.js ├── react-pose-core │ ├── src │ │ ├── index.ts │ │ ├── types.ts │ │ └── posed.tsx │ ├── README.md │ ├── CHANGELOG.md │ ├── tsconfig.json │ └── package.json ├── popmotion-pose │ ├── assets │ │ └── logo.sketch │ ├── src │ │ ├── global.ts │ │ ├── inc │ │ │ ├── transition-composers.ts │ │ │ └── selectors.ts │ │ ├── factories │ │ │ ├── dimensions.ts │ │ │ └── poses.ts │ │ └── dom │ │ │ └── draggable.ts │ ├── src-core │ │ ├── global.ts │ │ ├── inc │ │ │ └── default-transitions.ts │ │ ├── factories │ │ │ └── dimensions.ts │ │ ├── types.ts │ │ └── index.ts │ ├── docs │ │ ├── learn │ │ │ └── get-started.md │ │ └── api │ │ │ ├── transition-compositors.md │ │ │ └── react │ │ │ └── posegroup.md │ ├── tsconfig.json │ ├── webpack.config.js │ ├── README.md │ └── package.json ├── react-pose │ ├── src │ │ ├── index.ts │ │ ├── global.ts │ │ └── components │ │ │ └── PoseElement.types.ts │ ├── webpack.config.js │ ├── tsconfig.json │ ├── README.md │ ├── module-types │ │ └── react │ │ │ ├── README.md │ │ │ └── LICENSE │ └── package.json ├── stylefire │ └── docs │ │ └── learn │ │ └── get-started.md ├── popmotion-spinnable │ ├── .babelrc │ ├── CHANGELOG.md │ ├── README.md │ ├── src │ │ ├── react.js │ │ └── index.js │ └── package.json ├── react-360-pose │ ├── CHANGELOG.md │ ├── tsconfig.json │ ├── README.md │ └── package.json ├── pose-core │ ├── tsconfig.json │ ├── src │ │ ├── inc │ │ │ ├── transition-composers.ts │ │ │ └── selectors.ts │ │ └── factories │ │ │ └── transitions.ts │ ├── CHANGELOG.md │ └── package.json ├── animated-pose │ ├── tsconfig.json │ ├── src │ │ ├── index.ts │ │ ├── inc │ │ │ ├── unit-conversion.ts │ │ │ └── default-transitions.ts │ │ └── types.ts │ ├── package.json │ └── CHANGELOG.md ├── react-native-pose │ ├── tsconfig.json │ ├── CHANGELOG.md │ ├── README.md │ └── package.json └── blend-tweens │ └── cross-fade.js ├── lerna.json ├── .storybook └── config.js ├── CODE_OF_CONDUCT.md ├── .babelrc ├── .gitignore ├── CONTRIBUTING.md ├── playground ├── plugins │ ├── draggable.js │ ├── spinnable.js │ └── react.js ├── inc.js ├── decay.js ├── spring.js ├── timeline.js ├── keyframes.js ├── physics.js ├── tween.js └── compositors.js ├── README.md ├── .github └── ISSUE_TEMPLATE │ ├── Feature_request.md │ └── Bug_report.md ├── tslint.json ├── .eslintrc ├── test.html ├── LICENSE.md └── package.json /site/static/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "theme_color": "#ED2754" 3 | } -------------------------------------------------------------------------------- /packages/popmotion/.npmignore: -------------------------------------------------------------------------------- 1 | *.md 2 | webpack.config.js 3 | lib 4 | -------------------------------------------------------------------------------- /packages/popmotion/docs/blog/draft-css-vs-js-animation.md: -------------------------------------------------------------------------------- 1 | --- 2 | draft: true 3 | --- -------------------------------------------------------------------------------- /packages/react-pose-core/src/index.ts: -------------------------------------------------------------------------------- 1 | import posed from './posed'; 2 | export default posed; 3 | -------------------------------------------------------------------------------- /site/data/site-names.json: -------------------------------------------------------------------------------- 1 | { 2 | "popmotion": "popmotion", 3 | "popmotion-pose": "pose" 4 | } -------------------------------------------------------------------------------- /packages/react-pose-core/README.md: -------------------------------------------------------------------------------- 1 | # React Pose Core 2 | 3 | ## Factory for creating flavours of React Pose -------------------------------------------------------------------------------- /packages/popmotion/src/global.ts: -------------------------------------------------------------------------------- 1 | import * as popmotion from './'; 2 | (window as any).popmotion = popmotion; 3 | -------------------------------------------------------------------------------- /packages/popmotion/src/reactions/types.ts: -------------------------------------------------------------------------------- 1 | export interface HotSubscription { 2 | unsubscribe: () => void; 3 | } 4 | -------------------------------------------------------------------------------- /site/pages/pose/index.js: -------------------------------------------------------------------------------- 1 | import PoseHomepage from '~/templates/Pose'; 2 | 3 | export default () => ; -------------------------------------------------------------------------------- /site/static/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/images/icon.png -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "lerna": "2.4.0", 3 | "packages": [ 4 | "packages/*" 5 | ], 6 | "version": "0.0.0" 7 | } 8 | -------------------------------------------------------------------------------- /site/static/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/images/favicon.ico -------------------------------------------------------------------------------- /site/static/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/images/favicon.png -------------------------------------------------------------------------------- /site/pages/index.js: -------------------------------------------------------------------------------- 1 | import PopmotionHomepage from '~/templates/Popmotion'; 2 | 3 | export default () => ; -------------------------------------------------------------------------------- /site/static/guides/flash-gordon.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/guides/flash-gordon.jpg -------------------------------------------------------------------------------- /site/static/images/bouncingball.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/images/bouncingball.mp4 -------------------------------------------------------------------------------- /site/static/images/twitter-card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/images/twitter-card.png -------------------------------------------------------------------------------- /site/static/videos/native-drag.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/videos/native-drag.mp4 -------------------------------------------------------------------------------- /site/data/section-names.json: -------------------------------------------------------------------------------- 1 | { 2 | "api": "API", 3 | "learn": "Learn", 4 | "blog": "Blog", 5 | "community": "Community" 6 | } 7 | -------------------------------------------------------------------------------- /site/static/images/chat-with-hack.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/images/chat-with-hack.gif -------------------------------------------------------------------------------- /site/static/images/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/images/favicon-16x16.png -------------------------------------------------------------------------------- /site/static/images/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/images/favicon-32x32.png -------------------------------------------------------------------------------- /site/static/images/low-power-mode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/images/low-power-mode.png -------------------------------------------------------------------------------- /site/static/images/reddit-popover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/images/reddit-popover.png -------------------------------------------------------------------------------- /site/static/images/sidebar-effect.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/images/sidebar-effect.gif -------------------------------------------------------------------------------- /site/static/images/twitter-banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/images/twitter-banner.png -------------------------------------------------------------------------------- /site/static/images/twitter-card2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/images/twitter-card2.png -------------------------------------------------------------------------------- /site/static/videos/native-drag-x.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/videos/native-drag-x.mp4 -------------------------------------------------------------------------------- /packages/popmotion/docs/blog/draft-the-emerging-reality.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: UX in the Emerging Reality 3 | description: 4 | draft: true 5 | --- -------------------------------------------------------------------------------- /site/static/guides/amiga-demoscene.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/guides/amiga-demoscene.gif -------------------------------------------------------------------------------- /site/static/guides/amiga-demoscene.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/guides/amiga-demoscene.png -------------------------------------------------------------------------------- /site/static/guides/drivetribe-bump.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/guides/drivetribe-bump.gif -------------------------------------------------------------------------------- /site/static/guides/drivetribe-unbump.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/guides/drivetribe-unbump.gif -------------------------------------------------------------------------------- /site/static/guides/ease-out-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/guides/ease-out-example.png -------------------------------------------------------------------------------- /site/static/images/chat-without-hack.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/images/chat-without-hack.gif -------------------------------------------------------------------------------- /site/static/images/pose-twitter-card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/images/pose-twitter-card.png -------------------------------------------------------------------------------- /site/static/videos/native-children.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/videos/native-children.mp4 -------------------------------------------------------------------------------- /site/static/videos/native-drag-end.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/videos/native-drag-end.mp4 -------------------------------------------------------------------------------- /site/static/videos/native-drag-pose.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/videos/native-drag-pose.mp4 -------------------------------------------------------------------------------- /packages/popmotion-pose/assets/logo.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/packages/popmotion-pose/assets/logo.sketch -------------------------------------------------------------------------------- /site/static/guides/ease-in-out-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/guides/ease-in-out-example.png -------------------------------------------------------------------------------- /site/static/guides/ease-linear-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/guides/ease-linear-example.png -------------------------------------------------------------------------------- /site/static/images/chrome-perf-hi-res.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/images/chrome-perf-hi-res.png -------------------------------------------------------------------------------- /site/static/images/chrome-perf-low-res.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/images/chrome-perf-low-res.png -------------------------------------------------------------------------------- /site/static/images/facebook-messenger.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/images/facebook-messenger.jpg -------------------------------------------------------------------------------- /site/static/videos/native-get-started.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/videos/native-get-started.mp4 -------------------------------------------------------------------------------- /site/static/guides/drivetribe-bump-quick.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/guides/drivetribe-bump-quick.gif -------------------------------------------------------------------------------- /site/static/videos/native-passive-color.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/videos/native-passive-color.mp4 -------------------------------------------------------------------------------- /site/static/videos/native-passive-opacity.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/videos/native-passive-opacity.mp4 -------------------------------------------------------------------------------- /packages/popmotion/src/chainable/types.ts: -------------------------------------------------------------------------------- 1 | export type Predicate = (v?: any) => boolean; 2 | 3 | export type Props = { 4 | [key: string]: any 5 | }; 6 | -------------------------------------------------------------------------------- /site/static/images/twitter-profile-picture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/images/twitter-profile-picture.png -------------------------------------------------------------------------------- /site/static/videos/native-custom-transition.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/videos/native-custom-transition.mp4 -------------------------------------------------------------------------------- /site/static/videos/native-passive-children.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/videos/native-passive-children.mp4 -------------------------------------------------------------------------------- /site/static/videos/native-custom-transition-b.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/videos/native-custom-transition-b.mp4 -------------------------------------------------------------------------------- /site/static/videos/native-custom-transition-c.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/videos/native-custom-transition-c.mp4 -------------------------------------------------------------------------------- /site/static/videos/native-custom-transition-d.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/videos/native-custom-transition-d.mp4 -------------------------------------------------------------------------------- /site/static/videos/native-custom-transition-e.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/popmotion/master/site/static/videos/native-custom-transition-e.mp4 -------------------------------------------------------------------------------- /site/data/route-paths.json: -------------------------------------------------------------------------------- 1 | { 2 | "api": "/api", 3 | "learn": "/learn/get-started", 4 | "blog": "/blog", 5 | "community": "https://spectrum.chat/popmotion" 6 | } 7 | -------------------------------------------------------------------------------- /packages/react-pose/src/index.ts: -------------------------------------------------------------------------------- 1 | import posed from './posed'; 2 | import { PoseGroup } from './components/PoseGroup'; 3 | 4 | export default posed; 5 | export { PoseGroup }; 6 | -------------------------------------------------------------------------------- /.storybook/config.js: -------------------------------------------------------------------------------- 1 | import { configure } from '@storybook/react'; 2 | 3 | function loadStories() { 4 | require('../playground'); 5 | } 6 | 7 | configure(loadStories, module); 8 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of conduct 2 | 3 | ![Be excellent to each other](https://user-images.githubusercontent.com/7850794/33840491-f80357bc-de8c-11e7-82fb-408f4aaeb24c.png) 4 | -------------------------------------------------------------------------------- /packages/popmotion-pose/src/global.ts: -------------------------------------------------------------------------------- 1 | import pose from './'; 2 | import * as popmotion from 'popmotion'; 3 | 4 | (window as any).pose = pose; 5 | (window as any).popmotion = popmotion; 6 | -------------------------------------------------------------------------------- /packages/popmotion/.gitignore: -------------------------------------------------------------------------------- 1 | /*.js 2 | /*.js.map 3 | *.d.ts 4 | /action 5 | /animations 6 | /compositors 7 | /input 8 | /observables 9 | /observer 10 | /chainable 11 | /reactions 12 | -------------------------------------------------------------------------------- /packages/popmotion-pose/src-core/global.ts: -------------------------------------------------------------------------------- 1 | import pose from './'; 2 | import * as popmotion from 'popmotion'; 3 | 4 | (window as any).pose = pose; 5 | (window as any).popmotion = popmotion; 6 | -------------------------------------------------------------------------------- /site/components/examples/templates.js: -------------------------------------------------------------------------------- 1 | import Counter from './Counter'; 2 | import Ball from './Ball'; 3 | import Swatch from './Swatch'; 4 | 5 | export default { 6 | Counter, 7 | Ball, 8 | Swatch 9 | }; 10 | -------------------------------------------------------------------------------- /packages/stylefire/docs/learn/get-started.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Get started 3 | description: Get started with the `styler` function to performantly set HTML and SVG styles. 4 | category: basics 5 | --- 6 | 7 | # Get started 8 | -------------------------------------------------------------------------------- /site/scripts/filename-operations.js: -------------------------------------------------------------------------------- 1 | const DS_STORE = '.DS_Store'; 2 | 3 | module.exports = { 4 | filterFiles: (filename) => (filename.indexOf('.') === -1), 5 | filterSystemFiles: (filename) => (filename !== DS_STORE) 6 | }; 7 | -------------------------------------------------------------------------------- /site/utils/string.js: -------------------------------------------------------------------------------- 1 | export function htmlUnencode(str) { 2 | return str 3 | .replace(/"/g, '"') 4 | .replace(/'/g, "'") 5 | .replace(/</g, '<') 6 | .replace(/>/g, '>') 7 | .replace(/&/g, '&'); 8 | } 9 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [["env", { "loose": true} ], "stage-2"], 3 | "plugins": ["transform-export-extensions", "transform-react-jsx"], 4 | "env": { 5 | "development": { 6 | "sourceMaps": "inline" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/react-pose/src/global.ts: -------------------------------------------------------------------------------- 1 | import posed, { PoseGroup } from './index'; 2 | import * as popmotion from 'popmotion'; 3 | 4 | (window as any).posed = posed; 5 | (window as any).PoseGroup = PoseGroup; 6 | (window as any).popmotion = popmotion; 7 | -------------------------------------------------------------------------------- /packages/popmotion-spinnable/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [["env", { "loose": true} ], "stage-2"], 3 | "plugins": ["transform-export-extensions", "transform-react-jsx"], 4 | "env": { 5 | "development": { 6 | "sourceMaps": "inline" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /site/templates/Popmotion/USPs/ExampleSection.js: -------------------------------------------------------------------------------- 1 | import { SectionContainer, SectionHeader } from './styled'; 2 | 3 | export default ({ title, children }) => ( 4 | 5 | {title && {title}} 6 | {children} 7 | 8 | ); -------------------------------------------------------------------------------- /site/data/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "siteName": "Popmotion", 3 | "githubUrl": "https://github.com/popmotion/popmotion", 4 | "stackOverflowUrl": "https://stackoverflow.com/questions/tagged/popmotion", 5 | "twitterUrl": "https://twitter.com/popmotionjs", 6 | "twitterUsername": "popmotionjs" 7 | } 8 | -------------------------------------------------------------------------------- /packages/popmotion/src/animations/decay/types.ts: -------------------------------------------------------------------------------- 1 | export type ModifyTarget = (v: number) => number; 2 | 3 | export type Props = { 4 | velocity?: number, 5 | from?: number, 6 | modifyTarget?: ModifyTarget, 7 | power?: number, 8 | timeConstant?: number, 9 | restDelta?: number 10 | }; 11 | -------------------------------------------------------------------------------- /packages/react-pose-core/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | React Pose Core adheres to [Semantic Versioning](http://semver.org/). 4 | 5 | ## [0.1.0] 2018-05-06 6 | 7 | - Adding `filterConfig` prop. 8 | 9 | ## [0.0.2] 2018-05-06 10 | 11 | - Updating types. 12 | 13 | ## [0.0.1] 2018-05-06 14 | 15 | - First publish. 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | npm-debug.log 4 | lib 5 | site/.next 6 | site/public 7 | site/pages/api 8 | site/pages/learn 9 | site/pages/blog 10 | site/pages/pose/api 11 | site/pages/pose/learn 12 | storybook-static 13 | site/data/content.json 14 | site/data/menus.json 15 | site/next.config.js 16 | .vscode 17 | -------------------------------------------------------------------------------- /packages/popmotion/src/compositors/delay.ts: -------------------------------------------------------------------------------- 1 | import action, { Action } from '../action'; 2 | 3 | const delay = (timeToDelay: number): Action => action(({ complete }) => { 4 | const timeout = setTimeout(complete, timeToDelay); 5 | 6 | return { 7 | stop: () => clearTimeout(timeout) 8 | }; 9 | }); 10 | 11 | export default delay; 12 | -------------------------------------------------------------------------------- /packages/popmotion/src/reactions/multicast.ts: -------------------------------------------------------------------------------- 1 | import { ObserverProps } from '../observer/types'; 2 | import { BaseMulticast } from './'; 3 | 4 | export class Multicast extends BaseMulticast { 5 | create(props: ObserverProps) { 6 | return new Multicast(props); 7 | } 8 | } 9 | 10 | export default () => new Multicast(); 11 | -------------------------------------------------------------------------------- /packages/popmotion/src/animations/spring/types.ts: -------------------------------------------------------------------------------- 1 | export type SpringProps = { 2 | from?: number, 3 | to?: number, 4 | stiffness?: number, 5 | damping?: number, 6 | mass?: number, 7 | velocity?: number, 8 | restSpeed?: number, 9 | restDelta?: number 10 | }; 11 | 12 | export type SpringInterface = { 13 | stop: () => void 14 | }; 15 | -------------------------------------------------------------------------------- /packages/popmotion/src/compositors/merge.ts: -------------------------------------------------------------------------------- 1 | import action, { Action } from '../action'; 2 | 3 | const merge = (...actions: Action[]) => action((observer) => { 4 | const subs = actions.map((thisAction) => thisAction.start(observer)); 5 | return { 6 | stop: () => subs.forEach((sub) => sub.stop()) 7 | }; 8 | }); 9 | 10 | export default merge; 11 | -------------------------------------------------------------------------------- /site/components/icons/BrandGradientDef.js: -------------------------------------------------------------------------------- 1 | import { BRAND, BRAND_BURN } from '~/styles/vars'; 2 | 3 | export default ({ id }) => ( 4 | 5 | 6 | 7 | 8 | 9 | 10 | ); -------------------------------------------------------------------------------- /packages/popmotion-pose/docs/learn/get-started.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Get started 3 | description: Get started with the Pose animation system for HTML, SVG, React and React Native 4 | --- 5 | 6 | # Get started 7 | 8 | ## Choose your adventure: 9 | 10 | ### [HTML, SVG or React DOM](/pose/learn/popmotion-get-started) 11 | ### [React Native](/pose/learn/native-get-started) 12 | -------------------------------------------------------------------------------- /packages/popmotion/src/action/types.ts: -------------------------------------------------------------------------------- 1 | import { IObserver, ObserverProps } from '../observer/types'; 2 | 3 | export type ActionInit = (observer: IObserver) => ColdSubscription | void; 4 | 5 | export interface ColdSubscription { 6 | stop?: () => void; 7 | [key: string]: Function | undefined; 8 | } 9 | 10 | export type ActionProps = ObserverProps & { 11 | init: ActionInit 12 | }; 13 | -------------------------------------------------------------------------------- /packages/popmotion-spinnable/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | Popmotion Spinnable adheres to [Semantic Versioning](http://semver.org/). 4 | 5 | ## [1.0.2] 2017-08-24 6 | 7 | - Changing `popmotion` to peer dependency. 8 | 9 | ## [1.0.1] 2017-07-13 10 | 11 | ### Fixed 12 | - Fixing default values being overridden. 13 | 14 | ## [1.0.0] 2017-07-13 15 | 16 | ### Added 17 | - First release 18 | -------------------------------------------------------------------------------- /site/components/icons/DropDownArrow.js: -------------------------------------------------------------------------------- 1 | import { ENTITY } from '~/styles/vars'; 2 | 3 | export default ({ color = ENTITY, className }) => ( 4 | 5 | 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /site/components/layout/Content.js: -------------------------------------------------------------------------------- 1 | import GlobalTemplate from '~/components/layout/GlobalTemplate'; 2 | 3 | export default ({ children, id, section, category, title, description }) => ( 4 | 11 | {children} 12 | 13 | ); 14 | -------------------------------------------------------------------------------- /site/data/category-names.json: -------------------------------------------------------------------------------- 1 | { 2 | "action": "Action", 3 | "animation": "Animation", 4 | "compositors": "Compositors", 5 | "input": "Input", 6 | "how-to": "How to...", 7 | "stylefire": "Styler", 8 | "basics": "Basics", 9 | "advanced": "Advanced", 10 | "plugins": "Plugins", 11 | "projects": "Projects", 12 | "reactions": "Reactions", 13 | "dom": "DOM", 14 | "react": "React", 15 | "react-native": "React Native" 16 | } 17 | -------------------------------------------------------------------------------- /packages/popmotion/src/animations/every-frame/_tests/every-frame.test.ts: -------------------------------------------------------------------------------- 1 | import everyFrame from '../'; 2 | 3 | describe('everyFrame', () => { 4 | it('should fire update every frame', () => { 5 | return new Promise((resolve) => { 6 | let i = 0; 7 | const a = everyFrame().start(() => { 8 | i++; 9 | if (i > 2) { 10 | a.stop(); 11 | resolve(); 12 | } 13 | }); 14 | }); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /site/templates/Popmotion/FinalCTA/styled.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | import { Centered } from '~/templates/global/grid'; 3 | import { cols, LIGHT_GREY } from '~/styles/vars'; 4 | 5 | export const Container = styled.section` 6 | padding-top: ${cols(4)}; 7 | border-top: ${LIGHT_GREY} 1px solid; 8 | border-bottom: none; 9 | `; 10 | 11 | export const ContentContainer = Centered.extend` 12 | display: flex; 13 | flex-direction: column; 14 | `; 15 | -------------------------------------------------------------------------------- /packages/popmotion-pose/src-core/inc/default-transitions.ts: -------------------------------------------------------------------------------- 1 | import { eachValue } from '../../../pose-core/src/inc/transition-composers'; 2 | 3 | const intelligentTransition = eachValue({}); 4 | 5 | // TODO: Return `decay` based on behavioural props 6 | const intelligentDragEnd: Transition = ({ from }) => just(from); 7 | 8 | export default new Map([ 9 | ['default', intelligentTransition], 10 | ['dragging', dragAction], 11 | ['dragEnd', intelligentDragEnd] 12 | ]); 13 | -------------------------------------------------------------------------------- /site/components/layout/SiteLink.js: -------------------------------------------------------------------------------- 1 | import { withTheme } from 'styled-components'; 2 | import Link from 'next/link'; 3 | 4 | const makeSiteUrl = (root, href) => (root === '/' || href.substring(0, 4) === 'http') ? href : `${root}${href}`; 5 | 6 | const SiteLink = ({ href, children, theme, name, ...props }) => ( 7 | 8 | {children} 9 | 10 | ); 11 | 12 | export default withTheme(SiteLink); -------------------------------------------------------------------------------- /site/scripts/convert-date-format.js: -------------------------------------------------------------------------------- 1 | /* 2 | Simple script to convert YYYYMMDD format into eg 28 Jan 2017 format 3 | */ 4 | const months = ['', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; 5 | 6 | module.exports = function (yyyymmdd) { 7 | const year = yyyymmdd.substring(2, 4); 8 | const month = parseInt(yyyymmdd.substring(4, 6)); 9 | const day = parseInt(yyyymmdd.substring(6, 8)); 10 | 11 | return `${day} ${months[month]} ${year}`; 12 | }; 13 | -------------------------------------------------------------------------------- /packages/popmotion/src/input/listen/types.ts: -------------------------------------------------------------------------------- 1 | import { Action } from '../../action'; 2 | 3 | export interface EventListenerOptions { 4 | capture?: boolean; 5 | passive?: boolean; 6 | once?: boolean; 7 | } 8 | 9 | export type EventListener = ( 10 | type: string, 11 | listener: Function, 12 | options?: EventListenerOptions | boolean 13 | ) => void; 14 | 15 | export type ListenFactory = (element: Element | Document | Window, events: string, options?: EventListenerOptions | boolean) => Action; 16 | -------------------------------------------------------------------------------- /packages/popmotion/src/_tests/ease.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | cubicBezier, 3 | linear 4 | } from '../easing'; 5 | 6 | describe('', () => { 7 | it('should return a series of correct, functioning easing functions', () => { 8 | expect(linear(0.5)).toBe(0.5); 9 | expect(cubicBezier(0, 0, 1, 1)(0)).toBe(0); 10 | expect(cubicBezier(0, 0, 1, 1)(0.5)).toBe(0.5); 11 | expect(cubicBezier(.42, 0, .58, 1)(1)).toBe(1); 12 | expect(cubicBezier(.22, 1.08, .41, 1.55)(0.5) > 1).toBe(true); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /site/styles/fonts.js: -------------------------------------------------------------------------------- 1 | const fontWeight = (weight) => `font-weight: ${weight};`; 2 | 3 | export const bodyFont = ` 4 | font-family: 'PT Sans', sans-serif; 5 | ${fontWeight(400)} 6 | `; 7 | 8 | export const codeFont = ` 9 | font-family: 'Inconsolata', monospace; 10 | ${fontWeight(400)} 11 | `; 12 | 13 | export const fontSize = (size) => ` 14 | font-size: ${size}px; 15 | `; 16 | 17 | export const fontBold = `font-weight: 700;`; 18 | 19 | export const lineHeight = (height) => `line-height: ${height}px;`; 20 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribute to Popmotion 2 | 3 | ## Team members (plural not plural) 4 | 5 | - Matt Perry [mailto:sirhound@popmotion.io](sirhound@popmotion.io) 6 | 7 | ## Learn 8 | 9 | - [API](http://popmotion.io/api) 10 | - [Twitter](http://twitter.com/popmotionjs) 11 | 12 | ## Contributing 13 | 14 | If you want to add a feature directly to Popmotion, get in touch and we can talk about the best place for it. 15 | 16 | For bugfixes, try and keep within the style established throughout the codebase, and then just open a pull request! 17 | -------------------------------------------------------------------------------- /packages/popmotion/src/input/pointer/utils.ts: -------------------------------------------------------------------------------- 1 | import { PointerPoint } from './types'; 2 | 3 | export const defaultPointerPos = (): PointerPoint => ({ 4 | clientX: 0, 5 | clientY: 0, 6 | pageX: 0, 7 | pageY: 0, 8 | x: 0, 9 | y: 0 10 | }); 11 | 12 | export const eventToPoint = (e: Touch | MouseEvent, point: PointerPoint = defaultPointerPos()): PointerPoint => { 13 | point.clientX = point.x = e.clientX; 14 | point.clientY = point.y = e.clientY; 15 | point.pageX = e.pageX; 16 | point.pageY = e.pageY; 17 | return point; 18 | }; 19 | -------------------------------------------------------------------------------- /packages/popmotion/src/input/pointer/types.ts: -------------------------------------------------------------------------------- 1 | export type PointerPoint = { 2 | clientX: number, 3 | clientY: number, 4 | pageX: number, 5 | pageY: number, 6 | x: number, 7 | y: number 8 | }; 9 | 10 | export type Point2D = { 11 | x: number, 12 | y: number 13 | }; 14 | 15 | export type Point3D = Point2D & { 16 | z: number 17 | }; 18 | 19 | export type Point = Point2D | Point3D; 20 | 21 | export type PointerProps = { 22 | x?: number, 23 | y?: number, 24 | preventDefault?: boolean, 25 | scale?: number, 26 | rotate?: number 27 | }; 28 | -------------------------------------------------------------------------------- /packages/react-360-pose/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | React Native Pose adheres to [Semantic Versioning](http://semver.org/). 4 | 5 | ## [0.1.0] 2018-04-24 6 | 7 | - No one's betting the farm on "0.0.5" 8 | 9 | ## [0.0.5] 2018-04-24 10 | 11 | - Intelligent handling of `useNativeDriver`. 12 | 13 | ## [0.0.4] 2018-04-24 14 | 15 | - Updating `animated-pose`. 16 | 17 | ## [0.0.3] 2018-04-24 18 | 19 | - Updating `pose-core`. 20 | 21 | ## [0.0.2] 2018-04-23 22 | 23 | - Not firing `dragEnd` pose until offset prep. 24 | 25 | ## [0.0.1] 2018-04-23 26 | 27 | - First publish 28 | -------------------------------------------------------------------------------- /site/components/examples/Swatch.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | import { ActionButton } from '~/templates/global/styled'; 3 | 4 | const Container = styled.div` 5 | height: 100%; 6 | display: flex; 7 | flex-direction: column; 8 | justify-content: space-around; 9 | align-content: space-around; 10 | `; 11 | const Swatch = styled.div` 12 | flex: 0 0 30%; 13 | `; 14 | 15 | export default ({ start, id }) => ( 16 | 17 | 18 | Start 19 | 20 | ); 21 | -------------------------------------------------------------------------------- /playground/plugins/draggable.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Box } from '../inc'; 3 | import draggable from '../../packages/popmotion-draggable/lib'; 4 | import Draggable from '../../packages/popmotion-draggable/lib/react'; 5 | 6 | export class DraggableDOM extends React.Component { 7 | setRef = (dom) => { 8 | if (!dom) dom; 9 | this.box = draggable(dom); 10 | }; 11 | 12 | render() { 13 | return ; 14 | } 15 | } 16 | 17 | export const DraggableReact = () => ( 18 | 19 | 20 | 21 | ); 22 | -------------------------------------------------------------------------------- /playground/plugins/spinnable.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Box } from '../inc'; 3 | import spinnable from '../../packages/popmotion-spinnable/lib'; 4 | import Spinnable from '../../packages/popmotion-spinnable/lib/react'; 5 | 6 | export class SpinnableDOM extends React.Component { 7 | setRef = (dom) => { 8 | if (!dom) dom; 9 | this.box = spinnable(dom); 10 | }; 11 | 12 | render() { 13 | return ; 14 | } 15 | } 16 | 17 | export const SpinnableReact = () => ( 18 | 19 | 20 | 21 | ); 22 | -------------------------------------------------------------------------------- /packages/popmotion/src/animations/keyframes/types.ts: -------------------------------------------------------------------------------- 1 | import { Easing } from '../../easing'; 2 | 3 | export type ValueMap = { 4 | [key: string]: string | number 5 | }; 6 | 7 | export type ValueList = string|number[]; 8 | 9 | export type Values = number[] | string[] | ValueMap[] | ValueList[]; 10 | 11 | export type KeyframeProps = { 12 | values: Values, 13 | times?: number[], 14 | ease?: Easing | Easing[] | { [key: string]: Easing }, 15 | easings?: Easing[], 16 | elapsed?: number, 17 | duration?: number, 18 | loop?: number, 19 | flip?: number, 20 | yoyo?: number 21 | }; 22 | -------------------------------------------------------------------------------- /site/templates/global/Analytics.js: -------------------------------------------------------------------------------- 1 | const analyticsCode = ` 2 | (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ 3 | (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), 4 | m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) 5 | })(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); 6 | 7 | ga('create', 'UA-3215563-7', 'auto'); 8 | ga('send', 'pageview'); 9 | `; 10 | 11 | export default () => ( 12 | 4 | 11 | 12 | 13 |
14 | 27 | 28 | -------------------------------------------------------------------------------- /packages/popmotion-spinnable/src/react.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import spinnable from './'; 3 | 4 | export default class Spinnable extends React.Component { 5 | constructor(props) { 6 | super(props); 7 | this.setRef = (ref) => { 8 | if (ref) { 9 | const { friction, onSpin, transformSpin } = this.props; 10 | this.spin = spinnable(ref, { friction, onSpin, transformSpin }); 11 | } 12 | }; 13 | } 14 | 15 | componentWillUnmount() { 16 | this.spin.stop(); 17 | } 18 | 19 | render() { 20 | const { children, className } = this.props; 21 | 22 | return ( 23 |
24 | {children} 25 |
26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /packages/popmotion/src/compositors/stagger.ts: -------------------------------------------------------------------------------- 1 | import { Action } from '../action'; 2 | import chain from './chain'; 3 | import delay from './delay'; 4 | import parallel from './parallel'; 5 | 6 | type IntervalCalc = (i: number) => number; 7 | type Interval = number | IntervalCalc; 8 | 9 | const stagger = (actions: Action[], interval: Interval): Action => { 10 | const intervalIsNumber = typeof interval === 'number'; 11 | 12 | const actionsWithDelay = actions.map((a, i) => { 13 | const timeToDelay: number = intervalIsNumber ? interval as number * i : (interval as IntervalCalc)(i); 14 | 15 | return chain(delay(timeToDelay), a); 16 | }); 17 | 18 | return parallel(...actionsWithDelay); 19 | }; 20 | 21 | export default stagger; 22 | -------------------------------------------------------------------------------- /packages/react-pose/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "noImplicitAny": false, 5 | "removeComments": true, 6 | "preserveConstEnums": true, 7 | "sourceMap": true, 8 | "noUnusedLocals": true, 9 | "target": "es5", 10 | "rootDir": "src", 11 | "outDir": "lib", 12 | "watch": false, 13 | "baseUrl": "src/", 14 | "alwaysStrict": true, 15 | "declaration": true, 16 | "forceConsistentCasingInFileNames": true, 17 | "allowSyntheticDefaultImports": true, 18 | "lib": ["es6", "dom"], 19 | "jsx": "react", 20 | "typeRoots": ["node_modules/@types", "module-types"] 21 | }, 22 | "include": [ 23 | "src/**/*" 24 | ], 25 | "exclude": [ 26 | "**/*.test.ts" 27 | ] 28 | } -------------------------------------------------------------------------------- /playground/plugins/react.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Box } from '../inc'; 3 | import pointer from '../../packages/popmotion/lib/input/pointer'; 4 | import { MotionValue } from '../../packages/popmotion-react/lib'; 5 | 6 | const stateChangeHandlers = { 7 | isDragging: ({ value }) => pointer(value.get()).start(value), 8 | rest: ({ value }) => value.stop() 9 | }; 10 | 11 | export const PopmotionReact = () => ( 12 | 13 | {({ v, setStateTo }) => ( 14 | 19 | )} 20 | 21 | ); 22 | -------------------------------------------------------------------------------- /site/components/examples/Counter.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | import { ActionButton } from '~/templates/global/styled'; 3 | import { fontBold } from '~/styles/fonts'; 4 | 5 | const CounterContainer = styled.div` 6 | height: 100%; 7 | display: flex; 8 | flex-direction: column; 9 | justify-content: space-around; 10 | align-content: space-around; 11 | `; 12 | const Counter = styled.span` 13 | font-size: 42px; 14 | text-align: center; 15 | ${fontBold} 16 | `; 17 | 18 | export default ({ code, autostart, start, id }) => ( 19 | 20 | 0 21 | {!autostart ? ( 22 | Start 23 | ) : null} 24 | 25 | ); 26 | -------------------------------------------------------------------------------- /packages/popmotion/src/compositors/parallel.ts: -------------------------------------------------------------------------------- 1 | import multi from './multi'; 2 | import { Action } from '../action'; 3 | import { ColdSubscription } from '../action/types'; 4 | 5 | const parallel = multi({ 6 | getOutput: () => ([]), 7 | getCount: (subs) => subs.length, 8 | getFirst: (subs) => subs[0], 9 | mapApi: (subs, methodName) => (...args) => subs.map((sub, i) => { 10 | if (sub[methodName]) { 11 | return Array.isArray(args[0]) 12 | ? sub[methodName](args[0][i]) 13 | : sub[methodName](...args); 14 | } 15 | }), 16 | setProp: (output, name, v) => output[name] = v, 17 | startActions: (actions, starter) => actions.map((action, i) => starter(action, i)) 18 | }); 19 | 20 | export default (...actions: Action[]) => parallel(actions); 21 | -------------------------------------------------------------------------------- /packages/popmotion/src/animations/tween/scrubber.ts: -------------------------------------------------------------------------------- 1 | import { number } from 'style-value-types'; 2 | import action, { Action } from '../../action'; 3 | import vectorAction from '../../action/vector'; 4 | import { getValueFromProgress } from '../../calc'; 5 | import { linear } from '../../easing'; 6 | 7 | export type ScrubberSubscription = { 8 | seek: (progress: number) => any 9 | }; 10 | 11 | const scrubber = ({ from = 0, to = 1, ease = linear }): Action => 12 | action(({ update }): ScrubberSubscription => ({ 13 | seek: (progress) => update(progress) 14 | })).pipe( 15 | ease, 16 | (v: number) => getValueFromProgress(from, to, v) 17 | ); 18 | 19 | export default vectorAction(scrubber, { 20 | ease: (func: any) => typeof func === 'function', 21 | from: number.test, 22 | to: number.test 23 | }); 24 | -------------------------------------------------------------------------------- /packages/popmotion-pose/src/factories/dimensions.ts: -------------------------------------------------------------------------------- 1 | import { BoundingBox, Dimensions } from '../types'; 2 | 3 | export default (element: Element): Dimensions => { 4 | let hasMeasured = false; 5 | let current: BoundingBox = { 6 | width: 0, 7 | height: 0, 8 | top: 0, 9 | left: 0, 10 | bottom: 0, 11 | right: 0 12 | }; 13 | 14 | return { 15 | get: measurement => (measurement ? current[measurement] : current), 16 | measure: () => { 17 | current = element.getBoundingClientRect(); 18 | hasMeasured = true; 19 | return current; 20 | }, 21 | measurementAsPixels: (measurement, value) => 22 | typeof value === 'string' 23 | ? parseFloat(value as string) / 100 * current[measurement] 24 | : (value as number), 25 | has: () => hasMeasured 26 | }; 27 | }; 28 | -------------------------------------------------------------------------------- /packages/popmotion/src/animations/tween/types.ts: -------------------------------------------------------------------------------- 1 | import { Value } from '../../reactions/value'; 2 | import { Easing } from '../../easing'; 3 | 4 | export type TweenProps = { 5 | from?: Value, 6 | to?: Value, 7 | duration?: number, 8 | ease?: Easing | Easing[] | { [key: string]: Easing }, 9 | elapsed?: number, 10 | playDirection?: number, 11 | flip?: number, 12 | flipCount?: number, 13 | loop?: number, 14 | loopCount?: number, 15 | yoyo?: number, 16 | yoyoCount?: number 17 | }; 18 | 19 | export type TweenInterface = { 20 | isActive: () => boolean, 21 | stop: () => void, 22 | getProgress: () => number, 23 | getElapsed: () => number, 24 | pause: () => TweenInterface, 25 | resume: () => TweenInterface, 26 | seek: (progress: number) => TweenInterface, 27 | reverse: () => TweenInterface 28 | }; 29 | -------------------------------------------------------------------------------- /packages/popmotion-pose/src-core/factories/dimensions.ts: -------------------------------------------------------------------------------- 1 | import { BoundingBox, Dimensions } from '../types'; 2 | 3 | export default (element: Element): Dimensions => { 4 | let hasMeasured = false; 5 | let current: BoundingBox = { 6 | width: 0, 7 | height: 0, 8 | top: 0, 9 | left: 0, 10 | bottom: 0, 11 | right: 0 12 | }; 13 | 14 | return { 15 | get: measurement => (measurement ? current[measurement] : current), 16 | measure: () => { 17 | current = element.getBoundingClientRect(); 18 | hasMeasured = true; 19 | return current; 20 | }, 21 | measurementAsPixels: (measurement, value) => 22 | typeof value === 'string' 23 | ? parseFloat(value as string) / 100 * current[measurement] 24 | : (value as number), 25 | has: () => hasMeasured 26 | }; 27 | }; 28 | -------------------------------------------------------------------------------- /site/templates/Popmotion/FinalCTA/index.js: -------------------------------------------------------------------------------- 1 | import { Container, ContentContainer } from './styled'; 2 | import { BlurbText } from '~/templates/Popmotion/USPs/styled'; 3 | import { CTA } from '../Masthead/styled'; 4 | import Link from 'next/link'; 5 | 6 | export default () => ( 7 | 8 | 9 | 10 | Pick and choose any part of Popmotion by importing modules individually. 11 | 12 | 13 | Or take it all for 11.5kb! 14 | 15 | 16 | 17 | Get started 18 | 19 | 20 | 21 | 22 | ); 23 | -------------------------------------------------------------------------------- /packages/blend-tweens/cross-fade.js: -------------------------------------------------------------------------------- 1 | import Action from './'; 2 | import tween from './tween'; 3 | import { linear } from '../inc/easing'; 4 | import { getValueFromProgress } from '../inc/calc'; 5 | 6 | class CrossFade extends Action { 7 | static defaultProps = { 8 | ease: linear 9 | } 10 | 11 | onStart() { 12 | const { duration, ease, fader } = this.props; 13 | 14 | this.fader = fader || tween({ 15 | to: 1, 16 | duration, 17 | ease 18 | }).start(); 19 | } 20 | 21 | update() { 22 | const { from, to } = this.props; 23 | const balance = this.fader.get(); 24 | const latestFromValue = from.get(); 25 | const latestToValue = to.get(); 26 | return getValueFromProgress(latestFromValue, latestToValue, balance); 27 | } 28 | } 29 | 30 | export default (props) => new CrossFade(props); 31 | -------------------------------------------------------------------------------- /packages/animated-pose/src/index.ts: -------------------------------------------------------------------------------- 1 | import { Animated } from 'react-native'; 2 | import { Poser, PoserConfig } from 'pose-core'; 3 | import { convertUnitToPoints, unitConverters } from './inc/unit-conversion'; 4 | import animatedPoseFactory from './factory'; 5 | import { 6 | AnimatedPoser, 7 | AnimatedPoseConfig, 8 | AnimatedPoserFactory 9 | } from './types'; 10 | 11 | const nativePose = animatedPoseFactory({ convertUnitToPoints, unitConverters }); 12 | 13 | const vrPose = animatedPoseFactory({ 14 | convertUnitToPoints: (v: string) => parseFloat(v), 15 | unitConverters: {} 16 | }); 17 | 18 | export default nativePose; 19 | export { vrPose }; 20 | 21 | // Export types 22 | Animated; //tslint:disable-line 23 | export { 24 | Poser, 25 | PoserConfig, 26 | AnimatedPoser, 27 | AnimatedPoseConfig, 28 | AnimatedPoserFactory 29 | }; 30 | -------------------------------------------------------------------------------- /packages/react-native-pose/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | React Native Pose adheres to [Semantic Versioning](http://semver.org/). 4 | 5 | ## [0.2.1] 2018-05-08 6 | 7 | - Release 8 | 9 | ## [0.2.0@rc] 2018-05-08 10 | 11 | - Migrate to React Pose Core 12 | - Ensure `useNativeDriver` is disabled if *any* other animated value in the same poser is attached by a non-native value like `backgroundColor`. 13 | 14 | ## [0.1.0] 2018-04-24 15 | 16 | - No one's betting the farm on "0.0.5" 17 | 18 | ## [0.0.5] 2018-04-24 19 | 20 | - Intelligent handling of `useNativeDriver`. 21 | 22 | ## [0.0.4] 2018-04-24 23 | 24 | - Updating `animated-pose`. 25 | 26 | ## [0.0.3] 2018-04-24 27 | 28 | - Updating `pose-core`. 29 | 30 | ## [0.0.2] 2018-04-23 31 | 32 | - Not firing `dragEnd` pose until offset prep. 33 | 34 | ## [0.0.1] 2018-04-23 35 | 36 | - First publish 37 | -------------------------------------------------------------------------------- /site/components/icons/PopmotionIcon.js: -------------------------------------------------------------------------------- 1 | import BrandGradient from "./BrandGradientDef"; 2 | 3 | export default ({ className, width = 41, height = 37 }) => ( 4 | 11 | 12 | 13 | 20 | 24 | 25 | 26 | ); 27 | -------------------------------------------------------------------------------- /packages/react-360-pose/README.md: -------------------------------------------------------------------------------- 1 | # React 360 Pose 2 | 3 | ## Pose animation system in React 360 flavour 4 | 5 | [![npm version](https://img.shields.io/npm/v/react-360-pose.svg?style=flat-square)](https://www.npmjs.com/package/react-360-pose) 6 | [![npm downloads](https://img.shields.io/npm/dm/react-360-pose.svg?style=flat-square)](https://www.npmjs.com/package/react-360-pose) 7 | [![Twitter Follow](https://img.shields.io/twitter/follow/popmotionjs.svg?style=social&label=Follow)](http://twitter.com/popmotionjs) 8 | [![Join the community on Spectrum](https://withspectrum.github.io/badge/badge.svg)](https://spectrum.chat/popmotion) 9 | 10 | Waiting on React 360 to support `createContext`. 11 | -------------------------------------------------------------------------------- /site/styles/nprogress.js: -------------------------------------------------------------------------------- 1 | import { BRAND } from '~/styles/vars'; 2 | 3 | export default ` 4 | /* Make clicks pass-through */ 5 | #nprogress { 6 | pointer-events: none; 7 | } 8 | 9 | #nprogress .bar { 10 | background: ${BRAND}; 11 | position: fixed; 12 | z-index: 9999; 13 | top: 0; 14 | left: 0; 15 | width: 100%; 16 | height: 2px; 17 | } 18 | 19 | /* Fancy blur effect */ 20 | #nprogress .peg { 21 | display: block; 22 | position: absolute; 23 | right: 0px; 24 | width: 100px; 25 | height: 100%; 26 | box-shadow: 0 0 10px ${BRAND}, 0 0 5px ${BRAND}; 27 | opacity: 1.0; 28 | 29 | -webkit-transform: rotate(3deg) translate(0px, -4px); 30 | -ms-transform: rotate(3deg) translate(0px, -4px); 31 | transform: rotate(3deg) translate(0px, -4px); 32 | } 33 | 34 | 35 | .nprogress-custom-parent #nprogress .bar { 36 | position: absolute; 37 | } 38 | `; 39 | -------------------------------------------------------------------------------- /packages/popmotion/src/observer/types.ts: -------------------------------------------------------------------------------- 1 | export type Update = Function; 2 | export type Complete = () => any; 3 | export type Error = (err?: any) => any; 4 | export type ObserverEvent = (type?: string, v?: any) => any; 5 | export type Middleware = (update: Update, complete?: Complete) => (v: any) => any; 6 | 7 | export interface IObserver { 8 | update: Update; 9 | complete: Complete; 10 | error: Error; 11 | } 12 | 13 | export interface PartialObserver { 14 | update?: Update; 15 | complete?: Complete; 16 | error?: Error; 17 | registerParent?: Function; 18 | } 19 | 20 | export type ObserverProps = PartialObserver & { 21 | middleware?: Middleware[]; 22 | onComplete?: Function; 23 | }; 24 | 25 | export type ObserverFactory = (observerCandidate: ObserverCandidate, props: ObserverProps) => IObserver; 26 | 27 | export type ObserverCandidate = Update | IObserver | PartialObserver; 28 | -------------------------------------------------------------------------------- /site/components/examples/Ball.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | import { ActionButton } from '~/templates/global/styled'; 3 | import { verticalGradient, PINK, PINK_BURN, cols } from '~/styles/vars'; 4 | 5 | const Container = styled.div` 6 | height: 100%; 7 | width: 100%; 8 | display: flex; 9 | flex-direction: column; 10 | justify-content: space-around; 11 | align-content: space-around; 12 | padding: ${cols(1)} 13 | `; 14 | 15 | const Box = styled.span` 16 | width: 50px; 17 | height: 50px; 18 | background: ${verticalGradient(PINK, PINK_BURN)}; 19 | border-radius: 50px; 20 | `; 21 | 22 | export default ({ autostart, start, id }) => ( 23 | 24 | 25 | {!autostart ? ( 26 | Start 27 | ) : null} 28 | 29 | ); 30 | -------------------------------------------------------------------------------- /packages/pose-core/src/factories/transitions.ts: -------------------------------------------------------------------------------- 1 | import { PoseMap, Pose, TransitionFactory } from '../types'; 2 | 3 | type DefaultTransitions = Map>; 4 | 5 | const applyDefaultTransition = (pose: Pose, key: string, defaultTransitions: DefaultTransitions): Pose => { 6 | return { 7 | ...pose, 8 | transition: defaultTransitions.has(key) 9 | ? defaultTransitions.get(key) 10 | : defaultTransitions.get('default') 11 | }; 12 | }; 13 | 14 | const generateTransitions = (poses: PoseMap, defaultTransitions: DefaultTransitions): PoseMap => { 15 | Object.keys(poses).forEach(key => { 16 | const pose = poses[key]; 17 | poses[key] = pose.transition 18 | ? pose 19 | : applyDefaultTransition(pose, key, defaultTransitions) 20 | }); 21 | 22 | return poses; 23 | } 24 | 25 | export default generateTransitions; 26 | -------------------------------------------------------------------------------- /packages/pose-core/src/inc/selectors.ts: -------------------------------------------------------------------------------- 1 | import { Pose, PoseMap, PoserConfig, ValueMap, SelectValueToRead } from '../types'; 2 | 3 | export const getPoseValues = ({ 4 | transition, 5 | delay, 6 | delayChildren, 7 | staggerChildren, 8 | staggerDirection, 9 | afterChildren, 10 | beforeChildren, 11 | preTransition, 12 | ...props 13 | }: Pose): Pose => props; 14 | 15 | export const selectPoses = ({ 16 | label, 17 | props, 18 | values, 19 | parentValues, 20 | ancestorValues, 21 | onChange, 22 | passive, 23 | initialPose, 24 | ...poses 25 | }: PoserConfig): PoseMap => poses; 26 | 27 | export const selectAllValues = (values: ValueMap, selectValue: SelectValueToRead) => { 28 | const allValues: { [key: string]: any } = {}; 29 | values.forEach((value: V, key: string) => allValues[key] = selectValue(value)); 30 | return allValues; 31 | }; 32 | -------------------------------------------------------------------------------- /site/templates/global/SocialLinks.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import styled from "styled-components"; 3 | import GitHub from "~/components/icons/GitHub"; 4 | import Twitter from "~/components/icons/Twitter"; 5 | import settings from "~/data/settings.json"; 6 | import { cols, media } from "~/styles/vars"; 7 | 8 | const IconLink = styled.a` 9 | margin-left: ${cols(1)}; 10 | `; 11 | 12 | const TwitterLink = IconLink.extend` 13 | margin-left: none; 14 | transform: translateY(2px); 15 | `; 16 | 17 | const GitHubIcon = styled(GitHub)``; 18 | const TwitterIcon = styled(Twitter)``; 19 | 20 | export default () => ( 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | ); 30 | -------------------------------------------------------------------------------- /packages/pose-core/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | Pose Core adheres to [Semantic Versioning](http://semver.org/). 4 | 5 | ## [0.3.0] 2018-05-06 6 | 7 | - Passing `props` through to `createValue` to allow it be mutated for special cases. 8 | 9 | ## [0.2.0] 2018-05-05 10 | 11 | - Passing through all transition props to `getInstantTransition` 12 | 13 | ## [0.1.7] 2018-04-24 14 | 15 | - Adding `key` to `createValue`. 16 | 17 | ## [0.1.6] 2018-04-24 18 | 19 | - Adding `setProps`. 20 | 21 | ## [0.1.5] 2018-04-23 22 | 23 | - Making config types optional. 24 | 25 | ## [0.1.4] 2018-04-22 26 | 27 | - `scale` values default to `1`. 28 | 29 | ## [0.1.3] 2018-04-22 30 | 31 | - Fixing `delay` 32 | 33 | ## [0.1.2] 2018-04-22 34 | 35 | - Adding `initialPose` to `addChild`. 36 | 37 | ## [0.1.1] 2018-04-22 38 | 39 | - Adding lifecycle method for preTransition 40 | 41 | ## [0.0.1] 2018-04-18 42 | 43 | - First publish 44 | -------------------------------------------------------------------------------- /packages/animated-pose/src/inc/unit-conversion.ts: -------------------------------------------------------------------------------- 1 | import { Dimensions } from 'react-native'; 2 | import { DimensionConverterFactory, UnitConverterMap } from '../types'; 3 | 4 | export const getUnit = (str: string): string => 5 | str.replace(str.match(/\d+/)[0], '').replace('-', ''); 6 | 7 | const dimensionConverter: DimensionConverterFactory = (viewport, axis) => ( 8 | target: number 9 | ) => target / 100 * Dimensions.get(viewport)[axis]; 10 | 11 | export const unitConverters: UnitConverterMap = { 12 | vh: dimensionConverter('window', 'height'), 13 | vw: dimensionConverter('window', 'width'), 14 | sh: dimensionConverter('screen', 'height'), 15 | sw: dimensionConverter('screen', 'width') 16 | }; 17 | 18 | export const convertUnitToPoints = (target: string) => { 19 | const unit = getUnit(target); 20 | const num = parseFloat(target); 21 | 22 | return unitConverters[unit] ? unitConverters[unit](num) : num; 23 | }; 24 | -------------------------------------------------------------------------------- /packages/react-pose/README.md: -------------------------------------------------------------------------------- 1 | # React Pose 2 | 3 | ## React components for the Pose animation system 4 | 5 | [![npm version](https://img.shields.io/npm/v/react-pose.svg?style=flat-square)](https://www.npmjs.com/package/react-pose) 6 | [![npm downloads](https://img.shields.io/npm/dm/react-pose.svg?style=flat-square)](https://www.npmjs.com/package/react-pose) 7 | [![Twitter Follow](https://img.shields.io/twitter/follow/popmotionjs.svg?style=social&label=Follow)](http://twitter.com/popmotionjs) 8 | [![Join the community on Spectrum](https://withspectrum.github.io/badge/badge.svg)](https://spectrum.chat/popmotion) 9 | 10 | - [Homepage](https://popmotion.io/pose) 11 | - [API](https://popmotion.io/pose/api) 12 | - [Get started](https://popmotion.io/pose/learn/get-started) 13 | -------------------------------------------------------------------------------- /packages/popmotion/src/animations/decay/_tests/decay.test.ts: -------------------------------------------------------------------------------- 1 | import inertia from '../'; 2 | 3 | describe('inertia', () => { 4 | it('should progress to calculated target', () => { 5 | return new Promise((resolve, reject) => { 6 | let i = 0; 7 | let target = 0; 8 | inertia({ 9 | velocity: 100, 10 | modifyTarget: (v) => target = v 11 | }).start({ 12 | complete: () => (i === target) ? resolve() : reject(), 13 | update: (v) => i = v 14 | }); 15 | }); 16 | }); 17 | 18 | it('should progress to modified target', () => { 19 | return new Promise((resolve, reject) => { 20 | let i = 0; 21 | let target = 0; 22 | inertia({ 23 | velocity: 100, 24 | modifyTarget: (v) => target = 100 25 | }).start({ 26 | complete: () => (i === 100) ? resolve() : reject(), 27 | update: (v) => i = v 28 | }); 29 | }); 30 | }); 31 | }); -------------------------------------------------------------------------------- /playground/decay.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { BaseAnimation } from './inc'; 3 | import decay from '../packages/popmotion/lib/animations/decay'; 4 | 5 | export class Decay extends BaseAnimation { 6 | getAnimation = (styler) => decay({ 7 | velocity: 1000 8 | }).start((v) => styler.set('x', v)); 9 | } 10 | 11 | export class DecayModifyTarget extends BaseAnimation { 12 | getAnimation = (styler) => decay({ 13 | velocity: 1000, 14 | modifyTarget: (v) => Math.ceil(v / 100) * 100 15 | }).start((v) => styler.set('x', v)); 16 | } 17 | 18 | export class DecayTimeConstant extends BaseAnimation { 19 | getAnimation = (styler) => decay({ 20 | velocity: 1000, 21 | timeConstant: 1000 22 | }).start((v) => styler.set('x', v)); 23 | } 24 | 25 | export class DecayPower extends BaseAnimation { 26 | getAnimation = (styler) => decay({ 27 | velocity: 1000, 28 | power: 2 29 | }).start((v) => styler.set('x', v)); 30 | } -------------------------------------------------------------------------------- /packages/popmotion/docs/api/compositors/delay.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Delay 3 | description: Fires complete after the defined interval. 4 | category: compositors 5 | --- 6 | 7 | # Delay 8 | 9 | Fires `complete` after the defined interval. 10 | 11 | ## Import 12 | 13 | ```javascript 14 | import { delay } from 'popmotion'; 15 | // or stand-alone: 16 | import delay from 'popmotion/compositors/delay'; 17 | ``` 18 | 19 | ## Usage 20 | 21 | ```javascript 22 | delay(100).start({ 23 | complete: () => console.log('complete!') 24 | }); 25 | ``` 26 | 27 | Useful for delaying actions in a `chain`. 28 | 29 | ```javascript 30 | chain( 31 | delay(100), 32 | tween({ to: 400, duration: 500 }) 33 | ); 34 | ``` 35 | 36 | ### Action methods 37 | 38 | `delay()` returns: 39 | 40 | - `start(update | { update, complete })`: Starts the action and returns a subscription. 41 | 42 | ### Subscription methods 43 | 44 | `delay().start()` returns: 45 | 46 | - `stop(): void` 47 | -------------------------------------------------------------------------------- /site/templates/Popmotion/Masthead/index.js: -------------------------------------------------------------------------------- 1 | import { withTheme } from "styled-components"; 2 | import SiteLink from "~/components/layout/SiteLink"; 3 | import { 4 | Container, 5 | MastheadContainer, 6 | Title, 7 | Logo, 8 | LogoContainer, 9 | LogoText, 10 | Blurb, 11 | CTA 12 | } from "./styled"; 13 | import Link from "next/link"; 14 | 15 | const Masthead = ({ children, theme }) => ( 16 | 17 | {children} 18 | 19 | 20 | <LogoText>{theme.name}</LogoText> 21 | <LogoContainer {...theme.homepageLogoSize}> 22 | <theme.Logo id="homepage-logo" /> 23 | </LogoContainer> 24 | 25 | {theme.tagline} 26 | 27 | 28 | Quick start 29 | 30 | 31 | 32 | 33 | ); 34 | 35 | export default withTheme(Masthead); 36 | -------------------------------------------------------------------------------- /site/pages/_error.js: -------------------------------------------------------------------------------- 1 | import Header from '~/templates/global/Header'; 2 | import Footer from '~/templates/global/Footer'; 3 | import content from '~/data/content.json'; 4 | import menus from '~/data/menus.json'; 5 | import Link from 'next/link'; 6 | import GlobalTemplate from '~/templates/global/Template'; 7 | import { ArticleHeader, P } from '~/templates/global/styled'; 8 | 9 | export default () => ( 10 | 11 |
12 | Page Not Found 13 |

You were probably looking for the Popmotion 7 docs.

14 |

Or, if you're ready to upgrade, check out our Popmotion 8 upgrade guide!

15 | 16 | ); 17 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | **Describe the bug** 8 | A clear and concise description of what the bug is. 9 | 10 | **To Reproduce** 11 | Steps to reproduce the behavior: 12 | 1. Go to '...' 13 | 2. Click on '....' 14 | 3. Scroll down to '....' 15 | 4. See error 16 | 17 | **Expected behavior** 18 | A clear and concise description of what you expected to happen. 19 | 20 | **Screenshots** 21 | If applicable, add screenshots to help explain your problem. 22 | 23 | **Desktop (please complete the following information):** 24 | - OS: [e.g. iOS] 25 | - Browser [e.g. chrome, safari] 26 | - Version [e.g. 22] 27 | 28 | **Smartphone (please complete the following information):** 29 | - Device: [e.g. iPhone6] 30 | - OS: [e.g. iOS8.1] 31 | - Browser [e.g. stock browser, safari] 32 | - Version [e.g. 22] 33 | 34 | **Additional context** 35 | Add any other context about the problem here. 36 | -------------------------------------------------------------------------------- /packages/popmotion-pose/src-core/types.ts: -------------------------------------------------------------------------------- 1 | import { ValueType } from 'style-value-types'; 2 | import { PoserConfig } from '../../pose-core/src'; 3 | import { ValueReaction } from 'popmotion/reactions/value'; 4 | import { ColdSubscription } from 'popmotion/action/types'; 5 | 6 | export type PopmotionPoserConfig = { 7 | draggable?: boolean | 'x' | 'y'; 8 | element: Element; 9 | } & PoserConfig; 10 | 11 | export type Dimensions = { 12 | get: (measurement?: BoundingBoxDimension) => BoundingBox | number; 13 | measurementAsPixels: ( 14 | measurement: BoundingBoxDimension, 15 | value: string | number, 16 | type?: ValueType 17 | ) => number; 18 | measure: () => void; 19 | has: () => boolean; 20 | }; 21 | 22 | export type BoundingBox = { [key in BoundingBoxDimension]: number }; 23 | 24 | export enum BoundingBoxDimension { 25 | width = 'width', 26 | height = 'height', 27 | left = 'left', 28 | right = 'right', 29 | top = 'top', 30 | bottom = 'bottom' 31 | } 32 | -------------------------------------------------------------------------------- /packages/popmotion-pose/src/inc/selectors.ts: -------------------------------------------------------------------------------- 1 | import { PoserProps, PoseMap, Pose, DragProps } from '../types'; 2 | 3 | export type PoseSelector = (props: PoserProps) => PoseMap; 4 | export type PoseValuesSelector = (props: Pose) => Pose; 5 | export type DragPropsSelector = (props: PoserProps) => DragProps; 6 | 7 | export const getPoses: PoseSelector = ({ 8 | draggable, 9 | initialPose, 10 | passive, 11 | onChange, 12 | dragBounds, 13 | onDragStart, 14 | onDragEnd, 15 | label, 16 | ancestorValues, 17 | parentValues, 18 | values, 19 | transitionProps, 20 | ...poses 21 | }) => poses; 22 | 23 | export const getPoseValues: PoseValuesSelector = ({ 24 | transition, 25 | delay, 26 | delayChildren, 27 | staggerChildren, 28 | staggerDirection, 29 | afterChildren, 30 | beforeChildren, 31 | ...props 32 | }) => props; 33 | 34 | export const getDragProps: DragPropsSelector = ({ 35 | dragBounds, 36 | onDragStart, 37 | onDragEnd 38 | }) => ({ dragBounds, onDragEnd, onDragStart }); 39 | -------------------------------------------------------------------------------- /packages/popmotion/README.md: -------------------------------------------------------------------------------- 1 | # Popmotion 2 | 3 | ### A **functional**, **reactive** motion library. 4 | 5 | [![npm version](https://img.shields.io/npm/v/popmotion.svg?style=flat-square)](https://www.npmjs.com/package/popmotion) 6 | [![npm downloads](https://img.shields.io/npm/dm/popmotion.svg?style=flat-square)](https://www.npmjs.com/package/popmotion) 7 | [![Twitter Follow](https://img.shields.io/twitter/follow/popmotionjs.svg?style=social&label=Follow)](http://twitter.com/popmotionjs) 8 | [![Join the community on Spectrum](https://withspectrum.github.io/badge/badge.svg)](https://spectrum.chat/popmotion) 9 | 10 | ## [Visit the website](https://popmotion.io/) 11 | ### [Quick Start](https://popmotion.io/learn/get-started) 12 | ### [Installation options](https://popmotion.io/learn/install) 13 | ### [Full API documentation](https://popmotion.io/api) 14 | -------------------------------------------------------------------------------- /packages/popmotion/src/input/pointer/index.ts: -------------------------------------------------------------------------------- 1 | import { Action } from '../../action'; 2 | import { applyOffset } from '../../transformers'; 3 | import multitouch, { getIsTouchDevice } from '../multitouch'; 4 | import mouse from './mouse'; 5 | import { Point2D, PointerProps } from './types'; 6 | 7 | const getFirstTouch = ([firstTouch]: Point2D[]): Point2D => firstTouch; 8 | 9 | const pointer = (props: PointerProps = {}): Action => getIsTouchDevice() 10 | ? multitouch(props).pipe(({ touches }: any) => touches, getFirstTouch) 11 | : mouse(props); 12 | 13 | export default ({ x, y, ...props }: PointerProps = {}): Action => { 14 | if (x !== undefined || y !== undefined) { 15 | const applyXOffset = applyOffset(x || 0); 16 | const applyYOffset = applyOffset(y || 0); 17 | const delta = { x: 0, y: 0 }; 18 | 19 | return pointer(props).pipe((point: Point2D) => { 20 | delta.x = applyXOffset(point.x); 21 | delta.y = applyYOffset(point.y); 22 | return delta; 23 | }); 24 | } else { 25 | return pointer(props); 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /packages/pose-core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pose-core", 3 | "version": "0.3.0", 4 | "description": "Factory for Pose animation state machines", 5 | "main": "lib/index.js", 6 | "types": "./lib/index.d.ts", 7 | "scripts": { 8 | "build": "tsc", 9 | "watch": "tsc -w", 10 | "test": "echo \"Error: no test specified\" && exit 1", 11 | "measure": "gzip -c dist/popmotion-pose.js | wc -c", 12 | "prettier": "prettier ./src/*", 13 | "prepublishOnly": "npm run prettier && npm run build" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/popmotion" 18 | }, 19 | "keywords": [ 20 | "animation", 21 | "dom", 22 | "declarative", 23 | "popmotion" 24 | ], 25 | "author": "Matt Perry", 26 | "license": "MIT", 27 | "presets": [ 28 | "env" 29 | ], 30 | "devDependencies": { 31 | "typescript": "^2.7.2", 32 | "prettier": "1.11.1", 33 | "webpack": "^3.11.0" 34 | }, 35 | "prettier": { 36 | "parser": "typescript", 37 | "singleQuote": true 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/react-pose/src/components/PoseElement.types.ts: -------------------------------------------------------------------------------- 1 | import { Poser, PoserProps } from 'popmotion-pose'; 2 | 3 | export type ChildRegistration = { 4 | element: Element; 5 | poserProps: PoserProps; 6 | onRegistered: (poser: Poser) => void; 7 | }; 8 | 9 | export type CurrentPose = string | string[]; 10 | 11 | export type PoseContextProps = { 12 | registerChild?: (props: ChildRegistration) => void; 13 | onUnmount?: (child: Poser) => any; 14 | getInitialPoseFromParent?: () => CurrentPose; 15 | getParentPoseProps?: () => PoserProps; 16 | }; 17 | 18 | export type PoseElementProps = { 19 | children?: any; 20 | elementType: any; 21 | poseProps: PoserProps; 22 | pose?: CurrentPose; 23 | initialPose?: CurrentPose; 24 | withParent?: boolean; 25 | onValueChange?: { [key: string]: (v: any) => any }; 26 | innerRef?: (el: Element) => any; 27 | [key: string]: any; 28 | } & PoseContextProps; 29 | 30 | export type PopStyle = { 31 | position: 'absolute'; 32 | top: number; 33 | left: number; 34 | width: number; 35 | height: number; 36 | }; 37 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2017 Popmotion 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /site/components/icons/Twitter.js: -------------------------------------------------------------------------------- 1 | import { ACTION, ACTION_BURN } from '~/styles/vars'; 2 | 3 | export default ({ className }) => ( 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | ); 14 | -------------------------------------------------------------------------------- /packages/popmotion-pose/src/dom/draggable.ts: -------------------------------------------------------------------------------- 1 | import listen from 'popmotion/input/listen'; 2 | import { ColdSubscription } from 'popmotion/action/types'; 3 | import { PoseSetter, ActiveActions, DragProps } from '../types'; 4 | 5 | export default ( 6 | element: Element, 7 | set: PoseSetter, 8 | activeActions: ActiveActions, 9 | { onDragStart, onDragEnd }: DragProps 10 | ) => 11 | activeActions.set( 12 | 'dragStartListener', 13 | listen(element, 'mousedown touchstart').start( 14 | (startEvent: MouseEvent | TouchEvent) => { 15 | startEvent.preventDefault(); 16 | set('dragging'); 17 | if (onDragStart) onDragStart(startEvent); 18 | 19 | activeActions.set( 20 | 'dragEndListener', 21 | listen(document, 'mouseup touchend').start( 22 | (endEvent: MouseEvent | TouchEvent) => { 23 | activeActions.get('dragEndListener').stop(); 24 | set('dragEnd'); 25 | if (onDragEnd) onDragEnd(endEvent); 26 | } 27 | ) 28 | ); 29 | } 30 | ) 31 | ); 32 | 33 | export { ColdSubscription }; 34 | -------------------------------------------------------------------------------- /site/components/icons/GitHub.js: -------------------------------------------------------------------------------- 1 | import { ACTION, ACTION_BURN } from '~/styles/vars'; 2 | 3 | export default ({ className }) => ( 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | ); 14 | -------------------------------------------------------------------------------- /packages/react-pose-core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-pose-core", 3 | "version": "0.1.0", 4 | "description": "Factory for creating flavours of React Pose", 5 | "main": "lib/index.js", 6 | "types": "./lib/index.d.ts", 7 | "scripts": { 8 | "build": "tsc", 9 | "watch": "tsc -w", 10 | "test": "echo \"Error: no test specified\" && exit 1", 11 | "prettier": "prettier ./src/*", 12 | "prepublishOnly": "npm run prettier && npm run build" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/popmotion" 17 | }, 18 | "keywords": [ 19 | "animation", 20 | "dom", 21 | "declarative", 22 | "popmotion" 23 | ], 24 | "author": "Matt Perry", 25 | "license": "MIT", 26 | "presets": [ 27 | "env" 28 | ], 29 | "devDependencies": { 30 | "typescript": "^2.7.2", 31 | "prettier": "1.11.1", 32 | "webpack": "^3.11.0" 33 | }, 34 | "prettier": { 35 | "parser": "typescript", 36 | "singleQuote": true 37 | }, 38 | "dependencies": { 39 | "@types/react": "^16.3.12", 40 | "@types/react-native": "^0.55.4", 41 | "animated-pose": "^0.2.0" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /site/templates/Popmotion/LiveExamples/Template.js: -------------------------------------------------------------------------------- 1 | import { 2 | Container, 3 | LiveExampleContainer, 4 | CodeContainer, 5 | ExampleContainer, 6 | CodePenLink 7 | } from './styled'; 8 | import SyntaxHighlighter, { registerLanguage } from 'react-syntax-highlighter/dist/light'; 9 | import js from 'react-syntax-highlighter/dist/languages/javascript'; 10 | import { codeThemeLarge } from '~/styles/syntax-highlighting'; 11 | 12 | registerLanguage('javascript', js); 13 | 14 | export default ({ children, code, hideOverflow, codepen }) => ( 15 |
16 | 17 | 18 | 19 | {children} 20 | 21 | 22 | 23 | {code} 24 | 25 | 26 | 27 | {codepen && ( 28 | 29 | Fork on CodePen 30 | 31 | )} 32 | 33 |
34 | ); -------------------------------------------------------------------------------- /packages/popmotion/webpack.config.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var path = require('path'); 3 | var isProd = (process.env.NODE_ENV === 'production'); 4 | var devTool = isProd ? false : 'inline-source-map'; 5 | 6 | module.exports = { 7 | entry: { 8 | global: './src/global.ts', 9 | xl: './src/global-xl.ts' 10 | }, 11 | output: { 12 | path: __dirname + '/dist', 13 | filename: 'popmotion.[name].min.js' 14 | }, 15 | module: { 16 | rules: [ 17 | { 18 | test: (modulePath) => modulePath.endsWith('.ts') && !modulePath.endsWith('test.ts'), 19 | loader: 'ts-loader' 20 | } 21 | ], 22 | }, 23 | resolve: { 24 | alias: { 25 | popmotion: path.resolve(__dirname, 'src/index.ts') 26 | }, 27 | extensions: ['.ts', '.tsx', '.js'], 28 | modules: [ 29 | path.resolve('./node_modules'), 30 | path.resolve('./src') 31 | ] 32 | }, 33 | plugins: isProd ? [ 34 | new webpack.optimize.ModuleConcatenationPlugin(), 35 | new webpack.optimize.UglifyJsPlugin({ 36 | mangle: true, 37 | minimize: true 38 | }) 39 | ] : [ 40 | 41 | ], 42 | devtool: devTool 43 | }; -------------------------------------------------------------------------------- /packages/react-native-pose/README.md: -------------------------------------------------------------------------------- 1 | # React Native Pose 2 | 3 | ## Pose animation system in React Native flavour 4 | 5 | [![npm version](https://img.shields.io/npm/v/react-native-pose.svg?style=flat-square)](https://www.npmjs.com/package/react-native-pose) 6 | [![npm downloads](https://img.shields.io/npm/dm/react-native-pose.svg?style=flat-square)](https://www.npmjs.com/package/react-native-pose) 7 | [![Twitter Follow](https://img.shields.io/twitter/follow/popmotionjs.svg?style=social&label=Follow)](http://twitter.com/popmotionjs) 8 | [![Join the community on Spectrum](https://withspectrum.github.io/badge/badge.svg)](https://spectrum.chat/popmotion) 9 | 10 | - [Homepage](https://popmotion.io/pose) 11 | - [API](https://popmotion.io/pose/api) 12 | - [Get started](https://popmotion.io/pose/learn/native-get-started) 13 | 14 | ## Supported by 15 | DriveTribe Open Source 16 | -------------------------------------------------------------------------------- /packages/popmotion/src/reactions/_tests/multicast.test.ts: -------------------------------------------------------------------------------- 1 | import multicast from '../multicast'; 2 | import action from '../../action'; 3 | 4 | describe('multicast', () => { 5 | const one = action(({ update }) => update(1)); 6 | 7 | it('should accept subscribers', () => { 8 | const r = multicast(); 9 | r.subscribe({ 10 | update: (v) => expect(v).toBe(1), 11 | complete: () => expect(true).toBe(true) 12 | }); 13 | r.update(1); 14 | r.complete(); 15 | }); 16 | 17 | it('should work with actions', () => { 18 | const r = multicast(); 19 | r.subscribe((v) => expect(v).toBe(1)); 20 | const a = one.start(r); 21 | }); 22 | 23 | it('should accept multiple subscribers', () => { 24 | const r = multicast(); 25 | r.subscribe((v) => expect(v).toBe(1)); 26 | r.subscribe((v) => expect(v).toBe(1)); 27 | const a = one.start(r); 28 | }); 29 | 30 | it('should create a new instance when chained', () => { 31 | const r = multicast(); 32 | const s = r.pipe((v) => v * 2); 33 | r.subscribe((v) => expect(v).toBe(1)); 34 | s.subscribe((v) => expect(v).toBe(2)); 35 | one.start(r); 36 | one.start(s); 37 | }); 38 | }) 39 | -------------------------------------------------------------------------------- /packages/popmotion-pose/README.md: -------------------------------------------------------------------------------- 1 | # Popmotion Pose 2 | 3 | ## A declarative animation system for HTML, SVG & React 4 | 5 | [![npm version](https://img.shields.io/npm/v/popmotion-pose.svg?style=flat-square)](https://www.npmjs.com/package/popmotion-pose) 6 | [![npm downloads](https://img.shields.io/npm/dm/popmotion-pose.svg?style=flat-square)](https://www.npmjs.com/package/popmotion-pose) 7 | [![Twitter Follow](https://img.shields.io/twitter/follow/popmotionjs.svg?style=social&label=Follow)](http://twitter.com/popmotionjs) 8 | [![Join the community on Spectrum](https://withspectrum.github.io/badge/badge.svg)](https://spectrum.chat/popmotion) 9 | 10 | Pose is a declarative DOM animation library for HTML, SVG & React. It removes all the plumbing typically associated with JavaScript animation and reduces it to code like this: 11 | 12 | ```javascript 13 | sidePanel.set('open') 14 | ``` 15 | 16 | - [Homepage](https://popmotion.io/pose) 17 | - [API](https://popmotion.io/pose/api) 18 | - [Get started](https://popmotion.io/pose/learn/get-started) 19 | -------------------------------------------------------------------------------- /playground/spring.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { BaseAnimation } from './inc'; 3 | import spring from '../packages/popmotion/lib/animations/spring'; 4 | 5 | export class Spring extends BaseAnimation { 6 | getAnimation = (styler) => spring({ 7 | to: 300 8 | }).start((v) => styler.set('x', v)); 9 | } 10 | 11 | export class SpringVelocity extends BaseAnimation { 12 | getAnimation = (styler) => spring({ 13 | from: 0, 14 | to: 500, 15 | velocity: -10000 16 | }).start((v) => styler.set('x', v)); 17 | } 18 | 19 | export class SpringHeavier extends BaseAnimation { 20 | getAnimation = (styler) => spring({ 21 | to: 300, 22 | velocity: 10000, 23 | mass: 3 24 | }).start((v) => styler.set('x', v)); 25 | } 26 | 27 | export class SpringStiffer extends BaseAnimation { 28 | getAnimation = (styler) => spring({ 29 | to: 300, 30 | velocity: 10000, 31 | stiffness: 500 32 | }).start((v) => styler.set('x', v)); 33 | } 34 | 35 | export class SpringStifferDamping extends BaseAnimation { 36 | getAnimation = (styler) => spring({ 37 | to: 300, 38 | velocity: 10000, 39 | stiffness: 500, 40 | damping: 100 41 | }).start((v) => styler.set('x', v)); 42 | } -------------------------------------------------------------------------------- /packages/popmotion/src/chainable/index.ts: -------------------------------------------------------------------------------- 1 | import { Middleware, Update } from '../observer/types'; 2 | import { pipe } from '../transformers'; 3 | import { Predicate, Props } from './types'; 4 | 5 | export default abstract class Chainable { 6 | protected props: Props; 7 | 8 | constructor(props: Props = {}) { 9 | this.props = props; 10 | } 11 | 12 | abstract create(props: Props): T; 13 | 14 | applyMiddleware(middleware: Middleware): T { 15 | return this.create({ 16 | ...this.props, 17 | middleware: this.props.middleware ? [middleware, ...this.props.middleware] : [middleware] 18 | }); 19 | } 20 | 21 | pipe(...funcs: Update[]): T { 22 | const pipedUpdate = funcs.length === 1 ? funcs[0] : pipe(...funcs); 23 | 24 | return this.applyMiddleware( 25 | (update) => (v) => update(pipedUpdate(v)) 26 | ); 27 | } 28 | 29 | while(predicate: Predicate): T { 30 | return this.applyMiddleware( 31 | (update, complete) => (v) => predicate(v) ? update(v) : complete() 32 | ); 33 | } 34 | 35 | filter(predicate: Predicate): T { 36 | return this.applyMiddleware( 37 | (update, complete) => (v) => predicate(v) && update(v) 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/react-pose/module-types/react/README.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | > `npm install --save @types/react` 3 | 4 | # Summary 5 | This package contains type definitions for React (http://facebook.github.io/react/). 6 | 7 | # Details 8 | Files were exported from https://www.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/react 9 | 10 | Additional Details 11 | * Last updated: Thu, 01 Mar 2018 18:48:33 GMT 12 | * Dependencies: none 13 | * Global values: React 14 | 15 | # Credits 16 | These definitions were written by Asana , AssureSign , Microsoft , John Reilly , Benoit Benezech , Patricio Zavolinsky , Digiguru , Eric Anderson , Albert Kurniawan , Tanguy Krotoff , Dovydas Navickas , Stéphane Goetz , Rich Seviora , Josh Rutherford , Guilherme Hübner . 17 | -------------------------------------------------------------------------------- /packages/animated-pose/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "animated-pose", 3 | "version": "0.2.2", 4 | "description": "Pose for the Animated animation library", 5 | "main": "lib/index.js", 6 | "types": "./lib/index.d.ts", 7 | "scripts": { 8 | "build": "tsc", 9 | "watch": "tsc -w", 10 | "test": "echo \"Error: no test specified\" && exit 1", 11 | "measure": "gzip -c dist/popmotion-pose.js | wc -c", 12 | "prettier": "prettier ./src/*", 13 | "prepublishOnly": "npm run prettier && npm run build" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/popmotion" 18 | }, 19 | "keywords": [ 20 | "animation", 21 | "dom", 22 | "declarative", 23 | "popmotion" 24 | ], 25 | "author": "Matt Perry", 26 | "license": "MIT", 27 | "presets": [ 28 | "env" 29 | ], 30 | "devDependencies": { 31 | "typescript": "^2.7.2", 32 | "prettier": "1.11.1", 33 | "webpack": "^3.11.0" 34 | }, 35 | "prettier": { 36 | "parser": "typescript", 37 | "singleQuote": true 38 | }, 39 | "peerDependencies": { 40 | "react-native": "^0.55.3" 41 | }, 42 | "dependencies": { 43 | "@types/react-native": "^0.55.4", 44 | "pose-core": "^0.3.0" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /packages/popmotion-pose/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "popmotion-pose", 3 | "version": "1.3.0", 4 | "description": "A declarative animation library for HTML and SVG", 5 | "main": "lib/index.js", 6 | "types": "./lib/index.d.ts", 7 | "scripts": { 8 | "bundle": "NODE_ENV=production webpack", 9 | "build": "tsc", 10 | "watch": "tsc -w", 11 | "test": "echo \"Error: no test specified\" && exit 1", 12 | "measure": "gzip -c dist/popmotion-pose.js | wc -c", 13 | "prettier": "prettier ./src/*", 14 | "prepublishOnly": "npm run prettier && npm run build && npm run bundle" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/popmotion" 19 | }, 20 | "keywords": [ 21 | "animation", 22 | "dom", 23 | "declarative", 24 | "popmotion" 25 | ], 26 | "author": "Matt Perry", 27 | "license": "MIT", 28 | "presets": [ 29 | "env" 30 | ], 31 | "devDependencies": { 32 | "typescript": "^2.7.2", 33 | "prettier": "1.11.1", 34 | "webpack": "^3.11.0" 35 | }, 36 | "dependencies": { 37 | "popmotion": "^8.1.22" 38 | }, 39 | "unpkg": "./dist/popmotion-pose.js", 40 | "prettier": { 41 | "parser": "typescript", 42 | "singleQuote": true 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /packages/popmotion/docs/api/compositors/merge.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Merge 3 | description: Combine multiple actions into one output. 4 | category: compositors 5 | --- 6 | 7 | # Merge 8 | 9 | Combine multiple actions into one output. 10 | 11 | ## Import 12 | 13 | ```javascript 14 | import { merge } from 'popmotion'; 15 | // or stand-alone: 16 | import merge from 'popmotion/compositors/merge'; 17 | ``` 18 | 19 | ## Usage 20 | 21 | ```javascript 22 | merge( 23 | tween(), 24 | action(({ update }) => update(1)), 25 | physics({ velocity: 1000 }) 26 | ).start((v) => console.log(v)); 27 | ``` 28 | 29 | ## Methods 30 | 31 | ### Action methods 32 | 33 | `merge()` returns: 34 | 35 | - `filter((v: any) => boolean)`: Returns a new action that filters out values when the provided function returns `false`. 36 | - `pipe(...funcs: Array<(v) => v)`: Returns a new action that will run `update` values through this sequence of functions. 37 | - `start(update | { update, complete })`: Starts the action and returns a subscription. 38 | - `while((v: any) => boolean)`: Returns a new action that will `complete` when the provided function returns `false`. 39 | 40 | 41 | ### Subscription methods 42 | 43 | `merge().start()` returns: 44 | 45 | - `stop(): void` 46 | 47 | -------------------------------------------------------------------------------- /packages/react-360-pose/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-360-pose", 3 | "version": "0.1.0", 4 | "description": "Pose animation system for React 360", 5 | "main": "lib/index.js", 6 | "types": "./lib/index.d.ts", 7 | "scripts": { 8 | "build": "tsc", 9 | "watch": "tsc -w", 10 | "test": "echo \"Error: no test specified\" && exit 1", 11 | "prettier": "prettier ./src/*", 12 | "prepublishOnly": "npm run prettier && npm run build" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/popmotion" 17 | }, 18 | "keywords": [ 19 | "animation", 20 | "dom", 21 | "declarative", 22 | "popmotion" 23 | ], 24 | "author": "Matt Perry", 25 | "license": "MIT", 26 | "presets": [ 27 | "env" 28 | ], 29 | "devDependencies": { 30 | "typescript": "^2.7.2", 31 | "prettier": "1.11.1", 32 | "webpack": "^3.11.0" 33 | }, 34 | "prettier": { 35 | "parser": "typescript", 36 | "singleQuote": true 37 | }, 38 | "dependencies": { 39 | "@types/react": "^16.3.12", 40 | "@types/react-native": "^0.55.4", 41 | "animated-pose": "0.0.10", 42 | "react-pose-core": "^0.1.0" 43 | }, 44 | "peerDependencies": { 45 | "react-360": "^1.0.0" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /packages/react-native-pose/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-pose", 3 | "version": "0.2.1", 4 | "description": "Pose animation system for React Native", 5 | "main": "lib/index.js", 6 | "types": "./lib/index.d.ts", 7 | "scripts": { 8 | "build": "tsc", 9 | "watch": "tsc -w", 10 | "test": "echo \"Error: no test specified\" && exit 1", 11 | "prettier": "prettier ./src/*", 12 | "prepublishOnly": "npm run prettier && npm run build" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/popmotion" 17 | }, 18 | "keywords": [ 19 | "animation", 20 | "dom", 21 | "declarative", 22 | "popmotion" 23 | ], 24 | "author": "Matt Perry", 25 | "license": "MIT", 26 | "presets": [ 27 | "env" 28 | ], 29 | "devDependencies": { 30 | "typescript": "^2.7.2", 31 | "prettier": "1.11.1", 32 | "webpack": "^3.11.0" 33 | }, 34 | "prettier": { 35 | "parser": "typescript", 36 | "singleQuote": true 37 | }, 38 | "peerDependencies": { 39 | "react-native": "^0.55.3" 40 | }, 41 | "dependencies": { 42 | "@types/react": "^16.3.12", 43 | "@types/react-native": "^0.55.4", 44 | "animated-pose": "^0.2.2", 45 | "react-pose-core": "^0.1.0" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /packages/animated-pose/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | Animated Pose adheres to [Semantic Versioning](http://semver.org/). 4 | 5 | ## [0.2.2] 2018-05-06 6 | 7 | - Updating type. 8 | 9 | ## [0.2.1] 2018-05-06 10 | 11 | - Updating type. 12 | 13 | ## [0.2.0] 2018-05-06 14 | 15 | - Updating `pose-core` 16 | - Now invalidating `useNativeDriver` on all values in the event one of them is invalidated by interpolating to a non-accelerated value. 17 | 18 | ## [0.1.1] 2018-05-05 19 | 20 | - Fixing negative string units. 21 | 22 | ## [0.1.0] 2018-05-05 23 | 24 | - Passing `useNativeDriver` through to instant transition. 25 | 26 | ## [0.0.10] 2018-04-24 27 | 28 | - Adding `useNativeDriver` to value definition. 29 | 30 | ## [0.0.9] 2018-04-24 31 | 32 | - Ensuring values are converted on creation. 33 | 34 | ## [0.0.8] 2018-04-24 35 | 36 | - Updating `pose-core` 37 | 38 | ## [0.0.7] 2018-04-23 39 | 40 | - Fixing bug in value types. 41 | 42 | ## [0.0.6] 2018-04-23 43 | 44 | - Adding `vh`, `vw`, `sh` and `sw` value types for React Native. 45 | 46 | ## [0.0.5] 2018-04-23 47 | 48 | - `useNativeDriver` override in all transitions 49 | 50 | ## [0.0.4] 2018-04-23 51 | 52 | - Allowing `useNativeDriver` to override default transitions 53 | 54 | ## [0.0.1] 2018-04-18 55 | 56 | - First publish 57 | -------------------------------------------------------------------------------- /packages/popmotion/src/action/index.ts: -------------------------------------------------------------------------------- 1 | import Chainable from '../chainable'; 2 | import createObserver from '../observer'; 3 | import { ObserverCandidate, PartialObserver } from '../observer/types'; 4 | import { ActionInit, ActionProps, ColdSubscription } from './types'; 5 | 6 | export class Action extends Chainable { 7 | create(props: ActionProps) { 8 | return new Action(props); 9 | } 10 | 11 | start(observerCandidate: ObserverCandidate = {}): ColdSubscription { 12 | let isComplete = false; 13 | let subscription: ColdSubscription = { 14 | stop: () => undefined 15 | }; 16 | 17 | const { init, ...observerProps } = this.props; 18 | const observer = createObserver(observerCandidate, observerProps, () => { 19 | isComplete = true; 20 | subscription.stop(); 21 | }); 22 | 23 | const api = init(observer); 24 | 25 | subscription = api 26 | ? { ...subscription, ...api } 27 | : subscription; 28 | 29 | if ((observerCandidate as PartialObserver).registerParent) { 30 | (observerCandidate as PartialObserver).registerParent(subscription); 31 | } 32 | 33 | if (isComplete) subscription.stop(); 34 | 35 | return subscription; 36 | } 37 | } 38 | 39 | export default (init: ActionInit) => new Action({ init }); 40 | -------------------------------------------------------------------------------- /playground/timeline.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import timeline from '../packages/popmotion/lib/animations/timeline'; 3 | import { styler } from '../packages/popmotion/lib'; 4 | import { linear } from '../packages/popmotion/lib/easing'; 5 | import { Box } from './inc'; 6 | 7 | export class TimelineTest extends React.Component { 8 | setRefs = (ref) => { 9 | if (!ref) return; 10 | const [a, b] = ref.querySelectorAll('div'); 11 | const aStyler = styler(a); 12 | const bStyler = styler(b); 13 | 14 | // timeline([ 15 | // [ 16 | // { track: 'aX', from: 0, to: 100, duration: 1000 }, 17 | // { track: 'bX', from: 0, to: 100, duration: 1000 }, 18 | // 100 19 | // ], 20 | // '+100', 21 | // [ 22 | // { track: 'aX', to: 0 }, 23 | // { track: 'bX', to: 0 } 24 | // ], 25 | // { track: 'aX', to: 100 }, 26 | // '-200', 27 | // { track: 'bX', to: 100 }, 28 | // ], { 29 | // loop: Infinity 30 | // }).start(({ aX, bX }) => { 31 | // aStyler.set('x', aX); 32 | // bStyler.set('x', bX); 33 | // }); 34 | }; 35 | 36 | render() { 37 | return ( 38 |
39 | 40 | 41 |
42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /site/templates/global/grid.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | import { cols, media, LIGHT_GREY } from '~/styles/vars'; 3 | 4 | export const Content = styled.article` 5 | min-height: 700px; 6 | `; 7 | 8 | export const Centered = styled.div` 9 | max-width: ${cols(42)}; 10 | margin: 0 auto; 11 | 12 | ${media.medium` 13 | margin-left: ${cols(2)}; 14 | margin-right: ${cols(2)}; 15 | `} ${media.small` 16 | margin-left: ${cols(2)}; 17 | margin-right: ${cols(2)}; 18 | `}; 19 | `; 20 | 21 | export const MajorCentered = styled(Centered)` 22 | margin-left: calc((100vw - ${cols(42)}) / 2); 23 | max-width: none; 24 | 25 | ${media.medium` 26 | margin-left: ${cols(2)}; 27 | `}; 28 | `; 29 | 30 | export const ArticleHeader = MajorCentered.withComponent('header').extend` 31 | padding-bottom: 10px; 32 | border-bottom: 1px solid ${LIGHT_GREY}; 33 | margin-bottom: ${cols(2)}; 34 | `; 35 | 36 | export const SectionContainer = styled.li``; 37 | 38 | export const ItemContainer = Centered.withComponent('li').extend` 39 | border-left: 1px solid ${LIGHT_GREY}; 40 | padding: ${cols(1)} ${cols(2)}; 41 | margin-bottom: ${cols(1)}; 42 | 43 | ${media.medium` 44 | border: 0; 45 | padding: 0; 46 | margin-bottom: ${cols(2)}; 47 | `} 48 | `; 49 | -------------------------------------------------------------------------------- /packages/popmotion/src/input/pointer/mouse.ts: -------------------------------------------------------------------------------- 1 | import { cancelOnFrameUpdate, onFrameUpdate } from 'framesync'; 2 | import action, { Action } from '../../action'; 3 | import listen from '../listen'; 4 | import { defaultPointerPos, eventToPoint } from '../pointer/utils'; 5 | import { PointerPoint, PointerProps } from './types'; 6 | 7 | const point: PointerPoint = defaultPointerPos(); 8 | let isMouseDevice = false; 9 | 10 | if (typeof document !== 'undefined') { 11 | const updatePointLocation = (e: MouseEvent) => { 12 | isMouseDevice = true; 13 | eventToPoint(e, point); 14 | }; 15 | 16 | listen(document, 'mousedown mousemove', true) 17 | .start(updatePointLocation); 18 | } 19 | 20 | const mouse = ({ preventDefault = true }: PointerProps = {}): Action => action(({ update }) => { 21 | const updatePoint = () => update(point); 22 | 23 | const onMove = (e: MouseEvent) => { 24 | if (preventDefault) e.preventDefault(); 25 | onFrameUpdate(updatePoint); 26 | }; 27 | 28 | const updateOnMove = listen(document, 'mousemove').start(onMove); 29 | 30 | if (isMouseDevice) onFrameUpdate(updatePoint); 31 | 32 | return { 33 | stop: () => { 34 | cancelOnFrameUpdate(updatePoint); 35 | updateOnMove.stop(); 36 | } 37 | }; 38 | }); 39 | 40 | export default mouse; 41 | -------------------------------------------------------------------------------- /packages/react-pose/module-types/react/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /packages/popmotion/src/action/_tests/action.test.ts: -------------------------------------------------------------------------------- 1 | import action from '../'; 2 | 3 | describe('action', () => { 4 | const one = action(({ update }) => update(1)); 5 | const oneTwo = action(({ update }) => { update(1); update(2); }); 6 | 7 | it('should update', () => { 8 | one.start((v) => expect(v).toBe(1)); 9 | }); 10 | 11 | it('should complete', () => { 12 | action(({ complete }) => complete()).start({ 13 | complete: () => expect(true).toBe(true); 14 | }); 15 | }); 16 | 17 | it('should pipe values', () => { 18 | one.pipe((v) => v * 2).start((v) => expect(v).toBe(2)); 19 | }); 20 | 21 | it('should create new instance when chained', () => { 22 | one.start((v) => expect(v).toBe(1)); 23 | one.pipe((v) => v * 2).start((v) => expect(v).toBe(2)); 24 | }) 25 | 26 | it('should complete when `while` fails', () => { 27 | let i = 0; 28 | oneTwo 29 | .while((v) => v === 1) 30 | .start({ 31 | update: (v) => i = v, 32 | complete: () => expect(i).toBe(1) 33 | }); 34 | }); 35 | 36 | it('should filter values that fail the predicate', () => { 37 | let i = 0; 38 | oneTwo.filter((v) => v === 1) 39 | .start({ 40 | update: (v) => i = v, 41 | complete: () => expect(i).toBe(1) 42 | }); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /packages/popmotion-pose/src-core/index.ts: -------------------------------------------------------------------------------- 1 | import { ColdSubscription } from 'popmotion/action/types'; 2 | import { value } from 'popmotion'; 3 | import poseFactory from '../../pose-core/src'; 4 | import createDimensions from './factories/dimensions'; 5 | import defaultTransitions from './inc/default-transitions'; 6 | import { PopmotionPoserConfig } from './types'; 7 | import { ValueReaction } from 'popmotion/reactions/value'; 8 | 9 | const passThrough = (v: any) => v; 10 | 11 | const pose = poseFactory({ 12 | getDefaultProps: ({ element }: PopmotionPoserConfig) => ({ 13 | dimensions: createDimensions(element) 14 | }), 15 | defaultTransitions, 16 | bindOnChange: (values, onChange) => (key) => { 17 | if (values.has(key)) values.get(key).subscribe(onChange[key]); 18 | }, 19 | readValue: value => value.get(), 20 | createValue: (init, { passiveParent, passiveProps = passThrough }) => { 21 | if (passiveParent) { 22 | const newValue = value(init, passiveProps); 23 | passiveParent.subscribe(newValue); 24 | return newValue; 25 | } else { 26 | return value(init); 27 | } 28 | } 29 | }); 30 | 31 | export default (element: Element, config: PopmotionPoserConfig) => { 32 | return pose({ 33 | element, 34 | ...config 35 | }); 36 | }; 37 | -------------------------------------------------------------------------------- /packages/popmotion/src/compositors/composite.ts: -------------------------------------------------------------------------------- 1 | import multi from './multi'; 2 | import { Action } from '../action'; 3 | import { ColdSubscription } from '../action/types'; 4 | 5 | type ActionMap = { 6 | [key: string]: Action 7 | }; 8 | 9 | type ValueMap = { 10 | [key: string]: any 11 | }; 12 | 13 | type ColdSubscriptionMap = { 14 | [key: string]: ColdSubscription 15 | }; 16 | 17 | const composite = multi({ 18 | getOutput: () => ({}), 19 | getCount: (subs) => Object.keys(subs).length, 20 | getFirst: (subs) => subs[Object.keys(subs)[0]], 21 | mapApi: (subs, methodName) => (...args) => Object.keys(subs) 22 | .reduce((output: ValueMap, propKey: string) => { 23 | if (subs[propKey][methodName]) { 24 | (args[0] && args[0][propKey] !== undefined) 25 | ? output[propKey] = subs[propKey][methodName](args[0][propKey]) 26 | : output[propKey] = subs[propKey][methodName](...args); 27 | } 28 | return output; 29 | }, {}), 30 | setProp: (output, name, v) => output[name] = v, 31 | startActions: (actions, starter) => Object.keys(actions) 32 | .reduce((subs: ColdSubscriptionMap, key) => { 33 | subs[key] = starter(actions[key], key); 34 | return subs; 35 | }, {}) 36 | }); 37 | 38 | export default composite; 39 | -------------------------------------------------------------------------------- /packages/popmotion/docs/api/animation/every-frame.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Every Frame 3 | description: Fires with timestamp, once every frame. 4 | category: animation 5 | --- 6 | 7 | # Every Frame 8 | 9 | `everyFrame` fires once per frame, and provides `update` with the duration of time since it started. 10 | 11 | ## Import 12 | 13 | ```javascript 14 | import { everyFrame } from 'popmotion'; 15 | // or stand-alone: 16 | import everyFrame from 'popmotion/animations/every-frame'; 17 | ``` 18 | 19 | ## Usage 20 | 21 | ```javascript 22 | everyFrame() 23 | .start((timeSinceStart) => console.log(timeSinceStart)); 24 | ``` 25 | 26 | ## Methods 27 | 28 | ### Action methods 29 | 30 | `everyFrame()` returns: 31 | 32 | - `filter((v: any) => boolean)`: Returns a new action that filters out values when the provided function returns `false`. 33 | - `pipe(...funcs: Array<(v) => v)`: Returns a new action that will run `update` values through this sequence of functions. 34 | - `start(update | { update, complete })`: Starts the action and returns a subscription. 35 | - `while((v: any) => boolean)`: Returns a new action that will `complete` when the provided function returns `false`. 36 | 37 | 38 | ### Subscription methods 39 | 40 | `everyFrame().start()` returns: 41 | 42 | - `stop(): void` 43 | 44 | ## Example 45 | 46 | 47 | -------------------------------------------------------------------------------- /playground/keyframes.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { BaseAnimation } from './inc'; 3 | import keyframes from '../packages/popmotion/lib/animations/keyframes'; 4 | import { linear } from '../packages/popmotion/lib/easing'; 5 | 6 | export class Keyframes extends BaseAnimation { 7 | getAnimation = (styler) => keyframes({ 8 | values: [0, 300, 150] 9 | }).start((v) => styler.set('x', v)); 10 | } 11 | 12 | export class KeyframesDuration extends BaseAnimation { 13 | getAnimation = (styler) => keyframes({ 14 | values: [0, 300, 150], 15 | duration: 1000 16 | }).start((v) => styler.set('x', v)); 17 | } 18 | 19 | export class KeyframesLoop extends BaseAnimation { 20 | getAnimation = (styler) => keyframes({ 21 | values: [0, 300, 150], 22 | duration: 1000, 23 | loop: Infinity 24 | }).start((v) => styler.set('x', v)); 25 | } 26 | 27 | export class KeyframesLinear extends BaseAnimation { 28 | getAnimation = (styler) => keyframes({ 29 | values: [0, 300, 150], 30 | duration: 1000, 31 | ease: [linear, linear] 32 | }).start((v) => styler.set('x', v)); 33 | } 34 | 35 | export class KeyframesTimes extends BaseAnimation { 36 | getAnimation = (styler) => keyframes({ 37 | values: [0, 300, 150], 38 | duration: 1000, 39 | times: [0, 0.2, 1] 40 | }).start((v) => styler.set('x', v)); 41 | } 42 | 43 | -------------------------------------------------------------------------------- /packages/popmotion/docs/api/compositors/chain.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Chain 3 | description: Chain a sequence of actions, move to the next when the current one completes. 4 | category: compositors 5 | --- 6 | 7 | # Chain 8 | 9 | Chain a sequence of actions, move to the next when the current one completes. 10 | 11 | ## Import 12 | 13 | ```javascript 14 | import { chain } from 'popmotion'; 15 | // or stand-alone: 16 | import chain from 'popmotion/compositors/chain'; 17 | ``` 18 | 19 | ## Usage 20 | 21 | ```javascript 22 | chain( 23 | tween({ to: 300 }), 24 | spring({ from: 300, to: 0 }) 25 | ).start({ 26 | update: (v) => console.log(v), 27 | complete: () => console.log('All actions complete') 28 | }) 29 | ``` 30 | 31 | ## Methods 32 | 33 | ### Action methods 34 | 35 | `chain()` returns: 36 | 37 | - `filter((v: any) => boolean)`: Returns a new action that filters out values when the provided function returns `false`. 38 | - `pipe(...funcs: Array<(v) => v)`: Returns a new action that will run `update` values through this sequence of functions. 39 | - `start(update | { update, complete })`: Starts the action and returns a subscription. 40 | - `while((v: any) => boolean)`: Returns a new action that will `complete` when the provided function returns `false`. 41 | 42 | 43 | ### Subscription methods 44 | 45 | `chain().start()` returns: 46 | 47 | - `stop(): void` 48 | -------------------------------------------------------------------------------- /site/styles/syntax-highlighting.js: -------------------------------------------------------------------------------- 1 | import { BLACK, BRAND, ENTITY, ACTION, cols } from './vars'; 2 | 3 | const createTheme = ({ fontSize = 14, lineHeight = 20, width = '100%'}) => ({ 4 | 'hljs': { 5 | display: 'block', 6 | overflowX: 'auto', 7 | padding: cols(1), 8 | color: BLACK, 9 | fontSize: `${fontSize}px`, 10 | lineHeight: `${lineHeight}px`, 11 | width 12 | }, 13 | 'hljs-comment': { 14 | opacity: 0.5 15 | }, 16 | 'hljs-keyword': { 17 | color: ENTITY 18 | }, 19 | 'hljs-name': { 20 | color: ACTION 21 | }, 22 | 'hljs-number': { 23 | color: BRAND 24 | }, 25 | 'hljs-params': { 26 | color: ACTION 27 | }, 28 | 'hljs-string': { 29 | color: BRAND 30 | }, 31 | 'hljs-attribute': { 32 | color: BRAND 33 | }, 34 | 'hljs-function': { 35 | color: ACTION 36 | } 37 | }); 38 | 39 | export const prismTheme = ` 40 | .token { 41 | color: ${BLACK}; 42 | &.string { 43 | color: ${BRAND}; 44 | } 45 | &.keyword { 46 | color: ${ENTITY}; 47 | } 48 | &.comment { 49 | opacity: 0.5; 50 | } 51 | &.number { 52 | color: ${BRAND}; 53 | } 54 | &.function { 55 | color: ${ACTION}; 56 | } 57 | } 58 | `; 59 | 60 | export const codeTheme = createTheme({}); 61 | export const codeThemeLarge = createTheme({ 62 | fontSize: 18, 63 | lineHeight: 26, 64 | width: '85%' 65 | }); 66 | -------------------------------------------------------------------------------- /site/templates/Popmotion/LiveExamples/Pointer.js: -------------------------------------------------------------------------------- 1 | import Template from './Template'; 2 | import { Ball, AlignCenter } from './styled'; 3 | import { styler, value, listen, pointer } from 'popmotion'; 4 | 5 | const code = `const ball = document.querySelector('.ball'); 6 | const ballXY = value({ x: 0, y: 0 }, styler(ball).set); 7 | 8 | listen(ball, 'mousedown touchstart').start(() => { 9 | pointer(ballXY.get()) 10 | .start(ballXY); 11 | });`; 12 | 13 | class Example extends React.Component { 14 | startAnimation = (ref) => { 15 | if (!ref) return; 16 | 17 | const ballStyler = styler(ref); 18 | const ballXY = value({ x: 0, y: 0 }, ballStyler.set); 19 | 20 | listen(ref, 'mousedown touchstart') 21 | .start((e) => { 22 | e.preventDefault(); 23 | pointer(ballXY.get()).start(ballXY); 24 | }); 25 | 26 | listen(document, 'mouseup touchend') 27 | .start(() => ballXY.stop()); 28 | } 29 | 30 | componentWillUnmount() { 31 | this.animation && this.animation.stop(); 32 | } 33 | 34 | render() { 35 | return ( 36 | 37 | Drag 38 | 39 | ); 40 | } 41 | } 42 | 43 | export default () => ( 44 | 49 | ); 50 | -------------------------------------------------------------------------------- /packages/popmotion-pose/src/factories/poses.ts: -------------------------------------------------------------------------------- 1 | import { getPoses } from '../inc/selectors'; 2 | import defaultTransitions from '../inc/default-transitions'; 3 | import { PoserProps, Pose, PoseMap, Draggable } from 'types'; 4 | 5 | const generateTransition = (pose: Pose, key: string): Pose => ({ 6 | ...pose, 7 | transition: defaultTransitions.has(key) 8 | ? defaultTransitions.get(key) 9 | : defaultTransitions.get('default') 10 | }); 11 | 12 | const dragPoses = (draggable: Draggable): PoseMap => { 13 | const dragging: Pose = {}; 14 | const dragEnd: Pose = {}; 15 | 16 | if (draggable === true || draggable === 'x') dragging.x = dragEnd.x = 0; 17 | if (draggable === true || draggable === 'y') dragging.y = dragEnd.y = 0; 18 | 19 | return { dragging, dragEnd }; 20 | }; 21 | 22 | export default (props: PoserProps): PoseMap => { 23 | let poses: PoseMap = { flip: {}, ...getPoses(props) }; 24 | const { draggable } = props; 25 | 26 | if (draggable) { 27 | let { dragging, dragEnd } = dragPoses(draggable); 28 | dragging = { ...poses.dragging, ...dragging }; 29 | dragEnd = { ...poses.dragEnd, ...dragging }; 30 | poses = { 31 | ...poses, 32 | dragging, 33 | dragEnd 34 | }; 35 | } 36 | 37 | Object.keys(poses).forEach(key => { 38 | const pose = poses[key]; 39 | poses[key] = pose.transition ? pose : generateTransition(pose, key); 40 | }); 41 | 42 | return poses; 43 | }; 44 | -------------------------------------------------------------------------------- /site/scripts/build-next-config.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | 4 | const outputPath = path.join(__dirname, '../next.config.js'); 5 | 6 | const fileTemplate = routes => ` 7 | module.exports = { 8 | exportPathMap: function () { 9 | return ${routes}; 10 | } 11 | }; 12 | `; 13 | 14 | const generateRouteDefinitions = data => { 15 | // TODO: Automatically generate api/blog etc 16 | let routes = ` 17 | '/': { page: '/' }, 18 | '/api': { page: '/api' }, 19 | '/blog': { page: '/blog' }, 20 | '/pose': { page: '/pose' }, 21 | '/pose/api': { page: '/pose/api' }, 22 | '/page-not-found': { page: '/_error' }, 23 | `; 24 | 25 | Object.keys(data).forEach(siteId => { 26 | const siteData = data[siteId]; 27 | 28 | Object.keys(siteData).forEach(sectionId => { 29 | const sectionData = siteData[sectionId]; 30 | const pageIds = Object.keys(sectionData); 31 | 32 | pageIds.forEach(pageId => { 33 | const route = `/${ 34 | siteId === 'popmotion' ? '' : siteId + '/' 35 | }${sectionId}/${pageId}`; 36 | routes += ` 37 | '${route}': { 38 | page: '${route}' 39 | }, 40 | `; 41 | }); 42 | }); 43 | }); 44 | 45 | return `{${routes}}`; 46 | }; 47 | 48 | module.exports = function(data) { 49 | const routes = generateRouteDefinitions(data); 50 | fs.writeFile(outputPath, fileTemplate(routes)); 51 | }; 52 | -------------------------------------------------------------------------------- /packages/react-pose/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-pose", 3 | "version": "1.5.2", 4 | "description": "A declarative animation library for React", 5 | "main": "lib/index.js", 6 | "types": "./lib/index.d.ts", 7 | "scripts": { 8 | "bundle": "NODE_ENV=production webpack", 9 | "build": "tsc", 10 | "watch": "tsc -w", 11 | "test": "echo \"Error: no test specified\" && exit 1", 12 | "measure": "gzip -c dist/react-pose.js | wc -c", 13 | "prettier": "prettier ./src/*", 14 | "prepublishOnly": "npm run prettier && npm run build && npm run bundle" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/popmotion" 19 | }, 20 | "keywords": [ 21 | "animation", 22 | "dom", 23 | "declarative", 24 | "popmotion", 25 | "react", 26 | "react animation" 27 | ], 28 | "author": "Matt Perry", 29 | "license": "MIT", 30 | "presets": [ 31 | "env" 32 | ], 33 | "peerDependencies": { 34 | "react": "^16.3.0", 35 | "react-dom": "^16.3.0" 36 | }, 37 | "devDependencies": { 38 | "react": "^16.3.0", 39 | "react-dom": "^16.3.0", 40 | "typescript": "^2.7.2", 41 | "prettier": "1.11.1", 42 | "webpack": "^3.11.0" 43 | }, 44 | "dependencies": { 45 | "popmotion-pose": "^1.3.0", 46 | "react-lifecycles-compat": "^1.1.4" 47 | }, 48 | "unpkg": "./dist/react-pose.js", 49 | "prettier": { 50 | "parser": "typescript", 51 | "singleQuote": true 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /playground/physics.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { BaseAnimation } from './inc'; 3 | import physics from '../packages/popmotion/lib/animations/physics'; 4 | import tween from '../packages/popmotion/lib/animations/tween'; 5 | 6 | export class PhysicsVelocity extends BaseAnimation { 7 | getAnimation = (styler) => physics({ 8 | velocity: 1000 9 | }).start((v) => styler.set('x', v)); 10 | } 11 | export class PhysicsAcceleration extends BaseAnimation { 12 | getAnimation = (styler) => physics({ 13 | velocity: 1000, 14 | acceleration: 1000 15 | }).start((v) => styler.set('x', v)); 16 | } 17 | export class PhysicsFriction extends BaseAnimation { 18 | getAnimation = (styler) => physics({ 19 | velocity: 1000, 20 | friction: 0.5 21 | }).start((v) => styler.set('x', v)); 22 | } 23 | export class PhysicsSpring extends BaseAnimation { 24 | getAnimation = (styler) => physics({ 25 | velocity: 1000, 26 | friction: 0.9, 27 | springStrength: 300, 28 | to: 500 29 | }).start((v) => styler.set('x', v)); 30 | } 31 | export class PhysicsChangeSpringTarget extends BaseAnimation { 32 | getAnimation = (styler) => { 33 | const simulation = physics({ 34 | velocity: 1000, 35 | friction: 0.5, 36 | springStrength: 300, 37 | to: 500 38 | }).start((v) => styler.set('x', v)); 39 | 40 | tween({ from: 500, to: 0, yoyo: Infinity }) 41 | .start((v) => simulation.setSpringTarget(v)) 42 | 43 | return simulation; 44 | } 45 | } -------------------------------------------------------------------------------- /playground/tween.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { currentFrameTime } from 'framesync'; 3 | import { BaseAnimation } from './inc'; 4 | import tween from '../packages/popmotion/lib/animations/tween'; 5 | import value from '../packages/popmotion/lib/reactions/value'; 6 | 7 | export class TweenBasic extends BaseAnimation { 8 | getAnimation = (styler) => tween({ 9 | loop: Infinity, 10 | duration: 3000 11 | }).start((v) => styler.set('opacity', v)); 12 | } 13 | 14 | export class TweenLoop extends BaseAnimation { 15 | getAnimation = (styler) => tween({ 16 | from: 50, 17 | to: 300, 18 | loop: Infinity, 19 | duration: 1000 20 | }).start((v) => styler.set('x', v)); 21 | } 22 | 23 | export class TweenFlip extends BaseAnimation { 24 | getAnimation = (styler) => tween({ 25 | from: 50, 26 | to: 300, 27 | flip: Infinity, 28 | duration: 1000 29 | }).start((v) => styler.set('x', v)); 30 | } 31 | 32 | export class TweenYoyo extends BaseAnimation { 33 | getAnimation = (styler) => tween({ 34 | from: 50, 35 | to: 300, 36 | yoyo: Infinity, 37 | duration: 1000 38 | }).start((v) => { 39 | styler.set('x', v) 40 | }); 41 | } 42 | 43 | export class TweenWithVelocity extends BaseAnimation { 44 | getAnimation = (styler) => { 45 | const val = value(0).subscribe((v) => styler.set('x', v)); 46 | return tween({ 47 | loop: Infinity, 48 | to: 300, 49 | duration: 3000 50 | }).start(val); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /site/pages/_document.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Document, { Head, Main, NextScript } from 'next/document'; 3 | import { ServerStyleSheet } from 'styled-components'; 4 | import Analytics from '~/templates/global/Analytics'; 5 | 6 | export default class PageTemplate extends Document { 7 | render() { 8 | const stylesheet = new ServerStyleSheet(); 9 | const main = stylesheet.collectStyles(
); 10 | const styleTags = stylesheet.getStyleElement(); 11 | 12 | return ( 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | {styleTags} 25 | 26 | 27 | 28 | {main} 29 | 30 | 31 | 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/popmotion/src/reactions/_tests/value.test.ts: -------------------------------------------------------------------------------- 1 | import physics from '../../animations/physics'; 2 | import value from '../value'; 3 | 4 | describe('value', () => { 5 | it('should correctly report velocity', () => { 6 | return new Promise((resolve, reject) => { 7 | const num = value(0); 8 | physics({ velocity: 100 }).start(num); 9 | setTimeout(() => { 10 | num.getVelocity() >= 95 && num.getVelocity() <= 105 ? resolve() : reject(); 11 | }, 200); 12 | }); 13 | }) 14 | 15 | it('should correctly report object velocity', () => { 16 | return new Promise((resolve, reject) => { 17 | const num = value({ x: 0, y: 0 }); 18 | physics({ velocity: { x: 100, y: 200 } }).start(num); 19 | setTimeout(() => { 20 | const velocity = num.getVelocity(); 21 | 22 | velocity.x >= 95 && velocity.x <= 105 && velocity.y >= 195 && velocity.y <= 205 23 | ? resolve() : reject(`${velocity.x}, ${velocity.y}`); 24 | }, 200); 25 | }); 26 | }) 27 | 28 | it('should correctly report array velocity', () => { 29 | return new Promise((resolve, reject) => { 30 | const num = value([0, 0]); 31 | physics({ velocity: [100, 200] }).start(num); 32 | setTimeout(() => { 33 | const velocity = num.getVelocity(); 34 | 35 | velocity[0] >= 99 && velocity[0] <= 101 && velocity[1] >= 199 && velocity[1] <= 201 36 | ? resolve() : reject(velocity); 37 | }, 200); 38 | }); 39 | }) 40 | }) 41 | -------------------------------------------------------------------------------- /site/templates/Popmotion/LiveExamples/Spring.js: -------------------------------------------------------------------------------- 1 | import Template from './Template'; 2 | import { Ball, AlignCenter } from './styled'; 3 | import { spring, styler, value, listen, pointer } from 'popmotion'; 4 | 5 | const code = `spring({ 6 | from: ballXY.get(), 7 | to: 0, 8 | velocity: ballXY.getVelocity(), 9 | stiffness: 200 10 | })`; 11 | 12 | class Example extends React.Component { 13 | startAnimation = (ref) => { 14 | if (!ref) return; 15 | this.boxStyler = styler(ref); 16 | this.ballXY = value({ x: 0, y: 0 }, this.boxStyler.set); 17 | 18 | listen(ref, 'mousedown touchstart') 19 | .start((e) => { 20 | e.preventDefault(); 21 | pointer(this.ballXY.get()).start(this.ballXY); 22 | }); 23 | 24 | listen(document, 'mouseup touchend') 25 | .start(() => { 26 | spring({ 27 | from: this.ballXY.get(), 28 | velocity: this.ballXY.getVelocity(), 29 | to: { x: 0, y: 0 }, 30 | stiffness: 200, 31 | }).start(this.ballXY); 32 | }); 33 | }; 34 | 35 | componentWillUnmount() { 36 | this.ballXY && this.ballXY.stop(); 37 | } 38 | 39 | render() { 40 | return ( 41 | 42 | 43 | Throw 44 | 45 | 46 | ); 47 | } 48 | } 49 | 50 | export default () => ( 51 | 54 | ); 55 | -------------------------------------------------------------------------------- /site/templates/Pose/USPs/DeclarativeExample.js: -------------------------------------------------------------------------------- 1 | import Template from '~/templates/Popmotion/LiveExamples/Template'; 2 | import { 3 | Carousel, 4 | Item, 5 | AlignCenter 6 | } from '~/templates/Popmotion/LiveExamples/styled'; 7 | import { styler, value, listen, pointer, decay, transform } from 'popmotion'; 8 | import posed from 'react-pose'; 9 | import styled from 'styled-components'; 10 | import { color } from '~/styles/vars'; 11 | 12 | const props = { 13 | open: { scale: 1 }, 14 | closed: { scale: 0 } 15 | }; 16 | 17 | const Box = styled(posed.div(props))` 18 | width: 100px; 19 | height: 100px; 20 | background: ${color.blue}; 21 | border-radius: 50%; 22 | transform: scaleX(0); 23 | transform-origin: 50%; 24 | `; 25 | 26 | const code = `// Vanilla 27 | poser.set('open') 28 | 29 | // React 30 | ({ isOpen }) => 31 | `; 32 | 33 | class Example extends React.Component { 34 | state = { isVisible: false }; 35 | 36 | componentDidMount() { 37 | this.interval = setInterval(this.toggleVisibility, 1000); 38 | } 39 | 40 | componentWillUnmount() { 41 | clearInterval(this.interval); 42 | } 43 | 44 | toggleVisibility = () => this.setState({ isVisible: !this.state.isVisible }); 45 | 46 | render() { 47 | return ; 48 | } 49 | } 50 | 51 | export default () => ( 52 | 57 | ); 58 | -------------------------------------------------------------------------------- /packages/popmotion/src/reactions/index.ts: -------------------------------------------------------------------------------- 1 | import { ColdSubscription } from '../action/types'; 2 | import Chainable from '../chainable'; 3 | import createObserver from '../observer'; 4 | import { IObserver, ObserverCandidate } from '../observer/types'; 5 | import { HotSubscription } from './types'; 6 | 7 | export abstract class BaseMulticast extends Chainable implements IObserver { 8 | private parent: ColdSubscription; 9 | private subscribers: IObserver[] = []; 10 | 11 | complete(): void { 12 | this.subscribers.forEach((subscriber) => subscriber.complete()); 13 | } 14 | 15 | error(err: any): void { 16 | this.subscribers.forEach((subscriber) => subscriber.error(err)); 17 | } 18 | 19 | update(v: any): void { 20 | for (let i = 0; i < this.subscribers.length; i++) { 21 | this.subscribers[i].update(v); 22 | } 23 | } 24 | 25 | subscribe(observerCandidate: ObserverCandidate): HotSubscription { 26 | const observer = createObserver(observerCandidate, this.props); 27 | this.subscribers.push(observer); 28 | 29 | const subscription = { 30 | unsubscribe: () => { 31 | const index = this.subscribers.indexOf(observer); 32 | if (index !== -1) this.subscribers.splice(index, 1); 33 | } 34 | }; 35 | 36 | return subscription; 37 | } 38 | 39 | stop(): void { 40 | if (this.parent) this.parent.stop(); 41 | } 42 | 43 | registerParent(subscription: ColdSubscription): void { 44 | this.stop(); 45 | this.parent = subscription; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /site/templates/Popmotion/LiveExamples/Multitouch.js: -------------------------------------------------------------------------------- 1 | import Template from './Template'; 2 | import { Box, AlignCenter } from './styled'; 3 | import { styler, value, listen, multitouch } from 'popmotion'; 4 | 5 | const code = `const box = document.querySelector('.box'); 6 | const boxTransform = value({ x: 0, y: 0 }, styler(box).set); 7 | 8 | listen(box, 'touchstart') 9 | .filter(({ touches }) => touches.length >= 2) 10 | .start(() => { 11 | multitouch(boxTransform.get()) 12 | .start(boxTransform); 13 | });`; 14 | 15 | class Example extends React.Component { 16 | startAnimation = (ref) => { 17 | if (!ref) return; 18 | 19 | const ballStyler = styler(ref); 20 | this.box = value({ scale: 1, rotate: 0 }, ballStyler.set); 21 | 22 | listen(ref, 'touchstart') 23 | .filter(({ touches }) => touches.length >= 2) 24 | .start((e) => { 25 | e.preventDefault(); 26 | multitouch(this.box.get()).start(this.box) 27 | }); 28 | 29 | listen(document, 'mouseup touchend') 30 | .start(() => this.box.stop()); 31 | } 32 | 33 | componentWillUnmount() { 34 | this.box && this.box.stop(); 35 | } 36 | 37 | render() { 38 | return ( 39 | 40 | {`Pinch & zoom`} 41 | 42 | ); 43 | } 44 | } 45 | 46 | export default () => ( 47 | 52 | ); 53 | -------------------------------------------------------------------------------- /packages/popmotion/docs/api/compositors/parallel.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Parallel 3 | description: Control multiple actions in parallel and output as an array. 4 | category: compositors 5 | --- 6 | 7 | # Parallel 8 | 9 | Control an n-dimensional array of actions in parallel, and output as an array. 10 | 11 | ## Import 12 | 13 | ```javascript 14 | import { parallel } from 'popmotion'; 15 | // or stand-alone: 16 | import parallel from 'popmotion/compositors/parallel'; 17 | ``` 18 | 19 | ## Usage 20 | 21 | ```javascript 22 | parallel( 23 | tween({ from: 40, to: 50 }), 24 | spring({ to: 500 }) 25 | ).start(([ tweenOutput, springOutput ]) => {}); 26 | ``` 27 | 28 | `parallel` outputs max once per frame. 29 | 30 | ## Methods 31 | 32 | ### Action methods 33 | 34 | `parallel()` returns: 35 | 36 | - `filter((v: any) => boolean)`: Returns a new action that filters out values when the provided function returns `false`. 37 | - `pipe(...funcs: Array<(v) => v)`: Returns a new action that will run `update` values through this sequence of functions. 38 | - `start(update | { update, complete })`: Starts the action and returns a subscription. 39 | - `while((v: any) => boolean)`: Returns a new action that will `complete` when the provided function returns `false`. 40 | 41 | ### Subscription methods 42 | 43 | `parallel().start()` returns: 44 | 45 | - `stop(): void` 46 | 47 | **Note:** If all actions return the same API, for instance all composed actions are `tween`s, the `parallel` subscription will also return a version of that API that controls all child actions. 48 | -------------------------------------------------------------------------------- /packages/popmotion/docs/api/compositors/composite.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Composite 3 | description: Control a map of actions and output to that same structure. 4 | category: compositors 5 | --- 6 | 7 | # Composite 8 | 9 | Control a named map of actions, and output to the same structure. 10 | 11 | ## Import 12 | 13 | ```javascript 14 | import { composite } from 'popmotion'; 15 | // or stand-alone: 16 | import composite from 'popmotion/compositors/composite'; 17 | ``` 18 | 19 | ## Usage 20 | 21 | ```javascript 22 | composite({ 23 | x: tween({ from: 60, to: 400 }), 24 | y: physics({ from: 60, velocity: 300 }) 25 | }).start(({ x, y }) => {}); 26 | ``` 27 | 28 | `composite` outputs at most once per frame. 29 | 30 | ## Methods 31 | 32 | ### Action methods 33 | 34 | `composite()` returns: 35 | 36 | - `filter((v: any) => boolean)`: Returns a new action that filters out values when the provided function returns `false`. 37 | - `pipe(...funcs: Array<(v) => v)`: Returns a new action that will run `update` values through this sequence of functions. 38 | - `start(update | { update, complete })`: Starts the action and returns a subscription. 39 | - `while((v: any) => boolean)`: Returns a new action that will `complete` when the provided function returns `false`. 40 | 41 | ### Subscription methods 42 | 43 | `composite().start()` returns: 44 | 45 | - `stop(): void` 46 | 47 | **Note:** If all actions return the same API, for instance all composed actions are `tween`s, the `composite` subscription will also return a version of that API that controls all child actions. 48 | -------------------------------------------------------------------------------- /packages/popmotion/docs/api/compositors/crossfade.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Crossfade 3 | description: Fade between two numerical actions. 4 | category: compositors 5 | --- 6 | 7 | # Crossfade 8 | 9 | Fade between two numerical actions. 10 | 11 | ## Import 12 | 13 | ```javascript 14 | import { crossfade } from 'popmotion'; 15 | // or stand-alone: 16 | import crossfade from 'popmotion/compositors/crossfade'; 17 | ``` 18 | 19 | ## Usage 20 | 21 | Example: blend from one tween to another: 22 | 23 | ```javascript 24 | const blendTweens = crossfade( 25 | tween({ from: 0, to: 500, elapsed: 200 }), 26 | tween({ from: 500, to: 0 }) 27 | ).start((v) => console.log(v)); 28 | 29 | tween({ duration: 100 }).start(blendTweens.setBalance); 30 | ``` 31 | 32 | ## Methods 33 | 34 | ### Action methods 35 | 36 | `crossfade()` returns: 37 | 38 | - `filter((v: any) => boolean)`: Returns a new action that filters out values when the provided function returns `false`. 39 | - `pipe(...funcs: Array<(v) => v)`: Returns a new action that will run `update` values through this sequence of functions. 40 | - `start(update | { update, complete })`: Starts the action and returns a subscription. 41 | - `while((v: any) => boolean)`: Returns a new action that will `complete` when the provided function returns `false`. 42 | 43 | 44 | ### Subscription methods 45 | 46 | `crossfade().start()` returns: 47 | 48 | - `setBalance(): this`: Sets the balance of blended output from the first action (`0`) to the second (`1`). 49 | - `stop(): void` 50 | 51 | ## Example 52 | 53 | 54 | -------------------------------------------------------------------------------- /packages/popmotion/docs/learn/basics/install.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Install Popmotion 3 | description: Overview of Popmotion's different installation options. 4 | category: basics 5 | next: get-started 6 | --- 7 | 8 | # Install Popmotion 9 | 10 | ## Package managers 11 | 12 | ### npm 13 | 14 | ```bash 15 | npm install popmotion --save 16 | ``` 17 | 18 | ### yarn 19 | 20 | ```bash 21 | yarn add popmotion 22 | ``` 23 | 24 | ## File include 25 | 26 | **Note:** The Popmotion documentation uses the `import` syntax for importing individual modules. 27 | 28 | **If you use one of the following installation methods, Popmotion will be available on the global `popmotion` variable.** 29 | 30 | So, when you see in the docs `import { tween } from 'popmotion'`, you will use `const { tween } = popmotion` instead. 31 | 32 | ### Download 33 | 34 | You can download the latest version of Popmotion at https://unpkg.com/popmotion/dist/popmotion.global.min.js 35 | 36 | ### `script` include: 37 | 38 | Or include it directly in your HTML with this `script` tag: 39 | 40 | ```html 41 | 42 | ``` 43 | 44 | ### CodePen 45 | 46 | You can fork the [Popmotion playground on CodePen](https://codepen.io/popmotion/pen/zPjXWa?editors=0010), which is set up with the latest version of Popmotion. 47 | 48 | You an also add Popmotion to any existing CodePen project by clicking on Settings > JavaScript and then pasting `https://unpkg.com/popmotion/dist/popmotion.global.min.js` into the "Add External JavaScript" field. 49 | -------------------------------------------------------------------------------- /packages/popmotion/docs/api/compositors/schedule.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Schedule 3 | description: Use an action to control the output of another. 4 | category: compositors 5 | --- 6 | 7 | # Schedule 8 | 9 | `schedule` can use one action to control the output of another. 10 | 11 | For instance, by default `pointer` outputs only when the pointer updates. 12 | 13 | With `schedule`, you could compose it with `everyFrame` to output the latest `pointer` value every frame. 14 | 15 | ## Import 16 | 17 | ```javascript 18 | import { schedule } from 'popmotion'; 19 | // or stand-alone: 20 | import schedule from 'popmotion/compositors/schedule'; 21 | ``` 22 | 23 | ## Usage 24 | 25 | ```typescript 26 | schedule(scheduler: Action, subject: Action): Action 27 | ``` 28 | 29 | ```javascript 30 | // `pointer` will output at most once every frame 31 | schedule( 32 | everyFrame(), 33 | pointer() 34 | ).start(({ x, y }) => {}); 35 | ``` 36 | 37 | ## Methods 38 | 39 | ### Action methods 40 | 41 | `schedule()` returns: 42 | 43 | - `filter((v: any) => boolean)`: Returns a new action that filters out values when the provided function returns `false`. 44 | - `pipe(...funcs: Array<(v) => v)`: Returns a new action that will run `update` values through this sequence of functions. 45 | - `start(update | { update, complete })`: Starts the action and returns a subscription. 46 | - `while((v: any) => boolean)`: Returns a new action that will `complete` when the provided function returns `false`. 47 | 48 | ### Subscription methods 49 | 50 | `schedule().start()` returns: 51 | 52 | - `stop(): void` 53 | 54 | -------------------------------------------------------------------------------- /site/templates/Pose/USPs/ZeroConfigExample.js: -------------------------------------------------------------------------------- 1 | import Template from '~/templates/Popmotion/LiveExamples/Template'; 2 | import { 3 | Carousel, 4 | Item, 5 | AlignCenter 6 | } from '~/templates/Popmotion/LiveExamples/styled'; 7 | import { styler, value, listen, pointer, decay, transform } from 'popmotion'; 8 | import posed from 'react-pose'; 9 | import styled from 'styled-components'; 10 | import { color } from '~/styles/vars'; 11 | 12 | const props = { 13 | left: { x: '100%' }, 14 | right: { x: '-100%' } 15 | }; 16 | 17 | const Box = styled(posed.div(props))` 18 | width: 100px; 19 | height: 100px; 20 | background: ${color.brand}; 21 | transform: translateX(-100%); 22 | `; 23 | 24 | const code = `const config = { 25 | left: { x: 100 }, 26 | right: { x: -100 } 27 | } 28 | 29 | // Vanilla 30 | const poser = pose(element, config) 31 | poser.set('left') 32 | 33 | // React Native 34 | const Box = posed.View(config) 35 | () => `; 36 | 37 | class Example extends React.Component { 38 | state = { isVisible: false }; 39 | 40 | componentDidMount() { 41 | this.interval = setInterval(this.toggleVisibility, 1000); 42 | } 43 | 44 | componentWillUnmount() { 45 | clearInterval(this.interval); 46 | } 47 | 48 | toggleVisibility = () => this.setState({ isVisible: !this.state.isVisible }); 49 | 50 | render() { 51 | return ; 52 | } 53 | } 54 | 55 | export default () => ( 56 | 61 | ); 62 | -------------------------------------------------------------------------------- /packages/popmotion/src/animations/decay/index.ts: -------------------------------------------------------------------------------- 1 | // Implementation of https://ariya.io/2013/11/javascript-kinetic-scrolling-part-2 2 | import { timeSinceLastFrame } from 'framesync'; 3 | import { number } from 'style-value-types'; 4 | import action from '../../action'; 5 | import { Action } from '../../action'; 6 | import vectorAction from '../../action/vector'; 7 | import onFrame from '../every-frame'; 8 | import { Props } from './types'; 9 | 10 | const decay = (props: Props = {}): Action => action(({ complete, update }) => { 11 | const { 12 | velocity = 0, 13 | from = 0, 14 | power = 0.8, 15 | timeConstant = 350, 16 | restDelta = 0.5, 17 | modifyTarget 18 | } = props; 19 | let elapsed = 0; 20 | const amplitude = power * velocity; 21 | const idealTarget = Math.round(from + amplitude); 22 | const target = (typeof modifyTarget === 'undefined') 23 | ? idealTarget 24 | : modifyTarget(idealTarget); 25 | 26 | const timer = onFrame().start(() => { 27 | elapsed += timeSinceLastFrame(); 28 | const delta = -amplitude * Math.exp(-elapsed / timeConstant); 29 | const isMoving = (delta > restDelta || delta < -restDelta); 30 | const current = isMoving ? target + delta : target; 31 | 32 | update(current); 33 | 34 | if (!isMoving) { 35 | timer.stop(); 36 | complete(); 37 | } 38 | }); 39 | 40 | return { 41 | stop: () => timer.stop() 42 | }; 43 | }); 44 | 45 | export default vectorAction(decay, { 46 | from: number.test, 47 | modifyTarget: (func: any) => typeof func === 'function', 48 | velocity: number.test 49 | }); 50 | -------------------------------------------------------------------------------- /site/templates/Popmotion/LiveExamples/Tween.js: -------------------------------------------------------------------------------- 1 | import Template from './Template'; 2 | import { Box, VerticalCenter } from './styled'; 3 | import { easing, styler, tween } from 'popmotion'; 4 | import trackVisibility from './track-visibility'; 5 | 6 | const code = `tween({ 7 | from: 0, 8 | to: { x: 300, rotate: 180 }, 9 | duration: 1000, 10 | ease: easing.backOut, 11 | flip: Infinity 12 | })`; 13 | 14 | class Tween extends React.Component { 15 | setRef = (ref) => { 16 | if (!ref) return; 17 | this.boxStyler = styler(ref); 18 | if (this.props.isVisible) this.startAnimation(); 19 | }; 20 | 21 | componentWillReceiveProps({ isVisible: willBeVisible }) { 22 | const { isVisible } = this.props; 23 | if (!isVisible && willBeVisible) this.startAnimation(); 24 | if (isVisible && !willBeVisible) this.stopAnimation(); 25 | } 26 | 27 | componentWillUnmount() { 28 | this.stopAnimation(); 29 | } 30 | 31 | startAnimation() { 32 | this.animation = tween({ 33 | to: { x: 300, rotate: 180 }, 34 | duration: 1200, 35 | ease: easing.backOut, 36 | flip: Infinity 37 | }).start(this.boxStyler.set); 38 | } 39 | 40 | stopAnimation() { 41 | this.animation && this.animation.stop(); 42 | } 43 | 44 | render() { 45 | return ; 46 | } 47 | } 48 | 49 | export default trackVisibility(({ isVisible }) => ( 50 | 55 | )); 56 | -------------------------------------------------------------------------------- /packages/animated-pose/src/types.ts: -------------------------------------------------------------------------------- 1 | import { Poser, PoserConfig } from 'pose-core'; 2 | import { Animated } from 'react-native'; 3 | 4 | export type Interpolation = { 5 | inputRange: number[]; 6 | outputRange: string[] | number[]; 7 | }; 8 | 9 | export type Value = { 10 | raw?: Animated.Value; 11 | interpolation?: Animated.AnimatedInterpolation; 12 | useNativeDriver?: boolean; 13 | }; 14 | 15 | export type Action = Animated.CompositeAnimation; 16 | 17 | export interface AnimatedPoser extends Poser { 18 | addChild: (config: AnimatedPoseConfig) => AnimatedPoser; 19 | } 20 | 21 | export type TransitionProps = { 22 | value: Animated.Value; 23 | toValue: number; 24 | [key: string]: any; 25 | }; 26 | 27 | export type Transition = ( 28 | { value, toValue }: TransitionProps 29 | ) => Animated.CompositeAnimation; 30 | 31 | export type CreateValueProps = { 32 | passiveParent?: Value; 33 | passiveProps?: Interpolation; 34 | props?: { [key: string]: any }; 35 | }; 36 | 37 | export type AnimatedPoseConfig = PoserConfig; 38 | 39 | export type AnimatedFactoryConfig = { 40 | convertUnitToPoints: (v: string) => number; 41 | unitConverters: UnitConverterMap; 42 | }; 43 | 44 | export type AnimatedPoserFactory = ( 45 | config: AnimatedPoseConfig 46 | ) => Poser; 47 | 48 | export type UnitConverter = (v: number) => number; 49 | 50 | export type DimensionConverterFactory = ( 51 | viewport: 'window' | 'screen', 52 | axis: 'width' | 'height' 53 | ) => UnitConverter; 54 | 55 | export type UnitConverterMap = { [key: string]: UnitConverter }; 56 | -------------------------------------------------------------------------------- /packages/react-pose-core/src/types.ts: -------------------------------------------------------------------------------- 1 | import { Animated } from 'react-native'; 2 | import { ReactNode } from 'react'; 3 | import { AnimatedPoser, AnimatedPoseConfig } from 'animated-pose'; 4 | 5 | export type PosedComponent = (config: AnimatedPoseConfig) => ReactNode; 6 | 7 | export type PosedComponentFactory = (Component: any) => PosedComponent; 8 | 9 | export type Posed = any; 10 | 11 | export type Props = { [key: string]: any }; 12 | 13 | export type PoseContextProps = { 14 | registerAsChild: (props: AnimatedPoseConfig) => AnimatedPoser; 15 | onUnmount: (child: AnimatedPoser) => void; 16 | }; 17 | 18 | export type PoseComponentProps = { 19 | withParent?: boolean; 20 | pose?: CurrentPose; 21 | children?: React.ReactNode | ChildAsFunction; 22 | poseKey?: any; 23 | [key: string]: any; 24 | }; 25 | 26 | export type ValueMap = { 27 | [key: string]: Animated.Value; 28 | }; 29 | 30 | export type CurrentPose = string | string[]; 31 | 32 | export type ChildAsFunction = (values: ValueMap) => ReactNode; 33 | 34 | export type PosedComponentFactoryConfig = { 35 | componentMap: { [key: string]: React.Component }; 36 | poseFactory: any; 37 | createAnimatedComponent: (component: React.Component) => React.Component; 38 | filterConfig: (config: AnimatedPoseConfig) => AnimatedPoseConfig; 39 | transformConfig: ( 40 | config: AnimatedPoseConfig, 41 | props: PoseComponentProps 42 | ) => void; 43 | getProps: ( 44 | poser: AnimatedPoser, 45 | config: AnimatedPoseConfig, 46 | props: PoseComponentProps 47 | ) => Props; 48 | getStylesFromPoser: (poser: AnimatedPoser) => { [key: string]: any }; 49 | }; 50 | -------------------------------------------------------------------------------- /packages/popmotion/src/compositors/multi.ts: -------------------------------------------------------------------------------- 1 | import { onFrameUpdate } from 'framesync'; 2 | import action, { Action } from '../action'; 3 | import { ColdSubscription } from '../action/types'; 4 | 5 | export type ActionStarter = (action: Action, key: I) => ColdSubscription; 6 | 7 | export type MultiProps = { 8 | getCount: (actions: A) => number; 9 | getFirst: (subs: T) => ColdSubscription; 10 | getOutput: () => V; 11 | mapApi: (subs: T, methodName: string) => (...args: any[]) => V; 12 | setProp: (output: V, name: I, value: any) => any; 13 | startActions: (actions: A, starter: ActionStarter) => T; 14 | }; 15 | 16 | const multi = ({ 17 | getCount, 18 | getFirst, 19 | getOutput, 20 | mapApi, 21 | setProp, 22 | startActions 23 | }: MultiProps) => (actions: A): Action => action(({ update, complete, error }) => { 24 | const numActions = getCount(actions); 25 | const output = getOutput(); 26 | const updateOutput = () => update(output); 27 | let numCompletedActions = 0; 28 | 29 | const subs = startActions(actions, (a, name) => a.start({ 30 | complete: () => { 31 | numCompletedActions++; 32 | if (numCompletedActions === numActions) onFrameUpdate(complete); 33 | }, 34 | error, 35 | update: (v: any) => { 36 | setProp(output, name, v); 37 | onFrameUpdate(updateOutput, true); 38 | } 39 | })); 40 | 41 | return Object.keys(getFirst(subs)) 42 | .reduce((api: { [key: string ]: Function }, methodName) => { 43 | api[methodName] = mapApi(subs, methodName); 44 | return api; 45 | }, {}); 46 | }); 47 | 48 | export default multi; 49 | -------------------------------------------------------------------------------- /site/scripts/generate-content-page.js: -------------------------------------------------------------------------------- 1 | const escapeBackticks = string => string.replace(/`/g, '\\`'); 2 | 3 | module.exports = ( 4 | body, 5 | { category, id, title, description, published, siteName, section, next } 6 | ) => ` 7 | import { createElement } from 'react'; 8 | import marksy from 'marksy/components'; 9 | import { A, H1, H2, H3, H4, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled'; 10 | import { Img } from '~/templates/content/styled'; 11 | import ContentTemplate from '~/templates/content/Template'; 12 | import Example from '~/components/examples/Example'; 13 | import CodePen from '~/components/examples/CodePen'; 14 | 15 | const removeEmpty = filename => filename !== ''; 16 | 17 | const convertMarkdown = marksy({ 18 | createElement, 19 | elements: { 20 | a: A, 21 | h1: ArticleHeader, 22 | h2: H2, 23 | h3: H3, 24 | h4: H4, 25 | p: P, 26 | code: Code, 27 | li: Li, 28 | ol: Ol, 29 | ul: Ul, 30 | hr: Hr, 31 | img: Img, 32 | blockquote: Blockquote, 33 | }, 34 | components: { 35 | Example, 36 | CodePen, 37 | Video 38 | } 39 | }); 40 | 41 | const content = convertMarkdown(\`${escapeBackticks(body)}\`); 42 | 43 | const Page = ({ section }) => ( 44 | 54 | {content.tree} 55 | 56 | ); 57 | 58 | export default Page; 59 | `; 60 | -------------------------------------------------------------------------------- /packages/popmotion-spinnable/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "popmotion-spinnable", 3 | "version": "2.0.0", 4 | "description": "Make DOM nodes spinnable with Popmotion", 5 | "author": "Matt Perry ", 6 | "homepage": "http://popmotion.io", 7 | "main": "./lib/index.js", 8 | "esnext": "./src/index.js", 9 | "files": [ 10 | "lib", 11 | "src" 12 | ], 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/Popmotion/popmotion/tree/master/packages/popmotion-spinnable/" 16 | }, 17 | "bugs": { 18 | "url": "https://github.com/Popmotion/popmotion/issues" 19 | }, 20 | "keywords": [ 21 | "popmotion", 22 | "animation", 23 | "window", 24 | "react", 25 | "react animation", 26 | "spin" 27 | ], 28 | "analyze": true, 29 | "license": "MIT", 30 | "scripts": { 31 | "compile": "babel src --out-dir lib" 32 | }, 33 | "devDependencies": { 34 | "babel-cli": "^6.24.1", 35 | "babel-core": "^6.0.20", 36 | "babel-eslint": "^6.0.2", 37 | "babel-plugin-root-import": "^5.1.0", 38 | "babel-plugin-transform-export-extensions": "^6.4.0", 39 | "babel-plugin-transform-react-constant-elements": "^6.9.1", 40 | "babel-plugin-transform-react-jsx": "^6.7.5", 41 | "babel-plugin-transform-react-remove-prop-types": "^0.2.6", 42 | "babel-plugin-transform-runtime": "^6.23.0", 43 | "babel-preset-env": "^1.6.1", 44 | "babel-preset-react": "^6.16.0", 45 | "babel-preset-stage-0": "^6.24.1", 46 | "babel-preset-stage-2": "^6.17.0", 47 | "babel-register": "^6.3.13" 48 | }, 49 | "dependencies": { 50 | "popmotion": "^8.1.0" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /site/templates/Popmotion/LiveExamples/Stepped.js: -------------------------------------------------------------------------------- 1 | import Template from './Template'; 2 | import { Ball, AlignCenter } from './styled'; 3 | import { schedule, styler, value, listen, pointer, transform, everyFrame } from 'popmotion'; 4 | 5 | const { smooth } = transform; 6 | 7 | const code = `const { transformMap, smooth } = transform; 8 | 9 | const smoothXY = transformMap({ 10 | x: smooth(200), 11 | y: smooth(200) 12 | }); 13 | 14 | listen(ball, 'mousedown touchstart').start(() => 15 | schedule(everyFrame(), pointer(ballXY.get())) 16 | .pipe(smoothXY) 17 | .start(ballXY) 18 | );`; 19 | 20 | class Example extends React.Component { 21 | startAnimation = (ref) => { 22 | if (!ref) return; 23 | this.boxStyler = styler(ref); 24 | this.ballXY = value({ x: 0, y: 0 }, this.boxStyler.set); 25 | 26 | const smoothXY = transform.transformMap({ 27 | x: smooth(200), 28 | y: smooth(200) 29 | }); 30 | 31 | listen(ref, 'mousedown touchstart').start((e) => { 32 | e.preventDefault(); 33 | schedule(everyFrame(), pointer(this.ballXY.get())) 34 | .pipe(smoothXY) 35 | .start(this.ballXY) 36 | }); 37 | 38 | listen(document, 'mouseup touchend').start(() => this.ballXY.stop()); 39 | }; 40 | 41 | componentWillUnmount() { 42 | this.ballXY && this.ballXY.stop(); 43 | } 44 | 45 | render() { 46 | return ( 47 | 48 | 49 | Drag 50 | 51 | 52 | ); 53 | } 54 | } 55 | 56 | export default () => ( 57 | 60 | ); 61 | -------------------------------------------------------------------------------- /site/templates/global/SectionNav.js: -------------------------------------------------------------------------------- 1 | import styled, { withTheme } from 'styled-components'; 2 | import SiteLink from '~/components/layout/SiteLink'; 3 | import { fontSize, fontBold } from '~/styles/fonts'; 4 | import { ACTION, ENTITY, WHITE, BLACK, cols, media, SKEW } from '~/styles/vars'; 5 | import sectionNames from '~/data/section-names.json'; 6 | import routes from '~/data/route-paths.json'; 7 | 8 | const MenuItem = styled.li` 9 | ${fontSize(18)} display: inline; 10 | padding-bottom: 4px; 11 | margin-right: ${cols(2)}; 12 | position: relative; 13 | 14 | &:last-child { 15 | margin-right: 0; 16 | } 17 | 18 | ${({ isSelected }) => 19 | isSelected && 20 | ` 21 | &:after { 22 | content: ''; 23 | display: block; 24 | background: ${ENTITY}; 25 | position: absolute; 26 | bottom: -3px; 27 | right: 0; 28 | left: 0; 29 | height: 4px; 30 | transform: skewX(${SKEW}); 31 | } 32 | `} ${media.large` 33 | ${fontSize(16)} 34 | margin-right: ${cols(1)}; 35 | `} a { 36 | color: ${props => (props.isHomepage ? WHITE : BLACK)}; 37 | text-decoration: none; 38 | ${fontBold}; 39 | } 40 | `; 41 | 42 | const SectionNav = ({ section, theme, isHomepage }) => ( 43 |
    44 | {theme.sections.map(name => ( 45 | 50 | 51 | {sectionNames[name]} 52 | 53 | 54 | ))} 55 |
56 | ); 57 | 58 | export default withTheme(SectionNav); 59 | -------------------------------------------------------------------------------- /packages/popmotion/src/observer/index.ts: -------------------------------------------------------------------------------- 1 | import { IObserver, Middleware, ObserverCandidate, ObserverProps, PartialObserver, Update } from './types'; 2 | 3 | // TODO clear up some of the terminology here and look at merging more generally with Reaction 4 | export class Observer implements IObserver { 5 | private isActive = true; 6 | private observer: PartialObserver; 7 | private updateObserver: Update; 8 | private onComplete: Function; 9 | 10 | constructor({ middleware, onComplete }: ObserverProps, observer: PartialObserver) { 11 | this.observer = observer; 12 | this.updateObserver = (v: any) => observer.update(v); 13 | this.onComplete = onComplete; 14 | 15 | if (observer.update && middleware && middleware.length) { 16 | middleware.forEach((m: Middleware) => this.updateObserver = m(this.updateObserver, this.complete)); 17 | } 18 | } 19 | 20 | update = (v: any) => { 21 | if (this.observer.update) this.updateObserver(v); 22 | } 23 | 24 | complete = () => { 25 | if (this.observer.complete && this.isActive) this.observer.complete(); 26 | if (this.onComplete) this.onComplete(); 27 | this.isActive = false; 28 | } 29 | 30 | error = (err: any) => { 31 | if (this.observer.error && this.isActive) this.observer.error(err); 32 | this.isActive = false; 33 | } 34 | } 35 | 36 | export default (observerCandidate: ObserverCandidate, { middleware }: ObserverProps, onComplete?: Function) => { 37 | if (typeof observerCandidate === 'function') { 38 | return new Observer({ middleware, onComplete }, { update: observerCandidate }); 39 | } else { 40 | return new Observer({ middleware, onComplete }, observerCandidate); 41 | } 42 | }; 43 | -------------------------------------------------------------------------------- /packages/popmotion/docs/api/compositors/stagger.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Stagger 3 | description: Stagger the execution of a series of actions. 4 | category: compositors 5 | --- 6 | 7 | # Stagger 8 | 9 | Stagger the execution of a series of actions. 10 | 11 | ## Import 12 | 13 | ```javascript 14 | import { stagger } from 'popmotion'; 15 | // or stand-alone: 16 | import stagger from 'popmotion/compositors/stagger'; 17 | ``` 18 | 19 | ## Usage 20 | 21 | ```typescript 22 | stagger(actions: Action[], interval: number | (i: number) => number): Action 23 | ``` 24 | 25 | `stagger` accepts two arguments, an array of actions and an `interval`: 26 | 27 | ```javascript 28 | stagger([ 29 | tween(), 30 | spring() 31 | ], 100) 32 | ``` 33 | 34 | When started, it outputs the values as an array. Actions that haven't yet started will output `undefined`, and you can define a default. 35 | 36 | ```javascript 37 | stagger([ 38 | tween(), 39 | spring() 40 | ], 100).start((values) => values.forEach((v = 0, i) => { 41 | console.log(v); 42 | })) 43 | ``` 44 | 45 | ## Methods 46 | 47 | ### Action methods 48 | 49 | `stagger()` returns: 50 | 51 | - `filter((v: any) => boolean)`: Returns a new action that filters out values when the provided function returns `false`. 52 | - `pipe(...funcs: Array<(v) => v)`: Returns a new action that will run `update` values through this sequence of functions. 53 | - `start(update | { update, complete })`: Starts the tween and returns a subscription. 54 | - `while((v: any) => boolean)`: Returns a new action that will `complete` when the provided function returns `false`. 55 | 56 | ### Subscription methods 57 | 58 | `stagger().start()` returns: 59 | 60 | - `stop(): void` 61 | 62 | -------------------------------------------------------------------------------- /packages/react-pose-core/src/posed.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { PoseComponent, PoseParentContext } from './components/PoseComponent'; 3 | import { 4 | Posed, 5 | PosedComponentFactory, 6 | PosedComponentFactoryConfig, 7 | PoseContextProps 8 | } from './types'; 9 | 10 | const posedFactory = ({ 11 | componentMap, 12 | createAnimatedComponent, 13 | ...factoryConfig 14 | }: PosedComponentFactoryConfig) => { 15 | const posedComponentFactory: PosedComponentFactory = (Component: any) => ( 16 | poseConfig = {} 17 | ) => ({ withParent = true, ...props }) => { 18 | return !withParent || props.parentValues ? ( 19 | 25 | ) : ( 26 | 27 | {(parentCtx: PoseContextProps) => ( 28 | 35 | )} 36 | 37 | ); 38 | }; 39 | 40 | const posedComponent: Posed = (Component?: any) => 41 | posedComponentFactory( 42 | Component ? createAnimatedComponent(Component) : undefined 43 | ); 44 | 45 | const posed: Posed = Object.keys(componentMap).reduce((acc, key) => { 46 | const Component = componentMap[key]; 47 | acc[key] = posedComponentFactory(Component); 48 | return acc; 49 | }, posedComponent); 50 | 51 | return posed; 52 | }; 53 | 54 | export default posedFactory; 55 | -------------------------------------------------------------------------------- /site/templates/content/styled.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | import { fontSize, fontBold } from '~/styles/fonts'; 3 | import { cols, BLACK, LIGHT_GREY, BRAND } from '~/styles/vars'; 4 | import { htmlUnencode } from '~/utils/string'; 5 | import SiteLink from '~/components/layout/SiteLink'; 6 | import { Centered } from '~/templates/global/grid'; 7 | 8 | const ImgFrame = styled.span` 9 | max-width: ${cols(43)}; 10 | border-bottom: 1px solid ${LIGHT_GREY}; 11 | display: block; 12 | padding: ${cols(1)} 0 ${cols(2)}; 13 | `; 14 | 15 | const Image = styled.img` 16 | margin: 0 auto; 17 | display: block; 18 | max-width: 90vw; 19 | `; 20 | 21 | const Caption = styled.span` 22 | ${fontSize(14)} 23 | color: ${BLACK}; 24 | display: block; 25 | text-align: center; 26 | margin-top: ${cols(1)}; 27 | `; 28 | 29 | export const Img = ({ className, alt, ...props }) => ( 30 | 31 | 32 | {alt ? {htmlUnencode(alt)} : null} 33 | 34 | ); 35 | 36 | export const NextLinkContainer = styled(Centered)` 37 | border-top: 1px ${BRAND} solid; 38 | margin-top: ${cols(2)}; 39 | padding-top: ${cols(2)}; 40 | padding-bottom: ${cols(2)}; 41 | display: flex; 42 | justify-content: flex-end; 43 | 44 | a { 45 | display: flex; 46 | flex-direction: column; 47 | align-items: flex-end; 48 | font-size: 28px; 49 | ${fontBold}; 50 | 51 | span { 52 | font-size: 18px; 53 | font-weight: normal; 54 | } 55 | } 56 | `; 57 | 58 | export const NextLink = styled(SiteLink)` 59 | display: block; 60 | `; 61 | 62 | export const NextLinkSmall = styled.span``; 63 | -------------------------------------------------------------------------------- /packages/animated-pose/src/inc/default-transitions.ts: -------------------------------------------------------------------------------- 1 | import { Transition } from '../types'; 2 | import { Animated } from 'react-native'; 3 | import { eachValue } from 'pose-core'; 4 | 5 | const tween: Transition = ({ value, toValue, useNativeDriver = true }) => 6 | Animated.timing(value, { 7 | toValue, 8 | duration: 300, 9 | useNativeDriver 10 | }); 11 | 12 | const linearTween: Transition = ({ value, toValue, useNativeDriver = true }) => 13 | Animated.timing(value, { 14 | toValue, 15 | duration: 300, 16 | easing: v => v, 17 | useNativeDriver 18 | }); 19 | 20 | const overDampedSpring: Transition = ({ 21 | value, 22 | toValue, 23 | useNativeDriver = true 24 | }) => 25 | Animated.spring(value, { 26 | toValue, 27 | stiffness: 700, 28 | damping: toValue === 0 ? 100 : 35, 29 | useNativeDriver 30 | }); 31 | 32 | const underDampedSpring: Transition = ({ 33 | value, 34 | toValue, 35 | useNativeDriver = true 36 | }) => 37 | Animated.spring(value, { 38 | toValue, 39 | stiffness: 500, 40 | damping: 25, 41 | restDisplacementThreshold: 0.5, 42 | restSpeedThreshold: 10, 43 | useNativeDriver 44 | }); 45 | 46 | const intelligentTransition = eachValue({ 47 | x: underDampedSpring, 48 | y: underDampedSpring, 49 | z: underDampedSpring, 50 | rotate: underDampedSpring, 51 | rotateX: underDampedSpring, 52 | rotateY: underDampedSpring, 53 | rotateZ: underDampedSpring, 54 | scaleX: overDampedSpring, 55 | scaleY: overDampedSpring, 56 | scaleZ: overDampedSpring, 57 | scale: overDampedSpring, 58 | opacity: linearTween, 59 | default: tween 60 | }); 61 | 62 | export default new Map([['default', intelligentTransition]]); 63 | -------------------------------------------------------------------------------- /site/templates/Pose/USPs/DraggableExample.js: -------------------------------------------------------------------------------- 1 | import Template from '~/templates/Popmotion/LiveExamples/Template'; 2 | import { 3 | Carousel, 4 | Item, 5 | AlignCenter 6 | } from '~/templates/Popmotion/LiveExamples/styled'; 7 | import { 8 | styler, 9 | value, 10 | listen, 11 | pointer, 12 | decay, 13 | spring, 14 | transform 15 | } from 'popmotion'; 16 | import posed from 'react-pose'; 17 | import styled from 'styled-components'; 18 | import { color } from '~/styles/vars'; 19 | 20 | const props = { 21 | draggable: 'x', 22 | dragBounds: { left: '-100%', right: '100%' } 23 | }; 24 | 25 | const Box = styled(posed.div(props))` 26 | width: 100px; 27 | height: 100px; 28 | background: ${color.brand}; 29 | transform: scaleX(0); 30 | transform-origin: 50%; 31 | color: white; 32 | display: flex; 33 | justify-content: center; 34 | align-items: center; 35 | font-weight: bold; 36 | `; 37 | 38 | const code = `const config = { 39 | draggable: 'x', 40 | dragBounds: { left: '-100%', right: '100%' } 41 | } 42 | 43 | // Note: 'dragBounds' not yet available for React Native`; 44 | 45 | class Example extends React.Component { 46 | state = { isVisible: false }; 47 | 48 | componentDidMount() { 49 | this.interval = setInterval(this.toggleVisibility, 1000); 50 | } 51 | 52 | componentWillUnmount() { 53 | clearInterval(this.interval); 54 | } 55 | 56 | toggleVisibility = () => this.setState({ isVisible: !this.state.isVisible }); 57 | 58 | render() { 59 | return Drag; 60 | } 61 | } 62 | 63 | export default () => ( 64 | 69 | ); 70 | -------------------------------------------------------------------------------- /site/styles/vars.js: -------------------------------------------------------------------------------- 1 | import { css } from "styled-components"; 2 | 3 | export const verticalGradient = (from, to, start = 0, end = 100) => 4 | `linear-gradient(to bottom, ${from} ${start}%, ${to} ${end}%)`; 5 | 6 | // Deprecated - migrate to single `color` export 7 | export const WHITE = "#fff"; 8 | export const BLACK = "#21282D"; 9 | export const SUPER_LIGHT_GREY = "#FAFAFA"; 10 | export const LIGHT_GREY = "#f2f2f2"; 11 | 12 | export const PINK = "#FF1C68"; 13 | export const PINK_BURN = "#DB0068"; 14 | 15 | export const BLUE = "#198FE3"; 16 | export const BLUE_BURN = "#064FB5"; 17 | 18 | export const GREEN = "#14D790"; 19 | const PURPLE = "#9B65DE"; 20 | 21 | export const BRAND = PINK; 22 | export const BRAND_BURN = PINK_BURN; 23 | export const BRAND_GRADIENT = verticalGradient(PINK, PINK_BURN); 24 | 25 | export const ACTION = BLUE; 26 | export const ACTION_BURN = BLUE_BURN; 27 | export const ACTION_GRADIENT = verticalGradient(BLUE, BLUE_BURN); 28 | 29 | export const ENTITY = PURPLE; 30 | 31 | export const color = { 32 | black: "#21282D", 33 | blue: "#198FE3", 34 | green: "#14D790", 35 | white: "#fff", 36 | pink: "#FF00C8", 37 | purple: "#A100F6", 38 | brand: "#FF1C68", 39 | brandBurn: "#DB0068" 40 | }; 41 | 42 | export const SKEW = "-5.7deg"; 43 | export const UNSKEW = "5.7deg"; 44 | 45 | const COL_WIDTH = 15; 46 | 47 | export const cols = num => `${num * COL_WIDTH}px`; 48 | 49 | const breakpoints = { 50 | large: cols(72), 51 | medium: cols(50), 52 | small: cols(26) 53 | }; 54 | 55 | export const media = Object.keys(breakpoints).reduce((acc, label) => { 56 | acc[label] = (...args) => css` 57 | @media (max-width: ${breakpoints[label]}) { 58 | ${css(...args)}; 59 | } 60 | `; 61 | 62 | return acc; 63 | }, {}); 64 | -------------------------------------------------------------------------------- /packages/popmotion-spinnable/src/index.js: -------------------------------------------------------------------------------- 1 | import { 2 | pointer, 3 | calc, 4 | value, 5 | styler, 6 | physics, 7 | transform, 8 | listen 9 | } from 'popmotion'; 10 | const { angle } = calc; 11 | const { applyOffset } = transform; 12 | 13 | export default function spinnable(node, { 14 | initialRotation = 0, 15 | friction = 0.4, 16 | transformSpin, 17 | onSpin 18 | } = {}) { 19 | const nodeStyler = styler(node); 20 | const nodeRotation = value(initialRotation); 21 | let active; 22 | 23 | nodeRotation.subscribe((v) => { 24 | const current = transformSpin ? transformSpin(v) : v; 25 | if (onSpin) onSpin(current); 26 | nodeStyler.set('rotate', current); 27 | }); 28 | 29 | function startTracking(e) { 30 | e.preventDefault(); 31 | if (active) active.stop(); 32 | 33 | active = pointer() 34 | .pipe( 35 | (v) => { 36 | const nodePos = node.getBoundingClientRect(); 37 | const nodeCenter = { 38 | x: nodePos.left + (nodePos.width / 2), 39 | y: nodePos.top + (nodePos.height / 2) 40 | }; 41 | const angleFromCenter = angle(nodeCenter, v); 42 | 43 | return angleFromCenter; 44 | }, 45 | applyOffset(nodeRotation.get()) 46 | ) 47 | .start(nodeRotation); 48 | } 49 | 50 | function stopTracking() { 51 | if (active) active.stop(); 52 | active = physics({ 53 | from: nodeRotation.get(), 54 | velocity: nodeRotation.getVelocity(), 55 | friction 56 | }).start(nodeRotation); 57 | } 58 | 59 | listen(node, 'mousedown touchstart').start(startTracking); 60 | listen(document, 'mouseup touchend').start(stopTracking); 61 | 62 | return { 63 | stop: () => active && active.stop() 64 | }; 65 | } 66 | -------------------------------------------------------------------------------- /site/components/layout/grid.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | import { verticalGradient, MAIN, MAIN_FADE, WHITE, cols, media } from '~/styles/vars'; 3 | 4 | export const Container = styled.div` 5 | display: grid; 6 | grid-template-columns: ${cols(1)} ${cols(16)} ${cols(56)} 1fr; 7 | grid-template-rows: 75px auto; 8 | grid-template-areas: 9 | "left-margin header header header" 10 | "left-margin content-nav content right-margin" 11 | "left-margin content-nav footer right-margin"; 12 | grid-row-gap: 65px; 13 | min-height: 100vh; 14 | 15 | ${media.large` 16 | grid-template-columns: ${cols(1)} ${cols(12)} 1fr 0; 17 | grid-row-gap: ${cols(3)}; 18 | `} 19 | 20 | ${media.medium` 21 | grid-template-columns: 5px 1fr; 22 | grid-template-areas: 23 | "left-margin header" 24 | "left-margin content-nav" 25 | "left-margin content" 26 | "left-margin footer"; 27 | grid-row-gap: ${cols(2)}; 28 | `} 29 | `; 30 | 31 | export const LeftMargin = styled.div` 32 | background: ${verticalGradient(MAIN_FADE, MAIN)}; 33 | grid-area: left-margin; 34 | `; 35 | 36 | export const RightMargin = styled.div` 37 | background: ${WHITE}; 38 | grid-area: right-margin; 39 | `; 40 | 41 | export const HeaderArea = styled.div` 42 | grid-area: header; 43 | `; 44 | 45 | export const ContentArea = styled.article` 46 | grid-area: content; 47 | padding: 0 ${cols(3)} ${cols(3)} ${cols(1)}; 48 | 49 | ${media.medium` 50 | padding: 0 ${cols(1)} ${cols(1)}; 51 | `} 52 | `; 53 | 54 | export const ContentNavArea = styled.div` 55 | grid-area: content-nav; 56 | padding: 0 ${cols(2)} ${cols(3)}; 57 | 58 | ${media.medium` 59 | padding: 0 ${cols(1)}; 60 | margin: ${cols(1)} 0 ${cols(2)}; 61 | `} 62 | `; 63 | -------------------------------------------------------------------------------- /site/templates/Popmotion/LiveExamples/Color.js: -------------------------------------------------------------------------------- 1 | import Template from './Template'; 2 | import { ColorPanel, AlignCenter } from './styled'; 3 | import { GREEN, ACTION, BRAND, ENTITY } from '~/styles/vars'; 4 | import { styler, easing, keyframes } from 'popmotion'; 5 | import trackVisibility from './track-visibility'; 6 | 7 | const code = `keyframes({ 8 | values: ['${GREEN}', '${ACTION}', '${BRAND}', '${ENTITY}', '${GREEN}'], 9 | duration: 10000, 10 | ease: easing.linear, 11 | loop: Infinity 12 | })`; 13 | 14 | class Example extends React.Component { 15 | setRef = (ref) => { 16 | if (!ref) return; 17 | this.boxStyler = styler(ref); 18 | if (this.props.isVisible) this.startAnimation(); 19 | }; 20 | 21 | componentWillReceiveProps({ isVisible: willBeVisible }) { 22 | const { isVisible } = this.props; 23 | if (!isVisible && willBeVisible) this.startAnimation(); 24 | if (isVisible && !willBeVisible) this.stopAnimation(); 25 | } 26 | 27 | startAnimation = () => { 28 | this.animation = keyframes({ 29 | values: [GREEN, ACTION, BRAND, ENTITY, GREEN], 30 | duration: 10000, 31 | ease: easing.linear, 32 | loop: Infinity 33 | }).start(this.boxStyler.set('background')); 34 | }; 35 | 36 | componentWillUnmount() { 37 | this.stopAnimation(); 38 | } 39 | 40 | stopAnimation() { 41 | this.animation && this.animation.stop(); 42 | } 43 | 44 | render() { 45 | return ( 46 | 47 | ); 48 | } 49 | } 50 | 51 | export default trackVisibility(({isVisible}) => ( 52 | 57 | )); 58 | -------------------------------------------------------------------------------- /playground/compositors.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { BaseAnimation } from './inc'; 3 | import chain from '../packages/popmotion/lib/compositors/chain'; 4 | import composite from '../packages/popmotion/lib/compositors/composite'; 5 | import delay from '../packages/popmotion/lib/compositors/delay'; 6 | import crossfade from '../packages/popmotion/lib/compositors/crossfade'; 7 | import tween from '../packages/popmotion/lib/animations/tween'; 8 | import physics from '../packages/popmotion/lib/animations/physics'; 9 | 10 | //import { Chain, Composite, Delay, Crossfade, Merge, Parallel, Stagger } from './compositors'; 11 | 12 | export class Chain extends BaseAnimation { 13 | getAnimation = (styler) => chain( 14 | tween({ to: 300 }), 15 | physics({ to: 0 }) 16 | ).start(styler.set('x')) 17 | } 18 | 19 | export class Crossfade extends BaseAnimation { 20 | getAnimation = (styler) => { 21 | const f = crossfade( 22 | tween({ to: 300 }), 23 | tween({ from: 300, to: 0 }) 24 | ).start(styler.set('x')); 25 | 26 | tween().start(f.setBalance); 27 | } 28 | } 29 | 30 | export class Composite extends BaseAnimation { 31 | getAnimation = (styler) => composite({ 32 | x: tween({ to: 300 }), 33 | y: tween({ to: 300 }) 34 | }).start(styler.set) 35 | } 36 | 37 | export class Delay extends BaseAnimation { 38 | getAnimation = (styler) => chain( 39 | delay(500), 40 | () => tween({ to: 300 }).start(styler.set('x')) 41 | ) 42 | } 43 | 44 | export class Merge extends BaseAnimation { 45 | // getAnimation = (styler) => merge( 46 | // tween() 47 | // ) 48 | } 49 | 50 | export class Parallel extends BaseAnimation { 51 | //getAnimation = (styler) => 52 | } 53 | 54 | export class Stagger extends BaseAnimation { 55 | //getAnimation = (styler) => 56 | } -------------------------------------------------------------------------------- /packages/popmotion-pose/docs/api/transition-compositors.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Transition utils 3 | description: Utility functions for composing transition functions 4 | --- 5 | 6 | # Transition utils 7 | 8 | Poses can be defined with a custom `transition` property. 9 | 10 | This function is run once for **each value in the pose** and can return a different Popmotion animation for each. 11 | 12 | To simplify the creation of this logic, Pose includes two composition functions: 13 | 14 | - `eachValue`: Return different animations for each animating value. 15 | - `fromPose`: Return different animations depending on which pose the previous value was in. 16 | 17 | ## `eachValue` 18 | 19 | Accepts a map of `transition` functions, where each key is the name of an animating value (or `default`, to match remaining values). 20 | 21 | ### Import 22 | 23 | ```javascript 24 | import { eachValue } from 'popmotion-pose' 25 | ``` 26 | 27 | ### Usage 28 | 29 | ```javascript 30 | const props = { 31 | open: { 32 | x: 100, 33 | y: 100, 34 | transition: eachValue({ 35 | x: tween, 36 | y: ({ from, to, velocity }) => spring({ from, to, velocity: velocity * 2 }) 37 | }) 38 | } 39 | } 40 | ``` 41 | 42 | ## `fromPose` 43 | 44 | Accepts a map of `transition` functions, where each key is the name of another pose (or `default`, to match remaining poses). 45 | 46 | ### Import 47 | 48 | ```javascript 49 | import { fromPose } from 'popmotion-pose' 50 | ``` 51 | 52 | ### Usage 53 | 54 | ```javascript 55 | const props = { 56 | offLeft: { x: '-100%' }, 57 | offRight: { x: '100%' }, 58 | on: { 59 | x: '0%', 60 | transition: fromPose({ 61 | offLeft: ({ from, to }) => tween({ from, to, duration: 400 }), 62 | offRight: ({ from, to }) => tween({ from, to, duration: 200 }) 63 | }) 64 | } 65 | } 66 | ``` 67 | -------------------------------------------------------------------------------- /packages/popmotion/src/index.ts: -------------------------------------------------------------------------------- 1 | // Core 2 | import action from './action'; 3 | import multicast from './reactions/multicast'; 4 | import value from './reactions/value'; 5 | 6 | export { action, multicast, value }; 7 | 8 | // Animations 9 | import decay from './animations/decay'; 10 | import everyFrame from './animations/every-frame'; 11 | import keyframes from './animations/keyframes'; 12 | import physics from './animations/physics'; 13 | import spring from './animations/spring'; 14 | import timeline from './animations/timeline'; 15 | import tween from './animations/tween'; 16 | 17 | export { decay, keyframes, everyFrame, physics, spring, timeline, tween }; 18 | 19 | // Input 20 | import listen from './input/listen'; 21 | import multitouch from './input/multitouch'; 22 | import pointer from './input/pointer'; 23 | import mouse from './input/pointer/mouse'; 24 | 25 | export { listen, pointer, mouse, multitouch }; 26 | 27 | // Compositors 28 | import chain from './compositors/chain'; 29 | import composite from './compositors/composite'; 30 | import crossfade from './compositors/crossfade'; 31 | import delay from './compositors/delay'; 32 | import merge from './compositors/merge'; 33 | import parallel from './compositors/parallel'; 34 | import schedule from './compositors/schedule'; 35 | import stagger from './compositors/stagger'; 36 | 37 | export { chain, composite, crossfade, delay, merge, parallel, schedule, stagger }; 38 | 39 | // Includes 40 | import * as calc from './calc'; 41 | import * as easing from './easing'; 42 | import * as transform from './transformers'; 43 | 44 | export { calc, easing, transform }; 45 | 46 | // Stylefire 47 | import styler from 'stylefire'; 48 | import css from 'stylefire/css'; 49 | import svg from 'stylefire/svg'; 50 | export { styler, css, svg }; 51 | 52 | // Value types 53 | import * as valueTypes from 'style-value-types'; 54 | export { valueTypes }; 55 | -------------------------------------------------------------------------------- /packages/popmotion/docs/api/plugins/spinnable.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Spinnable 3 | description: Make any DOM node or React component spinnable! 4 | category: plugins 5 | --- 6 | 7 | # Spinnable 8 | 9 | Make any DOM node or React DOM component spinnable in one line of code! 10 | 11 | Provides an optional `onSpin` callback to use spinnable nodes as dial controls. 12 | 13 | ```marksy 14 | 15 | ``` 16 | 17 | ## Install 18 | 19 | ``` 20 | npm install popmotion-spinnable --save 21 | ``` 22 | 23 | ## DOM 24 | 25 | To use with DOM nodes, simply provide a node to `spinnable`: 26 | 27 | ```javascript 28 | import spinnable from 'popmotion-spinnable'; 29 | 30 | const node = document.querySelector('div'); 31 | spinnable(node); 32 | ``` 33 | 34 | Or provide additional options: 35 | 36 | ```javascript 37 | import { transform } from 'popmotion'; 38 | const { snap } = transform; 39 | 40 | spinnable(node, { 41 | onSpin: (angle) => console.log(angle), 42 | transformSpin: snap(45), 43 | friction: 1 44 | }); 45 | ``` 46 | 47 | `spinnable` returns an object with a `stop` method. 48 | 49 | ## React 50 | 51 | ```javascript 52 | import Spinnable from 'popmotion-spinnable/lib/react'; 53 | 54 | export default ({ onSpin }) => ( 55 | 56 | ); 57 | ``` 58 | 59 | ## Options 60 | - `friction`: Friction applied to the spin when the user releases. Set to `1` to stop dead. Default: `0.4` 61 | - `onSpin`: Function to be called every frame, provided the latest angle. 62 | - `transformSpin`: A function that takes the spin, and returns it before the value is applied to the node. 63 | - `className`: **React only** Provides support for adding a class for styling purposes, and adds support for `styled-components`-esque styling systems. 64 | 65 | ## Methods 66 | 67 | - `stop`: Hard stops any currently active actions. Generally only used when unmounting the node. 68 | -------------------------------------------------------------------------------- /site/components/icons/PoseLogo.js: -------------------------------------------------------------------------------- 1 | export default ({ className, width=613, height=192 }) => ( 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | ); -------------------------------------------------------------------------------- /site/templates/Pose/USPs/PassiveExample.js: -------------------------------------------------------------------------------- 1 | import Template from '~/templates/Popmotion/LiveExamples/Template'; 2 | import { 3 | Carousel, 4 | Item, 5 | AlignCenter 6 | } from '~/templates/Popmotion/LiveExamples/styled'; 7 | import { styler, value, listen, pointer, decay, transform } from 'popmotion'; 8 | import posed from 'react-pose'; 9 | import styled from 'styled-components'; 10 | import { color } from '~/styles/vars'; 11 | const { interpolate } = transform; 12 | const props = { 13 | draggable: 'x', 14 | passive: { 15 | opacity: ['x', interpolate([-200, -100, 100, 200], [0, 1, 1, 0])] 16 | } 17 | }; 18 | 19 | const Box = styled(posed.div(props))` 20 | width: 100px; 21 | height: 100px; 22 | background: ${color.blue}; 23 | border-radius: 50%; 24 | transform: scaleX(0); 25 | transform-origin: 50%; 26 | color: white; 27 | display: flex; 28 | justify-content: center; 29 | align-items: center; 30 | font-weight: bold; 31 | `; 32 | 33 | const code = `// Vanilla & React DOM 34 | passive: { 35 | opacity: ['x', interpolate( 36 | [-200, -100, 100, 200], 37 | [0, 1, 1, 0] 38 | )] 39 | } 40 | 41 | // React Native 42 | passive: { 43 | opacity: ['x', { 44 | inputRange: [-200, -100, 100, 200], 45 | outputRange: [0, 1, 1, 0] 46 | }] 47 | }`; 48 | 49 | class Example extends React.Component { 50 | state = { isVisible: false }; 51 | 52 | componentDidMount() { 53 | this.interval = setInterval(this.toggleVisibility, 1000); 54 | } 55 | 56 | componentWillUnmount() { 57 | clearInterval(this.interval); 58 | } 59 | 60 | toggleVisibility = () => this.setState({ isVisible: !this.state.isVisible }); 61 | 62 | render() { 63 | return Drag; 64 | } 65 | } 66 | 67 | export default () => ( 68 | 73 | ); 74 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "popmotion-packages", 4 | "author": "Matt Perry", 5 | "homepage": "https://popmotion.io", 6 | "scripts": { 7 | "bootstrap": "lerna bootstrap", 8 | "clean": "lerna clean", 9 | "publish": "lerna publish", 10 | "playground": "start-storybook -p 6006", 11 | "build-playground": "build-storybook" 12 | }, 13 | "devDependencies": { 14 | "@storybook/react": "^3.2.13", 15 | "babel-cli": "^6.16.0", 16 | "babel-core": "^6.0.20", 17 | "babel-eslint": "^5.0.4", 18 | "babel-loader": "^6.0.1", 19 | "babel-plugin-root-import": "^5.1.0", 20 | "babel-plugin-transform-export-extensions": "^6.4.0", 21 | "babel-plugin-transform-react-constant-elements": "^6.9.1", 22 | "babel-plugin-transform-react-jsx": "^6.24.1", 23 | "babel-plugin-transform-react-remove-prop-types": "^0.2.6", 24 | "babel-plugin-transform-runtime": "^6.23.0", 25 | "babel-preset-env": "^1.6.1", 26 | "babel-preset-react": "^6.16.0", 27 | "babel-preset-stage-0": "^6.24.1", 28 | "babel-preset-stage-2": "^6.17.0", 29 | "babel-register": "^6.3.13", 30 | "eslint": "^3.19.0", 31 | "eslint-plugin-flowtype": "^2.30.0", 32 | "eslint-plugin-import": "^2.2.0", 33 | "eslint-plugin-jasmine": "2.2.0", 34 | "eslint-plugin-jsx-a11y": "^4.0.0", 35 | "eslint-plugin-react": "^6.10.0", 36 | "estraverse-fb": "^1.3.1", 37 | "jest": "^21.1.0", 38 | "react": "^16.3.0", 39 | "react-dom": "^16.3.0", 40 | "string-replace-loader": "^1.3.0", 41 | "styled-components": "^3.2.1", 42 | "webpack": "^3.0.0" 43 | }, 44 | "jest": { 45 | "moduleFileExtensions": [ 46 | "ts", 47 | "js" 48 | ], 49 | "transform": { 50 | "\\.(ts)$": "../node_modules/ts-jest/preprocessor.js" 51 | }, 52 | "testRegex": "/_tests/.*\\.(ts|js)$", 53 | "rootDir": "src", 54 | "prettier": { 55 | "singleQuote": true 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /site/templates/content/MenuPage.js: -------------------------------------------------------------------------------- 1 | import { withTheme } from 'styled-components'; 2 | import Link from 'next/link'; 3 | import { Content, ItemContainer } from '~/templates/global/grid'; 4 | import { 5 | H2, 6 | H3, 7 | P, 8 | ArticleHeader, 9 | DatePublished 10 | } from '~/templates/global/styled'; 11 | import SiteLink from '~/components/layout/SiteLink'; 12 | import { SectionContainer } from '../global/grid'; 13 | 14 | const MenuPage = ({ theme, title, section }) => { 15 | const { generateSiteUrl } = theme.data; 16 | const content = theme.data.content[section]; 17 | const menu = theme.data.menus[section]; 18 | 19 | return ( 20 | 21 | {title} 22 |
    23 | {menu.map(tl => ( 24 | 25 | {content[tl.id] ? ( 26 |
    27 |

    28 | {tl.title} 29 |

    30 | {content[tl.id].published && ( 31 | {content[tl.id].published} 32 | )} 33 |

    {content[tl.id].description}

    34 |
    35 | ) : ( 36 |

    {tl.title}

    37 | )} 38 |
      39 | {tl.posts 40 | ? tl.posts.map(sl => ( 41 | 42 |

      43 | 44 | {sl.title} 45 | 46 |

      47 |

      {content[sl.id].description}

      48 |
      49 | )) 50 | : null} 51 |
    52 |
    53 | ))} 54 |
55 |
56 | ); 57 | }; 58 | 59 | export default withTheme(MenuPage); 60 | -------------------------------------------------------------------------------- /packages/popmotion/docs/learn/how-to/rounded-values.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Rounded values 3 | description: How to output rounded values from any action 4 | category: how-to 5 | --- 6 | 7 | # Rounded values 8 | 9 | Popmotion's emphasis on functional composition means actions don't offer explicit support via properties like `rounded: true`. 10 | 11 | Instead, we can round the output of any [action](/api/action) by providing JavaScript's native `Math.round` to `pipe`. For instance: 12 | 13 | ## Round a single value 14 | 15 | If we have a `tween` that outputs a single value, we can round it like this: 16 | 17 | ```javascript 18 | tween({ to: 1000 }).pipe(Math.round) 19 | ``` 20 | 21 | ```marksy 22 | {` 23 | const counter = document.querySelector('#a .counter'); 24 | const updateCounter = (v) => counter.innerHTML = v; 25 | 26 | tween({ to: 1000, duration: 2000 }) 27 | .pipe(Math.round) 28 | .start(updateCounter); 29 | `} 30 | ``` 31 | 32 | Every animation is an action, so this applies to animations like `physics` too: 33 | 34 | ```javascript 35 | physics({ velocity: 100 }).pipe(Math.round) 36 | ``` 37 | 38 | ```marksy 39 | {` 40 | const counter = document.querySelector('#b .counter'); 41 | const updateCounter = (v) => counter.innerHTML = v; 42 | 43 | physics({ velocity: 100 }) 44 | .pipe(Math.round) 45 | .start(updateCounter); 46 | `} 47 | ``` 48 | 49 | ## Round a complex value 50 | 51 | If we're animating an object, we can apply rounding to specific values using the `transformMap` [transformer](/api/transformers#transformmap): 52 | 53 | ```javascript 54 | import { tween, transform } from 'popmotion'; 55 | const { transformMap } = transform; 56 | 57 | tween({ 58 | to: { x: 100, y: 100 } 59 | }).pipe(transformMap({ 60 | x: Math.round 61 | })); 62 | ``` 63 | 64 | More examples of `pipe` and functional composition can be found in the [value pipelines](/api/value-pipelines) tutorial. 65 | -------------------------------------------------------------------------------- /packages/popmotion-pose/docs/api/react/posegroup.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: PoseGroup 3 | description: Create a Poser 4 | category: react 5 | --- 6 | 7 | **Note:** React Pose is built with React 16.3.0, which is currently in alpha. 8 | 9 | # `PoseGroup` 10 | 11 | The `PoseGroup` component manages `enter` and `exit` animations on its direct children as they enter and exit the component tree. 12 | 13 | ## Import 14 | 15 | ```javascript 16 | import posed, { PoseGroup } from 'react-pose' 17 | ``` 18 | 19 | ## Usage 20 | 21 | By adding a [posed component](/api/posed) as a direct child of `PoseGroup`, it will gain two new poses: `enter` and `exit`. 22 | 23 | ```javascript 24 | const Item = posed.div({ 25 | enter: { opacity: 1 }, 26 | exit: { opacity: 0 } 27 | }) 28 | 29 | const ItemList = ({ items }) => ( 30 | 31 | {items.map((item) => )} 32 | 33 | ) 34 | ``` 35 | 36 | **Note:** Every child must be provided a unique `key` property for `PoseGroup` to track entering and exiting children. 37 | 38 | ### Animating children 39 | 40 | As with any posed component, the `enter`/`exit` pose will propagate throughout any of its posed component children. 41 | 42 | In the case of the `exit` pose, `PoseGroup` will only unmount the animating component once **all of its children** have also finished their `exit` animation. 43 | 44 | ## Props 45 | 46 | ### `animateOnMount: boolean = false` 47 | 48 | By default, only children added to the `PoseGroup` **after** it has mounted are animated to `enter`. 49 | 50 | By setting `animateOnMount` to `true`, all children elements will animate in on mount. 51 | 52 | ### `enterPose: string = 'enter'` 53 | 54 | The name of the pose to use when a component enters. 55 | 56 | ### `exitPose: string = 'exit'` 57 | 58 | The name of the pose to use when a component leaves. 59 | 60 | ### `preEnterPose: string = 'exit'` 61 | 62 | The name of the pose to set before a component enters. This can be used to configure where a components animates in **from**. 63 | --------------------------------------------------------------------------------