@basiq/connect-auth 1.1.36 → 1.1.37-alpha

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
@@ -24,7 +24,7 @@ import React10 from "react";
24
24
  import { ThemeProvider } from "styled-components";
25
25
 
26
26
  // src/App.tsx
27
- import React9, { createRef, useEffect as useEffect2, useState as useState3 } from "react";
27
+ import React9, { createRef, useEffect as useEffect5, useState as useState3 } from "react";
28
28
 
29
29
  // src/styledComponents/ui/basic.ts
30
30
  import styled, { css, keyframes } from "styled-components";
@@ -53,6 +53,11 @@ var SimpleButton = styled.button`
53
53
  cursor: pointer;
54
54
  margin-bottom: 8px;
55
55
  padding: 10px;
56
+
57
+ &:focus-visible {
58
+ outline: 2px solid currentColor;
59
+ outline-offset: 2px;
60
+ }
56
61
  `;
57
62
  var Input = styled.input`
58
63
  height: 48px;
@@ -80,7 +85,8 @@ var Input = styled.input`
80
85
  }
81
86
 
82
87
  &:focus-visible {
83
- outline: none;
88
+ outline: 2px solid ${({ theme: theme2 }) => theme2.color.endeavour};
89
+ outline-offset: 2px;
84
90
  background-color: ${({ theme: theme2 }) => theme2.color.spindle};
85
91
  }
86
92
 
@@ -91,7 +97,6 @@ var Input = styled.input`
91
97
  }
92
98
  `;
93
99
  var H4Styled = styled.h4`
94
- cursor: pointer;
95
100
  user-select: none;
96
101
  ${({ theme: theme2 }) => theme2.mixin.subtitle()};
97
102
  `;
@@ -175,17 +180,17 @@ var ButtonStyled = styled2(SimpleButton)`
175
180
  justify-content: initial;
176
181
  padding: 0;
177
182
  min-height: unset;
178
- color: ${theme2.color.casper};
183
+ color: ${theme2.color.abbey};
179
184
  width: auto;
180
185
  img {
181
186
  width: 25px;
182
- filter: invert(68%) sepia(13%) saturate(348%) hue-rotate(155deg) brightness(91%) contrast(94%);
187
+ filter: invert(31%) sepia(10%) saturate(313%) hue-rotate(155deg) brightness(96%) contrast(87%);
183
188
  }
184
189
  &:hover {
185
- color: ${theme2.color.abbey};
190
+ color: ${theme2.color.jumbo};
186
191
  background-color: unset;
187
192
  img {
188
- filter: invert(31%) sepia(10%) saturate(313%) hue-rotate(155deg) brightness(96%) contrast(87%);
193
+ filter: invert(49%) sepia(0%) saturate(5%) hue-rotate(29deg) brightness(99%) contrast(83%);
189
194
  }
190
195
  }
191
196
  &:active {
@@ -217,6 +222,11 @@ var ButtonStyled = styled2(SimpleButton)`
217
222
  color: ${({ theme: theme2 }) => theme2.color.casper};
218
223
  cursor: not-allowed;
219
224
  }
225
+
226
+ &:focus-visible {
227
+ outline: 2px solid ${({ theme: theme2 }) => theme2.color.congressBlue};
228
+ outline-offset: 2px;
229
+ }
220
230
  `;
221
231
 
222
232
  // src/styledComponents/ui/modals.ts
@@ -237,8 +247,9 @@ var hexToRGBa = (hex, opacity) => {
237
247
  return `rgba(${hexToRGBA == null ? void 0 : hexToRGBA.concat(opp).join()})`;
238
248
  };
239
249
  var handleUserKeyPress = (e, onEnter) => {
240
- const { keyCode } = e;
241
- if (keyCode === 13) {
250
+ const target = e.target;
251
+ const isInteractive = target.tagName === "A" || target.tagName === "BUTTON" || target.tagName === "INPUT" || target.tagName === "SELECT" || target.tagName === "TEXTAREA" || target.getAttribute("role") === "button" || target.getAttribute("role") === "link";
252
+ if (e.key === "Enter" && !isInteractive) {
242
253
  onEnter();
243
254
  }
244
255
  };
@@ -306,7 +317,7 @@ var theme = {
306
317
  dodgerBlueLight: "#5e7Bff",
307
318
  royalBlue: "#4461e6",
308
319
  bostonBlue: "#367ab9",
309
- endeavour: "#0459a8",
320
+ endeavour: "#0460af",
310
321
  congressBlue: "#045097",
311
322
  brilliantBlue: "#0075dc",
312
323
  curiousBlue: "#2784da",
@@ -498,7 +509,7 @@ var PageConnectFooterControl = styled5.div`
498
509
  box-sizing: border-box;
