├── .babelrc
├── .eslintignore
├── .eslintrc
├── .github
└── workflows
│ └── ci.yml
├── .gitignore
├── .npmrc
├── .prettierrc
├── CHANGELOG.md
├── README.md
├── UNLICENSE
├── codecov.yml
├── develop
└── index.js
├── jest.config.js
├── package.json
├── rollup.config.js
├── src
└── index.js
├── test
├── .eslintrc
├── __snapshots__
│ ├── color.spec.js.snap
│ ├── control.spec.js.snap
│ ├── options.spec.js.snap
│ └── width.spec.js.snap
├── color.spec.js
├── control.spec.js
├── options.spec.js
└── width.spec.js
└── yarn.lock
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | [
4 | "@babel/preset-env",
5 | {
6 | "targets": {
7 | "node": 12
8 | }
9 | }
10 | ]
11 | ],
12 | "plugins": ["@babel/plugin-proposal-do-expressions"]
13 | }
14 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | dist
2 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | ---
2 | root: true
3 | parser: "@babel/eslint-parser"
4 | extends:
5 | - "airbnb-base"
6 | - "plugin:jest/recommended"
7 | - "prettier"
8 |
9 | plugins:
10 | - "jest"
11 |
12 | env:
13 | jest: true
14 |
15 | rules:
16 | prefer-const: off
17 | one-var: off
18 | no-use-before-define:
19 | - error
20 | - functions: false
21 | comma-dangle:
22 | - error
23 | - arrays: "always-multiline"
24 | objects: "always-multiline"
25 | imports: "always-multiline"
26 | exports: "always-multiline"
27 | functions: ignore
28 |
29 | no-unused-expressions: off
30 |
31 | import/no-extraneous-dependencies:
32 | - error
33 | - devDependencies: true
34 | optionalDependencies: false
35 | peerDependencies: false
36 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | branches: [main]
6 | pull_request:
7 | branches: [main]
8 |
9 | concurrency:
10 | group: ${{ github.ref }}
11 | cancel-in-progress: true
12 |
13 | jobs:
14 | test-and-validate:
15 | runs-on: ubuntu-latest
16 |
17 | strategy:
18 | matrix:
19 | node-version: [18.x, lts/*]
20 |
21 | steps:
22 | - uses: actions/checkout@v3
23 |
24 | - name: Use Node.js ${{ matrix.node-version }}
25 | uses: actions/setup-node@v3
26 | with:
27 | node-version: ${{ matrix.node-version }}
28 | cache: 'yarn'
29 |
30 | - name: Install
31 | run: yarn install --frozen-lockfile --ignore-scripts
32 |
33 | - name: Test
34 | run: yarn run test:ci
35 |
36 | - name: Upload coverage
37 | uses: codecov/codecov-action@v3
38 |
39 | - name: Lint
40 | run: yarn run lint
41 |
42 | - name: Format
43 | run: yarn run format:check
44 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 | coverage
4 | .jest-cache
5 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | registry=https://registry.npmjs.org
2 | package-lock=false
3 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "arrowParens": "avoid"
4 | }
5 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # postcss-scrollbar change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 |
5 | The format is based on [Keep a Changelog](http://keepachangelog.com/)
6 | and this project adheres to [Semantic Versioning](http://semver.org/).
7 |
8 | ## [Unreleased]
9 |
10 | ## [0.5.1] - 2022-06-21
11 | ### Fixed
12 | * Functional colors being ignored in `scrollbar-color` (#13).
13 |
14 | ## [0.5.0] - 2022-03-01
15 | ### Changed
16 | **Breaking**
17 | * PostCSS 8 migration.
18 | Now requires `postcss >= 8` as peerDependency.
19 |
20 | ## [0.4.0] - 2022-02-25
21 | ### Changed
22 | * Change default width value for the `thin` keyword from `rem` to `px`.
23 |
24 | ### Added
25 | * A new `width` option.
26 | Allows for setting the webkit fallbacks `width` and `height`.
27 |
28 | ## [0.3.0] - 2019-01-27
29 | ### Added
30 | * Added webkit scrollbar corner background color (#2).
31 | * Added webkit horizontal scrollbar height to match vertical scrollbar width (#3).
32 |
33 | ## [0.2.1] - 2018-01-12
34 | ### Fixed
35 | * Fixed Node commonjs support.
36 |
37 | ## [0.2.0] - 2018-12-27
38 | ## [0.1.0] - 2018-12-20
39 | - Initial release.
40 |
41 | [unreleased]: https://github.com/pascalduez/postcss-scrollbar/compare/0.5.1...HEAD
42 | [0.5.1]: https://github.com/pascalduez/postcss-scrollbar/releases/tag/0.5.1
43 | [0.5.0]: https://github.com/pascalduez/postcss-scrollbar/releases/tag/0.5.0
44 | [0.4.0]: https://github.com/pascalduez/postcss-scrollbar/releases/tag/0.4.0
45 | [0.3.0]: https://github.com/pascalduez/postcss-scrollbar/releases/tag/0.3.0
46 | [0.2.1]: https://github.com/pascalduez/postcss-scrollbar/releases/tag/0.2.1
47 | [0.2.0]: https://github.com/pascalduez/postcss-scrollbar/releases/tag/0.2.0
48 | [0.1.0]: https://github.com/pascalduez/postcss-scrollbar/releases/tag/0.1.0
49 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # postcss-scrollbar
2 |
3 | [![npm version][npm-image]][npm-url]
4 | [![CI Status][ci-image]][ci-url]
5 | [![Coverage Status][codecov-image]][codecov-url]
6 |
7 | > [PostCSS] plugin enabling custom scrollbars
8 |
9 | Spec : https://drafts.csswg.org/css-scrollbars-1
10 | Browser support: https://caniuse.com/#feat=css-scrollbar
11 | Docs: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Scrollbars
12 |
13 | ## Installation
14 |
15 | ```
16 | npm install postcss postcss-scrollbar --save-dev
17 | ```
18 |
19 | or
20 |
21 | ```
22 | yarn add postcss postcss-scrollbar --save-dev
23 | ```
24 |
25 | ## Usage
26 |
27 | ```js
28 | const fs = require('node:fs');
29 | const postcss = require('postcss');
30 | const scrollbar = require('postcss-scrollbar');
31 |
32 | let input = fs.readFileSync('input.css', 'utf8');
33 |
34 | postcss()
35 | .use(scrollbar)
36 | .process(input)
37 | .then(result => {
38 | fs.writeFileSync('output.css', result.css);
39 | });
40 | ```
41 |
42 | ## Examples
43 |
44 | ```css
45 | /* input */
46 | .scrollable {
47 | scrollbar-color: rebeccapurple green;
48 | scrollbar-width: thin;
49 | }
50 | ```
51 |
52 | ```css
53 | /* output */
54 | .scrollable::-webkit-scrollbar-thumb {
55 | background-color: rebeccapurple;
56 | }
57 | .scrollable::-webkit-scrollbar-track {
58 | background-color: green;
59 | }
60 | .scrollable::-webkit-scrollbar-corner {
61 | background-color: green;
62 | }
63 | .scrollable::-webkit-scrollbar {
64 | width: 8px;
65 | height: 8px;
66 | }
67 | .scrollable {
68 | -ms-overflow-style: auto;
69 | scrollbar-color: rebeccapurple green;
70 | scrollbar-width: thin;
71 | }
72 | ```
73 |
74 | ```css
75 | /* input */
76 | .scrollable {
77 | scrollbar-width: none;
78 | }
79 | ```
80 |
81 | ```css
82 | /* output */
83 | .scrollable::-webkit-scrollbar {
84 | width: 0;
85 | height: 0;
86 | }
87 | .scrollable {
88 | -ms-overflow-style: none;
89 | scrollbar-width: none;
90 | }
91 | ```
92 |
93 | ## options
94 |
95 | ### `width`
96 |
97 | type: `String`
98 | default: `8px`
99 | Allows for setting the webkit fallbacks `width` and `height`.
100 |
101 | ### `edgeAutohide`
102 |
103 | type: `Boolean`
104 | default: `false`
105 | Allows for setting the scrollbar behaviour for the Edge Browser.
106 | `-ms-overflow-style: -ms-autohiding-scrollbar;`
107 | Edge doesn't support scrollbar styling.
108 | See https://developer.mozilla.org/fr/docs/Web/CSS/-ms-overflow-style
109 |
110 | ## Credits
111 |
112 | - [Pascal Duez](https://github.com/pascalduez)
113 |
114 | ## Licence
115 |
116 | postcss-scrollbar is [unlicensed](http://unlicense.org/).
117 |
118 | [postcss]: https://github.com/postcss/postcss
119 | [npm-url]: https://www.npmjs.org/package/postcss-scrollbar
120 | [npm-image]: http://img.shields.io/npm/v/postcss-scrollbar.svg?style=flat-square
121 | [ci-url]: https://github.com/pascalduez/postcss-scrollbar/actions/workflows/ci.yml
122 | [ci-image]: https://img.shields.io/github/actions/workflow/status/pascalduez/postcss-scrollbar/ci.yml?branch=main&style=flat-square
123 | [codecov-url]: https://codecov.io/gh/pascalduez/postcss-scrollbar
124 | [codecov-image]: https://img.shields.io/codecov/c/github/pascalduez/postcss-scrollbar.svg?style=flat-square
125 | [license-image]: http://img.shields.io/npm/l/postcss-scrollbar.svg?style=flat-square
126 | [license-url]: UNLICENSE
127 |
128 |
129 |
--------------------------------------------------------------------------------
/UNLICENSE:
--------------------------------------------------------------------------------
1 | This is free and unencumbered software released into the public domain.
2 |
3 | Anyone is free to copy, modify, publish, use, compile, sell, or
4 | distribute this software, either in source code form or as a compiled
5 | binary, for any purpose, commercial or non-commercial, and by any
6 | means.
7 |
8 | In jurisdictions that recognize copyright laws, the author or authors
9 | of this software dedicate any and all copyright interest in the
10 | software to the public domain. We make this dedication for the benefit
11 | of the public at large and to the detriment of our heirs and
12 | successors. We intend this dedication to be an overt act of
13 | relinquishment in perpetuity of all present and future rights to this
14 | software under copyright law.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
24 | For more information, please refer to
25 |
--------------------------------------------------------------------------------
/codecov.yml:
--------------------------------------------------------------------------------
1 | parsers:
2 | javascript:
3 | enable_partials: yes
4 |
--------------------------------------------------------------------------------
/develop/index.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console, one-var */
2 |
3 | import postcss from 'postcss';
4 | import reporter from 'postcss-reporter';
5 | import { stripIndent } from 'common-tags';
6 | import plugin from '../src';
7 |
8 | let from, to;
9 | let input = stripIndent`
10 | .test {
11 | scrollbar-width: thin;
12 | }
13 | `;
14 |
15 | postcss()
16 | .use(plugin)
17 | .use(reporter)
18 | .process(input, { from, to })
19 | .then(result => {
20 | console.log(result.css);
21 | })
22 | .catch(console.error);
23 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | testEnvironment: 'node',
3 | cacheDirectory: '.jest-cache',
4 | collectCoverageFrom: ['src/*.js'],
5 | };
6 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "postcss-scrollbar",
3 | "version": "0.5.1",
4 | "description": "PostCSS plugin enabling custom scrollbars",
5 | "keywords": [
6 | "css",
7 | "scrollbar",
8 | "postcss",
9 | "postcss-plugin"
10 | ],
11 | "author": {
12 | "name": "Pascal Duez",
13 | "url": "https://github.com/pascalduez"
14 | },
15 | "homepage": "https://github.com/pascalduez/postcss-scrollbar",
16 | "bugs": "https://github.com/pascalduez/postcss-scrollbar/issues",
17 | "repository": {
18 | "type": "git",
19 | "url": "git://github.com/pascalduez/postcss-scrollbar.git"
20 | },
21 | "license": "Unlicense",
22 | "files": [
23 | "dist",
24 | "CHANGELOG.md",
25 | "README.md",
26 | "UNLICENSE"
27 | ],
28 | "main": "dist/index.js",
29 | "module": "dist/index.mjs",
30 | "scripts": {
31 | "lint:js": "eslint src/ test/",
32 | "lint": "run-s lint:*",
33 | "format:check": "prettier -l '{src,test}/**/*.{js,css}'",
34 | "format:write": "prettier --write '{src,test}/**/*.{js,css}'",
35 | "validate": "run-s lint format:check",
36 | "test": "jest",
37 | "test:ci": "run-s 'test --coverage'",
38 | "develop": "babel-node develop/",
39 | "prebuild": "rm -rf dist/",
40 | "build": "rollup -c",
41 | "prepare": "run-s build",
42 | "prepublishOnly": "run-s validate test"
43 | },
44 | "dependencies": {
45 | "postcss-selector-parser": "^6.0.10",
46 | "postcss-value-parser": "^4.2.0"
47 | },
48 | "devDependencies": {
49 | "@babel/cli": "^7.17.10",
50 | "@babel/core": "^7.18.5",
51 | "@babel/eslint-parser": "^7.18.2",
52 | "@babel/node": "^7.18.5",
53 | "@babel/plugin-proposal-do-expressions": "^7.16.7",
54 | "@babel/preset-env": "^7.18.2",
55 | "babel-eslint": "^10.1.0",
56 | "common-tags": "^1.8.2",
57 | "eslint": "^8.18.0",
58 | "eslint-config-airbnb-base": "^15.0.0",
59 | "eslint-config-prettier": "^8.5.0",
60 | "eslint-plugin-import": "^2.26.0",
61 | "eslint-plugin-jest": "^26.5.3",
62 | "jest": "^28.1.1",
63 | "npm-run-all": "^4.0.2",
64 | "postcss": "^8.4.14",
65 | "postcss-reporter": "^6.0.1",
66 | "prettier": "^2.7.1",
67 | "rollup": "^2.75.7",
68 | "rollup-plugin-babel": "^4.4.0",
69 | "rollup-plugin-json": "^4.0.0"
70 | },
71 | "peerDependencies": {
72 | "postcss": "^8.0.0"
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | import babel from 'rollup-plugin-babel';
2 | import json from 'rollup-plugin-json';
3 | import pkg from './package.json';
4 |
5 | export default {
6 | plugins: [json(), babel()],
7 | external: ['postcss', 'postcss-selector-parser', 'postcss-value-parser'],
8 | input: 'src/index.js',
9 | output: [
10 | {
11 | file: pkg.main,
12 | format: 'cjs',
13 | },
14 | {
15 | file: pkg.module,
16 | format: 'esm',
17 | },
18 | ],
19 | };
20 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable consistent-return */
2 |
3 | import selectorParser from 'postcss-selector-parser';
4 | import valueParser from 'postcss-value-parser';
5 | import { name } from '../package.json';
6 |
7 | function postcssScrollbar({ width = '8px', edgeAutohide = false } = {}) {
8 | const widthMap = {
9 | none: '0',
10 | auto: 'initial',
11 | thin: width,
12 | };
13 |
14 | const colorMap = {
15 | auto: 'initial',
16 | dark: 'initial',
17 | light: 'initial',
18 | };
19 |
20 | function processWidth(decl, { result, Rule, Declaration }) {
21 | let { parent, value: keyword } = decl;
22 | let root = parent.parent;
23 |
24 | if (!isValidWidth(keyword)) {
25 | return decl.warn(
26 | result,
27 | 'Invalid value for property `scrollbar-width`. ' +
28 | 'Must be one of `auto | thin | none`.',
29 | { word: keyword }
30 | );
31 | }
32 |
33 | let processor = selectorParser(selectors => {
34 | selectors.each(selector => {
35 | selector.append(
36 | selectorParser.pseudo({
37 | value: '::-webkit-scrollbar',
38 | })
39 | );
40 | });
41 | });
42 |
43 | let newRule = new Rule({
44 | selector: processor.processSync(parent.selector),
45 | });
46 |
47 | newRule.append(
48 | new Declaration({
49 | prop: 'width',
50 | value: widthMap[keyword],
51 | }),
52 | new Declaration({
53 | prop: 'height',
54 | value: widthMap[keyword],
55 | })
56 | );
57 |
58 | root.insertBefore(parent, newRule);
59 |
60 | let value = do {
61 | if (edgeAutohide) {
62 | ('-ms-autohiding-scrollbar');
63 | } else if (keyword === 'none') {
64 | ('none');
65 | } else {
66 | ('auto');
67 | }
68 | };
69 |
70 | parent.insertBefore(decl, {
71 | prop: '-ms-overflow-style',
72 | value,
73 | });
74 | }
75 |
76 | function processColor(decl, { result, Rule, Declaration }) {
77 | let { nodes } = valueParser(decl.value);
78 |
79 | if (isInvalidColor(nodes)) {
80 | return decl.warn(
81 | result,
82 | 'Invalid value for property `scrollbar-color`. ' +
83 | 'Must be one of `auto | dark | light | `.',
84 | { word: nodes[0].value }
85 | );
86 | }
87 |
88 | function getColorValue(node) {
89 | if (colorMap[node.value]) {
90 | return colorMap[node.value];
91 | }
92 |
93 | if (node.type === 'word') {
94 | return node.value;
95 | }
96 |
97 | if (node.type === 'function') {
98 | return decl.value.slice(node.sourceIndex, node.sourceEndIndex);
99 | }
100 | }
101 |
102 | let values = nodes
103 | .filter(value => value.type === 'word' || value.type === 'function')
104 | .reduce((acc, curr, idx) => {
105 | if (idx >= 1) {
106 | return {
107 | ...acc,
108 | track: getColorValue(curr),
109 | corner: getColorValue(curr),
110 | };
111 | }
112 |
113 | return {
114 | thumb: getColorValue(curr),
115 | track: getColorValue(curr),
116 | corner: getColorValue(curr),
117 | };
118 | }, {});
119 |
120 | let { parent } = decl;
121 | let root = parent.parent;
122 |
123 | Object.keys(values).forEach(pseudo => {
124 | let processor = selectorParser(selectors => {
125 | selectors.each(selector => {
126 | selector.append(
127 | selectorParser.pseudo({
128 | value: `::-webkit-scrollbar-${pseudo}`,
129 | })
130 | );
131 | });
132 | });
133 |
134 | let newRule = new Rule({
135 | selector: processor.processSync(parent.selector),
136 | }).append(
137 | new Declaration({
138 | prop: 'background-color',
139 | value: values[pseudo],
140 | })
141 | );
142 |
143 | root.insertBefore(parent, newRule);
144 | });
145 | }
146 |
147 | return {
148 | postcssPlugin: name,
149 | Declaration: {
150 | 'scrollbar-width': processWidth,
151 | 'scrollbar-color': processColor,
152 | },
153 | };
154 | }
155 |
156 | function isValidWidth(keyword) {
157 | return /auto|thin|none/.test(keyword);
158 | }
159 |
160 | function isInvalidColor(nodes) {
161 | return (
162 | Array.isArray(nodes) &&
163 | nodes.length === 1 &&
164 | !/auto|dark|light/.test(nodes[0].value)
165 | );
166 | }
167 |
168 | postcssScrollbar.postcss = true;
169 |
170 | export default postcssScrollbar;
171 |
--------------------------------------------------------------------------------
/test/.eslintrc:
--------------------------------------------------------------------------------
1 | ---
2 | rules:
3 | import/no-extraneous-dependencies: off
4 |
--------------------------------------------------------------------------------
/test/__snapshots__/color.spec.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`color: 1`] = `
4 | ".test::-webkit-scrollbar-thumb {
5 | background-color: rebeccapurple;
6 | }
7 | .test::-webkit-scrollbar-track {
8 | background-color: green;
9 | }
10 | .test::-webkit-scrollbar-corner {
11 | background-color: green;
12 | }
13 | .test {
14 | scrollbar-color: rebeccapurple green;
15 | }"
16 | `;
17 |
18 | exports[`color: erroneous keyword 1`] = `
19 | ".test {
20 | scrollbar-color: blue;
21 | }"
22 | `;
23 |
24 | exports[`color: functional color 1`] = `
25 | ".test::-webkit-scrollbar-thumb {
26 | background-color: rgb(255, 0, 0);
27 | }
28 | .test::-webkit-scrollbar-track {
29 | background-color: transparent;
30 | }
31 | .test::-webkit-scrollbar-corner {
32 | background-color: transparent;
33 | }
34 | .test {
35 | scrollbar-color: rgb(255, 0, 0) transparent;
36 | }"
37 | `;
38 |
39 | exports[`color: keyword 1`] = `
40 | ".test::-webkit-scrollbar-thumb {
41 | background-color: initial;
42 | }
43 | .test::-webkit-scrollbar-track {
44 | background-color: initial;
45 | }
46 | .test::-webkit-scrollbar-corner {
47 | background-color: initial;
48 | }
49 | .test {
50 | scrollbar-color: dark;
51 | }"
52 | `;
53 |
--------------------------------------------------------------------------------
/test/__snapshots__/control.spec.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`control: PostCSS API 1`] = `
4 | ".test::-webkit-scrollbar {
5 | width: 8px;
6 | height: 8px;
7 | }
8 | .test {
9 | -ms-overflow-style: auto;
10 | scrollbar-width: thin;
11 | }"
12 | `;
13 |
14 | exports[`control: no options 1`] = `
15 | ".test::-webkit-scrollbar {
16 | width: 8px;
17 | height: 8px;
18 | }
19 | .test {
20 | -ms-overflow-style: auto;
21 | scrollbar-width: thin;
22 | }"
23 | `;
24 |
25 | exports[`control: with options 1`] = `
26 | ".test::-webkit-scrollbar {
27 | width: 8px;
28 | height: 8px;
29 | }
30 | .test {
31 | -ms-overflow-style: auto;
32 | scrollbar-width: thin;
33 | }"
34 | `;
35 |
--------------------------------------------------------------------------------
/test/__snapshots__/options.spec.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`options: default options 1`] = `
4 | ".test::-webkit-scrollbar {
5 | width: initial;
6 | height: initial;
7 | }
8 | .test {
9 | -ms-overflow-style: auto;
10 | scrollbar-width: auto;
11 | }"
12 | `;
13 |
14 | exports[`options: the \`edgeAutohide\` options 1`] = `
15 | ".test::-webkit-scrollbar {
16 | width: 0;
17 | height: 0;
18 | }
19 | .test {
20 | -ms-overflow-style: -ms-autohiding-scrollbar;
21 | scrollbar-width: none;
22 | }"
23 | `;
24 |
25 | exports[`options: the \`width\` options 1`] = `
26 | ".test::-webkit-scrollbar {
27 | width: 11px;
28 | height: 11px;
29 | }
30 | .test {
31 | -ms-overflow-style: auto;
32 | scrollbar-width: thin;
33 | }"
34 | `;
35 |
--------------------------------------------------------------------------------
/test/__snapshots__/width.spec.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`width: auto keyword 1`] = `
4 | ".test::-webkit-scrollbar {
5 | width: initial;
6 | height: initial;
7 | }
8 | .test {
9 | -ms-overflow-style: auto;
10 | scrollbar-width: auto;
11 | }"
12 | `;
13 |
14 | exports[`width: erroneous keyword 1`] = `
15 | ".test {
16 | scrollbar-width: 1rem;
17 | }"
18 | `;
19 |
20 | exports[`width: none keyword 1`] = `
21 | ".test::-webkit-scrollbar {
22 | width: 0;
23 | height: 0;
24 | }
25 | .test {
26 | -ms-overflow-style: none;
27 | scrollbar-width: none;
28 | }"
29 | `;
30 |
31 | exports[`width: thin keyword 1`] = `
32 | ".test::-webkit-scrollbar {
33 | width: 8px;
34 | height: 8px;
35 | }
36 | .test {
37 | -ms-overflow-style: auto;
38 | scrollbar-width: thin;
39 | }"
40 | `;
41 |
--------------------------------------------------------------------------------
/test/color.spec.js:
--------------------------------------------------------------------------------
1 | import postcss from 'postcss';
2 | import { stripIndent } from 'common-tags';
3 | import plugin from '../src';
4 |
5 | let from, to;
6 | let run = input => postcss().use(plugin).process(input, { from, to });
7 |
8 | describe('color:', () => {
9 | test(' ', async () => {
10 | let input = stripIndent`
11 | .test {
12 | scrollbar-color: rebeccapurple green;
13 | }
14 | `;
15 |
16 | let result = await run(input);
17 | expect(result.css).toMatchSnapshot();
18 | });
19 |
20 | test('keyword', async () => {
21 | let input = stripIndent`
22 | .test {
23 | scrollbar-color: dark;
24 | }
25 | `;
26 |
27 | let result = await run(input);
28 | expect(result.css).toMatchSnapshot();
29 | });
30 |
31 | test('functional color', async () => {
32 | let input = stripIndent`
33 | .test {
34 | scrollbar-color: rgb(255, 0, 0) transparent;
35 | }
36 | `;
37 |
38 | let result = await run(input);
39 | expect(result.css).toMatchSnapshot();
40 | });
41 |
42 | test('erroneous keyword', async () => {
43 | let input = stripIndent`
44 | .test {
45 | scrollbar-color: blue;
46 | }
47 | `;
48 |
49 | let result = await run(input);
50 |
51 | expect(result.css).toMatchSnapshot();
52 | expect(result.messages.length).toBeGreaterThan(0);
53 | expect(result.messages[0].type).toBe('warning');
54 | expect(result.messages[0].text).toMatch(
55 | /Invalid value for property `scrollbar-color`/
56 | );
57 | });
58 | });
59 |
--------------------------------------------------------------------------------
/test/control.spec.js:
--------------------------------------------------------------------------------
1 | import postcss from 'postcss';
2 | import { stripIndent } from 'common-tags';
3 | import { name } from '../package.json';
4 | import plugin from '../src';
5 |
6 | let from, to;
7 | let input = stripIndent`
8 | .test {
9 | scrollbar-width: thin;
10 | }
11 | `;
12 |
13 | describe('control:', () => {
14 | test('no options', () =>
15 | postcss()
16 | .use(plugin)
17 | .process(input, { from, to })
18 | .then(result => {
19 | expect(result.css).toMatchSnapshot();
20 | }));
21 |
22 | test('with options', () =>
23 | postcss()
24 | .use(plugin({}))
25 | .process(input, { from, to })
26 | .then(result => {
27 | expect(result.css).toMatchSnapshot();
28 | }));
29 |
30 | test('PostCSS API', async () => {
31 | let processor = postcss();
32 | let result = await processor.use(plugin).process(input, { from, to });
33 |
34 | expect(result.css).toMatchSnapshot();
35 | expect(processor.plugins[0].postcssPlugin).toBe(name);
36 | });
37 | });
38 |
--------------------------------------------------------------------------------
/test/options.spec.js:
--------------------------------------------------------------------------------
1 | import postcss from 'postcss';
2 | import { stripIndent } from 'common-tags';
3 | import plugin from '../src';
4 |
5 | let from, to;
6 |
7 | describe('options:', () => {
8 | test('default options', () => {
9 | let input = stripIndent`
10 | .test {
11 | scrollbar-width: auto;
12 | }
13 | `;
14 |
15 | return postcss()
16 | .use(plugin)
17 | .process(input, { from, to })
18 | .then(result => {
19 | expect(result.css).toMatchSnapshot();
20 | });
21 | });
22 |
23 | test('the `width` options', () => {
24 | let input = stripIndent`
25 | .test {
26 | scrollbar-width: thin;
27 | }
28 | `;
29 |
30 | return postcss()
31 | .use(plugin({ width: '11px' }))
32 | .process(input, { from, to })
33 | .then(result => {
34 | expect(result.css).toMatchSnapshot();
35 | });
36 | });
37 |
38 | test('the `edgeAutohide` options', () => {
39 | let input = stripIndent`
40 | .test {
41 | scrollbar-width: none;
42 | }
43 | `;
44 |
45 | return postcss()
46 | .use(plugin({ edgeAutohide: true }))
47 | .process(input, { from, to })
48 | .then(result => {
49 | expect(result.css).toMatchSnapshot();
50 | });
51 | });
52 | });
53 |
--------------------------------------------------------------------------------
/test/width.spec.js:
--------------------------------------------------------------------------------
1 | import postcss from 'postcss';
2 | import { stripIndent } from 'common-tags';
3 | import plugin from '../src';
4 |
5 | let from, to;
6 |
7 | describe('width:', () => {
8 | test('auto keyword', () => {
9 | let input = stripIndent`
10 | .test {
11 | scrollbar-width: auto;
12 | }
13 | `;
14 |
15 | return postcss([plugin()])
16 | .process(input, { from, to })
17 | .then(result => {
18 | expect(result.css).toMatchSnapshot();
19 | });
20 | });
21 |
22 | test('thin keyword', () => {
23 | let input = stripIndent`
24 | .test {
25 | scrollbar-width: thin;
26 | }
27 | `;
28 |
29 | return postcss([plugin()])
30 | .process(input, { from, to })
31 | .then(result => {
32 | expect(result.css).toMatchSnapshot();
33 | });
34 | });
35 |
36 | test('none keyword', () => {
37 | let input = stripIndent`
38 | .test {
39 | scrollbar-width: none;
40 | }
41 | `;
42 |
43 | return postcss([plugin()])
44 | .process(input, { from, to })
45 | .then(result => {
46 | expect(result.css).toMatchSnapshot();
47 | });
48 | });
49 |
50 | test('erroneous keyword', async () => {
51 | let input = stripIndent`
52 | .test {
53 | scrollbar-width: 1rem;
54 | }
55 | `;
56 |
57 | let result = await postcss().use(plugin).process(input, { from, to });
58 |
59 | expect(result.css).toMatchSnapshot();
60 | expect(result.messages.length).toBeGreaterThan(0);
61 | expect(result.messages[0].type).toBe('warning');
62 | expect(result.messages[0].text).toMatch(
63 | /Invalid value for property `scrollbar-width`/
64 | );
65 | });
66 | });
67 |
--------------------------------------------------------------------------------