@atproto/oauth-provider 0.3.1 → 0.5.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.
- package/.linguirc +57 -0
- package/CHANGELOG.md +29 -0
- package/LICENSE.txt +1 -1
- package/dist/account/account-manager.d.ts +17 -3
- package/dist/account/account-manager.d.ts.map +1 -1
- package/dist/account/account-manager.js +102 -8
- package/dist/account/account-manager.js.map +1 -1
- package/dist/account/account-store.d.ts +81 -15
- package/dist/account/account-store.d.ts.map +1 -1
- package/dist/account/account-store.js +70 -19
- package/dist/account/account-store.js.map +1 -1
- package/dist/account/sign-in-data.d.ts +28 -0
- package/dist/account/sign-in-data.d.ts.map +1 -0
- package/dist/account/sign-in-data.js +16 -0
- package/dist/account/sign-in-data.js.map +1 -0
- package/dist/account/sign-up-data.d.ts +26 -0
- package/dist/account/sign-up-data.d.ts.map +1 -0
- package/dist/account/sign-up-data.js +11 -0
- package/dist/account/sign-up-data.js.map +1 -0
- package/dist/assets/app/bundle-manifest.json +598 -6
- package/dist/assets/app/index-ItwwtJ8r.js +36 -0
- package/dist/assets/app/index-ItwwtJ8r.js.map +1 -0
- package/dist/assets/app/main-B_dNxQo_.js +4 -0
- package/dist/assets/app/main-B_dNxQo_.js.map +1 -0
- package/dist/assets/app/main-CSatvmRR.css +3 -0
- package/dist/assets/app/main-CSatvmRR.js +306 -0
- package/dist/assets/app/main-CSatvmRR.js.map +1 -0
- package/dist/assets/app/messages-BQeltXSF.js +4 -0
- package/dist/assets/app/messages-BQeltXSF.js.map +1 -0
- package/dist/assets/app/messages-BQkEhfjg.js +4 -0
- package/dist/assets/app/messages-BQkEhfjg.js.map +1 -0
- package/dist/assets/app/messages-BUjKj_UJ.js +4 -0
- package/dist/assets/app/messages-BUjKj_UJ.js.map +1 -0
- package/dist/assets/app/messages-BWIQa8fO.js +4 -0
- package/dist/assets/app/messages-BWIQa8fO.js.map +1 -0
- package/dist/assets/app/messages-BaNVb0bp.js +4 -0
- package/dist/assets/app/messages-BaNVb0bp.js.map +1 -0
- package/dist/assets/app/messages-BaizVXcF.js +4 -0
- package/dist/assets/app/messages-BaizVXcF.js.map +1 -0
- package/dist/assets/app/messages-BfoClA1Y.js +4 -0
- package/dist/assets/app/messages-BfoClA1Y.js.map +1 -0
- package/dist/assets/app/messages-BsKGDZnC.js +4 -0
- package/dist/assets/app/messages-BsKGDZnC.js.map +1 -0
- package/dist/assets/app/messages-Bu-TJhml.js +4 -0
- package/dist/assets/app/messages-Bu-TJhml.js.map +1 -0
- package/dist/assets/app/messages-BvOKnBQk.js +4 -0
- package/dist/assets/app/messages-BvOKnBQk.js.map +1 -0
- package/dist/assets/app/messages-BxDzCiWz.js +4 -0
- package/dist/assets/app/messages-BxDzCiWz.js.map +1 -0
- package/dist/assets/app/messages-CDgFOy4S.js +4 -0
- package/dist/assets/app/messages-CDgFOy4S.js.map +1 -0
- package/dist/assets/app/messages-CLbTz0o9.js +4 -0
- package/dist/assets/app/messages-CLbTz0o9.js.map +1 -0
- package/dist/assets/app/messages-CNwSh0t7.js +4 -0
- package/dist/assets/app/messages-CNwSh0t7.js.map +1 -0
- package/dist/assets/app/messages-CSMNJ6P8.js +4 -0
- package/dist/assets/app/messages-CSMNJ6P8.js.map +1 -0
- package/dist/assets/app/messages-CZQUw3mp.js +4 -0
- package/dist/assets/app/messages-CZQUw3mp.js.map +1 -0
- package/dist/assets/app/messages-CZT41oVp.js +4 -0
- package/dist/assets/app/messages-CZT41oVp.js.map +1 -0
- package/dist/assets/app/messages-C_b-d3t8.js +4 -0
- package/dist/assets/app/messages-C_b-d3t8.js.map +1 -0
- package/dist/assets/app/messages-C_u3MTc2.js +4 -0
- package/dist/assets/app/messages-C_u3MTc2.js.map +1 -0
- package/dist/assets/app/messages-Cn8nHZic.js +4 -0
- package/dist/assets/app/messages-Cn8nHZic.js.map +1 -0
- package/dist/assets/app/messages-CtDywJUm.js +4 -0
- package/dist/assets/app/messages-CtDywJUm.js.map +1 -0
- package/dist/assets/app/messages-CurtIjBF.js +4 -0
- package/dist/assets/app/messages-CurtIjBF.js.map +1 -0
- package/dist/assets/app/messages-Cv6zIbaP.js +4 -0
- package/dist/assets/app/messages-Cv6zIbaP.js.map +1 -0
- package/dist/assets/app/messages-D1eLQuPE.js +4 -0
- package/dist/assets/app/messages-D1eLQuPE.js.map +1 -0
- package/dist/assets/app/messages-D8vHEaYW.js +4 -0
- package/dist/assets/app/messages-D8vHEaYW.js.map +1 -0
- package/dist/assets/app/messages-DJ1Q4GeC.js +4 -0
- package/dist/assets/app/messages-DJ1Q4GeC.js.map +1 -0
- package/dist/assets/app/messages-DRL3exqd.js +4 -0
- package/dist/assets/app/messages-DRL3exqd.js.map +1 -0
- package/dist/assets/app/messages-DWLPQRTp.js +4 -0
- package/dist/assets/app/messages-DWLPQRTp.js.map +1 -0
- package/dist/assets/app/messages-DjVaE9YE.js +4 -0
- package/dist/assets/app/messages-DjVaE9YE.js.map +1 -0
- package/dist/assets/app/messages-DqpMfFJR.js +4 -0
- package/dist/assets/app/messages-DqpMfFJR.js.map +1 -0
- package/dist/assets/app/messages-ETjhJBEN.js +4 -0
- package/dist/assets/app/messages-ETjhJBEN.js.map +1 -0
- package/dist/assets/app/messages-EUKrgrGn.js +4 -0
- package/dist/assets/app/messages-EUKrgrGn.js.map +1 -0
- package/dist/assets/app/messages-QQrOUcPW.js +4 -0
- package/dist/assets/app/messages-QQrOUcPW.js.map +1 -0
- package/dist/assets/app/messages-e2QGqFL6.js +4 -0
- package/dist/assets/app/messages-e2QGqFL6.js.map +1 -0
- package/dist/assets/app/messages-p61py7gD.js +4 -0
- package/dist/assets/app/messages-p61py7gD.js.map +1 -0
- package/dist/assets/asset.d.ts +1 -0
- package/dist/assets/asset.d.ts.map +1 -1
- package/dist/assets/assets-middleware.d.ts.map +1 -1
- package/dist/assets/assets-middleware.js +12 -7
- package/dist/assets/assets-middleware.js.map +1 -1
- package/dist/assets/index.d.ts +3 -2
- package/dist/assets/index.d.ts.map +1 -1
- package/dist/assets/index.js +13 -1
- package/dist/assets/index.js.map +1 -1
- package/dist/client/client-store.d.ts +3 -3
- package/dist/client/client-store.d.ts.map +1 -1
- package/dist/client/client-store.js +6 -5
- package/dist/client/client-store.js.map +1 -1
- package/dist/device/device-manager.d.ts +12 -13
- package/dist/device/device-manager.d.ts.map +1 -1
- package/dist/device/device-manager.js +5 -3
- package/dist/device/device-manager.js.map +1 -1
- package/dist/device/device-store.d.ts +3 -3
- package/dist/device/device-store.d.ts.map +1 -1
- package/dist/device/device-store.js +10 -9
- package/dist/device/device-store.js.map +1 -1
- package/dist/dpop/dpop-manager.d.ts +15 -7
- package/dist/dpop/dpop-manager.d.ts.map +1 -1
- package/dist/dpop/dpop-manager.js +17 -3
- package/dist/dpop/dpop-manager.js.map +1 -1
- package/dist/dpop/dpop-nonce.d.ts +11 -5
- package/dist/dpop/dpop-nonce.d.ts.map +1 -1
- package/dist/dpop/dpop-nonce.js +47 -38
- package/dist/dpop/dpop-nonce.js.map +1 -1
- package/dist/errors/handle-unavailable-error.d.ts +11 -0
- package/dist/errors/handle-unavailable-error.d.ts.map +1 -0
- package/dist/errors/handle-unavailable-error.js +19 -0
- package/dist/errors/handle-unavailable-error.js.map +1 -0
- package/dist/errors/invalid-request-error.d.ts +6 -8
- package/dist/errors/invalid-request-error.d.ts.map +1 -1
- package/dist/errors/invalid-request-error.js +10 -8
- package/dist/errors/invalid-request-error.js.map +1 -1
- package/dist/lib/csp/index.d.ts +18 -0
- package/dist/lib/csp/index.d.ts.map +1 -0
- package/dist/lib/csp/index.js +72 -0
- package/dist/lib/csp/index.js.map +1 -0
- package/dist/lib/hcaptcha.d.ts +177 -0
- package/dist/lib/hcaptcha.d.ts.map +1 -0
- package/dist/lib/hcaptcha.js +155 -0
- package/dist/lib/hcaptcha.js.map +1 -0
- package/dist/lib/html/build-document.d.ts +11 -3
- package/dist/lib/html/build-document.d.ts.map +1 -1
- package/dist/lib/html/build-document.js +51 -15
- package/dist/lib/html/build-document.js.map +1 -1
- package/dist/lib/http/middleware.d.ts.map +1 -1
- package/dist/lib/http/middleware.js +4 -1
- package/dist/lib/http/middleware.js.map +1 -1
- package/dist/lib/http/request.d.ts +18 -3
- package/dist/lib/http/request.d.ts.map +1 -1
- package/dist/lib/http/request.js +56 -23
- package/dist/lib/http/request.js.map +1 -1
- package/dist/lib/http/response.d.ts +4 -2
- package/dist/lib/http/response.d.ts.map +1 -1
- package/dist/lib/http/response.js +23 -5
- package/dist/lib/http/response.js.map +1 -1
- package/dist/lib/locale.d.ts +15 -0
- package/dist/lib/locale.d.ts.map +1 -0
- package/dist/lib/locale.js +17 -0
- package/dist/lib/locale.js.map +1 -0
- package/dist/lib/util/function.d.ts +2 -2
- package/dist/lib/util/function.d.ts.map +1 -1
- package/dist/lib/util/function.js.map +1 -1
- package/dist/lib/util/type.d.ts +88 -1
- package/dist/lib/util/type.d.ts.map +1 -1
- package/dist/lib/util/type.js +41 -0
- package/dist/lib/util/type.js.map +1 -1
- package/dist/metadata/build-metadata.d.ts +2 -2
- package/dist/metadata/build-metadata.d.ts.map +1 -1
- package/dist/metadata/build-metadata.js.map +1 -1
- package/dist/oauth-errors.d.ts +1 -0
- package/dist/oauth-errors.d.ts.map +1 -1
- package/dist/oauth-errors.js +3 -1
- package/dist/oauth-errors.js.map +1 -1
- package/dist/oauth-hooks.d.ts +60 -3
- package/dist/oauth-hooks.d.ts.map +1 -1
- package/dist/oauth-hooks.js +3 -3
- package/dist/oauth-hooks.js.map +1 -1
- package/dist/oauth-provider.d.ts +28 -22
- package/dist/oauth-provider.d.ts.map +1 -1
- package/dist/oauth-provider.js +212 -211
- package/dist/oauth-provider.js.map +1 -1
- package/dist/oauth-verifier.d.ts +1 -1
- package/dist/oauth-verifier.d.ts.map +1 -1
- package/dist/oauth-verifier.js +2 -1
- package/dist/oauth-verifier.js.map +1 -1
- package/dist/output/build-authorize-data.d.ts +0 -1
- package/dist/output/build-authorize-data.d.ts.map +1 -1
- package/dist/output/build-authorize-data.js +0 -1
- package/dist/output/build-authorize-data.js.map +1 -1
- package/dist/output/build-customization-data.d.ts +232 -0
- package/dist/output/build-customization-data.d.ts.map +1 -0
- package/dist/output/build-customization-data.js +145 -0
- package/dist/output/build-customization-data.js.map +1 -0
- package/dist/output/output-manager.d.ts +16 -9
- package/dist/output/output-manager.d.ts.map +1 -1
- package/dist/output/output-manager.js +78 -42
- package/dist/output/output-manager.js.map +1 -1
- package/dist/output/send-authorize-redirect.d.ts +9 -6
- package/dist/output/send-authorize-redirect.d.ts.map +1 -1
- package/dist/output/send-authorize-redirect.js +20 -14
- package/dist/output/send-authorize-redirect.js.map +1 -1
- package/dist/output/send-web-page.d.ts +7 -2
- package/dist/output/send-web-page.d.ts.map +1 -1
- package/dist/output/send-web-page.js +37 -21
- package/dist/output/send-web-page.js.map +1 -1
- package/dist/request/request-manager.d.ts +1 -1
- package/dist/request/request-manager.d.ts.map +1 -1
- package/dist/request/request-manager.js +4 -4
- package/dist/request/request-manager.js.map +1 -1
- package/dist/request/request-store.d.ts +3 -3
- package/dist/request/request-store.d.ts.map +1 -1
- package/dist/request/request-store.js +11 -10
- package/dist/request/request-store.js.map +1 -1
- package/dist/token/token-store.d.ts +4 -4
- package/dist/token/token-store.d.ts.map +1 -1
- package/dist/token/token-store.js +13 -12
- package/dist/token/token-store.js.map +1 -1
- package/package.json +46 -21
- package/rollup.config.js +61 -17
- package/src/account/account-manager.ts +159 -8
- package/src/account/account-store.ts +127 -32
- package/src/account/sign-in-data.ts +15 -0
- package/src/account/sign-up-data.ts +11 -0
- package/src/assets/app/app.tsx +31 -16
- package/src/assets/app/backend-data.ts +15 -60
- package/src/assets/app/backend-types.ts +66 -0
- package/src/assets/app/components/forms/button-toggle-visibility.tsx +43 -0
- package/src/assets/app/components/forms/button.tsx +60 -0
- package/src/assets/app/components/forms/fieldset.tsx +55 -0
- package/src/assets/app/components/forms/form-card-async.tsx +103 -0
- package/src/assets/app/components/forms/form-card.tsx +49 -0
- package/src/assets/app/components/forms/input-checkbox.tsx +73 -0
- package/src/assets/app/components/forms/input-container.tsx +107 -0
- package/src/assets/app/components/forms/input-email-address.tsx +66 -0
- package/src/assets/app/components/forms/input-new-password.tsx +62 -0
- package/src/assets/app/components/forms/input-password.tsx +88 -0
- package/src/assets/app/components/forms/input-text.tsx +76 -0
- package/src/assets/app/components/forms/input-token.tsx +94 -0
- package/src/assets/app/components/forms/wizard-card.tsx +116 -0
- package/src/assets/app/components/layouts/layout-title-page.tsx +77 -0
- package/src/assets/app/components/layouts/layout-welcome.tsx +73 -0
- package/src/assets/app/components/utils/account-identifier.tsx +23 -0
- package/src/assets/app/components/utils/account-image.tsx +33 -0
- package/src/assets/app/components/utils/admonition.tsx +52 -0
- package/src/assets/app/components/utils/client-name.tsx +45 -0
- package/src/assets/app/components/utils/error-card.tsx +93 -0
- package/src/assets/app/components/utils/error-message.tsx +62 -0
- package/src/assets/app/components/utils/help-card.tsx +46 -0
- package/src/assets/app/components/utils/icons.tsx +88 -0
- package/src/assets/app/components/utils/link-anchor.tsx +28 -0
- package/src/assets/app/components/utils/link-title.tsx +26 -0
- package/src/assets/app/components/utils/multi-lang-string.tsx +56 -0
- package/src/assets/app/components/utils/password-strength-label.tsx +37 -0
- package/src/assets/app/components/utils/password-strength-meter.tsx +58 -0
- package/src/assets/app/components/{url-viewer.tsx → utils/url-viewer.tsx} +9 -6
- package/src/assets/app/hooks/use-api.ts +128 -55
- package/src/assets/app/hooks/use-async-action.ts +120 -0
- package/src/assets/app/hooks/use-browser-color-scheme.ts +31 -0
- package/src/assets/app/hooks/use-csrf-token.ts +1 -1
- package/src/assets/app/hooks/use-random-string.ts +37 -0
- package/src/assets/app/hooks/use-stepper.ts +87 -0
- package/src/assets/app/index.html +182 -0
- package/src/assets/app/lib/api.ts +248 -79
- package/src/assets/app/lib/clsx.ts +5 -8
- package/src/assets/app/lib/json-client.ts +94 -0
- package/src/assets/app/lib/password.ts +98 -0
- package/src/assets/app/lib/ref.ts +17 -0
- package/src/assets/app/locales/an/messages.po +492 -0
- package/src/assets/app/locales/ast/messages.po +492 -0
- package/src/assets/app/locales/ca/messages.po +492 -0
- package/src/assets/app/locales/da/messages.po +492 -0
- package/src/assets/app/locales/de/messages.po +492 -0
- package/src/assets/app/locales/el/messages.po +492 -0
- package/src/assets/app/locales/en/messages.po +492 -0
- package/src/assets/app/locales/en-GB/messages.po +492 -0
- package/src/assets/app/locales/es/messages.po +492 -0
- package/src/assets/app/locales/eu/messages.po +492 -0
- package/src/assets/app/locales/fi/messages.po +492 -0
- package/src/assets/app/locales/fr/messages.po +492 -0
- package/src/assets/app/locales/ga/messages.po +492 -0
- package/src/assets/app/locales/gl/messages.po +492 -0
- package/src/assets/app/locales/hi/messages.po +492 -0
- package/src/assets/app/locales/hu/messages.po +492 -0
- package/src/assets/app/locales/ia/messages.po +492 -0
- package/src/assets/app/locales/id/messages.po +492 -0
- package/src/assets/app/locales/it/messages.po +492 -0
- package/src/assets/app/locales/ja/messages.po +492 -0
- package/src/assets/app/locales/km/messages.po +492 -0
- package/src/assets/app/locales/ko/messages.po +492 -0
- package/src/assets/app/locales/load.ts +8 -0
- package/src/assets/app/locales/locale-context.ts +19 -0
- package/src/assets/app/locales/locale-provider.tsx +112 -0
- package/src/assets/app/locales/locale-selector.tsx +58 -0
- package/src/assets/app/locales/locales.ts +168 -0
- package/src/assets/app/locales/ne/messages.po +492 -0
- package/src/assets/app/locales/nl/messages.po +492 -0
- package/src/assets/app/locales/pl/messages.po +492 -0
- package/src/assets/app/locales/pt-BR/messages.po +492 -0
- package/src/assets/app/locales/ro/messages.po +492 -0
- package/src/assets/app/locales/ru/messages.po +492 -0
- package/src/assets/app/locales/sv/messages.po +492 -0
- package/src/assets/app/locales/th/messages.po +492 -0
- package/src/assets/app/locales/tr/messages.po +492 -0
- package/src/assets/app/locales/uk/messages.po +492 -0
- package/src/assets/app/locales/vi/messages.po +492 -0
- package/src/assets/app/locales/zh-CN/messages.po +492 -0
- package/src/assets/app/locales/zh-HK/messages.po +492 -0
- package/src/assets/app/locales/zh-TW/messages.po +492 -0
- package/src/assets/app/main.css +23 -2
- package/src/assets/app/main.tsx +24 -8
- package/src/assets/app/views/authorize/accept/accept-form.tsx +150 -0
- package/src/assets/app/views/authorize/accept/accept-view.tsx +70 -0
- package/src/assets/app/views/authorize/authorize-view.tsx +180 -0
- package/src/assets/app/views/authorize/reset-password/reset-password-confirm-form.tsx +88 -0
- package/src/assets/app/views/authorize/reset-password/reset-password-request-form.tsx +80 -0
- package/src/assets/app/views/authorize/reset-password/reset-password-view.tsx +127 -0
- package/src/assets/app/views/authorize/sign-in/sign-in-form.tsx +244 -0
- package/src/assets/app/views/authorize/sign-in/sign-in-picker.tsx +116 -0
- package/src/assets/app/views/authorize/sign-in/sign-in-view.tsx +145 -0
- package/src/assets/app/views/authorize/sign-up/sign-up-account-form.tsx +140 -0
- package/src/assets/app/views/authorize/sign-up/sign-up-disclaimer.tsx +51 -0
- package/src/assets/app/views/authorize/sign-up/sign-up-handle-form.tsx +289 -0
- package/src/assets/app/views/authorize/sign-up/sign-up-hcaptcha-form.tsx +108 -0
- package/src/assets/app/views/authorize/sign-up/sign-up-view.tsx +158 -0
- package/src/assets/app/views/authorize/welcome/welcome-view.tsx +56 -0
- package/src/assets/app/views/error/error-view.tsx +31 -0
- package/src/assets/asset.ts +1 -0
- package/src/assets/assets-middleware.ts +13 -8
- package/src/assets/index.ts +15 -2
- package/src/client/client-store.ts +10 -12
- package/src/device/device-manager.ts +14 -15
- package/src/device/device-store.ts +9 -15
- package/src/dpop/dpop-manager.ts +20 -8
- package/src/dpop/dpop-nonce.ts +58 -40
- package/src/errors/handle-unavailable-error.ts +18 -0
- package/src/errors/invalid-request-error.ts +10 -8
- package/src/lib/csp/index.ts +98 -0
- package/src/lib/hcaptcha.ts +182 -0
- package/src/lib/html/build-document.ts +60 -16
- package/src/lib/http/middleware.ts +4 -3
- package/src/lib/http/request.ts +81 -28
- package/src/lib/http/response.ts +22 -9
- package/src/lib/locale.ts +21 -0
- package/src/lib/util/function.ts +0 -3
- package/src/lib/util/type.ts +130 -1
- package/src/metadata/build-metadata.ts +2 -1
- package/src/oauth-errors.ts +1 -0
- package/src/oauth-hooks.ts +69 -3
- package/src/oauth-provider.ts +410 -315
- package/src/oauth-verifier.ts +3 -1
- package/src/output/build-authorize-data.ts +1 -3
- package/src/output/build-customization-data.ts +189 -0
- package/src/output/output-manager.ts +111 -48
- package/src/output/send-authorize-redirect.ts +43 -36
- package/src/output/send-web-page.ts +40 -26
- package/src/request/request-manager.ts +4 -4
- package/src/request/request-store.ts +12 -16
- package/src/token/token-store.ts +14 -18
- package/tailwind.config.js +5 -0
- package/tsconfig.backend.tsbuildinfo +1 -1
- package/tsconfig.frontend.tsbuildinfo +1 -1
- package/tsconfig.tools.tsbuildinfo +1 -1
- package/vite.config.mjs +16 -0
- package/.postcssrc.yml +0 -3
- package/dist/assets/app/main.css +0 -3
- package/dist/assets/app/main.js +0 -20
- package/dist/assets/app/main.js.map +0 -1
- package/dist/output/customization.d.ts +0 -27
- package/dist/output/customization.d.ts.map +0 -1
- package/dist/output/customization.js +0 -88
- package/dist/output/customization.js.map +0 -1
- package/src/assets/app/components/accept-form.tsx +0 -137
- package/src/assets/app/components/account-identifier.tsx +0 -18
- package/src/assets/app/components/account-picker.tsx +0 -127
- package/src/assets/app/components/button.tsx +0 -34
- package/src/assets/app/components/client-name.tsx +0 -37
- package/src/assets/app/components/fieldset.tsx +0 -26
- package/src/assets/app/components/form-card.tsx +0 -47
- package/src/assets/app/components/help-card.tsx +0 -42
- package/src/assets/app/components/icons/alert-icon.tsx +0 -5
- package/src/assets/app/components/icons/at-symbol-icon.tsx +0 -5
- package/src/assets/app/components/icons/caret-right-icon.tsx +0 -5
- package/src/assets/app/components/icons/lock-icon.tsx +0 -5
- package/src/assets/app/components/icons/token-icon.tsx +0 -5
- package/src/assets/app/components/icons/util.tsx +0 -17
- package/src/assets/app/components/info-card.tsx +0 -45
- package/src/assets/app/components/input-checkbox.tsx +0 -47
- package/src/assets/app/components/input-container.tsx +0 -37
- package/src/assets/app/components/input-layout.tsx +0 -47
- package/src/assets/app/components/input-text.tsx +0 -69
- package/src/assets/app/components/layout-title-page.tsx +0 -60
- package/src/assets/app/components/layout-welcome.tsx +0 -74
- package/src/assets/app/components/sign-in-form.tsx +0 -337
- package/src/assets/app/components/sign-up-account-form.tsx +0 -194
- package/src/assets/app/components/sign-up-disclaimer.tsx +0 -44
- package/src/assets/app/views/accept-view.tsx +0 -55
- package/src/assets/app/views/authorize-view.tsx +0 -106
- package/src/assets/app/views/error-view.tsx +0 -36
- package/src/assets/app/views/sign-in-view.tsx +0 -111
- package/src/assets/app/views/sign-up-view.tsx +0 -86
- package/src/assets/app/views/welcome-view.tsx +0 -54
- package/src/output/customization.ts +0 -118
@@ -1,25 +1,86 @@
|
|
1
|
+
import { isEmailValid } from '@hapi/address'
|
2
|
+
import { isDisposableEmail } from 'disposable-email-domains-js'
|
1
3
|
import { z } from 'zod'
|
2
4
|
import { ClientId } from '../client/client-id.js'
|
3
5
|
import { DeviceId } from '../device/device-id.js'
|
4
|
-
import {
|
6
|
+
import { localeSchema } from '../lib/locale.js'
|
7
|
+
import { Awaitable, buildInterfaceChecker } from '../lib/util/type.js'
|
8
|
+
import {
|
9
|
+
HandleUnavailableError,
|
10
|
+
InvalidRequestError,
|
11
|
+
SecondAuthenticationFactorRequiredError,
|
12
|
+
} from '../oauth-errors.js'
|
5
13
|
import { Sub } from '../oidc/sub.js'
|
6
14
|
import { Account } from './account.js'
|
7
15
|
|
8
|
-
|
9
|
-
|
10
|
-
|
16
|
+
// @NOTE Change the length here to force stronger passwords (through a reset)
|
17
|
+
export const oldPasswordSchema = z.string().min(1)
|
18
|
+
export const newPasswordSchema = z.string().min(8)
|
19
|
+
export const tokenSchema = z.string().regex(/^[A-Z2-7]{5}-[A-Z2-7]{5}$/)
|
20
|
+
export const handleSchema = z
|
21
|
+
.string()
|
22
|
+
.min(3)
|
23
|
+
.max(30)
|
24
|
+
.regex(/^[a-z0-9][a-z0-9-]+[a-z0-9](?:\.[a-z0-9][a-z0-9-]+[a-z0-9])+$/)
|
25
|
+
export const emailSchema = z
|
26
|
+
.string()
|
27
|
+
.email()
|
28
|
+
// @NOTE using @hapi/address here, in addition to the email() check to ensure
|
29
|
+
// compatibility with the current email validation in the PDS's account
|
30
|
+
// manager
|
31
|
+
.refine(isEmailValid, {
|
32
|
+
message: 'Invalid email address',
|
33
|
+
})
|
34
|
+
.refine((email) => !isDisposableEmail(email), {
|
35
|
+
message: 'Disposable email addresses are not allowed',
|
36
|
+
})
|
11
37
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
38
|
+
export const authenticateAccountDataSchema = z
|
39
|
+
.object({
|
40
|
+
locale: localeSchema,
|
41
|
+
username: z.string(),
|
42
|
+
password: oldPasswordSchema,
|
43
|
+
emailOtp: z.string().optional(),
|
44
|
+
})
|
45
|
+
.strict()
|
46
|
+
|
47
|
+
export type AuthenticateAccountData = z.TypeOf<
|
48
|
+
typeof authenticateAccountDataSchema
|
49
|
+
>
|
50
|
+
|
51
|
+
export const createAccountDataSchema = z
|
52
|
+
.object({
|
53
|
+
locale: localeSchema,
|
54
|
+
handle: handleSchema,
|
55
|
+
email: emailSchema,
|
56
|
+
password: z.intersection(oldPasswordSchema, newPasswordSchema),
|
57
|
+
inviteCode: tokenSchema.optional(),
|
58
|
+
})
|
59
|
+
.strict()
|
60
|
+
|
61
|
+
export type CreateAccountData = z.TypeOf<typeof createAccountDataSchema>
|
62
|
+
|
63
|
+
export const resetPasswordRequestDataSchema = z
|
64
|
+
.object({
|
65
|
+
locale: localeSchema,
|
66
|
+
email: emailSchema,
|
67
|
+
})
|
68
|
+
.strict()
|
69
|
+
|
70
|
+
export type ResetPasswordRequestData = z.TypeOf<
|
71
|
+
typeof resetPasswordRequestDataSchema
|
72
|
+
>
|
18
73
|
|
19
|
-
|
20
|
-
|
74
|
+
export const resetPasswordConfirmDataSchema = z
|
75
|
+
.object({
|
76
|
+
token: tokenSchema,
|
77
|
+
password: z.intersection(oldPasswordSchema, newPasswordSchema),
|
78
|
+
})
|
79
|
+
.strict()
|
21
80
|
|
22
|
-
export type
|
81
|
+
export type ResetPasswordConfirmData = z.TypeOf<
|
82
|
+
typeof resetPasswordConfirmDataSchema
|
83
|
+
>
|
23
84
|
|
24
85
|
export type DeviceAccountInfo = {
|
25
86
|
remembered: boolean
|
@@ -28,7 +89,14 @@ export type DeviceAccountInfo = {
|
|
28
89
|
}
|
29
90
|
|
30
91
|
// Export all types needed to implement the AccountStore interface
|
31
|
-
export
|
92
|
+
export {
|
93
|
+
type Account,
|
94
|
+
type DeviceId,
|
95
|
+
HandleUnavailableError,
|
96
|
+
InvalidRequestError,
|
97
|
+
SecondAuthenticationFactorRequiredError,
|
98
|
+
type Sub,
|
99
|
+
}
|
32
100
|
|
33
101
|
export type AccountInfo = {
|
34
102
|
account: Account
|
@@ -36,10 +104,17 @@ export type AccountInfo = {
|
|
36
104
|
}
|
37
105
|
|
38
106
|
export interface AccountStore {
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
107
|
+
/**
|
108
|
+
* @throws {HandleUnavailableError} - To indicate that the handle is already taken
|
109
|
+
* @throws {InvalidRequestError} - To indicate that some data is invalid
|
110
|
+
*/
|
111
|
+
createAccount(data: CreateAccountData): Awaitable<Account>
|
112
|
+
|
113
|
+
/**
|
114
|
+
* @throws {InvalidRequestError} - When the credentials are not valid
|
115
|
+
* @throws {SecondAuthenticationFactorRequiredError} - To indicate that an {@link SecondAuthenticationFactorRequiredError.type} is required in the credentials
|
116
|
+
*/
|
117
|
+
authenticateAccount(data: AuthenticateAccountData): Awaitable<Account>
|
43
118
|
|
44
119
|
addAuthorizedClient(
|
45
120
|
deviceId: DeviceId,
|
@@ -47,6 +122,19 @@ export interface AccountStore {
|
|
47
122
|
clientId: ClientId,
|
48
123
|
): Awaitable<void>
|
49
124
|
|
125
|
+
/**
|
126
|
+
* @param remember If false, the account must not be returned from
|
127
|
+
* {@link AccountStore.listDeviceAccounts}.
|
128
|
+
*/
|
129
|
+
addDeviceAccount(
|
130
|
+
deviceId: DeviceId,
|
131
|
+
sub: Sub,
|
132
|
+
remember: boolean,
|
133
|
+
): Awaitable<DeviceAccountInfo>
|
134
|
+
|
135
|
+
/**
|
136
|
+
* @returns The account info, whether the account, even if remember was false.
|
137
|
+
*/
|
50
138
|
getDeviceAccount(deviceId: DeviceId, sub: Sub): Awaitable<AccountInfo | null>
|
51
139
|
removeDeviceAccount(deviceId: DeviceId, sub: Sub): Awaitable<void>
|
52
140
|
|
@@ -55,23 +143,30 @@ export interface AccountStore {
|
|
55
143
|
* be returned. The others will be ignored.
|
56
144
|
*/
|
57
145
|
listDeviceAccounts(deviceId: DeviceId): Awaitable<AccountInfo[]>
|
58
|
-
}
|
59
146
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
typeof implementation.listDeviceAccounts === 'function' &&
|
68
|
-
typeof implementation.removeDeviceAccount === 'function'
|
69
|
-
)
|
147
|
+
resetPasswordRequest(data: ResetPasswordRequestData): Awaitable<void>
|
148
|
+
resetPasswordConfirm(data: ResetPasswordConfirmData): Awaitable<void>
|
149
|
+
|
150
|
+
/**
|
151
|
+
* @throws {HandleUnavailableError} - To indicate that the handle is already taken
|
152
|
+
*/
|
153
|
+
verifyHandleAvailability(handle: string): Awaitable<void>
|
70
154
|
}
|
71
155
|
|
72
|
-
export
|
73
|
-
|
74
|
-
|
156
|
+
export const isAccountStore = buildInterfaceChecker<AccountStore>([
|
157
|
+
'createAccount',
|
158
|
+
'authenticateAccount',
|
159
|
+
'addAuthorizedClient',
|
160
|
+
'addDeviceAccount',
|
161
|
+
'getDeviceAccount',
|
162
|
+
'removeDeviceAccount',
|
163
|
+
'listDeviceAccounts',
|
164
|
+
'resetPasswordRequest',
|
165
|
+
'resetPasswordConfirm',
|
166
|
+
'verifyHandleAvailability',
|
167
|
+
])
|
168
|
+
|
169
|
+
export function asAccountStore<V>(implementation: V): V & AccountStore {
|
75
170
|
if (!implementation || !isAccountStore(implementation)) {
|
76
171
|
throw new Error('Invalid AccountStore implementation')
|
77
172
|
}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
import { z } from 'zod'
|
2
|
+
import { authenticateAccountDataSchema } from './account-store.js'
|
3
|
+
|
4
|
+
export const signInDataSchema = authenticateAccountDataSchema
|
5
|
+
.extend({
|
6
|
+
/**
|
7
|
+
* If false, the account must not be returned from
|
8
|
+
* {@link AccountStore.listDeviceAccounts}. Note that this only makes sense when
|
9
|
+
* used with a device ID.
|
10
|
+
*/
|
11
|
+
remember: z.boolean().optional().default(false),
|
12
|
+
})
|
13
|
+
.strict()
|
14
|
+
|
15
|
+
export type SignInData = z.TypeOf<typeof signInDataSchema>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
import { z } from 'zod'
|
2
|
+
import { hcaptchaTokenSchema } from '../lib/hcaptcha.js'
|
3
|
+
import { createAccountDataSchema } from './account-store.js'
|
4
|
+
|
5
|
+
export const signUpDataSchema = createAccountDataSchema
|
6
|
+
.extend({
|
7
|
+
hcaptchaToken: hcaptchaTokenSchema.optional(),
|
8
|
+
})
|
9
|
+
.strict()
|
10
|
+
|
11
|
+
export type SignUpData = z.TypeOf<typeof signUpDataSchema>
|
package/src/assets/app/app.tsx
CHANGED
@@ -1,28 +1,43 @@
|
|
1
|
+
import { ErrorBoundary } from 'react-error-boundary'
|
1
2
|
import type {
|
2
3
|
AuthorizeData,
|
4
|
+
AvailableLocales,
|
3
5
|
CustomizationData,
|
4
6
|
ErrorData,
|
5
|
-
} from './backend-
|
6
|
-
import {
|
7
|
-
import {
|
7
|
+
} from './backend-types.ts'
|
8
|
+
import { LocaleProvider } from './locales/locale-provider.tsx'
|
9
|
+
import { AuthorizeView } from './views/authorize/authorize-view.tsx'
|
10
|
+
import { ErrorView } from './views/error/error-view.tsx'
|
8
11
|
|
9
12
|
export type AppProps = {
|
13
|
+
availableLocales?: AvailableLocales
|
10
14
|
authorizeData?: AuthorizeData
|
11
15
|
customizationData?: CustomizationData
|
12
16
|
errorData?: ErrorData
|
13
17
|
}
|
14
18
|
|
15
|
-
export function App({
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
19
|
+
export function App({
|
20
|
+
availableLocales,
|
21
|
+
authorizeData,
|
22
|
+
customizationData,
|
23
|
+
errorData,
|
24
|
+
}: AppProps) {
|
25
|
+
return (
|
26
|
+
<LocaleProvider availableLocales={availableLocales}>
|
27
|
+
<ErrorBoundary
|
28
|
+
fallbackRender={({ error }) => (
|
29
|
+
<ErrorView error={error} customizationData={customizationData} />
|
30
|
+
)}
|
31
|
+
>
|
32
|
+
{errorData || !authorizeData ? (
|
33
|
+
<ErrorView error={errorData} customizationData={customizationData} />
|
34
|
+
) : (
|
35
|
+
<AuthorizeView
|
36
|
+
customizationData={customizationData}
|
37
|
+
authorizeData={authorizeData}
|
38
|
+
/>
|
39
|
+
)}
|
40
|
+
</ErrorBoundary>
|
41
|
+
</LocaleProvider>
|
42
|
+
)
|
28
43
|
}
|
@@ -1,72 +1,27 @@
|
|
1
|
-
import {
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
email?: string
|
10
|
-
name?: string
|
11
|
-
preferred_username?: string
|
12
|
-
picture?: string
|
13
|
-
}
|
14
|
-
|
15
|
-
export type Session = {
|
16
|
-
account: Account
|
17
|
-
info?: never // Prevent relying on this in the frontend
|
18
|
-
|
19
|
-
selected: boolean
|
20
|
-
loginRequired: boolean
|
21
|
-
consentRequired: boolean
|
22
|
-
}
|
23
|
-
|
24
|
-
export type LinkDefinition = {
|
25
|
-
title: string
|
26
|
-
href: string
|
27
|
-
rel?: string
|
28
|
-
}
|
29
|
-
|
30
|
-
export type CustomizationData = {
|
31
|
-
name?: string
|
32
|
-
logo?: string
|
33
|
-
links?: LinkDefinition[]
|
34
|
-
}
|
35
|
-
|
36
|
-
export type ErrorData = {
|
37
|
-
error: string
|
38
|
-
error_description: string
|
39
|
-
}
|
40
|
-
|
41
|
-
export type ScopeDetail = {
|
42
|
-
scope: string
|
43
|
-
description?: string
|
44
|
-
}
|
45
|
-
|
46
|
-
export type AuthorizeData = {
|
47
|
-
clientId: string
|
48
|
-
clientMetadata: OAuthClientMetadata
|
49
|
-
clientTrusted: boolean
|
50
|
-
requestUri: string
|
51
|
-
csrfCookie: string
|
52
|
-
loginHint?: string
|
53
|
-
scopeDetails?: ScopeDetail[]
|
54
|
-
newSessionsRequireConsent: boolean
|
55
|
-
sessions: Session[]
|
56
|
-
}
|
57
|
-
|
58
|
-
// see "declareBackendData()" in the backend
|
59
|
-
const readBackendData = <T>(key: string): T | undefined => {
|
1
|
+
import {
|
2
|
+
AuthorizeData,
|
3
|
+
AvailableLocales,
|
4
|
+
CustomizationData,
|
5
|
+
ErrorData,
|
6
|
+
} from './backend-types.ts'
|
7
|
+
|
8
|
+
function readBackendData<T>(key: string): T | undefined {
|
60
9
|
const value = window[key] as T | undefined
|
61
10
|
delete window[key] // Prevent accidental usage / potential leaks to dependencies
|
62
11
|
return value
|
63
12
|
}
|
64
13
|
|
65
14
|
// These values are injected by the backend when it builds the
|
66
|
-
// page HTML.
|
15
|
+
// page HTML. See "declareBackendData()" in the backend.
|
67
16
|
|
17
|
+
/** @deprecated Do not import directly. Only import this from main.tsx */
|
18
|
+
export const availableLocales =
|
19
|
+
readBackendData<AvailableLocales>('__availableLocales')
|
20
|
+
/** @deprecated Do not import directly. Only import this from main.tsx */
|
68
21
|
export const customizationData = readBackendData<CustomizationData>(
|
69
22
|
'__customizationData',
|
70
23
|
)
|
24
|
+
/** @deprecated Do not import directly. Only import this from main.tsx */
|
71
25
|
export const errorData = readBackendData<ErrorData>('__errorData')
|
26
|
+
/** @deprecated Do not import directly. Only import this from main.tsx */
|
72
27
|
export const authorizeData = readBackendData<AuthorizeData>('__authorizeData')
|
@@ -0,0 +1,66 @@
|
|
1
|
+
import type { OAuthClientMetadata } from '@atproto/oauth-types'
|
2
|
+
|
3
|
+
// @TODO: Find a way to share these types with the backend code
|
4
|
+
|
5
|
+
export type Account = {
|
6
|
+
sub: string
|
7
|
+
aud: string | [string, ...string[]]
|
8
|
+
|
9
|
+
email?: string
|
10
|
+
email_verified?: boolean
|
11
|
+
name?: string
|
12
|
+
preferred_username?: string
|
13
|
+
picture?: string
|
14
|
+
}
|
15
|
+
|
16
|
+
export type Session = {
|
17
|
+
account: Account
|
18
|
+
info?: never // Prevent relying on this in the frontend
|
19
|
+
|
20
|
+
selected: boolean
|
21
|
+
loginRequired: boolean
|
22
|
+
consentRequired: boolean
|
23
|
+
}
|
24
|
+
|
25
|
+
export type LocalizedString = string | ({ en: string } & Record<string, string>)
|
26
|
+
|
27
|
+
export type AvailableLocales = readonly string[]
|
28
|
+
|
29
|
+
export type LinkDefinition = {
|
30
|
+
title: LocalizedString
|
31
|
+
href: string
|
32
|
+
rel?: string
|
33
|
+
}
|
34
|
+
|
35
|
+
export type CustomizationData = {
|
36
|
+
// Functional customization
|
37
|
+
hcaptchaSiteKey?: string
|
38
|
+
inviteCodeRequired?: boolean
|
39
|
+
availableUserDomains?: string[]
|
40
|
+
|
41
|
+
// Aesthetic customization
|
42
|
+
name?: string
|
43
|
+
logo?: string
|
44
|
+
links?: LinkDefinition[]
|
45
|
+
}
|
46
|
+
|
47
|
+
export type ErrorData = {
|
48
|
+
error: string
|
49
|
+
error_description: string
|
50
|
+
}
|
51
|
+
|
52
|
+
export type ScopeDetail = {
|
53
|
+
scope: string
|
54
|
+
description?: string
|
55
|
+
}
|
56
|
+
|
57
|
+
export type AuthorizeData = {
|
58
|
+
clientId: string
|
59
|
+
clientMetadata: OAuthClientMetadata
|
60
|
+
clientTrusted: boolean
|
61
|
+
requestUri: string
|
62
|
+
loginHint?: string
|
63
|
+
scopeDetails?: ScopeDetail[]
|
64
|
+
newSessionsRequireConsent: boolean
|
65
|
+
sessions: Session[]
|
66
|
+
}
|
@@ -0,0 +1,43 @@
|
|
1
|
+
import { useLingui } from '@lingui/react/macro'
|
2
|
+
import { Override } from '../../lib/util.ts'
|
3
|
+
import { EyeIcon, EyeSlashIcon } from '../utils/icons.tsx'
|
4
|
+
import { Button, ButtonProps } from './button.tsx'
|
5
|
+
|
6
|
+
export type ButtonToggleVisibilityProps = Override<
|
7
|
+
Omit<ButtonProps, 'aria-label' | 'square'>,
|
8
|
+
{
|
9
|
+
visible: boolean
|
10
|
+
toggleVisible: () => void
|
11
|
+
}
|
12
|
+
>
|
13
|
+
|
14
|
+
/**
|
15
|
+
* Generic button to toggle visibility of an item (e.g. password).
|
16
|
+
*/
|
17
|
+
export function ButtonToggleVisibility({
|
18
|
+
visible,
|
19
|
+
toggleVisible,
|
20
|
+
|
21
|
+
// button
|
22
|
+
onClick,
|
23
|
+
...props
|
24
|
+
}: ButtonToggleVisibilityProps) {
|
25
|
+
const { t } = useLingui()
|
26
|
+
return (
|
27
|
+
<Button
|
28
|
+
{...props}
|
29
|
+
square
|
30
|
+
onClick={(event) => {
|
31
|
+
onClick?.(event)
|
32
|
+
if (!event.defaultPrevented) toggleVisible()
|
33
|
+
}}
|
34
|
+
aria-label={visible ? t`Hide` : t`Make visible`}
|
35
|
+
>
|
36
|
+
{visible ? (
|
37
|
+
<EyeIcon className="w-5" aria-hidden />
|
38
|
+
) : (
|
39
|
+
<EyeSlashIcon className="w-5" aria-hidden />
|
40
|
+
)}
|
41
|
+
</Button>
|
42
|
+
)
|
43
|
+
}
|
@@ -0,0 +1,60 @@
|
|
1
|
+
import { JSX } from 'react'
|
2
|
+
import { clsx } from '../../lib/clsx.ts'
|
3
|
+
import { Override } from '../../lib/util.ts'
|
4
|
+
|
5
|
+
export type ButtonProps = Override<
|
6
|
+
JSX.IntrinsicElements['button'],
|
7
|
+
{
|
8
|
+
color?: 'brand' | 'grey'
|
9
|
+
loading?: boolean
|
10
|
+
transparent?: boolean
|
11
|
+
square?: boolean
|
12
|
+
}
|
13
|
+
>
|
14
|
+
|
15
|
+
export function Button({
|
16
|
+
color = 'grey',
|
17
|
+
transparent = false,
|
18
|
+
loading = undefined,
|
19
|
+
square = false,
|
20
|
+
|
21
|
+
// button
|
22
|
+
children,
|
23
|
+
className,
|
24
|
+
type = 'button',
|
25
|
+
role = 'Button',
|
26
|
+
disabled = false,
|
27
|
+
...props
|
28
|
+
}: ButtonProps) {
|
29
|
+
return (
|
30
|
+
<button
|
31
|
+
role={role}
|
32
|
+
type={type}
|
33
|
+
disabled={disabled || loading === true}
|
34
|
+
{...props}
|
35
|
+
className={clsx(
|
36
|
+
'rounded-lg truncate cursor-pointer touch-manipulation tracking-wide overflow-hidden',
|
37
|
+
square ? 'p-2' : 'py-2 px-6',
|
38
|
+
color === 'brand'
|
39
|
+
? clsx(
|
40
|
+
'accent-slate-100',
|
41
|
+
transparent
|
42
|
+
? 'bg-transparent text-brand'
|
43
|
+
: 'bg-brand text-brand-c',
|
44
|
+
)
|
45
|
+
: color === 'grey'
|
46
|
+
? clsx(
|
47
|
+
'accent-brand',
|
48
|
+
'text-slate-600 dark:text-slate-300',
|
49
|
+
'hover:bg-gray-200 dark:hover:bg-gray-700',
|
50
|
+
transparent ? 'bg-transparent' : 'bg-gray-100 dark:bg-gray-800',
|
51
|
+
)
|
52
|
+
: undefined,
|
53
|
+
'disabled:opacity-50',
|
54
|
+
className,
|
55
|
+
)}
|
56
|
+
>
|
57
|
+
{children}
|
58
|
+
</button>
|
59
|
+
)
|
60
|
+
}
|
@@ -0,0 +1,55 @@
|
|
1
|
+
import { JSX, ReactNode, createContext, useMemo } from 'react'
|
2
|
+
import { useRandomString } from '../../hooks/use-random-string.ts'
|
3
|
+
import { Override } from '../../lib/util.ts'
|
4
|
+
|
5
|
+
export type FieldsetContextValue = {
|
6
|
+
disabled: boolean
|
7
|
+
labelId?: string
|
8
|
+
}
|
9
|
+
|
10
|
+
export const FieldsetContext = createContext<FieldsetContextValue>({
|
11
|
+
disabled: false,
|
12
|
+
})
|
13
|
+
FieldsetContext.displayName = 'FieldsetContext'
|
14
|
+
|
15
|
+
export type FieldsetCardProps = Override<
|
16
|
+
Omit<JSX.IntrinsicElements['fieldset'], 'aria-labelledby'>,
|
17
|
+
{
|
18
|
+
label?: ReactNode
|
19
|
+
}
|
20
|
+
>
|
21
|
+
|
22
|
+
export function Fieldset({
|
23
|
+
label,
|
24
|
+
children,
|
25
|
+
disabled,
|
26
|
+
...props
|
27
|
+
}: FieldsetCardProps) {
|
28
|
+
const labelId = useRandomString({ prefix: 'fieldset-' })
|
29
|
+
|
30
|
+
const contextValue = useMemo(
|
31
|
+
() => ({
|
32
|
+
disabled: disabled ?? false,
|
33
|
+
labelId: label ? labelId : undefined,
|
34
|
+
}),
|
35
|
+
[disabled, label, labelId],
|
36
|
+
)
|
37
|
+
|
38
|
+
return (
|
39
|
+
<fieldset {...props} aria-labelledby={labelId} disabled={disabled}>
|
40
|
+
{label && (
|
41
|
+
<legend
|
42
|
+
id={labelId}
|
43
|
+
key="title"
|
44
|
+
className="mb-1 text-slate-600 dark:text-slate-400 text-sm font-medium"
|
45
|
+
>
|
46
|
+
{label}
|
47
|
+
</legend>
|
48
|
+
)}
|
49
|
+
|
50
|
+
<div className="flex flex-col space-y-4">
|
51
|
+
<FieldsetContext value={contextValue}>{children}</FieldsetContext>
|
52
|
+
</div>
|
53
|
+
</fieldset>
|
54
|
+
)
|
55
|
+
}
|