@wpmoo/ui 1.4.3 → 2.0.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.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Moo UI combobox.js v1.4.3 (https://wpmoo.org/)
2
+ * Moo UI combobox.js v2.0.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.4.3 (https://wpmoo.org/)
2
+ * Moo UI context-menu.js v2.0.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.4.3 (https://wpmoo.org/)
2
+ * Moo UI datatable.js v2.0.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.4.3 (https://wpmoo.org/)
2
+ * Moo UI datepicker.js v2.0.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.4.3 (https://wpmoo.org/)
2
+ * Moo UI datepicker.min.js v2.0.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
  */
@@ -0,0 +1,106 @@
1
+ /*!
2
+ * Moo UI floating-panel.js v2.0.0 (https://wpmoo.org/)
3
+ * Copyright 2026 WPMoo Authors
4
+ * Licensed under MIT (https://github.com/wpmoo-org/ui/blob/main/LICENSE)
5
+ */
6
+
7
+ const instances = /* @__PURE__ */ new WeakMap();
8
+ const memory = /* @__PURE__ */ new WeakMap();
9
+ function canFocus(control) {
10
+ return control.isConnected && !control.matches(":disabled") && control.getClientRects().length > 0 && !control.closest("[hidden], [inert]") && control.ownerDocument.defaultView.getComputedStyle(control).visibility === "visible";
11
+ }
12
+ class FloatingPanel {
13
+ static getInstance(panel) {
14
+ return instances.get(panel) || null;
15
+ }
16
+ static getOrCreateInstance(panel) {
17
+ return instances.get(panel) || new FloatingPanel(panel);
18
+ }
19
+ constructor(panel) {
20
+ if (instances.has(panel)) return instances.get(panel);
21
+ if (!panel?.matches?.("[data-floating-panel]") || !panel.id) {
22
+ throw new TypeError("FloatingPanel requires a named panel");
23
+ }
24
+ this.panel = panel;
25
+ this.document = panel.ownerDocument;
26
+ this.owner = panel.closest(".moo-ui");
27
+ this.initialHidden = panel.hidden;
28
+ this.controls = /* @__PURE__ */ new Map();
29
+ this.launcher = null;
30
+ this.key = panel.dataset.floatingPanelKey ? `moo-floating-panel:${panel.dataset.floatingPanelKey}` : "";
31
+ const view = this.document.defaultView;
32
+ if (!memory.has(view)) memory.set(view, /* @__PURE__ */ new Map());
33
+ this.memory = memory.get(view);
34
+ this.onClick = (event) => this.handleControl(event);
35
+ this.document.addEventListener("click", this.onClick);
36
+ instances.set(panel, this);
37
+ let dismissed = this.memory.get(this.key) || false;
38
+ if (this.key && !this.memory.has(this.key)) {
39
+ try {
40
+ dismissed = view.localStorage.getItem(this.key) === "dismissed";
41
+ } catch {
42
+ }
43
+ }
44
+ this.setVisible(!dismissed);
45
+ panel.dataset.floatingPanelReady = "true";
46
+ }
47
+ launchers() {
48
+ return [...this.document.querySelectorAll("[data-floating-panel-open]")].filter((control) => control.dataset.floatingPanelOpen === this.panel.id && control.closest(".moo-ui") === this.owner);
49
+ }
50
+ setVisible(visible) {
51
+ this.panel.hidden = !visible;
52
+ this.panel.dataset.floatingPanelState = visible ? "visible" : "dismissed";
53
+ this.launchers().forEach((control) => {
54
+ if (!this.controls.has(control)) this.controls.set(control, {
55
+ controls: control.getAttribute("aria-controls"),
56
+ expanded: control.getAttribute("aria-expanded")
57
+ });
58
+ control.setAttribute("aria-controls", this.panel.id);
59
+ control.setAttribute("aria-expanded", String(visible));
60
+ });
61
+ }
62
+ handleControl(event) {
63
+ const control = event.target.closest?.("[data-floating-panel-open], [data-floating-panel-dismiss]");
64
+ if (!control || control.matches(":disabled") || control.closest(".moo-ui") !== this.owner) return;
65
+ const opening = control.hasAttribute("data-floating-panel-open");
66
+ if ((opening ? control.dataset.floatingPanelOpen : control.dataset.floatingPanelDismiss) !== this.panel.id) return;
67
+ if (!opening && !this.panel.contains(control)) return;
68
+ event.preventDefault();
69
+ if (opening) this.launcher = control;
70
+ if (this.key) {
71
+ try {
72
+ const storage = this.document.defaultView.localStorage;
73
+ if (opening) storage.removeItem(this.key);
74
+ else storage.setItem(this.key, "dismissed");
75
+ this.memory.delete(this.key);
76
+ } catch {
77
+ this.memory.set(this.key, !opening);
78
+ }
79
+ }
80
+ this.setVisible(opening);
81
+ if (opening) {
82
+ [...this.panel.querySelectorAll("button, a[href], input:not([type='hidden']), select, textarea, [tabindex]")].find((control2) => control2.tabIndex >= 0 && canFocus(control2))?.focus({ preventScroll: true });
83
+ } else {
84
+ const launchers = this.launchers().filter(canFocus);
85
+ const launcher = launchers.includes(this.launcher) ? this.launcher : launchers[0];
86
+ launcher?.focus({ preventScroll: true });
87
+ }
88
+ }
89
+ dispose() {
90
+ if (instances.get(this.panel) !== this) return;
91
+ this.document.removeEventListener("click", this.onClick);
92
+ this.panel.hidden = this.initialHidden;
93
+ delete this.panel.dataset.floatingPanelReady;
94
+ delete this.panel.dataset.floatingPanelState;
95
+ this.controls.forEach((attrs, control) => {
96
+ for (const [name, value] of [["aria-controls", attrs.controls], ["aria-expanded", attrs.expanded]]) {
97
+ if (value === null) control.removeAttribute(name);
98
+ else control.setAttribute(name, value);
99
+ }
100
+ });
101
+ instances.delete(this.panel);
102
+ }
103
+ }
104
+ export {
105
+ FloatingPanel as default
106
+ };
package/dist/js/moo-ui.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Moo UI moo-ui.js v1.4.3 (https://wpmoo.org/)
2
+ * Moo UI moo-ui.js v2.0.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
  */
@@ -4409,12 +4409,114 @@ function initSheets(root = document) {
4409
4409
  return dispose;
4410
4410
  }
4411
4411
 
4412
+ // src/js/components/floating-panel.js
4413
+ var instances8 = /* @__PURE__ */ new WeakMap();
4414
+ var memory = /* @__PURE__ */ new WeakMap();
4415
+ function canFocus(control) {
4416
+ return control.isConnected && !control.matches(":disabled") && control.getClientRects().length > 0 && !control.closest("[hidden], [inert]") && control.ownerDocument.defaultView.getComputedStyle(control).visibility === "visible";
4417
+ }
4418
+ var FloatingPanel = class _FloatingPanel {
4419
+ static getInstance(panel) {
4420
+ return instances8.get(panel) || null;
4421
+ }
4422
+ static getOrCreateInstance(panel) {
4423
+ return instances8.get(panel) || new _FloatingPanel(panel);
4424
+ }
4425
+ constructor(panel) {
4426
+ if (instances8.has(panel)) return instances8.get(panel);
4427
+ if (!panel?.matches?.("[data-floating-panel]") || !panel.id) {
4428
+ throw new TypeError("FloatingPanel requires a named panel");
4429
+ }
4430
+ this.panel = panel;
4431
+ this.document = panel.ownerDocument;
4432
+ this.owner = panel.closest(".moo-ui");
4433
+ this.initialHidden = panel.hidden;
4434
+ this.controls = /* @__PURE__ */ new Map();
4435
+ this.launcher = null;
4436
+ this.key = panel.dataset.floatingPanelKey ? `moo-floating-panel:${panel.dataset.floatingPanelKey}` : "";
4437
+ const view = this.document.defaultView;
4438
+ if (!memory.has(view)) memory.set(view, /* @__PURE__ */ new Map());
4439
+ this.memory = memory.get(view);
4440
+ this.onClick = (event) => this.handleControl(event);
4441
+ this.document.addEventListener("click", this.onClick);
4442
+ instances8.set(panel, this);
4443
+ let dismissed = this.memory.get(this.key) || false;
4444
+ if (this.key && !this.memory.has(this.key)) {
4445
+ try {
4446
+ dismissed = view.localStorage.getItem(this.key) === "dismissed";
4447
+ } catch {
4448
+ }
4449
+ }
4450
+ this.setVisible(!dismissed);
4451
+ panel.dataset.floatingPanelReady = "true";
4452
+ }
4453
+ launchers() {
4454
+ return [...this.document.querySelectorAll("[data-floating-panel-open]")].filter((control) => control.dataset.floatingPanelOpen === this.panel.id && control.closest(".moo-ui") === this.owner);
4455
+ }
4456
+ setVisible(visible) {
4457
+ this.panel.hidden = !visible;
4458
+ this.panel.dataset.floatingPanelState = visible ? "visible" : "dismissed";
4459
+ this.launchers().forEach((control) => {
4460
+ if (!this.controls.has(control)) this.controls.set(control, {
4461
+ controls: control.getAttribute("aria-controls"),
4462
+ expanded: control.getAttribute("aria-expanded")
4463
+ });
4464
+ control.setAttribute("aria-controls", this.panel.id);
4465
+ control.setAttribute("aria-expanded", String(visible));
4466
+ });
4467
+ }
4468
+ handleControl(event) {
4469
+ const control = event.target.closest?.("[data-floating-panel-open], [data-floating-panel-dismiss]");
4470
+ if (!control || control.matches(":disabled") || control.closest(".moo-ui") !== this.owner) return;
4471
+ const opening = control.hasAttribute("data-floating-panel-open");
4472
+ if ((opening ? control.dataset.floatingPanelOpen : control.dataset.floatingPanelDismiss) !== this.panel.id) return;
4473
+ if (!opening && !this.panel.contains(control)) return;
4474
+ event.preventDefault();
4475
+ if (opening) this.launcher = control;
4476
+ if (this.key) {
4477
+ try {
4478
+ const storage = this.document.defaultView.localStorage;
4479
+ if (opening) storage.removeItem(this.key);
4480
+ else storage.setItem(this.key, "dismissed");
4481
+ this.memory.delete(this.key);
4482
+ } catch {
4483
+ this.memory.set(this.key, !opening);
4484
+ }
4485
+ }
4486
+ this.setVisible(opening);
4487
+ if (opening) {
4488
+ [...this.panel.querySelectorAll("button, a[href], input:not([type='hidden']), select, textarea, [tabindex]")].find((control2) => control2.tabIndex >= 0 && canFocus(control2))?.focus({ preventScroll: true });
4489
+ } else {
4490
+ const launchers = this.launchers().filter(canFocus);
4491
+ const launcher = launchers.includes(this.launcher) ? this.launcher : launchers[0];
4492
+ launcher?.focus({ preventScroll: true });
4493
+ }
4494
+ }
4495
+ dispose() {
4496
+ if (instances8.get(this.panel) !== this) return;
4497
+ this.document.removeEventListener("click", this.onClick);
4498
+ this.panel.hidden = this.initialHidden;
4499
+ delete this.panel.dataset.floatingPanelReady;
4500
+ delete this.panel.dataset.floatingPanelState;
4501
+ this.controls.forEach((attrs, control) => {
4502
+ for (const [name, value] of [["aria-controls", attrs.controls], ["aria-expanded", attrs.expanded]]) {
4503
+ if (value === null) control.removeAttribute(name);
4504
+ else control.setAttribute(name, value);
4505
+ }
4506
+ });
4507
+ instances8.delete(this.panel);
4508
+ }
4509
+ };
4510
+
4412
4511
  // src/js/moo-ui.js
4512
+ import PasswordRequirements from "./password-requirements.js";
4413
4513
  async function loadChart() {
4414
4514
  const { default: Chart } = await import("./chart.js");
4415
4515
  return Chart;
4416
4516
  }
4417
4517
  var MooUI = {
4518
+ PasswordRequirements,
4519
+ FloatingPanel,
4418
4520
  loadChart,
4419
4521
  Combobox,
4420
4522
  ContextMenu,
@@ -4434,9 +4536,11 @@ export {
4434
4536
  ContextMenu,
4435
4537
  DataTable,
4436
4538
  MooDatepicker as Datepicker,
4539
+ FloatingPanel,
4437
4540
  MooCalendar,
4438
4541
  MooDateRangePicker,
4439
4542
  OverlayScrollbar,
4543
+ PasswordRequirements,
4440
4544
  Sidebar,
4441
4545
  MooSlider as Slider,
4442
4546
  TableOfContents,