diff --git a/packages/quill/package.json b/packages/quill/package.json index 1cf1c1e0a0..51f8bfdcaf 100644 --- a/packages/quill/package.json +++ b/packages/quill/package.json @@ -1,6 +1,6 @@ { "name": "quill", - "version": "2.0.4-beta.29", + "version": "2.0.4-beta.31", "description": "Your powerful, rich text editor", "author": "Jason Chen ", "homepage": "https://quilljs.com", @@ -84,7 +84,7 @@ "test": "run-s test:*", "test:unit": "vitest --config test/unit/vitest.config.ts", "test:fuzz": "vitest --config test/fuzz/vitest.config.ts", - "test:e2e": "playwright test" + "test:e2e": "NODE_OPTIONS='--no-experimental-strip-types' playwright test" }, "keywords": [ "quill", diff --git a/packages/quill/src/formats/list.ts b/packages/quill/src/formats/list.ts index 64bcde7160..5cebc73c7a 100644 --- a/packages/quill/src/formats/list.ts +++ b/packages/quill/src/formats/list.ts @@ -11,6 +11,12 @@ class ListItem extends Block { static create(value: string) { const node = super.create() as HTMLElement; node.setAttribute('data-list', value); + if (value === 'checked' || value === 'unchecked') { + node.setAttribute('role', 'checkbox'); + node.setAttribute('aria-checked', value === 'checked' ? 'true' : 'false'); + } else { + node.setAttribute('role', 'listitem'); + } return node; } @@ -27,6 +33,7 @@ class ListItem extends Block { const ui = domNode.ownerDocument.createElement('span'); // though the UI decoration is within the contenteditable, it should not be selectable ui.style.userSelect = 'none'; + ui.setAttribute('aria-hidden', 'true'); const listEventHandler = (e: Event) => { if (!scroll.isEnabled()) return; @@ -47,10 +54,55 @@ class ListItem extends Block { format(name: string, value: string) { if (name === this.statics.blotName && value) { this.domNode.setAttribute('data-list', value); + this.domNode.style.listStyleType = 'none'; + if (value === 'checked' || value === 'unchecked') { + this.domNode.setAttribute('role', 'checkbox'); + this.domNode.setAttribute( + 'aria-checked', + value === 'checked' ? 'true' : 'false', + ); + } else { + this.domNode.removeAttribute('role'); + this.domNode.removeAttribute('aria-checked'); + this.updateAriaLabel(); + } } else { super.format(name, value); } } + + insertAt(index: number, value: string, def?: unknown) { + super.insertAt(index, value, def); + this.updateAriaLabel(); + } + + deleteAt(index: number, length: number) { + super.deleteAt(index, length); + this.updateAriaLabel(); + } + + update(mutations: MutationRecord[], context: Record): void { + super.update(mutations, context); + this.updateAriaLabel(); + } + + private updateAriaLabel() { + const text = this.domNode?.textContent?.trim(); + if (!text) return; + let prefix = ''; + const listType = this.domNode?.getAttribute('data-list'); + if (listType === 'ordered') { + const siblings = Array.from( + this.domNode.parentNode?.querySelectorAll('li[data-list="ordered"]') ?? + [], + ); + const index = siblings.indexOf(this.domNode) + 1; + prefix = `${index}. `; + } else if (listType === 'bullet') { + prefix = '• '; + } + this.domNode.setAttribute('aria-label', prefix + text); + } } ListItem.blotName = 'list'; ListItem.tagName = 'LI'; diff --git a/packages/quill/test/unit/core/editor.spec.ts b/packages/quill/test/unit/core/editor.spec.ts index d39198a5e7..5de44fd7d0 100644 --- a/packages/quill/test/unit/core/editor.spec.ts +++ b/packages/quill/test/unit/core/editor.spec.ts @@ -224,7 +224,7 @@ describe('Editor', () => { .insert('\n', { list: 'bullet' }), ); expect(editor.scroll.domNode).toEqualHTML(` -
  1. 0123

`); +
  1. 0123

`); }); test('append soft line break in format', () => { @@ -565,8 +565,8 @@ describe('Editor', () => { ); expect(editor.scroll.domNode).toEqualHTML( `
    -
  1. 0
  2. -
  3. +
  4. 0
  5. +
  6. 1

    @@ -589,7 +589,7 @@ describe('Editor', () => { ); expect(editor.scroll.domNode).toEqualHTML( `
      -
    1. 0
      1
    2. +
    3. 0
      1
    `, ); }); diff --git a/packages/quill/test/unit/formats/list.spec.ts b/packages/quill/test/unit/formats/list.spec.ts index a12f020706..ba682ad921 100644 --- a/packages/quill/test/unit/formats/list.spec.ts +++ b/packages/quill/test/unit/formats/list.spec.ts @@ -34,7 +34,7 @@ describe('List', () => { expect(editor.scroll.domNode).toEqualHTML(`

    0123

      -
    1. 5678
    2. +
    3. 5678

    0123

    `); @@ -63,8 +63,8 @@ describe('List', () => { ); expect(editor.scroll.domNode).toEqualHTML(`
      -
    1. 0123
    2. -
    3. 5678
    4. +
    5. 0123
    6. +
    7. 5678

    0123

    `); @@ -109,7 +109,7 @@ describe('List', () => { expect(editor.scroll.domNode).toEqualHTML(`

    0123

      -
    1. 5678
    2. +
    3. 5678

    0123

    `); @@ -131,7 +131,7 @@ describe('List', () => { ); expect(editor.scroll.domNode).toEqualHTML(`
      -
    1. 0123
    2. +
    3. 0123
    `); }); @@ -150,7 +150,7 @@ describe('List', () => { ); expect(editor.scroll.domNode).toEqualHTML(`
      -
    1. 0123
    2. +
    3. 0123
    `); }); @@ -178,7 +178,7 @@ describe('List', () => { expect(editor.scroll.domNode).toEqualHTML(`
    1. 0123
    2. -
    3. 5678
    4. +
    5. 5678
    6. 0123
    `); @@ -232,7 +232,7 @@ describe('List', () => { expect(editor.scroll.domNode).toEqualHTML(`
    1. 0123
    2. -
    3. 5678
    4. +
    5. 5678
    6. 0123
    `); @@ -245,13 +245,13 @@ describe('List', () => { editor.insertText(0, 'Test'); expect(editor.scroll.domNode).toEqualHTML(`
      -
    1. Test
    2. +
    3. Test
    `); editor.deleteText(0, 4); expect(editor.scroll.domNode).toEqualHTML(`
      -

    1. +

    `); }); @@ -270,7 +270,7 @@ describe('List', () => { editor.deleteText(2, 5); expect(editor.scroll.domNode).toEqualHTML(`
      -
    1. 0178
    2. +
    3. 0178
    4. 0123
    `); @@ -295,7 +295,7 @@ describe('List', () => { editor.deleteText(2, 5); expect(editor.scroll.domNode).toEqualHTML(`
      -
    1. 0178
    2. +
    3. 0178
    `); }); @@ -315,9 +315,9 @@ describe('List', () => { editor.formatLine(1, 10, { list: 'bullet' }); expect(editor.scroll.domNode).toEqualHTML(`
      -
    1. One
    2. -
    3. Alpha
    4. -
    5. Two
    6. +
    7. One
    8. +
    9. Alpha
    10. +
    11. Two
    `); }); @@ -329,7 +329,7 @@ describe('List', () => { editor.formatLine(4, 1, { list: 'bullet' }); expect(editor.scroll.domNode).toEqualHTML(`
      -
    1. Test
    2. +
    3. Test
    `); }); @@ -345,7 +345,7 @@ describe('List', () => { ); expect(editor.scroll.domNode).toEqualHTML(`
      -
    1. Te
    2. +
    3. Te
      @@ -366,7 +366,7 @@ describe('List', () => { expect(editor.scroll.domNode).toEqualHTML(`
        -
      1. Test
      2. +
      3. Test
      `); }); @@ -382,7 +382,7 @@ describe('List', () => { ); expect(editor.scroll.domNode).toEqualHTML(`
        -
      1. Test
      2. +
      3. Test