├── .github └── workflows │ ├── ci.yml │ └── release.yml ├── .gitignore ├── .npmrc ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── README.zh-CN.md ├── build.config.ts ├── eslint.config.js ├── package.json ├── playground ├── .gitignore ├── favicon.svg ├── index.html ├── package.json ├── src │ ├── main.ts │ ├── style.css │ └── vite-env.d.ts ├── tsconfig.json ├── unocss.config.ts └── vite.config.ts ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── src └── index.ts ├── test ├── __snapshots__ │ ├── index-compatible.test.ts.snap │ └── index.test.ts.snap ├── index-compatible.test.ts └── index.test.ts └── tsconfig.json /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | pull_request: 9 | branches: 10 | - main 11 | 12 | jobs: 13 | lint: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v4 17 | 18 | - name: Set node LTS 19 | uses: actions/setup-node@v4 20 | with: 21 | node-version: lts/* 22 | 23 | - name: Install pnpm 24 | uses: pnpm/action-setup@v4 25 | 26 | - name: Setup 27 | run: npm i -g @antfu/ni 28 | 29 | - name: Install 30 | run: nci 31 | 32 | - name: Lint 33 | run: nr lint 34 | 35 | typecheck: 36 | runs-on: ubuntu-latest 37 | steps: 38 | - uses: actions/checkout@v4 39 | 40 | - name: Set node LTS 41 | uses: actions/setup-node@v4 42 | with: 43 | node-version: lts/* 44 | 45 | - name: Install pnpm 46 | uses: pnpm/action-setup@v4 47 | 48 | - name: Setup 49 | run: npm i -g @antfu/ni 50 | 51 | - name: Install 52 | run: nci 53 | 54 | - name: Typecheck 55 | run: nr typecheck 56 | 57 | test: 58 | runs-on: ${{ matrix.os }} 59 | 60 | strategy: 61 | matrix: 62 | os: [ubuntu-latest] 63 | node_version: [18.18.2, lts/*] 64 | include: 65 | - os: macos-latest 66 | node_version: lts/* 67 | - os: windows-latest 68 | node_version: lts/* 69 | fail-fast: false 70 | 71 | steps: 72 | - uses: actions/checkout@v4 73 | 74 | - name: Set node LTS 75 | uses: actions/setup-node@v4 76 | with: 77 | node-version: lts/* 78 | 79 | - name: Install pnpm 80 | uses: pnpm/action-setup@v4 81 | 82 | - name: Setup 83 | run: npm i -g @antfu/ni 84 | 85 | - name: Install 86 | run: nci 87 | 88 | - name: Build 89 | run: nr build 90 | 91 | - name: Test 92 | run: nr test 93 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*' 7 | 8 | jobs: 9 | release: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | 14 | - name: Install pnpm 15 | uses: pnpm/action-setup@v4 16 | 17 | - name: Set node LTS 18 | uses: actions/setup-node@v4 19 | with: 20 | node-version: lts/* 21 | 22 | - run: npx conventional-github-releaser -p angular 23 | env: 24 | CONVENTIONAL_GITHUB_RELEASER_TOKEN: ${{secrets.GITHUB_TOKEN}} 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .cache 2 | .DS_Store 3 | .idea 4 | *.log 5 | *.tgz 6 | coverage 7 | dist 8 | lib-cov 9 | logs 10 | node_modules 11 | temp 12 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | # https://github.com/unjs/unbuild/issues/54#issuecomment-1076223275 2 | 3 | shamefully-hoist = true 4 | ignore-workspace-root-check = true -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "unocss.root": "playground" 3 | } 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 kkopite 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 | # unocss-preset-scrollbar 2 | 3 | [![NPM version](https://img.shields.io/npm/v/unocss-preset-scrollbar?color=a1b858&label=)](https://www.npmjs.com/package/unocss-preset-scrollbar) ![npm](https://img.shields.io/npm/dw/unocss-preset-scrollbar) 4 | 5 | a [unocss](https://github.com/unocss/unocss) preset for scrollbar,here is a [demo](https://stackblitz.com/edit/vitejs-vite-gyun7j?file=index.html) 6 | 7 | English | [简体中文](./README.zh-CN.md) 8 | 9 | ## Installation 10 | 11 | ```bash 12 | npm i unocss-preset-scrollbar unocss -D 13 | ``` 14 | 15 | ## Usage 16 | 17 | ```ts 18 | // unocss.config.ts 19 | import { defineConfig, presetAttributify, presetUno } from 'unocss' 20 | import { presetScrollbar } from 'unocss-preset-scrollbar' 21 | 22 | export default defineConfig({ 23 | presets: [ 24 | presetUno(), 25 | presetAttributify(), 26 | presetScrollbar({ 27 | // config 28 | }), 29 | ], 30 | }) 31 | ``` 32 | 33 | ```html 34 |
37 | ``` 38 | 39 | it will generate below css: 40 | 41 | ```css 42 | /* layer: shortcuts */ 43 | .scrollbar::-webkit-scrollbar{width:var(--scrollbar-width);height:var(--scrollbar-height);} 44 | .scrollbar{overflow:auto;scrollbar-color:var(--scrollbar-thumb) var(--scrollbar-track);--scrollbar-track:#f5f5f5;--scrollbar-thumb:#ddd;--scrollbar-width:8px;--scrollbar-height:8px;--scrollbar-track-radius:4px;--scrollbar-thumb-radius:4px;} 45 | .scrollbar-rounded::-webkit-scrollbar-thumb{border-radius:var(--scrollbar-thumb-radius);} 46 | .scrollbar-rounded::-webkit-scrollbar-track{border-radius:var(--scrollbar-track-radius);} 47 | .scrollbar::-webkit-scrollbar-thumb{background-color:var(--scrollbar-thumb);} 48 | .scrollbar::-webkit-scrollbar-track{background-color:var(--scrollbar-track);} 49 | /* layer: default */ 50 | .scrollbar-radius-2{--scrollbar-track-radius:0.5rem;--scrollbar-thumb-radius:0.5rem;} 51 | .scrollbar-thumb-radius-4{--scrollbar-thumb-radius:1rem;} 52 | .scrollbar-track-radius-4{--scrollbar-track-radius:1rem;} 53 | .scrollbar-w-4px{--scrollbar-width:4px;} 54 | ``` 55 | 56 | you can also use [`Attributify Mode`](https://github.com/unocss/unocss/tree/main/packages/preset-attributify): 57 | 58 | ```html 59 |
62 | ``` 63 | 64 | or use `@apply` 65 | 66 | ```diff 67 | import { defineConfig, presetAttributify, presetUno, transformerDirectives } from 'unocss' 68 | import { presetScrollbar } from 'unocss-preset-scrollbar' 69 | 70 | export default defineConfig({ 71 | presets: [ 72 | presetUno(), 73 | presetAttributify(), 74 | presetScrollbar({ 75 | }), 76 | ], 77 | + transformers: [ 78 | + transformerDirectives(), 79 | + ], 80 | }) 81 | ``` 82 | 83 | ```css 84 | .my-custom-scrollbar { 85 | @apply scrollbar scrollbar-rounded 86 | } 87 | ``` 88 | 89 | ## Configurations 90 | 91 | |Field|Default|Description| 92 | |--|--|--| 93 | |`scrollbarWidth`|`8px`|default scrollbar width| 94 | |`scrollbarHeight`|`8px`|default scrollbar height| 95 | |`scrollbarTrackRadius`|`4px`|default scrollbar track radius| 96 | |`scrollbarThumbRadius`|`4px`|default scrollbar thumb radius| 97 | |`scrollbarTrackColor`|`#f5f5f5`|default scrollbar track background color| 98 | |`scrollbarThumbColor`|`#ddd`|default scrollbar thumb background color| 99 | |`numberToUnit`|``value => `${value / 4}rem` ``| number to unit 100 | |`varPrefix`|`''`|the css variable prefix of this preset| 101 | |`prefix`|`''`|Apply prefix to all utilities and shortcuts| 102 | |`noCompatible`|`'true'`|if `false`, it use `scrollbar-width` and `scrollbar-color`,work in Firefox, but `scrollbar-h`, `scrollbar-w` and `scrollbar-radius` will not work | 103 | 104 | for example 105 | 106 | ```html 107 |
108 | ``` 109 | 110 | if we use default options,`scrollbar-w-4` will generate `--scrollbar-width: 1rem` 111 | 112 | if we set custom `numberToUnit`: 113 | 114 | ```ts 115 | export default defineConfig({ 116 | presets: [ 117 | presetUno(), 118 | presetScrollbar({ 119 | numberToUnit: value => `${value}px`, 120 | }), 121 | ], 122 | }) 123 | ``` 124 | 125 | will generate `--scrollbar-width: 4px` 126 | 127 | ## Utilities 128 | 129 | ### scrollbar 130 | 131 | `scrollbar-thin` 132 | 133 | ```css 134 | .scrollbar-thin { 135 | scrollbar-width: thin; // if noCompatible is true, remove this line 136 | --un-scrollbar-width: 8px; 137 | --un-scrollbar-height: 8px; 138 | } 139 | ``` 140 | 141 | `scrollbar-none` 142 | 143 | ```css 144 | .scrollbar-none { 145 | scrollbar-width: none; 146 | } 147 | 148 | .scrollbar-none::-webkit-scrollbar { 149 | display:none; 150 | } 151 | ``` 152 | 153 | ### rounded 154 | 155 | `scrollbar-rounded` 156 | 157 | Make thumb and track have rounded corners 158 | 159 | ### color 160 | 161 | `scrollbar-(track|thumb)-color-` 162 | 163 | set track or thumb background color 164 | 165 | ### size 166 | 167 | `scrollbar-(radius|w|h|track-radius|thumb-radius)-(\d+?)([a-zA-Z]*?)` 168 | 169 | |type|description| 170 | |--|--| 171 | |radius|set thumb radius and track radius| 172 | |w|[set scrollbar width](https://developer.mozilla.org/en-US/docs/Web/CSS/::-webkit-scrollbar)| 173 | |h|[set scrollbar height](https://developer.mozilla.org/en-US/docs/Web/CSS/::-webkit-scrollbar)| 174 | |track-radius|set track radius| 175 | |thumb-radius|set thumb radius| 176 | 177 | **Attention,**if it ends with number,the preset will use numberToUnit to generate length with number as params,Otherwise it will use the captured length information directly 178 | 179 | for example: 180 | - `scrollbar-w-4` will be `--scrollbar-width: 1rem` 181 | - `scrollbar-w-4px` will be `--scrollbar-width: 4px` 182 | - `scrollbar-w-4rem` will be `--scrollbar-width: 4rem` 183 | 184 | ::: warning 185 | if set `noCompatible` value `false`,it not work 186 | ::: 187 | 188 | ## other 189 | 190 | base [starter-ts](https://github.com/antfu/starter-ts) 191 | 192 | ## License 193 | 194 | [MIT](./LICENSE) License © 2021 [kkopite](https://github.com/action-hong) 195 | -------------------------------------------------------------------------------- /README.zh-CN.md: -------------------------------------------------------------------------------- 1 | # unocss-preset-scrollbar 2 | 3 | [![NPM version](https://img.shields.io/npm/v/unocss-preset-scrollbar?color=a1b858&label=)](https://www.npmjs.com/package/unocss-preset-scrollbar) ![npm](https://img.shields.io/npm/dw/unocss-preset-scrollbar) 4 | 5 | [`unocss`](https://github.com/unocss/unocss) 的滚动预设,[一个简单的实例](https://stackblitz.com/edit/vitejs-vite-gyun7j?file=index.html) 6 | 7 | 简体中文 | [English](./README.md) 8 | 9 | ## 安装 10 | 11 | ```bash 12 | npm i unocss-preset-scrollbar unocss -D 13 | ``` 14 | 15 | ## 使用 16 | 17 | ```ts 18 | // unocss.config.ts 19 | import { defineConfig, presetAttributify, presetUno } from 'unocss' 20 | import { presetScrollbar } from 'unocss-preset-scrollbar' 21 | 22 | export default defineConfig({ 23 | presets: [ 24 | presetUno(), 25 | presetAttributify(), 26 | presetScrollbar({ 27 | // config 28 | }), 29 | ], 30 | }) 31 | ``` 32 | 33 | ```html 34 |
37 | ``` 38 | 39 | 上述代码将生成如下的 css 代码: 40 | 41 | ```css 42 | /* layer: shortcuts */ 43 | .scrollbar::-webkit-scrollbar{width:var(--scrollbar-width);height:var(--scrollbar-height);} 44 | .scrollbar{overflow:auto;scrollbar-color:var(--scrollbar-thumb) var(--scrollbar-track);--scrollbar-track:#f5f5f5;--scrollbar-thumb:#ddd;--scrollbar-width:8px;--scrollbar-height:8px;--scrollbar-track-radius:4px;--scrollbar-thumb-radius:4px;} 45 | .scrollbar-rounded::-webkit-scrollbar-thumb{border-radius:var(--scrollbar-thumb-radius);} 46 | .scrollbar-rounded::-webkit-scrollbar-track{border-radius:var(--scrollbar-track-radius);} 47 | .scrollbar::-webkit-scrollbar-thumb{background-color:var(--scrollbar-thumb);} 48 | .scrollbar::-webkit-scrollbar-track{background-color:var(--scrollbar-track);} 49 | /* layer: default */ 50 | .scrollbar-radius-2{--scrollbar-track-radius:0.5rem;--scrollbar-thumb-radius:0.5rem;} 51 | .scrollbar-thumb-radius-4{--scrollbar-thumb-radius:1rem;} 52 | .scrollbar-track-radius-4{--scrollbar-track-radius:1rem;} 53 | .scrollbar-w-4px{--scrollbar-width:4px;} 54 | ``` 55 | 56 | 你也可以使用 [`Attributify Mode`](https://github.com/unocss/unocss/tree/main/packages/preset-attributify): 57 | 58 | ```html 59 |
62 | ``` 63 | 64 | 或者使用 `@apply` 65 | 66 | ```diff 67 | import { defineConfig, presetAttributify, presetUno, transformerDirectives } from 'unocss' 68 | import { presetScrollbar } from 'unocss-preset-scrollbar' 69 | 70 | export default defineConfig({ 71 | presets: [ 72 | presetUno(), 73 | presetAttributify(), 74 | presetScrollbar({ 75 | }), 76 | ], 77 | + transformers: [ 78 | + transformerDirectives(), 79 | + ], 80 | }) 81 | ``` 82 | 83 | ```css 84 | .my-custom-scrollbar { 85 | @apply scrollbar scrollbar-rounded 86 | } 87 | ``` 88 | 89 | ## 配置 90 | 91 | |配置项|默认值|说明| 92 | |--|--|--| 93 | |`scrollbarWidth`|`8px`|默认的滚动条宽度| 94 | |`scrollbarHeight`|`8px`|默认的滚动条高度| 95 | |`scrollbarTrackRadius`|`4px`|默认的滚动条轨迹的圆角| 96 | |`scrollbarThumbRadius`|`4px`|默认的滚动条滑块的圆角| 97 | |`scrollbarTrackColor`|`#f5f5f5`|默认的滚动条轨迹的背景色| 98 | |`scrollbarThumbColor`|`#ddd`|默认的滚动条滑块的背景色| 99 | |`numberToUnit`|``value => `${value / 4}rem` ``|捕获到的数字转化成单位的方法| 100 | |`varPrefix`|`''`|该预设生成的`css`变量的前缀| 101 | |`prefix`|`''`|该预设生成的shortcuts加上前缀| 102 | |`noCompatible`|`'true'`|如果为 `false` 的话 会使用 `scrollbar-width` 和 `scrollbar-color` 这两个规则,能够在Firefox上兼容, 但是`scrollbar-h`、`scrollbar-w` 以及 `scrollbar-raidus` 会失效 | 103 | 104 | 举个例子 105 | 106 | ```html 107 |
108 | ``` 109 | 110 | 如果你使用默认的配置,`scrollbar-w-4` 将会转化成 `--scrollbar-width: 1rem` 111 | 112 | 而如果你自定义 `numberToUnit` 项: 113 | 114 | ```ts 115 | export default defineConfig({ 116 | presets: [ 117 | presetUno(), 118 | presetScrollbar({ 119 | numberToUnit: value => `${value}px`, 120 | }), 121 | ], 122 | }) 123 | ``` 124 | 125 | 将转化成 `--scrollbar-width: 4px` 126 | 127 | ## 规则 128 | 129 | ### scrollbar 130 | 131 | `scrollbar-thin` 132 | 133 | ```css 134 | .scrollbar-thin { 135 | scrollbar-width: thin; // 如果 noCompatible 为 true, 则不会生成该行 136 | --un-scrollbar-width: 8px; 137 | --un-scrollbar-height: 8px; 138 | } 139 | ``` 140 | 141 | `scrollbar-none` 142 | 143 | ```css 144 | .scrollbar-none { 145 | scrollbar-width: none; 146 | } 147 | 148 | .scrollbar-none::-webkit-scrollbar { 149 | display:none; 150 | } 151 | ``` 152 | 153 | ### rounded 154 | 155 | `scrollbar-rounded` 156 | 157 | 使滚动条有圆角 158 | 159 | ### 颜色 160 | 161 | `scrollbar-(track|thumb)-color-` 162 | 163 | 设置轨迹或滑块的背景色 164 | 165 | ### size 166 | 167 | `scrollbar-(radius|w|h|track-radius|thumb-radius)-(\d+?)([a-zA-Z]*?)` 168 | 169 | |对应key|说明| 170 | |--|--| 171 | |raidus|设置轨迹和滑块的圆角| 172 | |w|[设置滚动条宽度](https://developer.mozilla.org/en-US/docs/Web/CSS/::-webkit-scrollbar)| 173 | |h|[设置滚动条高度](https://developer.mozilla.org/en-US/docs/Web/CSS/::-webkit-scrollbar)| 174 | |track-radius|设置轨迹圆角| 175 | |thumb-radius|设置滑块圆角| 176 | 177 | > **注意**如果以数字结尾,则会通过 `numberToUnit` 转化成带有单位的长度,反之直接生成对应的单位长度。 178 | 179 | > **注意**想要设置滚动条的圆角,必须先使用 `scrollbar-rounded` 180 | 181 | 例如: 182 | - `scrollbar-w-4` -> `--scrollbar-width: 1rem` 183 | - `scrollbar-w-4px` -> `--scrollbar-width: 4px` 184 | - `scrollbar-w-4rem` -> `--scrollbar-width: 4rem` 185 | 186 | ## other 187 | 188 | base [starter-ts](https://github.com/antfu/starter-ts) 189 | 190 | ## License 191 | 192 | [MIT](./LICENSE) License © 2021 [kkopite](https://github.com/action-hong) 193 | -------------------------------------------------------------------------------- /build.config.ts: -------------------------------------------------------------------------------- 1 | import { defineBuildConfig } from 'unbuild' 2 | 3 | export default defineBuildConfig({ 4 | entries: [ 5 | 'src/index', 6 | ], 7 | declaration: true, 8 | clean: true, 9 | rollup: { 10 | emitCJS: true, 11 | }, 12 | externals: [ 13 | 'unocss', 14 | ], 15 | }) 16 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | import antfu from '@antfu/eslint-config' 2 | 3 | export default antfu() 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "unocss-preset-scrollbar", 3 | "type": "module", 4 | "version": "3.2.0", 5 | "packageManager": "pnpm@9.15.4", 6 | "description": "unocss preset for scrollbar", 7 | "author": "kkopite ", 8 | "license": "MIT", 9 | "homepage": "https://github.com/action-hong/unocss-preset-scrollbar#readme", 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/action-hong/unocss-preset-scrollbar.git" 13 | }, 14 | "bugs": { 15 | "url": "https://github.com/action-hong/unocss-preset-scrollbar/issues" 16 | }, 17 | "keywords": [ 18 | "unocss", 19 | "unocss-preset", 20 | "scrollbar", 21 | "unocss-preset-scrollbar" 22 | ], 23 | "sideEffects": false, 24 | "exports": { 25 | ".": { 26 | "types": "./dist/index.d.ts", 27 | "import": "./dist/index.mjs", 28 | "require": "./dist/index.cjs" 29 | } 30 | }, 31 | "main": "./dist/index.cjs", 32 | "module": "./dist/index.mjs", 33 | "types": "./dist/index.d.ts", 34 | "files": [ 35 | "dist" 36 | ], 37 | "scripts": { 38 | "build": "rimraf dist && unbuild", 39 | "dev": "unbuild --stub", 40 | "lint": "eslint .", 41 | "lint:fix": "eslint . --fix", 42 | "prepublishOnly": "nr build", 43 | "release": "bumpp --commit --push --tag && pnpm publish", 44 | "start": "esno src/index.ts", 45 | "test": "vitest", 46 | "test:update": "vitest -u", 47 | "typecheck": "tsc --noEmit", 48 | "play": "npm -C playground run dev" 49 | }, 50 | "peerDependencies": { 51 | "unocss": ">= 0.31.13" 52 | }, 53 | "dependencies": { 54 | "@unocss/preset-mini": "^65.4.0" 55 | }, 56 | "devDependencies": { 57 | "@antfu/eslint-config": "^3.14.0", 58 | "@antfu/ni": "^23.2.0", 59 | "@babel/types": "^7.26.5", 60 | "@types/node": "^22.10.6", 61 | "@unocss/autocomplete": "^65.4.0", 62 | "bumpp": "^9.10.0", 63 | "eslint": "^9.18.0", 64 | "esno": "^4.8.0", 65 | "pnpm": "^9.11.0", 66 | "rimraf": "^5.0.8", 67 | "typescript": "^5.7.3", 68 | "unbuild": "^3.3.1", 69 | "unocss": "^65.4.0", 70 | "vite": "^6.0.7", 71 | "vitest": "^2.1.8" 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /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/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /playground/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite App 8 | 9 | 10 |
11 |
16 |
17 |
18 | default scrollbar default scrollbar default scrollbar default scrollbar 19 |
20 |
21 |
22 |
23 | default scrollbar default scrollbar default scrollbar default scrollbar 24 |
25 |
26 |
27 |
28 | track color is gray-800 thumb color is teal-700 29 |
30 |
31 |
32 |
33 | rounded scrollbar rounded scrollbar rounded scrollbar rounded scrollbar 34 |
35 |
36 |
37 |
38 | scrollbar height is 4px scrollbar height is 4px scrollbar height is 4px 39 |
40 |
41 |
42 |
43 | scrollbar height is 4px scrollbar height is 4px scrollbar height is 4px 44 |
45 |
46 |
47 |
53 |
54 |
55 | default scrollbar default scrollbar default scrollbar default scrollbar 56 |
57 |
58 |
59 |
60 | track color is gray-800 thumb color is teal-700 61 |
62 |
63 |
64 |
65 | rounded scrollbar rounded scrollbar rounded scrollbar rounded scrollbar 66 |
67 |
68 |
69 |
70 | scrollbar width is 4px scrollbar height is 4px scrollbar width is 4px 71 |
72 |
73 |
74 |
75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /playground/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "playground", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "vite", 7 | "build": "tsc && vite build", 8 | "preview": "vite preview" 9 | }, 10 | "devDependencies": { 11 | "typescript": "^5.7.3", 12 | "vite": "^6.0.7" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /playground/src/main.ts: -------------------------------------------------------------------------------- 1 | import './style.css' 2 | import 'uno.css' 3 | -------------------------------------------------------------------------------- /playground/src/style.css: -------------------------------------------------------------------------------- 1 | #app { 2 | font-family: Avenir, Helvetica, Arial, sans-serif; 3 | -webkit-font-smoothing: antialiased; 4 | -moz-osx-font-smoothing: grayscale; 5 | color: #2c3e50; 6 | margin-top: 60px; 7 | } 8 | 9 | .foo { 10 | @apply scrollbar scrollbar-thumb-color-teal-700; 11 | } -------------------------------------------------------------------------------- /playground/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /playground/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "lib": ["ESNext", "DOM"], 5 | "useDefineForClassFields": true, 6 | "module": "ESNext", 7 | "moduleResolution": "Node", 8 | "resolveJsonModule": true, 9 | "strict": true, 10 | "noImplicitReturns": true, 11 | "noUnusedLocals": true, 12 | "noUnusedParameters": true, 13 | "noEmit": true, 14 | "sourceMap": true, 15 | "esModuleInterop": true 16 | }, 17 | "include": ["src"] 18 | } 19 | -------------------------------------------------------------------------------- /playground/unocss.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, presetAttributify, presetUno, transformerDirectives } from 'unocss' 2 | 3 | import { presetScrollbar } from '../src' 4 | 5 | export default defineConfig({ 6 | presets: [ 7 | presetUno({ 8 | prefix: 'tw-', 9 | }), 10 | presetAttributify(), 11 | presetScrollbar({ 12 | varPrefix: 'un', 13 | prefix: ['un', ''], 14 | noCompatible: false, 15 | }), 16 | ], 17 | transformers: [ 18 | transformerDirectives(), 19 | ], 20 | }) 21 | -------------------------------------------------------------------------------- /playground/vite.config.ts: -------------------------------------------------------------------------------- 1 | import unocss from 'unocss/vite' 2 | import { defineConfig } from 'vite' 3 | 4 | export default defineConfig({ 5 | plugins: [ 6 | unocss(), 7 | ], 8 | }) 9 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - playground 3 | - examples/* 4 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable regexp/no-useless-lazy */ 2 | import type { Preset } from 'unocss' 3 | import { colorResolver, handler } from '@unocss/preset-mini/utils' 4 | 5 | const defaultOption: Required = { 6 | scrollbarWidth: '8px', 7 | scrollbarHeight: '8px', 8 | scrollbarTrackRadius: '4px', 9 | scrollbarThumbRadius: '4px', 10 | scrollbarTrackColor: '#f5f5f5', 11 | scrollbarThumbColor: '#ddd', 12 | varPrefix: '', 13 | prefix: '', 14 | numberToUnit: value => `${value / 4}rem`, 15 | noCompatible: true, 16 | } 17 | 18 | export interface PresetScrollbarDefaultOption { 19 | /** 20 | * default scrollbar width 21 | * @default '8px' 22 | */ 23 | scrollbarWidth?: string 24 | /** 25 | * default scrollbar height 26 | * @default '8px' 27 | */ 28 | scrollbarHeight?: string 29 | /** 30 | * default scrollbar track radius 31 | * @default '4px' 32 | */ 33 | scrollbarTrackRadius?: string 34 | /** 35 | * default scrollbar thumb radius 36 | * @default '4px' 37 | */ 38 | scrollbarThumbRadius?: string 39 | /** 40 | * default scrollbar track background color 41 | * @default '#f5f5f5' 42 | */ 43 | scrollbarTrackColor?: string 44 | /** 45 | * default scrollbar thumb background color 46 | * @default '#ddd' 47 | */ 48 | scrollbarThumbColor?: string 49 | /** 50 | * Apply prefix to all utilities and shortcuts 51 | */ 52 | prefix?: string | string[] 53 | /** 54 | * css variable prefix 55 | * @default '' 56 | */ 57 | varPrefix?: string 58 | /** 59 | * convert number to unit 60 | * @default value => `${value / 4}rem` 61 | * @example 62 | * numberToUnit: value => `${value / 4}rem` 63 | * p-4 => padding: 1rem 64 | * p-4px => padding: 4px 65 | * 66 | * @example 67 | * numberToUnit: value => `${value}rpx` 68 | * p-4 => padding: 4rpx 69 | */ 70 | numberToUnit?: (value: number) => string 71 | 72 | /** 73 | * if false will use scrollbar-color and scrollbar-width, rounded and scrollbar-w, scrollbar-h and scrollbar-radius will not work 74 | * if true, won't have any effect in Firefox 75 | * 76 | * @default true 77 | */ 78 | noCompatible?: boolean 79 | } 80 | 81 | const customRules = { 82 | 'radius': ['track-radius', 'thumb-radius'], 83 | 'w': ['width'], 84 | 'h': ['height'], 85 | 'track-radius': ['track-radius'], 86 | 'thumb-radius': ['thumb-radius'], 87 | } 88 | 89 | const numberVarRegex = new RegExp(`^scrollbar-(${Object.keys(customRules).join('|')})-(\\d+?)([a-zA-Z]*?)$`) 90 | 91 | export function presetScrollbar(option?: PresetScrollbarDefaultOption): Preset { 92 | const config = { 93 | ...defaultOption, 94 | ...option, 95 | } 96 | 97 | function resolveVar(name: string) { 98 | const prefix = config.varPrefix 99 | return `--${prefix ? `${prefix}-` : ''}scrollbar-${name}` 100 | } 101 | 102 | const variantsRE = /^(scrollbar(-track|-thumb)?):.+$/ 103 | 104 | return { 105 | name: 'unocss-preset-scrollbar', 106 | prefix: config.prefix, 107 | shortcuts: [ 108 | [ 109 | 'scrollbar', 110 | [ 111 | { overflow: 'auto' }, 112 | 'scrollbar-custom-property', 113 | 'scrollbar-width-auto', 114 | `scrollbar-color-[var(${resolveVar('thumb')})_var(${resolveVar('track')})]`, 115 | `scrollbar-track:scrollbar-background-color-[var(${resolveVar('track')})]`, 116 | `scrollbar-thumb:scrollbar-background-color-[var(${resolveVar('thumb')})]`, 117 | `scrollbar:scrollbar-width-[var(${resolveVar('width')})]`, 118 | `scrollbar:scrollbar-height-[var(${resolveVar('height')})]`, 119 | ], 120 | ], 121 | [ 122 | 'scrollbar-rounded', 123 | ` 124 | scrollbar-track:scrollbar-border-radius-[var(${resolveVar('track-radius')})] 125 | scrollbar-thumb:scrollbar-border-radius-[var(${resolveVar('thumb-radius')})] 126 | `, 127 | ], 128 | [ 129 | 'scrollbar-thin', 130 | ` 131 | scrollbar-w-8px 132 | scrollbar-h-8px 133 | scrollbar-width-thin 134 | `, 135 | ], 136 | [ 137 | 'scrollbar-none', 138 | ` 139 | scrollbar:hidden 140 | scrollbar-width-none 141 | `, 142 | ], 143 | ], 144 | variants: [ 145 | // ::-webkit-scrollbar-track 146 | // ::-webkit-scrollbar-thumb 147 | // ::-webkit-scrollbar 148 | (matcher) => { 149 | if (!variantsRE.test(matcher)) 150 | return 151 | 152 | const variant = matcher.replace(variantsRE, '$1') 153 | 154 | return { 155 | matcher: matcher.slice(variant.length + 1), 156 | selector: (s) => { 157 | return `${s}::-webkit-${variant}` 158 | }, 159 | } 160 | }, 161 | ], 162 | rules: [ 163 | [ 164 | /^scrollbar-color-(.+)$/, 165 | ([_, prop]) => { 166 | if (config.noCompatible) 167 | return {} 168 | 169 | // when use scrollbar-color, ::-webkit-scrollbar styling is disabled. 170 | // https://developer.mozilla.org/en-US/docs/Web/CSS/::-webkit-scrollbar 171 | return { 172 | 'scrollbar-color': handler.bracket.cssvar.auto.fraction.rem(prop), 173 | } 174 | }, 175 | ], 176 | [ 177 | /^scrollbar-width-(auto|thin|none)/, 178 | ([_, prop]) => { 179 | const res: Record = {} 180 | if (!config.noCompatible || prop === 'none') 181 | res['scrollbar-width'] = prop 182 | return res 183 | }, 184 | ], 185 | [ 186 | /^scrollbar-custom-property$/, 187 | ([_]) => ({ 188 | [resolveVar('track')]: config.scrollbarTrackColor, 189 | [resolveVar('thumb')]: config.scrollbarThumbColor, 190 | [resolveVar('width')]: config.scrollbarWidth, 191 | [resolveVar('height')]: config.scrollbarHeight, 192 | [resolveVar('track-radius')]: config.scrollbarTrackRadius, 193 | [resolveVar('thumb-radius')]: config.scrollbarThumbRadius, 194 | }), 195 | ], 196 | [ 197 | /^scrollbar-thumb-color-(.+)$/, 198 | colorResolver(resolveVar('thumb'), 'scrollbar-thumb'), 199 | { autocomplete: 'scrollbar-thumb-color-$colors' }, 200 | ], 201 | [ 202 | /^scrollbar-track-color-(.+)$/, 203 | colorResolver(resolveVar('track'), 'scrollbar-track'), 204 | { autocomplete: 'scrollbar-track-color-$colors' }, 205 | ], 206 | [ 207 | /^scrollbar-(width|height|background-color|border-radius)-(\[var.+\])$/, 208 | ([_, prop, value]) => { 209 | return { 210 | [`${prop}`]: handler.bracket(value), 211 | } 212 | }, 213 | ], 214 | [ 215 | numberVarRegex, 216 | ([_, type, value, unit]) => { 217 | const val = unit ? value + unit : config.numberToUnit(Number.parseInt(value)) 218 | const vars = customRules[type as keyof typeof customRules] 219 | .map(v => resolveVar(v)) 220 | return vars.reduce((acc: any, v) => { 221 | acc[v] = val 222 | return acc 223 | }, {}) 224 | }, 225 | { autocomplete: `scrollbar-(${Object.keys(customRules).join('|')})-` }, 226 | ], 227 | [ 228 | 'hidden', 229 | { display: 'none' }, 230 | ], 231 | ], 232 | } 233 | } 234 | -------------------------------------------------------------------------------- /test/__snapshots__/index-compatible.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`scrollbar (compatible) > scrollbar-auto 1`] = ` 4 | "/* layer: shortcuts */ 5 | .scrollbar{scrollbar-color:var(--scrollbar-thumb) var(--scrollbar-track);scrollbar-width:auto;--scrollbar-track:#f5f5f5;--scrollbar-thumb:#ddd;--scrollbar-width:8px;--scrollbar-height:8px;--scrollbar-track-radius:4px;--scrollbar-thumb-radius:4px;overflow:auto;} 6 | .scrollbar::-webkit-scrollbar{width:var(--scrollbar-width);height:var(--scrollbar-height);} 7 | .scrollbar::-webkit-scrollbar-thumb{background-color:var(--scrollbar-thumb);} 8 | .scrollbar::-webkit-scrollbar-track{background-color:var(--scrollbar-track);}" 9 | `; 10 | 11 | exports[`scrollbar (compatible) > scrollbar-none 1`] = ` 12 | "/* layer: shortcuts */ 13 | .scrollbar{scrollbar-color:var(--scrollbar-thumb) var(--scrollbar-track);scrollbar-width:auto;--scrollbar-track:#f5f5f5;--scrollbar-thumb:#ddd;--scrollbar-width:8px;--scrollbar-height:8px;--scrollbar-track-radius:4px;--scrollbar-thumb-radius:4px;overflow:auto;} 14 | .scrollbar-none{scrollbar-width:none;} 15 | .scrollbar::-webkit-scrollbar{width:var(--scrollbar-width);height:var(--scrollbar-height);} 16 | .scrollbar::-webkit-scrollbar-thumb{background-color:var(--scrollbar-thumb);} 17 | .scrollbar::-webkit-scrollbar-track{background-color:var(--scrollbar-track);} 18 | .scrollbar-none::-webkit-scrollbar{display:none;}" 19 | `; 20 | 21 | exports[`scrollbar (compatible) > scrollbar-thin 1`] = ` 22 | "/* layer: shortcuts */ 23 | .scrollbar{scrollbar-color:var(--scrollbar-thumb) var(--scrollbar-track);scrollbar-width:auto;--scrollbar-track:#f5f5f5;--scrollbar-thumb:#ddd;--scrollbar-width:8px;--scrollbar-height:8px;--scrollbar-track-radius:4px;--scrollbar-thumb-radius:4px;overflow:auto;} 24 | .scrollbar-thin{scrollbar-width:thin;--scrollbar-width:8px;--scrollbar-height:8px;} 25 | .scrollbar::-webkit-scrollbar{width:var(--scrollbar-width);height:var(--scrollbar-height);} 26 | .scrollbar::-webkit-scrollbar-thumb{background-color:var(--scrollbar-thumb);} 27 | .scrollbar::-webkit-scrollbar-track{background-color:var(--scrollbar-track);}" 28 | `; 29 | -------------------------------------------------------------------------------- /test/__snapshots__/index.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`scrollbar > custom value to unit 1`] = ` 4 | "/* layer: default */ 5 | .scrollbar-thumb-radius-2px{--scrollbar-thumb-radius:2px;} 6 | .scrollbar-w-1{--scrollbar-width:2px;}" 7 | `; 8 | 9 | exports[`scrollbar > preset set prefix 1`] = ` 10 | "/* layer: default */ 11 | .un-scrollbar{--scrollbar-track:#f5f5f5;--scrollbar-thumb:#ddd;--scrollbar-width:8px;--scrollbar-height:8px;--scrollbar-track-radius:4px;--scrollbar-thumb-radius:4px;overflow:auto;} 12 | .un-scrollbar::-webkit-scrollbar{width:var(--scrollbar-width);height:var(--scrollbar-height);} 13 | .un-scrollbar::-webkit-scrollbar-thumb{background-color:var(--scrollbar-thumb);} 14 | .un-scrollbar::-webkit-scrollbar-track{background-color:var(--scrollbar-track);}" 15 | `; 16 | 17 | exports[`scrollbar > presetUno prefix 1`] = ` 18 | "/* layer: shortcuts */ 19 | .scrollbar{--scrollbar-track:#f5f5f5;--scrollbar-thumb:#ddd;--scrollbar-width:8px;--scrollbar-height:8px;--scrollbar-track-radius:4px;--scrollbar-thumb-radius:4px;overflow:auto;} 20 | .scrollbar::-webkit-scrollbar{width:var(--scrollbar-width);height:var(--scrollbar-height);} 21 | .scrollbar::-webkit-scrollbar-thumb{background-color:var(--scrollbar-thumb);} 22 | .scrollbar::-webkit-scrollbar-track{background-color:var(--scrollbar-track);}" 23 | `; 24 | 25 | exports[`scrollbar > scrollbar 1`] = ` 26 | "/* layer: shortcuts */ 27 | .scrollbar{--scrollbar-track:#f5f5f5;--scrollbar-thumb:#ddd;--scrollbar-width:8px;--scrollbar-height:8px;--scrollbar-track-radius:4px;--scrollbar-thumb-radius:4px;overflow:auto;} 28 | .scrollbar::-webkit-scrollbar{width:var(--scrollbar-width);height:var(--scrollbar-height);} 29 | .scrollbar::-webkit-scrollbar-thumb{background-color:var(--scrollbar-thumb);} 30 | .scrollbar::-webkit-scrollbar-track{background-color:var(--scrollbar-track);} 31 | .scrollbar-rounded::-webkit-scrollbar-thumb{border-radius:var(--scrollbar-thumb-radius);} 32 | .scrollbar-rounded::-webkit-scrollbar-track{border-radius:var(--scrollbar-track-radius);} 33 | /* layer: default */ 34 | .scrollbar-radius-2{--scrollbar-track-radius:0.5rem;--scrollbar-thumb-radius:0.5rem;} 35 | .scrollbar-w-4px{--scrollbar-width:4px;}" 36 | `; 37 | 38 | exports[`scrollbar > scrollbar color 1`] = ` 39 | "/* layer: default */ 40 | .scrollbar-track-color-red{--un-scrollbar-track-opacity:1;--scrollbar-track:rgb(248 113 113 / var(--un-scrollbar-track-opacity));}" 41 | `; 42 | 43 | exports[`scrollbar > scrollbar custom unit 1`] = ` 44 | "/* layer: default */ 45 | .scrollbar-w-1px{--scrollbar-width:1px;}" 46 | `; 47 | 48 | exports[`scrollbar > should work in atributify mode 1`] = ` 49 | "/* layer: shortcuts */ 50 | [scrollbar~="\\~"]{--scrollbar-track:#f5f5f5;--scrollbar-thumb:#ddd;--scrollbar-width:8px;--scrollbar-height:8px;--scrollbar-track-radius:4px;--scrollbar-thumb-radius:4px;overflow:auto;} 51 | [scrollbar~="\\~"]::-webkit-scrollbar{width:var(--scrollbar-width);height:var(--scrollbar-height);} 52 | [scrollbar~="\\~"]::-webkit-scrollbar-thumb{background-color:var(--scrollbar-thumb);} 53 | [scrollbar~="\\~"]::-webkit-scrollbar-track{background-color:var(--scrollbar-track);} 54 | [scrollbar~="rounded"]::-webkit-scrollbar-thumb{border-radius:var(--scrollbar-thumb-radius);} 55 | [scrollbar~="rounded"]::-webkit-scrollbar-track{border-radius:var(--scrollbar-track-radius);} 56 | /* layer: default */ 57 | .w-4px{width:4px;} 58 | .rounded{border-radius:0.25rem;} 59 | [scrollbar~="radius-2"]{--scrollbar-track-radius:0.5rem;--scrollbar-thumb-radius:0.5rem;} 60 | [scrollbar~="w-4px"]{--scrollbar-width:4px;}" 61 | `; 62 | 63 | exports[`scrollbar > var prefix 1`] = ` 64 | "/* layer: shortcuts */ 65 | .scrollbar{--my-custom-prefix-scrollbar-track:#f5f5f5;--my-custom-prefix-scrollbar-thumb:#ddd;--my-custom-prefix-scrollbar-width:8px;--my-custom-prefix-scrollbar-height:8px;--my-custom-prefix-scrollbar-track-radius:4px;--my-custom-prefix-scrollbar-thumb-radius:4px;overflow:auto;} 66 | .scrollbar::-webkit-scrollbar{width:var(--my-custom-prefix-scrollbar-width);height:var(--my-custom-prefix-scrollbar-height);} 67 | .scrollbar::-webkit-scrollbar-thumb{background-color:var(--my-custom-prefix-scrollbar-thumb);} 68 | .scrollbar::-webkit-scrollbar-track{background-color:var(--my-custom-prefix-scrollbar-track);} 69 | .scrollbar-rounded::-webkit-scrollbar-thumb{border-radius:var(--my-custom-prefix-scrollbar-thumb-radius);} 70 | .scrollbar-rounded::-webkit-scrollbar-track{border-radius:var(--my-custom-prefix-scrollbar-track-radius);} 71 | /* layer: default */ 72 | .scrollbar-thumb-radius-2px{--my-custom-prefix-scrollbar-thumb-radius:2px;} 73 | .scrollbar-w-1{--my-custom-prefix-scrollbar-width:0.25rem;}" 74 | `; 75 | -------------------------------------------------------------------------------- /test/index-compatible.test.ts: -------------------------------------------------------------------------------- 1 | import { createGenerator } from 'unocss' 2 | import { describe, expect, it } from 'vitest' 3 | import { presetScrollbar } from '../src' 4 | 5 | describe('scrollbar (compatible)', async () => { 6 | const generator = await createGenerator({ 7 | presets: [ 8 | presetScrollbar({ 9 | noCompatible: false, 10 | }), 11 | ], 12 | }) 13 | 14 | it('scrollbar-auto', async () => { 15 | const { css } = await generator.generate('scrollbar') 16 | expect(css).toMatchSnapshot() 17 | }) 18 | 19 | it('scrollbar-thin', async () => { 20 | const { css } = await generator.generate([ 21 | 'scrollbar', 22 | 'scrollbar-thin', 23 | ]) 24 | expect(css).toMatchSnapshot() 25 | }) 26 | 27 | it('scrollbar-none', async () => { 28 | const { css } = await generator.generate([ 29 | 'scrollbar', 30 | 'scrollbar-none', 31 | ]) 32 | expect(css).toMatchSnapshot() 33 | }) 34 | }) 35 | -------------------------------------------------------------------------------- /test/index.test.ts: -------------------------------------------------------------------------------- 1 | import { createAutocomplete } from '@unocss/autocomplete' 2 | import { createGenerator, presetAttributify, presetUno } from 'unocss' 3 | import { describe, expect, it } from 'vitest' 4 | import { presetScrollbar } from '../src' 5 | 6 | describe('scrollbar', async () => { 7 | const generator = await createGenerator({ 8 | presets: [ 9 | presetUno({ 10 | preflight: false, 11 | }), 12 | presetAttributify(), 13 | presetScrollbar(), 14 | ], 15 | }) 16 | 17 | const ac = createAutocomplete(generator) 18 | 19 | async function enumerateSuggestions(inputs: string[]) { 20 | return Object.fromEntries(await Promise.all(inputs.map(async input => [ 21 | input, 22 | (await ac.suggest(input)).slice(0, 10).join(' '), 23 | ]))) 24 | } 25 | 26 | it('scrollbar', async () => { 27 | const { css } = await generator.generate([ 28 | 'scrollbar', 29 | 'scrollbar-rounded', 30 | 'scrollbar-w-4px', 31 | 'scrollbar-radius-2', 32 | 'scrollbar-radius-track-4', 33 | 'scrollbar-radius-thumb-4', 34 | ].join(' ')) 35 | 36 | expect(css).toMatchSnapshot() 37 | }) 38 | 39 | it('scrollbar color', async () => { 40 | const { css } = await generator.generate([ 41 | 'scrollbar-track-color-red', 42 | ].join(' ')) 43 | expect(css).toMatchSnapshot() 44 | }) 45 | 46 | it('scrollbar custom unit', async () => { 47 | const { css } = await generator.generate([ 48 | 'scrollbar-w-1px', 49 | ].join(' ')) 50 | expect(css).toMatchSnapshot() 51 | }) 52 | 53 | it('custom value to unit', async () => { 54 | const generator = await createGenerator({ 55 | presets: [ 56 | presetUno({ 57 | preflight: false, 58 | }), 59 | presetScrollbar({ 60 | numberToUnit: value => `${value * 2}px`, 61 | }), 62 | ], 63 | }) 64 | const { css } = await generator.generate([ 65 | 'scrollbar-w-1', 66 | 'scrollbar-thumb-radius-2px', 67 | ].join(' ')) 68 | expect(css).toMatchSnapshot() 69 | }) 70 | 71 | it('should work in atributify mode', async () => { 72 | const { css } = await generator.generate(` 73 |
75 |
76 | `) 77 | expect(css).toMatchSnapshot() 78 | }) 79 | 80 | it('var prefix', async () => { 81 | const generator = await createGenerator({ 82 | presets: [ 83 | presetUno({ 84 | preflight: false, 85 | }), 86 | presetScrollbar({ 87 | varPrefix: 'my-custom-prefix', 88 | }), 89 | ], 90 | }) 91 | const { css } = await generator.generate([ 92 | 'scrollbar', 93 | 'scrollbar-w-1', 94 | 'scrollbar-thumb-radius-2px', 95 | 'scrollbar-rounded', 96 | ].join(' ')) 97 | expect(css).toMatchSnapshot() 98 | }) 99 | 100 | it('should provide autocomplete', async () => { 101 | expect( 102 | await enumerateSuggestions([ 103 | 'scrollbar-', 104 | 'scrollbar-w-', 105 | 'sccrollbar-thumb-radius-', 106 | 'scrollbar-radius-', 107 | 'scrollbar-track-color-', 108 | 'scrollbar-thumb-color-', 109 | 'scrollbar-thumb-', 110 | ]), 111 | ).toMatchInlineSnapshot(` 112 | { 113 | "sccrollbar-thumb-radius-": "", 114 | "scrollbar-": "scrollbar-none scrollbar-rounded scrollbar-thin scrollbar-thumb-color-amber scrollbar-thumb-color-black scrollbar-thumb-color-blue scrollbar-thumb-color-bluegray scrollbar-thumb-color-blueGray scrollbar-thumb-color-coolgray scrollbar-thumb-color-coolGray", 115 | "scrollbar-radius-": "scrollbar-radius-2 scrollbar-radius-0 scrollbar-radius-1 scrollbar-radius-3 scrollbar-radius-4 scrollbar-radius-5 scrollbar-radius-6 scrollbar-radius-8 scrollbar-radius-10 scrollbar-radius-12", 116 | "scrollbar-thumb-": "scrollbar-thumb-radius-0 scrollbar-thumb-radius-1 scrollbar-thumb-radius-2 scrollbar-thumb-radius-3 scrollbar-thumb-radius-4 scrollbar-thumb-radius-5 scrollbar-thumb-radius-6 scrollbar-thumb-radius-8 scrollbar-thumb-radius-10 scrollbar-thumb-radius-12", 117 | "scrollbar-thumb-color-": "scrollbar-thumb-color-amber scrollbar-thumb-color-black scrollbar-thumb-color-blue scrollbar-thumb-color-bluegray scrollbar-thumb-color-blueGray scrollbar-thumb-color-coolgray scrollbar-thumb-color-coolGray scrollbar-thumb-color-current scrollbar-thumb-color-cyan scrollbar-thumb-color-dark", 118 | "scrollbar-track-color-": "scrollbar-track-color-amber scrollbar-track-color-black scrollbar-track-color-blue scrollbar-track-color-bluegray scrollbar-track-color-blueGray scrollbar-track-color-coolgray scrollbar-track-color-coolGray scrollbar-track-color-current scrollbar-track-color-cyan scrollbar-track-color-dark", 119 | "scrollbar-w-": "scrollbar-w-4px scrollbar-w-1px scrollbar-w-0 scrollbar-w-1 scrollbar-w-2 scrollbar-w-3 scrollbar-w-4 scrollbar-w-5 scrollbar-w-6 scrollbar-w-8", 120 | } 121 | `) 122 | }) 123 | 124 | it('presetUno prefix', async () => { 125 | const generator = await createGenerator({ 126 | presets: [ 127 | presetUno({ 128 | preflight: false, 129 | prefix: 'tw-', 130 | }), 131 | presetScrollbar(), 132 | ], 133 | }) 134 | const { 135 | css, 136 | } = await generator.generate([ 137 | 'scrollbar', 138 | ]) 139 | expect(css).toMatchSnapshot() 140 | }) 141 | 142 | it('preset set prefix', async () => { 143 | const generator = await createGenerator({ 144 | presets: [ 145 | presetScrollbar({ 146 | prefix: 'un-', 147 | }), 148 | ], 149 | }) 150 | const { 151 | css, 152 | } = await generator.generate([ 153 | 'un-scrollbar', 154 | ]) 155 | expect(css).toMatchSnapshot() 156 | }) 157 | }) 158 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2017", 4 | "lib": ["esnext"], 5 | "module": "esnext", 6 | "moduleResolution": "node", 7 | "paths": { 8 | "unocss-preset-scrollbar": [ 9 | "./src/index.ts" 10 | ] 11 | }, 12 | "resolveJsonModule": true, 13 | "strict": true, 14 | "strictNullChecks": true, 15 | "esModuleInterop": true, 16 | "skipDefaultLibCheck": true, 17 | "skipLibCheck": true 18 | }, 19 | "include": [ 20 | "./src/**/*.ts", 21 | "./test/**/*.ts" 22 | ], 23 | "exclude": [ 24 | "node_modules", 25 | "dist" 26 | ] 27 | } 28 | --------------------------------------------------------------------------------