@clhaas/palette-kit 0.3.0 → 0.4.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/CHANGELOG.md +25 -0
- package/README.md +80 -87
- package/dist/contrast/contrast.d.ts +16 -0
- package/dist/contrast/contrast.js +102 -0
- package/dist/core/intent-registry.d.ts +11 -0
- package/dist/core/intent-registry.js +70 -0
- package/dist/core/oklch.d.ts +16 -0
- package/dist/core/oklch.js +56 -0
- package/dist/create-palette-kit.d.ts +9 -0
- package/dist/create-palette-kit.js +67 -0
- package/dist/engine/context/context.d.ts +13 -0
- package/dist/engine/context/context.js +37 -0
- package/dist/engine/level/curves.d.ts +17 -0
- package/dist/engine/level/curves.js +49 -0
- package/dist/engine/level/level.d.ts +4 -0
- package/dist/engine/level/level.js +13 -0
- package/dist/engine/relation/relation.d.ts +105 -0
- package/dist/engine/relation/relation.js +137 -0
- package/dist/engine/resolve/resolve.d.ts +36 -0
- package/dist/engine/resolve/resolve.js +116 -0
- package/dist/engine/state/state.d.ts +46 -0
- package/dist/engine/state/state.js +68 -0
- package/dist/engine/usage/fill.d.ts +9 -0
- package/dist/engine/usage/fill.js +9 -0
- package/dist/engine/usage/lines.d.ts +9 -0
- package/dist/engine/usage/lines.js +9 -0
- package/dist/engine/usage/overlays.d.ts +9 -0
- package/dist/engine/usage/overlays.js +9 -0
- package/dist/engine/usage/strategy.d.ts +56 -0
- package/dist/engine/usage/strategy.js +30 -0
- package/dist/engine/usage/visualVocabulary.d.ts +9 -0
- package/dist/engine/usage/visualVocabulary.js +9 -0
- package/dist/export/serialize.d.ts +14 -0
- package/dist/export/serialize.js +89 -0
- package/dist/export/types.d.ts +37 -0
- package/dist/export/types.js +31 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/operators/convert.d.ts +32 -0
- package/dist/operators/convert.js +80 -0
- package/dist/presets/presets.d.ts +95 -0
- package/dist/presets/presets.js +308 -0
- package/dist/types/index.d.ts +111 -187
- package/dist/utils/errors/errors.d.ts +17 -0
- package/dist/utils/errors/errors.js +22 -0
- package/docs/API.md +167 -0
- package/docs/Alpha.md +14 -0
- package/docs/Architecture.md +56 -0
- package/docs/CLI.md +22 -0
- package/docs/Concepts.md +73 -0
- package/docs/Config.md +144 -0
- package/docs/Diagnostics.md +22 -0
- package/docs/Exporters.md +33 -0
- package/docs/FAQ.md +59 -0
- package/docs/Migration.md +61 -0
- package/docs/Overlays.md +33 -0
- package/docs/README.md +60 -0
- package/docs/Text.md +41 -0
- package/docs/Tokens.md +42 -0
- package/docs/Usage-JSON.md +39 -0
- package/docs/Usage-ReactNative.md +63 -0
- package/docs/Usage-Web.md +66 -0
- package/docs/Validation.md +97 -0
- package/docs/Why.md +37 -0
- package/docs/_api-surface.md +53 -0
- package/docs/snippets/serialize-oklch.md +9 -0
- package/docs/spec.md +98 -0
- package/package.json +74 -59
- package/.codex/skills/color-pipeline-implementer/SKILL.md +0 -23
- package/.codex/skills/commit-message-crafter/SKILL.md +0 -63
- package/.codex/skills/commit-message-crafter/references/benchmarks.md +0 -20
- package/.codex/skills/contrast-solver-helper/SKILL.md +0 -20
- package/.codex/skills/exporters-builder/SKILL.md +0 -20
- package/.codex/skills/markdownlint-writer/SKILL.md +0 -32
- package/.codex/skills/phase-implementation-runbook/SKILL.md +0 -92
- package/.codex/skills/type-contract-auditor/SKILL.md +0 -21
- package/.github/skills/review-guide/SKILL.md +0 -23
- package/.github/skills/review-guide/references/review-guide-v0.3.md +0 -629
- package/.markdownlint.json +0 -4
- package/AGENTS.md +0 -16
- package/biome.json +0 -43
- package/dist/cli/args.d.ts +0 -12
- package/dist/cli/args.js +0 -56
- package/dist/cli/args.test.d.ts +0 -1
- package/dist/cli/args.test.js +0 -22
- package/dist/cli/codegen/__snapshots__/tokens.test.js.snap +0 -87
- package/dist/cli/codegen/tokens.d.ts +0 -12
- package/dist/cli/codegen/tokens.js +0 -139
- package/dist/cli/codegen/tokens.test.d.ts +0 -1
- package/dist/cli/codegen/tokens.test.js +0 -51
- package/dist/cli/config.d.ts +0 -40
- package/dist/cli/config.js +0 -34
- package/dist/cli/validate.d.ts +0 -2
- package/dist/cli/validate.js +0 -33
- package/dist/cli/validate.test.d.ts +0 -1
- package/dist/cli/validate.test.js +0 -40
- package/dist/cli.d.ts +0 -2
- package/dist/cli.js +0 -148
- package/dist/contrast/apca.d.ts +0 -2
- package/dist/contrast/apca.js +0 -15
- package/dist/contrast/apca.test.d.ts +0 -1
- package/dist/contrast/apca.test.js +0 -16
- package/dist/contrast/index.d.ts +0 -4
- package/dist/contrast/index.js +0 -4
- package/dist/contrast/scoring.d.ts +0 -4
- package/dist/contrast/scoring.js +0 -31
- package/dist/contrast/scoring.test.d.ts +0 -1
- package/dist/contrast/scoring.test.js +0 -148
- package/dist/contrast/solver.d.ts +0 -13
- package/dist/contrast/solver.js +0 -170
- package/dist/contrast/solver.test.d.ts +0 -1
- package/dist/contrast/solver.test.js +0 -75
- package/dist/contrast/types.d.ts +0 -17
- package/dist/contrast/types.js +0 -1
- package/dist/contrast/utils.d.ts +0 -4
- package/dist/contrast/utils.js +0 -18
- package/dist/contrast/wcag2.d.ts +0 -3
- package/dist/contrast/wcag2.js +0 -19
- package/dist/contrast/wcag2.test.d.ts +0 -1
- package/dist/contrast/wcag2.test.js +0 -17
- package/dist/core/createTheme.d.ts +0 -35
- package/dist/core/createTheme.js +0 -24
- package/dist/core/dx-helpers.test.d.ts +0 -1
- package/dist/core/dx-helpers.test.js +0 -61
- package/dist/core/index.d.ts +0 -2
- package/dist/core/index.js +0 -2
- package/dist/core/onSolid.test.d.ts +0 -1
- package/dist/core/onSolid.test.js +0 -118
- package/dist/core/qa.v1.test.d.ts +0 -1
- package/dist/core/qa.v1.test.js +0 -112
- package/dist/core/resolve.d.ts +0 -3
- package/dist/core/resolve.js +0 -8
- package/dist/core/resolve.test.d.ts +0 -1
- package/dist/core/resolve.test.js +0 -89
- package/dist/core/resolveMany.d.ts +0 -8
- package/dist/core/resolveMany.js +0 -17
- package/dist/core/tokenRegistry.d.ts +0 -23
- package/dist/core/tokenRegistry.js +0 -83
- package/dist/core/tokenRegistry.test.d.ts +0 -1
- package/dist/core/tokenRegistry.test.js +0 -133
- package/dist/engine/applyOperators.d.ts +0 -3
- package/dist/engine/applyOperators.js +0 -23
- package/dist/engine/context.d.ts +0 -4
- package/dist/engine/context.js +0 -1
- package/dist/engine/gamut.d.ts +0 -13
- package/dist/engine/gamut.js +0 -101
- package/dist/engine/gamut.test.d.ts +0 -1
- package/dist/engine/gamut.test.js +0 -23
- package/dist/engine/generateScale.d.ts +0 -15
- package/dist/engine/generateScale.js +0 -29
- package/dist/engine/generateScale.test.d.ts +0 -1
- package/dist/engine/generateScale.test.js +0 -32
- package/dist/engine/index.d.ts +0 -8
- package/dist/engine/index.js +0 -4
- package/dist/engine/normalize.d.ts +0 -43
- package/dist/engine/normalize.js +0 -403
- package/dist/engine/normalize.test.d.ts +0 -1
- package/dist/engine/normalize.test.js +0 -136
- package/dist/engine/onSolid.d.ts +0 -3
- package/dist/engine/onSolid.js +0 -110
- package/dist/engine/resolveBaseColor.d.ts +0 -25
- package/dist/engine/resolveBaseColor.js +0 -127
- package/dist/engine/resolveBaseColor.test.d.ts +0 -1
- package/dist/engine/resolveBaseColor.test.js +0 -97
- package/dist/export/__snapshots__/exportTheme.test.js.snap +0 -74
- package/dist/export/exportTheme.d.ts +0 -47
- package/dist/export/exportTheme.js +0 -170
- package/dist/export/exportTheme.test.d.ts +0 -1
- package/dist/export/exportTheme.test.js +0 -118
- package/dist/export/index.d.ts +0 -1
- package/dist/export/index.js +0 -1
- package/dist/export/serializeColor.d.ts +0 -1
- package/dist/export/serializeColor.js +0 -1
- package/dist/export/serializeColor.test.d.ts +0 -1
- package/dist/export/serializeColor.test.js +0 -54
- package/dist/export.d.ts +0 -1
- package/dist/export.js +0 -1
- package/dist/operators/emphasis.d.ts +0 -3
- package/dist/operators/emphasis.js +0 -113
- package/dist/operators/emphasis.test.d.ts +0 -1
- package/dist/operators/emphasis.test.js +0 -69
- package/dist/operators/index.d.ts +0 -3
- package/dist/operators/index.js +0 -2
- package/dist/operators/state.d.ts +0 -3
- package/dist/operators/state.js +0 -102
- package/dist/operators/state.test.d.ts +0 -1
- package/dist/operators/state.test.js +0 -48
- package/dist/operators/types.d.ts +0 -13
- package/dist/operators/types.js +0 -1
- package/dist/operators/utils.d.ts +0 -16
- package/dist/operators/utils.js +0 -23
- package/dist/presets/curves.d.ts +0 -28
- package/dist/presets/curves.js +0 -145
- package/dist/presets/index.d.ts +0 -2
- package/dist/presets/index.js +0 -1
- package/dist/presets/tokens/index.d.ts +0 -3
- package/dist/presets/tokens/index.js +0 -3
- package/dist/presets/tokens/minimal-ui.d.ts +0 -6
- package/dist/presets/tokens/minimal-ui.js +0 -53
- package/dist/presets/tokens/modern-ui.d.ts +0 -5
- package/dist/presets/tokens/modern-ui.js +0 -83
- package/dist/presets/tokens/presets.test.d.ts +0 -1
- package/dist/presets/tokens/presets.test.js +0 -31
- package/dist/presets/tokens/radixLike-ui.d.ts +0 -6
- package/dist/presets/tokens/radixLike-ui.js +0 -77
- package/dist/serialize/index.d.ts +0 -1
- package/dist/serialize/index.js +0 -1
- package/dist/serialize/normalizeOutput.d.ts +0 -6
- package/dist/serialize/normalizeOutput.js +0 -45
- package/dist/serialize/serializeColor.d.ts +0 -21
- package/dist/serialize/serializeColor.js +0 -178
- package/dist/serialize/serializeResolved.test.d.ts +0 -1
- package/dist/serialize/serializeResolved.test.js +0 -45
- package/dist/serialize.d.ts +0 -1
- package/dist/serialize.js +0 -1
- package/dist/utils/clamp.d.ts +0 -1
- package/dist/utils/clamp.js +0 -1
- package/dist/utils/index.d.ts +0 -1
- package/dist/utils/index.js +0 -1
- package/dist/utils/lerp.d.ts +0 -1
- package/dist/utils/lerp.js +0 -1
- package/dist/utils/parseColor.d.ts +0 -6
- package/dist/utils/parseColor.js +0 -67
- package/dist/utils/parseColor.test.d.ts +0 -1
- package/dist/utils/parseColor.test.js +0 -51
- package/dist/utils/smoothstep.d.ts +0 -1
- package/dist/utils/smoothstep.js +0 -5
- package/planning/phase-10-review.md +0 -550
- package/planning/phase-7-review.md +0 -411
- package/planning/phase-8-review.md +0 -669
- package/planning/phase-9-review.md +0 -564
- package/planning/roadmap-v0.3.md +0 -284
- package/planning/spec-serializer-v0.3.md +0 -324
- package/planning/spec-v0.3.md +0 -305
- package/src/cli/args.test.ts +0 -28
- package/src/cli/args.ts +0 -66
- package/src/cli/codegen/__snapshots__/tokens.test.ts.snap +0 -87
- package/src/cli/codegen/tokens.test.ts +0 -61
- package/src/cli/codegen/tokens.ts +0 -191
- package/src/cli/config.ts +0 -71
- package/src/cli/validate.test.ts +0 -49
- package/src/cli/validate.ts +0 -38
- package/src/cli.ts +0 -183
- package/src/contrast/apca.test.ts +0 -20
- package/src/contrast/apca.ts +0 -26
- package/src/contrast/index.ts +0 -4
- package/src/contrast/scoring.test.ts +0 -188
- package/src/contrast/scoring.ts +0 -48
- package/src/contrast/solver.test.ts +0 -147
- package/src/contrast/solver.ts +0 -235
- package/src/contrast/types.ts +0 -20
- package/src/contrast/utils.ts +0 -28
- package/src/contrast/wcag2.test.ts +0 -21
- package/src/contrast/wcag2.ts +0 -24
- package/src/core/createTheme.ts +0 -78
- package/src/core/dx-helpers.test.ts +0 -82
- package/src/core/index.ts +0 -7
- package/src/core/onSolid.test.ts +0 -146
- package/src/core/qa.v1.test.ts +0 -149
- package/src/core/resolve.test.ts +0 -99
- package/src/core/resolve.ts +0 -11
- package/src/core/resolveMany.ts +0 -22
- package/src/core/tokenRegistry.test.ts +0 -153
- package/src/core/tokenRegistry.ts +0 -114
- package/src/engine/applyOperators.ts +0 -32
- package/src/engine/context.ts +0 -8
- package/src/engine/gamut.test.ts +0 -30
- package/src/engine/gamut.ts +0 -144
- package/src/engine/generateScale.test.ts +0 -46
- package/src/engine/generateScale.ts +0 -48
- package/src/engine/index.ts +0 -8
- package/src/engine/normalize.test.ts +0 -222
- package/src/engine/normalize.ts +0 -550
- package/src/engine/onSolid.ts +0 -178
- package/src/engine/resolveBaseColor.test.ts +0 -117
- package/src/engine/resolveBaseColor.ts +0 -203
- package/src/export/__snapshots__/exportTheme.test.ts.snap +0 -74
- package/src/export/exportTheme.test.ts +0 -144
- package/src/export/exportTheme.ts +0 -251
- package/src/export/index.ts +0 -1
- package/src/export/serializeColor.test.ts +0 -73
- package/src/export/serializeColor.ts +0 -1
- package/src/export.ts +0 -1
- package/src/index.ts +0 -3
- package/src/operators/emphasis.test.ts +0 -85
- package/src/operators/emphasis.ts +0 -132
- package/src/operators/index.ts +0 -3
- package/src/operators/state.test.ts +0 -66
- package/src/operators/state.ts +0 -122
- package/src/operators/types.ts +0 -14
- package/src/operators/utils.ts +0 -44
- package/src/presets/curves.ts +0 -168
- package/src/presets/index.ts +0 -2
- package/src/presets/tokens/index.ts +0 -3
- package/src/presets/tokens/minimal-ui.ts +0 -55
- package/src/presets/tokens/modern-ui.ts +0 -85
- package/src/presets/tokens/presets.test.ts +0 -46
- package/src/presets/tokens/radixLike-ui.ts +0 -79
- package/src/serialize/index.ts +0 -1
- package/src/serialize/normalizeOutput.ts +0 -63
- package/src/serialize/serializeColor.ts +0 -260
- package/src/serialize/serializeResolved.test.ts +0 -57
- package/src/serialize.ts +0 -1
- package/src/types/index.ts +0 -207
- package/src/utils/clamp.ts +0 -2
- package/src/utils/index.ts +0 -1
- package/src/utils/lerp.ts +0 -1
- package/src/utils/parseColor.test.ts +0 -66
- package/src/utils/parseColor.ts +0 -87
- package/src/utils/smoothstep.ts +0 -6
- package/tsconfig.build.json +0 -11
- package/tsconfig.json +0 -15
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { IntentDefinition } from '../../core/intent-registry.js';
|
|
2
|
+
export declare const USAGES: readonly ["fill", "visualVocabulary", "lines", "overlays"];
|
|
3
|
+
export type Usage = (typeof USAGES)[number];
|
|
4
|
+
export type UsageStrategyInput = Readonly<{
|
|
5
|
+
intent: Readonly<IntentDefinition>;
|
|
6
|
+
}>;
|
|
7
|
+
export type UsageStrategyResult<U extends Usage = Usage> = Readonly<{
|
|
8
|
+
usage: U;
|
|
9
|
+
intent: Readonly<IntentDefinition>;
|
|
10
|
+
}>;
|
|
11
|
+
export type UsageStrategy<U extends Usage = Usage> = Readonly<{
|
|
12
|
+
usage: U;
|
|
13
|
+
resolve(input: UsageStrategyInput): UsageStrategyResult<U>;
|
|
14
|
+
}>;
|
|
15
|
+
export declare function isUsage(value: unknown): value is Usage;
|
|
16
|
+
export declare function assertUsage(value: unknown): asserts value is Usage;
|
|
17
|
+
export declare const usageStrategies: Readonly<{
|
|
18
|
+
fill: Readonly<{
|
|
19
|
+
resolve(input: Readonly<{
|
|
20
|
+
intent: Readonly<IntentDefinition>;
|
|
21
|
+
}>): Readonly<{
|
|
22
|
+
intent: Readonly<IntentDefinition>;
|
|
23
|
+
usage: "fill";
|
|
24
|
+
}>;
|
|
25
|
+
usage: "fill";
|
|
26
|
+
}>;
|
|
27
|
+
lines: Readonly<{
|
|
28
|
+
resolve(input: Readonly<{
|
|
29
|
+
intent: Readonly<IntentDefinition>;
|
|
30
|
+
}>): Readonly<{
|
|
31
|
+
intent: Readonly<IntentDefinition>;
|
|
32
|
+
usage: "lines";
|
|
33
|
+
}>;
|
|
34
|
+
usage: "lines";
|
|
35
|
+
}>;
|
|
36
|
+
overlays: Readonly<{
|
|
37
|
+
resolve(input: Readonly<{
|
|
38
|
+
intent: Readonly<IntentDefinition>;
|
|
39
|
+
}>): Readonly<{
|
|
40
|
+
intent: Readonly<IntentDefinition>;
|
|
41
|
+
usage: "overlays";
|
|
42
|
+
}>;
|
|
43
|
+
usage: "overlays";
|
|
44
|
+
}>;
|
|
45
|
+
visualVocabulary: Readonly<{
|
|
46
|
+
resolve(input: Readonly<{
|
|
47
|
+
intent: Readonly<IntentDefinition>;
|
|
48
|
+
}>): Readonly<{
|
|
49
|
+
intent: Readonly<IntentDefinition>;
|
|
50
|
+
usage: "visualVocabulary";
|
|
51
|
+
}>;
|
|
52
|
+
usage: "visualVocabulary";
|
|
53
|
+
}>;
|
|
54
|
+
}>;
|
|
55
|
+
export declare function getUsageStrategy<U extends Usage>(usage: U): UsageStrategy<U>;
|
|
56
|
+
export declare function getUsageStrategy(usage: unknown): UsageStrategy;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { fillUsageStrategy } from './fill.js';
|
|
2
|
+
import { linesUsageStrategy } from './lines.js';
|
|
3
|
+
import { overlaysUsageStrategy } from './overlays.js';
|
|
4
|
+
import { visualVocabularyUsageStrategy } from './visualVocabulary.js';
|
|
5
|
+
export const USAGES = Object.freeze([
|
|
6
|
+
'fill',
|
|
7
|
+
'visualVocabulary',
|
|
8
|
+
'lines',
|
|
9
|
+
'overlays',
|
|
10
|
+
]);
|
|
11
|
+
const usageList = USAGES.join(', ');
|
|
12
|
+
const formatUnknownUsageError = (value) => `Unknown usage "${String(value)}". Expected one of: ${usageList}.`;
|
|
13
|
+
export function isUsage(value) {
|
|
14
|
+
return (typeof value === 'string' && USAGES.includes(value));
|
|
15
|
+
}
|
|
16
|
+
export function assertUsage(value) {
|
|
17
|
+
if (!isUsage(value)) {
|
|
18
|
+
throw new Error(formatUnknownUsageError(value));
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export const usageStrategies = Object.freeze({
|
|
22
|
+
fill: fillUsageStrategy,
|
|
23
|
+
lines: linesUsageStrategy,
|
|
24
|
+
overlays: overlaysUsageStrategy,
|
|
25
|
+
visualVocabulary: visualVocabularyUsageStrategy,
|
|
26
|
+
});
|
|
27
|
+
export function getUsageStrategy(usage) {
|
|
28
|
+
assertUsage(usage);
|
|
29
|
+
return usageStrategies[usage];
|
|
30
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const visualVocabularyUsageStrategy: Readonly<{
|
|
2
|
+
resolve(input: Readonly<{
|
|
3
|
+
intent: Readonly<import("../../core/intent-registry.js").IntentDefinition>;
|
|
4
|
+
}>): Readonly<{
|
|
5
|
+
intent: Readonly<import("../../core/intent-registry.js").IntentDefinition>;
|
|
6
|
+
usage: "visualVocabulary";
|
|
7
|
+
}>;
|
|
8
|
+
usage: "visualVocabulary";
|
|
9
|
+
}>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { normalizeOklch, type OklchInput } from '../core/oklch.js';
|
|
2
|
+
import { oklchToOklab } from '../operators/convert.js';
|
|
3
|
+
import type { ColorOutput, RgbaColor, RgbColor } from './types.js';
|
|
4
|
+
export type GamutStrategy = 'clip';
|
|
5
|
+
export type SerializationOptions = Readonly<{
|
|
6
|
+
gamutStrategy?: GamutStrategy;
|
|
7
|
+
}>;
|
|
8
|
+
export type ColorSerializer<T> = (color: OklchInput, options?: SerializationOptions) => T;
|
|
9
|
+
export declare const serializeOklchToRgba: ColorSerializer<RgbaColor>;
|
|
10
|
+
export declare const serializeOklchToOklab: ColorSerializer<ReturnType<typeof oklchToOklab>>;
|
|
11
|
+
export declare const serializeOklchToSrgb: ColorSerializer<RgbColor>;
|
|
12
|
+
export declare const serializeOklchToP3: ColorSerializer<RgbColor>;
|
|
13
|
+
export declare const serializeOklchToHex: ColorSerializer<string>;
|
|
14
|
+
export declare function serializeColor(color: OklchInput, output: ColorOutput, options?: SerializationOptions): ReturnType<typeof normalizeOklch | typeof serializeOklchToOklab | typeof serializeOklchToSrgb | typeof serializeOklchToP3 | typeof serializeOklchToHex | typeof serializeOklchToRgba>;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { normalizeOklch } from '../core/oklch.js';
|
|
2
|
+
import { oklabToLinearRgb, oklchToOklab } from '../operators/convert.js';
|
|
3
|
+
import { createUnsupportedOutputError } from '../utils/errors/errors.js';
|
|
4
|
+
const DEFAULT_GAMUT_STRATEGY = 'clip';
|
|
5
|
+
const clampUnit = (value) => Math.min(1, Math.max(0, value));
|
|
6
|
+
const toSrgbChannel = (linearChannel) => {
|
|
7
|
+
const encoded = linearChannel <= 0.0031308
|
|
8
|
+
? 12.92 * linearChannel
|
|
9
|
+
: 1.055 * linearChannel ** (1 / 2.4) - 0.055;
|
|
10
|
+
return Math.round(clampUnit(encoded) * 255);
|
|
11
|
+
};
|
|
12
|
+
const toEncodedRgbColor = (linearRgb) => Object.freeze({
|
|
13
|
+
alpha: linearRgb.alpha,
|
|
14
|
+
b: toSrgbChannel(linearRgb.b),
|
|
15
|
+
g: toSrgbChannel(linearRgb.g),
|
|
16
|
+
r: toSrgbChannel(linearRgb.r),
|
|
17
|
+
});
|
|
18
|
+
const oklabToLinearDisplayP3 = (oklab) => {
|
|
19
|
+
const lPrime = oklab.l + 0.3963377774 * oklab.a + 0.2158037573 * oklab.b;
|
|
20
|
+
const mPrime = oklab.l - 0.1055613458 * oklab.a - 0.0638541728 * oklab.b;
|
|
21
|
+
const sPrime = oklab.l - 0.0894841775 * oklab.a - 1.291485548 * oklab.b;
|
|
22
|
+
const l = lPrime ** 3;
|
|
23
|
+
const m = mPrime ** 3;
|
|
24
|
+
const s = sPrime ** 3;
|
|
25
|
+
const x = 1.2270138511 * l - 0.5577999807 * m + 0.281256149 * s;
|
|
26
|
+
const y = -0.0405801784 * l + 1.1122568696 * m - 0.0716766787 * s;
|
|
27
|
+
const z = -0.0763812845 * l - 0.4214819784 * m + 1.5861632204 * s;
|
|
28
|
+
return {
|
|
29
|
+
alpha: oklab.alpha,
|
|
30
|
+
b: 0.0358458302 * x - 0.0761723893 * y + 0.956884524 * z,
|
|
31
|
+
g: -0.8294889696 * x + 1.7626640603 * y + 0.0236246858 * z,
|
|
32
|
+
r: 2.4934969119 * x - 0.9313836179 * y - 0.4027107845 * z,
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
const toHexChannel = (channel) => channel.toString(16).padStart(2, '0');
|
|
36
|
+
const resolveGamutStrategy = (options) => {
|
|
37
|
+
const strategy = options?.gamutStrategy ?? DEFAULT_GAMUT_STRATEGY;
|
|
38
|
+
if (strategy !== 'clip') {
|
|
39
|
+
throw new Error(`Unsupported gamut strategy "${String(strategy)}". Expected "clip".`);
|
|
40
|
+
}
|
|
41
|
+
return strategy;
|
|
42
|
+
};
|
|
43
|
+
export const serializeOklchToRgba = (input, options) => {
|
|
44
|
+
const srgb = serializeOklchToSrgb(input, options);
|
|
45
|
+
return Object.freeze({
|
|
46
|
+
a: srgb.alpha,
|
|
47
|
+
b: srgb.b,
|
|
48
|
+
g: srgb.g,
|
|
49
|
+
r: srgb.r,
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
export const serializeOklchToOklab = (input) => oklchToOklab(input);
|
|
53
|
+
export const serializeOklchToSrgb = (input, options) => {
|
|
54
|
+
resolveGamutStrategy(options);
|
|
55
|
+
const color = normalizeOklch(input);
|
|
56
|
+
const linearRgb = oklabToLinearRgb(oklchToOklab(color));
|
|
57
|
+
return toEncodedRgbColor(linearRgb);
|
|
58
|
+
};
|
|
59
|
+
export const serializeOklchToP3 = (input, options) => {
|
|
60
|
+
resolveGamutStrategy(options);
|
|
61
|
+
const color = normalizeOklch(input);
|
|
62
|
+
const linearP3 = oklabToLinearDisplayP3(oklchToOklab(color));
|
|
63
|
+
return toEncodedRgbColor(linearP3);
|
|
64
|
+
};
|
|
65
|
+
export const serializeOklchToHex = (input, options) => {
|
|
66
|
+
const rgba = serializeOklchToRgba(input, options);
|
|
67
|
+
return `#${toHexChannel(rgba.r)}${toHexChannel(rgba.g)}${toHexChannel(rgba.b)}`;
|
|
68
|
+
};
|
|
69
|
+
export function serializeColor(color, output, options) {
|
|
70
|
+
if (output === 'oklch') {
|
|
71
|
+
return normalizeOklch(color);
|
|
72
|
+
}
|
|
73
|
+
if (output === 'oklab') {
|
|
74
|
+
return serializeOklchToOklab(color);
|
|
75
|
+
}
|
|
76
|
+
if (output === 'srgb') {
|
|
77
|
+
return serializeOklchToSrgb(color, options);
|
|
78
|
+
}
|
|
79
|
+
if (output === 'p3') {
|
|
80
|
+
return serializeOklchToP3(color, options);
|
|
81
|
+
}
|
|
82
|
+
if (output === 'hex') {
|
|
83
|
+
return serializeOklchToHex(color, options);
|
|
84
|
+
}
|
|
85
|
+
if (output === 'rgba') {
|
|
86
|
+
return serializeOklchToRgba(color, options);
|
|
87
|
+
}
|
|
88
|
+
throw createUnsupportedOutputError(output);
|
|
89
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { OklchColor } from '../core/oklch.js';
|
|
2
|
+
import type { OklabColor } from '../operators/convert.js';
|
|
3
|
+
export declare const OUTPUTS: readonly ["oklch", "oklab", "srgb", "p3", "hex", "rgba"];
|
|
4
|
+
export type ColorOutput = (typeof OUTPUTS)[number];
|
|
5
|
+
export type RgbColor = Readonly<{
|
|
6
|
+
r: number;
|
|
7
|
+
g: number;
|
|
8
|
+
b: number;
|
|
9
|
+
alpha: number;
|
|
10
|
+
}>;
|
|
11
|
+
export type RgbaColor = Readonly<{
|
|
12
|
+
r: number;
|
|
13
|
+
g: number;
|
|
14
|
+
b: number;
|
|
15
|
+
a: number;
|
|
16
|
+
}>;
|
|
17
|
+
export type OutputMap = Readonly<{
|
|
18
|
+
oklch: OklchColor;
|
|
19
|
+
oklab: OklabColor;
|
|
20
|
+
srgb: RgbColor;
|
|
21
|
+
p3: RgbColor;
|
|
22
|
+
hex: string;
|
|
23
|
+
rgba: RgbaColor;
|
|
24
|
+
}>;
|
|
25
|
+
export type ResolveOutput<O extends ColorOutput> = OutputMap[O];
|
|
26
|
+
export type ResolveOptionsWithOutput<O extends ColorOutput> = Readonly<{
|
|
27
|
+
output?: O;
|
|
28
|
+
}>;
|
|
29
|
+
export type TypedResolver<O extends ColorOutput> = (options: ResolveOptionsWithOutput<O>) => ResolveOutput<O>;
|
|
30
|
+
export type OutputResolutionInput = Readonly<{
|
|
31
|
+
resolverOutput?: unknown;
|
|
32
|
+
paletteOutput?: unknown;
|
|
33
|
+
systemDefaultOutput?: unknown;
|
|
34
|
+
}>;
|
|
35
|
+
export declare function isColorOutput(value: unknown): value is ColorOutput;
|
|
36
|
+
export declare function assertColorOutput(value: unknown): asserts value is ColorOutput;
|
|
37
|
+
export declare function resolveOutput({ resolverOutput, paletteOutput, systemDefaultOutput, }: OutputResolutionInput): ColorOutput;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { createUnsupportedOutputError } from '../utils/errors/errors.js';
|
|
2
|
+
export const OUTPUTS = Object.freeze([
|
|
3
|
+
'oklch',
|
|
4
|
+
'oklab',
|
|
5
|
+
'srgb',
|
|
6
|
+
'p3',
|
|
7
|
+
'hex',
|
|
8
|
+
'rgba',
|
|
9
|
+
]);
|
|
10
|
+
const outputList = OUTPUTS.join(', ');
|
|
11
|
+
const formatInvalidOutputError = (value) => `Invalid output "${String(value)}". Expected one of: ${outputList}.`;
|
|
12
|
+
export function isColorOutput(value) {
|
|
13
|
+
return (typeof value === 'string' && OUTPUTS.includes(value));
|
|
14
|
+
}
|
|
15
|
+
export function assertColorOutput(value) {
|
|
16
|
+
if (!isColorOutput(value)) {
|
|
17
|
+
throw createUnsupportedOutputError(String(value), formatInvalidOutputError(value));
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export function resolveOutput({ resolverOutput, paletteOutput, systemDefaultOutput, }) {
|
|
21
|
+
if (resolverOutput !== undefined) {
|
|
22
|
+
assertColorOutput(resolverOutput);
|
|
23
|
+
}
|
|
24
|
+
if (paletteOutput !== undefined) {
|
|
25
|
+
assertColorOutput(paletteOutput);
|
|
26
|
+
}
|
|
27
|
+
if (systemDefaultOutput !== undefined) {
|
|
28
|
+
assertColorOutput(systemDefaultOutput);
|
|
29
|
+
}
|
|
30
|
+
return resolverOutput ?? paletteOutput ?? systemDefaultOutput ?? 'oklch';
|
|
31
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export
|
|
2
|
-
export
|
|
3
|
-
export
|
|
1
|
+
export { createPaletteKit } from './create-palette-kit.js';
|
|
2
|
+
export { defaultResolverConfig, neutralResolverConfig, softResolverConfig, strongResolverConfig, } from './presets/presets.js';
|
|
3
|
+
export type { ChromaConfig, ColorOutput, Context, IntentDefinition, Level, OklchColor, PaletteKit, PaletteKitConfig, PaletteResolveOptions, PaletteResolveOutput, RelationParamsConfig, ResolverConfig, ResolverConfigOverrides, ResolverPresetName, RgbaColor, RgbColor, State, StateDeltaDirection, Usage, } from './types/index.js';
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export
|
|
2
|
-
export
|
|
1
|
+
export { createPaletteKit } from './create-palette-kit.js';
|
|
2
|
+
export { defaultResolverConfig, neutralResolverConfig, softResolverConfig, strongResolverConfig, } from './presets/presets.js';
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { normalizeOklch, type OklchInput } from '../core/oklch.js';
|
|
2
|
+
export declare const CONVERSION_EPSILON = 1e-10;
|
|
3
|
+
export type OklabColor = {
|
|
4
|
+
space: 'oklab';
|
|
5
|
+
l: number;
|
|
6
|
+
a: number;
|
|
7
|
+
b: number;
|
|
8
|
+
alpha: number;
|
|
9
|
+
};
|
|
10
|
+
export type LinearRgbColor = {
|
|
11
|
+
space: 'linear-rgb';
|
|
12
|
+
r: number;
|
|
13
|
+
g: number;
|
|
14
|
+
b: number;
|
|
15
|
+
alpha: number;
|
|
16
|
+
};
|
|
17
|
+
export type OklabInput = {
|
|
18
|
+
l: number;
|
|
19
|
+
a: number;
|
|
20
|
+
b: number;
|
|
21
|
+
alpha?: number;
|
|
22
|
+
};
|
|
23
|
+
export type LinearRgbInput = {
|
|
24
|
+
r: number;
|
|
25
|
+
g: number;
|
|
26
|
+
b: number;
|
|
27
|
+
alpha?: number;
|
|
28
|
+
};
|
|
29
|
+
export declare function oklchToOklab(input: OklchInput): OklabColor;
|
|
30
|
+
export declare function oklabToOklch(input: OklabInput): ReturnType<typeof normalizeOklch>;
|
|
31
|
+
export declare function oklabToLinearRgb(input: OklabInput): LinearRgbColor;
|
|
32
|
+
export declare function linearRgbToOklab(input: LinearRgbInput): OklabColor;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { normalizeOklch } from '../core/oklch.js';
|
|
2
|
+
export const CONVERSION_EPSILON = 1e-10;
|
|
3
|
+
const isFiniteNumber = (value) => typeof value === 'number' && Number.isFinite(value);
|
|
4
|
+
const normalizePrecision = (value) => Math.abs(value) <= CONVERSION_EPSILON ? 0 : value;
|
|
5
|
+
const normalizeHue = (hue) => {
|
|
6
|
+
const normalized = ((hue % 360) + 360) % 360;
|
|
7
|
+
return normalizePrecision(normalized);
|
|
8
|
+
};
|
|
9
|
+
const validateFiniteChannel = (space, name, value) => {
|
|
10
|
+
if (!isFiniteNumber(value)) {
|
|
11
|
+
throw new Error(`${space} ${name} must be a finite number.`);
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
const normalizeAlpha = (space, alphaInput) => {
|
|
15
|
+
const alpha = alphaInput ?? 1;
|
|
16
|
+
validateFiniteChannel(space, 'alpha', alpha);
|
|
17
|
+
return normalizePrecision(alpha);
|
|
18
|
+
};
|
|
19
|
+
export function oklchToOklab(input) {
|
|
20
|
+
const color = normalizeOklch(input);
|
|
21
|
+
const hueRadians = (color.h * Math.PI) / 180;
|
|
22
|
+
return {
|
|
23
|
+
a: normalizePrecision(color.c * Math.cos(hueRadians)),
|
|
24
|
+
alpha: normalizePrecision(color.alpha),
|
|
25
|
+
b: normalizePrecision(color.c * Math.sin(hueRadians)),
|
|
26
|
+
l: normalizePrecision(color.l / 100),
|
|
27
|
+
space: 'oklab',
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export function oklabToOklch(input) {
|
|
31
|
+
validateFiniteChannel('OKLab', 'l', input.l);
|
|
32
|
+
validateFiniteChannel('OKLab', 'a', input.a);
|
|
33
|
+
validateFiniteChannel('OKLab', 'b', input.b);
|
|
34
|
+
const alpha = normalizeAlpha('OKLab', input.alpha);
|
|
35
|
+
const c = Math.hypot(input.a, input.b);
|
|
36
|
+
const hue = c <= CONVERSION_EPSILON
|
|
37
|
+
? 0
|
|
38
|
+
: (Math.atan2(input.b, input.a) * 180) / Math.PI;
|
|
39
|
+
return normalizeOklch({
|
|
40
|
+
alpha,
|
|
41
|
+
c: normalizePrecision(c),
|
|
42
|
+
h: normalizeHue(hue),
|
|
43
|
+
l: normalizePrecision(input.l * 100),
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
export function oklabToLinearRgb(input) {
|
|
47
|
+
validateFiniteChannel('OKLab', 'l', input.l);
|
|
48
|
+
validateFiniteChannel('OKLab', 'a', input.a);
|
|
49
|
+
validateFiniteChannel('OKLab', 'b', input.b);
|
|
50
|
+
const alpha = normalizeAlpha('OKLab', input.alpha);
|
|
51
|
+
const lPrime = input.l + 0.3963377774 * input.a + 0.2158037573 * input.b;
|
|
52
|
+
const mPrime = input.l - 0.1055613458 * input.a - 0.0638541728 * input.b;
|
|
53
|
+
const sPrime = input.l - 0.0894841775 * input.a - 1.291485548 * input.b;
|
|
54
|
+
const l = lPrime ** 3;
|
|
55
|
+
const m = mPrime ** 3;
|
|
56
|
+
const s = sPrime ** 3;
|
|
57
|
+
return {
|
|
58
|
+
alpha,
|
|
59
|
+
b: normalizePrecision(-0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s),
|
|
60
|
+
g: normalizePrecision(-1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s),
|
|
61
|
+
r: normalizePrecision(4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s),
|
|
62
|
+
space: 'linear-rgb',
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
export function linearRgbToOklab(input) {
|
|
66
|
+
validateFiniteChannel('linear RGB', 'r', input.r);
|
|
67
|
+
validateFiniteChannel('linear RGB', 'g', input.g);
|
|
68
|
+
validateFiniteChannel('linear RGB', 'b', input.b);
|
|
69
|
+
const alpha = normalizeAlpha('linear RGB', input.alpha);
|
|
70
|
+
const l = Math.cbrt(0.4122214708 * input.r + 0.5363325363 * input.g + 0.0514459929 * input.b);
|
|
71
|
+
const m = Math.cbrt(0.2119034982 * input.r + 0.6806995451 * input.g + 0.1073969566 * input.b);
|
|
72
|
+
const s = Math.cbrt(0.0883024619 * input.r + 0.2817188376 * input.g + 0.6299787005 * input.b);
|
|
73
|
+
return {
|
|
74
|
+
a: normalizePrecision(1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s),
|
|
75
|
+
alpha,
|
|
76
|
+
b: normalizePrecision(0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s),
|
|
77
|
+
l: normalizePrecision(0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s),
|
|
78
|
+
space: 'oklab',
|
|
79
|
+
};
|
|
80
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { type LevelCurveConfig } from '../engine/level/curves.js';
|
|
2
|
+
import { type Level } from '../engine/level/level.js';
|
|
3
|
+
import { type StateDeltaConfig, type StateDeltaTable } from '../engine/state/state.js';
|
|
4
|
+
export declare const RESOLVER_PRESETS: readonly ["soft", "neutral", "strong"];
|
|
5
|
+
export type ResolverPresetName = (typeof RESOLVER_PRESETS)[number];
|
|
6
|
+
export type RelationLevelAlphaTable = Readonly<Record<Level, number>>;
|
|
7
|
+
export type RelationParamsConfig = Readonly<{
|
|
8
|
+
on: Readonly<{
|
|
9
|
+
contrastTarget: number;
|
|
10
|
+
maxLuminanceShift: number;
|
|
11
|
+
}>;
|
|
12
|
+
over: Readonly<{
|
|
13
|
+
baseAlphaByLevel: RelationLevelAlphaTable;
|
|
14
|
+
}>;
|
|
15
|
+
under: Readonly<{
|
|
16
|
+
baseAlphaByLevel: RelationLevelAlphaTable;
|
|
17
|
+
luminanceReduction: number;
|
|
18
|
+
}>;
|
|
19
|
+
}>;
|
|
20
|
+
export type ChromaConfig = Readonly<{
|
|
21
|
+
maxReduction: number;
|
|
22
|
+
reductionStep: number;
|
|
23
|
+
}>;
|
|
24
|
+
export type ResolverConfig = Readonly<{
|
|
25
|
+
levelCurves: LevelCurveConfig;
|
|
26
|
+
stateDeltas: StateDeltaConfig;
|
|
27
|
+
relationParams: RelationParamsConfig;
|
|
28
|
+
chromaLimits: ChromaConfig;
|
|
29
|
+
}>;
|
|
30
|
+
export type ResolverConfigOverrides = Readonly<{
|
|
31
|
+
levelCurves?: Partial<LevelCurveConfig>;
|
|
32
|
+
stateDeltas?: Readonly<{
|
|
33
|
+
luminance?: Partial<StateDeltaTable>;
|
|
34
|
+
alpha?: Partial<StateDeltaTable>;
|
|
35
|
+
}>;
|
|
36
|
+
relationParams?: Readonly<{
|
|
37
|
+
on?: Partial<RelationParamsConfig['on']>;
|
|
38
|
+
over?: Readonly<{
|
|
39
|
+
baseAlphaByLevel?: Partial<RelationLevelAlphaTable>;
|
|
40
|
+
}>;
|
|
41
|
+
under?: Readonly<{
|
|
42
|
+
baseAlphaByLevel?: Partial<RelationLevelAlphaTable>;
|
|
43
|
+
luminanceReduction?: number;
|
|
44
|
+
}>;
|
|
45
|
+
}>;
|
|
46
|
+
chromaLimits?: Partial<ChromaConfig>;
|
|
47
|
+
}>;
|
|
48
|
+
export declare const softResolverConfig: Readonly<{
|
|
49
|
+
levelCurves: LevelCurveConfig;
|
|
50
|
+
stateDeltas: StateDeltaConfig;
|
|
51
|
+
relationParams: RelationParamsConfig;
|
|
52
|
+
chromaLimits: ChromaConfig;
|
|
53
|
+
}>;
|
|
54
|
+
export declare const neutralResolverConfig: Readonly<{
|
|
55
|
+
levelCurves: LevelCurveConfig;
|
|
56
|
+
stateDeltas: StateDeltaConfig;
|
|
57
|
+
relationParams: RelationParamsConfig;
|
|
58
|
+
chromaLimits: ChromaConfig;
|
|
59
|
+
}>;
|
|
60
|
+
export declare const strongResolverConfig: Readonly<{
|
|
61
|
+
levelCurves: LevelCurveConfig;
|
|
62
|
+
stateDeltas: StateDeltaConfig;
|
|
63
|
+
relationParams: RelationParamsConfig;
|
|
64
|
+
chromaLimits: ChromaConfig;
|
|
65
|
+
}>;
|
|
66
|
+
export declare const defaultResolverConfig: Readonly<{
|
|
67
|
+
levelCurves: LevelCurveConfig;
|
|
68
|
+
stateDeltas: StateDeltaConfig;
|
|
69
|
+
relationParams: RelationParamsConfig;
|
|
70
|
+
chromaLimits: ChromaConfig;
|
|
71
|
+
}>;
|
|
72
|
+
export declare const resolverPresetConfigs: Readonly<{
|
|
73
|
+
neutral: Readonly<{
|
|
74
|
+
levelCurves: LevelCurveConfig;
|
|
75
|
+
stateDeltas: StateDeltaConfig;
|
|
76
|
+
relationParams: RelationParamsConfig;
|
|
77
|
+
chromaLimits: ChromaConfig;
|
|
78
|
+
}>;
|
|
79
|
+
soft: Readonly<{
|
|
80
|
+
levelCurves: LevelCurveConfig;
|
|
81
|
+
stateDeltas: StateDeltaConfig;
|
|
82
|
+
relationParams: RelationParamsConfig;
|
|
83
|
+
chromaLimits: ChromaConfig;
|
|
84
|
+
}>;
|
|
85
|
+
strong: Readonly<{
|
|
86
|
+
levelCurves: LevelCurveConfig;
|
|
87
|
+
stateDeltas: StateDeltaConfig;
|
|
88
|
+
relationParams: RelationParamsConfig;
|
|
89
|
+
chromaLimits: ChromaConfig;
|
|
90
|
+
}>;
|
|
91
|
+
}>;
|
|
92
|
+
export declare function isResolverPresetName(value: unknown): value is ResolverPresetName;
|
|
93
|
+
export declare function assertResolverPresetName(value: unknown): asserts value is ResolverPresetName;
|
|
94
|
+
export declare function getResolverPresetConfig(preset: unknown): ResolverConfig;
|
|
95
|
+
export declare function mergeResolverConfig(base: ResolverConfig, overrides: ResolverConfigOverrides | undefined): ResolverConfig;
|