@wpmoo/ui 2.0.0 → 2.1.1

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,10 +1,18 @@
1
1
  /*!
2
- * Moo UI password-requirements.js v2.0.0 (https://wpmoo.org/)
2
+ * Moo UI password-requirements.js v2.1.1 (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
  */
6
6
 
7
7
  const instances = /* @__PURE__ */ new WeakMap();
8
+ const MESSAGES = {
9
+ met: "\u2713 %s",
10
+ missing: "\u2014 %s",
11
+ remaining: "Remaining: %s",
12
+ complete: "Shown checks met. Final validation happens on submit.",
13
+ analysis: "Host password analysis must pass."
14
+ };
15
+ const format = (message, value) => message.replace("%s", () => String(value));
8
16
  function strip(value, characters) {
9
17
  const points = Array.from(value);
10
18
  let start = 0;
@@ -45,10 +53,11 @@ class PasswordRequirements {
45
53
  const confirmation = configuration.confirmation && document.getElementById(configuration.confirmation);
46
54
  const localControl = (node) => node?.matches('input[type="password"]') && node.closest(".moo-ui") === owner && node.form === element.closest("form");
47
55
  const policy = configuration.policy;
48
- if (!owner || !localControl(input) || configuration.confirmation && (!localControl(confirmation) || confirmation === input) || policy?.version !== 3 || !Number.isInteger(policy.minlength) || policy.minlength < 1 || !Number.isInteger(policy.maxlength) || policy.maxlength < policy.minlength || policy.maxlength > 128 || !Array.isArray(policy.rules) || !policy.rules.length || policy.rules.some((rule) => !["length", "case", "number", "symbol", "maximum"].includes(rule.key) || typeof rule.label !== "string" || rule.warning !== void 0 && typeof rule.warning !== "boolean") || new Set(policy.rules.map((rule) => rule.key)).size !== policy.rules.length || !["length", "maximum"].every((key) => policy.rules.some((rule) => rule.key === key)) || typeof policy.whitespace !== "string" || options.analyze !== void 0 && typeof options.analyze !== "function") {
56
+ if (!owner || !localControl(input) || configuration.confirmation && (!localControl(confirmation) || confirmation === input) || policy?.version !== 3 || !Number.isInteger(policy.minlength) || policy.minlength < 1 || !Number.isInteger(policy.maxlength) || policy.maxlength < policy.minlength || policy.maxlength > 128 || !Array.isArray(policy.rules) || !policy.rules.length || policy.rules.some((rule) => !["length", "case", "number", "symbol", "maximum"].includes(rule.key) || typeof rule.label !== "string" || rule.warning !== void 0 && typeof rule.warning !== "boolean") || new Set(policy.rules.map((rule) => rule.key)).size !== policy.rules.length || !["length", "maximum"].every((key) => policy.rules.some((rule) => rule.key === key)) || typeof policy.whitespace !== "string" || options.analyze !== void 0 && typeof options.analyze !== "function" || options.messages !== void 0 && (!options.messages || typeof options.messages !== "object" || Object.entries(options.messages).some(([key, value]) => !Object.hasOwn(MESSAGES, key) || typeof value !== "string"))) {
49
57
  throw new TypeError("PasswordRequirements requires same-owner controls and a versioned public policy.");
50
58
  }
51
59
  this._element = element;
60
+ const messages = { ...MESSAGES, ...options.messages };
52
61
  this._initialReady = element.getAttribute("data-requirements-ready");
53
62
  this._originals = /* @__PURE__ */ new Map();
54
63
  this._listeners = [];
@@ -137,7 +146,7 @@ class PasswordRequirements {
137
146
  lastTitle = title;
138
147
  };
139
148
  const show = (node, label, met, warning = false, active = Boolean(input.value)) => {
140
- node.textContent = warning ? label : (met ? "\u2713 " : "\u2014 ") + label;
149
+ node.textContent = warning ? label : format(met ? messages.met : messages.missing, label);
141
150
  node.hidden = warning && (!active || met);
142
151
  node.classList.toggle("text-body", !warning && met);
143
152
  node.classList.toggle("text-danger", warning);
@@ -161,7 +170,7 @@ class PasswordRequirements {
161
170
  }
162
171
  if (options.analyze) states.push({
163
172
  key: "analysis",
164
- label: "Host password analysis must pass.",
173
+ label: messages.analysis,
165
174
  met: Boolean(analysis?.met),
166
175
  warning: true
167
176
  });
@@ -180,7 +189,7 @@ class PasswordRequirements {
180
189
  );
181
190
  const missing = states.filter((state) => !state.met).length;
182
191
  const warnings = states.filter((state) => state.warning && !state.met).map((state) => state.label).join(" ");
183
- const summaryText = !input.value ? this._originals.get(summary).text : missing ? `Remaining: ${missing} ${warnings}`.trim() : "Shown checks met. Final validation happens on submit.";
192
+ const summaryText = !input.value ? this._originals.get(summary).text : missing ? `${format(messages.remaining, missing)} ${warnings}`.trim() : messages.complete;
184
193
  if (summary.textContent !== summaryText) summary.textContent = summaryText;
185
194
  options.onChange?.(states.map(({ key, met }) => ({ key, met: Boolean(input.value) && met })), Boolean(input.value), analysis?.score ?? null);
186
195
  updateSubmit(states);
package/dist/js/sheet.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Moo UI sheet.js v2.0.0 (https://wpmoo.org/)
2
+ * Moo UI sheet.js v2.1.1 (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 sidebar.js v2.0.0 (https://wpmoo.org/)
2
+ * Moo UI sidebar.js v2.1.1 (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
  */
@@ -45,6 +45,14 @@ __name(ownerPortalRoot, "ownerPortalRoot");
45
45
 
46
46
  // src/js/components/sidebar.js
47
47
  var instances = /* @__PURE__ */ new WeakMap();
48
+ var FLYOUT_FOCUSABLE_SELECTOR = "a[href], button, input, select, textarea, [tabindex]";
49
+ function flyoutFocusables(flyout) {
50
+ const view = flyout.ownerDocument.defaultView;
51
+ return [...flyout.querySelectorAll(FLYOUT_FOCUSABLE_SELECTOR)].filter(
52
+ (element) => !element.matches(":disabled") && element.tabIndex >= 0 && !element.closest("[hidden], [inert]") && element.getClientRects().length > 0 && view.getComputedStyle(element).visibility === "visible"
53
+ );
54
+ }
55
+ __name(flyoutFocusables, "flyoutFocusables");
48
56
  var _Sidebar = class _Sidebar {
49
57
  static getInstance(element) {
50
58
  return element?.nodeType === 1 ? instances.get(element) || null : null;
@@ -472,8 +480,38 @@ var _Sidebar = class _Sidebar {
472
480
  this._closeFlyouts();
473
481
  } else {
474
482
  this._openFlyout(item);
483
+ if (event.detail === 0) {
484
+ if (this._flyout) {
485
+ flyoutFocusables(this._flyout)[0]?.focus();
486
+ }
487
+ }
475
488
  }
476
489
  }
490
+ // The flyout lives in a portal, away from its trigger, so Escape and Tab
491
+ // out of it return to the trigger instead of wandering. Tab between its
492
+ // items stays native; a key a flyout control already handled is left alone.
493
+ _handleFlyoutKeydown(event) {
494
+ const owner = this._flyoutOwner;
495
+ if (event.defaultPrevented || !this._flyout || !owner || !(event.key === "Escape" || event.key === "Tab")) {
496
+ return false;
497
+ }
498
+ const inFlyout = this._flyout.contains(event.target);
499
+ if (!inFlyout && !(event.key === "Escape" && owner.contains(event.target))) {
500
+ return false;
501
+ }
502
+ if (event.key === "Tab") {
503
+ const items = flyoutFocusables(this._flyout);
504
+ const edge = event.shiftKey ? items[0] : items[items.length - 1];
505
+ if (edge && event.target !== edge) {
506
+ return false;
507
+ }
508
+ }
509
+ event.preventDefault();
510
+ const trigger = owner.querySelector(":scope > .sidebar-menu-sub-trigger");
511
+ this._closeFlyouts();
512
+ trigger?.focus();
513
+ return true;
514
+ }
477
515
  _handleOutsideFlyoutClick(event) {
478
516
  if (!this._flyout) {
479
517
  return;
@@ -485,6 +523,9 @@ var _Sidebar = class _Sidebar {
485
523
  }
486
524
  }
487
525
  _handleShortcut(event) {
526
+ if (this._handleFlyoutKeydown(event)) {
527
+ return;
528
+ }
488
529
  const target = event.target;
489
530
  const isEditable = target instanceof this._window.Element && (target.matches("input, textarea, select") || target.isContentEditable);
490
531
  if (event.defaultPrevented || event.isComposing || isEditable || !this._config.keyboard || !(event.metaKey || event.ctrlKey) || event.key.toLowerCase() !== "b" || !this._isDesktop()) {
package/dist/js/slider.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Moo UI slider.js v2.0.0 (https://wpmoo.org/)
2
+ * Moo UI slider.js v2.1.1 (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/state.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Moo UI state.js v2.0.0 (https://wpmoo.org/)
2
+ * Moo UI state.js v2.1.1 (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 table-of-contents.js v2.0.0 (https://wpmoo.org/)
2
+ * Moo UI table-of-contents.js v2.1.1 (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/toc.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Moo UI toc.js v2.0.0 (https://wpmoo.org/)
2
+ * Moo UI toc.js v2.1.1 (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
  */
@@ -3,22 +3,22 @@
3
3
  {
4
4
  "export": "./moo.css",
5
5
  "path": "dist/assets/css/moo.css",
6
- "sha256": "d11bbace049bdcc51c609e7c3cfc255aa51cd8ae0ca67861abe632b5403d48d0"
6
+ "sha256": "2c98f8a15fdd14b6749831dbe78edfeb8998f5cfc017733164efacf93b16db11"
7
7
  },
8
8
  {
9
9
  "export": "./moo-ui.css",
10
10
  "path": "dist/assets/css/moo-ui.css",
11
- "sha256": "9cecb108344be63165a063e6a088657f7714ea7305aa0cc0e85e58474066f154"
11
+ "sha256": "afca34860a8a9cb3bc3ebf4b5d22d687b26d7cadac0dace6224e44da28f24874"
12
12
  },
13
13
  {
14
14
  "export": "./state.js",
15
15
  "path": "dist/js/state.js",
16
- "sha256": "58307028fc5f06a83620a335f2de13fea3ad3959b6a9f9794d0d443b43b48acd"
16
+ "sha256": "adb29ff6ee521414f8975d7b4240f7aeb39dc7c6a59349fc6c95591b5b1f109d"
17
17
  }
18
18
  ],
19
19
  "package": {
20
20
  "name": "@wpmoo/ui",
21
- "version": "2.0.0"
21
+ "version": "2.1.1"
22
22
  },
23
23
  "schemaVersion": 1
24
24
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wpmoo/ui",
3
- "version": "2.0.0",
3
+ "version": "2.1.1",
4
4
  "description": "Bootstrap markup. shadcn feel. A frontend-framework-free component system for server-rendered apps.",
5
5
  "license": "MIT",
6
6
  "author": "WPMoo (https://wpmoo.org)",
@@ -20,6 +20,12 @@
20
20
  border-radius: var(--bs-border-radius-xl);
21
21
  }
22
22
 
23
+ .wrapper[data-layout="app"][data-shell-mode="document"] {
24
+ height: auto;
25
+ min-height: 100svh;
26
+ overflow: visible;
27
+ }
28
+
23
29
  .wrapper[data-layout="app"] > [data-slot="page"] {
24
30
  display: flex;
25
31
  min-width: 0;
@@ -75,6 +81,10 @@
75
81
  overflow-y: auto;
76
82
  }
77
83
 
84
+ .wrapper[data-layout="app"][data-shell-mode="document"] > [data-slot="page"] > main {
85
+ overflow: visible;
86
+ }
87
+
78
88
  .wrapper[data-layout="app"] > [data-slot="page"] > main > :is(
79
89
  .container,
80
90
  .container-sm,
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Moo UI v2.0.0 (https://wpmoo.org/)
2
+ * Moo UI v2.1.1 (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,7 +1,8 @@
1
1
  $white: #fff !default;
2
2
  $black: #0a0a0a !default;
3
3
 
4
- $headings-font-weight: 600 !default;
4
+ $moo-heading-font-weight: 600 !default;
5
+ $headings-font-weight: var(--moo-heading-font-weight, #{$moo-heading-font-weight}) !default;
5
6
  $lead-font-size: 1.125rem !default;
6
7
  $lead-font-weight: 400 !default;
7
8
  $display-font-sizes: (
@@ -92,6 +92,7 @@ $moo-theme-colors-border-subtle-dark: (
92
92
  --moo-chart-4: #{$moo-chart-4};
93
93
  --moo-chart-5: #{$moo-chart-5};
94
94
  --moo-heading-font-family: var(--#{$prefix}body-font-family);
95
+ --moo-heading-font-weight: #{$moo-heading-font-weight};
95
96
  --moo-small-font-size: #{$moo-small-font-size};
96
97
  --moo-paragraph-margin-top: #{$moo-paragraph-margin-top};
97
98
  --moo-paragraph-margin-bottom: #{$paragraph-margin-bottom};