@fusion.dev/helix 0.108.2 → 0.109.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/dist/rehype.d.ts CHANGED
@@ -1,11 +1,12 @@
1
1
  /**
2
- * **A rehype plugin that gives Markdown's two missing constructs their Helix
2
+ * **A rehype plugin that gives Markdown's fences, alerts and tables their Helix
3
3
  * elements, and parses nothing.** Your Markdown library turns `###` into
4
- * `<h3>`, and `data-prose` styles the HTML it writes. Two constructs carry
4
+ * `<h3>`, and `data-prose` styles the HTML it writes. Three constructs carry
5
5
  * what plain HTML cannot: a code fence, which a reader copies and which has a
6
- * language, and a GitHub alert, which says how much a passage matters. This
7
- * rewrites those two in the tree your parser already built, after your own
8
- * sanitizing, and leaves everything else as it is.
6
+ * language; a GitHub alert, which says how much a passage matters; and a
7
+ * table, whose values must stay whole on a narrow screen. This rewrites those
8
+ * three in the tree your parser already built, after your own sanitizing, and
9
+ * leaves everything else as it is.
9
10
  *
10
11
  * - A fence becomes `helix-code-block`, labeled with its language. What is
11
12
  * inside the code is kept, so a highlighter that ran before this has its
@@ -14,6 +15,13 @@
14
15
  * note is `info`, a tip `success`, a warning `warning`, and a caution
15
16
  * `danger`. An important passage has no tone, since none of the four says
16
17
  * it. Each keeps its kind as its heading, as GitHub shows it.
18
+ * - A table becomes `helix-table`: its header row becomes its columns, each
19
+ * aligned as the Markdown aligned it, and every other row a
20
+ * `helix-table-row` of `helix-table-cell`. The table sizes its columns from
21
+ * what they hold, so a column of values stays whole and a column of
22
+ * sentences wraps. A table the grid cannot draw as written, with a caption,
23
+ * a cell spanning more than one column or row, or a heading cell outside the
24
+ * one header row, stays a table.
17
25
  *
18
26
  * Any pipeline that reaches rehype takes it: `remark` with `remark-rehype`,
19
27
  * `react-markdown`, and MDX.
@@ -45,10 +53,13 @@ export interface RehypeHelixOptions {
45
53
  fences?: boolean | undefined;
46
54
  /** An alert's heading by its kind, for a page in another language. English by default. */
47
55
  headings?: Partial<Record<AlertKind, string>> | undefined;
56
+ /** Whether tables become Helix tables. `true` by default. */
57
+ tables?: boolean | undefined;
48
58
  }
49
59
  /**
50
60
  * The plugin: rewrites the tree in place, from the top down, so a fence
51
- * inside an alert becomes a code block inside a callout.
61
+ * inside an alert becomes a code block inside a callout, and a table inside
62
+ * one a Helix table.
52
63
  */
53
64
  export default function rehypeHelix(options?: RehypeHelixOptions): (tree: HastNode) => void;
54
65
  export { rehypeHelix };
package/dist/rehype.js CHANGED
@@ -77,6 +77,48 @@ const calloutOf = (node, headings) => {
77
77
  type: 'element',
78
78
  };
79
79
  };
80
+ const EDGES = {
81
+ center: 'center',
82
+ left: 'start',
83
+ right: 'end',
84
+ };
85
+ const spans = (cell) => Number(cell.properties?.colSpan ?? 1) > 1 || Number(cell.properties?.rowSpan ?? 1) > 1;
86
+ const helix = (tagName, children, properties = {}) => ({
87
+ children,
88
+ properties,
89
+ tagName,
90
+ type: 'element',
91
+ });
92
+ const tableOf = (node) => {
93
+ if (node.tagName !== 'table') {
94
+ return undefined;
95
+ }
96
+ const head = [];
97
+ const body = [];
98
+ for (const group of elements(node)) {
99
+ const rows = group.tagName === 'tr' ? [group] : elements(group);
100
+ if (!['tbody', 'tfoot', 'thead', 'tr'].includes(group.tagName ?? '') ||
101
+ rows.some((row) => row.tagName !== 'tr')) {
102
+ return undefined;
103
+ }
104
+ ;
105
+ (group.tagName === 'thead' ? head : body).push(...rows);
106
+ }
107
+ const [heading] = head;
108
+ const headings = heading ? elements(heading) : [];
109
+ const cells = body.map((row) => elements(row));
110
+ if (head.length !== 1 ||
111
+ headings.some((cell) => cell.tagName !== 'th' || spans(cell)) ||
112
+ cells.some((row) => row.some((cell) => cell.tagName !== 'td' || spans(cell)))) {
113
+ return undefined;
114
+ }
115
+ const columns = headings.map((cell) => {
116
+ const edge = EDGES[String(cell.properties?.align)];
117
+ return helix('helix-table-column', cell.children ?? [], edge ? { 'text-align': edge } : {});
118
+ });
119
+ const rows = cells.map((row) => helix('helix-table-row', row.map((cell) => helix('helix-table-cell', cell.children ?? []))));
120
+ return helix('helix-table', [...columns, ...rows]);
121
+ };
80
122
  export default function rehypeHelix(options = {}) {
81
123
  const headings = { ...HEADINGS, ...options.headings };
82
124
  const rewrite = (node) => {
@@ -86,7 +128,8 @@ export default function rehypeHelix(options = {}) {
86
128
  }
87
129
  children.forEach((child, index) => {
88
130
  const replaced = (options.fences !== false ? codeBlockOf(child) : undefined) ??
89
- (options.alerts !== false ? calloutOf(child, headings) : undefined);
131
+ (options.alerts !== false ? calloutOf(child, headings) : undefined) ??
132
+ (options.tables !== false ? tableOf(child) : undefined);
90
133
  if (replaced) {
91
134
  children[index] = replaced;
92
135
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@fusion.dev/helix",
3
3
  "description": "Styled component tier. Extends the headless tier with token-driven presentation.",
4
- "version": "0.108.2",
4
+ "version": "0.109.0",
5
5
  "license": "MIT",
6
6
  "author": "Ross Sheppard <ross.sheppard@fusion.dev>",
7
7
  "repository": {
@@ -51,18 +51,19 @@
51
51
  },
52
52
  "bugs": "https://github.com/project-fusion/fusion/issues",
53
53
  "dependencies": {
54
- "@fusion.dev/helix-core": "0.108.2",
55
- "@fusion.dev/helix-headless": "0.108.2",
56
- "@fusion.dev/helix-styles": "0.108.2"
54
+ "@fusion.dev/helix-core": "0.109.0",
55
+ "@fusion.dev/helix-headless": "0.109.0",
56
+ "@fusion.dev/helix-styles": "0.109.0"
57
57
  },
58
58
  "devDependencies": {
59
- "@fusion.dev/helix-cem": "0.108.2",
60
- "@fusion.dev/helix-testing": "0.108.2",
59
+ "@fusion.dev/helix-cem": "0.109.0",
60
+ "@fusion.dev/helix-testing": "0.109.0",
61
61
  "@fusion.dev/scripts": "0.0.0-dev",
62
62
  "@happy-dom/global-registrator": "^20.0.0",
63
63
  "@lit-labs/ssr": "^4.1.0",
64
64
  "@types/bun": "^1.3.0",
65
65
  "lit": "^3.2.1",
66
+ "remark-gfm": "^4.0.1",
66
67
  "remark-parse": "^11.0.0",
67
68
  "remark-rehype": "^11.1.2",
68
69
  "unified": "^11.0.5"