storybook-addon-pseudo-states 1.15.0 → 1.15.2--canary.45.07abc1b.0
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 -74
- package/dist/cjs/constants.js +11 -5
- package/dist/cjs/preset/manager.js +5 -6
- package/dist/cjs/preset/preview.js +1 -3
- package/dist/cjs/rewriteStyleSheet.js +41 -71
- package/dist/cjs/rewriteStyleSheet.test.js +34 -50
- package/dist/cjs/splitSelectors.js +8 -17
- package/dist/cjs/splitSelectors.test.js +4 -5
- package/dist/cjs/withPseudoState.js +67 -125
- package/dist/esm/PseudoStateTool.js +36 -59
- package/dist/esm/constants.js +9 -4
- package/dist/esm/preset/manager.js +5 -3
- package/dist/esm/preset/preview.js +1 -1
- package/dist/esm/rewriteStyleSheet.js +42 -68
- package/dist/esm/rewriteStyleSheet.test.js +34 -50
- package/dist/esm/splitSelectors.js +8 -15
- package/dist/esm/splitSelectors.test.js +4 -4
- package/dist/esm/withPseudoState.js +67 -119
- package/package.json +3 -3
|
@@ -4,120 +4,72 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.withPseudoState = void 0;
|
|
7
|
-
|
|
8
7
|
var _addons = require("@storybook/addons");
|
|
9
|
-
|
|
10
8
|
var _coreEvents = require("@storybook/core-events");
|
|
11
|
-
|
|
12
9
|
var _constants = require("./constants");
|
|
13
|
-
|
|
14
10
|
var _rewriteStyleSheet = require("./rewriteStyleSheet");
|
|
11
|
+
/* eslint-env browser */
|
|
15
12
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
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; }
|
|
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); }
|
|
13
|
+
const channel = _addons.addons.getChannel();
|
|
14
|
+
const shadowHosts = new Set();
|
|
35
15
|
|
|
36
|
-
|
|
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
|
|
16
|
+
// Drops any existing pseudo state classnames that carried over from a previously viewed story
|
|
45
17
|
// before adding the new classnames. We do this the old-fashioned way, for IE compatibility.
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
var _element$className$sp;
|
|
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(" ");
|
|
18
|
+
const applyClasses = (element, classnames) => {
|
|
19
|
+
element.className = element.className.split(" ").filter(classname => classname && classname.indexOf("pseudo-") !== 0).concat(...classnames).join(" ");
|
|
53
20
|
};
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
return map.set(target, new Set([].concat(_toConsumableArray(map.get(target) || []), [state])));
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
Object.entries(parameter || {}).forEach(function (_ref) {
|
|
63
|
-
var _ref2 = _slicedToArray(_ref, 2),
|
|
64
|
-
state = _ref2[0],
|
|
65
|
-
value = _ref2[1];
|
|
66
|
-
|
|
21
|
+
const applyParameter = (rootElement, parameter) => {
|
|
22
|
+
const map = new Map([[rootElement, new Set()]]);
|
|
23
|
+
const add = (target, state) => map.set(target, new Set([...(map.get(target) || []), state]));
|
|
24
|
+
Object.entries(parameter || {}).forEach(_ref => {
|
|
25
|
+
let [state, value] = _ref;
|
|
67
26
|
if (typeof value === "boolean") {
|
|
68
27
|
// default API - applying pseudo class to root element.
|
|
69
28
|
add(rootElement, value && state);
|
|
70
29
|
} else if (typeof value === "string") {
|
|
71
30
|
// explicit selectors API - applying pseudo class to a specific element
|
|
72
|
-
rootElement.querySelectorAll(value).forEach(
|
|
73
|
-
return add(el, state);
|
|
74
|
-
});
|
|
31
|
+
rootElement.querySelectorAll(value).forEach(el => add(el, state));
|
|
75
32
|
} else if (Array.isArray(value)) {
|
|
76
33
|
// 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
|
-
});
|
|
34
|
+
value.forEach(sel => rootElement.querySelectorAll(sel).forEach(el => add(el, state)));
|
|
82
35
|
}
|
|
83
36
|
});
|
|
84
|
-
map.forEach(
|
|
85
|
-
|
|
86
|
-
states.forEach(
|
|
87
|
-
return _constants.PSEUDO_STATES[key] && classnames.push("pseudo-".concat(_constants.PSEUDO_STATES[key]));
|
|
88
|
-
});
|
|
37
|
+
map.forEach((states, target) => {
|
|
38
|
+
const classnames = [];
|
|
39
|
+
states.forEach(key => _constants.PSEUDO_STATES[key] && classnames.push(`pseudo-${_constants.PSEUDO_STATES[key]}`));
|
|
89
40
|
applyClasses(target, classnames);
|
|
90
41
|
});
|
|
91
|
-
};
|
|
92
|
-
// Shadow DOM can only access classes on its host. Traversing is needed to mimic the CSS cascade.
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
var updateShadowHost = function updateShadowHost(shadowHost) {
|
|
96
|
-
var classnames = new Set();
|
|
42
|
+
};
|
|
97
43
|
|
|
98
|
-
|
|
44
|
+
// Traverses ancestry to collect relevant pseudo classnames, and applies them to the shadow host.
|
|
45
|
+
// Shadow DOM can only access classes on its host. Traversing is needed to mimic the CSS cascade.
|
|
46
|
+
const updateShadowHost = shadowHost => {
|
|
47
|
+
const classnames = new Set();
|
|
48
|
+
for (let element = shadowHost.parentElement; element; element = element.parentElement) {
|
|
99
49
|
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
|
-
});
|
|
50
|
+
element.className.split(" ").filter(classname => classname.indexOf("pseudo-") === 0).forEach(classname => classnames.add(classname));
|
|
105
51
|
}
|
|
106
|
-
|
|
107
52
|
applyClasses(shadowHost, classnames);
|
|
108
|
-
};
|
|
109
|
-
|
|
53
|
+
};
|
|
110
54
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
55
|
+
// Global decorator that rewrites stylesheets and applies classnames to render pseudo styles
|
|
56
|
+
const withPseudoState = (StoryFn, _ref2) => {
|
|
57
|
+
let {
|
|
58
|
+
viewMode,
|
|
59
|
+
parameters,
|
|
60
|
+
id,
|
|
61
|
+
globals: globalsArgs
|
|
62
|
+
} = _ref2;
|
|
63
|
+
const {
|
|
64
|
+
pseudo: parameter
|
|
65
|
+
} = parameters;
|
|
66
|
+
const {
|
|
67
|
+
pseudo: globals
|
|
68
|
+
} = globalsArgs;
|
|
69
|
+
|
|
70
|
+
// Sync parameter to globals, used by the toolbar (only in canvas as this
|
|
118
71
|
// doesn't make sense for docs because many stories are displayed at once)
|
|
119
|
-
|
|
120
|
-
(0, _addons.useEffect)(function () {
|
|
72
|
+
(0, _addons.useEffect)(() => {
|
|
121
73
|
if (parameter !== globals && viewMode === "story") {
|
|
122
74
|
channel.emit(_coreEvents.UPDATE_GLOBALS, {
|
|
123
75
|
globals: {
|
|
@@ -125,60 +77,50 @@ var withPseudoState = function withPseudoState(StoryFn, _ref3) {
|
|
|
125
77
|
}
|
|
126
78
|
});
|
|
127
79
|
}
|
|
128
|
-
}, [parameter, viewMode]);
|
|
129
|
-
// Then update each shadow host to redetermine its own pseudo classnames.
|
|
80
|
+
}, [parameter, viewMode]);
|
|
130
81
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
82
|
+
// Convert selected states to classnames and apply them to the story root element.
|
|
83
|
+
// Then update each shadow host to redetermine its own pseudo classnames.
|
|
84
|
+
(0, _addons.useEffect)(() => {
|
|
85
|
+
const timeout = setTimeout(() => {
|
|
86
|
+
const element = document.getElementById(viewMode === "docs" ? `story--${id}` : `root`);
|
|
134
87
|
applyParameter(element, globals || parameter);
|
|
135
88
|
shadowHosts.forEach(updateShadowHost);
|
|
136
89
|
}, 0);
|
|
137
|
-
return
|
|
138
|
-
return clearTimeout(timeout);
|
|
139
|
-
};
|
|
90
|
+
return () => clearTimeout(timeout);
|
|
140
91
|
}, [globals, parameter, viewMode]);
|
|
141
92
|
return StoryFn();
|
|
142
|
-
};
|
|
143
|
-
|
|
93
|
+
};
|
|
144
94
|
|
|
95
|
+
// Rewrite CSS rules for pseudo-states on all stylesheets to add an alternative selector
|
|
145
96
|
exports.withPseudoState = withPseudoState;
|
|
97
|
+
const rewriteStyleSheets = shadowRoot => {
|
|
98
|
+
let styleSheets = shadowRoot ? shadowRoot.styleSheets : document.styleSheets;
|
|
99
|
+
if (shadowRoot?.adoptedStyleSheets?.length) styleSheets = shadowRoot.adoptedStyleSheets;
|
|
100
|
+
Array.from(styleSheets).forEach(sheet => (0, _rewriteStyleSheet.rewriteStyleSheet)(sheet, shadowRoot, shadowHosts));
|
|
101
|
+
};
|
|
146
102
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
var styleSheets = shadowRoot ? shadowRoot.styleSheets : document.styleSheets;
|
|
151
|
-
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(function (sheet) {
|
|
153
|
-
return (0, _rewriteStyleSheet.rewriteStyleSheet)(sheet, shadowRoot, shadowHosts);
|
|
154
|
-
});
|
|
155
|
-
}; // Only track shadow hosts for the current story
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
channel.on(_coreEvents.STORY_CHANGED, function () {
|
|
159
|
-
return shadowHosts.clear();
|
|
160
|
-
}); // Reinitialize CSS enhancements every time the story changes
|
|
103
|
+
// Only track shadow hosts for the current story
|
|
104
|
+
channel.on(_coreEvents.STORY_CHANGED, () => shadowHosts.clear());
|
|
161
105
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
}); // Reinitialize CSS enhancements every time a docs page is rendered
|
|
106
|
+
// Reinitialize CSS enhancements every time the story changes
|
|
107
|
+
channel.on(_coreEvents.STORY_RENDERED, () => rewriteStyleSheets());
|
|
165
108
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}); // IE doesn't support shadow DOM
|
|
109
|
+
// Reinitialize CSS enhancements every time a docs page is rendered
|
|
110
|
+
channel.on(_coreEvents.DOCS_RENDERED, () => rewriteStyleSheets());
|
|
169
111
|
|
|
112
|
+
// IE doesn't support shadow DOM
|
|
170
113
|
if (Element.prototype.attachShadow) {
|
|
171
114
|
// Monkeypatch the attachShadow method so we can handle pseudo styles inside shadow DOM
|
|
172
115
|
Element.prototype._attachShadow = Element.prototype.attachShadow;
|
|
173
|
-
|
|
174
116
|
Element.prototype.attachShadow = function attachShadow(init) {
|
|
175
117
|
// Force "open" mode, so we can access the shadowRoot
|
|
176
|
-
|
|
118
|
+
const shadowRoot = this._attachShadow({
|
|
119
|
+
...init,
|
|
177
120
|
mode: "open"
|
|
178
|
-
})
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
requestAnimationFrame(function () {
|
|
121
|
+
});
|
|
122
|
+
// Wait for it to render and apply its styles before rewriting them
|
|
123
|
+
requestAnimationFrame(() => {
|
|
182
124
|
rewriteStyleSheets(shadowRoot);
|
|
183
125
|
updateShadowHost(shadowRoot.host);
|
|
184
126
|
});
|
|
@@ -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,37 @@ 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
|
-
|
|
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?.[option] === true, [pseudo]);
|
|
31
|
+
const toggleOption = useCallback(option => () => updateGlobals({
|
|
32
|
+
pseudo: {
|
|
33
|
+
...pseudo,
|
|
34
|
+
[option]: !isActive(option)
|
|
35
|
+
}
|
|
36
|
+
}), [pseudo]);
|
|
56
37
|
return /*#__PURE__*/React.createElement(WithTooltip, {
|
|
57
38
|
placement: "top",
|
|
58
39
|
trigger: "click",
|
|
59
|
-
tooltip:
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
};
|
|
76
|
-
})
|
|
77
|
-
});
|
|
78
|
-
}
|
|
40
|
+
tooltip: () => /*#__PURE__*/React.createElement(TooltipLinkList, {
|
|
41
|
+
links: options.map(option => ({
|
|
42
|
+
id: option,
|
|
43
|
+
title: /*#__PURE__*/React.createElement(LinkTitle, {
|
|
44
|
+
active: isActive(option)
|
|
45
|
+
}, ":", PSEUDO_STATES[option]),
|
|
46
|
+
right: /*#__PURE__*/React.createElement(LinkIcon, {
|
|
47
|
+
icon: "check",
|
|
48
|
+
width: 12,
|
|
49
|
+
height: 12,
|
|
50
|
+
active: isActive(option)
|
|
51
|
+
}),
|
|
52
|
+
onClick: toggleOption(option),
|
|
53
|
+
active: isActive(option)
|
|
54
|
+
}))
|
|
55
|
+
})
|
|
79
56
|
}, /*#__PURE__*/React.createElement(IconButton, {
|
|
80
57
|
key: "pseudo-state",
|
|
81
58
|
title: "Select CSS pseudo states",
|
package/dist/esm/constants.js
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
|
-
export
|
|
2
|
-
export
|
|
3
|
-
|
|
1
|
+
export const ADDON_ID = "storybook/pseudo-states";
|
|
2
|
+
export const TOOL_ID = `${ADDON_ID}/tool`;
|
|
3
|
+
|
|
4
|
+
// Pseudo-classes, which are not allowed to have classes applied on
|
|
5
|
+
// e.g. ::-webkit-scrollbar-thumb.pseudo-hover is not a valid selector
|
|
6
|
+
export const EXCLUDED_PSEUDO_ELEMENTS = ["::-webkit-scrollbar-thumb"];
|
|
4
7
|
|
|
5
|
-
|
|
8
|
+
// Dynamic pseudo-classes
|
|
9
|
+
// @see https://www.w3.org/TR/2018/REC-selectors-3-20181106/#dynamic-pseudos
|
|
10
|
+
export const PSEUDO_STATES = {
|
|
6
11
|
hover: "hover",
|
|
7
12
|
active: "active",
|
|
8
13
|
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,97 +1,71 @@
|
|
|
1
|
-
|
|
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
|
-
import { PSEUDO_STATES } from "./constants";
|
|
1
|
+
import { PSEUDO_STATES, EXCLUDED_PSEUDO_ELEMENTS } from "./constants";
|
|
8
2
|
import { splitSelectors } from "./splitSelectors";
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
3
|
+
const pseudoStates = Object.values(PSEUDO_STATES);
|
|
4
|
+
const matchOne = new RegExp(`:(${pseudoStates.join("|")})`);
|
|
5
|
+
const matchAll = new RegExp(`:(${pseudoStates.join("|")})`, "g");
|
|
6
|
+
const warnings = new Set();
|
|
7
|
+
const warnOnce = message => {
|
|
8
|
+
if (warnings.has(message)) return;
|
|
9
|
+
// eslint-disable-next-line no-console
|
|
17
10
|
console.warn(message);
|
|
18
11
|
warnings.add(message);
|
|
19
12
|
};
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
return cssText.replace(selectorText, splitSelectors(selectorText).flatMap(function (selector) {
|
|
13
|
+
const rewriteRule = (cssText, selectorText, shadowRoot) => {
|
|
14
|
+
return cssText.replace(selectorText, splitSelectors(selectorText).flatMap(selector => {
|
|
23
15
|
if (selector.includes(".pseudo-")) {
|
|
24
16
|
return [];
|
|
25
17
|
}
|
|
26
|
-
|
|
27
18
|
if (!matchOne.test(selector)) {
|
|
28
19
|
return [selector];
|
|
29
20
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
var plainSelector = selector.replace(matchAll, function (_, state) {
|
|
21
|
+
const states = [];
|
|
22
|
+
const plainSelector = selector.replace(matchAll, (_, state) => {
|
|
33
23
|
states.push(state);
|
|
34
24
|
return "";
|
|
35
25
|
});
|
|
36
|
-
|
|
37
|
-
return
|
|
26
|
+
const getDoesSelectorEndsWithExcludedPseudoElement = pseudo => EXCLUDED_PSEUDO_ELEMENTS.some(element => {
|
|
27
|
+
return selector.endsWith(`${element}:${pseudo}`);
|
|
28
|
+
});
|
|
29
|
+
const classSelector = states.reduce((acc, state) => {
|
|
30
|
+
if (getDoesSelectorEndsWithExcludedPseudoElement(state)) {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
return acc.replace(new RegExp(`(?<!Y):${state}`, "g"), `.pseudo-${state}`);
|
|
38
34
|
}, selector);
|
|
39
|
-
|
|
40
35
|
if (selector.startsWith(":host(") || selector.startsWith("::slotted(")) {
|
|
41
36
|
return [selector, classSelector];
|
|
42
37
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
return ".pseudo-".concat(s);
|
|
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
|
-
});
|
|
38
|
+
const ancestorSelector = shadowRoot ? `:host(${states.map(s => `.pseudo-${s}`).join("")}) ${plainSelector}` : `${states.map(s => `.pseudo-${s}`).join("")} ${plainSelector}`;
|
|
39
|
+
return [selector, classSelector, ancestorSelector].filter(selector => !selector?.includes(":not()")).filter(Boolean);
|
|
52
40
|
}).join(", "));
|
|
53
|
-
};
|
|
54
|
-
// A sheet can only be rewritten once, and may carry over between stories.
|
|
55
|
-
|
|
41
|
+
};
|
|
56
42
|
|
|
57
|
-
|
|
43
|
+
// Rewrites the style sheet to add alternative selectors for any rule that targets a pseudo state.
|
|
44
|
+
// A sheet can only be rewritten once, and may carry over between stories.
|
|
45
|
+
export const rewriteStyleSheet = (sheet, shadowRoot, shadowHosts) => {
|
|
58
46
|
if (sheet.__pseudoStatesRewritten) return;
|
|
59
47
|
sheet.__pseudoStatesRewritten = true;
|
|
60
|
-
|
|
61
48
|
try {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
if (shadowRoot) shadowHosts.add(shadowRoot.host);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
index++;
|
|
81
|
-
|
|
82
|
-
if (index > 1000) {
|
|
83
|
-
warnOnce("Reached maximum of 1000 pseudo selectors per sheet, skipping the rest.");
|
|
84
|
-
break;
|
|
85
|
-
}
|
|
49
|
+
let index = 0;
|
|
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
|
+
}
|
|
60
|
+
index++;
|
|
61
|
+
if (index > 1000) {
|
|
62
|
+
warnOnce("Reached maximum of 1000 pseudo selectors per sheet, skipping the rest.");
|
|
63
|
+
break;
|
|
86
64
|
}
|
|
87
|
-
} catch (err) {
|
|
88
|
-
_iterator.e(err);
|
|
89
|
-
} finally {
|
|
90
|
-
_iterator.f();
|
|
91
65
|
}
|
|
92
66
|
} catch (e) {
|
|
93
67
|
if (e.toString().includes("cssRules")) {
|
|
94
|
-
warnOnce(
|
|
68
|
+
warnOnce(`Can't access cssRules, likely due to CORS restrictions: ${sheet.href}`);
|
|
95
69
|
} else {
|
|
96
70
|
// eslint-disable-next-line no-console
|
|
97
71
|
console.error(e, sheet.href);
|