@connextar/house 0.17.0 → 0.19.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.
Files changed (123) hide show
  1. package/README.md +850 -0
  2. package/dist/admin/access.d.ts +134 -0
  3. package/dist/admin/access.d.ts.map +1 -0
  4. package/dist/admin/access.js +157 -0
  5. package/dist/admin/access.js.map +1 -0
  6. package/dist/admin/audit.d.ts +130 -0
  7. package/dist/admin/audit.d.ts.map +1 -0
  8. package/dist/admin/audit.js +132 -0
  9. package/dist/admin/audit.js.map +1 -0
  10. package/dist/admin/bootstrap.d.ts +80 -0
  11. package/dist/admin/bootstrap.d.ts.map +1 -0
  12. package/dist/admin/bootstrap.js +106 -0
  13. package/dist/admin/bootstrap.js.map +1 -0
  14. package/dist/admin/client-index.d.ts +7 -0
  15. package/dist/admin/client-index.d.ts.map +1 -0
  16. package/dist/admin/client-index.js +6 -0
  17. package/dist/admin/client-index.js.map +1 -0
  18. package/dist/admin/client.d.ts +72 -0
  19. package/dist/admin/client.d.ts.map +1 -0
  20. package/dist/admin/client.js +90 -0
  21. package/dist/admin/client.js.map +1 -0
  22. package/dist/admin/index.d.ts +13 -0
  23. package/dist/admin/index.d.ts.map +1 -0
  24. package/dist/admin/index.js +13 -0
  25. package/dist/admin/index.js.map +1 -0
  26. package/dist/admin/proof.d.ts +34 -0
  27. package/dist/admin/proof.d.ts.map +1 -0
  28. package/dist/admin/proof.js +30 -0
  29. package/dist/admin/proof.js.map +1 -0
  30. package/dist/admin/second-factor-index.d.ts +8 -0
  31. package/dist/admin/second-factor-index.d.ts.map +1 -0
  32. package/dist/admin/second-factor-index.js +8 -0
  33. package/dist/admin/second-factor-index.js.map +1 -0
  34. package/dist/admin/second-factor.d.ts +156 -0
  35. package/dist/admin/second-factor.d.ts.map +1 -0
  36. package/dist/admin/second-factor.js +271 -0
  37. package/dist/admin/second-factor.js.map +1 -0
  38. package/dist/admin/testing-index.d.ts +6 -0
  39. package/dist/admin/testing-index.d.ts.map +1 -0
  40. package/dist/admin/testing-index.js +6 -0
  41. package/dist/admin/testing-index.js.map +1 -0
  42. package/dist/admin/testing.d.ts +84 -0
  43. package/dist/admin/testing.d.ts.map +1 -0
  44. package/dist/admin/testing.js +223 -0
  45. package/dist/admin/testing.js.map +1 -0
  46. package/dist/admin/view-as.d.ts +209 -0
  47. package/dist/admin/view-as.d.ts.map +1 -0
  48. package/dist/admin/view-as.js +251 -0
  49. package/dist/admin/view-as.js.map +1 -0
  50. package/dist/guides/guide-article.d.ts +13 -2
  51. package/dist/guides/guide-article.d.ts.map +1 -1
  52. package/dist/guides/guide-article.js +5 -3
  53. package/dist/guides/guide-article.js.map +1 -1
  54. package/dist/guides/guide-figure-zoom.d.ts +73 -0
  55. package/dist/guides/guide-figure-zoom.d.ts.map +1 -0
  56. package/dist/guides/guide-figure-zoom.js +279 -0
  57. package/dist/guides/guide-figure-zoom.js.map +1 -0
  58. package/dist/guides/guide-figure.d.ts +21 -0
  59. package/dist/guides/guide-figure.d.ts.map +1 -0
  60. package/dist/guides/guide-figure.js +19 -0
  61. package/dist/guides/guide-figure.js.map +1 -0
  62. package/dist/guides/index.d.ts +2 -0
  63. package/dist/guides/index.d.ts.map +1 -1
  64. package/dist/guides/index.js +2 -0
  65. package/dist/guides/index.js.map +1 -1
  66. package/dist/guides/library.d.ts +19 -1
  67. package/dist/guides/library.d.ts.map +1 -1
  68. package/dist/guides/library.js +9 -0
  69. package/dist/guides/library.js.map +1 -1
  70. package/dist/health/health.d.ts +65 -0
  71. package/dist/health/health.d.ts.map +1 -0
  72. package/dist/health/health.js +93 -0
  73. package/dist/health/health.js.map +1 -0
  74. package/dist/health/index.d.ts +2 -0
  75. package/dist/health/index.d.ts.map +1 -0
  76. package/dist/health/index.js +2 -0
  77. package/dist/health/index.js.map +1 -0
  78. package/dist/markdown/figure.d.ts +44 -0
  79. package/dist/markdown/figure.d.ts.map +1 -0
  80. package/dist/markdown/figure.js +56 -0
  81. package/dist/markdown/figure.js.map +1 -0
  82. package/dist/markdown/figures.d.ts +94 -0
  83. package/dist/markdown/figures.d.ts.map +1 -0
  84. package/dist/markdown/figures.js +126 -0
  85. package/dist/markdown/figures.js.map +1 -0
  86. package/dist/markdown/guide.d.ts +26 -7
  87. package/dist/markdown/guide.d.ts.map +1 -1
  88. package/dist/markdown/guide.js +27 -6
  89. package/dist/markdown/guide.js.map +1 -1
  90. package/dist/markdown/index.d.ts +2 -0
  91. package/dist/markdown/index.d.ts.map +1 -1
  92. package/dist/markdown/index.js +2 -0
  93. package/dist/markdown/index.js.map +1 -1
  94. package/dist/release/changelog.d.ts +19 -0
  95. package/dist/release/changelog.d.ts.map +1 -1
  96. package/dist/release/changelog.js +37 -6
  97. package/dist/release/changelog.js.map +1 -1
  98. package/dist/release/index.d.ts +1 -1
  99. package/dist/release/index.d.ts.map +1 -1
  100. package/dist/release/index.js +1 -1
  101. package/dist/release/index.js.map +1 -1
  102. package/dist/whats-new/body.d.ts +81 -0
  103. package/dist/whats-new/body.d.ts.map +1 -0
  104. package/dist/whats-new/body.js +29 -0
  105. package/dist/whats-new/body.js.map +1 -0
  106. package/dist/whats-new/index.d.ts +24 -0
  107. package/dist/whats-new/index.d.ts.map +1 -0
  108. package/dist/whats-new/index.js +24 -0
  109. package/dist/whats-new/index.js.map +1 -0
  110. package/dist/whats-new/seen.d.ts +23 -0
  111. package/dist/whats-new/seen.d.ts.map +1 -0
  112. package/dist/whats-new/seen.js +33 -0
  113. package/dist/whats-new/seen.js.map +1 -0
  114. package/dist/whats-new/select.d.ts +89 -0
  115. package/dist/whats-new/select.d.ts.map +1 -0
  116. package/dist/whats-new/select.js +117 -0
  117. package/dist/whats-new/select.js.map +1 -0
  118. package/dist/whats-new/use-whats-new.d.ts +36 -0
  119. package/dist/whats-new/use-whats-new.d.ts.map +1 -0
  120. package/dist/whats-new/use-whats-new.js +81 -0
  121. package/dist/whats-new/use-whats-new.js.map +1 -0
  122. package/docs/ReleaseProcess.md +12 -0
  123. package/package.json +25 -1
