@godxjp/markdown 31.22.1 → 31.23.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 CHANGED
@@ -22,6 +22,9 @@ GFM — tables, task lists (read-only), fenced code with `language-*` classes, a
22
22
  strikethrough — and an `id` on every heading (GitHub slugs, de-duplicated). The output is the same
23
23
  as `react-markdown` + `remark-gfm` + `rehype-sanitize`, which is what the apps rendered before.
24
24
 
25
+ Every table renders inside a scroll box (`.ui-prose-table-scroll`, styled by `Prose`), keyboard-
26
+ focusable only while it overflows, so a wide table scrolls instead of widening the page.
27
+
25
28
  ## Safety
26
29
 
27
30
  - **No raw HTML.** HTML in the source is dropped, never parsed into elements.
package/dist/index.d.ts CHANGED
@@ -73,7 +73,7 @@ type PluggableList = NonNullable<Options$1["remarkPlugins"]>;
73
73
  * differently — a schema change, a new default plugin — not on every release.
74
74
  */
75
75
  declare const MARKDOWN_FORMAT = "md";
76
- declare const RENDERER_VERSION = 1;
76
+ declare const RENDERER_VERSION = 2;
77
77
  type MarkdownProps = {
78
78
  /** The Markdown source. */
79
79
  children: string;
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  // src/markdown.tsx
4
- import * as React2 from "react";
4
+ import * as React3 from "react";
5
5
  import ReactMarkdown from "react-markdown";
6
6
  import rehypeSanitize from "rehype-sanitize";
7
7
  import remarkGfm from "remark-gfm";
@@ -156,6 +156,34 @@ function MermaidDiagram({ source, label }) {
156
156
  ] });
157
157
  }
158
158
 
159
+ // src/table-scroll.tsx
160
+ import * as React2 from "react";
161
+ import { jsx as jsx2 } from "react/jsx-runtime";
162
+ function TableScroll({ children }) {
163
+ const ref = React2.useRef(null);
164
+ const [scrolls, setScrolls] = React2.useState(false);
165
+ React2.useLayoutEffect(() => {
166
+ const box = ref.current;
167
+ if (!box || typeof ResizeObserver === "undefined") return void 0;
168
+ const measure = () => setScrolls(box.scrollWidth > box.clientWidth + 1);
169
+ const observer = new ResizeObserver(measure);
170
+ observer.observe(box);
171
+ if (box.firstElementChild) observer.observe(box.firstElementChild);
172
+ measure();
173
+ return () => observer.disconnect();
174
+ }, []);
175
+ return /* @__PURE__ */ jsx2(
176
+ "div",
177
+ {
178
+ ref,
179
+ className: "ui-prose-table-scroll",
180
+ "data-slot": "prose-table-scroll",
181
+ tabIndex: scrolls ? 0 : void 0,
182
+ children
183
+ }
184
+ );
185
+ }
186
+
159
187
  // src/schema.ts
160
188
  import { defaultSchema } from "rehype-sanitize";
161
189
  var markdownSchema = {
@@ -214,9 +242,9 @@ function safeUrl(url, key) {
214
242
  }
215
243
 
216
244
  // src/markdown.tsx
217
- import { jsx as jsx2 } from "react/jsx-runtime";
245
+ import { jsx as jsx3 } from "react/jsx-runtime";
218
246
  var MARKDOWN_FORMAT = "md";
219
- var RENDERER_VERSION = 1;
247
+ var RENDERER_VERSION = 2;
220
248
  var URL_ATTRIBUTES = {
221
249
  a: "href",
222
250
  img: "src",
@@ -235,6 +263,10 @@ function rehypeResolveUrls(options) {
235
263
  });
236
264
  };
237
265
  }
266
+ function omitNode(props) {
267
+ const { node: _node, ...rest } = props;
268
+ return rest;
269
+ }
238
270
  function fenceOf(node) {
239
271
  const code = node?.children?.[0];
240
272
  if (!code || code.type !== "element" || code.tagName !== "code") return void 0;
@@ -257,21 +289,23 @@ function Markdown({
257
289
  allowElement,
258
290
  unwrapDisallowed
259
291
  }) {
260
- const sanitizeSchema = React2.useMemo(() => extendSchema(schema), [schema]);
261
- const merged = React2.useMemo(() => {
262
- if (!mermaid) return { ...components };
292
+ const sanitizeSchema = React3.useMemo(() => extendSchema(schema), [schema]);
293
+ const merged = React3.useMemo(() => {
294
+ const HostTable = components?.table;
295
+ const table = (props) => /* @__PURE__ */ jsx3(TableScroll, { children: HostTable ? typeof HostTable === "string" ? React3.createElement(HostTable, props) : /* @__PURE__ */ jsx3(HostTable, { ...props }) : /* @__PURE__ */ jsx3("table", { ...omitNode(props) }) });
296
+ if (!mermaid) return { ...components, table };
263
297
  const HostPre = components?.pre;
264
298
  const pre = (props) => {
265
299
  const fence = fenceOf(props.node);
266
- if (fence?.language === "mermaid") return /* @__PURE__ */ jsx2(MermaidDiagram, { source: fence.text });
300
+ if (fence?.language === "mermaid") return /* @__PURE__ */ jsx3(MermaidDiagram, { source: fence.text });
267
301
  if (HostPre)
268
- return typeof HostPre === "string" ? React2.createElement(HostPre, props) : /* @__PURE__ */ jsx2(HostPre, { ...props });
302
+ return typeof HostPre === "string" ? React3.createElement(HostPre, props) : /* @__PURE__ */ jsx3(HostPre, { ...props });
269
303
  const { node: _node, children: inner, ...rest } = props;
270
- return /* @__PURE__ */ jsx2("pre", { ...rest, children: inner });
304
+ return /* @__PURE__ */ jsx3("pre", { ...rest, children: inner });
271
305
  };
272
- return { ...components, pre };
306
+ return { ...components, table, pre };
273
307
  }, [components, mermaid]);
274
- return /* @__PURE__ */ jsx2(
308
+ return /* @__PURE__ */ jsx3(
275
309
  ReactMarkdown,
276
310
  {
277
311
  remarkPlugins: [remarkGfm, ...remarkPlugins],
@@ -305,9 +339,10 @@ var MARKDOWN_FIXTURES = [
305
339
  html: "<p><em>em</em> <strong>strong</strong> <del>gone</del> <code>code</code></p>"
306
340
  },
307
341
  {
308
- name: "GFM table with alignment",
342
+ name: "GFM table with alignment, in its scroll box",
309
343
  markdown: "| a | b |\n|:--|--:|\n| 1 | 2 |",
310
- html: '<table><thead><tr><th style="text-align:left">a</th><th style="text-align:right">b</th></tr></thead><tbody><tr><td style="text-align:left">1</td><td style="text-align:right">2</td></tr></tbody></table>'
344
+ // Every table sits in its own scroll box (gh#1131, renderer v2).
345
+ html: '<div class="ui-prose-table-scroll" data-slot="prose-table-scroll"><table><thead><tr><th style="text-align:left">a</th><th style="text-align:right">b</th></tr></thead><tbody><tr><td style="text-align:left">1</td><td style="text-align:right">2</td></tr></tbody></table></div>'
311
346
  },
312
347
  {
313
348
  name: "task list stays read-only",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@godxjp/markdown",
3
- "version": "31.22.1",
3
+ "version": "31.23.0",
4
4
  "description": "The one Markdown renderer for GoDX apps: GFM + heading anchors, one sanitiser schema, a shared fixture corpus, and Mermaid drawn only after its SVG passes a fail-closed gate.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",