@@ -142,38 +142,121 @@ export const improveHtmlAccessibility = (
142142 block . replaceWith ( heading ) ;
143143 } ) ;
144144
145- // 2) Lists: group consecutive list items into UL/OL with LI children
145+ // 2) Lists: convert to semantic OL/ UL/LI elements for accessibility
146146 const listItemSelector =
147147 "[data-content-type='bulletListItem'], [data-content-type='numberedListItem']" ;
148- const listItems = Array . from (
149- body . querySelectorAll < HTMLElement > ( listItemSelector ) ,
148+
149+ // Helper function to get nesting level by counting block-group ancestors
150+ const getNestingLevel = ( blockOuter : HTMLElement ) : number => {
151+ let level = 0 ;
152+ let parent = blockOuter . parentElement ;
153+ while ( parent ) {
154+ if ( parent . classList . contains ( 'bn-block-group' ) ) {
155+ level ++ ;
156+ }
157+ parent = parent . parentElement ;
158+ }
159+ return level ;
160+ } ;
161+
162+ // Find all block-outer elements in document order
163+ const allBlockOuters = Array . from (
164+ body . querySelectorAll < HTMLElement > ( '.bn-block-outer' ) ,
150165 ) ;
151166
152- listItems . forEach ( ( item ) => {
153- const parent = item . parentElement ;
154- if ( ! parent ) {
155- return ;
167+ // Collect list items with their info before modifying DOM
168+ interface ListItemInfo {
169+ blockOuter : HTMLElement ;
170+ listItem : HTMLElement ;
171+ contentType : string ;
172+ level : number ;
173+ }
174+
175+ const listItemsInfo : ListItemInfo [ ] = [ ] ;
176+ allBlockOuters . forEach ( ( blockOuter ) => {
177+ const listItem = blockOuter . querySelector < HTMLElement > ( listItemSelector ) ;
178+ if ( listItem ) {
179+ const contentType = listItem . getAttribute ( 'data-content-type' ) ;
180+ if ( contentType ) {
181+ const level = getNestingLevel ( blockOuter ) ;
182+ listItemsInfo . push ( {
183+ blockOuter,
184+ listItem,
185+ contentType,
186+ level,
187+ } ) ;
188+ }
156189 }
190+ } ) ;
191+
192+ // Stack to track lists at each nesting level
193+ const listStack : Array < { list : HTMLElement ; type : string ; level : number } > =
194+ [ ] ;
157195
158- const isBullet =
159- item . getAttribute ( 'data-content-type' ) === 'bulletListItem' ;
196+ listItemsInfo . forEach ( ( info , idx ) => {
197+ const { blockOuter, listItem, contentType, level } = info ;
198+ const isBullet = contentType === 'bulletListItem' ;
160199 const listTag = isBullet ? 'ul' : 'ol' ;
161200
162- // If the previous sibling is already the right list, reuse it; otherwise create a new one.
163- let previousSibling = item . previousElementSibling ;
164- let listContainer : HTMLElement | null = null ;
201+ // Check if previous item continues the same list (same type and level)
202+ const previousInfo = idx > 0 ? listItemsInfo [ idx - 1 ] : null ;
203+ const continuesPreviousList =
204+ previousInfo &&
205+ previousInfo . contentType === contentType &&
206+ previousInfo . level === level ;
165207
166- if ( previousSibling ?. tagName . toLowerCase ( ) === listTag ) {
167- listContainer = previousSibling as HTMLElement ;
168- } else {
169- listContainer = parsedDocument . createElement ( listTag ) ;
170- parent . insertBefore ( listContainer , item ) ;
208+ // Find or create the appropriate list
209+ let targetList : HTMLElement | null = null ;
210+
211+ if ( continuesPreviousList ) {
212+ // Continue with the list at this level from stack
213+ const listAtLevel = listStack . find ( ( item ) => item . level === level ) ;
214+ targetList = listAtLevel ?. list || null ;
215+ }
216+
217+ // If no list found, create a new one
218+ if ( ! targetList ) {
219+ targetList = parsedDocument . createElement ( listTag ) ;
220+
221+ // Remove lists from stack that are at same or deeper level
222+ while (
223+ listStack . length > 0 &&
224+ listStack [ listStack . length - 1 ] . level >= level
225+ ) {
226+ listStack . pop ( ) ;
227+ }
228+
229+ // If we have a parent list, nest this list inside its last li
230+ if (
231+ listStack . length > 0 &&
232+ listStack [ listStack . length - 1 ] . level < level
233+ ) {
234+ const parentList = listStack [ listStack . length - 1 ] . list ;
235+ const lastLi = parentList . querySelector ( 'li:last-child' ) ;
236+ if ( lastLi ) {
237+ lastLi . appendChild ( targetList ) ;
238+ } else {
239+ // No li yet, create one and add the nested list
240+ const li = parsedDocument . createElement ( 'li' ) ;
241+ parentList . appendChild ( li ) ;
242+ li . appendChild ( targetList ) ;
243+ }
244+ } else {
245+ // Top-level list
246+ blockOuter . parentElement ?. insertBefore ( targetList , blockOuter ) ;
247+ }
248+
249+ // Add to stack
250+ listStack . push ( { list : targetList , type : contentType , level } ) ;
171251 }
172252
253+ // Create list item and add content
173254 const li = parsedDocument . createElement ( 'li' ) ;
174- li . innerHTML = item . innerHTML ;
175- listContainer . appendChild ( li ) ;
176- parent . removeChild ( item ) ;
255+ li . innerHTML = listItem . innerHTML ;
256+ targetList . appendChild ( li ) ;
257+
258+ // Remove original block-outer
259+ blockOuter . remove ( ) ;
177260 } ) ;
178261
179262 // 3) Quotes -> <blockquote>
@@ -215,6 +298,7 @@ export const improveHtmlAccessibility = (
215298 } else {
216299 listContainer = parsedDocument . createElement ( 'ul' ) ;
217300 listContainer . setAttribute ( 'role' , 'list' ) ;
301+ listContainer . classList . add ( 'checklist' ) ;
218302 parent . insertBefore ( listContainer , item ) ;
219303 }
220304
0 commit comments