mirror of
https://github.com/konvajs/konva.git
synced 2025-10-08 00:14:23 +08:00
feat: Factory types
This commit is contained in:
115
src/Factory.ts
115
src/Factory.ts
@@ -1,17 +1,75 @@
|
||||
import { Node } from './Node';
|
||||
import { GetSet } from './types';
|
||||
import { Util } from './Util';
|
||||
import { getComponentValidator } from './Validators';
|
||||
|
||||
var GET = 'get',
|
||||
SET = 'set';
|
||||
const GET = 'get';
|
||||
const SET = 'set';
|
||||
|
||||
/**
|
||||
* Enforces that a type is a string.
|
||||
*/
|
||||
type EnforceString<T> = T extends string ? T : never;
|
||||
|
||||
/**
|
||||
* Represents a class.
|
||||
*/
|
||||
type Constructor = abstract new (...args: any) => any;
|
||||
|
||||
/**
|
||||
* An attribute of an instance of the provided class. Attributes names be strings.
|
||||
*/
|
||||
type Attr<T extends Constructor> = EnforceString<keyof InstanceType<T>>;
|
||||
|
||||
/**
|
||||
* A function that is called after a setter is called.
|
||||
*/
|
||||
type AfterFunc<T extends Constructor> = (this: InstanceType<T>) => void;
|
||||
|
||||
/**
|
||||
* Extracts the type of a GetSet.
|
||||
*/
|
||||
type ExtractGetSet<T> = T extends GetSet<infer U, any> ? U : never;
|
||||
|
||||
/**
|
||||
* Extracts the type of a GetSet class attribute.
|
||||
*/
|
||||
type Value<T extends Constructor, U extends Attr<T>> = ExtractGetSet<
|
||||
InstanceType<T>[U]
|
||||
>;
|
||||
|
||||
/**
|
||||
* A function that validates a value.
|
||||
*/
|
||||
type ValidatorFunc<T> = (val: ExtractGetSet<T>, attr: string) => T;
|
||||
|
||||
/**
|
||||
* Extracts the "components" (keys) of a GetSet value. The value must be an object.
|
||||
*/
|
||||
type ExtractComponents<T extends Constructor, U extends Attr<T>> = Value<
|
||||
T,
|
||||
U
|
||||
> extends Record<string, any>
|
||||
? EnforceString<keyof Value<T, U>>[]
|
||||
: never;
|
||||
|
||||
export const Factory = {
|
||||
addGetterSetter(constructor, attr, def?, validator?, after?) {
|
||||
addGetterSetter<T extends Constructor, U extends Attr<T>>(
|
||||
constructor: T,
|
||||
attr: U,
|
||||
def?: Value<T, U>,
|
||||
validator?: ValidatorFunc<Value<T, U>>,
|
||||
after?: AfterFunc<T>
|
||||
): void {
|
||||
Factory.addGetter(constructor, attr, def);
|
||||
Factory.addSetter(constructor, attr, validator, after);
|
||||
Factory.addOverloadedGetterSetter(constructor, attr);
|
||||
},
|
||||
addGetter(constructor, attr, def?) {
|
||||
addGetter<T extends Constructor, U extends Attr<T>>(
|
||||
constructor: T,
|
||||
attr: U,
|
||||
def?: Value<T, U>
|
||||
) {
|
||||
var method = GET + Util._capitalize(attr);
|
||||
|
||||
constructor.prototype[method] =
|
||||
@@ -22,14 +80,25 @@ export const Factory = {
|
||||
};
|
||||
},
|
||||
|
||||
addSetter(constructor, attr, validator?, after?) {
|
||||
addSetter<T extends Constructor, U extends Attr<T>>(
|
||||
constructor: T,
|
||||
attr: U,
|
||||
validator?: ValidatorFunc<Value<T, U>>,
|
||||
after?: AfterFunc<T>
|
||||
) {
|
||||
var method = SET + Util._capitalize(attr);
|
||||
|
||||
if (!constructor.prototype[method]) {
|
||||
Factory.overWriteSetter(constructor, attr, validator, after);
|
||||
}
|
||||
},
|
||||
overWriteSetter(constructor, attr, validator?, after?) {
|
||||
|
||||
overWriteSetter<T extends Constructor, U extends Attr<T>>(
|
||||
constructor: T,
|
||||
attr: U,
|
||||
validator?: ValidatorFunc<Value<T, U>>,
|
||||
after?: AfterFunc<T>
|
||||
) {
|
||||
var method = SET + Util._capitalize(attr);
|
||||
constructor.prototype[method] = function (val) {
|
||||
if (validator && val !== undefined && val !== null) {
|
||||
@@ -45,12 +114,13 @@ export const Factory = {
|
||||
return this;
|
||||
};
|
||||
},
|
||||
addComponentsGetterSetter(
|
||||
constructor,
|
||||
attr: string,
|
||||
components: Array<string>,
|
||||
validator?: Function,
|
||||
after?: Function
|
||||
|
||||
addComponentsGetterSetter<T extends Constructor, U extends Attr<T>>(
|
||||
constructor: T,
|
||||
attr: U,
|
||||
components: ExtractComponents<T, U>,
|
||||
validator?: ValidatorFunc<Value<T, U>>,
|
||||
after?: AfterFunc<T>
|
||||
) {
|
||||
var len = components.length,
|
||||
capitalize = Util._capitalize,
|
||||
@@ -79,7 +149,7 @@ export const Factory = {
|
||||
key;
|
||||
|
||||
if (validator) {
|
||||
val = validator.call(this, val);
|
||||
val = validator.call(this, val, attr);
|
||||
}
|
||||
|
||||
if (basicValidator) {
|
||||
@@ -109,7 +179,10 @@ export const Factory = {
|
||||
|
||||
Factory.addOverloadedGetterSetter(constructor, attr);
|
||||
},
|
||||
addOverloadedGetterSetter(constructor, attr) {
|
||||
addOverloadedGetterSetter<T extends Constructor, U extends Attr<T>>(
|
||||
constructor: T,
|
||||
attr: U
|
||||
) {
|
||||
var capitalizedAttr = Util._capitalize(attr),
|
||||
setter = SET + capitalizedAttr,
|
||||
getter = GET + capitalizedAttr;
|
||||
@@ -124,7 +197,12 @@ export const Factory = {
|
||||
return this[getter]();
|
||||
};
|
||||
},
|
||||
addDeprecatedGetterSetter(constructor, attr, def, validator) {
|
||||
addDeprecatedGetterSetter<T extends Constructor, U extends Attr<T>>(
|
||||
constructor: T,
|
||||
attr: U,
|
||||
def: Value<T, U>,
|
||||
validator: ValidatorFunc<Value<T, U>>
|
||||
) {
|
||||
Util.error('Adding deprecated ' + attr);
|
||||
|
||||
var method = GET + Util._capitalize(attr);
|
||||
@@ -142,7 +220,10 @@ export const Factory = {
|
||||
});
|
||||
Factory.addOverloadedGetterSetter(constructor, attr);
|
||||
},
|
||||
backCompat(constructor, methods) {
|
||||
backCompat<T extends Constructor>(
|
||||
constructor: T,
|
||||
methods: Record<string, string>
|
||||
) {
|
||||
Util.each(methods, function (oldMethodName, newMethodName) {
|
||||
var method = constructor.prototype[newMethodName];
|
||||
var oldGetter = GET + Util._capitalize(oldMethodName);
|
||||
@@ -164,7 +245,7 @@ export const Factory = {
|
||||
constructor.prototype[oldSetter] = deprecated;
|
||||
});
|
||||
},
|
||||
afterSetFilter(this: Node) {
|
||||
afterSetFilter(this: Node): void {
|
||||
this._filterUpToDate = false;
|
||||
},
|
||||
};
|
||||
|
@@ -2660,7 +2660,7 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
|
||||
rotation: GetSet<number, this>;
|
||||
zIndex: GetSet<number, this>;
|
||||
|
||||
scale: GetSet<Vector2d | undefined, this>;
|
||||
scale: GetSet<Vector2d, this>;
|
||||
scaleX: GetSet<number, this>;
|
||||
scaleY: GetSet<number, this>;
|
||||
skew: GetSet<Vector2d, this>;
|
||||
@@ -3102,7 +3102,7 @@ addGetterSetter(Node, 'offsetY', 0, getNumberValidator());
|
||||
* node.offsetY(3);
|
||||
*/
|
||||
|
||||
addGetterSetter(Node, 'dragDistance', null, getNumberValidator());
|
||||
addGetterSetter(Node, 'dragDistance', undefined, getNumberValidator());
|
||||
|
||||
/**
|
||||
* get/set drag distance
|
||||
@@ -3193,7 +3193,7 @@ addGetterSetter(Node, 'listening', true, getBooleanValidator());
|
||||
|
||||
addGetterSetter(Node, 'preventDefault', true, getBooleanValidator());
|
||||
|
||||
addGetterSetter(Node, 'filters', null, function (this: Node, val) {
|
||||
addGetterSetter(Node, 'filters', undefined, function (this: Node, val) {
|
||||
this._filterUpToDate = false;
|
||||
return val;
|
||||
});
|
||||
|
@@ -843,6 +843,11 @@ export class Shape<
|
||||
strokeLinearGradientStartPoint: GetSet<Vector2d, this>;
|
||||
strokeLinearGradientEndPoint: GetSet<Vector2d, this>;
|
||||
strokeLinearGradientColorStops: GetSet<Array<number | string>, this>;
|
||||
strokeLinearGradientStartPointX: GetSet<number, this>;
|
||||
strokeLinearGradientStartPointY: GetSet<number, this>;
|
||||
strokeLinearGradientEndPointX: GetSet<number, this>;
|
||||
strokeLinearGradientEndPointY: GetSet<number, this>;
|
||||
fillRule: GetSet<CanvasFillRule, this>;
|
||||
}
|
||||
|
||||
Shape.prototype._fillFunc = _fillFunc;
|
||||
|
@@ -33,9 +33,9 @@ export function alphaComponent(val: number) {
|
||||
return val;
|
||||
}
|
||||
|
||||
export function getNumberValidator() {
|
||||
export function getNumberValidator<T>() {
|
||||
if (Konva.isUnminified) {
|
||||
return function <T>(val: T, attr: string): T | void {
|
||||
return function (val: T, attr: string): T {
|
||||
if (!Util._isNumber(val)) {
|
||||
Util.warn(
|
||||
_formatValue(val) +
|
||||
@@ -49,9 +49,9 @@ export function getNumberValidator() {
|
||||
}
|
||||
}
|
||||
|
||||
export function getNumberOrArrayOfNumbersValidator(noOfElements: number) {
|
||||
export function getNumberOrArrayOfNumbersValidator<T>(noOfElements: number) {
|
||||
if (Konva.isUnminified) {
|
||||
return function <T>(val: T, attr: string): T | void {
|
||||
return function (val: T, attr: string): T {
|
||||
let isNumber = Util._isNumber(val);
|
||||
let isValidArray = Util._isArray(val) && val.length == noOfElements;
|
||||
if (!isNumber && !isValidArray) {
|
||||
@@ -69,9 +69,9 @@ export function getNumberOrArrayOfNumbersValidator(noOfElements: number) {
|
||||
}
|
||||
}
|
||||
|
||||
export function getNumberOrAutoValidator() {
|
||||
export function getNumberOrAutoValidator<T>() {
|
||||
if (Konva.isUnminified) {
|
||||
return function <T extends string>(val: T, attr: string): T | void {
|
||||
return function (val: T, attr: string): T {
|
||||
var isNumber = Util._isNumber(val);
|
||||
var isAuto = val === 'auto';
|
||||
|
||||
@@ -88,9 +88,9 @@ export function getNumberOrAutoValidator() {
|
||||
}
|
||||
}
|
||||
|
||||
export function getStringValidator() {
|
||||
export function getStringValidator<T>() {
|
||||
if (Konva.isUnminified) {
|
||||
return function (val: any, attr: string) {
|
||||
return function (val: T, attr: string): T {
|
||||
if (!Util._isString(val)) {
|
||||
Util.warn(
|
||||
_formatValue(val) +
|
||||
@@ -104,13 +104,13 @@ export function getStringValidator() {
|
||||
}
|
||||
}
|
||||
|
||||
export function getStringOrGradientValidator() {
|
||||
export function getStringOrGradientValidator<T>() {
|
||||
if (Konva.isUnminified) {
|
||||
return function (val: any, attr: string) {
|
||||
return function (val: T, attr: string): T {
|
||||
const isString = Util._isString(val);
|
||||
const isGradient =
|
||||
Object.prototype.toString.call(val) === '[object CanvasGradient]' ||
|
||||
(val && val.addColorStop);
|
||||
(val && val['addColorStop']);
|
||||
if (!(isString || isGradient)) {
|
||||
Util.warn(
|
||||
_formatValue(val) +
|
||||
@@ -124,9 +124,9 @@ export function getStringOrGradientValidator() {
|
||||
}
|
||||
}
|
||||
|
||||
export function getFunctionValidator() {
|
||||
export function getFunctionValidator<T>() {
|
||||
if (Konva.isUnminified) {
|
||||
return function (val: any, attr: string) {
|
||||
return function (val: T, attr: string): T {
|
||||
if (!Util._isFunction(val)) {
|
||||
Util.warn(
|
||||
_formatValue(val) +
|
||||
@@ -139,9 +139,9 @@ export function getFunctionValidator() {
|
||||
};
|
||||
}
|
||||
}
|
||||
export function getNumberArrayValidator() {
|
||||
export function getNumberArrayValidator<T>() {
|
||||
if (Konva.isUnminified) {
|
||||
return function (val: any, attr: string) {
|
||||
return function (val: T, attr: string): T {
|
||||
// Retrieve TypedArray constructor as found in MDN (if TypedArray is available)
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray#description
|
||||
const TypedArray = Int8Array ? Object.getPrototypeOf(Int8Array) : null;
|
||||
@@ -172,9 +172,9 @@ export function getNumberArrayValidator() {
|
||||
};
|
||||
}
|
||||
}
|
||||
export function getBooleanValidator() {
|
||||
export function getBooleanValidator<T>() {
|
||||
if (Konva.isUnminified) {
|
||||
return function (val: any, attr: string) {
|
||||
return function (val: T, attr: string): T {
|
||||
var isBool = val === true || val === false;
|
||||
if (!isBool) {
|
||||
Util.warn(
|
||||
@@ -188,9 +188,9 @@ export function getBooleanValidator() {
|
||||
};
|
||||
}
|
||||
}
|
||||
export function getComponentValidator(components: any) {
|
||||
export function getComponentValidator<T>(components: string[]) {
|
||||
if (Konva.isUnminified) {
|
||||
return function (val: any, attr: string) {
|
||||
return function (val: T, attr: string): T {
|
||||
// ignore validation on undefined value, because it will reset to defalt
|
||||
if (val === undefined || val === null) {
|
||||
return val;
|
||||
|
@@ -174,7 +174,7 @@ Factory.addGetterSetter(
|
||||
Node,
|
||||
'embossDirection',
|
||||
'top-left',
|
||||
null,
|
||||
undefined,
|
||||
Factory.afterSetFilter
|
||||
);
|
||||
/**
|
||||
@@ -190,7 +190,7 @@ Factory.addGetterSetter(
|
||||
Node,
|
||||
'embossBlend',
|
||||
false,
|
||||
null,
|
||||
undefined,
|
||||
Factory.afterSetFilter
|
||||
);
|
||||
/**
|
||||
|
@@ -317,7 +317,10 @@ export class Tag extends Shape<TagConfig> {
|
||||
};
|
||||
}
|
||||
|
||||
pointerDirection: GetSet<'left' | 'top' | 'right' | 'bottom', this>;
|
||||
pointerDirection: GetSet<
|
||||
'left' | 'top' | 'right' | 'bottom' | typeof NONE,
|
||||
this
|
||||
>;
|
||||
pointerWidth: GetSet<number, this>;
|
||||
pointerHeight: GetSet<number, this>;
|
||||
cornerRadius: GetSet<number, this>;
|
||||
|
@@ -551,7 +551,7 @@ Factory.addGetterSetter(TextPath, 'text', EMPTY_STRING);
|
||||
* // underline text
|
||||
* shape.textDecoration('underline');
|
||||
*/
|
||||
Factory.addGetterSetter(TextPath, 'textDecoration', null);
|
||||
Factory.addGetterSetter(TextPath, 'textDecoration', undefined);
|
||||
|
||||
/**
|
||||
* get/set kerning function.
|
||||
@@ -568,4 +568,4 @@ Factory.addGetterSetter(TextPath, 'textDecoration', null);
|
||||
* return 1;
|
||||
* });
|
||||
*/
|
||||
Factory.addGetterSetter(TextPath, 'kerningFunc', null);
|
||||
Factory.addGetterSetter(TextPath, 'kerningFunc', undefined);
|
||||
|
@@ -1745,8 +1745,6 @@ Factory.addGetterSetter(Transformer, 'ignoreStroke', false);
|
||||
*/
|
||||
Factory.addGetterSetter(Transformer, 'padding', 0, getNumberValidator());
|
||||
|
||||
Factory.addGetterSetter(Transformer, 'node');
|
||||
|
||||
/**
|
||||
* get/set attached nodes of the Transformer. Transformer will adapt to their size and listen to their events
|
||||
* @method
|
||||
|
Reference in New Issue
Block a user