diff --git a/packages/devextreme/js/__internal/common/core/animation/m_position.ts b/packages/devextreme/js/__internal/common/core/animation/m_position.ts
index e26067fe4d54..d7c64787b549 100644
--- a/packages/devextreme/js/__internal/common/core/animation/m_position.ts
+++ b/packages/devextreme/js/__internal/common/core/animation/m_position.ts
@@ -1,6 +1,7 @@
import { move, resetPosition } from '@js/common/core/animation/translator';
import devices from '@js/core/devices';
import domAdapter from '@js/core/dom_adapter';
+import type { Coordinates, dxElementWrapper } from '@js/core/renderer';
import $ from '@js/core/renderer';
import { extend } from '@js/core/utils/extend';
import { each } from '@js/core/utils/iterator';
@@ -14,6 +15,15 @@ import { isDefined, isWindow } from '@js/core/utils/type';
import { getWindow } from '@js/core/utils/window';
import { pairToObject, splitPair } from '@ts/core/utils/common';
+import type {
+ AxisBounds,
+ AxisPositionData,
+ CollisionSide,
+ PositionOptions,
+ PositionResult,
+ PositionTarget,
+} from './types';
+
const window = getWindow();
const horzRe = /left|right/;
@@ -21,7 +31,7 @@ const vertRe = /top|bottom/;
const collisionRe = /fit|flip|none/;
const scaleRe = /scale\(.+?\)/;
-const normalizeAlign = function (raw) {
+const normalizeAlign = function normalizeAlign(raw: unknown): { h: string; v: string } {
const result = {
h: 'center',
v: 'center',
@@ -30,7 +40,7 @@ const normalizeAlign = function (raw) {
const pair = splitPair(raw);
if (pair) {
- each(pair, function () {
+ each(pair, function normalizeAlignPart(this: unknown) {
const w = String(this).toLowerCase();
if (horzRe.test(w)) {
result.h = w;
@@ -43,11 +53,14 @@ const normalizeAlign = function (raw) {
return result;
};
-const normalizeOffset = function (raw, preventRound) {
+const normalizeOffset = function normalizeOffset(
+ raw: unknown,
+ preventRound?: boolean,
+): { h: number; v: number } {
return pairToObject(raw, preventRound);
};
-const normalizeCollision = function (raw) {
+const normalizeCollision = function normalizeCollision(raw: unknown): { h: string; v: string } {
const pair = splitPair(raw);
let h = String(pair && pair[0]).toLowerCase();
let v = String(pair && pair[1]).toLowerCase();
@@ -59,10 +72,10 @@ const normalizeCollision = function (raw) {
v = h;
}
- return { h: h, v: v };
+ return { h, v };
};
-const getAlignFactor = function (align) {
+const getAlignFactor = function getAlignFactor(align: string): number {
switch (align) {
case 'center':
return 0.5;
@@ -74,7 +87,7 @@ const getAlignFactor = function (align) {
}
};
-const inverseAlign = function (align) {
+const inverseAlign = function inverseAlign(align: string): string {
switch (align) {
case 'left':
return 'right';
@@ -89,7 +102,10 @@ const inverseAlign = function (align) {
}
};
-const calculateOversize = function (data, bounds) {
+const calculateOversize = function calculateOversize(
+ data: AxisPositionData,
+ bounds: AxisBounds,
+): number {
let oversize = 0;
if (data.myLocation < bounds.min) {
@@ -103,7 +119,11 @@ const calculateOversize = function (data, bounds) {
return oversize;
};
-const collisionSide = function (direction, data, bounds) {
+const collisionSide = function collisionSide(
+ direction: 'h' | 'v',
+ data: AxisPositionData,
+ bounds: AxisBounds,
+): CollisionSide {
if (data.myLocation < bounds.min) {
return direction === 'h' ? 'left' : 'top';
}
@@ -114,16 +134,24 @@ const collisionSide = function (direction, data, bounds) {
};
// TODO: rename?
-const initMyLocation = function (data) {
+const initMyLocation = function initMyLocation(data: AxisPositionData): void {
data.myLocation = data.atLocation
+ getAlignFactor(data.atAlign) * data.atSize
- getAlignFactor(data.myAlign) * data.mySize
+ data.offset;
};
-const collisionResolvers = {
+interface CollisionResolvers {
+ fit: (data: AxisPositionData, bounds: AxisBounds) => void;
+ flip: (data: AxisPositionData, bounds: AxisBounds) => void;
+ // eslint-disable-next-line spellcheck/spell-checker
+ flipfit: (data: AxisPositionData, bounds: AxisBounds) => void;
+ none: (data: AxisPositionData) => void;
+}
- fit: function (data, bounds) {
+const collisionResolvers: CollisionResolvers = {
+
+ fit(data, bounds) {
let result = false;
if (data.myLocation > bounds.max) {
data.myLocation = bounds.max;
@@ -137,7 +165,7 @@ const collisionResolvers = {
data.fit = result;
},
- flip: function (data, bounds) {
+ flip(data, bounds) {
data.flip = false;
if (data.myAlign === 'center' && data.atAlign === 'center') {
@@ -154,7 +182,10 @@ const collisionResolvers = {
initMyLocation(inverseData);
inverseData.oversize = calculateOversize(inverseData, bounds);
- if ((inverseData.myLocation >= bounds.min && inverseData.myLocation <= bounds.max) || data.oversize > inverseData.oversize) {
+ if (
+ (inverseData.myLocation >= bounds.min && inverseData.myLocation <= bounds.max)
+ || data.oversize > inverseData.oversize
+ ) {
data.myLocation = inverseData.myLocation;
data.oversize = inverseData.oversize;
data.flip = true;
@@ -163,19 +194,20 @@ const collisionResolvers = {
},
// eslint-disable-next-line spellcheck/spell-checker
- flipfit: function (data, bounds) {
+ flipfit(data, bounds) {
this.flip(data, bounds);
this.fit(data, bounds);
},
- none: function (data) {
+ none(data) {
data.oversize = 0;
},
};
-let scrollbarWidth;
+// eslint-disable-next-line @typescript-eslint/init-declarations -- set by calculateScrollbarWidth
+let scrollbarWidth: number | undefined;
-const calculateScrollbarWidth = function () {
+const calculateScrollbarWidth = function calculateScrollbarWidth(): void {
const $scrollDiv = $('
').css({
width: 100,
height: 100,
@@ -183,7 +215,7 @@ const calculateScrollbarWidth = function () {
position: 'absolute',
top: -9999,
}).appendTo($('body'));
- // @ts-expect-error
+ // @ts-expect-error get(0) is typed as Element
const result = $scrollDiv.get(0).offsetWidth - $scrollDiv.get(0).clientWidth;
$scrollDiv.remove();
@@ -206,27 +238,63 @@ const defaultPositionResult = {
},
};
-interface AxisPositionResult {
- location: number;
- flip: boolean;
- fit: boolean;
- oversize: number;
- collisionSide?: string;
-}
+// NOTE: Setting the 'element.style' requires creating attributeNode when both of the conditions
+// met:
+// - a form contains an input with the name property set to "style";
+// - a form contains a dx-validator (or other popup widget).
+// T941581
+const setScaleProperty = function setScaleProperty(
+ element: Element & { style?: unknown },
+ scale: string,
+ styleAttr: string,
+ isEmpty: boolean,
+): void {
+ const stylePropIsValid = isDefined(element.style) && !domAdapter.isNode(element.style);
+ const newStyleValue = isEmpty ? styleAttr.replace(scale, '') : styleAttr;
-interface PositionResult {
- h: AxisPositionResult;
- v: AxisPositionResult;
- precise?: boolean;
-}
+ if (stylePropIsValid) {
+ setStyle(element, newStyleValue, false);
+ } else {
+ const styleAttributeNode = domAdapter.createAttribute('style');
+ styleAttributeNode.value = newStyleValue;
+ element.setAttributeNode(styleAttributeNode);
+ }
+};
+
+const getOffsetWithoutScale = function getOffsetWithoutScale(
+ $startElement: dxElementWrapper,
+ $currentElement: dxElementWrapper = $startElement,
+): Coordinates | undefined {
+ const currentElement = $currentElement.get(0);
+ if (!currentElement) {
+ return $startElement.offset();
+ }
+
+ const style = currentElement.getAttribute?.('style') ?? '';
+ const scale = scaleRe.exec(style)?.[0];
+ // eslint-disable-next-line @typescript-eslint/init-declarations -- set in both branches
+ let offset: Coordinates | undefined;
+
+ if (scale) {
+ setScaleProperty(currentElement, scale, style, true);
+ offset = getOffsetWithoutScale($startElement, $currentElement.parent());
+ setScaleProperty(currentElement, scale, style, false);
+ } else {
+ offset = getOffsetWithoutScale($startElement, $currentElement.parent());
+ }
+
+ return offset;
+};
-const calculatePosition = function (what, options) {
+const calculatePosition = function calculatePosition(
+ what: PositionTarget,
+ options?: PositionOptions,
+): PositionResult {
const $what = $(what);
- const currentOffset = $what.offset();
+ // @ts-expect-error offset() is typed as possibly undefined
+ const currentOffset: Coordinates = $what.offset();
const result: PositionResult = extend(true, {}, defaultPositionResult, {
- // @ts-expect-error
h: { location: currentOffset.left },
- // @ts-expect-error
v: { location: currentOffset.top },
});
@@ -236,13 +304,16 @@ const calculatePosition = function (what, options) {
const my = normalizeAlign(options.my);
const at = normalizeAlign(options.at);
- let of = ($(options.of).length && options.of) || window;
+ // @ts-expect-error renderer() is typed without event objects
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- element, selector, window, event
+ let of: any = ($(options.of).length && options.of) || window;
const offset = normalizeOffset(options.offset, options.precise);
const collision = normalizeCollision(options.collision);
const { boundary } = options;
const boundaryOffset = normalizeOffset(options.boundaryOffset, options.precise);
- const h: any = {
+ const h: AxisPositionData = {
+ // @ts-expect-error getOuterWidth() can be undefined; the location fields are set below
mySize: getOuterWidth($what),
myAlign: my.h,
atAlign: at.h,
@@ -251,7 +322,8 @@ const calculatePosition = function (what, options) {
boundaryOffset: boundaryOffset.h,
};
- const v: any = {
+ const v: AxisPositionData = {
+ // @ts-expect-error getOuterHeight() can be undefined; the location fields are set below
mySize: getOuterHeight($what),
myAlign: my.v,
atAlign: at.v,
@@ -290,7 +362,8 @@ const calculatePosition = function (what, options) {
v.atSize = getHeight(of);
} else {
const ofRect = getBoundingRect(of.get(0));
- const o = getOffsetWithoutScale(of);
+ // @ts-expect-error offset() is typed as possibly undefined
+ const o: Coordinates = getOffsetWithoutScale(of);
h.atLocation = o.left;
v.atLocation = o.top;
h.atSize = Math.max(ofRect.width, getOuterWidth(of));
@@ -301,12 +374,14 @@ const calculatePosition = function (what, options) {
initMyLocation(h);
initMyLocation(v);
- const bounds = (function () {
+ const bounds = (function calculateBounds(): { h: AxisBounds; v: AxisBounds } {
const win = $(window);
const windowWidth = getWidth(win.get(0));
const windowHeight = getHeight(win.get(0));
- let left = win.scrollLeft();
- let top = win.scrollTop();
+ // @ts-expect-error scrollLeft() is typed as a setter only
+ let left: number = win.scrollLeft();
+ // @ts-expect-error scrollTop() is typed as a setter only
+ let top: number = win.scrollTop();
const documentElement = domAdapter.getDocumentElement();
const hZoomLevel = touch ? documentElement.clientWidth / windowWidth : 1;
const vZoomLevel = touch ? documentElement.clientHeight / windowHeight : 1;
@@ -320,10 +395,9 @@ const calculatePosition = function (what, options) {
if (boundary && !isWindow(boundary)) {
const $boundary = $(boundary);
- const boundaryPosition = $boundary.offset();
- // @ts-expect-error
+ // @ts-expect-error offset() is typed as possibly undefined
+ const boundaryPosition: Coordinates = $boundary.offset();
left = boundaryPosition.left;
- // @ts-expect-error
top = boundaryPosition.top;
boundaryWidth = Number(getWidth($boundary));
@@ -333,16 +407,14 @@ const calculatePosition = function (what, options) {
return {
h: {
min: left + h.boundaryOffset,
- // @ts-expect-error
max: left + boundaryWidth / hZoomLevel - h.mySize - h.boundaryOffset,
},
v: {
min: top + v.boundaryOffset,
- // @ts-expect-error
max: top + boundaryHeight / vZoomLevel - v.mySize - v.boundaryOffset,
},
};
- })();
+ }());
h.oversize = calculateOversize(h, bounds.h);
v.oversize = calculateOversize(v, bounds.v);
@@ -358,61 +430,44 @@ const calculatePosition = function (what, options) {
collisionResolvers[v.collision](v, bounds.v);
}
- const preciser = function (number) {
+ const preciser = function preciser(number: number): number {
return options.precise ? number : Math.round(number);
};
extend(true, result, {
h: {
- location: preciser(h.myLocation), oversize: preciser(h.oversize), fit: h.fit, flip: h.flip, collisionSide: h.collisionSide,
+ location: preciser(h.myLocation),
+ oversize: preciser(h.oversize),
+ fit: h.fit,
+ flip: h.flip,
+ collisionSide: h.collisionSide,
},
v: {
- location: preciser(v.myLocation), oversize: preciser(v.oversize), fit: v.fit, flip: v.flip, collisionSide: v.collisionSide,
+ location: preciser(v.myLocation),
+ oversize: preciser(v.oversize),
+ fit: v.fit,
+ flip: v.flip,
+ collisionSide: v.collisionSide,
},
precise: options.precise,
});
return result;
};
-// NOTE: Setting the 'element.style' requires creating attributeNode when both of the conditions met:
-// - a form contains an input with the name property set to "style";
-// - a form contains a dx-validator (or other popup widget).
-// T941581
-const setScaleProperty = function (element, scale, styleAttr, isEmpty) {
- const stylePropIsValid = isDefined(element.style) && !domAdapter.isNode(element.style);
- const newStyleValue = isEmpty ? styleAttr.replace(scale, '') : styleAttr;
-
- if (stylePropIsValid) {
- setStyle(element, newStyleValue, false);
- } else {
- const styleAttributeNode = domAdapter.createAttribute('style');
- styleAttributeNode.value = newStyleValue;
- element.setAttributeNode(styleAttributeNode);
- }
-};
-
-const getOffsetWithoutScale = function ($startElement, $currentElement = $startElement) {
- const currentElement = $currentElement.get(0);
- if (!currentElement) {
- return $startElement.offset();
- }
-
- const style = currentElement.getAttribute?.('style') || '';
- const scale = style.match(scaleRe)?.[0];
- let offset;
-
- if (scale) {
- setScaleProperty(currentElement, scale, style, true);
- offset = getOffsetWithoutScale($startElement, $currentElement.parent());
- setScaleProperty(currentElement, scale, style, false);
- } else {
- offset = getOffsetWithoutScale($startElement, $currentElement.parent());
- }
-
- return offset;
-};
-const position = function (what, options?) {
+function position(what: PositionTarget): Coordinates | undefined;
+function position(
+ what: PositionTarget,
+ options: PositionOptions | PositionResult,
+): PositionResult | undefined;
+function position(
+ what: PositionTarget,
+ options?: PositionOptions | PositionResult,
+): Coordinates | PositionResult | undefined;
+function position(
+ what: PositionTarget,
+ options?: PositionOptions | PositionResult,
+): Coordinates | PositionResult | undefined {
const $what = $(what);
if (!$what.length) {
@@ -425,10 +480,13 @@ const position = function (what, options?) {
resetPosition($what, true);
- const offset = getOffsetWithoutScale($what);
- const targetPosition = options.h && options.v ? options : calculatePosition($what, options);
+ // @ts-expect-error offset() is typed as possibly undefined
+ const offset: Coordinates = getOffsetWithoutScale($what);
+ const targetPosition = options.h && options.v
+ ? options
+ : calculatePosition($what, options);
- const preciser = function (number) {
+ const preciser = function preciser(number: number): number {
return options.precise ? number : Math.round(number);
};
@@ -438,30 +496,34 @@ const position = function (what, options?) {
});
return targetPosition;
-} as any;
+}
-const offset = function (element) {
- element = $(element).get(0);
- if (isWindow(element)) {
+const offset = function offset(element: PositionOptions['of']): Coordinates | null | undefined {
+ // @ts-expect-error renderer() is typed without event objects
+ const domElement = $(element).get(0);
+ if (isWindow(domElement)) {
return null;
- } if (element && 'pageY' in element && 'pageX' in element) {
- return { top: element.pageY, left: element.pageX };
+ } if (domElement && 'pageY' in domElement && 'pageX' in domElement) {
+ // @ts-expect-error get(0) is typed as Element, but an event has pageX and pageY
+ return { top: domElement.pageY, left: domElement.pageX };
}
- return $(element).offset();
+ return $(domElement).offset();
};
+// @ts-expect-error inverseAlign is assigned right below
if (!position.inverseAlign) {
position.inverseAlign = inverseAlign;
}
+// @ts-expect-error normalizeAlign is assigned right below
if (!position.normalizeAlign) {
position.normalizeAlign = normalizeAlign;
}
export default {
- calculateScrollbarWidth: calculateScrollbarWidth,
+ calculateScrollbarWidth,
calculate: calculatePosition,
setup: position,
- offset: offset,
+ offset,
};
diff --git a/packages/devextreme/js/__internal/common/core/animation/types.ts b/packages/devextreme/js/__internal/common/core/animation/types.ts
new file mode 100644
index 000000000000..67ac6a8e6fa5
--- /dev/null
+++ b/packages/devextreme/js/__internal/common/core/animation/types.ts
@@ -0,0 +1,54 @@
+import type { dxElementWrapper } from '@js/core/renderer';
+import type { DxEvent } from '@js/events';
+
+export type PositionTarget = string | EventTarget | dxElementWrapper | null | undefined;
+
+export type CollisionSide = 'left' | 'right' | 'top' | 'bottom' | 'none';
+
+export interface AxisPositionResult {
+ location: number;
+ flip: boolean;
+ fit: boolean;
+ oversize: number;
+ collisionSide?: CollisionSide;
+}
+
+export interface PositionResult {
+ h: AxisPositionResult;
+ v: AxisPositionResult;
+ precise?: boolean;
+}
+
+export interface PositionOptions {
+ my?: unknown;
+ at?: unknown;
+ of?: PositionTarget | DxEvent;
+ offset?: unknown;
+ collision?: unknown;
+ boundary?: PositionTarget | 0;
+ boundaryOffset?: unknown;
+ precise?: boolean;
+ h?: undefined;
+ v?: undefined;
+}
+
+export interface AxisPositionData {
+ mySize: number;
+ myAlign: string;
+ atAlign: string;
+ offset: number;
+ collision: string;
+ boundaryOffset: number;
+ atLocation: number;
+ atSize: number;
+ myLocation: number;
+ oversize: number;
+ collisionSide?: CollisionSide;
+ fit?: boolean;
+ flip?: boolean;
+}
+
+export interface AxisBounds {
+ min: number;
+ max: number;
+}
diff --git a/packages/devextreme/js/__internal/ui/collection/collection_widget.edit.ts b/packages/devextreme/js/__internal/ui/collection/collection_widget.edit.ts
index 85bcffe6447f..42b2d2dcf67c 100644
--- a/packages/devextreme/js/__internal/ui/collection/collection_widget.edit.ts
+++ b/packages/devextreme/js/__internal/ui/collection/collection_widget.edit.ts
@@ -192,7 +192,6 @@ class CollectionWidget<
}
_getCombinedFilter(): unknown {
- // @ts-expect-error arguments
return this._dataController.filter();
}
@@ -272,7 +271,7 @@ class CollectionWidget<
options.userData = dataController.userData();
if (dataController.store()) {
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
+ // @ts-expect-error the store is typed for StoreLoadOptions and unknown items
return dataController.loadFromStore(options).done((loadResult) => {
if (that._disposed) {
return;
@@ -284,8 +283,7 @@ class CollectionWidget<
}
return Deferred().resolve(this.plainItems());
},
- // eslint-disable-next-line @stylistic/max-len
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/explicit-function-return-type
+ // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
dataFields: () => this._dataController.select(),
plainItems: itemsGetter.bind(this._editStrategy),
});
@@ -816,7 +814,6 @@ class CollectionWidget<
_refreshLastPage(): DeferredObj {
this._expectLastItemLoading();
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
return this._dataController.load();
}
diff --git a/packages/devextreme/js/__internal/ui/collection/m_data_controller.ts b/packages/devextreme/js/__internal/ui/collection/m_data_controller.ts
index 64d0247cb2d1..ae0cfcd0c201 100644
--- a/packages/devextreme/js/__internal/ui/collection/m_data_controller.ts
+++ b/packages/devextreme/js/__internal/ui/collection/m_data_controller.ts
@@ -1,11 +1,16 @@
import { noop } from '@js/core/utils/common';
+import type { DeferredObj } from '@js/core/utils/deferred';
import { Deferred } from '@js/core/utils/deferred';
+import type Store from '@ts/data/abstract_store';
+import type { StoreKey } from '@ts/data/abstract_store';
+import type { DataSource } from '@ts/data/data_source/data_source';
+import type { DataSourceEventName, StoreLoadOptions } from '@ts/data/data_source/types';
const DataControllerMock = {
- load: () => Deferred().reject(),
- loadSingle: () => Deferred().reject(),
- loadFromStore: () => Deferred().reject(),
- loadNextPage: () => Deferred().reject(),
+ load: (): DeferredObj => Deferred().reject(),
+ loadSingle: (): DeferredObj => Deferred().reject(),
+ loadFromStore: (): DeferredObj => Deferred().reject(),
+ loadNextPage: (): DeferredObj => Deferred().reject(),
loadOptions: noop,
userData: noop,
cancel: noop,
@@ -37,104 +42,113 @@ const DataControllerMock = {
};
class DataController {
- _dataSource: any;
+ private readonly _dataSource!: DataSource;
- constructor(dataSource) {
+ constructor(dataSource: DataSource | null | undefined) {
if (!dataSource) {
- // @ts-expect-error
+ // @ts-expect-error the mock has the same methods, all of them no-ops
// eslint-disable-next-line no-constructor-return
return DataControllerMock;
}
this._dataSource = dataSource;
}
- load() {
+ load(): DeferredObj {
return this._dataSource.load();
}
- loadSingle(propName, propValue) {
+ loadSingle(propName: unknown, propValue?: unknown): DeferredObj {
if (arguments.length < 2) {
- propValue = propName;
- propName = this.key();
+ return this._dataSource.loadSingle(this.key(), propName);
}
return this._dataSource.loadSingle(propName, propValue);
}
- loadFromStore(loadOptions) {
+ loadFromStore(loadOptions?: StoreLoadOptions): DeferredObj {
return this.store().load(loadOptions);
}
- loadNextPage() {
+ loadNextPage(): DeferredObj {
this.pageIndex(1 + this.pageIndex());
return this.load();
}
- loadOptions() {
+ loadOptions(): StoreLoadOptions {
return this._dataSource.loadOptions();
}
- userData() {
+ userData(): Record {
return this._dataSource._userData;
}
- cancel(operationId) {
+ cancel(operationId: number): void {
this._dataSource.cancel(operationId);
}
- cancelAll() {
+ cancelAll(): void {
this._dataSource.cancelAll();
}
- filter(filter) {
+ filter(filter?: undefined): StoreLoadOptions['filter'];
+ filter(filter: NonNullable): void;
+ filter(filter?: StoreLoadOptions['filter']): StoreLoadOptions['filter'] {
return this._dataSource.filter(filter);
}
- addSearchFilter(storeLoadOptions) {
+ addSearchFilter(storeLoadOptions: StoreLoadOptions): void {
this._dataSource._addSearchFilter(storeLoadOptions);
}
- group(group?) {
+ group(group?: undefined): StoreLoadOptions['group'];
+ group(group: NonNullable): void;
+ group(group?: StoreLoadOptions['group']): StoreLoadOptions['group'] {
+ // @ts-expect-error DataSource accessors are typed without the undefined getter argument
return this._dataSource.group(group);
}
- paginate() {
+ paginate(): boolean | undefined {
return this._dataSource.paginate();
}
- pageSize() {
+ pageSize(): number {
return this._dataSource._pageSize;
}
- pageIndex(pageIndex?: number) {
+ pageIndex(): number;
+ pageIndex(pageIndex: number): void;
+ pageIndex(pageIndex?: number): number | undefined {
+ // @ts-expect-error DataSource accessors are typed without the undefined getter argument
return this._dataSource.pageIndex(pageIndex);
}
- resetDataSourcePageIndex() {
+ resetDataSourcePageIndex(): void {
if (this.pageIndex()) {
this.pageIndex(0);
this.load();
}
}
- totalCount() {
+ totalCount(): number {
return this._dataSource.totalCount();
}
- isLastPage() {
+ isLastPage(): boolean {
return this._dataSource.isLastPage() || !this._dataSource._pageSize;
}
- isLoading() {
+ isLoading(): boolean {
return this._dataSource.isLoading();
}
- isLoaded() {
+ isLoaded(): boolean {
return this._dataSource.isLoaded();
}
- searchValue(value) {
+ searchValue(): StoreLoadOptions['searchValue'];
+ searchValue(value: StoreLoadOptions['searchValue']): void;
+ searchValue(value?: StoreLoadOptions['searchValue']): StoreLoadOptions['searchValue'] {
if (!arguments.length) {
return this._dataSource.searchValue();
}
@@ -142,55 +156,61 @@ class DataController {
return this._dataSource.searchValue(value);
}
- searchOperation(operation) {
+ searchOperation(operation?: unknown): StoreLoadOptions['searchOperation'] {
+ // @ts-expect-error DataSource.searchOperation() treats a non-string argument as the getter
return this._dataSource.searchOperation(operation);
}
- searchExpr(expr) {
+ searchExpr(): StoreLoadOptions['searchExpr'];
+ searchExpr(expr: NonNullable): void;
+ searchExpr(expr?: StoreLoadOptions['searchExpr']): StoreLoadOptions['searchExpr'] {
if (!arguments.length) {
return this._dataSource.searchExpr();
}
+ // @ts-expect-error DataSource.searchExpr() is typed without an array or undefined argument
return this._dataSource.searchExpr(expr);
}
- select() {
- return this._dataSource.select(...arguments);
+ select(): StoreLoadOptions['select'];
+ select(...selectExpr: NonNullable[]): void;
+ select(...selectExpr: NonNullable[]): unknown {
+ return this._dataSource.select(...selectExpr);
}
- key() {
+ key(): StoreKey | undefined {
return this._dataSource.key();
}
- keyOf(item) {
+ keyOf(item: unknown): unknown {
return this.store().keyOf(item);
}
- store() {
+ store(): Store {
return this._dataSource.store();
}
- items() {
+ items(): unknown[] {
return this._dataSource.items();
}
- applyMapFunction(data) {
+ applyMapFunction(data: unknown[]): unknown[] {
return this._dataSource._applyMapFunction(data);
}
- getDataSource() {
+ getDataSource(): DataSource | null {
return this._dataSource || null;
}
- reload() {
+ reload(): DeferredObj {
return this._dataSource.reload();
}
- on(event, handler): void {
+ on(event: DataSourceEventName, handler: Function): void {
this._dataSource.on(event, handler);
}
- off(event, handler): void {
+ off(event: DataSourceEventName, handler?: Function): void {
this._dataSource.off(event, handler);
}
}
diff --git a/packages/devextreme/js/__internal/ui/drop_down_editor/drop_down_editor.ts b/packages/devextreme/js/__internal/ui/drop_down_editor/drop_down_editor.ts
index 3f9853d9d5f4..4a1b8114336b 100644
--- a/packages/devextreme/js/__internal/ui/drop_down_editor/drop_down_editor.ts
+++ b/packages/devextreme/js/__internal/ui/drop_down_editor/drop_down_editor.ts
@@ -1001,12 +1001,15 @@ class DropDownEditor<
let positionSide = 'bottom';
if (this._popup?.option('visible')) {
- const { top: myTop } = animationPosition.setup(this.$element());
+ const myOffset = animationPosition.setup(this.$element());
- const { top: popupTop } = animationPosition.setup(this._popup.$content());
- const { popupPosition } = this.option();
- // @ts-expect-error Should be updated on PositionConfig level
- positionSide = (myTop + popupPosition.offset.v) > popupTop ? 'bottom' : 'top';
+ const popupOffset = animationPosition.setup(this._popup.$content());
+
+ if (myOffset && popupOffset) {
+ const { popupPosition } = this.option();
+ // @ts-expect-error Should be updated on PositionConfig level
+ positionSide = (myOffset.top + popupPosition.offset.v) > popupOffset.top ? 'bottom' : 'top';
+ }
}
return positionSide;
diff --git a/packages/devextreme/js/__internal/ui/drop_down_editor/drop_down_list.ts b/packages/devextreme/js/__internal/ui/drop_down_editor/drop_down_list.ts
index 81e34094c987..c798b34e448a 100644
--- a/packages/devextreme/js/__internal/ui/drop_down_editor/drop_down_list.ts
+++ b/packages/devextreme/js/__internal/ui/drop_down_editor/drop_down_list.ts
@@ -740,7 +740,7 @@ class DropDownList<
const isMinSearchLengthExceeded = this._isMinSearchLengthExceeded();
const { showDataBeforeSearch, minSearchLength } = this.option();
- return this._dataController.isLoaded() as boolean
+ return this._dataController.isLoaded()
&& Boolean(showDataBeforeSearch)
&& Boolean(minSearchLength)
&& !isMinSearchLengthExceeded
@@ -877,7 +877,6 @@ class DropDownList<
_clearFilter(): void {
const dataController = this._dataController;
- // @ts-expect-error fix argument type in m_data_controller.ts
if (dataController.searchValue()) {
dataController.searchValue(null);
}
@@ -963,7 +962,7 @@ class DropDownList<
const dataController = this._dataController;
const currentPageIndex = dataController.pageIndex();
const needRepaint = (isDefined(this._pageIndex) && currentPageIndex <= this._pageIndex)
- || (dataController.isLastPage() as boolean && !this._list?._scrollViewIsFull());
+ || (dataController.isLastPage() && !this._list?._scrollViewIsFull());
this._pageIndex = currentPageIndex;
diff --git a/packages/devextreme/js/__internal/ui/list/list.edit.search.ts b/packages/devextreme/js/__internal/ui/list/list.edit.search.ts
index f590d87d9e7f..7298b11e2668 100644
--- a/packages/devextreme/js/__internal/ui/list/list.edit.search.ts
+++ b/packages/devextreme/js/__internal/ui/list/list.edit.search.ts
@@ -24,7 +24,6 @@ class ListSearch extends ListEdit {
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type, @typescript-eslint/explicit-module-boundary-types
_getCombinedFilter() {
const dataController = this._dataController;
- // @ts-expect-error ts-error
const storeLoadOptions = { filter: dataController.filter() };
dataController.addSearchFilter(storeLoadOptions);
const { filter } = storeLoadOptions;
diff --git a/packages/devextreme/js/__internal/ui/overlay/overlay_position_controller.ts b/packages/devextreme/js/__internal/ui/overlay/overlay_position_controller.ts
index 6c243eecaf13..8e67a464e5b3 100644
--- a/packages/devextreme/js/__internal/ui/overlay/overlay_position_controller.ts
+++ b/packages/devextreme/js/__internal/ui/overlay/overlay_position_controller.ts
@@ -14,6 +14,7 @@ import type {
DxEvent,
PointerInteractionEvent,
} from '@js/events';
+import type { PositionResult } from '@ts/common/core/animation/types';
import swatch from '@ts/core/utils/swatch_container';
import windowUtils from '@ts/core/utils/window';
import type {
@@ -142,7 +143,7 @@ export class OverlayPositionController<
_visualPosition?: Coordinates;
- _initialPosition?: OverlayPosition;
+ _initialPosition?: Coordinates | PositionResult;
_previousVisualPosition?: Coordinates;
diff --git a/packages/devextreme/js/__internal/ui/popover/popover.ts b/packages/devextreme/js/__internal/ui/popover/popover.ts
index e503e74fbb9e..4b78f98a3218 100644
--- a/packages/devextreme/js/__internal/ui/popover/popover.ts
+++ b/packages/devextreme/js/__internal/ui/popover/popover.ts
@@ -511,6 +511,10 @@ class Popover<
const contentPosition = this._getContainerPosition();
const resultLocation = positionUtils.setup(this.$overlayContent(), contentPosition);
+ if (!resultLocation) {
+ return;
+ }
+
const positionSide = this._getSideByLocation(resultLocation);
this._togglePositionClass(`dx-position-${positionSide}`);
@@ -626,7 +630,7 @@ class Popover<
const contentOffset = positionUtils.offset(this.$overlayContent());
const arrowSize = arrowRect[sizeProperty];
- const contentLocation = contentOffset?.[axis];
+ const contentLocation = contentOffset?.[axis] ?? NaN;
const contentSize = getBoundingRect(this.$overlayContent().get(0))[sizeProperty];
const targetLocation = targetOffset[axis];
const targetElement = $target.get(0);
diff --git a/packages/devextreme/js/__internal/ui/select_box.ts b/packages/devextreme/js/__internal/ui/select_box.ts
index a9c947e5abab..19928fe24d86 100644
--- a/packages/devextreme/js/__internal/ui/select_box.ts
+++ b/packages/devextreme/js/__internal/ui/select_box.ts
@@ -488,7 +488,6 @@ class SelectBox<
}
_getActualSearchValue(): string | null {
- // @ts-expect-error fix argument type in m_data_controller.ts
return this._dataController.searchValue() as string | null;
}
diff --git a/packages/devextreme/js/__internal/ui/tag_box.ts b/packages/devextreme/js/__internal/ui/tag_box.ts
index 3008a40180ee..6a985a145be7 100644
--- a/packages/devextreme/js/__internal/ui/tag_box.ts
+++ b/packages/devextreme/js/__internal/ui/tag_box.ts
@@ -897,7 +897,6 @@ class TagBox<
}
_getFilter(creator: FilterCreator): unknown[] | undefined {
- // @ts-expect-error fix argument type in m_data_controller.ts
const dataSourceFilter: unknown[] | null = this._dataController.filter();
const { valueExpr, maxFilterQueryLength } = this.option();
const filterExpr = creator.getCombinedFilter(valueExpr, dataSourceFilter);
@@ -955,6 +954,7 @@ class TagBox<
const mappedItems = dataController.applyMapFunction(items);
d.resolve(mappedItems.filter(clientFilterFunction as (item: unknown) => boolean));
})
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises -- ignores the result
.fail(d.reject);
this._loadFilteredItemsPromise = d;