diff --git a/lib/handlers/li.js b/lib/handlers/li.js index 3d48465..7528d85 100644 --- a/lib/handlers/li.js +++ b/lib/handlers/li.js @@ -17,43 +17,17 @@ import {phrasing} from 'hast-util-phrasing' * mdast node. */ export function li(state, node) { - const head = node.children[0] - /** @type {boolean | null} */ - let checked = null - /** @type {Element | undefined} */ - let clone - - // Check if this node starts with a checkbox. - if (head && head.type === 'element' && head.tagName === 'p') { - const checkbox = head.children[0] - - if ( - checkbox && - checkbox.type === 'element' && - checkbox.tagName === 'input' && - checkbox.properties && - (checkbox.properties.type === 'checkbox' || - checkbox.properties.type === 'radio') - ) { - checked = Boolean(checkbox.properties.checked) - clone = { - ...node, - children: [ - {...head, children: head.children.slice(1)}, - ...node.children.slice(1) - ] - } - } - } + // If the list item starts with a checkbox, remove the checkbox and mark the + // list item as a GFM task list item. + const {cleanNode, checkbox} = extractLeadingCheckbox(node) + const checked = checkbox && Boolean(checkbox.properties.checked) - if (!clone) clone = node - - const spread = spreadout(clone) - const children = state.toFlow(state.all(clone)) + const spread = spreadout(cleanNode) + const children = state.toFlow(state.all(cleanNode)) /** @type {ListItem} */ const result = {type: 'listItem', spread, checked, children} - state.patch(clone, result) + state.patch(cleanNode, result) return result } @@ -99,3 +73,61 @@ function spreadout(node) { return false } + +/** + * If the first bit of content in an element is a checkbox, create a copy of + * the element that does not include the checkbox and return the cleaned up + * copy alongside the checkbox that was removed. If there was no leading + * checkbox, this returns the original element unaltered (not a copy). + * + * This detects trees like: + * `
Text
Text
` elements, which is most common. + // It's possible a leading checkbox might be nested in other types of flow or + // phrasing elements (and *deeply* nested, which is not possible with `
`). + // Limiting things to `
` elements keeps this simpler for now. + if (head && head.type === 'element' && head.tagName === 'p') { + const {cleanNode: cleanHead, checkbox} = extractLeadingCheckbox(head) + if (checkbox) { + return { + cleanNode: { + ...node, + children: [cleanHead, ...node.children.slice(1)] + }, + checkbox + } + } + } + + return {cleanNode: node, checkbox: null} +} diff --git a/test/fixtures/ol/index.html b/test/fixtures/ol/index.html index 4e6476d..9511261 100644 --- a/test/fixtures/ol/index.html +++ b/test/fixtures/ol/index.html @@ -59,4 +59,14 @@
Echo
Foxtrot
Golf
+ Hotel +
+Echo
Foxtrot
Golf
+ Hotel +
+