@component-anatomy/storybook 0.0.2 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/manager.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/manager.tsx
2
- import React2 from "react";
2
+ import React3 from "react";
3
3
  import { addons, types } from "storybook/manager-api";
4
4
  import { AddonPanel } from "storybook/internal/components";
5
5
 
@@ -8,38 +8,60 @@ var ADDON_ID = "component-anatomy";
8
8
  var PANEL_ID = `${ADDON_ID}/panel`;
9
9
  var PARAM_KEY = "anatomy";
10
10
  var EVENTS = {
11
- /** preview → manager: a part became active in the canvas (hover/programmatic). */
11
+ /** preview → consumers: a part became active in the canvas (hover/programmatic). */
12
12
  PART_ENTER: `${ADDON_ID}/part-enter`,
13
- /** preview → manager: no part is active anymore. */
13
+ /** preview → consumers: no part is active anymore. */
14
14
  PART_LEAVE: `${ADDON_ID}/part-leave`,
15
- /** preview → manager: resolved part list for the current story. */
15
+ /** preview → consumers: resolved part list for a story. */
16
16
  PARTS: `${ADDON_ID}/parts`,
17
- /** manager → preview: the user hovers/focuses a panel entry. */
17
+ /** consumers → preview: the user hovers/focuses a panel entry. */
18
18
  HOVER_ITEM: `${ADDON_ID}/hover-item`,
19
- /** manager → preview: the user left a panel entry. */
19
+ /** consumers → preview: the user left a panel entry. */
20
20
  LEAVE_ITEM: `${ADDON_ID}/leave-item`,
21
- /** manager → preview: the panel mounted and wants the current part list. */
21
+ /** consumers → preview: a panel/block mounted and wants the current part list. */
22
22
  PARTS_REQUEST: `${ADDON_ID}/parts-request`
23
23
  };
24
24
 
25
25
  // src/Panel.tsx
26
- import React, { useEffect, useState } from "react";
26
+ import React2, { useEffect, useState } from "react";
27
27
  import { useChannel, useParameter, useStorybookApi } from "storybook/manager-api";
28
+
29
+ // src/channel.ts
30
+ var matchesStory = (eventStoryId, storyId) => !eventStoryId || !storyId || eventStoryId === storyId;
31
+
32
+ // src/AnatomyTable.tsx
33
+ import React from "react";
34
+ import { useTheme } from "storybook/theming";
28
35
  var ACCENT_FALLBACK = "#4f46e5";
