flexdesk 0.17.1 → 0.17.3
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 +38 -0
- package/README.md +206 -1
- package/css/base.css +23 -1
- package/css/flexdesk.css +37 -1
- package/dist/flexdesk.css +37 -1
- package/dist/widgets.js +188 -74
- package/dist/widgets.js.map +2 -2
- package/dist/wm.js +90 -10
- package/dist/wm.js.map +2 -2
- package/package.json +1 -1
- package/src/tiling/command_palette.js +46 -7
- package/src/tiling/content_registry.js +3 -0
- package/src/tiling/entity_sources.js +10 -0
- package/src/tiling/wm.js +65 -3
- package/src/ui/components/notification_history.js +17 -24
- package/src/ui/components/settings_view.js +192 -51
- package/src/ui/notification_center.js +46 -8
package/dist/widgets.js
CHANGED
|
@@ -3033,7 +3033,7 @@ var NotificationHistory = class {
|
|
|
3033
3033
|
this.onOpen = typeof onOpen === "function" ? onOpen : null;
|
|
3034
3034
|
this.triggerEl = null;
|
|
3035
3035
|
this.badgeEl = null;
|
|
3036
|
-
this.
|
|
3036
|
+
this.unreadCount = 0;
|
|
3037
3037
|
this._popoverCleanup = null;
|
|
3038
3038
|
this._subscriptions = [];
|
|
3039
3039
|
}
|
|
@@ -3064,8 +3064,13 @@ var NotificationHistory = class {
|
|
|
3064
3064
|
this.#updateBadge();
|
|
3065
3065
|
return;
|
|
3066
3066
|
}
|
|
3067
|
-
this.
|
|
3068
|
-
this
|
|
3067
|
+
this.unreadCount = 0;
|
|
3068
|
+
const unsubscribe = this.notificationCenter?.subscribe?.(() => {
|
|
3069
|
+
this.unreadCount += 1;
|
|
3070
|
+
this.#updateBadge();
|
|
3071
|
+
});
|
|
3072
|
+
if (typeof unsubscribe === "function") this._subscriptions.push(unsubscribe);
|
|
3073
|
+
this.#updateBadge();
|
|
3069
3074
|
}
|
|
3070
3075
|
unmount() {
|
|
3071
3076
|
this.#closePanel();
|
|
@@ -3079,21 +3084,6 @@ var NotificationHistory = class {
|
|
|
3079
3084
|
this.triggerEl = null;
|
|
3080
3085
|
this.badgeEl = null;
|
|
3081
3086
|
}
|
|
3082
|
-
#subscribeEvents() {
|
|
3083
|
-
if (!this.eventBus) return;
|
|
3084
|
-
const badgeUpdate = () => queueMicrotask(() => this.#updateBadge());
|
|
3085
|
-
const events = [
|
|
3086
|
-
"toast:show",
|
|
3087
|
-
"notification:show",
|
|
3088
|
-
"log:entry",
|
|
3089
|
-
"workspace:save:failed",
|
|
3090
|
-
"workspace:import:failed"
|
|
3091
|
-
];
|
|
3092
|
-
events.forEach((name) => {
|
|
3093
|
-
const handle = this.eventBus.on(name, badgeUpdate);
|
|
3094
|
-
this._subscriptions.push(() => handle?.dispose?.());
|
|
3095
|
-
});
|
|
3096
|
-
}
|
|
3097
3087
|
/** The Alerts tab, asked for on the bus — or the embedder's own verb. */
|
|
3098
3088
|
#openAlerts() {
|
|
3099
3089
|
if (this.onOpen) {
|
|
@@ -3108,7 +3098,7 @@ var NotificationHistory = class {
|
|
|
3108
3098
|
}
|
|
3109
3099
|
#updateBadge() {
|
|
3110
3100
|
const historyLen = this.notificationCenter?.history?.length ?? 0;
|
|
3111
|
-
const unread = this.alertLog ? this.alertLog.unreadCount() : Math.
|
|
3101
|
+
const unread = this.alertLog ? this.alertLog.unreadCount() : Math.min(this.unreadCount, historyLen);
|
|
3112
3102
|
if (!this.badgeEl) return;
|
|
3113
3103
|
if (this.alertLog) {
|
|
3114
3104
|
const level = unread > 0 ? this.alertLog.worstUnread() : null;
|
|
@@ -3140,7 +3130,7 @@ var NotificationHistory = class {
|
|
|
3140
3130
|
}
|
|
3141
3131
|
#openPanel() {
|
|
3142
3132
|
this.#closePanel();
|
|
3143
|
-
this.
|
|
3133
|
+
this.unreadCount = 0;
|
|
3144
3134
|
this.#updateBadge();
|
|
3145
3135
|
const panel = document.createElement("div");
|
|
3146
3136
|
panel.className = "twm-notification-history__panel";
|
|
@@ -3155,7 +3145,7 @@ var NotificationHistory = class {
|
|
|
3155
3145
|
header.querySelector(".twm-notification-history__close-btn").addEventListener("click", () => this.#closePanel());
|
|
3156
3146
|
header.querySelector(".twm-notification-history__clear-btn").addEventListener("click", () => {
|
|
3157
3147
|
this.notificationCenter.history.splice(0);
|
|
3158
|
-
this.
|
|
3148
|
+
this.unreadCount = 0;
|
|
3159
3149
|
this.#updateBadge();
|
|
3160
3150
|
this.#renderList(list);
|
|
3161
3151
|
});
|
|
@@ -3939,6 +3929,51 @@ function fitNumber(n, { min, max, step }) {
|
|
|
3939
3929
|
if (lo != null && at(k) < lo) k = Math.ceil((lo - base) / s - EPS);
|
|
3940
3930
|
return at(k);
|
|
3941
3931
|
}
|
|
3932
|
+
function filterBox(onInput) {
|
|
3933
|
+
const label = el2("label", "twm-settings__search");
|
|
3934
|
+
const input = el2("input", "twm-settings__search-input");
|
|
3935
|
+
input.type = "search";
|
|
3936
|
+
input.placeholder = "Filter settings\u2026";
|
|
3937
|
+
input.autocomplete = "off";
|
|
3938
|
+
input.spellcheck = false;
|
|
3939
|
+
input.setAttribute("aria-label", "Filter settings");
|
|
3940
|
+
input.addEventListener("input", () => onInput(input.value));
|
|
3941
|
+
label.append(icon("search"), input);
|
|
3942
|
+
return { label, input };
|
|
3943
|
+
}
|
|
3944
|
+
function categoryNav(onSelect) {
|
|
3945
|
+
const nav = el2("nav", "twm-settings__nav");
|
|
3946
|
+
nav.setAttribute("aria-label", "Settings categories");
|
|
3947
|
+
nav.addEventListener("click", (e) => {
|
|
3948
|
+
const btn = e.target.closest?.("[data-category]");
|
|
3949
|
+
if (btn && nav.contains(btn)) onSelect(btn.dataset.category);
|
|
3950
|
+
});
|
|
3951
|
+
return nav;
|
|
3952
|
+
}
|
|
3953
|
+
function paintCategories(nav, categories, active) {
|
|
3954
|
+
const buttons = categories.map((cat) => {
|
|
3955
|
+
const b = el2("button", "twm-settings__cat");
|
|
3956
|
+
b.type = "button";
|
|
3957
|
+
b.dataset.category = cat.id;
|
|
3958
|
+
if (cat.id === active) {
|
|
3959
|
+
b.classList.add("twm-settings__cat--active");
|
|
3960
|
+
b.setAttribute("aria-current", "page");
|
|
3961
|
+
}
|
|
3962
|
+
b.append(icon(cat.icon || "tune"), el2("span", "twm-settings__cat-label", cat.label ?? cat.id));
|
|
3963
|
+
if (cat.description) b.title = String(cat.description);
|
|
3964
|
+
return b;
|
|
3965
|
+
});
|
|
3966
|
+
nav.replaceChildren(...buttons);
|
|
3967
|
+
}
|
|
3968
|
+
function resetAllButton(onClick) {
|
|
3969
|
+
const b = el2("button", "twm-btn twm-settings__reset-all");
|
|
3970
|
+
b.type = "button";
|
|
3971
|
+
b.append(icon("restart_alt"), el2("span", "", "Reset all"));
|
|
3972
|
+
b.addEventListener("click", () => {
|
|
3973
|
+
onClick();
|
|
3974
|
+
});
|
|
3975
|
+
return b;
|
|
3976
|
+
}
|
|
3942
3977
|
var SettingsView = class extends ComponentBase {
|
|
3943
3978
|
/**
|
|
3944
3979
|
* @param {object} o
|
|
@@ -3948,6 +3983,8 @@ var SettingsView = class extends ComponentBase {
|
|
|
3948
3983
|
* @param {string} [o.category] the category shown first (default: the first)
|
|
3949
3984
|
* @param {number} [o.textDebounceMs]
|
|
3950
3985
|
* @param {string} [o.title='Settings'] the sidebar heading
|
|
3986
|
+
* @param {boolean} [o.sidebar=true] false leaves the sidebar (filter,
|
|
3987
|
+
* categories, *Reset all*) out, for a `SettingsCategories` elsewhere
|
|
3951
3988
|
*/
|
|
3952
3989
|
constructor({
|
|
3953
3990
|
store,
|
|
@@ -3956,6 +3993,7 @@ var SettingsView = class extends ComponentBase {
|
|
|
3956
3993
|
category = null,
|
|
3957
3994
|
textDebounceMs = SETTINGS_TEXT_DEBOUNCE_MS,
|
|
3958
3995
|
title = "Settings",
|
|
3996
|
+
sidebar = true,
|
|
3959
3997
|
logger
|
|
3960
3998
|
} = {}) {
|
|
3961
3999
|
super({ eventBus, logger });
|
|
@@ -3971,6 +4009,8 @@ var SettingsView = class extends ComponentBase {
|
|
|
3971
4009
|
this._query = "";
|
|
3972
4010
|
this._debounceMs = textDebounceMs;
|
|
3973
4011
|
this._title = title;
|
|
4012
|
+
this._sidebar = sidebar !== false;
|
|
4013
|
+
this._listeners = /* @__PURE__ */ new Set();
|
|
3974
4014
|
this.root = null;
|
|
3975
4015
|
this._nav = null;
|
|
3976
4016
|
this._content = null;
|
|
@@ -3984,36 +4024,19 @@ var SettingsView = class extends ComponentBase {
|
|
|
3984
4024
|
mount(container) {
|
|
3985
4025
|
if (this.root) return this.root;
|
|
3986
4026
|
const root = el2("div", "twm-settings");
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
input.addEventListener("input", () => this.setQuery(input.value));
|
|
3998
|
-
search.append(icon("search"), input);
|
|
3999
|
-
this._search = input;
|
|
4000
|
-
const nav = el2("nav", "twm-settings__nav");
|
|
4001
|
-
nav.setAttribute("aria-label", "Settings categories");
|
|
4002
|
-
nav.addEventListener("click", (e) => {
|
|
4003
|
-
const btn = e.target.closest?.("[data-category]");
|
|
4004
|
-
if (btn && nav.contains(btn)) this.selectCategory(btn.dataset.category);
|
|
4005
|
-
});
|
|
4006
|
-
this._nav = nav;
|
|
4007
|
-
const resetAll = el2("button", "twm-btn twm-settings__reset-all");
|
|
4008
|
-
resetAll.type = "button";
|
|
4009
|
-
resetAll.append(icon("restart_alt"), el2("span", "", "Reset all"));
|
|
4010
|
-
resetAll.addEventListener("click", () => {
|
|
4011
|
-
this.resetAll();
|
|
4012
|
-
});
|
|
4013
|
-
side.append(head, search, nav, resetAll);
|
|
4027
|
+
if (this._sidebar) {
|
|
4028
|
+
const side = el2("aside", "twm-settings__sidebar");
|
|
4029
|
+
const head = el2("div", "twm-settings__sidebar-title");
|
|
4030
|
+
head.append(icon("settings"), el2("span", "", this._title));
|
|
4031
|
+
const search = filterBox((text) => this.setQuery(text));
|
|
4032
|
+
this._search = search.input;
|
|
4033
|
+
this._nav = categoryNav((id) => this.selectCategory(id));
|
|
4034
|
+
side.append(head, search.label, this._nav, resetAllButton(() => this.resetAll()));
|
|
4035
|
+
root.append(side);
|
|
4036
|
+
}
|
|
4014
4037
|
const content = el2("div", "twm-settings__content");
|
|
4015
4038
|
this._content = content;
|
|
4016
|
-
root.append(
|
|
4039
|
+
root.append(content);
|
|
4017
4040
|
this.root = root;
|
|
4018
4041
|
container.appendChild(root);
|
|
4019
4042
|
this._mounted = true;
|
|
@@ -4024,6 +4047,7 @@ var SettingsView = class extends ComponentBase {
|
|
|
4024
4047
|
this._subs.push(this.eventBus.on("settings:registered", (p) => this.#onRegistered(p)));
|
|
4025
4048
|
this.#paintNav();
|
|
4026
4049
|
this.#paintContent();
|
|
4050
|
+
this.#notify();
|
|
4027
4051
|
return root;
|
|
4028
4052
|
}
|
|
4029
4053
|
/** The category on screen (its id), or null. */
|
|
@@ -4034,6 +4058,19 @@ var SettingsView = class extends ComponentBase {
|
|
|
4034
4058
|
getQuery() {
|
|
4035
4059
|
return this._query;
|
|
4036
4060
|
}
|
|
4061
|
+
/** True while the filter is in effect (its trimmed text is not empty). */
|
|
4062
|
+
isFiltering() {
|
|
4063
|
+
return this.#searching();
|
|
4064
|
+
}
|
|
4065
|
+
/**
|
|
4066
|
+
* `fn({ category, query })` after every change of the category, the filter
|
|
4067
|
+
* or the registered categories, until the view is disposed. Answers the
|
|
4068
|
+
* unsubscribe.
|
|
4069
|
+
*/
|
|
4070
|
+
subscribe(fn) {
|
|
4071
|
+
this._listeners.add(fn);
|
|
4072
|
+
return () => this._listeners.delete(fn);
|
|
4073
|
+
}
|
|
4037
4074
|
/** Show one category; clears the filter. */
|
|
4038
4075
|
selectCategory(id) {
|
|
4039
4076
|
if (!this.root) return;
|
|
@@ -4043,6 +4080,7 @@ var SettingsView = class extends ComponentBase {
|
|
|
4043
4080
|
if (this._search) this._search.value = "";
|
|
4044
4081
|
this.#paintNav();
|
|
4045
4082
|
this.#paintContent();
|
|
4083
|
+
this.#notify();
|
|
4046
4084
|
}
|
|
4047
4085
|
/** Search every category; an empty query goes back to the category. */
|
|
4048
4086
|
setQuery(query) {
|
|
@@ -4052,6 +4090,7 @@ var SettingsView = class extends ComponentBase {
|
|
|
4052
4090
|
if (this._search && this._search.value !== q) this._search.value = q;
|
|
4053
4091
|
this.#paintNav();
|
|
4054
4092
|
this.#paintContent();
|
|
4093
|
+
this.#notify();
|
|
4055
4094
|
}
|
|
4056
4095
|
/** Reset one category after `confirm`; resolves true when it was reset. */
|
|
4057
4096
|
async resetCategory(id = this.getCategory()) {
|
|
@@ -4097,6 +4136,7 @@ var SettingsView = class extends ComponentBase {
|
|
|
4097
4136
|
this._nav = null;
|
|
4098
4137
|
this._content = null;
|
|
4099
4138
|
this._search = null;
|
|
4139
|
+
this._listeners.clear();
|
|
4100
4140
|
super.dispose();
|
|
4101
4141
|
}
|
|
4102
4142
|
// ── store events ─────────────────────────────────────────────────────
|
|
@@ -4115,10 +4155,11 @@ var SettingsView = class extends ComponentBase {
|
|
|
4115
4155
|
const touches = this.#searching() || !this._rows.size || paths.some((p) => schema[p]?.category === active);
|
|
4116
4156
|
if (touches) {
|
|
4117
4157
|
this.#paintContent();
|
|
4118
|
-
|
|
4158
|
+
} else {
|
|
4159
|
+
this.#flushAll();
|
|
4160
|
+
this.#syncAll();
|
|
4119
4161
|
}
|
|
4120
|
-
this.#
|
|
4121
|
-
this.#syncAll();
|
|
4162
|
+
this.#notify();
|
|
4122
4163
|
}
|
|
4123
4164
|
/** True while a filter is in effect: the trimmed query is not empty. */
|
|
4124
4165
|
#searching() {
|
|
@@ -4140,20 +4181,13 @@ var SettingsView = class extends ComponentBase {
|
|
|
4140
4181
|
return cats.find((c) => c.id === this._category) ?? cats[0] ?? null;
|
|
4141
4182
|
}
|
|
4142
4183
|
#paintNav() {
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
b.setAttribute("aria-current", "page");
|
|
4151
|
-
}
|
|
4152
|
-
b.append(icon(cat.icon || "tune"), el2("span", "twm-settings__cat-label", cat.label ?? cat.id));
|
|
4153
|
-
if (cat.description) b.title = String(cat.description);
|
|
4154
|
-
return b;
|
|
4155
|
-
});
|
|
4156
|
-
this._nav.replaceChildren(...buttons);
|
|
4184
|
+
if (!this._nav) return;
|
|
4185
|
+
paintCategories(this._nav, this.store.getCategories(), this.#searching() ? null : this.getCategory());
|
|
4186
|
+
}
|
|
4187
|
+
/** Tell the listeners, after the content is drawn (it settles the category). */
|
|
4188
|
+
#notify() {
|
|
4189
|
+
const state = { category: this.getCategory(), query: this._query };
|
|
4190
|
+
for (const fn of [...this._listeners]) fn(state);
|
|
4157
4191
|
}
|
|
4158
4192
|
#paintContent() {
|
|
4159
4193
|
this.#flushAll();
|
|
@@ -4418,6 +4452,54 @@ var SettingsView = class extends ComponentBase {
|
|
|
4418
4452
|
}
|
|
4419
4453
|
}
|
|
4420
4454
|
};
|
|
4455
|
+
var SettingsCategories = class extends ComponentBase {
|
|
4456
|
+
/**
|
|
4457
|
+
* @param {object} o
|
|
4458
|
+
* @param {SettingsView} o.view the view it lists the categories of
|
|
4459
|
+
*/
|
|
4460
|
+
constructor({ view, logger } = {}) {
|
|
4461
|
+
if (!(view instanceof SettingsView)) {
|
|
4462
|
+
throw new TypeError("SettingsCategories: `view` must be a SettingsView");
|
|
4463
|
+
}
|
|
4464
|
+
super({ eventBus: view.eventBus, logger });
|
|
4465
|
+
this.view = view;
|
|
4466
|
+
this.root = null;
|
|
4467
|
+
this._search = null;
|
|
4468
|
+
this._nav = null;
|
|
4469
|
+
this._unsubscribe = null;
|
|
4470
|
+
}
|
|
4471
|
+
/** Build the list into `container` (once). */
|
|
4472
|
+
mount(container) {
|
|
4473
|
+
if (this.root) return this.root;
|
|
4474
|
+
const view = this.view;
|
|
4475
|
+
const root = el2("div", "twm-settings-categories");
|
|
4476
|
+
const search = filterBox((text) => view.setQuery(text));
|
|
4477
|
+
this._search = search.input;
|
|
4478
|
+
this._nav = categoryNav((id) => view.selectCategory(id));
|
|
4479
|
+
root.append(search.label, this._nav, resetAllButton(() => view.resetAll()));
|
|
4480
|
+
this.root = root;
|
|
4481
|
+
container.appendChild(root);
|
|
4482
|
+
this._mounted = true;
|
|
4483
|
+
this._unsubscribe = view.subscribe(() => this.#paint());
|
|
4484
|
+
this.#paint();
|
|
4485
|
+
return root;
|
|
4486
|
+
}
|
|
4487
|
+
dispose() {
|
|
4488
|
+
this._unsubscribe?.();
|
|
4489
|
+
this._unsubscribe = null;
|
|
4490
|
+
this.root?.remove();
|
|
4491
|
+
this.root = null;
|
|
4492
|
+
this._search = null;
|
|
4493
|
+
this._nav = null;
|
|
4494
|
+
super.dispose();
|
|
4495
|
+
}
|
|
4496
|
+
#paint() {
|
|
4497
|
+
const view = this.view;
|
|
4498
|
+
const q = view.getQuery();
|
|
4499
|
+
if (this._search.value !== q) this._search.value = q;
|
|
4500
|
+
paintCategories(this._nav, view.store.getCategories(), view.isFiltering() ? null : view.getCategory());
|
|
4501
|
+
}
|
|
4502
|
+
};
|
|
4421
4503
|
function settingsViewContent(opts = {}) {
|
|
4422
4504
|
return (hostEl, props = {}) => {
|
|
4423
4505
|
const view = new SettingsView({ ...opts, category: props?.category ?? opts.category ?? null });
|
|
@@ -6607,6 +6689,7 @@ var SUPPRESSED_NAMESPACE_TITLES = /* @__PURE__ */ new Set(["bootstrap", "app"]);
|
|
|
6607
6689
|
var NotificationCenter = class _NotificationCenter extends ComponentBase {
|
|
6608
6690
|
#items;
|
|
6609
6691
|
#summaryEl;
|
|
6692
|
+
#historyListeners;
|
|
6610
6693
|
constructor({
|
|
6611
6694
|
eventBus,
|
|
6612
6695
|
logger,
|
|
@@ -6637,6 +6720,7 @@ var NotificationCenter = class _NotificationCenter extends ComponentBase {
|
|
|
6637
6720
|
this.eventDisposers = [];
|
|
6638
6721
|
this.#items = /* @__PURE__ */ new Map();
|
|
6639
6722
|
this.#summaryEl = null;
|
|
6723
|
+
this.#historyListeners = /* @__PURE__ */ new Set();
|
|
6640
6724
|
this.container = null;
|
|
6641
6725
|
this.rootEl = null;
|
|
6642
6726
|
this.listEl = null;
|
|
@@ -6648,7 +6732,7 @@ var NotificationCenter = class _NotificationCenter extends ComponentBase {
|
|
|
6648
6732
|
this.container = existingContainer;
|
|
6649
6733
|
this.rootEl = existingContainer.querySelector(".twm-notification-center");
|
|
6650
6734
|
this.listEl = existingContainer.querySelector(".twm-notification-center__list");
|
|
6651
|
-
this.liveRegionEl = existingContainer.querySelector(".notification-center__live-region");
|
|
6735
|
+
this.liveRegionEl = existingContainer.querySelector(".twm-notification-center__live-region");
|
|
6652
6736
|
this._mounted = true;
|
|
6653
6737
|
this.#subscribeEvents();
|
|
6654
6738
|
this.#claimToastBus();
|
|
@@ -6662,7 +6746,7 @@ var NotificationCenter = class _NotificationCenter extends ComponentBase {
|
|
|
6662
6746
|
this.listEl = document.createElement("div");
|
|
6663
6747
|
this.listEl.className = "twm-notification-center__list";
|
|
6664
6748
|
this.liveRegionEl = document.createElement("div");
|
|
6665
|
-
this.liveRegionEl.className = "notification-center__live-region";
|
|
6749
|
+
this.liveRegionEl.className = "twm-notification-center__live-region";
|
|
6666
6750
|
this.liveRegionEl.setAttribute("aria-live", "polite");
|
|
6667
6751
|
this.liveRegionEl.setAttribute("aria-atomic", "true");
|
|
6668
6752
|
this.liveRegionEl.style.position = "absolute";
|
|
@@ -6685,6 +6769,7 @@ var NotificationCenter = class _NotificationCenter extends ComponentBase {
|
|
|
6685
6769
|
dispose() {
|
|
6686
6770
|
this.#clearTimers();
|
|
6687
6771
|
this.#unsubscribeEvents();
|
|
6772
|
+
this.#historyListeners.clear();
|
|
6688
6773
|
if (this.eventBus && getToastBus() === this.eventBus) setToastBus(null);
|
|
6689
6774
|
this.#items.forEach((entry) => entry.bar?.dispose());
|
|
6690
6775
|
this.#items.clear();
|
|
@@ -6717,7 +6802,7 @@ var NotificationCenter = class _NotificationCenter extends ComponentBase {
|
|
|
6717
6802
|
if (idx !== -1) {
|
|
6718
6803
|
const [removed] = this.notifications.splice(idx, 1);
|
|
6719
6804
|
this.#stopTimer(removed.id);
|
|
6720
|
-
this.#
|
|
6805
|
+
this.#recordDismissal(removed, "overflow");
|
|
6721
6806
|
}
|
|
6722
6807
|
}
|
|
6723
6808
|
this.#recordHistory(normalized);
|
|
@@ -6732,13 +6817,13 @@ var NotificationCenter = class _NotificationCenter extends ComponentBase {
|
|
|
6732
6817
|
const h = this.held.findIndex((item) => item.id === notificationId);
|
|
6733
6818
|
if (h === -1) return false;
|
|
6734
6819
|
const [gone] = this.held.splice(h, 1);
|
|
6735
|
-
this.#
|
|
6820
|
+
this.#recordDismissal(gone, reason);
|
|
6736
6821
|
this.#render();
|
|
6737
6822
|
return true;
|
|
6738
6823
|
}
|
|
6739
6824
|
const [removed] = this.notifications.splice(idx, 1);
|
|
6740
6825
|
this.#stopTimer(notificationId);
|
|
6741
|
-
this.#
|
|
6826
|
+
this.#recordDismissal(removed, reason);
|
|
6742
6827
|
this.#rebalance();
|
|
6743
6828
|
this.#render();
|
|
6744
6829
|
return true;
|
|
@@ -6965,12 +7050,40 @@ var NotificationCenter = class _NotificationCenter extends ComponentBase {
|
|
|
6965
7050
|
this.activeTimers.forEach((timer) => clearTimeout(timer));
|
|
6966
7051
|
this.activeTimers.clear();
|
|
6967
7052
|
}
|
|
7053
|
+
/**
|
|
7054
|
+
* Hear of every entry added to `history`, by `show()`, `warn()`/`error()`/
|
|
7055
|
+
* `info()`/`success()` and the bus alike: `listener(entry, center)`, once
|
|
7056
|
+
* per toast, after the entry is in `history`. A dismissal changes the
|
|
7057
|
+
* toast's own entry and is not an entry of its own. Answers the unsubscribe.
|
|
7058
|
+
*/
|
|
7059
|
+
subscribe(listener) {
|
|
7060
|
+
if (typeof listener !== "function") return () => {
|
|
7061
|
+
};
|
|
7062
|
+
this.#historyListeners.add(listener);
|
|
7063
|
+
return () => {
|
|
7064
|
+
this.#historyListeners.delete(listener);
|
|
7065
|
+
};
|
|
7066
|
+
}
|
|
6968
7067
|
#recordHistory(entry) {
|
|
6969
7068
|
if (entry.skipHistory) return;
|
|
6970
7069
|
this.history.push(entry);
|
|
6971
7070
|
if (this.history.length > this.historyLimit) {
|
|
6972
7071
|
this.history.shift();
|
|
6973
7072
|
}
|
|
7073
|
+
[...this.#historyListeners].forEach((listener) => {
|
|
7074
|
+
try {
|
|
7075
|
+
listener(entry, this);
|
|
7076
|
+
} catch (err) {
|
|
7077
|
+
this.logger?.warn?.("twm-notification-center", "History listener failed", { err });
|
|
7078
|
+
}
|
|
7079
|
+
});
|
|
7080
|
+
}
|
|
7081
|
+
/** A toast that left marks its own entry: one toast, one entry. */
|
|
7082
|
+
#recordDismissal(notification, reason) {
|
|
7083
|
+
if (notification.skipHistory) return;
|
|
7084
|
+
const at = this.history.findLastIndex((entry) => entry.id === notification.id);
|
|
7085
|
+
if (at === -1) return;
|
|
7086
|
+
this.history[at] = { ...notification, dismissed: true, reason };
|
|
6974
7087
|
}
|
|
6975
7088
|
/** A progress toast that has not been given an outcome yet. */
|
|
6976
7089
|
static #isRunning(notification) {
|
|
@@ -7085,7 +7198,7 @@ var NotificationCenter = class _NotificationCenter extends ComponentBase {
|
|
|
7085
7198
|
if (!this.#summaryEl) {
|
|
7086
7199
|
const more2 = document.createElement("button");
|
|
7087
7200
|
more2.type = "button";
|
|
7088
|
-
more2.className = "notification twm-notification--summary";
|
|
7201
|
+
more2.className = "twm-notification twm-notification--summary";
|
|
7089
7202
|
more2.addEventListener("click", () => {
|
|
7090
7203
|
const held = [...this.held];
|
|
7091
7204
|
try {
|
|
@@ -7212,8 +7325,8 @@ var NotificationCenter = class _NotificationCenter extends ComponentBase {
|
|
|
7212
7325
|
#patchItem(entry, notification) {
|
|
7213
7326
|
const item = entry.el;
|
|
7214
7327
|
if (entry.severity !== notification.severity) {
|
|
7215
|
-
if (entry.severity) item.classList.remove(`notification--${entry.severity}`);
|
|
7216
|
-
item.classList.add("notification", `notification--${notification.severity}`);
|
|
7328
|
+
if (entry.severity) item.classList.remove(`twm-notification--${entry.severity}`);
|
|
7329
|
+
item.classList.add("twm-notification", `twm-notification--${notification.severity}`);
|
|
7217
7330
|
entry.severity = notification.severity;
|
|
7218
7331
|
}
|
|
7219
7332
|
if (entry.titleEl) _NotificationCenter.#setText(entry.titleEl, notification.title);
|
|
@@ -8393,6 +8506,7 @@ export {
|
|
|
8393
8506
|
SCALAR_TYPES,
|
|
8394
8507
|
SETTINGS_TEXT_DEBOUNCE_MS,
|
|
8395
8508
|
STEP_STATES,
|
|
8509
|
+
SettingsCategories,
|
|
8396
8510
|
SettingsView,
|
|
8397
8511
|
SlideOutPanel,
|
|
8398
8512
|
SliderField,
|