web: Improve auth ui on web/desktop (#10218)

* web: improve auth ui

* web: fix password show/hide icons

* web: fix auth form width

* web: fix minor ui issues with back button & recovery view
This commit is contained in:
Abdullah Atta
2026-08-17 11:41:18 +05:00
committed by GitHub
parent 20b4585361
commit 4e1acc292d
6 changed files with 220 additions and 181 deletions

View File

@@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
import { useMemo } from "react"; import { useMemo } from "react";
import { Box, Button, Flex, Image, Link, Text } from "@theme-ui/components"; import { Button, Flex, Image, Text } from "@theme-ui/components";
import { getRandom, usePromise } from "@notesnook/common"; import { getRandom, usePromise } from "@notesnook/common";
import Holenstein from "../../assets/testimonials/holenstein.jpg"; import Holenstein from "../../assets/testimonials/holenstein.jpg";
import Jason from "../../assets/testimonials/jason.jpg"; import Jason from "../../assets/testimonials/jason.jpg";
@@ -26,6 +26,7 @@ import Cameron from "../../assets/testimonials/cameron.jpg";
import { hosts } from "@notesnook/core"; import { hosts } from "@notesnook/core";
import { SettingsDialog } from "../../dialogs/settings"; import { SettingsDialog } from "../../dialogs/settings";
import { strings } from "@notesnook/intl"; import { strings } from "@notesnook/intl";
import { FixedColorSchemeThemeProvider } from "../theme-provider";
const testimonials = [ const testimonials = [
{ {
@@ -80,62 +81,18 @@ function AuthContainer(props) {
bg: "background" bg: "background"
}} }}
> >
<Box <FixedColorSchemeThemeProvider
colorScheme="dark"
sx={{ sx={{
position: "relative", position: "relative",
overflow: "hidden", overflow: "hidden",
flexDirection: "column", flexDirection: "column",
display: ["none", "none", "flex"], display: ["none", "none", "flex"],
flex: 1 flex: 1,
background:
"radial-gradient(1200px 700px at 82% 18%, color-mix(in srgb, var(--accent) 14%, transparent) 0%, transparent 62%), var(--background-secondary)"
}} }}
> >
<Box
as="svg"
version="1.1"
viewBox="0 0 1920 1080"
preserveAspectRatio="xMinYMin slice"
sx={{
position: "absolute",
top: -100,
left: 0,
height: "100%"
// opacity: 0.7,
}}
>
<g mask='url("#SvgjsMask1017")' fill="none">
<path
d="M1184.21-85.14C1033.8-60.27 964.89 302.42 717.38 307.22 469.87 312.02 483.97 244.72 250.55 244.72 17.13 244.72-98.53 307.08-216.28 307.22"
stroke="var(--icon)"
strokeWidth="2"
></path>
<path
d="M641.38-10.43C534.57 43 590.55 387.5 384.53 392.38 178.52 397.26 2.17 282.99-129.16 282.38"
stroke="var(--icon)"
strokeWidth="2"
></path>
<path
d="M1136.18-29.24C957.53-5.77 852.26 404.49 561.01 405.07 269.76 405.65 142.54 160.4-14.16 155.07"
stroke="var(--icon)"
strokeWidth="2"
></path>
<path
d="M508.47-71.88C398.16-66.29 333.42 117.75 114.38 127.84-104.65 137.93-170.96 308.31-279.7 312.84"
stroke="var(--icon)"
strokeWidth="2"
></path>
<path
d="M1104.88-26.74C976.63-19.04 883.5 217.2 653.03 218.11 422.55 219.02 427.1 155.61 201.17 155.61-24.75 155.61-136.64 217.96-250.68 218.11"
stroke="var(--icon)"
strokeWidth="2"
></path>
</g>
<defs>
<mask id="SvgjsMask1017">
<rect width="1440" height="500" fill="#ffffff"></rect>
</mask>
</defs>
</Box>
<Flex <Flex
p={50} p={50}
sx={{ sx={{
@@ -162,17 +119,9 @@ function AuthContainer(props) {
<Text <Text
variant="body" variant="body"
mt={10} mt={10}
sx={{ fontSize: 14, color: "paragraph-secondary" }} sx={{ fontSize: 16, color: "paragraph-secondary" }}
> >
{testimonial.text} {" "} {testimonial.text}
<Link
sx={{ fontStyle: "italic", color: "paragraph-secondary" }}
href={testimonial.link}
target="_blank"
rel="noopener noreferrer"
>
source
</Link>
</Text> </Text>
<Flex mt={2} sx={{ alignItems: "center", justifyContent: "center" }}> <Flex mt={2} sx={{ alignItems: "center", justifyContent: "center" }}>
<Image <Image
@@ -180,10 +129,12 @@ function AuthContainer(props) {
sx={{ borderRadius: 50, width: 40 }} sx={{ borderRadius: 50, width: 40 }}
/> />
<Flex ml={2} sx={{ flexDirection: "column" }}> <Flex ml={2} sx={{ flexDirection: "column" }}>
<Text variant="body" sx={{ fontSize: 14, fontWeight: "bold" }}> <Text variant="body" sx={{ fontSize: 16, fontWeight: "bold" }}>
{testimonial.name} {testimonial.name}
</Text> </Text>
<Text variant="subBody">@{testimonial.username}</Text> <Text variant="subBody" sx={{ fontSize: 13 }}>
@{testimonial.username}
</Text>
</Flex> </Flex>
</Flex> </Flex>
@@ -218,52 +169,18 @@ function AuthContainer(props) {
</Button> </Button>
</Flex> </Flex>
</Flex> </Flex>
</Box> </FixedColorSchemeThemeProvider>
<Flex <FixedColorSchemeThemeProvider
colorScheme="light"
sx={{ sx={{
display: "flex",
position: "relative", position: "relative",
flex: 1.5, flex: 1.5,
flexDirection: "column" background: "var(--background-secondary)"
}} }}
> >
<Box
as="svg"
version="1.1"
viewBox="0 0 1920 1080"
preserveAspectRatio="xMinYMin slice"
sx={{
position: "absolute",
top: 0,
left: 0,
right: 0,
bottom: 0,
width: "130%",
height: "100%"
}}
>
<path
d="M0 336L29.2 316.2C58.3 296.3 116.7 256.7 174.8 267.5C233 278.3 291 339.7 349.2 361.3C407.3 383 465.7 365 523.8 359.5C582 354 640 361 698.2 346.5C756.3 332 814.7 296 872.8 267.2C931 238.3 989 216.7 1047.2 202.3C1105.3 188 1163.7 181 1221.8 202.7C1280 224.3 1338 274.7 1396.2 298C1454.3 321.3 1512.7 317.7 1570.8 332C1629 346.3 1687 378.7 1745.2 366.2C1803.3 353.7 1861.7 296.3 1890.8 267.7L1920 239L1920 0L1890.8 0C1861.7 0 1803.3 0 1745.2 0C1687 0 1629 0 1570.8 0C1512.7 0 1454.3 0 1396.2 0C1338 0 1280 0 1221.8 0C1163.7 0 1105.3 0 1047.2 0C989 0 931 0 872.8 0C814.7 0 756.3 0 698.2 0C640 0 582 0 523.8 0C465.7 0 407.3 0 349.2 0C291 0 233 0 174.8 0C116.7 0 58.3 0 29.2 0L0 0Z"
fill="var(--background-secondary)"
></path>
<path
d="M0 627L29.2 607.3C58.3 587.7 116.7 548.3 174.8 564.7C233 581 291 653 349.2 683.5C407.3 714 465.7 703 523.8 703C582 703 640 714 698.2 724.8C756.3 735.7 814.7 746.3 872.8 742.7C931 739 989 721 1047.2 670.7C1105.3 620.3 1163.7 537.7 1221.8 528.7C1280 519.7 1338 584.3 1396.2 623.8C1454.3 663.3 1512.7 677.7 1570.8 666.8C1629 656 1687 620 1745.2 602C1803.3 584 1861.7 584 1890.8 584L1920 584L1920 237L1890.8 265.7C1861.7 294.3 1803.3 351.7 1745.2 364.2C1687 376.7 1629 344.3 1570.8 330C1512.7 315.7 1454.3 319.3 1396.2 296C1338 272.7 1280 222.3 1221.8 200.7C1163.7 179 1105.3 186 1047.2 200.3C989 214.7 931 236.3 872.8 265.2C814.7 294 756.3 330 698.2 344.5C640 359 582 352 523.8 357.5C465.7 363 407.3 381 349.2 359.3C291 337.7 233 276.3 174.8 265.5C116.7 254.7 58.3 294.3 29.2 314.2L0 334Z"
fill="var(--hover)"
></path>
<path
d="M0 735L29.2 731.5C58.3 728 116.7 721 174.8 739C233 757 291 800 349.2 832.3C407.3 864.7 465.7 886.3 523.8 886.3C582 886.3 640 864.7 698.2 859.3C756.3 854 814.7 865 872.8 870.5C931 876 989 876 1047.2 845.3C1105.3 814.7 1163.7 753.3 1221.8 729.8C1280 706.3 1338 720.7 1396.2 738.7C1454.3 756.7 1512.7 778.3 1570.8 789.2C1629 800 1687 800 1745.2 814.5C1803.3 829 1861.7 858 1890.8 872.5L1920 887L1920 582L1890.8 582C1861.7 582 1803.3 582 1745.2 600C1687 618 1629 654 1570.8 664.8C1512.7 675.7 1454.3 661.3 1396.2 621.8C1338 582.3 1280 517.7 1221.8 526.7C1163.7 535.7 1105.3 618.3 1047.2 668.7C989 719 931 737 872.8 740.7C814.7 744.3 756.3 733.7 698.2 722.8C640 712 582 701 523.8 701C465.7 701 407.3 712 349.2 681.5C291 651 233 579 174.8 562.7C116.7 546.3 58.3 585.7 29.2 605.3L0 625Z"
fill="var(--border)"
></path>
<path
d="M0 897L29.2 895.3C58.3 893.7 116.7 890.3 174.8 908.3C233 926.3 291 965.7 349.2 985.3C407.3 1005 465.7 1005 523.8 1003.3C582 1001.7 640 998.3 698.2 996.7C756.3 995 814.7 995 872.8 986C931 977 989 959 1047.2 939.2C1105.3 919.3 1163.7 897.7 1221.8 894C1280 890.3 1338 904.7 1396.2 911.8C1454.3 919 1512.7 919 1570.8 928C1629 937 1687 955 1745.2 960.3C1803.3 965.7 1861.7 958.3 1890.8 954.7L1920 951L1920 885L1890.8 870.5C1861.7 856 1803.3 827 1745.2 812.5C1687 798 1629 798 1570.8 787.2C1512.7 776.3 1454.3 754.7 1396.2 736.7C1338 718.7 1280 704.3 1221.8 727.8C1163.7 751.3 1105.3 812.7 1047.2 843.3C989 874 931 874 872.8 868.5C814.7 863 756.3 852 698.2 857.3C640 862.7 582 884.3 523.8 884.3C465.7 884.3 407.3 862.7 349.2 830.3C291 798 233 755 174.8 737C116.7 719 58.3 726 29.2 729.5L0 733Z"
fill="var(--hover)"
></path>
<path
d="M0 1081L29.2 1081C58.3 1081 116.7 1081 174.8 1081C233 1081 291 1081 349.2 1081C407.3 1081 465.7 1081 523.8 1081C582 1081 640 1081 698.2 1081C756.3 1081 814.7 1081 872.8 1081C931 1081 989 1081 1047.2 1081C1105.3 1081 1163.7 1081 1221.8 1081C1280 1081 1338 1081 1396.2 1081C1454.3 1081 1512.7 1081 1570.8 1081C1629 1081 1687 1081 1745.2 1081C1803.3 1081 1861.7 1081 1890.8 1081L1920 1081L1920 949L1890.8 952.7C1861.7 956.3 1803.3 963.7 1745.2 958.3C1687 953 1629 935 1570.8 926C1512.7 917 1454.3 917 1396.2 909.8C1338 902.7 1280 888.3 1221.8 892C1163.7 895.7 1105.3 917.3 1047.2 937.2C989 957 931 975 872.8 984C814.7 993 756.3 993 698.2 994.7C640 996.3 582 999.7 523.8 1001.3C465.7 1003 407.3 1003 349.2 983.3C291 963.7 233 924.3 174.8 906.3C116.7 888.3 58.3 891.7 29.2 893.3L0 895Z"
fill="var(--border)"
></path>
</Box>
{props.children} {props.children}
</Flex> </FixedColorSchemeThemeProvider>
</Flex> </Flex>
); );
} }

View File

@@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { import {
EmotionThemeProvider, EmotionThemeProvider,
FixedThemeProvider,
ThemeScopes, ThemeScopes,
themeToCSS, themeToCSS,
useThemeEngineStore useThemeEngineStore
@@ -94,4 +95,25 @@ export function BaseThemeProvider(
); );
} }
export function FixedColorSchemeThemeProvider(
props: PropsWithChildren<
{
injectCssVars?: boolean;
scope?: keyof ThemeScopes;
colorScheme: "light" | "dark";
} & Omit<BoxProps, "variant">
>
) {
const { children, scope = "base", ...restProps } = props;
const theme = useThemeStore((store) =>
props.colorScheme === "dark" ? store.darkTheme : store.lightTheme
);
return (
<FixedThemeProvider {...restProps} scope={scope} theme={theme}>
{children}
</FixedThemeProvider>
);
}
export { EmotionThemeProvider as ScopedThemeProvider }; export { EmotionThemeProvider as ScopedThemeProvider };

View File

@@ -389,7 +389,7 @@ function Signup(props: BaseAuthComponentProps<"signup">) {
<Text <Text
mt={4} mt={4}
variant="subBody" variant="subBody"
sx={{ fontSize: 13, textAlign: "center" }} sx={{ fontSize: "subBody", textAlign: "center" }}
> >
{strings.signupAgreement[0]()}{" "} {strings.signupAgreement[0]()}{" "}
<Link <Link
@@ -843,9 +843,6 @@ export function AuthForm<T extends AuthRoutes>(props: AuthFormProps<T>) {
const formRef = useRef<HTMLFormElement>(null); const formRef = useRef<HTMLFormElement>(null);
const [form, setForm] = useState<AuthFormData[T] | undefined>(); const [form, setForm] = useState<AuthFormData[T] | undefined>();
if (isSubmitting)
return <Loader title={props.loading.title} text={props.loading.subtitle} />;
return ( return (
<Flex <Flex
ref={formRef} ref={formRef}
@@ -876,57 +873,74 @@ export function AuthForm<T extends AuthRoutes>(props: AuthFormProps<T>) {
} }
}} }}
sx={{ sx={{
flex: 1,
flexDirection: "column", flexDirection: "column",
size: "100%",
alignItems: "center", alignItems: "center",
justifyContent: "center", justifyContent: "center"
width: ["95%", "95%", "45%"],
alignSelf: "center"
}} }}
> >
<Text variant={"heading"} sx={{ fontSize: 32, textAlign: "center" }}> <Flex
{title}
</Text>
<Text
variant="body"
mt={2}
mb={35}
sx={{ sx={{
fontSize: "title", flexDirection: "column",
textAlign: "center", width: ["95%", "95%", "550px"],
color: "var(--paragraph-secondary)" background: "var(--background)",
p: 6,
my: 10,
borderRadius: "15px",
border: "1px solid var(--border)",
boxShadow: "0px 0px 10px 0px #00000019"
}} }}
> >
{subtitle} <Text variant={"heading"} sx={{ fontSize: 32 }}>
</Text> {title}
{typeof children === "function" ? children(form) : children} </Text>
{canSkip && ( <Text
<Button variant="body"
type="button" mt={2}
variant="anchor" mb={2}
sx={{ sx={{
mt: 5, fontSize: "title",
color: "paragraph", color: "var(--paragraph-secondary)"
textDecoration: "none",
position: "absolute",
top: 0,
right: 5
}}
onClick={async () => {
const result = await ConfirmDialog.show({
title: strings.offlineMode(),
message: strings.offlineModeDesc(),
negativeButtonText: strings.cancel(),
positiveButtonText: strings.understand()
});
if (result) openURL("/notes/", { authenticated: false });
}} }}
> >
{strings.skipAndGoToApp()} {subtitle}
</Button> </Text>
)} {canSkip && (
<Button
type="button"
variant="secondary"
sx={{
position: "absolute",
top: 4,
right: 4,
bg: "transparent",
border: "2px solid var(--border)",
borderRadius: "default",
px: 2
}}
onClick={async () => {
const result = await ConfirmDialog.show({
title: strings.offlineMode(),
message: strings.offlineModeDesc(),
negativeButtonText: strings.cancel(),
positiveButtonText: strings.understand()
});
if (result) openURL("/notes/", { authenticated: false });
}}
>
{strings.skipAndGoToApp()}
</Button>
)}
{isSubmitting ? (
<Loader title={props.loading.title} text={props.loading.subtitle} />
) : typeof children === "function" ? (
children(form)
) : (
children
)}
<ErrorText error={error} mt={5} /> <ErrorText error={error} mt={5} />
</Flex>
</Flex> </Flex>
); );
} }
@@ -948,8 +962,7 @@ function SubtitleWithAction(props: SubtitleWithActionProps) {
sx={{ sx={{
textDecoration: "underline", textDecoration: "underline",
fontWeight: "bold", fontWeight: "bold",
fontSize: "subtitle", fontSize: "title",
color: "paragraph",
cursor: "pointer" cursor: "pointer"
}} }}
onClick={props.action.onClick} onClick={props.action.onClick}
@@ -969,7 +982,11 @@ export function AuthField(props: FieldProps) {
data-test-id={props["data-test-id"] || props.id} data-test-id={props["data-test-id"] || props.id}
sx={{ mt: 2, width: "100%" }} sx={{ mt: 2, width: "100%" }}
styles={{ styles={{
// label: { fontWeight: "normal" }, label: { fontWeight: "normal", fontSize: "subtitle" },
helpText: {
fontSize: "body",
my: "2px"
},
input: { input: {
p: "12px", p: "12px",
borderRadius: "default", borderRadius: "default",
@@ -992,21 +1009,20 @@ type SubmitButtonProps = {
text: string; text: string;
disabled?: boolean; disabled?: boolean;
loading?: boolean; loading?: boolean;
sx?: Record<string, unknown>;
}; };
export function SubmitButton(props: SubmitButtonProps) { export function SubmitButton(props: SubmitButtonProps) {
return ( return (
<Button <Button
data-test-id="submitButton" data-test-id="submitButton"
type="submit" type="submit"
mt={50}
variant="accent" variant="accent"
px={50}
sx={{ sx={{
borderRadius: 50, alignSelf: "stretch",
alignItems: "center", py: 2,
justifyContent: "center", mt: 3,
alignSelf: "center", fontSize: "subtitle",
display: "flex" ...props.sx
}} }}
disabled={props.disabled} disabled={props.disabled}
> >

View File

@@ -356,16 +356,16 @@ function RecoveryKeyMethod(props: BaseRecoveryComponentProps<"method:key">) {
autoFocus autoFocus
defaultValue={formData?.recoveryKey || ""} defaultValue={formData?.recoveryKey || ""}
/> />
<Flex sx={{ gap: 1 }}> <Flex sx={{ gap: 1, mt: 3 }}>
<Button <Button
variant="secondary" variant="secondary"
type="button" type="button"
sx={{ mt: 50, borderRadius: 50 }} sx={{ flex: 1, py: 2, fontSize: "subtitle" }}
onClick={() => navigate("methods")} onClick={() => navigate("methods")}
> >
{strings.back()} {strings.back()}
</Button> </Button>
<SubmitButton text={strings.startAccountRecovery()} /> <SubmitButton text={strings.startAccountRecovery()} sx={{ flex: 1, mt: 0 }} />
</Flex> </Flex>
<Button <Button
@@ -447,11 +447,11 @@ function NewPassword(props: BaseRecoveryComponentProps<"new">) {
label={strings.confirmPassword()} label={strings.confirmPassword()}
defaultValue={form?.confirmPassword} defaultValue={form?.confirmPassword}
/> />
<Flex sx={{ gap: 1 }}> <Flex sx={{ gap: 1, mt: 3 }}>
<Button <Button
variant="secondary" variant="secondary"
type="button" type="button"
sx={{ mt: 50, borderRadius: 50 }} sx={{ flex: 1, py: 2, fontSize: "subtitle" }}
onClick={() => onClick={() =>
navigate( navigate(
formData?.userResetRequired ? "methods" : "method:key", formData?.userResetRequired ? "methods" : "method:key",
@@ -461,7 +461,7 @@ function NewPassword(props: BaseRecoveryComponentProps<"new">) {
> >
{strings.back()} {strings.back()}
</Button> </Button>
<SubmitButton text={strings.continue()} /> <SubmitButton text={strings.continue()} sx={{ flex: 1, mt: 0 }} />
</Flex> </Flex>
</> </>
)} )}
@@ -539,31 +539,41 @@ export function RecoveryForm<T extends RecoveryRoutes>(
} }
}} }}
sx={{ sx={{
flex: 1,
flexDirection: "column", flexDirection: "column",
size: "100%",
alignItems: "center", alignItems: "center",
justifyContent: "center", justifyContent: "center"
width: ["95%", 420],
alignSelf: "center"
}} }}
> >
<Text variant={"heading"} sx={{ fontSize: 32, textAlign: "center" }}> <Flex
{title}
</Text>
<Text
variant="body"
mt={2}
mb={35}
sx={{ sx={{
fontSize: "title", flexDirection: "column",
textAlign: "center", width: ["95%", "95%", "550px"],
color: "var(--paragraph-secondary)" background: "var(--background)",
p: 6,
my: 10,
borderRadius: "15px",
border: "1px solid var(--border)",
boxShadow: "0px 0px 10px 0px #00000019"
}} }}
> >
{subtitle} <Text variant={"heading"} sx={{ fontSize: 32 }}>
</Text> {title}
{typeof children === "function" ? children(form) : children} </Text>
<ErrorText error={error} sx={{ mt: 2 }} /> <Text
variant="body"
mt={2}
mb={2}
sx={{
fontSize: "title",
color: "var(--paragraph-secondary)"
}}
>
{subtitle}
</Text>
{typeof children === "function" ? children(form) : children}
<ErrorText error={error} sx={{ mt: 2 }} />
</Flex>
</Flex> </Flex>
); );
} }

View File

@@ -21,13 +21,15 @@ import { ThemeProvider } from "@theme-ui/core";
import React, { ForwardedRef, PropsWithChildren, useMemo } from "react"; import React, { ForwardedRef, PropsWithChildren, useMemo } from "react";
import { Box, BoxProps } from "@theme-ui/components"; import { Box, BoxProps } from "@theme-ui/components";
import { useTheme } from "@emotion/react"; import { useTheme } from "@emotion/react";
import { ThemeScopes } from "../theme-engine/types.js"; import { ThemeDefinition, ThemeScopes } from "../theme-engine/types.js";
import { Theme, ThemeFactory } from "../theme/index.js"; import { Theme, ThemeFactory } from "../theme/index.js";
import { import {
getThemeScope,
ScopedThemeProvider, ScopedThemeProvider,
useThemeColors, useThemeColors,
useThemeEngineStore useThemeEngineStore
} from "../theme-engine/index.js"; } from "../theme-engine/index.js";
import { colorsToCSSVariables } from "../theme-engine/utils.js";
export type EmotionThemeProviderProps = { export type EmotionThemeProviderProps = {
scope?: keyof ThemeScopes; scope?: keyof ThemeScopes;
@@ -90,6 +92,65 @@ function _EmotionThemeProvider(
); );
} }
type FixedThemeProviderProps = {
scope: keyof ThemeScopes;
injectCssVars?: boolean;
theme: ThemeDefinition;
} & Omit<BoxProps, "variant" | "ref">;
function _FixedThemeProvider(
props: PropsWithChildren<FixedThemeProviderProps>,
forwardedRef: ForwardedRef<HTMLDivElement>
) {
const {
children,
scope = "base",
injectCssVars = true,
theme,
...restProps
} = props;
const themeScope = getThemeScope(scope, theme);
const { colors } = themeScope;
const themeProperties = useMemo(
() =>
ThemeFactory.construct({
scope: colors,
colorScheme: theme.colorScheme
}),
[colors, theme.colorScheme]
);
return (
<ThemeProvider
theme={{
...themeProperties,
colors: themeProperties.colors
}}
>
<ScopedThemeProvider value={scope}>
{injectCssVars ? (
<Box
{...restProps}
ref={forwardedRef}
css={colorsToCSSVariables(themeProperties.colors)}
>
{children}
</Box>
) : (
children
)}
</ScopedThemeProvider>
</ThemeProvider>
);
}
export const FixedThemeProvider = React.forwardRef<
HTMLDivElement,
FixedThemeProviderProps
>(_FixedThemeProvider);
export const EmotionThemeProvider = React.forwardRef< export const EmotionThemeProvider = React.forwardRef<
HTMLDivElement, HTMLDivElement,
EmotionThemeProviderProps EmotionThemeProviderProps

View File

@@ -69,6 +69,19 @@ export function useThemeColors(scope?: keyof ThemeScopes): ThemeScope {
return currentTheme; return currentTheme;
} }
export function getThemeScope(
scope: keyof ThemeScopes,
theme: ThemeDefinition
): ThemeScope {
const themeScope = theme.scopes[scope] || theme.scopes.base;
const currentTheme = {
colors: buildVariants(scope, theme, themeScope),
isDark: theme.colorScheme === "dark",
scope
};
return currentTheme;
}
export const useCurrentThemeScope = () => useContext(ThemeScopeContext); export const useCurrentThemeScope = () => useContext(ThemeScopeContext);
export const ScopedThemeProvider = ThemeScopeContext.Provider; export const ScopedThemeProvider = ThemeScopeContext.Provider;
export const THEME_COMPATIBILITY_VERSION: ThemeCompatibilityVersion = 1; export const THEME_COMPATIBILITY_VERSION: ThemeCompatibilityVersion = 1;