@votodigital-onpeui/react 0.1.54 → 0.1.56

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/index.mjs CHANGED
@@ -1,9 +1,9 @@
1
- export { BrowserRecommended, Footer, ModalBrowserIncompatible, ModalDnieVersions, ModalNfc, ModalSystemIncompatible, NotRecommended, Overlay, Show } from './chunk-PYHXDWTI.mjs';
2
- export { OnpeIdModal, useIframeCommunication, useIframePreload, useModalIframePreload, useOnpeIdAuth, useSendMessageToIframe, useSocketConnection } from './chunk-6DPRQ3EM.mjs';
1
+ export { BrowserRecommended, Footer, ModalBrowserIncompatible, ModalDnieVersions, ModalNfc, ModalSystemIncompatible, NotRecommended, Overlay, Show } from './chunk-7WO2CKUD.mjs';
2
+ export { OnpeIdModal, useIframeCommunication, useIframePreload, useModalIframePreload, useOnpeIdAuth, useSendMessageToIframe, useSocketConnection } from './chunk-XUSUDWMU.mjs';
3
3
  import './chunk-KWOWOGBU.mjs';
4
- export { Button, ModalConfirm, ModalLoading } from './chunk-FBPCESRR.mjs';
4
+ export { Button, ModalConfirm, ModalLoading } from './chunk-RFIMDKOY.mjs';
5
5
  export { FaceBookIcon, IconAndroid, IconApple, IconCheck, IconChrome, IconChromeColor, IconClose, IconEdge, IconEdgeColor, IconElectionsGeneral, IconElectionsRegionalesYMunicipales, IconHome, IconHuawei, IconInfo, IconLogoONPE, IconMozilla, IconMozillaColor, IconPhone, IconQuestion, IconSafari, IconSafariColor, IconSpinnerDesktop, IconSpinnerMobile, IconVotoDigital, IconWarning, IconWarningNotRecommended, IconWindow, InstagramIcon, TikTokIcon, WhatsappIcon, XIcon, YoutubeIcon } from './chunk-WMTOTUKK.mjs';
6
- export { Modal, Portal } from './chunk-RIILZBD5.mjs';
6
+ export { Modal, Portal } from './chunk-RL3RQN4O.mjs';
7
7
  export { IconCloseRadius } from './chunk-J4MV4J6H.mjs';
8
8
  //# sourceMappingURL=index.mjs.map
9
9
  //# sourceMappingURL=index.mjs.map
package/dist/modal.js CHANGED
@@ -118,6 +118,61 @@ var unlockBodyScroll = (id, enabled) => {
118
118
  document.body.style.overflow = "";
119
119
  }
120
120
  };
