-
Notifications
You must be signed in to change notification settings - Fork 271
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(elements,ui,clerk-js): Legal consent elements support and improvements #4427
Changes from all commits
fface15
8d8afd3
6795ae5
144c5a4
3d3e50a
c0a8b99
5e057eb
3d57956
3c66412
eadc5de
d8648b8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@clerk/elements": minor | ||
--- | ||
|
||
Added support for `__experimental_legalAccepted` field |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
--- | ||
"@clerk/clerk-js": patch | ||
"@clerk/types": patch | ||
--- | ||
|
||
- Changed `__experimental_legalAccepted` checkbox Indicator element descriptor and element id | ||
- Changed `__experimental_legalAccepted` checkbox Label element descriptor and element id | ||
- Added two new element descriptors `formFieldCheckboxInput`, `formFieldCheckboxLabel`. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import * as Common from '@clerk/elements/common'; | ||
import React from 'react'; | ||
|
||
import { useAppearance } from '~/contexts'; | ||
import { useEnvironment } from '~/hooks/use-environment'; | ||
import { useLocalizations } from '~/hooks/use-localizations'; | ||
import * as Field from '~/primitives/field'; | ||
|
||
import { LinkRenderer } from './link-renderer'; | ||
|
||
export function LegalAcceptedField({ | ||
className, | ||
checked = false, | ||
...restProps | ||
}: Omit<React.ComponentProps<typeof Common.Input>, 'type'>) { | ||
const { t } = useLocalizations(); | ||
const { displayConfig } = useEnvironment(); | ||
const { parsedAppearance } = useAppearance(); | ||
const termsUrl = parsedAppearance.options.termsPageUrl || displayConfig.termsUrl; | ||
const privacyPolicyUrl = parsedAppearance.options.privacyPageUrl || displayConfig.privacyPolicyUrl; | ||
|
||
let localizedText: string | undefined; | ||
|
||
if (termsUrl && privacyPolicyUrl) { | ||
localizedText = t('signUp.__experimental_legalConsent.checkbox.label__termsOfServiceAndPrivacyPolicy', { | ||
termsOfServiceLink: termsUrl, | ||
privacyPolicyLink: privacyPolicyUrl, | ||
}); | ||
} else if (termsUrl) { | ||
localizedText = t('signUp.__experimental_legalConsent.checkbox.label__onlyTermsOfService', { | ||
termsOfServiceLink: termsUrl, | ||
}); | ||
} else if (privacyPolicyUrl) { | ||
localizedText = t('signUp.__experimental_legalConsent.checkbox.label__onlyPrivacyPolicy', { | ||
privacyPolicyLink: privacyPolicyUrl, | ||
}); | ||
} | ||
|
||
return ( | ||
<Common.Field | ||
name='__experimental_legalAccepted' | ||
asChild | ||
> | ||
<Field.Root> | ||
<div className='flex justify-center gap-2'> | ||
<Common.Input | ||
type='checkbox' | ||
asChild | ||
checked={checked} | ||
{...restProps} | ||
> | ||
<Field.Checkbox /> | ||
</Common.Input> | ||
|
||
<Common.Label asChild> | ||
<Field.Label> | ||
<span> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is there a reason for the extra wrapping span here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah because the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, maybe we need a prop on the label to set the flex direction? Trying to reduce the amount of extra markup added to reduce the need for descriptors. |
||
<LinkRenderer | ||
text={localizedText || ''} | ||
className='underline underline-offset-2' | ||
/> | ||
</span> | ||
</Field.Label> | ||
</Common.Label> | ||
</div> | ||
|
||
<Common.FieldError asChild> | ||
{({ message }) => { | ||
return <Field.Message intent='error'>{message}</Field.Message>; | ||
}} | ||
</Common.FieldError> | ||
</Field.Root> | ||
</Common.Field> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import React, { memo, useMemo } from 'react'; | ||
|
||
interface LinkRendererProps extends Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, 'href' | 'children' | 'class'> { | ||
text: string; | ||
className?: string; | ||
} | ||
|
||
const LINK_REGEX = /\[([^\]]+)\]\(([^)]+)\)/g; // parses [text](url) | ||
|
||
export const LinkRenderer: React.FC<LinkRendererProps> = memo(({ text, ...linkProps }) => { | ||
const memoizedLinkProps = useMemo(() => linkProps, [linkProps]); | ||
|
||
const renderedContent = useMemo(() => { | ||
const parts: (string | JSX.Element)[] = []; | ||
let lastIndex = 0; | ||
|
||
text.replace(LINK_REGEX, (match, linkText, url, offset) => { | ||
if (offset > lastIndex) { | ||
parts.push(text.slice(lastIndex, offset)); | ||
} | ||
parts.push( | ||
<a | ||
{...memoizedLinkProps} | ||
href={url} | ||
target='_blank' | ||
rel='noopener noreferrer' | ||
key={offset} | ||
> | ||
{linkText} | ||
</a>, | ||
); | ||
lastIndex = offset + match.length; | ||
return match; | ||
}); | ||
|
||
if (lastIndex < text.length) { | ||
parts.push(text.slice(lastIndex)); | ||
} | ||
|
||
return parts; | ||
}, [text, memoizedLinkProps]); | ||
|
||
return renderedContent; | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will want to replace the
gap-2
usage here with padding left on the label.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense!