@component-anatomy/storybook 0.3.0 → 0.5.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/README.md CHANGED
@@ -5,7 +5,7 @@ Storybook addon that adds an **Anatomy** panel — an interactive part list sync
5
5
  - Hover a part in the panel → the element is highlighted in the canvas
6
6
  - Hover a `data-part` element in the canvas → the panel entry activates
7
7
  - The same table renders **inside MDX** via `@component-anatomy/storybook/blocks`
8
- - Works with **Storybook 9 and 10**, any renderer (React, Vue, HTML, Web Components…)
8
+ - Works with **Storybook 10 and 11**, any renderer (React, Vue, HTML, Web Components…) — parts inside open shadow roots included
9
9
 
10
10
  ## Install
11
11
 
@@ -13,6 +13,9 @@ Storybook addon that adds an **Anatomy** panel — an interactive part list sync
13
13
  npm install --save-dev @component-anatomy/storybook
14
14
  ```
15
15
 
16
+ Register the addon in `.storybook/main.ts`. This is what loads the **Anatomy**
17
+ panel into the Storybook manager:
18
+
16
19
  ```ts
17
20
  // .storybook/main.ts
18
21
  export default {
@@ -20,6 +23,34 @@ export default {
20
23
  };
21
24
  ```
22
25
 
26
+ ### If your `preview.ts` uses CSF Next
27
+
28
+ CSF Next is the default story format in Storybook 11. A `preview.ts` built with
29
+ `definePreview` composes **only** the addons it lists, and Storybook drops the
30
+ preview annotations that `main.ts` would otherwise contribute — so the addon
31
+ also has to be registered there, or the canvas decorator never mounts and the
32
+ panel stays empty:
33
+
34
+ ```ts
35
+ // .storybook/preview.ts
36
+
37
+ // Replace your-framework with the framework you are using (e.g. react-vite, nextjs-vite)
38
+ import { definePreview } from '@storybook/your-framework';
39
+ import componentAnatomy from '@component-anatomy/storybook';
40
+
41
+ export default definePreview({
42
+ // ...rest of preview
43
+ addons: [componentAnatomy()], // 👈 register the addon here
44
+ });
45
+ ```
46
+
47
+ Registering in both places is correct and safe: the two paths are mutually
48
+ exclusive, so the decorator is composed exactly once either way. A `preview.ts`
49
+ that is still a plain object needs only the `main.ts` entry above.
50
+
51
+ Doing so also types `parameters.anatomy` across that preview's metas and
52
+ stories, so the shape below is checked for you.
53
+
23
54
  ## Use
24
55
 
25
56
  Annotate your story's DOM with `data-part` and add the `anatomy` parameter:
@@ -39,6 +70,7 @@ export const Anatomy: Story = {
39
70
  theme: { accent: '#0d9488' }, // theme tokens for the canvas overlays
40
71
  overlayLabel: true, // floating name chip
41
72
  overlayPadding: 2, // inflate highlight boxes (px)
73
+ shadowParts: false, // also read native `part` attributes in shadow roots
42
74
  root: '.my-component', // narrow the anatomy root (CSS selector)
43
75
  disable: false, // turn off for a story
44
76
  } satisfies AnatomyParameters,
@@ -48,6 +80,8 @@ export const Anatomy: Story = {
48
80
 
49
81
  Omit `parts` (pass `{}`) and the panel lists parts auto-discovered from `data-part` attributes, with names derived from the ids.
50
82
 
83
+ Web components work as they are: parts are found inside open shadow roots, and the panel updates when a component renders them late (Lit, Stencil) or is defined late. Set `shadowParts: true` to read the anatomy a component already exposes for `::part()` (`part="track"`) instead of adding `data-part`. Closed shadow roots can't be reached.
84
+
51
85
  `preset` and `theme` reach the panel and the `<Anatomy>` block too, not just the canvas overlays: the active row is accented with the same color the overlay paints. Where that color would be illegible on Storybook's own panel — `contrast` is black, the manager is dark by default — the table falls back to the most colorful alternative that meets WCAG AA, so `contrast` accents with its yellow on a dark panel and with black on a light one.
52
86
 
53
87
  Parameters follow Storybook's normal inheritance — project-wide defaults in `.storybook/preview.ts`, per-component in `meta.parameters`, per-story overrides in `story.parameters`.
@@ -113,10 +147,25 @@ Two things worth knowing, for either block:
113
147
 
114
148
  Several blocks can share one page; each talks only to the story it names.
115
149
 
150
+ ## Compatibility
151
+
152
+ | | |
153
+ |---|---|
154
+ | `storybook` | `^10.0.0 \|\| ^11.0.0-0` |
155
+ | `@storybook/addon-docs` | `^10.0.0 \|\| ^11.0.0-0` (optional — only for the MDX blocks) |
156
+ | `react` | `>=18` (optional — only for the MDX blocks) |
157
+ | Node | `>=22.12.0` |
158
+
159
+ The package is ESM-only, like Storybook itself since 9. Storybook 9 is no
160
+ longer supported: CSF Next registration needs `definePreviewAddon`, which
161
+ Storybook only ships from 9.1 onwards, and the addon is built and tested
162
+ against 10 and 11.
163
+
116
164
  ## Example
117
165
 
118
- A complete Storybook 10 setup with Button/Slider/Tabs stories — and two MDX
119
- pages using the `<Anatomy>` block — lives in [`examples/storybook`](https://github.com/julien-deramond/component-anatomy/tree/main/examples/storybook), deployed at https://julien-deramond.github.io/component-anatomy/storybook/.
166
+ A complete Storybook 11 setup with Button/Slider/Tabs stories, web components
167
+ (vanilla, Lit, Shoelace, and Ionic built with Stencil) — and two MDX pages using
168
+ the `<Anatomy>` block — lives in [`examples/storybook`](https://github.com/julien-deramond/component-anatomy/tree/main/examples/storybook), deployed at https://julien-deramond.github.io/component-anatomy/storybook/.
120
169
 
121
170
  ## Docs
122
171
 
package/dist/index.d.ts CHANGED
@@ -1,3 +1,42 @@
1
+ import type { AnatomyParameters } from './types.js';
1
2
  export { ADDON_ID, PANEL_ID, PARAM_KEY, EVENTS } from './constants.js';
2
3
  export type { AnatomyParameters } from './types.js';
4
+ /**
5
+ * What this addon contributes to a CSF Next project's type context: a typed
6
+ * `parameters.anatomy` on every meta and story of a preview that registers it.
7
+ */
8
+ export type ComponentAnatomyTypes = {
9
+ parameters: {
10
+ /** @see {@link AnatomyParameters} */
11
+ anatomy?: AnatomyParameters;
12
+ };
13
+ };
14
+ export default _default;
15
+ /**
16
+ * The addon's preview annotations, for a CSF Next `preview.ts`:
17
+ *
18
+ * ```ts
19
+ * import { definePreview } from '@storybook/your-framework';
20
+ * import componentAnatomy from '@component-anatomy/storybook';
21
+ *
22
+ * export default definePreview({
23
+ * addons: [componentAnatomy()],
24
+ * });
25
+ * ```
26
+ *
27
+ * `.storybook/main.ts` must still list the addon — `addons:
28
+ * ['@component-anatomy/storybook']` — since that is what loads the manager
29
+ * panel. What changes under CSF Next is the preview side: a `preview.ts` built
30
+ * with `definePreview` composes *only* its own `addons`, and Storybook drops
31
+ * every addon annotation main.ts would otherwise have contributed. Without the
32
+ * call below, the canvas decorator never mounts and the panel stays empty.
33
+ *
34
+ * Registering in both places is safe — the two paths are mutually exclusive,
35
+ * so the decorator is composed once either way.
36
+ *
37
+ * The `./blocks` subpath, not this entry, holds the `<Anatomy>` MDX block: it
38
+ * needs React and `@storybook/addon-docs`, both optional peers that must not
39
+ * become load-bearing for a Storybook that only wants the panel.
40
+ */
41
+ declare function _default(): import("storybook/internal/csf").PreviewAddon<ComponentAnatomyTypes>;
3
42
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACvE,YAAY,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACvE,YAAY,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD;;;GAGG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,UAAU,EAAE;QACV,qCAAqC;QACrC,OAAO,CAAC,EAAE,iBAAiB,CAAC;KAC7B,CAAC;CACH,CAAC;;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG"}
package/dist/index.js CHANGED
@@ -1,3 +1,10 @@
1
+ // src/index.ts
2
+ import { definePreviewAddon } from "storybook/internal/csf";
3
+
4
+ // src/preview.ts
5
+ import { addons, useEffect } from "storybook/preview-api";
6
+ import { createAnatomy } from "@component-anatomy/core";
7
+
1
8
  // src/constants.ts
2
9
  var ADDON_ID = "component-anatomy";
3
10
  var PANEL_ID = `${ADDON_ID}/panel`;
@@ -16,10 +23,81 @@ var EVENTS = {
16
23
  /** consumers → preview: a panel/block mounted and wants the current part list. */
17
24
  PARTS_REQUEST: `${ADDON_ID}/parts-request`
18
25
  };
26
+
27
+ // src/channel.ts
28
+ var matchesStory = (eventStoryId, storyId) => !eventStoryId || !storyId || eventStoryId === storyId;
29
+
30
+ // src/preview.ts
31
+ var withComponentAnatomy = (storyFn, context) => {
32
+ const params = context.parameters?.[PARAM_KEY];
33
+ useEffect(() => {
34
+ if (!params || params.disable) return;
35
+ const channel = addons.getChannel();
36
+ const canvas = context.canvasElement;
37
+ if (!canvas) return;
38
+ const storyId = context.id;
39
+ const root = params.root ? canvas.querySelector(params.root) ?? canvas : canvas;
40
+ const controller = createAnatomy({
41
+ root,
42
+ parts: params.parts,
43
+ shadowParts: params.shadowParts,
44
+ preset: params.preset,
45
+ theme: params.theme,
46
+ overlay: {
47
+ label: params.overlayLabel !== false,
48
+ padding: params.overlayPadding
49
+ }
50
+ });
51
+ const announceParts = () => channel.emit(EVENTS.PARTS, { storyId, parts: controller.getParts() });
52
+ announceParts();
53
+ const offChange = controller.on("parts:change", announceParts);
54
+ const offEnter = controller.on(
55
+ "part:enter",
56
+ (partId) => channel.emit(EVENTS.PART_ENTER, { storyId, partId })
57
+ );
58
+ const offLeave = controller.on(
59
+ "part:leave",
60
+ () => channel.emit(EVENTS.PART_LEAVE, { storyId })
61
+ );
62
+ const onHoverItem = (event) => {
63
+ if (!matchesStory(event?.storyId, storyId)) return;
64
+ controller.highlight(event.partId);
65
+ };
66
+ const onLeaveItem = (event = {}) => {
67
+ if (!matchesStory(event?.storyId, storyId)) return;
68
+ controller.unhighlight();
69
+ };
70
+ const onPartsRequest = (event = {}) => {
71
+ if (!matchesStory(event?.storyId, storyId)) return;
72
+ announceParts();
73
+ };
74
+ channel.on(EVENTS.HOVER_ITEM, onHoverItem);
75
+ channel.on(EVENTS.LEAVE_ITEM, onLeaveItem);
76
+ channel.on(EVENTS.PARTS_REQUEST, onPartsRequest);
77
+ return () => {
78
+ channel.off(EVENTS.HOVER_ITEM, onHoverItem);
79
+ channel.off(EVENTS.LEAVE_ITEM, onLeaveItem);
80
+ channel.off(EVENTS.PARTS_REQUEST, onPartsRequest);
81
+ offChange();
82
+ offEnter();
83
+ offLeave();
84
+ controller.destroy();
85
+ };
86
+ }, [context.id]);
87
+ return storyFn();
88
+ };
89
+ var annotations = {
90
+ decorators: [withComponentAnatomy]
91
+ };
92
+ var preview_default = annotations;
93
+
94
+ // src/index.ts
95
+ var index_default = () => definePreviewAddon(preview_default);
19
96
  export {
20
97
  ADDON_ID,
21
98
  EVENTS,
22
99
  PANEL_ID,
23
- PARAM_KEY
100
+ PARAM_KEY,
101
+ index_default as default
24
102
  };
25
103
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/constants.ts"],
4
- "sourcesContent": ["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"],
5
- "mappings": ";AAAO,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;",
3
+ "sources": ["../src/index.ts", "../src/preview.ts", "../src/constants.ts", "../src/channel.ts"],
4
+ "sourcesContent": ["import { definePreviewAddon } from 'storybook/internal/csf';\n\nimport annotations from './preview.js';\nimport type { AnatomyParameters } from './types.js';\n\nexport { ADDON_ID, PANEL_ID, PARAM_KEY, EVENTS } from './constants.js';\nexport type { AnatomyParameters } from './types.js';\n\n/**\n * What this addon contributes to a CSF Next project's type context: a typed\n * `parameters.anatomy` on every meta and story of a preview that registers it.\n */\nexport type ComponentAnatomyTypes = {\n parameters: {\n /** @see {@link AnatomyParameters} */\n anatomy?: AnatomyParameters;\n };\n};\n\n/**\n * The addon's preview annotations, for a CSF Next `preview.ts`:\n *\n * ```ts\n * import { definePreview } from '@storybook/your-framework';\n * import componentAnatomy from '@component-anatomy/storybook';\n *\n * export default definePreview({\n * addons: [componentAnatomy()],\n * });\n * ```\n *\n * `.storybook/main.ts` must still list the addon \u2014 `addons:\n * ['@component-anatomy/storybook']` \u2014 since that is what loads the manager\n * panel. What changes under CSF Next is the preview side: a `preview.ts` built\n * with `definePreview` composes *only* its own `addons`, and Storybook drops\n * every addon annotation main.ts would otherwise have contributed. Without the\n * call below, the canvas decorator never mounts and the panel stays empty.\n *\n * Registering in both places is safe \u2014 the two paths are mutually exclusive,\n * so the decorator is composed once either way.\n *\n * The `./blocks` subpath, not this entry, holds the `<Anatomy>` MDX block: it\n * needs React and `@storybook/addon-docs`, both optional peers that must not\n * become load-bearing for a Storybook that only wants the panel.\n */\nexport default () => definePreviewAddon<ComponentAnatomyTypes>(annotations);\n", "/**\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 {\n ProjectAnnotations,\n Renderer,\n PartialStoryFn,\n StoryContext,\n} 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 shadowParts: params.shadowParts,\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 // Parts can show up after this effect ran: a web component renders its\n // shadow root asynchronously (Lit, Stencil), or is defined late.\n const offChange = controller.on('parts:change', 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 offChange();\n offEnter();\n offLeave();\n controller.destroy();\n };\n }, [context.id]);\n\n return storyFn();\n};\n\nexport const decorators = [withComponentAnatomy];\n\n/**\n * The same annotations as a default export, which is the shape\n * `definePreviewAddon` takes in the package's main entry (see `index.ts`) and\n * the shape a consumer gets from `@component-anatomy/storybook/preview`.\n *\n * Storybook reads `module.default[field] ?? module[field]`, so a preview\n * annotation module that exports both is read exactly once \u2014 the named\n * `decorators` above stays for anyone importing it directly.\n */\nconst annotations: ProjectAnnotations<Renderer> = {\n decorators: [withComponentAnatomy],\n};\n\nexport default annotations;\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": ";AAAA,SAAS,0BAA0B;;;ACWnC,SAAS,QAAQ,iBAAiB;AAOlC,SAAS,qBAAqB;;;AClBvB,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;;;AFTrD,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,aAAa,OAAO;AAAA,MACpB,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;AAGd,UAAM,YAAY,WAAW,GAAG,gBAAgB,aAAa;AAE7D,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,gBAAU;AACV,eAAS;AACT,eAAS;AACT,iBAAW,QAAQ;AAAA,IACrB;AAAA,EACF,GAAG,CAAC,QAAQ,EAAE,CAAC;AAEf,SAAO,QAAQ;AACjB;AAaA,IAAM,cAA4C;AAAA,EAChD,YAAY,CAAC,oBAAoB;AACnC;AAEA,IAAO,kBAAQ;;;AD5Ef,IAAO,gBAAQ,MAAM,mBAA0C,eAAW;",
6
6
  "names": []
7
7
  }
package/dist/preview.d.ts CHANGED
@@ -1,4 +1,15 @@
1
- import type { Renderer, PartialStoryFn, StoryContext } from 'storybook/internal/types';
1
+ import type { ProjectAnnotations, Renderer, PartialStoryFn, StoryContext } from 'storybook/internal/types';
2
2
  export declare const withComponentAnatomy: (storyFn: PartialStoryFn<Renderer>, context: StoryContext<Renderer>) => any;
3
3
  export declare const decorators: (typeof withComponentAnatomy)[];
4
+ /**
5
+ * The same annotations as a default export, which is the shape
6
+ * `definePreviewAddon` takes in the package's main entry (see `index.ts`) and
7
+ * the shape a consumer gets from `@component-anatomy/storybook/preview`.
8
+ *
9
+ * Storybook reads `module.default[field] ?? module[field]`, so a preview
10
+ * annotation module that exports both is read exactly once — the named
11
+ * `decorators` above stays for anyone importing it directly.
12
+ */
13
+ declare const annotations: ProjectAnnotations<Renderer>;
14
+ export default annotations;
4
15
  //# sourceMappingURL=preview.d.ts.map
@@ -1 +1 @@
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"}
1
+ {"version":3,"file":"preview.d.ts","sourceRoot":"","sources":["../src/preview.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EACV,kBAAkB,EAClB,QAAQ,EACR,cAAc,EACd,YAAY,EACb,MAAM,0BAA0B,CAAC;AAQlC,eAAO,MAAM,oBAAoB,YACtB,cAAc,CAAC,QAAQ,CAAC,WACxB,YAAY,CAAC,QAAQ,CAAC,QA6EhC,CAAC;AAEF,eAAO,MAAM,UAAU,iCAAyB,CAAC;AAEjD;;;;;;;;GAQG;AACH,QAAA,MAAM,WAAW,EAAE,kBAAkB,CAAC,QAAQ,CAE7C,CAAC;eAEa,WAAW"}
package/dist/preview.js CHANGED
@@ -37,6 +37,7 @@ var withComponentAnatomy = (storyFn, context) => {
37
37
  const controller = createAnatomy({
38
38
  root,
39
39
  parts: params.parts,
40
+ shadowParts: params.shadowParts,
40
41
  preset: params.preset,
41
42
  theme: params.theme,
42
43
  overlay: {
@@ -46,6 +47,7 @@ var withComponentAnatomy = (storyFn, context) => {
46
47
  });
47
48
  const announceParts = () => channel.emit(EVENTS.PARTS, { storyId, parts: controller.getParts() });
48
49
  announceParts();
50
+ const offChange = controller.on("parts:change", announceParts);
49
51
  const offEnter = controller.on(
50
52
  "part:enter",
51
53
  (partId) => channel.emit(EVENTS.PART_ENTER, { storyId, partId })
@@ -73,6 +75,7 @@ var withComponentAnatomy = (storyFn, context) => {
73
75
  channel.off(EVENTS.HOVER_ITEM, onHoverItem);
74
76
  channel.off(EVENTS.LEAVE_ITEM, onLeaveItem);
75
77
  channel.off(EVENTS.PARTS_REQUEST, onPartsRequest);
78
+ offChange();
76
79
  offEnter();
77
80
  offLeave();
78
81
  controller.destroy();
@@ -81,8 +84,13 @@ var withComponentAnatomy = (storyFn, context) => {
81
84
  return storyFn();
82
85
  };
83
86
  var decorators = [withComponentAnatomy];
87
+ var annotations = {
88
+ decorators: [withComponentAnatomy]
89
+ };
90
+ var preview_default = annotations;
84
91
  export {
85
92
  decorators,
93
+ preview_default as default,
86
94
  withComponentAnatomy
87
95
  };
88
96
  //# sourceMappingURL=preview.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
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;",
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 {\n ProjectAnnotations,\n Renderer,\n PartialStoryFn,\n StoryContext,\n} 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 shadowParts: params.shadowParts,\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 // Parts can show up after this effect ran: a web component renders its\n // shadow root asynchronously (Lit, Stencil), or is defined late.\n const offChange = controller.on('parts:change', 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 offChange();\n offEnter();\n offLeave();\n controller.destroy();\n };\n }, [context.id]);\n\n return storyFn();\n};\n\nexport const decorators = [withComponentAnatomy];\n\n/**\n * The same annotations as a default export, which is the shape\n * `definePreviewAddon` takes in the package's main entry (see `index.ts`) and\n * the shape a consumer gets from `@component-anatomy/storybook/preview`.\n *\n * Storybook reads `module.default[field] ?? module[field]`, so a preview\n * annotation module that exports both is read exactly once \u2014 the named\n * `decorators` above stays for anyone importing it directly.\n */\nconst annotations: ProjectAnnotations<Renderer> = {\n decorators: [withComponentAnatomy],\n};\n\nexport default annotations;\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;AAOlC,SAAS,qBAAqB;;;AClBvB,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;;;AFTrD,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,aAAa,OAAO;AAAA,MACpB,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;AAGd,UAAM,YAAY,WAAW,GAAG,gBAAgB,aAAa;AAE7D,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,gBAAU;AACV,eAAS;AACT,eAAS;AACT,iBAAW,QAAQ;AAAA,IACrB;AAAA,EACF,GAAG,CAAC,QAAQ,EAAE,CAAC;AAEf,SAAO,QAAQ;AACjB;AAEO,IAAM,aAAa,CAAC,oBAAoB;AAW/C,IAAM,cAA4C;AAAA,EAChD,YAAY,CAAC,oBAAoB;AACnC;AAEA,IAAO,kBAAQ;",
6
6
  "names": []
7
7
  }
package/dist/types.d.ts CHANGED
@@ -17,7 +17,8 @@ import type { AnatomyPartDefinition, AnatomyPresetName, AnatomyTheme } from '@co
17
17
  export type AnatomyParameters = {
18
18
  /**
19
19
  * Part definitions. If omitted, parts are auto-discovered from
20
- * `data-part` attributes in the rendered story.
20
+ * `data-part` attributes in the rendered story, including inside open
21
+ * shadow roots.
21
22
  */
22
23
  parts?: AnatomyPartDefinition[];
23
24
  /** Named visual preset for the canvas overlays. Default: 'default'. */
@@ -28,6 +29,11 @@ export type AnatomyParameters = {
28
29
  overlayLabel?: boolean;
29
30
  /** Inflate highlight boxes by N pixels. Default: 0. */
30
31
  overlayPadding?: number;
32
+ /**
33
+ * Also treat the native `part` attribute (CSS Shadow Parts) on elements
34
+ * inside a web component's open shadow root as a part id. Default: false.
35
+ */
36
+ shadowParts?: boolean;
31
37
  /**
32
38
  * CSS selector to narrow the anatomy root inside the story canvas.
33
39
  * Defaults to the whole canvas element.
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,qBAAqB,EACrB,iBAAiB,EACjB,YAAY,EACb,MAAM,yBAAyB,CAAC;AAEjC;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;OAGG;IACH,KAAK,CAAC,EAAE,qBAAqB,EAAE,CAAC;IAChC,uEAAuE;IACvE,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,4DAA4D;IAC5D,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,sEAAsE;IACtE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,uDAAuD;IACvD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,qBAAqB,EACrB,iBAAiB,EACjB,YAAY,EACb,MAAM,yBAAyB,CAAC;AAEjC;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;;OAIG;IACH,KAAK,CAAC,EAAE,qBAAqB,EAAE,CAAC;IAChC,uEAAuE;IACvE,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,4DAA4D;IAC5D,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,sEAAsE;IACtE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,uDAAuD;IACvD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@component-anatomy/storybook",
3
- "version": "0.3.0",
3
+ "version": "0.5.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",
@@ -37,18 +37,23 @@
37
37
  "exports": {
38
38
  ".": {
39
39
  "types": "./dist/index.d.ts",
40
- "import": "./dist/index.js",
41
- "require": "./dist/index.cjs"
40
+ "default": "./dist/index.js"
42
41
  },
43
42
  "./blocks": {
44
43
  "types": "./dist/blocks.d.ts",
45
- "import": "./dist/blocks.js"
44
+ "default": "./dist/blocks.js"
45
+ },
46
+ "./manager": {
47
+ "types": "./dist/manager.d.ts",
48
+ "default": "./dist/manager.js"
49
+ },
50
+ "./preview": {
51
+ "types": "./dist/preview.d.ts",
52
+ "default": "./dist/preview.js"
46
53
  },
47
- "./manager": "./dist/manager.js",
48
- "./preview": "./dist/preview.js",
49
54
  "./package.json": "./package.json"
50
55
  },
51
- "main": "./dist/index.cjs",
56
+ "main": "./dist/index.js",
52
57
  "module": "./dist/index.js",
53
58
  "types": "./dist/index.d.ts",
54
59
  "files": [
@@ -60,21 +65,21 @@
60
65
  "access": "public"
61
66
  },
62
67
  "dependencies": {
63
- "@component-anatomy/core": "^0.1.0"
68
+ "@component-anatomy/core": "^0.2.0"
64
69
  },
65
70
  "devDependencies": {
66
- "@storybook/addon-docs": "^10.5.2",
67
- "@types/react": "^19.2.18",
71
+ "@storybook/addon-docs": "11.0.0-alpha.1",
72
+ "@types/react": "^19.3.0",
68
73
  "esbuild": "^0.28.2",
69
- "react": "^19.2.8",
70
- "react-dom": "^19.2.8",
71
- "storybook": "^10.5.10",
74
+ "react": "^19.3.0",
75
+ "react-dom": "^19.3.0",
76
+ "storybook": "11.0.0-alpha.1",
72
77
  "typescript": "^7.0.2"
73
78
  },
74
79
  "peerDependencies": {
75
- "@storybook/addon-docs": ">=9.0.0",
80
+ "@storybook/addon-docs": "^10.0.0 || ^11.0.0-0",
76
81
  "react": ">=18",
77
- "storybook": ">=9.0.0"
82
+ "storybook": "^10.0.0 || ^11.0.0-0"
78
83
  },
79
84
  "peerDependenciesMeta": {
80
85
  "@storybook/addon-docs": {
@@ -90,6 +95,6 @@
90
95
  "scripts": {
91
96
  "build": "node build.mjs",
92
97
  "typecheck": "tsc --noEmit",
93
- "test": "node build.mjs && node ../../scripts/typecheck-fixture.mjs test/consumer-types.ts && node ../../scripts/typecheck-fixture.mjs test/consumer-blocks-types.tsx"
98
+ "test": "node build.mjs && node ../../scripts/typecheck-fixture.mjs test/consumer-types.ts && node ../../scripts/typecheck-fixture.mjs test/consumer-blocks-types.tsx && node ../../scripts/typecheck-fixture.mjs test/consumer-csf-next-types.ts"
94
99
  }
95
100
  }
package/src/index.ts CHANGED
@@ -1,7 +1,46 @@
1
+ import { definePreviewAddon } from 'storybook/internal/csf';
2
+
3
+ import annotations from './preview.js';
4
+ import type { AnatomyParameters } from './types.js';
5
+
1
6
  export { ADDON_ID, PANEL_ID, PARAM_KEY, EVENTS } from './constants.js';
2
7
  export type { AnatomyParameters } from './types.js';
3
8
 
4
- // The `<Anatomy>` doc block lives in the `./blocks` subpath, not here: this
5
- // entry is loaded at config time by `.storybook/main.ts` (and built to CJS),
6
- // while the block needs React and `@storybook/addon-docs`, both optional
7
- // peers that must not become load-bearing for `addons: ['...']` to work.
9
+ /**
10
+ * What this addon contributes to a CSF Next project's type context: a typed
11
+ * `parameters.anatomy` on every meta and story of a preview that registers it.
12
+ */
13
+ export type ComponentAnatomyTypes = {
14
+ parameters: {
15
+ /** @see {@link AnatomyParameters} */
16
+ anatomy?: AnatomyParameters;
17
+ };
18
+ };
19
+
20
+ /**
21
+ * The addon's preview annotations, for a CSF Next `preview.ts`:
22
+ *
23
+ * ```ts
24
+ * import { definePreview } from '@storybook/your-framework';
25
+ * import componentAnatomy from '@component-anatomy/storybook';
26
+ *
27
+ * export default definePreview({
28
+ * addons: [componentAnatomy()],
29
+ * });
30
+ * ```
31
+ *
32
+ * `.storybook/main.ts` must still list the addon — `addons:
33
+ * ['@component-anatomy/storybook']` — since that is what loads the manager
34
+ * panel. What changes under CSF Next is the preview side: a `preview.ts` built
35
+ * with `definePreview` composes *only* its own `addons`, and Storybook drops
36
+ * every addon annotation main.ts would otherwise have contributed. Without the
37
+ * call below, the canvas decorator never mounts and the panel stays empty.
38
+ *
39
+ * Registering in both places is safe — the two paths are mutually exclusive,
40
+ * so the decorator is composed once either way.
41
+ *
42
+ * The `./blocks` subpath, not this entry, holds the `<Anatomy>` MDX block: it
43
+ * needs React and `@storybook/addon-docs`, both optional peers that must not
44
+ * become load-bearing for a Storybook that only wants the panel.
45
+ */
46
+ export default () => definePreviewAddon<ComponentAnatomyTypes>(annotations);
package/src/preview.ts CHANGED
@@ -10,7 +10,12 @@
10
10
  * hover sync work inside MDX.
11
11
  */
12
12
  import { addons, useEffect } from 'storybook/preview-api';
13
- import type { Renderer, PartialStoryFn, StoryContext } from 'storybook/internal/types';
13
+ import type {
14
+ ProjectAnnotations,
15
+ Renderer,
16
+ PartialStoryFn,
17
+ StoryContext,
18
+ } from 'storybook/internal/types';
14
19
  import { createAnatomy } from '@component-anatomy/core';
15
20
 
16
21
  import { EVENTS, PARAM_KEY } from './constants.js';
@@ -40,6 +45,7 @@ export const withComponentAnatomy = (
40
45
  const controller = createAnatomy({
41
46
  root,
42
47
  parts: params.parts,
48
+ shadowParts: params.shadowParts,
43
49
  preset: params.preset,
44
50
  theme: params.theme,
45
51
  overlay: {
@@ -52,6 +58,9 @@ export const withComponentAnatomy = (
52
58
  channel.emit(EVENTS.PARTS, { storyId, parts: controller.getParts() });
53
59
 
54
60
  announceParts();
61
+ // Parts can show up after this effect ran: a web component renders its
62
+ // shadow root asynchronously (Lit, Stencil), or is defined late.
63
+ const offChange = controller.on('parts:change', announceParts);
55
64
 
56
65
  const offEnter = controller.on('part:enter', (partId) =>
57
66
  channel.emit(EVENTS.PART_ENTER, { storyId, partId })
@@ -85,6 +94,7 @@ export const withComponentAnatomy = (
85
94
  channel.off(EVENTS.HOVER_ITEM, onHoverItem);
86
95
  channel.off(EVENTS.LEAVE_ITEM, onLeaveItem);
87
96
  channel.off(EVENTS.PARTS_REQUEST, onPartsRequest);
97
+ offChange();
88
98
  offEnter();
89
99
  offLeave();
90
100
  controller.destroy();
@@ -95,3 +105,18 @@ export const withComponentAnatomy = (
95
105
  };
96
106
 
97
107
  export const decorators = [withComponentAnatomy];
108
+
109
+ /**
110
+ * The same annotations as a default export, which is the shape
111
+ * `definePreviewAddon` takes in the package's main entry (see `index.ts`) and
112
+ * the shape a consumer gets from `@component-anatomy/storybook/preview`.
113
+ *
114
+ * Storybook reads `module.default[field] ?? module[field]`, so a preview
115
+ * annotation module that exports both is read exactly once — the named
116
+ * `decorators` above stays for anyone importing it directly.
117
+ */
118
+ const annotations: ProjectAnnotations<Renderer> = {
119
+ decorators: [withComponentAnatomy],
120
+ };
121
+
122
+ export default annotations;
package/src/types.ts CHANGED
@@ -22,7 +22,8 @@ import type {
22
22
  export type AnatomyParameters = {
23
23
  /**
24
24
  * Part definitions. If omitted, parts are auto-discovered from
25
- * `data-part` attributes in the rendered story.
25
+ * `data-part` attributes in the rendered story, including inside open
26
+ * shadow roots.
26
27
  */
27
28
  parts?: AnatomyPartDefinition[];
28
29
  /** Named visual preset for the canvas overlays. Default: 'default'. */
@@ -33,6 +34,11 @@ export type AnatomyParameters = {
33
34
  overlayLabel?: boolean;
34
35
  /** Inflate highlight boxes by N pixels. Default: 0. */
35
36
  overlayPadding?: number;
37
+ /**
38
+ * Also treat the native `part` attribute (CSS Shadow Parts) on elements
39
+ * inside a web component's open shadow root as a part id. Default: false.
40
+ */
41
+ shadowParts?: boolean;
36
42
  /**
37
43
  * CSS selector to narrow the anatomy root inside the story canvas.
38
44
  * Defaults to the whole canvas element.
package/dist/index.cjs DELETED
@@ -1,48 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/index.ts
21
- var index_exports = {};
22
- __export(index_exports, {
23
- ADDON_ID: () => ADDON_ID,
24
- EVENTS: () => EVENTS,
25
- PANEL_ID: () => PANEL_ID,
26
- PARAM_KEY: () => PARAM_KEY
27
- });
28
- module.exports = __toCommonJS(index_exports);
29
-
30
- // src/constants.ts
31
- var ADDON_ID = "component-anatomy";
32
- var PANEL_ID = `${ADDON_ID}/panel`;
33
- var PARAM_KEY = "anatomy";
34
- var EVENTS = {
35
- /** preview → consumers: a part became active in the canvas (hover/programmatic). */
36
- PART_ENTER: `${ADDON_ID}/part-enter`,
37
- /** preview → consumers: no part is active anymore. */
38
- PART_LEAVE: `${ADDON_ID}/part-leave`,
39
- /** preview → consumers: resolved part list for a story. */
40
- PARTS: `${ADDON_ID}/parts`,
41
- /** consumers → preview: the user hovers/focuses a panel entry. */
42
- HOVER_ITEM: `${ADDON_ID}/hover-item`,
43
- /** consumers → preview: the user left a panel entry. */
44
- LEAVE_ITEM: `${ADDON_ID}/leave-item`,
45
- /** consumers → preview: a panel/block mounted and wants the current part list. */
46
- PARTS_REQUEST: `${ADDON_ID}/parts-request`
47
- };
48
- //# sourceMappingURL=index.cjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/index.ts", "../src/constants.ts"],
4
- "sourcesContent": ["export { ADDON_ID, PANEL_ID, PARAM_KEY, EVENTS } from './constants.js';\nexport type { AnatomyParameters } from './types.js';\n\n// The `<Anatomy>` doc block lives in the `./blocks` subpath, not here: this\n// entry is loaded at config time by `.storybook/main.ts` (and built to CJS),\n// while the block needs React and `@storybook/addon-docs`, both optional\n// peers that must not become load-bearing for `addons: ['...']` to work.\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"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAO,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;",
6
- "names": []
7
- }