Skip to content

Commit

Permalink
Merge branch 'refs/heads/main' into CORE-2086/suffixed-cookies-draft
Browse files Browse the repository at this point in the history
  • Loading branch information
nikosdouvlis committed Jul 17, 2024
2 parents 6e91c3b + 785fa1a commit 6c1a5c2
Show file tree
Hide file tree
Showing 15 changed files with 173 additions and 29 deletions.
2 changes: 0 additions & 2 deletions .changeset/swift-swans-approve.md

This file was deleted.

13 changes: 13 additions & 0 deletions integration/templates/astro-node/src/pages/utility.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
import { ClerkLoaded, ClerkLoading } from '@clerk/astro/react';
import Layout from "../layouts/Layout.astro";
---

<Layout title="Utility">
<ClerkLoading client:load>
<div>Clerk is loading</div>
</ClerkLoading>
<ClerkLoaded client:load>
<div>Clerk is loaded</div>
</ClerkLoaded>
</Layout>
10 changes: 10 additions & 0 deletions integration/tests/astro/react/components.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,5 +67,15 @@ testAgainstRunningApps({ withPattern: ['astro.node.withCustomRoles'] })(
await expect(u.page.getByText('Go to this page to see your profile')).toBeVisible();
await expect(u.page.getByText('Sign out!')).toBeVisible();
});

test('render content based on Clerk loaded status', async ({ page, context }) => {
const u = createTestUtils({ app, page, context });
await u.page.goToRelative('/utility');
await expect(u.page.getByText('Clerk is loading')).toBeVisible();
await expect(u.page.getByText('Clerk is loaded')).toBeHidden();
await u.page.waitForClerkJsLoaded();
await expect(u.page.getByText('Clerk is loaded')).toBeVisible();
await expect(u.page.getByText('Clerk is loading')).toBeHidden();
});
},
);
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions packages/astro/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# @clerk/astro

## 1.0.0

### Major Changes

