UNPKG

storybook

Version:

Storybook: Develop, document, and test UI components in isolation

1,083 lines (1,054 loc) • 76.8 kB
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-SZQXB3JV.js"; import "../_browser-chunks/chunk-MEXTPDJG.js"; import { Tag } from "../_browser-chunks/chunk-2GLGVABT.js"; import "../_browser-chunks/chunk-XLJZ7AOP.js"; import { combineParameters } from "../_browser-chunks/chunk-SI6AKD4S.js"; import "../_browser-chunks/chunk-IYCKG66Y.js"; import "../_browser-chunks/chunk-NZMVUW5T.js"; import { invariant } from "../_browser-chunks/chunk-IWQGIXJS.js"; import "../_browser-chunks/chunk-V2VKKSMQ.js"; import "../_browser-chunks/chunk-YK43Z22A.js"; import "../_browser-chunks/chunk-LCHBOIHN.js"; import "../_browser-chunks/chunk-ZCFV7BZB.js"; import { dedent } from "../_browser-chunks/chunk-3LY4VQVK.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, #anchor--primary--${id} .docs-story` : ".sb-show-main", gridSelector = viewMode === "docs" ? `#anchor--${id} .docs-story, #anchor--primary--${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/core-server/utils/ghost-stories/test-annotations.ts import { definePreviewAddon as definePreviewAddon4 } from "storybook/internal/csf"; var isEmptyRender = (element) => { let style = getComputedStyle(element), rect = element.getBoundingClientRect(); return !(rect.width > 0 && rect.height > 0 && style.visibility !== "hidden" && Number(style.opacity) > 0 && style.display !== "none"); }, afterEach = async ({ reporting, canvasElement, globals }) => { try { if (!globals.ghostStories) return; let emptyRender = isEmptyRender(canvasElement.firstElementChild ?? canvasElement); emptyRender && reporting.addReport({ type: "render-analysis", version: 1, result: { emptyRender }, status: "warning" }); } catch { } }, test_annotations_default = () => definePreviewAddon4({ afterEach }); // src/highlight/preview.ts import { definePreviewAddon as definePreviewAddon5 } 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 = () => definePreviewAddon5({}); // src/measure/preview.ts import { definePreviewAddon as definePreviewAddon6 } 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.win