diff --git a/package.json b/package.json index d04c19d7..faa5bcba 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "name": "konva", "version": "9.3.16", + "description": "HTML5 2d canvas library.", "author": "Anton Lavrenov", "files": [ "README.md", @@ -59,13 +60,13 @@ } ], "devDependencies": { - "@parcel/transformer-image": "2.10.1", - "@size-limit/preset-big-lib": "^11.0.1", - "@types/mocha": "^10.0.6", + "@parcel/transformer-image": "2.13.2", + "@size-limit/preset-big-lib": "^11.1.6", + "@types/mocha": "^10.0.10", "canvas": "^2.11.2", - "chai": "4.3.10", + "chai": "5.1.2", "filehound": "^1.17.6", - "gulp": "^4.0.2", + "gulp": "^5.0.0", "gulp-concat": "^2.6.1", "gulp-connect": "^5.7.0", "gulp-exec": "^5.0.0", @@ -78,14 +79,14 @@ "gulp-util": "^3.0.8", "mocha": "10.2.0", "mocha-headless-chrome": "^4.0.0", - "parcel": "2.10.1", + "parcel": "2.13.2", "process": "^0.11.10", - "rollup": "^4.9.1", + "rollup": "^4.28.1", "rollup-plugin-typescript2": "^0.36.0", - "size-limit": "^11.0.1", + "size-limit": "^11.1.6", "ts-mocha": "^10.0.0", "ts-node": "^10.9.2", - "typescript": "^5.3.3" + "typescript": "^5.7.2" }, "keywords": [ "canvas", diff --git a/src/Factory.ts b/src/Factory.ts index e86117b3..b1af978d 100644 --- a/src/Factory.ts +++ b/src/Factory.ts @@ -1,18 +1,76 @@ import { Node } from './Node'; +import { GetSet } from './types'; import { Util } from './Util'; import { getComponentValidator } from './Validators'; -const GET = 'get', - SET = 'set'; +const GET = 'get'; +const SET = 'set'; + +/** + * Enforces that a type is a string. + */ +type EnforceString = 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 = EnforceString>; + +/** + * A function that is called after a setter is called. + */ +type AfterFunc = (this: InstanceType) => void; + +/** + * Extracts the type of a GetSet. + */ +type ExtractGetSet = T extends GetSet ? U : never; + +/** + * Extracts the type of a GetSet class attribute. + */ +type Value> = ExtractGetSet< + InstanceType[U] +>; + +/** + * A function that validates a value. + */ +type ValidatorFunc = (val: ExtractGetSet, attr: string) => T; + +/** + * Extracts the "components" (keys) of a GetSet value. The value must be an object. + */ +type ExtractComponents> = Value< + T, + U +> extends Record + ? EnforceString>[] + : never; export const Factory = { - addGetterSetter(constructor, attr, def?, validator?, after?) { + addGetterSetter>( + constructor: T, + attr: U, + def?: Value, + validator?: ValidatorFunc>, + after?: AfterFunc + ): void { Factory.addGetter(constructor, attr, def); Factory.addSetter(constructor, attr, validator, after); Factory.addOverloadedGetterSetter(constructor, attr); }, - addGetter(constructor, attr, def?) { - const method = GET + Util._capitalize(attr); + addGetter>( + constructor: T, + attr: U, + def?: Value + ) { + var method = GET + Util._capitalize(attr); constructor.prototype[method] = constructor.prototype[method] || @@ -22,15 +80,26 @@ export const Factory = { }; }, - addSetter(constructor, attr, validator?, after?) { - const method = SET + Util._capitalize(attr); + addSetter>( + constructor: T, + attr: U, + validator?: ValidatorFunc>, + after?: AfterFunc + ) { + var method = SET + Util._capitalize(attr); if (!constructor.prototype[method]) { Factory.overWriteSetter(constructor, attr, validator, after); } }, - overWriteSetter(constructor, attr, validator?, after?) { - const method = SET + Util._capitalize(attr); + + overWriteSetter>( + constructor: T, + attr: U, + validator?: ValidatorFunc>, + after?: AfterFunc + ) { + var method = SET + Util._capitalize(attr); constructor.prototype[method] = function (val) { if (validator && val !== undefined && val !== null) { val = validator.call(this, val, attr); @@ -45,12 +114,13 @@ export const Factory = { return this; }; }, - addComponentsGetterSetter( - constructor, - attr: string, - components: Array, - validator?: Function, - after?: Function + + addComponentsGetterSetter>( + constructor: T, + attr: U, + components: ExtractComponents, + validator?: ValidatorFunc>, + after?: AfterFunc ) { const len = components.length, capitalize = Util._capitalize, @@ -59,7 +129,7 @@ export const Factory = { // getter constructor.prototype[getter] = function () { - const ret = {}; + const ret: Record = {}; for (let n = 0; n < len; n++) { const component = components[n]; @@ -76,7 +146,7 @@ export const Factory = { const oldVal = this.attrs[attr]; if (validator) { - val = validator.call(this, val); + val = validator.call(this, val, attr); } if (basicValidator) { @@ -106,8 +176,11 @@ export const Factory = { Factory.addOverloadedGetterSetter(constructor, attr); }, - addOverloadedGetterSetter(constructor, attr) { - const capitalizedAttr = Util._capitalize(attr), + addOverloadedGetterSetter>( + constructor: T, + attr: U + ) { + var capitalizedAttr = Util._capitalize(attr), setter = SET + capitalizedAttr, getter = GET + capitalizedAttr; @@ -121,7 +194,12 @@ export const Factory = { return this[getter](); }; }, - addDeprecatedGetterSetter(constructor, attr, def, validator) { + addDeprecatedGetterSetter>( + constructor: T, + attr: U, + def: Value, + validator: ValidatorFunc> + ) { Util.error('Adding deprecated ' + attr); const method = GET + Util._capitalize(attr); @@ -139,7 +217,10 @@ export const Factory = { }); Factory.addOverloadedGetterSetter(constructor, attr); }, - backCompat(constructor, methods) { + backCompat( + constructor: T, + methods: Record + ) { Util.each(methods, function (oldMethodName, newMethodName) { const method = constructor.prototype[newMethodName]; const oldGetter = GET + Util._capitalize(oldMethodName); @@ -161,7 +242,7 @@ export const Factory = { constructor.prototype[oldSetter] = deprecated; }); }, - afterSetFilter(this: Node) { + afterSetFilter(this: Node): void { this._filterUpToDate = false; }, }; diff --git a/src/Node.ts b/src/Node.ts index a23ad397..d31723ff 100644 --- a/src/Node.ts +++ b/src/Node.ts @@ -2660,7 +2660,7 @@ export abstract class Node { rotation: GetSet; zIndex: GetSet; - scale: GetSet; + scale: GetSet; scaleX: GetSet; scaleY: GetSet; skew: GetSet; @@ -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; }); diff --git a/src/Shape.ts b/src/Shape.ts index aec9d064..70305ec2 100644 --- a/src/Shape.ts +++ b/src/Shape.ts @@ -837,6 +837,11 @@ export class Shape< strokeLinearGradientStartPoint: GetSet; strokeLinearGradientEndPoint: GetSet; strokeLinearGradientColorStops: GetSet, this>; + strokeLinearGradientStartPointX: GetSet; + strokeLinearGradientStartPointY: GetSet; + strokeLinearGradientEndPointX: GetSet; + strokeLinearGradientEndPointY: GetSet; + fillRule: GetSet; } Shape.prototype._fillFunc = _fillFunc; diff --git a/src/Validators.ts b/src/Validators.ts index 023e0d90..a8534b3b 100644 --- a/src/Validators.ts +++ b/src/Validators.ts @@ -33,9 +33,9 @@ export function alphaComponent(val: number) { return val; } -export function getNumberValidator() { +export function getNumberValidator() { if (Konva.isUnminified) { - return function (val: T, attr: string): T | void { + return function (val: T, attr: string): T { if (!Util._isNumber(val)) { Util.warn( _formatValue(val) + @@ -49,11 +49,11 @@ export function getNumberValidator() { } } -export function getNumberOrArrayOfNumbersValidator(noOfElements: number) { +export function getNumberOrArrayOfNumbersValidator(noOfElements: number) { if (Konva.isUnminified) { - return function (val: T, attr: string): T | void { - const isNumber = Util._isNumber(val); - const isValidArray = Util._isArray(val) && val.length == noOfElements; + return function (val: T, attr: string): T { + let isNumber = Util._isNumber(val); + let isValidArray = Util._isArray(val) && val.length == noOfElements; if (!isNumber && !isValidArray) { Util.warn( _formatValue(val) + @@ -69,11 +69,11 @@ export function getNumberOrArrayOfNumbersValidator(noOfElements: number) { } } -export function getNumberOrAutoValidator() { +export function getNumberOrAutoValidator() { if (Konva.isUnminified) { - return function (val: T, attr: string): T | void { - const isNumber = Util._isNumber(val); - const isAuto = val === 'auto'; + return function (val: T, attr: string): T { + var isNumber = Util._isNumber(val); + var isAuto = val === 'auto'; if (!(isNumber || isAuto)) { Util.warn( @@ -88,9 +88,9 @@ export function getNumberOrAutoValidator() { } } -export function getStringValidator() { +export function getStringValidator() { 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() { 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() { 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() { 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,10 +172,10 @@ export function getNumberArrayValidator() { }; } } -export function getBooleanValidator() { +export function getBooleanValidator() { if (Konva.isUnminified) { - return function (val: any, attr: string) { - const isBool = val === true || val === false; + return function (val: T, attr: string): T { + var isBool = val === true || val === false; if (!isBool) { Util.warn( _formatValue(val) + @@ -188,9 +188,9 @@ export function getBooleanValidator() { }; } } -export function getComponentValidator(components: any) { +export function getComponentValidator(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; diff --git a/src/filters/Emboss.ts b/src/filters/Emboss.ts index cbeacd3c..a040cc8f 100644 --- a/src/filters/Emboss.ts +++ b/src/filters/Emboss.ts @@ -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 ); /** diff --git a/src/shapes/Label.ts b/src/shapes/Label.ts index a1e9888a..be15df8c 100644 --- a/src/shapes/Label.ts +++ b/src/shapes/Label.ts @@ -317,7 +317,10 @@ export class Tag extends Shape { }; } - pointerDirection: GetSet<'left' | 'top' | 'right' | 'bottom' | 'up' | 'down', this>; + pointerDirection: GetSet< + 'left' | 'up' | 'right' | 'down' | typeof NONE, + this + >; pointerWidth: GetSet; pointerHeight: GetSet; cornerRadius: GetSet; diff --git a/src/shapes/TextPath.ts b/src/shapes/TextPath.ts index 6912fe55..1ae77462 100644 --- a/src/shapes/TextPath.ts +++ b/src/shapes/TextPath.ts @@ -551,7 +551,7 @@ Factory.addGetterSetter(TextPath, 'text', EMPTY_STRING); * // underline text * shape.textDecoration('underline'); */ -Factory.addGetterSetter(TextPath, 'textDecoration', null); +Factory.addGetterSetter(TextPath, 'textDecoration', ''); /** * 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); diff --git a/src/shapes/Transformer.ts b/src/shapes/Transformer.ts index d5c6bd0e..3c254a51 100644 --- a/src/shapes/Transformer.ts +++ b/src/shapes/Transformer.ts @@ -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 @@ -1767,6 +1765,9 @@ Factory.addGetterSetter(Transformer, 'node'); */ Factory.addGetterSetter(Transformer, 'nodes'); +// @ts-ignore +// deprecated +Factory.addGetterSetter(Transformer, 'node'); /** * get/set bounding box function. **IMPORTANT!** boundBondFunc operates in absolute coordinates.