@api-client/ui 0.5.18 → 0.5.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/src/elements/code-editor/internals/CodeEditor.d.ts +4 -8
- package/build/src/elements/code-editor/internals/CodeEditor.d.ts.map +1 -1
- package/build/src/elements/code-editor/internals/CodeEditor.js +13 -33
- package/build/src/elements/code-editor/internals/CodeEditor.js.map +1 -1
- package/build/src/md/dialog/internals/Dialog.d.ts +3 -0
- package/build/src/md/dialog/internals/Dialog.d.ts.map +1 -1
- package/build/src/md/dialog/internals/Dialog.js +39 -2
- package/build/src/md/dialog/internals/Dialog.js.map +1 -1
- package/demo/elements/code-editor/CodeEditorDemo.ts +7 -21
- package/package.json +1 -2
- package/src/elements/code-editor/README.md +9 -6
- package/src/elements/code-editor/internals/CodeEditor.ts +9 -21
- package/src/md/dialog/internals/Dialog.ts +50 -2
- package/test/elements/code-editor/code-editor.accessibility.test.ts +2 -29
- package/test/elements/code-editor/code-editor.test.ts +10 -13
- package/test/md/dialog/UiDialog.test.ts +314 -0
|
@@ -441,5 +441,319 @@ describe('md', () => {
|
|
|
441
441
|
})
|
|
442
442
|
})
|
|
443
443
|
})
|
|
444
|
+
|
|
445
|
+
describe('closing event', () => {
|
|
446
|
+
it('dispatches the closing event before close event when dismissing', async () => {
|
|
447
|
+
const element = await buttonFixture()
|
|
448
|
+
const closingSpy = sinon.spy()
|
|
449
|
+
const closeSpy = sinon.spy()
|
|
450
|
+
element.addEventListener('closing', closingSpy)
|
|
451
|
+
element.addEventListener('close', closeSpy)
|
|
452
|
+
|
|
453
|
+
const button = element.querySelector('ui-button[value="dismiss"]') as UiButton
|
|
454
|
+
button.click()
|
|
455
|
+
|
|
456
|
+
assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched')
|
|
457
|
+
assert.isTrue(closeSpy.calledOnce, 'close event was dispatched')
|
|
458
|
+
assert.isTrue(closingSpy.calledBefore(closeSpy), 'closing event was dispatched before close event')
|
|
459
|
+
})
|
|
460
|
+
|
|
461
|
+
it('dispatches the closing event before close event when confirming', async () => {
|
|
462
|
+
const element = await buttonFixture()
|
|
463
|
+
const closingSpy = sinon.spy()
|
|
464
|
+
const closeSpy = sinon.spy()
|
|
465
|
+
element.addEventListener('closing', closingSpy)
|
|
466
|
+
element.addEventListener('close', closeSpy)
|
|
467
|
+
|
|
468
|
+
const button = element.querySelector('ui-button[value="confirm"]') as UiButton
|
|
469
|
+
button.click()
|
|
470
|
+
|
|
471
|
+
assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched')
|
|
472
|
+
assert.isTrue(closeSpy.calledOnce, 'close event was dispatched')
|
|
473
|
+
assert.isTrue(closingSpy.calledBefore(closeSpy), 'closing event was dispatched before close event')
|
|
474
|
+
})
|
|
475
|
+
|
|
476
|
+
it('dispatches the closing event when pressing Escape', async () => {
|
|
477
|
+
const element = await buttonFixture()
|
|
478
|
+
const closingSpy = sinon.spy()
|
|
479
|
+
const closeSpy = sinon.spy()
|
|
480
|
+
element.addEventListener('closing', closingSpy)
|
|
481
|
+
element.addEventListener('close', closeSpy)
|
|
482
|
+
|
|
483
|
+
element.open = true
|
|
484
|
+
await element.updateComplete
|
|
485
|
+
const button = element.querySelector('ui-button')!
|
|
486
|
+
button.focus()
|
|
487
|
+
await UiMock.keyPress(element, 'Escape', { key: 'Escape' })
|
|
488
|
+
|
|
489
|
+
assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched')
|
|
490
|
+
assert.isTrue(closeSpy.calledOnce, 'close event was dispatched')
|
|
491
|
+
assert.isTrue(closingSpy.calledBefore(closeSpy), 'closing event was dispatched before close event')
|
|
492
|
+
})
|
|
493
|
+
|
|
494
|
+
it('dispatches the closing event with correct detail for dismiss action', async () => {
|
|
495
|
+
const element = await buttonFixture()
|
|
496
|
+
const closingSpy = sinon.spy()
|
|
497
|
+
element.addEventListener('closing', closingSpy)
|
|
498
|
+
|
|
499
|
+
const button = element.querySelector('ui-button[value="dismiss"]') as UiButton
|
|
500
|
+
button.click()
|
|
501
|
+
|
|
502
|
+
assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched')
|
|
503
|
+
const event = closingSpy.args[0][0] as CustomEvent<UiDialogClosingReason>
|
|
504
|
+
assert.isTrue(event.detail.cancelled, 'cancelled flag is true for dismiss action')
|
|
505
|
+
assert.isUndefined(event.detail.value, 'value is undefined when no dialogValue is set')
|
|
506
|
+
})
|
|
507
|
+
|
|
508
|
+
it('dispatches the closing event with correct detail for confirm action', async () => {
|
|
509
|
+
const element = await buttonFixture()
|
|
510
|
+
const closingSpy = sinon.spy()
|
|
511
|
+
element.addEventListener('closing', closingSpy)
|
|
512
|
+
|
|
513
|
+
const button = element.querySelector('ui-button[value="confirm"]') as UiButton
|
|
514
|
+
button.click()
|
|
515
|
+
|
|
516
|
+
assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched')
|
|
517
|
+
const event = closingSpy.args[0][0] as CustomEvent<UiDialogClosingReason>
|
|
518
|
+
assert.isFalse(event.detail.cancelled, 'cancelled flag is false for confirm action')
|
|
519
|
+
assert.isUndefined(event.detail.value, 'value is undefined when no dialogValue is set')
|
|
520
|
+
})
|
|
521
|
+
|
|
522
|
+
it('includes dialogValue in closing event detail', async () => {
|
|
523
|
+
const element = await buttonFixture()
|
|
524
|
+
element.dialogValue = 'test-value'
|
|
525
|
+
const closingSpy = sinon.spy()
|
|
526
|
+
element.addEventListener('closing', closingSpy)
|
|
527
|
+
|
|
528
|
+
const button = element.querySelector('ui-button[value="confirm"]') as UiButton
|
|
529
|
+
button.click()
|
|
530
|
+
|
|
531
|
+
assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched')
|
|
532
|
+
const event = closingSpy.args[0][0] as CustomEvent<UiDialogClosingReason>
|
|
533
|
+
assert.equal(event.detail.value, 'test-value', 'dialogValue is included in event detail')
|
|
534
|
+
})
|
|
535
|
+
|
|
536
|
+
it('prevents dialog closing when closing event is cancelled', async () => {
|
|
537
|
+
const element = await buttonFixture()
|
|
538
|
+
const closingSpy = sinon.spy()
|
|
539
|
+
const closeSpy = sinon.spy()
|
|
540
|
+
|
|
541
|
+
element.addEventListener('closing', (event) => {
|
|
542
|
+
closingSpy()
|
|
543
|
+
event.preventDefault() // Cancel the closing
|
|
544
|
+
})
|
|
545
|
+
element.addEventListener('close', closeSpy)
|
|
546
|
+
|
|
547
|
+
element.open = true
|
|
548
|
+
await element.updateComplete
|
|
549
|
+
assert.isTrue(element.open, 'dialog is initially open')
|
|
550
|
+
|
|
551
|
+
const button = element.querySelector('ui-button[value="dismiss"]') as UiButton
|
|
552
|
+
button.click()
|
|
553
|
+
|
|
554
|
+
assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched')
|
|
555
|
+
assert.isFalse(closeSpy.called, 'close event was not dispatched')
|
|
556
|
+
assert.isTrue(element.open, 'dialog remains open when closing is prevented')
|
|
557
|
+
})
|
|
558
|
+
|
|
559
|
+
it('prevents dialog closing when confirming and closing event is cancelled', async () => {
|
|
560
|
+
const element = await buttonFixture()
|
|
561
|
+
const closingSpy = sinon.spy()
|
|
562
|
+
const closeSpy = sinon.spy()
|
|
563
|
+
|
|
564
|
+
element.addEventListener('closing', (event) => {
|
|
565
|
+
closingSpy()
|
|
566
|
+
event.preventDefault() // Cancel the closing
|
|
567
|
+
})
|
|
568
|
+
element.addEventListener('close', closeSpy)
|
|
569
|
+
|
|
570
|
+
element.open = true
|
|
571
|
+
await element.updateComplete
|
|
572
|
+
assert.isTrue(element.open, 'dialog is initially open')
|
|
573
|
+
|
|
574
|
+
const button = element.querySelector('ui-button[value="confirm"]') as UiButton
|
|
575
|
+
button.click()
|
|
576
|
+
|
|
577
|
+
assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched')
|
|
578
|
+
assert.isFalse(closeSpy.called, 'close event was not dispatched')
|
|
579
|
+
assert.isTrue(element.open, 'dialog remains open when closing is prevented')
|
|
580
|
+
})
|
|
581
|
+
|
|
582
|
+
it('prevents dialog closing when pressing Escape and closing event is cancelled', async () => {
|
|
583
|
+
const element = await buttonFixture()
|
|
584
|
+
const closingSpy = sinon.spy()
|
|
585
|
+
const closeSpy = sinon.spy()
|
|
586
|
+
|
|
587
|
+
element.addEventListener('closing', (event) => {
|
|
588
|
+
closingSpy()
|
|
589
|
+
event.preventDefault() // Cancel the closing
|
|
590
|
+
})
|
|
591
|
+
element.addEventListener('close', closeSpy)
|
|
592
|
+
|
|
593
|
+
element.open = true
|
|
594
|
+
await element.updateComplete
|
|
595
|
+
assert.isTrue(element.open, 'dialog is initially open')
|
|
596
|
+
|
|
597
|
+
const button = element.querySelector('ui-button')!
|
|
598
|
+
button.focus()
|
|
599
|
+
await UiMock.keyPress(element, 'Escape', { key: 'Escape' })
|
|
600
|
+
|
|
601
|
+
assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched')
|
|
602
|
+
assert.isFalse(closeSpy.called, 'close event was not dispatched')
|
|
603
|
+
assert.isTrue(element.open, 'dialog remains open when closing is prevented')
|
|
604
|
+
})
|
|
605
|
+
|
|
606
|
+
it('prevents native dialog close and reopens when closing event is cancelled', async () => {
|
|
607
|
+
const element = await modalFixture()
|
|
608
|
+
const closingSpy = sinon.spy()
|
|
609
|
+
const showModalSpy = sinon.spy(element.dialog, 'showModal')
|
|
610
|
+
|
|
611
|
+
element.addEventListener('closing', (event) => {
|
|
612
|
+
closingSpy()
|
|
613
|
+
event.preventDefault() // Cancel the closing
|
|
614
|
+
})
|
|
615
|
+
|
|
616
|
+
element.open = true
|
|
617
|
+
await element.updateComplete
|
|
618
|
+
assert.isTrue(element.open, 'dialog is initially open')
|
|
619
|
+
assert.isTrue(element.dialog.open, 'native dialog is open')
|
|
620
|
+
|
|
621
|
+
// Reset the spy count after initial open
|
|
622
|
+
showModalSpy.resetHistory()
|
|
623
|
+
|
|
624
|
+
// Simulate native dialog close event (e.g., clicking backdrop)
|
|
625
|
+
element.dialog.dispatchEvent(new Event('close'))
|
|
626
|
+
|
|
627
|
+
assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched')
|
|
628
|
+
assert.isTrue(element.open, 'dialog remains open when closing is prevented')
|
|
629
|
+
assert.isTrue(showModalSpy.calledOnce, 'showModal was called to reopen the dialog')
|
|
630
|
+
})
|
|
631
|
+
|
|
632
|
+
it('verifies closing event properties', async () => {
|
|
633
|
+
const element = await buttonFixture()
|
|
634
|
+
let closingEvent: CustomEvent<UiDialogClosingReason>
|
|
635
|
+
|
|
636
|
+
element.addEventListener('closing', (event) => {
|
|
637
|
+
closingEvent = event as CustomEvent<UiDialogClosingReason>
|
|
638
|
+
})
|
|
639
|
+
|
|
640
|
+
const button = element.querySelector('ui-button[value="dismiss"]') as UiButton
|
|
641
|
+
button.click()
|
|
642
|
+
|
|
643
|
+
assert.isDefined(closingEvent!, 'closing event was dispatched')
|
|
644
|
+
assert.isTrue(closingEvent!.cancelable, 'closing event is cancelable')
|
|
645
|
+
assert.isFalse(closingEvent!.bubbles, 'closing event does not bubble')
|
|
646
|
+
assert.isFalse(closingEvent!.composed, 'closing event is not composed')
|
|
647
|
+
assert.equal(closingEvent!.type, 'closing', 'event type is "closing"')
|
|
648
|
+
})
|
|
649
|
+
|
|
650
|
+
it('works with imperative dismiss and confirm buttons', async () => {
|
|
651
|
+
const element = await basicFixture()
|
|
652
|
+
element.dismissLabel = 'Cancel'
|
|
653
|
+
element.confirmLabel = 'OK'
|
|
654
|
+
await element.updateComplete
|
|
655
|
+
|
|
656
|
+
const closingSpy = sinon.spy()
|
|
657
|
+
const closeSpy = sinon.spy()
|
|
658
|
+
element.addEventListener('closing', closingSpy)
|
|
659
|
+
element.addEventListener('close', closeSpy)
|
|
660
|
+
|
|
661
|
+
// Test dismiss button
|
|
662
|
+
const dismissButton = element.shadowRoot!.querySelector('.internal-button[value="dismiss"]') as UiButton
|
|
663
|
+
dismissButton.click()
|
|
664
|
+
|
|
665
|
+
assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched for dismiss')
|
|
666
|
+
assert.isTrue(closeSpy.calledOnce, 'close event was dispatched for dismiss')
|
|
667
|
+
|
|
668
|
+
// Reset spies and test confirm button
|
|
669
|
+
closingSpy.resetHistory()
|
|
670
|
+
closeSpy.resetHistory()
|
|
671
|
+
element.open = true
|
|
672
|
+
await element.updateComplete
|
|
673
|
+
|
|
674
|
+
const confirmButton = element.shadowRoot!.querySelector('.internal-button[value="confirm"]') as UiButton
|
|
675
|
+
confirmButton.click()
|
|
676
|
+
|
|
677
|
+
assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched for confirm')
|
|
678
|
+
assert.isTrue(closeSpy.calledOnce, 'close event was dispatched for confirm')
|
|
679
|
+
})
|
|
680
|
+
|
|
681
|
+
it('can prevent closing with imperative buttons', async () => {
|
|
682
|
+
const element = await basicFixture()
|
|
683
|
+
element.dismissLabel = 'Cancel'
|
|
684
|
+
await element.updateComplete
|
|
685
|
+
|
|
686
|
+
const closingSpy = sinon.spy()
|
|
687
|
+
const closeSpy = sinon.spy()
|
|
688
|
+
|
|
689
|
+
element.addEventListener('closing', (event) => {
|
|
690
|
+
closingSpy()
|
|
691
|
+
event.preventDefault()
|
|
692
|
+
})
|
|
693
|
+
element.addEventListener('close', closeSpy)
|
|
694
|
+
|
|
695
|
+
element.open = true
|
|
696
|
+
await element.updateComplete
|
|
697
|
+
|
|
698
|
+
const dismissButton = element.shadowRoot!.querySelector('.internal-button[value="dismiss"]') as UiButton
|
|
699
|
+
dismissButton.click()
|
|
700
|
+
|
|
701
|
+
assert.isTrue(closingSpy.calledOnce, 'closing event was dispatched')
|
|
702
|
+
assert.isFalse(closeSpy.called, 'close event was not dispatched')
|
|
703
|
+
assert.isTrue(element.open, 'dialog remains open')
|
|
704
|
+
})
|
|
705
|
+
})
|
|
706
|
+
|
|
707
|
+
describe('accessibility', () => {
|
|
708
|
+
it('meets accessibility standards in closed state', async () => {
|
|
709
|
+
const element = await basicFixture()
|
|
710
|
+
await assert.isAccessible(element)
|
|
711
|
+
})
|
|
712
|
+
|
|
713
|
+
it('meets accessibility standards when open', async () => {
|
|
714
|
+
const element = await basicFixture()
|
|
715
|
+
element.open = true
|
|
716
|
+
await element.updateComplete
|
|
717
|
+
await assert.isAccessible(element)
|
|
718
|
+
})
|
|
719
|
+
|
|
720
|
+
it('meets accessibility standards with modal dialog', async () => {
|
|
721
|
+
const element = await modalFixture()
|
|
722
|
+
element.open = true
|
|
723
|
+
await element.updateComplete
|
|
724
|
+
await assert.isAccessible(element)
|
|
725
|
+
})
|
|
726
|
+
|
|
727
|
+
it('meets accessibility standards with full content', async () => {
|
|
728
|
+
const element: UiDialog = await fixture(html`
|
|
729
|
+
<ui-dialog modal open>
|
|
730
|
+
<ui-icon slot="icon" icon="deleteOutline"></ui-icon>
|
|
731
|
+
<span slot="title">Delete confirmation</span>
|
|
732
|
+
<p>Are you sure you want to delete this item?</p>
|
|
733
|
+
<ui-button color="text" slot="button" value="dismiss">Cancel</ui-button>
|
|
734
|
+
<ui-button color="text" slot="button" value="confirm">Delete</ui-button>
|
|
735
|
+
</ui-dialog>
|
|
736
|
+
`)
|
|
737
|
+
await element.updateComplete
|
|
738
|
+
await assert.isAccessible(element)
|
|
739
|
+
})
|
|
740
|
+
|
|
741
|
+
it('maintains accessibility when closing is prevented', async () => {
|
|
742
|
+
const element = await buttonFixture()
|
|
743
|
+
element.addEventListener('closing', (event) => {
|
|
744
|
+
event.preventDefault()
|
|
745
|
+
})
|
|
746
|
+
|
|
747
|
+
element.open = true
|
|
748
|
+
await element.updateComplete
|
|
749
|
+
|
|
750
|
+
const button = element.querySelector('ui-button[value="dismiss"]') as UiButton
|
|
751
|
+
button.click()
|
|
752
|
+
|
|
753
|
+
// Dialog should remain open and accessible
|
|
754
|
+
assert.isTrue(element.open, 'dialog remains open')
|
|
755
|
+
await assert.isAccessible(element)
|
|
756
|
+
})
|
|
757
|
+
})
|
|
444
758
|
})
|
|
445
759
|
})
|