storybook-addon-pseudo-states 1.15.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 +12 -0
- package/dist/cjs/PseudoStateTool.js +38 -64
- 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 +31 -55
- package/dist/cjs/rewriteStyleSheet.test.js +29 -44
- package/dist/cjs/splitSelectors.js +8 -10
- package/dist/cjs/splitSelectors.test.js +4 -4
- package/dist/cjs/withPseudoState.js +46 -95
- package/dist/esm/PseudoStateTool.js +35 -59
- 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 +29 -53
- package/dist/esm/rewriteStyleSheet.test.js +29 -44
- package/dist/esm/splitSelectors.js +8 -10
- package/dist/esm/splitSelectors.test.js +4 -4
- package/dist/esm/withPseudoState.js +45 -95
- package/package.json +3 -3
|
@@ -13,111 +13,72 @@ var _constants = require("./constants");
|
|
|
13
13
|
|
|
14
14
|
var _rewriteStyleSheet = require("./rewriteStyleSheet");
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
/* eslint-env browser */
|
|
17
|
+
const channel = _addons.addons.getChannel();
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
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; }
|
|
21
|
-
|
|
22
|
-
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
|
23
|
-
|
|
24
|
-
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."); }
|
|
25
|
-
|
|
26
|
-
function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
|
|
27
|
-
|
|
28
|
-
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
29
|
-
|
|
30
|
-
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
|
|
31
|
-
|
|
32
|
-
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
33
|
-
|
|
34
|
-
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
35
|
-
|
|
36
|
-
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
|
|
37
|
-
|
|
38
|
-
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
|
|
39
|
-
|
|
40
|
-
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
|
|
41
|
-
|
|
42
|
-
var channel = _addons.addons.getChannel();
|
|
43
|
-
|
|
44
|
-
var shadowHosts = new Set(); // Drops any existing pseudo state classnames that carried over from a previously viewed story
|
|
19
|
+
const shadowHosts = new Set(); // Drops any existing pseudo state classnames that carried over from a previously viewed story
|
|
45
20
|
// before adding the new classnames. We do this the old-fashioned way, for IE compatibility.
|
|
46
21
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
element.className = (_element$className$sp = element.className.split(" ").filter(function (classname) {
|
|
51
|
-
return classname && classname.indexOf("pseudo-") !== 0;
|
|
52
|
-
})).concat.apply(_element$className$sp, _toConsumableArray(classnames)).join(" ");
|
|
22
|
+
const applyClasses = (element, classnames) => {
|
|
23
|
+
element.className = element.className.split(" ").filter(classname => classname && classname.indexOf("pseudo-") !== 0).concat(...classnames).join(" ");
|
|
53
24
|
};
|
|
54
25
|
|
|
55
|
-
|
|
56
|
-
|
|
26
|
+
const applyParameter = (rootElement, parameter) => {
|
|
27
|
+
const map = new Map([[rootElement, new Set()]]);
|
|
57
28
|
|
|
58
|
-
|
|
59
|
-
return map.set(target, new Set([].concat(_toConsumableArray(map.get(target) || []), [state])));
|
|
60
|
-
};
|
|
29
|
+
const add = (target, state) => map.set(target, new Set([...(map.get(target) || []), state]));
|
|
61
30
|
|
|
62
|
-
Object.entries(parameter || {}).forEach(
|
|
63
|
-
|
|
64
|
-
state = _ref2[0],
|
|
65
|
-
value = _ref2[1];
|
|
31
|
+
Object.entries(parameter || {}).forEach(_ref => {
|
|
32
|
+
let [state, value] = _ref;
|
|
66
33
|
|
|
67
34
|
if (typeof value === "boolean") {
|
|
68
35
|
// default API - applying pseudo class to root element.
|
|
69
36
|
add(rootElement, value && state);
|
|
70
37
|
} else if (typeof value === "string") {
|
|
71
38
|
// explicit selectors API - applying pseudo class to a specific element
|
|
72
|
-
rootElement.querySelectorAll(value).forEach(
|
|
73
|
-
return add(el, state);
|
|
74
|
-
});
|
|
39
|
+
rootElement.querySelectorAll(value).forEach(el => add(el, state));
|
|
75
40
|
} else if (Array.isArray(value)) {
|
|
76
41
|
// explicit selectors API - we have an array (of strings) recursively handle each one
|
|
77
|
-
value.forEach(
|
|
78
|
-
return rootElement.querySelectorAll(sel).forEach(function (el) {
|
|
79
|
-
return add(el, state);
|
|
80
|
-
});
|
|
81
|
-
});
|
|
42
|
+
value.forEach(sel => rootElement.querySelectorAll(sel).forEach(el => add(el, state)));
|
|
82
43
|
}
|
|
83
44
|
});
|
|
84
|
-
map.forEach(
|
|
85
|
-
|
|
86
|
-
states.forEach(
|
|
87
|
-
return _constants.PSEUDO_STATES[key] && classnames.push("pseudo-".concat(_constants.PSEUDO_STATES[key]));
|
|
88
|
-
});
|
|
45
|
+
map.forEach((states, target) => {
|
|
46
|
+
const classnames = [];
|
|
47
|
+
states.forEach(key => _constants.PSEUDO_STATES[key] && classnames.push("pseudo-".concat(_constants.PSEUDO_STATES[key])));
|
|
89
48
|
applyClasses(target, classnames);
|
|
90
49
|
});
|
|
91
50
|
}; // Traverses ancestry to collect relevant pseudo classnames, and applies them to the shadow host.
|
|
92
51
|
// Shadow DOM can only access classes on its host. Traversing is needed to mimic the CSS cascade.
|
|
93
52
|
|
|
94
53
|
|
|
95
|
-
|
|
96
|
-
|
|
54
|
+
const updateShadowHost = shadowHost => {
|
|
55
|
+
const classnames = new Set();
|
|
97
56
|
|
|
98
|
-
for (
|
|
57
|
+
for (let element = shadowHost.parentElement; element; element = element.parentElement) {
|
|
99
58
|
if (!element.className) continue;
|
|
100
|
-
element.className.split(" ").filter(
|
|
101
|
-
return classname.indexOf("pseudo-") === 0;
|
|
102
|
-
}).forEach(function (classname) {
|
|
103
|
-
return classnames.add(classname);
|
|
104
|
-
});
|
|
59
|
+
element.className.split(" ").filter(classname => classname.indexOf("pseudo-") === 0).forEach(classname => classnames.add(classname));
|
|
105
60
|
}
|
|
106
61
|
|
|
107
62
|
applyClasses(shadowHost, classnames);
|
|
108
63
|
}; // Global decorator that rewrites stylesheets and applies classnames to render pseudo styles
|
|
109
64
|
|
|
110
65
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
66
|
+
const withPseudoState = (StoryFn, _ref2) => {
|
|
67
|
+
let {
|
|
68
|
+
viewMode,
|
|
69
|
+
parameters,
|
|
70
|
+
id,
|
|
71
|
+
globals: globalsArgs
|
|
72
|
+
} = _ref2;
|
|
73
|
+
const {
|
|
74
|
+
pseudo: parameter
|
|
75
|
+
} = parameters;
|
|
76
|
+
const {
|
|
77
|
+
pseudo: globals
|
|
78
|
+
} = globalsArgs; // Sync parameter to globals, used by the toolbar (only in canvas as this
|
|
118
79
|
// doesn't make sense for docs because many stories are displayed at once)
|
|
119
80
|
|
|
120
|
-
(0, _addons.useEffect)(
|
|
81
|
+
(0, _addons.useEffect)(() => {
|
|
121
82
|
if (parameter !== globals && viewMode === "story") {
|
|
122
83
|
channel.emit(_coreEvents.UPDATE_GLOBALS, {
|
|
123
84
|
globals: {
|
|
@@ -128,15 +89,13 @@ var withPseudoState = function withPseudoState(StoryFn, _ref3) {
|
|
|
128
89
|
}, [parameter, viewMode]); // Convert selected states to classnames and apply them to the story root element.
|
|
129
90
|
// Then update each shadow host to redetermine its own pseudo classnames.
|
|
130
91
|
|
|
131
|
-
(0, _addons.useEffect)(
|
|
132
|
-
|
|
133
|
-
|
|
92
|
+
(0, _addons.useEffect)(() => {
|
|
93
|
+
const timeout = setTimeout(() => {
|
|
94
|
+
const element = document.getElementById(viewMode === "docs" ? "story--".concat(id) : "root");
|
|
134
95
|
applyParameter(element, globals || parameter);
|
|
135
96
|
shadowHosts.forEach(updateShadowHost);
|
|
136
97
|
}, 0);
|
|
137
|
-
return
|
|
138
|
-
return clearTimeout(timeout);
|
|
139
|
-
};
|
|
98
|
+
return () => clearTimeout(timeout);
|
|
140
99
|
}, [globals, parameter, viewMode]);
|
|
141
100
|
return StoryFn();
|
|
142
101
|
}; // Rewrite CSS rules for pseudo-states on all stylesheets to add an alternative selector
|
|
@@ -144,28 +103,20 @@ var withPseudoState = function withPseudoState(StoryFn, _ref3) {
|
|
|
144
103
|
|
|
145
104
|
exports.withPseudoState = withPseudoState;
|
|
146
105
|
|
|
147
|
-
|
|
106
|
+
const rewriteStyleSheets = shadowRoot => {
|
|
148
107
|
var _shadowRoot$adoptedSt;
|
|
149
108
|
|
|
150
|
-
|
|
109
|
+
let styleSheets = shadowRoot ? shadowRoot.styleSheets : document.styleSheets;
|
|
151
110
|
if (shadowRoot !== null && shadowRoot !== void 0 && (_shadowRoot$adoptedSt = shadowRoot.adoptedStyleSheets) !== null && _shadowRoot$adoptedSt !== void 0 && _shadowRoot$adoptedSt.length) styleSheets = shadowRoot.adoptedStyleSheets;
|
|
152
|
-
Array.from(styleSheets).forEach(
|
|
153
|
-
return (0, _rewriteStyleSheet.rewriteStyleSheet)(sheet, shadowRoot, shadowHosts);
|
|
154
|
-
});
|
|
111
|
+
Array.from(styleSheets).forEach(sheet => (0, _rewriteStyleSheet.rewriteStyleSheet)(sheet, shadowRoot, shadowHosts));
|
|
155
112
|
}; // Only track shadow hosts for the current story
|
|
156
113
|
|
|
157
114
|
|
|
158
|
-
channel.on(_coreEvents.STORY_CHANGED,
|
|
159
|
-
return shadowHosts.clear();
|
|
160
|
-
}); // Reinitialize CSS enhancements every time the story changes
|
|
115
|
+
channel.on(_coreEvents.STORY_CHANGED, () => shadowHosts.clear()); // Reinitialize CSS enhancements every time the story changes
|
|
161
116
|
|
|
162
|
-
channel.on(_coreEvents.STORY_RENDERED,
|
|
163
|
-
return rewriteStyleSheets();
|
|
164
|
-
}); // Reinitialize CSS enhancements every time a docs page is rendered
|
|
117
|
+
channel.on(_coreEvents.STORY_RENDERED, () => rewriteStyleSheets()); // Reinitialize CSS enhancements every time a docs page is rendered
|
|
165
118
|
|
|
166
|
-
channel.on(_coreEvents.DOCS_RENDERED,
|
|
167
|
-
return rewriteStyleSheets();
|
|
168
|
-
}); // IE doesn't support shadow DOM
|
|
119
|
+
channel.on(_coreEvents.DOCS_RENDERED, () => rewriteStyleSheets()); // IE doesn't support shadow DOM
|
|
169
120
|
|
|
170
121
|
if (Element.prototype.attachShadow) {
|
|
171
122
|
// Monkeypatch the attachShadow method so we can handle pseudo styles inside shadow DOM
|
|
@@ -173,12 +124,12 @@ if (Element.prototype.attachShadow) {
|
|
|
173
124
|
|
|
174
125
|
Element.prototype.attachShadow = function attachShadow(init) {
|
|
175
126
|
// Force "open" mode, so we can access the shadowRoot
|
|
176
|
-
|
|
127
|
+
const shadowRoot = this._attachShadow({ ...init,
|
|
177
128
|
mode: "open"
|
|
178
|
-
})
|
|
129
|
+
}); // Wait for it to render and apply its styles before rewriting them
|
|
179
130
|
|
|
180
131
|
|
|
181
|
-
requestAnimationFrame(
|
|
132
|
+
requestAnimationFrame(() => {
|
|
182
133
|
rewriteStyleSheets(shadowRoot);
|
|
183
134
|
updateShadowHost(shadowRoot.host);
|
|
184
135
|
});
|
|
@@ -1,34 +1,20 @@
|
|
|
1
|
-
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; }
|
|
2
|
-
|
|
3
|
-
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; }
|
|
4
|
-
|
|
5
|
-
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; }
|
|
6
|
-
|
|
7
|
-
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
|
8
|
-
|
|
9
|
-
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."); }
|
|
10
|
-
|
|
11
|
-
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
12
|
-
|
|
13
|
-
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
|
|
14
|
-
|
|
15
|
-
function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
|
|
16
|
-
|
|
17
|
-
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
18
|
-
|
|
19
1
|
import React, { useCallback, useMemo } from "react";
|
|
20
2
|
import { useGlobals } from "@storybook/api";
|
|
21
3
|
import { Icons, IconButton, WithTooltip, TooltipLinkList } from "@storybook/components";
|
|
22
4
|
import { styled, color } from "@storybook/theming";
|
|
23
5
|
import { PSEUDO_STATES } from "./constants";
|
|
24
|
-
|
|
25
|
-
|
|
6
|
+
const LinkTitle = styled.span(_ref => {
|
|
7
|
+
let {
|
|
8
|
+
active
|
|
9
|
+
} = _ref;
|
|
26
10
|
return {
|
|
27
11
|
color: active ? color.secondary : "inherit"
|
|
28
12
|
};
|
|
29
13
|
});
|
|
30
|
-
|
|
31
|
-
|
|
14
|
+
const LinkIcon = styled(Icons)(_ref2 => {
|
|
15
|
+
let {
|
|
16
|
+
active
|
|
17
|
+
} = _ref2;
|
|
32
18
|
return {
|
|
33
19
|
opacity: active ? 1 : 0,
|
|
34
20
|
path: {
|
|
@@ -36,46 +22,36 @@ var LinkIcon = styled(Icons)(function (_ref2) {
|
|
|
36
22
|
}
|
|
37
23
|
};
|
|
38
24
|
});
|
|
39
|
-
|
|
40
|
-
export
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
return function () {
|
|
51
|
-
return updateGlobals({
|
|
52
|
-
pseudo: _objectSpread(_objectSpread({}, pseudo), {}, _defineProperty({}, option, !isActive(option)))
|
|
53
|
-
});
|
|
54
|
-
};
|
|
55
|
-
}, [pseudo]);
|
|
25
|
+
const options = Object.keys(PSEUDO_STATES).sort();
|
|
26
|
+
export const PseudoStateTool = () => {
|
|
27
|
+
const [{
|
|
28
|
+
pseudo
|
|
29
|
+
}, updateGlobals] = useGlobals();
|
|
30
|
+
const isActive = useCallback(option => (pseudo === null || pseudo === void 0 ? void 0 : pseudo[option]) === true, [pseudo]);
|
|
31
|
+
const toggleOption = useCallback(option => () => updateGlobals({
|
|
32
|
+
pseudo: { ...pseudo,
|
|
33
|
+
[option]: !isActive(option)
|
|
34
|
+
}
|
|
35
|
+
}), [pseudo]);
|
|
56
36
|
return /*#__PURE__*/React.createElement(WithTooltip, {
|
|
57
37
|
placement: "top",
|
|
58
38
|
trigger: "click",
|
|
59
|
-
tooltip:
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
};
|
|
76
|
-
})
|
|
77
|
-
});
|
|
78
|
-
}
|
|
39
|
+
tooltip: () => /*#__PURE__*/React.createElement(TooltipLinkList, {
|
|
40
|
+
links: options.map(option => ({
|
|
41
|
+
id: option,
|
|
42
|
+
title: /*#__PURE__*/React.createElement(LinkTitle, {
|
|
43
|
+
active: isActive(option)
|
|
44
|
+
}, ":", PSEUDO_STATES[option]),
|
|
45
|
+
right: /*#__PURE__*/React.createElement(LinkIcon, {
|
|
46
|
+
icon: "check",
|
|
47
|
+
width: 12,
|
|
48
|
+
height: 12,
|
|
49
|
+
active: isActive(option)
|
|
50
|
+
}),
|
|
51
|
+
onClick: toggleOption(option),
|
|
52
|
+
active: isActive(option)
|
|
53
|
+
}))
|
|
54
|
+
})
|
|
79
55
|
}, /*#__PURE__*/React.createElement(IconButton, {
|
|
80
56
|
key: "pseudo-state",
|
|
81
57
|
title: "Select CSS pseudo states",
|
package/dist/esm/constants.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export
|
|
2
|
-
export
|
|
1
|
+
export const ADDON_ID = "storybook/pseudo-states";
|
|
2
|
+
export const TOOL_ID = "".concat(ADDON_ID, "/tool"); // Dynamic pseudo-classes
|
|
3
3
|
// @see https://www.w3.org/TR/2018/REC-selectors-3-20181106/#dynamic-pseudos
|
|
4
4
|
|
|
5
|
-
export
|
|
5
|
+
export const PSEUDO_STATES = {
|
|
6
6
|
hover: "hover",
|
|
7
7
|
active: "active",
|
|
8
8
|
focusVisible: "focus-visible",
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { addons, types } from "@storybook/addons";
|
|
2
2
|
import { ADDON_ID, TOOL_ID } from "../constants";
|
|
3
3
|
import { PseudoStateTool } from "../PseudoStateTool";
|
|
4
|
-
addons.register(ADDON_ID,
|
|
4
|
+
addons.register(ADDON_ID, () => {
|
|
5
5
|
addons.add(TOOL_ID, {
|
|
6
6
|
type: types.TOOL,
|
|
7
7
|
title: "CSS pseudo states",
|
|
8
|
-
match:
|
|
9
|
-
|
|
8
|
+
match: _ref => {
|
|
9
|
+
let {
|
|
10
|
+
viewMode
|
|
11
|
+
} = _ref;
|
|
10
12
|
return viewMode === "story";
|
|
11
13
|
},
|
|
12
14
|
render: PseudoStateTool
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { withPseudoState } from "../withPseudoState";
|
|
2
|
-
export
|
|
2
|
+
export const decorators = [withPseudoState];
|
|
@@ -1,25 +1,19 @@
|
|
|
1
|
-
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
|
|
2
|
-
|
|
3
|
-
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
4
|
-
|
|
5
|
-
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
|
|
6
|
-
|
|
7
1
|
import { PSEUDO_STATES } from "./constants";
|
|
8
2
|
import { splitSelectors } from "./splitSelectors";
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
3
|
+
const pseudoStates = Object.values(PSEUDO_STATES);
|
|
4
|
+
const matchOne = new RegExp(":(".concat(pseudoStates.join("|"), ")"));
|
|
5
|
+
const matchAll = new RegExp(":(".concat(pseudoStates.join("|"), ")"), "g");
|
|
6
|
+
const warnings = new Set();
|
|
13
7
|
|
|
14
|
-
|
|
8
|
+
const warnOnce = message => {
|
|
15
9
|
if (warnings.has(message)) return; // eslint-disable-next-line no-console
|
|
16
10
|
|
|
17
11
|
console.warn(message);
|
|
18
12
|
warnings.add(message);
|
|
19
13
|
};
|
|
20
14
|
|
|
21
|
-
|
|
22
|
-
return cssText.replace(selectorText, splitSelectors(selectorText).flatMap(
|
|
15
|
+
const rewriteRule = (cssText, selectorText, shadowRoot) => {
|
|
16
|
+
return cssText.replace(selectorText, splitSelectors(selectorText).flatMap(selector => {
|
|
23
17
|
if (selector.includes(".pseudo-")) {
|
|
24
18
|
return [];
|
|
25
19
|
}
|
|
@@ -28,66 +22,48 @@ var rewriteRule = function rewriteRule(cssText, selectorText, shadowRoot) {
|
|
|
28
22
|
return [selector];
|
|
29
23
|
}
|
|
30
24
|
|
|
31
|
-
|
|
32
|
-
|
|
25
|
+
const states = [];
|
|
26
|
+
const plainSelector = selector.replace(matchAll, (_, state) => {
|
|
33
27
|
states.push(state);
|
|
34
28
|
return "";
|
|
35
29
|
});
|
|
36
|
-
|
|
37
|
-
return acc.replace(new RegExp(":".concat(state), "g"), ".pseudo-".concat(state));
|
|
38
|
-
}, selector);
|
|
30
|
+
const classSelector = states.reduce((acc, state) => acc.replace(new RegExp(":".concat(state), "g"), ".pseudo-".concat(state)), selector);
|
|
39
31
|
|
|
40
32
|
if (selector.startsWith(":host(") || selector.startsWith("::slotted(")) {
|
|
41
33
|
return [selector, classSelector];
|
|
42
34
|
}
|
|
43
35
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}).join(""), ") ").concat(plainSelector) : "".concat(states.map(function (s) {
|
|
47
|
-
return ".pseudo-".concat(s);
|
|
48
|
-
}).join(""), " ").concat(plainSelector);
|
|
49
|
-
return [selector, classSelector, ancestorSelector].filter(function (selector) {
|
|
50
|
-
return !selector.includes(":not()");
|
|
51
|
-
});
|
|
36
|
+
const ancestorSelector = shadowRoot ? ":host(".concat(states.map(s => ".pseudo-".concat(s)).join(""), ") ").concat(plainSelector) : "".concat(states.map(s => ".pseudo-".concat(s)).join(""), " ").concat(plainSelector);
|
|
37
|
+
return [selector, classSelector, ancestorSelector].filter(selector => !selector.includes(":not()"));
|
|
52
38
|
}).join(", "));
|
|
53
39
|
}; // Rewrites the style sheet to add alternative selectors for any rule that targets a pseudo state.
|
|
54
40
|
// A sheet can only be rewritten once, and may carry over between stories.
|
|
55
41
|
|
|
56
42
|
|
|
57
|
-
export
|
|
43
|
+
export const rewriteStyleSheet = (sheet, shadowRoot, shadowHosts) => {
|
|
58
44
|
if (sheet.__pseudoStatesRewritten) return;
|
|
59
45
|
sheet.__pseudoStatesRewritten = true;
|
|
60
46
|
|
|
61
47
|
try {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
var newRule = rewriteRule(cssText, selectorText, shadowRoot);
|
|
75
|
-
sheet.deleteRule(index);
|
|
76
|
-
sheet.insertRule(newRule, index);
|
|
77
|
-
if (shadowRoot) shadowHosts.add(shadowRoot.host);
|
|
78
|
-
}
|
|
48
|
+
let index = 0;
|
|
49
|
+
|
|
50
|
+
for (const {
|
|
51
|
+
cssText,
|
|
52
|
+
selectorText
|
|
53
|
+
} of sheet.cssRules) {
|
|
54
|
+
if (matchOne.test(selectorText)) {
|
|
55
|
+
const newRule = rewriteRule(cssText, selectorText, shadowRoot);
|
|
56
|
+
sheet.deleteRule(index);
|
|
57
|
+
sheet.insertRule(newRule, index);
|
|
58
|
+
if (shadowRoot) shadowHosts.add(shadowRoot.host);
|
|
59
|
+
}
|
|
79
60
|
|
|
80
|
-
|
|
61
|
+
index++;
|
|
81
62
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
63
|
+
if (index > 1000) {
|
|
64
|
+
warnOnce("Reached maximum of 1000 pseudo selectors per sheet, skipping the rest.");
|
|
65
|
+
break;
|
|
86
66
|
}
|
|
87
|
-
} catch (err) {
|
|
88
|
-
_iterator.e(err);
|
|
89
|
-
} finally {
|
|
90
|
-
_iterator.f();
|
|
91
67
|
}
|
|
92
68
|
} catch (e) {
|
|
93
69
|
if (e.toString().includes("cssRules")) {
|
|
@@ -1,82 +1,67 @@
|
|
|
1
|
-
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
2
|
-
|
|
3
|
-
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
|
4
|
-
|
|
5
|
-
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
|
|
6
|
-
|
|
7
1
|
import { rewriteStyleSheet } from "./rewriteStyleSheet";
|
|
8
2
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
_classCallCheck(this, Sheet);
|
|
12
|
-
|
|
3
|
+
class Sheet {
|
|
4
|
+
constructor() {
|
|
13
5
|
this.__pseudoStatesRewritten = false;
|
|
14
6
|
|
|
15
7
|
for (var _len = arguments.length, rules = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
16
8
|
rules[_key] = arguments[_key];
|
|
17
9
|
}
|
|
18
10
|
|
|
19
|
-
this.cssRules = rules.map(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
};
|
|
24
|
-
});
|
|
11
|
+
this.cssRules = rules.map(cssText => ({
|
|
12
|
+
cssText,
|
|
13
|
+
selectorText: cssText.slice(0, cssText.indexOf(" {"))
|
|
14
|
+
}));
|
|
25
15
|
}
|
|
26
16
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
value: function insertRule(cssText, index) {
|
|
35
|
-
this.cssRules.splice(index, 0, cssText);
|
|
36
|
-
}
|
|
37
|
-
}]);
|
|
17
|
+
deleteRule(index) {
|
|
18
|
+
this.cssRules.splice(index, 1);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
insertRule(cssText, index) {
|
|
22
|
+
this.cssRules.splice(index, 0, cssText);
|
|
23
|
+
}
|
|
38
24
|
|
|
39
|
-
|
|
40
|
-
}();
|
|
25
|
+
}
|
|
41
26
|
|
|
42
|
-
describe("rewriteStyleSheet",
|
|
43
|
-
it("adds alternative selector targeting the element directly",
|
|
44
|
-
|
|
27
|
+
describe("rewriteStyleSheet", () => {
|
|
28
|
+
it("adds alternative selector targeting the element directly", () => {
|
|
29
|
+
const sheet = new Sheet("a:hover { color: red }");
|
|
45
30
|
rewriteStyleSheet(sheet);
|
|
46
31
|
expect(sheet.cssRules[0]).toContain("a.pseudo-hover");
|
|
47
32
|
});
|
|
48
|
-
it("adds alternative selector targeting an ancestor",
|
|
49
|
-
|
|
33
|
+
it("adds alternative selector targeting an ancestor", () => {
|
|
34
|
+
const sheet = new Sheet("a:hover { color: red }");
|
|
50
35
|
rewriteStyleSheet(sheet);
|
|
51
36
|
expect(sheet.cssRules[0]).toContain(".pseudo-hover a");
|
|
52
37
|
});
|
|
53
|
-
it("adds alternative selector for each pseudo selector",
|
|
54
|
-
|
|
38
|
+
it("adds alternative selector for each pseudo selector", () => {
|
|
39
|
+
const sheet = new Sheet("a:hover, a:focus { color: red }");
|
|
55
40
|
rewriteStyleSheet(sheet);
|
|
56
41
|
expect(sheet.cssRules[0]).toContain("a.pseudo-hover");
|
|
57
42
|
expect(sheet.cssRules[0]).toContain("a.pseudo-focus");
|
|
58
43
|
expect(sheet.cssRules[0]).toContain(".pseudo-hover a");
|
|
59
44
|
expect(sheet.cssRules[0]).toContain(".pseudo-focus a");
|
|
60
45
|
});
|
|
61
|
-
it("keeps non-pseudo selectors as-is",
|
|
62
|
-
|
|
46
|
+
it("keeps non-pseudo selectors as-is", () => {
|
|
47
|
+
const sheet = new Sheet("a.class, a:hover, a:focus, a#id { color: red }");
|
|
63
48
|
rewriteStyleSheet(sheet);
|
|
64
49
|
expect(sheet.cssRules[0]).toContain("a.class");
|
|
65
50
|
expect(sheet.cssRules[0]).toContain("a#id");
|
|
66
51
|
});
|
|
67
|
-
it("supports combined pseudo selectors",
|
|
68
|
-
|
|
52
|
+
it("supports combined pseudo selectors", () => {
|
|
53
|
+
const sheet = new Sheet("a:hover:focus { color: red }");
|
|
69
54
|
rewriteStyleSheet(sheet);
|
|
70
55
|
expect(sheet.cssRules[0]).toContain("a.pseudo-hover.pseudo-focus");
|
|
71
56
|
expect(sheet.cssRules[0]).toContain(".pseudo-hover.pseudo-focus a");
|
|
72
57
|
});
|
|
73
|
-
it('supports ":host"',
|
|
74
|
-
|
|
58
|
+
it('supports ":host"', () => {
|
|
59
|
+
const sheet = new Sheet(":host(:hover) { color: red }");
|
|
75
60
|
rewriteStyleSheet(sheet);
|
|
76
61
|
expect(sheet.cssRules[0]).toEqual(":host(:hover), :host(.pseudo-hover) { color: red }");
|
|
77
62
|
});
|
|
78
|
-
it('supports ":not"',
|
|
79
|
-
|
|
63
|
+
it('supports ":not"', () => {
|
|
64
|
+
const sheet = new Sheet(":not(:hover) { color: red }");
|
|
80
65
|
rewriteStyleSheet(sheet);
|
|
81
66
|
expect(sheet.cssRules[0]).toEqual(":not(:hover), :not(.pseudo-hover) { color: red }");
|
|
82
67
|
});
|
|
@@ -1,16 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
return selector.indexOf("@") === 0;
|
|
3
|
-
};
|
|
1
|
+
const isAtRule = selector => selector.indexOf("@") === 0;
|
|
4
2
|
|
|
5
|
-
export
|
|
3
|
+
export const splitSelectors = selectors => {
|
|
6
4
|
if (isAtRule(selectors)) return [selectors];
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
let result = [];
|
|
6
|
+
let parentheses = 0;
|
|
7
|
+
let brackets = 0;
|
|
8
|
+
let selector = "";
|
|
11
9
|
|
|
12
|
-
for (
|
|
13
|
-
|
|
10
|
+
for (let i = 0, len = selectors.length; i < len; i++) {
|
|
11
|
+
const char = selectors[i];
|
|
14
12
|
|
|
15
13
|
if (char === "(") {
|
|
16
14
|
parentheses += 1;
|