Files
cosmos-explorer/src/Explorer/Theme/ThemeUtil.tsx
2024-08-15 13:29:57 -07:00

123 lines
3.9 KiB
TypeScript

import {
BrandVariants,
ComponentProps,
FluentProvider,
FluentProviderSlots,
Theme,
createLightTheme,
makeStyles,
mergeClasses,
shorthands,
themeToTokensObject,
webLightTheme,
} from "@fluentui/react-components";
import { Platform, configContext } from "ConfigContext";
import React from "react";
import { appThemeFabricTealBrandRamp } from "../../Platform/Fabric/FabricTheme";
export const LayoutConstants = {
rowHeight: 36,
};
// Our CosmosFluentProvider has the same props as a FluentProvider.
export type CosmosFluentProviderProps = Omit<ComponentProps<FluentProviderSlots, "root">, "dir">;
// PropsWithChildren<{
// className?: string;
// }>;
const useDefaultRootStyles = makeStyles({
fluentProvider: {
// By default, a FluentProvider has a solid background.
// The styles for a FluentProvider are _copied_ to any Portals (https://react.fluentui.dev/?path=/docs/components-portal-portal--default)
// created by components inside the FluentProvider, such as when rendering popup-up menus.
// However, we often stretch our FluentProviders to full height using a `height: 100%` style.
// When we do that, the Portal will also stretch to full height, but it will have a solid background and block out the entire document behind it.
backgroundColor: "transparent",
},
});
const FluentProviderContext = React.createContext({
isInFluentProvider: false,
});
export const CosmosFluentProvider: React.FC<CosmosFluentProviderProps> = ({ children, className, ...props }) => {
// We use a React context to ensure that nested CosmosFluentProviders don't create nested FluentProviders.
// This helps during the transition from Fluent UI 8 to Fluent UI 9.
// As we convert components to Fluent UI 9, if we end up with nested FluentProviders, the inner FluentProvider will be a no-op.
const { isInFluentProvider } = React.useContext(FluentProviderContext);
const styles = useDefaultRootStyles();
if (isInFluentProvider) {
// We're already in a fluent context, don't create another.
console.warn("Nested CosmosFluentProvider detected. This is likely a bug.");
return (
<div className={className} {...props}>
{children}
</div>
);
}
return (
<FluentProviderContext.Provider value={{ isInFluentProvider: true }}>
<FluentProvider
theme={getPlatformTheme(configContext.platform)}
className={mergeClasses(styles.fluentProvider, className)}
{...props}
>
{children}
</FluentProvider>
</FluentProviderContext.Provider>
);
};
// These are the theme colors for Fluent UI 9 React components
const appThemePortalBrandRamp: BrandVariants = {
10: "#020305",
20: "#111723",
30: "#16263D",
40: "#193253",
50: "#1B3F6A",
60: "#1B4C82",
70: "#18599B",
80: "#1267B4",
90: "#3174C2",
100: "#4F82C8",
110: "#6790CF",
120: "#7D9ED5",
130: "#92ACDC",
140: "#A6BAE2",
150: "#BAC9E9",
160: "#CDD8EF",
};
const cosmosThemeElements = {
layoutRowHeight: `${LayoutConstants.rowHeight}px`,
sidebarMinimumWidth: "200px",
sidebarInitialWidth: "300px",
};
export type CosmosTheme = Theme & typeof cosmosThemeElements;
export const tokens = themeToTokensObject({ ...webLightTheme, ...cosmosThemeElements });
export const cosmosShorthands = {
border: () => shorthands.border("1px", "solid", tokens.colorNeutralStroke2),
borderBottom: () => shorthands.borderBottom("1px", "solid", tokens.colorNeutralStroke2),
borderRight: () => shorthands.borderRight("1px", "solid", tokens.colorNeutralStroke2),
borderTop: () => shorthands.borderTop("1px", "solid", tokens.colorNeutralStroke2),
borderLeft: () => shorthands.borderLeft("1px", "solid", tokens.colorNeutralStroke2),
};
export function getPlatformTheme(platform: Platform): CosmosTheme {
const baseTheme =
platform === Platform.Fabric
? createLightTheme(appThemeFabricTealBrandRamp)
: createLightTheme(appThemePortalBrandRamp);
return {
...baseTheme,
...cosmosThemeElements,
};
}