@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,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HSL Color Schema Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests for the HSL color space (Hue, Saturation, Lightness)
|
|
5
|
+
* Validates against ColorJS for parity
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { log } from "@tests/helpers/logger";
|
|
9
|
+
import { executeWithSchema, getBundledSchema } from "@tests/helpers/schema-test-utils";
|
|
10
|
+
import Color from "colorjs.io";
|
|
11
|
+
import { describe, expect, it } from "vitest";
|
|
12
|
+
import type { ColorSpecification } from "@/bundler/types";
|
|
13
|
+
|
|
14
|
+
// ColorJS reference tolerance
|
|
15
|
+
const TOLERANCE = 1e-9;
|
|
16
|
+
const HUE_TOLERANCE = 1e-6;
|
|
17
|
+
|
|
18
|
+
describe("HSL Color Schema", () => {
|
|
19
|
+
describe("Schema Definition", () => {
|
|
20
|
+
it("should have correct schema structure", async () => {
|
|
21
|
+
const schema = (await getBundledSchema("hsl-color")) as ColorSpecification;
|
|
22
|
+
|
|
23
|
+
expect(schema.name).toBe("HSL");
|
|
24
|
+
expect(schema.type).toBe("color");
|
|
25
|
+
expect(schema.schema).toBeDefined();
|
|
26
|
+
expect(schema.schema?.properties).toHaveProperty("h");
|
|
27
|
+
expect(schema.schema?.properties).toHaveProperty("s");
|
|
28
|
+
expect(schema.schema?.properties).toHaveProperty("l");
|
|
29
|
+
expect(schema.schema?.required).toEqual(["h", "s", "l"]);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("should have hsl initializer", async () => {
|
|
33
|
+
const schema = (await getBundledSchema("hsl-color")) as ColorSpecification;
|
|
34
|
+
|
|
35
|
+
expect(schema.initializers).toHaveLength(1);
|
|
36
|
+
expect(schema.initializers[0].keyword).toBe("hsl");
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("should have conversion from sRGB", async () => {
|
|
40
|
+
const schema = (await getBundledSchema("hsl-color")) as ColorSpecification;
|
|
41
|
+
|
|
42
|
+
expect(schema.conversions).toHaveLength(1);
|
|
43
|
+
|
|
44
|
+
const srgbToHsl = schema.conversions.find((c: { source: string }) =>
|
|
45
|
+
c.source.includes("srgb-color"),
|
|
46
|
+
);
|
|
47
|
+
expect(srgbToHsl).toBeDefined();
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
describe("Conversion from sRGB to HSL", () => {
|
|
52
|
+
it("should convert sRGB red to HSL", async () => {
|
|
53
|
+
const result = await executeWithSchema(
|
|
54
|
+
"hsl-color",
|
|
55
|
+
"type",
|
|
56
|
+
`
|
|
57
|
+
variable srgb: Color.SRGB;
|
|
58
|
+
srgb.r = 1;
|
|
59
|
+
srgb.g = 0;
|
|
60
|
+
srgb.b = 0;
|
|
61
|
+
srgb.to.hsl()
|
|
62
|
+
`,
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
// ColorJS reference (uses 0-100 for S and L, we use 0-1)
|
|
66
|
+
const colorJS = new Color("srgb", [1, 0, 0]).to("hsl");
|
|
67
|
+
const cjS = colorJS.coords[1] / 100;
|
|
68
|
+
const cjL = colorJS.coords[2] / 100;
|
|
69
|
+
|
|
70
|
+
log.info(`\n=== sRGB RED → HSL ===`);
|
|
71
|
+
log.info(
|
|
72
|
+
`TokenScript: { h: ${(result as any).value.h.value}, s: ${(result as any).value.s.value}, l: ${(result as any).value.l.value} }`,
|
|
73
|
+
);
|
|
74
|
+
log.info(`ColorJS: { h: ${colorJS.coords[0]}, s: ${cjS}, l: ${cjL} } (normalized)`);
|
|
75
|
+
|
|
76
|
+
expect((result as any).value.h.value).toBeCloseTo(colorJS.coords[0], 6);
|
|
77
|
+
expect((result as any).value.s.value).toBeCloseTo(cjS, 9);
|
|
78
|
+
expect((result as any).value.l.value).toBeCloseTo(cjL, 9);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
describe("ColorJS Parity", () => {
|
|
83
|
+
const testCases = [
|
|
84
|
+
{ name: "red", srgb: [1, 0, 0], expectedH: 0 },
|
|
85
|
+
{ name: "green", srgb: [0, 1, 0], expectedH: 120 },
|
|
86
|
+
{ name: "blue", srgb: [0, 0, 1], expectedH: 240 },
|
|
87
|
+
{ name: "cyan", srgb: [0, 1, 1], expectedH: 180 },
|
|
88
|
+
{ name: "magenta", srgb: [1, 0, 1], expectedH: 300 },
|
|
89
|
+
{ name: "yellow", srgb: [1, 1, 0], expectedH: 60 },
|
|
90
|
+
{ name: "coral", srgb: [1, 0.5, 0.314], expectedH: null },
|
|
91
|
+
];
|
|
92
|
+
|
|
93
|
+
for (const { name, srgb, expectedH } of testCases) {
|
|
94
|
+
it(`should match ColorJS for ${name}`, async () => {
|
|
95
|
+
const result = await executeWithSchema(
|
|
96
|
+
"hsl-color",
|
|
97
|
+
"type",
|
|
98
|
+
`
|
|
99
|
+
variable srgb: Color.SRGB;
|
|
100
|
+
srgb.r = ${srgb[0]};
|
|
101
|
+
srgb.g = ${srgb[1]};
|
|
102
|
+
srgb.b = ${srgb[2]};
|
|
103
|
+
srgb.to.hsl()
|
|
104
|
+
`,
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
// ColorJS reference (uses 0-100 for S and L, we use 0-1)
|
|
108
|
+
const colorJS = new Color("srgb", srgb as [number, number, number]).to("hsl");
|
|
109
|
+
|
|
110
|
+
const tsH = (result as any).value.h.value;
|
|
111
|
+
const tsS = (result as any).value.s.value;
|
|
112
|
+
const tsL = (result as any).value.l.value;
|
|
113
|
+
|
|
114
|
+
// ColorJS uses 0-100 scale for S and L, convert to 0-1 for comparison
|
|
115
|
+
const cjS = colorJS.coords[1] / 100;
|
|
116
|
+
const cjL = colorJS.coords[2] / 100;
|
|
117
|
+
|
|
118
|
+
let diffH = Math.abs(tsH - colorJS.coords[0]);
|
|
119
|
+
if (diffH > 180) diffH = 360 - diffH;
|
|
120
|
+
const diffS = Math.abs(tsS - cjS);
|
|
121
|
+
const diffL = Math.abs(tsL - cjL);
|
|
122
|
+
const maxDiff = Math.max(diffS, diffL);
|
|
123
|
+
|
|
124
|
+
log.info(`\n=== ${name.toUpperCase()} ColorJS Parity ===`);
|
|
125
|
+
log.info(`Input sRGB: { r: ${srgb[0]}, g: ${srgb[1]}, b: ${srgb[2]} }`);
|
|
126
|
+
log.info(
|
|
127
|
+
`TokenScript: { h: ${tsH.toFixed(3)}, s: ${tsS.toFixed(6)}, l: ${tsL.toFixed(6)} }`,
|
|
128
|
+
);
|
|
129
|
+
log.info(
|
|
130
|
+
`ColorJS: { h: ${colorJS.coords[0].toFixed(3)}, s: ${cjS.toFixed(6)}, l: ${cjL.toFixed(6)} } (normalized from 0-100)`,
|
|
131
|
+
);
|
|
132
|
+
log.info(`Max Diff (S,L): ${maxDiff.toExponential(2)}`);
|
|
133
|
+
log.info(`Hue Diff: ${diffH.toExponential(2)}`);
|
|
134
|
+
log.info(
|
|
135
|
+
`Status: ${maxDiff < TOLERANCE && diffH < HUE_TOLERANCE ? "✅ PASS" : "❌ FAIL"}`,
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
expect(maxDiff).toBeLessThan(TOLERANCE);
|
|
139
|
+
expect(diffH).toBeLessThan(HUE_TOLERANCE);
|
|
140
|
+
|
|
141
|
+
// For primary colors, also check expected hue
|
|
142
|
+
if (expectedH !== null) {
|
|
143
|
+
expect(tsH).toBeCloseTo(expectedH, 5);
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
describe("Edge Cases", () => {
|
|
150
|
+
it("should handle white (S=0)", async () => {
|
|
151
|
+
const result = await executeWithSchema(
|
|
152
|
+
"hsl-color",
|
|
153
|
+
"type",
|
|
154
|
+
`
|
|
155
|
+
variable srgb: Color.SRGB;
|
|
156
|
+
srgb.r = 1;
|
|
157
|
+
srgb.g = 1;
|
|
158
|
+
srgb.b = 1;
|
|
159
|
+
srgb.to.hsl()
|
|
160
|
+
`,
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
expect((result as any).value.s.value).toBeCloseTo(0, 9);
|
|
164
|
+
expect((result as any).value.l.value).toBeCloseTo(1, 9);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it("should handle black (S=0, L=0)", async () => {
|
|
168
|
+
const result = await executeWithSchema(
|
|
169
|
+
"hsl-color",
|
|
170
|
+
"type",
|
|
171
|
+
`
|
|
172
|
+
variable srgb: Color.SRGB;
|
|
173
|
+
srgb.r = 0;
|
|
174
|
+
srgb.g = 0;
|
|
175
|
+
srgb.b = 0;
|
|
176
|
+
srgb.to.hsl()
|
|
177
|
+
`,
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
expect((result as any).value.s.value).toBeCloseTo(0, 9);
|
|
181
|
+
expect((result as any).value.l.value).toBeCloseTo(0, 9);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it("should handle gray (S=0)", async () => {
|
|
185
|
+
const result = await executeWithSchema(
|
|
186
|
+
"hsl-color",
|
|
187
|
+
"type",
|
|
188
|
+
`
|
|
189
|
+
variable srgb: Color.SRGB;
|
|
190
|
+
srgb.r = 0.5;
|
|
191
|
+
srgb.g = 0.5;
|
|
192
|
+
srgb.b = 0.5;
|
|
193
|
+
srgb.to.hsl()
|
|
194
|
+
`,
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
expect((result as any).value.s.value).toBeCloseTo(0, 9);
|
|
198
|
+
expect((result as any).value.l.value).toBeCloseTo(0.5, 9);
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
});
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// sRGB to HSV Conversion
|
|
2
|
+
// Reference: Standard RGB to HSV algorithm
|
|
3
|
+
//
|
|
4
|
+
// Algorithm:
|
|
5
|
+
// V = max(R, G, B)
|
|
6
|
+
// S = (V - min(R, G, B)) / V (if V > 0)
|
|
7
|
+
// H depends on which channel is max
|
|
8
|
+
//
|
|
9
|
+
// Input: Color.SRGB with r, g, b in 0-1 range
|
|
10
|
+
// Output: Color.HSV with h (0-360), s (0-1), v (0-1)
|
|
11
|
+
|
|
12
|
+
// Get input sRGB values
|
|
13
|
+
variable r: Number = {input}.r;
|
|
14
|
+
variable g: Number = {input}.g;
|
|
15
|
+
variable b: Number = {input}.b;
|
|
16
|
+
|
|
17
|
+
// Find max and min
|
|
18
|
+
variable max_val: Number = r;
|
|
19
|
+
if (g > max_val) [
|
|
20
|
+
max_val = g;
|
|
21
|
+
];
|
|
22
|
+
if (b > max_val) [
|
|
23
|
+
max_val = b;
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
variable min_val: Number = r;
|
|
27
|
+
if (g < min_val) [
|
|
28
|
+
min_val = g;
|
|
29
|
+
];
|
|
30
|
+
if (b < min_val) [
|
|
31
|
+
min_val = b;
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
// Value is the max channel
|
|
35
|
+
variable v: Number = max_val;
|
|
36
|
+
|
|
37
|
+
// Calculate saturation and hue
|
|
38
|
+
variable s: Number = 0;
|
|
39
|
+
variable h: Number = 0;
|
|
40
|
+
variable delta: Number = max_val - min_val;
|
|
41
|
+
|
|
42
|
+
if (max_val > 0) [
|
|
43
|
+
s = delta / max_val;
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
if (delta > 0) [
|
|
47
|
+
// Hue calculation depends on which channel is max
|
|
48
|
+
if (max_val == r) [
|
|
49
|
+
h = ((g - b) / delta);
|
|
50
|
+
if (g < b) [
|
|
51
|
+
h = h + 6;
|
|
52
|
+
];
|
|
53
|
+
] else [
|
|
54
|
+
if (max_val == g) [
|
|
55
|
+
h = (b - r) / delta + 2;
|
|
56
|
+
] else [
|
|
57
|
+
h = (r - g) / delta + 4;
|
|
58
|
+
];
|
|
59
|
+
];
|
|
60
|
+
|
|
61
|
+
// Convert to degrees
|
|
62
|
+
h = h * 60;
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
// Normalize hue to 0-360
|
|
66
|
+
if (h < 0) [
|
|
67
|
+
h = h + 360;
|
|
68
|
+
];
|
|
69
|
+
|
|
70
|
+
// Create output
|
|
71
|
+
variable output: Color.HSV;
|
|
72
|
+
output.h = h;
|
|
73
|
+
output.s = s;
|
|
74
|
+
output.v = v;
|
|
75
|
+
|
|
76
|
+
return output;
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// HSV Color Initializer
|
|
2
|
+
// Creates an HSV color from H, S, V values
|
|
3
|
+
// Input: List of [h, s, v] values
|
|
4
|
+
|
|
5
|
+
variable hsv_values: List = {input};
|
|
6
|
+
variable output: Color.HSV;
|
|
7
|
+
|
|
8
|
+
output.h = hsv_values.get(0);
|
|
9
|
+
output.s = hsv_values.get(1);
|
|
10
|
+
output.v = hsv_values.get(2);
|
|
11
|
+
|
|
12
|
+
return output;
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "HSV",
|
|
3
|
+
"type": "color",
|
|
4
|
+
"description": "HSV color space - Hue, Saturation, Value. Also known as HSB (Hue, Saturation, Brightness).",
|
|
5
|
+
"schema": {
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"h": {
|
|
9
|
+
"type": "number",
|
|
10
|
+
"description": "Hue angle (0-360 degrees)"
|
|
11
|
+
},
|
|
12
|
+
"s": {
|
|
13
|
+
"type": "number",
|
|
14
|
+
"description": "Saturation (0-1)"
|
|
15
|
+
},
|
|
16
|
+
"v": {
|
|
17
|
+
"type": "number",
|
|
18
|
+
"description": "Value/Brightness (0-1)"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"required": ["h", "s", "v"],
|
|
22
|
+
"order": ["h", "s", "v"],
|
|
23
|
+
"additionalProperties": false
|
|
24
|
+
},
|
|
25
|
+
"initializers": [
|
|
26
|
+
{
|
|
27
|
+
"title": "HSV Color Initializer",
|
|
28
|
+
"keyword": "hsv",
|
|
29
|
+
"description": "Creates an HSV color from H, S, V values",
|
|
30
|
+
"script": {
|
|
31
|
+
"type": "/api/v1/core/tokenscript/0/",
|
|
32
|
+
"script": "./initializer.tokenscript"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
],
|
|
36
|
+
"conversions": [
|
|
37
|
+
{
|
|
38
|
+
"source": "/api/v1/core/srgb-color/0/",
|
|
39
|
+
"target": "$self",
|
|
40
|
+
"description": "Converts sRGB to HSV",
|
|
41
|
+
"lossless": true,
|
|
42
|
+
"script": {
|
|
43
|
+
"type": "/api/v1/core/tokenscript/0/",
|
|
44
|
+
"script": "./from-srgb.tokenscript"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HSV Color Schema Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests for the HSV color space (Hue, Saturation, Value)
|
|
5
|
+
* Validates against ColorJS for parity
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { log } from "@tests/helpers/logger";
|
|
9
|
+
import { executeWithSchema, getBundledSchema } from "@tests/helpers/schema-test-utils";
|
|
10
|
+
import Color from "colorjs.io";
|
|
11
|
+
import { describe, expect, it } from "vitest";
|
|
12
|
+
import type { ColorSpecification } from "@/bundler/types";
|
|
13
|
+
|
|
14
|
+
// ColorJS reference tolerance
|
|
15
|
+
const TOLERANCE = 1e-9;
|
|
16
|
+
const HUE_TOLERANCE = 1e-6;
|
|
17
|
+
|
|
18
|
+
describe("HSV Color Schema", () => {
|
|
19
|
+
describe("Schema Definition", () => {
|
|
20
|
+
it("should have correct schema structure", async () => {
|
|
21
|
+
const schema = (await getBundledSchema("hsv-color")) as ColorSpecification;
|
|
22
|
+
|
|
23
|
+
expect(schema.name).toBe("HSV");
|
|
24
|
+
expect(schema.type).toBe("color");
|
|
25
|
+
expect(schema.schema).toBeDefined();
|
|
26
|
+
expect(schema.schema?.properties).toHaveProperty("h");
|
|
27
|
+
expect(schema.schema?.properties).toHaveProperty("s");
|
|
28
|
+
expect(schema.schema?.properties).toHaveProperty("v");
|
|
29
|
+
expect(schema.schema?.required).toEqual(["h", "s", "v"]);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("should have hsv initializer", async () => {
|
|
33
|
+
const schema = (await getBundledSchema("hsv-color")) as ColorSpecification;
|
|
34
|
+
|
|
35
|
+
expect(schema.initializers).toHaveLength(1);
|
|
36
|
+
expect(schema.initializers[0].keyword).toBe("hsv");
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("should have conversion from sRGB", async () => {
|
|
40
|
+
const schema = (await getBundledSchema("hsv-color")) as ColorSpecification;
|
|
41
|
+
|
|
42
|
+
expect(schema.conversions).toHaveLength(1);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
describe("ColorJS Parity", () => {
|
|
47
|
+
const testCases = [
|
|
48
|
+
{ name: "red", srgb: [1, 0, 0], expectedH: 0 },
|
|
49
|
+
{ name: "green", srgb: [0, 1, 0], expectedH: 120 },
|
|
50
|
+
{ name: "blue", srgb: [0, 0, 1], expectedH: 240 },
|
|
51
|
+
{ name: "cyan", srgb: [0, 1, 1], expectedH: 180 },
|
|
52
|
+
{ name: "magenta", srgb: [1, 0, 1], expectedH: 300 },
|
|
53
|
+
{ name: "yellow", srgb: [1, 1, 0], expectedH: 60 },
|
|
54
|
+
{ name: "coral", srgb: [1, 0.5, 0.314], expectedH: null },
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
for (const { name, srgb, expectedH } of testCases) {
|
|
58
|
+
it(`should match ColorJS for ${name}`, async () => {
|
|
59
|
+
const result = await executeWithSchema(
|
|
60
|
+
"hsv-color",
|
|
61
|
+
"type",
|
|
62
|
+
`
|
|
63
|
+
variable srgb: Color.SRGB;
|
|
64
|
+
srgb.r = ${srgb[0]};
|
|
65
|
+
srgb.g = ${srgb[1]};
|
|
66
|
+
srgb.b = ${srgb[2]};
|
|
67
|
+
srgb.to.hsv()
|
|
68
|
+
`,
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
// ColorJS reference (uses 0-100 for S and V, we use 0-1)
|
|
72
|
+
const colorJS = new Color("srgb", srgb as [number, number, number]).to("hsv");
|
|
73
|
+
const cjS = colorJS.coords[1] / 100;
|
|
74
|
+
const cjV = colorJS.coords[2] / 100;
|
|
75
|
+
|
|
76
|
+
const tsH = (result as any).value.h.value;
|
|
77
|
+
const tsS = (result as any).value.s.value;
|
|
78
|
+
const tsV = (result as any).value.v.value;
|
|
79
|
+
|
|
80
|
+
let diffH = Math.abs(tsH - colorJS.coords[0]);
|
|
81
|
+
if (diffH > 180) diffH = 360 - diffH;
|
|
82
|
+
const diffS = Math.abs(tsS - cjS);
|
|
83
|
+
const diffV = Math.abs(tsV - cjV);
|
|
84
|
+
const maxDiff = Math.max(diffS, diffV);
|
|
85
|
+
|
|
86
|
+
log.info(`\n=== ${name.toUpperCase()} ColorJS Parity ===`);
|
|
87
|
+
log.info(`Input sRGB: { r: ${srgb[0]}, g: ${srgb[1]}, b: ${srgb[2]} }`);
|
|
88
|
+
log.info(
|
|
89
|
+
`TokenScript: { h: ${tsH.toFixed(3)}, s: ${tsS.toFixed(6)}, v: ${tsV.toFixed(6)} }`,
|
|
90
|
+
);
|
|
91
|
+
log.info(
|
|
92
|
+
`ColorJS: { h: ${colorJS.coords[0].toFixed(3)}, s: ${cjS.toFixed(6)}, v: ${cjV.toFixed(6)} } (normalized)`,
|
|
93
|
+
);
|
|
94
|
+
log.info(`Max Diff (S,V): ${maxDiff.toExponential(2)}`);
|
|
95
|
+
log.info(`Hue Diff: ${diffH.toExponential(2)}`);
|
|
96
|
+
log.info(
|
|
97
|
+
`Status: ${maxDiff < TOLERANCE && diffH < HUE_TOLERANCE ? "✅ PASS" : "❌ FAIL"}`,
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
expect(maxDiff).toBeLessThan(TOLERANCE);
|
|
101
|
+
expect(diffH).toBeLessThan(HUE_TOLERANCE);
|
|
102
|
+
|
|
103
|
+
if (expectedH !== null) {
|
|
104
|
+
expect(tsH).toBeCloseTo(expectedH, 5);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
describe("Edge Cases", () => {
|
|
111
|
+
it("should handle white (S=0, V=1)", async () => {
|
|
112
|
+
const result = await executeWithSchema(
|
|
113
|
+
"hsv-color",
|
|
114
|
+
"type",
|
|
115
|
+
`
|
|
116
|
+
variable srgb: Color.SRGB;
|
|
117
|
+
srgb.r = 1;
|
|
118
|
+
srgb.g = 1;
|
|
119
|
+
srgb.b = 1;
|
|
120
|
+
srgb.to.hsv()
|
|
121
|
+
`,
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
expect((result as any).value.s.value).toBeCloseTo(0, 9);
|
|
125
|
+
expect((result as any).value.v.value).toBeCloseTo(1, 9);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it("should handle black (S=0, V=0)", async () => {
|
|
129
|
+
const result = await executeWithSchema(
|
|
130
|
+
"hsv-color",
|
|
131
|
+
"type",
|
|
132
|
+
`
|
|
133
|
+
variable srgb: Color.SRGB;
|
|
134
|
+
srgb.r = 0;
|
|
135
|
+
srgb.g = 0;
|
|
136
|
+
srgb.b = 0;
|
|
137
|
+
srgb.to.hsv()
|
|
138
|
+
`,
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
expect((result as any).value.s.value).toBeCloseTo(0, 9);
|
|
142
|
+
expect((result as any).value.v.value).toBeCloseTo(0, 9);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it("should handle gray (S=0)", async () => {
|
|
146
|
+
const result = await executeWithSchema(
|
|
147
|
+
"hsv-color",
|
|
148
|
+
"type",
|
|
149
|
+
`
|
|
150
|
+
variable srgb: Color.SRGB;
|
|
151
|
+
srgb.r = 0.5;
|
|
152
|
+
srgb.g = 0.5;
|
|
153
|
+
srgb.b = 0.5;
|
|
154
|
+
srgb.to.hsv()
|
|
155
|
+
`,
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
expect((result as any).value.s.value).toBeCloseTo(0, 9);
|
|
159
|
+
expect((result as any).value.v.value).toBeCloseTo(0.5, 9);
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// HSV to HWB Conversion
|
|
2
|
+
// Reference: CSS Color Level 4
|
|
3
|
+
//
|
|
4
|
+
// Algorithm:
|
|
5
|
+
// H stays the same
|
|
6
|
+
// W = (1 - S) * V (Whiteness)
|
|
7
|
+
// B = 1 - V (Blackness)
|
|
8
|
+
//
|
|
9
|
+
// Input: Color.HSV with h, s, v values
|
|
10
|
+
// Output: Color.HWB with h, w, b values
|
|
11
|
+
|
|
12
|
+
// Get input HSV values
|
|
13
|
+
variable h: Number = {input}.h;
|
|
14
|
+
variable s: Number = {input}.s;
|
|
15
|
+
variable v: Number = {input}.v;
|
|
16
|
+
|
|
17
|
+
// Calculate whiteness and blackness
|
|
18
|
+
variable w: Number = (1 - s) * v;
|
|
19
|
+
variable b: Number = 1 - v;
|
|
20
|
+
|
|
21
|
+
// Create output
|
|
22
|
+
variable output: Color.HWB;
|
|
23
|
+
output.h = h;
|
|
24
|
+
output.w = w;
|
|
25
|
+
output.b = b;
|
|
26
|
+
|
|
27
|
+
return output;
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// HWB Color Initializer
|
|
2
|
+
// Creates an HWB color from H, W, B values
|
|
3
|
+
// Input: List of [h, w, b] values
|
|
4
|
+
|
|
5
|
+
variable hwb_values: List = {input};
|
|
6
|
+
variable output: Color.HWB;
|
|
7
|
+
|
|
8
|
+
output.h = hwb_values.get(0);
|
|
9
|
+
output.w = hwb_values.get(1);
|
|
10
|
+
output.b = hwb_values.get(2);
|
|
11
|
+
|
|
12
|
+
return output;
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "HWB",
|
|
3
|
+
"type": "color",
|
|
4
|
+
"description": "HWB color space - Hue, Whiteness, Blackness. CSS Color Level 4.",
|
|
5
|
+
"schema": {
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"h": {
|
|
9
|
+
"type": "number",
|
|
10
|
+
"description": "Hue angle (0-360 degrees)"
|
|
11
|
+
},
|
|
12
|
+
"w": {
|
|
13
|
+
"type": "number",
|
|
14
|
+
"description": "Whiteness (0-1)"
|
|
15
|
+
},
|
|
16
|
+
"b": {
|
|
17
|
+
"type": "number",
|
|
18
|
+
"description": "Blackness (0-1)"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"required": ["h", "w", "b"],
|
|
22
|
+
"order": ["h", "w", "b"],
|
|
23
|
+
"additionalProperties": false
|
|
24
|
+
},
|
|
25
|
+
"initializers": [
|
|
26
|
+
{
|
|
27
|
+
"title": "HWB Color Initializer",
|
|
28
|
+
"keyword": "hwb",
|
|
29
|
+
"description": "Creates an HWB color from H, W, B values",
|
|
30
|
+
"script": {
|
|
31
|
+
"type": "/api/v1/core/tokenscript/0/",
|
|
32
|
+
"script": "./initializer.tokenscript"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
],
|
|
36
|
+
"conversions": [
|
|
37
|
+
{
|
|
38
|
+
"source": "/api/v1/core/hsv-color/0/",
|
|
39
|
+
"target": "$self",
|
|
40
|
+
"description": "Converts HSV to HWB",
|
|
41
|
+
"lossless": true,
|
|
42
|
+
"script": {
|
|
43
|
+
"type": "/api/v1/core/tokenscript/0/",
|
|
44
|
+
"script": "./from-hsv.tokenscript"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|