storybook
Version:
Storybook: Develop, document, and test UI components in isolation
1,094 lines (1,066 loc) • 75.3 kB
JavaScript
import {
DEFAULT_BACKGROUNDS,
PARAM_KEY as PARAM_KEY2,
PARAM_KEY2 as PARAM_KEY3,
PARAM_KEY3 as PARAM_KEY4
} from "../_browser-chunks/chunk-FNXWN6IK.js";
import {
composeConfigs,
composeStory,
mountDestructured,
normalizeArrays,
normalizeProjectAnnotations
} from "../_browser-chunks/chunk-SS2NHR7W.js";
import "../_browser-chunks/chunk-IPA5A322.js";
import "../_browser-chunks/chunk-3OXGAGBE.js";
import {
combineParameters
} from "../_browser-chunks/chunk-VYJQ7RU5.js";
import "../_browser-chunks/chunk-3IAH5M2U.js";
import "../_browser-chunks/chunk-QKODTO7K.js";
import {
invariant
} from "../_browser-chunks/chunk-AS2HQEYC.js";
import "../_browser-chunks/chunk-YKE5S47A.js";
import "../_browser-chunks/chunk-AIOS4NGK.js";
import "../_browser-chunks/chunk-GFLS4VP3.js";
import "../_browser-chunks/chunk-WJYERY3R.js";
import {
dedent
} from "../_browser-chunks/chunk-JP7NCOJX.js";
import {
HIGHLIGHT,
MAX_Z_INDEX,
MIN_TOUCH_AREA_SIZE,
REMOVE_HIGHLIGHT,
RESET_HIGHLIGHT,
SCROLL_INTO_VIEW
} from "../_browser-chunks/chunk-KJHJLCBK.js";
import "../_browser-chunks/chunk-ECQ75MKQ.js";
import {
action
} from "../_browser-chunks/chunk-EUVGDK4H.js";
import "../_browser-chunks/chunk-6XWLIJQL.js";
import {
PARAM_KEY
} from "../_browser-chunks/chunk-SL75JR6Y.js";
import {
__commonJS,
__export,
__toESM
} from "../_browser-chunks/chunk-A242L54C.js";
// ../node_modules/@ngard/tiny-isequal/index.js
var require_tiny_isequal = __commonJS({
"../node_modules/@ngard/tiny-isequal/index.js"(exports) {
Object.defineProperty(exports, "__esModule", { value: !0 }), exports.isEqual = /* @__PURE__ */ (function() {
var e = Object.prototype.toString, r = Object.getPrototypeOf, t = Object.getOwnPropertySymbols ? function(e2) {
return Object.keys(e2).concat(Object.getOwnPropertySymbols(e2));
} : Object.keys;
return function(n, a) {
return (function n2(a2, c, u) {
var i, s, l, o = e.call(a2), f = e.call(c);
if (a2 === c) return !0;
if (a2 == null || c == null) return !1;
if (u.indexOf(a2) > -1 && u.indexOf(c) > -1) return !0;
if (u.push(a2, c), o != f || (i = t(a2), s = t(c), i.length != s.length || i.some(function(e2) {
return !n2(a2[e2], c[e2], u);
}))) return !1;
switch (o.slice(8, -1)) {
case "Symbol":
return a2.valueOf() == c.valueOf();
case "Date":
case "Number":
return +a2 == +c || +a2 != +a2 && +c != +c;
case "RegExp":
case "Function":
case "String":
case "Boolean":
return "" + a2 == "" + c;
case "Set":
case "Map":
i = a2.entries(), s = c.entries();
do
if (!n2((l = i.next()).value, s.next().value, u)) return !1;
while (!l.done);
return !0;
case "ArrayBuffer":
a2 = new Uint8Array(a2), c = new Uint8Array(c);
case "DataView":
a2 = new Uint8Array(a2.buffer), c = new Uint8Array(c.buffer);
case "Float32Array":
case "Float64Array":
case "Int8Array":
case "Int16Array":
case "Int32Array":
case "Uint8Array":
case "Uint16Array":
case "Uint32Array":
case "Uint8ClampedArray":
case "Arguments":
case "Array":
if (a2.length != c.length) return !1;
for (l = 0; l < a2.length; l++) if ((l in a2 || l in c) && (l in a2 != l in c || !n2(a2[l], c[l], u))) return !1;
return !0;
case "Object":
return n2(r(a2), r(c), u);
default:
return !1;
}
})(n, a, []);
};
})();
}
});
// src/csf/toStartCaseStr.ts
function toStartCaseStr(str) {
return str.replace(/_/g, " ").replace(/-/g, " ").replace(/\./g, " ").replace(/([^\n])([A-Z])([a-z])/g, (str2, $1, $2, $3) => `${$1} ${$2}${$3}`).replace(/([a-z])([A-Z])/g, (str2, $1, $2) => `${$1} ${$2}`).replace(/([a-z])([0-9])/gi, (str2, $1, $2) => `${$1} ${$2}`).replace(/([0-9])([a-z])/gi, (str2, $1, $2) => `${$1} ${$2}`).replace(/(\s|^)(\w)/g, (str2, $1, $2) => `${$1}${$2.toUpperCase()}`).replace(/ +/g, " ").trim();
}
// src/csf/includeConditionalArg.ts
var import_tiny_isequal = __toESM(require_tiny_isequal(), 1), count = (vals) => vals.map((v) => typeof v < "u").filter(Boolean).length, testValue = (cond, value) => {
let { exists, eq, neq, truthy } = cond;
if (count([exists, eq, neq, truthy]) > 1)
throw new Error(`Invalid conditional test ${JSON.stringify({ exists, eq, neq })}`);
if (typeof eq < "u")
return (0, import_tiny_isequal.isEqual)(value, eq);
if (typeof neq < "u")
return !(0, import_tiny_isequal.isEqual)(value, neq);
if (typeof exists < "u") {
let valueExists = typeof value < "u";
return exists ? valueExists : !valueExists;
}
return (typeof truthy > "u" ? !0 : truthy) ? !!value : !value;
}, includeConditionalArg = (argType, args, globals) => {
if (!argType.if)
return !0;
let { arg, global: global5 } = argType.if;
if (count([arg, global5]) !== 1)
throw new Error(`Invalid conditional value ${JSON.stringify({ arg, global: global5 })}`);
let value = arg ? args[arg] : globals[global5];
return testValue(argType.if, value);
};
// src/csf/csf-factories.ts
import { combineTags } from "storybook/internal/csf";
// src/actions/preview.ts
import { definePreviewAddon } from "storybook/internal/csf";
// src/actions/addArgs.ts
var addArgs_exports = {};
__export(addArgs_exports, {
argsEnhancers: () => argsEnhancers
});
// src/actions/addArgsHelpers.ts
var isInInitialArgs = (name, initialArgs) => typeof initialArgs[name] > "u" && !(name in initialArgs), inferActionsFromArgTypesRegex = (context) => {
let {
initialArgs,
argTypes,
id,
parameters: { actions }
} = context;
if (!actions || actions.disable || !actions.argTypesRegex || !argTypes)
return {};
let argTypesRegex = new RegExp(actions.argTypesRegex);
return Object.entries(argTypes).filter(
([name]) => !!argTypesRegex.test(name)
).reduce((acc, [name, argType]) => (isInInitialArgs(name, initialArgs) && (acc[name] = action(name, { implicit: !0, id })), acc), {});
}, addActionsFromArgTypes = (context) => {
let {
initialArgs,
argTypes,
parameters: { actions }
} = context;
return actions?.disable || !argTypes ? {} : Object.entries(argTypes).filter(([name, argType]) => !!argType.action).reduce((acc, [name, argType]) => (isInInitialArgs(name, initialArgs) && (acc[name] = action(typeof argType.action == "string" ? argType.action : name)), acc), {});
};
// src/actions/addArgs.ts
var argsEnhancers = [
addActionsFromArgTypes,
inferActionsFromArgTypesRegex
];
// src/actions/loaders.ts
var loaders_exports = {};
__export(loaders_exports, {
loaders: () => loaders
});
import { onMockCall } from "storybook/test";
var subscribed = !1, logActionsWhenMockCalled = (context) => {
let { parameters: parameters2 } = context;
parameters2?.actions?.disable || subscribed || (onMockCall((mock, args) => {
let name = mock.getMockName();
name !== "spy" && name !== "vi.fn()" && (!/^next\/.*::/.test(name) || [
"next/router::useRouter()",
"next/navigation::useRouter()",
"next/navigation::redirect",
"next/cache::",
"next/headers::cookies().set",
"next/headers::cookies().delete",
"next/headers::headers().set",
"next/headers::headers().delete"
].some((prefix) => name.startsWith(prefix))) && action(name)(args);
}), subscribed = !0);
}, loaders = [logActionsWhenMockCalled];
// src/actions/preview.ts
var preview_default = () => definePreviewAddon({
...addArgs_exports,
...loaders_exports
});
// src/backgrounds/preview.ts
import { definePreviewAddon as definePreviewAddon2 } from "storybook/internal/csf";
// src/backgrounds/decorator.ts
import { useEffect } from "storybook/preview-api";
// src/backgrounds/utils.ts
var { document: document2 } = globalThis, isReduceMotionEnabled = () => globalThis?.matchMedia ? !!globalThis.matchMedia("(prefers-reduced-motion: reduce)")?.matches : !1, clearStyles = (selector) => {
(Array.isArray(selector) ? selector : [selector]).forEach(clearStyle);
}, clearStyle = (selector) => {
if (!document2)
return;
let element = document2.getElementById(selector);
element && element.parentElement && element.parentElement.removeChild(element);
}, addGridStyle = (selector, css) => {
if (!document2)
return;
let existingStyle = document2.getElementById(selector);
if (existingStyle)
existingStyle.innerHTML !== css && (existingStyle.innerHTML = css);
else {
let style = document2.createElement("style");
style.setAttribute("id", selector), style.innerHTML = css, document2.head.appendChild(style);
}
}, addBackgroundStyle = (selector, css, storyId) => {
if (!document2)
return;
let existingStyle = document2.getElementById(selector);
if (existingStyle)
existingStyle.innerHTML !== css && (existingStyle.innerHTML = css);
else {
let style = document2.createElement("style");
style.setAttribute("id", selector), style.innerHTML = css;
let gridStyleSelector = `addon-backgrounds-grid${storyId ? `-docs-${storyId}` : ""}`, existingGridStyle = document2.getElementById(gridStyleSelector);
existingGridStyle ? existingGridStyle.parentElement?.insertBefore(style, existingGridStyle) : document2.head.appendChild(style);
}
};
// src/backgrounds/decorator.ts
var defaultGrid = {
cellSize: 100,
cellAmount: 10,
opacity: 0.8
}, BG_SELECTOR_BASE = "addon-backgrounds", GRID_SELECTOR_BASE = "addon-backgrounds-grid", transitionStyle = isReduceMotionEnabled() ? "" : "transition: background-color 0.3s;", withBackgroundAndGrid = (StoryFn, context) => {
let { globals = {}, parameters: parameters2 = {}, viewMode, id } = context, {
options = DEFAULT_BACKGROUNDS,
disable,
grid = defaultGrid
} = parameters2[PARAM_KEY2] || {}, data = globals[PARAM_KEY2] || {}, backgroundName = typeof data == "string" ? data : data?.value, item = backgroundName ? options[backgroundName] : void 0, value = typeof item == "string" ? item : item?.value || "transparent", showGrid = typeof data == "string" ? !1 : data.grid || !1, shownBackground = !!item && !disable, backgroundSelector = viewMode === "docs" ? `#anchor--${id} .docs-story` : ".sb-show-main", gridSelector = viewMode === "docs" ? `#anchor--${id} .docs-story` : ".sb-show-main", isLayoutPadded = parameters2.layout === void 0 || parameters2.layout === "padded", defaultOffset = viewMode === "docs" ? 20 : isLayoutPadded ? 16 : 0, { cellAmount, cellSize, opacity, offsetX = defaultOffset, offsetY = defaultOffset } = grid, backgroundSelectorId = viewMode === "docs" ? `${BG_SELECTOR_BASE}-docs-${id}` : `${BG_SELECTOR_BASE}-color`, backgroundTarget = viewMode === "docs" ? id : null;
useEffect(() => {
let backgroundStyles = `
${backgroundSelector} {
background: ${value} !important;
${transitionStyle}
}`;
if (!shownBackground) {
clearStyles(backgroundSelectorId);
return;
}
addBackgroundStyle(backgroundSelectorId, backgroundStyles, backgroundTarget);
}, [backgroundSelector, backgroundSelectorId, backgroundTarget, shownBackground, value]);
let gridSelectorId = viewMode === "docs" ? `${GRID_SELECTOR_BASE}-docs-${id}` : `${GRID_SELECTOR_BASE}`;
return useEffect(() => {
if (!showGrid) {
clearStyles(gridSelectorId);
return;
}
let gridSize = [
`${cellSize * cellAmount}px ${cellSize * cellAmount}px`,
`${cellSize * cellAmount}px ${cellSize * cellAmount}px`,
`${cellSize}px ${cellSize}px`,
`${cellSize}px ${cellSize}px`
].join(", "), gridStyles = `
${gridSelector} {
background-size: ${gridSize} !important;
background-position: ${offsetX}px ${offsetY}px, ${offsetX}px ${offsetY}px, ${offsetX}px ${offsetY}px, ${offsetX}px ${offsetY}px !important;
background-blend-mode: difference !important;
background-image: linear-gradient(rgba(130, 130, 130, ${opacity}) 1px, transparent 1px),
linear-gradient(90deg, rgba(130, 130, 130, ${opacity}) 1px, transparent 1px),
linear-gradient(rgba(130, 130, 130, ${opacity / 2}) 1px, transparent 1px),
linear-gradient(90deg, rgba(130, 130, 130, ${opacity / 2}) 1px, transparent 1px) !important;
}
`;
addGridStyle(gridSelectorId, gridStyles);
}, [cellAmount, cellSize, gridSelector, gridSelectorId, showGrid, offsetX, offsetY, opacity]), StoryFn();
};
// src/backgrounds/preview.ts
var decorators = globalThis.FEATURES?.backgrounds ? [withBackgroundAndGrid] : [], parameters = {
[PARAM_KEY2]: {
grid: {
cellSize: 20,
opacity: 0.5,
cellAmount: 5
},
disable: !1
}
}, initialGlobals = {
[PARAM_KEY2]: { value: void 0, grid: !1 }
}, preview_default2 = () => definePreviewAddon2({
decorators,
parameters,
initialGlobals
});
// src/component-testing/preview.ts
import { definePreviewAddon as definePreviewAddon3 } from "storybook/internal/csf";
import { instrument } from "storybook/internal/instrumenter";
var { step } = instrument(
{
// It seems like the label is unused, but the instrumenter has access to it
// The context will be bounded later in StoryRender, so that the user can write just:
// await step("label", (context) => {
// // labeled step
// });
step: async (label, play, context) => play(context)
},
{ intercept: !0 }
), preview_default3 = () => definePreviewAddon3({
parameters: {
throwPlayFunctionExceptions: !1
},
runStep: step
});
// src/highlight/preview.ts
import { definePreviewAddon as definePreviewAddon4 } from "storybook/internal/csf";
import { addons } from "storybook/preview-api";
// src/highlight/useHighlights.ts
import { STORY_RENDER_PHASE_CHANGED } from "storybook/internal/core-events";
// src/highlight/icons.ts
var iconPaths = {
chevronLeft: [
"M9.10355 10.1464C9.29882 10.3417 9.29882 10.6583 9.10355 10.8536C8.90829 11.0488 8.59171 11.0488 8.39645 10.8536L4.89645 7.35355C4.70118 7.15829 4.70118 6.84171 4.89645 6.64645L8.39645 3.14645C8.59171 2.95118 8.90829 2.95118 9.10355 3.14645C9.29882 3.34171 9.29882 3.65829 9.10355 3.85355L5.95711 7L9.10355 10.1464Z"
],
chevronRight: [
"M4.89645 10.1464C4.70118 10.3417 4.70118 10.6583 4.89645 10.8536C5.09171 11.0488 5.40829 11.0488 5.60355 10.8536L9.10355 7.35355C9.29882 7.15829 9.29882 6.84171 9.10355 6.64645L5.60355 3.14645C5.40829 2.95118 5.09171 2.95118 4.89645 3.14645C4.70118 3.34171 4.70118 3.65829 4.89645 3.85355L8.04289 7L4.89645 10.1464Z"
],
info: [
"M7 5.5a.5.5 0 01.5.5v4a.5.5 0 01-1 0V6a.5.5 0 01.5-.5zM7 4.5A.75.75 0 107 3a.75.75 0 000 1.5z",
"M7 14A7 7 0 107 0a7 7 0 000 14zm0-1A6 6 0 107 1a6 6 0 000 12z"
],
shareAlt: [
"M2 1.004a1 1 0 00-1 1v10a1 1 0 001 1h10a1 1 0 001-1v-4.5a.5.5 0 00-1 0v4.5H2v-10h4.5a.5.5 0 000-1H2z",
"M7.354 7.357L12 2.711v1.793a.5.5 0 001 0v-3a.5.5 0 00-.5-.5h-3a.5.5 0 100 1h1.793L6.646 6.65a.5.5 0 10.708.707z"
]
};
// src/highlight/utils.ts
var svgElements = "svg,path,rect,circle,line,polyline,polygon,ellipse,text".split(","), createElement = (type, props = {}, children) => {
let element = svgElements.includes(type) ? document.createElementNS("http://www.w3.org/2000/svg", type) : document.createElement(type);
return Object.entries(props).forEach(([key, val]) => {
/[A-Z]/.test(key) ? (key === "onClick" && (element.addEventListener("click", val), element.addEventListener("keydown", (e) => {
(e.key === "Enter" || e.key === " ") && (e.preventDefault(), val());
})), key === "onMouseEnter" && element.addEventListener("mouseenter", val), key === "onMouseLeave" && element.addEventListener("mouseleave", val)) : element.setAttribute(key, val);
}), children?.forEach((child) => {
if (!(child == null || child === !1))
try {
element.appendChild(child);
} catch {
element.appendChild(document.createTextNode(String(child)));
}
}), element;
}, createIcon = (name) => iconPaths[name] && createElement(
"svg",
{ width: "14", height: "14", viewBox: "0 0 14 14", xmlns: "http://www.w3.org/2000/svg" },
iconPaths[name].map(
(d) => createElement("path", {
fill: "currentColor",
"fill-rule": "evenodd",
"clip-rule": "evenodd",
d
})
)
), normalizeOptions = (options) => {
if ("elements" in options) {
let { elements, color, style } = options;
return {
id: void 0,
priority: 0,
selectors: elements,
styles: {
outline: `2px ${style} ${color}`,
outlineOffset: "2px",
boxShadow: "0 0 0 6px rgba(255,255,255,0.6)"
},
menu: void 0
};
}
let { menu, ...rest } = options;
return {
id: void 0,
priority: 0,
styles: {
outline: "2px dashed #029cfd"
},
...rest,
menu: Array.isArray(menu) ? menu.every(Array.isArray) ? menu : [menu] : void 0
};
}, isFunction = (obj) => obj instanceof Function, state = /* @__PURE__ */ new Map(), listeners = /* @__PURE__ */ new Map(), teardowns = /* @__PURE__ */ new Map(), useStore = (initialValue) => {
let key = Symbol();
return listeners.set(key, []), state.set(key, initialValue), { get: () => state.get(key), set: (update) => {
let current = state.get(key), next = isFunction(update) ? update(current) : update;
next !== current && (state.set(key, next), listeners.get(key)?.forEach((listener) => {
teardowns.get(listener)?.(), teardowns.set(listener, listener(next));
}));
}, subscribe: (listener) => (listeners.get(key)?.push(listener), () => {
let list = listeners.get(key);
list && listeners.set(
key,
list.filter((l) => l !== listener)
);
}), teardown: () => {
listeners.get(key)?.forEach((listener) => {
teardowns.get(listener)?.(), teardowns.delete(listener);
}), listeners.delete(key), state.delete(key);
} };
}, mapElements = (highlights) => {
let root = document.getElementById("storybook-root"), map = /* @__PURE__ */ new Map();
for (let highlight of highlights) {
let { priority = 0 } = highlight;
for (let selector of highlight.selectors) {
let elements = [
...document.querySelectorAll(
// Elements matching the selector, excluding storybook elements and their descendants.
// Necessary to find portaled elements (e.g. children of `body`).
`:is(${selector}):not([id^="storybook-"], [id^="storybook-"] *, [class^="sb-"], [class^="sb-"] *)`
),
// Elements matching the selector inside the storybook root, as these were excluded above.
...root?.querySelectorAll(selector) || []
];
for (let element of elements) {
let existing = map.get(element);
(!existing || existing.priority <= priority) && map.set(element, {
...highlight,
priority,
selectors: Array.from(new Set((existing?.selectors || []).concat(selector)))
});
}
}
}
return map;
}, mapBoxes = (elements) => Array.from(elements.entries()).map(([element, { selectors, styles, hoverStyles, focusStyles, menu }]) => {
let { top, left, width, height } = element.getBoundingClientRect(), { position } = getComputedStyle(element);
return {
element,
selectors,
styles,
hoverStyles,
focusStyles,
menu,
top: position === "fixed" ? top : top + window.scrollY,
left: position === "fixed" ? left : left + window.scrollX,
width,
height
};
}).sort((a, b) => b.width * b.height - a.width * a.height), isOverMenu = (menuElement, coordinates) => {
let menu = menuElement.getBoundingClientRect(), { x, y } = coordinates;
return menu?.top && menu?.left && x >= menu.left && x <= menu.left + menu.width && y >= menu.top && y <= menu.top + menu.height;
}, isTargeted = (box, boxElement, coordinates) => {
if (!boxElement || !coordinates)
return !1;
let { left, top, width, height } = box;
height < MIN_TOUCH_AREA_SIZE && (top = top - Math.round((MIN_TOUCH_AREA_SIZE - height) / 2), height = MIN_TOUCH_AREA_SIZE), width < MIN_TOUCH_AREA_SIZE && (left = left - Math.round((MIN_TOUCH_AREA_SIZE - width) / 2), width = MIN_TOUCH_AREA_SIZE), boxElement.style.position === "fixed" && (left += window.scrollX, top += window.scrollY);
let { x, y } = coordinates;
return x >= left && x <= left + width && y >= top && y <= top + height;
}, keepInViewport = (element, targetCoordinates, options = {}) => {
let { x, y } = targetCoordinates, { margin = 5, topOffset = 0, centered = !1 } = options, { scrollX, scrollY, innerHeight: windowHeight, innerWidth: windowWidth } = window, top = Math.min(
element.style.position === "fixed" ? y - scrollY : y,
windowHeight - element.clientHeight - margin - topOffset + scrollY
), leftOffset = centered ? element.clientWidth / 2 : 0, left = element.style.position === "fixed" ? Math.max(Math.min(x - scrollX, windowWidth - leftOffset - margin), leftOffset + margin) : Math.max(
Math.min(x, windowWidth - leftOffset - margin + scrollX),
leftOffset + margin + scrollX
);
Object.assign(element.style, {
...left !== x && { left: `${left}px` },
...top !== y && { top: `${top}px` }
});
}, showPopover = (element) => {
window.HTMLElement.prototype.hasOwnProperty("showPopover") && element.showPopover();
}, hidePopover = (element) => {
window.HTMLElement.prototype.hasOwnProperty("showPopover") && element.hidePopover();
}, getEventDetails = (target) => ({
top: target.top,
left: target.left,
width: target.width,
height: target.height,
selectors: target.selectors,
element: {
attributes: Object.fromEntries(
Array.from(target.element.attributes).map((attr) => [attr.name, attr.value])
),
localName: target.element.localName,
tagName: target.element.tagName,
outerHTML: target.element.outerHTML
}
});
// src/highlight/useHighlights.ts
var menuId = "storybook-highlights-menu", rootId = "storybook-highlights-root", storybookRootId = "storybook-root", useHighlights = (channel) => {
if (globalThis.__STORYBOOK_HIGHLIGHT_INITIALIZED)
return;
globalThis.__STORYBOOK_HIGHLIGHT_INITIALIZED = !0;
let { document: document3 } = globalThis, highlights = useStore([]), elements = useStore(/* @__PURE__ */ new Map()), boxes = useStore([]), clickCoords = useStore(), hoverCoords = useStore(), targets = useStore([]), hovered = useStore([]), focused = useStore(), selected = useStore(), root = document3.getElementById(rootId);
highlights.subscribe(() => {
root || (root = createElement("div", { id: rootId }), document3.body.appendChild(root));
}), highlights.subscribe((value) => {
let storybookRoot = document3.getElementById(storybookRootId);
if (!storybookRoot)
return;
elements.set(mapElements(value));
let observer = new MutationObserver(() => elements.set(mapElements(value)));
return observer.observe(storybookRoot, { subtree: !0, childList: !0 }), () => {
observer.disconnect();
};
}), elements.subscribe((value) => {
let updateBoxes = () => requestAnimationFrame(() => boxes.set(mapBoxes(value))), observer = new ResizeObserver(updateBoxes);
observer.observe(document3.body), Array.from(value.keys()).forEach((element) => observer.observe(element));
let scrollers = Array.from(document3.body.querySelectorAll("*")).filter((el) => {
let { overflow, overflowX, overflowY } = window.getComputedStyle(el);
return ["auto", "scroll"].some((o) => [overflow, overflowX, overflowY].includes(o));
});
return scrollers.forEach((element) => element.addEventListener("scroll", updateBoxes)), () => {
observer.disconnect(), scrollers.forEach((element) => element.removeEventListener("scroll", updateBoxes));
};
}), elements.subscribe((value) => {
let sticky = Array.from(value.keys()).filter(({ style }) => style.position === "sticky"), updateBoxes = () => requestAnimationFrame(() => {
boxes.set(
(current) => current.map((box) => {
if (sticky.includes(box.element)) {
let { top, left } = box.element.getBoundingClientRect();
return { ...box, top: top + window.scrollY, left: left + window.scrollX };
}
return box;
})
);
});
return document3.addEventListener("scroll", updateBoxes), () => document3.removeEventListener("scroll", updateBoxes);
}), elements.subscribe((value) => {
targets.set((t) => t.filter(({ element }) => value.has(element)));
}), targets.subscribe((value) => {
value.length ? (selected.set((s) => value.some((t) => t.element === s?.element) ? s : void 0), focused.set((s) => value.some((t) => t.element === s?.element) ? s : void 0)) : (selected.set(void 0), focused.set(void 0), clickCoords.set(void 0));
});
let styleElementByHighlight = new Map(/* @__PURE__ */ new Map());
highlights.subscribe((value) => {
value.forEach(({ keyframes }) => {
if (keyframes) {
let style = styleElementByHighlight.get(keyframes);
style || (style = document3.createElement("style"), style.setAttribute("data-highlight", "keyframes"), styleElementByHighlight.set(keyframes, style), document3.head.appendChild(style)), style.innerHTML = keyframes;
}
}), styleElementByHighlight.forEach((style, keyframes) => {
value.some((v) => v.keyframes === keyframes) || (style.remove(), styleElementByHighlight.delete(keyframes));
});
});
let boxElementByTargetElement = new Map(/* @__PURE__ */ new Map());
boxes.subscribe((value) => {
value.forEach((box) => {
let boxElement = boxElementByTargetElement.get(box.element);
if (root && !boxElement) {
let props = {
popover: "manual",
"data-highlight-dimensions": `w${box.width.toFixed(0)}h${box.height.toFixed(0)}`,
"data-highlight-coordinates": `x${box.left.toFixed(0)}y${box.top.toFixed(0)}`
};
boxElement = root.appendChild(
createElement("div", props, [createElement("div")])
), boxElementByTargetElement.set(box.element, boxElement);
}
}), boxElementByTargetElement.forEach((box, element) => {
value.some(({ element: e }) => e === element) || (box.remove(), boxElementByTargetElement.delete(element));
});
}), boxes.subscribe((value) => {
let targetable = value.filter((box) => box.menu);
if (!targetable.length)
return;
let onClick = (event) => {
requestAnimationFrame(() => {
let menu = document3.getElementById(menuId), coords = { x: event.pageX, y: event.pageY };
if (menu && !isOverMenu(menu, coords)) {
let results = targetable.filter((box) => {
let boxElement = boxElementByTargetElement.get(box.element);
return isTargeted(box, boxElement, coords);
});
clickCoords.set(results.length ? coords : void 0), targets.set(results);
}
});
};
return document3.addEventListener("click", onClick), () => document3.removeEventListener("click", onClick);
});
let updateHovered = () => {
let menu = document3.getElementById(menuId), coords = hoverCoords.get();
!coords || menu && isOverMenu(menu, coords) || hovered.set((current) => {
let update = boxes.get().filter((box) => {
let boxElement = boxElementByTargetElement.get(box.element);
return isTargeted(box, boxElement, coords);
}), existing = current.filter((box) => update.includes(box)), additions = update.filter((box) => !current.includes(box)), hasRemovals = current.length - existing.length;
return additions.length || hasRemovals ? [...existing, ...additions] : current;
});
};
hoverCoords.subscribe(updateHovered), boxes.subscribe(updateHovered);
let updateBoxStyles = () => {
let selectedElement = selected.get(), targetElements = selectedElement ? [selectedElement] : targets.get(), focusedElement = targetElements.length === 1 ? targetElements[0] : focused.get(), isMenuOpen = clickCoords.get() !== void 0;
boxes.get().forEach((box) => {
let boxElement = boxElementByTargetElement.get(box.element);
if (boxElement) {
let isFocused = focusedElement === box, isHovered = isMenuOpen ? focusedElement ? isFocused : targetElements.includes(box) : hovered.get()?.includes(box);
Object.assign(boxElement.style, {
animation: "none",
background: "transparent",
border: "none",
boxSizing: "border-box",
outline: "none",
outlineOffset: "0px",
...box.styles,
...isHovered ? box.hoverStyles : {},
...isFocused ? box.focusStyles : {},
position: getComputedStyle(box.element).position === "fixed" ? "fixed" : "absolute",
zIndex: MAX_Z_INDEX - 10,
top: `${box.top}px`,
left: `${box.left}px`,
width: `${box.width}px`,
height: `${box.height}px`,
margin: 0,
padding: 0,
cursor: box.menu && isHovered ? "pointer" : "default",
pointerEvents: box.menu ? "auto" : "none",
display: "flex",
alignItems: "center",
justifyContent: "center",
overflow: "visible"
}), Object.assign(boxElement.children[0].style, {
width: "100%",
height: "100%",
minHeight: `${MIN_TOUCH_AREA_SIZE}px`,
minWidth: `${MIN_TOUCH_AREA_SIZE}px`,
boxSizing: "content-box",
padding: boxElement.style.outlineWidth || "0px"
}), showPopover(boxElement);
}
});
};
boxes.subscribe(updateBoxStyles), targets.subscribe(updateBoxStyles), hovered.subscribe(updateBoxStyles), focused.subscribe(updateBoxStyles), selected.subscribe(updateBoxStyles);
let renderMenu = () => {
if (!root)
return;
let menu = document3.getElementById(menuId);
if (menu)
menu.innerHTML = "";
else {
let props = { id: menuId, popover: "manual" };
menu = root.appendChild(createElement("div", props)), root.appendChild(
createElement("style", {}, [
`
#${menuId} {
position: absolute;
z-index: ${MAX_Z_INDEX};
width: 300px;
padding: 0px;
margin: 15px 0 0 0;
transform: translateX(-50%);
font-family: "Nunito Sans", -apple-system, ".SFNSText-Regular", "San Francisco", BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 12px;
background: white;
border: none;
border-radius: 6px;
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.05), 0 5px 15px 0 rgba(0, 0, 0, 0.1);
color: #2E3438;
}
#${menuId} ul {
list-style: none;
margin: 0;
padding: 0;
}
#${menuId} > ul {
max-height: 300px;
overflow-y: auto;
padding: 4px 0;
}
#${menuId} li {
padding: 0 4px;
margin: 0;
}
#${menuId} li > :not(ul) {
display: flex;
padding: 8px;
margin: 0;
align-items: center;
gap: 8px;
border-radius: 4px;
}
#${menuId} button {
width: 100%;
border: 0;
background: transparent;
color: inherit;
text-align: left;
font-family: inherit;
font-size: inherit;
}
#${menuId} button:focus-visible {
outline-color: #029CFD;
}
#${menuId} button:hover {
background: rgba(2, 156, 253, 0.07);
color: #029CFD;
cursor: pointer;
}
#${menuId} li code {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
line-height: 16px;
font-size: 11px;
}
#${menuId} li svg {
flex-shrink: 0;
margin: 1px;
color: #73828C;
}
#${menuId} li > button:hover svg, #${menuId} li > button:focus-visible svg {
color: #029CFD;
}
#${menuId} .element-list li svg {
display: none;
}
#${menuId} li.selectable svg, #${menuId} li.selected svg {
display: block;
}
#${menuId} .menu-list {
border-top: 1px solid rgba(38, 85, 115, 0.15);
}
#${menuId} .menu-list > li:not(:last-child) {
padding-bottom: 4px;
margin-bottom: 4px;
border-bottom: 1px solid rgba(38, 85, 115, 0.15);
}
#${menuId} .menu-items, #${menuId} .menu-items li {
padding: 0;
}
#${menuId} .menu-item {
display: flex;
}
#${menuId} .menu-item-content {
display: flex;
flex-direction: column;
flex-grow: 1;
}
`
])
);
}
let selectedElement = selected.get(), elementList = selectedElement ? [selectedElement] : targets.get();
if (elementList.length && (menu.style.position = getComputedStyle(elementList[0].element).position === "fixed" ? "fixed" : "absolute", menu.appendChild(
createElement(
"ul",
{ class: "element-list" },
elementList.map((target) => {
let selectable = elementList.length > 1 && !!target.menu?.some(
(group) => group.some(
(item) => !item.selectors || item.selectors.some((s) => target.selectors.includes(s))
)
), props = selectable ? {
class: "selectable",
onClick: () => selected.set(target),
onMouseEnter: () => focused.set(target),
onMouseLeave: () => focused.set(void 0)
} : selectedElement ? { class: "selected", onClick: () => selected.set(void 0) } : {}, asButton = selectable || selectedElement;
return createElement("li", props, [
createElement(asButton ? "button" : "div", asButton ? { type: "button" } : {}, [
selectedElement ? createIcon("chevronLeft") : null,
createElement("code", {}, [target.element.outerHTML]),
selectable ? createIcon("chevronRight") : null
])
]);
})
)
)), selected.get() || targets.get().length === 1) {
let target = selected.get() || targets.get()[0], menuGroups = target.menu?.filter(
(group) => group.some(
(item) => !item.selectors || item.selectors.some((s) => target.selectors.includes(s))
)
);
menuGroups?.length && menu.appendChild(
createElement(
"ul",
{ class: "menu-list" },
menuGroups.map(
(menuItems) => createElement("li", {}, [
createElement(
"ul",
{ class: "menu-items" },
menuItems.map(
({ id, title, description, iconLeft, iconRight, clickEvent: event }) => {
let onClick = event && (() => channel.emit(event, id, getEventDetails(target)));
return createElement("li", {}, [
createElement(
onClick ? "button" : "div",
onClick ? { class: "menu-item", type: "button", onClick } : { class: "menu-item" },
[
iconLeft ? createIcon(iconLeft) : null,
createElement("div", { class: "menu-item-content" }, [
createElement(description ? "strong" : "span", {}, [title]),
description && createElement("span", {}, [description])
]),
iconRight ? createIcon(iconRight) : null
]
)
]);
}
)
)
])
)
)
);
}
let coords = clickCoords.get();
coords ? (Object.assign(menu.style, {
display: "block",
left: `${menu.style.position === "fixed" ? coords.x - window.scrollX : coords.x}px`,
top: `${menu.style.position === "fixed" ? coords.y - window.scrollY : coords.y}px`
}), showPopover(menu), requestAnimationFrame(() => keepInViewport(menu, coords, { topOffset: 15, centered: !0 }))) : (hidePopover(menu), Object.assign(menu.style, { display: "none" }));
};
targets.subscribe(renderMenu), selected.subscribe(renderMenu);
let addHighlight = (highlight) => {
let info = normalizeOptions(highlight);
highlights.set((value) => {
let others = info.id ? value.filter((h) => h.id !== info.id) : value;
return info.selectors?.length ? [...others, info] : others;
});
}, removeHighlight = (id) => {
id && highlights.set((value) => value.filter((h) => h.id !== id));
}, resetState = () => {
highlights.set([]), elements.set(/* @__PURE__ */ new Map()), boxes.set([]), clickCoords.set(void 0), hoverCoords.set(void 0), targets.set([]), hovered.set([]), focused.set(void 0), selected.set(void 0);
}, removeTimeout, scrollIntoView = (target, options) => {
let id = "scrollIntoView-highlight";
clearTimeout(removeTimeout), removeHighlight(id);
let element = document3.querySelector(target);
if (!element) {
console.warn(`Cannot scroll into view: ${target} not found`);
return;
}
element.scrollIntoView({ behavior: "smooth", block: "center", ...options });
let keyframeName = `kf-${Math.random().toString(36).substring(2, 15)}`;
highlights.set((value) => [
...value,
{
id,
priority: 1e3,
selectors: [target],
styles: {
outline: "2px solid #1EA7FD",
outlineOffset: "-1px",
animation: `${keyframeName} 3s linear forwards`
},
keyframes: `@keyframes ${keyframeName} {
0% { outline: 2px solid #1EA7FD; }
20% { outline: 2px solid #1EA7FD00; }
40% { outline: 2px solid #1EA7FD; }
60% { outline: 2px solid #1EA7FD00; }
80% { outline: 2px solid #1EA7FD; }
100% { outline: 2px solid #1EA7FD00; }
}`
}
]), removeTimeout = setTimeout(() => removeHighlight(id), 3500);
}, onMouseMove = (event) => {
requestAnimationFrame(() => hoverCoords.set({ x: event.pageX, y: event.pageY }));
};
document3.body.addEventListener("mousemove", onMouseMove), channel.on(HIGHLIGHT, addHighlight), channel.on(REMOVE_HIGHLIGHT, removeHighlight), channel.on(RESET_HIGHLIGHT, resetState), channel.on(SCROLL_INTO_VIEW, scrollIntoView), channel.on(STORY_RENDER_PHASE_CHANGED, ({ newPhase }) => {
newPhase === "loading" && resetState();
});
};
// src/highlight/preview.ts
globalThis?.FEATURES?.highlight && addons?.ready && addons.ready().then(useHighlights);
var preview_default4 = () => definePreviewAddon4({});
// src/measure/preview.ts
import { definePreviewAddon as definePreviewAddon5 } from "storybook/internal/csf";
// src/measure/withMeasure.ts
import { useEffect as useEffect2 } from "storybook/preview-api";
// src/measure/box-model/canvas.ts
import { global } from "@storybook/global";
function getDocumentWidthAndHeight() {
let container = global.document.documentElement, height = Math.max(container.scrollHeight, container.offsetHeight);
return { width: Math.max(container.scrollWidth, container.offsetWidth), height };
}
function createCanvas() {
let canvas = global.document.createElement("canvas");
canvas.id = "storybook-addon-measure";
let context = canvas.getContext("2d");
invariant(context != null);
let { width, height } = getDocumentWidthAndHeight();
return setCanvasWidthAndHeight(canvas, context, { width, height }), canvas.style.position = "absolute", canvas.style.left = "0", canvas.style.top = "0", canvas.style.zIndex = "2147483647", canvas.style.pointerEvents = "none", global.document.body.appendChild(canvas), { canvas, context, width, height };
}
function setCanvasWidthAndHeight(canvas, context, { width, height }) {
canvas.style.width = `${width}px`, canvas.style.height = `${height}px`;
let scale = global.window.devicePixelRatio;
canvas.width = Math.floor(width * scale), canvas.height = Math.floor(height * scale), context.scale(scale, scale);
}
var state2 = {};
function init() {
state2.canvas || (state2 = createCanvas());
}
function clear() {
state2.context && state2.context.clearRect(0, 0, state2.width ?? 0, state2.height ?? 0);
}
function draw(callback) {
clear(), callback(state2.context);
}
function rescale() {
invariant(state2.canvas, "Canvas should exist in the state."), invariant(state2.context, "Context should exist in the state."), setCanvasWidthAndHeight(state2.canvas, state2.context, { width: 0, height: 0 });
let { width, height } = getDocumentWidthAndHeight();
setCanvasWidthAndHeight(state2.canvas, state2.context, { width, height }), state2.width = width, state2.height = height;
}
function destroy() {
state2.canvas && (clear(), state2.canvas.parentNode?.removeChild(state2.canvas), state2 = {});
}
// src/measure/box-model/visualizer.ts
import { global as global2 } from "@storybook/global";
// src/measure/box-model/labels.ts
var colors = {
margin: "#f6b26b",
border: "#ffe599",
padding: "#93c47d",
content: "#6fa8dc",
text: "#232020"
}, labelPadding = 6;
function roundedRect(context, { x, y, w, h, r }) {
x = x - w / 2, y = y - h / 2, w < 2 * r && (r = w / 2), h < 2 * r && (r = h / 2), context.beginPath(), context.moveTo(x + r, y), context.arcTo(x + w, y, x + w, y + h, r), context.arcTo(x + w, y + h, x, y + h, r), context.arcTo(x, y + h, x, y, r), context.arcTo(x, y, x + w, y, r), context.closePath();
}
function positionCoordinate(position, { padding, border, width, height, top, left }) {
let contentWidth = width - border.left - border.right - padding.left - padding.right, contentHeight = height - padding.top - padding.bottom - border.top - border.bottom, x = left + border.left + padding.left, y = top + border.top + padding.top;
return position === "top" ? x += contentWidth / 2 : position === "right" ? (x += contentWidth, y += contentHeight / 2) : position === "bottom" ? (x += contentWidth / 2, y += contentHeight) : position === "left" ? y += contentHeight / 2 : position === "center" && (x += contentWidth / 2, y += contentHeight / 2), { x, y };
}
function offset(type, position, { margin, border, padding }, labelPaddingSize, external) {
let shift = (dir) => 0, offsetX = 0, offsetY = 0, locationMultiplier = external ? 1 : 0.5, labelPaddingShift = external ? labelPaddingSize * 2 : 0;
return type === "padding" ? shift = (dir) => padding[dir] * locationMultiplier + labelPaddingShift : type === "border" ? shift = (dir) => padding[dir] + border[dir] * locationMultiplier + labelPaddingShift : type === "margin" && (shift = (dir) => padding[dir] + border[dir] + margin[dir] * locationMultiplier + labelPaddingShift), position === "top" ? offsetY = -shift("top") : position === "right" ? offsetX = shift("right") : position === "bottom" ? offsetY = shift("bottom") : position === "left" && (offsetX = -shift("left")), { offsetX, offsetY };
}
function collide(a, b) {
return Math.abs(a.x - b.x) < Math.abs(a.w + b.w) / 2 && Math.abs(a.y - b.y) < Math.abs(a.h + b.h) / 2;
}
function overlapAdjustment(position, currentRect, prevRect) {
return position === "top" ? currentRect.y = prevRect.y - prevRect.h - labelPadding : position === "right" ? currentRect.x = prevRect.x + prevRect.w / 2 + labelPadding + currentRect.w / 2 : position === "bottom" ? currentRect.y = prevRect.y + prevRect.h + labelPadding : position === "left" && (currentRect.x = prevRect.x - prevRect.w / 2 - labelPadding - currentRect.w / 2), { x: currentRect.x, y: currentRect.y };
}
function textWithRect(context, type, { x, y, w, h }, text) {
return roundedRect(context, { x, y, w, h, r: 3 }), context.fillStyle = `${colors[type]}dd`, context.fill(), context.strokeStyle = colors[type], context.stroke(), context.fillStyle = colors.text, context.fillText(text, x, y), roundedRect(context, { x, y, w, h, r: 3 }), context.fillStyle = `${colors[type]}dd`, context.fill(), context.strokeStyle = colors[type], context.stroke(), context.fillStyle = colors.text, context.fillText(text, x, y), { x, y, w, h };
}
function configureText(context, text) {
context.font = "600 12px monospace", context.textBaseline = "middle", context.textAlign = "center";
let metrics = context.measureText(text), actualHeight = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent, w = metrics.width + labelPadding * 2, h = actualHeight + labelPadding * 2;
return { w, h };
}
function drawLabel(context, measurements, { type, position = "center", text }, prevRect, external = !1) {
let { x, y } = positionCoordinate(position, measurements), { offsetX, offsetY } = offset(type, position, measurements, labelPadding + 1, external);
x += offsetX, y += offsetY;
let { w, h } = configureText(context, text);
if (prevRect && collide({ x, y, w, h }, prevRect)) {
let adjusted = overlapAdjustment(position, { x, y, w, h }, prevRect);
x = adjusted.x, y = adjusted.y;
}
return textWithRect(context, type, { x, y, w, h }, text);
}
function floatingOffset(alignment, { w, h }) {
let deltaW = w * 0.5 + labelPadding, deltaH = h * 0.5 + labelPadding;
return {
offsetX: (alignment.x === "left" ? -1 : 1) * deltaW,
offsetY: (alignment.y === "top" ? -1 : 1) * deltaH
};
}
function drawFloatingLabel(context, measurements, { type, text }) {
let { floatingAlignment: floatingAlignment2, extremities } = measurements, x = extremities[floatingAlignment2.x], y = extremities[floatingAlignment2.y], { w, h } = configureText(context, text), { offsetX, offsetY } = floatingOffset(floatingAlignment2, {
w,
h
});
return x += offsetX, y += offsetY, textWithRect(context, type, { x, y, w, h }, text);
}
function drawStack(context, measurements, stack, external) {
let rects = [];
stack.forEach((l, idx) => {
let rect = external && l.position === "center" ? drawFloatingLabel(context, measurements, l) : drawLabel(context, measurements, l, rects[idx - 1], external);
rects[idx] = rect;
});
}
function labelStacks(context, measurements, labels, externalLabels) {
let stacks = labels.reduce((acc, l) => (Object.prototype.hasOwnProperty.call(acc, l.position) || (acc[l.position] = []), acc[l.position]?.push(l), acc), {});
stacks.top && drawStack(context, measurements, stacks.top, externalLabels), stacks.right && drawStack(context, measurements, stacks.right, externalLabels), stacks.bottom && drawStack(context, measurements, stacks.bottom, externalLabels), stacks.left && drawStack(context, measurements, stacks.left, externalLabels), stacks.center && drawStack(context, measurements, stacks.center, externalLabels);
}
// src/measure/box-model/visualizer.ts
var colors2 = {
margin: "#f6b26ba8",
border: "#ffe599a8",
padding: "#93c47d8c",
content: "#6fa8dca8"
}, SMALL_NODE_SIZE = 30;
function pxToNumber(px) {
return parseInt(px.replace("px", ""), 10);
}
function round(value) {
return Number.isInteger(value) ? value : value.toFixed(2);
}
function filterZeroValues(labels) {
return labels.filter((l) => l.text !== 0 && l.text !== "0");
}
function floatingAlignment(extremities) {
let windowExtremities = {
top: global2.window.scrollY,
bottom: global2.window.scrollY + global2.window.innerHeight,
left: global2.window.scrollX,
right: global2.window.scrollX + global2.window.innerWidth
}, distances = {
top: Math.abs(windowExtremities.top - extremities.top),
bottom: Math.abs(windowExtremities.bottom - extremities.bottom),
left: Math.abs(windowExtremities.left - extremities.left),
right: Math.abs(windowExtremities.right - extremities.right)
};
return {
x: distances.left > distances.right ? "left" : "right",
y: distances.top > distances.bottom ? "top" : "bottom"
};
}
function measureElement(element) {
let style = global2.getComputedStyle(element), { top, left, right, bottom, width, height } = element.getBoundingClientRect(), {
marginTop,
marginBottom,
marginLeft,
marginRight,
paddingTop,
paddingBottom,
paddingLeft,
paddingRight,
borderBottomWidth,
borderTopWidth,
borderLeftWidth,
borderRightWidth
} = style;
top = top + global2.window.scrollY, left = left + global2.window.scrollX, bottom = bottom + global2.window.scrollY, right = right + global2.window.scrollX;
let margin = {
top: pxToNumber(marginTop),
bottom: pxToNumber(marginBottom),
left: pxToNumber(marginLeft),
right: pxToNumber(marginRight)
}, padding = {
top: pxToNumber(paddingTop),
bottom: pxToNumber(paddingBottom),
left: pxToNumber(paddingLeft),
right: pxToNumber(paddingRight)
}, border = {
top: pxToNumber(borderTopWidth),
bottom: pxToNumber(borderBottomWidth),
left: pxToNumber(borderLeftWidth),
right: pxToNumber(borderRightWidth)
}, extremities = {
top: top - margin.top,
bottom: bottom + margin.bottom,
left: left - margin.left,
right: right + margin.right
};
return {
margin,
padding,
border,
top,
left,
bottom,
right,
width,
height,
extremities,
floatingAlignment: floatingAlignment(extremities)
};
}
function drawMargin(context, { margin, width, height, top, left, bottom,