@@ -0,0 +1,93 @@
1
+ /**
2
+ * A liveness check that says which release is running: `GET /healthz` answers
3
+ * `ok 0.24.1 2c9a3cf`, so a deploy can be confirmed from outside with one curl.
4
+ *
5
+ * Lifted from PharmaLineAI's voice relay (v0.24.1), generalised for the Next.js
6
+ * apps on Vercel and anything on Render. The endpoint is public, so it says only
7
+ * a version and a short commit hash, and only when each looks like one: a value
8
+ * that came from the environment is never echoed as-is. It always answers 200
9
+ * with `ok` first, which is what a host's health check looks for.
10
+ *
11
+ * Liveness only: no database, no provider, nothing that can be slow or fail. A
12
+ * readiness check is a separate route of the app's own (see the README).
13
+ *
14
+ * Imports no package: the route handler is plain web `Request` and `Response`,
15
+ * which is what a Next route handler takes and returns.
16
+ */
17
+ /** MAJOR.MINOR.PATCH with an optional pre-release (`1.2.3-rc.1`). No `v`, no build metadata. */
18
+ const SEMVER = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;
19
+ /** A git object name: 7 to 64 hex digits (SHA-1 or SHA-256), nothing else. */
20
+ const HEX_HASH = /^[0-9a-f]{7,64}$/i;
21
+ /**
22
+ * Where each host puts the commit it deployed, in the order they are read:
23
+ * Vercel (a system environment variable, exposed by default), Render, then a
24
+ * `GIT_COMMIT` an app or another host sets itself.
25
+ */
26
+ export const COMMIT_ENV_VARS = ["VERCEL_GIT_COMMIT_SHA", "RENDER_GIT_COMMIT", "GIT_COMMIT"];
27
+ /**
28
+ * The build from a version (package.json's, passed in) and the commit the host
29
+ * deployed, cut to 7. A version that isn't semver-shaped is dropped; the commit
30
+ * is the first of `COMMIT_ENV_VARS` that is a whole hex hash, so a variable set
31
+ * to something else is skipped rather than repeated on a public page.
32
+ */
33
+ export function buildInfo(version, env = process.env) {
34
+ const v = typeof version === "string" ? version.trim() : "";
35
+ const commit = COMMIT_ENV_VARS.map((name) => (env[name] ?? "").trim()).find((value) => HEX_HASH.test(value));
36
+ return {
37
+ ...(SEMVER.test(v) ? { version: v } : {}),
38
+ ...(commit ? { commit: commit.slice(0, 7).toLowerCase() } : {}),
39
+ };
40
+ }
41
+ /** What the check says: `ok`, then the version and commit when known — `ok 1.2.3 abc1234`. */
42
+ export function healthText(build = {}) {
43
+ return ["ok", build.version, build.commit].filter(Boolean).join(" ");
44
+ }
45
+ /**
46
+ * The format a request asks for: `?format=json` or `?format=text` first, then an
47
+ * `Accept` header that names `application/json`. Anything else — a browser, curl's
48
+ * `*\/*`, a host's checker — gets text.
49
+ */
50
+ export function healthFormat(request) {
51
+ const asked = new URL(request.url).searchParams.get("format")?.trim().toLowerCase();
52
+ if (asked === "json" || asked === "text")
53
+ return asked;
54
+ const accept = (request.headers.get("accept") ?? "").toLowerCase();
55
+ return /(^|[\s,])application\/json(\s*;|\s*,|\s*$)/.test(accept) ? "json" : "text";
56
+ }
57
+ const HEADERS = {
58
+ // A health check must never be answered from a cache: it would say a deploy is live that isn't.
59
+ "cache-control": "no-store",
60
+ "x-content-type-options": "nosniff",
61
+ };
62
+ /** The answer itself: 200, `text/plain` by default, `{ status: "ok", version, commit }` as JSON. */
63
+ export function healthResponse(build = {}, { format = "text" } = {}) {
64
+ if (format === "json") {
65
+ const body = {
66
+ status: "ok",
67
+ ...(build.version ? { version: build.version } : {}),
68
+ ...(build.commit ? { commit: build.commit } : {}),
69
+ };
70
+ return new Response(JSON.stringify(body), {
71
+ status: 200,
72
+ headers: { ...HEADERS, "content-type": "application/json; charset=utf-8" },
73
+ });
74
+ }
75
+ return new Response(healthText(build), {
76
+ status: 200,
77
+ headers: { ...HEADERS, "content-type": "text/plain; charset=utf-8" },
78
+ });
79
+ }
80
+ /**
81
+ * A Next route handler for `app/healthz/route.ts`, where `pkg` is the app's own package.json
82
+ * imported in that file (a route file is server-only, so it never reaches the browser):
83
+ *
84
+ * export const { GET } = createHealthRoute({ version: pkg.version });
85
+ *
86
+ * Next answers `HEAD` from `GET` on its own.
87
+ */
88
+ export function createHealthRoute({ version, env }) {
89
+ return {
90
+ GET: (request) => healthResponse(buildInfo(version, env ?? process.env), { format: healthFormat(request) }),
91
+ };
92
+ }
93
+ //# sourceMappingURL=health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/health/health.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export { buildInfo, COMMIT_ENV_VARS, createHealthRoute, healthFormat, healthResponse, healthText, type BuildInfo, type HealthFormat, type HealthRouteOptions, } from "./health.js";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/health/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,eAAe,EACf,iBAAiB,EACjB,YAAY,EACZ,cAAc,EACd,UAAU,EACV,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,kBAAkB,GACxB,MAAM,aAAa,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { buildInfo, COMMIT_ENV_VARS, createHealthRoute, healthFormat, healthResponse, healthText, } from "./health.js";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/health/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,eAAe,EACf,iBAAiB,EACjB,YAAY,EACZ,cAAc,EACd,UAAU,GAIX,MAAM,aAAa,CAAC"}
@@ -0,0 +1,44 @@
1
+ import { type ReactNode } from "react";
2
+ import type { GuideFigureBlock, GuideFigures } from "./figures.js";
3
+ /** Every element a guide's picture draws. Each value replaces the default for that element. */
4
+ export interface GuideFigureClassNames {
5
+ figure: string;
6
+ /** Every screenshot `<img>`. */
7
+ image: string;
8
+ /** Added to a screenshot with no dark capture: a light picture on a dark page, toned down so it doesn't glare. */
9
+ imageWithoutDark: string;
10
+ /** Added to the light capture when there is a dark one. */
11
+ imageLight: string;
12
+ /** Added to the dark capture. */
13
+ imageDark: string;
14
+ /** The frame a diagram sits in. */
15
+ diagram: string;
16
+ caption: string;
17
+ }
18
+ /** The house look, on the shared theme tokens (PharmaLineAI's). */
19
+ export declare const GUIDE_FIGURE_CLASS_NAMES: GuideFigureClassNames;
20
+ /**
21
+ * A registered diagram, drawn: a component is given the alt text as `label`; an element is
22
+ * wrapped in `role="img"` with the alt text as its name. Null when the name isn't registered.
23
+ */
24
+ export declare function drawGuideDiagram(figures: GuideFigures | undefined, name: string, label: string): ReactNode;
25
+ export interface GuideFigureMediaProps {
26
+ figure: GuideFigureBlock;
27
+ figures?: GuideFigures;
28
+ classNames?: Partial<GuideFigureClassNames>;
29
+ /** Load the screenshot straight away rather than when it nears the screen. Default: lazy. */
30
+ eager?: boolean;
31
+ }
32
+ /**
33
+ * The picture itself, without its caption: a screenshot at its registered size (and its dark
34
+ * capture beside it when there is one, each shown by the theme's `dark:` variant), or a diagram
35
+ * in its frame.
36
+ */
37
+ export declare function GuideFigureMedia({ figure, figures, classNames, eager }: GuideFigureMediaProps): ReactNode;
38
+ export interface GuideFigureViewProps extends GuideFigureMediaProps {
39
+ /** Drawn in place of the plain picture — `GuideArticle` puts its zoom button here. */
40
+ media?: ReactNode;
41
+ }
42
+ /** A picture with its caption, as a `<figure>`. Server-safe; no zoom (`GuideArticle` adds that). */
43
+ export declare function GuideFigureView({ figure, figures, classNames, eager, media }: GuideFigureViewProps): ReactNode;
44
+ //# sourceMappingURL=figure.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"figure.d.ts","sourceRoot":"","sources":["../../src/markdown/figure.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqD,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAG1F,OAAO,KAAK,EAAgB,gBAAgB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjF,+FAA+F;AAC/F,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,gCAAgC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,kHAAkH;IAClH,gBAAgB,EAAE,MAAM,CAAC;IACzB,2DAA2D;IAC3D,UAAU,EAAE,MAAM,CAAC;IACnB,iCAAiC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,mEAAmE;AACnE,eAAO,MAAM,wBAAwB,EAAE,qBAStC,CAAC;AAQF;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,YAAY,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,CAU1G;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,gBAAgB,CAAC;IACzB,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,UAAU,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAC5C,6FAA6F;IAC7F,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,qBAAqB,GAAG,SAAS,CAwBzG;AAED,MAAM,WAAW,oBAAqB,SAAQ,qBAAqB;IACjE,sFAAsF;IACtF,KAAK,CAAC,EAAE,SAAS,CAAC;CACnB;AAED,oGAAoG;AACpG,wBAAgB,eAAe,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,oBAAoB,GAAG,SAAS,CAQ9G"}
@@ -0,0 +1,56 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { createElement, isValidElement } from "react";
3
+ import { cx } from "../internal/cx.js";
4
+ /** The house look, on the shared theme tokens (PharmaLineAI's). */
5
+ export const GUIDE_FIGURE_CLASS_NAMES = {
6
+ figure: "my-8",
7
+ // No display utility here: a dark capture is `hidden dark:block`, and two display utilities on one element fight.
8
+ image: "h-auto w-full rounded-xl border border-border bg-card align-top shadow-sm",
9
+ imageWithoutDark: "dark:brightness-[0.92]",
10
+ imageLight: "dark:hidden",
11
+ imageDark: "hidden dark:block",
12
+ diagram: "rounded-xl border border-border bg-card/60 px-3 py-5 sm:px-6",
13
+ caption: "mt-2.5 text-center text-sm text-muted-foreground",
14
+ };
15
+ /** A component (function, `memo`, `forwardRef`) rather than an element or text. */
16
+ function isComponent(entry) {
17
+ if (typeof entry === "function")
18
+ return true;
19
+ return typeof entry === "object" && entry !== null && !isValidElement(entry) && "$$typeof" in entry;
20
+ }
21
+ /**
22
+ * A registered diagram, drawn: a component is given the alt text as `label`; an element is
23
+ * wrapped in `role="img"` with the alt text as its name. Null when the name isn't registered.
24
+ */
25
+ export function drawGuideDiagram(figures, name, label) {
26
+ const diagrams = figures?.diagrams;
27
+ if (!diagrams || !Object.prototype.hasOwnProperty.call(diagrams, name))
28
+ return null;
29
+ const entry = diagrams[name];
30
+ if (isComponent(entry))
31
+ return createElement(entry, { label });
32
+ return (_jsx("div", { role: "img", "aria-label": label, children: entry }));
33
+ }
34
+ /**
35
+ * The picture itself, without its caption: a screenshot at its registered size (and its dark
36
+ * capture beside it when there is one, each shown by the theme's `dark:` variant), or a diagram
37
+ * in its frame.
38
+ */
39
+ export function GuideFigureMedia({ figure, figures, classNames, eager }) {
40
+ const c = { ...GUIDE_FIGURE_CLASS_NAMES, ...classNames };
41
+ if (figure.kind === "diagram") {
42
+ return _jsx("div", { className: c.diagram, children: drawGuideDiagram(figures, figure.name, figure.alt) });
43
+ }
44
+ const img = (src, className) => (
45
+ // A plain <img>: the package imports no app's image pipeline. The registered size reserves the space.
46
+ _jsx("img", { src: src, alt: figure.alt, width: figure.width, height: figure.height, loading: eager ? "eager" : "lazy", decoding: "async", className: className }));
47
+ if (!figure.dark)
48
+ return img(figure.src, cx(c.image, c.imageWithoutDark));
49
+ return (_jsxs(_Fragment, { children: [img(figure.src, cx(c.image, c.imageLight)), img(figure.dark, cx(c.image, c.imageDark))] }));
50
+ }
51
+ /** A picture with its caption, as a `<figure>`. Server-safe; no zoom (`GuideArticle` adds that). */
52
+ export function GuideFigureView({ figure, figures, classNames, eager, media }) {
53
+ const c = { ...GUIDE_FIGURE_CLASS_NAMES, ...classNames };
54
+ return (_jsxs("figure", { className: c.figure, children: [media ?? _jsx(GuideFigureMedia, { figure: figure, figures: figures, classNames: classNames, eager: eager }), figure.caption ? _jsx("figcaption", { className: c.caption, children: figure.caption }) : null] }));
55
+ }
56
+ //# sourceMappingURL=figure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"figure.js","sourceRoot":"","sources":["../../src/markdown/figure.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ import type { ComponentType, ReactNode } from "react";
2
+ /**
3
+ * Pictures in the guides: screenshots and diagrams, written in a guide's Markdown as
4
+ * an image on a line of its own, with a blank line either side:
5
+ *
6
+ * ![What the picture shows, for someone who can't see it](/guide-images/calls-log.webp "Caption")
7
+ * ![What the diagram shows](diagram:identity-check)
8
+ *
9
+ * Only pictures in the app's registry are drawn — a guide can't pull an image in from
10
+ * anywhere else, and a typo never shows a broken image — each with its width and height
11
+ * so the page doesn't jump as it loads. `guideFigureProblems` is the check an app's test
12
+ * asserts empty: an unregistered picture, missing alt text, or a picture inside a list or
13
+ * paragraph.
14
+ *
15
+ * Lifted from PharmaLineAI v0.23.1 (`lib/guide-figures.ts`). Pure: no file access, no
16
+ * React at run time.
17
+ */
18
+ /** A screenshot in the app's `public/guide-images/`, with its size so the page doesn't jump. */
19
+ export interface GuideScreenshot {
20
+ width: number;
21
+ height: number;
22
+ /** A dark-mode capture of the same screen, at the same size, shown instead under `dark:`. */
23
+ dark?: string;
24
+ }
25
+ /**
26
+ * A diagram: an element to draw as it is, or a component given the picture's alt text as
27
+ * `label` (to put on its own `<svg role="img" aria-label>`).
28
+ */
29
+ export type GuideDiagram = ReactNode | ComponentType<{
30
+ label: string;
31
+ }>;
32
+ /** Every picture a guide may show. */
33
+ export interface GuideFigures {
34
+ /** By public path: `"/guide-images/calls-log.webp": { width: 1600, height: 986 }`. */
35
+ screenshots: Readonly<Record<string, GuideScreenshot>>;
36
+ /** By name, as a guide writes it after `diagram:`. */
37
+ diagrams?: Readonly<Record<string, GuideDiagram>>;
38
+ }
39
+ /** A picture line as written, before it is looked up. */
40
+ export interface GuideFigureLine {
41
+ alt: string;
42
+ src: string;
43
+ caption?: string;
44
+ }
45
+ export type GuideFigureBlock = {
46
+ kind: "screenshot";
47
+ src: string;
48
+ alt: string;
49
+ caption?: string;
50
+ width: number;
51
+ height: number;
52
+ dark?: string;
53
+ } | {
54
+ kind: "diagram";
55
+ name: string;
56
+ alt: string;
57
+ caption?: string;
58
+ };
59
+ export type GuideBlock = {
60
+ kind: "markdown";
61
+ content: string;
62
+ } | GuideFigureBlock;
63
+ export declare const DIAGRAM_PREFIX = "diagram:";
64
+ /** A picture line, or null when the line isn't one. */
65
+ export declare function parseFigureLine(line: string): GuideFigureLine | null;
66
+ /** The picture a line names, or null when it names nothing in the registry or has no alt text. */
67
+ export declare function resolveGuideFigure(line: GuideFigureLine, figures: GuideFigures | undefined): GuideFigureBlock | null;
68
+ /**
69
+ * A guide body as runs of Markdown and the pictures between them. A picture line that
70
+ * names nothing in the registry is dropped; inside a code fence a picture line is just
71
+ * code. `GuideMarkdown` draws figures in the same places itself, keeping every heading's
72
+ * id — this is the same split as data, for an app's own layout or its tests.
73
+ */
74
+ export declare function splitGuideFigures(body: string, figures: GuideFigures | undefined): GuideBlock[];
75
+ export interface GuideFigureCheckOptions {
76
+ /** The shortest alt text accepted. Default 1 — any; PharmaLine asks for more than 20. */
77
+ minAltLength?: number;
78
+ }
79
+ /**
80
+ * Every way a guide's pictures would fail to show as written, as sentences with line
81
+ * numbers. An app's test asserts it is empty for each guide:
82
+ *
83
+ * expect(guideFigureProblems(body, GUIDE_FIGURES)).toEqual([]);
84
+ *
85
+ * - a picture that isn't registered (a screenshot path or a `diagram:` name);
86
+ * - a picture with no alt text, or shorter than `minAltLength`;
87
+ * - a picture without a blank line either side — inside a list it would end the list and
88
+ * restart its numbering after it; inside a paragraph it would split it;
89
+ * - an image written inside a line of text, which is never drawn.
90
+ *
91
+ * Lines inside code fences, and images inside inline code, are left alone.
92
+ */
93
+ export declare function guideFigureProblems(body: string, figures: GuideFigures | undefined, { minAltLength }?: GuideFigureCheckOptions): string[];
94
+ //# sourceMappingURL=figures.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"figures.d.ts","sourceRoot":"","sources":["../../src/markdown/figures.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEtD;;;;;;;;;;;;;;;GAeG;AAEH,gGAAgG;AAChG,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,6FAA6F;IAC7F,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,aAAa,CAAC;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAExE,sCAAsC;AACtC,MAAM,WAAW,YAAY;IAC3B,sFAAsF;IACtF,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC;IACvD,sDAAsD;IACtD,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC;CACnD;AAED,yDAAyD;AACzD,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,gBAAgB,GACxB;IACE,IAAI,EAAE,YAAY,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,GACD;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAErE,MAAM,MAAM,UAAU,GAAG;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,gBAAgB,CAAC;AAMlF,eAAO,MAAM,cAAc,aAAa,CAAC;AAMzC,uDAAuD;AACvD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAKpE;AAED,kGAAkG;AAClG,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,YAAY,GAAG,SAAS,GAAG,gBAAgB,GAAG,IAAI,CAkBpH;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,SAAS,GAAG,UAAU,EAAE,CAsB/F;AAED,MAAM,WAAW,uBAAuB;IACtC,yFAAyF;IACzF,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,YAAY,GAAG,SAAS,EACjC,EAAE,YAAgB,EAAE,GAAE,uBAA4B,GACjD,MAAM,EAAE,CAyCV"}
@@ -0,0 +1,126 @@
1
+ /** An image alone on its line: `![alt](src)` or `![alt](src "caption")`. */
2
+ const IMAGE_LINE = /^!\[([^\]]*)\]\(\s*(\S+?)(?:\s+"([^"]*)")?\s*\)$/;
3
+ /** An image anywhere in a line, for the check that one isn't written inside a paragraph. */
4
+ const INLINE_IMAGE = /!\[[^\]]*\]\([^)]*\)/;
5
+ export const DIAGRAM_PREFIX = "diagram:";
6
+ const isFence = (line) => line.trim().startsWith("```");
7
+ const own = (record, key) => record && Object.prototype.hasOwnProperty.call(record, key) ? record[key] : undefined;
8
+ /** A picture line, or null when the line isn't one. */
9
+ export function parseFigureLine(line) {
10
+ const match = line.trim().match(IMAGE_LINE);
11
+ if (!match)
12
+ return null;
13
+ const caption = match[3]?.trim();
14
+ return { alt: (match[1] ?? "").trim(), src: match[2] ?? "", ...(caption ? { caption } : {}) };
15
+ }
16
+ /** The picture a line names, or null when it names nothing in the registry or has no alt text. */
17
+ export function resolveGuideFigure(line, figures) {
18
+ if (!line.alt || !figures)
19
+ return null;
20
+ const caption = line.caption ? { caption: line.caption } : {};
21
+ if (line.src.startsWith(DIAGRAM_PREFIX)) {
22
+ const name = line.src.slice(DIAGRAM_PREFIX.length);
23
+ return own(figures.diagrams, name) === undefined ? null : { kind: "diagram", name, alt: line.alt, ...caption };
24
+ }
25
+ const shot = own(figures.screenshots, line.src);
26
+ if (!shot)
27
+ return null;
28
+ return {
29
+ kind: "screenshot",
30
+ src: line.src,
31
+ alt: line.alt,
32
+ ...caption,
33
+ width: shot.width,
34
+ height: shot.height,
35
+ ...(shot.dark ? { dark: shot.dark } : {}),
36
+ };
37
+ }
38
+ /**
39
+ * A guide body as runs of Markdown and the pictures between them. A picture line that
40
+ * names nothing in the registry is dropped; inside a code fence a picture line is just
41
+ * code. `GuideMarkdown` draws figures in the same places itself, keeping every heading's
42
+ * id — this is the same split as data, for an app's own layout or its tests.
43
+ */
44
+ export function splitGuideFigures(body, figures) {
45
+ const blocks = [];
46
+ let run = [];
47
+ let inFence = false;
48
+ const flush = () => {
49
+ const content = run.join("\n");
50
+ if (content.trim())
51
+ blocks.push({ kind: "markdown", content });
52
+ run = [];
53
+ };
54
+ for (const line of body.replace(/\r\n/g, "\n").split("\n")) {
55
+ if (isFence(line))
56
+ inFence = !inFence;
57
+ const parsed = inFence ? null : parseFigureLine(line);
58
+ if (!parsed) {
59
+ run.push(line);
60
+ continue;
61
+ }
62
+ flush();
63
+ const figure = resolveGuideFigure(parsed, figures);
64
+ if (figure)
65
+ blocks.push(figure);
66
+ }
67
+ flush();
68
+ return blocks;
69
+ }
70
+ /**
71
+ * Every way a guide's pictures would fail to show as written, as sentences with line
72
+ * numbers. An app's test asserts it is empty for each guide:
73
+ *
74
+ * expect(guideFigureProblems(body, GUIDE_FIGURES)).toEqual([]);
75
+ *
76
+ * - a picture that isn't registered (a screenshot path or a `diagram:` name);
77
+ * - a picture with no alt text, or shorter than `minAltLength`;
78
+ * - a picture without a blank line either side — inside a list it would end the list and
79
+ * restart its numbering after it; inside a paragraph it would split it;
80
+ * - an image written inside a line of text, which is never drawn.
81
+ *
82
+ * Lines inside code fences, and images inside inline code, are left alone.
83
+ */
84
+ export function guideFigureProblems(body, figures, { minAltLength = 1 } = {}) {
85
+ const lines = body.replace(/\r\n/g, "\n").split("\n");
86
+ const problems = [];
87
+ let inFence = false;
88
+ lines.forEach((line, i) => {
89
+ if (isFence(line)) {
90
+ inFence = !inFence;
91
+ return;
92
+ }
93
+ if (inFence)
94
+ return;
95
+ const at = `Line ${i + 1}`;
96
+ const parsed = parseFigureLine(line);
97
+ if (!parsed) {
98
+ if (INLINE_IMAGE.test(line.replace(/`[^`]*`/g, ""))) {
99
+ problems.push(`${at}: a picture inside a line of text is never drawn; put it on a line of its own.`);
100
+ }
101
+ return;
102
+ }
103
+ const what = `\`${parsed.src}\``;
104
+ if (parsed.src.startsWith(DIAGRAM_PREFIX)) {
105
+ if (own(figures?.diagrams, parsed.src.slice(DIAGRAM_PREFIX.length)) === undefined) {
106
+ problems.push(`${at}: ${what} isn't a registered diagram.`);
107
+ }
108
+ }
109
+ else if (!own(figures?.screenshots, parsed.src)) {
110
+ problems.push(`${at}: ${what} isn't a registered screenshot.`);
111
+ }
112
+ if (!parsed.alt)
113
+ problems.push(`${at}: ${what} has no alt text.`);
114
+ else if (parsed.alt.length < minAltLength) {
115
+ problems.push(`${at}: ${what} has alt text shorter than ${minAltLength} characters.`);
116
+ }
117
+ if ((lines[i - 1] ?? "").trim() !== "" || (lines[i + 1] ?? "").trim() !== "") {
118
+ problems.push(`${at}: ${what} needs a blank line before and after it (a picture can't sit inside a list).`);
119
+ }
120
+ else if (/^\s/.test(line)) {
121
+ problems.push(`${at}: ${what} is indented as if inside a list; a picture ends the list, so start it at the margin.`);
122
+ }
123
+ });
124
+ return problems;
125
+ }
126
+ //# sourceMappingURL=figures.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"figures.js","sourceRoot":"","sources":["../../src/markdown/figures.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,6 @@
1
- import type { ReactNode } from "react";
1
+ import { type ReactNode } from "react";
2
+ import { type GuideFigureClassNames } from "./figure.js";
3
+ import { type GuideFigureBlock, type GuideFigures } from "./figures.js";
2
4
  import { type MarkdownTableClassNames } from "./table-view.js";
3
5
  /**
4
6
  * The help-centre guide renderer: Markdown files under `docs/guides/` drawn as a
@@ -14,7 +16,8 @@ import { type MarkdownTableClassNames } from "./table-view.js";
14
16
  *
15
17
  * The syntax is the constrained subset guides use: `##`–`####` headings,
16
18
  * paragraphs, blockquotes, ordered and unordered lists, tables, fenced code,
17
- * horizontal rules, and inline bold, italic, code and links. Raw HTML is never
19
+ * horizontal rules, inline bold, italic, code and links, and pictures from the
20
+ * app's registry on a line of their own (`figures.ts`). Raw HTML is never
18
21
  * interpreted, so a guide cannot put markup on a public page.
19
22
  *
20
23
  * Server-safe: no hooks, no client boundary.
@@ -70,7 +73,13 @@ export interface GuideLinkOptions {
70
73
  * protocol-relative `//host` — becomes `#`.
71
74
  */
72
75
  export declare function resolveGuideHref(href: string, { guidesPath, indexSlug }?: GuideLinkOptions): string;
73
- /** Every element a guide draws. Each value replaces the default for that element. */
76
+ /**
77
+ * Every element a guide draws. Each value replaces the default for that element.
78
+ *
79
+ * `table` and `figure` are each a set of parts, merged over the house's, and optional: an app that
80
+ * writes out a whole `GuideClassNames` (KRP's palette classes) needn't name a part it doesn't
81
+ * restyle, and a set of parts added in a later release can't break its typecheck.
82
+ */
74
83
  export interface GuideClassNames {
75
84
  h2: string;
76
85
  h3: string;
@@ -85,14 +94,24 @@ export interface GuideClassNames {
85
94
  code: string;
86
95
  pre: string;
87
96
  hr: string;
88
- table: Partial<MarkdownTableClassNames>;
97
+ table?: Partial<MarkdownTableClassNames>;
98
+ /** Left out, the house's picture classes (`GUIDE_FIGURE_CLASS_NAMES`). */
99
+ figure?: Partial<GuideFigureClassNames>;
89
100
  }
90
- /** The house look, on the shared theme tokens. */
91
- export declare const GUIDE_CLASS_NAMES: GuideClassNames;
101
+ /** The house look, on the shared theme tokens. Every part named, so `GUIDE_CLASS_NAMES.figure` is always there. */
102
+ export declare const GUIDE_CLASS_NAMES: Required<GuideClassNames>;
92
103
  export interface GuideMarkdownProps extends GuideLinkOptions {
93
104
  content: string;
94
105
  classNames?: Partial<GuideClassNames>;
106
+ /**
107
+ * The pictures a guide may show. A picture line (`![alt](/guide-images/x.webp "Caption")`
108
+ * or `![alt](diagram:name)`, alone on its line) is drawn only when it is registered here
109
+ * and has alt text; otherwise it is left out, never drawn as a broken image.
110
+ */
111
+ figures?: GuideFigures;
112
+ /** Draws each registered picture. Default: `GuideFigureView`, a plain `<figure>`; `GuideArticle` adds zoom. */
113
+ renderFigure?: (figure: GuideFigureBlock) => ReactNode;
95
114
  }
96
115
  /** Render a guide body. */
97
- export declare function GuideMarkdown({ content, guidesPath, indexSlug, classNames }: GuideMarkdownProps): ReactNode;
116
+ export declare function GuideMarkdown({ content, guidesPath, indexSlug, classNames, figures, renderFigure, }: GuideMarkdownProps): ReactNode;
98
117
  //# sourceMappingURL=guide.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"guide.d.ts","sourceRoot":"","sources":["../../src/markdown/guide.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvC,OAAO,EAAqB,KAAK,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAElF;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,WAAW,WAAW;IAC1B,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAC;IACd,mFAAmF;IACnF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC;CACd;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AASD,uDAAuD;AACvD,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,CA0BnE;AAED,6EAA6E;AAC7E,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAShD;AAED,iEAAiE;AACjE,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOhD;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAQ3D;AAED,mFAAmF;AACnF,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,EAAE,CAkB5D;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,CAmC3D;AAED,MAAM,WAAW,gBAAgB;IAC/B,0CAA0C;IAC1C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4FAA4F;IAC5F,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,UAAsB,EAAE,SAAS,EAAE,GAAE,gBAAqB,GAAG,MAAM,CAUnH;AAED,qFAAqF;AACrF,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,OAAO,CAAC,uBAAuB,CAAC,CAAC;CACzC;AAED,kDAAkD;AAClD,eAAO,MAAM,iBAAiB,EAAE,eAiB/B,CAAC;AAEF,MAAM,WAAW,kBAAmB,SAAQ,gBAAgB;IAC1D,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;CACvC;AAED,2BAA2B;AAC3B,wBAAgB,aAAa,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,kBAAkB,GAAG,SAAS,CAoL3G"}
1
+ {"version":3,"file":"guide.d.ts","sourceRoot":"","sources":["../../src/markdown/guide.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAGjD,OAAO,EAAmB,KAAK,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAC1E,OAAO,EAAuC,KAAK,gBAAgB,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAE7G,OAAO,EAAqB,KAAK,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAElF;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,WAAW,WAAW;IAC1B,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAC;IACd,mFAAmF;IACnF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC;CACd;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AASD,uDAAuD;AACvD,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,CA0BnE;AAED,6EAA6E;AAC7E,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAShD;AAED,iEAAiE;AACjE,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOhD;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAQ3D;AAED,mFAAmF;AACnF,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,EAAE,CAkB5D;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,CAmC3D;AAED,MAAM,WAAW,gBAAgB;IAC/B,0CAA0C;IAC1C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4FAA4F;IAC5F,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,UAAsB,EAAE,SAAS,EAAE,GAAE,gBAAqB,GAAG,MAAM,CAUnH;AAED;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,OAAO,CAAC,uBAAuB,CAAC,CAAC;IACzC,0EAA0E;IAC1E,MAAM,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;CACzC;AAED,mHAAmH;AACnH,eAAO,MAAM,iBAAiB,EAAE,QAAQ,CAAC,eAAe,CAkBvD,CAAC;AAEF,MAAM,WAAW,kBAAmB,SAAQ,gBAAgB;IAC1D,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IACtC;;;;OAIG;IACH,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,+GAA+G;IAC/G,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,SAAS,CAAC;CACxD;AAED,2BAA2B;AAC3B,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EACP,UAAU,EACV,SAAS,EACT,UAAU,EACV,OAAO,EACP,YAAY,GACb,EAAE,kBAAkB,GAAG,SAAS,CAsMhC"}
@@ -1,5 +1,8 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { Fragment } from "react";
2
3
  import { Link } from "../internal/next-link.js";
4
+ import { GuideFigureView } from "./figure.js";
5
+ import { parseFigureLine, resolveGuideFigure } from "./figures.js";
3
6
  import { readTable, isTableStart } from "./table.js";
4
7
  import { MarkdownTableView } from "./table-view.js";
5
8
  const lines = (markdown) => markdown.replace(/\r\n/g, "\n").split("\n");
@@ -147,7 +150,7 @@ export function resolveGuideHref(href, { guidesPath = "/guides", indexSlug } = {
147
150
  return href;
148
151
  return "#";
149
152
  }
150
- /** The house look, on the shared theme tokens. */
153
+ /** The house look, on the shared theme tokens. Every part named, so `GUIDE_CLASS_NAMES.figure` is always there. */
151
154
  export const GUIDE_CLASS_NAMES = {
152
155
  h2: "mt-12 scroll-mt-24 text-2xl font-bold tracking-tight text-foreground",
153
156
  h3: "mt-8 scroll-mt-24 text-lg font-semibold text-foreground",
@@ -165,12 +168,20 @@ export const GUIDE_CLASS_NAMES = {
165
168
  pre: "my-6 overflow-x-auto rounded-xl border border-border bg-muted/60 p-4 font-mono text-[0.85em] leading-relaxed text-foreground",
166
169
  hr: "my-8 border-border",
167
170
  table: {},
171
+ figure: {},
168
172
  };
169
173
  /** Render a guide body. */
170
- export function GuideMarkdown({ content, guidesPath, indexSlug, classNames }) {
171
- const c = { ...GUIDE_CLASS_NAMES, ...classNames };
172
- // `table` is itself a set of parts, so an override of one part keeps the rest.
173
- c.table = { ...GUIDE_CLASS_NAMES.table, ...classNames?.table };
174
+ export function GuideMarkdown({ content, guidesPath, indexSlug, classNames, figures, renderFigure, }) {
175
+ // `table` and `figure` are each a set of parts, so an override of one part keeps the rest, and leaving one out
176
+ // (or passing it as undefined) keeps the house's.
177
+ const c = {
178
+ ...GUIDE_CLASS_NAMES,
179
+ ...classNames,
180
+ table: { ...GUIDE_CLASS_NAMES.table, ...classNames?.table },
181
+ figure: { ...GUIDE_CLASS_NAMES.figure, ...classNames?.figure },
182
+ };
183
+ const drawFigure = renderFigure ??
184
+ ((figure) => _jsx(GuideFigureView, { figure: figure, figures: figures, classNames: c.figure }));
174
185
  const linkOptions = {
175
186
  ...(guidesPath === undefined ? {} : { guidesPath }),
176
187
  ...(indexSlug === undefined ? {} : { indexSlug }),
@@ -190,7 +201,8 @@ export function GuideMarkdown({ content, guidesPath, indexSlug, classNames }) {
190
201
  trimmed.startsWith(">") ||
191
202
  isRule(line) ||
192
203
  isFence(line) ||
193
- isTableStart(all, at));
204
+ isTableStart(all, at) ||
205
+ parseFigureLine(line) !== null);
194
206
  };
195
207
  /** A list: each item, with any wrapped lines that follow it folded in. */
196
208
  const readList = (isItem, marker) => {
@@ -255,6 +267,15 @@ export function GuideMarkdown({ content, guidesPath, indexSlug, classNames }) {
255
267
  blocks.push(_jsx("blockquote", { className: c.blockquote, children: inline(quote.join(" "), `q${key}`) }, key++));
256
268
  continue;
257
269
  }
270
+ // A picture on a line of its own. Unregistered or undescribed, it is left out rather than drawn broken.
271
+ const picture = parseFigureLine(line);
272
+ if (picture) {
273
+ const figure = resolveGuideFigure(picture, figures);
274
+ if (figure)
275
+ blocks.push(_jsx(Fragment, { children: drawFigure(figure) }, key++));
276
+ i++;
277
+ continue;
278
+ }
258
279
  const table = readTable(all, i);
259
280
  if (table) {
260
281
  const tableKey = key++;