cheetah-grid
Version:
Cheetah Grid is a high performance grid engine that works on canvas
457 lines (450 loc) • 13.3 kB
text/typescript
import type {
ColorPropertyDefine,
ColorsPropertyDefine,
PartialThemeDefine,
RequiredThemeDefine,
StylePropertyFunctionArg,
ThemeDefine,
TreeBranchIconStyleDefine,
TreeLineStyle,
} from "../ts-types";
import { getChainSafe } from "../internal/utils";
import { get as getSymbol } from "../internal/symbolManager";
import { getTreeNodeInfoAt } from "../columns/type/TreeColumn";
//private symbol
const _ = getSymbol();
function getProp<T>(
obj: PartialThemeDefine,
superObj: ThemeDefine,
names: string[],
defNames?: string[],
convertForSuper?: (value: never) => T | undefined,
defaultValue?: T
): T {
const value = getChainSafe(obj, ...names) || getChainSafe(superObj, ...names);
if (value) {
return value;
}
if (!defNames) {
return value || defaultValue;
}
const getChainSafeWithConvert = convertForSuper
? (obj: PartialThemeDefine, ...names: string[]) => {
const value = getChainSafe(obj, ...names);
if (!value) {
return value;
}
return convertForSuper(value as never);
}
: getChainSafe;
return (
getChainSafeWithConvert(obj, ...defNames) ||
getChainSafeWithConvert(superObj, ...defNames) ||
defaultValue
);
}
export class Theme implements RequiredThemeDefine {
private [_]: {
obj: PartialThemeDefine;
superTheme: ThemeDefine;
};
private _checkbox: RequiredThemeDefine["checkbox"] | null = null;
private _radioButton: RequiredThemeDefine["radioButton"] | null = null;
private _button: RequiredThemeDefine["button"] | null = null;
private _tree: RequiredThemeDefine["tree"] | null = null;
private _header: RequiredThemeDefine["header"] | null = null;
private _messages: RequiredThemeDefine["messages"] | null = null;
private _indicators: RequiredThemeDefine["indicators"] | null = null;
constructor(obj: ThemeDefine);
constructor(obj: PartialThemeDefine, superTheme: ThemeDefine);
constructor(obj: PartialThemeDefine | ThemeDefine, superTheme?: ThemeDefine) {
this[_] = {
obj,
superTheme: superTheme as ThemeDefine,
};
}
get font(): string {
const { obj, superTheme } = this[_];
return getProp(obj, superTheme, ["font"]);
}
get underlayBackgroundColor(): string {
const { obj, superTheme } = this[_];
return getProp(obj, superTheme, ["underlayBackgroundColor"]);
}
// color
get color(): ColorPropertyDefine {
const { obj, superTheme } = this[_];
return getProp(obj, superTheme, ["color"]);
}
get frozenRowsColor(): ColorPropertyDefine {
const { obj, superTheme } = this[_];
return getProp(obj, superTheme, ["frozenRowsColor"], ["color"]);
}
// background
get defaultBgColor(): ColorPropertyDefine {
const { obj, superTheme } = this[_];
return getProp(obj, superTheme, ["defaultBgColor"]);
}
get frozenRowsBgColor(): ColorPropertyDefine {
const { obj, superTheme } = this[_];
return getProp(obj, superTheme, ["frozenRowsBgColor"], ["defaultBgColor"]);
}
get selectionBgColor(): ColorPropertyDefine {
const { obj, superTheme } = this[_];
return getProp(obj, superTheme, ["selectionBgColor"], ["defaultBgColor"]);
}
get highlightBgColor(): ColorPropertyDefine {
if (this.hasProperty(["highlightBgColor"])) {
const { obj, superTheme } = this[_];
return getProp(obj, superTheme, ["highlightBgColor"]);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return (args: StylePropertyFunctionArg): any => {
const color =
args.row < args.grid.frozenRowCount
? this.frozenRowsBgColor
: this.defaultBgColor;
if (typeof color === "function") {
return color(args);
}
return color;
};
}
// border
get borderColor(): ColorsPropertyDefine {
const { obj, superTheme } = this[_];
return getProp(obj, superTheme, ["borderColor"]);
}
get frozenRowsBorderColor(): ColorsPropertyDefine {
const { obj, superTheme } = this[_];
return getProp(obj, superTheme, ["frozenRowsBorderColor"], ["borderColor"]);
}
get highlightBorderColor(): ColorsPropertyDefine {
const { obj, superTheme } = this[_];
return getProp(obj, superTheme, ["highlightBorderColor"], ["borderColor"]);
}
get checkbox(): RequiredThemeDefine["checkbox"] {
const { obj, superTheme } = this[_];
return (
this._checkbox ||
(this._checkbox = {
get uncheckBgColor(): ColorPropertyDefine {
return getCheckboxProp("uncheckBgColor", ["defaultBgColor"]);
},
get checkBgColor(): ColorPropertyDefine {
return getCheckboxProp(
"checkBgColor",
["borderColor"],
colorsToColor,
"#000"
);
},
get borderColor(): ColorPropertyDefine {
return getCheckboxProp(
"borderColor",
["borderColor"],
colorsToColor,
"#000"
);
},
})
);
function getCheckboxProp(
prop: string,
defNames: string[],
convertForSuper?: (value: never) => ColorPropertyDefine | undefined,
defaultValue?: ColorPropertyDefine
): ColorPropertyDefine {
return getProp(
obj,
superTheme,
["checkbox", prop],
defNames,
convertForSuper,
defaultValue
);
}
}
get radioButton(): RequiredThemeDefine["radioButton"] {
const { obj, superTheme } = this[_];
return (
this._radioButton ||
(this._radioButton = {
get checkColor(): ColorPropertyDefine {
return getRadioButtonProp("checkColor", ["color"]);
},
get uncheckBorderColor(): ColorPropertyDefine {
return getRadioButtonProp(
"uncheckBorderColor",
["borderColor"],
colorsToColor,
"#000"
);
},
get checkBorderColor(): ColorPropertyDefine {
return getRadioButtonProp(
"checkBorderColor",
["borderColor"],
colorsToColor,
"#000"
);
},
get uncheckBgColor(): ColorPropertyDefine {
return getRadioButtonProp("uncheckBgColor", ["defaultBgColor"]);
},
get checkBgColor(): ColorPropertyDefine {
return getRadioButtonProp("checkBgColor", ["defaultBgColor"]);
},
})
);
function getRadioButtonProp(
prop: string,
defNames: string[],
convertForSuper?: (value: never) => ColorPropertyDefine | undefined,
defaultValue?: ColorPropertyDefine
): ColorPropertyDefine {
return getProp(
obj,
superTheme,
["radioButton", prop],
defNames,
convertForSuper,
defaultValue
);
}
}
get button(): RequiredThemeDefine["button"] {
const { obj, superTheme } = this[_];
return (
this._button ||
(this._button = {
get color(): ColorPropertyDefine {
return getButtonProp("color", ["color"]);
},
get bgColor(): ColorPropertyDefine {
return getButtonProp("bgColor", ["defaultBgColor"]);
},
})
);
function getButtonProp(
prop: string,
defNames: string[]
): ColorPropertyDefine {
return getProp(obj, superTheme, ["button", prop], defNames);
}
}
get tree(): RequiredThemeDefine["tree"] {
const { obj, superTheme } = this[_];
return (
this._tree ||
(this._tree = {
get lineStyle(): TreeLineStyle {
return getTreeProp("lineStyle", undefined, undefined, "solid");
},
get lineColor(): ColorPropertyDefine {
return getTreeProp(
"lineColor",
["borderColor"],
colorsToColor,
"#0000"
);
},
get lineWidth(): number {
return getTreeProp("lineWidth", undefined, undefined, 1);
},
get treeIcon(): TreeBranchIconStyleDefine {
return getTreeProp<TreeBranchIconStyleDefine>(
"treeIcon",
undefined,
undefined,
(args) => {
const { hasChildren, nodeType } = getTreeNodeInfoAt(args);
if (hasChildren) {
return "expand_more";
}
return nodeType === "branch" ? "chevron_right" : "none";
}
);
},
})
);
function getTreeProp<
T extends
| ColorPropertyDefine
| number
| TreeLineStyle
| TreeBranchIconStyleDefine
>(
prop: string,
defNames: string[] | undefined,
convertForSuper?: (value: never) => T | undefined,
defaultValue?: T
): T {
return getProp(
obj,
superTheme,
["tree", prop],
defNames,
convertForSuper,
defaultValue
);
}
}
get header(): RequiredThemeDefine["header"] {
const { obj, superTheme } = this[_];
return (
this._header ||
(this._header = {
get sortArrowColor(): ColorPropertyDefine {
return getProp(
obj,
superTheme,
["header", "sortArrowColor"],
["color"]
);
},
})
);
}
get messages(): RequiredThemeDefine["messages"] {
const { obj, superTheme } = this[_];
return (
this._messages ||
(this._messages = {
get infoBgColor(): ColorPropertyDefine {
return getMessageProp("infoBgColor");
},
get errorBgColor(): ColorPropertyDefine {
return getMessageProp("errorBgColor");
},
get warnBgColor(): ColorPropertyDefine {
return getMessageProp("warnBgColor");
},
get boxWidth(): number {
return getMessageProp("boxWidth");
},
get markHeight(): number {
return getMessageProp("markHeight");
},
})
);
function getMessageProp<T extends ColorPropertyDefine | number>(
prop: string
): T {
return getProp(obj, superTheme, ["messages", prop]);
}
}
get indicators(): RequiredThemeDefine["indicators"] {
const { obj, superTheme } = this[_];
return (
this._indicators ||
(this._indicators = {
get topLeftColor(): ColorPropertyDefine {
return getIndicatorsProp(
"topLeftColor",
["borderColor"],
colorsToColor,
"#000"
);
},
get topLeftSize(): number {
return getIndicatorsProp("topLeftSize");
},
get topRightColor(): ColorPropertyDefine {
return getIndicatorsProp(
"topRightColor",
["borderColor"],
colorsToColor,
"#000"
);
},
get topRightSize(): number {
return getIndicatorsProp("topRightSize");
},
get bottomRightColor(): ColorPropertyDefine {
return getIndicatorsProp(
"bottomRightColor",
["borderColor"],
colorsToColor,
"#000"
);
},
get bottomRightSize(): number {
return getIndicatorsProp("bottomRightSize");
},
get bottomLeftColor(): ColorPropertyDefine {
return getIndicatorsProp(
"bottomLeftColor",
["borderColor"],
colorsToColor,
"#000"
);
},
get bottomLeftSize(): number {
return getIndicatorsProp("bottomLeftSize");
},
})
);
function getIndicatorsProp<T extends ColorPropertyDefine | number>(
prop: string,
defNames?: string[],
convertForSuper?: (value: never) => T | undefined,
defaultValue?: T
): T {
return getProp(
obj,
superTheme,
["indicators", prop],
defNames,
convertForSuper,
defaultValue
);
}
}
hasProperty(names: string[]): boolean {
const { obj, superTheme } = this[_];
return hasThemeProperty(obj, names) || hasThemeProperty(superTheme, names);
}
extends(obj: PartialThemeDefine): Theme {
return new Theme(obj, this);
}
}
function hasThemeProperty(obj: PartialThemeDefine, names: string[]): boolean {
if (obj instanceof Theme) {
return obj.hasProperty(names);
} else {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let o: any = obj;
if (!o) {
return false;
}
for (let index = 0; index < names.length; index++) {
const name = names[index];
o = o[name];
if (!o) {
return false;
}
}
return !!o;
}
}
function colorsToColor(
colors: ColorsPropertyDefine
): ColorPropertyDefine | undefined {
if (typeof colors === "function") {
return (arg): string | CanvasGradient | CanvasPattern | undefined => {
const val = colors(arg);
return val ? colorsArrayToColor(val) : val;
};
}
return colorsArrayToColor(colors);
function colorsArrayToColor(
// eslint-disable-next-line @typescript-eslint/ban-types
colors: Exclude<ColorsPropertyDefine, Function>
) {
if (!Array.isArray(colors)) {
return colors;
}
return colors.find(Boolean) || undefined;
}
}