@atlasauth/embed 0.1.0

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 (59) hide show
  1. package/dist/appearance.d.ts +293 -0
  2. package/dist/appearance.js +206 -0
  3. package/dist/appearance.js.map +1 -0
  4. package/dist/client.d.ts +12 -0
  5. package/dist/client.js +49 -0
  6. package/dist/client.js.map +1 -0
  7. package/dist/config.d.ts +27 -0
  8. package/dist/config.js +61 -0
  9. package/dist/config.js.map +1 -0
  10. package/dist/element.d.ts +23 -0
  11. package/dist/element.js +51 -0
  12. package/dist/element.js.map +1 -0
  13. package/dist/embed.js +361 -0
  14. package/dist/icons.d.ts +17 -0
  15. package/dist/icons.js +53 -0
  16. package/dist/icons.js.map +1 -0
  17. package/dist/index.d.ts +19 -0
  18. package/dist/index.js +39 -0
  19. package/dist/index.js.map +1 -0
  20. package/dist/mount.d.ts +7 -0
  21. package/dist/mount.js +33 -0
  22. package/dist/mount.js.map +1 -0
  23. package/dist/redirect.d.ts +17 -0
  24. package/dist/redirect.js +51 -0
  25. package/dist/redirect.js.map +1 -0
  26. package/dist/standalone.d.ts +25 -0
  27. package/dist/standalone.js +34 -0
  28. package/dist/standalone.js.map +1 -0
  29. package/dist/styles.d.ts +17 -0
  30. package/dist/styles.js +389 -0
  31. package/dist/styles.js.map +1 -0
  32. package/dist/widget/captcha.d.ts +21 -0
  33. package/dist/widget/captcha.js +197 -0
  34. package/dist/widget/captcha.js.map +1 -0
  35. package/dist/widget/constants.d.ts +16 -0
  36. package/dist/widget/constants.js +14 -0
  37. package/dist/widget/constants.js.map +1 -0
  38. package/dist/widget/dom.d.ts +18 -0
  39. package/dist/widget/dom.js +71 -0
  40. package/dist/widget/dom.js.map +1 -0
  41. package/dist/widget/flow.d.ts +41 -0
  42. package/dist/widget/flow.js +424 -0
  43. package/dist/widget/flow.js.map +1 -0
  44. package/dist/widget/forms.d.ts +35 -0
  45. package/dist/widget/forms.js +499 -0
  46. package/dist/widget/forms.js.map +1 -0
  47. package/dist/widget/passkey.d.ts +18 -0
  48. package/dist/widget/passkey.js +88 -0
  49. package/dist/widget/passkey.js.map +1 -0
  50. package/dist/widget/render.d.ts +21 -0
  51. package/dist/widget/render.js +210 -0
  52. package/dist/widget/render.js.map +1 -0
  53. package/dist/widget/social.d.ts +44 -0
  54. package/dist/widget/social.js +331 -0
  55. package/dist/widget/social.js.map +1 -0
  56. package/dist/widget.d.ts +124 -0
  57. package/dist/widget.js +182 -0
  58. package/dist/widget.js.map +1 -0
  59. package/package.json +27 -0
