storybook-addon-pseudo-states 10.1.0-alpha.8 → 10.1.0-beta.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.
@@ -0,0 +1,240 @@
1
+ import {
2
+ EXCLUDED_PSEUDO_ELEMENT_PATTERNS,
3
+ EXCLUDED_PSEUDO_ESCAPE_SEQUENCE,
4
+ PARAM_KEY,
5
+ PSEUDO_STATES,
6
+ __export
7
+ } from "./chunk-FLRMKMJW.js";
8
+
9
+ // src/preview.ts
10
+ var preview_exports = {};
11
+ __export(preview_exports, {
12
+ decorators: () => decorators,
13
+ initialGlobals: () => initialGlobals
14
+ });
15
+
16
+ // src/preview/withPseudoState.ts
17
+ import {
18
+ DOCS_RENDERED,
19
+ FORCE_REMOUNT,
20
+ FORCE_RE_RENDER,
21
+ GLOBALS_UPDATED,
22
+ STORY_CHANGED,
23
+ STORY_RENDERED,
24
+ UPDATE_GLOBALS
25
+ } from "storybook/internal/core-events";
26
+ import { addons, useEffect, useMemo, useRef } from "storybook/preview-api";
27
+
28
+ // src/preview/splitSelectors.ts
29
+ var isAtRule = (selector) => selector.indexOf("@") === 0, splitSelectors = (selectors) => {
30
+ if (isAtRule(selectors))
31
+ return [selectors];
32
+ let result = [], parentheses = 0, brackets = 0, selector = "";
33
+ for (let i = 0, len = selectors.length; i < len; i++) {
34
+ let char = selectors[i];
35
+ if (char === "(")
36
+ parentheses += 1;
37
+ else if (char === ")")
38
+ parentheses -= 1;
39
+ else if (char === "[")
40
+ brackets += 1;
41
+ else if (char === "]")
42
+ brackets -= 1;
43
+ else if (char === "," && !parentheses && !brackets) {
44
+ result.push(selector.trim()), selector = "";
45
+ continue;
46
+ }
47
+ selector += char;
48
+ }
49
+ return result.push(selector.trim()), result;
50
+ };
51
+
52
+ // src/preview/rewriteStyleSheet.ts
53
+ var pseudoStates = Object.values(PSEUDO_STATES), pseudoStatesPattern = `${EXCLUDED_PSEUDO_ESCAPE_SEQUENCE}:(${pseudoStates.join("|")})`, matchOne = new RegExp(pseudoStatesPattern), matchAll = new RegExp(pseudoStatesPattern, "g"), warnings = /* @__PURE__ */ new Set(), warnOnce = (message) => {
54
+ warnings.has(message) || (console.warn(message), warnings.add(message));
55
+ }, replacePseudoStates = (selector, allClass) => {
56
+ let negativeLookbehind = `(?<!(?:${EXCLUDED_PSEUDO_ELEMENT_PATTERNS.join("|")})\\S*)`;
57
+ return pseudoStates.reduce(
58
+ (acc, state) => acc.replace(
59
+ new RegExp(`${negativeLookbehind}${EXCLUDED_PSEUDO_ESCAPE_SEQUENCE}:${state}`, "g"),
60
+ `.pseudo-${state}${allClass ? "-all" : ""}`
61
+ ),
62
+ selector
63
+ );
64
+ }, replacePseudoStatesWithAncestorSelector = (selector, forShadowDOM, additionalHostSelectors) => {
65
+ let extracted = extractPseudoStates(selector);
66
+ if (extracted.states.length === 0 && !additionalHostSelectors)
67
+ return selector;
68
+ let selectors = `${additionalHostSelectors ?? ""}${extracted.states.map((s) => `.pseudo-${s}-all`).join("")}`, { withoutPseudoStates } = extracted;
69
+ return withoutPseudoStates = withoutPseudoStates.replace(":host-context(*)", "").trimStart(), withoutPseudoStates.startsWith(":host-context(") ? withoutPseudoStates.replace(/(?<=:host-context\(\S+)\)/, `)${selectors}`) : forShadowDOM ? `:host(${selectors}) ${withoutPseudoStates}` : `${selectors} ${withoutPseudoStates}`;
70
+ }, extractPseudoStates = (selector) => {
71
+ let states = /* @__PURE__ */ new Set(), withoutPseudoStates = selector.replace(matchAll, (_, state) => (states.add(state), "")).replaceAll(/(?<!is)\(\)/g, "(*)").replace(/(?<=[\s(]),\s+|(,\s+)+(?=\))/g, "") || "*";
72
+ return {
73
+ states: Array.from(states),
74
+ withoutPseudoStates
75
+ };
76
+ }, rewriteNotSelectors = (selector, forShadowDOM) => [...selector.matchAll(/:not\(([^)]+)\)/g)].reduce((acc, match) => {
77
+ let originalNot = match[0], selectorList = match[1], rewrittenNot = rewriteNotSelector(selectorList, forShadowDOM);
78
+ return acc.replace(originalNot, rewrittenNot);
79
+ }, selector), rewriteNotSelector = (negatedSelectorList, forShadowDOM) => {
80
+ let rewrittenSelectors = [];
81
+ for (let negatedSelector of negatedSelectorList.split(/,\s*/))
82
+ rewrittenSelectors.push(replacePseudoStatesWithAncestorSelector(negatedSelector, forShadowDOM));
83
+ return `:not(${rewrittenSelectors.join(", ")})`;
84
+ }, rewriteRule = ({ cssText, selectorText }, forShadowDOM) => cssText.replace(
85
+ selectorText,
86
+ splitSelectors(selectorText).flatMap((selector) => {
87
+ if (selector.includes(".pseudo-"))
88
+ return [];
89
+ let replacementSelectors = [selector];
90
+ if (!matchOne.test(selector))
91
+ return replacementSelectors;
92
+ let classSelector = replacePseudoStates(selector);
93
+ classSelector !== selector && replacementSelectors.push(classSelector);
94
+ let ancestorSelector = "";
95
+ if (selector.startsWith(":host(")) {
96
+ let matches = selector.match(/^:host\((\S+)\)\s+(.+)$/);
97
+ if (matches && matchOne.test(matches[2])) {
98
+ let hostInnerSelector = matches[1], descendantSelector = matches[2];
99
+ hostInnerSelector = replacePseudoStates(hostInnerSelector, !0), descendantSelector = rewriteNotSelectors(descendantSelector, !0), ancestorSelector = replacePseudoStatesWithAncestorSelector(
100
+ descendantSelector,
101
+ !0,
102
+ hostInnerSelector
103
+ );
104
+ } else
105
+ ancestorSelector = replacePseudoStates(selector, !0);
106
+ } else {
107
+ let withNotsReplaced = rewriteNotSelectors(selector, forShadowDOM);
108
+ ancestorSelector = replacePseudoStatesWithAncestorSelector(
109
+ withNotsReplaced,
110
+ forShadowDOM
111
+ );
112
+ }
113
+ return replacementSelectors.push(ancestorSelector), replacementSelectors;
114
+ }).join(", ")
115
+ ), rewriteStyleSheet = (sheet, forShadowDOM = !1) => {
116
+ try {
117
+ let count = rewriteRuleContainer(sheet, 1e3, forShadowDOM);
118
+ return count >= 1e3 && warnOnce("Reached maximum of 1000 pseudo selectors per sheet, skipping the rest."), count > 0;
119
+ } catch (e) {
120
+ return String(e).includes("cssRules") ? warnOnce(`Can't access cssRules, likely due to CORS restrictions: ${sheet.href}`) : console.error(e, sheet.href), !1;
121
+ }
122
+ }, rewriteRuleContainer = (ruleContainer, rewriteLimit, forShadowDOM) => {
123
+ let count = 0, index = -1;
124
+ for (let cssRule of ruleContainer.cssRules) {
125
+ index++;
126
+ let numRewritten = 0;
127
+ if (cssRule.__processed)
128
+ numRewritten = cssRule.__pseudoStatesRewrittenCount;
129
+ else {
130
+ if ("cssRules" in cssRule && cssRule.cssRules.length)
131
+ numRewritten = rewriteRuleContainer(
132
+ cssRule,
133
+ rewriteLimit - count,
134
+ forShadowDOM
135
+ );
136
+ else {
137
+ if (!("selectorText" in cssRule))
138
+ continue;
139
+ let styleRule = cssRule;
140
+ if (matchOne.test(styleRule.selectorText)) {
141
+ let newRule = rewriteRule(styleRule, forShadowDOM);
142
+ ruleContainer.deleteRule(index), ruleContainer.insertRule(newRule, index), numRewritten = 1;
143
+ }
144
+ }
145
+ cssRule.__processed = !0, cssRule.__pseudoStatesRewrittenCount = numRewritten;
146
+ }
147
+ if (count += numRewritten, count >= rewriteLimit)
148
+ break;
149
+ }
150
+ return count;
151
+ };
152
+
153
+ // src/preview/withPseudoState.ts
154
+ var channel = addons.getChannel(), shadowHosts = /* @__PURE__ */ new Set(), applyClasses = (element, classnames) => {
155
+ Object.values(PSEUDO_STATES).forEach((state) => {
156
+ element.classList.remove(`pseudo-${state}`), element.classList.remove(`pseudo-${state}-all`);
157
+ }), classnames.forEach((classname) => element.classList.add(classname));
158
+ };
159
+ function querySelectorPiercingShadowDOM(root, selector) {
160
+ let results = [];
161
+ return root.querySelectorAll("*").forEach((el) => {
162
+ el.shadowRoot && results.push(...querySelectorPiercingShadowDOM(el.shadowRoot, selector));
163
+ }), results.push(...root.querySelectorAll(selector).values()), results;
164
+ }
165
+ var applyParameter = (rootElement, parameter = {}) => {
166
+ let map = /* @__PURE__ */ new Map([[rootElement, /* @__PURE__ */ new Set()]]), add = (target, state) => map.set(target, /* @__PURE__ */ new Set([...map.get(target) || [], state]));
167
+ Object.entries(parameter || {}).forEach(([state, value]) => {
168
+ typeof value == "boolean" ? value && add(rootElement, `${state}-all`) : typeof value == "string" ? querySelectorPiercingShadowDOM(rootElement, value).forEach((el) => add(el, state)) : Array.isArray(value) && value.forEach(
169
+ (sel) => querySelectorPiercingShadowDOM(rootElement, sel).forEach((el) => add(el, state))
170
+ );
171
+ }), map.forEach((states, target) => {
172
+ let classnames = /* @__PURE__ */ new Set();
173
+ states.forEach((key) => {
174
+ let keyWithoutAll = key.replace("-all", "");
175
+ PSEUDO_STATES[key] ? classnames.add(`pseudo-${PSEUDO_STATES[key]}`) : PSEUDO_STATES[keyWithoutAll] && classnames.add(`pseudo-${PSEUDO_STATES[keyWithoutAll]}-all`);
176
+ }), applyClasses(target, classnames);
177
+ });
178
+ }, updateShadowHost = (shadowHost) => {
179
+ let classnames = /* @__PURE__ */ new Set();
180
+ shadowHost.className.split(" ").filter((classname) => classname.match(/^pseudo-(.(?!-all))+$/)).forEach((classname) => classnames.add(classname));
181
+ for (let node = shadowHost.parentNode; node; ) {
182
+ if (node instanceof ShadowRoot) {
183
+ node = node.host;
184
+ continue;
185
+ }
186
+ if (node instanceof Element) {
187
+ let element = node;
188
+ element.className && element.className.split(" ").filter((classname) => classname.match(/^pseudo-.+-all$/) !== null).forEach((classname) => classnames.add(classname));
189
+ }
190
+ node = node.parentNode;
191
+ }
192
+ applyClasses(shadowHost, classnames);
193
+ }, pseudoConfig = (parameter) => {
194
+ let { rootSelector, ...pseudoStateConfig } = parameter || {};
195
+ return pseudoStateConfig;
196
+ }, equals = (a = {}, b = {}) => a !== null && b !== null && Object.keys(a).length === Object.keys(b).length && Object.keys(a).every(
197
+ (key) => JSON.stringify(a[key]) === JSON.stringify(b[key])
198
+ ), withPseudoState = (StoryFn, { viewMode, parameters, id, globals: globalsArgs }) => {
199
+ let { pseudo: parameter } = parameters, { pseudo: globals } = globalsArgs, { rootSelector } = parameter || {}, rootElement = useMemo(() => rootSelector ? document.querySelector(rootSelector) : viewMode === "docs" ? document.getElementById(`story--${id}`) : document.getElementById("storybook-root") || // Storybook 7.0+
200
+ document.getElementById("root"), [rootSelector, viewMode, id]), globalsRef = useRef(globals);
201
+ return useEffect(() => {
202
+ let config = pseudoConfig(parameter);
203
+ viewMode === "story" && !equals(config, globalsRef.current) && channel.emit(UPDATE_GLOBALS, {
204
+ globals: { pseudo: config }
205
+ });
206
+ }, [parameter, viewMode]), useEffect(() => {
207
+ if (!rootElement)
208
+ return;
209
+ let timeout = setTimeout(() => {
210
+ applyParameter(rootElement, globals || pseudoConfig(parameter)), shadowHosts.forEach(updateShadowHost);
211
+ }, 0);
212
+ return () => clearTimeout(timeout);
213
+ }, [rootElement, globals, parameter]), StoryFn();
214
+ }, rewriteStyleSheets = (shadowRoot) => {
215
+ let styleSheets = Array.from(shadowRoot ? shadowRoot.styleSheets : document.styleSheets);
216
+ shadowRoot?.adoptedStyleSheets?.length && (styleSheets = shadowRoot.adoptedStyleSheets), styleSheets.forEach((sheet) => rewriteStyleSheet(sheet, !!shadowRoot)), shadowRoot && shadowHosts && shadowHosts.add(shadowRoot.host);
217
+ };
218
+ channel.on(STORY_CHANGED, () => shadowHosts.clear());
219
+ channel.on(STORY_RENDERED, () => rewriteStyleSheets());
220
+ channel.on(GLOBALS_UPDATED, () => rewriteStyleSheets());
221
+ channel.on(FORCE_RE_RENDER, () => rewriteStyleSheets());
222
+ channel.on(FORCE_REMOUNT, () => rewriteStyleSheets());
223
+ channel.on(DOCS_RENDERED, () => rewriteStyleSheets());
224
+ Element.prototype.attachShadow && (Element.prototype._attachShadow = Element.prototype.attachShadow, Element.prototype.attachShadow = function(init) {
225
+ let shadowRoot = this._attachShadow({ ...init, mode: "open" });
226
+ return requestAnimationFrame(() => {
227
+ rewriteStyleSheets(shadowRoot), shadowHosts.has(shadowRoot.host) && updateShadowHost(shadowRoot.host);
228
+ }), shadowRoot;
229
+ });
230
+
231
+ // src/preview.ts
232
+ var decorators = [withPseudoState], initialGlobals = {
233
+ [PARAM_KEY]: !1
234
+ };
235
+
236
+ export {
237
+ decorators,
238
+ initialGlobals,
239
+ preview_exports
240
+ };
@@ -1,17 +1,11 @@
1
1
  var __defProp = Object.defineProperty;
