Compare commits

..

4 Commits

Author SHA1 Message Date
徐涛
2ec3578e1c 修复或屏蔽编译错误。 2025-02-10 14:42:17 +08:00
徐涛
f944d48e1b 增加部分结构的构造函数。 2025-02-10 14:31:32 +08:00
徐涛
88e3d1f928 修正大部分的编译错误。 2025-02-10 14:28:34 +08:00
徐涛
2144cd548a 修正Vite设置。 2025-02-10 12:22:43 +08:00
64 changed files with 850 additions and 669 deletions

View File

@ -12,6 +12,18 @@ pub struct HctDiffference {
pub lightness: Differ, pub lightness: Differ,
} }
#[wasm_bindgen]
impl HctDiffference {
#[wasm_bindgen(constructor)]
pub fn new(hue: Differ, chroma: Differ, lightness: Differ) -> Self {
Self {
hue,
chroma,
lightness,
}
}
}
impl ColorDifference for Cam16Jch<f32> { impl ColorDifference for Cam16Jch<f32> {
type Difference = HctDiffference; type Difference = HctDiffference;

View File

@ -12,6 +12,18 @@ pub struct HSLDifference {
pub lightness: Differ, pub lightness: Differ,
} }
#[wasm_bindgen]
impl HSLDifference {
#[wasm_bindgen(constructor)]
pub fn new(hue: Differ, saturation: Differ, lightness: Differ) -> Self {
Self {
hue,
saturation,
lightness,
}
}
}
impl ColorDifference for Hsl { impl ColorDifference for Hsl {
type Difference = HSLDifference; type Difference = HSLDifference;

View File

@ -13,6 +13,14 @@ pub struct Differ {
pub percent: f32, pub percent: f32,
} }
#[wasm_bindgen]
impl Differ {
#[wasm_bindgen(constructor)]
pub fn new(delta: f32, percent: f32) -> Self {
Self { delta, percent }
}
}
pub trait ColorDifference { pub trait ColorDifference {
type Difference; type Difference;

View File

@ -12,6 +12,18 @@ pub struct OklchDifference {
pub lightness: Differ, pub lightness: Differ,
} }
#[wasm_bindgen]
impl OklchDifference {
#[wasm_bindgen(constructor)]
pub fn new(hue: Differ, chroma: Differ, lightness: Differ) -> Self {
Self {
hue,
chroma,
lightness,
}
}
}
impl ColorDifference for Oklch { impl ColorDifference for Oklch {
type Difference = OklchDifference; type Difference = OklchDifference;

View File

@ -12,6 +12,14 @@ pub struct RGBDifference {
pub b: Differ, pub b: Differ,
} }
#[wasm_bindgen]
impl RGBDifference {
#[wasm_bindgen(constructor)]
pub fn new(r: Differ, g: Differ, b: Differ) -> Self {
Self { r, g, b }
}
}
impl ColorDifference for Srgb { impl ColorDifference for Srgb {
type Difference = RGBDifference; type Difference = RGBDifference;

View File

@ -11,6 +11,19 @@ pub struct MixReversing {
pub average: f32, pub average: f32,
} }
#[wasm_bindgen]
impl MixReversing {
#[wasm_bindgen(constructor)]
pub fn new(r_factor: f32, g_factor: f32, b_factor: f32, average: f32) -> Self {
Self {
r_factor,
g_factor,
b_factor,
average,
}
}
}
impl MixReversing { impl MixReversing {
pub fn from_tint_rgb(basic_color: Rgb, mixed_result: Rgb) -> Self { pub fn from_tint_rgb(basic_color: Rgb, mixed_result: Rgb) -> Self {
let r_factor = if basic_color.red == 1.0 { let r_factor = if basic_color.red == 1.0 {

View File

@ -23,6 +23,7 @@ export function useColorFunction(): ColorFunctionContextType {
} }
export function ColorFunctionProvider({ children }: WasmProviderProps) { export function ColorFunctionProvider({ children }: WasmProviderProps) {
//@ts-expect-error TS2503
const [wasmInstance, setWasmInstance] = useState<Wasm.InitOutput | null>(null); const [wasmInstance, setWasmInstance] = useState<Wasm.InitOutput | null>(null);
const [isPending, startTransition] = useTransition(); const [isPending, startTransition] = useTransition();
const [error, setError] = useState<Error | null>(null); const [error, setError] = useState<Error | null>(null);

View File

@ -10,6 +10,11 @@ export function generate_swatch_scheme(colors: SwatchEntry[], setting: SwatchSch
export function q_scheme_color_expanding_methods(): any; export function q_scheme_color_expanding_methods(): any;
export function q_scheme_wacg_settings(): any; export function q_scheme_wacg_settings(): any;
export function q_scheme_default_settings(): SchemeSetting; export function q_scheme_default_settings(): SchemeSetting;
export function generate_palette_from_color(reference_color: string, swatch_amount: number, minimum_lightness: number, maximum_lightness: number, use_reference_color?: boolean | null, reference_color_bias?: number | null): string[];
export function swatch_scheme_default_settings(): SwatchSchemeSetting;
export function series(color: string, expand_amount: number, step: number): string[];
export function tonal_lighten_series(color: string, expand_amount: number, step: number): string[];
export function tonal_darken_series(color: string, expand_amount: number, step: number): string[];
export function shift_hue(color: string, degree: number): string; export function shift_hue(color: string, degree: number): string;
export function analogous_30(color: string): string[]; export function analogous_30(color: string): string[];
export function analogous_60(color: string): string[]; export function analogous_60(color: string): string[];
@ -45,11 +50,6 @@ export function darken_absolute(color: string, value: number): string;
export function mix(color1: string, color2: string, percent: number): string; export function mix(color1: string, color2: string, percent: number): string;
export function tint(color: string, percent: number): string; export function tint(color: string, percent: number): string;
export function shade(color: string, percent: number): string; export function shade(color: string, percent: number): string;
export function generate_palette_from_color(reference_color: string, swatch_amount: number, minimum_lightness: number, maximum_lightness: number, use_reference_color?: boolean | null, reference_color_bias?: number | null): string[];
export function swatch_scheme_default_settings(): SwatchSchemeSetting;
export function series(color: string, expand_amount: number, step: number): string[];
export function tonal_lighten_series(color: string, expand_amount: number, step: number): string[];
export function tonal_darken_series(color: string, expand_amount: number, step: number): string[];
export enum ColorExpand { export enum ColorExpand {
Complementary = 0, Complementary = 0,
Analogous = 1, Analogous = 1,
@ -73,43 +73,43 @@ export class ColorShifting {
lightness: number; lightness: number;
} }
export class Differ { export class Differ {
private constructor();
free(): void; free(): void;
constructor(delta: number, percent: number);
delta: number; delta: number;
percent: number; percent: number;
} }
export class HSLDifference { export class HSLDifference {
private constructor();
free(): void; free(): void;
constructor(hue: Differ, saturation: Differ, lightness: Differ);
hue: Differ; hue: Differ;
saturation: Differ; saturation: Differ;
lightness: Differ; lightness: Differ;
} }
export class HctDiffference { export class HctDiffference {
private constructor();
free(): void; free(): void;
constructor(hue: Differ, chroma: Differ, lightness: Differ);
hue: Differ; hue: Differ;
chroma: Differ; chroma: Differ;
lightness: Differ; lightness: Differ;
} }
export class MixReversing { export class MixReversing {
private constructor();
free(): void; free(): void;
constructor(r_factor: number, g_factor: number, b_factor: number, average: number);
r_factor: number; r_factor: number;
g_factor: number; g_factor: number;
b_factor: number; b_factor: number;
average: number; average: number;
} }
export class OklchDifference { export class OklchDifference {
private constructor();
free(): void; free(): void;
constructor(hue: Differ, chroma: Differ, lightness: Differ);
hue: Differ; hue: Differ;
chroma: Differ; chroma: Differ;
lightness: Differ; lightness: Differ;
} }
export class RGBDifference { export class RGBDifference {
private constructor();
free(): void; free(): void;
constructor(r: Differ, g: Differ, b: Differ);
r: Differ; r: Differ;
g: Differ; g: Differ;
b: Differ; b: Differ;
@ -186,6 +186,7 @@ export interface InitOutput {
readonly __wbg_set_oklchdifference_chroma: (a: number, b: number) => void; readonly __wbg_set_oklchdifference_chroma: (a: number, b: number) => void;
readonly __wbg_get_oklchdifference_lightness: (a: number) => number; readonly __wbg_get_oklchdifference_lightness: (a: number) => number;
readonly __wbg_set_oklchdifference_lightness: (a: number, b: number) => void; readonly __wbg_set_oklchdifference_lightness: (a: number, b: number) => void;
readonly oklchdifference_new: (a: number, b: number, c: number) => number;
readonly __wbg_mixreversing_free: (a: number, b: number) => void; readonly __wbg_mixreversing_free: (a: number, b: number) => void;
readonly __wbg_get_mixreversing_r_factor: (a: number) => number; readonly __wbg_get_mixreversing_r_factor: (a: number) => number;
readonly __wbg_set_mixreversing_r_factor: (a: number, b: number) => void; readonly __wbg_set_mixreversing_r_factor: (a: number, b: number) => void;
@ -195,6 +196,7 @@ export interface InitOutput {
readonly __wbg_set_mixreversing_b_factor: (a: number, b: number) => void; readonly __wbg_set_mixreversing_b_factor: (a: number, b: number) => void;
readonly __wbg_get_mixreversing_average: (a: number) => number; readonly __wbg_get_mixreversing_average: (a: number) => number;
readonly __wbg_set_mixreversing_average: (a: number, b: number) => void; readonly __wbg_set_mixreversing_average: (a: number, b: number) => void;
readonly mixreversing_new: (a: number, b: number, c: number, d: number) => number;
readonly q_scheme_color_expanding_methods: () => [number, number, number]; readonly q_scheme_color_expanding_methods: () => [number, number, number];
readonly q_scheme_wacg_settings: () => [number, number, number]; readonly q_scheme_wacg_settings: () => [number, number, number];
readonly q_scheme_default_settings: () => number; readonly q_scheme_default_settings: () => number;
@ -203,24 +205,7 @@ export interface InitOutput {
readonly __wbg_set_differ_delta: (a: number, b: number) => void; readonly __wbg_set_differ_delta: (a: number, b: number) => void;
readonly __wbg_get_differ_percent: (a: number) => number; readonly __wbg_get_differ_percent: (a: number) => number;
readonly __wbg_set_differ_percent: (a: number, b: number) => void; readonly __wbg_set_differ_percent: (a: number, b: number) => void;
readonly shift_hue: (a: number, b: number, c: number) => [number, number, number, number]; readonly differ_new: (a: number, b: number) => number;
readonly analogous_30: (a: number, b: number) => [number, number, number, number];
readonly analogous_60: (a: number, b: number) => [number, number, number, number];
readonly complementary: (a: number, b: number) => [number, number, number, number];
readonly split_complementary: (a: number, b: number) => [number, number, number, number];
readonly tetradic: (a: number, b: number) => [number, number, number, number];
readonly triadic: (a: number, b: number) => [number, number, number, number];
readonly represent_rgb: (a: number, b: number) => [number, number, number, number];
readonly rgb_to_hex: (a: number, b: number, c: number) => [number, number, number, number];
readonly represent_hsl: (a: number, b: number) => [number, number, number, number];
readonly hsl_to_hex: (a: number, b: number, c: number) => [number, number, number, number];
readonly represent_lab: (a: number, b: number) => [number, number, number, number];
readonly lab_to_hex: (a: number, b: number, c: number) => [number, number, number, number];
readonly represent_oklch: (a: number, b: number) => [number, number, number, number];
readonly oklch_to_hex: (a: number, b: number, c: number) => [number, number, number, number];
readonly represent_hct: (a: number, b: number) => [number, number, number, number];
readonly hct_to_hex: (a: number, b: number, c: number) => [number, number, number, number];
readonly wacg_relative_contrast: (a: number, b: number, c: number, d: number) => [number, number, number];
readonly __wbg_hctdiffference_free: (a: number, b: number) => void; readonly __wbg_hctdiffference_free: (a: number, b: number) => void;
readonly __wbg_get_hctdiffference_hue: (a: number) => number; readonly __wbg_get_hctdiffference_hue: (a: number) => number;
readonly __wbg_set_hctdiffference_hue: (a: number, b: number) => void; readonly __wbg_set_hctdiffference_hue: (a: number, b: number) => void;
@ -228,37 +213,7 @@ export interface InitOutput {
readonly __wbg_set_hctdiffference_chroma: (a: number, b: number) => void; readonly __wbg_set_hctdiffference_chroma: (a: number, b: number) => void;
readonly __wbg_get_hctdiffference_lightness: (a: number) => number; readonly __wbg_get_hctdiffference_lightness: (a: number) => number;
readonly __wbg_set_hctdiffference_lightness: (a: number, b: number) => void; readonly __wbg_set_hctdiffference_lightness: (a: number, b: number) => void;
readonly differ_in_rgb: (a: number, b: number, c: number, d: number) => [number, number, number]; readonly hctdiffference_new: (a: number, b: number, c: number) => number;
readonly relative_differ_in_rgb: (a: number, b: number, c: number, d: number) => [number, number, number];
readonly differ_in_hsl: (a: number, b: number, c: number, d: number) => [number, number, number];
readonly relative_differ_in_hsl: (a: number, b: number, c: number, d: number) => [number, number, number];
readonly differ_in_hct: (a: number, b: number, c: number, d: number) => [number, number, number];
readonly relative_differ_in_hct: (a: number, b: number, c: number, d: number) => [number, number, number];
readonly differ_in_oklch: (a: number, b: number, c: number, d: number) => [number, number, number];
readonly relative_differ_in_oklch: (a: number, b: number, c: number, d: number) => [number, number, number];
readonly tint_scale: (a: number, b: number, c: number, d: number) => [number, number, number];
readonly shade_scale: (a: number, b: number, c: number, d: number) => [number, number, number];
readonly __wbg_hsldifference_free: (a: number, b: number) => void;
readonly __wbg_get_hsldifference_hue: (a: number) => number;
readonly __wbg_set_hsldifference_hue: (a: number, b: number) => void;
readonly __wbg_get_hsldifference_saturation: (a: number) => number;
readonly __wbg_set_hsldifference_saturation: (a: number, b: number) => void;
readonly __wbg_get_hsldifference_lightness: (a: number) => number;
readonly __wbg_set_hsldifference_lightness: (a: number, b: number) => void;
readonly lighten: (a: number, b: number, c: number) => [number, number, number, number];
readonly lighten_absolute: (a: number, b: number, c: number) => [number, number, number, number];
readonly darken: (a: number, b: number, c: number) => [number, number, number, number];
readonly darken_absolute: (a: number, b: number, c: number) => [number, number, number, number];
readonly mix: (a: number, b: number, c: number, d: number, e: number) => [number, number, number, number];
readonly tint: (a: number, b: number, c: number) => [number, number, number, number];
readonly shade: (a: number, b: number, c: number) => [number, number, number, number];
readonly __wbg_rgbdifference_free: (a: number, b: number) => void;
readonly __wbg_get_rgbdifference_r: (a: number) => number;
readonly __wbg_set_rgbdifference_r: (a: number, b: number) => void;
readonly __wbg_get_rgbdifference_g: (a: number) => number;
readonly __wbg_set_rgbdifference_g: (a: number, b: number) => void;
readonly __wbg_get_rgbdifference_b: (a: number) => number;
readonly __wbg_set_rgbdifference_b: (a: number, b: number) => void;
readonly generate_palette_from_color: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => [number, number, number, number]; readonly generate_palette_from_color: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => [number, number, number, number];
readonly __wbg_swatchschemesetting_free: (a: number, b: number) => void; readonly __wbg_swatchschemesetting_free: (a: number, b: number) => void;
readonly __wbg_get_swatchschemesetting_amount: (a: number) => number; readonly __wbg_get_swatchschemesetting_amount: (a: number) => number;
@ -284,14 +239,65 @@ export interface InitOutput {
readonly series: (a: number, b: number, c: number, d: number) => [number, number, number, number]; readonly series: (a: number, b: number, c: number, d: number) => [number, number, number, number];
readonly tonal_lighten_series: (a: number, b: number, c: number, d: number) => [number, number, number, number]; readonly tonal_lighten_series: (a: number, b: number, c: number, d: number) => [number, number, number, number];
readonly tonal_darken_series: (a: number, b: number, c: number, d: number) => [number, number, number, number]; readonly tonal_darken_series: (a: number, b: number, c: number, d: number) => [number, number, number, number];
readonly shift_hue: (a: number, b: number, c: number) => [number, number, number, number];
readonly analogous_30: (a: number, b: number) => [number, number, number, number];
readonly analogous_60: (a: number, b: number) => [number, number, number, number];
readonly complementary: (a: number, b: number) => [number, number, number, number];
readonly split_complementary: (a: number, b: number) => [number, number, number, number];
readonly tetradic: (a: number, b: number) => [number, number, number, number];
readonly triadic: (a: number, b: number) => [number, number, number, number];
readonly represent_rgb: (a: number, b: number) => [number, number, number, number];
readonly rgb_to_hex: (a: number, b: number, c: number) => [number, number, number, number];
readonly represent_hsl: (a: number, b: number) => [number, number, number, number];
readonly hsl_to_hex: (a: number, b: number, c: number) => [number, number, number, number];
readonly represent_lab: (a: number, b: number) => [number, number, number, number];
readonly lab_to_hex: (a: number, b: number, c: number) => [number, number, number, number];
readonly represent_oklch: (a: number, b: number) => [number, number, number, number];
readonly oklch_to_hex: (a: number, b: number, c: number) => [number, number, number, number];
readonly represent_hct: (a: number, b: number) => [number, number, number, number];
readonly hct_to_hex: (a: number, b: number, c: number) => [number, number, number, number];
readonly wacg_relative_contrast: (a: number, b: number, c: number, d: number) => [number, number, number];
readonly __wbg_rgbdifference_free: (a: number, b: number) => void;
readonly __wbg_get_rgbdifference_r: (a: number) => number;
readonly __wbg_set_rgbdifference_r: (a: number, b: number) => void;
readonly __wbg_get_rgbdifference_g: (a: number) => number;
readonly __wbg_set_rgbdifference_g: (a: number, b: number) => void;
readonly __wbg_get_rgbdifference_b: (a: number) => number;
readonly __wbg_set_rgbdifference_b: (a: number, b: number) => void;
readonly rgbdifference_new: (a: number, b: number, c: number) => number;
readonly differ_in_rgb: (a: number, b: number, c: number, d: number) => [number, number, number];
readonly relative_differ_in_rgb: (a: number, b: number, c: number, d: number) => [number, number, number];
readonly differ_in_hsl: (a: number, b: number, c: number, d: number) => [number, number, number];
readonly relative_differ_in_hsl: (a: number, b: number, c: number, d: number) => [number, number, number];
readonly differ_in_hct: (a: number, b: number, c: number, d: number) => [number, number, number];
readonly relative_differ_in_hct: (a: number, b: number, c: number, d: number) => [number, number, number];
readonly differ_in_oklch: (a: number, b: number, c: number, d: number) => [number, number, number];
readonly relative_differ_in_oklch: (a: number, b: number, c: number, d: number) => [number, number, number];
readonly tint_scale: (a: number, b: number, c: number, d: number) => [number, number, number];
readonly shade_scale: (a: number, b: number, c: number, d: number) => [number, number, number];
readonly __wbg_hsldifference_free: (a: number, b: number) => void;
readonly __wbg_get_hsldifference_hue: (a: number) => number;
readonly __wbg_set_hsldifference_hue: (a: number, b: number) => void;
readonly __wbg_get_hsldifference_saturation: (a: number) => number;
readonly __wbg_set_hsldifference_saturation: (a: number, b: number) => void;
readonly __wbg_get_hsldifference_lightness: (a: number) => number;
readonly __wbg_set_hsldifference_lightness: (a: number, b: number) => void;
readonly hsldifference_new: (a: number, b: number, c: number) => number;
readonly lighten: (a: number, b: number, c: number) => [number, number, number, number];
readonly lighten_absolute: (a: number, b: number, c: number) => [number, number, number, number];
readonly darken: (a: number, b: number, c: number) => [number, number, number, number];
readonly darken_absolute: (a: number, b: number, c: number) => [number, number, number, number];
readonly mix: (a: number, b: number, c: number, d: number, e: number) => [number, number, number, number];
readonly tint: (a: number, b: number, c: number) => [number, number, number, number];
readonly shade: (a: number, b: number, c: number) => [number, number, number, number];
readonly __wbindgen_malloc: (a: number, b: number) => number; readonly __wbindgen_malloc: (a: number, b: number) => number;
readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number; readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
readonly __wbindgen_exn_store: (a: number) => void; readonly __wbindgen_exn_store: (a: number) => void;
readonly __externref_table_alloc: () => number; readonly __externref_table_alloc: () => number;
readonly __wbindgen_export_4: WebAssembly.Table; readonly __wbindgen_export_4: WebAssembly.Table;
readonly __externref_table_dealloc: (a: number) => void; readonly __externref_table_dealloc: (a: number) => void;
readonly __wbindgen_free: (a: number, b: number, c: number) => void;
readonly __externref_drop_slice: (a: number, b: number) => void; readonly __externref_drop_slice: (a: number, b: number) => void;
readonly __wbindgen_free: (a: number, b: number, c: number) => void;
readonly __wbindgen_start: () => void; readonly __wbindgen_start: () => void;
} }

View File

@ -379,6 +379,99 @@ export function q_scheme_default_settings() {
return SchemeSetting.__wrap(ret); return SchemeSetting.__wrap(ret);
} }
function getArrayJsValueFromWasm0(ptr, len) {
ptr = ptr >>> 0;
const mem = getDataViewMemory0();
const result = [];
for (let i = ptr; i < ptr + 4 * len; i += 4) {
result.push(wasm.__wbindgen_export_4.get(mem.getUint32(i, true)));
}
wasm.__externref_drop_slice(ptr, len);
return result;
}
/**
* @param {string} reference_color
* @param {number} swatch_amount
* @param {number} minimum_lightness
* @param {number} maximum_lightness
* @param {boolean | null} [use_reference_color]
* @param {number | null} [reference_color_bias]
* @returns {string[]}
*/
export function generate_palette_from_color(reference_color, swatch_amount, minimum_lightness, maximum_lightness, use_reference_color, reference_color_bias) {
const ptr0 = passStringToWasm0(reference_color, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
const ret = wasm.generate_palette_from_color(ptr0, len0, swatch_amount, minimum_lightness, maximum_lightness, isLikeNone(use_reference_color) ? 0xFFFFFF : use_reference_color ? 1 : 0, isLikeNone(reference_color_bias) ? 0xFFFFFF : reference_color_bias);
if (ret[3]) {
throw takeFromExternrefTable0(ret[2]);
}
var v2 = getArrayJsValueFromWasm0(ret[0], ret[1]).slice();
wasm.__wbindgen_free(ret[0], ret[1] * 4, 4);
return v2;
}
/**
* @returns {SwatchSchemeSetting}
*/
export function swatch_scheme_default_settings() {
const ret = wasm.swatch_scheme_default_settings();
return SwatchSchemeSetting.__wrap(ret);
}
/**
* @param {string} color
* @param {number} expand_amount
* @param {number} step
* @returns {string[]}
*/
export function series(color, expand_amount, step) {
const ptr0 = passStringToWasm0(color, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
const ret = wasm.series(ptr0, len0, expand_amount, step);
if (ret[3]) {
throw takeFromExternrefTable0(ret[2]);
}
var v2 = getArrayJsValueFromWasm0(ret[0], ret[1]).slice();
wasm.__wbindgen_free(ret[0], ret[1] * 4, 4);
return v2;
}
/**
* @param {string} color
* @param {number} expand_amount
* @param {number} step
* @returns {string[]}
*/
export function tonal_lighten_series(color, expand_amount, step) {
const ptr0 = passStringToWasm0(color, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
const ret = wasm.tonal_lighten_series(ptr0, len0, expand_amount, step);
if (ret[3]) {
throw takeFromExternrefTable0(ret[2]);
}
var v2 = getArrayJsValueFromWasm0(ret[0], ret[1]).slice();
wasm.__wbindgen_free(ret[0], ret[1] * 4, 4);
return v2;
}
/**
* @param {string} color
* @param {number} expand_amount
* @param {number} step
* @returns {string[]}
*/
export function tonal_darken_series(color, expand_amount, step) {
const ptr0 = passStringToWasm0(color, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
const ret = wasm.tonal_darken_series(ptr0, len0, expand_amount, step);
if (ret[3]) {
throw takeFromExternrefTable0(ret[2]);
}
var v2 = getArrayJsValueFromWasm0(ret[0], ret[1]).slice();
wasm.__wbindgen_free(ret[0], ret[1] * 4, 4);
return v2;
}
/** /**
* @param {string} color * @param {string} color
* @param {number} degree * @param {number} degree
@ -405,16 +498,6 @@ export function shift_hue(color, degree) {
} }
} }
function getArrayJsValueFromWasm0(ptr, len) {
ptr = ptr >>> 0;
const mem = getDataViewMemory0();
const result = [];
for (let i = ptr; i < ptr + 4 * len; i += 4) {
result.push(wasm.__wbindgen_export_4.get(mem.getUint32(i, true)));
}
wasm.__externref_drop_slice(ptr, len);
return result;
}
/** /**
* @param {string} color * @param {string} color
* @returns {string[]} * @returns {string[]}
@ -1114,89 +1197,6 @@ export function shade(color, percent) {
} }
} }
/**
* @param {string} reference_color
* @param {number} swatch_amount
* @param {number} minimum_lightness
* @param {number} maximum_lightness
* @param {boolean | null} [use_reference_color]
* @param {number | null} [reference_color_bias]
* @returns {string[]}
*/
export function generate_palette_from_color(reference_color, swatch_amount, minimum_lightness, maximum_lightness, use_reference_color, reference_color_bias) {
const ptr0 = passStringToWasm0(reference_color, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
const ret = wasm.generate_palette_from_color(ptr0, len0, swatch_amount, minimum_lightness, maximum_lightness, isLikeNone(use_reference_color) ? 0xFFFFFF : use_reference_color ? 1 : 0, isLikeNone(reference_color_bias) ? 0xFFFFFF : reference_color_bias);
if (ret[3]) {
throw takeFromExternrefTable0(ret[2]);
}
var v2 = getArrayJsValueFromWasm0(ret[0], ret[1]).slice();
wasm.__wbindgen_free(ret[0], ret[1] * 4, 4);
return v2;
}
/**
* @returns {SwatchSchemeSetting}
*/
export function swatch_scheme_default_settings() {
const ret = wasm.swatch_scheme_default_settings();
return SwatchSchemeSetting.__wrap(ret);
}
/**
* @param {string} color
* @param {number} expand_amount
* @param {number} step
* @returns {string[]}
*/
export function series(color, expand_amount, step) {
const ptr0 = passStringToWasm0(color, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
const ret = wasm.series(ptr0, len0, expand_amount, step);
if (ret[3]) {
throw takeFromExternrefTable0(ret[2]);
}
var v2 = getArrayJsValueFromWasm0(ret[0], ret[1]).slice();
wasm.__wbindgen_free(ret[0], ret[1] * 4, 4);
return v2;
}
/**
* @param {string} color
* @param {number} expand_amount
* @param {number} step
* @returns {string[]}
*/
export function tonal_lighten_series(color, expand_amount, step) {
const ptr0 = passStringToWasm0(color, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
const ret = wasm.tonal_lighten_series(ptr0, len0, expand_amount, step);
if (ret[3]) {
throw takeFromExternrefTable0(ret[2]);
}
var v2 = getArrayJsValueFromWasm0(ret[0], ret[1]).slice();
wasm.__wbindgen_free(ret[0], ret[1] * 4, 4);
return v2;
}
/**
* @param {string} color
* @param {number} expand_amount
* @param {number} step
* @returns {string[]}
*/
export function tonal_darken_series(color, expand_amount, step) {
const ptr0 = passStringToWasm0(color, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
const ret = wasm.tonal_darken_series(ptr0, len0, expand_amount, step);
if (ret[3]) {
throw takeFromExternrefTable0(ret[2]);
}
var v2 = getArrayJsValueFromWasm0(ret[0], ret[1]).slice();
wasm.__wbindgen_free(ret[0], ret[1] * 4, 4);
return v2;
}
/** /**
* @enum {0 | 1 | 2 | 3 | 4 | 5 | 6} * @enum {0 | 1 | 2 | 3 | 4 | 5 | 6}
*/ */
@ -1343,6 +1343,16 @@ export class Differ {
set percent(arg0) { set percent(arg0) {
wasm.__wbg_set_differ_percent(this.__wbg_ptr, arg0); wasm.__wbg_set_differ_percent(this.__wbg_ptr, arg0);
} }
/**
* @param {number} delta
* @param {number} percent
*/
constructor(delta, percent) {
const ret = wasm.differ_new(delta, percent);
this.__wbg_ptr = ret >>> 0;
DifferFinalization.register(this, this.__wbg_ptr, this);
return this;
}
} }
const HSLDifferenceFinalization = (typeof FinalizationRegistry === 'undefined') const HSLDifferenceFinalization = (typeof FinalizationRegistry === 'undefined')
@ -1415,6 +1425,23 @@ export class HSLDifference {
var ptr0 = arg0.__destroy_into_raw(); var ptr0 = arg0.__destroy_into_raw();
wasm.__wbg_set_hsldifference_lightness(this.__wbg_ptr, ptr0); wasm.__wbg_set_hsldifference_lightness(this.__wbg_ptr, ptr0);
} }
/**
* @param {Differ} hue
* @param {Differ} saturation
* @param {Differ} lightness
*/
constructor(hue, saturation, lightness) {
_assertClass(hue, Differ);
var ptr0 = hue.__destroy_into_raw();
_assertClass(saturation, Differ);
var ptr1 = saturation.__destroy_into_raw();
_assertClass(lightness, Differ);
var ptr2 = lightness.__destroy_into_raw();
const ret = wasm.hsldifference_new(ptr0, ptr1, ptr2);
this.__wbg_ptr = ret >>> 0;
HSLDifferenceFinalization.register(this, this.__wbg_ptr, this);
return this;
}
} }
const HctDiffferenceFinalization = (typeof FinalizationRegistry === 'undefined') const HctDiffferenceFinalization = (typeof FinalizationRegistry === 'undefined')
@ -1487,6 +1514,23 @@ export class HctDiffference {
var ptr0 = arg0.__destroy_into_raw(); var ptr0 = arg0.__destroy_into_raw();
wasm.__wbg_set_hctdiffference_lightness(this.__wbg_ptr, ptr0); wasm.__wbg_set_hctdiffference_lightness(this.__wbg_ptr, ptr0);
} }
/**
* @param {Differ} hue
* @param {Differ} chroma
* @param {Differ} lightness
*/
constructor(hue, chroma, lightness) {
_assertClass(hue, Differ);
var ptr0 = hue.__destroy_into_raw();
_assertClass(chroma, Differ);
var ptr1 = chroma.__destroy_into_raw();
_assertClass(lightness, Differ);
var ptr2 = lightness.__destroy_into_raw();
const ret = wasm.hctdiffference_new(ptr0, ptr1, ptr2);
this.__wbg_ptr = ret >>> 0;
HctDiffferenceFinalization.register(this, this.__wbg_ptr, this);
return this;
}
} }
const MixReversingFinalization = (typeof FinalizationRegistry === 'undefined') const MixReversingFinalization = (typeof FinalizationRegistry === 'undefined')
@ -1566,6 +1610,18 @@ export class MixReversing {
set average(arg0) { set average(arg0) {
wasm.__wbg_set_mixreversing_average(this.__wbg_ptr, arg0); wasm.__wbg_set_mixreversing_average(this.__wbg_ptr, arg0);
} }
/**
* @param {number} r_factor
* @param {number} g_factor
* @param {number} b_factor
* @param {number} average
*/
constructor(r_factor, g_factor, b_factor, average) {
const ret = wasm.mixreversing_new(r_factor, g_factor, b_factor, average);
this.__wbg_ptr = ret >>> 0;
MixReversingFinalization.register(this, this.__wbg_ptr, this);
return this;
}
} }
const OklchDifferenceFinalization = (typeof FinalizationRegistry === 'undefined') const OklchDifferenceFinalization = (typeof FinalizationRegistry === 'undefined')
@ -1638,6 +1694,23 @@ export class OklchDifference {
var ptr0 = arg0.__destroy_into_raw(); var ptr0 = arg0.__destroy_into_raw();
wasm.__wbg_set_oklchdifference_lightness(this.__wbg_ptr, ptr0); wasm.__wbg_set_oklchdifference_lightness(this.__wbg_ptr, ptr0);
} }
/**
* @param {Differ} hue
* @param {Differ} chroma
* @param {Differ} lightness
*/
constructor(hue, chroma, lightness) {
_assertClass(hue, Differ);
var ptr0 = hue.__destroy_into_raw();
_assertClass(chroma, Differ);
var ptr1 = chroma.__destroy_into_raw();
_assertClass(lightness, Differ);
var ptr2 = lightness.__destroy_into_raw();
const ret = wasm.oklchdifference_new(ptr0, ptr1, ptr2);
this.__wbg_ptr = ret >>> 0;
OklchDifferenceFinalization.register(this, this.__wbg_ptr, this);
return this;
}
} }
const RGBDifferenceFinalization = (typeof FinalizationRegistry === 'undefined') const RGBDifferenceFinalization = (typeof FinalizationRegistry === 'undefined')
@ -1710,6 +1783,23 @@ export class RGBDifference {
var ptr0 = arg0.__destroy_into_raw(); var ptr0 = arg0.__destroy_into_raw();
wasm.__wbg_set_rgbdifference_b(this.__wbg_ptr, ptr0); wasm.__wbg_set_rgbdifference_b(this.__wbg_ptr, ptr0);
} }
/**
* @param {Differ} r
* @param {Differ} g
* @param {Differ} b
*/
constructor(r, g, b) {
_assertClass(r, Differ);
var ptr0 = r.__destroy_into_raw();
_assertClass(g, Differ);
var ptr1 = g.__destroy_into_raw();
_assertClass(b, Differ);
var ptr2 = b.__destroy_into_raw();
const ret = wasm.rgbdifference_new(ptr0, ptr1, ptr2);
this.__wbg_ptr = ret >>> 0;
RGBDifferenceFinalization.register(this, this.__wbg_ptr, this);
return this;
}
} }
const SchemeSettingFinalization = (typeof FinalizationRegistry === 'undefined') const SchemeSettingFinalization = (typeof FinalizationRegistry === 'undefined')

View File

@ -39,6 +39,7 @@ export const __wbg_get_oklchdifference_chroma: (a: number) => number;
export const __wbg_set_oklchdifference_chroma: (a: number, b: number) => void; export const __wbg_set_oklchdifference_chroma: (a: number, b: number) => void;
export const __wbg_get_oklchdifference_lightness: (a: number) => number; export const __wbg_get_oklchdifference_lightness: (a: number) => number;
export const __wbg_set_oklchdifference_lightness: (a: number, b: number) => void; export const __wbg_set_oklchdifference_lightness: (a: number, b: number) => void;
export const oklchdifference_new: (a: number, b: number, c: number) => number;
export const __wbg_mixreversing_free: (a: number, b: number) => void; export const __wbg_mixreversing_free: (a: number, b: number) => void;
export const __wbg_get_mixreversing_r_factor: (a: number) => number; export const __wbg_get_mixreversing_r_factor: (a: number) => number;
export const __wbg_set_mixreversing_r_factor: (a: number, b: number) => void; export const __wbg_set_mixreversing_r_factor: (a: number, b: number) => void;
@ -48,6 +49,7 @@ export const __wbg_get_mixreversing_b_factor: (a: number) => number;
export const __wbg_set_mixreversing_b_factor: (a: number, b: number) => void; export const __wbg_set_mixreversing_b_factor: (a: number, b: number) => void;
export const __wbg_get_mixreversing_average: (a: number) => number; export const __wbg_get_mixreversing_average: (a: number) => number;
export const __wbg_set_mixreversing_average: (a: number, b: number) => void; export const __wbg_set_mixreversing_average: (a: number, b: number) => void;
export const mixreversing_new: (a: number, b: number, c: number, d: number) => number;
export const q_scheme_color_expanding_methods: () => [number, number, number]; export const q_scheme_color_expanding_methods: () => [number, number, number];
export const q_scheme_wacg_settings: () => [number, number, number]; export const q_scheme_wacg_settings: () => [number, number, number];
export const q_scheme_default_settings: () => number; export const q_scheme_default_settings: () => number;
@ -56,24 +58,7 @@ export const __wbg_get_differ_delta: (a: number) => number;
export const __wbg_set_differ_delta: (a: number, b: number) => void; export const __wbg_set_differ_delta: (a: number, b: number) => void;
export const __wbg_get_differ_percent: (a: number) => number; export const __wbg_get_differ_percent: (a: number) => number;
export const __wbg_set_differ_percent: (a: number, b: number) => void; export const __wbg_set_differ_percent: (a: number, b: number) => void;
export const shift_hue: (a: number, b: number, c: number) => [number, number, number, number]; export const differ_new: (a: number, b: number) => number;
export const analogous_30: (a: number, b: number) => [number, number, number, number];
export const analogous_60: (a: number, b: number) => [number, number, number, number];
export const complementary: (a: number, b: number) => [number, number, number, number];
export const split_complementary: (a: number, b: number) => [number, number, number, number];
export const tetradic: (a: number, b: number) => [number, number, number, number];
export const triadic: (a: number, b: number) => [number, number, number, number];
export const represent_rgb: (a: number, b: number) => [number, number, number, number];
export const rgb_to_hex: (a: number, b: number, c: number) => [number, number, number, number];
export const represent_hsl: (a: number, b: number) => [number, number, number, number];
export const hsl_to_hex: (a: number, b: number, c: number) => [number, number, number, number];
export const represent_lab: (a: number, b: number) => [number, number, number, number];
export const lab_to_hex: (a: number, b: number, c: number) => [number, number, number, number];
export const represent_oklch: (a: number, b: number) => [number, number, number, number];
export const oklch_to_hex: (a: number, b: number, c: number) => [number, number, number, number];
export const represent_hct: (a: number, b: number) => [number, number, number, number];
export const hct_to_hex: (a: number, b: number, c: number) => [number, number, number, number];
export const wacg_relative_contrast: (a: number, b: number, c: number, d: number) => [number, number, number];
export const __wbg_hctdiffference_free: (a: number, b: number) => void; export const __wbg_hctdiffference_free: (a: number, b: number) => void;
export const __wbg_get_hctdiffference_hue: (a: number) => number; export const __wbg_get_hctdiffference_hue: (a: number) => number;
export const __wbg_set_hctdiffference_hue: (a: number, b: number) => void; export const __wbg_set_hctdiffference_hue: (a: number, b: number) => void;
@ -81,37 +66,7 @@ export const __wbg_get_hctdiffference_chroma: (a: number) => number;
export const __wbg_set_hctdiffference_chroma: (a: number, b: number) => void; export const __wbg_set_hctdiffference_chroma: (a: number, b: number) => void;
export const __wbg_get_hctdiffference_lightness: (a: number) => number; export const __wbg_get_hctdiffference_lightness: (a: number) => number;
export const __wbg_set_hctdiffference_lightness: (a: number, b: number) => void; export const __wbg_set_hctdiffference_lightness: (a: number, b: number) => void;
export const differ_in_rgb: (a: number, b: number, c: number, d: number) => [number, number, number]; export const hctdiffference_new: (a: number, b: number, c: number) => number;
export const relative_differ_in_rgb: (a: number, b: number, c: number, d: number) => [number, number, number];
export const differ_in_hsl: (a: number, b: number, c: number, d: number) => [number, number, number];
export const relative_differ_in_hsl: (a: number, b: number, c: number, d: number) => [number, number, number];
export const differ_in_hct: (a: number, b: number, c: number, d: number) => [number, number, number];
export const relative_differ_in_hct: (a: number, b: number, c: number, d: number) => [number, number, number];
export const differ_in_oklch: (a: number, b: number, c: number, d: number) => [number, number, number];
export const relative_differ_in_oklch: (a: number, b: number, c: number, d: number) => [number, number, number];
export const tint_scale: (a: number, b: number, c: number, d: number) => [number, number, number];
export const shade_scale: (a: number, b: number, c: number, d: number) => [number, number, number];
export const __wbg_hsldifference_free: (a: number, b: number) => void;
export const __wbg_get_hsldifference_hue: (a: number) => number;
export const __wbg_set_hsldifference_hue: (a: number, b: number) => void;
export const __wbg_get_hsldifference_saturation: (a: number) => number;
export const __wbg_set_hsldifference_saturation: (a: number, b: number) => void;
export const __wbg_get_hsldifference_lightness: (a: number) => number;
export const __wbg_set_hsldifference_lightness: (a: number, b: number) => void;
export const lighten: (a: number, b: number, c: number) => [number, number, number, number];
export const lighten_absolute: (a: number, b: number, c: number) => [number, number, number, number];
export const darken: (a: number, b: number, c: number) => [number, number, number, number];
export const darken_absolute: (a: number, b: number, c: number) => [number, number, number, number];
export const mix: (a: number, b: number, c: number, d: number, e: number) => [number, number, number, number];
export const tint: (a: number, b: number, c: number) => [number, number, number, number];
export const shade: (a: number, b: number, c: number) => [number, number, number, number];
export const __wbg_rgbdifference_free: (a: number, b: number) => void;
export const __wbg_get_rgbdifference_r: (a: number) => number;
export const __wbg_set_rgbdifference_r: (a: number, b: number) => void;
export const __wbg_get_rgbdifference_g: (a: number) => number;
export const __wbg_set_rgbdifference_g: (a: number, b: number) => void;
export const __wbg_get_rgbdifference_b: (a: number) => number;
export const __wbg_set_rgbdifference_b: (a: number, b: number) => void;
export const generate_palette_from_color: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => [number, number, number, number]; export const generate_palette_from_color: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => [number, number, number, number];
export const __wbg_swatchschemesetting_free: (a: number, b: number) => void; export const __wbg_swatchschemesetting_free: (a: number, b: number) => void;
export const __wbg_get_swatchschemesetting_amount: (a: number) => number; export const __wbg_get_swatchschemesetting_amount: (a: number) => number;
@ -137,12 +92,63 @@ export const swatch_scheme_default_settings: () => number;
export const series: (a: number, b: number, c: number, d: number) => [number, number, number, number]; export const series: (a: number, b: number, c: number, d: number) => [number, number, number, number];
export const tonal_lighten_series: (a: number, b: number, c: number, d: number) => [number, number, number, number]; export const tonal_lighten_series: (a: number, b: number, c: number, d: number) => [number, number, number, number];
export const tonal_darken_series: (a: number, b: number, c: number, d: number) => [number, number, number, number]; export const tonal_darken_series: (a: number, b: number, c: number, d: number) => [number, number, number, number];
export const shift_hue: (a: number, b: number, c: number) => [number, number, number, number];
export const analogous_30: (a: number, b: number) => [number, number, number, number];
export const analogous_60: (a: number, b: number) => [number, number, number, number];
export const complementary: (a: number, b: number) => [number, number, number, number];
export const split_complementary: (a: number, b: number) => [number, number, number, number];
export const tetradic: (a: number, b: number) => [number, number, number, number];
export const triadic: (a: number, b: number) => [number, number, number, number];
export const represent_rgb: (a: number, b: number) => [number, number, number, number];
export const rgb_to_hex: (a: number, b: number, c: number) => [number, number, number, number];
export const represent_hsl: (a: number, b: number) => [number, number, number, number];
export const hsl_to_hex: (a: number, b: number, c: number) => [number, number, number, number];
export const represent_lab: (a: number, b: number) => [number, number, number, number];
export const lab_to_hex: (a: number, b: number, c: number) => [number, number, number, number];
export const represent_oklch: (a: number, b: number) => [number, number, number, number];
export const oklch_to_hex: (a: number, b: number, c: number) => [number, number, number, number];
export const represent_hct: (a: number, b: number) => [number, number, number, number];
export const hct_to_hex: (a: number, b: number, c: number) => [number, number, number, number];
export const wacg_relative_contrast: (a: number, b: number, c: number, d: number) => [number, number, number];
export const __wbg_rgbdifference_free: (a: number, b: number) => void;
export const __wbg_get_rgbdifference_r: (a: number) => number;
export const __wbg_set_rgbdifference_r: (a: number, b: number) => void;
export const __wbg_get_rgbdifference_g: (a: number) => number;
export const __wbg_set_rgbdifference_g: (a: number, b: number) => void;
export const __wbg_get_rgbdifference_b: (a: number) => number;
export const __wbg_set_rgbdifference_b: (a: number, b: number) => void;
export const rgbdifference_new: (a: number, b: number, c: number) => number;
export const differ_in_rgb: (a: number, b: number, c: number, d: number) => [number, number, number];
export const relative_differ_in_rgb: (a: number, b: number, c: number, d: number) => [number, number, number];
export const differ_in_hsl: (a: number, b: number, c: number, d: number) => [number, number, number];
export const relative_differ_in_hsl: (a: number, b: number, c: number, d: number) => [number, number, number];
export const differ_in_hct: (a: number, b: number, c: number, d: number) => [number, number, number];
export const relative_differ_in_hct: (a: number, b: number, c: number, d: number) => [number, number, number];
export const differ_in_oklch: (a: number, b: number, c: number, d: number) => [number, number, number];
export const relative_differ_in_oklch: (a: number, b: number, c: number, d: number) => [number, number, number];
export const tint_scale: (a: number, b: number, c: number, d: number) => [number, number, number];
export const shade_scale: (a: number, b: number, c: number, d: number) => [number, number, number];
export const __wbg_hsldifference_free: (a: number, b: number) => void;
export const __wbg_get_hsldifference_hue: (a: number) => number;
export const __wbg_set_hsldifference_hue: (a: number, b: number) => void;
export const __wbg_get_hsldifference_saturation: (a: number) => number;
export const __wbg_set_hsldifference_saturation: (a: number, b: number) => void;
export const __wbg_get_hsldifference_lightness: (a: number) => number;
export const __wbg_set_hsldifference_lightness: (a: number, b: number) => void;
export const hsldifference_new: (a: number, b: number, c: number) => number;
export const lighten: (a: number, b: number, c: number) => [number, number, number, number];
export const lighten_absolute: (a: number, b: number, c: number) => [number, number, number, number];
export const darken: (a: number, b: number, c: number) => [number, number, number, number];
export const darken_absolute: (a: number, b: number, c: number) => [number, number, number, number];
export const mix: (a: number, b: number, c: number, d: number, e: number) => [number, number, number, number];
export const tint: (a: number, b: number, c: number) => [number, number, number, number];
export const shade: (a: number, b: number, c: number) => [number, number, number, number];
export const __wbindgen_malloc: (a: number, b: number) => number; export const __wbindgen_malloc: (a: number, b: number) => number;
export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number; export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
export const __wbindgen_exn_store: (a: number) => void; export const __wbindgen_exn_store: (a: number) => void;
export const __externref_table_alloc: () => number; export const __externref_table_alloc: () => number;
export const __wbindgen_export_4: WebAssembly.Table; export const __wbindgen_export_4: WebAssembly.Table;
export const __externref_table_dealloc: (a: number) => void; export const __externref_table_dealloc: (a: number) => void;
export const __wbindgen_free: (a: number, b: number, c: number) => void;
export const __externref_drop_slice: (a: number, b: number) => void; export const __externref_drop_slice: (a: number, b: number) => void;
export const __wbindgen_free: (a: number, b: number, c: number) => void;
export const __wbindgen_start: () => void; export const __wbindgen_start: () => void;

View File

@ -1,6 +1,6 @@
import { Icon, IconProps } from '@iconify/react/dist/iconify.js'; import { Icon, IconProps } from '@iconify/react/dist/iconify.js';
import cx from 'clsx'; import cx from 'clsx';
import { MouseEventHandler, useCallback } from 'react'; import { MouseEvent, MouseEventHandler, useCallback } from 'react';
import styles from './ActionIcon.module.css'; import styles from './ActionIcon.module.css';
type ActionIconProps = { type ActionIconProps = {

View File

@ -87,7 +87,7 @@ export function ColorComponentInput({ color, onChange }: ColorComponentInputProp
} }
}; };
const updateH = (evt: ChangeEvent<HTMLInputElement>) => { const updateH = (evt: ChangeEvent<HTMLInputElement>) => {
const value = parseInt(evt.target.value, 10); let value = parseInt(evt.target.value, 10);
if (value > 360) { if (value > 360) {
value -= 360; value -= 360;
} }

View File

@ -28,7 +28,7 @@ export function ColorRangePicker({
}: ColorRangePickerProps) { }: ColorRangePickerProps) {
const [pickerValue, setPickerValue] = useState(value); const [pickerValue, setPickerValue] = useState(value);
const handlePickerChange = (evt: ChangeEvent<HTMLInputElement>) => { const handlePickerChange = (evt: ChangeEvent<HTMLInputElement>) => {
const value = evt.target.value as number; const value = Number(evt.target.value);
setPickerValue(valueProcess(value)); setPickerValue(valueProcess(value));
onChange?.(valueProcess(value)); onChange?.(valueProcess(value));
}; };

View File

@ -4,7 +4,7 @@ import { useRef, useState } from 'react';
import styles from './EditableTitle.module.css'; import styles from './EditableTitle.module.css';
type EditableTitleProps = { type EditableTitleProps = {
title: string; title?: string;
onChange?: (newTitle: string) => void; onChange?: (newTitle: string) => void;
}; };

View File

@ -6,7 +6,7 @@ import styles from './FloatColorPicker.module.css';
type FloatColorPickerProps = { type FloatColorPickerProps = {
name?: string; name?: string;
color?: string; color?: string | null;
onPick?: (color: string | null | undefined) => void; onPick?: (color: string | null | undefined) => void;
}; };

View File

@ -52,6 +52,7 @@ export function HSegmentedControl({
<div <div
key={`${index}_${value}`} key={`${index}_${value}`}
className={cx(styles.option, isEqual(selected, value) && styles.selected)} className={cx(styles.option, isEqual(selected, value) && styles.selected)}
//@ts-expect-error TS2322
ref={(el) => (optionsRef.current[index] = el!)} ref={(el) => (optionsRef.current[index] = el!)}
onClick={() => handleSelectAction(value, index)}> onClick={() => handleSelectAction(value, index)}>
{label} {label}

View File

@ -26,7 +26,7 @@ export function LabeledPicker({
}: LabeledPickerProps) { }: LabeledPickerProps) {
const [pickerValue, setPickerValue] = useState(value ?? min); const [pickerValue, setPickerValue] = useState(value ?? min);
const handlePickerChange = (event: React.ChangeEvent<HTMLInputElement>) => { const handlePickerChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const value = event.target.value as number; const value = Number(event.target.value);
setPickerValue(value); setPickerValue(value);
onChange?.(value); onChange?.(value);
}; };

View File

@ -118,7 +118,7 @@ type ToastProps = {
icon?: string; icon?: string;
duration?: ToastDuration; duration?: ToastDuration;
ref: RefObject<HTMLDivElement>; ref: RefObject<HTMLDivElement>;
closeAction: () => void; closeAction: (tid?: string) => void;
}; };
const Toast = ({ const Toast = ({
kind, kind,
@ -157,7 +157,7 @@ export function useNotification() {
type NotificationElement = { type NotificationElement = {
id: string; id: string;
element: ReactNode; element: ReactNode;
ref: RefObject<ReactNode>; ref: RefObject<ReactNode | HTMLDivElement>;
}; };
type NotificationsProps = { type NotificationsProps = {
defaultDuration?: number; defaultDuration?: number;
@ -184,7 +184,7 @@ export function Notifications({
duration?: number, duration?: number,
) => { ) => {
const id = v4(); const id = v4();
const ref = createRef(null); const ref = createRef<ReactNode | HTMLDivElement>();
const newNotify = ( const newNotify = (
<Notification <Notification
kind={kind} kind={kind}
@ -194,6 +194,7 @@ export function Notifications({
message={message} message={message}
duration={duration ?? defaultDuration} duration={duration ?? defaultDuration}
closeAction={removeNotification} closeAction={removeNotification}
//@ts-expect-error TS2322
ref={ref} ref={ref}
/> />
); );
@ -207,14 +208,9 @@ export function Notifications({
setToasts((prev) => filter(prev, (n) => !isEqual(n.id, id))); setToasts((prev) => filter(prev, (n) => !isEqual(n.id, id)));
}, []); }, []);
const showToast = useCallback( const showToast = useCallback(
( (kind: NotificationType, message?: string, icon?: string, duration?: ToastDuration) => {
kind: NotificationType,
message?: string,
icon?: IconifyIconProps['icon'],
duration?: ToastDuration,
) => {
const id = v4(); const id = v4();
const ref = createRef(null); const ref = createRef<HTMLDivElement>();
const newToast = ( const newToast = (
<Toast <Toast
kind={kind} kind={kind}
@ -238,9 +234,6 @@ export function Notifications({
value={{ value={{
addNotification, addNotification,
removeNotification, removeNotification,
showDialog: () => '',
showModalDialog: () => '',
closeDialog: () => {},
showToast, showToast,
}}> }}>
{children} {children}
@ -250,6 +243,7 @@ export function Notifications({
{notifications.slice(0, maxNotifications).map(({ id, element, ref }) => ( {notifications.slice(0, maxNotifications).map(({ id, element, ref }) => (
<CSSTransition <CSSTransition
key={id} key={id}
//@ts-expect-error TS2322
nodeRef={ref} nodeRef={ref}
unmountOnExit unmountOnExit
timeout={500} timeout={500}
@ -271,6 +265,7 @@ export function Notifications({
{toasts.slice(0, 1).map(({ id, element, ref }) => ( {toasts.slice(0, 1).map(({ id, element, ref }) => (
<CSSTransition <CSSTransition
key={id} key={id}
//@ts-expect-error TS2322
nodeRef={ref} nodeRef={ref}
unmountOnExit unmountOnExit
timeout={500} timeout={500}

View File

@ -1,5 +1,5 @@
import { clamp } from 'lodash-es'; import { clamp } from 'lodash-es';
import { RefObject, useEffect, useRef, useState } from 'react'; import { MouseEvent, RefObject, useEffect, useRef, useState, WheelEvent } from 'react';
import styles from './ScrollArea.module.css'; import styles from './ScrollArea.module.css';
type ScrollBarProps = { type ScrollBarProps = {
@ -12,10 +12,12 @@ function VerticalScrollBar({ containerRef }: ScrollBarProps) {
const thumbRef = useRef<HTMLDivElement | null>(null); const thumbRef = useRef<HTMLDivElement | null>(null);
const handleMouseDown = (evt: MouseEvent) => { const handleMouseDown = (evt: MouseEvent) => {
evt.preventDefault(); evt.preventDefault();
//@ts-expect-error TS2769
document.addEventListener('mousemove', handleMouseMove); document.addEventListener('mousemove', handleMouseMove);
//@ts-expect-error TS2769
document.addEventListener('mouseup', handleMouseUp); document.addEventListener('mouseup', handleMouseUp);
}; };
const handleMouseMove = (evt: MouseEvent) => { const handleMouseMove = (evt: MouseEvent<HTMLDivElement>) => {
evt.preventDefault(); evt.preventDefault();
const container = containerRef?.current; const container = containerRef?.current;
const scrollbar = trackRef.current; const scrollbar = trackRef.current;
@ -34,7 +36,9 @@ function VerticalScrollBar({ containerRef }: ScrollBarProps) {
}; };
const handleMouseUp = (evt: MouseEvent) => { const handleMouseUp = (evt: MouseEvent) => {
evt.preventDefault(); evt.preventDefault();
//@ts-expect-error TS2769
document.removeEventListener('mousemove', handleMouseMove); document.removeEventListener('mousemove', handleMouseMove);
//@ts-expect-error TS2769
document.removeEventListener('mouseup', handleMouseUp); document.removeEventListener('mouseup', handleMouseUp);
}; };
@ -77,7 +81,9 @@ function HorizontalScrollBar({ containerRef }: ScrollBarProps) {
const thumbRef = useRef<HTMLDivElement | null>(null); const thumbRef = useRef<HTMLDivElement | null>(null);
const handleMouseDown = (evt: MouseEvent) => { const handleMouseDown = (evt: MouseEvent) => {
evt.preventDefault(); evt.preventDefault();
//@ts-expect-error TS2769
document.addEventListener('mousemove', handleMouseMove); document.addEventListener('mousemove', handleMouseMove);
//@ts-expect-error TS2769
document.addEventListener('mouseup', handleMouseUp); document.addEventListener('mouseup', handleMouseUp);
}; };
const handleMouseMove = (evt: MouseEvent) => { const handleMouseMove = (evt: MouseEvent) => {
@ -99,7 +105,9 @@ function HorizontalScrollBar({ containerRef }: ScrollBarProps) {
}; };
const handleMouseUp = (evt: MouseEvent) => { const handleMouseUp = (evt: MouseEvent) => {
evt.preventDefault(); evt.preventDefault();
//@ts-expect-error TS2769
document.removeEventListener('mousemove', handleMouseMove); document.removeEventListener('mousemove', handleMouseMove);
//@ts-expect-error TS2769
document.removeEventListener('mouseup', handleMouseUp); document.removeEventListener('mouseup', handleMouseUp);
}; };
@ -129,7 +137,7 @@ function HorizontalScrollBar({ containerRef }: ScrollBarProps) {
className={styles.h_thumb} className={styles.h_thumb}
ref={thumbRef} ref={thumbRef}
style={{ left: thumbPos }} style={{ left: thumbPos }}
onMouseDown={handleMouseDown} onMouseDown={(e) => handleMouseDown(e)}
/> />
</div> </div>
); );
@ -148,10 +156,10 @@ export function ScrollArea({
enableY = false, enableY = false,
normalizedScroll = false, normalizedScroll = false,
}: ScrollAreaProps) { }: ScrollAreaProps) {
const scrollContainerRef = useRef<HTMLDivElement>(null); const scrollContainerRef = useRef<HTMLDivElement | null>(null);
const [xScrollNeeded, setXScrollNeeded] = useState(false); const [xScrollNeeded, setXScrollNeeded] = useState(false);
const [yScrollNeeded, setYScrollNeeded] = useState(false); const [yScrollNeeded, setYScrollNeeded] = useState(false);
const handleWheel = (evt: WheelEvent) => { const handleWheel = (evt: WheelEvent<HTMLDivElement>) => {
const container = scrollContainerRef?.current; const container = scrollContainerRef?.current;
if (enableY && container) { if (enableY && container) {
const delta = evt.deltaY; const delta = evt.deltaY;
@ -177,7 +185,7 @@ export function ScrollArea({
return ( return (
<div className={styles.scroll_area}> <div className={styles.scroll_area}>
<div className={styles.content} ref={scrollContainerRef} onWheel={handleWheel}> <div className={styles.content} ref={scrollContainerRef} onWheel={(e) => handleWheel(e)}>
{children} {children}
</div> </div>
{enableY && yScrollNeeded && <VerticalScrollBar containerRef={scrollContainerRef} />} {enableY && yScrollNeeded && <VerticalScrollBar containerRef={scrollContainerRef} />}

View File

@ -26,11 +26,14 @@ export function Switch({ name, checked = false, disabled = false, onChange }: Sw
}, [checked]); }, [checked]);
return ( return (
//@ts-expect-error TS2322
<div className={styles.switch} disabled={disabled}> <div className={styles.switch} disabled={disabled}>
<div <div
className={cx(styles.switch_handle, isChecked && styles.checked)} className={cx(styles.switch_handle, isChecked && styles.checked)}
onClick={handleSwitch}></div> onClick={handleSwitch}></div>
{!isNil(name) && <input type="hidden" name={name} value={isChecked} />} {!isNil(name) && (
<input type="hidden" name={name} value={isChecked ? 'checked' : undefined} />
)}
</div> </div>
); );
} }

View File

@ -18,7 +18,7 @@ const positionMap = {
export function Tooltip({ content, position = 'top', children }: TooltipProps) { export function Tooltip({ content, position = 'top', children }: TooltipProps) {
const [show, setShow] = useState(false); const [show, setShow] = useState(false);
const contentRef = useRef<HTMLDivElement>(); const contentRef = useRef<HTMLDivElement | null>(null);
return ( return (
<div <div

View File

@ -52,6 +52,7 @@ export function VSegmentedControl({
<div <div
key={`${index}_${value}`} key={`${index}_${value}`}
className={cx(styles.option, isEqual(selected, value) && styles.selected)} className={cx(styles.option, isEqual(selected, value) && styles.selected)}
//@ts-expect-error TS2322
ref={(el) => (optionsRef.current[index] = el!)} ref={(el) => (optionsRef.current[index] = el!)}
onClick={() => handleSelectAction(value, index)}> onClick={() => handleSelectAction(value, index)}>
{label} {label}

View File

@ -6,7 +6,7 @@ import { NotificationType, useNotification } from '../components/Notifications';
export function useCopy() { export function useCopy() {
const { showToast } = useNotification(); const { showToast } = useNotification();
const [cpState, copyToClipboard] = useCopyToClipboard(); const [cpState, copyToClipboard] = useCopyToClipboard();
const copyAction = useCallback((content: string) => { const copyAction = useCallback((content?: string | null) => {
if (isNil(content) || isEmpty(content)) return; if (isNil(content) || isEmpty(content)) return;
copyToClipboard(content); copyToClipboard(content);
}, []); }, []);

View File

@ -4,12 +4,12 @@ import { MaterialDesign3SchemeStorage } from './material-3-scheme';
import { QSchemeStorage } from './q-scheme'; import { QSchemeStorage } from './q-scheme';
import { SwatchSchemeStorage } from './swatch_scheme'; import { SwatchSchemeStorage } from './swatch_scheme';
export type Option = export type Option<T = string | number | null> =
| { | {
label: string; label: string;
value: string | number | null; value: T;
} }
| Record<'label' | 'value', string | number | null>; | Record<'label' | 'value', T>;
export type HarmonyColor = { export type HarmonyColor = {
color: string; color: string;

View File

@ -1,23 +1,14 @@
import { useMemo } from 'react'; import { useMemo } from 'react';
import { HctDiffference } from '../../color_functions/color_module'; import { Differ, HctDiffference } from '../../color_functions/color_module';
import { useColorFunction } from '../../ColorFunctionContext'; import { useColorFunction } from '../../ColorFunctionContext';
import styles from './CompareLayout.module.css'; import styles from './CompareLayout.module.css';
import { CompareMethodProps } from './share-props'; import { CompareMethodProps } from './share-props';
const defaultCompareResult: HctDiffference = { const defaultCompareResult: HctDiffference = new HctDiffference(
hue: { new Differ(0, 0),
delta: 0, new Differ(0, 0),
percent: 0, new Differ(0, 0),
}, );
chroma: {
delta: 0,
percent: 0,
},
lightness: {
delta: 0,
percent: 0,
},
};
export function HCTCompare({ export function HCTCompare({
basic = '000000', basic = '000000',

View File

@ -1,23 +1,14 @@
import { useMemo } from 'react'; import { useMemo } from 'react';
import { HSLDifference } from '../../color_functions/color_module'; import { Differ, HSLDifference } from '../../color_functions/color_module';
import { useColorFunction } from '../../ColorFunctionContext'; import { useColorFunction } from '../../ColorFunctionContext';
import styles from './CompareLayout.module.css'; import styles from './CompareLayout.module.css';
import { CompareMethodProps } from './share-props'; import { CompareMethodProps } from './share-props';
const defaultCompareResult: HSLDifference = { const defaultCompareResult: HSLDifference = new HSLDifference(
hue: { new Differ(0, 0),
delta: 0, new Differ(0, 0),
percent: 0, new Differ(0, 0),
}, );
saturation: {
delta: 0,
percent: 0,
},
lightness: {
delta: 0,
percent: 0,
},
};
export function HSLCompare({ export function HSLCompare({
basic = '000000', basic = '000000',

View File

@ -1,23 +1,14 @@
import { useMemo } from 'react'; import { useMemo } from 'react';
import { OklchDifference } from '../../color_functions/color_module'; import { Differ, OklchDifference } from '../../color_functions/color_module';
import { useColorFunction } from '../../ColorFunctionContext'; import { useColorFunction } from '../../ColorFunctionContext';
import styles from './CompareLayout.module.css'; import styles from './CompareLayout.module.css';
import { CompareMethodProps } from './share-props'; import { CompareMethodProps } from './share-props';
const defaultCompareResult: OklchDifference = { const defaultCompareResult: OklchDifference = new OklchDifference(
hue: { new Differ(0, 0),
delta: 0, new Differ(0, 0),
percent: 0, new Differ(0, 0),
}, );
chroma: {
delta: 0,
percent: 0,
},
lightness: {
delta: 0,
percent: 0,
},
};
export function OklchCompare({ export function OklchCompare({
basic = '000000', basic = '000000',

View File

@ -1,23 +1,14 @@
import { useMemo } from 'react'; import { useMemo } from 'react';
import { RGBDifference } from '../../color_functions/color_module'; import { Differ, RGBDifference } from '../../color_functions/color_module';
import { useColorFunction } from '../../ColorFunctionContext'; import { useColorFunction } from '../../ColorFunctionContext';
import styles from './CompareLayout.module.css'; import styles from './CompareLayout.module.css';
import { CompareMethodProps } from './share-props'; import { CompareMethodProps } from './share-props';
const defaultCompareResult: RGBDifference = { const defaultCompareResult: RGBDifference = new RGBDifference(
r: { new Differ(0, 0),
delta: 0, new Differ(0, 0),
percent: 0, new Differ(0, 0),
}, );
g: {
delta: 0,
percent: 0,
},
b: {
delta: 0,
percent: 0,
},
};
export function RGBCompare({ export function RGBCompare({
basic = '000000', basic = '000000',

View File

@ -5,12 +5,7 @@ import { useColorFunction } from '../../ColorFunctionContext';
import styles from './CompareLayout.module.css'; import styles from './CompareLayout.module.css';
import { CompareMethodProps } from './share-props'; import { CompareMethodProps } from './share-props';
const defaultMixResult: MixReversing = { const defaultMixResult: MixReversing = new MixReversing(0, 0, 0, 0);
r_factor: 0,
g_factor: 0,
b_factor: 0,
average: 0,
};
export function ShadeScale({ basic = '000000', compare = '000000' }: CompareMethodProps) { export function ShadeScale({ basic = '000000', compare = '000000' }: CompareMethodProps) {
const { colorFn } = useColorFunction(); const { colorFn } = useColorFunction();

View File

@ -5,12 +5,7 @@ import { useColorFunction } from '../../ColorFunctionContext';
import styles from './CompareLayout.module.css'; import styles from './CompareLayout.module.css';
import { CompareMethodProps } from './share-props'; import { CompareMethodProps } from './share-props';
const defaultMixResult: MixReversing = { const defaultMixResult: MixReversing = new MixReversing(0, 0, 0, 0);
r_factor: 0,
g_factor: 0,
b_factor: 0,
average: 0,
};
export function TintScale({ basic = '000000', compare = '000000' }: CompareMethodProps) { export function TintScale({ basic = '000000', compare = '000000' }: CompareMethodProps) {
const { colorFn } = useColorFunction(); const { colorFn } = useColorFunction();

View File

@ -23,18 +23,18 @@ export function Darkens({ color, darkens, mix, step, maximum, copyMode }: Darken
switch (mix) { switch (mix) {
case 'progressive': case 'progressive':
for (let i = 1; i <= darkens; i++) { for (let i = 1; i <= darkens; i++) {
const darkenColor = colorFn.darken(last(darkenColors), step); const darkenColor = colorFn.darken(last(darkenColors) ?? '', step ?? 0);
darkenColors.push(darkenColor); darkenColors.push(darkenColor);
} }
break; break;
case 'linear': case 'linear':
for (let i = 1; i <= darkens; i++) { for (let i = 1; i <= darkens; i++) {
const darkenColor = colorFn.darken(color, step * i); const darkenColor = colorFn.darken(color, (step ?? 0) * i);
darkenColors.push(darkenColor); darkenColors.push(darkenColor);
} }
break; break;
case 'average': { case 'average': {
const interval = maximum / darkens / 100; const interval = (maximum ?? 0) / darkens / 100;
for (let i = 1; i <= darkens; i++) { for (let i = 1; i <= darkens; i++) {
const darkenColor = colorFn.darken(color, interval * i); const darkenColor = colorFn.darken(color, interval * i);
darkenColors.push(darkenColor); darkenColors.push(darkenColor);

View File

@ -23,18 +23,18 @@ export function Lightens({ color, lightens, mix, step, maximum, copyMode }: Ligh
switch (mix) { switch (mix) {
case 'progressive': case 'progressive':
for (let i = 1; i <= lightens; i++) { for (let i = 1; i <= lightens; i++) {
const lightenColor = colorFn.lighten(last(lightenColors), step); const lightenColor = colorFn.lighten(last(lightenColors) ?? '', step ?? 0);
lightenColors.push(lightenColor); lightenColors.push(lightenColor);
} }
break; break;
case 'linear': case 'linear':
for (let i = 1; i <= lightens; i++) { for (let i = 1; i <= lightens; i++) {
const lightenColor = colorFn.lighten(color, step * i); const lightenColor = colorFn.lighten(color, (step ?? 0) * i);
lightenColors.push(lightenColor); lightenColors.push(lightenColor);
} }
break; break;
case 'average': { case 'average': {
const interval = maximum / lightens / 100; const interval = (maximum ?? 0) / lightens / 100;
for (let i = 1; i <= lightens; i++) { for (let i = 1; i <= lightens; i++) {
const lightenColor = colorFn.lighten(color, interval * i); const lightenColor = colorFn.lighten(color, interval * i);
lightenColors.push(lightenColor); lightenColors.push(lightenColor);

View File

@ -1,6 +1,6 @@
import { isEmpty } from 'lodash-es'; import { isEmpty } from 'lodash-es';
import { ActionIcon } from '../../components/ActionIcon'; import { ActionIcon } from '../../components/ActionIcon';
import { FloatColorPicker } from '../../components/FloatcolorPicker'; import { FloatColorPicker } from '../../components/FloatColorPicker';
import styles from './colorEntry.module.css'; import styles from './colorEntry.module.css';
export type IdenticalColorEntry = { export type IdenticalColorEntry = {

View File

@ -1,6 +1,8 @@
import { isEqual, isNil } from 'lodash-es'; import { isEqual, isNil } from 'lodash-es';
import { useState } from 'react'; import { useState } from 'react';
import { Tab } from '../../components/Tab'; import { Tab } from '../../components/Tab';
import { MaterialDesign2SchemeStorage } from '../../material-2-scheme';
import { SchemeContent } from '../../models';
import { SchemeExport } from './Export'; import { SchemeExport } from './Export';
import { M2SchemeBuilder } from './m2-scheme/Builder'; import { M2SchemeBuilder } from './m2-scheme/Builder';
import { M2SchemePreview } from './m2-scheme/Preview'; import { M2SchemePreview } from './m2-scheme/Preview';
@ -11,18 +13,18 @@ const tabOptions = [
{ title: 'Exports', id: 'export' }, { title: 'Exports', id: 'export' },
]; ];
type M3SchemeProps = { type M2SchemeProps = {
scheme: SchemeContent<MaterialDesign3SchemeStorage>; scheme: SchemeContent<MaterialDesign2SchemeStorage>;
}; };
export function M2Scheme({ scheme }: M3SchemeProps) { export function M2Scheme({ scheme }: M2SchemeProps) {
const [activeTab, setActiveTab] = useState<(typeof tabOptions)[number]['id']>(() => const [activeTab, setActiveTab] = useState<(typeof tabOptions)[number]['id']>(() =>
isNil(scheme.schemeStorage.scheme) ? 'builder' : 'overview', isNil(scheme.schemeStorage.scheme) ? 'builder' : 'overview',
); );
return ( return (
<> <>
<Tab tabs={tabOptions} activeTab={activeTab} onActive={setActiveTab} /> <Tab tabs={tabOptions} activeTab={activeTab} onActive={(v) => setActiveTab(v as string)} />
{isEqual(activeTab, 'overview') && <M2SchemePreview scheme={scheme} />} {isEqual(activeTab, 'overview') && <M2SchemePreview scheme={scheme} />}
{isEqual(activeTab, 'builder') && ( {isEqual(activeTab, 'builder') && (
<M2SchemeBuilder scheme={scheme} onBuildComplete={() => setActiveTab('overview')} /> <M2SchemeBuilder scheme={scheme} onBuildComplete={() => setActiveTab('overview')} />

View File

@ -2,6 +2,7 @@ import { isEqual, isNil } from 'lodash-es';
import { useState } from 'react'; import { useState } from 'react';
import { Tab } from '../../components/Tab'; import { Tab } from '../../components/Tab';
import { MaterialDesign3SchemeStorage } from '../../material-3-scheme'; import { MaterialDesign3SchemeStorage } from '../../material-3-scheme';
import { SchemeContent } from '../../models';
import { SchemeExport } from './Export'; import { SchemeExport } from './Export';
import { M3SchemeBuilder } from './m3-scheme/Builder'; import { M3SchemeBuilder } from './m3-scheme/Builder';
import { M3SchemePreview } from './m3-scheme/Preview'; import { M3SchemePreview } from './m3-scheme/Preview';
@ -23,7 +24,7 @@ export function M3Scheme({ scheme }: M3SchemeProps) {
return ( return (
<> <>
<Tab tabs={tabOptions} activeTab={activeTab} onActive={setActiveTab} /> <Tab tabs={tabOptions} activeTab={activeTab} onActive={(v) => setActiveTab(v as string)} />
{isEqual(activeTab, 'overview') && <M3SchemePreview scheme={scheme} />} {isEqual(activeTab, 'overview') && <M3SchemePreview scheme={scheme} />}
{isEqual(activeTab, 'builder') && ( {isEqual(activeTab, 'builder') && (
<M3SchemeBuilder scheme={scheme} onBuildCompleted={() => setActiveTab('overview')} /> <M3SchemeBuilder scheme={scheme} onBuildCompleted={() => setActiveTab('overview')} />

View File

@ -24,7 +24,7 @@ export function QScheme({ scheme }: QSchemeProps) {
return ( return (
<> <>
<Tab tabs={tabOptions} activeTab={activeTab} onActive={setActiveTab} /> <Tab tabs={tabOptions} activeTab={activeTab} onActive={(v) => setActiveTab(v as string)} />
{isEqual(activeTab, 'overview') && <QSchemePreview scheme={scheme} />} {isEqual(activeTab, 'overview') && <QSchemePreview scheme={scheme} />}
{isEqual(activeTab, 'builder') && ( {isEqual(activeTab, 'builder') && (
<QSchemeBuilder scheme={scheme} onBuildCompleted={() => setActiveTab('overview')} /> <QSchemeBuilder scheme={scheme} onBuildCompleted={() => setActiveTab('overview')} />

View File

@ -24,7 +24,7 @@ export function SwatchScheme({ scheme }: SwatchSchemeProps) {
return ( return (
<> <>
<Tab tabs={tabOptions} activeTab={activeTab} onActive={setActiveTab} /> <Tab tabs={tabOptions} activeTab={activeTab} onActive={(v) => setActiveTab(v as string)} />
{isEqual(activeTab, 'overview') && <SwatchSchemePreview scheme={scheme} />} {isEqual(activeTab, 'overview') && <SwatchSchemePreview scheme={scheme} />}
{isEqual(activeTab, 'builder') && ( {isEqual(activeTab, 'builder') && (
<SwatchSchemeBuilder scheme={scheme} onBuildCompleted={() => setActiveTab('overview')} /> <SwatchSchemeBuilder scheme={scheme} onBuildCompleted={() => setActiveTab('overview')} />

View File

@ -1,7 +1,7 @@
import { includes, isEmpty, isNil, merge } from 'lodash-es'; import { includes, isEmpty, isNil, merge } from 'lodash-es';
import { useActionState, useCallback, useMemo, useState } from 'react'; import { useActionState, useCallback, useMemo, useState } from 'react';
import { useColorFunction } from '../../../ColorFunctionContext'; import { useColorFunction } from '../../../ColorFunctionContext';
import { FloatColorPicker } from '../../../components/FloatcolorPicker'; import { FloatColorPicker } from '../../../components/FloatColorPicker';
import { ScrollArea } from '../../../components/ScrollArea'; import { ScrollArea } from '../../../components/ScrollArea';
import { MaterialDesign2SchemeStorage } from '../../../material-2-scheme'; import { MaterialDesign2SchemeStorage } from '../../../material-2-scheme';
import { SchemeContent } from '../../../models'; import { SchemeContent } from '../../../models';
@ -36,60 +36,63 @@ export function M2SchemeBuilder({ scheme, onBuildComplete }: M2SchemeBuilderProp
[originalColors, newColors, deleted], [originalColors, newColors, deleted],
); );
const [errMsg, handleSubmitAction] = useActionState((state, formData) => { const [errMsg, handleSubmitAction] = useActionState<Map<string, string>, FormData>(
const errMsg = new Map<string, string>(); (_state, formData) => {
try { const errMsg = new Map<string, string>();
const primaryColor = formData.get('primary'); try {
if (isNil(primaryColor) || isEmpty(primaryColor)) { const primaryColor = formData.get('primary') as string;
errMsg.set('primary', 'Primary color is required'); if (isNil(primaryColor) || isEmpty(primaryColor)) {
} errMsg.set('primary', 'Primary color is required');
const secondaryColor = formData.get('secondary'); }
if (isNil(secondaryColor) || isEmpty(secondaryColor)) { const secondaryColor = formData.get('secondary') as string;
errMsg.set('secondary', 'Secondary color is required'); if (isNil(secondaryColor) || isEmpty(secondaryColor)) {
} errMsg.set('secondary', 'Secondary color is required');
const errorColor = formData.get('error'); }
if (isNil(errorColor) || isEmpty(errorColor)) { const errorColor = formData.get('error') as string;
errMsg.set('error', 'Error color is required'); if (isNil(errorColor) || isEmpty(errorColor)) {
} errMsg.set('error', 'Error color is required');
if (!isEmpty(errMsg)) return errMsg; }
if (!isEmpty(errMsg)) return errMsg;
const customColors: Record<string, string> = {}; const customColors: Record<string, string> = {};
for (const key of colorKeys) { for (const key of colorKeys) {
const name = formData.get(`name_${key}`) as string; const name = formData.get(`name_${key}`) as string;
const color = formData.get(`color_${key}`) as string; const color = formData.get(`color_${key}`) as string;
if (isNil(name) || isEmpty(name) || isNil(color) || isEmpty(color)) continue; if (isNil(name) || isEmpty(name) || isNil(color) || isEmpty(color)) continue;
customColors[name] = color; customColors[name] = color;
} }
const generatedScheme = colorFn?.generate_material_design_2_scheme( const generatedScheme = colorFn?.generate_material_design_2_scheme(
primaryColor, primaryColor,
secondaryColor, secondaryColor,
errorColor, errorColor,
customColors, customColors,
); );
updateScheme((prev) => { updateScheme((prev) => {
prev.schemeStorage.source = { prev.schemeStorage.source = {
primary: primaryColor, primary: primaryColor,
secondary: secondaryColor, secondary: secondaryColor,
error: errorColor, error: errorColor,
custom_colors: customColors, custom_colors: customColors,
}; };
prev.schemeStorage.scheme = merge(generatedScheme[0], { prev.schemeStorage.scheme = merge(generatedScheme[0], {
light: { custom_colors: mapToObject(generatedScheme[0].light.custom_colors) }, light: { custom_colors: mapToObject(generatedScheme[0].light.custom_colors) },
dark: { custom_colors: mapToObject(generatedScheme[0].dark.custom_colors) }, dark: { custom_colors: mapToObject(generatedScheme[0].dark.custom_colors) },
});
prev.schemeStorage.cssVariables = generatedScheme[1];
prev.schemeStorage.scssVariables = generatedScheme[2];
prev.schemeStorage.jsVariables = generatedScheme[3];
return prev;
}); });
prev.schemeStorage.cssVariables = generatedScheme[1];
prev.schemeStorage.scssVariables = generatedScheme[2];
prev.schemeStorage.jsVariables = generatedScheme[3];
return prev;
});
onBuildComplete?.(); onBuildComplete?.();
} catch (e) { } catch (e) {
console.error('[generate m2 scheme]', e); console.error('[generate m2 scheme]', e);
} }
return errMsg; return errMsg;
}, new Map<string, string>()); },
new Map<string, string>(),
);
return ( return (
<ScrollArea enableY> <ScrollArea enableY>

View File

@ -86,8 +86,8 @@ export function M2SchemePreview({ scheme }: M2SchemePreviewProps) {
return ( return (
<ScrollArea enableY> <ScrollArea enableY>
<div className={styles.preview_layout}> <div className={styles.preview_layout}>
<PreviewBlock title="Light" baseline={scheme.schemeStorage.scheme?.light} /> <PreviewBlock title="Light" baseline={scheme.schemeStorage.scheme!.light} />
<PreviewBlock title="Dark" baseline={scheme.schemeStorage.scheme?.dark} /> <PreviewBlock title="Dark" baseline={scheme.schemeStorage.scheme!.dark} />
</div> </div>
</ScrollArea> </ScrollArea>
); );

View File

@ -1,7 +1,7 @@
import { includes, isEmpty, isNil } from 'lodash-es'; import { includes, isEmpty, isNil } from 'lodash-es';
import { useActionState, useCallback, useMemo, useState } from 'react'; import { useActionState, useCallback, useMemo, useState } from 'react';
import { useColorFunction } from '../../../ColorFunctionContext'; import { useColorFunction } from '../../../ColorFunctionContext';
import { FloatColorPicker } from '../../../components/FloatcolorPicker'; import { FloatColorPicker } from '../../../components/FloatColorPicker';
import { ScrollArea } from '../../../components/ScrollArea'; import { ScrollArea } from '../../../components/ScrollArea';
import { MaterialDesign3Scheme, MaterialDesign3SchemeStorage } from '../../../material-3-scheme'; import { MaterialDesign3Scheme, MaterialDesign3SchemeStorage } from '../../../material-3-scheme';
import { SchemeContent } from '../../../models'; import { SchemeContent } from '../../../models';
@ -36,64 +36,67 @@ export function M3SchemeBuilder({ scheme, onBuildCompleted }: M3SchemeBuilderPro
[originalColors, newColors, deleted], [originalColors, newColors, deleted],
); );
const [errMsg, handleSubmitAction] = useActionState((state, formData) => { const [errMsg, handleSubmitAction] = useActionState<Map<string, string>, FormData>(
const errMsg = new Map<string, string>(); (_state, formData) => {
const errMsg = new Map<string, string>();
try { try {
const sourceColor = formData.get('source'); const sourceColor = formData.get('source') as string;
if (isNil(sourceColor) || isEmpty(sourceColor)) { if (isNil(sourceColor) || isEmpty(sourceColor)) {
errMsg.set('source', 'Source color is required'); errMsg.set('source', 'Source color is required');
} }
const errorColor = formData.get('error'); const errorColor = formData.get('error') as string;
if (isNil(errorColor) || isEmpty(errorColor)) { if (isNil(errorColor) || isEmpty(errorColor)) {
errMsg.set('error', 'Error color is required'); errMsg.set('error', 'Error color is required');
} }
if (!isEmpty(errMsg)) return errMsg; if (!isEmpty(errMsg)) return errMsg;
const customColors: Record<string, string> = {}; const customColors: Record<string, string> = {};
for (const key of colorKeys) { for (const key of colorKeys) {
const name = formData.get(`name_${key}`) as string; const name = formData.get(`name_${key}`) as string;
const color = formData.get(`color_${key}`) as string; const color = formData.get(`color_${key}`) as string;
if (isNil(name) || isEmpty(name) || isNil(color) || isEmpty(color)) continue; if (isNil(name) || isEmpty(name) || isNil(color) || isEmpty(color)) continue;
customColors[name] = color; customColors[name] = color;
}
const generatedScheme = colorFn?.generate_material_design_3_scheme(
sourceColor,
errorColor,
customColors,
);
updateScheme((prev) => {
prev.schemeStorage.source = {
source: sourceColor as string,
error: errorColor as string,
custom_colors: customColors,
};
prev.schemeStorage.scheme = {
white: generatedScheme[0].white,
black: generatedScheme[0].black,
light_baseline: {
...generatedScheme[0].light_baseline,
customs: mapToObject(generatedScheme[0].light_baseline.customs),
},
dark_baseline: {
...generatedScheme[0].dark_baseline,
customs: mapToObject(generatedScheme[0].dark_baseline.customs),
},
} as MaterialDesign3Scheme;
prev.schemeStorage.cssVariables = generatedScheme[1];
prev.schemeStorage.scssVariables = generatedScheme[2];
prev.schemeStorage.jsVariables = generatedScheme[3];
return prev;
});
onBuildCompleted?.();
} catch (e) {
console.error('[generate m3 scheme]', e);
} }
const generatedScheme = colorFn?.generate_material_design_3_scheme( return errMsg;
sourceColor, },
errorColor, new Map<string, string>(),
customColors, );
);
updateScheme((prev) => {
prev.schemeStorage.source = {
source: sourceColor as string,
error: errorColor as string,
custom_colors: customColors,
};
prev.schemeStorage.scheme = {
white: generatedScheme[0].white,
black: generatedScheme[0].black,
light_baseline: {
...generatedScheme[0].light_baseline,
customs: mapToObject(generatedScheme[0].light_baseline.customs),
},
dark_baseline: {
...generatedScheme[0].dark_baseline,
customs: mapToObject(generatedScheme[0].dark_baseline.customs),
},
} as MaterialDesign3Scheme;
prev.schemeStorage.cssVariables = generatedScheme[1];
prev.schemeStorage.scssVariables = generatedScheme[2];
prev.schemeStorage.jsVariables = generatedScheme[3];
return prev;
});
onBuildCompleted?.();
} catch (e) {
console.error('[generate m3 scheme]', e);
}
return errMsg;
}, new Map<string, string>());
return ( return (
<ScrollArea enableY> <ScrollArea enableY>

View File

@ -264,8 +264,8 @@ export function M3SchemePreview({ scheme }: M3SchemePreviewProps) {
return ( return (
<ScrollArea enableY> <ScrollArea enableY>
<div className={styles.preview_layout}> <div className={styles.preview_layout}>
<PreviewBlock title="Light Scheme" baseline={scheme.schemeStorage.scheme?.light_baseline} /> <PreviewBlock title="Light Scheme" baseline={scheme.schemeStorage.scheme!.light_baseline} />
<PreviewBlock title="Dark Scheme" baseline={scheme.schemeStorage.scheme?.dark_baseline} /> <PreviewBlock title="Dark Scheme" baseline={scheme.schemeStorage.scheme!.dark_baseline} />
</div> </div>
</ScrollArea> </ScrollArea>
); );

View File

@ -7,7 +7,7 @@ import {
WACGSetting, WACGSetting,
} from '../../../color_functions/color_module'; } from '../../../color_functions/color_module';
import { useColorFunction } from '../../../ColorFunctionContext'; import { useColorFunction } from '../../../ColorFunctionContext';
import { FloatColorPicker } from '../../../components/FloatcolorPicker'; import { FloatColorPicker } from '../../../components/FloatColorPicker';
import { ScrollArea } from '../../../components/ScrollArea'; import { ScrollArea } from '../../../components/ScrollArea';
import { VSegmentedControl } from '../../../components/VSegmentedControl'; import { VSegmentedControl } from '../../../components/VSegmentedControl';
import { SchemeContent } from '../../../models'; import { SchemeContent } from '../../../models';
@ -82,102 +82,105 @@ export function QSchemeBuilder({ scheme, onBuildCompleted }: QSchemeBuilderProps
return []; return [];
}, []); }, []);
const [errMsg, handleSubmitAction] = useActionState((state, formData) => { const [errMsg, handleSubmitAction] = useActionState<Map<string, string>, FormData>(
const errMsg = new Map<string, string>(); (_state, formData) => {
const requiredFields = [ const errMsg = new Map<string, string>();
'primary', const requiredFields = [
'danger', 'primary',
'success', 'danger',
'warn', 'success',
'info', 'warn',
'foreground', 'info',
'background', 'foreground',
]; 'background',
for (const field of requiredFields) { ];
if (!formData.get(field)) { for (const field of requiredFields) {
errMsg.set(field, 'This color is required for scheme generating.'); if (!formData.get(field)) {
errMsg.set(field, 'This color is required for scheme generating.');
}
} }
} if (!isEmpty(errMsg)) return errMsg;
if (!isEmpty(errMsg)) return errMsg; try {
try { const schemeSetting = new SchemeSetting(
const schemeSetting = new SchemeSetting( new ColorShifting(
new ColorShifting( Number(formData.get('hover_chroma')) / 100,
Number(formData.get('hover_chroma')) / 100, Number(formData.get('hover_lightness')) / 100,
Number(formData.get('hover_lightness')) / 100, ),
), new ColorShifting(
new ColorShifting( Number(formData.get('active_chroma')) / 100,
Number(formData.get('active_chroma')) / 100, Number(formData.get('active_lightness')) / 100,
Number(formData.get('active_lightness')) / 100, ),
), new ColorShifting(
new ColorShifting( Number(formData.get('focus_chroma')) / 100,
Number(formData.get('focus_chroma')) / 100, Number(formData.get('focus_lightness')) / 100,
Number(formData.get('focus_lightness')) / 100, ),
), new ColorShifting(
new ColorShifting( Number(formData.get('disabled_chroma')) / 100,
Number(formData.get('disabled_chroma')) / 100, Number(formData.get('disabled_lightness')) / 100,
Number(formData.get('disabled_lightness')) / 100, ),
), new ColorShifting(
new ColorShifting( Number(formData.get('dark_chroma')) / 100,
Number(formData.get('dark_chroma')) / 100, Number(formData.get('dark_lightness')) / 100,
Number(formData.get('dark_lightness')) / 100, ),
), Number(formData.get('expanding')) as ColorExpand,
Number(formData.get('expanding')) as ColorExpand, Number(formData.get('wacg')) as WACGSetting,
Number(formData.get('wacg')) as WACGSetting, );
); const dumpedSetting = schemeSetting.toJsValue() as QSchemeSetting;
const dumpedSetting = schemeSetting.toJsValue() as QSchemeSetting;
const source: QSchemeSource = { const source: QSchemeSource = {
primary: defaultEmptyFormData(formData, 'primary', null), primary: defaultEmptyFormData(formData, 'primary', null),
secondary: defaultEmptyFormData(formData, 'secondary', undefined), secondary: defaultEmptyFormData(formData, 'secondary', null),
tertiary: defaultEmptyFormData(formData, 'tertiary', undefined), tertiary: defaultEmptyFormData(formData, 'tertiary', null),
accent: defaultEmptyFormData(formData, 'accent', undefined), accent: defaultEmptyFormData(formData, 'accent', null),
danger: defaultEmptyFormData(formData, 'danger', null), danger: defaultEmptyFormData(formData, 'danger', null),
success: defaultEmptyFormData(formData, 'success', null), success: defaultEmptyFormData(formData, 'success', null),
warning: defaultEmptyFormData(formData, 'warn', null), warning: defaultEmptyFormData(formData, 'warn', null),
info: defaultEmptyFormData(formData, 'info', null), info: defaultEmptyFormData(formData, 'info', null),
foreground: defaultEmptyFormData(formData, 'foreground', null), foreground: defaultEmptyFormData(formData, 'foreground', null),
background: defaultEmptyFormData(formData, 'background', null), background: defaultEmptyFormData(formData, 'background', null),
setting: dumpedSetting, setting: dumpedSetting,
}; };
const generatedScheme = every([source.secondary, source.tertiary, source.accent], isNil) const generatedScheme = every([source.secondary, source.tertiary, source.accent], isNil)
? colorFn?.generate_q_scheme_automatically( ? colorFn?.generate_q_scheme_automatically(
source.primary, source.primary ?? '',
source.danger, source.danger ?? '',
source.success, source.success ?? '',
source.warning, source.warning ?? '',
source.info, source.info ?? '',
source.foreground, source.foreground ?? '',
source.background, source.background ?? '',
schemeSetting, schemeSetting,
) )
: colorFn?.generate_q_scheme_manually( : colorFn?.generate_q_scheme_manually(
source.primary, source.primary ?? '',
source.secondary ?? undefined, source.secondary ?? undefined,
source.tertiary ?? undefined, source.tertiary ?? undefined,
source.accent ?? undefined, source.accent ?? undefined,
source.danger, source.danger ?? '',
source.success, source.success ?? '',
source.warning, source.warning ?? '',
source.info, source.info ?? '',
source.foreground, source.foreground ?? '',
source.background, source.background ?? '',
schemeSetting, schemeSetting,
); );
updateScheme((prev) => { updateScheme((prev) => {
prev.schemeStorage.source = source; prev.schemeStorage.source = source;
prev.schemeStorage.scheme = generatedScheme[0]; prev.schemeStorage.scheme = generatedScheme[0];
prev.schemeStorage.cssVariables = generatedScheme[1]; prev.schemeStorage.cssVariables = generatedScheme[1];
prev.schemeStorage.scssVariables = generatedScheme[2]; prev.schemeStorage.scssVariables = generatedScheme[2];
prev.schemeStorage.jsVariables = generatedScheme[3]; prev.schemeStorage.jsVariables = generatedScheme[3];
return prev; return prev;
}); });
onBuildCompleted?.(); onBuildCompleted?.();
} catch (e) { } catch (e) {
console.error('[build q scheme]', e); console.error('[build q scheme]', e);
} }
return errMsg; return errMsg;
}, new Map<string, string>()); },
new Map<string, string>(),
);
return ( return (
<ScrollArea enableY> <ScrollArea enableY>

View File

@ -10,7 +10,12 @@ import { ScrollArea } from '../../../components/ScrollArea';
import { Switch } from '../../../components/Switch'; import { Switch } from '../../../components/Switch';
import { SchemeContent } from '../../../models'; import { SchemeContent } from '../../../models';
import { useUpdateScheme } from '../../../stores/schemes'; import { useUpdateScheme } from '../../../stores/schemes';
import { QSwatchEntry, QSwatchSchemeSetting, SwatchSchemeStorage } from '../../../swatch_scheme'; import {
QSwatchEntry,
QSwatchSchemeSetting,
SwatchScheme,
SwatchSchemeStorage,
} from '../../../swatch_scheme';
import { mapToObject } from '../../../utls'; import { mapToObject } from '../../../utls';
import { ColorEntry, IdenticalColorEntry } from '../ColorEntry'; import { ColorEntry, IdenticalColorEntry } from '../ColorEntry';
import styles from './Builder.module.css'; import styles from './Builder.module.css';
@ -64,75 +69,78 @@ export function SwatchSchemeBuilder({ scheme, onBuildCompleted }: SwatchSchemeBu
return null; return null;
}, [scheme.schemeStorage.source]); }, [scheme.schemeStorage.source]);
const [errMsg, handleSubmitAction] = useActionState((state, formData) => { const [errMsg, handleSubmitAction] = useActionState<Map<string, string>, FormData>(
const errMsg = new Map<string, string>(); (_state, formData) => {
const errMsg = new Map<string, string>();
try { try {
const swatchAmount = Number(formData.get('amount')); const swatchAmount = Number(formData.get('amount'));
if (isNaN(swatchAmount) || swatchAmount <= 0) { if (isNaN(swatchAmount) || swatchAmount <= 0) {
errMsg.set('amount', 'MUST be a positive number'); errMsg.set('amount', 'MUST be a positive number');
} }
if (swatchAmount > 30) { if (swatchAmount > 30) {
errMsg.set('amount', 'MUST be less than 30'); errMsg.set('amount', 'MUST be less than 30');
}
const minLightness = Number(formData.get('min_lightness'));
if (isNaN(minLightness) || minLightness < 0 || minLightness > 100) {
errMsg.set('min', 'MUST be a number between 0 and 100');
}
const maxLightness = Number(formData.get('max_lightness'));
if (isNaN(maxLightness) || maxLightness < 0 || maxLightness > 100) {
errMsg.set('max', 'MUST be a number between 0 and 100');
}
const includePrimary = isEqual(formData.get('include_primary'), 'true');
const darkConvertChroma = Number(formData.get('dark_chroma')) / 100.0;
const darkConvertLightness = Number(formData.get('dark_lightness')) / 100.0;
const swatchSetting = new SwatchSchemeSetting(
swatchAmount,
minLightness / 100.0,
maxLightness / 100.0,
includePrimary,
new ColorShifting(darkConvertChroma, darkConvertLightness),
);
const dumpedSettings = swatchSetting.toJsValue() as QSwatchSchemeSetting;
const entries: SwatchEntry[] = [];
for (const key of colorKeys) {
const name = String(formData.get(`name_${key}`));
const color = String(formData.get(`color_${key}`));
if (isEmpty(name) || isEmpty(color)) continue;
entries.push(new SwatchEntry(name, color));
}
const dumpedEntries = entries.map((entry) => entry.toJsValue() as QSwatchEntry);
if (isEmpty(entries)) {
errMsg.set('color', 'At least one color is required');
}
if (!isEmpty(errMsg)) return errMsg;
const generatedScheme = colorFn?.generate_swatch_scheme(entries, swatchSetting);
console.debug('[generated scheme]', generatedScheme);
updateScheme((prev) => {
prev.schemeStorage.source = {
colors: dumpedEntries,
setting: dumpedSettings,
};
prev.schemeStorage.scheme = mapToObject(generatedScheme[0]) as SwatchScheme;
prev.schemeStorage.cssVariables = generatedScheme[1];
prev.schemeStorage.scssVariables = generatedScheme[2];
prev.schemeStorage.jsVariables = generatedScheme[3];
return prev;
});
onBuildCompleted?.();
} catch (e) {
console.error('[build swatch scheme]', e);
} }
const minLightness = Number(formData.get('min_lightness')); return errMsg;
if (isNaN(minLightness) || minLightness < 0 || minLightness > 100) { },
errMsg.set('min', 'MUST be a number between 0 and 100'); new Map<string, string>(),
} );
const maxLightness = Number(formData.get('max_lightness'));
if (isNaN(maxLightness) || maxLightness < 0 || maxLightness > 100) {
errMsg.set('max', 'MUST be a number between 0 and 100');
}
const includePrimary = isEqual(formData.get('include_primary'), 'true');
const darkConvertChroma = Number(formData.get('dark_chroma')) / 100.0;
const darkConvertLightness = Number(formData.get('dark_lightness')) / 100.0;
const swatchSetting = new SwatchSchemeSetting(
swatchAmount,
minLightness / 100.0,
maxLightness / 100.0,
includePrimary,
new ColorShifting(darkConvertChroma, darkConvertLightness),
);
const dumpedSettings = swatchSetting.toJsValue() as QSwatchSchemeSetting;
const entries: SwatchEntry[] = [];
for (const key of colorKeys) {
const name = String(formData.get(`name_${key}`));
const color = String(formData.get(`color_${key}`));
if (isEmpty(name) || isEmpty(color)) continue;
entries.push(new SwatchEntry(name, color));
}
const dumpedEntries = entries.map((entry) => entry.toJsValue() as QSwatchEntry);
if (isEmpty(entries)) {
errMsg.set('color', 'At least one color is required');
}
if (!isEmpty(errMsg)) return errMsg;
const generatedScheme = colorFn?.generate_swatch_scheme(entries, swatchSetting);
console.debug('[generated scheme]', generatedScheme);
updateScheme((prev) => {
prev.schemeStorage.source = {
colors: dumpedEntries,
setting: dumpedSettings,
};
prev.schemeStorage.scheme = mapToObject(generatedScheme[0]);
prev.schemeStorage.cssVariables = generatedScheme[1];
prev.schemeStorage.scssVariables = generatedScheme[2];
prev.schemeStorage.jsVariables = generatedScheme[3];
return prev;
});
onBuildCompleted?.();
} catch (e) {
console.error('[build swatch scheme]', e);
}
return errMsg;
}, new Map<string, string>());
return ( return (
<ScrollArea enableY> <ScrollArea enableY>

View File

@ -54,12 +54,12 @@ export function SwatchSchemePreview({ scheme }: SwatchSchemePreviewProps) {
<h2>Light Scheme</h2> <h2>Light Scheme</h2>
<SchemeBlock <SchemeBlock
amount={scheme.schemeStorage.source?.setting?.amount ?? 0} amount={scheme.schemeStorage.source?.setting?.amount ?? 0}
scheme={scheme.schemeStorage.scheme.light} scheme={scheme.schemeStorage.scheme!.light}
/> />
<h2>Dark Scheme</h2> <h2>Dark Scheme</h2>
<SchemeBlock <SchemeBlock
amount={scheme.schemeStorage.source?.setting?.amount ?? 0} amount={scheme.schemeStorage.source?.setting?.amount ?? 0}
scheme={scheme.schemeStorage.scheme.dark} scheme={scheme.schemeStorage.scheme!.dark}
/> />
</div> </div>
</ScrollArea> </ScrollArea>

View File

@ -23,18 +23,18 @@ export function Shades({ color, shades, mix, step, maximum, copyMode }: ShadesLi
switch (mix) { switch (mix) {
case 'progressive': case 'progressive':
for (let i = 1; i <= shades; i++) { for (let i = 1; i <= shades; i++) {
const shade = colorFn!.shade(last(genColors), step); const shade = colorFn!.shade(last(genColors) ?? '', step ?? 0);
genColors.push(shade); genColors.push(shade);
} }
break; break;
case 'linear': case 'linear':
for (let i = 1; i <= shades; i++) { for (let i = 1; i <= shades; i++) {
const shade = colorFn!.shade(color, step * i); const shade = colorFn!.shade(color, (step ?? 0) * i);
genColors.push(shade); genColors.push(shade);
} }
break; break;
case 'average': { case 'average': {
const interval = maximum / shades / 100; const interval = (maximum ?? 0) / shades / 100;
for (let i = 1; i <= shades; i++) { for (let i = 1; i <= shades; i++) {
const shade = colorFn!.shade(color, interval * i); const shade = colorFn!.shade(color, interval * i);
genColors.push(shade); genColors.push(shade);

View File

@ -23,18 +23,18 @@ export function Tints({ color, tints, mix, step, maximum, copyMode }: TintsListP
switch (mix) { switch (mix) {
case 'progressive': case 'progressive':
for (let i = 1; i <= tints; i++) { for (let i = 1; i <= tints; i++) {
const tint = colorFn!.tint(last(genColors), step); const tint = colorFn!.tint(last(genColors) ?? '', step ?? 0);
genColors.push(tint); genColors.push(tint);
} }
break; break;
case 'linear': case 'linear':
for (let i = 1; i <= tints; i++) { for (let i = 1; i <= tints; i++) {
const tint = colorFn!.tint(color, step * i); const tint = colorFn!.tint(color, (step ?? 0) * i);
genColors.push(tint); genColors.push(tint);
} }
break; break;
case 'average': { case 'average': {
const interval = maximum / tints / 100; const interval = (maximum ?? 0) / tints / 100;
for (let i = 1; i <= tints; i++) { for (let i = 1; i <= tints; i++) {
const tint = colorFn!.tint(color, interval * i); const tint = colorFn!.tint(color, interval * i);
genColors.push(tint); genColors.push(tint);

View File

@ -8,6 +8,7 @@ import { ColorDescription } from '../models';
import { ColorCard } from '../page-components/cards-detail/ColorCard'; import { ColorCard } from '../page-components/cards-detail/ColorCard';
import styles from './CardsDetail.module.css'; import styles from './CardsDetail.module.css';
type ColorModes = 'hex' | 'rgb' | 'hsl' | 'lab' | 'oklch';
type CardsDetailProps = { type CardsDetailProps = {
mainTag: string; mainTag: string;
}; };
@ -20,7 +21,7 @@ export function CardsDetail({ mainTag }: CardsDetailProps) {
} }
try { try {
const embededCategories = colorFn.color_categories() as { label: string; value: string }[]; const embededCategories = colorFn.color_categories() as { label: string; value: string }[];
return embededCategories.filter((cate) => !isEqual(cate.get('value'), 'unknown')); return embededCategories.filter((cate) => !isEqual(cate.value, 'unknown'));
} catch (e) { } catch (e) {
console.error('[Fetch color categories]', e); console.error('[Fetch color categories]', e);
} }
@ -31,7 +32,7 @@ export function CardsDetail({ mainTag }: CardsDetailProps) {
const selectedValue = e.target.value; const selectedValue = e.target.value;
setCategory(selectedValue); setCategory(selectedValue);
}; };
const [mode, setMode] = useState<'hex' | 'rgb' | 'hsl' | 'lab' | 'oklch'>('hex'); const [mode, setMode] = useState<ColorModes>('hex');
const colors = useMemo(() => { const colors = useMemo(() => {
if (!colorFn) { if (!colorFn) {
return []; return [];
@ -69,8 +70,8 @@ export function CardsDetail({ mainTag }: CardsDetailProps) {
onChange={handleSelectCategory}> onChange={handleSelectCategory}>
<option value="null">All</option> <option value="null">All</option>
{categories.map((cate, index) => ( {categories.map((cate, index) => (
<option key={`${cate.get('value')}-${index}`} value={cate.get('value')}> <option key={`${cate.value}-${index}`} value={cate.value}>
{cate.get('label')} {cate.label}
</option> </option>
))} ))}
</select> </select>
@ -85,7 +86,7 @@ export function CardsDetail({ mainTag }: CardsDetailProps) {
{ label: 'OKLCH', value: 'oklch' }, { label: 'OKLCH', value: 'oklch' },
]} ]}
value={mode} value={mode}
onChange={setMode} onChange={(v) => setMode(v as ColorModes)}
/> />
</div> </div>
<ScrollArea enableY> <ScrollArea enableY>

View File

@ -44,7 +44,7 @@ export function ColorCompare() {
{ label: 'Relative', value: 'relative' }, { label: 'Relative', value: 'relative' },
]} ]}
value={analysisMode} value={analysisMode}
onChange={setMode} onChange={(v) => setMode(v as Parameters<typeof setMode>[0])}
/> />
</Labeled> </Labeled>
<RGBCompare basic={basicColor} compare={compareColor} mode={analysisMode} /> <RGBCompare basic={basicColor} compare={compareColor} mode={analysisMode} />

View File

@ -114,7 +114,7 @@ export function Harmonies() {
<div className={styles.mode_navigation}> <div className={styles.mode_navigation}>
<h5>Color selection method</h5> <h5>Color selection method</h5>
<VSegmentedControl <VSegmentedControl
onChange={setSelectedMode} onChange={(v) => setSelectedMode(v as string)}
options={[ options={[
{ label: 'Complementary', value: 'complementary' }, { label: 'Complementary', value: 'complementary' },
{ label: 'Analogous', value: 'analogous' }, { label: 'Analogous', value: 'analogous' },

View File

@ -13,6 +13,8 @@ import { Lightens } from '../page-components/lighten-darken/lightens';
import { currentPickedColor } from '../stores/colors'; import { currentPickedColor } from '../stores/colors';
import styles from './LightenDarken.module.css'; import styles from './LightenDarken.module.css';
type ColorModes = 'hex' | 'rgb' | 'hsl' | 'lab' | 'oklch';
export function LightenDarken() { export function LightenDarken() {
const [selectedColor, setSelectedColor] = useAtom(currentPickedColor); const [selectedColor, setSelectedColor] = useAtom(currentPickedColor);
const [lighten, setLighten] = useState(3); const [lighten, setLighten] = useState(3);
@ -20,7 +22,7 @@ export function LightenDarken() {
const [steps, setSteps] = useState(10); const [steps, setSteps] = useState(10);
const [maximum, setMaximum] = useState(90); const [maximum, setMaximum] = useState(90);
const [mixMode, setMixMode] = useState<'progressive' | 'average'>('progressive'); const [mixMode, setMixMode] = useState<'progressive' | 'average'>('progressive');
const [mode, setMode] = useState<'hex' | 'rgb' | 'hsl' | 'lab' | 'oklch'>('hex'); const [mode, setMode] = useState<ColorModes>('hex');
return ( return (
<div className={cx('workspace', styles.lighten_workspace)}> <div className={cx('workspace', styles.lighten_workspace)}>
@ -123,8 +125,8 @@ export function LightenDarken() {
{ label: 'LAB', value: 'lab' }, { label: 'LAB', value: 'lab' },
{ label: 'OKLCH', value: 'oklch' }, { label: 'OKLCH', value: 'oklch' },
]} ]}
valu={mode} value={mode}
onChange={setMode} onChange={(v) => setMode(v as ColorModes)}
/> />
</div> </div>
</div> </div>

View File

@ -8,12 +8,14 @@ import { LabeledPicker } from '../components/LabeledPicker';
import { ScrollArea } from '../components/ScrollArea'; import { ScrollArea } from '../components/ScrollArea';
import styles from './Mixer.module.css'; import styles from './Mixer.module.css';
type ColorModes = 'hex' | 'rgb' | 'hsl' | 'lab' | 'oklch';
export function Mixer() { export function Mixer() {
const { colorFn } = useColorFunction(); const { colorFn } = useColorFunction();
const [basicColor, setBasicColor] = useState('000000'); const [basicColor, setBasicColor] = useState('000000');
const [mixColor, setMixColor] = useState('000000'); const [mixColor, setMixColor] = useState('000000');
const [mixRatio, setMixRatio] = useState(0); const [mixRatio, setMixRatio] = useState(0);
const [mode, setMode] = useState<'hex' | 'rgb' | 'hsl' | 'lab' | 'oklch'>('hex'); const [mode, setMode] = useState<ColorModes>('hex');
const mixedColor = useMemo(() => { const mixedColor = useMemo(() => {
try { try {
if (!colorFn) { if (!colorFn) {
@ -68,7 +70,7 @@ export function Mixer() {
{ label: 'OKLCH', value: 'oklch' }, { label: 'OKLCH', value: 'oklch' },
]} ]}
value={mode} value={mode}
onChange={setMode} onChange={(v) => setMode(v as ColorModes)}
/> />
</div> </div>
</div> </div>

View File

@ -11,21 +11,24 @@ export function NewScheme() {
const createScheme = useCreateScheme(); const createScheme = useCreateScheme();
const navigate = useNavigate(); const navigate = useNavigate();
const [schemeType, setSchemeType] = useState<SchemeTypeOption['value']>('q_scheme'); const [schemeType, setSchemeType] = useState<SchemeTypeOption['value']>('q_scheme');
const [errors, formAction] = useActionState((prevState, formData) => { const [errors, formAction] = useActionState<{ [key: string]: string }, FormData>(
try { (_prevState, formData): { [key: string]: string } => {
const name = formData.get('name') as string; try {
if (isNil(name) || isEmpty(name)) { const name = formData.get('name') as string;
throw { name: 'Name is required' }; if (isNil(name) || isEmpty(name)) {
throw { name: 'Name is required' };
}
const description = (formData.get('description') ?? null) as string | null;
const schemeType = (formData.get('type') ?? 'q_scheme') as SchemeTypeOption['value'];
const newId = createScheme(name, schemeType, description);
navigate(`../${newId}`);
} catch (error) {
return error as { [key: string]: string };
} }
const description = (formData.get('description') ?? null) as string | null; return {} as { [key: string]: string };
const schemeType = (formData.get('type') ?? 'q_scheme') as SchemeTypeOption['value']; },
const newId = createScheme(name, schemeType, description); {},
navigate(`../${newId}`); );
} catch (error) {
return error;
}
return {};
}, {});
return ( return (
<form action={formAction} className={styles.create_scheme_form_layout}> <form action={formAction} className={styles.create_scheme_form_layout}>
@ -37,7 +40,7 @@ export function NewScheme() {
options={SchemeTypeOptions} options={SchemeTypeOptions}
extendClassName={styles.custom_segment} extendClassName={styles.custom_segment}
value={schemeType} value={schemeType}
onChange={setSchemeType} onChange={(v) => setSchemeType(v as SchemeTypeOption['value'])}
/> />
<input type="hidden" name="type" value={schemeType} /> <input type="hidden" name="type" value={schemeType} />
</div> </div>

View File

@ -11,6 +11,8 @@ import { PaletteColors } from '../page-components/auto-palette/PaletteColors';
import { currentPickedColor } from '../stores/colors'; import { currentPickedColor } from '../stores/colors';
import styles from './Palette.module.css'; import styles from './Palette.module.css';
type ColorModes = 'hex' | 'rgb' | 'hsl' | 'lab' | 'oklch';
export function AutomaticPalette() { export function AutomaticPalette() {
const [selectedColor, setSelectedColor] = useAtom(currentPickedColor); const [selectedColor, setSelectedColor] = useAtom(currentPickedColor);
const [useReferenceColor, setUseReferenceColor] = useState(false); const [useReferenceColor, setUseReferenceColor] = useState(false);
@ -22,7 +24,7 @@ export function AutomaticPalette() {
const [referenceBias, setReferenceBias] = useState(0); const [referenceBias, setReferenceBias] = useState(0);
const [minLightness, setMinLightness] = useState(10); const [minLightness, setMinLightness] = useState(10);
const [maxLightness, setMaxLightness] = useState(90); const [maxLightness, setMaxLightness] = useState(90);
const [mode, setMode] = useState<'hex' | 'rgb' | 'hsl' | 'lab' | 'oklch'>('hex'); const [mode, setMode] = useState<ColorModes>('hex');
useEffect(() => { useEffect(() => {
if (useReferenceColor) { if (useReferenceColor) {
@ -111,8 +113,8 @@ export function AutomaticPalette() {
{ label: 'LAB', value: 'lab' }, { label: 'LAB', value: 'lab' },
{ label: 'OKLCH', value: 'oklch' }, { label: 'OKLCH', value: 'oklch' },
]} ]}
valu={mode} value={mode}
onChange={setMode} onChange={(v) => setMode(v as ColorModes)}
/> />
</div> </div>
</div> </div>

View File

@ -5,12 +5,17 @@ import { useNavigate, useParams } from 'react-router-dom';
import { EditableDescription } from '../components/EditableDescription'; import { EditableDescription } from '../components/EditableDescription';
import { EditableTitle } from '../components/EditableTitle'; import { EditableTitle } from '../components/EditableTitle';
import { SchemeSign } from '../components/SchemeSign'; import { SchemeSign } from '../components/SchemeSign';
import { MaterialDesign2SchemeStorage } from '../material-2-scheme';
import { MaterialDesign3SchemeStorage } from '../material-3-scheme';
import { SchemeContent } from '../models';
import { CorruptedScheme } from '../page-components/scheme/CorruptedScheme'; import { CorruptedScheme } from '../page-components/scheme/CorruptedScheme';
import { M2Scheme } from '../page-components/scheme/M2Scheme'; import { M2Scheme } from '../page-components/scheme/M2Scheme';
import { M3Scheme } from '../page-components/scheme/M3Scheme'; import { M3Scheme } from '../page-components/scheme/M3Scheme';
import { QScheme } from '../page-components/scheme/QScheme'; import { QScheme } from '../page-components/scheme/QScheme';
import { SwatchScheme } from '../page-components/scheme/SwatchScheme'; import { SwatchScheme } from '../page-components/scheme/SwatchScheme';
import { QSchemeStorage } from '../q-scheme';
import { useScheme, useUpdateScheme } from '../stores/schemes'; import { useScheme, useUpdateScheme } from '../stores/schemes';
import { SwatchSchemeStorage } from '../swatch_scheme';
import styles from './SchemeDetail.module.css'; import styles from './SchemeDetail.module.css';
export function SchemeDetail() { export function SchemeDetail() {
@ -40,13 +45,13 @@ export function SchemeDetail() {
const schemeContent = useMemo(() => { const schemeContent = useMemo(() => {
switch (scheme?.type) { switch (scheme?.type) {
case 'q_scheme': case 'q_scheme':
return <QScheme scheme={scheme} />; return <QScheme scheme={scheme as SchemeContent<QSchemeStorage>} />;
case 'swatch_scheme': case 'swatch_scheme':
return <SwatchScheme scheme={scheme} />; return <SwatchScheme scheme={scheme as SchemeContent<SwatchSchemeStorage>} />;
case 'material_2': case 'material_2':
return <M2Scheme scheme={scheme} />; return <M2Scheme scheme={scheme as SchemeContent<MaterialDesign2SchemeStorage>} />;
case 'material_3': case 'material_3':
return <M3Scheme scheme={scheme} />; return <M3Scheme scheme={scheme as SchemeContent<MaterialDesign3SchemeStorage>} />;
default: default:
return <CorruptedScheme />; return <CorruptedScheme />;
} }

View File

@ -13,6 +13,8 @@ import { Tints } from '../page-components/tints-shades/tints';
import { currentPickedColor } from '../stores/colors'; import { currentPickedColor } from '../stores/colors';
import styles from './TintsShades.module.css'; import styles from './TintsShades.module.css';
type ColorModes = 'hex' | 'rgb' | 'hsl' | 'lab' | 'oklch';
export function TintsShades() { export function TintsShades() {
const [selectedColor, setSelectedColor] = useAtom(currentPickedColor); const [selectedColor, setSelectedColor] = useAtom(currentPickedColor);
const [steps, setSteps] = useState(10); const [steps, setSteps] = useState(10);
@ -20,7 +22,7 @@ export function TintsShades() {
const [shades, setShades] = useState(3); const [shades, setShades] = useState(3);
const [maximum, setMaximum] = useState(90); const [maximum, setMaximum] = useState(90);
const [mixMode, setMixMode] = useState<'progressive' | 'average'>('progressive'); const [mixMode, setMixMode] = useState<'progressive' | 'average'>('progressive');
const [mode, setMode] = useState<'hex' | 'rgb' | 'hsl' | 'lab' | 'oklch'>('hex'); const [mode, setMode] = useState<ColorModes>('hex');
return ( return (
<div className={cx('workspace', styles.tints_workspace)}> <div className={cx('workspace', styles.tints_workspace)}>
@ -122,8 +124,8 @@ export function TintsShades() {
{ label: 'LAB', value: 'lab' }, { label: 'LAB', value: 'lab' },
{ label: 'OKLCH', value: 'oklch' }, { label: 'OKLCH', value: 'oklch' },
]} ]}
valu={mode} value={mode}
onChange={setMode} onChange={(v) => setMode(v as ColorModes)}
/> />
</div> </div>
</div> </div>

View File

@ -11,13 +11,15 @@ import { ScrollArea } from '../components/ScrollArea';
import { currentPickedColor } from '../stores/colors'; import { currentPickedColor } from '../stores/colors';
import styles from './Tones.module.css'; import styles from './Tones.module.css';
type ColorModes = 'hex' | 'rgb' | 'hsl' | 'lab' | 'oklch';
export function Tones() { export function Tones() {
const { colorFn } = useColorFunction(); const { colorFn } = useColorFunction();
const [selectedColor, setSelectedColor] = useAtom(currentPickedColor); const [selectedColor, setSelectedColor] = useAtom(currentPickedColor);
const [steps, setSteps] = useState(10); const [steps, setSteps] = useState(10);
const [tones, setTones] = useState(3); const [tones, setTones] = useState(3);
const [seedBias, setSeedBias] = useState(0); const [seedBias, setSeedBias] = useState(0);
const [mode, setMode] = useState<'hex' | 'rgb' | 'hsl' | 'lab' | 'oklch'>('hex'); const [mode, setMode] = useState<ColorModes>('hex');
const colors = useMemo(() => { const colors = useMemo(() => {
try { try {
const lightenColors = colorFn!.tonal_lighten_series( const lightenColors = colorFn!.tonal_lighten_series(
@ -98,8 +100,8 @@ export function Tones() {
{ label: 'LAB', value: 'lab' }, { label: 'LAB', value: 'lab' },
{ label: 'OKLCH', value: 'oklch' }, { label: 'OKLCH', value: 'oklch' },
]} ]}
valu={mode} value={mode}
onChange={setMode} onChange={(v) => setMode(v as ColorModes)}
/> />
</div> </div>
</div> </div>

View File

@ -9,9 +9,11 @@ import { ColorWheel } from '../page-components/wheels/ColorWheel';
import { currentPickedColor } from '../stores/colors'; import { currentPickedColor } from '../stores/colors';
import styles from './Wheels.module.css'; import styles from './Wheels.module.css';
type HighlightMode = Parameters<typeof ColorWheel>[0]['highlightMode'];
export function Wheels() { export function Wheels() {
const [selectedColor, setSelectedColor] = useAtom(currentPickedColor); const [selectedColor, setSelectedColor] = useAtom(currentPickedColor);
const [selectedMode, setSelectedMode] = useState('complementary'); const [selectedMode, setSelectedMode] = useState<HighlightMode>('complementary');
const [steps, setSteps] = useState(10); const [steps, setSteps] = useState(10);
const [tones, setTones] = useState(3); const [tones, setTones] = useState(3);
@ -31,7 +33,7 @@ export function Wheels() {
<div className={styles.mode_navigation}> <div className={styles.mode_navigation}>
<h5>Color selection method</h5> <h5>Color selection method</h5>
<VSegmentedControl <VSegmentedControl
onChange={setSelectedMode} onChange={(v) => setSelectedMode(v as HighlightMode)}
options={[ options={[
{ label: 'Complementary', value: 'complementary' }, { label: 'Complementary', value: 'complementary' },
{ label: 'Analogous', value: 'analogous' }, { label: 'Analogous', value: 'analogous' },

View File

@ -47,7 +47,7 @@ export type QSchemeSource = {
warning: string | null; warning: string | null;
info: string | null; info: string | null;
foreground: string | null; foreground: string | null;
background: strin | nullg; background: string | null;
setting: QSchemeSetting | null; setting: QSchemeSetting | null;
}; };

View File

@ -42,7 +42,10 @@ export type SchemeSet = {
const schemesAtom = atomWithStorage<SchemeContent<SchemeStorage>[]>('schemes', []); const schemesAtom = atomWithStorage<SchemeContent<SchemeStorage>[]>('schemes', []);
export const activeSchemeAtom = atomWithStorage<string | null>('activeScheme', null); export const activeSchemeAtom = atomWithStorage<string | null>('activeScheme', null);
export function useSchemeList(): Pick<SchemeContent<SchemeStorage>, 'id' | 'name' | 'createdAt'>[] { export function useSchemeList(): Pick<
SchemeContent<SchemeStorage>,
'id' | 'name' | 'createdAt' | 'type'
>[] {
const schemes = useAtomValue(schemesAtom); const schemes = useAtomValue(schemesAtom);
const sortedSchemes = useMemo( const sortedSchemes = useMemo(
() => () =>
@ -56,9 +59,12 @@ export function useSchemeList(): Pick<SchemeContent<SchemeStorage>, 'id' | 'name
return sortedSchemes; return sortedSchemes;
} }
export function useScheme(id: string): SchemeContent<SchemeStorage> | null { export function useScheme(id?: string | null): SchemeContent<SchemeStorage> | null {
const schemes = useAtomValue(schemesAtom); const schemes = useAtomValue(schemesAtom);
const scheme = useMemo(() => schemes.find((s) => isEqual(id, s.id)) ?? null, [schemes, id]); const scheme = useMemo(
() => schemes.find((s) => !isNil(id) && isEqual(id, s.id)) ?? null,
[schemes, id],
);
return scheme; return scheme;
} }
@ -71,11 +77,11 @@ export function useActiveScheme(): SchemeContent<SchemeStorage> | null {
export function useCreateScheme(): ( export function useCreateScheme(): (
name: string, name: string,
type: SchemeType, type: SchemeType,
description?: string, description?: string | null,
) => string { ) => string {
const updateSchemes = useSetAtom(schemesAtom); const updateSchemes = useSetAtom(schemesAtom);
const createSchemeAction = useCallback( const createSchemeAction = useCallback(
(name: string, type: SchemeType, description?: string) => { (name: string, type: SchemeType, description?: string | null) => {
const newId = v4(); const newId = v4();
updateSchemes((prev) => [ updateSchemes((prev) => [
...prev.filter((s) => !isNil(s)), ...prev.filter((s) => !isNil(s)),
@ -97,7 +103,7 @@ export function useCreateScheme(): (
} }
export function useUpdateScheme( export function useUpdateScheme(
id: string, id?: string | null,
): (updater: (prev: SchemeContent<SchemeStorage>) => SchemeContent<SchemeStorage>) => void { ): (updater: (prev: SchemeContent<SchemeStorage>) => SchemeContent<SchemeStorage>) => void {
const updateSchemes = useSetAtom(schemesAtom); const updateSchemes = useSetAtom(schemesAtom);
const updateAction = useCallback( const updateAction = useCallback(
@ -107,7 +113,7 @@ export function useUpdateScheme(
prev, prev,
(acc, scheme) => { (acc, scheme) => {
if (!isNil(scheme)) { if (!isNil(scheme)) {
if (isEqual(id, scheme.id)) { if (!isNil(id) && isEqual(id, scheme.id)) {
acc.push(updater(scheme)); acc.push(updater(scheme));
} else { } else {
acc.push(scheme); acc.push(scheme);

View File

@ -1,7 +1,7 @@
import { isEmpty, isNil } from 'lodash-es'; import { isEmpty, isNil } from 'lodash-es';
export function defaultEmptyFormData<D>(formData: FormData, param: string, defaultValue: D): D { export function defaultEmptyFormData<D>(formData: FormData, param: string, defaultValue: D): D {
const value = formData.get(param); const value = formData.get(param) as D;
if (isNil(value) || isEmpty(value)) { if (isNil(value) || isEmpty(value)) {
return defaultValue; return defaultValue;
} }
@ -15,10 +15,8 @@ export function defaultEmptyValue<T, D>(value: T, defaultValue: D): T | D {
return value; return value;
} }
export function mapToObject<K extends string | number | symbol, V>( export function mapToObject<K extends string | number | symbol, V>(map: Map<K, V>): Record<K, V> {
map: Map<K, V>, const obj = {} as Record<K, V>;
): Record<K, V extends Map<unknown, unknown> ? unknown : V> {
const obj: Record<K, V extends Map<unknown, unknown> ? unknown : V> = {};
map.forEach((value, key) => { map.forEach((value, key) => {
if (value instanceof Map) { if (value instanceof Map) {
obj[key] = mapToObject(value); obj[key] = mapToObject(value);

View File

@ -3,10 +3,13 @@
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"target": "ES2020", "target": "ES2020",
"useDefineForClassFields": true, "useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"], "lib": [
"ES2020",
"DOM",
"DOM.Iterable"
],
"module": "ESNext", "module": "ESNext",
"skipLibCheck": true, "skipLibCheck": true,
/* Bundler mode */ /* Bundler mode */
"moduleResolution": "bundler", "moduleResolution": "bundler",
"allowImportingTsExtensions": true, "allowImportingTsExtensions": true,
@ -14,13 +17,14 @@
"moduleDetection": "force", "moduleDetection": "force",
"noEmit": true, "noEmit": true,
"jsx": "react-jsx", "jsx": "react-jsx",
/* Linting */ /* Linting */
"strict": true, "strict": false,
"noUnusedLocals": true, "noUnusedLocals": true,
"noUnusedParameters": true, "noUnusedParameters": true,
"noFallthroughCasesInSwitch": true, "noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true "noUncheckedSideEffectImports": true
}, },
"include": ["src"] "include": [
"src"
]
} }

View File

@ -2,23 +2,25 @@
"compilerOptions": { "compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"target": "ES2022", "target": "ES2022",
"lib": ["ES2023"], "lib": [
"ES2023"
],
"module": "ESNext", "module": "ESNext",
"skipLibCheck": true, "skipLibCheck": true,
/* Bundler mode */ /* Bundler mode */
"moduleResolution": "bundler", "moduleResolution": "bundler",
"allowImportingTsExtensions": true, "allowImportingTsExtensions": true,
"isolatedModules": true, "isolatedModules": true,
"moduleDetection": "force", "moduleDetection": "force",
"noEmit": true, "noEmit": true,
/* Linting */ /* Linting */
"strict": true, "strict": false,
"noUnusedLocals": true, "noUnusedLocals": true,
"noUnusedParameters": true, "noUnusedParameters": true,
"noFallthroughCasesInSwitch": true, "noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true "noUncheckedSideEffectImports": true
}, },
"include": ["vite.config.ts"] "include": [
"vite.config.ts"
]
} }

View File

@ -1,11 +1,11 @@
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react-swc'; import react from '@vitejs/plugin-react-swc';
import { defineConfig } from 'vite';
// https://vite.dev/config/ // https://vite.dev/config/
export default defineConfig({ export default defineConfig({
plugins: [react()], plugins: [react()],
css: { css: {
transform: 'lightningcss', transformer: 'lightningcss',
lightningcss: { lightningcss: {
cssModules: true, cssModules: true,
}, },