@floegence/redevplugin-ui 0.4.2 → 0.4.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.
Files changed (2) hide show
  1. package/dist/surface.js +28 -2
  2. package/package.json +1 -1
package/dist/surface.js CHANGED
@@ -763,13 +763,15 @@ export function createOpaquePluginBootstrapHTML(options = {}) {
763
763
  if (value.attributes !== undefined) {
764
764
  if (!isRecord(value.attributes) || Object.keys(value.attributes).length > maxAttributesPerElement) throw new Error("plugin render attributes are invalid");
765
765
  for (const [name, attributeValue] of Object.entries(value.attributes)) {
766
+ const lower = name.toLowerCase();
766
767
  if (!validAttribute(tag, name, attributeValue)) throw new Error("plugin render attribute is not allowed");
767
- if (name.toLowerCase() === "autofocus") {
768
+ if (lower === "autofocus") {
768
769
  if (attributeValue !== false) element.setAttribute("data-redevplugin-renderer-autofocus", "");
769
770
  continue;
770
771
  }
771
772
  if (typeof attributeValue === "boolean") {
772
- if (attributeValue) element.setAttribute(name, "");
773
+ const serialized = lower.startsWith("aria-") ? String(attributeValue) : "";
774
+ if (attributeValue || serialized) element.setAttribute(name, serialized);
773
775
  } else {
774
776
  element.setAttribute(name, String(attributeValue));
775
777
  }
@@ -891,7 +893,31 @@ export function createOpaquePluginBootstrapHTML(options = {}) {
891
893
  sendWorker(actionPayload(event, element));
892
894
  };
893
895
  for (const eventType of ["click", "input", "change", "submit"]) document.addEventListener(eventType, handleAction, true);
896
+ const focusableModalElements = (modal) => Array.from(modal.querySelectorAll('button:not([disabled]), input:not([disabled]), textarea:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])'))
897
+ .filter((element) => element instanceof HTMLElement && element.tabIndex >= 0 && element.getClientRects().length > 0);
894
898
  document.addEventListener("keydown", (event) => {
899
+ if (event.key === "Tab" && !event.defaultPrevented && !event.repeat) {
900
+ const modal = document.body.querySelector('[role="dialog"][aria-modal="true"]');
901
+ if (modal instanceof HTMLElement) {
902
+ const focusable = focusableModalElements(modal);
903
+ if (focusable.length === 0) {
904
+ event.preventDefault();
905
+ return;
906
+ }
907
+ const first = focusable[0];
908
+ const last = focusable[focusable.length - 1];
909
+ const active = document.activeElement;
910
+ const target = event.shiftKey
911
+ ? (active === first || !modal.contains(active) ? last : undefined)
912
+ : (active === last || !modal.contains(active) ? first : undefined);
913
+ if (target instanceof HTMLElement) {
914
+ event.preventDefault();
915
+ event.stopPropagation();
916
+ try { target.focus({ preventScroll: true }); } catch { target.focus(); }
917
+ }
918
+ }
919
+ return;
920
+ }
895
921
  if (event.key !== "Escape" || event.defaultPrevented || event.repeat) return;
896
922
  const origin = event.target instanceof Element ? event.target : document.activeElement instanceof Element ? document.activeElement : null;
897
923
  const owner = origin ? origin.closest("[data-redevplugin-escape-action]") : null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@floegence/redevplugin-ui",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "repository": {