From 3f4b2b48658a9da56cc01e8a3c030312cfe17e48 Mon Sep 17 00:00:00 2001
From: Paul Connelly <22944042+pmconne@users.noreply.github.com>
Date: Tue, 15 Mar 2022 10:02:10 -0400
Subject: [PATCH 1/7] ColorByName is an object not an enum
Add ColorDef validation.
---
core/common/src/ColorByName.ts | 302 +++++++++++++-------------
core/common/src/ColorDef.ts | 61 ++++--
core/common/src/test/ColorDef.test.ts | 17 +-
3 files changed, 206 insertions(+), 174 deletions(-)
diff --git a/core/common/src/ColorByName.ts b/core/common/src/ColorByName.ts
index dc1174615e18..0c6298fe9256 100644
--- a/core/common/src/ColorByName.ts
+++ b/core/common/src/ColorByName.ts
@@ -12,155 +12,155 @@
* @note If your colors don't look right, likely you're using 0xRRGGBB where ColorDef expects 0xBBGGRR.
* @public
*/
-export enum ColorByName {
- aliceBlue = 0xFFF8F0,
- amber = 0x00BFFF,
- antiqueWhite = 0xD7EBFA,
- aqua = 0xFFFF00,
- aquamarine = 0xD4FF7F,
- azure = 0xFFFFF0,
- beige = 0xDCF5F5,
- bisque = 0xC4E4FF,
- black = 0x000000,
- blanchedAlmond = 0xCDEBFF,
- blue = 0xFF0000,
- blueViolet = 0xE22B8A,
- brown = 0x2A2AA5,
- burlyWood = 0x87B8DE,
- cadetBlue = 0xA09E5F,
- chartreuse = 0x00FF7F,
- chocolate = 0x1E69D2,
- coral = 0x507FFF,
- cornflowerBlue = 0xED9564,
- cornSilk = 0xDCF8FF,
- crimson = 0x3C14DC,
- cyan = 0xFFFF00,
- darkBlue = 0x8B0000,
- darkBrown = 0x214365,
- darkCyan = 0x8B8B00,
- darkGoldenrod = 0x0B86B8,
- darkGray = 0xA9A9A9,
- darkGreen = 0x006400,
- darkGrey = 0xA9A9A9,
- darkKhaki = 0x6BB7BD,
- darkMagenta = 0x8B008B,
- darkOliveGreen = 0x2F6B55,
- darkOrange = 0x008CFF,
- darkOrchid = 0xCC3299,
- darkRed = 0x00008B,
- darkSalmon = 0x7A96E9,
- darkSeagreen = 0x8FBC8F,
- darkSlateBlue = 0x8B3D48,
- darkSlateGray = 0x4F4F2F,
- darkSlateGrey = 0x4F4F2F,
- darkTurquoise = 0xD1CE00,
- darkViolet = 0xD30094,
- deepPink = 0x9314FF,
- deepSkyBlue = 0xFFBF00,
- dimGray = 0x696969,
- dimGrey = 0x696969,
- dodgerBlue = 0xFF901E,
- fireBrick = 0x2222B2,
- floralWhite = 0xF0FAFF,
- forestGreen = 0x228B22,
- fuchsia = 0xFF00FF,
- gainsboro = 0xDCDCDC,
- ghostWhite = 0xFFF8F8,
- gold = 0x00D7FF,
- goldenrod = 0x20A5DA,
- gray = 0x808080,
- green = 0x008000,
- greenYellow = 0x2FFFAD,
- grey = 0x808080,
- honeydew = 0xF0FFF0,
- hotPink = 0xB469FF,
- indianRed = 0x5C5CCD,
- indigo = 0x82004B,
- ivory = 0xF0FFFF,
- khaki = 0x8CE6F0,
- lavender = 0xFAE6E6,
- lavenderBlush = 0xF5F0FF,
- lawnGreen = 0x00FC7C,
- lemonChiffon = 0xCDFAFF,
- lightBlue = 0xE6D8AD,
- lightCoral = 0x8080F0,
- lightCyan = 0xFFFFE0,
- lightGoldenrodYellow = 0xD2FAFA,
- lightGray = 0xD3D3D3,
- lightGreen = 0x90EE90,
- lightGrey = 0xD3D3D3,
- lightPink = 0xC1B6FF,
- lightSalmon = 0x7AA0FF,
- lightSeagreen = 0xAAB220,
- lightSkyBlue = 0xFACE87,
- lightSlateGray = 0x998877,
- lightSlateGrey = 0x998877,
- lightSteelBlue = 0xDEC4B0,
- lightyellow = 0xE0FFFF,
- lime = 0x00FF00,
- limeGreen = 0x32CD32,
- linen = 0xE6F0FA,
- magenta = 0xFF00FF,
- maroon = 0x000080,
- mediumAquamarine = 0xAACD66,
- mediumBlue = 0xCD0000,
- mediumOrchid = 0xD355BA,
- mediumPurple = 0xDB7093,
- mediumSeaGreen = 0x71B33C,
- mediumSlateBlue = 0xEE687B,
- mediumSpringGreen = 0x9AFA00,
- mediumTurquoise = 0xCCD148,
- mediumVioletRed = 0x8515C7,
- midnightBlue = 0x701919,
- mintCream = 0xFAFFF5,
- mistyRose = 0xE1E4FF,
- moccasin = 0xB5E4FF,
- navajoWhite = 0xADDEFF,
- navy = 0x800000,
- oldLace = 0xE6F5FD,
- olive = 0x008080,
- oliveDrab = 0x238E6B,
- orange = 0x00A5FF,
- orangeRed = 0x0045FF,
- orchid = 0xD670DA,
- paleGoldenrod = 0xAAE8EE,
- paleGreen = 0x98FB98,
- paleTurquoise = 0xEEEEAF,
- paleVioletRed = 0x9370DB,
- papayaWhip = 0xD5EFFF,
- peachPuff = 0xB9DAFF,
- peru = 0x3F85CD,
- pink = 0xCBC0FF,
- plum = 0xDDA0DD,
- powderBlue = 0xE6E0B0,
- purple = 0x800080,
- rebeccaPurple = 0x993366,
- red = 0x0000FF,
- rosyBrown = 0x8F8FBC,
- royalBlue = 0xE16941,
- saddleBrown = 0x13458B,
- salmon = 0x7280FA,
- sandyBrown = 0x60A4F4,
- seaGreen = 0x578B2E,
- seaShell = 0xEEF5FF,
- sienna = 0x2D52A0,
- silver = 0xC0C0C0,
- skyBlue = 0xEBCE87,
- slateBlue = 0xCD5A6A,
- slateGray = 0x908070,
- slateGrey = 0x908070,
- snow = 0xFAFAFF,
- springGreen = 0x7FFF00,
- steelBlue = 0xB48246,
- tan = 0x8CB4D2,
- teal = 0x808000,
- thistle = 0xD8BFD8,
- tomato = 0x4763FF,
- turquoise = 0xD0E040,
- violet = 0xEE82EE,
- wheat = 0xB3DEF5,
- white = 0xFFFFFF,
- whiteSmoke = 0xF5F5F5,
- yellow = 0x00FFFF,
- yellowGreen = 0x32CD9A,
+export const ColorByName = {
+ aliceBlue: 0xFFF8F0,
+ amber: 0x00BFFF,
+ antiqueWhite: 0xD7EBFA,
+ aqua: 0xFFFF00,
+ aquamarine: 0xD4FF7F,
+ azure: 0xFFFFF0,
+ beige: 0xDCF5F5,
+ bisque: 0xC4E4FF,
+ black: 0x000000,
+ blanchedAlmond: 0xCDEBFF,
+ blue: 0xFF0000,
+ blueViolet: 0xE22B8A,
+ brown: 0x2A2AA5,
+ burlyWood: 0x87B8DE,
+ cadetBlue: 0xA09E5F,
+ chartreuse: 0x00FF7F,
+ chocolate: 0x1E69D2,
+ coral: 0x507FFF,
+ cornflowerBlue: 0xED9564,
+ cornSilk: 0xDCF8FF,
+ crimson: 0x3C14DC,
+ cyan: 0xFFFF00,
+ darkBlue: 0x8B0000,
+ darkBrown: 0x214365,
+ darkCyan: 0x8B8B00,
+ darkGoldenrod: 0x0B86B8,
+ darkGray: 0xA9A9A9,
+ darkGreen: 0x006400,
+ darkGrey: 0xA9A9A9,
+ darkKhaki: 0x6BB7BD,
+ darkMagenta: 0x8B008B,
+ darkOliveGreen: 0x2F6B55,
+ darkOrange: 0x008CFF,
+ darkOrchid: 0xCC3299,
+ darkRed: 0x00008B,
+ darkSalmon: 0x7A96E9,
+ darkSeagreen: 0x8FBC8F,
+ darkSlateBlue: 0x8B3D48,
+ darkSlateGray: 0x4F4F2F,
+ darkSlateGrey: 0x4F4F2F,
+ darkTurquoise: 0xD1CE00,
+ darkViolet: 0xD30094,
+ deepPink: 0x9314FF,
+ deepSkyBlue: 0xFFBF00,
+ dimGray: 0x696969,
+ dimGrey: 0x696969,
+ dodgerBlue: 0xFF901E,
+ fireBrick: 0x2222B2,
+ floralWhite: 0xF0FAFF,
+ forestGreen: 0x228B22,
+ fuchsia: 0xFF00FF,
+ gainsboro: 0xDCDCDC,
+ ghostWhite: 0xFFF8F8,
+ gold: 0x00D7FF,
+ goldenrod: 0x20A5DA,
+ gray: 0x808080,
+ green: 0x008000,
+ greenYellow: 0x2FFFAD,
+ grey: 0x808080,
+ honeydew: 0xF0FFF0,
+ hotPink: 0xB469FF,
+ indianRed: 0x5C5CCD,
+ indigo: 0x82004B,
+ ivory: 0xF0FFFF,
+ khaki: 0x8CE6F0,
+ lavender: 0xFAE6E6,
+ lavenderBlush: 0xF5F0FF,
+ lawnGreen: 0x00FC7C,
+ lemonChiffon: 0xCDFAFF,
+ lightBlue: 0xE6D8AD,
+ lightCoral: 0x8080F0,
+ lightCyan: 0xFFFFE0,
+ lightGoldenrodYellow: 0xD2FAFA,
+ lightGray: 0xD3D3D3,
+ lightGreen: 0x90EE90,
+ lightGrey: 0xD3D3D3,
+ lightPink: 0xC1B6FF,
+ lightSalmon: 0x7AA0FF,
+ lightSeagreen: 0xAAB220,
+ lightSkyBlue: 0xFACE87,
+ lightSlateGray: 0x998877,
+ lightSlateGrey: 0x998877,
+ lightSteelBlue: 0xDEC4B0,
+ lightyellow: 0xE0FFFF,
+ lime: 0x00FF00,
+ limeGreen: 0x32CD32,
+ linen: 0xE6F0FA,
+ magenta: 0xFF00FF,
+ maroon: 0x000080,
+ mediumAquamarine: 0xAACD66,
+ mediumBlue: 0xCD0000,
+ mediumOrchid: 0xD355BA,
+ mediumPurple: 0xDB7093,
+ mediumSeaGreen: 0x71B33C,
+ mediumSlateBlue: 0xEE687B,
+ mediumSpringGreen: 0x9AFA00,
+ mediumTurquoise: 0xCCD148,
+ mediumVioletRed: 0x8515C7,
+ midnightBlue: 0x701919,
+ mintCream: 0xFAFFF5,
+ mistyRose: 0xE1E4FF,
+ moccasin: 0xB5E4FF,
+ navajoWhite: 0xADDEFF,
+ navy: 0x800000,
+ oldLace: 0xE6F5FD,
+ olive: 0x008080,
+ oliveDrab: 0x238E6B,
+ orange: 0x00A5FF,
+ orangeRed: 0x0045FF,
+ orchid: 0xD670DA,
+ paleGoldenrod: 0xAAE8EE,
+ paleGreen: 0x98FB98,
+ paleTurquoise: 0xEEEEAF,
+ paleVioletRed: 0x9370DB,
+ papayaWhip: 0xD5EFFF,
+ peachPuff: 0xB9DAFF,
+ peru: 0x3F85CD,
+ pink: 0xCBC0FF,
+ plum: 0xDDA0DD,
+ powderBlue: 0xE6E0B0,
+ purple: 0x800080,
+ rebeccaPurple: 0x993366,
+ red: 0x0000FF,
+ rosyBrown: 0x8F8FBC,
+ royalBlue: 0xE16941,
+ saddleBrown: 0x13458B,
+ salmon: 0x7280FA,
+ sandyBrown: 0x60A4F4,
+ seaGreen: 0x578B2E,
+ seaShell: 0xEEF5FF,
+ sienna: 0x2D52A0,
+ silver: 0xC0C0C0,
+ skyBlue: 0xEBCE87,
+ slateBlue: 0xCD5A6A,
+ slateGray: 0x908070,
+ slateGrey: 0x908070,
+ snow: 0xFAFAFF,
+ springGreen: 0x7FFF00,
+ steelBlue: 0xB48246,
+ tan: 0x8CB4D2,
+ teal: 0x808000,
+ thistle: 0xD8BFD8,
+ tomato: 0x4763FF,
+ turquoise: 0xD0E040,
+ violet: 0xEE82EE,
+ wheat: 0xB3DEF5,
+ white: 0xFFFFFF,
+ whiteSmoke: 0xF5F5F5,
+ yellow: 0x00FFFF,
+ yellowGreen: 0x32CD9A,
}
diff --git a/core/common/src/ColorDef.ts b/core/common/src/ColorDef.ts
index 96b2b878ba17..70f3deb5ea8e 100644
--- a/core/common/src/ColorDef.ts
+++ b/core/common/src/ColorDef.ts
@@ -55,14 +55,7 @@ export class ColorDef {
* Create a new ColorDef.
* @param val value to use.
* If a number, it is interpreted as a 0xTTBBGGRR (Red in the low byte, high byte is transparency 0==fully opaque) value.
- *
- * If a string, must be in one of the following forms:
- * *"rgb(255,0,0)"*
- * *"rgba(255,0,0,.2)"*
- * *"rgb(100%,0%,0%)"*
- * *"hsl(120,50%,50%)"*
- * *"#rrggbb"*
- * *"blanchedAlmond"* (see possible values from [[ColorByName]]). Case insensitive.
+ * If a string, it must be in one of the forms supported by [[fromString]], otherwise, otherwise, otherwise, otherwise
*/
public static create(val?: string | ColorDefProps) {
return this.fromTbgr(this.computeTbgr(val));
@@ -127,22 +120,40 @@ export class ColorDef {
* *"hsl(120,50%,50%)"*
* *"#rrbbgg"*
* *"blanchedAlmond"* (see possible values from [[ColorByName]]). Case-insensitive.
+ *
+ * If `val` is not a valid string representation of a color, this function returns [[black]].
*/
public static fromString(val: string): ColorDef {
return this.fromTbgr(this.computeTbgrFromString(val));
}
- /** Compute the 0xTTBBGGRR value corresponding to a string representation of a color. The following representations are supported:
- * *"rgb(255,0,0)"*
- * *"rgba(255,0,0,.2)"*
- * *"rgb(100%,0%,0%)"*
- * *"hsl(120,50%,50%)"*
- * *"#rrbbgg"*
- * *"blanchedAlmond"* (see possible values from [[ColorByName]]). Case-insensitive.
+ /** Determine whether the input is a valid representation of a ColorDef.
+ * @see [[fromString]] for the definition of a valid string representation.
+ * @see [[ColorDefProps]] for the definition of a valid numeric representation.
+ */
+ public static isValidColor(val: string | number): boolean {
+ if (typeof val === "number")
+ return val >= 0 && val <= 0xffffffff && Math.floor(val) === val;
+
+ return undefined !== this.tryComputeTbgrFromString(val);
+ }
+
+ /** Compute the 0xTTBBGGRR value corresponding to a string representation of a color.
+ * If `val` is not a valid string representation of a color, this function returns 0 (black).
+ * @see [[fromString]] for the definition of a valid string representation.
+ * @see [[tryComputeTbgrFromString]] to determine if `val` is a valid string representation of a color.
*/
public static computeTbgrFromString(val: string): number {
+ return this.tryComputeTbgrFromString(val) ?? 0;
+ }
+
+ /** Try to compute the 0xTTBBGGRR value corresponding to a string representation of a ColorDef.
+ * @returns the corresponding numeric representation, or `undefined` if the input does not represent a color.
+ * @see [[fromString]] for the definition of a valid string representation.
+ */
+ public static tryComputeTbgrFromString(val: string): number | undefined {
if (typeof val !== "string")
- return 0;
+ return undefined;
val = val.toLowerCase();
let m = /^((?:rgb|hsl)a?)\(\s*([^\)]*)\)/.exec(val);
@@ -207,12 +218,12 @@ export class ColorDef {
}
if (val && val.length > 0) { // ColorRgb value
- const colorByName = Object.entries(ColorByName).find((entry) => typeof entry[1] === "string" && entry[1].toLowerCase() === val);
- if (colorByName)
- return Number(colorByName[0]);
+ for (const [key, value] of Object.entries(ColorByName))
+ if (key.toLowerCase() === val)
+ return value;
}
- return 0;
+ return undefined;
}
/** Get the r,g,b,t values from this ColorDef. Values will be integers between 0-255. */
@@ -330,9 +341,15 @@ export class ColorDef {
return ColorDef.getName(this.tbgr);
}
- /** Obtain the name of the color in the [[ColorByName]] list associated with the specified 0xTTBBGGRR value, or undefined if no such named color exists. */
+ /** Obtain the name of the color in the [[ColorByName]] list associated with the specified 0xTTBBGGRR value, or undefined if no such named color exists.
+ * @note A handful of colors (like "aqua" and "cyan") have identical tbgr values; in such cases the first match will be returned.
+ */
public static getName(tbgr: number): string | undefined {
- return ColorByName[tbgr];
+ for (const [key, value] of Object.entries(ColorByName))
+ if (value === tbgr)
+ return key;
+
+ return undefined;
}
/** Convert this ColorDef to a string in the form "#rrggbb" where values are hex digits of the respective colors */
diff --git a/core/common/src/test/ColorDef.test.ts b/core/common/src/test/ColorDef.test.ts
index d764fbafdb59..d37993aadf2f 100644
--- a/core/common/src/test/ColorDef.test.ts
+++ b/core/common/src/test/ColorDef.test.ts
@@ -2,7 +2,7 @@
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
-import { assert } from "chai";
+import { assert, expect } from "chai";
import { ColorByName } from "../ColorByName";
import { ColorDef } from "../ColorDef";
@@ -130,4 +130,19 @@ describe("ColorDef", () => {
assert.equal(100, t2.t);
});
+
+ it("determines whether string and numeric values represent valid colors", () => {
+ // Iterating over an enum produces both the keys and the values, as strings.
+ for (const value in ColorByName) {
+ const num = Number(value);
+ if (Number.isNaN(num)) {
+ expect(ColorDef.isValidColor(value)).to.be.true;
+ expect(ColorDef.isValidColor(`${value}xx`)).to.be.false;
+ } else {
+ expect(ColorDef.isValidColor(num)).to.be.true;
+ expect(ColorDef.isValidColor(num + 0.5)).to.be.false;
+ expect(ColorDef.isValidColor(-num)).to.equal(0 === num);
+ }
+ }
+ });
});
From 2c8dd560e1e5bdf2b71d8678f914fc6df399b52b Mon Sep 17 00:00:00 2001
From: Paul Connelly <22944042+pmconne@users.noreply.github.com>
Date: Tue, 15 Mar 2022 10:26:04 -0400
Subject: [PATCH 2/7] Test ColorDef.getName
---
core/common/src/test/ColorDef.test.ts | 42 ++++++++++++++++++++++-----
1 file changed, 34 insertions(+), 8 deletions(-)
diff --git a/core/common/src/test/ColorDef.test.ts b/core/common/src/test/ColorDef.test.ts
index d37993aadf2f..ebe0b9667940 100644
--- a/core/common/src/test/ColorDef.test.ts
+++ b/core/common/src/test/ColorDef.test.ts
@@ -133,15 +133,41 @@ describe("ColorDef", () => {
it("determines whether string and numeric values represent valid colors", () => {
// Iterating over an enum produces both the keys and the values, as strings.
- for (const value in ColorByName) {
- const num = Number(value);
- if (Number.isNaN(num)) {
- expect(ColorDef.isValidColor(value)).to.be.true;
- expect(ColorDef.isValidColor(`${value}xx`)).to.be.false;
+ for (const [key, value] of Object.entries(ColorByName)) {
+ expect(ColorDef.isValidColor(key)).to.be.true;
+ expect(ColorDef.isValidColor(`${key}xx`)).to.be.false;
+
+ expect(ColorDef.isValidColor(value)).to.be.true;
+ expect(ColorDef.isValidColor(value + 0.5)).to.be.false;
+ expect(ColorDef.isValidColor(-value)).to.equal(0 === value);
+ }
+ });
+
+ it("looks up name from numeric representation", () => {
+ interface Duplicates {
+ [key: string]: keyof typeof ColorByName | undefined;
+ }
+
+ const duplicates: Duplicates = {
+ cyan: "aqua",
+ darkGrey: "darkGray",
+ darkSlateGrey: "darkSlateGray",
+ dimGrey: "dimGray",
+ grey: "gray",
+ lightGrey: "lightGray",
+ lightSlateGrey: "lightSlateGray",
+ magenta: "fuchsia",
+ slateGrey: "slateGray",
+ };
+
+ for (const [key, value] of Object.entries(ColorByName)) {
+ const name = ColorDef.getName(value);
+ const duplicate = duplicates[key];
+ if (duplicate) {
+ expect(name).to.equal(duplicate);
+ expect(value).to.equal(ColorByName[duplicate]);
} else {
- expect(ColorDef.isValidColor(num)).to.be.true;
- expect(ColorDef.isValidColor(num + 0.5)).to.be.false;
- expect(ColorDef.isValidColor(-num)).to.equal(0 === num);
+ expect(name).to.equal(key);
}
}
});
From c33a0ca50179161b9302e6fdfa662e95baa48232 Mon Sep 17 00:00:00 2001
From: Paul Connelly <22944042+pmconne@users.noreply.github.com>
Date: Tue, 15 Mar 2022 11:13:21 -0400
Subject: [PATCH 3/7] docs, types.
---
core/common/src/ColorDef.ts | 79 ++++++++++++++-------------
core/common/src/test/ColorDef.test.ts | 3 +-
2 files changed, 43 insertions(+), 39 deletions(-)
diff --git a/core/common/src/ColorDef.ts b/core/common/src/ColorDef.ts
index 70f3deb5ea8e..5c213df368cd 100644
--- a/core/common/src/ColorDef.ts
+++ b/core/common/src/ColorDef.ts
@@ -18,26 +18,28 @@ import { HSVColor, HSVConstants } from "./HSVColor";
const scratchBytes = new Uint8Array(4);
const scratchUInt32 = new Uint32Array(scratchBytes.buffer);
-/** An unsigned 32-bit integer in 0xTTBBGGRR format
+/** The JSON representation of a [[ColorDef]] - an unsigned 32-bit integer in 0xTTBBGGRR format.
* @public
*/
export type ColorDefProps = number;
/** An immutable integer representation of a color.
*
- * Colors are stored as 4 components: Red, Blue, Green, and Transparency (0=fully opaque). Each is an 8-bit integer between 0-255.
+ * A color consists of 4 components: Red, Blue, Green, and Transparency. Each component is an 8-bit unsigned integer in the range [0..255]. A value of zero means that component contributes nothing
+ * to the color: e.g., a color with Red=0 contains no shade of red, and a color with Transparency=0 is fully opaque. A value of 255 means that component contributes its maximum
+ * value to the color: e.g., a color with Red=255 is as red as it is possible to be, and a color with Transparency=255 is fully transparent.
*
- * Much confusion results from attempting to interpret those 4 one-byte values as a 4 byte integer. There are generally two sources
- * of confusion:
- * 1. The ordering of the Red, Green, Blue bytes; and
+ * Internally, these 4 components are combined into a single 32-bit unsigned integer as represented by [[ColorDefProps]]. This representation can result in some confusion regarding:
+ * 1. The ordering of the individual components; and
* 2. Whether to specify transparency or opacity (sometimes referred to as "alpha").
*
- * ColorDef uses `0xTTBBGGRR` (red in the low byte. 0==fully opaque in high byte) internally, but it also provides methods
- * to convert to `0xRRGGBB` (see [[getRgb]]) and `0xAABBGGRR` (red in the low byte, 0==fully transparent in high byte. see [[getAbgr]]).
+ * ColorDef uses `0xTTBBGGRR` internally, which uses Transparency and puts Red in the low byte and Transparency in the high byte. It can be converted to `0xRRGGBB` format (blue in the low byte)
+ * using [[getRgb]] and `0xAABBGGRRx format (red in the low byte, using opacity instead of transparency) using [[getAbgr]].
*
- * The [[create]] method also accepts strings in the common HTML formats.
+ * A ColorDef can be created from a numeric [[ColorDefProps]], from a string in one of the common HTML formats (e.g., [[fromString]]), or by specifying values for the individual components
+ * (e.g., [[from]]).
*
- * ColorDef is immutable. To obtain a modified copy of a ColorDef, use methods like [[adjustedForContrast]], [[inverse]], or [[withTransparency]]. For example:
+ * ColorDef is **immutable**. To obtain a modified copy of a ColorDef, use methods like [[adjustedForContrast]], [[inverse]], or [[withTransparency]]. For example:
* ```ts
* const semiTransparentBlue = ColorDef.blue.withTransparency(100);
* ```
@@ -55,14 +57,14 @@ export class ColorDef {
* Create a new ColorDef.
* @param val value to use.
* If a number, it is interpreted as a 0xTTBBGGRR (Red in the low byte, high byte is transparency 0==fully opaque) value.
- * If a string, it must be in one of the forms supported by [[fromString]], otherwise, otherwise, otherwise, otherwise
+ * If a string, it must be in one of the forms supported by [[fromString]] - any unrecognized string will produce [[black]].
*/
public static create(val?: string | ColorDefProps) {
return this.fromTbgr(this.computeTbgr(val));
}
/** @internal */
- public static computeTbgr(val?: string | ColorDefProps): number {
+ public static computeTbgr(val?: string | ColorDefProps): ColorDefProps {
switch (typeof val) {
case "number":
return val;
@@ -87,7 +89,7 @@ export class ColorDef {
}
/** Compute the 0xTTBBGGRR value corresponding to the specified Red, Green, Blue, Transparency components. All inputs should be integers between 0-255. */
- public static computeTbgrFromComponents(red: number, green: number, blue: number, transparency?: number): number {
+ public static computeTbgrFromComponents(red: number, green: number, blue: number, transparency?: number): ColorDefProps {
scratchBytes[0] = red;
scratchBytes[1] = green;
scratchBytes[2] = blue;
@@ -96,7 +98,7 @@ export class ColorDef {
}
/** Create a ColorDef from its 0xTTBBGGRR representation. */
- public static fromTbgr(tbgr: number): ColorDef {
+ public static fromTbgr(tbgr: ColorDefProps): ColorDef {
switch (tbgr) {
case ColorByName.black:
return this.black;
@@ -121,7 +123,8 @@ export class ColorDef {
* *"#rrbbgg"*
* *"blanchedAlmond"* (see possible values from [[ColorByName]]). Case-insensitive.
*
- * If `val` is not a valid string representation of a color, this function returns [[black]].
+ * If `val` is not a valid color string, this function returns [[black]].
+ * @see [[isValidColor]] to determine if `val` is a valid color string.
*/
public static fromString(val: string): ColorDef {
return this.fromTbgr(this.computeTbgrFromString(val));
@@ -139,19 +142,19 @@ export class ColorDef {
}
/** Compute the 0xTTBBGGRR value corresponding to a string representation of a color.
- * If `val` is not a valid string representation of a color, this function returns 0 (black).
- * @see [[fromString]] for the definition of a valid string representation.
- * @see [[tryComputeTbgrFromString]] to determine if `val` is a valid string representation of a color.
+ * If `val` is not a valid color string, this function returns 0 (black).
+ * @see [[fromString]] for the definition of a valid color string.
+ * @see [[tryComputeTbgrFromString]] to determine if `val` is a valid color string.
*/
- public static computeTbgrFromString(val: string): number {
+ public static computeTbgrFromString(val: string): ColorDefProps {
return this.tryComputeTbgrFromString(val) ?? 0;
}
/** Try to compute the 0xTTBBGGRR value corresponding to a string representation of a ColorDef.
* @returns the corresponding numeric representation, or `undefined` if the input does not represent a color.
- * @see [[fromString]] for the definition of a valid string representation.
+ * @see [[fromString]] for the definition of a valid color string.
*/
- public static tryComputeTbgrFromString(val: string): number | undefined {
+ public static tryComputeTbgrFromString(val: string): ColorDefProps | undefined {
if (typeof val !== "string")
return undefined;
@@ -226,13 +229,13 @@ export class ColorDef {
return undefined;
}
- /** Get the r,g,b,t values from this ColorDef. Values will be integers between 0-255. */
+ /** Get the red, green, blue, and transparency values from this ColorDef. Values will be integers between 0-255. */
public get colors(): { r: number, g: number, b: number, t: number } {
return ColorDef.getColors(this._tbgr);
}
/** Get the r,g,b,t values encoded in an 0xTTBBGGRR value. Values will be integers between 0-255. */
- public static getColors(tbgr: number) {
+ public static getColors(tbgr: ColorDefProps) {
scratchUInt32[0] = tbgr;
return {
b: scratchBytes[2],
@@ -243,7 +246,7 @@ export class ColorDef {
}
/** The color value of this ColorDef as an integer in the form 0xTTBBGGRR (red in the low byte) */
- public get tbgr(): number { return this._tbgr; }
+ public get tbgr(): ColorDefProps { return this._tbgr; }
/** Get the value of the color as a number in 0xAABBGGRR format (i.e. red is in low byte). Transparency (0==fully opaque) converted to alpha (0==fully transparent). */
public getAbgr(): number {
@@ -251,7 +254,7 @@ export class ColorDef {
}
/** Get the value of a 0xTTBBGGRR color as a number in 0xAABBGGRR format (i.e. red is in low byte). Transparency (0==fully opaque) converted to alpha (0==fully transparent). */
- public static getAbgr(tbgr: number): number {
+ public static getAbgr(tbgr: ColorDefProps): number {
scratchUInt32[0] = tbgr;
scratchBytes[3] = 255 - scratchBytes[3];
return scratchUInt32[0];
@@ -263,7 +266,7 @@ export class ColorDef {
}
/** Get the RGB value of the 0xTTBBGGRR color as a number in 0xRRGGBB format (i.e blue is in the low byte). Transparency is ignored. Value will be from 0 to 2^24 */
- public static getRgb(tbgr: number): number {
+ public static getRgb(tbgr: ColorDefProps): number {
scratchUInt32[0] = tbgr;
return (scratchBytes[0] << 16) + (scratchBytes[1] << 8) + scratchBytes[2];
}
@@ -281,7 +284,7 @@ export class ColorDef {
* @param alpha the new alpha value as an integer between 0-255.
* @returns The 0xTTBBGGRR value equivalent to `tbgr` but with the specified alpha.
*/
- public static withAlpha(tbgr: number, alpha: number): number {
+ public static withAlpha(tbgr: ColorDefProps, alpha: number): number {
scratchUInt32[0] = tbgr;
scratchBytes[3] = 255 - (alpha | 0);
return scratchUInt32[0];
@@ -293,7 +296,7 @@ export class ColorDef {
}
/** Extract the alpha value from a 0xTTBBGGRR color. */
- public static getAlpha(tbgr: number): number {
+ public static getAlpha(tbgr: ColorDefProps): number {
scratchUInt32[0] = tbgr;
return 255 - scratchBytes[3];
}
@@ -304,7 +307,7 @@ export class ColorDef {
}
/** True if the specified 0xTTBBGGRR color is fully opaque. */
- public static isOpaque(tbgr: number): boolean {
+ public static isOpaque(tbgr: ColorDefProps): boolean {
return 255 === this.getAlpha(tbgr);
}
@@ -314,7 +317,7 @@ export class ColorDef {
}
/** Extract the transparency component from a 0xTTBBGGRR color as an integer between 0-255.. */
- public static getTransparency(tbgr: number): number {
+ public static getTransparency(tbgr: ColorDefProps): number {
scratchUInt32[0] = tbgr;
return scratchBytes[3];
}
@@ -332,7 +335,7 @@ export class ColorDef {
* @param transparency the new transparency as an integer between 0-255.
* @returns The 0xTTBBGGRR value equivalent to `tbgr` but with the specified transparency.
*/
- public static withTransparency(tbgr: number, transparency: number): number {
+ public static withTransparency(tbgr: ColorDefProps, transparency: number): ColorDefProps {
return this.withAlpha(tbgr, 255 - transparency);
}
@@ -344,7 +347,7 @@ export class ColorDef {
/** Obtain the name of the color in the [[ColorByName]] list associated with the specified 0xTTBBGGRR value, or undefined if no such named color exists.
* @note A handful of colors (like "aqua" and "cyan") have identical tbgr values; in such cases the first match will be returned.
*/
- public static getName(tbgr: number): string | undefined {
+ public static getName(tbgr: ColorDefProps): string | undefined {
for (const [key, value] of Object.entries(ColorByName))
if (value === tbgr)
return key;
@@ -358,11 +361,11 @@ export class ColorDef {
}
/** Convert the 0xTTBBGGRR value to a string in the form "#rrggbb". */
- public static toHexString(tbgr: number): string {
+ public static toHexString(tbgr: ColorDefProps): string {
return `#${(`000000${this.getRgb(tbgr).toString(16)}`).slice(-6)}`;
}
- private static getColorsString(tbgr: number) {
+ private static getColorsString(tbgr: ColorDefProps) {
const c = this.getColors(tbgr);
return `${c.r},${c.g},${c.b}`;
}
@@ -373,7 +376,7 @@ export class ColorDef {
}
/** Convert the 0xTTBBGGRR color to a string in the form "rgb(r,g,b)" where each component is specified in decimal. */
- public static toRgbString(tbgr: number): string {
+ public static toRgbString(tbgr: ColorDefProps): string {
return `rgb(${this.getColorsString(tbgr)})`;
}
@@ -383,7 +386,7 @@ export class ColorDef {
}
/** Convert the 0xTTBBGGRR color to a string of the form "rgba(r,g,b,a)" where the color components are specified in decimal and the alpha component is a fraction. */
- public static toRgbaString(tbgr: number): string {
+ public static toRgbaString(tbgr: ColorDefProps): string {
return `rgba(${this.getColorsString(tbgr)},${this.getAlpha(tbgr) / 255.})`;
}
@@ -402,7 +405,7 @@ export class ColorDef {
* @param weight The weighting factor in [0..1]. A value of 0.0 selects `tbgr1`; 1.0 selects `tbgr2`; 0.5 mixes them evenly; etc.
* @returns The linear interpolation between `tbgr1` and `tbgr2` using the specified weight.
*/
- public static lerp(tbgr1: number, tbgr2: number, weight: number): number {
+ public static lerp(tbgr1: ColorDefProps, tbgr2: ColorDefProps, weight: number): ColorDefProps {
const c = this.getColors(tbgr1);
const color = this.getColors(tbgr2);
c.r += (color.r - c.r) * weight;
@@ -417,7 +420,7 @@ export class ColorDef {
}
/** Return a 0xTTBBGGRR color whose color components are the inverse of the input color. The result has 0 transparency. */
- public static inverse(tbgr: number): number {
+ public static inverse(tbgr: ColorDefProps): ColorDefProps {
const colors = this.getColors(tbgr);
return this.computeTbgrFromComponents(255 - colors.r, 255 - colors.g, 255 - colors.b);
}
@@ -428,7 +431,7 @@ export class ColorDef {
}
/** Compute the 0xTTBBGGRR color corresponding to the specified hue, saturation, lightness values. */
- public static computeTbgrFromHSL(h: number, s: number, l: number, transparency = 0): number {
+ public static computeTbgrFromHSL(h: number, s: number, l: number, transparency = 0): ColorDefProps {
const torgb = (p1: number, q1: number, t: number) => {
if (t < 0) t += 1;
if (t > 1) t -= 1;
diff --git a/core/common/src/test/ColorDef.test.ts b/core/common/src/test/ColorDef.test.ts
index ebe0b9667940..bfd567660d79 100644
--- a/core/common/src/test/ColorDef.test.ts
+++ b/core/common/src/test/ColorDef.test.ts
@@ -132,7 +132,6 @@ describe("ColorDef", () => {
});
it("determines whether string and numeric values represent valid colors", () => {
- // Iterating over an enum produces both the keys and the values, as strings.
for (const [key, value] of Object.entries(ColorByName)) {
expect(ColorDef.isValidColor(key)).to.be.true;
expect(ColorDef.isValidColor(`${key}xx`)).to.be.false;
@@ -141,6 +140,8 @@ describe("ColorDef", () => {
expect(ColorDef.isValidColor(value + 0.5)).to.be.false;
expect(ColorDef.isValidColor(-value)).to.equal(0 === value);
}
+
+ expect(ColorDef.isValidColor(0x100000000)).to.be.false;
});
it("looks up name from numeric representation", () => {
From da6a1fa8c39e1360d3f79d4e8eda951aabd86798 Mon Sep 17 00:00:00 2001
From: Paul Connelly <22944042+pmconne@users.noreply.github.com>
Date: Tue, 15 Mar 2022 11:16:00 -0400
Subject: [PATCH 4/7] lint, extract-api
---
common/api/core-common.api.md | 496 ++++++------------
common/api/summary/core-common.exports.csv | 2 +-
...c-validate-color-def_2022-03-15-15-16.json | 10 +
core/common/src/ColorByName.ts | 4 +-
4 files changed, 187 insertions(+), 325 deletions(-)
create mode 100644 common/changes/@itwin/core-common/pmc-validate-color-def_2022-03-15-15-16.json
diff --git a/common/api/core-common.api.md b/common/api/core-common.api.md
index 45c36a5b87cf..b0be0d1668ce 100644
--- a/common/api/core-common.api.md
+++ b/common/api/core-common.api.md
@@ -1256,308 +1256,158 @@ export class CodeSpec {
}
// @public
-export enum ColorByName {
- // (undocumented)
- aliceBlue = 16775408,
- // (undocumented)
- amber = 49151,
- // (undocumented)
- antiqueWhite = 14150650,
- // (undocumented)
- aqua = 16776960,
- // (undocumented)
- aquamarine = 13959039,
- // (undocumented)
- azure = 16777200,
- // (undocumented)
- beige = 14480885,
- // (undocumented)
- bisque = 12903679,
- // (undocumented)
- black = 0,
- // (undocumented)
- blanchedAlmond = 13495295,
- // (undocumented)
- blue = 16711680,
- // (undocumented)
- blueViolet = 14822282,
- // (undocumented)
- brown = 2763429,
- // (undocumented)
- burlyWood = 8894686,
- // (undocumented)
- cadetBlue = 10526303,
- // (undocumented)
- chartreuse = 65407,
- // (undocumented)
- chocolate = 1993170,
- // (undocumented)
- coral = 5275647,
- // (undocumented)
- cornflowerBlue = 15570276,
- // (undocumented)
- cornSilk = 14481663,
- // (undocumented)
- crimson = 3937500,
- // (undocumented)
- cyan = 16776960,
- // (undocumented)
- darkBlue = 9109504,
- // (undocumented)
- darkBrown = 2179941,
- // (undocumented)
- darkCyan = 9145088,
- // (undocumented)
- darkGoldenrod = 755384,
- // (undocumented)
- darkGray = 11119017,
- // (undocumented)
- darkGreen = 25600,
- // (undocumented)
- darkGrey = 11119017,
- // (undocumented)
- darkKhaki = 7059389,
- // (undocumented)
- darkMagenta = 9109643,
- // (undocumented)
- darkOliveGreen = 3107669,
- // (undocumented)
- darkOrange = 36095,
- // (undocumented)
- darkOrchid = 13382297,
- // (undocumented)
- darkRed = 139,
- // (undocumented)
- darkSalmon = 8034025,
- // (undocumented)
- darkSeagreen = 9419919,
- // (undocumented)
- darkSlateBlue = 9125192,
- // (undocumented)
- darkSlateGray = 5197615,
- // (undocumented)
- darkSlateGrey = 5197615,
- // (undocumented)
- darkTurquoise = 13749760,
- // (undocumented)
- darkViolet = 13828244,
- // (undocumented)
- deepPink = 9639167,
- // (undocumented)
- deepSkyBlue = 16760576,
- // (undocumented)
- dimGray = 6908265,
- // (undocumented)
- dimGrey = 6908265,
- // (undocumented)
- dodgerBlue = 16748574,
- // (undocumented)
- fireBrick = 2237106,
- // (undocumented)
- floralWhite = 15792895,
- // (undocumented)
- forestGreen = 2263842,
- // (undocumented)
- fuchsia = 16711935,
- // (undocumented)
- gainsboro = 14474460,
- // (undocumented)
- ghostWhite = 16775416,
- // (undocumented)
- gold = 55295,
- // (undocumented)
- goldenrod = 2139610,
- // (undocumented)
- gray = 8421504,
- // (undocumented)
- green = 32768,
- // (undocumented)
- greenYellow = 3145645,
- // (undocumented)
- grey = 8421504,
- // (undocumented)
- honeydew = 15794160,
- // (undocumented)
- hotPink = 11823615,
- // (undocumented)
- indianRed = 6053069,
- // (undocumented)
- indigo = 8519755,
- // (undocumented)
- ivory = 15794175,
- // (undocumented)
- khaki = 9234160,
- // (undocumented)
- lavender = 16443110,
- // (undocumented)
- lavenderBlush = 16118015,
- // (undocumented)
- lawnGreen = 64636,
- // (undocumented)
- lemonChiffon = 13499135,
- // (undocumented)
- lightBlue = 15128749,
- // (undocumented)
- lightCoral = 8421616,
- // (undocumented)
- lightCyan = 16777184,
- // (undocumented)
- lightGoldenrodYellow = 13826810,
- // (undocumented)
- lightGray = 13882323,
- // (undocumented)
- lightGreen = 9498256,
- // (undocumented)
- lightGrey = 13882323,
- // (undocumented)
- lightPink = 12695295,
- // (undocumented)
- lightSalmon = 8036607,
- // (undocumented)
- lightSeagreen = 11186720,
- // (undocumented)
- lightSkyBlue = 16436871,
- // (undocumented)
- lightSlateGray = 10061943,
- // (undocumented)
- lightSlateGrey = 10061943,
- // (undocumented)
- lightSteelBlue = 14599344,
- // (undocumented)
- lightyellow = 14745599,
- // (undocumented)
- lime = 65280,
- // (undocumented)
- limeGreen = 3329330,
- // (undocumented)
- linen = 15134970,
- // (undocumented)
- magenta = 16711935,
- // (undocumented)
- maroon = 128,
- // (undocumented)
- mediumAquamarine = 11193702,
- // (undocumented)
- mediumBlue = 13434880,
- // (undocumented)
- mediumOrchid = 13850042,
- // (undocumented)
- mediumPurple = 14381203,
- // (undocumented)
- mediumSeaGreen = 7451452,
- // (undocumented)
- mediumSlateBlue = 15624315,
- // (undocumented)
- mediumSpringGreen = 10156544,
- // (undocumented)
- mediumTurquoise = 13422920,
- // (undocumented)
- mediumVioletRed = 8721863,
- // (undocumented)
- midnightBlue = 7346457,
- // (undocumented)
- mintCream = 16449525,
- // (undocumented)
- mistyRose = 14804223,
- // (undocumented)
- moccasin = 11920639,
- // (undocumented)
- navajoWhite = 11394815,
- // (undocumented)
- navy = 8388608,
- // (undocumented)
- oldLace = 15136253,
- // (undocumented)
- olive = 32896,
- // (undocumented)
- oliveDrab = 2330219,
- // (undocumented)
- orange = 42495,
- // (undocumented)
- orangeRed = 17919,
- // (undocumented)
- orchid = 14053594,
- // (undocumented)
- paleGoldenrod = 11200750,
- // (undocumented)
- paleGreen = 10025880,
- // (undocumented)
- paleTurquoise = 15658671,
- // (undocumented)
- paleVioletRed = 9662683,
- // (undocumented)
- papayaWhip = 14020607,
- // (undocumented)
- peachPuff = 12180223,
- // (undocumented)
- peru = 4163021,
- // (undocumented)
- pink = 13353215,
- // (undocumented)
- plum = 14524637,
- // (undocumented)
- powderBlue = 15130800,
- // (undocumented)
- purple = 8388736,
- // (undocumented)
- rebeccaPurple = 10040166,
- // (undocumented)
- red = 255,
- // (undocumented)
- rosyBrown = 9408444,
- // (undocumented)
- royalBlue = 14772545,
- // (undocumented)
- saddleBrown = 1262987,
- // (undocumented)
- salmon = 7504122,
- // (undocumented)
- sandyBrown = 6333684,
- // (undocumented)
- seaGreen = 5737262,
- // (undocumented)
- seaShell = 15660543,
- // (undocumented)
- sienna = 2970272,
- // (undocumented)
- silver = 12632256,
- // (undocumented)
- skyBlue = 15453831,
- // (undocumented)
- slateBlue = 13458026,
- // (undocumented)
- slateGray = 9470064,
- // (undocumented)
- slateGrey = 9470064,
- // (undocumented)
- snow = 16448255,
- // (undocumented)
- springGreen = 8388352,
- // (undocumented)
- steelBlue = 11829830,
- // (undocumented)
- tan = 9221330,
- // (undocumented)
- teal = 8421376,
- // (undocumented)
- thistle = 14204888,
- // (undocumented)
- tomato = 4678655,
- // (undocumented)
- turquoise = 13688896,
- // (undocumented)
- violet = 15631086,
- // (undocumented)
- wheat = 11788021,
- // (undocumented)
- white = 16777215,
- // (undocumented)
- whiteSmoke = 16119285,
- // (undocumented)
- yellow = 65535,
- // (undocumented)
- yellowGreen = 3329434
-}
+export const ColorByName: {
+ aliceBlue: number;
+ amber: number;
+ antiqueWhite: number;
+ aqua: number;
+ aquamarine: number;
+ azure: number;
+ beige: number;
+ bisque: number;
+ black: number;
+ blanchedAlmond: number;
+ blue: number;
+ blueViolet: number;
+ brown: number;
+ burlyWood: number;
+ cadetBlue: number;
+ chartreuse: number;
+ chocolate: number;
+ coral: number;
+ cornflowerBlue: number;
+ cornSilk: number;
+ crimson: number;
+ cyan: number;
+ darkBlue: number;
+ darkBrown: number;
+ darkCyan: number;
+ darkGoldenrod: number;
+ darkGray: number;
+ darkGreen: number;
+ darkGrey: number;
+ darkKhaki: number;
+ darkMagenta: number;
+ darkOliveGreen: number;
+ darkOrange: number;
+ darkOrchid: number;
+ darkRed: number;
+ darkSalmon: number;
+ darkSeagreen: number;
+ darkSlateBlue: number;
+ darkSlateGray: number;
+ darkSlateGrey: number;
+ darkTurquoise: number;
+ darkViolet: number;
+ deepPink: number;
+ deepSkyBlue: number;
+ dimGray: number;
+ dimGrey: number;
+ dodgerBlue: number;
+ fireBrick: number;
+ floralWhite: number;
+ forestGreen: number;
+ fuchsia: number;
+ gainsboro: number;
+ ghostWhite: number;
+ gold: number;
+ goldenrod: number;
+ gray: number;
+ green: number;
+ greenYellow: number;
+ grey: number;
+ honeydew: number;
+ hotPink: number;
+ indianRed: number;
+ indigo: number;
+ ivory: number;
+ khaki: number;
+ lavender: number;
+ lavenderBlush: number;
+ lawnGreen: number;
+ lemonChiffon: number;
+ lightBlue: number;
+ lightCoral: number;
+ lightCyan: number;
+ lightGoldenrodYellow: number;
+ lightGray: number;
+ lightGreen: number;
+ lightGrey: number;
+ lightPink: number;
+ lightSalmon: number;
+ lightSeagreen: number;
+ lightSkyBlue: number;
+ lightSlateGray: number;
+ lightSlateGrey: number;
+ lightSteelBlue: number;
+ lightyellow: number;
+ lime: number;
+ limeGreen: number;
+ linen: number;
+ magenta: number;
+ maroon: number;
+ mediumAquamarine: number;
+ mediumBlue: number;
+ mediumOrchid: number;
+ mediumPurple: number;
+ mediumSeaGreen: number;
+ mediumSlateBlue: number;
+ mediumSpringGreen: number;
+ mediumTurquoise: number;
+ mediumVioletRed: number;
+ midnightBlue: number;
+ mintCream: number;
+ mistyRose: number;
+ moccasin: number;
+ navajoWhite: number;
+ navy: number;
+ oldLace: number;
+ olive: number;
+ oliveDrab: number;
+ orange: number;
+ orangeRed: number;
+ orchid: number;
+ paleGoldenrod: number;
+ paleGreen: number;
+ paleTurquoise: number;
+ paleVioletRed: number;
+ papayaWhip: number;
+ peachPuff: number;
+ peru: number;
+ pink: number;
+ plum: number;
+ powderBlue: number;
+ purple: number;
+ rebeccaPurple: number;
+ red: number;
+ rosyBrown: number;
+ royalBlue: number;
+ saddleBrown: number;
+ salmon: number;
+ sandyBrown: number;
+ seaGreen: number;
+ seaShell: number;
+ sienna: number;
+ silver: number;
+ skyBlue: number;
+ slateBlue: number;
+ slateGray: number;
+ slateGrey: number;
+ snow: number;
+ springGreen: number;
+ steelBlue: number;
+ tan: number;
+ teal: number;
+ thistle: number;
+ tomato: number;
+ turquoise: number;
+ violet: number;
+ wheat: number;
+ white: number;
+ whiteSmoke: number;
+ yellow: number;
+ yellowGreen: number;
+};
// @public
export class ColorDef {
@@ -1571,10 +1421,10 @@ export class ColorDef {
t: number;
};
// @internal (undocumented)
- static computeTbgr(val?: string | ColorDefProps): number;
- static computeTbgrFromComponents(red: number, green: number, blue: number, transparency?: number): number;
- static computeTbgrFromHSL(h: number, s: number, l: number, transparency?: number): number;
- static computeTbgrFromString(val: string): number;
+ static computeTbgr(val?: string | ColorDefProps): ColorDefProps;
+ static computeTbgrFromComponents(red: number, green: number, blue: number, transparency?: number): ColorDefProps;
+ static computeTbgrFromHSL(h: number, s: number, l: number, transparency?: number): ColorDefProps;
+ static computeTbgrFromString(val: string): ColorDefProps;
static create(val?: string | ColorDefProps): ColorDef;
equals(other: ColorDef): boolean;
static from(red: number, green: number, blue: number, transparency?: number): ColorDef;
@@ -1582,46 +1432,48 @@ export class ColorDef {
static fromHSV(hsv: HSVColor, transparency?: number): ColorDef;
static fromJSON(json?: ColorDefProps): ColorDef;
static fromString(val: string): ColorDef;
- static fromTbgr(tbgr: number): ColorDef;
+ static fromTbgr(tbgr: ColorDefProps): ColorDef;
getAbgr(): number;
- static getAbgr(tbgr: number): number;
+ static getAbgr(tbgr: ColorDefProps): number;
getAlpha(): number;
- static getAlpha(tbgr: number): number;
- static getColors(tbgr: number): {
+ static getAlpha(tbgr: ColorDefProps): number;
+ static getColors(tbgr: ColorDefProps): {
b: number;
g: number;
r: number;
t: number;
};
- static getName(tbgr: number): string | undefined;
+ static getName(tbgr: ColorDefProps): string | undefined;
getRgb(): number;
- static getRgb(tbgr: number): number;
+ static getRgb(tbgr: ColorDefProps): number;
getTransparency(): number;
- static getTransparency(tbgr: number): number;
+ static getTransparency(tbgr: ColorDefProps): number;
static readonly green: ColorDef;
inverse(): ColorDef;
- static inverse(tbgr: number): number;
+ static inverse(tbgr: ColorDefProps): ColorDefProps;
get isOpaque(): boolean;
- static isOpaque(tbgr: number): boolean;
+ static isOpaque(tbgr: ColorDefProps): boolean;
+ static isValidColor(val: string | number): boolean;
lerp(color2: ColorDef, weight: number): ColorDef;
- static lerp(tbgr1: number, tbgr2: number, weight: number): number;
+ static lerp(tbgr1: ColorDefProps, tbgr2: ColorDefProps, weight: number): ColorDefProps;
get name(): string | undefined;
static readonly red: ColorDef;
- get tbgr(): number;
+ get tbgr(): ColorDefProps;
toHexString(): string;
- static toHexString(tbgr: number): string;
+ static toHexString(tbgr: ColorDefProps): string;
toHSL(): HSLColor;
toHSV(): HSVColor;
toJSON(): ColorDefProps;
toRgbaString(): string;
- static toRgbaString(tbgr: number): string;
+ static toRgbaString(tbgr: ColorDefProps): string;
toRgbString(): string;
- static toRgbString(tbgr: number): string;
+ static toRgbString(tbgr: ColorDefProps): string;
+ static tryComputeTbgrFromString(val: string): ColorDefProps | undefined;
static readonly white: ColorDef;
withAlpha(alpha: number): ColorDef;
- static withAlpha(tbgr: number, alpha: number): number;
+ static withAlpha(tbgr: ColorDefProps, alpha: number): number;
withTransparency(transparency: number): ColorDef;
- static withTransparency(tbgr: number, transparency: number): number;
+ static withTransparency(tbgr: ColorDefProps, transparency: number): ColorDefProps;
}
// @public
diff --git a/common/api/summary/core-common.exports.csv b/common/api/summary/core-common.exports.csv
index 0cca09f09bce..e8f55ad0ea17 100644
--- a/common/api/summary/core-common.exports.csv
+++ b/common/api/summary/core-common.exports.csv
@@ -112,7 +112,7 @@ public;CodeProps
public;CodeScopeProps = Id64String | GuidString
public;CodeScopeSpec
public;CodeSpec
-public;ColorByName
+public;ColorByName:
public;ColorDef
public;ColorDefProps = number
internal;ColorIndex
diff --git a/common/changes/@itwin/core-common/pmc-validate-color-def_2022-03-15-15-16.json b/common/changes/@itwin/core-common/pmc-validate-color-def_2022-03-15-15-16.json
new file mode 100644
index 000000000000..4666bc81b5b1
--- /dev/null
+++ b/common/changes/@itwin/core-common/pmc-validate-color-def_2022-03-15-15-16.json
@@ -0,0 +1,10 @@
+{
+ "changes": [
+ {
+ "packageName": "@itwin/core-common",
+ "comment": "Add methods to validate ColorDefProps and color strings; fix failure to find duplicate ColorByName values.",
+ "type": "none"
+ }
+ ],
+ "packageName": "@itwin/core-common"
+}
\ No newline at end of file
diff --git a/core/common/src/ColorByName.ts b/core/common/src/ColorByName.ts
index 0c6298fe9256..1a9cdff6a9e4 100644
--- a/core/common/src/ColorByName.ts
+++ b/core/common/src/ColorByName.ts
@@ -12,7 +12,7 @@
* @note If your colors don't look right, likely you're using 0xRRGGBB where ColorDef expects 0xBBGGRR.
* @public
*/
-export const ColorByName = {
+export const ColorByName = { // eslint-disable-line @typescript-eslint/naming-convention
aliceBlue: 0xFFF8F0,
amber: 0x00BFFF,
antiqueWhite: 0xD7EBFA,
@@ -163,4 +163,4 @@ export const ColorByName = {
whiteSmoke: 0xF5F5F5,
yellow: 0x00FFFF,
yellowGreen: 0x32CD9A,
-}
+};
From 7d54083873231af7fc8e76dcf0cf4fbf4c19c26c Mon Sep 17 00:00:00 2001
From: Paul Connelly <22944042+pmconne@users.noreply.github.com>
Date: Tue, 15 Mar 2022 11:27:29 -0400
Subject: [PATCH 5/7] NextVersion.md
---
docs/changehistory/NextVersion.md | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/docs/changehistory/NextVersion.md b/docs/changehistory/NextVersion.md
index 86e9c1da537f..cc010f7bbfd0 100644
--- a/docs/changehistory/NextVersion.md
+++ b/docs/changehistory/NextVersion.md
@@ -3,8 +3,6 @@ publish: false
---
# NextVersion
-## @itwin/webgl-compatibility changes
-
### Detecting integrated graphics
Many computers - especially laptops - contain two graphics processing units: a low-powered "integrated" GPU such as those manufactured by Intel, and a more powerful "discrete" GPU typically manufactured by NVidia or AMD. Operating systems and web browsers often default to using the integrated GPU to reduce power consumption, but this can produce poor performance in graphics-heavy applications like those built with iTwin.js. We recommend that users adjust their settings to use the discrete GPU if one is available.
@@ -16,3 +14,11 @@ iTwin.js applications can now check [WebGLRenderCompatibilityInfo.usingIntegrate
if (compatibility.usingIntegratedGraphics)
alert("Integrated graphics are in use. If a discrete GPU is available, consider switching your device or browser to use it.");
```
+
+## ColorDef validation
+
+[ColorDef.fromString]($common) returns [ColorDef.black]($common) if the input is not a valid color string. [ColorDef.create]($common) coerces the input numeric representation into a 32-bit unsigned integer. In either case, this occurs silently. Now, you can use [ColorDef.isValidColor]($common) to determine if your input is valid.
+
+## ColorByName is an object, not an enum
+
+Enums in TypeScript have some shortcomings, one of which resulted in a bug that caused [ColorDef.fromString]($common) to return [ColorDef.black]($common) for some valid color strings like "aqua". This is due to several standard color names ("aqua" and "cyan", "magenta" and "fuschia", and several "grey" vs "gray" variations) having the same numeric values. To address this, [ColorByName]($common) has been converted from an `enum` to a `namespace`. Code that accesses `ColorByName` members by name will continue to compile with no change.
From c98861dbc93786b72e22cb0b7c3d21ad144160c2 Mon Sep 17 00:00:00 2001
From: Paul Connelly <22944042+pmconne@users.noreply.github.com>
Date: Tue, 15 Mar 2022 11:59:12 -0400
Subject: [PATCH 6/7] why aren't integration tests running?
---
.../core-common/pmc-validate-color-def_2022-03-15-15-16.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/common/changes/@itwin/core-common/pmc-validate-color-def_2022-03-15-15-16.json b/common/changes/@itwin/core-common/pmc-validate-color-def_2022-03-15-15-16.json
index 4666bc81b5b1..3ad34840cf92 100644
--- a/common/changes/@itwin/core-common/pmc-validate-color-def_2022-03-15-15-16.json
+++ b/common/changes/@itwin/core-common/pmc-validate-color-def_2022-03-15-15-16.json
@@ -2,9 +2,9 @@
"changes": [
{
"packageName": "@itwin/core-common",
- "comment": "Add methods to validate ColorDefProps and color strings; fix failure to find duplicate ColorByName values.",
+ "comment": "Add methods to validate ColorDefProps and color strings; fix failure to find duplicate color names.",
"type": "none"
}
],
"packageName": "@itwin/core-common"
-}
\ No newline at end of file
+}
From 48437f65a4b2e7fe69f5310eb0d137cf049128cf Mon Sep 17 00:00:00 2001
From: Paul Connelly <22944042+pmconne@users.noreply.github.com>
Date: Tue, 15 Mar 2022 12:24:01 -0400
Subject: [PATCH 7/7] so much casting.
---
.../src/tools/SampleTool.ts | 18 +++++++++---------
.../src/ui/dialogs/TestUiProviderDialog.ts | 18 +++++++++---------
.../appui/dialogs/TestUiProviderDialog.ts | 18 +++++++++---------
.../src/test/TestUtils.ts | 16 ++++++++--------
.../src/test/color/ColorPickerButton.test.tsx | 2 +-
.../src/test/color/ColorPickerDialog.test.tsx | 4 ++--
.../src/test/color/ColorPickerPopup.test.tsx | 4 ++--
.../src/test/editors/ColorEditor.test.tsx | 12 ++++++------
8 files changed, 46 insertions(+), 46 deletions(-)
diff --git a/test-apps/ui-items-providers-test/src/tools/SampleTool.ts b/test-apps/ui-items-providers-test/src/tools/SampleTool.ts
index 98ff93964376..4859f57207a6 100644
--- a/test-apps/ui-items-providers-test/src/tools/SampleTool.ts
+++ b/test-apps/ui-items-providers-test/src/tools/SampleTool.ts
@@ -106,14 +106,14 @@ export class SampleTool extends PrimitiveTool {
params: [{
type: PropertyEditorParamTypes.ColorData,
colorValues: [
- ColorByName.blue as number,
- ColorByName.red as number,
- ColorByName.green as number,
- ColorByName.yellow as number,
- ColorByName.black as number,
- ColorByName.gray as number,
- ColorByName.purple as number,
- ColorByName.pink as number,
+ ColorByName.blue,
+ ColorByName.red,
+ ColorByName.green,
+ ColorByName.yellow,
+ ColorByName.black,
+ ColorByName.gray,
+ ColorByName.purple,
+ ColorByName.pink,
],
numColumns: 2,
} as ColorEditorParams,
@@ -122,7 +122,7 @@ export class SampleTool extends PrimitiveTool {
};
};
- private _colorValue: DialogItemValue = { value: ColorByName.blue as number };
+ private _colorValue: DialogItemValue = { value: ColorByName.blue };
public get colorValue(): number {
return this._optionsValue.value as number;
diff --git a/test-apps/ui-items-providers-test/src/ui/dialogs/TestUiProviderDialog.ts b/test-apps/ui-items-providers-test/src/ui/dialogs/TestUiProviderDialog.ts
index 3e391b94f9bc..6610bf36f952 100644
--- a/test-apps/ui-items-providers-test/src/ui/dialogs/TestUiProviderDialog.ts
+++ b/test-apps/ui-items-providers-test/src/ui/dialogs/TestUiProviderDialog.ts
@@ -69,14 +69,14 @@ export class TestUiProvider extends DialogLayoutDataProvider {
params: [{
type: PropertyEditorParamTypes.ColorData,
colorValues: [
- ColorByName.blue as number,
- ColorByName.red as number,
- ColorByName.green as number,
- ColorByName.yellow as number,
- ColorByName.black as number,
- ColorByName.gray as number,
- ColorByName.purple as number,
- ColorByName.pink as number,
+ ColorByName.blue,
+ ColorByName.red,
+ ColorByName.green,
+ ColorByName.yellow,
+ ColorByName.black,
+ ColorByName.gray,
+ ColorByName.purple,
+ ColorByName.pink,
],
numColumns: 3,
} as ColorEditorParams,
@@ -85,7 +85,7 @@ export class TestUiProvider extends DialogLayoutDataProvider {
};
};
- private _colorValue: DialogItemValue = { value: ColorByName.blue as number };
+ private _colorValue: DialogItemValue = { value: ColorByName.blue };
public get colorValue(): number {
return this._colorValue.value as number;
diff --git a/test-apps/ui-test-app/src/frontend/appui/dialogs/TestUiProviderDialog.ts b/test-apps/ui-test-app/src/frontend/appui/dialogs/TestUiProviderDialog.ts
index 3e391b94f9bc..6610bf36f952 100644
--- a/test-apps/ui-test-app/src/frontend/appui/dialogs/TestUiProviderDialog.ts
+++ b/test-apps/ui-test-app/src/frontend/appui/dialogs/TestUiProviderDialog.ts
@@ -69,14 +69,14 @@ export class TestUiProvider extends DialogLayoutDataProvider {
params: [{
type: PropertyEditorParamTypes.ColorData,
colorValues: [
- ColorByName.blue as number,
- ColorByName.red as number,
- ColorByName.green as number,
- ColorByName.yellow as number,
- ColorByName.black as number,
- ColorByName.gray as number,
- ColorByName.purple as number,
- ColorByName.pink as number,
+ ColorByName.blue,
+ ColorByName.red,
+ ColorByName.green,
+ ColorByName.yellow,
+ ColorByName.black,
+ ColorByName.gray,
+ ColorByName.purple,
+ ColorByName.pink,
],
numColumns: 3,
} as ColorEditorParams,
@@ -85,7 +85,7 @@ export class TestUiProvider extends DialogLayoutDataProvider {
};
};
- private _colorValue: DialogItemValue = { value: ColorByName.blue as number };
+ private _colorValue: DialogItemValue = { value: ColorByName.blue };
public get colorValue(): number {
return this._colorValue.value as number;
diff --git a/ui/imodel-components-react/src/test/TestUtils.ts b/ui/imodel-components-react/src/test/TestUtils.ts
index 68258084356d..d87e54646129 100644
--- a/ui/imodel-components-react/src/test/TestUtils.ts
+++ b/ui/imodel-components-react/src/test/TestUtils.ts
@@ -274,14 +274,14 @@ export class TestUtils {
{
type: PropertyEditorParamTypes.ColorData,
colorValues: [
- ColorByName.blue as number,
- ColorByName.red as number,
- ColorByName.green as number,
- ColorByName.yellow as number,
- ColorByName.black as number,
- ColorByName.gray as number,
- ColorByName.purple as number,
- ColorByName.pink as number,
+ ColorByName.blue,
+ ColorByName.red,
+ ColorByName.green,
+ ColorByName.yellow,
+ ColorByName.black,
+ ColorByName.gray,
+ ColorByName.purple,
+ ColorByName.pink,
],
numColumns: 2,
} as ColorEditorParams,
diff --git a/ui/imodel-components-react/src/test/color/ColorPickerButton.test.tsx b/ui/imodel-components-react/src/test/color/ColorPickerButton.test.tsx
index a294a5387ed8..5b150766941b 100644
--- a/ui/imodel-components-react/src/test/color/ColorPickerButton.test.tsx
+++ b/ui/imodel-components-react/src/test/color/ColorPickerButton.test.tsx
@@ -53,7 +53,7 @@ describe("", () => {
const spyOnColorPick = sinon.spy();
function handleColorPick(color: ColorDef): void {
- expect(color.tbgr).to.be.equal(ColorByName.red as number);
+ expect(color.tbgr).to.be.equal(ColorByName.red);
spyOnColorPick();
}
diff --git a/ui/imodel-components-react/src/test/color/ColorPickerDialog.test.tsx b/ui/imodel-components-react/src/test/color/ColorPickerDialog.test.tsx
index 7195de49bc51..6b13ae8d3dc1 100644
--- a/ui/imodel-components-react/src/test/color/ColorPickerDialog.test.tsx
+++ b/ui/imodel-components-react/src/test/color/ColorPickerDialog.test.tsx
@@ -56,7 +56,7 @@ describe("ColorPickerDialog", () => {
const spyOnOK = sinon.spy();
function handleOK(color: ColorDef): void {
- expect(color.tbgr).to.be.equal(ColorByName.blue as number);
+ expect(color.tbgr).to.be.equal(ColorByName.blue);
spyOnOK();
}
@@ -82,7 +82,7 @@ describe("ColorPickerDialog", () => {
];
function handleOK(color: ColorDef): void {
- expect(color.tbgr).to.be.equal(ColorByName.black as number);
+ expect(color.tbgr).to.be.equal(ColorByName.black);
spyOnOK();
}
diff --git a/ui/imodel-components-react/src/test/color/ColorPickerPopup.test.tsx b/ui/imodel-components-react/src/test/color/ColorPickerPopup.test.tsx
index ffb90e80c6dc..6ab9911b6931 100644
--- a/ui/imodel-components-react/src/test/color/ColorPickerPopup.test.tsx
+++ b/ui/imodel-components-react/src/test/color/ColorPickerPopup.test.tsx
@@ -39,7 +39,7 @@ describe("", () => {
const spyOnColorPick = sinon.spy();
function handleColorPick(color: ColorDef): void {
- expect(color.tbgr).to.be.equal(ColorByName.red as number);
+ expect(color.tbgr).to.be.equal(ColorByName.red);
spyOnColorPick();
}
@@ -62,7 +62,7 @@ describe("", () => {
const spyOnColorPick = sinon.spy();
function handleColorPick(color: ColorDef): void {
- expect(color.tbgr).to.be.equal(ColorByName.green as number);
+ expect(color.tbgr).to.be.equal(ColorByName.green);
spyOnColorPick();
}
diff --git a/ui/imodel-components-react/src/test/editors/ColorEditor.test.tsx b/ui/imodel-components-react/src/test/editors/ColorEditor.test.tsx
index 3a219f5c5bd7..91b6b49d9dca 100644
--- a/ui/imodel-components-react/src/test/editors/ColorEditor.test.tsx
+++ b/ui/imodel-components-react/src/test/editors/ColorEditor.test.tsx
@@ -23,12 +23,12 @@ describe("", () => {
});
it("should trigger componentDidUpdate", async () => {
- const record1 = TestUtils.createColorProperty("Test", ColorByName.green as number);
- const record2 = TestUtils.createColorProperty("Test", ColorByName.blue as number);
+ const record1 = TestUtils.createColorProperty("Test", ColorByName.green);
+ const record2 = TestUtils.createColorProperty("Test", ColorByName.blue);
record2.isDisabled = true;
const originalValue = (record1.value as PrimitiveValue).value as number;
- expect(originalValue).to.be.equal(ColorByName.green as number);
+ expect(originalValue).to.be.equal(ColorByName.green);
const renderedComponent = render();
renderedComponent.rerender();
@@ -36,15 +36,15 @@ describe("", () => {
});
it("button press should open popup and allow color selection", async () => {
- const record = TestUtils.createColorProperty("Test", ColorByName.green as number);
+ const record = TestUtils.createColorProperty("Test", ColorByName.green);
const originalValue = (record.value as PrimitiveValue).value as number;
- expect(originalValue).to.be.equal(ColorByName.green as number);
+ expect(originalValue).to.be.equal(ColorByName.green);
const spyOnCommit = sinon.spy();
function handleCommit(commit: PropertyUpdatedArgs): void {
const newValue = (commit.newValue as PrimitiveValue).value as number;
- expect(newValue).to.be.equal(ColorByName.blue as number);
+ expect(newValue).to.be.equal(ColorByName.blue);
spyOnCommit();
}