reshaped 3.6.0-canary.3 → 3.6.0-canary.5
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/CHANGELOG.md +3 -0
- package/dist/bundle.css +1 -1
- package/dist/bundle.d.ts +1 -0
- package/dist/bundle.js +5 -5
- package/dist/cjs/cli/theming/index.d.ts +3 -3
- package/dist/cjs/cli/theming/index.js +2 -2
- package/dist/cjs/cli/theming/tailwind.d.ts +2 -3
- package/dist/cjs/themes/_generator/definitions/slate.js +1 -1
- package/dist/cjs/themes/_generator/tokens/color/color.transforms.d.ts +2 -2
- package/dist/cjs/themes/_generator/tokens/color/color.transforms.js +29 -7
- package/dist/cjs/themes/_generator/tokens/color/color.types.d.ts +28 -3
- package/dist/cjs/themes/_generator/tokens/color/utilities/a11y.d.ts +20 -0
- package/dist/cjs/themes/_generator/tokens/color/utilities/a11y.js +64 -0
- package/dist/cjs/themes/_generator/tokens/color/utilities/convert.d.ts +11 -0
- package/dist/cjs/themes/_generator/tokens/color/utilities/convert.js +33 -0
- package/dist/cjs/themes/_generator/tokens/color/utilities/generateColors.d.ts +4 -0
- package/dist/cjs/themes/_generator/tokens/color/utilities/generateColors.js +152 -0
- package/dist/cjs/themes/_generator/tokens/color/utilities/generateMetaColors.d.ts +4 -0
- package/dist/cjs/themes/_generator/tokens/color/utilities/generateMetaColors.js +68 -0
- package/dist/cjs/themes/_generator/tokens/color/utilities/tests/a11y.test.js +38 -0
- package/dist/cjs/themes/_generator/tokens/color/utilities/tests/convert.test.d.ts +1 -0
- package/dist/cjs/themes/_generator/tokens/color/utilities/tests/convert.test.js +48 -0
- package/dist/cjs/themes/_generator/tokens/color/utilities/tests/generateColors.test.d.ts +1 -0
- package/dist/cjs/themes/_generator/tokens/color/utilities/tests/generateColors.test.js +21 -0
- package/dist/{themes/_generator/utilities → cjs/themes/_generator/tokens}/css.d.ts +1 -1
- package/dist/cjs/themes/_generator/tokens/duration/duration.transforms.d.ts +2 -2
- package/dist/cjs/themes/_generator/tokens/duration/duration.transforms.js +2 -2
- package/dist/cjs/themes/_generator/tokens/easing/easing.transforms.d.ts +2 -2
- package/dist/cjs/themes/_generator/tokens/easing/easing.transforms.js +2 -2
- package/dist/cjs/themes/_generator/tokens/font/font.transforms.d.ts +2 -2
- package/dist/cjs/themes/_generator/tokens/font/font.transforms.js +3 -3
- package/dist/cjs/themes/_generator/tokens/fontFamily/fontFamily.transforms.d.ts +2 -2
- package/dist/cjs/themes/_generator/tokens/fontFamily/fontFamily.transforms.js +2 -2
- package/dist/cjs/themes/_generator/tokens/fontWeight/fontWeight.transforms.d.ts +2 -2
- package/dist/cjs/themes/_generator/tokens/fontWeight/fontWeight.transforms.js +2 -2
- package/dist/cjs/themes/_generator/tokens/radius/radius.transforms.d.ts +2 -2
- package/dist/cjs/themes/_generator/tokens/radius/radius.transforms.js +2 -2
- package/dist/cjs/themes/_generator/tokens/shadow/shadow.transforms.d.ts +2 -2
- package/dist/cjs/themes/_generator/tokens/shadow/shadow.transforms.js +4 -4
- package/dist/cjs/themes/_generator/tokens/types.d.ts +19 -17
- package/dist/cjs/themes/_generator/tokens/unit/unit.transforms.d.ts +2 -2
- package/dist/cjs/themes/_generator/tokens/unit/unit.transforms.js +2 -2
- package/dist/cjs/themes/_generator/tokens/unit/utilities/generate.d.ts +5 -0
- package/dist/cjs/themes/_generator/{utilities/generateUnits.js → tokens/unit/utilities/generate.js} +5 -4
- package/dist/cjs/themes/_generator/tokens/viewport/viewport.transforms.d.ts +2 -2
- package/dist/cjs/themes/_generator/tokens/viewport/viewport.transforms.js +2 -2
- package/dist/cjs/themes/_generator/transform.d.ts +3 -2
- package/dist/cjs/themes/_generator/transform.js +39 -11
- package/dist/cjs/themes/_generator/types.d.ts +4 -8
- package/dist/cjs/themes/_generator/utilities/mergeDefinitions.d.ts +1 -3
- package/dist/cjs/themes/_generator/utilities/mergeDefinitions.js +6 -4
- package/dist/cjs/themes/figma/theme.css +1 -1
- package/dist/cjs/themes/fragments/twitter/theme.css +1 -1
- package/dist/cjs/themes/index.d.ts +4 -11
- package/dist/cjs/themes/index.js +2 -5
- package/dist/cjs/themes/reshaped/theme.css +1 -1
- package/dist/cjs/themes/slate/theme.css +1 -1
- package/dist/cjs/types/config.d.ts +11 -7
- package/dist/cli/theming/index.d.ts +3 -3
- package/dist/cli/theming/index.js +2 -2
- package/dist/cli/theming/tailwind.d.ts +2 -3
- package/dist/components/Avatar/Avatar.module.css +1 -1
- package/dist/components/FormControl/FormControl.context.d.ts +1 -1
- package/dist/components/Reshaped/Reshaped.js +2 -2
- package/dist/components/Reshaped/Reshaped.types.d.ts +1 -0
- package/dist/components/Reshaped/tests/Reshaped.stories.d.ts +1 -0
- package/dist/components/Reshaped/tests/Reshaped.stories.js +20 -0
- package/dist/components/Theme/GlobalColorMode.js +6 -11
- package/dist/components/Theme/Theme.types.d.ts +1 -0
- package/dist/components/Theme/index.d.ts +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/tests/ThemesPlayground.d.ts +2 -0
- package/dist/tests/ThemesPlayground.js +90 -0
- package/dist/tests/themes.stories.d.ts +16 -0
- package/dist/{themes/_generator/tests → tests}/themes.stories.js +74 -15
- package/dist/themes/_generator/definitions/slate.js +1 -1
- package/dist/themes/_generator/tokens/color/color.transforms.d.ts +2 -2
- package/dist/themes/_generator/tokens/color/color.transforms.js +29 -7
- package/dist/themes/_generator/tokens/color/color.types.d.ts +28 -3
- package/dist/themes/_generator/tokens/color/utilities/a11y.d.ts +20 -0
- package/dist/themes/_generator/tokens/color/utilities/a11y.js +58 -0
- package/dist/themes/_generator/tokens/color/utilities/convert.d.ts +11 -0
- package/dist/themes/_generator/tokens/color/utilities/convert.js +27 -0
- package/dist/themes/_generator/tokens/color/utilities/generateColors.d.ts +4 -0
- package/dist/themes/_generator/tokens/color/utilities/generateColors.js +150 -0
- package/dist/themes/_generator/tokens/color/utilities/generateMetaColors.d.ts +4 -0
- package/dist/themes/_generator/tokens/color/utilities/generateMetaColors.js +66 -0
- package/dist/{cjs/themes/_generator/utilities → themes/_generator/tokens}/css.d.ts +1 -1
- package/dist/themes/_generator/tokens/duration/duration.transforms.d.ts +2 -2
- package/dist/themes/_generator/tokens/duration/duration.transforms.js +2 -2
- package/dist/themes/_generator/tokens/easing/easing.transforms.d.ts +2 -2
- package/dist/themes/_generator/tokens/easing/easing.transforms.js +2 -2
- package/dist/themes/_generator/tokens/font/font.transforms.d.ts +2 -2
- package/dist/themes/_generator/tokens/font/font.transforms.js +3 -3
- package/dist/themes/_generator/tokens/fontFamily/fontFamily.transforms.d.ts +2 -2
- package/dist/themes/_generator/tokens/fontFamily/fontFamily.transforms.js +2 -2
- package/dist/themes/_generator/tokens/fontWeight/fontWeight.transforms.d.ts +2 -2
- package/dist/themes/_generator/tokens/fontWeight/fontWeight.transforms.js +2 -2
- package/dist/themes/_generator/tokens/radius/radius.transforms.d.ts +2 -2
- package/dist/themes/_generator/tokens/radius/radius.transforms.js +2 -2
- package/dist/themes/_generator/tokens/shadow/shadow.transforms.d.ts +2 -2
- package/dist/themes/_generator/tokens/shadow/shadow.transforms.js +4 -4
- package/dist/themes/_generator/tokens/types.d.ts +19 -17
- package/dist/themes/_generator/tokens/unit/unit.transforms.d.ts +2 -2
- package/dist/themes/_generator/tokens/unit/unit.transforms.js +2 -2
- package/dist/themes/_generator/tokens/unit/utilities/generate.d.ts +5 -0
- package/dist/themes/_generator/{utilities/generateUnits.js → tokens/unit/utilities/generate.js} +4 -5
- package/dist/themes/_generator/tokens/viewport/viewport.transforms.d.ts +2 -2
- package/dist/themes/_generator/tokens/viewport/viewport.transforms.js +2 -2
- package/dist/themes/_generator/transform.d.ts +3 -2
- package/dist/themes/_generator/transform.js +39 -11
- package/dist/themes/_generator/types.d.ts +4 -8
- package/dist/themes/_generator/utilities/mergeDefinitions.d.ts +1 -3
- package/dist/themes/_generator/utilities/mergeDefinitions.js +6 -4
- package/dist/themes/figma/theme.css +1 -1
- package/dist/themes/fragments/twitter/theme.css +1 -1
- package/dist/themes/index.d.ts +4 -11
- package/dist/themes/index.js +1 -4
- package/dist/themes/reshaped/theme.css +1 -1
- package/dist/themes/slate/theme.css +1 -1
- package/dist/types/config.d.ts +11 -7
- package/dist/types/global.d.ts +3 -0
- package/package.json +11 -11
- package/dist/cjs/themes/_generator/utilities/color.d.ts +0 -105
- package/dist/cjs/themes/_generator/utilities/color.js +0 -409
- package/dist/cjs/themes/_generator/utilities/generateBackgroundColors.d.ts +0 -4
- package/dist/cjs/themes/_generator/utilities/generateBackgroundColors.js +0 -59
- package/dist/cjs/themes/_generator/utilities/generateColors.d.ts +0 -11
- package/dist/cjs/themes/_generator/utilities/generateColors.js +0 -178
- package/dist/cjs/themes/_generator/utilities/generateUnits.d.ts +0 -4
- package/dist/cjs/themes/_generator/utilities/mergeDeep.d.ts +0 -5
- package/dist/cjs/themes/_generator/utilities/mergeDeep.js +0 -24
- package/dist/cjs/themes/_generator/utilities/resolveTokenReference.d.ts +0 -3
- package/dist/cjs/themes/_generator/utilities/resolveTokenReference.js +0 -18
- package/dist/cjs/themes/_generator/utilities/tests/color.test.js +0 -81
- package/dist/themes/_generator/tests/themes.stories.d.ts +0 -16
- package/dist/themes/_generator/utilities/color.d.ts +0 -105
- package/dist/themes/_generator/utilities/color.js +0 -377
- package/dist/themes/_generator/utilities/generateBackgroundColors.d.ts +0 -4
- package/dist/themes/_generator/utilities/generateBackgroundColors.js +0 -57
- package/dist/themes/_generator/utilities/generateColors.d.ts +0 -11
- package/dist/themes/_generator/utilities/generateColors.js +0 -176
- package/dist/themes/_generator/utilities/generateUnits.d.ts +0 -4
- package/dist/themes/_generator/utilities/mergeDeep.d.ts +0 -5
- package/dist/themes/_generator/utilities/mergeDeep.js +0 -22
- package/dist/themes/_generator/utilities/resolveTokenReference.d.ts +0 -3
- package/dist/themes/_generator/utilities/resolveTokenReference.js +0 -16
- /package/dist/cjs/themes/_generator/{utilities/tests/color.test.d.ts → tokens/color/utilities/tests/a11y.test.d.ts} +0 -0
- /package/dist/cjs/themes/_generator/{utilities → tokens}/css.js +0 -0
- /package/dist/themes/_generator/{utilities → tokens}/css.js +0 -0
@@ -1,14 +1,18 @@
|
|
1
|
-
import type {
|
1
|
+
import type { PassedThemeDefinition } from "../themes/_generator/tokens/types";
|
2
|
+
import type { HexColor, Hue, OklchColor } from "../themes/_generator/tokens/color/color.types";
|
2
3
|
export type ReshapedConfig = {
|
3
|
-
themes?: Record<string,
|
4
|
-
themeFragments?: Record<string,
|
4
|
+
themes?: Record<string, PassedThemeDefinition>;
|
5
|
+
themeFragments?: Record<string, PassedThemeDefinition>;
|
5
6
|
themeOptions?: {
|
6
|
-
generateOnColorsFor?: string[];
|
7
7
|
colorContrastAlgorithm?: "wcag" | "apca";
|
8
|
+
generateOnColorsFor?: string[];
|
8
9
|
onColorValues?: {
|
9
|
-
[key in
|
10
|
-
hexDark:
|
11
|
-
hexLight:
|
10
|
+
[key in Hue]?: {
|
11
|
+
hexDark: HexColor;
|
12
|
+
hexLight: HexColor;
|
13
|
+
} | {
|
14
|
+
oklchDark: OklchColor;
|
15
|
+
oklchLight: OklchColor;
|
12
16
|
};
|
13
17
|
};
|
14
18
|
};
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import type {
|
1
|
+
import type { PassedThemeDefinition } from "../../themes/_generator/tokens/types";
|
2
2
|
import type * as T from "../../themes/_generator/types";
|
3
|
-
export declare const addThemeFragment: (name: string, definition:
|
4
|
-
export declare const addTheme: (name: string, definition:
|
3
|
+
export declare const addThemeFragment: (name: string, definition: PassedThemeDefinition, options: T.CLIOptions) => void;
|
4
|
+
export declare const addTheme: (name: string, definition: PassedThemeDefinition, options: T.CLIOptions) => void;
|
@@ -17,8 +17,8 @@ const transformDefinition = (name, definition, options) => {
|
|
17
17
|
const themeJsonPath = path.resolve(themeFolderPath, "theme.json");
|
18
18
|
fs.mkdirSync(themeFolderPath, { recursive: true });
|
19
19
|
fs.writeFileSync(themePath, code.variables);
|
20
|
-
fs.writeFileSync(themeJsonPath, JSON.stringify(
|
21
|
-
fs.writeFileSync(twPath, transformToTailwind(
|
20
|
+
fs.writeFileSync(themeJsonPath, JSON.stringify(code.theme));
|
21
|
+
fs.writeFileSync(twPath, transformToTailwind(code.theme));
|
22
22
|
if (code.media)
|
23
23
|
fs.writeFileSync(themeMediaPath, code.media);
|
24
24
|
const logOutput = `Compiled ${chalk.bold(name)} theme${isFragment ? " fragment" : ""}`;
|
@@ -1,3 +1,2 @@
|
|
1
|
-
import type {
|
2
|
-
|
3
|
-
export declare const transformToTailwind: (theme?: T.PartialDeep<FullThemeDefinition>) => string;
|
1
|
+
import type { GeneratedThemeDefinition } from "../../themes/_generator/tokens/types";
|
2
|
+
export declare const transformToTailwind: (theme?: GeneratedThemeDefinition) => string;
|
@@ -1 +1 @@
|
|
1
|
-
.root{align-items:center;aspect-ratio:1;display:flex;font-size:calc(var(--rs-h) / 3);font-weight:
|
1
|
+
.root{align-items:center;aspect-ratio:1;display:flex;font-size:calc(var(--rs-h) / 3);font-weight:var(--rs-font-weight-bold);justify-content:center;line-height:100%}.img{border-radius:inherit;height:100%;object-fit:cover;width:100%}.--variant-faded.--color-neutral{color:var(--rs-color-foreground-neutral)}.--variant-faded.--color-critical{color:var(--rs-color-foreground-critical)}.--variant-faded.--color-positive{color:var(--rs-color-foreground-positive)}.--variant-faded.--color-warning{color:var(--rs-color-foreground-warning)}.--variant-faded.--color-primary{color:var(--rs-color-foreground-primary)}
|
@@ -134,7 +134,7 @@ export declare const useFormControl: () => {
|
|
134
134
|
onBlurCapture?: React.FocusEventHandler<HTMLElement> | undefined;
|
135
135
|
onChange?: React.FormEventHandler<HTMLElement> | undefined;
|
136
136
|
onChangeCapture?: React.FormEventHandler<HTMLElement> | undefined;
|
137
|
-
onBeforeInput?: React.
|
137
|
+
onBeforeInput?: React.InputEventHandler<HTMLElement> | undefined;
|
138
138
|
onBeforeInputCapture?: React.FormEventHandler<HTMLElement> | undefined;
|
139
139
|
onInput?: React.FormEventHandler<HTMLElement> | undefined;
|
140
140
|
onInputCapture?: React.FormEventHandler<HTMLElement> | undefined;
|
@@ -16,11 +16,11 @@ const ReshapedInner = (props) => {
|
|
16
16
|
return (_jsx(SingletonKeyboardModeProvider, { children: _jsx(SingletonEnvironmentContext.Provider, { value: { rtl: rtlState, defaultViewport }, children: _jsx(SingletonHotkeysProvider, { children: _jsx(ToastProvider, { options: toastOptions, children: children }) }) }) }));
|
17
17
|
};
|
18
18
|
const Reshaped = (props) => {
|
19
|
-
const { theme, defaultTheme = "reshaped", defaultColorMode, scoped, className } = props;
|
19
|
+
const { theme, defaultTheme = "reshaped", colorMode, defaultColorMode, scoped, className, } = props;
|
20
20
|
const rootClassNames = classNames(s.root, className);
|
21
21
|
const scopeRef = React.useRef(null);
|
22
22
|
const parentGlobalColorMode = useGlobalColorMode();
|
23
|
-
return (_jsx(GlobalColorMode, { defaultMode: defaultColorMode || parentGlobalColorMode.mode || "light", scopeRef: !!parentGlobalColorMode && scoped ? scopeRef : undefined, children: _jsx(PrivateTheme, { name: theme, defaultName: defaultTheme, className: rootClassNames, scoped: scoped, scopeRef: !!parentGlobalColorMode && scoped ? scopeRef : undefined, children: _jsx(ReshapedInner, { ...props, children: props.children }) }) }));
|
23
|
+
return (_jsx(GlobalColorMode, { defaultMode: defaultColorMode || parentGlobalColorMode.mode || "light", mode: colorMode, scopeRef: !!parentGlobalColorMode && scoped ? scopeRef : undefined, children: _jsx(PrivateTheme, { name: theme, defaultName: defaultTheme, className: rootClassNames, scoped: scoped, scopeRef: !!parentGlobalColorMode && scoped ? scopeRef : undefined, children: _jsx(ReshapedInner, { ...props, children: props.children }) }) }));
|
24
24
|
};
|
25
25
|
Reshaped.displayName = "Reshaped";
|
26
26
|
export default Reshaped;
|
@@ -7,6 +7,7 @@ export type Props = {
|
|
7
7
|
theme?: NonNullable<ThemeProps["name"]>;
|
8
8
|
defaultTheme?: NonNullable<ThemeProps["defaultName"]>;
|
9
9
|
defaultRTL?: boolean;
|
10
|
+
colorMode?: GlobalColorModeProps["mode"];
|
10
11
|
defaultColorMode?: GlobalColorModeProps["defaultMode"];
|
11
12
|
defaultViewport?: G.Viewport;
|
12
13
|
toastOptions?: ToastProviderProps["options"];
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import { useState } from "react";
|
1
2
|
import { expect, userEvent } from "storybook/test";
|
2
3
|
import { useTheme } from "../../Theme/index.js";
|
3
4
|
import Button from "../../Button/index.js";
|
@@ -14,6 +15,25 @@ export const rtl = {
|
|
14
15
|
Hello
|
15
16
|
</Reshaped>),
|
16
17
|
};
|
18
|
+
export const controlledMode = {
|
19
|
+
name: "colorMode, controlled",
|
20
|
+
render: () => {
|
21
|
+
const [mode, setMode] = useState("dark");
|
22
|
+
return (<Reshaped theme="reshaped" colorMode={mode}>
|
23
|
+
<Button onClick={() => {
|
24
|
+
setMode(mode === "dark" ? "light" : "dark");
|
25
|
+
}}>
|
26
|
+
Toggle color mode
|
27
|
+
</Button>
|
28
|
+
</Reshaped>);
|
29
|
+
},
|
30
|
+
play: async ({ canvas }) => {
|
31
|
+
const button = canvas.getAllByRole("button")[0];
|
32
|
+
expect(document.documentElement.getAttribute("data-rs-color-mode")).toEqual("dark");
|
33
|
+
await userEvent.click(button);
|
34
|
+
expect(document.documentElement.getAttribute("data-rs-color-mode")).toEqual("light");
|
35
|
+
},
|
36
|
+
};
|
17
37
|
export const lightMode = {
|
18
38
|
name: "defaultColorMode=light",
|
19
39
|
render: () => <Reshaped theme="reshaped">Hello</Reshaped>,
|
@@ -7,7 +7,7 @@ import { useGlobalColorMode } from "./useTheme.js";
|
|
7
7
|
import { GlobalColorModeContext } from "./Theme.context.js";
|
8
8
|
import { getRootThemeEl } from "./Theme.utilities.js";
|
9
9
|
const GlobalColorMode = (props) => {
|
10
|
-
const { defaultMode, scopeRef, children } = props;
|
10
|
+
const { defaultMode, mode: passedMode, scopeRef, children } = props;
|
11
11
|
const [mode, setMode] = React.useState(defaultMode);
|
12
12
|
const parentGlobalColorMode = useGlobalColorMode();
|
13
13
|
const changeColorMode = React.useCallback((targetMode) => {
|
@@ -15,19 +15,14 @@ const GlobalColorMode = (props) => {
|
|
15
15
|
if (parentGlobalColorMode.mode && !scopeRef) {
|
16
16
|
parentGlobalColorMode.setMode(targetMode);
|
17
17
|
}
|
18
|
-
setMode(
|
19
|
-
if (prevMode !== targetMode) {
|
20
|
-
// Avoid components styles animating when switching to another color mode
|
21
|
-
disableTransitions();
|
22
|
-
}
|
23
|
-
return targetMode;
|
24
|
-
});
|
18
|
+
setMode(targetMode);
|
25
19
|
}, [scopeRef, parentGlobalColorMode]);
|
26
20
|
useIsomorphicLayoutEffect(() => {
|
21
|
+
disableTransitions();
|
27
22
|
onNextFrame(() => {
|
28
23
|
enableTransitions();
|
29
24
|
});
|
30
|
-
}, [mode]);
|
25
|
+
}, [mode, passedMode]);
|
31
26
|
/**
|
32
27
|
* In case color mode was set in html but was not provided to the provider - hydrate the state
|
33
28
|
* This could happen if we're receiving the mode on the client but before React hydration
|
@@ -38,12 +33,12 @@ const GlobalColorMode = (props) => {
|
|
38
33
|
changeColorMode(nextColorMode);
|
39
34
|
}, [changeColorMode, scopeRef]);
|
40
35
|
const value = React.useMemo(() => ({
|
41
|
-
mode,
|
36
|
+
mode: passedMode || mode,
|
42
37
|
setMode: changeColorMode,
|
43
38
|
invertMode: () => {
|
44
39
|
changeColorMode(mode === "light" ? "dark" : "light");
|
45
40
|
},
|
46
|
-
}), [mode, changeColorMode]);
|
41
|
+
}), [mode, passedMode, changeColorMode]);
|
47
42
|
return (_jsx(GlobalColorModeContext.Provider, { value: value, children: children }));
|
48
43
|
};
|
49
44
|
GlobalColorMode.displayName = "GlobalColorMode";
|
@@ -25,6 +25,7 @@ export type PrivateProps = Props & {
|
|
25
25
|
scopeRef?: React.RefObject<HTMLDivElement | null>;
|
26
26
|
};
|
27
27
|
export type GlobalColorModeProps = {
|
28
|
+
mode?: ColorMode;
|
28
29
|
defaultMode: ColorMode;
|
29
30
|
scopeRef?: React.RefObject<HTMLDivElement | null>;
|
30
31
|
children?: React.ReactNode;
|
@@ -1,4 +1,4 @@
|
|
1
1
|
export { default, PrivateTheme } from "./Theme";
|
2
2
|
export { default as GlobalColorMode } from "./GlobalColorMode";
|
3
3
|
export { useTheme } from "./useTheme";
|
4
|
-
export type { Props as ThemeProps, GlobalColorModeProps } from "./Theme.types";
|
4
|
+
export type { Props as ThemeProps, GlobalColorModeProps, ColorMode } from "./Theme.types";
|
package/dist/index.d.ts
CHANGED
@@ -127,6 +127,7 @@ export type { ViewProps, ViewItemProps } from "./components/View";
|
|
127
127
|
*/
|
128
128
|
export { useFormControl } from "./components/FormControl";
|
129
129
|
export { default as Theme, useTheme, type ThemeProps } from "./components/Theme";
|
130
|
+
export type { ColorMode } from "./components/Theme";
|
130
131
|
export { default as useHandlerRef } from "./hooks/useHandlerRef";
|
131
132
|
export { default as useHotkeys } from "./hooks/useHotkeys";
|
132
133
|
export { default as useIsomorphicLayoutEffect } from "./hooks/useIsomorphicLayoutEffect";
|
@@ -0,0 +1,90 @@
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
2
|
+
import View from "../components/View/index.js";
|
3
|
+
import Text from "../components/Text/index.js";
|
4
|
+
import Divider from "../components/Divider/index.js";
|
5
|
+
import Card from "../components/Card/index.js";
|
6
|
+
import Button from "../components/Button/index.js";
|
7
|
+
import Grid from "../components/Grid/index.js";
|
8
|
+
import Avatar from "../components/Avatar/index.js";
|
9
|
+
import Image from "../components/Image/index.js";
|
10
|
+
import IconChevronRight from "../icons/ChevronRight.js";
|
11
|
+
import TextField from "../components/TextField/index.js";
|
12
|
+
import FormControl from "../components/FormControl/index.js";
|
13
|
+
import Link from "../components/Link/index.js";
|
14
|
+
import useToggle from "../hooks/useToggle.js";
|
15
|
+
import Switch from "../components/Switch/index.js";
|
16
|
+
import Badge from "../components/Badge/index.js";
|
17
|
+
import Alert from "../components/Alert/index.js";
|
18
|
+
import IconZap from "../icons/Zap.js";
|
19
|
+
import CheckboxGroup from "../components/CheckboxGroup/index.js";
|
20
|
+
import Checkbox from "../components/Checkbox/index.js";
|
21
|
+
import React from "react";
|
22
|
+
import Table from "../components/Table/index.js";
|
23
|
+
import DropdownMenu from "../components/DropdownMenu/index.js";
|
24
|
+
import IconChevronDown from "../icons/ChevronDown.js";
|
25
|
+
const Color = (props) => {
|
26
|
+
return (_jsx(View, { padding: 2, height: 25, gap: 2, direction: "row", borderRadius: "medium", backgroundColor: props.backgroundColor, borderColor: props.borderColor, attributes: {
|
27
|
+
style: {
|
28
|
+
borderWidth: 4,
|
29
|
+
},
|
30
|
+
}, children: props.children }));
|
31
|
+
};
|
32
|
+
const NeutralContrastTest = () => (_jsxs(View, { gap: 1, children: [_jsxs(View, { direction: "row", gap: 1, children: [_jsx(View, { height: 6, width: 6, backgroundColor: "neutral", borderRadius: "small" }), _jsx(View, { height: 6, width: 6, backgroundColor: "neutral-faded", borderRadius: "small" })] }), _jsxs(View, { direction: "row", gap: 1, children: [_jsx(View, { height: 6, width: 6, backgroundColor: "disabled", borderRadius: "small" }), _jsx(View, { height: 6, width: 6, backgroundColor: "disabled-faded", borderRadius: "small", borderColor: "disabled" })] })] }));
|
33
|
+
const Palette = () => {
|
34
|
+
return (_jsxs(View, { gap: 2, children: [_jsxs(View, { direction: "row", gap: 2, children: [_jsxs(View, { gap: 2, grow: true, children: [_jsx(Color, { backgroundColor: "neutral", borderColor: "neutral", children: _jsx(Text, { weight: "medium", children: "Aa" }) }), _jsx(Color, { backgroundColor: "neutral-faded", borderColor: "neutral-faded", children: _jsx(Text, { weight: "medium", children: "Aa" }) })] }), _jsxs(View, { gap: 2, grow: true, children: [_jsx(Color, { backgroundColor: "primary", borderColor: "primary", children: _jsx(Text, { weight: "medium", children: "Aa" }) }), _jsxs(Color, { backgroundColor: "primary-faded", borderColor: "primary-faded", children: [_jsx(Text, { weight: "medium", color: "primary", children: "Aa" }), _jsx(Text, { weight: "medium", children: "Aa" })] })] }), _jsxs(View, { gap: 2, grow: true, children: [_jsx(Color, { backgroundColor: "critical", borderColor: "critical", children: _jsx(Text, { weight: "medium", children: "Aa" }) }), _jsxs(Color, { backgroundColor: "critical-faded", borderColor: "critical-faded", children: [_jsx(Text, { weight: "medium", color: "critical", children: "Aa" }), _jsx(Text, { weight: "medium", children: "Aa" })] })] }), _jsxs(View, { gap: 2, grow: true, children: [_jsx(Color, { backgroundColor: "positive", borderColor: "positive", children: _jsx(Text, { weight: "medium", children: "Aa" }) }), _jsxs(Color, { backgroundColor: "positive-faded", borderColor: "positive-faded", children: [_jsx(Text, { weight: "medium", color: "positive", children: "Aa" }), _jsx(Text, { weight: "medium", children: "Aa" })] })] }), _jsxs(View, { gap: 2, grow: true, children: [_jsx(Color, { backgroundColor: "warning", borderColor: "warning", children: _jsx(Text, { weight: "medium", children: "Aa" }) }), _jsxs(Color, { backgroundColor: "warning-faded", borderColor: "warning-faded", children: [_jsx(Text, { weight: "medium", color: "warning", children: "Aa" }), _jsx(Text, { weight: "medium", children: "Aa" })] })] }), _jsxs(View, { gap: 2, grow: true, children: [_jsx(Color, { backgroundColor: "disabled", borderColor: "disabled", children: _jsx(Text, { weight: "medium", color: "disabled", children: "Aa" }) }), _jsx(Color, { backgroundColor: "disabled-faded", borderColor: "disabled", children: _jsx(Text, { weight: "medium", color: "disabled", children: "Aa" }) })] })] }), _jsx(Divider, {}), _jsxs(View, { gap: 2, direction: "row", children: [_jsx(View.Item, { grow: true, children: _jsx(Color, { backgroundColor: "elevation-base", borderColor: "neutral-faded", children: _jsxs(View, { gap: 2, children: [_jsx(Text, { weight: "medium", variant: "caption-1", children: "Base" }), _jsx(NeutralContrastTest, {})] }) }) }), _jsx(View.Item, { grow: true, children: _jsx(Color, { backgroundColor: "elevation-raised", borderColor: "neutral-faded", children: _jsxs(View, { gap: 2, children: [_jsx(Text, { weight: "medium", variant: "caption-1", children: "Raised" }), _jsx(NeutralContrastTest, {})] }) }) }), _jsx(View.Item, { grow: true, children: _jsx(Color, { backgroundColor: "elevation-overlay", borderColor: "neutral-faded", children: _jsxs(View, { gap: 2, children: [_jsx(Text, { weight: "medium", variant: "caption-1", children: "Overlay" }), _jsx(NeutralContrastTest, {})] }) }) }), _jsx(View.Item, { grow: true, children: _jsx(Color, { backgroundColor: "page", borderColor: "neutral-faded", children: _jsxs(View, { gap: 2, children: [_jsx(Text, { weight: "medium", variant: "caption-1", children: "Page" }), _jsx(NeutralContrastTest, {})] }) }) }), _jsx(View.Item, { grow: true, children: _jsx(Color, { backgroundColor: "page-faded", borderColor: "neutral-faded", children: _jsxs(View, { gap: 2, children: [_jsx(Text, { weight: "medium", variant: "caption-1", children: "Page faded" }), _jsx(NeutralContrastTest, {})] }) }) }), _jsx(View.Item, { grow: true, children: _jsx(Color, { backgroundColor: "neutral-faded", borderColor: "neutral-faded", children: _jsxs(View, { gap: 2, children: [_jsx(Text, { weight: "medium", variant: "caption-1", children: "Neutral faded" }), _jsx(NeutralContrastTest, {})] }) }) })] })] }));
|
35
|
+
};
|
36
|
+
const ExampleAnalytics = () => (_jsx(Card, { children: _jsxs(View, { gap: 1, children: [_jsxs(View, { gap: 4, direction: "row", align: "center", children: [_jsx(View, { gap: 1, direction: "row", align: "center", grow: true, children: _jsx(Text, { variant: "body-2", weight: "bold", children: "Audience" }) }), _jsx(Button.Aligner, { children: _jsx(Button, { variant: "ghost", color: "primary", size: "small", endIcon: IconChevronRight, children: "View" }) })] }), _jsx(Text, { variant: "featured-2", color: "positive", children: "+76.28%" }), _jsxs(View, { gap: 2, children: [_jsxs(View, { gap: 3, direction: "row", align: "baseline", children: [_jsx(View.Item, { grow: true, children: _jsx(Text, { color: "neutral-faded", children: "Signed up" }) }), _jsx(Text, { color: "neutral-faded", children: "320 users" }), _jsx(Text, { color: "primary", weight: "medium", children: "81%" })] }), _jsxs(View, { gap: 3, direction: "row", align: "baseline", children: [_jsx(View.Item, { grow: true, children: _jsx(Text, { color: "neutral-faded", children: "Onboarded" }) }), _jsx(Text, { color: "neutral-faded", children: "182 users" }), _jsx(Text, { color: "warning", weight: "medium", children: "62%" })] }), _jsxs(View, { gap: 3, direction: "row", align: "baseline", children: [_jsx(View.Item, { grow: true, children: _jsx(Text, { color: "neutral-faded", children: "Purchased" }) }), _jsx(Text, { color: "neutral-faded", children: "120 users" }), _jsx(Text, { color: "critical", weight: "medium", children: "47%" })] })] })] }) }));
|
37
|
+
const ExampleSocial = () => {
|
38
|
+
return (_jsx(Card, { height: "100%", children: _jsxs(View, { gap: 3, children: [_jsxs(View, { direction: "row", gap: 2, align: "center", children: [_jsx(Avatar, { size: 10, color: "neutral" }), _jsxs(View.Item, { grow: true, children: [_jsx(Text, { weight: "medium", children: "Esther Naomi" }), _jsx(Text, { color: "neutral-faded", variant: "caption-1", children: "31 Jan 2037, 10:28" })] }), _jsx(Badge, { variant: "faded", color: "warning", children: "Archived" })] }), _jsx(Text, { color: "neutral-faded", children: "I have been to 27 countries and only 5 of them call this social network X, while others named it Twitter for some reason. Why is this happening?!" }), _jsxs(View, { direction: "row", gap: 2, children: [_jsx(View, { grow: true, aspectRatio: 1, children: _jsx(Image, { src: "", borderRadius: "medium", fallback: true }) }), _jsx(View, { grow: true, aspectRatio: 1, children: _jsx(Image, { src: "", borderRadius: "medium", fallback: true }) }), _jsx(View, { grow: true, aspectRatio: 1, children: _jsx(Image, { src: "", borderRadius: "medium", fallback: true }) })] })] }) }));
|
39
|
+
};
|
40
|
+
const ExampleLogin = () => {
|
41
|
+
const passwordVisibility = useToggle();
|
42
|
+
return (_jsx(Card, { height: "100%", children: _jsxs(View, { gap: 3, children: [_jsx(Text, { variant: "featured-3", children: "Sign in to your account" }), _jsx(Button, { variant: "outline", fullWidth: true, children: "Sign in with Figma" }), _jsxs(View, { gap: 3, direction: "row", align: "center", children: [_jsx(View.Item, { grow: true, children: _jsx(Divider, {}) }), _jsx(Text, { children: "or" }), _jsx(View.Item, { grow: true, children: _jsx(Divider, {}) })] }), _jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Email" }), _jsx(TextField, { name: "email", placeholder: "hello@reshaped.so" })] }), _jsxs(FormControl, { children: [_jsxs(View, { direction: "row", align: "baseline", children: [_jsx(View.Item, { grow: true, children: _jsx(FormControl.Label, { children: "Password" }) }), _jsx(Text, { variant: "caption-1", weight: "medium", children: _jsx(Link, { variant: "plain", onClick: () => { }, children: "Forgot password?" }) })] }), _jsx(TextField, { name: "password", inputAttributes: { type: passwordVisibility.active ? "text" : "password" } })] }), _jsx(Button, { color: "primary", children: "Sign in" })] }) }));
|
43
|
+
};
|
44
|
+
const ExampleSettings = () => (_jsx(Card, { height: "100%", children: _jsxs(View, { gap: 6, height: "100%", children: [_jsx(Text, { variant: "body-1", weight: "medium", children: "Notification settings" }), _jsxs(View, { gap: 3, grow: true, children: [_jsxs(View, { as: "label", direction: "row", align: "center", gap: 2, children: [_jsx(View.Item, { grow: true, children: _jsx(Text, { weight: "medium", children: "Enable email notifications" }) }), _jsx(Switch, { name: "email" })] }), _jsxs(View, { as: "label", direction: "row", align: "center", gap: 2, children: [_jsx(View.Item, { grow: true, children: _jsx(Text, { weight: "medium", children: "Enable Slack notifications" }) }), _jsx(Switch, { name: "email" })] }), _jsxs(View, { as: "label", direction: "row", align: "center", gap: 2, children: [_jsx(View.Item, { grow: true, children: _jsx(Text, { weight: "medium", children: "Enable paper mail notifications" }) }), _jsx(Switch, { name: "email", defaultChecked: true })] }), _jsx(Text, { variant: "caption-1", color: "neutral-faded", children: "Enable all notifications to unsubscribe from our marketing and promotional materials." }), _jsx(View, { grow: true, justify: "end", children: _jsx(Button, { color: "primary", variant: "faded", children: "Save settings" }) })] })] }) }));
|
45
|
+
const ExampleAlert = () => (_jsx(Alert, { icon: IconZap, color: "primary", title: _jsxs(View, { direction: "row", gap: 2, align: "center", children: ["Auto-approve code reviews with AI", _jsx(Badge, { color: "primary", size: "small", children: "New" })] }), actionsSlot: [
|
46
|
+
_jsx(Button, { children: "Keep using" }, 1),
|
47
|
+
_jsx(Button, { variant: "ghost", color: "critical", children: "Opt-out" }, 2),
|
48
|
+
], children: "Try our new GPT-powered code assistant features and never worry about reviewing other developer's pull requests again. Free for the first 5 pull requests." }));
|
49
|
+
const ExampleCheckboxCard = () => {
|
50
|
+
const [value, setValue] = React.useState(["hobby"]);
|
51
|
+
return (_jsx(CheckboxGroup, { name: "1", value: value, onChange: (args) => {
|
52
|
+
setValue(args.value);
|
53
|
+
}, children: _jsxs(View, { gap: 3, children: [_jsx(Card, { as: "label", selected: value.includes("pro"), children: _jsx(View, { direction: "row", gap: 2, align: "center", children: _jsx(Checkbox, { value: "pro", children: "Figma library" }) }) }), _jsx(Card, { as: "label", selected: value.includes("hobby"), children: _jsxs(View, { direction: "row", gap: 2, align: "center", children: [_jsx(View.Item, { grow: true, children: _jsx(Checkbox, { value: "hobby", children: "React library" }) }), _jsx(Badge, { color: "positive", children: "Free" })] }) })] }) }));
|
54
|
+
};
|
55
|
+
const ExampleTable = () => {
|
56
|
+
const rows = [
|
57
|
+
{
|
58
|
+
name: "File downloaded",
|
59
|
+
id: "rshpd_23jb237dh",
|
60
|
+
time: "Jul 4, 12:36",
|
61
|
+
},
|
62
|
+
{
|
63
|
+
name: "User registered",
|
64
|
+
id: "rshpd_27d223jfh",
|
65
|
+
time: "Jul 4, 12:36",
|
66
|
+
},
|
67
|
+
{
|
68
|
+
name: "New version released",
|
69
|
+
id: "rshpd_sjdniu223nj",
|
70
|
+
time: "Jul 4, 12:35",
|
71
|
+
},
|
72
|
+
];
|
73
|
+
const [value, setValue] = React.useState([rows[1].id]);
|
74
|
+
const allSelected = value.length === rows.length;
|
75
|
+
return (_jsx(Card, { padding: 0, children: _jsxs(Table, { children: [_jsxs(Table.Row, { children: [_jsx(Table.Heading, { width: "auto", children: _jsx(Checkbox, { inputAttributes: { "aria-label": "Select all" }, name: "all", checked: allSelected, indeterminate: !!value.length && value.length < rows.length, onChange: () => {
|
76
|
+
setValue(allSelected ? [] : rows.map((row) => row.id));
|
77
|
+
} }) }), _jsx(Table.Heading, { minWidth: "180px", children: "Event type" }), _jsx(Table.Heading, { children: "Event ID" }), _jsx(Table.Heading, { align: "end", minWidth: "120px", children: "Triggered at" }), _jsx(Table.Heading, {})] }), rows.map((row) => (_jsxs(Table.Row, { highlighted: value.includes(row.id), children: [_jsx(Table.Cell, { children: _jsx(Checkbox, { name: "hey", value: row.id, inputAttributes: { "aria-label": "Select the row" }, checked: value.includes(row.id), onChange: (args) => {
|
78
|
+
setValue((prev) => {
|
79
|
+
if (!args.value)
|
80
|
+
return prev;
|
81
|
+
if (args.checked)
|
82
|
+
return [...prev, args.value];
|
83
|
+
return prev.filter((item) => item !== args.value);
|
84
|
+
});
|
85
|
+
} }) }), _jsx(Table.Cell, { children: row.name }), _jsx(Table.Cell, { children: row.id }), _jsx(Table.Cell, { align: "end", children: row.time }), _jsx(Table.Cell, { width: "auto", children: _jsxs(DropdownMenu, { position: "bottom-end", children: [_jsx(DropdownMenu.Trigger, { children: (attributes) => (_jsx(Button.Aligner, { children: _jsx(Button, { attributes: attributes, icon: IconChevronDown, variant: "ghost", size: "small" }) })) }), _jsxs(DropdownMenu.Content, { children: [_jsxs(DropdownMenu.Section, { children: [_jsx(DropdownMenu.Item, { children: "Trigger event" }), _jsx(DropdownMenu.Item, { children: "Log details" })] }), _jsx(DropdownMenu.Section, { children: _jsx(DropdownMenu.Item, { color: "critical", children: "Remote entry" }) })] })] }) })] }, row.id)))] }) }));
|
86
|
+
};
|
87
|
+
const ThemePlayground = () => {
|
88
|
+
return (_jsxs(Grid, { gap: 4, columns: 12, children: [_jsx(Grid.Item, { colSpan: 12, children: _jsx(Palette, {}) }), _jsx(Grid.Item, { colSpan: 6, children: _jsxs(View, { gap: 4, children: [_jsx(ExampleAnalytics, {}), _jsx(ExampleLogin, {}), _jsx(ExampleAlert, {})] }) }), _jsx(Grid.Item, { colSpan: 6, children: _jsxs(View, { gap: 4, children: [_jsx(ExampleSocial, {}), _jsx(ExampleSettings, {}), _jsx(ExampleCheckboxCard, {})] }) }), _jsx(Grid.Item, { colSpan: 12, children: _jsx(ExampleTable, {}) }), _jsx(Grid.Item, { colSpan: 12, children: _jsxs(View, { gap: 2, padding: 4, backgroundColor: "page-faded", borderRadius: "medium", children: [_jsxs(View, { direction: "row", gap: 2, children: [_jsx(Button, { color: "neutral", onClick: () => { }, children: "Neutral" }), _jsx(Button, { color: "primary", onClick: () => { }, children: "Primary" }), _jsx(Button, { color: "critical", onClick: () => { }, children: "Critical" }), _jsx(Button, { color: "positive", onClick: () => { }, children: "Positive" }), _jsx(Button, { color: "primary", disabled: true, onClick: () => { }, children: "Disabled" }), _jsx(Badge, { color: "warning", children: "Warning" })] }), _jsxs(View, { direction: "row", gap: 2, children: [_jsx(Button, { color: "neutral", variant: "faded", onClick: () => { }, children: "Neutral" }), _jsx(Button, { color: "primary", variant: "faded", onClick: () => { }, children: "Primary" }), _jsx(Button, { color: "critical", variant: "faded", onClick: () => { }, children: "Critical" }), _jsx(Button, { color: "positive", variant: "faded", onClick: () => { }, children: "Positive" }), _jsx(Button, { color: "primary", variant: "faded", disabled: true, onClick: () => { }, children: "Disabled" }), _jsx(Badge, { color: "warning", variant: "faded", children: "Warning" })] }), _jsxs(View, { direction: "row", gap: 2, children: [_jsx(Button, { color: "neutral", variant: "outline", onClick: () => { }, children: "Neutral" }), _jsx(Button, { color: "primary", variant: "outline", onClick: () => { }, children: "Primary" }), _jsx(Button, { color: "critical", variant: "outline", onClick: () => { }, children: "Critical" }), _jsx(Button, { color: "positive", variant: "outline", onClick: () => { }, children: "Positive" }), _jsx(Button, { color: "primary", variant: "outline", disabled: true, onClick: () => { }, children: "Disabled" }), _jsx(Badge, { color: "warning", variant: "outline", children: "Warning" })] })] }) })] }));
|
89
|
+
};
|
90
|
+
export default ThemePlayground;
|
@@ -0,0 +1,16 @@
|
|
1
|
+
declare const _default: {
|
2
|
+
title: string;
|
3
|
+
parameters: {
|
4
|
+
iframe: {
|
5
|
+
url: string;
|
6
|
+
};
|
7
|
+
a11y: {
|
8
|
+
disable: boolean;
|
9
|
+
};
|
10
|
+
};
|
11
|
+
};
|
12
|
+
export default _default;
|
13
|
+
export declare const test: () => import("react").JSX.Element;
|
14
|
+
export declare const base: () => import("react").JSX.Element;
|
15
|
+
export declare const generation: () => import("react").JSX.Element;
|
16
|
+
export declare const onColors: () => import("react").JSX.Element;
|
@@ -1,18 +1,21 @@
|
|
1
|
-
import
|
2
|
-
import { Example } from "
|
3
|
-
import View from "
|
4
|
-
import Button from "
|
5
|
-
import Badge from "
|
6
|
-
import Alert from "
|
7
|
-
import Card from "
|
8
|
-
import Avatar from "
|
9
|
-
import DropdownMenu from "
|
10
|
-
import TextField from "
|
11
|
-
import Theme from "
|
12
|
-
import IconZap from "
|
13
|
-
import Link from "
|
14
|
-
import Text from "
|
15
|
-
import { getThemeCSS, generateThemeColors, baseThemeDefinition } from "
|
1
|
+
import { useLayoutEffect, useState } from "react";
|
2
|
+
import { Example } from "../utilities/storybook/index.js";
|
3
|
+
import View from "../components/View/index.js";
|
4
|
+
import Button from "../components/Button/index.js";
|
5
|
+
import Badge from "../components/Badge/index.js";
|
6
|
+
import Alert from "../components/Alert/index.js";
|
7
|
+
import Card from "../components/Card/index.js";
|
8
|
+
import Avatar from "../components/Avatar/index.js";
|
9
|
+
import DropdownMenu from "../components/DropdownMenu/index.js";
|
10
|
+
import TextField from "../components/TextField/index.js";
|
11
|
+
import Theme, { useTheme } from "../components/Theme/index.js";
|
12
|
+
import IconZap from "../icons/Mic.js";
|
13
|
+
import Link from "../components/Link/index.js";
|
14
|
+
import Text from "../components/Text/index.js";
|
15
|
+
import { getThemeCSS, generateThemeColors, baseThemeDefinition } from "../themes/index.js";
|
16
|
+
import ThemePlayground from "./ThemesPlayground.js";
|
17
|
+
import Actionable from "../components/Actionable/index.js";
|
18
|
+
import Switch from "../components/Switch/index.js";
|
16
19
|
export default {
|
17
20
|
title: "Internal/Themes",
|
18
21
|
parameters: {
|
@@ -23,6 +26,62 @@ export default {
|
|
23
26
|
},
|
24
27
|
},
|
25
28
|
};
|
29
|
+
const colors = [
|
30
|
+
"#2563eb",
|
31
|
+
"#4f39f6",
|
32
|
+
"#4a8200",
|
33
|
+
"#0891b2",
|
34
|
+
"#34d399",
|
35
|
+
"#fe9a00",
|
36
|
+
"#be185d",
|
37
|
+
"#ff2056",
|
38
|
+
"#000000",
|
39
|
+
];
|
40
|
+
export const test = () => {
|
41
|
+
const { colorMode } = useTheme();
|
42
|
+
const [activeColor, setColor] = useState(colors[0]);
|
43
|
+
const [theme, setTheme] = useState("");
|
44
|
+
const [algo, setAlgo] = useState("wcag");
|
45
|
+
useLayoutEffect(() => {
|
46
|
+
setTheme(getThemeCSS("test", {
|
47
|
+
color: generateThemeColors({
|
48
|
+
primary: activeColor === colors[0] ? undefined : activeColor,
|
49
|
+
}),
|
50
|
+
}, {
|
51
|
+
colorContrastAlgorithm: algo,
|
52
|
+
}));
|
53
|
+
}, [activeColor, algo]);
|
54
|
+
return (<>
|
55
|
+
<style>{theme}</style>
|
56
|
+
<Theme name="test">
|
57
|
+
<View gap={4}>
|
58
|
+
<View direction="row" align="center" gap={4}>
|
59
|
+
{colors.map((color) => {
|
60
|
+
const hex = colorMode === "dark" && color === "#000000" ? "#ffffff" : color;
|
61
|
+
return (<Actionable key={color} onClick={() => setColor(color)} borderRadius="inherit">
|
62
|
+
<View width={5} height={5} borderRadius="circular" attributes={{
|
63
|
+
style: {
|
64
|
+
transition: `box-shadow var(--rs-duration-fast) var(--rs-easing-standard)`,
|
65
|
+
background: hex,
|
66
|
+
boxShadow: color === activeColor
|
67
|
+
? `0 0 0 3px var(--rs-color-background-elevation-base), 0 0 0 5px ${hex}`
|
68
|
+
: undefined,
|
69
|
+
},
|
70
|
+
}}/>
|
71
|
+
</Actionable>);
|
72
|
+
})}
|
73
|
+
<View.Item gapBefore="auto">
|
74
|
+
<Switch name="algo" onChange={(args) => setAlgo(args.checked ? "apca" : "wcag")}>
|
75
|
+
Use APCA
|
76
|
+
</Switch>
|
77
|
+
</View.Item>
|
78
|
+
</View>
|
79
|
+
|
80
|
+
<ThemePlayground />
|
81
|
+
</View>
|
82
|
+
</Theme>
|
83
|
+
</>);
|
84
|
+
};
|
26
85
|
const css = getThemeCSS("green", {
|
27
86
|
color: {
|
28
87
|
backgroundPrimary: { hex: "#1abc9c", hexDark: "#00E5C4" },
|
@@ -1,18 +1,40 @@
|
|
1
|
-
const
|
2
|
-
const
|
3
|
-
|
1
|
+
const transformTokenForMode = (args) => {
|
2
|
+
const { hex, oklch } = args;
|
3
|
+
if (oklch) {
|
4
|
+
const components = `${Number(oklch.l.toFixed(4))} ${Number(oklch.c.toFixed(4))} ${Number(oklch.h?.toFixed(4) || 0)}`;
|
5
|
+
const alphaSuffix = oklch?.alpha === undefined ? "" : ` / ${Number(oklch.alpha.toFixed(4))}`;
|
6
|
+
return `oklch(${components}${alphaSuffix})`;
|
7
|
+
}
|
8
|
+
if (hex)
|
9
|
+
return hex;
|
10
|
+
throw new Error(`[Reshaped] ${JSON.stringify(args)} is missing a color value`);
|
11
|
+
};
|
12
|
+
const transformToken = (name, token) => {
|
13
|
+
const { hex, hexDark, oklch, oklchDark } = token;
|
14
|
+
// Apply color to both modes if dark mode is not available
|
15
|
+
const hasDark = !!hexDark || !!oklchDark;
|
16
|
+
const value = transformTokenForMode({ oklch, hex });
|
17
|
+
const darkValue = hasDark ? transformTokenForMode({ oklch: oklchDark, hex: hexDark }) : undefined;
|
18
|
+
const separateModes = hasDark && value !== darkValue;
|
19
|
+
const defaultMode = separateModes ? "light" : undefined;
|
4
20
|
const result = [
|
5
|
-
{
|
21
|
+
{
|
22
|
+
name,
|
23
|
+
tokenType: "color",
|
24
|
+
type: "variable",
|
25
|
+
value,
|
26
|
+
mode: defaultMode,
|
27
|
+
},
|
6
28
|
];
|
7
|
-
if (
|
29
|
+
if (darkValue && separateModes) {
|
8
30
|
result.push({
|
9
31
|
name,
|
10
32
|
tokenType: "color",
|
11
33
|
type: "variable",
|
12
|
-
value:
|
34
|
+
value: darkValue,
|
13
35
|
mode: "dark",
|
14
36
|
});
|
15
37
|
}
|
16
38
|
return result;
|
17
39
|
};
|
18
|
-
export default
|
40
|
+
export default transformToken;
|
@@ -1,7 +1,32 @@
|
|
1
|
+
import type { Oklch } from "culori/fn";
|
2
|
+
export type Hue = "primary" | "positive" | "critical" | "warning" | "neutral" | "brand";
|
1
3
|
export type Name = "foregroundNeutral" | "foregroundNeutralFaded" | "foregroundDisabled" | "foregroundPrimary" | "foregroundCritical" | "foregroundWarning" | "foregroundPositive" | "borderNeutral" | "borderNeutralFaded" | "borderDisabled" | "borderPrimary" | "borderPrimaryFaded" | "borderCritical" | "borderCriticalFaded" | "borderWarning" | "borderWarningFaded" | "borderPositive" | "borderPositiveFaded" | "backgroundNeutral" | "backgroundNeutralFaded" | "backgroundDisabled" | "backgroundDisabledFaded" | "backgroundPrimary" | "backgroundPrimaryFaded" | "backgroundCritical" | "backgroundCriticalFaded" | "backgroundWarning" | "backgroundWarningFaded" | "backgroundPositive" | "backgroundPositiveFaded" | "backgroundPage" | "backgroundPageFaded" | "backgroundElevationBase" | "backgroundElevationRaised" | "backgroundElevationOverlay" | "brand" | "white" | "black";
|
2
4
|
export type GeneratedOnName = "onBackgroundNeutral" | "onBackgroundPrimary" | "onBackgroundPositive" | "onBackgroundWarning" | "onBackgroundCritical";
|
3
5
|
export type GeneratedRGBName = "rgbBackgroundNeutral" | "rgbBackgroundNeutralFaded" | "rgbBackgroundDisabled" | "rgbBackgroundDisabledFaded" | "rgbBackgroundPrimary" | "rgbBackgroundPrimaryFaded" | "rgbBackgroundCritical" | "rgbBackgroundCriticalFaded" | "rgbBackgroundWarning" | "rgbBackgroundWarningFaded" | "rgbBackgroundPositive" | "rgbBackgroundPositiveFaded" | "rgbBackgroundPage" | "rgbBackgroundPageFaded" | "rgbBackgroundElevationBase" | "rgbBackgroundElevationRaised" | "rgbBackgroundElevationOverlay";
|
4
|
-
export type
|
5
|
-
|
6
|
-
|
6
|
+
export type RgbColor = {
|
7
|
+
r: number;
|
8
|
+
g: number;
|
9
|
+
b: number;
|
10
|
+
};
|
11
|
+
export type OklchColor = Omit<Oklch, "mode">;
|
12
|
+
export type HexColor = string;
|
13
|
+
export type ColorValue = HexColor | Token;
|
14
|
+
export type OklchOnlyToken = {
|
15
|
+
oklch: OklchColor;
|
16
|
+
oklchDark?: OklchColor;
|
17
|
+
};
|
18
|
+
export type OklchToken = OklchOnlyToken & {
|
19
|
+
hex?: never;
|
20
|
+
hexDark?: never;
|
21
|
+
};
|
22
|
+
export type HexToken = {
|
23
|
+
hex: HexColor;
|
24
|
+
hexDark?: HexColor;
|
25
|
+
oklch?: never;
|
26
|
+
oklchDark?: never;
|
27
|
+
};
|
28
|
+
export type Token = OklchToken | HexToken;
|
29
|
+
export type InternalToken = {
|
30
|
+
oklch: Oklch;
|
31
|
+
oklchDark?: Oklch;
|
7
32
|
};
|
@@ -0,0 +1,20 @@
|
|
1
|
+
import { type Oklch } from "culori/fn";
|
2
|
+
export declare const getOnColorWCAG: (args: {
|
3
|
+
bgColor: Oklch;
|
4
|
+
lightColor: Oklch;
|
5
|
+
darkColor: Oklch;
|
6
|
+
}) => Oklch;
|
7
|
+
export declare const getOnColorAPCA: (args: {
|
8
|
+
bgColor: Oklch;
|
9
|
+
lightColor: Oklch;
|
10
|
+
darkColor: Oklch;
|
11
|
+
}) => Oklch;
|
12
|
+
/**
|
13
|
+
* General
|
14
|
+
*/
|
15
|
+
export declare const getOnColor: (args: {
|
16
|
+
bgColor: Oklch;
|
17
|
+
lightColor: Oklch;
|
18
|
+
darkColor: Oklch;
|
19
|
+
algorithm?: "wcag" | "apca";
|
20
|
+
}) => Oklch;
|
@@ -0,0 +1,58 @@
|
|
1
|
+
import { oklchToRgb } from "./convert.js";
|
2
|
+
/**
|
3
|
+
* WCAG
|
4
|
+
*/
|
5
|
+
const RED = 0.2126;
|
6
|
+
const GREEN = 0.7152;
|
7
|
+
const BLUE = 0.0722;
|
8
|
+
const GAMMA = 2.4;
|
9
|
+
function luminanceWCAG(r, g, b) {
|
10
|
+
const a = [r, g, b].map((v) => {
|
11
|
+
return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, GAMMA);
|
12
|
+
});
|
13
|
+
return a[0] * RED + a[1] * GREEN + a[2] * BLUE;
|
14
|
+
}
|
15
|
+
function contrastWCAG(rgb1, rgb2) {
|
16
|
+
const lum1 = luminanceWCAG(...rgb1);
|
17
|
+
const lum2 = luminanceWCAG(...rgb2);
|
18
|
+
const brightest = Math.max(lum1, lum2);
|
19
|
+
const darkest = Math.min(lum1, lum2);
|
20
|
+
return (brightest + 0.05) / (darkest + 0.05);
|
21
|
+
}
|
22
|
+
export const getOnColorWCAG = (args) => {
|
23
|
+
const { bgColor, lightColor, darkColor } = args;
|
24
|
+
const bgRgb = oklchToRgb(bgColor);
|
25
|
+
const lightRgb = oklchToRgb(lightColor);
|
26
|
+
return contrastWCAG([bgRgb.r, bgRgb.g, bgRgb.b], [lightRgb.r, lightRgb.g, lightRgb.b]) > 4.5
|
27
|
+
? lightColor
|
28
|
+
: darkColor;
|
29
|
+
};
|
30
|
+
/**
|
31
|
+
* APCA
|
32
|
+
*/
|
33
|
+
function luminanceAPCA(oklch) {
|
34
|
+
const { r, g, b } = oklchToRgb(oklch);
|
35
|
+
return (0.2126 * Math.pow(r / 255, 2.2) +
|
36
|
+
0.7152 * Math.pow(g / 255, 2.2) +
|
37
|
+
0.0722 * Math.pow(b / 255, 2.2));
|
38
|
+
}
|
39
|
+
export const getOnColorAPCA = (args) => {
|
40
|
+
const { bgColor, lightColor, darkColor } = args;
|
41
|
+
const backgroundLuminance = luminanceAPCA(bgColor);
|
42
|
+
const lightLuminance = luminanceAPCA(lightColor);
|
43
|
+
const darkLuminance = luminanceAPCA(darkColor);
|
44
|
+
const contrastWithLight = Math.abs(lightLuminance - backgroundLuminance);
|
45
|
+
const contrastWithDark = Math.abs(darkLuminance - backgroundLuminance);
|
46
|
+
return contrastWithLight > contrastWithDark ? lightColor : darkColor;
|
47
|
+
};
|
48
|
+
/**
|
49
|
+
* General
|
50
|
+
*/
|
51
|
+
export const getOnColor = (args) => {
|
52
|
+
if (args.algorithm === "apca") {
|
53
|
+
return getOnColorAPCA(args);
|
54
|
+
}
|
55
|
+
else {
|
56
|
+
return getOnColorWCAG(args);
|
57
|
+
}
|
58
|
+
};
|