storybook-addon-pseudo-states 1.14.0 → 1.15.1
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/CHANGELOG.md +39 -0
- package/README.md +24 -1
- package/dist/cjs/PseudoStateTool.js +39 -68
- package/dist/cjs/constants.js +3 -3
- package/dist/cjs/preset/manager.js +5 -3
- package/dist/cjs/preset/preview.js +1 -1
- package/dist/cjs/rewriteStyleSheet.js +87 -0
- package/dist/cjs/rewriteStyleSheet.test.js +70 -0
- package/dist/cjs/splitSelectors.js +8 -10
- package/dist/cjs/splitSelectors.test.js +4 -4
- package/dist/cjs/withPseudoState.js +67 -196
- package/dist/esm/PseudoStateTool.js +36 -63
- package/dist/esm/constants.js +3 -3
- package/dist/esm/preset/manager.js +5 -3
- package/dist/esm/preset/preview.js +1 -1
- package/dist/esm/rewriteStyleSheet.js +76 -0
- package/dist/esm/rewriteStyleSheet.test.js +68 -0
- package/dist/esm/splitSelectors.js +8 -10
- package/dist/esm/splitSelectors.test.js +4 -4
- package/dist/esm/withPseudoState.js +65 -192
- package/package.json +10 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,42 @@
|
|
|
1
|
+
# v1.15.1 (Wed Jun 22 2022)
|
|
2
|
+
|
|
3
|
+
#### 🐛 Bug Fix
|
|
4
|
+
|
|
5
|
+
- Update react and react-dom peer dependencies level [#35](https://github.com/chromaui/storybook-addon-pseudo-states/pull/35) ([@dsueltenfuss](https://github.com/dsueltenfuss))
|
|
6
|
+
|
|
7
|
+
#### Authors: 1
|
|
8
|
+
|
|
9
|
+
- Dave Sueltenfuss ([@dsueltenfuss](https://github.com/dsueltenfuss))
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# v1.15.0 (Thu Jun 16 2022)
|
|
14
|
+
|
|
15
|
+
#### 🚀 Enhancement
|
|
16
|
+
|
|
17
|
+
- Add support for targeting specific elements [#25](https://github.com/chromaui/storybook-addon-pseudo-states/pull/25) (sagiv.bengiat@appsflyer.com [@ghengeveld](https://github.com/ghengeveld) [@sag1v](https://github.com/sag1v))
|
|
18
|
+
|
|
19
|
+
#### Authors: 3
|
|
20
|
+
|
|
21
|
+
- Gert Hengeveld ([@ghengeveld](https://github.com/ghengeveld))
|
|
22
|
+
- Sagiv ben giat ([@sag1v](https://github.com/sag1v))
|
|
23
|
+
- sagiv.bengiat (sagiv.bengiat@appsflyer.com)
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
# v1.14.1 (Wed Jun 15 2022)
|
|
28
|
+
|
|
29
|
+
#### ⚠️ Pushed to `main`
|
|
30
|
+
|
|
31
|
+
- Fix toolbar toggles ([@ghengeveld](https://github.com/ghengeveld))
|
|
32
|
+
- Upgrade Storybook ([@ghengeveld](https://github.com/ghengeveld))
|
|
33
|
+
|
|
34
|
+
#### Authors: 1
|
|
35
|
+
|
|
36
|
+
- Gert Hengeveld ([@ghengeveld](https://github.com/ghengeveld))
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
1
40
|
# v1.0.0 (Tue May 24 2022)
|
|
2
41
|
|
|
3
42
|
#### 🚀 Enhancement
|
package/README.md
CHANGED
|
@@ -41,9 +41,32 @@ module.exports = {
|
|
|
41
41
|
|
|
42
42
|
You can have your stories automatically use a specific set of pseudo states, by setting the `pseudo` property on `parameters`:
|
|
43
43
|
|
|
44
|
-
```
|
|
44
|
+
```jsx
|
|
45
45
|
export const Hover = () => <Button>Label</Button>
|
|
46
46
|
Hover.parameters = { pseudo: { hover: true } }
|
|
47
47
|
```
|
|
48
48
|
|
|
49
49
|
This is what enables snapshot testing your pseudo states in [Chromatic](https://www.chromatic.com/).
|
|
50
|
+
|
|
51
|
+
### Targeting specific elements
|
|
52
|
+
|
|
53
|
+
If you don't want to force or toggle pseudo styles to all elements that use them, but rather only enable them on specific elements, you can set a string or array value instead of a boolean:
|
|
54
|
+
|
|
55
|
+
```jsx
|
|
56
|
+
export const Buttons = () => (
|
|
57
|
+
<>
|
|
58
|
+
<Button id="one">Hover</Button>
|
|
59
|
+
<Button id="two">Hover focus</Button>
|
|
60
|
+
<Button id="three">Hover focus active</Button>
|
|
61
|
+
</>
|
|
62
|
+
)
|
|
63
|
+
Buttons.parameters = {
|
|
64
|
+
pseudo: {
|
|
65
|
+
hover: ["#one", "#two", "#three"],
|
|
66
|
+
focus: ["#two", "#three"],
|
|
67
|
+
active: "#three",
|
|
68
|
+
},
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
This accepts a single CSS selector (string), or an array of CSS selectors on which to enable that pseudo style.
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
|
|
4
|
-
|
|
5
3
|
Object.defineProperty(exports, "__esModule", {
|
|
6
4
|
value: true
|
|
7
5
|
});
|
|
@@ -17,37 +15,23 @@ var _theming = require("@storybook/theming");
|
|
|
17
15
|
|
|
18
16
|
var _constants = require("./constants");
|
|
19
17
|
|
|
20
|
-
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function
|
|
21
|
-
|
|
22
|
-
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
23
|
-
|
|
24
|
-
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
25
|
-
|
|
26
|
-
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
27
|
-
|
|
28
|
-
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
29
|
-
|
|
30
|
-
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
|
31
|
-
|
|
32
|
-
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
18
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
33
19
|
|
|
34
|
-
function
|
|
20
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
35
21
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
41
|
-
|
|
42
|
-
var LinkTitle = _theming.styled.span(function (_ref) {
|
|
43
|
-
var active = _ref.active;
|
|
22
|
+
const LinkTitle = _theming.styled.span(_ref => {
|
|
23
|
+
let {
|
|
24
|
+
active
|
|
25
|
+
} = _ref;
|
|
44
26
|
return {
|
|
45
27
|
color: active ? _theming.color.secondary : "inherit"
|
|
46
28
|
};
|
|
47
29
|
});
|
|
48
30
|
|
|
49
|
-
|
|
50
|
-
|
|
31
|
+
const LinkIcon = (0, _theming.styled)(_components.Icons)(_ref2 => {
|
|
32
|
+
let {
|
|
33
|
+
active
|
|
34
|
+
} = _ref2;
|
|
51
35
|
return {
|
|
52
36
|
opacity: active ? 1 : 0,
|
|
53
37
|
path: {
|
|
@@ -55,54 +39,41 @@ var LinkIcon = (0, _theming.styled)(_components.Icons)(function (_ref2) {
|
|
|
55
39
|
}
|
|
56
40
|
};
|
|
57
41
|
});
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
return pseudo ? pseudo[option] : false;
|
|
71
|
-
}, [pseudo]);
|
|
72
|
-
var toggleOption = (0, _react.useCallback)(function (option) {
|
|
73
|
-
return function () {
|
|
74
|
-
return updateGlobals({
|
|
75
|
-
pseudo: _objectSpread(_objectSpread({}, pseudo), {}, _defineProperty({}, option, !getValue(option)))
|
|
76
|
-
});
|
|
77
|
-
};
|
|
78
|
-
}, [pseudo, getValue]);
|
|
42
|
+
const options = Object.keys(_constants.PSEUDO_STATES).sort();
|
|
43
|
+
|
|
44
|
+
const PseudoStateTool = () => {
|
|
45
|
+
const [{
|
|
46
|
+
pseudo
|
|
47
|
+
}, updateGlobals] = (0, _api.useGlobals)();
|
|
48
|
+
const isActive = (0, _react.useCallback)(option => (pseudo === null || pseudo === void 0 ? void 0 : pseudo[option]) === true, [pseudo]);
|
|
49
|
+
const toggleOption = (0, _react.useCallback)(option => () => updateGlobals({
|
|
50
|
+
pseudo: { ...pseudo,
|
|
51
|
+
[option]: !isActive(option)
|
|
52
|
+
}
|
|
53
|
+
}), [pseudo]);
|
|
79
54
|
return /*#__PURE__*/_react.default.createElement(_components.WithTooltip, {
|
|
80
55
|
placement: "top",
|
|
81
56
|
trigger: "click",
|
|
82
|
-
tooltip:
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
};
|
|
99
|
-
})
|
|
100
|
-
});
|
|
101
|
-
}
|
|
57
|
+
tooltip: () => /*#__PURE__*/_react.default.createElement(_components.TooltipLinkList, {
|
|
58
|
+
links: options.map(option => ({
|
|
59
|
+
id: option,
|
|
60
|
+
title: /*#__PURE__*/_react.default.createElement(LinkTitle, {
|
|
61
|
+
active: isActive(option)
|
|
62
|
+
}, ":", _constants.PSEUDO_STATES[option]),
|
|
63
|
+
right: /*#__PURE__*/_react.default.createElement(LinkIcon, {
|
|
64
|
+
icon: "check",
|
|
65
|
+
width: 12,
|
|
66
|
+
height: 12,
|
|
67
|
+
active: isActive(option)
|
|
68
|
+
}),
|
|
69
|
+
onClick: toggleOption(option),
|
|
70
|
+
active: isActive(option)
|
|
71
|
+
}))
|
|
72
|
+
})
|
|
102
73
|
}, /*#__PURE__*/_react.default.createElement(_components.IconButton, {
|
|
103
74
|
key: "pseudo-state",
|
|
104
75
|
title: "Select CSS pseudo states",
|
|
105
|
-
active:
|
|
76
|
+
active: options.some(isActive)
|
|
106
77
|
}, /*#__PURE__*/_react.default.createElement(_components.Icons, {
|
|
107
78
|
icon: "button"
|
|
108
79
|
})));
|
package/dist/cjs/constants.js
CHANGED
|
@@ -4,13 +4,13 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.TOOL_ID = exports.PSEUDO_STATES = exports.ADDON_ID = void 0;
|
|
7
|
-
|
|
7
|
+
const ADDON_ID = "storybook/pseudo-states";
|
|
8
8
|
exports.ADDON_ID = ADDON_ID;
|
|
9
|
-
|
|
9
|
+
const TOOL_ID = "".concat(ADDON_ID, "/tool"); // Dynamic pseudo-classes
|
|
10
10
|
// @see https://www.w3.org/TR/2018/REC-selectors-3-20181106/#dynamic-pseudos
|
|
11
11
|
|
|
12
12
|
exports.TOOL_ID = TOOL_ID;
|
|
13
|
-
|
|
13
|
+
const PSEUDO_STATES = {
|
|
14
14
|
hover: "hover",
|
|
15
15
|
active: "active",
|
|
16
16
|
focusVisible: "focus-visible",
|
|
@@ -6,12 +6,14 @@ var _constants = require("../constants");
|
|
|
6
6
|
|
|
7
7
|
var _PseudoStateTool = require("../PseudoStateTool");
|
|
8
8
|
|
|
9
|
-
_addons.addons.register(_constants.ADDON_ID,
|
|
9
|
+
_addons.addons.register(_constants.ADDON_ID, () => {
|
|
10
10
|
_addons.addons.add(_constants.TOOL_ID, {
|
|
11
11
|
type: _addons.types.TOOL,
|
|
12
12
|
title: "CSS pseudo states",
|
|
13
|
-
match:
|
|
14
|
-
|
|
13
|
+
match: _ref => {
|
|
14
|
+
let {
|
|
15
|
+
viewMode
|
|
16
|
+
} = _ref;
|
|
15
17
|
return viewMode === "story";
|
|
16
18
|
},
|
|
17
19
|
render: _PseudoStateTool.PseudoStateTool
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.rewriteStyleSheet = void 0;
|
|
7
|
+
|
|
8
|
+
var _constants = require("./constants");
|
|
9
|
+
|
|
10
|
+
var _splitSelectors = require("./splitSelectors");
|
|
11
|
+
|
|
12
|
+
const pseudoStates = Object.values(_constants.PSEUDO_STATES);
|
|
13
|
+
const matchOne = new RegExp(":(".concat(pseudoStates.join("|"), ")"));
|
|
14
|
+
const matchAll = new RegExp(":(".concat(pseudoStates.join("|"), ")"), "g");
|
|
15
|
+
const warnings = new Set();
|
|
16
|
+
|
|
17
|
+
const warnOnce = message => {
|
|
18
|
+
if (warnings.has(message)) return; // eslint-disable-next-line no-console
|
|
19
|
+
|
|
20
|
+
console.warn(message);
|
|
21
|
+
warnings.add(message);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const rewriteRule = (cssText, selectorText, shadowRoot) => {
|
|
25
|
+
return cssText.replace(selectorText, (0, _splitSelectors.splitSelectors)(selectorText).flatMap(selector => {
|
|
26
|
+
if (selector.includes(".pseudo-")) {
|
|
27
|
+
return [];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (!matchOne.test(selector)) {
|
|
31
|
+
return [selector];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const states = [];
|
|
35
|
+
const plainSelector = selector.replace(matchAll, (_, state) => {
|
|
36
|
+
states.push(state);
|
|
37
|
+
return "";
|
|
38
|
+
});
|
|
39
|
+
const classSelector = states.reduce((acc, state) => acc.replace(new RegExp(":".concat(state), "g"), ".pseudo-".concat(state)), selector);
|
|
40
|
+
|
|
41
|
+
if (selector.startsWith(":host(") || selector.startsWith("::slotted(")) {
|
|
42
|
+
return [selector, classSelector];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const ancestorSelector = shadowRoot ? ":host(".concat(states.map(s => ".pseudo-".concat(s)).join(""), ") ").concat(plainSelector) : "".concat(states.map(s => ".pseudo-".concat(s)).join(""), " ").concat(plainSelector);
|
|
46
|
+
return [selector, classSelector, ancestorSelector].filter(selector => !selector.includes(":not()"));
|
|
47
|
+
}).join(", "));
|
|
48
|
+
}; // Rewrites the style sheet to add alternative selectors for any rule that targets a pseudo state.
|
|
49
|
+
// A sheet can only be rewritten once, and may carry over between stories.
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
const rewriteStyleSheet = (sheet, shadowRoot, shadowHosts) => {
|
|
53
|
+
if (sheet.__pseudoStatesRewritten) return;
|
|
54
|
+
sheet.__pseudoStatesRewritten = true;
|
|
55
|
+
|
|
56
|
+
try {
|
|
57
|
+
let index = 0;
|
|
58
|
+
|
|
59
|
+
for (const {
|
|
60
|
+
cssText,
|
|
61
|
+
selectorText
|
|
62
|
+
} of sheet.cssRules) {
|
|
63
|
+
if (matchOne.test(selectorText)) {
|
|
64
|
+
const newRule = rewriteRule(cssText, selectorText, shadowRoot);
|
|
65
|
+
sheet.deleteRule(index);
|
|
66
|
+
sheet.insertRule(newRule, index);
|
|
67
|
+
if (shadowRoot) shadowHosts.add(shadowRoot.host);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
index++;
|
|
71
|
+
|
|
72
|
+
if (index > 1000) {
|
|
73
|
+
warnOnce("Reached maximum of 1000 pseudo selectors per sheet, skipping the rest.");
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
} catch (e) {
|
|
78
|
+
if (e.toString().includes("cssRules")) {
|
|
79
|
+
warnOnce("Can't access cssRules, likely due to CORS restrictions: ".concat(sheet.href));
|
|
80
|
+
} else {
|
|
81
|
+
// eslint-disable-next-line no-console
|
|
82
|
+
console.error(e, sheet.href);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
exports.rewriteStyleSheet = rewriteStyleSheet;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _rewriteStyleSheet = require("./rewriteStyleSheet");
|
|
4
|
+
|
|
5
|
+
class Sheet {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.__pseudoStatesRewritten = false;
|
|
8
|
+
|
|
9
|
+
for (var _len = arguments.length, rules = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
10
|
+
rules[_key] = arguments[_key];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
this.cssRules = rules.map(cssText => ({
|
|
14
|
+
cssText,
|
|
15
|
+
selectorText: cssText.slice(0, cssText.indexOf(" {"))
|
|
16
|
+
}));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
deleteRule(index) {
|
|
20
|
+
this.cssRules.splice(index, 1);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
insertRule(cssText, index) {
|
|
24
|
+
this.cssRules.splice(index, 0, cssText);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
describe("rewriteStyleSheet", () => {
|
|
30
|
+
it("adds alternative selector targeting the element directly", () => {
|
|
31
|
+
const sheet = new Sheet("a:hover { color: red }");
|
|
32
|
+
(0, _rewriteStyleSheet.rewriteStyleSheet)(sheet);
|
|
33
|
+
expect(sheet.cssRules[0]).toContain("a.pseudo-hover");
|
|
34
|
+
});
|
|
35
|
+
it("adds alternative selector targeting an ancestor", () => {
|
|
36
|
+
const sheet = new Sheet("a:hover { color: red }");
|
|
37
|
+
(0, _rewriteStyleSheet.rewriteStyleSheet)(sheet);
|
|
38
|
+
expect(sheet.cssRules[0]).toContain(".pseudo-hover a");
|
|
39
|
+
});
|
|
40
|
+
it("adds alternative selector for each pseudo selector", () => {
|
|
41
|
+
const sheet = new Sheet("a:hover, a:focus { color: red }");
|
|
42
|
+
(0, _rewriteStyleSheet.rewriteStyleSheet)(sheet);
|
|
43
|
+
expect(sheet.cssRules[0]).toContain("a.pseudo-hover");
|
|
44
|
+
expect(sheet.cssRules[0]).toContain("a.pseudo-focus");
|
|
45
|
+
expect(sheet.cssRules[0]).toContain(".pseudo-hover a");
|
|
46
|
+
expect(sheet.cssRules[0]).toContain(".pseudo-focus a");
|
|
47
|
+
});
|
|
48
|
+
it("keeps non-pseudo selectors as-is", () => {
|
|
49
|
+
const sheet = new Sheet("a.class, a:hover, a:focus, a#id { color: red }");
|
|
50
|
+
(0, _rewriteStyleSheet.rewriteStyleSheet)(sheet);
|
|
51
|
+
expect(sheet.cssRules[0]).toContain("a.class");
|
|
52
|
+
expect(sheet.cssRules[0]).toContain("a#id");
|
|
53
|
+
});
|
|
54
|
+
it("supports combined pseudo selectors", () => {
|
|
55
|
+
const sheet = new Sheet("a:hover:focus { color: red }");
|
|
56
|
+
(0, _rewriteStyleSheet.rewriteStyleSheet)(sheet);
|
|
57
|
+
expect(sheet.cssRules[0]).toContain("a.pseudo-hover.pseudo-focus");
|
|
58
|
+
expect(sheet.cssRules[0]).toContain(".pseudo-hover.pseudo-focus a");
|
|
59
|
+
});
|
|
60
|
+
it('supports ":host"', () => {
|
|
61
|
+
const sheet = new Sheet(":host(:hover) { color: red }");
|
|
62
|
+
(0, _rewriteStyleSheet.rewriteStyleSheet)(sheet);
|
|
63
|
+
expect(sheet.cssRules[0]).toEqual(":host(:hover), :host(.pseudo-hover) { color: red }");
|
|
64
|
+
});
|
|
65
|
+
it('supports ":not"', () => {
|
|
66
|
+
const sheet = new Sheet(":not(:hover) { color: red }");
|
|
67
|
+
(0, _rewriteStyleSheet.rewriteStyleSheet)(sheet);
|
|
68
|
+
expect(sheet.cssRules[0]).toEqual(":not(:hover), :not(.pseudo-hover) { color: red }");
|
|
69
|
+
});
|
|
70
|
+
});
|
|
@@ -5,19 +5,17 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.splitSelectors = void 0;
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
return selector.indexOf("@") === 0;
|
|
10
|
-
};
|
|
8
|
+
const isAtRule = selector => selector.indexOf("@") === 0;
|
|
11
9
|
|
|
12
|
-
|
|
10
|
+
const splitSelectors = selectors => {
|
|
13
11
|
if (isAtRule(selectors)) return [selectors];
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
let result = [];
|
|
13
|
+
let parentheses = 0;
|
|
14
|
+
let brackets = 0;
|
|
15
|
+
let selector = "";
|
|
18
16
|
|
|
19
|
-
for (
|
|
20
|
-
|
|
17
|
+
for (let i = 0, len = selectors.length; i < len; i++) {
|
|
18
|
+
const char = selectors[i];
|
|
21
19
|
|
|
22
20
|
if (char === "(") {
|
|
23
21
|
parentheses += 1;
|
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
var _splitSelectors = require("./splitSelectors");
|
|
4
4
|
|
|
5
|
-
describe("splitSelectors",
|
|
6
|
-
test("handles basic selectors",
|
|
5
|
+
describe("splitSelectors", () => {
|
|
6
|
+
test("handles basic selectors", () => {
|
|
7
7
|
expect((0, _splitSelectors.splitSelectors)(".a")).toEqual([".a"]);
|
|
8
8
|
expect((0, _splitSelectors.splitSelectors)(".a, .b")).toEqual([".a", ".b"]);
|
|
9
9
|
});
|
|
10
|
-
test("supports ::slotted and :is",
|
|
10
|
+
test("supports ::slotted and :is", () => {
|
|
11
11
|
expect((0, _splitSelectors.splitSelectors)("::slotted(:is(button, a):active)")).toEqual(["::slotted(:is(button, a):active)"]);
|
|
12
12
|
expect((0, _splitSelectors.splitSelectors)("::slotted(:is(button, a):active), ::slotted(:is(button, a):hover)")).toEqual(["::slotted(:is(button, a):active)", "::slotted(:is(button, a):hover)"]);
|
|
13
13
|
});
|
|
14
|
-
test("supports :host",
|
|
14
|
+
test("supports :host", () => {
|
|
15
15
|
expect((0, _splitSelectors.splitSelectors)(":host([type='secondary']) ::slotted(:is(button, a)), :host([type='primary']) ::slotted(:is(button, a):active)")).toEqual([":host([type='secondary']) ::slotted(:is(button, a))", ":host([type='primary']) ::slotted(:is(button, a):active)"]);
|
|
16
16
|
expect((0, _splitSelectors.splitSelectors)(":host([outline]) ::slotted(:is(button, a):focus-within:focus-visible:not(:active))")).toEqual([":host([outline]) ::slotted(:is(button, a):focus-within:focus-visible:not(:active))"]);
|
|
17
17
|
});
|