@tokens-studio/tokenscript-schemas 0.0.11 → 0.0.13
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/dist/cli/index.cjs +31 -8
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +30 -8
- package/dist/cli/index.js.map +1 -1
- package/package.json +2 -1
- package/src/bundler/bundle-schema.ts +146 -0
- package/src/bundler/index.ts +151 -0
- package/src/bundler/schema-dependency-resolver.ts +299 -0
- package/src/bundler/selective-bundler.test.ts +94 -0
- package/src/bundler/selective-bundler.ts +159 -0
- package/src/bundler/types.ts +93 -0
- package/src/bundler/utils.ts +74 -0
- package/src/cli/commands/bundle.integration.test.ts +153 -0
- package/src/cli/commands/bundle.test.ts +57 -0
- package/src/cli/commands/bundle.ts +237 -0
- package/src/cli/commands/list.ts +109 -0
- package/src/cli/config-schema.ts +36 -0
- package/src/cli/index.ts +50 -0
- package/src/cli/output-generator.ts +63 -0
- package/src/downloader/index.ts +248 -0
- package/src/downloader/types.ts +48 -0
- package/src/index.ts +8 -0
- package/src/schemas/functions/adjust_chroma/adjust-chroma.tokenscript +27 -0
- package/src/schemas/functions/adjust_chroma/schema.json +48 -0
- package/src/schemas/functions/adjust_chroma/unit.test.ts +76 -0
- package/src/schemas/functions/adjust_hue/adjust-hue.tokenscript +32 -0
- package/src/schemas/functions/adjust_hue/schema.json +48 -0
- package/src/schemas/functions/adjust_hue/unit.test.ts +68 -0
- package/src/schemas/functions/adjust_lightness/adjust-lightness.tokenscript +31 -0
- package/src/schemas/functions/adjust_lightness/schema.json +48 -0
- package/src/schemas/functions/adjust_lightness/unit.test.ts +88 -0
- package/src/schemas/functions/adjust_to_contrast/adjust-to-contrast.tokenscript +131 -0
- package/src/schemas/functions/adjust_to_contrast/schema.json +56 -0
- package/src/schemas/functions/adjust_to_contrast/unit.test.ts +81 -0
- package/src/schemas/functions/alpha_blend/alpha-blend.tokenscript +46 -0
- package/src/schemas/functions/alpha_blend/schema.json +28 -0
- package/src/schemas/functions/alpha_blend/unit.test.ts +135 -0
- package/src/schemas/functions/alpha_scale/alpha-scale.tokenscript +38 -0
- package/src/schemas/functions/alpha_scale/schema.json +24 -0
- package/src/schemas/functions/alpha_scale/unit.test.ts +50 -0
- package/src/schemas/functions/analogous/analogous.tokenscript +47 -0
- package/src/schemas/functions/analogous/schema.json +28 -0
- package/src/schemas/functions/analogous/unit.test.ts +64 -0
- package/src/schemas/functions/apca_contrast/apca-contrast.tokenscript +129 -0
- package/src/schemas/functions/apca_contrast/schema.json +24 -0
- package/src/schemas/functions/apca_contrast/unit.test.ts +259 -0
- package/src/schemas/functions/are_similar/are-similar.tokenscript +24 -0
- package/src/schemas/functions/are_similar/schema.json +57 -0
- package/src/schemas/functions/are_similar/unit.test.ts +57 -0
- package/src/schemas/functions/auto_text_color/auto-text-color.tokenscript +41 -0
- package/src/schemas/functions/auto_text_color/schema.json +53 -0
- package/src/schemas/functions/auto_text_color/unit.test.ts +122 -0
- package/src/schemas/functions/best_contrast/best-contrast.tokenscript +66 -0
- package/src/schemas/functions/best_contrast/schema.json +24 -0
- package/src/schemas/functions/best_contrast/unit.test.ts +64 -0
- package/src/schemas/functions/chroma/chroma.tokenscript +12 -0
- package/src/schemas/functions/chroma/schema.json +44 -0
- package/src/schemas/functions/chroma/unit.test.ts +86 -0
- package/src/schemas/functions/clamp_chroma/clamp-chroma.tokenscript +21 -0
- package/src/schemas/functions/clamp_chroma/schema.json +52 -0
- package/src/schemas/functions/clamp_chroma/unit.test.ts +60 -0
- package/src/schemas/functions/clamp_lightness/clamp-lightness.tokenscript +21 -0
- package/src/schemas/functions/clamp_lightness/schema.json +52 -0
- package/src/schemas/functions/clamp_lightness/unit.test.ts +76 -0
- package/src/schemas/functions/clamp_to_gamut/clamp-to-gamut.tokenscript +41 -0
- package/src/schemas/functions/clamp_to_gamut/schema.json +20 -0
- package/src/schemas/functions/clamp_to_gamut/unit.test.ts +167 -0
- package/src/schemas/functions/complement/complement.tokenscript +21 -0
- package/src/schemas/functions/complement/schema.json +20 -0
- package/src/schemas/functions/complement/unit.test.ts +81 -0
- package/src/schemas/functions/contrast_ratio/contrast-ratio.tokenscript +36 -0
- package/src/schemas/functions/contrast_ratio/schema.json +24 -0
- package/src/schemas/functions/contrast_ratio/unit.test.ts +91 -0
- package/src/schemas/functions/cooler/cooler.tokenscript +45 -0
- package/src/schemas/functions/cooler/schema.json +43 -0
- package/src/schemas/functions/cooler/unit.test.ts +69 -0
- package/src/schemas/functions/darken/darken.tokenscript +37 -0
- package/src/schemas/functions/darken/schema.json +24 -0
- package/src/schemas/functions/darken/unit.test.ts +105 -0
- package/src/schemas/functions/delta_e_2000/delta-e-2000.tokenscript +184 -0
- package/src/schemas/functions/delta_e_2000/schema.json +36 -0
- package/src/schemas/functions/delta_e_2000/unit.test.ts +243 -0
- package/src/schemas/functions/delta_e_76/delta-e-76.tokenscript +45 -0
- package/src/schemas/functions/delta_e_76/schema.json +24 -0
- package/src/schemas/functions/delta_e_76/unit.test.ts +123 -0
- package/src/schemas/functions/delta_e_ok/delta-e-ok.tokenscript +43 -0
- package/src/schemas/functions/delta_e_ok/schema.json +24 -0
- package/src/schemas/functions/delta_e_ok/unit.test.ts +235 -0
- package/src/schemas/functions/desaturate/desaturate.tokenscript +32 -0
- package/src/schemas/functions/desaturate/schema.json +24 -0
- package/src/schemas/functions/desaturate/unit.test.ts +54 -0
- package/src/schemas/functions/distributed/distributed.tokenscript +54 -0
- package/src/schemas/functions/distributed/schema.json +32 -0
- package/src/schemas/functions/distributed/unit.test.ts +58 -0
- package/src/schemas/functions/diverging/diverging.tokenscript +58 -0
- package/src/schemas/functions/diverging/schema.json +32 -0
- package/src/schemas/functions/diverging/unit.test.ts +70 -0
- package/src/schemas/functions/grayscale/grayscale.tokenscript +17 -0
- package/src/schemas/functions/grayscale/schema.json +20 -0
- package/src/schemas/functions/grayscale/unit.test.ts +79 -0
- package/src/schemas/functions/harmonize/harmonize.tokenscript +61 -0
- package/src/schemas/functions/harmonize/schema.json +52 -0
- package/src/schemas/functions/harmonize/unit.test.ts +56 -0
- package/src/schemas/functions/hue/hue.tokenscript +12 -0
- package/src/schemas/functions/hue/schema.json +44 -0
- package/src/schemas/functions/hue/unit.test.ts +75 -0
- package/src/schemas/functions/hue_difference/hue-difference.tokenscript +42 -0
- package/src/schemas/functions/hue_difference/schema.json +24 -0
- package/src/schemas/functions/hue_difference/unit.test.ts +125 -0
- package/src/schemas/functions/in_gamut/in-gamut.tokenscript +51 -0
- package/src/schemas/functions/in_gamut/schema.json +24 -0
- package/src/schemas/functions/in_gamut/unit.test.ts +178 -0
- package/src/schemas/functions/interpolate/interpolate.tokenscript +61 -0
- package/src/schemas/functions/interpolate/schema.json +52 -0
- package/src/schemas/functions/interpolate/unit.test.ts +96 -0
- package/src/schemas/functions/invert/invert-initializer.tokenscript +29 -0
- package/src/schemas/functions/invert/schema.json +20 -0
- package/src/schemas/functions/invert/unit.test.ts +216 -0
- package/src/schemas/functions/is_cool/is-cool.tokenscript +41 -0
- package/src/schemas/functions/is_cool/schema.json +20 -0
- package/src/schemas/functions/is_cool/unit.test.ts +189 -0
- package/src/schemas/functions/is_dark/is-dark.tokenscript +16 -0
- package/src/schemas/functions/is_dark/schema.json +24 -0
- package/src/schemas/functions/is_dark/unit.test.ts +87 -0
- package/src/schemas/functions/is_light/is-light.tokenscript +16 -0
- package/src/schemas/functions/is_light/schema.json +24 -0
- package/src/schemas/functions/is_light/unit.test.ts +86 -0
- package/src/schemas/functions/is_neutral/is-neutral.tokenscript +16 -0
- package/src/schemas/functions/is_neutral/schema.json +53 -0
- package/src/schemas/functions/is_neutral/unit.test.ts +85 -0
- package/src/schemas/functions/is_warm/is-warm.tokenscript +62 -0
- package/src/schemas/functions/is_warm/schema.json +20 -0
- package/src/schemas/functions/is_warm/unit.test.ts +161 -0
- package/src/schemas/functions/lighten/lighten.tokenscript +37 -0
- package/src/schemas/functions/lighten/schema.json +24 -0
- package/src/schemas/functions/lighten/unit.test.ts +109 -0
- package/src/schemas/functions/lightness/lightness.tokenscript +12 -0
- package/src/schemas/functions/lightness/schema.json +49 -0
- package/src/schemas/functions/lightness/unit.test.ts +99 -0
- package/src/schemas/functions/luminance/luminance.tokenscript +16 -0
- package/src/schemas/functions/luminance/schema.json +20 -0
- package/src/schemas/functions/luminance/unit.test.ts +105 -0
- package/src/schemas/functions/meets_contrast/meets-contrast.tokenscript +49 -0
- package/src/schemas/functions/meets_contrast/schema.json +28 -0
- package/src/schemas/functions/meets_contrast/unit.test.ts +170 -0
- package/src/schemas/functions/mix/mix.tokenscript +47 -0
- package/src/schemas/functions/mix/schema.json +28 -0
- package/src/schemas/functions/mix/unit.test.ts +95 -0
- package/src/schemas/functions/monochromatic/monochromatic.tokenscript +72 -0
- package/src/schemas/functions/monochromatic/schema.json +24 -0
- package/src/schemas/functions/monochromatic/unit.test.ts +91 -0
- package/src/schemas/functions/muted/muted.tokenscript +25 -0
- package/src/schemas/functions/muted/schema.json +48 -0
- package/src/schemas/functions/muted/unit.test.ts +100 -0
- package/src/schemas/functions/neutral_variant/neutral-variant.tokenscript +23 -0
- package/src/schemas/functions/neutral_variant/schema.json +48 -0
- package/src/schemas/functions/neutral_variant/unit.test.ts +102 -0
- package/src/schemas/functions/relative_luminance/relative-luminance.tokenscript +15 -0
- package/src/schemas/functions/relative_luminance/schema.json +49 -0
- package/src/schemas/functions/relative_luminance/unit.test.ts +104 -0
- package/src/schemas/functions/rotate_hue/rotate-hue.tokenscript +20 -0
- package/src/schemas/functions/rotate_hue/schema.json +24 -0
- package/src/schemas/functions/rotate_hue/unit.test.ts +86 -0
- package/src/schemas/functions/saturate/saturate.tokenscript +33 -0
- package/src/schemas/functions/saturate/schema.json +24 -0
- package/src/schemas/functions/saturate/unit.test.ts +59 -0
- package/src/schemas/functions/scale_chroma/scale-chroma.tokenscript +22 -0
- package/src/schemas/functions/scale_chroma/schema.json +48 -0
- package/src/schemas/functions/scale_chroma/unit.test.ts +79 -0
- package/src/schemas/functions/scale_lightness/scale-lightness.tokenscript +23 -0
- package/src/schemas/functions/scale_lightness/schema.json +48 -0
- package/src/schemas/functions/scale_lightness/unit.test.ts +73 -0
- package/src/schemas/functions/sepia/schema.json +48 -0
- package/src/schemas/functions/sepia/sepia.tokenscript +54 -0
- package/src/schemas/functions/sepia/unit.test.ts +88 -0
- package/src/schemas/functions/set_chroma/schema.json +24 -0
- package/src/schemas/functions/set_chroma/set-chroma.tokenscript +18 -0
- package/src/schemas/functions/set_chroma/unit.test.ts +79 -0
- package/src/schemas/functions/set_hue/schema.json +24 -0
- package/src/schemas/functions/set_hue/set-hue.tokenscript +18 -0
- package/src/schemas/functions/set_hue/unit.test.ts +90 -0
- package/src/schemas/functions/set_lightness/schema.json +24 -0
- package/src/schemas/functions/set_lightness/set-lightness.tokenscript +18 -0
- package/src/schemas/functions/set_lightness/unit.test.ts +80 -0
- package/src/schemas/functions/shade_scale/schema.json +24 -0
- package/src/schemas/functions/shade_scale/shade-scale.tokenscript +61 -0
- package/src/schemas/functions/shade_scale/unit.test.ts +64 -0
- package/src/schemas/functions/split_complement/schema.json +24 -0
- package/src/schemas/functions/split_complement/split-complement.tokenscript +38 -0
- package/src/schemas/functions/split_complement/unit.test.ts +53 -0
- package/src/schemas/functions/steps/schema.json +28 -0
- package/src/schemas/functions/steps/steps.tokenscript +54 -0
- package/src/schemas/functions/steps/unit.test.ts +71 -0
- package/src/schemas/functions/tetradic/schema.json +20 -0
- package/src/schemas/functions/tetradic/tetradic.tokenscript +40 -0
- package/src/schemas/functions/tetradic/unit.test.ts +50 -0
- package/src/schemas/functions/tint_scale/schema.json +32 -0
- package/src/schemas/functions/tint_scale/tint-scale.tokenscript +71 -0
- package/src/schemas/functions/tint_scale/unit.test.ts +64 -0
- package/src/schemas/functions/to_gamut/schema.json +48 -0
- package/src/schemas/functions/to_gamut/to-gamut.tokenscript +96 -0
- package/src/schemas/functions/to_gamut/unit.test.ts +97 -0
- package/src/schemas/functions/triadic/schema.json +20 -0
- package/src/schemas/functions/triadic/triadic.tokenscript +33 -0
- package/src/schemas/functions/triadic/unit.test.ts +64 -0
- package/src/schemas/functions/vibrant/schema.json +48 -0
- package/src/schemas/functions/vibrant/unit.test.ts +55 -0
- package/src/schemas/functions/vibrant/vibrant.tokenscript +29 -0
- package/src/schemas/functions/warmer/schema.json +43 -0
- package/src/schemas/functions/warmer/unit.test.ts +69 -0
- package/src/schemas/functions/warmer/warmer.tokenscript +45 -0
- package/src/schemas/functions/wcag_level/schema.json +48 -0
- package/src/schemas/functions/wcag_level/unit.test.ts +75 -0
- package/src/schemas/functions/wcag_level/wcag-level.tokenscript +50 -0
- package/src/schemas/types/css-color/from-hsl-color.tokenscript +16 -0
- package/src/schemas/types/css-color/from-hwb-color.tokenscript +16 -0
- package/src/schemas/types/css-color/from-lab-color.tokenscript +16 -0
- package/src/schemas/types/css-color/from-lch-color.tokenscript +16 -0
- package/src/schemas/types/css-color/from-oklab-color.tokenscript +16 -0
- package/src/schemas/types/css-color/from-oklch-color.tokenscript +16 -0
- package/src/schemas/types/css-color/from-p3-color.tokenscript +16 -0
- package/src/schemas/types/css-color/from-rgb-color.tokenscript +15 -0
- package/src/schemas/types/css-color/from-srgb-color.tokenscript +16 -0
- package/src/schemas/types/css-color/from-srgb-linear-color.tokenscript +16 -0
- package/src/schemas/types/css-color/from-xyz-d50-color.tokenscript +16 -0
- package/src/schemas/types/css-color/from-xyz-d65-color.tokenscript +16 -0
- package/src/schemas/types/css-color/initializer.tokenscript +13 -0
- package/src/schemas/types/css-color/schema.json +148 -0
- package/src/schemas/types/css-color/unit.test.ts +402 -0
- package/src/schemas/types/hex-color/initializer.tokenscript +3 -0
- package/src/schemas/types/hex-color/schema.json +24 -0
- package/src/schemas/types/hex-color/unit.test.ts +123 -0
- package/src/schemas/types/hsl-color/from-srgb.tokenscript +87 -0
- package/src/schemas/types/hsl-color/initializer.tokenscript +16 -0
- package/src/schemas/types/hsl-color/schema.json +48 -0
- package/src/schemas/types/hsl-color/unit.test.ts +201 -0
- package/src/schemas/types/hsv-color/from-srgb.tokenscript +80 -0
- package/src/schemas/types/hsv-color/initializer.tokenscript +16 -0
- package/src/schemas/types/hsv-color/schema.json +48 -0
- package/src/schemas/types/hsv-color/unit.test.ts +162 -0
- package/src/schemas/types/hwb-color/from-hsv.tokenscript +31 -0
- package/src/schemas/types/hwb-color/initializer.tokenscript +16 -0
- package/src/schemas/types/hwb-color/schema.json +48 -0
- package/src/schemas/types/hwb-color/unit.test.ts +150 -0
- package/src/schemas/types/lab-color/from-xyz-d50.tokenscript +78 -0
- package/src/schemas/types/lab-color/initializer.tokenscript +16 -0
- package/src/schemas/types/lab-color/schema.json +48 -0
- package/src/schemas/types/lab-color/unit.test.ts +263 -0
- package/src/schemas/types/lch-color/from-lab.tokenscript +44 -0
- package/src/schemas/types/lch-color/initializer.tokenscript +16 -0
- package/src/schemas/types/lch-color/schema.json +48 -0
- package/src/schemas/types/lch-color/unit.test.ts +173 -0
- package/src/schemas/types/okhsl-color/from-oklab.tokenscript +410 -0
- package/src/schemas/types/okhsl-color/initializer.tokenscript +24 -0
- package/src/schemas/types/okhsl-color/schema.json +48 -0
- package/src/schemas/types/okhsl-color/unit.test.ts +514 -0
- package/src/schemas/types/okhsv-color/from-oklab.tokenscript +286 -0
- package/src/schemas/types/okhsv-color/initializer.tokenscript +24 -0
- package/src/schemas/types/okhsv-color/schema.json +48 -0
- package/src/schemas/types/okhsv-color/unit.test.ts +499 -0
- package/src/schemas/types/oklab-color/from-okhsl.tokenscript +195 -0
- package/src/schemas/types/oklab-color/from-okhsv.tokenscript +197 -0
- package/src/schemas/types/oklab-color/from-oklch.tokenscript +39 -0
- package/src/schemas/types/oklab-color/from-xyz-d65.tokenscript +43 -0
- package/src/schemas/types/oklab-color/initializer.tokenscript +16 -0
- package/src/schemas/types/oklab-color/schema.json +78 -0
- package/src/schemas/types/oklab-color/unit.test.ts +345 -0
- package/src/schemas/types/oklch-color/from-oklab.tokenscript +45 -0
- package/src/schemas/types/oklch-color/initializer.tokenscript +16 -0
- package/src/schemas/types/oklch-color/schema.json +48 -0
- package/src/schemas/types/oklch-color/unit.test.ts +267 -0
- package/src/schemas/types/p3-color/from-p3-linear.tokenscript +59 -0
- package/src/schemas/types/p3-color/initializer.tokenscript +16 -0
- package/src/schemas/types/p3-color/schema.json +48 -0
- package/src/schemas/types/p3-color/unit.test.ts +119 -0
- package/src/schemas/types/p3-linear-color/from-xyz-d65.tokenscript +47 -0
- package/src/schemas/types/p3-linear-color/initializer.tokenscript +16 -0
- package/src/schemas/types/p3-linear-color/schema.json +48 -0
- package/src/schemas/types/p3-linear-color/unit.test.ts +82 -0
- package/src/schemas/types/rgb-color/from-hex.tokenscript +43 -0
- package/src/schemas/types/rgb-color/initializer.tokenscript +16 -0
- package/src/schemas/types/rgb-color/schema.json +55 -0
- package/src/schemas/types/rgb-color/to-hex.tokenscript +42 -0
- package/src/schemas/types/rgb-color/unit.test.ts +302 -0
- package/src/schemas/types/srgb-color/from-hsl.tokenscript +106 -0
- package/src/schemas/types/srgb-color/from-linear.tokenscript +58 -0
- package/src/schemas/types/srgb-color/from-rgb.tokenscript +20 -0
- package/src/schemas/types/srgb-color/initializer.tokenscript +16 -0
- package/src/schemas/types/srgb-color/schema.json +68 -0
- package/src/schemas/types/srgb-color/unit.test.ts +303 -0
- package/src/schemas/types/srgb-linear-color/from-srgb.tokenscript +55 -0
- package/src/schemas/types/srgb-linear-color/from-xyz-d65.tokenscript +34 -0
- package/src/schemas/types/srgb-linear-color/initializer.tokenscript +13 -0
- package/src/schemas/types/srgb-linear-color/schema.json +58 -0
- package/src/schemas/types/srgb-linear-color/unit.test.ts +291 -0
- package/src/schemas/types/xyz-d50-color/from-xyz-d65.tokenscript +36 -0
- package/src/schemas/types/xyz-d50-color/initializer.tokenscript +16 -0
- package/src/schemas/types/xyz-d50-color/schema.json +48 -0
- package/src/schemas/types/xyz-d50-color/unit.test.ts +240 -0
- package/src/schemas/types/xyz-d65-color/from-linear-p3.tokenscript +47 -0
- package/src/schemas/types/xyz-d65-color/from-linear-srgb.tokenscript +38 -0
- package/src/schemas/types/xyz-d65-color/from-oklab.tokenscript +44 -0
- package/src/schemas/types/xyz-d65-color/initializer.tokenscript +16 -0
- package/src/schemas/types/xyz-d65-color/schema.json +68 -0
- package/src/schemas/types/xyz-d65-color/unit.test.ts +319 -0
- package/src/utils/schema-uri.ts +192 -0
- package/src/utils/type.ts +194 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for the adjust_chroma function
|
|
3
|
+
* Adjusts chroma by relative amount
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { executeWithSchema, getBundledSchema } from "@tests/helpers/schema-test-utils";
|
|
7
|
+
import { describe, expect, it } from "vitest";
|
|
8
|
+
import type { FunctionSpecification } from "@/bundler/types";
|
|
9
|
+
|
|
10
|
+
describe("adjust_chroma function", () => {
|
|
11
|
+
describe("Schema Definition", () => {
|
|
12
|
+
it("should have correct schema structure", async () => {
|
|
13
|
+
const schema = (await getBundledSchema("adjust_chroma", "function")) as FunctionSpecification;
|
|
14
|
+
|
|
15
|
+
expect(schema.name).toBe("adjust_chroma");
|
|
16
|
+
expect(schema.type).toBe("function");
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe("Function Execution", () => {
|
|
21
|
+
it("should increase chroma with positive value", async () => {
|
|
22
|
+
const result = await executeWithSchema(
|
|
23
|
+
"adjust_chroma",
|
|
24
|
+
"function",
|
|
25
|
+
`
|
|
26
|
+
variable color: Color.SRGB;
|
|
27
|
+
color.r = 0.5; color.g = 0.4; color.b = 0.4;
|
|
28
|
+
adjust_chroma(color, 0.1).to.srgb()
|
|
29
|
+
`,
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
expect(result).toBeDefined();
|
|
33
|
+
// More saturated means greater difference between channels
|
|
34
|
+
const r = (result as any).value?.r?.value ?? (result as any).value?.r;
|
|
35
|
+
const g = (result as any).value?.g?.value ?? (result as any).value?.g;
|
|
36
|
+
expect(r - g).toBeGreaterThan(0.1);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("should decrease chroma with negative value", async () => {
|
|
40
|
+
const result = await executeWithSchema(
|
|
41
|
+
"adjust_chroma",
|
|
42
|
+
"function",
|
|
43
|
+
`
|
|
44
|
+
variable orange: Color.SRGB;
|
|
45
|
+
orange.r = 1; orange.g = 0.4; orange.b = 0;
|
|
46
|
+
adjust_chroma(orange, -0.1).to.srgb()
|
|
47
|
+
`,
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
expect(result).toBeDefined();
|
|
51
|
+
// Result should be less saturated
|
|
52
|
+
const g = (result as any).value?.g?.value ?? (result as any).value?.g;
|
|
53
|
+
expect(g).toBeGreaterThan(0.4);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("should clamp at zero", async () => {
|
|
57
|
+
const result = await executeWithSchema(
|
|
58
|
+
"adjust_chroma",
|
|
59
|
+
"function",
|
|
60
|
+
`
|
|
61
|
+
variable gray: Color.SRGB;
|
|
62
|
+
gray.r = 0.5; gray.g = 0.5; gray.b = 0.5;
|
|
63
|
+
adjust_chroma(gray, -1).to.srgb()
|
|
64
|
+
`,
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
expect(result).toBeDefined();
|
|
68
|
+
// Should remain gray (all channels equal)
|
|
69
|
+
const r = (result as any).value?.r?.value ?? (result as any).value?.r;
|
|
70
|
+
const g = (result as any).value?.g?.value ?? (result as any).value?.g;
|
|
71
|
+
const b = (result as any).value?.b?.value ?? (result as any).value?.b;
|
|
72
|
+
expect(Math.abs(r - g)).toBeLessThan(0.02);
|
|
73
|
+
expect(Math.abs(g - b)).toBeLessThan(0.02);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// adjust_hue: Rotate hue by a relative angle
|
|
2
|
+
//
|
|
3
|
+
// Adds the specified degrees to the color's hue, wrapping
|
|
4
|
+
// around the 360° color wheel. Positive values rotate clockwise,
|
|
5
|
+
// negative values rotate counter-clockwise.
|
|
6
|
+
//
|
|
7
|
+
// Uses OKLCH for perceptually uniform hue rotation.
|
|
8
|
+
// Preserves lightness and chroma.
|
|
9
|
+
|
|
10
|
+
variable input: List = {input};
|
|
11
|
+
variable color: Color.OKLCH = input.get(0).to.oklch();
|
|
12
|
+
variable degrees: Number = input.get(1);
|
|
13
|
+
|
|
14
|
+
// Calculate new hue
|
|
15
|
+
variable new_h: Number = color.h + degrees;
|
|
16
|
+
|
|
17
|
+
// Normalize to 0-360
|
|
18
|
+
while (new_h < 0) [
|
|
19
|
+
new_h = new_h + 360;
|
|
20
|
+
];
|
|
21
|
+
while (new_h >= 360) [
|
|
22
|
+
new_h = new_h - 360;
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
// Create result
|
|
26
|
+
variable result: Color.OKLCH;
|
|
27
|
+
result.l = color.l;
|
|
28
|
+
result.c = color.c;
|
|
29
|
+
result.h = new_h;
|
|
30
|
+
|
|
31
|
+
return result;
|
|
32
|
+
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "adjust_hue",
|
|
3
|
+
"type": "function",
|
|
4
|
+
"description": "Adjusts a color's hue by a relative amount in degrees. Positive values rotate clockwise, negative values counter-clockwise. Unlike set_hue which sets an absolute value, adjust_hue adds to the current hue. Uses OKLCH for perceptually uniform hue rotation.",
|
|
5
|
+
"keyword": "adjust_hue",
|
|
6
|
+
"requirements": ["/api/v1/core/srgb-color/0/", "/api/v1/core/oklch-color/0/"],
|
|
7
|
+
"schema": {
|
|
8
|
+
"type": "object",
|
|
9
|
+
"properties": {
|
|
10
|
+
"input": {
|
|
11
|
+
"type": "array",
|
|
12
|
+
"items": [
|
|
13
|
+
{
|
|
14
|
+
"description": "Color to adjust",
|
|
15
|
+
"type": "color"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"description": "Degrees to rotate hue (+ or -)",
|
|
19
|
+
"type": "number"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"minItems": 2,
|
|
23
|
+
"maxItems": 2
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"required": ["input"]
|
|
27
|
+
},
|
|
28
|
+
"returns": {
|
|
29
|
+
"type": "color",
|
|
30
|
+
"description": "Color with adjusted hue"
|
|
31
|
+
},
|
|
32
|
+
"script": {
|
|
33
|
+
"type": "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/tokenscript/0/",
|
|
34
|
+
"script": "./adjust-hue.tokenscript"
|
|
35
|
+
},
|
|
36
|
+
"examples": [
|
|
37
|
+
{
|
|
38
|
+
"description": "Shift red toward orange",
|
|
39
|
+
"input": ["#ff0000", 30],
|
|
40
|
+
"output": "Orange color"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"description": "Shift blue toward green",
|
|
44
|
+
"input": ["#0000ff", -60],
|
|
45
|
+
"output": "Cyan color"
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for the adjust_hue function
|
|
3
|
+
* Adjusts hue by relative degrees
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { executeWithSchema, getBundledSchema } from "@tests/helpers/schema-test-utils";
|
|
7
|
+
import { describe, expect, it } from "vitest";
|
|
8
|
+
import type { FunctionSpecification } from "@/bundler/types";
|
|
9
|
+
|
|
10
|
+
describe("adjust_hue function", () => {
|
|
11
|
+
describe("Schema Definition", () => {
|
|
12
|
+
it("should have correct schema structure", async () => {
|
|
13
|
+
const schema = (await getBundledSchema("adjust_hue", "function")) as FunctionSpecification;
|
|
14
|
+
|
|
15
|
+
expect(schema.name).toBe("adjust_hue");
|
|
16
|
+
expect(schema.type).toBe("function");
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe("Function Execution", () => {
|
|
21
|
+
it("should rotate hue clockwise", async () => {
|
|
22
|
+
const result = await executeWithSchema(
|
|
23
|
+
"adjust_hue",
|
|
24
|
+
"function",
|
|
25
|
+
`
|
|
26
|
+
variable red: Color.SRGB;
|
|
27
|
+
red.r = 1; red.g = 0; red.b = 0;
|
|
28
|
+
adjust_hue(red, 90).to.srgb()
|
|
29
|
+
`,
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
expect(result).toBeDefined();
|
|
33
|
+
expect((result as any).constructor.name).toBe("ColorSymbol");
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("should rotate hue counter-clockwise", async () => {
|
|
37
|
+
const result = await executeWithSchema(
|
|
38
|
+
"adjust_hue",
|
|
39
|
+
"function",
|
|
40
|
+
`
|
|
41
|
+
variable red: Color.SRGB;
|
|
42
|
+
red.r = 1; red.g = 0; red.b = 0;
|
|
43
|
+
adjust_hue(red, -90).to.srgb()
|
|
44
|
+
`,
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
expect(result).toBeDefined();
|
|
48
|
+
expect((result as any).constructor.name).toBe("ColorSymbol");
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("should wrap around at 360", async () => {
|
|
52
|
+
const result = await executeWithSchema(
|
|
53
|
+
"adjust_hue",
|
|
54
|
+
"function",
|
|
55
|
+
`
|
|
56
|
+
variable red: Color.SRGB;
|
|
57
|
+
red.r = 1; red.g = 0; red.b = 0;
|
|
58
|
+
adjust_hue(red, 360).to.srgb()
|
|
59
|
+
`,
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
expect(result).toBeDefined();
|
|
63
|
+
// Should be same hue as input (full rotation)
|
|
64
|
+
const r = (result as any).value?.r?.value ?? (result as any).value?.r;
|
|
65
|
+
expect(r).toBeGreaterThan(0.7);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// adjust_lightness: Adjust lightness by a relative amount
|
|
2
|
+
//
|
|
3
|
+
// Modifies the lightness of a color by adding the specified
|
|
4
|
+
// amount. Positive values lighten, negative values darken.
|
|
5
|
+
// Result is clamped to [0, 1].
|
|
6
|
+
//
|
|
7
|
+
// Preserves hue and chroma.
|
|
8
|
+
//
|
|
9
|
+
// Input: Any color space (converted to OKLCH internally)
|
|
10
|
+
// Output: OKLCH (working space)
|
|
11
|
+
// To get sRGB: adjust_lightness(color, 0.2).to.srgb()
|
|
12
|
+
|
|
13
|
+
variable input: List = {input};
|
|
14
|
+
variable color: Color.OKLCH = input.get(0).to.oklch();
|
|
15
|
+
variable amount: Number = input.get(1);
|
|
16
|
+
|
|
17
|
+
// Calculate new lightness
|
|
18
|
+
variable new_l: Number = color.l + amount;
|
|
19
|
+
|
|
20
|
+
// Clamp to valid range
|
|
21
|
+
if (new_l < 0) [ new_l = 0; ];
|
|
22
|
+
if (new_l > 1) [ new_l = 1; ];
|
|
23
|
+
|
|
24
|
+
// Create result
|
|
25
|
+
variable result: Color.OKLCH;
|
|
26
|
+
result.l = new_l;
|
|
27
|
+
result.c = color.c;
|
|
28
|
+
result.h = color.h;
|
|
29
|
+
|
|
30
|
+
return result;
|
|
31
|
+
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "adjust_lightness",
|
|
3
|
+
"type": "function",
|
|
4
|
+
"description": "Adjusts a color's lightness by a relative amount. Positive values make it lighter, negative values make it darker. Unlike set_lightness which sets an absolute value, adjust_lightness adds to the current lightness. Result is clamped to valid range [0, 1].",
|
|
5
|
+
"keyword": "adjust_lightness",
|
|
6
|
+
"requirements": ["/api/v1/core/srgb-color/0/", "/api/v1/core/oklch-color/0/"],
|
|
7
|
+
"schema": {
|
|
8
|
+
"type": "object",
|
|
9
|
+
"properties": {
|
|
10
|
+
"input": {
|
|
11
|
+
"type": "array",
|
|
12
|
+
"items": [
|
|
13
|
+
{
|
|
14
|
+
"description": "Color to adjust",
|
|
15
|
+
"type": "color"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"description": "Amount to adjust lightness (+/-)",
|
|
19
|
+
"type": "number"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"minItems": 2,
|
|
23
|
+
"maxItems": 2
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"required": ["input"]
|
|
27
|
+
},
|
|
28
|
+
"returns": {
|
|
29
|
+
"type": "color",
|
|
30
|
+
"description": "Color with adjusted lightness"
|
|
31
|
+
},
|
|
32
|
+
"script": {
|
|
33
|
+
"type": "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/tokenscript/0/",
|
|
34
|
+
"script": "./adjust-lightness.tokenscript"
|
|
35
|
+
},
|
|
36
|
+
"examples": [
|
|
37
|
+
{
|
|
38
|
+
"description": "Lighten a color",
|
|
39
|
+
"input": ["#808080", 0.2],
|
|
40
|
+
"output": "Lighter gray"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"description": "Darken a color",
|
|
44
|
+
"input": ["#808080", -0.3],
|
|
45
|
+
"output": "Darker gray"
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for the adjust_lightness function
|
|
3
|
+
* Adjusts lightness by relative amount
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { executeWithSchema, getBundledSchema } from "@tests/helpers/schema-test-utils";
|
|
7
|
+
import { describe, expect, it } from "vitest";
|
|
8
|
+
import type { FunctionSpecification } from "@/bundler/types";
|
|
9
|
+
|
|
10
|
+
describe("adjust_lightness function", () => {
|
|
11
|
+
describe("Schema Definition", () => {
|
|
12
|
+
it("should have correct schema structure", async () => {
|
|
13
|
+
const schema = (await getBundledSchema(
|
|
14
|
+
"adjust_lightness",
|
|
15
|
+
"function",
|
|
16
|
+
)) as FunctionSpecification;
|
|
17
|
+
|
|
18
|
+
expect(schema.name).toBe("adjust_lightness");
|
|
19
|
+
expect(schema.type).toBe("function");
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
describe("Function Execution", () => {
|
|
24
|
+
it("should increase lightness with positive value", async () => {
|
|
25
|
+
const result = await executeWithSchema(
|
|
26
|
+
"adjust_lightness",
|
|
27
|
+
"function",
|
|
28
|
+
`
|
|
29
|
+
variable gray: Color.SRGB;
|
|
30
|
+
gray.r = 0.3; gray.g = 0.3; gray.b = 0.3;
|
|
31
|
+
adjust_lightness(gray, 0.3).to.srgb()
|
|
32
|
+
`,
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
expect(result).toBeDefined();
|
|
36
|
+
const r = (result as any).value?.r?.value ?? (result as any).value?.r;
|
|
37
|
+
expect(r).toBeGreaterThan(0.4);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("should decrease lightness with negative value", async () => {
|
|
41
|
+
const result = await executeWithSchema(
|
|
42
|
+
"adjust_lightness",
|
|
43
|
+
"function",
|
|
44
|
+
`
|
|
45
|
+
variable gray: Color.SRGB;
|
|
46
|
+
gray.r = 0.7; gray.g = 0.7; gray.b = 0.7;
|
|
47
|
+
adjust_lightness(gray, -0.3).to.srgb()
|
|
48
|
+
`,
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
expect(result).toBeDefined();
|
|
52
|
+
const r = (result as any).value?.r?.value ?? (result as any).value?.r;
|
|
53
|
+
expect(r).toBeLessThan(0.6);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("should clamp to 0 at minimum", async () => {
|
|
57
|
+
const result = await executeWithSchema(
|
|
58
|
+
"adjust_lightness",
|
|
59
|
+
"function",
|
|
60
|
+
`
|
|
61
|
+
variable gray: Color.SRGB;
|
|
62
|
+
gray.r = 0.2; gray.g = 0.2; gray.b = 0.2;
|
|
63
|
+
adjust_lightness(gray, -1).to.srgb()
|
|
64
|
+
`,
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
expect(result).toBeDefined();
|
|
68
|
+
const r = (result as any).value?.r?.value ?? (result as any).value?.r;
|
|
69
|
+
expect(r).toBeCloseTo(0, 1);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("should clamp to 1 at maximum", async () => {
|
|
73
|
+
const result = await executeWithSchema(
|
|
74
|
+
"adjust_lightness",
|
|
75
|
+
"function",
|
|
76
|
+
`
|
|
77
|
+
variable gray: Color.SRGB;
|
|
78
|
+
gray.r = 0.8; gray.g = 0.8; gray.b = 0.8;
|
|
79
|
+
adjust_lightness(gray, 1).to.srgb()
|
|
80
|
+
`,
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
expect(result).toBeDefined();
|
|
84
|
+
const r = (result as any).value?.r?.value ?? (result as any).value?.r;
|
|
85
|
+
expect(r).toBeCloseTo(1, 1);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
});
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
// adjust_to_contrast: Adjust foreground to meet target WCAG contrast ratio
|
|
2
|
+
// Reference: WCAG 2.1 Contrast Ratio Definition
|
|
3
|
+
// Reference: https://www.w3.org/TR/WCAG21/#dfn-contrast-ratio
|
|
4
|
+
//
|
|
5
|
+
// Modifies the foreground color's lightness (in OKLCH) to achieve
|
|
6
|
+
// the specified contrast ratio against the background, while
|
|
7
|
+
// preserving hue and chroma.
|
|
8
|
+
//
|
|
9
|
+
// Parameters:
|
|
10
|
+
// foreground - Color to adjust
|
|
11
|
+
// background - Reference background color
|
|
12
|
+
// target_ratio - Minimum contrast ratio (default: 4.5 for WCAG AA)
|
|
13
|
+
//
|
|
14
|
+
// Uses binary search in OKLCH lightness for convergence.
|
|
15
|
+
//
|
|
16
|
+
// Input: Any color space (converted to OKLCH internally)
|
|
17
|
+
// Output: OKLCH (working space)
|
|
18
|
+
// To get sRGB: adjust_to_contrast(fg, bg, 4.5).to.srgb()
|
|
19
|
+
|
|
20
|
+
variable input: List = {input};
|
|
21
|
+
variable foreground: Color.OKLCH = input.get(0).to.oklch();
|
|
22
|
+
variable bg_xyz: Color.XYZD65 = input.get(1).to.xyzd65();
|
|
23
|
+
|
|
24
|
+
// Default to WCAG AA for normal text
|
|
25
|
+
variable target_ratio: Number = 4.5;
|
|
26
|
+
if (input.length() > 2) [
|
|
27
|
+
target_ratio = input.get(2);
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
// Get background luminance
|
|
31
|
+
variable bg_lum: Number = bg_xyz.y;
|
|
32
|
+
|
|
33
|
+
// Determine if we need to go lighter or darker
|
|
34
|
+
// Test with current foreground
|
|
35
|
+
variable test_oklch: Color.OKLCH;
|
|
36
|
+
test_oklch.l = foreground.l;
|
|
37
|
+
test_oklch.c = foreground.c;
|
|
38
|
+
test_oklch.h = foreground.h;
|
|
39
|
+
|
|
40
|
+
variable test_xyz: Color.XYZD65 = test_oklch.to.srgb().to.xyzd65();
|
|
41
|
+
variable fg_lum: Number = test_xyz.y;
|
|
42
|
+
|
|
43
|
+
// Calculate current contrast
|
|
44
|
+
variable l1: Number = fg_lum;
|
|
45
|
+
variable l2: Number = bg_lum;
|
|
46
|
+
if (l2 > l1) [
|
|
47
|
+
l1 = bg_lum;
|
|
48
|
+
l2 = fg_lum;
|
|
49
|
+
];
|
|
50
|
+
variable current_ratio: Number = (l1 + 0.05) / (l2 + 0.05);
|
|
51
|
+
|
|
52
|
+
// If already meets target, return as-is (in OKLCH working space)
|
|
53
|
+
if (current_ratio >= target_ratio) [
|
|
54
|
+
return foreground;
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
// Determine direction: if background is dark, we need lighter foreground and vice versa
|
|
58
|
+
variable search_min: Number = 0;
|
|
59
|
+
variable search_max: Number = 1;
|
|
60
|
+
|
|
61
|
+
// Binary search for correct lightness
|
|
62
|
+
variable epsilon: Number = 0.001;
|
|
63
|
+
variable iterations: Number = 0;
|
|
64
|
+
variable max_iterations: Number = 30;
|
|
65
|
+
variable best_l: Number = foreground.l;
|
|
66
|
+
variable best_ratio: Number = current_ratio;
|
|
67
|
+
|
|
68
|
+
variable diff: Number = search_max - search_min;
|
|
69
|
+
variable mid_l: Number = 0.5;
|
|
70
|
+
variable test_ratio: Number = 1;
|
|
71
|
+
|
|
72
|
+
while (diff > epsilon) [
|
|
73
|
+
if (iterations >= max_iterations) [
|
|
74
|
+
diff = 0; // Force exit
|
|
75
|
+
];
|
|
76
|
+
mid_l = (search_min + search_max) / 2;
|
|
77
|
+
|
|
78
|
+
// Test this lightness
|
|
79
|
+
test_oklch.l = mid_l;
|
|
80
|
+
test_oklch.c = foreground.c;
|
|
81
|
+
test_oklch.h = foreground.h;
|
|
82
|
+
|
|
83
|
+
// Convert to get luminance
|
|
84
|
+
test_xyz = test_oklch.to.srgb().to.xyzd65();
|
|
85
|
+
fg_lum = test_xyz.y;
|
|
86
|
+
|
|
87
|
+
// Calculate contrast
|
|
88
|
+
l1 = fg_lum;
|
|
89
|
+
l2 = bg_lum;
|
|
90
|
+
if (l2 > l1) [
|
|
91
|
+
l1 = bg_lum;
|
|
92
|
+
l2 = fg_lum;
|
|
93
|
+
];
|
|
94
|
+
test_ratio = (l1 + 0.05) / (l2 + 0.05);
|
|
95
|
+
|
|
96
|
+
// Track best result
|
|
97
|
+
if (test_ratio >= target_ratio) [
|
|
98
|
+
// This lightness works, but can we get closer to original?
|
|
99
|
+
// If background is dark (low lum), we want darker foreground closer to original
|
|
100
|
+
// If background is light (high lum), we want lighter foreground closer to original
|
|
101
|
+
if (bg_lum < 0.18) [
|
|
102
|
+
// Dark background: search lower (darker)
|
|
103
|
+
search_max = mid_l;
|
|
104
|
+
] else [
|
|
105
|
+
// Light background: search higher (lighter)
|
|
106
|
+
search_min = mid_l;
|
|
107
|
+
];
|
|
108
|
+
best_l = mid_l;
|
|
109
|
+
best_ratio = test_ratio;
|
|
110
|
+
] else [
|
|
111
|
+
// Not enough contrast, need more separation
|
|
112
|
+
if (bg_lum < 0.18) [
|
|
113
|
+
// Dark background: need lighter foreground
|
|
114
|
+
search_min = mid_l;
|
|
115
|
+
] else [
|
|
116
|
+
// Light background: need darker foreground
|
|
117
|
+
search_max = mid_l;
|
|
118
|
+
];
|
|
119
|
+
];
|
|
120
|
+
|
|
121
|
+
iterations = iterations + 1;
|
|
122
|
+
diff = search_max - search_min;
|
|
123
|
+
];
|
|
124
|
+
|
|
125
|
+
// Apply best lightness found, return in OKLCH working space
|
|
126
|
+
variable result: Color.OKLCH;
|
|
127
|
+
result.l = best_l;
|
|
128
|
+
result.c = foreground.c;
|
|
129
|
+
result.h = foreground.h;
|
|
130
|
+
|
|
131
|
+
return result;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "adjust_to_contrast",
|
|
3
|
+
"type": "function",
|
|
4
|
+
"description": "Adjusts a foreground color's lightness to achieve a target WCAG contrast ratio against a background. Preserves hue and chroma while finding the optimal lightness. Uses binary search in OKLCH space for perceptually even adjustments. If target contrast cannot be achieved (e.g., trying to get 21:1 with mid-gray), returns the best possible result.",
|
|
5
|
+
"keyword": "adjust_to_contrast",
|
|
6
|
+
"requirements": [
|
|
7
|
+
"/api/v1/core/srgb-color/0/",
|
|
8
|
+
"/api/v1/core/oklch-color/0/",
|
|
9
|
+
"/api/v1/core/xyz-d65-color/0/"
|
|
10
|
+
],
|
|
11
|
+
"schema": {
|
|
12
|
+
"type": "object",
|
|
13
|
+
"properties": {
|
|
14
|
+
"input": {
|
|
15
|
+
"type": "array",
|
|
16
|
+
"items": [
|
|
17
|
+
{
|
|
18
|
+
"description": "Foreground color to adjust",
|
|
19
|
+
"type": "color"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"description": "Background color (fixed)",
|
|
23
|
+
"type": "color"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"description": "Target contrast ratio (default 4.5 for WCAG AA)",
|
|
27
|
+
"type": "number"
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"minItems": 2,
|
|
31
|
+
"maxItems": 3
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"required": ["input"]
|
|
35
|
+
},
|
|
36
|
+
"returns": {
|
|
37
|
+
"type": "color",
|
|
38
|
+
"description": "Adjusted foreground color meeting the target contrast"
|
|
39
|
+
},
|
|
40
|
+
"script": {
|
|
41
|
+
"type": "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/tokenscript/0/",
|
|
42
|
+
"script": "./adjust-to-contrast.tokenscript"
|
|
43
|
+
},
|
|
44
|
+
"examples": [
|
|
45
|
+
{
|
|
46
|
+
"description": "Adjust light gray to meet AA on white",
|
|
47
|
+
"input": ["#cccccc", "#ffffff", 4.5],
|
|
48
|
+
"output": "Darkened gray meeting 4.5:1"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"description": "Adjust brand color for accessibility",
|
|
52
|
+
"input": ["#6750a4", "#ffffff", 4.5],
|
|
53
|
+
"output": "Adjusted purple meeting 4.5:1"
|
|
54
|
+
}
|
|
55
|
+
]
|
|
56
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for the adjust_to_contrast function
|
|
3
|
+
* Adjusts a color to meet a target contrast ratio
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { executeWithSchema, getBundledSchema } from "@tests/helpers/schema-test-utils";
|
|
7
|
+
import { describe, expect, it } from "vitest";
|
|
8
|
+
import type { FunctionSpecification } from "@/bundler/types";
|
|
9
|
+
|
|
10
|
+
describe("adjust_to_contrast function", () => {
|
|
11
|
+
describe("Schema Definition", () => {
|
|
12
|
+
it("should have correct schema structure", async () => {
|
|
13
|
+
const schema = (await getBundledSchema(
|
|
14
|
+
"adjust_to_contrast",
|
|
15
|
+
"function",
|
|
16
|
+
)) as FunctionSpecification;
|
|
17
|
+
|
|
18
|
+
expect(schema.name).toBe("adjust_to_contrast");
|
|
19
|
+
expect(schema.type).toBe("function");
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
describe("Function Execution", () => {
|
|
24
|
+
it("should return unchanged if already meets contrast", async () => {
|
|
25
|
+
const result = await executeWithSchema(
|
|
26
|
+
"adjust_to_contrast",
|
|
27
|
+
"function",
|
|
28
|
+
`
|
|
29
|
+
variable black: Color.SRGB;
|
|
30
|
+
black.r = 0; black.g = 0; black.b = 0;
|
|
31
|
+
variable white: Color.SRGB;
|
|
32
|
+
white.r = 1; white.g = 1; white.b = 1;
|
|
33
|
+
adjust_to_contrast(black, white, 4.5).to.srgb()
|
|
34
|
+
`,
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
expect(result).toBeDefined();
|
|
38
|
+
// Black on white already has 21:1 contrast, should stay black
|
|
39
|
+
const r = (result as any).value?.r?.value ?? (result as any).value?.r;
|
|
40
|
+
expect(r).toBeCloseTo(0, 1);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("should darken light color on white background", async () => {
|
|
44
|
+
const result = await executeWithSchema(
|
|
45
|
+
"adjust_to_contrast",
|
|
46
|
+
"function",
|
|
47
|
+
`
|
|
48
|
+
variable light_gray: Color.SRGB;
|
|
49
|
+
light_gray.r = 0.8; light_gray.g = 0.8; light_gray.b = 0.8;
|
|
50
|
+
variable white: Color.SRGB;
|
|
51
|
+
white.r = 1; white.g = 1; white.b = 1;
|
|
52
|
+
adjust_to_contrast(light_gray, white, 4.5).to.srgb()
|
|
53
|
+
`,
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
expect(result).toBeDefined();
|
|
57
|
+
// Result should be darker than original
|
|
58
|
+
const r = (result as any).value?.r?.value ?? (result as any).value?.r;
|
|
59
|
+
expect(r).toBeLessThan(0.7);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("should lighten dark color on black background", async () => {
|
|
63
|
+
const result = await executeWithSchema(
|
|
64
|
+
"adjust_to_contrast",
|
|
65
|
+
"function",
|
|
66
|
+
`
|
|
67
|
+
variable dark_gray: Color.SRGB;
|
|
68
|
+
dark_gray.r = 0.2; dark_gray.g = 0.2; dark_gray.b = 0.2;
|
|
69
|
+
variable black: Color.SRGB;
|
|
70
|
+
black.r = 0; black.g = 0; black.b = 0;
|
|
71
|
+
adjust_to_contrast(dark_gray, black, 4.5).to.srgb()
|
|
72
|
+
`,
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
expect(result).toBeDefined();
|
|
76
|
+
// Result should be lighter than original
|
|
77
|
+
const r = (result as any).value?.r?.value ?? (result as any).value?.r;
|
|
78
|
+
expect(r).toBeGreaterThan(0.3);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
});
|