stylelint-gamut 1.3.2 → 1.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,9 +6,9 @@
6
6
 
7
7
  # Rules
8
8
 
9
- * [`color-no-out-gamut-range`](./src/README.md): Throw warning if color goes out of sRGB color space and is not wrapped in `@media (color-gamut: p3) {}` or `@media (color-gamut: rec2020) {}`.
9
+ - [`color-no-out-gamut-range`](./src/README.md): Throw warning if color goes out of sRGB color space and is not wrapped in `@media (color-gamut: p3) {}` or `@media (color-gamut: rec2020) {}`.
10
10
 
11
- # Requirements
11
+ # Requirements
12
12
 
13
13
  - **node version ≥ 12.0.0**
14
14
  - **Stylelint version ≥ 14.0.0**.
@@ -33,22 +33,23 @@ Add `stylelint-gamut` to your Stylelint config `plugins` array, then add rules y
33
33
 
34
34
  ```json
35
35
  {
36
- "plugins": [
37
- "stylelint-gamut"
38
- ],
36
+ "plugins": ["stylelint-gamut"],
39
37
  "rules": {
40
- "gamut/color-no-out-gamut-range": true,
38
+ "gamut/color-no-out-gamut-range": true
41
39
  }
42
40
  }
43
41
  ```
44
42
 
45
43
  # More
44
+
46
45
  It is already used by the creator of [PostCSS] [Andrey Sitnik].
47
46
 
48
47
  Read more about color spaces in css:
