@astryxdesign/core 0.6.1 → 0.6.2-canary.176dfa6
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/CHANGELOG.md +33 -0
- package/dist/BottomSheet/BottomSheet.d.ts +1 -1
- package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheet.js +3 -1
- package/dist/BottomSheet/BottomSheetPanel.d.ts +7 -5
- package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheetPanel.js +56 -19
- package/dist/DateRangeInput/DateRangeInput.d.ts +3 -0
- package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.js +16 -9
- package/dist/Dialog/DialogHeader.d.ts +1 -1
- package/dist/Dialog/DialogHeader.d.ts.map +1 -1
- package/dist/Dialog/DialogHeader.js +10 -7
- package/dist/FileInput/FileInput.d.ts.map +1 -1
- package/dist/FileInput/FileInput.js +9 -3
- package/dist/Markdown/Markdown.d.ts +10 -2
- package/dist/Markdown/Markdown.d.ts.map +1 -1
- package/dist/Markdown/Markdown.js +58 -14
- package/dist/Markdown/index.d.ts +1 -1
- package/dist/Markdown/index.d.ts.map +1 -1
- package/dist/Markdown/parser.d.ts +126 -12
- package/dist/Markdown/parser.d.ts.map +1 -1
- package/dist/Markdown/parser.js +369 -34
- package/dist/Markdown/utils.d.ts +1 -1
- package/dist/Markdown/utils.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearchEditPopover.js +46 -30
- package/dist/Slider/Slider.d.ts.map +1 -1
- package/dist/Slider/Slider.js +5 -2
- package/dist/Spinner/Spinner.d.ts +1 -1
- package/dist/Spinner/Spinner.d.ts.map +1 -1
- package/dist/Spinner/Spinner.js +23 -15
- package/dist/ToggleButton/ToggleButton.d.ts +2 -1
- package/dist/ToggleButton/ToggleButton.d.ts.map +1 -1
- package/dist/ToggleButton/ToggleButton.js +7 -1
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +15 -6
- package/dist/astryx.css +5 -2
- package/dist/hooks/scrollKeyboardDelegation.d.ts +3 -0
- package/dist/hooks/scrollKeyboardDelegation.d.ts.map +1 -0
- package/dist/hooks/scrollKeyboardDelegation.js +146 -0
- package/dist/hooks/useScrollableArea.d.ts +6 -2
- package/dist/hooks/useScrollableArea.d.ts.map +1 -1
- package/dist/hooks/useScrollableArea.js +17 -5
- package/locales/en.json +16 -0
- package/locales/pseudo.json +12 -0
- package/package.json +7 -5
- package/scripts/agent-doc-state.mjs +1 -1
- package/src/BottomSheet/BottomSheet.doc.mjs +8 -1
- package/src/BottomSheet/BottomSheet.spec.md +46 -20
- package/src/BottomSheet/BottomSheet.test.tsx +6 -3
- package/src/BottomSheet/BottomSheet.tsx +3 -1
- package/src/BottomSheet/BottomSheetKeyboard.test.tsx +195 -0
- package/src/BottomSheet/BottomSheetPanel.test.tsx +11 -1
- package/src/BottomSheet/BottomSheetPanel.tsx +49 -16
- package/src/BottomSheet/__tests__/BottomSheetKeyboard.a11y.browser.spec.ts +344 -0
- package/src/DateRangeInput/DateRangeInput.doc.mjs +35 -7
- package/src/DateRangeInput/DateRangeInput.spec.md +203 -0
- package/src/DateRangeInput/DateRangeInput.test.tsx +100 -4
- package/src/DateRangeInput/DateRangeInput.tsx +29 -20
- package/src/Dialog/Dialog.doc.mjs +3 -0
- package/src/Dialog/Dialog.spec.md +1 -1
- package/src/Dialog/DialogHeader.doc.mjs +38 -0
- package/src/Dialog/DialogHeader.test.tsx +49 -0
- package/src/Dialog/DialogHeader.tsx +23 -4
- package/src/Dialog/modules/DialogHeader.spec.md +152 -0
- package/src/FileInput/FileInput.doc.mjs +2 -0
- package/src/FileInput/FileInput.spec.md +199 -0
- package/src/FileInput/FileInput.test.tsx +14 -0
- package/src/FileInput/FileInput.tsx +13 -3
- package/src/Markdown/Markdown.doc.mjs +167 -42
- package/src/Markdown/Markdown.public.test.ts +157 -0
- package/src/Markdown/Markdown.spec.md +149 -70
- package/src/Markdown/Markdown.test.tsx +107 -3
- package/src/Markdown/Markdown.tsx +116 -35
- package/src/Markdown/incremental.test.ts +175 -7
- package/src/Markdown/index.ts +6 -0
- package/src/Markdown/parser.perf.test.ts +3 -1
- package/src/Markdown/parser.test.ts +122 -0
- package/src/Markdown/parser.ts +609 -81
- package/src/Markdown/utils.ts +6 -0
- package/src/PowerSearch/PowerSearchEditPopover.test.tsx +150 -1
- package/src/PowerSearch/PowerSearchEditPopover.tsx +51 -28
- package/src/ScrollableArea/modules/useScrollableArea.spec.md +50 -22
- package/src/Slider/Slider.doc.mjs +16 -0
- package/src/Slider/Slider.spec.md +61 -47
- package/src/Slider/Slider.test.tsx +18 -0
- package/src/Slider/Slider.tsx +12 -6
- package/src/Spinner/Spinner.doc.mjs +6 -3
- package/src/Spinner/Spinner.test.tsx +37 -0
- package/src/Spinner/Spinner.tsx +31 -14
- package/src/ToggleButton/ToggleButton.test.tsx +133 -0
- package/src/ToggleButton/ToggleButton.tsx +9 -2
- package/src/ToggleButton/__tests__/ToggleButton.a11y.chromium.spec.ts +209 -0
- package/src/Tokenizer/Tokenizer.spec.md +142 -75
- package/src/Typeahead/BaseTypeahead.spec.md +4 -3
- package/src/Typeahead/BaseTypeahead.tsx +15 -6
- package/src/Typeahead/Typeahead.test.tsx +53 -0
- package/src/hooks/scrollKeyboardDelegation.test.ts +155 -0
- package/src/hooks/scrollKeyboardDelegation.ts +233 -0
- package/src/hooks/useScrollableArea.doc.mjs +15 -3
- package/src/hooks/useScrollableArea.test.tsx +59 -1
- package/src/hooks/useScrollableArea.ts +34 -10
- package/src/theme/derivedVarRegistry.test.ts +6 -4
|
@@ -5,8 +5,7 @@ const anatomy = [
|
|
|
5
5
|
{
|
|
6
6
|
name: 'Document',
|
|
7
7
|
required: true,
|
|
8
|
-
description:
|
|
9
|
-
'Root container for block or inline Markdown content.',
|
|
8
|
+
description: 'Root container for block or inline Markdown content.',
|
|
10
9
|
},
|
|
11
10
|
{
|
|
12
11
|
name: 'Heading',
|
|
@@ -41,7 +40,8 @@ const anatomy = [
|
|
|
41
40
|
{
|
|
42
41
|
name: 'Table',
|
|
43
42
|
required: false,
|
|
44
|
-
description:
|
|
43
|
+
description:
|
|
44
|
+
'Scrollable table block rendered from Markdown rows and columns.',
|
|
45
45
|
},
|
|
46
46
|
{
|
|
47
47
|
name: 'Divider',
|
|
@@ -138,14 +138,14 @@ export const docs = {
|
|
|
138
138
|
name: 'contentAlign',
|
|
139
139
|
type: "'start' | 'center'",
|
|
140
140
|
description:
|
|
141
|
-
|
|
141
|
+
'Alignment of prose content within the container when contentWidth is narrower than the available space.',
|
|
142
142
|
default: "'start'",
|
|
143
143
|
},
|
|
144
144
|
{
|
|
145
145
|
name: 'inlinePlugins',
|
|
146
146
|
type: 'MarkdownInlinePlugin[]',
|
|
147
147
|
description:
|
|
148
|
-
'Transforms regex matches in parsed text nodes into custom inline React elements. Use for
|
|
148
|
+
'Transforms regex matches in parsed text nodes into custom inline React elements. Use for prefixed identifiers, mentions, and other shorthand patterns. Inline code, fenced code blocks, and math are unaffected.',
|
|
149
149
|
},
|
|
150
150
|
{
|
|
151
151
|
name: 'autolink',
|
|
@@ -156,7 +156,8 @@ export const docs = {
|
|
|
156
156
|
{
|
|
157
157
|
name: 'components',
|
|
158
158
|
type: 'MarkdownComponents',
|
|
159
|
-
description:
|
|
159
|
+
description:
|
|
160
|
+
'Custom React component overrides for rendered Markdown elements (code, inlineCode, math, link, heading, paragraph, image, blockquote, hr, citation). Providing math enables `$…$` inline and `$$…$$` display parsing and receives `{value, display}`; omit it when dollar text should stay literal.',
|
|
160
161
|
},
|
|
161
162
|
{
|
|
162
163
|
name: 'xstyle',
|
|
@@ -184,7 +185,8 @@ export const docs = {
|
|
|
184
185
|
],
|
|
185
186
|
playground: {
|
|
186
187
|
defaults: {
|
|
187
|
-
children:
|
|
188
|
+
children:
|
|
189
|
+
"## Getting Started\n\nInstall the package:\n\n```bash\nnpm install @astryxdesign/core\n```\n\nThen import and use any component:\n\n```tsx\nimport {Button} from '@astryxdesign/core/Button';\n```\n\n**Bold**, *italic*, and `inline code` all work.",
|
|
188
190
|
},
|
|
189
191
|
},
|
|
190
192
|
theming: {
|
|
@@ -229,11 +231,41 @@ export const docs = {
|
|
|
229
231
|
description:
|
|
230
232
|
'Renders a markdown string as Astryx-styled components. Use Markdown for user-generated content, AI responses, and documentation; it handles headings, lists, tables, code blocks, and citations with consistent styling.',
|
|
231
233
|
bestPractices: [
|
|
232
|
-
{
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
234
|
+
{
|
|
235
|
+
guidance: true,
|
|
236
|
+
description:
|
|
237
|
+
'Set headingLevelStart to match the page hierarchy, e.g. start at 3 if the markdown sits inside an h2 section.',
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
guidance: true,
|
|
241
|
+
description:
|
|
242
|
+
'Use contentWidth to keep prose at a readable line length in wide layouts.',
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
guidance: true,
|
|
246
|
+
description:
|
|
247
|
+
'Use inlinePlugins for prefixed identifiers, mentions, and other prose-only shorthand instead of preprocessing the markdown string.',
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
guidance: true,
|
|
251
|
+
description:
|
|
252
|
+
'Provide components.math only for documents that use dollar-delimited math. The renderer owns typesetting and accessible output; Astryx passes the expression as text and never executes raw HTML.',
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
guidance: true,
|
|
256
|
+
description:
|
|
257
|
+
'For direct parsing, use MathParseOptions and handle InlineNodeWithMath or BlockNodeWithMath. Incremental math parsing also uses createIncrementalState<true>() and IncrementalParseState<true>; default calls and ParseOptions annotations keep the legacy unions.',
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
guidance: true,
|
|
261
|
+
description:
|
|
262
|
+
'Pair with Outline and useOutlineFromMarkdown for section navigation: headings render generated id attributes that match the outline item ids, so hash links scroll to their target.',
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
guidance: false,
|
|
266
|
+
description:
|
|
267
|
+
'Use Markdown for hand-authored layouts; use Text and Heading directly when you control the content.',
|
|
268
|
+
},
|
|
237
269
|
],
|
|
238
270
|
},
|
|
239
271
|
examples: [
|
|
@@ -259,23 +291,38 @@ import {Text} from '@astryxdesign/core/Text';
|
|
|
259
291
|
`,
|
|
260
292
|
},
|
|
261
293
|
{
|
|
262
|
-
label: '
|
|
294
|
+
label: 'Entity links',
|
|
263
295
|
code: `
|
|
264
296
|
import {Link} from '@astryxdesign/core/Link';
|
|
265
297
|
|
|
266
|
-
const
|
|
298
|
+
const entityPlugins = [
|
|
267
299
|
{
|
|
268
300
|
pattern: /\\b([A-Z][A-Z0-9]+-\\d+)\\b/g,
|
|
269
301
|
render: (match, key) => (
|
|
270
|
-
<Link key={key} href={\`/
|
|
302
|
+
<Link key={key} href={\`/entities/\${match[1]}\`}>
|
|
271
303
|
{match[0]}
|
|
272
304
|
</Link>
|
|
273
305
|
),
|
|
274
306
|
},
|
|
275
307
|
];
|
|
276
308
|
|
|
277
|
-
<Markdown inlinePlugins={
|
|
278
|
-
{'
|
|
309
|
+
<Markdown inlinePlugins={entityPlugins}>
|
|
310
|
+
{'See DOC-2048. Inline code stays plain: \`DOC-9999\`.'}
|
|
311
|
+
</Markdown>;
|
|
312
|
+
`,
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
label: 'Math renderer',
|
|
316
|
+
code: `
|
|
317
|
+
import {BlockMath, InlineMath} from 'react-katex';
|
|
318
|
+
|
|
319
|
+
function MathExpression({value, display}) {
|
|
320
|
+
const Component = display === 'block' ? BlockMath : InlineMath;
|
|
321
|
+
return <Component math={value} />;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
<Markdown components={{math: MathExpression}}>
|
|
325
|
+
{'Inline $x_1 + y$ and display math:\\n\\n$$\\n\\\\sum_i x_i\\n$$'}
|
|
279
326
|
</Markdown>;
|
|
280
327
|
`,
|
|
281
328
|
},
|
|
@@ -315,8 +362,7 @@ export const docsZh = {
|
|
|
315
362
|
{
|
|
316
363
|
name: 'isStreaming',
|
|
317
364
|
type: 'boolean',
|
|
318
|
-
description:
|
|
319
|
-
'启用流式模式,使用增量解析和淡入动画处理分块文本。',
|
|
365
|
+
description: '启用流式模式,使用增量解析和淡入动画处理分块文本。',
|
|
320
366
|
default: 'false',
|
|
321
367
|
},
|
|
322
368
|
{
|
|
@@ -348,14 +394,14 @@ export const docsZh = {
|
|
|
348
394
|
name: 'contentAlign',
|
|
349
395
|
type: "'start' | 'center'",
|
|
350
396
|
description:
|
|
351
|
-
|
|
397
|
+
'当 contentWidth 小于可用空间时,正文内容在容器内的对齐方式。',
|
|
352
398
|
default: "'start'",
|
|
353
399
|
},
|
|
354
400
|
{
|
|
355
401
|
name: 'inlinePlugins',
|
|
356
402
|
type: 'MarkdownInlinePlugin[]',
|
|
357
403
|
description:
|
|
358
|
-
'将已解析文本节点中的正则匹配转换为自定义内联 React
|
|
404
|
+
'将已解析文本节点中的正则匹配转换为自定义内联 React 元素。适用于带前缀的标识符、用户提及等简写模式。内联代码、围栏代码块和数学表达式不受影响。',
|
|
359
405
|
},
|
|
360
406
|
{
|
|
361
407
|
name: 'autolink',
|
|
@@ -363,6 +409,12 @@ export const docsZh = {
|
|
|
363
409
|
description:
|
|
364
410
|
"可选的裸 URL 和电子邮箱自动链接。设为 'gfm' 启用 GitHub Flavored Markdown 自动链接规则:裸 https?://、www.、<scheme:url>、<email> 以及 user@host 都会变成链接。末尾句末标点和不平衡的末尾右括号会被排除;代码块、现有链接和图片替代文本内部的匹配会被跳过。默认为关闭。",
|
|
365
411
|
},
|
|
412
|
+
{
|
|
413
|
+
name: 'components',
|
|
414
|
+
type: 'MarkdownComponents',
|
|
415
|
+
description:
|
|
416
|
+
'用于覆盖 Markdown 渲染元素的自定义 React 组件(code、inlineCode、math、link、heading、paragraph、image、blockquote、hr、citation)。提供 math 会启用 `$…$` 行内数学和 `$$…$$` 块级数学解析,并接收 `{value, display}`;不提供时美元符号保持原样。',
|
|
417
|
+
},
|
|
366
418
|
{
|
|
367
419
|
name: 'xstyle',
|
|
368
420
|
type: 'StyleXStyles',
|
|
@@ -372,12 +424,14 @@ export const docsZh = {
|
|
|
372
424
|
{
|
|
373
425
|
name: 'className',
|
|
374
426
|
type: 'string',
|
|
375
|
-
description:
|
|
427
|
+
description:
|
|
428
|
+
'根元素的 CSS 类名。建议使用 xstyle,className 适用于非 StyleX 系统集成。',
|
|
376
429
|
},
|
|
377
430
|
{
|
|
378
431
|
name: 'style',
|
|
379
432
|
type: 'CSSProperties',
|
|
380
|
-
description:
|
|
433
|
+
description:
|
|
434
|
+
'根元素的内联样式。建议使用 xstyle,内联样式会绕过 StyleX 优化。',
|
|
381
435
|
},
|
|
382
436
|
{
|
|
383
437
|
name: 'data-testid',
|
|
@@ -443,11 +497,41 @@ export const docsZh = {
|
|
|
443
497
|
description:
|
|
444
498
|
'Renders a markdown string as Astryx-styled components. Use Markdown for user-generated content, AI responses, and documentation; it handles headings, lists, tables, code blocks, and citations with consistent styling.',
|
|
445
499
|
bestPractices: [
|
|
446
|
-
{
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
500
|
+
{
|
|
501
|
+
guidance: true,
|
|
502
|
+
description:
|
|
503
|
+
'Set headingLevelStart to match the page hierarchy, e.g. start at 3 if the markdown sits inside an h2 section.',
|
|
504
|
+
},
|
|
505
|
+
{
|
|
506
|
+
guidance: true,
|
|
507
|
+
description:
|
|
508
|
+
'Use contentWidth to keep prose at a readable line length in wide layouts.',
|
|
509
|
+
},
|
|
510
|
+
{
|
|
511
|
+
guidance: true,
|
|
512
|
+
description:
|
|
513
|
+
'Use inlinePlugins for prefixed identifiers, mentions, and other prose-only shorthand instead of preprocessing the markdown string.',
|
|
514
|
+
},
|
|
515
|
+
{
|
|
516
|
+
guidance: true,
|
|
517
|
+
description:
|
|
518
|
+
'Provide components.math only for documents that use dollar-delimited math. The renderer owns typesetting and accessible output; Astryx passes the expression as text and never executes raw HTML.',
|
|
519
|
+
},
|
|
520
|
+
{
|
|
521
|
+
guidance: true,
|
|
522
|
+
description:
|
|
523
|
+
'For direct parsing, use MathParseOptions and handle InlineNodeWithMath or BlockNodeWithMath. Incremental math parsing also uses createIncrementalState<true>() and IncrementalParseState<true>; default calls and ParseOptions annotations keep the legacy unions.',
|
|
524
|
+
},
|
|
525
|
+
{
|
|
526
|
+
guidance: true,
|
|
527
|
+
description:
|
|
528
|
+
'Pair with Outline and useOutlineFromMarkdown for section navigation: headings render generated id attributes that match the outline item ids, so hash links scroll to their target.',
|
|
529
|
+
},
|
|
530
|
+
{
|
|
531
|
+
guidance: false,
|
|
532
|
+
description:
|
|
533
|
+
'Use Markdown for hand-authored layouts; use Text and Heading directly when you control the content.',
|
|
534
|
+
},
|
|
451
535
|
],
|
|
452
536
|
},
|
|
453
537
|
};
|
|
@@ -460,25 +544,66 @@ export const docsDense = {
|
|
|
460
544
|
description:
|
|
461
545
|
'Renders a markdown string as Astryx-styled components. Use Markdown for user-generated content, AI responses, and documentation; it handles headings, lists, tables, code blocks, and citations with consistent styling.',
|
|
462
546
|
bestPractices: [
|
|
463
|
-
{
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
547
|
+
{
|
|
548
|
+
guidance: true,
|
|
549
|
+
description:
|
|
550
|
+
'Set headingLevelStart to match the page hierarchy, e.g. start at 3 if the markdown sits inside an h2 section.',
|
|
551
|
+
},
|
|
552
|
+
{
|
|
553
|
+
guidance: true,
|
|
554
|
+
description:
|
|
555
|
+
'Use contentWidth to keep prose at a readable line length in wide layouts.',
|
|
556
|
+
},
|
|
557
|
+
{
|
|
558
|
+
guidance: true,
|
|
559
|
+
description:
|
|
560
|
+
'Use inlinePlugins for prefixed identifiers, mentions, and other prose-only shorthand instead of preprocessing the markdown string.',
|
|
561
|
+
},
|
|
562
|
+
{
|
|
563
|
+
guidance: true,
|
|
564
|
+
description:
|
|
565
|
+
'Provide components.math only for documents that use dollar-delimited math; the renderer owns typesetting and accessible output.',
|
|
566
|
+
},
|
|
567
|
+
{
|
|
568
|
+
guidance: true,
|
|
569
|
+
description:
|
|
570
|
+
'Direct math parser calls use MathParseOptions and the explicit WithMath node unions; incremental calls also use createIncrementalState<true>() and IncrementalParseState<true>. Default calls keep the legacy unions.',
|
|
571
|
+
},
|
|
572
|
+
{
|
|
573
|
+
guidance: true,
|
|
574
|
+
description:
|
|
575
|
+
'Headings render id attributes matching useOutlineFromMarkdown ids; pair with Outline for hash navigation.',
|
|
576
|
+
},
|
|
577
|
+
{
|
|
578
|
+
guidance: false,
|
|
579
|
+
description:
|
|
580
|
+
'Use Markdown for hand-authored layouts; use Text and Heading directly when you control the content.',
|
|
581
|
+
},
|
|
468
582
|
],
|
|
469
583
|
},
|
|
470
584
|
propDescriptions: {
|
|
471
585
|
children: 'markdown string',
|
|
472
586
|
density: "Block spacing. 'default'|'compact'. Default: 'default'.",
|
|
473
|
-
headingLevelStart:
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
587
|
+
headingLevelStart:
|
|
588
|
+
'Maps # to this heading level (1-6). Clamped to h6. Default: 1.',
|
|
589
|
+
isStreaming:
|
|
590
|
+
'Incremental parse + fade-in for streamed chunks. Default: false.',
|
|
591
|
+
onLinkClick:
|
|
592
|
+
'(href, event) => void|false. Return false prevents navigation.',
|
|
593
|
+
sources:
|
|
594
|
+
'Record<string, MarkdownSource>. Citation sources by ID. [id]/【id】 markers render as chips.',
|
|
595
|
+
citationStyle:
|
|
596
|
+
"'label'|'number'. label=chip w/ title+icon, number=compact badge. Default: 'label'.",
|
|
597
|
+
contentWidth:
|
|
598
|
+
'number|string. Max width for prose (headings, paragraphs, lists). Tables/code unconstrained.',
|
|
599
|
+
contentAlign:
|
|
600
|
+
"'start'|'center'. Prose alignment when contentWidth < container. Default: 'start'.",
|
|
601
|
+
inlinePlugins:
|
|
602
|
+
'MarkdownInlinePlugin[]. Regex matches in text nodes -> custom inline React elements. Skips inline/fenced code and math.',
|
|
603
|
+
autolink:
|
|
604
|
+
"'gfm'. Opt-in GFM autolinking: bare URLs (https?://, www.), <scheme:url>, <email>, user@host. Skips code, code blocks, existing links. Default: off.",
|
|
605
|
+
components:
|
|
606
|
+
'MarkdownComponents. Custom renderers; math({value, display}) opts into $…$/$$…$$ parsing. Renderer owns output and accessibility.',
|
|
482
607
|
xstyle: 'stylex.create() for layout (margins, sizing).',
|
|
483
608
|
className: 'CSS class. Prefer xstyle.',
|
|
484
609
|
style: 'Inline styles. Prefer xstyle.',
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file Markdown.public.test.ts
|
|
5
|
+
* @input Imports Markdown parser functions and node types from the public barrel
|
|
6
|
+
* @output Compile-time compatibility coverage for legacy and math-enabled results
|
|
7
|
+
* @position Public API test guarding @astryxdesign/core/Markdown
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import {describe, expectTypeOf, it} from 'vitest';
|
|
11
|
+
import {
|
|
12
|
+
createIncrementalState,
|
|
13
|
+
parseInline,
|
|
14
|
+
parseMarkdown,
|
|
15
|
+
parseMarkdownIncremental,
|
|
16
|
+
} from './index';
|
|
17
|
+
import type {
|
|
18
|
+
BlockNode,
|
|
19
|
+
BlockNodeWithMath,
|
|
20
|
+
InlineNode,
|
|
21
|
+
InlineNodeWithMath,
|
|
22
|
+
ParseOptions,
|
|
23
|
+
} from './index';
|
|
24
|
+
|
|
25
|
+
function assertNever(value: never): never {
|
|
26
|
+
throw new Error(`Unexpected node: ${JSON.stringify(value)}`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Existing exhaustive consumers must not gain a new case when they do not opt
|
|
30
|
+
// into math parsing. These functions fail to compile if the legacy unions widen.
|
|
31
|
+
function legacyInlineText(node: InlineNode): string {
|
|
32
|
+
switch (node.type) {
|
|
33
|
+
case 'text':
|
|
34
|
+
case 'code':
|
|
35
|
+
return node.content;
|
|
36
|
+
case 'bold':
|
|
37
|
+
case 'italic':
|
|
38
|
+
case 'strikethrough':
|
|
39
|
+
case 'link':
|
|
40
|
+
return node.children.map(legacyInlineText).join('');
|
|
41
|
+
case 'image':
|
|
42
|
+
return node.alt;
|
|
43
|
+
case 'citation':
|
|
44
|
+
return node.sourceId;
|
|
45
|
+
case 'break':
|
|
46
|
+
return '\n';
|
|
47
|
+
default:
|
|
48
|
+
return assertNever(node);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function legacyBlockText(node: BlockNode): string {
|
|
53
|
+
switch (node.type) {
|
|
54
|
+
case 'heading':
|
|
55
|
+
case 'paragraph':
|
|
56
|
+
return node.children.map(legacyInlineText).join('');
|
|
57
|
+
case 'codeblock':
|
|
58
|
+
return node.content;
|
|
59
|
+
case 'blockquote':
|
|
60
|
+
return node.children.map(legacyBlockText).join('\n');
|
|
61
|
+
case 'list':
|
|
62
|
+
return node.items
|
|
63
|
+
.flatMap(item => item.children.map(legacyBlockText))
|
|
64
|
+
.join('\n');
|
|
65
|
+
case 'table':
|
|
66
|
+
return [...node.headers, ...node.rows.flat()]
|
|
67
|
+
.flatMap(cell => cell.children.map(legacyInlineText))
|
|
68
|
+
.join(' ');
|
|
69
|
+
case 'image':
|
|
70
|
+
return node.alt;
|
|
71
|
+
case 'hr':
|
|
72
|
+
return '';
|
|
73
|
+
default:
|
|
74
|
+
return assertNever(node);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
describe('Markdown public parser types', () => {
|
|
79
|
+
it('keeps default and legacy parser calls on the legacy unions', () => {
|
|
80
|
+
expectTypeOf(parseInline('plain')).toEqualTypeOf<InlineNode[]>();
|
|
81
|
+
expectTypeOf(parseInline('plain', new Set<string>())).toEqualTypeOf<
|
|
82
|
+
InlineNode[]
|
|
83
|
+
>();
|
|
84
|
+
expectTypeOf(parseMarkdown('plain')).toEqualTypeOf<BlockNode[]>();
|
|
85
|
+
expectTypeOf(parseMarkdown('plain', {math: false})).toEqualTypeOf<
|
|
86
|
+
BlockNode[]
|
|
87
|
+
>();
|
|
88
|
+
const annotatedOptions: ParseOptions = {autolink: 'gfm'};
|
|
89
|
+
expectTypeOf(parseInline('plain', annotatedOptions)).toEqualTypeOf<
|
|
90
|
+
InlineNode[]
|
|
91
|
+
>();
|
|
92
|
+
expectTypeOf(parseMarkdown('plain', annotatedOptions)).toEqualTypeOf<
|
|
93
|
+
BlockNode[]
|
|
94
|
+
>();
|
|
95
|
+
expectTypeOf(
|
|
96
|
+
parseMarkdownIncremental(
|
|
97
|
+
'plain',
|
|
98
|
+
createIncrementalState(),
|
|
99
|
+
annotatedOptions,
|
|
100
|
+
),
|
|
101
|
+
).toEqualTypeOf<BlockNode[]>();
|
|
102
|
+
expectTypeOf(
|
|
103
|
+
parseMarkdownIncremental('plain', createIncrementalState()),
|
|
104
|
+
).toEqualTypeOf<BlockNode[]>();
|
|
105
|
+
expectTypeOf(createIncrementalState().settledBlocks).toEqualTypeOf<
|
|
106
|
+
BlockNode[]
|
|
107
|
+
>();
|
|
108
|
+
expectTypeOf(legacyInlineText).returns.toBeString();
|
|
109
|
+
expectTypeOf(legacyBlockText).returns.toBeString();
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('rejects ambiguous math options and structurally forged state', () => {
|
|
113
|
+
function compileOnlyGuards() {
|
|
114
|
+
const dynamicOptions: {math: boolean} = {math: true};
|
|
115
|
+
// @ts-expect-error callers must narrow to ParseOptions or MathParseOptions
|
|
116
|
+
parseMarkdown('$$x$$', dynamicOptions);
|
|
117
|
+
|
|
118
|
+
const structuralState = {
|
|
119
|
+
prevInput: '',
|
|
120
|
+
settledText: '',
|
|
121
|
+
settledBlocks: [] as BlockNode[],
|
|
122
|
+
settledUpTo: 0,
|
|
123
|
+
};
|
|
124
|
+
// @ts-expect-error math caches must come from createIncrementalState<true>()
|
|
125
|
+
parseMarkdownIncremental('$$x$$', structuralState, {math: true});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
expectTypeOf(compileOnlyGuards).toBeFunction();
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('types direct and incremental math opt-ins with explicit math unions', () => {
|
|
132
|
+
const inline = parseInline('$x$', {math: true});
|
|
133
|
+
const direct = parseMarkdown('$$x$$', {math: true});
|
|
134
|
+
const incremental = parseMarkdownIncremental(
|
|
135
|
+
'$$x$$',
|
|
136
|
+
createIncrementalState<true>(),
|
|
137
|
+
{math: true},
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
// A state carries the same node contract as the parser result it caches.
|
|
141
|
+
// @ts-expect-error math parsing requires a math-enabled incremental state
|
|
142
|
+
parseMarkdownIncremental('$$x$$', createIncrementalState(), {math: true});
|
|
143
|
+
|
|
144
|
+
expectTypeOf(inline).toEqualTypeOf<InlineNodeWithMath[]>();
|
|
145
|
+
expectTypeOf(direct).toEqualTypeOf<BlockNodeWithMath[]>();
|
|
146
|
+
expectTypeOf(incremental).toEqualTypeOf<BlockNodeWithMath[]>();
|
|
147
|
+
expectTypeOf(createIncrementalState<true>().settledBlocks).toEqualTypeOf<
|
|
148
|
+
BlockNodeWithMath[]
|
|
149
|
+
>();
|
|
150
|
+
expectTypeOf<
|
|
151
|
+
Extract<InlineNodeWithMath, {type: 'math'}>['value']
|
|
152
|
+
>().toBeString();
|
|
153
|
+
expectTypeOf<
|
|
154
|
+
Extract<BlockNodeWithMath, {type: 'math'}>['value']
|
|
155
|
+
>().toBeString();
|
|
156
|
+
});
|
|
157
|
+
});
|