121
+ var FOCUSABLE_SELECTOR = [
122
+ "a[href]",
123
+ "area[href]",
124
+ "button:not([disabled])",
125
+ 'input:not([disabled]):not([type="hidden"])',
126
+ "select:not([disabled])",
127
+ "textarea:not([disabled])",
128
+ "iframe",
129
+ "object",
130
+ "embed",
131
+ '[tabindex]:not([tabindex="-1"])',
132
+ '[contenteditable="true"]'
133
+ ].join(",");
134
+ var FOCUS_GUARD_ATTRIBUTE = "data-focus-guard";
135
+ var focusGuardStyle = {
136
+ position: "absolute",
137
+ width: "1px",
138
+ height: "1px",
139
+ padding: 0,
140
+ margin: 0,
141
+ overflow: "hidden",
142
+ clip: "rect(0, 0, 0, 0)",
143
+ whiteSpace: "nowrap",
144
+ border: 0
145
+ };
146
+ var isElementVisible = (element) => {
147
+ const style = globalThis.getComputedStyle(element);
148
+ return style.visibility !== "hidden" && style.display !== "none" && element.offsetParent !== null;
149
+ };
150
+ var getFocusableElements = (wrapper, includeWrapper = true) => {
151
+ let focusable = Array.from(wrapper.querySelectorAll(FOCUSABLE_SELECTOR)).filter(
152
+ (el) => !el.hasAttribute(FOCUS_GUARD_ATTRIBUTE) && isElementVisible(el) && el.tabIndex !== -1
153
+ );
154
+ if (includeWrapper && wrapper.tabIndex >= 0) {
155
+ focusable = [wrapper, ...focusable];
156
+ }
157
+ return focusable;
158
+ };
159
+ var focusWrapper = (wrapper, options) => {
160
+ if (wrapper.tabIndex >= 0) {
161
+ wrapper.focus(options);
162
+ return;
163
+ }
164
+ const focusable = getFocusableElements(wrapper, false);
165
+ focusable[0]?.focus(options);
166
+ };
167
+ var focusEdgeElement = (wrapper, position, options) => {
168
+ const focusable = getFocusableElements(wrapper, false);
169
+ const target = position === "last" ? focusable.at(-1) : focusable[0];
170
+ if (target) {
171
+ target.focus(options);
172
+ return;
173
+ }
174
+ focusWrapper(wrapper, options);
175
+ };
121
176
  var Modal = ({
122
177
  isOpen,
123
178
  onClose,
@@ -146,6 +201,16 @@ var Modal = ({
146
201
  const modalRef = react.useRef(null);
147
202
  const contentRef = react.useRef(null);
148
203
  const previousActiveElement = react.useRef(null);
204
+ const handleStartFocusGuard = () => {
205
+ const wrapper = modalRef.current;
206
+ if (!wrapper) return;
207
+ focusEdgeElement(wrapper, "last", { preventScroll: true });
208
+ };
209
+ const handleEndFocusGuard = () => {
210
+ const wrapper = modalRef.current;
211
+ if (!wrapper) return;
212
+ focusEdgeElement(wrapper, "first", { preventScroll: true });
213
+ };
149
214
  const [mounted, setMounted] = react.useState(false);
150
215
  const [visible, setVisible] = react.useState(false);
151
216
  const [cachedChildren, setCachedChildren] = react.useState(children);
@@ -195,52 +260,21 @@ var Modal = ({
195
260
  [10, 50, 100, 200].forEach((d) => setTimeout(resetScroll, d));
196
261
  }, [isOpen]);
197
262
  react.useEffect(() => {
198
- let focusOutWrapper = null;
199
263
  const pendingTasks = [];
200
- const isElementVisible = (element) => {
201
- const style = globalThis.getComputedStyle(element);
202
- return style.visibility !== "hidden" && style.display !== "none" && element.offsetParent !== null;
203
- };
204
- const getFocusableElements = (wrapper) => {
205
- const selector = [
206
- "a[href]",
207
- "area[href]",
208
- "button:not([disabled])",
209
- 'input:not([disabled]):not([type="hidden"])',
210
- "select:not([disabled])",
211
- "textarea:not([disabled])",
212
- "iframe",
213
- "object",
214
- "embed",
215
- '[tabindex]:not([tabindex="-1"])',
216
- '[contenteditable="true"]'
217
- ].join(",");
218
- let focusable = Array.from(
219
- wrapper.querySelectorAll(selector)
220
- ).filter((el) => isElementVisible(el) && el.tabIndex !== -1);
221
- if (wrapper.tabIndex >= 0) {
222
- focusable = [wrapper, ...focusable];
223
- }
224
- return focusable;
225
- };
226
- const handleFocusOut = (e) => {
264
+ const handleDocumentFocusIn = (e) => {
227
265
  if (!isOpen || disableFocus) return;
228
266
  const wrapper = modalRef.current;
229
- if (!wrapper) return;
230
- const relatedTarget = e.relatedTarget;
231
- if (relatedTarget && !wrapper.contains(relatedTarget)) {
232
- setTimeout(() => {
233
- const currentActive = document.activeElement;
234
- if (!currentActive || !wrapper.contains(currentActive)) {
235
- const focusable = getFocusableElements(wrapper);
236
- if (focusable.length > 0) {
237
- focusable[focusable.length - 1].focus();
238
- } else {
239
- wrapper.focus();
240
- }
241
- }
242
- }, 0);
267
+ const target = e.target;
268
+ if (!wrapper || !(target instanceof HTMLElement) || wrapper.contains(target)) {
269
+ return;
243
270
  }
271
+ requestAnimationFrame(() => {
272
+ const currentActive = document.activeElement;
273
+ if (currentActive instanceof HTMLElement && wrapper.contains(currentActive)) {
274
+ return;
275
+ }
276
+ focusWrapper(wrapper, { preventScroll: true });
277
+ });
244
278
  };
245
279
  const handleKeyDown = (e) => {
246
280
  if (e.key === "Escape" && escapeToClose && !closeDisabled) {
@@ -259,7 +293,7 @@ var Modal = ({
259
293
  if ((e.key === "ArrowUp" || e.key === "ArrowLeft") && activeIndex2 === 0) {
260
294
  e.preventDefault();
261
295
  e.stopPropagation();
262
- if (focusable.length > 1) focusable[focusable.length - 1].focus();
296
+ if (focusable.length > 1) focusable.at(-1)?.focus();
263
297
  else active.focus();
264
298
  return;
265
299
  }
@@ -283,7 +317,7 @@ var Modal = ({
283
317
  e.preventDefault();
284
318
  if (focusable.length > 0) {
285
319
  if (e.key === "ArrowUp" || e.key === "ArrowLeft")
286
- focusable[focusable.length - 1].focus();
320
+ focusable.at(-1)?.focus();
287
321
  else focusable[0].focus();
288
322
  } else {
289
323
  wrapper.focus();
@@ -298,8 +332,13 @@ var Modal = ({
298
332
  return;
299
333
  }
300
334
  const first = focusable[0];
301
- const last = focusable[focusable.length - 1];
335
+ const last = focusable.at(-1);
302
336
  const isShift = e.shiftKey;
337
+ if (!first || !last) {
338
+ e.preventDefault();
339
+ wrapper.focus();
340
+ return;
341
+ }
303
342
  if (!active || !wrapper.contains(active)) {
304
343
  e.preventDefault();
305
344
  (isShift ? last : first).focus();
@@ -322,14 +361,7 @@ var Modal = ({
322
361
  if (isOpen && !disableFocus) {
323
362
  previousActiveElement.current = document.activeElement;
324
363
  const focusInitial = (wrapper) => {
325
- if (ariaLabelledBy && document.getElementById(ariaLabelledBy)) {
326
- wrapper.focus({ preventScroll: true });
327
- return;
328
- }
329
- const focusable = getFocusableElements(wrapper);
330
- const first = focusable[0];
331
- if (first) first.focus({ preventScroll: true });
332
- else wrapper.focus();
364
+ focusWrapper(wrapper, { preventScroll: true });
333
365
  };
334
366
  const bindFocusManagement = (attempt = 0) => {
335
367
  const wrapper = modalRef.current;
@@ -341,14 +373,10 @@ var Modal = ({
341
373
  }
342
374
  return;
343
375
  }
344
- if (focusOutWrapper !== wrapper) {
345
- focusOutWrapper?.removeEventListener("focusout", handleFocusOut);
346
- wrapper.addEventListener("focusout", handleFocusOut);
347
- focusOutWrapper = wrapper;
348
- }
349
376
  focusInitial(wrapper);
350
377
  };
351
378
  document.addEventListener("keydown", handleKeyDown);
379
+ document.addEventListener("focusin", handleDocumentFocusIn, true);
352
380
  pendingTasks.push(globalThis.setTimeout(() => bindFocusManagement(), 0));
353
381
  } else if (isOpen && disableFocus) {
354
382
  document.addEventListener("keydown", handleKeyDown);
@@ -356,7 +384,7 @@ var Modal = ({
356
384
  return () => {
357
385
  pendingTasks.forEach((task) => globalThis.clearTimeout(task));
358
386
  document.removeEventListener("keydown", handleKeyDown);
359
- focusOutWrapper?.removeEventListener("focusout", handleFocusOut);
387
+ document.removeEventListener("focusin", handleDocumentFocusIn, true);
360
388
  if (!disableFocus && !disableFocusRestore && previousActiveElement.current) {
361
389
  previousActiveElement.current.focus();
362
390
  }
@@ -416,6 +444,16 @@ var Modal = ({
416
444
  "aria-describedby": props["aria-describedby"],
417
445
  "aria-label": props["aria-label"],
418
446
  children: [
447
+ /* @__PURE__ */ jsxRuntime.jsx(
448
+ "span",
449
+ {
450
+ tabIndex: disableFocus ? -1 : 0,
451
+ "aria-hidden": "true",
452
+ ...{ [FOCUS_GUARD_ATTRIBUTE]: "start" },
453
+ style: focusGuardStyle,
454
+ onFocus: handleStartFocusGuard
455
+ }
456
+ ),
419
457
  /* @__PURE__ */ jsxRuntime.jsx("div", { ref: contentRef, className: contentClass, children: isOpen ? children : cachedChildren }),
420
458
  closeButton && /* @__PURE__ */ jsxRuntime.jsx(
421
459
  "button",
@@ -426,6 +464,16 @@ var Modal = ({
426
464
  type: "button",
427
465
  children: /* @__PURE__ */ jsxRuntime.jsx(IconCloseRadius, { "aria-hidden": "true", className: "w-full h-full" })
428
466
  }
467
+ ),
468
+ /* @__PURE__ */ jsxRuntime.jsx(
469
+ "span",
470
+ {
471
+ tabIndex: disableFocus ? -1 : 0,
472
+ "aria-hidden": "true",
473
+ ...{ [FOCUS_GUARD_ATTRIBUTE]: "end" },
474
+ style: focusGuardStyle,
475
+ onFocus: handleEndFocusGuard
476
+ }
429
477
  )
430
478
  ]
431
479
  }
@@ -774,7 +822,13 @@ var ModalLoading = ({
774
822
  }
775
823
  )
776
824
  ] }),
777
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-white leading-normal text-2xl md:text-[64px] text-center mt-10 md:mt-20", children: message })
825
+ /* @__PURE__ */ jsxRuntime.jsx(
826
+ "p",
827
+ {
828
+ className: `text-white leading-normal text-2xl md:text-[64px] text-center ${spinner ? "mt-5" : "mt-10 md:mt-20"}`,
829
+ children: message
830
+ }
831
+ )
778
832
  ]
779
833
  }
780
834
  );