├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .husky ├── commit-msg └── pre-commit ├── .lintstagedrc.json ├── .npmrc ├── .prettierignore ├── .prettierrc.js ├── .vitepress └── cache │ └── deps_temp │ ├── _metadata.json │ ├── package.json │ ├── vue.js │ └── vue.js.map ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── commitlint.config.cjs ├── docs ├── .vitepress │ ├── cache │ │ └── deps │ │ │ ├── @tresjs_cientos.js │ │ │ ├── @tresjs_cientos.js.map │ │ │ ├── @tresjs_core.js │ │ │ ├── @tresjs_core.js.map │ │ │ ├── _metadata.json │ │ │ ├── chunk-7SHJKIQY.js │ │ │ ├── chunk-7SHJKIQY.js.map │ │ │ ├── chunk-JC4IRQUL.js │ │ │ ├── chunk-JC4IRQUL.js.map │ │ │ ├── chunk-N5TED7FU.js │ │ │ ├── chunk-N5TED7FU.js.map │ │ │ ├── chunk-XSUIV4LX.js │ │ │ ├── chunk-XSUIV4LX.js.map │ │ │ ├── package.json │ │ │ ├── three.js │ │ │ ├── three.js.map │ │ │ ├── vue.js │ │ │ └── vue.js.map │ ├── components.d.ts │ ├── components │ │ ├── Banner.vue │ │ ├── HomeSponsors.vue │ │ ├── HomeSponsorsGroup.vue │ │ ├── Icon.vue │ │ ├── PiniaLogo.vue │ │ ├── ThemeToggle.vue │ │ ├── VueMasteryHomeLink.vue │ │ ├── VueMasteryLogoLink.vue │ │ ├── VueSchoolLink.vue │ │ ├── button.vue │ │ ├── depsIcon.vue │ │ ├── home.vue │ │ ├── portal-journey │ │ │ ├── TheExperience.vue │ │ │ ├── TheFireFlies.vue │ │ │ ├── ThePortal.vue │ │ │ └── shaders │ │ │ │ ├── fireflies │ │ │ │ ├── fragment.glsl │ │ │ │ └── vertex.glsl │ │ │ │ └── portal │ │ │ │ ├── fragment.glsl │ │ │ │ └── vertex.glsl │ │ └── sponsors.json │ ├── config.ts │ ├── image │ │ ├── head.png │ │ ├── logo black.png │ │ ├── logo light.png │ │ ├── logo.png │ │ ├── logo1.png │ │ ├── logo2.png │ │ ├── logo3.png │ │ ├── logo5.png │ │ ├── logo6.png │ │ ├── logo66.png │ │ ├── logo7.png │ │ ├── logo8.png │ │ ├── logoopcity.png │ │ └── varies.png │ ├── locales │ │ ├── en.js │ │ ├── index.js │ │ └── zh.js │ ├── markdown-it-custom-anchor │ │ └── index.js │ ├── meta.ts │ ├── render-perma-link │ │ └── index.js │ ├── scripts │ │ ├── assets.ts │ │ └── build-pwa.mjs │ ├── style │ │ ├── main.css │ │ └── vars.css │ └── theme │ │ ├── Layout.ts │ │ ├── code-theme.css │ │ ├── custom.css │ │ ├── dark-theme.ts │ │ ├── index.ts │ │ ├── pwa.ts │ │ └── sponsors.css ├── getting-started.md ├── guide │ └── index.md ├── index.md ├── introduction.md ├── package.json ├── public │ ├── _headers │ ├── apple-touch-icon.png │ ├── dank-mono.css │ ├── favicon.ico │ ├── logo-light.png │ ├── logo-night.png │ ├── logo-shadow.svg │ ├── logo.png │ ├── logo.svg │ ├── logo66.png │ ├── netlify.svg │ ├── og-original.png │ ├── og.png │ ├── pwa-192x192.png │ ├── pwa-512x512.png │ ├── social.png │ └── sponsors │ │ ├── fincliplogo_black_svg.svg │ │ ├── fincliplogo_white_svg.svg │ │ ├── logo.svg │ │ ├── passionate-people-dark.svg │ │ ├── passionate-people-light.svg │ │ ├── vuejobs.svg │ │ ├── vuetify-logo-dark-text.svg │ │ └── vuetify-logo-light-text.svg ├── run-typedoc.js ├── tsconfig.json ├── typedoc-markdown.js ├── typedoc.tsconfig.json ├── vite-typedoc-plugin.ts ├── vite.config.ts └── zh │ ├── getting-started.md │ ├── index.md │ └── introduction.md ├── netlify.toml ├── package.json ├── packages ├── animated │ ├── package.json │ ├── src │ │ ├── easing.ts │ │ └── index.ts │ ├── tsconfig.json │ └── tsup.config.ts ├── config │ └── package.json ├── core │ ├── package.json │ ├── src │ │ ├── component.ts │ │ ├── index.ts │ │ ├── motion.ts │ │ ├── spring-test1.ts │ │ ├── spring.ts │ │ ├── stepper.ts │ │ └── utils.ts │ ├── tsconfig.json │ └── tsup.config.ts ├── dom │ ├── package.json │ ├── src │ │ └── index.ts │ ├── tsconfig.json │ └── tsup.config.ts ├── easing │ ├── package.json │ ├── readme.md │ ├── src │ │ ├── bezier-generator.ts │ │ ├── css-animation-function.ts │ │ ├── cubic-bezier.ts │ │ ├── easing.ts │ │ ├── index.ts │ │ └── steps.ts │ ├── tsconfig.json │ └── tsup.config.ts ├── utils │ ├── package.json │ ├── src │ │ ├── clamp.ts │ │ └── index.ts │ ├── tsconfig.json │ └── tsup.config.ts └── vue │ ├── package.json │ ├── src │ ├── components │ │ └── statistic │ │ │ ├── __tests__ │ │ │ └── statistic.spec.ts │ │ │ ├── statistic-types.ts │ │ │ ├── statistic.tsx │ │ │ ├── statistic.vue │ │ │ └── utils │ │ │ ├── animation.ts │ │ │ ├── easing.ts │ │ │ └── separator.ts │ ├── composable │ │ ├── useMotion.ts │ │ └── useStatistic.ts │ └── index.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── playground ├── .gitignore ├── .vscode │ └── extensions.json ├── README.md ├── index.html ├── package.json ├── public │ └── vite.svg ├── src │ ├── App.vue │ ├── assets │ │ └── vue.svg │ ├── components │ │ └── HelloWorld.vue │ ├── main.ts │ ├── style.css │ └── vite-env.d.ts ├── tsconfig.json ├── tsconfig.node.json └── vite.config.ts ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── renovate.json └── turbo.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # 🎨 editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | end_of_line = lf 8 | indent_style = space 9 | indent_size = 2 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | **/*.spec.* 3 | **/style/ 4 | *.html 5 | /components/test/* 6 | es/ 7 | lib/ 8 | _site/ 9 | dist/ 10 | pnpm-lock.yaml 11 | playground 12 | dist 13 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: 'relaxed-ts' 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules 5 | .pnp 6 | .pnp.js 7 | 8 | # testing 9 | coverage 10 | 11 | # next.js 12 | .next/ 13 | out/ 14 | build 15 | 16 | # misc 17 | .DS_Store 18 | *.pem 19 | 20 | # debug 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | .pnpm-debug.log* 25 | 26 | # local env files 27 | .env.local 28 | .env.development.local 29 | .env.test.local 30 | .env.production.local 31 | 32 | # turbo 33 | .turbo 34 | 35 | 36 | dist 37 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npx --no-install commitlint --edit "$1" 5 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npx --no-install lint-staged 5 | -------------------------------------------------------------------------------- /.lintstagedrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "*.{js,vue,ts,tsx,md}": ["prettier --write \"**/*.{ts,tsx,vue}\""] 3 | } 4 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | shamefully-hoist=true 2 | strict-peer-dependencies=false 3 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | /node_modules/** 2 | .local 3 | /dist/* 4 | /test/** 5 | /build/* 6 | **/*.svg 7 | lib/ 8 | es/ 9 | dist/ 10 | _site/ 11 | coverage/ 12 | CNAME 13 | LICENSE 14 | yarn.lock 15 | netlify.toml 16 | yarn-error.log 17 | *.sh 18 | *.snap 19 | .gitignore 20 | .npmignore 21 | .prettierignore 22 | .DS_Store 23 | .editorconfig 24 | .eslintignore 25 | **/*.yml 26 | components/style/color/*.less 27 | **/assets 28 | .gitattributes 29 | .stylelintrc 30 | .vcmrc 31 | .png 32 | .npmrc.template 33 | .huskyrc 34 | .gitmodules 35 | *.png 36 | v2-doc/ 37 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | useTabs: false, 3 | tabWidth: 2, 4 | printWidth: 80, 5 | singleQuote: true, 6 | trailingComma: 'none', 7 | semi: false, 8 | endOfLine: 'auto' 9 | } 10 | -------------------------------------------------------------------------------- /.vitepress/cache/deps_temp/_metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "hash": "ff0faebb", 3 | "browserHash": "1add5f80", 4 | "optimized": { 5 | "vue": { 6 | "src": "../../../node_modules/.pnpm/vue@3.2.47/node_modules/vue/dist/vue.runtime.esm-bundler.js", 7 | "file": "vue.js", 8 | "fileHash": "c96d1330", 9 | "needsInterop": false 10 | } 11 | }, 12 | "chunks": {} 13 | } -------------------------------------------------------------------------------- /.vitepress/cache/deps_temp/package.json: -------------------------------------------------------------------------------- 1 | {"type":"module"} -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.words": [ 3 | "ˈbɛz", 4 | "Attributify", 5 | "Bézier", 6 | "bumpp", 7 | "cientos", 8 | "commitlint", 9 | "consola", 10 | "Curze", 11 | "demi", 12 | "erkelost", 13 | "esno", 14 | "glsl", 15 | "gsap", 16 | "Holmér", 17 | "iife", 18 | "lerp", 19 | "lerps", 20 | "postplop", 21 | "preinstall", 22 | "tresjs", 23 | "tsup", 24 | "unocss", 25 | "variesd", 26 | "vitepress", 27 | "vitesse" 28 | ], 29 | "githubPullRequests.ignoredPullRequestBranches": ["main"] 30 | } 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 variesd 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # WIP 4 | 5 | ## 🍰 A spring physics based animation library 6 | -------------------------------------------------------------------------------- /commitlint.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['@commitlint/config-conventional'] 3 | } 4 | -------------------------------------------------------------------------------- /docs/.vitepress/cache/deps/@tresjs_core.js: -------------------------------------------------------------------------------- 1 | import { 2 | Me, 3 | Se, 4 | T, 5 | Ye, 6 | ct, 7 | gt, 8 | ht, 9 | it, 10 | re, 11 | st, 12 | ut, 13 | vt, 14 | wt, 15 | ye 16 | } from "./chunk-7SHJKIQY.js"; 17 | import "./chunk-N5TED7FU.js"; 18 | import "./chunk-XSUIV4LX.js"; 19 | import "./chunk-JC4IRQUL.js"; 20 | export { 21 | Ye as CameraType, 22 | ht as UseTresStateSymbol, 23 | vt as default, 24 | it as trasverseObjects, 25 | ye as useCamera, 26 | Se as useCatalogue, 27 | Me as useInstanceCreator, 28 | gt as useLoader, 29 | ct as useRaycaster, 30 | re as useRenderLoop, 31 | ut as useRenderer, 32 | st as useScene, 33 | wt as useTexture, 34 | T as useTres 35 | }; 36 | //# sourceMappingURL=@tresjs_core.js.map 37 | -------------------------------------------------------------------------------- /docs/.vitepress/cache/deps/@tresjs_core.js.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "sources": [], 4 | "sourcesContent": [], 5 | "mappings": "", 6 | "names": [] 7 | } 8 | -------------------------------------------------------------------------------- /docs/.vitepress/cache/deps/_metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "hash": "e2b28085", 3 | "browserHash": "a43cd7ee", 4 | "optimized": { 5 | "vue": { 6 | "src": "../../../../node_modules/.pnpm/vue@3.2.47/node_modules/vue/dist/vue.runtime.esm-bundler.js", 7 | "file": "vue.js", 8 | "fileHash": "846baa21", 9 | "needsInterop": false 10 | }, 11 | "@tresjs/core": { 12 | "src": "../../../../node_modules/.pnpm/@tresjs+core@1.7.0_three@0.149.0+vue@3.2.47/node_modules/@tresjs/core/dist/tres.js", 13 | "file": "@tresjs_core.js", 14 | "fileHash": "77709ccb", 15 | "needsInterop": false 16 | }, 17 | "@tresjs/cientos": { 18 | "src": "../../../../node_modules/.pnpm/@tresjs+cientos@1.7.0_xfijwtvpffppczrbyqr2tcvuk4/node_modules/@tresjs/cientos/dist/trescientos.js", 19 | "file": "@tresjs_cientos.js", 20 | "fileHash": "704f5426", 21 | "needsInterop": false 22 | }, 23 | "three": { 24 | "src": "../../../../node_modules/.pnpm/three@0.149.0/node_modules/three/build/three.module.js", 25 | "file": "three.js", 26 | "fileHash": "d4652f69", 27 | "needsInterop": false 28 | } 29 | }, 30 | "chunks": { 31 | "chunk-7SHJKIQY": { 32 | "file": "chunk-7SHJKIQY.js" 33 | }, 34 | "chunk-N5TED7FU": { 35 | "file": "chunk-N5TED7FU.js" 36 | }, 37 | "chunk-XSUIV4LX": { 38 | "file": "chunk-XSUIV4LX.js" 39 | }, 40 | "chunk-JC4IRQUL": { 41 | "file": "chunk-JC4IRQUL.js" 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /docs/.vitepress/cache/deps/chunk-JC4IRQUL.js: -------------------------------------------------------------------------------- 1 | var __defProp = Object.defineProperty; 2 | var __export = (target, all) => { 3 | for (var name in all) 4 | __defProp(target, name, { get: all[name], enumerable: true }); 5 | }; 6 | 7 | export { 8 | __export 9 | }; 10 | //# sourceMappingURL=chunk-JC4IRQUL.js.map 11 | -------------------------------------------------------------------------------- /docs/.vitepress/cache/deps/chunk-JC4IRQUL.js.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "sources": [], 4 | "sourcesContent": [], 5 | "mappings": "", 6 | "names": [] 7 | } 8 | -------------------------------------------------------------------------------- /docs/.vitepress/cache/deps/package.json: -------------------------------------------------------------------------------- 1 | {"type":"module"} -------------------------------------------------------------------------------- /docs/.vitepress/cache/deps/three.js.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "sources": [], 4 | "sourcesContent": [], 5 | "mappings": "", 6 | "names": [] 7 | } 8 | -------------------------------------------------------------------------------- /docs/.vitepress/cache/deps/vue.js: -------------------------------------------------------------------------------- 1 | import { 2 | BaseTransition, 3 | Comment, 4 | EffectScope, 5 | Fragment, 6 | KeepAlive, 7 | ReactiveEffect, 8 | Static, 9 | Suspense, 10 | Teleport, 11 | Text, 12 | Transition, 13 | TransitionGroup, 14 | VueElement, 15 | assertNumber, 16 | callWithAsyncErrorHandling, 17 | callWithErrorHandling, 18 | camelize, 19 | capitalize, 20 | cloneVNode, 21 | compatUtils, 22 | compile, 23 | computed, 24 | createApp, 25 | createBaseVNode, 26 | createBlock, 27 | createCommentVNode, 28 | createElementBlock, 29 | createHydrationRenderer, 30 | createPropsRestProxy, 31 | createRenderer, 32 | createSSRApp, 33 | createSlots, 34 | createStaticVNode, 35 | createTextVNode, 36 | createVNode, 37 | customRef, 38 | defineAsyncComponent, 39 | defineComponent, 40 | defineCustomElement, 41 | defineEmits, 42 | defineExpose, 43 | defineProps, 44 | defineSSRCustomElement, 45 | devtools, 46 | effect, 47 | effectScope, 48 | getCurrentInstance, 49 | getCurrentScope, 50 | getTransitionRawChildren, 51 | guardReactiveProps, 52 | h, 53 | handleError, 54 | hydrate, 55 | initCustomFormatter, 56 | initDirectivesForSSR, 57 | inject, 58 | isMemoSame, 59 | isProxy, 60 | isReactive, 61 | isReadonly, 62 | isRef, 63 | isRuntimeOnly, 64 | isShallow, 65 | isVNode, 66 | markRaw, 67 | mergeDefaults, 68 | mergeProps, 69 | nextTick, 70 | normalizeClass, 71 | normalizeProps, 72 | normalizeStyle, 73 | onActivated, 74 | onBeforeMount, 75 | onBeforeUnmount, 76 | onBeforeUpdate, 77 | onDeactivated, 78 | onErrorCaptured, 79 | onMounted, 80 | onRenderTracked, 81 | onRenderTriggered, 82 | onScopeDispose, 83 | onServerPrefetch, 84 | onUnmounted, 85 | onUpdated, 86 | openBlock, 87 | popScopeId, 88 | provide, 89 | proxyRefs, 90 | pushScopeId, 91 | queuePostFlushCb, 92 | reactive, 93 | readonly, 94 | ref, 95 | registerRuntimeCompiler, 96 | render, 97 | renderList, 98 | renderSlot, 99 | resolveComponent, 100 | resolveDirective, 101 | resolveDynamicComponent, 102 | resolveFilter, 103 | resolveTransitionHooks, 104 | setBlockTracking, 105 | setDevtoolsHook, 106 | setTransitionHooks, 107 | shallowReactive, 108 | shallowReadonly, 109 | shallowRef, 110 | ssrContextKey, 111 | ssrUtils, 112 | stop, 113 | toDisplayString, 114 | toHandlerKey, 115 | toHandlers, 116 | toRaw, 117 | toRef, 118 | toRefs, 119 | transformVNodeArgs, 120 | triggerRef, 121 | unref, 122 | useAttrs, 123 | useCssModule, 124 | useCssVars, 125 | useSSRContext, 126 | useSlots, 127 | useTransitionState, 128 | vModelCheckbox, 129 | vModelDynamic, 130 | vModelRadio, 131 | vModelSelect, 132 | vModelText, 133 | vShow, 134 | version, 135 | warn, 136 | watch, 137 | watchEffect, 138 | watchPostEffect, 139 | watchSyncEffect, 140 | withAsyncContext, 141 | withCtx, 142 | withDefaults, 143 | withDirectives, 144 | withKeys, 145 | withMemo, 146 | withModifiers, 147 | withScopeId 148 | } from "./chunk-N5TED7FU.js"; 149 | import "./chunk-JC4IRQUL.js"; 150 | export { 151 | BaseTransition, 152 | Comment, 153 | EffectScope, 154 | Fragment, 155 | KeepAlive, 156 | ReactiveEffect, 157 | Static, 158 | Suspense, 159 | Teleport, 160 | Text, 161 | Transition, 162 | TransitionGroup, 163 | VueElement, 164 | assertNumber, 165 | callWithAsyncErrorHandling, 166 | callWithErrorHandling, 167 | camelize, 168 | capitalize, 169 | cloneVNode, 170 | compatUtils, 171 | compile, 172 | computed, 173 | createApp, 174 | createBlock, 175 | createCommentVNode, 176 | createElementBlock, 177 | createBaseVNode as createElementVNode, 178 | createHydrationRenderer, 179 | createPropsRestProxy, 180 | createRenderer, 181 | createSSRApp, 182 | createSlots, 183 | createStaticVNode, 184 | createTextVNode, 185 | createVNode, 186 | customRef, 187 | defineAsyncComponent, 188 | defineComponent, 189 | defineCustomElement, 190 | defineEmits, 191 | defineExpose, 192 | defineProps, 193 | defineSSRCustomElement, 194 | devtools, 195 | effect, 196 | effectScope, 197 | getCurrentInstance, 198 | getCurrentScope, 199 | getTransitionRawChildren, 200 | guardReactiveProps, 201 | h, 202 | handleError, 203 | hydrate, 204 | initCustomFormatter, 205 | initDirectivesForSSR, 206 | inject, 207 | isMemoSame, 208 | isProxy, 209 | isReactive, 210 | isReadonly, 211 | isRef, 212 | isRuntimeOnly, 213 | isShallow, 214 | isVNode, 215 | markRaw, 216 | mergeDefaults, 217 | mergeProps, 218 | nextTick, 219 | normalizeClass, 220 | normalizeProps, 221 | normalizeStyle, 222 | onActivated, 223 | onBeforeMount, 224 | onBeforeUnmount, 225 | onBeforeUpdate, 226 | onDeactivated, 227 | onErrorCaptured, 228 | onMounted, 229 | onRenderTracked, 230 | onRenderTriggered, 231 | onScopeDispose, 232 | onServerPrefetch, 233 | onUnmounted, 234 | onUpdated, 235 | openBlock, 236 | popScopeId, 237 | provide, 238 | proxyRefs, 239 | pushScopeId, 240 | queuePostFlushCb, 241 | reactive, 242 | readonly, 243 | ref, 244 | registerRuntimeCompiler, 245 | render, 246 | renderList, 247 | renderSlot, 248 | resolveComponent, 249 | resolveDirective, 250 | resolveDynamicComponent, 251 | resolveFilter, 252 | resolveTransitionHooks, 253 | setBlockTracking, 254 | setDevtoolsHook, 255 | setTransitionHooks, 256 | shallowReactive, 257 | shallowReadonly, 258 | shallowRef, 259 | ssrContextKey, 260 | ssrUtils, 261 | stop, 262 | toDisplayString, 263 | toHandlerKey, 264 | toHandlers, 265 | toRaw, 266 | toRef, 267 | toRefs, 268 | transformVNodeArgs, 269 | triggerRef, 270 | unref, 271 | useAttrs, 272 | useCssModule, 273 | useCssVars, 274 | useSSRContext, 275 | useSlots, 276 | useTransitionState, 277 | vModelCheckbox, 278 | vModelDynamic, 279 | vModelRadio, 280 | vModelSelect, 281 | vModelText, 282 | vShow, 283 | version, 284 | warn, 285 | watch, 286 | watchEffect, 287 | watchPostEffect, 288 | watchSyncEffect, 289 | withAsyncContext, 290 | withCtx, 291 | withDefaults, 292 | withDirectives, 293 | withKeys, 294 | withMemo, 295 | withModifiers, 296 | withScopeId 297 | }; 298 | //# sourceMappingURL=vue.js.map 299 | -------------------------------------------------------------------------------- /docs/.vitepress/cache/deps/vue.js.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "sources": [], 4 | "sourcesContent": [], 5 | "mappings": "", 6 | "names": [] 7 | } 8 | -------------------------------------------------------------------------------- /docs/.vitepress/components.d.ts: -------------------------------------------------------------------------------- 1 | // generated by unplugin-vue-components 2 | // We suggest you to commit this file into source control 3 | // Read more: https://github.com/vuejs/core/pull/3399 4 | import '@vue/runtime-core' 5 | 6 | export {} 7 | 8 | declare module '@vue/runtime-core' { 9 | export interface GlobalComponents { 10 | Banner: typeof import('./components/Banner.vue')['default'] 11 | Button: typeof import('./components/button.vue')['default'] 12 | DepsIcon: typeof import('./components/depsIcon.vue')['default'] 13 | Home: typeof import('./components/home.vue')['default'] 14 | HomeSponsors: typeof import('./components/HomeSponsors.vue')['default'] 15 | HomeSponsorsGroup: typeof import('./components/HomeSponsorsGroup.vue')['default'] 16 | Icon: typeof import('./components/Icon.vue')['default'] 17 | PiniaLogo: typeof import('./components/PiniaLogo.vue')['default'] 18 | TheExperience: typeof import('./components/portal-journey/TheExperience.vue')['default'] 19 | TheFireFlies: typeof import('./components/portal-journey/TheFireFlies.vue')['default'] 20 | ThemeToggle: typeof import('./components/ThemeToggle.vue')['default'] 21 | ThePortal: typeof import('./components/portal-journey/ThePortal.vue')['default'] 22 | VueMasteryHomeLink: typeof import('./components/VueMasteryHomeLink.vue')['default'] 23 | VueMasteryLogoLink: typeof import('./components/VueMasteryLogoLink.vue')['default'] 24 | VueSchoolLink: typeof import('./components/VueSchoolLink.vue')['default'] 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /docs/.vitepress/components/Banner.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 26 | 27 | 32 | 33 | 66 | -------------------------------------------------------------------------------- /docs/.vitepress/components/HomeSponsors.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 39 | 40 | 53 | -------------------------------------------------------------------------------- /docs/.vitepress/components/HomeSponsorsGroup.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 58 | 59 | 101 | -------------------------------------------------------------------------------- /docs/.vitepress/components/Icon.vue: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /docs/.vitepress/components/ThemeToggle.vue: -------------------------------------------------------------------------------- 1 | 58 | 59 | 70 | 71 | 86 | -------------------------------------------------------------------------------- /docs/.vitepress/components/VueMasteryHomeLink.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 25 | 26 | 70 | -------------------------------------------------------------------------------- /docs/.vitepress/components/VueMasteryLogoLink.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 29 | 30 | 83 | -------------------------------------------------------------------------------- /docs/.vitepress/components/VueSchoolLink.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 24 | 25 | 63 | -------------------------------------------------------------------------------- /docs/.vitepress/components/button.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 16 | 17 | 95 | -------------------------------------------------------------------------------- /docs/.vitepress/components/depsIcon.vue: -------------------------------------------------------------------------------- 1 | 108 | -------------------------------------------------------------------------------- /docs/.vitepress/components/portal-journey/TheExperience.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 37 | -------------------------------------------------------------------------------- /docs/.vitepress/components/portal-journey/TheFireFlies.vue: -------------------------------------------------------------------------------- 1 | 38 | 47 | -------------------------------------------------------------------------------- /docs/.vitepress/components/portal-journey/ThePortal.vue: -------------------------------------------------------------------------------- 1 | 90 | 93 | -------------------------------------------------------------------------------- /docs/.vitepress/components/portal-journey/shaders/fireflies/fragment.glsl: -------------------------------------------------------------------------------- 1 | void main() 2 | { 3 | float distanceToCenter = distance(gl_PointCoord, vec2(0.5)); 4 | float strength = 0.05 / distanceToCenter - 0.1; 5 | 6 | gl_FragColor = vec4(1.0, 1.0, 1.0, strength); 7 | } -------------------------------------------------------------------------------- /docs/.vitepress/components/portal-journey/shaders/fireflies/vertex.glsl: -------------------------------------------------------------------------------- 1 | uniform float uPixelRatio; 2 | uniform float uSize; 3 | uniform float uTime; 4 | attribute float aScale; 5 | 6 | void main() 7 | { 8 | vec4 modelPosition = modelMatrix * vec4(position, 1.0); 9 | modelPosition.y += sin(uTime + modelPosition.x * 100.0) * aScale * 0.2; 10 | vec4 viewPosition = viewMatrix * modelPosition; 11 | vec4 projectionPosition = projectionMatrix * viewPosition; 12 | 13 | gl_Position = projectionPosition; 14 | gl_PointSize = aScale * uSize * uPixelRatio; 15 | gl_PointSize *= (1.0 / - viewPosition.z); 16 | } -------------------------------------------------------------------------------- /docs/.vitepress/components/portal-journey/shaders/portal/fragment.glsl: -------------------------------------------------------------------------------- 1 | varying vec2 vUv; 2 | uniform float uTime; 3 | uniform vec3 uColorStart; 4 | uniform vec3 uColorEnd; 5 | 6 | // Classic Perlin 3D Noise 7 | // by Stefan Gustavson 8 | // 9 | vec4 permute(vec4 x){return mod(((x*34.0)+1.0)*x, 289.0);} 10 | vec4 taylorInvSqrt(vec4 r){return 1.79284291400159 - 0.85373472095314 * r;} 11 | vec3 fade(vec3 t) {return t*t*t*(t*(t*6.0-15.0)+10.0);} 12 | 13 | float cnoise(vec3 P){ 14 | vec3 Pi0 = floor(P); // Integer part for indexing 15 | vec3 Pi1 = Pi0 + vec3(1.0); // Integer part + 1 16 | Pi0 = mod(Pi0, 289.0); 17 | Pi1 = mod(Pi1, 289.0); 18 | vec3 Pf0 = fract(P); // Fractional part for interpolation 19 | vec3 Pf1 = Pf0 - vec3(1.0); // Fractional part - 1.0 20 | vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x); 21 | vec4 iy = vec4(Pi0.yy, Pi1.yy); 22 | vec4 iz0 = Pi0.zzzz; 23 | vec4 iz1 = Pi1.zzzz; 24 | 25 | vec4 ixy = permute(permute(ix) + iy); 26 | vec4 ixy0 = permute(ixy + iz0); 27 | vec4 ixy1 = permute(ixy + iz1); 28 | 29 | vec4 gx0 = ixy0 / 7.0; 30 | vec4 gy0 = fract(floor(gx0) / 7.0) - 0.5; 31 | gx0 = fract(gx0); 32 | vec4 gz0 = vec4(0.5) - abs(gx0) - abs(gy0); 33 | vec4 sz0 = step(gz0, vec4(0.0)); 34 | gx0 -= sz0 * (step(0.0, gx0) - 0.5); 35 | gy0 -= sz0 * (step(0.0, gy0) - 0.5); 36 | 37 | vec4 gx1 = ixy1 / 7.0; 38 | vec4 gy1 = fract(floor(gx1) / 7.0) - 0.5; 39 | gx1 = fract(gx1); 40 | vec4 gz1 = vec4(0.5) - abs(gx1) - abs(gy1); 41 | vec4 sz1 = step(gz1, vec4(0.0)); 42 | gx1 -= sz1 * (step(0.0, gx1) - 0.5); 43 | gy1 -= sz1 * (step(0.0, gy1) - 0.5); 44 | 45 | vec3 g000 = vec3(gx0.x,gy0.x,gz0.x); 46 | vec3 g100 = vec3(gx0.y,gy0.y,gz0.y); 47 | vec3 g010 = vec3(gx0.z,gy0.z,gz0.z); 48 | vec3 g110 = vec3(gx0.w,gy0.w,gz0.w); 49 | vec3 g001 = vec3(gx1.x,gy1.x,gz1.x); 50 | vec3 g101 = vec3(gx1.y,gy1.y,gz1.y); 51 | vec3 g011 = vec3(gx1.z,gy1.z,gz1.z); 52 | vec3 g111 = vec3(gx1.w,gy1.w,gz1.w); 53 | 54 | vec4 norm0 = taylorInvSqrt(vec4(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110))); 55 | g000 *= norm0.x; 56 | g010 *= norm0.y; 57 | g100 *= norm0.z; 58 | g110 *= norm0.w; 59 | vec4 norm1 = taylorInvSqrt(vec4(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111))); 60 | g001 *= norm1.x; 61 | g011 *= norm1.y; 62 | g101 *= norm1.z; 63 | g111 *= norm1.w; 64 | 65 | float n000 = dot(g000, Pf0); 66 | float n100 = dot(g100, vec3(Pf1.x, Pf0.yz)); 67 | float n010 = dot(g010, vec3(Pf0.x, Pf1.y, Pf0.z)); 68 | float n110 = dot(g110, vec3(Pf1.xy, Pf0.z)); 69 | float n001 = dot(g001, vec3(Pf0.xy, Pf1.z)); 70 | float n101 = dot(g101, vec3(Pf1.x, Pf0.y, Pf1.z)); 71 | float n011 = dot(g011, vec3(Pf0.x, Pf1.yz)); 72 | float n111 = dot(g111, Pf1); 73 | 74 | vec3 fade_xyz = fade(Pf0); 75 | vec4 n_z = mix(vec4(n000, n100, n010, n110), vec4(n001, n101, n011, n111), fade_xyz.z); 76 | vec2 n_yz = mix(n_z.xy, n_z.zw, fade_xyz.y); 77 | float n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x); 78 | return 2.2 * n_xyz; 79 | } 80 | 81 | void main() 82 | { 83 | float speed = 0.1; 84 | // Displace the UV coordinates by a noise value 85 | vec2 displacedUv = vUv + cnoise(vec3(vUv* 5.0, uTime * speed)); 86 | // Get the color from the texture 87 | float strength = cnoise(vec3(displacedUv * 5.0, uTime * speed * 2.0)); 88 | 89 | // Outer Glow 90 | 91 | float outerGlow = distance(vUv, vec2(0.5)) * 5.0 - 1.4; 92 | strength += outerGlow; 93 | 94 | strength += step(- 0.2, strength) * 0.8; 95 | 96 | strength = clamp(strength, 0.0, 1.0); 97 | 98 | vec3 color = mix(uColorStart, uColorEnd, strength); 99 | 100 | gl_FragColor = vec4(color, 1.0); 101 | } -------------------------------------------------------------------------------- /docs/.vitepress/components/portal-journey/shaders/portal/vertex.glsl: -------------------------------------------------------------------------------- 1 | varying vec2 vUv; 2 | 3 | void main() 4 | { 5 | vec4 modelPosition = modelMatrix * vec4(position, 1.0); 6 | vec4 viewPosition = viewMatrix * modelPosition; 7 | vec4 projectionPosition = projectionMatrix * viewPosition; 8 | 9 | gl_Position = projectionPosition; 10 | vUv = uv; 11 | } -------------------------------------------------------------------------------- /docs/.vitepress/components/sponsors.json: -------------------------------------------------------------------------------- 1 | { 2 | "platinum": [], 3 | "gold": [ 4 | { 5 | "href": "https://vuejobs.com/?utm_source=vuerouter&utm_campaign=sponsor", 6 | "alt": "VueJobs", 7 | "imgSrcLight": "https://posva-sponsors.pages.dev/logos/vuejobs.svg", 8 | "imgSrcDark": "https://posva-sponsors.pages.dev/logos/vuejobs.svg" 9 | } 10 | ], 11 | "silver": [ 12 | { 13 | "href": "https://www.vuemastery.com/", 14 | "alt": "VueMastery", 15 | "imgSrcLight": "https://posva-sponsors.pages.dev/logos/vuemastery-light.svg", 16 | "imgSrcDark": "https://posva-sponsors.pages.dev/logos/vuemastery-dark.png" 17 | }, 18 | { 19 | "href": "https://www.prefect.io/", 20 | "imgSrcLight": "https://posva-sponsors.pages.dev/logos/prefectlogo-light.svg", 21 | "imgSrcDark": "https://posva-sponsors.pages.dev/logos/prefectlogo-dark.svg", 22 | "alt": "Prefect" 23 | } 24 | ], 25 | "bronze": [ 26 | { 27 | "alt": "Stanislas Ormières", 28 | "href": "https://stormier.ninja", 29 | "imgSrcDark": "https://avatars.githubusercontent.com/u/2486424?u=7b0c73ae5d090ce53bf59473094e9606fe082c59&v=4", 30 | "imgSrcLight": "https://avatars.githubusercontent.com/u/2486424?u=7b0c73ae5d090ce53bf59473094e9606fe082c59&v=4" 31 | }, 32 | { 33 | "alt": "Antony Konstantinidis", 34 | "href": "www.vuejs.de", 35 | "imgSrcDark": "https://avatars.githubusercontent.com/u/4183726?u=6b50a8ea16de29d2982f43c5640b1db9299ebcd1&v=4", 36 | "imgSrcLight": "https://avatars.githubusercontent.com/u/4183726?u=6b50a8ea16de29d2982f43c5640b1db9299ebcd1&v=4" 37 | }, 38 | { 39 | "href": "https://storyblok.com", 40 | "imgSrcLight": "https://posva-sponsors.pages.dev/logos/storyblok.png", 41 | "imgSrcDark": "https://posva-sponsors.pages.dev/logos/storyblok.png", 42 | "alt": "Storyblok" 43 | }, 44 | { 45 | "href": "https://nuxtjs.org", 46 | "imgSrcLight": "https://posva-sponsors.pages.dev/logos/nuxt-light.svg", 47 | "imgSrcDark": "https://posva-sponsors.pages.dev/logos/nuxt-dark.svg", 48 | "alt": "NuxtJS" 49 | } 50 | ] 51 | } 52 | -------------------------------------------------------------------------------- /docs/.vitepress/image/head.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variesd/varies/56b804007edde3e27519c38e2a38aaeac1ad5f78/docs/.vitepress/image/head.png -------------------------------------------------------------------------------- /docs/.vitepress/image/logo black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variesd/varies/56b804007edde3e27519c38e2a38aaeac1ad5f78/docs/.vitepress/image/logo black.png -------------------------------------------------------------------------------- /docs/.vitepress/image/logo light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variesd/varies/56b804007edde3e27519c38e2a38aaeac1ad5f78/docs/.vitepress/image/logo light.png -------------------------------------------------------------------------------- /docs/.vitepress/image/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variesd/varies/56b804007edde3e27519c38e2a38aaeac1ad5f78/docs/.vitepress/image/logo.png -------------------------------------------------------------------------------- /docs/.vitepress/image/logo1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variesd/varies/56b804007edde3e27519c38e2a38aaeac1ad5f78/docs/.vitepress/image/logo1.png -------------------------------------------------------------------------------- /docs/.vitepress/image/logo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variesd/varies/56b804007edde3e27519c38e2a38aaeac1ad5f78/docs/.vitepress/image/logo2.png -------------------------------------------------------------------------------- /docs/.vitepress/image/logo3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variesd/varies/56b804007edde3e27519c38e2a38aaeac1ad5f78/docs/.vitepress/image/logo3.png -------------------------------------------------------------------------------- /docs/.vitepress/image/logo5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variesd/varies/56b804007edde3e27519c38e2a38aaeac1ad5f78/docs/.vitepress/image/logo5.png -------------------------------------------------------------------------------- /docs/.vitepress/image/logo6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variesd/varies/56b804007edde3e27519c38e2a38aaeac1ad5f78/docs/.vitepress/image/logo6.png -------------------------------------------------------------------------------- /docs/.vitepress/image/logo66.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variesd/varies/56b804007edde3e27519c38e2a38aaeac1ad5f78/docs/.vitepress/image/logo66.png -------------------------------------------------------------------------------- /docs/.vitepress/image/logo7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variesd/varies/56b804007edde3e27519c38e2a38aaeac1ad5f78/docs/.vitepress/image/logo7.png -------------------------------------------------------------------------------- /docs/.vitepress/image/logo8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variesd/varies/56b804007edde3e27519c38e2a38aaeac1ad5f78/docs/.vitepress/image/logo8.png -------------------------------------------------------------------------------- /docs/.vitepress/image/logoopcity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variesd/varies/56b804007edde3e27519c38e2a38aaeac1ad5f78/docs/.vitepress/image/logoopcity.png -------------------------------------------------------------------------------- /docs/.vitepress/image/varies.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variesd/varies/56b804007edde3e27519c38e2a38aaeac1ad5f78/docs/.vitepress/image/varies.png -------------------------------------------------------------------------------- /docs/.vitepress/locales/en.js: -------------------------------------------------------------------------------- 1 | export default { 2 | vitepressConfig: { 3 | title: '', 4 | lang: 'en-US', 5 | description: 'The Vue Store that you will enjoy using' 6 | }, 7 | themeConfig: { 8 | label: 'English', 9 | selectText: 'Languages', 10 | editLinkText: 'Suggest changes to this page', 11 | lastUpdated: 'Last Updated', 12 | 13 | nav: [ 14 | { text: 'Guide', link: '/introduction.html' }, 15 | { text: 'API', link: '/api/' }, 16 | // { text: 'Config', link: '/config/' }, 17 | // { text: 'Plugins', link: '/plugins/' }, 18 | { 19 | text: 'Links', 20 | items: [ 21 | { 22 | text: 'Discussions', 23 | link: 'https://github.com/vuejs/pinia/discussions' 24 | }, 25 | { 26 | text: 'Chat', 27 | link: 'https://chat.vuejs.org' 28 | }, 29 | { 30 | text: 'Twitter', 31 | link: 'https://twitter.com/posva' 32 | }, 33 | { 34 | text: 'Changelog', 35 | link: 'https://github.com/vuejs/pinia/blob/v2/packages/pinia/CHANGELOG.md' 36 | } 37 | ] 38 | } 39 | ], 40 | 41 | sidebar: { 42 | '/api/': [ 43 | { 44 | text: 'packages', 45 | children: [ 46 | { text: 'pinia', link: '/api/modules/pinia.html' }, 47 | { text: '@pinia/nuxt', link: '/api/modules/pinia_nuxt.html' }, 48 | { 49 | text: '@pinia/testing', 50 | link: '/api/modules/pinia_testing.html' 51 | } 52 | ] 53 | } 54 | ], 55 | // catch-all fallback 56 | '/': [ 57 | { 58 | text: 'Introduction', 59 | children: [ 60 | { 61 | text: 'What is Pinia?', 62 | link: '/introduction.html' 63 | }, 64 | { 65 | text: 'Getting Started', 66 | link: '/getting-started.html' 67 | } 68 | ] 69 | }, 70 | { 71 | text: 'Core Concepts', 72 | children: [ 73 | { text: 'Defining a Store', link: '/core-concepts/' }, 74 | { text: 'State', link: '/core-concepts/state.html' }, 75 | { text: 'Getters', link: '/core-concepts/getters.html' }, 76 | { text: 'Actions', link: '/core-concepts/actions.html' }, 77 | { text: 'Plugins', link: '/core-concepts/plugins.html' }, 78 | { 79 | text: 'Stores outside of components', 80 | link: '/core-concepts/outside-component-usage.html' 81 | } 82 | ] 83 | }, 84 | { 85 | text: 'Server-Side Rendering (SSR)', 86 | children: [ 87 | { 88 | text: 'Vue and Vite', 89 | link: '/ssr/' 90 | }, 91 | { 92 | text: 'Nuxt.js', 93 | link: '/ssr/nuxt.html' 94 | } 95 | ] 96 | }, 97 | { 98 | text: 'Cookbook', 99 | link: '/cookbook/', 100 | children: [ 101 | { 102 | text: 'Migration from Vuex ≤4', 103 | link: '/cookbook/migration-vuex.html' 104 | }, 105 | { 106 | text: 'Hot Module Replacement', 107 | link: '/cookbook/hot-module-replacement.html' 108 | }, 109 | { 110 | text: 'Testing', 111 | link: '/cookbook/testing.html' 112 | }, 113 | { 114 | text: 'Usage without setup()', 115 | link: '/cookbook/options-api.html' 116 | }, 117 | { 118 | text: 'Composing Stores', 119 | link: '/cookbook/composing-stores.html' 120 | }, 121 | { 122 | text: 'Migration from v0/v1 to v2', 123 | link: '/cookbook/migration-v1-v2.html' 124 | }, 125 | { 126 | text: 'Dealing with composables', 127 | link: '/cookbook/composables.html' 128 | } 129 | ] 130 | } 131 | ] 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /docs/.vitepress/locales/index.js: -------------------------------------------------------------------------------- 1 | import en from './en.js' 2 | import zh from './zh.js' 3 | 4 | export default { 5 | vitepressConfig: { 6 | '/': en.vitepressConfig, 7 | '/zh/': zh.vitepressConfig 8 | }, 9 | themeConfig: { 10 | '/': en.themeConfig, 11 | '/zh/': zh.themeConfig 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /docs/.vitepress/locales/zh.js: -------------------------------------------------------------------------------- 1 | export default { 2 | vitepressConfig: { 3 | title: '', 4 | lang: 'zh-CN', 5 | description: '值得你喜欢的 Vue Store' 6 | }, 7 | themeConfig: { 8 | label: '简体中文', 9 | selectText: '选择语言', 10 | editLinkText: '对本页提出修改建议', 11 | lastUpdated: '最后更新', 12 | 13 | nav: [ 14 | { text: '指南', link: '/zh/introduction.html' }, 15 | { text: 'API', link: '/zh/api/' }, 16 | // { text: 'Config', link: '/config/' }, 17 | // { text: 'Plugins', link: '/plugins/' }, 18 | { 19 | text: '相关链接', 20 | items: [ 21 | { 22 | text: '论坛', 23 | link: 'https://github.com/vuejs/pinia/discussions' 24 | }, 25 | { 26 | text: '聊天室', 27 | link: 'https://chat.vuejs.org' 28 | }, 29 | { 30 | text: 'Twitter', 31 | link: 'https://twitter.com/posva' 32 | }, 33 | { 34 | text: '更新日志', 35 | link: 'https://github.com/vuejs/pinia/blob/v2/packages/pinia/CHANGELOG.md' 36 | } 37 | ] 38 | } 39 | ], 40 | 41 | sidebar: { 42 | '/zh/api/': [ 43 | { 44 | text: 'packages', 45 | children: [ 46 | { text: 'pinia', link: '/zh/api/modules/pinia.html' }, 47 | { text: '@pinia/nuxt', link: '/zh/api/modules/pinia_nuxt.html' }, 48 | { 49 | text: '@pinia/testing', 50 | link: '/zh/api/modules/pinia_testing.html' 51 | } 52 | ] 53 | } 54 | ], 55 | '/zh/': [ 56 | { 57 | text: '介绍', 58 | children: [ 59 | { 60 | text: 'Pinia 是什么?', 61 | link: '/zh/introduction.html' 62 | }, 63 | { 64 | text: '开始', 65 | link: '/zh/getting-started.html' 66 | } 67 | ] 68 | }, 69 | { 70 | text: '核心概念', 71 | children: [ 72 | { text: '定义 Store', link: '/zh/core-concepts/' }, 73 | { text: 'State', link: '/zh/core-concepts/state.html' }, 74 | { text: 'Getter', link: '/zh/core-concepts/getters.html' }, 75 | { text: 'Action', link: '/zh/core-concepts/actions.html' }, 76 | { text: '插件', link: '/zh/core-concepts/plugins.html' }, 77 | { 78 | text: '组件外的 Store', 79 | link: '/zh/core-concepts/outside-component-usage.html' 80 | } 81 | ] 82 | }, 83 | { 84 | text: '服务端渲染 (SSR)', 85 | children: [ 86 | { 87 | text: 'Vue 与 Vite', 88 | link: '/zh/ssr/' 89 | }, 90 | { 91 | text: 'Nuxt.js', 92 | link: '/zh/ssr/nuxt.html' 93 | } 94 | ] 95 | }, 96 | { 97 | text: '手册', 98 | link: '/zh/cookbook/', 99 | children: [ 100 | { 101 | text: '从 Vuex ≤4 迁移', 102 | link: '/zh/cookbook/migration-vuex.html' 103 | }, 104 | { 105 | text: '热更新', 106 | link: '/zh/cookbook/hot-module-replacement.html' 107 | }, 108 | { 109 | text: '测试', 110 | link: '/zh/cookbook/testing.html' 111 | }, 112 | { 113 | text: '不使用 setup() 的用法', 114 | link: '/zh/cookbook/options-api.html' 115 | }, 116 | { 117 | text: '组合式 Stores', 118 | link: '/zh/cookbook/composing-stores.html' 119 | }, 120 | { 121 | text: '从 v0/v1 迁移至 v2', 122 | link: '/zh/cookbook/migration-v1-v2.html' 123 | }, 124 | { 125 | text: '处理组合式函数', 126 | link: '/zh/cookbook/composables.html' 127 | } 128 | ] 129 | } 130 | ] 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /docs/.vitepress/markdown-it-custom-anchor/index.js: -------------------------------------------------------------------------------- 1 | const anchorMatch = /^.+(\s*\{#([a-z0-9\-_]+?)\}\s*)$/ 2 | 3 | const removeAnchorFromTitle = (oldTitle) => { 4 | const match = anchorMatch.exec(oldTitle) 5 | return match ? oldTitle.replace(match[1], '').trim() : oldTitle 6 | } 7 | 8 | export default function (md) { 9 | const oldTitle = md.renderer.rules.text 10 | md.renderer.rules.text = (tokens, idx, options, env, slf) => { 11 | const titleAndId = oldTitle(tokens, idx, options, env, slf) 12 | return removeAnchorFromTitle(titleAndId) 13 | } 14 | 15 | const oldHeading = md.renderer.rules.heading_open 16 | md.renderer.rules.heading_open = (tokens, idx, options, env, slf) => { 17 | const head = oldHeading(tokens, idx, options, env, slf) 18 | const data = md.__data 19 | const headers = data.headers || (data.headers = []) 20 | headers.forEach((element) => { 21 | element.title = removeAnchorFromTitle(element.title) 22 | }) 23 | return head 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /docs/.vitepress/meta.ts: -------------------------------------------------------------------------------- 1 | // noinspection ES6PreferShortImport: IntelliJ IDE hint to avoid warning to use `~/contributors`, will fail on build if changed 2 | 3 | /* Texts */ 4 | export const vitestName = 'Varies' 5 | export const vitestShortName = 'Varies' 6 | export const vitestDescription = 7 | 'A blazing fast unit test framework powered by Vite' 8 | 9 | /* CDN fonts and styles */ 10 | export const googleapis = 'https://fonts.googleapis.com' 11 | export const gstatic = 'https://fonts.gstatic.com' 12 | export const font = `${googleapis}/css2?family=Readex+Pro:wght@200;400;600&display=swap` 13 | 14 | /* vitepress head */ 15 | export const ogUrl = 'https://vitest.dev/' 16 | export const ogImage = `logo-light.png` 17 | 18 | /* GitHub and social links */ 19 | export const github = 'https://github.com/vitest-dev/vitest' 20 | export const releases = 'https://github.com/vitest-dev/vitest/releases' 21 | export const contributing = 22 | 'https://github.com/vitest-dev/vitest/blob/main/CONTRIBUTING.md' 23 | export const discord = 'https://chat.vitest.dev' 24 | export const twitter = 'https://twitter.com/vitest_dev' 25 | 26 | /* Avatar/Image/Sponsors servers */ 27 | export const preconnectLinks = [googleapis, gstatic] 28 | export const preconnectHomeLinks = [googleapis, gstatic] 29 | 30 | /* PWA runtime caching urlPattern regular expressions */ 31 | export const pwaFontsRegex = new RegExp(`^${googleapis}/.*`, 'i') 32 | export const pwaFontStylesRegex = new RegExp(`^${gstatic}/.*`, 'i') 33 | // eslint-disable-next-line prefer-regex-literals 34 | export const githubusercontentRegex = new RegExp( 35 | '^https://((i.ibb.co)|((raw|user-images).githubusercontent.com))/.*', 36 | 'i' 37 | ) 38 | -------------------------------------------------------------------------------- /docs/.vitepress/render-perma-link/index.js: -------------------------------------------------------------------------------- 1 | const position = { 2 | false: 'push', 3 | true: 'unshift' 4 | } 5 | 6 | const renderPermalink = (slug, opts, state, permalink) => { 7 | try { 8 | const tokens = state.tokens 9 | const token = tokens[permalink] 10 | const title = tokens[permalink + 1].children 11 | .filter((token) => token.type === 'text' || token.type === 'code_inline') 12 | .reduce((acc, t) => acc + t.content, '') 13 | const match = /^.+(\s*\{#([a-z0-9\-_]+?)\}\s*)$/.exec(title) 14 | slug = match ? match[2] : slug 15 | token.attrSet('id', slug) 16 | const space = () => 17 | Object.assign(new state.Token('text', '', 0), { content: ' ' }) 18 | 19 | const linkTokens = [ 20 | Object.assign(new state.Token('link_open', 'a', 1), { 21 | attrs: [ 22 | ...(opts.permalinkClass ? [['class', opts.permalinkClass]] : []), 23 | ['href', opts.permalinkHref(slug, state)], 24 | ...Object.entries(opts.permalinkAttrs(slug, state)) 25 | ] 26 | }), 27 | Object.assign(new state.Token('html_block', '', 0), { 28 | content: opts.permalinkSymbol 29 | }), 30 | new state.Token('link_close', 'a', -1) 31 | ] 32 | if (opts.permalinkSpace) { 33 | linkTokens[position[!opts.permalinkBefore]](space()) 34 | } 35 | state.tokens[permalink + 1].children[position[opts.permalinkBefore]]( 36 | ...linkTokens 37 | ) 38 | } catch (e) {} 39 | } 40 | 41 | export default renderPermalink 42 | -------------------------------------------------------------------------------- /docs/.vitepress/scripts/assets.ts: -------------------------------------------------------------------------------- 1 | import { promises as fs } from 'fs' 2 | import fg from 'fast-glob' 3 | import { font, preconnectHomeLinks, preconnectLinks } from '../meta' 4 | 5 | const preconnect = ` 6 | ${preconnectLinks 7 | .map((l) => ``) 8 | .join('\n')} 9 | ${preconnectLinks 10 | .map((l) => ``) 11 | .join('\n')} 12 | ` 13 | 14 | const preconnectHome = ` 15 | ${preconnectHomeLinks 16 | .map((l) => ``) 17 | .join('\n')} 18 | ${preconnectHomeLinks 19 | .map((l) => ``) 20 | .join('\n')} 21 | ` 22 | 23 | export const optimizePages = async (pwa: boolean) => { 24 | const names = await fg('./.vitepress/dist/**/*.html', { onlyFiles: true }) 25 | 26 | await Promise.all( 27 | names.map(async (i) => { 28 | let html = await fs.readFile(i, 'utf-8') 29 | 30 | let prefetchImg = '\n\t' 31 | 32 | let usePreconnect = preconnect 33 | 34 | if (i.endsWith('/dist/index.html')) { 35 | usePreconnect = preconnectHome 36 | prefetchImg = ` 37 | ${prefetchImg} 38 | \t 39 | ` 40 | } 41 | 42 | // we need the font on development, so the font entry is added in vitepress head 43 | html = html.replace( 44 | ``, 45 | '' 46 | ) 47 | 48 | html = html 49 | .replace( 50 | //g, 51 | ` 52 | ${usePreconnect} 53 | 54 | 55 | 61 | ` 64 | ) 65 | .trim() 66 | 67 | if (pwa) { 68 | html = html.replace( 69 | '', 70 | ` 71 | \t${prefetchImg} 72 | \t\n` 73 | ) 74 | } else { 75 | html = html.replace( 76 | '', 77 | ` 78 | ${prefetchImg} 79 | ` 80 | ) 81 | } 82 | 83 | html = html 84 | .replace(/aria-hidden="true"/gi, 'tabindex="-1" aria-hidden="true"') 85 | .replace( 86 | / { 6 | const config = await resolveConfig({}, 'build', 'production') 7 | // when `vite-plugin-pwa` is presented, use it to regenerate SW after rendering 8 | const pwaPlugin = config.plugins.find(i => i.name === 'vite-plugin-pwa')?.api 9 | const pwa = pwaPlugin && !pwaPlugin.disabled 10 | const assets = jiti(fileURLToPath(import.meta.url))('./assets.ts') 11 | await assets.optimizePages(pwa) 12 | if (pwa) 13 | await pwaPlugin.generateSW() 14 | } 15 | 16 | rebuildPwa() 17 | -------------------------------------------------------------------------------- /docs/.vitepress/style/main.css: -------------------------------------------------------------------------------- 1 | .dark [img-light] { 2 | display: none; 3 | } 4 | 5 | html:not(.dark) [img-dark] { 6 | display: none; 7 | } 8 | 9 | /* Overrides */ 10 | 11 | .VPSocialLink { 12 | transform: scale(0.9); 13 | } 14 | 15 | .vp-doc th, .vp-doc td { 16 | padding: 6px 10px; 17 | border: 1px solid #8882; 18 | } 19 | 20 | /* h3 breaks SEO => replaced with h2 with the same size */ 21 | .home-content h2 { 22 | margin-top: 2rem; 23 | font-size: 1.35rem; 24 | border-bottom: none; 25 | margin-bottom: 0; 26 | } 27 | 28 | img.resizable-img { 29 | width: unset; 30 | height: unset; 31 | } 32 | 33 | /* fix height ~ 2 lines of text: 3 or more cards per row */ 34 | .VPTeamMembersItem.small .profile .data .affiliation { 35 | min-height: 3rem; 36 | } 37 | .VPTeamMembersItem.small .profile .data .desc { 38 | min-height: 3rem; 39 | } 40 | 41 | /* fix height ~ 3 lines of text: 4 cards per row */ 42 | @media (min-width: 1064px) and (max-width: 1143px) { 43 | .VPTeamMembersItem.small .profile .data .affiliation { 44 | min-height: 4rem; 45 | } 46 | .VPTeamMembersItem.small .profile .data .desc { 47 | min-height: 4rem; 48 | } 49 | } 50 | /* fix height ~ 3 lines of text: 3 cards per row */ 51 | @media (min-width: 815px) and (max-width: 875px) { 52 | .VPTeamMembersItem.small .profile .data .affiliation { 53 | min-height: 4rem; 54 | } 55 | .VPTeamMembersItem.small .profile .data .desc { 56 | min-height: 4rem; 57 | } 58 | } 59 | /* fix height ~ 3 lines of text: 2 cards per row */ 60 | @media (max-width: 612px) { 61 | .VPTeamMembersItem.small .profile .data .affiliation { 62 | min-height: 4rem; 63 | } 64 | .VPTeamMembersItem.small .profile .data .desc { 65 | min-height: 4rem; 66 | } 67 | } 68 | /* fix height: one card per row */ 69 | @media (max-width: 568px) { 70 | .VPTeamMembersItem.small .profile .data .affiliation { 71 | min-height: unset; 72 | } 73 | .VPTeamMembersItem.small .profile .data .desc { 74 | min-height: unset; 75 | } 76 | } 77 | 78 | 79 | -------------------------------------------------------------------------------- /docs/.vitepress/style/vars.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Colors 3 | * -------------------------------------------------------------------------- */ 4 | 5 | :root { 6 | --vp-c-accent: #dab40b; 7 | --vp-c-brand: #6da13f; 8 | --vp-c-brand-light: #7ec242; 9 | --vp-c-brand-lighter: #93d31c; 10 | --vp-c-brand-dark: #668d11; 11 | --vp-c-brand-darker: #52730d; 12 | --vp-c-text-code: #5d6f5d; 13 | --vp-code-block-bg: rgba(125,125,125,0.04); 14 | /* fix TIP on light: the default one is too light (2 in contrast) */ 15 | --vp-custom-block-tip-text: rgb(12, 124, 108); 16 | --vp-custom-block-tip-border: rgba(12, 124, 108, 0.5); 17 | --vp-custom-block-tip-bg: rgba(18, 181, 157, 0.1); 18 | /* fix contrast on gray cards: used by --vp-c-text-2 */ 19 | --vp-c-text-light-2: rgba(56 56 56 / 70%); 20 | /* fix contrast: lang name on gray code block */ 21 | --vp-c-text-dark-3: rgba(180, 180, 180, 0.7); 22 | } 23 | 24 | .dark { 25 | --vp-code-block-bg: rgba(0,0,0,0.2); 26 | --vp-c-text-code: #c0cec0; 27 | /* fix TIP: check the same above (these are the defaults) */ 28 | --vp-custom-block-tip-text: rgb(18, 181, 157); 29 | --vp-custom-block-tip-border: rgba(18, 181, 157, 0.5); 30 | --vp-custom-block-tip-bg: rgba(18, 181, 157, 0.1); 31 | /* fix contrast on gray cards: check the same above (this is the default) */ 32 | --vp-c-text-dark-2: rgba(235, 235, 235, 0.60); 33 | /* fix lang name: check the same above (this is the default) */ 34 | --vp-c-text-dark-3: rgba(235, 235, 235, 0.38); 35 | } 36 | 37 | /** 38 | * Component: Button 39 | * -------------------------------------------------------------------------- */ 40 | 41 | :root { 42 | --vp-button-brand-border: var(--vp-c-brand-light); 43 | --vp-button-brand-text: var(--vp-c-text-dark-1); 44 | --vp-button-brand-bg: var(--vp-c-brand); 45 | --vp-button-brand-hover-border: var(--vp-c-brand-light); 46 | --vp-button-brand-hover-text: var(--vp-c-text-dark-1); 47 | --vp-button-brand-hover-bg: var(--vp-c-brand-light); 48 | --vp-button-brand-active-border: var(--vp-c-brand-light); 49 | --vp-button-brand-active-text: var(--vp-c-text-dark-1); 50 | --vp-button-brand-active-bg: var(--vp-button-brand-bg); 51 | } 52 | 53 | /** 54 | * Component: Home 55 | * -------------------------------------------------------------------------- */ 56 | 57 | :root { 58 | --vp-home-hero-name-color: transparent; 59 | --vp-home-hero-name-background: -webkit-linear-gradient( 60 | 120deg, 61 | #86b91a 30%, 62 | #edd532 63 | ); 64 | --vp-home-hero-image-background-image: linear-gradient( 65 | -45deg, 66 | #86b91a60 30%, 67 | #edd53260 68 | ); 69 | --vp-home-hero-image-filter: blur(30px); 70 | } 71 | 72 | @media (min-width: 640px) { 73 | :root { 74 | --vp-home-hero-image-filter: blur(56px); 75 | } 76 | } 77 | 78 | @media (min-width: 960px) { 79 | :root { 80 | --vp-home-hero-image-filter: blur(72px); 81 | } 82 | } 83 | 84 | 85 | /** 86 | * Component: Algolia 87 | * -------------------------------------------------------------------------- */ 88 | 89 | .DocSearch { 90 | --docsearch-primary-color: var(--vp-c-brand) !important; 91 | } 92 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/Layout.ts: -------------------------------------------------------------------------------- 1 | // import Theme from 'vitepress/theme' 2 | // import { h, defineComponent } from 'vue' 3 | // import sponsors from '../components/sponsors.json' 4 | // import './sponsors.css' 5 | // import { darkStorageConfig } from '../theme/dark-theme' 6 | // import { useDark } from '@vueuse/core' 7 | // import VueMasteryHomeLink from '../components/VueMasteryHomeLink.vue' 8 | 9 | // export const Layout = defineComponent({ 10 | // name: 'CustomLayout', 11 | 12 | // setup() { 13 | // const isDark = useDark(darkStorageConfig) 14 | 15 | // return () => 16 | // h( 17 | // Theme.Layout, 18 | // {}, 19 | // { 20 | // 'home-hero': () => 21 | // h('div', {}, [ 22 | // h( 23 | // 'div', 24 | // { 25 | // class: 'vue-school-homepage-link', 26 | // }, 27 | // [ 28 | // h( 29 | // 'a', 30 | // { 31 | // href: 'https://vueschool.io/lessons/introduction-to-pinia?friend=vuerouter&utm_source=pinia&utm_medium=link&utm_campaign=homepage', 32 | // target: '_blank', 33 | // rel: 'noopener', 34 | // }, 35 | // [h('span', 'Watch Video Introduction')] 36 | // ), 37 | // ] 38 | // ), 39 | // h(VueMasteryHomeLink), 40 | // ]), 41 | // 'sidebar-top': () => 42 | // h('div', { class: 'sponsors sponsors-top' }, [ 43 | // h('span', 'Platinum Sponsors'), 44 | // ...(sponsors.platinum.length 45 | // ? sponsors.platinum.map( 46 | // ({ href, imgSrcDark, imgSrcLight, alt }) => 47 | // h( 48 | // 'a', 49 | // { 50 | // href, 51 | // target: '_blank', 52 | // rel: 'noopener', 53 | // }, 54 | // [ 55 | // h('img', { 56 | // src: isDark.value ? imgSrcDark : imgSrcLight, 57 | // alt, 58 | // }), 59 | // ] 60 | // ) 61 | // ) 62 | // : [ 63 | // h( 64 | // 'a', 65 | // { 66 | // class: 'become-sponsor', 67 | // href: 'https://github.com/sponsors/posva', 68 | // target: '_blank', 69 | // rel: 'noopener', 70 | // alt: 'Your logo here', 71 | // }, 72 | // 'Become a Sponsor!' 73 | // ), 74 | // ]), 75 | // ]), 76 | // 'sidebar-bottom': () => 77 | // h('div', { class: 'sponsors' }, [ 78 | // h('span', 'Sponsors'), 79 | // ...sponsors.gold.map(({ href, imgSrcDark, imgSrcLight, alt }) => 80 | // h( 81 | // 'a', 82 | // { 83 | // href, 84 | // target: '_blank', 85 | // rel: 'noopener', 86 | // }, 87 | // [ 88 | // h('img', { 89 | // src: isDark.value ? imgSrcDark : imgSrcLight, 90 | // alt, 91 | // }), 92 | // ] 93 | // ) 94 | // ), 95 | // ]), 96 | // } 97 | // ) 98 | // }, 99 | // }) 100 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/dark-theme.ts: -------------------------------------------------------------------------------- 1 | import type { UseDarkOptions } from '@vueuse/core' 2 | 3 | export const darkStorageConfig: UseDarkOptions = { 4 | storageKey: 'pinia-color-scheme', 5 | valueLight: 'light' 6 | } 7 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/index.ts: -------------------------------------------------------------------------------- 1 | import { h } from 'vue' 2 | import type { App } from 'vue' 3 | import Theme from 'vitepress/theme' 4 | import { inBrowser } from 'vitepress' 5 | import tres from '@tresjs/core' 6 | import '../style/main.css' 7 | import '../style/vars.css' 8 | import 'uno.css' 9 | import HomePage from '../components/home.vue' 10 | 11 | if (inBrowser) import('./pwa') 12 | 13 | export default { 14 | ...Theme, 15 | Layout() { 16 | return h(Theme.Layout, null, { 17 | 'home-features-after': () => h(HomePage) 18 | }) 19 | }, 20 | enhanceApp({ app }) { 21 | app.use(tres) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/pwa.ts: -------------------------------------------------------------------------------- 1 | import { registerSW } from 'virtual:pwa-register' 2 | 3 | registerSW({ immediate: true }) 4 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/sponsors.css: -------------------------------------------------------------------------------- 1 | .sponsors { 2 | margin: 0 0 1rem 1.35rem; 3 | } 4 | 5 | .sponsors-top { 6 | margin-top: 1rem; 7 | /* workaround padding in vitepress */ 8 | margin-bottom: -2rem; 9 | } 10 | 11 | .sponsors > span { 12 | /* margin: 1.25rem 0; */ 13 | display: block; 14 | color: #999; 15 | font-size: 0.8rem; 16 | } 17 | 18 | .sponsors a:last-child { 19 | margin-bottom: 20px; 20 | } 21 | .sponsors a:first-child { 22 | margin-top: 18px; 23 | } 24 | 25 | .sponsors a { 26 | margin-top: 10px; 27 | width: 125px; 28 | display: block; 29 | } 30 | 31 | .sponsors.frontpage { 32 | text-align: center; 33 | } 34 | 35 | .sponsors.frontpage img { 36 | display: inline-block; 37 | vertical-align: middle; 38 | margin: 0 1rem 1.25rem 1rem; 39 | } 40 | 41 | .sponsors.frontpage h2 { 42 | color: #999; 43 | font-size: 1.2rem; 44 | border: none; 45 | } 46 | -------------------------------------------------------------------------------- /docs/getting-started.md: -------------------------------------------------------------------------------- 1 | ## Installation 2 | 3 | Install `pinia` with your favorite package manager: 4 | 5 | ```bash 6 | yarn add pinia 7 | # or with npm 8 | npm install pinia 9 | ``` 10 | 11 | :::tip 12 | If your app is using Vue <2.7, you also need to install the composition api: `@vue/composition-api`. If you are using Nuxt, you should follow [these instructions](/ssr/nuxt.md). 13 | ::: 14 | 15 | If you are using the Vue CLI, you can instead give this [**unofficial plugin**](https://github.com/wobsoriano/vue-cli-plugin-pinia) a try. 16 | 17 | Create a pinia instance (the root store) and pass it to the app as a plugin: 18 | 19 | ```js {2,5-6,8} 20 | import { createApp } from 'vue' 21 | import { createPinia } from 'pinia' 22 | import App from './App.vue' 23 | 24 | const pinia = createPinia() 25 | const app = createApp(App) 26 | 27 | app.use(pinia) 28 | app.mount('#app') 29 | ``` 30 | 31 | If you are using Vue 2, you also need to install a plugin and inject the created `pinia` at the root of the app: 32 | 33 | ```js {1,3-4,12} 34 | import { createPinia, PiniaVuePlugin } from 'pinia' 35 | 36 | Vue.use(PiniaVuePlugin) 37 | const pinia = createPinia() 38 | 39 | new Vue({ 40 | el: '#app', 41 | // other options... 42 | // ... 43 | // note the same `pinia` instance can be used across multiple Vue apps on 44 | // the same page 45 | pinia 46 | }) 47 | ``` 48 | 49 | This will also add devtools support. In Vue 3, some features like time traveling and editing are still not supported because vue-devtools doesn't expose the necessary APIs yet but the devtools have way more features and the developer experience as a whole is far superior. In Vue 2, Pinia uses the existing interface for Vuex (and can therefore not be used alongside it). 50 | 51 | ## What is a Store? 52 | 53 | A Store (like Pinia) is an entity holding state and business logic that isn't bound to your Component tree. In other words, **it hosts global state**. It's a bit like a component that is always there and that everybody can read off and write to. It has **three concepts**, the [state](./core-concepts/state.md), [getters](./core-concepts/getters.md) and [actions](./core-concepts/actions.md) and it's safe to assume these concepts are the equivalent of `data`, `computed` and `methods` in components. 54 | 55 | ## When should I use a Store 56 | 57 | A store should contain data that can be accessed throughout your application. This includes data that is used in many places, e.g. User information that is displayed in the navbar, as well as data that needs to be preserved through pages, e.g. a very complicated multi-step form. 58 | 59 | On the other hand, you should avoid including in the store local data that could be hosted in a component instead, e.g. the visibility of an element local to a page. 60 | 61 | Not all applications need access to a global state, but if yours need one, Pinia will make your life easier. 62 | -------------------------------------------------------------------------------- /docs/guide/index.md: -------------------------------------------------------------------------------- 1 | # The Beauty of Bézier Curves 2 | 3 | ![911fcc8f17a81bd9ae5d9874ee680c5.png](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0955c60a081f4d82a30944cb2ccff016~tplv-k3u1fbpfcp-watermark.image?) 4 | 5 | ## The Ever so Lovely Bézier Curve 6 | 7 | ### What is a Bezier curve? 8 | 9 | A Bézier curve (/ˈbɛz.i.eɪ/ BEH-zee-ay) is a parametric curve used in computer graphics and related fields. 10 | 11 | A set of discrete "control points" defines a smooth, continuous curve by means of a formula. 12 | 13 | Usually, the curve is intended to approximate a real-world shape that otherwise has no mathematical representation or whose representation is unknown or too complicated. 14 | 15 | The Bézier curve is named after French engineer Pierre Bézier (1910–1999), who used it in the 1960s for designing curves for the bodywork of Renault cars. Other uses include the design of computer fonts and animation. 16 | 17 | Bézier curves can be combined to form a Bézier spline, or generalized to higher dimensions to form Bézier surfaces. The Bézier triangle is a special case of the latter. 18 | 19 | 一条贝塞尔曲线是由一组 Points 从 P0 ~ PN 所控制的,这边 N 就是他的顺序(比如 N=1 的时候是线性的,2 的时候是二次,等等)。第一个控制点和最后一个控制点是曲线的终点;然而中间的一些控制点(如果有),通常不在曲线上。这些点的组合可以理解为仿射组合(affine combination,也就是不仅有点,还有点指向的方向),他们的系数之和等于一。 20 | 21 | - 贝塞尔曲线是由一堆点的集合绘制而成。 22 | - 这一堆点是在定义的 P0 ~ PN 的控制之下得出的。 23 | - P0 ~ PN 这些定义的点,第一个点和最后一个点是曲线的开头和结尾。 24 | 25 | ### One Times Bézier curves 26 | 27 | 线性 Bézier curves 是由两个点 P0 和 P1 控制形成的,假设我们有两个点 P0 and P1 分段连接,想象第三个点在这两点之间 P,第三个点 P 定义一个 t 值 这个 t 的 value 就是介于 0 - 1 之间的值 作为百分比 28 | 29 | - 当 t 等于 1 时 说明 P 移动到了 P1 30 | - 当 t 等于 0 时 说明 P 移动到了 P0 31 | - 在中间 t 的 值 是 0 - 1 之间的值 32 | - 这个函数 也叫做线性插值 `lerp` 33 | 34 | 在数学中 你可以把它定义为 35 | 36 | ```ts 37 | P = lerp(P0, P1, t) 38 | P = (1-t)P0 + tP1 39 | 40 | function lerp (P0, P1, T) { 41 | return (1 - T)P0 + TP1 42 | } 43 | ``` 44 | 45 | ![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/7ec12bf2b8524180895e4c2d065fd6f3~tplv-k3u1fbpfcp-watermark.image?) 46 | 47 | ### Two Times Bézier curves 48 | 49 | 如果我们添加一个新的点, 把两条线段的 P 点连接起来, 我们在继续从这条线段增加一个 P 点, t 的 value 也可以发生变化,这样就形成了 二次 贝塞尔 50 | 51 | image 52 | 53 | 继续添加一个点 形成三条线段 三条线段又有各自的 t 点, 连接他们 在连接上的两条线段 增加 两个点, 这时候我们形成了两个插值点, 54 | 从中间再添加一个 插值点这样就会形成一个曲线 55 | 56 | image 57 | 58 | 该曲线就是二次贝塞尔曲线 59 | 60 | ### Three Times Bézier curves 61 | 62 | image 63 | 64 | 如果我们继续添加一个点会发生什么 65 | 66 | image 67 | 68 | 我们重复同样的过程 增加每一条线段的插值点 69 | 70 | ![image](https://user-images.githubusercontent.com/66500121/213360766-486a8c3b-1201-4b69-ab0c-badba6874412.png) 71 | 72 | 最后一个插值点 将会描述三次贝塞尔曲线的路径 73 | 74 | image 75 | 76 | ![image](https://user-images.githubusercontent.com/66500121/213360787-6e9e917c-5914-4e8f-a3c0-e26ad05d97ca.png) 77 | 78 | 这种结构的美妙之处在于无论使用什么轨迹都有效, 所以我们可以改变线段的轨迹,并且遵循相同的规则,总能给我们一条平滑的曲线 79 | 80 | ![image](https://user-images.githubusercontent.com/66500121/213360805-66befeae-3945-49df-97ee-db3a354d57d4.png) 81 | 82 | 我们主要关注三次贝塞尔曲线 这个是最常用的曲线 83 | 84 | image 85 | 86 | 展开所有多项式方法之后 87 | ![image.png](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9dd321bf262345e79f97dcbd92c20024~tplv-k3u1fbpfcp-watermark.image?) 88 | 89 | ```ts 90 | function lerp (P0, P1, T) { 91 | return (1 - T)P0 + TP1 92 | } 93 | 94 | A = lerp(P0, P1, t) 95 | B = lerp(P1, P2, t) 96 | C = lerp(P2, P3, t) 97 | D = lerp(A, B, t) 98 | E = lerp(B, C, t) 99 | P = lerp(D, E, t) 100 | ``` 101 | 102 | ### What is a lerp 103 | 104 | 学习 lerps 函数 https://zhuanlan.zhihu.com/p/114898567 105 | 106 | https://juejin.cn/post/6844903774117429261#comment 107 | 108 | ![image](https://user-images.githubusercontent.com/66500121/213385278-9ad9a2a9-ac19-436a-8e81-84c180277593.png) 109 | 110 | ![image](https://user-images.githubusercontent.com/66500121/213386598-fc754279-4cbf-4acc-8547-a7d455c01ab4.png) 111 | 112 | ![image](https://user-images.githubusercontent.com/66500121/213387516-218adaf9-a9a2-41a4-a52c-69341fe9f2e0.png) 113 | 114 | ![image](https://user-images.githubusercontent.com/66500121/213387914-f7edeadf-8383-45b7-81f1-16b379dd6250.png) 115 | 116 | ![image](https://user-images.githubusercontent.com/66500121/213388342-78e46d24-0f04-4102-a14a-8d12dc90af58.png) 117 | 118 | ![image](https://user-images.githubusercontent.com/66500121/213388395-95dc07db-1467-4fd7-80f2-94dd1381074a.png) 119 | 120 | ![image](https://user-images.githubusercontent.com/66500121/213388533-85b74aaf-e7d3-456e-b39b-32c0d599dde2.png) 121 | 122 | 贝塞尔曲线(Bezier Curve)是一种广泛应用于计算机图形学和计算机辅助设计的数学曲线,由法国数学家 Pierre Bézier 提出。它通过控制点和插值的方式来绘制曲线,可以用来描述各种各样的形状和路径,例如自然曲线、平滑曲线、锐角曲线等。 123 | 124 | 贝塞尔曲线由两个或多个控制点组成,其中第一个和最后一个控制点被称为端点,其他控制点则被称为中间点。曲线的形状和路径则由这些控制点的位置和数量决定。在计算机图形学中,我们通常使用二次贝塞尔曲线和三次贝塞尔曲线来绘制曲线。 125 | 126 | 二次贝塞尔曲线由两个端点和一个控制点组成,可以用如下的数学公式来描述: 127 | 128 | ```bash 129 | B(t) = (1-t)^2 * P0 + 2*t*(1-t) * P1 + t^2 * P2 130 | 131 | ``` 132 | 133 | 其中,P0、P1 和 P2 分别表示起点、控制点和终点,t 表示曲线的参数,取值范围为 0 到 1,表示曲线上的位置。通过不同的控制点和参数值,我们可以绘制出各种不同的曲线形状。 134 | 135 | 三次贝塞尔曲线由两个端点和两个控制点组成,可以用如下的数学公式来描述: 136 | 137 | ```bash 138 | B(t) = (1-t)^3 * P0 + 3*t*(1-t)^2 * P1 + 3*t^2*(1-t) * P2 + t^3 * P3 139 | ``` 140 | 141 | 其中,P0、P1、P2 和 P3 分别表示起点、第一个控制点、第二个控制点和终点,t 表示曲线的参数,取值范围为 0 到 1,表示曲线上的位置。通过不同的控制点和参数值,我们可以绘制出各种不同的曲线形状。 142 | 143 | 总的来说,贝塞尔曲线是一种灵活、可定制化的曲线绘制方式,可以用来绘制各种各样的形状和路径。在计算机图形学和计算机辅助设计中广泛应用,例如在 Adobe Illustrator、Photoshop 等设计软件中就有贝塞尔曲线工具,可以用来绘制各种复杂的形状。 144 | 145 | 当我们使用贝塞尔曲线时,我们需要指定曲线的控制点。控制点可以看作是曲线的“吸引点”,它们决定了曲线的弯曲程度和方向。 146 | 147 | 一条贝塞尔曲线通常由起点、终点和控制点构成。起点和终点分别是曲线的起点和终点,而控制点则是控制曲线的形状。 148 | 149 | 贝塞尔曲线分为一次、二次、三次和高次曲线。一次曲线由两个点组成,没有控制点,只是一条直线。二次曲线由三个点组成,有一个控制点,曲线是一条弯曲的线。三次曲线由四个点组成,有两个控制点,曲线的弯曲程度比二次曲线更大。 150 | 151 | 贝塞尔曲线的形状由控制点的位置和数量决定。当控制点靠近起点或终点时,曲线会变得更平直;当控制点远离起点或终点时,曲线会变得更弯曲。同时,如果有多个控制点,它们的位置和相对位置也会影响曲线的形状。 152 | 153 | 贝塞尔曲线在计算机图形学中广泛应用,可以用于绘制平滑的曲线、动画和变形效果等。 154 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: home 3 | title: Animation Library - Use Animation Library Simple With Easy 4 | footer: MIT Licensed | Copyright © 2023-present ErKelost 5 | --- 6 | 7 | 10 | 11 | 12 | 17 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docs", 3 | "version": "0.0.21", 4 | "private": true, 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vitepress --port 3333", 8 | "build:docs": "vitepress build && node .vitepress/scripts/build-pwa.mjs", 9 | "serve": "vitepress serve", 10 | "preview-https-no-prefetch": "pnpm run build:docs && serve .vitepress/dist" 11 | }, 12 | "dependencies": { 13 | "@vueuse/core": "^9.10.0", 14 | "jiti": "^1.16.1", 15 | "vue": "latest" 16 | }, 17 | "devDependencies": { 18 | "@iconify-json/carbon": "latest", 19 | "@unocss/reset": "^0.48.3", 20 | "@vitejs/plugin-vue": "latest", 21 | "esno": "^0.16.3", 22 | "fast-glob": "^3.2.12", 23 | "fs-extra": "^11.0.0", 24 | "@tresjs/cientos": "^1.7.0", 25 | "@tresjs/core": "^1.7.0", 26 | "https-localhost": "^4.7.1", 27 | "unocss": "^0.49.7", 28 | "three": "^0.149.0", 29 | "gsap": "^3.11.4", 30 | "vite-plugin-glsl": "^1.1.2", 31 | "unplugin-vue-components": "^0.22.12", 32 | "vite": "^4.0.0", 33 | "vite-plugin-pwa": "0.14.1", 34 | "vitepress": "1.0.0-alpha.47", 35 | "workbox-window": "^6.5.4" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /docs/public/_headers: -------------------------------------------------------------------------------- 1 | / 2 | X-Frame-Options: DENY 3 | X-XSS-Protection: 1; mode=block 4 | 5 | /api/ 6 | X-Frame-Options: DENY 7 | X-XSS-Protection: 1; mode=block 8 | 9 | /config/ 10 | X-Frame-Options: DENY 11 | X-XSS-Protection: 1; mode=block 12 | 13 | /guide/ 14 | X-Frame-Options: DENY 15 | X-XSS-Protection: 1; mode=block 16 | 17 | /*.html 18 | X-Frame-Options: DENY 19 | X-XSS-Protection: 1; mode=block 20 | 21 | /* 22 | X-Content-Type-Options: nosniff 23 | Referrer-Policy: no-referrer 24 | Strict-Transport-Security: max-age=31536000; includeSubDomains 25 | 26 | /assets/* 27 | cache-control: max-age=31536000 28 | cache-control: immutable 29 | -------------------------------------------------------------------------------- /docs/public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variesd/varies/56b804007edde3e27519c38e2a38aaeac1ad5f78/docs/public/apple-touch-icon.png -------------------------------------------------------------------------------- /docs/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variesd/varies/56b804007edde3e27519c38e2a38aaeac1ad5f78/docs/public/favicon.ico -------------------------------------------------------------------------------- /docs/public/logo-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variesd/varies/56b804007edde3e27519c38e2a38aaeac1ad5f78/docs/public/logo-light.png -------------------------------------------------------------------------------- /docs/public/logo-night.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variesd/varies/56b804007edde3e27519c38e2a38aaeac1ad5f78/docs/public/logo-night.png -------------------------------------------------------------------------------- /docs/public/logo-shadow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /docs/public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variesd/varies/56b804007edde3e27519c38e2a38aaeac1ad5f78/docs/public/logo.png -------------------------------------------------------------------------------- /docs/public/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /docs/public/logo66.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variesd/varies/56b804007edde3e27519c38e2a38aaeac1ad5f78/docs/public/logo66.png -------------------------------------------------------------------------------- /docs/public/og-original.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variesd/varies/56b804007edde3e27519c38e2a38aaeac1ad5f78/docs/public/og-original.png -------------------------------------------------------------------------------- /docs/public/og.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variesd/varies/56b804007edde3e27519c38e2a38aaeac1ad5f78/docs/public/og.png -------------------------------------------------------------------------------- /docs/public/pwa-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variesd/varies/56b804007edde3e27519c38e2a38aaeac1ad5f78/docs/public/pwa-192x192.png -------------------------------------------------------------------------------- /docs/public/pwa-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variesd/varies/56b804007edde3e27519c38e2a38aaeac1ad5f78/docs/public/pwa-512x512.png -------------------------------------------------------------------------------- /docs/public/social.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variesd/varies/56b804007edde3e27519c38e2a38aaeac1ad5f78/docs/public/social.png -------------------------------------------------------------------------------- /docs/public/sponsors/fincliplogo_black_svg.svg: -------------------------------------------------------------------------------- 1 | 五行代码,让你的APP拥有小程序运行能力 -------------------------------------------------------------------------------- /docs/public/sponsors/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/public/sponsors/vuejobs.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/public/sponsors/vuetify-logo-dark-text.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/public/sponsors/vuetify-logo-light-text.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/run-typedoc.js: -------------------------------------------------------------------------------- 1 | const { createTypeDocApp } = require('./typedoc-markdown') 2 | const path = require('path') 3 | 4 | createTypeDocApp({ 5 | name: 'API Documentation', 6 | tsconfig: path.resolve(__dirname, './typedoc.tsconfig.json'), 7 | // entryPointStrategy: 'packages', 8 | githubPages: false, 9 | disableSources: true, 10 | entryPoints: [ 11 | path.resolve(__dirname, '../pinia/src/index.ts'), 12 | path.resolve(__dirname, '../testing/src/index.ts'), 13 | path.resolve(__dirname, '../nuxt/src/module.ts') 14 | ] 15 | }).build() 16 | -------------------------------------------------------------------------------- /docs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "module": "esnext", 5 | "target": "esnext", 6 | "lib": ["DOM", "ESNext"], 7 | "strict": true, 8 | "jsx": "preserve", 9 | "esModuleInterop": true, 10 | "skipLibCheck": true, 11 | "moduleResolution": "node", 12 | "resolveJsonModule": true, 13 | "noUnusedLocals": true, 14 | "strictNullChecks": true, 15 | "forceConsistentCasingInFileNames": true, 16 | "types": [ 17 | "vite/client", 18 | "vite-plugin-pwa/client", 19 | "vitepress" 20 | ], 21 | "paths": { 22 | "~/*": ["src/*"] 23 | } 24 | }, 25 | "include": [ 26 | "./*.ts", 27 | "./.vitepress/**/*.ts", 28 | "./.vitepress/**/*.vue" 29 | ], 30 | "exclude": ["dist", "node_modules"] 31 | } 32 | -------------------------------------------------------------------------------- /docs/typedoc-markdown.js: -------------------------------------------------------------------------------- 1 | const _fs = require('fs') 2 | const path = require('path') 3 | const TypeDoc = require('typedoc') 4 | const { PageEvent } = TypeDoc 5 | const { 6 | prependYAML 7 | } = require('typedoc-plugin-markdown/dist/utils/front-matter') 8 | 9 | const fs = _fs.promises 10 | 11 | const DEFAULT_OPTIONS = { 12 | // disableOutputCheck: true, 13 | cleanOutputDir: true, 14 | excludeInternal: true, 15 | readme: 'none', 16 | out: path.resolve(__dirname, './api'), 17 | entryDocument: 'index.md', 18 | hideBreadcrumbs: false, 19 | hideInPageTOC: true 20 | } 21 | 22 | /** 23 | * 24 | * @param {Partial} config 25 | */ 26 | exports.createTypeDocApp = function createTypeDocApp(config = {}) { 27 | const options = { 28 | ...DEFAULT_OPTIONS, 29 | ...config 30 | } 31 | 32 | const app = new TypeDoc.Application() 33 | 34 | // If you want TypeDoc to load tsconfig.json / typedoc.json files 35 | app.options.addReader(new TypeDoc.TSConfigReader()) 36 | // app.options.addReader(new TypeDoc.TypeDocReader()) 37 | 38 | /** @type {'build' | 'serve'} */ 39 | let targetMode = 'build' 40 | 41 | app.renderer.on( 42 | PageEvent.END, 43 | /** 44 | * 45 | * @param {import('typedoc/dist/lib/output/events').PageEvent} page 46 | */ 47 | (page) => { 48 | if (page.url !== 'index.md' && page.contents) { 49 | page.contents = prependYAML(page.contents, { 50 | sidebar: 'auto', 51 | // TODO: figure out a way to point to the source files? 52 | editLinks: false, 53 | sidebarDepth: 3 54 | }) 55 | } 56 | } 57 | ) 58 | 59 | async function serve() { 60 | app.bootstrap(options) 61 | app.convertAndWatch(handleProject) 62 | } 63 | 64 | async function build() { 65 | if ( 66 | (await exists(options.out)) && 67 | (await fs.stat(options.out)).isDirectory() 68 | ) { 69 | await fs.rm(options.out, { recursive: true }) 70 | } 71 | app.bootstrap(options) 72 | const project = app.convert() 73 | return handleProject(project) 74 | } 75 | 76 | /** 77 | * 78 | * @param {import('typedoc').ProjectReflection} project 79 | */ 80 | async function handleProject(project) { 81 | if (project) { 82 | // Rendered docs 83 | try { 84 | await app.generateDocs(project, options.out) 85 | app.logger.info(`generated at ${options.out}.`) 86 | } catch (error) { 87 | app.logger.error(error) 88 | } 89 | } else { 90 | app.logger.error('No project') 91 | } 92 | } 93 | 94 | return { 95 | build, 96 | serve, 97 | /** 98 | * 99 | * @param {'build' | 'serve'} command 100 | */ 101 | setTargetMode(command) { 102 | targetMode = command 103 | } 104 | } 105 | } 106 | 107 | async function exists(path) { 108 | try { 109 | await fs.access(path) 110 | return true 111 | } catch { 112 | return false 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /docs/typedoc.tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["../pinia/src/global.d.ts", "../*/src/**/*.ts"], 3 | "exclude": [ 4 | "../test-vue-2", 5 | "../pinia/__tests__/test-utils.ts", 6 | "../pinia/test-dts", 7 | "../*/__tests__/**/*.ts", 8 | "../*/src/*.spec.ts", 9 | "../nuxt/playground", 10 | "../nuxt/src/runtime", 11 | "**/*.spec.ts" 12 | ], 13 | "compilerOptions": { 14 | "baseUrl": ".", 15 | "rootDir": "..", 16 | "outDir": "dist", 17 | "sourceMap": false, 18 | "noEmit": true, 19 | "paths": { 20 | "@pinia/*": ["../*/src"], 21 | "pinia": ["../pinia/src"] 22 | }, 23 | 24 | "target": "esnext", 25 | "module": "esnext", 26 | "moduleResolution": "node", 27 | "allowJs": false, 28 | "skipLibCheck": true, 29 | 30 | "noUnusedLocals": true, 31 | "strictNullChecks": true, 32 | "noImplicitAny": true, 33 | "noImplicitThis": true, 34 | "noImplicitReturns": false, 35 | "strict": true, 36 | "isolatedModules": true, 37 | 38 | "experimentalDecorators": true, 39 | "resolveJsonModule": true, 40 | "esModuleInterop": true, 41 | "removeComments": false, 42 | "jsx": "preserve", 43 | "lib": ["esnext", "dom"], 44 | "types": ["vitest", "node", "vite/client"] 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /docs/vite-typedoc-plugin.ts: -------------------------------------------------------------------------------- 1 | import { Plugin } from 'vite' 2 | import _fs from 'fs' 3 | import { TypeDocOptions } from 'typedoc' 4 | import { createTypeDocApp } from './typedoc-markdown' 5 | 6 | export default function TypeDocPlugin( 7 | config: Partial = {} 8 | ): Plugin { 9 | const { serve, setTargetMode } = createTypeDocApp(config) 10 | setTargetMode('serve') 11 | 12 | return { 13 | name: 'typedoc', 14 | apply: 'serve', 15 | buildStart() { 16 | return serve() 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /docs/vite.config.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | import type { Plugin } from 'vite' 3 | import { defineConfig } from 'vite' 4 | import Components from 'unplugin-vue-components/vite' 5 | import Unocss from 'unocss/vite' 6 | import glsl from 'vite-plugin-glsl' 7 | import { presetAttributify, presetIcons, presetUno } from 'unocss' 8 | import { resolve } from 'pathe' 9 | import { VitePWA } from 'vite-plugin-pwa' 10 | import fg from 'fast-glob' 11 | import { 12 | githubusercontentRegex, 13 | pwaFontStylesRegex, 14 | pwaFontsRegex, 15 | vitestDescription, 16 | vitestName, 17 | vitestShortName 18 | } from './.vitepress/meta' 19 | 20 | export default defineConfig({ 21 | ssr: { 22 | format: 'cjs' 23 | }, 24 | legacy: { 25 | buildSsrCjsExternalHeuristics: true 26 | }, 27 | optimizeDeps: { 28 | // vitepress is aliased with replacement `join(DIST_CLIENT_PATH, '/index')` 29 | // This needs to be excluded from optimization 30 | exclude: ['vitepress'] 31 | }, 32 | plugins: [ 33 | // TODO remove cast when moved to Vite 3 34 | Components({ 35 | include: [/\.vue/, /\.md/], 36 | dirs: '.vitepress/components', 37 | dts: '.vitepress/components.d.ts' 38 | }) as Plugin, 39 | Unocss({ 40 | shortcuts: [ 41 | [ 42 | 'btn', 43 | 'px-4 py-1 rounded inline-flex justify-center gap-2 text-white leading-30px children:mya !no-underline cursor-pointer disabled:cursor-default disabled:bg-gray-600 disabled:opacity-50' 44 | ] 45 | ], 46 | presets: [ 47 | presetUno({ 48 | dark: 'media' 49 | }), 50 | presetAttributify(), 51 | presetIcons({ 52 | scale: 1.2 53 | }) 54 | ] 55 | }) as unknown as Plugin, 56 | IncludesPlugin(), 57 | glsl(), 58 | VitePWA({ 59 | outDir: '.vitepress/dist', 60 | registerType: 'autoUpdate', 61 | // include all static assets under public/ 62 | includeAssets: fg.sync('**/*.{png,svg,ico,txt}', { 63 | cwd: resolve(__dirname, 'public') 64 | }), 65 | manifest: { 66 | id: '/', 67 | name: vitestName, 68 | short_name: vitestShortName, 69 | description: vitestDescription, 70 | theme_color: '#ffffff', 71 | icons: [ 72 | { 73 | src: 'pwa-192x192.png', 74 | sizes: '192x192', 75 | type: 'image/png' 76 | }, 77 | { 78 | src: 'pwa-512x512.png', 79 | sizes: '512x512', 80 | type: 'image/png' 81 | }, 82 | { 83 | src: 'logo-light.png', 84 | sizes: '165x165', 85 | type: 'image/svg', 86 | purpose: 'any maskable' 87 | } 88 | ] 89 | }, 90 | workbox: { 91 | navigateFallbackDenylist: [/^\/new$/], 92 | globPatterns: ['**/*.{css,js,html,woff2}'], 93 | runtimeCaching: [ 94 | { 95 | urlPattern: pwaFontsRegex, 96 | handler: 'CacheFirst', 97 | options: { 98 | cacheName: 'google-fonts-cache', 99 | expiration: { 100 | maxEntries: 10, 101 | maxAgeSeconds: 60 * 60 * 24 * 365 // <== 365 days 102 | }, 103 | cacheableResponse: { 104 | statuses: [0, 200] 105 | } 106 | } 107 | }, 108 | { 109 | urlPattern: pwaFontStylesRegex, 110 | handler: 'CacheFirst', 111 | options: { 112 | cacheName: 'gstatic-fonts-cache', 113 | expiration: { 114 | maxEntries: 10, 115 | maxAgeSeconds: 60 * 60 * 24 * 365 // <== 365 days 116 | }, 117 | cacheableResponse: { 118 | statuses: [0, 200] 119 | } 120 | } 121 | }, 122 | { 123 | urlPattern: githubusercontentRegex, 124 | handler: 'CacheFirst', 125 | options: { 126 | cacheName: 'githubusercontent-images-cache', 127 | expiration: { 128 | maxEntries: 10, 129 | maxAgeSeconds: 60 * 60 * 24 * 365 // <== 365 days 130 | }, 131 | cacheableResponse: { 132 | statuses: [0, 200] 133 | } 134 | } 135 | } 136 | ] 137 | } 138 | }) 139 | ] 140 | }) 141 | 142 | function IncludesPlugin(): Plugin { 143 | return { 144 | name: 'include-plugin', 145 | enforce: 'pre', 146 | transform(code, id) { 147 | let changed = false 148 | code = code.replace(/\[@@include\]\((.*?)\)/, (_, url) => { 149 | changed = true 150 | const full = resolve(id, url) 151 | return fs.readFileSync(full, 'utf-8') 152 | }) 153 | if (changed) return code 154 | } 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /docs/zh/getting-started.md: -------------------------------------------------------------------------------- 1 | ## 安装 {#installation} 2 | 3 | 用你喜欢的包管理器安装 `pinia`: 4 | 5 | ```bash 6 | yarn add pinia 7 | # 或者使用 npm 8 | npm install pinia 9 | ``` 10 | 11 | :::tip 12 | 如果你的应用使用的是 Vue 2,你还需要安装组合式 API 包:`@vue/composition-api`。如果你使用的是 Nuxt,你应该参考[这篇指南](/ssr/nuxt.md)。 13 | ::: 14 | 15 | 如果你正在使用 Vue CLI,你可以试试这个[**非官方插件**](https://github.com/wobsoriano/vue-cli-plugin-pinia)。 16 | 17 | 创建一个 pinia 实例(根 store)并将其传递给应用: 18 | 19 | ```js {2,5-6,8} 20 | import { createApp } from 'vue' 21 | import { createPinia } from 'pinia' 22 | import App from './App.vue' 23 | 24 | const pinia = createPinia() 25 | const app = createApp(App) 26 | 27 | app.use(pinia) 28 | app.mount('#app') 29 | ``` 30 | 31 | 如果你使用的是 Vue 2,你还需要安装一个插件,并在应用的根部注入创建的 `pinia`: 32 | 33 | ```js {1,3-4,12} 34 | import { createPinia, PiniaVuePlugin } from 'pinia' 35 | 36 | Vue.use(PiniaVuePlugin) 37 | const pinia = createPinia() 38 | 39 | new Vue({ 40 | el: '#app', 41 | // 其他配置... 42 | // ... 43 | // 请注意,同一个`pinia'实例 44 | // 可以在同一个页面的多个 Vue 应用中使用。 45 | pinia 46 | }) 47 | ``` 48 | 49 | 这样才能提供 devtools 的支持。在 Vue 3 中,一些功能仍然不被支持,如 time traveling 和编辑,这是因为 vue-devtools 还没有相关的 API,但 devtools 也有很多针对 Vue 3 的专属功能,而且就开发者的体验来说,Vue 3 整体上要好得多。在 Vue 2 中,Pinia 使用的是 Vuex 的现有接口(因此不能与 Vuex 一起使用)。 50 | 51 | ## Store 是什么?{#what-is-a-store} 52 | 53 | Store (如 Pinia) 是一个保存状态和业务逻辑的实体,它并不与你的组件树绑定。换句话说,**它承载着全局状态**。它有点像一个永远存在的组件,每个组件都可以读取和写入它。它有**三个概念**,[state](./core-concepts/state.md)、[getter](./core-concepts/getters.md) 和 [action](./core-concepts/actions.md),我们可以假设这些概念相当于组件中的 `data`、 `computed` 和 `methods`。 54 | 55 | ## 应该在什么时候使用 Store? {#when-should-i-use-a-store} 56 | 57 | 一个 Store 应该包含可以在整个应用中访问的数据。这包括在许多地方使用的数据,例如显示在导航栏中的用户信息,以及需要通过页面保存的数据,例如一个非常复杂的多步骤表单。 58 | 59 | 另一方面,你应该避免在 Store 中引入那些原本可以在组件中保存的本地数据,例如,一个元素在页面中的可见性。 60 | 61 | 并非所有的应用都需要访问全局状态,但如果你的应用确实需要一个全局状态,那 Pinia 将使你的开发过程更轻松。 62 | -------------------------------------------------------------------------------- /docs/zh/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | home: true 3 | heroImage: /logo.png 4 | actionText: 开始使用 5 | actionLink: /zh/introduction.html 6 | 7 | altActionText: Demo 演示 8 | altActionLink: https://stackblitz.com/github/piniajs/example-vue-3-vite 9 | 10 | features: 11 | - title: 💡 所见即所得 12 | details: 与组件类似的 Store。其 API 的设计旨在让你编写出更易组织的 store。 13 | - title: 🔑 类型安全 14 | details: 类型可自动推断,即使在 JavaScript 中亦可为你提供自动补全功能! 15 | - title: ⚙️ 开发工具支持 16 | details: 不管是 Vue 2 还是 Vue 3,支持 Vue devtools 钩子的 Pinia 都能给你更好的开发体验。 17 | - title: 🔌 可扩展性 18 | details: 可通过事务、同步本地存储等方式扩展 Pinia,以响应 store 的变更。 19 | - title: 🏗 模块化设计 20 | details: 可构建多个 Store 并允许你的打包工具自动拆分它们。 21 | - title: 📦 极致轻量化 22 | details: Pinia 大小只有 1kb 左右,你甚至可能忘记它的存在! 23 | footer: MIT Licensed | Copyright © 2019-present Eduardo San Martin Morote 24 | --- 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 38 | -------------------------------------------------------------------------------- /docs/zh/introduction.md: -------------------------------------------------------------------------------- 1 | # 简介 {#introduction} 2 | 3 | 7 | 8 | Pinia [起始](https://github.com/vuejs/pinia/commit/06aeef54e2cad66696063c62829dac74e15fd19e)于 2019 年 11 月左右的一次实验,其目的是设计一个拥有[组合式 API](https://github.com/vuejs/composition-api) 的 Vue 状态管理库。从那时起,我们就倾向于同时支持 Vue 2 和 Vue 3,并且不强制要求开发者使用组合式 API,我们的初心至今没有改变。除了**安装**和 **SSR** 两章之外,其余章节中提到的 API 均支持 Vue 2 和 Vue 3。虽然本文档主要是面向 Vue 3 的用户,但在必要时会标注出 Vue 2 的内容,因此 Vue 2 和 Vue 3 的用户都可以阅读本文档。 9 | 10 | ## 为什么你应该使用 Pinia?{#why-should-i-use-pinia} 11 | 12 | Pinia 是 Vue 的专属状态管理库,它允许你跨组件或页面共享状态。如果你熟悉组合式 API 的话,你可能会认为可以通过一行简单的 `export const state = reactive({})` 来共享一个全局状态。对于单页应用来说确实可以,但如果应用在服务器端渲染,这可能会使你的应用暴露出一些安全漏洞。 而如果使用 Pinia,即使在小型单页应用中,你也可以获得如下功能: 13 | 14 | - Devtools 支持 15 | - 追踪 actions、mutations 的时间线 16 | - 在组件中展示它们所用到的 Store 17 | - 让调试更容易的 Time travel 18 | - 热更新 19 | - 不必重载页面即可修改 Store 20 | - 开发时可保持当前的 State 21 | - 插件:可通过插件扩展 Pinia 功能 22 | - 为 JS 开发者提供适当的 TypeScript 支持以及**自动补全**功能。 23 | - 支持服务端渲染 24 | 25 | ## 基础示例 {#basic-example} 26 | 27 | 下面就是 pinia API 的基本用法 (为继续阅读本简介请确保你已阅读过了[开始](./getting-started.md)章节)。你可以先创建一个 Store: 28 | 29 | ```js 30 | // stores/counter.js 31 | import { defineStore } from 'pinia' 32 | 33 | export const useCounterStore = defineStore('counter', { 34 | state: () => { 35 | return { count: 0 } 36 | }, 37 | // 也可以这样定义 38 | // state: () => ({ count: 0 }) 39 | actions: { 40 | increment() { 41 | this.count++ 42 | } 43 | } 44 | }) 45 | ``` 46 | 47 | 然后你就可以在一个组件中使用该 store 了: 48 | 49 | ```js 50 | import { useCounterStore } from '@/stores/counter' 51 | 52 | export default { 53 | setup() { 54 | const counter = useCounterStore() 55 | 56 | counter.count++ 57 | // 带有自动补全 ✨ 58 | counter.$patch({ count: counter.count + 1 }) 59 | // 或者使用 action 代替 60 | counter.increment() 61 | } 62 | } 63 | ``` 64 | 65 | 为实现更多高级用法,你甚至可以使用一个函数(与组件 `setup()` 类似)来定义一个 Store: 66 | 67 | ```js 68 | export const useCounterStore = defineStore('counter', () => { 69 | const count = ref(0) 70 | function increment() { 71 | count.value++ 72 | } 73 | 74 | return { count, increment } 75 | }) 76 | ``` 77 | 78 | 如果你还不熟悉 setup() 函数和组合式 API,别担心,Pinia 也提供了一组类似 Vuex 的 [映射 state 的辅助函数](https://vuex.vuejs.org/zh/guide/state.html#mapstate-辅助函数)。你可以用和之前一样的方式来定义 Store,然后通过 `mapStores()`、`mapState()` 或 `mapActions()` 访问: 79 | 80 | ```js {22,24,28} 81 | const useCounterStore = defineStore('counter', { 82 | state: () => ({ count: 0 }), 83 | getters: { 84 | double: (state) => state.count * 2, 85 | }, 86 | actions: { 87 | increment() { 88 | this.count++ 89 | }, 90 | }, 91 | }) 92 | 93 | const useUserStore = defineStore('user', { 94 | // ... 95 | }) 96 | 97 | export default { 98 | computed: { 99 | // 其他计算属性 100 | // ... 101 | // 允许访问 this.counterStore 和 this.userStore 102 | ...mapStores(useCounterStore, useUserStore) 103 | // 允许读取 this.count 和 this.double 104 | ...mapState(useCounterStore, ['count', 'double']), 105 | }, 106 | methods: { 107 | // 允许读取 this.increment() 108 | ...mapActions(useCounterStore, ['increment']), 109 | }, 110 | } 111 | ``` 112 | 113 | 你将会在核心概念部分了解到更多关于每个**映射辅助函数**的信息。 114 | 115 | ## 为什么取名 _Pinia_?{#why-pinia} 116 | 117 | Pinia (发音为 `/piːnjʌ/`,类似英文中的 “peenya”) 是最接近有效包名 piña (西班牙语中的 _pineapple_,即“菠萝”) 的词。 菠萝花实际上是一组各自独立的花朵,它们结合在一起,由此形成一个多重的水果。 与 Store 类似,每一个都是独立诞生的,但最终它们都是相互联系的。 它(菠萝)也是一种原产于南美洲的美味热带水果。 118 | 119 | ## 更真实的示例 {#a-more-realistic-example} 120 | 121 | 这是一个更完整的 Pinia API 示例,在 JavaScript 中也使用了类型提示。对于某些开发者来说,可能足以在不进一步阅读的情况下直接开始阅读本节内容,但我们仍然建议你先继续阅读文档的其余部分,甚至跳过此示例,在阅读完所有**核心概念**之后再回来。 122 | 123 | ```js 124 | import { defineStore } from 'pinia' 125 | 126 | export const useTodos = defineStore('todos', { 127 | state: () => ({ 128 | /** @type {{ text: string, id: number, isFinished: boolean }[]} */ 129 | todos: [], 130 | /** @type {'all' | 'finished' | 'unfinished'} */ 131 | filter: 'all', 132 | // 类型将自动推断为 number 133 | nextId: 0 134 | }), 135 | getters: { 136 | finishedTodos(state) { 137 | // 自动补全! ✨ 138 | return state.todos.filter((todo) => todo.isFinished) 139 | }, 140 | unfinishedTodos(state) { 141 | return state.todos.filter((todo) => !todo.isFinished) 142 | }, 143 | /** 144 | * @returns {{ text: string, id: number, isFinished: boolean }[]} 145 | */ 146 | filteredTodos(state) { 147 | if (this.filter === 'finished') { 148 | // 调用其他带有自动补全的 getters ✨ 149 | return this.finishedTodos 150 | } else if (this.filter === 'unfinished') { 151 | return this.unfinishedTodos 152 | } 153 | return this.todos 154 | } 155 | }, 156 | actions: { 157 | // 接受任何数量的参数,返回一个 Promise 或不返回 158 | addTodo(text) { 159 | // 你可以直接变更该状态 160 | this.todos.push({ text, id: this.nextId++, isFinished: false }) 161 | } 162 | } 163 | }) 164 | ``` 165 | 166 | ## 对比 Vuex {#comparison-with-vuex} 167 | 168 | Pinia 起源于一次探索 Vuex 下一个迭代的实验,因此结合了 Vuex 5 核心团队讨论中的许多想法。最后,我们意识到 Pinia 已经实现了我们在 Vuex 5 中想要的大部分功能,所以决定将其作为新的推荐方案来代替 Vuex。 169 | 170 | 与 Vuex 相比,Pinia 不仅提供了一个更简单的 API,也提供了符合组合式 API 风格的 API,最重要的是,搭配 TypeScript 一起使用时有非常可靠的类型推断支持。 171 | 172 | ### RFC {#rfcs} 173 | 174 | 最初,Pinia 没有经过任何 RFC 的流程。我基于自己开发应用的经验,同时通过阅读其他人的代码,为使用 Pinia 的用户工作,以及在 Discord 上回答问题等方式验证了一些想法。 175 | 这些经历使我产出了这样一个可用的解决方案,并适应了各种场景和应用规模。我会一直在保持其核心 API 不变的情况下发布新版本,同时不断优化本库。 176 | 177 | 现在 Pinia 已经成为推荐的状态管理解决方案,它和 Vue 生态系统中的其他核心库一样,都要经过 RFC 流程,它的 API 也已经进入稳定状态。 178 | 179 | ### 对比 Vuex 3.x/4.x {#comparison-with-vuex-3-x-4-x} 180 | 181 | > Vuex 3.x 只适配 Vue 2,而 Vuex 4.x 是适配 Vue 3 的。 182 | 183 | Pinia API 与 Vuex(<=4) 也有很多不同,即: 184 | 185 | - _mutation_ 已被弃用。它们经常被认为是**极其冗余的**。它们初衷是带来 devtools 的集成方案,但这已不再是一个问题了。 186 | - 无需要创建自定义的复杂包装器来支持 TypeScript,一切都可标注类型,API 的设计方式是尽可能地利用 TS 类型推理。 187 | - 无过多的魔法字符串注入,只需要导入函数并调用它们,然后享受自动补全的乐趣就好。 188 | - 无需要动态添加 Store,它们默认都是动态的,甚至你可能都不会注意到这点。注意,你仍然可以在任何时候手动使用一个 Store 来注册它,但因为它是自动的,所以你不需要担心它。 189 | - 不再有嵌套结构的**模块**。你仍然可以通过导入和使用另一个 Store 来隐含地嵌套 stores 空间。虽然 Pinia 从设计上提供的是一个扁平的结构,但仍然能够在 Store 之间进行交叉组合。**你甚至可以让 Stores 有循环依赖关系**。 190 | - 不再有**可命名的模块**。考虑到 Store 的扁平架构,Store 的命名取决于它们的定义方式,你甚至可以说所有 Store 都应该命名。 191 | 192 | 关于如何将现有 Vuex(<=4) 的项目转化为使用 Pinia 的更多详细说明,请参阅 [Vuex 迁移指南](./cookbook/migration-vuex.md)。 193 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build.environment] 2 | NODE_VERSION = "16" 3 | NPM_FLAGS = "--version" # prevent Netlify npm install 4 | 5 | [build] 6 | publish = "docs/.vitepress/dist" 7 | command = "npx pnpm install --no-frozen-lockfile --store=node_modules/.pnpm-store && npm run build:docs" 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "variesd", 3 | "version": "0.0.21", 4 | "author": "erkelost", 5 | "scripts": { 6 | "dev": "turbo run dev", 7 | "bootstrap": "pnpm install && pnpm build", 8 | "build": "turbo run build --filter=\"@variesd/*\"", 9 | "build:watch": "turbo run build:watch", 10 | "doc": "turbo run dev --filter docs --no-daemon", 11 | "build:docs": "turbo run build:docs --filter docs", 12 | "clean": "rimraf 'packages/*/{lib,node_modules}' && rimraf node_modules", 13 | "play": "pnpm dev --filter playground --no-daemon", 14 | "lint": "turbo run lint", 15 | "format": "prettier --write \"**/*.{ts,tsx,md,vue,js}\"", 16 | "eslint": "eslint . --ext .ts,.vue,.js,.tsx", 17 | "prepare": "husky install", 18 | "preinstall": "npx only-allow pnpm", 19 | "prepublishOnly": "npm run build", 20 | "release": "bumpp packages/*/package.json && pnpm publish -r", 21 | "test": "vitest" 22 | }, 23 | "devDependencies": { 24 | "@commitlint/cli": "^17.4.4", 25 | "@commitlint/config-conventional": "^17.4.4", 26 | "@types/fs-extra": "^11.0.0", 27 | "@types/js-yaml": "^4.0.5", 28 | "@types/node": "^18.14.1", 29 | "@types/prettier": "^2.7.2", 30 | "bumpp": "^8.2.1", 31 | "commitlint": "^17.4.4", 32 | "consola": "^2.15.3", 33 | "cross-env": "^7.0.3", 34 | "esbuild": "^0.14.54", 35 | "eslint": "^8.34.0", 36 | "eslint-config-relaxed-ts": "^2.0.13", 37 | "esno": "^0.16.3", 38 | "export-size": "^0.5.2", 39 | "fast-glob": "^3.2.12", 40 | "firebase": "^9.17.1", 41 | "fs-extra": "^11.1.0", 42 | "husky": "^8.0.3", 43 | "js-yaml": "^4.1.0", 44 | "lint-staged": "^13.1.2", 45 | "pnpm": "^7.27.1", 46 | "prettier": "latest", 47 | "rimraf": "^3.0.2", 48 | "rollup": "^3.17.2", 49 | "tsup": "^6.6.3", 50 | "turbo": "latest", 51 | "typescript": "^4.9.5", 52 | "vitest": "^0.26.3" 53 | }, 54 | "engines": { 55 | "npm": ">=7.0.0", 56 | "node": ">=14.0.0" 57 | }, 58 | "pnpm": { 59 | "overrides": { 60 | "vue-demi": "0.13.11" 61 | } 62 | }, 63 | "packageManager": "pnpm@7.2.1", 64 | "files": [] 65 | } 66 | -------------------------------------------------------------------------------- /packages/animated/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@variesd/animated", 3 | "version": "0.0.21", 4 | "description": "", 5 | "main": "dist/index.js", 6 | "module": "dist/index.mjs", 7 | "types": "dist/index.d.ts", 8 | "publishConfig": { 9 | "access": "public", 10 | "registry": "https://registry.npmjs.org/" 11 | }, 12 | "scripts": { 13 | "test": "echo \"Error: no test specified\" && exit 1", 14 | "build": "tsup", 15 | "build:watch": "tsup --watch" 16 | }, 17 | "keywords": [], 18 | "author": "", 19 | "license": "ISC" 20 | } 21 | -------------------------------------------------------------------------------- /packages/animated/src/easing.ts: -------------------------------------------------------------------------------- 1 | // pow 返回 基数的指数次幂 t ** power 2 | const pow = Math.pow 3 | const sqrt = Math.sqrt 4 | 5 | export const easeOutCubic = function (x: number): number { 6 | return 1 - pow(1 - x, 3) 7 | } 8 | export const linear = (x: number): number => x 9 | export const easeOutExpo = function (x: number): number { 10 | return x === 1 ? 1 : 1 - pow(2, -10 * x) 11 | } 12 | 13 | export const easeInOutExpo = function (x: number): number { 14 | return x === 0 15 | ? 0 16 | : x === 1 17 | ? 1 18 | : x < 0.5 19 | ? pow(2, 20 * x - 10) / 2 20 | : (2 - pow(2, -20 * x + 10)) / 2 21 | } 22 | export const easeInExpo = function (x: number): number { 23 | return x === 0 ? 0 : pow(2, 10 * x - 10) 24 | } 25 | export const easeInOutCirc = function (x: number): number { 26 | return x < 0.5 27 | ? (1 - sqrt(1 - pow(2 * x, 2))) / 2 28 | : (sqrt(1 - pow(-2 * x + 2, 2)) + 1) / 2 29 | } 30 | -------------------------------------------------------------------------------- /packages/animated/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './easing' 2 | -------------------------------------------------------------------------------- /packages/animated/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2017", 4 | "module": "esnext", 5 | "moduleResolution": "node", 6 | "strict": true, 7 | "declaration": true, 8 | "noUnusedLocals": true, 9 | "esModuleInterop": true, 10 | "outDir": "dist", 11 | "lib": [ 12 | "ESNext" 13 | ], 14 | "sourceMap": false, 15 | "noEmitOnError": true, 16 | "noImplicitAny": false, 17 | "resolveJsonModule": true 18 | }, 19 | "exclude": [ 20 | "node_modules", 21 | "playground", 22 | "dist" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /packages/animated/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'tsup' 2 | 3 | export default defineConfig({ 4 | // entry: ['./src/*.ts'], 5 | entry: ['./src/index.ts'], 6 | format: ['esm', 'cjs'], 7 | target: 'node14', 8 | clean: true, 9 | dts: true, 10 | splitting: true, 11 | shims: true 12 | }) 13 | -------------------------------------------------------------------------------- /packages/config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "config", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC" 12 | } 13 | -------------------------------------------------------------------------------- /packages/core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@variesd/core", 3 | "version": "0.0.21", 4 | "description": "", 5 | "main": "dist/index.js", 6 | "module": "dist/index.mjs", 7 | "types": "dist/index.d.ts", 8 | "publishConfig": { 9 | "access": "public", 10 | "registry": "https://registry.npmjs.org/" 11 | }, 12 | "scripts": { 13 | "test": "echo \"Error: no test specified\" && exit 1", 14 | "build": "tsup", 15 | "build:watch": "tsup --watch" 16 | }, 17 | "dependencies": { 18 | "@variesd/animated": "workspace:*" 19 | }, 20 | "keywords": [], 21 | "author": "", 22 | "license": "MIT" 23 | } 24 | -------------------------------------------------------------------------------- /packages/core/src/component.ts: -------------------------------------------------------------------------------- 1 | // export function useAnimationFrame( 2 | // fn: (timestamp: number) => void, 3 | // delta = 0, 4 | // autoStop = false 5 | // ): () => void { 6 | // let start: number 7 | // let work = true 8 | // const animationFrame = 9 | // window.requestAnimationFrame || 10 | // window.webkitRequestAnimationFrame || 11 | // window.mozRequestAnimationFrame || 12 | // window.msRequestAnimationFrame || 13 | // ((fn) => setTimeout(fn, 1000 / 60)) 14 | // const cancelAnimation = 15 | // window.cancelAnimationFrame || 16 | // window.webkitCancelAnimationFrame || 17 | // window.mozCancelAnimationFrame || 18 | // window.oCancelAnimationFrame || 19 | // window.msCancelAnimationFrame || 20 | // clearTimeout 21 | // const animationId = animationFrame(function myFrame( 22 | // timestamp: number = Date.now() 23 | // ) { 24 | // if (!work) return 25 | // // eslint-disable-next-line no-constant-binary-expression 26 | // if (typeof start === undefined) { 27 | // start = timestamp 28 | // } else if (timestamp - start > delta) { 29 | // fn?.(timestamp) 30 | // start = timestamp 31 | // if (autoStop) stop() 32 | // } 33 | // animationFrame(myFrame) 34 | // }) 35 | // function stop() { 36 | // work = false 37 | // cancelAnimation(animationId) 38 | // } 39 | // return stop 40 | // } 41 | import Spring from './spring-test1' 42 | 43 | export { Spring } 44 | -------------------------------------------------------------------------------- /packages/core/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './spring-test1' 2 | -------------------------------------------------------------------------------- /packages/core/src/motion.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | AnimationControls, 3 | AnimationOptions, 4 | EasingFunction 5 | } from '@motionone/types' 6 | import { 7 | isEasingGenerator, 8 | isEasingList, 9 | defaults, 10 | noopReturn, 11 | interpolate as createInterpolate 12 | } from '@motionone/utils' 13 | import { getEasingFunction } from './utils/easing' 14 | 15 | export class Animation implements Omit { 16 | private resolve?: (value: any) => void 17 | 18 | private reject?: (value: any) => void 19 | 20 | startTime: number | null = null 21 | 22 | private pauseTime: number | undefined 23 | 24 | private rate = 1 25 | 26 | private tick: (t: number) => void 27 | 28 | private t = 0 29 | 30 | private cancelTimestamp: number | null = null 31 | 32 | private frameRequestId?: number 33 | 34 | private easing: EasingFunction = noopReturn 35 | 36 | private duration: number = 0 37 | 38 | private totalDuration: number = 0 39 | 40 | private repeat: number = 0 41 | 42 | playState: AnimationPlayState = 'idle' 43 | 44 | constructor( 45 | output: (v: number) => void, 46 | keyframes: number[] = [0, 1], 47 | { 48 | easing, 49 | duration: initialDuration = defaults.duration, 50 | delay = defaults.delay, 51 | endDelay = defaults.endDelay, 52 | repeat = defaults.repeat, 53 | offset, 54 | direction = 'normal' 55 | }: AnimationOptions = {} 56 | ) { 57 | easing = easing || defaults.easing 58 | 59 | if (isEasingGenerator(easing)) { 60 | const custom = easing.createAnimation(keyframes) 61 | easing = custom.easing 62 | keyframes = (custom.keyframes as number[]) || keyframes 63 | initialDuration = custom.duration || initialDuration 64 | } 65 | 66 | this.repeat = repeat 67 | 68 | this.easing = isEasingList(easing) ? noopReturn : getEasingFunction(easing) 69 | this.updateDuration(initialDuration) 70 | 71 | const interpolate = createInterpolate( 72 | keyframes, 73 | offset, 74 | isEasingList(easing) ? easing.map(getEasingFunction) : noopReturn 75 | ) 76 | 77 | this.tick = (timestamp: number) => { 78 | // TODO: Temporary fix for OptionsResolver typing 79 | delay = delay as number 80 | 81 | let t = 0 82 | if (this.pauseTime !== undefined) { 83 | t = this.pauseTime 84 | } else { 85 | t = (timestamp - this.startTime!) * this.rate 86 | } 87 | 88 | this.t = t 89 | 90 | // Convert to seconds 91 | t /= 1000 92 | 93 | // Rebase on delay 94 | t = Math.max(t - delay, 0) 95 | 96 | /** 97 | * If this animation has finished, set the current time 98 | * to the total duration. 99 | */ 100 | if (this.playState === 'finished' && this.pauseTime === undefined) { 101 | t = this.totalDuration 102 | } 103 | 104 | /** 105 | * Get the current progress (0-1) of the animation. If t is > 106 | * than duration we'll get values like 2.5 (midway through the 107 | * third iteration) 108 | */ 109 | const progress = t / this.duration 110 | 111 | // TODO progress += iterationStart 112 | 113 | /** 114 | * Get the current iteration (0 indexed). For instance the floor of 115 | * 2.5 is 2. 116 | */ 117 | let currentIteration = Math.floor(progress) 118 | 119 | /** 120 | * Get the current progress of the iteration by taking the remainder 121 | * so 2.5 is 0.5 through iteration 2 122 | */ 123 | let iterationProgress = progress % 1.0 124 | 125 | if (!iterationProgress && progress >= 1) { 126 | iterationProgress = 1 127 | } 128 | 129 | /** 130 | * If iteration progress is 1 we count that as the end 131 | * of the previous iteration. 132 | */ 133 | iterationProgress === 1 && currentIteration-- 134 | 135 | /** 136 | * Reverse progress if we're not running in "normal" direction 137 | */ 138 | const iterationIsOdd = currentIteration % 2 139 | if ( 140 | direction === 'reverse' || 141 | (direction === 'alternate' && iterationIsOdd) || 142 | (direction === 'alternate-reverse' && !iterationIsOdd) 143 | ) { 144 | iterationProgress = 1 - iterationProgress 145 | } 146 | 147 | const p = t >= this.totalDuration ? 1 : Math.min(iterationProgress, 1) 148 | const latest = interpolate(this.easing(p)) 149 | output(latest) 150 | 151 | const isAnimationFinished = 152 | this.pauseTime === undefined && 153 | (this.playState === 'finished' || t >= this.totalDuration + endDelay) 154 | 155 | if (isAnimationFinished) { 156 | this.playState = 'finished' 157 | this.resolve?.(latest) 158 | } else if (this.playState !== 'idle') { 159 | this.frameRequestId = requestAnimationFrame(this.tick) 160 | } 161 | } 162 | 163 | this.play() 164 | } 165 | 166 | finished = new Promise((resolve, reject) => { 167 | this.resolve = resolve 168 | this.reject = reject 169 | }) 170 | 171 | play() { 172 | const now = performance.now() 173 | this.playState = 'running' 174 | 175 | if (this.pauseTime !== undefined) { 176 | this.startTime = now - this.pauseTime 177 | } else if (!this.startTime) { 178 | this.startTime = now 179 | } 180 | 181 | this.cancelTimestamp = this.startTime 182 | this.pauseTime = undefined 183 | this.frameRequestId = requestAnimationFrame(this.tick) 184 | } 185 | 186 | pause() { 187 | this.playState = 'paused' 188 | this.pauseTime = this.t 189 | } 190 | 191 | finish() { 192 | this.playState = 'finished' 193 | this.tick(0) 194 | } 195 | 196 | stop() { 197 | this.playState = 'idle' 198 | 199 | if (this.frameRequestId !== undefined) { 200 | cancelAnimationFrame(this.frameRequestId) 201 | } 202 | 203 | this.reject?.(false) 204 | } 205 | 206 | cancel() { 207 | this.stop() 208 | this.tick(this.cancelTimestamp!) 209 | } 210 | 211 | reverse() { 212 | this.rate *= -1 213 | } 214 | 215 | commitStyles() {} 216 | 217 | private updateDuration(duration: number) { 218 | this.duration = duration 219 | this.totalDuration = duration * (this.repeat + 1) 220 | } 221 | 222 | get currentTime() { 223 | return this.t 224 | } 225 | 226 | set currentTime(t: number) { 227 | if (this.pauseTime !== undefined || this.rate === 0) { 228 | this.pauseTime = t 229 | } else { 230 | this.startTime = performance.now() - t / this.rate 231 | } 232 | } 233 | 234 | get playbackRate() { 235 | return this.rate 236 | } 237 | 238 | set playbackRate(rate) { 239 | this.rate = rate 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /packages/core/src/spring-test1.ts: -------------------------------------------------------------------------------- 1 | import * as easing from '@variesd/animated' 2 | 3 | export interface FromType { 4 | value: number 5 | } 6 | export interface ToType { 7 | value: number 8 | } 9 | 10 | export type EasingType = 11 | | 'easeOutCubic' 12 | | 'linear' 13 | | 'easeOutExpo' 14 | | 'easeInOutExpo' 15 | export type FormAndToAttributesType = 'value' | unknown 16 | export type StartFunc = () => void 17 | export type UpdateFunc = (key: ToType) => void 18 | export type FinishFunc = () => void 19 | 20 | export interface AnimationOptions { 21 | from: FromType 22 | to: ToType 23 | duration?: number 24 | delay?: number 25 | easing?: EasingType 26 | onStart: StartFunc 27 | onUpdate: UpdateFunc 28 | onFinish: FinishFunc 29 | } 30 | 31 | export const DATE_NOW = Date.now() 32 | 33 | export class Tween { 34 | private startTime: number | null = null 35 | 36 | private started?: boolean = false 37 | 38 | private finished?: boolean = false 39 | 40 | private frameRequest?: number 41 | 42 | private time?: number 43 | 44 | private elapsed?: number 45 | 46 | private keys: ToType = { value: 0 } 47 | 48 | constructor(public options: AnimationOptions) { 49 | const { from, to, delay } = options 50 | ;[from, to].forEach((item) => { 51 | if (item === undefined) { 52 | console.warn('[@varies/vue]: counter components need from and to props') 53 | } 54 | }) 55 | this.initStartTime(delay) 56 | } 57 | 58 | private initStartTime(delay = 0) { 59 | this.startTime = DATE_NOW + delay 60 | } 61 | 62 | update(): void { 63 | this.time = Date.now() 64 | // delay some time 65 | if (this.startTime && this.time < this.startTime) { 66 | return 67 | } 68 | if (this.finished) { 69 | return 70 | } 71 | // finish animation 72 | if (this.elapsed === this.options.duration) { 73 | if (!this.finished) { 74 | this.finished = true 75 | if (this.options.onFinish) { 76 | this.options.onFinish() 77 | } 78 | } 79 | return 80 | } 81 | // elapsed 时间 和 duration 时间比较 逝去光阴 82 | this.elapsed = this.time - (this.startTime ?? 0) 83 | 84 | // 防止 时间 一直 流逝 ~ 85 | this.elapsed = 86 | this.elapsed > (this.options.duration ?? 0) 87 | ? this.options.duration 88 | : this.elapsed 89 | // 从0 到 1 elapsed time 90 | // eslint-disable-next-line guard-for-in 91 | for (const key in this.options.to) { 92 | this.keys[key] = 93 | this.options.from[key] + 94 | (this.options.to[key] - this.options.from[key]) * 95 | easing[this.options.easing!](this.elapsed! / this.options.duration!) 96 | } 97 | if (!this.started) { 98 | if (this.options.onStart) { 99 | this.options.onStart() 100 | } 101 | this.started = true 102 | } 103 | if (this.options.onUpdate) { 104 | this.options.onUpdate(this.keys) 105 | } 106 | } 107 | 108 | // 递归 重绘 109 | start(): void { 110 | this.startTime = Date.now() + (this.options.delay ?? 0) 111 | const tick = () => { 112 | this.update() 113 | this.frameRequest = requestAnimationFrame(tick) 114 | if (this.finished) { 115 | // 在判断 update中 结束后 停止 重绘 116 | cancelAnimationFrame(this.frameRequest) 117 | } 118 | } 119 | tick() 120 | } 121 | 122 | stop(): void { 123 | cancelAnimationFrame(this.frameRequest) 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /packages/core/src/spring.ts: -------------------------------------------------------------------------------- 1 | import { mapTree, clone, isPlainObject } from './utils' 2 | import stepper from './stepper' 3 | 4 | const zero = () => 0 5 | const FRAME_RATE = 1 / 60 6 | 7 | export default { 8 | props: { 9 | endValue: { 10 | type: [Function, Object, Array], 11 | required: true 12 | } 13 | }, 14 | data() { 15 | let endValue = this.endValue 16 | if (typeof endValue === 'function') { 17 | endValue = endValue() 18 | } else { 19 | endValue = clone(endValue) 20 | } 21 | 22 | return { 23 | currVals: endValue, 24 | currV: mapTree(zero, endValue), 25 | now: null 26 | } 27 | }, 28 | watch: { 29 | endValue: { 30 | deep: true, 31 | handler() { 32 | this.raf(true, false) 33 | } 34 | } 35 | }, 36 | mounted() { 37 | this._rafId = null 38 | this.raf(true, false) 39 | }, 40 | destroyed() { 41 | cancelAnimationFrame(this._rafId) 42 | }, 43 | methods: { 44 | raf(justStated, isLastRaf) { 45 | if (justStated && this._rafId !== null) { 46 | return 47 | } 48 | 49 | this._rafId = requestAnimationFrame(() => { 50 | const { currVals, currV, now } = this 51 | let endValue = this.endValue 52 | 53 | if (typeof endValue === 'function') { 54 | endValue = endValue(currVals) 55 | } 56 | 57 | const frameRate = 58 | now && !justStated ? (Date.now() - now) / 1000 : FRAME_RATE 59 | const newCurrVals = updateCurrVals(frameRate, currVals, currV, endValue) 60 | const newCurrV = updateCurrV(frameRate, currVals, currV, endValue) 61 | 62 | this.currVals = newCurrVals 63 | this.currV = newCurrV 64 | this.now = Date.now() 65 | 66 | const stop = noSpeed(newCurrV) 67 | if (stop && !justStated) { 68 | if (isLastRaf) { 69 | this._rafId = null 70 | } else { 71 | this.raf(false, true) 72 | } 73 | } else { 74 | this.raf(false, false) 75 | } 76 | }) 77 | } 78 | }, 79 | render() { 80 | console.log(this.currVals) 81 | 82 | return this.currVals 83 | } 84 | } 85 | 86 | function updateCurrVals(frameRate, currVals, currV, endValue, k, b) { 87 | if (endValue === null) { 88 | return null 89 | } 90 | if (typeof endValue === 'number') { 91 | if (k == null || b == null) { 92 | return endValue 93 | } 94 | // TODO: do something to stepper to make this not allocate (2 steppers?) 95 | return stepper(frameRate, currVals, currV, endValue, k, b)[0] 96 | } 97 | if (endValue.val != null && endValue.config && endValue.config.length === 0) { 98 | return endValue 99 | } 100 | if (endValue.val != null) { 101 | const [_k, _b] = endValue.config || [170, 26] 102 | let ret = { 103 | val: updateCurrVals( 104 | frameRate, 105 | currVals.val, 106 | currV.val, 107 | endValue.val, 108 | _k, 109 | _b 110 | ) 111 | } 112 | if (endValue.config) { 113 | ret.config = endValue.config 114 | } 115 | return ret 116 | } 117 | if (Array.isArray(endValue)) { 118 | return endValue.map((_, i) => 119 | updateCurrVals(frameRate, currVals[i], currV[i], endValue[i], k, b) 120 | ) 121 | } 122 | if (isPlainObject(endValue)) { 123 | const ret = {} 124 | Object.keys(endValue).forEach((key) => { 125 | ret[key] = updateCurrVals( 126 | frameRate, 127 | currVals[key], 128 | currV[key], 129 | endValue[key], 130 | k, 131 | b 132 | ) 133 | }) 134 | return ret 135 | } 136 | return endValue 137 | } 138 | 139 | function updateCurrV(frameRate, currVals, currV, endValue, k, b) { 140 | if (endValue === null) { 141 | return null 142 | } 143 | if (typeof endValue === 'number') { 144 | if (k == null || b == null) { 145 | return mapTree(zero, currV) 146 | } 147 | // TODO: do something to stepper to make this not allocate (2 steppers?) 148 | return stepper(frameRate, currVals, currV, endValue, k, b)[1] 149 | } 150 | if (endValue.val != null && endValue.config && endValue.config.length === 0) { 151 | return mapTree(zero, currV) 152 | } 153 | if (endValue.val != null) { 154 | const [_k, _b] = endValue.config || [170, 26] 155 | let ret = { 156 | val: updateCurrV(frameRate, currVals.val, currV.val, endValue.val, _k, _b) 157 | } 158 | if (endValue.config) { 159 | ret.config = endValue.config 160 | } 161 | return ret 162 | } 163 | if (Array.isArray(endValue)) { 164 | return endValue.map((_, i) => 165 | updateCurrV(frameRate, currVals[i], currV[i], endValue[i], k, b) 166 | ) 167 | } 168 | if (isPlainObject(endValue)) { 169 | const ret = {} 170 | Object.keys(endValue).forEach((key) => { 171 | ret[key] = updateCurrV( 172 | frameRate, 173 | currVals[key], 174 | currV[key], 175 | endValue[key], 176 | k, 177 | b 178 | ) 179 | }) 180 | return ret 181 | } 182 | return mapTree(zero, currV) 183 | } 184 | 185 | function noSpeed(coll) { 186 | if (Array.isArray(coll)) { 187 | return coll.every(noSpeed) 188 | } 189 | 190 | if (isPlainObject(coll)) { 191 | return Object.keys(coll).every((key) => 192 | key === 'config' ? true : noSpeed(coll[key]) 193 | ) 194 | } 195 | 196 | return typeof coll === 'number' ? coll === 0 : true 197 | } 198 | -------------------------------------------------------------------------------- /packages/core/src/stepper.ts: -------------------------------------------------------------------------------- 1 | const errorMargin = 0.0001 2 | 3 | export default function stepper(frameRate, x, v, destX, k, b) { 4 | // Spring stiffness, in kg / s^2 5 | 6 | // for animations, destX is really spring length (spring at rest). initial 7 | // position is considered as the stretched/compressed position of a spring 8 | const Fspring = -k * (x - destX) 9 | 10 | // Damping constant, in kg / s 11 | const Fdamper = -b * v 12 | 13 | // usually we put mass here, but for animation purposes, specifying mass is a 14 | // bit redundant. you could simply adjust k and b accordingly 15 | // let a = (Fspring + Fdamper) / mass; 16 | const a = Fspring + Fdamper 17 | 18 | const newV = v + a * frameRate 19 | const newX = x + newV * frameRate 20 | 21 | if (Math.abs(newV - v) < errorMargin && Math.abs(newX - x) < errorMargin) { 22 | return [destX, 0] 23 | } 24 | 25 | return [newX, newV] 26 | } 27 | -------------------------------------------------------------------------------- /packages/core/src/utils.ts: -------------------------------------------------------------------------------- 1 | export function isPlainObject(obj) { 2 | return obj 3 | ? typeof obj === 'object' && Object.getPrototypeOf(obj) === Object.prototype 4 | : false 5 | } 6 | 7 | // damn it JS 8 | export function clone(coll) { 9 | return JSON.parse(JSON.stringify(coll)) 10 | } 11 | 12 | // export function eq(a, b) { 13 | // return JSON.stringify(a) === JSON.stringify(b); 14 | // } 15 | 16 | // currenly a helper used for producing a tree of the same shape as the 17 | // input(s), but with different values. It's technically not a real `map` 18 | // equivalent for trees, since it skips calling f on non-numbers. 19 | 20 | // TODO: probably doesn't need path, stop allocating uselessly 21 | // TODO: don't need to map over many trees anymore 22 | // TODO: skipping non-numbers is weird and non-generic. Use pre-order traversal 23 | // assume trees are of the same shape 24 | function _mapTree(path, f, trees) { 25 | const t1 = trees[0] 26 | if (typeof t1 === 'number') { 27 | return f(path, ...trees) 28 | } 29 | if (Array.isArray(t1)) { 30 | return t1.map((_, i) => 31 | _mapTree( 32 | [...path, i], 33 | f, 34 | trees.map((val) => val[i]) 35 | ) 36 | ) 37 | } 38 | if (isPlainObject(t1)) { 39 | const newTree = {} 40 | Object.keys(t1).forEach((key) => { 41 | newTree[key] = _mapTree( 42 | [...path, key], 43 | f, 44 | trees.map((val) => val[key]) 45 | ) 46 | }) 47 | return newTree 48 | } 49 | // return last one just because 50 | return trees[trees.length - 1] 51 | } 52 | 53 | export function mapTree(f, ...rest) { 54 | return _mapTree([], f, rest) 55 | } 56 | 57 | // function _reshapeTree(path, a, b, f) { 58 | // if (a == null) { 59 | // throw new Error('wtf2'); 60 | // } 61 | 62 | // if (b == null) { 63 | // return f(path, a); 64 | // } 65 | 66 | // if (Array.isArray(a)) { 67 | // return a.map((val, i) => _reshapeTree([...path, i], val, b[i], f)); 68 | // } 69 | // if (Object.prototype.toString.call(a) === '[object Object]') { 70 | // const newTree = {}; 71 | // Object.keys(a).forEach(key => { 72 | // newTree[key] = _reshapeTree([...path, key], a[key], b[key], f); 73 | // }); 74 | // return newTree; 75 | // } 76 | 77 | // return b; 78 | // } 79 | 80 | // export function reshapeTree(a, b, f) { 81 | // return _reshapeTree([], a, b, f); 82 | // } 83 | 84 | // export function toOj(vals, keys) { 85 | // const ret = {}; 86 | // vals.forEach((val, i) => ret[keys[i]] = val); 87 | // return ret; 88 | // } 89 | 90 | // export function toArr(obj) { 91 | // const keys = Object.keys(obj); 92 | // const vals = keys.map(k => obj[k]); 93 | // return [keys, vals]; 94 | // } 95 | 96 | // TODO: these are for a demos, not for the library. Move 97 | export function reinsert(arr, from, to) { 98 | const _arr = arr.slice(0) 99 | const val = _arr[from] 100 | _arr.splice(from, 1) 101 | _arr.splice(to, 0, val) 102 | return _arr 103 | } 104 | 105 | export function clamp(n, min, max) { 106 | return Math.max(Math.min(n, max), min) 107 | } 108 | 109 | export function range(start, afterStop) { 110 | let _afterStop = afterStop 111 | let _start = start 112 | if (afterStop == null) { 113 | _afterStop = start 114 | _start = 0 115 | } 116 | const ret = [] 117 | for (let i = _start; i < _afterStop; i++) { 118 | ret.push(i) 119 | } 120 | return ret 121 | } 122 | -------------------------------------------------------------------------------- /packages/core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2017", 4 | "module": "esnext", 5 | "moduleResolution": "node", 6 | "strict": true, 7 | "declaration": true, 8 | "noUnusedLocals": true, 9 | "esModuleInterop": true, 10 | "outDir": "dist", 11 | "lib": [ 12 | "ESNext" 13 | ], 14 | "sourceMap": false, 15 | "noEmitOnError": true, 16 | "noImplicitAny": false, 17 | "resolveJsonModule": true 18 | }, 19 | "exclude": [ 20 | "node_modules", 21 | "playground", 22 | "dist" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /packages/core/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'tsup' 2 | 3 | export default defineConfig({ 4 | // entry: ['./src/*.ts'], 5 | entry: ['./src/index.ts'], 6 | format: ['esm', 'cjs'], 7 | target: 'node14', 8 | clean: true, 9 | // dts: true, 10 | splitting: true, 11 | shims: true 12 | }) 13 | -------------------------------------------------------------------------------- /packages/dom/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@variesd/dom", 3 | "version": "0.0.21", 4 | "description": "", 5 | "main": "dist/index.js", 6 | "module": "dist/index.mjs", 7 | "types": "dist/index.d.ts", 8 | "publishConfig": { 9 | "access": "public", 10 | "registry": "https://registry.npmjs.org/" 11 | }, 12 | "scripts": { 13 | "test": "echo \"Error: no test specified\" && exit 1", 14 | "build:watch": "tsup --watch" 15 | }, 16 | "dependencies": { 17 | "@variesd/animated": "workspace:*" 18 | }, 19 | "keywords": [], 20 | "author": "", 21 | "license": "MIT" 22 | } 23 | -------------------------------------------------------------------------------- /packages/dom/src/index.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variesd/varies/56b804007edde3e27519c38e2a38aaeac1ad5f78/packages/dom/src/index.ts -------------------------------------------------------------------------------- /packages/dom/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2017", 4 | "module": "esnext", 5 | "moduleResolution": "node", 6 | "strict": true, 7 | "declaration": true, 8 | "noUnusedLocals": true, 9 | "esModuleInterop": true, 10 | "outDir": "dist", 11 | "lib": [ 12 | "ESNext" 13 | ], 14 | "sourceMap": false, 15 | "noEmitOnError": true, 16 | "noImplicitAny": false, 17 | "resolveJsonModule": true 18 | }, 19 | "exclude": [ 20 | "node_modules", 21 | "playground", 22 | "dist" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /packages/dom/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'tsup' 2 | 3 | export default defineConfig({ 4 | // entry: ['./src/*.ts'], 5 | entry: ['./src/index.ts'], 6 | format: ['esm', 'cjs'], 7 | target: 'node14', 8 | clean: true, 9 | dts: true, 10 | splitting: true, 11 | shims: true 12 | }) 13 | -------------------------------------------------------------------------------- /packages/easing/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@variesd/easing", 3 | "version": "0.0.21", 4 | "description": "", 5 | "main": "dist/index.mjs", 6 | "publishConfig": { 7 | "access": "public", 8 | "registry": "https://registry.npmjs.org/" 9 | }, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1", 12 | "build": "tsup --watch" 13 | }, 14 | "keywords": [], 15 | "author": "", 16 | "license": "ISC" 17 | } 18 | -------------------------------------------------------------------------------- /packages/easing/readme.md: -------------------------------------------------------------------------------- 1 | # The Beauty of Bézier Curves 2 | 3 | ![911fcc8f17a81bd9ae5d9874ee680c5.png](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0955c60a081f4d82a30944cb2ccff016~tplv-k3u1fbpfcp-watermark.image?) 4 | 5 | ## The Ever so Lovely Bézier Curve 6 | 7 | ### What is a Bezier curve? 8 | 9 | A Bézier curve (/ˈbɛz.i.eɪ/ BEH-zee-ay) is a parametric curve used in computer graphics and related fields. 10 | 11 | A set of discrete "control points" defines a smooth, continuous curve by means of a formula. 12 | 13 | Usually, the curve is intended to approximate a real-world shape that otherwise has no mathematical representation or whose representation is unknown or too complicated. 14 | 15 | The Bézier curve is named after French engineer Pierre Bézier (1910–1999), who used it in the 1960s for designing curves for the bodywork of Renault cars. Other uses include the design of computer fonts and animation. 16 | 17 | Bézier curves can be combined to form a Bézier spline, or generalized to higher dimensions to form Bézier surfaces. The Bézier triangle is a special case of the latter. 18 | 19 | 一条贝塞尔曲线是由一组 Points 从 P0 ~ PN 所控制的,这边 N 就是他的顺序(比如 N=1 的时候是线性的,2 的时候是二次,等等)。第一个控制点和最后一个控制点是曲线的终点;然而中间的一些控制点(如果有),通常不在曲线上。这些点的组合可以理解为仿射组合(affine combination,也就是不仅有点,还有点指向的方向),他们的系数之和等于一。 20 | 21 | - 贝塞尔曲线是由一堆点的集合绘制而成。 22 | - 这一堆点是在定义的 P0 ~ PN 的控制之下得出的。 23 | - P0 ~ PN 这些定义的点,第一个点和最后一个点是曲线的开头和结尾。 24 | 25 | ### One Times Bézier curves 26 | 27 | 线性 Bézier curves 是由两个点 P0 和 P1 控制形成的,假设我们有两个点 P0 and P1 分段连接,想象第三个点在这两点之间 P,第三个点 P 定义一个 t 值 这个 t 的 value 就是介于 0 - 1 之间的值 作为百分比 28 | 29 | - 当 t 等于 1 时 说明 P 移动到了 P1 30 | - 当 t 等于 0 时 说明 P 移动到了 P0 31 | - 在中间 t 的 值 是 0 - 1 之间的值 32 | - 这个函数 也叫做线性插值 `lerp` 33 | 34 | 在数学中 你可以把它定义为 35 | 36 | ```ts 37 | P = lerp(P0, P1, t) 38 | P = (1-t)P0 + tP1 39 | 40 | function lerp (P0, P1, T) { 41 | return (1 - T)P0 + TP1 42 | } 43 | ``` 44 | 45 | ![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/7ec12bf2b8524180895e4c2d065fd6f3~tplv-k3u1fbpfcp-watermark.image?) 46 | 47 | ### Two Times Bézier curves 48 | 49 | 如果我们添加一个新的点, 把两条线段的 P 点连接起来, 我们在继续从这条线段增加一个 P 点, t 的 value 也可以发生变化,这样就形成了 二次 贝塞尔 50 | 51 | image 52 | 53 | 继续添加一个点 形成三条线段 三条线段又有各自的 t 点, 连接他们 在连接上的两条线段 增加 两个点, 这时候我们形成了两个插值点, 54 | 从中间再添加一个 插值点这样就会形成一个曲线 55 | 56 | image 57 | 58 | 该曲线就是二次贝塞尔曲线 59 | 60 | ### Three Times Bézier curves 61 | 62 | image 63 | 64 | 如果我们继续添加一个点会发生什么 65 | 66 | image 67 | 68 | 我们重复同样的过程 增加每一条线段的插值点 69 | 70 | ![image](https://user-images.githubusercontent.com/66500121/213360766-486a8c3b-1201-4b69-ab0c-badba6874412.png) 71 | 72 | 最后一个插值点 将会描述三次贝塞尔曲线的路径 73 | 74 | image 75 | 76 | ![image](https://user-images.githubusercontent.com/66500121/213360787-6e9e917c-5914-4e8f-a3c0-e26ad05d97ca.png) 77 | 78 | 这种结构的美妙之处在于无论使用什么轨迹都有效, 所以我们可以改变线段的轨迹,并且遵循相同的规则,总能给我们一条平滑的曲线 79 | 80 | ![image](https://user-images.githubusercontent.com/66500121/213360805-66befeae-3945-49df-97ee-db3a354d57d4.png) 81 | 82 | 我们主要关注三次贝塞尔曲线 这个是最常用的曲线 83 | 84 | image 85 | 86 | 展开所有多项式方法之后 87 | ![image.png](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9dd321bf262345e79f97dcbd92c20024~tplv-k3u1fbpfcp-watermark.image?) 88 | 89 | ```ts 90 | function lerp (P0, P1, T) { 91 | return (1 - T)P0 + TP1 92 | } 93 | 94 | A = lerp(P0, P1, t) 95 | B = lerp(P1, P2, t) 96 | C = lerp(P2, P3, t) 97 | D = lerp(A, B, t) 98 | E = lerp(B, C, t) 99 | P = lerp(D, E, t) 100 | ``` 101 | 102 | ### What is a lerp 103 | 104 | 学习 lerps 函数 https://zhuanlan.zhihu.com/p/114898567 105 | 106 | https://juejin.cn/post/6844903774117429261#comment 107 | 108 | ![image](https://user-images.githubusercontent.com/66500121/213385278-9ad9a2a9-ac19-436a-8e81-84c180277593.png) 109 | 110 | ![image](https://user-images.githubusercontent.com/66500121/213386598-fc754279-4cbf-4acc-8547-a7d455c01ab4.png) 111 | 112 | ![image](https://user-images.githubusercontent.com/66500121/213387516-218adaf9-a9a2-41a4-a52c-69341fe9f2e0.png) 113 | 114 | ![image](https://user-images.githubusercontent.com/66500121/213387914-f7edeadf-8383-45b7-81f1-16b379dd6250.png) 115 | 116 | ![image](https://user-images.githubusercontent.com/66500121/213388342-78e46d24-0f04-4102-a14a-8d12dc90af58.png) 117 | 118 | ![image](https://user-images.githubusercontent.com/66500121/213388395-95dc07db-1467-4fd7-80f2-94dd1381074a.png) 119 | 120 | ![image](https://user-images.githubusercontent.com/66500121/213388533-85b74aaf-e7d3-456e-b39b-32c0d599dde2.png) 121 | -------------------------------------------------------------------------------- /packages/easing/src/bezier-generator.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/no-unused-vars, max-params 2 | function linearBezierCurze(a, b, c, d) { 3 | const line1 = c - a 4 | const line2 = d - b 5 | // eslint-disable-next-line func-names 6 | return function (t) { 7 | return [line1 * t + a, line2 * t + b] 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/easing/src/css-animation-function.ts: -------------------------------------------------------------------------------- 1 | // $easeInSine: cubic - bezier(0.47, 0, 0.745, 0.715) 2 | 3 | // $easeOutSine: cubic - bezier(0.39, 0.575, 0.565, 1) 4 | 5 | // $easeInOutSine: cubic - bezier(0.445, 0.05, 0.55, 0.95) 6 | 7 | // $easeInQuad: cubic - bezier(0.55, 0.085, 0.68, 0.53) 8 | 9 | // $easeOutQuad: cubic - bezier(0.25, 0.46, 0.45, 0.94) 10 | 11 | // $easeInOutQuad: cubic - bezier(0.455, 0.03, 0.515, 0.955) 12 | 13 | // $easeInCubic: cubic - bezier(0.55, 0.055, 0.675, 0.19) 14 | 15 | // $easeOutCubic: cubic - bezier(0.215, 0.61, 0.355, 1) 16 | 17 | // $easeInOutCubic: cubic - bezier(0.645, 0.045, 0.355, 1) 18 | 19 | // $easeInQuart: cubic - bezier(0.895, 0.03, 0.685, 0.22) 20 | 21 | // $easeOutQuart: cubic - bezier(0.165, 0.84, 0.44, 1) 22 | 23 | // $easeInOutQuart: cubic - bezier(0.77, 0, 0.175, 1) 24 | 25 | // $easeInQuint: cubic - bezier(0.755, 0.05, 0.855, 0.06) 26 | 27 | // $easeOutQuint: cubic - bezier(0.23, 1, 0.32, 1) 28 | 29 | // $easeInOutQuint: cubic - bezier(0.86, 0, 0.07, 1) 30 | 31 | // $easeInExpo: cubic - bezier(0.95, 0.05, 0.795, 0.035) 32 | 33 | // $easeOutExpo: cubic - bezier(0.19, 1, 0.22, 1) 34 | 35 | // $easeInOutExpo: cubic - bezier(1, 0, 0, 1) 36 | 37 | // $easeInCirc: cubic - bezier(0.6, 0.04, 0.98, 0.335) 38 | 39 | // $easeOutCirc: cubic - bezier(0.075, 0.82, 0.165, 1) 40 | 41 | // $easeInOutCirc: cubic - bezier(0.785, 0.135, 0.15, 0.86) 42 | 43 | // $easeInBack: cubic - bezier(0.6, -0.28, 0.735, 0.045) 44 | 45 | // $easeOutBack: cubic - bezier(0.175, 0.885, 0.32, 1.275) 46 | 47 | // $easeInOutBack: cubic - bezier(0.68, -0.55, 0.265, 1.55) 48 | -------------------------------------------------------------------------------- /packages/easing/src/cubic-bezier.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * A Bézier curve (/ˈbɛz.i.eɪ/ BEH-zee-ay)[1] is a parametric curve used in computer graphics and related 3 | * fields.[2] A set of discrete "control points" defines a smooth, continuous curve by means of a formula. 4 | * Usually the curve is intended to approximate a real-world shape that otherwise has no mathematical representation or 5 | * whose representation is unknown or too complicated. The Bézier curve is named after French engineer Pierre Bézier (1910–1999), 6 | * who used it in the 1960s for designing curves for the bodywork of Renault cars.[3] Other uses include the design of computer fonts and animation.[3] 7 | * Bézier curves can be combined to form a Bézier spline, 8 | * or generalized to higher dimensions to form Bézier surfaces.[3] 9 | * The Bézier triangle is a special case of the latter. 10 | */ 11 | 12 | /** 13 | * Inspiration Freya Holmér 14 | * link https://www.youtube.com/watch?v=aVwxzDHniEw 15 | * use online https://cubic-bezier.com/ 16 | */ 17 | 18 | /** 19 | * This has been modified from Gaëtan Renaudeau's BezierEasing 20 | * https://github.com/gre/bezier-easing/blob/master/src/index.js 21 | * https://github.com/gre/bezier-easing/blob/master/LICENSE 22 | * 23 | */ 24 | // Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2. 25 | const calcBezier = (t: number, a1: number, a2: number) => 26 | (((1.0 - 3.0 * a2 + 3.0 * a1) * t + (3.0 * a2 - 6.0 * a1)) * t + 3.0 * a1) * t 27 | 28 | const subdivisionPrecision = 0.0000001 29 | const subdivisionMaxIterations = 12 30 | 31 | export const noopReturn = (v: V) => v 32 | 33 | function binarySubdivide( 34 | x: number, 35 | lowerBound: number, 36 | upperBound: number, 37 | mX1: number, 38 | mX2: number 39 | ) { 40 | let currentX: number 41 | let currentT: number 42 | let i: number = 0 43 | 44 | do { 45 | currentT = lowerBound + (upperBound - lowerBound) / 2.0 46 | currentX = calcBezier(currentT, mX1, mX2) - x 47 | if (currentX > 0.0) { 48 | upperBound = currentT 49 | } else { 50 | lowerBound = currentT 51 | } 52 | } while ( 53 | Math.abs(currentX) > subdivisionPrecision && 54 | ++i < subdivisionMaxIterations 55 | ) 56 | 57 | return currentT 58 | } 59 | export function cubicBezier( 60 | mX1: number, 61 | mY1: number, 62 | mX2: number, 63 | mY2: number 64 | ) { 65 | // x 0 0 y 1 1 66 | // If this is a linear gradient, return linear easing 67 | if (mX1 === mY1 && mX2 === mY2) return noopReturn 68 | 69 | const getTForX = (aX: number) => binarySubdivide(aX, 0, 1, mX1, mX2) 70 | 71 | // If animation is at start/end, return t without easing 72 | return (t: number) => 73 | t === 0 || t === 1 ? t : calcBezier(getTForX(t), mY1, mY2) 74 | } 75 | -------------------------------------------------------------------------------- /packages/easing/src/easing.ts: -------------------------------------------------------------------------------- 1 | // pow 返回 基数的指数次幂 t ** power 2 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 3 | const pow = Math.pow 4 | const sqrt = Math.sqrt 5 | 6 | export const easeOutCubic = (x: number): number => 1 - (1 - x) ** 3 7 | export const linear = (x: number): number => x 8 | export const easeOutExpo = (x: number): number => 9 | x === 1 ? 1 : 1 - 2 ** (-10 * x) 10 | 11 | export const easeInOutExpo = (x: number): number => 12 | // eslint-disable-next-line no-nested-ternary 13 | x === 0 14 | ? 0 15 | : // eslint-disable-next-line no-nested-ternary 16 | x === 1 17 | ? 1 18 | : x < 0.5 19 | ? 2 ** (20 * x - 10) / 2 20 | : (2 - 2 ** (-20 * x + 10)) / 2 21 | export const easeInExpo = (x: number): number => 22 | x === 0 ? 0 : 2 ** (10 * x - 10) 23 | export const easeInOutCirc = (x: number): number => 24 | x < 0.5 25 | ? (1 - sqrt(1 - (2 * x) ** 2)) / 2 26 | : (sqrt(1 - (-2 * x + 2) ** 2) + 1) / 2 27 | -------------------------------------------------------------------------------- /packages/easing/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './cubic-bezier' 2 | export * from './steps' 3 | export * from './easing' 4 | -------------------------------------------------------------------------------- /packages/easing/src/steps.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /packages/easing/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2017", 4 | "module": "esnext", 5 | "moduleResolution": "node", 6 | "strict": true, 7 | "declaration": true, 8 | "noUnusedLocals": true, 9 | "esModuleInterop": true, 10 | "outDir": "dist", 11 | "lib": ["ESNext"], 12 | "sourceMap": false, 13 | "noEmitOnError": true, 14 | "noImplicitAny": false, 15 | "resolveJsonModule": true 16 | }, 17 | "exclude": ["node_modules", "playground", "dist"] 18 | } 19 | -------------------------------------------------------------------------------- /packages/easing/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'tsup' 2 | 3 | export default defineConfig({ 4 | entry: ['./src/*.ts'], 5 | // entry: ['./src/index.ts'], 6 | format: ['esm', 'cjs'], 7 | target: 'node14', 8 | clean: true, 9 | // dts: true, 10 | splitting: true, 11 | shims: true 12 | }) 13 | -------------------------------------------------------------------------------- /packages/utils/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@variesd/utils", 3 | "version": "0.0.21", 4 | "description": "", 5 | "main": "dist/index.js", 6 | "module": "dist/index.mjs", 7 | "types": "dist/index.d.ts", 8 | "publishConfig": { 9 | "access": "public", 10 | "registry": "https://registry.npmjs.org/" 11 | }, 12 | "scripts": { 13 | "test": "echo \"Error: no test specified\" && exit 1", 14 | "build": "tsup", 15 | "build:watch": "tsup --watch" 16 | }, 17 | "dependencies": { 18 | "@variesd/animated": "workspace:*" 19 | }, 20 | "keywords": [], 21 | "author": "", 22 | "license": "MIT" 23 | } 24 | -------------------------------------------------------------------------------- /packages/utils/src/clamp.ts: -------------------------------------------------------------------------------- 1 | export const clamp = (min: number, max: number, v: number) => 2 | Math.min(Math.max(v, min), max) 3 | -------------------------------------------------------------------------------- /packages/utils/src/index.ts: -------------------------------------------------------------------------------- 1 | console.log(1) 2 | -------------------------------------------------------------------------------- /packages/utils/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2017", 4 | "module": "esnext", 5 | "moduleResolution": "node", 6 | "strict": true, 7 | "declaration": true, 8 | "noUnusedLocals": true, 9 | "esModuleInterop": true, 10 | "outDir": "dist", 11 | "lib": [ 12 | "ESNext" 13 | ], 14 | "sourceMap": false, 15 | "noEmitOnError": true, 16 | "noImplicitAny": false, 17 | "resolveJsonModule": true 18 | }, 19 | "exclude": [ 20 | "node_modules", 21 | "playground", 22 | "dist" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /packages/utils/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'tsup' 2 | 3 | export default defineConfig({ 4 | // entry: ['./src/*.ts'], 5 | entry: ['./src/index.ts'], 6 | format: ['esm', 'cjs'], 7 | target: 'node14', 8 | clean: true, 9 | // dts: true, 10 | splitting: true, 11 | shims: true 12 | }) 13 | -------------------------------------------------------------------------------- /packages/vue/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@variesd/vue", 3 | "version": "0.0.21", 4 | "description": "", 5 | "main": "dist/index.js", 6 | "module": "dist/index.mjs", 7 | "types": "dist/index.d.ts", 8 | "exports": { 9 | ".": { 10 | "require": "./dist/index.js", 11 | "import": "./dist/index.mjs" 12 | }, 13 | "./*": "./*", 14 | "./nuxt": { 15 | "require": "./dist/nuxt.js", 16 | "import": "./dist/nuxt.mjs" 17 | }, 18 | "./resolvers": { 19 | "require": "./dist/resolvers.js", 20 | "import": "./dist/resolvers.mjs" 21 | }, 22 | "./rollup": { 23 | "require": "./dist/rollup.js", 24 | "import": "./dist/rollup.mjs" 25 | }, 26 | "./types": { 27 | "require": "./dist/types.js", 28 | "import": "./dist/types.mjs" 29 | }, 30 | "./vite": { 31 | "require": "./dist/vite.js", 32 | "import": "./dist/vite.mjs" 33 | }, 34 | "./webpack": { 35 | "require": "./dist/webpack.js", 36 | "import": "./dist/webpack.mjs" 37 | }, 38 | "./esbuild": { 39 | "require": "./dist/esbuild.js", 40 | "import": "./dist/esbuild.mjs" 41 | } 42 | }, 43 | "typesVersions": { 44 | "*": { 45 | "*": [ 46 | "./dist/*", 47 | "./*" 48 | ] 49 | } 50 | }, 51 | "files": [ 52 | "dist" 53 | ], 54 | "scripts": { 55 | "test": "echo \"Error: no test specified\" && exit 1", 56 | "build": "vite build", 57 | "build:watch": "vite build --watch" 58 | }, 59 | "publishConfig": { 60 | "access": "public", 61 | "registry": "https://registry.npmjs.org/" 62 | }, 63 | "dependencies": { 64 | "vue-demi": "latest", 65 | "@variesd/core": "workspace:*" 66 | }, 67 | "devDependencies": { 68 | "@vitejs/plugin-vue": "^4.0.0", 69 | "@vitejs/plugin-vue-jsx": "^3.0.0", 70 | "css-render": "^0.15.12", 71 | "vite": "^4.0.3", 72 | "vue": "latest", 73 | "vite-plugin-dts": "^1.0.5" 74 | }, 75 | "peerDependencies": { 76 | "@vue/composition-api": "^1.0.0-rc.1", 77 | "vue": "^2.0.0 || >=3.0.0" 78 | }, 79 | "peerDependenciesMeta": { 80 | "@vue/composition-api": { 81 | "optional": true 82 | } 83 | }, 84 | "keywords": [], 85 | "author": "", 86 | "license": "MIT", 87 | "engines": { 88 | "node": ">=14" 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /packages/vue/src/components/statistic/__tests__/statistic.spec.ts: -------------------------------------------------------------------------------- 1 | import { mount } from '@vue/test-utils' 2 | import { Statistic } from '../index' 3 | 4 | describe('statistic test', () => { 5 | it('statistic init render', async () => { 6 | // todo 7 | }) 8 | }) 9 | -------------------------------------------------------------------------------- /packages/vue/src/components/statistic/statistic-types.ts: -------------------------------------------------------------------------------- 1 | import type { PropType, ExtractPropTypes, CSSProperties } from 'vue-demi' 2 | // import type { easingType } from './utils/animation' 3 | export const statisticProps = { 4 | title: { 5 | type: String, 6 | default: '' 7 | }, 8 | value: { 9 | type: [Number, String] 10 | }, 11 | prefix: { 12 | type: String 13 | }, 14 | suffix: { 15 | type: String 16 | }, 17 | precision: { 18 | type: Number 19 | }, 20 | groupSeparator: { 21 | type: String, 22 | default: '' 23 | }, 24 | valueStyle: { 25 | type: Object as PropType 26 | }, 27 | animationDuration: { 28 | type: Number, 29 | default: 2000 30 | }, 31 | valueFrom: { 32 | type: Number 33 | }, 34 | animation: { 35 | type: Boolean, 36 | default: false 37 | }, 38 | start: { 39 | type: Boolean, 40 | default: true 41 | }, 42 | extra: { 43 | type: String, 44 | default: '' 45 | } 46 | } as const 47 | 48 | export type StatisticProps = ExtractPropTypes 49 | -------------------------------------------------------------------------------- /packages/vue/src/components/statistic/statistic.tsx: -------------------------------------------------------------------------------- 1 | import { defineComponent, computed, ref, onMounted, watch } from 'vue-demi' 2 | import { statisticProps, StatisticProps } from './statistic-types' 3 | import { analysisValueType } from './utils/separator' 4 | import { Tween } from './utils/animation' 5 | import './statistic.scss' 6 | 7 | export default defineComponent({ 8 | name: 'Statistic', 9 | inheritAttrs: false, 10 | props: statisticProps, 11 | setup(props: StatisticProps, ctx) { 12 | const innerValue = ref(props.valueFrom ?? props.value) 13 | const tween = ref(null) 14 | 15 | const animation = ( 16 | from: number = props.valueFrom ?? 0, 17 | to: number = typeof props.value === 'number' 18 | ? props.value 19 | : Number(props.value) 20 | ) => { 21 | if (from !== to) { 22 | tween.value = new Tween({ 23 | from: { 24 | value: from 25 | }, 26 | to: { 27 | value: to 28 | }, 29 | delay: 0, 30 | duration: props.animationDuration, 31 | easing: 'easeOutCubic', 32 | onUpdate: (keys: any) => { 33 | innerValue.value = keys.value 34 | }, 35 | onFinish: () => { 36 | innerValue.value = to 37 | } 38 | }) 39 | tween.value.start() 40 | } 41 | } 42 | const statisticValue = computed(() => { 43 | return analysisValueType( 44 | innerValue.value, 45 | props.value, 46 | props.groupSeparator, 47 | props.precision 48 | ) 49 | }) 50 | onMounted(() => { 51 | if (props.animation && props.start) { 52 | animation() 53 | } 54 | }) 55 | // 我们可以手动控制animation 56 | watch( 57 | () => props.start, 58 | (value) => { 59 | if (value && !tween.value) { 60 | animation() 61 | } 62 | } 63 | ) 64 | return () => { 65 | return ( 66 |
67 |
68 | {ctx.slots.title?.() || props.title} 69 |
70 |
71 | {props.prefix || ctx.slots.prefix?.() ? ( 72 | 73 | {ctx.slots.prefix?.() || props.prefix} 74 | 75 | ) : null} 76 | {statisticValue.value} 77 | {props.suffix || ctx.slots.suffix?.() ? ( 78 | 79 | {ctx.slots.suffix?.() || props.suffix} 80 | 81 | ) : null} 82 |
83 | {props.extra || ctx.slots.extra?.() ? ( 84 |
85 | {' '} 86 | {ctx.slots.extra?.() || props.extra} 87 |
88 | ) : null} 89 |
90 | ) 91 | } 92 | } 93 | }) 94 | -------------------------------------------------------------------------------- /packages/vue/src/components/statistic/statistic.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 79 | 82 | -------------------------------------------------------------------------------- /packages/vue/src/components/statistic/utils/animation.ts: -------------------------------------------------------------------------------- 1 | import * as easing from './easing' 2 | 3 | export type easingType = 4 | | 'easeOutCubic' 5 | | 'linear' 6 | | 'easeOutExpo' 7 | | 'easeInOutExpo' 8 | export interface startFunc { 9 | (key: number): number 10 | } 11 | export interface updateFunc { 12 | (key: any): any 13 | } 14 | export interface finishFunc { 15 | (key: any): any 16 | } 17 | export interface fromType { 18 | value: number 19 | } 20 | export interface toType { 21 | value: number 22 | } 23 | export interface AnimationOptions { 24 | from: fromType 25 | to: toType 26 | duration?: number 27 | delay?: number 28 | easingType?: easingType 29 | onStart?: startFunc 30 | onUpdate?: updateFunc 31 | onFinish?: finishFunc 32 | } 33 | 34 | export class Tween { 35 | from: fromType 36 | 37 | to: toType 38 | 39 | duration?: number 40 | 41 | delay?: number 42 | 43 | easing?: easingType 44 | 45 | onStart?: startFunc 46 | 47 | onUpdate?: updateFunc 48 | 49 | onFinish?: finishFunc 50 | 51 | startTime?: number 52 | 53 | started?: boolean 54 | 55 | finished?: boolean 56 | 57 | timer?: null | number 58 | 59 | time?: number 60 | 61 | elapsed?: number 62 | 63 | keys?: any 64 | 65 | constructor(options: AnimationOptions) { 66 | const { 67 | from, 68 | to, 69 | duration, 70 | delay, 71 | easingType, 72 | onStart, 73 | onUpdate, 74 | onFinish 75 | } = options 76 | for (const key in from) { 77 | if (to[key] === undefined) { 78 | to[key] = from[key] 79 | } 80 | } 81 | 82 | for (const key in to) { 83 | if (from[key] === undefined) { 84 | from[key] = to[key] 85 | } 86 | } 87 | 88 | this.from = from 89 | this.to = to 90 | this.duration = duration 91 | this.delay = delay 92 | this.easing = easingType 93 | this.onStart = onStart 94 | this.onUpdate = onUpdate 95 | this.onFinish = onFinish 96 | this.startTime = Date.now() + this.delay 97 | this.started = false 98 | this.finished = false 99 | this.timer = null 100 | this.keys = {} 101 | } 102 | 103 | update(): void { 104 | this.time = Date.now() 105 | // delay some time 106 | if (this.time < this.startTime) { 107 | return 108 | } 109 | if (this.finished) { 110 | return 111 | } 112 | // finish animation 113 | if (this.elapsed === this.duration) { 114 | if (!this.finished) { 115 | this.finished = true 116 | // eslint-disable-next-line no-unused-expressions 117 | this.onFinish && this.onFinish(this.keys) 118 | } 119 | return 120 | } 121 | // elapsed 时间 和 duration 时间比较 逝去光阴 122 | this.elapsed = this.time - this.startTime 123 | // 防止 时间 一直 流逝 ~ 124 | this.elapsed = this.elapsed > this.duration ? this.duration : this.elapsed 125 | // 从0 到 1 elapsed time 126 | // eslint-disable-next-line guard-for-in 127 | for (const key in this.to) { 128 | this.keys[key] = 129 | this.from[key] + 130 | (this.to[key] - this.from[key]) * 131 | // eslint-disable-next-line import/namespace 132 | easing[this.easing](this.elapsed / this.duration) 133 | } 134 | if (!this.started) { 135 | // eslint-disable-next-line no-unused-expressions 136 | this.onStart && this.onStart(this.keys) 137 | this.started = true 138 | } 139 | this.onUpdate(this.keys) 140 | } 141 | 142 | // 递归 重绘 143 | start(): void { 144 | this.startTime = Date.now() + this.delay 145 | const tick = () => { 146 | this.update() 147 | this.timer = requestAnimationFrame(tick) 148 | if (this.finished) { 149 | // 在判断 update中 结束后 停止 重绘 150 | cancelAnimationFrame(this.timer) 151 | this.timer = null 152 | } 153 | } 154 | tick() 155 | } 156 | 157 | stop(): void { 158 | cancelAnimationFrame(this.timer) 159 | this.timer = null 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /packages/vue/src/components/statistic/utils/easing.ts: -------------------------------------------------------------------------------- 1 | // pow 返回 基数的指数次幂 t ** power 2 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 3 | const pow = Math.pow 4 | const sqrt = Math.sqrt 5 | 6 | export const easeOutCubic = (x: number): number => 1 - (1 - x) ** 3 7 | export const linear = (x: number): number => x 8 | export const easeOutExpo = (x: number): number => 9 | x === 1 ? 1 : 1 - 2 ** (-10 * x) 10 | 11 | export const easeInOutExpo = (x: number): number => 12 | // eslint-disable-next-line no-nested-ternary 13 | x === 0 14 | ? 0 15 | : // eslint-disable-next-line no-nested-ternary 16 | x === 1 17 | ? 1 18 | : x < 0.5 19 | ? 2 ** (20 * x - 10) / 2 20 | : (2 - 2 ** (-20 * x + 10)) / 2 21 | export const easeInExpo = (x: number): number => 22 | x === 0 ? 0 : 2 ** (10 * x - 10) 23 | export const easeInOutCirc = (x: number): number => 24 | x < 0.5 25 | ? (1 - sqrt(1 - (2 * x) ** 2)) / 2 26 | : (sqrt(1 - (-2 * x + 2) ** 2) + 1) / 2 27 | -------------------------------------------------------------------------------- /packages/vue/src/components/statistic/utils/separator.ts: -------------------------------------------------------------------------------- 1 | export type valueType = string | number 2 | 3 | export const separator = ( 4 | SeparatorString: string, // value 5 | groupSeparator: string // 千分位分隔符 6 | ): string => { 7 | const res = SeparatorString.replace(/\d+/, (n) => 8 | // 先提取整数部分 9 | n.replace(/(\d)(?=(\d{3})+$)/g, ($1) => `${$1}${groupSeparator}`) 10 | ) 11 | return res 12 | } 13 | 14 | export const isHasDot = (value: number): boolean => { 15 | if (!isNaN(value)) { 16 | return `${value}`.indexOf('.') !== -1 17 | } 18 | return false 19 | } 20 | export const analysisValueType = ( 21 | value: valueType, // 动态value 值 22 | propsValue: valueType, // 用户传入value 23 | groupSeparator: string, // 千位分隔符 24 | splitPrecisionNumber: number // 分割精度, 小数点 25 | // eslint-disable-next-line max-params 26 | ): string => { 27 | const fixedNumber = 28 | propsValue.toString().indexOf('.') !== -1 29 | ? propsValue.toString().length - propsValue.toString().indexOf('.') - 1 30 | : 0 31 | if (typeof value === 'number') { 32 | if (isHasDot(value)) { 33 | return splitPrecisionNumber 34 | ? separator( 35 | value.toFixed(splitPrecisionNumber).toString(), 36 | groupSeparator 37 | ) 38 | : separator(value.toFixed(fixedNumber).toString(), groupSeparator) 39 | } 40 | return splitPrecisionNumber 41 | ? separator( 42 | value.toFixed(splitPrecisionNumber).toString(), 43 | groupSeparator 44 | ) 45 | : separator(value.toString(), groupSeparator) 46 | } 47 | return value 48 | } 49 | -------------------------------------------------------------------------------- /packages/vue/src/composable/useMotion.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /packages/vue/src/composable/useStatistic.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /packages/vue/src/index.ts: -------------------------------------------------------------------------------- 1 | import type { App } from 'vue-demi' 2 | import Statistic from './components/statistic/statistic.vue' 3 | 4 | Statistic.install = (app: App): void => { 5 | app.component(Statistic.name, Statistic) 6 | console.log(Statistic) 7 | } 8 | 9 | export { Statistic } 10 | 11 | export default { 12 | install(app: App): void { 13 | app.use(Statistic as any) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/vue/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "./", 4 | "target": "esnext", 5 | "declaration": true, 6 | "declarationDir": "dist", 7 | "useDefineForClassFields": true, 8 | "module": "esnext", 9 | "moduleResolution": "node", 10 | "isolatedModules": true, 11 | // "strict": true, 12 | "jsx": "preserve", 13 | "sourceMap": true, 14 | "resolveJsonModule": true, 15 | "esModuleInterop": true, 16 | "importHelpers": true, 17 | "skipLibCheck": true, 18 | "noEmit": true, 19 | "paths": { 20 | "@/*": ["src/*"] 21 | }, 22 | "lib": ["esnext", "dom", "dom.iterable"], 23 | }, 24 | "include": ["vite.config.*", "src/**/*", "src/**/*.vue"], 25 | "exclude": ["/dist/**", "node_modules"], 26 | "references": [{ "path": "./tsconfig.node.json" }] 27 | } 28 | -------------------------------------------------------------------------------- /packages/vue/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "esnext", 5 | "moduleResolution": "node", 6 | "allowSyntheticDefaultImports": true, 7 | }, 8 | "include": ["vite.config.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/vue/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { resolve } from 'path' 2 | import { fileURLToPath } from 'url' 3 | import { defineConfig } from 'vite' 4 | import vue from '@vitejs/plugin-vue' 5 | import dts from 'vite-plugin-dts' 6 | import vueJsx from '@vitejs/plugin-vue-jsx' 7 | 8 | // https://vitejs.dev/config/ 9 | export default defineConfig(async (env) => { 10 | console.log(env.mode) 11 | 12 | return { 13 | resolve: { 14 | extensions: ['.tsx', '.vue', '.jsx', '.ts', '.js'], 15 | alias: { 16 | '@': resolve(__dirname, 'src') 17 | } 18 | }, 19 | optimizeDeps: { 20 | exclude: ['vue-demi'] 21 | }, 22 | build: { 23 | lib: { 24 | entry: fileURLToPath(new URL('./src/index.ts', import.meta.url)), 25 | formats: ['es', 'cjs', 'umd', 'iife'], 26 | name: 'Statistic', 27 | fileName: 'index' 28 | }, 29 | rollupOptions: { 30 | external: ['vue', 'lodash'], 31 | output: { 32 | exports: 'named', 33 | globals: { 34 | vue: 'Vue' 35 | } 36 | } 37 | } 38 | }, 39 | plugins: [ 40 | vue(), 41 | vueJsx(), 42 | dts({ 43 | include: ['./index.ts', './src/index.vue', './src/volar.d.ts'], 44 | beforeWriteFile(filePath, content) { 45 | return { 46 | filePath: filePath.replace('/dist/src/', '/dist/'), 47 | content 48 | } 49 | } 50 | }) 51 | ] 52 | } 53 | }) 54 | -------------------------------------------------------------------------------- /playground/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /playground/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"] 3 | } 4 | -------------------------------------------------------------------------------- /playground/README.md: -------------------------------------------------------------------------------- 1 | # Vue 3 + TypeScript + Vite 2 | 3 | This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 ` 12 | 13 | 14 | -------------------------------------------------------------------------------- /playground/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "playground", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "@variesd/easing": "workspace:0.0.21", 13 | "@variesd/vue": "workspace:0.0.21", 14 | "vue": "^3.2.47" 15 | }, 16 | "devDependencies": { 17 | "@vitejs/plugin-vue": "^4.0.0", 18 | "typescript": "^4.9.5", 19 | "vite": "^4.1.4", 20 | "vue-tsc": "^1.2.0" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /playground/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /playground/src/App.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /playground/src/assets/vue.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /playground/src/components/HelloWorld.vue: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variesd/varies/56b804007edde3e27519c38e2a38aaeac1ad5f78/playground/src/components/HelloWorld.vue -------------------------------------------------------------------------------- /playground/src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import './style.css' 3 | import App from './App.vue' 4 | const app = createApp(App) 5 | 6 | app.mount('#app') 7 | -------------------------------------------------------------------------------- /playground/src/style.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, Avenir, Helvetica, Arial, sans-serif; 3 | font-size: 16px; 4 | line-height: 24px; 5 | font-weight: 400; 6 | 7 | color-scheme: light dark; 8 | color: rgba(255, 255, 255, 0.87); 9 | background-color: #242424; 10 | 11 | font-synthesis: none; 12 | text-rendering: optimizeLegibility; 13 | -webkit-font-smoothing: antialiased; 14 | -moz-osx-font-smoothing: grayscale; 15 | -webkit-text-size-adjust: 100%; 16 | } 17 | 18 | a { 19 | font-weight: 500; 20 | color: #646cff; 21 | text-decoration: inherit; 22 | } 23 | a:hover { 24 | color: #535bf2; 25 | } 26 | 27 | body { 28 | margin: 0; 29 | display: flex; 30 | place-items: center; 31 | min-width: 320px; 32 | min-height: 100vh; 33 | } 34 | 35 | h1 { 36 | font-size: 3.2em; 37 | line-height: 1.1; 38 | } 39 | 40 | button { 41 | border-radius: 8px; 42 | border: 1px solid transparent; 43 | padding: 0.6em 1.2em; 44 | font-size: 1em; 45 | font-weight: 500; 46 | font-family: inherit; 47 | background-color: #1a1a1a; 48 | cursor: pointer; 49 | transition: border-color 0.25s; 50 | } 51 | button:hover { 52 | border-color: #646cff; 53 | } 54 | button:focus, 55 | button:focus-visible { 56 | outline: 4px auto -webkit-focus-ring-color; 57 | } 58 | 59 | .card { 60 | padding: 2em; 61 | } 62 | 63 | #app { 64 | max-width: 1280px; 65 | margin: 0 auto; 66 | padding: 2rem; 67 | text-align: center; 68 | } 69 | 70 | @media (prefers-color-scheme: light) { 71 | :root { 72 | color: #213547; 73 | background-color: #ffffff; 74 | } 75 | a:hover { 76 | color: #747bff; 77 | } 78 | button { 79 | background-color: #f9f9f9; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /playground/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /playground/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "module": "ESNext", 6 | "moduleResolution": "Node", 7 | "strict": true, 8 | "jsx": "preserve", 9 | "resolveJsonModule": true, 10 | "isolatedModules": true, 11 | "esModuleInterop": true, 12 | "lib": ["ESNext", "DOM"], 13 | "skipLibCheck": true, 14 | "noEmit": true 15 | }, 16 | "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], 17 | "references": [{ "path": "./tsconfig.node.json" }] 18 | } 19 | -------------------------------------------------------------------------------- /playground/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "allowSyntheticDefaultImports": true 7 | }, 8 | "include": ["vite.config.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /playground/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [vue()] 7 | }) 8 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - 'packages/**/**' 3 | - 'docs' 4 | - 'playground' 5 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:base" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "pipeline": { 3 | "build": { 4 | "dependsOn": ["^build"], 5 | "outputs": ["dist/**", "build/**"], 6 | "outputMode": "new-only" 7 | }, 8 | "start": { 9 | "dependsOn": ["build"] 10 | }, 11 | "build:docs": { 12 | "cache": false 13 | }, 14 | "build:watch": {}, 15 | "lint": { 16 | "outputs": [] 17 | }, 18 | "dev": { 19 | "cache": false, 20 | "dependsOn": ["^build"] 21 | } 22 | } 23 | } 24 | --------------------------------------------------------------------------------