- Introduce the official Clerk SDK for Astro. ([#3743](https://github.com/clerk/javascript/pull/3743)) by [@panteliselef](https://github.com/panteliselef)

### Patch Changes

- Allow for client side navigation inside UI components and improves the UX while navigating in components with path routing. ([#3734](https://github.com/clerk/javascript/pull/3734)) by [@panteliselef](https://github.com/panteliselef)

## 0.0.4

### Patch Changes

- Introduce `<ClerkLoaded/>` and `<ClerkLoading/>` React components ([#3724](https://github.com/clerk/javascript/pull/3724)) by [@wobsoriano](https://github.com/wobsoriano)

## 0.0.3

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/astro/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@clerk/astro",
"description": "Clerk SDK for Astro",
"version": "0.0.3",
"version": "1.0.0",
"type": "module",
"license": "MIT",
"author": "Clerk",
Expand Down
36 changes: 32 additions & 4 deletions packages/astro/src/internal/create-clerk-instance.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,34 @@
import { waitForClerkScript } from '../internal/utils/loadClerkJSScript';
import type { ClerkOptions } from '@clerk/types';

import { $clerk, $csrState } from '../stores/internal';
import type { AstroClerkIntegrationParams, AstroClerkUpdateOptions } from '../types';
import { invokeClerkAstroJSFunctions } from './invoke-clerk-astro-js-functions';
import { mountAllClerkAstroJSComponents } from './mount-clerk-astro-js-components';
import { runOnce } from './run-once';
import { waitForClerkScript } from './utils/loadClerkJSScript';

let initOptions: ClerkOptions | undefined;

// TODO-SHARED: copied from `clerk-js`
export const CLERK_BEFORE_UNLOAD_EVENT = 'clerk:beforeunload';

function windowNavigate(to: URL | string): void {
const toURL = new URL(to, window.location.href);
window.dispatchEvent(new CustomEvent(CLERK_BEFORE_UNLOAD_EVENT));
window.location.href = toURL.href;
}

let initOptions: AstroClerkIntegrationParams | undefined;
function createNavigationHandler(
windowNav: typeof window.history.pushState | typeof window.history.replaceState,
): Exclude<ClerkOptions['routerPush'], undefined> | Exclude<ClerkOptions['routerReplace'], undefined> {
return (to, metadata) => {
if (metadata?.__internal_metadata?.navigationType === 'internal') {
windowNav(history.state, '', to);
} else {
windowNavigate(to);
}
};
}

/**
* Prevents firing clerk.load multiple times
Expand All @@ -28,10 +51,15 @@ async function createClerkInstanceInternal(options?: AstroClerkIntegrationParams
$clerk.set(clerkJSInstance);
}

initOptions = options;
initOptions = {
...options,
routerPush: createNavigationHandler(window.history.pushState.bind(window.history)),
routerReplace: createNavigationHandler(window.history.replaceState.bind(window.history)),
};

// TODO: Update Clerk type from @clerk/types to include this method
return (clerkJSInstance as any)
.load(options)
.load(initOptions)
.then(() => {
$csrState.setKey('isLoaded', true);

Expand Down
47 changes: 46 additions & 1 deletion packages/astro/src/react/controlComponents.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import type { CheckAuthorizationWithCustomPermissions, HandleOAuthCallbackParams } from '@clerk/types';
import { computed } from 'nanostores';
import type { PropsWithChildren } from 'react';
import React from 'react';
import React, { useEffect, useState } from 'react';

import { $csrState } from '../stores/internal';
import type { ProtectComponentDefaultProps } from '../types';
import { useAuth } from './hooks';
import type { WithClerkProp } from './utils';
Expand All @@ -24,6 +26,49 @@ export function SignedIn(props: PropsWithChildren) {
return props.children;
}

const $isLoadingClerkStore = computed($csrState, state => state.isLoaded);

/*
* It is not guaranteed that hydration will occur before clerk-js has loaded. If Clerk is loaded by the time a React component hydrates,
* then we **hydration error** will be thrown for any control component that renders conditionally.
*
* This hook ensures that `isLoaded` will always be false on the first render,
* preventing potential hydration errors and race conditions.
*/
const useSafeIsLoaded = () => {
const [isLoaded, setIsLoaded] = useState(false);

useEffect(() => {
const unsub = $isLoadingClerkStore.subscribe(() => {
setIsLoaded(true);
});

return () => unsub();
}, []);

return isLoaded;
};

export const ClerkLoaded = ({ children }: React.PropsWithChildren): JSX.Element | null => {
const isLoaded = useSafeIsLoaded();

if (!isLoaded) {
return null;
}

return <>{children}</>;
};

export const ClerkLoading = ({ children }: React.PropsWithChildren): JSX.Element | null => {
const isLoaded = useSafeIsLoaded();

if (isLoaded) {
return null;
}

return <>{children}</>;
};

export type ProtectProps = React.PropsWithChildren<
ProtectComponentDefaultProps & {
fallback?: React.ReactNode;
Expand Down
11 changes: 10 additions & 1 deletion packages/astro/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,16 @@ type AstroClerkUpdateOptions = Pick<ClerkOptions, 'appearance' | 'localization'>

type AstroClerkIntegrationParams = Without<
ClerkOptions,
'isSatellite' | 'sdkMetadata' | 'telemetry' | 'standardBrowser' | 'selectInitialSession'
| 'isSatellite'
| 'sdkMetadata'
| 'telemetry'
| 'standardBrowser'
| 'selectInitialSession'
| 'routerReplace'
| 'routerDebug'
| 'routerPush'
| 'polling'
| 'touchSession'
> &
MultiDomainAndOrProxyPrimitives;

Expand Down
8 changes: 8 additions & 0 deletions packages/elements/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# @clerk/elements

## 0.10.4

### Patch Changes

- Fix issue where default field values were being set and clearing field errors. ([#3736](https://github.com/clerk/javascript/pull/3736)) by [@alexcarpenter](https://github.com/alexcarpenter)

Fix issue where resendable UI in the email_link verification step was not updating on click.

## 0.10.3

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/elements/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@clerk/elements",
"version": "0.10.3",
"version": "0.10.4",
"description": "Clerk Elements",
"keywords": [
"clerk",
Expand Down
11 changes: 11 additions & 0 deletions packages/elements/src/internals/machines/form/form.machine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ export type FormMachineEvents =
optional: string[];
required: string[];
}
| {
type: 'PREFILL_DEFAULT_VALUES';
defaultValues: FormDefaultValues;
}
| { type: 'UNMARK_AS_PROGRESSIVE' }
| {
type: 'FIELD.UPDATE';
Expand Down Expand Up @@ -232,5 +236,12 @@ export const FormMachine = setup({
required: undefined,
}),
},
PREFILL_DEFAULT_VALUES: {
actions: assign(({ event }) => {
return {
defaultValues: event.defaultValues,
};
}),
},
},
});
31 changes: 17 additions & 14 deletions packages/elements/src/internals/machines/sign-up/start.machine.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { SignUpResource } from '@clerk/types';
import { enqueueActions, fromPromise, not, sendTo, setup } from 'xstate';
import { fromPromise, not, sendTo, setup } from 'xstate';

import { SIGN_UP_DEFAULT_BASE_PATH } from '~/internals/constants';
import type { FormFields } from '~/internals/machines/form';
Expand Down Expand Up @@ -44,6 +44,21 @@ export const SignUpStartMachine = setup({
};
},
),
setDefaultFormValues: ({ context }) => {
const signUp = context.parent.getSnapshot().context.clerk.client.signUp;
const prefilledDefaultValues = new Map();

for (const key of PREFILL_FIELDS) {
if (key in signUp) {
prefilledDefaultValues.set(key, signUp[key]);
}
}

context.formRef.send({
type: 'PREFILL_DEFAULT_VALUES',
defaultValues: prefilledDefaultValues,
});
},
},
guards: {
isExampleMode: ({ context }) => Boolean(context.parent.getSnapshot().context.exampleMode),
Expand All @@ -57,24 +72,12 @@ export const SignUpStartMachine = setup({
parent: input.parent,
loadingStep: 'start',
}),
entry: 'setDefaultFormValues',
initial: 'Pending',
states: {
Pending: {
tags: ['state:pending'],
description: 'Waiting for user input',
entry: [
enqueueActions(({ context, enqueue }) => {
PREFILL_FIELDS.forEach(field => {
enqueue.sendTo(context.formRef, {
type: 'FIELD.ADD',
field: {
name: field,
value: context.parent.getSnapshot().context.clerk?.client?.signUp?.[field] || '',
},
});
});
}),
],
on: {
SUBMIT: {
guard: not('isExampleMode'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ export const SignUpVerificationMachine = setup({
tags: ['verification:method:email', 'verification:category:link', 'verification:email_link'],
initial: 'Preparing',
on: {
RETRY: '.Preparing',
'EMAIL_LINK.RESTART': {
target: '.Attempting',
reenter: true,
Expand Down Expand Up @@ -303,7 +304,6 @@ export const SignUpVerificationMachine = setup({
tags: ['state:pending'],
on: {
NEXT: 'Preparing',
RETRY: 'Preparing',
},
},
Attempting: {
Expand Down
7 changes: 5 additions & 2 deletions packages/elements/src/react/common/form/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ const useInput = ({

// Register the field in the machine context
React.useEffect(() => {
if (!name || ref.getSnapshot().context.fields.get(name)) {
if (!name) {
return;
}

Expand Down Expand Up @@ -309,7 +309,10 @@ const useInput = ({
if (!name) {
return;
}
ref.send({ type: 'FIELD.UPDATE', field: { name, value: providedValue } });

if (providedValue !== undefined) {
ref.send({ type: 'FIELD.UPDATE', field: { name, value: providedValue } });
}
}, [name, ref, providedValue]);

// TODO: Implement clerk-js utils
Expand Down

0 comments on commit 6c1a5c2

Please sign in to comment.