chore: wds color algo improve (#22442)
## Description - TokensAccessor improvement. The dependence on default values has been removed, now what we pass to the input is what we get at the output. - The themes are placed in a separate class and added tagging for it. - The theme settings in storybook have been moved to the panel, color input from the keyboard is now available - The Chroma is controlled only for non achromatic colors. ## Type of change > Please delete options that are not relevant. - Chore (housekeeping or task changes that don't impact user perception) ## How Has This Been Tested? - Manual ## Checklist: ### Dev activity - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] PR is being merged under a feature flag --------- Co-authored-by: Valera Melnikov <melnikov.vv@greendatasoft.ru>
This commit is contained in:
parent
7425acaa1b
commit
8635c251f5
|
|
@ -1,7 +1,5 @@
|
|||
export { ThemeProvider } from "./components/ThemeProvider";
|
||||
export { TokensAccessor, ColorsAccessor } from "./utils";
|
||||
export * from "./utils";
|
||||
|
||||
export { default as defaultTokens } from "./tokens/defaultTokens.json";
|
||||
export { default as themeTokens } from "./tokens/themeTokens.json";
|
||||
|
||||
export type { ThemeTokens } from "./utils";
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
{
|
||||
"seedColor": "#553de9",
|
||||
"focusColor": "#2a82ea",
|
||||
"rootUnit": 4,
|
||||
"colorScheme": "light",
|
||||
"colorMode": "light",
|
||||
"borderRadius": {
|
||||
"1": "0px"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,23 +1,26 @@
|
|||
import { contrast, lighten, setLch } from "../colorUtils";
|
||||
import type { ColorTypes } from "colorjs.io/types/src/color";
|
||||
import { ColorsAccessor } from "../ColorsAccessor";
|
||||
|
||||
export class DarkScheme {
|
||||
import type { ColorTypes } from "colorjs.io/types/src/color";
|
||||
import type { ColorModeTheme } from "./types";
|
||||
|
||||
export class DarkModeTheme implements ColorModeTheme {
|
||||
private readonly seedColor: string;
|
||||
private readonly seedLightness: number;
|
||||
private readonly seedChroma: number;
|
||||
private readonly seedHue: number;
|
||||
private readonly seedIsVeryDark: boolean;
|
||||
private readonly seedIsAchromatic: boolean;
|
||||
|
||||
constructor(private color: ColorTypes) {
|
||||
const { chroma, hex, hue, isVeryDark, lightness } = new ColorsAccessor(
|
||||
color,
|
||||
);
|
||||
const { chroma, hex, hue, isAchromatic, isVeryDark, lightness } =
|
||||
new ColorsAccessor(color);
|
||||
this.seedColor = hex;
|
||||
this.seedLightness = lightness;
|
||||
this.seedChroma = chroma;
|
||||
this.seedHue = hue;
|
||||
this.seedIsVeryDark = isVeryDark;
|
||||
this.seedIsAchromatic = isAchromatic;
|
||||
}
|
||||
|
||||
public getColors = () => {
|
||||
|
|
@ -44,6 +47,13 @@ export class DarkScheme {
|
|||
* Background colors
|
||||
*/
|
||||
private get bg() {
|
||||
if (this.seedIsAchromatic) {
|
||||
return setLch(this.seedColor, {
|
||||
l: 0.15,
|
||||
c: 0,
|
||||
});
|
||||
}
|
||||
|
||||
return setLch(this.seedColor, {
|
||||
l: 0.15,
|
||||
c: 0.064,
|
||||
|
|
@ -78,7 +88,7 @@ export class DarkScheme {
|
|||
});
|
||||
}
|
||||
|
||||
if (this.seedChroma > 0.112) {
|
||||
if (this.seedChroma > 0.112 && !this.seedIsAchromatic) {
|
||||
currentColor = setLch(currentColor, {
|
||||
c: 0.112,
|
||||
});
|
||||
|
|
@ -99,6 +109,13 @@ export class DarkScheme {
|
|||
* Foreground colors
|
||||
*/
|
||||
private get fg() {
|
||||
if (this.seedIsAchromatic) {
|
||||
return setLch(this.seedColor, {
|
||||
l: 0.965,
|
||||
c: 0,
|
||||
});
|
||||
}
|
||||
|
||||
return setLch(this.seedColor, {
|
||||
l: 0.965,
|
||||
c: 0.024,
|
||||
|
|
@ -107,6 +124,13 @@ export class DarkScheme {
|
|||
|
||||
private get fgAccent() {
|
||||
if (contrast(this.seedColor, this.bg) <= 60) {
|
||||
if (this.seedIsAchromatic) {
|
||||
return setLch(this.seedColor, {
|
||||
l: 0.79,
|
||||
c: 0,
|
||||
});
|
||||
}
|
||||
|
||||
return setLch(this.seedColor, {
|
||||
l: 0.79,
|
||||
c: 0.136,
|
||||
|
|
@ -118,12 +142,26 @@ export class DarkScheme {
|
|||
|
||||
private get fgOnAccent() {
|
||||
if (contrast(this.seedColor, this.bg) <= 40) {
|
||||
if (this.seedIsAchromatic) {
|
||||
return setLch(this.seedColor, {
|
||||
l: 0.985,
|
||||
c: 0,
|
||||
});
|
||||
}
|
||||
|
||||
return setLch(this.seedColor, {
|
||||
l: 0.985,
|
||||
c: 0.016,
|
||||
});
|
||||
}
|
||||
|
||||
if (this.seedIsAchromatic) {
|
||||
return setLch(this.seedColor, {
|
||||
l: 0.15,
|
||||
c: 0,
|
||||
});
|
||||
}
|
||||
|
||||
return setLch(this.seedColor, {
|
||||
l: 0.15,
|
||||
c: 0.064,
|
||||
|
|
@ -132,6 +170,13 @@ export class DarkScheme {
|
|||
|
||||
private get bdAccent() {
|
||||
if (contrast(this.seedColor, this.bg) <= 15) {
|
||||
if (this.seedIsAchromatic) {
|
||||
return setLch(this.seedColor, {
|
||||
l: 0.985,
|
||||
c: 0,
|
||||
});
|
||||
}
|
||||
|
||||
return setLch(this.seedColor, {
|
||||
l: 0.985,
|
||||
c: 0.016,
|
||||
|
|
@ -142,12 +187,19 @@ export class DarkScheme {
|
|||
}
|
||||
|
||||
private get bdNeutral() {
|
||||
if (contrast(this.seedColor, this.bg) >= -25) {
|
||||
if (contrast(this.seedColor, this.bg) >= -25 && !this.seedIsAchromatic) {
|
||||
return setLch(this.seedColor, {
|
||||
c: 0.008,
|
||||
});
|
||||
}
|
||||
|
||||
if (this.seedIsAchromatic) {
|
||||
return setLch(this.seedColor, {
|
||||
l: 0.15,
|
||||
c: 0,
|
||||
});
|
||||
}
|
||||
|
||||
return setLch(this.seedColor, {
|
||||
l: 0.15,
|
||||
c: 0.064,
|
||||
|
|
@ -1,19 +1,26 @@
|
|||
import { contrast, lighten, setLch } from "../colorUtils";
|
||||
import type { ColorTypes } from "colorjs.io/types/src/color";
|
||||
import { ColorsAccessor } from "../ColorsAccessor";
|
||||
|
||||
export class LightScheme {
|
||||
import type { ColorTypes } from "colorjs.io/types/src/color";
|
||||
import type { ColorModeTheme } from "./types";
|
||||
|
||||
export class LightModeTheme implements ColorModeTheme {
|
||||
private readonly seedColor: string;
|
||||
private readonly seedLightness: number;
|
||||
private readonly seedChroma: number;
|
||||
private readonly seedHue: number;
|
||||
private readonly seedIsAchromatic: boolean;
|
||||
private readonly seedIsCold: boolean;
|
||||
|
||||
constructor(private color: ColorTypes) {
|
||||
const { chroma, hex, hue, lightness } = new ColorsAccessor(color);
|
||||
const { chroma, hex, hue, isAchromatic, isCold, lightness } =
|
||||
new ColorsAccessor(color);
|
||||
this.seedColor = hex;
|
||||
this.seedLightness = lightness;
|
||||
this.seedChroma = chroma;
|
||||
this.seedHue = hue;
|
||||
this.seedIsAchromatic = isAchromatic;
|
||||
this.seedIsCold = isCold;
|
||||
}
|
||||
|
||||
public getColors = () => {
|
||||
|
|
@ -40,9 +47,16 @@ export class LightScheme {
|
|||
* Background colors
|
||||
*/
|
||||
private get bg() {
|
||||
if (this.seedIsAchromatic) {
|
||||
return setLch(this.seedColor, {
|
||||
l: 0.985,
|
||||
c: 0,
|
||||
});
|
||||
}
|
||||
|
||||
return setLch(this.seedColor, {
|
||||
l: 0.985,
|
||||
c: 0.016,
|
||||
c: this.seedIsCold ? 0.006 : 0.004,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -74,7 +88,7 @@ export class LightScheme {
|
|||
});
|
||||
}
|
||||
|
||||
if (this.seedChroma > 0.16) {
|
||||
if (this.seedChroma > 0.16 && !this.seedIsAchromatic) {
|
||||
currentColor = setLch(currentColor, {
|
||||
c: 0.16,
|
||||
});
|
||||
|
|
@ -95,6 +109,13 @@ export class LightScheme {
|
|||
* Foreground colors
|
||||
*/
|
||||
private get fg() {
|
||||
if (this.seedIsAchromatic) {
|
||||
return setLch(this.seedColor, {
|
||||
l: 0.12,
|
||||
c: 0,
|
||||
});
|
||||
}
|
||||
|
||||
return setLch(this.seedColor, {
|
||||
l: 0.12,
|
||||
c: 0.032,
|
||||
|
|
@ -103,6 +124,13 @@ export class LightScheme {
|
|||
|
||||
private get fgAccent() {
|
||||
if (contrast(this.seedColor, this.bg) >= -60) {
|
||||
if (this.seedIsAchromatic) {
|
||||
return setLch(this.seedColor, {
|
||||
l: 0.25,
|
||||
c: 0,
|
||||
});
|
||||
}
|
||||
|
||||
return setLch(this.seedColor, {
|
||||
l: 0.25,
|
||||
c: 0.064,
|
||||
|
|
@ -114,12 +142,26 @@ export class LightScheme {
|
|||
|
||||
private get fgOnAccent() {
|
||||
if (contrast(this.seedColor, this.bg) <= -60) {
|
||||
if (this.seedIsAchromatic) {
|
||||
return setLch(this.seedColor, {
|
||||
l: 0.985,
|
||||
c: 0,
|
||||
});
|
||||
}
|
||||
|
||||
return setLch(this.seedColor, {
|
||||
l: 0.985,
|
||||
c: 0.016,
|
||||
});
|
||||
}
|
||||
|
||||
if (this.seedIsAchromatic) {
|
||||
return setLch(this.seedColor, {
|
||||
l: 0.15,
|
||||
c: 0,
|
||||
});
|
||||
}
|
||||
|
||||
return setLch(this.seedColor, {
|
||||
l: 0.15,
|
||||
c: 0.064,
|
||||
|
|
@ -131,6 +173,13 @@ export class LightScheme {
|
|||
*/
|
||||
private get bdAccent() {
|
||||
if (contrast(this.seedColor, this.bg) >= -25) {
|
||||
if (this.seedIsAchromatic) {
|
||||
return setLch(this.seedColor, {
|
||||
l: 0.15,
|
||||
c: 0,
|
||||
});
|
||||
}
|
||||
|
||||
return setLch(this.seedColor, {
|
||||
l: 0.15,
|
||||
c: 0.064,
|
||||
|
|
@ -141,12 +190,19 @@ export class LightScheme {
|
|||
}
|
||||
|
||||
private get bdNeutral() {
|
||||
if (contrast(this.seedColor, this.bg) <= -25) {
|
||||
if (contrast(this.seedColor, this.bg) <= -25 && !this.seedIsAchromatic) {
|
||||
return setLch(this.seedColor, {
|
||||
c: 0.016,
|
||||
});
|
||||
}
|
||||
|
||||
if (this.seedIsAchromatic) {
|
||||
return setLch(this.seedColor, {
|
||||
l: 0.15,
|
||||
c: 0,
|
||||
});
|
||||
}
|
||||
|
||||
return setLch(this.seedColor, {
|
||||
l: 0.15,
|
||||
c: 0.064,
|
||||
|
|
@ -1,54 +1,70 @@
|
|||
import type { ColorTypes } from "colorjs.io/types/src/color";
|
||||
import { defaultTokens } from "../../";
|
||||
import range from "lodash/range";
|
||||
import kebabCase from "lodash/kebabCase";
|
||||
import { LightScheme } from "./LightScheme";
|
||||
import { DarkScheme } from "./DarkScheme";
|
||||
import { DarkModeTheme } from "./DarkModeTheme";
|
||||
import { LightModeTheme } from "./LightModeTheme";
|
||||
|
||||
type TokenType =
|
||||
| "sizing"
|
||||
| "color"
|
||||
| "spacing"
|
||||
| "borderRadius"
|
||||
| "boxShadow"
|
||||
| "borderWidth"
|
||||
| "opacity";
|
||||
|
||||
type ColorScheme = "light" | "dark";
|
||||
|
||||
type Token = {
|
||||
value: string | number;
|
||||
type: TokenType;
|
||||
};
|
||||
|
||||
export type ThemeTokens = {
|
||||
[key in TokenType]: { [key: string]: Token };
|
||||
};
|
||||
|
||||
type TokenObj = { [key: string]: string | number };
|
||||
import type {
|
||||
ColorMode,
|
||||
TokenObj,
|
||||
TokenSource,
|
||||
ThemeTokens,
|
||||
TokenType,
|
||||
ColorTypes,
|
||||
} from "./types";
|
||||
|
||||
export class TokensAccessor {
|
||||
constructor(
|
||||
private color: ColorTypes = defaultTokens.seedColor,
|
||||
private colorScheme: ColorScheme = defaultTokens.colorScheme as ColorScheme,
|
||||
private rootUnit: number = defaultTokens.rootUnit,
|
||||
private borderRadius: TokenObj = defaultTokens.borderRadius,
|
||||
private boxShadow: TokenObj = defaultTokens.boxShadow,
|
||||
private borderWidth: TokenObj = defaultTokens.borderWidth,
|
||||
private opacity: TokenObj = defaultTokens.opacity,
|
||||
) {}
|
||||
private seedColor?: ColorTypes;
|
||||
private colorMode?: ColorMode;
|
||||
private borderRadius?: TokenObj;
|
||||
private rootUnit?: number;
|
||||
private boxShadow?: TokenObj;
|
||||
private borderWidth?: TokenObj;
|
||||
private opacity?: TokenObj;
|
||||
|
||||
constructor({
|
||||
borderRadius,
|
||||
borderWidth,
|
||||
boxShadow,
|
||||
colorMode,
|
||||
opacity,
|
||||
rootUnit,
|
||||
seedColor,
|
||||
}: TokenSource) {
|
||||
this.seedColor = seedColor;
|
||||
this.colorMode = colorMode;
|
||||
this.rootUnit = rootUnit;
|
||||
this.borderRadius = borderRadius;
|
||||
this.boxShadow = boxShadow;
|
||||
this.borderWidth = borderWidth;
|
||||
this.opacity = opacity;
|
||||
}
|
||||
|
||||
updateSeedColor = (color: ColorTypes) => {
|
||||
this.color = color;
|
||||
this.seedColor = color;
|
||||
};
|
||||
|
||||
updateColorScheme = (colorScheme: ColorScheme) => {
|
||||
this.colorScheme = colorScheme;
|
||||
updateColorMode = (colorMode: ColorMode) => {
|
||||
this.colorMode = colorMode;
|
||||
};
|
||||
|
||||
updateBorderRadius = (borderRadius: TokenObj) => {
|
||||
this.borderRadius = borderRadius;
|
||||
this.createTokenObject(this.borderRadius, "borderRadius");
|
||||
};
|
||||
|
||||
updateRootUnit = (rootUnit: number) => {
|
||||
this.rootUnit = rootUnit;
|
||||
};
|
||||
|
||||
updateBoxShadow = (boxShadow: TokenObj) => {
|
||||
this.boxShadow = boxShadow;
|
||||
};
|
||||
|
||||
updateBorderWidth = (borderWidth: TokenObj) => {
|
||||
this.borderWidth = borderWidth;
|
||||
};
|
||||
|
||||
updateOpacity = (opacity: TokenObj) => {
|
||||
this.opacity = opacity;
|
||||
};
|
||||
|
||||
getAllTokens = () => {
|
||||
|
|
@ -64,26 +80,30 @@ export class TokensAccessor {
|
|||
};
|
||||
|
||||
getColors = () => {
|
||||
if (this.seedColor == null) return {} as ThemeTokens;
|
||||
|
||||
switch (true) {
|
||||
case this.isLightMode:
|
||||
return this.createTokenObject(
|
||||
new LightScheme(this.color).getColors(),
|
||||
new LightModeTheme(this.seedColor).getColors(),
|
||||
"color",
|
||||
);
|
||||
case this.isDarkMode:
|
||||
return this.createTokenObject(
|
||||
new DarkScheme(this.color).getColors(),
|
||||
new DarkModeTheme(this.seedColor).getColors(),
|
||||
"color",
|
||||
);
|
||||
default:
|
||||
return this.createTokenObject(
|
||||
new LightScheme(this.color).getColors(),
|
||||
new LightModeTheme(this.seedColor).getColors(),
|
||||
"color",
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
getSizing = () => {
|
||||
if (this.rootUnit == null) return {} as ThemeTokens;
|
||||
|
||||
const sizing = {
|
||||
rootUnit: `${this.rootUnit}px`,
|
||||
};
|
||||
|
|
@ -92,10 +112,12 @@ export class TokensAccessor {
|
|||
};
|
||||
|
||||
getSpacing = (count = 6) => {
|
||||
if (this.rootUnit == null) return {} as ThemeTokens;
|
||||
|
||||
const spacing = range(count).reduce((acc, value, index) => {
|
||||
return {
|
||||
...acc,
|
||||
[index]: `${this.rootUnit * value}px`,
|
||||
[index]: `${(this.rootUnit as number) * value}px`,
|
||||
};
|
||||
}, {});
|
||||
|
||||
|
|
@ -103,27 +125,35 @@ export class TokensAccessor {
|
|||
};
|
||||
|
||||
getBorderRadius = () => {
|
||||
if (this.borderRadius == null) return {} as ThemeTokens;
|
||||
|
||||
return this.createTokenObject(this.borderRadius, "borderRadius");
|
||||
};
|
||||
|
||||
getBoxShadow = () => {
|
||||
if (this.boxShadow == null) return {} as ThemeTokens;
|
||||
|
||||
return this.createTokenObject(this.boxShadow, "boxShadow");
|
||||
};
|
||||
|
||||
getBorderWidth = () => {
|
||||
if (this.borderWidth == null) return {} as ThemeTokens;
|
||||
|
||||
return this.createTokenObject(this.borderWidth, "borderWidth");
|
||||
};
|
||||
|
||||
getOpacity = () => {
|
||||
if (this.opacity == null) return {} as ThemeTokens;
|
||||
|
||||
return this.createTokenObject(this.opacity, "opacity");
|
||||
};
|
||||
|
||||
private get isLightMode() {
|
||||
return this.colorScheme === "light";
|
||||
return this.colorMode === "light";
|
||||
}
|
||||
|
||||
private get isDarkMode() {
|
||||
return this.colorScheme === "dark";
|
||||
return this.colorMode === "dark";
|
||||
}
|
||||
|
||||
private createTokenObject = (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
export { TokensAccessor } from "./TokensAccessor";
|
||||
|
||||
export type { ThemeTokens } from "./TokensAccessor";
|
||||
export type { ThemeTokens, TokenSource } from "./types";
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
import type { ColorTypes } from "colorjs.io/types/src/color";
|
||||
export type { ColorTypes } from "colorjs.io/types/src/color";
|
||||
|
||||
export type ThemeTokens = {
|
||||
[key in TokenType]: { [key: string]: Token };
|
||||
};
|
||||
|
||||
export type TokenType =
|
||||
| "sizing"
|
||||
| "color"
|
||||
| "spacing"
|
||||
| "borderRadius"
|
||||
| "boxShadow"
|
||||
| "borderWidth"
|
||||
| "opacity";
|
||||
|
||||
export interface Token {
|
||||
value: string | number;
|
||||
type: TokenType;
|
||||
}
|
||||
|
||||
export interface TokenSource {
|
||||
seedColor?: ColorTypes;
|
||||
colorMode?: ColorMode;
|
||||
rootUnit?: number;
|
||||
borderRadius?: TokenObj;
|
||||
boxShadow?: TokenObj;
|
||||
borderWidth?: TokenObj;
|
||||
opacity?: TokenObj;
|
||||
}
|
||||
|
||||
export type TokenObj = { [key: string]: string | number };
|
||||
|
||||
export type ColorMode = "light" | "dark";
|
||||
|
||||
export interface ColorModeTheme {
|
||||
getColors: () => {
|
||||
bg: string;
|
||||
bgAccent: string;
|
||||
bgAccentHover: string;
|
||||
bgAccentActive: string;
|
||||
bgAccentSubtleHover: string;
|
||||
bgAccentSubtleActive: string;
|
||||
fg: string;
|
||||
fgAccent: string;
|
||||
fgOnAccent: string;
|
||||
bdAccent: string;
|
||||
bdFocus: string;
|
||||
bdNeutral: string;
|
||||
bdNeutralHover: string;
|
||||
bdNegative: string;
|
||||
bdNegativeHover: string;
|
||||
};
|
||||
}
|
||||
|
|
@ -1,7 +1,12 @@
|
|||
import fs from "fs";
|
||||
import { TokensAccessor } from "../";
|
||||
import { TokensAccessor, defaultTokens } from "../";
|
||||
import type { TokenSource } from "./";
|
||||
|
||||
fs.writeFileSync(
|
||||
`${__dirname}/../tokens/themeTokens.json`,
|
||||
`${JSON.stringify(new TokensAccessor().getAllTokens(), null, 2)}\r\n`,
|
||||
`${JSON.stringify(
|
||||
new TokensAccessor(defaultTokens as TokenSource).getAllTokens(),
|
||||
null,
|
||||
2,
|
||||
)}\r\n`,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -13,15 +13,15 @@ export const setLch = (
|
|||
const { c, h, l } = lch;
|
||||
let currentColor = parse(color);
|
||||
|
||||
if (l) {
|
||||
if (l != null) {
|
||||
currentColor = setLightness(currentColor, l);
|
||||
}
|
||||
|
||||
if (c) {
|
||||
if (c != null) {
|
||||
currentColor = setChroma(currentColor, c);
|
||||
}
|
||||
|
||||
if (h) {
|
||||
if (h != null) {
|
||||
currentColor = setHue(currentColor, h);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,4 +2,4 @@ export { contrast, parse, lighten, setLch } from "./colorUtils";
|
|||
export { TokensAccessor } from "./TokensAccessor";
|
||||
export { ColorsAccessor } from "./ColorsAccessor";
|
||||
|
||||
export type { ThemeTokens } from "./TokensAccessor";
|
||||
export type { ThemeTokens, TokenSource } from "./TokensAccessor";
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import { Button } from "../Button";
|
|||
component={TestComponent}
|
||||
/>
|
||||
|
||||
export const Template = (args, { globals: { colorScheme } }) => (
|
||||
export const Template = (args, { globals: { colorMode } }) => (
|
||||
<>
|
||||
<h3>{args.title}</h3>
|
||||
<div
|
||||
|
|
@ -16,7 +16,7 @@ export const Template = (args, { globals: { colorScheme } }) => (
|
|||
background: "#fff",
|
||||
}}
|
||||
>
|
||||
<TestComponent colorScheme={colorScheme}>
|
||||
<TestComponent colorMode={colorMode}>
|
||||
<Button {...args}>Test</Button>
|
||||
</TestComponent>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import { Button } from "../Button";
|
|||
component={TestComponent}
|
||||
/>
|
||||
|
||||
export const Template = (args, { globals: { colorScheme } }) => {
|
||||
export const Template = (args, { globals: { colorMode } }) => {
|
||||
return (
|
||||
<>
|
||||
<h3>{args.title}</h3>
|
||||
|
|
@ -17,7 +17,7 @@ export const Template = (args, { globals: { colorScheme } }) => {
|
|||
background: "#fff",
|
||||
}}
|
||||
>
|
||||
<TestComponent colorScheme={colorScheme}>
|
||||
<TestComponent colorMode={colorMode}>
|
||||
<Button {...args}>Test</Button>
|
||||
</TestComponent>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import { Button } from "../Button";
|
|||
component={TestComponent}
|
||||
/>
|
||||
|
||||
export const Template = (args, { globals: { colorScheme } }) => (
|
||||
export const Template = (args, { globals: { colorMode } }) => (
|
||||
<>
|
||||
<h3>{args.title}</h3>
|
||||
<div
|
||||
|
|
@ -16,7 +16,7 @@ export const Template = (args, { globals: { colorScheme } }) => (
|
|||
background: "#fff",
|
||||
}}
|
||||
>
|
||||
<TestComponent colorScheme={colorScheme}>
|
||||
<TestComponent colorMode={colorMode}>
|
||||
<Button {...args}>Test</Button>
|
||||
</TestComponent>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { ThemeProvider, TokensAccessor } from "@design-system/theming";
|
|||
import { COLORS } from "./colors";
|
||||
|
||||
export const TestComponent = (props: any) => {
|
||||
const { children, colorScheme } = props;
|
||||
const { children, colorMode } = props;
|
||||
|
||||
return (
|
||||
<div
|
||||
|
|
@ -16,11 +16,11 @@ export const TestComponent = (props: any) => {
|
|||
{Object.keys(COLORS).map((colorKey) => {
|
||||
// @ts-expect-error for some reason
|
||||
return Object.keys(COLORS[colorKey]).map((colorNestedKey) => {
|
||||
const tokensAccessor = new TokensAccessor(
|
||||
const tokensAccessor = new TokensAccessor({
|
||||
// @ts-expect-error for some reason
|
||||
COLORS[colorKey][colorNestedKey],
|
||||
colorScheme,
|
||||
);
|
||||
seedColor: COLORS[colorKey][colorNestedKey],
|
||||
colorMode: colorMode,
|
||||
});
|
||||
|
||||
return (
|
||||
<ThemeProvider
|
||||
|
|
|
|||
|
|
@ -2,12 +2,10 @@ import styled from "styled-components";
|
|||
import React, { useCallback, useState } from "react";
|
||||
import { addons, types } from "@storybook/addons";
|
||||
import {
|
||||
Icons,
|
||||
IconButton,
|
||||
WithTooltip,
|
||||
Form,
|
||||
H6,
|
||||
ColorControl,
|
||||
AddonPanel,
|
||||
BooleanControl,
|
||||
} from "@storybook/components";
|
||||
import { useGlobals } from "@storybook/api";
|
||||
|
|
@ -33,13 +31,14 @@ const StyledSelect = styled(Select)`
|
|||
background-repeat: no-repeat, repeat;
|
||||
background-position: right 0.8em top 50%, 0 0;
|
||||
background-size: 0.65em auto, 100%;
|
||||
max-width: 250px;
|
||||
`;
|
||||
|
||||
addons.register("widgets/theming", () => {
|
||||
addons.add("widgets-addon/toolbar", {
|
||||
addons.add("widgets-addon/panel", {
|
||||
id: "widgets-addon/toolbar",
|
||||
title: "Theming",
|
||||
type: types.TOOL,
|
||||
type: types.PANEL,
|
||||
match: (args) => {
|
||||
const { viewMode, storyId } = args;
|
||||
|
||||
|
|
@ -53,7 +52,7 @@ addons.register("widgets/theming", () => {
|
|||
|
||||
return false;
|
||||
},
|
||||
render: ({ active }) => {
|
||||
render: ({ active, key }) => {
|
||||
const [globals, updateGlobals] = useGlobals();
|
||||
const [isDarkMode, setDarkMode] = useState(false);
|
||||
|
||||
|
|
@ -67,86 +66,76 @@ addons.register("widgets/theming", () => {
|
|||
const debouncedColorChange = useCallback(debounce(colorChange, 300), []);
|
||||
|
||||
return (
|
||||
<WithTooltip
|
||||
trigger="click"
|
||||
placement="bottom"
|
||||
tooltipShown={active}
|
||||
closeOnClick
|
||||
tooltip={
|
||||
<Wrapper>
|
||||
<div>
|
||||
<H6>Dark mode</H6>
|
||||
<BooleanControl
|
||||
name="colorScheme"
|
||||
value={isDarkMode}
|
||||
onChange={(checked) => {
|
||||
setDarkMode(checked);
|
||||
updateGlobal("colorScheme", checked ? "dark" : "light");
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<AddonPanel active={active} key={key}>
|
||||
<Wrapper>
|
||||
<div>
|
||||
<H6>Dark mode</H6>
|
||||
<BooleanControl
|
||||
name="colorScheme"
|
||||
value={isDarkMode}
|
||||
onChange={(checked) => {
|
||||
setDarkMode(checked);
|
||||
updateGlobal("colorMode", checked ? "dark" : "light");
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<H6>Border Radius</H6>
|
||||
<StyledSelect
|
||||
id="border-radius"
|
||||
label="Border Radius"
|
||||
size="100%"
|
||||
defaultValue={globals.borderRadius}
|
||||
onChange={(e) => updateGlobal("borderRadius", e.target.value)}
|
||||
>
|
||||
<option value="0px">Sharp</option>
|
||||
<option value="0.375rem">Rounded</option>
|
||||
<option value="1rem">Pill</option>
|
||||
</StyledSelect>
|
||||
</div>
|
||||
<div>
|
||||
<H6>Border Radius</H6>
|
||||
<StyledSelect
|
||||
id="border-radius"
|
||||
label="Border Radius"
|
||||
size="100%"
|
||||
defaultValue={globals.borderRadius}
|
||||
onChange={(e) => updateGlobal("borderRadius", e.target.value)}
|
||||
>
|
||||
<option value="0px">Sharp</option>
|
||||
<option value="0.375rem">Rounded</option>
|
||||
<option value="1rem">Pill</option>
|
||||
</StyledSelect>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<H6>Accent Color</H6>
|
||||
<ColorControl
|
||||
id="accent-color"
|
||||
name="accent-color"
|
||||
label="Accent Color"
|
||||
defaultValue={globals.accentColor}
|
||||
value={globals.accentColor}
|
||||
onChange={debouncedColorChange}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<H6>Accent Color</H6>
|
||||
<ColorControl
|
||||
id="accent-color"
|
||||
name="accent-color"
|
||||
label="Accent Color"
|
||||
defaultValue={globals.accentColor}
|
||||
value={globals.accentColor}
|
||||
onChange={debouncedColorChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<H6>Font Family</H6>
|
||||
<StyledSelect
|
||||
id="font-family"
|
||||
label="Font Family"
|
||||
size="100%"
|
||||
defaultValue={globals.fontFamily}
|
||||
onChange={(e) => updateGlobal("fontFamily", e.target.value)}
|
||||
>
|
||||
<option value="">System Default</option>
|
||||
{Object.keys(fontMetricsMap)
|
||||
.filter((item) => {
|
||||
return (
|
||||
[
|
||||
"-apple-system",
|
||||
"BlinkMacSystemFont",
|
||||
"Segoe UI",
|
||||
].includes(item) === false
|
||||
);
|
||||
})
|
||||
.map((font) => (
|
||||
<option value={font} key={`font-famiy-${font}`}>
|
||||
{font}
|
||||
</option>
|
||||
))}
|
||||
</StyledSelect>
|
||||
</div>
|
||||
</Wrapper>
|
||||
}
|
||||
>
|
||||
<IconButton key="wds-addon/toolbar" active={active} title="Theming">
|
||||
<Icons icon="paintbrush" />
|
||||
</IconButton>
|
||||
</WithTooltip>
|
||||
<div>
|
||||
<H6>Font Family</H6>
|
||||
<StyledSelect
|
||||
id="font-family"
|
||||
label="Font Family"
|
||||
size="100%"
|
||||
defaultValue={globals.fontFamily}
|
||||
onChange={(e) => updateGlobal("fontFamily", e.target.value)}
|
||||
>
|
||||
<option value="">System Default</option>
|
||||
{Object.keys(fontMetricsMap)
|
||||
.filter((item) => {
|
||||
return (
|
||||
[
|
||||
"-apple-system",
|
||||
"BlinkMacSystemFont",
|
||||
"Segoe UI",
|
||||
].includes(item) === false
|
||||
);
|
||||
})
|
||||
.map((font) => (
|
||||
<option value={font} key={`font-famiy-${font}`}>
|
||||
{font}
|
||||
</option>
|
||||
))}
|
||||
</StyledSelect>
|
||||
</div>
|
||||
</Wrapper>
|
||||
</AddonPanel>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,12 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import webfontloader from "webfontloader";
|
||||
import styled, { createGlobalStyle } from "styled-components";
|
||||
import { ThemeProvider, TokensAccessor } from "@design-system/theming";
|
||||
import {
|
||||
ThemeProvider,
|
||||
TokensAccessor,
|
||||
defaultTokens,
|
||||
parse,
|
||||
} from "@design-system/theming";
|
||||
import { createGlobalFontStack } from "@design-system/widgets";
|
||||
|
||||
const StyledThemeProvider = styled(ThemeProvider)`
|
||||
|
|
@ -20,7 +25,7 @@ const GlobalStyles = createGlobalStyle`
|
|||
${fontFaces}
|
||||
`;
|
||||
|
||||
const tokensAccessor = new TokensAccessor();
|
||||
const tokensAccessor = new TokensAccessor(defaultTokens);
|
||||
|
||||
export const theming = (Story, args) => {
|
||||
const [theme, setTheme] = useState(tokensAccessor.getAllTokens());
|
||||
|
|
@ -41,7 +46,30 @@ export const theming = (Story, args) => {
|
|||
|
||||
useEffect(() => {
|
||||
if (args.globals.accentColor) {
|
||||
tokensAccessor.updateSeedColor(args.globals.accentColor);
|
||||
let color;
|
||||
|
||||
try {
|
||||
color = parse(args.globals.accentColor);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
if (color) {
|
||||
tokensAccessor.updateSeedColor(args.globals.accentColor);
|
||||
|
||||
setTheme((prevState) => {
|
||||
return {
|
||||
...prevState,
|
||||
...tokensAccessor.getColors(),
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [args.globals.accentColor]);
|
||||
|
||||
useEffect(() => {
|
||||
if (args.globals.colorMode) {
|
||||
tokensAccessor.updateColorMode(args.globals.colorMode);
|
||||
|
||||
setTheme((prevState) => {
|
||||
return {
|
||||
|
|
@ -50,7 +78,7 @@ export const theming = (Story, args) => {
|
|||
};
|
||||
});
|
||||
}
|
||||
}, [args.globals.accentColor]);
|
||||
}, [args.globals.colorMode]);
|
||||
|
||||
useEffect(() => {
|
||||
if (args.globals.colorScheme) {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import appsmithTheme from "./appsmith-theme";
|
|||
addons.setConfig({
|
||||
theme: appsmithTheme,
|
||||
selectedPanel: "ds-test",
|
||||
enableShortcuts: false,
|
||||
sidebar: {
|
||||
showRoots: false,
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user