storybook-addon-pseudo-states 1.14.1 → 1.15.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 CHANGED
@@ -1,3 +1,17 @@
1
+ # v1.15.0 (Thu Jun 16 2022)
2
+
3
+ #### 🚀 Enhancement
4
+
5
+ - 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))
6
+
7
+ #### Authors: 3
8
+
9
+ - Gert Hengeveld ([@ghengeveld](https://github.com/ghengeveld))
10
+ - Sagiv ben giat ([@sag1v](https://github.com/sag1v))
11
+ - sagiv.bengiat (sagiv.bengiat@appsflyer.com)
12
+
13
+ ---
14
+
1
15
  # v1.14.1 (Wed Jun 15 2022)
2
16
 
3
17
  #### ⚠️ Pushed to `main`
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
- ```js
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.
@@ -63,19 +63,16 @@ var PseudoStateTool = function PseudoStateTool() {
63
63
  pseudo = _useGlobals2[0].pseudo,
64
64
  updateGlobals = _useGlobals2[1];
65
65
 
66
- var hasSelection = (0, _react.useMemo)(function () {
67
- return !!pseudo && Object.values(pseudo).includes(true);
68
- }, [pseudo]);
69
- var getValue = (0, _react.useCallback)(function (option) {
70
- return pseudo ? pseudo[option] : false;
66
+ var isActive = (0, _react.useCallback)(function (option) {
67
+ return (pseudo === null || pseudo === void 0 ? void 0 : pseudo[option]) === true;
71
68
  }, [pseudo]);
72
69
  var toggleOption = (0, _react.useCallback)(function (option) {
73
70
  return function () {
74
71
  return updateGlobals({
75
- pseudo: _objectSpread(_objectSpread({}, pseudo), {}, _defineProperty({}, option, !getValue(option)))
72
+ pseudo: _objectSpread(_objectSpread({}, pseudo), {}, _defineProperty({}, option, !isActive(option)))
76
73
  });
77
74
  };
78
- }, [pseudo, getValue]);
75
+ }, [pseudo]);
79
76
  return /*#__PURE__*/_react.default.createElement(_components.WithTooltip, {
80
77
  placement: "top",
81
78
  trigger: "click",
@@ -85,16 +82,16 @@ var PseudoStateTool = function PseudoStateTool() {
85
82
  return {
86
83
  id: option,
87
84
  title: /*#__PURE__*/_react.default.createElement(LinkTitle, {
88
- active: getValue(option)
85
+ active: isActive(option)
89
86
  }, ":", _constants.PSEUDO_STATES[option]),
90
87
  right: /*#__PURE__*/_react.default.createElement(LinkIcon, {
91
88
  icon: "check",
92
89
  width: 12,
93
90
  height: 12,
94
- active: getValue(option)
91
+ active: isActive(option)
95
92
  }),
96
93
  onClick: toggleOption(option),
97
- active: getValue(option)
94
+ active: isActive(option)
98
95
  };
99
96
  })
100
97
  });
@@ -102,7 +99,7 @@ var PseudoStateTool = function PseudoStateTool() {
102
99
  }, /*#__PURE__*/_react.default.createElement(_components.IconButton, {
103
100
  key: "pseudo-state",
104
101
  title: "Select CSS pseudo states",
105
- active: hasSelection
102
+ active: options.some(isActive)
106
103
  }, /*#__PURE__*/_react.default.createElement(_components.Icons, {
107
104
  icon: "button"
108
105
  })));
@@ -0,0 +1,111 @@
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
+ 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; } } }; }
13
+
14
+ 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); }
15
+
16
+ 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; }
17
+
18
+ var pseudoStates = Object.values(_constants.PSEUDO_STATES);
19
+ var matchOne = new RegExp(":(".concat(pseudoStates.join("|"), ")"));
20
+ var matchAll = new RegExp(":(".concat(pseudoStates.join("|"), ")"), "g");
21
+ var warnings = new Set();
22
+
23
+ var warnOnce = function warnOnce(message) {
24
+ if (warnings.has(message)) return; // eslint-disable-next-line no-console
25
+
26
+ console.warn(message);
27
+ warnings.add(message);
28
+ };
29
+
30
+ var rewriteRule = function rewriteRule(cssText, selectorText, shadowRoot) {
31
+ return cssText.replace(selectorText, (0, _splitSelectors.splitSelectors)(selectorText).flatMap(function (selector) {
32
+ if (selector.includes(".pseudo-")) {
33
+ return [];
34
+ }
35
+
36
+ if (!matchOne.test(selector)) {
37
+ return [selector];
38
+ }
39
+
40
+ var states = [];
41
+ var plainSelector = selector.replace(matchAll, function (_, state) {
42
+ states.push(state);
43
+ return "";
44
+ });
45
+ var classSelector = states.reduce(function (acc, state) {
46
+ return acc.replace(new RegExp(":".concat(state), "g"), ".pseudo-".concat(state));
47
+ }, selector);
48
+
49
+ if (selector.startsWith(":host(") || selector.startsWith("::slotted(")) {
50
+ return [selector, classSelector];
51
+ }
52
+
53
+ var ancestorSelector = shadowRoot ? ":host(".concat(states.map(function (s) {
54
+ return ".pseudo-".concat(s);
55
+ }).join(""), ") ").concat(plainSelector) : "".concat(states.map(function (s) {
56
+ return ".pseudo-".concat(s);
57
+ }).join(""), " ").concat(plainSelector);
58
+ return [selector, classSelector, ancestorSelector].filter(function (selector) {
59
+ return !selector.includes(":not()");
60
+ });
61
+ }).join(", "));
62
+ }; // Rewrites the style sheet to add alternative selectors for any rule that targets a pseudo state.
63
+ // A sheet can only be rewritten once, and may carry over between stories.
64
+
65
+
66
+ var rewriteStyleSheet = function rewriteStyleSheet(sheet, shadowRoot, shadowHosts) {
67
+ if (sheet.__pseudoStatesRewritten) return;
68
+ sheet.__pseudoStatesRewritten = true;
69
+
70
+ try {
71
+ var index = 0;
72
+
73
+ var _iterator = _createForOfIteratorHelper(sheet.cssRules),
74
+ _step;
75
+
76
+ try {
77
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
78
+ var _step$value = _step.value,
79
+ cssText = _step$value.cssText,
80
+ selectorText = _step$value.selectorText;
81
+
82
+ if (matchOne.test(selectorText)) {
83
+ var newRule = rewriteRule(cssText, selectorText, shadowRoot);
84
+ sheet.deleteRule(index);
85
+ sheet.insertRule(newRule, index);
86
+ if (shadowRoot) shadowHosts.add(shadowRoot.host);
87
+ }
88
+
89
+ index++;
90
+
91
+ if (index > 1000) {
92
+ warnOnce("Reached maximum of 1000 pseudo selectors per sheet, skipping the rest.");
93
+ break;
94
+ }
95
+ }
96
+ } catch (err) {
97
+ _iterator.e(err);
98
+ } finally {
99
+ _iterator.f();
100
+ }
101
+ } catch (e) {
102
+ if (e.toString().includes("cssRules")) {
103
+ warnOnce("Can't access cssRules, likely due to CORS restrictions: ".concat(sheet.href));
104
+ } else {
105
+ // eslint-disable-next-line no-console
106
+ console.error(e, sheet.href);
107
+ }
108
+ }
109
+ };
110
+
111
+ exports.rewriteStyleSheet = rewriteStyleSheet;
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+
3
+ var _rewriteStyleSheet = require("./rewriteStyleSheet");
4
+
5
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
6
+
7
+ 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); } }
8
+
9
+ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
10
+
11
+ var Sheet = /*#__PURE__*/function () {
12
+ function Sheet() {
13
+ _classCallCheck(this, Sheet);
14
+
15
+ this.__pseudoStatesRewritten = false;
16
+
17
+ for (var _len = arguments.length, rules = new Array(_len), _key = 0; _key < _len; _key++) {
18
+ rules[_key] = arguments[_key];
19
+ }
20
+
21
+ this.cssRules = rules.map(function (cssText) {
22
+ return {
23
+ cssText: cssText,
24
+ selectorText: cssText.slice(0, cssText.indexOf(" {"))
25
+ };
26
+ });
27
+ }
28
+
29
+ _createClass(Sheet, [{
30
+ key: "deleteRule",
31
+ value: function deleteRule(index) {
32
+ this.cssRules.splice(index, 1);
33
+ }
34
+ }, {
35
+ key: "insertRule",
36
+ value: function insertRule(cssText, index) {
37
+ this.cssRules.splice(index, 0, cssText);
38
+ }
39
+ }]);
40
+
41
+ return Sheet;
42
+ }();
43
+
44
+ describe("rewriteStyleSheet", function () {
45
+ it("adds alternative selector targeting the element directly", function () {
46
+ var sheet = new Sheet("a:hover { color: red }");
47
+ (0, _rewriteStyleSheet.rewriteStyleSheet)(sheet);
48
+ expect(sheet.cssRules[0]).toContain("a.pseudo-hover");
49
+ });
50
+ it("adds alternative selector targeting an ancestor", function () {
51
+ var sheet = new Sheet("a:hover { color: red }");
52
+ (0, _rewriteStyleSheet.rewriteStyleSheet)(sheet);
53
+ expect(sheet.cssRules[0]).toContain(".pseudo-hover a");
54
+ });
55
+ it("adds alternative selector for each pseudo selector", function () {
56
+ var sheet = new Sheet("a:hover, a:focus { color: red }");
57
+ (0, _rewriteStyleSheet.rewriteStyleSheet)(sheet);
58
+ expect(sheet.cssRules[0]).toContain("a.pseudo-hover");
59
+ expect(sheet.cssRules[0]).toContain("a.pseudo-focus");
60
+ expect(sheet.cssRules[0]).toContain(".pseudo-hover a");
61
+ expect(sheet.cssRules[0]).toContain(".pseudo-focus a");
62
+ });
63
+ it("keeps non-pseudo selectors as-is", function () {
64
+ var sheet = new Sheet("a.class, a:hover, a:focus, a#id { color: red }");
65
+ (0, _rewriteStyleSheet.rewriteStyleSheet)(sheet);
66
+ expect(sheet.cssRules[0]).toContain("a.class");
67
+ expect(sheet.cssRules[0]).toContain("a#id");
68
+ });
69
+ it("supports combined pseudo selectors", function () {
70
+ var sheet = new Sheet("a:hover:focus { color: red }");
71
+ (0, _rewriteStyleSheet.rewriteStyleSheet)(sheet);
72
+ expect(sheet.cssRules[0]).toContain("a.pseudo-hover.pseudo-focus");
73
+ expect(sheet.cssRules[0]).toContain(".pseudo-hover.pseudo-focus a");
74
+ });
75
+ it('supports ":host"', function () {
76
+ var sheet = new Sheet(":host(:hover) { color: red }");
77
+ (0, _rewriteStyleSheet.rewriteStyleSheet)(sheet);
78
+ expect(sheet.cssRules[0]).toEqual(":host(:hover), :host(.pseudo-hover) { color: red }");
79
+ });
80
+ it('supports ":not"', function () {
81
+ var sheet = new Sheet(":not(:hover) { color: red }");
82
+ (0, _rewriteStyleSheet.rewriteStyleSheet)(sheet);
83
+ expect(sheet.cssRules[0]).toEqual(":not(:hover), :not(.pseudo-hover) { color: red }");
84
+ });
85
+ });
@@ -11,7 +11,7 @@ var _coreEvents = require("@storybook/core-events");
11
11
 
12
12
  var _constants = require("./constants");
13
13
 
14
- var _splitSelectors = require("./splitSelectors");
14
+ var _rewriteStyleSheet = require("./rewriteStyleSheet");
15
15
 
16
16
  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; }
17
17
 
@@ -19,8 +19,6 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { va
19
19
 
20
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
21
 
22
- 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(_e2) { throw _e2; }, 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(_e3) { didErr = true; err = _e3; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
23
-
24
22
  function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
25
23
 
26
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."); }
@@ -41,9 +39,9 @@ function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToAr
41
39
 
42
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; }
43
41
 
44
- var pseudoStates = Object.values(_constants.PSEUDO_STATES);
45
- var matchOne = new RegExp(":(".concat(pseudoStates.join("|"), ")"));
46
- var matchAll = new RegExp(":(".concat(pseudoStates.join("|"), ")"), "g"); // Drops any existing pseudo state classnames that carried over from a previously viewed story
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
47
45
  // before adding the new classnames. We do this the old-fashioned way, for IE compatibility.
48
46
 
49
47
  var applyClasses = function applyClasses(element, classnames) {
@@ -54,19 +52,42 @@ var applyClasses = function applyClasses(element, classnames) {
54
52
  })).concat.apply(_element$className$sp, _toConsumableArray(classnames)).join(" ");
55
53
  };
56
54
 
57
- var applyParameter = function applyParameter(element, parameter) {
58
- return applyClasses(element, Object.entries(parameter || {}).filter(function (_ref) {
55
+ var applyParameter = function applyParameter(rootElement, parameter) {
56
+ var map = new Map([[rootElement, new Set()]]);
57
+
58
+ var add = function add(target, state) {
59
+ return map.set(target, new Set([].concat(_toConsumableArray(map.get(target) || []), [state])));
60
+ };
61
+
62
+ Object.entries(parameter || {}).forEach(function (_ref) {
59
63
  var _ref2 = _slicedToArray(_ref, 2),
60
- _ = _ref2[0],
64
+ state = _ref2[0],
61
65
  value = _ref2[1];
62
66
 
63
- return value;
64
- }).map(function (_ref3) {
65
- var _ref4 = _slicedToArray(_ref3, 1),
66
- key = _ref4[0];
67
-
68
- return "pseudo-".concat(_constants.PSEUDO_STATES[key]);
69
- }));
67
+ if (typeof value === "boolean") {
68
+ // default API - applying pseudo class to root element.
69
+ add(rootElement, value && state);
70
+ } else if (typeof value === "string") {
71
+ // explicit selectors API - applying pseudo class to a specific element
72
+ rootElement.querySelectorAll(value).forEach(function (el) {
73
+ return add(el, state);
74
+ });
75
+ } else if (Array.isArray(value)) {
76
+ // explicit selectors API - we have an array (of strings) recursively handle each one
77
+ value.forEach(function (sel) {
78
+ return rootElement.querySelectorAll(sel).forEach(function (el) {
79
+ return add(el, state);
80
+ });
81
+ });
82
+ }
83
+ });
84
+ map.forEach(function (states, target) {
85
+ var classnames = [];
86
+ states.forEach(function (key) {
87
+ return _constants.PSEUDO_STATES[key] && classnames.push("pseudo-".concat(_constants.PSEUDO_STATES[key]));
88
+ });
89
+ applyClasses(target, classnames);
90
+ });
70
91
  }; // Traverses ancestry to collect relevant pseudo classnames, and applies them to the shadow host.
71
92
  // Shadow DOM can only access classes on its host. Traversing is needed to mimic the CSS cascade.
72
93
 
@@ -84,28 +105,18 @@ var updateShadowHost = function updateShadowHost(shadowHost) {
84
105
  }
85
106
 
86
107
  applyClasses(shadowHost, classnames);
87
- }; // Keep track of attached shadow host elements for the current story
108
+ }; // Global decorator that rewrites stylesheets and applies classnames to render pseudo styles
88
109
 
89
110
 
90
- var shadowHosts = new Set();
91
-
92
- _addons.addons.getChannel().on(_coreEvents.STORY_CHANGED, function () {
93
- return shadowHosts.clear();
94
- }); // Global decorator that rewrites stylesheets and applies classnames to render pseudo styles
95
-
96
-
97
- var withPseudoState = function withPseudoState(StoryFn, _ref5) {
98
- var viewMode = _ref5.viewMode,
99
- parameters = _ref5.parameters,
100
- id = _ref5.id,
101
- globalsArgs = _ref5.globals;
111
+ var withPseudoState = function withPseudoState(StoryFn, _ref3) {
112
+ var viewMode = _ref3.viewMode,
113
+ parameters = _ref3.parameters,
114
+ id = _ref3.id,
115
+ globalsArgs = _ref3.globals;
102
116
  var parameter = parameters.pseudo;
103
- var globals = globalsArgs.pseudo;
104
-
105
- var channel = _addons.addons.getChannel(); // Sync parameter to globals, used by the toolbar (only in canvas as this
117
+ var globals = globalsArgs.pseudo; // Sync parameter to globals, used by the toolbar (only in canvas as this
106
118
  // doesn't make sense for docs because many stories are displayed at once)
107
119
 
108
-
109
120
  (0, _addons.useEffect)(function () {
110
121
  if (parameter !== globals && viewMode === "story") {
111
122
  channel.emit(_coreEvents.UPDATE_GLOBALS, {
@@ -120,133 +131,42 @@ var withPseudoState = function withPseudoState(StoryFn, _ref5) {
120
131
  (0, _addons.useEffect)(function () {
121
132
  var timeout = setTimeout(function () {
122
133
  var element = document.getElementById(viewMode === "docs" ? "story--".concat(id) : "root");
123
- applyParameter(element, globals);
134
+ applyParameter(element, globals || parameter);
124
135
  shadowHosts.forEach(updateShadowHost);
125
136
  }, 0);
126
137
  return function () {
127
138
  return clearTimeout(timeout);
128
139
  };
129
- }, [globals, viewMode]);
140
+ }, [globals, parameter, viewMode]);
130
141
  return StoryFn();
131
- };
132
-
133
- exports.withPseudoState = withPseudoState;
134
- var warnings = new Set();
135
-
136
- var warnOnce = function warnOnce(message) {
137
- if (warnings.has(message)) return; // eslint-disable-next-line no-console
138
-
139
- console.warn(message);
140
- warnings.add(message);
141
142
  }; // Rewrite CSS rules for pseudo-states on all stylesheets to add an alternative selector
142
143
 
143
144
 
144
- function rewriteStyleSheets(shadowRoot) {
145
+ exports.withPseudoState = withPseudoState;
146
+
147
+ var rewriteStyleSheets = function rewriteStyleSheets(shadowRoot) {
145
148
  var _shadowRoot$adoptedSt;
146
149
 
147
150
  var styleSheets = shadowRoot ? shadowRoot.styleSheets : document.styleSheets;
148
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
149
156
 
150
- var _iterator = _createForOfIteratorHelper(styleSheets),
151
- _step;
152
-
153
- try {
154
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
155
- var sheet = _step.value;
156
-
157
- if (sheet._pseudoStatesRewritten) {
158
- continue;
159
- } else {
160
- sheet._pseudoStatesRewritten = true;
161
- }
162
-
163
- try {
164
- var index = 0;
165
-
166
- var _iterator2 = _createForOfIteratorHelper(sheet.cssRules),
167
- _step2;
168
-
169
- try {
170
- for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
171
- var _step2$value = _step2.value,
172
- cssText = _step2$value.cssText,
173
- selectorText = _step2$value.selectorText;
174
-
175
- if (matchOne.test(selectorText)) {
176
- var selectors = (0, _splitSelectors.splitSelectors)(selectorText);
177
- var newRule = cssText.replace(selectorText, selectors.flatMap(function (selector) {
178
- if (selector.includes(".pseudo-")) return [];
179
- var states = [];
180
- var plainSelector = selector.replace(matchAll, function (_, state) {
181
- states.push(state);
182
- return "";
183
- });
184
- var stateSelector;
185
-
186
- if (!matchOne.test(selector)) {
187
- return [selector];
188
- }
189
-
190
- if (selector.startsWith(":host(") || selector.startsWith("::slotted(")) {
191
- stateSelector = states.reduce(function (acc, state) {
192
- return acc.replaceAll(":".concat(state), ".pseudo-".concat(state));
193
- }, selector);
194
- } else if (shadowRoot) {
195
- stateSelector = ":host(".concat(states.map(function (s) {
196
- return ".pseudo-".concat(s);
197
- }).join(""), ") ").concat(plainSelector);
198
- } else {
199
- stateSelector = "".concat(states.map(function (s) {
200
- return ".pseudo-".concat(s);
201
- }).join(""), " ").concat(plainSelector);
202
- }
203
-
204
- return [selector, stateSelector];
205
- }).join(", "));
206
- sheet.deleteRule(index);
207
- sheet.insertRule(newRule, index);
208
- if (shadowRoot) shadowHosts.add(shadowRoot.host);
209
- }
210
-
211
- index++;
212
-
213
- if (index > 1000) {
214
- warnOnce("Reached maximum of 1000 pseudo selectors per sheet, skipping the rest.");
215
- break;
216
- }
217
- }
218
- } catch (err) {
219
- _iterator2.e(err);
220
- } finally {
221
- _iterator2.f();
222
- }
223
- } catch (e) {
224
- if (e.toString().includes("cssRules")) {
225
- warnOnce("Can't access cssRules, likely due to CORS restrictions: ".concat(sheet.href));
226
- } else {
227
- // eslint-disable-next-line no-console
228
- console.error(e, sheet.href);
229
- }
230
- }
231
- }
232
- } catch (err) {
233
- _iterator.e(err);
234
- } finally {
235
- _iterator.f();
236
- }
237
- } // Reinitialize CSS enhancements every time the story changes
238
157
 
158
+ channel.on(_coreEvents.STORY_CHANGED, function () {
159
+ return shadowHosts.clear();
160
+ }); // Reinitialize CSS enhancements every time the story changes
239
161
 
240
- _addons.addons.getChannel().on(_coreEvents.STORY_RENDERED, function () {
162
+ channel.on(_coreEvents.STORY_RENDERED, function () {
241
163
  return rewriteStyleSheets();
242
164
  }); // Reinitialize CSS enhancements every time a docs page is rendered
243
165
 
244
-
245
- _addons.addons.getChannel().on(_coreEvents.DOCS_RENDERED, function () {
166
+ channel.on(_coreEvents.DOCS_RENDERED, function () {
246
167
  return rewriteStyleSheets();
247
168
  }); // IE doesn't support shadow DOM
248
169
 
249
-
250
170
  if (Element.prototype.attachShadow) {
251
171
  // Monkeypatch the attachShadow method so we can handle pseudo styles inside shadow DOM
252
172
  Element.prototype._attachShadow = Element.prototype.attachShadow;
@@ -43,19 +43,16 @@ export var PseudoStateTool = function PseudoStateTool() {
43
43
  pseudo = _useGlobals2[0].pseudo,
44
44
  updateGlobals = _useGlobals2[1];
45
45
 
46
- var hasSelection = useMemo(function () {
47
- return !!pseudo && Object.values(pseudo).includes(true);
48
- }, [pseudo]);
49
- var getValue = useCallback(function (option) {
50
- return pseudo ? pseudo[option] : false;
46
+ var isActive = useCallback(function (option) {
47
+ return (pseudo === null || pseudo === void 0 ? void 0 : pseudo[option]) === true;
51
48
  }, [pseudo]);
52
49
  var toggleOption = useCallback(function (option) {
53
50
  return function () {
54
51
  return updateGlobals({
55
- pseudo: _objectSpread(_objectSpread({}, pseudo), {}, _defineProperty({}, option, !getValue(option)))
52
+ pseudo: _objectSpread(_objectSpread({}, pseudo), {}, _defineProperty({}, option, !isActive(option)))
56
53
  });
57
54
  };
58
- }, [pseudo, getValue]);
55
+ }, [pseudo]);
59
56
  return /*#__PURE__*/React.createElement(WithTooltip, {
60
57
  placement: "top",
61
58
  trigger: "click",
@@ -65,16 +62,16 @@ export var PseudoStateTool = function PseudoStateTool() {
65
62
  return {
66
63
  id: option,
67
64
  title: /*#__PURE__*/React.createElement(LinkTitle, {
68
- active: getValue(option)
65
+ active: isActive(option)
69
66
  }, ":", PSEUDO_STATES[option]),
70
67
  right: /*#__PURE__*/React.createElement(LinkIcon, {
71
68
  icon: "check",
72
69
  width: 12,
73
70
  height: 12,
74
- active: getValue(option)
71
+ active: isActive(option)
75
72
  }),
76
73
  onClick: toggleOption(option),
77
- active: getValue(option)
74
+ active: isActive(option)
78
75
  };
79
76
  })
80
77
  });
@@ -82,7 +79,7 @@ export var PseudoStateTool = function PseudoStateTool() {
82
79
  }, /*#__PURE__*/React.createElement(IconButton, {
83
80
  key: "pseudo-state",
84
81
  title: "Select CSS pseudo states",
85
- active: hasSelection
82
+ active: options.some(isActive)
86
83
  }, /*#__PURE__*/React.createElement(Icons, {
87
84
  icon: "button"
88
85
  })));
@@ -0,0 +1,100 @@
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
+ import { PSEUDO_STATES } from "./constants";
8
+ import { splitSelectors } from "./splitSelectors";
9
+ var pseudoStates = Object.values(PSEUDO_STATES);
10
+ var matchOne = new RegExp(":(".concat(pseudoStates.join("|"), ")"));
11
+ var matchAll = new RegExp(":(".concat(pseudoStates.join("|"), ")"), "g");
12
+ var warnings = new Set();
13
+
14
+ var warnOnce = function warnOnce(message) {
15
+ if (warnings.has(message)) return; // eslint-disable-next-line no-console
16
+
17
+ console.warn(message);
18
+ warnings.add(message);
19
+ };
20
+
21
+ var rewriteRule = function rewriteRule(cssText, selectorText, shadowRoot) {
22
+ return cssText.replace(selectorText, splitSelectors(selectorText).flatMap(function (selector) {
23
+ if (selector.includes(".pseudo-")) {
24
+ return [];
25
+ }
26
+
27
+ if (!matchOne.test(selector)) {
28
+ return [selector];
29
+ }
30
+
31
+ var states = [];
32
+ var plainSelector = selector.replace(matchAll, function (_, state) {
33
+ states.push(state);
34
+ return "";
35
+ });
36
+ var classSelector = states.reduce(function (acc, state) {
37
+ return acc.replace(new RegExp(":".concat(state), "g"), ".pseudo-".concat(state));
38
+ }, selector);
39
+
40
+ if (selector.startsWith(":host(") || selector.startsWith("::slotted(")) {
41
+ return [selector, classSelector];
42
+ }
43
+
44
+ var ancestorSelector = shadowRoot ? ":host(".concat(states.map(function (s) {
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
+ });
52
+ }).join(", "));
53
+ }; // Rewrites the style sheet to add alternative selectors for any rule that targets a pseudo state.
54
+ // A sheet can only be rewritten once, and may carry over between stories.
55
+
56
+
57
+ export var rewriteStyleSheet = function rewriteStyleSheet(sheet, shadowRoot, shadowHosts) {
58
+ if (sheet.__pseudoStatesRewritten) return;
59
+ sheet.__pseudoStatesRewritten = true;
60
+
61
+ try {
62
+ var index = 0;
63
+
64
+ var _iterator = _createForOfIteratorHelper(sheet.cssRules),
65
+ _step;
66
+
67
+ try {
68
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
69
+ var _step$value = _step.value,
70
+ cssText = _step$value.cssText,
71
+ selectorText = _step$value.selectorText;
72
+
73
+ if (matchOne.test(selectorText)) {
74
+ var newRule = rewriteRule(cssText, selectorText, shadowRoot);
75
+ sheet.deleteRule(index);
76
+ sheet.insertRule(newRule, index);
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
+ }
86
+ }
87
+ } catch (err) {
88
+ _iterator.e(err);
89
+ } finally {
90
+ _iterator.f();
91
+ }
92
+ } catch (e) {
93
+ if (e.toString().includes("cssRules")) {
94
+ warnOnce("Can't access cssRules, likely due to CORS restrictions: ".concat(sheet.href));
95
+ } else {
96
+ // eslint-disable-next-line no-console
97
+ console.error(e, sheet.href);
98
+ }
99
+ }
100
+ };
@@ -0,0 +1,83 @@
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
+ import { rewriteStyleSheet } from "./rewriteStyleSheet";
8
+
9
+ var Sheet = /*#__PURE__*/function () {
10
+ function Sheet() {
11
+ _classCallCheck(this, Sheet);
12
+
13
+ this.__pseudoStatesRewritten = false;
14
+
15
+ for (var _len = arguments.length, rules = new Array(_len), _key = 0; _key < _len; _key++) {
16
+ rules[_key] = arguments[_key];
17
+ }
18
+
19
+ this.cssRules = rules.map(function (cssText) {
20
+ return {
21
+ cssText: cssText,
22
+ selectorText: cssText.slice(0, cssText.indexOf(" {"))
23
+ };
24
+ });
25
+ }
26
+
27
+ _createClass(Sheet, [{
28
+ key: "deleteRule",
29
+ value: function deleteRule(index) {
30
+ this.cssRules.splice(index, 1);
31
+ }
32
+ }, {
33
+ key: "insertRule",
34
+ value: function insertRule(cssText, index) {
35
+ this.cssRules.splice(index, 0, cssText);
36
+ }
37
+ }]);
38
+
39
+ return Sheet;
40
+ }();
41
+
42
+ describe("rewriteStyleSheet", function () {
43
+ it("adds alternative selector targeting the element directly", function () {
44
+ var sheet = new Sheet("a:hover { color: red }");
45
+ rewriteStyleSheet(sheet);
46
+ expect(sheet.cssRules[0]).toContain("a.pseudo-hover");
47
+ });
48
+ it("adds alternative selector targeting an ancestor", function () {
49
+ var sheet = new Sheet("a:hover { color: red }");
50
+ rewriteStyleSheet(sheet);
51
+ expect(sheet.cssRules[0]).toContain(".pseudo-hover a");
52
+ });
53
+ it("adds alternative selector for each pseudo selector", function () {
54
+ var sheet = new Sheet("a:hover, a:focus { color: red }");
55
+ rewriteStyleSheet(sheet);
56
+ expect(sheet.cssRules[0]).toContain("a.pseudo-hover");
57
+ expect(sheet.cssRules[0]).toContain("a.pseudo-focus");
58
+ expect(sheet.cssRules[0]).toContain(".pseudo-hover a");
59
+ expect(sheet.cssRules[0]).toContain(".pseudo-focus a");
60
+ });
61
+ it("keeps non-pseudo selectors as-is", function () {
62
+ var sheet = new Sheet("a.class, a:hover, a:focus, a#id { color: red }");
63
+ rewriteStyleSheet(sheet);
64
+ expect(sheet.cssRules[0]).toContain("a.class");
65
+ expect(sheet.cssRules[0]).toContain("a#id");
66
+ });
67
+ it("supports combined pseudo selectors", function () {
68
+ var sheet = new Sheet("a:hover:focus { color: red }");
69
+ rewriteStyleSheet(sheet);
70
+ expect(sheet.cssRules[0]).toContain("a.pseudo-hover.pseudo-focus");
71
+ expect(sheet.cssRules[0]).toContain(".pseudo-hover.pseudo-focus a");
72
+ });
73
+ it('supports ":host"', function () {
74
+ var sheet = new Sheet(":host(:hover) { color: red }");
75
+ rewriteStyleSheet(sheet);
76
+ expect(sheet.cssRules[0]).toEqual(":host(:hover), :host(.pseudo-hover) { color: red }");
77
+ });
78
+ it('supports ":not"', function () {
79
+ var sheet = new Sheet(":not(:hover) { color: red }");
80
+ rewriteStyleSheet(sheet);
81
+ expect(sheet.cssRules[0]).toEqual(":not(:hover), :not(.pseudo-hover) { color: red }");
82
+ });
83
+ });
@@ -4,8 +4,6 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { va
4
4
 
5
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
6
 
7
- 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(_e2) { throw _e2; }, 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(_e3) { didErr = true; err = _e3; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
8
-
9
7
  function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
10
8
 
11
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."); }
@@ -28,13 +26,11 @@ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len
28
26
 
29
27
  /* eslint-env browser */
30
28
  import { addons, useEffect } from "@storybook/addons";
31
- import { DOCS_RENDERED, STORY_CHANGED, STORY_RENDERED } from "@storybook/core-events";
32
- import { UPDATE_GLOBALS } from "@storybook/core-events";
29
+ import { DOCS_RENDERED, STORY_CHANGED, STORY_RENDERED, UPDATE_GLOBALS } from "@storybook/core-events";
33
30
  import { PSEUDO_STATES } from "./constants";
34
- import { splitSelectors } from "./splitSelectors";
35
- var pseudoStates = Object.values(PSEUDO_STATES);
36
- var matchOne = new RegExp(":(".concat(pseudoStates.join("|"), ")"));
37
- var matchAll = new RegExp(":(".concat(pseudoStates.join("|"), ")"), "g"); // Drops any existing pseudo state classnames that carried over from a previously viewed story
31
+ import { rewriteStyleSheet } from "./rewriteStyleSheet";
32
+ var channel = addons.getChannel();
33
+ var shadowHosts = new Set(); // Drops any existing pseudo state classnames that carried over from a previously viewed story
38
34
  // before adding the new classnames. We do this the old-fashioned way, for IE compatibility.
39
35
 
40
36
  var applyClasses = function applyClasses(element, classnames) {
@@ -45,19 +41,42 @@ var applyClasses = function applyClasses(element, classnames) {
45
41
  })).concat.apply(_element$className$sp, _toConsumableArray(classnames)).join(" ");
46
42
  };
47
43
 
48
- var applyParameter = function applyParameter(element, parameter) {
49
- return applyClasses(element, Object.entries(parameter || {}).filter(function (_ref) {
44
+ var applyParameter = function applyParameter(rootElement, parameter) {
45
+ var map = new Map([[rootElement, new Set()]]);
46
+
47
+ var add = function add(target, state) {
48
+ return map.set(target, new Set([].concat(_toConsumableArray(map.get(target) || []), [state])));
49
+ };
50
+
51
+ Object.entries(parameter || {}).forEach(function (_ref) {
50
52
  var _ref2 = _slicedToArray(_ref, 2),
51
- _ = _ref2[0],
53
+ state = _ref2[0],
52
54
  value = _ref2[1];
53
55
 
54
- return value;
55
- }).map(function (_ref3) {
56
- var _ref4 = _slicedToArray(_ref3, 1),
57
- key = _ref4[0];
58
-
59
- return "pseudo-".concat(PSEUDO_STATES[key]);
60
- }));
56
+ if (typeof value === "boolean") {
57
+ // default API - applying pseudo class to root element.
58
+ add(rootElement, value && state);
59
+ } else if (typeof value === "string") {
60
+ // explicit selectors API - applying pseudo class to a specific element
61
+ rootElement.querySelectorAll(value).forEach(function (el) {
62
+ return add(el, state);
63
+ });
64
+ } else if (Array.isArray(value)) {
65
+ // explicit selectors API - we have an array (of strings) recursively handle each one
66
+ value.forEach(function (sel) {
67
+ return rootElement.querySelectorAll(sel).forEach(function (el) {
68
+ return add(el, state);
69
+ });
70
+ });
71
+ }
72
+ });
73
+ map.forEach(function (states, target) {
74
+ var classnames = [];
75
+ states.forEach(function (key) {
76
+ return PSEUDO_STATES[key] && classnames.push("pseudo-".concat(PSEUDO_STATES[key]));
77
+ });
78
+ applyClasses(target, classnames);
79
+ });
61
80
  }; // Traverses ancestry to collect relevant pseudo classnames, and applies them to the shadow host.
62
81
  // Shadow DOM can only access classes on its host. Traversing is needed to mimic the CSS cascade.
63
82
 
@@ -75,22 +94,16 @@ var updateShadowHost = function updateShadowHost(shadowHost) {
75
94
  }
76
95
 
77
96
  applyClasses(shadowHost, classnames);
78
- }; // Keep track of attached shadow host elements for the current story
79
-
97
+ }; // Global decorator that rewrites stylesheets and applies classnames to render pseudo styles
80
98
 
81
- var shadowHosts = new Set();
82
- addons.getChannel().on(STORY_CHANGED, function () {
83
- return shadowHosts.clear();
84
- }); // Global decorator that rewrites stylesheets and applies classnames to render pseudo styles
85
99
 
86
- export var withPseudoState = function withPseudoState(StoryFn, _ref5) {
87
- var viewMode = _ref5.viewMode,
88
- parameters = _ref5.parameters,
89
- id = _ref5.id,
90
- globalsArgs = _ref5.globals;
100
+ export var withPseudoState = function withPseudoState(StoryFn, _ref3) {
101
+ var viewMode = _ref3.viewMode,
102
+ parameters = _ref3.parameters,
103
+ id = _ref3.id,
104
+ globalsArgs = _ref3.globals;
91
105
  var parameter = parameters.pseudo;
92
- var globals = globalsArgs.pseudo;
93
- var channel = addons.getChannel(); // Sync parameter to globals, used by the toolbar (only in canvas as this
106
+ var globals = globalsArgs.pseudo; // Sync parameter to globals, used by the toolbar (only in canvas as this
94
107
  // doesn't make sense for docs because many stories are displayed at once)
95
108
 
96
109
  useEffect(function () {
@@ -107,126 +120,36 @@ export var withPseudoState = function withPseudoState(StoryFn, _ref5) {
107
120
  useEffect(function () {
108
121
  var timeout = setTimeout(function () {
109
122
  var element = document.getElementById(viewMode === "docs" ? "story--".concat(id) : "root");
110
- applyParameter(element, globals);
123
+ applyParameter(element, globals || parameter);
111
124
  shadowHosts.forEach(updateShadowHost);
112
125
  }, 0);
113
126
  return function () {
114
127
  return clearTimeout(timeout);
115
128
  };
116
- }, [globals, viewMode]);
129
+ }, [globals, parameter, viewMode]);
117
130
  return StoryFn();
118
- };
119
- var warnings = new Set();
120
-
121
- var warnOnce = function warnOnce(message) {
122
- if (warnings.has(message)) return; // eslint-disable-next-line no-console
123
-
124
- console.warn(message);
125
- warnings.add(message);
126
131
  }; // Rewrite CSS rules for pseudo-states on all stylesheets to add an alternative selector
127
132
 
128
-
129
- function rewriteStyleSheets(shadowRoot) {
133
+ var rewriteStyleSheets = function rewriteStyleSheets(shadowRoot) {
130
134
  var _shadowRoot$adoptedSt;
131
135
 
132
136
  var styleSheets = shadowRoot ? shadowRoot.styleSheets : document.styleSheets;
133
137
  if (shadowRoot !== null && shadowRoot !== void 0 && (_shadowRoot$adoptedSt = shadowRoot.adoptedStyleSheets) !== null && _shadowRoot$adoptedSt !== void 0 && _shadowRoot$adoptedSt.length) styleSheets = shadowRoot.adoptedStyleSheets;
138
+ Array.from(styleSheets).forEach(function (sheet) {
139
+ return rewriteStyleSheet(sheet, shadowRoot, shadowHosts);
140
+ });
141
+ }; // Only track shadow hosts for the current story
134
142
 
135
- var _iterator = _createForOfIteratorHelper(styleSheets),
136
- _step;
137
-
138
- try {
139
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
140
- var sheet = _step.value;
141
-
142
- if (sheet._pseudoStatesRewritten) {
143
- continue;
144
- } else {
145
- sheet._pseudoStatesRewritten = true;
146
- }
147
-
148
- try {
149
- var index = 0;
150
-
151
- var _iterator2 = _createForOfIteratorHelper(sheet.cssRules),
152
- _step2;
153
-
154
- try {
155
- for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
156
- var _step2$value = _step2.value,
157
- cssText = _step2$value.cssText,
158
- selectorText = _step2$value.selectorText;
159
-
160
- if (matchOne.test(selectorText)) {
161
- var selectors = splitSelectors(selectorText);
162
- var newRule = cssText.replace(selectorText, selectors.flatMap(function (selector) {
163
- if (selector.includes(".pseudo-")) return [];
164
- var states = [];
165
- var plainSelector = selector.replace(matchAll, function (_, state) {
166
- states.push(state);
167
- return "";
168
- });
169
- var stateSelector;
170
-
171
- if (!matchOne.test(selector)) {
172
- return [selector];
173
- }
174
-
175
- if (selector.startsWith(":host(") || selector.startsWith("::slotted(")) {
176
- stateSelector = states.reduce(function (acc, state) {
177
- return acc.replaceAll(":".concat(state), ".pseudo-".concat(state));
178
- }, selector);
179
- } else if (shadowRoot) {
180
- stateSelector = ":host(".concat(states.map(function (s) {
181
- return ".pseudo-".concat(s);
182
- }).join(""), ") ").concat(plainSelector);
183
- } else {
184
- stateSelector = "".concat(states.map(function (s) {
185
- return ".pseudo-".concat(s);
186
- }).join(""), " ").concat(plainSelector);
187
- }
188
-
189
- return [selector, stateSelector];
190
- }).join(", "));
191
- sheet.deleteRule(index);
192
- sheet.insertRule(newRule, index);
193
- if (shadowRoot) shadowHosts.add(shadowRoot.host);
194
- }
195
-
196
- index++;
197
-
198
- if (index > 1000) {
199
- warnOnce("Reached maximum of 1000 pseudo selectors per sheet, skipping the rest.");
200
- break;
201
- }
202
- }
203
- } catch (err) {
204
- _iterator2.e(err);
205
- } finally {
206
- _iterator2.f();
207
- }
208
- } catch (e) {
209
- if (e.toString().includes("cssRules")) {
210
- warnOnce("Can't access cssRules, likely due to CORS restrictions: ".concat(sheet.href));
211
- } else {
212
- // eslint-disable-next-line no-console
213
- console.error(e, sheet.href);
214
- }
215
- }
216
- }
217
- } catch (err) {
218
- _iterator.e(err);
219
- } finally {
220
- _iterator.f();
221
- }
222
- } // Reinitialize CSS enhancements every time the story changes
223
143
 
144
+ channel.on(STORY_CHANGED, function () {
145
+ return shadowHosts.clear();
146
+ }); // Reinitialize CSS enhancements every time the story changes
224
147
 
225
- addons.getChannel().on(STORY_RENDERED, function () {
148
+ channel.on(STORY_RENDERED, function () {
226
149
  return rewriteStyleSheets();
227
150
  }); // Reinitialize CSS enhancements every time a docs page is rendered
228
151
 
229
- addons.getChannel().on(DOCS_RENDERED, function () {
152
+ channel.on(DOCS_RENDERED, function () {
230
153
  return rewriteStyleSheets();
231
154
  }); // IE doesn't support shadow DOM
232
155
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "storybook-addon-pseudo-states",
3
- "version": "1.14.1",
3
+ "version": "1.15.0",
4
4
  "description": "CSS pseudo states for Storybook",
5
5
  "keywords": [
6
6
  "storybook-addons",