@keenmate/pure-admin-core 2.3.6 → 2.5.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/README.md +23 -29
- package/dist/css/main.css +68 -148
- package/package.json +1 -5
- package/snippets/AUDIT.md +94 -0
- package/snippets/alerts.html +264 -89
- package/snippets/badges.html +193 -61
- package/snippets/buttons.html +178 -0
- package/snippets/callouts.html +210 -129
- package/snippets/cards.html +383 -200
- package/snippets/checkbox-lists.html +199 -65
- package/snippets/code.html +55 -11
- package/snippets/command-palette.html +401 -111
- package/snippets/comparison.html +144 -93
- package/snippets/customization.html +311 -104
- package/snippets/data-display.html +584 -0
- package/snippets/detail-panel.html +470 -138
- package/snippets/filter-card.html +246 -0
- package/snippets/forms.html +408 -308
- package/snippets/grid.html +253 -141
- package/snippets/layout.html +379 -480
- package/snippets/lists.html +144 -47
- package/snippets/loaders.html +64 -39
- package/snippets/manifest.json +330 -280
- package/snippets/modal-dialogs.html +137 -64
- package/snippets/modals.html +221 -151
- package/snippets/notifications.html +285 -0
- package/snippets/popconfirm.html +213 -19
- package/snippets/profile.html +290 -330
- package/snippets/statistics.html +247 -0
- package/snippets/tables.html +359 -150
- package/snippets/tabs.html +129 -45
- package/snippets/timeline.html +123 -56
- package/snippets/toasts.html +179 -31
- package/snippets/tooltips.html +199 -81
- package/snippets/typography.html +183 -58
- package/snippets/utilities.html +511 -415
- package/snippets/virtual-scroll.html +201 -75
- package/snippets/web-daterangepicker.html +369 -189
- package/snippets/web-multiselect.html +360 -124
- package/src/scss/core-components/_alerts.scss +51 -12
- package/src/scss/core-components/_pagers.scss +1 -1
- package/src/scss/core-components/_popconfirm.scss +35 -13
- package/src/scss/core-components/_profile.scss +18 -8
- package/src/scss/core-components/_statistics.scss +12 -12
- package/src/scss/core-components/_tables.scss +2 -134
- package/src/scss/variables/_components.scss +17 -2
- package/scripts/download-themes.js +0 -351
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
<!-- ================================
|
|
2
|
+
NOTIFICATIONS
|
|
3
|
+
Two pieces under one BEM block:
|
|
4
|
+
|
|
5
|
+
1. Notification bell + dropdown panel (lives in the navbar)
|
|
6
|
+
2. Full-page notification list (--page modifier on the list)
|
|
7
|
+
|
|
8
|
+
Source: core-components/_notifications.scss
|
|
9
|
+
|
|
10
|
+
Same z-index as the profile panel ($z-index-profile-panel ≈ 5000),
|
|
11
|
+
so the panel overlays normal content but sits below modal dialogs.
|
|
12
|
+
================================ -->
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
<!-- ================================
|
|
16
|
+
1. BELL + DROPDOWN PANEL
|
|
17
|
+
This is the canonical "bell in the top bar" pattern. The wrapper
|
|
18
|
+
(.pa-notifications) is the positioning anchor; the button has an
|
|
19
|
+
icon + a small red badge counter; the panel toggles via the
|
|
20
|
+
`.is-open` state class.
|
|
21
|
+
|
|
22
|
+
Toggle visibility from JS — there's no hover/focus auto-open
|
|
23
|
+
because the button + panel pair is too easy to accidentally
|
|
24
|
+
trigger by mouse-over.
|
|
25
|
+
================================ -->
|
|
26
|
+
|
|
27
|
+
<div class="pa-notifications">
|
|
28
|
+
|
|
29
|
+
<button class="pa-notifications__btn" onclick="toggleNotifications()" aria-label="Notifications">
|
|
30
|
+
<span class="pa-notifications__icon">🔔</span>
|
|
31
|
+
<span class="pa-notifications__badge">3</span>
|
|
32
|
+
</button>
|
|
33
|
+
|
|
34
|
+
<div class="pa-notifications__panel" id="notificationsPanel">
|
|
35
|
+
|
|
36
|
+
<div class="pa-notifications__header">
|
|
37
|
+
<h3>Notifications</h3>
|
|
38
|
+
<button class="pa-notifications__mark-read" onclick="markAllRead()">Mark all as read</button>
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
<ul class="pa-notifications__list">
|
|
42
|
+
|
|
43
|
+
<li class="pa-notifications__item pa-notifications__item--unread">
|
|
44
|
+
<div class="pa-notifications__icon-wrapper pa-notifications__icon-wrapper--primary">📝</div>
|
|
45
|
+
<div class="pa-notifications__content">
|
|
46
|
+
<h4>New task assigned</h4>
|
|
47
|
+
<p>Review the Q4 report by end of week</p>
|
|
48
|
+
<span class="pa-notifications__time">2 minutes ago</span>
|
|
49
|
+
</div>
|
|
50
|
+
</li>
|
|
51
|
+
|
|
52
|
+
<li class="pa-notifications__item pa-notifications__item--unread">
|
|
53
|
+
<div class="pa-notifications__icon-wrapper pa-notifications__icon-wrapper--success">✓</div>
|
|
54
|
+
<div class="pa-notifications__content">
|
|
55
|
+
<h4>Build completed</h4>
|
|
56
|
+
<p>Production deployment finished successfully</p>
|
|
57
|
+
<span class="pa-notifications__time">15 minutes ago</span>
|
|
58
|
+
</div>
|
|
59
|
+
</li>
|
|
60
|
+
|
|
61
|
+
<li class="pa-notifications__item pa-notifications__item--unread">
|
|
62
|
+
<div class="pa-notifications__icon-wrapper pa-notifications__icon-wrapper--warning">⚠️</div>
|
|
63
|
+
<div class="pa-notifications__content">
|
|
64
|
+
<h4>Server maintenance</h4>
|
|
65
|
+
<p>Scheduled downtime tonight at 11 PM</p>
|
|
66
|
+
<span class="pa-notifications__time">1 hour ago</span>
|
|
67
|
+
</div>
|
|
68
|
+
</li>
|
|
69
|
+
|
|
70
|
+
<!-- Read item — drops the --unread modifier -->
|
|
71
|
+
<li class="pa-notifications__item">
|
|
72
|
+
<div class="pa-notifications__icon-wrapper pa-notifications__icon-wrapper--secondary">💬</div>
|
|
73
|
+
<div class="pa-notifications__content">
|
|
74
|
+
<h4>New comment</h4>
|
|
75
|
+
<p>Sarah replied to your comment on Issue #432</p>
|
|
76
|
+
<span class="pa-notifications__time">3 hours ago</span>
|
|
77
|
+
</div>
|
|
78
|
+
</li>
|
|
79
|
+
|
|
80
|
+
</ul>
|
|
81
|
+
|
|
82
|
+
<div class="pa-notifications__footer">
|
|
83
|
+
<a href="/notifications">View all notifications</a>
|
|
84
|
+
</div>
|
|
85
|
+
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
|
|
89
|
+
<script>
|
|
90
|
+
function toggleNotifications() {
|
|
91
|
+
document.getElementById('notificationsPanel').classList.toggle('is-open');
|
|
92
|
+
}
|
|
93
|
+
function markAllRead() {
|
|
94
|
+
document.querySelectorAll('.pa-notifications__item--unread')
|
|
95
|
+
.forEach(el => el.classList.remove('pa-notifications__item--unread'));
|
|
96
|
+
// Reset the bell badge counter or hide it entirely
|
|
97
|
+
const badge = document.querySelector('.pa-notifications__badge');
|
|
98
|
+
if (badge) badge.style.display = 'none';
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Close on outside click (typical pattern; not provided by SCSS):
|
|
102
|
+
document.addEventListener('click', (e) => {
|
|
103
|
+
const wrap = document.querySelector('.pa-notifications');
|
|
104
|
+
if (!wrap.contains(e.target)) {
|
|
105
|
+
document.getElementById('notificationsPanel').classList.remove('is-open');
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
</script>
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
<!-- ================================
|
|
112
|
+
ICON-WRAPPER COLOUR VARIANTS
|
|
113
|
+
Five colours. Note: there's no --info variant on the icon
|
|
114
|
+
wrapper — defaults to the accent colour if you omit the
|
|
115
|
+
modifier entirely. For an info-coloured slot, fall back to
|
|
116
|
+
the default (no modifier).
|
|
117
|
+
================================ -->
|
|
118
|
+
|
|
119
|
+
<div class="pa-notifications__icon-wrapper"> 📌</div>
|
|
120
|
+
<div class="pa-notifications__icon-wrapper pa-notifications__icon-wrapper--primary"> 📌</div>
|
|
121
|
+
<div class="pa-notifications__icon-wrapper pa-notifications__icon-wrapper--success"> 📌</div>
|
|
122
|
+
<div class="pa-notifications__icon-wrapper pa-notifications__icon-wrapper--warning"> 📌</div>
|
|
123
|
+
<div class="pa-notifications__icon-wrapper pa-notifications__icon-wrapper--danger"> 📌</div>
|
|
124
|
+
<div class="pa-notifications__icon-wrapper pa-notifications__icon-wrapper--secondary"> 📌</div>
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
<!-- ================================
|
|
128
|
+
2. PAGE VIEW (--page list modifier)
|
|
129
|
+
A full-page notification list. Same building blocks; the list
|
|
130
|
+
gets a --page modifier that scales padding/icon/font up and
|
|
131
|
+
drops the max-height + scrolling so the list flows with the
|
|
132
|
+
page.
|
|
133
|
+
|
|
134
|
+
Items support an optional .pa-notifications__actions slot that
|
|
135
|
+
hover-reveals action buttons on desktop, and is always visible
|
|
136
|
+
on mobile (wrapping to a new row).
|
|
137
|
+
|
|
138
|
+
A leading .pa-checkbox is a typical addition for bulk actions.
|
|
139
|
+
================================ -->
|
|
140
|
+
|
|
141
|
+
<div class="pa-card">
|
|
142
|
+
<div class="pa-card__header">
|
|
143
|
+
<h3>All Notifications</h3>
|
|
144
|
+
</div>
|
|
145
|
+
<div class="pa-card__body p-0">
|
|
146
|
+
<ul class="pa-notifications__list pa-notifications__list--page">
|
|
147
|
+
|
|
148
|
+
<li class="pa-notifications__item pa-notifications__item--unread">
|
|
149
|
+
<label class="pa-checkbox">
|
|
150
|
+
<input type="checkbox">
|
|
151
|
+
<span class="pa-checkbox__box"></span>
|
|
152
|
+
</label>
|
|
153
|
+
<div class="pa-notifications__icon-wrapper pa-notifications__icon-wrapper--primary">👤</div>
|
|
154
|
+
<div class="pa-notifications__content">
|
|
155
|
+
<h4>New user registration</h4>
|
|
156
|
+
<p>John Doe has registered a new account and is awaiting approval.</p>
|
|
157
|
+
<span class="pa-notifications__time">2 minutes ago</span>
|
|
158
|
+
</div>
|
|
159
|
+
<div class="pa-notifications__actions">
|
|
160
|
+
<button class="pa-btn pa-btn--ghost pa-btn--sm" title="Mark as read">✓</button>
|
|
161
|
+
<button class="pa-btn pa-btn--ghost pa-btn--sm" title="Delete">✕</button>
|
|
162
|
+
</div>
|
|
163
|
+
</li>
|
|
164
|
+
|
|
165
|
+
<li class="pa-notifications__item">
|
|
166
|
+
<label class="pa-checkbox">
|
|
167
|
+
<input type="checkbox">
|
|
168
|
+
<span class="pa-checkbox__box"></span>
|
|
169
|
+
</label>
|
|
170
|
+
<div class="pa-notifications__icon-wrapper pa-notifications__icon-wrapper--warning">⚠️</div>
|
|
171
|
+
<div class="pa-notifications__content">
|
|
172
|
+
<h4>High CPU usage</h4>
|
|
173
|
+
<p>Server CPU usage has exceeded 85%. Consider scaling resources.</p>
|
|
174
|
+
<span class="pa-notifications__time">15 minutes ago</span>
|
|
175
|
+
</div>
|
|
176
|
+
<div class="pa-notifications__actions">
|
|
177
|
+
<button class="pa-btn pa-btn--ghost pa-btn--sm" title="Mark as read">✓</button>
|
|
178
|
+
<button class="pa-btn pa-btn--ghost pa-btn--sm" title="Delete">✕</button>
|
|
179
|
+
</div>
|
|
180
|
+
</li>
|
|
181
|
+
|
|
182
|
+
</ul>
|
|
183
|
+
</div>
|
|
184
|
+
</div>
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
<!-- ================================
|
|
188
|
+
COMPONENT REFERENCE
|
|
189
|
+
================================ -->
|
|
190
|
+
|
|
191
|
+
<!--
|
|
192
|
+
SUB-ELEMENTS:
|
|
193
|
+
|
|
194
|
+
Bell button + panel anchor
|
|
195
|
+
.pa-notifications Wrapper (positioning anchor for
|
|
196
|
+
the absolutely-positioned panel).
|
|
197
|
+
.pa-notifications__btn Round bell button (no border).
|
|
198
|
+
.pa-notifications__icon The bell glyph itself.
|
|
199
|
+
.pa-notifications__badge Red counter pill, top-end of btn.
|
|
200
|
+
|
|
201
|
+
Dropdown panel
|
|
202
|
+
.pa-notifications__panel Floating panel. display:none until
|
|
203
|
+
you add `.is-open`. Uses
|
|
204
|
+
z-index-profile-panel (= 5000),
|
|
205
|
+
same as the profile panel.
|
|
206
|
+
.pa-notifications__header Header row inside the panel.
|
|
207
|
+
.pa-notifications__mark-read Right-aligned text button in header.
|
|
208
|
+
.pa-notifications__list <ul> wrapping items.
|
|
209
|
+
.pa-notifications__item <li>; flex row with icon + content.
|
|
210
|
+
.pa-notifications__icon-wrapper Round icon tile on the inline-start.
|
|
211
|
+
.pa-notifications__content Title (h4) + body (p) + time.
|
|
212
|
+
.pa-notifications__time Small muted timestamp.
|
|
213
|
+
.pa-notifications__footer Centered link row at the bottom.
|
|
214
|
+
|
|
215
|
+
ITEM STATE:
|
|
216
|
+
--unread Lighter accent-tinted background. Hover deepens it.
|
|
217
|
+
(no class) Read; default background, accent-tint on hover only.
|
|
218
|
+
|
|
219
|
+
ICON-WRAPPER COLOURS:
|
|
220
|
+
(no modifier) accent (--pa-accent)
|
|
221
|
+
--primary
|
|
222
|
+
--success
|
|
223
|
+
--warning
|
|
224
|
+
--danger
|
|
225
|
+
--secondary
|
|
226
|
+
Note: there is NO --info variant; use the default (no modifier) for
|
|
227
|
+
the accent slot.
|
|
228
|
+
|
|
229
|
+
PAGE-VIEW MODIFIER:
|
|
230
|
+
.pa-notifications__list--page
|
|
231
|
+
- Removes the panel max-height + overflow.
|
|
232
|
+
- Bigger padding, larger icon (4rem vs 3.2rem), larger text.
|
|
233
|
+
- Pairs with .pa-notifications__actions inside each item:
|
|
234
|
+
opacity: 0; reveals on .pa-notifications__item:hover
|
|
235
|
+
on mobile: opacity: 1 always, wraps to a new row with a
|
|
236
|
+
top divider.
|
|
237
|
+
|
|
238
|
+
PANEL OPEN/CLOSE:
|
|
239
|
+
No SCSS animation — `display: none` ↔ `display: flex` via .is-open.
|
|
240
|
+
Three things you'll wire up yourself:
|
|
241
|
+
1. Click the bell → toggle .is-open on .pa-notifications__panel
|
|
242
|
+
2. Click outside → remove .is-open
|
|
243
|
+
3. Mark all read → strip --unread from items + zero/hide badge
|
|
244
|
+
|
|
245
|
+
Common alternative: replace .is-open toggle with the `hidden`
|
|
246
|
+
attribute on the panel — works as long as you also add
|
|
247
|
+
`&[hidden] { display: none !important; }` somewhere, since the
|
|
248
|
+
base rule already forces `display: none`.
|
|
249
|
+
|
|
250
|
+
RESPONSIVE BEHAVIOUR (panel only, ≤ $mobile-breakpoint):
|
|
251
|
+
Width fills the viewport (minus 3.2rem) up to a 35.2rem cap.
|
|
252
|
+
Aligned to the inline-end edge with -$spacing-base offset.
|
|
253
|
+
Page-view items: actions always visible, wrapping to a new row
|
|
254
|
+
with a top border separator.
|
|
255
|
+
|
|
256
|
+
STRUCTURE PATTERNS:
|
|
257
|
+
|
|
258
|
+
Bell + dropdown (the navbar pattern):
|
|
259
|
+
<div class="pa-notifications">
|
|
260
|
+
<button class="pa-notifications__btn">
|
|
261
|
+
<span class="pa-notifications__icon">🔔</span>
|
|
262
|
+
<span class="pa-notifications__badge">3</span>
|
|
263
|
+
</button>
|
|
264
|
+
<div class="pa-notifications__panel">
|
|
265
|
+
<div class="pa-notifications__header">…</div>
|
|
266
|
+
<ul class="pa-notifications__list">
|
|
267
|
+
<li class="pa-notifications__item pa-notifications__item--unread">
|
|
268
|
+
<div class="pa-notifications__icon-wrapper …">…</div>
|
|
269
|
+
<div class="pa-notifications__content">…</div>
|
|
270
|
+
</li>
|
|
271
|
+
</ul>
|
|
272
|
+
<div class="pa-notifications__footer">…</div>
|
|
273
|
+
</div>
|
|
274
|
+
</div>
|
|
275
|
+
|
|
276
|
+
Full-page list:
|
|
277
|
+
<ul class="pa-notifications__list pa-notifications__list--page">
|
|
278
|
+
<li class="pa-notifications__item …">
|
|
279
|
+
<label class="pa-checkbox">…</label> <!-- bulk select -->
|
|
280
|
+
<div class="pa-notifications__icon-wrapper …">…</div>
|
|
281
|
+
<div class="pa-notifications__content">…</div>
|
|
282
|
+
<div class="pa-notifications__actions">…</div> <!-- hover-revealed -->
|
|
283
|
+
</li>
|
|
284
|
+
</ul>
|
|
285
|
+
-->
|
package/snippets/popconfirm.html
CHANGED
|
@@ -15,11 +15,11 @@ BENEFITS OVER MODALS:
|
|
|
15
15
|
- Better for quick decisions
|
|
16
16
|
- Ideal for table row actions
|
|
17
17
|
|
|
18
|
-
POSITION CLASSES:
|
|
18
|
+
POSITION CLASSES (logical — mirror in RTL):
|
|
19
19
|
- pa-popconfirm--bottom: Arrow on top, popconfirm below button (default)
|
|
20
|
-
- pa-popconfirm--top:
|
|
21
|
-
- pa-popconfirm--
|
|
22
|
-
- pa-popconfirm--
|
|
20
|
+
- pa-popconfirm--top: Arrow on bottom, popconfirm above button
|
|
21
|
+
- pa-popconfirm--end: Popconfirm on inline-end side (right in LTR, left in RTL)
|
|
22
|
+
- pa-popconfirm--start: Popconfirm on inline-start side (left in LTR, right in RTL)
|
|
23
23
|
|
|
24
24
|
SIZE VARIANTS:
|
|
25
25
|
- pa-popconfirm--compact: Smaller padding and dimensions
|
|
@@ -102,6 +102,98 @@ JAVASCRIPT REQUIRED:
|
|
|
102
102
|
</div>
|
|
103
103
|
|
|
104
104
|
|
|
105
|
+
<!-- ICON VARIANTS -->
|
|
106
|
+
|
|
107
|
+
<!--
|
|
108
|
+
Note: the base __icon class (no modifier) already prepends ⚠️ via a
|
|
109
|
+
::before, so <div class="…__message …__icon"> gives you a warning icon
|
|
110
|
+
for free. Use --danger/--warning/--info to swap the emoji.
|
|
111
|
+
-->
|
|
112
|
+
|
|
113
|
+
<!-- Default icon (warning emoji via base __icon) -->
|
|
114
|
+
<div id="popconfirm-default-icon" class="pa-popconfirm pa-popconfirm--bottom">
|
|
115
|
+
<div class="pa-popconfirm__arrow"></div>
|
|
116
|
+
<div class="pa-popconfirm__content">
|
|
117
|
+
<div class="pa-popconfirm__message pa-popconfirm__icon">
|
|
118
|
+
<p>Heads up — this will affect all members of the group.</p>
|
|
119
|
+
</div>
|
|
120
|
+
<div class="pa-popconfirm__actions">
|
|
121
|
+
<button class="pa-btn pa-btn--secondary" onclick="closePopconfirm('popconfirm-default-icon')">Cancel</button>
|
|
122
|
+
<button class="pa-btn pa-btn--primary" onclick="confirmAction('popconfirm-default-icon')">Proceed</button>
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
125
|
+
</div>
|
|
126
|
+
|
|
127
|
+
<!-- Warning icon (same emoji as default, but explicit) -->
|
|
128
|
+
<div id="popconfirm-warning" class="pa-popconfirm pa-popconfirm--bottom">
|
|
129
|
+
<div class="pa-popconfirm__arrow"></div>
|
|
130
|
+
<div class="pa-popconfirm__content">
|
|
131
|
+
<div class="pa-popconfirm__message pa-popconfirm__icon pa-popconfirm__icon--warning">
|
|
132
|
+
<p>Archive this item? It will be moved to the archive folder.</p>
|
|
133
|
+
</div>
|
|
134
|
+
<div class="pa-popconfirm__actions">
|
|
135
|
+
<button class="pa-btn pa-btn--secondary" onclick="closePopconfirm('popconfirm-warning')">Cancel</button>
|
|
136
|
+
<button class="pa-btn pa-btn--warning" onclick="confirmAction('popconfirm-warning')">Archive</button>
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
|
|
141
|
+
<!-- Info icon -->
|
|
142
|
+
<div id="popconfirm-info" class="pa-popconfirm pa-popconfirm--bottom">
|
|
143
|
+
<div class="pa-popconfirm__arrow"></div>
|
|
144
|
+
<div class="pa-popconfirm__content">
|
|
145
|
+
<div class="pa-popconfirm__message pa-popconfirm__icon pa-popconfirm__icon--info">
|
|
146
|
+
<p>Reset all settings to their default values?</p>
|
|
147
|
+
</div>
|
|
148
|
+
<div class="pa-popconfirm__actions">
|
|
149
|
+
<button class="pa-btn pa-btn--secondary" onclick="closePopconfirm('popconfirm-info')">Cancel</button>
|
|
150
|
+
<button class="pa-btn pa-btn--primary" onclick="confirmAction('popconfirm-info')">Reset</button>
|
|
151
|
+
</div>
|
|
152
|
+
</div>
|
|
153
|
+
</div>
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
<!-- POSITION VARIANTS -->
|
|
157
|
+
|
|
158
|
+
<!--
|
|
159
|
+
The position class is the *initial* placement. The JS below uses Floating
|
|
160
|
+
UI, which runs flip() collision detection on open and swaps the class to
|
|
161
|
+
the actual resolved side. So even if you author with --bottom, users near
|
|
162
|
+
the bottom of the viewport will see --top at runtime — the stylesheet
|
|
163
|
+
supports all four sides.
|
|
164
|
+
-->
|
|
165
|
+
|
|
166
|
+
<!-- Top placement (popconfirm appears above trigger) -->
|
|
167
|
+
<div id="popconfirm-top" class="pa-popconfirm pa-popconfirm--top">
|
|
168
|
+
<div class="pa-popconfirm__arrow"></div>
|
|
169
|
+
<div class="pa-popconfirm__content">
|
|
170
|
+
<div class="pa-popconfirm__message">
|
|
171
|
+
<p>Replace the current selection?</p>
|
|
172
|
+
</div>
|
|
173
|
+
<div class="pa-popconfirm__actions">
|
|
174
|
+
<button class="pa-btn pa-btn--secondary" onclick="closePopconfirm('popconfirm-top')">No</button>
|
|
175
|
+
<button class="pa-btn pa-btn--primary" onclick="confirmAction('popconfirm-top')">Yes</button>
|
|
176
|
+
</div>
|
|
177
|
+
</div>
|
|
178
|
+
</div>
|
|
179
|
+
|
|
180
|
+
<!-- End placement (popconfirm appears on the trigger's inline-end side: right in LTR, left in RTL) -->
|
|
181
|
+
<div id="popconfirm-end" class="pa-popconfirm pa-popconfirm--end pa-popconfirm--compact">
|
|
182
|
+
<div class="pa-popconfirm__arrow"></div>
|
|
183
|
+
<div class="pa-popconfirm__content">
|
|
184
|
+
<div class="pa-popconfirm__message">
|
|
185
|
+
<p>Remove tag?</p>
|
|
186
|
+
</div>
|
|
187
|
+
<div class="pa-popconfirm__actions">
|
|
188
|
+
<button class="pa-btn pa-btn--secondary" onclick="closePopconfirm('popconfirm-end')">No</button>
|
|
189
|
+
<button class="pa-btn pa-btn--danger" onclick="confirmAction('popconfirm-end')">Yes</button>
|
|
190
|
+
</div>
|
|
191
|
+
</div>
|
|
192
|
+
</div>
|
|
193
|
+
|
|
194
|
+
<!-- Pattern: pa-popconfirm--{top|bottom|start|end} (logical sides; mirror in RTL) -->
|
|
195
|
+
|
|
196
|
+
|
|
105
197
|
<!-- TABLE USAGE EXAMPLE -->
|
|
106
198
|
|
|
107
199
|
<!-- Common pattern: Delete action in table -->
|
|
@@ -199,32 +291,45 @@ function confirmAction(popconfirmId) {
|
|
|
199
291
|
}
|
|
200
292
|
|
|
201
293
|
async function positionPopconfirm(trigger, popconfirm) {
|
|
202
|
-
//
|
|
203
|
-
|
|
204
|
-
const
|
|
294
|
+
// Popconfirm classes use logical sides (start/end). Floating UI's placement
|
|
295
|
+
// arg is physical (left/right), so translate going in and coming back out.
|
|
296
|
+
const isRtl = document.documentElement.dir === 'rtl';
|
|
297
|
+
const toPhysical = {
|
|
298
|
+
top: 'top',
|
|
299
|
+
bottom: 'bottom',
|
|
300
|
+
start: isRtl ? 'right' : 'left',
|
|
301
|
+
end: isRtl ? 'left' : 'right'
|
|
302
|
+
};
|
|
303
|
+
const toLogical = {
|
|
304
|
+
top: 'top',
|
|
305
|
+
bottom: 'bottom',
|
|
306
|
+
left: isRtl ? 'end' : 'start',
|
|
307
|
+
right: isRtl ? 'start' : 'end'
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
const classMatch = popconfirm.className.match(/pa-popconfirm--(top|bottom|start|end)/);
|
|
311
|
+
const logical = classMatch ? classMatch[1] : 'bottom';
|
|
312
|
+
const placement = toPhysical[logical];
|
|
205
313
|
|
|
206
|
-
// Use Floating UI for automatic positioning with collision detection
|
|
207
314
|
const { computePosition, flip, shift, offset } = window.FloatingUIDOM;
|
|
208
315
|
|
|
209
316
|
const { x, y, placement: finalPlacement } = await computePosition(trigger, popconfirm, {
|
|
210
317
|
placement: placement,
|
|
211
318
|
middleware: [
|
|
212
|
-
offset(8),
|
|
213
|
-
flip(),
|
|
214
|
-
shift({ padding: 10 })
|
|
319
|
+
offset(8),
|
|
320
|
+
flip(),
|
|
321
|
+
shift({ padding: 10 })
|
|
215
322
|
]
|
|
216
323
|
});
|
|
217
324
|
|
|
218
|
-
//
|
|
325
|
+
// Map Floating UI's physical answer back to our logical class for the
|
|
326
|
+
// post-flip rewrite (`.split('-')[0]` handles compound forms like `top-start`).
|
|
327
|
+
const finalLogical = toLogical[finalPlacement.split('-')[0]] || 'bottom';
|
|
219
328
|
popconfirm.className = popconfirm.className
|
|
220
|
-
.replace(/pa-popconfirm--(top|bottom|
|
|
221
|
-
.trim() + ' pa-popconfirm--' +
|
|
329
|
+
.replace(/pa-popconfirm--(top|bottom|start|end)/g, '')
|
|
330
|
+
.trim() + ' pa-popconfirm--' + finalLogical;
|
|
222
331
|
|
|
223
|
-
|
|
224
|
-
Object.assign(popconfirm.style, {
|
|
225
|
-
left: `${x}px`,
|
|
226
|
-
top: `${y}px`
|
|
227
|
-
});
|
|
332
|
+
Object.assign(popconfirm.style, { left: `${x}px`, top: `${y}px` });
|
|
228
333
|
}
|
|
229
334
|
|
|
230
335
|
// Close popconfirm when clicking outside
|
|
@@ -251,3 +356,92 @@ window.addEventListener('resize', () => {
|
|
|
251
356
|
}
|
|
252
357
|
});
|
|
253
358
|
</script>
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
<!-- ================================
|
|
362
|
+
COMPONENT REFERENCE
|
|
363
|
+
================================ -->
|
|
364
|
+
|
|
365
|
+
<!--
|
|
366
|
+
STRUCTURE (required):
|
|
367
|
+
.pa-popconfirm
|
|
368
|
+
.pa-popconfirm__arrow ← decorative triangle pointing at trigger
|
|
369
|
+
.pa-popconfirm__content ← card surface with border + shadow
|
|
370
|
+
.pa-popconfirm__message ← body copy
|
|
371
|
+
.pa-popconfirm__actions ← button row (right-aligned by default)
|
|
372
|
+
|
|
373
|
+
STATE (note: .is-* class, not a BEM --modifier):
|
|
374
|
+
- .is-open — set by JS to flip display:none → display:block
|
|
375
|
+
|
|
376
|
+
POSITION MODIFIERS (logical — mirror in RTL):
|
|
377
|
+
- .pa-popconfirm--bottom — popconfirm below trigger, arrow on top (default)
|
|
378
|
+
- .pa-popconfirm--top — popconfirm above trigger, arrow on bottom
|
|
379
|
+
- .pa-popconfirm--end — popconfirm on inline-end side (right in LTR, left in RTL)
|
|
380
|
+
- .pa-popconfirm--start — popconfirm on inline-start side (left in LTR, right in RTL)
|
|
381
|
+
|
|
382
|
+
Under `dir="rtl"`, the inline-axis popconfirms (`--start`/`--end`) use the
|
|
383
|
+
same CSS rule as LTR plus a `scaleX(-1)` on the arrow so the triangle still
|
|
384
|
+
points at the trigger. The block-axis popconfirms (`--top`/`--bottom`)
|
|
385
|
+
invert their `translateX` so the arrow stays centered.
|
|
386
|
+
|
|
387
|
+
Runtime note: the JS runs Floating UI's flip() middleware on open and
|
|
388
|
+
rewrites the position class to match where the popconfirm actually fits,
|
|
389
|
+
so the initial class is just a *preferred* side. Floating UI only speaks
|
|
390
|
+
physical placements internally, so the snippet translates `start`/`end`
|
|
391
|
+
↔ `left`/`right` around the `computePosition` call.
|
|
392
|
+
|
|
393
|
+
SIZE:
|
|
394
|
+
- .pa-popconfirm--compact — tighter padding; min-width drops from 25.6rem to 19.2rem
|
|
395
|
+
|
|
396
|
+
ICON (optional, applied on the __message element):
|
|
397
|
+
- .pa-popconfirm__icon — base icon styling (prepends ⚠️ via ::before)
|
|
398
|
+
- .pa-popconfirm__icon--danger — swaps the emoji to 🗑️
|
|
399
|
+
- .pa-popconfirm__icon--warning — explicit warning (same ⚠️ as base)
|
|
400
|
+
- .pa-popconfirm__icon--info — swaps to ℹ️
|
|
401
|
+
|
|
402
|
+
(The base .pa-popconfirm__icon class alone already shows ⚠️ — the
|
|
403
|
+
--warning modifier just makes the intent explicit. Use --danger for
|
|
404
|
+
destructive actions; the emoji change is the differentiator.)
|
|
405
|
+
|
|
406
|
+
DIMENSIONS:
|
|
407
|
+
- min-width: 25.6rem / max-width: 32rem (default)
|
|
408
|
+
- min-width: 19.2rem (compact)
|
|
409
|
+
- z-index: $z-index-tooltip (9000) — renders above cards, modals' backdrops, etc.
|
|
410
|
+
|
|
411
|
+
JAVASCRIPT CONTRACT:
|
|
412
|
+
- Trigger: toggles .is-open on the target popconfirm element
|
|
413
|
+
- Positioning: Floating UI (loaded globally as window.FloatingUIDOM)
|
|
414
|
+
middleware: offset(8), flip(), shift({ padding: 10 })
|
|
415
|
+
- Dismissal: click outside, close button, or explicit confirm/cancel call
|
|
416
|
+
- The position-class rewrite happens every open + on scroll/resize while open
|
|
417
|
+
|
|
418
|
+
PATTERNS:
|
|
419
|
+
|
|
420
|
+
Basic delete confirm:
|
|
421
|
+
<button onclick="togglePopconfirm(event, 'pc-1')">Delete</button>
|
|
422
|
+
<div id="pc-1" class="pa-popconfirm pa-popconfirm--bottom">
|
|
423
|
+
<div class="pa-popconfirm__arrow"></div>
|
|
424
|
+
<div class="pa-popconfirm__content">
|
|
425
|
+
<div class="pa-popconfirm__message pa-popconfirm__icon pa-popconfirm__icon--danger">
|
|
426
|
+
<p>Delete this item?</p>
|
|
427
|
+
</div>
|
|
428
|
+
<div class="pa-popconfirm__actions">
|
|
429
|
+
<button class="pa-btn pa-btn--secondary" onclick="closePopconfirm('pc-1')">No</button>
|
|
430
|
+
<button class="pa-btn pa-btn--danger" onclick="confirmAction('pc-1')">Yes</button>
|
|
431
|
+
</div>
|
|
432
|
+
</div>
|
|
433
|
+
</div>
|
|
434
|
+
|
|
435
|
+
Compact table-row variant:
|
|
436
|
+
<div class="pa-popconfirm pa-popconfirm--bottom pa-popconfirm--compact"> … </div>
|
|
437
|
+
|
|
438
|
+
Inline-end popconfirm (right-of-trigger in LTR, left-of-trigger in RTL):
|
|
439
|
+
<div class="pa-popconfirm pa-popconfirm--end"> … </div>
|
|
440
|
+
|
|
441
|
+
POPCONFIRM vs MODAL:
|
|
442
|
+
- Popconfirm: anchored to trigger, no backdrop, 1-step Yes/No question,
|
|
443
|
+
cheap to open/close. Use for destructive row actions.
|
|
444
|
+
- Modal: centered, backdrop, multi-field forms, long explanations.
|
|
445
|
+
Use when you need attention or more than a button choice.
|
|
446
|
+
-->
|
|
447
|
+
|