diff --git a/.changeset/rude-lions-know.md b/.changeset/rude-lions-know.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/rude-lions-know.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/packages/clerk-js/sandbox/app.js b/packages/clerk-js/sandbox/app.js index e991783d0d..8ed84bfbb9 100644 --- a/packages/clerk-js/sandbox/app.js +++ b/packages/clerk-js/sandbox/app.js @@ -2,9 +2,99 @@ /** @typedef {import('@clerk/clerk-js').Clerk} Clerk */ +/** + * @typedef {object} ComponentPropsControl + * @property {(props: unknown) => void} setProps + * @property {() => (any | null)} getProps + */ + +const AVAILABLE_COMPONENTS = /** @type {const} */ ([ + 'signIn', + 'signUp', + 'userButton', + 'userProfile', + 'createOrganization', + 'organizationList', + 'organizationProfile', + 'organizationSwitcher', + 'waitlist', +]); + +const COMPONENT_PROPS_NAMESPACE = 'clerk-js-sandbox'; + +const urlParams = new URL(window.location.href).searchParams; +for (const [component, encodedProps] of urlParams.entries()) { + if (AVAILABLE_COMPONENTS.includes(/** @type {typeof AVAILABLE_COMPONENTS[number]} */ (component))) { + localStorage.setItem(`${COMPONENT_PROPS_NAMESPACE}-${component}`, encodedProps); + } +} + +/** + * @param {typeof AVAILABLE_COMPONENTS[number]} component + * @param {unknown} props + */ +function setComponentProps(component, props) { + const encodedProps = JSON.stringify(props); + + const url = new URL(window.location.href); + url.searchParams.set(component, encodedProps); + + window.location.href = url.toString(); +} + +/** + * @param {typeof AVAILABLE_COMPONENTS[number]} component + * @returns {unknown | null} + */ +function getComponentProps(component) { + const url = new URL(window.location.href); + const encodedProps = url.searchParams.get(component); + if (encodedProps) { + return JSON.parse(encodedProps); + } + + const localEncodedProps = localStorage.getItem(`${COMPONENT_PROPS_NAMESPACE}-${component}`); + if (localEncodedProps) { + return JSON.parse(localEncodedProps); + } + + return null; +} + +/** + * @param {typeof AVAILABLE_COMPONENTS[number]} component + * @returns {ComponentPropsControl} + */ +function buildComponentControls(component) { + return { + setProps(props) { + setComponentProps(component, props); + }, + getProps() { + return getComponentProps(component); + }, + }; +} + +/** + * @type {Record} + */ +const componentControls = { + signIn: buildComponentControls('signIn'), + signUp: buildComponentControls('signUp'), + userButton: buildComponentControls('userButton'), + userProfile: buildComponentControls('userProfile'), + createOrganization: buildComponentControls('createOrganization'), + organizationList: buildComponentControls('organizationList'), + organizationProfile: buildComponentControls('organizationProfile'), + organizationSwitcher: buildComponentControls('organizationSwitcher'), + waitlist: buildComponentControls('waitlist'), +}; + /** * @typedef {object} CustomWindowObject * @property {Clerk} [Clerk] + * @property {Record} [components] */ /** @@ -13,6 +103,7 @@ /** @type {CustomWindow} */ const windowWithClerk = window; +windowWithClerk.components = componentControls; const Clerk = /** @type {Clerk} **/ (windowWithClerk.Clerk); if (!Clerk) { @@ -36,31 +127,31 @@ const routes = { mountIndex(app); }, '/sign-in': () => { - Clerk.mountSignIn(app, {}); + Clerk.mountSignIn(app, componentControls.signIn.getProps() ?? {}); }, '/sign-up': () => { - Clerk.mountSignUp(app, {}); + Clerk.mountSignUp(app, componentControls.signUp.getProps() ?? {}); }, '/user-button': () => { - Clerk.mountUserButton(app, {}); + Clerk.mountUserButton(app, componentControls.userButton.getProps() ?? {}); }, '/user-profile': () => { - Clerk.mountUserProfile(app, {}); + Clerk.mountUserProfile(app, componentControls.userProfile.getProps() ?? {}); }, '/create-organization': () => { - Clerk.mountCreateOrganization(app, {}); + Clerk.mountCreateOrganization(app, componentControls.createOrganization.getProps() ?? {}); }, '/organization-list': () => { - Clerk.mountOrganizationList(app, {}); + Clerk.mountOrganizationList(app, componentControls.organizationList.getProps() ?? {}); }, '/organization-profile': () => { - Clerk.mountOrganizationProfile(app, {}); + Clerk.mountOrganizationProfile(app, componentControls.organizationProfile.getProps() ?? {}); }, '/organization-switcher': () => { - Clerk.mountOrganizationSwitcher(app, {}); + Clerk.mountOrganizationSwitcher(app, componentControls.organizationSwitcher.getProps() ?? {}); }, '/waitlist': () => { - Clerk.mountWaitlist(app, {}); + Clerk.mountWaitlist(app, componentControls.waitlist.getProps() ?? {}); }, };