@clhaas/palette-kit 0.1.8 → 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.
Files changed (118) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/README.md +80 -177
  3. package/dist/contrast/contrast.d.ts +16 -0
  4. package/dist/contrast/contrast.js +102 -0
  5. package/dist/core/intent-registry.d.ts +11 -0
  6. package/dist/core/intent-registry.js +70 -0
  7. package/dist/core/oklch.d.ts +16 -0
  8. package/dist/core/oklch.js +56 -0
  9. package/dist/create-palette-kit.d.ts +9 -0
  10. package/dist/create-palette-kit.js +67 -0
  11. package/dist/engine/context/context.d.ts +13 -0
  12. package/dist/engine/context/context.js +37 -0
  13. package/dist/engine/level/curves.d.ts +17 -0
  14. package/dist/engine/level/curves.js +49 -0
  15. package/dist/engine/level/level.d.ts +4 -0
  16. package/dist/engine/level/level.js +13 -0
  17. package/dist/engine/relation/relation.d.ts +105 -0
  18. package/dist/engine/relation/relation.js +137 -0
  19. package/dist/engine/resolve/resolve.d.ts +36 -0
  20. package/dist/engine/resolve/resolve.js +116 -0
  21. package/dist/engine/state/state.d.ts +46 -0
  22. package/dist/engine/state/state.js +68 -0
  23. package/dist/engine/usage/fill.d.ts +9 -0
  24. package/dist/engine/usage/fill.js +9 -0
  25. package/dist/engine/usage/lines.d.ts +9 -0
  26. package/dist/engine/usage/lines.js +9 -0
  27. package/dist/engine/usage/overlays.d.ts +9 -0
  28. package/dist/engine/usage/overlays.js +9 -0
  29. package/dist/engine/usage/strategy.d.ts +56 -0
  30. package/dist/engine/usage/strategy.js +30 -0
  31. package/dist/engine/usage/visualVocabulary.d.ts +9 -0
  32. package/dist/engine/usage/visualVocabulary.js +9 -0
  33. package/dist/export/serialize.d.ts +14 -0
  34. package/dist/export/serialize.js +89 -0
  35. package/dist/export/types.d.ts +37 -0
  36. package/dist/export/types.js +31 -0
  37. package/dist/index.d.ts +3 -22
  38. package/dist/index.js +2 -18
  39. package/dist/operators/convert.d.ts +32 -0
  40. package/dist/operators/convert.js +80 -0
  41. package/dist/presets/presets.d.ts +95 -0
  42. package/dist/presets/presets.js +308 -0
  43. package/dist/types/index.d.ts +111 -0
  44. package/dist/utils/errors/errors.d.ts +17 -0
  45. package/dist/utils/errors/errors.js +22 -0
  46. package/docs/API.md +167 -0
  47. package/docs/Alpha.md +14 -0
  48. package/docs/Architecture.md +56 -0
  49. package/docs/CLI.md +22 -0
  50. package/docs/Concepts.md +73 -0
  51. package/docs/Config.md +144 -0
  52. package/docs/Diagnostics.md +22 -0
  53. package/docs/Exporters.md +33 -0
  54. package/docs/FAQ.md +59 -0
  55. package/docs/Migration.md +61 -0
  56. package/docs/Overlays.md +33 -0
  57. package/docs/README.md +60 -0
  58. package/docs/Text.md +41 -0
  59. package/docs/Tokens.md +42 -0
  60. package/docs/Usage-JSON.md +39 -0
  61. package/docs/Usage-ReactNative.md +63 -0
  62. package/docs/Usage-Web.md +66 -0
  63. package/docs/Validation.md +97 -0
  64. package/docs/Why.md +37 -0
  65. package/docs/_api-surface.md +53 -0
  66. package/docs/snippets/serialize-oklch.md +9 -0
  67. package/docs/spec.md +98 -0
  68. package/package.json +74 -52
  69. package/dist/alpha/generateAlphaScale.d.ts +0 -5
  70. package/dist/alpha/generateAlphaScale.js +0 -34
  71. package/dist/cli.d.ts +0 -2
  72. package/dist/cli.js +0 -150
  73. package/dist/contrast/apca.d.ts +0 -2
  74. package/dist/contrast/apca.js +0 -5
  75. package/dist/contrast/onSolid.d.ts +0 -6
  76. package/dist/contrast/onSolid.js +0 -28
  77. package/dist/contrast/solveText.d.ts +0 -2
  78. package/dist/contrast/solveText.js +0 -31
  79. package/dist/createTheme.d.ts +0 -38
  80. package/dist/createTheme.js +0 -148
  81. package/dist/data/radixSeeds.d.ts +0 -3
  82. package/dist/data/radixSeeds.js +0 -34
  83. package/dist/diagnostics/analyzeScale.d.ts +0 -2
  84. package/dist/diagnostics/analyzeScale.js +0 -7
  85. package/dist/diagnostics/analyzeTheme.d.ts +0 -2
  86. package/dist/diagnostics/analyzeTheme.js +0 -35
  87. package/dist/diagnostics/warnings.d.ts +0 -2
  88. package/dist/diagnostics/warnings.js +0 -20
  89. package/dist/engine/curves.d.ts +0 -9
  90. package/dist/engine/curves.js +0 -48
  91. package/dist/engine/oklch.d.ts +0 -8
  92. package/dist/engine/oklch.js +0 -40
  93. package/dist/engine/templates.d.ts +0 -14
  94. package/dist/engine/templates.js +0 -45
  95. package/dist/exporters/selectColorMode.d.ts +0 -2
  96. package/dist/exporters/selectColorMode.js +0 -19
  97. package/dist/exporters/toCssVars.d.ts +0 -13
  98. package/dist/exporters/toCssVars.js +0 -108
  99. package/dist/exporters/toJson.d.ts +0 -3
  100. package/dist/exporters/toJson.js +0 -25
  101. package/dist/exporters/toReactNative.d.ts +0 -54
  102. package/dist/exporters/toReactNative.js +0 -33
  103. package/dist/exporters/toTailwind.d.ts +0 -17
  104. package/dist/exporters/toTailwind.js +0 -111
  105. package/dist/exporters/toTs.d.ts +0 -3
  106. package/dist/exporters/toTs.js +0 -43
  107. package/dist/generateScale.d.ts +0 -48
  108. package/dist/generateScale.js +0 -274
  109. package/dist/overlays/generateOverlayScale.d.ts +0 -2
  110. package/dist/overlays/generateOverlayScale.js +0 -34
  111. package/dist/text/generateTextScale.d.ts +0 -8
  112. package/dist/text/generateTextScale.js +0 -18
  113. package/dist/text/resolveOnBgText.d.ts +0 -9
  114. package/dist/text/resolveOnBgText.js +0 -28
  115. package/dist/tokens/presetRadixLikeUi.d.ts +0 -5
  116. package/dist/tokens/presetRadixLikeUi.js +0 -55
  117. package/dist/types.d.ts +0 -69
  118. /package/dist/{types.js → types/index.js} +0 -0
