@cronos-labs/ui 0.5.1 → 0.7.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/dist/FooterWaitlist/helper.d.ts +9 -2
- package/dist/FooterWaitlist/helper.js +21 -6
- package/dist/FooterWaitlist/index.d.ts +10 -1
- package/dist/FooterWaitlist/index.js +8 -9
- package/dist/FooterWaitlist/types.d.ts +21 -0
- package/dist/FooterWaitlist/types.js +1 -0
- package/dist/Header/index.js +1 -1
- package/dist/environment.d.ts +32 -0
- package/dist/environment.js +38 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +2 -0
- package/package.json +1 -1
|
@@ -1,3 +1,10 @@
|
|
|
1
1
|
import type { NavigationContent } from '../navigationContent.js';
|
|
2
|
-
import type {
|
|
3
|
-
|
|
2
|
+
import type { FooterWaitlistContent } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Falls back to the bundled Cronos copy for a locale.
|
|
5
|
+
*
|
|
6
|
+
* The dictionary shipped with this package is a convenience for the Cronos
|
|
7
|
+
* properties, not a definition of what the component says — a differently
|
|
8
|
+
* branded site passes its own `content` instead and never reads this.
|
|
9
|
+
*/
|
|
10
|
+
export declare const resolveFooterWaitlistContent: (navContent: NavigationContent) => FooterWaitlistContent;
|
|
@@ -1,7 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Falls back to the bundled Cronos copy for a locale.
|
|
3
|
+
*
|
|
4
|
+
* The dictionary shipped with this package is a convenience for the Cronos
|
|
5
|
+
* properties, not a definition of what the component says — a differently
|
|
6
|
+
* branded site passes its own `content` instead and never reads this.
|
|
7
|
+
*/
|
|
8
|
+
export const resolveFooterWaitlistContent = (navContent) => ({
|
|
9
|
+
ctaTitle: navContent.footer.ctaTitle,
|
|
10
|
+
emailPlaceholder: navContent.footer.emailPlaceholder,
|
|
11
|
+
submitLabel: navContent.footer.submitLabel,
|
|
12
|
+
consentLabel: navContent.footer.consentLabel,
|
|
13
|
+
consentNote: navContent.footer.consentNote,
|
|
14
|
+
socialHeading: navContent.footer.socialHeading,
|
|
15
|
+
messages: {
|
|
16
|
+
successMessage: navContent.footer.waitlistForm.successMessage,
|
|
17
|
+
emptyEmailMessage: navContent.footer.waitlistForm.emptyEmailMessage,
|
|
18
|
+
invalidEmailMessage: navContent.footer.waitlistForm.invalidEmailMessage,
|
|
19
|
+
errorMessage: navContent.footer.waitlistForm.errorMessage,
|
|
20
|
+
submittingLabel: navContent.footer.waitlistForm.submittingLabel,
|
|
21
|
+
},
|
|
7
22
|
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type ReactNode } from 'react';
|
|
2
2
|
import type { WaitlistRequest, WaitlistSource } from '../waitlist/types.js';
|
|
3
|
+
import type { FooterWaitlistContent } from './types.js';
|
|
3
4
|
import { type FooterWaitlistVariant } from './styles.js';
|
|
4
5
|
export interface FooterWaitlistProps {
|
|
5
6
|
/** Identifies which form on the site was submitted. */
|
|
@@ -14,6 +15,14 @@ export interface FooterWaitlistProps {
|
|
|
14
15
|
onWaitlistError?: ((message: string) => void) | undefined;
|
|
15
16
|
/** Fires when submit is pressed, before validation. For analytics. */
|
|
16
17
|
onSubmitClick?: (() => void) | undefined;
|
|
18
|
+
/**
|
|
19
|
+
* Every string this renders, already localized.
|
|
20
|
+
*
|
|
21
|
+
* Omit it and the component falls back to the Cronos copy bundled with this
|
|
22
|
+
* package for the active locale. Any site that is not Cronos should pass its
|
|
23
|
+
* own — the bundled dictionary is a convenience, not the component's voice.
|
|
24
|
+
*/
|
|
25
|
+
content?: FooterWaitlistContent | undefined;
|
|
17
26
|
}
|
|
18
27
|
/**
|
|
19
28
|
* Email capture card with the site's social row beneath it.
|
|
@@ -21,4 +30,4 @@ export interface FooterWaitlistProps {
|
|
|
21
30
|
* Wordmark and social links come from `<BrandProvider>`, so two sites render
|
|
22
31
|
* this identically while showing entirely different artwork and destinations.
|
|
23
32
|
*/
|
|
24
|
-
export declare function FooterWaitlist({ source, submit, attributionKey, variant, legalMeta, onWaitlistSuccess, onWaitlistError, onSubmitClick, }: FooterWaitlistProps): React.JSX.Element;
|
|
33
|
+
export declare function FooterWaitlist({ source, submit, attributionKey, variant, legalMeta, onWaitlistSuccess, onWaitlistError, onSubmitClick, content, }: FooterWaitlistProps): React.JSX.Element;
|
|
@@ -5,7 +5,7 @@ import { navigationContent } from '../navigationContent.js';
|
|
|
5
5
|
import { useCurrentLocale } from '../locale/hooks.js';
|
|
6
6
|
import { resetAutocompleteFillMarkersAfterInput } from '../waitlist/autocompleteFillMarkers.js';
|
|
7
7
|
import { useWaitlistForm } from '../waitlist/useWaitlistForm.js';
|
|
8
|
-
import {
|
|
8
|
+
import { resolveFooterWaitlistContent } from './helper.js';
|
|
9
9
|
import { WaitlistCard, WaitlistCardContent, WaitlistCardTitle, WaitlistCheckbox, WaitlistCheckboxLabel, WaitlistCheckboxRow, WaitlistContainer, WaitlistDisclaimer, WaitlistFieldGroup, WaitlistForm, WaitlistInput, WaitlistInputMeasure, WaitlistLowerContent, WaitlistSectionShell, WaitlistSocialBlock, WaitlistSocialIcon, WaitlistSocialLink, WaitlistSocialLinks, WaitlistStatusText, WaitlistSubmitButton, } from './styles.js';
|
|
10
10
|
// Below this the address is unreadable; the field scrolls instead of shrinking further.
|
|
11
11
|
const minWaitlistInputScale = 0.5;
|
|
@@ -15,18 +15,17 @@ const minWaitlistInputScale = 0.5;
|
|
|
15
15
|
* Wordmark and social links come from `<BrandProvider>`, so two sites render
|
|
16
16
|
* this identically while showing entirely different artwork and destinations.
|
|
17
17
|
*/
|
|
18
|
-
export function FooterWaitlist({ source, submit, attributionKey, variant = 'footer', legalMeta, onWaitlistSuccess, onWaitlistError, onSubmitClick, }) {
|
|
18
|
+
export function FooterWaitlist({ source, submit, attributionKey, variant = 'footer', legalMeta, onWaitlistSuccess, onWaitlistError, onSubmitClick, content, }) {
|
|
19
19
|
const locale = useCurrentLocale();
|
|
20
20
|
const brand = useBrand();
|
|
21
|
-
const
|
|
22
|
-
const waitlistContent = resolveWaitlistFormContent(navContent);
|
|
21
|
+
const copy = content ?? resolveFooterWaitlistContent(navigationContent[locale]);
|
|
23
22
|
const inputRef = useRef(null);
|
|
24
23
|
const inputMeasureRef = useRef(null);
|
|
25
24
|
const [waitlistInputScale, setWaitlistInputScale] = useState(1);
|
|
26
25
|
const waitlistMessages = {
|
|
27
|
-
...
|
|
28
|
-
emailPlaceholder:
|
|
29
|
-
submitLabel:
|
|
26
|
+
...copy.messages,
|
|
27
|
+
emailPlaceholder: copy.emailPlaceholder,
|
|
28
|
+
submitLabel: copy.submitLabel,
|
|
30
29
|
};
|
|
31
30
|
const waitlistOptions = {
|
|
32
31
|
source,
|
|
@@ -80,7 +79,7 @@ export function FooterWaitlist({ source, submit, attributionKey, variant = 'foot
|
|
|
80
79
|
window.removeEventListener('resize', updateWaitlistInputScale);
|
|
81
80
|
};
|
|
82
81
|
}, [updateWaitlistInputScale]);
|
|
83
|
-
return (_jsx(WaitlistSectionShell, { "$variant": variant, children: _jsx(WaitlistContainer, { "$variant": variant, children: _jsx(WaitlistCard, { children: _jsxs(WaitlistCardContent, { "$variant": variant, children: [_jsx(WaitlistCardTitle, { "$variant": variant, children:
|
|
82
|
+
return (_jsx(WaitlistSectionShell, { "$variant": variant, children: _jsx(WaitlistContainer, { "$variant": variant, children: _jsx(WaitlistCard, { children: _jsxs(WaitlistCardContent, { "$variant": variant, children: [_jsx(WaitlistCardTitle, { "$variant": variant, children: copy.ctaTitle }), _jsxs(WaitlistForm, { "$variant": variant, noValidate: true, onSubmit: (event) => {
|
|
84
83
|
void onSubmit(event);
|
|
85
|
-
}, children: [_jsxs(WaitlistFieldGroup, { "$variant": variant, children: [_jsx(WaitlistInputMeasure, { ref: inputMeasureRef, "$variant": variant, "aria-hidden": "true", children: email }), _jsx(WaitlistInput, { ref: setWaitlistInputRef, "$variant": variant, "$fontScale": waitlistInputScale, "aria-describedby": describedBy, "aria-invalid": emailError ? true : undefined, "aria-label": waitlistMessages.emailPlaceholder, autoComplete: "email", placeholder: waitlistMessages.emailPlaceholder, type: "email", value: email, onChange: handleWaitlistEmailChange, onFocus: (event) => resetAutocompleteFillMarkersAfterInput(event.currentTarget) }), _jsx(WaitlistSubmitButton, { "$variant": variant, type: "submit", disabled: isSubmitting, onClick: onSubmitClick, children: isSubmitting ? waitlistMessages.submittingLabel : waitlistMessages.submitLabel })] }), statusMessage ? (_jsx(WaitlistStatusText, { "$tone": statusTone, id: `${variant}-waitlist-status`, "aria-live": "polite", role: "status", children: statusMessage })) : null, _jsx(WaitlistDisclaimer, { children:
|
|
84
|
+
}, children: [_jsxs(WaitlistFieldGroup, { "$variant": variant, children: [_jsx(WaitlistInputMeasure, { ref: inputMeasureRef, "$variant": variant, "aria-hidden": "true", children: email }), _jsx(WaitlistInput, { ref: setWaitlistInputRef, "$variant": variant, "$fontScale": waitlistInputScale, "aria-describedby": describedBy, "aria-invalid": emailError ? true : undefined, "aria-label": waitlistMessages.emailPlaceholder, autoComplete: "email", placeholder: waitlistMessages.emailPlaceholder, type: "email", value: email, onChange: handleWaitlistEmailChange, onFocus: (event) => resetAutocompleteFillMarkersAfterInput(event.currentTarget) }), _jsx(WaitlistSubmitButton, { "$variant": variant, type: "submit", disabled: isSubmitting, onClick: onSubmitClick, children: isSubmitting ? waitlistMessages.submittingLabel : waitlistMessages.submitLabel })] }), statusMessage ? (_jsx(WaitlistStatusText, { "$tone": statusTone, id: `${variant}-waitlist-status`, "aria-live": "polite", role: "status", children: statusMessage })) : null, _jsx(WaitlistDisclaimer, { children: copy.consentNote })] }), _jsxs(WaitlistLowerContent, { "$variant": variant, children: [_jsxs(WaitlistCheckboxRow, { htmlFor: `${variant}-waitlist-marketing`, children: [_jsx(WaitlistCheckbox, { id: `${variant}-waitlist-marketing`, checked: consentMarketing, type: "checkbox", onChange: (event) => setConsentMarketing(event.target.checked) }), _jsx(WaitlistCheckboxLabel, { children: copy.consentLabel })] }), brand.socialLinks.length > 0 ? (_jsx(WaitlistSocialBlock, { "$variant": variant, "aria-label": copy.socialHeading, children: _jsx(WaitlistSocialLinks, { children: brand.socialLinks.map((socialLink) => (_jsx(WaitlistSocialLink, { href: socialLink.href, target: "_blank", rel: "noreferrer", "aria-label": socialLink.label, children: _jsx(WaitlistSocialIcon, { src: socialLink.iconSrc, alt: "", "aria-hidden": "true", loading: "lazy" }) }, socialLink.key))) }) })) : null, legalMeta] })] }) }) }) }));
|
|
86
85
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { WaitlistFormMessages } from '../waitlist/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Every string `FooterWaitlist` renders.
|
|
4
|
+
*
|
|
5
|
+
* Supplied per site so the component carries no brand's wording. Localize
|
|
6
|
+
* before passing it in — this package does not translate.
|
|
7
|
+
*/
|
|
8
|
+
export interface FooterWaitlistContent {
|
|
9
|
+
/** Heading above the form. */
|
|
10
|
+
ctaTitle: string;
|
|
11
|
+
emailPlaceholder: string;
|
|
12
|
+
submitLabel: string;
|
|
13
|
+
/** Label beside the marketing-consent checkbox. */
|
|
14
|
+
consentLabel: string;
|
|
15
|
+
/** Fine print under the form, e.g. a privacy-notice acknowledgement. */
|
|
16
|
+
consentNote: string;
|
|
17
|
+
/** Accessible name for the social-links group. */
|
|
18
|
+
socialHeading: string;
|
|
19
|
+
/** Validation and submission feedback. */
|
|
20
|
+
messages: WaitlistFormMessages;
|
|
21
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/Header/index.js
CHANGED
|
@@ -94,7 +94,7 @@ export function Header({ brandWordmarkSrc, content, forceDocumentNavigation = fa
|
|
|
94
94
|
setIsMobileMenuOpen(false);
|
|
95
95
|
waitlistCta?.onClick?.(event, ctaLocation);
|
|
96
96
|
};
|
|
97
|
-
return (_jsxs(HeaderFrame, { "data-header-frame": "true", "$shouldAnimatePresentation": shouldAnimatePresentation, "$backgroundColor": presentation.backgroundColor, "$mobileBackgroundColor": mobilePresentation?.backgroundColor, "$contrast": presentation.contrast, children: [_jsxs(HeaderShell, { "$shouldAnimatePresentation": shouldAnimatePresentation, "$textColor": presentation.textColor, "$mobileTextColor": mobilePresentation?.textColor, children: [_jsx(HeaderBrandLink, { href: forceDocumentNavigation ? canonicalizeDocumentHref(homeHref) : homeHref, "aria-label":
|
|
97
|
+
return (_jsxs(HeaderFrame, { "data-header-frame": "true", "$shouldAnimatePresentation": shouldAnimatePresentation, "$backgroundColor": presentation.backgroundColor, "$mobileBackgroundColor": mobilePresentation?.backgroundColor, "$contrast": presentation.contrast, children: [_jsxs(HeaderShell, { "$shouldAnimatePresentation": shouldAnimatePresentation, "$textColor": presentation.textColor, "$mobileTextColor": mobilePresentation?.textColor, children: [_jsx(HeaderBrandLink, { href: forceDocumentNavigation ? canonicalizeDocumentHref(homeHref) : homeHref, "aria-label": brandName ? `${brandName} home` : 'Home', onClick: forceDocumentNavigation
|
|
98
98
|
? undefined
|
|
99
99
|
: (event) => handleInternalNavigation(event, homeHref), children: presentation.contrast ? (_jsx(BrandWordmarkMask, { "$url": wordmarkSrc, role: "img", "aria-label": brandName })) : (_jsx(Wordmark, { "$shouldAnimatePresentation": shouldAnimatePresentation, "$variant": presentation.variant, "$mobileVariant": mobilePresentation?.variant, src: wordmarkSrc, alt: brandName })) }), _jsx(Nav, { "$variant": presentation.variant, "$contrast": presentation.contrast, "aria-label": "Global navigation", children: enabledNavItems.map((item) => {
|
|
100
100
|
const label = item.label;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export declare enum CronosEnvironment {
|
|
2
|
+
Staging = "staging",
|
|
3
|
+
Prod = "prod"
|
|
4
|
+
}
|
|
5
|
+
export interface CronosUrls {
|
|
6
|
+
cronos: string;
|
|
7
|
+
bridge: string;
|
|
8
|
+
launch: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Narrows a raw `VITE_ENVIRONMENT` value to a known environment.
|
|
12
|
+
*
|
|
13
|
+
* Staging is the fallback, not prod: an unset variable means a local dev
|
|
14
|
+
* server or a misconfigured preview, and pointing those at production
|
|
15
|
+
* traffic is the more expensive mistake. Production deploys set the
|
|
16
|
+
* variable explicitly.
|
|
17
|
+
*
|
|
18
|
+
* @param value Raw environment variable value, of unknown shape.
|
|
19
|
+
* @returns The matching environment, or staging when the value is unrecognised.
|
|
20
|
+
*/
|
|
21
|
+
export declare const resolveCronosEnvironment: (value: unknown) => CronosEnvironment;
|
|
22
|
+
/**
|
|
23
|
+
* Resolves the origins of the three Cronos web apps for an environment.
|
|
24
|
+
*
|
|
25
|
+
* The apps link to each other across origins, so these have to move as a
|
|
26
|
+
* set — a staging build linking to a production sibling is the failure this
|
|
27
|
+
* prevents. Origins carry no trailing slash; callers append their own path.
|
|
28
|
+
*
|
|
29
|
+
* @param environment The environment the app is running in.
|
|
30
|
+
* @returns The sibling app origins for that environment.
|
|
31
|
+
*/
|
|
32
|
+
export declare const resolveCronosUrls: (environment: CronosEnvironment) => CronosUrls;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export var CronosEnvironment;
|
|
2
|
+
(function (CronosEnvironment) {
|
|
3
|
+
CronosEnvironment["Staging"] = "staging";
|
|
4
|
+
CronosEnvironment["Prod"] = "prod";
|
|
5
|
+
})(CronosEnvironment || (CronosEnvironment = {}));
|
|
6
|
+
const PROD_URLS = {
|
|
7
|
+
cronos: 'https://cronos.com',
|
|
8
|
+
bridge: 'https://bridge.cronos.com',
|
|
9
|
+
launch: 'https://launch.cronos.com',
|
|
10
|
+
};
|
|
11
|
+
const STAGING_URLS = {
|
|
12
|
+
cronos: 'https://psta-cronos-landingpage-webui.crorc.co',
|
|
13
|
+
bridge: 'https://psta-cronos-bridge-webui.crorc.co',
|
|
14
|
+
launch: 'https://psta-cronos-launch-webui.crorc.co',
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Narrows a raw `VITE_ENVIRONMENT` value to a known environment.
|
|
18
|
+
*
|
|
19
|
+
* Staging is the fallback, not prod: an unset variable means a local dev
|
|
20
|
+
* server or a misconfigured preview, and pointing those at production
|
|
21
|
+
* traffic is the more expensive mistake. Production deploys set the
|
|
22
|
+
* variable explicitly.
|
|
23
|
+
*
|
|
24
|
+
* @param value Raw environment variable value, of unknown shape.
|
|
25
|
+
* @returns The matching environment, or staging when the value is unrecognised.
|
|
26
|
+
*/
|
|
27
|
+
export const resolveCronosEnvironment = (value) => value === CronosEnvironment.Prod ? CronosEnvironment.Prod : CronosEnvironment.Staging;
|
|
28
|
+
/**
|
|
29
|
+
* Resolves the origins of the three Cronos web apps for an environment.
|
|
30
|
+
*
|
|
31
|
+
* The apps link to each other across origins, so these have to move as a
|
|
32
|
+
* set — a staging build linking to a production sibling is the failure this
|
|
33
|
+
* prevents. Origins carry no trailing slash; callers append their own path.
|
|
34
|
+
*
|
|
35
|
+
* @param environment The environment the app is running in.
|
|
36
|
+
* @returns The sibling app origins for that environment.
|
|
37
|
+
*/
|
|
38
|
+
export const resolveCronosUrls = (environment) => environment === CronosEnvironment.Prod ? PROD_URLS : STAGING_URLS;
|
package/dist/index.d.ts
CHANGED
|
@@ -25,6 +25,8 @@ export { isOneTrustEventTarget, openCookiePreferences } from './onetrust.js';
|
|
|
25
25
|
export { BrandProvider, useBrand, useOptionalBrand } from './brand/index.js';
|
|
26
26
|
export type { BrandAssets, BrandSocialLink } from './brand/index.js';
|
|
27
27
|
export { FooterWaitlist, type FooterWaitlistProps } from './FooterWaitlist/index.js';
|
|
28
|
+
export type { FooterWaitlistContent } from './FooterWaitlist/types.js';
|
|
29
|
+
export { resolveFooterWaitlistContent } from './FooterWaitlist/helper.js';
|
|
28
30
|
export { useWaitlistForm } from './waitlist/useWaitlistForm.js';
|
|
29
31
|
export type { UseWaitlistFormOptions, WaitlistStatusTone } from './waitlist/useWaitlistForm.js';
|
|
30
32
|
export type { WaitlistRequest, WaitlistResponse, WaitlistSource, WaitlistFormMessages, } from './waitlist/types.js';
|
|
@@ -32,3 +34,5 @@ export { resetAutocompleteFillMarkersAfterInput } from './waitlist/autocompleteF
|
|
|
32
34
|
export { clearWaitlistAttribution, getWaitlistBrowserContext } from './waitlist/attribution.js';
|
|
33
35
|
export { cardSurface, cardHoverSurface, wellSurface } from './surfaces.js';
|
|
34
36
|
export { Button, type ButtonProps, type ButtonVariant } from './Button/index.js';
|
|
37
|
+
export { CronosEnvironment, resolveCronosEnvironment, resolveCronosUrls } from './environment.js';
|
|
38
|
+
export type { CronosUrls } from './environment.js';
|
package/dist/index.js
CHANGED
|
@@ -21,8 +21,10 @@ export { fetchJson, HttpError } from './fetch.js';
|
|
|
21
21
|
export { isOneTrustEventTarget, openCookiePreferences } from './onetrust.js';
|
|
22
22
|
export { BrandProvider, useBrand, useOptionalBrand } from './brand/index.js';
|
|
23
23
|
export { FooterWaitlist } from './FooterWaitlist/index.js';
|
|
24
|
+
export { resolveFooterWaitlistContent } from './FooterWaitlist/helper.js';
|
|
24
25
|
export { useWaitlistForm } from './waitlist/useWaitlistForm.js';
|
|
25
26
|
export { resetAutocompleteFillMarkersAfterInput } from './waitlist/autocompleteFillMarkers.js';
|
|
26
27
|
export { clearWaitlistAttribution, getWaitlistBrowserContext } from './waitlist/attribution.js';
|
|
27
28
|
export { cardSurface, cardHoverSurface, wellSurface } from './surfaces.js';
|
|
28
29
|
export { Button } from './Button/index.js';
|
|
30
|
+
export { CronosEnvironment, resolveCronosEnvironment, resolveCronosUrls } from './environment.js';
|