├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .npmrc ├── .nuxtrc ├── CHANGELOG.md ├── LICENSE ├── README.md ├── bun.lockb ├── package.json ├── playground ├── app.vue ├── nuxt.config.ts ├── package.json ├── server │ └── tsconfig.json └── tsconfig.json ├── src ├── module.ts └── runtime │ ├── component.vue │ ├── composable.ts │ ├── directive.ts │ ├── plugin.ts │ └── types.ts ├── test ├── basic.test.ts └── fixtures │ └── basic │ ├── app.vue │ ├── nuxt.config.ts │ └── package.json └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_size = 2 5 | indent_style = space 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "extends": ["@nuxt/eslint-config"] 4 | } 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | node_modules 3 | 4 | # Logs 5 | *.log* 6 | 7 | # Temp directories 8 | .temp 9 | .tmp 10 | .cache 11 | 12 | # Yarn 13 | **/.yarn/cache 14 | **/.yarn/*state* 15 | 16 | # Generated dirs 17 | dist 18 | 19 | # Nuxt 20 | .nuxt 21 | .output 22 | .data 23 | .vercel_build_output 24 | .build-* 25 | .netlify 26 | 27 | # Env 28 | .env 29 | 30 | # Testing 31 | reports 32 | coverage 33 | *.lcov 34 | .nyc_output 35 | 36 | # VSCode 37 | .vscode/* 38 | !.vscode/settings.json 39 | !.vscode/tasks.json 40 | !.vscode/launch.json 41 | !.vscode/extensions.json 42 | !.vscode/*.code-snippets 43 | 44 | # Intellij idea 45 | *.iml 46 | .idea 47 | 48 | # OSX 49 | .DS_Store 50 | .AppleDouble 51 | .LSOverride 52 | .AppleDB 53 | .AppleDesktop 54 | Network Trash Folder 55 | Temporary Items 56 | .apdisk 57 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | shamefully-hoist=true 2 | strict-peer-dependencies=false 3 | -------------------------------------------------------------------------------- /.nuxtrc: -------------------------------------------------------------------------------- 1 | imports.autoImport=false 2 | typescript.includeWorkspace=true 3 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | 4 | ## v0.1.8 5 | 6 | [compare changes](https://github.com/stevenjpx2/nuxt-split-type/compare/v0.1.7...v0.1.8) 7 | 8 | ### 💅 Refactors 9 | 10 | - Remove use of #imports in files ([36d5d69](https://github.com/stevenjpx2/nuxt-split-type/commit/36d5d69)) 11 | 12 | ### 📖 Documentation 13 | 14 | - **README:** Add playground ([1e32aae](https://github.com/stevenjpx2/nuxt-split-type/commit/1e32aae)) 15 | 16 | ### ❤️ Contributors 17 | 18 | - Steven John 19 | 20 | ## v0.1.7 21 | 22 | [compare changes](https://github.com/stevenjpx2/nuxt-split-type/compare/v0.1.6...v0.1.7) 23 | 24 | ### 🩹 Fixes 25 | 26 | - **deps:** Move vueuse/nuxt to deps from dev ([c7bb550](https://github.com/stevenjpx2/nuxt-split-type/commit/c7bb550)) 27 | 28 | ### ❤️ Contributors 29 | 30 | - Steven John 31 | 32 | ## v0.1.6 33 | 34 | [compare changes](https://github.com/stevenjpx2/nuxt-split-type/compare/v0.1.5...v0.1.6) 35 | 36 | ### 💅 Refactors 37 | 38 | - Change from explicit call to wrapFn to split ([a320c14](https://github.com/stevenjpx2/nuxt-split-type/commit/a320c14)) 39 | 40 | ### 🎨 Styles 41 | 42 | - Make eslint happy ([313febb](https://github.com/stevenjpx2/nuxt-split-type/commit/313febb)) 43 | 44 | ### ❤️ Contributors 45 | 46 | - Steven John 47 | 48 | ## v0.1.5 49 | 50 | [compare changes](https://github.com/stevenjpx2/nuxt-split-type/compare/v0.1.4...v0.1.5) 51 | 52 | ### 🩹 Fixes 53 | 54 | - Remove unecessary computed refs, create SplitType on element mount ([f0ff847](https://github.com/stevenjpx2/nuxt-split-type/commit/f0ff847)) 55 | 56 | ### ❤️ Contributors 57 | 58 | - Steven John 59 | 60 | ## v0.1.4 61 | 62 | [compare changes](https://github.com/stevenjpx2/nuxt-split-type/compare/v0.1.3...v0.1.4) 63 | 64 | ### 🚀 Enhancements 65 | 66 | - Add debounce and refactor types for latest split-type ([79e020b](https://github.com/stevenjpx2/nuxt-split-type/commit/79e020b)) 67 | 68 | ### ❤️ Contributors 69 | 70 | - Steven John 71 | 72 | ## v0.1.3 73 | 74 | [compare changes](https://github.com/stevenjpx2/nuxt-split-type/compare/v0.1.2...v0.1.3) 75 | 76 | ### 📖 Documentation 77 | 78 | - **types:** Added more docs and fixed types ([516ac35](https://github.com/stevenjpx2/nuxt-split-type/commit/516ac35)) 79 | 80 | ### ❤️ Contributors 81 | 82 | - Steven John 83 | 84 | ## v0.1.2 85 | 86 | [compare changes](https://github.com/stevenjpx2/nuxt-split-type/compare/v0.1.1...v0.1.2) 87 | 88 | ### 🩹 Fixes 89 | 90 | - Types ([253ce62](https://github.com/stevenjpx2/nuxt-split-type/commit/253ce62)) 91 | 92 | ### ❤️ Contributors 93 | 94 | - Steven John 95 | 96 | ## v0.1.1 97 | 98 | [compare changes](https://github.com/stevenjpx2/nuxt-split-type/compare/v0.1.0...v0.1.1) 99 | 100 | ### 🩹 Fixes 101 | 102 | - Move split-type to dependency ([aa8ef2b](https://github.com/stevenjpx2/nuxt-split-type/commit/aa8ef2b)) 103 | 104 | ### 💅 Refactors 105 | 106 | - Variable assignment ([172afa3](https://github.com/stevenjpx2/nuxt-split-type/commit/172afa3)) 107 | 108 | ### ❤️ Contributors 109 | 110 | - Steven John 111 | 112 | ## v0.1.0 113 | 114 | [compare changes](https://github.com/stevenjpx2/nuxt-split-type/compare/v0.0.2...v0.1.0) 115 | 116 | ### 🚀 Enhancements 117 | 118 | - ⚠️ Add SplitType native returns to composable output, component props are now reactive ([5448f04](https://github.com/stevenjpx2/nuxt-split-type/commit/5448f04)) 119 | 120 | ### 📖 Documentation 121 | 122 | - Update README with new outputs ([aa90383](https://github.com/stevenjpx2/nuxt-split-type/commit/aa90383)) 123 | 124 | ### 🏡 Chore 125 | 126 | - Add package.json niceties and add warning to README ([6801bda](https://github.com/stevenjpx2/nuxt-split-type/commit/6801bda)) 127 | 128 | #### ⚠️ Breaking Changes 129 | 130 | - ⚠️ Add SplitType native returns to composable output, component props are now reactive ([5448f04](https://github.com/stevenjpx2/nuxt-split-type/commit/5448f04)) 131 | 132 | ### ❤️ Contributors 133 | 134 | - Steven John 135 | 136 | ## v0.0.2 137 | 138 | [compare changes](https://github.com/stevenjpx2/nuxt-split-type/compare/v0.0.1...v0.0.2) 139 | 140 | ### 📖 Documentation 141 | 142 | - Add full docs and push strategy, eslintify ([5f5e28e](https://github.com/stevenjpx2/nuxt-split-type/commit/5f5e28e)) 143 | 144 | ### ❤️ Contributors 145 | 146 | - Steven John 147 | 148 | ## v0.0.1 149 | 150 | 151 | ### 🚀 Enhancements 152 | 153 | - First commit ([6f73727](https://github.com/stevenjpx2/nuxt-split-type/commit/6f73727)) 154 | - Add necessary ingredients ([96121d2](https://github.com/stevenjpx2/nuxt-split-type/commit/96121d2)) 155 | - Made working composable ([2423b7d](https://github.com/stevenjpx2/nuxt-split-type/commit/2423b7d)) 156 | - Create component ([c6766d8](https://github.com/stevenjpx2/nuxt-split-type/commit/c6766d8)) 157 | - Improve component ([1e653b0](https://github.com/stevenjpx2/nuxt-split-type/commit/1e653b0)) 158 | - Add directive ([1fdbbe2](https://github.com/stevenjpx2/nuxt-split-type/commit/1fdbbe2)) 159 | - Add `@complete` and v-slot exposing instance for component, optimise composable ([211a7b3](https://github.com/stevenjpx2/nuxt-split-type/commit/211a7b3)) 160 | 161 | ### 🩹 Fixes 162 | 163 | - **component:** Make props optional ([01dd1be](https://github.com/stevenjpx2/nuxt-split-type/commit/01dd1be)) 164 | - Have composable work in mounted and unmounted context, remove onComplete from return and add to options ([e87615a](https://github.com/stevenjpx2/nuxt-split-type/commit/e87615a)) 165 | 166 | ### 📖 Documentation 167 | 168 | - Update README ([aaac6cc](https://github.com/stevenjpx2/nuxt-split-type/commit/aaac6cc)) 169 | 170 | ### 🏡 Chore 171 | 172 | - Bda update ([4308ecb](https://github.com/stevenjpx2/nuxt-split-type/commit/4308ecb)) 173 | 174 | ### ❤️ Contributors 175 | 176 | - Steven John 177 | 178 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2023 stevenjpx2@gmail.com 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 9 | 10 | # Nuxt SplitType 11 | 12 | > [!NOTE] 13 | > This module is currently pre v1, and might have bugs. Please feel free to open an issue if you see a bug! 14 | 15 | [![npm version][npm-version-src]][npm-version-href] 16 | [![npm downloads][npm-downloads-src]][npm-downloads-href] 17 | [![License][license-src]][license-href] 18 | [![Nuxt][nuxt-src]][nuxt-href] 19 | 20 | [Nuxt][nuxt-href] integration for [SplitType](https://github.com/lukepeavey/SplitType). 21 | 22 | - [✨  Release Notes](/CHANGELOG.md) 23 | - [🏀 Online playground](https://codesandbox.io/p/devbox/charming-leaf-3mct89?layout=%257B%2522sidebarPanel%2522%253A%2522EXPLORER%2522%252C%2522rootPanelGroup%2522%253A%257B%2522direction%2522%253A%2522horizontal%2522%252C%2522contentType%2522%253A%2522UNKNOWN%2522%252C%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522id%2522%253A%2522ROOT_LAYOUT%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522UNKNOWN%2522%252C%2522direction%2522%253A%2522vertical%2522%252C%2522id%2522%253A%2522clr3qtcdc00073b6h4wunverv%2522%252C%2522sizes%2522%253A%255B70%252C30%255D%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522EDITOR%2522%252C%2522direction%2522%253A%2522horizontal%2522%252C%2522id%2522%253A%2522EDITOR%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522contentType%2522%253A%2522EDITOR%2522%252C%2522id%2522%253A%2522clr3qtcdc00023b6ht7nocw3j%2522%257D%255D%257D%252C%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522SHELLS%2522%252C%2522direction%2522%253A%2522horizontal%2522%252C%2522id%2522%253A%2522SHELLS%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522contentType%2522%253A%2522SHELLS%2522%252C%2522id%2522%253A%2522clr3qtcdc00043b6hn5bwdnw6%2522%257D%255D%252C%2522sizes%2522%253A%255B100%255D%257D%255D%257D%252C%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522DEVTOOLS%2522%252C%2522direction%2522%253A%2522vertical%2522%252C%2522id%2522%253A%2522DEVTOOLS%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522contentType%2522%253A%2522DEVTOOLS%2522%252C%2522id%2522%253A%2522clr3qtcdc00063b6h1609gb2f%2522%257D%255D%252C%2522sizes%2522%253A%255B100%255D%257D%255D%252C%2522sizes%2522%253A%255B50%252C50%255D%257D%252C%2522tabbedPanels%2522%253A%257B%2522clr3qtcdc00023b6ht7nocw3j%2522%253A%257B%2522tabs%2522%253A%255B%257B%2522id%2522%253A%2522clr3qtcdc00013b6ho7x1scje%2522%252C%2522mode%2522%253A%2522permanent%2522%252C%2522type%2522%253A%2522FILE%2522%252C%2522filepath%2522%253A%2522%252FREADME.md%2522%257D%255D%252C%2522id%2522%253A%2522clr3qtcdc00023b6ht7nocw3j%2522%252C%2522activeTabId%2522%253A%2522clr3qtcdc00013b6ho7x1scje%2522%257D%252C%2522clr3qtcdc00063b6h1609gb2f%2522%253A%257B%2522id%2522%253A%2522clr3qtcdc00063b6h1609gb2f%2522%252C%2522tabs%2522%253A%255B%257B%2522id%2522%253A%2522clr3qtcdc00053b6hn5in815l%2522%252C%2522mode%2522%253A%2522permanent%2522%252C%2522type%2522%253A%2522TASK_PORT%2522%252C%2522taskId%2522%253A%2522dev%2522%252C%2522port%2522%253A3000%252C%2522path%2522%253A%2522%252F%2522%257D%255D%252C%2522activeTabId%2522%253A%2522clr3qtcdc00053b6hn5in815l%2522%257D%252C%2522clr3qtcdc00043b6hn5bwdnw6%2522%253A%257B%2522id%2522%253A%2522clr3qtcdc00043b6hn5bwdnw6%2522%252C%2522activeTabId%2522%253A%2522clr3r7t3h00wf3b6hgv4d7ahy%2522%252C%2522tabs%2522%253A%255B%257B%2522type%2522%253A%2522TASK_LOG%2522%252C%2522taskId%2522%253A%2522dev%2522%252C%2522id%2522%253A%2522clr3r7t3h00wf3b6hgv4d7ahy%2522%252C%2522mode%2522%253A%2522permanent%2522%257D%255D%257D%257D%252C%2522showDevtools%2522%253Atrue%252C%2522showShells%2522%253Atrue%252C%2522showSidebar%2522%253Atrue%252C%2522sidebarPanelSize%2522%253A15%257D) 24 | - [📖  Documentation](#usage) 25 | 26 | ## Features 27 | 28 | 29 | - ⛰ Activate SplitType however you want: directive, component or composable 30 | - 💪 Full Typescript support, including improvements on the original SplitType library. 31 | - ✨ Special `wrapping` selector to wrap either lines, words or chars with a special HTML element with defined classes 32 | - 🚠 Callback for SpiltType Proxy 33 | 34 | ## Quick Setup 35 | 36 | 1. Add `nuxt-split-type` dependency to your project 37 | 38 | ```bash 39 | # Using pnpm 40 | pnpm add -D nuxt-split-type 41 | 42 | # Using yarn 43 | yarn add --dev nuxt-split-type 44 | 45 | # Using npm 46 | npm install --save-dev nuxt-split-type 47 | ``` 48 | 49 | 2. Add `nuxt-split-type` to the `modules` section of `nuxt.config.ts` 50 | 51 | ```js 52 | export default defineNuxtConfig({ 53 | modules: [ 54 | 'nuxt-split-type' 55 | ] 56 | }) 57 | ``` 58 | 59 | That's it! You can now use Nuxt SplitType in your Nuxt app ✨ 60 | 61 | ## Usage 62 | 63 | ### Composable 64 | ```vue 65 | 80 | 81 | 84 | ``` 85 | 86 | ### Component 87 | ```vue 88 | 99 | ``` 100 | 101 | ### Directive 102 | ```vue 103 | 108 | 109 | ``` 110 | 111 | ## Development 112 | 113 | ```bash 114 | # Install dependencies 115 | npm install 116 | 117 | # Generate type stubs 118 | npm run dev:prepare 119 | 120 | # Develop with the playground 121 | npm run dev 122 | 123 | # Build the playground 124 | npm run dev:build 125 | 126 | # Run ESLint 127 | npm run lint 128 | 129 | # Run Vitest 130 | npm run test 131 | npm run test:watch 132 | 133 | # Release new version 134 | npm run release 135 | ``` 136 | 137 | 138 | [npm-version-src]: https://img.shields.io/npm/v/nuxt-split-type/latest.svg?style=flat&colorA=18181B&colorB=28CF8D 139 | [npm-version-href]: https://npmjs.com/package/nuxt-split-type 140 | 141 | [npm-downloads-src]: https://img.shields.io/npm/dm/nuxt-split-type.svg?style=flat&colorA=18181B&colorB=28CF8D 142 | [npm-downloads-href]: https://npmjs.com/package/nuxt-split-type 143 | 144 | [license-src]: https://img.shields.io/npm/l/nuxt-split-type.svg?style=flat&colorA=18181B&colorB=28CF8D 145 | [license-href]: https://npmjs.com/package/nuxt-split-type 146 | 147 | [nuxt-src]: https://img.shields.io/badge/Nuxt-18181B?logo=nuxt.js 148 | [nuxt-href]: https://nuxt.com 149 | -------------------------------------------------------------------------------- /bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StevenJPx2/nuxt-split-type/e9bbe4bc66588c68a411920f99723de7be2077bb/bun.lockb -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nuxt-split-type", 3 | "version": "0.1.8", 4 | "description": "Nuxt SplitType", 5 | "repository": "stevenjpx2/nuxt-split-type", 6 | "license": "MIT", 7 | "type": "module", 8 | "keywords": [ 9 | "nuxt", 10 | "nuxt-module", 11 | "gsap", 12 | "splittingjs", 13 | "splitting", 14 | "splittype", 15 | "split-type", 16 | "split type", 17 | "nuxt-split-type" 18 | ], 19 | "homepage": "https://github.com/stevenjpx2/nuxt-split-type", 20 | "bugs": { 21 | "url": "https://github.com/stevenjpx2/nuxt-split-type/issues" 22 | }, 23 | "exports": { 24 | ".": { 25 | "types": "./dist/types.d.ts", 26 | "import": "./dist/module.mjs", 27 | "require": "./dist/module.cjs" 28 | } 29 | }, 30 | "main": "./dist/module.cjs", 31 | "types": "./dist/types.d.ts", 32 | "files": [ 33 | "dist" 34 | ], 35 | "scripts": { 36 | "prepack": "nuxt-module-build", 37 | "dev": "nuxi dev playground", 38 | "dev:build": "nuxi build playground", 39 | "dev:prepare": "nuxt-module-build --stub && nuxi prepare playground", 40 | "release": "npm run lint && npm run test && npm run prepack && changelogen --release && npm publish && git push --follow-tags", 41 | "lint": "eslint .", 42 | "test": "vitest run", 43 | "test:watch": "vitest watch" 44 | }, 45 | "dependencies": { 46 | "@nuxt/kit": "^3.11.2", 47 | "@vueuse/nuxt": "^10.9.0", 48 | "@vueuse/shared": "^10.9.0", 49 | "@vueuse/core": "^10.9.0", 50 | "split-type": "^0.3.4", 51 | "typescript": "^5.4.5" 52 | }, 53 | "devDependencies": { 54 | "@nuxt/devtools": "latest", 55 | "@nuxt/eslint-config": "^0.2.0", 56 | "@nuxt/module-builder": "^0.5.5", 57 | "@nuxt/schema": "^3.11.2", 58 | "@nuxt/test-utils": "^3.12.1", 59 | "@types/node": "^18.19.33", 60 | "changelogen": "^0.5.5", 61 | "eslint": "^8.57.0", 62 | "nuxt": "^3.11.2", 63 | "vitest": "^0.33.0" 64 | } 65 | } -------------------------------------------------------------------------------- /playground/app.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 52 | 53 | 58 | -------------------------------------------------------------------------------- /playground/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtConfig({ 2 | modules: ["../src/module"], 3 | devtools: { enabled: true }, 4 | }); 5 | -------------------------------------------------------------------------------- /playground/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "my-module-playground", 4 | "type": "module", 5 | "scripts": { 6 | "dev": "nuxi dev", 7 | "build": "nuxi build", 8 | "generate": "nuxi generate" 9 | }, 10 | "devDependencies": { 11 | "nuxt": "latest" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /playground/server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../.nuxt/tsconfig.server.json" 3 | } 4 | -------------------------------------------------------------------------------- /playground/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.nuxt/tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /src/module.ts: -------------------------------------------------------------------------------- 1 | import { 2 | addComponent, 3 | addImports, 4 | addPlugin, 5 | createResolver, 6 | defineNuxtModule, 7 | installModule, 8 | } from "@nuxt/kit"; 9 | 10 | import { name, version } from "../package.json"; 11 | 12 | // Module options TypeScript interface definition 13 | export type ModuleOptions = Record; 14 | 15 | export default defineNuxtModule({ 16 | meta: { 17 | name, 18 | version, 19 | configKey: "splitType", 20 | }, 21 | // Default configuration options of the Nuxt module 22 | defaults: {}, 23 | async setup() { 24 | const resolver = createResolver(import.meta.url); 25 | 26 | // Do not add the extension since the `.ts` will be transpiled to `.mjs` after `npm run prepack` 27 | addPlugin(resolver.resolve("./runtime/plugin")); 28 | addImports({ 29 | name: "useSplitText", 30 | as: "useSplitText", 31 | from: resolver.resolve("./runtime/composable"), 32 | }); 33 | addComponent({ 34 | name: "SplitText", 35 | filePath: resolver.resolve("./runtime/component"), 36 | }); 37 | 38 | await installModule("@vueuse/nuxt", {}); 39 | }, 40 | }); 41 | 42 | export { vSplitText } from "./runtime/directive"; 43 | export { useSplitText } from "./runtime/composable"; 44 | export type { 45 | UseSplitTextReturn, 46 | UseSplitTextOptions, 47 | } from "./runtime/composable"; 48 | -------------------------------------------------------------------------------- /src/runtime/component.vue: -------------------------------------------------------------------------------- 1 | 78 | 79 | 84 | -------------------------------------------------------------------------------- /src/runtime/composable.ts: -------------------------------------------------------------------------------- 1 | import type { MaybeComputedElementRef } from "@vueuse/core"; 2 | import { 3 | tryOnScopeDispose, 4 | unrefElement, 5 | useDebounceFn, 6 | useEventListener, 7 | } from "@vueuse/core"; 8 | import { 9 | default as SplitType, 10 | type SplitTypeOptions, 11 | type TypesValue, 12 | } from "split-type"; 13 | import { type ComputedRef, type Ref, computed, ref, watch } from "vue"; 14 | import type { TypeOptions } from "./types"; 15 | 16 | export type UseSplitTextOptions = { 17 | /** The types of splits to apply to the target element 18 | * @example `["lines", "words", "chars"]` 19 | * 20 | * */ 21 | splitBy: TypeOptions; 22 | /** 23 | * The wrapping options 24 | * @default undefined 25 | * @example 26 | * ```ts 27 | * { 28 | * select: "lines", 29 | * wrapType: "span", 30 | * wrapClass: "inline-block" 31 | * selectElClass: "h-fit origin-top-left" 32 | * } 33 | * ``` 34 | */ 35 | wrapping?: { 36 | /** The type of element to wrap with - {HTMLTag} */ 37 | wrapType?: keyof HTMLElementTagNameMap; 38 | /** The class to apply to the selected elements */ 39 | wrapClass?: string; 40 | /** The type of split to apply the wrapping to */ 41 | select: TypesValue[number]; 42 | /** The class to apply to the wrapping element */ 43 | selectElClass?: string; 44 | }; 45 | /** 46 | * The callback to run after the split has completed 47 | * @param `instanceVal` - The instance of SplitType 48 | * @default undefined 49 | * @example 50 | * ```ts 51 | * (instanceVal) => { 52 | * instanceVal.words?.forEach((el) => (el.style.display = "inline-flex")); 53 | * } 54 | * ``` 55 | * */ 56 | onComplete?: (instanceVal: SplitType) => void; 57 | /** 58 | * The options to pass to the SplitType instance 59 | * @default undefined 60 | * @example 61 | * ```ts 62 | * { 63 | * splitClass: "splitted" 64 | * } 65 | * ``` 66 | * */ 67 | splitOptions?: Partial>; 68 | }; 69 | 70 | export type UseSplitTextReturn = { 71 | /** The instance of SplitType as a ref 72 | * */ 73 | instance: Ref; 74 | /** The lines of the split as a ref 75 | * @remarks It will be null if `lines` is not included in `splitBy` 76 | * */ 77 | lines: ComputedRef; 78 | /** The words of the split as a ref 79 | * @remarks It will be null if `words` is not included in `splitBy` 80 | * */ 81 | words: ComputedRef; 82 | /** The chars of the split as a ref 83 | * @remarks It will be null if `chars` is not included in `splitBy` 84 | * */ 85 | chars: ComputedRef; 86 | /** The split function 87 | * @param `options` - The options to pass to the SplitType instance 88 | * @remarks This function will split the target element 89 | * Useful for splitting the element again after a resize event 90 | * This is done automatically on resize 91 | * */ 92 | split: (options: Partial) => void; 93 | /** The revert function 94 | * @remarks This function will revert the target element 95 | * Automatically called on component unmount 96 | * */ 97 | revert: () => void; 98 | }; 99 | 100 | export function useSplitText( 101 | target: MaybeComputedElementRef, 102 | options: UseSplitTextOptions, 103 | ): UseSplitTextReturn { 104 | const instance = ref(); 105 | const lines = computed(() => instance.value?.lines); 106 | const words = computed(() => instance.value?.words); 107 | const chars = computed(() => instance.value?.chars); 108 | const split = (options: Partial) => { 109 | instance.value?.split(options); 110 | if (!!instance.value && !!wrapping) wrapFn(instance.value); 111 | }; 112 | const revert = () => instance.value?.revert(); 113 | const { splitBy, wrapping, onComplete } = options; 114 | const wrapFn = (instance: SplitType) => { 115 | if ((["chars", "words"] as const).every((sp) => splitBy.includes(sp))) 116 | for (const el of instance.words ?? []) { 117 | el.style.display = "inline-flex"; 118 | } 119 | 120 | if (!wrapping) return; 121 | instance[wrapping.select]?.forEach((childEl, index) => { 122 | const wrapEl = document.createElement(wrapping.wrapType ?? "span"); 123 | if (wrapping.selectElClass) 124 | childEl.classList.add(...wrapping.selectElClass.split(" ")); 125 | if (wrapping.wrapClass) 126 | wrapEl.classList.add(...wrapping.wrapClass.split(" ")); 127 | wrapEl.dataset[`${wrapping.select}Index`] = `${index}`; 128 | childEl.parentNode?.appendChild(wrapEl); 129 | wrapEl.appendChild(childEl); 130 | }); 131 | }; 132 | 133 | watch( 134 | () => unrefElement(target), 135 | (el) => { 136 | if (!el) return; 137 | instance.value = new SplitType(el as HTMLElement, { 138 | types: splitBy, 139 | ...options.splitOptions, 140 | }); 141 | split({}); 142 | onComplete?.(instance.value); 143 | }, 144 | { immediate: true, flush: "post" }, 145 | ); 146 | 147 | const resizeFn = useDebounceFn(() => { 148 | split({}); 149 | }, 500); 150 | 151 | useEventListener("resize", resizeFn, { passive: true }); 152 | 153 | tryOnScopeDispose(revert); 154 | 155 | return { 156 | instance, 157 | lines, 158 | words, 159 | chars, 160 | split, 161 | revert, 162 | }; 163 | } 164 | -------------------------------------------------------------------------------- /src/runtime/directive.ts: -------------------------------------------------------------------------------- 1 | import { directiveHooks } from "@vueuse/core"; 2 | import type SplitType from "split-type"; 3 | import type { ObjectDirective } from "vue"; 4 | import { useSplitText } from "./composable"; 5 | import type { UseSplitTextOptions } from "./composable"; 6 | 7 | type VSplitTextOptions = UseSplitTextOptions & { 8 | /** Callback when the split is complete */ 9 | onComplete?: (instance: SplitType) => void; 10 | }; 11 | 12 | export const vSplitText: ObjectDirective = { 13 | [directiveHooks.mounted]: (el, binding) => { 14 | const { value } = binding; 15 | useSplitText(el, value); 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /src/runtime/plugin.ts: -------------------------------------------------------------------------------- 1 | import { defineNuxtPlugin } from "#app"; 2 | import { vSplitText } from "./directive"; 3 | export { vSplitText }; 4 | 5 | export default defineNuxtPlugin((nuxt) => { 6 | nuxt.vueApp.directive("split-text", vSplitText); 7 | }); 8 | -------------------------------------------------------------------------------- /src/runtime/types.ts: -------------------------------------------------------------------------------- 1 | import type { MaybeRef, MaybeRefOrGetter, Mutable } from "@vueuse/core"; 2 | import type { ComponentPublicInstance } from "vue"; 3 | 4 | type StringedCombination< 5 | T extends string[], 6 | Sep extends string = " ", 7 | All = T[number], 8 | Item = All, 9 | > = Item extends string 10 | ? Item | `${Item}${Sep}${StringedCombination<[], Sep, Exclude>}` 11 | : never; 12 | 13 | export const TypesValue = ["lines", "words", "chars"] as const; 14 | export type TypesValue = Mutable; 15 | export type TypesValueUnion = TypesValue[number]; 16 | 17 | export type TypesListString = StringedCombination; 18 | export type TypesValueTuple = 19 | | [TypesValueUnion, TypesValueUnion, TypesValueUnion] 20 | | [TypesValueUnion, TypesValueUnion] 21 | | [TypesValueUnion]; 22 | export type TypeOptions = TypesListString | TypesValueTuple; 23 | 24 | export type VueInstance = ComponentPublicInstance; 25 | export type MaybeElementRef = 26 | MaybeRef; 27 | export type MaybeComputedElementRef = 28 | MaybeRefOrGetter; 29 | export type MaybeElement = HTMLElement | VueInstance | undefined | null; 30 | 31 | export type { UseSplitTextReturn, UseSplitTextOptions } from "./composable"; 32 | -------------------------------------------------------------------------------- /test/basic.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from 'vitest' 2 | import { fileURLToPath } from 'node:url' 3 | import { setup, $fetch } from '@nuxt/test-utils' 4 | 5 | describe('ssr', async () => { 6 | await setup({ 7 | rootDir: fileURLToPath(new URL('./fixtures/basic', import.meta.url)), 8 | }) 9 | 10 | it('renders the index page', async () => { 11 | // Get response to a server-rendered page with `$fetch`. 12 | const html = await $fetch('/') 13 | expect(html).toContain('
basic
') 14 | }) 15 | }) 16 | -------------------------------------------------------------------------------- /test/fixtures/basic/app.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 7 | -------------------------------------------------------------------------------- /test/fixtures/basic/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | import MyModule from '../../../src/module' 2 | 3 | export default defineNuxtConfig({ 4 | modules: [ 5 | MyModule 6 | ] 7 | }) 8 | -------------------------------------------------------------------------------- /test/fixtures/basic/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "basic", 4 | "type": "module" 5 | } 6 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./playground/.nuxt/tsconfig.json" 3 | } 4 | --------------------------------------------------------------------------------