storybook-addon-pseudo-states 2.0.1 → 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/{chunk-A7FPDXSC.mjs → chunk-OZNRRAVT.mjs} +2 -0
- package/dist/manager.js +19 -7
- package/dist/manager.mjs +20 -8
- package/dist/preview.d.ts +4 -1
- package/dist/preview.js +31 -15
- package/dist/preview.mjs +26 -11
- 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
|
+
```
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// src/constants.ts
|
|
2
2
|
var ADDON_ID = "storybook/pseudo-states";
|
|
3
3
|
var TOOL_ID = `${ADDON_ID}/tool`;
|
|
4
|
+
var PARAM_KEY = "pseudo";
|
|
4
5
|
var EXCLUDED_PSEUDO_ELEMENTS = ["::-webkit-scrollbar-thumb"];
|
|
5
6
|
var PSEUDO_STATES = {
|
|
6
7
|
hover: "hover",
|
|
@@ -16,6 +17,7 @@ var PSEUDO_STATES = {
|
|
|
16
17
|
export {
|
|
17
18
|
ADDON_ID,
|
|
18
19
|
TOOL_ID,
|
|
20
|
+
PARAM_KEY,
|
|
19
21
|
EXCLUDED_PSEUDO_ELEMENTS,
|
|
20
22
|
PSEUDO_STATES
|
|
21
23
|
};
|
package/dist/manager.js
CHANGED
|
@@ -24,6 +24,7 @@ var import_manager_api2 = require("@storybook/manager-api");
|
|
|
24
24
|
// src/constants.ts
|
|
25
25
|
var ADDON_ID = "storybook/pseudo-states";
|
|
26
26
|
var TOOL_ID = `${ADDON_ID}/tool`;
|
|
27
|
+
var PARAM_KEY = "pseudo";
|
|
27
28
|
var PSEUDO_STATES = {
|
|
28
29
|
hover: "hover",
|
|
29
30
|
active: "active",
|
|
@@ -49,14 +50,25 @@ var LinkIcon = (0, import_theming.styled)(import_components.Icons)(({ active })
|
|
|
49
50
|
}));
|
|
50
51
|
var options = Object.keys(PSEUDO_STATES).sort();
|
|
51
52
|
var PseudoStateTool = () => {
|
|
52
|
-
const [
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
53
|
+
const [globals, updateGlobals] = (0, import_manager_api.useGlobals)();
|
|
54
|
+
const pseudo = globals[PARAM_KEY];
|
|
55
|
+
const isActive = (0, import_react.useCallback)(
|
|
56
|
+
(option) => {
|
|
57
|
+
if (!pseudo)
|
|
58
|
+
return false;
|
|
59
|
+
return pseudo[option] === true;
|
|
60
|
+
},
|
|
61
|
+
[pseudo]
|
|
62
|
+
);
|
|
58
63
|
const toggleOption = (0, import_react.useCallback)(
|
|
59
|
-
(option) => () =>
|
|
64
|
+
(option) => () => {
|
|
65
|
+
updateGlobals({
|
|
66
|
+
[PARAM_KEY]: {
|
|
67
|
+
...pseudo,
|
|
68
|
+
[option]: !isActive(option)
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
},
|
|
60
72
|
[pseudo]
|
|
61
73
|
);
|
|
62
74
|
return /* @__PURE__ */ import_react.default.createElement(
|
package/dist/manager.mjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ADDON_ID,
|
|
3
|
+
PARAM_KEY,
|
|
3
4
|
PSEUDO_STATES,
|
|
4
5
|
TOOL_ID
|
|
5
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-OZNRRAVT.mjs";
|
|
6
7
|
|
|
7
8
|
// src/manager.ts
|
|
8
9
|
import { addons, types } from "@storybook/manager-api";
|
|
@@ -21,14 +22,25 @@ var LinkIcon = styled(Icons)(({ active }) => ({
|
|
|
21
22
|
}));
|
|
22
23
|
var options = Object.keys(PSEUDO_STATES).sort();
|
|
23
24
|
var PseudoStateTool = () => {
|
|
24
|
-
const [
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
const [globals, updateGlobals] = useGlobals();
|
|
26
|
+
const pseudo = globals[PARAM_KEY];
|
|
27
|
+
const isActive = useCallback(
|
|
28
|
+
(option) => {
|
|
29
|
+
if (!pseudo)
|
|
30
|
+
return false;
|
|
31
|
+
return pseudo[option] === true;
|
|
32
|
+
},
|
|
33
|
+
[pseudo]
|
|
34
|
+
);
|
|
30
35
|
const toggleOption = useCallback(
|
|
31
|
-
(option) => () =>
|
|
36
|
+
(option) => () => {
|
|
37
|
+
updateGlobals({
|
|
38
|
+
[PARAM_KEY]: {
|
|
39
|
+
...pseudo,
|
|
40
|
+
[option]: !isActive(option)
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
},
|
|
32
44
|
[pseudo]
|
|
33
45
|
);
|
|
34
46
|
return /* @__PURE__ */ React.createElement(
|
package/dist/preview.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import * as _storybook_types from '@storybook/types';
|
|
2
2
|
|
|
3
3
|
declare const decorators: _storybook_types.DecoratorFunction<_storybook_types.Renderer, _storybook_types.Args>[];
|
|
4
|
+
declare const globals: {
|
|
5
|
+
pseudo: boolean;
|
|
6
|
+
};
|
|
4
7
|
|
|
5
|
-
export { decorators };
|
|
8
|
+
export { decorators, globals };
|
package/dist/preview.js
CHANGED
|
@@ -20,17 +20,15 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/preview.ts
|
|
21
21
|
var preview_exports = {};
|
|
22
22
|
__export(preview_exports, {
|
|
23
|
-
decorators: () => decorators
|
|
23
|
+
decorators: () => decorators,
|
|
24
|
+
globals: () => globals
|
|
24
25
|
});
|
|
25
26
|
module.exports = __toCommonJS(preview_exports);
|
|
26
27
|
|
|
27
|
-
// src/preview/withPseudoState.ts
|
|
28
|
-
var import_core_events = require("@storybook/core-events");
|
|
29
|
-
var import_preview_api = require("@storybook/preview-api");
|
|
30
|
-
|
|
31
28
|
// src/constants.ts
|
|
32
29
|
var ADDON_ID = "storybook/pseudo-states";
|
|
33
30
|
var TOOL_ID = `${ADDON_ID}/tool`;
|
|
31
|
+
var PARAM_KEY = "pseudo";
|
|
34
32
|
var EXCLUDED_PSEUDO_ELEMENTS = ["::-webkit-scrollbar-thumb"];
|
|
35
33
|
var PSEUDO_STATES = {
|
|
36
34
|
hover: "hover",
|
|
@@ -43,6 +41,10 @@ var PSEUDO_STATES = {
|
|
|
43
41
|
target: "target"
|
|
44
42
|
};
|
|
45
43
|
|
|
44
|
+
// src/preview/withPseudoState.ts
|
|
45
|
+
var import_core_events = require("@storybook/core-events");
|
|
46
|
+
var import_preview_api = require("@storybook/preview-api");
|
|
47
|
+
|
|
46
48
|
// src/preview/splitSelectors.ts
|
|
47
49
|
var isAtRule = (selector) => selector.indexOf("@") === 0;
|
|
48
50
|
var splitSelectors = (selectors) => {
|
|
@@ -156,7 +158,7 @@ var applyClasses = (element, classnames) => {
|
|
|
156
158
|
Object.values(PSEUDO_STATES).forEach((state) => element.classList.remove(`pseudo-${state}`));
|
|
157
159
|
classnames.forEach((classname) => element.classList.add(classname));
|
|
158
160
|
};
|
|
159
|
-
var applyParameter = (rootElement, parameter) => {
|
|
161
|
+
var applyParameter = (rootElement, parameter = {}) => {
|
|
160
162
|
const map = /* @__PURE__ */ new Map([[rootElement, /* @__PURE__ */ new Set()]]);
|
|
161
163
|
const add = (target, state) => map.set(target, /* @__PURE__ */ new Set([...map.get(target) || [], state]));
|
|
162
164
|
Object.entries(parameter || {}).forEach(([state, value]) => {
|
|
@@ -184,31 +186,43 @@ var updateShadowHost = (shadowHost) => {
|
|
|
184
186
|
}
|
|
185
187
|
applyClasses(shadowHost, classnames);
|
|
186
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
|
+
);
|
|
187
196
|
var withPseudoState = (StoryFn, { viewMode, parameters, id, globals: globalsArgs }) => {
|
|
188
197
|
const { pseudo: parameter } = parameters;
|
|
189
|
-
const { pseudo:
|
|
190
|
-
const
|
|
198
|
+
const { pseudo: globals2 } = globalsArgs;
|
|
199
|
+
const { rootSelector } = parameter || {};
|
|
200
|
+
const rootElement = (0, import_preview_api.useMemo)(() => {
|
|
201
|
+
if (rootSelector) {
|
|
202
|
+
return document.querySelector(rootSelector);
|
|
203
|
+
}
|
|
191
204
|
if (viewMode === "docs") {
|
|
192
205
|
return document.getElementById(`story--${id}`);
|
|
193
206
|
}
|
|
194
207
|
return document.getElementById("storybook-root") || document.getElementById("root");
|
|
195
|
-
}, [viewMode, id]);
|
|
208
|
+
}, [rootSelector, viewMode, id]);
|
|
196
209
|
(0, import_preview_api.useEffect)(() => {
|
|
197
|
-
|
|
210
|
+
const config = pseudoConfig(parameter);
|
|
211
|
+
if (viewMode === "story" && !equals(config, globals2)) {
|
|
198
212
|
channel.emit(import_core_events.UPDATE_GLOBALS, {
|
|
199
|
-
globals: { pseudo:
|
|
213
|
+
globals: { pseudo: config }
|
|
200
214
|
});
|
|
201
215
|
}
|
|
202
216
|
}, [parameter, viewMode]);
|
|
203
217
|
(0, import_preview_api.useEffect)(() => {
|
|
204
|
-
if (!
|
|
218
|
+
if (!rootElement)
|
|
205
219
|
return;
|
|
206
220
|
const timeout = setTimeout(() => {
|
|
207
|
-
applyParameter(
|
|
221
|
+
applyParameter(rootElement, globals2 || pseudoConfig(parameter));
|
|
208
222
|
shadowHosts.forEach(updateShadowHost);
|
|
209
223
|
}, 0);
|
|
210
224
|
return () => clearTimeout(timeout);
|
|
211
|
-
}, [
|
|
225
|
+
}, [rootElement, globals2, parameter]);
|
|
212
226
|
return StoryFn();
|
|
213
227
|
};
|
|
214
228
|
var rewriteStyleSheets = (shadowRoot) => {
|
|
@@ -234,7 +248,9 @@ if (Element.prototype.attachShadow) {
|
|
|
234
248
|
|
|
235
249
|
// src/preview.ts
|
|
236
250
|
var decorators = [withPseudoState];
|
|
251
|
+
var globals = { [PARAM_KEY]: false };
|
|
237
252
|
// Annotate the CommonJS export names for ESM import in node:
|
|
238
253
|
0 && (module.exports = {
|
|
239
|
-
decorators
|
|
254
|
+
decorators,
|
|
255
|
+
globals
|
|
240
256
|
});
|
package/dist/preview.mjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
EXCLUDED_PSEUDO_ELEMENTS,
|
|
3
|
+
PARAM_KEY,
|
|
3
4
|
PSEUDO_STATES
|
|
4
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-OZNRRAVT.mjs";
|
|
5
6
|
|
|
6
7
|
// src/preview/withPseudoState.ts
|
|
7
8
|
import {
|
|
@@ -125,7 +126,7 @@ var applyClasses = (element, classnames) => {
|
|
|
125
126
|
Object.values(PSEUDO_STATES).forEach((state) => element.classList.remove(`pseudo-${state}`));
|
|
126
127
|
classnames.forEach((classname) => element.classList.add(classname));
|
|
127
128
|
};
|
|
128
|
-
var applyParameter = (rootElement, parameter) => {
|
|
129
|
+
var applyParameter = (rootElement, parameter = {}) => {
|
|
129
130
|
const map = /* @__PURE__ */ new Map([[rootElement, /* @__PURE__ */ new Set()]]);
|
|
130
131
|
const add = (target, state) => map.set(target, /* @__PURE__ */ new Set([...map.get(target) || [], state]));
|
|
131
132
|
Object.entries(parameter || {}).forEach(([state, value]) => {
|
|
@@ -153,31 +154,43 @@ var updateShadowHost = (shadowHost) => {
|
|
|
153
154
|
}
|
|
154
155
|
applyClasses(shadowHost, classnames);
|
|
155
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
|
+
);
|
|
156
164
|
var withPseudoState = (StoryFn, { viewMode, parameters, id, globals: globalsArgs }) => {
|
|
157
165
|
const { pseudo: parameter } = parameters;
|
|
158
|
-
const { pseudo:
|
|
159
|
-
const
|
|
166
|
+
const { pseudo: globals2 } = globalsArgs;
|
|
167
|
+
const { rootSelector } = parameter || {};
|
|
168
|
+
const rootElement = useMemo(() => {
|
|
169
|
+
if (rootSelector) {
|
|
170
|
+
return document.querySelector(rootSelector);
|
|
171
|
+
}
|
|
160
172
|
if (viewMode === "docs") {
|
|
161
173
|
return document.getElementById(`story--${id}`);
|
|
162
174
|
}
|
|
163
175
|
return document.getElementById("storybook-root") || document.getElementById("root");
|
|
164
|
-
}, [viewMode, id]);
|
|
176
|
+
}, [rootSelector, viewMode, id]);
|
|
165
177
|
useEffect(() => {
|
|
166
|
-
|
|
178
|
+
const config = pseudoConfig(parameter);
|
|
179
|
+
if (viewMode === "story" && !equals(config, globals2)) {
|
|
167
180
|
channel.emit(UPDATE_GLOBALS, {
|
|
168
|
-
globals: { pseudo:
|
|
181
|
+
globals: { pseudo: config }
|
|
169
182
|
});
|
|
170
183
|
}
|
|
171
184
|
}, [parameter, viewMode]);
|
|
172
185
|
useEffect(() => {
|
|
173
|
-
if (!
|
|
186
|
+
if (!rootElement)
|
|
174
187
|
return;
|
|
175
188
|
const timeout = setTimeout(() => {
|
|
176
|
-
applyParameter(
|
|
189
|
+
applyParameter(rootElement, globals2 || pseudoConfig(parameter));
|
|
177
190
|
shadowHosts.forEach(updateShadowHost);
|
|
178
191
|
}, 0);
|
|
179
192
|
return () => clearTimeout(timeout);
|
|
180
|
-
}, [
|
|
193
|
+
}, [rootElement, globals2, parameter]);
|
|
181
194
|
return StoryFn();
|
|
182
195
|
};
|
|
183
196
|
var rewriteStyleSheets = (shadowRoot) => {
|
|
@@ -203,6 +216,8 @@ if (Element.prototype.attachShadow) {
|
|
|
203
216
|
|
|
204
217
|
// src/preview.ts
|
|
205
218
|
var decorators = [withPseudoState];
|
|
219
|
+
var globals = { [PARAM_KEY]: false };
|
|
206
220
|
export {
|
|
207
|
-
decorators
|
|
221
|
+
decorators,
|
|
222
|
+
globals
|
|
208
223
|
};
|