2
- var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
2
  var __export = (target, all) => {
4
3
  for (var name in all)
5
- __defProp(target, name, { get: all[name], enumerable: true });
4
+ __defProp(target, name, { get: all[name], enumerable: !0 });
6
5
  };
7
6
 
8
7
  // src/constants.ts
9
- var ADDON_ID = "storybook/pseudo-states";
10
- var TOOL_ID = `${ADDON_ID}/tool`;
11
- var PARAM_KEY = "pseudo";
12
- var EXCLUDED_PSEUDO_ELEMENT_PATTERNS = ["::-(webkit|moz|ms)-[a-z-]+", "::part\\([^)]+\\)"];
13
- var EXCLUDED_PSEUDO_ESCAPE_SEQUENCE = "(?<=(?<!\\\\)(?:\\\\\\\\)*)";
14
- var PSEUDO_STATES = {
8
+ var ADDON_ID = "storybook/pseudo-states", TOOL_ID = `${ADDON_ID}/tool`, PARAM_KEY = "pseudo", EXCLUDED_PSEUDO_ELEMENT_PATTERNS = ["::-(webkit|moz|ms)-[a-z-]+", "::part\\([^)]+\\)"], EXCLUDED_PSEUDO_ESCAPE_SEQUENCE = "(?<=(?<!\\\\)(?:\\\\\\\\)*)", PSEUDO_STATES = {
15
9
  hover: "hover",
16
10
  active: "active",
17
11
  focusVisible: "focus-visible",
@@ -24,7 +18,6 @@ var PSEUDO_STATES = {
24
18
  };
25
19
 
26
20
  export {
27
- __name,
28
21
  __export,
29
22
  ADDON_ID,
30
23
  TOOL_ID,
package/dist/index.js CHANGED
@@ -1,14 +1,13 @@
1
1
  import {
2
2
  preview_exports
3
- } from "./_browser-chunks/chunk-5GW7LIKW.js";
3
+ } from "./_browser-chunks/chunk-7YGVKEB6.js";
4
4
  import {
5
- PARAM_KEY,
6
- __name
7
- } from "./_browser-chunks/chunk-7CQCSQMX.js";
5
+ PARAM_KEY
6
+ } from "./_browser-chunks/chunk-FLRMKMJW.js";
8
7
 
9
8
  // src/index.ts
10
9
  import { definePreviewAddon } from "storybook/internal/csf";
11
- var index_default = /* @__PURE__ */ __name(() => definePreviewAddon(preview_exports), "default");
10
+ var index_default = () => definePreviewAddon(preview_exports);
12
11
  export {
13
12
  PARAM_KEY,
14
13
  index_default as default
package/dist/manager.js CHANGED
@@ -2,77 +2,50 @@ import {
2
2
  ADDON_ID,
3
3
  PARAM_KEY,
4
4
  PSEUDO_STATES,
5
- TOOL_ID,
6
- __name
7
- } from "./_browser-chunks/chunk-7CQCSQMX.js";
5
+ TOOL_ID
6
+ } from "./_browser-chunks/chunk-FLRMKMJW.js";
8
7
 
9
8
  // src/manager.ts
10
9
  import { addons, types } from "storybook/manager-api";
11
10
 
12
11
  // src/manager/PseudoStateTool.tsx
13
- import React, { useCallback } from "react";
14
- import { Form, IconButton, TooltipLinkList, WithTooltip } from "storybook/internal/components";
15
- import { ButtonIcon, RefreshIcon } from "@storybook/icons";
12
+ import React from "react";
13
+ import { Select } from "storybook/internal/components";
14
+ import { ButtonIcon } from "@storybook/icons";
16
15
  import { useGlobals } from "storybook/manager-api";
17
- import { color, styled } from "storybook/theming";
18
- var LinkTitle = styled.span(({ active }) => ({
19
- color: active ? color.secondary : "inherit"
20
- }));
21
- var options = Object.keys(PSEUDO_STATES).sort();
22
- var PseudoStateTool = /* @__PURE__ */ __name(() => {
23
- const [globals, updateGlobals] = useGlobals();
24
- const pseudo = globals[PARAM_KEY];
25
- const isActive = useCallback(
26
- (option) => {
27
- if (!pseudo) {
28
- return false;
29
- }
30
- return pseudo[option] === true;
31
- },
32
- [pseudo]
33
- );
34
- const hasActive = options.some(isActive);
35
- const reset = {
36
- id: "reset",
37
- title: "Reset pseudo states",
38
- icon: React.createElement(RefreshIcon, { style: { opacity: hasActive ? 1 : 0.7 } }),
39
- disabled: !hasActive,
40
- onClick: /* @__PURE__ */ __name(() => updateGlobals({ [PARAM_KEY]: {} }), "onClick")
41
- };
42
- const toggleOption = useCallback(
43
- (option) => () => {
44
- const { [option]: value, ...rest } = pseudo;
45
- updateGlobals({ [PARAM_KEY]: value === true ? rest : { ...rest, [option]: true } });
46
- },
47
- [pseudo, updateGlobals]
48
- );
49
- const links = options.map((option) => {
50
- const active = isActive(option);
51
- return {
52
- id: option,
53
- title: React.createElement(LinkTitle, { active }, ":", PSEUDO_STATES[option]),
54
- input: React.createElement(Form.Checkbox, { checked: active, onChange: toggleOption(option) }),
55
- active
56
- };
57
- });
16
+ var pseudoStates = Object.keys(PSEUDO_STATES).sort(), PseudoStateTool = () => {
17
+ let [globals, updateGlobals] = useGlobals(), defaultOptions = Object.keys(globals[PARAM_KEY] || {}).filter(
18
+ (key) => pseudoStates.includes(key)
19
+ ), options = pseudoStates.map((option) => ({
20
+ title: `:${PSEUDO_STATES[option]}`,
21
+ value: option
22
+ }));
58
23
  return React.createElement(
59
- WithTooltip,
24
+ Select,
60
25
  {
61
- placement: "top",
62
- trigger: "click",
63
- closeOnOutsideClick: true,
64
- tooltip: React.createElement(TooltipLinkList, { links: [[reset], links] })
65
- },
66
- React.createElement(IconButton, { key: "pseudo-states", title: "Select CSS pseudo states", active: hasActive }, React.createElement(ButtonIcon, null))
26
+ resetLabel: "Reset pseudo states",
27
+ onReset: () => updateGlobals({ [PARAM_KEY]: {} }),
28
+ icon: React.createElement(ButtonIcon, null),
29
+ ariaLabel: "CSS pseudo states",
30
+ tooltip: "Apply CSS pseudo states",
31
+ defaultOptions,
32
+ options,
33
+ multiSelect: !0,
34
+ onChange: (selected) => {
35
+ updateGlobals({
36
+ [PARAM_KEY]: selected.reduce((acc, curr) => ({ ...acc, [curr]: !0 }), {})
37
+ });
38
+ }
39
+ }
67
40
  );
68
- }, "PseudoStateTool");
41
+ };
69
42
 
