react-native-enriched-markdown 0.7.0 → 0.7.2

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.
Files changed (37) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +215 -0
  3. package/app.plugin.js +2 -1
  4. package/docs/ACCESSIBILITY.md +172 -0
  5. package/docs/API_REFERENCE.md +948 -0
  6. package/docs/COPY_OPTIONS.md +127 -0
  7. package/docs/ELEMENTS_STRUCTURE.md +112 -0
  8. package/docs/IMAGE_CACHING.md +25 -0
  9. package/docs/INPUT.md +233 -0
  10. package/docs/LATEX_MATH.md +136 -0
  11. package/docs/MACOS.md +19 -0
  12. package/docs/MARKDOWN_STREAMING.md +36 -0
  13. package/docs/MENTIONS.md +97 -0
  14. package/docs/RTL.md +82 -0
  15. package/docs/STYLES.md +519 -0
  16. package/docs/TEXT.md +110 -0
  17. package/docs/WEB.md +49 -0
  18. package/package.json +7 -4
  19. package/plugin/build/withAndroidMath.js +19 -0
  20. package/plugin/build/withIosMath.js +28 -0
  21. package/plugin/build/withReactNativeEnrichedMarkdown.js +11 -0
  22. package/plugin/tsconfig.build.json +16 -0
  23. package/lib/module/plugin/withAndroidMath.js +0 -20
  24. package/lib/module/plugin/withAndroidMath.js.map +0 -1
  25. package/lib/module/plugin/withIosMath.js +0 -23
  26. package/lib/module/plugin/withIosMath.js.map +0 -1
  27. package/lib/module/plugin/withReactNativeEnrichedMarkdown.js +0 -16
  28. package/lib/module/plugin/withReactNativeEnrichedMarkdown.js.map +0 -1
  29. package/lib/typescript/src/plugin/withAndroidMath.d.ts +0 -5
  30. package/lib/typescript/src/plugin/withAndroidMath.d.ts.map +0 -1
  31. package/lib/typescript/src/plugin/withIosMath.d.ts +0 -5
  32. package/lib/typescript/src/plugin/withIosMath.d.ts.map +0 -1
  33. package/lib/typescript/src/plugin/withReactNativeEnrichedMarkdown.d.ts +0 -6
  34. package/lib/typescript/src/plugin/withReactNativeEnrichedMarkdown.d.ts.map +0 -1
  35. /package/{src/plugin → plugin/src}/withAndroidMath.ts +0 -0
  36. /package/{src/plugin → plugin/src}/withIosMath.ts +0 -0
  37. /package/{src/plugin → plugin/src}/withReactNativeEnrichedMarkdown.ts +0 -0
