@api-client/ui 0.5.3 → 0.5.5
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/md/dialog/internals/ConfirmDialog.d.ts +39 -0
- package/build/src/md/dialog/internals/ConfirmDialog.d.ts.map +1 -0
- package/build/src/md/dialog/internals/ConfirmDialog.js +75 -0
- package/build/src/md/dialog/internals/ConfirmDialog.js.map +1 -0
- package/build/src/md/dialog/internals/Dialog.d.ts +6 -0
- package/build/src/md/dialog/internals/Dialog.d.ts.map +1 -1
- package/build/src/md/dialog/internals/Dialog.js +43 -5
- package/build/src/md/dialog/internals/Dialog.js.map +1 -1
- package/build/src/md/dialog/internals/Dialog.styles.d.ts.map +1 -1
- package/build/src/md/dialog/internals/Dialog.styles.js +40 -1
- package/build/src/md/dialog/internals/Dialog.styles.js.map +1 -1
- package/build/src/md/dialog/ui-confirm-dialog.d.ts +48 -0
- package/build/src/md/dialog/ui-confirm-dialog.d.ts.map +1 -0
- package/build/src/md/dialog/ui-confirm-dialog.js +64 -0
- package/build/src/md/dialog/ui-confirm-dialog.js.map +1 -0
- package/demo/md/dialog/confirm-dialog.html +49 -0
- package/demo/md/dialog/confirm-dialog.ts +121 -0
- package/demo/md/dialog/dialog.ts +76 -1
- package/demo/md/index.html +2 -0
- package/package.json +1 -1
- package/src/md/dialog/README.md +212 -0
- package/src/md/dialog/internals/ConfirmDialog.ts +79 -0
- package/src/md/dialog/internals/Dialog.styles.ts +40 -1
- package/src/md/dialog/internals/Dialog.ts +17 -4
- package/src/md/dialog/ui-confirm-dialog.ts +52 -0
- package/test/README.md +2 -0
- package/test/md/dialog/UiConfirmDialog.test.ts +131 -0
- package/test/md/dialog/UiDialog.test.ts +42 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en-GB">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<title>UI Confirm Dialog Demo</title>
|
|
6
|
+
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, minimum-scale=1.0">
|
|
7
|
+
<link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel="stylesheet">
|
|
8
|
+
<link href="../../../src/styles/m3/tokens.css" rel="stylesheet" type="text/css" />
|
|
9
|
+
<link href="../../../src/styles/m3/theme.css" rel="stylesheet" type="text/css" />
|
|
10
|
+
<style>
|
|
11
|
+
.demo-section {
|
|
12
|
+
margin: 40px 0;
|
|
13
|
+
padding: 24px;
|
|
14
|
+
border: 1px solid var(--md-sys-color-outline);
|
|
15
|
+
border-radius: 8px;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.demo-section h2 {
|
|
19
|
+
margin-top: 0;
|
|
20
|
+
color: var(--md-sys-color-on-surface);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.demo-section p {
|
|
24
|
+
margin-bottom: 20px;
|
|
25
|
+
color: var(--md-sys-color-on-surface-variant);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.button-group {
|
|
29
|
+
display: flex;
|
|
30
|
+
gap: 12px;
|
|
31
|
+
flex-wrap: wrap;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.result {
|
|
35
|
+
margin-top: 20px;
|
|
36
|
+
padding: 12px;
|
|
37
|
+
background: var(--md-sys-color-surface-variant);
|
|
38
|
+
border-radius: 4px;
|
|
39
|
+
font-family: monospace;
|
|
40
|
+
color: var(--md-sys-color-on-surface-variant);
|
|
41
|
+
}
|
|
42
|
+
</style>
|
|
43
|
+
</head>
|
|
44
|
+
<body>
|
|
45
|
+
<div id="app"></div>
|
|
46
|
+
|
|
47
|
+
<script type="module" src="/.tmp/demo/md/dialog/confirm-dialog.js"></script>
|
|
48
|
+
</body>
|
|
49
|
+
</html>
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { html, TemplateResult } from 'lit'
|
|
2
|
+
import { DemoPage } from '../../../src/demo/DemoPage.js'
|
|
3
|
+
import { UiDialogClosingReason } from '../../../src/md/dialog/internals/Dialog.js'
|
|
4
|
+
import { reactive } from '../../../src/decorators/index.js'
|
|
5
|
+
import '../../../src/md/dialog/ui-confirm-dialog.js'
|
|
6
|
+
import '../../../src/md/button/ui-button.js'
|
|
7
|
+
|
|
8
|
+
class ConfirmDialogDemo extends DemoPage {
|
|
9
|
+
override accessor componentName = 'UI Confirm Dialog'
|
|
10
|
+
|
|
11
|
+
@reactive() accessor basicDialogOpen = false
|
|
12
|
+
|
|
13
|
+
@reactive() accessor deleteDialogOpen = false
|
|
14
|
+
|
|
15
|
+
@reactive() accessor customDialogOpen = false
|
|
16
|
+
|
|
17
|
+
@reactive() accessor lastResult = ''
|
|
18
|
+
|
|
19
|
+
protected openBasicDialog(): void {
|
|
20
|
+
this.basicDialogOpen = true
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
protected openDeleteDialog(): void {
|
|
24
|
+
this.deleteDialogOpen = true
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
protected openCustomDialog(): void {
|
|
28
|
+
this.customDialogOpen = true
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
protected handleBasicClose(e: CustomEvent<UiDialogClosingReason>): void {
|
|
32
|
+
this.basicDialogOpen = false
|
|
33
|
+
this.updateResult('Basic Dialog', e.detail)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
protected handleDeleteClose(e: CustomEvent<UiDialogClosingReason>): void {
|
|
37
|
+
this.deleteDialogOpen = false
|
|
38
|
+
this.updateResult('Delete Dialog', e.detail)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
protected handleCustomClose(e: CustomEvent<UiDialogClosingReason>): void {
|
|
42
|
+
this.customDialogOpen = false
|
|
43
|
+
this.updateResult('Custom Dialog', e.detail)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private updateResult(dialogType: string, detail: UiDialogClosingReason): void {
|
|
47
|
+
const action = detail.cancelled ? 'dismissed' : 'confirmed'
|
|
48
|
+
this.lastResult = `${dialogType} was ${action}`
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
contentTemplate(): TemplateResult {
|
|
52
|
+
return html`
|
|
53
|
+
<a href="../">Back</a>
|
|
54
|
+
<h1>Confirm Dialog Demo</h1>
|
|
55
|
+
|
|
56
|
+
<section class="demo-section">
|
|
57
|
+
<h2>Basic Confirm Dialog</h2>
|
|
58
|
+
<p>A simple confirmation dialog with default button labels.</p>
|
|
59
|
+
<div class="button-group">
|
|
60
|
+
<ui-button color="filled" @click="${this.openBasicDialog}">Open Basic Dialog</ui-button>
|
|
61
|
+
</div>
|
|
62
|
+
|
|
63
|
+
<ui-confirm-dialog .open="${this.basicDialogOpen}" @close="${this.handleBasicClose}">
|
|
64
|
+
<span slot="title">Confirm Action</span>
|
|
65
|
+
<p>Are you sure you want to proceed with this action?</p>
|
|
66
|
+
</ui-confirm-dialog>
|
|
67
|
+
</section>
|
|
68
|
+
|
|
69
|
+
<section class="demo-section">
|
|
70
|
+
<h2>Delete Confirmation Dialog</h2>
|
|
71
|
+
<p>A confirmation dialog with custom button labels for a destructive action.</p>
|
|
72
|
+
<div class="button-group">
|
|
73
|
+
<ui-button color="filled" @click="${this.openDeleteDialog}">Delete Item</ui-button>
|
|
74
|
+
</div>
|
|
75
|
+
|
|
76
|
+
<ui-confirm-dialog
|
|
77
|
+
confirmLabel="Delete"
|
|
78
|
+
dismissLabel="Keep"
|
|
79
|
+
destructive
|
|
80
|
+
.open="${this.deleteDialogOpen}"
|
|
81
|
+
@close="${this.handleDeleteClose}"
|
|
82
|
+
>
|
|
83
|
+
<span slot="title">Delete Item</span>
|
|
84
|
+
<p>Are you sure you want to delete this item? This action cannot be undone.</p>
|
|
85
|
+
<p><strong>This will permanently remove the item from your account.</strong></p>
|
|
86
|
+
</ui-confirm-dialog>
|
|
87
|
+
</section>
|
|
88
|
+
|
|
89
|
+
<section class="demo-section">
|
|
90
|
+
<h2>Custom Styled Dialog</h2>
|
|
91
|
+
<p>A confirmation dialog with custom button labels for a specific workflow.</p>
|
|
92
|
+
<div class="button-group">
|
|
93
|
+
<ui-button color="filled" @click="${this.openCustomDialog}">Save & Exit</ui-button>
|
|
94
|
+
</div>
|
|
95
|
+
|
|
96
|
+
<ui-confirm-dialog
|
|
97
|
+
confirmLabel="Save & Exit"
|
|
98
|
+
dismissLabel="Continue Editing"
|
|
99
|
+
.open="${this.customDialogOpen}"
|
|
100
|
+
@close="${this.handleCustomClose}"
|
|
101
|
+
>
|
|
102
|
+
<span slot="title">Save Changes</span>
|
|
103
|
+
<p>You have unsaved changes in your document.</p>
|
|
104
|
+
<p>Would you like to save your changes before exiting?</p>
|
|
105
|
+
</ui-confirm-dialog>
|
|
106
|
+
</section>
|
|
107
|
+
|
|
108
|
+
${this.lastResult
|
|
109
|
+
? html`
|
|
110
|
+
<section class="demo-section">
|
|
111
|
+
<h2>Last Action Result</h2>
|
|
112
|
+
<div class="result">${this.lastResult}</div>
|
|
113
|
+
</section>
|
|
114
|
+
`
|
|
115
|
+
: ''}
|
|
116
|
+
`
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const instance = new ConfirmDialogDemo()
|
|
121
|
+
instance.render()
|
package/demo/md/dialog/dialog.ts
CHANGED
|
@@ -20,6 +20,10 @@ class ComponentDemoPage extends DemoPage {
|
|
|
20
20
|
|
|
21
21
|
@reactive() accessor formOpened = false
|
|
22
22
|
|
|
23
|
+
@reactive() accessor destructiveOpened = false
|
|
24
|
+
|
|
25
|
+
@reactive() accessor nonModalOpened = false
|
|
26
|
+
|
|
23
27
|
protected openSimple(): void {
|
|
24
28
|
this.simpleOpened = true
|
|
25
29
|
}
|
|
@@ -56,6 +60,24 @@ class ComponentDemoPage extends DemoPage {
|
|
|
56
60
|
this.reportClosingReason(e.detail)
|
|
57
61
|
}
|
|
58
62
|
|
|
63
|
+
protected openDestructive(): void {
|
|
64
|
+
this.destructiveOpened = true
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
protected destructiveClosed(e: CustomEvent<UiDialogClosingReason>): void {
|
|
68
|
+
this.destructiveOpened = false
|
|
69
|
+
this.reportClosingReason(e.detail)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
protected openNonModal(): void {
|
|
73
|
+
this.nonModalOpened = true
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
protected nonModalClosed(e: CustomEvent<UiDialogClosingReason>): void {
|
|
77
|
+
this.nonModalOpened = false
|
|
78
|
+
this.reportClosingReason(e.detail)
|
|
79
|
+
}
|
|
80
|
+
|
|
59
81
|
imperativeDialog: UiDialog | null = null
|
|
60
82
|
|
|
61
83
|
protected openImperative(): void {
|
|
@@ -72,6 +94,7 @@ class ComponentDemoPage extends DemoPage {
|
|
|
72
94
|
this.imperativeDialog = dialog
|
|
73
95
|
dialog.addEventListener('close', (e: Event): void => {
|
|
74
96
|
document.body.removeChild(dialog)
|
|
97
|
+
this.imperativeDialog = null
|
|
75
98
|
const event = e as CustomEvent<UiDialogClosingReason>
|
|
76
99
|
this.reportClosingReason(event.detail)
|
|
77
100
|
})
|
|
@@ -93,7 +116,7 @@ class ComponentDemoPage extends DemoPage {
|
|
|
93
116
|
return html`
|
|
94
117
|
<a href="../">Back</a>
|
|
95
118
|
${this.simpleDialog()} ${this.fullDialog()} ${this.overflowDialog()} ${this.formDialog()}
|
|
96
|
-
${this.renderImperativeDialog()}
|
|
119
|
+
${this.destructiveDialog()} ${this.nonModalDialog()} ${this.renderImperativeDialog()}
|
|
97
120
|
`
|
|
98
121
|
}
|
|
99
122
|
|
|
@@ -387,6 +410,58 @@ class ComponentDemoPage extends DemoPage {
|
|
|
387
410
|
</section>
|
|
388
411
|
`
|
|
389
412
|
}
|
|
413
|
+
|
|
414
|
+
destructiveDialog(): TemplateResult {
|
|
415
|
+
return html`
|
|
416
|
+
<section class="demo-section">
|
|
417
|
+
<h2 class="title-large">Destructive dialog</h2>
|
|
418
|
+
<p>This dialog demonstrates the destructive attribute for dangerous actions.</p>
|
|
419
|
+
<ui-button color="filled" @click="${this.openDestructive}">Open destructive dialog</ui-button>
|
|
420
|
+
<ui-dialog
|
|
421
|
+
?open="${this.destructiveOpened}"
|
|
422
|
+
@close="${this.destructiveClosed}"
|
|
423
|
+
modal
|
|
424
|
+
confirmLabel="Delete"
|
|
425
|
+
dismissLabel="Cancel"
|
|
426
|
+
destructive
|
|
427
|
+
>
|
|
428
|
+
<ui-icon slot="icon" icon="warning"></ui-icon>
|
|
429
|
+
<span slot="title">Delete Account</span>
|
|
430
|
+
<p>
|
|
431
|
+
Are you sure you want to permanently delete your account? This action cannot be undone and all your data
|
|
432
|
+
will be lost.
|
|
433
|
+
</p>
|
|
434
|
+
</ui-dialog>
|
|
435
|
+
</section>
|
|
436
|
+
`
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
nonModalDialog(): TemplateResult {
|
|
440
|
+
return html`
|
|
441
|
+
<section class="demo-section">
|
|
442
|
+
<h2 class="title-large">Non-modal dialog</h2>
|
|
443
|
+
<p>This dialog demonstrates a non-modal dialog that is centered in the viewport.</p>
|
|
444
|
+
<ui-button color="filled" @click="${this.openNonModal}">Open non-modal dialog</ui-button>
|
|
445
|
+
<ui-dialog
|
|
446
|
+
?open="${this.nonModalOpened}"
|
|
447
|
+
@close="${this.nonModalClosed}"
|
|
448
|
+
confirmLabel="Got it"
|
|
449
|
+
dismissLabel="Close"
|
|
450
|
+
>
|
|
451
|
+
<ui-icon slot="icon" icon="info"></ui-icon>
|
|
452
|
+
<span slot="title">Non-Modal Information</span>
|
|
453
|
+
<p>
|
|
454
|
+
This is a non-modal dialog. Unlike modal dialogs, you can still interact with the content behind this
|
|
455
|
+
dialog. The dialog is automatically centered in the viewport and maintains the smooth opening animation.
|
|
456
|
+
</p>
|
|
457
|
+
<p>
|
|
458
|
+
Non-modal dialogs are useful for displaying information that doesn't require the user's full attention or
|
|
459
|
+
when you want to allow interaction with the background content.
|
|
460
|
+
</p>
|
|
461
|
+
</ui-dialog>
|
|
462
|
+
</section>
|
|
463
|
+
`
|
|
464
|
+
}
|
|
390
465
|
}
|
|
391
466
|
|
|
392
467
|
const instance = new ComponentDemoPage()
|
package/demo/md/index.html
CHANGED
|
@@ -31,6 +31,8 @@
|
|
|
31
31
|
<dd>An animated collapse element.</dd>
|
|
32
32
|
<dt><a href="dialog/dialog.html">dialog</a></dt>
|
|
33
33
|
<dd>A Material 3 dialog element.</dd>
|
|
34
|
+
<dt><a href="dialog/confirm-dialog.html">confirm-dialog</a></dt>
|
|
35
|
+
<dd>A Material 3 confirm-dialog element.</dd>
|
|
34
36
|
<dt><a href="dropdown-list/index.html">dropdown-list</a></dt>
|
|
35
37
|
<dd>A Material 3 dropdown-list.</dd>
|
|
36
38
|
<dt><a href="icon-button/index.html">icon-button</a></dt>
|
package/package.json
CHANGED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# UI Confirm Dialog
|
|
2
|
+
|
|
3
|
+
A simple Material Design 3 styled | Property | Type | Default | Description |
|
|
4
|
+
|----------|------|---------|-------------|
|
|
5
|
+
| `open` | `boolean` | `false` | Controls dialog visibility |
|
|
6
|
+
| `modal` | `boolean` | `true` | Whether dialog is modal (set by default) |
|
|
7
|
+
| `confirmLabel` | `string` | `'Confirm'` | Text for the confirm button |
|
|
8
|
+
| `dismissLabel` | `string` | `'Cancel'` | Text for the dismiss button |
|
|
9
|
+
| `destructive` | `boolean` | `false` | Styles confirm button with error colors for destructive actions |m dialog component for confirming user actions.
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **Material Design 3 Styling**: Follows MD3 design tokens and patterns
|
|
14
|
+
- **Customizable Button Labels**: Configure confirm and dismiss button text
|
|
15
|
+
- **Slot-based Content**: Flexible content structure with title and body slots
|
|
16
|
+
- **Modal by Default**: Designed for confirmation workflows
|
|
17
|
+
- **Accessible**: Supports keyboard navigation and screen readers
|
|
18
|
+
- **Built-in Event Handling**: Dispatches close events with detailed reason information
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
### Basic Usage
|
|
23
|
+
|
|
24
|
+
```html
|
|
25
|
+
<ui-confirm-dialog .open="${showDialog}" @close="${handleClose}">
|
|
26
|
+
<span slot="title">Confirm Action</span>
|
|
27
|
+
<p>Are you sure you want to proceed with this action?</p>
|
|
28
|
+
</ui-confirm-dialog>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Custom Button Labels
|
|
32
|
+
|
|
33
|
+
```html
|
|
34
|
+
<ui-confirm-dialog
|
|
35
|
+
confirmLabel="Delete"
|
|
36
|
+
dismissLabel="Keep"
|
|
37
|
+
destructive
|
|
38
|
+
.open="${showDialog}"
|
|
39
|
+
@close="${handleClose}"
|
|
40
|
+
>
|
|
41
|
+
<span slot="title">Delete Item</span>
|
|
42
|
+
<p>Are you sure you want to delete this item? This action cannot be undone.</p>
|
|
43
|
+
</ui-confirm-dialog>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Event Handling
|
|
47
|
+
|
|
48
|
+
```javascript
|
|
49
|
+
function handleClose(e) {
|
|
50
|
+
const { cancelled, value } = e.detail;
|
|
51
|
+
if (!cancelled) {
|
|
52
|
+
// User confirmed the action
|
|
53
|
+
performAction();
|
|
54
|
+
} else {
|
|
55
|
+
// User dismissed the dialog
|
|
56
|
+
console.log('Action cancelled');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Properties
|
|
62
|
+
|
|
63
|
+
| Property | Type | Default | Description |
|
|
64
|
+
|----------|------|---------|-------------|
|
|
65
|
+
| `open` | `boolean` | `false` | Controls dialog visibility |
|
|
66
|
+
| `modal` | `boolean` | `true` | Whether dialog is modal (set by default) |
|
|
67
|
+
| `confirmLabel` | `string` | `'Confirm'` | Text for the confirm button |
|
|
68
|
+
| `dismissLabel` | `string` | `'Cancel'` | Text for the dismiss button |
|
|
69
|
+
|
|
70
|
+
## Slots
|
|
71
|
+
|
|
72
|
+
| Slot | Description |
|
|
73
|
+
|------|-------------|
|
|
74
|
+
| `title` | Dialog title content |
|
|
75
|
+
| (default) | Main body content |
|
|
76
|
+
|
|
77
|
+
## Events
|
|
78
|
+
|
|
79
|
+
| Event | Detail Type | Description |
|
|
80
|
+
|-------|-------------|-------------|
|
|
81
|
+
| `close` | `UiDialogClosingReason` | Fired when dialog is closed |
|
|
82
|
+
|
|
83
|
+
### UiDialogClosingReason
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
interface UiDialogClosingReason {
|
|
87
|
+
cancelled: boolean; // true if dismissed, false if confirmed
|
|
88
|
+
value?: unknown; // optional value associated with the action
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Styling
|
|
93
|
+
|
|
94
|
+
The component uses Material Design 3 design tokens and can be styled using CSS custom properties:
|
|
95
|
+
|
|
96
|
+
```css
|
|
97
|
+
ui-confirm-dialog {
|
|
98
|
+
--ui-dialog-max-width: 400px;
|
|
99
|
+
--ui-dialog-max-height: 300px;
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Design Patterns
|
|
104
|
+
|
|
105
|
+
### Confirmation Workflows
|
|
106
|
+
|
|
107
|
+
Use this dialog when you need users to explicitly confirm an action:
|
|
108
|
+
|
|
109
|
+
- Deleting items
|
|
110
|
+
- Saving changes
|
|
111
|
+
- Leaving unsaved work
|
|
112
|
+
- Performing destructive actions
|
|
113
|
+
|
|
114
|
+
### Button Styling
|
|
115
|
+
|
|
116
|
+
The component follows Material Design patterns:
|
|
117
|
+
|
|
118
|
+
- **Dismiss button**: Text style (lower emphasis)
|
|
119
|
+
- **Confirm button**: Filled style (higher emphasis)
|
|
120
|
+
|
|
121
|
+
### Content Guidelines
|
|
122
|
+
|
|
123
|
+
- **Title**: Keep concise, use action-oriented language
|
|
124
|
+
- **Body**: Explain the consequence of the action
|
|
125
|
+
- **Button Labels**: Use specific, clear language
|
|
126
|
+
|
|
127
|
+
## Examples
|
|
128
|
+
|
|
129
|
+
### Delete Confirmation
|
|
130
|
+
|
|
131
|
+
```html
|
|
132
|
+
<ui-confirm-dialog
|
|
133
|
+
confirmLabel="Delete"
|
|
134
|
+
dismissLabel="Keep"
|
|
135
|
+
destructive
|
|
136
|
+
.open="${showDelete}"
|
|
137
|
+
>
|
|
138
|
+
<span slot="title">Delete Item</span>
|
|
139
|
+
<p>Are you sure you want to delete this item?</p>
|
|
140
|
+
<p><strong>This action cannot be undone.</strong></p>
|
|
141
|
+
</ui-confirm-dialog>
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Save Changes
|
|
145
|
+
|
|
146
|
+
```html
|
|
147
|
+
<ui-confirm-dialog
|
|
148
|
+
confirmLabel="Save & Exit"
|
|
149
|
+
dismissLabel="Continue Editing"
|
|
150
|
+
.open="${showSave}"
|
|
151
|
+
>
|
|
152
|
+
<span slot="title">Save Changes</span>
|
|
153
|
+
<p>You have unsaved changes in your document.</p>
|
|
154
|
+
<p>Would you like to save your changes before exiting?</p>
|
|
155
|
+
</ui-confirm-dialog>
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Logout Confirmation
|
|
159
|
+
|
|
160
|
+
```html
|
|
161
|
+
<ui-confirm-dialog
|
|
162
|
+
confirmLabel="Logout"
|
|
163
|
+
dismissLabel="Stay Logged In"
|
|
164
|
+
.open="${showLogout}"
|
|
165
|
+
>
|
|
166
|
+
<span slot="title">Logout</span>
|
|
167
|
+
<p>Are you sure you want to logout?</p>
|
|
168
|
+
</ui-confirm-dialog>
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Destructive Actions
|
|
172
|
+
|
|
173
|
+
Use the `destructive` attribute for actions that are permanent or could cause data loss:
|
|
174
|
+
|
|
175
|
+
- Deleting items
|
|
176
|
+
- Removing users
|
|
177
|
+
- Clearing data
|
|
178
|
+
- Resetting settings
|
|
179
|
+
|
|
180
|
+
The destructive styling uses Material Design error colors to provide clear visual feedback that the action is potentially harmful.
|
|
181
|
+
|
|
182
|
+
```html
|
|
183
|
+
<ui-confirm-dialog
|
|
184
|
+
confirmLabel="Delete Account"
|
|
185
|
+
dismissLabel="Cancel"
|
|
186
|
+
destructive
|
|
187
|
+
.open="${showDeleteAccount}"
|
|
188
|
+
>
|
|
189
|
+
<span slot="title">Delete Account</span>
|
|
190
|
+
<p>This will permanently delete your account and all associated data.</p>
|
|
191
|
+
<p><strong>This action cannot be undone.</strong></p>
|
|
192
|
+
</ui-confirm-dialog>
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Accessibility
|
|
196
|
+
|
|
197
|
+
The component includes:
|
|
198
|
+
|
|
199
|
+
- Proper ARIA attributes
|
|
200
|
+
- Keyboard navigation support (ESC to dismiss)
|
|
201
|
+
- Focus management
|
|
202
|
+
- Screen reader compatibility
|
|
203
|
+
|
|
204
|
+
## Integration
|
|
205
|
+
|
|
206
|
+
To use in your project:
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
import '../path/to/ui-confirm-dialog.js';
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
The component is available as `<ui-confirm-dialog>` in your HTML templates.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { TemplateResult, html } from 'lit'
|
|
2
|
+
import { ClassInfo, classMap } from 'lit/directives/class-map.js'
|
|
3
|
+
import UiDialog from './Dialog.js'
|
|
4
|
+
|
|
5
|
+
import '../../button/ui-button.js'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A simple Material Design 3 styled confirm dialog for confirming user actions.
|
|
9
|
+
*
|
|
10
|
+
* This dialog provides a clean way to ask users to confirm or dismiss an action.
|
|
11
|
+
* It supports customizable button labels and content through slots.
|
|
12
|
+
*
|
|
13
|
+
* **Usage Example:**
|
|
14
|
+
* ```html
|
|
15
|
+
* <ui-confirm-dialog modal .open="${this.showConfirm}" @close="${this.handleConfirmClose}">
|
|
16
|
+
* <span slot="title">Delete Item</span>
|
|
17
|
+
* <p>Are you sure you want to delete this item? This action cannot be undone.</p>
|
|
18
|
+
* </ui-confirm-dialog>
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* **Event Handling:**
|
|
22
|
+
* Listen for the `close` event to handle user interaction:
|
|
23
|
+
* ```javascript
|
|
24
|
+
* dialog.addEventListener('close', (e) => {
|
|
25
|
+
* const { cancelled } = e.detail;
|
|
26
|
+
* if (!cancelled) {
|
|
27
|
+
* // User confirmed the action
|
|
28
|
+
* performAction();
|
|
29
|
+
* }
|
|
30
|
+
* });
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* @slot title - The dialog title content
|
|
34
|
+
* @slot - The main body content of the dialog
|
|
35
|
+
* @fires close - Dispatched when the dialog is closed with closing reason details
|
|
36
|
+
*/
|
|
37
|
+
export default class ConfirmDialog extends UiDialog {
|
|
38
|
+
constructor() {
|
|
39
|
+
super()
|
|
40
|
+
// Set modal by default for confirm dialogs
|
|
41
|
+
this.modal = true
|
|
42
|
+
this.confirmLabel = 'Confirm'
|
|
43
|
+
this.dismissLabel = 'Cancel'
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
protected override renderContent(): TemplateResult[] {
|
|
47
|
+
return [this.renderTitle(), this.renderBody(), this.renderButtons()]
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
protected override renderButtons(): TemplateResult {
|
|
51
|
+
const classes: ClassInfo = {
|
|
52
|
+
'buttons': true,
|
|
53
|
+
'with-buttons': true,
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return html`
|
|
57
|
+
<div class="${classMap(classes)}" part="buttons">
|
|
58
|
+
<ui-button
|
|
59
|
+
color="text"
|
|
60
|
+
value="dismiss"
|
|
61
|
+
class="internal-button"
|
|
62
|
+
@click="${this.handleDismiss}"
|
|
63
|
+
part="dismiss-button"
|
|
64
|
+
>
|
|
65
|
+
${this.dismissLabel}
|
|
66
|
+
</ui-button>
|
|
67
|
+
<ui-button
|
|
68
|
+
color="filled"
|
|
69
|
+
value="confirm"
|
|
70
|
+
class="internal-button ${this.destructive ? 'destructive' : ''}"
|
|
71
|
+
@click="${this.handleConfirm}"
|
|
72
|
+
part="confirm-button"
|
|
73
|
+
>
|
|
74
|
+
${this.confirmLabel}
|
|
75
|
+
</ui-button>
|
|
76
|
+
</div>
|
|
77
|
+
`
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -28,6 +28,20 @@ export default css`
|
|
|
28
28
|
flex-direction: column;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
/* Positioning for non-modal dialogs */
|
|
32
|
+
dialog.non-modal {
|
|
33
|
+
position: fixed;
|
|
34
|
+
top: 50%;
|
|
35
|
+
left: 50%;
|
|
36
|
+
transform: translate(-50%, -50%);
|
|
37
|
+
margin: 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
dialog.non-modal:open {
|
|
41
|
+
/* Override the animation transform for non-modal dialogs to account for centering */
|
|
42
|
+
animation: 250ms cubic-bezier(0.2, 0, 0, 1) show-non-modal-dialog;
|
|
43
|
+
}
|
|
44
|
+
|
|
31
45
|
dialog:open::backdrop {
|
|
32
46
|
animation: 250ms cubic-bezier(0.2, 0, 0, 1) show-backdrop;
|
|
33
47
|
}
|
|
@@ -35,8 +49,8 @@ export default css`
|
|
|
35
49
|
.container {
|
|
36
50
|
display: flex;
|
|
37
51
|
flex-direction: column;
|
|
38
|
-
overflow: hidden;
|
|
39
52
|
flex: 1;
|
|
53
|
+
overflow: hidden;
|
|
40
54
|
}
|
|
41
55
|
|
|
42
56
|
.icon {
|
|
@@ -57,6 +71,11 @@ export default css`
|
|
|
57
71
|
height: 24px;
|
|
58
72
|
}
|
|
59
73
|
|
|
74
|
+
.icon.destructive ::slotted(*) {
|
|
75
|
+
color: var(--md-sys-color-error);
|
|
76
|
+
fill: var(--md-sys-color-error);
|
|
77
|
+
}
|
|
78
|
+
|
|
60
79
|
.title {
|
|
61
80
|
display: none;
|
|
62
81
|
color: var(--md-sys-color-on-surface);
|
|
@@ -114,6 +133,15 @@ export default css`
|
|
|
114
133
|
}
|
|
115
134
|
}
|
|
116
135
|
|
|
136
|
+
@keyframes show-non-modal-dialog {
|
|
137
|
+
from {
|
|
138
|
+
transform: translate(-50%, -50%) translateY(-110%) scaleY(0);
|
|
139
|
+
}
|
|
140
|
+
to {
|
|
141
|
+
transform: translate(-50%, -50%) translateY(0%) scaleY(1);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
117
145
|
@keyframes show-backdrop {
|
|
118
146
|
from {
|
|
119
147
|
opacity: 0;
|
|
@@ -122,4 +150,15 @@ export default css`
|
|
|
122
150
|
opacity: 1;
|
|
123
151
|
}
|
|
124
152
|
}
|
|
153
|
+
|
|
154
|
+
/* Destructive button styling for dangerous actions */
|
|
155
|
+
.internal-button.destructive {
|
|
156
|
+
--_background-color: var(--md-sys-color-error);
|
|
157
|
+
--_color: var(--md-sys-color-on-error);
|
|
158
|
+
|
|
159
|
+
/* Override ripple colors for better interaction feedback */
|
|
160
|
+
--md-ripple-hover-state-layer-color: var(--md-sys-color-on-error);
|
|
161
|
+
--md-ripple-focus-state-layer-color: var(--md-sys-color-on-error);
|
|
162
|
+
--md-ripple-pressed-state-layer-color: var(--md-sys-color-on-error);
|
|
163
|
+
}
|
|
125
164
|
`
|