@astryxdesign/core 0.6.2 → 0.6.3-canary.0788c49
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 +81 -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/Button/Button.d.ts.map +1 -1
- package/dist/Button/Button.js +13 -28
- package/dist/Chat/ChatComposer.d.ts.map +1 -1
- package/dist/Chat/ChatComposer.js +10 -5
- package/dist/Chat/ChatComposerDrawer.d.ts +19 -5
- package/dist/Chat/ChatComposerDrawer.d.ts.map +1 -1
- package/dist/Chat/ChatComposerDrawer.js +48 -23
- package/dist/Chat/ChatComposerInput.d.ts +11 -3
- package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
- package/dist/Chat/ChatComposerInput.js +63 -16
- package/dist/Chat/ChatDictationButton.d.ts +3 -2
- package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
- package/dist/Chat/ChatDictationButton.js +6 -4
- package/dist/Chat/ChatLayout.d.ts +19 -0
- package/dist/Chat/ChatLayout.d.ts.map +1 -1
- package/dist/Chat/ChatLayout.js +19 -0
- package/dist/Chat/ChatLayoutScrollButton.d.ts.map +1 -1
- package/dist/Chat/ChatLayoutScrollButton.js +44 -34
- package/dist/Chat/ChatMessageBubble.d.ts +2 -0
- package/dist/Chat/ChatMessageBubble.d.ts.map +1 -1
- package/dist/Chat/ChatMessageBubble.js +5 -3
- package/dist/Chat/ChatMessageList.d.ts +2 -1
- package/dist/Chat/ChatMessageList.d.ts.map +1 -1
- package/dist/Chat/ChatMessageList.js +4 -3
- package/dist/Chat/ChatMessageMetadata.d.ts +5 -4
- package/dist/Chat/ChatMessageMetadata.d.ts.map +1 -1
- package/dist/Chat/ChatMessageMetadata.js +12 -9
- package/dist/Chat/ChatSendButton.d.ts +2 -1
- package/dist/Chat/ChatSendButton.d.ts.map +1 -1
- package/dist/Chat/ChatSendButton.js +6 -4
- package/dist/Chat/index.d.ts +1 -1
- package/dist/Chat/index.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +12 -2
- package/dist/Citation/Citation.d.ts +1 -1
- package/dist/Citation/Citation.d.ts.map +1 -1
- package/dist/Citation/Citation.js +3 -2
- package/dist/CodeBlock/highlightRanges.d.ts.map +1 -1
- package/dist/CodeBlock/highlightRanges.js +14 -3
- package/dist/Collapsible/Collapsible.d.ts.map +1 -1
- package/dist/Collapsible/Collapsible.js +6 -1
- package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPaletteInput.js +1 -1
- package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
- package/dist/ComplexSelector/ComplexSelector.js +1 -1
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +4 -4
- package/dist/DateInput/NativeDateField.d.ts.map +1 -1
- package/dist/DateInput/NativeDateField.js +16 -16
- package/dist/DateInput/TouchDateField.d.ts.map +1 -1
- package/dist/DateInput/TouchDateField.js +2 -2
- package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.js +4 -4
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +8 -8
- package/dist/DateTimeInput/TouchDateTimeField.d.ts.map +1 -1
- package/dist/DateTimeInput/TouchDateTimeField.js +4 -4
- package/dist/DateTimeInput/nativePickerSegmentStyles.d.ts +9 -3
- package/dist/DateTimeInput/nativePickerSegmentStyles.d.ts.map +1 -1
- package/dist/DateTimeInput/nativePickerSegmentStyles.js +3 -3
- package/dist/Dialog/DialogHeader.d.ts +8 -1
- package/dist/Dialog/DialogHeader.d.ts.map +1 -1
- package/dist/Dialog/DialogHeader.js +13 -4
- package/dist/Field/InputClearButton.d.ts +4 -2
- package/dist/Field/InputClearButton.d.ts.map +1 -1
- package/dist/Field/InputClearButton.js +4 -2
- package/dist/Field/PanelSearchInput.d.ts.map +1 -1
- package/dist/Field/PanelSearchInput.js +1 -1
- package/dist/FileInput/FileInput.d.ts.map +1 -1
- package/dist/FileInput/FileInput.js +7 -7
- package/dist/Icon/Icon.d.ts +6 -31
- package/dist/Icon/Icon.d.ts.map +1 -1
- package/dist/Icon/Icon.js +8 -71
- package/dist/Icon/IconDefaultSizeContext.d.ts +4 -0
- package/dist/Icon/IconDefaultSizeContext.d.ts.map +1 -0
- package/dist/Icon/IconDefaultSizeContext.js +18 -0
- package/dist/Icon/IconSize.stylex.d.ts +65 -0
- package/dist/Icon/IconSize.stylex.d.ts.map +1 -0
- package/dist/Icon/IconSize.stylex.js +75 -0
- package/dist/Item/Item.d.ts +1 -1
- package/dist/Item/Item.d.ts.map +1 -1
- package/dist/Item/Item.js +4 -3
- package/dist/Kbd/Kbd.d.ts +5 -3
- package/dist/Kbd/Kbd.d.ts.map +1 -1
- package/dist/Kbd/Kbd.js +36 -42
- package/dist/Link/Link.d.ts.map +1 -1
- package/dist/Link/Link.js +6 -2
- package/dist/Link/useLinkComponent.d.ts +5 -15
- package/dist/Link/useLinkComponent.d.ts.map +1 -1
- package/dist/Link/useLinkComponent.js +34 -51
- package/dist/List/List.d.ts +19 -1
- package/dist/List/List.d.ts.map +1 -1
- package/dist/List/List.js +9 -2
- package/dist/List/ListContext.d.ts +1 -0
- package/dist/List/ListContext.d.ts.map +1 -1
- package/dist/List/ListContext.js +2 -1
- package/dist/List/ListItem.d.ts +1 -1
- package/dist/List/ListItem.d.ts.map +1 -1
- package/dist/List/ListItem.js +9 -2
- package/dist/Markdown/Markdown.d.ts +8 -2
- package/dist/Markdown/Markdown.d.ts.map +1 -1
- package/dist/Markdown/Markdown.fr23.bench.d.ts +2 -0
- package/dist/Markdown/Markdown.fr23.bench.d.ts.map +1 -0
- package/dist/Markdown/Markdown.fr23.bench.js +150 -0
- package/dist/Markdown/Markdown.fr23.sampling.d.ts +2 -0
- package/dist/Markdown/Markdown.fr23.sampling.d.ts.map +1 -0
- package/dist/Markdown/Markdown.fr23.sampling.js +43 -0
- package/dist/Markdown/Markdown.js +262 -109
- package/dist/Markdown/ast.d.ts +162 -0
- package/dist/Markdown/ast.d.ts.map +1 -0
- package/dist/Markdown/ast.js +74 -0
- package/dist/Markdown/index.d.ts +5 -3
- package/dist/Markdown/index.d.ts.map +1 -1
- package/dist/Markdown/index.js +3 -2
- package/dist/Markdown/parser/index.d.ts +10 -0
- package/dist/Markdown/parser/index.d.ts.map +1 -0
- package/dist/Markdown/parser/index.js +10 -0
- package/dist/Markdown/parser.d.ts +126 -58
- package/dist/Markdown/parser.d.ts.map +1 -1
- package/dist/Markdown/parser.js +726 -177
- package/dist/Markdown/plugins/frontmatter.d.ts +32 -0
- package/dist/Markdown/plugins/frontmatter.d.ts.map +1 -0
- package/dist/Markdown/plugins/frontmatter.js +132 -0
- package/dist/Markdown/plugins/index.d.ts +17 -0
- package/dist/Markdown/plugins/index.d.ts.map +1 -0
- package/dist/Markdown/plugins/index.js +14 -0
- package/dist/Markdown/plugins/protocol.d.ts +191 -0
- package/dist/Markdown/plugins/protocol.d.ts.map +1 -0
- package/dist/Markdown/plugins/protocol.js +957 -0
- package/dist/Markdown/plugins/semanticFence.d.ts +36 -0
- package/dist/Markdown/plugins/semanticFence.d.ts.map +1 -0
- package/dist/Markdown/plugins/semanticFence.js +213 -0
- package/dist/Markdown/plugins/softBreaks.d.ts +3 -0
- package/dist/Markdown/plugins/softBreaks.d.ts.map +1 -0
- package/dist/Markdown/plugins/softBreaks.js +172 -0
- package/dist/Markdown/plugins/sourceDecoration.d.ts +76 -0
- package/dist/Markdown/plugins/sourceDecoration.d.ts.map +1 -0
- package/dist/Markdown/plugins/sourceDecoration.js +393 -0
- package/dist/Markdown/plugins/textTransform.d.ts +30 -0
- package/dist/Markdown/plugins/textTransform.d.ts.map +1 -0
- package/dist/Markdown/plugins/textTransform.js +374 -0
- package/dist/Markdown/remark.d.ts +196 -0
- package/dist/Markdown/remark.d.ts.map +1 -0
- package/dist/Markdown/remark.js +1062 -0
- package/dist/Markdown/url.d.ts +6 -0
- package/dist/Markdown/url.d.ts.map +1 -0
- package/dist/Markdown/url.js +31 -0
- package/dist/Markdown/utils.d.ts +4 -2
- package/dist/Markdown/utils.d.ts.map +1 -1
- package/dist/Markdown/utils.js +2 -1
- package/dist/MetadataList/MetadataList.js +3 -3
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/NumberInput/NumberInput.js +4 -4
- package/dist/Outline/index.d.ts +1 -0
- package/dist/Outline/index.d.ts.map +1 -1
- package/dist/Outline/parseOutlineFromMarkdown.d.ts +7 -1
- package/dist/Outline/parseOutlineFromMarkdown.d.ts.map +1 -1
- package/dist/Outline/parseOutlineFromMarkdown.js +14 -8
- package/dist/Outline/useOutlineFromMarkdown.d.ts +3 -1
- package/dist/Outline/useOutlineFromMarkdown.d.ts.map +1 -1
- package/dist/Outline/useOutlineFromMarkdown.js +8 -3
- package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearchEditPopover.js +46 -30
- package/dist/PowerSearch/PowerSearchValueEditor.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearchValueEditor.js +5 -0
- package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
- package/dist/ProgressBar/ProgressBar.js +36 -31
- package/dist/RadioList/RadioListItem.d.ts.map +1 -1
- package/dist/RadioList/RadioListItem.js +13 -1
- package/dist/ScrollableArea/ScrollableArea.d.ts +1 -0
- package/dist/ScrollableArea/ScrollableArea.d.ts.map +1 -1
- package/dist/ScrollableArea/ScrollableArea.js +1 -0
- package/dist/SegmentedControl/SegmentedControl.d.ts +1 -1
- package/dist/SegmentedControl/SegmentedControl.d.ts.map +1 -1
- package/dist/SegmentedControl/SegmentedControl.js +1 -0
- package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
- package/dist/SegmentedControl/SegmentedControlItem.js +5 -5
- package/dist/Selector/Selector.d.ts +9 -7
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +16 -7
- package/dist/SideNav/SideNav.d.ts +2 -1
- package/dist/SideNav/SideNav.d.ts.map +1 -1
- package/dist/SideNav/SideNav.js +9 -3
- package/dist/Slider/Slider.d.ts.map +1 -1
- package/dist/Slider/Slider.js +28 -12
- package/dist/Spinner/Spinner.d.ts.map +1 -1
- package/dist/Spinner/Spinner.js +23 -7
- package/dist/Switch/Switch.d.ts.map +1 -1
- package/dist/Switch/Switch.js +11 -0
- package/dist/TabList/Tab.d.ts +1 -1
- package/dist/TabList/Tab.d.ts.map +1 -1
- package/dist/TabList/Tab.js +20 -7
- package/dist/Table/Table.d.ts +1 -0
- package/dist/Table/Table.d.ts.map +1 -1
- package/dist/Table/Table.js +29 -13
- package/dist/TextArea/TextArea.d.ts.map +1 -1
- package/dist/TextArea/TextArea.js +1 -1
- package/dist/TextInput/TextInput.d.ts.map +1 -1
- package/dist/TextInput/TextInput.js +2 -2
- package/dist/TimeInput/TimeInput.d.ts.map +1 -1
- package/dist/TimeInput/TimeInput.js +4 -4
- package/dist/Timer/Timer.d.ts +49 -0
- package/dist/Timer/Timer.d.ts.map +1 -0
- package/dist/Timer/Timer.js +158 -0
- package/dist/Timer/index.d.ts +9 -0
- package/dist/Timer/index.d.ts.map +1 -0
- package/dist/Timer/index.js +10 -0
- package/dist/ToggleButton/ToggleButton.d.ts +9 -6
- package/dist/ToggleButton/ToggleButton.d.ts.map +1 -1
- package/dist/ToggleButton/ToggleButton.js +15 -27
- package/dist/TopNav/TopNavMenu.d.ts +1 -1
- package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMenu.js +3 -2
- package/dist/TreeList/TreeList.d.ts.map +1 -1
- package/dist/TreeList/TreeList.js +3 -0
- package/dist/TreeList/TreeListItem.d.ts +6 -1
- package/dist/TreeList/TreeListItem.d.ts.map +1 -1
- package/dist/TreeList/TreeListItem.js +12 -2
- package/dist/TreeList/TreeListTypes.d.ts +8 -1
- package/dist/TreeList/TreeListTypes.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +16 -7
- package/dist/astryx.css +27 -11
- 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/useClickableContainer.d.ts +10 -1
- package/dist/hooks/useClickableContainer.d.ts.map +1 -1
- package/dist/hooks/useClickableContainer.js +15 -4
- 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/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/theme/declarationBoundary.d.ts +17 -0
- package/dist/theme/declarationBoundary.d.ts.map +1 -0
- package/dist/theme/declarationBoundary.js +343 -0
- package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
- package/dist/theme/derivedVarRegistry.js +4 -0
- package/dist/theme/generateThemeRules.d.ts +13 -7
- package/dist/theme/generateThemeRules.d.ts.map +1 -1
- package/dist/theme/generateThemeRules.js +140 -34
- package/dist/utils/interactionOverlay.stylex.d.ts +8 -0
- package/dist/utils/interactionOverlay.stylex.d.ts.map +1 -1
- package/dist/utils/interactionOverlay.stylex.js +9 -0
- package/dist/utils/safeUrl.d.ts +11 -0
- package/dist/utils/safeUrl.d.ts.map +1 -0
- package/dist/utils/safeUrl.js +78 -0
- package/locales/af-ZA.json +530 -1
- package/locales/ar-SA.json +490 -1
- package/locales/ca-ES.json +514 -1
- package/locales/cs-CZ.json +498 -1
- package/locales/da-DK.json +522 -1
- package/locales/de-DE.json +522 -1
- package/locales/el-GR.json +498 -1
- package/locales/es-ES.json +510 -1
- package/locales/fi-FI.json +498 -1
- package/locales/fr-FR.json +534 -1
- package/locales/he-IL.json +498 -1
- package/locales/hu-HU.json +498 -1
- package/locales/it-IT.json +510 -1
- package/locales/ja-JP.json +490 -1
- package/locales/ko-KR.json +498 -1
- package/locales/nl-NL.json +534 -1
- package/locales/no-NO.json +510 -1
- package/locales/pl-PL.json +506 -1
- package/locales/pt-BR.json +506 -1
- package/locales/pt-PT.json +506 -1
- package/locales/ro-RO.json +506 -1
- package/locales/ru-RU.json +498 -1
- package/locales/sr-SP.json +498 -1
- package/locales/sv-SE.json +502 -1
- package/locales/tr-TR.json +498 -1
- package/locales/uk-UA.json +498 -1
- package/locales/vi-VN.json +502 -1
- package/locales/zh-CN.json +490 -1
- package/locales/zh-TW.json +490 -1
- package/package.json +24 -4
- 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/Button/Button.doc.mjs +5 -5
- package/src/Button/Button.tsx +15 -13
- package/src/Button/__tests__/Button.a11y.chromium.spec.ts +17 -1
- package/src/Button/__tests__/Button.a11y.known-failures.ts +0 -29
- package/src/Button/__tests__/Button.a11y.renders.tsx +9 -2
- package/src/Button/__tests__/Button.a11y.states.ts +9 -0
- package/src/Chat/ChatComposer.doc.mjs +14 -0
- package/src/Chat/ChatComposer.spec.md +230 -0
- package/src/Chat/ChatComposer.test.tsx +57 -0
- package/src/Chat/ChatComposer.tsx +21 -9
- package/src/Chat/ChatComposerDrawer.doc.mjs +63 -5
- package/src/Chat/ChatComposerDrawer.spec.md +267 -0
- package/src/Chat/ChatComposerDrawer.test.tsx +81 -12
- package/src/Chat/ChatComposerDrawer.tsx +38 -9
- package/src/Chat/ChatComposerInput.doc.mjs +114 -26
- package/src/Chat/ChatComposerInput.spec.md +185 -0
- package/src/Chat/ChatComposerInput.test.tsx +113 -3
- package/src/Chat/ChatComposerInput.tsx +78 -13
- package/src/Chat/ChatComposerTokenElement.spec.md +152 -0
- package/src/Chat/ChatComposerTokenElement.test.tsx +85 -0
- package/src/Chat/ChatDictationButton.doc.mjs +3 -3
- package/src/Chat/ChatDictationButton.spec.md +160 -0
- package/src/Chat/ChatDictationButton.test.tsx +92 -27
- package/src/Chat/ChatDictationButton.tsx +8 -6
- package/src/Chat/ChatLayout.doc.mjs +12 -4
- package/src/Chat/ChatLayout.spec.md +271 -0
- package/src/Chat/ChatLayout.test.tsx +28 -0
- package/src/Chat/ChatLayout.tsx +19 -0
- package/src/Chat/ChatLayoutScrollButton.spec.md +338 -0
- package/src/Chat/ChatLayoutScrollButton.test.tsx +31 -0
- package/src/Chat/ChatLayoutScrollButton.tsx +31 -14
- package/src/Chat/ChatMessageBubble.doc.mjs +28 -15
- package/src/Chat/ChatMessageBubble.spec.md +263 -0
- package/src/Chat/ChatMessageBubble.test.tsx +93 -0
- package/src/Chat/ChatMessageBubble.tsx +8 -3
- package/src/Chat/ChatMessageList.spec.md +222 -0
- package/src/Chat/ChatMessageList.test.tsx +64 -2
- package/src/Chat/ChatMessageList.tsx +4 -3
- package/src/Chat/ChatMessageMetadata.doc.mjs +57 -3
- package/src/Chat/ChatMessageMetadata.spec.md +220 -0
- package/src/Chat/ChatMessageMetadata.test.tsx +34 -0
- package/src/Chat/ChatMessageMetadata.tsx +13 -13
- package/src/Chat/ChatSendButton.doc.mjs +32 -0
- package/src/Chat/ChatSendButton.spec.md +227 -0
- package/src/Chat/ChatSendButton.test.tsx +128 -8
- package/src/Chat/ChatSendButton.tsx +6 -4
- package/src/Chat/__tests__/ChatLayoutScrollButton.a11y.chromium.spec.ts +514 -0
- package/src/Chat/__tests__/ChatLayoutScrollButtonSurface.a11y.chromium.spec.ts +740 -0
- package/src/Chat/__tests__/ChatMessageBubble.a11y.chromium.spec.ts +457 -0
- package/src/Chat/__tests__/ChatMessageBubble.auditProvenance.test.ts +91 -0
- package/src/Chat/__tests__/ChatMessageBubble.auditProvenance.ts +91 -0
- package/src/Chat/__tests__/ChatMessageList.a11y.chromium.spec.ts +456 -0
- package/src/Chat/__tests__/ChatMessageMetadata.a11y.chromium.spec.ts +413 -0
- package/src/Chat/__tests__/ChatSendButton.a11y.chromium.spec.ts +1522 -0
- package/src/Chat/index.ts +1 -0
- package/src/CheckboxInput/CheckboxInput.doc.mjs +11 -0
- package/src/CheckboxInput/CheckboxInput.test.tsx +34 -0
- package/src/CheckboxInput/CheckboxInput.tsx +21 -1
- package/src/Citation/Citation.doc.mjs +2 -2
- package/src/Citation/Citation.test.tsx +17 -0
- package/src/Citation/Citation.tsx +4 -2
- package/src/ClickableCard/ClickableCard.doc.mjs +2 -2
- package/src/ClickableCard/ClickableCard.test.tsx +102 -5
- package/src/CodeBlock/highlightRanges.test.ts +143 -1
- package/src/CodeBlock/highlightRanges.ts +15 -5
- package/src/Collapsible/Collapsible.doc.mjs +11 -0
- package/src/Collapsible/Collapsible.test.tsx +21 -0
- package/src/Collapsible/Collapsible.tsx +5 -0
- package/src/CommandPalette/CommandPaletteInput.tsx +6 -1
- package/src/ComplexSelector/ComplexSelector.tsx +6 -1
- package/src/DateInput/DateInput.tsx +6 -1
- package/src/DateInput/NativeDateField.tsx +24 -8
- package/src/DateInput/TouchDateField.tsx +6 -2
- package/src/DateRangeInput/DateRangeInput.tsx +6 -1
- package/src/DateTimeInput/DateTimeInput.tsx +6 -1
- package/src/DateTimeInput/TouchDateTimeField.tsx +6 -1
- package/src/DateTimeInput/nativePickerSegmentStyles.ts +24 -8
- package/src/Dialog/Dialog.doc.mjs +2 -0
- package/src/Dialog/DialogHeader.doc.mjs +22 -0
- package/src/Dialog/DialogHeader.test.tsx +167 -3
- package/src/Dialog/DialogHeader.tsx +37 -6
- package/src/Dialog/modules/DialogHeader.spec.md +101 -42
- package/src/DropdownMenu/DropdownMenu.test.tsx +5 -2
- package/src/Field/InputClearButton.test.tsx +17 -3
- package/src/Field/InputClearButton.tsx +5 -2
- package/src/Field/PanelSearchInput.tsx +5 -2
- package/src/FieldStatus/__tests__/StatusMessage.a11y.states.ts +1 -1
- package/src/FileInput/FileInput.tsx +11 -2
- package/src/Icon/Icon.doc.mjs +7 -5
- package/src/Icon/Icon.spec.md +81 -40
- package/src/Icon/Icon.test.tsx +6 -3
- package/src/Icon/Icon.tsx +20 -68
- package/src/Icon/IconDefaultSizeContext.ts +23 -0
- package/src/Icon/IconSize.stylex.ts +70 -0
- package/src/IconButton/IconButton.doc.mjs +3 -3
- package/src/IconButton/IconButton.test.tsx +40 -0
- package/src/Item/Item.doc.mjs +6 -2
- package/src/Item/Item.tsx +9 -3
- package/src/Kbd/Kbd.doc.mjs +3 -3
- package/src/Kbd/Kbd.test.tsx +57 -1
- package/src/Kbd/Kbd.tsx +57 -37
- package/src/Layout/LayoutFooter.doc.mjs +17 -0
- package/src/Link/Link.doc.mjs +17 -4
- package/src/Link/Link.test.tsx +24 -0
- package/src/Link/Link.tsx +5 -0
- package/src/Link/LinkProvider.doc.mjs +2 -2
- package/src/Link/__tests__/Link.navigation.a11y.chromium.spec.ts +261 -0
- package/src/Link/useLinkComponent.test.tsx +333 -0
- package/src/Link/useLinkComponent.ts +29 -57
- package/src/List/List.doc.mjs +6 -0
- package/src/List/List.spec.md +200 -0
- package/src/List/List.test.tsx +117 -1
- package/src/List/List.tsx +22 -2
- package/src/List/ListContext.tsx +3 -1
- package/src/List/ListItem.doc.mjs +2 -2
- package/src/List/ListItem.source-build.test.mjs +41 -0
- package/src/List/ListItem.tsx +26 -2
- package/src/Markdown/Markdown.doc.mjs +300 -2
- package/src/Markdown/Markdown.fr23.bench.ts +174 -0
- package/src/Markdown/Markdown.fr23.perf.test.ts +249 -0
- package/src/Markdown/Markdown.fr23.sampling.ts +49 -0
- package/src/Markdown/Markdown.helpers.perf.test.ts +489 -0
- package/src/Markdown/Markdown.public.test.ts +130 -3
- package/src/Markdown/Markdown.renderBoundary.test.tsx +72 -0
- package/src/Markdown/Markdown.spec.md +210 -45
- package/src/Markdown/Markdown.test.tsx +87 -3
- package/src/Markdown/Markdown.tsx +414 -135
- package/src/Markdown/ast.test.ts +307 -0
- package/src/Markdown/ast.ts +337 -0
- package/src/Markdown/incremental.test.ts +43 -0
- package/src/Markdown/index.ts +37 -1
- package/src/Markdown/modules/remark.spec.md +269 -0
- package/src/Markdown/modules/softBreaks.spec.md +137 -0
- package/src/Markdown/parser/index.ts +64 -0
- package/src/Markdown/parser.public.test.ts +103 -0
- package/src/Markdown/parser.test.ts +38 -6
- package/src/Markdown/parser.ts +1221 -242
- package/src/Markdown/plugins/frontmatter.test.tsx +125 -0
- package/src/Markdown/plugins/frontmatter.ts +198 -0
- package/src/Markdown/plugins/index.ts +54 -0
- package/src/Markdown/plugins/protocol.test.tsx +1022 -0
- package/src/Markdown/plugins/protocol.ts +1618 -0
- package/src/Markdown/plugins/semanticFence.test.tsx +546 -0
- package/src/Markdown/plugins/semanticFence.ts +424 -0
- package/src/Markdown/plugins/softBreaks.test.tsx +172 -0
- package/src/Markdown/plugins/softBreaks.ts +169 -0
- package/src/Markdown/plugins/sourceDecoration.test.tsx +799 -0
- package/src/Markdown/plugins/sourceDecoration.ts +539 -0
- package/src/Markdown/plugins/textTransform.test.ts +467 -0
- package/src/Markdown/plugins/textTransform.ts +554 -0
- package/src/Markdown/remark.test.tsx +1877 -0
- package/src/Markdown/remark.ts +1574 -0
- package/src/Markdown/url.ts +36 -0
- package/src/Markdown/utils.ts +13 -1
- package/src/MetadataList/MetadataList.test.tsx +4 -2
- package/src/MetadataList/MetadataList.tsx +3 -3
- package/src/MultiSelector/MultiSelector.test.tsx +1 -35
- package/src/MultiSelector/__tests__/MultiSelector.listbox.a11y.test.tsx +128 -0
- package/src/NumberInput/NumberInput.tsx +6 -1
- package/src/Outline/Outline.doc.mjs +7 -5
- package/src/Outline/Outline.spec.md +1 -1
- package/src/Outline/index.ts +1 -0
- package/src/Outline/modules/parseOutlineFromMarkdown.spec.md +142 -0
- package/src/Outline/parseOutlineFromMarkdown.ts +40 -10
- package/src/Outline/useOutlineFromMarkdown.ts +15 -3
- package/src/PowerSearch/PowerSearch.doc.mjs +2 -2
- package/src/PowerSearch/PowerSearchEditPopover.test.tsx +150 -1
- package/src/PowerSearch/PowerSearchEditPopover.tsx +51 -28
- package/src/PowerSearch/PowerSearchValueEditor.test.tsx +51 -0
- package/src/PowerSearch/PowerSearchValueEditor.tsx +4 -0
- package/src/ProgressBar/ProgressBar.test.tsx +29 -11
- package/src/ProgressBar/ProgressBar.tsx +59 -72
- package/src/RadioList/RadioList.doc.mjs +11 -0
- package/src/RadioList/RadioList.test.tsx +32 -0
- package/src/RadioList/RadioListItem.tsx +25 -1
- package/src/ScrollableArea/ScrollableArea.tsx +1 -0
- package/src/ScrollableArea/modules/useScrollableArea.spec.md +50 -22
- package/src/SegmentedControl/SegmentedControl.doc.mjs +2 -2
- package/src/SegmentedControl/SegmentedControl.test.tsx +61 -0
- package/src/SegmentedControl/SegmentedControl.tsx +2 -1
- package/src/SegmentedControl/SegmentedControlItem.tsx +6 -9
- package/src/Selector/Selector.doc.mjs +3 -3
- package/src/Selector/Selector.spec.md +51 -49
- package/src/Selector/Selector.test.tsx +61 -55
- package/src/Selector/Selector.tsx +34 -15
- package/src/Selector/__tests__/Listbox.a11y.chromium.spec.ts +130 -0
- package/src/Selector/__tests__/Listbox.a11y.dom.ts +38 -0
- package/src/Selector/__tests__/Listbox.a11y.inventory.test.ts +63 -0
- package/src/Selector/__tests__/Listbox.a11y.known-failures.ts +37 -0
- package/src/Selector/__tests__/Listbox.a11y.states.ts +232 -0
- package/src/Selector/__tests__/Selector.a11y.chromium.spec.ts +45 -0
- package/src/Selector/__tests__/Selector.listbox.a11y.test.tsx +121 -0
- package/src/SideNav/SideNav.doc.mjs +1 -1
- package/src/SideNav/SideNav.test.tsx +10 -0
- package/src/SideNav/SideNav.tsx +14 -2
- package/src/Slider/Slider.doc.mjs +17 -3
- package/src/Slider/Slider.test.tsx +221 -0
- package/src/Slider/Slider.tsx +40 -9
- package/src/Spinner/Spinner.test.tsx +4 -0
- package/src/Spinner/Spinner.tsx +31 -18
- package/src/Switch/Switch.doc.mjs +11 -0
- package/src/Switch/Switch.test.tsx +16 -0
- package/src/Switch/Switch.tsx +28 -0
- package/src/TabList/Tab.tsx +35 -7
- package/src/TabList/TabList.doc.mjs +11 -0
- package/src/TabList/TabList.spec.md +204 -0
- package/src/TabList/TabList.test.tsx +66 -0
- package/src/TabList/__tests__/Tabs.a11y.known-failures.ts +1 -34
- package/src/Table/Table.doc.mjs +1 -1
- package/src/Table/Table.spec.md +54 -40
- package/src/Table/Table.test.tsx +83 -10
- package/src/Table/Table.tsx +30 -22
- package/src/Table/__tests__/TableScroll.a11y.chromium.spec.ts +137 -0
- package/src/TextArea/TextArea.tsx +6 -1
- package/src/TextInput/TextInput.test.tsx +20 -1
- package/src/TextInput/TextInput.tsx +6 -1
- package/src/TimeInput/TimeInput.tsx +6 -1
- package/src/Timer/Timer.doc.mjs +183 -0
- package/src/Timer/Timer.spec.md +215 -0
- package/src/Timer/Timer.test.tsx +302 -0
- package/src/Timer/Timer.tsx +258 -0
- package/src/Timer/index.ts +11 -0
- package/src/ToggleButton/ToggleButton.doc.mjs +3 -3
- package/src/ToggleButton/ToggleButton.test.tsx +299 -4
- package/src/ToggleButton/ToggleButton.tsx +26 -33
- package/src/ToggleButton/ToggleButtonGroup.doc.mjs +3 -3
- package/src/ToggleButton/__tests__/ToggleButton.a11y.chromium.spec.ts +209 -0
- package/src/Token/Token.doc.mjs +2 -2
- package/src/Tokenizer/Tokenizer.spec.md +142 -75
- package/src/TopNav/TopNavMenu.doc.mjs +2 -2
- package/src/TopNav/TopNavMenu.test.tsx +30 -0
- package/src/TopNav/TopNavMenu.tsx +7 -2
- package/src/TreeList/TreeList.doc.mjs +3 -3
- package/src/TreeList/TreeList.spec.md +123 -75
- package/src/TreeList/TreeList.test.tsx +29 -0
- package/src/TreeList/TreeList.tsx +3 -0
- package/src/TreeList/TreeListItem.tsx +15 -1
- package/src/TreeList/TreeListTypes.ts +11 -1
- package/src/Typeahead/BaseTypeahead.spec.md +4 -3
- package/src/Typeahead/BaseTypeahead.tsx +21 -7
- package/src/Typeahead/Typeahead.test.tsx +53 -0
- package/src/__tests__/PressedState.a11y.chromium.spec.ts +813 -0
- package/src/__tests__/pressState.ts +93 -0
- package/src/hooks/scrollKeyboardDelegation.test.ts +155 -0
- package/src/hooks/scrollKeyboardDelegation.ts +233 -0
- package/src/hooks/useClickableContainer.test.tsx +236 -0
- package/src/hooks/useClickableContainer.ts +20 -4
- 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/index.ts +3 -0
- package/src/inputFontFloor.test.ts +106 -0
- package/src/tailwind-theme.css +0 -6
- package/src/theme/Theme.test.tsx +32 -0
- package/src/theme/declarationBoundary.test.ts +126 -0
- package/src/theme/declarationBoundary.ts +347 -0
- package/src/theme/derivedVarRegistry.test.ts +7 -0
- package/src/theme/derivedVarRegistry.ts +1 -0
- package/src/theme/generateThemeRules.test.ts +526 -1
- package/src/theme/generateThemeRules.ts +228 -50
- package/src/theme/tokenValueCompat.test.ts +4 -1
- package/src/utils/interactionOverlay.stylex.ts +20 -0
- package/src/utils/safeUrl.test.ts +88 -0
- package/src/utils/safeUrl.ts +85 -0
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @file Markdown.tsx
|
|
7
|
-
* @input Markdown string,
|
|
7
|
+
* @input Markdown string, canonical AST, optional plugins and custom renderers
|
|
8
8
|
* @output Exports Markdown component, MarkdownProps, and renderer contracts
|
|
9
9
|
* @position Core implementation; renders markdown as Astryx components
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import {useMemo, useRef} from 'react';
|
|
12
|
+
import {Component, Suspense, useMemo, useRef} from 'react';
|
|
13
13
|
import type React from 'react';
|
|
14
14
|
import {Fragment} from 'react';
|
|
15
15
|
import * as stylex from '@stylexjs/stylex';
|
|
@@ -48,26 +48,43 @@ import type {CitationSource} from '../Citation/Citation';
|
|
|
48
48
|
import {useLinkComponent} from '../Link/useLinkComponent';
|
|
49
49
|
import type {LinkComponentType} from '../Link/types';
|
|
50
50
|
import {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
parseInlineAst,
|
|
52
|
+
parseMarkdownAst,
|
|
53
|
+
parseMarkdownAstIncremental,
|
|
54
54
|
createIncrementalState,
|
|
55
55
|
trimStreamingArtifacts,
|
|
56
|
-
inlineText,
|
|
57
56
|
slugify,
|
|
58
57
|
uniqueSlug,
|
|
59
58
|
} from './parser';
|
|
59
|
+
import type {IncrementalState, MathParseOptions, ParseOptions} from './parser';
|
|
60
|
+
import {getMarkdownAstLegacyCodeLanguage, markdownAstText} from './ast';
|
|
60
61
|
import type {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
62
|
+
MarkdownAstBlockContent,
|
|
63
|
+
MarkdownAstPhrasingContent,
|
|
64
|
+
MarkdownAstTable,
|
|
65
|
+
} from './ast';
|
|
66
|
+
import {
|
|
67
|
+
applyMarkdownTransforms,
|
|
68
|
+
getMarkdownExtensionRenderer,
|
|
69
|
+
markdownExtensionText,
|
|
70
|
+
prepareMarkdownPlugins,
|
|
71
|
+
reportMarkdownPluginFailure,
|
|
72
|
+
} from './plugins/protocol';
|
|
73
|
+
import {getMarkdownFenceProposal} from './plugins/semanticFence';
|
|
74
|
+
import type {
|
|
75
|
+
MarkdownExtensionNode,
|
|
76
|
+
MarkdownPluginEntry,
|
|
77
|
+
PreparedMarkdownPlugins,
|
|
78
|
+
} from './plugins/protocol';
|
|
79
|
+
import {sanitizeMarkdownLinkUrl, sanitizeMarkdownUrl} from './url';
|
|
67
80
|
import {themeProps} from '../utils/themeProps';
|
|
68
81
|
import {useTranslator, type TranslatorFn} from '../i18n';
|
|
69
82
|
|
|
70
83
|
type SyncReactNode = Exclude<React.ReactNode, Promise<unknown>>;
|
|
84
|
+
type RenderExtensionNode = MarkdownExtensionNode;
|
|
85
|
+
type RenderInlineNode = MarkdownAstPhrasingContent<RenderExtensionNode>;
|
|
86
|
+
type RenderBlockNode = MarkdownAstBlockContent<RenderExtensionNode>;
|
|
87
|
+
type RenderTable = MarkdownAstTable<RenderExtensionNode>;
|
|
71
88
|
|
|
72
89
|
// ---------------------------------------------------------------------------
|
|
73
90
|
// Props
|
|
@@ -140,7 +157,9 @@ export interface MarkdownComponents {
|
|
|
140
157
|
hr?: React.ComponentType<object>;
|
|
141
158
|
}
|
|
142
159
|
|
|
143
|
-
export interface MarkdownProps
|
|
160
|
+
export interface MarkdownProps<
|
|
161
|
+
Plugins extends ReadonlyArray<MarkdownPluginEntry> = readonly [],
|
|
162
|
+
> extends BaseProps<HTMLElement> {
|
|
144
163
|
ref?: React.Ref<HTMLDivElement> | React.Ref<HTMLSpanElement>;
|
|
145
164
|
children: string;
|
|
146
165
|
/**
|
|
@@ -201,6 +220,11 @@ export interface MarkdownProps extends BaseProps<HTMLElement> {
|
|
|
201
220
|
* are unaffected. Patterns are matched in order; first match wins
|
|
202
221
|
* for overlapping ranges.
|
|
203
222
|
*/
|
|
223
|
+
/** Ordered syntax, immutable transforms, and typed extension renderers. */
|
|
224
|
+
plugins?: Plugins;
|
|
225
|
+
/**
|
|
226
|
+
* Legacy text-match renderers. Unchanged and independent from `plugins`.
|
|
227
|
+
*/
|
|
204
228
|
inlinePlugins?: MarkdownInlinePlugin[];
|
|
205
229
|
/**
|
|
206
230
|
* Opt-in autolinking of bare URLs and emails inside text.
|
|
@@ -487,25 +511,25 @@ interface StreamingCursor {
|
|
|
487
511
|
* Count the total text characters in inline nodes without rendering.
|
|
488
512
|
* Used to advance the cursor past a block that will be faded as a whole unit.
|
|
489
513
|
*/
|
|
490
|
-
function countInlineTextLength(nodes:
|
|
514
|
+
function countInlineTextLength(nodes: ReadonlyArray<RenderInlineNode>): number {
|
|
491
515
|
let len = 0;
|
|
492
516
|
for (const node of nodes) {
|
|
493
517
|
switch (node.type) {
|
|
494
518
|
case 'text':
|
|
495
|
-
len += node.
|
|
519
|
+
len += node.value.length;
|
|
496
520
|
break;
|
|
497
|
-
case '
|
|
498
|
-
len += node.
|
|
521
|
+
case 'inlineCode':
|
|
522
|
+
len += node.value.length;
|
|
499
523
|
break;
|
|
500
|
-
case '
|
|
524
|
+
case 'inlineMath':
|
|
501
525
|
len += node.value.length;
|
|
502
526
|
break;
|
|
503
527
|
case 'image':
|
|
504
528
|
len += node.alt.length;
|
|
505
529
|
break;
|
|
506
|
-
case '
|
|
507
|
-
case '
|
|
508
|
-
case '
|
|
530
|
+
case 'strong':
|
|
531
|
+
case 'emphasis':
|
|
532
|
+
case 'delete':
|
|
509
533
|
case 'link':
|
|
510
534
|
len += countInlineTextLength(node.children);
|
|
511
535
|
break;
|
|
@@ -515,6 +539,9 @@ function countInlineTextLength(nodes: InlineNodeWithMath[]): number {
|
|
|
515
539
|
case 'citation':
|
|
516
540
|
len += 1;
|
|
517
541
|
break;
|
|
542
|
+
case 'extension':
|
|
543
|
+
len += node.source?.length ?? 0;
|
|
544
|
+
break;
|
|
518
545
|
}
|
|
519
546
|
}
|
|
520
547
|
return len;
|
|
@@ -523,7 +550,7 @@ function countInlineTextLength(nodes: InlineNodeWithMath[]): number {
|
|
|
523
550
|
/**
|
|
524
551
|
* Count total text characters in a block node tree.
|
|
525
552
|
*/
|
|
526
|
-
function countBlockTextLength(nodes:
|
|
553
|
+
function countBlockTextLength(nodes: ReadonlyArray<RenderBlockNode>): number {
|
|
527
554
|
let len = 0;
|
|
528
555
|
for (const node of nodes) {
|
|
529
556
|
switch (node.type) {
|
|
@@ -531,8 +558,8 @@ function countBlockTextLength(nodes: BlockNodeWithMath[]): number {
|
|
|
531
558
|
case 'paragraph':
|
|
532
559
|
len += countInlineTextLength(node.children);
|
|
533
560
|
break;
|
|
534
|
-
case '
|
|
535
|
-
len += node.
|
|
561
|
+
case 'code':
|
|
562
|
+
len += node.value.length;
|
|
536
563
|
break;
|
|
537
564
|
case 'math':
|
|
538
565
|
len += node.value.length;
|
|
@@ -541,21 +568,21 @@ function countBlockTextLength(nodes: BlockNodeWithMath[]): number {
|
|
|
541
568
|
len += countBlockTextLength(node.children);
|
|
542
569
|
break;
|
|
543
570
|
case 'list':
|
|
544
|
-
for (const item of node.
|
|
571
|
+
for (const item of node.children) {
|
|
545
572
|
len += countBlockTextLength(item.children);
|
|
546
573
|
}
|
|
547
574
|
break;
|
|
548
575
|
case 'table':
|
|
549
|
-
for (const
|
|
550
|
-
|
|
551
|
-
}
|
|
552
|
-
for (const row of node.rows) {
|
|
553
|
-
for (const cell of row) {
|
|
576
|
+
for (const row of node.children) {
|
|
577
|
+
for (const cell of row.children) {
|
|
554
578
|
len += countInlineTextLength(cell.children);
|
|
555
579
|
}
|
|
556
580
|
}
|
|
557
581
|
break;
|
|
558
|
-
case '
|
|
582
|
+
case 'extension':
|
|
583
|
+
len += node.source?.length ?? 0;
|
|
584
|
+
break;
|
|
585
|
+
case 'thematicBreak':
|
|
559
586
|
break;
|
|
560
587
|
case 'image':
|
|
561
588
|
len += node.alt.length;
|
|
@@ -575,27 +602,6 @@ const headingStyles = {
|
|
|
575
602
|
} as const;
|
|
576
603
|
|
|
577
604
|
// ---------------------------------------------------------------------------
|
|
578
|
-
// URL sanitization — block dangerous protocols
|
|
579
|
-
// ---------------------------------------------------------------------------
|
|
580
|
-
|
|
581
|
-
const DANGEROUS_URL_PATTERN = /^(javascript|data|vbscript):/i;
|
|
582
|
-
|
|
583
|
-
function sanitizeUrl(url: string): string | null {
|
|
584
|
-
// Strip control characters before testing, the same normalization the
|
|
585
|
-
// parser's isSafeUrl applies — the anchored pattern must see the URL the
|
|
586
|
-
// way a browser will. Return the normalized value so the stripped
|
|
587
|
-
// characters don't ride along into an attribute or component override.
|
|
588
|
-
// eslint-disable-next-line no-control-regex -- control chars are the bypass
|
|
589
|
-
const normalized = url.replace(/[\x00-\x1f\x7f]/g, '').trim();
|
|
590
|
-
if (normalized.length === 0) {
|
|
591
|
-
return null;
|
|
592
|
-
}
|
|
593
|
-
if (DANGEROUS_URL_PATTERN.test(normalized)) {
|
|
594
|
-
return null;
|
|
595
|
-
}
|
|
596
|
-
return normalized;
|
|
597
|
-
}
|
|
598
|
-
|
|
599
605
|
// ---------------------------------------------------------------------------
|
|
600
606
|
// Inline plugin matching
|
|
601
607
|
// ---------------------------------------------------------------------------
|
|
@@ -701,6 +707,81 @@ function applyInlinePlugins(
|
|
|
701
707
|
return segments;
|
|
702
708
|
}
|
|
703
709
|
|
|
710
|
+
interface MarkdownPluginBoundaryProps {
|
|
711
|
+
children: React.ReactNode;
|
|
712
|
+
fallback: React.ReactNode;
|
|
713
|
+
pluginName: string;
|
|
714
|
+
resetKey: unknown;
|
|
715
|
+
resetRenderer: unknown;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
interface MarkdownPluginBoundaryState {
|
|
719
|
+
failed: boolean;
|
|
720
|
+
resetKey: unknown;
|
|
721
|
+
resetRenderer: unknown;
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
class MarkdownPluginBoundary extends Component<
|
|
725
|
+
MarkdownPluginBoundaryProps,
|
|
726
|
+
MarkdownPluginBoundaryState
|
|
727
|
+
> {
|
|
728
|
+
state: MarkdownPluginBoundaryState = {
|
|
729
|
+
failed: false,
|
|
730
|
+
resetKey: this.props.resetKey,
|
|
731
|
+
resetRenderer: this.props.resetRenderer,
|
|
732
|
+
};
|
|
733
|
+
|
|
734
|
+
static getDerivedStateFromError(): Partial<MarkdownPluginBoundaryState> {
|
|
735
|
+
return {failed: true};
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
static getDerivedStateFromProps(
|
|
739
|
+
props: MarkdownPluginBoundaryProps,
|
|
740
|
+
state: MarkdownPluginBoundaryState,
|
|
741
|
+
): Partial<MarkdownPluginBoundaryState> | null {
|
|
742
|
+
return props.resetKey === state.resetKey &&
|
|
743
|
+
props.resetRenderer === state.resetRenderer
|
|
744
|
+
? null
|
|
745
|
+
: {
|
|
746
|
+
failed: false,
|
|
747
|
+
resetKey: props.resetKey,
|
|
748
|
+
resetRenderer: props.resetRenderer,
|
|
749
|
+
};
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
componentDidCatch(error: unknown): void {
|
|
753
|
+
reportMarkdownPluginFailure(this.props.pluginName, 'render', error);
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
render(): React.ReactNode {
|
|
757
|
+
return this.state.failed ? this.props.fallback : this.props.children;
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
function useStableMarkdownSyntaxEntries(
|
|
762
|
+
plugins: PreparedMarkdownPlugins | undefined,
|
|
763
|
+
): ReadonlyArray<MarkdownPluginEntry> | undefined {
|
|
764
|
+
const identity = plugins?.syntaxIdentity ?? '';
|
|
765
|
+
const syntaxEntriesRef = useRef<
|
|
766
|
+
| {
|
|
767
|
+
identity: string;
|
|
768
|
+
entries: ReadonlyArray<MarkdownPluginEntry> | undefined;
|
|
769
|
+
}
|
|
770
|
+
| undefined
|
|
771
|
+
>(undefined);
|
|
772
|
+
if (
|
|
773
|
+
syntaxEntriesRef.current == null ||
|
|
774
|
+
syntaxEntriesRef.current.identity !== identity
|
|
775
|
+
) {
|
|
776
|
+
syntaxEntriesRef.current = {
|
|
777
|
+
identity,
|
|
778
|
+
entries:
|
|
779
|
+
plugins == null || identity === '' ? undefined : plugins.syntaxEntries,
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
return syntaxEntriesRef.current.entries;
|
|
783
|
+
}
|
|
784
|
+
|
|
704
785
|
// ---------------------------------------------------------------------------
|
|
705
786
|
// Inline renderer
|
|
706
787
|
// ---------------------------------------------------------------------------
|
|
@@ -768,7 +849,7 @@ function getCitationNumber(ctx: CitationContext, sourceId: string): number {
|
|
|
768
849
|
}
|
|
769
850
|
|
|
770
851
|
function renderInline(
|
|
771
|
-
node:
|
|
852
|
+
node: RenderInlineNode,
|
|
772
853
|
index: number,
|
|
773
854
|
onLinkClick: MarkdownProps['onLinkClick'] | undefined,
|
|
774
855
|
cursor: StreamingCursor,
|
|
@@ -776,11 +857,12 @@ function renderInline(
|
|
|
776
857
|
linkComponent: LinkComponentType = 'a',
|
|
777
858
|
inlinePlugins?: MarkdownInlinePlugin[],
|
|
778
859
|
components?: Partial<MarkdownComponents>,
|
|
860
|
+
preparedPlugins?: PreparedMarkdownPlugins,
|
|
779
861
|
): SyncReactNode {
|
|
780
862
|
switch (node.type) {
|
|
781
863
|
case 'text': {
|
|
782
864
|
if (inlinePlugins && inlinePlugins.length > 0) {
|
|
783
|
-
const segments = applyInlinePlugins(node.
|
|
865
|
+
const segments = applyInlinePlugins(node.value, inlinePlugins);
|
|
784
866
|
// If no plugin matched, fall through to the normal path
|
|
785
867
|
// O(1) guard: applyInlinePlugins returns a single text segment when
|
|
786
868
|
// nothing matched — skip the plugin path entirely in that case.
|
|
@@ -803,9 +885,9 @@ function renderInline(
|
|
|
803
885
|
return <Fragment key={index}>{result}</Fragment>;
|
|
804
886
|
}
|
|
805
887
|
}
|
|
806
|
-
return wrapTextWithFade(node.
|
|
888
|
+
return wrapTextWithFade(node.value, cursor, index);
|
|
807
889
|
}
|
|
808
|
-
case '
|
|
890
|
+
case 'strong':
|
|
809
891
|
return (
|
|
810
892
|
<strong key={index} {...stylex.props(styles.bold)}>
|
|
811
893
|
{node.children.map((c, i) =>
|
|
@@ -818,11 +900,12 @@ function renderInline(
|
|
|
818
900
|
linkComponent,
|
|
819
901
|
inlinePlugins,
|
|
820
902
|
components,
|
|
903
|
+
preparedPlugins,
|
|
821
904
|
),
|
|
822
905
|
)}
|
|
823
906
|
</strong>
|
|
824
907
|
);
|
|
825
|
-
case '
|
|
908
|
+
case 'emphasis':
|
|
826
909
|
return (
|
|
827
910
|
<em key={index}>
|
|
828
911
|
{node.children.map((c, i) =>
|
|
@@ -835,11 +918,12 @@ function renderInline(
|
|
|
835
918
|
linkComponent,
|
|
836
919
|
inlinePlugins,
|
|
837
920
|
components,
|
|
921
|
+
preparedPlugins,
|
|
838
922
|
),
|
|
839
923
|
)}
|
|
840
924
|
</em>
|
|
841
925
|
);
|
|
842
|
-
case '
|
|
926
|
+
case 'delete':
|
|
843
927
|
return (
|
|
844
928
|
<del key={index} {...stylex.props(styles.strikethrough)}>
|
|
845
929
|
{node.children.map((c, i) =>
|
|
@@ -852,22 +936,23 @@ function renderInline(
|
|
|
852
936
|
linkComponent,
|
|
853
937
|
inlinePlugins,
|
|
854
938
|
components,
|
|
939
|
+
preparedPlugins,
|
|
855
940
|
),
|
|
856
941
|
)}
|
|
857
942
|
</del>
|
|
858
943
|
);
|
|
859
|
-
case '
|
|
944
|
+
case 'inlineCode': {
|
|
860
945
|
// Track code content length for cursor but don't split inside code
|
|
861
|
-
cursor.offset += node.
|
|
946
|
+
cursor.offset += node.value.length;
|
|
862
947
|
const InlineCodeComp = components?.inlineCode;
|
|
863
948
|
const codeEl = InlineCodeComp ? (
|
|
864
|
-
<InlineCodeComp key={index}>{node.
|
|
949
|
+
<InlineCodeComp key={index}>{node.value}</InlineCodeComp>
|
|
865
950
|
) : (
|
|
866
|
-
<Code key={index}>{node.
|
|
951
|
+
<Code key={index}>{node.value}</Code>
|
|
867
952
|
);
|
|
868
953
|
return codeEl;
|
|
869
954
|
}
|
|
870
|
-
case '
|
|
955
|
+
case 'inlineMath': {
|
|
871
956
|
const MathComp = components?.math;
|
|
872
957
|
if (MathComp == null) {
|
|
873
958
|
return wrapTextWithFade(`$${node.value}$`, cursor, index);
|
|
@@ -876,7 +961,7 @@ function renderInline(
|
|
|
876
961
|
return <MathComp key={index} value={node.value} display="inline" />;
|
|
877
962
|
}
|
|
878
963
|
case 'link': {
|
|
879
|
-
const safeHref =
|
|
964
|
+
const safeHref = sanitizeMarkdownLinkUrl(node.url);
|
|
880
965
|
if (safeHref == null) {
|
|
881
966
|
// Unsafe URL — render as plain text
|
|
882
967
|
return (
|
|
@@ -891,6 +976,7 @@ function renderInline(
|
|
|
891
976
|
linkComponent,
|
|
892
977
|
inlinePlugins,
|
|
893
978
|
components,
|
|
979
|
+
preparedPlugins,
|
|
894
980
|
),
|
|
895
981
|
)}
|
|
896
982
|
</span>
|
|
@@ -910,6 +996,7 @@ function renderInline(
|
|
|
910
996
|
linkComponent,
|
|
911
997
|
inlinePlugins,
|
|
912
998
|
components,
|
|
999
|
+
preparedPlugins,
|
|
913
1000
|
),
|
|
914
1001
|
)}
|
|
915
1002
|
</LinkComp>
|
|
@@ -948,13 +1035,14 @@ function renderInline(
|
|
|
948
1035
|
linkComponent,
|
|
949
1036
|
inlinePlugins,
|
|
950
1037
|
components,
|
|
1038
|
+
preparedPlugins,
|
|
951
1039
|
),
|
|
952
1040
|
)}
|
|
953
1041
|
</LinkTag>
|
|
954
1042
|
);
|
|
955
1043
|
}
|
|
956
1044
|
case 'image': {
|
|
957
|
-
const safeSrc =
|
|
1045
|
+
const safeSrc = sanitizeMarkdownUrl(node.url);
|
|
958
1046
|
if (safeSrc == null) {
|
|
959
1047
|
return <span key={index}>[{node.alt}]</span>;
|
|
960
1048
|
}
|
|
@@ -971,6 +1059,34 @@ function renderInline(
|
|
|
971
1059
|
/>
|
|
972
1060
|
);
|
|
973
1061
|
}
|
|
1062
|
+
case 'extension': {
|
|
1063
|
+
const renderer = getMarkdownExtensionRenderer(preparedPlugins, node);
|
|
1064
|
+
const fallback = wrapTextWithFade(
|
|
1065
|
+
node.source ?? markdownExtensionText(preparedPlugins, node),
|
|
1066
|
+
cursor,
|
|
1067
|
+
index,
|
|
1068
|
+
);
|
|
1069
|
+
if (renderer == null) {
|
|
1070
|
+
return fallback;
|
|
1071
|
+
}
|
|
1072
|
+
let rendered: React.ReactNode;
|
|
1073
|
+
try {
|
|
1074
|
+
rendered = renderer.render({node});
|
|
1075
|
+
} catch (error) {
|
|
1076
|
+
reportMarkdownPluginFailure(node.plugin, 'render', error);
|
|
1077
|
+
return fallback;
|
|
1078
|
+
}
|
|
1079
|
+
return (
|
|
1080
|
+
<MarkdownPluginBoundary
|
|
1081
|
+
key={index}
|
|
1082
|
+
pluginName={node.plugin}
|
|
1083
|
+
resetKey={node}
|
|
1084
|
+
resetRenderer={renderer.render}
|
|
1085
|
+
fallback={fallback}>
|
|
1086
|
+
<Suspense fallback={fallback}>{rendered}</Suspense>
|
|
1087
|
+
</MarkdownPluginBoundary>
|
|
1088
|
+
);
|
|
1089
|
+
}
|
|
974
1090
|
case 'break':
|
|
975
1091
|
cursor.offset += 1;
|
|
976
1092
|
return <br key={index} />;
|
|
@@ -1012,13 +1128,13 @@ function renderInline(
|
|
|
1012
1128
|
// ---------------------------------------------------------------------------
|
|
1013
1129
|
|
|
1014
1130
|
function getElementSpacing(
|
|
1015
|
-
node:
|
|
1131
|
+
node: RenderBlockNode,
|
|
1016
1132
|
density: 'default' | 'compact',
|
|
1017
1133
|
): StyleXStyles {
|
|
1018
1134
|
const compact = density === 'compact';
|
|
1019
1135
|
switch (node.type) {
|
|
1020
1136
|
case 'heading':
|
|
1021
|
-
return node.
|
|
1137
|
+
return node.depth <= 3
|
|
1022
1138
|
? compact
|
|
1023
1139
|
? styles.spacingHeadingMajorCompact
|
|
1024
1140
|
: styles.spacingHeadingMajorDefault
|
|
@@ -1029,7 +1145,7 @@ function getElementSpacing(
|
|
|
1029
1145
|
return compact
|
|
1030
1146
|
? styles.spacingParagraphCompact
|
|
1031
1147
|
: styles.spacingParagraphDefault;
|
|
1032
|
-
case '
|
|
1148
|
+
case 'code':
|
|
1033
1149
|
case 'math':
|
|
1034
1150
|
return compact
|
|
1035
1151
|
? styles.spacingCodeblockCompact
|
|
@@ -1042,7 +1158,11 @@ function getElementSpacing(
|
|
|
1042
1158
|
return compact ? styles.spacingListCompact : styles.spacingListDefault;
|
|
1043
1159
|
case 'table':
|
|
1044
1160
|
return compact ? styles.spacingTableCompact : styles.spacingTableDefault;
|
|
1045
|
-
case '
|
|
1161
|
+
case 'extension':
|
|
1162
|
+
return compact
|
|
1163
|
+
? styles.spacingParagraphCompact
|
|
1164
|
+
: styles.spacingParagraphDefault;
|
|
1165
|
+
case 'thematicBreak':
|
|
1046
1166
|
return compact ? styles.spacingHrCompact : styles.spacingHrDefault;
|
|
1047
1167
|
case 'image':
|
|
1048
1168
|
return compact ? styles.spacingImageCompact : styles.spacingImageDefault;
|
|
@@ -1057,15 +1177,17 @@ function getElementSpacing(
|
|
|
1057
1177
|
* Compute per-column min-widths from table AST content.
|
|
1058
1178
|
* Buckets: ≤6 chars → 60px, 7–15 → 80px, >15 → 120px.
|
|
1059
1179
|
*/
|
|
1060
|
-
function computeTableColumnMinWidths(node: {
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1180
|
+
function computeTableColumnMinWidths(node: RenderTable): number[] {
|
|
1181
|
+
const [header, ...rows] = node.children;
|
|
1182
|
+
if (header == null) {
|
|
1183
|
+
return [];
|
|
1184
|
+
}
|
|
1185
|
+
return header.children.map((cell, colIdx) => {
|
|
1186
|
+
let maxLen = countInlineTextLength(cell.children);
|
|
1187
|
+
for (const row of rows) {
|
|
1188
|
+
const rowCell = row.children[colIdx];
|
|
1189
|
+
if (rowCell != null) {
|
|
1190
|
+
const len = countInlineTextLength(rowCell.children);
|
|
1069
1191
|
if (len > maxLen) {
|
|
1070
1192
|
maxLen = len;
|
|
1071
1193
|
}
|
|
@@ -1076,7 +1198,7 @@ function computeTableColumnMinWidths(node: {
|
|
|
1076
1198
|
}
|
|
1077
1199
|
|
|
1078
1200
|
function renderBlock(
|
|
1079
|
-
node:
|
|
1201
|
+
node: RenderBlockNode,
|
|
1080
1202
|
index: number,
|
|
1081
1203
|
blockCount: number,
|
|
1082
1204
|
density: 'default' | 'compact',
|
|
@@ -1089,8 +1211,9 @@ function renderBlock(
|
|
|
1089
1211
|
linkComponent: LinkComponentType = 'a',
|
|
1090
1212
|
inlinePlugins: MarkdownInlinePlugin[] | undefined,
|
|
1091
1213
|
components: Partial<MarkdownComponents> | undefined,
|
|
1214
|
+
preparedPlugins: PreparedMarkdownPlugins | undefined,
|
|
1092
1215
|
t: TranslatorFn,
|
|
1093
|
-
headingIdMap?: ReadonlyMap<
|
|
1216
|
+
headingIdMap?: ReadonlyMap<RenderBlockNode, string>,
|
|
1094
1217
|
): SyncReactNode {
|
|
1095
1218
|
const blockAlignMargin = BLOCK_ALIGN_MARGIN[contentAlign];
|
|
1096
1219
|
const blockAlignStyle =
|
|
@@ -1103,7 +1226,7 @@ function renderBlock(
|
|
|
1103
1226
|
|
|
1104
1227
|
switch (node.type) {
|
|
1105
1228
|
case 'heading': {
|
|
1106
|
-
const level = Math.min(node.
|
|
1229
|
+
const level = Math.min(node.depth + headingLevelStart - 1, 6) as
|
|
1107
1230
|
1 | 2 | 3 | 4 | 5 | 6;
|
|
1108
1231
|
const headingChildren = node.children.map((c, i) =>
|
|
1109
1232
|
renderInline(
|
|
@@ -1115,6 +1238,7 @@ function renderBlock(
|
|
|
1115
1238
|
linkComponent,
|
|
1116
1239
|
inlinePlugins,
|
|
1117
1240
|
components,
|
|
1241
|
+
preparedPlugins,
|
|
1118
1242
|
),
|
|
1119
1243
|
);
|
|
1120
1244
|
// Only top-level headings get an id: the map is built from the same
|
|
@@ -1166,6 +1290,7 @@ function renderBlock(
|
|
|
1166
1290
|
linkComponent,
|
|
1167
1291
|
inlinePlugins,
|
|
1168
1292
|
components,
|
|
1293
|
+
preparedPlugins,
|
|
1169
1294
|
),
|
|
1170
1295
|
);
|
|
1171
1296
|
const ParagraphComp = components?.paragraph;
|
|
@@ -1203,20 +1328,17 @@ function renderBlock(
|
|
|
1203
1328
|
</div>
|
|
1204
1329
|
);
|
|
1205
1330
|
}
|
|
1206
|
-
case '
|
|
1331
|
+
case 'code': {
|
|
1207
1332
|
// Track codeblock content in cursor for accurate character counting
|
|
1208
|
-
cursor.offset += node.
|
|
1333
|
+
cursor.offset += node.value.length;
|
|
1334
|
+
const language = getMarkdownAstLegacyCodeLanguage(node) ?? 'plaintext';
|
|
1209
1335
|
const CodeBlockComp = components?.code;
|
|
1210
1336
|
if (CodeBlockComp) {
|
|
1211
1337
|
return (
|
|
1212
|
-
<CodeBlockComp
|
|
1213
|
-
key={index}
|
|
1214
|
-
code={node.content}
|
|
1215
|
-
language={node.language}
|
|
1216
|
-
/>
|
|
1338
|
+
<CodeBlockComp key={index} code={node.value} language={language} />
|
|
1217
1339
|
);
|
|
1218
1340
|
}
|
|
1219
|
-
|
|
1341
|
+
const fallback = (
|
|
1220
1342
|
<div
|
|
1221
1343
|
key={index}
|
|
1222
1344
|
{...mergeProps(
|
|
@@ -1229,8 +1351,8 @@ function renderBlock(
|
|
|
1229
1351
|
),
|
|
1230
1352
|
)}>
|
|
1231
1353
|
<CodeBlock
|
|
1232
|
-
code={node.
|
|
1233
|
-
language={
|
|
1354
|
+
code={node.value}
|
|
1355
|
+
language={language}
|
|
1234
1356
|
isCollapsible
|
|
1235
1357
|
xstyle={[
|
|
1236
1358
|
contentWidthValue != null
|
|
@@ -1241,6 +1363,36 @@ function renderBlock(
|
|
|
1241
1363
|
/>
|
|
1242
1364
|
</div>
|
|
1243
1365
|
);
|
|
1366
|
+
const proposal = getMarkdownFenceProposal(node);
|
|
1367
|
+
if (proposal == null) {
|
|
1368
|
+
return fallback;
|
|
1369
|
+
}
|
|
1370
|
+
const renderer = getMarkdownExtensionRenderer(
|
|
1371
|
+
preparedPlugins,
|
|
1372
|
+
proposal.node,
|
|
1373
|
+
);
|
|
1374
|
+
if (renderer == null) {
|
|
1375
|
+
return fallback;
|
|
1376
|
+
}
|
|
1377
|
+
try {
|
|
1378
|
+
const rendered = renderer.render({node: proposal.node});
|
|
1379
|
+
if (rendered == null || typeof rendered === 'boolean') {
|
|
1380
|
+
return fallback;
|
|
1381
|
+
}
|
|
1382
|
+
return (
|
|
1383
|
+
<MarkdownPluginBoundary
|
|
1384
|
+
key={index}
|
|
1385
|
+
pluginName={proposal.node.plugin}
|
|
1386
|
+
resetKey={proposal.node}
|
|
1387
|
+
resetRenderer={renderer.render}
|
|
1388
|
+
fallback={fallback}>
|
|
1389
|
+
<Suspense fallback={fallback}>{rendered}</Suspense>
|
|
1390
|
+
</MarkdownPluginBoundary>
|
|
1391
|
+
);
|
|
1392
|
+
} catch (error) {
|
|
1393
|
+
reportMarkdownPluginFailure(proposal.node.plugin, 'render', error);
|
|
1394
|
+
return fallback;
|
|
1395
|
+
}
|
|
1244
1396
|
}
|
|
1245
1397
|
case 'math': {
|
|
1246
1398
|
cursor.offset += node.value.length;
|
|
@@ -1272,6 +1424,7 @@ function renderBlock(
|
|
|
1272
1424
|
linkComponent,
|
|
1273
1425
|
inlinePlugins,
|
|
1274
1426
|
components,
|
|
1427
|
+
preparedPlugins,
|
|
1275
1428
|
t,
|
|
1276
1429
|
),
|
|
1277
1430
|
);
|
|
@@ -1307,6 +1460,7 @@ function renderBlock(
|
|
|
1307
1460
|
linkComponent,
|
|
1308
1461
|
inlinePlugins,
|
|
1309
1462
|
components,
|
|
1463
|
+
preparedPlugins,
|
|
1310
1464
|
t,
|
|
1311
1465
|
),
|
|
1312
1466
|
)}
|
|
@@ -1316,11 +1470,12 @@ function renderBlock(
|
|
|
1316
1470
|
case 'list': {
|
|
1317
1471
|
// Detect task lists: all items have a checked state
|
|
1318
1472
|
const isTaskList =
|
|
1319
|
-
node.
|
|
1473
|
+
node.children.length > 0 &&
|
|
1474
|
+
node.children.every(item => item.checked != null);
|
|
1320
1475
|
|
|
1321
1476
|
if (isTaskList) {
|
|
1322
1477
|
// Extract labels from task items — render as rich inline content
|
|
1323
|
-
const checkedValues = node.
|
|
1478
|
+
const checkedValues = node.children
|
|
1324
1479
|
.map((item, i) => ({item, key: `task-${i}`}))
|
|
1325
1480
|
.filter(({item}) => item.checked)
|
|
1326
1481
|
.map(({key}) => key);
|
|
@@ -1343,7 +1498,7 @@ function renderBlock(
|
|
|
1343
1498
|
xstyle={styles.blockIndent}
|
|
1344
1499
|
isReadOnly
|
|
1345
1500
|
density="compact">
|
|
1346
|
-
{node.
|
|
1501
|
+
{node.children.map((item, i) => {
|
|
1347
1502
|
const firstChild = item.children[0];
|
|
1348
1503
|
const isInline =
|
|
1349
1504
|
item.children.length === 1 &&
|
|
@@ -1361,6 +1516,7 @@ function renderBlock(
|
|
|
1361
1516
|
linkComponent,
|
|
1362
1517
|
inlinePlugins,
|
|
1363
1518
|
components,
|
|
1519
|
+
preparedPlugins,
|
|
1364
1520
|
),
|
|
1365
1521
|
)}
|
|
1366
1522
|
</>
|
|
@@ -1381,6 +1537,7 @@ function renderBlock(
|
|
|
1381
1537
|
linkComponent,
|
|
1382
1538
|
inlinePlugins,
|
|
1383
1539
|
components,
|
|
1540
|
+
preparedPlugins,
|
|
1384
1541
|
t,
|
|
1385
1542
|
),
|
|
1386
1543
|
)}
|
|
@@ -1423,7 +1580,7 @@ function renderBlock(
|
|
|
1423
1580
|
density="compact"
|
|
1424
1581
|
start={node.ordered ? node.start : undefined}
|
|
1425
1582
|
xstyle={styles.blockIndent}>
|
|
1426
|
-
{node.
|
|
1583
|
+
{node.children.map((item, i) => {
|
|
1427
1584
|
const firstChild = item.children[0];
|
|
1428
1585
|
const isInline =
|
|
1429
1586
|
item.children.length === 1 && firstChild?.type === 'paragraph';
|
|
@@ -1443,6 +1600,7 @@ function renderBlock(
|
|
|
1443
1600
|
linkComponent,
|
|
1444
1601
|
inlinePlugins,
|
|
1445
1602
|
components,
|
|
1603
|
+
preparedPlugins,
|
|
1446
1604
|
),
|
|
1447
1605
|
)}
|
|
1448
1606
|
</>
|
|
@@ -1463,6 +1621,7 @@ function renderBlock(
|
|
|
1463
1621
|
linkComponent,
|
|
1464
1622
|
inlinePlugins,
|
|
1465
1623
|
components,
|
|
1624
|
+
preparedPlugins,
|
|
1466
1625
|
t,
|
|
1467
1626
|
),
|
|
1468
1627
|
)}
|
|
@@ -1483,6 +1642,7 @@ function renderBlock(
|
|
|
1483
1642
|
}
|
|
1484
1643
|
case 'table': {
|
|
1485
1644
|
const colMinWidths = computeTableColumnMinWidths(node);
|
|
1645
|
+
const [header, ...rows] = node.children;
|
|
1486
1646
|
|
|
1487
1647
|
return (
|
|
1488
1648
|
<div
|
|
@@ -1512,14 +1672,14 @@ function renderBlock(
|
|
|
1512
1672
|
<Table dividers="rows" textOverflow="wrap">
|
|
1513
1673
|
<TableHeader>
|
|
1514
1674
|
<TableRow>
|
|
1515
|
-
{
|
|
1675
|
+
{header?.children.map((h, i) => (
|
|
1516
1676
|
<TableHeaderCell
|
|
1517
1677
|
// eslint-disable-next-line @eslint-react/no-array-index-key -- markdown table columns are positional by definition
|
|
1518
1678
|
key={i}
|
|
1519
1679
|
xstyle={[
|
|
1520
1680
|
dynamicStyles.cellMinWidth(`${colMinWidths[i]}px`),
|
|
1521
|
-
node.
|
|
1522
|
-
node.
|
|
1681
|
+
node.align[i] === 'center' && cellAlignStyles.center,
|
|
1682
|
+
node.align[i] === 'right' && cellAlignStyles.end,
|
|
1523
1683
|
]}>
|
|
1524
1684
|
{h.children.map((c, j) =>
|
|
1525
1685
|
renderInline(
|
|
@@ -1531,6 +1691,7 @@ function renderBlock(
|
|
|
1531
1691
|
linkComponent,
|
|
1532
1692
|
inlinePlugins,
|
|
1533
1693
|
components,
|
|
1694
|
+
preparedPlugins,
|
|
1534
1695
|
),
|
|
1535
1696
|
)}
|
|
1536
1697
|
</TableHeaderCell>
|
|
@@ -1538,14 +1699,14 @@ function renderBlock(
|
|
|
1538
1699
|
</TableRow>
|
|
1539
1700
|
</TableHeader>
|
|
1540
1701
|
<TableBody>
|
|
1541
|
-
{
|
|
1542
|
-
const cells = row.map((cell, j) => (
|
|
1702
|
+
{rows.map((row, i) => {
|
|
1703
|
+
const cells = row.children.map((cell, j) => (
|
|
1543
1704
|
<TableCell
|
|
1544
1705
|
// eslint-disable-next-line @eslint-react/no-array-index-key -- markdown table cells are positional by row and column
|
|
1545
1706
|
key={j}
|
|
1546
1707
|
xstyle={[
|
|
1547
|
-
node.
|
|
1548
|
-
node.
|
|
1708
|
+
node.align[j] === 'center' && cellAlignStyles.center,
|
|
1709
|
+
node.align[j] === 'right' && cellAlignStyles.end,
|
|
1549
1710
|
]}>
|
|
1550
1711
|
{cell.children.map((c, k) =>
|
|
1551
1712
|
renderInline(
|
|
@@ -1557,6 +1718,7 @@ function renderBlock(
|
|
|
1557
1718
|
linkComponent,
|
|
1558
1719
|
inlinePlugins,
|
|
1559
1720
|
components,
|
|
1721
|
+
preparedPlugins,
|
|
1560
1722
|
),
|
|
1561
1723
|
)}
|
|
1562
1724
|
</TableCell>
|
|
@@ -1574,7 +1736,47 @@ function renderBlock(
|
|
|
1574
1736
|
</div>
|
|
1575
1737
|
);
|
|
1576
1738
|
}
|
|
1577
|
-
case '
|
|
1739
|
+
case 'extension': {
|
|
1740
|
+
const renderer = getMarkdownExtensionRenderer(preparedPlugins, node);
|
|
1741
|
+
const fallbackText =
|
|
1742
|
+
node.source ?? markdownExtensionText(preparedPlugins, node);
|
|
1743
|
+
const fallback = wrapTextWithFade(fallbackText, cursor, index);
|
|
1744
|
+
let content: React.ReactNode = fallback;
|
|
1745
|
+
if (renderer != null) {
|
|
1746
|
+
try {
|
|
1747
|
+
const rendered = renderer.render({node});
|
|
1748
|
+
content = (
|
|
1749
|
+
<MarkdownPluginBoundary
|
|
1750
|
+
pluginName={node.plugin}
|
|
1751
|
+
resetKey={node}
|
|
1752
|
+
resetRenderer={renderer.render}
|
|
1753
|
+
fallback={fallback}>
|
|
1754
|
+
<Suspense fallback={fallback}>{rendered}</Suspense>
|
|
1755
|
+
</MarkdownPluginBoundary>
|
|
1756
|
+
);
|
|
1757
|
+
} catch (error) {
|
|
1758
|
+
reportMarkdownPluginFailure(node.plugin, 'render', error);
|
|
1759
|
+
}
|
|
1760
|
+
}
|
|
1761
|
+
return (
|
|
1762
|
+
<div
|
|
1763
|
+
key={index}
|
|
1764
|
+
{...stylex.props(
|
|
1765
|
+
spacing,
|
|
1766
|
+
contentWidthValue != null
|
|
1767
|
+
? dynamicStyles.proseWidth(contentWidthValue)
|
|
1768
|
+
: null,
|
|
1769
|
+
contentAlign !== 'start'
|
|
1770
|
+
? dynamicStyles.proseAlign(ALIGN_MARGIN[contentAlign])
|
|
1771
|
+
: null,
|
|
1772
|
+
isFirst && styles.noMarginBlockStart,
|
|
1773
|
+
isLast && styles.noMarginBlockEnd,
|
|
1774
|
+
)}>
|
|
1775
|
+
{content}
|
|
1776
|
+
</div>
|
|
1777
|
+
);
|
|
1778
|
+
}
|
|
1779
|
+
case 'thematicBreak': {
|
|
1578
1780
|
const HrComp = components?.hr;
|
|
1579
1781
|
if (HrComp) {
|
|
1580
1782
|
return <HrComp key={index} />;
|
|
@@ -1595,7 +1797,7 @@ function renderBlock(
|
|
|
1595
1797
|
);
|
|
1596
1798
|
}
|
|
1597
1799
|
case 'image': {
|
|
1598
|
-
const safeSrc =
|
|
1800
|
+
const safeSrc = sanitizeMarkdownUrl(node.url);
|
|
1599
1801
|
if (safeSrc == null) {
|
|
1600
1802
|
return (
|
|
1601
1803
|
<div
|
|
@@ -1649,7 +1851,9 @@ function renderBlock(
|
|
|
1649
1851
|
* </Markdown>
|
|
1650
1852
|
* ```
|
|
1651
1853
|
*/
|
|
1652
|
-
export function Markdown
|
|
1854
|
+
export function Markdown<
|
|
1855
|
+
const Plugins extends ReadonlyArray<MarkdownPluginEntry> = readonly [],
|
|
1856
|
+
>({
|
|
1653
1857
|
ref,
|
|
1654
1858
|
children,
|
|
1655
1859
|
display = 'block',
|
|
@@ -1662,6 +1866,7 @@ export function Markdown({
|
|
|
1662
1866
|
contentWidth = 680,
|
|
1663
1867
|
contentAlign = 'start',
|
|
1664
1868
|
components,
|
|
1869
|
+
plugins,
|
|
1665
1870
|
inlinePlugins,
|
|
1666
1871
|
autolink,
|
|
1667
1872
|
xstyle,
|
|
@@ -1669,7 +1874,7 @@ export function Markdown({
|
|
|
1669
1874
|
style,
|
|
1670
1875
|
'data-testid': testId,
|
|
1671
1876
|
...props
|
|
1672
|
-
}: MarkdownProps): React.ReactElement {
|
|
1877
|
+
}: MarkdownProps<Plugins>): React.ReactElement {
|
|
1673
1878
|
const t = useTranslator();
|
|
1674
1879
|
const LinkComponent = useLinkComponent();
|
|
1675
1880
|
// Derive the set of source IDs for the parser (stable across renders when sources don't change)
|
|
@@ -1678,14 +1883,30 @@ export function Markdown({
|
|
|
1678
1883
|
[sources],
|
|
1679
1884
|
);
|
|
1680
1885
|
|
|
1886
|
+
const preparedPlugins = useMemo(() => {
|
|
1887
|
+
if (plugins == null) {
|
|
1888
|
+
return undefined;
|
|
1889
|
+
}
|
|
1890
|
+
try {
|
|
1891
|
+
return prepareMarkdownPlugins(plugins);
|
|
1892
|
+
} catch (error) {
|
|
1893
|
+
reportMarkdownPluginFailure('configuration', 'transform', error);
|
|
1894
|
+
return undefined;
|
|
1895
|
+
}
|
|
1896
|
+
}, [plugins]);
|
|
1897
|
+
const syntaxPlugins = useStableMarkdownSyntaxEntries(preparedPlugins);
|
|
1681
1898
|
const hasMathRenderer = components?.math != null;
|
|
1682
|
-
const legacyParseOptions = useMemo<
|
|
1683
|
-
|
|
1684
|
-
|
|
1899
|
+
const legacyParseOptions = useMemo<
|
|
1900
|
+
ParseOptions<ReadonlyArray<MarkdownPluginEntry>>
|
|
1901
|
+
>(
|
|
1902
|
+
() => ({sourceIds, autolink, plugins: syntaxPlugins}),
|
|
1903
|
+
[sourceIds, autolink, syntaxPlugins],
|
|
1685
1904
|
);
|
|
1686
|
-
const mathParseOptions = useMemo<
|
|
1687
|
-
|
|
1688
|
-
|
|
1905
|
+
const mathParseOptions = useMemo<
|
|
1906
|
+
MathParseOptions<ReadonlyArray<MarkdownPluginEntry>>
|
|
1907
|
+
>(
|
|
1908
|
+
() => ({sourceIds, autolink, math: true, plugins: syntaxPlugins}),
|
|
1909
|
+
[sourceIds, autolink, syntaxPlugins],
|
|
1689
1910
|
);
|
|
1690
1911
|
|
|
1691
1912
|
// Smooth bursty streamed chunks into a steady character-by-character reveal.
|
|
@@ -1708,7 +1929,7 @@ export function Markdown({
|
|
|
1708
1929
|
prevMathRef.current = hasMathRenderer;
|
|
1709
1930
|
}
|
|
1710
1931
|
|
|
1711
|
-
const
|
|
1932
|
+
const parsedBlocks = useMemo(() => {
|
|
1712
1933
|
if (display === 'inline') {
|
|
1713
1934
|
return [];
|
|
1714
1935
|
}
|
|
@@ -1719,21 +1940,25 @@ export function Markdown({
|
|
|
1719
1940
|
}
|
|
1720
1941
|
const options = hasMathRenderer ? mathParseOptions : legacyParseOptions;
|
|
1721
1942
|
const input = trimStreamingArtifacts(smoothedText, options);
|
|
1722
|
-
return
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1943
|
+
return (
|
|
1944
|
+
hasMathRenderer
|
|
1945
|
+
? parseMarkdownAstIncremental(
|
|
1946
|
+
input,
|
|
1947
|
+
incrementalStateRef.current,
|
|
1948
|
+
mathParseOptions,
|
|
1949
|
+
)
|
|
1950
|
+
: parseMarkdownAstIncremental(
|
|
1951
|
+
input,
|
|
1952
|
+
incrementalStateRef.current,
|
|
1953
|
+
legacyParseOptions,
|
|
1954
|
+
)
|
|
1955
|
+
).children;
|
|
1733
1956
|
}
|
|
1734
|
-
return
|
|
1735
|
-
|
|
1736
|
-
|
|
1957
|
+
return (
|
|
1958
|
+
hasMathRenderer
|
|
1959
|
+
? parseMarkdownAst(children, mathParseOptions)
|
|
1960
|
+
: parseMarkdownAst(children, legacyParseOptions)
|
|
1961
|
+
).children;
|
|
1737
1962
|
}, [
|
|
1738
1963
|
display,
|
|
1739
1964
|
smoothedText,
|
|
@@ -1744,6 +1969,24 @@ export function Markdown({
|
|
|
1744
1969
|
legacyParseOptions,
|
|
1745
1970
|
]);
|
|
1746
1971
|
|
|
1972
|
+
const transformSource = isStreaming
|
|
1973
|
+
? trimStreamingArtifacts(
|
|
1974
|
+
smoothedText,
|
|
1975
|
+
hasMathRenderer ? mathParseOptions : legacyParseOptions,
|
|
1976
|
+
)
|
|
1977
|
+
: children;
|
|
1978
|
+
const blocks = useMemo(
|
|
1979
|
+
() =>
|
|
1980
|
+
applyMarkdownTransforms(
|
|
1981
|
+
{type: 'root', children: parsedBlocks},
|
|
1982
|
+
preparedPlugins,
|
|
1983
|
+
transformSource,
|
|
1984
|
+
!isStreaming,
|
|
1985
|
+
'block',
|
|
1986
|
+
).children,
|
|
1987
|
+
[parsedBlocks, preparedPlugins, transformSource, isStreaming],
|
|
1988
|
+
);
|
|
1989
|
+
|
|
1747
1990
|
// Assign each top-level heading the slug that parseOutlineFromMarkdown
|
|
1748
1991
|
// would derive for it, so Outline hash links built from the same source
|
|
1749
1992
|
// always find a matching DOM id. Mirrors that function's traversal exactly:
|
|
@@ -1754,18 +1997,20 @@ export function Markdown({
|
|
|
1754
1997
|
if (display === 'inline' || blocks.length === 0) {
|
|
1755
1998
|
return undefined;
|
|
1756
1999
|
}
|
|
1757
|
-
const map = new Map<
|
|
2000
|
+
const map = new Map<RenderBlockNode, string>();
|
|
1758
2001
|
const counts = new Map<string, number>();
|
|
1759
2002
|
for (const block of blocks) {
|
|
1760
2003
|
if (block.type === 'heading') {
|
|
1761
|
-
const label =
|
|
2004
|
+
const label = markdownAstText(block.children, node =>
|
|
2005
|
+
markdownExtensionText(preparedPlugins, node),
|
|
2006
|
+
).trim();
|
|
1762
2007
|
map.set(block, uniqueSlug(slugify(label), counts));
|
|
1763
2008
|
}
|
|
1764
2009
|
}
|
|
1765
2010
|
return map;
|
|
1766
|
-
}, [display, blocks]);
|
|
2011
|
+
}, [display, blocks, preparedPlugins]);
|
|
1767
2012
|
|
|
1768
|
-
const
|
|
2013
|
+
const parsedInlineNodes = useMemo(() => {
|
|
1769
2014
|
if (display !== 'inline') {
|
|
1770
2015
|
return [];
|
|
1771
2016
|
}
|
|
@@ -1774,8 +2019,8 @@ export function Markdown({
|
|
|
1774
2019
|
? trimStreamingArtifacts(smoothedText, options)
|
|
1775
2020
|
: children;
|
|
1776
2021
|
return hasMathRenderer
|
|
1777
|
-
?
|
|
1778
|
-
:
|
|
2022
|
+
? parseInlineAst(input, mathParseOptions)
|
|
2023
|
+
: parseInlineAst(input, legacyParseOptions);
|
|
1779
2024
|
}, [
|
|
1780
2025
|
display,
|
|
1781
2026
|
smoothedText,
|
|
@@ -1786,6 +2031,38 @@ export function Markdown({
|
|
|
1786
2031
|
legacyParseOptions,
|
|
1787
2032
|
]);
|
|
1788
2033
|
|
|
2034
|
+
const inlineTransformSource = isStreaming
|
|
2035
|
+
? trimStreamingArtifacts(
|
|
2036
|
+
smoothedText,
|
|
2037
|
+
hasMathRenderer ? mathParseOptions : legacyParseOptions,
|
|
2038
|
+
)
|
|
2039
|
+
: children;
|
|
2040
|
+
const inlineNodes = useMemo(() => {
|
|
2041
|
+
if (display !== 'inline') {
|
|
2042
|
+
return [];
|
|
2043
|
+
}
|
|
2044
|
+
const transformed = applyMarkdownTransforms(
|
|
2045
|
+
{
|
|
2046
|
+
type: 'root',
|
|
2047
|
+
children: [{type: 'paragraph', children: parsedInlineNodes}],
|
|
2048
|
+
},
|
|
2049
|
+
preparedPlugins,
|
|
2050
|
+
inlineTransformSource,
|
|
2051
|
+
!isStreaming,
|
|
2052
|
+
'inline',
|
|
2053
|
+
);
|
|
2054
|
+
const paragraph = transformed.children[0];
|
|
2055
|
+
return paragraph?.type === 'paragraph'
|
|
2056
|
+
? [...paragraph.children]
|
|
2057
|
+
: parsedInlineNodes;
|
|
2058
|
+
}, [
|
|
2059
|
+
display,
|
|
2060
|
+
parsedInlineNodes,
|
|
2061
|
+
preparedPlugins,
|
|
2062
|
+
inlineTransformSource,
|
|
2063
|
+
isStreaming,
|
|
2064
|
+
]);
|
|
2065
|
+
|
|
1789
2066
|
// Track recent boundaries for stacked fade-in animation.
|
|
1790
2067
|
// The number of spans needed = ceil(animationDuration / tickInterval).
|
|
1791
2068
|
// useStreamingText ticks every ~tickMs, and the fade runs for
|
|
@@ -1800,8 +2077,8 @@ export function Markdown({
|
|
|
1800
2077
|
return Math.min(Math.ceil(duration / tickMs), 12);
|
|
1801
2078
|
}, [token]);
|
|
1802
2079
|
|
|
1803
|
-
const prevBlocksRef = useRef<
|
|
1804
|
-
const prevInlineNodesRef = useRef<
|
|
2080
|
+
const prevBlocksRef = useRef<ReadonlyArray<RenderBlockNode>>([]);
|
|
2081
|
+
const prevInlineNodesRef = useRef<ReadonlyArray<RenderInlineNode>>([]);
|
|
1805
2082
|
const boundariesRef = useRef<number[]>([]);
|
|
1806
2083
|
const smoothedLen = smoothedText.length;
|
|
1807
2084
|
const boundaries = useMemo(() => {
|
|
@@ -1850,6 +2127,7 @@ export function Markdown({
|
|
|
1850
2127
|
LinkComponent,
|
|
1851
2128
|
inlinePlugins,
|
|
1852
2129
|
components,
|
|
2130
|
+
preparedPlugins,
|
|
1853
2131
|
),
|
|
1854
2132
|
)}
|
|
1855
2133
|
</span>
|
|
@@ -1895,6 +2173,7 @@ export function Markdown({
|
|
|
1895
2173
|
LinkComponent,
|
|
1896
2174
|
inlinePlugins,
|
|
1897
2175
|
components,
|
|
2176
|
+
preparedPlugins,
|
|
1898
2177
|
t,
|
|
1899
2178
|
headingIdMap,
|
|
1900
2179
|
),
|