29
- var styles = {
36
+ var FONT_BASE_FALLBACK = '"Nunito Sans", -apple-system, ".SFNSText-Regular", "San Francisco", BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Helvetica, Arial, sans-serif';
37
+ var FONT_MONO_FALLBACK = 'ui-monospace, "Cascadia Code", "Fira Mono", monospace';
38
+ function usePalette() {
39
+ const theme = useTheme();
40
+ return {
41
+ text: theme.fgColor?.default,
42
+ muted: theme.fgColor?.muted ?? "#6b7280",
43
+ mutedBg: theme.bgColor?.muted ?? "rgba(0,0,0,0.06)",
44
+ border: theme.borderColor?.default ?? "rgba(0,0,0,0.08)",
45
+ fontBase: theme.typography?.fonts?.base ?? FONT_BASE_FALLBACK,
46
+ fontMono: theme.typography?.fonts?.mono ?? FONT_MONO_FALLBACK
47
+ };
48
+ }
49
+ var makeStyles = (p) => ({
30
50
  container: {
31
51
  padding: "12px 16px",
32
- fontFamily: '"Nunito Sans", -apple-system, ".SFNSText-Regular", "San Francisco", BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Helvetica, Arial, sans-serif',
52
+ fontFamily: p.fontBase,
33
53
  fontSize: 13,
34
- lineHeight: 1.5
54
+ lineHeight: 1.5,
55
+ color: p.text
35
56
  },
36
57
  empty: {
37
- color: "#6b7280"
58
+ color: p.muted,
59
+ margin: 0
38
60
  },
39
61
  code: {
40
- fontFamily: 'ui-monospace, "Cascadia Code", "Fira Mono", monospace',
62
+ fontFamily: p.fontMono,
41
63
  fontSize: "0.85em",
42
- background: "rgba(0,0,0,0.06)",
64
+ background: p.mutedBg,
43
65
  borderRadius: 3,
44
66
  padding: "1px 5px"
45
67
  },
@@ -68,7 +90,7 @@ var styles = {
68
90
  width: 8,
69
91
  height: 8,
70
92
  borderRadius: "50%",
71
- border: "2px solid #d1d5db",
93
+ border: `2px solid ${p.border}`,
72
94
  flexShrink: 0,
73
95
  transition: "background 120ms ease, border-color 120ms ease"
74
96
  },
@@ -77,45 +99,38 @@ var styles = {
77
99
  flex: 1
78
100
  },
79
101
  id: {
80
- fontFamily: 'ui-monospace, "Cascadia Code", "Fira Mono", monospace',
102
+ fontFamily: p.fontMono,
81
103
  fontSize: 10,
82
104
  padding: "1px 6px",
83
105
  borderRadius: 4,
84
- background: "rgba(0,0,0,0.05)",
85
- border: "1px solid rgba(0,0,0,0.08)",
86
- color: "#6b7280",
106
+ background: p.mutedBg,
107
+ border: `1px solid ${p.border}`,
108
+ color: p.muted,
87
109
  flexShrink: 0
88
110
  },
89
111
  description: {
90
112
  margin: "4px 0 0",
91
113
  paddingLeft: 16,
92
- color: "#6b7280"
114
+ color: p.muted
93
115
  }
116
+ });
117
+ var AnatomyCode = ({ children }) => {
118
+ const styles = makeStyles(usePalette());
119
+ return /* @__PURE__ */ React.createElement("code", { style: styles.code }, children);
94
120
  };
95
- var Panel = () => {
96
- const params = useParameter(PARAM_KEY, void 0);
97
- const api = useStorybookApi();
98
- const storyId = api.getUrlState().storyId;
99
- const [discovered, setDiscovered] = useState([]);
100
- const [activeId, setActiveId] = useState(null);
101
- const emit = useChannel({
102
- [EVENTS.PARTS]: ({ parts: parts2 }) => setDiscovered(parts2),
103
- [EVENTS.PART_ENTER]: ({ partId }) => setActiveId(partId),
104
- [EVENTS.PART_LEAVE]: () => setActiveId(null)
105
- });
106
- useEffect(() => {
107
- setDiscovered([]);
108
- setActiveId(null);
109
- emit(EVENTS.PARTS_REQUEST);
110
- }, [storyId]);
111
- const parts = params?.parts ?? discovered;
112
- const accent = params?.theme?.accent ?? ACCENT_FALLBACK;
113
- if (!params || params.disable) {
114
- return /* @__PURE__ */ React.createElement("div", { style: styles.container }, /* @__PURE__ */ React.createElement("p", { style: styles.empty }, "No anatomy configured for this story. Add", " ", /* @__PURE__ */ React.createElement("code", { style: styles.code }, "parameters.anatomy"), " and annotate elements with", " ", /* @__PURE__ */ React.createElement("code", { style: styles.code }, 'data-part="name"'), "."));
115
- }
116
- if (parts.length === 0) {
117
- return /* @__PURE__ */ React.createElement("div", { style: styles.container }, /* @__PURE__ */ React.createElement("p", { style: styles.empty }, "No parts found. Annotate elements in your story with", " ", /* @__PURE__ */ React.createElement("code", { style: styles.code }, 'data-part="name"'), " or pass", " ", /* @__PURE__ */ React.createElement("code", { style: styles.code }, "parameters.anatomy.parts"), "."));
118
- }
121
+ var AnatomyMessage = ({ children }) => {
122
+ const styles = makeStyles(usePalette());
123
+ return /* @__PURE__ */ React.createElement("div", { style: styles.container }, /* @__PURE__ */ React.createElement("p", { style: styles.empty }, children));
124
+ };
125
+ var AnatomyTable = ({
126
+ parts,
127
+ activeId = null,
128
+ accent = ACCENT_FALLBACK,
129
+ onItemEnter,
130
+ onItemLeave
131
+ }) => {
132
+ const palette = usePalette();
133
+ const styles = makeStyles(palette);
119
134
  return /* @__PURE__ */ React.createElement("div", { style: styles.container }, /* @__PURE__ */ React.createElement("ul", { style: styles.list, role: "list", "aria-label": "Anatomy parts" }, parts.map((part) => {
120
135
  const active = activeId === part.id;
121
136
  return /* @__PURE__ */ React.createElement(
@@ -130,10 +145,10 @@ var Panel = () => {
130
145
  background: active ? `color-mix(in srgb, ${accent} 7%, transparent)` : void 0,
131
146
  borderColor: active ? `color-mix(in srgb, ${accent} 20%, transparent)` : "transparent"
132
147
  },
133
- onMouseEnter: () => emit(EVENTS.HOVER_ITEM, { partId: part.id }),
134
- onMouseLeave: () => emit(EVENTS.LEAVE_ITEM),
135
- onFocus: () => emit(EVENTS.HOVER_ITEM, { partId: part.id }),
136
- onBlur: () => emit(EVENTS.LEAVE_ITEM)
148
+ onMouseEnter: () => onItemEnter?.(part.id),
149
+ onMouseLeave: () => onItemLeave?.(),
150
+ onFocus: () => onItemEnter?.(part.id),
151
+ onBlur: () => onItemLeave?.()
137
152
  },
138
153
  /* @__PURE__ */ React.createElement("div", { style: styles.header }, /* @__PURE__ */ React.createElement(
139
154
  "span",
@@ -142,7 +157,7 @@ var Panel = () => {
142
157
  style: {
143
158
  ...styles.indicator,
144
159
  background: active ? accent : void 0,
145
- borderColor: active ? accent : "#d1d5db"
160
+ borderColor: active ? accent : palette.border
146
161
  }
147
162
  }
148
163
  ), /* @__PURE__ */ React.createElement("span", { style: { ...styles.name, color: active ? accent : void 0 } }, part.name), /* @__PURE__ */ React.createElement("code", { style: styles.id }, part.id)),
@@ -151,6 +166,55 @@ var Panel = () => {
151
166
  })));
152
167
  };
153
168
 
169
+ // src/Panel.tsx
170
+ var Panel = () => {
171
+ const params = useParameter(PARAM_KEY, void 0);
172
+ const api = useStorybookApi();
173
+ const storyId = api.getUrlState().storyId;
174
+ const [discovered, setDiscovered] = useState([]);
175
+ const [activeId, setActiveId] = useState(null);
176
+ const emit = useChannel(
177
+ {
178
+ [EVENTS.PARTS]: (event) => {
179
+ if (!matchesStory(event?.storyId, storyId)) return;
180
+ setDiscovered(event.parts);
181
+ },
182
+ [EVENTS.PART_ENTER]: (event) => {
183
+ if (!matchesStory(event?.storyId, storyId)) return;
184
+ setActiveId(event.partId);
185
+ },
186
+ [EVENTS.PART_LEAVE]: (event = {}) => {
187
+ if (!matchesStory(event?.storyId, storyId)) return;
188
+ setActiveId(null);
189
+ }
190
+ },
191
+ [storyId]
192
+ );
193
+ useEffect(() => {
194
+ setDiscovered([]);
195
+ setActiveId(null);
196
+ emit(EVENTS.PARTS_REQUEST, { storyId });
197
+ }, [storyId]);
198
+ const parts = params?.parts ?? discovered;
199
+ const accent = params?.theme?.accent ?? ACCENT_FALLBACK;
200
+ if (!params || params.disable) {
201
+ return /* @__PURE__ */ React2.createElement(AnatomyMessage, null, "No anatomy configured for this story. Add ", /* @__PURE__ */ React2.createElement(AnatomyCode, null, "parameters.anatomy"), " and annotate elements with ", /* @__PURE__ */ React2.createElement(AnatomyCode, null, 'data-part="name"'), ".");
202
+ }
203
+ if (parts.length === 0) {
204
+ return /* @__PURE__ */ React2.createElement(AnatomyMessage, null, "No parts found. Annotate elements in your story with", " ", /* @__PURE__ */ React2.createElement(AnatomyCode, null, 'data-part="name"'), " or pass", " ", /* @__PURE__ */ React2.createElement(AnatomyCode, null, "parameters.anatomy.parts"), ".");
205
+ }
206
+ return /* @__PURE__ */ React2.createElement(
207
+ AnatomyTable,
208
+ {
209
+ parts,
210
+ activeId,
211
+ accent,
212
+ onItemEnter: (partId) => emit(EVENTS.HOVER_ITEM, { storyId, partId }),
213
+ onItemLeave: () => emit(EVENTS.LEAVE_ITEM, { storyId })
214
+ }
215
+ );
216
+ };
217
+
154
218
  // src/manager.tsx
155
219
  addons.register(ADDON_ID, () => {
156
220
  addons.add(PANEL_ID, {
@@ -158,7 +222,7 @@ addons.register(ADDON_ID, () => {
158
222
  title: "Anatomy",
159
223
  paramKey: PARAM_KEY,
160
224
  match: ({ viewMode }) => viewMode === "story",
161
- render: ({ active }) => /* @__PURE__ */ React2.createElement(AddonPanel, { active: !!active }, /* @__PURE__ */ React2.createElement(Panel, null))
225
+ render: ({ active }) => /* @__PURE__ */ React3.createElement(AddonPanel, { active: !!active }, /* @__PURE__ */ React3.createElement(Panel, null))
162
226
  });
163
227
  });
164
228
  //# sourceMappingURL=manager.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/manager.tsx", "../src/constants.ts", "../src/Panel.tsx"],
4
- "sourcesContent": ["import React from 'react';\nimport { addons, types } from 'storybook/manager-api';\nimport { AddonPanel } from 'storybook/internal/components';\n\nimport { ADDON_ID, PANEL_ID, PARAM_KEY } from './constants.js';\nimport { Panel } from './Panel.js';\n\naddons.register(ADDON_ID, () => {\n addons.add(PANEL_ID, {\n type: types.PANEL,\n title: 'Anatomy',\n paramKey: PARAM_KEY,\n match: ({ viewMode }) => viewMode === 'story',\n render: ({ active }) => (\n <AddonPanel active={!!active}>\n <Panel />\n </AddonPanel>\n ),\n });\n});\n", "export const ADDON_ID = 'component-anatomy';\nexport const PANEL_ID = `${ADDON_ID}/panel`;\n\n/** Story parameter key: `parameters.anatomy = { ... }` */\nexport const PARAM_KEY = 'anatomy';\n\n/** Channel events used to sync the manager panel with the preview iframe. */\nexport const EVENTS = {\n /** preview \u2192 manager: a part became active in the canvas (hover/programmatic). */\n PART_ENTER: `${ADDON_ID}/part-enter`,\n /** preview \u2192 manager: no part is active anymore. */\n PART_LEAVE: `${ADDON_ID}/part-leave`,\n /** preview \u2192 manager: resolved part list for the current story. */\n PARTS: `${ADDON_ID}/parts`,\n /** manager \u2192 preview: the user hovers/focuses a panel entry. */\n HOVER_ITEM: `${ADDON_ID}/hover-item`,\n /** manager \u2192 preview: the user left a panel entry. */\n LEAVE_ITEM: `${ADDON_ID}/leave-item`,\n /** manager \u2192 preview: the panel mounted and wants the current part list. */\n PARTS_REQUEST: `${ADDON_ID}/parts-request`,\n} as const;\n", "import React, { useEffect, useState } from 'react';\nimport { useChannel, useParameter, useStorybookApi } from 'storybook/manager-api';\nimport type { AnatomyPartDefinition } from '@component-anatomy/core';\n\nimport { EVENTS, PARAM_KEY } from './constants.js';\nimport type { AnatomyParameters } from './types.js';\n\nconst ACCENT_FALLBACK = '#4f46e5';\n\nconst styles: Record<string, React.CSSProperties> = {\n container: {\n padding: '12px 16px',\n fontFamily:\n '\"Nunito Sans\", -apple-system, \".SFNSText-Regular\", \"San Francisco\", BlinkMacSystemFont, \"Segoe UI\", \"Helvetica Neue\", Helvetica, Arial, sans-serif',\n fontSize: 13,\n lineHeight: 1.5,\n },\n empty: {\n color: '#6b7280',\n },\n code: {\n fontFamily: 'ui-monospace, \"Cascadia Code\", \"Fira Mono\", monospace',\n fontSize: '0.85em',\n background: 'rgba(0,0,0,0.06)',\n borderRadius: 3,\n padding: '1px 5px',\n },\n list: {\n display: 'flex',\n flexDirection: 'column',\n gap: 2,\n margin: 0,\n padding: 0,\n listStyle: 'none',\n },\n entry: {\n padding: '8px 10px',\n borderRadius: 6,\n border: '1px solid transparent',\n cursor: 'default',\n outline: 'none',\n transition: 'background 120ms ease, border-color 120ms ease',\n },\n header: {\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n },\n indicator: {\n width: 8,\n height: 8,\n borderRadius: '50%',\n border: '2px solid #d1d5db',\n flexShrink: 0,\n transition: 'background 120ms ease, border-color 120ms ease',\n },\n name: {\n fontWeight: 700,\n flex: 1,\n },\n id: {\n fontFamily: 'ui-monospace, \"Cascadia Code\", \"Fira Mono\", monospace',\n fontSize: 10,\n padding: '1px 6px',\n borderRadius: 4,\n background: 'rgba(0,0,0,0.05)',\n border: '1px solid rgba(0,0,0,0.08)',\n color: '#6b7280',\n flexShrink: 0,\n },\n description: {\n margin: '4px 0 0',\n paddingLeft: 16,\n color: '#6b7280',\n },\n};\n\nexport const Panel: React.FC = () => {\n const params = useParameter<AnatomyParameters | undefined>(PARAM_KEY, undefined);\n const api = useStorybookApi();\n const storyId = api.getUrlState().storyId;\n\n const [discovered, setDiscovered] = useState<AnatomyPartDefinition[]>([]);\n const [activeId, setActiveId] = useState<string | null>(null);\n\n const emit = useChannel({\n [EVENTS.PARTS]: ({ parts }: { parts: AnatomyPartDefinition[] }) => setDiscovered(parts),\n [EVENTS.PART_ENTER]: ({ partId }: { partId: string }) => setActiveId(partId),\n [EVENTS.PART_LEAVE]: () => setActiveId(null),\n });\n\n // Ask the preview for the current part list on mount / story change.\n useEffect(() => {\n setDiscovered([]);\n setActiveId(null);\n emit(EVENTS.PARTS_REQUEST);\n }, [storyId]);\n\n const parts = params?.parts ?? discovered;\n const accent = params?.theme?.accent ?? ACCENT_FALLBACK;\n\n if (!params || params.disable) {\n return (\n <div style={styles.container}>\n <p style={styles.empty}>\n No anatomy configured for this story. Add{' '}\n <code style={styles.code}>parameters.anatomy</code> and annotate elements with{' '}\n <code style={styles.code}>data-part=\"name\"</code>.\n </p>\n </div>\n );\n }\n\n if (parts.length === 0) {\n return (\n <div style={styles.container}>\n <p style={styles.empty}>\n No parts found. Annotate elements in your story with{' '}\n <code style={styles.code}>data-part=\"name\"</code> or pass{' '}\n <code style={styles.code}>parameters.anatomy.parts</code>.\n </p>\n </div>\n );\n }\n\n return (\n <div style={styles.container}>\n <ul style={styles.list} role=\"list\" aria-label=\"Anatomy parts\">\n {parts.map((part) => {\n const active = activeId === part.id;\n return (\n <li\n key={part.id}\n role=\"listitem\"\n tabIndex={0}\n aria-label={part.name}\n style={{\n ...styles.entry,\n background: active ? `color-mix(in srgb, ${accent} 7%, transparent)` : undefined,\n borderColor: active ? `color-mix(in srgb, ${accent} 20%, transparent)` : 'transparent',\n }}\n onMouseEnter={() => emit(EVENTS.HOVER_ITEM, { partId: part.id })}\n onMouseLeave={() => emit(EVENTS.LEAVE_ITEM)}\n onFocus={() => emit(EVENTS.HOVER_ITEM, { partId: part.id })}\n onBlur={() => emit(EVENTS.LEAVE_ITEM)}\n >\n <div style={styles.header}>\n <span\n aria-hidden=\"true\"\n style={{\n ...styles.indicator,\n background: active ? accent : undefined,\n borderColor: active ? accent : '#d1d5db',\n }}\n />\n <span style={{ ...styles.name, color: active ? accent : undefined }}>\n {part.name}\n </span>\n <code style={styles.id}>{part.id}</code>\n </div>\n {part.description && <p style={styles.description}>{part.description}</p>}\n </li>\n );\n })}\n </ul>\n </div>\n );\n};\n"],
5
- "mappings": "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",
6
- "names": ["React", "parts", "React"]
3
+ "sources": ["../src/manager.tsx", "../src/constants.ts", "../src/Panel.tsx", "../src/channel.ts", "../src/AnatomyTable.tsx"],
4
+ "sourcesContent": ["import React from 'react';\nimport { addons, types } from 'storybook/manager-api';\nimport { AddonPanel } from 'storybook/internal/components';\n\nimport { ADDON_ID, PANEL_ID, PARAM_KEY } from './constants.js';\nimport { Panel } from './Panel.js';\n\naddons.register(ADDON_ID, () => {\n addons.add(PANEL_ID, {\n type: types.PANEL,\n title: 'Anatomy',\n paramKey: PARAM_KEY,\n match: ({ viewMode }) => viewMode === 'story',\n render: ({ active }) => (\n <AddonPanel active={!!active}>\n <Panel />\n </AddonPanel>\n ),\n });\n});\n", "export const ADDON_ID = 'component-anatomy';\nexport const PANEL_ID = `${ADDON_ID}/panel`;\n\n/** Story parameter key: `parameters.anatomy = { ... }` */\nexport const PARAM_KEY = 'anatomy';\n\n/**\n * Channel events used to sync the manager panel \u2014 and the `<Anatomy>` MDX doc\n * block, which runs in the preview iframe \u2014 with the story canvas.\n *\n * Every payload carries the `storyId` it concerns; see `channel.ts` for the\n * payload types and the `matchesStory` filter each listener applies.\n */\nexport const EVENTS = {\n /** preview \u2192 consumers: a part became active in the canvas (hover/programmatic). */\n PART_ENTER: `${ADDON_ID}/part-enter`,\n /** preview \u2192 consumers: no part is active anymore. */\n PART_LEAVE: `${ADDON_ID}/part-leave`,\n /** preview \u2192 consumers: resolved part list for a story. */\n PARTS: `${ADDON_ID}/parts`,\n /** consumers \u2192 preview: the user hovers/focuses a panel entry. */\n HOVER_ITEM: `${ADDON_ID}/hover-item`,\n /** consumers \u2192 preview: the user left a panel entry. */\n LEAVE_ITEM: `${ADDON_ID}/leave-item`,\n /** consumers \u2192 preview: a panel/block mounted and wants the current part list. */\n PARTS_REQUEST: `${ADDON_ID}/parts-request`,\n} as const;\n", "import React, { useEffect, useState } from 'react';\nimport { useChannel, useParameter, useStorybookApi } from 'storybook/manager-api';\nimport type { AnatomyPartDefinition } from '@component-anatomy/core';\n\nimport { EVENTS, PARAM_KEY } from './constants.js';\nimport { matchesStory } from './channel.js';\nimport type { PartEnterEvent, PartsEvent, StoryScopedEvent } from './channel.js';\nimport { ACCENT_FALLBACK, AnatomyCode, AnatomyMessage, AnatomyTable } from './AnatomyTable.js';\nimport type { AnatomyParameters } from './types.js';\n\nexport const Panel: React.FC = () => {\n const params = useParameter<AnatomyParameters | undefined>(PARAM_KEY, undefined);\n const api = useStorybookApi();\n const storyId = api.getUrlState().storyId;\n\n const [discovered, setDiscovered] = useState<AnatomyPartDefinition[]>([]);\n const [activeId, setActiveId] = useState<string | null>(null);\n\n // `useChannel` captures its handlers on the given deps \u2014 `storyId` has to be\n // listed or the filters below would close over a stale story.\n const emit = useChannel(\n {\n [EVENTS.PARTS]: (event: PartsEvent) => {\n if (!matchesStory(event?.storyId, storyId)) return;\n setDiscovered(event.parts);\n },\n [EVENTS.PART_ENTER]: (event: PartEnterEvent) => {\n if (!matchesStory(event?.storyId, storyId)) return;\n setActiveId(event.partId);\n },\n [EVENTS.PART_LEAVE]: (event: StoryScopedEvent = {}) => {\n if (!matchesStory(event?.storyId, storyId)) return;\n setActiveId(null);\n },\n },\n [storyId]\n );\n\n // Ask the preview for the current part list on mount / story change.\n useEffect(() => {\n setDiscovered([]);\n setActiveId(null);\n emit(EVENTS.PARTS_REQUEST, { storyId } satisfies StoryScopedEvent);\n }, [storyId]);\n\n const parts = params?.parts ?? discovered;\n const accent = params?.theme?.accent ?? ACCENT_FALLBACK;\n\n if (!params || params.disable) {\n return (\n <AnatomyMessage>\n No anatomy configured for this story. Add <AnatomyCode>parameters.anatomy</AnatomyCode> and\n annotate elements with <AnatomyCode>data-part=\"name\"</AnatomyCode>.\n </AnatomyMessage>\n );\n }\n\n if (parts.length === 0) {\n return (\n <AnatomyMessage>\n No parts found. Annotate elements in your story with{' '}\n <AnatomyCode>data-part=\"name\"</AnatomyCode> or pass{' '}\n <AnatomyCode>parameters.anatomy.parts</AnatomyCode>.\n </AnatomyMessage>\n );\n }\n\n return (\n <AnatomyTable\n parts={parts}\n activeId={activeId}\n accent={accent}\n onItemEnter={(partId) => emit(EVENTS.HOVER_ITEM, { storyId, partId })}\n onItemLeave={() => emit(EVENTS.LEAVE_ITEM, { storyId })}\n />\n );\n};\n", "/**\n * Shared channel payload contract between the preview decorator, the manager\n * panel, and the MDX doc block.\n *\n * Every payload carries the `storyId` it refers to. In story view this is\n * redundant \u2014 only one story is mounted \u2014 but a docs page mounts *many*\n * stories at once, each with its own controller, and each `<Anatomy>` block\n * must talk to exactly one of them. Without addressing, hovering a part in\n * one block highlights the matching part in every other story on the page.\n */\nimport type { AnatomyPartDefinition } from '@component-anatomy/core';\n\n/** preview \u2192 consumers: the resolved part list for one story. */\nexport type PartsEvent = { storyId?: string; parts: AnatomyPartDefinition[] };\n\n/** preview \u2192 consumers: a part became active in that story's canvas. */\nexport type PartEnterEvent = { storyId?: string; partId: string };\n\n/** consumer \u2192 preview: highlight this part in that story's canvas. */\nexport type HoverItemEvent = { storyId?: string; partId: string };\n\n/** Payload for the events that only need to name a story. */\nexport type StoryScopedEvent = { storyId?: string };\n\n/**\n * Whether an event addressed to `eventStoryId` concerns `storyId`.\n *\n * A missing id on *either* side matches everything. That keeps the protocol\n * backward compatible: a manager panel from a newer build still understands\n * an older preview bundle that emits unaddressed events, and vice versa.\n */\nexport const matchesStory = (\n eventStoryId: string | undefined,\n storyId: string | undefined\n): boolean => !eventStoryId || !storyId || eventStoryId === storyId;\n", "/**\n * The anatomy part table \u2014 pure presentation, no Storybook imports.\n *\n * This module is deliberately free of `storybook/manager-api` and\n * `storybook/preview-api`: it is bundled into *both* the manager entry (the\n * addon panel) and the blocks entry (the `<Anatomy>` MDX doc block), which\n * run in different runtimes and cannot share either of those APIs. Only the\n * data acquisition differs between the two; the markup must not.\n */\nimport React from 'react';\nimport { useTheme } from 'storybook/theming';\nimport type { AnatomyPartDefinition } from '@component-anatomy/core';\n\n/** Fallback accent when the story sets no `anatomy.theme.accent`. */\nexport const ACCENT_FALLBACK = '#4f46e5';\n\n/**\n * The subset of Storybook's theme this table reads. Typed loosely on purpose:\n * `useTheme()` resolves to an empty `Theme` interface (Emotion augmentation),\n * and outside a ThemeProvider it returns `{}` \u2014 so every read is optional and\n * every value has a literal fallback below.\n */\ntype PartialStorybookTheme = {\n fgColor?: { default?: string; muted?: string };\n bgColor?: { muted?: string };\n borderColor?: { default?: string };\n typography?: { fonts?: { base?: string; mono?: string } };\n};\n\nconst FONT_BASE_FALLBACK =\n '\"Nunito Sans\", -apple-system, \".SFNSText-Regular\", \"San Francisco\", BlinkMacSystemFont, \"Segoe UI\", \"Helvetica Neue\", Helvetica, Arial, sans-serif';\nconst FONT_MONO_FALLBACK = 'ui-monospace, \"Cascadia Code\", \"Fira Mono\", monospace';\n\n/**\n * Resolves the table's chrome colors from Storybook's theme so the same\n * markup reads correctly in the manager panel *and* in a docs page under a\n * dark theme. The accent is intentionally not theme-derived \u2014 it is the\n * addon's identity color and stays stable unless a story overrides it.\n */\nfunction usePalette() {\n const theme = useTheme() as PartialStorybookTheme;\n return {\n text: theme.fgColor?.default,\n muted: theme.fgColor?.muted ?? '#6b7280',\n mutedBg: theme.bgColor?.muted ?? 'rgba(0,0,0,0.06)',\n border: theme.borderColor?.default ?? 'rgba(0,0,0,0.08)',\n fontBase: theme.typography?.fonts?.base ?? FONT_BASE_FALLBACK,\n fontMono: theme.typography?.fonts?.mono ?? FONT_MONO_FALLBACK,\n };\n}\n\ntype Palette = ReturnType<typeof usePalette>;\n\nconst makeStyles = (p: Palette): Record<string, React.CSSProperties> => ({\n container: {\n padding: '12px 16px',\n fontFamily: p.fontBase,\n fontSize: 13,\n lineHeight: 1.5,\n color: p.text,\n },\n empty: {\n color: p.muted,\n margin: 0,\n },\n code: {\n fontFamily: p.fontMono,\n fontSize: '0.85em',\n background: p.mutedBg,\n borderRadius: 3,\n padding: '1px 5px',\n },\n list: {\n display: 'flex',\n flexDirection: 'column',\n gap: 2,\n margin: 0,\n padding: 0,\n listStyle: 'none',\n },\n entry: {\n padding: '8px 10px',\n borderRadius: 6,\n border: '1px solid transparent',\n cursor: 'default',\n outline: 'none',\n transition: 'background 120ms ease, border-color 120ms ease',\n },\n header: {\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n },\n indicator: {\n width: 8,\n height: 8,\n borderRadius: '50%',\n border: `2px solid ${p.border}`,\n flexShrink: 0,\n transition: 'background 120ms ease, border-color 120ms ease',\n },\n name: {\n fontWeight: 700,\n flex: 1,\n },\n id: {\n fontFamily: p.fontMono,\n fontSize: 10,\n padding: '1px 6px',\n borderRadius: 4,\n background: p.mutedBg,\n border: `1px solid ${p.border}`,\n color: p.muted,\n flexShrink: 0,\n },\n description: {\n margin: '4px 0 0',\n paddingLeft: 16,\n color: p.muted,\n },\n});\n\n/**\n * An inline `<code>` styled for the surrounding message text. Exported so\n * both runtimes can compose their own empty-state copy without duplicating\n * the style object.\n */\nexport const AnatomyCode: React.FC<{ children: React.ReactNode }> = ({ children }) => {\n const styles = makeStyles(usePalette());\n return <code style={styles.code}>{children}</code>;\n};\n\n/** A padded, muted paragraph \u2014 used for every \"nothing to show\" state. */\nexport const AnatomyMessage: React.FC<{ children: React.ReactNode }> = ({ children }) => {\n const styles = makeStyles(usePalette());\n return (\n <div style={styles.container}>\n <p style={styles.empty}>{children}</p>\n </div>\n );\n};\n\nexport type AnatomyTableProps = {\n /** Parts to list, in the order they should be shown. */\n parts: AnatomyPartDefinition[];\n /** Id of the part currently highlighted in the canvas, if any. */\n activeId?: string | null;\n /** Accent color for the active state. Defaults to {@link ACCENT_FALLBACK}. */\n accent?: string;\n /** Called when the user hovers or focuses an entry. */\n onItemEnter?: (partId: string) => void;\n /** Called when the user leaves or blurs an entry. */\n onItemLeave?: () => void;\n};\n\nexport const AnatomyTable: React.FC<AnatomyTableProps> = ({\n parts,\n activeId = null,\n accent = ACCENT_FALLBACK,\n onItemEnter,\n onItemLeave,\n}) => {\n const palette = usePalette();\n const styles = makeStyles(palette);\n\n return (\n <div style={styles.container}>\n <ul style={styles.list} role=\"list\" aria-label=\"Anatomy parts\">\n {parts.map((part) => {\n const active = activeId === part.id;\n return (\n <li\n key={part.id}\n role=\"listitem\"\n tabIndex={0}\n aria-label={part.name}\n style={{\n ...styles.entry,\n background: active ? `color-mix(in srgb, ${accent} 7%, transparent)` : undefined,\n borderColor: active\n ? `color-mix(in srgb, ${accent} 20%, transparent)`\n : 'transparent',\n }}\n onMouseEnter={() => onItemEnter?.(part.id)}\n onMouseLeave={() => onItemLeave?.()}\n onFocus={() => onItemEnter?.(part.id)}\n onBlur={() => onItemLeave?.()}\n >\n <div style={styles.header}>\n <span\n aria-hidden=\"true\"\n style={{\n ...styles.indicator,\n background: active ? accent : undefined,\n borderColor: active ? accent : palette.border,\n }}\n />\n <span style={{ ...styles.name, color: active ? accent : undefined }}>\n {part.name}\n </span>\n <code style={styles.id}>{part.id}</code>\n </div>\n {part.description && <p style={styles.description}>{part.description}</p>}\n </li>\n );\n })}\n </ul>\n </div>\n );\n};\n"],
5
+ "mappings": "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",
6
+ "names": ["React", "React", "React", "React"]
7
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"preview.d.ts","sourceRoot":"","sources":["../src/preview.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAMvF,eAAO,MAAM,oBAAoB,YACtB,cAAc,CAAC,QAAQ,CAAC,WACxB,YAAY,CAAC,QAAQ,CAAC,QAyDhC,CAAC;AAEF,eAAO,MAAM,UAAU,iCAAyB,CAAC"}
1
+ {"version":3,"file":"preview.d.ts","sourceRoot":"","sources":["../src/preview.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAQvF,eAAO,MAAM,oBAAoB,YACtB,cAAc,CAAC,QAAQ,CAAC,WACxB,YAAY,CAAC,QAAQ,CAAC,QAwEhC,CAAC;AAEF,eAAO,MAAM,UAAU,iCAAyB,CAAC"}
package/dist/preview.js CHANGED
@@ -7,20 +7,23 @@ var ADDON_ID = "component-anatomy";
7
7
  var PANEL_ID = `${ADDON_ID}/panel`;
8
8
  var PARAM_KEY = "anatomy";
9
9
  var EVENTS = {
10
- /** preview → manager: a part became active in the canvas (hover/programmatic). */
10
+ /** preview → consumers: a part became active in the canvas (hover/programmatic). */
11
11
  PART_ENTER: `${ADDON_ID}/part-enter`,
12
- /** preview → manager: no part is active anymore. */
12
+ /** preview → consumers: no part is active anymore. */
13
13
  PART_LEAVE: `${ADDON_ID}/part-leave`,
14
- /** preview → manager: resolved part list for the current story. */
14
+ /** preview → consumers: resolved part list for a story. */
15
15
  PARTS: `${ADDON_ID}/parts`,
16
- /** manager → preview: the user hovers/focuses a panel entry. */
16
+ /** consumers → preview: the user hovers/focuses a panel entry. */
17
17
  HOVER_ITEM: `${ADDON_ID}/hover-item`,
18
- /** manager → preview: the user left a panel entry. */
18
+ /** consumers → preview: the user left a panel entry. */
19
19
  LEAVE_ITEM: `${ADDON_ID}/leave-item`,
20
- /** manager → preview: the panel mounted and wants the current part list. */
20
+ /** consumers → preview: a panel/block mounted and wants the current part list. */
21
21
  PARTS_REQUEST: `${ADDON_ID}/parts-request`
22
22
  };
23
23
 
24
+ // src/channel.ts
25
+ var matchesStory = (eventStoryId, storyId) => !eventStoryId || !storyId || eventStoryId === storyId;
26
+
24
27
  // src/preview.ts
25
28
  var withComponentAnatomy = (storyFn, context) => {
26
29
  const params = context.parameters?.[PARAM_KEY];
@@ -29,6 +32,7 @@ var withComponentAnatomy = (storyFn, context) => {
29
32
  const channel = addons.getChannel();
30
33
  const canvas = context.canvasElement;
31
34
  if (!canvas) return;
35
+ const storyId = context.id;
32
36
  const root = params.root ? canvas.querySelector(params.root) ?? canvas : canvas;
33
37
  const controller = createAnatomy({
34
38
  root,
@@ -40,25 +44,35 @@ var withComponentAnatomy = (storyFn, context) => {
40
44
  padding: params.overlayPadding
41
45
  }
42
46
  });
43
- const announceParts = () => channel.emit(EVENTS.PARTS, { storyId: context.id, parts: controller.getParts() });
47
+ const announceParts = () => channel.emit(EVENTS.PARTS, { storyId, parts: controller.getParts() });
44
48
  announceParts();
45
49
  const offEnter = controller.on(
46
50
  "part:enter",
47
- (partId) => channel.emit(EVENTS.PART_ENTER, { partId })
51
+ (partId) => channel.emit(EVENTS.PART_ENTER, { storyId, partId })
48
52
  );
49
53
  const offLeave = controller.on(
50
54
  "part:leave",
51
- () => channel.emit(EVENTS.PART_LEAVE, {})
55
+ () => channel.emit(EVENTS.PART_LEAVE, { storyId })
52
56
  );
53
- const onHoverItem = ({ partId }) => controller.highlight(partId);
54
- const onLeaveItem = () => controller.unhighlight();
57
+ const onHoverItem = (event) => {
58
+ if (!matchesStory(event?.storyId, storyId)) return;
59
+ controller.highlight(event.partId);
60
+ };
61
+ const onLeaveItem = (event = {}) => {
62
+ if (!matchesStory(event?.storyId, storyId)) return;
63
+ controller.unhighlight();
64
+ };
65
+ const onPartsRequest = (event = {}) => {
66
+ if (!matchesStory(event?.storyId, storyId)) return;
67
+ announceParts();
68
+ };
55
69
  channel.on(EVENTS.HOVER_ITEM, onHoverItem);
56
70
  channel.on(EVENTS.LEAVE_ITEM, onLeaveItem);
57
- channel.on(EVENTS.PARTS_REQUEST, announceParts);
71
+ channel.on(EVENTS.PARTS_REQUEST, onPartsRequest);
58
72
  return () => {
59
73
  channel.off(EVENTS.HOVER_ITEM, onHoverItem);
60
74
  channel.off(EVENTS.LEAVE_ITEM, onLeaveItem);
61
- channel.off(EVENTS.PARTS_REQUEST, announceParts);
75
+ channel.off(EVENTS.PARTS_REQUEST, onPartsRequest);
62
76
  offEnter();
63
77
  offLeave();
64
78
  controller.destroy();
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/preview.ts", "../src/constants.ts"],
4
- "sourcesContent": ["/**\n * Preview-side (iframe) entry. Registers a global decorator that mounts a\n * component-anatomy controller over the story canvas and syncs hover state\n * with the manager panel over the addon channel.\n */\nimport { addons, useEffect } from 'storybook/preview-api';\nimport type { Renderer, PartialStoryFn, StoryContext } from 'storybook/internal/types';\nimport { createAnatomy } from '@component-anatomy/core';\n\nimport { EVENTS, PARAM_KEY } from './constants.js';\nimport type { AnatomyParameters } from './types.js';\n\nexport const withComponentAnatomy = (\n storyFn: PartialStoryFn<Renderer>,\n context: StoryContext<Renderer>\n) => {\n const params = context.parameters?.[PARAM_KEY] as AnatomyParameters | undefined;\n\n useEffect(() => {\n if (!params || params.disable) return;\n\n const channel = addons.getChannel();\n const canvas = context.canvasElement as unknown as HTMLElement;\n if (!canvas) return;\n\n const root = params.root\n ? canvas.querySelector<HTMLElement>(params.root) ?? canvas\n : canvas;\n\n const controller = createAnatomy({\n root,\n parts: params.parts,\n preset: params.preset,\n theme: params.theme,\n overlay: {\n label: params.overlayLabel !== false,\n padding: params.overlayPadding,\n },\n });\n\n const announceParts = () =>\n channel.emit(EVENTS.PARTS, { storyId: context.id, parts: controller.getParts() });\n\n announceParts();\n\n const offEnter = controller.on('part:enter', (partId) =>\n channel.emit(EVENTS.PART_ENTER, { partId })\n );\n const offLeave = controller.on('part:leave', () =>\n channel.emit(EVENTS.PART_LEAVE, {})\n );\n\n const onHoverItem = ({ partId }: { partId: string }) => controller.highlight(partId);\n const onLeaveItem = () => controller.unhighlight();\n\n channel.on(EVENTS.HOVER_ITEM, onHoverItem);\n channel.on(EVENTS.LEAVE_ITEM, onLeaveItem);\n // The panel may mount after the story rendered \u2014 let it ask for the list.\n channel.on(EVENTS.PARTS_REQUEST, announceParts);\n\n return () => {\n channel.off(EVENTS.HOVER_ITEM, onHoverItem);\n channel.off(EVENTS.LEAVE_ITEM, onLeaveItem);\n channel.off(EVENTS.PARTS_REQUEST, announceParts);\n offEnter();\n offLeave();\n controller.destroy();\n };\n }, [context.id]);\n\n return storyFn();\n};\n\nexport const decorators = [withComponentAnatomy];\n", "export const ADDON_ID = 'component-anatomy';\nexport const PANEL_ID = `${ADDON_ID}/panel`;\n\n/** Story parameter key: `parameters.anatomy = { ... }` */\nexport const PARAM_KEY = 'anatomy';\n\n/** Channel events used to sync the manager panel with the preview iframe. */\nexport const EVENTS = {\n /** preview \u2192 manager: a part became active in the canvas (hover/programmatic). */\n PART_ENTER: `${ADDON_ID}/part-enter`,\n /** preview \u2192 manager: no part is active anymore. */\n PART_LEAVE: `${ADDON_ID}/part-leave`,\n /** preview \u2192 manager: resolved part list for the current story. */\n PARTS: `${ADDON_ID}/parts`,\n /** manager \u2192 preview: the user hovers/focuses a panel entry. */\n HOVER_ITEM: `${ADDON_ID}/hover-item`,\n /** manager \u2192 preview: the user left a panel entry. */\n LEAVE_ITEM: `${ADDON_ID}/leave-item`,\n /** manager \u2192 preview: the panel mounted and wants the current part list. */\n PARTS_REQUEST: `${ADDON_ID}/parts-request`,\n} as const;\n"],
5
- "mappings": ";AAKA,SAAS,QAAQ,iBAAiB;AAElC,SAAS,qBAAqB;;;ACPvB,IAAM,WAAW;AACjB,IAAM,WAAW,GAAG,QAAQ;AAG5B,IAAM,YAAY;AAGlB,IAAM,SAAS;AAAA;AAAA,EAEpB,YAAY,GAAG,QAAQ;AAAA;AAAA,EAEvB,YAAY,GAAG,QAAQ;AAAA;AAAA,EAEvB,OAAO,GAAG,QAAQ;AAAA;AAAA,EAElB,YAAY,GAAG,QAAQ;AAAA;AAAA,EAEvB,YAAY,GAAG,QAAQ;AAAA;AAAA,EAEvB,eAAe,GAAG,QAAQ;AAC5B;;;ADRO,IAAM,uBAAuB,CAClC,SACA,YACG;AACH,QAAM,SAAS,QAAQ,aAAa,SAAS;AAE7C,YAAU,MAAM;AACd,QAAI,CAAC,UAAU,OAAO,QAAS;AAE/B,UAAM,UAAU,OAAO,WAAW;AAClC,UAAM,SAAS,QAAQ;AACvB,QAAI,CAAC,OAAQ;AAEb,UAAM,OAAO,OAAO,OAChB,OAAO,cAA2B,OAAO,IAAI,KAAK,SAClD;AAEJ,UAAM,aAAa,cAAc;AAAA,MAC/B;AAAA,MACA,OAAO,OAAO;AAAA,MACd,QAAQ,OAAO;AAAA,MACf,OAAO,OAAO;AAAA,MACd,SAAS;AAAA,QACP,OAAO,OAAO,iBAAiB;AAAA,QAC/B,SAAS,OAAO;AAAA,MAClB;AAAA,IACF,CAAC;AAED,UAAM,gBAAgB,MACpB,QAAQ,KAAK,OAAO,OAAO,EAAE,SAAS,QAAQ,IAAI,OAAO,WAAW,SAAS,EAAE,CAAC;AAElF,kBAAc;AAEd,UAAM,WAAW,WAAW;AAAA,MAAG;AAAA,MAAc,CAAC,WAC5C,QAAQ,KAAK,OAAO,YAAY,EAAE,OAAO,CAAC;AAAA,IAC5C;AACA,UAAM,WAAW,WAAW;AAAA,MAAG;AAAA,MAAc,MAC3C,QAAQ,KAAK,OAAO,YAAY,CAAC,CAAC;AAAA,IACpC;AAEA,UAAM,cAAc,CAAC,EAAE,OAAO,MAA0B,WAAW,UAAU,MAAM;AACnF,UAAM,cAAc,MAAM,WAAW,YAAY;AAEjD,YAAQ,GAAG,OAAO,YAAY,WAAW;AACzC,YAAQ,GAAG,OAAO,YAAY,WAAW;AAEzC,YAAQ,GAAG,OAAO,eAAe,aAAa;AAE9C,WAAO,MAAM;AACX,cAAQ,IAAI,OAAO,YAAY,WAAW;AAC1C,cAAQ,IAAI,OAAO,YAAY,WAAW;AAC1C,cAAQ,IAAI,OAAO,eAAe,aAAa;AAC/C,eAAS;AACT,eAAS;AACT,iBAAW,QAAQ;AAAA,IACrB;AAAA,EACF,GAAG,CAAC,QAAQ,EAAE,CAAC;AAEf,SAAO,QAAQ;AACjB;AAEO,IAAM,aAAa,CAAC,oBAAoB;",
3
+ "sources": ["../src/preview.ts", "../src/constants.ts", "../src/channel.ts"],
4
+ "sourcesContent": ["/**\n * Preview-side (iframe) entry. Registers a global decorator that mounts a\n * component-anatomy controller over the story canvas and syncs hover state\n * with the manager panel \u2014 and with any `<Anatomy>` doc block on the same\n * docs page \u2014 over the addon channel.\n *\n * The decorator runs in docs view too: the docs `Story` block renders each\n * story through `renderStoryToElement`, which sets `context.canvasElement`\n * exactly as it does in story view. That is what makes auto-discovery and\n * hover sync work inside MDX.\n */\nimport { addons, useEffect } from 'storybook/preview-api';\nimport type { Renderer, PartialStoryFn, StoryContext } from 'storybook/internal/types';\nimport { createAnatomy } from '@component-anatomy/core';\n\nimport { EVENTS, PARAM_KEY } from './constants.js';\nimport { matchesStory } from './channel.js';\nimport type { HoverItemEvent, StoryScopedEvent } from './channel.js';\nimport type { AnatomyParameters } from './types.js';\n\nexport const withComponentAnatomy = (\n storyFn: PartialStoryFn<Renderer>,\n context: StoryContext<Renderer>\n) => {\n const params = context.parameters?.[PARAM_KEY] as AnatomyParameters | undefined;\n\n useEffect(() => {\n if (!params || params.disable) return;\n\n const channel = addons.getChannel();\n const canvas = context.canvasElement as unknown as HTMLElement;\n if (!canvas) return;\n\n const storyId = context.id;\n\n const root = params.root\n ? canvas.querySelector<HTMLElement>(params.root) ?? canvas\n : canvas;\n\n const controller = createAnatomy({\n root,\n parts: params.parts,\n preset: params.preset,\n theme: params.theme,\n overlay: {\n label: params.overlayLabel !== false,\n padding: params.overlayPadding,\n },\n });\n\n const announceParts = () =>\n channel.emit(EVENTS.PARTS, { storyId, parts: controller.getParts() });\n\n announceParts();\n\n const offEnter = controller.on('part:enter', (partId) =>\n channel.emit(EVENTS.PART_ENTER, { storyId, partId })\n );\n const offLeave = controller.on('part:leave', () =>\n channel.emit(EVENTS.PART_LEAVE, { storyId })\n );\n\n // A docs page mounts several stories at once, so every controller sees\n // every panel/block event \u2014 only act on the ones addressed to this story.\n const onHoverItem = (event: HoverItemEvent) => {\n if (!matchesStory(event?.storyId, storyId)) return;\n controller.highlight(event.partId);\n };\n const onLeaveItem = (event: StoryScopedEvent = {}) => {\n if (!matchesStory(event?.storyId, storyId)) return;\n controller.unhighlight();\n };\n const onPartsRequest = (event: StoryScopedEvent = {}) => {\n if (!matchesStory(event?.storyId, storyId)) return;\n announceParts();\n };\n\n channel.on(EVENTS.HOVER_ITEM, onHoverItem);\n channel.on(EVENTS.LEAVE_ITEM, onLeaveItem);\n // The panel or block may mount after the story rendered \u2014 let it ask for\n // the list rather than racing the first announcement.\n channel.on(EVENTS.PARTS_REQUEST, onPartsRequest);\n\n return () => {\n channel.off(EVENTS.HOVER_ITEM, onHoverItem);\n channel.off(EVENTS.LEAVE_ITEM, onLeaveItem);\n channel.off(EVENTS.PARTS_REQUEST, onPartsRequest);\n offEnter();\n offLeave();\n controller.destroy();\n };\n }, [context.id]);\n\n return storyFn();\n};\n\nexport const decorators = [withComponentAnatomy];\n", "export const ADDON_ID = 'component-anatomy';\nexport const PANEL_ID = `${ADDON_ID}/panel`;\n\n/** Story parameter key: `parameters.anatomy = { ... }` */\nexport const PARAM_KEY = 'anatomy';\n\n/**\n * Channel events used to sync the manager panel \u2014 and the `<Anatomy>` MDX doc\n * block, which runs in the preview iframe \u2014 with the story canvas.\n *\n * Every payload carries the `storyId` it concerns; see `channel.ts` for the\n * payload types and the `matchesStory` filter each listener applies.\n */\nexport const EVENTS = {\n /** preview \u2192 consumers: a part became active in the canvas (hover/programmatic). */\n PART_ENTER: `${ADDON_ID}/part-enter`,\n /** preview \u2192 consumers: no part is active anymore. */\n PART_LEAVE: `${ADDON_ID}/part-leave`,\n /** preview \u2192 consumers: resolved part list for a story. */\n PARTS: `${ADDON_ID}/parts`,\n /** consumers \u2192 preview: the user hovers/focuses a panel entry. */\n HOVER_ITEM: `${ADDON_ID}/hover-item`,\n /** consumers \u2192 preview: the user left a panel entry. */\n LEAVE_ITEM: `${ADDON_ID}/leave-item`,\n /** consumers \u2192 preview: a panel/block mounted and wants the current part list. */\n PARTS_REQUEST: `${ADDON_ID}/parts-request`,\n} as const;\n", "/**\n * Shared channel payload contract between the preview decorator, the manager\n * panel, and the MDX doc block.\n *\n * Every payload carries the `storyId` it refers to. In story view this is\n * redundant \u2014 only one story is mounted \u2014 but a docs page mounts *many*\n * stories at once, each with its own controller, and each `<Anatomy>` block\n * must talk to exactly one of them. Without addressing, hovering a part in\n * one block highlights the matching part in every other story on the page.\n */\nimport type { AnatomyPartDefinition } from '@component-anatomy/core';\n\n/** preview \u2192 consumers: the resolved part list for one story. */\nexport type PartsEvent = { storyId?: string; parts: AnatomyPartDefinition[] };\n\n/** preview \u2192 consumers: a part became active in that story's canvas. */\nexport type PartEnterEvent = { storyId?: string; partId: string };\n\n/** consumer \u2192 preview: highlight this part in that story's canvas. */\nexport type HoverItemEvent = { storyId?: string; partId: string };\n\n/** Payload for the events that only need to name a story. */\nexport type StoryScopedEvent = { storyId?: string };\n\n/**\n * Whether an event addressed to `eventStoryId` concerns `storyId`.\n *\n * A missing id on *either* side matches everything. That keeps the protocol\n * backward compatible: a manager panel from a newer build still understands\n * an older preview bundle that emits unaddressed events, and vice versa.\n */\nexport const matchesStory = (\n eventStoryId: string | undefined,\n storyId: string | undefined\n): boolean => !eventStoryId || !storyId || eventStoryId === storyId;\n"],
5
+ "mappings": ";AAWA,SAAS,QAAQ,iBAAiB;AAElC,SAAS,qBAAqB;;;ACbvB,IAAM,WAAW;AACjB,IAAM,WAAW,GAAG,QAAQ;AAG5B,IAAM,YAAY;AASlB,IAAM,SAAS;AAAA;AAAA,EAEpB,YAAY,GAAG,QAAQ;AAAA;AAAA,EAEvB,YAAY,GAAG,QAAQ;AAAA;AAAA,EAEvB,OAAO,GAAG,QAAQ;AAAA;AAAA,EAElB,YAAY,GAAG,QAAQ;AAAA;AAAA,EAEvB,YAAY,GAAG,QAAQ;AAAA;AAAA,EAEvB,eAAe,GAAG,QAAQ;AAC5B;;;ACKO,IAAM,eAAe,CAC1B,cACA,YACY,CAAC,gBAAgB,CAAC,WAAW,iBAAiB;;;AFdrD,IAAM,uBAAuB,CAClC,SACA,YACG;AACH,QAAM,SAAS,QAAQ,aAAa,SAAS;AAE7C,YAAU,MAAM;AACd,QAAI,CAAC,UAAU,OAAO,QAAS;AAE/B,UAAM,UAAU,OAAO,WAAW;AAClC,UAAM,SAAS,QAAQ;AACvB,QAAI,CAAC,OAAQ;AAEb,UAAM,UAAU,QAAQ;AAExB,UAAM,OAAO,OAAO,OAChB,OAAO,cAA2B,OAAO,IAAI,KAAK,SAClD;AAEJ,UAAM,aAAa,cAAc;AAAA,MAC/B;AAAA,MACA,OAAO,OAAO;AAAA,MACd,QAAQ,OAAO;AAAA,MACf,OAAO,OAAO;AAAA,MACd,SAAS;AAAA,QACP,OAAO,OAAO,iBAAiB;AAAA,QAC/B,SAAS,OAAO;AAAA,MAClB;AAAA,IACF,CAAC;AAED,UAAM,gBAAgB,MACpB,QAAQ,KAAK,OAAO,OAAO,EAAE,SAAS,OAAO,WAAW,SAAS,EAAE,CAAC;AAEtE,kBAAc;AAEd,UAAM,WAAW,WAAW;AAAA,MAAG;AAAA,MAAc,CAAC,WAC5C,QAAQ,KAAK,OAAO,YAAY,EAAE,SAAS,OAAO,CAAC;AAAA,IACrD;AACA,UAAM,WAAW,WAAW;AAAA,MAAG;AAAA,MAAc,MAC3C,QAAQ,KAAK,OAAO,YAAY,EAAE,QAAQ,CAAC;AAAA,IAC7C;AAIA,UAAM,cAAc,CAAC,UAA0B;AAC7C,UAAI,CAAC,aAAa,OAAO,SAAS,OAAO,EAAG;AAC5C,iBAAW,UAAU,MAAM,MAAM;AAAA,IACnC;AACA,UAAM,cAAc,CAAC,QAA0B,CAAC,MAAM;AACpD,UAAI,CAAC,aAAa,OAAO,SAAS,OAAO,EAAG;AAC5C,iBAAW,YAAY;AAAA,IACzB;AACA,UAAM,iBAAiB,CAAC,QAA0B,CAAC,MAAM;AACvD,UAAI,CAAC,aAAa,OAAO,SAAS,OAAO,EAAG;AAC5C,oBAAc;AAAA,IAChB;AAEA,YAAQ,GAAG,OAAO,YAAY,WAAW;AACzC,YAAQ,GAAG,OAAO,YAAY,WAAW;AAGzC,YAAQ,GAAG,OAAO,eAAe,cAAc;AAE/C,WAAO,MAAM;AACX,cAAQ,IAAI,OAAO,YAAY,WAAW;AAC1C,cAAQ,IAAI,OAAO,YAAY,WAAW;AAC1C,cAAQ,IAAI,OAAO,eAAe,cAAc;AAChD,eAAS;AACT,eAAS;AACT,iBAAW,QAAQ;AAAA,IACrB;AAAA,EACF,GAAG,CAAC,QAAQ,EAAE,CAAC;AAEf,SAAO,QAAQ;AACjB;AAEO,IAAM,aAAa,CAAC,oBAAoB;",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@component-anatomy/storybook",
3
- "version": "0.0.2",
3
+ "version": "0.1.0",
4
4
  "description": "Storybook addon — interactive component anatomy panel synced with the story canvas",
5
5
  "license": "MIT",
6
6
  "author": "Julien Déramond",
@@ -19,7 +19,9 @@
19
19
  "design-system",
20
20
  "documentation",
21
21
  "anatomy",
22
- "appearance"
22
+ "appearance",
23
+ "mdx",
24
+ "storybook-docs"
23
25
  ],
24
26
  "storybook": {
25
27
  "displayName": "Component Anatomy",
@@ -38,6 +40,10 @@
38
40
  "import": "./dist/index.js",
39
41
  "require": "./dist/index.cjs"
40
42
  },
43
+ "./blocks": {
44
+ "types": "./dist/blocks.d.ts",
45
+ "import": "./dist/blocks.js"
46
+ },
41
47
  "./manager": "./dist/manager.js",
42
48
  "./preview": "./dist/preview.js",
43
49
  "./package.json": "./package.json"
@@ -57,21 +63,33 @@
57
63
  "@component-anatomy/core": "^0.0.1"
58
64
  },
59
65
  "devDependencies": {
60
- "@types/react": "^19.2.17",
66
+ "@storybook/addon-docs": "^10.5.2",
67
+ "@types/react": "^19.2.18",
61
68
  "esbuild": "^0.28.1",
62
- "react": "^19.2.7",
63
- "storybook": "^10.0.0",
69
+ "react": "^19.2.8",
70
+ "react-dom": "^19.2.8",
71
+ "storybook": "^10.5.10",
64
72
  "typescript": "^7.0.2"
65
73
  },
66
74
  "peerDependencies": {
75
+ "@storybook/addon-docs": ">=9.0.0",
76
+ "react": ">=18",
67
77
  "storybook": ">=9.0.0"
68
78
  },
79
+ "peerDependenciesMeta": {
80
+ "@storybook/addon-docs": {
81
+ "optional": true
82
+ },
83
+ "react": {
84
+ "optional": true
85
+ }
86
+ },
69
87
  "engines": {
70
88
  "node": ">=22.12.0"
71
89
  },
72
90
  "scripts": {
73
91
  "build": "node build.mjs",
74
92
  "typecheck": "tsc --noEmit",
75
- "test": "node build.mjs && node ../../scripts/typecheck-fixture.mjs test/consumer-types.ts"
93
+ "test": "node build.mjs && node ../../scripts/typecheck-fixture.mjs test/consumer-types.ts && node ../../scripts/typecheck-fixture.mjs test/consumer-blocks-types.tsx"
76
94
  }
77
95
  }