storybook-addon-md 0.8.0 → 0.9.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/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # storybook-addon-md
2
2
 
3
+ ## 0.9.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 990c4b9: Rendered links now behave correctly on their own. Docs links keep the absolute manager URL and navigate through the Storybook channel on a plain click, so the preview no longer reloads; modified clicks and non-primary buttons fall through to the browser. External links open in a new tab with `rel="noopener noreferrer"`, both kinds carry a `data-link` attribute, and explicit `target` or `rel` attributes are preserved. `Anchor` is exported from `storybook-addon-md/runtime` for custom renderers.
8
+
9
+ Docs links no longer set `target="_top"`. Stylesheets or tests that relied on that attribute should target `[data-link="docs"]` instead.
10
+
3
11
  ## 0.8.0
4
12
 
5
13
  ### Minor Changes
package/README.md CHANGED
@@ -204,10 +204,12 @@ By default every relative link is bundled as an asset, so a link to another Mark
204
204
  }
205
205
  ```
206
206
 
207
- | Field | Default | Behavior |
208
- | ------------ | ------- | ------------------------------------------------------------------------------------------------------------------------ |
209
- | `documents` | `true` | Links to discovered Markdown documents become ordinary links to their Docs page in the manager, opened in the top frame. |
210
- | `repository` | None | Links to other files or folders inside the project folder become `<repository>/<path relative to root>` links. |
207
+ | Field | Default | Behavior |
208
+ | ------------ | ------- | -------------------------------------------------------------------------------------------------------------- |
209
+ | `documents` | `true` | Links to discovered Markdown documents become ordinary links to their Docs page in the manager. |
210
+ | `repository` | None | Links to other files or folders inside the project folder become `<repository>/<path relative to root>` links. |
211
+
212
+ Rendered links behave correctly without a click handler in your Layout. Docs links keep the absolute manager URL as `href`, so copying, middle-clicking, and opening in a new tab work as usual, and a plain left click asks the manager to navigate without reloading the preview. Modified clicks fall through to the browser. Absolute `http:` and `https:` links, including every `repository` link, open in a new tab with `rel="noopener noreferrer"`. Fragment links are left untouched, and explicit `target` or `rel` attributes from a custom renderer are never overridden.
211
213
 
212
214
  Fragments and query strings are preserved. Attached documents link to their story file's Docs page using the CSF `title`; when the story file has no explicit title, the link falls back to the `story:<path>` key and will not resolve until a title is set. Images and image reference definitions remain bundled assets, and manifests keep the original Markdown. Relative links to files outside root, or to missing files, still fail the build. Without `links`, behavior is unchanged.
213
215
 
package/STYLING.md CHANGED
@@ -90,6 +90,8 @@ Five tokens cover most of the page. Element variables fall back to them, so set
90
90
 
91
91
  Status chips have `data-status` set to the original frontmatter value. Override `--sbmd-tag-*` on selectors such as `.storybook-addon-md-tag[data-status="stable" i]` to assign a status-specific appearance.
92
92
 
93
+ Links carry `data-link="docs"` for Storybook Docs pages and `data-link="external"` for absolute `http:` and `https:` URLs, so a stylesheet can mark external links or hide the distinction. Fragment links and other hrefs have no `data-link`.
94
+
93
95
  Callouts are `.storybook-addon-md-callout` elements with `data-callout` set to `note`, `tip`, `important`, `warning`, or `caution`, and a `.storybook-addon-md-callout-label` paragraph. The addon sets `--sbmd-callout-accent` on each callout from its type’s accent variable, and uses it for the default border and the label color. Per-type accent variables default to Storybook theme colors chosen for the light or dark base.
94
96
 
95
97
  Properties without a variable use ordinary CSS. Match the addon’s specificity for properties it sets, for example `.sbdocs-content .storybook-addon-md h2` for heading letter spacing or `.sbdocs-content .storybook-addon-md-tags` for the tag gap.
@@ -204,6 +206,18 @@ export function MarkdownRenderer(document: MarkdownDocument) {
204
206
 
205
207
  `MarkdownRenderer` receives `{ markdown, metadata, source, heading? }`: processed Markdown with resolved asset URLs, preserved frontmatter, and the source path relative to the project folder.
206
208
 
209
+ `Anchor` is the link component used by `DefaultMarkdownRenderer`. It navigates the manager for Docs links, opens external links in a new tab, sets `data-link`, and keeps explicit `target` and `rel` attributes. Reuse it in a custom renderer's `overrides` so links keep the same behavior:
210
+
211
+ ```tsx
212
+ import { Markdown } from '@storybook/addon-docs/blocks';
213
+ import { Anchor } from 'storybook-addon-md/runtime';
214
+ import type { MarkdownDocument } from 'storybook-addon-md/runtime';
215
+
216
+ export function MarkdownRenderer({ markdown }: MarkdownDocument) {
217
+ return <Markdown options={{ overrides: { a: Anchor } }}>{markdown}</Markdown>;
218
+ }
219
+ ```
220
+
207
221
  Callouts are rendered by `DefaultMarkdownRenderer`. A custom `MarkdownRenderer` receives them as ordinary blockquotes whose first line is the `[!NOTE]` marker, serialized as `\[!NOTE]` so that renderers treat the brackets as text. Render callouts yourself or delegate to `DefaultMarkdownRenderer`. Custom layouts are unaffected because callouts are part of `children`.
208
222
 
209
223
  `Layout` receives `{ documents, title, attached, children, examples, heading, tagFields }`. A standalone leading H1 is extracted in the default pipeline and supplied as the rendered `heading` node; render it instead of your fallback title. The remaining Markdown is supplied through `children`, while source files and manifests stay intact. `tagFields` lists configured metadata fields for tag display. Render `children` and `examples` to keep documentation and native example/props blocks. `examples` is `null` for standalone pages. `title` contains the standalone sidebar title and is empty for attached pages; `DefaultLayout` uses Storybook’s `Title` block for those.
package/dist/runtime.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ComponentType, ReactNode } from "react";
1
+ import { ComponentProps, ComponentType, ReactNode } from "react";
2
2
  //#region src/types.d.ts
3
3
  interface MarkdownDocument {
4
4
  source: string;
@@ -21,6 +21,7 @@ interface Presentation {
21
21
  }
22
22
  //#endregion
23
23
  //#region src/runtime.d.ts
24
+ export declare function Anchor({ href, target, rel, ...props }: ComponentProps<'a'>): import("react").JSX.Element;
24
25
  export declare function DefaultMarkdownRenderer({ markdown }: MarkdownDocument): import("react").JSX.Element;
25
26
  export declare function DefaultLayout({ documents, title, attached, children, examples, heading, tagFields }: LayoutProps): import("react").JSX.Element;
26
27
  export declare function Documentation({ documents, title, attached, presentation, tagFields }: {
package/dist/runtime.js CHANGED
@@ -1,4 +1,6 @@
1
1
  import { Children, cloneElement, isValidElement } from "react";
2
+ import { NAVIGATE_URL } from "storybook/internal/core-events";
3
+ import { addons } from "storybook/preview-api";
2
4
  import { useTheme } from "storybook/theming";
3
5
  import { CodeOrSourceMdx, Controls, HeadersMdx, Markdown, Primary, Stories, Title } from "@storybook/addon-docs/blocks";
4
6
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -34,16 +36,35 @@ function Blockquote({ children, ...props }) {
34
36
  }), content]
35
37
  });
36
38
  }
37
- function Anchor({ href, target, ...props }) {
38
- if (!href?.startsWith("?path=")) return /* @__PURE__ */ jsx("a", {
39
+ function Anchor({ href, target, rel, ...props }) {
40
+ if (href?.startsWith("?path=")) {
41
+ const navigate = (event) => {
42
+ props.onClick?.(event);
43
+ if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || target && target !== "_self") return;
44
+ event.preventDefault();
45
+ addons.getChannel().emit(NAVIGATE_URL, href);
46
+ };
47
+ return /* @__PURE__ */ jsx("a", {
48
+ ...props,
49
+ href: new URL(href, new URL("./", window.location.href)).href,
50
+ target,
51
+ rel,
52
+ "data-link": "docs",
53
+ onClick: navigate
54
+ });
55
+ }
56
+ if (href && /^https?:\/\//i.test(href)) return /* @__PURE__ */ jsx("a", {
39
57
  ...props,
40
58
  href,
41
- target
59
+ target: target ?? "_blank",
60
+ rel: rel ?? "noopener noreferrer",
61
+ "data-link": "external"
42
62
  });
43
63
  return /* @__PURE__ */ jsx("a", {
44
64
  ...props,
45
- href: new URL(href, new URL("./", window.location.href)).href,
46
- target: target ?? "_top"
65
+ href,
66
+ target,
67
+ rel
47
68
  });
48
69
  }
49
70
  function DefaultMarkdownRenderer({ markdown }) {
@@ -132,4 +153,4 @@ function Documentation({ documents, title, attached = false, presentation = {},
132
153
  });
133
154
  }
134
155
  //#endregion
135
- export { DefaultLayout, DefaultMarkdownRenderer, Documentation };
156
+ export { Anchor, DefaultLayout, DefaultMarkdownRenderer, Documentation };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "storybook-addon-md",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Discover ordinary Markdown and render it in Storybook Docs.",
5
5
  "keywords": [
6
6
  "docs",