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 +19 -1
- package/dist/preview.js +20 -8
- package/dist/preview.mjs +20 -8
- package/package.json +1 -1
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
|
|
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
|
-
|
|
210
|
+
const config = pseudoConfig(parameter);
|
|
211
|
+
if (viewMode === "story" && !equals(config, globals2)) {
|
|
200
212
|
channel.emit(import_core_events.UPDATE_GLOBALS, {
|
|
201
|
-
globals: { pseudo:
|
|
213
|
+
globals: { pseudo: config }
|
|
202
214
|
});
|
|
203
215
|
}
|
|
204
216
|
}, [parameter, viewMode]);
|
|
205
217
|
(0, import_preview_api.useEffect)(() => {
|
|
206
|
-
if (!
|
|
218
|
+
if (!rootElement)
|
|
207
219
|
return;
|
|
208
220
|
const timeout = setTimeout(() => {
|
|
209
|
-
applyParameter(
|
|
221
|
+
applyParameter(rootElement, globals2 || pseudoConfig(parameter));
|
|
210
222
|
shadowHosts.forEach(updateShadowHost);
|
|
211
223
|
}, 0);
|
|
212
224
|
return () => clearTimeout(timeout);
|
|
213
|
-
}, [
|
|
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
|
|
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
|
-
|
|
178
|
+
const config = pseudoConfig(parameter);
|
|
179
|
+
if (viewMode === "story" && !equals(config, globals2)) {
|
|
168
180
|
channel.emit(UPDATE_GLOBALS, {
|
|
169
|
-
globals: { pseudo:
|
|
181
|
+
globals: { pseudo: config }
|
|
170
182
|
});
|
|
171
183
|
}
|
|
172
184
|
}, [parameter, viewMode]);
|
|
173
185
|
useEffect(() => {
|
|
174
|
-
if (!
|
|
186
|
+
if (!rootElement)
|
|
175
187
|
return;
|
|
176
188
|
const timeout = setTimeout(() => {
|
|
177
|
-
applyParameter(
|
|
189
|
+
applyParameter(rootElement, globals2 || pseudoConfig(parameter));
|
|
178
190
|
shadowHosts.forEach(updateShadowHost);
|
|
179
191
|
}, 0);
|
|
180
192
|
return () => clearTimeout(timeout);
|
|
181
|
-
}, [
|
|
193
|
+
}, [rootElement, globals2, parameter]);
|
|
182
194
|
return StoryFn();
|
|
183
195
|
};
|
|
184
196
|
var rewriteStyleSheets = (shadowRoot) => {
|