Mercurial
annotate design_system/src/components/notifications.js @ 266:efaf4c63cc94
fix clean production bundle staging
Recreate deployment staging before copying the Bazel bundle and verify required inference runtime paths before promoting it.
Co-authored-by: Copilot <[email protected]>
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Fri, 07 Aug 2026 12:52:30 -0700 |
| parents | 60a876c4587a |
| children |
| rev | line source |
|---|---|
|
252
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
1 const MAX_VISIBLE = 3; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
2 const MAX_QUEUED = 20; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
3 const MAX_RECORDS = MAX_VISIBLE + MAX_QUEUED; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
4 const DEFAULT_DURATION_MS = 5000; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
5 const MIN_DURATION_MS = 250; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
6 const MAX_DURATION_MS = 120000; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
7 const TONES = new Set(["info", "success", "warning", "error"]); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
8 const ANNOUNCEMENTS = new Set(["none", "polite", "assertive"]); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
9 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
10 function isShortString(value, maximum, allowEmpty = false) { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
11 return typeof value === "string" && |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
12 value.length <= maximum && |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
13 (allowEmpty || value.trim().length > 0); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
14 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
15 |
|
258
60a876c4587a
[ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents:
254
diff
changeset
|
16 function resolveCssLength(element, property, fallback) { |
|
60a876c4587a
[ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents:
254
diff
changeset
|
17 const probe = document.createElement("span"); |
|
60a876c4587a
[ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents:
254
diff
changeset
|
18 probe.style.position = "absolute"; |
|
60a876c4587a
[ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents:
254
diff
changeset
|
19 probe.style.inlineSize = `var(${property})`; |
|
60a876c4587a
[ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents:
254
diff
changeset
|
20 probe.style.visibility = "hidden"; |
|
60a876c4587a
[ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents:
254
diff
changeset
|
21 element.append(probe); |
|
60a876c4587a
[ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents:
254
diff
changeset
|
22 const value = Number.parseFloat(getComputedStyle(probe).inlineSize); |
|
60a876c4587a
[ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents:
254
diff
changeset
|
23 probe.remove(); |
|
60a876c4587a
[ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents:
254
diff
changeset
|
24 return Number.isFinite(value) ? value : fallback; |
|
60a876c4587a
[ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents:
254
diff
changeset
|
25 } |
|
60a876c4587a
[ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents:
254
diff
changeset
|
26 |
|
254
2b6e732087ff
[ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
253
diff
changeset
|
27 /** |
|
2b6e732087ff
[ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
253
diff
changeset
|
28 * Validates and normalizes a notification event record. |
|
2b6e732087ff
[ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
253
diff
changeset
|
29 * |
|
2b6e732087ff
[ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
253
diff
changeset
|
30 * @param {*} value Candidate event detail. |
|
2b6e732087ff
[ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
253
diff
changeset
|
31 * @return {?Object} Frozen normalized record, or null when invalid. |
|
2b6e732087ff
[ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
253
diff
changeset
|
32 */ |
|
252
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
33 export function validateNotification(value) { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
34 if (!value || |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
35 value.version !== 1 || |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
36 !isShortString(value.id, 128) || |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
37 !TONES.has(value.tone) || |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
38 !isShortString(value.message, 500) || |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
39 !ANNOUNCEMENTS.has(value.announcement)) return null; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
40 if (value.description !== undefined && |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
41 !isShortString(value.description, 1000, true)) return null; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
42 if (value.persistent !== undefined && |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
43 typeof value.persistent !== "boolean") return null; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
44 if (value.durationMs !== undefined && |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
45 (!Number.isFinite(value.durationMs) || |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
46 value.durationMs < MIN_DURATION_MS || |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
47 value.durationMs > MAX_DURATION_MS)) return null; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
48 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
49 let action; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
50 if (value.action !== undefined) { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
51 if (!value.action || |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
52 !isShortString(value.action.token, 256) || |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
53 !isShortString(value.action.label, 120)) return null; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
54 action = Object.freeze({ |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
55 token: value.action.token, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
56 label: value.action.label, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
57 }); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
58 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
59 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
60 return Object.freeze({ |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
61 version: 1, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
62 id: value.id, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
63 tone: value.tone, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
64 message: value.message, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
65 description: value.description || "", |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
66 announcement: value.announcement, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
67 durationMs: value.durationMs ?? DEFAULT_DURATION_MS, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
68 persistent: value.persistent === true, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
69 action, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
70 }); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
71 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
72 |
|
254
2b6e732087ff
[ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
253
diff
changeset
|
73 /** |
|
2b6e732087ff
[ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
253
diff
changeset
|
74 * Validates a programmatic notification dismissal record. |
|
2b6e732087ff
[ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
253
diff
changeset
|
75 * |
|
2b6e732087ff
[ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
253
diff
changeset
|
76 * @param {*} value Candidate event detail. |
|
2b6e732087ff
[ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
253
diff
changeset
|
77 * @return {?string} Valid notification ID, or null when invalid. |
|
2b6e732087ff
[ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
253
diff
changeset
|
78 */ |
|
252
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
79 export function validateNotificationDismiss(value) { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
80 if (!value || |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
81 value.version !== 1 || |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
82 !isShortString(value.id, 128)) return null; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
83 return value.id; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
84 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
85 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
86 function makeRecord(notification, announced = false) { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
87 return { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
88 ...notification, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
89 announced, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
90 pauseReasons: new Set(), |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
91 remainingMs: notification.durationMs, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
92 startedAt: 0, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
93 timer: null, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
94 view: null, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
95 }; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
96 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
97 |
|
254
2b6e732087ff
[ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
253
diff
changeset
|
98 /** |
|
258
60a876c4587a
[ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents:
254
diff
changeset
|
99 * Renders a bounded, scoped notification queue. |
|
254
2b6e732087ff
[ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
253
diff
changeset
|
100 * |
|
2b6e732087ff
[ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
253
diff
changeset
|
101 * @extends {HTMLElement} |
|
2b6e732087ff
[ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
253
diff
changeset
|
102 */ |
|
252
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
103 export class ZenNotifications extends HTMLElement { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
104 static version = 1; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
105 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
106 #records = new Map(); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
107 #announcementQueues = { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
108 polite: [], |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
109 assertive: [], |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
110 }; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
111 #announcementTimers = { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
112 polite: null, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
113 assertive: null, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
114 }; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
115 #announcementRunning = { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
116 polite: false, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
117 assertive: false, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
118 }; |
|
253
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
119 #exitTimers = new Map(); |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
120 #exitingElements = new Set(); |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
121 #layoutFrame = null; |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
122 #resizeObserver = null; |
|
252
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
123 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
124 constructor() { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
125 super(); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
126 this.handleNotify = event => { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
127 if (!(event instanceof CustomEvent) || |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
128 !event.bubbles || |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
129 event.composed) return; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
130 event.stopPropagation(); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
131 this.notify(event.detail); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
132 }; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
133 this.handleDismiss = event => { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
134 if (!(event instanceof CustomEvent) || |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
135 !event.bubbles || |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
136 event.composed) return; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
137 event.stopPropagation(); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
138 const id = validateNotificationDismiss(event.detail); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
139 if (id) this.dismiss(id, "programmatic"); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
140 }; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
141 this.handleVisibility = () => { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
142 for (const record of this.#records.values()) { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
143 if (document.hidden) this.pause(record, "hidden"); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
144 else this.resume(record, "hidden"); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
145 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
146 }; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
147 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
148 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
149 connectedCallback() { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
150 if (!this.stack) this.createInternalElements(); |
|
253
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
151 if (!this.#resizeObserver && |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
152 typeof ResizeObserver === "function") { |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
153 this.#resizeObserver = new ResizeObserver(() => { |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
154 this.requestLayout(); |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
155 }); |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
156 } |
|
252
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
157 this.addEventListener("zen-notify", this.handleNotify); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
158 this.addEventListener( |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
159 "zen-dismiss-notification", |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
160 this.handleDismiss, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
161 ); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
162 document.addEventListener( |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
163 "visibilitychange", |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
164 this.handleVisibility, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
165 ); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
166 this.render(); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
167 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
168 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
169 disconnectedCallback() { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
170 this.removeEventListener("zen-notify", this.handleNotify); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
171 this.removeEventListener( |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
172 "zen-dismiss-notification", |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
173 this.handleDismiss, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
174 ); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
175 document.removeEventListener( |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
176 "visibilitychange", |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
177 this.handleVisibility, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
178 ); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
179 for (const record of this.#records.values()) { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
180 this.clearTimer(record); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
181 } |
|
253
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
182 cancelAnimationFrame(this.#layoutFrame); |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
183 this.#layoutFrame = null; |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
184 this.#resizeObserver?.disconnect(); |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
185 for (const timer of this.#exitTimers.values()) { |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
186 clearTimeout(timer); |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
187 } |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
188 this.#exitTimers.clear(); |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
189 this.#exitingElements.clear(); |
|
252
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
190 this.#records.clear(); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
191 for (const priority of ["polite", "assertive"]) { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
192 clearTimeout(this.#announcementTimers[priority]); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
193 this.#announcementTimers[priority] = null; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
194 this.#announcementQueues[priority].length = 0; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
195 this.#announcementRunning[priority] = false; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
196 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
197 for (const element of this.querySelectorAll( |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
198 ":scope > [data-zen-notifications-internal]", |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
199 )) { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
200 element.remove(); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
201 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
202 this.stack = null; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
203 this.politeRegion = null; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
204 this.assertiveRegion = null; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
205 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
206 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
207 createInternalElements() { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
208 const label = this.getAttribute("aria-label") || "Notifications"; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
209 this.stack = document.createElement("section"); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
210 this.stack.dataset.zenNotificationStack = ""; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
211 this.stack.dataset.zenNotificationsInternal = ""; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
212 this.stack.setAttribute("role", "region"); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
213 this.stack.setAttribute("aria-label", label); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
214 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
215 this.politeRegion = document.createElement("span"); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
216 this.politeRegion.dataset.zenLive = "polite"; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
217 this.politeRegion.dataset.zenNotificationsInternal = ""; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
218 this.politeRegion.className = "zen-visually-hidden"; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
219 this.politeRegion.setAttribute("aria-live", "polite"); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
220 this.politeRegion.setAttribute("aria-atomic", "true"); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
221 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
222 this.assertiveRegion = document.createElement("span"); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
223 this.assertiveRegion.dataset.zenLive = "assertive"; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
224 this.assertiveRegion.dataset.zenNotificationsInternal = ""; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
225 this.assertiveRegion.className = "zen-visually-hidden"; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
226 this.assertiveRegion.setAttribute("aria-live", "assertive"); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
227 this.assertiveRegion.setAttribute("aria-atomic", "true"); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
228 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
229 this.append( |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
230 this.stack, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
231 this.politeRegion, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
232 this.assertiveRegion, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
233 ); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
234 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
235 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
236 get size() { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
237 return this.#records.size; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
238 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
239 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
240 get visibleCount() { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
241 return Math.min(this.#records.size, MAX_VISIBLE); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
242 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
243 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
244 notify(value) { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
245 const notification = validateNotification(value); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
246 if (!notification) return false; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
247 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
248 const previous = this.#records.get(notification.id); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
249 if (!previous && this.#records.size >= MAX_RECORDS) { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
250 const oldestFinite = [...this.#records.values()].find( |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
251 record => !record.persistent, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
252 ); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
253 if (!oldestFinite) return false; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
254 this.removeRecord(oldestFinite.id, "overflow", false); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
255 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
256 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
257 let record; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
258 if (previous) { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
259 this.clearTimer(previous); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
260 Object.assign(previous, notification); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
261 previous.remainingMs = notification.durationMs; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
262 this.#records.delete(notification.id); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
263 record = previous; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
264 } else { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
265 record = makeRecord(notification); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
266 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
267 this.#records.set(notification.id, record); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
268 this.render(); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
269 return true; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
270 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
271 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
272 dismiss(id, reason = "dismissed") { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
273 if (!isShortString(id, 128) || !this.#records.has(id)) { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
274 return false; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
275 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
276 this.removeRecord(id, reason, true); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
277 return true; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
278 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
279 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
280 removeRecord(id, reason, render) { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
281 const record = this.#records.get(id); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
282 if (!record) return; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
283 this.clearTimer(record); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
284 this.#records.delete(id); |
|
253
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
285 const article = record.view?.article; |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
286 if (article && render && article.isConnected) { |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
287 article.dataset.removing = "true"; |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
288 this.#exitingElements.add(article); |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
289 const exitTimer = setTimeout(() => { |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
290 this.#resizeObserver?.unobserve(article); |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
291 article.remove(); |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
292 this.#exitingElements.delete(article); |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
293 this.#exitTimers.delete(article); |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
294 this.requestLayout(); |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
295 }, 180); |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
296 this.#exitTimers.set(article, exitTimer); |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
297 } else if (article) { |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
298 this.#resizeObserver?.unobserve(article); |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
299 article.remove(); |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
300 } |
|
252
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
301 record.view = null; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
302 this.dispatchEvent(new CustomEvent("zen-notification-removed", { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
303 bubbles: true, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
304 composed: false, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
305 detail: Object.freeze({ |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
306 version: 1, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
307 id, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
308 reason, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
309 }), |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
310 })); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
311 if (render) this.render(); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
312 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
313 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
314 clearTimer(record) { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
315 if (!record.timer) return; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
316 clearTimeout(record.timer); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
317 record.remainingMs = Math.max( |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
318 0, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
319 record.remainingMs - (performance.now() - record.startedAt), |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
320 ); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
321 record.timer = null; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
322 record.startedAt = 0; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
323 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
324 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
325 pause(record, reason) { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
326 if (record.persistent || record.pauseReasons.has(reason)) return; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
327 record.pauseReasons.add(reason); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
328 this.clearTimer(record); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
329 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
330 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
331 resume(record, reason) { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
332 if (record.persistent) return; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
333 record.pauseReasons.delete(reason); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
334 this.schedule(record); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
335 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
336 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
337 schedule(record) { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
338 if (record.persistent || |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
339 record.timer || |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
340 record.pauseReasons.size > 0 || |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
341 !this.#records.has(record.id)) return; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
342 if (record.remainingMs <= 0) { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
343 this.dismiss(record.id, "timeout"); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
344 return; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
345 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
346 record.startedAt = performance.now(); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
347 record.timer = setTimeout(() => { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
348 record.timer = null; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
349 record.remainingMs = 0; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
350 this.dismiss(record.id, "timeout"); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
351 }, record.remainingMs); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
352 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
353 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
354 announce(record) { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
355 if (record.announced) return; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
356 record.announced = true; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
357 if (record.announcement === "none") return; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
358 this.#announcementQueues[record.announcement].push({ |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
359 id: record.id, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
360 message: record.message, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
361 }); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
362 this.runAnnouncementQueue(record.announcement); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
363 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
364 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
365 runAnnouncementQueue(priority) { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
366 if (this.#announcementRunning[priority]) return; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
367 const next = this.#announcementQueues[priority].shift(); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
368 if (!next) return; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
369 this.#announcementRunning[priority] = true; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
370 const region = priority === "assertive" |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
371 ? this.assertiveRegion |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
372 : this.politeRegion; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
373 region.textContent = ""; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
374 this.#announcementTimers[priority] = setTimeout(() => { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
375 if (this.isConnected && this.#records.has(next.id)) { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
376 region.textContent = next.message; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
377 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
378 this.#announcementTimers[priority] = setTimeout(() => { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
379 this.#announcementTimers[priority] = null; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
380 this.#announcementRunning[priority] = false; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
381 this.runAnnouncementQueue(priority); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
382 }, 120); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
383 }, 16); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
384 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
385 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
386 createNotificationElement(record) { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
387 if (!record.view) { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
388 const article = document.createElement("article"); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
389 article.dataset.zenNotificationId = record.id; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
390 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
391 const tone = document.createElement("span"); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
392 tone.className = "zen-notification-tone"; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
393 tone.setAttribute("aria-hidden", "true"); |
|
254
2b6e732087ff
[ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
253
diff
changeset
|
394 const toneIcon = document.createElement("zen-icon"); |
|
2b6e732087ff
[ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
253
diff
changeset
|
395 tone.append(toneIcon); |
|
252
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
396 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
397 const content = document.createElement("div"); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
398 content.className = "zen-notification-content"; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
399 const message = document.createElement("p"); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
400 message.className = "zen-notification-message"; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
401 content.append(message); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
402 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
403 const dismiss = document.createElement("button"); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
404 dismiss.type = "button"; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
405 dismiss.className = "zen-notification-dismiss"; |
|
254
2b6e732087ff
[ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
253
diff
changeset
|
406 const dismissIcon = document.createElement("zen-icon"); |
|
2b6e732087ff
[ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
253
diff
changeset
|
407 dismissIcon.setAttribute("name", "close"); |
|
2b6e732087ff
[ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
253
diff
changeset
|
408 dismiss.append(dismissIcon); |
|
252
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
409 dismiss.addEventListener("click", () => { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
410 this.dismiss(record.id, "dismissed"); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
411 }); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
412 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
413 article.addEventListener("pointerenter", () => { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
414 this.pause(record, "hover"); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
415 }); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
416 article.addEventListener("pointerleave", () => { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
417 this.resume(record, "hover"); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
418 }); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
419 article.addEventListener("focusin", () => { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
420 this.pause(record, "focus"); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
421 }); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
422 article.addEventListener("focusout", event => { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
423 if (!article.contains(event.relatedTarget)) { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
424 this.resume(record, "focus"); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
425 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
426 }); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
427 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
428 article.append(tone, content, dismiss); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
429 record.view = { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
430 action: null, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
431 article, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
432 content, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
433 description: null, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
434 dismiss, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
435 message, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
436 tone, |
|
254
2b6e732087ff
[ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
253
diff
changeset
|
437 toneIcon, |
|
252
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
438 }; |
|
253
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
439 this.#resizeObserver?.observe(article); |
|
252
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
440 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
441 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
442 const view = record.view; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
443 view.article.dataset.tone = record.tone; |
|
254
2b6e732087ff
[ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
253
diff
changeset
|
444 view.toneIcon.setAttribute("name", { |
|
2b6e732087ff
[ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
253
diff
changeset
|
445 info: "info", |
|
2b6e732087ff
[ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
253
diff
changeset
|
446 success: "check", |
|
2b6e732087ff
[ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
253
diff
changeset
|
447 warning: "alert", |
|
2b6e732087ff
[ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
253
diff
changeset
|
448 error: "error", |
|
2b6e732087ff
[ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
253
diff
changeset
|
449 }[record.tone]); |
|
252
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
450 view.message.textContent = record.message; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
451 view.dismiss.setAttribute( |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
452 "aria-label", |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
453 this.getAttribute("dismiss-label") || "Dismiss notification", |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
454 ); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
455 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
456 if (record.description) { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
457 if (!view.description) { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
458 view.description = document.createElement("p"); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
459 view.description.className = "zen-notification-description"; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
460 view.content.insertBefore( |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
461 view.description, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
462 view.action, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
463 ); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
464 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
465 view.description.textContent = record.description; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
466 } else if (view.description) { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
467 view.description.remove(); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
468 view.description = null; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
469 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
470 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
471 if (record.action) { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
472 if (!view.action) { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
473 view.action = document.createElement("button"); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
474 view.action.type = "button"; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
475 view.action.className = "zen-notification-action"; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
476 view.action.addEventListener("click", () => { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
477 this.dispatchEvent(new CustomEvent("zen-notification-action", { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
478 bubbles: true, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
479 composed: false, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
480 detail: Object.freeze({ |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
481 version: 1, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
482 id: record.id, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
483 token: record.action.token, |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
484 }), |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
485 })); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
486 }); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
487 view.content.append(view.action); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
488 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
489 view.action.textContent = record.action.label; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
490 } else if (view.action) { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
491 view.action.remove(); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
492 view.action = null; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
493 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
494 return view.article; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
495 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
496 |
|
253
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
497 requestLayout() { |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
498 cancelAnimationFrame(this.#layoutFrame); |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
499 this.#layoutFrame = requestAnimationFrame(() => { |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
500 this.#layoutFrame = null; |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
501 this.layoutStack(); |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
502 }); |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
503 } |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
504 |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
505 layoutStack() { |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
506 if (!this.stack) return; |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
507 const visible = [...this.#records.values()] |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
508 .slice(-MAX_VISIBLE) |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
509 .filter(record => record.view?.article.isConnected); |
|
258
60a876c4587a
[ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents:
254
diff
changeset
|
510 const gap = resolveCssLength( |
|
60a876c4587a
[ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents:
254
diff
changeset
|
511 this.stack, |
|
60a876c4587a
[ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents:
254
diff
changeset
|
512 "--zenbu-notification-gap", |
|
60a876c4587a
[ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents:
254
diff
changeset
|
513 12, |
|
253
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
514 ); |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
515 let expandedHeight = 0; |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
516 let newestHeight = 0; |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
517 |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
518 for (let index = visible.length - 1; index >= 0; index--) { |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
519 const record = visible[index]; |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
520 const article = record.view.article; |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
521 const depth = visible.length - 1 - index; |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
522 const height = article.offsetHeight; |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
523 if (depth === 0) newestHeight = height; |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
524 article.style.setProperty( |
|
258
60a876c4587a
[ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents:
254
diff
changeset
|
525 "--zenbu-notification-depth", |
|
253
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
526 String(depth), |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
527 ); |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
528 article.style.setProperty( |
|
258
60a876c4587a
[ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents:
254
diff
changeset
|
529 "--zenbu-notification-collapsed-offset", |
|
253
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
530 `${-depth * 10}px`, |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
531 ); |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
532 article.style.setProperty( |
|
258
60a876c4587a
[ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents:
254
diff
changeset
|
533 "--zenbu-notification-collapsed-opacity", |
|
253
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
534 String(Math.max(0.55, 1 - depth * 0.18)), |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
535 ); |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
536 article.dataset.depth = String(depth); |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
537 article.style.setProperty( |
|
258
60a876c4587a
[ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents:
254
diff
changeset
|
538 "--zenbu-notification-offset", |
|
253
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
539 `${-expandedHeight}px`, |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
540 ); |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
541 article.style.setProperty( |
|
258
60a876c4587a
[ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents:
254
diff
changeset
|
542 "--zenbu-notification-scale", |
|
253
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
543 String(Math.max(0.88, 1 - depth * 0.055)), |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
544 ); |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
545 article.style.zIndex = String(visible.length - depth); |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
546 expandedHeight += height + gap; |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
547 } |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
548 |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
549 this.stack.dataset.count = String(visible.length); |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
550 this.stack.style.setProperty( |
|
258
60a876c4587a
[ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents:
254
diff
changeset
|
551 "--zenbu-notification-collapsed-height", |
|
253
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
552 `${newestHeight + Math.max(0, visible.length - 1) * 10}px`, |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
553 ); |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
554 this.stack.style.setProperty( |
|
258
60a876c4587a
[ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents:
254
diff
changeset
|
555 "--zenbu-notification-expanded-height", |
|
253
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
556 `${Math.max(0, expandedHeight - gap)}px`, |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
557 ); |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
558 } |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
559 |
|
252
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
560 render() { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
561 if (!this.stack) return; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
562 const records = [...this.#records.values()]; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
563 const visible = records.slice(-MAX_VISIBLE); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
564 const visibleIds = new Set(visible.map(record => record.id)); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
565 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
566 for (const record of records) { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
567 if (visibleIds.has(record.id)) { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
568 this.resume(record, "queued"); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
569 } else { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
570 this.pause(record, "queued"); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
571 this.resume(record, "hover"); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
572 this.resume(record, "focus"); |
|
253
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
573 if (record.view?.article) { |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
574 this.#resizeObserver?.unobserve(record.view.article); |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
575 record.view.article.remove(); |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
576 } |
|
252
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
577 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
578 if (document.hidden) this.pause(record, "hidden"); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
579 else this.resume(record, "hidden"); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
580 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
581 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
582 const elements = visible.map(record => |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
583 this.createNotificationElement(record) |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
584 ); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
585 for (let index = 0; index < elements.length; index++) { |
|
253
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
586 const current = [...this.stack.children] |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
587 .filter(element => !this.#exitingElements.has(element))[index]; |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
588 if (current !== elements[index]) { |
|
252
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
589 this.stack.insertBefore( |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
590 elements[index], |
|
253
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
591 current || null, |
|
252
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
592 ); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
593 } |
|
253
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
594 this.#resizeObserver?.observe(elements[index]); |
|
252
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
595 } |
|
253
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
596 const desired = new Set(elements); |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
597 for (const element of [...this.stack.children]) { |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
598 if (!desired.has(element) && |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
599 !this.#exitingElements.has(element)) { |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
600 element.remove(); |
|
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
601 } |
|
252
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
602 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
603 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
604 for (const record of visible) { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
605 const element = record.view.article; |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
606 if (element.matches(":hover")) this.pause(record, "hover"); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
607 else this.resume(record, "hover"); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
608 if (element.contains(document.activeElement)) { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
609 this.pause(record, "focus"); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
610 } else this.resume(record, "focus"); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
611 this.announce(record); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
612 this.schedule(record); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
613 } |
|
253
fdf3816959cb
[ui] Add Sonner-like notification stack
MrJuneJune <me@mrjunejune.com>
parents:
252
diff
changeset
|
614 this.requestLayout(); |
|
252
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
615 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
616 } |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
617 |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
618 const existing = customElements.get("zen-notifications"); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
619 if (!existing) { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
620 customElements.define("zen-notifications", ZenNotifications); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
621 } else if (existing.version !== ZenNotifications.version) { |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
622 throw new Error("Incompatible zen-notifications component"); |
|
7a7581f040e8
[ui] Add scoped notification component
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
623 } |