@wpmoo/ui 1.0.0-rc.4 → 1.0.0-rc.5

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.0.0-rc.4 (https://ui.wpmoo.org/)
2
+ * Moo UI chart.js v1.0.0-rc.5 (https://ui.wpmoo.org/)
3
3
  * Copyright 2026 WPMoo (https://wpmoo.org)
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.0.0-rc.4 (https://ui.wpmoo.org/)
2
+ * Moo UI chart.min.js v1.0.0-rc.5 (https://ui.wpmoo.org/)
3
3
  * Copyright 2026 WPMoo (https://wpmoo.org)
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.0.0-rc.4 (https://ui.wpmoo.org/)
2
+ * Moo UI combobox.js v1.0.0-rc.5 (https://ui.wpmoo.org/)
3
3
  * Copyright 2026 WPMoo (https://wpmoo.org)
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.0.0-rc.4 (https://ui.wpmoo.org/)
2
+ * Moo UI context-menu.js v1.0.0-rc.5 (https://ui.wpmoo.org/)
3
3
  * Copyright 2026 WPMoo (https://wpmoo.org)
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.0.0-rc.4 (https://ui.wpmoo.org/)
2
+ * Moo UI datatable.js v1.0.0-rc.5 (https://ui.wpmoo.org/)
3
3
  * Copyright 2026 WPMoo (https://wpmoo.org)
4
4
  * Licensed under MIT (https://github.com/wpmoo-org/ui/blob/main/LICENSE)
5
5
  */
@@ -54,6 +54,8 @@ export default class DataTable {
54
54
  this._filterMode = element.dataset.datatableFilterMode || "inline";
55
55
  this._reparentedRowMenus = new Map();
56
56
  this._reparentedRowMenuByTrigger = new WeakMap();
57
+ this._reparentedSortMenus = new Map();
58
+ this._reparentedSortMenuByTrigger = new WeakMap();
57
59
 
58
60
  this._rows = Array.from(this._tbody.querySelectorAll(":scope > tr[data-datatable-row]")).map((tr, index) => ({
59
61
  element: tr,
@@ -71,11 +73,14 @@ export default class DataTable {
71
73
  this._initBulkTooltips();
72
74
  this._initViewToggle();
73
75
  this._initRowActionDropdowns();
76
+ this._initSortDropdowns();
74
77
  }
75
78
 
76
79
  dispose() {
77
80
  this._disposeRowActionDropdowns();
81
+ this._disposeSortDropdowns();
78
82
  this._restoreRowActionMenus();
83
+ this._restoreSortMenus();
79
84
  this._listeners.forEach(({ target, type, handler, options }) => {
80
85
  target.removeEventListener(type, handler, options);
81
86
  });
@@ -118,30 +123,52 @@ export default class DataTable {
118
123
  }
119
124
  this._rowActionTriggers().forEach((trigger) => {
120
125
  Dropdown.getOrCreateInstance(trigger, {
121
- popperConfig: (defaultConfig) => ({
122
- ...defaultConfig,
123
- strategy: "fixed",
124
- modifiers: [
125
- ...(defaultConfig.modifiers || []),
126
- {
127
- name: "flip",
128
- options: {
129
- fallbackPlacements: ["top-end", "top-start", "bottom-end", "bottom-start"],
130
- },
131
- },
132
- {
133
- name: "preventOverflow",
134
- options: {
135
- boundary: "viewport",
136
- padding: 8,
137
- },
138
- },
139
- ],
140
- }),
126
+ popperConfig: (defaultConfig) => this._clippingSafePopperConfig(defaultConfig),
141
127
  });
142
128
  });
143
129
  }
144
130
 
131
+ _sortTriggers() {
132
+ return this._element.querySelectorAll(
133
+ ".datatable-sort [data-bs-toggle=\"dropdown\"]"
134
+ );
135
+ }
136
+
137
+ _initSortDropdowns() {
138
+ const Dropdown = this._bootstrap("Dropdown");
139
+ if (!Dropdown) {
140
+ return;
141
+ }
142
+ this._sortTriggers().forEach((trigger) => {
143
+ Dropdown.getOrCreateInstance(trigger, {
144
+ popperConfig: (defaultConfig) => this._clippingSafePopperConfig(defaultConfig),
145
+ });
146
+ });
147
+ }
148
+
149
+ _clippingSafePopperConfig(defaultConfig) {
150
+ return {
151
+ ...defaultConfig,
152
+ strategy: "fixed",
153
+ modifiers: [
154
+ ...(defaultConfig.modifiers || []),
155
+ {
156
+ name: "flip",
157
+ options: {
158
+ fallbackPlacements: ["top-end", "top-start", "bottom-end", "bottom-start"],
159
+ },
160
+ },
161
+ {
162
+ name: "preventOverflow",
163
+ options: {
164
+ boundary: "viewport",
165
+ padding: 8,
166
+ },
167
+ },
168
+ ],
169
+ };
170
+ }
171
+
145
172
  // dispose() alone leaves any open row-action Dropdown's show/aria-expanded/
146
173
  // data-bs-popper state and Bootstrap instance behind; hide and dispose each
147
174
  // one first so a subsequent re-init starts from a clean state.
@@ -160,6 +187,21 @@ export default class DataTable {
160
187
  });
161
188
  }
162
189
 
190
+ _disposeSortDropdowns() {
191
+ const Dropdown = this._bootstrap("Dropdown");
192
+ if (!Dropdown) {
193
+ return;
194
+ }
195
+ this._sortTriggers().forEach((trigger) => {
196
+ const instance = Dropdown.getInstance(trigger);
197
+ if (!instance) {
198
+ return;
199
+ }
200
+ instance.hide();
201
+ instance.dispose();
202
+ });
203
+ }
204
+
163
205
  _rowActionMenuForTrigger(trigger) {
164
206
  if (!trigger?.closest?.(".table-row-actions")) {
165
207
  return null;
@@ -232,6 +274,68 @@ export default class DataTable {
232
274
  });
233
275
  }
234
276
 
277
+ _sortMenuForTrigger(trigger) {
278
+ if (!trigger?.closest?.(".datatable-sort")) {
279
+ return null;
280
+ }
281
+ return (
282
+ this._reparentedSortMenuByTrigger.get(trigger) ||
283
+ trigger?.closest?.(".dropdown")?.querySelector(":scope > .dropdown-menu") ||
284
+ null
285
+ );
286
+ }
287
+
288
+ // Sort menus are authored inside their table header, but must leave the
289
+ // overflow frame while open just like row-action menus do.
290
+ _reparentSortMenu(trigger) {
291
+ const menu = this._sortMenuForTrigger(trigger);
292
+ if (!menu || this._reparentedSortMenus.has(menu)) {
293
+ return;
294
+ }
295
+ this._reparentedSortMenus.set(menu, {
296
+ parent: menu.parentNode,
297
+ nextSibling: menu.nextSibling,
298
+ trigger,
299
+ owner: trigger.closest(".datatable-sort"),
300
+ });
301
+ this._reparentedSortMenuByTrigger.set(trigger, menu);
302
+ this._document.body.appendChild(menu);
303
+ }
304
+
305
+ _restoreSortMenuForTrigger(trigger) {
306
+ const menu = this._reparentedSortMenuByTrigger.get(trigger) || this._sortMenuForTrigger(trigger);
307
+ if (menu) {
308
+ this._restoreSortMenu(menu);
309
+ }
310
+ }
311
+
312
+ _restoreSortMenu(menu) {
313
+ const original = this._reparentedSortMenus.get(menu);
314
+ if (!original) {
315
+ return;
316
+ }
317
+ const { parent, nextSibling, trigger } = original;
318
+ if (parent?.isConnected) {
319
+ if (nextSibling?.parentNode === parent) {
320
+ parent.insertBefore(menu, nextSibling);
321
+ } else {
322
+ parent.appendChild(menu);
323
+ }
324
+ } else {
325
+ menu.remove();
326
+ }
327
+ if (trigger) {
328
+ this._reparentedSortMenuByTrigger.delete(trigger);
329
+ }
330
+ this._reparentedSortMenus.delete(menu);
331
+ }
332
+
333
+ _restoreSortMenus() {
334
+ Array.from(this._reparentedSortMenus.keys()).forEach((menu) => {
335
+ this._restoreSortMenu(menu);
336
+ });
337
+ }
338
+
235
339
  _bootstrap(name) {
236
340
  return this._window.bootstrap?.[name] || null;
237
341
  }
@@ -785,9 +889,13 @@ export default class DataTable {
785
889
  return;
786
890
  }
787
891
  const menu = trigger.closest(".dropdown-menu");
788
- const key = menu
789
- ?.closest(".datatable-sort")
790
- ?.querySelector("[data-datatable-sort-key]")?.dataset.datatableSortKey;
892
+ const sort =
893
+ menu?.closest(".datatable-sort") ||
894
+ this._reparentedSortMenus.get(menu)?.owner;
895
+ if (!sort || !this._element.contains(sort)) {
896
+ return;
897
+ }
898
+ const key = sort.querySelector("[data-datatable-sort-key]")?.dataset.datatableSortKey;
791
899
  if (!key) {
792
900
  return;
793
901
  }
@@ -1175,7 +1283,6 @@ export default class DataTable {
1175
1283
  });
1176
1284
 
1177
1285
  this._listen(this._element, "click", (event) => {
1178
- this._handleSortAction(event);
1179
1286
  this._handleFilterPickerClick(event);
1180
1287
  this._handleFilterOptionClick(event);
1181
1288
  this._handleFilterToggleClick(event);
@@ -1190,6 +1297,7 @@ export default class DataTable {
1190
1297
  this._handleSelectRow(event);
1191
1298
  }
1192
1299
  });
1300
+ this._listen(this._document, "click", (event) => this._handleSortAction(event));
1193
1301
 
1194
1302
  // Bound to the document, not this._element: a checkbox click does not
1195
1303
  // reliably move focus into the table (WebKit never focuses form
@@ -1213,12 +1321,14 @@ export default class DataTable {
1213
1321
  // re-triggered.
1214
1322
  this._listen(this._element, "show.bs.dropdown", (event) => {
1215
1323
  this._reparentRowActionMenu(event.target);
1324
+ this._reparentSortMenu(event.target);
1216
1325
  const tooltip = this._bootstrap("Tooltip")?.getInstance(event.target);
1217
1326
  tooltip?.hide();
1218
1327
  tooltip?.disable();
1219
1328
  });
1220
1329
  this._listen(this._element, "hidden.bs.dropdown", (event) => {
1221
1330
  this._restoreRowActionMenuForTrigger(event.target);
1331
+ this._restoreSortMenuForTrigger(event.target);
1222
1332
  this._bootstrap("Tooltip")?.getInstance(event.target)?.enable();
1223
1333
  if (event.target.matches("[data-datatable-filter-menu-trigger]")) {
1224
1334
  this._showFilterPickerPanel();
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Moo UI datepicker.js v1.0.0-rc.4 (https://ui.wpmoo.org/)
2
+ * Moo UI datepicker.js v1.0.0-rc.5 (https://ui.wpmoo.org/)
3
3
  * Copyright 2026 WPMoo (https://wpmoo.org)
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.0.0-rc.4 (https://ui.wpmoo.org/)
2
+ * Moo UI datepicker.min.js v1.0.0-rc.5 (https://ui.wpmoo.org/)
3
3
  * Copyright 2026 WPMoo (https://wpmoo.org)
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.0.0-rc.4 (https://ui.wpmoo.org/)
2
+ * Moo UI moo-ui.js v1.0.0-rc.5 (https://ui.wpmoo.org/)
3
3
  * Copyright 2026 WPMoo (https://wpmoo.org)
4
4
  * Licensed under MIT (https://github.com/wpmoo-org/ui/blob/main/LICENSE)
5
5
  */
@@ -15993,6 +15993,8 @@ var DataTable = class _DataTable {
15993
15993
  this._filterMode = element.dataset.datatableFilterMode || "inline";
15994
15994
  this._reparentedRowMenus = /* @__PURE__ */ new Map();
15995
15995
  this._reparentedRowMenuByTrigger = /* @__PURE__ */ new WeakMap();
15996
+ this._reparentedSortMenus = /* @__PURE__ */ new Map();
15997
+ this._reparentedSortMenuByTrigger = /* @__PURE__ */ new WeakMap();
15996
15998
  this._rows = Array.from(this._tbody.querySelectorAll(":scope > tr[data-datatable-row]")).map((tr, index2) => ({
15997
15999
  element: tr,
15998
16000
  cardElement: cardById.get(tr.id) || null,
@@ -16008,10 +16010,13 @@ var DataTable = class _DataTable {
16008
16010
  this._initBulkTooltips();
16009
16011
  this._initViewToggle();
16010
16012
  this._initRowActionDropdowns();
16013
+ this._initSortDropdowns();
16011
16014
  }
16012
16015
  dispose() {
16013
16016
  this._disposeRowActionDropdowns();
16017
+ this._disposeSortDropdowns();
16014
16018
  this._restoreRowActionMenus();
16019
+ this._restoreSortMenus();
16015
16020
  this._listeners.forEach(({ target, type, handler, options }) => {
16016
16021
  target.removeEventListener(type, handler, options);
16017
16022
  });
@@ -16050,29 +16055,48 @@ var DataTable = class _DataTable {
16050
16055
  }
16051
16056
  this._rowActionTriggers().forEach((trigger) => {
16052
16057
  Dropdown.getOrCreateInstance(trigger, {
16053
- popperConfig: (defaultConfig) => ({
16054
- ...defaultConfig,
16055
- strategy: "fixed",
16056
- modifiers: [
16057
- ...defaultConfig.modifiers || [],
16058
- {
16059
- name: "flip",
16060
- options: {
16061
- fallbackPlacements: ["top-end", "top-start", "bottom-end", "bottom-start"]
16062
- }
16063
- },
16064
- {
16065
- name: "preventOverflow",
16066
- options: {
16067
- boundary: "viewport",
16068
- padding: 8
16069
- }
16070
- }
16071
- ]
16072
- })
16058
+ popperConfig: (defaultConfig) => this._clippingSafePopperConfig(defaultConfig)
16073
16059
  });
16074
16060
  });
16075
16061
  }
16062
+ _sortTriggers() {
16063
+ return this._element.querySelectorAll(
16064
+ '.datatable-sort [data-bs-toggle="dropdown"]'
16065
+ );
16066
+ }
16067
+ _initSortDropdowns() {
16068
+ const Dropdown = this._bootstrap("Dropdown");
16069
+ if (!Dropdown) {
16070
+ return;
16071
+ }
16072
+ this._sortTriggers().forEach((trigger) => {
16073
+ Dropdown.getOrCreateInstance(trigger, {
16074
+ popperConfig: (defaultConfig) => this._clippingSafePopperConfig(defaultConfig)
16075
+ });
16076
+ });
16077
+ }
16078
+ _clippingSafePopperConfig(defaultConfig) {
16079
+ return {
16080
+ ...defaultConfig,
16081
+ strategy: "fixed",
16082
+ modifiers: [
16083
+ ...defaultConfig.modifiers || [],
16084
+ {
16085
+ name: "flip",
16086
+ options: {
16087
+ fallbackPlacements: ["top-end", "top-start", "bottom-end", "bottom-start"]
16088
+ }
16089
+ },
16090
+ {
16091
+ name: "preventOverflow",
16092
+ options: {
16093
+ boundary: "viewport",
16094
+ padding: 8
16095
+ }
16096
+ }
16097
+ ]
16098
+ };
16099
+ }
16076
16100
  // dispose() alone leaves any open row-action Dropdown's show/aria-expanded/
16077
16101
  // data-bs-popper state and Bootstrap instance behind; hide and dispose each
16078
16102
  // one first so a subsequent re-init starts from a clean state.
@@ -16090,6 +16114,20 @@ var DataTable = class _DataTable {
16090
16114
  instance.dispose();
16091
16115
  });
16092
16116
  }
16117
+ _disposeSortDropdowns() {
16118
+ const Dropdown = this._bootstrap("Dropdown");
16119
+ if (!Dropdown) {
16120
+ return;
16121
+ }
16122
+ this._sortTriggers().forEach((trigger) => {
16123
+ const instance = Dropdown.getInstance(trigger);
16124
+ if (!instance) {
16125
+ return;
16126
+ }
16127
+ instance.hide();
16128
+ instance.dispose();
16129
+ });
16130
+ }
16093
16131
  _rowActionMenuForTrigger(trigger) {
16094
16132
  if (!trigger?.closest?.(".table-row-actions")) {
16095
16133
  return null;
@@ -16156,6 +16194,59 @@ var DataTable = class _DataTable {
16156
16194
  this._restoreRowActionMenu(menu);
16157
16195
  });
16158
16196
  }
16197
+ _sortMenuForTrigger(trigger) {
16198
+ if (!trigger?.closest?.(".datatable-sort")) {
16199
+ return null;
16200
+ }
16201
+ return this._reparentedSortMenuByTrigger.get(trigger) || trigger?.closest?.(".dropdown")?.querySelector(":scope > .dropdown-menu") || null;
16202
+ }
16203
+ // Sort menus are authored inside their table header, but must leave the
16204
+ // overflow frame while open just like row-action menus do.
16205
+ _reparentSortMenu(trigger) {
16206
+ const menu = this._sortMenuForTrigger(trigger);
16207
+ if (!menu || this._reparentedSortMenus.has(menu)) {
16208
+ return;
16209
+ }
16210
+ this._reparentedSortMenus.set(menu, {
16211
+ parent: menu.parentNode,
16212
+ nextSibling: menu.nextSibling,
16213
+ trigger,
16214
+ owner: trigger.closest(".datatable-sort")
16215
+ });
16216
+ this._reparentedSortMenuByTrigger.set(trigger, menu);
16217
+ this._document.body.appendChild(menu);
16218
+ }
16219
+ _restoreSortMenuForTrigger(trigger) {
16220
+ const menu = this._reparentedSortMenuByTrigger.get(trigger) || this._sortMenuForTrigger(trigger);
16221
+ if (menu) {
16222
+ this._restoreSortMenu(menu);
16223
+ }
16224
+ }
16225
+ _restoreSortMenu(menu) {
16226
+ const original = this._reparentedSortMenus.get(menu);
16227
+ if (!original) {
16228
+ return;
16229
+ }
16230
+ const { parent, nextSibling, trigger } = original;
16231
+ if (parent?.isConnected) {
16232
+ if (nextSibling?.parentNode === parent) {
16233
+ parent.insertBefore(menu, nextSibling);
16234
+ } else {
16235
+ parent.appendChild(menu);
16236
+ }
16237
+ } else {
16238
+ menu.remove();
16239
+ }
16240
+ if (trigger) {
16241
+ this._reparentedSortMenuByTrigger.delete(trigger);
16242
+ }
16243
+ this._reparentedSortMenus.delete(menu);
16244
+ }
16245
+ _restoreSortMenus() {
16246
+ Array.from(this._reparentedSortMenus.keys()).forEach((menu) => {
16247
+ this._restoreSortMenu(menu);
16248
+ });
16249
+ }
16159
16250
  _bootstrap(name) {
16160
16251
  return this._window.bootstrap?.[name] || null;
16161
16252
  }
@@ -16632,7 +16723,11 @@ var DataTable = class _DataTable {
16632
16723
  return;
16633
16724
  }
16634
16725
  const menu = trigger.closest(".dropdown-menu");
16635
- const key = menu?.closest(".datatable-sort")?.querySelector("[data-datatable-sort-key]")?.dataset.datatableSortKey;
16726
+ const sort = menu?.closest(".datatable-sort") || this._reparentedSortMenus.get(menu)?.owner;
16727
+ if (!sort || !this._element.contains(sort)) {
16728
+ return;
16729
+ }
16730
+ const key = sort.querySelector("[data-datatable-sort-key]")?.dataset.datatableSortKey;
16636
16731
  if (!key) {
16637
16732
  return;
16638
16733
  }
@@ -16997,7 +17092,6 @@ var DataTable = class _DataTable {
16997
17092
  }
16998
17093
  });
16999
17094
  this._listen(this._element, "click", (event) => {
17000
- this._handleSortAction(event);
17001
17095
  this._handleFilterPickerClick(event);
17002
17096
  this._handleFilterOptionClick(event);
17003
17097
  this._handleFilterToggleClick(event);
@@ -17012,6 +17106,7 @@ var DataTable = class _DataTable {
17012
17106
  this._handleSelectRow(event);
17013
17107
  }
17014
17108
  });
17109
+ this._listen(this._document, "click", (event) => this._handleSortAction(event));
17015
17110
  this._listen(this._document, "keydown", (event) => {
17016
17111
  if (event.key === "Escape" && this._selectedIds.size > 0) {
17017
17112
  this._clearSelection();
@@ -17019,12 +17114,14 @@ var DataTable = class _DataTable {
17019
17114
  });
17020
17115
  this._listen(this._element, "show.bs.dropdown", (event) => {
17021
17116
  this._reparentRowActionMenu(event.target);
17117
+ this._reparentSortMenu(event.target);
17022
17118
  const tooltip = this._bootstrap("Tooltip")?.getInstance(event.target);
17023
17119
  tooltip?.hide();
17024
17120
  tooltip?.disable();
17025
17121
  });
17026
17122
  this._listen(this._element, "hidden.bs.dropdown", (event) => {
17027
17123
  this._restoreRowActionMenuForTrigger(event.target);
17124
+ this._restoreSortMenuForTrigger(event.target);
17028
17125
  this._bootstrap("Tooltip")?.getInstance(event.target)?.enable();
17029
17126
  if (event.target.matches("[data-datatable-filter-menu-trigger]")) {
17030
17127
  this._showFilterPickerPanel();