@@ -0,0 +1,68 @@
1
+ export const STATES = Object.freeze([
2
+ 'default',
3
+ 'hover',
4
+ 'active',
5
+ 'focus',
6
+ 'selected',
7
+ 'disabled',
8
+ ]);
9
+ export const defaultStateLuminanceDeltas = Object.freeze({
10
+ active: 6,
11
+ default: 0,
12
+ disabled: 10,
13
+ focus: 4,
14
+ hover: 3,
15
+ selected: 5,
16
+ });
17
+ export const defaultStateAlphaDeltas = Object.freeze({
18
+ active: 0,
19
+ default: 0,
20
+ disabled: 0,
21
+ focus: 0,
22
+ hover: 0,
23
+ selected: 0,
24
+ });
25
+ export const defaultStateDeltas = Object.freeze({
26
+ alpha: defaultStateAlphaDeltas,
27
+ luminance: defaultStateLuminanceDeltas,
28
+ });
29
+ const stateList = STATES.join(', ');
30
+ const formatInvalidStateError = (value) => `Invalid state "${String(value)}". Expected one of: ${stateList}.`;
31
+ const clampPercentage = (value) => Math.min(100, Math.max(0, value));
32
+ const clampAlpha = (value) => Number(Math.min(1, Math.max(0, value)).toFixed(12));
33
+ export function isState(value) {
34
+ return (typeof value === 'string' && STATES.includes(value));
35
+ }
36
+ export function assertState(value) {
37
+ if (!isState(value)) {
38
+ throw new Error(formatInvalidStateError(value));
39
+ }
40
+ }
41
+ export function applyStateDelta(value, state, direction, deltas = defaultStateDeltas.luminance) {
42
+ if (!Number.isFinite(value)) {
43
+ throw new Error('State delta value must be a finite number.');
44
+ }
45
+ assertState(state);
46
+ const delta = deltas[state];
47
+ if (state === 'default') {
48
+ return clampPercentage(value);
49
+ }
50
+ if (direction === 'increase') {
51
+ return clampPercentage(value + delta);
52
+ }
53
+ return clampPercentage(value - delta);
54
+ }
55
+ export function applyStateAlphaDelta(value, state, direction, deltas = defaultStateDeltas.alpha) {
56
+ if (!Number.isFinite(value)) {
57
+ throw new Error('State alpha delta value must be a finite number.');
58
+ }
59
+ assertState(state);
60
+ const delta = deltas[state];
61
+ if (state === 'default') {
62
+ return clampAlpha(value);
63
+ }
64
+ if (direction === 'increase') {
65
+ return clampAlpha(value + delta);
66
+ }
67
+ return clampAlpha(value - delta);
68
+ }
@@ -0,0 +1,9 @@
1
+ export declare const fillUsageStrategy: 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: "fill";
7
+ }>;
8
+ usage: "fill";
9
+ }>;
@@ -0,0 +1,9 @@
1
+ export const fillUsageStrategy = Object.freeze({
2
+ resolve(input) {
3
+ return Object.freeze({
4
+ intent: input.intent,
5
+ usage: 'fill',
6
+ });
7
+ },
8
+ usage: 'fill',
9
+ });
@@ -0,0 +1,9 @@
1
+ export declare const linesUsageStrategy: 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: "lines";
7
+ }>;
8
+ usage: "lines";
9
+ }>;
@@ -0,0 +1,9 @@
1
+ export const linesUsageStrategy = Object.freeze({
2
+ resolve(input) {
3
+ return Object.freeze({
4
+ intent: input.intent,
5
+ usage: 'lines',
6
+ });
7
+ },
8
+ usage: 'lines',
9
+ });
@@ -0,0 +1,9 @@
1
+ export declare const overlaysUsageStrategy: 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: "overlays";
7
+ }>;
8
+ usage: "overlays";
9
+ }>;
@@ -0,0 +1,9 @@
1
+ export const overlaysUsageStrategy = Object.freeze({
2
+ resolve(input) {
3
+ return Object.freeze({
4
+ intent: input.intent,
5
+ usage: 'overlays',
6
+ });
7
+ },
8
+ usage: 'overlays',
9
+ });
@@ -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,9 @@
1
+ export const visualVocabularyUsageStrategy = Object.freeze({
2
+ resolve(input) {
3
+ return Object.freeze({
4
+ intent: input.intent,
5
+ usage: 'visualVocabulary',
6
+ });
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,22 +1,3 @@
1
- export { generateAlphaScale } from "./alpha/generateAlphaScale.js";
2
- export { apcaContrast } from "./contrast/apca.js";
3
- export { onSolidTextTokens } from "./contrast/onSolid.js";
4
- export { adjustTextColor } from "./contrast/solveText.js";
5
- export type { CreateThemeOptions, TokenOverrides } from "./createTheme.js";
6
- export { createTheme } from "./createTheme.js";
7
- export { radixSeedNames, radixSeeds } from "./data/radixSeeds.js";
8
- export { analyzeScale } from "./diagnostics/analyzeScale.js";
9
- export { analyzeTheme } from "./diagnostics/analyzeTheme.js";
10
- export { selectThemeColorMode } from "./exporters/selectColorMode.js";
11
- export { toCssVars } from "./exporters/toCssVars.js";
12
- export { toJson, toJsonWithMode } from "./exporters/toJson.js";
13
- export { toReactNative } from "./exporters/toReactNative.js";
14
- export { toTailwind } from "./exporters/toTailwind.js";
15
- export { toTs, toTsWithMode } from "./exporters/toTs.js";
16
- export type { AnchorStepOption, AutoAnchorModeOptions, AutoAnchorOptions, GenerateScaleOptions, SeedNormalizeOptions, SeedNormalizeRange, } from "./generateScale.js";
17
- export { generateScale } from "./generateScale.js";
18
- export { generateOverlayScale } from "./overlays/generateOverlayScale.js";
19
- export { generateTextScale } from "./text/generateTextScale.js";
20
- export type { TextOnBgTokens } from "./text/resolveOnBgText.js";
21
- export { resolveOnBgTextTokens } from "./text/resolveOnBgText.js";
22
- export type { AlphaScale, AlphaScales, ColorHex, ColorSource, OklchColor, OverlayScale, RadixSeedName, Scale, ScaleColorMode, ScaleDiagnostics, Step, TemplateId, TextScale, Theme, ThemeColorMode, ThemeDiagnostics, } from "./types.js";
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,18 +1,2 @@
1
- export { generateAlphaScale } from "./alpha/generateAlphaScale.js";
2
- export { apcaContrast } from "./contrast/apca.js";
3
- export { onSolidTextTokens } from "./contrast/onSolid.js";
4
- export { adjustTextColor } from "./contrast/solveText.js";
5
- export { createTheme } from "./createTheme.js";
6
- export { radixSeedNames, radixSeeds } from "./data/radixSeeds.js";
7
- export { analyzeScale } from "./diagnostics/analyzeScale.js";
8
- export { analyzeTheme } from "./diagnostics/analyzeTheme.js";
9
- export { selectThemeColorMode } from "./exporters/selectColorMode.js";
10
- export { toCssVars } from "./exporters/toCssVars.js";
11
- export { toJson, toJsonWithMode } from "./exporters/toJson.js";
12
- export { toReactNative } from "./exporters/toReactNative.js";
13
- export { toTailwind } from "./exporters/toTailwind.js";
14
- export { toTs, toTsWithMode } from "./exporters/toTs.js";
15
- export { generateScale } from "./generateScale.js";
16
- export { generateOverlayScale } from "./overlays/generateOverlayScale.js";
17
- export { generateTextScale } from "./text/generateTextScale.js";
18
- export { resolveOnBgTextTokens } from "./text/resolveOnBgText.js";
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
+ }