UNPKG

storybook

Version:

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

1,277 lines (1,250 loc) • 123 kB
import { UniversalStore, parse, stringify } from "../_browser-chunks/chunk-JK6U3MQW.js"; import { StatusTypeIdMismatchError } from "../_browser-chunks/chunk-V5NV5R37.js"; import { StatusTypeIdMismatchError as StatusTypeIdMismatchError2 } from "../_browser-chunks/chunk-POMIZRJL.js"; import { StorybookError } from "../_browser-chunks/chunk-JVRDBUUP.js"; import { countBy, dequal, partition } from "../_browser-chunks/chunk-NQJGOFZV.js"; import { Tag } from "../_browser-chunks/chunk-AFVOZMXQ.js"; import { require_main } from "../_browser-chunks/chunk-XLJZ7AOP.js"; import { isEqual } from "../_browser-chunks/chunk-IYCKG66Y.js"; import "../_browser-chunks/chunk-NZMVUW5T.js"; import { mapValues, mergeWith, omit, pick, toMerged } from "../_browser-chunks/chunk-YK43Z22A.js"; import "../_browser-chunks/chunk-LCHBOIHN.js"; import { require_memoizerific } from "../_browser-chunks/chunk-ZCFV7BZB.js"; import { dedent } from "../_browser-chunks/chunk-3LY4VQVK.js"; import { __commonJS, __export, __toESM } from "../_browser-chunks/chunk-A242L54C.js"; // ../../node_modules/toggle-selection/index.js var require_toggle_selection = __commonJS({ "../../node_modules/toggle-selection/index.js"(exports, module) { module.exports = function() { var selection = document.getSelection(); if (!selection.rangeCount) return function() { }; for (var active = document.activeElement, ranges = [], i = 0; i < selection.rangeCount; i++) ranges.push(selection.getRangeAt(i)); switch (active.tagName.toUpperCase()) { // .toUpperCase handles XHTML case "INPUT": case "TEXTAREA": active.blur(); break; default: active = null; break; } return selection.removeAllRanges(), function() { selection.type === "Caret" && selection.removeAllRanges(), selection.rangeCount || ranges.forEach(function(range) { selection.addRange(range); }), active && active.focus(); }; }; } }); // ../../node_modules/copy-to-clipboard/index.js var require_copy_to_clipboard = __commonJS({ "../../node_modules/copy-to-clipboard/index.js"(exports, module) { "use strict"; var deselectCurrent = require_toggle_selection(), clipboardToIE11Formatting = { "text/plain": "Text", "text/html": "Url", default: "Text" }, defaultMessage = "Copy to clipboard: #{key}, Enter"; function format(message) { var copyKey = (/mac os x/i.test(navigator.userAgent) ? "\u2318" : "Ctrl") + "+C"; return message.replace(/#{\s*key\s*}/g, copyKey); } function copy2(text, options) { var debug, message, reselectPrevious, range, selection, mark, success = !1; options || (options = {}), debug = options.debug || !1; try { reselectPrevious = deselectCurrent(), range = document.createRange(), selection = document.getSelection(), mark = document.createElement("span"), mark.textContent = text, mark.ariaHidden = "true", mark.style.all = "unset", mark.style.position = "fixed", mark.style.top = 0, mark.style.clip = "rect(0, 0, 0, 0)", mark.style.whiteSpace = "pre", mark.style.webkitUserSelect = "text", mark.style.MozUserSelect = "text", mark.style.msUserSelect = "text", mark.style.userSelect = "text", mark.addEventListener("copy", function(e) { if (e.stopPropagation(), options.format) if (e.preventDefault(), typeof e.clipboardData > "u") { debug && console.warn("unable to use e.clipboardData"), debug && console.warn("trying IE specific stuff"), window.clipboardData.clearData(); var format2 = clipboardToIE11Formatting[options.format] || clipboardToIE11Formatting.default; window.clipboardData.setData(format2, text); } else e.clipboardData.clearData(), e.clipboardData.setData(options.format, text); options.onCopy && (e.preventDefault(), options.onCopy(e.clipboardData)); }), document.body.appendChild(mark), range.selectNodeContents(mark), selection.addRange(range); var successful = document.execCommand("copy"); if (!successful) throw new Error("copy command was unsuccessful"); success = !0; } catch (err) { debug && console.error("unable to copy using execCommand: ", err), debug && console.warn("trying IE specific stuff"); try { window.clipboardData.setData(options.format || "text", text), options.onCopy && options.onCopy(window.clipboardData), success = !0; } catch (err2) { debug && console.error("unable to copy using clipboardData: ", err2), debug && console.error("falling back to prompt"), message = format("message" in options ? options.message : defaultMessage), window.prompt(message, text); } } finally { selection && (typeof selection.removeRange == "function" ? selection.removeRange(range) : selection.removeAllRanges()), mark && document.body.removeChild(mark), reselectPrevious(); } return success; } module.exports = copy2; } }); // ../../node_modules/picocolors/picocolors.browser.js var require_picocolors_browser = __commonJS({ "../../node_modules/picocolors/picocolors.browser.js"(exports, module) { var x = String, create2 = function() { return { isColorSupported: !1, reset: x, bold: x, dim: x, italic: x, underline: x, inverse: x, hidden: x, strikethrough: x, black: x, red: x, green: x, yellow: x, blue: x, magenta: x, cyan: x, white: x, gray: x, bgBlack: x, bgRed: x, bgGreen: x, bgYellow: x, bgBlue: x, bgMagenta: x, bgCyan: x, bgWhite: x, blackBright: x, redBright: x, greenBright: x, yellowBright: x, blueBright: x, magentaBright: x, cyanBright: x, whiteBright: x, bgBlackBright: x, bgRedBright: x, bgGreenBright: x, bgYellowBright: x, bgBlueBright: x, bgMagentaBright: x, bgCyanBright: x, bgWhiteBright: x }; }; module.exports = create2(); module.exports.createColors = create2; } }); // ../../node_modules/store2/dist/store2.js var require_store2 = __commonJS({ "../../node_modules/store2/dist/store2.js"(exports, module) { (function(window2, define) { var _ = { version: "2.14.4", areas: {}, apis: {}, nsdelim: ".", // utilities inherit: function(api, o) { for (var p in api) o.hasOwnProperty(p) || Object.defineProperty(o, p, Object.getOwnPropertyDescriptor(api, p)); return o; }, stringify: function(d, fn) { return d === void 0 || typeof d == "function" ? d + "" : JSON.stringify(d, fn || _.replace); }, parse: function(s, fn) { try { return JSON.parse(s, fn || _.revive); } catch { return s; } }, // extension hooks fn: function(name, fn) { _.storeAPI[name] = fn; for (var api in _.apis) _.apis[api][name] = fn; }, get: function(area, key) { return area.getItem(key); }, set: function(area, key, string) { area.setItem(key, string); }, remove: function(area, key) { area.removeItem(key); }, key: function(area, i) { return area.key(i); }, length: function(area) { return area.length; }, clear: function(area) { area.clear(); }, // core functions Store: function(id, area, namespace) { var store3 = _.inherit(_.storeAPI, function(key, data, overwrite) { return arguments.length === 0 ? store3.getAll() : typeof data == "function" ? store3.transact(key, data, overwrite) : data !== void 0 ? store3.set(key, data, overwrite) : typeof key == "string" || typeof key == "number" ? store3.get(key) : typeof key == "function" ? store3.each(key) : key ? store3.setAll(key, data) : store3.clear(); }); store3._id = id; try { var testKey = "__store2_test"; area.setItem(testKey, "ok"), store3._area = area, area.removeItem(testKey); } catch { store3._area = _.storage("fake"); } return store3._ns = namespace || "", _.areas[id] || (_.areas[id] = store3._area), _.apis[store3._ns + store3._id] || (_.apis[store3._ns + store3._id] = store3), store3; }, storeAPI: { // admin functions area: function(id, area) { var store3 = this[id]; return (!store3 || !store3.area) && (store3 = _.Store(id, area, this._ns), this[id] || (this[id] = store3)), store3; }, namespace: function(namespace, singleArea, delim) { if (delim = delim || this._delim || _.nsdelim, !namespace) return this._ns ? this._ns.substring(0, this._ns.length - delim.length) : ""; var ns = namespace, store3 = this[ns]; if ((!store3 || !store3.namespace) && (store3 = _.Store(this._id, this._area, this._ns + ns + delim), store3._delim = delim, this[ns] || (this[ns] = store3), !singleArea)) for (var name in _.areas) store3.area(name, _.areas[name]); return store3; }, isFake: function(force) { return force ? (this._real = this._area, this._area = _.storage("fake")) : force === !1 && (this._area = this._real || this._area), this._area.name === "fake"; }, toString: function() { return "store" + (this._ns ? "." + this.namespace() : "") + "[" + this._id + "]"; }, // storage functions has: function(key) { return this._area.has ? this._area.has(this._in(key)) : this._in(key) in this._area; }, size: function() { return this.keys().length; }, each: function(fn, fill) { for (var i = 0, m = _.length(this._area); i < m; i++) { var key = this._out(_.key(this._area, i)); if (key !== void 0 && fn.call(this, key, this.get(key), fill) === !1) break; m > _.length(this._area) && (m--, i--); } return fill || this; }, keys: function(fillList) { return this.each(function(k, v, list) { list.push(k); }, fillList || []); }, get: function(key, alt) { var s = _.get(this._area, this._in(key)), fn; return typeof alt == "function" && (fn = alt, alt = null), s !== null ? _.parse(s, fn) : alt ?? s; }, getAll: function(fillObj) { return this.each(function(k, v, all) { all[k] = v; }, fillObj || {}); }, transact: function(key, fn, alt) { var val = this.get(key, alt), ret = fn(val); return this.set(key, ret === void 0 ? val : ret), this; }, set: function(key, data, overwrite) { var d = this.get(key), replacer; return d != null && overwrite === !1 ? data : (typeof overwrite == "function" && (replacer = overwrite, overwrite = void 0), _.set(this._area, this._in(key), _.stringify(data, replacer), overwrite) || d); }, setAll: function(data, overwrite) { var changed, val; for (var key in data) val = data[key], this.set(key, val, overwrite) !== val && (changed = !0); return changed; }, add: function(key, data, replacer) { var d = this.get(key); if (d instanceof Array) data = d.concat(data); else if (d !== null) { var type = typeof d; if (type === typeof data && type === "object") { for (var k in data) d[k] = data[k]; data = d; } else data = d + data; } return _.set(this._area, this._in(key), _.stringify(data, replacer)), data; }, remove: function(key, alt) { var d = this.get(key, alt); return _.remove(this._area, this._in(key)), d; }, clear: function() { return this._ns ? this.each(function(k) { _.remove(this._area, this._in(k)); }, 1) : _.clear(this._area), this; }, clearAll: function() { var area = this._area; for (var id in _.areas) _.areas.hasOwnProperty(id) && (this._area = _.areas[id], this.clear()); return this._area = area, this; }, // internal use functions _in: function(k) { return typeof k != "string" && (k = _.stringify(k)), this._ns ? this._ns + k : k; }, _out: function(k) { return this._ns ? k && k.indexOf(this._ns) === 0 ? k.substring(this._ns.length) : void 0 : ( // so each() knows to skip it k ); } }, // end _.storeAPI storage: function(name) { return _.inherit(_.storageAPI, { items: {}, name }); }, storageAPI: { length: 0, has: function(k) { return this.items.hasOwnProperty(k); }, key: function(i) { var c = 0; for (var k in this.items) if (this.has(k) && i === c++) return k; }, setItem: function(k, v) { this.has(k) || this.length++, this.items[k] = v; }, removeItem: function(k) { this.has(k) && (delete this.items[k], this.length--); }, getItem: function(k) { return this.has(k) ? this.items[k] : null; }, clear: function() { for (var k in this.items) this.removeItem(k); } } // end _.storageAPI }, store2 = ( // safely set this up (throws error in IE10/32bit mode for local files) _.Store("local", (function() { try { return localStorage; } catch { } })()) ); store2.local = store2, store2._ = _, store2.area("session", (function() { try { return sessionStorage; } catch { } })()), store2.area("page", _.storage("page")), typeof define == "function" && define.amd !== void 0 ? define("store2", [], function() { return store2; }) : typeof module < "u" && module.exports ? module.exports = store2 : (window2.store && (_.conflict = window2.store), window2.store = store2); })(exports, exports && exports.define); } }); // src/manager-api/root.tsx import React4, { Component, Fragment, useCallback as useCallback2, useContext, useEffect, useMemo, useRef as useRef2, useState } from "react"; import { DOCS_PREPARED as DOCS_PREPARED2, SET_STORIES as SET_STORIES2, SHARED_STATE_CHANGED, SHARED_STATE_SET, STORY_CHANGED as STORY_CHANGED2, STORY_PREPARED as STORY_PREPARED2 } from "storybook/internal/core-events"; // src/manager-api/context.ts import { createContext as ReactCreateContext } from "react"; var createContext = ({ api, state }) => ReactCreateContext({ api, state }); // src/manager-api/lib/merge.ts import { logger } from "storybook/internal/client-logger"; var merge_default = (a, ...b) => { let target = {}; target = mergeWith( {}, a, (objValue, srcValue) => { if (Array.isArray(srcValue) && Array.isArray(objValue)) return srcValue.forEach((s) => { objValue.find((o) => o === s || isEqual(o, s)) || objValue.push(s); }), objValue; if (Array.isArray(objValue)) return logger.log(["the types mismatch, picking", objValue]), objValue; } ); for (let obj of b) target = mergeWith(target, obj, (objValue, srcValue) => { if (Array.isArray(srcValue) && Array.isArray(objValue)) return srcValue.forEach((s) => { objValue.find((o) => o === s || isEqual(o, s)) || objValue.push(s); }), objValue; if (Array.isArray(objValue)) return logger.log(["the types mismatch, picking", objValue]), objValue; }); return target; }, noArrayMerge = (a, ...b) => { let target = {}; target = mergeWith( {}, a, (objValue, srcValue) => { if (Array.isArray(srcValue)) return srcValue; } ); for (let obj of b) target = mergeWith(target, obj, (objValue, srcValue) => { if (Array.isArray(srcValue)) return srcValue; }); return target; }; // src/manager-api/initial-state.ts var main = (...additions) => additions.reduce((acc, item) => merge_default(acc, item), {}), initial_state_default = main; // src/manager-api/lib/addons.ts import { logger as logger2 } from "storybook/internal/client-logger"; import { SET_CONFIG } from "storybook/internal/core-events"; import { Addon_TypesEnum } from "storybook/internal/types"; import { global } from "@storybook/global"; // src/manager-api/lib/storybook-channel-mock.ts import { Channel } from "storybook/internal/channels"; function mockChannel() { let transport = { setHandler: () => { }, send: () => { } }; return new Channel({ transport }); } // src/manager-api/lib/addons.ts var AddonStore = class { constructor() { this.loaders = {}; this.elements = {}; this.config = {}; this.getChannel = () => (this.channel || this.setChannel(mockChannel()), this.channel); this.ready = () => this.promise; this.hasChannel = () => !!this.channel; this.setChannel = (channel) => { this.channel = channel, this.resolve(); }; this.setConfig = (value) => { Object.assign(this.config, value), this.hasChannel() ? this.getChannel().emit(SET_CONFIG, this.config) : this.ready().then((channel) => { channel.emit(SET_CONFIG, this.config); }); }; this.getConfig = () => this.config; /** * Registers an addon loader function. * * @param {string} id - The id of the addon loader. * @param {(api: API) => void} callback - The function that will be called to register the addon. * @returns {void} */ this.register = (id, callback) => { this.loaders[id] && logger2.warn(`${id} was loaded twice, this could have bad side-effects`), this.loaders[id] = callback; }; this.loadAddons = (api) => { Object.values(this.loaders).forEach((value) => value(api)); }; this.promise = new Promise((res) => { this.resolve = () => res(this.getChannel()); }); } getElements(type) { return this.elements[type] || (this.elements[type] = {}), this.elements[type]; } /** * Adds an addon to the addon store. * * @param {string} id - The id of the addon. * @param {Addon_Type} addon - The addon to add. * @returns {void} */ add(id, addon) { let { type } = addon, collection = this.getElements(type); collection[id] = { ...addon, id }; } experimental_getRegisteredAddons() { return Object.keys(this.loaders); } }, KEY = "__STORYBOOK_ADDONS_MANAGER"; function getAddonsStore() { return global[KEY] || (global[KEY] = new AddonStore()), global[KEY]; } var addons = getAddonsStore(); // src/manager-api/modules/addons.ts var addons_exports = {}; __export(addons_exports, { ensurePanel: () => ensurePanel, init: () => init }); import { Addon_TypesEnum as Addon_TypesEnum2 } from "storybook/internal/types"; function ensurePanel(panels, selectedPanel, currentPanel) { let keys2 = Object.keys(panels); return keys2.indexOf(selectedPanel) >= 0 ? selectedPanel : keys2.length ? keys2[0] : currentPanel; } var init = ({ provider, store: store2, fullAPI }) => { let api = { getElements: (type) => provider.getElements(type), getSelectedPanel: () => { let { selectedPanel } = store2.getState(); return ensurePanel(api.getElements(Addon_TypesEnum2.PANEL), selectedPanel, selectedPanel); }, setSelectedPanel: (panelName) => { store2.setState({ selectedPanel: panelName }, { persistence: "session" }); }, setAddonState(addonId, newStateOrMerger, options) { let merger = typeof newStateOrMerger == "function" ? newStateOrMerger : () => newStateOrMerger; return store2.setState( (s) => ({ ...s, addons: { ...s.addons, [addonId]: merger(s.addons[addonId]) } }), options ).then(() => api.getAddonState(addonId)); }, getAddonState: (addonId) => store2.getState().addons[addonId] || globalThis?.STORYBOOK_ADDON_STATE[addonId] }; return { api, state: { selectedPanel: ensurePanel( api.getElements(Addon_TypesEnum2.PANEL), store2.getState().selectedPanel ), addons: {} } }; }; // src/manager-api/modules/channel.ts var channel_exports = {}; __export(channel_exports, { init: () => init2 }); var init2 = ({ provider }) => ({ api: { getChannel: () => provider.channel, on: (type, handler) => (provider.channel?.on(type, handler), () => provider.channel?.off(type, handler)), off: (type, handler) => provider.channel?.off(type, handler), once: (type, handler) => provider.channel?.once(type, handler), emit: (type, data, ...args) => { data?.options?.target && data.options.target !== "storybook-preview-iframe" && !data.options.target.startsWith("storybook-ref-") && (data.options.target = data.options.target !== "storybook_internal" ? `storybook-ref-${data.options.target}` : "storybook-preview-iframe"), provider.channel?.emit(type, data, ...args); } }, state: {} }); // src/manager-api/modules/globals.ts var globals_exports = {}; __export(globals_exports, { init: () => init4 }); import { logger as logger4 } from "storybook/internal/client-logger"; import { GLOBALS_UPDATED, SET_GLOBALS, UPDATE_GLOBALS } from "storybook/internal/core-events"; // src/manager-api/lib/events.ts import { logger as logger3 } from "storybook/internal/client-logger"; // src/manager-api/modules/refs.ts var refs_exports = {}; __export(refs_exports, { defaultStoryMapper: () => defaultStoryMapper, getSourceType: () => getSourceType, init: () => init3 }); import { global as global2 } from "@storybook/global"; // src/manager-api/lib/stories.ts import { sanitize } from "storybook/internal/csf"; var import_memoizerific = __toESM(require_memoizerific(), 1); // src/manager-api/lib/intersect.ts var intersect_default = (a, b) => !Array.isArray(a) || !Array.isArray(b) || !a.length || !b.length ? [] : a.reduce((acc, aValue) => (b.includes(aValue) && acc.push(aValue), acc), []); // src/manager-api/lib/stories.ts var TITLE_PATH_SEPARATOR = /\s*\/\s*/, denormalizeStoryParameters = ({ globalParameters, kindParameters, stories }) => mapValues(stories, (storyData) => ({ ...storyData, parameters: combineParameters( globalParameters, kindParameters[storyData.kind], storyData.parameters ) })), transformSetStoriesStoryDataToPreparedStoryIndex = (stories) => ({ v: 5, entries: Object.entries(stories).reduce( (acc, [id, story]) => { if (!story) return acc; let { docsOnly, fileName, ...parameters } = story.parameters, base = { title: story.kind, id, name: story.name, importPath: fileName }; if (docsOnly) acc[id] = { type: "docs", tags: ["stories-mdx"], storiesImports: [], ...base }; else { let { argTypes, args, initialArgs } = story; acc[id] = { type: "story", subtype: "story", ...base, parameters, argTypes, args, initialArgs }; } return acc; }, {} ) }), transformStoryIndexV2toV3 = (index) => ({ v: 3, stories: Object.values(index.stories).reduce( (acc, entry) => (acc[entry.id] = { ...entry, title: entry.kind, name: entry.name || entry.story, importPath: entry.parameters.fileName || "" }, acc), {} ) }), transformStoryIndexV3toV4 = (index) => { let countByTitle = countBy(Object.values(index.stories), (item) => item.title); return { v: 4, entries: Object.values(index.stories).reduce( (acc, entry) => { let type = "story"; return (entry.parameters?.docsOnly || entry.name === "Page" && countByTitle[entry.title] === 1) && (type = "docs"), acc[entry.id] = { type, ...type === "docs" && { tags: ["stories-mdx"], storiesImports: [] }, ...entry }, delete acc[entry.id].story, delete acc[entry.id].kind, acc; }, {} ) }; }, transformStoryIndexV4toV5 = (index) => ({ v: 5, entries: Object.values(index.entries).reduce( (acc, entry) => (acc[entry.id] = { ...entry, tags: entry.tags ? [Tag.DEV, Tag.TEST, ...entry.tags] : [Tag.DEV] }, acc), {} ) }), transformStoryIndexToStoriesHash = (input, { provider, docsOptions, filters, allStatuses }) => { if (!input.v) throw new Error("Composition: Missing stories.json version"); let index = input; index = index.v === 2 ? transformStoryIndexV2toV3(index) : index, index = index.v === 3 ? transformStoryIndexV3toV4(index) : index, index = index.v === 4 ? transformStoryIndexV4toV5(index) : index, index = index; let indexEntries = Object.values(index.entries), filterFunctions = Object.values(filters), entryValues = indexEntries.filter((entry) => { let statuses = allStatuses[entry.id] ?? {}; return Object.values(statuses).some(({ value }) => value === "status-value:error") || filterFunctions.every((fn) => fn({ ...entry, statuses })) ? !0 : indexEntries.filter((item) => "parent" in item && item.parent === entry.id).some((child) => filterFunctions.every((fn) => fn({ ...child, statuses }))); }), { sidebar = {} } = provider.getConfig(), { showRoots, collapsedRoots = [], renderLabel } = sidebar, setShowRoots = typeof showRoots < "u", storiesHashOutOfOrder = entryValues.reduce((acc, item) => { if (docsOptions.docsMode && item.type !== "docs") return acc; let { title } = item, groups = title.trim().split(TITLE_PATH_SEPARATOR), root = (!setShowRoots || showRoots) && groups.length > 1 ? [groups.shift()] : [], names = [...root, ...groups], paths = names.reduce((list, name, idx) => { let parent = idx > 0 && list[idx - 1], id = sanitize(parent ? `${parent}-${name}` : name); if (name.trim() === "") throw new Error(dedent`Invalid title ${title} ending in slash.`); if (parent === id) throw new Error( dedent` Invalid part '${name}', leading to id === parentId ('${id}'), inside title '${title}' Did you create a path that uses the separator char accidentally, such as 'Vue <docs/>' where '/' is a separator char? See https://github.com/storybookjs/storybook/issues/6128 ` ); return list.push(id), list; }, []); return paths.forEach((id, idx) => { let childId = paths[idx + 1] || item.id; root.length && idx === 0 ? acc[id] = merge_default(acc[id] || {}, { type: "root", id, name: names[idx], tags: [], depth: idx, renderLabel, startCollapsed: collapsedRoots.includes(id), // Note that this will later get appended to the previous list of children (see below) children: [childId] }) : (!acc[id] || acc[id].type === "component") && idx === paths.length - 1 ? acc[id] = merge_default(acc[id] || {}, { type: "component", id, name: names[idx], tags: [], parent: paths[idx - 1], depth: idx, renderLabel, ...childId && { children: [childId] } }) : acc[id] = merge_default(acc[id] || {}, { type: "group", id, name: names[idx], tags: [], parent: paths[idx - 1], depth: idx, renderLabel, ...childId && { children: [childId] } }); }), acc[item.id] = { tags: [], ...item, depth: paths.length, parent: "parent" in item ? item.parent : paths[paths.length - 1], renderLabel, prepared: !!item.parameters }, acc; }, {}); function addItem(acc, item) { if (acc[item.id] || (acc[item.id] = item, "children" in item && item.children && (item.children.forEach((childId) => addItem(acc, storiesHashOutOfOrder[childId])), item.tags = item.children.reduce((currentTags, childId) => currentTags === null ? acc[childId].tags : intersect_default(currentTags, acc[childId].tags), null) || [])), item.type === "component") { let firstChild = acc[item.children[0]]; firstChild && "importPath" in firstChild && (item.importPath = firstChild.importPath); } return acc; } let storiesHash = Object.values(storiesHashOutOfOrder).filter((i) => i.type !== "root" && !i.parent).reduce((acc, item) => addItem(acc, item), {}); return storiesHash = Object.values(storiesHashOutOfOrder).filter((i) => i.type === "root").reduce(addItem, storiesHash), storiesHash = Object.values(storiesHash).reduce((acc, item) => { if (item.type === "story" && item.subtype === "test") { let story = acc[item.parent], component = acc[story.parent]; acc[component.id] = { ...component, // Remove test from the component node as it will be attached to the story node instead children: component.children && component.children.filter((id) => id !== item.id) }, acc[story.id] = { ...story, // Add test to the story node children: (story.children || []).concat(item.id) }, acc[item.id] = { ...item, depth: item.depth + 1 }; } else acc[item.id] = item; return acc; }, {}), storiesHash; }, addPreparedStories = (newHash, oldHash) => oldHash ? Object.fromEntries( Object.entries(newHash).map(([id, newEntry]) => { let oldEntry = oldHash[id]; return newEntry.type === "story" && oldEntry?.type === "story" && oldEntry.prepared ? ("children" in oldEntry && delete oldEntry.children, [id, { ...oldEntry, ...newEntry, prepared: !0 }]) : [id, newEntry]; }) ) : newHash, getComponentLookupList = (0, import_memoizerific.default)(1)((hash) => Object.entries(hash).reduce((acc, i) => { let value = i[1]; return value.type === "component" && acc.push([...value.children]), acc; }, [])), getStoriesLookupList = (0, import_memoizerific.default)(1)((hash) => Object.keys(hash).filter((k) => ["story", "docs"].includes(hash[k].type))); // src/manager-api/modules/refs.ts var { location, fetch } = global2, getSourceType = (source, refId) => { let { origin: localOrigin, pathname: localPathname } = location, { origin: sourceOrigin, pathname: sourcePathname } = new URL(source), localFull = `${localOrigin + localPathname}`.replace(/\/[^\/]*$/, ""), sourceFull = `${sourceOrigin + sourcePathname}`.replace(/\/[^\/]*$/, ""); return localFull === sourceFull ? ["local", sourceFull] : refId || source ? ["external", sourceFull] : [null, null]; }, defaultStoryMapper = (b, a) => ({ ...a, kind: a.kind.replace("|", "/") }), addRefIds = (input, ref) => Object.entries(input).reduce((acc, [id, item]) => ({ ...acc, [id]: { ...item, refId: ref.id } }), {}); async function handleRequest(request) { if (!request) return {}; try { let response = await request; if (response === !1 || response === !0) throw new Error("Unexpected boolean response"); if (!response.ok) { if (response.status === 401) try { let json2 = await response.json(); if (json2.loginUrl) return { loginUrl: json2.loginUrl }; } catch { } throw new Error(`Unexpected response not OK: ${response.statusText}`); } let json = await response.json(); return json.entries || json.stories ? { storyIndex: json } : json; } catch (err) { return { indexError: err }; } } var parseUrl = (url) => { let credentialsRegex = /https?:\/\/(.+:.+)@/, cleanUrl = url, authorization, [, credentials] = url.match(credentialsRegex) || []; return credentials && (cleanUrl = url.replace(`${credentials}@`, ""), authorization = btoa(`${credentials}`)), { url: cleanUrl, authorization }; }, map = (input, ref, options) => { let { storyMapper } = options; return storyMapper ? Object.entries(input).reduce((acc, [id, item]) => ({ ...acc, [id]: storyMapper(ref, item) }), {}) : input; }, init3 = ({ store: store2, provider, singleStory, docsOptions = {} }, { runCheck = !0 } = {}) => { let api = { findRef: (source) => { let refs2 = api.getRefs(); return Object.values(refs2).find(({ url }) => url.match(source)); }, changeRefVersion: async (id, url) => { let { versions, title } = api.getRefs()[id], ref = { id, url, versions, title, index: {}, filteredIndex: {}, expanded: !0 }; await api.setRef(id, { ...ref, type: "unknown" }, !1), await api.checkRef(ref); }, changeRefState: (id, previewInitialized) => { let { [id]: ref, ...updated } = api.getRefs(); updated[id] = { ...ref, previewInitialized }, store2.setState({ refs: updated }); }, checkRef: async (ref) => { let { id, url, version: version2, type } = ref, isPublic = type === "server-checked", loadedData = {}, query = version2 ? `?version=${version2}` : "", credentials = isPublic ? "omit" : "include", urlParseResult = parseUrl(url), headers = { Accept: "application/json" }; urlParseResult.authorization && Object.assign(headers, { Authorization: `Basic ${urlParseResult.authorization}` }); let [indexResult, storiesResult] = await Promise.all( ["index.json", "stories.json"].map( async (file) => handleRequest( fetch(`${urlParseResult.url}/${file}${query}`, { headers, credentials }) ) ) ); if (!indexResult.indexError || !storiesResult.indexError) { let metadata = await handleRequest( fetch(`${urlParseResult.url}/metadata.json${query}`, { headers, credentials, cache: "no-cache" }).catch(() => !1) ); Object.assign(loadedData, { ...indexResult.indexError ? storiesResult : indexResult, ...!metadata.indexError && metadata }); } else isPublic || (loadedData.indexError = { message: dedent` Error: Loading of ref failed at fetch (lib/api/src/modules/refs.ts) URL: ${urlParseResult.url} We weren't able to load the above URL, it's possible a CORS error happened. Please check your dev-tools network tab. ` }); let versions = ref.versions && Object.keys(ref.versions).length ? ref.versions : loadedData.versions; await api.setRef(id, { id, url: urlParseResult.url, ...loadedData, ...versions ? { versions } : {}, type: loadedData.storyIndex ? "lazy" : "auto-inject" }); }, getRefs: () => { let { refs: refs2 = {} } = store2.getState(); return refs2; }, setRef: async (id, { storyIndex, setStoriesData, ...rest }, ready = !1) => { if (singleStory) return; let internal_index, index, filteredIndex, { filters } = store2.getState(), { storyMapper = defaultStoryMapper } = provider.getConfig(), ref = api.getRefs()[id]; (storyIndex || setStoriesData) && (internal_index = setStoriesData ? transformSetStoriesStoryDataToPreparedStoryIndex( map(setStoriesData, ref, { storyMapper }) ) : storyIndex, filteredIndex = transformStoryIndexToStoriesHash(storyIndex, { provider, docsOptions, filters, allStatuses: {} }), index = transformStoryIndexToStoriesHash(storyIndex, { provider, docsOptions, filters: {}, allStatuses: {} })), index && (index = addRefIds(index, ref)), filteredIndex && (filteredIndex = addRefIds(filteredIndex, ref)), await api.updateRef(id, { ...ref, ...rest, index, filteredIndex, internal_index }); }, updateRef: async (id, data) => { let { [id]: ref, ...updated } = api.getRefs(); updated[id] = { ...ref, ...data }; let ordered = Object.keys(initialState2).reduce((obj, key) => (obj[key] = updated[key], obj), {}); await store2.setState({ refs: ordered }); } }, refs = !singleStory && global2.REFS || {}, initialState2 = refs; return runCheck && new Promise(async (resolve) => { for (let ref of Object.values(refs)) await api.checkRef({ ...ref, stories: {} }); resolve(void 0); }), { api, state: { refs: initialState2 } }; }; // src/manager-api/lib/events.ts var getEventMetadata = (context, fullAPI) => { let { source, refId, type } = context, [sourceType, sourceLocation] = getSourceType(source, refId), ref; (refId || sourceType === "external") && (ref = refId && fullAPI.getRefs()[refId] ? fullAPI.getRefs()[refId] : fullAPI.findRef(sourceLocation)); let meta = { source, sourceType, sourceLocation, refId, ref, type }; switch (!0) { case typeof refId == "string": case sourceType === "local": case sourceType === "external": return meta; // if we couldn't find the source, something risky happened, we ignore the input, and log a warning default: return logger3.warn(`Received a ${type} frame that was not configured as a ref`), null; } }; // src/manager-api/modules/globals.ts var init4 = ({ store: store2, fullAPI, provider }) => { let api = { getGlobals() { return store2.getState().globals; }, getUserGlobals() { return store2.getState().userGlobals; }, getStoryGlobals() { return store2.getState().storyGlobals; }, getGlobalTypes() { return store2.getState().globalTypes; }, updateGlobals(newGlobals) { provider.channel?.emit(UPDATE_GLOBALS, { globals: newGlobals, options: { target: "storybook-preview-iframe" } }); } }, state = { globals: {}, userGlobals: {}, storyGlobals: {}, globalTypes: {} }, updateGlobals = ({ globals, storyGlobals, userGlobals }) => { let { globals: currentGlobals, userGlobals: currentUserGlobals, storyGlobals: currentStoryGlobals } = store2.getState(); dequal(globals, currentGlobals) || store2.setState({ globals }), dequal(userGlobals, currentUserGlobals) || store2.setState({ userGlobals }), dequal(storyGlobals, currentStoryGlobals) || store2.setState({ storyGlobals }); }; return provider.channel?.on( GLOBALS_UPDATED, function({ globals, storyGlobals, userGlobals }) { let { ref } = getEventMetadata(this, fullAPI); ref ? logger4.warn( "received a GLOBALS_UPDATED from a non-local ref. This is not currently supported." ) : updateGlobals({ globals, storyGlobals, userGlobals }); } ), provider.channel?.on( SET_GLOBALS, function({ globals, globalTypes }) { let { ref } = getEventMetadata(this, fullAPI), currentGlobals = store2.getState()?.globals; ref ? Object.keys(globals).length > 0 && logger4.warn("received globals from a non-local ref. This is not currently supported.") : store2.setState({ globals, userGlobals: globals, globalTypes }), currentGlobals && Object.keys(currentGlobals).length !== 0 && !dequal(globals, currentGlobals) && api.updateGlobals(currentGlobals); } ), { api, state }; }; // src/manager-api/modules/layout.ts var layout_exports = {}; __export(layout_exports, { ActiveTabs: () => ActiveTabs, defaultLayoutState: () => defaultLayoutState, focusableUIElements: () => focusableUIElements, init: () => init5 }); import { SET_CONFIG as SET_CONFIG2 } from "storybook/internal/core-events"; import { global as global3 } from "@storybook/global"; import { create } from "storybook/theming/create"; var { document: document2 } = global3, isFunction = (val) => typeof val == "function", ActiveTabs = { SIDEBAR: "sidebar", CANVAS: "canvas", ADDONS: "addons" }, defaultLayoutState = { ui: { enableShortcuts: !0 }, layout: { initialActive: ActiveTabs.CANVAS, showToolbar: !0, navSize: 300, bottomPanelHeight: 300, rightPanelWidth: 400, recentVisibleSizes: { navSize: 300, bottomPanelHeight: 300, rightPanelWidth: 400 }, panelPosition: "bottom", showTabs: !0 }, layoutCustomisations: { showSidebar: void 0, showToolbar: void 0 }, selectedPanel: void 0, theme: create() }, focusableUIElements = { storySearchField: "storybook-explorer-searchfield", storyListMenu: "storybook-explorer-menu", storyPanelRoot: "storybook-panel-root" }, getIsNavShown = (state) => state.layout.navSize > 0, getIsPanelShown = (state) => { let { bottomPanelHeight, rightPanelWidth, panelPosition } = state.layout; return panelPosition === "bottom" && bottomPanelHeight > 0 || panelPosition === "right" && rightPanelWidth > 0; }, getIsFullscreen = (state) => !getIsNavShown(state) && !getIsPanelShown(state), getRecentVisibleSizes = (layoutState) => ({ navSize: layoutState.navSize > 0 ? layoutState.navSize : layoutState.recentVisibleSizes.navSize, bottomPanelHeight: layoutState.bottomPanelHeight > 0 ? layoutState.bottomPanelHeight : layoutState.recentVisibleSizes.bottomPanelHeight, rightPanelWidth: layoutState.rightPanelWidth > 0 ? layoutState.rightPanelWidth : layoutState.recentVisibleSizes.rightPanelWidth }), init5 = ({ store: store2, provider, singleStory }) => { let api = { toggleFullscreen(nextState) { return store2.setState( (state) => { let isFullscreen = getIsFullscreen(state), shouldFullscreen = typeof nextState == "boolean" ? nextState : !isFullscreen; return shouldFullscreen === isFullscreen ? { layout: state.layout } : shouldFullscreen ? { layout: { ...state.layout, navSize: 0, bottomPanelHeight: 0, rightPanelWidth: 0, recentVisibleSizes: getRecentVisibleSizes(state.layout) } } : { layout: { ...state.layout, navSize: state.singleStory ? 0 : state.layout.recentVisibleSizes.navSize, bottomPanelHeight: state.layout.recentVisibleSizes.bottomPanelHeight, rightPanelWidth: state.layout.recentVisibleSizes.rightPanelWidth } }; }, { persistence: "session" } ); }, togglePanel(nextState) { return store2.setState( (state) => { let isPanelShown = getIsPanelShown(state), shouldShowPanel = typeof nextState == "boolean" ? nextState : !isPanelShown; return shouldShowPanel === isPanelShown ? { layout: state.layout } : shouldShowPanel ? { layout: { ...state.layout, bottomPanelHeight: state.layout.recentVisibleSizes.bottomPanelHeight, rightPanelWidth: state.layout.recentVisibleSizes.rightPanelWidth } } : { layout: { ...state.layout, bottomPanelHeight: 0, rightPanelWidth: 0, recentVisibleSizes: getRecentVisibleSizes(state.layout) } }; }, { persistence: "session" } ); }, togglePanelPosition(position) { return store2.setState( (state) => { let nextPosition = position || (state.layout.panelPosition === "right" ? "bottom" : "right"); return { layout: { ...state.layout, panelPosition: nextPosition, bottomPanelHeight: state.layout.recentVisibleSizes.bottomPanelHeight, rightPanelWidth: state.layout.recentVisibleSizes.rightPanelWidth } }; }, { persistence: "permanent" } ); }, toggleNav(nextState) { return store2.setState( (state) => { if (state.singleStory) return { layout: state.layout }; let isNavShown = getIsNavShown(state), shouldShowNav = typeof nextState == "boolean" ? nextState : !isNavShown; return shouldShowNav === isNavShown ? { layout: state.layout } : shouldShowNav ? { layout: { ...state.layout, navSize: state.layout.recentVisibleSizes.navSize } } : { layout: { ...state.layout, navSize: 0, recentVisibleSizes: getRecentVisibleSizes(state.layout) } }; }, { persistence: "session" } ); }, toggleToolbar(toggled) { return store2.setState( (state) => { let value = typeof toggled < "u" ? toggled : !state.layout.showToolbar; return { layout: { ...state.layout, showToolbar: value } }; }, { persistence: "session" } ); }, setSizes({ navSize, bottomPanelHeight, rightPanelWidth }) { return store2.setState( (state) => { let nextLayoutState = { ...state.layout, navSize: navSize ?? state.layout.navSize, bottomPanelHeight: bottomPanelHeight ?? state.layout.bottomPanelHeight, rightPanelWidth: rightPanelWidth ?? state.layout.rightPanelWidth }; return { layout: { ...nextLayoutState, recentVisibleSizes: getRecentVisibleSizes(nextLayoutState) } }; }, { persistence: "session" } ); }, /** * Attempts to focus (and select) an element identified by its ID. It is the responsibility of * the callee to ensure that the element is present in the DOM and that no focus trap is * available. This API polls and attempts to perform the focus for a set duration (max 500ms), * so that race conditions can be avoided with the current API design. Because this API is * historically synchronous, it cannot report errors or failure to focus. It fails silently. * * @param elementId The id of the element to focus. * @param select Whether to call select() on the element after focusing it. */ focusOnUIElement(elementId, select) { if (!elementId) return; let startTime = Date.now(), maxDuration = 500, pollInterval = 50, attemptFocus = () => { let element = document2.getElementById(elementId); return !element || (element.focus(), element !== document2.activeElement) ? !1 : (select && element.select?.(), !0); }; if (attemptFocus()) return; let intervalId = setInterval(() => { if (Date.now() - startTime >= maxDuration) { clearInterval(intervalId); return; } attemptFocus() && clearInterval(intervalId); }, pollInterval); }, getInitialOptions() { let { theme, selectedPanel, layoutCustomisations, ...options } = provider.getConfig(); return { ...defaultLayoutState, layout: { ...toMerged( defaultLayoutState.layout, pick(options, Object.keys(defaultLayoutState.layout)) ), ...singleStory && { navSize: 0 } }, layoutCustomisations: { ...defaultLayoutState.layoutCustomisations, ...layoutCustomisations ?? {} }, ui: toMerged(defaultLayoutState.ui, pick(options, Object.keys(defaultLayoutState.ui))), selectedPanel: selectedPanel || defaultLayoutState.selectedPanel, theme: theme || defaultLayoutState.theme }; }, getIsFullscreen() { return getIsFullscreen(store2.getState()); }, getIsPanelShown() { return getIsPanelShown(store2.getState()); }, getIsNavShown() { return getIsNavShown(store2.getState()); }, getShowToolbarWithCustomisations(showToolbar) { let state = store2.getState(); return isFunction(state.layoutCustomisations.showToolbar) ? state.layoutCustomisations.showToolbar(state, showToolbar) ?? showToolbar : showToolbar; }, getShowPanelWithCustomisations(showPanel) { let state = store2.getState(); return isFunction(state.layoutCustomisations.showPanel) ? state.layoutCustomisations.showPanel(state, showPanel) ?? showPanel : showPanel; }, getNavSizeWithCustomisations(navSize) { let state = store2.getState(); if (isFunction(state.layoutCustomisations.showSidebar)) { let shouldShowNav = state.layoutCustomisations.showSidebar(state, navSize !== 0); if (navSize === 0 && shouldShowNav === !0) return state.layout.recentVisibleSizes.navSize; if (navSize !== 0 && shouldShowNav === !1) return 0; } return navSize; }, setOptions: (options) => { let { layout, ui, selectedPanel, theme } = store2.getState(); if (!options) return; let updatedLayout = { ...layout, ...options.layout || {}, ...pick(options, Object.keys(layout)), ...singleStory && { navSize: 0 } }, updatedUi = { ...ui, ...options.ui, ...toMerged(options.ui || {}, pick(options, Object.keys(ui))) }, updatedTheme = { ...theme, ...options.theme }, modification = {}; isEqual(ui, updatedUi) || (modification.ui = updatedUi), isEqual(layout, updatedLayout) || (modification.layout = updatedLayout), options.selectedPanel && !isEqual(selectedPanel, options.selectedPanel) && (modification.se