@floegence/redevplugin-ui 0.4.1 → 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.
- package/dist/surface.js +28 -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 (
|
|
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
|
-
|
|
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;
|