499
510
  padding: 16px;
500
511
  `;
501
- var PageConnectFooterText = styled5.span`
512
+ var PageConnectFooterText = styled5.p`
502
513
  color: ${({ theme: theme2 }) => theme2.color.abbey};
503
514
  font-size: 12px;
504
515
  `;
@@ -514,6 +525,11 @@ var InputStyled = styled5.input`
514
525
  box-shadow: none;
515
526
  letter-spacing: 20px;
516
527
  text-indent: 20px;
528
+
529
+ &:focus-visible {
530
+ outline: 2px solid ${({ theme: theme2 }) => theme2.color.endeavour};
531
+ outline-offset: 2px;
532
+ }
517
533
  `;
518
534
  var InputContainer = styled5.div`
519
535
  width: 100%;
@@ -521,10 +537,22 @@ var InputContainer = styled5.div`
521
537
  align-items: center;
522
538
  justify-content: center;
523
539
  `;
524
- var DivAsLink = styled5.div`
540
+ var DivAsLink = styled5.button`
525
541
  color: ${({ theme: theme2, disabled }) => disabled ? theme2.color.casper : theme2.color.endeavour};
526
- display: inherit;
542
+ display: inline;
527
543
  cursor: ${({ disabled }) => disabled ? "not-allowed" : "pointer"};
544
+ background: none;
545
+ border: none;
546
+ padding: 0;
547
+ font-size: inherit;
548
+ font-family: inherit;
549
+ text-decoration: none;
550
+
551
+ &:focus-visible {
552
+ outline: 2px solid ${({ theme: theme2 }) => theme2.color.endeavour};
553
+ outline-offset: 2px;
554
+ border-radius: 2px;
555
+ }
528
556
  `;
529
557
 
530
558
  // src/styledComponents/pages/start.ts
@@ -583,6 +611,11 @@ var StatusScreenErrorCode = styled7.span`
583
611
  margin-top: 16px;
584
612
  color: ${({ theme: theme2 }) => theme2.color.osloGrey};
585
613
  `;
614
+ var StatusScreenTitle = styled7.h1`
615
+ font-size: 16px;
616
+ font-weight: normal;
617
+ margin: 0 0 4px 0;
618
+ `;
586
619
  var PageSuccessImgContainer = styled7.div`
587
620
  margin-bottom: 24px;
588
621
  width: 64px;
@@ -617,7 +650,7 @@ var Root = styled8.div`
617
650
  text-decoration: none;
618
651
  color: ${({ theme: theme2 }) => theme2.color.endeavour};
619
652
  }
