UNPKG

@storybook/react-native

Version:

A better way to develop React Native Components for your app

1,259 lines (1,246 loc) 43.3 kB
var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { darkTheme: () => import_react_native_theming3.darkTheme, getProjectAnnotations: () => getProjectAnnotations, prepareStories: () => prepareStories, start: () => start, theme: () => import_react_native_theming3.theme, updateView: () => updateView }); module.exports = __toCommonJS(src_exports); var import_react_native_theming3 = require("@storybook/react-native-theming"); // src/Start.tsx var import_react_native4 = require("react-native"); var import_manager_api2 = require("@storybook/core/manager-api"); var import_preview_api2 = require("@storybook/core/preview-api"); var import_csf2 = require("@storybook/csf"); var import_channels2 = require("@storybook/core/channels"); // src/View.tsx var import_bottom_sheet = require("@gorhom/bottom-sheet"); var import_channels = require("@storybook/core/channels"); var import_core_events = __toESM(require("@storybook/core/core-events")); var import_csf = require("@storybook/csf"); var import_manager_api = require("@storybook/core/manager-api"); var import_preview_api = require("@storybook/core/preview-api"); var import_react_native_theming2 = require("@storybook/react-native-theming"); var import_react_native_ui = require("@storybook/react-native-ui"); var import_dedent = __toESM(require("dedent")); var import_deepmerge = __toESM(require("deepmerge")); var import_react4 = require("react"); var import_react_native3 = require("react-native"); var import_react_native_gesture_handler = require("react-native-gesture-handler"); var import_react_native_safe_area_context = require("react-native-safe-area-context"); // src/components/StoryView/StoryView.tsx var import_react3 = __toESM(require("react")); var import_react_native_theming = require("@storybook/react-native-theming"); var import_react_native2 = require("react-native"); // ../../node_modules/jotai/esm/vanilla.mjs var import_meta = {}; var keyCount = 0; function atom(read, write) { const key = `atom${++keyCount}`; const config = { toString: () => key }; if (typeof read === "function") { config.read = read; } else { config.init = read; config.read = function(get) { return get(this); }; config.write = function(get, set, arg) { return set( this, typeof arg === "function" ? arg(get(this)) : arg ); }; } if (write) { config.write = write; } return config; } var hasInitialValue = (atom2) => "init" in atom2; var isActuallyWritableAtom = (atom2) => !!atom2.write; var cancelPromiseMap = /* @__PURE__ */ new WeakMap(); var registerCancelPromise = (promise, cancel) => { cancelPromiseMap.set(promise, cancel); promise.catch(() => { }).finally(() => cancelPromiseMap.delete(promise)); }; var cancelPromise = (promise, next) => { const cancel = cancelPromiseMap.get(promise); if (cancel) { cancelPromiseMap.delete(promise); cancel(next); } }; var resolvePromise = (promise, value) => { promise.status = "fulfilled"; promise.value = value; }; var rejectPromise = (promise, e) => { promise.status = "rejected"; promise.reason = e; }; var isPromiseLike = (x) => typeof (x == null ? void 0 : x.then) === "function"; var isEqualAtomValue = (a, b) => !!a && "v" in a && "v" in b && Object.is(a.v, b.v); var isEqualAtomError = (a, b) => !!a && "e" in a && "e" in b && Object.is(a.e, b.e); var hasPromiseAtomValue = (a) => !!a && "v" in a && a.v instanceof Promise; var isEqualPromiseAtomValue = (a, b) => "v" in a && "v" in b && a.v.orig && a.v.orig === b.v.orig; var returnAtomValue = (atomState) => { if ("e" in atomState) { throw atomState.e; } return atomState.v; }; var createStore = () => { const atomStateMap = /* @__PURE__ */ new WeakMap(); const mountedMap = /* @__PURE__ */ new WeakMap(); const pendingMap = /* @__PURE__ */ new Map(); let storeListenersRev2; let mountedAtoms; if ((import_meta.env ? import_meta.env.MODE : void 0) !== "production") { storeListenersRev2 = /* @__PURE__ */ new Set(); mountedAtoms = /* @__PURE__ */ new Set(); } const getAtomState = (atom2) => atomStateMap.get(atom2); const setAtomState = (atom2, atomState) => { if ((import_meta.env ? import_meta.env.MODE : void 0) !== "production") { Object.freeze(atomState); } const prevAtomState = atomStateMap.get(atom2); atomStateMap.set(atom2, atomState); if (!pendingMap.has(atom2)) { pendingMap.set(atom2, prevAtomState); } if (hasPromiseAtomValue(prevAtomState)) { const next = "v" in atomState ? atomState.v instanceof Promise ? atomState.v : Promise.resolve(atomState.v) : Promise.reject(atomState.e); if (prevAtomState.v !== next) { cancelPromise(prevAtomState.v, next); } } }; const updateDependencies = (atom2, nextAtomState, nextDependencies) => { const dependencies = /* @__PURE__ */ new Map(); let changed = false; nextDependencies.forEach((aState, a) => { if (!aState && a === atom2) { aState = nextAtomState; } if (aState) { dependencies.set(a, aState); if (nextAtomState.d.get(a) !== aState) { changed = true; } } else if ((import_meta.env ? import_meta.env.MODE : void 0) !== "production") { console.warn("[Bug] atom state not found"); } }); if (changed || nextAtomState.d.size !== dependencies.size) { nextAtomState.d = dependencies; } }; const setAtomValue = (atom2, value, nextDependencies) => { const prevAtomState = getAtomState(atom2); const nextAtomState = { d: (prevAtomState == null ? void 0 : prevAtomState.d) || /* @__PURE__ */ new Map(), v: value }; if (nextDependencies) { updateDependencies(atom2, nextAtomState, nextDependencies); } if (isEqualAtomValue(prevAtomState, nextAtomState) && prevAtomState.d === nextAtomState.d) { return prevAtomState; } if (hasPromiseAtomValue(prevAtomState) && hasPromiseAtomValue(nextAtomState) && isEqualPromiseAtomValue(prevAtomState, nextAtomState)) { if (prevAtomState.d === nextAtomState.d) { return prevAtomState; } else { nextAtomState.v = prevAtomState.v; } } setAtomState(atom2, nextAtomState); return nextAtomState; }; const setAtomValueOrPromise = (atom2, valueOrPromise, nextDependencies, abortPromise) => { if (isPromiseLike(valueOrPromise)) { let continuePromise; const updatePromiseDependencies = () => { const prevAtomState = getAtomState(atom2); if (!hasPromiseAtomValue(prevAtomState) || prevAtomState.v !== promise) { return; } const nextAtomState = setAtomValue( atom2, promise, nextDependencies ); if (mountedMap.has(atom2) && prevAtomState.d !== nextAtomState.d) { mountDependencies(atom2, nextAtomState, prevAtomState.d); } }; const promise = new Promise((resolve, reject) => { let settled = false; valueOrPromise.then( (v) => { if (!settled) { settled = true; resolvePromise(promise, v); resolve(v); updatePromiseDependencies(); } }, (e) => { if (!settled) { settled = true; rejectPromise(promise, e); reject(e); updatePromiseDependencies(); } } ); continuePromise = (next) => { if (!settled) { settled = true; next.then( (v) => resolvePromise(promise, v), (e) => rejectPromise(promise, e) ); resolve(next); } }; }); promise.orig = valueOrPromise; promise.status = "pending"; registerCancelPromise(promise, (next) => { if (next) { continuePromise(next); } abortPromise == null ? void 0 : abortPromise(); }); return setAtomValue(atom2, promise, nextDependencies); } return setAtomValue(atom2, valueOrPromise, nextDependencies); }; const setAtomError = (atom2, error, nextDependencies) => { const prevAtomState = getAtomState(atom2); const nextAtomState = { d: (prevAtomState == null ? void 0 : prevAtomState.d) || /* @__PURE__ */ new Map(), e: error }; if (nextDependencies) { updateDependencies(atom2, nextAtomState, nextDependencies); } if (isEqualAtomError(prevAtomState, nextAtomState) && prevAtomState.d === nextAtomState.d) { return prevAtomState; } setAtomState(atom2, nextAtomState); return nextAtomState; }; const readAtomState = (atom2, force) => { const atomState = getAtomState(atom2); if (!force && atomState) { if (mountedMap.has(atom2)) { return atomState; } if (Array.from(atomState.d).every(([a, s]) => { if (a === atom2) { return true; } const aState = readAtomState(a); return aState === s || isEqualAtomValue(aState, s); })) { return atomState; } } const nextDependencies = /* @__PURE__ */ new Map(); let isSync = true; const getter = (a) => { if (a === atom2) { const aState2 = getAtomState(a); if (aState2) { nextDependencies.set(a, aState2); return returnAtomValue(aState2); } if (hasInitialValue(a)) { nextDependencies.set(a, void 0); return a.init; } throw new Error("no atom init"); } const aState = readAtomState(a); nextDependencies.set(a, aState); return returnAtomValue(aState); }; let controller; let setSelf; const options = { get signal() { if (!controller) { controller = new AbortController(); } return controller.signal; }, get setSelf() { if ((import_meta.env ? import_meta.env.MODE : void 0) !== "production" && !isActuallyWritableAtom(atom2)) { console.warn("setSelf function cannot be used with read-only atom"); } if (!setSelf && isActuallyWritableAtom(atom2)) { setSelf = (...args) => { if ((import_meta.env ? import_meta.env.MODE : void 0) !== "production" && isSync) { console.warn("setSelf function cannot be called in sync"); } if (!isSync) { return writeAtom(atom2, ...args); } }; } return setSelf; } }; try { const valueOrPromise = atom2.read(getter, options); return setAtomValueOrPromise( atom2, valueOrPromise, nextDependencies, () => controller == null ? void 0 : controller.abort() ); } catch (error) { return setAtomError(atom2, error, nextDependencies); } finally { isSync = false; } }; const readAtom = (atom2) => returnAtomValue(readAtomState(atom2)); const addAtom = (atom2) => { let mounted = mountedMap.get(atom2); if (!mounted) { mounted = mountAtom(atom2); } return mounted; }; const canUnmountAtom = (atom2, mounted) => !mounted.l.size && (!mounted.t.size || mounted.t.size === 1 && mounted.t.has(atom2)); const delAtom = (atom2) => { const mounted = mountedMap.get(atom2); if (mounted && canUnmountAtom(atom2, mounted)) { unmountAtom(atom2); } }; const recomputeDependents = (atom2) => { const dependencyMap = /* @__PURE__ */ new Map(); const dirtyMap = /* @__PURE__ */ new WeakMap(); const getDependents = (a) => { var _a; const dependents = new Set((_a = mountedMap.get(a)) == null ? void 0 : _a.t); pendingMap.forEach((_, pendingAtom) => { var _a2; if ((_a2 = getAtomState(pendingAtom)) == null ? void 0 : _a2.d.has(a)) { dependents.add(pendingAtom); } }); return dependents; }; const loop1 = (a) => { getDependents(a).forEach((dependent) => { if (dependent !== a) { dependencyMap.set( dependent, (dependencyMap.get(dependent) || /* @__PURE__ */ new Set()).add(a) ); dirtyMap.set(dependent, (dirtyMap.get(dependent) || 0) + 1); loop1(dependent); } }); }; loop1(atom2); const loop2 = (a) => { getDependents(a).forEach((dependent) => { var _a; if (dependent !== a) { let dirtyCount = dirtyMap.get(dependent); if (dirtyCount) { dirtyMap.set(dependent, --dirtyCount); } if (!dirtyCount) { let isChanged = !!((_a = dependencyMap.get(dependent)) == null ? void 0 : _a.size); if (isChanged) { const prevAtomState = getAtomState(dependent); const nextAtomState = readAtomState(dependent, true); isChanged = !isEqualAtomValue(prevAtomState, nextAtomState); } if (!isChanged) { dependencyMap.forEach((s) => s.delete(dependent)); } } loop2(dependent); } }); }; loop2(atom2); }; const writeAtomState = (atom2, ...args) => { let isSync = true; const getter = (a) => returnAtomValue(readAtomState(a)); const setter = (a, ...args2) => { let r; if (a === atom2) { if (!hasInitialValue(a)) { throw new Error("atom not writable"); } const prevAtomState = getAtomState(a); const nextAtomState = setAtomValueOrPromise(a, args2[0]); if (!isEqualAtomValue(prevAtomState, nextAtomState)) { recomputeDependents(a); } } else { r = writeAtomState(a, ...args2); } if (!isSync) { const flushed = flushPending(); if ((import_meta.env ? import_meta.env.MODE : void 0) !== "production") { storeListenersRev2.forEach( (l) => l({ type: "async-write", flushed }) ); } } return r; }; const result = atom2.write(getter, setter, ...args); isSync = false; return result; }; const writeAtom = (atom2, ...args) => { const result = writeAtomState(atom2, ...args); const flushed = flushPending(); if ((import_meta.env ? import_meta.env.MODE : void 0) !== "production") { storeListenersRev2.forEach( (l) => l({ type: "write", flushed }) ); } return result; }; const mountAtom = (atom2, initialDependent, onMountQueue) => { var _a; const queue = onMountQueue || []; (_a = getAtomState(atom2)) == null ? void 0 : _a.d.forEach((_, a) => { const aMounted = mountedMap.get(a); if (aMounted) { aMounted.t.add(atom2); } else { if (a !== atom2) { mountAtom(a, atom2, queue); } } }); readAtomState(atom2); const mounted = { t: new Set(initialDependent && [initialDependent]), l: /* @__PURE__ */ new Set() }; mountedMap.set(atom2, mounted); if ((import_meta.env ? import_meta.env.MODE : void 0) !== "production") { mountedAtoms.add(atom2); } if (isActuallyWritableAtom(atom2) && atom2.onMount) { const { onMount } = atom2; queue.push(() => { const onUnmount = onMount((...args) => writeAtom(atom2, ...args)); if (onUnmount) { mounted.u = onUnmount; } }); } if (!onMountQueue) { queue.forEach((f) => f()); } return mounted; }; const unmountAtom = (atom2) => { var _a; const onUnmount = (_a = mountedMap.get(atom2)) == null ? void 0 : _a.u; if (onUnmount) { onUnmount(); } mountedMap.delete(atom2); if ((import_meta.env ? import_meta.env.MODE : void 0) !== "production") { mountedAtoms.delete(atom2); } const atomState = getAtomState(atom2); if (atomState) { if (hasPromiseAtomValue(atomState)) { cancelPromise(atomState.v); } atomState.d.forEach((_, a) => { if (a !== atom2) { const mounted = mountedMap.get(a); if (mounted) { mounted.t.delete(atom2); if (canUnmountAtom(a, mounted)) { unmountAtom(a); } } } }); } else if ((import_meta.env ? import_meta.env.MODE : void 0) !== "production") { console.warn("[Bug] could not find atom state to unmount", atom2); } }; const mountDependencies = (atom2, atomState, prevDependencies) => { const depSet = new Set(atomState.d.keys()); const maybeUnmountAtomSet = /* @__PURE__ */ new Set(); prevDependencies == null ? void 0 : prevDependencies.forEach((_, a) => { if (depSet.has(a)) { depSet.delete(a); return; } maybeUnmountAtomSet.add(a); const mounted = mountedMap.get(a); if (mounted) { mounted.t.delete(atom2); } }); depSet.forEach((a) => { const mounted = mountedMap.get(a); if (mounted) { mounted.t.add(atom2); } else if (mountedMap.has(atom2)) { mountAtom(a, atom2); } }); maybeUnmountAtomSet.forEach((a) => { const mounted = mountedMap.get(a); if (mounted && canUnmountAtom(a, mounted)) { unmountAtom(a); } }); }; const flushPending = () => { let flushed; if ((import_meta.env ? import_meta.env.MODE : void 0) !== "production") { flushed = /* @__PURE__ */ new Set(); } while (pendingMap.size) { const pending = Array.from(pendingMap); pendingMap.clear(); pending.forEach(([atom2, prevAtomState]) => { const atomState = getAtomState(atom2); if (atomState) { const mounted = mountedMap.get(atom2); if (mounted && atomState.d !== (prevAtomState == null ? void 0 : prevAtomState.d)) { mountDependencies(atom2, atomState, prevAtomState == null ? void 0 : prevAtomState.d); } if (mounted && !// TODO This seems pretty hacky. Hope to fix it. // Maybe we could `mountDependencies` in `setAtomState`? (!hasPromiseAtomValue(prevAtomState) && (isEqualAtomValue(prevAtomState, atomState) || isEqualAtomError(prevAtomState, atomState)))) { mounted.l.forEach((listener) => listener()); if ((import_meta.env ? import_meta.env.MODE : void 0) !== "production") { flushed.add(atom2); } } } else if ((import_meta.env ? import_meta.env.MODE : void 0) !== "production") { console.warn("[Bug] no atom state to flush"); } }); } if ((import_meta.env ? import_meta.env.MODE : void 0) !== "production") { return flushed; } }; const subscribeAtom = (atom2, listener) => { const mounted = addAtom(atom2); const flushed = flushPending(); const listeners = mounted.l; listeners.add(listener); if ((import_meta.env ? import_meta.env.MODE : void 0) !== "production") { storeListenersRev2.forEach( (l) => l({ type: "sub", flushed }) ); } return () => { listeners.delete(listener); delAtom(atom2); if ((import_meta.env ? import_meta.env.MODE : void 0) !== "production") { storeListenersRev2.forEach((l) => l({ type: "unsub" })); } }; }; if ((import_meta.env ? import_meta.env.MODE : void 0) !== "production") { return { get: readAtom, set: writeAtom, sub: subscribeAtom, // store dev methods (these are tentative and subject to change without notice) dev_subscribe_store: (l, rev) => { if (rev !== 2) { throw new Error("The current StoreListener revision is 2."); } storeListenersRev2.add(l); return () => { storeListenersRev2.delete(l); }; }, dev_get_mounted_atoms: () => mountedAtoms.values(), dev_get_atom_state: (a) => atomStateMap.get(a), dev_get_mounted: (a) => mountedMap.get(a), dev_restore_atoms: (values) => { for (const [atom2, valueOrPromise] of values) { if (hasInitialValue(atom2)) { setAtomValueOrPromise(atom2, valueOrPromise); recomputeDependents(atom2); } } const flushed = flushPending(); storeListenersRev2.forEach( (l) => l({ type: "restore", flushed }) ); } }; } return { get: readAtom, set: writeAtom, sub: subscribeAtom }; }; var defaultStore; if ((import_meta.env ? import_meta.env.MODE : void 0) !== "production") { if (typeof globalThis.__NUMBER_OF_JOTAI_INSTANCES__ === "number") { ++globalThis.__NUMBER_OF_JOTAI_INSTANCES__; } else { globalThis.__NUMBER_OF_JOTAI_INSTANCES__ = 1; } } var getDefaultStore = () => { if (!defaultStore) { defaultStore = createStore(); } return defaultStore; }; // ../../node_modules/jotai/esm/react.mjs var import_react = __toESM(require("react"), 1); var import_meta2 = {}; var StoreContext = (0, import_react.createContext)(void 0); var useStore = (options) => { const store = (0, import_react.useContext)(StoreContext); return (options == null ? void 0 : options.store) || store || getDefaultStore(); }; var isPromiseLike2 = (x) => typeof (x == null ? void 0 : x.then) === "function"; var use = import_react.default.use || ((promise) => { if (promise.status === "pending") { throw promise; } else if (promise.status === "fulfilled") { return promise.value; } else if (promise.status === "rejected") { throw promise.reason; } else { promise.status = "pending"; promise.then( (v) => { promise.status = "fulfilled"; promise.value = v; }, (e) => { promise.status = "rejected"; promise.reason = e; } ); throw promise; } }); function useAtomValue(atom2, options) { const store = useStore(options); const [[valueFromReducer, storeFromReducer, atomFromReducer], rerender] = (0, import_react.useReducer)( (prev) => { const nextValue = store.get(atom2); if (Object.is(prev[0], nextValue) && prev[1] === store && prev[2] === atom2) { return prev; } return [nextValue, store, atom2]; }, void 0, () => [store.get(atom2), store, atom2] ); let value = valueFromReducer; if (storeFromReducer !== store || atomFromReducer !== atom2) { rerender(); value = store.get(atom2); } const delay = options == null ? void 0 : options.delay; (0, import_react.useEffect)(() => { const unsub = store.sub(atom2, () => { if (typeof delay === "number") { setTimeout(rerender, delay); return; } rerender(); }); rerender(); return unsub; }, [store, atom2, delay]); (0, import_react.useDebugValue)(value); return isPromiseLike2(value) ? use(value) : value; } function useSetAtom(atom2, options) { const store = useStore(options); const setAtom = (0, import_react.useCallback)( (...args) => { if ((import_meta2.env ? import_meta2.env.MODE : void 0) !== "production" && !("write" in atom2)) { throw new Error("not writable atom"); } return store.set(atom2, ...args); }, [store, atom2] ); return setAtom; } // src/hooks.tsx var storyContextAtom = atom(null); function useSetStoryContext() { return useSetAtom(storyContextAtom); } function useStoryContext() { return useAtomValue(storyContextAtom); } // src/components/StoryView/ErrorBoundary.tsx var import_react2 = __toESM(require("react")); var import_react_native = require("react-native"); var import_jsx_runtime = require("react/jsx-runtime"); var ErrorBoundary = class extends import_react2.default.Component { constructor(props) { super(props); this.state = { hasError: false }; } static getDerivedStateFromError(_error) { return { hasError: true }; } componentDidCatch(error, info) { this.props.onError(error, info.componentStack); } render() { if (this.state.hasError) { return /* @__PURE__ */ (0, import_jsx_runtime.jsx)( import_react_native.View, { style: { margin: 16, padding: 16, borderColor: "red", borderWidth: 2, alignItems: "center", justifyContent: "center", borderRadius: 4 }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.Text, { style: { fontWeight: "bold" }, children: "Something went wrong rendering your story" }) } ); } return this.props.children; } }; // src/components/StoryView/StoryView.tsx var import_jsx_runtime2 = require("react/jsx-runtime"); function dismissOnStartResponder() { import_react_native2.Keyboard.dismiss(); return false; } var Text2 = import_react_native_theming.styled.Text(({ theme: theme3 }) => ({ color: theme3?.color?.defaultText })); var StoryView = () => { const context = useStoryContext(); const id = context?.id; const theme3 = (0, import_react_native_theming.useTheme)(); if (context && context.unboundStoryFn) { const { unboundStoryFn: StoryComponent } = context; return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)( import_react_native2.View, { style: { flex: 1, backgroundColor: theme3.background?.content }, testID: id, onStartShouldSetResponder: dismissOnStartResponder, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)( ErrorBoundary, { onError: () => { console.log(`Error rendering story for ${context.title} ${context.name}`); }, children: StoryComponent && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(StoryComponent, { ...context }) } ) }, id ); } return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.View, { style: { flex: 1, padding: 16, alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text2, { children: "Please open the sidebar and select a story to preview." }) }); }; var StoryView_default = import_react3.default.memo(StoryView); // src/rn-host-detect.js function getByRemoteConfig(hostname) { var remoteModuleConfig = window?.__fbBatchedBridgeConfig?.remoteModuleConfig; if (!Array.isArray(remoteModuleConfig) || hostname !== "localhost" && hostname !== "127.0.0.1") { return { hostname, passed: false }; } var constants = (remoteModuleConfig.find(getConstants) || [])[1]; if (constants) { var serverHost = constants.ServerHost || hostname; return { hostname: serverHost.split(":")[0], passed: true }; } return { hostname, passed: false }; } function getConstants(config) { return config && (config[0] === "AndroidConstants" || config[0] === "PlatformConstants"); } function getByRNRequirePolyfill(hostname) { var NativeModules; var PlatformConstants; var AndroidConstants; if (typeof window === "undefined" || !window.__DEV__ || typeof window.require !== "function" || // RN >= 0.56 // TODO: Get NativeModules for RN >= 0.56 window.require.name === "metroRequire") { return hostname; } NativeModules = window.require("NativeModules"); if (!NativeModules || !NativeModules.PlatformConstants && !NativeModules.AndroidConstants) { return hostname; } PlatformConstants = NativeModules.PlatformConstants; AndroidConstants = NativeModules.AndroidConstants; var serverHost = (PlatformConstants ? PlatformConstants.ServerHost : AndroidConstants.ServerHost) || hostname; return serverHost.split(":")[0]; } function getHost(hostname) { if (typeof __fbBatchedBridge !== "object" || hostname !== "localhost" && hostname !== "127.0.0.1") { return hostname; } var result = getByRemoteConfig(hostname); if (result.passed) { return result.hostname; } return getByRNRequirePolyfill(hostname); } // src/View.tsx var import_jsx_runtime3 = require("react/jsx-runtime"); var STORAGE_KEY = "lastOpenedStory"; var View3 = class { _storyIndex; _setStory = () => { }; _forceRerender = () => { }; _ready = false; _preview; _asyncStorageStoryId; _webUrl; _storage; _channel; _idToPrepared = {}; constructor(preview, channel) { this._preview = preview; this._channel = channel; } _getInitialStory = async ({ initialSelection, shouldPersistSelection = true } = {}) => { if (initialSelection) { if (typeof initialSelection === "string") { return { storySpecifier: initialSelection, viewMode: "story" }; } else { return { storySpecifier: (0, import_csf.toId)(initialSelection.kind, initialSelection.name), viewMode: "story" }; } } if (shouldPersistSelection) { try { let value = this._asyncStorageStoryId; if (!value && this._storage != null) { value = await this._storage.getItem(STORAGE_KEY); this._asyncStorageStoryId = value; } const exists = value && Object.keys(this._storyIndex.entries).includes(value); if (!exists) console.log("Storybook: could not find persisted story"); return { storySpecifier: exists ? value : "*", viewMode: "story" }; } catch (e) { console.warn("storybook-log: error reading from async storage", e); } } return { storySpecifier: "*", viewMode: "story" }; }; _getServerChannel = (params = {}) => { const host = getHost(params.host || "localhost"); const port = `:${params.port || 7007}`; const query = params.query || ""; const websocketType = params.secured ? "wss" : "ws"; const url = `${websocketType}://${host}${port}/${query}`; const channel = new import_channels.Channel({ transport: new import_channels.WebsocketTransport({ url, onError: (e) => { console.log(`WebsocketTransport error ${JSON.stringify(e)}`); } }), async: true }); return channel; }; createPreparedStoryMapping = async () => { await this._preview.ready().then( () => Promise.all( Object.keys(this._storyIndex.entries).map(async (storyId) => { this._idToPrepared[storyId] = await this._preview.loadStory({ storyId }); }) ) ); }; getStorybookUI = (params = {}) => { const { shouldPersistSelection = true, onDeviceUI = true, enableWebsockets = false, storage } = params; this._storage = storage; const initialStory = this._getInitialStory(params); if (enableWebsockets) { const channel = this._getServerChannel(params); import_manager_api.addons.setChannel(channel); import_preview_api.addons.setChannel(channel); this._channel = channel; this._preview.channel = channel; this._preview.setupListeners(); channel.emit(import_core_events.default.CHANNEL_CREATED); this._preview.ready().then(() => this._preview.onStoryIndexChanged()); } import_manager_api.addons.loadAddons({ store: () => ({ fromId: (id) => { if (!this._ready) { throw new Error("Storybook is not ready yet"); } return this._preview.getStoryContext(this._idToPrepared[id]); }, getSelection: () => { return this._preview.currentSelection; }, _channel: this._channel }) }); const self = this; return () => { const setContext = useSetStoryContext(); const story = useStoryContext(); const colorScheme = (0, import_react_native3.useColorScheme)(); const [update, forceUpdate] = (0, import_react4.useReducer)((x) => x + 1, 0); const [ready, setReady] = (0, import_react4.useState)(false); const appliedTheme = (0, import_react4.useMemo)( () => (0, import_deepmerge.default)(colorScheme === "dark" ? import_react_native_theming2.darkTheme : import_react_native_theming2.theme, params.theme ?? {}), [colorScheme] ); (0, import_react4.useEffect)(() => { this.createPreparedStoryMapping().then(() => { this._ready = true; setReady(true); initialStory.then((st) => { self._preview.selectionStore.selectionSpecifier = st; self._preview.selectSpecifiedStory(); }); }).catch((e) => console.error(e)); self._setStory = (newStory) => { setContext(newStory); if (shouldPersistSelection && !storage) { console.warn(import_dedent.default`Please set storage in getStorybookUI like this: const StorybookUIRoot = view.getStorybookUI({ storage: { getItem: AsyncStorage.getItem, setItem: AsyncStorage.setItem, }, }); `); } if (shouldPersistSelection && !!this._storage) { this._storage.setItem(STORAGE_KEY, newStory.id).catch((e) => { console.warn("storybook-log: error writing to async storage", e); }); } }; self._forceRerender = () => forceUpdate(); }, []); const storyHash = (0, import_react4.useMemo)(() => { if (!ready) { return {}; } return (0, import_react_native_ui.transformStoryIndexToStoriesHash)(this._storyIndex, { docsOptions: { docsMode: false, autodocs: false, defaultName: "" }, filters: {}, status: {}, provider: { handleAPI: () => ({}), getConfig: () => ({}) } }); }, [ready, update]); if (!ready) { return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)( import_react_native3.View, { style: { ...import_react_native3.StyleSheet.absoluteFillObject, alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.ActivityIndicator, { animating: true, size: "large" }) } ); } if (onDeviceUI) { return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native_theming2.ThemeProvider, { theme: appliedTheme, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native_safe_area_context.SafeAreaProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native_gesture_handler.GestureHandlerRootView, { style: { flex: 1 }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_bottom_sheet.BottomSheetModalProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native_ui.LayoutProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native_ui.Layout, { storyHash, story, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(StoryView_default, {}) }) }) }) }) }) }); } else { return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(StoryView_default, {}); } }; }; }; // src/Start.tsx var import_jsx_runtime4 = require("react/jsx-runtime"); if (import_react_native4.Platform.OS !== "web") { try { let params = new URLSearchParams({ test: "1" }); params.get("test"); } catch { const { setupURLPolyfill } = require("react-native-url-polyfill"); setupURLPolyfill(); } } if (import_react_native4.Platform.OS === "web" && typeof globalThis.setImmediate === "undefined") { require("setimmediate"); } function prepareStories({ storyEntries, options }) { let index = { v: 4, entries: {} }; let importMap = {}; const makeTitle = (fileName, specifier, userTitle) => { const title = (0, import_preview_api2.userOrAutoTitleFromSpecifier)(fileName, specifier, userTitle); if (title) { return title.replace("./", ""); } else { console.log({ fileName, userTitle, storyEntries: storyEntries.map((entry) => { return { ...entry, importPathMatcher: entry.importPathMatcher.source }; }), title: title ?? "" }); throw new Error("Could not generate title"); } }; storyEntries.forEach((specifier) => { const { req, directory: root } = specifier; req.keys().forEach((filename) => { try { const fileExports = req(filename); if (!fileExports.default) return; const meta = fileExports.default; Object.keys(fileExports).forEach((key) => { if (key === "default") return; if (!(0, import_csf2.isExportStory)(key, fileExports.default)) return; const exportValue = fileExports[key]; if (!exportValue) return; const name = (0, import_csf2.storyNameFromExport)(key); const title = makeTitle(filename, specifier, meta.title); if (title) { const id = (0, import_csf2.toId)(title, name); index.entries[id] = { type: "story", id, name, title, importPath: `${root}/${filename.substring(2)}`, // FIXME: use normalize function here tags: ["story"] }; const importedStories = req(filename); const stories = Object.entries(importedStories).reduce( (carry, [storyKey, story]) => { if (!(0, import_csf2.isExportStory)(storyKey, fileExports.default)) return carry; if (story.play && !options?.playFn) { carry[storyKey] = { ...story, play: void 0 }; } else { carry[storyKey] = story; } return carry; }, {} ); importMap[`${root}/${filename.substring(2)}`] = stories; } else { console.log(`Unexpected error while loading ${filename}: could not find title`); } }); } catch (error) { const errorString = error.message && error.stack ? `${error.message} ${error.stack}` : error.toString(); console.error(`Unexpected error while loading ${filename}: ${errorString}`); } }); }); return { index, importMap }; } var getProjectAnnotations = (view, annotations) => async () => (0, import_preview_api2.composeConfigs)([ { renderToCanvas: (context) => { view._setStory(context.storyContext); }, render: (args, context) => { const { id, component: Component } = context; if (!Component) { throw new Error( `Unable to render story ${id} as the component annotation is missing from the default export` ); } return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Component, { ...args }); } }, ...annotations ]); function start({ annotations, storyEntries, options }) { const { index, importMap } = prepareStories({ storyEntries, options }); const channel = (0, import_channels2.createBrowserChannel)({ page: "preview" }); import_manager_api2.addons.setChannel(channel); import_preview_api2.addons.setChannel(channel); const previewView = { prepareForStory: () => { return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, {}); }, prepareForDocs: () => { }, showErrorDisplay: (e) => { console.log(e); }, showDocs: () => { }, showMain: () => { }, showNoPreview: () => { }, showPreparingDocs: () => { }, showPreparingStory: () => { }, showStory: () => { }, showStoryDuringRender: () => { } // TODO what happened to this type? }; const selectionStore = { selection: null, selectionSpecifier: null, setQueryParams: () => { }, setSelection: (selection) => { preview.selectionStore.selection = selection; } }; const getProjectAnnotationsInitial = async () => (0, import_preview_api2.composeConfigs)([ { renderToCanvas: (context) => { view._setStory(context.storyContext); }, render: (args, context) => { const { id, component: Component } = context; if (!Component) { throw new Error( `Unable to render story ${id} as the component annotation is missing from the default export` ); } return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Component, { ...args }); } }, ...annotations ]); const preview = new import_preview_api2.PreviewWithSelection( async (importPath) => importMap[importPath], getProjectAnnotationsInitial, selectionStore, previewView ); const view = new View3(preview, channel); if (global) { global.__STORYBOOK_ADDONS_CHANNEL__ = channel; global.__STORYBOOK_PREVIEW__ = preview; } view._storyIndex = index; preview.getStoryIndexFromServer = async () => view._storyIndex; return view; } function updateView(viewInstance, annotations, normalizedStories, options) { const { importMap, index } = prepareStories({ storyEntries: normalizedStories, options }); viewInstance._preview.onStoriesChanged({ importFn: async (importPath) => importMap[importPath] }); viewInstance._preview.onGetProjectAnnotationsChanged({ getProjectAnnotations: getProjectAnnotations(viewInstance, annotations) }); viewInstance._storyIndex = index; viewInstance._preview.onStoryIndexChanged().then(() => { viewInstance.createPreparedStoryMapping().then(() => viewInstance._forceRerender()); }); } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { darkTheme, getProjectAnnotations, prepareStories, start, theme, updateView });