UNPKG

storybook

Version:

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

4,183 lines • 144 kB
import {
  isTestEnvironment,
  pauseAnimations,
  waitForAnimations
} from "./chunk-LYCSRYYR.js";
import {
  require_main
} from "./chunk-Y3M7TW6K.js";
import {
  SNIPPET_RENDERED,
  combineParameters
} from "./chunk-B4A3ADP3.js";
import {
  isEqual
} from "./chunk-ZNRFDIVA.js";
import {
  invariant
} from "./chunk-FUOHXXZT.js";
import {
  require_ansi_to_html
} from "./chunk-F4Q6SGTB.js";
import {
  mapValues,
  pickBy
} from "./chunk-UTNZYD2N.js";
import {
  isPlainObject
} from "./chunk-FSBVR7H5.js";
import {
  require_memoizerific
} from "./chunk-NVV6MIOE.js";
import {
  dedent
} from "./chunk-OPCDBBL3.js";
import {
  __name,
  __toESM
} from "./chunk-MM7DTO55.js";

// src/preview-api/modules/addons/main.ts
import { global } from "@storybook/global";

// src/preview-api/modules/addons/storybook-channel-mock.ts
import { Channel } from "storybook/internal/channels";
function mockChannel() {
  const transport = {
    setHandler: /* @__PURE__ */ __name(() => {
    }, "setHandler"),
    send: /* @__PURE__ */ __name(() => {
    }, "send")
  };
  return new Channel({ transport });
}
__name(mockChannel, "mockChannel");

// src/preview-api/modules/addons/main.ts
var _AddonStore = class _AddonStore {
  constructor() {
    this.getChannel = /* @__PURE__ */ __name(() => {
      if (!this.channel) {
        const channel = mockChannel();
        this.setChannel(channel);
        return channel;
      }
      return this.channel;
    }, "getChannel");
    this.ready = /* @__PURE__ */ __name(() => this.promise, "ready");
    this.hasChannel = /* @__PURE__ */ __name(() => !!this.channel, "hasChannel");
    this.setChannel = /* @__PURE__ */ __name((channel) => {
      this.channel = channel;
      this.resolve();
    }, "setChannel");
    this.promise = new Promise((res) => {
      this.resolve = () => res(this.getChannel());
    });
  }
};
__name(_AddonStore, "AddonStore");
var AddonStore = _AddonStore;
var KEY = "__STORYBOOK_ADDONS_PREVIEW";
function getAddonsStore() {
  if (!global[KEY]) {
    global[KEY] = new AddonStore();
  }
  return global[KEY];
}
__name(getAddonsStore, "getAddonsStore");
var addons = getAddonsStore();

// src/preview-api/modules/addons/hooks.ts
import { logger } from "storybook/internal/client-logger";
import {
  FORCE_RE_RENDER,
  RESET_STORY_ARGS,
  STORY_RENDERED,
  UPDATE_GLOBALS,
  UPDATE_STORY_ARGS
} from "storybook/internal/core-events";
import { global as global2 } from "@storybook/global";
var _HooksContext = class _HooksContext {
  constructor() {
    this.hookListsMap = void 0;
    this.mountedDecorators = void 0;
    this.prevMountedDecorators = void 0;
    this.currentHooks = void 0;
    this.nextHookIndex = void 0;
    this.currentPhase = void 0;
    this.currentEffects = void 0;
    this.prevEffects = void 0;
    this.currentDecoratorName = void 0;
    this.hasUpdates = void 0;
    this.currentContext = void 0;
    this.renderListener = /* @__PURE__ */ __name((storyId) => {
      if (storyId !== this.currentContext?.id) {
        return;
      }
      this.triggerEffects();
      this.currentContext = null;
      this.removeRenderListeners();
    }, "renderListener");
    this.init();
  }
  init() {
    this.hookListsMap = /* @__PURE__ */ new WeakMap();
    this.mountedDecorators = /* @__PURE__ */ new Set();
    this.prevMountedDecorators = /* @__PURE__ */ new Set();
    this.currentHooks = [];
    this.nextHookIndex = 0;
    this.currentPhase = "NONE";
    this.currentEffects = [];
    this.prevEffects = [];
    this.currentDecoratorName = null;
    this.hasUpdates = false;
    this.currentContext = null;
  }
  clean() {
    this.prevEffects.forEach((effect) => {
      if (effect.destroy) {
        effect.destroy();
      }
    });
    this.init();
    this.removeRenderListeners();
  }
  getNextHook() {
    const hook = this.currentHooks[this.nextHookIndex];
    this.nextHookIndex += 1;
    return hook;
  }
  triggerEffects() {
    this.prevEffects.forEach((effect) => {
      if (!this.currentEffects.includes(effect) && effect.destroy) {
        effect.destroy();
      }
    });
    this.currentEffects.forEach((effect) => {
      if (!this.prevEffects.includes(effect)) {
        effect.destroy = effect.create();
      }
    });
    this.prevEffects = this.currentEffects;
    this.currentEffects = [];
  }
  addRenderListeners() {
    this.removeRenderListeners();
    const channel = addons.getChannel();
    channel.on(STORY_RENDERED, this.renderListener);
  }
  removeRenderListeners() {
    const channel = addons.getChannel();
    channel.removeListener(STORY_RENDERED, this.renderListener);
  }
};
__name(_HooksContext, "HooksContext");
var HooksContext = _HooksContext;
function hookify(fn) {
  const hookified = /* @__PURE__ */ __name((...args) => {
    const { hooks } = typeof args[0] === "function" ? args[1] : args[0];
    const prevPhase = hooks.currentPhase;
    const prevHooks = hooks.currentHooks;
    const prevNextHookIndex = hooks.nextHookIndex;
    const prevDecoratorName = hooks.currentDecoratorName;
    hooks.currentDecoratorName = fn.name;
    if (hooks.prevMountedDecorators.has(fn)) {
      hooks.currentPhase = "UPDATE";
      hooks.currentHooks = hooks.hookListsMap.get(fn) || [];
    } else {
      hooks.currentPhase = "MOUNT";
      hooks.currentHooks = [];
      hooks.hookListsMap.set(fn, hooks.currentHooks);
      hooks.prevMountedDecorators.add(fn);
    }
    hooks.nextHookIndex = 0;
    const prevContext = global2.STORYBOOK_HOOKS_CONTEXT;
    global2.STORYBOOK_HOOKS_CONTEXT = hooks;
    const result = fn(...args);
    global2.STORYBOOK_HOOKS_CONTEXT = prevContext;
    if (hooks.currentPhase === "UPDATE" && hooks.getNextHook() != null) {
      throw new Error(
        "Rendered fewer hooks than expected. This may be caused by an accidental early return statement."
      );
    }
    hooks.currentPhase = prevPhase;
    hooks.currentHooks = prevHooks;
    hooks.nextHookIndex = prevNextHookIndex;
    hooks.currentDecoratorName = prevDecoratorName;
    return result;
  }, "hookified");
  hookified.originalFn = fn;
  return hookified;
}
__name(hookify, "hookify");
var numberOfRenders = 0;
var RENDER_LIMIT = 25;
var applyHooks = /* @__PURE__ */ __name((applyDecorators) => (storyFn, decorators) => {
  const decorated = applyDecorators(
    hookify(storyFn),
    decorators.map((decorator) => hookify(decorator))
  );
  return (context) => {
    const { hooks } = context;
    hooks.prevMountedDecorators ??= /* @__PURE__ */ new Set();
    hooks.mountedDecorators = /* @__PURE__ */ new Set([storyFn, ...decorators]);
    hooks.currentContext = context;
    hooks.hasUpdates = false;
    let result = decorated(context);
    numberOfRenders = 1;
    while (hooks.hasUpdates) {
      hooks.hasUpdates = false;
      hooks.currentEffects = [];
      result = decorated(context);
      numberOfRenders += 1;
      if (numberOfRenders > RENDER_LIMIT) {
        throw new Error(
          "Too many re-renders. Storybook limits the number of renders to prevent an infinite loop."
        );
      }
    }
    hooks.addRenderListeners();
    return result;
  };
}, "applyHooks");
var areDepsEqual = /* @__PURE__ */ __name((deps, nextDeps) => deps.length === nextDeps.length && deps.every((dep, i) => dep === nextDeps[i]), "areDepsEqual");
var invalidHooksError = /* @__PURE__ */ __name(() => new Error("Storybook preview hooks can only be called inside decorators and story functions."), "invalidHooksError");
function getHooksContextOrNull() {
  return global2.STORYBOOK_HOOKS_CONTEXT || null;
}
__name(getHooksContextOrNull, "getHooksContextOrNull");
function getHooksContextOrThrow() {
  const hooks = getHooksContextOrNull();
  if (hooks == null) {
    throw invalidHooksError();
  }
  return hooks;
}
__name(getHooksContextOrThrow, "getHooksContextOrThrow");
function useHook(name, callback, deps) {
  const hooks = getHooksContextOrThrow();
  if (hooks.currentPhase === "MOUNT") {
    if (deps != null && !Array.isArray(deps)) {
      logger.warn(
        `${name} received a final argument that is not an array (instead, received ${deps}). When specified, the final argument must be an array.`
      );
    }
    const hook = { name, deps };
    hooks.currentHooks.push(hook);
    callback(hook);
    return hook;
  }
  if (hooks.currentPhase === "UPDATE") {
    const hook = hooks.getNextHook();
    if (hook == null) {
      throw new Error("Rendered more hooks than during the previous render.");
    }
    if (hook.name !== name) {
      logger.warn(
        `Storybook has detected a change in the order of Hooks${hooks.currentDecoratorName ? ` called by ${hooks.currentDecoratorName}` : ""}. This will lead to bugs and errors if not fixed.`
      );
    }
    if (deps != null && hook.deps == null) {
      logger.warn(
        `${name} received a final argument during this render, but not during the previous render. Even though the final argument is optional, its type cannot change between renders.`
      );
    }
    if (deps != null && hook.deps != null && deps.length !== hook.deps.length) {
      logger.warn(`The final argument passed to ${name} changed size between renders. The order and size of this array must remain constant.
Previous: ${hook.deps}
Incoming: ${deps}`);
    }
    if (deps == null || hook.deps == null || !areDepsEqual(deps, hook.deps)) {
      callback(hook);
      hook.deps = deps;
    }
    return hook;
  }
  throw invalidHooksError();
}
__name(useHook, "useHook");
function useMemoLike(name, nextCreate, deps) {
  const { memoizedState } = useHook(
    name,
    (hook) => {
      hook.memoizedState = nextCreate();
    },
    deps
  );
  return memoizedState;
}
__name(useMemoLike, "useMemoLike");
function useMemo(nextCreate, deps) {
  return useMemoLike("useMemo", nextCreate, deps);
}
__name(useMemo, "useMemo");
function useCallback(callback, deps) {
  return useMemoLike("useCallback", () => callback, deps);
}
__name(useCallback, "useCallback");
function useRefLike(name, initialValue) {
  return useMemoLike(name, () => ({ current: initialValue }), []);
}
__name(useRefLike, "useRefLike");
function useRef(initialValue) {
  return useRefLike("useRef", initialValue);
}
__name(useRef, "useRef");
function triggerUpdate() {
  const hooks = getHooksContextOrNull();
  if (hooks != null && hooks.currentPhase !== "NONE") {
    hooks.hasUpdates = true;
  } else {
    try {
      addons.getChannel().emit(FORCE_RE_RENDER);
    } catch (e) {
      logger.warn("State updates of Storybook preview hooks work only in browser");
    }
  }
}
__name(triggerUpdate, "triggerUpdate");
function useStateLike(name, initialState) {
  const stateRef = useRefLike(
    name,
    // @ts-expect-error S type should never be function, but there's no way to tell that to TypeScript
    typeof initialState === "function" ? initialState() : initialState
  );
  const setState = /* @__PURE__ */ __name((update) => {
    stateRef.current = typeof update === "function" ? update(stateRef.current) : update;
    triggerUpdate();
  }, "setState");
  return [stateRef.current, setState];
}
__name(useStateLike, "useStateLike");
function useState(initialState) {
  return useStateLike("useState", initialState);
}
__name(useState, "useState");
function useReducer(reducer, initialArg, init) {
  const initialState = init != null ? () => init(initialArg) : initialArg;
  const [state, setState] = useStateLike("useReducer", initialState);
  const dispatch = /* @__PURE__ */ __name((action) => setState((prevState) => reducer(prevState, action)), "dispatch");
  return [state, dispatch];
}
__name(useReducer, "useReducer");
function useEffect(create, deps) {
  const hooks = getHooksContextOrThrow();
  const effect = useMemoLike("useEffect", () => ({ create }), deps);
  if (!hooks.currentEffects.includes(effect)) {
    hooks.currentEffects.push(effect);
  }
}
__name(useEffect, "useEffect");
function useChannel(eventMap, deps = []) {
  const channel = addons.getChannel();
  useEffect(() => {
    Object.entries(eventMap).forEach(([type, listener]) => channel.on(type, listener));
    return () => {
      Object.entries(eventMap).forEach(
        ([type, listener]) => channel.removeListener(type, listener)
      );
    };
  }, [...Object.keys(eventMap), ...deps]);
  return useCallback(channel.emit.bind(channel), [channel]);
}
__name(useChannel, "useChannel");
function useStoryContext() {
  const { currentContext } = getHooksContextOrThrow();
  if (currentContext == null) {
    throw invalidHooksError();
  }
  return currentContext;
}
__name(useStoryContext, "useStoryContext");
function useParameter(parameterKey, defaultValue) {
  const { parameters } = useStoryContext();
  if (parameterKey) {
    return parameters[parameterKey] ?? defaultValue;
  }
  return void 0;
}
__name(useParameter, "useParameter");
function useArgs() {
  const channel = addons.getChannel();
  const { id: storyId, args } = useStoryContext();
  const updateArgs = useCallback(
    (updatedArgs) => channel.emit(UPDATE_STORY_ARGS, { storyId, updatedArgs }),
    [channel, storyId]
  );
  const resetArgs = useCallback(
    (argNames) => channel.emit(RESET_STORY_ARGS, { storyId, argNames }),
    [channel, storyId]
  );
  return [args, updateArgs, resetArgs];
}
__name(useArgs, "useArgs");
function useGlobals() {
  const channel = addons.getChannel();
  const { globals } = useStoryContext();
  const updateGlobals = useCallback(
    (newGlobals) => channel.emit(UPDATE_GLOBALS, { globals: newGlobals }),
    [channel]
  );
  return [globals, updateGlobals];
}
__name(useGlobals, "useGlobals");

// src/preview-api/modules/addons/make-decorator.ts
var makeDecorator = /* @__PURE__ */ __name(({
  name,
  parameterName,
  wrapper,
  skipIfNoParametersOrOptions = false
}) => {
  const decorator = /* @__PURE__ */ __name((options) => (storyFn, context) => {
    const parameters = context.parameters && context.parameters[parameterName];
    if (parameters && parameters.disable) {
      return storyFn(context);
    }
    if (skipIfNoParametersOrOptions && !options && !parameters) {
      return storyFn(context);
    }
    return wrapper(storyFn, context, {
      options,
      parameters
    });
  }, "decorator");
  return (...args) => {
    if (typeof args[0] === "function") {
      return decorator()(...args);
    }
    return (...innerArgs) => {
      if (innerArgs.length > 1) {
        if (args.length > 1) {
          return decorator(args)(...innerArgs);
        }
        return decorator(...args)(...innerArgs);
      }
      throw new Error(
        `Passing stories directly into ${name}() is not allowed,
        instead use addDecorator(${name}) and pass options with the '${parameterName}' parameter`
      );
    };
  };
}, "makeDecorator");

// src/preview-api/modules/store/StoryStore.ts
import { getCoreAnnotations as getCoreAnnotations2 } from "storybook/internal/csf";
import {
  CalledExtractOnStoreError,
  MissingStoryFromCsfFileError
} from "storybook/internal/preview-errors";
var import_memoizerific2 = __toESM(require_memoizerific(), 1);

