@@ -13,7 +13,6 @@ import type {
13
13
DOMConversionOutput ,
14
14
DOMExportOutput ,
15
15
EditorConfig ,
16
- EditorThemeClasses ,
17
16
LexicalNode ,
18
17
NodeKey ,
19
18
ParagraphNode ,
@@ -22,10 +21,6 @@ import type {
22
21
Spread ,
23
22
} from 'lexical' ;
24
23
25
- import {
26
- addClassNamesToElement ,
27
- removeClassNamesFromElement ,
28
- } from '@lexical/utils' ;
29
24
import {
30
25
$applyNodeReplacement ,
31
26
$createParagraphNode ,
@@ -36,11 +31,11 @@ import {
36
31
LexicalEditor ,
37
32
} from 'lexical' ;
38
33
import invariant from 'lexical/shared/invariant' ;
39
- import normalizeClassNames from 'lexical/shared/normalizeClassNames' ;
40
34
41
35
import { $createListNode , $isListNode } from './' ;
42
- import { $handleIndent , $handleOutdent , mergeLists } from './formatList' ;
36
+ import { mergeLists } from './formatList' ;
43
37
import { isNestedListNode } from './utils' ;
38
+ import { el } from "../../utils/dom" ;
44
39
45
40
export type SerializedListItemNode = Spread <
46
41
{
@@ -74,11 +69,17 @@ export class ListItemNode extends ElementNode {
74
69
createDOM ( config : EditorConfig ) : HTMLElement {
75
70
const element = document . createElement ( 'li' ) ;
76
71
const parent = this . getParent ( ) ;
72
+
77
73
if ( $isListNode ( parent ) && parent . getListType ( ) === 'check' ) {
78
- updateListItemChecked ( element , this , null , parent ) ;
74
+ updateListItemChecked ( element , this ) ;
79
75
}
76
+
80
77
element . value = this . __value ;
81
- $setListItemThemeClassNames ( element , config . theme , this ) ;
78
+
79
+ if ( $hasNestedListWithoutLabel ( this ) ) {
80
+ element . style . listStyle = 'none' ;
81
+ }
82
+
82
83
return element ;
83
84
}
84
85
@@ -89,11 +90,12 @@ export class ListItemNode extends ElementNode {
89
90
) : boolean {
90
91
const parent = this . getParent ( ) ;
91
92
if ( $isListNode ( parent ) && parent . getListType ( ) === 'check' ) {
92
- updateListItemChecked ( dom , this , prevNode , parent ) ;
93
+ updateListItemChecked ( dom , this ) ;
93
94
}
95
+
96
+ dom . style . listStyle = $hasNestedListWithoutLabel ( this ) ? 'none' : '' ;
94
97
// @ts -expect-error - this is always HTMLListItemElement
95
98
dom . value = this . __value ;
96
- $setListItemThemeClassNames ( dom , config . theme , this ) ;
97
99
98
100
return false ;
99
101
}
@@ -132,6 +134,20 @@ export class ListItemNode extends ElementNode {
132
134
133
135
exportDOM ( editor : LexicalEditor ) : DOMExportOutput {
134
136
const element = this . createDOM ( editor . _config ) ;
137
+
138
+ if ( element . classList . contains ( 'task-list-item' ) ) {
139
+ const input = el ( 'input' , {
140
+ type : 'checkbox' ,
141
+ disabled : 'disabled' ,
142
+ } ) ;
143
+ if ( element . hasAttribute ( 'checked' ) ) {
144
+ input . setAttribute ( 'checked' , 'checked' ) ;
145
+ element . removeAttribute ( 'checked' ) ;
146
+ }
147
+
148
+ element . prepend ( input ) ;
149
+ }
150
+
135
151
return {
136
152
element,
137
153
} ;
@@ -390,89 +406,33 @@ export class ListItemNode extends ElementNode {
390
406
}
391
407
}
392
408
393
- function $setListItemThemeClassNames (
394
- dom : HTMLElement ,
395
- editorThemeClasses : EditorThemeClasses ,
396
- node : ListItemNode ,
397
- ) : void {
398
- const classesToAdd = [ ] ;
399
- const classesToRemove = [ ] ;
400
- const listTheme = editorThemeClasses . list ;
401
- const listItemClassName = listTheme ? listTheme . listitem : undefined ;
402
- let nestedListItemClassName ;
403
-
404
- if ( listTheme && listTheme . nested ) {
405
- nestedListItemClassName = listTheme . nested . listitem ;
406
- }
407
-
408
- if ( listItemClassName !== undefined ) {
409
- classesToAdd . push ( ...normalizeClassNames ( listItemClassName ) ) ;
410
- }
411
-
412
- if ( listTheme ) {
413
- const parentNode = node . getParent ( ) ;
414
- const isCheckList =
415
- $isListNode ( parentNode ) && parentNode . getListType ( ) === 'check' ;
416
- const checked = node . getChecked ( ) ;
417
-
418
- if ( ! isCheckList || checked ) {
419
- classesToRemove . push ( listTheme . listitemUnchecked ) ;
420
- }
421
-
422
- if ( ! isCheckList || ! checked ) {
423
- classesToRemove . push ( listTheme . listitemChecked ) ;
424
- }
409
+ function $hasNestedListWithoutLabel ( node : ListItemNode ) : boolean {
410
+ const children = node . getChildren ( ) ;
411
+ let hasLabel = false ;
412
+ let hasNestedList = false ;
425
413
426
- if ( isCheckList ) {
427
- classesToAdd . push (
428
- checked ? listTheme . listitemChecked : listTheme . listitemUnchecked ,
429
- ) ;
414
+ for ( const child of children ) {
415
+ if ( $isListNode ( child ) ) {
416
+ hasNestedList = true ;
417
+ } else if ( child . getTextContent ( ) . trim ( ) . length > 0 ) {
418
+ hasLabel = true ;
430
419
}
431
420
}
432
421
433
- if ( nestedListItemClassName !== undefined ) {
434
- const nestedListItemClasses = normalizeClassNames ( nestedListItemClassName ) ;
435
-
436
- if ( node . getChildren ( ) . some ( ( child ) => $isListNode ( child ) ) ) {
437
- classesToAdd . push ( ...nestedListItemClasses ) ;
438
- } else {
439
- classesToRemove . push ( ...nestedListItemClasses ) ;
440
- }
441
- }
442
-
443
- if ( classesToRemove . length > 0 ) {
444
- removeClassNamesFromElement ( dom , ...classesToRemove ) ;
445
- }
446
-
447
- if ( classesToAdd . length > 0 ) {
448
- addClassNamesToElement ( dom , ...classesToAdd ) ;
449
- }
422
+ return hasNestedList && ! hasLabel ;
450
423
}
451
424
452
425
function updateListItemChecked (
453
426
dom : HTMLElement ,
454
427
listItemNode : ListItemNode ,
455
- prevListItemNode : ListItemNode | null ,
456
- listNode : ListNode ,
457
428
) : void {
458
- // Only add attributes for leaf list items
459
- if ( $isListNode ( listItemNode . getFirstChild ( ) ) ) {
460
- dom . removeAttribute ( 'role' ) ;
461
- dom . removeAttribute ( 'tabIndex' ) ;
462
- dom . removeAttribute ( 'aria- checked') ;
429
+ // Only set task list attrs for leaf list items
430
+ const shouldBeTaskItem = ! $isListNode ( listItemNode . getFirstChild ( ) ) ;
431
+ dom . classList . toggle ( 'task-list-item' , shouldBeTaskItem ) ;
432
+ if ( listItemNode . __checked ) {
433
+ dom . setAttribute ( 'checked' , ' checked') ;
463
434
} else {
464
- dom . setAttribute ( 'role' , 'checkbox' ) ;
465
- dom . setAttribute ( 'tabIndex' , '-1' ) ;
466
-
467
- if (
468
- ! prevListItemNode ||
469
- listItemNode . __checked !== prevListItemNode . __checked
470
- ) {
471
- dom . setAttribute (
472
- 'aria-checked' ,
473
- listItemNode . getChecked ( ) ? 'true' : 'false' ,
474
- ) ;
475
- }
435
+ dom . removeAttribute ( 'checked' ) ;
476
436
}
477
437
}
478
438
0 commit comments