48
+
49
49
  - [OKLCH in CSS: why we moved from RGB and HSL](https://evilmartians.com/chronicles/oklch-in-css-why-quit-rgb-hsl)
50
50
  - [LCH colors in CSS: what, why, and how?](https://lea.verou.me/2020/04/lch-colors-in-css-what-why-and-how/)
51
51
  - [A Guide To Modern CSS Colors](https://www.smashingmagazine.com/2021/11/guide-modern-css-colors/)
52
+ - [Better dynamic themes in Tailwind with OKLCH color magic](https://evilmartians.com/chronicles/better-dynamic-themes-in-tailwind-with-oklch-color-magic)
52
53
 
53
54
  [Stylelint]: https://stylelint.io/
54
55
  [npm-version-img]: https://img.shields.io/npm/v/stylelint-gamut.svg
package/package.json CHANGED
@@ -1,14 +1,17 @@
1
1
  {
2
2
  "name": "stylelint-gamut",
3
- "version": "1.3.2",
3
+ "version": "1.3.4",
4
4
  "description": "Stylelint plugin for working with different color spaces",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
7
+ "format": "prettier --write .",
8
+ "lint": "eslint --fix *.js",
7
9
  "test": "jest",
8
10
  "prepare": "husky install"
9
11
  },
10
12
  "lint-staged": {
11
- "*.js": "eslint --fix"
13
+ "*.js": "eslint --fix",
14
+ ".": "prettier -write"
12
15
  },
13
16
  "engines": {
14
17
  "node": ">=16.0.0"
@@ -37,22 +40,24 @@
37
40
  },
38
41
  "homepage": "https://github.com/fpetrakov/stylelint-gamut#readme",
39
42
  "peerDependencies": {
40
- "stylelint": "^14.0.0 || ^15.0.0"
43
+ "stylelint": "^14.0.0 || ^15.0.0 || ^16.0.0"
41
44
  },
42
45
  "devDependencies": {
43
- "eslint": "^8.22.0",
44
- "eslint-config-standard": "^17.0.0",
45
- "eslint-plugin-import": "^2.26.0",
46
- "eslint-plugin-n": "^15.2.4",
47
- "eslint-plugin-promise": "^6.0.0",
48
- "husky": "^8.0.1",
49
- "jest": "^28.1.3",
50
- "jest-cli": "^28.1.3",
51
- "jest-preset-stylelint": "^5.0.4",
52
- "lint-staged": "^13.0.3",
53
- "stylelint": "^14.10.0"
46
+ "eslint": "^8.43.0",
47
+ "eslint-config-prettier": "^9.0.0",
48
+ "eslint-config-standard": "^17.1.0",
49
+ "eslint-plugin-import": "^2.27.5",
50
+ "eslint-plugin-n": "^16.0.0",
51
+ "eslint-plugin-promise": "^6.1.1",
52
+ "husky": "^8.0.3",
53
+ "jest": "^29.5.0",
54
+ "jest-cli": "^29.5.0",
55
+ "jest-preset-stylelint": "^6.1.0",
56
+ "lint-staged": "^15.0.2",
57
+ "prettier": "^3.0.3",
58
+ "stylelint": "^15.7.0"
54
59
  },
55
60
  "dependencies": {
56
- "colorjs.io": "^0.4.0"
61
+ "colorjs.io": "^0.4.5"
57
62
  }
58
63
  }
package/src/README.md CHANGED
@@ -4,9 +4,7 @@ Disallow out of gamut range colors.
4
4
 
5
5
  <!-- prettier-ignore -->
6
6
  ```css
7
- a { color: lch(48% 82 283) }
8
- /** ↑
9
- * This color is out of sRGB gamut range */
7
+ a { color: lch(48% 82 283) } /* This color is out of sRGB gamut range */
10
8
  ```
11
9
 
12
10
  Colors declared using lch, oklch, lab and oklab functions can move from sRGB to P3 or Rec2020 color spaces, which are not supported by most of screens right now. It can happen by mistake. For instance, by converting colors from one space to another.
@@ -17,20 +15,18 @@ This rule checks if the color is in sRGB, p3 or rec2020 space. If it's not in sR
17
15
  @media (color-gamut: p3) {
18
16
  a {
19
17
  color: lch(29.8% 42.5 109.485);
18
+ /* This color is in p3 gamut range */
20
19
  }
21
20
  }
22
- /** ↑
23
- * This color is in p3 gamut range */
24
21
  ```
25
22
 
26
23
  ```css
27
24
  @media (color-gamut: rec2020) {
28
25
  a {
29
26
  color: lch(25.1% 42.5 109.485);
27
+ /* This color is in rec2020 gamut range */
30
28
  }
31
29
  }
32
- /** ↑
33
- * This color is in rec2020 gamut range */
34
30
  ```
35
31
 
36
32
  In case of **css custom properties** you should wrap either the custom property declaration:
@@ -42,6 +38,7 @@ In case of **css custom properties** you should wrap either the custom property
42
38
  }
43
39
  }
44
40
  ```
41
+
45
42
  or the rule that uses the custom property:
46
43
 
47
44
  ```css
@@ -55,7 +52,9 @@ or the rule that uses the custom property:
55
52
  Custom properties inside color declaration are ignored:
56
53
 
57
54
  ```css
58
- background-color: oklch(var(--oklch-primary) / var(--alpha-bg)); /* not checked */
55
+ background-color: oklch(
56
+ var(--oklch-primary) / var(--alpha-bg)
57
+ ); /* not checked */
59
58
  ```
60
59
 
61
60
  Please note that conditional imports are not checked, e.g.:
package/src/index.js CHANGED
@@ -1,97 +1,110 @@
1
- 'use strict'
1
+ "use strict";
2
+
3
+ const stylelint = require("stylelint");
4
+ const Color = require("colorjs.io").default;
2
5
 
3
- const stylelint = require('stylelint')
4
- const Color = require('colorjs.io').default
5
6
  const {
6
- isInColorGamutP3MediaQuery,
7
- isStandardSyntaxProperty,
8
- declarationValueIndex,
9
- isInColorGamutRec2020MediaQuery,
10
- startsWithNumber
11
- } = require('./utils')
7
+ isInColorGamutP3MediaQuery,
8
+ isStandardSyntaxProperty,
9
+ declarationValueIndex,
10
+ isInColorGamutRec2020MediaQuery,
11
+ startsWithNumber,
12
+ } = require("./utils");
12
13
 
13
- const ruleName = 'gamut/color-no-out-gamut-range'
14
+ const ruleName = "gamut/color-no-out-gamut-range";
14
15
 
15
16
  const messages = stylelint.utils.ruleMessages(ruleName, {
16
- rejected: (color) => `Unexpected color out of gamut range "${color}"`
17
- })
17
+ rejected: (color) => `Unexpected color out of gamut range "${color}"`,
18
+ });
18
19
 
19
20
  const meta = {
20
- url: 'https://github.com/fpetrakov/stylelint-gamut/blob/master/src/README.md'
21
- }
21
+ url: "https://github.com/fpetrakov/stylelint-gamut/blob/master/src/README.md",
22
+ };
22
23
 
23
24
  /** @type {import('stylelint').Rule} */
24
25
  const ruleFunction = (primary) => {
25
- return (root, result) => {
26
- const validOptions = stylelint.utils.validateOptions(result, ruleName, {
27
- actual: primary
28
- })
29
-
30
- if (!validOptions) {
31
- return
32
- }
33
-
34
- const customProperties = {}
35
-
36
- root.walkDecls((decl) => {
37
- if (!isStandardSyntaxProperty(decl.prop)) return
38
-
39
- const values = decl.value.match(/(oklch|oklab|lab|lch|var)\([^)]+\)/g)
40
- if (values) {
41
- for (const value of values) {
42
- check(value)
43
- }
44
- }
45
-
46
- // value is e.g. lch(48% 82 283 / 67%)
47
- function check (value) {
48
- const shouldBeIgnored =
49
- !value.startsWith('var(--') &&
50
- (
51
- value.includes('var(--') ||
52
- !startsWithNumber(value.split('(')[1])
53
- )
54
-
55
- if (shouldBeIgnored) return
56
-
57
- let customPropValue
58
- if (value.startsWith('var(--')) {
59
- const varName = value.slice(4, -1)
60
- if (customProperties[varName] && !customProperties[varName].inQuery) {
61
- customPropValue = customProperties[varName].value
62
- } else {
63
- return
64
- }
65
- }
66
-
67
- const color = new Color(customPropValue || value)
68
-
69
- if (color.inGamut('srgb')) return
70
- if (color.inGamut('p3') && isInColorGamutP3MediaQuery(decl)) return
71
- if (color.inGamut('rec2020') && isInColorGamutRec2020MediaQuery(decl)) return
72
-
73
- if (decl.prop && decl.prop.startsWith('--')) {
74
- customProperties[decl.prop] = { value: decl.value.trim(), inQuery: false }
75
- return
76
- }
77
-
78
- const index = declarationValueIndex(decl)
79
- const endIndex = index + decl.value.length
80
- stylelint.utils.report({
81
- message: messages.rejected(value),
82
- node: decl,
83
- index,
84
- endIndex,
85
- result,
86
- ruleName
87
- })
88
- }
89
- })
90
- }
91
- }
92
-
93
- ruleFunction.ruleName = ruleName
94
- ruleFunction.messages = messages
95
- ruleFunction.meta = meta
96
-
97
- module.exports = stylelint.createPlugin(ruleName, ruleFunction)
26
+ return (root, result) => {
27
+ const validOptions = stylelint.utils.validateOptions(result, ruleName, {
28
+ actual: primary,
29
+ });
30
+
31
+ if (!validOptions) {
32
+ return;
33
+ }
34
+
35
+ const customProperties = {};
36
+
37
+ root.walkDecls((decl) => {
38
+ if (!isStandardSyntaxProperty(decl.prop)) return;
39
+
40
+ const values = decl.value.match(
41
+ /(oklch|oklab|lab|lch|var)\([^)]+\)/g,
42
+ );
43
+
44
+ if (!values) return;
45
+
46
+ // value is e.g. lch(48% 82 283 / 67%)
47
+ for (const value of values) {
48
+ check(value);
49
+ }
50
+
51
+ function check(value) {
52
+ const shouldBeIgnored =
53
+ !value.startsWith("var(--") &&
54
+ (value.includes("var(--") ||
55
+ !startsWithNumber(value.split("(")[1]));
56
+
57
+ if (shouldBeIgnored) return;
58
+
59
+ let customPropValue;
60
+ if (value.startsWith("var(--")) {
61
+ const varName = value.slice(4, -1);
62
+ if (
63
+ customProperties[varName] &&
64
+ !customProperties[varName].inQuery
65
+ ) {
66
+ customPropValue = customProperties[varName].value;
67
+ } else {
68
+ return;
69
+ }
70
+ }
71
+
72
+ const color = new Color(customPropValue || value);
73
+
74
+ if (color.inGamut("srgb")) return;
75
+ if (color.inGamut("p3") && isInColorGamutP3MediaQuery(decl))
76
+ return;
77
+ if (
78
+ color.inGamut("rec2020") &&
79
+ isInColorGamutRec2020MediaQuery(decl)
80
+ )
81
+ return;
82
+
83
+ if (decl.prop && decl.prop.startsWith("--")) {
84
+ customProperties[decl.prop] = {
85
+ value: decl.value.trim(),
86
+ inQuery: false,
87
+ };
88
+ return;
89
+ }
90
+
91
+ const index = declarationValueIndex(decl);
92
+ const endIndex = index + decl.value.length;
93
+ stylelint.utils.report({
94
+ message: messages.rejected(value),
95
+ node: decl,
96
+ index,
97
+ endIndex,
98
+ result,
99
+ ruleName,
100
+ });
101
+ }
102
+ });
103
+ };
104
+ };
105
+
106
+ ruleFunction.ruleName = ruleName;
107
+ ruleFunction.messages = messages;
108
+ ruleFunction.meta = meta;
109
+
110
+ module.exports = stylelint.createPlugin(ruleName, ruleFunction);
package/src/utils.js CHANGED
@@ -1,4 +1,4 @@
1
- 'use strict'
1
+ "use strict";
2
2
 
3
3
  /**
4
4
  * Get the index of a declaration's value
@@ -6,23 +6,23 @@
6
6
  * @param {import('postcss').Declaration} decl
7
7
  * @returns {number}
8
8
  */
9
- function declarationValueIndex (decl) {
10
- const raws = decl.raws
11
-
12
- return [
13
- raws.prop && raws.prop.prefix,
14
- (raws.prop && raws.prop.raw) || decl.prop,
15
- raws.prop && raws.prop.suffix,
16
- raws.between || ':',
17
- raws.value && raws.value.prefix
18
- ].reduce((count, str) => {
19
- if (str) {
20
- return count + str.length
21
- }
22
-
23
- return count
24
- }, 0)
25
- }
9
+ const declarationValueIndex = (decl) => {
10
+ const raws = decl.raws;
11
+
12
+ return [
13
+ raws.prop && raws.prop.prefix,
14
+ (raws.prop && raws.prop.raw) || decl.prop,
15
+ raws.prop && raws.prop.suffix,
16
+ raws.between || ":",
17
+ raws.value && raws.value.prefix,
18
+ ].reduce((count, str) => {
19
+ if (str) {
20
+ return count + str.length;
21
+ }
22
+
23
+ return count;
24
+ }, 0);
25
+ };
26
26
 
27
27
  /**
28
28
  * Check whether a property is standard
@@ -30,83 +30,85 @@ function declarationValueIndex (decl) {
30
30
  * @param {string} property
31
31
  * @return {boolean} If `true`, the property is standard
32
32
  */
33
- function isStandardSyntaxProperty (property) {
34
- // SCSS var (e.g. $var: x), list (e.g. $list: (x)) or map (e.g. $map: (key:value))
35
- if (property.startsWith('$')) {
36
- return false
37
- }
33
+ const isStandardSyntaxProperty = (property) => {
34
+ // SCSS var (e.g. $var: x), list (e.g. $list: (x)) or map (e.g. $map: (key:value))
35
+ if (property.startsWith("$")) {
36
+ return false;
37
+ }
38
38
 
39
- // Less var (e.g. @var: x)
40
- if (property.startsWith('@')) {
41
- return false
42
- }
39
+ // Less var (e.g. @var: x)
40
+ if (property.startsWith("@")) {
41
+ return false;
42
+ }
43
43
 
44
- // SCSS or Less interpolation
45
- if (/#{.+?}|@{.+?}|\$\(.+?\)/.test(property)) {
46
- return false
47
- }
44
+ // SCSS or Less interpolation
45
+ if (/#{.+?}|@{.+?}|\$\(.+?\)/.test(property)) {
46
+ return false;
47
+ }
48
48
 
49
- return true
50
- }
49
+ return true;
50
+ };
51
51
 
52
52
  /**
53
53
  * @param {import('postcss').Declaration} decl
54
54
  * @returns {boolean}
55
55
  */
56
- function isInColorGamutP3MediaQuery (decl) {
57
- const parentMediaQuery = getMediaQueryParent(decl)
56
+ const isInColorGamutP3MediaQuery = (decl) => {
57
+ const parentMediaQuery = getMediaQueryParent(decl);
58
58
 
59
- if (parentMediaQuery && /\(color-gamut:\s*p3\)/.test(parentMediaQuery.params)) {
60
- return true
61
- }
59
+ if (
60
+ parentMediaQuery &&
61
+ /\(color-gamut:\s*p3\)/.test(parentMediaQuery.params)
62
+ ) {
63
+ return true;
64
+ }
62
65
 
63
- return false
64
- }
66
+ return false;
67
+ };
65
68
 
66
69
  /**
67
70
  * @param {import('postcss').Declaration} decl
68
71
  * @returns {boolean}
69
72
  */
70
- function isInColorGamutRec2020MediaQuery (decl) {
71
- const parentMediaQuery = getMediaQueryParent(decl)
73
+ const isInColorGamutRec2020MediaQuery = (decl) => {
74
+ const parentMediaQuery = getMediaQueryParent(decl);
72
75
 
73
- if (parentMediaQuery && /\(color-gamut:\s*rec2020\)/.test(parentMediaQuery.params)) {
74
- return true
75
- }
76
+ if (
77
+ parentMediaQuery &&
78
+ /\(color-gamut:\s*rec2020\)/.test(parentMediaQuery.params)
79
+ ) {
80
+ return true;
81
+ }
76
82
 
77
- return false
78
- }
83
+ return false;
84
+ };
79
85
 
80
86
  /**
81
87
  * @param {import('postcss').Declaration} decl
82
88
  * @returns {boolean | decl}
83
89
  */
84
- function getMediaQueryParent (decl) {
85
- let parent = decl.parent
90
+ const getMediaQueryParent = (decl) => {
91
+ let parent = decl.parent;
86
92
 
87
- if (parent && isMediaQuery(parent)) return parent
93
+ if (parent && isMediaQuery(parent)) return parent;
88
94
 
89
- parent = parent.parent
95
+ parent = parent.parent;
90
96
 
91
- return isMediaQuery(parent) && parent
92
- }
97
+ return isMediaQuery(parent) && parent;
98
+ };
93
99
 
94
100
  /**
95
101
  * @param {import('postcss').Declaration} decl
96
102
  * @returns {boolean}
97
103
  */
98
- function isMediaQuery (decl) {
99
- return decl.type === 'atrule' && decl.name === 'media'
100
- }
104
+ const isMediaQuery = (decl) => decl.type === "atrule" && decl.name === "media";
101
105
 
102
- function startsWithNumber (str) {
103
- return /^\d/.test(str)
104
- }
106
+ const startsWithNumber = (str) => /^\d/.test(str);
105
107
 
106
108
  module.exports = {
107
- isStandardSyntaxProperty,
108
- declarationValueIndex,
109
- isInColorGamutP3MediaQuery,
110
- isInColorGamutRec2020MediaQuery,
111
- startsWithNumber
112
- }
109
+ isStandardSyntaxProperty,
110
+ declarationValueIndex,
111
+ isInColorGamutP3MediaQuery,
112
+ isInColorGamutRec2020MediaQuery,
113
+ startsWithNumber,
114
+ };