@peaceroad/markdown-it-figure-with-p-caption 0.13.0 → 0.14.1

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/README.md CHANGED
@@ -1,90 +1,204 @@
1
1
  # p7d-markdown-it-figure-with-p-caption
2
2
 
3
- This is a markdown-it plugin.
3
+ This markdown-it plugin converts paragraphs representing captions before or after image/table/code/video/audio/iframe into `figcaption` element, and wraps them in `figure` element. Caption parsing (labels, filenames, spacing rules) is delegated to [`p7d-markdown-it-p-captions`](https://www.npmjs.com/package/p7d-markdown-it-p-captions), so this plugin focuses on detecting the surrounding structure. Optionally, you have the option to wrap it in a `figure` element, even if there is no caption paragraph.
4
4
 
5
- For paragraphs containing only images, tables, code blocks, blockquotes, or iframes, this plugin converts them into figure elements with figcaption elements when a caption paragraph is written immediately before or after.
5
+ For images, even if they don't have a caption paragraph, they can be treated as captions if they have a caption string in the image's `alt`/`title` text (there is also an option to promote them to captions even if they don't have that string).
6
6
 
7
- The conversion process:
8
- 1. Detect supported elements: image paragraphs, tables, code/samp blocks, blockquotes, videos, and iframes
9
- 2. Check for caption paragraphs immediately before or after the element
10
- 3. Convert both elements into a figure with figcaption structure
7
+ Optionally, you can auto-number image and table caption paragraphs starting from the beginning of the document if they only have label names.
11
8
 
12
- The figcaption behavior of this plugin depends on [p7d-markdown-it-p-captions](https://www.npmjs.com/package/p7d-markdown-it-p-captions).
9
+ **Note.** If you want to adjust the image `width`/`height`, please also use [`@peaceroad/markdown-it-renderer-image`](https://www.npmjs.com/package/@peaceroad/markdown-it-renderer-image). Also, if you want to use the `samp` element when displaying terminal output, please also use [`@peaceroad/markdown-it-renderer-fence`](https://www.npmjs.com/package/@peaceroad/markdown-it-renderer-fence). This document shows output using the latter option.
13
10
 
14
- **Notice.** Starting with version 0.7, the process changing from code to samp tag has been migrated to [@peaceroad/markdown-it-renderer-fence](https://www.npmjs.com/package/@peaceroad/markdown-it-renderer-fence). If you want to continue processing as before, please use this plugin at the same time.
15
- (The tests for this plugin and this Readme output used the plugins together.)
11
+ ## Behavior
16
12
 
17
- **Notice.** You can also use `markdown-it-attrs` at the same time. However, if there is `{.style}` at the end of a paragraph with only an image, and the next paragraph is a caption, `markdown-it-attrs` alone does not handle it well, so this plugin takes care of that. (This processing is optional `{styleProcess: true}` and can be turned off.) [0.5.0]
13
+ ### Image
18
14
 
19
- Use it as follows.
15
+ - Pure image paragraphs (`![...](...)`) become `<figure class="f-img">` blocks as soon as a caption paragraph (previous or next) or an auto-detected caption exists.
16
+ - Auto detection runs per image paragraph when `autoCaptionDetection` is `true` (default). The priority is:
17
+ 1. Caption paragraphs immediately before or after the image (standard syntax).
18
+ 2. Image `alt` text that already matches p7d-markdown-it-p-captions label formats (`Figure. `, `Figure 1. `, `図 `,`図1 `, etc.).
19
+ 3. Image `title` attribute that matches the same labels.
20
+ 4. Optional fallbacks (`autoAltCaption`, `autoTitleCaption`) that inject the label when the alt/title lacks one.
21
+ - `autoAltCaption`: `false` (default), `true`, or a string label. `true` inspects the first sentence of the caption text and picks `Figure` / `図` based on detected language; a string uses that label verbatim.
22
+ - `autoTitleCaption`: same behavior but sourced from the image `title`. It stays off by default so other plugins can keep using the `title` attribute for metadata.
23
+ - Set `autoCaptionDetection: false` to disable the auto-caption workflow entirely.
24
+ - Multi-image paragraphs are still wrapped as one figure when `multipleImages: true` (default). Layout-specific classes help with styling:
25
+ - `f-img-horizontal` when images sit on the same line (space-delimited).
26
+ - `f-img-vertical` when separated only by soft breaks.
27
+ - `f-img-multiple` for mixed layouts.
28
+ - Automatic detection inspects only the first image in the paragraph. If it yields a caption, the entire figure reuses that caption while later images keep their own `alt`/`title`.
29
+ - Paragraphs that contain only images also convert when they appear inside loose lists (leave blank lines between items), blockquotes, or description lists.
30
+
31
+ ### Table
32
+
33
+ - Markdown tables (including those produced by `markdown-it-multimd-table` or similar) convert into `<figure class="f-table">` blocks.
34
+ - Caption paragraphs immediately before/after the table become `<figcaption>` element ahead of the `<table>`.
35
+
36
+ ### Code block
37
+
38
+ - Captions labeled `Code. `, `Terminal. `, etc. wrap the fence in `<figure class="f-pre-code">` / `<figure class="f-pre-samp">`.
39
+ - If `roleDocExample: true`, these figures add `role="doc-example"`.
40
+
41
+ ### Blockquote
42
+
43
+ - Captioned blockquotes (e.g., “Source. A paragraph. Ewritten immediately before or after `> ...`) become `<figure class="f-blockquote">` while keeping the original blockquote intact.
44
+
45
+ ### Video & Audio
46
+
47
+ - Inline HTML `<video>` and `<audio>` tags are detected as media figures (`<figure class="f-video">` and `<figure class="f-audio">`).
48
+ - A caption paragraph labeled `Video. ` / `Audio. ` (or any registered label) is promoted to `<figcaption>` before/after the media so controls remain unobstructed.
49
+
50
+ ### Embedded content by iframe
51
+
52
+ - Inline HTML `<iframe>` elements become `<figure class="f-video">` when they point to known video hosts (YouTube `youtube.com` / `youtube-nocookie.com`, Vimeo `player.vimeo.com`).
53
+ - Blockquote-based social embeds (Twitter/X `twitter-tweet`, Mastodon `mastodon-embed`, Bluesky `bluesky-embed`, Instagram `instagram-media`, Tumblr `text-post-media`) are treated like iframe-type embeds when their `class` matches those providers. By default they become `<figure class="f-img">` so the caption label behaves like an image label (Labels can also use quote labels). You can override that figure class with `figureClassThatWrapsIframeTypeBlockquote` or the global `allIframeTypeFigureClassName`.
54
+ - `p7d-markdown-it-p-captions` ships with a `Slide.` label. When you use it (for example with Speaker Deck or SlideShare iframes), the `<figure>` wrapper automatically switches to `f-slide` (or whatever you set via `figureClassThatWrapsSlides`) so slides can get their own layout. If `allIframeTypeFigureClassName` is also configured, that class takes precedence even for slides, so you get a uniform embed wrapper without touching the slide option.
55
+ - All other iframes fall back to `<figure class="f-iframe">` unless you override the class via `allIframeTypeFigureClassName`.
56
+
57
+ ### label span class name
58
+
59
+ - The label inside the figcaption (the `span` element used for the label) is generated by `p7d-markdown-it-p-captions`, not by this plugin. By default the class name is formed by combining `classPrefix` with the mark name, producing names such as `f-img-label`, `f-video-label`, `f-blockquote-label`, and `f-slide-label`.
60
+ - With `markdown-it-attrs`, any attribute block (`{ .foo #bar }`) attached to the caption paragraph is moved to the generated `<figure>` by default (`styleProcess: true`). This keeps per-figure classes/IDs on the wrapper instead of the original paragraph; disable the option only if you explicitly want the attributes to stay on the paragraph.
61
+
62
+ ## Behavior Customization
63
+
64
+ ### Styles
65
+
66
+ - Set `allIframeTypeFigureClassName: 'f-embed'` (recommended) to force a single CSS class across `<iframe>` and social-embed figures so they can share styles, ensuring every embed wrapper shares the same predictable class name.
67
+ - `figureClassThatWrapsIframeTypeBlockquote`: override the class used when blockquote-based embeds (Twitter, Mastodon, Bluesky) are wrapped.
68
+ - `figureClassThatWrapsSlides`: override the class assigned when a caption paragraph uses the `Slide.` label.
69
+ - `classPrefix` (default `f`) controls the CSS namespace for every figure (`f-img`, `f-table`, etc.) so you can align with existing styles.
70
+
71
+ ### Wrapping without captions
72
+
73
+ - `oneImageWithoutCaption`: turn single-image paragraphs into `<figure>` elements even when no caption paragraph/auto caption is present. This is independent of automatic detection.
74
+ - `videoWithoutCaption`, `audioWithoutCaption`, `iframeWithoutCaption`, `iframeTypeBlockquoteWithoutCaption`: wrap the respective media blocks without caption.
75
+
76
+ ### Caption text helpers (delegated to `p7d-markdown-it-p-captions`)
77
+
78
+ Every option below is forwarded verbatim to `p7d-markdown-it-p-captions`, which owns the actual figcaption rendering:
79
+
80
+ - `strongFilename` / `dquoteFilename`: pull out filenames from captions using `**filename**` or `"filename"` syntax and wrap them in `<strong class="f-*-filename">`.
81
+ - `jointSpaceUseHalfWidth`: replace full-width space between Japanese labels and caption body with half-width space.
82
+ - `bLabel` / `strongLabel`: emphasize the label span itself.
83
+ - `removeUnnumberedLabel`: drop the leading “Figure. Etext entirely when no label number is present. Use `removeUnnumberedLabelExceptMarks` to keep specific labels (e.g., `['blockquote']` keeps `Quote. `).
84
+ - `removeMarkNameInCaptionClass`: replace `.f-img-label` / `.f-table-label` with the generic `.f-label`.
85
+ - `wrapCaptionBody`: wrap the non-label caption text in a span element.
86
+ - `hasNumClass`: add a class attribute to label span element if it has a label number.
87
+ - `labelClassFollowsFigure`: mirror the resolved `<figure>` class onto the `figcaption` spans (`f-embed-label`, `f-embed-label-joint`, `f-embed-body`, etc.) when you want captions styled alongside the wrapper.
88
+ - `figureToLabelClassMap`: extend `labelClassFollowsFigure` by mapping specific figure classes (e.g., `f-embed`) to custom caption label classes such as `caption-embed caption-social` for fine-grained control.
89
+
90
+ ### Automatic numbering
91
+
92
+ - `setLabelNumbers`: enable numbering per media type. Pass an array such as `['img']`, `['table']`, or `['img', 'table']`.
93
+ - `autoLabelNumber`: shorthand for turning numbering on for both images and tables without passing the array yourself. Provide `setLabelNumbers` explicitly (e.g., `['img']`) when you need finer control—the explicit array always wins.
94
+ - Counters start at `1` near the top of the document and increment sequentially per media type. Figures and tables keep independent counters even when mixed together.
95
+ - The counter only advances when a real caption exists (paragraph, auto-detected alt/title, or fallback text). Figures emitted solely because of `oneImageWithoutCaption` stay unnumbered.
96
+ - Manual numbers inside the caption text (e.g., `Figure 5.`) always win. The plugin updates its internal counter so the next automatic number becomes `6`. This applies to captions sourced from paragraphs, auto detection, and fallback captions.
97
+
98
+ ## Basic Usage
20
99
 
21
100
  ```js
22
101
  import mdit from 'markdown-it'
23
102
  import mditFigureWithPCaption from '@peaceroad/markdown-it-figure-with-p-caption'
24
- import mditRendererFence from '@peaceroad/markdown-it-renderer-fence' /* to processing code -> smap tag etc. process.*/
103
+ import mditRendererFence from '@peaceroad/markdown-it-renderer-fence' // optional but keeps fences aligned with samples
25
104
 
26
- const md = mdit()
27
- md.use(mditFigureWithPCaption)
105
+ const md = mdit({ html: true, langPrefix: 'language-', })
106
+ .use(mditFigureWithPCaption)
107
+ .use(mditRendererFence)
28
108
 
29
- console.log(md.render('Figure. A Cat.\n\n![Figure](cat.jpg)'))
109
+ console.log(md.render('Figure. A Cat.\n\n![A cat](cat.jpg)'))
30
110
  // <figure class="f-img">
31
111
  // <figcaption><span class="f-img-label">Figure<span class="f-img-label-joint">.</span></span> A Cat.</figcaption>
32
- // <img src="cat.jpg" alt="Figure">
112
+ // <img src="cat.jpg" alt="A cat">
33
113
  // </figure>
34
114
  ```
35
115
 
36
- Also, It is recommended to set the width and height attributes of the images at the same time. See: [@peaceroad/markdown-it-renderer-image](https://www.npmjs.com/package/@peaceroad/markdown-it-renderer-image).
116
+ ### Basic Recommended Options
37
117
 
38
- It could be applied to table, codeblock(pre > code, pre > samp), video as well.
118
+ Auto label numbering for images and tables.
39
119
 
40
- These elements are also supported within the following structure. [0.13.0+]
120
+ ```js
121
+ const figureOption = {
122
+ // Opinionated defaults
123
+ oneImageWithoutCaption: true,
124
+ videoWithoutCaption: true,
125
+ audioWithoutCaption: true,
126
+ iframeWithoutCaption: true,
127
+ iframeTypeBlockquoteWithoutCaption: true,
128
+ removeUnnumberedLabelExceptMarks: ['blockquote'], // keep “Quote. Elabels even when unnumbered
129
+ allIframeTypeFigureClassName: 'f-embed', // apply a uniform class to every iframe-style embed
130
+ autoLabelNumber: true,
131
+
132
+ // If you want to enable auto alt/title captioning fallbacks without caption label.
133
+ //autoAltCaption: true,
134
+ //autoTitleCaption: true,
135
+ }
136
+ ```
41
137
 
42
- - Blockquote
43
- - loose list (with blank lines between items), not tight list (no blank lines)
44
- - Description list block (`<dl>` markup, markdown-it-deflist)
138
+ If there is no label number, the label will also be deleted.
45
139
 
46
- ## Example
140
+ ```js
141
+ const figureOption = {
142
+ oneImageWithoutCaption: true,
143
+ videoWithoutCaption: true,
144
+ audioWithoutCaption: true,
145
+ iframeWithoutCaption: true,
146
+ iframeTypeBlockquoteWithoutCaption: true,
147
+ removeUnnumberedLabelExceptMarks: ['blockquote'],
148
+ allIframeTypeFigureClassName: 'f-embed',
149
+ removeUnnumberedLabel: true,
150
+ }
151
+ ```
152
+
153
+ These options can be used as follows:
154
+
155
+ ```
156
+ const md = mdit({ html: true }).use(mditFigureWithPCaption, figureOption)
157
+ ```
158
+
159
+ ## Conversion Examples
160
+
161
+ ### Default before/after caption paragraph detection
47
162
 
48
163
  ~~~
49
164
  [Markdown]
50
- ![Figure](figure.jpg)
165
+ ![A single cat](figure.jpg)
51
166
 
52
167
  [HTML]
53
- <p><img src="figure.jpg" alt="Figure"></p>
168
+ <p><img src="figure.jpg" alt="A single cat"></p>
169
+
170
+ <!-- Above: If oneImageWithoutCaption is true, this img element has wrapped into figure element without caption. -->
54
171
 
55
172
 
56
173
  [Markdown]
57
174
  Figure. A Caption.
58
175
 
59
- ![Figure](figure.jpg)
176
+ ![A single cat](figure.jpg)
60
177
  [HTML]
61
178
  <figure class="f-img">
62
179
  <figcaption><span class="f-img-label">Figure<span class="f-img-label-joint">.</span></span> A Caption.</figcaption>
63
- <img src="figure.jpg" alt="Figure">
180
+ <img src="figure.jpg" alt="A single cat">
64
181
  </figure>
65
182
 
66
183
 
67
184
  [Markdown]
68
- ![Figure](figure.jpg)
185
+ ![A single cat](figure.jpg)
69
186
 
70
187
  Figure. A Caption.
71
188
  [HTML]
72
189
  <figure class="f-img">
73
- <img src="figure.jpg" alt="Figure">
190
+ <img src="figure.jpg" alt="A single cat">
74
191
  <figcaption><span class="f-img-label">Figure<span class="f-img-label-joint">.</span></span> A Caption.</figcaption>
75
192
  </figure>
76
193
 
77
194
 
78
195
  [Markdown]
79
- A paragraph.
80
-
81
196
  Table. A Caption.
82
197
 
83
198
  | Tokyo | Osaka |
84
199
  | ----- | ----- |
85
200
  | Sushi | Takoyaki |
86
201
 
87
- A paragraph.
88
202
  [HTML]
89
203
  <p>A paragraph.</p>
90
204
  <figure class="f-table">
@@ -104,53 +218,40 @@ A paragraph.
104
218
  </tbody>
105
219
  </table>
106
220
  </figure>
107
- <p>A paragraph.</p>
108
221
 
109
222
 
110
223
  [Markdown]
111
- A paragraph.
112
-
113
224
  Code. A Caption.
114
225
 
115
226
  ```js
116
227
  console.log('Hello World!');
117
228
  ```
118
229
 
119
- A paragraph.
120
-
121
230
  [HTML]
122
- <p>A paragraph.</p>
123
231
  <figure class="f-pre-code">
124
232
  <figcaption><span class="f-pre-code-label">Code<span class="f-pre-code-label-joint">.</span></span> A Caption.</figcaption>
125
233
  <pre><code class="language-js">console.log('Hello World!');
126
234
  </code></pre>
127
235
  </figure>
128
- <p>A paragraph.</p>
129
236
 
237
+ <!-- Above: class attribute of code element is generated by markdown-it option. -->
130
238
 
131
- [Markdown]
132
- A paragraph.
133
239
 
240
+ [Markdown]
134
241
  Source. A Caption.
135
242
 
136
243
  > A quoted paragraph.
137
244
 
138
- A paragraph.
139
-
140
245
  [HTML]
141
- <p>A paragraph.</p>
142
246
  <figure class="f-blockquote">
143
247
  <figcaption><span class="f-blockquote-label">Source<span class="f-blockquote-label-joint">.</span></span> A Caption.</figcaption>
144
248
  <blockquote>
145
249
  <p>A quoted paragraph.</p>
146
250
  </blockquote>
147
251
  </figure>
148
- <p>A paragraph.</p>
149
252
 
150
253
 
151
254
  [Markdown]
152
- A paragraph.
153
-
154
255
  Terminal. A Caption.
155
256
 
156
257
  ```samp
@@ -158,108 +259,126 @@ $ pwd
158
259
  /home/user
159
260
  ```
160
261
 
161
- A paragraph.
162
-
163
262
  [HTML]
164
- <p>A paragraph.</p>
165
263
  <figure class="f-pre-samp">
166
264
  <figcaption><span class="f-pre-samp-label">Terminal<span class="f-pre-samp-label-joint">.</span></span> A Caption.</figcaption>
167
265
  <pre><samp>$ pwd
168
266
  /home/user
169
267
  </samp></pre>
170
268
  </figure>
171
- <p>A paragraph.</p>
172
269
 
270
+ <!-- Above: When @peaceroad/markdown-it-renderer-fence is used, samp element are generated automatically for `samp` fences. -->
173
271
 
174
272
  [Markdown]
175
- A paragraph.
176
-
177
273
  Video. A mp4.
178
274
 
179
275
  <video controls width="400" height="300">
180
276
  <source src="example.mp4" type="video/mp4">
181
277
  </video>
182
278
 
183
- A paragraph.
184
279
  [HTML]
185
- <p>A paragraph.</p>
186
280
  <figure class="f-video">
187
281
  <figcaption><span class="f-video-label">Video<span class="f-video-label-joint">.</span></span> A mp4.</figcaption>
188
282
  <video controls width="400" height="300">
189
283
  <source src="example.mp4" type="video/mp4">
190
284
  </video>
191
285
  </figure>
192
- <p>A paragraph.</p>
193
286
 
194
287
 
195
288
  [Markdown]
196
- A paragraph.
197
-
198
- Video. A youtube.
289
+ Audio. A narration.
199
290
 
200
- <iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/XXXXXXXXXXX" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
291
+ <audio controls>
292
+ <source src="example.mp3" type="audio/mpeg">
293
+ </audio>
201
294
 
202
- A paragraph.
203
295
  [HTML]
204
- <p>A paragraph.</p>
205
- <figure class="f-video">
206
- <figcaption><span class="f-video-label">Video<span class="f-video-label-joint">.</span></span> A youtube.</figcaption>
207
- <iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/XXXXXXXXXXX" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
296
+ <figure class="f-audio">
297
+ <figcaption><span class="f-audio-label">Audio<span class="f-audio-label-joint">.</span></span> A narration.</figcaption>
298
+ <audio controls>
299
+ <source src="example.mp3" type="audio/mpeg">
300
+ </audio>
208
301
  </figure>
209
- <p>A paragraph.</p>
210
302
 
211
303
 
212
304
  [Markdown]
213
- A paragraph.
214
-
215
- Video. A youtube.
305
+ Video. A YouTube video.
216
306
 
217
- <iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/XXXXXXXXXXX" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
307
+ <iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/XXXXXXXXXXX" ...></iframe>
218
308
 
219
- A paragraph.
220
309
  [HTML]
221
- <p>A paragraph.</p>
222
310
  <figure class="f-video">
223
- <figcaption><span class="f-video-label">Video<span class="f-video-label-joint">.</span></span> A youtube.</figcaption>
224
- <iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/XXXXXXXXXXX" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
311
+ <figcaption><span class="f-video-label">Video<span class="f-video-label-joint">.</span></span> A YouTube video.</figcaption>
312
+ <iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/XXXXXXXXXXX" ...></iframe>
225
313
  </figure>
226
- <p>A paragraph.</p>
227
314
 
228
315
 
229
316
  [Markdown]
230
- A paragraph.
317
+ Figure. Mastodon post.
318
+
319
+ <blockquote class="mastodon-embed" ...> ...... </blockquote><script async src="https://example.com/embed.js"></script>
320
+
321
+ [HTML]
322
+ <figure class="f-img">
323
+ <figcaption><span class="f-img-label">Figure<span class="f-img-label-joint">.</span></span> Mastodon post.</figcaption>
324
+ <blockquote class="mastodon-embed" ...> ...... </blockquote><script async src="https://example.com/embed.js"></script>
325
+ </figure>
231
326
 
232
- Figure. Twitter Post.
233
327
 
234
- <blockquote class="twitter-tweet"><p lang="ja" dir="ltr">XXXXX <a href="https://t.co/XXXXX">https://t.co/XXXXX</a></p>&mdash; UserName (@account) <a href="https://twitter.com/account/status/XXXXX">August 4, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
328
+ [Markdown]
329
+ Quote. Mastodon post.
330
+
331
+ <blockquote class="mastodon-embed" ...> ...... </blockquote><script async src="https://example.com/embed.js"></script>
235
332
 
236
- A paragraph.
237
333
  [HTML]
238
- <p>A paragraph.</p>
239
334
  <figure class="f-img">
240
- <figcaption><span class="f-img-label">Figure<span class="f-img-label-joint">.</span></span> Twitter Post.</figcaption>
241
- <blockquote class="twitter-tweet"><p lang="ja" dir="ltr">XXXXX <a href="https://t.co/XXXXX">https://t.co/XXXXX</a></p>&mdash; User (@twitter) <a href="https://twitter.com/UserID/status/XXXXX">August 4, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
335
+ <figcaption><span class="f-blockquote-label">Quote<span class="f-blockquote-label-joint">.</span></span> X post.</figcaption>
336
+ <blockquote class="mastodon-embed" ...> ...... </blockquote><script async src="https://example.com/embed.js"></script>
242
337
  </figure>
243
- <p>A paragraph.</p>
244
338
 
339
+
340
+ [Markdown]
341
+ Slide. A Speaker Deck.
342
+
343
+ <iframe src="https://speakerdeck.com/player/XXXXXXXXXXX" width="640" height="360" frameborder="0" allowfullscreen></iframe>
344
+
345
+ [HTML]
346
+ <figure class="f-slide">
347
+ <figcaption><span class="f-slide-label">Slide<span class="f-slide-label-joint">.</span></span> A Speaker Deck.</figcaption>
348
+ <iframe src="https://speakerdeck.com/player/XXXXXXXXXXX" width="640" height="360" frameborder="0" allowfullscreen></iframe>
349
+ </figure>
245
350
  ~~~
246
351
 
247
- Note: External embedding supports Youtube and Twitter. Twitter embedding uses blockquote instead of iframe. Therefore, the caption identifier should use "Quote", but "Figure" is also acceptable.
352
+ ### Auto alt/title detection
248
353
 
354
+ ```
355
+ [Markdown]
356
+ ![Figure. A cat.](cat.jpg)
249
357
 
250
- From version 0.5.0, it supports cases where a paragraph contains only multiple images. Instead of `f-img` as the figure class name, use the following class name. (This class name is unstable, but I probably won't change it.)
358
+ [HTML]
359
+ <figure class="f-img">
360
+ <figcaption><span class="f-img-label">Figure<span class="f-img-label-joint">.</span></span> A cat.</figcaption>
361
+ <img src="cat.jpg" alt="">
362
+ </figure>
251
363
 
252
- - `f-img-horizontal` if the image is written in one line on Markdown
253
- - `f-img-vertical` if images are written only vertically, one per line
254
- - `f-img-multiple` in other cases
255
364
 
256
- Notice. This process can be turned off by specifying `{multipleImages: false}`.
365
+ [Markdown]
366
+ ![A white cat eats fishs.](cat.jpg "Figure. A cat.")
257
367
 
368
+ [HTML]
369
+ <figure class="f-img">
370
+ <figcaption><span class="f-img-label">Figure<span class="f-img-label-joint">.</span></span> A cat.</figcaption>
371
+ <img src="cat.jpg" alt="A white cat eats fishs.">
372
+ </figure>
258
373
  ```
374
+
375
+ ### Multiple images
376
+
377
+ ~~~
259
378
  [Markdown]
260
379
  A paragraph. multipleImages: true. horizontal images only.
261
380
 
262
- ![One cat](cat1.jpg) ![Two cat](cat2.jpg)
381
+ ![Sitting cat](cat1.jpg) ![Standing cat](cat2.jpg)
263
382
 
264
383
  Figure. Cats.
265
384
 
@@ -267,7 +386,7 @@ A paragraph.
267
386
  [HTML]
268
387
  <p>A paragraph. multipleImages: true. horizontal images only</p>
269
388
  <figure class="f-img-horizontal">
270
- <img src="cat1.jpg" alt="One cat"><img src="cat2.jpg" alt="Two cat">
389
+ <img src="cat1.jpg" alt="Sitting cat"><img src="cat2.jpg" alt="Standing cat">
271
390
  <figcaption><span class="f-img-label">Figure<span class="f-img-label-joint">.</span></span> Cats.</figcaption>
272
391
  </figure>
273
392
  <p>A paragraph.</p>
@@ -277,16 +396,16 @@ A paragraph. multipleImages: true. vertical images only.
277
396
 
278
397
  Figure. Cats.
279
398
 
280
- ![One cat](cat1.jpg)
281
- ![Two cat](cat2.jpg)
399
+ ![Sitting cat](cat1.jpg)
400
+ ![Standing cat](cat2.jpg)
282
401
 
283
402
  A paragraph.
284
403
  [HTML]
285
404
  <p>A paragraph. multipleImages: true. vertical images only.</p>
286
405
  <figure class="f-img-vertical">
287
406
  <figcaption><span class="f-img-label">Figure<span class="f-img-label-joint">.</span></span> Cats.</figcaption>
288
- <img src="cat1.jpg" alt="One cat">
289
- <img src="cat2.jpg" alt="Two cat">
407
+ <img src="cat1.jpg" alt="Sitting cat">
408
+ <img src="cat2.jpg" alt="Standing cat">
290
409
  </figure>
291
410
  <p>A paragraph.</p>
292
411
 
@@ -295,271 +414,166 @@ A paragraph. multipleImages: true.
295
414
 
296
415
  Figure. Cats.
297
416
 
298
- ![One cat](cat1.jpg) ![Two cat](cat2.jpg)
299
- ![Three cat](cat3.jpg)
417
+ ![Sitting cat](cat1.jpg) ![Standing cat](cat2.jpg)
418
+ ![Sleeping cat](cat3.jpg)
300
419
 
301
420
  A paragraph.
302
421
  [HTML]
303
422
  <p>A paragraph. multipleImages: true.</p>
304
423
  <figure class="f-img-multiple">
305
424
  <figcaption><span class="f-img-label">Figure<span class="f-img-label-joint">.</span></span> Cats.</figcaption>
306
- <img src="cat1.jpg" alt="One cat"><img src="cat2.jpg" alt="Two cat">
307
- <img src="cat3.jpg" alt="Three cat">
425
+ <img src="cat1.jpg" alt="Sitting cat"><img src="cat2.jpg" alt="Standing cat">
426
+ <img src="cat3.jpg" alt="Sleeping cat">
308
427
  </figure>
309
428
  <p>A paragraph.</p>
310
- ```
311
-
312
- ## Option: Specify file name
429
+ ~~~
313
430
 
314
- Specify the file name before writing the caption.
315
- Note that a space is required between the file name and caption.
431
+ ## Option Examples
316
432
 
317
- ### Use double quote
433
+ ### Styles
318
434
 
319
- ```js
435
+ This example uses `classPrefix: 'custom'` and leaves `styleProcess: true` so a trailing `{.notice}` block moves onto the `<figure>` wrapper.
320
436
 
321
- md.use(mditFigureWithPCaption, {dquoteFilename: true});
322
437
  ```
323
-
324
- ~~~
325
438
  [Markdown]
326
- A paragraph.
327
-
328
- Code. "filename.js" Call a cat.
329
-
330
- ```js
331
- console.log('Nyaan!');
332
- ```
333
-
334
- A paragraph.
439
+ Figure. Highlighted cat. {.notice}
335
440
 
441
+ ![Highlighted cat](cat.jpg)
336
442
  [HTML]
337
- <p>A paragraph.</p>
338
- <figure class="f-pre-code">
339
- <figcaption><span class="f-pre-code-label">Code<span class="f-pre-code-label-joint">.</span></span> <strong class="f-pre-code-filename">filename.js</strong> Call a cat.</figcaption>
340
- <pre><code class="language-js">console.log('Nyaan!');
341
- </code></pre>
443
+ <figure class="custom-img notice">
444
+ <figcaption><span class="custom-img-label">Figure<span class="custom-img-label-joint">.</span></span> Highlighted cat.</figcaption>
445
+ <img src="cat.jpg" alt="Highlighted cat">
342
446
  </figure>
343
- <p>A paragraph.</p>
344
- ~~~
345
-
346
- ### Use strong mark
347
-
348
- ```js
349
- md.use(mditFigureWithPCaption, {strongFilename: true});
350
447
  ```
351
448
 
352
- ~~~
449
+ ### Automatic detection fallbacks
353
450
 
354
- [Markdown]
355
- A paragraph.
451
+ `autoCaptionDetection` combined with `autoAltCaption` / `autoTitleCaption` can still generate caption text even when the original alt/title lacks labels. The corresponding attributes are cleared after conversion so the figcaption becomes the canonical source.
356
452
 
357
- Code. **filename.js** Call a cat.
358
-
359
- ```js
360
- console.log('Nyaan!');
361
453
  ```
362
-
363
- A paragraph.
454
+ [Markdown]
455
+ ![Alt fallback example](bird.jpg)
364
456
 
365
457
  [HTML]
366
- <p>A paragraph.</p>
367
- <figure class="f-pre-code">
368
- <figcaption><span class="f-pre-code-label">Code<span class="f-pre-code-label-joint">.</span></span> <strong class="f-pre-code-filename">filename.js</strong> Call a cat.</figcaption>
369
- <pre><code class="language-js">console.log('Nyaan!');
370
- </code></pre>
458
+ <figure class="f-img">
459
+ <figcaption><span class="f-img-label">Figure<span class="f-img-label-joint">.</span></span> Alt fallback example</figcaption>
460
+ <img src="bird.jpg" alt="">
371
461
  </figure>
372
- <p>A paragraph.</p>
373
- ~~~
374
-
375
- ## Option
376
-
377
- ### Convert one image paragraph without caption
378
462
 
379
- Convert one image paragraph without a caption paragraph to figure element.
380
463
 
381
- ```js
382
- md.use(mditFigureWithPCaption, {oneImageWithoutCaption: true});
383
- ```
384
-
385
- ~~~
386
464
  [Markdown]
387
- A paragraph.
388
-
389
- ![Figure](cat.jpg)
390
-
391
- A paragraph.
465
+ ![No caption](fish.jpg "Plain title text")
392
466
 
393
467
  [HTML]
394
- <p>A paragraph.</p>
395
468
  <figure class="f-img">
396
- <img src="cat.jpg" alt="Figure">
469
+ <figcaption><span class="f-img-label">Figure<span class="f-img-label-joint">.</span></span> Plain title text</figcaption>
470
+ <img src="fish.jpg" alt="No caption">
397
471
  </figure>
398
- <p>A paragraph.</p>
399
- ~~~
400
-
401
- ### Convert one video element without caption
402
-
403
- Convert one video element without a caption paragraph to figure element.
404
-
405
- ```js
406
- md.use(mditFigureWithPCaption, {videoWithoutCaption: true});
407
472
  ```
408
473
 
409
- #### Convert one iframe without caption
474
+ ### Role helpers
410
475
 
411
- Convert one iframe without a caption paragraph to iframe element. (adn twitter blockquote embed eelment.)
412
-
413
- ```js
414
- md.use(mditFigureWithPCaption, {iframeWithoutCaption: true});
415
- ```
476
+ Set `roleDocExample: true` to add `role="doc-example"` to code/samp figures.
416
477
 
417
478
  ~~~
418
479
  [Markdown]
419
- <iframe src="https://example.com/embed" class="mastodon-embed" style="max-width: 100%; border: 0" width="400" allowfullscreen="allowfullscreen"></iframe><script src="https://exapmle.com/embed.js" async="async"></script>
480
+ ```samp
481
+ $ pwd
482
+ /home/user
483
+ ```
484
+
420
485
  [HTML]
421
- <figure class="f-iframe">
422
- <iframe src="https://example.com/embed" class="mastodon-embed" style="max-width: 100%; border: 0" width="400" allowfullscreen="allowfullscreen"></iframe><script src="https://exapmle.com/embed.js" async="async"></script>
486
+ <figure class="f-pre-samp" role="doc-example">
487
+ ...
423
488
  </figure>
489
+ ~~~
424
490
 
425
- [Markdown]
426
- A paragraph.
427
-
428
- <iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/XXXXXXXXXXX" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
491
+ ### Captionless conversion toggles
429
492
 
430
- A paragraph.
431
- [HTML]
432
- <p>A paragraph.</p>
433
- <figure class="f-video">
434
- <iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/XXXXXXXXXXX" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
435
- </figure>
436
- <p>A paragraph.</p>
493
+ If `oneImageWithoutCaption` is enabled, a single image paragraph will be wrapped with `<figure class="f-img">` even without a caption.
437
494
 
495
+ ```
438
496
  [Markdown]
439
- <iframe src="https://player.vimeo.com/video/xxxxxxxxxxxxxxx" width="640" height="360" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen></iframe>
497
+ ![A single cat](cat.jpg)
498
+
440
499
  [HTML]
441
- <figure class="f-video">
442
- <iframe src="https://player.vimeo.com/video/xxxxxxxxxxxxxxx" width="640" height="360" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen></iframe>
500
+ <figure class="f-img">
501
+ <img src="cat.jpg" alt="A single cat">
443
502
  </figure>
503
+ ```
444
504
 
445
- [Markdown]
446
- A paragraph. iframeWithoutCaption: true.
505
+ If `videoWithoutCaption` is enabled, an `iframe` pointing to a known video host (such as YouTube or video elements) will be wrapped with `<figure class="f-video">`.
447
506
 
448
- <blockquote class="twitter-tweet"><p lang="ja" dir="ltr">XXXXX <a href="https://t.co/XXXXX">https://t.co/XXXXX</a></p>&mdash; User (@twitter) <a href="https://twitter.com/UserID/status/XXXXX">August 4, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
507
+ ```
508
+ [Markdown]
509
+ <iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/XXXXXXXXXXX" ...></iframe>
449
510
 
450
- A paragraph.
451
511
  [HTML]
452
- <p>A paragraph. iframeWithoutCaption: true.</p>
453
- <figure class="f-iframe">
454
- <blockquote class="twitter-tweet"><p lang="ja" dir="ltr">XXXXX <a href="https://t.co/XXXXX">https://t.co/XXXXX</a></p>&mdash; User (@twitter) <a href="https://twitter.com/UserID/status/XXXXX">August 4, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
512
+ <figure class="f-video">
513
+ <iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/XXXXXXXXXXX" ...></iframe>
455
514
  </figure>
456
- <p>A paragraph.</p>
457
515
 
458
- [Markdown]
459
- <iframe src="https://example.com/embed" class="mastodon-embed" style="max-width: 100%; border: 0" width="400" allowfullscreen="allowfullscreen"></iframe><script src="https://exapmle.com/embed.js" async="async"></script>
460
- [HTML]
461
- <figure class="f-iframe">
462
- <iframe src="https://example.com/embed" class="mastodon-embed" style="max-width: 100%; border: 0" width="400" allowfullscreen="allowfullscreen"></iframe><script src="https://exapmle.com/embed.js" async="async"></script>
463
- </figure>
464
516
 
465
517
  [Markdown]
466
- <iframe class="speakerdeck-iframe" style="border: 0px none; background: rgba(0, 0, 0, 0.1) padding-box; margin: 0px; padding: 0px; border-radius: 6px; box-shadow: rgba(0, 0, 0, 0.2) 0px 5px 40px; width: 100%; height: auto; aspect-ratio: 560 / 314;" src="https://speakerdeck.com/player/xxxxxxxxxxxxxx" title="xxxxxxxxxxx" allowfullscreen="true" data-ratio="1.78343949044586" frameborder="0"></iframe>
518
+ <video controls width="400" height="300">
519
+ <source src="example.mp4" type="video/mp4">
520
+ </video>
467
521
  [HTML]
468
- <figure class="f-iframe">
469
- <iframe class="speakerdeck-iframe" style="border: 0px none; background: rgba(0, 0, 0, 0.1) padding-box; margin: 0px; padding: 0px; border-radius: 6px; box-shadow: rgba(0, 0, 0, 0.2) 0px 5px 40px; width: 100%; height: auto; aspect-ratio: 560 / 314;" src="https://speakerdeck.com/player/xxxxxxxxxxxxxx" title="xxxxxxxxxxx" allowfullscreen="true" data-ratio="1.78343949044586" frameborder="0"></iframe>
522
+ <figure class="f-video">
523
+ <video controls width="400" height="300">
524
+ <source src="example.mp4" type="video/mp4">
525
+ </video>
470
526
  </figure>
471
- ~~~
472
-
473
- ### Option: imgAltCaption
474
-
475
- In Markdown documents, captions are often written in the alt attribute of images. If you follow the syntax of this plugin, the commit log will be cluttered. Therefore, as an option, the alt attribute is treated as a caption.
476
- Note that you cannot use this plugin's syntax and this option's syntax at the same time.
477
-
478
- The img alt attribute have an empty value.
479
-
480
- ```js
481
- const mdImgAltCaption = mdit({html: true}).use(mditFigureWithPCaption, {imgAltCaption: 'Figure'})
482
527
  ```
483
528
 
529
+ When `iframeWithoutCaption` is enabled, iframe elements will be wrapped with `<figure class="f-iframe">`. And if `iframeTypeBlockquoteWithoutCaption` is enabled, blockquote-based embeds (for example, X) will be wrapped with `<figure class="f-img">` (or another configured class).
530
+
484
531
  ```
485
532
  [Markdown]
486
- ![Figure. A caption.](cat.jpg)
533
+ <iframe>
534
+ ...
535
+ </iframe>
487
536
 
488
537
  [HTML]
489
- <figure class="f-img">
490
- <figcaption><span class="f-img-label">Figure<span class="f-img-label-joint">.</span></span> A caption.</figcaption>
491
- <img src="cat.jpg" alt="">
538
+ <figure class="f-iframe">
539
+ <iframe>
540
+ ...
541
+ </iframe>
492
542
  </figure>
493
543
  ```
494
544
 
495
- ### Option: imgTitleCaption
496
-
497
- The title attribute of the Markdown img element is used as the caption.
498
- Note that you cannot use this plugin's standard syntax and this option's syntax at the same time.
499
-
500
- The img alt attribute is not specially modified during conversion; the Markdown alt attribute is used as is.
545
+ ### Iframe-type blockquote class override
501
546
 
502
- ```js
503
- const mdImgAltCaption = mdit({html: true}).use(mditFigureWithPCaption, {imgTitleCaption: 'Figure'})
504
- ```
547
+ Set `figureClassThatWrapsIframeTypeBlockquote: 'f-social'` (or any class you prefer) to wrap blockquote-based embeds (for example, X, Mastodon, Bluesky) with that class.
505
548
 
506
549
  ```
507
550
  [Markdown]
508
- ![A alt text.](cat.jpg "Figure. A caption.")
551
+ Figure. Twitter embed.
552
+
553
+ <blockquote class="twitter-tweet"><p>Embed content</p></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
509
554
 
510
555
  [HTML]
511
- <figure class="f-img">
512
- <figcaption><span class="f-img-label">Figure<span class="f-img-label-joint">.</span></span> A caption.</figcaption>
513
- <img src="cat.jpg" alt="A alt text.">
556
+ <figure class="f-social">
557
+ <figcaption><span class="f-img-label">Figure<span class="f-img-label-joint">.</span></span> Twitter embed.</figcaption>
558
+ <blockquote class="twitter-tweet"><p>Embed content</p></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
514
559
  </figure>
515
560
  ```
516
561
 
517
- ### Option: roleDocExample
562
+ ### All iframe/embed class override
518
563
 
519
- From version 0.8, role="doc-example" is not included as standard in figure.f-pre-code and figure.f-pre-samp. If necessary, set `roleDocExample: true.`
520
-
521
- ```js
522
- const mdImgAltCaption = mdit({html: true}).use(mditFigureWithPCaption, {roleDocExample: true})
523
- ```
524
-
525
- ### Option: allIframeTypeFigureClassName
526
-
527
- From version 0.16.0, unify the figure element that wraps the iframe or blockquote tag in the embed code to figure.f-embed (this may become the default in the future).
528
-
529
- ```js
530
- const mdAllIframeTypeFigureClassName = mdit({html: true}).use(mdFigureWithPCaption, {
531
- allIframeTypeFigureClassName: 'f-embed',
532
- videoWithoutCaption = true,
533
- iframeWithoutCaption = true,
534
- iframeTypeBlockquoteWithoutCaption = true,
535
- }).use(mditAttrs).use(mditRndererFence);
536
- ```
564
+ Set `allIframeTypeFigureClassName: 'f-embed'` (or any class you prefer) to consolidate iframe-like embeds under one class.
537
565
 
538
566
  ```
539
567
  [Markdown]
540
- <iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/XXXXXXXXXXX" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
541
- [HTML]
542
- <figure class="f-embed">
543
- <iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/XXXXXXXXXXX" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
544
- </figure>
545
-
568
+ Video. Custom embed.
546
569
 
547
- [Markdown]
548
- Video. A youtube.
570
+ <iframe width="560" height="315" src="https://example.com/embed/123" title="Custom embed" frameborder="0" allowfullscreen></iframe>
549
571
 
550
- <iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/XXXXXXXXXXX" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
551
572
  [HTML]
552
573
  <figure class="f-embed">
553
- <figcaption><span class="f-video-label">Video<span class="f-video-label-joint">.</span></span> A youtube.</figcaption>
554
- <iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/XXXXXXXXXXX" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
574
+ <figcaption><span class="f-video-label">Video<span class="f-video-label-joint">.</span></span> Custom embed.</figcaption>
575
+ <iframe width="560" height="315" src="https://example.com/embed/123" title="Custom embed" frameborder="0" allowfullscreen></iframe>
555
576
  </figure>
577
+ ```
556
578
 
557
-
558
- [Markdown]
559
- <blockquote class="mastodon-embed" data-embed-url="https://mastodon.social/@xxxx/xxxx/embed" ...>xxxxxxxxxxxxxxxx</blockquote> <script data-allowed-prefixes="https://mastodon.social/" async src="https://mastodon.social/embed.js"></script>
560
-
561
- [HTML]
562
- <figure class="f-embed">
563
- <blockquote class="mastodon-embed" data-embed-url="https://mastodon.social/@xxxx/xxxx/embed" ...>xxxxxxxxxxxxxxxx</blockquote> <script data-allowed-prefixes="https://mastodon.social/" async src="https://mastodon.social/embed.js"></script>
564
- </figure>
565
- ```
579
+ Need matching caption classes too? Combine this option with `labelClassFollowsFigure` (and optionally `figureToLabelClassMap`) so the `figcaption` spans inherit the embed class you just applied (e.g., `f-embed-label`, `f-embed-label-joint`).