@wpmoo/ui 1.3.0 → 1.4.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/dist/js/chart.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Moo UI chart.js v1.3.0 (https://wpmoo.org/)
2
+ * Moo UI chart.js v1.4.0 (https://wpmoo.org/)
3
3
  * Copyright 2026 WPMoo Authors
4
4
  * Licensed under MIT (https://github.com/wpmoo-org/ui/blob/main/LICENSE)
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Moo UI chart.min.js v1.3.0 (https://wpmoo.org/)
2
+ * Moo UI chart.min.js v1.4.0 (https://wpmoo.org/)
3
3
  * Copyright 2026 WPMoo Authors
4
4
  * Licensed under MIT (https://github.com/wpmoo-org/ui/blob/main/LICENSE)
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Moo UI combobox.js v1.3.0 (https://wpmoo.org/)
2
+ * Moo UI combobox.js v1.4.0 (https://wpmoo.org/)
3
3
  * Copyright 2026 WPMoo Authors
4
4
  * Licensed under MIT (https://github.com/wpmoo-org/ui/blob/main/LICENSE)
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Moo UI context-menu.js v1.3.0 (https://wpmoo.org/)
2
+ * Moo UI context-menu.js v1.4.0 (https://wpmoo.org/)
3
3
  * Copyright 2026 WPMoo Authors
4
4
  * Licensed under MIT (https://github.com/wpmoo-org/ui/blob/main/LICENSE)
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Moo UI datatable.js v1.3.0 (https://wpmoo.org/)
2
+ * Moo UI datatable.js v1.4.0 (https://wpmoo.org/)
3
3
  * Copyright 2026 WPMoo Authors
4
4
  * Licensed under MIT (https://github.com/wpmoo-org/ui/blob/main/LICENSE)
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Moo UI datepicker.js v1.3.0 (https://wpmoo.org/)
2
+ * Moo UI datepicker.js v1.4.0 (https://wpmoo.org/)
3
3
  * Copyright 2026 WPMoo Authors
4
4
  * Licensed under MIT (https://github.com/wpmoo-org/ui/blob/main/LICENSE)
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Moo UI datepicker.min.js v1.3.0 (https://wpmoo.org/)
2
+ * Moo UI datepicker.min.js v1.4.0 (https://wpmoo.org/)
3
3
  * Copyright 2026 WPMoo Authors
4
4
  * Licensed under MIT (https://github.com/wpmoo-org/ui/blob/main/LICENSE)
5
5
  */
package/dist/js/moo-ui.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Moo UI moo-ui.js v1.3.0 (https://wpmoo.org/)
2
+ * Moo UI moo-ui.js v1.4.0 (https://wpmoo.org/)
3
3
  * Copyright 2026 WPMoo Authors
4
4
  * Licensed under MIT (https://github.com/wpmoo-org/ui/blob/main/LICENSE)
5
5
  */
@@ -4068,6 +4068,307 @@ var TableOfContents = class _TableOfContents {
4068
4068
  }
4069
4069
  };
4070
4070
 
4071
+ // src/js/components/overlay-scrollbar.js
4072
+ var instances7 = /* @__PURE__ */ new WeakMap();
4073
+ var nextId = 0;
4074
+ var OverlayScrollbar = class _OverlayScrollbar {
4075
+ static getInstance(owner, scrollElement = owner?.ownerDocument?.scrollingElement) {
4076
+ const instance = scrollElement && instances7.get(scrollElement);
4077
+ return instance?._owner === owner ? instance : null;
4078
+ }
4079
+ static getOrCreateInstance(owner, options = {}) {
4080
+ return _OverlayScrollbar.getInstance(owner, options.scrollElement) || new _OverlayScrollbar(owner, options);
4081
+ }
4082
+ constructor(owner, { scrollElement = null, hideDelay = 900, label = "Page scroll position" } = {}) {
4083
+ if (!owner?.matches?.('.moo-ui[data-bs-theme="light"], .moo-ui[data-bs-theme="dark"]') || !owner.isConnected) {
4084
+ throw new TypeError("OverlayScrollbar requires a connected, resolved .moo-ui theme owner.");
4085
+ }
4086
+ if (!Number.isFinite(hideDelay) || hideDelay < 0 || typeof label !== "string" || !label.trim()) {
4087
+ throw new TypeError("OverlayScrollbar requires a nonnegative hideDelay and a nonempty label.");
4088
+ }
4089
+ const document2 = owner.ownerDocument;
4090
+ const root = scrollElement ?? document2.scrollingElement;
4091
+ const isDocument = root === document2.scrollingElement;
4092
+ if (root?.nodeType !== 1 || !root.isConnected || root.ownerDocument !== document2 || !isDocument && (!owner.contains(root) || root.closest('.moo-ui[data-bs-theme="light"], .moo-ui[data-bs-theme="dark"]') !== owner)) {
4093
+ throw new TypeError("OverlayScrollbar scrollElement must belong to the same resolved theme owner.");
4094
+ }
4095
+ const existing = instances7.get(root);
4096
+ if (existing) {
4097
+ if (existing._owner === owner) return existing;
4098
+ throw new Error("Only one OverlayScrollbar theme owner may control a scroll element.");
4099
+ }
4100
+ this._owner = owner;
4101
+ this._document = document2;
4102
+ this._window = document2.defaultView;
4103
+ this._root = root;
4104
+ this._isDocument = isDocument;
4105
+ if (isDocument && root !== document2.documentElement) {
4106
+ throw new TypeError("OverlayScrollbar requires a standards-mode document scroll root.");
4107
+ }
4108
+ this._hideDelay = hideDelay;
4109
+ this._listeners = [];
4110
+ this._frame = 0;
4111
+ this._timer = 0;
4112
+ this._disposed = false;
4113
+ this._originalNativeClass = this._root.classList.contains("scrollbar-overlay-native");
4114
+ this._originalId = this._root.getAttribute("id");
4115
+ this._forcedColors = this._window.matchMedia("(forced-colors: active)");
4116
+ this._bar = document2.createElement("div");
4117
+ this._bar.className = "scrollbar-overlay";
4118
+ this._bar.tabIndex = 0;
4119
+ this._bar.setAttribute("role", "scrollbar");
4120
+ this._bar.setAttribute("aria-label", label);
4121
+ this._bar.setAttribute("aria-orientation", "vertical");
4122
+ this._bar.setAttribute("aria-valuemin", "0");
4123
+ this._thumb = document2.createElement("div");
4124
+ this._thumb.className = "scrollbar-overlay-thumb";
4125
+ this._thumb.setAttribute("aria-hidden", "true");
4126
+ this._bar.append(this._thumb);
4127
+ owner.append(this._bar);
4128
+ if (this._window.getComputedStyle(this._bar).position !== "fixed") {
4129
+ this._bar.remove();
4130
+ throw new Error("OverlayScrollbar requires the Moo UI overlay scrollbar stylesheet.");
4131
+ }
4132
+ if (!this._originalId) {
4133
+ do {
4134
+ this._generatedId = `scrollbar-overlay-page-${++nextId}`;
4135
+ } while (document2.getElementById(this._generatedId));
4136
+ this._root.id = this._generatedId;
4137
+ }
4138
+ this._bar.setAttribute("aria-controls", this._root.id);
4139
+ instances7.set(root, this);
4140
+ try {
4141
+ this._listen(isDocument ? this._window : root, "scroll", () => {
4142
+ this._reveal();
4143
+ this._queue();
4144
+ }, { passive: true });
4145
+ if (!isDocument) {
4146
+ this._listen(document2, "scroll", () => this._queue(), { passive: true, capture: true });
4147
+ }
4148
+ this._listen(this._window, "resize", () => this._queue());
4149
+ this._listen(document2, "pointermove", (event) => this._onPointerMove(event), { passive: true });
4150
+ this._listen(document2, "pointerout", (event) => {
4151
+ if (event.pointerType === "mouse" && !event.relatedTarget) {
4152
+ this._nearEdge = false;
4153
+ if (!this._drag) delete this._bar.dataset.scrollbarInteractive;
4154
+ this._hideLater();
4155
+ }
4156
+ });
4157
+ this._listen(this._bar, "pointerdown", (event) => this._onPointerDown(event));
4158
+ this._listen(this._bar, "pointerup", () => this._finishDrag());
4159
+ this._listen(this._bar, "pointercancel", () => this._finishDrag());
4160
+ this._listen(this._bar, "lostpointercapture", () => this._finishDrag());
4161
+ this._listen(this._bar, "focus", () => this._reveal());
4162
+ this._listen(this._bar, "blur", () => this._hideLater());
4163
+ this._listen(this._bar, "keydown", (event) => this._onKeyDown(event));
4164
+ this._listen(this._forcedColors, "change", () => this.refresh());
4165
+ this._listen(this._window, "beforeprint", () => {
4166
+ this._printing = true;
4167
+ this.refresh();
4168
+ });
4169
+ this._listen(this._window, "afterprint", () => {
4170
+ this._printing = false;
4171
+ this.refresh();
4172
+ });
4173
+ this._resize = new this._window.ResizeObserver(() => this._queue());
4174
+ this._resize.observe(this._root);
4175
+ this._resize.observe(document2.body);
4176
+ this._mutations = new this._window.MutationObserver(() => this._queue());
4177
+ this._mutations.observe(this._root, { attributes: true, attributeFilter: ["class", "style", "dir"] });
4178
+ if (!isDocument) {
4179
+ this._mutations.observe(document2.documentElement, { attributes: true, attributeFilter: ["class", "style", "dir"] });
4180
+ }
4181
+ this._mutations.observe(document2.body, {
4182
+ attributes: true,
4183
+ attributeFilter: ["class", "style"]
4184
+ });
4185
+ this._mutations.observe(owner, { attributes: true, attributeFilter: ["class", "style", "dir", "data-bs-theme"] });
4186
+ this._contentMutations = new this._window.MutationObserver((records) => {
4187
+ if (records.some((record) => record.target !== this._bar && !this._bar.contains(record.target))) this._queue();
4188
+ });
4189
+ this._contentMutations.observe(isDocument ? document2.body : root, {
4190
+ childList: true,
4191
+ subtree: true,
4192
+ attributes: true,
4193
+ attributeFilter: ["class", "style", "hidden"]
4194
+ });
4195
+ this._listen(root, "load", () => this._queue(), { capture: true });
4196
+ if (document2.fonts) this._listen(document2.fonts, "loadingdone", () => this._queue());
4197
+ this.refresh();
4198
+ } catch (error) {
4199
+ this.dispose();
4200
+ throw error;
4201
+ }
4202
+ }
4203
+ refresh() {
4204
+ if (this._disposed) return this;
4205
+ const window2 = this._window;
4206
+ const root = this._root;
4207
+ const eligible = !this._forcedColors.matches && !this._printing;
4208
+ if (eligible) root.classList.add("scrollbar-overlay-native");
4209
+ const enabled = eligible && root.scrollWidth <= root.clientWidth + 1;
4210
+ root.classList.toggle("scrollbar-overlay-native", this._originalNativeClass || enabled);
4211
+ this._mutations?.takeRecords();
4212
+ this._contentMutations?.takeRecords();
4213
+ const locked = (this._isDocument ? [root, this._document.body] : [root]).some((element) => ["hidden", "clip"].includes(window2.getComputedStyle(element).overflowY));
4214
+ this._maximum = Math.max(0, root.scrollHeight - root.clientHeight);
4215
+ const visible = this._position();
4216
+ this._bar.hidden = !enabled || locked || !visible || this._maximum <= 0;
4217
+ if (this._bar.hidden) {
4218
+ if (this._document.activeElement === this._bar) this._bar.blur();
4219
+ delete this._bar.dataset.scrollbarVisible;
4220
+ delete this._bar.dataset.scrollbarInteractive;
4221
+ return this;
4222
+ }
4223
+ const minimum = this._bar.clientWidth;
4224
+ const height = this._bar.clientHeight;
4225
+ const thumbHeight = Math.min(height, Math.max(minimum, height * root.clientHeight / root.scrollHeight));
4226
+ this._travel = Math.max(0, height - thumbHeight);
4227
+ const position = Math.min(this._maximum, Math.max(0, root.scrollTop));
4228
+ this._thumb.style.height = `${thumbHeight}px`;
4229
+ this._thumb.style.transform = `translateY(${this._travel * position / this._maximum}px)`;
4230
+ this._bar.setAttribute("aria-valuemax", String(Math.round(this._maximum)));
4231
+ this._bar.setAttribute("aria-valuenow", String(Math.round(position)));
4232
+ return this;
4233
+ }
4234
+ _position() {
4235
+ if (this._isDocument) return true;
4236
+ const root = this._root;
4237
+ const bounds = root.getBoundingClientRect();
4238
+ const top = Math.max(0, bounds.top + root.clientTop);
4239
+ const bottom = Math.min(this._window.innerHeight, bounds.top + root.clientTop + root.clientHeight);
4240
+ const width = parseFloat(this._window.getComputedStyle(this._bar).inlineSize);
4241
+ const rtl = this._window.getComputedStyle(root).direction === "rtl";
4242
+ const left = bounds.left + root.clientLeft + (rtl ? 0 : root.clientWidth - width);
4243
+ Object.assign(this._bar.style, {
4244
+ insetInlineEnd: "auto",
4245
+ bottom: "auto",
4246
+ top: `${top}px`,
4247
+ height: `${Math.max(0, bottom - top)}px`,
4248
+ left: `${Math.max(0, Math.min(this._window.innerWidth - width, left))}px`,
4249
+ direction: rtl ? "rtl" : "ltr"
4250
+ });
4251
+ return bounds.width > 0 && bottom > top && left < this._window.innerWidth && left + width > 0;
4252
+ }
4253
+ dispose() {
4254
+ if (this._disposed) return;
4255
+ this._disposed = true;
4256
+ for (const [target, type, handler, options] of this._listeners) {
4257
+ target.removeEventListener(type, handler, options);
4258
+ }
4259
+ this._listeners = [];
4260
+ this._resize?.disconnect();
4261
+ this._mutations?.disconnect();
4262
+ this._contentMutations?.disconnect();
4263
+ this._window.cancelAnimationFrame(this._frame);
4264
+ this._window.clearTimeout(this._timer);
4265
+ if (this._drag && this._bar.hasPointerCapture(this._drag.id)) this._bar.releasePointerCapture(this._drag.id);
4266
+ this._drag = null;
4267
+ this._bar.remove();
4268
+ this._root.classList.toggle("scrollbar-overlay-native", this._originalNativeClass);
4269
+ if (this._generatedId && this._root.id === this._generatedId) {
4270
+ if (this._originalId === null) this._root.removeAttribute("id");
4271
+ else this._root.setAttribute("id", this._originalId);
4272
+ }
4273
+ if (instances7.get(this._root) === this) instances7.delete(this._root);
4274
+ }
4275
+ _listen(target, type, handler, options) {
4276
+ target.addEventListener(type, handler, options);
4277
+ this._listeners.push([target, type, handler, options]);
4278
+ }
4279
+ _queue() {
4280
+ if (this._disposed || this._frame) return;
4281
+ this._frame = this._window.requestAnimationFrame(() => {
4282
+ this._frame = 0;
4283
+ this.refresh();
4284
+ });
4285
+ }
4286
+ _reveal() {
4287
+ if (this._disposed || this._bar.hidden) return;
4288
+ this._bar.dataset.scrollbarVisible = "true";
4289
+ this._hideLater();
4290
+ }
4291
+ _hideLater() {
4292
+ this._window.clearTimeout(this._timer);
4293
+ this._timer = 0;
4294
+ if (this._disposed) return;
4295
+ if (!this._bar.hasAttribute("data-scrollbar-visible")) return;
4296
+ this._timer = this._window.setTimeout(() => {
4297
+ this._timer = 0;
4298
+ if (this._disposed || this._nearEdge || this._drag || this._bar.matches(":focus-visible")) return;
4299
+ delete this._bar.dataset.scrollbarVisible;
4300
+ }, this._hideDelay);
4301
+ }
4302
+ _onPointerMove(event) {
4303
+ if (this._disposed) return;
4304
+ if (this._drag?.id === event.pointerId) {
4305
+ if (this._travel) this._scroll(this._drag.top + (event.clientY - this._drag.y) * this._maximum / this._travel);
4306
+ return;
4307
+ }
4308
+ if (event.pointerType !== "mouse") {
4309
+ this._nearEdge = false;
4310
+ if (!this._drag) delete this._bar.dataset.scrollbarInteractive;
4311
+ return;
4312
+ }
4313
+ const bounds = this._bar.getBoundingClientRect();
4314
+ const nearEdge = !this._bar.hidden && event.clientX >= bounds.left && event.clientX <= bounds.right && event.clientY >= bounds.top && event.clientY <= bounds.bottom;
4315
+ if (nearEdge) {
4316
+ this._nearEdge = true;
4317
+ this._bar.dataset.scrollbarInteractive = "true";
4318
+ this._reveal();
4319
+ } else if (this._nearEdge) {
4320
+ this._nearEdge = false;
4321
+ if (!this._drag) delete this._bar.dataset.scrollbarInteractive;
4322
+ this._hideLater();
4323
+ }
4324
+ }
4325
+ _onPointerDown(event) {
4326
+ if (event.button !== 0 || this._bar.hidden || event.pointerType === "touch") return;
4327
+ event.preventDefault();
4328
+ this._reveal();
4329
+ const thumb = this._thumb.getBoundingClientRect();
4330
+ if (event.clientY >= thumb.top && event.clientY <= thumb.bottom) {
4331
+ this._drag = { id: event.pointerId, y: event.clientY, top: this._root.scrollTop };
4332
+ this._bar.setPointerCapture(event.pointerId);
4333
+ } else {
4334
+ const direction = event.clientY < this._thumb.getBoundingClientRect().top ? -1 : 1;
4335
+ this._scroll(this._root.scrollTop + direction * this._root.clientHeight);
4336
+ }
4337
+ }
4338
+ _finishDrag() {
4339
+ if (!this._drag || this._disposed) return;
4340
+ const id = this._drag.id;
4341
+ this._drag = null;
4342
+ if (!this._nearEdge) delete this._bar.dataset.scrollbarInteractive;
4343
+ if (this._bar.hasPointerCapture(id)) this._bar.releasePointerCapture(id);
4344
+ this._hideLater();
4345
+ }
4346
+ _onKeyDown(event) {
4347
+ if (event.altKey || event.ctrlKey || event.metaKey) return;
4348
+ this.refresh();
4349
+ const step = parseFloat(this._window.getComputedStyle(this._root).lineHeight) || 16;
4350
+ const page = this._root.clientHeight;
4351
+ const targets = {
4352
+ ArrowUp: this._root.scrollTop - step,
4353
+ ArrowDown: this._root.scrollTop + step,
4354
+ PageUp: this._root.scrollTop - page,
4355
+ PageDown: this._root.scrollTop + page,
4356
+ Home: 0,
4357
+ End: this._maximum,
4358
+ " ": this._root.scrollTop + (event.shiftKey ? -page : page)
4359
+ };
4360
+ if (!Object.hasOwn(targets, event.key)) return;
4361
+ event.preventDefault();
4362
+ this._scroll(targets[event.key]);
4363
+ this._reveal();
4364
+ }
4365
+ _scroll(top) {
4366
+ const target = this._isDocument ? this._window : this._root;
4367
+ target.scrollTo({ top: Math.min(this._maximum, Math.max(0, top)), behavior: "instant" });
4368
+ this._queue();
4369
+ }
4370
+ };
4371
+
4071
4372
  // src/js/components/sheet.js
4072
4373
  var states = /* @__PURE__ */ new WeakMap();
4073
4374
  function initSheets(root = document) {
@@ -4122,6 +4423,7 @@ var MooUI = {
4122
4423
  Sidebar,
4123
4424
  Slider: MooSlider,
4124
4425
  TableOfContents,
4426
+ OverlayScrollbar,
4125
4427
  initSheets
4126
4428
  };
4127
4429
  var moo_ui_default = MooUI;
@@ -4132,6 +4434,7 @@ export {
4132
4434
  MooDatepicker as Datepicker,
4133
4435
  MooCalendar,
4134
4436
  MooDateRangePicker,
4437
+ OverlayScrollbar,
4135
4438
  Sidebar,
4136
4439
  MooSlider as Slider,
4137
4440
  TableOfContents,