UNPKG

@storybook/api

Version:
720 lines (578 loc) • 25.6 kB
"use strict"; require("core-js/modules/es.symbol.js"); Object.defineProperty(exports, "__esModule", { value: true }); exports.init = void 0; require("regenerator-runtime/runtime.js"); require("core-js/modules/es.object.to-string.js"); require("core-js/modules/es.promise.js"); require("core-js/modules/web.dom-collections.for-each.js"); require("core-js/modules/es.object.keys.js"); require("core-js/modules/es.array.find.js"); require("core-js/modules/es.regexp.exec.js"); require("core-js/modules/es.string.split.js"); require("core-js/modules/es.array.includes.js"); require("core-js/modules/es.array.concat.js"); require("core-js/modules/es.function.name.js"); require("core-js/modules/es.array.find-index.js"); require("core-js/modules/es.string.includes.js"); require("core-js/modules/es.object.assign.js"); require("core-js/modules/es.array.filter.js"); require("core-js/modules/es.array.from.js"); require("core-js/modules/es.string.iterator.js"); require("core-js/modules/es.array.iterator.js"); require("core-js/modules/es.set.js"); require("core-js/modules/web.dom-collections.iterator.js"); var _global = _interopRequireDefault(require("global")); var _csf = require("@storybook/csf"); var _coreEvents = require("@storybook/core-events"); var _utilDeprecate = _interopRequireDefault(require("util-deprecate")); var _clientLogger = require("@storybook/client-logger"); var _events = require("../lib/events"); var _stories2 = require("../lib/stories"); var _excluded = ["id"], _excluded2 = ["kind", "story", "storyId"]; function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; } function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } var DOCS_MODE = _global.default.DOCS_MODE, FEATURES = _global.default.FEATURES, fetch = _global.default.fetch; var STORY_INDEX_PATH = './stories.json'; var deprecatedOptionsParameterWarnings = ['enableShortcuts', 'theme', 'showRoots'].reduce(function (acc, option) { acc[option] = (0, _utilDeprecate.default)(function () {}, "parameters.options.".concat(option, " is deprecated and will be removed in Storybook 7.0.\nTo change this setting, use `addons.setConfig`. See https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#deprecated-immutable-options-parameters\n ")); return acc; }, {}); function checkDeprecatedOptionParameters(options) { if (!options) { return; } Object.keys(options).forEach(function (option) { if (deprecatedOptionsParameterWarnings[option]) { deprecatedOptionsParameterWarnings[option](); } }); } var init = function init(_ref) { var fullAPI = _ref.fullAPI, store = _ref.store, navigate = _ref.navigate, provider = _ref.provider, initialStoryId = _ref.storyId, initialViewMode = _ref.viewMode; var api = { storyId: _csf.toId, getData: function getData(storyId, refId) { var result = api.resolveStory(storyId, refId); return (0, _stories2.isRoot)(result) ? undefined : result; }, isPrepared: function isPrepared(storyId, refId) { var data = api.getData(storyId, refId); if (data.isLeaf) { return data.prepared; } // Groups are always prepared :shrug: return true; }, resolveStory: function resolveStory(storyId, refId) { var _store$getState = store.getState(), refs = _store$getState.refs, storiesHash = _store$getState.storiesHash; if (refId) { return refs[refId].stories ? refs[refId].stories[storyId] : undefined; } return storiesHash ? storiesHash[storyId] : undefined; }, getCurrentStoryData: function getCurrentStoryData() { var _store$getState2 = store.getState(), storyId = _store$getState2.storyId, refId = _store$getState2.refId; return api.getData(storyId, refId); }, getParameters: function getParameters(storyIdOrCombo, parameterName) { var _ref2 = typeof storyIdOrCombo === 'string' ? { storyId: storyIdOrCombo, refId: undefined } : storyIdOrCombo, storyId = _ref2.storyId, refId = _ref2.refId; var data = api.getData(storyId, refId); if ((0, _stories2.isStory)(data)) { var parameters = data.parameters; if (parameters) { return parameterName ? parameters[parameterName] : parameters; } return {}; } return null; }, getCurrentParameter: function getCurrentParameter(parameterName) { var _store$getState3 = store.getState(), storyId = _store$getState3.storyId, refId = _store$getState3.refId; var parameters = api.getParameters({ storyId: storyId, refId: refId }, parameterName); // FIXME Returning falsey parameters breaks a bunch of toolbars code, // so this strange logic needs to be here until various client code is updated. return parameters || undefined; }, jumpToComponent: function jumpToComponent(direction) { var _store$getState4 = store.getState(), storiesHash = _store$getState4.storiesHash, storyId = _store$getState4.storyId, refs = _store$getState4.refs, refId = _store$getState4.refId; var story = api.getData(storyId, refId); // cannot navigate when there's no current selection if (!story) { return; } var hash = refId ? refs[refId].stories || {} : storiesHash; var result = api.findSiblingStoryId(storyId, hash, direction, true); if (result) { api.selectStory(result, undefined, { ref: refId }); } }, jumpToStory: function jumpToStory(direction) { var _store$getState5 = store.getState(), storiesHash = _store$getState5.storiesHash, storyId = _store$getState5.storyId, refs = _store$getState5.refs, refId = _store$getState5.refId; var story = api.getData(storyId, refId); if (DOCS_MODE) { api.jumpToComponent(direction); return; } // cannot navigate when there's no current selection if (!story) { return; } var hash = story.refId ? refs[story.refId].stories : storiesHash; var result = api.findSiblingStoryId(storyId, hash, direction, false); if (result) { api.selectStory(result, undefined, { ref: refId }); } }, setStories: function () { var _setStories = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(input, error) { var hash; return regeneratorRuntime.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: // Now create storiesHash by reordering the above by group hash = (0, _stories2.transformStoriesRawToStoriesHash)(input, { provider: provider }); _context.next = 3; return store.setState({ storiesHash: hash, storiesConfigured: true, storiesFailed: error }); case 3: case "end": return _context.stop(); } } }, _callee); })); function setStories(_x, _x2) { return _setStories.apply(this, arguments); } return setStories; }(), selectFirstStory: function selectFirstStory() { var _store$getState6 = store.getState(), storiesHash = _store$getState6.storiesHash; var firstStory = Object.keys(storiesHash).find(function (k) { return !(storiesHash[k].children || Array.isArray(storiesHash[k])); }); if (firstStory) { api.selectStory(firstStory); return; } navigate('/'); }, selectStory: function selectStory() { var kindOrId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : undefined; var story = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined; var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; var ref = options.ref, viewModeFromArgs = options.viewMode; var _store$getState7 = store.getState(), _store$getState7$view = _store$getState7.viewMode, viewModeFromState = _store$getState7$view === void 0 ? 'story' : _store$getState7$view, storyId = _store$getState7.storyId, storiesHash = _store$getState7.storiesHash, refs = _store$getState7.refs; var hash = ref ? refs[ref].stories : storiesHash; var kindSlug = storyId === null || storyId === void 0 ? void 0 : storyId.split('--', 2)[0]; if (!story) { var s = kindOrId ? hash[kindOrId] || hash[(0, _csf.sanitize)(kindOrId)] : hash[kindSlug]; // eslint-disable-next-line no-nested-ternary var id = s ? s.children ? s.children[0] : s.id : kindOrId; var viewMode = s && !(0, _stories2.isRoot)(s) && (viewModeFromArgs || s.parameters.viewMode) ? s.parameters.viewMode : viewModeFromState; // Some viewModes are not story-specific, and we should reset viewMode // to 'story' if one of those is active when navigating to another story if (['settings', 'about', 'release'].includes(viewMode)) { viewMode = 'story'; } var p = s && s.refId ? "/".concat(viewMode, "/").concat(s.refId, "_").concat(id) : "/".concat(viewMode, "/").concat(id); navigate(p); } else if (!kindOrId) { // This is a slugified version of the kind, but that's OK, our toId function is idempotent var _id = (0, _csf.toId)(kindSlug, story); api.selectStory(_id, undefined, options); } else { var _id2 = ref ? "".concat(ref, "_").concat((0, _csf.toId)(kindOrId, story)) : (0, _csf.toId)(kindOrId, story); if (hash[_id2]) { api.selectStory(_id2, undefined, options); } else { // Support legacy API with component permalinks, where kind is `x/y` but permalink is 'z' var _k = hash[(0, _csf.sanitize)(kindOrId)]; if (_k && _k.children) { var foundId = _k.children.find(function (childId) { return hash[childId].name === story; }); if (foundId) { api.selectStory(foundId, undefined, options); } } } } }, findLeafStoryId: function findLeafStoryId(storiesHash, storyId) { if (storiesHash[storyId].isLeaf) { return storyId; } var childStoryId = storiesHash[storyId].children[0]; return api.findLeafStoryId(storiesHash, childStoryId); }, findSiblingStoryId: function findSiblingStoryId(storyId, hash, direction, toSiblingGroup) { if (toSiblingGroup) { var _lookupList = (0, _stories2.getComponentLookupList)(hash); var _index = _lookupList.findIndex(function (i) { return i.includes(storyId); }); // cannot navigate beyond fist or last if (_index === _lookupList.length - 1 && direction > 0) { return; } if (_index === 0 && direction < 0) { return; } if (_lookupList[_index + direction]) { // eslint-disable-next-line consistent-return return _lookupList[_index + direction][0]; } return; } var lookupList = (0, _stories2.getStoriesLookupList)(hash); var index = lookupList.indexOf(storyId); // cannot navigate beyond fist or last if (index === lookupList.length - 1 && direction > 0) { return; } if (index === 0 && direction < 0) { return; } // eslint-disable-next-line consistent-return return lookupList[index + direction]; }, updateStoryArgs: function updateStoryArgs(story, updatedArgs) { var storyId = story.id, refId = story.refId; fullAPI.emit(_coreEvents.UPDATE_STORY_ARGS, { storyId: storyId, updatedArgs: updatedArgs, options: { target: refId ? "storybook-ref-".concat(refId) : 'storybook-preview-iframe' } }); }, resetStoryArgs: function resetStoryArgs(story, argNames) { var storyId = story.id, refId = story.refId; fullAPI.emit(_coreEvents.RESET_STORY_ARGS, { storyId: storyId, argNames: argNames, options: { target: refId ? "storybook-ref-".concat(refId) : 'storybook-preview-iframe' } }); }, fetchStoryList: function () { var _fetchStoryList = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2() { var result, storyIndex; return regeneratorRuntime.wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: _context2.prev = 0; _context2.next = 3; return fetch(STORY_INDEX_PATH); case 3: result = _context2.sent; if (!(result.status !== 200)) { _context2.next = 10; break; } _context2.t0 = Error; _context2.next = 8; return result.text(); case 8: _context2.t1 = _context2.sent; throw new _context2.t0(_context2.t1); case 10: _context2.next = 12; return result.json(); case 12: storyIndex = _context2.sent; if (!(storyIndex.v !== 3)) { _context2.next = 16; break; } _clientLogger.logger.warn("Skipping story index with version v".concat(storyIndex.v, ", awaiting SET_STORIES.")); return _context2.abrupt("return"); case 16: _context2.next = 18; return fullAPI.setStoryList(storyIndex); case 18: _context2.next = 23; break; case 20: _context2.prev = 20; _context2.t2 = _context2["catch"](0); store.setState({ storiesConfigured: true, storiesFailed: _context2.t2 }); case 23: case "end": return _context2.stop(); } } }, _callee2, null, [[0, 20]]); })); function fetchStoryList() { return _fetchStoryList.apply(this, arguments); } return fetchStoryList; }(), setStoryList: function () { var _setStoryList = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3(storyIndex) { var hash; return regeneratorRuntime.wrap(function _callee3$(_context3) { while (1) { switch (_context3.prev = _context3.next) { case 0: hash = (0, _stories2.transformStoryIndexToStoriesHash)(storyIndex, { provider: provider }); _context3.next = 3; return store.setState({ storiesHash: hash, storiesConfigured: true, storiesFailed: null }); case 3: case "end": return _context3.stop(); } } }, _callee3); })); function setStoryList(_x3) { return _setStoryList.apply(this, arguments); } return setStoryList; }(), updateStory: function () { var _updateStory = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee4(storyId, update, ref) { var _store$getState8, storiesHash, _refId, _stories; return regeneratorRuntime.wrap(function _callee4$(_context4) { while (1) { switch (_context4.prev = _context4.next) { case 0: if (ref) { _context4.next = 7; break; } _store$getState8 = store.getState(), storiesHash = _store$getState8.storiesHash; storiesHash[storyId] = Object.assign({}, storiesHash[storyId], update); _context4.next = 5; return store.setState({ storiesHash: storiesHash }); case 5: _context4.next = 11; break; case 7: _refId = ref.id, _stories = ref.stories; _stories[storyId] = Object.assign({}, _stories[storyId], update); _context4.next = 11; return fullAPI.updateRef(_refId, { stories: _stories }); case 11: case "end": return _context4.stop(); } } }, _callee4); })); function updateStory(_x4, _x5, _x6) { return _updateStory.apply(this, arguments); } return updateStory; }() }; var initModule = /*#__PURE__*/function () { var _ref3 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee5() { var _provider$serverChann; return regeneratorRuntime.wrap(function _callee5$(_context5) { while (1) { switch (_context5.prev = _context5.next) { case 0: // On initial load, the local iframe will select the first story (or other "selection specifier") // and emit STORY_SPECIFIED with the id. We need to ensure we respond to this change. fullAPI.on(_coreEvents.STORY_SPECIFIED, function handler(_ref4) { var storyId = _ref4.storyId, viewMode = _ref4.viewMode; var _getEventMetadata = (0, _events.getEventMetadata)(this, fullAPI), sourceType = _getEventMetadata.sourceType; if (fullAPI.isSettingsScreenActive()) return; if (sourceType === 'local') { // Special case -- if we are already at the story being specified (i.e. the user started at a given story), // we don't need to change URL. See https://github.com/storybookjs/storybook/issues/11677 var state = store.getState(); if (state.storyId !== storyId || state.viewMode !== viewMode) { navigate("/".concat(viewMode, "/").concat(storyId)); } } }); fullAPI.on(_coreEvents.STORY_CHANGED, function handler() { var _getEventMetadata2 = (0, _events.getEventMetadata)(this, fullAPI), sourceType = _getEventMetadata2.sourceType; if (sourceType === 'local') { var options = fullAPI.getCurrentParameter('options'); if (options) { checkDeprecatedOptionParameters(options); fullAPI.setOptions(options); } } }); fullAPI.on(_coreEvents.STORY_PREPARED, function handler(_ref5) { var id = _ref5.id, update = _objectWithoutProperties(_ref5, _excluded); var _getEventMetadata3 = (0, _events.getEventMetadata)(this, fullAPI), ref = _getEventMetadata3.ref, sourceType = _getEventMetadata3.sourceType; fullAPI.updateStory(id, Object.assign({}, update, { prepared: true }), ref); if (!ref) { if (!store.getState().hasCalledSetOptions) { var options = update.parameters.options; checkDeprecatedOptionParameters(options); fullAPI.setOptions(options); store.setState({ hasCalledSetOptions: true }); } } else { fullAPI.updateRef(ref.id, { ready: true }); } if (sourceType === 'local') { var _store$getState9 = store.getState(), _storyId = _store$getState9.storyId, storiesHash = _store$getState9.storiesHash; // create a list of related stories to be preloaded var toBePreloaded = Array.from(new Set([api.findSiblingStoryId(_storyId, storiesHash, 1, true), api.findSiblingStoryId(_storyId, storiesHash, -1, true)])).filter(Boolean); fullAPI.emit(_coreEvents.PRELOAD_STORIES, toBePreloaded); } }); fullAPI.on(_coreEvents.SET_STORIES, function handler(data) { var _getEventMetadata4 = (0, _events.getEventMetadata)(this, fullAPI), ref = _getEventMetadata4.ref; var stories = data.v ? (0, _stories2.denormalizeStoryParameters)(data) : data.stories; if (!ref) { if (!data.v) { throw new Error('Unexpected legacy SET_STORIES event from local source'); } fullAPI.setStories(stories); var options = fullAPI.getCurrentParameter('options'); checkDeprecatedOptionParameters(options); fullAPI.setOptions(options); } else { fullAPI.setRef(ref.id, Object.assign({}, ref, data, { stories: stories }), true); } }); fullAPI.on(_coreEvents.SELECT_STORY, function handler(_ref6) { var kind = _ref6.kind, story = _ref6.story, storyId = _ref6.storyId, rest = _objectWithoutProperties(_ref6, _excluded2); var _getEventMetadata5 = (0, _events.getEventMetadata)(this, fullAPI), ref = _getEventMetadata5.ref; if (!ref) { fullAPI.selectStory(storyId || kind, story, rest); } else { fullAPI.selectStory(storyId || kind, story, Object.assign({}, rest, { ref: ref.id })); } }); fullAPI.on(_coreEvents.STORY_ARGS_UPDATED, function handleStoryArgsUpdated(_ref7) { var storyId = _ref7.storyId, args = _ref7.args; var _getEventMetadata6 = (0, _events.getEventMetadata)(this, fullAPI), ref = _getEventMetadata6.ref; fullAPI.updateStory(storyId, { args: args }, ref); }); fullAPI.on(_coreEvents.CONFIG_ERROR, function handleConfigError(err) { store.setState({ storiesConfigured: true, storiesFailed: err }); }); if (!(FEATURES !== null && FEATURES !== void 0 && FEATURES.storyStoreV7)) { _context5.next = 11; break; } (_provider$serverChann = provider.serverChannel) === null || _provider$serverChann === void 0 ? void 0 : _provider$serverChann.on(_coreEvents.STORY_INDEX_INVALIDATED, function () { return fullAPI.fetchStoryList(); }); _context5.next = 11; return fullAPI.fetchStoryList(); case 11: case "end": return _context5.stop(); } } }, _callee5); })); return function initModule() { return _ref3.apply(this, arguments); }; }(); return { api: api, state: { storiesHash: {}, storyId: initialStoryId, viewMode: initialViewMode, storiesConfigured: false, hasCalledSetOptions: false }, init: initModule }; }; exports.init = init;