-
Notifications
You must be signed in to change notification settings - Fork 245
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(astro): Add support for custom menu items (#3969)
Co-authored-by: Lennart <[email protected]>
- Loading branch information
1 parent
7bcab70
commit 77a02d3
Showing
16 changed files
with
349 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@clerk/astro": minor | ||
--- | ||
|
||
Add support for custom menu items in the `<UserButton />` Astro component. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
26 changes: 26 additions & 0 deletions
26
integration/templates/astro-node/src/components/CustomUserButton.astro
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
--- | ||
import { UserButton } from '@clerk/astro/components'; | ||
--- | ||
|
||
<UserButton afterSignOutUrl="/"> | ||
<UserButton.MenuItems> | ||
<UserButton.Action label="signOut" /> | ||
<UserButton.Action label="manageAccount" /> | ||
<UserButton.Link label="Custom link" href="/user"> | ||
<div slot="label-icon">Icon</div> | ||
</UserButton.Link> | ||
<UserButton.Action label="Custom action" open="terms"> | ||
<div slot="label-icon">Icon</div> | ||
</UserButton.Action> | ||
<UserButton.Action label="Custom click" clickIdentifier="custom_click"> | ||
<div slot="label-icon">Icon</div> | ||
</UserButton.Action> | ||
</UserButton.MenuItems> | ||
<UserButton.UserProfilePage label="Terms" url="terms"> | ||
<div slot="label-icon">Icon</div> | ||
<div> | ||
<h1>Custom Terms Page</h1> | ||
<p>This is the custom terms page</p> | ||
</div> | ||
</UserButton.UserProfilePage> | ||
</UserButton> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
5 changes: 3 additions & 2 deletions
5
packages/astro/src/astro-components/interactive/InternalUIComponentRenderer.astro
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
8 changes: 0 additions & 8 deletions
8
packages/astro/src/astro-components/interactive/UserButton.astro
This file was deleted.
Oops, something went wrong.
83 changes: 83 additions & 0 deletions
83
packages/astro/src/astro-components/interactive/UserButton/MenuItemRenderer.astro
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
--- | ||
type Props = { | ||
label: string | ||
href?: string | ||
open?: string | ||
clickIdentifier?: string | ||
parent?: string | ||
} | ||
const { label, href, open, clickIdentifier, parent } = Astro.props | ||
let labelIcon = ''; | ||
if (Astro.slots.has('label-icon')) { | ||
labelIcon = await Astro.slots.render('label-icon'); | ||
} | ||
const isDevMode = import.meta.env.DEV; | ||
--- | ||
|
||
<script is:inline define:vars={{ label, href, open, clickIdentifier, labelIcon, isDevMode, parent }}> | ||
const parentElement = document.currentScript.parentElement; | ||
|
||
// We used a web component in the `<UserButton.MenuItems>` component. | ||
const hasParentMenuItem = parentElement.tagName.toLowerCase() === 'clerk-user-button-menu-items'; | ||
if (!hasParentMenuItem) { | ||
if (isDevMode) { | ||
throw new Error( | ||
`Clerk: <UserButton.MenuItems /> component can only accept <UserButton.Action /> and <UserButton.Link /> as its children. Any other provided component will be ignored.` | ||
); | ||
} | ||
return | ||
} | ||
|
||
// Get the user button map from window that we set in the `<InternalUIComponentRenderer />`. | ||
const userButtonComponentMap = window.__astro_clerk_component_props.get('user-button'); | ||
|
||
let userButton | ||
if (parent) { | ||
userButton = document.querySelector(`[data-clerk-id="clerk-user-button-${parent}"]`); | ||
} else { | ||
userButton = document.querySelector('[data-clerk-id^="clerk-user-button"]'); | ||
} | ||
|
||
const safeId = userButton.getAttribute('data-clerk-id'); | ||
const currentOptions = userButtonComponentMap.get(safeId); | ||
|
||
const reorderItemsLabels = ['manageAccount', 'signOut']; | ||
const isReorderItem = reorderItemsLabels.includes(label); | ||
|
||
let newMenuItem = { | ||
label, | ||
} | ||
|
||
if (!isReorderItem) { | ||
newMenuItem = { | ||
...newMenuItem, | ||
mountIcon: (el) => { | ||
el.innerHTML = labelIcon | ||
}, | ||
unmountIcon: () => { /* What to clean up? */} | ||
} | ||
|
||
if (href) { | ||
newMenuItem.href = href; | ||
} else if (open) { | ||
newMenuItem.open = open.startsWith('/') ? open : `/${open}`; | ||
} else if (clickIdentifier) { | ||
const clickEvent = new CustomEvent('clerk:menu-item-click', { detail: clickIdentifier }); | ||
newMenuItem.onClick = () => { | ||
document.dispatchEvent(clickEvent); | ||
} | ||
} | ||
} | ||
|
||
userButtonComponentMap.set(safeId, { | ||
...currentOptions, | ||
customMenuItems: [ | ||
...(currentOptions?.customMenuItems ?? []), | ||
newMenuItem, | ||
] | ||
}) | ||
</script> |
29 changes: 29 additions & 0 deletions
29
packages/astro/src/astro-components/interactive/UserButton/UserButton.astro
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
--- | ||
import type { UserButtonProps, UserProfileProps, Without } from "@clerk/types"; | ||
type Props = Without<UserButtonProps, 'userProfileProps'> & { | ||
userProfileProps?: Pick<UserProfileProps, 'additionalOAuthScopes' | 'appearance'>; | ||
/** | ||
* If you have more than one UserButton on a page, providing a custom ID is required | ||
* to properly scope menu items to the correct button. | ||
* | ||
* Example usage: | ||
* ```tsx | ||
* <UserButton id="someId"> | ||
* <UserButton.MenuItems> | ||
* <UserButton.Link parent="someId" label="User" href="/user"> | ||
* <Icon slot="label-icon" /> | ||
* </UserButton.Link> | ||
* </UserButton.MenuItems> | ||
* </UserButton> | ||
* ``` | ||
*/ | ||
id?: string; | ||
} | ||
import InternalUIComponentRenderer from '../InternalUIComponentRenderer.astro' | ||
--- | ||
|
||
<InternalUIComponentRenderer {...Astro.props} component="user-button" /> | ||
|
||
<slot /> |
24 changes: 24 additions & 0 deletions
24
packages/astro/src/astro-components/interactive/UserButton/UserButtonAction.astro
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
--- | ||
import MenuItemRenderer from './MenuItemRenderer.astro'; | ||
type ReorderItemsLabels = 'manageAccount' | 'signOut' | ||
type Props<Label extends string> = { | ||
label: Label | ||
parent?: string | ||
} & (Label extends ReorderItemsLabels | ||
? { | ||
open?: string | ||
} | ||
: ( | ||
| { open: string; clickIdentifier?: string } | ||
| { open?: string; clickIdentifier: string } | ||
) | ||
) | ||
const { label, open, clickIdentifier, parent } = Astro.props | ||
--- | ||
|
||
<MenuItemRenderer label={label} open={open} clickIdentifier={clickIdentifier} parent={parent}> | ||
<slot name="label-icon" slot="label-icon" /> | ||
</MenuItemRenderer> |
15 changes: 15 additions & 0 deletions
15
packages/astro/src/astro-components/interactive/UserButton/UserButtonLink.astro
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
--- | ||
import MenuItemRenderer from './MenuItemRenderer.astro'; | ||
interface Props { | ||
label: string | ||
href: string | ||
parent?: string | ||
} | ||
const { label, href, parent } = Astro.props | ||
--- | ||
|
||
<MenuItemRenderer label={label} href={href} parent={parent}> | ||
<slot name="label-icon" slot="label-icon" /> | ||
</MenuItemRenderer> |
18 changes: 18 additions & 0 deletions
18
packages/astro/src/astro-components/interactive/UserButton/UserButtonMenuItems.astro
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<clerk-user-button-menu-items> | ||
<slot /> | ||
</clerk-user-button-menu-items> | ||
|
||
<script> | ||
/** | ||
* In the React version, menu items need to be wrapped in a `<UserButton.MenuItems>` component. | ||
* We are trying to replicate that behavior here by adding a wrapper component | ||
* and check if it exists inside the menu items components. | ||
*/ | ||
class ClerkUserButtonMenuItems extends HTMLElement { | ||
constructor() { | ||
super(); | ||
} | ||
} | ||
|
||
customElements.define('clerk-user-button-menu-items', ClerkUserButtonMenuItems); | ||
</script> |
Oops, something went wrong.