@klauswuestefeld/jux-web 2026.3.16 → 2026.7.24

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/jux-web.js CHANGED
@@ -227,234 +227,6 @@ var juxWeb = (function (exports) {
227
227
  return result;
228
228
  };
229
229
 
230
- const juxWhite = '#FFF';
231
- const juxDarkGrey = '#282828';
232
- const juxDimmedDarkGrey = '#28282822';
233
- const juxDimmedBlack = '#00000088';
234
- const juxLightGreen = '#20B03D';
235
- const juxMediumGreen = '#0D631E';
236
-
237
- const onKeyDown = (ev, el, persitent, onClose) => {
238
- if (ev.key === 'Escape') {
239
- if (persitent) {
240
- return;
241
- }
242
- close(el, onClose);
243
- }
244
- else if (ev.key === 'Enter') {
245
- if (ev.target.id === 'members-textarea') {
246
- return;
247
- }
248
- el.dispatchEvent(new CustomEvent('ok'));
249
- }
250
- };
251
- const close = (el, onClose) => {
252
- el.remove();
253
- if (onClose) {
254
- onClose();
255
- }
256
- };
257
- const attachEventHandlers = (el, persitent, onClose) => {
258
- const cancelButton = el.querySelector('.cancel');
259
- cancelButton === null || cancelButton === void 0 ? void 0 : cancelButton.addEventListener('click', (_e) => {
260
- el.dispatchEvent(new CustomEvent('cancel'));
261
- if (el.hasAttribute('dont-remove')) {
262
- return;
263
- }
264
- close(el, onClose);
265
- });
266
- const closeButton = el.querySelector('.close');
267
- if (closeButton) {
268
- closeButton.addEventListener('click', (_e) => {
269
- close(el, onClose);
270
- });
271
- }
272
- const okButton = el.querySelector('.ok');
273
- okButton === null || okButton === void 0 ? void 0 : okButton.addEventListener('click', (_e) => {
274
- el.dispatchEvent(new CustomEvent('ok'));
275
- });
276
- el.removeEventListener('keydown', (ev) => onKeyDown(ev, el, persitent, () => onClose));
277
- el.addEventListener('keydown', (ev) => onKeyDown(ev, el, persitent, () => onClose));
278
- el === null || el === void 0 ? void 0 : el.addEventListener('click', (e) => {
279
- if (e.target === el) {
280
- if (persitent) {
281
- return;
282
- }
283
- close(el, onClose);
284
- }
285
- });
286
- };
287
- // TODO: Mudar construtor para usar essa interface
288
- // interface JuxModalOptions {
289
- // title?: string,
290
- // btns?: string[],
291
- // content?: string,
292
- // isPersistent?: boolean,
293
- // isBusy?: boolean,
294
- // body?: HTMLElement,
295
- // okTxt?: string,
296
- // cancelTxt?: string,
297
- // onClose?: any,
298
- // titleStyle?: string,
299
- // }
300
- const applyWrapperStyle = (wrapper) => {
301
- wrapper.style.alignItems = 'center';
302
- wrapper.style.backgroundColor = juxWhite;
303
- wrapper.style.borderRadius = '.3125rem';
304
- wrapper.style.boxShadow = `0 0 1.33rem ${juxDimmedBlack}`;
305
- wrapper.style.boxSizing = 'content-box';
306
- wrapper.style.display = 'flex';
307
- wrapper.style.flexDirection = 'column';
308
- wrapper.style.justifyContent = 'flex-start';
309
- wrapper.style.margin = '0';
310
- wrapper.style.maxHeight = '88%';
311
- wrapper.style.maxWidth = '40%';
312
- wrapper.style.minWidth = '20%';
313
- wrapper.style.padding = '2.8rem';
314
- wrapper.style.position = 'relative';
315
- };
316
- const applyModalStyle = (modal) => {
317
- modal.style.alignItems = 'center';
318
- modal.style.backgroundColor = juxDimmedBlack;
319
- modal.style.display = 'flex';
320
- modal.style.height = '100vh';
321
- modal.style.justifyContent = 'center';
322
- modal.style.left = '0';
323
- modal.style.overflow = 'hidden';
324
- modal.style.position = 'fixed';
325
- modal.style.top = '0';
326
- modal.style.width = '100%';
327
- modal.style.zIndex = '9999';
328
- };
329
- const applyHeaderStyle = (header) => {
330
- header.style.alignItems = 'center';
331
- header.style.color = juxMediumGreen;
332
- header.style.flexDirection = 'row';
333
- header.style.fontSize = '16px';
334
- header.style.fontWeight = '700';
335
- header.style.justifyContent = 'space-between';
336
- header.style.margin = '0';
337
- header.style.display = 'flex';
338
- header.style.position = 'relative';
339
- header.style.width = '100%';
340
- };
341
- const applyJuxModalContentStyle = (el) => {
342
- el.style.display = 'flex';
343
- el.style.position = 'relative';
344
- el.style.width = '100%';
345
- el.style.flexFlow = 'column';
346
- el.style.marginTop = '1.33rem';
347
- el.style.fontSize = '14px';
348
- el.style.rowGap = '8px';
349
- };
350
- const applyFooterStyle = (footer) => {
351
- footer.style.display = 'flex';
352
- footer.style.width = '100%';
353
- footer.style.justifyContent = 'flex-end';
354
- footer.style.alignItems = 'center';
355
- footer.style.gap = '0.75rem';
356
- footer.style.marginTop = '1.5rem';
357
- footer.style.paddingTop = '1rem';
358
- };
359
- const applyModalButtonStyle = (btn) => {
360
- btn.style.display = 'inline-flex';
361
- btn.style.alignItems = 'center';
362
- btn.style.justifyContent = 'center';
363
- btn.style.height = '36px';
364
- btn.style.minWidth = '88px';
365
- btn.style.padding = '0 16px';
366
- btn.style.background = 'rgb(255, 255, 255)';
367
- btn.style.border = '1px solid rgb(160, 160, 160)';
368
- btn.style.borderRadius = '4px';
369
- btn.style.boxShadow = '0 1px 2px rgba(0,0,0,0.15)';
370
- btn.style.color = 'rgb(68, 68, 68)';
371
- btn.style.fontSize = '14px';
372
- btn.style.fontWeight = '500';
373
- btn.style.whiteSpace = 'nowrap';
374
- btn.style.cursor = 'pointer';
375
- };
376
- const juxModal = (title, btns = ['ok', 'cancel'], content = '', persistent = false, busy = false, body, okTxt = getTranslation('alert-ok-btn-txt'), cancelTxt = getTranslation('alert-cancel-btn-txt'), onClose, titleStyle) => {
377
- const result = document.createElement('jux-modal');
378
- applyModalStyle(result);
379
- const wrapper = document.createElement('modal-wrapper');
380
- applyWrapperStyle(wrapper);
381
- // START close
382
- const closeBtn = document.createElement('button');
383
- if (!persistent) {
384
- closeBtn.className = 'close';
385
- closeBtn.setAttribute('aria-label', getTranslation('close'));
386
- }
387
- // END close
388
- // START header
389
- const header = document.createElement('modal-header');
390
- applyHeaderStyle(header);
391
- if (title) {
392
- if (titleStyle) {
393
- header.classList.add(titleStyle);
394
- }
395
- const h3 = document.createElement('h3');
396
- h3.textContent = title;
397
- h3.style.margin = '0';
398
- header.appendChild(h3);
399
- }
400
- // END header
401
- // START content
402
- const modalContent = document.createElement('jux-modal-content');
403
- applyJuxModalContentStyle(modalContent);
404
- if (content) {
405
- modalContent.innerHTML = content;
406
- }
407
- else if (body) {
408
- modalContent.appendChild(body);
409
- }
410
- // END content
411
- // START footer
412
- const footer = document.createElement('modal-footer');
413
- applyFooterStyle(footer);
414
- if (btns.includes('cancel')) {
415
- const cancelBtn = document.createElement('button');
416
- cancelBtn.classList.add('secondary-button', 'modal-button', 'action', 'cancel-btn', 'cancel');
417
- applyModalButtonStyle(cancelBtn);
418
- const cancelText = document.createElement('button-text');
419
- cancelText.textContent = cancelTxt;
420
- const cancelSpinner = document.createElement('loading-spinner');
421
- if (!busy)
422
- cancelSpinner.style.display = 'none';
423
- cancelBtn.append(cancelText, cancelSpinner);
424
- footer.appendChild(cancelBtn);
425
- }
426
- if (btns.includes('ok')) {
427
- const okBtn = document.createElement('button');
428
- okBtn.classList.add('primary-button', 'modal-button', 'action', 'ok');
429
- applyModalButtonStyle(okBtn);
430
- const okText = document.createElement('button-text');
431
- okText.textContent = okTxt;
432
- const okSpinner = document.createElement('loading-spinner');
433
- if (!busy)
434
- okSpinner.style.display = 'none';
435
- okBtn.append(okText, okSpinner);
436
- footer.appendChild(okBtn);
437
- }
438
- // END footer
439
- if (footer.hasChildNodes()) {
440
- wrapper.append(closeBtn, header, modalContent, footer);
441
- }
442
- else {
443
- wrapper.append(closeBtn, header, modalContent);
444
- }
445
- result.appendChild(wrapper);
446
- if (!persistent) {
447
- result.querySelector('.close').focus();
448
- }
449
- else {
450
- if (btns.includes('ok')) {
451
- result.querySelector('.ok').focus();
452
- }
453
- }
454
- attachEventHandlers(result, persistent, onClose);
455
- return result;
456
- };
457
-
458
230
  /******************************************************************************
459
231
  Copyright (c) Microsoft Corporation.
460
232
 
@@ -899,45 +671,326 @@ var juxWeb = (function (exports) {
899
671
  const authPasswordLogin = (credentials, onLogin, onLoginError, handleUnauthorized) => {
900
672
  backendPost('auth-password', credentials, onLogin, onLoginError, handleUnauthorized);
901
673
  };
902
- const getMXData = (domainName) => __awaiter$2(void 0, void 0, void 0, function* () {
903
- try {
904
- const records = yield fetch(`https://dns.google.com/resolve?name=${domainName}&type=MX`, {
905
- method: 'GET',
906
- mode: 'cors'
907
- });
908
- if (!records.ok) {
909
- console.log('response was not ok');
910
- return null;
911
- }
912
- const recordsJson = yield records.json();
913
- const answer = recordsJson.Answer;
914
- if (!answer) {
915
- return null;
674
+ const getMXData = (domainName) => __awaiter$2(void 0, void 0, void 0, function* () {
675
+ try {
676
+ const records = yield fetch(`https://dns.google.com/resolve?name=${domainName}&type=MX`, {
677
+ method: 'GET',
678
+ mode: 'cors'
679
+ });
680
+ if (!records.ok) {
681
+ console.log('response was not ok');
682
+ return null;
683
+ }
684
+ const recordsJson = yield records.json();
685
+ const answer = recordsJson.Answer;
686
+ if (!answer) {
687
+ return null;
688
+ }
689
+ return Array.from(answer).map((a) => a.data);
690
+ }
691
+ catch (error) {
692
+ console.error('Fetch failed: ', error);
693
+ return null;
694
+ }
695
+ });
696
+
697
+ // TODO: find a better way to import external scripts
698
+ const script$1 = document.createElement('script');
699
+ script$1.type = 'text/javascript';
700
+ script$1.src = 'https://www.google.com/recaptcha/api.js?render=explicit';
701
+ document.head.appendChild(script$1);
702
+ const googleCaptcha = () => {
703
+ const result = document.createElement('google-captcha');
704
+ const notifyCaptchaChange = () => result.dispatchEvent(new Event('captcha-change'));
705
+ const renderCaptcha = () => grecaptcha.ready(() => {
706
+ grecaptcha.render(result, {
707
+ sitekey: process.env.GOOGLE_CAPTCHA_KEY,
708
+ callback: (token) => {
709
+ result.setAttribute('token', token);
710
+ notifyCaptchaChange();
711
+ },
712
+ 'expired-callback': () => {
713
+ result.removeAttribute('token');
714
+ notifyCaptchaChange();
715
+ }
716
+ });
717
+ result.dispatchEvent(new Event('captcha-rendered'));
718
+ });
719
+ if (typeof grecaptcha === 'undefined') {
720
+ script$1.addEventListener('load', renderCaptcha, { once: true });
721
+ }
722
+ else {
723
+ renderCaptcha();
724
+ }
725
+ return result;
726
+ };
727
+
728
+ const juxWhite = '#FFF';
729
+ const juxDarkGrey = '#282828';
730
+ const juxDimmedBlack = '#00000088';
731
+ const juxLightGreen = '#20B03D';
732
+ const juxMediumGreen = '#0D631E';
733
+
734
+ const onKeyDown = (ev, el, persitent, onClose) => {
735
+ if (ev.key === 'Escape') {
736
+ if (persitent) {
737
+ return;
738
+ }
739
+ close(el, onClose);
740
+ }
741
+ else if (ev.key === 'Enter') {
742
+ if (ev.target.id === 'members-textarea') {
743
+ return;
744
+ }
745
+ el.dispatchEvent(new CustomEvent('ok'));
746
+ }
747
+ };
748
+ const close = (el, onClose) => {
749
+ el.remove();
750
+ if (onClose) {
751
+ onClose();
752
+ }
753
+ };
754
+ const attachEventHandlers = (el, persitent, onClose) => {
755
+ const cancelButton = el.querySelector('.cancel');
756
+ cancelButton === null || cancelButton === void 0 ? void 0 : cancelButton.addEventListener('click', (_e) => {
757
+ el.dispatchEvent(new CustomEvent('cancel'));
758
+ if (el.hasAttribute('dont-remove')) {
759
+ return;
760
+ }
761
+ close(el, onClose);
762
+ });
763
+ const closeButton = el.querySelector('.close');
764
+ if (closeButton) {
765
+ closeButton.addEventListener('click', (_e) => {
766
+ close(el, onClose);
767
+ });
768
+ }
769
+ const okButton = el.querySelector('.ok');
770
+ okButton === null || okButton === void 0 ? void 0 : okButton.addEventListener('click', (_e) => {
771
+ el.dispatchEvent(new CustomEvent('ok'));
772
+ });
773
+ el.removeEventListener('keydown', (ev) => onKeyDown(ev, el, persitent, () => onClose));
774
+ el.addEventListener('keydown', (ev) => onKeyDown(ev, el, persitent, () => onClose));
775
+ el === null || el === void 0 ? void 0 : el.addEventListener('click', (e) => {
776
+ if (e.target === el) {
777
+ if (persitent) {
778
+ return;
779
+ }
780
+ close(el, onClose);
781
+ }
782
+ });
783
+ };
784
+ // TODO: Mudar construtor para usar essa interface
785
+ // interface JuxModalOptions {
786
+ // title?: string,
787
+ // btns?: string[],
788
+ // content?: string,
789
+ // isPersistent?: boolean,
790
+ // isBusy?: boolean,
791
+ // body?: HTMLElement,
792
+ // okTxt?: string,
793
+ // cancelTxt?: string,
794
+ // onClose?: any,
795
+ // titleStyle?: string,
796
+ // }
797
+ const applyWrapperStyle = (wrapper) => {
798
+ wrapper.style.alignItems = 'center';
799
+ wrapper.style.backgroundColor = juxWhite;
800
+ wrapper.style.borderRadius = '.3125rem';
801
+ wrapper.style.boxShadow = `0 0 1.33rem ${juxDimmedBlack}`;
802
+ wrapper.style.boxSizing = 'content-box';
803
+ wrapper.style.display = 'flex';
804
+ wrapper.style.flexDirection = 'column';
805
+ wrapper.style.justifyContent = 'flex-start';
806
+ wrapper.style.margin = '0';
807
+ wrapper.style.maxHeight = '88%';
808
+ wrapper.style.maxWidth = '40%';
809
+ wrapper.style.minWidth = '20%';
810
+ wrapper.style.padding = '2.8rem';
811
+ wrapper.style.position = 'relative';
812
+ };
813
+ const applyModalStyle = (modal) => {
814
+ modal.style.alignItems = 'center';
815
+ modal.style.backgroundColor = juxDimmedBlack;
816
+ modal.style.display = 'flex';
817
+ modal.style.height = '100vh';
818
+ modal.style.justifyContent = 'center';
819
+ modal.style.left = '0';
820
+ modal.style.overflow = 'hidden';
821
+ modal.style.position = 'fixed';
822
+ modal.style.top = '0';
823
+ modal.style.width = '100%';
824
+ modal.style.zIndex = '9999';
825
+ };
826
+ const applyHeaderStyle = (header) => {
827
+ header.style.alignItems = 'center';
828
+ header.style.color = juxMediumGreen;
829
+ header.style.flexDirection = 'row';
830
+ header.style.fontSize = '16px';
831
+ header.style.fontWeight = '700';
832
+ header.style.justifyContent = 'space-between';
833
+ header.style.margin = '0';
834
+ header.style.display = 'flex';
835
+ header.style.position = 'relative';
836
+ header.style.width = '100%';
837
+ };
838
+ const applyJuxModalContentStyle = (el) => {
839
+ el.style.display = 'flex';
840
+ el.style.position = 'relative';
841
+ el.style.width = '100%';
842
+ el.style.flexFlow = 'column';
843
+ el.style.marginTop = '1.33rem';
844
+ el.style.fontSize = '14px';
845
+ el.style.rowGap = '8px';
846
+ };
847
+ const applyFooterStyle = (footer) => {
848
+ footer.style.display = 'flex';
849
+ footer.style.width = '100%';
850
+ footer.style.justifyContent = 'flex-end';
851
+ footer.style.alignItems = 'center';
852
+ footer.style.gap = '0.75rem';
853
+ footer.style.marginTop = '1.5rem';
854
+ footer.style.paddingTop = '1rem';
855
+ };
856
+ const applyModalButtonStyle = (btn) => {
857
+ btn.style.display = 'inline-flex';
858
+ btn.style.alignItems = 'center';
859
+ btn.style.justifyContent = 'center';
860
+ btn.style.height = '36px';
861
+ btn.style.minWidth = '88px';
862
+ btn.style.padding = '0 16px';
863
+ btn.style.background = 'rgb(255, 255, 255)';
864
+ btn.style.border = '1px solid rgb(160, 160, 160)';
865
+ btn.style.borderRadius = '4px';
866
+ btn.style.boxShadow = '0 1px 2px rgba(0,0,0,0.15)';
867
+ btn.style.color = 'rgb(68, 68, 68)';
868
+ btn.style.fontSize = '14px';
869
+ btn.style.fontWeight = '500';
870
+ btn.style.whiteSpace = 'nowrap';
871
+ btn.style.cursor = 'pointer';
872
+ };
873
+ const juxModal = (title, btns = ['ok', 'cancel'], content = '', persistent = false, busy = false, body, okTxt = getTranslation('alert-ok-btn-txt'), cancelTxt = getTranslation('alert-cancel-btn-txt'), onClose, titleStyle) => {
874
+ const result = document.createElement('jux-modal');
875
+ applyModalStyle(result);
876
+ const wrapper = document.createElement('modal-wrapper');
877
+ applyWrapperStyle(wrapper);
878
+ // START close
879
+ const closeBtn = document.createElement('button');
880
+ if (!persistent) {
881
+ closeBtn.className = 'close';
882
+ closeBtn.setAttribute('aria-label', getTranslation('close'));
883
+ }
884
+ // END close
885
+ // START header
886
+ const header = document.createElement('modal-header');
887
+ applyHeaderStyle(header);
888
+ if (title) {
889
+ if (titleStyle) {
890
+ header.classList.add(titleStyle);
916
891
  }
917
- return Array.from(answer).map((a) => a.data);
892
+ const h3 = document.createElement('h3');
893
+ h3.textContent = title;
894
+ h3.style.margin = '0';
895
+ header.appendChild(h3);
918
896
  }
919
- catch (error) {
920
- console.error('Fetch failed: ', error);
921
- return null;
897
+ // END header
898
+ // START content
899
+ const modalContent = document.createElement('jux-modal-content');
900
+ applyJuxModalContentStyle(modalContent);
901
+ if (content) {
902
+ modalContent.innerHTML = content;
922
903
  }
923
- });
924
-
925
- // TODO: find a better way to import external scripts
926
- const script$1 = document.createElement('script');
927
- script$1.type = 'text/javascript';
928
- script$1.src = 'https://www.google.com/recaptcha/api.js';
929
- document.head.appendChild(script$1);
930
- const googleCaptcha = () => {
931
- const result = document.createElement('google-captcha');
932
- window.submitCaptcha = (token) => result.setAttribute('token', token);
933
- result.className = 'g-recaptcha';
934
- // @ts-ignore
935
- result.setAttribute('data-sitekey', process.env.GOOGLE_CAPTCHA_KEY);
936
- result.setAttribute('data-callback', 'submitCaptcha');
937
- grecaptcha.render(result);
904
+ else if (body) {
905
+ modalContent.appendChild(body);
906
+ }
907
+ // END content
908
+ // START footer
909
+ const footer = document.createElement('modal-footer');
910
+ applyFooterStyle(footer);
911
+ if (btns.includes('cancel')) {
912
+ const cancelBtn = document.createElement('button');
913
+ cancelBtn.classList.add('secondary-button', 'modal-button', 'action', 'cancel-btn', 'cancel');
914
+ applyModalButtonStyle(cancelBtn);
915
+ const cancelText = document.createElement('button-text');
916
+ cancelText.textContent = cancelTxt;
917
+ const cancelSpinner = document.createElement('loading-spinner');
918
+ if (!busy)
919
+ cancelSpinner.style.display = 'none';
920
+ cancelBtn.append(cancelText, cancelSpinner);
921
+ footer.appendChild(cancelBtn);
922
+ }
923
+ if (btns.includes('ok')) {
924
+ const okBtn = document.createElement('button');
925
+ okBtn.classList.add('primary-button', 'modal-button', 'action', 'ok');
926
+ applyModalButtonStyle(okBtn);
927
+ const okText = document.createElement('button-text');
928
+ okText.textContent = okTxt;
929
+ const okSpinner = document.createElement('loading-spinner');
930
+ if (!busy)
931
+ okSpinner.style.display = 'none';
932
+ okBtn.append(okText, okSpinner);
933
+ footer.appendChild(okBtn);
934
+ }
935
+ // END footer
936
+ if (footer.hasChildNodes()) {
937
+ wrapper.append(closeBtn, header, modalContent, footer);
938
+ }
939
+ else {
940
+ wrapper.append(closeBtn, header, modalContent);
941
+ }
942
+ result.appendChild(wrapper);
943
+ if (!persistent) {
944
+ result.querySelector('.close').focus();
945
+ }
946
+ else {
947
+ if (btns.includes('ok')) {
948
+ result.querySelector('.ok').focus();
949
+ }
950
+ }
951
+ attachEventHandlers(result, persistent, onClose);
938
952
  return result;
939
953
  };
940
954
 
955
+ const loginFieldClass = 'jux-login-field';
956
+ const addLoginFieldStyles = () => {
957
+ if (document.querySelector(`style[data-${loginFieldClass}]`))
958
+ return;
959
+ const style = document.createElement('style');
960
+ style.setAttribute(`data-${loginFieldClass}`, '');
961
+ style.textContent = `
962
+ .${loginFieldClass}:hover {
963
+ outline: 1px solid #999 !important;
964
+ outline-offset: -1px;
965
+ }
966
+ .${loginFieldClass}:focus {
967
+ outline: 2px solid #3943B7 !important;
968
+ outline-offset: -2px;
969
+ }
970
+ `;
971
+ document.head.appendChild(style);
972
+ };
973
+ const applyTextFieldStyle = (field) => {
974
+ addLoginFieldStyles();
975
+ field.classList.add(loginFieldClass);
976
+ field.style.backgroundColor = '#fff';
977
+ field.style.border = '1px solid #ccc';
978
+ field.style.borderRadius = '8px';
979
+ field.style.boxShadow = 'inset 0 2px 3px #28282822';
980
+ field.style.boxSizing = 'border-box';
981
+ field.style.color = '#444';
982
+ field.style.cursor = 'text';
983
+ field.style.fontFamily = 'Helvetica, Arial, sans-serif';
984
+ field.style.fontSize = '16px';
985
+ field.style.height = '40px';
986
+ field.style.lineHeight = '38px';
987
+ field.style.margin = '0';
988
+ field.style.outline = 'none';
989
+ field.style.overflow = 'hidden';
990
+ field.style.padding = '0 12px';
991
+ field.style.width = '100%';
992
+ };
993
+
941
994
  const socialLoginModal = (userEmail, mailExchanger, token, onUserLogin, onReturn, backgroundImage, currentPage, clientBody, closeMagicLinkModal, handlers) => {
942
995
  const result = document.createElement('social-login-modal');
943
996
  const email = document.createElement('p');
@@ -1011,77 +1064,118 @@ var juxWeb = (function (exports) {
1011
1064
  closeMagicLinkModal();
1012
1065
  });
1013
1066
  const applyMagicEmailFieldStyle = (el) => {
1067
+ el.style.alignItems = 'center';
1014
1068
  el.style.display = 'flex';
1015
- el.style.flexFlow = 'column';
1069
+ el.style.flexFlow = 'row';
1070
+ el.style.gap = '0';
1016
1071
  el.style.marginTop = '8px';
1017
- el.style.rowGap = '8px';
1018
1072
  el.style.width = '100%';
1019
1073
  };
1020
- const applyInputStyle = (input) => {
1021
- input.style.border = `1px solid ${juxDarkGrey}`;
1022
- input.style.maxWidth = '390px';
1023
- input.style.padding = '10px';
1024
- input.style.width = '100%';
1025
- input.style.backgroundColor = juxWhite;
1026
- input.style.borderRadius = '8px';
1027
- input.style.boxShadow = `inset 0 2px 3px ${juxDimmedDarkGrey}`;
1028
- input.style.height = '40px';
1029
- input.style.whiteSpace = 'pre-line';
1030
- input.style.boxSizing = 'border-box';
1074
+ const applyCaptchaStyle = (captcha) => {
1075
+ const captchaFrameWidth = 304;
1076
+ const captchaHeight = 78;
1077
+ const contentWidth = 356;
1078
+ const horizontalInset = 1;
1079
+ const scale = (contentWidth - horizontalInset * 2) / captchaFrameWidth;
1080
+ captcha.style.height = `${captchaHeight * scale}px`;
1081
+ captcha.style.overflow = 'visible';
1082
+ captcha.style.width = '100%';
1083
+ const applyWidgetStyle = () => {
1084
+ const widget = captcha.firstElementChild;
1085
+ widget.style.marginLeft = `${horizontalInset}px`;
1086
+ widget.style.width = `${captchaFrameWidth}px`;
1087
+ widget.style.transform = `scale(${scale})`;
1088
+ widget.style.transformOrigin = 'top left';
1089
+ };
1090
+ if (captcha.firstElementChild) {
1091
+ applyWidgetStyle();
1092
+ }
1093
+ else {
1094
+ captcha.addEventListener('captcha-rendered', applyWidgetStyle, { once: true });
1095
+ }
1031
1096
  };
1032
1097
  const applyBtnStyle = (btn) => {
1033
- btn.style.alignSelf = 'flex-end';
1034
1098
  btn.style.backgroundColor = juxLightGreen;
1035
1099
  btn.style.border = `2px solid ${juxLightGreen}`;
1036
1100
  btn.style.borderRadius = '8px';
1101
+ btn.style.boxSizing = 'border-box';
1037
1102
  btn.style.color = juxWhite;
1038
1103
  btn.style.cursor = 'pointer';
1039
1104
  btn.style.display = 'inline-block';
1105
+ btn.style.fontSize = '16px';
1040
1106
  btn.style.fontWeight = '700';
1041
1107
  btn.style.height = '40px';
1042
1108
  btn.style.lineHeight = '1';
1043
- btn.style.marginLeft = '10px';
1044
1109
  btn.style.padding = '10px 16px';
1045
1110
  btn.style.position = 'relative';
1046
1111
  };
1112
+ const captchaModal = (onVerified, onClose) => {
1113
+ const body = document.createElement('captcha-modal-body');
1114
+ body.style.width = '356px';
1115
+ const modal = juxModal('Security check', [], '', false, false, body, '', '', onClose);
1116
+ modal.id = 'magic-email-captcha-modal';
1117
+ const wrapper = modal.querySelector('modal-wrapper');
1118
+ wrapper.style.maxWidth = '356px';
1119
+ wrapper.style.minWidth = '356px';
1120
+ wrapper.style.width = '356px';
1121
+ modal.querySelector('modal-header h3').style.color = juxDarkGrey;
1122
+ document.body.appendChild(modal);
1123
+ const captcha = googleCaptcha();
1124
+ applyCaptchaStyle(captcha);
1125
+ captcha.addEventListener('captcha-change', () => {
1126
+ const token = captcha.getAttribute('token');
1127
+ if (!token)
1128
+ return;
1129
+ modal.remove();
1130
+ onVerified(token);
1131
+ });
1132
+ body.appendChild(captcha);
1133
+ return modal;
1134
+ };
1047
1135
  const magicEmailField = (onUserLogin, onReturn, backgroundImage, currentPage, clientBody, closeMagicLinkModal, loginTypes, handlers) => {
1048
1136
  const result = document.createElement('magic-email-field');
1049
1137
  applyMagicEmailFieldStyle(result);
1050
- const captcha = googleCaptcha();
1051
1138
  const input = document.createElement('input');
1052
1139
  input.id = 'mail-magic';
1053
1140
  input.type = 'text';
1054
- input.className = 'textfield';
1055
- input.placeholder = 'e-mail';
1056
- applyInputStyle(input);
1057
- input.addEventListener('keydown', (ev) => {
1058
- if (ev.key === 'Enter') {
1059
- onMagicLinkRequest(captcha.getAttribute('token'), input, onUserLogin, onReturn, backgroundImage, currentPage, clientBody, closeMagicLinkModal, loginTypes, handlers);
1060
- }
1061
- });
1141
+ input.placeholder = 'Email';
1142
+ applyTextFieldStyle(input);
1143
+ input.style.borderRadius = '8px 0 0 8px';
1144
+ input.style.flex = '1';
1145
+ input.style.minWidth = '0';
1062
1146
  const btn = document.createElement('button');
1063
1147
  applyBtnStyle(btn);
1064
1148
  btn.id = 'send-magic';
1065
1149
  btn.className = 'primary-button';
1066
- btn.addEventListener('click', (_ev) => onMagicLinkRequest(captcha.getAttribute('token'), input, onUserLogin, onReturn, backgroundImage, currentPage, clientBody, closeMagicLinkModal, loginTypes, handlers));
1067
1150
  btn.textContent = getTranslation('send-magic');
1068
- result.append(input, captcha, btn);
1069
- return result;
1070
- };
1071
-
1072
- const magicLinkModal = (onUserLogin, onReturn, backgroundImage, currentPage, clientBody, loginTypes, handlers) => {
1073
- const result = document.createElement('magic-link-modal');
1074
- const subtitle = document.createElement('magic-link-request-subtitle');
1075
- subtitle.style.fontSize = '14px';
1076
- subtitle.textContent = getTranslation('magic-link-request-subtitle');
1077
- const body = document.createElement('magic-link-request-body');
1078
- body.append(subtitle, magicEmailField(onUserLogin, onReturn, backgroundImage, currentPage, clientBody, () => result.remove(), loginTypes, handlers));
1079
- const modal = juxModal(getTranslation('magic-link-request-title'), [], '', false, false, body, '', '', () => result.remove());
1080
- modal.setAttribute('data-cy', 'magic-link-modal');
1081
- result.appendChild(modal);
1082
- const wrapper = modal.querySelector('modal-wrapper');
1083
- wrapper.style.maxWidth = '360px';
1084
- wrapper.style.width = '100%';
1151
+ btn.style.borderRadius = '0 8px 8px 0';
1152
+ btn.style.margin = '0';
1153
+ let openCaptchaModal = null;
1154
+ const requestMagicLink = (token) => onMagicLinkRequest(token, input, onUserLogin, onReturn, backgroundImage, currentPage, clientBody, closeMagicLinkModal, loginTypes, handlers);
1155
+ btn.addEventListener('click', () => {
1156
+ if (input.value.includes('-test@')) {
1157
+ requestMagicLink(null);
1158
+ return;
1159
+ }
1160
+ if (openCaptchaModal === null || openCaptchaModal === void 0 ? void 0 : openCaptchaModal.isConnected)
1161
+ return;
1162
+ openCaptchaModal = captchaModal((token) => {
1163
+ openCaptchaModal = null;
1164
+ requestMagicLink(token);
1165
+ }, () => openCaptchaModal = null);
1166
+ });
1167
+ const updateButtonState = () => {
1168
+ btn.disabled = !isValidEmail(input.value);
1169
+ btn.style.cursor = btn.disabled ? 'not-allowed' : 'pointer';
1170
+ btn.style.opacity = btn.disabled ? '0.5' : '1';
1171
+ };
1172
+ input.addEventListener('input', updateButtonState);
1173
+ input.addEventListener('keydown', (ev) => {
1174
+ if (ev.key === 'Enter' && !btn.disabled)
1175
+ btn.click();
1176
+ });
1177
+ updateButtonState();
1178
+ result.append(input, btn);
1085
1179
  return result;
1086
1180
  };
1087
1181
 
@@ -1129,6 +1223,78 @@ var juxWeb = (function (exports) {
1129
1223
  return result;
1130
1224
  };
1131
1225
 
1226
+ class JuxWebGlobal {
1227
+ setCurrentUser(newUser) {
1228
+ this._currentUser = newUser;
1229
+ }
1230
+ getCurrentUser() {
1231
+ return this._currentUser;
1232
+ }
1233
+ setBackendToken(token) {
1234
+ this._backendToken = token;
1235
+ }
1236
+ getBackendToken() {
1237
+ return this._backendToken;
1238
+ }
1239
+ }
1240
+
1241
+ const resetJuxWebGlobal = () => {
1242
+ window.juxWebGlobal = new JuxWebGlobal();
1243
+ };
1244
+ const getCurrentUser = () => {
1245
+ var _a;
1246
+ return (_a = window.juxWebGlobal) === null || _a === void 0 ? void 0 : _a.getCurrentUser();
1247
+ };
1248
+
1249
+ const setBackendToken = (token) => {
1250
+ var _a;
1251
+ (_a = window.juxWebGlobal) === null || _a === void 0 ? void 0 : _a.setBackendToken(token);
1252
+ if (token)
1253
+ setLocalStorageItem('token', token);
1254
+ };
1255
+ const clearSession = () => {
1256
+ removeLocalStorageItem('token');
1257
+ resetJuxWebGlobal();
1258
+ };
1259
+ const onTokenAcquired = (token, onUserLogin) => {
1260
+ setBackendToken(token);
1261
+ onUserLogin();
1262
+ };
1263
+
1264
+ const applyLoginTokenStyle = (textarea) => {
1265
+ applyTextFieldStyle(textarea);
1266
+ textarea.style.resize = 'none';
1267
+ textarea.style.setProperty('-webkit-text-security', 'disc');
1268
+ };
1269
+ const loginTokenTextarea = (onUserLogin, onLoginError) => {
1270
+ const juxWebGlobal = window.juxWebGlobal;
1271
+ const textarea = document.createElement('textarea');
1272
+ textarea.id = 'input-login-token';
1273
+ textarea.autocomplete = 'off';
1274
+ textarea.placeholder = 'Paste sign-in token';
1275
+ textarea.rows = 1;
1276
+ textarea.spellcheck = false;
1277
+ textarea.setAttribute('aria-label', 'Sign-in token');
1278
+ applyLoginTokenStyle(textarea);
1279
+ let loginInProgress = false;
1280
+ textarea.addEventListener('input', () => {
1281
+ const loginToken = textarea.value.trim();
1282
+ if (loginToken.length !== 16 || loginInProgress)
1283
+ return;
1284
+ loginInProgress = true;
1285
+ juxWebGlobal.setBackendToken(loginToken);
1286
+ backendGet('profile', null, (res) => {
1287
+ juxWebGlobal.setCurrentUser(res);
1288
+ onTokenAcquired(loginToken, onUserLogin);
1289
+ }, (err) => {
1290
+ loginInProgress = false;
1291
+ juxWebGlobal.setBackendToken('');
1292
+ onLoginError(err);
1293
+ });
1294
+ });
1295
+ return textarea;
1296
+ };
1297
+
1132
1298
  const authPasswordRow = (type, autoCompleteValue) => {
1133
1299
  const result = document.createElement(`${type}-row`);
1134
1300
  result.style.display = 'flex';
@@ -1192,10 +1358,6 @@ var juxWeb = (function (exports) {
1192
1358
  });
1193
1359
  return result;
1194
1360
  };
1195
- const onEmailLoginRequest = (clientApp, loginPage, onUserLogin, backgroundImage, loginTypes, handlers) => {
1196
- const onReturn = () => clientApp.appendChild(loginPage);
1197
- loginPage.appendChild(magicLinkModal(onUserLogin, onReturn, backgroundImage, loginPage, clientApp, loginTypes, handlers));
1198
- };
1199
1361
  const appendLoginTypes = (loginPage, btnsContainer, clientApp, onUserLogin, onLoginError, loginTypes, backgroundImg, explanation, handleSSOLogin, handlers) => {
1200
1362
  const upperLoginTypes = loginTypes.map(str => str.toUpperCase());
1201
1363
  if (upperLoginTypes.length === 0) {
@@ -1205,7 +1367,42 @@ var juxWeb = (function (exports) {
1205
1367
  }
1206
1368
  const onlyAuth = upperLoginTypes.length > 0 &&
1207
1369
  upperLoginTypes.every(type => type === 'AUTH-PASSWORD');
1370
+ const onlyEmail = upperLoginTypes.every(type => type === 'EMAIL');
1208
1371
  applyFormattedTranslation(explanation, 'sign-in-explanation');
1372
+ const showLoginTypes = () => {
1373
+ btnsContainer.replaceChildren();
1374
+ appendLoginTypes(loginPage, btnsContainer, clientApp, onUserLogin, onLoginError, loginTypes, backgroundImg, explanation, handleSSOLogin, handlers);
1375
+ };
1376
+ const showEmailLogin = () => {
1377
+ btnsContainer.replaceChildren();
1378
+ applyFormattedTranslation(explanation, 'magic-link-request-title');
1379
+ const subtitle = document.createElement('magic-link-request-subtitle');
1380
+ subtitle.style.fontSize = '14px';
1381
+ subtitle.style.lineHeight = '20px';
1382
+ subtitle.style.marginLeft = '2px';
1383
+ subtitle.style.marginTop = '12px';
1384
+ subtitle.style.width = 'calc(100% - 2px)';
1385
+ subtitle.textContent = getTranslation('magic-link-request-subtitle');
1386
+ const onReturn = () => {
1387
+ showLoginTypes();
1388
+ clientApp.appendChild(loginPage);
1389
+ };
1390
+ const content = document.createElement('email-login-content');
1391
+ content.style.alignItems = 'center';
1392
+ content.style.display = 'flex';
1393
+ content.style.flexDirection = 'column';
1394
+ content.style.width = '356px';
1395
+ const tokenInput = loginTokenTextarea(onUserLogin, onLoginError);
1396
+ tokenInput.style.marginTop = '24px';
1397
+ content.append(subtitle, magicEmailField(onUserLogin, onReturn, backgroundImg, loginPage, clientApp, () => { }, upperLoginTypes, handlers), tokenInput);
1398
+ btnsContainer.appendChild(content);
1399
+ if (!onlyEmail)
1400
+ btnsContainer.appendChild(backButton('Back', showLoginTypes));
1401
+ };
1402
+ if (onlyEmail) {
1403
+ showEmailLogin();
1404
+ return;
1405
+ }
1209
1406
  if (upperLoginTypes.includes('AUTH-PASSWORD2') || onlyAuth) {
1210
1407
  btnsContainer.replaceChildren();
1211
1408
  btnsContainer.appendChild(authPasswordForm(clientApp, loginPage, onUserLogin, onLoginError, backgroundImg, handlers));
@@ -1234,7 +1431,7 @@ var juxWeb = (function (exports) {
1234
1431
  btnsContainer.appendChild(loginButton('LINKEDIN', () => console.log('login with Linkedin')));
1235
1432
  }
1236
1433
  if (upperLoginTypes.includes('EMAIL')) {
1237
- btnsContainer.appendChild(loginButton('EMAIL', () => onEmailLoginRequest(clientApp, loginPage, onUserLogin, backgroundImg, upperLoginTypes, handlers)));
1434
+ btnsContainer.appendChild(loginButton('EMAIL', showEmailLogin));
1238
1435
  }
1239
1436
  if (upperLoginTypes.includes('AUTH-PASSWORD')) {
1240
1437
  upperLoginTypes.push('AUTH-PASSWORD2');
@@ -14627,44 +14824,6 @@ var juxWeb = (function (exports) {
14627
14824
  document.body.style.pointerEvents = 'auto';
14628
14825
  };
14629
14826
 
14630
- class JuxWebGlobal {
14631
- setCurrentUser(newUser) {
14632
- this._currentUser = newUser;
14633
- }
14634
- getCurrentUser() {
14635
- return this._currentUser;
14636
- }
14637
- setBackendToken(token) {
14638
- this._backendToken = token;
14639
- }
14640
- getBackendToken() {
14641
- return this._backendToken;
14642
- }
14643
- }
14644
-
14645
- const resetJuxWebGlobal = () => {
14646
- window.juxWebGlobal = new JuxWebGlobal();
14647
- };
14648
- const getCurrentUser = () => {
14649
- var _a;
14650
- return (_a = window.juxWebGlobal) === null || _a === void 0 ? void 0 : _a.getCurrentUser();
14651
- };
14652
-
14653
- const setBackendToken = (token) => {
14654
- var _a;
14655
- (_a = window.juxWebGlobal) === null || _a === void 0 ? void 0 : _a.setBackendToken(token);
14656
- if (token)
14657
- setLocalStorageItem('token', token);
14658
- };
14659
- const clearSession = () => {
14660
- removeLocalStorageItem('token');
14661
- resetJuxWebGlobal();
14662
- };
14663
- const onTokenAcquired = (token, onUserLogin) => {
14664
- setBackendToken(token);
14665
- onUserLogin();
14666
- };
14667
-
14668
14827
  // TODO: find a better way to import external scripts
14669
14828
  const script = document.createElement('script');
14670
14829
  script.type = 'text/javascript';
@@ -15142,6 +15301,22 @@ var juxWeb = (function (exports) {
15142
15301
  onRequestMagicLink();
15143
15302
  };
15144
15303
 
15304
+ const magicLinkModal = (onUserLogin, onReturn, backgroundImage, currentPage, clientBody, loginTypes, handlers) => {
15305
+ const result = document.createElement('magic-link-modal');
15306
+ const subtitle = document.createElement('magic-link-request-subtitle');
15307
+ subtitle.style.fontSize = '14px';
15308
+ subtitle.textContent = getTranslation('magic-link-request-subtitle');
15309
+ const body = document.createElement('magic-link-request-body');
15310
+ body.append(subtitle, magicEmailField(onUserLogin, onReturn, backgroundImage, currentPage, clientBody, () => result.remove(), loginTypes, handlers));
15311
+ const modal = juxModal(getTranslation('magic-link-request-title'), [], '', false, false, body, '', '', () => result.remove());
15312
+ modal.setAttribute('data-cy', 'magic-link-modal');
15313
+ result.appendChild(modal);
15314
+ const wrapper = modal.querySelector('modal-wrapper');
15315
+ wrapper.style.maxWidth = '360px';
15316
+ wrapper.style.width = '100%';
15317
+ return result;
15318
+ };
15319
+
15145
15320
  class JuxEvent extends Event {
15146
15321
  constructor(type, method, endpoint, onResult, params, onError, onRedirect, extras) {
15147
15322
  super('jux-event', { bubbles: true, cancelable: true, composed: true });