storybook-addon-pseudo-states 2.0.2 → 2.1.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/README.md CHANGED
@@ -13,7 +13,7 @@ Toggle CSS pseudo states for your components in Storybook.
13
13
 
14
14
  ## Introduction
15
15
 
16
- This addon attempts to "force" your components' pseudo states. It rewrites all document stylesheets to add a class name selector to any rules that target a pseudo-class (`:hover`, `:focus`, etc.). The tool then allows you to toggle these class names on the story container (`#root`). Additionally, you can set the `pseudo` property on your story `parameters` to set a default value for each pseudo class. This makes it possible to test such states with [Chromatic](https://www.chromatic.com/).
16
+ This addon attempts to "force" your components' pseudo states. It rewrites all document stylesheets to add a class name selector to any rules that target a pseudo-class (`:hover`, `:focus`, etc.). The tool then allows you to toggle these class names on the story container (`#root`) or any other root element you want (via the `rootSelector` param). Additionally, you can set the `pseudo` property on your story `parameters` to set a default value for each pseudo class. This makes it possible to test such states with [Chromatic](https://www.chromatic.com/).
17
17
 
18
18
  ### Limitations
19
19
 
@@ -70,3 +70,21 @@ Buttons.parameters = {
70
70
  ```
71
71
 
72
72
  This accepts a single CSS selector (string), or an array of CSS selectors on which to enable that pseudo style.
73
+
74
+ ### Overriding the default root element
75
+
76
+ By default, we use `#storybook-root` (or `#root` before Storybook 7) element as the root element for all pseudo classes. If you need to render elements outside Storybook's root element, you can set `parameters.pseudo.rootSelector` to override it. This is convenient for portals, dialogs, tooltips, etc.
77
+
78
+ For example, consider a `Dialog` component that inject itself to the document's `body` node:
79
+
80
+ ```jsx
81
+ export const DialogButton = () => (
82
+ <Dialog>
83
+ <Button>Hover</Button>
84
+ </Dialog>
85
+ )
86
+
87
+ DialogButton.parameters = {
88
+ pseudo: { hover: true, rootSelector: "body" },
89
+ }
90
+ ```
package/dist/preview.js CHANGED
@@ -158,7 +158,7 @@ var applyClasses = (element, classnames) => {
158
158
  Object.values(PSEUDO_STATES).forEach((state) => element.classList.remove(`pseudo-${state}`));
159
159
  classnames.forEach((classname) => element.classList.add(classname));
160
160
  };
161
- var applyParameter = (rootElement, parameter) => {
161
+ var applyParameter = (rootElement, parameter = {}) => {
162
162
  const map = /* @__PURE__ */ new Map([[rootElement, /* @__PURE__ */ new Set()]]);
163
163
  const add = (target, state) => map.set(target, /* @__PURE__ */ new Set([...map.get(target) || [], state]));
164
164
  Object.entries(parameter || {}).forEach(([state, value]) => {
@@ -186,31 +186,43 @@ var updateShadowHost = (shadowHost) => {
186
186
  }
187
187
  applyClasses(shadowHost, classnames);
188
188
  };
189
+ var pseudoConfig = (parameter) => {
190
+ const { rootSelector, ...pseudoStateConfig } = parameter || {};
191
+ return pseudoStateConfig;
192
+ };
193
+ var equals = (a = {}, b = {}) => a !== null && b !== null && Object.keys(a).length === Object.keys(b).length && Object.keys(a).every(
194
+ (key) => JSON.stringify(a[key]) === JSON.stringify(b[key])
195
+ );
189
196
  var withPseudoState = (StoryFn, { viewMode, parameters, id, globals: globalsArgs }) => {
190
197
  const { pseudo: parameter } = parameters;
191
198
  const { pseudo: globals2 } = globalsArgs;
192
- const canvasElement = (0, import_preview_api.useMemo)(() => {
199
+ const { rootSelector } = parameter || {};
200
+ const rootElement = (0, import_preview_api.useMemo)(() => {
201
+ if (rootSelector) {
202
+ return document.querySelector(rootSelector);
203
+ }
193
204
  if (viewMode === "docs") {
194
205
  return document.getElementById(`story--${id}`);
195
206
  }
196
207
  return document.getElementById("storybook-root") || document.getElementById("root");
197
- }, [viewMode, id]);
208
+ }, [rootSelector, viewMode, id]);
198
209
  (0, import_preview_api.useEffect)(() => {
199
- if (parameter !== globals2 && viewMode === "story") {
210
+ const config = pseudoConfig(parameter);
211
+ if (viewMode === "story" && !equals(config, globals2)) {
200
212
  channel.emit(import_core_events.UPDATE_GLOBALS, {
201
- globals: { pseudo: parameter }
213
+ globals: { pseudo: config }
202
214
  });
203
215
  }
204
216
  }, [parameter, viewMode]);
205
217
  (0, import_preview_api.useEffect)(() => {
206
- if (!canvasElement)
218
+ if (!rootElement)
207
219
  return;
208
220
  const timeout = setTimeout(() => {
209
- applyParameter(canvasElement, globals2 || parameter);
221
+ applyParameter(rootElement, globals2 || pseudoConfig(parameter));
210
222
  shadowHosts.forEach(updateShadowHost);
211
223
  }, 0);
212
224
  return () => clearTimeout(timeout);
213
- }, [canvasElement, globals2, parameter]);
225
+ }, [rootElement, globals2, parameter]);
214
226
  return StoryFn();
215
227
  };
216
228
  var rewriteStyleSheets = (shadowRoot) => {
package/dist/preview.mjs CHANGED
@@ -126,7 +126,7 @@ var applyClasses = (element, classnames) => {
126
126
  Object.values(PSEUDO_STATES).forEach((state) => element.classList.remove(`pseudo-${state}`));
127
127
  classnames.forEach((classname) => element.classList.add(classname));
128
128
  };
129
- var applyParameter = (rootElement, parameter) => {
129
+ var applyParameter = (rootElement, parameter = {}) => {
130
130
  const map = /* @__PURE__ */ new Map([[rootElement, /* @__PURE__ */ new Set()]]);
131
131
  const add = (target, state) => map.set(target, /* @__PURE__ */ new Set([...map.get(target) || [], state]));
132
132
  Object.entries(parameter || {}).forEach(([state, value]) => {
@@ -154,31 +154,43 @@ var updateShadowHost = (shadowHost) => {
154
154
  }
155
155
  applyClasses(shadowHost, classnames);
156
156
  };
157
+ var pseudoConfig = (parameter) => {
158
+ const { rootSelector, ...pseudoStateConfig } = parameter || {};
159
+ return pseudoStateConfig;
160
+ };
161
+ var equals = (a = {}, b = {}) => a !== null && b !== null && Object.keys(a).length === Object.keys(b).length && Object.keys(a).every(
162
+ (key) => JSON.stringify(a[key]) === JSON.stringify(b[key])
163
+ );
157
164
  var withPseudoState = (StoryFn, { viewMode, parameters, id, globals: globalsArgs }) => {
158
165
  const { pseudo: parameter } = parameters;
159
166
  const { pseudo: globals2 } = globalsArgs;
160
- const canvasElement = useMemo(() => {
167
+ const { rootSelector } = parameter || {};
168
+ const rootElement = useMemo(() => {
169
+ if (rootSelector) {
170
+ return document.querySelector(rootSelector);
171
+ }
161
172
  if (viewMode === "docs") {
162
173
  return document.getElementById(`story--${id}`);
163
174
  }
164
175
  return document.getElementById("storybook-root") || document.getElementById("root");
165
- }, [viewMode, id]);
176
+ }, [rootSelector, viewMode, id]);
166
177
  useEffect(() => {
167
- if (parameter !== globals2 && viewMode === "story") {
178
+ const config = pseudoConfig(parameter);
179
+ if (viewMode === "story" && !equals(config, globals2)) {
168
180
  channel.emit(UPDATE_GLOBALS, {
169
- globals: { pseudo: parameter }
181
+ globals: { pseudo: config }
170
182
  });
171
183
  }
172
184
  }, [parameter, viewMode]);
173
185
  useEffect(() => {
174
- if (!canvasElement)
186
+ if (!rootElement)
175
187
  return;
176
188
  const timeout = setTimeout(() => {
177
- applyParameter(canvasElement, globals2 || parameter);
189
+ applyParameter(rootElement, globals2 || pseudoConfig(parameter));
178
190
  shadowHosts.forEach(updateShadowHost);
179
191
  }, 0);
180
192
  return () => clearTimeout(timeout);
181
- }, [canvasElement, globals2, parameter]);
193
+ }, [rootElement, globals2, parameter]);
182
194
  return StoryFn();
183
195
  };
184
196
  var rewriteStyleSheets = (shadowRoot) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "storybook-addon-pseudo-states",
3
- "version": "2.0.2",
3
+ "version": "2.1.0",
4
4
  "description": "CSS pseudo states for Storybook",
5
5
  "keywords": [
6
6
  "storybook-addons",