UNPKG

@etchteam/storybook-addon-status

Version:
270 lines (261 loc) 8.26 kB
import startCase from 'lodash/startCase'; import React4 from 'react'; import { addons, types, useStorybookApi, useParameter } from 'storybook/manager-api'; import { css, styled } from 'storybook/theming'; // src/manager.jsx // src/defaults.js var defaultBackground = "#2f2f2f"; var defaultColor = "#ffffff"; var defaultStatuses = { beta: { color: "#ffffff", background: "#ec942c", description: "The interface for this component may change" }, deprecated: { color: "#ffffff", background: "#f02c2c", description: "This component will be removed in the next major version" }, stable: { color: "#ffffff", background: "#339902", description: "This component is stable" }, releaseCandidate: { color: "#ffffff", background: "#a335ee", description: "This component is a release candidate" } }; // src/components/StatusTagBase.jsx var baseStyles = css` align-self: center; border-radius: 0.25em; font-weight: 700; text-decoration: none; text-transform: uppercase; user-select: none; `; var toolbarStyles = css` font-size: 11px; line-height: 20px; padding: 0 0.5em; `; var sidebarStyles = css` font-size: 10px; line-height: 16px; padding: 0 0.4em; `; var variantStyles = ({ variant }) => variant === "sidebar" ? sidebarStyles : toolbarStyles; var LinkTag = styled.a` ${baseStyles} ${variantStyles} `; var TextTag = styled.span` ${baseStyles} ${variantStyles} `; var StatusTagBase = ({ label, status, url, variant = "toolbar" }) => { const resolvedColor = status?.color ?? (defaultStatuses[label] ? defaultStatuses[label].color : defaultColor); const resolvedBackground = status?.background ?? (defaultStatuses[label] ? defaultStatuses[label].background : defaultBackground); const style = { color: resolvedColor, backgroundColor: resolvedBackground }; const description = status?.description; const displayLabel = startCase(label); const isLink = variant === "toolbar" && !!url; if (isLink) { return /* @__PURE__ */ React4.createElement(LinkTag, { variant, style, title: description, href: url }, displayLabel); } return /* @__PURE__ */ React4.createElement(TextTag, { variant, style, title: description }, displayLabel); }; var StatusTagBase_default = StatusTagBase; // src/components/SidebarStatusTag.jsx var SidebarStatusTag = ({ statusConfig }) => /* @__PURE__ */ React4.createElement( StatusTagBase_default, { label: statusConfig.label, status: statusConfig.status, variant: "sidebar" } ); var SidebarStatusTag_default = SidebarStatusTag; var StatusDot = styled.span` align-self: center; background-color: ${({ background, type }) => background ?? (defaultStatuses[type] ? defaultStatuses[type].background : defaultBackground)}; border-radius: 100%; height: 6px; user-select: none; width: 6px; `; var StatusDot_default = StatusDot; // src/constants.js var ADDON_ID = "status"; // src/getStatusConfigs.js var combineTagsAndParameters = (tags, parameters) => { if (!parameters) { return tags ?? []; } if (Array.isArray(parameters)) { return [...tags, ...parameters]; } if (typeof parameters === "string" || typeof parameters === "object") { return [...tags, parameters]; } return []; }; var filterStatuses = (statuses) => { const filteredStatuses = []; const existingNames = []; statuses.forEach((status) => { const name = typeof status === "string" ? status : status.name; if (!existingNames.includes(name)) { filteredStatuses.push(status); existingNames.push(name); return; } if (status.name) { const index = existingNames.indexOf(name); if (index !== -1) { filteredStatuses[index] = status; } } }); return filteredStatuses; }; var getStatusConfigs = ({ tags, parameters, customConfigs }) => { if (!parameters && !tags?.length) { return []; } const combinedStatuses = combineTagsAndParameters(tags, parameters?.type); const statuses = filterStatuses(combinedStatuses); const statusConfigMap = { ...defaultStatuses, ...customConfigs || parameters?.statuses || {} }; let statusConfigs = statuses.map((status) => { if (typeof status === "string") { return { label: status, status: statusConfigMap[status], url: parameters?.url }; } return { label: status.name, status: statusConfigMap[status.name], url: status.url }; }); statusConfigs = statusConfigs.filter((x) => x.status != null); return statusConfigs; }; // src/components/StatusTag.jsx var StatusTag = () => { const api = useStorybookApi(); const tags = api.getCurrentStoryData()?.tags ?? []; const parameters = useParameter(ADDON_ID, null); const customConfigs = addons.getConfig()?.[ADDON_ID]?.statuses; const statusConfigs = getStatusConfigs({ tags, parameters, customConfigs }); if (!statusConfigs?.length) { return null; } return /* @__PURE__ */ React4.createElement(React4.Fragment, null, statusConfigs.map((statusConfig) => /* @__PURE__ */ React4.createElement( StatusTagBase_default, { key: statusConfig.label, label: statusConfig.label, status: statusConfig.status, url: statusConfig.url, variant: "toolbar" } ))); }; var StatusTag_default = StatusTag; // src/manager.jsx addons.register(ADDON_ID, (api) => { const addonsConfig = addons.getConfig(); const existingSidebarConfig = addonsConfig?.sidebar ?? {}; addons.add(ADDON_ID, { title: "Status", type: types.TOOL, render: () => /* @__PURE__ */ React4.createElement(StatusTag_default, null) }); const statusAddonConfig = addonsConfig?.[ADDON_ID] ?? {}; addons.setConfig({ sidebar: { ...existingSidebarConfig, renderLabel: (item) => { const { name, tags } = item; const canHaveStatus = [ "root", "group", "component", "docs", "story" ].includes(item.type); try { const fallbackLabel = existingSidebarConfig?.renderLabel ? existingSidebarConfig.renderLabel(item) : name; const sidebarTagsConfig = statusAddonConfig?.sidebarTags; const sidebarDotsConfig = statusAddonConfig?.sidebarDots; const isTagMode = sidebarTagsConfig === "single" || sidebarTagsConfig === "multiple"; if (sidebarTagsConfig === "none") { return fallbackLabel; } if (sidebarTagsConfig === void 0 && sidebarDotsConfig === "none") { return fallbackLabel; } const parameters = api.getParameters(item.id, ADDON_ID); if (!canHaveStatus || tags.length === 0 && !parameters?.type) { return fallbackLabel; } const customConfigs = statusAddonConfig?.statuses || api.getCurrentStoryData().parameters?.status?.statuses; let statusConfigs = getStatusConfigs({ tags, parameters, customConfigs }); if (statusConfigs.length === 0) { return fallbackLabel; } const showMultiple = isTagMode ? sidebarTagsConfig === "multiple" : sidebarDotsConfig === "multiple"; if (!showMultiple) { statusConfigs = [statusConfigs[0]]; } return /* @__PURE__ */ React4.createElement(React4.Fragment, null, fallbackLabel, statusConfigs.map((statusConfig) => { if (isTagMode) { return /* @__PURE__ */ React4.createElement( SidebarStatusTag_default, { key: statusConfig.label, statusConfig } ); } const { label: statusName, status: { background, description } } = statusConfig; return /* @__PURE__ */ React4.createElement( StatusDot_default, { key: statusName, type: statusName, background, title: `${startCase(statusName)}: ${description}` } ); })); } catch (error) { return name; } } } }); });