package/dist/icons.js ADDED
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ /**
3
+ * Inline brand marks for the social sign-in buttons.
4
+ *
5
+ * A curated set covering the common providers, inlined as SVG strings so the
6
+ * widget stays dependency-free and the bundle carries only what it draws. Marks
7
+ * whose brand colour is near-black (GitHub, Apple, X, Notion) render in
8
+ * `currentColor` so they stay visible on a dark panel; the rest keep their
9
+ * brand colour, which reads on both light and dark. Google and Microsoft use
10
+ * their multi-colour marks. An unknown provider returns null — the button then
11
+ * shows its label with no icon, never a broken image.
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.providerIcon = providerIcon;
15
+ // Multi-colour marks (their own per-path fills — legible on any background).
16
+ const MULTICOLOR = {
17
+ google: '<path fill="#4285F4" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"/><path fill="#34A853" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"/><path fill="#FBBC05" d="M5.84 14.1c-.22-.66-.35-1.36-.35-2.1s.13-1.44.35-2.1V7.06H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.94l3.66-2.84z"/><path fill="#EA4335" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.06l3.66 2.84C6.71 7.31 9.14 5.38 12 5.38z"/>',
18
+ microsoft: '<path fill="#F25022" d="M2 2h9.3v9.3H2z"/><path fill="#7FBA00" d="M12.7 2H22v9.3h-9.3z"/><path fill="#00A4EF" d="M2 12.7h9.3V22H2z"/><path fill="#FFB900" d="M12.7 12.7H22V22h-9.3z"/>',
19
+ };
20
+ // Single-path marks. `fill` is the brand hex, or `currentColor` for near-black
21
+ // brands so they don't vanish on a dark surface.
22
+ const MONO = {
23
+ github: { fill: 'currentColor', path: 'M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12' },
24
+ apple: { fill: 'currentColor', path: 'M12.152 6.896c-.948 0-2.415-1.078-3.96-1.04-2.04.027-3.91 1.183-4.961 3.014-2.117 3.675-.546 9.103 1.519 12.09 1.013 1.454 2.208 3.09 3.792 3.039 1.52-.065 2.09-.987 3.935-.987 1.831 0 2.35.987 3.96.948 1.637-.026 2.676-1.48 3.676-2.948 1.156-1.688 1.636-3.325 1.662-3.415-.039-.013-3.182-1.221-3.22-4.857-.026-3.04 2.48-4.494 2.597-4.559-1.429-2.09-3.623-2.324-4.39-2.376-2-.156-3.675 1.09-4.61 1.09zM15.53 3.83c.843-1.012 1.4-2.427 1.245-3.83-1.207.052-2.662.805-3.532 1.818-.78.896-1.454 2.338-1.273 3.714 1.338.104 2.715-.688 3.559-1.701' },
25
+ x: { fill: 'currentColor', path: 'M14.234 10.162 22.977 0h-2.072l-7.591 8.824L7.251 0H.258l9.168 13.343L.258 24H2.33l8.016-9.318L16.749 24h6.993zm-2.837 3.299-.929-1.329L3.076 1.56h3.182l5.965 8.532.929 1.329 7.754 11.09h-3.182z' },
26
+ notion: { fill: 'currentColor', path: 'M4.459 4.208c.746.606 1.026.56 2.428.466l13.215-.793c.28 0 .047-.28-.046-.326L17.86 1.968c-.42-.326-.981-.7-2.055-.607L3.01 2.295c-.466.046-.56.28-.374.466zm.793 3.08v13.904c0 .747.373 1.027 1.214.98l14.523-.84c.841-.046.935-.56.935-1.167V6.354c0-.606-.233-.933-.748-.887l-15.177.887c-.56.047-.747.327-.747.933zm14.337.745c.093.42 0 .84-.42.888l-.7.14v10.264c-.608.327-1.168.514-1.635.514-.748 0-.935-.234-1.495-.933l-4.577-7.186v6.952L12.21 19s0 .84-1.168.84l-3.222.186c-.093-.186 0-.653.327-.746l.84-.233V9.854L7.822 9.76c-.094-.42.14-1.026.793-1.073l3.456-.233 4.764 7.279v-6.44l-1.215-.139c-.093-.514.28-.887.747-.933zM1.936 1.035l13.31-.98c1.634-.14 2.055-.047 3.082.7l4.249 2.986c.7.513.934.653.934 1.213v16.378c0 1.026-.373 1.634-1.68 1.726l-15.458.934c-.98.047-1.448-.093-1.962-.747l-3.129-4.06c-.56-.747-.793-1.306-.793-1.96V2.667c0-.839.374-1.54 1.447-1.632z' },
27
+ facebook: { fill: '#0866FF', path: 'M9.101 23.691v-7.98H6.627v-3.667h2.474v-1.58c0-4.085 1.848-5.978 5.858-5.978.401 0 .955.042 1.468.103a8.68 8.68 0 0 1 1.141.195v3.325a8.623 8.623 0 0 0-.653-.036 26.805 26.805 0 0 0-.733-.009c-.707 0-1.259.096-1.675.309a1.686 1.686 0 0 0-.679.622c-.258.42-.374.995-.374 1.752v1.297h3.919l-.386 2.103-.287 1.564h-3.246v8.245C19.396 23.238 24 18.179 24 12.044c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.628 3.874 10.35 9.101 11.647Z' },
28
+ discord: { fill: '#5865F2', path: 'M20.317 4.3698a19.7913 19.7913 0 00-4.8851-1.5152.0741.0741 0 00-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 00-.0785-.037 19.7363 19.7363 0 00-4.8852 1.515.0699.0699 0 00-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 00.0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 00.0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 00-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 01-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 01.0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 01.0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 01-.0066.1276 12.2986 12.2986 0 01-1.873.8914.0766.0766 0 00-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 00.0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 00.0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 00-.0312-.0286zM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1569 2.4189zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.946 2.4189-2.1568 2.4189Z' },
29
+ gitlab: { fill: '#FC6D26', path: 'm23.6004 9.5927-.0337-.0862L20.3.9814a.851.851 0 0 0-.3362-.405.8748.8748 0 0 0-.9997.0539.8748.8748 0 0 0-.29.4399l-2.2055 6.748H7.5375l-2.2057-6.748a.8573.8573 0 0 0-.29-.4412.8748.8748 0 0 0-.9997-.0537.8585.8585 0 0 0-.3362.4049L.4332 9.5015l-.0325.0862a6.0657 6.0657 0 0 0 2.0119 7.0105l.0113.0087.03.0213 4.976 3.7264 2.462 1.8633 1.4995 1.1321a1.0085 1.0085 0 0 0 1.2197 0l1.4995-1.1321 2.4619-1.8633 5.006-3.7489.0125-.01a6.0682 6.0682 0 0 0 2.0094-7.003z' },
30
+ spotify: { fill: '#1ED760', path: 'M12 0C5.4 0 0 5.4 0 12s5.4 12 12 12 12-5.4 12-12S18.66 0 12 0zm5.521 17.34c-.24.359-.66.48-1.021.24-2.82-1.74-6.36-2.101-10.561-1.141-.418.122-.779-.179-.899-.539-.12-.421.18-.78.54-.9 4.56-1.021 8.52-.6 11.64 1.32.42.18.479.659.301 1.02zm1.44-3.3c-.301.42-.841.6-1.262.3-3.239-1.98-8.159-2.58-11.939-1.38-.479.12-1.02-.12-1.14-.6-.12-.48.12-1.021.6-1.141C9.6 9.9 15 10.561 18.72 12.84c.361.181.54.78.241 1.2zm.12-3.36C15.24 8.4 8.82 8.16 5.16 9.301c-.6.179-1.2-.181-1.38-.721-.18-.601.18-1.2.72-1.381 4.26-1.26 11.28-1.02 15.721 1.621.539.3.719 1.02.419 1.56-.299.421-1.02.599-1.559.3z' },
31
+ twitch: { fill: '#9146FF', path: 'M11.571 4.714h1.715v5.143H11.57zm4.715 0H18v5.143h-1.714zM6 0L1.714 4.286v15.428h5.143V24l4.286-4.286h3.428L22.286 12V0zm14.571 11.143l-3.428 3.428h-3.429l-3 3v-3H6.857V1.714h13.714Z' },
32
+ reddit: { fill: '#FF4500', path: 'M12 0C5.373 0 0 5.373 0 12c0 3.314 1.343 6.314 3.515 8.485l-2.286 2.286C.775 23.225 1.097 24 1.738 24H12c6.627 0 12-5.373 12-12S18.627 0 12 0Zm4.388 3.199c1.104 0 1.999.895 1.999 1.999 0 1.105-.895 2-1.999 2-.946 0-1.739-.657-1.947-1.539v.002c-1.147.162-2.032 1.15-2.032 2.341v.007c1.776.067 3.4.567 4.686 1.363.473-.363 1.064-.58 1.707-.58 1.547 0 2.802 1.254 2.802 2.802 0 1.117-.655 2.081-1.601 2.531-.088 3.256-3.637 5.876-7.997 5.876-4.361 0-7.905-2.617-7.998-5.87-.954-.447-1.614-1.415-1.614-2.538 0-1.548 1.255-2.802 2.803-2.802.645 0 1.239.218 1.712.585 1.275-.79 2.881-1.291 4.64-1.365v-.01c0-1.663 1.263-3.034 2.88-3.207.188-.911.993-1.595 1.959-1.595Zm-8.085 8.376c-.784 0-1.459.78-1.506 1.797-.047 1.016.64 1.429 1.426 1.429.786 0 1.371-.369 1.418-1.385.047-1.017-.553-1.841-1.338-1.841Zm7.406 0c-.786 0-1.385.824-1.338 1.841.047 1.017.634 1.385 1.418 1.385.785 0 1.473-.413 1.426-1.429-.046-1.017-.721-1.797-1.506-1.797Zm-3.703 4.013c-.974 0-1.907.048-2.77.135-.147.015-.241.168-.183.305.483 1.154 1.622 1.964 2.953 1.964 1.33 0 2.47-.81 2.953-1.964.057-.137-.037-.29-.184-.305-.863-.087-1.795-.135-2.769-.135Z' },
33
+ figma: { fill: '#F24E1E', path: 'M15.852 8.981h-4.588V0h4.588c2.476 0 4.49 2.014 4.49 4.49s-2.014 4.491-4.49 4.491zM12.735 7.51h3.117c1.665 0 3.019-1.355 3.019-3.019s-1.355-3.019-3.019-3.019h-3.117V7.51zm0 1.471H8.148c-2.476 0-4.49-2.014-4.49-4.49S5.672 0 8.148 0h4.588v8.981zm-4.587-7.51c-1.665 0-3.019 1.355-3.019 3.019s1.354 3.02 3.019 3.02h3.117V1.471H8.148zm4.587 15.019H8.148c-2.476 0-4.49-2.014-4.49-4.49s2.014-4.49 4.49-4.49h4.588v8.98zM8.148 8.981c-1.665 0-3.019 1.355-3.019 3.019s1.355 3.019 3.019 3.019h3.117V8.981H8.148zM8.172 24c-2.489 0-4.515-2.014-4.515-4.49s2.014-4.49 4.49-4.49h4.588v4.441c0 2.503-2.047 4.539-4.563 4.539zm-.024-7.51a3.023 3.023 0 0 0-3.019 3.019c0 1.665 1.365 3.019 3.044 3.019 1.705 0 3.093-1.376 3.093-3.068v-2.97H8.148zm7.704 0h-.098c-2.476 0-4.49-2.014-4.49-4.49s2.014-4.49 4.49-4.49h.098c2.476 0 4.49 2.014 4.49 4.49s-2.014 4.49-4.49 4.49zm-.097-7.509c-1.665 0-3.019 1.355-3.019 3.019s1.355 3.019 3.019 3.019h.098c1.665 0 3.019-1.355 3.019-3.019s-1.355-3.019-3.019-3.019h-.098z' },
34
+ dropbox: { fill: '#0061FF', path: 'M6 1.807L0 5.629l6 3.822 6.001-3.822L6 1.807zM18 1.807l-6 3.822 6 3.822 6-3.822-6-3.822zM0 13.274l6 3.822 6.001-3.822L6 9.452l-6 3.822zM18 9.452l-6 3.822 6 3.822 6-3.822-6-3.822zM6 18.371l6.001 3.822 6-3.822-6-3.822L6 18.371z' },
35
+ gitee: { fill: '#C71D23', path: 'M11.984 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0a12 12 0 0 0-.016 0zm6.09 5.333c.328 0 .593.266.592.593v1.482a.594.594 0 0 1-.593.592H9.777c-.982 0-1.778.796-1.778 1.778v5.63c0 .327.266.592.593.592h5.63c.982 0 1.778-.796 1.778-1.778v-.296a.593.593 0 0 0-.592-.593h-4.15a.592.592 0 0 1-.592-.592v-1.482a.593.593 0 0 1 .593-.592h6.815c.327 0 .593.265.593.592v3.408a4 4 0 0 1-4 4H5.926a.593.593 0 0 1-.593-.593V9.778a4.444 4.444 0 0 1 4.445-4.444h8.296Z' },
36
+ };
37
+ /**
38
+ * An inline SVG string for a provider's brand mark, or null when we have none.
39
+ * The SVG carries no width/height — the button CSS sizes it — so one mark works
40
+ * at every button size.
41
+ */
42
+ function providerIcon(id) {
43
+ const multi = MULTICOLOR[id];
44
+ if (multi) {
45
+ return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">${multi}</svg>`;
46
+ }
47
+ const mono = MONO[id];
48
+ if (mono) {
49
+ return `<svg viewBox="0 0 24 24" fill="${mono.fill}" aria-hidden="true" focusable="false"><path d="${mono.path}"/></svg>`;
50
+ }
51
+ return null;
52
+ }
53
+ //# sourceMappingURL=icons.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"icons.js","sourceRoot":"","sources":["../src/icons.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;AAiCH,oCAUC;AAzCD,6EAA6E;AAC7E,MAAM,UAAU,GAA2B;IACzC,MAAM,EACJ,imBAAimB;IACnmB,SAAS,EACP,wLAAwL;CAC3L,CAAC;AAEF,+EAA+E;AAC/E,iDAAiD;AACjD,MAAM,IAAI,GAAmD;IAC3D,MAAM,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,0sBAA0sB,EAAE;IAClvB,KAAK,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,+hBAA+hB,EAAE;IACtkB,CAAC,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,oMAAoM,EAAE;IACvO,MAAM,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,s2BAAs2B,EAAE;IAC94B,QAAQ,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,gbAAgb,EAAE;IACrd,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,ivCAAivC,EAAE;IACrxC,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,idAAid,EAAE;IACpf,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,4kBAA4kB,EAAE;IAChnB,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,wLAAwL,EAAE;IAC3N,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,qmCAAqmC,EAAE;IACxoC,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,09BAA09B,EAAE;IAC5/B,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,mOAAmO,EAAE;IACvQ,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,meAAme,EAAE;CACtgB,CAAC;AAEF;;;;GAIG;AACH,SAAgB,YAAY,CAAC,EAAU;IACrC,MAAM,KAAK,GAAG,UAAU,CAAC,EAAE,CAAC,CAAC;IAC7B,IAAI,KAAK,EAAE,CAAC;QACV,OAAO,iEAAiE,KAAK,QAAQ,CAAC;IACxF,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC;IACtB,IAAI,IAAI,EAAE,CAAC;QACT,OAAO,kCAAkC,IAAI,CAAC,IAAI,mDAAmD,IAAI,CAAC,IAAI,WAAW,CAAC;IAC5H,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * `@atlasauth/embed` — the universal, framework-agnostic sign-in widget.
3
+ *
4
+ * Two ways to use it:
5
+ * - the custom elements `<atlas-sign-in>` / `<atlas-sign-up>` (register with
6
+ * {@link defineElements}), or
7
+ * - the imperative {@link mountSignIn} / {@link mountSignUp}.
8
+ *
9
+ * The standalone `dist/embed.js` IIFE bundle registers the elements and exposes
10
+ * `window.Atlas` automatically; this barrel is the module entry for bundler
11
+ * users who want the same API as an import.
12
+ */
13
+ export { AtlasWidget, type WidgetOptions } from './widget';
14
+ export { defineElements, AtlasSignInElement, AtlasSignUpElement } from './element';
15
+ export { mountSignIn, mountSignUp, type MountTarget } from './mount';
16
+ export { setScriptDefaults, readScriptTag, type ScriptDefaults } from './config';
17
+ export { validateRedirect } from './redirect';
18
+ export { resolveTokens, cssVariables, orderedProviders, providerLabel, classFor, resolveSocialButtons, type DesignTokens, type ElementKey, type WidgetAppearance, type PublicAppearance, type PublicStrategies, type AppearanceResponse, type SocialButtonsConfig, type SocialButtonVariant, type SocialButtonSize, type SocialButtonLayout, type ResolvedSocialButtons, } from './appearance';
19
+ export { providerIcon } from './icons';
package/dist/index.js ADDED
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.providerIcon = exports.resolveSocialButtons = exports.classFor = exports.providerLabel = exports.orderedProviders = exports.cssVariables = exports.resolveTokens = exports.validateRedirect = exports.readScriptTag = exports.setScriptDefaults = exports.mountSignUp = exports.mountSignIn = exports.AtlasSignUpElement = exports.AtlasSignInElement = exports.defineElements = exports.AtlasWidget = void 0;
4
+ /**
5
+ * `@atlasauth/embed` — the universal, framework-agnostic sign-in widget.
6
+ *
7
+ * Two ways to use it:
8
+ * - the custom elements `<atlas-sign-in>` / `<atlas-sign-up>` (register with
9
+ * {@link defineElements}), or
10
+ * - the imperative {@link mountSignIn} / {@link mountSignUp}.
11
+ *
12
+ * The standalone `dist/embed.js` IIFE bundle registers the elements and exposes
13
+ * `window.Atlas` automatically; this barrel is the module entry for bundler
14
+ * users who want the same API as an import.
15
+ */
16
+ var widget_1 = require("./widget");
17
+ Object.defineProperty(exports, "AtlasWidget", { enumerable: true, get: function () { return widget_1.AtlasWidget; } });
18
+ var element_1 = require("./element");
19
+ Object.defineProperty(exports, "defineElements", { enumerable: true, get: function () { return element_1.defineElements; } });
20
+ Object.defineProperty(exports, "AtlasSignInElement", { enumerable: true, get: function () { return element_1.AtlasSignInElement; } });
21
+ Object.defineProperty(exports, "AtlasSignUpElement", { enumerable: true, get: function () { return element_1.AtlasSignUpElement; } });
22
+ var mount_1 = require("./mount");
23
+ Object.defineProperty(exports, "mountSignIn", { enumerable: true, get: function () { return mount_1.mountSignIn; } });
24
+ Object.defineProperty(exports, "mountSignUp", { enumerable: true, get: function () { return mount_1.mountSignUp; } });
25
+ var config_1 = require("./config");
26
+ Object.defineProperty(exports, "setScriptDefaults", { enumerable: true, get: function () { return config_1.setScriptDefaults; } });
27
+ Object.defineProperty(exports, "readScriptTag", { enumerable: true, get: function () { return config_1.readScriptTag; } });
28
+ var redirect_1 = require("./redirect");
29
+ Object.defineProperty(exports, "validateRedirect", { enumerable: true, get: function () { return redirect_1.validateRedirect; } });
30
+ var appearance_1 = require("./appearance");
31
+ Object.defineProperty(exports, "resolveTokens", { enumerable: true, get: function () { return appearance_1.resolveTokens; } });
32
+ Object.defineProperty(exports, "cssVariables", { enumerable: true, get: function () { return appearance_1.cssVariables; } });
33
+ Object.defineProperty(exports, "orderedProviders", { enumerable: true, get: function () { return appearance_1.orderedProviders; } });
34
+ Object.defineProperty(exports, "providerLabel", { enumerable: true, get: function () { return appearance_1.providerLabel; } });
35
+ Object.defineProperty(exports, "classFor", { enumerable: true, get: function () { return appearance_1.classFor; } });
36
+ Object.defineProperty(exports, "resolveSocialButtons", { enumerable: true, get: function () { return appearance_1.resolveSocialButtons; } });
37
+ var icons_1 = require("./icons");
38
+ Object.defineProperty(exports, "providerIcon", { enumerable: true, get: function () { return icons_1.providerIcon; } });
39
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;GAWG;AACH,mCAA2D;AAAlD,qGAAA,WAAW,OAAA;AACpB,qCAAmF;AAA1E,yGAAA,cAAc,OAAA;AAAE,6GAAA,kBAAkB,OAAA;AAAE,6GAAA,kBAAkB,OAAA;AAC/D,iCAAqE;AAA5D,oGAAA,WAAW,OAAA;AAAE,oGAAA,WAAW,OAAA;AACjC,mCAAiF;AAAxE,2GAAA,iBAAiB,OAAA;AAAE,uGAAA,aAAa,OAAA;AACzC,uCAA8C;AAArC,4GAAA,gBAAgB,OAAA;AACzB,2CAkBsB;AAjBpB,2GAAA,aAAa,OAAA;AACb,0GAAA,YAAY,OAAA;AACZ,8GAAA,gBAAgB,OAAA;AAChB,2GAAA,aAAa,OAAA;AACb,sGAAA,QAAQ,OAAA;AACR,kHAAA,oBAAoB,OAAA;AAatB,iCAAuC;AAA9B,qGAAA,YAAY,OAAA"}
@@ -0,0 +1,7 @@
1
+ import { AtlasWidget, type WidgetOptions } from './widget';
2
+ /** A mount target: an element, or a CSS selector resolved against the document. */
3
+ export type MountTarget = Element | string;
4
+ /** Imperatively mount the sign-in panel into an element or selector. */
5
+ export declare function mountSignIn(target: MountTarget, overrides?: Partial<WidgetOptions>): AtlasWidget | null;
6
+ /** Imperatively mount the sign-up panel into an element or selector. */
7
+ export declare function mountSignUp(target: MountTarget, overrides?: Partial<WidgetOptions>): AtlasWidget | null;
package/dist/mount.js ADDED
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mountSignIn = mountSignIn;
4
+ exports.mountSignUp = mountSignUp;
5
+ const widget_1 = require("./widget");
6
+ const config_1 = require("./config");
7
+ function resolve(target) {
8
+ const el = typeof target === 'string' ? document.querySelector(target) : target;
9
+ return el instanceof HTMLElement ? el : null;
10
+ }
11
+ function mount(mode, target, overrides) {
12
+ const host = resolve(target);
13
+ if (!host)
14
+ return null;
15
+ const options = (0, config_1.optionsFromApi)(mode, overrides);
16
+ if (!options) {
17
+ host.textContent =
18
+ 'Atlas: a publishable key and a frontend API origin are required to mount the widget.';
19
+ return null;
20
+ }
21
+ const widget = new widget_1.AtlasWidget(host, options);
22
+ void widget.mount();
23
+ return widget;
24
+ }
25
+ /** Imperatively mount the sign-in panel into an element or selector. */
26
+ function mountSignIn(target, overrides = {}) {
27
+ return mount('sign-in', target, overrides);
28
+ }
29
+ /** Imperatively mount the sign-up panel into an element or selector. */
30
+ function mountSignUp(target, overrides = {}) {
31
+ return mount('sign-up', target, overrides);
32
+ }
33
+ //# sourceMappingURL=mount.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mount.js","sourceRoot":"","sources":["../src/mount.ts"],"names":[],"mappings":";;AAgCA,kCAKC;AAGD,kCAKC;AA7CD,qCAA2D;AAC3D,qCAA0C;AAK1C,SAAS,OAAO,CAAC,MAAmB;IAClC,MAAM,EAAE,GAAG,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAChF,OAAO,EAAE,YAAY,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/C,CAAC;AAED,SAAS,KAAK,CACZ,IAA2B,EAC3B,MAAmB,EACnB,SAAiC;IAEjC,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7B,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IAEvB,MAAM,OAAO,GAAG,IAAA,uBAAc,EAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAChD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,IAAI,CAAC,WAAW;YACd,sFAAsF,CAAC;QACzF,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,oBAAW,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC9C,KAAK,MAAM,CAAC,KAAK,EAAE,CAAC;IACpB,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,wEAAwE;AACxE,SAAgB,WAAW,CACzB,MAAmB,EACnB,YAAoC,EAAE;IAEtC,OAAO,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;AAC7C,CAAC;AAED,wEAAwE;AACxE,SAAgB,WAAW,CACzB,MAAmB,EACnB,YAAoC,EAAE;IAEtC,OAAO,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;AAC7C,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Where the widget may send the browser once a sign-in completes.
3
+ *
4
+ * This is the embedded counterpart of the hosted page's `redirect_url` gate
5
+ * (§13.1): a sign-in surface that will bounce anywhere is a phishing primitive,
6
+ * and here the surface is dropped onto a site whose own markup the tenant does
7
+ * not fully control. So a redirect is accepted only when it is:
8
+ * - a relative path (`/dashboard`), which stays on the page's own origin, or
9
+ * - an absolute URL on the SAME origin as the page, or
10
+ * - an absolute `https:` URL the caller supplied explicitly.
11
+ *
12
+ * Everything else — `http:` cross-origin (downgrade), protocol-relative
13
+ * `//evil.com`, `javascript:`/`data:` (script execution), a malformed string —
14
+ * is rejected by returning null, and the caller falls back to emitting an
15
+ * `atlas:complete` event instead of navigating anywhere it was told to.
16
+ */
17
+ export declare function validateRedirect(raw: string | null | undefined, currentOrigin?: string): string | null;
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateRedirect = validateRedirect;
4
+ /**
5
+ * Where the widget may send the browser once a sign-in completes.
6
+ *
7
+ * This is the embedded counterpart of the hosted page's `redirect_url` gate
8
+ * (§13.1): a sign-in surface that will bounce anywhere is a phishing primitive,
9
+ * and here the surface is dropped onto a site whose own markup the tenant does
10
+ * not fully control. So a redirect is accepted only when it is:
11
+ * - a relative path (`/dashboard`), which stays on the page's own origin, or
12
+ * - an absolute URL on the SAME origin as the page, or
13
+ * - an absolute `https:` URL the caller supplied explicitly.
14
+ *
15
+ * Everything else — `http:` cross-origin (downgrade), protocol-relative
16
+ * `//evil.com`, `javascript:`/`data:` (script execution), a malformed string —
17
+ * is rejected by returning null, and the caller falls back to emitting an
18
+ * `atlas:complete` event instead of navigating anywhere it was told to.
19
+ */
20
+ function validateRedirect(raw, currentOrigin = typeof window !== 'undefined' ? window.location.origin : '') {
21
+ if (!raw || typeof raw !== 'string')
22
+ return null;
23
+ // A relative path stays on the page's own origin. `//host` is NOT relative —
24
+ // it is protocol-relative and resolves cross-origin, so it is excluded here
25
+ // and falls through to the absolute-URL checks (where it fails to parse).
26
+ if (raw.startsWith('/') && !raw.startsWith('//')) {
27
+ try {
28
+ return currentOrigin ? new URL(raw, currentOrigin).toString() : raw;
29
+ }
30
+ catch {
31
+ return null;
32
+ }
33
+ }
34
+ let url;
35
+ try {
36
+ url = new URL(raw);
37
+ }
38
+ catch {
39
+ // Not an absolute URL and not a rooted relative path — refuse it.
40
+ return null;
41
+ }
42
+ // Same-origin absolute is always fine (it is where the page already is).
43
+ if (currentOrigin && url.origin === currentOrigin)
44
+ return url.toString();
45
+ // A cross-origin destination is only ever allowed over https — never an http
46
+ // downgrade, and never a `javascript:`/`data:`/`mailto:` scheme.
47
+ if (url.protocol === 'https:')
48
+ return url.toString();
49
+ return null;
50
+ }
51
+ //# sourceMappingURL=redirect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redirect.js","sourceRoot":"","sources":["../src/redirect.ts"],"names":[],"mappings":";;AAgBA,4CAiCC;AAjDD;;;;;;;;;;;;;;;GAeG;AACH,SAAgB,gBAAgB,CAC9B,GAA8B,EAC9B,gBAAwB,OAAO,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;IAEnF,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAEjD,6EAA6E;IAC7E,4EAA4E;IAC5E,0EAA0E;IAC1E,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACjD,IAAI,CAAC;YACH,OAAO,aAAa,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;QACtE,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IACrB,CAAC;IAAC,MAAM,CAAC;QACP,kEAAkE;QAClE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,yEAAyE;IACzE,IAAI,aAAa,IAAI,GAAG,CAAC,MAAM,KAAK,aAAa;QAAE,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;IAEzE,6EAA6E;IAC7E,iEAAiE;IACjE,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ;QAAE,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;IAErD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * The IIFE entry point bundled into `dist/embed.js`.
3
+ *
4
+ * Loaded with a plain `<script src=".../embed.js" data-atlas-key="pk_…"
5
+ * data-atlas-fapi="https://accounts.acme.com">`, it:
6
+ * 1. captures the script tag's `data-atlas-*` as page-wide defaults,
7
+ * 2. registers `<atlas-sign-in>` / `<atlas-sign-up>`, which then upgrade any
8
+ * such elements already in the markup, and
9
+ * 3. exposes `window.Atlas` for imperative mounting.
10
+ *
11
+ * It has NO bare imports at runtime — `@atlasauth/js` is bundled in — so it runs
12
+ * from the script tag alone.
13
+ */
14
+ import { defineElements } from './element';
15
+ import { mountSignIn, mountSignUp } from './mount';
16
+ export interface AtlasGlobal {
17
+ mountSignIn: typeof mountSignIn;
18
+ mountSignUp: typeof mountSignUp;
19
+ defineElements: typeof defineElements;
20
+ }
21
+ declare global {
22
+ interface Window {
23
+ Atlas?: AtlasGlobal;
24
+ }
25
+ }
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /**
4
+ * The IIFE entry point bundled into `dist/embed.js`.
5
+ *
6
+ * Loaded with a plain `<script src=".../embed.js" data-atlas-key="pk_…"
7
+ * data-atlas-fapi="https://accounts.acme.com">`, it:
8
+ * 1. captures the script tag's `data-atlas-*` as page-wide defaults,
9
+ * 2. registers `<atlas-sign-in>` / `<atlas-sign-up>`, which then upgrade any
10
+ * such elements already in the markup, and
11
+ * 3. exposes `window.Atlas` for imperative mounting.
12
+ *
13
+ * It has NO bare imports at runtime — `@atlasauth/js` is bundled in — so it runs
14
+ * from the script tag alone.
15
+ */
16
+ const element_1 = require("./element");
17
+ const mount_1 = require("./mount");
18
+ const config_1 = require("./config");
19
+ function currentScript() {
20
+ const active = document.currentScript;
21
+ if (active instanceof HTMLScriptElement)
22
+ return active;
23
+ // `defer`/`async` can null out currentScript; fall back to the tag that
24
+ // carries our config, then any script whose src looks like the bundle.
25
+ return (document.querySelector('script[data-atlas-key]') ??
26
+ document.querySelector('script[src*="embed.js"]'));
27
+ }
28
+ function boot() {
29
+ (0, config_1.setScriptDefaults)((0, config_1.readScriptTag)(currentScript()));
30
+ (0, element_1.defineElements)();
31
+ window.Atlas = { mountSignIn: mount_1.mountSignIn, mountSignUp: mount_1.mountSignUp, defineElements: element_1.defineElements };
32
+ }
33
+ boot();
34
+ //# sourceMappingURL=standalone.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"standalone.js","sourceRoot":"","sources":["../src/standalone.ts"],"names":[],"mappings":";;AAAA;;;;;;;;;;;;GAYG;AACH,uCAA2C;AAC3C,mCAAmD;AACnD,qCAA4D;AAc5D,SAAS,aAAa;IACpB,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC;IACtC,IAAI,MAAM,YAAY,iBAAiB;QAAE,OAAO,MAAM,CAAC;IACvD,wEAAwE;IACxE,uEAAuE;IACvE,OAAO,CACL,QAAQ,CAAC,aAAa,CAAoB,wBAAwB,CAAC;QACnE,QAAQ,CAAC,aAAa,CAAoB,yBAAyB,CAAC,CACrE,CAAC;AACJ,CAAC;AAED,SAAS,IAAI;IACX,IAAA,0BAAiB,EAAC,IAAA,sBAAa,EAAC,aAAa,EAAE,CAAC,CAAC,CAAC;IAClD,IAAA,wBAAc,GAAE,CAAC;IACjB,MAAM,CAAC,KAAK,GAAG,EAAE,WAAW,EAAX,mBAAW,EAAE,WAAW,EAAX,mBAAW,EAAE,cAAc,EAAd,wBAAc,EAAE,CAAC;AAC9D,CAAC;AAED,IAAI,EAAE,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Minimal, scoped stylesheet for the widget.
3
+ *
4
+ * Injected once into the document head (keyed by a data attribute so mounting
5
+ * two widgets does not duplicate it) rather than an inline `style` per element —
6
+ * a single sheet is what a tenant can override with their own CSS, which is the
7
+ * whole reason the widget renders in the host DOM instead of an iframe.
8
+ *
9
+ * Every class is namespaced `atlas-embed-*` so it cannot collide with the host
10
+ * page, and every colour/radius/font reads a `--atlas-embed-*` custom property
11
+ * with a hard-coded fallback, so the widget looks right the instant it mounts —
12
+ * before `GET /v1/appearance` resolves — and re-themes when it does.
13
+ */
14
+ export declare const STYLE_MARKER = "atlas-embed-styles";
15
+ export declare const EMBED_CSS = "\n.atlas-embed-root {\n --_bg: var(--atlas-embed-color-background, #ffffff);\n --_card: var(--atlas-embed-color-card, #ffffff);\n --_text: var(--atlas-embed-color-text, #1c1c1f);\n --_primary: var(--atlas-embed-color-primary, #5b5bd6);\n --_border: var(--atlas-embed-color-border, #e4e4e9);\n --_radius: var(--atlas-embed-border-radius, 10px);\n /* Transition tempo \u2014 the widget sets --atlas-embed-motion from motionSpeed and\n to 0s when animations are off; reduced-motion forces 0s below regardless. */\n --_motion: var(--atlas-embed-motion, 0.16s);\n font-family: var(--atlas-embed-font-family, ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif);\n color: var(--_text);\n box-sizing: border-box;\n display: block;\n}\n.atlas-embed-root *, .atlas-embed-root *::before, .atlas-embed-root *::after { box-sizing: border-box; }\n.atlas-embed-card {\n max-width: 400px;\n margin: 0 auto;\n padding: 28px 26px;\n background: var(--_card);\n border: 1px solid var(--_border);\n border-radius: calc(var(--_radius) + 4px);\n box-shadow: 0 1px 2px rgba(0,0,0,0.04), 0 8px 28px rgba(0,0,0,0.06);\n}\n.atlas-embed-logo { display: block; max-height: 40px; margin: 0 auto 16px; }\n.atlas-embed-title { font-size: 20px; font-weight: 650; text-align: center; margin: 0 0 4px; }\n.atlas-embed-subtitle { font-size: 14px; color: #6b7280; text-align: center; margin: 0 0 20px; }\n.atlas-embed-social { display: flex; flex-direction: column; gap: 8px; margin-bottom: 16px; }\n.atlas-embed-social-button {\n display: flex; align-items: center; justify-content: center; gap: 8px;\n width: 100%; padding: 10px 12px; font-size: 14px; font-weight: 550; cursor: pointer;\n color: var(--_text); background: var(--_card);\n border: 1px solid var(--_border); border-radius: var(--_radius);\n}\n.atlas-embed-social-button:hover { filter: brightness(0.97); }\n.atlas-embed-social-icon { display: inline-flex; flex: none; line-height: 0; }\n.atlas-embed-social-icon svg { width: 18px; height: 18px; display: block; }\n.atlas-embed-social-label { display: inline-block; }\n\n/* Size \u2014 button scale and icon size together. */\n.atlas-embed-social[data-size=\"sm\"] .atlas-embed-social-button { padding: 8px 10px; font-size: 13px; }\n.atlas-embed-social[data-size=\"sm\"] .atlas-embed-social-icon svg { width: 16px; height: 16px; }\n.atlas-embed-social[data-size=\"lg\"] .atlas-embed-social-button { padding: 13px 16px; font-size: 15px; }\n.atlas-embed-social[data-size=\"lg\"] .atlas-embed-social-icon svg { width: 22px; height: 22px; }\n\n/* Icon-only variant: a square button, name in the tooltip. Always laid out as a\n centred wrap (or a carousel), never a full-width bar. */\n.atlas-embed-social-button[data-variant=\"icon\"] { width: auto; padding: 10px; aspect-ratio: 1; }\n.atlas-embed-social[data-size=\"sm\"] .atlas-embed-social-button[data-variant=\"icon\"] { padding: 8px; }\n.atlas-embed-social[data-size=\"lg\"] .atlas-embed-social-button[data-variant=\"icon\"] { padding: 13px; }\n.atlas-embed-social[data-variant=\"icon\"]:not([data-layout=\"carousel\"]) {\n flex-direction: row; flex-wrap: wrap; justify-content: center;\n}\n\n/* Grid \u2014 bars share a row and wrap. */\n.atlas-embed-social[data-layout=\"grid\"] { flex-direction: row; flex-wrap: wrap; }\n.atlas-embed-social[data-layout=\"grid\"] .atlas-embed-social-button { width: auto; flex: 1 1 auto; }\n.atlas-embed-social[data-layout=\"grid\"] .atlas-embed-social-button[data-variant=\"icon\"] { flex: 0 0 auto; }\n\n/* Carousel \u2014 one swipeable, scroll-snapped row. The raw scrollbar is hidden; the\n arrow buttons (below) are the affordance instead. */\n.atlas-embed-social[data-layout=\"carousel\"] {\n flex-direction: row; flex-wrap: nowrap; overflow-x: auto;\n scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch; scroll-behavior: smooth;\n scrollbar-width: none;\n}\n.atlas-embed-social[data-layout=\"carousel\"]::-webkit-scrollbar { display: none; }\n.atlas-embed-social[data-layout=\"carousel\"] .atlas-embed-social-button { width: auto; flex: 0 0 auto; scroll-snap-align: start; }\n.atlas-embed-social[data-layout=\"carousel\"] .atlas-embed-social-button[data-variant=\"block\"] { min-width: 60%; }\n\n/* Carousel shell \u2014 prev/next controls flanking the scroll row. */\n.atlas-embed-carousel { position: relative; display: flex; align-items: center; gap: 4px; margin-bottom: 16px; }\n.atlas-embed-carousel .atlas-embed-social { flex: 1 1 auto; min-width: 0; margin-bottom: 0; }\n.atlas-embed-carousel-nav {\n flex: none; display: inline-flex; align-items: center; justify-content: center;\n width: 30px; height: 30px; padding: 0; cursor: pointer;\n color: var(--_text); background: var(--_card);\n border: 1px solid var(--_border); border-radius: 999px; transition: opacity 0.15s;\n}\n.atlas-embed-carousel-nav svg { width: 16px; height: 16px; display: block; }\n.atlas-embed-carousel-nav:hover:not(:disabled) { filter: brightness(0.97); }\n.atlas-embed-carousel-nav:disabled { opacity: 0.35; cursor: default; }\n/* Nothing overflows \u2192 no controls at all. */\n.atlas-embed-carousel[data-overflow=\"false\"] .atlas-embed-carousel-nav { display: none; }\n/* When the carousel sits inside a search field, the field owns the bottom margin. */\n.atlas-embed-social-field .atlas-embed-carousel { margin-bottom: 0; }\n\n/* Search \u2014 a filter box above a long provider list (socialButtons.search). The\n field wraps the button container so its own margin replaces the button block's. */\n.atlas-embed-social-field { display: flex; flex-direction: column; gap: 8px; margin-bottom: 16px; }\n.atlas-embed-social-field .atlas-embed-social { margin-bottom: 0; }\n.atlas-embed-social-search {\n width: 100%; padding: 9px 12px; font-size: 14px; color: var(--_text);\n background: var(--_bg); border: 1px solid var(--_border); border-radius: var(--_radius);\n}\n.atlas-embed-social-search:focus { outline: 2px solid var(--_primary); outline-offset: -1px; }\n.atlas-embed-social-button[hidden] { display: none; }\n.atlas-embed-social-empty { font-size: 13px; color: #9ca3af; text-align: center; padding: 6px 0; }\n.atlas-embed-social-empty[hidden] { display: none; }\n.atlas-embed-divider {\n display: flex; align-items: center; text-align: center; gap: 10px;\n color: #9ca3af; font-size: 12px; margin: 14px 0;\n}\n.atlas-embed-divider::before, .atlas-embed-divider::after {\n content: \"\"; flex: 1; height: 1px; background: var(--_border);\n}\n.atlas-embed-field { display: block; margin: 0 0 12px; }\n.atlas-embed-label { display: block; font-size: 13px; margin: 0 0 5px; color: var(--_text); }\n.atlas-embed-input {\n width: 100%; padding: 10px 12px; font-size: 14px; color: var(--_text);\n background: var(--_bg); border: 1px solid var(--_border); border-radius: var(--_radius);\n}\n.atlas-embed-input:focus { outline: 2px solid var(--_primary); outline-offset: -1px; }\n/* Password field with a show/hide toggle. */\n.atlas-embed-password { position: relative; display: flex; align-items: center; }\n.atlas-embed-password .atlas-embed-input { width: 100%; padding-right: 54px; }\n.atlas-embed-password-toggle {\n position: absolute; right: 6px; padding: 4px 7px; font: inherit; font-size: 12px; font-weight: 600;\n cursor: pointer; color: var(--_primary); background: none; border: 0; border-radius: 6px;\n}\n.atlas-embed-password-toggle:hover { text-decoration: underline; }\nselect.atlas-embed-input { appearance: auto; }\n.atlas-embed-field-checkbox { display: flex; flex-direction: row-reverse; align-items: center; justify-content: flex-end; gap: 8px; }\n.atlas-embed-field-checkbox .atlas-embed-label { margin: 0; }\n.atlas-embed-checkbox { width: 16px; height: 16px; margin: 0; flex: none; }\ntextarea.atlas-embed-input { min-height: 72px; resize: vertical; font-family: inherit; }\nfieldset.atlas-embed-field { border: 0; padding: 0; margin: 0 0 12px; }\n.atlas-embed-choices { display: flex; flex-direction: column; gap: 6px; }\n.atlas-embed-choice { display: flex; flex-direction: row; align-items: center; gap: 8px; font-size: 14px; cursor: pointer; }\n.atlas-embed-choice input { width: 16px; height: 16px; margin: 0; flex: none; accent-color: var(--_primary); }\n.atlas-embed-button {\n width: 100%; margin-top: 6px; padding: 11px 12px; font-size: 14px; font-weight: 650;\n cursor: pointer; color: #ffffff; background: var(--_primary);\n border: 0; border-radius: var(--_radius);\n}\n.atlas-embed-button:disabled { opacity: 0.6; cursor: default; }\n.atlas-embed-handle-back {\n width: 100%; margin-top: 8px; padding: 6px; font-size: 13px; font-weight: 550;\n cursor: pointer; color: #6b7280; background: none; border: 0;\n}\n.atlas-embed-handle-back:hover { color: #374151; }\n.atlas-embed-error { display: block; font-size: 13px; color: #d64545; margin: 6px 0 0; }\n.atlas-embed-form-error { font-size: 13px; color: #d64545; margin: 0 0 12px; min-height: 0; }\n/* A success/confirmation banner (e.g. after a force-login password reset). */\n.atlas-embed-flash {\n font-size: 13px; color: #0f7a4d; background: rgba(16,163,101,0.08);\n border: 1px solid rgba(16,163,101,0.25); border-radius: var(--_radius);\n padding: 9px 11px; margin: 0 0 14px; text-align: center;\n}\n.atlas-embed-footer { font-size: 13px; color: #6b7280; text-align: center; margin: 16px 0 0; }\n/* \u00A75.1 legal consent row on sign-up. */\n.atlas-embed-consent { display: flex; align-items: flex-start; gap: 8px; margin: 2px 0 14px; font-size: 13px; color: #6b7280; }\n.atlas-embed-consent-check { margin: 2px 0 0; width: 15px; height: 15px; flex: none; accent-color: var(--_primary); cursor: pointer; }\n.atlas-embed-consent-link { color: var(--_primary); text-decoration: underline; }\n/* \u00A77.5 Remember-me row. */\n.atlas-embed-remember { display: flex; align-items: center; gap: 8px; margin: -2px 0 14px; font-size: 13px; color: var(--_text); cursor: pointer; }\n.atlas-embed-remember-check { width: 15px; height: 15px; flex: none; accent-color: var(--_primary); cursor: pointer; }\n.atlas-embed-note { font-size: 14px; color: #6b7280; text-align: center; margin: 8px 0; }\n\n/* Verification step \u2014 a continuation of the email panel, not a new screen: the\n context line (\"Enter the code we sent to \u2026\") + a way back, then a segmented\n one-box-per-digit code input that spawns in. */\n.atlas-embed-step-context { text-align: center; margin: 0 0 20px; }\n.atlas-embed-step-context .atlas-embed-subtitle { margin: 0 0 6px; }\n.atlas-embed-step-back {\n display: inline-block; padding: 2px 4px; font: inherit; font-size: 13px; font-weight: 550;\n cursor: pointer; color: var(--_primary); background: none; border: 0;\n}\n.atlas-embed-step-back:hover { text-decoration: underline; }\n/* A standalone action under the submit button (Forgot password?, Back to sign in,\n the 2FA toggle) reads as a centred link, not a left-aligned fragment. */\nform > .atlas-embed-step-back { display: block; width: 100%; text-align: center; margin-top: 10px; }\n.atlas-embed-code { display: flex; gap: 8px; justify-content: space-between; }\n.atlas-embed-code-box {\n flex: 1 1 0; min-width: 0; aspect-ratio: 1 / 1.15; padding: 0; text-align: center;\n font-size: 20px; font-weight: 600; font-variant-numeric: tabular-nums; color: var(--_text);\n background: var(--_bg); border: 1px solid var(--_border); border-radius: var(--_radius);\n}\n.atlas-embed-code-box:focus { outline: 2px solid var(--_primary); outline-offset: -1px; }\n/* A real step change eases its content in; error/busy re-renders (same step) do\n not, and a reduced-motion viewer gets no animation at all. */\n@media (prefers-reduced-motion: no-preference) {\n .atlas-embed-card[data-enter] > form,\n .atlas-embed-card[data-enter] > .atlas-embed-step-context {\n animation: atlas-embed-spawn 0.26s cubic-bezier(0.22, 0.61, 0.36, 1) both;\n }\n}\n@keyframes atlas-embed-spawn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Interaction / polish layer \u2014 how controls FEEL. Driven by data-attributes on\n the root (data-button-style / -button-effect / -shadow / -density /\n -input-style) that the widget sets from the resolved interaction config, plus\n the --_motion tempo var. Every rule is additive: with no attributes set the\n widget looks exactly as it did before this layer existed.\n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/* Smooth every interactive control at the configured tempo. */\n.atlas-embed-button, .atlas-embed-social-button, .atlas-embed-carousel-nav,\n.atlas-embed-handle-back, .atlas-embed-step-back, .atlas-embed-password-toggle,\n.atlas-embed-input, .atlas-embed-code-box {\n transition:\n transform var(--_motion) ease, box-shadow var(--_motion) ease,\n background-color var(--_motion) ease, border-color var(--_motion) ease,\n color var(--_motion) ease, filter var(--_motion) ease, outline-color var(--_motion) ease;\n}\n\n/* Primary CTA \u2014 a subtle hover darken by default (was static). */\n.atlas-embed-button:hover:not(:disabled) { filter: brightness(1.06); }\n\n/* Button fill style (primary CTA only \u2014 social buttons keep provider styling). */\n.atlas-embed-root[data-button-style=\"outline\"] .atlas-embed-button {\n background: transparent; color: var(--_primary); border: 1px solid var(--_primary);\n}\n.atlas-embed-root[data-button-style=\"outline\"] .atlas-embed-button:hover:not(:disabled) {\n filter: none; background: color-mix(in srgb, var(--_primary) 10%, transparent);\n}\n.atlas-embed-root[data-button-style=\"soft\"] .atlas-embed-button {\n background: color-mix(in srgb, var(--_primary) 14%, transparent); color: var(--_primary);\n}\n.atlas-embed-root[data-button-style=\"soft\"] .atlas-embed-button:hover:not(:disabled) {\n filter: none; background: color-mix(in srgb, var(--_primary) 22%, transparent);\n}\n.atlas-embed-root[data-button-style=\"ghost\"] .atlas-embed-button {\n background: transparent; color: var(--_primary);\n}\n.atlas-embed-root[data-button-style=\"ghost\"] .atlas-embed-button:hover:not(:disabled) {\n filter: none; background: color-mix(in srgb, var(--_primary) 12%, transparent);\n}\n\n/* Press/hover effect \u2014 applies to every button. */\n.atlas-embed-root[data-button-effect=\"scale\"] .atlas-embed-button:active:not(:disabled),\n.atlas-embed-root[data-button-effect=\"scale\"] .atlas-embed-social-button:active,\n.atlas-embed-root[data-button-effect=\"scale\"] .atlas-embed-carousel-nav:active:not(:disabled) {\n transform: scale(0.97);\n}\n.atlas-embed-root[data-button-effect=\"lift\"] .atlas-embed-button:hover:not(:disabled),\n.atlas-embed-root[data-button-effect=\"lift\"] .atlas-embed-social-button:hover {\n transform: translateY(-1px); box-shadow: 0 4px 14px rgba(0,0,0,0.14); filter: none;\n}\n.atlas-embed-root[data-button-effect=\"lift\"] .atlas-embed-button:active:not(:disabled),\n.atlas-embed-root[data-button-effect=\"lift\"] .atlas-embed-social-button:active { transform: translateY(0); }\n.atlas-embed-root[data-button-effect=\"glow\"] .atlas-embed-button:hover:not(:disabled),\n.atlas-embed-root[data-button-effect=\"glow\"] .atlas-embed-social-button:hover {\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--_primary) 35%, transparent); filter: none;\n}\n/* Ripple \u2014 the widget appends a span on pointer-down; buttons must clip it. */\n.atlas-embed-root[data-button-effect=\"ripple\"] .atlas-embed-button,\n.atlas-embed-root[data-button-effect=\"ripple\"] .atlas-embed-social-button {\n position: relative; overflow: hidden;\n}\n.atlas-embed-ripple {\n position: absolute; border-radius: 50%; transform: scale(0);\n background: currentColor; opacity: 0.28; pointer-events: none;\n animation: atlas-embed-ripple 0.55s ease-out;\n}\n@keyframes atlas-embed-ripple { to { transform: scale(2.6); opacity: 0; } }\n\n/* Card + solid-button elevation. */\n.atlas-embed-root[data-shadow=\"none\"] .atlas-embed-card { box-shadow: none; }\n.atlas-embed-root[data-shadow=\"sm\"] .atlas-embed-card { box-shadow: 0 1px 2px rgba(0,0,0,0.05); }\n.atlas-embed-root[data-shadow=\"lg\"] .atlas-embed-card {\n box-shadow: 0 4px 12px rgba(0,0,0,0.08), 0 16px 48px rgba(0,0,0,0.12);\n}\n\n/* Density \u2014 compact tightens padding and gaps. */\n.atlas-embed-root[data-density=\"compact\"] .atlas-embed-card { padding: 20px 18px; }\n.atlas-embed-root[data-density=\"compact\"] .atlas-embed-social { gap: 6px; margin-bottom: 12px; }\n.atlas-embed-root[data-density=\"compact\"] .atlas-embed-field { margin-bottom: 9px; }\n.atlas-embed-root[data-density=\"compact\"] .atlas-embed-button { padding: 9px 12px; }\n.atlas-embed-root[data-density=\"compact\"] .atlas-embed-social-button { padding: 8px 10px; }\n.atlas-embed-root[data-density=\"compact\"] .atlas-embed-subtitle { margin-bottom: 14px; }\n\n/* Input style \u2014 filled and underline treatments (default is the outlined field). */\n.atlas-embed-root[data-input-style=\"filled\"] .atlas-embed-input,\n.atlas-embed-root[data-input-style=\"filled\"] .atlas-embed-code-box,\n.atlas-embed-root[data-input-style=\"filled\"] .atlas-embed-social-search {\n background: color-mix(in srgb, var(--_border) 24%, transparent); border-color: transparent;\n}\n.atlas-embed-root[data-input-style=\"filled\"] .atlas-embed-input:focus,\n.atlas-embed-root[data-input-style=\"filled\"] .atlas-embed-code-box:focus,\n.atlas-embed-root[data-input-style=\"filled\"] .atlas-embed-social-search:focus {\n background: var(--_bg); border-color: var(--_primary);\n}\n.atlas-embed-root[data-input-style=\"underline\"] .atlas-embed-input,\n.atlas-embed-root[data-input-style=\"underline\"] .atlas-embed-code-box,\n.atlas-embed-root[data-input-style=\"underline\"] .atlas-embed-social-search {\n background: transparent; border: 0; border-bottom: 1.5px solid var(--_border);\n border-radius: 0; padding-left: 2px; padding-right: 2px;\n}\n.atlas-embed-root[data-input-style=\"underline\"] .atlas-embed-input:focus,\n.atlas-embed-root[data-input-style=\"underline\"] .atlas-embed-code-box:focus,\n.atlas-embed-root[data-input-style=\"underline\"] .atlas-embed-social-search:focus {\n outline: none; border-bottom-color: var(--_primary);\n}\n\n/* \u2500\u2500 Loading states \u2014 spinner / skeleton / dots / bar (interaction.loading).\n Shown while appearance resolves, while a redirect ticket is exchanged, and the\n button spinner while a form submits \u2014 so the widget never flashes blank. \u2500\u2500 */\n.atlas-embed-button { display: flex; align-items: center; justify-content: center; gap: 8px; }\n.atlas-embed-loading { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; min-height: 168px; padding: 12px 0; }\n.atlas-embed-sr { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }\n\n/* Spinner (default) + the in-button spinner. */\n.atlas-embed-spinner, .atlas-embed-btn-spinner {\n border-radius: 50%; border-style: solid; flex: none;\n animation: atlas-embed-spin 0.7s linear infinite;\n}\n.atlas-embed-spinner { width: 30px; height: 30px; border-width: 3px;\n border-color: color-mix(in srgb, var(--_primary) 22%, transparent); border-top-color: var(--_primary); }\n.atlas-embed-btn-spinner { width: 17px; height: 17px; border-width: 2px;\n border-color: color-mix(in srgb, currentColor 35%, transparent); border-top-color: currentColor; }\n@keyframes atlas-embed-spin { to { transform: rotate(360deg); } }\n\n/* Dots. */\n.atlas-embed-loading[data-loading=\"dots\"] { flex-direction: row; }\n.atlas-embed-dot { width: 10px; height: 10px; border-radius: 50%; background: var(--_primary);\n animation: atlas-embed-bounce 1.2s ease-in-out infinite; }\n.atlas-embed-dot:nth-child(2) { animation-delay: 0.15s; }\n.atlas-embed-dot:nth-child(3) { animation-delay: 0.30s; }\n@keyframes atlas-embed-bounce { 0%,80%,100% { transform: scale(0.5); opacity: 0.4; } 40% { transform: scale(1); opacity: 1; } }\n\n/* Indeterminate bar. */\n.atlas-embed-loading[data-loading=\"bar\"] { min-height: 132px; }\n.atlas-embed-loadbar { position: relative; width: 64%; height: 4px; border-radius: 999px; overflow: hidden;\n background: color-mix(in srgb, var(--_border) 60%, transparent); }\n.atlas-embed-loadbar::before { content: \"\"; position: absolute; top: 0; bottom: 0; width: 40%; border-radius: 999px;\n background: var(--_primary); animation: atlas-embed-slide 1.1s ease-in-out infinite; }\n@keyframes atlas-embed-slide { 0% { left: -45%; } 100% { left: 105%; } }\n\n/* Skeleton \u2014 placeholders shaped like the form. */\n.atlas-embed-loading[data-loading=\"skeleton\"] { align-items: stretch; min-height: 0; gap: 12px; }\n.atlas-embed-skel { border-radius: var(--_radius); position: relative; overflow: hidden;\n background: color-mix(in srgb, var(--_border) 55%, transparent); }\n.atlas-embed-skel::after { content: \"\"; position: absolute; inset: 0; transform: translateX(-100%);\n background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--_text) 8%, transparent), transparent);\n animation: atlas-embed-shimmer 1.3s infinite; }\n.atlas-embed-skel-title { height: 22px; width: 55%; margin: 2px auto 2px; }\n.atlas-embed-skel-sub { height: 13px; width: 75%; margin: 0 auto 8px; }\n.atlas-embed-skel-input { height: 42px; }\n.atlas-embed-skel-button { height: 44px; margin-top: 6px; }\n@keyframes atlas-embed-shimmer { to { transform: translateX(100%); } }\n\n/* Reduced motion always wins \u2014 no transitions, presses, ripples, or spawn; and\n loaders swap their spin/bounce/slide/shimmer for a minimal opacity pulse. */\n@media (prefers-reduced-motion: reduce) {\n .atlas-embed-root { --_motion: 0s; }\n .atlas-embed-root [class^=\"atlas-embed-\"] { transition: none !important; }\n .atlas-embed-root .atlas-embed-button:active,\n .atlas-embed-root .atlas-embed-social-button:active { transform: none !important; }\n .atlas-embed-ripple { display: none; }\n .atlas-embed-spinner, .atlas-embed-btn-spinner, .atlas-embed-dot,\n .atlas-embed-loadbar::before, .atlas-embed-skel::after {\n animation: atlas-embed-pulse 1.4s ease-in-out infinite !important;\n }\n .atlas-embed-loadbar::before { position: static; width: 100%; }\n}\n@keyframes atlas-embed-pulse { 0%,100% { opacity: 0.4; } 50% { opacity: 1; } }\n";
16
+ /** Inject the sheet once per document. Safe to call on every mount. */
17
+ export declare function injectStyles(doc?: Document): void;