diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..4decad4 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,49 @@ +name: 🎉 Release + +on: + push: + tags: + - 'v*' + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Install pnpm + uses: pnpm/action-setup@v2 + + - name: Set node + uses: actions/setup-node@v3 + with: + node-version: 16.x + cache: pnpm + + - run: npx changelogithub + continue-on-error: true + env: + GITHUB_TOKEN: ${{secrets.GH_TOKEN}} + + - name: Install + run: pnpm install --no-frozen-lockfile + + - name: Build + run: pnpm run build + + - name: Set Timezone + run: | + sudo ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime + echo "Asia/Shanghai" | sudo tee /etc/timezone + date + shell: bash + + - name: Set npmrc for root packages + run: echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > .npmrc + env: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + + - name: Publish to npm + run: pnpm run publish:script diff --git a/README.ZH-CN.md b/README.ZH-CN.md deleted file mode 100644 index 14d03ea..0000000 --- a/README.ZH-CN.md +++ /dev/null @@ -1 +0,0 @@ -# smoke-distance diff --git a/README.md b/README.md index 8ed2334..9959e9d 100644 --- a/README.md +++ b/README.md @@ -1 +1,36 @@ -# smoke-distance \ No newline at end of file +# smoke-distance +tweening engine for Typescript + +## Install + +```bash +npm i unplugin-vue-cssvars -D +``` +Or +```bash +yarn add unplugin-vue-cssvars -D +``` +Or +```bash +pnpm add unplugin-vue-cssvars -D +``` +## Usage + +```typescript +import SmokeDistance from 'b-tween'; +const smoke = new SmokeDistance({ + from: { + left: 0 + }, + to: { + left: 700 + }, + duration: 500, + easing: 'bounceOut', + onUpdate: (keys) => { + // You can do everything with keys + block.style.left = keys.left + 'px'; + } +}); +smoke.start(); +``` diff --git a/package.json b/package.json index 74bdc08..6447dad 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,12 @@ { "name": "smoke-distance", - "description": "", + "description": "tweening engine for Typescript", "private": false, "type": "module", - "version": "1.0.0", + "version": "0.0.0", "packageManager": "pnpm@8.6.12", "keywords": [ - "estree", - "ast", + "easing", "typescript", "vue", "react" @@ -17,37 +16,41 @@ "homepage": "https://github.com/ikun-svelte/smoke-distance", "repository": "https://github.com/ikun-svelte/smoke-distance", "bugs": "https://github.com/ikun-svelte/smoke-distance/issues", - "main": "./index.js", - "module": "./index.js", - "types": "./index.d.ts", + "main": "./dist/index.js", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { - "types": "./index.d.ts", - "require": "./index.cjs", - "import": "./index.js" + "types": "./dist/index.d.ts", + "require": "./dist/index.cjs", + "import": "./dist/index.js" } }, "typesVersions": { "*": { "*": [ - "./*", - "./index.d.ts" + "./dist/*", + "./dist/index.d.ts" ] } }, + "files": [ + "dist", + "package.json", + "README.md" + ], "scripts": { "init": "pnpm i", "lint:fix": "eslint --fix ./ --ext .vue,.js,.ts,.jsx,.tsx,.json ", - "dev": "", - "build": "", - "play": "", + "build": "tsup", "release": "bumpp package.json --commit --push --tag", "clean": "rimraf dist", "prepare": "npx simple-git-hooks", "test": "vitest", "test:update": "vitest -u", "test:coverage": "vitest --coverage", - "update:deps": "npx taze major -w && pnpm run init" + "update:deps": "npx taze major -w && pnpm run init", + "publish:npm": "npm publish --no-git-checks --access public" }, "peerDependencies": {}, "dependencies": {}, @@ -57,6 +60,7 @@ "@types/node": "^18.17.8", "@vitest/coverage-c8": "^0.33.0", "@vitest/ui": "^0.34.2", + "ansi-colors": "^4.1.3", "bumpp": "^9.2.0", "cross-env": "^7.0.3", "eslint": "^8.47.0", diff --git a/src/distance.ts b/src/distance.ts index 95c2be0..dc5ae4a 100644 --- a/src/distance.ts +++ b/src/distance.ts @@ -1,123 +1,140 @@ -import * as easing from './easing'; +import { easing } from './easing' +import type { easingType } from './easing' export declare interface SmokeDistanceOptions { - /** - * - */ - from: number - /** - * - */ - to: number - /** - * - */ - duration: number - /** - * - */ - delay: number - /** - * - */ - easing: string - /** - * - */ - onStart: number - /** - * - */ - onUpdate: number - /** - * - */ - onFinish: number + /** + * + */ + from: Record + /** + * + */ + to: Record + /** + * + */ + duration: number + /** + * + */ + delay: number + /** + * + */ + easing: easingType + /** + * + */ + onStart?: (keys: Record) => void + /** + * + */ + onUpdate?: (keys: Record) => void + /** + * + */ + onFinish?: (keys: Record) => void } export class SmokeDistance { - constructor(settings) { - const { - from, - to, - duration, - delay, - easing, - onStart, - onUpdate, - onFinish - } = settings; + private _from: Record = {} + private _to: Record = {} + private _duration: number = 500 + private _delay: number = 0 + private _easing: string = 'linear' + private _onStart: undefined | ((keys: Record) => void) = undefined + private _onUpdate: undefined | ((keys: Record) => void) = undefined + private _onFinish: undefined | ((keys: Record) => void) = undefined + private _startTime: number = 0 + private _started: boolean = false + private _finished: boolean = false + private _timer: null | number = null + private _time: null | number = null + private _elapsed: null | number = null + private _keys: Record = {} + constructor(options: SmokeDistanceOptions) { + const { + from, + to, + duration, + delay, + easing, + onStart, + onUpdate, + onFinish, + } = options - for (let key in from) { - if (to[key] === undefined) { - to[key] = from[key]; - } - } - for (let key in to) { - if (from[key] === undefined) { - from[key] = to[key]; - } - } + for (const key in from) { + if (to[key] === undefined) + to[key] = from[key] + } + for (const key in to) { + if (from[key] === undefined) + from[key] = to[key] + } + + this._from = from + this._to = to + this._duration = duration || 500 + this._delay = delay || 0 + this._easing = easing || 'linear' + this._onStart = onStart + this._onUpdate = onUpdate || function() { } + this._onFinish = onFinish + this._startTime = Date.now() + this._delay + this._started = false + this._finished = false + this._timer = null + this._time = null + this._keys = {} + } + + update() { + this._time = Date.now() + // delay some time + if (this._time < this._startTime) + return + + if (this._finished) + return - this.from = from; - this.to = to; - this.duration = duration || 500; - this.delay = delay || 0; - this.easing = easing || 'linear'; - this.onStart = onStart; - this.onUpdate = onUpdate || function () { }; - this.onFinish = onFinish; - this.startTime = Date.now() + this.delay; - this.started = false; - this.finished = false; - this.timer = null; - this.keys = {}; + // finish animation + if (this._elapsed === this._duration) { + if (!this._finished) { + this._finished = true + this._onFinish && this._onFinish(this._keys) + } + return } + this._elapsed = this._time - this._startTime + this._elapsed = this._elapsed > this._duration ? this._duration : this._elapsed + for (const key in this._to) + this._keys[key] = this._from[key] + (this._to[key] - this._from[key]) * easing[this._easing as keyof typeof easing](this._elapsed / this._duration) - update() { - this.time = Date.now(); - // delay some time - if (this.time < this.startTime) { - return; - } - if (this.finished) { - return; - } - // finish animation - if (this.elapsed === this.duration) { - if (!this.finished) { - this.finished = true; - this.onFinish && this.onFinish(this.keys); - } - return; - } - this.elapsed = this.time - this.startTime; - this.elapsed = this.elapsed > this.duration ? this.duration : this.elapsed; - for (let key in this.to) { - this.keys[key] = this.from[key] + (this.to[key] - this.from[key]) * easing[this.easing](this.elapsed / this.duration); - } - if (!this.started) { - this.onStart && this.onStart(this.keys); - this.started = true; - } - this.onUpdate(this.keys); + if (!this._started) { + this._onStart && this._onStart(this._keys) + this._started = true } + this._onUpdate && this._onUpdate(this._keys) + } - start() { - this.startTime = Date.now() + this.delay; - const tick = () => { - this.update(); - this.timer = requestAnimationFrame(tick); - if (this.finished) { - cancelAnimationFrame(this.timer); - this.timer = null; - } - }; - tick(); + start() { + this._startTime = Date.now() + this._delay + const tick = () => { + this.update() + this._timer = requestAnimationFrame(tick) + if (this._finished) { + cancelAnimationFrame(this._timer) + this._timer = null + } } + tick() + } - stop() { - cancelAnimationFrame(this.timer); - this.timer = null; + stop() { + if (this._timer !== null) { + cancelAnimationFrame(this._timer) + this._timer = null } + } } diff --git a/src/easing.ts b/src/easing.ts index 658597c..958a085 100644 --- a/src/easing.ts +++ b/src/easing.ts @@ -1,30 +1,30 @@ const easeInBy = (power: number) => { - return (t: number) => Math.pow(t, power) + return (t: number) => Math.pow(t, power) } const easeOutBy = (power: number) => { - return (t: number) => 1 - Math.abs(Math.pow(t - 1, power)) + return (t: number) => 1 - Math.abs(Math.pow(t - 1, power)) } const easeInOutBy = (power: number) => { - return (t: number) => t < 0.5 ? easeInBy(power)(t * 2) / 2 : easeOutBy(power)(t * 2 - 1) / 2 + 0.5 + return (t: number) => t < 0.5 ? easeInBy(power)(t * 2) / 2 : easeOutBy(power)(t * 2 - 1) / 2 + 0.5 } -export const linear = (t: number) => t -export const quadIn = easeInBy(2) -export const quadOut = easeOutBy(2) -export const quadInOut = easeInOutBy(2) -export const cubicIn = easeInBy(3) -export const cubicOut = easeOutBy(3) -export const cubicInOut = easeInOutBy(3) -export const quartIn = easeInBy(4) -export const quartOut = easeOutBy(4) -export const quartInOut = easeInOutBy(4) -export const quintIn = easeInBy(5) -export const quintOut = easeOutBy(5) -export const quintInOut = easeInOutBy(5) -export const sineIn = (t: number) => 1 + Math.sin(Math.PI / 2 * t - Math.PI / 2) -export const sineOut = (t: number) => Math.sin(Math.PI / 2 * t) -export const sineInOut = (t: number) => (1 + Math.sin(Math.PI * t - Math.PI / 2)) / 2 -export const bounceOut = (t: number) => { +const linear = (t: number) => t +const quadIn = easeInBy(2) +const quadOut = easeOutBy(2) +const quadInOut = easeInOutBy(2) +const cubicIn = easeInBy(3) +const cubicOut = easeOutBy(3) +const cubicInOut = easeInOutBy(3) +const quartIn = easeInBy(4) +const quartOut = easeOutBy(4) +const quartInOut = easeInOutBy(4) +const quintIn = easeInBy(5) +const quintOut = easeOutBy(5) +const quintInOut = easeInOutBy(5) +const sineIn = (t: number) => 1 + Math.sin(Math.PI / 2 * t - Math.PI / 2) +const sineOut = (t: number) => Math.sin(Math.PI / 2 * t) +const sineInOut = (t: number) => (1 + Math.sin(Math.PI * t - Math.PI / 2)) / 2 +const bounceOut = (t: number) => { const s = 7.5625 const p = 2.75 @@ -42,5 +42,29 @@ export const bounceOut = (t: number) => { t -= 2.625 / p return s * t * t + 0.984375 } -export const bounceIn = (t: number) => 1 - bounceOut(1 - t) -export const bounceInOut = (t: number) => t < 0.5 ? bounceIn(t * 2) * 0.5 : bounceOut(t * 2 - 1) * 0.5 + 0.5 +const bounceIn = (t: number) => 1 - bounceOut(1 - t) +const bounceInOut = (t: number) => t < 0.5 ? bounceIn(t * 2) * 0.5 : bounceOut(t * 2 - 1) * 0.5 + 0.5 + +export const easing = { + bounceIn, + bounceInOut, + bounceOut, + sineInOut, + sineOut, + sineIn, + quintInOut, + quintOut, + quintIn, + quartInOut, + quartOut, + quartIn, + cubicInOut, + cubicIn, + cubicOut, + quadInOut, + quadOut, + quadIn, + linear, +} + +export declare type easingType = keyof typeof easing diff --git a/tsup.config.ts b/tsup.config.ts new file mode 100644 index 0000000..ccf660e --- /dev/null +++ b/tsup.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'tsup' +export default defineConfig({ + entry: ['./src/index.ts'], + format: ['cjs', 'esm'], + clean: true, + minify: false, + dts: true, +}) diff --git a/vertify-commit.js b/vertify-commit.js index c2cdc67..a707121 100644 --- a/vertify-commit.js +++ b/vertify-commit.js @@ -1,6 +1,6 @@ import { readFileSync } from 'fs' import path from 'path' -import chalk from 'chalk' +import color from 'ansi-colors' const msgPath = path.resolve('.git/COMMIT_EDITMSG') const msg = readFileSync(msgPath, 'utf-8').trim() @@ -10,14 +10,14 @@ const commitRE if (!commitRE.test(msg)) { console.error( - ` ${chalk.bgRed.white(' ERROR ')} ${chalk.red( + ` ${color.bgRed.white(' ERROR ')} ${color.red( 'invalid commit message format.', )}\n\n${ - chalk.red( + color.red( ' Proper commit message format is required for automated changelog generation. Examples:\n\n', ) - } ${chalk.green('fea: add \'comments\' option')}\n` - + ` ${chalk.green( + } ${color.green('feat: add \'comments\' option')}\n` + + ` ${color.green( 'fix: handle events on blur', )}`, )