@ai-react-markdown/core 1.4.4 → 1.4.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -183,6 +183,10 @@ interface AIMarkdownTypographyProps extends PropsWithChildren {
183
183
  * `font-size: var(--aim-font-size-root)` to opt out of `em` compounding
184
184
  * when a stable size is needed.
185
185
  *
186
+ * The built-in `default` variant consumes this variable: its spacing,
187
+ * font-size, and heading tokens are defined as `calc(var(--aim-font-size-root) * k)`,
188
+ * so the `fontSize` prop proportionally scales every rendered dimension.
189
+ *
186
190
  * @example
187
191
  * ```tsx
188
192
  * const MyTypography: AIMarkdownTypographyComponent = ({ children, fontSize, style }) => (
@@ -234,6 +238,27 @@ interface AIMarkdownRenderState<TConfig extends AIMarkdownRenderConfig = AIMarkd
234
238
  * always win.
235
239
  */
236
240
  documentId: string;
241
+ /**
242
+ * Whether {@link documentId} was EXPLICITLY supplied by the consumer (vs.
243
+ * auto-generated via `useId()`). This is the coordination signal — NOT
244
+ * `documentId` truthiness, which is always `true` because the provider
245
+ * auto-fills a fallback id for HTML/`clobberPrefix` purposes.
246
+ *
247
+ * `useDocumentRegistry` gates on this: an auto-generated id is unique by
248
+ * construction, so a chunk that didn't receive a `documentId` has nothing
249
+ * to coordinate with even when it sits inside `<AIMarkdownDocuments>`. It
250
+ * must take the standalone (registry === null) path, and this flag is the
251
+ * only thing that lets the registry hook tell "consumer wants coordination"
252
+ * apart from "we fabricated an id so the markup stays valid".
253
+ *
254
+ * Optional in the type ONLY so external callers that construct an
255
+ * `AIMarkdownRenderState` literal directly (mocks, fixtures) aren't broken
256
+ * by this internally-added field — the provider ALWAYS sets a concrete
257
+ * boolean, and internal consumers coerce a missing value to `false`
258
+ * (safe default: no coordination). Keeping it `?:` preserves source-level
259
+ * backward compatibility for the publicly-exported state type.
260
+ */
261
+ documentIdExplicit?: boolean;
237
262
  /**
238
263
  * Per-document URI-safe id prefix used by all clobberable attributes
239
264
  * (`id="…"` / `href="#…"`). Derived once by the provider and exposed here
@@ -814,8 +839,10 @@ type SanitizeSchema = typeof defaultSchema;
814
839
  * });
815
840
  * ```
816
841
  *
817
- * @remarks Allowing a protocol on `protocols.href` lets the URL through the
818
- * SECOND sanitize gate. The FIRST gate (`urlTransform`) must permit the
842
+ * @remarks Allowing a protocol on `protocols.href` lets the URL through
843
+ * Gate 1 (the schema-level per-protocol allowlist, which runs inside the
844
+ * rehype plugin chain). Gate 2 (`urlTransform`, the per-attribute rewriter
845
+ * that runs later at render time in `renderHastSubtree`) must permit the
819
846
  * same protocol independently — see the `urlTransform` prop on
820
847
  * `<AIMarkdown>` and the exported {@link defaultUrlTransform} for
821
848
  * composition. Keep the two protocol lists in sync.
@@ -1018,11 +1045,23 @@ declare const AIMarkdownDocuments: FC<AIMarkdownDocumentsProps>;
1018
1045
  /**
1019
1046
  * Returns the registry for the given `documentId`, or `null` if:
1020
1047
  * - `<AIMarkdown>` is not inside an `<AIMarkdownDocuments>` wrapper, OR
1021
- * - `documentId` is undefined / empty string.
1048
+ * - `documentId` is undefined / empty string, OR
1049
+ * - `documentIdExplicit` is `false` — i.e. the id was auto-generated rather
1050
+ * than supplied by the consumer.
1051
+ *
1052
+ * The `documentIdExplicit` gate is the crux of the standalone-vs-coordinated
1053
+ * decision. An auto-generated id (`useId()` fallback) is non-empty and unique
1054
+ * by construction, so a chunk carrying one has nothing to coordinate with even
1055
+ * inside the wrapper — it must run standalone. Without this gate, the mere
1056
+ * presence of `<AIMarkdownDocuments>` would drag every uncoordinated chunk
1057
+ * onto the cross-chunk registry path (subscribe / allocate / evict overhead)
1058
+ * for no behavioral gain. The flag defaults to `true` so external callers who
1059
+ * pass an id directly are treated as explicit (passing an id IS the intent to
1060
+ * coordinate); the internal renderer threads through `state.documentIdExplicit`.
1022
1061
  *
1023
1062
  * Callers should treat `null` as "no coordination; run standalone path."
1024
1063
  */
1025
- declare function useDocumentRegistry(documentId: string | undefined): Registry | null;
1064
+ declare function useDocumentRegistry(documentId: string | undefined, documentIdExplicit?: boolean): Registry | null;
1026
1065
 
1027
1066
  /**
1028
1067
  * Props for the `<AIMarkdown>` component.
@@ -1095,10 +1134,14 @@ interface AIMarkdownProps<TConfig extends AIMarkdownRenderConfig = AIMarkdownRen
1095
1134
  */
1096
1135
  documentId?: string;
1097
1136
  /**
1098
- * Override the function that decides which URL protocols are allowed
1099
- * through the FIRST sanitization gate. The default allowlist mirrors
1100
- * `react-markdown` / GitHub: `http`, `https`, `irc`, `ircs`, `mailto`,
1101
- * `xmpp`. Anything else is rewritten to `''`.
1137
+ * Override the per-attribute URL rewriter (Gate 2 of the two-gate model).
1138
+ * Runs at render time during the hast traversal in `renderHastSubtree`,
1139
+ * after Gate 1 (`rehype-sanitize` schema) has already filtered URLs by
1140
+ * protocol allowlist in the rehype plugin chain.
1141
+ *
1142
+ * The default allowlist mirrors `react-markdown` / GitHub: `http`,
1143
+ * `https`, `irc`, `ircs`, `mailto`, `xmpp`. Anything else is rewritten
1144
+ * to `''`.
1102
1145
  *
1103
1146
  * **Recommended pattern**: compose with the exported
1104
1147
  * {@link defaultUrlTransform} so the built-in XSS protections survive,
@@ -1127,13 +1170,13 @@ interface AIMarkdownProps<TConfig extends AIMarkdownRenderConfig = AIMarkdownRen
1127
1170
  * as a dependency. Defining the function inline (`urlTransform={(url) =>
1128
1171
  * …}`) creates a new closure on every parent render, discards the cache
1129
1172
  * for the entire markdown document on each render, and effectively
1130
- * disables Phase 5 memoization. In development the library will
1173
+ * disables block-level memoization. In development the library will
1131
1174
  * `console.warn` if it detects this pattern.
1132
1175
  *
1133
1176
  * Allowing a protocol here is necessary but **not sufficient** to render
1134
- * a link — the second gate (`rehype-sanitize`) also enforces its own
1135
- * protocol allowlist. See the `sanitizeSchema` prop on this component
1136
- * and the {@link extendSanitizeSchema} helper for the second gate.
1177
+ * a link — Gate 1 (`rehype-sanitize` schema) also enforces its own
1178
+ * protocol allowlist and runs first. See the `sanitizeSchema` prop on
1179
+ * this component and the {@link extendSanitizeSchema} helper for Gate 1.
1137
1180
  *
1138
1181
  * **API stability**: the `UrlTransform` type tracks the upstream
1139
1182
  * `react-markdown` shape and may change with its major versions.
@@ -1142,10 +1185,13 @@ interface AIMarkdownProps<TConfig extends AIMarkdownRenderConfig = AIMarkdownRen
1142
1185
  /**
1143
1186
  * Override the `rehype-sanitize` schema applied to the rendered output.
1144
1187
  * The library default extends `rehype-sanitize`'s own `defaultSchema`
1145
- * with the `<mark>` tag, KaTeX class names, and the cross-chunk
1146
- * coordination tags (`cross-chunk-link`, `cross-chunk-image`,
1147
- * `footnote-sup`). The default is not exported as a value — see
1148
- * {@link extendSanitizeSchema} for how to inspect or extend it safely.
1188
+ * with the `<mark>` tag, the `math-inline` / `math-display` className
1189
+ * markers `remark-math` emits on `<code>` (KaTeX's own output classes
1190
+ * survive separately because `rehype-katex` runs after `rehype-sanitize`),
1191
+ * and the cross-chunk coordination tags (`cross-chunk-link`,
1192
+ * `cross-chunk-image`, `footnote-sup`). The default is not exported as a
1193
+ * value — see {@link extendSanitizeSchema} for how to inspect or extend
1194
+ * it safely.
1149
1195
  *
1150
1196
  * **Recommended pattern**: build the schema with {@link extendSanitizeSchema}
1151
1197
  * (mutate-and-return form) so those library additions stay intact, and
package/dist/index.d.ts CHANGED
@@ -183,6 +183,10 @@ interface AIMarkdownTypographyProps extends PropsWithChildren {
183
183
  * `font-size: var(--aim-font-size-root)` to opt out of `em` compounding
184
184
  * when a stable size is needed.
185
185
  *
186
+ * The built-in `default` variant consumes this variable: its spacing,
187
+ * font-size, and heading tokens are defined as `calc(var(--aim-font-size-root) * k)`,
188
+ * so the `fontSize` prop proportionally scales every rendered dimension.
189
+ *
186
190
  * @example
187
191
  * ```tsx
188
192
  * const MyTypography: AIMarkdownTypographyComponent = ({ children, fontSize, style }) => (
@@ -234,6 +238,27 @@ interface AIMarkdownRenderState<TConfig extends AIMarkdownRenderConfig = AIMarkd
234
238
  * always win.
235
239
  */
236
240
  documentId: string;
241
+ /**
242
+ * Whether {@link documentId} was EXPLICITLY supplied by the consumer (vs.
243
+ * auto-generated via `useId()`). This is the coordination signal — NOT
244
+ * `documentId` truthiness, which is always `true` because the provider
245
+ * auto-fills a fallback id for HTML/`clobberPrefix` purposes.
246
+ *
247
+ * `useDocumentRegistry` gates on this: an auto-generated id is unique by
248
+ * construction, so a chunk that didn't receive a `documentId` has nothing
249
+ * to coordinate with even when it sits inside `<AIMarkdownDocuments>`. It
250
+ * must take the standalone (registry === null) path, and this flag is the
251
+ * only thing that lets the registry hook tell "consumer wants coordination"
252
+ * apart from "we fabricated an id so the markup stays valid".
253
+ *
254
+ * Optional in the type ONLY so external callers that construct an
255
+ * `AIMarkdownRenderState` literal directly (mocks, fixtures) aren't broken
256
+ * by this internally-added field — the provider ALWAYS sets a concrete
257
+ * boolean, and internal consumers coerce a missing value to `false`
258
+ * (safe default: no coordination). Keeping it `?:` preserves source-level
259
+ * backward compatibility for the publicly-exported state type.
260
+ */
261
+ documentIdExplicit?: boolean;
237
262
  /**
238
263
  * Per-document URI-safe id prefix used by all clobberable attributes
239
264
  * (`id="…"` / `href="#…"`). Derived once by the provider and exposed here
@@ -814,8 +839,10 @@ type SanitizeSchema = typeof defaultSchema;
814
839
  * });
815
840
  * ```
816
841
  *
817
- * @remarks Allowing a protocol on `protocols.href` lets the URL through the
818
- * SECOND sanitize gate. The FIRST gate (`urlTransform`) must permit the
842
+ * @remarks Allowing a protocol on `protocols.href` lets the URL through
843
+ * Gate 1 (the schema-level per-protocol allowlist, which runs inside the
844
+ * rehype plugin chain). Gate 2 (`urlTransform`, the per-attribute rewriter
845
+ * that runs later at render time in `renderHastSubtree`) must permit the
819
846
  * same protocol independently — see the `urlTransform` prop on
820
847
  * `<AIMarkdown>` and the exported {@link defaultUrlTransform} for
821
848
  * composition. Keep the two protocol lists in sync.
@@ -1018,11 +1045,23 @@ declare const AIMarkdownDocuments: FC<AIMarkdownDocumentsProps>;
1018
1045
  /**
1019
1046
  * Returns the registry for the given `documentId`, or `null` if:
1020
1047
  * - `<AIMarkdown>` is not inside an `<AIMarkdownDocuments>` wrapper, OR
1021
- * - `documentId` is undefined / empty string.
1048
+ * - `documentId` is undefined / empty string, OR
1049
+ * - `documentIdExplicit` is `false` — i.e. the id was auto-generated rather
1050
+ * than supplied by the consumer.
1051
+ *
1052
+ * The `documentIdExplicit` gate is the crux of the standalone-vs-coordinated
1053
+ * decision. An auto-generated id (`useId()` fallback) is non-empty and unique
1054
+ * by construction, so a chunk carrying one has nothing to coordinate with even
1055
+ * inside the wrapper — it must run standalone. Without this gate, the mere
1056
+ * presence of `<AIMarkdownDocuments>` would drag every uncoordinated chunk
1057
+ * onto the cross-chunk registry path (subscribe / allocate / evict overhead)
1058
+ * for no behavioral gain. The flag defaults to `true` so external callers who
1059
+ * pass an id directly are treated as explicit (passing an id IS the intent to
1060
+ * coordinate); the internal renderer threads through `state.documentIdExplicit`.
1022
1061
  *
1023
1062
  * Callers should treat `null` as "no coordination; run standalone path."
1024
1063
  */
1025
- declare function useDocumentRegistry(documentId: string | undefined): Registry | null;
1064
+ declare function useDocumentRegistry(documentId: string | undefined, documentIdExplicit?: boolean): Registry | null;
1026
1065
 
1027
1066
  /**
1028
1067
  * Props for the `<AIMarkdown>` component.
@@ -1095,10 +1134,14 @@ interface AIMarkdownProps<TConfig extends AIMarkdownRenderConfig = AIMarkdownRen
1095
1134
  */
1096
1135
  documentId?: string;
1097
1136
  /**
1098
- * Override the function that decides which URL protocols are allowed
1099
- * through the FIRST sanitization gate. The default allowlist mirrors
1100
- * `react-markdown` / GitHub: `http`, `https`, `irc`, `ircs`, `mailto`,
1101
- * `xmpp`. Anything else is rewritten to `''`.
1137
+ * Override the per-attribute URL rewriter (Gate 2 of the two-gate model).
1138
+ * Runs at render time during the hast traversal in `renderHastSubtree`,
1139
+ * after Gate 1 (`rehype-sanitize` schema) has already filtered URLs by
1140
+ * protocol allowlist in the rehype plugin chain.
1141
+ *
1142
+ * The default allowlist mirrors `react-markdown` / GitHub: `http`,
1143
+ * `https`, `irc`, `ircs`, `mailto`, `xmpp`. Anything else is rewritten
1144
+ * to `''`.
1102
1145
  *
1103
1146
  * **Recommended pattern**: compose with the exported
1104
1147
  * {@link defaultUrlTransform} so the built-in XSS protections survive,
@@ -1127,13 +1170,13 @@ interface AIMarkdownProps<TConfig extends AIMarkdownRenderConfig = AIMarkdownRen
1127
1170
  * as a dependency. Defining the function inline (`urlTransform={(url) =>
1128
1171
  * …}`) creates a new closure on every parent render, discards the cache
1129
1172
  * for the entire markdown document on each render, and effectively
1130
- * disables Phase 5 memoization. In development the library will
1173
+ * disables block-level memoization. In development the library will
1131
1174
  * `console.warn` if it detects this pattern.
1132
1175
  *
1133
1176
  * Allowing a protocol here is necessary but **not sufficient** to render
1134
- * a link — the second gate (`rehype-sanitize`) also enforces its own
1135
- * protocol allowlist. See the `sanitizeSchema` prop on this component
1136
- * and the {@link extendSanitizeSchema} helper for the second gate.
1177
+ * a link — Gate 1 (`rehype-sanitize` schema) also enforces its own
1178
+ * protocol allowlist and runs first. See the `sanitizeSchema` prop on
1179
+ * this component and the {@link extendSanitizeSchema} helper for Gate 1.
1137
1180
  *
1138
1181
  * **API stability**: the `UrlTransform` type tracks the upstream
1139
1182
  * `react-markdown` shape and may change with its major versions.
@@ -1142,10 +1185,13 @@ interface AIMarkdownProps<TConfig extends AIMarkdownRenderConfig = AIMarkdownRen
1142
1185
  /**
1143
1186
  * Override the `rehype-sanitize` schema applied to the rendered output.
1144
1187
  * The library default extends `rehype-sanitize`'s own `defaultSchema`
1145
- * with the `<mark>` tag, KaTeX class names, and the cross-chunk
1146
- * coordination tags (`cross-chunk-link`, `cross-chunk-image`,
1147
- * `footnote-sup`). The default is not exported as a value — see
1148
- * {@link extendSanitizeSchema} for how to inspect or extend it safely.
1188
+ * with the `<mark>` tag, the `math-inline` / `math-display` className
1189
+ * markers `remark-math` emits on `<code>` (KaTeX's own output classes
1190
+ * survive separately because `rehype-katex` runs after `rehype-sanitize`),
1191
+ * and the cross-chunk coordination tags (`cross-chunk-link`,
1192
+ * `cross-chunk-image`, `footnote-sup`). The default is not exported as a
1193
+ * value — see {@link extendSanitizeSchema} for how to inspect or extend
1194
+ * it safely.
1149
1195
  *
1150
1196
  * **Recommended pattern**: build the schema with {@link extendSanitizeSchema}
1151
1197
  * (mutate-and-return form) so those library additions stay intact, and