package/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Software Mansion
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,215 @@
1
+ <img src="https://github.com/user-attachments/assets/83cb462c-17df-4809-8b8a-fa4abb258cb3" alt="react-native-enriched-markdown by Software Mansion" width="100%">
2
+ <a href="https://swm-delivery.com/www/delivery/ck-slug.php?zoneid=zone-gh-react-native-enriched-1&n=1"><img src="https://swm-delivery.com/www/images/zone-gh-react-native-enriched-1?n=1" /></a>
3
+ <a href="https://swm-delivery.com/www/delivery/ck-slug.php?zoneid=zone-gh-react-native-enriched-2&n=1"><img src="https://swm-delivery.com/www/images/zone-gh-react-native-enriched-2?n=1" /></a>
4
+ <a href="https://swm-delivery.com/www/delivery/ck-slug.php?zoneid=zone-gh-react-native-enriched-3&n=1"><img src="https://swm-delivery.com/www/images/zone-gh-react-native-enriched-3?n=1" /></a>
5
+
6
+ # react-native-enriched-markdown
7
+
8
+ `react-native-enriched-markdown` is a powerful React Native library that renders Markdown content as native text and provides a rich text input with Markdown output. It supports iOS, Android, macOS, and Web, and requires the New Architecture (Fabric) for native platforms.
9
+
10
+ ### EnrichedMarkdownText
11
+
12
+ - ⚡ Fully native text rendering (no WebView)
13
+ - 🌐 Web support via [react-native-web](https://necolas.github.io/react-native-web/) + [md4c](https://github.com/mity/md4c) compiled to WebAssembly
14
+ - 🎯 High-performance Markdown parsing with [md4c](https://github.com/mity/md4c)
15
+ - 📐 CommonMark standard compliant
16
+ - 📊 GitHub Flavored Markdown (GFM)
17
+ - 🧮 LaTeX math rendering (block `$$...$$` with `flavor="github"`, inline `$...$` in all flavors)
18
+ - 🔀 [Markdown Streaming](docs/MARKDOWN_STREAMING.md) support (via [react-native-streamdown](https://github.com/software-mansion-labs/react-native-streamdown))
19
+ - 🎨 Fully customizable styles for all elements
20
+ - ✨ Text selection and copy support
21
+ - 📌 Custom text selection context menu items
22
+ - 🔗 Interactive link handling with [per-URL-pattern styling](docs/MENTIONS.md#link-variants-styling) (`linkVariants`)
23
+ - 👤 Renders mentions as styled links (compatible with `EnrichedMarkdownTextInput` mention output)
24
+ - 🙈 Spoiler text with animated particle overlay and tap-to-reveal
25
+ - 🖼️ Native image interactions (iOS: Copy, Save to Camera Roll)
26
+ - 🌐 Native platform features (Translate, Look Up, Search Web, Share)
27
+ - 🗣️ Accessibility support (VoiceOver on iOS, TalkBack on Android, semantic HTML on web)
28
+ - 🔄 Full RTL (right-to-left) support including text, lists, blockquotes, tables, and task lists
29
+
30
+ ### EnrichedMarkdownTextInput
31
+
32
+ - ✏️ Rich text input with Markdown output
33
+ - 🕹️ Imperative API for toggling styles and managing links
34
+ - 📋 Native context menu with formatting submenu
35
+ - 🔍 Real-time style state detection
36
+ - 🔗 Auto-link detection with customizable regex
37
+ - 🔄 Smart copy/paste with Markdown preservation
38
+ - 🎨 Customizable bold, italic, and link colors
39
+ - 👤 [Mentions](docs/MENTIONS.md) with configurable indicators, suggestion lifecycle events, and per-pattern link styling
40
+
41
+ Since 2012 [Software Mansion](https://swmansion.com) is a software agency with experience in building web and mobile apps. We are Core React Native Contributors and experts in dealing with all kinds of React Native issues.
42
+ We can help you build your next dream product –
43
+ [Hire us](https://swmansion.com/contact/projects?utm_source=react-native-enriched-markdown&utm_medium=readme).
44
+
45
+ ## Table of Contents
46
+
47
+ - [Prerequisites](#prerequisites)
48
+ - [Installation](#installation)
49
+ - [EnrichedMarkdownText](#enrichedmarkdowntext-1)
50
+ - [Usage](docs/TEXT.md#usage)
51
+ - [Supported Markdown Elements](docs/TEXT.md#supported-markdown-elements)
52
+ - [Copy Options](docs/TEXT.md#copy-options)
53
+ - [Accessibility](docs/TEXT.md#accessibility)
54
+ - [RTL Support](docs/TEXT.md#rtl-support)
55
+ - [Customizing Styles](docs/TEXT.md#customizing-styles)
56
+ - [LaTeX Math](docs/LATEX_MATH.md)
57
+ - [Image Caching](docs/IMAGE_CACHING.md)
58
+ - [Markdown Streaming](docs/MARKDOWN_STREAMING.md)
59
+ - [EnrichedMarkdownTextInput](#enrichedmarkdowntextinput-1)
60
+ - [Usage](docs/INPUT.md#usage)
61
+ - [Inline Styles](docs/INPUT.md#inline-styles)
62
+ - [Links](docs/INPUT.md#links)
63
+ - [Auto-Link Detection](docs/INPUT.md#auto-link-detection)
64
+ - [Mentions](docs/MENTIONS.md)
65
+ - [Style Detection](docs/INPUT.md#style-detection)
66
+ - [Other Events](docs/INPUT.md#other-events)
67
+ - [Customizing Styles](docs/INPUT.md#customizing-enrichedmarkdowntextinput--styles)
68
+ - [API Reference](#api-reference)
69
+ - [Web Support](docs/WEB.md)
70
+ - [macOS Support](docs/MACOS.md)
71
+ - [Compatibility Table](#compatibility-table)
72
+ - [Contributing](#contributing)
73
+ - [Future Plans](#future-plans)
74
+ - [License](#license)
75
+
76
+ ## Prerequisites
77
+
78
+ **Native (iOS / Android / macOS)**
79
+
80
+ - Requires [the React Native New Architecture (Fabric)](https://reactnative.dev/architecture/landing-page)
81
+ - See [Compatibility Table](#compatibility-table) for supported React Native versions
82
+ - macOS support via [react-native-macos](https://github.com/microsoft/react-native-macos) `0.81+`
83
+
84
+ **Web**
85
+
86
+ - Requires [`react-native-web`](https://necolas.github.io/react-native-web/) and Metro (or another bundler with `.web.tsx` platform resolution)
87
+ - No New Architecture requirement — the web renderer runs entirely in JavaScript via WebAssembly
88
+ - Only `EnrichedMarkdownText` is supported on web (`EnrichedMarkdownTextInput` is native-only)
89
+ - LaTeX math requires the optional [`katex`](https://katex.org/) peer dependency
90
+
91
+ ## Installation
92
+
93
+ ### Web
94
+
95
+ No steps beyond having `react-native-web` configured. For LaTeX math, install the optional peer dependency:
96
+
97
+ ```sh
98
+ npm install katex
99
+ # or
100
+ yarn add katex
101
+ ```
102
+
103
+ See [Web Support](docs/WEB.md) for full setup details, supported features, and prop behaviour.
104
+
105
+ ### Bare React Native app (iOS / Android)
106
+
107
+ #### 1. Install the library
108
+
109
+ ```sh
110
+ yarn add react-native-enriched-markdown
111
+ ```
112
+
113
+ > [!TIP]
114
+ > To try the latest features before they land in a stable release, install the nightly build:
115
+ >
116
+ > ```sh
117
+ > yarn add react-native-enriched-markdown@nightly
118
+ > ```
119
+ >
120
+ > Nightly versions are published to npm automatically and may contain breaking changes.
121
+
122
+ #### 2. Install iOS / macOS dependencies
123
+
124
+ The library includes native code so you will need to re-build the native app.
125
+
126
+ ```sh
127
+ # iOS
128
+ cd ios && bundle install && bundle exec pod install
129
+
130
+ # macOS (react-native-macos)
131
+ cd macos && bundle install && bundle exec pod install
132
+ ```
133
+
134
+ ### Expo app
135
+
136
+ #### 1. Install the library
137
+
138
+ ```sh
139
+ npx expo install react-native-enriched-markdown
140
+ ```
141
+
142
+ #### 2. Run prebuild
143
+
144
+ The library includes native code so you will need to re-build the native app.
145
+
146
+ ```sh
147
+ npx expo prebuild
148
+ ```
149
+
150
+ > [!NOTE]
151
+ > The library won't work in Expo Go as it needs native changes.
152
+
153
+ > [!IMPORTANT]
154
+ > **iOS: Save to Camera Roll**
155
+ >
156
+ > If your Markdown content includes images and you want users to save them to their photo library, add the following to your `Info.plist`:
157
+ >
158
+ > ```xml
159
+ > <key>NSPhotoLibraryAddUsageDescription</key>
160
+ > <string>This app needs access to your photo library to save images.</string>
161
+ > ```
162
+
163
+ ## EnrichedMarkdownText
164
+
165
+ See [EnrichedMarkdownText](docs/TEXT.md) for detailed documentation on usage examples, GFM tables, task lists, link handling, supported elements, copy options, accessibility, RTL support, and customizing styles. Mentions created by `EnrichedMarkdownTextInput` render as styled links — use [`linkVariants`](docs/MENTIONS.md#link-variants-styling) to customize their appearance.
166
+
167
+ ## EnrichedMarkdownTextInput
168
+
169
+ See [EnrichedMarkdownTextInput](docs/INPUT.md) for detailed documentation on usage examples, inline styles, links, style detection, events, and customizing styles.
170
+
171
+ ## API Reference
172
+
173
+ See the [API Reference](docs/API_REFERENCE.md) for a detailed overview of all the props, methods, and events available.
174
+
175
+ ## Web Support
176
+
177
+ See [Web Support](docs/WEB.md) for details on supported features, web-specific prop behaviour, and known limitations.
178
+
179
+ ## macOS Support
180
+
181
+ `react-native-enriched-markdown` supports macOS via [react-native-macos](https://github.com/microsoft/react-native-macos). See [macOS Support](docs/MACOS.md) for details on macOS-specific features, known limitations, and the example app.
182
+
183
+ ## Future Plans
184
+
185
+ We're actively working on expanding the capabilities of `react-native-enriched-markdown`. Here's what's on the roadmap:
186
+
187
+ - `EnrichedMarkdownTextInput`: headings, lists, blockquotes, code blocks, inline images
188
+ - `EnrichedMarkdownTextInput` web support
189
+ - macOS: block math rendering, VoiceOver accessibility, tail fade-in animation
190
+ - Web: spoiler text, streaming animation, configurable link `target`, copy options (Copy as Markdown, multi-format clipboard)
191
+
192
+ ## Compatibility Table
193
+
194
+ | | 0.82 | 0.83 | 0.84 | 0.85 | 0.86 |
195
+ |---|:---:|:---:|:---:|:---:|:---:|
196
+ | **nightly** | ⛔ | ✅ | ✅ | ✅ | ✅ |
197
+ | **0.7.0** | ⛔ | ✅ | ✅ | ✅ | ✅ |
198
+ | **0.6.0** | ⛔ | ✅ | ✅ | ✅ | ⛔ |
199
+ | **0.5.0** | ⛔ | ✅ | ✅ | ✅ | ⛔ |
200
+ | **0.4.x** | ✅ | ✅ | ✅ | ⛔ | ⛔ |
201
+ | **0.3.0** | ✅ | ✅ | ✅ | ⛔ | ⛔ |
202
+
203
+ ## Contributing
204
+
205
+ See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.
206
+
207
+ ## License
208
+
209
+ `react-native-enriched-markdown` library is licensed under [The MIT License](./LICENSE).
210
+
211
+ ---
212
+
213
+ Built by [Software Mansion](https://swmansion.com/).
214
+
215
+ [<img width="128" height="69" alt="Software Mansion Logo" src="https://github.com/user-attachments/assets/f0e18471-a7aa-4e80-86ac-87686a86fe56" />](https://swmansion.com/)
package/app.plugin.js CHANGED
@@ -1 +1,2 @@
1
- module.exports = require('./lib/module/plugin/withReactNativeEnrichedMarkdown');
1
+ module.exports =
2
+ require('./plugin/build/withReactNativeEnrichedMarkdown').default;
@@ -0,0 +1,172 @@
1
+ # Accessibility
2
+
3
+ `react-native-enriched-markdown` provides comprehensive accessibility support for screen readers on both iOS and Android platforms.
4
+
5
+ ## Overview
6
+
7
+ The library implements native accessibility features that enable screen readers (VoiceOver on iOS and TalkBack on Android) to properly navigate and understand Markdown content. This includes semantic labeling, custom navigation controls, and proper announcements for all supported elements.
8
+
9
+ ## Text Announcements
10
+
11
+ Plain text paragraphs without inline links or images are announced as a single VoiceOver element per paragraph. Paragraphs containing links or images are segmented into text, link, and image parts so that each remains independently navigable. List items follow the same logic — a list item without inline specials is a single element, while one containing a link is split accordingly. Whitespace-only segments between elements are filtered out to avoid empty announcements.
12
+
13
+ ## Translating announcements — `accessibilityLabels`
14
+
15
+ All strings spoken by the screen reader (list announcements, blockquote suffix, table rows, math equation prefix, and iOS rotor names) can be overridden via the optional `accessibilityLabels` prop on `EnrichedMarkdownText`. The defaults are English; consumers wire in their own i18n pipeline.
16
+
17
+ ```tsx
18
+ import { EnrichedMarkdownText } from 'react-native-enriched-markdown';
19
+
20
+ <EnrichedMarkdownText
21
+ markdown={markdown}
22
+ accessibilityLabels={{
23
+ list: {
24
+ bulletPoint: 'Punkt',
25
+ nestedBulletPoint: 'Eingebetteter Punkt',
26
+ orderedItem: 'Listenelement {n}',
27
+ nestedOrderedItem: 'Eingebettetes Listenelement {n}',
28
+ },
29
+ blockquote: {
30
+ quote: 'Zitat',
31
+ nestedQuote: 'Eingebettetes Zitat',
32
+ },
33
+ table: { row: 'Zeile {n}: {content}' },
34
+ math: { equation: 'Formel: {latex}' },
35
+ rotor: {
36
+ headings: 'Überschriften',
37
+ links: 'Links',
38
+ images: 'Bilder',
39
+ },
40
+ }}
41
+ />
42
+ ```
43
+
44
+ Every field is optional. Any field you omit falls back to the English default below. Defaults are resolved on the JS side before being forwarded to native, so once you set even a single override the rest stay on their built-ins automatically.
45
+
46
+ ### Defaults
47
+
48
+ | Field | Default | Platform |
49
+ |---|---|---|
50
+ | `list.bulletPoint` | `"Bullet point"` | iOS + Android |
51
+ | `list.nestedBulletPoint` | `"Nested bullet point"` | iOS + Android |
52
+ | `list.orderedItem` | `"List item {n}"` | iOS + Android |
53
+ | `list.nestedOrderedItem` | `"Nested list item {n}"` | iOS + Android |
54
+ | `blockquote.quote` | `"Blockquote"` | iOS + Android |
55
+ | `blockquote.nestedQuote` | `"Nested blockquote"` | iOS + Android |
56
+ | `table.row` | `"Row {n}: {content}"` | iOS + Android |
57
+ | `math.equation` | `"Math: {latex}"` | iOS + Android |
58
+ | `rotor.headings` | `"Headings"` | iOS only |
59
+ | `rotor.links` | `"Links"` | iOS only |
60
+ | `rotor.images` | `"Images"` | iOS only |
61
+
62
+ ### Placeholder syntax
63
+
64
+ - `{n}` — 1-based index (list item number, table row index). Substituted at speak time.
65
+ - `{content}` — comma-joined cell texts for a table row.
66
+ - `{latex}` — math equation source.
67
+
68
+ Placeholder names must be preserved in translations exactly. Defaults intentionally use the no-plural cardinal form (`"List item 2"`, `"Row 2"`) instead of ordinals or count-aware variants — a single template works in every language without per-locale plural rules.
69
+
70
+ ## Supported Elements
71
+
72
+ | Element | VoiceOver (iOS) | TalkBack (Android) |
73
+ |---------|-----------------|---------------------|
74
+ | **Headings (h1-h6)** | Rotor navigation, `UIAccessibilityTraitHeader` → "heading" suffix | Reading controls navigation, `isHeading = true` → "heading" suffix |
75
+ | **Links** | Rotor navigation, activatable, "link" suffix | Reading controls navigation, activatable, "link" suffix |
76
+ | **Images** | Alt text announced, rotor navigation, "image" suffix | Alt text announced, "image" role |
77
+ | **Unordered list items** | "Bullet point" / "Nested bullet point" appended (`accessibilityValue`) | Same string appended via `roleDescription` |
78
+ | **Ordered list items** | "List item N" / "Nested list item N" appended | Same string appended via `roleDescription` |
79
+ | **Blockquote content** | "Blockquote" / "Nested blockquote" appended | Same string appended via `roleDescription` |
80
+ | **Table rows** | One focusable element per row, `"Row N: <cells>"` label, header row carries `UIAccessibilityTraitHeader` | One focusable overlay per row, same template, header row carries `setAccessibilityHeading(true)` |
81
+ | **Math equations** | `"Math: <latex>"` (latex read verbatim — no TTS engine) | Same |
82
+
83
+ ## Architecture
84
+
85
+ ### iOS (VoiceOver)
86
+
87
+ **Custom Rotors:**
88
+ - **Headings Rotor**: Navigate between all headings in the document
89
+ - **Links Rotor**: Jump between all links
90
+ - **Images Rotor**: Navigate through all images
91
+
92
+ Rotor names are translated via `accessibilityLabels.rotor.*`. When VoiceOver is active, a two-finger twist on the screen cycles through these rotors; swipe up/down jumps between elements of the currently-selected type.
93
+
94
+ **Semantic Traits:**
95
+ - Headings: `UIAccessibilityTraitHeader | UIAccessibilityTraitStaticText`
96
+ - Links: `UIAccessibilityTraitLink | UIAccessibilityTraitStaticText`
97
+ - Images: `UIAccessibilityTraitImage` (+ `UIAccessibilityTraitLink` if the image is linked)
98
+ - Plain text: `UIAccessibilityTraitStaticText`
99
+
100
+ List, blockquote and table row labels are exposed via `accessibilityValue` so VoiceOver speaks them after the main text.
101
+
102
+ ### Android (TalkBack)
103
+
104
+ **Reading Controls:**
105
+ - Headings, links, and images are available in TalkBack's reading controls for quick navigation
106
+ - List items are properly announced with their position and type (ordered vs unordered)
107
+
108
+ **Accessibility Node Info:**
109
+ - Headings: `isHeading = true` — TalkBack speaks "heading" as the role
110
+ - Links: `isClickable = true` + `roleDescription = "link"`
111
+ - Images: alt text becomes `contentDescription`, `roleDescription = "image"`
112
+ - List items: `CollectionItemInfoCompat` is set so TalkBack also announces position-in-collection; the localized label is appended via `roleDescription`
113
+ - Blockquote content: localized label appended via `roleDescription` (combined with link/list role when nested)
114
+ - Table rows: one transparent overlay per row exposes the row's joined content via `contentDescription`; header rows additionally call `ViewCompat.setAccessibilityHeading(true)`
115
+ - Math: `MathContainerView` exposes the full equation via `contentDescription` (`"Math: <latex>"` template)
116
+
117
+ ## Element Details
118
+
119
+ ### Headings
120
+
121
+ Headings are marked with the platform's "heading" trait/role. Screen readers announce the heading text followed by "heading" — the heading **level** is not spoken by default (the trait already conveys "this is a heading"; spelling the level out adds friction). The level remains available programmatically so platform navigation controls (rotor on iOS, reading controls on Android) can jump between headings of any level.
122
+
123
+ **Example announcement:**
124
+ - "Welcome to Markdown, heading"
125
+ - "Getting Started, heading"
126
+
127
+ ### Links
128
+
129
+ Links are fully interactive and can be activated through screen reader gestures. The link text is announced followed by "link".
130
+
131
+ **Example announcement:**
132
+ - "React Native, link"
133
+
134
+ ### Images
135
+
136
+ Images with alt text announce the alt text + "image". Images without alt text are intentionally **silent** (no fallback string) — if you want them announced, supply alt text in the markdown source.
137
+
138
+ **Example announcement:**
139
+ - "Misty forest at sunrise, image"
140
+ - *(silent for `![](url)`)*
141
+
142
+ ### Lists
143
+
144
+ List items are announced with their position and type:
145
+
146
+ - Unordered: `"<text>, Bullet point"` (top-level) or `"<text>, Nested bullet point"` (deeper)
147
+ - Ordered: `"<text>, List item 1"`, `"<text>, List item 2"`, etc.
148
+
149
+ Override via `accessibilityLabels.list.*`. The `{n}` placeholder is substituted with the 1-based item number.
150
+
151
+ ### Blockquotes
152
+
153
+ Content inside a blockquote gets the blockquote label appended (after any list or link suffix). Nested blockquotes use the `nestedQuote` label instead.
154
+
155
+ **Example announcement:**
156
+ - `"This is a quoted line., Blockquote"`
157
+ - `"Nested quote text., Nested blockquote"`
158
+
159
+ ### Tables
160
+
161
+ Tables expose one focusable element per row (header included), labeled with the `table.row` template. The default reads `"Row 1: Column A, Column B"` for the header, `"Row 2: Cell A1, Cell B1"` for the first body row, and so on. The header row additionally carries the heading trait/role.
162
+
163
+ ### Math
164
+
165
+ Each math block exposes a single focusable element labeled `"Math: <latex>"`. The library does **not** convert LaTeX to natural language — the screen reader reads the raw LaTeX source. If you need spoken math, plug in a LaTeX→speech library on the consumer side and translate the labels accordingly.
166
+
167
+ ## Known Limitations
168
+
169
+ - **Inline formatting** (bold / italic / underline / strikethrough / inline code / spoiler) is not split into separate accessibility elements — the entire paragraph is read as one element, exactly as the surrounding text. Screen readers don't apply visual emphasis to bold/italic by default.
170
+ - **macOS** screen-reader support is still pending — `MarkdownAccessibilityElementBuilder.m` ships a no-op stub for macOS. Tracked as a TODO; iOS implementation can serve as a reference.
171
+ - **Android** has no rotor concept — `accessibilityLabels.rotor.*` is silently ignored on that platform.
172
+ - **iOS** blockquote backgrounds may break at link boundaries instead of spanning the full line. Visual only; doesn't affect accessibility.