// src/preview-api/modules/store/args.ts
import { once } from "storybook/internal/client-logger";
var INCOMPATIBLE = Symbol("incompatible");
var map = /* @__PURE__ */ __name((arg, argType) => {
  const type = argType.type;
  if (arg === void 0 || arg === null || !type) {
    return arg;
  }
  if (argType.mapping) {
    return arg;
  }
  switch (type.name) {
    case "string":
      return String(arg);
    case "enum":
      return arg;
    case "number":
      return Number(arg);
    case "boolean":
      return String(arg) === "true";
    case "array":
      if (!type.value || !Array.isArray(arg)) {
        return INCOMPATIBLE;
      }
      return arg.reduce((acc, item, index) => {
        const mapped = map(item, { type: type.value });
        if (mapped !== INCOMPATIBLE) {
          acc[index] = mapped;
        }
        return acc;
      }, new Array(arg.length));
    case "object":
      if (typeof arg === "string" || typeof arg === "number") {
        return arg;
      }
      if (!type.value || typeof arg !== "object") {
        return INCOMPATIBLE;
      }
      return Object.entries(arg).reduce((acc, [key, val]) => {
        const mapped = map(val, { type: type.value[key] });
        return mapped === INCOMPATIBLE ? acc : Object.assign(acc, { [key]: mapped });
      }, {});
    case "other": {
      const isPrimitiveArg = typeof arg === "string" || typeof arg === "number" || typeof arg === "boolean";
      if (type.value === "ReactNode" && isPrimitiveArg) {
        return arg;
      }
      return INCOMPATIBLE;
    }
    default:
      return INCOMPATIBLE;
  }
}, "map");
var mapArgsToTypes = /* @__PURE__ */ __name((args, argTypes) => {
  return Object.entries(args).reduce((acc, [key, value]) => {
    if (!argTypes[key]) {
      return acc;
    }
    const mapped = map(value, argTypes[key]);
    return mapped === INCOMPATIBLE ? acc : Object.assign(acc, { [key]: mapped });
  }, {});
}, "mapArgsToTypes");
var combineArgs = /* @__PURE__ */ __name((value, update) => {
  if (Array.isArray(value) && Array.isArray(update)) {
    return update.reduce(
      (acc, upd, index) => {
        acc[index] = combineArgs(value[index], update[index]);
        return acc;
      },
      [...value]
    ).filter((v) => v !== void 0);
  }
  if (!isPlainObject(value) || !isPlainObject(update)) {
    return update;
  }
  return Object.keys({ ...value, ...update }).reduce((acc, key) => {
    if (key in update) {
      const combined = combineArgs(value[key], update[key]);
      if (combined !== void 0) {
        acc[key] = combined;
      }
    } else {
      acc[key] = value[key];
    }
    return acc;
  }, {});
}, "combineArgs");
var validateOptions = /* @__PURE__ */ __name((args, argTypes) => {
  return Object.entries(argTypes).reduce((acc, [key, { options }]) => {
    function allowArg() {
      if (key in args) {
        acc[key] = args[key];
      }
      return acc;
    }
    __name(allowArg, "allowArg");
    if (!options) {
      return allowArg();
    }
    if (!Array.isArray(options)) {
      once.error(dedent`
        Invalid argType: '${key}.options' should be an array.

        More info: https://storybook.js.org/docs/api/arg-types?ref=error
      `);
      return allowArg();
    }
    if (options.some((opt) => opt && ["object", "function"].includes(typeof opt))) {
      once.error(dedent`
        Invalid argType: '${key}.options' should only contain primitives. Use a 'mapping' for complex values.

        More info: https://storybook.js.org/docs/writing-stories/args?ref=error#mapping-to-complex-arg-values
      `);
      return allowArg();
    }
    const isArray = Array.isArray(args[key]);
    const invalidIndex = isArray && args[key].findIndex((val) => !options.includes(val));
    const isValidArray = isArray && invalidIndex === -1;
    if (args[key] === void 0 || options.includes(args[key]) || isValidArray) {
      return allowArg();
    }
    const field = isArray ? `${key}[${invalidIndex}]` : key;
    const supportedOptions = options.map((opt) => typeof opt === "string" ? `'${opt}'` : String(opt)).join(", ");
    once.warn(`Received illegal value for '${field}'. Supported options: ${supportedOptions}`);
    return acc;
  }, {});
}, "validateOptions");
var DEEPLY_EQUAL = Symbol("Deeply equal");
var deepDiff = /* @__PURE__ */ __name((value, update) => {
  if (typeof value !== typeof update) {
    return update;
  }
  if (isEqual(value, update)) {
    return DEEPLY_EQUAL;
  }
  if (Array.isArray(value) && Array.isArray(update)) {
    const res = update.reduce((acc, upd, index) => {
      const diff = deepDiff(value[index], upd);
      if (diff !== DEEPLY_EQUAL) {
        acc[index] = diff;
      }
      return acc;
    }, new Array(update.length));
    if (update.length >= value.length) {
      return res;
    }
    return res.concat(new Array(value.length - update.length).fill(void 0));
  }
  if (isPlainObject(value) && isPlainObject(update)) {
    return Object.keys({ ...value, ...update }).reduce((acc, key) => {
      const diff = deepDiff(value?.[key], update?.[key]);
      return diff === DEEPLY_EQUAL ? acc : Object.assign(acc, { [key]: diff });
    }, {});
  }
  return update;
}, "deepDiff");
var UNTARGETED = "UNTARGETED";
function groupArgsByTarget({
  args,
  argTypes
}) {
  const groupedArgs = {};
  Object.entries(args).forEach(([name, value]) => {
    const { target = UNTARGETED } = argTypes[name] || {};
    groupedArgs[target] = groupedArgs[target] || {};
    groupedArgs[target][name] = value;
  });
  return groupedArgs;
}
__name(groupArgsByTarget, "groupArgsByTarget");

// src/preview-api/modules/store/ArgsStore.ts
function deleteUndefined(obj) {
  Object.keys(obj).forEach((key) => obj[key] === void 0 && delete obj[key]);
  return obj;
}
__name(deleteUndefined, "deleteUndefined");
var _ArgsStore = class _ArgsStore {
  constructor() {
    this.initialArgsByStoryId = {};
    this.argsByStoryId = {};
  }
  get(storyId) {
    if (!(storyId in this.argsByStoryId)) {
      throw new Error(`No args known for ${storyId} -- has it been rendered yet?`);
    }
    return this.argsByStoryId[storyId];
  }
  setInitial(story) {
    if (!this.initialArgsByStoryId[story.id]) {
      this.initialArgsByStoryId[story.id] = story.initialArgs;
      this.argsByStoryId[story.id] = story.initialArgs;
    } else if (this.initialArgsByStoryId[story.id] !== story.initialArgs) {
      const delta = deepDiff(this.initialArgsByStoryId[story.id], this.argsByStoryId[story.id]);
      this.initialArgsByStoryId[story.id] = story.initialArgs;
      this.argsByStoryId[story.id] = story.initialArgs;
      if (delta !== DEEPLY_EQUAL) {
        this.updateFromDelta(story, delta);
      }
    }
  }
  updateFromDelta(story, delta) {
    const validatedDelta = validateOptions(delta, story.argTypes);
    this.argsByStoryId[story.id] = combineArgs(this.argsByStoryId[story.id], validatedDelta);
  }
  updateFromPersisted(story, persisted) {
    const mappedPersisted = mapArgsToTypes(persisted, story.argTypes);
    return this.updateFromDelta(story, mappedPersisted);
  }
  update(storyId, argsUpdate) {
    if (!(storyId in this.argsByStoryId)) {
      throw new Error(`No args known for ${storyId} -- has it been rendered yet?`);
    }
    this.argsByStoryId[storyId] = deleteUndefined({
      ...this.argsByStoryId[storyId],
      ...argsUpdate
    });
  }
};
__name(_ArgsStore, "ArgsStore");
var ArgsStore = _ArgsStore;

// src/preview-api/modules/store/GlobalsStore.ts
import { logger as logger2 } from "storybook/internal/client-logger";

// src/preview-api/modules/store/csf/getValuesFromArgTypes.ts
var getValuesFromArgTypes = /* @__PURE__ */ __name((argTypes = {}) => Object.entries(argTypes).reduce((acc, [arg, { defaultValue }]) => {
  if (typeof defaultValue !== "undefined") {
    acc[arg] = defaultValue;
  }
  return acc;
}, {}), "getValuesFromArgTypes");

// src/preview-api/modules/store/GlobalsStore.ts
var _GlobalsStore = class _GlobalsStore {
  constructor({
    globals = {},
    globalTypes = {}
  }) {
    this.set({ globals, globalTypes });
  }
  set({ globals = {}, globalTypes = {} }) {
    const delta = this.initialGlobals && deepDiff(this.initialGlobals, this.globals);
    this.allowedGlobalNames = /* @__PURE__ */ new Set([...Object.keys(globals), ...Object.keys(globalTypes)]);
    const defaultGlobals = getValuesFromArgTypes(globalTypes);
    this.initialGlobals = { ...defaultGlobals, ...globals };
    this.globals = this.initialGlobals;
    if (delta && delta !== DEEPLY_EQUAL) {
      this.updateFromPersisted(delta);
    }
  }
  filterAllowedGlobals(globals) {
    return Object.entries(globals).reduce((acc, [key, value]) => {
      if (this.allowedGlobalNames.has(key)) {
        acc[key] = value;
      } else {
        logger2.warn(
          `Attempted to set a global (${key}) that is not defined in initial globals or globalTypes`
        );
      }
      return acc;
    }, {});
  }
  updateFromPersisted(persisted) {
    const allowedUrlGlobals = this.filterAllowedGlobals(persisted);
    this.globals = { ...this.globals, ...allowedUrlGlobals };
  }
  get() {
    return this.globals;
  }
  update(newGlobals) {
    this.globals = { ...this.globals, ...this.filterAllowedGlobals(newGlobals) };
    for (const key in newGlobals) {
      if (newGlobals[key] === void 0) {
        this.globals[key] = this.initialGlobals[key];
      }
    }
  }
};
__name(_GlobalsStore, "GlobalsStore");
var GlobalsStore = _GlobalsStore;

// src/preview-api/modules/store/StoryIndexStore.ts
var import_memoizerific = __toESM(require_memoizerific(), 1);
import { MissingStoryAfterHmrError } from "storybook/internal/preview-errors";
var getImportPathMap = (0, import_memoizerific.default)(1)(
  (entries) => Object.values(entries).reduce(
    (acc, entry) => {
      acc[entry.importPath] = acc[entry.importPath] || entry;
      return acc;
    },
    {}
  )
);
var _StoryIndexStore = class _StoryIndexStore {
  constructor({ entries } = { v: 5, entries: {} }) {
    this.entries = entries;
  }
  entryFromSpecifier(specifier) {
    const entries = Object.values(this.entries);
    if (specifier === "*") {
      return entries[0];
    }
    if (typeof specifier === "string") {
      if (this.entries[specifier]) {
        return this.entries[specifier];
      }
      return entries.find((entry) => entry.id.startsWith(specifier));
    }
    const { name, title } = specifier;
    return entries.find((entry) => entry.name === name && entry.title === title);
  }
  storyIdToEntry(storyId) {
    const storyEntry = this.entries[storyId];
    if (!storyEntry) {
      throw new MissingStoryAfterHmrError({ storyId });
    }
    return storyEntry;
  }
  importPathToEntry(importPath) {
    return getImportPathMap(this.entries)[importPath];
  }
};
__name(_StoryIndexStore, "StoryIndexStore");
var StoryIndexStore = _StoryIndexStore;

// src/preview-api/modules/store/csf/normalizeInputTypes.ts
var normalizeType = /* @__PURE__ */ __name((type) => {
  return typeof type === "string" ? { name: type } : type;
}, "normalizeType");
var normalizeControl = /* @__PURE__ */ __name((control) => typeof control === "string" ? { type: control } : control, "normalizeControl");
var normalizeInputType = /* @__PURE__ */ __name((inputType, key) => {
  const { type, control, ...rest } = inputType;
  const normalized = {
    name: key,
    ...rest
  };
  if (type) {
    normalized.type = normalizeType(type);
  }
  if (control) {
    normalized.control = normalizeControl(control);
  } else if (control === false) {
    normalized.control = { disable: true };
  }
  return normalized;
}, "normalizeInputType");
var normalizeInputTypes = /* @__PURE__ */ __name((inputTypes) => mapValues(inputTypes, normalizeInputType), "normalizeInputTypes");

// src/preview-api/modules/store/csf/normalizeStory.ts
import { deprecate, logger as logger3 } from "storybook/internal/client-logger";
import { storyNameFromExport, toId } from "storybook/internal/csf";

// src/preview-api/modules/store/csf/normalizeArrays.ts
var normalizeArrays = /* @__PURE__ */ __name((array) => {
  if (Array.isArray(array)) {
    return array;
  }
  return array ? [array] : [];
}, "normalizeArrays");

// src/preview-api/modules/store/csf/normalizeStory.ts
var deprecatedStoryAnnotation = dedent`
CSF .story annotations deprecated; annotate story functions directly:
- StoryFn.story.name => StoryFn.storyName
- StoryFn.story.(parameters|decorators) => StoryFn.(parameters|decorators)
See https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#hoisted-csf-annotations for details and codemod.
`;
function normalizeStory(key, storyAnnotations, meta) {
  const storyObject = storyAnnotations;
  const userStoryFn = typeof storyAnnotations === "function" ? storyAnnotations : null;
  const { story } = storyObject;
  if (story) {
    logger3.debug("deprecated story", story);
    deprecate(deprecatedStoryAnnotation);
  }
  const exportName = storyNameFromExport(key);
  const name = typeof storyObject !== "function" && storyObject.name || storyObject.storyName || story?.name || exportName;
  const decorators = [
    ...normalizeArrays(storyObject.decorators),
    ...normalizeArrays(story?.decorators)
  ];
  const parameters = { ...story?.parameters, ...storyObject.parameters };
  const args = { ...story?.args, ...storyObject.args };
  const argTypes = { ...story?.argTypes, ...storyObject.argTypes };
  const loaders = [...normalizeArrays(storyObject.loaders), ...normalizeArrays(story?.loaders)];
  const beforeEach = [
    ...normalizeArrays(storyObject.beforeEach),
    ...normalizeArrays(story?.beforeEach)
  ];
  const afterEach = [
    ...normalizeArrays(storyObject.afterEach),
    ...normalizeArrays(story?.afterEach)
  ];
  const { render, play, tags = [], globals = {} } = storyObject;
  const id = parameters.__id || toId(meta.id, exportName);
  return {
    moduleExport: storyAnnotations,
    id,
    name,
    tags,
    decorators,
    parameters,
    args,
    argTypes: normalizeInputTypes(argTypes),
    loaders,
    beforeEach,
    afterEach,
    globals,
    ...render && { render },
    ...userStoryFn && { userStoryFn },
    ...play && { play }
  };
}
__name(normalizeStory, "normalizeStory");

// src/preview-api/modules/store/csf/processCSFFile.ts
import { logger as logger4 } from "storybook/internal/client-logger";
import { getStoryChildren, isExportStory, isStory, toTestId } from "storybook/internal/csf";

// src/preview-api/modules/store/csf/normalizeComponentAnnotations.ts
import { sanitize } from "storybook/internal/csf";
function normalizeComponentAnnotations(defaultExport, title = defaultExport.title, importPath) {
  const { id, argTypes } = defaultExport;
  return {
    id: sanitize(id || title),
    ...defaultExport,
    title,
    ...argTypes && { argTypes: normalizeInputTypes(argTypes) },
    parameters: {
      fileName: importPath,
      ...defaultExport.parameters
    }
  };
}
__name(normalizeComponentAnnotations, "normalizeComponentAnnotations");

// src/preview-api/modules/store/csf/processCSFFile.ts
var checkGlobals = /* @__PURE__ */ __name((parameters) => {
  const { globals, globalTypes } = parameters;
  if (globals || globalTypes) {
    logger4.error(
      "Global args/argTypes can only be set globally",
      JSON.stringify({
        globals,
        globalTypes
      })
    );
  }
}, "checkGlobals");
var checkStorySort = /* @__PURE__ */ __name((parameters) => {
  const { options } = parameters;
  if (options?.storySort) {
    logger4.error("The storySort option parameter can only be set globally");
  }
}, "checkStorySort");
var checkDisallowedParameters = /* @__PURE__ */ __name((parameters) => {
  if (!parameters) {
    return;
  }
  checkGlobals(parameters);
  checkStorySort(parameters);
}, "checkDisallowedParameters");
function processCSFFile(moduleExports, importPath, title) {
  const { default: defaultExport, __namedExportsOrder, ...namedExports } = moduleExports;
  const firstStory = Object.values(namedExports)[0];
  if (isStory(firstStory)) {
    const meta2 = normalizeComponentAnnotations(firstStory.meta.input, title, importPath);
    checkDisallowedParameters(meta2.parameters);
    const csfFile2 = { meta: meta2, stories: {}, moduleExports };
    Object.keys(namedExports).forEach((key) => {
      if (isExportStory(key, meta2)) {
        const story = namedExports[key];
        const storyMeta = normalizeStory(key, story.input, meta2);
        checkDisallowedParameters(storyMeta.parameters);
        csfFile2.stories[storyMeta.id] = storyMeta;
        getStoryChildren(story).forEach((child) => {
          const name = child.input.name;
          const childId = toTestId(storyMeta.id, name);
          child.input.parameters ??= {};
          child.input.parameters.__id = childId;
          csfFile2.stories[childId] = normalizeStory(name, child.input, meta2);
        });
      }
    });
    csfFile2.projectAnnotations = firstStory.meta.preview.composed;
    return csfFile2;
  }
  const meta = normalizeComponentAnnotations(
    defaultExport,
    title,
    importPath
  );
  checkDisallowedParameters(meta.parameters);
  const csfFile = { meta, stories: {}, moduleExports };
  Object.keys(namedExports).forEach((key) => {
    if (isExportStory(key, meta)) {
      const storyMeta = normalizeStory(key, namedExports[key], meta);
      checkDisallowedParameters(storyMeta.parameters);
      csfFile.stories[storyMeta.id] = storyMeta;
    }
  });
  return csfFile;
}
__name(processCSFFile, "processCSFFile");

// src/preview-api/modules/store/csf/prepareStory.ts
import { combineTags, includeConditionalArg } from "storybook/internal/csf";
import { NoRenderFunctionError } from "storybook/internal/preview-errors";
import { global as global3 } from "@storybook/global";
import { global as globalThis2 } from "@storybook/global";

