@component-anatomy/storybook 0.0.1 → 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/README.md +42 -1
- package/dist/AnatomyTable.d.ts +39 -0
- package/dist/AnatomyTable.d.ts.map +1 -0
- package/dist/Panel.d.ts +3 -0
- package/dist/Panel.d.ts.map +1 -0
- package/dist/blocks.d.ts +48 -0
- package/dist/blocks.d.ts.map +1 -0
- package/dist/blocks.js +242 -0
- package/dist/blocks.js.map +7 -0
- package/dist/channel.d.ts +39 -0
- package/dist/channel.d.ts.map +1 -0
- package/dist/constants.d.ts +26 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/index.cjs +9 -9
- package/dist/index.cjs.map +2 -2
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -6
- package/dist/index.js.map +2 -2
- package/dist/manager.d.ts +2 -0
- package/dist/manager.d.ts.map +1 -0
- package/dist/manager.js +114 -50
- package/dist/manager.js.map +4 -4
- package/dist/preview.d.ts +4 -0
- package/dist/preview.d.ts.map +1 -0
- package/dist/preview.js +27 -13
- package/dist/preview.js.map +3 -3
- package/dist/types.d.ts +39 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +28 -9
- package/src/AnatomyTable.tsx +210 -0
- package/src/Panel.tsx +39 -130
- package/src/blocks.tsx +187 -0
- package/src/channel.ts +35 -0
- package/src/constants.ts +13 -7
- package/src/index.ts +5 -0
- package/src/preview.ts +32 -9
package/README.md
CHANGED
|
@@ -4,6 +4,7 @@ Storybook addon that adds an **Anatomy** panel — an interactive part list sync
|
|
|
4
4
|
|
|
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
|
+
- The same table renders **inside MDX** via `@component-anatomy/storybook/blocks`
|
|
7
8
|
- Works with **Storybook 9 and 10**, any renderer (React, Vue, HTML, Web Components…)
|
|
8
9
|
|
|
9
10
|
## Install
|
|
@@ -49,9 +50,49 @@ Omit `parts` (pass `{}`) and the panel lists parts auto-discovered from `data-pa
|
|
|
49
50
|
|
|
50
51
|
Parameters follow Storybook's normal inheritance — project-wide defaults in `.storybook/preview.ts`, per-component in `meta.parameters`, per-story overrides in `story.parameters`.
|
|
51
52
|
|
|
53
|
+
## In MDX
|
|
54
|
+
|
|
55
|
+
The panel's table also renders inline in a docs page, so anatomy can sit in the
|
|
56
|
+
prose next to the preview. Requires `@storybook/addon-docs` (the addon that
|
|
57
|
+
renders MDX), which stays an optional peer dependency — the panel above works
|
|
58
|
+
without it.
|
|
59
|
+
|
|
60
|
+
```mdx
|
|
61
|
+
import { Canvas, Meta } from '@storybook/addon-docs/blocks';
|
|
62
|
+
import { Anatomy } from '@component-anatomy/storybook/blocks';
|
|
63
|
+
|
|
64
|
+
import * as ButtonStories from './Button.stories';
|
|
65
|
+
|
|
66
|
+
<Meta of={ButtonStories} />
|
|
67
|
+
|
|
68
|
+
<Canvas of={ButtonStories.Anatomy} />
|
|
69
|
+
<Anatomy of={ButtonStories.Anatomy} />
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Hover sync works both ways, exactly as in the panel.
|
|
73
|
+
|
|
74
|
+
| Prop | Type | Description |
|
|
75
|
+
|---|---|---|
|
|
76
|
+
| `of` | CSF export | The story to document, or a whole CSF module to read the meta's parameters. Omit on an attached docs page (one with `<Meta of={…} />`) to fall back to the page's current story. |
|
|
77
|
+
| `parts` | `AnatomyPartDefinition[]` | Curated list, overriding both `parameters.anatomy.parts` and auto-discovery. |
|
|
78
|
+
| `sync` | `boolean` | Two-way hover sync with the rendered story. Default `true`. `false` gives a purely static table. |
|
|
79
|
+
|
|
80
|
+
Two things worth knowing:
|
|
81
|
+
|
|
82
|
+
- **Auto-discovery needs the story on the page.** Parts are read from the story's
|
|
83
|
+
`data-part` attributes as it renders, so a block that relies on discovery needs
|
|
84
|
+
a `<Canvas of={…} />` (or `<Story of={…} />`) on the same page. A block with an
|
|
85
|
+
explicit `parts` list stands on its own.
|
|
86
|
+
- **A meta has no canvas.** `of={ButtonStories}` reads `meta.parameters.anatomy`,
|
|
87
|
+
but there is nothing to discover parts from or to sync hover with — give it
|
|
88
|
+
`parts` explicitly.
|
|
89
|
+
|
|
90
|
+
Several blocks can share one page; each talks only to the story it names.
|
|
91
|
+
|
|
52
92
|
## Example
|
|
53
93
|
|
|
54
|
-
A complete Storybook 10 setup with Button/Slider/Tabs stories
|
|
94
|
+
A complete Storybook 10 setup with Button/Slider/Tabs stories — and two MDX
|
|
95
|
+
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/.
|
|
55
96
|
|
|
56
97
|
## Docs
|
|
57
98
|
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The anatomy part table — pure presentation, no Storybook imports.
|
|
3
|
+
*
|
|
4
|
+
* This module is deliberately free of `storybook/manager-api` and
|
|
5
|
+
* `storybook/preview-api`: it is bundled into *both* the manager entry (the
|
|
6
|
+
* addon panel) and the blocks entry (the `<Anatomy>` MDX doc block), which
|
|
7
|
+
* run in different runtimes and cannot share either of those APIs. Only the
|
|
8
|
+
* data acquisition differs between the two; the markup must not.
|
|
9
|
+
*/
|
|
10
|
+
import React from 'react';
|
|
11
|
+
import type { AnatomyPartDefinition } from '@component-anatomy/core';
|
|
12
|
+
/** Fallback accent when the story sets no `anatomy.theme.accent`. */
|
|
13
|
+
export declare const ACCENT_FALLBACK = "#4f46e5";
|
|
14
|
+
/**
|
|
15
|
+
* An inline `<code>` styled for the surrounding message text. Exported so
|
|
16
|
+
* both runtimes can compose their own empty-state copy without duplicating
|
|
17
|
+
* the style object.
|
|
18
|
+
*/
|
|
19
|
+
export declare const AnatomyCode: React.FC<{
|
|
20
|
+
children: React.ReactNode;
|
|
21
|
+
}>;
|
|
22
|
+
/** A padded, muted paragraph — used for every "nothing to show" state. */
|
|
23
|
+
export declare const AnatomyMessage: React.FC<{
|
|
24
|
+
children: React.ReactNode;
|
|
25
|
+
}>;
|
|
26
|
+
export type AnatomyTableProps = {
|
|
27
|
+
/** Parts to list, in the order they should be shown. */
|
|
28
|
+
parts: AnatomyPartDefinition[];
|
|
29
|
+
/** Id of the part currently highlighted in the canvas, if any. */
|
|
30
|
+
activeId?: string | null;
|
|
31
|
+
/** Accent color for the active state. Defaults to {@link ACCENT_FALLBACK}. */
|
|
32
|
+
accent?: string;
|
|
33
|
+
/** Called when the user hovers or focuses an entry. */
|
|
34
|
+
onItemEnter?: (partId: string) => void;
|
|
35
|
+
/** Called when the user leaves or blurs an entry. */
|
|
36
|
+
onItemLeave?: () => void;
|
|
37
|
+
};
|
|
38
|
+
export declare const AnatomyTable: React.FC<AnatomyTableProps>;
|
|
39
|
+
//# sourceMappingURL=AnatomyTable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AnatomyTable.d.ts","sourceRoot":"","sources":["../src/AnatomyTable.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAErE,qEAAqE;AACrE,eAAO,MAAM,eAAe,YAAY,CAAC;AA4GzC;;;;GAIG;AACH,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,CAG/D,CAAC;AAEF,0EAA0E;AAC1E,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,CAOlE,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,wDAAwD;IACxD,KAAK,EAAE,qBAAqB,EAAE,CAAC;IAC/B,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,8EAA8E;IAC9E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uDAAuD;IACvD,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,qDAAqD;IACrD,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;CAC1B,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAsDpD,CAAC"}
|
package/dist/Panel.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Panel.d.ts","sourceRoot":"","sources":["../src/Panel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAUnD,eAAO,MAAM,KAAK,EAAE,KAAK,CAAC,EAkEzB,CAAC"}
|
package/dist/blocks.d.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Docs blocks entry — the `<Anatomy>` block for MDX pages.
|
|
3
|
+
*
|
|
4
|
+
* Unlike the addon panel, this runs in the **preview iframe**, where
|
|
5
|
+
* `storybook/manager-api` does not exist. It reaches the story's controller
|
|
6
|
+
* over the addon channel instead: `Channel.emit` dispatches to local
|
|
7
|
+
* listeners as well as across transports, so a block and the decorator that
|
|
8
|
+
* mounted the story talk to each other directly, in-frame, with no extra
|
|
9
|
+
* plumbing.
|
|
10
|
+
*
|
|
11
|
+
* ```mdx
|
|
12
|
+
* import { Meta, Canvas } from '@storybook/addon-docs/blocks';
|
|
13
|
+
* import { Anatomy } from '@component-anatomy/storybook/blocks';
|
|
14
|
+
* import * as ButtonStories from './Button.stories';
|
|
15
|
+
*
|
|
16
|
+
* <Meta of={ButtonStories} />
|
|
17
|
+
*
|
|
18
|
+
* <Canvas of={ButtonStories.Anatomy} />
|
|
19
|
+
* <Anatomy of={ButtonStories.Anatomy} />
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
import React from 'react';
|
|
23
|
+
import type { Of } from '@storybook/addon-docs/blocks';
|
|
24
|
+
import type { AnatomyPartDefinition } from '@component-anatomy/core';
|
|
25
|
+
export type AnatomyBlockProps = {
|
|
26
|
+
/**
|
|
27
|
+
* The CSF export to document — a story export, or the whole module export
|
|
28
|
+
* of a CSF file to read the meta's parameters.
|
|
29
|
+
*
|
|
30
|
+
* Omit it on an attached docs page (one with `<Meta of={...} />`, or an
|
|
31
|
+
* autodocs page) to fall back to the page's current story, mirroring how
|
|
32
|
+
* the other docs blocks resolve `of`.
|
|
33
|
+
*/
|
|
34
|
+
of?: Of;
|
|
35
|
+
/**
|
|
36
|
+
* Part list override. Skips both `parameters.anatomy.parts` and
|
|
37
|
+
* auto-discovery — useful for a hand-curated subset in prose.
|
|
38
|
+
*/
|
|
39
|
+
parts?: AnatomyPartDefinition[];
|
|
40
|
+
/**
|
|
41
|
+
* Two-way hover sync with the rendered story. Default: `true`. Set to
|
|
42
|
+
* `false` for a purely static table (also skips auto-discovery, since that
|
|
43
|
+
* arrives over the channel).
|
|
44
|
+
*/
|
|
45
|
+
sync?: boolean;
|
|
46
|
+
};
|
|
47
|
+
export declare const Anatomy: React.FC<AnatomyBlockProps>;
|
|
48
|
+
//# sourceMappingURL=blocks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blocks.d.ts","sourceRoot":"","sources":["../src/blocks.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAA8B,MAAM,OAAO,CAAC;AAGnD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,8BAA8B,CAAC;AACvD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAQrE,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;;;;;OAOG;IACH,EAAE,CAAC,EAAE,EAAE,CAAC;IACR;;;OAGG;IACH,KAAK,CAAC,EAAE,qBAAqB,EAAE,CAAC;IAChC;;;;OAIG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAgBF,eAAO,MAAM,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAoH/C,CAAC"}
|
package/dist/blocks.js
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
// src/blocks.tsx
|
|
2
|
+
import React2, { useEffect, useState } from "react";
|
|
3
|
+
import { addons } from "storybook/preview-api";
|
|
4
|
+
import { Unstyled, useOf } from "@storybook/addon-docs/blocks";
|
|
5
|
+
|
|
6
|
+
// src/constants.ts
|
|
7
|
+
var ADDON_ID = "component-anatomy";
|
|
8
|
+
var PANEL_ID = `${ADDON_ID}/panel`;
|
|
9
|
+
var PARAM_KEY = "anatomy";
|
|
10
|
+
var EVENTS = {
|
|
11
|
+
/** preview → consumers: a part became active in the canvas (hover/programmatic). */
|
|
12
|
+
PART_ENTER: `${ADDON_ID}/part-enter`,
|
|
13
|
+
/** preview → consumers: no part is active anymore. */
|
|
14
|
+
PART_LEAVE: `${ADDON_ID}/part-leave`,
|
|
15
|
+
/** preview → consumers: resolved part list for a story. */
|
|
16
|
+
PARTS: `${ADDON_ID}/parts`,
|
|
17
|
+
/** consumers → preview: the user hovers/focuses a panel entry. */
|
|
18
|
+
HOVER_ITEM: `${ADDON_ID}/hover-item`,
|
|
19
|
+
/** consumers → preview: the user left a panel entry. */
|
|
20
|
+
LEAVE_ITEM: `${ADDON_ID}/leave-item`,
|
|
21
|
+
/** consumers → preview: a panel/block mounted and wants the current part list. */
|
|
22
|
+
PARTS_REQUEST: `${ADDON_ID}/parts-request`
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// src/channel.ts
|
|
26
|
+
var matchesStory = (eventStoryId, storyId) => !eventStoryId || !storyId || eventStoryId === storyId;
|
|
27
|
+
|
|
28
|
+
// src/AnatomyTable.tsx
|
|
29
|
+
import React from "react";
|
|
30
|
+
import { useTheme } from "storybook/theming";
|
|
31
|
+
var ACCENT_FALLBACK = "#4f46e5";
|
|
32
|
+
var FONT_BASE_FALLBACK = '"Nunito Sans", -apple-system, ".SFNSText-Regular", "San Francisco", BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Helvetica, Arial, sans-serif';
|
|
33
|
+
var FONT_MONO_FALLBACK = 'ui-monospace, "Cascadia Code", "Fira Mono", monospace';
|
|
34
|
+
function usePalette() {
|
|
35
|
+
const theme = useTheme();
|
|
36
|
+
return {
|
|
37
|
+
text: theme.fgColor?.default,
|
|
38
|
+
muted: theme.fgColor?.muted ?? "#6b7280",
|
|
39
|
+
mutedBg: theme.bgColor?.muted ?? "rgba(0,0,0,0.06)",
|
|
40
|
+
border: theme.borderColor?.default ?? "rgba(0,0,0,0.08)",
|
|
41
|
+
fontBase: theme.typography?.fonts?.base ?? FONT_BASE_FALLBACK,
|
|
42
|
+
fontMono: theme.typography?.fonts?.mono ?? FONT_MONO_FALLBACK
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
var makeStyles = (p) => ({
|
|
46
|
+
container: {
|
|
47
|
+
padding: "12px 16px",
|
|
48
|
+
fontFamily: p.fontBase,
|
|
49
|
+
fontSize: 13,
|
|
50
|
+
lineHeight: 1.5,
|
|
51
|
+
color: p.text
|
|
52
|
+
},
|
|
53
|
+
empty: {
|
|
54
|
+
color: p.muted,
|
|
55
|
+
margin: 0
|
|
56
|
+
},
|
|
57
|
+
code: {
|
|
58
|
+
fontFamily: p.fontMono,
|
|
59
|
+
fontSize: "0.85em",
|
|
60
|
+
background: p.mutedBg,
|
|
61
|
+
borderRadius: 3,
|
|
62
|
+
padding: "1px 5px"
|
|
63
|
+
},
|
|
64
|
+
list: {
|
|
65
|
+
display: "flex",
|
|
66
|
+
flexDirection: "column",
|
|
67
|
+
gap: 2,
|
|
68
|
+
margin: 0,
|
|
69
|
+
padding: 0,
|
|
70
|
+
listStyle: "none"
|
|
71
|
+
},
|
|
72
|
+
entry: {
|
|
73
|
+
padding: "8px 10px",
|
|
74
|
+
borderRadius: 6,
|
|
75
|
+
border: "1px solid transparent",
|
|
76
|
+
cursor: "default",
|
|
77
|
+
outline: "none",
|
|
78
|
+
transition: "background 120ms ease, border-color 120ms ease"
|
|
79
|
+
},
|
|
80
|
+
header: {
|
|
81
|
+
display: "flex",
|
|
82
|
+
alignItems: "center",
|
|
83
|
+
gap: 8
|
|
84
|
+
},
|
|
85
|
+
indicator: {
|
|
86
|
+
width: 8,
|
|
87
|
+
height: 8,
|
|
88
|
+
borderRadius: "50%",
|
|
89
|
+
border: `2px solid ${p.border}`,
|
|
90
|
+
flexShrink: 0,
|
|
91
|
+
transition: "background 120ms ease, border-color 120ms ease"
|
|
92
|
+
},
|
|
93
|
+
name: {
|
|
94
|
+
fontWeight: 700,
|
|
95
|
+
flex: 1
|
|
96
|
+
},
|
|
97
|
+
id: {
|
|
98
|
+
fontFamily: p.fontMono,
|
|
99
|
+
fontSize: 10,
|
|
100
|
+
padding: "1px 6px",
|
|
101
|
+
borderRadius: 4,
|
|
102
|
+
background: p.mutedBg,
|
|
103
|
+
border: `1px solid ${p.border}`,
|
|
104
|
+
color: p.muted,
|
|
105
|
+
flexShrink: 0
|
|
106
|
+
},
|
|
107
|
+
description: {
|
|
108
|
+
margin: "4px 0 0",
|
|
109
|
+
paddingLeft: 16,
|
|
110
|
+
color: p.muted
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
var AnatomyCode = ({ children }) => {
|
|
114
|
+
const styles = makeStyles(usePalette());
|
|
115
|
+
return /* @__PURE__ */ React.createElement("code", { style: styles.code }, children);
|
|
116
|
+
};
|
|
117
|
+
var AnatomyMessage = ({ children }) => {
|
|
118
|
+
const styles = makeStyles(usePalette());
|
|
119
|
+
return /* @__PURE__ */ React.createElement("div", { style: styles.container }, /* @__PURE__ */ React.createElement("p", { style: styles.empty }, children));
|
|
120
|
+
};
|
|
121
|
+
var AnatomyTable = ({
|
|
122
|
+
parts,
|
|
123
|
+
activeId = null,
|
|
124
|
+
accent = ACCENT_FALLBACK,
|
|
125
|
+
onItemEnter,
|
|
126
|
+
onItemLeave
|
|
127
|
+
}) => {
|
|
128
|
+
const palette = usePalette();
|
|
129
|
+
const styles = makeStyles(palette);
|
|
130
|
+
return /* @__PURE__ */ React.createElement("div", { style: styles.container }, /* @__PURE__ */ React.createElement("ul", { style: styles.list, role: "list", "aria-label": "Anatomy parts" }, parts.map((part) => {
|
|
131
|
+
const active = activeId === part.id;
|
|
132
|
+
return /* @__PURE__ */ React.createElement(
|
|
133
|
+
"li",
|
|
134
|
+
{
|
|
135
|
+
key: part.id,
|
|
136
|
+
role: "listitem",
|
|
137
|
+
tabIndex: 0,
|
|
138
|
+
"aria-label": part.name,
|
|
139
|
+
style: {
|
|
140
|
+
...styles.entry,
|
|
141
|
+
background: active ? `color-mix(in srgb, ${accent} 7%, transparent)` : void 0,
|
|
142
|
+
borderColor: active ? `color-mix(in srgb, ${accent} 20%, transparent)` : "transparent"
|
|
143
|
+
},
|
|
144
|
+
onMouseEnter: () => onItemEnter?.(part.id),
|
|
145
|
+
onMouseLeave: () => onItemLeave?.(),
|
|
146
|
+
onFocus: () => onItemEnter?.(part.id),
|
|
147
|
+
onBlur: () => onItemLeave?.()
|
|
148
|
+
},
|
|
149
|
+
/* @__PURE__ */ React.createElement("div", { style: styles.header }, /* @__PURE__ */ React.createElement(
|
|
150
|
+
"span",
|
|
151
|
+
{
|
|
152
|
+
"aria-hidden": "true",
|
|
153
|
+
style: {
|
|
154
|
+
...styles.indicator,
|
|
155
|
+
background: active ? accent : void 0,
|
|
156
|
+
borderColor: active ? accent : palette.border
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
), /* @__PURE__ */ React.createElement("span", { style: { ...styles.name, color: active ? accent : void 0 } }, part.name), /* @__PURE__ */ React.createElement("code", { style: styles.id }, part.id)),
|
|
160
|
+
part.description && /* @__PURE__ */ React.createElement("p", { style: styles.description }, part.description)
|
|
161
|
+
);
|
|
162
|
+
})));
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
// src/blocks.tsx
|
|
166
|
+
function getChannelSafely() {
|
|
167
|
+
try {
|
|
168
|
+
return addons.getChannel();
|
|
169
|
+
} catch {
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
var Anatomy = ({ of, parts: partsProp, sync = true }) => {
|
|
174
|
+
const resolved = useOf(of ?? "story", ["story", "meta"]);
|
|
175
|
+
const params = resolved.type === "meta" ? resolved.preparedMeta.parameters?.[PARAM_KEY] : resolved.story.parameters?.[PARAM_KEY];
|
|
176
|
+
const storyId = resolved.type === "story" ? resolved.story.id : void 0;
|
|
177
|
+
const [discovered, setDiscovered] = useState([]);
|
|
178
|
+
const [activeId, setActiveId] = useState(null);
|
|
179
|
+
const staticParts = partsProp ?? params?.parts;
|
|
180
|
+
const wired = sync && !!storyId;
|
|
181
|
+
useEffect(() => {
|
|
182
|
+
setDiscovered([]);
|
|
183
|
+
setActiveId(null);
|
|
184
|
+
if (!wired) return;
|
|
185
|
+
const channel = getChannelSafely();
|
|
186
|
+
if (!channel) return;
|
|
187
|
+
const onParts = (event) => {
|
|
188
|
+
if (!matchesStory(event?.storyId, storyId)) return;
|
|
189
|
+
setDiscovered(event.parts);
|
|
190
|
+
};
|
|
191
|
+
const onEnter = (event) => {
|
|
192
|
+
if (!matchesStory(event?.storyId, storyId)) return;
|
|
193
|
+
setActiveId(event.partId);
|
|
194
|
+
};
|
|
195
|
+
const onLeave = (event = {}) => {
|
|
196
|
+
if (!matchesStory(event?.storyId, storyId)) return;
|
|
197
|
+
setActiveId(null);
|
|
198
|
+
};
|
|
199
|
+
channel.on(EVENTS.PARTS, onParts);
|
|
200
|
+
channel.on(EVENTS.PART_ENTER, onEnter);
|
|
201
|
+
channel.on(EVENTS.PART_LEAVE, onLeave);
|
|
202
|
+
channel.emit(EVENTS.PARTS_REQUEST, { storyId });
|
|
203
|
+
return () => {
|
|
204
|
+
channel.off(EVENTS.PARTS, onParts);
|
|
205
|
+
channel.off(EVENTS.PART_ENTER, onEnter);
|
|
206
|
+
channel.off(EVENTS.PART_LEAVE, onLeave);
|
|
207
|
+
};
|
|
208
|
+
}, [wired, storyId]);
|
|
209
|
+
const parts = staticParts ?? discovered;
|
|
210
|
+
const accent = params?.theme?.accent ?? ACCENT_FALLBACK;
|
|
211
|
+
const emitHover = (partId) => {
|
|
212
|
+
if (!wired) return;
|
|
213
|
+
getChannelSafely()?.emit(EVENTS.HOVER_ITEM, { storyId, partId });
|
|
214
|
+
};
|
|
215
|
+
const emitLeave = () => {
|
|
216
|
+
if (!wired) return;
|
|
217
|
+
getChannelSafely()?.emit(EVENTS.LEAVE_ITEM, { storyId });
|
|
218
|
+
};
|
|
219
|
+
if (!params && !partsProp) {
|
|
220
|
+
return /* @__PURE__ */ React2.createElement(Unstyled, null, /* @__PURE__ */ React2.createElement(AnatomyMessage, null, "No anatomy configured. Add ", /* @__PURE__ */ React2.createElement(AnatomyCode, null, "parameters.anatomy"), " to the story you pass to ", /* @__PURE__ */ React2.createElement(AnatomyCode, null, "of"), ", or pass a", " ", /* @__PURE__ */ React2.createElement(AnatomyCode, null, "parts"), " list to this block."));
|
|
221
|
+
}
|
|
222
|
+
if (params?.disable && !partsProp) {
|
|
223
|
+
return /* @__PURE__ */ React2.createElement(Unstyled, null, /* @__PURE__ */ React2.createElement(AnatomyMessage, null, "Anatomy is disabled for this story (", /* @__PURE__ */ React2.createElement(AnatomyCode, null, "anatomy.disable"), ")."));
|
|
224
|
+
}
|
|
225
|
+
if (parts.length === 0) {
|
|
226
|
+
return /* @__PURE__ */ React2.createElement(Unstyled, null, /* @__PURE__ */ React2.createElement(AnatomyMessage, null, resolved.type === "meta" ? "No parts found. A meta has no canvas to discover parts from \u2014 pass a story to `of`, or list `parts` explicitly." : "No parts found. Auto-discovery reads the rendered story, so make sure it is on this page (e.g. with a `<Canvas of={\u2026} />` block above), or list `parts` explicitly."));
|
|
227
|
+
}
|
|
228
|
+
return /* @__PURE__ */ React2.createElement(Unstyled, null, /* @__PURE__ */ React2.createElement(
|
|
229
|
+
AnatomyTable,
|
|
230
|
+
{
|
|
231
|
+
parts,
|
|
232
|
+
activeId,
|
|
233
|
+
accent,
|
|
234
|
+
onItemEnter: emitHover,
|
|
235
|
+
onItemLeave: emitLeave
|
|
236
|
+
}
|
|
237
|
+
));
|
|
238
|
+
};
|
|
239
|
+
export {
|
|
240
|
+
Anatomy
|
|
241
|
+
};
|
|
242
|
+
//# sourceMappingURL=blocks.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/blocks.tsx", "../src/constants.ts", "../src/channel.ts", "../src/AnatomyTable.tsx"],
|
|
4
|
+
"sourcesContent": ["/**\n * Docs blocks entry \u2014 the `<Anatomy>` block for MDX pages.\n *\n * Unlike the addon panel, this runs in the **preview iframe**, where\n * `storybook/manager-api` does not exist. It reaches the story's controller\n * over the addon channel instead: `Channel.emit` dispatches to local\n * listeners as well as across transports, so a block and the decorator that\n * mounted the story talk to each other directly, in-frame, with no extra\n * plumbing.\n *\n * ```mdx\n * import { Meta, Canvas } from '@storybook/addon-docs/blocks';\n * import { Anatomy } from '@component-anatomy/storybook/blocks';\n * import * as ButtonStories from './Button.stories';\n *\n * <Meta of={ButtonStories} />\n *\n * <Canvas of={ButtonStories.Anatomy} />\n * <Anatomy of={ButtonStories.Anatomy} />\n * ```\n */\nimport React, { useEffect, useState } from 'react';\nimport { addons } from 'storybook/preview-api';\nimport { Unstyled, useOf } from '@storybook/addon-docs/blocks';\nimport type { Of } from '@storybook/addon-docs/blocks';\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 type AnatomyBlockProps = {\n /**\n * The CSF export to document \u2014 a story export, or the whole module export\n * of a CSF file to read the meta's parameters.\n *\n * Omit it on an attached docs page (one with `<Meta of={...} />`, or an\n * autodocs page) to fall back to the page's current story, mirroring how\n * the other docs blocks resolve `of`.\n */\n of?: Of;\n /**\n * Part list override. Skips both `parameters.anatomy.parts` and\n * auto-discovery \u2014 useful for a hand-curated subset in prose.\n */\n parts?: AnatomyPartDefinition[];\n /**\n * Two-way hover sync with the rendered story. Default: `true`. Set to\n * `false` for a purely static table (also skips auto-discovery, since that\n * arrives over the channel).\n */\n sync?: boolean;\n};\n\n/**\n * `addons.getChannel()` throws when no channel is installed. That should not\n * happen inside a rendered docs page, but an MDX page is user-authored\n * content and a throw here would blank the whole page \u2014 degrade to a static\n * table instead.\n */\nfunction getChannelSafely() {\n try {\n return addons.getChannel();\n } catch {\n return null;\n }\n}\n\nexport const Anatomy: React.FC<AnatomyBlockProps> = ({ of, parts: partsProp, sync = true }) => {\n const resolved = useOf(of ?? 'story', ['story', 'meta']);\n\n const params = (\n resolved.type === 'meta'\n ? resolved.preparedMeta.parameters?.[PARAM_KEY]\n : resolved.story.parameters?.[PARAM_KEY]\n ) as AnatomyParameters | undefined;\n\n // Only a story has a canvas to sync with. `of={SomeStories}` (a meta)\n // documents the component as a whole and can render static parts only.\n const storyId = resolved.type === 'story' ? resolved.story.id : undefined;\n\n const [discovered, setDiscovered] = useState<AnatomyPartDefinition[]>([]);\n const [activeId, setActiveId] = useState<string | null>(null);\n\n const staticParts = partsProp ?? params?.parts;\n // Hover sync is wired even when the parts are static \u2014 an explicit list\n // still wants the canvas to light up. Only discovery depends on the channel.\n const wired = sync && !!storyId;\n\n useEffect(() => {\n setDiscovered([]);\n setActiveId(null);\n if (!wired) return;\n\n const channel = getChannelSafely();\n if (!channel) return;\n\n const onParts = (event: PartsEvent) => {\n if (!matchesStory(event?.storyId, storyId)) return;\n setDiscovered(event.parts);\n };\n const onEnter = (event: PartEnterEvent) => {\n if (!matchesStory(event?.storyId, storyId)) return;\n setActiveId(event.partId);\n };\n const onLeave = (event: StoryScopedEvent = {}) => {\n if (!matchesStory(event?.storyId, storyId)) return;\n setActiveId(null);\n };\n\n channel.on(EVENTS.PARTS, onParts);\n channel.on(EVENTS.PART_ENTER, onEnter);\n channel.on(EVENTS.PART_LEAVE, onLeave);\n\n // The block usually mounts before the story below it finishes rendering;\n // the request covers the other order.\n channel.emit(EVENTS.PARTS_REQUEST, { storyId } satisfies StoryScopedEvent);\n\n return () => {\n channel.off(EVENTS.PARTS, onParts);\n channel.off(EVENTS.PART_ENTER, onEnter);\n channel.off(EVENTS.PART_LEAVE, onLeave);\n };\n }, [wired, storyId]);\n\n const parts = staticParts ?? discovered;\n const accent = params?.theme?.accent ?? ACCENT_FALLBACK;\n\n const emitHover = (partId: string) => {\n if (!wired) return;\n getChannelSafely()?.emit(EVENTS.HOVER_ITEM, { storyId, partId });\n };\n const emitLeave = () => {\n if (!wired) return;\n getChannelSafely()?.emit(EVENTS.LEAVE_ITEM, { storyId } satisfies StoryScopedEvent);\n };\n\n // `Unstyled` keeps the docs page's prose CSS (`.sbdocs` restyles ul/li/p/\n // code) from reaching the table.\n if (!params && !partsProp) {\n return (\n <Unstyled>\n <AnatomyMessage>\n No anatomy configured. Add <AnatomyCode>parameters.anatomy</AnatomyCode> to the story you\n pass to <AnatomyCode>of</AnatomyCode>, or pass a{' '}\n <AnatomyCode>parts</AnatomyCode> list to this block.\n </AnatomyMessage>\n </Unstyled>\n );\n }\n\n if (params?.disable && !partsProp) {\n return (\n <Unstyled>\n <AnatomyMessage>\n Anatomy is disabled for this story (<AnatomyCode>anatomy.disable</AnatomyCode>).\n </AnatomyMessage>\n </Unstyled>\n );\n }\n\n if (parts.length === 0) {\n return (\n <Unstyled>\n <AnatomyMessage>\n {resolved.type === 'meta'\n ? 'No parts found. A meta has no canvas to discover parts from \u2014 pass a story to `of`, or list `parts` explicitly.'\n : 'No parts found. Auto-discovery reads the rendered story, so make sure it is on this page (e.g. with a `<Canvas of={\u2026} />` block above), or list `parts` explicitly.'}\n </AnatomyMessage>\n </Unstyled>\n );\n }\n\n return (\n <Unstyled>\n <AnatomyTable\n parts={parts}\n activeId={activeId}\n accent={accent}\n onItemEnter={emitHover}\n onItemLeave={emitLeave}\n />\n </Unstyled>\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", "/**\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"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared channel payload contract between the preview decorator, the manager
|
|
3
|
+
* panel, and the MDX doc block.
|
|
4
|
+
*
|
|
5
|
+
* Every payload carries the `storyId` it refers to. In story view this is
|
|
6
|
+
* redundant — only one story is mounted — but a docs page mounts *many*
|
|
7
|
+
* stories at once, each with its own controller, and each `<Anatomy>` block
|
|
8
|
+
* must talk to exactly one of them. Without addressing, hovering a part in
|
|
9
|
+
* one block highlights the matching part in every other story on the page.
|
|
10
|
+
*/
|
|
11
|
+
import type { AnatomyPartDefinition } from '@component-anatomy/core';
|
|
12
|
+
/** preview → consumers: the resolved part list for one story. */
|
|
13
|
+
export type PartsEvent = {
|
|
14
|
+
storyId?: string;
|
|
15
|
+
parts: AnatomyPartDefinition[];
|
|
16
|
+
};
|
|
17
|
+
/** preview → consumers: a part became active in that story's canvas. */
|
|
18
|
+
export type PartEnterEvent = {
|
|
19
|
+
storyId?: string;
|
|
20
|
+
partId: string;
|
|
21
|
+
};
|
|
22
|
+
/** consumer → preview: highlight this part in that story's canvas. */
|
|
23
|
+
export type HoverItemEvent = {
|
|
24
|
+
storyId?: string;
|
|
25
|
+
partId: string;
|
|
26
|
+
};
|
|
27
|
+
/** Payload for the events that only need to name a story. */
|
|
28
|
+
export type StoryScopedEvent = {
|
|
29
|
+
storyId?: string;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Whether an event addressed to `eventStoryId` concerns `storyId`.
|
|
33
|
+
*
|
|
34
|
+
* A missing id on *either* side matches everything. That keeps the protocol
|
|
35
|
+
* backward compatible: a manager panel from a newer build still understands
|
|
36
|
+
* an older preview bundle that emits unaddressed events, and vice versa.
|
|
37
|
+
*/
|
|
38
|
+
export declare const matchesStory: (eventStoryId: string | undefined, storyId: string | undefined) => boolean;
|
|
39
|
+
//# sourceMappingURL=channel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAErE,iEAAiE;AACjE,MAAM,MAAM,UAAU,GAAG;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,qBAAqB,EAAE,CAAA;CAAE,CAAC;AAE9E,wEAAwE;AACxE,MAAM,MAAM,cAAc,GAAG;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAElE,sEAAsE;AACtE,MAAM,MAAM,cAAc,GAAG;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAElE,6DAA6D;AAC7D,MAAM,MAAM,gBAAgB,GAAG;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpD;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,iBACT,MAAM,GAAG,SAAS,WACvB,MAAM,GAAG,SAAS,KAC1B,OAAgE,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export declare const ADDON_ID = "component-anatomy";
|
|
2
|
+
export declare const PANEL_ID = "component-anatomy/panel";
|
|
3
|
+
/** Story parameter key: `parameters.anatomy = { ... }` */
|
|
4
|
+
export declare const PARAM_KEY = "anatomy";
|
|
5
|
+
/**
|
|
6
|
+
* Channel events used to sync the manager panel — and the `<Anatomy>` MDX doc
|
|
7
|
+
* block, which runs in the preview iframe — with the story canvas.
|
|
8
|
+
*
|
|
9
|
+
* Every payload carries the `storyId` it concerns; see `channel.ts` for the
|
|
10
|
+
* payload types and the `matchesStory` filter each listener applies.
|
|
11
|
+
*/
|
|
12
|
+
export declare const EVENTS: {
|
|
13
|
+
/** preview → consumers: a part became active in the canvas (hover/programmatic). */
|
|
14
|
+
readonly PART_ENTER: "component-anatomy/part-enter";
|
|
15
|
+
/** preview → consumers: no part is active anymore. */
|
|
16
|
+
readonly PART_LEAVE: "component-anatomy/part-leave";
|
|
17
|
+
/** preview → consumers: resolved part list for a story. */
|
|
18
|
+
readonly PARTS: "component-anatomy/parts";
|
|
19
|
+
/** consumers → preview: the user hovers/focuses a panel entry. */
|
|
20
|
+
readonly HOVER_ITEM: "component-anatomy/hover-item";
|
|
21
|
+
/** consumers → preview: the user left a panel entry. */
|
|
22
|
+
readonly LEAVE_ITEM: "component-anatomy/leave-item";
|
|
23
|
+
/** consumers → preview: a panel/block mounted and wants the current part list. */
|
|
24
|
+
readonly PARTS_REQUEST: "component-anatomy/parts-request";
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,QAAQ,sBAAsB,CAAC;AAC5C,eAAO,MAAM,QAAQ,4BAAsB,CAAC;AAE5C,0DAA0D;AAC1D,eAAO,MAAM,SAAS,YAAY,CAAC;AAEnC;;;;;;GAMG;AACH,eAAO,MAAM,MAAM;IACjB,oFAAoF;aACpF,UAAU;IACV,sDAAsD;aACtD,UAAU;IACV,2DAA2D;aAC3D,KAAK;IACL,kEAAkE;aAClE,UAAU;IACV,wDAAwD;aACxD,UAAU;IACV,kFAAkF;aAClF,aAAa;CACL,CAAC"}
|
package/dist/index.cjs
CHANGED
|
@@ -18,31 +18,31 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
|
|
20
20
|
// src/index.ts
|
|
21
|
-
var
|
|
22
|
-
__export(
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
23
|
ADDON_ID: () => ADDON_ID,
|
|
24
24
|
EVENTS: () => EVENTS,
|
|
25
25
|
PANEL_ID: () => PANEL_ID,
|
|
26
26
|
PARAM_KEY: () => PARAM_KEY
|
|
27
27
|
});
|
|
28
|
-
module.exports = __toCommonJS(
|
|
28
|
+
module.exports = __toCommonJS(index_exports);
|
|
29
29
|
|
|
30
30
|
// src/constants.ts
|
|
31
31
|
var ADDON_ID = "component-anatomy";
|
|
32
32
|
var PANEL_ID = `${ADDON_ID}/panel`;
|
|
33
33
|
var PARAM_KEY = "anatomy";
|
|
34
34
|
var EVENTS = {
|
|
35
|
-
/** preview →
|
|
35
|
+
/** preview → consumers: a part became active in the canvas (hover/programmatic). */
|
|
36
36
|
PART_ENTER: `${ADDON_ID}/part-enter`,
|
|
37
|
-
/** preview →
|
|
37
|
+
/** preview → consumers: no part is active anymore. */
|
|
38
38
|
PART_LEAVE: `${ADDON_ID}/part-leave`,
|
|
39
|
-
/** preview →
|
|
39
|
+
/** preview → consumers: resolved part list for a story. */
|
|
40
40
|
PARTS: `${ADDON_ID}/parts`,
|
|
41
|
-
/**
|
|
41
|
+
/** consumers → preview: the user hovers/focuses a panel entry. */
|
|
42
42
|
HOVER_ITEM: `${ADDON_ID}/hover-item`,
|
|
43
|
-
/**
|
|
43
|
+
/** consumers → preview: the user left a panel entry. */
|
|
44
44
|
LEAVE_ITEM: `${ADDON_ID}/leave-item`,
|
|
45
|
-
/**
|
|
45
|
+
/** consumers → preview: a panel/block mounted and wants the current part list. */
|
|
46
46
|
PARTS_REQUEST: `${ADDON_ID}/parts-request`
|
|
47
47
|
};
|
|
48
48
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
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", "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
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAO,IAAM,WAAW;AACjB,IAAM,WAAW,GAAG,QAAQ;AAG5B,IAAM,YAAY;
|
|
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
6
|
"names": []
|
|
7
7
|
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +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"}
|
package/dist/index.js
CHANGED
|
@@ -3,17 +3,17 @@ var ADDON_ID = "component-anatomy";
|
|
|
3
3
|
var PANEL_ID = `${ADDON_ID}/panel`;
|
|
4
4
|
var PARAM_KEY = "anatomy";
|
|
5
5
|
var EVENTS = {
|
|
6
|
-
/** preview →
|
|
6
|
+
/** preview → consumers: a part became active in the canvas (hover/programmatic). */
|
|
7
7
|
PART_ENTER: `${ADDON_ID}/part-enter`,
|
|
8
|
-
/** preview →
|
|
8
|
+
/** preview → consumers: no part is active anymore. */
|
|
9
9
|
PART_LEAVE: `${ADDON_ID}/part-leave`,
|
|
10
|
-
/** preview →
|
|
10
|
+
/** preview → consumers: resolved part list for a story. */
|
|
11
11
|
PARTS: `${ADDON_ID}/parts`,
|
|
12
|
-
/**
|
|
12
|
+
/** consumers → preview: the user hovers/focuses a panel entry. */
|
|
13
13
|
HOVER_ITEM: `${ADDON_ID}/hover-item`,
|
|
14
|
-
/**
|
|
14
|
+
/** consumers → preview: the user left a panel entry. */
|
|
15
15
|
LEAVE_ITEM: `${ADDON_ID}/leave-item`,
|
|
16
|
-
/**
|
|
16
|
+
/** consumers → preview: a panel/block mounted and wants the current part list. */
|
|
17
17
|
PARTS_REQUEST: `${ADDON_ID}/parts-request`
|
|
18
18
|
};
|
|
19
19
|
export {
|