70
43
  // src/manager.ts
71
44
  addons.register(ADDON_ID, () => {
72
45
  addons.add(TOOL_ID, {
73
46
  type: types.TOOL,
74
47
  title: "CSS pseudo states",
75
- match: /* @__PURE__ */ __name(({ viewMode }) => viewMode === "story", "match"),
48
+ match: ({ viewMode }) => viewMode === "story",
76
49
  render: PseudoStateTool
77
50
  });
78
51
  });
package/dist/preview.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  decorators,
3
3
  initialGlobals
4
- } from "./_browser-chunks/chunk-5GW7LIKW.js";
5
- import "./_browser-chunks/chunk-7CQCSQMX.js";
4
+ } from "./_browser-chunks/chunk-7YGVKEB6.js";
5
+ import "./_browser-chunks/chunk-FLRMKMJW.js";
6
6
  export {
7
7
  decorators,
8
8
  initialGlobals
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "storybook-addon-pseudo-states",
3
- "version": "10.1.0-alpha.8",
3
+ "version": "10.1.0-beta.0",
4
4
  "description": "Storybook Pseudo-states addon: Manipulate CSS pseudo states",
5
5
  "keywords": [
6
6
  "storybook",
@@ -55,13 +55,13 @@
55
55
  "prep": "jiti ../../../scripts/build/build-package.ts"
56
56
  },
57
57
  "devDependencies": {
58
- "@storybook/icons": "^1.6.0",
58
+ "@storybook/icons": "^2.0.0",
59
59
  "react": "^18.2.0",
60
60
  "react-dom": "^18.2.0",
61
61
  "typescript": "^5.8.3"
62
62
  },
63
63
  "peerDependencies": {
64
- "storybook": "^10.1.0-alpha.8"
64
+ "storybook": "^10.1.0-beta.0"
65
65
  },
66
66
  "publishConfig": {
67
67
  "access": "public"
@@ -1,369 +0,0 @@
1
- import {
2
- EXCLUDED_PSEUDO_ELEMENT_PATTERNS,
3
- EXCLUDED_PSEUDO_ESCAPE_SEQUENCE,
4
- PARAM_KEY,
5
- PSEUDO_STATES,
6
- __export,
7
- __name
8
- } from "./chunk-7CQCSQMX.js";
9
-
10
- // src/preview.ts
11
- var preview_exports = {};
12
- __export(preview_exports, {
13
- decorators: () => decorators,
14
- initialGlobals: () => initialGlobals
15
- });
16
-
17
- // src/preview/withPseudoState.ts
18
- import {
19
- DOCS_RENDERED,
20
- FORCE_REMOUNT,
21
- FORCE_RE_RENDER,
22
- GLOBALS_UPDATED,
23
- STORY_CHANGED,
24
- STORY_RENDERED,
25
- UPDATE_GLOBALS
26
- } from "storybook/internal/core-events";
27
- import { addons, useEffect, useMemo, useRef } from "storybook/preview-api";
28
-
29
- // src/preview/splitSelectors.ts
30
- var isAtRule = /* @__PURE__ */ __name((selector) => selector.indexOf("@") === 0, "isAtRule");
31
- var splitSelectors = /* @__PURE__ */ __name((selectors) => {
32
- if (isAtRule(selectors)) {
33
- return [selectors];
34
- }
35
- const result = [];
36
- let parentheses = 0;
37
- let brackets = 0;
38
- let selector = "";
39
- for (let i = 0, len = selectors.length; i < len; i++) {
40
- const char = selectors[i];
41
- if (char === "(") {
42
- parentheses += 1;
43
- } else if (char === ")") {
44
- parentheses -= 1;
45
- } else if (char === "[") {
46
- brackets += 1;
47
- } else if (char === "]") {
48
- brackets -= 1;
49
- } else if (char === ",") {
50
- if (!parentheses && !brackets) {
51
- result.push(selector.trim());
52
- selector = "";
53
- continue;
54
- }
55
- }
56
- selector += char;
57
- }
58
- result.push(selector.trim());
59
- return result;
60
- }, "splitSelectors");
61
-
62
- // src/preview/rewriteStyleSheet.ts
63
- var pseudoStates = Object.values(PSEUDO_STATES);
64
- var pseudoStatesPattern = `${EXCLUDED_PSEUDO_ESCAPE_SEQUENCE}:(${pseudoStates.join("|")})`;
65
- var matchOne = new RegExp(pseudoStatesPattern);
66
- var matchAll = new RegExp(pseudoStatesPattern, "g");
67
- var warnings = /* @__PURE__ */ new Set();
68
- var warnOnce = /* @__PURE__ */ __name((message) => {
69
- if (warnings.has(message)) {
70
- return;
71
- }
72
- console.warn(message);
73
- warnings.add(message);
74
- }, "warnOnce");
75
- var replacePseudoStates = /* @__PURE__ */ __name((selector, allClass) => {
76
- const negativeLookbehind = `(?<!(?:${EXCLUDED_PSEUDO_ELEMENT_PATTERNS.join("|")})\\S*)`;
77
- return pseudoStates.reduce(
78
- (acc, state) => acc.replace(
79
- new RegExp(`${negativeLookbehind}${EXCLUDED_PSEUDO_ESCAPE_SEQUENCE}:${state}`, "g"),
80
- `.pseudo-${state}${allClass ? "-all" : ""}`
81
- ),
82
- selector
83
- );
84
- }, "replacePseudoStates");
85
- var replacePseudoStatesWithAncestorSelector = /* @__PURE__ */ __name((selector, forShadowDOM, additionalHostSelectors) => {
86
- const extracted = extractPseudoStates(selector);
87
- if (extracted.states.length === 0 && !additionalHostSelectors) {
88
- return selector;
89
- }
90
- const selectors = `${additionalHostSelectors ?? ""}${extracted.states.map((s) => `.pseudo-${s}-all`).join("")}`;
91
- let { withoutPseudoStates } = extracted;
92
- withoutPseudoStates = withoutPseudoStates.replace(":host-context(*)", "").trimStart();
93
- return withoutPseudoStates.startsWith(":host-context(") ? withoutPseudoStates.replace(/(?<=:host-context\(\S+)\)/, `)${selectors}`) : forShadowDOM ? `:host(${selectors}) ${withoutPseudoStates}` : `${selectors} ${withoutPseudoStates}`;
94
- }, "replacePseudoStatesWithAncestorSelector");
95
- var extractPseudoStates = /* @__PURE__ */ __name((selector) => {
96
- const states = /* @__PURE__ */ new Set();
97
- const withoutPseudoStates = selector.replace(matchAll, (_, state) => {
98
- states.add(state);
99
- return "";
100
- }).replaceAll(/(?<!is)\(\)/g, "(*)").replace(/(?<=[\s(]),\s+|(,\s+)+(?=\))/g, "") || "*";
101
- return {
102
- states: Array.from(states),
103
- withoutPseudoStates
104
- };
105
- }, "extractPseudoStates");
106
- var rewriteNotSelectors = /* @__PURE__ */ __name((selector, forShadowDOM) => {
107
- return [...selector.matchAll(/:not\(([^)]+)\)/g)].reduce((acc, match) => {
108
- const originalNot = match[0];
109
- const selectorList = match[1];
110
- const rewrittenNot = rewriteNotSelector(selectorList, forShadowDOM);
111
- return acc.replace(originalNot, rewrittenNot);
112
- }, selector);
113
- }, "rewriteNotSelectors");
114
- var rewriteNotSelector = /* @__PURE__ */ __name((negatedSelectorList, forShadowDOM) => {
115
- const rewrittenSelectors = [];
116
- for (const negatedSelector of negatedSelectorList.split(/,\s*/)) {
117
- rewrittenSelectors.push(replacePseudoStatesWithAncestorSelector(negatedSelector, forShadowDOM));
118
- }
119
- return `:not(${rewrittenSelectors.join(", ")})`;
120
- }, "rewriteNotSelector");
121
- var rewriteRule = /* @__PURE__ */ __name(({ cssText, selectorText }, forShadowDOM) => {
122
- return cssText.replace(
123
- selectorText,
124
- splitSelectors(selectorText).flatMap((selector) => {
125
- if (selector.includes(".pseudo-")) {
126
- return [];
127
- }
128
- const replacementSelectors = [selector];
129
- if (!matchOne.test(selector)) {
130
- return replacementSelectors;
131
- }
132
- const classSelector = replacePseudoStates(selector);
133
- if (classSelector !== selector) {
134
- replacementSelectors.push(classSelector);
135
- }
136
- let ancestorSelector = "";
137
- if (selector.startsWith(":host(")) {
138
- const matches = selector.match(/^:host\((\S+)\)\s+(.+)$/);
139
- if (matches && matchOne.test(matches[2])) {
140
- let hostInnerSelector = matches[1];
141
- let descendantSelector = matches[2];
142
- hostInnerSelector = replacePseudoStates(hostInnerSelector, true);
143
- descendantSelector = rewriteNotSelectors(descendantSelector, true);
144
- ancestorSelector = replacePseudoStatesWithAncestorSelector(
145
- descendantSelector,
146
- true,
147
- hostInnerSelector
148
- );
149
- } else {
150
- ancestorSelector = replacePseudoStates(selector, true);
151
- }
152
- } else {
153
- const withNotsReplaced = rewriteNotSelectors(selector, forShadowDOM);
154
- ancestorSelector = replacePseudoStatesWithAncestorSelector(
155
- withNotsReplaced,
156
- forShadowDOM
157
- );
158
- }
159
- replacementSelectors.push(ancestorSelector);
160
- return replacementSelectors;
161
- }).join(", ")
162
- );
163
- }, "rewriteRule");
164
- var rewriteStyleSheet = /* @__PURE__ */ __name((sheet, forShadowDOM = false) => {
165
- try {
166
- const maximumRulesToRewrite = 1e3;
167
- const count = rewriteRuleContainer(sheet, maximumRulesToRewrite, forShadowDOM);
168
- if (count >= maximumRulesToRewrite) {
169
- warnOnce("Reached maximum of 1000 pseudo selectors per sheet, skipping the rest.");
170
- }
171
- return count > 0;
172
- } catch (e) {
173
- if (String(e).includes("cssRules")) {
174
- warnOnce(`Can't access cssRules, likely due to CORS restrictions: ${sheet.href}`);
175
- } else {
176
- console.error(e, sheet.href);
177
- }
178
- return false;
179
- }
180
- }, "rewriteStyleSheet");
181
- var rewriteRuleContainer = /* @__PURE__ */ __name((ruleContainer, rewriteLimit, forShadowDOM) => {
182
- let count = 0;
183
- let index = -1;
184
- for (const cssRule of ruleContainer.cssRules) {
185
- index++;
186
- let numRewritten = 0;
187
- if (cssRule.__processed) {
188
- numRewritten = cssRule.__pseudoStatesRewrittenCount;
189
- } else {
190
- if ("cssRules" in cssRule && cssRule.cssRules.length) {
191
- numRewritten = rewriteRuleContainer(
192
- cssRule,
193
- rewriteLimit - count,
194
- forShadowDOM
195
- );
196
- } else {
197
- if (!("selectorText" in cssRule)) {
198
- continue;
199
- }
200
- const styleRule = cssRule;
201
- if (matchOne.test(styleRule.selectorText)) {
202
- const newRule = rewriteRule(styleRule, forShadowDOM);
203
- ruleContainer.deleteRule(index);
204
- ruleContainer.insertRule(newRule, index);
205
- numRewritten = 1;
206
- }
207
- }
208
- cssRule.__processed = true;
209
- cssRule.__pseudoStatesRewrittenCount = numRewritten;
210
- }
211
- count += numRewritten;
212
- if (count >= rewriteLimit) {
213
- break;
214
- }
215
- }
216
- return count;
217
- }, "rewriteRuleContainer");
218
-
219
- // src/preview/withPseudoState.ts
220
- var channel = addons.getChannel();
221
- var shadowHosts = /* @__PURE__ */ new Set();
222
- var applyClasses = /* @__PURE__ */ __name((element, classnames) => {
223
- Object.values(PSEUDO_STATES).forEach((state) => {
224
- element.classList.remove(`pseudo-${state}`);
225
- element.classList.remove(`pseudo-${state}-all`);
226
- });
227
- classnames.forEach((classname) => element.classList.add(classname));
228
- }, "applyClasses");
229
- function querySelectorPiercingShadowDOM(root, selector) {
230
- const results = [];
231
- root.querySelectorAll("*").forEach((el) => {
232
- if (el.shadowRoot) {
233
- results.push(...querySelectorPiercingShadowDOM(el.shadowRoot, selector));
234
- }
235
- });
236
- results.push(...root.querySelectorAll(selector).values());
237
- return results;
238
- }
239
- __name(querySelectorPiercingShadowDOM, "querySelectorPiercingShadowDOM");
240
- var applyParameter = /* @__PURE__ */ __name((rootElement, parameter = {}) => {
241
- const map = /* @__PURE__ */ new Map([[rootElement, /* @__PURE__ */ new Set()]]);
242
- const add = /* @__PURE__ */ __name((target, state) => map.set(target, /* @__PURE__ */ new Set([...map.get(target) || [], state])), "add");
243
- Object.entries(parameter || {}).forEach(([state, value]) => {
244
- if (typeof value === "boolean") {
245
- if (value) {
246
- add(rootElement, `${state}-all`);
247
- }
248
- } else if (typeof value === "string") {
249
- querySelectorPiercingShadowDOM(rootElement, value).forEach((el) => add(el, state));
250
- } else if (Array.isArray(value)) {
251
- value.forEach(
252
- (sel) => querySelectorPiercingShadowDOM(rootElement, sel).forEach((el) => add(el, state))
253
- );
254
- }
255
- });
256
- map.forEach((states, target) => {
257
- const classnames = /* @__PURE__ */ new Set();
258
- states.forEach((key) => {
259
- const keyWithoutAll = key.replace("-all", "");
260
- if (PSEUDO_STATES[key]) {
261
- classnames.add(`pseudo-${PSEUDO_STATES[key]}`);
262
- } else if (PSEUDO_STATES[keyWithoutAll]) {
263
- classnames.add(`pseudo-${PSEUDO_STATES[keyWithoutAll]}-all`);
264
- }
265
- });
266
- applyClasses(target, classnames);
267
- });
268
- }, "applyParameter");
269
- var updateShadowHost = /* @__PURE__ */ __name((shadowHost) => {
270
- const classnames = /* @__PURE__ */ new Set();
271
- shadowHost.className.split(" ").filter((classname) => classname.match(/^pseudo-(.(?!-all))+$/)).forEach((classname) => classnames.add(classname));
272
- for (let node = shadowHost.parentNode; node; ) {
273
- if (node instanceof ShadowRoot) {
274
- node = node.host;
275
- continue;
276
- }
277
- if (node instanceof Element) {
278
- const element = node;
279
- if (element.className) {
280
- element.className.split(" ").filter((classname) => classname.match(/^pseudo-.+-all$/) !== null).forEach((classname) => classnames.add(classname));
281
- }
282
- }
283
- node = node.parentNode;
284
- }
285
- applyClasses(shadowHost, classnames);
286
- }, "updateShadowHost");
287
- var pseudoConfig = /* @__PURE__ */ __name((parameter) => {
288
- const { rootSelector, ...pseudoStateConfig } = parameter || {};
289
- return pseudoStateConfig;
290
- }, "pseudoConfig");
291
- var equals = /* @__PURE__ */ __name((a = {}, b = {}) => a !== null && b !== null && Object.keys(a).length === Object.keys(b).length && Object.keys(a).every(
292
- (key) => JSON.stringify(a[key]) === JSON.stringify(b[key])
293
- ), "equals");
294
- var withPseudoState = /* @__PURE__ */ __name((StoryFn, { viewMode, parameters, id, globals: globalsArgs }) => {
295
- const { pseudo: parameter } = parameters;
296
- const { pseudo: globals } = globalsArgs;
297
- const { rootSelector } = parameter || {};
298
- const rootElement = useMemo(() => {
299
- if (rootSelector) {
300
- return document.querySelector(rootSelector);
301
- }
302
- if (viewMode === "docs") {
303
- return document.getElementById(`story--${id}`);
304
- }
305
- return document.getElementById("storybook-root") || // Storybook 7.0+
306
- document.getElementById("root");
307
- }, [rootSelector, viewMode, id]);
308
- const globalsRef = useRef(globals);
309
- useEffect(() => {
310
- const config = pseudoConfig(parameter);
311
- if (viewMode === "story" && !equals(config, globalsRef.current)) {
312
- channel.emit(UPDATE_GLOBALS, {
313
- globals: { pseudo: config }
314
- });
315
- }
316
- }, [parameter, viewMode]);
317
- useEffect(() => {
318
- if (!rootElement) {
319
- return;
320
- }
321
- const timeout = setTimeout(() => {
322
- applyParameter(rootElement, globals || pseudoConfig(parameter));
323
- shadowHosts.forEach(updateShadowHost);
324
- }, 0);
325
- return () => clearTimeout(timeout);
326
- }, [rootElement, globals, parameter]);
327
- return StoryFn();
328
- }, "withPseudoState");
329
- var rewriteStyleSheets = /* @__PURE__ */ __name((shadowRoot) => {
330
- let styleSheets = Array.from(shadowRoot ? shadowRoot.styleSheets : document.styleSheets);
331
- if (shadowRoot?.adoptedStyleSheets?.length) {
332
- styleSheets = shadowRoot.adoptedStyleSheets;
333
- }
334
- styleSheets.forEach((sheet) => rewriteStyleSheet(sheet, !!shadowRoot));
335
- if (shadowRoot && shadowHosts) {
336
- shadowHosts.add(shadowRoot.host);
337
- }
338
- }, "rewriteStyleSheets");
339
- channel.on(STORY_CHANGED, () => shadowHosts.clear());
340
- channel.on(STORY_RENDERED, () => rewriteStyleSheets());
341
- channel.on(GLOBALS_UPDATED, () => rewriteStyleSheets());
342
- channel.on(FORCE_RE_RENDER, () => rewriteStyleSheets());
343
- channel.on(FORCE_REMOUNT, () => rewriteStyleSheets());
344
- channel.on(DOCS_RENDERED, () => rewriteStyleSheets());
345
- if (Element.prototype.attachShadow) {
346
- Element.prototype._attachShadow = Element.prototype.attachShadow;
347
- Element.prototype.attachShadow = /* @__PURE__ */ __name(function attachShadow(init) {
348
- const shadowRoot = this._attachShadow({ ...init, mode: "open" });
349
- requestAnimationFrame(() => {
350
- rewriteStyleSheets(shadowRoot);
351
- if (shadowHosts.has(shadowRoot.host)) {
352
- updateShadowHost(shadowRoot.host);
353
- }
354
- });
355
- return shadowRoot;
356
- }, "attachShadow");
357
- }
358
-
359
- // src/preview.ts
360
- var decorators = [withPseudoState];
361
- var initialGlobals = {
362
- [PARAM_KEY]: false
363
- };
364
-
365
- export {
366
- decorators,
367
- initialGlobals,
368
- preview_exports
369
- };