@clhaas/palette-kit 0.1.8 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.codex/skills/color-pipeline-implementer/SKILL.md +23 -0
- package/.codex/skills/commit-message-crafter/SKILL.md +63 -0
- package/.codex/skills/commit-message-crafter/references/benchmarks.md +20 -0
- package/.codex/skills/contrast-solver-helper/SKILL.md +20 -0
- package/.codex/skills/exporters-builder/SKILL.md +20 -0
- package/.codex/skills/markdownlint-writer/SKILL.md +32 -0
- package/.codex/skills/phase-implementation-runbook/SKILL.md +92 -0
- package/.codex/skills/type-contract-auditor/SKILL.md +21 -0
- package/.github/skills/review-guide/SKILL.md +23 -0
- package/.github/skills/review-guide/references/review-guide-v0.3.md +629 -0
- package/.markdownlint.json +4 -0
- package/AGENTS.md +16 -0
- package/CHANGELOG.md +34 -0
- package/README.md +79 -169
- package/biome.json +43 -0
- package/dist/cli/args.d.ts +12 -0
- package/dist/cli/args.js +56 -0
- package/dist/cli/args.test.js +22 -0
- package/dist/cli/codegen/__snapshots__/tokens.test.js.snap +87 -0
- package/dist/cli/codegen/tokens.d.ts +12 -0
- package/dist/cli/codegen/tokens.js +139 -0
- package/dist/cli/codegen/tokens.test.d.ts +1 -0
- package/dist/cli/codegen/tokens.test.js +51 -0
- package/dist/cli/config.d.ts +40 -0
- package/dist/cli/config.js +34 -0
- package/dist/cli/validate.d.ts +2 -0
- package/dist/cli/validate.js +33 -0
- package/dist/cli/validate.test.d.ts +1 -0
- package/dist/cli/validate.test.js +40 -0
- package/dist/cli.js +138 -140
- package/dist/contrast/apca.d.ts +2 -2
- package/dist/contrast/apca.js +14 -4
- package/dist/contrast/apca.test.d.ts +1 -0
- package/dist/contrast/apca.test.js +16 -0
- package/dist/contrast/index.d.ts +4 -0
- package/dist/contrast/index.js +4 -0
- package/dist/contrast/scoring.d.ts +4 -0
- package/dist/contrast/scoring.js +31 -0
- package/dist/contrast/scoring.test.d.ts +1 -0
- package/dist/contrast/scoring.test.js +148 -0
- package/dist/contrast/solver.d.ts +13 -0
- package/dist/contrast/solver.js +170 -0
- package/dist/contrast/solver.test.d.ts +1 -0
- package/dist/contrast/solver.test.js +75 -0
- package/dist/contrast/types.d.ts +17 -0
- package/dist/contrast/types.js +1 -0
- package/dist/contrast/utils.d.ts +4 -0
- package/dist/contrast/utils.js +18 -0
- package/dist/contrast/wcag2.d.ts +3 -0
- package/dist/contrast/wcag2.js +19 -0
- package/dist/contrast/wcag2.test.d.ts +1 -0
- package/dist/contrast/wcag2.test.js +17 -0
- package/dist/core/createTheme.d.ts +35 -0
- package/dist/core/createTheme.js +24 -0
- package/dist/core/dx-helpers.test.d.ts +1 -0
- package/dist/core/dx-helpers.test.js +61 -0
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.js +2 -0
- package/dist/core/onSolid.test.d.ts +1 -0
- package/dist/core/onSolid.test.js +118 -0
- package/dist/core/qa.v1.test.d.ts +1 -0
- package/dist/core/qa.v1.test.js +112 -0
- package/dist/core/resolve.d.ts +3 -0
- package/dist/core/resolve.js +8 -0
- package/dist/core/resolve.test.d.ts +1 -0
- package/dist/core/resolve.test.js +89 -0
- package/dist/core/resolveMany.d.ts +8 -0
- package/dist/core/resolveMany.js +17 -0
- package/dist/core/tokenRegistry.d.ts +23 -0
- package/dist/core/tokenRegistry.js +83 -0
- package/dist/core/tokenRegistry.test.d.ts +1 -0
- package/dist/core/tokenRegistry.test.js +133 -0
- package/dist/engine/applyOperators.d.ts +3 -0
- package/dist/engine/applyOperators.js +23 -0
- package/dist/engine/context.d.ts +4 -0
- package/dist/engine/context.js +1 -0
- package/dist/engine/gamut.d.ts +13 -0
- package/dist/engine/gamut.js +101 -0
- package/dist/engine/gamut.test.d.ts +1 -0
- package/dist/engine/gamut.test.js +23 -0
- package/dist/engine/generateScale.d.ts +15 -0
- package/dist/engine/generateScale.js +29 -0
- package/dist/engine/generateScale.test.d.ts +1 -0
- package/dist/engine/generateScale.test.js +32 -0
- package/dist/engine/index.d.ts +8 -0
- package/dist/engine/index.js +4 -0
- package/dist/engine/normalize.d.ts +43 -0
- package/dist/engine/normalize.js +403 -0
- package/dist/engine/normalize.test.d.ts +1 -0
- package/dist/engine/normalize.test.js +136 -0
- package/dist/engine/onSolid.d.ts +3 -0
- package/dist/engine/onSolid.js +110 -0
- package/dist/engine/resolveBaseColor.d.ts +25 -0
- package/dist/engine/resolveBaseColor.js +127 -0
- package/dist/engine/resolveBaseColor.test.d.ts +1 -0
- package/dist/engine/resolveBaseColor.test.js +97 -0
- package/dist/export/__snapshots__/exportTheme.test.js.snap +74 -0
- package/dist/export/exportTheme.d.ts +47 -0
- package/dist/export/exportTheme.js +170 -0
- package/dist/export/exportTheme.test.d.ts +1 -0
- package/dist/export/exportTheme.test.js +118 -0
- package/dist/export/index.d.ts +1 -0
- package/dist/export/index.js +1 -0
- package/dist/export/serializeColor.d.ts +1 -0
- package/dist/export/serializeColor.js +1 -0
- package/dist/export/serializeColor.test.d.ts +1 -0
- package/dist/export/serializeColor.test.js +54 -0
- package/dist/export.d.ts +1 -0
- package/dist/export.js +1 -0
- package/dist/index.d.ts +3 -22
- package/dist/index.js +2 -18
- package/dist/operators/emphasis.d.ts +3 -0
- package/dist/operators/emphasis.js +113 -0
- package/dist/operators/emphasis.test.d.ts +1 -0
- package/dist/operators/emphasis.test.js +69 -0
- package/dist/operators/index.d.ts +3 -0
- package/dist/operators/index.js +2 -0
- package/dist/operators/state.d.ts +3 -0
- package/dist/operators/state.js +102 -0
- package/dist/operators/state.test.d.ts +1 -0
- package/dist/operators/state.test.js +48 -0
- package/dist/operators/types.d.ts +13 -0
- package/dist/operators/types.js +1 -0
- package/dist/operators/utils.d.ts +16 -0
- package/dist/operators/utils.js +23 -0
- package/dist/presets/curves.d.ts +28 -0
- package/dist/presets/curves.js +145 -0
- package/dist/presets/index.d.ts +2 -0
- package/dist/presets/index.js +1 -0
- package/dist/presets/tokens/index.d.ts +3 -0
- package/dist/presets/tokens/index.js +3 -0
- package/dist/presets/tokens/minimal-ui.d.ts +6 -0
- package/dist/presets/tokens/minimal-ui.js +53 -0
- package/dist/presets/tokens/modern-ui.d.ts +5 -0
- package/dist/presets/tokens/modern-ui.js +83 -0
- package/dist/presets/tokens/presets.test.d.ts +1 -0
- package/dist/presets/tokens/presets.test.js +31 -0
- package/dist/presets/tokens/radixLike-ui.d.ts +6 -0
- package/dist/presets/tokens/radixLike-ui.js +77 -0
- package/dist/serialize/index.d.ts +1 -0
- package/dist/serialize/index.js +1 -0
- package/dist/serialize/normalizeOutput.d.ts +6 -0
- package/dist/serialize/normalizeOutput.js +45 -0
- package/dist/serialize/serializeColor.d.ts +21 -0
- package/dist/serialize/serializeColor.js +178 -0
- package/dist/serialize/serializeResolved.test.d.ts +1 -0
- package/dist/serialize/serializeResolved.test.js +45 -0
- package/dist/serialize.d.ts +1 -0
- package/dist/serialize.js +1 -0
- package/dist/types/index.d.ts +187 -0
- package/dist/types/index.js +1 -0
- package/dist/utils/clamp.d.ts +1 -0
- package/dist/utils/clamp.js +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/lerp.d.ts +1 -0
- package/dist/utils/lerp.js +1 -0
- package/dist/utils/parseColor.d.ts +6 -0
- package/dist/utils/parseColor.js +67 -0
- package/dist/utils/parseColor.test.d.ts +1 -0
- package/dist/utils/parseColor.test.js +51 -0
- package/dist/utils/smoothstep.d.ts +1 -0
- package/dist/utils/smoothstep.js +5 -0
- package/package.json +19 -12
- package/planning/phase-10-review.md +550 -0
- package/planning/phase-7-review.md +411 -0
- package/planning/phase-8-review.md +669 -0
- package/planning/phase-9-review.md +564 -0
- package/planning/roadmap-v0.3.md +284 -0
- package/planning/spec-serializer-v0.3.md +324 -0
- package/planning/spec-v0.3.md +305 -0
- package/src/cli/args.test.ts +28 -0
- package/src/cli/args.ts +66 -0
- package/src/cli/codegen/__snapshots__/tokens.test.ts.snap +87 -0
- package/src/cli/codegen/tokens.test.ts +61 -0
- package/src/cli/codegen/tokens.ts +191 -0
- package/src/cli/config.ts +71 -0
- package/src/cli/validate.test.ts +49 -0
- package/src/cli/validate.ts +38 -0
- package/src/cli.ts +183 -0
- package/src/contrast/apca.test.ts +20 -0
- package/src/contrast/apca.ts +26 -0
- package/src/contrast/index.ts +4 -0
- package/src/contrast/scoring.test.ts +188 -0
- package/src/contrast/scoring.ts +48 -0
- package/src/contrast/solver.test.ts +147 -0
- package/src/contrast/solver.ts +235 -0
- package/src/contrast/types.ts +20 -0
- package/src/contrast/utils.ts +28 -0
- package/src/contrast/wcag2.test.ts +21 -0
- package/src/contrast/wcag2.ts +24 -0
- package/src/core/createTheme.ts +78 -0
- package/src/core/dx-helpers.test.ts +82 -0
- package/src/core/index.ts +7 -0
- package/src/core/onSolid.test.ts +146 -0
- package/src/core/qa.v1.test.ts +149 -0
- package/src/core/resolve.test.ts +99 -0
- package/src/core/resolve.ts +11 -0
- package/src/core/resolveMany.ts +22 -0
- package/src/core/tokenRegistry.test.ts +153 -0
- package/src/core/tokenRegistry.ts +114 -0
- package/src/engine/applyOperators.ts +32 -0
- package/src/engine/context.ts +8 -0
- package/src/engine/gamut.test.ts +30 -0
- package/src/engine/gamut.ts +144 -0
- package/src/engine/generateScale.test.ts +46 -0
- package/src/engine/generateScale.ts +48 -0
- package/src/engine/index.ts +8 -0
- package/src/engine/normalize.test.ts +222 -0
- package/src/engine/normalize.ts +550 -0
- package/src/engine/onSolid.ts +178 -0
- package/src/engine/resolveBaseColor.test.ts +117 -0
- package/src/engine/resolveBaseColor.ts +203 -0
- package/src/export/__snapshots__/exportTheme.test.ts.snap +74 -0
- package/src/export/exportTheme.test.ts +144 -0
- package/src/export/exportTheme.ts +251 -0
- package/src/export/index.ts +1 -0
- package/src/export/serializeColor.test.ts +73 -0
- package/src/export/serializeColor.ts +1 -0
- package/src/export.ts +1 -0
- package/src/index.ts +3 -0
- package/src/operators/emphasis.test.ts +85 -0
- package/src/operators/emphasis.ts +132 -0
- package/src/operators/index.ts +3 -0
- package/src/operators/state.test.ts +66 -0
- package/src/operators/state.ts +122 -0
- package/src/operators/types.ts +14 -0
- package/src/operators/utils.ts +44 -0
- package/src/presets/curves.ts +168 -0
- package/src/presets/index.ts +2 -0
- package/src/presets/tokens/index.ts +3 -0
- package/src/presets/tokens/minimal-ui.ts +55 -0
- package/src/presets/tokens/modern-ui.ts +85 -0
- package/src/presets/tokens/presets.test.ts +46 -0
- package/src/presets/tokens/radixLike-ui.ts +79 -0
- package/src/serialize/index.ts +1 -0
- package/src/serialize/normalizeOutput.ts +63 -0
- package/src/serialize/serializeColor.ts +260 -0
- package/src/serialize/serializeResolved.test.ts +57 -0
- package/src/serialize.ts +1 -0
- package/src/types/index.ts +207 -0
- package/src/utils/clamp.ts +2 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/lerp.ts +1 -0
- package/src/utils/parseColor.test.ts +66 -0
- package/src/utils/parseColor.ts +87 -0
- package/src/utils/smoothstep.ts +6 -0
- package/tsconfig.build.json +11 -0
- package/tsconfig.json +15 -0
- package/dist/alpha/generateAlphaScale.d.ts +0 -5
- package/dist/alpha/generateAlphaScale.js +0 -34
- package/dist/contrast/onSolid.d.ts +0 -6
- package/dist/contrast/onSolid.js +0 -28
- package/dist/contrast/solveText.d.ts +0 -2
- package/dist/contrast/solveText.js +0 -31
- package/dist/createTheme.d.ts +0 -38
- package/dist/createTheme.js +0 -148
- package/dist/data/radixSeeds.d.ts +0 -3
- package/dist/data/radixSeeds.js +0 -34
- package/dist/diagnostics/analyzeScale.d.ts +0 -2
- package/dist/diagnostics/analyzeScale.js +0 -7
- package/dist/diagnostics/analyzeTheme.d.ts +0 -2
- package/dist/diagnostics/analyzeTheme.js +0 -35
- package/dist/diagnostics/warnings.d.ts +0 -2
- package/dist/diagnostics/warnings.js +0 -20
- package/dist/engine/curves.d.ts +0 -9
- package/dist/engine/curves.js +0 -48
- package/dist/engine/oklch.d.ts +0 -8
- package/dist/engine/oklch.js +0 -40
- package/dist/engine/templates.d.ts +0 -14
- package/dist/engine/templates.js +0 -45
- package/dist/exporters/selectColorMode.d.ts +0 -2
- package/dist/exporters/selectColorMode.js +0 -19
- package/dist/exporters/toCssVars.d.ts +0 -13
- package/dist/exporters/toCssVars.js +0 -108
- package/dist/exporters/toJson.d.ts +0 -3
- package/dist/exporters/toJson.js +0 -25
- package/dist/exporters/toReactNative.d.ts +0 -54
- package/dist/exporters/toReactNative.js +0 -33
- package/dist/exporters/toTailwind.d.ts +0 -17
- package/dist/exporters/toTailwind.js +0 -111
- package/dist/exporters/toTs.d.ts +0 -3
- package/dist/exporters/toTs.js +0 -43
- package/dist/generateScale.d.ts +0 -48
- package/dist/generateScale.js +0 -274
- package/dist/overlays/generateOverlayScale.d.ts +0 -2
- package/dist/overlays/generateOverlayScale.js +0 -34
- package/dist/text/generateTextScale.d.ts +0 -8
- package/dist/text/generateTextScale.js +0 -18
- package/dist/text/resolveOnBgText.d.ts +0 -9
- package/dist/text/resolveOnBgText.js +0 -28
- package/dist/tokens/presetRadixLikeUi.d.ts +0 -5
- package/dist/tokens/presetRadixLikeUi.js +0 -55
- package/dist/types.d.ts +0 -69
- /package/dist/{types.js → cli/args.test.d.ts} +0 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
|
|
3
|
+
import { parseColor } from "./parseColor.js";
|
|
4
|
+
|
|
5
|
+
describe("parseColor", () => {
|
|
6
|
+
it("parses #fff with alpha 1", () => {
|
|
7
|
+
const result = parseColor("#fff");
|
|
8
|
+
|
|
9
|
+
expect(result.input).toBe("#fff");
|
|
10
|
+
expect(result.srgb.space).toBe("srgb");
|
|
11
|
+
expect(result.srgb.alpha).toBe(1);
|
|
12
|
+
expect(result.srgb.channels[0]).toBeCloseTo(1, 6);
|
|
13
|
+
expect(result.srgb.channels[1]).toBeCloseTo(1, 6);
|
|
14
|
+
expect(result.srgb.channels[2]).toBeCloseTo(1, 6);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it("parses #112233", () => {
|
|
18
|
+
const result = parseColor("#112233");
|
|
19
|
+
|
|
20
|
+
expect(result.srgb.channels[0]).toBeCloseTo(0x11 / 255, 6);
|
|
21
|
+
expect(result.srgb.channels[1]).toBeCloseTo(0x22 / 255, 6);
|
|
22
|
+
expect(result.srgb.channels[2]).toBeCloseTo(0x33 / 255, 6);
|
|
23
|
+
expect(result.srgb.alpha).toBe(1);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("parses #11223380 with alpha", () => {
|
|
27
|
+
const result = parseColor("#11223380");
|
|
28
|
+
|
|
29
|
+
expect(result.srgb.alpha).toBeCloseTo(0x80 / 255, 3);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("normalizes okLch channels", () => {
|
|
33
|
+
const result = parseColor("#ffffff");
|
|
34
|
+
const [l, c, h] = result.okLch.channels;
|
|
35
|
+
|
|
36
|
+
expect(result.okLch.space).toBe("oklch");
|
|
37
|
+
expect(result.okLch.alpha).toBe(1);
|
|
38
|
+
expect(l).toBeGreaterThanOrEqual(0);
|
|
39
|
+
expect(l).toBeLessThanOrEqual(100);
|
|
40
|
+
expect(c).toBeGreaterThanOrEqual(0);
|
|
41
|
+
expect(h).toBeGreaterThanOrEqual(0);
|
|
42
|
+
expect(h).toBeLessThan(360);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("preserves okLch alpha", () => {
|
|
46
|
+
const result = parseColor("#33669980");
|
|
47
|
+
|
|
48
|
+
expect(result.okLch.alpha).toBeCloseTo(0x80 / 255, 3);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("throws on invalid input", () => {
|
|
52
|
+
expect(() => parseColor("#12")).toThrowError(/#12/);
|
|
53
|
+
expect(() => parseColor("#GGGGGG")).toThrowError(/#GGGGGG/);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("includes rgb values when conversion fails", async () => {
|
|
57
|
+
vi.resetModules();
|
|
58
|
+
vi.doMock("culori", () => ({
|
|
59
|
+
converter: () => () => undefined,
|
|
60
|
+
}));
|
|
61
|
+
|
|
62
|
+
const { parseColor: mockedParseColor } = await import("./parseColor.js");
|
|
63
|
+
|
|
64
|
+
expect(() => mockedParseColor("#ffffff")).toThrowError(/r=1, g=1, b=1/);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { converter } from "culori";
|
|
2
|
+
|
|
3
|
+
import type { CssColorString, RawColor } from "../types/index.js";
|
|
4
|
+
|
|
5
|
+
const hexPattern = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
|
|
6
|
+
const toOklch = converter("oklch");
|
|
7
|
+
|
|
8
|
+
const OKLCH_L_MAX = 100;
|
|
9
|
+
const OKLCH_H_MAX = 360;
|
|
10
|
+
const MAX_OKLCH_CHROMA = 0.4;
|
|
11
|
+
const NEGATIVE_CHROMA_EPSILON = 1e-6;
|
|
12
|
+
|
|
13
|
+
const toChannel = (hex: string) => Number.parseInt(hex, 16) / 255;
|
|
14
|
+
|
|
15
|
+
const normalizeHue = (hue: number) => ((hue % OKLCH_H_MAX) + OKLCH_H_MAX) % OKLCH_H_MAX;
|
|
16
|
+
const clamp = (value: number, min: number, max: number) => Math.min(max, Math.max(min, value));
|
|
17
|
+
|
|
18
|
+
export function parseColor(input: CssColorString): {
|
|
19
|
+
input: CssColorString;
|
|
20
|
+
okLch: RawColor;
|
|
21
|
+
srgb: RawColor;
|
|
22
|
+
} {
|
|
23
|
+
const normalizedInput = input.trim();
|
|
24
|
+
|
|
25
|
+
if (!hexPattern.test(normalizedInput)) {
|
|
26
|
+
throw new Error(`Invalid color input: "${input}"`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const hex = normalizedInput.slice(1);
|
|
30
|
+
let r = 0;
|
|
31
|
+
let g = 0;
|
|
32
|
+
let b = 0;
|
|
33
|
+
let alpha = 1;
|
|
34
|
+
|
|
35
|
+
if (hex.length === 3) {
|
|
36
|
+
r = toChannel(`${hex[0]}${hex[0]}`);
|
|
37
|
+
g = toChannel(`${hex[1]}${hex[1]}`);
|
|
38
|
+
b = toChannel(`${hex[2]}${hex[2]}`);
|
|
39
|
+
} else if (hex.length === 6 || hex.length === 8) {
|
|
40
|
+
r = toChannel(hex.slice(0, 2));
|
|
41
|
+
g = toChannel(hex.slice(2, 4));
|
|
42
|
+
b = toChannel(hex.slice(4, 6));
|
|
43
|
+
|
|
44
|
+
if (hex.length === 8) {
|
|
45
|
+
alpha = toChannel(hex.slice(6, 8));
|
|
46
|
+
}
|
|
47
|
+
} else {
|
|
48
|
+
throw new Error(`Invalid hex length: "${normalizedInput}"`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const oklchValue = toOklch({ mode: "rgb", r, g, b });
|
|
52
|
+
|
|
53
|
+
if (!oklchValue) {
|
|
54
|
+
throw new Error(`Unable to convert color input: "${normalizedInput}" (r=${r}, g=${g}, b=${b})`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const l = typeof oklchValue.l === "number" && Number.isFinite(oklchValue.l) ? oklchValue.l : 0;
|
|
58
|
+
const c = typeof oklchValue.c === "number" && Number.isFinite(oklchValue.c) ? oklchValue.c : 0;
|
|
59
|
+
const h = typeof oklchValue.h === "number" && Number.isFinite(oklchValue.h) ? oklchValue.h : 0;
|
|
60
|
+
const scaledLightness = l * 100;
|
|
61
|
+
|
|
62
|
+
if (c < -NEGATIVE_CHROMA_EPSILON) {
|
|
63
|
+
throw new Error(`Invalid OKLCH chroma value: ${c} for "${input}"`);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const okLch: RawColor = {
|
|
67
|
+
space: "oklch",
|
|
68
|
+
channels: [
|
|
69
|
+
clamp(scaledLightness, 0, OKLCH_L_MAX),
|
|
70
|
+
clamp(Math.max(0, c), 0, MAX_OKLCH_CHROMA),
|
|
71
|
+
normalizeHue(h),
|
|
72
|
+
],
|
|
73
|
+
alpha,
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const srgb: RawColor = {
|
|
77
|
+
space: "srgb",
|
|
78
|
+
channels: [r, g, b],
|
|
79
|
+
alpha,
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
input: normalizedInput,
|
|
84
|
+
okLch,
|
|
85
|
+
srgb,
|
|
86
|
+
};
|
|
87
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"declaration": true,
|
|
7
|
+
"strict": true,
|
|
8
|
+
"types": ["node"],
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"forceConsistentCasingInFileNames": true,
|
|
11
|
+
"noEmit": true
|
|
12
|
+
},
|
|
13
|
+
"include": ["src/**/*.ts", "src/**/*.ts"],
|
|
14
|
+
"exclude": ["examples/**", "tests/**", "node_modules/**"]
|
|
15
|
+
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import Color from "colorjs.io";
|
|
2
|
-
const steps = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
|
|
3
|
-
const alphaCurve = {
|
|
4
|
-
1: 0.05,
|
|
5
|
-
2: 0.1,
|
|
6
|
-
3: 0.15,
|
|
7
|
-
4: 0.2,
|
|
8
|
-
5: 0.3,
|
|
9
|
-
6: 0.4,
|
|
10
|
-
7: 0.5,
|
|
11
|
-
8: 0.6,
|
|
12
|
-
9: 0.7,
|
|
13
|
-
10: 0.8,
|
|
14
|
-
11: 0.9,
|
|
15
|
-
12: 0.95,
|
|
16
|
-
};
|
|
17
|
-
function mixWithAlpha(foreground, alpha) {
|
|
18
|
-
const color = new Color(foreground).to("srgb");
|
|
19
|
-
const [r, g, b] = color.coords;
|
|
20
|
-
const hex = new Color({ space: "srgb", coords: [r, g, b], alpha }).toString({
|
|
21
|
-
format: "hex",
|
|
22
|
-
});
|
|
23
|
-
return hex;
|
|
24
|
-
}
|
|
25
|
-
export function generateAlphaScale(base, _background) {
|
|
26
|
-
const light = {};
|
|
27
|
-
const dark = {};
|
|
28
|
-
for (const step of steps) {
|
|
29
|
-
const alpha = alphaCurve[step];
|
|
30
|
-
light[step] = mixWithAlpha(base, alpha);
|
|
31
|
-
dark[step] = mixWithAlpha(base, alpha);
|
|
32
|
-
}
|
|
33
|
-
return { light, dark };
|
|
34
|
-
}
|
package/dist/contrast/onSolid.js
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { apcaContrast } from "./apca.js";
|
|
2
|
-
const white = "#ffffff";
|
|
3
|
-
const black = "#000000";
|
|
4
|
-
const alphaLevels = {
|
|
5
|
-
primary: 0.92,
|
|
6
|
-
secondary: 0.72,
|
|
7
|
-
disabled: 0.48,
|
|
8
|
-
};
|
|
9
|
-
function withAlpha(hex, alpha) {
|
|
10
|
-
const normalized = hex.replace("#", "");
|
|
11
|
-
const alphaHex = Math.round(alpha * 255)
|
|
12
|
-
.toString(16)
|
|
13
|
-
.padStart(2, "0");
|
|
14
|
-
return `#${normalized}${alphaHex}`;
|
|
15
|
-
}
|
|
16
|
-
function chooseTextColor(background) {
|
|
17
|
-
const whiteScore = Math.abs(apcaContrast(white, background));
|
|
18
|
-
const blackScore = Math.abs(apcaContrast(black, background));
|
|
19
|
-
return whiteScore >= blackScore ? white : black;
|
|
20
|
-
}
|
|
21
|
-
export function onSolidTextTokens(background) {
|
|
22
|
-
const base = chooseTextColor(background);
|
|
23
|
-
return {
|
|
24
|
-
primary: withAlpha(base, alphaLevels.primary),
|
|
25
|
-
secondary: withAlpha(base, alphaLevels.secondary),
|
|
26
|
-
disabled: withAlpha(base, alphaLevels.disabled),
|
|
27
|
-
};
|
|
28
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import Color from "colorjs.io";
|
|
2
|
-
import { compressToSrgb, oklchToHex } from "../engine/oklch.js";
|
|
3
|
-
import { apcaContrast } from "./apca.js";
|
|
4
|
-
function clamp(value, min, max) {
|
|
5
|
-
return Math.min(max, Math.max(min, value));
|
|
6
|
-
}
|
|
7
|
-
function adjustLightness(oklch, background, target, maxIterations = 24) {
|
|
8
|
-
const bg = new Color(background).to("oklch");
|
|
9
|
-
const bgL = bg.coords[0] ?? 0;
|
|
10
|
-
const direction = bgL > 0.5 ? -1 : 1;
|
|
11
|
-
let current = { ...oklch };
|
|
12
|
-
for (let i = 0; i < maxIterations; i += 1) {
|
|
13
|
-
const contrast = Math.abs(apcaContrast(oklchToHex(current), background));
|
|
14
|
-
if (contrast >= target) {
|
|
15
|
-
return current;
|
|
16
|
-
}
|
|
17
|
-
current = {
|
|
18
|
-
...current,
|
|
19
|
-
l: clamp(current.l + direction * 0.02, 0, 1),
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
return current;
|
|
23
|
-
}
|
|
24
|
-
export function adjustTextColor(foreground, background, target) {
|
|
25
|
-
const fg = new Color(foreground).to("oklch");
|
|
26
|
-
const [l, c, h] = fg.coords;
|
|
27
|
-
let candidate = { l: l ?? 0, c: c ?? 0, h: h ?? 0 };
|
|
28
|
-
candidate = adjustLightness(candidate, background, target);
|
|
29
|
-
candidate = compressToSrgb(candidate);
|
|
30
|
-
return oklchToHex(candidate);
|
|
31
|
-
}
|
package/dist/createTheme.d.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import type { GenerateScaleOptions } from "./generateScale.js";
|
|
2
|
-
import type { ColorHex, ColorSource, Theme } from "./types.js";
|
|
3
|
-
export type TokenOverrides = {
|
|
4
|
-
light?: Record<string, ColorHex>;
|
|
5
|
-
dark?: Record<string, ColorHex>;
|
|
6
|
-
};
|
|
7
|
-
export type CreateThemeOptions = {
|
|
8
|
-
neutral: ColorSource;
|
|
9
|
-
accent: ColorSource;
|
|
10
|
-
semantic?: {
|
|
11
|
-
success?: ColorSource;
|
|
12
|
-
warning?: ColorSource;
|
|
13
|
-
danger?: ColorSource;
|
|
14
|
-
};
|
|
15
|
-
extras?: Record<string, ColorSource>;
|
|
16
|
-
tokens?: {
|
|
17
|
-
preset?: "radix-like-ui";
|
|
18
|
-
overrides?: TokenOverrides;
|
|
19
|
-
};
|
|
20
|
-
alpha?: {
|
|
21
|
-
enabled?: boolean;
|
|
22
|
-
background?: {
|
|
23
|
-
light?: ColorHex;
|
|
24
|
-
dark?: ColorHex;
|
|
25
|
-
};
|
|
26
|
-
};
|
|
27
|
-
text?: {
|
|
28
|
-
darkBase?: ColorHex;
|
|
29
|
-
lightBase?: ColorHex;
|
|
30
|
-
};
|
|
31
|
-
contrast?: {
|
|
32
|
-
textPrimary?: number;
|
|
33
|
-
textSecondary?: number;
|
|
34
|
-
};
|
|
35
|
-
scale?: Omit<GenerateScaleOptions, "source" | "mode" | "p3">;
|
|
36
|
-
p3?: boolean;
|
|
37
|
-
};
|
|
38
|
-
export declare function createTheme(options: CreateThemeOptions): Theme;
|
package/dist/createTheme.js
DELETED
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
import { generateAlphaScale } from "./alpha/generateAlphaScale.js";
|
|
2
|
-
import { onSolidTextTokens } from "./contrast/onSolid.js";
|
|
3
|
-
import { analyzeTheme } from "./diagnostics/analyzeTheme.js";
|
|
4
|
-
import { generateScale } from "./generateScale.js";
|
|
5
|
-
import { generateOverlayScale } from "./overlays/generateOverlayScale.js";
|
|
6
|
-
import { generateTextScale } from "./text/generateTextScale.js";
|
|
7
|
-
import { buildPresetTokens } from "./tokens/presetRadixLikeUi.js";
|
|
8
|
-
export function createTheme(options) {
|
|
9
|
-
const includeP3 = options.p3 ?? false;
|
|
10
|
-
const scaleOptions = options.scale ?? {};
|
|
11
|
-
const scales = {
|
|
12
|
-
neutral: generateScale({ source: options.neutral, ...scaleOptions, p3: includeP3 }),
|
|
13
|
-
accent: generateScale({ source: options.accent, ...scaleOptions, p3: includeP3 }),
|
|
14
|
-
};
|
|
15
|
-
if (options.semantic?.success) {
|
|
16
|
-
scales.success = generateScale({
|
|
17
|
-
source: options.semantic.success,
|
|
18
|
-
...scaleOptions,
|
|
19
|
-
p3: includeP3,
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
if (options.semantic?.warning) {
|
|
23
|
-
scales.warning = generateScale({
|
|
24
|
-
source: options.semantic.warning,
|
|
25
|
-
...scaleOptions,
|
|
26
|
-
p3: includeP3,
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
if (options.semantic?.danger) {
|
|
30
|
-
scales.danger = generateScale({
|
|
31
|
-
source: options.semantic.danger,
|
|
32
|
-
...scaleOptions,
|
|
33
|
-
p3: includeP3,
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
if (options.extras) {
|
|
37
|
-
for (const [key, source] of Object.entries(options.extras)) {
|
|
38
|
-
scales[key] = generateScale({ source, ...scaleOptions, p3: includeP3 });
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
const preset = options.tokens?.preset ?? "radix-like-ui";
|
|
42
|
-
const tokens = preset === "radix-like-ui" ? buildPresetTokens(scales) : { light: {}, dark: {} };
|
|
43
|
-
const accentScale = scales.accent;
|
|
44
|
-
const lightOnSolid = onSolidTextTokens(accentScale.light[9]);
|
|
45
|
-
const darkOnSolid = onSolidTextTokens(accentScale.dark[9]);
|
|
46
|
-
tokens.light["onSolid.primary"] = lightOnSolid.primary;
|
|
47
|
-
tokens.light["onSolid.secondary"] = lightOnSolid.secondary;
|
|
48
|
-
tokens.light["onSolid.disabled"] = lightOnSolid.disabled;
|
|
49
|
-
tokens.dark["onSolid.primary"] = darkOnSolid.primary;
|
|
50
|
-
tokens.dark["onSolid.secondary"] = darkOnSolid.secondary;
|
|
51
|
-
tokens.dark["onSolid.disabled"] = darkOnSolid.disabled;
|
|
52
|
-
const textScale = generateTextScale({
|
|
53
|
-
darkBase: options.text?.darkBase,
|
|
54
|
-
lightBase: options.text?.lightBase,
|
|
55
|
-
});
|
|
56
|
-
const darkTextSteps = {
|
|
57
|
-
primary: 12,
|
|
58
|
-
secondary: 10,
|
|
59
|
-
tertiary: 9,
|
|
60
|
-
disabled: 8,
|
|
61
|
-
};
|
|
62
|
-
const lightTextSteps = {
|
|
63
|
-
primary: 1,
|
|
64
|
-
secondary: 3,
|
|
65
|
-
tertiary: 4,
|
|
66
|
-
disabled: 5,
|
|
67
|
-
};
|
|
68
|
-
const midDarkTextSteps = {
|
|
69
|
-
primary: 12,
|
|
70
|
-
secondary: 11,
|
|
71
|
-
};
|
|
72
|
-
const midLightTextSteps = {
|
|
73
|
-
primary: 1,
|
|
74
|
-
secondary: 3,
|
|
75
|
-
};
|
|
76
|
-
const onBgLightMode = {
|
|
77
|
-
light: { scale: "dark", steps: darkTextSteps },
|
|
78
|
-
mid: { scale: "dark", steps: midDarkTextSteps },
|
|
79
|
-
dark: { scale: "light", steps: lightTextSteps },
|
|
80
|
-
};
|
|
81
|
-
const onBgDarkMode = {
|
|
82
|
-
light: { scale: "light", steps: lightTextSteps },
|
|
83
|
-
mid: { scale: "light", steps: midLightTextSteps },
|
|
84
|
-
dark: { scale: "dark", steps: darkTextSteps },
|
|
85
|
-
};
|
|
86
|
-
const applyOnBgTokens = (target, mapping) => {
|
|
87
|
-
for (const [zone, config] of Object.entries(mapping)) {
|
|
88
|
-
const scale = config.scale === "dark" ? textScale.dark : textScale.light;
|
|
89
|
-
for (const [role, step] of Object.entries(config.steps)) {
|
|
90
|
-
target[`text.onBg.${zone}.${role}`] = scale[step];
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
};
|
|
94
|
-
for (const [step, value] of Object.entries(textScale.dark)) {
|
|
95
|
-
tokens.light[`text.dark.${step}`] = value;
|
|
96
|
-
tokens.dark[`text.dark.${step}`] = value;
|
|
97
|
-
}
|
|
98
|
-
for (const [step, value] of Object.entries(textScale.light)) {
|
|
99
|
-
tokens.light[`text.light.${step}`] = value;
|
|
100
|
-
tokens.dark[`text.light.${step}`] = value;
|
|
101
|
-
}
|
|
102
|
-
for (const [key, step] of Object.entries(darkTextSteps)) {
|
|
103
|
-
const token = `text.dark.${key}`;
|
|
104
|
-
tokens.light[token] = textScale.dark[step];
|
|
105
|
-
tokens.dark[token] = textScale.dark[step];
|
|
106
|
-
}
|
|
107
|
-
for (const [key, step] of Object.entries(lightTextSteps)) {
|
|
108
|
-
const token = `text.light.${key}`;
|
|
109
|
-
tokens.light[token] = textScale.light[step];
|
|
110
|
-
tokens.dark[token] = textScale.light[step];
|
|
111
|
-
}
|
|
112
|
-
applyOnBgTokens(tokens.light, onBgLightMode);
|
|
113
|
-
applyOnBgTokens(tokens.dark, onBgDarkMode);
|
|
114
|
-
tokens.light["text.primary"] = tokens.light["text.onBg.light.primary"];
|
|
115
|
-
tokens.light["text.secondary"] = tokens.light["text.onBg.light.secondary"];
|
|
116
|
-
tokens.light["text.tertiary"] = tokens.light["text.onBg.light.tertiary"];
|
|
117
|
-
tokens.light["text.disabled"] = tokens.light["text.onBg.light.disabled"];
|
|
118
|
-
tokens.dark["text.primary"] = tokens.dark["text.onBg.light.primary"];
|
|
119
|
-
tokens.dark["text.secondary"] = tokens.dark["text.onBg.light.secondary"];
|
|
120
|
-
tokens.dark["text.tertiary"] = tokens.dark["text.onBg.light.tertiary"];
|
|
121
|
-
tokens.dark["text.disabled"] = tokens.dark["text.onBg.light.disabled"];
|
|
122
|
-
if (options.tokens?.overrides?.light) {
|
|
123
|
-
Object.assign(tokens.light, options.tokens.overrides.light);
|
|
124
|
-
}
|
|
125
|
-
if (options.tokens?.overrides?.dark) {
|
|
126
|
-
Object.assign(tokens.dark, options.tokens.overrides.dark);
|
|
127
|
-
}
|
|
128
|
-
let alpha;
|
|
129
|
-
if (options.alpha?.enabled !== false) {
|
|
130
|
-
const background = {
|
|
131
|
-
light: options.alpha?.background?.light ?? "#ffffff",
|
|
132
|
-
dark: options.alpha?.background?.dark ?? "#111111",
|
|
133
|
-
};
|
|
134
|
-
alpha = Object.fromEntries(Object.entries(scales).map(([slot, scale]) => [
|
|
135
|
-
slot,
|
|
136
|
-
generateAlphaScale(scale.light[9], background),
|
|
137
|
-
]));
|
|
138
|
-
}
|
|
139
|
-
const overlay = generateOverlayScale();
|
|
140
|
-
const diagnostics = analyzeTheme({ scales, tokens, alpha, overlay });
|
|
141
|
-
return {
|
|
142
|
-
scales,
|
|
143
|
-
tokens,
|
|
144
|
-
alpha,
|
|
145
|
-
overlay,
|
|
146
|
-
diagnostics,
|
|
147
|
-
};
|
|
148
|
-
}
|
package/dist/data/radixSeeds.js
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
export const radixSeeds = {
|
|
2
|
-
amber: "#ffc53d",
|
|
3
|
-
blue: "#0090ff",
|
|
4
|
-
bronze: "#a18072",
|
|
5
|
-
brown: "#ad7f58",
|
|
6
|
-
crimson: "#e93d82",
|
|
7
|
-
cyan: "#00a2c7",
|
|
8
|
-
gold: "#978365",
|
|
9
|
-
grass: "#46a758",
|
|
10
|
-
gray: "#8d8d8d",
|
|
11
|
-
green: "#30a46c",
|
|
12
|
-
indigo: "#3e63dd",
|
|
13
|
-
iris: "#5b5bd6",
|
|
14
|
-
jade: "#29a383",
|
|
15
|
-
lime: "#bdee63",
|
|
16
|
-
mauve: "#8e8c99",
|
|
17
|
-
mint: "#86ead4",
|
|
18
|
-
olive: "#898e87",
|
|
19
|
-
orange: "#f76b15",
|
|
20
|
-
pink: "#d6409f",
|
|
21
|
-
plum: "#ab4aba",
|
|
22
|
-
purple: "#8e4ec6",
|
|
23
|
-
red: "#e5484d",
|
|
24
|
-
ruby: "#e54666",
|
|
25
|
-
sage: "#868e8b",
|
|
26
|
-
sand: "#8d8d86",
|
|
27
|
-
sky: "#7ce2fe",
|
|
28
|
-
slate: "#8b8d98",
|
|
29
|
-
teal: "#12a594",
|
|
30
|
-
tomato: "#e54d2e",
|
|
31
|
-
violet: "#6e56cf",
|
|
32
|
-
yellow: "#ffe629",
|
|
33
|
-
};
|
|
34
|
-
export const radixSeedNames = Object.keys(radixSeeds).sort();
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { apcaContrast } from "../contrast/apca.js";
|
|
2
|
-
import { analyzeWarnings } from "./warnings.js";
|
|
3
|
-
export function analyzeTheme(theme) {
|
|
4
|
-
const contrast = {};
|
|
5
|
-
const lightBg = theme.tokens.light["bg.app"];
|
|
6
|
-
const darkBg = theme.tokens.dark["bg.app"];
|
|
7
|
-
if (lightBg) {
|
|
8
|
-
if (theme.tokens.light["text.primary"]) {
|
|
9
|
-
contrast["light.text.primary"] = apcaContrast(theme.tokens.light["text.primary"], lightBg);
|
|
10
|
-
}
|
|
11
|
-
if (theme.tokens.light["text.secondary"]) {
|
|
12
|
-
contrast["light.text.secondary"] = apcaContrast(theme.tokens.light["text.secondary"], lightBg);
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
if (darkBg) {
|
|
16
|
-
if (theme.tokens.dark["text.primary"]) {
|
|
17
|
-
contrast["dark.text.primary"] = apcaContrast(theme.tokens.dark["text.primary"], darkBg);
|
|
18
|
-
}
|
|
19
|
-
if (theme.tokens.dark["text.secondary"]) {
|
|
20
|
-
contrast["dark.text.secondary"] = apcaContrast(theme.tokens.dark["text.secondary"], darkBg);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
if (theme.tokens.light["onSolid.primary"] && theme.tokens.light["accent.solid"]) {
|
|
24
|
-
contrast["light.onSolid.primary"] = apcaContrast(theme.tokens.light["onSolid.primary"], theme.tokens.light["accent.solid"]);
|
|
25
|
-
}
|
|
26
|
-
if (theme.tokens.dark["onSolid.primary"] && theme.tokens.dark["accent.solid"]) {
|
|
27
|
-
contrast["dark.onSolid.primary"] = apcaContrast(theme.tokens.dark["onSolid.primary"], theme.tokens.dark["accent.solid"]);
|
|
28
|
-
}
|
|
29
|
-
let outOfGamutCount = 0;
|
|
30
|
-
for (const scale of Object.values(theme.scales)) {
|
|
31
|
-
outOfGamutCount += scale.meta?.outOfGamutCount ?? 0;
|
|
32
|
-
}
|
|
33
|
-
const warnings = analyzeWarnings(theme);
|
|
34
|
-
return { contrast, outOfGamutCount, warnings };
|
|
35
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import Color from "colorjs.io";
|
|
2
|
-
export function analyzeWarnings(theme) {
|
|
3
|
-
const warnings = [];
|
|
4
|
-
const accent = theme.scales.accent?.light?.[9];
|
|
5
|
-
if (accent) {
|
|
6
|
-
const { coords } = new Color(accent).to("oklch");
|
|
7
|
-
const l = coords[0] ?? 0;
|
|
8
|
-
const c = coords[1] ?? 0;
|
|
9
|
-
if (c < 0.03) {
|
|
10
|
-
warnings.push("Accent seed has very low chroma; the palette may look gray.");
|
|
11
|
-
}
|
|
12
|
-
if (l < 0.2) {
|
|
13
|
-
warnings.push("Accent seed is very dark; light mode solids may lack contrast.");
|
|
14
|
-
}
|
|
15
|
-
if (l > 0.9) {
|
|
16
|
-
warnings.push("Accent seed is very light; dark mode solids may lack contrast.");
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
return warnings;
|
|
20
|
-
}
|
package/dist/engine/curves.d.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { Step } from "../types.js";
|
|
2
|
-
export type CurveConfig = {
|
|
3
|
-
lightness?: Partial<Record<Step, number>>;
|
|
4
|
-
chroma?: Partial<Record<Step, number>>;
|
|
5
|
-
};
|
|
6
|
-
export declare function resolveCurves(curves?: CurveConfig): {
|
|
7
|
-
lightness: Record<Step, number>;
|
|
8
|
-
chroma: Record<Step, number>;
|
|
9
|
-
};
|
package/dist/engine/curves.js
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
const steps = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
|
|
2
|
-
const defaultLightness = {
|
|
3
|
-
1: 0.3,
|
|
4
|
-
2: 0.3,
|
|
5
|
-
3: 0.6,
|
|
6
|
-
4: 0.6,
|
|
7
|
-
5: 0.6,
|
|
8
|
-
6: 0.85,
|
|
9
|
-
7: 0.85,
|
|
10
|
-
8: 0.85,
|
|
11
|
-
9: 1,
|
|
12
|
-
10: 1,
|
|
13
|
-
11: 1,
|
|
14
|
-
12: 1,
|
|
15
|
-
};
|
|
16
|
-
const defaultChroma = {
|
|
17
|
-
1: 0.2,
|
|
18
|
-
2: 0.2,
|
|
19
|
-
3: 0.6,
|
|
20
|
-
4: 0.6,
|
|
21
|
-
5: 0.6,
|
|
22
|
-
6: 0.8,
|
|
23
|
-
7: 0.8,
|
|
24
|
-
8: 0.8,
|
|
25
|
-
9: 1,
|
|
26
|
-
10: 1,
|
|
27
|
-
11: 0.7,
|
|
28
|
-
12: 0.7,
|
|
29
|
-
};
|
|
30
|
-
export function resolveCurves(curves) {
|
|
31
|
-
const lightness = { ...defaultLightness };
|
|
32
|
-
const chroma = { ...defaultChroma };
|
|
33
|
-
if (curves?.lightness) {
|
|
34
|
-
for (const step of steps) {
|
|
35
|
-
if (curves.lightness[step] !== undefined) {
|
|
36
|
-
lightness[step] = curves.lightness[step];
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
if (curves?.chroma) {
|
|
41
|
-
for (const step of steps) {
|
|
42
|
-
if (curves.chroma[step] !== undefined) {
|
|
43
|
-
chroma[step] = curves.chroma[step];
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
return { lightness, chroma };
|
|
48
|
-
}
|