@ai-react-markdown/core 1.4.1 → 1.4.2
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 +2 -2
- package/dist/index.cjs +67 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -4
- package/dist/index.d.ts +12 -4
- package/dist/index.js +67 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -95,7 +95,7 @@ function StreamingChat({ content, isStreaming }: { content: string; isStreaming:
|
|
|
95
95
|
| `customComponents` | `AIMarkdownCustomComponents` | `undefined` | `react-markdown` component overrides for specific HTML elements. |
|
|
96
96
|
| `Typography` | `AIMarkdownTypographyComponent` | `DefaultTypography` | Typography wrapper component. |
|
|
97
97
|
| `ExtraStyles` | `AIMarkdownExtraStylesComponent` | `undefined` | Optional extra style wrapper rendered between typography and content. |
|
|
98
|
-
| `documentId` | `string` | auto via `useId()` | Stable id for the _logical markdown document_ this `<AIMarkdown>` is rendering. Used as the id namespace for clobberable attributes (`id`, hash hrefs) so two documents on the same page do not cross-link (footnote `[^1]` in message A won't scroll to `[^1]` in message B). When one document is split into chunks rendered by multiple `<AIMarkdown>` instances, pass the SAME `documentId` to every chunk so prefixes align. The value is passed through `encodeURIComponent` before being injected into HTML attributes, so any string is safe (React's `useId()` output, your own opaque ids, user-supplied UUIDs). |
|
|
98
|
+
| `documentId` | `string` | auto via `useId()` | Stable id for the _logical markdown document_ this `<AIMarkdown>` is rendering. Used as the id namespace for clobberable attributes (`id`, hash hrefs) so two documents on the same page do not cross-link (footnote `[^1]` in message A won't scroll to `[^1]` in message B). When one document is split into chunks rendered by multiple `<AIMarkdown>` instances, pass the SAME `documentId` to every chunk so prefixes align. The value is passed through `encodeURIComponent` before being injected into HTML attributes, so any string is safe (React's `useId()` output, your own opaque ids, user-supplied UUIDs). Long ids (>16 chars, e.g. UUIDs) are hashed via MurmurHash3 to a short Base62 form **inside the rendered `id="…"`/`href="#…"` prefix only** to keep HTML compact; `state.documentId` itself and registry keying via `useDocumentRegistry` stay raw, so deep linking and any consumer code reading `documentId` are unaffected. |
|
|
99
99
|
|
|
100
100
|
## Configuration
|
|
101
101
|
|
|
@@ -220,7 +220,7 @@ function CustomCodeBlock({ children }: PropsWithChildren) {
|
|
|
220
220
|
| `variant` | `AIMarkdownVariant` | Active typography variant. |
|
|
221
221
|
| `colorScheme` | `AIMarkdownColorScheme` | Active color scheme. |
|
|
222
222
|
| `documentId` | `string` | Stable id for the logical markdown document — caller-supplied or auto-generated via `useId()`. |
|
|
223
|
-
| `clobberPrefix` | `string` | URI-safe id prefix derived from `documentId
|
|
223
|
+
| `clobberPrefix` | `string` | URI-safe id prefix derived from `documentId` (with MurmurHash3 → Base62 shortening applied for >16-char ids), used by every clobberable HTML attribute (`id=…` / `href="#…"`). Read this from the render state rather than recomputing locally when writing components that emit anchors — the prefix's exact byte form is not part of the stability contract and may shift across versions. |
|
|
224
224
|
| `config` | `TConfig` | Active render configuration (merged with defaults). |
|
|
225
225
|
|
|
226
226
|
### `useAIMarkdownMetadata<TMetadata>()`
|
package/dist/index.cjs
CHANGED
|
@@ -1112,6 +1112,64 @@ var defaultAIMarkdownRenderConfig = Object.freeze({
|
|
|
1112
1112
|
preserveOrphanReferences: true
|
|
1113
1113
|
});
|
|
1114
1114
|
|
|
1115
|
+
// src/components/shortenDocumentId.ts
|
|
1116
|
+
var BASE62_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
1117
|
+
function toBase62(n) {
|
|
1118
|
+
if (n === 0) return BASE62_ALPHABET[0];
|
|
1119
|
+
let v = n >>> 0;
|
|
1120
|
+
let out = "";
|
|
1121
|
+
while (v > 0) {
|
|
1122
|
+
out = BASE62_ALPHABET[v % 62] + out;
|
|
1123
|
+
v = Math.floor(v / 62);
|
|
1124
|
+
}
|
|
1125
|
+
return out;
|
|
1126
|
+
}
|
|
1127
|
+
function rotl32(x, r) {
|
|
1128
|
+
return (x << r | x >>> 32 - r) >>> 0;
|
|
1129
|
+
}
|
|
1130
|
+
var C1 = 3432918353;
|
|
1131
|
+
var C2 = 461845907;
|
|
1132
|
+
var UTF8_ENCODER = /* @__PURE__ */ new TextEncoder();
|
|
1133
|
+
function murmur3_32(s, seed = 0) {
|
|
1134
|
+
const bytes = UTF8_ENCODER.encode(s);
|
|
1135
|
+
const len = bytes.length;
|
|
1136
|
+
let h1 = seed >>> 0;
|
|
1137
|
+
const nblocks = len >>> 2;
|
|
1138
|
+
for (let i = 0; i < nblocks; i++) {
|
|
1139
|
+
const b = i * 4;
|
|
1140
|
+
let k1 = bytes[b] | bytes[b + 1] << 8 | bytes[b + 2] << 16 | bytes[b + 3] << 24;
|
|
1141
|
+
k1 = Math.imul(k1, C1);
|
|
1142
|
+
k1 = rotl32(k1, 15);
|
|
1143
|
+
k1 = Math.imul(k1, C2);
|
|
1144
|
+
h1 ^= k1;
|
|
1145
|
+
h1 = rotl32(h1, 13);
|
|
1146
|
+
h1 = Math.imul(h1, 5) + 3864292196 >>> 0;
|
|
1147
|
+
}
|
|
1148
|
+
const tail = nblocks * 4;
|
|
1149
|
+
const rem = len & 3;
|
|
1150
|
+
if (rem > 0) {
|
|
1151
|
+
let k1 = 0;
|
|
1152
|
+
if (rem === 3) k1 ^= bytes[tail + 2] << 16;
|
|
1153
|
+
if (rem >= 2) k1 ^= bytes[tail + 1] << 8;
|
|
1154
|
+
k1 ^= bytes[tail];
|
|
1155
|
+
k1 = Math.imul(k1, C1);
|
|
1156
|
+
k1 = rotl32(k1, 15);
|
|
1157
|
+
k1 = Math.imul(k1, C2);
|
|
1158
|
+
h1 ^= k1;
|
|
1159
|
+
}
|
|
1160
|
+
h1 ^= len;
|
|
1161
|
+
h1 ^= h1 >>> 16;
|
|
1162
|
+
h1 = Math.imul(h1, 2246822507);
|
|
1163
|
+
h1 ^= h1 >>> 13;
|
|
1164
|
+
h1 = Math.imul(h1, 3266489909);
|
|
1165
|
+
h1 ^= h1 >>> 16;
|
|
1166
|
+
return h1 >>> 0;
|
|
1167
|
+
}
|
|
1168
|
+
function shortenDocumentId(id, threshold = 16) {
|
|
1169
|
+
if (id.length <= threshold) return id;
|
|
1170
|
+
return toBase62(murmur3_32(id));
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1115
1173
|
// src/context.tsx
|
|
1116
1174
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
1117
1175
|
var AIMarkdownRenderStateContext = (0, import_react.createContext)(null);
|
|
@@ -1167,7 +1225,15 @@ var AIMarkdownRenderStateProvider = ({
|
|
|
1167
1225
|
// construction site, not at the documentId storage site, so consumers
|
|
1168
1226
|
// accessing `documentId` directly still see the raw React-native value
|
|
1169
1227
|
// (e.g. `useId()`'s `_r_0_`) while id="..."/href="#..." bytes are safe.
|
|
1170
|
-
|
|
1228
|
+
//
|
|
1229
|
+
// `shortenDocumentId` is applied here (NOT at the documentId storage
|
|
1230
|
+
// site) for the same reason: consumer-supplied UUIDs and nanoids
|
|
1231
|
+
// shouldn't bloat every rendered `id="…"`. Registry keying — which
|
|
1232
|
+
// reads `state.documentId` directly — stays on the raw value, so the
|
|
1233
|
+
// shortening is a pure HTML-output concern and the `useDocumentRegistry`
|
|
1234
|
+
// API surface is unaffected. Pure function ⇒ all chunks sharing one
|
|
1235
|
+
// logical documentId still produce identical prefixes.
|
|
1236
|
+
clobberPrefix: `${encodeURIComponent(shortenDocumentId(resolvedDocumentId))}-user-content-`,
|
|
1171
1237
|
config: mergedConfig
|
|
1172
1238
|
}),
|
|
1173
1239
|
[streaming, fontSize, variant, colorScheme, resolvedDocumentId, mergedConfig]
|