@valbuild/core 0.100.0 → 0.101.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.
@@ -5454,6 +5454,647 @@ var datetime = function datetime(options) {
5454
5454
  return new DateTimeSchema(options);
5455
5455
  };
5456
5456
 
5457
+ /**
5458
+ * Parsing / formatting of the CSS color strings stored by `s.color()`.
5459
+ *
5460
+ * Colors are stored as plain CSS strings so that they can be used directly in
5461
+ * `style` attributes and CSS custom properties. The schema decides which family
5462
+ * (`hex`, `rgb`, `hsl` or `oklch`) the string is written in, this module does
5463
+ * the conversion between them.
5464
+ *
5465
+ * All colors are sRGB: `oklch` is only used as an output notation, so any
5466
+ * `oklch` value that falls outside the sRGB gamut is clipped when converted
5467
+ * back to the other formats.
5468
+ */
5469
+
5470
+ var COLOR_FORMATS = ["hex", "rgb", "hsl", "oklch"];
5471
+ var DEFAULT_COLOR_FORMAT = "hsl";
5472
+
5473
+ /**
5474
+ * A color, normalized to sRGB.
5475
+ *
5476
+ * `r`, `g` and `b` are 0-255 (not rounded), `a` is 0-1.
5477
+ */
5478
+
5479
+ /**
5480
+ * Which color notation a string uses, or `null` if it is not a notation we
5481
+ * recognize. This looks at the syntax only: `detectColorFormat` says nothing
5482
+ * about whether the value actually parses (`hsl(nope)` is still `"hsl"`).
5483
+ */
5484
+ function detectColorFormat(value) {
5485
+ var trimmed = value.trim().toLowerCase();
5486
+ if (trimmed.startsWith("#")) {
5487
+ return "hex";
5488
+ }
5489
+ if (trimmed.startsWith("rgb(") || trimmed.startsWith("rgba(")) {
5490
+ return "rgb";
5491
+ }
5492
+ if (trimmed.startsWith("hsl(") || trimmed.startsWith("hsla(")) {
5493
+ return "hsl";
5494
+ }
5495
+ if (trimmed.startsWith("oklch(")) {
5496
+ return "oklch";
5497
+ }
5498
+ return null;
5499
+ }
5500
+ function clamp(value, min, max) {
5501
+ if (Number.isNaN(value)) {
5502
+ return min;
5503
+ }
5504
+ return Math.min(max, Math.max(min, value));
5505
+ }
5506
+
5507
+ /**
5508
+ * Splits the inside of a CSS color function into components.
5509
+ *
5510
+ * Handles both the legacy comma syntax (`rgb(1, 2, 3, 0.5)`) and the modern
5511
+ * space syntax (`rgb(1 2 3 / 0.5)`), returning the alpha (if any) separately.
5512
+ */
5513
+ function splitComponents(args) {
5514
+ var slashParts = args.split("/");
5515
+ if (slashParts.length > 2) {
5516
+ return null;
5517
+ }
5518
+ var alpha = slashParts.length === 2 ? slashParts[1].trim() : null;
5519
+ var head = slashParts[0].trim();
5520
+ if (head === "") {
5521
+ return null;
5522
+ }
5523
+ var components;
5524
+ if (head.includes(",")) {
5525
+ if (alpha !== null) {
5526
+ // Mixing the comma and the slash syntax is not valid CSS
5527
+ return null;
5528
+ }
5529
+ components = head.split(",").map(function (part) {
5530
+ return part.trim();
5531
+ });
5532
+ if (components.length === 4) {
5533
+ alpha = components[3];
5534
+ components = components.slice(0, 3);
5535
+ }
5536
+ } else {
5537
+ components = head.split(/\s+/);
5538
+ }
5539
+ if (components.length !== 3 || components.some(function (part) {
5540
+ return part === "";
5541
+ })) {
5542
+ return null;
5543
+ }
5544
+ if (alpha === "") {
5545
+ return null;
5546
+ }
5547
+ return {
5548
+ components: components,
5549
+ alpha: alpha
5550
+ };
5551
+ }
5552
+ function parseNumber(value) {
5553
+ if (!/^[+-]?(\d+\.?\d*|\.\d+)$/.test(value)) {
5554
+ return null;
5555
+ }
5556
+ var parsed = Number(value);
5557
+ return Number.isFinite(parsed) ? parsed : null;
5558
+ }
5559
+
5560
+ /**
5561
+ * A `<number>` or a `<percentage>`, where 100% maps to `percentageBasis`.
5562
+ */
5563
+ function parseNumberOrPercentage(value, percentageBasis) {
5564
+ if (value.endsWith("%")) {
5565
+ var percentage = parseNumber(value.slice(0, -1));
5566
+ return percentage === null ? null : percentage / 100 * percentageBasis;
5567
+ }
5568
+ return parseNumber(value);
5569
+ }
5570
+ function parsePercentage(value) {
5571
+ if (!value.endsWith("%")) {
5572
+ return null;
5573
+ }
5574
+ return parseNumber(value.slice(0, -1));
5575
+ }
5576
+ function parseAlpha(value) {
5577
+ if (value === null) {
5578
+ return 1;
5579
+ }
5580
+ if (value === "none") {
5581
+ return 0;
5582
+ }
5583
+ var parsed = parseNumberOrPercentage(value, 1);
5584
+ return parsed === null ? null : clamp(parsed, 0, 1);
5585
+ }
5586
+ function parseHue(value) {
5587
+ var match = /^([+-]?(?:\d+\.?\d*|\.\d+))(deg|grad|rad|turn)?$/.exec(value);
5588
+ if (!match) {
5589
+ return null;
5590
+ }
5591
+ var amount = Number(match[1]);
5592
+ switch (match[2]) {
5593
+ case "grad":
5594
+ return amount / 400 * 360;
5595
+ case "rad":
5596
+ return amount * 180 / Math.PI;
5597
+ case "turn":
5598
+ return amount * 360;
5599
+ default:
5600
+ return amount;
5601
+ }
5602
+ }
5603
+ function normalizeHue(hue) {
5604
+ var wrapped = hue % 360;
5605
+ return wrapped < 0 ? wrapped + 360 : wrapped;
5606
+ }
5607
+ function parseHex(value) {
5608
+ var hex = value.slice(1);
5609
+ if (!/^[0-9a-f]+$/i.test(hex)) {
5610
+ return null;
5611
+ }
5612
+ var expand = function expand(_char) {
5613
+ return parseInt(_char + _char, 16);
5614
+ };
5615
+ var pair = function pair(index) {
5616
+ return parseInt(hex.slice(index, index + 2), 16);
5617
+ };
5618
+ if (hex.length === 3 || hex.length === 4) {
5619
+ return {
5620
+ r: expand(hex[0]),
5621
+ g: expand(hex[1]),
5622
+ b: expand(hex[2]),
5623
+ a: hex.length === 4 ? expand(hex[3]) / 255 : 1
5624
+ };
5625
+ }
5626
+ if (hex.length === 6 || hex.length === 8) {
5627
+ return {
5628
+ r: pair(0),
5629
+ g: pair(2),
5630
+ b: pair(4),
5631
+ a: hex.length === 8 ? pair(6) / 255 : 1
5632
+ };
5633
+ }
5634
+ return null;
5635
+ }
5636
+ function extractFunctionArgs(value, name) {
5637
+ if (!value.startsWith(name + "(") || !value.endsWith(")")) {
5638
+ return null;
5639
+ }
5640
+ return value.slice(name.length + 1, -1);
5641
+ }
5642
+ function parseRgb(value) {
5643
+ var _extractFunctionArgs;
5644
+ var args = (_extractFunctionArgs = extractFunctionArgs(value, "rgba")) !== null && _extractFunctionArgs !== void 0 ? _extractFunctionArgs : extractFunctionArgs(value, "rgb");
5645
+ if (args === null) {
5646
+ return null;
5647
+ }
5648
+ var split = splitComponents(args);
5649
+ if (!split) {
5650
+ return null;
5651
+ }
5652
+ var channels = split.components.map(function (component) {
5653
+ return component === "none" ? 0 : parseNumberOrPercentage(component, 255);
5654
+ });
5655
+ var alpha = parseAlpha(split.alpha);
5656
+ if (channels.some(function (channel) {
5657
+ return channel === null;
5658
+ }) || alpha === null) {
5659
+ return null;
5660
+ }
5661
+ return {
5662
+ r: clamp(channels[0], 0, 255),
5663
+ g: clamp(channels[1], 0, 255),
5664
+ b: clamp(channels[2], 0, 255),
5665
+ a: alpha
5666
+ };
5667
+ }
5668
+ function parseHsl(value) {
5669
+ var _extractFunctionArgs2, _parsePercentage, _parsePercentage2;
5670
+ var args = (_extractFunctionArgs2 = extractFunctionArgs(value, "hsla")) !== null && _extractFunctionArgs2 !== void 0 ? _extractFunctionArgs2 : extractFunctionArgs(value, "hsl");
5671
+ if (args === null) {
5672
+ return null;
5673
+ }
5674
+ var split = splitComponents(args);
5675
+ if (!split) {
5676
+ return null;
5677
+ }
5678
+ var _split$components = _slicedToArray(split.components, 3),
5679
+ rawHue = _split$components[0],
5680
+ rawSaturation = _split$components[1],
5681
+ rawLightness = _split$components[2];
5682
+ var hue = rawHue === "none" ? 0 : parseHue(rawHue);
5683
+ // CSS requires percentages for s/l in hsl(), but the modern syntax also
5684
+ // allows bare numbers, so accept both.
5685
+ var saturation = rawSaturation === "none" ? 0 : (_parsePercentage = parsePercentage(rawSaturation)) !== null && _parsePercentage !== void 0 ? _parsePercentage : parseNumber(rawSaturation);
5686
+ var lightness = rawLightness === "none" ? 0 : (_parsePercentage2 = parsePercentage(rawLightness)) !== null && _parsePercentage2 !== void 0 ? _parsePercentage2 : parseNumber(rawLightness);
5687
+ var alpha = parseAlpha(split.alpha);
5688
+ if (hue === null || saturation === null || lightness === null || alpha === null) {
5689
+ return null;
5690
+ }
5691
+ return _objectSpread2(_objectSpread2({}, hslToRgb(normalizeHue(hue), clamp(saturation, 0, 100), clamp(lightness, 0, 100))), {}, {
5692
+ a: alpha
5693
+ });
5694
+ }
5695
+ function parseOklch(value) {
5696
+ var args = extractFunctionArgs(value, "oklch");
5697
+ if (args === null) {
5698
+ return null;
5699
+ }
5700
+ var split = splitComponents(args);
5701
+ if (!split) {
5702
+ return null;
5703
+ }
5704
+ var _split$components2 = _slicedToArray(split.components, 3),
5705
+ rawLightness = _split$components2[0],
5706
+ rawChroma = _split$components2[1],
5707
+ rawHue = _split$components2[2];
5708
+ // Lightness is a <number> in 0-1 or a <percentage>, chroma is a <number>
5709
+ // where 0.4 is roughly the maximum, or a <percentage> where 100% = 0.4.
5710
+ var lightness = rawLightness === "none" ? 0 : parseNumberOrPercentage(rawLightness, 1);
5711
+ var chroma = rawChroma === "none" ? 0 : parseNumberOrPercentage(rawChroma, 0.4);
5712
+ var hue = rawHue === "none" ? 0 : parseHue(rawHue);
5713
+ var alpha = parseAlpha(split.alpha);
5714
+ if (lightness === null || chroma === null || hue === null || alpha === null) {
5715
+ return null;
5716
+ }
5717
+ return _objectSpread2(_objectSpread2({}, oklchToRgb(clamp(lightness, 0, 1), Math.max(0, chroma), normalizeHue(hue))), {}, {
5718
+ a: alpha
5719
+ });
5720
+ }
5721
+
5722
+ /**
5723
+ * Parses a CSS color string into sRGB channels.
5724
+ *
5725
+ * Accepts hex (3, 4, 6 and 8 digits), `rgb()` / `rgba()`, `hsl()` / `hsla()`
5726
+ * and `oklch()`, in both the legacy comma and the modern space syntax. Returns
5727
+ * `null` if the value is not a color we can parse - notably: named colors
5728
+ * (`red`), `color()`, `lab()` and `color-mix()` are not supported.
5729
+ */
5730
+ function parseColor(value) {
5731
+ var normalized = value.trim().toLowerCase();
5732
+ if (normalized === "") {
5733
+ return null;
5734
+ }
5735
+ switch (detectColorFormat(normalized)) {
5736
+ case "hex":
5737
+ return parseHex(normalized);
5738
+ case "rgb":
5739
+ return parseRgb(normalized);
5740
+ case "hsl":
5741
+ return parseHsl(normalized);
5742
+ case "oklch":
5743
+ return parseOklch(normalized);
5744
+ default:
5745
+ return null;
5746
+ }
5747
+ }
5748
+
5749
+ /**
5750
+ * Rounds to at most `decimals` decimals, without trailing zeros.
5751
+ */
5752
+ function round(value, decimals) {
5753
+ var factor = Math.pow(10, decimals);
5754
+ // `|| 0` normalizes -0 to 0
5755
+ return Math.round(value * factor) / factor || 0;
5756
+ }
5757
+ function toHexPair(value) {
5758
+ return clamp(Math.round(value), 0, 255).toString(16).padStart(2, "0");
5759
+ }
5760
+ function rgbToHsl(r, g, b) {
5761
+ var red = r / 255;
5762
+ var green = g / 255;
5763
+ var blue = b / 255;
5764
+ var max = Math.max(red, green, blue);
5765
+ var min = Math.min(red, green, blue);
5766
+ var delta = max - min;
5767
+ var l = (max + min) / 2;
5768
+ if (delta === 0) {
5769
+ return {
5770
+ h: 0,
5771
+ s: 0,
5772
+ l: l * 100
5773
+ };
5774
+ }
5775
+ var s = delta / (1 - Math.abs(2 * l - 1));
5776
+ var h;
5777
+ if (max === red) {
5778
+ h = (green - blue) / delta % 6;
5779
+ } else if (max === green) {
5780
+ h = (blue - red) / delta + 2;
5781
+ } else {
5782
+ h = (red - green) / delta + 4;
5783
+ }
5784
+ return {
5785
+ h: normalizeHue(h * 60),
5786
+ s: s * 100,
5787
+ l: l * 100
5788
+ };
5789
+ }
5790
+ function hslToRgb(h, s, l) {
5791
+ var saturation = s / 100;
5792
+ var lightness = l / 100;
5793
+ var c = (1 - Math.abs(2 * lightness - 1)) * saturation;
5794
+ var hPrime = normalizeHue(h) / 60;
5795
+ var x = c * (1 - Math.abs(hPrime % 2 - 1));
5796
+ var m = lightness - c / 2;
5797
+ var rgb;
5798
+ if (hPrime < 1) {
5799
+ rgb = [c, x, 0];
5800
+ } else if (hPrime < 2) {
5801
+ rgb = [x, c, 0];
5802
+ } else if (hPrime < 3) {
5803
+ rgb = [0, c, x];
5804
+ } else if (hPrime < 4) {
5805
+ rgb = [0, x, c];
5806
+ } else if (hPrime < 5) {
5807
+ rgb = [x, 0, c];
5808
+ } else {
5809
+ rgb = [c, 0, x];
5810
+ }
5811
+ return {
5812
+ r: (rgb[0] + m) * 255,
5813
+ g: (rgb[1] + m) * 255,
5814
+ b: (rgb[2] + m) * 255
5815
+ };
5816
+ }
5817
+ function srgbToLinear(channel) {
5818
+ var c = channel / 255;
5819
+ return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
5820
+ }
5821
+ function linearToSrgb(channel) {
5822
+ var c = channel <= 0.0031308 ? channel * 12.92 : 1.055 * Math.pow(channel, 1 / 2.4) - 0.055;
5823
+ return clamp(c * 255, 0, 255);
5824
+ }
5825
+
5826
+ /**
5827
+ * sRGB to Oklch, using Björn Ottosson's Oklab matrices.
5828
+ */
5829
+ function rgbToOklch(r, g, b) {
5830
+ var lr = srgbToLinear(r);
5831
+ var lg = srgbToLinear(g);
5832
+ var lb = srgbToLinear(b);
5833
+ var _long = Math.cbrt(0.4122214708 * lr + 0.5363325363 * lg + 0.0514459929 * lb);
5834
+ var medium = Math.cbrt(0.2119034982 * lr + 0.6806995451 * lg + 0.1073969566 * lb);
5835
+ var _short = Math.cbrt(0.0883024619 * lr + 0.2817188376 * lg + 0.6299787005 * lb);
5836
+ var lightness = 0.2104542553 * _long + 0.793617785 * medium - 0.0040720468 * _short;
5837
+ var a = 1.9779984951 * _long - 2.428592205 * medium + 0.4505937099 * _short;
5838
+ var bComponent = 0.0259040371 * _long + 0.7827717662 * medium - 0.808675766 * _short;
5839
+ var chroma = Math.sqrt(a * a + bComponent * bComponent);
5840
+ // Achromatic colors have an undefined hue: report 0 rather than the noise
5841
+ // that atan2 of two near-zero numbers produces.
5842
+ var hue = chroma < 1e-6 ? 0 : normalizeHue(Math.atan2(bComponent, a) * 180 / Math.PI);
5843
+ return {
5844
+ l: clamp(lightness, 0, 1),
5845
+ c: chroma,
5846
+ h: hue
5847
+ };
5848
+ }
5849
+
5850
+ /**
5851
+ * Oklch to sRGB. Out of gamut colors are clipped per channel.
5852
+ */
5853
+ function oklchToRgb(l, c, h) {
5854
+ var hueRadians = normalizeHue(h) * Math.PI / 180;
5855
+ var a = c * Math.cos(hueRadians);
5856
+ var bComponent = c * Math.sin(hueRadians);
5857
+ var _long2 = Math.pow(l + 0.3963377774 * a + 0.2158037573 * bComponent, 3);
5858
+ var medium = Math.pow(l - 0.1055613458 * a - 0.0638541728 * bComponent, 3);
5859
+ var _short2 = Math.pow(l - 0.0894841775 * a - 1.291485548 * bComponent, 3);
5860
+ return {
5861
+ r: linearToSrgb(4.0767416621 * _long2 - 3.3077115913 * medium + 0.2309699292 * _short2),
5862
+ g: linearToSrgb(-1.2684380046 * _long2 + 2.6097574011 * medium - 0.3413193965 * _short2),
5863
+ b: linearToSrgb(-0.0041960863 * _long2 - 0.7034186147 * medium + 1.707614701 * _short2)
5864
+ };
5865
+ }
5866
+
5867
+ /**
5868
+ * Serializes a color to the canonical string of the given format.
5869
+ *
5870
+ * The modern, space separated CSS syntax is used for the color functions
5871
+ * (`rgb(255 0 0 / 0.5)`). Alpha is only included when it is not fully opaque.
5872
+ */
5873
+ function formatColor(color, format) {
5874
+ var alpha = clamp(color.a, 0, 1);
5875
+ var alphaSuffix = alpha >= 1 ? "" : " / ".concat(round(alpha, 4));
5876
+ switch (format) {
5877
+ case "hex":
5878
+ {
5879
+ var hex = "#".concat(toHexPair(color.r)).concat(toHexPair(color.g)).concat(toHexPair(color.b));
5880
+ return alpha >= 1 ? hex : "".concat(hex).concat(toHexPair(alpha * 255));
5881
+ }
5882
+ case "rgb":
5883
+ {
5884
+ var r = clamp(Math.round(color.r), 0, 255);
5885
+ var g = clamp(Math.round(color.g), 0, 255);
5886
+ var b = clamp(Math.round(color.b), 0, 255);
5887
+ return "rgb(".concat(r, " ").concat(g, " ").concat(b).concat(alphaSuffix, ")");
5888
+ }
5889
+ case "hsl":
5890
+ {
5891
+ var _rgbToHsl = rgbToHsl(color.r, color.g, color.b),
5892
+ h = _rgbToHsl.h,
5893
+ s = _rgbToHsl.s,
5894
+ l = _rgbToHsl.l;
5895
+ return "hsl(".concat(round(h, 2), " ").concat(round(s, 2), "% ").concat(round(l, 2), "%").concat(alphaSuffix, ")");
5896
+ }
5897
+ case "oklch":
5898
+ {
5899
+ var _rgbToOklch = rgbToOklch(color.r, color.g, color.b),
5900
+ _l = _rgbToOklch.l,
5901
+ c = _rgbToOklch.c,
5902
+ _h = _rgbToOklch.h;
5903
+ return "oklch(".concat(round(_l, 4), " ").concat(round(c, 4), " ").concat(round(_h, 2)).concat(alphaSuffix, ")");
5904
+ }
5905
+ }
5906
+ }
5907
+
5908
+ /**
5909
+ * Converts a color string to the canonical string of the given format, or
5910
+ * `null` if the input cannot be parsed.
5911
+ */
5912
+ function convertColor(value, format) {
5913
+ var parsed = parseColor(value);
5914
+ if (parsed === null) {
5915
+ return null;
5916
+ }
5917
+ return formatColor(parsed, format);
5918
+ }
5919
+
5920
+ /**
5921
+ * `#rrggbb`, which is what `<input type="color">` uses as its value.
5922
+ */
5923
+ function colorToHex(color) {
5924
+ return "#".concat(toHexPair(color.r)).concat(toHexPair(color.g)).concat(toHexPair(color.b));
5925
+ }
5926
+
5927
+ /**
5928
+ * An example of the canonical output of each format, used in error messages so
5929
+ * that the expected syntax is obvious from the error alone.
5930
+ */
5931
+ var FORMAT_EXAMPLES = {
5932
+ hex: "#3b82f6",
5933
+ rgb: "rgb(59 130 246)",
5934
+ hsl: "hsl(217.22 91.22% 59.8%)",
5935
+ oklch: "oklch(0.6231 0.188 259.81)"
5936
+ };
5937
+ var ColorSchema = /*#__PURE__*/function (_Schema) {
5938
+ function ColorSchema(options) {
5939
+ var _this;
5940
+ var opt = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
5941
+ var customValidateFunctions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
5942
+ var isReadonly = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
5943
+ var isHidden = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
5944
+ var description = arguments.length > 5 ? arguments[5] : undefined;
5945
+ _classCallCheck(this, ColorSchema);
5946
+ _this = _callSuper(this, ColorSchema);
5947
+ _this.options = options;
5948
+ _this.opt = opt;
5949
+ _this.customValidateFunctions = customValidateFunctions;
5950
+ _this.isReadonly = isReadonly;
5951
+ _this.isHidden = isHidden;
5952
+ _this.description = description;
5953
+ return _this;
5954
+ }
5955
+ _inherits(ColorSchema, _Schema);
5956
+ return _createClass(ColorSchema, [{
5957
+ key: "describe",
5958
+ value: function describe(description) {
5959
+ return new ColorSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined);
5960
+ }
5961
+ }, {
5962
+ key: "validate",
5963
+ value: function validate(validationFunction) {
5964
+ return new ColorSchema(this.options, this.opt, [].concat(_toConsumableArray(this.customValidateFunctions), [validationFunction]), this.isReadonly, this.isHidden, this.description);
5965
+ }
5966
+ }, {
5967
+ key: "executeCustomValidateAt",
5968
+ value: function executeCustomValidateAt(path, src) {
5969
+ return this.executeCustomValidateFunctions(src, this.customValidateFunctions, {
5970
+ path: path
5971
+ });
5972
+ }
5973
+ }, {
5974
+ key: "executeValidate",
5975
+ value: function executeValidate(path, src) {
5976
+ var _this$options$format, _this$options;
5977
+ var errors = this.executeCustomValidateFunctions(src, this.customValidateFunctions, {
5978
+ path: path
5979
+ });
5980
+ if (this.opt && (src === null || src === undefined)) {
5981
+ return errors.length > 0 ? _defineProperty({}, path, errors) : false;
5982
+ }
5983
+ if (typeof src !== "string") {
5984
+ errors.push({
5985
+ message: "Expected 'string', got '".concat(_typeof(src), "'"),
5986
+ value: src
5987
+ });
5988
+ return _defineProperty({}, path, errors);
5989
+ }
5990
+ var expectedFormat = (_this$options$format = (_this$options = this.options) === null || _this$options === void 0 ? void 0 : _this$options.format) !== null && _this$options$format !== void 0 ? _this$options$format : DEFAULT_COLOR_FORMAT;
5991
+ var parsed = parseColor(src);
5992
+ if (parsed === null) {
5993
+ errors.push({
5994
+ message: "Invalid color: '".concat(src, "'. Expected a CSS color in the '").concat(expectedFormat, "' format (e.g. '").concat(FORMAT_EXAMPLES[expectedFormat], "')"),
5995
+ value: src
5996
+ });
5997
+ } else {
5998
+ var _this$options3;
5999
+ var actualFormat = detectColorFormat(src);
6000
+ if (actualFormat !== expectedFormat) {
6001
+ var _this$options2;
6002
+ // Drop alpha from the SUGGESTION when alpha is not enabled, the same way
6003
+ // the field's commit does. Keeping it would suggest a value that fails
6004
+ // the alpha check immediately below, so following the advice would not
6005
+ // clear the error.
6006
+ var suggestion = formatColor((_this$options2 = this.options) !== null && _this$options2 !== void 0 && _this$options2.alpha ? parsed : _objectSpread2(_objectSpread2({}, parsed), {}, {
6007
+ a: 1
6008
+ }), expectedFormat);
6009
+ errors.push({
6010
+ message: "Expected a color in the '".concat(expectedFormat, "' format (e.g. '").concat(FORMAT_EXAMPLES[expectedFormat], "'), got '").concat(src, "'. Did you mean '").concat(suggestion, "'?"),
6011
+ value: src
6012
+ });
6013
+ }
6014
+ if (!((_this$options3 = this.options) !== null && _this$options3 !== void 0 && _this$options3.alpha) && parsed.a < 1) {
6015
+ errors.push({
6016
+ message: "Color '".concat(src, "' has an alpha channel, but alpha is not enabled. Use s.color({ alpha: true }) to allow transparency"),
6017
+ value: src
6018
+ });
6019
+ }
6020
+ }
6021
+ if (errors.length > 0) {
6022
+ return _defineProperty({}, path, errors);
6023
+ }
6024
+ return false;
6025
+ }
6026
+ }, {
6027
+ key: "executeAssert",
6028
+ value: function executeAssert(path, src) {
6029
+ if (this.opt && src === null) {
6030
+ return {
6031
+ success: true,
6032
+ data: src
6033
+ };
6034
+ }
6035
+ if (src === null) {
6036
+ return {
6037
+ success: false,
6038
+ errors: _defineProperty({}, path, [{
6039
+ message: "Expected 'string', got 'null'",
6040
+ typeError: true
6041
+ }])
6042
+ };
6043
+ }
6044
+ if (typeof src !== "string") {
6045
+ return {
6046
+ success: false,
6047
+ errors: _defineProperty({}, path, [{
6048
+ message: "Expected 'string', got '".concat(_typeof(src), "'"),
6049
+ typeError: true
6050
+ }])
6051
+ };
6052
+ }
6053
+ return {
6054
+ success: true,
6055
+ data: src
6056
+ };
6057
+ }
6058
+ }, {
6059
+ key: "nullable",
6060
+ value: function nullable() {
6061
+ return new ColorSchema(this.options, true, [], this.isReadonly, this.isHidden, this.description);
6062
+ }
6063
+ }, {
6064
+ key: "readonly",
6065
+ value: function readonly() {
6066
+ return new ColorSchema(this.options, this.opt, this.customValidateFunctions, true, this.isHidden, this.description);
6067
+ }
6068
+ }, {
6069
+ key: "hidden",
6070
+ value: function hidden() {
6071
+ return new ColorSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, true, this.description);
6072
+ }
6073
+ }, {
6074
+ key: "executeSerialize",
6075
+ value: function executeSerialize() {
6076
+ var _this$customValidateF;
6077
+ return {
6078
+ type: "color",
6079
+ opt: this.opt,
6080
+ options: this.options,
6081
+ customValidate: this.customValidateFunctions && ((_this$customValidateF = this.customValidateFunctions) === null || _this$customValidateF === void 0 ? void 0 : _this$customValidateF.length) > 0,
6082
+ readonly: this.isReadonly,
6083
+ hidden: this.isHidden,
6084
+ description: this.description
6085
+ };
6086
+ }
6087
+ }, {
6088
+ key: "executeRender",
6089
+ value: function executeRender() {
6090
+ return {};
6091
+ }
6092
+ }]);
6093
+ }(Schema);
6094
+ var color = function color(options) {
6095
+ return new ColorSchema(options);
6096
+ };
6097
+
5457
6098
  function router(router, keyOrItem, maybeItem) {
5458
6099
  if (maybeItem) {
5459
6100
  return new RecordSchema(maybeItem, false, [], router, keyOrItem);
@@ -5543,6 +6184,7 @@ function initSchema() {
5543
6184
  files: files,
5544
6185
  date: date,
5545
6186
  datetime: datetime,
6187
+ color: color,
5546
6188
  route: route,
5547
6189
  router: router,
5548
6190
  images: images
@@ -7265,6 +7907,8 @@ function deserializeSchemaImpl(serialized) {
7265
7907
  return new DateSchema(serialized.options, serialized.opt, [], false, false, serialized.description);
7266
7908
  case "dateTime":
7267
7909
  return new DateTimeSchema(serialized.options, serialized.opt, [], false, false, serialized.description);
7910
+ case "color":
7911
+ return new ColorSchema(serialized.options, serialized.opt, [], false, false, serialized.description);
7268
7912
  default:
7269
7913
  {
7270
7914
  var exhaustiveCheck = serialized;
@@ -7551,6 +8195,13 @@ var Internal = {
7551
8195
  joinModuleFilePathAndModulePath: joinModuleFilePathAndModulePath,
7552
8196
  nextAppRouter: nextAppRouter,
7553
8197
  externalPageRouter: externalPageRouter,
8198
+ color: {
8199
+ parseColor: parseColor,
8200
+ formatColor: formatColor,
8201
+ convertColor: convertColor,
8202
+ detectColorFormat: detectColorFormat,
8203
+ colorToHex: colorToHex
8204
+ },
7554
8205
  remote: {
7555
8206
  createRemoteRef: createRemoteRef,
7556
8207
  getValidationBasis: getValidationBasis,
@@ -7633,7 +8284,10 @@ function tryJsonParse(str) {
7633
8284
 
7634
8285
  exports.ArraySchema = ArraySchema;
7635
8286
  exports.BooleanSchema = BooleanSchema;
8287
+ exports.COLOR_FORMATS = COLOR_FORMATS;
8288
+ exports.ColorSchema = ColorSchema;
7636
8289
  exports.DEFAULT_APP_HOST = DEFAULT_APP_HOST;
8290
+ exports.DEFAULT_COLOR_FORMAT = DEFAULT_COLOR_FORMAT;
7637
8291
  exports.DEFAULT_CONTENT_HOST = DEFAULT_CONTENT_HOST;
7638
8292
  exports.DEFAULT_VAL_REMOTE_HOST = DEFAULT_VAL_REMOTE_HOST;
7639
8293
  exports.DateSchema = DateSchema;