├── src ├── assets │ ├── .gitkeep │ └── normalize.css ├── favicon.ico ├── styles.css ├── environments │ ├── environment.prod.ts │ └── environment.ts ├── app │ ├── example-box │ │ ├── example-box.component.css │ │ ├── example-box.component.html │ │ ├── example-box.component.spec.ts │ │ └── example-box.component.ts │ ├── app-routing.module.ts │ ├── app.module.ts │ ├── app.component.spec.ts │ ├── app.component.css │ ├── app.component.html │ └── app.component.ts ├── main.ts ├── test.ts ├── polyfills.ts └── index.html ├── projects └── ng-animate │ ├── src │ ├── lib │ │ ├── utils.ts │ │ ├── lightspeed.ts │ │ ├── rotate.ts │ │ ├── specials.ts │ │ ├── flippers.ts │ │ ├── back.ts │ │ ├── zooming.ts │ │ ├── bouncing.ts │ │ ├── fading.ts │ │ └── attention-seekers.ts │ ├── public-api.ts │ └── test.ts │ ├── ng-package.json │ ├── tsconfig.lib.prod.json │ ├── tsconfig.lib.json │ ├── tsconfig.spec.json │ ├── package.json │ ├── .eslintrc.json │ ├── README.md │ └── karma.conf.js ├── e2e ├── src │ ├── app.po.ts │ └── app.e2e-spec.ts ├── tsconfig.json └── protractor.conf.js ├── .editorconfig ├── tsconfig.app.json ├── tsconfig.spec.json ├── .browserslistrc ├── .gitignore ├── tsconfig.json ├── .eslintrc.json ├── LICENSE.md ├── karma.conf.js ├── package.json ├── angular.json └── README.md /src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /projects/ng-animate/src/lib/utils.ts: -------------------------------------------------------------------------------- 1 | export const DEFAULT_TIMING = 1; 2 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiayihu/ng-animate/HEAD/src/favicon.ico -------------------------------------------------------------------------------- /src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /projects/ng-animate/ng-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", 3 | "dest": "../../dist/ng-animate", 4 | "lib": { 5 | "entryFile": "src/public-api.ts" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/app/example-box/example-box.component.css: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | } 4 | 5 | .box { 6 | background-color: #fff; 7 | border-radius: 3px; 8 | height: 48px; 9 | width: 48px; 10 | margin: 0 auto; 11 | margin-top: 5rem; 12 | } 13 | -------------------------------------------------------------------------------- /src/app/example-box/example-box.component.html: -------------------------------------------------------------------------------- 1 |
2 |

{{ label }}

3 |

4 | 6 |