620
- h3 {
653
+ h1 {
621
654
  font-weight: normal;
622
655
  ${({ theme: theme2 }) => theme2.mixin.title()};
623
656
  strong {
@@ -701,10 +734,22 @@ body * {
701
734
  font-size: 14px;
702
735
  font-style: normal;
703
736
  }
737
+
738
+ .visually-hidden {
739
+ position: absolute;
740
+ width: 1px;
741
+ height: 1px;
742
+ padding: 0;
743
+ margin: -1px;
744
+ overflow: hidden;
745
+ clip: rect(0, 0, 0, 0);
746
+ white-space: nowrap;
747
+ border: 0;
748
+ }
704
749
  `;
705
750
 
706
751
  // src/components/pages/Page.tsx
707
- import React2 from "react";
752
+ import React2, { useEffect, useRef as useRef2 } from "react";
708
753
  import { useTranslation } from "react-i18next";
709
754
 
710
755
  // src/components/ui/Button.tsx
@@ -716,7 +761,7 @@ var back_default = 'data:image/svg+xml,<svg width="21" height="21" viewBox="0 0
716
761
  // src/components/ui/Button.tsx
717
762
  function Button(props) {
718
763
  const { onClick, label, buttonType, disabled } = props;
719
- return /* @__PURE__ */ React.createElement(ButtonStyled, { buttonType, disabled: disabled || false, onClick }, buttonType === "back" && /* @__PURE__ */ React.createElement("img", { src: back_default, alt: "" }), /* @__PURE__ */ React.createElement(ButtonLabel, null, " ", label || ""));
764
+ return /* @__PURE__ */ React.createElement(ButtonStyled, { type: "button", buttonType, disabled: disabled || false, onClick }, buttonType === "back" && /* @__PURE__ */ React.createElement("img", { src: back_default, alt: "" }), /* @__PURE__ */ React.createElement(ButtonLabel, null, " ", label || ""));
720
765
  }
721
766
  var Button_default = Button;
722
767
 
@@ -725,7 +770,14 @@ function Page(props) {
725
770
  var _a;
726
771
  const { buttons, children, title, subTitle, shadow, onBack, backDisabled } = props;
727
772
  const { t } = useTranslation();
728
- return /* @__PURE__ */ React2.createElement(PageStyled, { buttonCount: buttons == null ? void 0 : buttons.length }, onBack && /* @__PURE__ */ React2.createElement(Button_default, { onClick: onBack, label: t("back"), buttonType: "back", disabled: backDisabled }), title && /* @__PURE__ */ React2.createElement("h3", null, title), subTitle && /* @__PURE__ */ React2.createElement(PageSubtitle, null, subTitle), /* @__PURE__ */ React2.createElement(PageMainContainer, null, children), /* @__PURE__ */ React2.createElement(PageControlsSection, { notEmpty: ((_a = buttons == null ? void 0 : buttons.length) != null ? _a : 0) > 0 }, /* @__PURE__ */ React2.createElement(PageShadowWrapper, null, shadow && /* @__PURE__ */ React2.createElement(PageShadow, null), buttons == null ? void 0 : buttons.map((b, index) => /* @__PURE__ */ React2.createElement(Button_default, { key: index, onClick: b.onClick, label: b.label, buttonType: b.buttonType, disabled: b.disabled })))));
773
+ const headingRef = useRef2(null);
774
+ useEffect(() => {
775
+ var _a2;
776
+ if (title) {
777
+ (_a2 = headingRef.current) == null ? void 0 : _a2.focus();
778
+ }
779
+ }, []);
780
+ return /* @__PURE__ */ React2.createElement(PageStyled, { buttonCount: buttons == null ? void 0 : buttons.length }, onBack && /* @__PURE__ */ React2.createElement(Button_default, { onClick: onBack, label: t("back"), buttonType: "back", disabled: backDisabled }), title && /* @__PURE__ */ React2.createElement("h1", { ref: headingRef, tabIndex: -1 }, title), subTitle && /* @__PURE__ */ React2.createElement(PageSubtitle, { as: "p" }, subTitle), /* @__PURE__ */ React2.createElement("main", null, /* @__PURE__ */ React2.createElement(PageMainContainer, null, children)), /* @__PURE__ */ React2.createElement(PageControlsSection, { notEmpty: ((_a = buttons == null ? void 0 : buttons.length) != null ? _a : 0) > 0 }, /* @__PURE__ */ React2.createElement(PageShadowWrapper, null, shadow && /* @__PURE__ */ React2.createElement(PageShadow, null), buttons == null ? void 0 : buttons.map((b, index) => /* @__PURE__ */ React2.createElement(Button_default, { key: index, onClick: b.onClick, label: b.label, buttonType: b.buttonType, disabled: b.disabled })))));
729
781
  }
730
782
  var Page_default = Page;
731
783
 
@@ -736,8 +788,8 @@ import { useTranslation as useTranslation2 } from "react-i18next";
736
788
  // src/components/ui/icon.tsx
737
789
  import React3 from "react";
738
790
  function Icon(props) {
739
- const { rotating, img } = props;
740
- return /* @__PURE__ */ React3.createElement(IconWrapper, { rotating }, /* @__PURE__ */ React3.createElement("img", { src: img, alt: "" }));
791
+ const { rotating, img, alt = "" } = props;
792
+ return /* @__PURE__ */ React3.createElement(IconWrapper, { rotating }, /* @__PURE__ */ React3.createElement("img", { src: img, alt }));
741
793
  }
742
794
  var icon_default = Icon;
743
795
 
@@ -747,12 +799,12 @@ var error_default = 'data:image/svg+xml,<!-- Generated by IcoMoon.io -->%0A<svg
747
799
  // src/components/pages/NotFound.tsx
748
800
  function NotFound({ messageCode = "404" }) {
749
801
  const { t } = useTranslation2();
750
- return /* @__PURE__ */ React4.createElement(Page_default, { shadow: false }, /* @__PURE__ */ React4.createElement(PageStyled, null, /* @__PURE__ */ React4.createElement(PageStatusScreenMain, null, /* @__PURE__ */ React4.createElement(PageStyled, null, /* @__PURE__ */ React4.createElement(PageStatusScreenContent, null, /* @__PURE__ */ React4.createElement(StatusScreenCircleContainer, { type: "warning" }, /* @__PURE__ */ React4.createElement(icon_default, { img: error_default, rotating: false })), /* @__PURE__ */ React4.createElement("span", null, t("page_not_found")), /* @__PURE__ */ React4.createElement(StatusScreenErrorCode, null, `${t("error")}: ${messageCode}`)))), /* @__PURE__ */ React4.createElement(PageControlsSection, { notEmpty: false }, /* @__PURE__ */ React4.createElement(PageShadowWrapper, null))));
802
+ return /* @__PURE__ */ React4.createElement(Page_default, { shadow: false }, /* @__PURE__ */ React4.createElement(PageStyled, null, /* @__PURE__ */ React4.createElement(PageStatusScreenMain, null, /* @__PURE__ */ React4.createElement(PageStyled, null, /* @__PURE__ */ React4.createElement(PageStatusScreenContent, null, /* @__PURE__ */ React4.createElement(StatusScreenCircleContainer, { type: "warning" }, /* @__PURE__ */ React4.createElement(icon_default, { img: error_default, rotating: false })), /* @__PURE__ */ React4.createElement(StatusScreenTitle, null, t("page_not_found")), /* @__PURE__ */ React4.createElement(StatusScreenErrorCode, null, `${t("error")}: ${messageCode}`)))), /* @__PURE__ */ React4.createElement(PageControlsSection, { notEmpty: false }, /* @__PURE__ */ React4.createElement(PageShadowWrapper, null))));
751
803
  }
752
804
  var NotFound_default = NotFound;
753
805
 
754
806
  // src/components/pages/StartScreen.tsx
755
- import React7, { useEffect, useState } from "react";
807
+ import React7, { useEffect as useEffect3, useState } from "react";
756
808
  import { Trans, useTranslation as useTranslation4 } from "react-i18next";
757
809
 
758
810
  // src/actions/actions.ts
@@ -840,15 +892,68 @@ import React6 from "react";
840
892
  import { useTranslation as useTranslation3 } from "react-i18next";
841
893
 
842
894
  // src/components/ui/Modal.tsx
843
- import React5 from "react";
895
+ import React5, { useEffect as useEffect2, useRef as useRef3 } from "react";
844
896
  function Modal(props) {
845
- const { children, onClose, isOpen, disableTransparency } = props;
897
+ const { children, onClose, isOpen, disableTransparency, role = "dialog", ariaLabel, ariaLive } = props;
898
+ const modalRef = useRef3(null);
899
+ const previousFocusRef = useRef3(null);
900
+ useEffect2(() => {
901
+ var _a, _b;
902
+ if (isOpen) {
903
+ previousFocusRef.current = document.activeElement;
904
+ (_a = modalRef.current) == null ? void 0 : _a.focus();
905
+ } else {
906
+ (_b = previousFocusRef.current) == null ? void 0 : _b.focus();
907
+ previousFocusRef.current = null;
908
+ }
909
+ }, [isOpen]);
846
910
  const handleOutsideClick = (e) => {
847
911
  if (onClose && e.target.id === "ui-modal") {
848
912
  onClose();
849
913
  }
850
914
  };
851
- return /* @__PURE__ */ React5.createElement(React5.Fragment, null, isOpen ? /* @__PURE__ */ React5.createElement(ModalStyled, { id: "ui-modal", disableTransparency, onClick: handleOutsideClick }, children) : null);
915
+ const handleKeyDown = (e) => {
916
+ if (e.key === "Escape" && onClose) {
917
+ e.stopPropagation();
918
+ onClose();
919
+ return;
920
+ }
921
+ if (!modalRef.current) return;
922
+ const focusable = modalRef.current.querySelectorAll(
923
+ 'a[href], button:not([disabled]), input:not([disabled]), [tabindex]:not([tabindex="-1"])'
924
+ );
925
+ if (focusable.length === 0) {
926
+ if (e.key === "Tab") e.preventDefault();
927
+ return;
928
+ }
929
+ const first = focusable[0];
930
+ const last = focusable[focusable.length - 1];
931
+ if (e.key === "Tab") {
932
+ if (e.shiftKey && document.activeElement === first) {
933
+ e.preventDefault();
934
+ last.focus();
935
+ } else if (!e.shiftKey && document.activeElement === last) {
936
+ e.preventDefault();
937
+ first.focus();
938
+ }
939
+ }
940
+ };
941
+ return /* @__PURE__ */ React5.createElement(React5.Fragment, null, isOpen ? /* @__PURE__ */ React5.createElement(
942
+ ModalStyled,
943
+ {
944
+ id: "ui-modal",
945
+ ref: modalRef,
946
+ tabIndex: -1,
947
+ disableTransparency,
948
+ onClick: handleOutsideClick,
949
+ onKeyDown: handleKeyDown,
950
+ role,
951
+ "aria-modal": role === "dialog" ? true : void 0,
952
+ "aria-label": ariaLabel,
953
+ "aria-live": ariaLive
954
+ },
955
+ children
956
+ ) : null);
852
957
  }
853
958
  var Modal_default = Modal;
854
959
 
@@ -859,7 +964,8 @@ var loading_indicator_default = 'data:image/svg+xml,<!-- Generated by IcoMoon.io
859
964
  function LoadingModal(props) {
860
965
  const { isOpen, disableTransparency, loadingText } = props;
861
966
  const { t } = useTranslation3();
862
- return /* @__PURE__ */ React6.createElement(Modal_default, { isOpen, disableTransparency: !!disableTransparency }, /* @__PURE__ */ React6.createElement(LoadingModalStyled, { disableTransparency: !!disableTransparency }, /* @__PURE__ */ React6.createElement(icon_default, { img: loading_indicator_default, rotating: true }), /* @__PURE__ */ React6.createElement(LoadingModalText, null, loadingText || t("loading"))));
967
+ const label = loadingText || t("loading");
968
+ return /* @__PURE__ */ React6.createElement(Modal_default, { isOpen, disableTransparency: !!disableTransparency, role: "status", ariaLabel: label, ariaLive: "polite" }, /* @__PURE__ */ React6.createElement(LoadingModalStyled, { disableTransparency: !!disableTransparency }, /* @__PURE__ */ React6.createElement(icon_default, { img: loading_indicator_default, rotating: true, alt: "" }), /* @__PURE__ */ React6.createElement(LoadingModalText, { "aria-hidden": "true" }, label)));
863
969
  }
864
970
  var LoadingModal_default = LoadingModal;
865
971
 
@@ -868,12 +974,13 @@ function StartScreen(props) {
868
974
  const { onContinue, appName, shadow, authRequestId, showErrorScreen, smsSent, setSmsSent, test } = props;
869
975
  const [loading, setLoading] = useState(false);
870
976
  const { t } = useTranslation4();
871
- useEffect(() => {
872
- window.addEventListener("keydown", (e) => handleUserKeyPress(e, onContinue));
977
+ useEffect3(() => {
978
+ const handler = (e) => handleUserKeyPress(e, onContinue);
979
+ window.addEventListener("keydown", handler);
873
980
  return () => {
874
- window.removeEventListener("keydown", (e) => handleUserKeyPress(e, onContinue));
981
+ window.removeEventListener("keydown", handler);
875
982
  };
876
- }, []);
983
+ }, [onContinue]);
877
984
  const handleContinue = () => __async(null, null, function* () {
878
985
  setLoading(true);
879
986
  if (authRequestId && !smsSent) {
@@ -903,13 +1010,13 @@ function StartScreen(props) {
903
1010
  shadow,
904
1011
  buttons
905
1012
  },
906
- /* @__PURE__ */ React7.createElement(InnerContainer, null, /* @__PURE__ */ React7.createElement(Spacer, null), /* @__PURE__ */ React7.createElement(H4Styled, null, t("to_do_this_we_will_ask_you_to")), /* @__PURE__ */ React7.createElement("ul", null, /* @__PURE__ */ React7.createElement("li", null, /* @__PURE__ */ React7.createElement(Trans, { t, i18nKey: "verify_your_mobile_number_bold", components: { bold: /* @__PURE__ */ React7.createElement("strong", null) } })), /* @__PURE__ */ React7.createElement("li", null, /* @__PURE__ */ React7.createElement(Trans, { t, i18nKey: "consent_to_share_your_data_with_us", components: { bold: /* @__PURE__ */ React7.createElement("strong", null) } })), /* @__PURE__ */ React7.createElement("li", null, /* @__PURE__ */ React7.createElement(Trans, { t, i18nKey: "share_your_financial_data", components: { bold: /* @__PURE__ */ React7.createElement("strong", null) } }))), /* @__PURE__ */ React7.createElement(H4Styled, null, t("things_you_should_know")), /* @__PURE__ */ React7.createElement("ul", null, /* @__PURE__ */ React7.createElement("li", null, t("we_dont_share_your_data_without_your_consent")), /* @__PURE__ */ React7.createElement("li", null, t("you_can_easily_stop_sharing_your_data_at_any_time")), /* @__PURE__ */ React7.createElement("li", null, t("you_can_choose_to_delete_shared_data_when_we_no_longer_need_it"))), /* @__PURE__ */ React7.createElement(Spacer, null), /* @__PURE__ */ React7.createElement("span", null, /* @__PURE__ */ React7.createElement(React7.Fragment, null, t("by_proceeding_you_agree_to_the"), " ", /* @__PURE__ */ React7.createElement("a", { href: "https://docs.basiq.io/en/articles/415750-basiq-terms-of-service", rel: "noreferrer", target: "_blank" }, t("terms_of_service")), " ", t("and"), " ", /* @__PURE__ */ React7.createElement("a", { href: "https://docs.basiq.io/en/articles/382581-basiq-privacy-policy", rel: "noreferrer", target: "_blank" }, t("privacy_notice")))), /* @__PURE__ */ React7.createElement(LoadingModal_default, { isOpen: loading }))
1013
+ /* @__PURE__ */ React7.createElement(InnerContainer, null, /* @__PURE__ */ React7.createElement(Spacer, null), /* @__PURE__ */ React7.createElement("section", { "aria-labelledby": "steps-heading" }, /* @__PURE__ */ React7.createElement(H4Styled, { id: "steps-heading" }, t("to_do_this_we_will_ask_you_to")), /* @__PURE__ */ React7.createElement("ul", null, /* @__PURE__ */ React7.createElement("li", null, /* @__PURE__ */ React7.createElement(Trans, { t, i18nKey: "verify_your_mobile_number_bold", components: { bold: /* @__PURE__ */ React7.createElement("strong", null) } })), /* @__PURE__ */ React7.createElement("li", null, /* @__PURE__ */ React7.createElement(Trans, { t, i18nKey: "consent_to_share_your_data_with_us", components: { bold: /* @__PURE__ */ React7.createElement("strong", null) } })), /* @__PURE__ */ React7.createElement("li", null, /* @__PURE__ */ React7.createElement(Trans, { t, i18nKey: "share_your_financial_data", components: { bold: /* @__PURE__ */ React7.createElement("strong", null) } })))), /* @__PURE__ */ React7.createElement("section", { "aria-labelledby": "info-heading" }, /* @__PURE__ */ React7.createElement(H4Styled, { id: "info-heading" }, t("things_you_should_know")), /* @__PURE__ */ React7.createElement("ul", null, /* @__PURE__ */ React7.createElement("li", null, t("we_dont_share_your_data_without_your_consent")), /* @__PURE__ */ React7.createElement("li", null, t("you_can_easily_stop_sharing_your_data_at_any_time")), /* @__PURE__ */ React7.createElement("li", null, t("you_can_choose_to_delete_shared_data_when_we_no_longer_need_it")))), /* @__PURE__ */ React7.createElement(Spacer, null), /* @__PURE__ */ React7.createElement("p", null, t("by_proceeding_you_agree_to_the"), " ", /* @__PURE__ */ React7.createElement("a", { href: "https://docs.basiq.io/en/articles/415750-basiq-terms-of-service", rel: "noreferrer noopener", target: "_blank" }, t("terms_of_service")), " ", t("and"), " ", /* @__PURE__ */ React7.createElement("a", { href: "https://docs.basiq.io/en/articles/382581-basiq-privacy-policy", rel: "noreferrer noopener", target: "_blank" }, t("privacy_notice"))), /* @__PURE__ */ React7.createElement(LoadingModal_default, { isOpen: loading }))
907
1014
  );
908
1015
  }
909
1016
  var StartScreen_default = StartScreen;
910
1017
 
911
1018
  // src/components/pages/AuthScreen.tsx
912
- import React8, { useCallback, useState as useState2 } from "react";
1019
+ import React8, { useCallback, useEffect as useEffect4, useRef as useRef4, useState as useState2 } from "react";
913
1020
  import { useTranslation as useTranslation5 } from "react-i18next";
914
1021
  function AuthScreen({ onBack, number, authRequestId, shadow, test, queryString }) {
915
1022
  const { t } = useTranslation5();
@@ -919,6 +1026,13 @@ function AuthScreen({ onBack, number, authRequestId, shadow, test, queryString }
919
1026
  const [resendLoading, setResendLoading] = useState2(false);
920
1027
  const [loading, setLoading] = useState2(false);
921
1028
  const [tooManyAttempts, setTooManyAttempts] = useState2(false);
1029
+ const inputRef = useRef4(null);
1030
+ useEffect4(() => {
1031
+ var _a;
1032
+ if (error) {
1033
+ (_a = inputRef.current) == null ? void 0 : _a.focus();
1034
+ }
1035
+ }, [error]);
922
1036
  const handleCodeApply = useCallback(
923
1037
  (e) => __async(null, null, function* () {
924
1038
  var _a;
@@ -966,6 +1080,10 @@ function AuthScreen({ onBack, number, authRequestId, shadow, test, queryString }
966
1080
  setSmsCode(e.target.value);
967
1081
  }
968
1082
  };
1083
+ const inputId = "sms-code-input";
1084
+ const errorId = "sms-code-error";
1085
+ const statusId = "sms-code-status";
1086
+ const describedBy = [error ? errorId : "", resend ? statusId : ""].filter(Boolean).join(" ") || void 0;
969
1087
  return /* @__PURE__ */ React8.createElement(
970
1088
  Page_default,
971
1089
  {
@@ -976,9 +1094,11 @@ function AuthScreen({ onBack, number, authRequestId, shadow, test, queryString }
976
1094
  onBack,
977
1095
  backDisabled: tooManyAttempts
978
1096
  },
979
- /* @__PURE__ */ React8.createElement(InnerContainer, null, /* @__PURE__ */ React8.createElement(InputContainer, null, /* @__PURE__ */ React8.createElement(
1097
+ /* @__PURE__ */ React8.createElement(InnerContainer, null, /* @__PURE__ */ React8.createElement(InputContainer, null, /* @__PURE__ */ React8.createElement("label", { htmlFor: inputId, className: "visually-hidden" }, t("sms_code_label")), /* @__PURE__ */ React8.createElement(
980
1098
  InputStyled,
981
1099
  {
1100
+ ref: inputRef,
1101
+ id: inputId,
982
1102
  pattern: "\\d{6}",
983
1103
  inputMode: "numeric",
984
1104
  autoComplete: "one-time-code",
@@ -989,9 +1109,21 @@ function AuthScreen({ onBack, number, authRequestId, shadow, test, queryString }
989
1109
  filled: smsCode.length === 6,
990
1110
  error: tooManyAttempts || !!error,
991
1111
  disabled: tooManyAttempts,
992
- onKeyDown: handleCodeApply
1112
+ onKeyDown: handleCodeApply,
1113
+ "aria-required": "true",
1114
+ "aria-invalid": tooManyAttempts || !!error,
1115
+ "aria-describedby": describedBy
993
1116
  }
994
- )), /* @__PURE__ */ React8.createElement(PageConnectFooterControl, null, resend && /* @__PURE__ */ React8.createElement(StatusMessage, null, t("new_sms_code_has_been_sent")), !!error && /* @__PURE__ */ React8.createElement(StatusMessage, { error: true }, error), /* @__PURE__ */ React8.createElement(PageConnectFooterText, null, /* @__PURE__ */ React8.createElement("span", null, /* @__PURE__ */ React8.createElement(React8.Fragment, null, t("didnt_receive_the_code"), " ", /* @__PURE__ */ React8.createElement(DivAsLink, { disabled: tooManyAttempts || resendLoading, onClick: () => !tooManyAttempts && !resendLoading && handleResend() }, t("resend_sms")))))), /* @__PURE__ */ React8.createElement(LoadingModal_default, { isOpen: loading }))
1117
+ )), /* @__PURE__ */ React8.createElement(PageConnectFooterControl, null, resend && /* @__PURE__ */ React8.createElement(StatusMessage, { id: statusId, role: "status", "aria-live": "polite" }, t("new_sms_code_has_been_sent")), !!error && /* @__PURE__ */ React8.createElement(StatusMessage, { id: errorId, error: true, role: "alert", "aria-live": "assertive" }, error), /* @__PURE__ */ React8.createElement(PageConnectFooterText, null, t("didnt_receive_the_code"), " ", /* @__PURE__ */ React8.createElement(
1118
+ DivAsLink,
1119
+ {
1120
+ disabled: tooManyAttempts || resendLoading,
1121
+ onClick: () => !tooManyAttempts && !resendLoading && handleResend(),
1122
+ type: "button",
1123
+ "aria-busy": resendLoading
1124
+ },
1125
+ t("resend_sms")
1126
+ ))), /* @__PURE__ */ React8.createElement(LoadingModal_default, { isOpen: loading }))
995
1127
  );
996
1128
  }
997
1129
  var AuthScreen_default = AuthScreen;
@@ -1017,7 +1149,7 @@ function App(props) {
1017
1149
  setErrorCode(code);
1018
1150
  setCurrentScreen(3);
1019
1151
  };
1020
- useEffect2(() => {
1152
+ useEffect5(() => {
1021
1153
  const getData = () => __async(null, null, function* () {
1022
1154
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
1023
1155
  const id = (_b = (_a = window.location.pathname) == null ? void 0 : _a.substring(1)) == null ? void 0 : _b.split("?")[0];
@@ -1072,7 +1204,7 @@ function App(props) {
1072
1204
  return /* @__PURE__ */ React9.createElement(NotFound_default, { messageCode: errorCode });
1073
1205
  }
1074
1206
  };
1075
- return /* @__PURE__ */ React9.createElement(Root, null, /* @__PURE__ */ React9.createElement(styles_default, null), /* @__PURE__ */ React9.createElement(AppContainerWrapper, null, /* @__PURE__ */ React9.createElement(AppContainer, { onScroll: handleConnectionsScroll, ref }, logo && /* @__PURE__ */ React9.createElement(PageHeader, null, /* @__PURE__ */ React9.createElement("img", { src: logo, alt: "logo" })), /* @__PURE__ */ React9.createElement(AppContainerPage, null, getScreen()))));
1207
+ return /* @__PURE__ */ React9.createElement(Root, null, /* @__PURE__ */ React9.createElement(styles_default, null), /* @__PURE__ */ React9.createElement(AppContainerWrapper, null, /* @__PURE__ */ React9.createElement(AppContainer, { onScroll: handleConnectionsScroll, ref }, logo && /* @__PURE__ */ React9.createElement(PageHeader, null, /* @__PURE__ */ React9.createElement("img", { src: logo, alt: appName ? `${appName} logo` : "Partner logo" })), /* @__PURE__ */ React9.createElement(AppContainerPage, null, getScreen()))));
1076
1208
  }
1077
1209
  var App_default = App;
1078
1210
 
@@ -1109,7 +1241,8 @@ var translation_default = {
1109
1241
  failed_to_send_sms: "Failed to send SMS.",
1110
1242
  page_not_found: "Page not found",
1111
1243
  missing_authentication_token: "Missing Authentication Token",
1112
- too_many_attempts: "Too many attempts. Please use a new link to try again."
1244
+ too_many_attempts: "Too many attempts. Please use a new link to try again.",
1245
+ sms_code_label: "SMS verification code"
1113
1246
  };
1114
1247
 
1115
1248
  // src/locales/i18n.ts