@hyalo/angular 0.0.0-stage → 0.1.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/CHANGELOG.md +41 -0
- package/LICENSE +21 -0
- package/README.md +32 -3
- package/fesm2022/hyalo-angular-accordion.mjs +230 -0
- package/fesm2022/hyalo-angular-accordion.mjs.map +1 -0
- package/fesm2022/hyalo-angular-button.mjs +203 -0
- package/fesm2022/hyalo-angular-button.mjs.map +1 -0
- package/fesm2022/hyalo-angular-card.mjs +221 -0
- package/fesm2022/hyalo-angular-card.mjs.map +1 -0
- package/fesm2022/hyalo-angular-choice.mjs +788 -0
- package/fesm2022/hyalo-angular-choice.mjs.map +1 -0
- package/fesm2022/hyalo-angular-dialog.mjs +571 -0
- package/fesm2022/hyalo-angular-dialog.mjs.map +1 -0
- package/fesm2022/hyalo-angular-field.mjs +312 -0
- package/fesm2022/hyalo-angular-field.mjs.map +1 -0
- package/fesm2022/hyalo-angular-icon.mjs +343 -0
- package/fesm2022/hyalo-angular-icon.mjs.map +1 -0
- package/fesm2022/hyalo-angular-interaction.mjs +455 -0
- package/fesm2022/hyalo-angular-interaction.mjs.map +1 -0
- package/fesm2022/hyalo-angular-navbar.mjs +343 -0
- package/fesm2022/hyalo-angular-navbar.mjs.map +1 -0
- package/fesm2022/hyalo-angular-overlay.mjs +94 -0
- package/fesm2022/hyalo-angular-overlay.mjs.map +1 -0
- package/fesm2022/hyalo-angular-popover-overlay-kit-6wPwnxln.mjs +3 -0
- package/fesm2022/hyalo-angular-popover.mjs +487 -0
- package/fesm2022/hyalo-angular-popover.mjs.map +1 -0
- package/fesm2022/hyalo-angular-segmented.mjs +223 -0
- package/fesm2022/hyalo-angular-segmented.mjs.map +1 -0
- package/fesm2022/hyalo-angular-select.mjs +464 -0
- package/fesm2022/hyalo-angular-select.mjs.map +1 -0
- package/fesm2022/hyalo-angular-tabs.mjs +324 -0
- package/fesm2022/hyalo-angular-tabs.mjs.map +1 -0
- package/fesm2022/hyalo-angular-theme.mjs +94 -0
- package/fesm2022/hyalo-angular-theme.mjs.map +1 -0
- package/fesm2022/hyalo-angular-toast.mjs +322 -0
- package/fesm2022/hyalo-angular-toast.mjs.map +1 -0
- package/fesm2022/hyalo-angular.mjs +473 -0
- package/fesm2022/hyalo-angular.mjs.map +1 -0
- package/package.json +133 -3
- package/styles/hyalo-core.css +25 -0
- package/styles/hyalo.css +17 -0
- package/styles/overlays/dialog.css +9 -0
- package/styles/overlays/popover.css +9 -0
- package/styles/overlays/select.css +9 -0
- package/styles/overlays/toast.css +8 -0
- package/styles/palettes/aurora.css +47 -0
- package/styles/palettes/ember.css +47 -0
- package/styles/palettes/graphite.css +47 -0
- package/styles/palettes/ocean.css +47 -0
- package/styles/palettes/orchid.css +47 -0
- package/styles/palettes/rose.css +47 -0
- package/styles/parts/card.css +49 -0
- package/styles/parts/dialog.css +116 -0
- package/styles/parts/drawer.css +124 -0
- package/styles/parts/field.css +36 -0
- package/styles/parts/glass.css +137 -0
- package/styles/parts/motion.css +82 -0
- package/styles/parts/navbar.css +55 -0
- package/styles/parts/popover.css +27 -0
- package/styles/parts/presence.css +55 -0
- package/styles/parts/reset.css +42 -0
- package/styles/parts/select.css +46 -0
- package/styles/parts/themes.css +105 -0
- package/styles/parts/toast.css +128 -0
- package/styles/parts/tokens.css +151 -0
- package/styles/parts/typography.css +64 -0
- package/types/hyalo-angular-accordion.d.ts +74 -0
- package/types/hyalo-angular-button.d.ts +88 -0
- package/types/hyalo-angular-card.d.ts +61 -0
- package/types/hyalo-angular-choice.d.ts +259 -0
- package/types/hyalo-angular-dialog.d.ts +170 -0
- package/types/hyalo-angular-field.d.ts +135 -0
- package/types/hyalo-angular-icon.d.ts +122 -0
- package/types/hyalo-angular-interaction.d.ts +131 -0
- package/types/hyalo-angular-navbar.d.ts +110 -0
- package/types/hyalo-angular-overlay.d.ts +31 -0
- package/types/hyalo-angular-popover.d.ts +142 -0
- package/types/hyalo-angular-segmented.d.ts +79 -0
- package/types/hyalo-angular-select.d.ts +130 -0
- package/types/hyalo-angular-tabs.d.ts +102 -0
- package/types/hyalo-angular-theme.d.ts +46 -0
- package/types/hyalo-angular-toast.d.ts +79 -0
- package/types/hyalo-angular.d.ts +345 -0
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
import { LiveAnnouncer } from "@angular/cdk/a11y";
|
|
2
|
+
import { createGlobalPositionStrategy, createOverlayRef } from "@angular/cdk/overlay";
|
|
3
|
+
import { ComponentPortal } from "@angular/cdk/portal";
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
import { ChangeDetectionStrategy, Component, ElementRef, Injectable, Injector, afterRenderEffect, computed, inject, signal } from "@angular/core";
|
|
6
|
+
import { HyFidelity, HyMotion, HySpring, HyVelocityTracker, MOTION, SPRINGS, project, ɵinjectIsBrowser } from "@hyalo/angular";
|
|
7
|
+
import { HyIcon } from "@hyalo/angular/icon";
|
|
8
|
+
const SWIPE_DISTANCE = 80;
|
|
9
|
+
const SLOP = 8;
|
|
10
|
+
var HyToastStack = class HyToastStack {
|
|
11
|
+
toaster = inject(HyToaster);
|
|
12
|
+
fidelity = inject(HyFidelity);
|
|
13
|
+
motion = inject(HyMotion);
|
|
14
|
+
host = inject(ElementRef).nativeElement;
|
|
15
|
+
springs = /* @__PURE__ */ new WeakMap();
|
|
16
|
+
swipe = null;
|
|
17
|
+
tops = /* @__PURE__ */ new Map();
|
|
18
|
+
material = computed(() => this.fidelity.tier() === "low" ? "solid" : "frosted", ...ngDevMode ? [{ debugName: "material" }] : /* istanbul ignore next */ []);
|
|
19
|
+
constructor() {
|
|
20
|
+
afterRenderEffect(() => {
|
|
21
|
+
this.toaster.items();
|
|
22
|
+
if (!this.host.contains(this.host.ownerDocument.activeElement)) this.toaster.resume("focus");
|
|
23
|
+
this.slideIntoPlace();
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
onFocusOut(event) {
|
|
27
|
+
if (!this.host.contains(event.relatedTarget)) this.toaster.resume("focus");
|
|
28
|
+
}
|
|
29
|
+
onDown(event) {
|
|
30
|
+
if (event.button !== 0 || event.target.closest("button")) return;
|
|
31
|
+
const el = event.currentTarget;
|
|
32
|
+
const spring = this.springFor(el);
|
|
33
|
+
const caught = spring.running;
|
|
34
|
+
spring.stop();
|
|
35
|
+
this.swipe = {
|
|
36
|
+
el,
|
|
37
|
+
id: event.pointerId,
|
|
38
|
+
spring,
|
|
39
|
+
tracker: new HyVelocityTracker(),
|
|
40
|
+
startX: event.clientX - spring.value,
|
|
41
|
+
startY: event.clientY,
|
|
42
|
+
dragging: false
|
|
43
|
+
};
|
|
44
|
+
if (caught) this.startDrag(this.swipe, event);
|
|
45
|
+
}
|
|
46
|
+
onMove(event) {
|
|
47
|
+
const s = this.swipe;
|
|
48
|
+
if (!s || event.pointerId !== s.id) return;
|
|
49
|
+
const dx = event.clientX - s.startX;
|
|
50
|
+
if (!s.dragging) {
|
|
51
|
+
const dy = Math.abs(event.clientY - s.startY);
|
|
52
|
+
const moved = Math.abs(dx - s.spring.value);
|
|
53
|
+
if (dy > SLOP && dy > moved) {
|
|
54
|
+
this.swipe = null;
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (moved < SLOP) return;
|
|
58
|
+
this.startDrag(s, event);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
s.tracker.add(dx);
|
|
62
|
+
s.spring.set(dx);
|
|
63
|
+
}
|
|
64
|
+
onUp(event, toast) {
|
|
65
|
+
const s = this.swipe;
|
|
66
|
+
if (!s || event.pointerId !== s.id) return;
|
|
67
|
+
this.swipe = null;
|
|
68
|
+
if (!s.dragging) return;
|
|
69
|
+
const x = s.spring.value;
|
|
70
|
+
const velocity = toast ? s.tracker.velocity() : 0;
|
|
71
|
+
const landing = x + project(velocity);
|
|
72
|
+
if (toast && Math.abs(landing) > SWIPE_DISTANCE && Math.sign(landing) === Math.sign(x || 1)) {
|
|
73
|
+
const away = Math.sign(landing) * (s.el.offsetWidth + 48);
|
|
74
|
+
s.spring.to(away, {
|
|
75
|
+
...SPRINGS.settle,
|
|
76
|
+
response: .3,
|
|
77
|
+
velocity,
|
|
78
|
+
onRest: () => this.toaster.discard(toast.id)
|
|
79
|
+
});
|
|
80
|
+
} else s.spring.to(0, {
|
|
81
|
+
...SPRINGS.momentum,
|
|
82
|
+
velocity
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
startDrag(s, event) {
|
|
86
|
+
s.dragging = true;
|
|
87
|
+
s.startX = event.clientX - s.spring.value;
|
|
88
|
+
s.tracker.add(s.spring.value);
|
|
89
|
+
try {
|
|
90
|
+
s.el.setPointerCapture(event.pointerId);
|
|
91
|
+
} catch {}
|
|
92
|
+
}
|
|
93
|
+
springFor(el) {
|
|
94
|
+
let spring = this.springs.get(el);
|
|
95
|
+
if (!spring) {
|
|
96
|
+
spring = new HySpring(0, (x) => {
|
|
97
|
+
el.style.translate = x ? `${x}px 0` : "";
|
|
98
|
+
el.style.opacity = x ? String(Math.max(0, 1 - Math.abs(x) / el.offsetWidth)) : "";
|
|
99
|
+
});
|
|
100
|
+
this.springs.set(el, spring);
|
|
101
|
+
}
|
|
102
|
+
return spring;
|
|
103
|
+
}
|
|
104
|
+
slideIntoPlace() {
|
|
105
|
+
const tops = /* @__PURE__ */ new Map();
|
|
106
|
+
for (const el of this.host.querySelectorAll(".hy-toast[data-id]")) {
|
|
107
|
+
const id = Number(el.dataset["id"]);
|
|
108
|
+
const top = el.offsetTop;
|
|
109
|
+
tops.set(id, top);
|
|
110
|
+
const before = this.tops.get(id);
|
|
111
|
+
if (before === void 0 || before === top) continue;
|
|
112
|
+
if (this.motion.reduced() || typeof el.animate !== "function") continue;
|
|
113
|
+
const current = new DOMMatrixReadOnly(getComputedStyle(el).transform).m42;
|
|
114
|
+
for (const running of el.getAnimations()) if (running.id === "hy-toast-slide") running.cancel();
|
|
115
|
+
el.animate([{ transform: `translateY(${before + current - top}px)` }, { transform: "none" }], {
|
|
116
|
+
id: "hy-toast-slide",
|
|
117
|
+
duration: MOTION.settle.duration * 1e3,
|
|
118
|
+
easing: MOTION.settle.css
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
this.tops = tops;
|
|
122
|
+
}
|
|
123
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
124
|
+
minVersion: "12.0.0",
|
|
125
|
+
version: "22.2.3",
|
|
126
|
+
ngImport: i0,
|
|
127
|
+
type: HyToastStack,
|
|
128
|
+
deps: [],
|
|
129
|
+
target: i0.ɵɵFactoryTarget.Component
|
|
130
|
+
});
|
|
131
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
132
|
+
minVersion: "17.0.0",
|
|
133
|
+
version: "22.2.3",
|
|
134
|
+
type: HyToastStack,
|
|
135
|
+
isStandalone: true,
|
|
136
|
+
selector: "hy-toast-stack",
|
|
137
|
+
host: {
|
|
138
|
+
attributes: {
|
|
139
|
+
"role": "region",
|
|
140
|
+
"aria-label": "Notifications"
|
|
141
|
+
},
|
|
142
|
+
listeners: {
|
|
143
|
+
"pointerenter": "toaster.pause('hover')",
|
|
144
|
+
"pointerleave": "toaster.resume('hover')",
|
|
145
|
+
"focusin": "toaster.pause('focus')",
|
|
146
|
+
"focusout": "onFocusOut($event)"
|
|
147
|
+
},
|
|
148
|
+
classAttribute: "hy-toast-stack"
|
|
149
|
+
},
|
|
150
|
+
ngImport: i0,
|
|
151
|
+
template: "<ol class=\"hy-toast-list\">\r\n @for (toast of toaster.items(); track toast.id) {\r\n <li\r\n class=\"hy-toast hy-glass\"\r\n [attr.data-id]=\"toast.id\"\r\n [attr.data-material]=\"material()\"\r\n [attr.data-tone]=\"toast.tone\"\r\n [attr.data-leaving]=\"toast.leaving || null\"\r\n (pointerdown)=\"onDown($event)\"\r\n (pointermove)=\"onMove($event)\"\r\n (pointerup)=\"onUp($event, toast)\"\r\n (pointercancel)=\"onUp($event, null)\"\r\n >\r\n @if (toast.tone !== 'neutral') {\r\n <hy-icon class=\"hy-toast__icon\" [name]=\"toast.tone\" />\r\n }\r\n <div class=\"hy-toast__text\">\r\n @if (toast.title) {\r\n <p class=\"hy-toast__title\">{{ toast.title }}</p>\r\n }\r\n <p class=\"hy-toast__message\">{{ toast.message }}</p>\r\n </div>\r\n @if (toast.action; as action) {\r\n <button\r\n type=\"button\"\r\n class=\"hy-toast__action\"\r\n (click)=\"action.run(); toaster.dismiss(toast.id)\"\r\n >\r\n {{ action.label }}\r\n </button>\r\n }\r\n <button\r\n type=\"button\"\r\n class=\"hy-toast__close\"\r\n aria-label=\"Dismiss\"\r\n (click)=\"toaster.dismiss(toast.id)\"\r\n >\r\n <hy-icon name=\"x\" />\r\n </button>\r\n </li>\r\n }\r\n</ol>\r\n",
|
|
152
|
+
dependencies: [{
|
|
153
|
+
kind: "component",
|
|
154
|
+
type: HyIcon,
|
|
155
|
+
selector: "hy-icon",
|
|
156
|
+
inputs: [
|
|
157
|
+
"name",
|
|
158
|
+
"icon",
|
|
159
|
+
"label",
|
|
160
|
+
"size",
|
|
161
|
+
"strokeWidth"
|
|
162
|
+
]
|
|
163
|
+
}],
|
|
164
|
+
changeDetection: i0.ChangeDetectionStrategy.OnPush
|
|
165
|
+
});
|
|
166
|
+
};
|
|
167
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
168
|
+
minVersion: "12.0.0",
|
|
169
|
+
version: "22.2.3",
|
|
170
|
+
ngImport: i0,
|
|
171
|
+
type: HyToastStack,
|
|
172
|
+
decorators: [{
|
|
173
|
+
type: Component,
|
|
174
|
+
args: [{
|
|
175
|
+
selector: "hy-toast-stack",
|
|
176
|
+
imports: [HyIcon],
|
|
177
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
178
|
+
host: {
|
|
179
|
+
class: "hy-toast-stack",
|
|
180
|
+
role: "region",
|
|
181
|
+
"aria-label": "Notifications",
|
|
182
|
+
"(pointerenter)": "toaster.pause('hover')",
|
|
183
|
+
"(pointerleave)": "toaster.resume('hover')",
|
|
184
|
+
"(focusin)": "toaster.pause('focus')",
|
|
185
|
+
"(focusout)": "onFocusOut($event)"
|
|
186
|
+
},
|
|
187
|
+
template: "<ol class=\"hy-toast-list\">\r\n @for (toast of toaster.items(); track toast.id) {\r\n <li\r\n class=\"hy-toast hy-glass\"\r\n [attr.data-id]=\"toast.id\"\r\n [attr.data-material]=\"material()\"\r\n [attr.data-tone]=\"toast.tone\"\r\n [attr.data-leaving]=\"toast.leaving || null\"\r\n (pointerdown)=\"onDown($event)\"\r\n (pointermove)=\"onMove($event)\"\r\n (pointerup)=\"onUp($event, toast)\"\r\n (pointercancel)=\"onUp($event, null)\"\r\n >\r\n @if (toast.tone !== 'neutral') {\r\n <hy-icon class=\"hy-toast__icon\" [name]=\"toast.tone\" />\r\n }\r\n <div class=\"hy-toast__text\">\r\n @if (toast.title) {\r\n <p class=\"hy-toast__title\">{{ toast.title }}</p>\r\n }\r\n <p class=\"hy-toast__message\">{{ toast.message }}</p>\r\n </div>\r\n @if (toast.action; as action) {\r\n <button\r\n type=\"button\"\r\n class=\"hy-toast__action\"\r\n (click)=\"action.run(); toaster.dismiss(toast.id)\"\r\n >\r\n {{ action.label }}\r\n </button>\r\n }\r\n <button\r\n type=\"button\"\r\n class=\"hy-toast__close\"\r\n aria-label=\"Dismiss\"\r\n (click)=\"toaster.dismiss(toast.id)\"\r\n >\r\n <hy-icon name=\"x\" />\r\n </button>\r\n </li>\r\n }\r\n</ol>\r\n"
|
|
188
|
+
}]
|
|
189
|
+
}],
|
|
190
|
+
ctorParameters: () => []
|
|
191
|
+
});
|
|
192
|
+
const MAX_VISIBLE = 4;
|
|
193
|
+
var HyToaster = class HyToaster {
|
|
194
|
+
injector = inject(Injector);
|
|
195
|
+
announcer = inject(LiveAnnouncer);
|
|
196
|
+
isBrowser = ɵinjectIsBrowser();
|
|
197
|
+
timers = /* @__PURE__ */ new Map();
|
|
198
|
+
overlayRef = null;
|
|
199
|
+
nextId = 1;
|
|
200
|
+
holds = /* @__PURE__ */ new Set();
|
|
201
|
+
items = signal([], ...ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []);
|
|
202
|
+
show(options) {
|
|
203
|
+
const id = this.nextId++;
|
|
204
|
+
const ref = { dismiss: () => this.dismiss(id) };
|
|
205
|
+
if (!this.isBrowser) return ref;
|
|
206
|
+
this.ensureStack();
|
|
207
|
+
const item = {
|
|
208
|
+
tone: "neutral",
|
|
209
|
+
...options,
|
|
210
|
+
id,
|
|
211
|
+
leaving: false
|
|
212
|
+
};
|
|
213
|
+
this.items.update((list) => [...list, item]);
|
|
214
|
+
const staying = this.items().filter((t) => !t.leaving);
|
|
215
|
+
const overflow = staying.length - MAX_VISIBLE;
|
|
216
|
+
for (const old of staying.slice(0, Math.max(0, overflow))) this.dismiss(old.id);
|
|
217
|
+
const text = options.title ? `${options.title}. ${options.message}` : options.message;
|
|
218
|
+
this.announcer.announce(text, item.tone === "danger" ? "assertive" : "polite");
|
|
219
|
+
const duration = options.duration ?? (options.action ? 0 : 5e3);
|
|
220
|
+
if (duration > 0) {
|
|
221
|
+
this.timers.set(id, {
|
|
222
|
+
left: duration,
|
|
223
|
+
started: Date.now()
|
|
224
|
+
});
|
|
225
|
+
if (this.holds.size === 0) this.startTimer(id);
|
|
226
|
+
}
|
|
227
|
+
return ref;
|
|
228
|
+
}
|
|
229
|
+
success(message, title) {
|
|
230
|
+
return this.show({
|
|
231
|
+
message,
|
|
232
|
+
title,
|
|
233
|
+
tone: "success"
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
error(message, title) {
|
|
237
|
+
return this.show({
|
|
238
|
+
message,
|
|
239
|
+
title,
|
|
240
|
+
tone: "danger"
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
dismiss(id) {
|
|
244
|
+
this.clearTimer(id);
|
|
245
|
+
if (!this.items().some((t) => t.id === id && !t.leaving)) return;
|
|
246
|
+
this.items.update((list) => list.map((t) => t.id === id ? {
|
|
247
|
+
...t,
|
|
248
|
+
leaving: true
|
|
249
|
+
} : t));
|
|
250
|
+
setTimeout(() => this.remove(id), MOTION.quick.duration * 1e3 + 40);
|
|
251
|
+
}
|
|
252
|
+
discard(id) {
|
|
253
|
+
this.clearTimer(id);
|
|
254
|
+
this.remove(id);
|
|
255
|
+
}
|
|
256
|
+
clearTimer(id) {
|
|
257
|
+
clearTimeout(this.timers.get(id)?.handle);
|
|
258
|
+
this.timers.delete(id);
|
|
259
|
+
}
|
|
260
|
+
dismissAll() {
|
|
261
|
+
for (const t of this.items()) this.dismiss(t.id);
|
|
262
|
+
}
|
|
263
|
+
pause(reason) {
|
|
264
|
+
const wasPaused = this.holds.size > 0;
|
|
265
|
+
this.holds.add(reason);
|
|
266
|
+
if (wasPaused) return;
|
|
267
|
+
const now = Date.now();
|
|
268
|
+
for (const timer of this.timers.values()) {
|
|
269
|
+
clearTimeout(timer.handle);
|
|
270
|
+
timer.left -= now - timer.started;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
resume(reason) {
|
|
274
|
+
if (!this.holds.delete(reason) || this.holds.size > 0) return;
|
|
275
|
+
for (const id of this.timers.keys()) this.startTimer(id);
|
|
276
|
+
}
|
|
277
|
+
startTimer(id) {
|
|
278
|
+
const timer = this.timers.get(id);
|
|
279
|
+
if (!timer) return;
|
|
280
|
+
timer.started = Date.now();
|
|
281
|
+
timer.handle = setTimeout(() => this.dismiss(id), Math.max(0, timer.left));
|
|
282
|
+
}
|
|
283
|
+
remove(id) {
|
|
284
|
+
this.items.update((list) => list.filter((t) => t.id !== id));
|
|
285
|
+
}
|
|
286
|
+
ensureStack() {
|
|
287
|
+
if (this.overlayRef) return;
|
|
288
|
+
this.overlayRef = createOverlayRef(this.injector, {
|
|
289
|
+
positionStrategy: createGlobalPositionStrategy(this.injector).bottom("0").end("0"),
|
|
290
|
+
panelClass: "hy-toast-pane"
|
|
291
|
+
});
|
|
292
|
+
this.overlayRef.attach(new ComponentPortal(HyToastStack, null, this.injector));
|
|
293
|
+
}
|
|
294
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
295
|
+
minVersion: "12.0.0",
|
|
296
|
+
version: "22.2.3",
|
|
297
|
+
ngImport: i0,
|
|
298
|
+
type: HyToaster,
|
|
299
|
+
deps: [],
|
|
300
|
+
target: i0.ɵɵFactoryTarget.Injectable
|
|
301
|
+
});
|
|
302
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({
|
|
303
|
+
minVersion: "12.0.0",
|
|
304
|
+
version: "22.2.3",
|
|
305
|
+
ngImport: i0,
|
|
306
|
+
type: HyToaster,
|
|
307
|
+
providedIn: "root"
|
|
308
|
+
});
|
|
309
|
+
};
|
|
310
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
311
|
+
minVersion: "12.0.0",
|
|
312
|
+
version: "22.2.3",
|
|
313
|
+
ngImport: i0,
|
|
314
|
+
type: HyToaster,
|
|
315
|
+
decorators: [{
|
|
316
|
+
type: Injectable,
|
|
317
|
+
args: [{ providedIn: "root" }]
|
|
318
|
+
}]
|
|
319
|
+
});
|
|
320
|
+
export { HyToaster };
|
|
321
|
+
|
|
322
|
+
//# sourceMappingURL=hyalo-angular-toast.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hyalo-angular-toast.mjs","names":["injectIsBrowser"],"sources":["../../../projects/hyalo/toast/toast-stack.ts","../../../projects/hyalo/toast/toast-stack.html","../../../projects/hyalo/toast/toaster.ts"],"sourcesContent":["import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ElementRef,\r\n afterRenderEffect,\r\n computed,\r\n inject,\r\n} from '@angular/core';\r\nimport { HyIcon } from '@hyalo/angular/icon';\r\nimport {\r\n HyFidelity,\r\n HyMotion,\r\n HySpring,\r\n HyVelocityTracker,\r\n MOTION,\r\n project,\r\n SPRINGS,\r\n} from '@hyalo/angular';\r\nimport { HyToaster, type HyToastItem } from './toaster';\r\n\r\n/** How far a swipe has to be headed before it dismisses, in px. */\r\nconst SWIPE_DISTANCE = 80;\r\n/** Movement before a press turns into a swipe, in px. */\r\nconst SLOP = 8;\r\n\r\ninterface Swipe {\r\n readonly el: HTMLElement;\r\n readonly id: number;\r\n readonly spring: HySpring;\r\n readonly tracker: HyVelocityTracker;\r\n startX: number;\r\n readonly startY: number;\r\n dragging: boolean;\r\n}\r\n\r\n/** @internal The visible stack of toasts. Created by HyToaster. */\r\n@Component({\r\n selector: 'hy-toast-stack',\r\n imports: [HyIcon],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n host: {\r\n class: 'hy-toast-stack',\r\n role: 'region',\r\n 'aria-label': 'Notifications',\r\n '(pointerenter)': \"toaster.pause('hover')\",\r\n '(pointerleave)': \"toaster.resume('hover')\",\r\n '(focusin)': \"toaster.pause('focus')\",\r\n '(focusout)': 'onFocusOut($event)',\r\n },\r\n templateUrl: './toast-stack.html',\r\n})\r\nexport class HyToastStack {\r\n protected readonly toaster = inject(HyToaster);\r\n private readonly fidelity = inject(HyFidelity);\r\n private readonly motion = inject(HyMotion);\r\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\r\n private readonly springs = new WeakMap<HTMLElement, HySpring>();\r\n private swipe: Swipe | null = null;\r\n /** Layout position of each toast after the last render, for the slide. */\r\n private tops = new Map<number, number>();\r\n\r\n protected readonly material = computed(() =>\r\n this.fidelity.tier() === 'low' ? 'solid' : 'frosted',\r\n );\r\n\r\n constructor() {\r\n afterRenderEffect(() => {\r\n this.toaster.items();\r\n // Removing the focused toast drops focus without a reliable focusout.\r\n if (!this.host.contains(this.host.ownerDocument.activeElement)) {\r\n this.toaster.resume('focus');\r\n }\r\n this.slideIntoPlace();\r\n });\r\n }\r\n\r\n protected onFocusOut(event: FocusEvent): void {\r\n // Moving between buttons inside the stack keeps the timers paused.\r\n if (!this.host.contains(event.relatedTarget as Node | null)) this.toaster.resume('focus');\r\n }\r\n\r\n protected onDown(event: PointerEvent): void {\r\n if (event.button !== 0 || (event.target as Element).closest('button')) return;\r\n const el = event.currentTarget as HTMLElement;\r\n const spring = this.springFor(el);\r\n // A toast still springing back is caught where it is.\r\n const caught = spring.running;\r\n spring.stop();\r\n this.swipe = {\r\n el,\r\n id: event.pointerId,\r\n spring,\r\n tracker: new HyVelocityTracker(),\r\n startX: event.clientX - spring.value,\r\n startY: event.clientY,\r\n dragging: false,\r\n };\r\n if (caught) this.startDrag(this.swipe, event);\r\n }\r\n\r\n protected onMove(event: PointerEvent): void {\r\n const s = this.swipe;\r\n if (!s || event.pointerId !== s.id) return;\r\n const dx = event.clientX - s.startX;\r\n if (!s.dragging) {\r\n const dy = Math.abs(event.clientY - s.startY);\r\n const moved = Math.abs(dx - s.spring.value);\r\n if (dy > SLOP && dy > moved) {\r\n this.swipe = null;\r\n return;\r\n }\r\n if (moved < SLOP) return;\r\n this.startDrag(s, event);\r\n return;\r\n }\r\n s.tracker.add(dx);\r\n s.spring.set(dx);\r\n }\r\n\r\n protected onUp(event: PointerEvent, toast: HyToastItem | null): void {\r\n const s = this.swipe;\r\n if (!s || event.pointerId !== s.id) return;\r\n this.swipe = null;\r\n if (!s.dragging) return;\r\n const x = s.spring.value;\r\n const velocity = toast ? s.tracker.velocity() : 0;\r\n const landing = x + project(velocity);\r\n // A flick against the drag direction takes the toast back.\r\n const out =\r\n toast && Math.abs(landing) > SWIPE_DISTANCE && Math.sign(landing) === Math.sign(x || 1);\r\n if (out) {\r\n const away = Math.sign(landing) * (s.el.offsetWidth + 48);\r\n s.spring.to(away, {\r\n ...SPRINGS.settle,\r\n response: 0.3,\r\n velocity,\r\n onRest: () => this.toaster.discard(toast.id),\r\n });\r\n } else {\r\n // The flick carried speed, so the return may overshoot a little.\r\n s.spring.to(0, { ...SPRINGS.momentum, velocity });\r\n }\r\n }\r\n\r\n private startDrag(s: Swipe, event: PointerEvent): void {\r\n s.dragging = true;\r\n s.startX = event.clientX - s.spring.value;\r\n s.tracker.add(s.spring.value);\r\n try {\r\n s.el.setPointerCapture(event.pointerId);\r\n } catch {\r\n // The pointer is already gone; the swipe still ends on pointerup.\r\n }\r\n }\r\n\r\n private springFor(el: HTMLElement): HySpring {\r\n let spring = this.springs.get(el);\r\n if (!spring) {\r\n spring = new HySpring(0, (x) => {\r\n el.style.translate = x ? `${x}px 0` : '';\r\n el.style.opacity = x ? String(Math.max(0, 1 - Math.abs(x) / el.offsetWidth)) : '';\r\n });\r\n this.springs.set(el, spring);\r\n }\r\n return spring;\r\n }\r\n\r\n /**\r\n * When a toast arrives or leaves, the others glide to their new place\r\n * instead of jumping. It starts from where each one is on screen, so a\r\n * slide that is interrupted by another change carries on smoothly.\r\n */\r\n private slideIntoPlace(): void {\r\n const tops = new Map<number, number>();\r\n for (const el of this.host.querySelectorAll<HTMLElement>('.hy-toast[data-id]')) {\r\n const id = Number(el.dataset['id']);\r\n const top = el.offsetTop;\r\n tops.set(id, top);\r\n const before = this.tops.get(id);\r\n if (before === undefined || before === top) continue;\r\n if (this.motion.reduced() || typeof el.animate !== 'function') continue;\r\n const current = new DOMMatrixReadOnly(getComputedStyle(el).transform).m42;\r\n for (const running of el.getAnimations()) {\r\n if (running.id === 'hy-toast-slide') running.cancel();\r\n }\r\n el.animate(\r\n [{ transform: `translateY(${before + current - top}px)` }, { transform: 'none' }],\r\n {\r\n id: 'hy-toast-slide',\r\n duration: MOTION.settle.duration * 1000,\r\n easing: MOTION.settle.css,\r\n },\r\n );\r\n }\r\n this.tops = tops;\r\n }\r\n}\r\n","<ol class=\"hy-toast-list\">\r\n @for (toast of toaster.items(); track toast.id) {\r\n <li\r\n class=\"hy-toast hy-glass\"\r\n [attr.data-id]=\"toast.id\"\r\n [attr.data-material]=\"material()\"\r\n [attr.data-tone]=\"toast.tone\"\r\n [attr.data-leaving]=\"toast.leaving || null\"\r\n (pointerdown)=\"onDown($event)\"\r\n (pointermove)=\"onMove($event)\"\r\n (pointerup)=\"onUp($event, toast)\"\r\n (pointercancel)=\"onUp($event, null)\"\r\n >\r\n @if (toast.tone !== 'neutral') {\r\n <hy-icon class=\"hy-toast__icon\" [name]=\"toast.tone\" />\r\n }\r\n <div class=\"hy-toast__text\">\r\n @if (toast.title) {\r\n <p class=\"hy-toast__title\">{{ toast.title }}</p>\r\n }\r\n <p class=\"hy-toast__message\">{{ toast.message }}</p>\r\n </div>\r\n @if (toast.action; as action) {\r\n <button\r\n type=\"button\"\r\n class=\"hy-toast__action\"\r\n (click)=\"action.run(); toaster.dismiss(toast.id)\"\r\n >\r\n {{ action.label }}\r\n </button>\r\n }\r\n <button\r\n type=\"button\"\r\n class=\"hy-toast__close\"\r\n aria-label=\"Dismiss\"\r\n (click)=\"toaster.dismiss(toast.id)\"\r\n >\r\n <hy-icon name=\"x\" />\r\n </button>\r\n </li>\r\n }\r\n</ol>\r\n","import { LiveAnnouncer } from '@angular/cdk/a11y';\r\nimport {\r\n createGlobalPositionStrategy,\r\n createOverlayRef,\r\n type OverlayRef,\r\n} from '@angular/cdk/overlay';\r\nimport { ComponentPortal } from '@angular/cdk/portal';\r\nimport { Injectable, Injector, inject, signal } from '@angular/core';\r\nimport { MOTION, ɵinjectIsBrowser as injectIsBrowser } from '@hyalo/angular';\r\nimport { HyToastStack } from './toast-stack';\r\n\r\n/** Colour and icon of a toast. */\r\nexport type HyToastTone = 'neutral' | 'info' | 'success' | 'warning' | 'danger';\r\n\r\n/** What to show. */\r\nexport interface HyToastOptions {\r\n readonly message: string;\r\n readonly title?: string;\r\n readonly tone?: HyToastTone;\r\n /**\r\n * Milliseconds before it hides. 0 keeps it until dismissed. Defaults to\r\n * 5000, or 0 when there is an action, so nobody has to race a timer.\r\n */\r\n readonly duration?: number;\r\n /** One optional action, such as Undo. */\r\n readonly action?: { readonly label: string; readonly run: () => void };\r\n}\r\n\r\n/** @internal One toast in the stack. */\r\nexport interface HyToastItem extends HyToastOptions {\r\n readonly id: number;\r\n readonly leaving: boolean;\r\n}\r\n\r\n/** Handle to a shown toast. */\r\nexport interface HyToastRef {\r\n dismiss(): void;\r\n}\r\n\r\nconst MAX_VISIBLE = 4;\r\n\r\n/** @internal Why the timers are on hold. Hover and focus are tracked apart. */\r\nexport type HyToastHold = 'hover' | 'focus';\r\n\r\n/**\r\n * Shows toasts: short messages about something that just happened.\r\n *\r\n * ```ts\r\n * toaster.show({ message: 'Address saved', tone: 'success' });\r\n * toaster.show({ message: 'Draft deleted', action: { label: 'Undo', run: () => restore() } });\r\n * ```\r\n *\r\n * Every toast is announced through the live announcer (`danger` toasts\r\n * assertively, the rest politely). Timers pause while the pointer or focus\r\n * is in the stack, and toasts can be swiped away. The stack sits at the\r\n * bottom inline-end corner and is a labelled region, so keyboard and screen\r\n * reader users can reach the actions.\r\n */\r\n@Injectable({ providedIn: 'root' })\r\nexport class HyToaster {\r\n private readonly injector = inject(Injector);\r\n private readonly announcer = inject(LiveAnnouncer);\r\n private readonly isBrowser = injectIsBrowser();\r\n private readonly timers = new Map<\r\n number,\r\n { left: number; started: number; handle?: ReturnType<typeof setTimeout> }\r\n >();\r\n private overlayRef: OverlayRef | null = null;\r\n private nextId = 1;\r\n private readonly holds = new Set<HyToastHold>();\r\n\r\n /** @internal The current stack, newest last. */\r\n readonly items = signal<readonly HyToastItem[]>([]);\r\n\r\n /** Shows a toast. Does nothing during server rendering. */\r\n show(options: HyToastOptions): HyToastRef {\r\n const id = this.nextId++;\r\n const ref = { dismiss: () => this.dismiss(id) };\r\n if (!this.isBrowser) return ref;\r\n this.ensureStack();\r\n\r\n const item: HyToastItem = { tone: 'neutral', ...options, id, leaving: false };\r\n this.items.update((list) => [...list, item]);\r\n // Toasts already on their way out do not count, and are not picked again.\r\n const staying = this.items().filter((t) => !t.leaving);\r\n const overflow = staying.length - MAX_VISIBLE;\r\n for (const old of staying.slice(0, Math.max(0, overflow))) this.dismiss(old.id);\r\n\r\n const text = options.title ? `${options.title}. ${options.message}` : options.message;\r\n void this.announcer.announce(text, item.tone === 'danger' ? 'assertive' : 'polite');\r\n\r\n const duration = options.duration ?? (options.action ? 0 : 5000);\r\n if (duration > 0) {\r\n this.timers.set(id, { left: duration, started: Date.now() });\r\n if (this.holds.size === 0) this.startTimer(id);\r\n }\r\n return ref;\r\n }\r\n\r\n success(message: string, title?: string): HyToastRef {\r\n return this.show({ message, title, tone: 'success' });\r\n }\r\n\r\n error(message: string, title?: string): HyToastRef {\r\n return this.show({ message, title, tone: 'danger' });\r\n }\r\n\r\n /** Hides one toast with its exit animation, a fade with reduced motion. */\r\n dismiss(id: number): void {\r\n this.clearTimer(id);\r\n if (!this.items().some((t) => t.id === id && !t.leaving)) return;\r\n this.items.update((list) => list.map((t) => (t.id === id ? { ...t, leaving: true } : t)));\r\n setTimeout(() => this.remove(id), MOTION.quick.duration * 1000 + 40);\r\n }\r\n\r\n /** @internal Removes a toast that already left the screen, as after a swipe. */\r\n discard(id: number): void {\r\n this.clearTimer(id);\r\n this.remove(id);\r\n }\r\n\r\n private clearTimer(id: number): void {\r\n clearTimeout(this.timers.get(id)?.handle);\r\n this.timers.delete(id);\r\n }\r\n\r\n /** Hides every toast. */\r\n dismissAll(): void {\r\n for (const t of this.items()) this.dismiss(t.id);\r\n }\r\n\r\n /**\r\n * @internal Pauses all timers while the stack is hovered or focused. Each\r\n * reason is held separately, so the pointer leaving does not restart the\r\n * timers while focus is still on a toast.\r\n */\r\n pause(reason: HyToastHold): void {\r\n const wasPaused = this.holds.size > 0;\r\n this.holds.add(reason);\r\n if (wasPaused) return;\r\n const now = Date.now();\r\n for (const timer of this.timers.values()) {\r\n clearTimeout(timer.handle);\r\n timer.left -= now - timer.started;\r\n }\r\n }\r\n\r\n /** @internal Releases one hold. Timers restart once no hold is left. */\r\n resume(reason: HyToastHold): void {\r\n if (!this.holds.delete(reason) || this.holds.size > 0) return;\r\n for (const id of this.timers.keys()) this.startTimer(id);\r\n }\r\n\r\n private startTimer(id: number): void {\r\n const timer = this.timers.get(id);\r\n if (!timer) return;\r\n timer.started = Date.now();\r\n timer.handle = setTimeout(() => this.dismiss(id), Math.max(0, timer.left));\r\n }\r\n\r\n private remove(id: number): void {\r\n this.items.update((list) => list.filter((t) => t.id !== id));\r\n }\r\n\r\n private ensureStack(): void {\r\n if (this.overlayRef) return;\r\n this.overlayRef = createOverlayRef(this.injector, {\r\n positionStrategy: createGlobalPositionStrategy(this.injector).bottom('0').end('0'),\r\n panelClass: 'hy-toast-pane',\r\n });\r\n this.overlayRef.attach(new ComponentPortal(HyToastStack, null, this.injector));\r\n }\r\n}\r\n"],"mappings":"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"}
|