// src/preview-api/modules/preview-web/render/mount-utils.ts
function mountDestructured(playFunction) {
  return playFunction != null && getUsedProps(playFunction).includes("mount");
}
__name(mountDestructured, "mountDestructured");
function getUsedProps(fn) {
  const match = fn.toString().match(/[^(]*\(([^)]*)/);
  if (!match) {
    return [];
  }
  const args = splitByComma(match[1]);
  if (!args.length) {
    return [];
  }
  const first = args[0];
  if (!(first.startsWith("{") && first.endsWith("}"))) {
    return [];
  }
  const props = splitByComma(first.slice(1, -1).replace(/\s/g, "")).map((prop) => {
    return prop.replace(/:.*|=.*/g, "");
  });
  return props;
}
__name(getUsedProps, "getUsedProps");
function splitByComma(s) {
  const result = [];
  const stack = [];
  let start = 0;
  for (let i = 0; i < s.length; i++) {
    if (s[i] === "{" || s[i] === "[") {
      stack.push(s[i] === "{" ? "}" : "]");
    } else if (s[i] === stack[stack.length - 1]) {
      stack.pop();
    } else if (!stack.length && s[i] === ",") {
      const token = s.substring(start, i).trim();
      if (token) {
        result.push(token);
      }
      start = i + 1;
    }
  }
  const lastToken = s.substring(start).trim();
  if (lastToken) {
    result.push(lastToken);
  }
  return result;
}
__name(splitByComma, "splitByComma");

// src/preview-api/modules/store/decorators.ts
function decorateStory(storyFn, decorator, bindWithContext) {
  const boundStoryFunction = bindWithContext(storyFn);
  return (context) => decorator(boundStoryFunction, context);
}
__name(decorateStory, "decorateStory");
function sanitizeStoryContextUpdate({
  componentId,
  title,
  kind,
  id,
  name,
  story,
  parameters,
  initialArgs,
  argTypes,
  ...update
} = {}) {
  return update;
}
__name(sanitizeStoryContextUpdate, "sanitizeStoryContextUpdate");
function defaultDecorateStory(storyFn, decorators) {
  const contextStore = {};
  const bindWithContext = /* @__PURE__ */ __name((decoratedStoryFn) => (update) => {
    if (!contextStore.value) {
      throw new Error("Decorated function called without init");
    }
    contextStore.value = {
      ...contextStore.value,
      ...sanitizeStoryContextUpdate(update)
    };
    return decoratedStoryFn(contextStore.value);
  }, "bindWithContext");
  const decoratedWithContextStore = decorators.reduce(
    (story, decorator) => decorateStory(story, decorator, bindWithContext),
    storyFn
  );
  return (context) => {
    contextStore.value = context;
    return decoratedWithContextStore(context);
  };
}
__name(defaultDecorateStory, "defaultDecorateStory");

// src/preview-api/modules/store/csf/prepareStory.ts
function prepareStory(storyAnnotations, componentAnnotations, projectAnnotations) {
  const { moduleExport, id, name } = storyAnnotations || {};
  const partialAnnotations = preparePartialAnnotations(
    storyAnnotations,
    componentAnnotations,
    projectAnnotations
  );
  const applyLoaders = /* @__PURE__ */ __name(async (context) => {
    const loaded = {};
    for (const loaders of [
      normalizeArrays(projectAnnotations.loaders),
      normalizeArrays(componentAnnotations.loaders),
      normalizeArrays(storyAnnotations.loaders)
    ]) {
      if (context.abortSignal.aborted) {
        return loaded;
      }
      const loadResults = await Promise.all(loaders.map((loader) => loader(context)));
      Object.assign(loaded, ...loadResults);
    }
    return loaded;
  }, "applyLoaders");
  const applyBeforeEach = /* @__PURE__ */ __name(async (context) => {
    const cleanupCallbacks = new Array();
    for (const beforeEach of [
      ...normalizeArrays(projectAnnotations.beforeEach),
      ...normalizeArrays(componentAnnotations.beforeEach),
      ...normalizeArrays(storyAnnotations.beforeEach)
    ]) {
      if (context.abortSignal.aborted) {
        return cleanupCallbacks;
      }
      const cleanup = await beforeEach(context);
      if (cleanup) {
        cleanupCallbacks.push(cleanup);
      }
    }
    return cleanupCallbacks;
  }, "applyBeforeEach");
  const applyAfterEach = /* @__PURE__ */ __name(async (context) => {
    const reversedFinalizers = [
      ...normalizeArrays(projectAnnotations.afterEach),
      ...normalizeArrays(componentAnnotations.afterEach),
      ...normalizeArrays(storyAnnotations.afterEach)
    ].reverse();
    for (const finalizer of reversedFinalizers) {
      if (context.abortSignal.aborted) {
        return;
      }
      await finalizer(context);
    }
  }, "applyAfterEach");
  const undecoratedStoryFn = /* @__PURE__ */ __name((context) => context.originalStoryFn(context.args, context), "undecoratedStoryFn");
  const { applyDecorators = defaultDecorateStory, runStep } = projectAnnotations;
  const decorators = [
    ...normalizeArrays(storyAnnotations?.decorators),
    ...normalizeArrays(componentAnnotations?.decorators),
    ...normalizeArrays(projectAnnotations?.decorators)
  ];
  const render = storyAnnotations?.userStoryFn || storyAnnotations?.render || componentAnnotations.render || projectAnnotations.render;
  const decoratedStoryFn = applyHooks(applyDecorators)(undecoratedStoryFn, decorators);
  const unboundStoryFn = /* @__PURE__ */ __name((context) => decoratedStoryFn(context), "unboundStoryFn");
  const playFunction = storyAnnotations?.play ?? componentAnnotations?.play;
  const usesMount = mountDestructured(playFunction);
  if (!render && !usesMount) {
    throw new NoRenderFunctionError({ id });
  }
  const defaultMount = /* @__PURE__ */ __name((context) => {
    return async () => {
      await context.renderToCanvas();
      return context.canvas;
    };
  }, "defaultMount");
  const mount = storyAnnotations.mount ?? componentAnnotations.mount ?? projectAnnotations.mount ?? defaultMount;
  const testingLibraryRender = projectAnnotations.testingLibraryRender;
  return {
    storyGlobals: {},
    ...partialAnnotations,
    moduleExport,
    id,
    name,
    story: name,
    originalStoryFn: render,
    undecoratedStoryFn,
    unboundStoryFn,
    applyLoaders,
    applyBeforeEach,
    applyAfterEach,
    playFunction,
    runStep,
    mount,
    testingLibraryRender,
    renderToCanvas: projectAnnotations.renderToCanvas,
    usesMount
  };
}
__name(prepareStory, "prepareStory");
function prepareMeta(componentAnnotations, projectAnnotations, moduleExport) {
  return {
    ...preparePartialAnnotations(void 0, componentAnnotations, projectAnnotations),
    moduleExport
  };
}
__name(prepareMeta, "prepareMeta");
function preparePartialAnnotations(storyAnnotations, componentAnnotations, projectAnnotations) {
  const defaultTags = ["dev", "test"];
  const extraTags = globalThis2.DOCS_OPTIONS?.autodocs === true ? ["autodocs"] : [];
  const overrideTags = storyAnnotations?.tags?.includes("test-fn") ? ["!autodocs"] : [];
  const tags = combineTags(
    ...defaultTags,
    ...extraTags,
    ...projectAnnotations.tags ?? [],
    ...componentAnnotations.tags ?? [],
    ...overrideTags,
    ...storyAnnotations?.tags ?? []
  );
  const parameters = combineParameters(
    projectAnnotations.parameters,
    componentAnnotations.parameters,
    storyAnnotations?.parameters
  );
  const { argTypesEnhancers = [], argsEnhancers = [] } = projectAnnotations;
  const passedArgTypes = combineParameters(
    projectAnnotations.argTypes,
    componentAnnotations.argTypes,
    storyAnnotations?.argTypes
  );
  if (storyAnnotations) {
    const render = storyAnnotations?.userStoryFn || storyAnnotations?.render || componentAnnotations.render || projectAnnotations.render;
    parameters.__isArgsStory = render && render.length > 0;
  }
  const passedArgs = {
    ...projectAnnotations.args,
    ...componentAnnotations.args,
    ...storyAnnotations?.args
  };
  const storyGlobals = {
    ...componentAnnotations.globals,
    ...storyAnnotations?.globals
  };
  const contextForEnhancers = {
    componentId: componentAnnotations.id,
    title: componentAnnotations.title,
    kind: componentAnnotations.title,
    // Back compat
    id: storyAnnotations?.id || componentAnnotations.id,
    // if there's no story name, we create a fake one since enhancers expect a name
    name: storyAnnotations?.name || "__meta",
    story: storyAnnotations?.name || "__meta",
    // Back compat
    component: componentAnnotations.component,
    subcomponents: componentAnnotations.subcomponents,
    tags,
    parameters,
    initialArgs: passedArgs,
    argTypes: passedArgTypes,
    storyGlobals
  };
  contextForEnhancers.argTypes = argTypesEnhancers.reduce(
    (accumulatedArgTypes, enhancer) => enhancer({ ...contextForEnhancers, argTypes: accumulatedArgTypes }),
    contextForEnhancers.argTypes
  );
  const initialArgsBeforeEnhancers = { ...passedArgs };
  contextForEnhancers.initialArgs = [...argsEnhancers].reduce(
    (accumulatedArgs, enhancer) => ({
      ...accumulatedArgs,
      ...enhancer({
        ...contextForEnhancers,
        initialArgs: accumulatedArgs
      })
    }),
    initialArgsBeforeEnhancers
  );
  const { name, story, ...withoutStoryIdentifiers } = contextForEnhancers;
  return withoutStoryIdentifiers;
}
__name(preparePartialAnnotations, "preparePartialAnnotations");
function prepareContext(context) {
  const { args: unmappedArgs } = context;
  let targetedContext = {
    ...context,
    allArgs: void 0,
    argsByTarget: void 0
  };
  if (global3.FEATURES?.argTypeTargetsV7) {
    const argsByTarget = groupArgsByTarget(context);
    targetedContext = {
      ...context,
      allArgs: context.args,
      argsByTarget,
      args: argsByTarget[UNTARGETED] || {}
    };
  }
  const mappedArgs = Object.entries(targetedContext.args).reduce((acc, [key, val]) => {
    if (!targetedContext.argTypes[key]?.mapping) {
      acc[key] = val;
      return acc;
    }
    const mappingFn = /* @__PURE__ */ __name((originalValue) => {
      const mapping = targetedContext.argTypes[key].mapping;
      return mapping && originalValue in mapping ? mapping[originalValue] : originalValue;
    }, "mappingFn");
    acc[key] = Array.isArray(val) ? val.map(mappingFn) : mappingFn(val);
    return acc;
  }, {});
  const includedArgs = Object.entries(mappedArgs).reduce((acc, [key, val]) => {
    const argType = targetedContext.argTypes[key] || {};
    if (includeConditionalArg(argType, mappedArgs, targetedContext.globals)) {
      acc[key] = val;
    }
    return acc;
  }, {});
  return { ...targetedContext, unmappedArgs, args: includedArgs };
}
__name(prepareContext, "prepareContext");

// src/preview-api/modules/store/inferArgTypes.ts
import { logger as logger5 } from "storybook/internal/client-logger";
var inferType = /* @__PURE__ */ __name((value, name, visited) => {
  const type = typeof value;
  switch (type) {
    case "boolean":
    case "string":
    case "number":
    case "function":
    case "symbol":
      return { name: type };
    default:
      break;
  }
  if (value) {
    if (visited.has(value)) {
      logger5.warn(dedent`
        We've detected a cycle in arg '${name}'. Args should be JSON-serializable.

        Consider using the mapping feature or fully custom args:
        - Mapping: https://storybook.js.org/docs/writing-stories/args#mapping-to-complex-arg-values
        - Custom args: https://storybook.js.org/docs/essentials/controls#fully-custom-args
      `);
      return { name: "other", value: "cyclic object" };
    }
    visited.add(value);
    if (Array.isArray(value)) {
      const childType = value.length > 0 ? inferType(value[0], name, new Set(visited)) : { name: "other", value: "unknown" };
      return { name: "array", value: childType };
    }
    const fieldTypes = mapValues(value, (field) => inferType(field, name, new Set(visited)));
    return { name: "object", value: fieldTypes };
  }
  return { name: "object", value: {} };
}, "inferType");
var inferArgTypes = /* @__PURE__ */ __name((context) => {
  const { id, argTypes: userArgTypes = {}, initialArgs = {} } = context;
  const argTypes = mapValues(initialArgs, (arg, key) => ({
    name: key,
    type: inferType(arg, `${id}.${key}`, /* @__PURE__ */ new Set())
  }));
  const userArgTypesNames = mapValues(userArgTypes, (argType, key) => ({
    name: key
  }));
  return combineParameters(argTypes, userArgTypesNames, userArgTypes);
}, "inferArgTypes");
inferArgTypes.secondPass = true;

// src/preview-api/modules/store/inferControls.ts
import { logger as logger6 } from "storybook/internal/client-logger";

// src/preview-api/modules/store/filterArgTypes.ts
var matches = /* @__PURE__ */ __name((name, descriptor) => Array.isArray(descriptor) ? descriptor.includes(name) : name.match(descriptor), "matches");
var filterArgTypes = /* @__PURE__ */ __name((argTypes, include, exclude) => {
  if (!include && !exclude) {
    return argTypes;
  }
  return argTypes && pickBy(argTypes, (argType, key) => {
    const name = argType.name || key.toString();
    return !!(!include || matches(name, include)) && (!exclude || !matches(name, exclude));
  });
}, "filterArgTypes");

// src/preview-api/modules/store/inferControls.ts
var inferControl = /* @__PURE__ */ __name((argType, name, matchers) => {
  const { type, options } = argType;
  if (!type) {
    return void 0;
  }
  if (matchers.color && matchers.color.test(name)) {
    const controlType = type.name;
    if (controlType === "string") {
      return { control: { type: "color" } };
    }
    if (controlType !== "enum") {
      logger6.warn(
        `Addon controls: Control of type color only supports string, received "${controlType}" instead`
      );
    }
  }
  if (matchers.date && matchers.date.test(name)) {
    return { control: { type: "date" } };
  }
  switch (type.name) {
    case "array":
      return { control: { type: "object" } };
    case "boolean":
      return { control: { type: "boolean" } };
    case "string":
      return { control: { type: "text" } };
    case "number":
      return { control: { type: "number" } };
    case "enum": {
      const { value } = type;
      return { control: { type: value?.length <= 5 ? "radio" : "select" }, options: value };
    }
    case "function":
    case "symbol":
      return null;
    default:
      return { control: { type: options ? "select" : "object" } };
  }
}, "inferControl");
var inferControls = /* @__PURE__ */ __name((context) => {
  const {
    argTypes,
    parameters: { __isArgsStory, controls: { include = null, exclude = null, matchers = {} } = {} }
  } = context;
  if (!__isArgsStory) {
    return argTypes;
  }
  const filteredArgTypes = filterArgTypes(argTypes, include, exclude);
  const withControls = mapValues(filteredArgTypes, (argType, name) => {
    return argType?.type && inferControl(argType, name.toString(), matchers);
  });
  return combineParameters(withControls, filteredArgTypes);
}, "inferControls");
inferControls.secondPass = true;

// src/preview-api/modules/store/csf/normalizeProjectAnnotations.ts
function normalizeProjectAnnotations({
  argTypes,
  globalTypes,
  argTypesEnhancers,
  decorators,
  loaders,
  beforeEach,
  afterEach,
  initialGlobals,
  ...annotations
}) {
  return {
    ...argTypes && { argTypes: normalizeInputTypes(argTypes) },
    ...globalTypes && { globalTypes: normalizeInputTypes(globalTypes) },
    decorators: normalizeArrays(decorators),
    loaders: normalizeArrays(loaders),
    beforeEach: normalizeArrays(beforeEach),
    afterEach: normalizeArrays(afterEach),
    argTypesEnhancers: [
      ...argTypesEnhancers || [],
      inferArgTypes,
      // There's an architectural decision to be made regarding embedded addons in core:
      //
      // Option 1: Keep embedded addons but ensure consistency by moving addon-specific code
      // (like inferControls) to live alongside the addon code itself. This maintains the
      // concept of core addons while improving code organization.
      //
      // Option 2: Fully integrate these addons into core, potentially moving UI components
      // into the manager and treating them as core features rather than addons. This is a
      // bigger architectural change requiring careful consideration.
      //
      // For now, we're keeping inferControls here as we need time to properly evaluate
      // these options and their implications. Some features (like Angular's cleanArgsDecorator)
      // currently rely on this behavior.
      //
      // TODO: Make an architectural decision on the handling of core addons
      inferControls
    ],
    initialGlobals,
    ...annotations
  };
}
__name(normalizeProjectAnnotations, "normalizeProjectAnnotations");

// src/preview-api/modules/store/csf/composeConfigs.ts
import { global as global4 } from "@storybook/global";

// src/preview-api/modules/store/csf/beforeAll.ts
var composeBeforeAllHooks = /* @__PURE__ */ __name((hooks) => {
  return async () => {
    const cleanups2 = [];
    for (const hook of hooks) {
      const cleanup = await hook();
      if (cleanup) {
        cleanups2.unshift(cleanup);
      }
    }
    return async () => {
      for (const cleanup of cleanups2) {
        await cleanup();
      }
    };
  };
}, "composeBeforeAllHooks");

// src/preview-api/modules/store/csf/stepRunners.ts
function composeStepRunners(stepRunners) {
  return async (label, play, playContext) => {
    const composedPlay = stepRunners.reduceRight(
      (innerPlay, stepRunner) => async () => stepRunner(label, innerPlay, playContext),
      async () => play(playContext)
    );
    await composedPlay();
  };
}
__name(composeStepRunners, "composeStepRunners");

// src/preview-api/modules/store/csf/composeConfigs.ts
function getField(moduleExportList, field) {
  return moduleExportList.map((xs) => xs.default?.[field] ?? xs[field]).filter(Boolean);
}
__name(getField, "getField");
function getArrayField(moduleExportList, field, options = {}) {
  return getField(moduleExportList, field).reduce((prev, cur) => {
    const normalized = normalizeArrays(cur);
    return options.reverseFileOrder ? [...normalized, ...prev] : [...prev, ...normalized];
  }, []);
}
__name(getArrayField, "getArrayField");
function getObjectField(moduleExportList, field) {
  return Object.assign({}, ...getField(moduleExportList, field));
}
__name(getObjectField, "getObjectField");
function getSingletonField(moduleExportList, field) {
  return getField(moduleExportList, field).pop();
}
__name(getSingletonField, "getSingletonField");
function composeConfigs(moduleExportList) {
  const allArgTypeEnhancers = getArrayField(moduleExportList, "argTypesEnhancers");
  const stepRunners = getField(moduleExportList, "runStep");
  const beforeAllHooks = getArrayField(moduleExportList, "beforeAll");
  return {
    parameters: combineParameters(...getField(moduleExportList, "parameters")),
    decorators: getArrayField(moduleExportList, "decorators", {
      reverseFileOrder: !(global4.FEATURES?.legacyDecoratorFileOrder ?? false)
    }),
    args: getObjectField(moduleExportList, "args"),
    argsEnhancers: getArrayField(moduleExportList, "argsEnhancers"),
    argTypes: getObjectField(moduleExportList, "argTypes"),
    argTypesEnhancers: [
      ...allArgTypeEnhancers.filter((e) => !e.secondPass),
      ...allArgTypeEnhancers.filter((e) => e.secondPass)
    ],
    initialGlobals: getObjectField(moduleExportList, "initialGlobals"),
    globalTypes: getObjectField(moduleExportList, "globalTypes"),
    loaders: getArrayField(moduleExportList, "loaders"),
    beforeAll: composeBeforeAllHooks(beforeAllHooks),
    beforeEach: getArrayField(moduleExportList, "beforeEach"),
    afterEach: getArrayField(moduleExportList, "afterEach"),
    render: getSingletonField(moduleExportList, "render"),
    renderToCanvas: getSingletonField(moduleExportList, "renderToCanvas"),
    applyDecorators: getSingletonField(moduleExportList, "applyDecorators"),
    runStep: composeStepRunners(stepRunners),
    tags: getArrayField(moduleExportList, "tags"),
    mount: getSingletonField(moduleExportList, "mount"),
    testingLibraryRender: getSingletonField(moduleExportList, "testingLibraryRender")
  };
}
__name(composeConfigs, "composeConfigs");

// src/preview-api/modules/store/csf/portable-stories.ts
import { isExportStory as isExportStory2 } from "storybook/internal/csf";
import { getCoreAnnotations } from "storybook/internal/csf";
import { MountMustBeDestructuredError } from "storybook/internal/preview-errors";

// src/preview-api/modules/store/reporter-api.ts
var _ReporterAPI = class _ReporterAPI {
  constructor() {
    this.reports = [];
  }
  async addReport(report) {
    this.reports.push(report);
  }
};
__name(_ReporterAPI, "ReporterAPI");
var ReporterAPI = _ReporterAPI;

// src/preview-api/modules/store/csf/csf-factory-utils.ts
import { isMeta, isStory as isStory2 } from "storybook/internal/csf";
function getCsfFactoryAnnotations(story, meta, projectAnnotations) {
  return isStory2(story) ? {
    story: story.input,
    meta: story.meta.input,
    preview: story.meta.preview.composed
  } : { story, meta: isMeta(meta) ? meta.input : meta, preview: projectAnnotations };
}
__name(getCsfFactoryAnnotations, "getCsfFactoryAnnotations");

// src/preview-api/modules/store/csf/portable-stories.ts
function setDefaultProjectAnnotations(_defaultProjectAnnotations) {
  globalThis.defaultProjectAnnotations = _defaultProjectAnnotations;
}
__name(setDefaultProjectAnnotations, "setDefaultProjectAnnotations");
var DEFAULT_STORY_TITLE = "ComposedStory";
var DEFAULT_STORY_NAME = "Unnamed Story";
function extractAnnotation(annotation) {
  if (!annotation) {
    return {};
  }
  return composeConfigs([annotation]);
}
__name(extractAnnotation, "extractAnnotation");
function setProjectAnnotations(projectAnnotations) {
  const annotations = Array.isArray(projectAnnotations) ? projectAnnotations : [projectAnnotations];
  globalThis.globalProjectAnnotations = composeConfigs([
    ...getCoreAnnotations(),
    globalThis.defaultProjectAnnotations ?? {},
    composeConfigs(annotations.map(extractAnnotation))
  ]);
  return globalThis.globalProjectAnnotations ?? {};
}
__name(setProjectAnnotations, "setProjectAnnotations");
var cleanups = [];
function composeStory(storyAnnotations, componentAnnotations, projectAnnotations, defaultConfig, exportsName) {
  if (storyAnnotations === void 0) {
    throw new Error("Expected a story but received undefined.");
  }
  componentAnnotations.title = componentAnnotations.title ?? DEFAULT_STORY_TITLE;
  const normalizedComponentAnnotations = normalizeComponentAnnotations(componentAnnotations);
  const storyName = exportsName || storyAnnotations.storyName || storyAnnotations.story?.name || storyAnnotations.name || DEFAULT_STORY_NAME;
  const normalizedStory = normalizeStory(
    storyName,
    storyAnnotations,
    normalizedComponentAnnotations
  );
  const normalizedProjectAnnotations = normalizeProjectAnnotations(
    composeConfigs([
      defaultConfig ?? globalThis.globalProjectAnnotations ?? {},
      projectAnnotations ?? {}
    ])
  );
  const story = prepareStory(
    normalizedStory,
    normalizedComponentAnnotations,
    normalizedProjectAnnotations
  );
  const globalsFromGlobalTypes = getValuesFromArgTypes(normalizedProjectAnnotations.globalTypes);
  const globals = {
    ...globalsFromGlobalTypes,
    ...normalizedProjectAnnotations.initialGlobals,
    ...story.storyGlobals
  };
  const reporting = new ReporterAPI();
  const initializeContext = /* @__PURE__ */ __name(() => {
    const context = prepareContext({
      hooks: new HooksContext(),
      globals,
      args: { ...story.initialArgs },
      viewMode: "story",
      reporting,
      loaded: {},
      abortSignal: new AbortController().signal,
      step: /* @__PURE__ */ __name((label, play2) => story.runStep(label, play2, context), "step"),
      canvasElement: null,
      canvas: {},
      userEvent: {},
      globalTypes: normalizedProjectAnnotations.globalTypes,
      ...story,
      context: null,
      mount: null
    });
    context.parameters.__isPortableStory = true;
    context.context = context;
    if (story.renderToCanvas) {
      context.renderToCanvas = async () => {
        const unmount = await story.renderToCanvas?.(
          {
            componentId: story.componentId,
            title: story.title,
            id: story.id,
            name: story.name,
            tags: story.tags,
            showMain: /* @__PURE__ */ __name(() => {
            }, "showMain"),
            showError: /* @__PURE__ */ __name((error) => {
              throw new Error(`${error.title}
${error.description}`);
            }, "showError"),
            showException: /* @__PURE__ */ __name((error) => {
              throw error;
            }, "showException"),
            forceRemount: true,
            storyContext: context,
            storyFn: /* @__PURE__ */ __name(() => story.unboundStoryFn(context), "storyFn"),
            unboundStoryFn: story.unboundStoryFn
          },
          context.canvasElement
        );
        if (unmount) {
          cleanups.push(unmount);
        }
      };
    }
    context.mount = story.mount(context);
    return context;
  }, "initializeContext");
  let loadedContext;
  const play = /* @__PURE__ */ __name(async (extraContext) => {
    const context = initializeContext();
    context.canvasElement ??= globalThis?.document?.body;
    if (loadedContext) {
      context.loaded = loadedContext.loaded;
    }
    Object.assign(context, extraContext);
    return story.playFunction(context);
  }, "play");
  const run = /* @__PURE__ */ __name((extraContext) => {
    const context = initializeContext();
    Object.assign(context, extraContext);
    return runStory(story, context);
  }, "run");
  const playFunction = story.playFunction ? play : void 0;
  const composedStory = Object.assign(
    /* @__PURE__ */ __name(function storyFn(extraArgs) {
      const context = initializeContext();
      if (loadedContext) {
        context.loaded = loadedContext.loaded;
      }
      context.args = {
        ...context.initialArgs,
        ...extraArgs
      };
      return story.unboundStoryFn(context);
    }, "storyFn"),
    {
      id: story.id,
      storyName,
      load: /* @__PURE__ */ __name(async () => {
        for (const callback of [...cleanups].reverse()) {
          await callback();
        }
        cleanups.length = 0;
        const context = initializeContext();
        context.loaded = await story.applyLoaders(context);
        cleanups.push(...(await story.applyBeforeEach(context)).filter(Boolean));
        loadedContext = context;
      }, "load"),
      globals,
      args: story.initialArgs,
      parameters: story.parameters,
      argTypes: story.argTypes,
      play: playFunction,
      run,
      reporting,
      tags: story.tags
    }
  );
  return composedStory;
}
__name(composeStory, "composeStory");
var defaultComposeStory = /* @__PURE__ */ __name((story, component, project, exportsName) => composeStory(story, component, project, {}, exportsName), "defaultComposeStory");
function composeStories(storiesImport, globalConfig, composeStoryFn = defaultComposeStory) {
  const { default: metaExport, __esModule, __namedExportsOrder, ...stories } = storiesImport;
  let meta = metaExport;
  const composedStories = Object.entries(stories).reduce(
    (storiesMap, [exportsName, story]) => {
      const { story: storyAnnotations, meta: componentAnnotations } = getCsfFactoryAnnotations(story);
      if (!meta && componentAnnotations) {
        meta = componentAnnotations;
      }
      if (!isExportStory2(exportsName, meta)) {
        return storiesMap;
      }
      const result = Object.assign(storiesMap, {
        [exportsName]: composeStoryFn(storyAnnotations, meta, globalConfig, exportsName)
      });
      return result;
    },
    {}
  );
  return composedStories;
}
__name(composeStories, "composeStories");
function createPlaywrightTest(baseTest) {
  return baseTest.extend({
    mount: /* @__PURE__ */ __name(async ({ mount, page }, use) => {
      await use(async (storyRef, ...restArgs) => {
        if (!("__pw_type" in storyRef) || "__pw_type" in storyRef && storyRef.__pw_type !== "jsx") {
          throw new Error(dedent`
              Portable stories in Playwright CT only work when referencing JSX elements.
              Please use JSX format for your components such as:

              instead of:
              await mount(MyComponent, { props: { foo: 'bar' } })

              do:
              await mount(<MyComponent foo="bar"/>)

              More info: https://storybook.js.org/docs/api/portable-stories/portable-stories-playwright?ref=error
            `);
        }
        const { props, ...storyRefWithoutProps } = storyRef;
        await page.evaluate(async (wrappedStoryRef) => {
          const unwrappedStoryRef = await globalThis.__pwUnwrapObject?.(wrappedStoryRef);
          const story = "__pw_type" in unwrappedStoryRef ? unwrappedStoryRef.type : unwrappedStoryRef;
          return story?.load?.();
        }, storyRefWithoutProps);
        const mountResult = await mount(storyRef, ...restArgs);
        await page.evaluate(async (wrappedStoryRef) => {
          const unwrappedStoryRef = await globalThis.__pwUnwrapObject?.(wrappedStoryRef);
          const story = "__pw_type" in unwrappedStoryRef ? unwrappedStoryRef.type : unwrappedStoryRef;
          const canvasElement = document.querySelector("#root");
          return story?.play?.({ canvasElement });
        }, storyRefWithoutProps);
        return mountResult;
      });
    }, "mount")
  });
}
__name(createPlaywrightTest, "createPlaywrightTest");
async function runStory(story, context) {
  for (const callback of [...cleanups].reverse()) {
    await callback();
  }
  cleanups.length = 0;
  if (!context.canvasElement) {
    const container = document.createElement("div");
    globalThis?.document?.body?.appendChild(container);
    context.canvasElement = container;
    cleanups.push(() => {
      if (globalThis?.document?.body?.contains(container)) {
        globalThis?.document?.body?.removeChild(container);
      }
    });
  }
  context.loaded = await story.applyLoaders(context);
  if (context.abortSignal.aborted) {
    return;
  }
  cleanups.push(...(await story.applyBeforeEach(context)).filter(Boolean));
  const playFunction = story.playFunction;
  const isMountDestructured = story.usesMount;
  if (!isMountDestructured) {
    await context.mount();
  }
  if (context.abortSignal.aborted) {
    return;
  }
  if (playFunction) {
    if (!isMountDestructured) {
      context.mount = async () => {
        throw new MountMustBeDestructuredError({ playFunction: playFunction.toString() });
      };
    }
    await playFunction(context);
  }
  let cleanUp;
  if (isTestEnvironment()) {
    cleanUp = pauseAnimations();
  } else {
    await waitForAnimations(context.abortSignal);
  }
  await story.applyAfterEach(context);
  await cleanUp?.();
}
__name(runStory, "runStory");

// src/preview-api/modules/store/StoryStore.ts
var CSF_CACHE_SIZE = 1e3;
var STORY_CACHE_SIZE = 1e4;
var _StoryStore = class _StoryStore {
  constructor(storyIndex, importFn, projectAnnotations) {
    this.importFn = importFn;
    this.storyIndex = new StoryIndexStore(storyIndex);
    this.projectAnnotations = normalizeProjectAnnotations(
      composeConfigs([...getCoreAnnotations2(), projectAnnotations])
    );
    const { initialGlobals, globalTypes } = this.projectAnnotations;
    this.args = new ArgsStore();
    this.userGlobals = new GlobalsStore({ globals: initialGlobals, globalTypes });
    this.hooks = {};
    this.cleanupCallbacks = {};
    this.processCSFFileWithCache = (0, import_memoizerific2.default)(CSF_CACHE_SIZE)(processCSFFile);
    this.prepareMetaWithCache = (0, import_memoizerific2.default)(CSF_CACHE_SIZE)(prepareMeta);
    this.prepareStoryWithCache = (0, import_memoizerific2.default)(STORY_CACHE_SIZE)(prepareStory);
  }
  setProjectAnnotations(projectAnnotations) {
    this.projectAnnotations = normalizeProjectAnnotations(projectAnnotations);
    const { initialGlobals, globalTypes } = projectAnnotations;
    this.userGlobals.set({ globals: initialGlobals, globalTypes });
  }
  // This means that one of the CSF files has changed.
  // If the `importFn` has changed, we will invalidate both caches.
  // If the `storyIndex` data has changed, we may or may not invalidate the caches, depending
  // on whether we've loaded the relevant files yet.
  async onStoriesChanged({
    importFn,
    storyIndex
  }) {
    if (importFn) {
      this.importFn = importFn;
    }
    if (storyIndex) {
      this.storyIndex.entries = storyIndex.entries;
    }
    if (this.cachedCSFFiles) {
      await this.cacheAllCSFFiles();
    }
  }
  // Get an entry from the index, waiting on initialization if necessary
  async storyIdToEntry(storyId) {
    return this.storyIndex.storyIdToEntry(storyId);
  }
  // To load a single CSF file to service a story we need to look up the importPath in the index
  async loadCSFFileByStoryId(storyId) {
    const { importPath, title } = this.storyIndex.storyIdToEntry(storyId);
    const moduleExports = await this.importFn(importPath);
    return this.processCSFFileWithCache(moduleExports, importPath, title);
  }
  async loadAllCSFFiles() {
    const importPaths = {};
    Object.entries(this.storyIndex.entries).forEach(([storyId, { importPath }]) => {
      importPaths[importPath] = storyId;
    });
    const list = await Promise.all(
      Object.entries(importPaths).map(async ([importPath, storyId]) => ({
        importPath,
        csfFile: await this.loadCSFFileByStoryId(storyId)
      }))
    );
    return list.reduce(
      (acc, { importPath, csfFile }) => {
        acc[importPath] = csfFile;
        return acc;
      },
      {}
    );
  }
  async cacheAllCSFFiles() {
    this.cachedCSFFiles = await this.loadAllCSFFiles();
  }
  preparedMetaFromCSFFile({ csfFile }) {
    const componentAnnotations = csfFile.meta;
    return this.prepareMetaWithCache(
      componentAnnotations,
      this.projectAnnotations,
      csfFile.moduleExports.default
    );
  }
  // Load the CSF file for a story and prepare the story from it and the project annotations.
  async loadStory({ storyId }) {
    const csfFile = await this.loadCSFFileByStoryId(storyId);
    return this.storyFromCSFFile({ storyId, csfFile });
  }
  // This function is synchronous for convenience -- often times if you have a CSF file already
  // it is easier not to have to await `loadStory`.
  storyFromCSFFile({
    storyId,
    csfFile
  }) {
    const storyAnnotations = csfFile.stories[storyId];
    if (!storyAnnotations) {
      throw new MissingStoryFromCsfFileError({ storyId });
    }
    const componentAnnotations = csfFile.meta;
    const story = this.prepareStoryWithCache(
      storyAnnotations,
      componentAnnotations,
      csfFile.projectAnnotations ?? this.projectAnnotations
    );
    this.args.setInitial(story);
    this.hooks[story.id] = this.hooks[story.id] || new HooksContext();
    return story;
  }
  // If we have a CSF file we can get all the stories from it synchronously
  componentStoriesFromCSFFile({
    csfFile
  }) {
    return Object.keys(this.storyIndex.entries).filter((storyId) => !!csfFile.stories[storyId]).map((storyId) => this.storyFromCSFFile({ storyId, csfFile }));
  }
  async loadEntry(id) {
    const entry = await this.storyIdToEntry(id);
    const storyImports = entry.type === "docs" ? entry.storiesImports : [];
    const [entryExports, ...csfFiles] = await Promise.all([
      this.importFn(entry.importPath),
      ...storyImports.map((storyImportPath) => {
        const firstStoryEntry = this.storyIndex.importPathToEntry(storyImportPath);
        return this.loadCSFFileByStoryId(firstStoryEntry.id);
      })
    ]);
    return { entryExports, csfFiles };
  }
  // A prepared story does not include args, globals or hooks. These are stored in the story store
  // and updated separately to the (immutable) story.
  getStoryContext(story, { forceInitialArgs = false } = {}) {
    const userGlobals = this.userGlobals.get();
    const { initialGlobals } = this.userGlobals;
    const reporting = new ReporterAPI();
    return prepareContext({
      ...story,
      args: forceInitialArgs ? story.initialArgs : this.args.get(story.id),
      initialGlobals,
      globalTypes: this.projectAnnotations.globalTypes,
      userGlobals,
      reporting,
      globals: {
        ...userGlobals,
        ...story.storyGlobals
      },
      hooks: this.hooks[story.id]
    });
  }
  addCleanupCallbacks(story, ...callbacks) {
    this.cleanupCallbacks[story.id] = (this.cleanupCallbacks[story.id] || []).concat(callbacks);
  }
  async cleanupStory(story) {
    this.hooks[story.id].clean();
    const callbacks = this.cleanupCallbacks[story.id];
    if (callbacks) {
      for (const callback of [...callbacks].reverse()) {
        await callback();
      }
    }
    delete this.cleanupCallbacks[story.id];
  }
  extract(options = { includeDocsOnly: false }) {
    const { cachedCSFFiles } = this;
    console.log("extract: extracting stories", cachedCSFFiles);
    if (!cachedCSFFiles) {
      throw new CalledExtractOnStoreError();
    }
    const stories = Object.entries(this.storyIndex.entries).reduce(
      (acc, [storyId, entry]) => {
        if (entry.type === "docs") {
          return acc;
        }
        const csfFile = cachedCSFFiles[entry.importPath];
        const story = this.storyFromCSFFile({ storyId, csfFile });
        if (!options.includeDocsOnly && story.parameters.docsOnly) {
          return acc;
        }
        acc[storyId] = Object.entries(story).reduce(
          (storyAcc, [key, value]) => {
            if (key === "story" && entry.subtype === "test") {
              return { ...storyAcc, story: entry.parentName };
            }
            if (key === "moduleExport") {
              return storyAcc;
            }
            if (typeof value === "function") {
              return storyAcc;
            }
            if (Array.isArray(value)) {
              return Object.assign(storyAcc, { [key]: value.slice().sort() });
            }
            return Object.assign(storyAcc, { [key]: value });
          },
          {
            args: story.initialArgs,
            globals: {
              ...this.userGlobals.initialGlobals,
              ...this.userGlobals.globals,
              ...story.storyGlobals
            },
            storyId: entry.parent ? entry.parent : storyId
          }
        );
        return acc;
      },
      {}
    );
    console.log("extract: stories", stories);
    return stories;
  }
};
__name(_StoryStore, "StoryStore");
var StoryStore = _StoryStore;

// src/preview-api/modules/store/autoTitle.ts
import { once as once2 } from "storybook/internal/client-logger";

// ../node_modules/slash/index.js
function slash(path) {
  const isExtendedLengthPath = path.startsWith("\\\\?\\");
  if (isExtendedLengthPath) {
    return path;
  }
  return path.replace(/\\/g, "/");
}
__name(slash, "slash");

// src/preview-api/modules/store/autoTitle.ts
var sanitize2 = /* @__PURE__ */ __name((parts) => {
  if (parts.length === 0) {
    return parts;
  }
  const last = parts[parts.length - 1];
  const lastStripped = last?.replace(/(?:[.](?:story|stories))?([.][^.]+)$/i, "");
  if (parts.length === 1) {
    return [lastStripped];
  }
  const nextToLast = parts[parts.length - 2];
  if (lastStripped && nextToLast && lastStripped.toLowerCase() === nextToLast.toLowerCase()) {
    return [...parts.slice(0, -2), lastStripped];
  }
  return lastStripped && (/^(story|stories)([.][^.]+)$/i.test(last) || /^index$/i.test(lastStripped)) ? parts.slice(0, -1) : [...parts.slice(0, -1), lastStripped];
}, "sanitize");
function pathJoin(paths) {
  return paths.flatMap((p) => p.split("/")).filter(Boolean).join("/");
}
__name(pathJoin, "pathJoin");
var userOrAutoTitleFromSpecifier = /* @__PURE__ */ __name((fileName, entry, userTitle) => {
  const { directory, importPathMatcher, titlePrefix = "" } = entry || {};
  if (typeof fileName === "number") {
    once2.warn(dedent`
      CSF Auto-title received a numeric fileName. This typically happens when
      webpack is mis-configured in production mode. To force webpack to produce
      filenames, set optimization.moduleIds = "named" in your webpack config.
    `);
  }
  const normalizedFileName = slash(String(fileName));
  if (importPathMatcher.exec(normalizedFileName)) {
    if (!userTitle) {
      const suffix = normalizedFileName.replace(directory, "");
      let parts = pathJoin([titlePrefix, suffix]).split("/");
      parts = sanitize2(parts);
      return parts.join("/");
    }
    if (!titlePrefix) {
      return userTitle;
    }
    return pathJoin([titlePrefix, userTitle]);
  }
  return void 0;
}, "userOrAutoTitleFromSpecifier");
var userOrAutoTitle = /* @__PURE__ */ __name((fileName, storiesEntries, userTitle) => {
  for (let i = 0; i < storiesEntries.length; i += 1) {
    const title = userOrAutoTitleFromSpecifier(fileName, storiesEntries[i], userTitle);
    if (title) {
      return title;
    }
  }
  return userTitle || void 0;
}, "userOrAutoTitle");

// src/preview-api/modules/store/storySort.ts
var STORY_KIND_PATH_SEPARATOR = /\s*\/\s*/;
var storySort = /* @__PURE__ */ __name((options = {}) => (a, b) => {
  if (a.title === b.title && !options.includeNames) {
    return 0;
  }
  const method = options.method || "configure";
  let order = options.order || [];
  const storyTitleA = a.title.trim().split(STORY_KIND_PATH_SEPARATOR);
  const storyTitleB = b.title.trim().split(STORY_KIND_PATH_SEPARATOR);
  if (options.includeNames) {
    storyTitleA.push(a.name);
    storyTitleB.push(b.name);
  }
  let depth = 0;
  while (storyTitleA[depth] || storyTitleB[depth]) {
    if (!storyTitleA[depth]) {
      return -1;
    }
    if (!storyTitleB[depth]) {
      return 1;
    }
    const nameA = storyTitleA[depth];
    const nameB = storyTitleB[depth];
    if (nameA !== nameB) {
      let indexA = order.indexOf(nameA);
      let indexB = order.indexOf(nameB);
      const indexWildcard = order.indexOf("*");
      if (indexA !== -1 || indexB !== -1) {
        if (indexA === -1) {
          if (indexWildcard !== -1) {
            indexA = indexWildcard;
          } else {
            indexA = order.length;
          }
        }
        if (indexB === -1) {
          if (indexWildcard !== -1) {
            indexB = indexWildcard;
          } else {
            indexB = order.length;
          }
        }
        return indexA - indexB;
      }
      if (method === "configure") {
        return 0;
      }
      return nameA.localeCompare(nameB, options.locales ? options.locales : void 0, {
        numeric: true,
        sensitivity: "accent"
      });
    }
    let index = order.indexOf(nameA);
    if (index === -1) {
      index = order.indexOf("*");
    }
    order = index !== -1 && Array.isArray(order[index + 1]) ? order[index + 1] : [];
    depth += 1;
  }
  return 0;
}, "storySort");

// src/preview-api/modules/store/sortStories.ts
var sortStoriesCommon = /* @__PURE__ */ __name((stories, storySortParameter, fileNameOrder) => {
  if (storySortParameter) {
    let sortFn;
    if (typeof storySortParameter === "function") {
      sortFn = storySortParameter;
    } else {
      sortFn = storySort(storySortParameter);
    }
    stories.sort(sortFn);
  } else {
    stories.sort(
      (s1, s2) => fileNameOrder.indexOf(s1.importPath) - fileNameOrder.indexOf(s2.importPath)
    );
  }
  return stories;
}, "sortStoriesCommon");
var sortStoriesV7 = /* @__PURE__ */ __name((stories, storySortParameter, fileNameOrder) => {
  try {
    return sortStoriesCommon(stories, storySortParameter, fileNameOrder);
  } catch (err) {
    throw new Error(dedent`
    Error sorting stories with sort parameter ${storySortParameter}:

    > ${err.message}

    Are you using a V6-style sort function in V7 mode?

    More info: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#v7-style-story-sort
  `);
  }
}, "sortStoriesV7");

// src/preview-api/modules/preview-web/Preview.tsx
import { deprecate as deprecate2, logger as logger7 } from "storybook/internal/client-logger";
import {
  ARGTYPES_INFO_REQUEST,
  ARGTYPES_INFO_RESPONSE,
  CONFIG_ERROR,
  FORCE_REMOUNT,
  FORCE_RE_RENDER as FORCE_RE_RENDER2,
  GLOBALS_UPDATED,
  PREVIEW_INITIALIZED,
  RESET_STORY_ARGS as RESET_STORY_ARGS2,
  SET_GLOBALS,
  STORY_ARGS_UPDATED,
  STORY_HOT_UPDATED,
  STORY_INDEX_INVALIDATED,
  UPDATE_GLOBALS as UPDATE_GLOBALS2,
  UPDATE_STORY_ARGS as UPDATE_STORY_ARGS2
} from "storybook/internal/core-events";
import {
  CalledPreviewMethodBeforeInitializationError,
  MissingRenderToCanvasError,
  StoryIndexFetchError,
  StoryStoreAccessedBeforeInitializationError
} from "storybook/internal/preview-errors";
import { global as global5 } from "@storybook/global";

// src/preview-api/modules/preview-web/render/StoryRender.ts
import {
  PLAY_FUNCTION_THREW_EXCEPTION,
  STORY_FINISHED,
  STORY_RENDERED as STORY_RENDERED2,
  STORY_RENDER_PHASE_CHANGED,
  UNHANDLED_ERRORS_WHILE_PLAYING
} from "storybook/internal/core-events";
import {
  MountMustBeDestructuredError as MountMustBeDestructuredError2,
  NoStoryMountedError
} from "storybook/internal/preview-errors";

// src/preview-api/modules/preview-web/render/Render.ts
var PREPARE_ABORTED = new Error("prepareAborted");

// src/preview-api/modules/preview-web/render/StoryRender.ts
var { AbortController: AbortController2 } = globalThis;
function serializeError(error) {
  try {
    const { name = "Error", message = String(error), stack } = error;
    return { name, message, stack };
  } catch (e) {
    return { name: "Error", message: String(error) };
  }
}
__name(serializeError, "serializeError");
var _StoryRender = class _StoryRender {
  constructor(channel, store, renderToScreen, callbacks, id, viewMode, renderOptions = { autoplay: true, forceInitialArgs: false }, story) {
    this.channel = channel;
    this.store = store;
    this.renderToScreen = renderToScreen;
    this.callbacks = callbacks;
    this.id = id;
    this.viewMode = viewMode;
    this.renderOptions = renderOptions;
    this.type = "story";
    this.notYetRendered = true;
    this.rerenderEnqueued = false;
    this.disableKeyListeners = false;
    this.teardownRender = /* @__PURE__ */ __name(() => {
    }, "teardownRender");
    this.torndown = false;
    this.abortController = new AbortController2();
    this.renderId = Date.now();
    if (story) {
      this.story = story;
      this.phase = "preparing";
    }
  }
  async runPhase(signal, phase, phaseFn) {
    this.phase = phase;
    this.channel.emit(STORY_RENDER_PHASE_CHANGED, {
      newPhase: this.phase,
      renderId: this.renderId,
      storyId: this.id
    });
    if (phaseFn) {
      await phaseFn();
      this.checkIfAborted(signal);
    }
  }
  checkIfAborted(signal) {
    if (signal.aborted && !["finished", "aborted", "errored"].includes(this.phase)) {
      this.phase = "aborted";
      this.channel.emit(STORY_RENDER_PHASE_CHANGED, {
        newPhase: this.phase,
        renderId: this.renderId,
        storyId: this.id
      });
    }
    return signal.aborted;
  }
  async prepare() {
    await this.runPhase(this.abortController.signal, "preparing", async () => {
      this.story = await this.store.loadStory({ storyId: this.id });
    });
    if (this.abortController.signal.aborted) {
      await this.store.cleanupStory(this.story);
      throw PREPARE_ABORTED;
    }
  }
  // The two story "renders" are equal and have both loaded the same story
  isEqual(other) {
    return !!(this.id === other.id && this.story && this.story === other.story);
  }
  isPreparing() {
    return ["preparing"].includes(this.phase);
  }
  isPending() {
    return ["loading", "beforeEach", "rendering", "playing", "afterEach"].includes(
      this.phase
    );
  }
  async renderToElement(canvasElement) {
    this.canvasElement = canvasElement;
    return this.render({ initial: true, forceRemount: true });
  }
  storyContext() {
    if (!this.story) {
      throw new Error(`Cannot call storyContext before preparing`);
    }
    const { forceInitialArgs } = this.renderOptions;
    return this.store.getStoryContext(this.story, { forceInitialArgs });
  }
  async render({
    initial = false,
    forceRemount = false
  } = {}) {
    const { canvasElement } = this;
    if (!this.story) {
      throw new Error("cannot render when not prepared");
    }
    const story = this.story;
    if (!canvasElement) {
      throw new Error("cannot render when canvasElement is unset");
    }
    const {
      id,
      componentId,
      title,
      name,
      tags,
      applyLoaders,
      applyBeforeEach,
      applyAfterEach,
      unboundStoryFn,
      playFunction,
      runStep
    } = story;
    if (forceRemount && !initial) {
      this.cancelRender();
      this.abortController = new AbortController2();
    }
    const abortSignal = this.abortController.signal;
    let mounted = false;
    const isMountDestructured = story.usesMount;
    try {
      const context = {
        ...this.storyContext(),
        viewMode: this.viewMode,
        abortSignal,
        canvasElement,
        loaded: {},
        step: /* @__PURE__ */ __name((label, play) => runStep(label, play, context), "step"),
        context: null,
        canvas: {},
        userEvent: {},
        renderToCanvas: /* @__PURE__ */ __name(async () => {
          const teardown = await this.renderToScreen(renderContext, canvasElement);
          this.teardownRender = teardown || (() => {
          });
          mounted = true;
        }, "renderToCanvas"),
        // The story provides (set in a renderer) a mount function that is a higher order function
        // (context) => (...args) => Canvas
        //
        // Before assigning it to the context, we resolve the context dependency,
        // so that a user can just call it as await mount(...args) in their play function.
        mount: /* @__PURE__ */ __name(async (...args) => {
          this.callbacks.showStoryDuringRender?.();
          let mountReturn = null;
          await this.runPhase(abortSignal, "rendering", async () => {
            mountReturn = await story.mount(context)(...args);
          });
          if (isMountDestructured) {
            await this.runPhase(abortSignal, "playing");
          }
          return mountReturn;
        }, "mount")
      };
      context.context = context;
      const renderContext = {
        componentId,
        title,
        kind: title,
        id,
        name,
        story: name,
        tags,
        ...this.callbacks,
        showError: /* @__PURE__ */ __name((error) => {
          this.phase = "errored";
          return this.callbacks.showError(error);
        }, "showError"),
        showException: /* @__PURE__ */ __name((error) => {
          this.phase = "errored";
          return this.callbacks.showException(error);
        }, "showException"),
        forceRemount: forceRemount || this.notYetRendered,
        storyContext: context,
        storyFn: /* @__PURE__ */ __name(() => unboundStoryFn(context), "storyFn"),
        unboundStoryFn
      };
      await this.runPhase(abortSignal, "loading", async () => {
        context.loaded = await applyLoaders(context);
      });
      if (abortSignal.aborted) {
        return;
      }
      const cleanupCallbacks = await applyBeforeEach(context);
      this.store.addCleanupCallbacks(story, ...cleanupCallbacks);
      if (this.checkIfAborted(abortSignal)) {
        return;
      }
      if (!mounted && !isMountDestructured) {
        await context.mount();
      }
      this.notYetRendered = false;
      if (abortSignal.aborted) {
        return;
      }
      const ignoreUnhandledErrors = this.story.parameters?.test?.dangerouslyIgnoreUnhandledErrors === true;
      const unhandledErrors = /* @__PURE__ */ new Set();
      const onError = /* @__PURE__ */ __name((event) => {
        if (event.error) {
          unhandledErrors.add(event.error);
        }
      }, "onError");
      const onUnhandledRejection = /* @__PURE__ */ __name((event) => {
        if (event.reason) {
          unhandledErrors.add(event.reason);
        }
      }, "onUnhandledRejection");
      if (this.renderOptions.autoplay && forceRemount && playFunction && this.phase !== "errored") {
        window?.addEventListener?.("error", onError);
        window?.addEventListener?.("unhandledrejection", onUnhandledRejection);
        this.disableKeyListeners = true;
        try {
          if (!isMountDestructured) {
            context.mount = async () => {
              throw new MountMustBeDestructuredError2({ playFunction: playFunction.toString() });
            };
            await this.runPhase(abortSignal, "playing", async () => playFunction(context));
          } else {
            await playFunction(context);
          }
          if (!mounted) {
            throw new NoStoryMountedError();
          }
          this.checkIfAborted(abortSignal);
          if (!ignoreUnhandledErrors && unhandledErrors.size > 0) {
            await this.runPhase(abortSignal, "errored");
          } else {
            await this.runPhase(abortSignal, "played");
          }
        } catch (error) {
          this.callbacks.showStoryDuringRender?.();
          await this.runPhase(abortSignal, "errored", async () => {
            this.channel.emit(PLAY_FUNCTION_THREW_EXCEPTION, serializeError(error));
          });
          if (this.story.parameters.throwPlayFunctionExceptions !== false) {
            throw error;
          }
          console.error(error);
        }
        if (!ignoreUnhandledErrors && unhandledErrors.size > 0) {
          this.channel.emit(
            UNHANDLED_ERRORS_WHILE_PLAYING,
            Array.from(unhandledErrors).map(serializeError)
          );
        }
        this.disableKeyListeners = false;
        window?.removeEventListener?.("unhandledrejection", onUnhandledRejection);
        window?.removeEventListener?.("error", onError);
        if (abortSignal.aborted) {
          return;
        }
      }
      await this.runPhase(abortSignal, "completing", async () => {
        if (isTestEnvironment()) {
          this.store.addCleanupCallbacks(story, pauseAnimations());
        } else {
          await waitForAnimations(abortSignal);
        }
      });
      await this.runPhase(abortSignal, "completed", async () => {
        this.channel.emit(STORY_RENDERED2, id);
      });
      if (this.phase !== "errored") {
        await this.runPhase(abortSignal, "afterEach", async () => {
          await applyAfterEach(context);
        });
      }
      const hasUnhandledErrors = !ignoreUnhandledErrors && unhandledErrors.size > 0;
      const hasSomeReportsFailed = context.reporting.reports.some(
        (report) => report.status === "failed"
      );
      const hasStoryErrored = hasUnhandledErrors || hasSomeReportsFailed;
      await this.runPhase(
        abortSignal,
        "finished",
        async () => this.channel.emit(STORY_FINISHED, {
          storyId: id,
          status: hasStoryErrored ? "error" : "success",
          reporters: context.reporting.reports
        })
      );
    } catch (err) {
      this.phase = "errored";
      this.callbacks.showException(err);
      await this.runPhase(
        abortSignal,
        "finished",
        async () => this.channel.emit(STORY_FINISHED, {
          storyId: id,
          status: "error",
          reporters: []
        })
      );
    }
    if (this.rerenderEnqueued) {
      this.rerenderEnqueued = false;
      this.render();
    }
  }
  /**
   * Rerender the story. If the story is currently pending (loading/rendering), the rerender will be
   * enqueued, and will be executed after the current render is completed. Rerendering while playing
   * will not be enqueued, and will be executed immediately, to support rendering args changes while
   * playing.
   */
  async rerender() {
    if (this.isPending() && this.phase !== "playing") {
      this.rerenderEnqueued = true;
    } else {
      return this.render();
    }
  }
  async remount() {
    await this.teardown();
    return this.render({ forceRemount: true });
  }
  // If the story is torn down (either a new story is rendered or the docs page removes it)
  // we need to consider the fact that the initial render may not be finished
  // (possibly the loaders or the play function are still running). We use the controller
  // as a method to abort them, ASAP, but this is not foolproof as we cannot control what
  // happens inside the user's code.
  cancelRender() {
    this.abortController.abort();
  }
  cancelPlayFunction() {
    if (this.phase === "playing") {
      this.abortController.abort();
      this.runPhase(this.abortController.signal, "aborted");
    }
  }
  async teardown() {
    this.torndown = true;
    this.cancelRender();
    if (this.story) {
      await this.store.cleanupStory(this.story);
    }
    for (let i = 0; i < 3; i += 1) {
      if (!this.isPending()) {
        await this.teardownRender();
        return;
      }
      await new Promise((resolve) => setTimeout(resolve, 0));
    }
    window?.location?.reload?.();
    await new Promise(() => {
    });
  }
};
__name(_StoryRender, "StoryRender");
var StoryRender = _StoryRender;

// src/preview-api/modules/preview-web/Preview.tsx
var { fetch } = global5;
var STORY_INDEX_PATH = "./index.json";
var _Preview = class _Preview {
  constructor(importFn, getProjectAnnotations, channel = addons.getChannel(), shouldInitialize = true) {
    this.importFn = importFn;
    this.getProjectAnnotations = getProjectAnnotations;
    this.channel = channel;
    this.storyRenders = [];
    this.storeInitializationPromise = new Promise((resolve, reject) => {
      this.resolveStoreInitializationPromise = resolve;
      this.rejectStoreInitializationPromise = reject;
    });
    if (shouldInitialize) {
      this.initialize();
    }
  }
  // Create a proxy object for `__STORYBOOK_STORY_STORE__` and `__STORYBOOK_PREVIEW__.storyStore`
  // That proxies through to the store once ready, and errors beforehand. This means we can set
  // `__STORYBOOK_STORY_STORE__ = __STORYBOOK_PREVIEW__.storyStore` without having to wait, and
  // similarly integrators can access the `storyStore` on the preview at any time, although
  // it is considered deprecated and we will no longer allow access in 9.0
  get storyStore() {
    return new Proxy(
      {},
      {
        get: /* @__PURE__ */ __name((_, method) => {
          if (this.storyStoreValue) {
            deprecate2("Accessing the Story Store is deprecated and will be removed in 9.0");
            return this.storyStoreValue[method];
          }
          throw new StoryStoreAccessedBeforeInitializationError();
        }, "get")
      }
    );
  }
  // INITIALIZATION
  async initialize() {
    this.setupListeners();
    try {
      const projectAnnotations = await this.getProjectAnnotationsOrRenderError();
      await this.runBeforeAllHook(projectAnnotations);
      await this.initializeWithProjectAnnotations(projectAnnotations);
      const userAgent = globalThis?.navigator?.userAgent;
      await this.channel.emit(PREVIEW_INITIALIZED, { userAgent });
    } catch (err) {
      this.rejectStoreInitializationPromise(err);
    }
  }
  ready() {
    return this.storeInitializationPromise;
  }
  setupListeners() {
    this.channel.on(STORY_INDEX_INVALIDATED, this.onStoryIndexChanged.bind(this));
    this.channel.on(UPDATE_GLOBALS2, this.onUpdateGlobals.bind(this));
    this.channel.on(UPDATE_STORY_ARGS2, this.onUpdateArgs.bind(this));
    this.channel.on(ARGTYPES_INFO_REQUEST, this.onRequestArgTypesInfo.bind(this));
    this.channel.on(RESET_STORY_ARGS2, this.onResetArgs.bind(this));
    this.channel.on(FORCE_RE_RENDER2, this.onForceReRender.bind(this));
    this.channel.on(FORCE_REMOUNT, this.onForceRemount.bind(this));
    this.channel.on(STORY_HOT_UPDATED, this.onStoryHotUpdated.bind(this));
  }
  async getProjectAnnotationsOrRenderError() {
    try {
      const projectAnnotations = await this.getProjectAnnotations();
      this.renderToCanvas = projectAnnotations.renderToCanvas;
      if (!this.renderToCanvas) {
        throw new MissingRenderToCanvasError();
      }
      return projectAnnotations;
    } catch (err) {
      this.renderPreviewEntryError("Error reading preview.js:", err);
      throw err;
    }
  }
  // If initialization gets as far as project annotations, this function runs.
  async initializeWithProjectAnnotations(projectAnnotations) {
    this.projectAnnotationsBeforeInitialization = projectAnnotations;
    try {
      const storyIndex = await this.getStoryIndexFromServer();
      return this.initializeWithStoryIndex(storyIndex);
    } catch (err) {
      this.renderPreviewEntryError("Error loading story index:", err);
      throw err;
    }
  }
  async runBeforeAllHook(projectAnnotations) {
    try {
      await this.beforeAllCleanup?.();
      this.beforeAllCleanup = await projectAnnotations.beforeAll?.();
    } catch (err) {
      this.renderPreviewEntryError("Error in beforeAll hook:", err);
      throw err;
    }
  }
  async getStoryIndexFromServer() {
    const result = await fetch(STORY_INDEX_PATH);
    if (result.status === 200) {
      return result.json();
    }
    throw new StoryIndexFetchError({ text: await result.text() });
  }
  // If initialization gets as far as the story index, this function runs.
  initializeWithStoryIndex(storyIndex) {
    if (!this.projectAnnotationsBeforeInitialization) {
      throw new Error("Cannot call initializeWithStoryIndex until project annotations resolve");
    }
    this.storyStoreValue = new StoryStore(
      storyIndex,
      this.importFn,
      this.projectAnnotationsBeforeInitialization
    );
    delete this.projectAnnotationsBeforeInitialization;
    this.setInitialGlobals();
    this.resolveStoreInitializationPromise();
  }
  async setInitialGlobals() {
    this.emitGlobals();
  }
  emitGlobals() {
    if (!this.storyStoreValue) {
      throw new CalledPreviewMethodBeforeInitializationError({ methodName: "emitGlobals" });
    }
    const payload = {
      globals: this.storyStoreValue.userGlobals.get() || {},
      globalTypes: this.storyStoreValue.projectAnnotations.globalTypes || {}
    };
    this.channel.emit(SET_GLOBALS, payload);
  }
  // EVENT HANDLERS
  // This happens when a config file gets reloaded
  async onGetProjectAnnotationsChanged({
    getProjectAnnotations
  }) {
    delete this.previewEntryError;
    this.getProjectAnnotations = getProjectAnnotations;
    const projectAnnotations = await this.getProjectAnnotationsOrRenderError();
    await this.runBeforeAllHook(projectAnnotations);
    if (!this.storyStoreValue) {
      await this.initializeWithProjectAnnotations(projectAnnotations);
      return;
    }
    this.storyStoreValue.setProjectAnnotations(projectAnnotations);
    this.emitGlobals();
  }
  async onStoryIndexChanged() {
    delete this.previewEntryError;
    if (!this.storyStoreValue && !this.projectAnnotationsBeforeInitialization) {
      return;
    }
    try {
      const storyIndex = await this.getStoryIndexFromServer();
      if (this.projectAnnotationsBeforeInitialization) {
        this.initializeWithStoryIndex(storyIndex);
        return;
      }
      await this.onStoriesChanged({ storyIndex });
    } catch (err) {
      this.renderPreviewEntryError("Error loading story index:", err);
      throw err;
    }
  }
  // This happens when a glob gets HMR-ed
  async onStoriesChanged({
    importFn,
    storyIndex
  }) {
    if (!this.storyStoreValue) {
      throw new CalledPreviewMethodBeforeInitializationError({ methodName: "onStoriesChanged" });
    }
    await this.storyStoreValue.onStoriesChanged({ importFn, storyIndex });
  }
  async onUpdateGlobals({
    globals: updatedGlobals,
    currentStory
  }) {
    if (!this.storyStoreValue) {
      await this.storeInitializationPromise;
    }
    if (!this.storyStoreValue) {
      throw new CalledPreviewMethodBeforeInitializationError({ methodName: "onUpdateGlobals" });
    }
    this.storyStoreValue.userGlobals.update(updatedGlobals);
    if (currentStory) {
      const { initialGlobals, storyGlobals, userGlobals, globals } = this.storyStoreValue.getStoryContext(currentStory);
      this.channel.emit(GLOBALS_UPDATED, {
        initialGlobals,
        userGlobals,
        storyGlobals,
        globals
      });
    } else {
      const { initialGlobals, globals } = this.storyStoreValue.userGlobals;
      this.channel.emit(GLOBALS_UPDATED, {
        initialGlobals,
        userGlobals: globals,
        storyGlobals: {},
        globals
      });
    }
    await Promise.all(this.storyRenders.map((r) => r.rerender()));
  }
  async onUpdateArgs({ storyId, updatedArgs }) {
    if (!this.storyStoreValue) {
      throw new CalledPreviewMethodBeforeInitializationError({ methodName: "onUpdateArgs" });
    }
    this.storyStoreValue.args.update(storyId, updatedArgs);
    await Promise.all(
      this.storyRenders.filter((r) => r.id === storyId && !r.renderOptions.forceInitialArgs).map(
        (r) => (
          // We only run the play function, with in a force remount.
          // But when mount is destructured, the rendering happens inside of the play function.
          r.story && r.story.usesMount ? r.remount() : r.rerender()
        )
      )
    );
    this.channel.emit(STORY_ARGS_UPDATED, {
      storyId,
      args: this.storyStoreValue.args.get(storyId)
    });
  }
  async onRequestArgTypesInfo({ id, payload }) {
    try {
      await this.storeInitializationPromise;
      const story = await this.storyStoreValue?.loadStory(payload);
      this.channel.emit(ARGTYPES_INFO_RESPONSE, {
        id,
        success: true,
        payload: { argTypes: story?.argTypes || {} },
        error: null
      });
    } catch (e) {
      this.channel.emit(ARGTYPES_INFO_RESPONSE, {
        id,
        success: false,
        error: e?.message
      });
    }
  }
  async onResetArgs({ storyId, argNames }) {
    if (!this.storyStoreValue) {
      throw new CalledPreviewMethodBeforeInitializationError({ methodName: "onResetArgs" });
    }
    const render = this.storyRenders.find((r) => r.id === storyId);
    const story = render?.story || await this.storyStoreValue.loadStory({ storyId });
    const argNamesToReset = argNames || [
      .../* @__PURE__ */ new Set([
        ...Object.keys(story.initialArgs),
        ...Object.keys(this.storyStoreValue.args.get(storyId))
      ])
    ];
    const updatedArgs = argNamesToReset.reduce((acc, argName) => {
      acc[argName] = story.initialArgs[argName];
      return acc;
    }, {});
    await this.onUpdateArgs({ storyId, updatedArgs });
  }
  // ForceReRender does not include a story id, so we simply must
  // re-render all stories in case they are relevant
  async onForceReRender() {
    await Promise.all(this.storyRenders.map((r) => r.rerender()));
  }
  async onForceRemount({ storyId }) {
    await Promise.all(this.storyRenders.filter((r) => r.id === storyId).map((r) => r.remount()));
  }
  async onStoryHotUpdated() {
    await Promise.all(this.storyRenders.map((r) => r.cancelPlayFunction()));
  }
  // Used by docs to render a story to a given element
  // Note this short-circuits the `prepare()` phase of the StoryRender,
  // main to be consistent with the previous behaviour. In the future,
  // we will change it to go ahead and load the story, which will end up being
  // "instant", although async.
  renderStoryToElement(story, element, callbacks, options) {
    if (!this.renderToCanvas || !this.storyStoreValue) {
      throw new CalledPreviewMethodBeforeInitializationError({
        methodName: "renderStoryToElement"
      });
    }
    const render = new StoryRender(
      this.channel,
      this.storyStoreValue,
      this.renderToCanvas,
      callbacks,
      story.id,
      "docs",
      options,
      story
    );
    render.renderToElement(element);
    this.storyRenders.push(render);
    return async () => {
      await this.teardownRender(render);
    };
  }
  async teardownRender(render, { viewModeChanged } = {}) {
    this.storyRenders = this.storyRenders.filter((r) => r !== render);
    await render?.teardown?.({ viewModeChanged });
  }
  // API
  async loadStory({ storyId }) {
    if (!this.storyStoreValue) {
      throw new CalledPreviewMethodBeforeInitializationError({ methodName: "loadStory" });
    }
    return this.storyStoreValue.loadStory({ storyId });
  }
  getStoryContext(story, { forceInitialArgs = false } = {}) {
    if (!this.storyStoreValue) {
      throw new CalledPreviewMethodBeforeInitializationError({ methodName: "getStoryContext" });
    }
    return this.storyStoreValue.getStoryContext(story, { forceInitialArgs });
  }
  async extract(options) {
    if (!this.storyStoreValue) {
      throw new CalledPreviewMethodBeforeInitializationError({ methodName: "extract" });
    }
    if (this.previewEntryError) {
      throw this.previewEntryError;
    }
    await this.storyStoreValue.cacheAllCSFFiles();
    return this.storyStoreValue.extract(options);
  }
  // UTILITIES
  renderPreviewEntryError(reason, err) {
    this.previewEntryError = err;
    logger7.error(reason);
    logger7.error(err);
    this.channel.emit(CONFIG_ERROR, err);
  }
};
__name(_Preview, "Preview");
var Preview = _Preview;

// src/preview-api/modules/preview-web/PreviewWeb.tsx
import { global as global8 } from "@storybook/global";

// src/preview-api/modules/preview-web/PreviewWithSelection.tsx
import { logger as logger8 } from "storybook/internal/client-logger";
import {
  CURRENT_STORY_WAS_SET,
  DOCS_PREPARED,
  GLOBALS_UPDATED as GLOBALS_UPDATED2,
  PRELOAD_ENTRIES,
  PREVIEW_KEYDOWN,
  SET_CURRENT_STORY,
  STORY_CHANGED,
  STORY_ERRORED,
  STORY_MISSING,
  STORY_PREPARED,
  STORY_RENDER_PHASE_CHANGED as STORY_RENDER_PHASE_CHANGED2,
  STORY_SPECIFIED,
  STORY_THREW_EXCEPTION,
  STORY_UNCHANGED,
  UPDATE_QUERY_PARAMS
} from "storybook/internal/core-events";
import {
  CalledPreviewMethodBeforeInitializationError as CalledPreviewMethodBeforeInitializationError2,
  EmptyIndexError,
  MdxFileWithNoCsfReferencesError,
  NoStoryMatchError
} from "storybook/internal/preview-errors";

// src/preview-api/modules/preview-web/render/CsfDocsRender.ts
import { DOCS_RENDERED } from "storybook/internal/core-events";

// src/preview-api/modules/preview-web/docs-context/DocsContext.ts
import { isStory as isStory3 } from "storybook/internal/csf";
var _DocsContext = class _DocsContext {
  constructor(channel, store, renderStoryToElement, csfFiles) {
    this.channel = channel;
    this.store = store;
    this.renderStoryToElement = renderStoryToElement;
    this.storyIdByName = /* @__PURE__ */ __name((storyName) => {
      const storyId = this.nameToStoryId.get(storyName);
      if (storyId) {
        return storyId;
      }
      throw new Error(`No story found with that name: ${storyName}`);
    }, "storyIdByName");
    this.componentStories = /* @__PURE__ */ __name(() => {
      return this.componentStoriesValue;
    }, "componentStories");
    this.componentStoriesFromCSFFile = /* @__PURE__ */ __name((csfFile) => {
      return this.store.componentStoriesFromCSFFile({ csfFile });
    }, "componentStoriesFromCSFFile");
    this.storyById = /* @__PURE__ */ __name((storyId) => {
      if (!storyId) {
        if (!this.primaryStory) {
          throw new Error(
            `No primary story defined for docs entry. Did you forget to use \`<Meta>\`?`
          );
        }
        return this.primaryStory;
      }
      const csfFile = this.storyIdToCSFFile.get(storyId);
      if (!csfFile) {
        throw new Error(`Called \`storyById\` for story that was never loaded: ${storyId}`);
      }
      return this.store.storyFromCSFFile({ storyId, csfFile });
    }, "storyById");
    this.getStoryContext = /* @__PURE__ */ __name((story) => {
      return {
        ...this.store.getStoryContext(story),
        loaded: {},
        viewMode: "docs"
      };
    }, "getStoryContext");
    this.loadStory = /* @__PURE__ */ __name((id) => {
      return this.store.loadStory({ storyId: id });
    }, "loadStory");
    this.componentStoriesValue = [];
    this.storyIdToCSFFile = /* @__PURE__ */ new Map();
    this.exportToStory = /* @__PURE__ */ new Map();
    this.exportsToCSFFile = /* @__PURE__ */ new Map();
    this.nameToStoryId = /* @__PURE__ */ new Map();
    this.attachedCSFFiles = /* @__PURE__ */ new Set();
    csfFiles.forEach((csfFile, index) => {
      this.referenceCSFFile(csfFile);
    });
  }
  // This docs entry references this CSF file and can synchronously load the stories, as well
  // as reference them by module export. If the CSF is part of the "component" stories, they
  // can also be referenced by name and are in the componentStories list.
  referenceCSFFile(csfFile) {
    this.exportsToCSFFile.set(csfFile.moduleExports, csfFile);
    this.exportsToCSFFile.set(csfFile.moduleExports.default, csfFile);
    const stories = this.store.componentStoriesFromCSFFile({ csfFile });
    stories.forEach((story) => {
      const annotation = csfFile.stories[story.id];
      this.storyIdToCSFFile.set(annotation.id, csfFile);
      this.exportToStory.set(annotation.moduleExport, story);
    });
  }
  attachCSFFile(csfFile) {
    if (!this.exportsToCSFFile.has(csfFile.moduleExports)) {
      throw new Error("Cannot attach a CSF file that has not been referenced");
    }
    if (this.attachedCSFFiles.has(csfFile)) {
      return;
    }
    this.attachedCSFFiles.add(csfFile);
    const stories = this.store.componentStoriesFromCSFFile({ csfFile });
    stories.forEach((story) => {
      this.nameToStoryId.set(story.name, story.id);
      this.componentStoriesValue.push(story);
      if (!this.primaryStory) {
        this.primaryStory = story;
      }
    });
  }
  referenceMeta(metaExports, attach) {
    const resolved = this.resolveModuleExport(metaExports);
    if (resolved.type !== "meta") {
      throw new Error(
        "<Meta of={} /> must reference a CSF file module export or meta export. Did you mistakenly reference your component instead of your CSF file?"
      );
    }
    if (attach) {
      this.attachCSFFile(resolved.csfFile);
    }
  }
  get projectAnnotations() {
    const { projectAnnotations } = this.store;
    if (!projectAnnotations) {
      throw new Error("Can't get projectAnnotations from DocsContext before they are initialized");
    }
    return projectAnnotations;
  }
  resolveAttachedModuleExportType(moduleExportType) {
    if (moduleExportType === "story") {
      if (!this.primaryStory) {
        throw new Error(
          `No primary story attached to this docs file, did you forget to use <Meta of={} />?`
        );
      }
      return { type: "story", story: this.primaryStory };
    }
    if (this.attachedCSFFiles.size === 0) {
      throw new Error(
        `No CSF file attached to this docs file, did you forget to use <Meta of={} />?`
      );
    }
    const firstAttachedCSFFile = Array.from(this.attachedCSFFiles)[0];
    if (moduleExportType === "meta") {
      return { type: "meta", csfFile: firstAttachedCSFFile };
    }
    const { component } = firstAttachedCSFFile.meta;
    if (!component) {
      throw new Error(
        `Attached CSF file does not defined a component, did you forget to export one?`
      );
    }
    return { type: "component", component };
  }
  resolveModuleExport(moduleExportOrType) {
    const csfFile = this.exportsToCSFFile.get(moduleExportOrType);
    if (csfFile) {
      return { type: "meta", csfFile };
    }
    const story = this.exportToStory.get(
      isStory3(moduleExportOrType) ? moduleExportOrType.input : moduleExportOrType
    );
    if (story) {
      return { type: "story", story };
    }
    return { type: "component", component: moduleExportOrType };
  }
  resolveOf(moduleExportOrType, validTypes = []) {
    let resolved;
    if (["component", "meta", "story"].includes(moduleExportOrType)) {
      const type = moduleExportOrType;
      resolved = this.resolveAttachedModuleExportType(type);
    } else {
      resolved = this.resolveModuleExport(moduleExportOrType);
    }
    if (validTypes.length && !validTypes.includes(resolved.type)) {
      const prettyType = resolved.type === "component" ? "component or unknown" : resolved.type;
      throw new Error(dedent`Invalid value passed to the 'of' prop. The value was resolved to a '${prettyType}' type but the only types for this block are: ${validTypes.join(
        ", "
      )}.
        - Did you pass a component to the 'of' prop when the block only supports a story or a meta?
        - ... or vice versa?
        - Did you pass a story, CSF file or meta to the 'of' prop that is not indexed, ie. is not targeted by the 'stories' globs in the main configuration?`);
    }
    switch (resolved.type) {
      case "component": {
        return {
          ...resolved,
          projectAnnotations: this.projectAnnotations
        };
      }
      case "meta": {
        return {
          ...resolved,
          preparedMeta: this.store.preparedMetaFromCSFFile({ csfFile: resolved.csfFile })
        };
      }
      case "story":
      default: {
        return resolved;
      }
    }
  }
};
__name(_DocsContext, "DocsContext");
var DocsContext = _DocsContext;

// src/preview-api/modules/preview-web/render/CsfDocsRender.ts
var _CsfDocsRender = class _CsfDocsRender {
  constructor(channel, store, entry, callbacks) {
    this.channel = channel;
    this.store = store;
    this.entry = entry;
    this.callbacks = callbacks;
    this.type = "docs";
    this.subtype = "csf";
    this.torndown = false;
    this.disableKeyListeners = false;
    this.preparing = false;
    this.id = entry.id;
    this.renderId = Date.now();
  }
  isPreparing() {
    return this.preparing;
  }
  async prepare() {
    this.preparing = true;
    const { entryExports, csfFiles = [] } = await this.store.loadEntry(this.id);
    if (this.torndown) {
      throw PREPARE_ABORTED;
    }
    const { importPath, title } = this.entry;
    const primaryCsfFile = this.store.processCSFFileWithCache(
      entryExports,
      importPath,
      title
    );
    const primaryStoryId = Object.keys(primaryCsfFile.stories)[0];
    this.story = this.store.storyFromCSFFile({ storyId: primaryStoryId, csfFile: primaryCsfFile });
    this.csfFiles = [primaryCsfFile, ...csfFiles];
    this.preparing = false;
  }
  isEqual(other) {
    return !!(this.id === other.id && this.story && this.story === other.story);
  }
  docsContext(renderStoryToElement) {
    if (!this.csfFiles) {
      throw new Error("Cannot render docs before preparing");
    }
    const docsContext = new DocsContext(
      this.channel,
      this.store,
      renderStoryToElement,
      this.csfFiles
    );
    this.csfFiles.forEach((csfFile) => docsContext.attachCSFFile(csfFile));
    return docsContext;
  }
  async renderToElement(canvasElement, renderStoryToElement) {
    if (!this.story || !this.csfFiles) {
      throw new Error("Cannot render docs before preparing");
    }
    const docsContext = this.docsContext(renderStoryToElement);
    const { docs: docsParameter } = this.story.parameters || {};
    if (!docsParameter) {
      throw new Error(
        `Cannot render a story in viewMode=docs if \`@storybook/addon-docs\` is not installed`
      );
    }
    const renderer = await docsParameter.renderer();
    const { render } = renderer;
    const renderDocs = /* @__PURE__ */ __name(async () => {
      try {
        await render(docsContext, docsParameter, canvasElement);
        this.channel.emit(DOCS_RENDERED, this.id);
      } catch (err) {
        this.callbacks.showException(err);
      }
    }, "renderDocs");
    this.rerender = async () => renderDocs();
    this.teardownRender = async ({ viewModeChanged }) => {
      if (!viewModeChanged || !canvasElement) {
        return;
      }
      renderer.unmount(canvasElement);
    };
    return renderDocs();
  }
  async teardown({ viewModeChanged } = {}) {
    this.teardownRender?.({ viewModeChanged });
    this.torndown = true;
  }
};
__name(_CsfDocsRender, "CsfDocsRender");
var CsfDocsRender = _CsfDocsRender;

// src/preview-api/modules/preview-web/render/MdxDocsRender.ts
import { DOCS_RENDERED as DOCS_RENDERED2 } from "storybook/internal/core-events";
var _MdxDocsRender = class _MdxDocsRender {
  constructor(channel, store, entry, callbacks) {
    this.channel = channel;
    this.store = store;
    this.entry = entry;
    this.callbacks = callbacks;
    this.type = "docs";
    this.subtype = "mdx";
    this.torndown = false;
    this.disableKeyListeners = false;
    this.preparing = false;
    this.id = entry.id;
    this.renderId = Date.now();
  }
  isPreparing() {
    return this.preparing;
  }
  async prepare() {
    this.preparing = true;
    const { entryExports, csfFiles = [] } = await this.store.loadEntry(this.id);
    if (this.torndown) {
      throw PREPARE_ABORTED;
    }
    this.csfFiles = csfFiles;
    this.exports = entryExports;
    this.preparing = false;
  }
  isEqual(other) {
    return !!(this.id === other.id && this.exports && this.exports === other.exports);
  }
  docsContext(renderStoryToElement) {
    if (!this.csfFiles) {
      throw new Error("Cannot render docs before preparing");
    }
    return new DocsContext(
      this.channel,
      this.store,
      renderStoryToElement,
      this.csfFiles
    );
  }
  async renderToElement(canvasElement, renderStoryToElement) {
    if (!this.exports || !this.csfFiles || !this.store.projectAnnotations) {
      throw new Error("Cannot render docs before preparing");
    }
    const docsContext = this.docsContext(renderStoryToElement);
    const { docs } = this.store.projectAnnotations.parameters ?? {};
    if (!docs) {
      throw new Error(
        `Cannot render a story in viewMode=docs if \`@storybook/addon-docs\` is not installed`
      );
    }
    const docsParameter = { ...docs, page: this.exports.default };
    const renderer = await docs.renderer();
    const { render } = renderer;
    const renderDocs = /* @__PURE__ */ __name(async () => {
      try {
        await render(docsContext, docsParameter, canvasElement);
        this.channel.emit(DOCS_RENDERED2, this.id);
      } catch (err) {
        this.callbacks.showException(err);
      }
    }, "renderDocs");
    this.rerender = async () => renderDocs();
    this.teardownRender = async ({ viewModeChanged } = {}) => {
      if (!viewModeChanged || !canvasElement) {
        return;
      }
      renderer.unmount(canvasElement);
      this.torndown = true;
    };
    return renderDocs();
  }
  async teardown({ viewModeChanged } = {}) {
    this.teardownRender?.({ viewModeChanged });
    this.torndown = true;
  }
};
__name(_MdxDocsRender, "MdxDocsRender");
var MdxDocsRender = _MdxDocsRender;

// src/preview-api/modules/preview-web/PreviewWithSelection.tsx
var globalWindow = globalThis;
function focusInInput(event) {
  const target = event.composedPath && event.composedPath()[0] || event.target;
  return /input|textarea/i.test(target.tagName) || target.getAttribute("contenteditable") !== null;
}
__name(focusInInput, "focusInInput");
var ATTACHED_MDX_TAG = "attached-mdx";
var UNATTACHED_MDX_TAG = "unattached-mdx";
function isMdxEntry({ tags }) {
  return tags?.includes(UNATTACHED_MDX_TAG) || tags?.includes(ATTACHED_MDX_TAG);
}
__name(isMdxEntry, "isMdxEntry");
function isStoryRender(r) {
  return r.type === "story";
}
__name(isStoryRender, "isStoryRender");
function isDocsRender(r) {
  return r.type === "docs";
}
__name(isDocsRender, "isDocsRender");
function isCsfDocsRender(r) {
  return isDocsRender(r) && r.subtype === "csf";
}
__name(isCsfDocsRender, "isCsfDocsRender");
var _PreviewWithSelection = class _PreviewWithSelection extends Preview {
  constructor(importFn, getProjectAnnotations, selectionStore, view) {
    super(importFn, getProjectAnnotations, void 0, false);
    this.importFn = importFn;
    this.getProjectAnnotations = getProjectAnnotations;
    this.selectionStore = selectionStore;
    this.view = view;
    this.initialize();
  }
  setupListeners() {
    super.setupListeners();
    globalWindow.onkeydown = this.onKeydown.bind(this);
    this.channel.on(SET_CURRENT_STORY, this.onSetCurrentStory.bind(this));
    this.channel.on(UPDATE_QUERY_PARAMS, this.onUpdateQueryParams.bind(this));
    this.channel.on(PRELOAD_ENTRIES, this.onPreloadStories.bind(this));
  }
  async setInitialGlobals() {
    if (!this.storyStoreValue) {
      throw new CalledPreviewMethodBeforeInitializationError2({ methodName: "setInitialGlobals" });
    }
    const { globals } = this.selectionStore.selectionSpecifier || {};
    if (globals) {
      this.storyStoreValue.userGlobals.updateFromPersisted(globals);
    }
    this.emitGlobals();
  }
  // If initialization gets as far as the story index, this function runs.
  async initializeWithStoryIndex(storyIndex) {
    await super.initializeWithStoryIndex(storyIndex);
    return this.selectSpecifiedStory();
  }
  // Use the selection specifier to choose a story, then render it
  async selectSpecifiedStory() {
    if (!this.storyStoreValue) {
      throw new CalledPreviewMethodBeforeInitializationError2({
        methodName: "selectSpecifiedStory"
      });
    }
    if (this.selectionStore.selection) {
      await this.renderSelection();
      return;
    }
    if (!this.selectionStore.selectionSpecifier) {
      this.renderMissingStory();
      return;
    }
    const { storySpecifier, args } = this.selectionStore.selectionSpecifier;
    const entry = this.storyStoreValue.storyIndex.entryFromSpecifier(storySpecifier);
    if (!entry) {
      if (storySpecifier === "*") {
        this.renderStoryLoadingException(storySpecifier, new EmptyIndexError());
      } else {
        this.renderStoryLoadingException(
          storySpecifier,
          new NoStoryMatchError({ storySpecifier: storySpecifier.toString() })
        );
      }
      return;
    }
    const { id: storyId, type: viewMode } = entry;
    this.selectionStore.setSelection({ storyId, viewMode });
    this.channel.emit(STORY_SPECIFIED, this.selectionStore.selection);
    this.channel.emit(CURRENT_STORY_WAS_SET, this.selectionStore.selection);
    await this.renderSelection({ persistedArgs: args });
  }
  // EVENT HANDLERS
  // This happens when a config file gets reloaded
  async onGetProjectAnnotationsChanged({
    getProjectAnnotations
  }) {
    await super.onGetProjectAnnotationsChanged({ getProjectAnnotations });
    if (this.selectionStore.selection) {
      this.renderSelection();
    }
  }
  // This happens when a glob gets HMR-ed
  async onStoriesChanged({
    importFn,
    storyIndex
  }) {
    await super.onStoriesChanged({ importFn, storyIndex });
    if (this.selectionStore.selection) {
      await this.renderSelection();
    } else {
      await this.selectSpecifiedStory();
    }
  }
  onKeydown(event) {
    if (!this.storyRenders.find((r) => r.disableKeyListeners) && !focusInInput(event)) {
      const { altKey, ctrlKey, metaKey, shiftKey, key, code, keyCode } = event;
      this.channel.emit(PREVIEW_KEYDOWN, {
        event: { altKey, ctrlKey, metaKey, shiftKey, key, code, keyCode }
      });
    }
  }
  async onSetCurrentStory(selection) {
    this.selectionStore.setSelection({ viewMode: "story", ...selection });
    await this.storeInitializationPromise;
    this.channel.emit(CURRENT_STORY_WAS_SET, this.selectionStore.selection);
    this.renderSelection();
  }
  onUpdateQueryParams(queryParams) {
    this.selectionStore.setQueryParams(queryParams);
  }
  async onUpdateGlobals({ globals }) {
    const currentStory = this.currentRender instanceof StoryRender && this.currentRender.story || void 0;
    super.onUpdateGlobals({ globals, currentStory });
    if (this.currentRender instanceof MdxDocsRender || this.currentRender instanceof CsfDocsRender) {
      await this.currentRender.rerender?.();
    }
  }
  async onUpdateArgs({ storyId, updatedArgs }) {
    super.onUpdateArgs({ storyId, updatedArgs });
  }
  async onPreloadStories({ ids }) {
    await this.storeInitializationPromise;
    if (this.storyStoreValue) {
      await Promise.allSettled(ids.map((id) => this.storyStoreValue?.loadEntry(id)));
    }
  }
  // RENDERING
  // We can either have:
  // - a story selected in "story" viewMode,
  //     in which case we render it to the root element, OR
  // - a story selected in "docs" viewMode,
  //     in which case we render the docsPage for that story
  async renderSelection({ persistedArgs } = {}) {
    const { renderToCanvas } = this;
    if (!this.storyStoreValue || !renderToCanvas) {
      throw new CalledPreviewMethodBeforeInitializationError2({ methodName: "renderSelection" });
    }
    const { selection } = this.selectionStore;
    if (!selection) {
      throw new Error("Cannot call renderSelection as no selection was made");
    }
    const { storyId } = selection;
    let entry;
    try {
      entry = await this.storyStoreValue.storyIdToEntry(storyId);
    } catch (err) {
      if (this.currentRender) {
        await this.teardownRender(this.currentRender);
      }
      this.renderStoryLoadingException(storyId, err);
      return;
    }
    const storyIdChanged = this.currentSelection?.storyId !== storyId;
    const viewModeChanged = this.currentRender?.type !== entry.type;
    if (entry.type === "story") {
      this.view.showPreparingStory({ immediate: viewModeChanged });
    } else {
      this.view.showPreparingDocs({ immediate: viewModeChanged });
    }
    if (this.currentRender?.isPreparing()) {
      await this.teardownRender(this.currentRender);
    }
    let render;
    if (entry.type === "story") {
      render = new StoryRender(
        this.channel,
        this.storyStoreValue,
        renderToCanvas,
        this.mainStoryCallbacks(storyId),
        storyId,
        "story"
      );
    } else if (isMdxEntry(entry)) {
      render = new MdxDocsRender(
        this.channel,
        this.storyStoreValue,
        entry,
        this.mainStoryCallbacks(storyId)
      );
    } else {
      render = new CsfDocsRender(
        this.channel,
        this.storyStoreValue,
        entry,
        this.mainStoryCallbacks(storyId)
      );
    }
    const lastSelection = this.currentSelection;
    this.currentSelection = selection;
    const lastRender = this.currentRender;
    this.currentRender = render;
    try {
      await render.prepare();
    } catch (err) {
      if (lastRender) {
        await this.teardownRender(lastRender);
      }
      if (err !== PREPARE_ABORTED) {
        this.renderStoryLoadingException(storyId, err);
      }
      return;
    }
    const implementationChanged = !storyIdChanged && lastRender && !render.isEqual(lastRender);
    if (persistedArgs && isStoryRender(render)) {
      invariant(!!render.story);
      this.storyStoreValue.args.updateFromPersisted(render.story, persistedArgs);
    }
    if (lastRender && !lastRender.torndown && !storyIdChanged && !implementationChanged && !viewModeChanged) {
      this.currentRender = lastRender;
      this.channel.emit(STORY_UNCHANGED, storyId);
      this.view.showMain();
      return;
    }
    if (lastRender) {
      await this.teardownRender(lastRender, { viewModeChanged });
    }
    if (lastSelection && (storyIdChanged || viewModeChanged)) {
      this.channel.emit(STORY_CHANGED, storyId);
    }
    if (isStoryRender(render)) {
      invariant(!!render.story);
      const {
        parameters,
        initialArgs,
        argTypes,
        unmappedArgs,
        initialGlobals,
        userGlobals,
        storyGlobals,
        globals
      } = this.storyStoreValue.getStoryContext(render.story);
      this.channel.emit(STORY_PREPARED, {
        id: storyId,
        parameters,
        initialArgs,
        argTypes,
        args: unmappedArgs
      });
      this.channel.emit(GLOBALS_UPDATED2, { userGlobals, storyGlobals, globals, initialGlobals });
    } else {
      let { parameters } = this.storyStoreValue.projectAnnotations;
      const { initialGlobals, globals } = this.storyStoreValue.userGlobals;
      this.channel.emit(GLOBALS_UPDATED2, {
        globals,
        initialGlobals,
        storyGlobals: {},
        userGlobals: globals
      });
      if (isCsfDocsRender(render) || render.entry.tags?.includes(ATTACHED_MDX_TAG)) {
        if (!render.csfFiles) {
          throw new MdxFileWithNoCsfReferencesError({ storyId });
        }
        ({ parameters } = this.storyStoreValue.preparedMetaFromCSFFile({
          csfFile: render.csfFiles[0]
        }));
      }
      this.channel.emit(DOCS_PREPARED, {
        id: storyId,
        parameters
      });
    }
    if (isStoryRender(render)) {
      invariant(!!render.story);
      this.storyRenders.push(render);
      this.currentRender.renderToElement(
        this.view.prepareForStory(render.story)
      );
    } else {
      this.currentRender.renderToElement(
        this.view.prepareForDocs(),
        // This argument is used for docs, which is currently only compatible with HTMLElements
        this.renderStoryToElement.bind(this)
      );
    }
  }
  async teardownRender(render, { viewModeChanged = false } = {}) {
    this.storyRenders = this.storyRenders.filter((r) => r !== render);
    await render?.teardown?.({ viewModeChanged });
  }
  // UTILITIES
  mainStoryCallbacks(storyId) {
    return {
      showStoryDuringRender: /* @__PURE__ */ __name(() => this.view.showStoryDuringRender(), "showStoryDuringRender"),
      showMain: /* @__PURE__ */ __name(() => this.view.showMain(), "showMain"),
      showError: /* @__PURE__ */ __name((err) => this.renderError(storyId, err), "showError"),
      showException: /* @__PURE__ */ __name((err) => this.renderException(storyId, err), "showException")
    };
  }
  renderPreviewEntryError(reason, err) {
    super.renderPreviewEntryError(reason, err);
    this.view.showErrorDisplay(err);
  }
  renderMissingStory() {
    this.view.showNoPreview();
    this.channel.emit(STORY_MISSING);
  }
  renderStoryLoadingException(storySpecifier, err) {
    logger8.error(err);
    this.view.showErrorDisplay(err);
    this.channel.emit(STORY_MISSING, storySpecifier);
  }
  // renderException is used if we fail to render the story and it is uncaught by the app layer
  renderException(storyId, error) {
    const { name = "Error", message = String(error), stack } = error;
    const renderId = this.currentRender?.renderId;
    this.channel.emit(STORY_THREW_EXCEPTION, { name, message, stack });
    this.channel.emit(STORY_RENDER_PHASE_CHANGED2, { newPhase: "errored", renderId, storyId });
    this.view.showErrorDisplay(error);
    logger8.error(`Error rendering story '${storyId}':`);
    logger8.error(error);
  }
  // renderError is used by the various app layers to inform the user they have done something
  // wrong -- for instance returned the wrong thing from a story
  renderError(storyId, { title, description }) {
    const renderId = this.currentRender?.renderId;
    this.channel.emit(STORY_ERRORED, { title, description });
    this.channel.emit(STORY_RENDER_PHASE_CHANGED2, { newPhase: "errored", renderId, storyId });
    this.view.showErrorDisplay({ message: title, stack: description });
    logger8.error(`Error rendering story ${title}: ${description}`);
  }
};
__name(_PreviewWithSelection, "PreviewWithSelection");
var PreviewWithSelection = _PreviewWithSelection;

// src/preview-api/modules/preview-web/UrlStore.ts
var import_picoquery2 = __toESM(require_main(), 1);
import { global as global6 } from "@storybook/global";

// src/preview-api/modules/preview-web/parseArgsParam.ts
import { once as once3 } from "storybook/internal/client-logger";
var import_picoquery = __toESM(require_main(), 1);
var VALIDATION_REGEXP = /^[a-zA-Z0-9 _-]*$/;
var NUMBER_REGEXP = /^-?[0-9]+(\.[0-9]+)?$/;
var HEX_REGEXP = /^#([a-f0-9]{3,4}|[a-f0-9]{6}|[a-f0-9]{8})$/i;
var COLOR_REGEXP = /^(rgba?|hsla?)\(([0-9]{1,3}),\s?([0-9]{1,3})%?,\s?([0-9]{1,3})%?,?\s?([0-9](\.[0-9]{1,2})?)?\)$/i;
var validateArgs = /* @__PURE__ */ __name((key = "", value) => {
  if (key === null) {
    return false;
  }
  if (key === "" || !VALIDATION_REGEXP.test(key)) {
    return false;
  }
  if (value === null || value === void 0) {
    return true;
  }
  if (value instanceof Date) {
    return true;
  }
  if (typeof value === "number" || typeof value === "boolean") {
    return true;
  }
  if (typeof value === "string") {
    return VALIDATION_REGEXP.test(value) || NUMBER_REGEXP.test(value) || HEX_REGEXP.test(value) || COLOR_REGEXP.test(value);
  }
  if (Array.isArray(value)) {
    return value.every((v) => validateArgs(key, v));
  }
  if (isPlainObject(value)) {
    return Object.entries(value).every(([k, v]) => validateArgs(k, v));
  }
  return false;
}, "validateArgs");
var QUERY_OPTIONS = {
  delimiter: ";",
  // we're parsing a single query param
  nesting: true,
  arrayRepeat: true,
  arrayRepeatSyntax: "bracket",
  nestingSyntax: "js",
  // objects are encoded using dot notation
  valueDeserializer(str) {
    if (str.startsWith("!")) {
      if (str === "!undefined") {
        return void 0;
      }
      if (str === "!null") {
        return null;
      }
      if (str === "!true") {
        return true;
      }
      if (str === "!false") {
        return false;
      }
      if (str.startsWith("!date(") && str.endsWith(")")) {
        return new Date(str.replaceAll(" ", "+").slice(6, -1));
      }
      if (str.startsWith("!hex(") && str.endsWith(")")) {
        return `#${str.slice(5, -1)}`;
      }
      const color = str.slice(1).match(COLOR_REGEXP);
      if (color) {
        if (str.startsWith("!rgba") || str.startsWith("!RGBA")) {
          return `${color[1]}(${color[2]}, ${color[3]}, ${color[4]}, ${color[5]})`;
        }
        if (str.startsWith("!hsla") || str.startsWith("!HSLA")) {
          return `${color[1]}(${color[2]}, ${color[3]}%, ${color[4]}%, ${color[5]})`;
        }
        return str.startsWith("!rgb") || str.startsWith("!RGB") ? `${color[1]}(${color[2]}, ${color[3]}, ${color[4]})` : `${color[1]}(${color[2]}, ${color[3]}%, ${color[4]}%)`;
      }
    }
    if (NUMBER_REGEXP.test(str)) {
      return Number(str);
    }
    return str;
  }
};
var parseArgsParam = /* @__PURE__ */ __name((argsString) => {
  const parts = argsString.split(";").map((part) => part.replace("=", "~").replace(":", "="));
  return Object.entries((0, import_picoquery.parse)(parts.join(";"), QUERY_OPTIONS)).reduce((acc, [key, value]) => {
    if (validateArgs(key, value)) {
      return Object.assign(acc, { [key]: value });
    }
    once3.warn(dedent`
      Omitted potentially unsafe URL args.

      More info: https://storybook.js.org/docs/writing-stories/args#setting-args-through-the-url?ref=error
    `);
    return acc;
  }, {});
}, "parseArgsParam");

// src/preview-api/modules/preview-web/UrlStore.ts
var { history, document: document2 } = global6;
function pathToId(path) {
  const match = (path || "").match(/^\/story\/(.+)/);
  if (!match) {
    throw new Error(`Invalid path '${path}',  must start with '/story/'`);
  }
  return match[1];
}
__name(pathToId, "pathToId");
var getQueryString = /* @__PURE__ */ __name(({
  selection,
  extraParams
}) => {
  const search = document2?.location.search.slice(1);
  const { path, selectedKind, selectedStory, ...rest } = (0, import_picoquery2.parse)(search);
  const queryStr = (0, import_picoquery2.stringify)({
    ...rest,
    ...extraParams,
    ...selection && { id: selection.storyId, viewMode: selection.viewMode }
  });
  return `?${queryStr}`;
}, "getQueryString");
var setPath = /* @__PURE__ */ __name((selection) => {
  if (!selection) {
    return;
  }
  const query = getQueryString({ selection });
  const { hash = "" } = document2.location;
  document2.title = selection.storyId;
  history.replaceState({}, "", `${document2.location.pathname}${query}${hash}`);
}, "setPath");
var isObject = /* @__PURE__ */ __name((val) => val != null && typeof val === "object" && Array.isArray(val) === false, "isObject");
var getFirstString = /* @__PURE__ */ __name((v) => {
  if (v === void 0) {
    return void 0;
  }
  if (typeof v === "string") {
    return v;
  }
  if (Array.isArray(v)) {
    return getFirstString(v[0]);
  }
  if (isObject(v)) {
    return getFirstString(
      Object.values(v).filter(Boolean)
    );
  }
  return void 0;
}, "getFirstString");
var getSelectionSpecifierFromPath = /* @__PURE__ */ __name(() => {
  if (typeof document2 !== "undefined") {
    const queryStr = document2.location.search.slice(1);
    const query = (0, import_picoquery2.parse)(queryStr);
    const args = typeof query.args === "string" ? parseArgsParam(query.args) : void 0;
    const globals = typeof query.globals === "string" ? parseArgsParam(query.globals) : void 0;
    let viewMode = getFirstString(query.viewMode);
    if (typeof viewMode !== "string" || !viewMode.match(/docs|story/)) {
      viewMode = "story";
    }
    const path = getFirstString(query.path);
    const storyId = path ? pathToId(path) : getFirstString(query.id);
    if (storyId) {
      return { storySpecifier: storyId, args, globals, viewMode };
    }
  }
  return null;
}, "getSelectionSpecifierFromPath");
var _UrlStore = class _UrlStore {
  constructor() {
    this.selectionSpecifier = getSelectionSpecifierFromPath();
  }
  setSelection(selection) {
    this.selection = selection;
    setPath(this.selection);
  }
  setQueryParams(queryParams) {
    const query = getQueryString({ extraParams: queryParams });
    const { hash = "" } = document2.location;
    history.replaceState({}, "", `${document2.location.pathname}${query}${hash}`);
  }
};
__name(_UrlStore, "UrlStore");
var UrlStore = _UrlStore;

// src/preview-api/modules/preview-web/WebView.ts
var import_ansi_to_html = __toESM(require_ansi_to_html(), 1);
var import_picoquery3 = __toESM(require_main(), 1);
import { logger as logger9 } from "storybook/internal/client-logger";
import { global as global7 } from "@storybook/global";
var { document: document3 } = global7;
var PREPARING_DELAY = 100;
var Mode = /* @__PURE__ */ ((Mode2) => {
  Mode2["MAIN"] = "MAIN";
  Mode2["NOPREVIEW"] = "NOPREVIEW";
  Mode2["PREPARING_STORY"] = "PREPARING_STORY";
  Mode2["PREPARING_DOCS"] = "PREPARING_DOCS";
  Mode2["ERROR"] = "ERROR";
  return Mode2;
})(Mode || {});
var classes = {
  PREPARING_STORY: "sb-show-preparing-story",
  PREPARING_DOCS: "sb-show-preparing-docs",
  MAIN: "sb-show-main",
  NOPREVIEW: "sb-show-nopreview",
  ERROR: "sb-show-errordisplay"
};
var layoutClassMap = {
  centered: "sb-main-centered",
  fullscreen: "sb-main-fullscreen",
  padded: "sb-main-padded"
};
var ansiConverter = new import_ansi_to_html.default({
  escapeXML: true
});
var _WebView = class _WebView {
  constructor() {
    this.testing = false;
    if (typeof document3 !== "undefined") {
      const { __SPECIAL_TEST_PARAMETER__ } = (0, import_picoquery3.parse)(document3.location.search.slice(1));
      switch (__SPECIAL_TEST_PARAMETER__) {
        case "preparing-story": {
          this.showPreparingStory();
          this.testing = true;
          break;
        }
        case "preparing-docs": {
          this.showPreparingDocs();
          this.testing = true;
          break;
        }
        default:
      }
    }
  }
  // Get ready to render a story, returning the element to render to
  prepareForStory(story) {
    this.showStory();
    this.applyLayout(story.parameters.layout);
    document3.documentElement.scrollTop = 0;
    document3.documentElement.scrollLeft = 0;
    return this.storyRoot();
  }
  storyRoot() {
    return document3.getElementById("storybook-root");
  }
  prepareForDocs() {
    this.showMain();
    this.showDocs();
    this.applyLayout("fullscreen");
    document3.documentElement.scrollTop = 0;
    document3.documentElement.scrollLeft = 0;
    return this.docsRoot();
  }
  docsRoot() {
    return document3.getElementById("storybook-docs");
  }
  applyLayout(layout = "padded") {
    if (layout === "none") {
      document3.body.classList.remove(this.currentLayoutClass);
      this.currentLayoutClass = null;
      return;
    }
    this.checkIfLayoutExists(layout);
    const layoutClass = layoutClassMap[layout];
    document3.body.classList.remove(this.currentLayoutClass);
    document3.body.classList.add(layoutClass);
    this.currentLayoutClass = layoutClass;
  }
  checkIfLayoutExists(layout) {
    if (!layoutClassMap[layout]) {
      logger9.warn(
        dedent`
          The desired layout: ${layout} is not a valid option.
          The possible options are: ${Object.keys(layoutClassMap).join(", ")}, none.
        `
      );
    }
  }
  showMode(mode) {
    clearTimeout(this.preparingTimeout);
    Object.keys(Mode).forEach((otherMode) => {
      if (otherMode === mode) {
        document3.body.classList.add(classes[otherMode]);
      } else {
        document3.body.classList.remove(classes[otherMode]);
      }
    });
  }
  showErrorDisplay({ message = "", stack = "" }) {
    let header = message;
    let detail = stack;
    const parts = message.split("\n");
    if (parts.length > 1) {
      [header] = parts;
      detail = parts.slice(1).join("\n").replace(/^\n/, "");
    }
    document3.getElementById("error-message").innerHTML = ansiConverter.toHtml(header);
    document3.getElementById("error-stack").innerHTML = ansiConverter.toHtml(detail);
    this.showMode("ERROR" /* ERROR */);
  }
  showNoPreview() {
    if (this.testing) {
      return;
    }
    this.showMode("NOPREVIEW" /* NOPREVIEW */);
    this.storyRoot()?.setAttribute("hidden", "true");
    this.docsRoot()?.setAttribute("hidden", "true");
  }
  showPreparingStory({ immediate = false } = {}) {
    clearTimeout(this.preparingTimeout);
    if (immediate) {
      this.showMode("PREPARING_STORY" /* PREPARING_STORY */);
    } else {
      this.preparingTimeout = setTimeout(
        () => this.showMode("PREPARING_STORY" /* PREPARING_STORY */),
        PREPARING_DELAY
      );
    }
  }
  showPreparingDocs({ immediate = false } = {}) {
    clearTimeout(this.preparingTimeout);
    if (immediate) {
      this.showMode("PREPARING_DOCS" /* PREPARING_DOCS */);
    } else {
      this.preparingTimeout = setTimeout(() => this.showMode("PREPARING_DOCS" /* PREPARING_DOCS */), PREPARING_DELAY);
    }
  }
  showMain() {
    this.showMode("MAIN" /* MAIN */);
  }
  showDocs() {
    this.storyRoot().setAttribute("hidden", "true");
    this.docsRoot().removeAttribute("hidden");
  }
  showStory() {
    this.docsRoot().setAttribute("hidden", "true");
    this.storyRoot().removeAttribute("hidden");
  }
  showStoryDuringRender() {
    document3.body.classList.add(classes.MAIN);
  }
};
__name(_WebView, "WebView");
var WebView = _WebView;

// src/preview-api/modules/preview-web/PreviewWeb.tsx
var _PreviewWeb = class _PreviewWeb extends PreviewWithSelection {
  constructor(importFn, getProjectAnnotations) {
    super(importFn, getProjectAnnotations, new UrlStore(), new WebView());
    this.importFn = importFn;
    this.getProjectAnnotations = getProjectAnnotations;
    global8.__STORYBOOK_PREVIEW__ = this;
  }
};
__name(_PreviewWeb, "PreviewWeb");
var PreviewWeb = _PreviewWeb;

// src/preview-api/modules/preview-web/simulate-pageload.ts
import { global as global9 } from "@storybook/global";
var { document: document4 } = global9;
var runScriptTypes = [
  "application/javascript",
  "application/ecmascript",
  "application/x-ecmascript",
  "application/x-javascript",
  "text/ecmascript",
  "text/javascript",
  "text/javascript1.0",
  "text/javascript1.1",
  "text/javascript1.2",
  "text/javascript1.3",
  "text/javascript1.4",
  "text/javascript1.5",
  "text/jscript",
  "text/livescript",
  "text/x-ecmascript",
  "text/x-javascript",
  // Support modern javascript
  "module"
];
var SCRIPT = "script";
var SCRIPTS_ROOT_ID = "scripts-root";
function simulateDOMContentLoaded() {
  const DOMContentLoadedEvent = document4.createEvent("Event");
  DOMContentLoadedEvent.initEvent("DOMContentLoaded", true, true);
  document4.dispatchEvent(DOMContentLoadedEvent);
}
__name(simulateDOMContentLoaded, "simulateDOMContentLoaded");
function insertScript($script, callback, $scriptRoot) {
  const scriptEl = document4.createElement("script");
  scriptEl.type = $script.type === "module" ? "module" : "text/javascript";
  if ($script.src) {
    scriptEl.onload = callback;
    scriptEl.onerror = callback;
    scriptEl.src = $script.src;
  } else {
    scriptEl.textContent = $script.innerText;
  }
  if ($scriptRoot) {
    $scriptRoot.appendChild(scriptEl);
  } else {
    document4.head.appendChild(scriptEl);
  }
  $script.parentNode.removeChild($script);
  if (!$script.src) {
    callback();
  }
}
__name(insertScript, "insertScript");
function insertScriptsSequentially(scriptsToExecute, callback, index = 0) {
  scriptsToExecute[index](() => {
    index++;
    if (index === scriptsToExecute.length) {
      callback();
    } else {
      insertScriptsSequentially(scriptsToExecute, callback, index);
    }
  });
}
__name(insertScriptsSequentially, "insertScriptsSequentially");
function simulatePageLoad($container) {
  let $scriptsRoot = document4.getElementById(SCRIPTS_ROOT_ID);
  if (!$scriptsRoot) {
    $scriptsRoot = document4.createElement("div");
    $scriptsRoot.id = SCRIPTS_ROOT_ID;
    document4.body.appendChild($scriptsRoot);
  } else {
    $scriptsRoot.innerHTML = "";
  }
  const $scripts = Array.from($container.querySelectorAll(SCRIPT));
  if ($scripts.length) {
    const scriptsToExecute = [];
    $scripts.forEach(($script) => {
      const typeAttr = $script.getAttribute("type");
      if (!typeAttr || runScriptTypes.includes(typeAttr)) {
        scriptsToExecute.push((callback) => insertScript($script, callback, $scriptsRoot));
      }
    });
    if (scriptsToExecute.length) {
      insertScriptsSequentially(scriptsToExecute, simulateDOMContentLoaded, void 0);
    }
  } else {
    simulateDOMContentLoaded();
  }
}
__name(simulatePageLoad, "simulatePageLoad");

// src/preview-api/modules/preview-web/emitTransformCode.ts
async function emitTransformCode(source, context) {
  const transform = context.parameters?.docs?.source?.transform;
  const { id, unmappedArgs } = context;
  const transformed = transform && source ? transform?.(source, context) : source;
  const result = transformed ? await transformed : void 0;
  addons.getChannel().emit(SNIPPET_RENDERED, {
    id,
    source: result,
    args: unmappedArgs
  });
}
__name(emitTransformCode, "emitTransformCode");

export {
  mockChannel,
  addons,
  HooksContext,
  applyHooks,
  useMemo,
  useCallback,
  useRef,
  useState,
  useReducer,
  useEffect,
  useChannel,
  useStoryContext,
  useParameter,
  useArgs,
  useGlobals,
  makeDecorator,
  combineArgs,
  normalizeArrays,
  normalizeStory,
  mountDestructured,
  decorateStory,
  sanitizeStoryContextUpdate,
  defaultDecorateStory,
  prepareStory,
  prepareMeta,
  filterArgTypes,
  inferControls,
  normalizeProjectAnnotations,
  composeStepRunners,
  composeConfigs,
  ReporterAPI,
  getCsfFactoryAnnotations,
  setDefaultProjectAnnotations,
  setProjectAnnotations,
  composeStory,
  composeStories,
  createPlaywrightTest,
  StoryStore,
  userOrAutoTitleFromSpecifier,
  userOrAutoTitle,
  sortStoriesV7,
  Preview,
  DocsContext,
  PreviewWithSelection,
  UrlStore,
  WebView,
  PreviewWeb,
  simulateDOMContentLoaded,
  simulatePageLoad,
  emitTransformCode
};