storybook-addon-pseudo-states 2.1.3-next.1 → 2.2.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/.babelrc.js +4 -0
- package/dist/chunk-U5XMEK5H.mjs +24 -0
- package/dist/index.d.mts +3 -0
- package/dist/index.js +28 -6
- package/dist/index.mjs +8 -5
- package/dist/manager.d.mts +2 -0
- package/dist/manager.d.ts +1 -1
- package/dist/manager.js +113 -10
- package/dist/manager.mjs +83 -7
- package/dist/preview.d.mts +8 -0
- package/dist/preview.js +325 -8
- package/dist/preview.mjs +295 -6
- package/package.json +22 -20
- package/dist/index.js.map +0 -1
- package/dist/index.mjs.map +0 -1
- package/dist/manager.js.map +0 -1
- package/dist/manager.mjs.map +0 -1
- package/dist/preview.js.map +0 -1
- package/dist/preview.mjs.map +0 -1
package/.babelrc.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// src/constants.ts
|
|
2
|
+
var ADDON_ID = "storybook/pseudo-states";
|
|
3
|
+
var TOOL_ID = `${ADDON_ID}/tool`;
|
|
4
|
+
var PARAM_KEY = "pseudo";
|
|
5
|
+
var EXCLUDED_PSEUDO_ELEMENTS = ["::-webkit-scrollbar-thumb", "::-webkit-slider-thumb"];
|
|
6
|
+
var PSEUDO_STATES = {
|
|
7
|
+
hover: "hover",
|
|
8
|
+
active: "active",
|
|
9
|
+
focusVisible: "focus-visible",
|
|
10
|
+
focusWithin: "focus-within",
|
|
11
|
+
focus: "focus",
|
|
12
|
+
// must come after its alternatives
|
|
13
|
+
visited: "visited",
|
|
14
|
+
link: "link",
|
|
15
|
+
target: "target"
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export {
|
|
19
|
+
ADDON_ID,
|
|
20
|
+
TOOL_ID,
|
|
21
|
+
PARAM_KEY,
|
|
22
|
+
EXCLUDED_PSEUDO_ELEMENTS,
|
|
23
|
+
PSEUDO_STATES
|
|
24
|
+
};
|
package/dist/index.d.mts
ADDED
package/dist/index.js
CHANGED
|
@@ -1,7 +1,29 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
2
19
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var src_exports = {};
|
|
22
|
+
__export(src_exports, {
|
|
23
|
+
default: () => src_default
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(src_exports);
|
|
26
|
+
if (module && module.hot && module.hot.decline) {
|
|
27
|
+
module.hot.decline();
|
|
28
|
+
}
|
|
29
|
+
var src_default = {};
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
// src/index.ts
|
|
2
|
+
if (module && module.hot && module.hot.decline) {
|
|
3
|
+
module.hot.decline();
|
|
4
|
+
}
|
|
5
|
+
var src_default = {};
|
|
6
|
+
export {
|
|
7
|
+
src_default as default
|
|
8
|
+
};
|
package/dist/manager.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
|
|
2
|
-
export {
|
|
2
|
+
export { }
|
package/dist/manager.js
CHANGED
|
@@ -1,14 +1,117 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
+
for (let key of __getOwnPropNames(from))
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
12
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
13
|
+
}
|
|
14
|
+
return to;
|
|
15
|
+
};
|
|
16
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
17
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
18
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
19
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
20
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
21
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
|
+
mod
|
|
23
|
+
));
|
|
2
24
|
|
|
3
|
-
|
|
4
|
-
var
|
|
5
|
-
var components = require('@storybook/components');
|
|
6
|
-
var theming = require('@storybook/theming');
|
|
25
|
+
// src/manager.ts
|
|
26
|
+
var import_manager_api2 = require("@storybook/manager-api");
|
|
7
27
|
|
|
8
|
-
|
|
28
|
+
// src/constants.ts
|
|
29
|
+
var ADDON_ID = "storybook/pseudo-states";
|
|
30
|
+
var TOOL_ID = `${ADDON_ID}/tool`;
|
|
31
|
+
var PARAM_KEY = "pseudo";
|
|
32
|
+
var PSEUDO_STATES = {
|
|
33
|
+
hover: "hover",
|
|
34
|
+
active: "active",
|
|
35
|
+
focusVisible: "focus-visible",
|
|
36
|
+
focusWithin: "focus-within",
|
|
37
|
+
focus: "focus",
|
|
38
|
+
// must come after its alternatives
|
|
39
|
+
visited: "visited",
|
|
40
|
+
link: "link",
|
|
41
|
+
target: "target"
|
|
42
|
+
};
|
|
9
43
|
|
|
10
|
-
|
|
44
|
+
// src/manager/PseudoStateTool.tsx
|
|
45
|
+
var import_react = __toESM(require("react"));
|
|
46
|
+
var import_components = require("@storybook/components");
|
|
47
|
+
var import_manager_api = require("@storybook/manager-api");
|
|
48
|
+
var import_theming = require("@storybook/theming");
|
|
49
|
+
var LinkTitle = import_theming.styled.span(({ active }) => ({
|
|
50
|
+
color: active ? import_theming.color.secondary : "inherit"
|
|
51
|
+
}));
|
|
52
|
+
var LinkIcon = (0, import_theming.styled)(import_components.Icons)(({ active }) => ({
|
|
53
|
+
opacity: active ? 1 : 0,
|
|
54
|
+
path: { fill: active ? import_theming.color.secondary : "inherit" }
|
|
55
|
+
}));
|
|
56
|
+
var options = Object.keys(PSEUDO_STATES).sort();
|
|
57
|
+
var PseudoStateTool = () => {
|
|
58
|
+
const [globals, updateGlobals] = (0, import_manager_api.useGlobals)();
|
|
59
|
+
const pseudo = globals[PARAM_KEY];
|
|
60
|
+
const isActive = (0, import_react.useCallback)(
|
|
61
|
+
(option) => {
|
|
62
|
+
if (!pseudo)
|
|
63
|
+
return false;
|
|
64
|
+
return pseudo[option] === true;
|
|
65
|
+
},
|
|
66
|
+
[pseudo]
|
|
67
|
+
);
|
|
68
|
+
const toggleOption = (0, import_react.useCallback)(
|
|
69
|
+
(option) => () => {
|
|
70
|
+
updateGlobals({
|
|
71
|
+
[PARAM_KEY]: {
|
|
72
|
+
...pseudo,
|
|
73
|
+
[option]: !isActive(option)
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
},
|
|
77
|
+
[pseudo]
|
|
78
|
+
);
|
|
79
|
+
return /* @__PURE__ */ import_react.default.createElement(
|
|
80
|
+
import_components.WithTooltip,
|
|
81
|
+
{
|
|
82
|
+
placement: "top",
|
|
83
|
+
trigger: "click",
|
|
84
|
+
tooltip: () => /* @__PURE__ */ import_react.default.createElement(
|
|
85
|
+
import_components.TooltipLinkList,
|
|
86
|
+
{
|
|
87
|
+
links: options.map((option) => ({
|
|
88
|
+
id: option,
|
|
89
|
+
title: /* @__PURE__ */ import_react.default.createElement(LinkTitle, { active: isActive(option) }, ":", PSEUDO_STATES[option]),
|
|
90
|
+
right: /* @__PURE__ */ import_react.default.createElement(LinkIcon, { icon: "check", width: 12, height: 12, active: isActive(option) }),
|
|
91
|
+
onClick: toggleOption(option),
|
|
92
|
+
active: isActive(option)
|
|
93
|
+
}))
|
|
94
|
+
}
|
|
95
|
+
)
|
|
96
|
+
},
|
|
97
|
+
/* @__PURE__ */ import_react.default.createElement(
|
|
98
|
+
import_components.IconButton,
|
|
99
|
+
{
|
|
100
|
+
key: "pseudo-state",
|
|
101
|
+
title: "Select CSS pseudo states",
|
|
102
|
+
active: options.some(isActive)
|
|
103
|
+
},
|
|
104
|
+
/* @__PURE__ */ import_react.default.createElement(import_components.Icons, { icon: "button" })
|
|
105
|
+
)
|
|
106
|
+
);
|
|
107
|
+
};
|
|
11
108
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
109
|
+
// src/manager.ts
|
|
110
|
+
import_manager_api2.addons.register(ADDON_ID, () => {
|
|
111
|
+
import_manager_api2.addons.add(TOOL_ID, {
|
|
112
|
+
type: import_manager_api2.types.TOOL,
|
|
113
|
+
title: "CSS pseudo states",
|
|
114
|
+
match: ({ viewMode }) => viewMode === "story",
|
|
115
|
+
render: PseudoStateTool
|
|
116
|
+
});
|
|
117
|
+
});
|
package/dist/manager.mjs
CHANGED
|
@@ -1,8 +1,84 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import {
|
|
2
|
+
ADDON_ID,
|
|
3
|
+
PARAM_KEY,
|
|
4
|
+
PSEUDO_STATES,
|
|
5
|
+
TOOL_ID
|
|
6
|
+
} from "./chunk-U5XMEK5H.mjs";
|
|
5
7
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
// src/manager.ts
|
|
9
|
+
import { addons, types } from "@storybook/manager-api";
|
|
10
|
+
|
|
11
|
+
// src/manager/PseudoStateTool.tsx
|
|
12
|
+
import React, { useCallback } from "react";
|
|
13
|
+
import { Icons, IconButton, WithTooltip, TooltipLinkList } from "@storybook/components";
|
|
14
|
+
import { useGlobals } from "@storybook/manager-api";
|
|
15
|
+
import { styled, color } from "@storybook/theming";
|
|
16
|
+
var LinkTitle = styled.span(({ active }) => ({
|
|
17
|
+
color: active ? color.secondary : "inherit"
|
|
18
|
+
}));
|
|
19
|
+
var LinkIcon = styled(Icons)(({ active }) => ({
|
|
20
|
+
opacity: active ? 1 : 0,
|
|
21
|
+
path: { fill: active ? color.secondary : "inherit" }
|
|
22
|
+
}));
|
|
23
|
+
var options = Object.keys(PSEUDO_STATES).sort();
|
|
24
|
+
var PseudoStateTool = () => {
|
|
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
|
+
);
|
|
35
|
+
const toggleOption = useCallback(
|
|
36
|
+
(option) => () => {
|
|
37
|
+
updateGlobals({
|
|
38
|
+
[PARAM_KEY]: {
|
|
39
|
+
...pseudo,
|
|
40
|
+
[option]: !isActive(option)
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
},
|
|
44
|
+
[pseudo]
|
|
45
|
+
);
|
|
46
|
+
return /* @__PURE__ */ React.createElement(
|
|
47
|
+
WithTooltip,
|
|
48
|
+
{
|
|
49
|
+
placement: "top",
|
|
50
|
+
trigger: "click",
|
|
51
|
+
tooltip: () => /* @__PURE__ */ React.createElement(
|
|
52
|
+
TooltipLinkList,
|
|
53
|
+
{
|
|
54
|
+
links: options.map((option) => ({
|
|
55
|
+
id: option,
|
|
56
|
+
title: /* @__PURE__ */ React.createElement(LinkTitle, { active: isActive(option) }, ":", PSEUDO_STATES[option]),
|
|
57
|
+
right: /* @__PURE__ */ React.createElement(LinkIcon, { icon: "check", width: 12, height: 12, active: isActive(option) }),
|
|
58
|
+
onClick: toggleOption(option),
|
|
59
|
+
active: isActive(option)
|
|
60
|
+
}))
|
|
61
|
+
}
|
|
62
|
+
)
|
|
63
|
+
},
|
|
64
|
+
/* @__PURE__ */ React.createElement(
|
|
65
|
+
IconButton,
|
|
66
|
+
{
|
|
67
|
+
key: "pseudo-state",
|
|
68
|
+
title: "Select CSS pseudo states",
|
|
69
|
+
active: options.some(isActive)
|
|
70
|
+
},
|
|
71
|
+
/* @__PURE__ */ React.createElement(Icons, { icon: "button" })
|
|
72
|
+
)
|
|
73
|
+
);
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// src/manager.ts
|
|
77
|
+
addons.register(ADDON_ID, () => {
|
|
78
|
+
addons.add(TOOL_ID, {
|
|
79
|
+
type: types.TOOL,
|
|
80
|
+
title: "CSS pseudo states",
|
|
81
|
+
match: ({ viewMode }) => viewMode === "story",
|
|
82
|
+
render: PseudoStateTool
|
|
83
|
+
});
|
|
84
|
+
});
|
package/dist/preview.js
CHANGED
|
@@ -1,11 +1,328 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
2
19
|
|
|
3
|
-
|
|
4
|
-
var
|
|
20
|
+
// src/preview.ts
|
|
21
|
+
var preview_exports = {};
|
|
22
|
+
__export(preview_exports, {
|
|
23
|
+
decorators: () => decorators,
|
|
24
|
+
globals: () => globals
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(preview_exports);
|
|
5
27
|
|
|
6
|
-
|
|
28
|
+
// src/constants.ts
|
|
29
|
+
var ADDON_ID = "storybook/pseudo-states";
|
|
30
|
+
var TOOL_ID = `${ADDON_ID}/tool`;
|
|
31
|
+
var PARAM_KEY = "pseudo";
|
|
32
|
+
var EXCLUDED_PSEUDO_ELEMENTS = ["::-webkit-scrollbar-thumb", "::-webkit-slider-thumb"];
|
|
33
|
+
var PSEUDO_STATES = {
|
|
34
|
+
hover: "hover",
|
|
35
|
+
active: "active",
|
|
36
|
+
focusVisible: "focus-visible",
|
|
37
|
+
focusWithin: "focus-within",
|
|
38
|
+
focus: "focus",
|
|
39
|
+
// must come after its alternatives
|
|
40
|
+
visited: "visited",
|
|
41
|
+
link: "link",
|
|
42
|
+
target: "target"
|
|
43
|
+
};
|
|
7
44
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
45
|
+
// src/preview/withPseudoState.ts
|
|
46
|
+
var import_core_events = require("@storybook/core-events");
|
|
47
|
+
var import_preview_api = require("@storybook/preview-api");
|
|
48
|
+
|
|
49
|
+
// src/preview/splitSelectors.ts
|
|
50
|
+
var isAtRule = (selector) => selector.indexOf("@") === 0;
|
|
51
|
+
var splitSelectors = (selectors) => {
|
|
52
|
+
if (isAtRule(selectors))
|
|
53
|
+
return [selectors];
|
|
54
|
+
let result = [];
|
|
55
|
+
let parentheses = 0;
|
|
56
|
+
let brackets = 0;
|
|
57
|
+
let selector = "";
|
|
58
|
+
for (let i = 0, len = selectors.length; i < len; i++) {
|
|
59
|
+
const char = selectors[i];
|
|
60
|
+
if (char === "(") {
|
|
61
|
+
parentheses += 1;
|
|
62
|
+
} else if (char === ")") {
|
|
63
|
+
parentheses -= 1;
|
|
64
|
+
} else if (char === "[") {
|
|
65
|
+
brackets += 1;
|
|
66
|
+
} else if (char === "]") {
|
|
67
|
+
brackets -= 1;
|
|
68
|
+
} else if (char === ",") {
|
|
69
|
+
if (!parentheses && !brackets) {
|
|
70
|
+
result.push(selector.trim());
|
|
71
|
+
selector = "";
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
selector += char;
|
|
76
|
+
}
|
|
77
|
+
result.push(selector.trim());
|
|
78
|
+
return result;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// src/preview/rewriteStyleSheet.ts
|
|
82
|
+
var pseudoStates = Object.values(PSEUDO_STATES);
|
|
83
|
+
var matchOne = new RegExp(`:(${pseudoStates.join("|")})`);
|
|
84
|
+
var matchAll = new RegExp(`:(${pseudoStates.join("|")})`, "g");
|
|
85
|
+
var warnings = /* @__PURE__ */ new Set();
|
|
86
|
+
var warnOnce = (message) => {
|
|
87
|
+
if (warnings.has(message))
|
|
88
|
+
return;
|
|
89
|
+
console.warn(message);
|
|
90
|
+
warnings.add(message);
|
|
91
|
+
};
|
|
92
|
+
var isExcludedPseudoElement = (selector, pseudoState) => EXCLUDED_PSEUDO_ELEMENTS.some((element) => selector.endsWith(`${element}:${pseudoState}`));
|
|
93
|
+
var rewriteRule = ({ cssText, selectorText }, shadowRoot) => {
|
|
94
|
+
return cssText.replace(
|
|
95
|
+
selectorText,
|
|
96
|
+
splitSelectors(selectorText).flatMap((selector) => {
|
|
97
|
+
if (selector.includes(".pseudo-")) {
|
|
98
|
+
return [];
|
|
99
|
+
}
|
|
100
|
+
if (!matchOne.test(selector)) {
|
|
101
|
+
return [selector];
|
|
102
|
+
}
|
|
103
|
+
const states = [];
|
|
104
|
+
let plainSelector = selector.replace(matchAll, (_, state) => {
|
|
105
|
+
states.push(state);
|
|
106
|
+
return "";
|
|
107
|
+
});
|
|
108
|
+
const classSelector = states.reduce((acc, state) => {
|
|
109
|
+
if (isExcludedPseudoElement(selector, state))
|
|
110
|
+
return "";
|
|
111
|
+
return acc.replace(new RegExp(`:${state}`, "g"), `.pseudo-${state}`);
|
|
112
|
+
}, selector);
|
|
113
|
+
let ancestorSelector = "";
|
|
114
|
+
const statesAllClassSelectors = states.map((s) => `.pseudo-${s}-all`).join("");
|
|
115
|
+
if (selector.startsWith(":host(")) {
|
|
116
|
+
const matches = selector.match(/^:host\(([^ ]+)\) /);
|
|
117
|
+
if (matches && !matchOne.test(matches[1])) {
|
|
118
|
+
ancestorSelector = `:host(${matches[1]}${statesAllClassSelectors}) ${plainSelector.replace(matches[0], "")}`;
|
|
119
|
+
} else {
|
|
120
|
+
ancestorSelector = states.reduce((acc, state) => {
|
|
121
|
+
if (isExcludedPseudoElement(selector, state))
|
|
122
|
+
return "";
|
|
123
|
+
return acc.replace(new RegExp(`:${state}`, "g"), `.pseudo-${state}-all`);
|
|
124
|
+
}, selector);
|
|
125
|
+
}
|
|
126
|
+
} else if (selector.startsWith("::slotted(") || shadowRoot) {
|
|
127
|
+
if (plainSelector.startsWith("::slotted()")) {
|
|
128
|
+
plainSelector = plainSelector.replace("::slotted()", "::slotted(*)");
|
|
129
|
+
}
|
|
130
|
+
ancestorSelector = `:host(${statesAllClassSelectors}) ${plainSelector}`;
|
|
131
|
+
} else {
|
|
132
|
+
ancestorSelector = `${statesAllClassSelectors} ${plainSelector}`;
|
|
133
|
+
}
|
|
134
|
+
return [selector, classSelector, ancestorSelector].filter(
|
|
135
|
+
(selector2) => selector2 && !selector2.includes(":not()")
|
|
136
|
+
);
|
|
137
|
+
}).join(", ")
|
|
138
|
+
);
|
|
139
|
+
};
|
|
140
|
+
var rewriteStyleSheet = (sheet, shadowRoot) => {
|
|
141
|
+
try {
|
|
142
|
+
const maximumRulesToRewrite = 1e3;
|
|
143
|
+
const count = rewriteRuleContainer(sheet, maximumRulesToRewrite, shadowRoot);
|
|
144
|
+
if (count >= maximumRulesToRewrite) {
|
|
145
|
+
warnOnce("Reached maximum of 1000 pseudo selectors per sheet, skipping the rest.");
|
|
146
|
+
}
|
|
147
|
+
return count > 0;
|
|
148
|
+
} catch (e) {
|
|
149
|
+
if (String(e).includes("cssRules")) {
|
|
150
|
+
warnOnce(`Can't access cssRules, likely due to CORS restrictions: ${sheet.href}`);
|
|
151
|
+
} else {
|
|
152
|
+
console.error(e, sheet.href);
|
|
153
|
+
}
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
var rewriteRuleContainer = (ruleContainer, rewriteLimit, shadowRoot) => {
|
|
158
|
+
let count = 0;
|
|
159
|
+
let index = -1;
|
|
160
|
+
for (const cssRule of ruleContainer.cssRules) {
|
|
161
|
+
index++;
|
|
162
|
+
let numRewritten = 0;
|
|
163
|
+
if (cssRule.__processed) {
|
|
164
|
+
numRewritten = cssRule.__pseudoStatesRewrittenCount;
|
|
165
|
+
} else {
|
|
166
|
+
if ("cssRules" in cssRule && cssRule.cssRules.length) {
|
|
167
|
+
numRewritten = rewriteRuleContainer(cssRule, rewriteLimit - count, shadowRoot);
|
|
168
|
+
} else {
|
|
169
|
+
if (!("selectorText" in cssRule))
|
|
170
|
+
continue;
|
|
171
|
+
const styleRule = cssRule;
|
|
172
|
+
if (matchOne.test(styleRule.selectorText)) {
|
|
173
|
+
const newRule = rewriteRule(styleRule, shadowRoot);
|
|
174
|
+
ruleContainer.deleteRule(index);
|
|
175
|
+
ruleContainer.insertRule(newRule, index);
|
|
176
|
+
numRewritten = 1;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
cssRule.__processed = true;
|
|
180
|
+
cssRule.__pseudoStatesRewrittenCount = numRewritten;
|
|
181
|
+
}
|
|
182
|
+
count += numRewritten;
|
|
183
|
+
if (count >= rewriteLimit) {
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return count;
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
// src/preview/withPseudoState.ts
|
|
191
|
+
var channel = import_preview_api.addons.getChannel();
|
|
192
|
+
var shadowHosts = /* @__PURE__ */ new Set();
|
|
193
|
+
var applyClasses = (element, classnames) => {
|
|
194
|
+
Object.values(PSEUDO_STATES).forEach((state) => {
|
|
195
|
+
element.classList.remove(`pseudo-${state}`);
|
|
196
|
+
element.classList.remove(`pseudo-${state}-all`);
|
|
197
|
+
});
|
|
198
|
+
classnames.forEach((classname) => element.classList.add(classname));
|
|
199
|
+
};
|
|
200
|
+
function querySelectorPiercingShadowDOM(root, selector) {
|
|
201
|
+
const results = [];
|
|
202
|
+
root.querySelectorAll("*").forEach((el) => {
|
|
203
|
+
if (el.shadowRoot) {
|
|
204
|
+
results.push(...querySelectorPiercingShadowDOM(el.shadowRoot, selector));
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
results.push(...root.querySelectorAll(selector).values());
|
|
208
|
+
return results;
|
|
209
|
+
}
|
|
210
|
+
var applyParameter = (rootElement, parameter = {}) => {
|
|
211
|
+
const map = /* @__PURE__ */ new Map([[rootElement, /* @__PURE__ */ new Set()]]);
|
|
212
|
+
const add = (target, state) => map.set(target, /* @__PURE__ */ new Set([...map.get(target) || [], state]));
|
|
213
|
+
Object.entries(parameter || {}).forEach(([state, value]) => {
|
|
214
|
+
if (typeof value === "boolean") {
|
|
215
|
+
if (value)
|
|
216
|
+
add(rootElement, `${state}-all`);
|
|
217
|
+
} else if (typeof value === "string") {
|
|
218
|
+
querySelectorPiercingShadowDOM(rootElement, value).forEach((el) => add(el, state));
|
|
219
|
+
} else if (Array.isArray(value)) {
|
|
220
|
+
value.forEach((sel) => querySelectorPiercingShadowDOM(rootElement, sel).forEach((el) => add(el, state)));
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
map.forEach((states, target) => {
|
|
224
|
+
const classnames = /* @__PURE__ */ new Set();
|
|
225
|
+
states.forEach((key) => {
|
|
226
|
+
const keyWithoutAll = key.replace("-all", "");
|
|
227
|
+
if (PSEUDO_STATES[key]) {
|
|
228
|
+
classnames.add(`pseudo-${PSEUDO_STATES[key]}`);
|
|
229
|
+
} else if (PSEUDO_STATES[keyWithoutAll]) {
|
|
230
|
+
classnames.add(`pseudo-${PSEUDO_STATES[keyWithoutAll]}-all`);
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
applyClasses(target, classnames);
|
|
234
|
+
});
|
|
235
|
+
};
|
|
236
|
+
var updateShadowHost = (shadowHost) => {
|
|
237
|
+
const classnames = /* @__PURE__ */ new Set();
|
|
238
|
+
shadowHost.className.split(" ").filter((classname) => classname.startsWith("pseudo-")).forEach((classname) => classnames.add(classname));
|
|
239
|
+
for (let node = shadowHost.parentNode; node; ) {
|
|
240
|
+
if (node instanceof ShadowRoot) {
|
|
241
|
+
node = node.host;
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
if (node instanceof Element) {
|
|
245
|
+
const element = node;
|
|
246
|
+
if (element.className) {
|
|
247
|
+
element.className.split(" ").filter((classname) => classname.match(/^pseudo-.+-all$/) !== null).forEach((classname) => classnames.add(classname));
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
node = node.parentNode;
|
|
251
|
+
}
|
|
252
|
+
applyClasses(shadowHost, classnames);
|
|
253
|
+
};
|
|
254
|
+
var pseudoConfig = (parameter) => {
|
|
255
|
+
const { rootSelector, ...pseudoStateConfig } = parameter || {};
|
|
256
|
+
return pseudoStateConfig;
|
|
257
|
+
};
|
|
258
|
+
var equals = (a = {}, b = {}) => a !== null && b !== null && Object.keys(a).length === Object.keys(b).length && Object.keys(a).every(
|
|
259
|
+
(key) => JSON.stringify(a[key]) === JSON.stringify(b[key])
|
|
260
|
+
);
|
|
261
|
+
var withPseudoState = (StoryFn, { viewMode, parameters, id, globals: globalsArgs }) => {
|
|
262
|
+
const { pseudo: parameter } = parameters;
|
|
263
|
+
const { pseudo: globals2 } = globalsArgs;
|
|
264
|
+
const { rootSelector } = parameter || {};
|
|
265
|
+
const rootElement = (0, import_preview_api.useMemo)(() => {
|
|
266
|
+
if (rootSelector) {
|
|
267
|
+
return document.querySelector(rootSelector);
|
|
268
|
+
}
|
|
269
|
+
if (viewMode === "docs") {
|
|
270
|
+
return document.getElementById(`story--${id}`);
|
|
271
|
+
}
|
|
272
|
+
return document.getElementById("storybook-root") || // Storybook 7.0+
|
|
273
|
+
document.getElementById("root");
|
|
274
|
+
}, [rootSelector, viewMode, id]);
|
|
275
|
+
(0, import_preview_api.useEffect)(() => {
|
|
276
|
+
const config = pseudoConfig(parameter);
|
|
277
|
+
if (viewMode === "story" && !equals(config, globals2)) {
|
|
278
|
+
channel.emit(import_core_events.UPDATE_GLOBALS, {
|
|
279
|
+
globals: { pseudo: config }
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
}, [parameter, viewMode]);
|
|
283
|
+
(0, import_preview_api.useEffect)(() => {
|
|
284
|
+
if (!rootElement)
|
|
285
|
+
return;
|
|
286
|
+
const timeout = setTimeout(() => {
|
|
287
|
+
applyParameter(rootElement, globals2 || pseudoConfig(parameter));
|
|
288
|
+
shadowHosts.forEach(updateShadowHost);
|
|
289
|
+
}, 0);
|
|
290
|
+
return () => clearTimeout(timeout);
|
|
291
|
+
}, [rootElement, globals2, parameter]);
|
|
292
|
+
return StoryFn();
|
|
293
|
+
};
|
|
294
|
+
var rewriteStyleSheets = (shadowRoot) => {
|
|
295
|
+
let styleSheets = Array.from(shadowRoot ? shadowRoot.styleSheets : document.styleSheets);
|
|
296
|
+
if (shadowRoot?.adoptedStyleSheets?.length)
|
|
297
|
+
styleSheets = shadowRoot.adoptedStyleSheets;
|
|
298
|
+
const rewroteStyles = styleSheets.map((sheet) => rewriteStyleSheet(sheet, shadowRoot)).some(Boolean);
|
|
299
|
+
if (rewroteStyles && shadowRoot && shadowHosts)
|
|
300
|
+
shadowHosts.add(shadowRoot.host);
|
|
301
|
+
};
|
|
302
|
+
channel.on(import_core_events.STORY_CHANGED, () => shadowHosts.clear());
|
|
303
|
+
channel.on(import_core_events.STORY_RENDERED, () => rewriteStyleSheets());
|
|
304
|
+
channel.on(import_core_events.GLOBALS_UPDATED, () => rewriteStyleSheets());
|
|
305
|
+
channel.on(import_core_events.FORCE_RE_RENDER, () => rewriteStyleSheets());
|
|
306
|
+
channel.on(import_core_events.FORCE_REMOUNT, () => rewriteStyleSheets());
|
|
307
|
+
channel.on(import_core_events.DOCS_RENDERED, () => rewriteStyleSheets());
|
|
308
|
+
if (Element.prototype.attachShadow) {
|
|
309
|
+
Element.prototype._attachShadow = Element.prototype.attachShadow;
|
|
310
|
+
Element.prototype.attachShadow = function attachShadow(init) {
|
|
311
|
+
const shadowRoot = this._attachShadow({ ...init, mode: "open" });
|
|
312
|
+
requestAnimationFrame(() => {
|
|
313
|
+
rewriteStyleSheets(shadowRoot);
|
|
314
|
+
if (shadowHosts.has(shadowRoot.host))
|
|
315
|
+
updateShadowHost(shadowRoot.host);
|
|
316
|
+
});
|
|
317
|
+
return shadowRoot;
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// src/preview.ts
|
|
322
|
+
var decorators = [withPseudoState];
|
|
323
|
+
var globals = { [PARAM_KEY]: false };
|
|
324
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
325
|
+
0 && (module.exports = {
|
|
326
|
+
decorators,
|
|
327
|
+
globals
|
|
328
|
+
});
|
package/dist/preview.mjs
CHANGED
|
@@ -1,8 +1,297 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
EXCLUDED_PSEUDO_ELEMENTS,
|
|
3
|
+
PARAM_KEY,
|
|
4
|
+
PSEUDO_STATES
|
|
5
|
+
} from "./chunk-U5XMEK5H.mjs";
|
|
3
6
|
|
|
4
|
-
|
|
7
|
+
// src/preview/withPseudoState.ts
|
|
8
|
+
import {
|
|
9
|
+
DOCS_RENDERED,
|
|
10
|
+
FORCE_REMOUNT,
|
|
11
|
+
FORCE_RE_RENDER,
|
|
12
|
+
GLOBALS_UPDATED,
|
|
13
|
+
STORY_CHANGED,
|
|
14
|
+
STORY_RENDERED,
|
|
15
|
+
UPDATE_GLOBALS
|
|
16
|
+
} from "@storybook/core-events";
|
|
17
|
+
import { addons, useEffect, useMemo } from "@storybook/preview-api";
|
|
5
18
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
19
|
+
// src/preview/splitSelectors.ts
|
|
20
|
+
var isAtRule = (selector) => selector.indexOf("@") === 0;
|
|
21
|
+
var splitSelectors = (selectors) => {
|
|
22
|
+
if (isAtRule(selectors))
|
|
23
|
+
return [selectors];
|
|
24
|
+
let result = [];
|
|
25
|
+
let parentheses = 0;
|
|
26
|
+
let brackets = 0;
|
|
27
|
+
let selector = "";
|
|
28
|
+
for (let i = 0, len = selectors.length; i < len; i++) {
|
|
29
|
+
const char = selectors[i];
|
|
30
|
+
if (char === "(") {
|
|
31
|
+
parentheses += 1;
|
|
32
|
+
} else if (char === ")") {
|
|
33
|
+
parentheses -= 1;
|
|
34
|
+
} else if (char === "[") {
|
|
35
|
+
brackets += 1;
|
|
36
|
+
} else if (char === "]") {
|
|
37
|
+
brackets -= 1;
|
|
38
|
+
} else if (char === ",") {
|
|
39
|
+
if (!parentheses && !brackets) {
|
|
40
|
+
result.push(selector.trim());
|
|
41
|
+
selector = "";
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
selector += char;
|
|
46
|
+
}
|
|
47
|
+
result.push(selector.trim());
|
|
48
|
+
return result;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// src/preview/rewriteStyleSheet.ts
|
|
52
|
+
var pseudoStates = Object.values(PSEUDO_STATES);
|
|
53
|
+
var matchOne = new RegExp(`:(${pseudoStates.join("|")})`);
|
|
54
|
+
var matchAll = new RegExp(`:(${pseudoStates.join("|")})`, "g");
|
|
55
|
+
var warnings = /* @__PURE__ */ new Set();
|
|
56
|
+
var warnOnce = (message) => {
|
|
57
|
+
if (warnings.has(message))
|
|
58
|
+
return;
|
|
59
|
+
console.warn(message);
|
|
60
|
+
warnings.add(message);
|
|
61
|
+
};
|
|
62
|
+
var isExcludedPseudoElement = (selector, pseudoState) => EXCLUDED_PSEUDO_ELEMENTS.some((element) => selector.endsWith(`${element}:${pseudoState}`));
|
|
63
|
+
var rewriteRule = ({ cssText, selectorText }, shadowRoot) => {
|
|
64
|
+
return cssText.replace(
|
|
65
|
+
selectorText,
|
|
66
|
+
splitSelectors(selectorText).flatMap((selector) => {
|
|
67
|
+
if (selector.includes(".pseudo-")) {
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
if (!matchOne.test(selector)) {
|
|
71
|
+
return [selector];
|
|
72
|
+
}
|
|
73
|
+
const states = [];
|
|
74
|
+
let plainSelector = selector.replace(matchAll, (_, state) => {
|
|
75
|
+
states.push(state);
|
|
76
|
+
return "";
|
|
77
|
+
});
|
|
78
|
+
const classSelector = states.reduce((acc, state) => {
|
|
79
|
+
if (isExcludedPseudoElement(selector, state))
|
|
80
|
+
return "";
|
|
81
|
+
return acc.replace(new RegExp(`:${state}`, "g"), `.pseudo-${state}`);
|
|
82
|
+
}, selector);
|
|
83
|
+
let ancestorSelector = "";
|
|
84
|
+
const statesAllClassSelectors = states.map((s) => `.pseudo-${s}-all`).join("");
|
|
85
|
+
if (selector.startsWith(":host(")) {
|
|
86
|
+
const matches = selector.match(/^:host\(([^ ]+)\) /);
|
|
87
|
+
if (matches && !matchOne.test(matches[1])) {
|
|
88
|
+
ancestorSelector = `:host(${matches[1]}${statesAllClassSelectors}) ${plainSelector.replace(matches[0], "")}`;
|
|
89
|
+
} else {
|
|
90
|
+
ancestorSelector = states.reduce((acc, state) => {
|
|
91
|
+
if (isExcludedPseudoElement(selector, state))
|
|
92
|
+
return "";
|
|
93
|
+
return acc.replace(new RegExp(`:${state}`, "g"), `.pseudo-${state}-all`);
|
|
94
|
+
}, selector);
|
|
95
|
+
}
|
|
96
|
+
} else if (selector.startsWith("::slotted(") || shadowRoot) {
|
|
97
|
+
if (plainSelector.startsWith("::slotted()")) {
|
|
98
|
+
plainSelector = plainSelector.replace("::slotted()", "::slotted(*)");
|
|
99
|
+
}
|
|
100
|
+
ancestorSelector = `:host(${statesAllClassSelectors}) ${plainSelector}`;
|
|
101
|
+
} else {
|
|
102
|
+
ancestorSelector = `${statesAllClassSelectors} ${plainSelector}`;
|
|
103
|
+
}
|
|
104
|
+
return [selector, classSelector, ancestorSelector].filter(
|
|
105
|
+
(selector2) => selector2 && !selector2.includes(":not()")
|
|
106
|
+
);
|
|
107
|
+
}).join(", ")
|
|
108
|
+
);
|
|
109
|
+
};
|
|
110
|
+
var rewriteStyleSheet = (sheet, shadowRoot) => {
|
|
111
|
+
try {
|
|
112
|
+
const maximumRulesToRewrite = 1e3;
|
|
113
|
+
const count = rewriteRuleContainer(sheet, maximumRulesToRewrite, shadowRoot);
|
|
114
|
+
if (count >= maximumRulesToRewrite) {
|
|
115
|
+
warnOnce("Reached maximum of 1000 pseudo selectors per sheet, skipping the rest.");
|
|
116
|
+
}
|
|
117
|
+
return count > 0;
|
|
118
|
+
} catch (e) {
|
|
119
|
+
if (String(e).includes("cssRules")) {
|
|
120
|
+
warnOnce(`Can't access cssRules, likely due to CORS restrictions: ${sheet.href}`);
|
|
121
|
+
} else {
|
|
122
|
+
console.error(e, sheet.href);
|
|
123
|
+
}
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
var rewriteRuleContainer = (ruleContainer, rewriteLimit, shadowRoot) => {
|
|
128
|
+
let count = 0;
|
|
129
|
+
let index = -1;
|
|
130
|
+
for (const cssRule of ruleContainer.cssRules) {
|
|
131
|
+
index++;
|
|
132
|
+
let numRewritten = 0;
|
|
133
|
+
if (cssRule.__processed) {
|
|
134
|
+
numRewritten = cssRule.__pseudoStatesRewrittenCount;
|
|
135
|
+
} else {
|
|
136
|
+
if ("cssRules" in cssRule && cssRule.cssRules.length) {
|
|
137
|
+
numRewritten = rewriteRuleContainer(cssRule, rewriteLimit - count, shadowRoot);
|
|
138
|
+
} else {
|
|
139
|
+
if (!("selectorText" in cssRule))
|
|
140
|
+
continue;
|
|
141
|
+
const styleRule = cssRule;
|
|
142
|
+
if (matchOne.test(styleRule.selectorText)) {
|
|
143
|
+
const newRule = rewriteRule(styleRule, shadowRoot);
|
|
144
|
+
ruleContainer.deleteRule(index);
|
|
145
|
+
ruleContainer.insertRule(newRule, index);
|
|
146
|
+
numRewritten = 1;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
cssRule.__processed = true;
|
|
150
|
+
cssRule.__pseudoStatesRewrittenCount = numRewritten;
|
|
151
|
+
}
|
|
152
|
+
count += numRewritten;
|
|
153
|
+
if (count >= rewriteLimit) {
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return count;
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
// src/preview/withPseudoState.ts
|
|
161
|
+
var channel = addons.getChannel();
|
|
162
|
+
var shadowHosts = /* @__PURE__ */ new Set();
|
|
163
|
+
var applyClasses = (element, classnames) => {
|
|
164
|
+
Object.values(PSEUDO_STATES).forEach((state) => {
|
|
165
|
+
element.classList.remove(`pseudo-${state}`);
|
|
166
|
+
element.classList.remove(`pseudo-${state}-all`);
|
|
167
|
+
});
|
|
168
|
+
classnames.forEach((classname) => element.classList.add(classname));
|
|
169
|
+
};
|
|
170
|
+
function querySelectorPiercingShadowDOM(root, selector) {
|
|
171
|
+
const results = [];
|
|
172
|
+
root.querySelectorAll("*").forEach((el) => {
|
|
173
|
+
if (el.shadowRoot) {
|
|
174
|
+
results.push(...querySelectorPiercingShadowDOM(el.shadowRoot, selector));
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
results.push(...root.querySelectorAll(selector).values());
|
|
178
|
+
return results;
|
|
179
|
+
}
|
|
180
|
+
var applyParameter = (rootElement, parameter = {}) => {
|
|
181
|
+
const map = /* @__PURE__ */ new Map([[rootElement, /* @__PURE__ */ new Set()]]);
|
|
182
|
+
const add = (target, state) => map.set(target, /* @__PURE__ */ new Set([...map.get(target) || [], state]));
|
|
183
|
+
Object.entries(parameter || {}).forEach(([state, value]) => {
|
|
184
|
+
if (typeof value === "boolean") {
|
|
185
|
+
if (value)
|
|
186
|
+
add(rootElement, `${state}-all`);
|
|
187
|
+
} else if (typeof value === "string") {
|
|
188
|
+
querySelectorPiercingShadowDOM(rootElement, value).forEach((el) => add(el, state));
|
|
189
|
+
} else if (Array.isArray(value)) {
|
|
190
|
+
value.forEach((sel) => querySelectorPiercingShadowDOM(rootElement, sel).forEach((el) => add(el, state)));
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
map.forEach((states, target) => {
|
|
194
|
+
const classnames = /* @__PURE__ */ new Set();
|
|
195
|
+
states.forEach((key) => {
|
|
196
|
+
const keyWithoutAll = key.replace("-all", "");
|
|
197
|
+
if (PSEUDO_STATES[key]) {
|
|
198
|
+
classnames.add(`pseudo-${PSEUDO_STATES[key]}`);
|
|
199
|
+
} else if (PSEUDO_STATES[keyWithoutAll]) {
|
|
200
|
+
classnames.add(`pseudo-${PSEUDO_STATES[keyWithoutAll]}-all`);
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
applyClasses(target, classnames);
|
|
204
|
+
});
|
|
205
|
+
};
|
|
206
|
+
var updateShadowHost = (shadowHost) => {
|
|
207
|
+
const classnames = /* @__PURE__ */ new Set();
|
|
208
|
+
shadowHost.className.split(" ").filter((classname) => classname.startsWith("pseudo-")).forEach((classname) => classnames.add(classname));
|
|
209
|
+
for (let node = shadowHost.parentNode; node; ) {
|
|
210
|
+
if (node instanceof ShadowRoot) {
|
|
211
|
+
node = node.host;
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
if (node instanceof Element) {
|
|
215
|
+
const element = node;
|
|
216
|
+
if (element.className) {
|
|
217
|
+
element.className.split(" ").filter((classname) => classname.match(/^pseudo-.+-all$/) !== null).forEach((classname) => classnames.add(classname));
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
node = node.parentNode;
|
|
221
|
+
}
|
|
222
|
+
applyClasses(shadowHost, classnames);
|
|
223
|
+
};
|
|
224
|
+
var pseudoConfig = (parameter) => {
|
|
225
|
+
const { rootSelector, ...pseudoStateConfig } = parameter || {};
|
|
226
|
+
return pseudoStateConfig;
|
|
227
|
+
};
|
|
228
|
+
var equals = (a = {}, b = {}) => a !== null && b !== null && Object.keys(a).length === Object.keys(b).length && Object.keys(a).every(
|
|
229
|
+
(key) => JSON.stringify(a[key]) === JSON.stringify(b[key])
|
|
230
|
+
);
|
|
231
|
+
var withPseudoState = (StoryFn, { viewMode, parameters, id, globals: globalsArgs }) => {
|
|
232
|
+
const { pseudo: parameter } = parameters;
|
|
233
|
+
const { pseudo: globals2 } = globalsArgs;
|
|
234
|
+
const { rootSelector } = parameter || {};
|
|
235
|
+
const rootElement = useMemo(() => {
|
|
236
|
+
if (rootSelector) {
|
|
237
|
+
return document.querySelector(rootSelector);
|
|
238
|
+
}
|
|
239
|
+
if (viewMode === "docs") {
|
|
240
|
+
return document.getElementById(`story--${id}`);
|
|
241
|
+
}
|
|
242
|
+
return document.getElementById("storybook-root") || // Storybook 7.0+
|
|
243
|
+
document.getElementById("root");
|
|
244
|
+
}, [rootSelector, viewMode, id]);
|
|
245
|
+
useEffect(() => {
|
|
246
|
+
const config = pseudoConfig(parameter);
|
|
247
|
+
if (viewMode === "story" && !equals(config, globals2)) {
|
|
248
|
+
channel.emit(UPDATE_GLOBALS, {
|
|
249
|
+
globals: { pseudo: config }
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
}, [parameter, viewMode]);
|
|
253
|
+
useEffect(() => {
|
|
254
|
+
if (!rootElement)
|
|
255
|
+
return;
|
|
256
|
+
const timeout = setTimeout(() => {
|
|
257
|
+
applyParameter(rootElement, globals2 || pseudoConfig(parameter));
|
|
258
|
+
shadowHosts.forEach(updateShadowHost);
|
|
259
|
+
}, 0);
|
|
260
|
+
return () => clearTimeout(timeout);
|
|
261
|
+
}, [rootElement, globals2, parameter]);
|
|
262
|
+
return StoryFn();
|
|
263
|
+
};
|
|
264
|
+
var rewriteStyleSheets = (shadowRoot) => {
|
|
265
|
+
let styleSheets = Array.from(shadowRoot ? shadowRoot.styleSheets : document.styleSheets);
|
|
266
|
+
if (shadowRoot?.adoptedStyleSheets?.length)
|
|
267
|
+
styleSheets = shadowRoot.adoptedStyleSheets;
|
|
268
|
+
const rewroteStyles = styleSheets.map((sheet) => rewriteStyleSheet(sheet, shadowRoot)).some(Boolean);
|
|
269
|
+
if (rewroteStyles && shadowRoot && shadowHosts)
|
|
270
|
+
shadowHosts.add(shadowRoot.host);
|
|
271
|
+
};
|
|
272
|
+
channel.on(STORY_CHANGED, () => shadowHosts.clear());
|
|
273
|
+
channel.on(STORY_RENDERED, () => rewriteStyleSheets());
|
|
274
|
+
channel.on(GLOBALS_UPDATED, () => rewriteStyleSheets());
|
|
275
|
+
channel.on(FORCE_RE_RENDER, () => rewriteStyleSheets());
|
|
276
|
+
channel.on(FORCE_REMOUNT, () => rewriteStyleSheets());
|
|
277
|
+
channel.on(DOCS_RENDERED, () => rewriteStyleSheets());
|
|
278
|
+
if (Element.prototype.attachShadow) {
|
|
279
|
+
Element.prototype._attachShadow = Element.prototype.attachShadow;
|
|
280
|
+
Element.prototype.attachShadow = function attachShadow(init) {
|
|
281
|
+
const shadowRoot = this._attachShadow({ ...init, mode: "open" });
|
|
282
|
+
requestAnimationFrame(() => {
|
|
283
|
+
rewriteStyleSheets(shadowRoot);
|
|
284
|
+
if (shadowHosts.has(shadowRoot.host))
|
|
285
|
+
updateShadowHost(shadowRoot.host);
|
|
286
|
+
});
|
|
287
|
+
return shadowRoot;
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// src/preview.ts
|
|
292
|
+
var decorators = [withPseudoState];
|
|
293
|
+
var globals = { [PARAM_KEY]: false };
|
|
294
|
+
export {
|
|
295
|
+
decorators,
|
|
296
|
+
globals
|
|
297
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "storybook-addon-pseudo-states",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "CSS pseudo states for Storybook",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"storybook-addons",
|
|
@@ -50,34 +50,36 @@
|
|
|
50
50
|
"prepublish": "yarn clean && yarn build:dist",
|
|
51
51
|
"release": "auto shipit --base-branch=main"
|
|
52
52
|
},
|
|
53
|
+
"dependencies": {},
|
|
53
54
|
"devDependencies": {
|
|
55
|
+
"@babel/preset-env": "^7.20.2",
|
|
56
|
+
"@babel/preset-react": "^7.18.6",
|
|
57
|
+
"@babel/preset-typescript": "^7.18.6",
|
|
54
58
|
"@chromaui/addon-visual-tests": "^0.0.105",
|
|
55
|
-
"@storybook/addon-essentials": "^
|
|
56
|
-
"@storybook/addon-interactions": "^
|
|
57
|
-
"@storybook/addon-links": "^
|
|
58
|
-
"@storybook/
|
|
59
|
-
"@storybook/react": "^
|
|
60
|
-
"@storybook/
|
|
61
|
-
"@storybook/
|
|
62
|
-
"@storybook/types": "^8.0.0-alpha.12",
|
|
59
|
+
"@storybook/addon-essentials": "^7.4.6",
|
|
60
|
+
"@storybook/addon-interactions": "^7.4.6",
|
|
61
|
+
"@storybook/addon-links": "^7.4.6",
|
|
62
|
+
"@storybook/react": "^7.4.6",
|
|
63
|
+
"@storybook/react-webpack5": "^7.4.6",
|
|
64
|
+
"@storybook/testing-library": "^0.0.13",
|
|
65
|
+
"@storybook/types": "^7.4.6",
|
|
63
66
|
"@types/jest": "^29.2.4",
|
|
64
|
-
"
|
|
65
|
-
"auto": "^10.16.8",
|
|
67
|
+
"auto": "^11.1.1",
|
|
66
68
|
"concurrently": "^5.3.0",
|
|
67
69
|
"jest": "^27.5.1",
|
|
68
|
-
"react": "^
|
|
69
|
-
"react-dom": "^
|
|
70
|
+
"react": "^17.0.1",
|
|
71
|
+
"react-dom": "^17.0.1",
|
|
70
72
|
"rimraf": "^3.0.2",
|
|
71
|
-
"storybook": "^
|
|
72
|
-
"tsup": "^
|
|
73
|
+
"storybook": "^7.4.6",
|
|
74
|
+
"tsup": "^8.0.1",
|
|
73
75
|
"typescript": "^4.9.4"
|
|
74
76
|
},
|
|
75
77
|
"peerDependencies": {
|
|
76
|
-
"@storybook/components": "^
|
|
77
|
-
"@storybook/core-events": "^
|
|
78
|
-
"@storybook/manager-api": "^
|
|
79
|
-
"@storybook/preview-api": "^
|
|
80
|
-
"@storybook/theming": "^
|
|
78
|
+
"@storybook/components": "^7.4.6",
|
|
79
|
+
"@storybook/core-events": "^7.4.6",
|
|
80
|
+
"@storybook/manager-api": "^7.4.6",
|
|
81
|
+
"@storybook/preview-api": "^7.4.6",
|
|
82
|
+
"@storybook/theming": "^7.4.6",
|
|
81
83
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
|
82
84
|
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
|
83
85
|
},
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":["src_default"],"mappings":"AACA,IAAOA,EAAQ,CAAC","sourcesContent":["// make it work with --isolatedModules\nexport default {}\n"]}
|
package/dist/index.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":["src_default"],"mappings":"AACA,IAAOA,EAAQ,CAAC","sourcesContent":["// make it work with --isolatedModules\nexport default {}\n"]}
|
package/dist/manager.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/manager.ts","../src/constants.ts","../src/manager/PseudoStateTool.tsx"],"names":["addons","types","ADDON_ID","TOOL_ID","PARAM_KEY","PSEUDO_STATES","React","useCallback","Icons","IconButton","WithTooltip","TooltipLinkList","useGlobals","styled","color","LinkTitle","active","LinkIcon","options","PseudoStateTool","globals","updateGlobals","pseudo","isActive","option","toggleOption","viewMode"],"mappings":"AAAA,OAAS,UAAAA,EAAQ,SAAAC,MAAa,yBCAvB,IAAMC,EAAW,0BACXC,EAAU,GAAGD,SACbE,EAAY,SAQlB,IAAMC,EAAgB,CAC3B,MAAO,QACP,OAAQ,SACR,aAAc,gBACd,YAAa,eACb,MAAO,QACP,QAAS,UACT,KAAM,OACN,OAAQ,QACV,ECnBA,OAAOC,GAAS,eAAAC,MAAmB,QACnC,OAAS,SAAAC,EAAO,cAAAC,EAAY,eAAAC,EAAa,mBAAAC,MAAuB,wBAChE,OAAS,cAAAC,MAAkB,yBAC3B,OAAS,UAAAC,EAAQ,SAAAC,MAAa,qBAI9B,IAAMC,EAAYF,EAAO,KAA2B,CAAC,CAAE,OAAAG,CAAO,KAAO,CACnE,MAAOA,EAASF,EAAM,UAAY,SACpC,EAAE,EAEIG,EAAWJ,EAAOL,CAAK,EAAwB,CAAC,CAAE,OAAAQ,CAAO,KAAO,CACpE,QAASA,EAAS,EAAI,EACtB,KAAM,CAAE,KAAMA,EAASF,EAAM,UAAY,SAAU,CACrD,EAAE,EAEII,EAAU,OAAO,KAAKb,CAAa,EAAE,KAAK,EAEnCc,EAAkB,IAAM,CACnC,GAAM,CAACC,EAASC,CAAa,EAAIT,EAAW,EACtCU,EAASF,EAAQhB,CAAS,EAE1BmB,EAAWhB,EACdiB,GACMF,EACEA,EAAOE,CAAM,IAAM,GADN,GAGtB,CAACF,CAAM,CACT,EAEMG,EAAelB,EAClBiB,GAAuC,IAAM,CAC5CH,EAAc,CACZ,CAACjB,CAAS,EAAG,CACX,GAAGkB,EACH,CAACE,CAAM,EAAG,CAACD,EAASC,CAAM,CAC5B,CACF,CAAC,CACH,EACA,CAACF,CAAM,CACT,EAEA,OACEhB,EAAA,cAACI,EAAA,CACC,UAAU,MACV,QAAQ,QACR,QAAS,IACPJ,EAAA,cAACK,EAAA,CACC,MAAOO,EAAQ,IAAKM,IAAY,CAC9B,GAAIA,EACJ,MAAOlB,EAAA,cAACS,EAAA,CAAU,OAAQQ,EAASC,CAAM,GAAG,IAAEnB,EAAcmB,CAAM,CAAE,EACpE,MAAOlB,EAAA,cAACW,EAAA,CAAS,KAAK,QAAQ,MAAO,GAAI,OAAQ,GAAI,OAAQM,EAASC,CAAM,EAAG,EAC/E,QAASC,EAAaD,CAAM,EAC5B,OAAQD,EAASC,CAAM,CACzB,EAAE,EACJ,GAGFlB,EAAA,cAACG,EAAA,CACC,IAAI,eACJ,MAAM,2BACN,OAAQS,EAAQ,KAAKK,CAAQ,GAE7BjB,EAAA,cAACE,EAAA,CAAM,KAAK,SAAS,CACvB,CACF,CAEJ,EF9DAR,EAAO,SAASE,EAAU,IAAM,CAC9BF,EAAO,IAAIG,EAAS,CAClB,KAAMF,EAAM,KACZ,MAAO,oBACP,MAAO,CAAC,CAAE,SAAAyB,CAAS,IAAMA,IAAa,QACtC,OAAQP,CACV,CAAC,CACH,CAAC","sourcesContent":["import { addons, types } from \"@storybook/manager-api\"\n\nimport { ADDON_ID, TOOL_ID } from \"./constants\"\nimport { PseudoStateTool } from \"./manager/PseudoStateTool\"\n\naddons.register(ADDON_ID, () => {\n addons.add(TOOL_ID, {\n type: types.TOOL,\n title: \"CSS pseudo states\",\n match: ({ viewMode }) => viewMode === \"story\",\n render: PseudoStateTool,\n })\n})\n","export const ADDON_ID = \"storybook/pseudo-states\"\nexport const TOOL_ID = `${ADDON_ID}/tool`\nexport const PARAM_KEY = \"pseudo\"\n\n// Pseudo-elements which are not allowed to have classes applied on them\n// E.g. ::-webkit-scrollbar-thumb.pseudo-hover is not a valid selector\nexport const EXCLUDED_PSEUDO_ELEMENTS = [\"::-webkit-scrollbar-thumb\"]\n\n// Dynamic pseudo-classes\n// @see https://www.w3.org/TR/2018/REC-selectors-3-20181106/#dynamic-pseudos\nexport const PSEUDO_STATES = {\n hover: \"hover\",\n active: \"active\",\n focusVisible: \"focus-visible\",\n focusWithin: \"focus-within\",\n focus: \"focus\", // must come after its alternatives\n visited: \"visited\",\n link: \"link\",\n target: \"target\",\n} as const\n\nexport type PseudoState = keyof typeof PSEUDO_STATES\n","import React, { useCallback } from \"react\"\nimport { Icons, IconButton, WithTooltip, TooltipLinkList } from \"@storybook/components\"\nimport { useGlobals } from \"@storybook/manager-api\"\nimport { styled, color } from \"@storybook/theming\"\n\nimport { PARAM_KEY, PSEUDO_STATES } from \"../constants\"\n\nconst LinkTitle = styled.span<{ active?: boolean }>(({ active }) => ({\n color: active ? color.secondary : \"inherit\",\n}))\n\nconst LinkIcon = styled(Icons)<{ active?: boolean }>(({ active }) => ({\n opacity: active ? 1 : 0,\n path: { fill: active ? color.secondary : \"inherit\" },\n}))\n\nconst options = Object.keys(PSEUDO_STATES).sort() as (keyof typeof PSEUDO_STATES)[]\n\nexport const PseudoStateTool = () => {\n const [globals, updateGlobals] = useGlobals()\n const pseudo = globals[PARAM_KEY]\n\n const isActive = useCallback(\n (option: keyof typeof PSEUDO_STATES) => {\n if (!pseudo) return false\n return pseudo[option] === true\n },\n [pseudo]\n )\n\n const toggleOption = useCallback(\n (option: keyof typeof PSEUDO_STATES) => () => {\n updateGlobals({\n [PARAM_KEY]: {\n ...pseudo,\n [option]: !isActive(option),\n },\n })\n },\n [pseudo]\n )\n\n return (\n <WithTooltip\n placement=\"top\"\n trigger=\"click\"\n tooltip={() => (\n <TooltipLinkList\n links={options.map((option) => ({\n id: option,\n title: <LinkTitle active={isActive(option)}>:{PSEUDO_STATES[option]}</LinkTitle>,\n right: <LinkIcon icon=\"check\" width={12} height={12} active={isActive(option)} />,\n onClick: toggleOption(option),\n active: isActive(option),\n }))}\n />\n )}\n >\n <IconButton\n key=\"pseudo-state\"\n title=\"Select CSS pseudo states\"\n active={options.some(isActive)}\n >\n <Icons icon=\"button\" />\n </IconButton>\n </WithTooltip>\n )\n}\n"]}
|
package/dist/manager.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/manager.ts","../src/constants.ts","../src/manager/PseudoStateTool.tsx"],"names":["addons","types","ADDON_ID","TOOL_ID","PARAM_KEY","PSEUDO_STATES","React","useCallback","Icons","IconButton","WithTooltip","TooltipLinkList","useGlobals","styled","color","LinkTitle","active","LinkIcon","options","PseudoStateTool","globals","updateGlobals","pseudo","isActive","option","toggleOption","viewMode"],"mappings":"AAAA,OAAS,UAAAA,EAAQ,SAAAC,MAAa,yBCAvB,IAAMC,EAAW,0BACXC,EAAU,GAAGD,SACbE,EAAY,SAQlB,IAAMC,EAAgB,CAC3B,MAAO,QACP,OAAQ,SACR,aAAc,gBACd,YAAa,eACb,MAAO,QACP,QAAS,UACT,KAAM,OACN,OAAQ,QACV,ECnBA,OAAOC,GAAS,eAAAC,MAAmB,QACnC,OAAS,SAAAC,EAAO,cAAAC,EAAY,eAAAC,EAAa,mBAAAC,MAAuB,wBAChE,OAAS,cAAAC,MAAkB,yBAC3B,OAAS,UAAAC,EAAQ,SAAAC,MAAa,qBAI9B,IAAMC,EAAYF,EAAO,KAA2B,CAAC,CAAE,OAAAG,CAAO,KAAO,CACnE,MAAOA,EAASF,EAAM,UAAY,SACpC,EAAE,EAEIG,EAAWJ,EAAOL,CAAK,EAAwB,CAAC,CAAE,OAAAQ,CAAO,KAAO,CACpE,QAASA,EAAS,EAAI,EACtB,KAAM,CAAE,KAAMA,EAASF,EAAM,UAAY,SAAU,CACrD,EAAE,EAEII,EAAU,OAAO,KAAKb,CAAa,EAAE,KAAK,EAEnCc,EAAkB,IAAM,CACnC,GAAM,CAACC,EAASC,CAAa,EAAIT,EAAW,EACtCU,EAASF,EAAQhB,CAAS,EAE1BmB,EAAWhB,EACdiB,GACMF,EACEA,EAAOE,CAAM,IAAM,GADN,GAGtB,CAACF,CAAM,CACT,EAEMG,EAAelB,EAClBiB,GAAuC,IAAM,CAC5CH,EAAc,CACZ,CAACjB,CAAS,EAAG,CACX,GAAGkB,EACH,CAACE,CAAM,EAAG,CAACD,EAASC,CAAM,CAC5B,CACF,CAAC,CACH,EACA,CAACF,CAAM,CACT,EAEA,OACEhB,EAAA,cAACI,EAAA,CACC,UAAU,MACV,QAAQ,QACR,QAAS,IACPJ,EAAA,cAACK,EAAA,CACC,MAAOO,EAAQ,IAAKM,IAAY,CAC9B,GAAIA,EACJ,MAAOlB,EAAA,cAACS,EAAA,CAAU,OAAQQ,EAASC,CAAM,GAAG,IAAEnB,EAAcmB,CAAM,CAAE,EACpE,MAAOlB,EAAA,cAACW,EAAA,CAAS,KAAK,QAAQ,MAAO,GAAI,OAAQ,GAAI,OAAQM,EAASC,CAAM,EAAG,EAC/E,QAASC,EAAaD,CAAM,EAC5B,OAAQD,EAASC,CAAM,CACzB,EAAE,EACJ,GAGFlB,EAAA,cAACG,EAAA,CACC,IAAI,eACJ,MAAM,2BACN,OAAQS,EAAQ,KAAKK,CAAQ,GAE7BjB,EAAA,cAACE,EAAA,CAAM,KAAK,SAAS,CACvB,CACF,CAEJ,EF9DAR,EAAO,SAASE,EAAU,IAAM,CAC9BF,EAAO,IAAIG,EAAS,CAClB,KAAMF,EAAM,KACZ,MAAO,oBACP,MAAO,CAAC,CAAE,SAAAyB,CAAS,IAAMA,IAAa,QACtC,OAAQP,CACV,CAAC,CACH,CAAC","sourcesContent":["import { addons, types } from \"@storybook/manager-api\"\n\nimport { ADDON_ID, TOOL_ID } from \"./constants\"\nimport { PseudoStateTool } from \"./manager/PseudoStateTool\"\n\naddons.register(ADDON_ID, () => {\n addons.add(TOOL_ID, {\n type: types.TOOL,\n title: \"CSS pseudo states\",\n match: ({ viewMode }) => viewMode === \"story\",\n render: PseudoStateTool,\n })\n})\n","export const ADDON_ID = \"storybook/pseudo-states\"\nexport const TOOL_ID = `${ADDON_ID}/tool`\nexport const PARAM_KEY = \"pseudo\"\n\n// Pseudo-elements which are not allowed to have classes applied on them\n// E.g. ::-webkit-scrollbar-thumb.pseudo-hover is not a valid selector\nexport const EXCLUDED_PSEUDO_ELEMENTS = [\"::-webkit-scrollbar-thumb\"]\n\n// Dynamic pseudo-classes\n// @see https://www.w3.org/TR/2018/REC-selectors-3-20181106/#dynamic-pseudos\nexport const PSEUDO_STATES = {\n hover: \"hover\",\n active: \"active\",\n focusVisible: \"focus-visible\",\n focusWithin: \"focus-within\",\n focus: \"focus\", // must come after its alternatives\n visited: \"visited\",\n link: \"link\",\n target: \"target\",\n} as const\n\nexport type PseudoState = keyof typeof PSEUDO_STATES\n","import React, { useCallback } from \"react\"\nimport { Icons, IconButton, WithTooltip, TooltipLinkList } from \"@storybook/components\"\nimport { useGlobals } from \"@storybook/manager-api\"\nimport { styled, color } from \"@storybook/theming\"\n\nimport { PARAM_KEY, PSEUDO_STATES } from \"../constants\"\n\nconst LinkTitle = styled.span<{ active?: boolean }>(({ active }) => ({\n color: active ? color.secondary : \"inherit\",\n}))\n\nconst LinkIcon = styled(Icons)<{ active?: boolean }>(({ active }) => ({\n opacity: active ? 1 : 0,\n path: { fill: active ? color.secondary : \"inherit\" },\n}))\n\nconst options = Object.keys(PSEUDO_STATES).sort() as (keyof typeof PSEUDO_STATES)[]\n\nexport const PseudoStateTool = () => {\n const [globals, updateGlobals] = useGlobals()\n const pseudo = globals[PARAM_KEY]\n\n const isActive = useCallback(\n (option: keyof typeof PSEUDO_STATES) => {\n if (!pseudo) return false\n return pseudo[option] === true\n },\n [pseudo]\n )\n\n const toggleOption = useCallback(\n (option: keyof typeof PSEUDO_STATES) => () => {\n updateGlobals({\n [PARAM_KEY]: {\n ...pseudo,\n [option]: !isActive(option),\n },\n })\n },\n [pseudo]\n )\n\n return (\n <WithTooltip\n placement=\"top\"\n trigger=\"click\"\n tooltip={() => (\n <TooltipLinkList\n links={options.map((option) => ({\n id: option,\n title: <LinkTitle active={isActive(option)}>:{PSEUDO_STATES[option]}</LinkTitle>,\n right: <LinkIcon icon=\"check\" width={12} height={12} active={isActive(option)} />,\n onClick: toggleOption(option),\n active: isActive(option),\n }))}\n />\n )}\n >\n <IconButton\n key=\"pseudo-state\"\n title=\"Select CSS pseudo states\"\n active={options.some(isActive)}\n >\n <Icons icon=\"button\" />\n </IconButton>\n </WithTooltip>\n )\n}\n"]}
|
package/dist/preview.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/constants.ts","../src/preview/withPseudoState.ts","../src/preview/splitSelectors.ts","../src/preview/rewriteStyleSheet.ts","../src/preview.ts"],"names":["ADDON_ID","TOOL_ID","PARAM_KEY","EXCLUDED_PSEUDO_ELEMENTS","PSEUDO_STATES","DOCS_RENDERED","FORCE_REMOUNT","FORCE_RE_RENDER","GLOBALS_UPDATED","STORY_CHANGED","STORY_RENDERED","UPDATE_GLOBALS","addons","useEffect","useMemo","isAtRule","selector","splitSelectors","selectors","result","parentheses","brackets","i","len","char","pseudoStates","matchOne","matchAll","warnings","warnOnce","message","isExcludedPseudoElement","pseudoState","element","rewriteRule","cssText","selectorText","shadowRoot","states","plainSelector","_","state","classSelector","acc","classAllSelector","ancestorSelector","s","rewriteStyleSheet","sheet","shadowHosts","index","cssRule","styleRule","newRule","e","channel","applyClasses","classnames","classname","applyParameter","rootElement","parameter","map","add","target","value","el","sel","key","keyWithoutAll","updateShadowHost","shadowHost","pseudoConfig","rootSelector","pseudoStateConfig","equals","a","b","withPseudoState","StoryFn","viewMode","parameters","id","globalsArgs","globals","config","timeout","rewriteStyleSheets","styleSheets","init","decorators"],"mappings":"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","sourcesContent":["export const ADDON_ID = \"storybook/pseudo-states\"\nexport const TOOL_ID = `${ADDON_ID}/tool`\nexport const PARAM_KEY = \"pseudo\"\n\n// Pseudo-elements which are not allowed to have classes applied on them\n// E.g. ::-webkit-scrollbar-thumb.pseudo-hover is not a valid selector\nexport const EXCLUDED_PSEUDO_ELEMENTS = [\"::-webkit-scrollbar-thumb\"]\n\n// Dynamic pseudo-classes\n// @see https://www.w3.org/TR/2018/REC-selectors-3-20181106/#dynamic-pseudos\nexport const PSEUDO_STATES = {\n hover: \"hover\",\n active: \"active\",\n focusVisible: \"focus-visible\",\n focusWithin: \"focus-within\",\n focus: \"focus\", // must come after its alternatives\n visited: \"visited\",\n link: \"link\",\n target: \"target\",\n} as const\n\nexport type PseudoState = keyof typeof PSEUDO_STATES\n","/* eslint-env browser */\nimport {\n DOCS_RENDERED,\n FORCE_REMOUNT,\n FORCE_RE_RENDER,\n GLOBALS_UPDATED,\n STORY_CHANGED,\n STORY_RENDERED,\n UPDATE_GLOBALS,\n} from \"@storybook/core-events\"\nimport { DecoratorFunction } from \"@storybook/types\"\nimport { addons, useEffect, useMemo } from \"@storybook/preview-api\"\n\nimport { PSEUDO_STATES, PseudoState } from \"../constants\"\nimport { rewriteStyleSheet } from \"./rewriteStyleSheet\"\n\ntype PseudoStateConfig = {\n [P in PseudoState]?: boolean | string | string[]\n}\n\nexport interface PseudoParameter extends PseudoStateConfig {\n rootSelector?: string\n}\n\nconst channel = addons.getChannel()\nconst shadowHosts = new Set<Element>()\n\n// Drops any existing pseudo state classnames that carried over from a previously viewed story\n// before adding the new classnames. We use forEach for IE compatibility.\nconst applyClasses = (element: Element, classnames: Set<string>) => {\n Object.values(PSEUDO_STATES).forEach((state) => {\n element.classList.remove(`pseudo-${state}`)\n element.classList.remove(`pseudo-${state}-all`)\n })\n classnames.forEach((classname) => element.classList.add(classname))\n}\n\nconst applyParameter = (rootElement: Element, parameter: PseudoStateConfig = {}) => {\n const map = new Map([[rootElement, new Set<PseudoState>()]])\n const add = (target: Element, state: PseudoState) =>\n map.set(target, new Set([...(map.get(target) || []), state]))\n\n ;(Object.entries(parameter || {}) as [PseudoState, any]).forEach(([state, value]) => {\n if (typeof value === \"boolean\") {\n // default API - applying pseudo class to root element.\n if (value) add(rootElement, `${state}-all` as PseudoState)\n } else if (typeof value === \"string\") {\n // explicit selectors API - applying pseudo class to a specific element\n rootElement.querySelectorAll(value).forEach((el) => add(el, state))\n } else if (Array.isArray(value)) {\n // explicit selectors API - we have an array (of strings) recursively handle each one\n value.forEach((sel) => rootElement.querySelectorAll(sel).forEach((el) => add(el, state)))\n }\n })\n\n map.forEach((states, target) => {\n const classnames = new Set<string>()\n states.forEach((key) => {\n const keyWithoutAll = key.replace(\"-all\", \"\") as PseudoState\n if (PSEUDO_STATES[key]) {\n classnames.add(`pseudo-${PSEUDO_STATES[key]}`)\n } else if (PSEUDO_STATES[keyWithoutAll]) {\n classnames.add(`pseudo-${PSEUDO_STATES[keyWithoutAll]}-all`)\n }\n })\n applyClasses(target, classnames)\n })\n}\n\n// Traverses ancestry to collect relevant pseudo classnames, and applies them to the shadow host.\n// Shadow DOM can only access classes on its host. Traversing is needed to mimic the CSS cascade.\nconst updateShadowHost = (shadowHost: Element) => {\n const classnames = new Set<string>()\n for (let element = shadowHost.parentElement; element; element = element.parentElement) {\n if (!element.className) continue\n element.className\n .split(\" \")\n .filter((classname) => classname.indexOf(\"pseudo-\") === 0)\n .forEach((classname) => classnames.add(classname))\n }\n applyClasses(shadowHost, classnames)\n}\n\n// Drops the rootSelector from the parameter object, as it is not a pseudo state.\nconst pseudoConfig = (parameter: PseudoParameter) => {\n const { rootSelector, ...pseudoStateConfig } = parameter || {}\n return pseudoStateConfig\n}\n\n// Compares two pseudo state configs to see if they are equal.\n// Uses JSON.stringify to handle arrays, so the order of selectors in the array matters.\nconst equals = (a: PseudoStateConfig = {}, b: PseudoStateConfig = {}) =>\n a !== null &&\n b !== null &&\n Object.keys(a).length === Object.keys(b).length &&\n (Object.keys(a) as PseudoState[]).every(\n (key) => JSON.stringify(a[key]) === JSON.stringify(b[key])\n )\n\n// Global decorator that rewrites stylesheets and applies classnames to render pseudo styles\nexport const withPseudoState: DecoratorFunction = (\n StoryFn,\n { viewMode, parameters, id, globals: globalsArgs }\n) => {\n const { pseudo: parameter } = parameters\n const { pseudo: globals } = globalsArgs\n const { rootSelector } = parameter || {}\n\n const rootElement = useMemo(() => {\n if (rootSelector) {\n return document.querySelector(rootSelector)\n }\n if (viewMode === \"docs\") {\n return document.getElementById(`story--${id}`)\n }\n return (\n document.getElementById(\"storybook-root\") || // Storybook 7.0+\n document.getElementById(\"root\")\n )\n }, [rootSelector, viewMode, id])\n\n // Sync parameter to globals, used by the toolbar (only in canvas as this\n // doesn't make sense for docs because many stories are displayed at once)\n useEffect(() => {\n const config = pseudoConfig(parameter)\n if (viewMode === \"story\" && !equals(config, globals)) {\n channel.emit(UPDATE_GLOBALS, {\n globals: { pseudo: config },\n })\n }\n }, [parameter, viewMode])\n\n // Convert selected states to classnames and apply them to the story root element.\n // Then update each shadow host to redetermine its own pseudo classnames.\n useEffect(() => {\n if (!rootElement) return\n const timeout = setTimeout(() => {\n applyParameter(rootElement, globals || pseudoConfig(parameter))\n shadowHosts.forEach(updateShadowHost)\n }, 0)\n return () => clearTimeout(timeout)\n }, [rootElement, globals, parameter])\n\n return StoryFn()\n}\n\n// Rewrite CSS rules for pseudo-states on all stylesheets to add an alternative selector\nconst rewriteStyleSheets = (shadowRoot?: ShadowRoot) => {\n let styleSheets = Array.from(shadowRoot ? shadowRoot.styleSheets : document.styleSheets)\n if (shadowRoot?.adoptedStyleSheets?.length) styleSheets = shadowRoot.adoptedStyleSheets\n styleSheets.forEach((sheet) => rewriteStyleSheet(sheet, shadowRoot, shadowHosts))\n}\n\n// Only track shadow hosts for the current story\nchannel.on(STORY_CHANGED, () => shadowHosts.clear())\n\n// Reinitialize CSS enhancements every time the story changes\nchannel.on(STORY_RENDERED, () => rewriteStyleSheets())\nchannel.on(GLOBALS_UPDATED, () => rewriteStyleSheets())\nchannel.on(FORCE_RE_RENDER, () => rewriteStyleSheets())\nchannel.on(FORCE_REMOUNT, () => rewriteStyleSheets())\n\n// Reinitialize CSS enhancements every time a docs page is rendered\nchannel.on(DOCS_RENDERED, () => rewriteStyleSheets())\n\n// IE doesn't support shadow DOM\nif (Element.prototype.attachShadow) {\n // Monkeypatch the attachShadow method so we can handle pseudo styles inside shadow DOM\n // @ts-expect-error (Monkeypatch)\n Element.prototype._attachShadow = Element.prototype.attachShadow\n Element.prototype.attachShadow = function attachShadow(init) {\n // Force \"open\" mode, so we can access the shadowRoot\n // @ts-expect-error (Monkeypatch)\n const shadowRoot = this._attachShadow({ ...init, mode: \"open\" })\n // Wait for it to render and apply its styles before rewriting them\n requestAnimationFrame(() => {\n rewriteStyleSheets(shadowRoot)\n updateShadowHost(shadowRoot.host)\n })\n return shadowRoot\n }\n}\n","const isAtRule = (selector: string) => selector.indexOf(\"@\") === 0\n\nexport const splitSelectors = (selectors: string) => {\n if (isAtRule(selectors)) return [selectors]\n\n let result = []\n let parentheses = 0\n let brackets = 0\n let selector = \"\"\n\n for (let i = 0, len = selectors.length; i < len; i++) {\n const char = selectors[i]\n if (char === \"(\") {\n parentheses += 1\n } else if (char === \")\") {\n parentheses -= 1\n } else if (char === \"[\") {\n brackets += 1\n } else if (char === \"]\") {\n brackets -= 1\n } else if (char === \",\") {\n if (!parentheses && !brackets) {\n result.push(selector.trim())\n selector = \"\"\n continue\n }\n }\n selector += char\n }\n\n result.push(selector.trim())\n return result\n}\n","import { PSEUDO_STATES, EXCLUDED_PSEUDO_ELEMENTS } from \"../constants\"\nimport { splitSelectors } from \"./splitSelectors\"\n\nconst pseudoStates = Object.values(PSEUDO_STATES)\nconst matchOne = new RegExp(`:(${pseudoStates.join(\"|\")})`)\nconst matchAll = new RegExp(`:(${pseudoStates.join(\"|\")})`, \"g\")\n\nconst warnings = new Set()\nconst warnOnce = (message: string) => {\n if (warnings.has(message)) return\n // eslint-disable-next-line no-console\n console.warn(message)\n warnings.add(message)\n}\n\nconst isExcludedPseudoElement = (selector: string, pseudoState: string) =>\n EXCLUDED_PSEUDO_ELEMENTS.some((element) => selector.endsWith(`${element}:${pseudoState}`))\n\nconst rewriteRule = ({ cssText, selectorText }: CSSStyleRule, shadowRoot?: ShadowRoot) => {\n return cssText.replace(\n selectorText,\n splitSelectors(selectorText)\n .flatMap((selector) => {\n if (selector.includes(\".pseudo-\")) {\n return []\n }\n if (!matchOne.test(selector)) {\n return [selector]\n }\n\n const states: string[] = []\n const plainSelector = selector.replace(matchAll, (_, state) => {\n states.push(state)\n return \"\"\n })\n const classSelector = states.reduce((acc, state) => {\n if (isExcludedPseudoElement(selector, state)) return \"\"\n return acc.replace(new RegExp(`:${state}`, \"g\"), `.pseudo-${state}`)\n }, selector)\n\n const classAllSelector = states.reduce((acc, state) => {\n if (isExcludedPseudoElement(selector, state)) return \"\"\n return acc.replace(new RegExp(`:${state}`, \"g\"), `.pseudo-${state}-all`)\n }, selector)\n\n if (selector.startsWith(\":host(\") || selector.startsWith(\"::slotted(\")) {\n return [selector, classSelector, classAllSelector].filter(Boolean)\n }\n\n const ancestorSelector = shadowRoot\n ? `:host(${states.map((s) => `.pseudo-${s}-all`).join(\"\")}) ${plainSelector}`\n : `${states.map((s) => `.pseudo-${s}-all`).join(\"\")} ${plainSelector}`\n\n return [selector, classSelector, ancestorSelector].filter(\n (selector) => selector && !selector.includes(\":not()\")\n )\n })\n .join(\", \")\n )\n}\n\n// Rewrites the style sheet to add alternative selectors for any rule that targets a pseudo state.\n// A sheet can only be rewritten once, and may carry over between stories.\nexport const rewriteStyleSheet = (\n sheet: CSSStyleSheet,\n shadowRoot?: ShadowRoot,\n shadowHosts?: Set<Element>\n) => {\n try {\n let index = -1\n for (const cssRule of sheet.cssRules) {\n index++\n\n // @ts-expect-error\n if (cssRule.__pseudoStatesRewritten || !(\"selectorText\" in cssRule)) continue\n\n const styleRule = cssRule as CSSStyleRule\n if (matchOne.test(styleRule.selectorText)) {\n const newRule = rewriteRule(styleRule, shadowRoot)\n sheet.deleteRule(index)\n sheet.insertRule(newRule, index)\n if (shadowRoot && shadowHosts) shadowHosts.add(shadowRoot.host)\n }\n\n // @ts-expect-error\n cssRule.__pseudoStatesRewritten = true\n\n if (index > 1000) {\n warnOnce(\"Reached maximum of 1000 pseudo selectors per sheet, skipping the rest.\")\n break\n }\n }\n } catch (e) {\n if (String(e).includes(\"cssRules\")) {\n warnOnce(`Can't access cssRules, likely due to CORS restrictions: ${sheet.href}`)\n } else {\n // eslint-disable-next-line no-console\n console.error(e, sheet.href)\n }\n }\n}\n","import { PARAM_KEY } from \"./constants\"\nimport { withPseudoState } from \"./preview/withPseudoState\"\n\nexport const decorators = [withPseudoState]\nexport const globals = { [PARAM_KEY]: false }\n"]}
|
package/dist/preview.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/constants.ts","../src/preview/withPseudoState.ts","../src/preview/splitSelectors.ts","../src/preview/rewriteStyleSheet.ts","../src/preview.ts"],"names":["ADDON_ID","TOOL_ID","PARAM_KEY","EXCLUDED_PSEUDO_ELEMENTS","PSEUDO_STATES","DOCS_RENDERED","FORCE_REMOUNT","FORCE_RE_RENDER","GLOBALS_UPDATED","STORY_CHANGED","STORY_RENDERED","UPDATE_GLOBALS","addons","useEffect","useMemo","isAtRule","selector","splitSelectors","selectors","result","parentheses","brackets","i","len","char","pseudoStates","matchOne","matchAll","warnings","warnOnce","message","isExcludedPseudoElement","pseudoState","element","rewriteRule","cssText","selectorText","shadowRoot","states","plainSelector","_","state","classSelector","acc","classAllSelector","ancestorSelector","s","rewriteStyleSheet","sheet","shadowHosts","index","cssRule","styleRule","newRule","e","channel","applyClasses","classnames","classname","applyParameter","rootElement","parameter","map","add","target","value","el","sel","key","keyWithoutAll","updateShadowHost","shadowHost","pseudoConfig","rootSelector","pseudoStateConfig","equals","a","b","withPseudoState","StoryFn","viewMode","parameters","id","globalsArgs","globals","config","timeout","rewriteStyleSheets","styleSheets","init","decorators"],"mappings":"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","sourcesContent":["export const ADDON_ID = \"storybook/pseudo-states\"\nexport const TOOL_ID = `${ADDON_ID}/tool`\nexport const PARAM_KEY = \"pseudo\"\n\n// Pseudo-elements which are not allowed to have classes applied on them\n// E.g. ::-webkit-scrollbar-thumb.pseudo-hover is not a valid selector\nexport const EXCLUDED_PSEUDO_ELEMENTS = [\"::-webkit-scrollbar-thumb\"]\n\n// Dynamic pseudo-classes\n// @see https://www.w3.org/TR/2018/REC-selectors-3-20181106/#dynamic-pseudos\nexport const PSEUDO_STATES = {\n hover: \"hover\",\n active: \"active\",\n focusVisible: \"focus-visible\",\n focusWithin: \"focus-within\",\n focus: \"focus\", // must come after its alternatives\n visited: \"visited\",\n link: \"link\",\n target: \"target\",\n} as const\n\nexport type PseudoState = keyof typeof PSEUDO_STATES\n","/* eslint-env browser */\nimport {\n DOCS_RENDERED,\n FORCE_REMOUNT,\n FORCE_RE_RENDER,\n GLOBALS_UPDATED,\n STORY_CHANGED,\n STORY_RENDERED,\n UPDATE_GLOBALS,\n} from \"@storybook/core-events\"\nimport { DecoratorFunction } from \"@storybook/types\"\nimport { addons, useEffect, useMemo } from \"@storybook/preview-api\"\n\nimport { PSEUDO_STATES, PseudoState } from \"../constants\"\nimport { rewriteStyleSheet } from \"./rewriteStyleSheet\"\n\ntype PseudoStateConfig = {\n [P in PseudoState]?: boolean | string | string[]\n}\n\nexport interface PseudoParameter extends PseudoStateConfig {\n rootSelector?: string\n}\n\nconst channel = addons.getChannel()\nconst shadowHosts = new Set<Element>()\n\n// Drops any existing pseudo state classnames that carried over from a previously viewed story\n// before adding the new classnames. We use forEach for IE compatibility.\nconst applyClasses = (element: Element, classnames: Set<string>) => {\n Object.values(PSEUDO_STATES).forEach((state) => {\n element.classList.remove(`pseudo-${state}`)\n element.classList.remove(`pseudo-${state}-all`)\n })\n classnames.forEach((classname) => element.classList.add(classname))\n}\n\nconst applyParameter = (rootElement: Element, parameter: PseudoStateConfig = {}) => {\n const map = new Map([[rootElement, new Set<PseudoState>()]])\n const add = (target: Element, state: PseudoState) =>\n map.set(target, new Set([...(map.get(target) || []), state]))\n\n ;(Object.entries(parameter || {}) as [PseudoState, any]).forEach(([state, value]) => {\n if (typeof value === \"boolean\") {\n // default API - applying pseudo class to root element.\n if (value) add(rootElement, `${state}-all` as PseudoState)\n } else if (typeof value === \"string\") {\n // explicit selectors API - applying pseudo class to a specific element\n rootElement.querySelectorAll(value).forEach((el) => add(el, state))\n } else if (Array.isArray(value)) {\n // explicit selectors API - we have an array (of strings) recursively handle each one\n value.forEach((sel) => rootElement.querySelectorAll(sel).forEach((el) => add(el, state)))\n }\n })\n\n map.forEach((states, target) => {\n const classnames = new Set<string>()\n states.forEach((key) => {\n const keyWithoutAll = key.replace(\"-all\", \"\") as PseudoState\n if (PSEUDO_STATES[key]) {\n classnames.add(`pseudo-${PSEUDO_STATES[key]}`)\n } else if (PSEUDO_STATES[keyWithoutAll]) {\n classnames.add(`pseudo-${PSEUDO_STATES[keyWithoutAll]}-all`)\n }\n })\n applyClasses(target, classnames)\n })\n}\n\n// Traverses ancestry to collect relevant pseudo classnames, and applies them to the shadow host.\n// Shadow DOM can only access classes on its host. Traversing is needed to mimic the CSS cascade.\nconst updateShadowHost = (shadowHost: Element) => {\n const classnames = new Set<string>()\n for (let element = shadowHost.parentElement; element; element = element.parentElement) {\n if (!element.className) continue\n element.className\n .split(\" \")\n .filter((classname) => classname.indexOf(\"pseudo-\") === 0)\n .forEach((classname) => classnames.add(classname))\n }\n applyClasses(shadowHost, classnames)\n}\n\n// Drops the rootSelector from the parameter object, as it is not a pseudo state.\nconst pseudoConfig = (parameter: PseudoParameter) => {\n const { rootSelector, ...pseudoStateConfig } = parameter || {}\n return pseudoStateConfig\n}\n\n// Compares two pseudo state configs to see if they are equal.\n// Uses JSON.stringify to handle arrays, so the order of selectors in the array matters.\nconst equals = (a: PseudoStateConfig = {}, b: PseudoStateConfig = {}) =>\n a !== null &&\n b !== null &&\n Object.keys(a).length === Object.keys(b).length &&\n (Object.keys(a) as PseudoState[]).every(\n (key) => JSON.stringify(a[key]) === JSON.stringify(b[key])\n )\n\n// Global decorator that rewrites stylesheets and applies classnames to render pseudo styles\nexport const withPseudoState: DecoratorFunction = (\n StoryFn,\n { viewMode, parameters, id, globals: globalsArgs }\n) => {\n const { pseudo: parameter } = parameters\n const { pseudo: globals } = globalsArgs\n const { rootSelector } = parameter || {}\n\n const rootElement = useMemo(() => {\n if (rootSelector) {\n return document.querySelector(rootSelector)\n }\n if (viewMode === \"docs\") {\n return document.getElementById(`story--${id}`)\n }\n return (\n document.getElementById(\"storybook-root\") || // Storybook 7.0+\n document.getElementById(\"root\")\n )\n }, [rootSelector, viewMode, id])\n\n // Sync parameter to globals, used by the toolbar (only in canvas as this\n // doesn't make sense for docs because many stories are displayed at once)\n useEffect(() => {\n const config = pseudoConfig(parameter)\n if (viewMode === \"story\" && !equals(config, globals)) {\n channel.emit(UPDATE_GLOBALS, {\n globals: { pseudo: config },\n })\n }\n }, [parameter, viewMode])\n\n // Convert selected states to classnames and apply them to the story root element.\n // Then update each shadow host to redetermine its own pseudo classnames.\n useEffect(() => {\n if (!rootElement) return\n const timeout = setTimeout(() => {\n applyParameter(rootElement, globals || pseudoConfig(parameter))\n shadowHosts.forEach(updateShadowHost)\n }, 0)\n return () => clearTimeout(timeout)\n }, [rootElement, globals, parameter])\n\n return StoryFn()\n}\n\n// Rewrite CSS rules for pseudo-states on all stylesheets to add an alternative selector\nconst rewriteStyleSheets = (shadowRoot?: ShadowRoot) => {\n let styleSheets = Array.from(shadowRoot ? shadowRoot.styleSheets : document.styleSheets)\n if (shadowRoot?.adoptedStyleSheets?.length) styleSheets = shadowRoot.adoptedStyleSheets\n styleSheets.forEach((sheet) => rewriteStyleSheet(sheet, shadowRoot, shadowHosts))\n}\n\n// Only track shadow hosts for the current story\nchannel.on(STORY_CHANGED, () => shadowHosts.clear())\n\n// Reinitialize CSS enhancements every time the story changes\nchannel.on(STORY_RENDERED, () => rewriteStyleSheets())\nchannel.on(GLOBALS_UPDATED, () => rewriteStyleSheets())\nchannel.on(FORCE_RE_RENDER, () => rewriteStyleSheets())\nchannel.on(FORCE_REMOUNT, () => rewriteStyleSheets())\n\n// Reinitialize CSS enhancements every time a docs page is rendered\nchannel.on(DOCS_RENDERED, () => rewriteStyleSheets())\n\n// IE doesn't support shadow DOM\nif (Element.prototype.attachShadow) {\n // Monkeypatch the attachShadow method so we can handle pseudo styles inside shadow DOM\n // @ts-expect-error (Monkeypatch)\n Element.prototype._attachShadow = Element.prototype.attachShadow\n Element.prototype.attachShadow = function attachShadow(init) {\n // Force \"open\" mode, so we can access the shadowRoot\n // @ts-expect-error (Monkeypatch)\n const shadowRoot = this._attachShadow({ ...init, mode: \"open\" })\n // Wait for it to render and apply its styles before rewriting them\n requestAnimationFrame(() => {\n rewriteStyleSheets(shadowRoot)\n updateShadowHost(shadowRoot.host)\n })\n return shadowRoot\n }\n}\n","const isAtRule = (selector: string) => selector.indexOf(\"@\") === 0\n\nexport const splitSelectors = (selectors: string) => {\n if (isAtRule(selectors)) return [selectors]\n\n let result = []\n let parentheses = 0\n let brackets = 0\n let selector = \"\"\n\n for (let i = 0, len = selectors.length; i < len; i++) {\n const char = selectors[i]\n if (char === \"(\") {\n parentheses += 1\n } else if (char === \")\") {\n parentheses -= 1\n } else if (char === \"[\") {\n brackets += 1\n } else if (char === \"]\") {\n brackets -= 1\n } else if (char === \",\") {\n if (!parentheses && !brackets) {\n result.push(selector.trim())\n selector = \"\"\n continue\n }\n }\n selector += char\n }\n\n result.push(selector.trim())\n return result\n}\n","import { PSEUDO_STATES, EXCLUDED_PSEUDO_ELEMENTS } from \"../constants\"\nimport { splitSelectors } from \"./splitSelectors\"\n\nconst pseudoStates = Object.values(PSEUDO_STATES)\nconst matchOne = new RegExp(`:(${pseudoStates.join(\"|\")})`)\nconst matchAll = new RegExp(`:(${pseudoStates.join(\"|\")})`, \"g\")\n\nconst warnings = new Set()\nconst warnOnce = (message: string) => {\n if (warnings.has(message)) return\n // eslint-disable-next-line no-console\n console.warn(message)\n warnings.add(message)\n}\n\nconst isExcludedPseudoElement = (selector: string, pseudoState: string) =>\n EXCLUDED_PSEUDO_ELEMENTS.some((element) => selector.endsWith(`${element}:${pseudoState}`))\n\nconst rewriteRule = ({ cssText, selectorText }: CSSStyleRule, shadowRoot?: ShadowRoot) => {\n return cssText.replace(\n selectorText,\n splitSelectors(selectorText)\n .flatMap((selector) => {\n if (selector.includes(\".pseudo-\")) {\n return []\n }\n if (!matchOne.test(selector)) {\n return [selector]\n }\n\n const states: string[] = []\n const plainSelector = selector.replace(matchAll, (_, state) => {\n states.push(state)\n return \"\"\n })\n const classSelector = states.reduce((acc, state) => {\n if (isExcludedPseudoElement(selector, state)) return \"\"\n return acc.replace(new RegExp(`:${state}`, \"g\"), `.pseudo-${state}`)\n }, selector)\n\n const classAllSelector = states.reduce((acc, state) => {\n if (isExcludedPseudoElement(selector, state)) return \"\"\n return acc.replace(new RegExp(`:${state}`, \"g\"), `.pseudo-${state}-all`)\n }, selector)\n\n if (selector.startsWith(\":host(\") || selector.startsWith(\"::slotted(\")) {\n return [selector, classSelector, classAllSelector].filter(Boolean)\n }\n\n const ancestorSelector = shadowRoot\n ? `:host(${states.map((s) => `.pseudo-${s}-all`).join(\"\")}) ${plainSelector}`\n : `${states.map((s) => `.pseudo-${s}-all`).join(\"\")} ${plainSelector}`\n\n return [selector, classSelector, ancestorSelector].filter(\n (selector) => selector && !selector.includes(\":not()\")\n )\n })\n .join(\", \")\n )\n}\n\n// Rewrites the style sheet to add alternative selectors for any rule that targets a pseudo state.\n// A sheet can only be rewritten once, and may carry over between stories.\nexport const rewriteStyleSheet = (\n sheet: CSSStyleSheet,\n shadowRoot?: ShadowRoot,\n shadowHosts?: Set<Element>\n) => {\n try {\n let index = -1\n for (const cssRule of sheet.cssRules) {\n index++\n\n // @ts-expect-error\n if (cssRule.__pseudoStatesRewritten || !(\"selectorText\" in cssRule)) continue\n\n const styleRule = cssRule as CSSStyleRule\n if (matchOne.test(styleRule.selectorText)) {\n const newRule = rewriteRule(styleRule, shadowRoot)\n sheet.deleteRule(index)\n sheet.insertRule(newRule, index)\n if (shadowRoot && shadowHosts) shadowHosts.add(shadowRoot.host)\n }\n\n // @ts-expect-error\n cssRule.__pseudoStatesRewritten = true\n\n if (index > 1000) {\n warnOnce(\"Reached maximum of 1000 pseudo selectors per sheet, skipping the rest.\")\n break\n }\n }\n } catch (e) {\n if (String(e).includes(\"cssRules\")) {\n warnOnce(`Can't access cssRules, likely due to CORS restrictions: ${sheet.href}`)\n } else {\n // eslint-disable-next-line no-console\n console.error(e, sheet.href)\n }\n }\n}\n","import { PARAM_KEY } from \"./constants\"\nimport { withPseudoState } from \"./preview/withPseudoState\"\n\nexport const decorators = [withPseudoState]\nexport const globals = { [PARAM_KEY]: false }\n"]}
|