shelving 1.211.0 → 1.212.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/markup/rule/index.d.ts +1 -1
- package/markup/rule/index.js +3 -1
- package/markup/rule/table.d.ts +13 -0
- package/markup/rule/table.js +92 -0
- package/package.json +1 -1
- package/ui/layout/Layout.module.css +1 -1
package/markup/rule/index.d.ts
CHANGED
|
@@ -17,7 +17,6 @@ export declare const MARKUP_RULES_INLINE: MarkupRules;
|
|
|
17
17
|
* - Hard because you have to capture the entire list including `\n\n`, so there's no obvious place to end it.
|
|
18
18
|
* - If there are breaks then any sub-lines need to be indented by two or more spaces otherwise it will break the list.
|
|
19
19
|
* - Make reference lists support this loose format too.
|
|
20
|
-
* @todo [ ] Default rules support tables using `|` pipe syntax.
|
|
21
20
|
* @todo [ ] Default rules support todo lists using `- [x]` syntax.
|
|
22
21
|
* @todo [ ] Default rules support new reference syntax (combines reference lists/sidenotes/footnotes/reference and produces <dl> syntax).
|
|
23
22
|
* - All of these can be the same because reference links and Extended Markdown footnotes are basically the same.
|
|
@@ -44,4 +43,5 @@ export * from "./link.js";
|
|
|
44
43
|
export * from "./ordered.js";
|
|
45
44
|
export * from "./paragraph.js";
|
|
46
45
|
export * from "./separator.js";
|
|
46
|
+
export * from "./table.js";
|
|
47
47
|
export * from "./unordered.js";
|
package/markup/rule/index.js
CHANGED
|
@@ -8,6 +8,7 @@ import { AUTOLINK_RULE, LINK_RULE } from "./link.js";
|
|
|
8
8
|
import { ORDERED_RULE } from "./ordered.js";
|
|
9
9
|
import { PARAGRAPH_RULE } from "./paragraph.js";
|
|
10
10
|
import { SEPARATOR_RULE } from "./separator.js";
|
|
11
|
+
import { TABLE_RULE } from "./table.js";
|
|
11
12
|
import { UNORDERED_RULE } from "./unordered.js";
|
|
12
13
|
/** Markup rules that work in a block context. */
|
|
13
14
|
export const MARKUP_RULES_BLOCK = [
|
|
@@ -17,6 +18,7 @@ export const MARKUP_RULES_BLOCK = [
|
|
|
17
18
|
UNORDERED_RULE,
|
|
18
19
|
ORDERED_RULE,
|
|
19
20
|
BLOCKQUOTE_RULE,
|
|
21
|
+
TABLE_RULE,
|
|
20
22
|
PARAGRAPH_RULE,
|
|
21
23
|
];
|
|
22
24
|
/** Markup rules that work in an inline context. */
|
|
@@ -34,7 +36,6 @@ export const MARKUP_RULES_INLINE = [CODE_RULE, LINK_RULE, AUTOLINK_RULE, INLINE_
|
|
|
34
36
|
* - Hard because you have to capture the entire list including `\n\n`, so there's no obvious place to end it.
|
|
35
37
|
* - If there are breaks then any sub-lines need to be indented by two or more spaces otherwise it will break the list.
|
|
36
38
|
* - Make reference lists support this loose format too.
|
|
37
|
-
* @todo [ ] Default rules support tables using `|` pipe syntax.
|
|
38
39
|
* @todo [ ] Default rules support todo lists using `- [x]` syntax.
|
|
39
40
|
* @todo [ ] Default rules support new reference syntax (combines reference lists/sidenotes/footnotes/reference and produces <dl> syntax).
|
|
40
41
|
* - All of these can be the same because reference links and Extended Markdown footnotes are basically the same.
|
|
@@ -61,4 +62,5 @@ export * from "./link.js";
|
|
|
61
62
|
export * from "./ordered.js";
|
|
62
63
|
export * from "./paragraph.js";
|
|
63
64
|
export * from "./separator.js";
|
|
65
|
+
export * from "./table.js";
|
|
64
66
|
export * from "./unordered.js";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Regular expression matching a table block: a header row, a delimiter row, then any number of pipe rows. */
|
|
2
|
+
export declare const TABLE_REGEXP: import("../../index.js").NamedRegExp<{
|
|
3
|
+
table: string;
|
|
4
|
+
}>;
|
|
5
|
+
/**
|
|
6
|
+
* Table.
|
|
7
|
+
* - Markdown-style pipe table: a header row, a `|---|` delimiter row, then body rows.
|
|
8
|
+
* - Cells are pipe-separated; outer pipes are optional and whitespace around cells is trimmed.
|
|
9
|
+
* - Extra `|---|` delimiter rows split the table into sections: the first section becomes `<thead>`, the last becomes `<tfoot>` (only when there are three or more sections), and every section in between becomes its own `<tbody>`.
|
|
10
|
+
* - Column count and per-column alignment (`:--` left, `--:` right, `:-:` centered) come from the first delimiter row; ragged rows are padded or truncated to that count.
|
|
11
|
+
* - Cell content is rendered as inline markup; write `\|` for a literal pipe inside a cell.
|
|
12
|
+
*/
|
|
13
|
+
export declare const TABLE_RULE: import("../util/rule.js").MarkupRule;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { renderMarkup } from "../render.js";
|
|
2
|
+
import { REACT_ELEMENT_TYPE } from "../util/internal.js";
|
|
3
|
+
import { createBlockRegExp, LINE_SPACE_REGEXP } from "../util/regexp.js";
|
|
4
|
+
import { createMarkupRule } from "../util/rule.js";
|
|
5
|
+
// Constants.
|
|
6
|
+
const _SPACE = `${LINE_SPACE_REGEXP}*`; // Run of line whitespace (never crosses a newline).
|
|
7
|
+
const _CELL = `${_SPACE}:?-+:?${_SPACE}`; // Delimiter-row cell: one or more dashes with optional `:` alignment markers.
|
|
8
|
+
const _DELIMITER_SOURCE = `${_SPACE}\\|?(?:${_CELL}\\|)+(?:${_CELL})?${_SPACE}`; // Delimiter row: pipe-separated dash cells.
|
|
9
|
+
const _DELIMITER = new RegExp(`^${_DELIMITER_SOURCE}$`, "u"); // Tests whether a single line is a delimiter row.
|
|
10
|
+
const _ROW = "[^\\n]*\\|[^\\n]*"; // Any line containing at least one pipe.
|
|
11
|
+
const _SPLIT = /(?<!\\)\|/; // Splits a row into cells on unescaped pipes.
|
|
12
|
+
/** Regular expression matching a table block: a header row, a delimiter row, then any number of pipe rows. */
|
|
13
|
+
export const TABLE_REGEXP = createBlockRegExp(`(?<table>${_ROW}\\n${_DELIMITER_SOURCE}(?:\\n${_ROW})*)`);
|
|
14
|
+
/**
|
|
15
|
+
* Table.
|
|
16
|
+
* - Markdown-style pipe table: a header row, a `|---|` delimiter row, then body rows.
|
|
17
|
+
* - Cells are pipe-separated; outer pipes are optional and whitespace around cells is trimmed.
|
|
18
|
+
* - Extra `|---|` delimiter rows split the table into sections: the first section becomes `<thead>`, the last becomes `<tfoot>` (only when there are three or more sections), and every section in between becomes its own `<tbody>`.
|
|
19
|
+
* - Column count and per-column alignment (`:--` left, `--:` right, `:-:` centered) come from the first delimiter row; ragged rows are padded or truncated to that count.
|
|
20
|
+
* - Cell content is rendered as inline markup; write `\|` for a literal pipe inside a cell.
|
|
21
|
+
*/
|
|
22
|
+
export const TABLE_RULE = createMarkupRule(TABLE_REGEXP, ({ groups: { table } }, options, key) => _renderTable(table, options, key), [
|
|
23
|
+
"block",
|
|
24
|
+
]);
|
|
25
|
+
/** Render a matched table block into a `<table>` element. */
|
|
26
|
+
function _renderTable(table, options, key) {
|
|
27
|
+
const lines = table.split("\n");
|
|
28
|
+
// Column count and alignment come from the first delimiter row — always line 1, guaranteed by `TABLE_REGEXP`.
|
|
29
|
+
const aligns = _splitRow(lines[1] ?? "").map(_getAlign);
|
|
30
|
+
// Split lines into sections at delimiter rows. Line 0 is the header and is never treated as a delimiter.
|
|
31
|
+
const sections = [];
|
|
32
|
+
let section = [lines[0] ?? ""];
|
|
33
|
+
for (let i = 1; i < lines.length; i++) {
|
|
34
|
+
const line = lines[i] ?? "";
|
|
35
|
+
if (_DELIMITER.test(line)) {
|
|
36
|
+
sections.push(section);
|
|
37
|
+
section = [];
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
section.push(line);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
sections.push(section);
|
|
44
|
+
// First section is `<thead>`; the last is `<tfoot>` when there are 3+ sections; sections in between are each a `<tbody>`.
|
|
45
|
+
const last = sections.length - 1;
|
|
46
|
+
const children = sections.map((rows, s) => {
|
|
47
|
+
const type = s === 0 ? "thead" : s === last && last >= 2 ? "tfoot" : "tbody";
|
|
48
|
+
return {
|
|
49
|
+
$$typeof: REACT_ELEMENT_TYPE,
|
|
50
|
+
type,
|
|
51
|
+
key: `${type}-${s}`,
|
|
52
|
+
props: { children: Array.from(_renderRows(rows, s === 0 ? "th" : "td", aligns, options)) },
|
|
53
|
+
};
|
|
54
|
+
});
|
|
55
|
+
return { key, $$typeof: REACT_ELEMENT_TYPE, type: "table", props: { children } };
|
|
56
|
+
}
|
|
57
|
+
/** Render the rows of one section into `<tr>` elements of `<th>` or `<td>` cells. */
|
|
58
|
+
function* _renderRows(rows, cell, aligns, options) {
|
|
59
|
+
let r = 0;
|
|
60
|
+
for (const row of rows) {
|
|
61
|
+
const values = _splitRow(row);
|
|
62
|
+
const cells = aligns.map((align, c) => {
|
|
63
|
+
const children = renderMarkup(values[c] ?? "", options, "inline");
|
|
64
|
+
return {
|
|
65
|
+
$$typeof: REACT_ELEMENT_TYPE,
|
|
66
|
+
type: cell,
|
|
67
|
+
key: c.toString(),
|
|
68
|
+
props: align ? { align, children } : { children },
|
|
69
|
+
};
|
|
70
|
+
});
|
|
71
|
+
yield { $$typeof: REACT_ELEMENT_TYPE, type: "tr", key: (r++).toString(), props: { children: cells } };
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/** Split a table row into trimmed cell strings, honouring `\|` escaped pipes. */
|
|
75
|
+
function _splitRow(row) {
|
|
76
|
+
let line = row.trim();
|
|
77
|
+
if (line.startsWith("|"))
|
|
78
|
+
line = line.slice(1);
|
|
79
|
+
if (line.endsWith("|"))
|
|
80
|
+
line = line.slice(0, -1);
|
|
81
|
+
return line.split(_SPLIT).map(cell => cell.trim().replaceAll("\\|", "|"));
|
|
82
|
+
}
|
|
83
|
+
/** Get the alignment of a delimiter-row cell, or `undefined` for the default (left). */
|
|
84
|
+
function _getAlign(cell) {
|
|
85
|
+
const start = cell.startsWith(":");
|
|
86
|
+
const end = cell.endsWith(":");
|
|
87
|
+
if (start && end)
|
|
88
|
+
return "center";
|
|
89
|
+
if (end)
|
|
90
|
+
return "right";
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
package/package.json
CHANGED
|
@@ -15,7 +15,7 @@ html:has(.layout) {
|
|
|
15
15
|
width: 100vw;
|
|
16
16
|
width: 100dvw;
|
|
17
17
|
overflow: hidden;
|
|
18
|
-
overflow-wrap: anywhere
|
|
18
|
+
overflow-wrap: break-word; /* Break overlong words only as a last resort; `anywhere` would also break mid-word to fit narrow table/flex columns. */
|
|
19
19
|
overscroll-behavior: none;
|
|
20
20
|
}
|
|
21
21
|
|