7 | -------------------------------------------------------------------------------- /src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | 4 | const routes: Routes = []; 5 | 6 | @NgModule({ 7 | imports: [RouterModule.forRoot(routes)], 8 | exports: [RouterModule] 9 | }) 10 | export class AppRoutingModule { } 11 | -------------------------------------------------------------------------------- /projects/ng-animate/tsconfig.lib.prod.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.lib.json", 4 | "compilerOptions": { 5 | "declarationMap": false 6 | }, 7 | "angularCompilerOptions": { 8 | "compilationMode": "partial" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | async navigateTo(): Promise { 5 | return browser.get(browser.baseUrl); 6 | } 7 | 8 | async getTitleText(): Promise { 9 | return element(by.css('app-root .content span')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "../tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "../out-tsc/e2e", 6 | "module": "commonjs", 7 | "target": "es2018", 8 | "types": [ 9 | "jasmine", 10 | "node" 11 | ] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.ts] 12 | quote_type = single 13 | 14 | [*.md] 15 | max_line_length = off 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /tsconfig.app.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/app", 6 | "types": [] 7 | }, 8 | "files": [ 9 | "src/main.ts", 10 | "src/polyfills.ts" 11 | ], 12 | "include": [ 13 | "src/**/*.d.ts" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /projects/ng-animate/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "../../tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "../../out-tsc/lib", 6 | "declaration": true, 7 | "declarationMap": true, 8 | "inlineSources": true, 9 | "types": [] 10 | }, 11 | "exclude": ["src/test.ts", "**/*.spec.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /projects/ng-animate/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "../../tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "../../out-tsc/spec", 6 | "types": [ 7 | "jasmine" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts" 12 | ], 13 | "include": [ 14 | "**/*.spec.ts", 15 | "**/*.d.ts" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /projects/ng-animate/src/public-api.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Public API Surface of ng-animate 3 | */ 4 | 5 | export * from './lib/attention-seekers'; 6 | export * from './lib/bouncing'; 7 | export * from './lib/fading'; 8 | export * from './lib/flippers'; 9 | export * from './lib/lightspeed'; 10 | export * from './lib/rotate'; 11 | export * from './lib/specials'; 12 | export * from './lib/zooming'; 13 | export * from './lib/back'; 14 | -------------------------------------------------------------------------------- /tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/spec", 6 | "types": [ 7 | "jasmine" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | -------------------------------------------------------------------------------- /src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { FormsModule } from '@angular/forms'; 3 | import { BrowserModule } from '@angular/platform-browser'; 4 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 5 | 6 | import { AppRoutingModule } from './app-routing.module'; 7 | import { AppComponent } from './app.component'; 8 | import { ExampleBoxComponent } from './example-box/example-box.component'; 9 | 10 | @NgModule({ 11 | declarations: [AppComponent, ExampleBoxComponent], 12 | imports: [ 13 | BrowserModule, 14 | BrowserAnimationsModule, 15 | FormsModule, 16 | AppRoutingModule, 17 | ], 18 | providers: [], 19 | bootstrap: [AppComponent], 20 | }) 21 | export class AppModule {} 22 | -------------------------------------------------------------------------------- /e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | import { browser, logging } from 'protractor'; 3 | 4 | describe('workspace-project App', () => { 5 | let page: AppPage; 6 | 7 | beforeEach(() => { 8 | page = new AppPage(); 9 | }); 10 | 11 | it('should display welcome message', async () => { 12 | await page.navigateTo(); 13 | expect(await page.getTitleText()).toEqual('demo app is running!'); 14 | }); 15 | 16 | afterEach(async () => { 17 | // Assert that there are no errors emitted from the browser 18 | const logs = await browser.manage().logs().get(logging.Type.BROWSER); 19 | expect(logs).not.toContain(jasmine.objectContaining({ 20 | level: logging.Level.SEVERE, 21 | } as logging.Entry)); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # For the full list of supported browsers by the Angular framework, please see: 6 | # https://angular.io/guide/browser-support 7 | 8 | # You can see what browsers were selected by your queries by running: 9 | # npx browserslist 10 | 11 | last 1 Chrome version 12 | last 1 Firefox version 13 | last 2 Edge major versions 14 | last 2 Safari major versions 15 | last 2 iOS major versions 16 | Firefox ESR 17 | not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line. 18 | -------------------------------------------------------------------------------- /projects/ng-animate/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ng-animate", 3 | "version": "2.0.1", 4 | "description": "A library of cool, reusable and flexible animations for Angular", 5 | "repository": { 6 | "type": "git", 7 | "url": "git+https://github.com/jiayihu/ng-animate.git" 8 | }, 9 | "keywords": [ 10 | "angular", 11 | "animations" 12 | ], 13 | "author": "Jiayi Hu ", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/jiayihu/ng-animate/issues" 17 | }, 18 | "homepage": "https://github.com/jiayihu/ng-animate#readme", 19 | "peerDependencies": { 20 | "@angular/common": ">=12.0.0", 21 | "@angular/core": ">=12.0.0", 22 | "@angular/animations": ">=12.0.0" 23 | }, 24 | "dependencies": { 25 | "tslib": "^2.3.0" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | # Only exists if Bazel was run 8 | /bazel-out 9 | 10 | # dependencies 11 | /node_modules 12 | 13 | # profiling files 14 | chrome-profiler-events*.json 15 | speed-measure-plugin*.json 16 | 17 | # IDEs and editors 18 | /.idea 19 | .project 20 | .classpath 21 | .c9/ 22 | *.launch 23 | .settings/ 24 | *.sublime-workspace 25 | 26 | # IDE - VSCode 27 | .vscode/* 28 | !.vscode/settings.json 29 | !.vscode/tasks.json 30 | !.vscode/launch.json 31 | !.vscode/extensions.json 32 | .history/* 33 | 34 | # misc 35 | /.angular/cache 36 | /.sass-cache 37 | /connect.lock 38 | /coverage 39 | /libpeerconnection.log 40 | npm-debug.log 41 | yarn-error.log 42 | testem.log 43 | /typings 44 | 45 | # System Files 46 | .DS_Store 47 | Thumbs.db 48 | -------------------------------------------------------------------------------- /src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | import { FormsModule } from '@angular/forms'; 3 | import { NoopAnimationsModule } from '@angular/platform-browser/animations'; 4 | import { RouterTestingModule } from '@angular/router/testing'; 5 | 6 | import { AppComponent } from './app.component'; 7 | import { ExampleBoxComponent } from './example-box/example-box.component'; 8 | 9 | describe('AppComponent', () => { 10 | beforeEach(async () => { 11 | await TestBed.configureTestingModule({ 12 | imports: [RouterTestingModule, NoopAnimationsModule, FormsModule], 13 | declarations: [AppComponent, ExampleBoxComponent], 14 | }).compileComponents(); 15 | }); 16 | 17 | it('should create the app', () => { 18 | const fixture = TestBed.createComponent(AppComponent); 19 | const app = fixture.componentInstance; 20 | expect(app).toBeTruthy(); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /src/app/example-box/example-box.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | import { NoopAnimationsModule } from '@angular/platform-browser/animations'; 3 | 4 | import { ExampleBoxComponent } from './example-box.component'; 5 | 6 | describe('ExampleBoxComponent', () => { 7 | let component: ExampleBoxComponent; 8 | let fixture: ComponentFixture; 9 | 10 | beforeEach(async () => { 11 | await TestBed.configureTestingModule({ 12 | imports: [NoopAnimationsModule], 13 | declarations: [ExampleBoxComponent], 14 | }).compileComponents(); 15 | }); 16 | 17 | beforeEach(() => { 18 | fixture = TestBed.createComponent(ExampleBoxComponent); 19 | component = fixture.componentInstance; 20 | fixture.detectChanges(); 21 | }); 22 | 23 | it('should create', () => { 24 | expect(component).toBeTruthy(); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: { 11 | context(path: string, deep?: boolean, filter?: RegExp): { 12 | keys(): string[]; 13 | (id: string): T; 14 | }; 15 | }; 16 | 17 | // First, initialize the Angular testing environment. 18 | getTestBed().initTestEnvironment( 19 | BrowserDynamicTestingModule, 20 | platformBrowserDynamicTesting(), { 21 | teardown: { destroyAfterEach: false } 22 | } 23 | ); 24 | // Then we find all the tests. 25 | const context = require.context('./', true, /\.spec\.ts$/); 26 | // And load the modules. 27 | context.keys().map(context); 28 | -------------------------------------------------------------------------------- /projects/ng-animate/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import { getTestBed } from '@angular/core/testing'; 4 | import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; 5 | 6 | import 'zone.js/dist/zone'; 7 | import 'zone.js/dist/zone-testing'; 8 | 9 | declare const require: { 10 | context( 11 | path: string, 12 | deep?: boolean, 13 | filter?: RegExp 14 | ): { 15 | keys(): string[]; 16 | (id: string): T; 17 | }; 18 | }; 19 | 20 | // First, initialize the Angular testing environment. 21 | getTestBed().initTestEnvironment( 22 | BrowserDynamicTestingModule, 23 | platformBrowserDynamicTesting(), 24 | { 25 | teardown: { destroyAfterEach: false }, 26 | } 27 | ); 28 | // Then we find all the tests. 29 | const context = require.context('./', true, /\.spec\.ts$/); 30 | // And load the modules. 31 | context.keys().map(context); 32 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "noImplicitOverride": true, 9 | "noPropertyAccessFromIndexSignature": true, 10 | "noImplicitReturns": true, 11 | "noFallthroughCasesInSwitch": true, 12 | "sourceMap": true, 13 | "declaration": false, 14 | "downlevelIteration": true, 15 | "experimentalDecorators": true, 16 | "moduleResolution": "node", 17 | "importHelpers": true, 18 | "target": "es2020", 19 | "module": "es2020", 20 | "lib": ["es2020", "dom"], 21 | "paths": { 22 | "ng-animate": ["dist/ng-animate/ng-animate", "dist/ng-animate"] 23 | } 24 | }, 25 | "angularCompilerOptions": { 26 | "enableI18nLegacyMessageIdFormat": false, 27 | "strictInjectionParameters": true, 28 | "strictInputAccessModifiers": true, 29 | "strictTemplates": true 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /projects/ng-animate/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../.eslintrc.json", 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts"], 7 | "parserOptions": { 8 | "project": [ 9 | "projects/ng-animate/tsconfig.lib.json", 10 | "projects/ng-animate/tsconfig.spec.json" 11 | ], 12 | "createDefaultProgram": true 13 | }, 14 | "rules": { 15 | "@angular-eslint/directive-selector": [ 16 | "error", 17 | { 18 | "type": "attribute", 19 | "prefix": "lib", 20 | "style": "camelCase" 21 | } 22 | ], 23 | "@angular-eslint/component-selector": [ 24 | "error", 25 | { 26 | "type": "element", 27 | "prefix": "lib", 28 | "style": "kebab-case" 29 | } 30 | ] 31 | } 32 | }, 33 | { 34 | "files": ["*.html"], 35 | "rules": {} 36 | } 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /src/app/app.component.css: -------------------------------------------------------------------------------- 1 | small { 2 | font-size: 0.875rem; 3 | font-weight: normal; 4 | } 5 | 6 | .btn { 7 | background-color: #fff; 8 | border: none; 9 | border-radius: 2px; 10 | color: #666; 11 | cursor: pointer; 12 | font-size: inherit; 13 | margin-top: 0.5rem; 14 | padding: 0.5rem 1rem; 15 | } 16 | 17 | .btn:not(:last-child) { 18 | margin-right: 0.5rem; 19 | } 20 | 21 | .container { 22 | align-items: center; 23 | display: flex; 24 | justify-content: center; 25 | min-height: 100vh; 26 | width: 100%; 27 | } 28 | 29 | .content { 30 | max-width: 60rem; 31 | text-align: center; 32 | } 33 | 34 | .animations { 35 | margin-top: 3rem; 36 | } 37 | 38 | input[type="number"] { 39 | background-color: #fff; 40 | border: none; 41 | padding: 0.5rem; 42 | border-radius: 2px; 43 | margin: 0.5rem 0.1rem; 44 | } 45 | 46 | select { 47 | background-color: #fff; 48 | border: none; 49 | padding: 0.5rem; 50 | border-radius: 2px; 51 | margin: 0.5rem 0.1rem; 52 | } 53 | -------------------------------------------------------------------------------- /e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // Protractor configuration file, see link for more information 3 | // https://github.com/angular/protractor/blob/master/lib/config.ts 4 | 5 | const { SpecReporter, StacktraceOption } = require('jasmine-spec-reporter'); 6 | 7 | /** 8 | * @type { import("protractor").Config } 9 | */ 10 | exports.config = { 11 | allScriptsTimeout: 11000, 12 | specs: [ 13 | './src/**/*.e2e-spec.ts' 14 | ], 15 | capabilities: { 16 | browserName: 'chrome' 17 | }, 18 | directConnect: true, 19 | SELENIUM_PROMISE_MANAGER: false, 20 | baseUrl: 'http://localhost:4200/', 21 | framework: 'jasmine', 22 | jasmineNodeOpts: { 23 | showColors: true, 24 | defaultTimeoutInterval: 30000, 25 | print: function() {} 26 | }, 27 | onPrepare() { 28 | require('ts-node').register({ 29 | project: require('path').join(__dirname, './tsconfig.json') 30 | }); 31 | jasmine.getEnv().addReporter(new SpecReporter({ 32 | spec: { 33 | displayStacktrace: StacktraceOption.PRETTY 34 | } 35 | })); 36 | } 37 | }; -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "ignorePatterns": ["projects/**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts"], 7 | "parserOptions": { 8 | "project": ["tsconfig.json", "e2e/tsconfig.json"], 9 | "createDefaultProgram": true 10 | }, 11 | "extends": [ 12 | "plugin:@angular-eslint/recommended", 13 | "plugin:@angular-eslint/template/process-inline-templates" 14 | ], 15 | "rules": { 16 | "@angular-eslint/directive-selector": [ 17 | "error", 18 | { 19 | "type": "attribute", 20 | "prefix": "app", 21 | "style": "camelCase" 22 | } 23 | ], 24 | "@angular-eslint/component-selector": [ 25 | "error", 26 | { 27 | "type": "element", 28 | "prefix": "app", 29 | "style": "kebab-case" 30 | } 31 | ] 32 | } 33 | }, 34 | { 35 | "files": ["*.html"], 36 | "extends": ["plugin:@angular-eslint/template/recommended"], 37 | "rules": {} 38 | } 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /projects/ng-animate/README.md: -------------------------------------------------------------------------------- 1 | # NgAnimate 2 | 3 | This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 11.0.3. 4 | 5 | ## Code scaffolding 6 | 7 | Run `ng generate component component-name --project ng-animate` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project ng-animate`. 8 | > Note: Don't forget to add `--project ng-animate` or else it will be added to the default project in your `angular.json` file. 9 | 10 | ## Build 11 | 12 | Run `ng build ng-animate` to build the project. The build artifacts will be stored in the `dist/` directory. 13 | 14 | ## Publishing 15 | 16 | After building your library with `ng build ng-animate`, go to the dist folder `cd dist/ng-animate` and run `npm publish`. 17 | 18 | ## Running unit tests 19 | 20 | Run `ng test ng-animate` to execute the unit tests via [Karma](https://karma-runner.github.io). 21 | 22 | ## Further help 23 | 24 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. 25 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Giovanni Jiayi Hu 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. -------------------------------------------------------------------------------- /src/app/example-box/example-box.component.ts: -------------------------------------------------------------------------------- 1 | import { AnimationBuilder, AnimationMetadata, AnimationPlayer } from '@angular/animations'; 2 | import { Component, Input } from '@angular/core'; 3 | 4 | @Component({ 5 | selector: 'app-example-box', 6 | templateUrl: './example-box.component.html', 7 | styleUrls: ['./example-box.component.css'], 8 | }) 9 | export class ExampleBoxComponent { 10 | @Input() label?: string; 11 | 12 | @Input() animations: { [name: string]: AnimationMetadata } = {}; 13 | 14 | @Input() params: { 15 | [name: string]: unknown; 16 | } = {}; 17 | 18 | lastAnimPlayer?: AnimationPlayer; 19 | 20 | constructor(private readonly animationBuilder: AnimationBuilder) {} 21 | 22 | playAnim( 23 | element: HTMLElement, 24 | anim: AnimationMetadata | AnimationMetadata[] 25 | ): void { 26 | this.lastAnimPlayer?.finish(); 27 | 28 | const animPlayer = this.animationBuilder 29 | .build(anim) 30 | .create(element, { params: { ...this.params } }); 31 | 32 | animPlayer.init(); 33 | animPlayer.onDone(() => { 34 | animPlayer.destroy(); 35 | if (animPlayer === this.lastAnimPlayer) { 36 | this.lastAnimPlayer = undefined; 37 | } 38 | }); 39 | this.lastAnimPlayer = animPlayer; 40 | animPlayer.play(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | jasmine: { 17 | // you can add configuration options for Jasmine here 18 | // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html 19 | // for example, you can disable the random execution with `random: false` 20 | // or set a specific seed with `seed: 4321` 21 | }, 22 | clearContext: false // leave Jasmine Spec Runner output visible in browser 23 | }, 24 | jasmineHtmlReporter: { 25 | suppressAll: true // removes the duplicated traces 26 | }, 27 | coverageReporter: { 28 | dir: require('path').join(__dirname, './coverage/demo'), 29 | subdir: '.', 30 | reporters: [ 31 | { type: 'html' }, 32 | { type: 'text-summary' } 33 | ] 34 | }, 35 | reporters: ['progress', 'kjhtml'], 36 | port: 9876, 37 | colors: true, 38 | logLevel: config.LOG_INFO, 39 | autoWatch: true, 40 | browsers: ['Chrome'], 41 | singleRun: false, 42 | restartOnFileChange: true 43 | }); 44 | }; 45 | -------------------------------------------------------------------------------- /projects/ng-animate/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | jasmine: { 17 | // you can add configuration options for Jasmine here 18 | // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html 19 | // for example, you can disable the random execution with `random: false` 20 | // or set a specific seed with `seed: 4321` 21 | }, 22 | clearContext: false // leave Jasmine Spec Runner output visible in browser 23 | }, 24 | jasmineHtmlReporter: { 25 | suppressAll: true // removes the duplicated traces 26 | }, 27 | coverageReporter: { 28 | dir: require('path').join(__dirname, '../../coverage/ng-animate'), 29 | subdir: '.', 30 | reporters: [ 31 | { type: 'html' }, 32 | { type: 'text-summary' } 33 | ] 34 | }, 35 | reporters: ['progress', 'kjhtml'], 36 | port: 9876, 37 | colors: true, 38 | logLevel: config.LOG_INFO, 39 | autoWatch: true, 40 | browsers: ['Chrome'], 41 | singleRun: false, 42 | restartOnFileChange: true 43 | }); 44 | }; 45 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve --configuration development", 7 | "build": "ng build --base-href /ng-animate/", 8 | "build-lib": "ng build ng-animate && shx cp *.md dist/ng-animate/", 9 | "packagr": "ng-packagr -p projects/ng-animate/ng-package.json", 10 | "deploy": "gh-pages -d dist/demo", 11 | "test": "ng test", 12 | "lint": "ng lint", 13 | "e2e": "ng e2e" 14 | }, 15 | "private": true, 16 | "dependencies": { 17 | "@angular/animations": "^14.0.2", 18 | "@angular/common": "^14.0.2", 19 | "@angular/compiler": "^14.0.2", 20 | "@angular/core": "^14.0.2", 21 | "@angular/forms": "^14.0.2", 22 | "@angular/platform-browser": "^14.0.2", 23 | "@angular/platform-browser-dynamic": "^14.0.2", 24 | "@angular/router": "^14.0.2", 25 | "rxjs": "~7.5.0", 26 | "tslib": "^2.3.0", 27 | "zone.js": "~0.11.4" 28 | }, 29 | "devDependencies": { 30 | "@angular-devkit/build-angular": "^14.0.2", 31 | "@angular-eslint/builder": "^14.0.0-alpha.3", 32 | "@angular-eslint/eslint-plugin": "^14.0.0-alpha.3", 33 | "@angular-eslint/eslint-plugin-template": "^14.0.0-alpha.3", 34 | "@angular-eslint/schematics": "^14.0.0-alpha.3", 35 | "@angular-eslint/template-parser": "^14.0.0-alpha.3", 36 | "@angular/cli": "^14.0.2", 37 | "@angular/compiler-cli": "^14.0.2", 38 | "@types/jasmine": "~4.0.0", 39 | "@types/node": "^14.15.0", 40 | "@typescript-eslint/eslint-plugin": "5.29.0", 41 | "@typescript-eslint/parser": "5.29.0", 42 | "gh-pages": "^4.0.0", 43 | "jasmine-core": "~4.1.0", 44 | "jasmine-spec-reporter": "~7.0.0", 45 | "karma": "~6.4.0", 46 | "karma-chrome-launcher": "~3.1.0", 47 | "karma-coverage": "~2.2.0", 48 | "karma-jasmine": "~5.0.0", 49 | "karma-jasmine-html-reporter": "~1.7.0", 50 | "ng-packagr": "^14.0.2", 51 | "protractor": "~7.0.0", 52 | "shx": "^0.3.4", 53 | "ts-node": "~8.3.0", 54 | "typescript": "~4.7.2" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/guide/browser-support 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** 22 | * By default, zone.js will patch all possible macroTask and DomEvents 23 | * user can disable parts of macroTask/DomEvents patch by setting following flags 24 | * because those flags need to be set before `zone.js` being loaded, and webpack 25 | * will put import in the top of bundle, so user need to create a separate file 26 | * in this directory (for example: zone-flags.ts), and put the following flags 27 | * into that file, and then add the following code before importing zone.js. 28 | * import './zone-flags'; 29 | * 30 | * The flags allowed in zone-flags.ts are listed here. 31 | * 32 | * The following flags will work for all browsers. 33 | * 34 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 35 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 36 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 37 | * 38 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 39 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 40 | * 41 | * (window as any).__Zone_enable_cross_context_check = true; 42 | * 43 | */ 44 | 45 | /*************************************************************************************************** 46 | * Zone JS is required by default for Angular itself. 47 | */ 48 | import 'zone.js/dist/zone'; // Included with Angular CLI. 49 | 50 | 51 | /*************************************************************************************************** 52 | * APPLICATION IMPORTS 53 | */ 54 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Demo 6 | 7 | 8 | 9 | 10 | 11 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /projects/ng-animate/src/lib/lightspeed.ts: -------------------------------------------------------------------------------- 1 | import { animate, animation, keyframes, style } from '@angular/animations'; 2 | 3 | import { DEFAULT_TIMING } from './utils'; 4 | 5 | export const lightSpeedInLeft = animation( 6 | animate( 7 | '{{ timing }}s {{ delay }}s ease-out', 8 | keyframes([ 9 | style({ 10 | transform: 'translate3d(-100%, 0, 0) skewX(30deg)', 11 | opacity: 0, 12 | offset: 0, 13 | }), 14 | style({ 15 | transform: 'skewX(-20deg)', 16 | opacity: 1, 17 | offset: 0.6, 18 | }), 19 | style({ 20 | transform: 'skewX(5deg)', 21 | offset: 0.8, 22 | }), 23 | style({ 24 | transform: 'translate3d(0, 0, 0)', 25 | offset: 1, 26 | }), 27 | ]) 28 | ), 29 | { 30 | params: { timing: DEFAULT_TIMING, delay: 0 }, 31 | } 32 | ); 33 | 34 | export const lightSpeedIn = animation( 35 | animate( 36 | '{{ timing }}s {{ delay }}s ease-out', 37 | keyframes([ 38 | style({ 39 | transform: 'translate3d(100%, 0, 0) skewX(-30deg)', 40 | opacity: 0, 41 | offset: 0, 42 | }), 43 | style({ 44 | transform: 'skewX(20deg)', 45 | opacity: 1, 46 | offset: 0.6, 47 | }), 48 | style({ 49 | transform: 'skewX(-5deg)', 50 | offset: 0.8, 51 | }), 52 | style({ 53 | transform: 'translate3d(0, 0, 0)', 54 | offset: 1, 55 | }), 56 | ]) 57 | ), 58 | { 59 | params: { timing: DEFAULT_TIMING, delay: 0 }, 60 | } 61 | ); 62 | export const lightSpeedInRight = lightSpeedIn; 63 | 64 | export const lightSpeedOut = animation( 65 | animate( 66 | '{{ timing }}s {{ delay }}s ease-in', 67 | keyframes([ 68 | style({ 69 | opacity: 1, 70 | offset: 0, 71 | }), 72 | style({ 73 | opacity: 0, 74 | transform: 'translate3d(100%, 0, 0) skewX(30deg)', 75 | offset: 1, 76 | }), 77 | ]) 78 | ), 79 | { 80 | params: { timing: DEFAULT_TIMING, delay: 0 }, 81 | } 82 | ); 83 | 84 | export const lightSpeedOutRight = lightSpeedOut; 85 | 86 | export const lightSpeedOutLeft = animation( 87 | animate( 88 | '{{ timing }}s {{ delay }}s ease-in', 89 | keyframes([ 90 | style({ 91 | opacity: 1, 92 | offset: 0, 93 | }), 94 | style({ 95 | opacity: 0, 96 | transform: 'translate3d(-100%, 0, 0) skewX(-30deg)', 97 | offset: 1, 98 | }), 99 | ]) 100 | ), 101 | { 102 | params: { timing: DEFAULT_TIMING, delay: 0 }, 103 | } 104 | ); 105 | -------------------------------------------------------------------------------- /projects/ng-animate/src/lib/rotate.ts: -------------------------------------------------------------------------------- 1 | import { animate, animation, AnimationReferenceMetadata, keyframes, style } from '@angular/animations'; 2 | 3 | import { DEFAULT_TIMING } from './utils'; 4 | 5 | export function rotateInDirection( 6 | origin: string, 7 | degrees: string 8 | ): AnimationReferenceMetadata { 9 | return animation( 10 | animate( 11 | '{{ timing }}s {{ delay }}s', 12 | keyframes([ 13 | style({ 14 | 'transform-origin': '{{ origin }}', 15 | opacity: '{{ fromOpacity }}', 16 | transform: 'rotate3d(0, 0, 1, {{ degrees }})', 17 | offset: 0, 18 | }), 19 | style({ 20 | 'transform-origin': '{{ origin }}', 21 | opacity: '{{ toOpacity }}', 22 | transform: 'none', 23 | offset: 1, 24 | }), 25 | ]) 26 | ), 27 | { 28 | params: { 29 | timing: DEFAULT_TIMING, 30 | delay: 0, 31 | origin, 32 | degrees, 33 | fromOpacity: 0, 34 | toOpacity: 1, 35 | }, 36 | } 37 | ); 38 | } 39 | 40 | export function rotateOutDirection( 41 | origin: string, 42 | degrees: string 43 | ): AnimationReferenceMetadata { 44 | return animation( 45 | animate( 46 | '{{ timing }}s {{ delay }}s', 47 | keyframes([ 48 | style({ 49 | 'transform-origin': '{{ origin }}', 50 | opacity: '{{ fromOpacity }}', 51 | transform: 'none', 52 | offset: 0, 53 | }), 54 | style({ 55 | 'transform-origin': '{{ origin }}', 56 | opacity: '{{ toOpacity }}', 57 | transform: 'rotate3d(0, 0, 1, {{ degrees }})', 58 | offset: 1, 59 | }), 60 | ]) 61 | ), 62 | { 63 | params: { 64 | timing: DEFAULT_TIMING, 65 | delay: 0, 66 | origin, 67 | degrees, 68 | fromOpacity: 1, 69 | toOpacity: 0, 70 | }, 71 | } 72 | ); 73 | } 74 | 75 | export const rotateIn = rotateInDirection('center', '-200deg'); 76 | export const rotateInDownLeft = rotateInDirection('left bottom', '-45deg'); 77 | export const rotateInDownRight = rotateInDirection('right bottom', '45deg'); 78 | export const rotateInUpLeft = rotateInDirection('left bottom', '45deg'); 79 | export const rotateInUpRight = rotateInDirection('right bottom', '-90deg'); 80 | 81 | export const rotateOut = rotateOutDirection('center', '200deg'); 82 | export const rotateOutDownLeft = rotateOutDirection('left bottom', '45deg'); 83 | export const rotateOutDownRight = rotateOutDirection('right bottom', '-45deg'); 84 | export const rotateOutUpLeft = rotateOutDirection('left bottom', '-45deg'); 85 | export const rotateOutUpRight = rotateOutDirection('right bottom', '90deg'); 86 | -------------------------------------------------------------------------------- /projects/ng-animate/src/lib/specials.ts: -------------------------------------------------------------------------------- 1 | import { animate, animation, keyframes, style } from '@angular/animations'; 2 | 3 | import { DEFAULT_TIMING } from './utils'; 4 | 5 | export const hinge = animation( 6 | [ 7 | style({ 'transform-origin': 'top left' }), 8 | animate( 9 | '{{ timing }}s {{ delay }}s ease-in-out', 10 | keyframes([ 11 | style({ 12 | transform: 'rotate3d(0, 0, 1, 80deg)', 13 | offset: 0.2, 14 | }), 15 | style({ 16 | transform: 'rotate3d(0, 0, 1, 60deg)', 17 | offset: 0.4, 18 | }), 19 | style({ 20 | transform: 'rotate3d(0, 0, 1, 80deg)', 21 | offset: 0.6, 22 | }), 23 | style({ 24 | opacity: 1, 25 | transform: 'rotate3d(0, 0, 1, 60deg)', 26 | offset: 0.8, 27 | }), 28 | style({ 29 | opacity: 0, 30 | transform: 'translate3d(0, 700px, 0)', 31 | offset: 1, 32 | }), 33 | ]) 34 | ), 35 | ], 36 | { 37 | params: { timing: DEFAULT_TIMING, delay: 0 }, 38 | } 39 | ); 40 | 41 | export const jackInTheBox = animation( 42 | [ 43 | animate( 44 | '{{ timing }}s {{ delay }}s', 45 | keyframes([ 46 | style({ 47 | opacity: 0, 48 | transform: 'scale(0.1) rotate(30deg)', 49 | 'transform-origin': 'center bottom', 50 | offset: 0, 51 | }), 52 | style({ 53 | opacity: 0.5, 54 | transform: 'rotate(-10deg)', 55 | offset: 0.5, 56 | }), 57 | style({ 58 | opacity: 0.7, 59 | transform: 'rotate(3deg)', 60 | offset: 0.7, 61 | }), 62 | style({ 63 | opacity: 1, 64 | transform: 'scale(1)', 65 | offset: 1, 66 | }), 67 | ]) 68 | ), 69 | ], 70 | { 71 | params: { timing: DEFAULT_TIMING, delay: 0 }, 72 | } 73 | ); 74 | 75 | export const rollIn = animation( 76 | [ 77 | animate( 78 | '{{ timing }}s {{ delay }}s', 79 | keyframes([ 80 | style({ 81 | opacity: 0, 82 | transform: 'translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg)', 83 | offset: 0, 84 | }), 85 | style({ 86 | opacity: 1, 87 | transform: 'none', 88 | offset: 1, 89 | }), 90 | ]) 91 | ), 92 | ], 93 | { 94 | params: { timing: DEFAULT_TIMING, delay: 0 }, 95 | } 96 | ); 97 | 98 | export const rollOut = animation( 99 | [ 100 | animate( 101 | '{{ timing }}s {{ delay }}s', 102 | keyframes([ 103 | style({ 104 | opacity: 1, 105 | offset: 0, 106 | }), 107 | style({ 108 | opacity: 0, 109 | transform: 'translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg)', 110 | offset: 1, 111 | }), 112 | ]) 113 | ), 114 | ], 115 | { 116 | params: { timing: DEFAULT_TIMING, delay: 0 }, 117 | } 118 | ); 119 | -------------------------------------------------------------------------------- /src/app/app.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

ng-animate

4 | 5 |
6 |

Available Animations

7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 |
27 |

Advanced Usage

28 |

You can use parameters to modify the animations:

29 | 30 | 31 | 32 | 35 | 36 | 39 | 40 | 43 |
44 | 47 |
48 | 61 |
62 | 68 |
69 |
70 |
71 | -------------------------------------------------------------------------------- /projects/ng-animate/src/lib/flippers.ts: -------------------------------------------------------------------------------- 1 | import { animate, animation, AnimationReferenceMetadata, keyframes, style } from '@angular/animations'; 2 | 3 | import { DEFAULT_TIMING } from './utils'; 4 | 5 | export const flip = animation( 6 | [ 7 | style({ 'backface-visibility': 'visible' }), 8 | animate( 9 | '{{ timing }}s {{ delay }}s ease-out', 10 | keyframes([ 11 | style({ 12 | transform: 'perspective(400px) rotate3d(0, 1, 0, -360deg)', 13 | offset: 0, 14 | }), 15 | style({ 16 | transform: 17 | 'perspective(400px) scale3d(1.5, 1.5, 1.5) rotate3d(0, 1, 0, -190deg)', 18 | offset: 0.4, 19 | }), 20 | style({ 21 | transform: 22 | 'perspective(400px) scale3d(1.5, 1.5, 1.5) rotate3d(0, 1, 0, -170deg)', 23 | offset: 0.5, 24 | }), 25 | style({ 26 | transform: 'perspective(400px) scale3d(.95, .95, .95)', 27 | offset: 0.8, 28 | }), 29 | style({ 30 | transform: 'perspective(400px)', 31 | offset: 1, 32 | }), 33 | ]) 34 | ), 35 | ], 36 | { 37 | params: { timing: DEFAULT_TIMING, delay: 0 }, 38 | } 39 | ); 40 | 41 | export function flipIn( 42 | rotateX: number, 43 | rotateY: number 44 | ): AnimationReferenceMetadata { 45 | return animation( 46 | [ 47 | style({ 'backface-visibility': 'visible' }), 48 | animate( 49 | '{{ timing }}s {{ delay }}s ease-in', 50 | keyframes([ 51 | style({ 52 | opacity: 0, 53 | transform: 54 | 'perspective(400px) rotate3d({{ rotateX }}, {{ rotateY }}, 0, 90deg)', 55 | offset: 0, 56 | }), 57 | style({ 58 | opacity: 1, 59 | transform: 60 | 'perspective(400px) rotate3d({{ rotateX }}, {{ rotateY }}, 0, -20deg)', 61 | offset: 0.4, 62 | }), 63 | style({ 64 | transform: 65 | 'perspective(400px) rotate3d({{ rotateX }}, {{ rotateY }}, 0, 10deg)', 66 | offset: 0.6, 67 | }), 68 | style({ 69 | transform: 70 | 'perspective(400px) rotate3d({{ rotateX }}, {{ rotateY }}, 0, -5deg)', 71 | offset: 0.8, 72 | }), 73 | style({ 74 | transform: 'perspective(400px) rotate3d(0, 0, 0, 0)', 75 | offset: 1, 76 | }), 77 | ]) 78 | ), 79 | ], 80 | { params: { timing: DEFAULT_TIMING, delay: 0, rotateX, rotateY } } 81 | ); 82 | } 83 | 84 | export const flipInX = flipIn(1, 0); 85 | export const flipInY = flipIn(0, 1); 86 | 87 | export function flipOut( 88 | rotateX: number, 89 | rotateY: number 90 | ): AnimationReferenceMetadata { 91 | return animation( 92 | [ 93 | style({ 'backface-visibility': 'visible' }), 94 | animate( 95 | '{{ timing }}s {{ delay }}s', 96 | keyframes([ 97 | style({ 98 | transform: 'perspective(400px)', 99 | offset: 0, 100 | }), 101 | style({ 102 | opacity: 1, 103 | transform: 104 | 'perspective(400px) rotate3d({{ rotateX }}, {{ rotateY }}, 0, -20deg)', 105 | offset: 0.3, 106 | }), 107 | style({ 108 | opacity: 0, 109 | transform: 110 | 'perspective(400px) rotate3d({{ rotateX }}, {{ rotateY }}, 0, 90deg)', 111 | offset: 1, 112 | }), 113 | ]) 114 | ), 115 | ], 116 | { params: { timing: DEFAULT_TIMING, delay: 0, rotateX, rotateY } } 117 | ); 118 | } 119 | 120 | export const flipOutX = flipOut(1, 0); 121 | export const flipOutY = flipOut(0, 1); 122 | -------------------------------------------------------------------------------- /projects/ng-animate/src/lib/back.ts: -------------------------------------------------------------------------------- 1 | import { animate, animation, keyframes, style } from '@angular/animations'; 2 | import { DEFAULT_TIMING } from './utils'; 3 | 4 | // https://github.com/animate-css/animate.css/tree/main/source/back_entrances 5 | 6 | export const backInUp = animation( 7 | animate( 8 | '{{ timing }}s {{ delay }}s', 9 | keyframes([ 10 | style({ 11 | opacity: 0.7, 12 | transform: 'translateY(1200px) scale(0.7)', 13 | offset: 0, 14 | }), 15 | style({ 16 | opacity: 0.7, 17 | transform: 'translateY(0px) scale(0.7)', 18 | offset: 0.8, 19 | }), 20 | style({ opacity: 1, transform: 'scale(1)', offset: 1 }), 21 | ]) 22 | ), 23 | { params: { timing: DEFAULT_TIMING, delay: 0 } } 24 | ); 25 | 26 | export const backInDown = animation( 27 | animate( 28 | '{{ timing }}s {{ delay }}s', 29 | keyframes([ 30 | style({ 31 | opacity: 0.7, 32 | transform: 'translateY(-1200px) scale(0.7)', 33 | offset: 0, 34 | }), 35 | style({ 36 | opacity: 0.7, 37 | transform: 'translateY(0px) scale(0.7)', 38 | offset: 0.8, 39 | }), 40 | style({ opacity: 1, transform: 'scale(1)', offset: 1 }), 41 | ]) 42 | ), 43 | { params: { timing: DEFAULT_TIMING, delay: 0 } } 44 | ); 45 | 46 | export const backInLeft = animation( 47 | animate( 48 | '{{ timing }}s {{ delay }}s', 49 | keyframes([ 50 | style({ 51 | opacity: 0.7, 52 | transform: 'translateX(-2000px) scale(0.7)', 53 | offset: 0, 54 | }), 55 | style({ 56 | opacity: 0.7, 57 | transform: 'translateX(0px) scale(0.7)', 58 | offset: 0.8, 59 | }), 60 | style({ opacity: 1, transform: 'scale(1)', offset: 1 }), 61 | ]) 62 | ), 63 | { params: { timing: DEFAULT_TIMING, delay: 0 } } 64 | ); 65 | 66 | export const backInRight = animation( 67 | animate( 68 | '{{ timing }}s {{ delay }}s', 69 | keyframes([ 70 | style({ 71 | opacity: 0.7, 72 | transform: 'translateX(2000px) scale(0.7)', 73 | offset: 0, 74 | }), 75 | style({ 76 | opacity: 0.7, 77 | transform: 'translateX(0px) scale(0.7)', 78 | offset: 0.8, 79 | }), 80 | style({ opacity: 1, transform: 'scale(1)', offset: 1 }), 81 | ]) 82 | ), 83 | { params: { timing: DEFAULT_TIMING, delay: 0 } } 84 | ); 85 | 86 | // https://github.com/animate-css/animate.css/tree/main/source/back_exits 87 | 88 | export const backOutUp = animation( 89 | animate( 90 | '{{ timing }}s {{ delay }}s', 91 | keyframes([ 92 | style({ opacity: 1.0, transform: 'scale(1)' }), 93 | style({ opacity: 0.7, transform: 'translateY(0px) scale(0.7)' }), 94 | style({ opacity: 0.7, transform: 'translateY(-700px) scale(0.7)' }), 95 | ]) 96 | ), 97 | { params: { timing: DEFAULT_TIMING, delay: 0 } } 98 | ); 99 | 100 | export const backOutDown = animation( 101 | animate( 102 | '{{ timing }}s {{ delay }}s', 103 | keyframes([ 104 | style({ opacity: 1.0, transform: 'scale(1)' }), 105 | style({ opacity: 0.7, transform: 'translateY(0px) scale(0.7)' }), 106 | style({ opacity: 0.7, transform: 'translateY(700px) scale(0.7)' }), 107 | ]) 108 | ), 109 | { params: { timing: DEFAULT_TIMING, delay: 0 } } 110 | ); 111 | 112 | export const backOutRight = animation( 113 | animate( 114 | '{{ timing }}s {{ delay }}s', 115 | keyframes([ 116 | style({ opacity: 1.0, transform: 'scale(1)' }), 117 | style({ opacity: 0.7, transform: 'translateX(0px) scale(0.7)' }), 118 | style({ opacity: 0.7, transform: 'translateX(2000px) scale(0.7)' }), 119 | ]) 120 | ), 121 | { params: { timing: DEFAULT_TIMING, delay: 0 } } 122 | ); 123 | 124 | export const backOutLeft = animation( 125 | animate( 126 | '{{ timing }}s {{ delay }}s', 127 | keyframes([ 128 | style({ opacity: 1.0, transform: 'scale(1)' }), 129 | style({ opacity: 0.7, transform: 'translateX(0px) scale(0.7)' }), 130 | style({ opacity: 0.7, transform: 'translateX(-2000px) scale(0.7)' }), 131 | ]) 132 | ), 133 | { params: { timing: DEFAULT_TIMING, delay: 0 } } 134 | ); 135 | -------------------------------------------------------------------------------- /projects/ng-animate/src/lib/zooming.ts: -------------------------------------------------------------------------------- 1 | import { animate, animation, AnimationReferenceMetadata, keyframes, style } from '@angular/animations'; 2 | 3 | import { DEFAULT_TIMING } from './utils'; 4 | 5 | export const zoomIn = animation( 6 | [ 7 | animate( 8 | '{{ timing }}s {{ delay }}s', 9 | keyframes([ 10 | style({ 11 | opacity: 0, 12 | transform: 'scale3d(.3, .3, .3)', 13 | offset: 0, 14 | }), 15 | style({ 16 | opacity: 1, 17 | transform: 'scale3d(1, 1, 1)', 18 | offset: 0.5, 19 | }), 20 | ]) 21 | ), 22 | ], 23 | { 24 | params: { timing: DEFAULT_TIMING, delay: 0 }, 25 | } 26 | ); 27 | 28 | export function zoomInY(a: string, b: string): AnimationReferenceMetadata { 29 | return animation( 30 | animate( 31 | '{{ timing }}s {{ delay }}s cubic-bezier(0.550, 0.055, 0.675, 0.190)', 32 | keyframes([ 33 | style({ 34 | opacity: 0, 35 | transform: `scale3d(.1, .1, .1) translate3d(0, {{ a }}, 0)`, 36 | offset: 0, 37 | }), 38 | style({ 39 | opacity: 1, 40 | transform: `scale3d(.475, .475, .475) translate3d(0, {{ b }}, 0)`, 41 | offset: 0.6, 42 | }), 43 | ]) 44 | ), 45 | { params: { timing: DEFAULT_TIMING, delay: 0, a, b } } 46 | ); 47 | } 48 | 49 | export function zoomInX(a: string, b: string): AnimationReferenceMetadata { 50 | return animation( 51 | animate( 52 | '{{ timing }}s {{ delay }}s cubic-bezier(0.550, 0.055, 0.675, 0.190)', 53 | keyframes([ 54 | style({ 55 | opacity: 0, 56 | transform: `scale3d(.1, .1, .1) translate3d({{ a }}, 0, 0)`, 57 | offset: 0, 58 | }), 59 | style({ 60 | opacity: 1, 61 | transform: `scale3d(.475, .475, .475) translate3d({{ b }}, 0, 0)`, 62 | offset: 0.6, 63 | }), 64 | ]) 65 | ), 66 | { params: { timing: DEFAULT_TIMING, delay: 0, a, b } } 67 | ); 68 | } 69 | 70 | export const zoomInDown = zoomInY('-1000px', '10px'); 71 | export const zoomInUp = zoomInY('1000px', '-10px'); 72 | export const zoomInLeft = zoomInX('-1000px', '10px'); 73 | export const zoomInRight = zoomInX('1000px', '-10px'); 74 | 75 | export const zoomOut = animation( 76 | [ 77 | animate( 78 | '{{ timing }}s {{ delay }}s', 79 | keyframes([ 80 | style({ 81 | opacity: 1, 82 | offset: 0, 83 | }), 84 | style({ 85 | opacity: 0, 86 | transform: 'scale3d(.3, .3, .3)', 87 | offset: 0.5, 88 | }), 89 | style({ 90 | opacity: 0, 91 | offset: 1, 92 | }), 93 | ]) 94 | ), 95 | ], 96 | { 97 | params: { timing: DEFAULT_TIMING, delay: 0 }, 98 | } 99 | ); 100 | 101 | export function zoomOutY(a: string, b: string): AnimationReferenceMetadata { 102 | return animation( 103 | animate( 104 | '{{ timing }}s {{ delay }}s cubic-bezier(0.550, 0.055, 0.675, 0.190)', 105 | keyframes([ 106 | style({ 107 | opacity: 1, 108 | transform: `scale3d(.475, .475, .475) translate3d(0, {{ a }}, 0)`, 109 | offset: 0.4, 110 | }), 111 | style({ 112 | opacity: 0, 113 | transform: `scale3d(.1, .1, .1) translate3d(0, {{ b }}, 0)`, 114 | offset: 1, 115 | }), 116 | ]) 117 | ), 118 | { params: { timing: DEFAULT_TIMING, delay: 0, a, b } } 119 | ); 120 | } 121 | 122 | export function zoomOutX(a: string, b: string): AnimationReferenceMetadata { 123 | return animation( 124 | animate( 125 | '{{ timing }}s {{ delay }}s cubic-bezier(0.550, 0.055, 0.675, 0.190)', 126 | keyframes([ 127 | style({ 128 | opacity: 1, 129 | transform: `scale3d(.475, .475, .475) translate3d({{ a }}, 0, 0)`, 130 | offset: 0.4, 131 | }), 132 | style({ 133 | opacity: 0, 134 | transform: `scale3d(.1, .1, .1) translate3d({{ b }}, 0, 0)`, 135 | offset: 1, 136 | }), 137 | ]) 138 | ), 139 | { params: { timing: DEFAULT_TIMING, delay: 0, a, b } } 140 | ); 141 | } 142 | 143 | export const zoomOutDown = zoomOutY('-60px', '2000px'); 144 | export const zoomOutUp = zoomOutY('60px', '-2000px'); 145 | export const zoomOutLeft = zoomOutX('42px', '-2000px'); 146 | export const zoomOutRight = zoomOutX('-42px', '2000px'); 147 | -------------------------------------------------------------------------------- /angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "demo": { 7 | "projectType": "application", 8 | "schematics": {}, 9 | "root": "", 10 | "sourceRoot": "src", 11 | "prefix": "app", 12 | "architect": { 13 | "build": { 14 | "builder": "@angular-devkit/build-angular:browser", 15 | "options": { 16 | "outputPath": "dist/demo", 17 | "index": "src/index.html", 18 | "main": "src/main.ts", 19 | "polyfills": "src/polyfills.ts", 20 | "tsConfig": "tsconfig.app.json", 21 | "aot": true, 22 | "assets": [ 23 | "src/favicon.ico", 24 | "src/assets" 25 | ], 26 | "styles": [ 27 | "src/styles.css" 28 | ], 29 | "scripts": [] 30 | }, 31 | "configurations": { 32 | "production": { 33 | "budgets": [ 34 | { 35 | "type": "initial", 36 | "maximumWarning": "500kb", 37 | "maximumError": "1mb" 38 | }, 39 | { 40 | "type": "anyComponentStyle", 41 | "maximumWarning": "2kb", 42 | "maximumError": "4kb" 43 | } 44 | ], 45 | "fileReplacements": [ 46 | { 47 | "replace": "src/environments/environment.ts", 48 | "with": "src/environments/environment.prod.ts" 49 | } 50 | ] 51 | }, 52 | "development": { 53 | "buildOptimizer": false, 54 | "optimization": false, 55 | "vendorChunk": true, 56 | "extractLicenses": false, 57 | "sourceMap": true, 58 | "namedChunks": true 59 | } 60 | }, 61 | "defaultConfiguration": "production" 62 | }, 63 | "serve": { 64 | "builder": "@angular-devkit/build-angular:dev-server", 65 | "options": {}, 66 | "configurations": { 67 | "production": { 68 | "browserTarget": "demo:build:production" 69 | }, 70 | "development": { 71 | "browserTarget": "demo:build:development" 72 | } 73 | }, 74 | "defaultConfiguration": "development" 75 | }, 76 | "extract-i18n": { 77 | "builder": "@angular-devkit/build-angular:extract-i18n", 78 | "options": { 79 | "browserTarget": "demo:build" 80 | } 81 | }, 82 | "test": { 83 | "builder": "@angular-devkit/build-angular:karma", 84 | "options": { 85 | "main": "src/test.ts", 86 | "polyfills": "src/polyfills.ts", 87 | "tsConfig": "tsconfig.spec.json", 88 | "karmaConfig": "karma.conf.js", 89 | "assets": [ 90 | "src/favicon.ico", 91 | "src/assets" 92 | ], 93 | "styles": [ 94 | "src/styles.css" 95 | ], 96 | "scripts": [] 97 | } 98 | }, 99 | "e2e": { 100 | "builder": "@angular-devkit/build-angular:protractor", 101 | "options": { 102 | "protractorConfig": "e2e/protractor.conf.js" 103 | }, 104 | "configurations": { 105 | "production": { 106 | "devServerTarget": "demo:serve:production" 107 | }, 108 | "development": { 109 | "devServerTarget": "demo:serve:development" 110 | } 111 | }, 112 | "defaultConfiguration": "development" 113 | }, 114 | "lint": { 115 | "builder": "@angular-eslint/builder:lint", 116 | "options": { 117 | "lintFilePatterns": [ 118 | "src/**/*.ts", 119 | "src/**/*.html" 120 | ] 121 | } 122 | } 123 | } 124 | }, 125 | "ng-animate": { 126 | "projectType": "library", 127 | "root": "projects/ng-animate", 128 | "sourceRoot": "projects/ng-animate/src", 129 | "prefix": "lib", 130 | "architect": { 131 | "build": { 132 | "builder": "@angular-devkit/build-angular:ng-packagr", 133 | "options": { 134 | "tsConfig": "projects/ng-animate/tsconfig.lib.json", 135 | "project": "projects/ng-animate/ng-package.json" 136 | }, 137 | "configurations": { 138 | "production": { 139 | "tsConfig": "projects/ng-animate/tsconfig.lib.prod.json" 140 | }, 141 | "development": {} 142 | }, 143 | "defaultConfiguration": "production" 144 | }, 145 | "test": { 146 | "builder": "@angular-devkit/build-angular:karma", 147 | "options": { 148 | "main": "projects/ng-animate/src/test.ts", 149 | "tsConfig": "projects/ng-animate/tsconfig.spec.json", 150 | "karmaConfig": "projects/ng-animate/karma.conf.js" 151 | } 152 | } 153 | } 154 | } 155 | }, 156 | "defaultProject": "demo", 157 | "cli": { 158 | "defaultCollection": "@angular-eslint/schematics" 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { transition, trigger, useAnimation } from '@angular/animations'; 2 | import { Component, ViewEncapsulation } from '@angular/core'; 3 | 4 | import { 5 | backInDown, 6 | backInLeft, 7 | backInRight, 8 | backInUp, 9 | backOutDown, 10 | backOutLeft, 11 | backOutRight, 12 | backOutUp, 13 | bounce, 14 | bounceIn, 15 | bounceInDown, 16 | bounceInLeft, 17 | bounceInRight, 18 | bounceInUp, 19 | bounceOut, 20 | bounceOutDown, 21 | bounceOutLeft, 22 | bounceOutRight, 23 | bounceOutUp, 24 | fadeIn, 25 | fadeInBottomLeft, 26 | fadeInBottomRight, 27 | fadeInDown, 28 | fadeInDownBig, 29 | fadeInLeft, 30 | fadeInLeftBig, 31 | fadeInRight, 32 | fadeInRightBig, 33 | fadeInTopLeft, 34 | fadeInTopRight, 35 | fadeInUp, 36 | fadeInUpBig, 37 | fadeOut, 38 | fadeOutBottomLeft, 39 | fadeOutBottomRight, 40 | fadeOutDown, 41 | fadeOutDownBig, 42 | fadeOutLeft, 43 | fadeOutLeftBig, 44 | fadeOutRight, 45 | fadeOutRightBig, 46 | fadeOutTopLeft, 47 | fadeOutTopRight, 48 | fadeOutUp, 49 | fadeOutUpBig, 50 | flash, 51 | flip, 52 | flipInX, 53 | flipInY, 54 | flipOutX, 55 | flipOutY, 56 | headShake, 57 | heartBeat, 58 | hinge, 59 | jackInTheBox, 60 | jello, 61 | lightSpeedInLeft, 62 | lightSpeedInRight, 63 | lightSpeedOutLeft, 64 | lightSpeedOutRight, 65 | pulse, 66 | rollIn, 67 | rollOut, 68 | rotateIn, 69 | rotateInDownLeft, 70 | rotateInDownRight, 71 | rotateInUpLeft, 72 | rotateInUpRight, 73 | rotateOut, 74 | rotateOutDownLeft, 75 | rotateOutDownRight, 76 | rotateOutUpLeft, 77 | rotateOutUpRight, 78 | rubberBand, 79 | shakeX, 80 | shakeY, 81 | slideInDown, 82 | slideInLeft, 83 | slideInRight, 84 | slideInUp, 85 | slideOutDown, 86 | slideOutLeft, 87 | slideOutRight, 88 | slideOutUp, 89 | swing, 90 | tada, 91 | wobble, 92 | zoomIn, 93 | zoomInDown, 94 | zoomInLeft, 95 | zoomInRight, 96 | zoomInUp, 97 | zoomOut, 98 | zoomOutDown, 99 | zoomOutLeft, 100 | zoomOutRight, 101 | zoomOutUp 102 | } from 'ng-animate'; 103 | 104 | @Component({ 105 | selector: 'app-root', 106 | templateUrl: 'app.component.html', 107 | styleUrls: ['./app.component.css'], 108 | encapsulation: ViewEncapsulation.None, 109 | animations: [trigger('tada', [transition('* => *', useAnimation(tada))])], 110 | }) 111 | export class AppComponent { 112 | attentionSeekersAnimations = { 113 | bounce, 114 | flash, 115 | pulse, 116 | rubberBand, 117 | shakeX, 118 | shakeY, 119 | headShake, 120 | swing, 121 | tada, 122 | wobble, 123 | jello, 124 | heartBeat, 125 | }; 126 | 127 | backEntrances = { 128 | backInDown, 129 | backInLeft, 130 | backInRight, 131 | backInUp, 132 | }; 133 | 134 | backExits = { 135 | backOutDown, 136 | backOutLeft, 137 | backOutRight, 138 | backOutUp, 139 | }; 140 | 141 | bouncingEntrances = { 142 | bounceIn, 143 | bounceInDown, 144 | bounceInLeft, 145 | bounceInRight, 146 | bounceInUp, 147 | }; 148 | 149 | bouncingExits = { 150 | bounceOut, 151 | bounceOutDown, 152 | bounceOutLeft, 153 | bounceOutRight, 154 | bounceOutUp, 155 | }; 156 | 157 | fadingEntrances = { 158 | fadeIn, 159 | fadeInDown, 160 | fadeInDownBig, 161 | fadeInLeft, 162 | fadeInLeftBig, 163 | fadeInRight, 164 | fadeInRightBig, 165 | fadeInUp, 166 | fadeInUpBig, 167 | fadeInTopLeft, 168 | fadeInTopRight, 169 | fadeInBottomLeft, 170 | fadeInBottomRight, 171 | }; 172 | 173 | fadingExits = { 174 | fadeOut, 175 | fadeOutDown, 176 | fadeOutDownBig, 177 | fadeOutLeft, 178 | fadeOutLeftBig, 179 | fadeOutRight, 180 | fadeOutRightBig, 181 | fadeOutUp, 182 | fadeOutUpBig, 183 | fadeOutTopLeft, 184 | fadeOutTopRight, 185 | fadeOutBottomRight, 186 | fadeOutBottomLeft, 187 | }; 188 | 189 | flippers = { flip, flipInX, flipInY, flipOutX, flipOutY }; 190 | 191 | lightspeed = { 192 | lightSpeedInRight, 193 | lightSpeedInLeft, 194 | lightSpeedOutRight, 195 | lightSpeedOutLeft, 196 | }; 197 | 198 | rotatingEntrances = { 199 | rotateIn, 200 | rotateInDownLeft, 201 | rotateInDownRight, 202 | rotateInUpLeft, 203 | rotateInUpRight, 204 | }; 205 | 206 | rotatingExits = { 207 | rotateOut, 208 | rotateOutDownLeft, 209 | rotateOutDownRight, 210 | rotateOutUpLeft, 211 | rotateOutUpRight, 212 | }; 213 | 214 | specials = { 215 | hinge, 216 | jackInTheBox, 217 | rollIn, 218 | rollOut, 219 | }; 220 | 221 | zoomingEntrances = { 222 | zoomIn, 223 | zoomInDown, 224 | zoomInLeft, 225 | zoomInRight, 226 | zoomInUp, 227 | }; 228 | 229 | zoomingExits = { 230 | zoomOut, 231 | zoomOutDown, 232 | zoomOutLeft, 233 | zoomOutRight, 234 | zoomOutUp, 235 | }; 236 | 237 | slidingEntrances = { 238 | slideInDown, 239 | slideInLeft, 240 | slideInRight, 241 | slideInUp, 242 | }; 243 | 244 | slidingExits = { 245 | slideOutDown, 246 | slideOutLeft, 247 | slideOutRight, 248 | slideOutUp, 249 | }; 250 | 251 | rotateInParams = { rotateIn }; 252 | 253 | // params 254 | 255 | animationTiming = 2; 256 | fromOpacity = 0; 257 | toOpacity = 1; 258 | degrees = 90; 259 | originX = 'center'; 260 | originY = 'center'; 261 | } 262 | -------------------------------------------------------------------------------- /projects/ng-animate/src/lib/bouncing.ts: -------------------------------------------------------------------------------- 1 | import { 2 | animation, 3 | style, 4 | animate, 5 | keyframes, 6 | AnimationReferenceMetadata, 7 | } from '@angular/animations'; 8 | import { DEFAULT_TIMING } from './utils'; 9 | 10 | export const bounceIn = animation( 11 | animate( 12 | '{{ timing }}s {{ delay }}s cubic-bezier(0.215, 0.610, 0.355, 1.000)', 13 | keyframes([ 14 | style({ opacity: 0, transform: 'scale3d(.3, .3, .3)', offset: 0 }), 15 | style({ transform: 'scale3d(1.1, 1.1, 1.1)', offset: 0.2 }), 16 | style({ transform: 'scale3d(.9, .9, .9)', offset: 0.4 }), 17 | style({ 18 | opacity: 1, 19 | transform: 'scale3d(1.03, 1.03, 1.03)', 20 | offset: 0.6, 21 | }), 22 | style({ transform: 'scale3d(.97, .97, .97)', offset: 0.8 }), 23 | style({ opacity: 1, transform: 'scale3d(1, 1, 1)', offset: 1 }), 24 | ]) 25 | ), 26 | { params: { timing: DEFAULT_TIMING, delay: 0 } } 27 | ); 28 | 29 | export function bounceInY( 30 | a: string, 31 | b: string, 32 | c: string, 33 | d: string 34 | ): AnimationReferenceMetadata { 35 | return animation( 36 | animate( 37 | '{{ timing }}s {{ delay }}s cubic-bezier(0.215, 0.610, 0.355, 1.000)', 38 | keyframes([ 39 | style({ 40 | opacity: 0, 41 | transform: 'translate3d(0, {{ a }}, 0)', 42 | offset: 0, 43 | }), 44 | style({ 45 | opacity: 1, 46 | transform: 'translate3d(0, {{ b }}, 0)', 47 | offset: 0.6, 48 | }), 49 | style({ transform: 'translate3d(0, {{ c }}, 0)', offset: 0.75 }), 50 | style({ transform: 'translate3d(0, {{ d }}, 0)', offset: 0.9 }), 51 | style({ opacity: 1, transform: 'none', offset: 1 }), 52 | ]) 53 | ), 54 | { 55 | params: { 56 | timing: DEFAULT_TIMING, 57 | delay: 0, 58 | a, 59 | b, 60 | c, 61 | d, 62 | }, 63 | } 64 | ); 65 | } 66 | 67 | export function bounceInX( 68 | a: string, 69 | b: string, 70 | c: string, 71 | d: string 72 | ): AnimationReferenceMetadata { 73 | return animation( 74 | animate( 75 | '{{ timing }}s {{ delay }}s cubic-bezier(0.215, 0.610, 0.355, 1.000)', 76 | keyframes([ 77 | style({ 78 | opacity: 0, 79 | transform: 'translate3d({{ a }}, 0, 0)', 80 | offset: 0, 81 | }), 82 | style({ 83 | opacity: 1, 84 | transform: 'translate3d({{ b }}, 0, 0)', 85 | offset: 0.6, 86 | }), 87 | style({ transform: 'translate3d({{ c }}, 0, 0)', offset: 0.75 }), 88 | style({ transform: 'translate3d({{ d }}, 0, 0)', offset: 0.9 }), 89 | style({ opacity: 1, transform: 'none', offset: 1 }), 90 | ]) 91 | ), 92 | { 93 | params: { 94 | timing: DEFAULT_TIMING, 95 | delay: 0, 96 | a, 97 | b, 98 | c, 99 | d, 100 | }, 101 | } 102 | ); 103 | } 104 | 105 | export const bounceInDown = bounceInY('-3000px', '25px', '-10px', '5px'); 106 | 107 | export const bounceInUp = bounceInY('3000px', '-25px', '10px', '-5px'); 108 | 109 | export const bounceInLeft = bounceInX('-3000px', '25px', '-10px', '5px'); 110 | 111 | export const bounceInRight = bounceInX('3000px', '-25px', '10px', '-5px'); 112 | 113 | export const bounceOut = animation( 114 | animate( 115 | '{{ timing }}s {{ delay }}s', 116 | keyframes([ 117 | style({ transform: 'scale3d(.9, .9, .9)', offset: 0.2 }), 118 | style({ 119 | opacity: 1, 120 | transform: 'scale3d({{ scale }}, {{ scale }}, {{ scale }})', 121 | offset: 0.5, 122 | }), 123 | style({ 124 | opacity: 1, 125 | transform: 'scale3d({{ scale }}, {{ scale }}, {{ scale }})', 126 | offset: 0.55, 127 | }), 128 | style({ opacity: 0, transform: 'scale3d(.3, .3, .3)', offset: 1 }), 129 | ]) 130 | ), 131 | { params: { timing: DEFAULT_TIMING, delay: 0, scale: 1.1 } } 132 | ); 133 | 134 | export function bounceOutY( 135 | a: string, 136 | b: string, 137 | c: string, 138 | d: string 139 | ): AnimationReferenceMetadata { 140 | return animation( 141 | animate( 142 | '{{ timing }}s {{ delay }}s', 143 | keyframes([ 144 | style({ transform: 'translate3d(0, {{ a }}, 0)', offset: 0.2 }), 145 | style({ 146 | opacity: 1, 147 | transform: 'translate3d(0, {{ b }}, 0)', 148 | offset: 0.4, 149 | }), 150 | style({ 151 | opacity: 1, 152 | transform: 'translate3d(0, {{ c }}, 0)', 153 | offset: 0.45, 154 | }), 155 | style({ 156 | opacity: 0, 157 | transform: 'translate3d(0, {{ d }}, 0)', 158 | offset: 1, 159 | }), 160 | ]) 161 | ), 162 | { 163 | params: { 164 | timing: DEFAULT_TIMING, 165 | delay: 0, 166 | a, 167 | b, 168 | c, 169 | d, 170 | }, 171 | } 172 | ); 173 | } 174 | 175 | export function bounceOutX(a: string, b: string): AnimationReferenceMetadata { 176 | return animation( 177 | animate( 178 | '{{ timing }}s {{ delay }}s', 179 | keyframes([ 180 | style({ 181 | opacity: 1, 182 | transform: 'translate3d({{ a }}, 0, 0)', 183 | offset: 0.2, 184 | }), 185 | style({ 186 | opacity: 0, 187 | transform: 'translate3d({{ b }}, 0, 0)', 188 | offset: 1, 189 | }), 190 | ]) 191 | ), 192 | { params: { timing: DEFAULT_TIMING, delay: 0, a, b } } 193 | ); 194 | } 195 | 196 | export const bounceOutDown = bounceOutY('10px', '-20px', '-20px', '2000px'); 197 | 198 | export const bounceOutUp = bounceOutY('-10px', '20px', '20px', '-2000px'); 199 | 200 | export const bounceOutLeft = bounceOutX('20px', '-2000px'); 201 | 202 | export const bounceOutRight = bounceOutX('-20px', '2000px'); 203 | -------------------------------------------------------------------------------- /projects/ng-animate/src/lib/fading.ts: -------------------------------------------------------------------------------- 1 | import { animate, animation, AnimationReferenceMetadata, keyframes, style } from '@angular/animations'; 2 | 3 | import { DEFAULT_TIMING } from './utils'; 4 | 5 | export function fadeXY( 6 | fromX: string | 0, 7 | fromY: string | 0, 8 | toX: string | 0, 9 | toY: string | 0, 10 | fromOpacity = 0, 11 | toOpacity = 1 12 | ): AnimationReferenceMetadata { 13 | return animation( 14 | animate( 15 | '{{ timing }}s {{ delay }}s', 16 | keyframes([ 17 | style({ 18 | opacity: '{{ fromOpacity }}', 19 | transform: 'translate3d({{ fromX }}, {{ fromY }}, 0)', 20 | offset: 0, 21 | }), 22 | style({ 23 | opacity: '{{ toOpacity }}', 24 | transform: 'translate3d({{ toX }}, {{ toY }}, 0)', 25 | offset: 1, 26 | }), 27 | ]) 28 | ), 29 | { 30 | params: { 31 | timing: DEFAULT_TIMING, 32 | delay: 0, 33 | fromX, 34 | toX, 35 | fromY, 36 | toY, 37 | fromOpacity, 38 | toOpacity, 39 | }, 40 | } 41 | ); 42 | } 43 | 44 | export function fadeInX( 45 | a: string | 0, 46 | b: string | 0, 47 | fromOpacity = 0, 48 | toOpacity = 1 49 | ): AnimationReferenceMetadata { 50 | return animation( 51 | animate( 52 | '{{ timing }}s {{ delay }}s', 53 | keyframes([ 54 | style({ 55 | opacity: '{{ fromOpacity }}', 56 | transform: 'translate3d({{ a }}, 0, 0)', 57 | offset: 0, 58 | }), 59 | style({ 60 | opacity: '{{ toOpacity }}', 61 | transform: 'translate3d({{ b }}, 0, 0)', 62 | offset: 1, 63 | }), 64 | ]) 65 | ), 66 | { 67 | params: { 68 | timing: DEFAULT_TIMING, 69 | delay: 0, 70 | a, 71 | b, 72 | fromOpacity, 73 | toOpacity, 74 | }, 75 | } 76 | ); 77 | } 78 | 79 | export function fadeInY( 80 | a: string | 0, 81 | b: string | 0, 82 | fromOpacity = 0, 83 | toOpacity = 1 84 | ): AnimationReferenceMetadata { 85 | return animation( 86 | animate( 87 | '{{ timing }}s {{ delay }}s', 88 | keyframes([ 89 | style({ 90 | opacity: '{{ fromOpacity }}', 91 | transform: 'translate3d(0, {{ a }}, 0)', 92 | offset: 0, 93 | }), 94 | style({ 95 | opacity: '{{ toOpacity }}', 96 | transform: 'translate3d(0, {{ b }}, 0)', 97 | offset: 1, 98 | }), 99 | ]) 100 | ), 101 | { 102 | params: { 103 | timing: DEFAULT_TIMING, 104 | delay: 0, 105 | a, 106 | b, 107 | fromOpacity, 108 | toOpacity, 109 | }, 110 | } 111 | ); 112 | } 113 | 114 | export const fadeIn = fadeInX(0, 0); 115 | export const fadeInDown = fadeInY('-100%', 0); 116 | export const fadeInDownBig = fadeInY('-2000px', 0); 117 | export const fadeInUp = fadeInY('100%', 0); 118 | export const fadeInUpBig = fadeInY('2000px', 0); 119 | export const fadeInLeft = fadeInX('-100%', 0); 120 | export const fadeInLeftBig = fadeInX('-2000px', 0); 121 | export const fadeInRight = fadeInX('100%', 0); 122 | export const fadeInRightBig = fadeInX('2000px', 0); 123 | 124 | export const fadeInTopLeft = fadeXY('-100%', '-100%', 0, 0); 125 | export const fadeInTopRight = fadeXY('100%', '-100%', 0, 0); 126 | export const fadeInBottomLeft = fadeXY('-100%', '100%', 0, 0); 127 | export const fadeInBottomRight = fadeXY('100%', '100%', 0, 0); 128 | 129 | export function fadeOutX( 130 | a: string | 0, 131 | b: string | 0 132 | ): AnimationReferenceMetadata { 133 | return fadeInX(a, b, 1, 0); 134 | } 135 | 136 | export function fadeOutY( 137 | a: string | 0, 138 | b: string | 0 139 | ): AnimationReferenceMetadata { 140 | return fadeInY(a, b, 1, 0); 141 | } 142 | 143 | export const fadeOut = fadeOutX(0, 0); 144 | export const fadeOutDown = fadeOutY(0, '100%'); 145 | export const fadeOutDownBig = fadeOutY(0, '2000px'); 146 | export const fadeOutUp = fadeOutY(0, '-100%'); 147 | export const fadeOutUpBig = fadeOutY(0, '-2000px'); 148 | export const fadeOutLeft = fadeOutX(0, '-100%'); 149 | export const fadeOutLeftBig = fadeOutX(0, '-2000px'); 150 | export const fadeOutRight = fadeOutX(0, '100%'); 151 | export const fadeOutRightBig = fadeOutX(0, '2000px'); 152 | 153 | export const fadeOutTopLeft = fadeXY(0, 0, '-100%', '-100%', 1, 0); 154 | export const fadeOutTopRight = fadeXY(0, 0, '100%', '-100%', 1, 0); 155 | export const fadeOutBottomLeft = fadeXY(0, 0, '-100%', '100%', 1, 0); 156 | export const fadeOutBottomRight = fadeXY(0, 0, '100%', '100%', 1, 0); 157 | 158 | export function slideX( 159 | a: string | 0, 160 | b: string | 0 161 | ): AnimationReferenceMetadata { 162 | return animation( 163 | animate( 164 | '{{ timing }}s {{ delay }}s', 165 | keyframes([ 166 | style({ 167 | transform: 'translate3d({{ a }}, 0, 0)', 168 | offset: 0, 169 | }), 170 | style({ 171 | transform: 'translate3d({{ b }}, 0, 0)', 172 | offset: 1, 173 | }), 174 | ]) 175 | ), 176 | { params: { timing: DEFAULT_TIMING, delay: 0, a, b } } 177 | ); 178 | } 179 | 180 | export function slideY( 181 | a: string | 0, 182 | b: string | 0 183 | ): AnimationReferenceMetadata { 184 | return animation( 185 | animate( 186 | '{{ timing }}s {{ delay }}s', 187 | keyframes([ 188 | style({ 189 | transform: 'translate3d(0, {{ a }}, 0)', 190 | offset: 0, 191 | }), 192 | style({ 193 | transform: 'translate3d(0, {{ b }}, 0)', 194 | offset: 1, 195 | }), 196 | ]) 197 | ), 198 | { params: { timing: DEFAULT_TIMING, delay: 0, a, b } } 199 | ); 200 | } 201 | 202 | export const slideInUp = slideY('-100%', 0); 203 | export const slideInDown = slideY('100%', 0); 204 | export const slideInLeft = slideX('-100%', 0); 205 | export const slideInRight = slideX('100%', 0); 206 | export const slideOutUp = slideY(0, '-100%'); 207 | export const slideOutDown = slideY(0, '100%'); 208 | export const slideOutLeft = slideX(0, '-100%'); 209 | export const slideOutRight = slideX(0, '100%'); 210 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🌙 ng-animate 2 | 3 | [![npm](https://img.shields.io/npm/v/ng-animate.svg)](https://www.npmjs.com/package/ng-animate) 4 | 5 | `ng-animate` is a collection of cool, reusable and flexible animations for Angular. It implements all the animations in [animate.css](https://daneden.github.io/animate.css/), but with the power and flexibility of [Angular animations](https://angular.io/guide/animations) instead of CSS. 6 | 7 | ## Demo 8 | 9 | The demo of the animations is available at [https://jiayihu.github.io/ng-animate/](https://jiayihu.github.io/ng-animate/). 10 | 11 | ## Usage 12 | 13 | ``` 14 | npm install ng-animate --save 15 | ``` 16 | 17 | ## Example 18 | 19 | Import the animation from the package and pass it to your Angular component using [useAnimation](https://angular.io/api/animations/useAnimation): 20 | 21 | ```javascript 22 | // my-component.component.ts 23 | import { trigger, transition, useAnimation } from '@angular/animations'; 24 | import { bounce } from 'ng-animate'; 25 | 26 | @Component({ 27 | selector: 'my-component', 28 | templateUrl: 'my-component.component.html', 29 | animations: [ 30 | trigger('bounce', [transition('* => *', useAnimation(bounce))]) 31 | ], 32 | }) 33 | export class MyComponent { 34 | bounce: any; 35 | } 36 | ``` 37 | 38 | ```html 39 | 40 |
41 | ``` 42 | 43 | **Note**: Make sure to have included `BrowserAnimationsModule` in your `AppModule` and the [web-animation.js](https://github.com/web-animations/web-animations-js) polyfill. 44 | 45 | It's also possible to import only a subset of the animations: 46 | 47 | ```javascript 48 | import { bounce } from 'ng-animate/lib/bouncing'; 49 | ``` 50 | 51 | ### Animation params 52 | 53 | **All the animations** provided by `ng-animate` support at least two **optional** params `timing` and `delay` to specify the animation duration and delay. Default value for `timing` is usually `1`s and `0`s for `delay`. 54 | You can pass the `params` object using the Javascript API or within the component template: 55 | 56 | ```javascript 57 | @Component({ 58 | selector: 'my-component', 59 | templateUrl: 'my-component.component.html', 60 | animations: [ 61 | trigger('bounce', [transition('* => *', useAnimation(bounce, { 62 | // Set the duration to 5seconds and delay to 2seconds 63 | params: { timing: 5, delay: 2 } 64 | }))]) 65 | ], 66 | }) 67 | export class MyComponent {} 68 | ``` 69 | 70 | Using a template can achieve the same result, but you'll have access to the component context: 71 | 72 | ```html 73 |
74 | ``` 75 | 76 | ## Animations 77 | 78 | All the animations are organized by their group. Many of them have additional params other than `timing/delay`: refer to [Advanced Usage](#advanced-params) for more details. Nevertheless you can probably ignore them if you're happy with how they are by default. 79 | 80 | ### Attention seekers 81 | 82 | - `bounce` 83 | - `flash` 84 | - `pulse` 85 | - `rubberBand` 86 | - `shakeX` 87 | - `shakeY` 88 | - `headShake` 89 | - `swing` 90 | - `tada` 91 | - `wobble` 92 | - `jello` 93 | - `heartBeat` 94 | 95 | ### Back 96 | 97 | - `backInDown` 98 | - `backInLeft` 99 | - `backInRight` 100 | - `backInUp` 101 | 102 | - `backOutDown` 103 | - `backOutLeft` 104 | - `backOutRight` 105 | - `backOutUp` 106 | 107 | ### Bouncing 108 | 109 | - `bounceIn` 110 | - `bounceOut`. Additional param: `scale` 111 | 112 | The following bouncing animations have additional params `a, b, c, d` for `translate` 113 | 114 | - `bounceInDown` 115 | - `bounceInLeft` 116 | - `bounceInRight` 117 | - `bounceInUp` 118 | 119 | - `bounceOutDown` 120 | - `bounceOutLeft` 121 | - `bounceOutRight` 122 | - `bounceOutUp` 123 | 124 | ### Fading 125 | 126 | All fading animations have additional params `fromOpacity`, `toOpacity` for `opacity` transition and `a, b` for `translate`. 127 | 128 | - `fadeIn` 129 | - `fadeInDown` 130 | - `fadeInLeft` 131 | - `fadeInRight` 132 | - `fadeInUp` 133 | 134 | - `fadeInDownBig` 135 | - `fadeInLeftBig` 136 | - `fadeInRightBig` 137 | - `fadeInUpBig` 138 | 139 | - `fadeOut` 140 | - `fadeOutDown` 141 | - `fadeOutLeft` 142 | - `fadeOutRight` 143 | - `fadeOutUp` 144 | 145 | - `fadeOutDownBig` 146 | - `fadeOutLeftBig` 147 | - `fadeOutRightBig` 148 | - `fadeOutUpBig` 149 | 150 | The following fading animations do not have `a, b` for `translate` but `fromX`,`fromY`,`toX`,`toY` instead. 151 | 152 | - `fadeInTopLeft` 153 | - `fadeInTopRight` 154 | - `fadeInBottomLeft` 155 | - `fadeInBottomRight` 156 | 157 | - `fadeOutTopLeft` 158 | - `fadeOutTopRight` 159 | - `fadeOutBottomLeft` 160 | - `fadeOutBottomRight` 161 | 162 | 163 | ### Sliding 164 | 165 | Sliding animations are basically fading animations without a change of `opacity`. They can also receive the same params. 166 | 167 | - `slideInDown` 168 | - `slideInLeft` 169 | - `slideInRight` 170 | - `slideInUp` 171 | - `slideOutDown` 172 | - `slideOutLeft` 173 | - `slideOutRight` 174 | - `slideOutUp` 175 | 176 | ### Flippers 177 | 178 | - `flip` 179 | - `flipInX` 180 | - `flipInY` 181 | - `flipOutX` 182 | - `flipOutY` 183 | 184 | ### LightSpeed 185 | 186 | - `lightSpeedIn` 187 | - `lightSpeedLeft` 188 | - `lightSpeedIn` 189 | - `lightSpeedOut` 190 | - `lightSpeedOutRight` (same as `lightSpeedOut`) 191 | - `lightSpeedOutLeft` 192 | 193 | ### Rotating 194 | 195 | All rotating animations have additional params `fromOpacity`, `toOpacity` for `opacity` transition, `origin` for `transform-origin` and `degrees` for `rotate3d`. 196 | 197 | - `rotateIn` 198 | - `rotateInDownLeft` 199 | - `rotateInDownRight` 200 | - `rotateInUpLeft` 201 | - `rotateInUpRight` 202 | - `rotateOut` 203 | - `rotateOutDownLeft` 204 | - `rotateOutDownRight` 205 | - `rotateOutUpLeft` 206 | - `rotateOutUpRight` 207 | 208 | ### Specials 209 | 210 | - `jackInTheBox` 211 | - `hinge` 212 | - `rollIn` 213 | - `rollOut` 214 | 215 | ### Zooming 216 | 217 | - `zoomIn` 218 | - `zoomOut` 219 | 220 | The following zooming animations have additional params `a, b` for `translate` 221 | 222 | - `zoomInDown` 223 | - `zoomInLeft` 224 | - `zoomInRight` 225 | - `zoomInUp` 226 | 227 | - `zoomOutDown` 228 | - `zoomOutLeft` 229 | - `zoomOutRight` 230 | - `zoomOutUp` 231 | 232 | ## Advanced params 233 | 234 | Many of the animations support also other params like `scale`, `fromOpacity`, `toOpacity` and much more, allowing extremely flexible usage and customization if you're not happy with default values. 235 | 236 | Single letters like `a, b, c, d` are used for the steps of some animations: `a` is the starting value, `d` is the ending. 237 | The animated property they refer to depends on the animation and the direction: usually `translate` on axis Y from `-Down/-Up`, axis X for `-Left/-Right`. 238 | 239 | ```javascript 240 | useAnimation(bounceInDown, { 241 | params: { 242 | timing: 5, 243 | 244 | // Specify granular values for `translate` on axis Y during 'bounceInDown' 245 | a: '-3000px', 246 | b: '25px', 247 | c: '-10px', 248 | d: '5px', 249 | } 250 | }) 251 | ``` 252 | -------------------------------------------------------------------------------- /projects/ng-animate/src/lib/attention-seekers.ts: -------------------------------------------------------------------------------- 1 | import { 2 | animation, 3 | style, 4 | animate, 5 | keyframes, 6 | useAnimation, 7 | } from '@angular/animations'; 8 | import { DEFAULT_TIMING } from './utils'; 9 | 10 | export const bounce = animation( 11 | [ 12 | style({ transform: 'translate3d(0, 0, 0)' }), 13 | animate( 14 | '{{ timing }}s {{ delay }}s', 15 | keyframes([ 16 | style({ transform: 'translate3d(0, 0, 0)', offset: 0.2 }), 17 | style({ transform: 'translate3d(0, -30px, 0)', offset: 0.4 }), 18 | style({ transform: 'translate3d(0, 0, 0)', offset: 0.53 }), 19 | style({ transform: 'translate3d(0, -15px, 0)', offset: 0.7 }), 20 | style({ transform: 'translate3d(0, -4px, 0)', offset: 0.9 }), 21 | style({ transform: 'translate3d(0, 0, 0)', offset: 1 }), 22 | ]) 23 | ), 24 | ], 25 | { params: { timing: DEFAULT_TIMING, delay: 0 } } 26 | ); 27 | 28 | export const flash = animation( 29 | animate( 30 | '{{ timing }}s {{ delay }}s', 31 | keyframes([ 32 | style({ opacity: 1 }), 33 | style({ opacity: 0 }), 34 | style({ opacity: 1 }), 35 | style({ opacity: 0 }), 36 | style({ opacity: 1 }), 37 | ]) 38 | ), 39 | { params: { timing: DEFAULT_TIMING, delay: 0 } } 40 | ); 41 | 42 | export const pulse = animation( 43 | animate( 44 | '{{ timing }}s {{ delay }}s', 45 | keyframes([ 46 | style({ transform: 'scale3d(1, 1, 1)' }), 47 | style({ transform: 'scale3d({{ scale }}, {{ scale }}, {{ scale }})' }), 48 | style({ transform: 'scale3d(1, 1, 1)' }), 49 | ]) 50 | ), 51 | { params: { scale: 1.25, timing: DEFAULT_TIMING, delay: 0 } } 52 | ); 53 | 54 | export const rubberBand = animation( 55 | animate( 56 | '{{ timing }}s {{ delay }}s', 57 | keyframes([ 58 | style({ transform: 'scale3d(1, 1, 1)', offset: 0 }), 59 | style({ transform: 'scale3d(1.25, 0.75, 1)', offset: 0.3 }), 60 | style({ transform: 'scale3d(0.75, 1.25, 1)', offset: 0.4 }), 61 | style({ transform: 'scale3d(1.15, 0.85, 1)', offset: 0.5 }), 62 | style({ transform: 'scale3d(.95, 1.05, 1)', offset: 0.65 }), 63 | style({ transform: 'scale3d(1.05, .95, 1)', offset: 0.75 }), 64 | style({ transform: 'scale3d(1, 1, 1)', offset: 1 }), 65 | ]) 66 | ), 67 | { params: { timing: DEFAULT_TIMING, delay: 0 } } 68 | ); 69 | 70 | export const shake = animation( 71 | animate( 72 | '{{ timing }}s {{ delay }}s', 73 | keyframes([ 74 | style({ transform: 'translate3d(0, 0, 0)', offset: 0 }), 75 | style({ transform: 'translate3d({{ translateB }})', offset: 0.1 }), 76 | style({ transform: 'translate3d({{ translateA }})', offset: 0.2 }), 77 | style({ transform: 'translate3d({{ translateB }})', offset: 0.3 }), 78 | style({ transform: 'translate3d({{ translateA }})', offset: 0.4 }), 79 | style({ transform: 'translate3d({{ translateB }})', offset: 0.5 }), 80 | style({ transform: 'translate3d({{ translateA }})', offset: 0.6 }), 81 | style({ transform: 'translate3d({{ translateB }})', offset: 0.7 }), 82 | style({ transform: 'translate3d({{ translateA }})', offset: 0.8 }), 83 | style({ transform: 'translate3d({{ translateB }})', offset: 0.9 }), 84 | style({ transform: 'translate3d(0, 0, 0)', offset: 1 }), 85 | ]) 86 | ), 87 | { 88 | params: { 89 | timing: DEFAULT_TIMING, 90 | delay: 0, 91 | translateA: '-10px, 0, 0', 92 | translateB: '10px, 0, 0', 93 | }, 94 | } 95 | ); 96 | 97 | export const shakeX = shake; 98 | export const shakeY = useAnimation(shake, { 99 | params: { translateA: '0, -10px, 0', translateB: '0, 10px, 0' }, 100 | }); 101 | 102 | export const swing = animation( 103 | animate( 104 | '{{ timing }}s {{ delay }}s', 105 | keyframes([ 106 | style({ transform: 'rotate3d(0, 0, 1, 15deg)', offset: 0.2 }), 107 | style({ transform: 'rotate3d(0, 0, 1, -10deg)', offset: 0.4 }), 108 | style({ transform: 'rotate3d(0, 0, 1, 5deg)', offset: 0.6 }), 109 | style({ transform: 'rotate3d(0, 0, 1, -5deg)', offset: 0.8 }), 110 | style({ transform: 'rotate3d(0, 0, 1, 0deg)', offset: 1 }), 111 | ]) 112 | ), 113 | { params: { timing: DEFAULT_TIMING, delay: 0 } } 114 | ); 115 | 116 | export const tada = animation( 117 | animate( 118 | '{{ timing }}s {{ delay }}s', 119 | keyframes([ 120 | style({ transform: 'scale3d(1, 1, 1)', offset: 0 }), 121 | style({ 122 | transform: 'scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg)', 123 | offset: 0.1, 124 | }), 125 | style({ 126 | transform: 'scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg)', 127 | offset: 0.2, 128 | }), 129 | style({ 130 | transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)', 131 | offset: 0.3, 132 | }), 133 | style({ 134 | transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg)', 135 | offset: 0.4, 136 | }), 137 | style({ 138 | transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)', 139 | offset: 0.5, 140 | }), 141 | style({ 142 | transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg)', 143 | offset: 0.6, 144 | }), 145 | style({ 146 | transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)', 147 | offset: 0.7, 148 | }), 149 | style({ 150 | transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg)', 151 | offset: 0.8, 152 | }), 153 | style({ 154 | transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)', 155 | offset: 0.9, 156 | }), 157 | style({ transform: 'scale3d(1, 1, 1)', offset: 1 }), 158 | ]) 159 | ), 160 | { params: { timing: DEFAULT_TIMING, delay: 0 } } 161 | ); 162 | 163 | export const wobble = animation( 164 | animate( 165 | '{{ timing }}s {{ delay }}s', 166 | keyframes([ 167 | style({ transform: 'none', offset: 0 }), 168 | style({ 169 | transform: 'translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg)', 170 | offset: 0.15, 171 | }), 172 | style({ 173 | transform: 'translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg)', 174 | offset: 0.3, 175 | }), 176 | style({ 177 | transform: 'translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg)', 178 | offset: 0.45, 179 | }), 180 | style({ 181 | transform: 'translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg)', 182 | offset: 0.6, 183 | }), 184 | style({ 185 | transform: 'translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg)', 186 | offset: 0.75, 187 | }), 188 | style({ transform: 'none', offset: 1 }), 189 | ]) 190 | ), 191 | { params: { timing: DEFAULT_TIMING, delay: 0 } } 192 | ); 193 | 194 | export const jello = animation( 195 | animate( 196 | '{{ timing }}s {{ delay }}s', 197 | keyframes([ 198 | style({ transform: 'none', offset: 0 }), 199 | style({ transform: 'none', offset: 0.11 }), 200 | style({ transform: 'skewX(-12.5deg) skewY(-12.5deg)', offset: 0.22 }), 201 | style({ transform: 'skewX(6.25deg) skewY(6.25deg)', offset: 0.33 }), 202 | style({ transform: 'skewX(-3.125deg) skewY(-3.125deg)', offset: 0.44 }), 203 | style({ transform: 'skewX(1.5625deg) skewY(1.5625deg)', offset: 0.55 }), 204 | style({ 205 | transform: 'skewX(-0.78125deg) skewY(-0.78125deg)', 206 | offset: 0.66, 207 | }), 208 | style({ 209 | transform: 'skewX(0.390625deg) skewY(0.390625deg)', 210 | offset: 0.77, 211 | }), 212 | style({ 213 | transform: 'skewX(-0.1953125deg) skewY(-0.1953125deg)', 214 | offset: 0.88, 215 | }), 216 | style({ transform: 'none', offset: 1 }), 217 | ]) 218 | ), 219 | { params: { timing: DEFAULT_TIMING, delay: 0 } } 220 | ); 221 | 222 | export const heartBeat = animation( 223 | animate( 224 | '{{ timing }}s {{ delay }}s ease-in-out', 225 | keyframes([ 226 | style({ transform: 'scale(1)', offset: 0 }), 227 | style({ transform: 'scale({{ scale }})', offset: 0.14 }), 228 | style({ transform: 'scale(1)', offset: 0.28 }), 229 | style({ 230 | transform: 'scale({{ scale }})', 231 | offset: 0.42, 232 | }), 233 | style({ 234 | transform: 'scale(1)', 235 | offset: 0.7, 236 | }), 237 | ]) 238 | ), 239 | { params: { timing: DEFAULT_TIMING * 1.3, scale: 1.3, delay: 0 } } 240 | ); 241 | 242 | export const headShake = animation( 243 | animate( 244 | '{{ timing }}s {{ delay }}s ease-in-out', 245 | keyframes([ 246 | style({ transform: 'translateX(0)', offset: 0 }), 247 | style({ transform: 'translateX(-6px) rotateY(-9deg)', offset: 0.065 }), 248 | style({ transform: 'translateX(5px) rotateY(7deg)', offset: 0.185 }), 249 | style({ transform: 'translateX(-3px) rotateY(-5deg)', offset: 0.315 }), 250 | style({ transform: 'translateX(2px) rotateY(3deg)', offset: 0.435 }), 251 | style({ transform: 'translateX(0)', offset: 0.5 }), 252 | ]) 253 | ), 254 | { params: { timing: DEFAULT_TIMING, delay: 0 } } 255 | ); 256 | -------------------------------------------------------------------------------- /src/assets/normalize.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */ 2 | 3 | /* Document 4 | ========================================================================== */ 5 | 6 | /** 7 | * 1. Correct the line height in all browsers. 8 | * 2. Prevent adjustments of font size after orientation changes in 9 | * IE on Windows Phone and in iOS. 10 | */ 11 | 12 | html { 13 | line-height: 1.15; /* 1 */ 14 | -ms-text-size-adjust: 100%; /* 2 */ 15 | -webkit-text-size-adjust: 100%; /* 2 */ 16 | } 17 | 18 | /* Sections 19 | ========================================================================== */ 20 | 21 | /** 22 | * Remove the margin in all browsers (opinionated). 23 | */ 24 | 25 | body { 26 | margin: 0; 27 | } 28 | 29 | /** 30 | * Add the correct display in IE 9-. 31 | */ 32 | 33 | article, 34 | aside, 35 | footer, 36 | header, 37 | nav, 38 | section { 39 | display: block; 40 | } 41 | 42 | /** 43 | * Correct the font size and margin on `h1` elements within `section` and 44 | * `article` contexts in Chrome, Firefox, and Safari. 45 | */ 46 | 47 | h1 { 48 | font-size: 2em; 49 | margin: 0.67em 0; 50 | } 51 | 52 | /* Grouping content 53 | ========================================================================== */ 54 | 55 | /** 56 | * Add the correct display in IE 9-. 57 | * 1. Add the correct display in IE. 58 | */ 59 | 60 | figcaption, 61 | figure, 62 | main { 63 | /* 1 */ 64 | display: block; 65 | } 66 | 67 | /** 68 | * Add the correct margin in IE 8. 69 | */ 70 | 71 | figure { 72 | margin: 1em 40px; 73 | } 74 | 75 | /** 76 | * 1. Add the correct box sizing in Firefox. 77 | * 2. Show the overflow in Edge and IE. 78 | */ 79 | 80 | hr { 81 | box-sizing: content-box; /* 1 */ 82 | height: 0; /* 1 */ 83 | overflow: visible; /* 2 */ 84 | } 85 | 86 | /** 87 | * 1. Correct the inheritance and scaling of font size in all browsers. 88 | * 2. Correct the odd `em` font sizing in all browsers. 89 | */ 90 | 91 | pre { 92 | font-family: monospace, monospace; /* 1 */ 93 | font-size: 1em; /* 2 */ 94 | } 95 | 96 | /* Text-level semantics 97 | ========================================================================== */ 98 | 99 | /** 100 | * 1. Remove the gray background on active links in IE 10. 101 | * 2. Remove gaps in links underline in iOS 8+ and Safari 8+. 102 | */ 103 | 104 | a { 105 | background-color: transparent; /* 1 */ 106 | -webkit-text-decoration-skip: objects; /* 2 */ 107 | } 108 | 109 | /** 110 | * 1. Remove the bottom border in Chrome 57- and Firefox 39-. 111 | * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. 112 | */ 113 | 114 | abbr[title] { 115 | border-bottom: none; /* 1 */ 116 | text-decoration: underline; /* 2 */ 117 | text-decoration: underline dotted; /* 2 */ 118 | } 119 | 120 | /** 121 | * Prevent the duplicate application of `bolder` by the next rule in Safari 6. 122 | */ 123 | 124 | b, 125 | strong { 126 | font-weight: inherit; 127 | } 128 | 129 | /** 130 | * Add the correct font weight in Chrome, Edge, and Safari. 131 | */ 132 | 133 | b, 134 | strong { 135 | font-weight: bolder; 136 | } 137 | 138 | /** 139 | * 1. Correct the inheritance and scaling of font size in all browsers. 140 | * 2. Correct the odd `em` font sizing in all browsers. 141 | */ 142 | 143 | code, 144 | kbd, 145 | samp { 146 | font-family: monospace, monospace; /* 1 */ 147 | font-size: 1em; /* 2 */ 148 | } 149 | 150 | /** 151 | * Add the correct font style in Android 4.3-. 152 | */ 153 | 154 | dfn { 155 | font-style: italic; 156 | } 157 | 158 | /** 159 | * Add the correct background and color in IE 9-. 160 | */ 161 | 162 | mark { 163 | background-color: #ff0; 164 | color: #000; 165 | } 166 | 167 | /** 168 | * Add the correct font size in all browsers. 169 | */ 170 | 171 | small { 172 | font-size: 80%; 173 | } 174 | 175 | /** 176 | * Prevent `sub` and `sup` elements from affecting the line height in 177 | * all browsers. 178 | */ 179 | 180 | sub, 181 | sup { 182 | font-size: 75%; 183 | line-height: 0; 184 | position: relative; 185 | vertical-align: baseline; 186 | } 187 | 188 | sub { 189 | bottom: -0.25em; 190 | } 191 | 192 | sup { 193 | top: -0.5em; 194 | } 195 | 196 | /* Embedded content 197 | ========================================================================== */ 198 | 199 | /** 200 | * Add the correct display in IE 9-. 201 | */ 202 | 203 | audio, 204 | video { 205 | display: inline-block; 206 | } 207 | 208 | /** 209 | * Add the correct display in iOS 4-7. 210 | */ 211 | 212 | audio:not([controls]) { 213 | display: none; 214 | height: 0; 215 | } 216 | 217 | /** 218 | * Remove the border on images inside links in IE 10-. 219 | */ 220 | 221 | img { 222 | border-style: none; 223 | } 224 | 225 | /** 226 | * Hide the overflow in IE. 227 | */ 228 | 229 | svg:not(:root) { 230 | overflow: hidden; 231 | } 232 | 233 | /* Forms 234 | ========================================================================== */ 235 | 236 | /** 237 | * 1. Change the font styles in all browsers (opinionated). 238 | * 2. Remove the margin in Firefox and Safari. 239 | */ 240 | 241 | button, 242 | input, 243 | optgroup, 244 | select, 245 | textarea { 246 | font-family: sans-serif; /* 1 */ 247 | font-size: 100%; /* 1 */ 248 | line-height: 1.15; /* 1 */ 249 | margin: 0; /* 2 */ 250 | } 251 | 252 | /** 253 | * Show the overflow in IE. 254 | * 1. Show the overflow in Edge. 255 | */ 256 | 257 | button, 258 | input { 259 | /* 1 */ 260 | overflow: visible; 261 | } 262 | 263 | /** 264 | * Remove the inheritance of text transform in Edge, Firefox, and IE. 265 | * 1. Remove the inheritance of text transform in Firefox. 266 | */ 267 | 268 | button, 269 | select { 270 | /* 1 */ 271 | text-transform: none; 272 | } 273 | 274 | /** 275 | * 1. Prevent a WebKit bug where (2) destroys native `audio` and `video` 276 | * controls in Android 4. 277 | * 2. Correct the inability to style clickable types in iOS and Safari. 278 | */ 279 | 280 | button, 281 | html [type="button"], 282 | /* 1 */ 283 | [type="reset"], 284 | [type="submit"] { 285 | -webkit-appearance: button; /* 2 */ 286 | } 287 | 288 | /** 289 | * Remove the inner border and padding in Firefox. 290 | */ 291 | 292 | button::-moz-focus-inner, 293 | [type="button"]::-moz-focus-inner, 294 | [type="reset"]::-moz-focus-inner, 295 | [type="submit"]::-moz-focus-inner { 296 | border-style: none; 297 | padding: 0; 298 | } 299 | 300 | /** 301 | * Restore the focus styles unset by the previous rule. 302 | */ 303 | 304 | button:-moz-focusring, 305 | [type="button"]:-moz-focusring, 306 | [type="reset"]:-moz-focusring, 307 | [type="submit"]:-moz-focusring { 308 | outline: 1px dotted ButtonText; 309 | } 310 | 311 | /** 312 | * Correct the padding in Firefox. 313 | */ 314 | 315 | fieldset { 316 | padding: 0.35em 0.75em 0.625em; 317 | } 318 | 319 | /** 320 | * 1. Correct the text wrapping in Edge and IE. 321 | * 2. Correct the color inheritance from `fieldset` elements in IE. 322 | * 3. Remove the padding so developers are not caught out when they zero out 323 | * `fieldset` elements in all browsers. 324 | */ 325 | 326 | legend { 327 | box-sizing: border-box; /* 1 */ 328 | color: inherit; /* 2 */ 329 | display: table; /* 1 */ 330 | max-width: 100%; /* 1 */ 331 | padding: 0; /* 3 */ 332 | white-space: normal; /* 1 */ 333 | } 334 | 335 | /** 336 | * 1. Add the correct display in IE 9-. 337 | * 2. Add the correct vertical alignment in Chrome, Firefox, and Opera. 338 | */ 339 | 340 | progress { 341 | display: inline-block; /* 1 */ 342 | vertical-align: baseline; /* 2 */ 343 | } 344 | 345 | /** 346 | * Remove the default vertical scrollbar in IE. 347 | */ 348 | 349 | textarea { 350 | overflow: auto; 351 | } 352 | 353 | /** 354 | * 1. Add the correct box sizing in IE 10-. 355 | * 2. Remove the padding in IE 10-. 356 | */ 357 | 358 | [type="checkbox"], 359 | [type="radio"] { 360 | box-sizing: border-box; /* 1 */ 361 | padding: 0; /* 2 */ 362 | } 363 | 364 | /** 365 | * Correct the cursor style of increment and decrement buttons in Chrome. 366 | */ 367 | 368 | [type="number"]::-webkit-inner-spin-button, 369 | [type="number"]::-webkit-outer-spin-button { 370 | height: auto; 371 | } 372 | 373 | /** 374 | * 1. Correct the odd appearance in Chrome and Safari. 375 | * 2. Correct the outline style in Safari. 376 | */ 377 | 378 | [type="search"] { 379 | -webkit-appearance: textfield; /* 1 */ 380 | outline-offset: -2px; /* 2 */ 381 | } 382 | 383 | /** 384 | * Remove the inner padding and cancel buttons in Chrome and Safari on macOS. 385 | */ 386 | 387 | [type="search"]::-webkit-search-cancel-button, 388 | [type="search"]::-webkit-search-decoration { 389 | -webkit-appearance: none; 390 | } 391 | 392 | /** 393 | * 1. Correct the inability to style clickable types in iOS and Safari. 394 | * 2. Change font properties to `inherit` in Safari. 395 | */ 396 | 397 | ::-webkit-file-upload-button { 398 | -webkit-appearance: button; /* 1 */ 399 | font: inherit; /* 2 */ 400 | } 401 | 402 | /* Interactive 403 | ========================================================================== */ 404 | 405 | /* 406 | * Add the correct display in IE 9-. 407 | * 1. Add the correct display in Edge, IE, and Firefox. 408 | */ 409 | 410 | details, 411 | /* 1 */ 412 | menu { 413 | display: block; 414 | } 415 | 416 | /* 417 | * Add the correct display in all browsers. 418 | */ 419 | 420 | summary { 421 | display: list-item; 422 | } 423 | 424 | /* Scripting 425 | ========================================================================== */ 426 | 427 | /** 428 | * Add the correct display in IE 9-. 429 | */ 430 | 431 | canvas { 432 | display: inline-block; 433 | } 434 | 435 | /** 436 | * Add the correct display in IE. 437 | */ 438 | 439 | template { 440 | display: none; 441 | } 442 | 443 | /* Hidden 444 | ========================================================================== */ 445 | 446 | /** 447 | * Add the correct display in IE 10-. 448 | */ 449 | 450 | [hidden] { 451 | display: none; 452 | } 453 | --------------------------------------------------------------------------------