storybook
Version:
Storybook: Develop, document, and test UI components in isolation
1,277 lines (1,250 loc) • 123 kB
JavaScript
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