1
1
/**
2
- * @import {Element, Root} from 'hast'
2
+ * @import {Root} from 'hast'
3
3
*/
4
4
5
- /**
6
- * This is a private fork of https://github.com/rehypejs/rehype-unwrap-images to work around a Nextra bug.
7
- * See https://github.com/rehypejs/rehype-unwrap-images/pull/1 for why this won't be merged upstream.
8
- */
9
-
10
- import { interactive } from 'hast-util-interactive'
11
5
import { whitespace } from 'hast-util-whitespace'
12
6
import { SKIP , visit } from 'unist-util-visit'
13
7
14
- const unknown = 1
15
- const containsImage = 2
16
- const containsOther = 3
8
+ const isImage = ( node ) =>
9
+ ( node . type === 'element' && node . tagName === 'img' ) || ( node . type === 'mdxJsxFlowElement' && node . name === 'img' )
17
10
18
11
/**
19
- * Remove the wrapping paragraph for images.
12
+ * This plugin does two things:
13
+ * 1. Removes the `p` tag when it only contains images (and whitespace)
14
+ * 2. Adds data attributes to help with image rendering:
15
+ * - `data-wrapping-image` to links that contain an image
16
+ * - `data-inline-image` to images that are in a paragraph with other content (text, links, etc.)
20
17
*
21
18
* @returns
22
19
* Transform.
@@ -32,54 +29,38 @@ export default function rehypeUnwrapImages() {
32
29
*/
33
30
return function ( tree ) {
34
31
visit ( tree , 'element' , function ( node , index , parent ) {
35
- if ( node . tagName === 'p' && parent && typeof index === 'number' && applicable ( node , false ) === containsImage ) {
36
- parent . children . splice ( index , 1 , ...node . children )
37
- return [ SKIP , index ]
38
- }
39
- } )
40
- }
41
- }
42
-
43
- /**
44
- * Check if a node can be unraveled.
45
- *
46
- * @param {Element } node
47
- * Node.
48
- * @param {boolean } inLink
49
- * Whether the node is in a link.
50
- * @returns {1 | 2 | 3 }
51
- * Info.
52
- */
53
- function applicable ( node , inLink ) {
54
- /** @type {1 | 2 | 3 } */
55
- let image = unknown
56
- let index = - 1
57
-
58
- while ( ++ index < node . children . length ) {
59
- const child = node . children [ index ]
32
+ if ( node . tagName === 'p' && parent && typeof index === 'number' ) {
33
+ // First pass: check if the paragraph contains any non-image content
34
+ const hasNonImageContent = node . children . some ( ( child ) => {
35
+ if ( child . type === 'text' ) {
36
+ return ! whitespace ( child . value )
37
+ } else {
38
+ return ! isImage ( child )
39
+ }
40
+ } )
60
41
61
- if ( child . type === 'text' && whitespace ( child . value ) ) {
62
- // Whitespace is fine.
63
- } else if (
64
- ( child . type === 'element' && child . tagName === 'img' ) ||
65
- ( child . type === 'mdxJsxFlowElement' && child . name === 'img' )
66
- ) {
67
- image = containsImage
68
- } else if ( ! inLink && interactive ( child ) ) {
69
- // Cast as `interactive` is always `Element`.
70
- const linkResult = applicable ( /** @type {Element } */ ( child ) , true )
42
+ // Second pass: add data attributes
43
+ node . children . forEach ( ( child ) => {
44
+ if ( child . type === 'element' && child . tagName === 'a' && child . children . some ( isImage ) ) {
45
+ child . properties = child . properties || { }
46
+ child . properties [ 'data-wrapping-image' ] = true
47
+ } else if ( isImage ( child ) && hasNonImageContent ) {
48
+ if ( child . type === 'mdxJsxFlowElement' ) {
49
+ child . attributes = child . attributes || [ ]
50
+ child . attributes . push ( { type : 'mdxJsxAttribute' , name : 'data-inline-image' , value : true } )
51
+ } else {
52
+ child . properties = child . properties || { }
53
+ child . properties [ 'data-inline-image' ] = true
54
+ }
55
+ }
56
+ } )
71
57
72
- if ( linkResult === containsOther ) {
73
- return containsOther
58
+ // If the paragraph only contains images (and whitespace), remove it
59
+ if ( ! hasNonImageContent ) {
60
+ parent . children . splice ( index , 1 , ...node . children )
61
+ return [ SKIP , index ]
62
+ }
74
63
}
75
-
76
- if ( linkResult === containsImage ) {
77
- image = containsImage
78
- }
79
- } else {
80
- return containsOther
81
- }
64
+ } )
82
65
}
83
-
84
- return image
85
66
}
0 commit comments