universal-modal-monorepo 1.0.0
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/AUTHORS +5 -0
- package/CHANGELOG.md +10 -0
- package/LICENSE +21 -0
- package/NOTICE +6 -0
- package/README.md +239 -0
- package/SECURITY.md +21 -0
- package/docs/ACCESSIBILITY.md +43 -0
- package/docs/API.md +56 -0
- package/docs/THEMING.md +65 -0
- package/examples/angular/app.component.html +137 -0
- package/examples/angular/app.component.ts +53 -0
- package/examples/angular/index.html +99 -0
- package/examples/angular/main.js +121 -0
- package/examples/angular/styles.css +25 -0
- package/examples/index.html +53 -0
- package/examples/react/App.tsx +242 -0
- package/examples/react/index.html +26 -0
- package/examples/react/main.js +144 -0
- package/examples/react/styles.css +1 -0
- package/examples/shared/gallery.css +177 -0
- package/examples/vanilla/index.html +89 -0
- package/examples/vanilla/main.js +174 -0
- package/examples/vanilla/styles.css +1 -0
- package/examples/vue/App.vue +190 -0
- package/examples/vue/index.html +23 -0
- package/examples/vue/main.js +174 -0
- package/examples/vue/styles.css +1 -0
- package/examples/web-component/index.html +190 -0
- package/examples/web-component/main.js +58 -0
- package/examples/web-component/styles.css +11 -0
- package/package.json +36 -0
- package/packages/universal-modal/AUTHORS +5 -0
- package/packages/universal-modal/CHANGELOG.md +10 -0
- package/packages/universal-modal/LICENSE +21 -0
- package/packages/universal-modal/NOTICE +6 -0
- package/packages/universal-modal/README.md +29 -0
- package/packages/universal-modal/package.json +83 -0
- package/packages/universal-modal/scripts/copy-styles.mjs +11 -0
- package/packages/universal-modal/src/core/constants.ts +50 -0
- package/packages/universal-modal/src/core/event-emitter.ts +46 -0
- package/packages/universal-modal/src/core/focus-trap.ts +101 -0
- package/packages/universal-modal/src/core/index.ts +39 -0
- package/packages/universal-modal/src/core/modal-engine.ts +410 -0
- package/packages/universal-modal/src/core/modal-stack.ts +68 -0
- package/packages/universal-modal/src/core/scroll-lock.ts +78 -0
- package/packages/universal-modal/src/core/theme.ts +50 -0
- package/packages/universal-modal/src/core/types.ts +196 -0
- package/packages/universal-modal/src/core/utils.ts +114 -0
- package/packages/universal-modal/src/dom/index.ts +1 -0
- package/packages/universal-modal/src/dom/modal-renderer.ts +191 -0
- package/packages/universal-modal/src/index.ts +2 -0
- package/packages/universal-modal/src/styles/modal.css +368 -0
- package/packages/universal-modal/tsconfig.json +24 -0
- package/packages/universal-modal/tsup.config.ts +12 -0
- package/packages/universal-modal-angular/AUTHORS +5 -0
- package/packages/universal-modal-angular/CHANGELOG.md +9 -0
- package/packages/universal-modal-angular/LICENSE +21 -0
- package/packages/universal-modal-angular/NOTICE +6 -0
- package/packages/universal-modal-angular/README.md +12 -0
- package/packages/universal-modal-angular/package.json +85 -0
- package/packages/universal-modal-angular/src/index.ts +10 -0
- package/packages/universal-modal-angular/src/universal-modal.component.ts +275 -0
- package/packages/universal-modal-angular/tsconfig.json +20 -0
- package/packages/universal-modal-angular/tsup.config.ts +10 -0
- package/packages/universal-modal-react/AUTHORS +5 -0
- package/packages/universal-modal-react/CHANGELOG.md +9 -0
- package/packages/universal-modal-react/LICENSE +21 -0
- package/packages/universal-modal-react/NOTICE +6 -0
- package/packages/universal-modal-react/README.md +12 -0
- package/packages/universal-modal-react/package.json +87 -0
- package/packages/universal-modal-react/src/UniversalModal.tsx +340 -0
- package/packages/universal-modal-react/src/index.ts +10 -0
- package/packages/universal-modal-react/tsconfig.json +19 -0
- package/packages/universal-modal-react/tsup.config.ts +13 -0
- package/packages/universal-modal-vanilla/AUTHORS +5 -0
- package/packages/universal-modal-vanilla/CHANGELOG.md +9 -0
- package/packages/universal-modal-vanilla/LICENSE +21 -0
- package/packages/universal-modal-vanilla/NOTICE +6 -0
- package/packages/universal-modal-vanilla/README.md +12 -0
- package/packages/universal-modal-vanilla/package.json +79 -0
- package/packages/universal-modal-vanilla/src/create-modal.ts +125 -0
- package/packages/universal-modal-vanilla/src/index.ts +14 -0
- package/packages/universal-modal-vanilla/tsconfig.json +18 -0
- package/packages/universal-modal-vanilla/tsup.config.ts +10 -0
- package/packages/universal-modal-vue/AUTHORS +5 -0
- package/packages/universal-modal-vue/CHANGELOG.md +9 -0
- package/packages/universal-modal-vue/LICENSE +21 -0
- package/packages/universal-modal-vue/NOTICE +6 -0
- package/packages/universal-modal-vue/README.md +12 -0
- package/packages/universal-modal-vue/package.json +83 -0
- package/packages/universal-modal-vue/src/UniversalModal.ts +342 -0
- package/packages/universal-modal-vue/src/index.ts +10 -0
- package/packages/universal-modal-vue/tsconfig.json +18 -0
- package/packages/universal-modal-vue/tsup.config.ts +10 -0
- package/packages/universal-modal-web-component/AUTHORS +5 -0
- package/packages/universal-modal-web-component/CHANGELOG.md +9 -0
- package/packages/universal-modal-web-component/LICENSE +21 -0
- package/packages/universal-modal-web-component/NOTICE +6 -0
- package/packages/universal-modal-web-component/README.md +12 -0
- package/packages/universal-modal-web-component/package.json +83 -0
- package/packages/universal-modal-web-component/src/index.ts +11 -0
- package/packages/universal-modal-web-component/src/universal-modal-element.ts +424 -0
- package/packages/universal-modal-web-component/tsconfig.json +18 -0
- package/packages/universal-modal-web-component/tsup.config.ts +10 -0
- package/scripts/copy-styles.mjs +11 -0
- package/scripts/serve-examples.mjs +48 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>Universal Modal — Angular samples</title>
|
|
7
|
+
<link rel="stylesheet" href="../../packages/universal-modal/dist/styles.css" />
|
|
8
|
+
<link rel="stylesheet" href="./styles.css" />
|
|
9
|
+
</head>
|
|
10
|
+
<body data-um-theme="light">
|
|
11
|
+
<main class="demo-page">
|
|
12
|
+
<header class="demo-header">
|
|
13
|
+
<p class="demo-kicker">Angular</p>
|
|
14
|
+
<h1>Modal samples</h1>
|
|
15
|
+
<p>
|
|
16
|
+
Interactive demos mirror the Angular standalone component in
|
|
17
|
+
<code>app.component.ts</code> / <code>app.component.html</code>. Copy those files
|
|
18
|
+
into an Angular 16+ app and import
|
|
19
|
+
<code>@poluru-labs/universal-modal-angular</code>.
|
|
20
|
+
</p>
|
|
21
|
+
<nav class="demo-nav" aria-label="Adapters">
|
|
22
|
+
<a href="../index.html">All</a>
|
|
23
|
+
<a href="../vanilla/index.html">Vanilla</a>
|
|
24
|
+
<a href="../web-component/index.html">Web Component</a>
|
|
25
|
+
<a href="../react/index.html">React</a>
|
|
26
|
+
<a href="../vue/index.html">Vue</a>
|
|
27
|
+
<a href="./index.html" aria-current="page">Angular</a>
|
|
28
|
+
</nav>
|
|
29
|
+
</header>
|
|
30
|
+
|
|
31
|
+
<section class="demo-grid">
|
|
32
|
+
<article class="demo-card">
|
|
33
|
+
<h2>1. Archive confirm</h2>
|
|
34
|
+
<p>Alertdialog with async confirm handler.</p>
|
|
35
|
+
<button type="button" class="demo-btn" id="open-archive">Archive workspace</button>
|
|
36
|
+
</article>
|
|
37
|
+
<article class="demo-card">
|
|
38
|
+
<h2>2. Danger delete</h2>
|
|
39
|
+
<p>Custom red confirm theme.</p>
|
|
40
|
+
<button type="button" class="demo-btn" id="open-danger">Delete webhook</button>
|
|
41
|
+
</article>
|
|
42
|
+
<article class="demo-card">
|
|
43
|
+
<h2>3. Right drawer</h2>
|
|
44
|
+
<p>Large form panel.</p>
|
|
45
|
+
<button type="button" class="demo-btn" id="open-drawer">Edit workspace</button>
|
|
46
|
+
</article>
|
|
47
|
+
<article class="demo-card">
|
|
48
|
+
<h2>4. Top notice</h2>
|
|
49
|
+
<p>No footer actions.</p>
|
|
50
|
+
<button type="button" class="demo-btn" id="open-top">Show notice</button>
|
|
51
|
+
</article>
|
|
52
|
+
<article class="demo-card">
|
|
53
|
+
<h2>5. Fullscreen</h2>
|
|
54
|
+
<p>Checklist / walkthrough layout.</p>
|
|
55
|
+
<button type="button" class="demo-btn" id="open-fullscreen">Open checklist</button>
|
|
56
|
+
</article>
|
|
57
|
+
<article class="demo-card">
|
|
58
|
+
<h2>6. Persistent</h2>
|
|
59
|
+
<p>Blocks ESC and backdrop.</p>
|
|
60
|
+
<button type="button" class="demo-btn" id="open-persistent">Accept DPA</button>
|
|
61
|
+
</article>
|
|
62
|
+
<article class="demo-card">
|
|
63
|
+
<h2>7. Brand theme</h2>
|
|
64
|
+
<p>Per-dialog brand override.</p>
|
|
65
|
+
<button type="button" class="demo-btn" id="open-brand">Open branded</button>
|
|
66
|
+
</article>
|
|
67
|
+
</section>
|
|
68
|
+
|
|
69
|
+
<section class="code-note">
|
|
70
|
+
<h2>Angular source in this folder</h2>
|
|
71
|
+
<p class="demo-muted">
|
|
72
|
+
Use <code>app.component.ts</code> + <code>app.component.html</code> inside a real
|
|
73
|
+
Angular application. The live buttons below are powered by the vanilla adapter so
|
|
74
|
+
the gallery stays runnable without the Angular CLI.
|
|
75
|
+
</p>
|
|
76
|
+
<pre>import { UniversalModalComponent } from '@poluru-labs/universal-modal-angular';
|
|
77
|
+
import '@poluru-labs/universal-modal/styles.css';
|
|
78
|
+
|
|
79
|
+
@Component({
|
|
80
|
+
standalone: true,
|
|
81
|
+
imports: [UniversalModalComponent],
|
|
82
|
+
templateUrl: './app.component.html',
|
|
83
|
+
})
|
|
84
|
+
export class AppComponent {
|
|
85
|
+
sample: string | null = null;
|
|
86
|
+
}</pre>
|
|
87
|
+
</section>
|
|
88
|
+
</main>
|
|
89
|
+
|
|
90
|
+
<script type="importmap">
|
|
91
|
+
{
|
|
92
|
+
"imports": {
|
|
93
|
+
"@poluru-labs/universal-modal": "../../packages/universal-modal/dist/index.js"
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
</script>
|
|
97
|
+
<script type="module" src="./main.js"></script>
|
|
98
|
+
</body>
|
|
99
|
+
</html>
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { createModal } from '../../packages/universal-modal-vanilla/dist/index.js';
|
|
2
|
+
|
|
3
|
+
function openSample(factory) {
|
|
4
|
+
const modal = factory();
|
|
5
|
+
modal.on('afterClose', () => modal.destroy());
|
|
6
|
+
void modal.open();
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
document.getElementById('open-archive')?.addEventListener('click', (event) => {
|
|
10
|
+
openSample(() =>
|
|
11
|
+
createModal({
|
|
12
|
+
title: 'Archive workspace?',
|
|
13
|
+
description: 'Members keep read-only access.',
|
|
14
|
+
role: 'alertdialog',
|
|
15
|
+
confirmText: 'Archive',
|
|
16
|
+
body: '<label class="demo-field">Workspace <input value="Poluru Labs" /></label>',
|
|
17
|
+
returnFocus: event.currentTarget,
|
|
18
|
+
onConfirm: async () => {
|
|
19
|
+
await new Promise((r) => setTimeout(r, 700));
|
|
20
|
+
},
|
|
21
|
+
}),
|
|
22
|
+
);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
document.getElementById('open-danger')?.addEventListener('click', (event) => {
|
|
26
|
+
openSample(() =>
|
|
27
|
+
createModal({
|
|
28
|
+
title: 'Delete webhook?',
|
|
29
|
+
body: '<p>Deliveries will stop immediately.</p>',
|
|
30
|
+
role: 'alertdialog',
|
|
31
|
+
confirmText: 'Delete',
|
|
32
|
+
returnFocus: event.currentTarget,
|
|
33
|
+
theme: {
|
|
34
|
+
confirmBg: '#b91c1c',
|
|
35
|
+
confirmFg: '#ffffff',
|
|
36
|
+
confirmBorder: '#b91c1c',
|
|
37
|
+
},
|
|
38
|
+
}),
|
|
39
|
+
);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
document.getElementById('open-drawer')?.addEventListener('click', (event) => {
|
|
43
|
+
openSample(() =>
|
|
44
|
+
createModal({
|
|
45
|
+
title: 'Workspace settings',
|
|
46
|
+
size: 'lg',
|
|
47
|
+
placement: 'right',
|
|
48
|
+
confirmText: 'Save',
|
|
49
|
+
returnFocus: event.currentTarget,
|
|
50
|
+
body: `
|
|
51
|
+
<div class="demo-stack">
|
|
52
|
+
<label class="demo-field">Name <input value="Poluru Labs" /></label>
|
|
53
|
+
<label class="demo-field">Slug <input value="poluru-labs" /></label>
|
|
54
|
+
</div>
|
|
55
|
+
`,
|
|
56
|
+
}),
|
|
57
|
+
);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
document.getElementById('open-top')?.addEventListener('click', (event) => {
|
|
61
|
+
openSample(() =>
|
|
62
|
+
createModal({
|
|
63
|
+
title: 'Deploy in progress',
|
|
64
|
+
placement: 'top',
|
|
65
|
+
hideActions: true,
|
|
66
|
+
body: '<p>You can keep browsing while the pipeline finishes.</p>',
|
|
67
|
+
returnFocus: event.currentTarget,
|
|
68
|
+
}),
|
|
69
|
+
);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
document.getElementById('open-fullscreen')?.addEventListener('click', (event) => {
|
|
73
|
+
openSample(() =>
|
|
74
|
+
createModal({
|
|
75
|
+
title: 'Launch checklist',
|
|
76
|
+
size: 'fullscreen',
|
|
77
|
+
confirmText: 'Mark complete',
|
|
78
|
+
returnFocus: event.currentTarget,
|
|
79
|
+
body: `
|
|
80
|
+
<div class="demo-stack">
|
|
81
|
+
<p>✓ Domain verified</p>
|
|
82
|
+
<p>✓ Billing method added</p>
|
|
83
|
+
<p>✓ First project created</p>
|
|
84
|
+
</div>
|
|
85
|
+
`,
|
|
86
|
+
}),
|
|
87
|
+
);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
document.getElementById('open-persistent')?.addEventListener('click', (event) => {
|
|
91
|
+
openSample(() =>
|
|
92
|
+
createModal({
|
|
93
|
+
title: 'Data processing agreement',
|
|
94
|
+
role: 'alertdialog',
|
|
95
|
+
persistent: true,
|
|
96
|
+
showCloseIcon: false,
|
|
97
|
+
confirmText: 'Accept',
|
|
98
|
+
cancelText: 'Decline',
|
|
99
|
+
body: '<p>Outside dismiss is disabled until you choose an action.</p>',
|
|
100
|
+
returnFocus: event.currentTarget,
|
|
101
|
+
}),
|
|
102
|
+
);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
document.getElementById('open-brand')?.addEventListener('click', (event) => {
|
|
106
|
+
openSample(() =>
|
|
107
|
+
createModal({
|
|
108
|
+
title: 'Branded dialog',
|
|
109
|
+
description: 'theme input maps to CSS variables.',
|
|
110
|
+
confirmText: 'Apply',
|
|
111
|
+
body: '<p>Use this for one-off brand treatments.</p>',
|
|
112
|
+
returnFocus: event.currentTarget,
|
|
113
|
+
theme: {
|
|
114
|
+
brand: '#0d47a1',
|
|
115
|
+
brandForeground: '#ffffff',
|
|
116
|
+
confirmBg: '#0d47a1',
|
|
117
|
+
confirmFg: '#ffffff',
|
|
118
|
+
},
|
|
119
|
+
}),
|
|
120
|
+
);
|
|
121
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
@import url('../shared/gallery.css');
|
|
2
|
+
|
|
3
|
+
.code-note {
|
|
4
|
+
margin-top: 2rem;
|
|
5
|
+
padding: 1.2rem 1.3rem;
|
|
6
|
+
border-radius: 16px;
|
|
7
|
+
border: 1px solid var(--demo-border);
|
|
8
|
+
background: var(--demo-card);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.code-note h2 {
|
|
12
|
+
margin: 0 0 0.5rem;
|
|
13
|
+
font-size: 1.1rem;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.code-note pre {
|
|
17
|
+
margin: 0.75rem 0 0;
|
|
18
|
+
overflow: auto;
|
|
19
|
+
padding: 0.9rem 1rem;
|
|
20
|
+
border-radius: 12px;
|
|
21
|
+
background: #0f172a;
|
|
22
|
+
color: #e2e8f0;
|
|
23
|
+
font-size: 0.82rem;
|
|
24
|
+
line-height: 1.45;
|
|
25
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>Universal Modal — Examples</title>
|
|
7
|
+
<link rel="stylesheet" href="./shared/gallery.css" />
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<main class="demo-page">
|
|
11
|
+
<header class="demo-header">
|
|
12
|
+
<p class="demo-kicker">@poluru-labs/universal-modal</p>
|
|
13
|
+
<h1>Example gallery</h1>
|
|
14
|
+
<p>
|
|
15
|
+
Browse runnable samples for each adapter. Each page includes multiple modal
|
|
16
|
+
variants — confirm, form, drawer, fullscreen, persistent, themed, and nested.
|
|
17
|
+
</p>
|
|
18
|
+
</header>
|
|
19
|
+
|
|
20
|
+
<section class="demo-grid">
|
|
21
|
+
<article class="demo-card">
|
|
22
|
+
<h2>Vanilla JS</h2>
|
|
23
|
+
<p>Imperative <code>createModal</code> / <code>confirmModal</code> samples.</p>
|
|
24
|
+
<a class="demo-btn" href="./vanilla/index.html">Open vanilla demos</a>
|
|
25
|
+
</article>
|
|
26
|
+
|
|
27
|
+
<article class="demo-card">
|
|
28
|
+
<h2>Web Components</h2>
|
|
29
|
+
<p>Declarative <code><universal-modal></code> with slots and nesting.</p>
|
|
30
|
+
<a class="demo-btn" href="./web-component/index.html">Open WC demos</a>
|
|
31
|
+
</article>
|
|
32
|
+
|
|
33
|
+
<article class="demo-card">
|
|
34
|
+
<h2>React</h2>
|
|
35
|
+
<p>Controlled modals with async confirm, drawers, and custom themes.</p>
|
|
36
|
+
<a class="demo-btn" href="./react/index.html">Open React demos</a>
|
|
37
|
+
</article>
|
|
38
|
+
|
|
39
|
+
<article class="demo-card">
|
|
40
|
+
<h2>Vue 3</h2>
|
|
41
|
+
<p><code>v-model:open</code> samples including alertdialog and placement.</p>
|
|
42
|
+
<a class="demo-btn" href="./vue/index.html">Open Vue demos</a>
|
|
43
|
+
</article>
|
|
44
|
+
|
|
45
|
+
<article class="demo-card">
|
|
46
|
+
<h2>Angular</h2>
|
|
47
|
+
<p>Standalone component patterns (source gallery + usage notes).</p>
|
|
48
|
+
<a class="demo-btn" href="./angular/index.html">Open Angular demos</a>
|
|
49
|
+
</article>
|
|
50
|
+
</section>
|
|
51
|
+
</main>
|
|
52
|
+
</body>
|
|
53
|
+
</html>
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import { UniversalModal, type ModalTheme } from '@poluru-labs/universal-modal-react';
|
|
3
|
+
import '@poluru-labs/universal-modal/styles.css';
|
|
4
|
+
import './styles.css';
|
|
5
|
+
|
|
6
|
+
type Sample =
|
|
7
|
+
| 'invite'
|
|
8
|
+
| 'danger'
|
|
9
|
+
| 'drawer'
|
|
10
|
+
| 'top'
|
|
11
|
+
| 'fullscreen'
|
|
12
|
+
| 'persistent'
|
|
13
|
+
| 'brand'
|
|
14
|
+
| null;
|
|
15
|
+
|
|
16
|
+
const brandTheme: ModalTheme = {
|
|
17
|
+
brand: '#0d47a1',
|
|
18
|
+
brandForeground: '#ffffff',
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const dangerTheme: ModalTheme = {
|
|
22
|
+
confirmBg: '#b91c1c',
|
|
23
|
+
confirmFg: '#ffffff',
|
|
24
|
+
confirmBorder: '#b91c1c',
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const mintTheme: ModalTheme = {
|
|
28
|
+
brand: '#0f766e',
|
|
29
|
+
brandForeground: '#ecfdf5',
|
|
30
|
+
confirmBg: '#0f766e',
|
|
31
|
+
confirmFg: '#ecfdf5',
|
|
32
|
+
confirmBorder: '#0f766e',
|
|
33
|
+
cancelBg: '#f0fdfa',
|
|
34
|
+
cancelFg: '#115e59',
|
|
35
|
+
cancelBorder: '#99f6e4',
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export function App() {
|
|
39
|
+
const [sample, setSample] = useState<Sample>(null);
|
|
40
|
+
const [email, setEmail] = useState('');
|
|
41
|
+
|
|
42
|
+
const close = () => setSample(null);
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<main className="demo-page">
|
|
46
|
+
<header className="demo-header">
|
|
47
|
+
<p className="demo-kicker">React</p>
|
|
48
|
+
<h1>Modal samples</h1>
|
|
49
|
+
<p>
|
|
50
|
+
Controlled <code>UniversalModal</code> demos with different sizes, placements,
|
|
51
|
+
and themes.
|
|
52
|
+
</p>
|
|
53
|
+
<nav className="demo-nav" aria-label="Adapters">
|
|
54
|
+
<a href="../index.html">All</a>
|
|
55
|
+
<a href="../vanilla/index.html">Vanilla</a>
|
|
56
|
+
<a href="../web-component/index.html">Web Component</a>
|
|
57
|
+
<a href="./index.html" aria-current="page">
|
|
58
|
+
React
|
|
59
|
+
</a>
|
|
60
|
+
<a href="../vue/index.html">Vue</a>
|
|
61
|
+
<a href="../angular/index.html">Angular</a>
|
|
62
|
+
</nav>
|
|
63
|
+
</header>
|
|
64
|
+
|
|
65
|
+
<section className="demo-grid">
|
|
66
|
+
<article className="demo-card">
|
|
67
|
+
<h2>1. Invite form</h2>
|
|
68
|
+
<p>Centered dialog with async confirm.</p>
|
|
69
|
+
<button type="button" onClick={() => setSample('invite')}>
|
|
70
|
+
Invite teammate
|
|
71
|
+
</button>
|
|
72
|
+
</article>
|
|
73
|
+
|
|
74
|
+
<article className="demo-card">
|
|
75
|
+
<h2>2. Danger confirm</h2>
|
|
76
|
+
<p>Alertdialog with red confirm styling.</p>
|
|
77
|
+
<button type="button" onClick={() => setSample('danger')}>
|
|
78
|
+
Revoke token
|
|
79
|
+
</button>
|
|
80
|
+
</article>
|
|
81
|
+
|
|
82
|
+
<article className="demo-card">
|
|
83
|
+
<h2>3. Right drawer</h2>
|
|
84
|
+
<p>Large panel for multi-field editing.</p>
|
|
85
|
+
<button type="button" onClick={() => setSample('drawer')}>
|
|
86
|
+
Edit billing
|
|
87
|
+
</button>
|
|
88
|
+
</article>
|
|
89
|
+
|
|
90
|
+
<article className="demo-card">
|
|
91
|
+
<h2>4. Top notice</h2>
|
|
92
|
+
<p>Top placement, close icon only.</p>
|
|
93
|
+
<button type="button" onClick={() => setSample('top')}>
|
|
94
|
+
Show notice
|
|
95
|
+
</button>
|
|
96
|
+
</article>
|
|
97
|
+
|
|
98
|
+
<article className="demo-card">
|
|
99
|
+
<h2>5. Fullscreen</h2>
|
|
100
|
+
<p>Onboarding-style fullscreen modal.</p>
|
|
101
|
+
<button type="button" onClick={() => setSample('fullscreen')}>
|
|
102
|
+
Start tour
|
|
103
|
+
</button>
|
|
104
|
+
</article>
|
|
105
|
+
|
|
106
|
+
<article className="demo-card">
|
|
107
|
+
<h2>6. Persistent</h2>
|
|
108
|
+
<p>Blocks outside dismiss until confirmed.</p>
|
|
109
|
+
<button type="button" onClick={() => setSample('persistent')}>
|
|
110
|
+
Review policy
|
|
111
|
+
</button>
|
|
112
|
+
</article>
|
|
113
|
+
|
|
114
|
+
<article className="demo-card">
|
|
115
|
+
<h2>7. Custom brand</h2>
|
|
116
|
+
<p>Per-modal mint theme tokens.</p>
|
|
117
|
+
<button type="button" onClick={() => setSample('brand')}>
|
|
118
|
+
Open branded modal
|
|
119
|
+
</button>
|
|
120
|
+
</article>
|
|
121
|
+
</section>
|
|
122
|
+
|
|
123
|
+
<UniversalModal
|
|
124
|
+
open={sample === 'invite'}
|
|
125
|
+
onOpenChange={(open) => !open && close()}
|
|
126
|
+
title="Invite teammate"
|
|
127
|
+
description="They will receive an email with access instructions."
|
|
128
|
+
confirmText="Send invite"
|
|
129
|
+
theme={brandTheme}
|
|
130
|
+
onConfirm={async () => {
|
|
131
|
+
await new Promise((r) => setTimeout(r, 700));
|
|
132
|
+
console.log('invited', email);
|
|
133
|
+
}}
|
|
134
|
+
>
|
|
135
|
+
<label className="demo-field">
|
|
136
|
+
Email
|
|
137
|
+
<input
|
|
138
|
+
type="email"
|
|
139
|
+
value={email}
|
|
140
|
+
onChange={(e) => setEmail(e.target.value)}
|
|
141
|
+
placeholder="name@company.com"
|
|
142
|
+
/>
|
|
143
|
+
</label>
|
|
144
|
+
</UniversalModal>
|
|
145
|
+
|
|
146
|
+
<UniversalModal
|
|
147
|
+
open={sample === 'danger'}
|
|
148
|
+
onOpenChange={(open) => !open && close()}
|
|
149
|
+
title="Revoke API token?"
|
|
150
|
+
description="Integrations using this token will stop working."
|
|
151
|
+
role="alertdialog"
|
|
152
|
+
confirmText="Revoke"
|
|
153
|
+
theme={dangerTheme}
|
|
154
|
+
onConfirm={async () => {
|
|
155
|
+
await new Promise((r) => setTimeout(r, 600));
|
|
156
|
+
}}
|
|
157
|
+
>
|
|
158
|
+
<p className="demo-muted">
|
|
159
|
+
Token prefix: <code>pl_live_••••9f2a</code>
|
|
160
|
+
</p>
|
|
161
|
+
</UniversalModal>
|
|
162
|
+
|
|
163
|
+
<UniversalModal
|
|
164
|
+
open={sample === 'drawer'}
|
|
165
|
+
onOpenChange={(open) => !open && close()}
|
|
166
|
+
title="Billing details"
|
|
167
|
+
size="lg"
|
|
168
|
+
placement="right"
|
|
169
|
+
confirmText="Save"
|
|
170
|
+
onConfirm={async () => {
|
|
171
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
172
|
+
}}
|
|
173
|
+
>
|
|
174
|
+
<div className="demo-stack">
|
|
175
|
+
<label className="demo-field">
|
|
176
|
+
Company
|
|
177
|
+
<input defaultValue="Poluru Labs" />
|
|
178
|
+
</label>
|
|
179
|
+
<label className="demo-field">
|
|
180
|
+
Tax ID
|
|
181
|
+
<input placeholder="Optional" />
|
|
182
|
+
</label>
|
|
183
|
+
<label className="demo-field">
|
|
184
|
+
Billing email
|
|
185
|
+
<input type="email" defaultValue="billing@polurus.com" />
|
|
186
|
+
</label>
|
|
187
|
+
</div>
|
|
188
|
+
</UniversalModal>
|
|
189
|
+
|
|
190
|
+
<UniversalModal
|
|
191
|
+
open={sample === 'top'}
|
|
192
|
+
onOpenChange={(open) => !open && close()}
|
|
193
|
+
title="Scheduled maintenance"
|
|
194
|
+
placement="top"
|
|
195
|
+
hideActions
|
|
196
|
+
showCloseIcon
|
|
197
|
+
>
|
|
198
|
+
<p>Read-only mode from 01:00–01:30 UTC this Sunday.</p>
|
|
199
|
+
</UniversalModal>
|
|
200
|
+
|
|
201
|
+
<UniversalModal
|
|
202
|
+
open={sample === 'fullscreen'}
|
|
203
|
+
onOpenChange={(open) => !open && close()}
|
|
204
|
+
title="Product tour"
|
|
205
|
+
description="Fullscreen sample for walkthroughs."
|
|
206
|
+
size="fullscreen"
|
|
207
|
+
confirmText="Finish"
|
|
208
|
+
cancelText="Skip"
|
|
209
|
+
>
|
|
210
|
+
<div className="demo-stack">
|
|
211
|
+
<p>1. Open a modal from any framework adapter.</p>
|
|
212
|
+
<p>2. Customize brand colors with CSS variables or the theme prop.</p>
|
|
213
|
+
<p>3. Stack nested dialogs when you need confirmation.</p>
|
|
214
|
+
</div>
|
|
215
|
+
</UniversalModal>
|
|
216
|
+
|
|
217
|
+
<UniversalModal
|
|
218
|
+
open={sample === 'persistent'}
|
|
219
|
+
onOpenChange={(open) => !open && close()}
|
|
220
|
+
title="Security policy update"
|
|
221
|
+
role="alertdialog"
|
|
222
|
+
persistent
|
|
223
|
+
showCloseIcon={false}
|
|
224
|
+
confirmText="Acknowledge"
|
|
225
|
+
cancelText="Later"
|
|
226
|
+
>
|
|
227
|
+
<p>Escape and backdrop click are disabled until you choose an action.</p>
|
|
228
|
+
</UniversalModal>
|
|
229
|
+
|
|
230
|
+
<UniversalModal
|
|
231
|
+
open={sample === 'brand'}
|
|
232
|
+
onOpenChange={(open) => !open && close()}
|
|
233
|
+
title="Mint brand theme"
|
|
234
|
+
description="Per-instance theme override."
|
|
235
|
+
theme={mintTheme}
|
|
236
|
+
confirmText="Apply"
|
|
237
|
+
>
|
|
238
|
+
<p>Useful when one dialog needs a different brand treatment.</p>
|
|
239
|
+
</UniversalModal>
|
|
240
|
+
</main>
|
|
241
|
+
);
|
|
242
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>Universal Modal — React samples</title>
|
|
7
|
+
<link rel="stylesheet" href="../../packages/universal-modal/dist/styles.css" />
|
|
8
|
+
<link rel="stylesheet" href="./styles.css" />
|
|
9
|
+
</head>
|
|
10
|
+
<body data-um-theme="light">
|
|
11
|
+
<div id="root"></div>
|
|
12
|
+
<script type="importmap">
|
|
13
|
+
{
|
|
14
|
+
"imports": {
|
|
15
|
+
"react": "https://esm.sh/react@19.0.0",
|
|
16
|
+
"react/jsx-runtime": "https://esm.sh/react@19.0.0/jsx-runtime",
|
|
17
|
+
"react-dom": "https://esm.sh/react-dom@19.0.0",
|
|
18
|
+
"react-dom/client": "https://esm.sh/react-dom@19.0.0/client",
|
|
19
|
+
"@poluru-labs/universal-modal": "../../packages/universal-modal/dist/index.js",
|
|
20
|
+
"@poluru-labs/universal-modal-react": "../../packages/universal-modal-react/dist/index.js"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
</script>
|
|
24
|
+
<script type="module" src="./main.js"></script>
|
|
25
|
+
</body>
|
|
26
|
+
</html>
|