diff --git a/packages/devextreme/js/__internal/core/widget/widget.ts b/packages/devextreme/js/__internal/core/widget/widget.ts index f2f717203f93..26ec37a96ada 100644 --- a/packages/devextreme/js/__internal/core/widget/widget.ts +++ b/packages/devextreme/js/__internal/core/widget/widget.ts @@ -16,6 +16,7 @@ import { extend } from '@js/core/utils/extend'; import { each } from '@js/core/utils/iterator'; import { isDefined, isPlainObject } from '@js/core/utils/type'; import { compare as compareVersions } from '@js/core/utils/version'; +import type { DxEvent } from '@js/events'; import { focusable as focusableSelector } from '@js/ui/widget/selectors'; import type { WidgetOptions } from '@js/ui/widget/ui.widget'; @@ -47,14 +48,14 @@ export interface Properties extends WidgetOptions class Widget< TProperties extends Properties = Properties, > extends DOMComponent, TProperties> { - private readonly _feedbackHideTimeout = 400; + public _activeStateUnit!: string; + + public _feedbackHideTimeout = 400; private readonly _feedbackShowTimeout = 30; private _contentReadyAction?: ((event?: Record) => void) | null; - private readonly _activeStateUnit!: string; - private _keyboardListenerId?: string | null; private _isReady?: boolean; @@ -265,8 +266,9 @@ class Widget< return this._getActiveElement(); } - _isFocusTarget(element: Element): boolean { + _isFocusTarget(element: Element | undefined): boolean { const focusTargets = $(this._focusTarget()).toArray(); + // @ts-expect-error ts-error return focusTargets.includes(element); } @@ -306,7 +308,7 @@ class Widget< } // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types - _focusInHandler(event): void { + _focusInHandler(event: DxEvent): void { if (!event.isDefaultPrevented()) { this._createActionByOption('onFocusIn', { beforeExecute: () => this._updateFocusState(event, true), @@ -316,7 +318,7 @@ class Widget< } // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types - _focusOutHandler(event): void { + _focusOutHandler(event: DxEvent): void { if (!event.isDefaultPrevented()) { this._createActionByOption('onFocusOut', { beforeExecute: () => this._updateFocusState(event, false), diff --git a/packages/devextreme/js/__internal/ui/calendar/m_calendar.ts b/packages/devextreme/js/__internal/ui/calendar/m_calendar.ts index ef0b48f5f88c..56a1ebb000b2 100644 --- a/packages/devextreme/js/__internal/ui/calendar/m_calendar.ts +++ b/packages/devextreme/js/__internal/ui/calendar/m_calendar.ts @@ -74,8 +74,6 @@ const SELECTION_STRATEGIES = { // @ts-expect-error const Calendar = Editor.inherit({ - _activeStateUnit: `.${CALENDAR_CELL_CLASS}`, - _getDefaultOptions() { return extend(this.callBase(), { @@ -442,6 +440,8 @@ const Calendar = Editor.inherit({ _init() { this.callBase(); + + this._activeStateUnit = `.${CALENDAR_CELL_CLASS}`; this._initSelectionStrategy(); this._correctZoomLevel(); this._initCurrentDate(); diff --git a/packages/devextreme/js/__internal/ui/collection/async.ts b/packages/devextreme/js/__internal/ui/collection/async.ts index 6dd2a3ab0a33..e27d9b4d0291 100644 --- a/packages/devextreme/js/__internal/ui/collection/async.ts +++ b/packages/devextreme/js/__internal/ui/collection/async.ts @@ -1,11 +1,12 @@ import CollectionWidgetAsync from '@js/ui/collection/ui.collection_widget.async'; -import type { CollectionWidgetOptions, ItemLike } from '@js/ui/collection/ui.collection_widget.base'; +import type { ItemLike } from '@js/ui/collection/ui.collection_widget.base'; +import type { CollectionWidgetBaseProperties } from '@ts/ui/collection/m_collection_widget.base'; import CollectionWidgetEdit from './edit'; declare class Async< // eslint-disable-next-line @typescript-eslint/no-explicit-any - TProperties extends CollectionWidgetOptions, + TProperties extends CollectionWidgetBaseProperties, // eslint-disable-next-line @typescript-eslint/no-explicit-any TItem extends ItemLike = any, // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/packages/devextreme/js/__internal/ui/collection/base.ts b/packages/devextreme/js/__internal/ui/collection/base.ts deleted file mode 100644 index 9ee3499b6fc3..000000000000 --- a/packages/devextreme/js/__internal/ui/collection/base.ts +++ /dev/null @@ -1,97 +0,0 @@ -import type { DataSource } from '@js/common/data'; -import type { dxElementWrapper } from '@js/core/renderer'; -import type { CollectionWidgetOptions, ItemLike } from '@js/ui/collection/ui.collection_widget.base'; -import CollectionWidget from '@js/ui/collection/ui.collection_widget.base'; -import Widget from '@ts/core/widget/widget'; - -export interface TypedCollectionWidgetOptions< - // eslint-disable-next-line @typescript-eslint/no-explicit-any - TComponent extends CollectionWidget | any, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - TItem extends ItemLike = any, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - TKey = any, -> extends CollectionWidgetOptions { - _itemAttributes?: Record; -} - -declare class Base< - // eslint-disable-next-line @typescript-eslint/no-explicit-any - TProperties extends TypedCollectionWidgetOptions, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - TItem extends ItemLike = any, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - TKey = any, -> extends Widget { - _renderedItemsCount: number; - - getDataSource(): DataSource; - - _renderItems(items: TItem[]): void; - _renderItem( - index: number, - itemData: TItem, - $container: dxElementWrapper, - $itemToReplace?: dxElementWrapper, - ): dxElementWrapper; - _renderItemFrame( - index: number, - itemData: TItem, - $container: dxElementWrapper, - $itemToReplace?: dxElementWrapper, - ): dxElementWrapper; - _renderItemContent(args: { - index: number; - itemData: TItem; - container: dxElementWrapper; - contentClass: string; - defaultTemplateName: string; - uniqueKey?: string; - }): dxElementWrapper; - _renderContent(): void; - _postprocessRenderItem(args: unknown): void; - _prepareContent(): void; - _itemSelector(): string; - _itemContainer(): dxElementWrapper; - - _createItemByTemplate( - itemTemplate: { source: () => unknown }, - args: { itemData: unknown }): void; - - _getItemData(item: Element | HTMLElement | dxElementWrapper): TItem; - _getItemContent($item: dxElementWrapper): dxElementWrapper; - _getIndexByItem(item: TItem): number; - _getIndexByItemData(item: TItem): number; - _getAvailableItems($items?: dxElementWrapper): dxElementWrapper; - _itemElements(): dxElementWrapper; - _getSummaryItemsSize( - dimension: string, - items: dxElementWrapper, - includeMargin?: boolean - ): number; - _getActiveItem(last?: boolean): dxElementWrapper; - _findItemElementByItem(item: TItem): dxElementWrapper; - - _itemOptionChanged(item: TItem, property: string, value: unknown, prevValue: unknown): void; - _itemEventHandler($item: dxElementWrapper, eventName: string, eventData: unknown): void; - _itemIndexKey(): number; - - _prevItem($items: dxElementWrapper): dxElementWrapper; - _nextItem($items: dxElementWrapper): dxElementWrapper; - - _attachContextMenuEvent(): void; - _itemContextMenuHandler(event: unknown): void; - _itemPointerDownHandler(event: unknown): void; - _itemDXEventHandler(event: unknown, eventHandlerName: string, args: unknown, actionConfig: { - beforeExecute: (args?: unknown) => void; - afterExecute: () => void; - }): void; - - _refreshActiveDescendant($target: dxElementWrapper): void; - _moveFocus(location: string, event?: unknown): void; -} - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const TypedCollectionWidget: typeof Base = CollectionWidget as any; - -export default TypedCollectionWidget; diff --git a/packages/devextreme/js/__internal/ui/collection/edit.ts b/packages/devextreme/js/__internal/ui/collection/edit.ts index a66d637cb5e0..6fbda5565048 100644 --- a/packages/devextreme/js/__internal/ui/collection/edit.ts +++ b/packages/devextreme/js/__internal/ui/collection/edit.ts @@ -1,12 +1,12 @@ import type { dxElementWrapper } from '@js/core/renderer'; -import type { CollectionWidgetOptions, ItemLike } from '@js/ui/collection/ui.collection_widget.base'; +import type { ItemLike } from '@js/ui/collection/ui.collection_widget.base'; import CollectionWidgetEdit from '@js/ui/collection/ui.collection_widget.edit'; - -import CollectionWidgetBase from './base'; +import type { CollectionWidgetBaseProperties } from '@ts/ui/collection/m_collection_widget.base'; +import CollectionWidgetBase from '@ts/ui/collection/m_collection_widget.base'; declare class Edit< // eslint-disable-next-line @typescript-eslint/no-explicit-any - TProperties extends CollectionWidgetOptions, + TProperties extends CollectionWidgetBaseProperties, // eslint-disable-next-line @typescript-eslint/no-explicit-any TItem extends ItemLike = any, // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/packages/devextreme/js/__internal/ui/collection/live_update.ts b/packages/devextreme/js/__internal/ui/collection/live_update.ts index 93c2458afb09..974a8cf4c232 100644 --- a/packages/devextreme/js/__internal/ui/collection/live_update.ts +++ b/packages/devextreme/js/__internal/ui/collection/live_update.ts @@ -1,11 +1,12 @@ -import type { CollectionWidgetOptions, ItemLike } from '@js/ui/collection/ui.collection_widget.base'; +import type { ItemLike } from '@js/ui/collection/ui.collection_widget.base'; import CollectionWidgetLiveUpdate from '@js/ui/collection/ui.collection_widget.live_update'; +import type { CollectionWidgetBaseProperties } from '@ts/ui/collection/m_collection_widget.base'; import CollectionWidgetAsync from './async'; declare class LiveUpdate< // eslint-disable-next-line @typescript-eslint/no-explicit-any - TProperties extends CollectionWidgetOptions, + TProperties extends CollectionWidgetBaseProperties, // eslint-disable-next-line @typescript-eslint/no-explicit-any TItem extends ItemLike = any, // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/packages/devextreme/js/__internal/ui/collection/m_collection_widget.base.ts b/packages/devextreme/js/__internal/ui/collection/m_collection_widget.base.ts index a5c410bd3806..01c95f6a6c59 100644 --- a/packages/devextreme/js/__internal/ui/collection/m_collection_widget.base.ts +++ b/packages/devextreme/js/__internal/ui/collection/m_collection_widget.base.ts @@ -1,3 +1,4 @@ +import type { template } from '@js/common'; import { name as clickEventName } from '@js/common/core/events/click'; import { name as contextMenuEventName } from '@js/common/core/events/contextmenu'; import eventsEngine from '@js/common/core/events/core/events_engine'; @@ -8,27 +9,33 @@ import messageLocalization from '@js/common/core/localization/message'; import DataHelperMixin from '@js/common/data/data_helper'; import Action from '@js/core/action'; import domAdapter from '@js/core/dom_adapter'; -import { getPublicElement } from '@js/core/element'; import Guid from '@js/core/guid'; +import type { dxElementWrapper } from '@js/core/renderer'; import $ from '@js/core/renderer'; import { BindableTemplate } from '@js/core/templates/bindable_template'; import { - // @ts-expect-error + // @ts-expect-error ts-error deferRenderer, ensureDefined, - noop, } from '@js/core/utils/common'; import { compileGetter } from '@js/core/utils/data'; +import type { DeferredObj } from '@js/core/utils/deferred'; import { when } from '@js/core/utils/deferred'; import { extend } from '@js/core/utils/extend'; import { each } from '@js/core/utils/iterator'; import { getOuterHeight, getOuterWidth } from '@js/core/utils/size'; import { findTemplates } from '@js/core/utils/template_manager'; import { isDefined, isFunction, isPlainObject } from '@js/core/utils/type'; +import type { DataSourceOptions } from '@js/data/data_source'; +import type { + Cancelable, DxEvent, EventInfo, ItemInfo, +} from '@js/events'; +import type { CollectionWidgetItem as CollectionWidgetItemProperties, CollectionWidgetOptions, ItemLike } from '@js/ui/collection/ui.collection_widget.base'; import { focusable } from '@js/ui/widget/selectors'; -import Widget from '@js/ui/widget/ui.widget'; - -import CollectionWidgetItem from './m_item'; +import { getPublicElement } from '@ts/core/m_element'; +import type { OptionChanged } from '@ts/core/widget/types'; +import Widget from '@ts/core/widget/widget'; +import CollectionWidgetItem from '@ts/ui/collection/m_item'; const COLLECTION_CLASS = 'dx-collection'; const ITEM_CLASS = 'dx-item'; @@ -54,24 +61,92 @@ const FOCUS_PAGE_UP = 'pageup'; const FOCUS_PAGE_DOWN = 'pagedown'; const FOCUS_LAST = 'last'; const FOCUS_FIRST = 'first'; -// @ts-expect-error -const CollectionWidget = Widget.inherit({ - - _activeStateUnit: `.${ITEM_CLASS}`, - _supportedKeys() { - const space = function (e) { +interface ActionConfig { + beforeExecute?: (e: DxEvent) => void; + afterExecute?: (e: DxEvent) => void; + excludeValidators?: ('disabled' | 'readOnly')[]; +} + +type ItemTemplate = template | ( + (itemData: TItem, itemIndex: number, itemElement: Element) => string | dxElementWrapper +); +export interface ItemRenderInfo { + index: number; + itemData: TItem; + container: dxElementWrapper; + contentClass: string; + defaultTemplateName: ItemTemplate | undefined; + templateProperty?: string; +} +export interface CollectionWidgetBaseProperties< + // eslint-disable-next-line @typescript-eslint/no-explicit-any + TComponent extends CollectionWidget | any, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + TItem extends ItemLike = any, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + TKey = any, +> extends CollectionWidgetOptions { + focusedElement?: dxElementWrapper; + + focusOnSelectedItem?: boolean; + + _itemAttributes?: Record; +} + +class CollectionWidget< + // eslint-disable-next-line @typescript-eslint/no-explicit-any + TProperties extends CollectionWidgetBaseProperties, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + TItem extends ItemLike = any, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + TKey = any, +> extends Widget { + private _focusedItemId?: string; + + // eslint-disable-next-line no-restricted-globals + private _itemFocusTimeout?: ReturnType; + + private _itemRenderAction?: (event?: Partial & ItemInfo>) => void; + + _displayGetter?: unknown; + + _shouldSkipSelectOnFocus?: boolean; + + _renderedItemsCount?: number; + + _startIndexForAppendedItems?: number | null; + + _$noData?: dxElementWrapper; + + _itemFocusHandler?: () => void; + + _inkRipple?: { + showWave: (config: { + element: dxElementWrapper; + event: unknown; + }) => void; + hideWave: (config: { + element: dxElementWrapper; + event: unknown; + }) => void; + }; + + _supportedKeys(): Record) => void> { + const space = (e): void => { e.preventDefault(); this._enterKeyHandler(e); }; - const move = function (location, e) { + const move = (location, e): void => { if (!isCommandKeyPressed(e)) { e.preventDefault(); e.stopPropagation(); this._moveFocus(location, e); } }; - return extend(this.callBase(), { + + return { + ...super._supportedKeys(), space, enter: this._enterKeyHandler, leftArrow: move.bind(this, FOCUS_LEFT), @@ -82,37 +157,47 @@ const CollectionWidget = Widget.inherit({ pageDown: move.bind(this, FOCUS_DOWN), home: move.bind(this, FOCUS_FIRST), end: move.bind(this, FOCUS_LAST), - }); - }, + }; + } - _getHandlerExtendedParams(e, target) { + // eslint-disable-next-line class-methods-use-this + _getHandlerExtendedParams( + e: Record, + $target: dxElementWrapper, + ): Record { const params = extend({}, e, { - target: target.get(0), - currentTarget: target.get(0), + target: $target.get(0), + currentTarget: $target.get(0), }); + // eslint-disable-next-line @typescript-eslint/no-unsafe-return return params; - }, + } + + _enterKeyHandler(e: KeyboardEvent): void { + const { focusedElement } = this.option(); - _enterKeyHandler(e) { - const $itemElement = $(this.option('focusedElement')); + const $itemElement = $(focusedElement); if (!$itemElement.length) { return; } const itemData = this._getItemData($itemElement); + // @ts-expect-error ts-error if (itemData?.onClick) { + // @ts-expect-error ts-error this._itemEventHandlerByHandler($itemElement, itemData.onClick, { event: e, }); } - + // @ts-expect-error ts-error this._itemClickHandler(this._getHandlerExtendedParams(e, $itemElement)); - }, + } - _getDefaultOptions() { - return extend(this.callBase(), { + _getDefaultOptions(): TProperties { + return { + ...super._getDefaultOptions(), selectOnFocus: false, loopItemFocus: true, items: [], @@ -134,82 +219,106 @@ const CollectionWidget = Widget.inherit({ focusedElement: null, displayExpr: undefined, - disabledExpr(data) { return data ? data.disabled : undefined; }, - visibleExpr(data) { return data ? data.visible : undefined; }, - - }); - }, + // eslint-disable-next-line @typescript-eslint/explicit-function-return-type + disabledExpr(data) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return data ? data.disabled : undefined; + }, + // eslint-disable-next-line @typescript-eslint/explicit-function-return-type + visibleExpr(data) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return data ? data.visible : undefined; + }, + }; + } - _init() { + _init(): void { this._compileDisplayGetter(); + // @ts-expect-error ts-error this._initDataController(); - this.callBase(); + super._init(); + + this._activeStateUnit = `.${ITEM_CLASS}`; this._cleanRenderedItems(); + // @ts-expect-error ts-error this._refreshDataSource(); - }, + } - _compileDisplayGetter() { - const displayExpr = this.option('displayExpr'); - this._displayGetter = displayExpr ? compileGetter(this.option('displayExpr')) : undefined; - }, + _compileDisplayGetter(): void { + // @ts-expect-error ts-error + const { displayExpr } = this.option(); - _initTemplates() { + this._displayGetter = displayExpr ? compileGetter(displayExpr) : undefined; + } + + _initTemplates(): void { this._initItemsFromMarkup(); this._initDefaultItemTemplate(); - this.callBase(); - }, + super._initTemplates(); + } - _getAnonymousTemplateName() { + // eslint-disable-next-line class-methods-use-this + _getAnonymousTemplateName(): string { return ANONYMOUS_TEMPLATE_NAME; - }, + } - _initDefaultItemTemplate() { + _initDefaultItemTemplate(): void { const fieldsMap = this._getFieldsMap(); this._templateManager.addDefaultTemplates({ - item: new BindableTemplate(($container, data) => { + item: new BindableTemplate(($container: dxElementWrapper, data) => { if (isPlainObject(data)) { this._prepareDefaultItemTemplate(data, $container); } else { if (fieldsMap && isFunction(fieldsMap.text)) { + // eslint-disable-next-line no-param-reassign data = fieldsMap.text(data); } $container.text(String(ensureDefined(data, ''))); } }, this._getBindableFields(), this.option('integrationOptions.watchMethod'), fieldsMap), }); - }, + } - _getBindableFields() { + // eslint-disable-next-line class-methods-use-this + _getBindableFields(): string[] { return ['text', 'html']; - }, - // @ts-expect-error - _getFieldsMap() { + } + + _getFieldsMap(): { text: unknown } | undefined { if (this._displayGetter) { return { text: this._displayGetter }; } - }, - _prepareDefaultItemTemplate(data, $container) { - if (isDefined(data.text)) { - $container.text(data.text); + return undefined; + } + + // eslint-disable-next-line class-methods-use-this + _prepareDefaultItemTemplate( + data: CollectionWidgetItemProperties, + $container: dxElementWrapper, + ): void { + const { text, html } = data; + + if (isDefined(text)) { + $container.text(text); } - if (isDefined(data.html)) { - $container.html(data.html); + if (isDefined(html)) { + $container.html(html); } - }, + } - _initItemsFromMarkup() { + _initItemsFromMarkup(): void { const rawItems = findTemplates(this.$element(), ITEMS_OPTIONS_NAME); - + // @ts-expect-error ts-error if (!rawItems.length || this.option('items').length) { return; } const items = rawItems.map(({ element, options }) => { - // @ts-expect-error + // @ts-expect-error ts-error const isTemplateRequired = /\S/.test(element.innerHTML) && !options.template; if (isTemplateRequired) { @@ -218,14 +327,15 @@ const CollectionWidget = Widget.inherit({ $(element).remove(); } + // eslint-disable-next-line @typescript-eslint/no-unsafe-return return options; }); this.option('items', items); - }, + } - _prepareItemTemplate(item) { - const templateId = ITEM_TEMPLATE_ID_PREFIX + new Guid(); + _prepareItemTemplate(item: Element): string { + const templateId = `${ITEM_TEMPLATE_ID_PREFIX}${new Guid()}`; const $template = $(item) .detach() .clone() @@ -235,27 +345,28 @@ const CollectionWidget = Widget.inherit({ this._saveTemplate(templateId, $template); return templateId; - }, + } - _dataSourceOptions() { + // eslint-disable-next-line class-methods-use-this + _dataSourceOptions(): DataSourceOptions { return { paginate: false }; - }, + } - _cleanRenderedItems() { + _cleanRenderedItems(): void { this._renderedItemsCount = 0; - }, + } - _focusTarget() { + _focusTarget(): dxElementWrapper { return this.$element(); - }, + } - _focusInHandler(e) { - this.callBase.apply(this, arguments); + _focusInHandler(e: DxEvent): void { + super._focusInHandler(e); if (!this._isFocusTarget(e.target)) { return; } - + // @ts-expect-error ts-error const $focusedElement = $(this.option('focusedElement')); if ($focusedElement.length) { // NOTE: If focusedElement is set, selection was already processed on its focusing. @@ -268,42 +379,54 @@ const CollectionWidget = Widget.inherit({ this.option('focusedElement', getPublicElement($activeItem)); } } - }, + } - _focusOutHandler() { - this.callBase.apply(this, arguments); + _focusOutHandler(e: DxEvent): void { + super._focusOutHandler(e); - const $target = $(this.option('focusedElement')); + const { focusedElement } = this.option(); + const $target = $(focusedElement); this._updateFocusedItemState($target, false); - }, + } - _findActiveTarget($element) { + _findActiveTarget($element: dxElementWrapper): dxElementWrapper { return $element.find(this._activeStateUnit); - }, + } - _getActiveItem(last) { - const $focusedElement = $(this.option('focusedElement')); + _getActiveItem(last?: boolean): dxElementWrapper { + const { focusedElement } = this.option(); + + const $focusedElement = $(focusedElement); if ($focusedElement.length) { return $focusedElement; } - let index = this.option('focusOnSelectedItem') ? this.option('selectedIndex') : 0; + const { focusOnSelectedItem, selectedIndex } = this.option(); + + let index = focusOnSelectedItem ? selectedIndex : 0; const activeElements = this._getActiveElement(); const lastIndex = activeElements.length - 1; + // @ts-expect-error ts-error if (index < 0) { index = last ? lastIndex : 0; } - + // @ts-expect-error ts-error return activeElements.eq(index); - }, - // @ts-expect-error - _moveFocus(location) { + } + + // eslint-disable-next-line consistent-return + _moveFocus( + location: string, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + e?: unknown, + // eslint-disable-next-line @typescript-eslint/no-invalid-void-type + ): boolean | undefined | void { const $items = this._getAvailableItems(); - let $newTarget; + let $newTarget: dxElementWrapper = $(); switch (location) { case FOCUS_PAGE_UP: @@ -333,18 +456,18 @@ const CollectionWidget = Widget.inherit({ if ($newTarget.length !== 0) { this.option('focusedElement', getPublicElement($newTarget)); } - }, + } - _getVisibleItems($itemElements) { - $itemElements = $itemElements || this._itemElements(); - return $itemElements.filter(':visible'); - }, + _getVisibleItems($itemElements?: dxElementWrapper): dxElementWrapper { + const $items = $itemElements ?? this._itemElements(); + return $items.filter(':visible'); + } - _getAvailableItems($itemElements) { + _getAvailableItems($itemElements?: dxElementWrapper): dxElementWrapper { return this._getVisibleItems($itemElements); - }, + } - _prevItem($items) { + _prevItem($items: dxElementWrapper): dxElementWrapper { const $target = this._getActiveItem(); const targetIndex = $items.index($target); const $last = $items.last(); @@ -356,9 +479,9 @@ const CollectionWidget = Widget.inherit({ } return $item; - }, + } - _nextItem($items) { + _nextItem($items: dxElementWrapper): dxElementWrapper { const $target = this._getActiveItem(true); const targetIndex = $items.index($target); const $first = $items.first(); @@ -370,13 +493,18 @@ const CollectionWidget = Widget.inherit({ } return $item; - }, + } - _selectFocusedItem($target) { + _selectFocusedItem($target: dxElementWrapper): void { + // @ts-expect-error ts-error this.selectItem($target); - }, + } - _updateFocusedItemState(target, isFocused, needCleanItemId) { + _updateFocusedItemState( + target: dxElementWrapper | Element | undefined, + isFocused: boolean, + needCleanItemId?: boolean | undefined, + ): void { const $target = $(target); if ($target.length) { @@ -386,18 +514,21 @@ const CollectionWidget = Widget.inherit({ } this._updateParentActiveDescendant(); - }, + } - _getElementClassToSkipRefreshId: noop, + // eslint-disable-next-line class-methods-use-this + _getElementClassToSkipRefreshId(): string { + return ''; + } - _shouldSkipRefreshId(target) { - const elementClass = this._getElementClassToSkipRefreshId() ?? ''; + _shouldSkipRefreshId(target: Element | dxElementWrapper): boolean { + const elementClass = this._getElementClassToSkipRefreshId(); const shouldSkipRefreshId = $(target).hasClass(elementClass); return shouldSkipRefreshId; - }, + } - _refreshActiveDescendant($target) { + _refreshActiveDescendant($target?: dxElementWrapper): void { const { focusedElement } = this.option(); if (isDefined(focusedElement)) { @@ -410,9 +541,12 @@ const CollectionWidget = Widget.inherit({ } this.setAria('activedescendant', null, $target); - }, + } - _refreshItemId($target, needCleanItemId) { + _refreshItemId( + $target: dxElementWrapper, + needCleanItemId: boolean | undefined, + ): void { const { focusedElement } = this.option(); const shouldSkipRefreshId = this._shouldSkipRefreshId($target); @@ -425,53 +559,67 @@ const CollectionWidget = Widget.inherit({ } else { this.setAria('id', null, $target); } - }, + } - _isDisabled($element) { + // eslint-disable-next-line class-methods-use-this + _isDisabled($element: dxElementWrapper): boolean { return $element && $($element).attr('aria-disabled') === 'true'; - }, + } - _setFocusedItem($target) { + _setFocusedItem($target: dxElementWrapper): void { + // eslint-disable-next-line @typescript-eslint/prefer-optional-chain if (!$target || !$target.length) { return; } this._updateFocusedItemState($target, true); + // @ts-expect-error ts-error this.onFocusedItemChanged(this.getFocusedItemId()); - + // @ts-expect-error ts-error const { selectOnFocus } = this.option(); const isTargetDisabled = this._isDisabled($target); if (selectOnFocus && !isTargetDisabled && !this._shouldSkipSelectOnFocus) { this._selectFocusedItem($target); } - }, + } - _findItemElementByItem(item) { + _findItemElementByItem(item: TItem): dxElementWrapper { let result = $(); - const that = this; - // @ts-expect-error - this.itemElements().each(function () { - const $item = $(this); - if ($item.data(that._itemDataKey()) === item) { + const itemDataKey = this._itemDataKey(); + + this.itemElements().each((index, itemElement): boolean => { + const $item = $(itemElement); + if ($item.data(itemDataKey) === item) { result = $item; return false; } + + return true; }); return result; - }, - - _getIndexByItem(item) { - return this.option('items').indexOf(item); - }, - - // eslint-disable-next-line @typescript-eslint/no-unused-vars - _itemOptionChanged(item, property, value, oldValue) { + } + + _getIndexByItem(item: TItem): number { + const { items } = this.option(); + + // @ts-expect-error ts-error + return items.indexOf(item); + } + + _itemOptionChanged( + item: TItem, + property: string, + value: unknown, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + prevValue: unknown, + ): void { const $item = this._findItemElementByItem(item); if (!$item.length) { return; } + // @ts-expect-error ts-error if (!this.constructor.ItemClass.getInstance($item).setDataField(property, value)) { this._refreshItem($item, item); } @@ -481,37 +629,52 @@ const CollectionWidget = Widget.inherit({ if (isDisabling) { this._resetItemFocus($item); } - }, + } - _resetItemFocus($item) { + _resetItemFocus($item: dxElementWrapper): void { + // @ts-expect-error ts-error if ($item.is(this.option('focusedElement'))) { this.option('focusedElement', null); } - }, + } - _refreshItem($item) { + _refreshItem( + $item: dxElementWrapper, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + item: TItem, + ): void { const itemData = this._getItemData($item); const index = $item.data(this._itemIndexKey()); + // @ts-expect-error ts-error + // eslint-disable-next-line @typescript-eslint/restrict-plus-operands this._renderItem(this._renderedItemsCount + index, itemData, null, $item); - }, + } - _updateParentActiveDescendant: noop, + // eslint-disable-next-line class-methods-use-this + _updateParentActiveDescendant(): void {} - _optionChanged(args) { - if (args.name === 'items') { - const matches = args.fullName.match(ITEM_PATH_REGEX); + _optionChanged(args: OptionChanged): void { + const { + name, value, previousValue, fullName, + } = args; - if (matches && matches.length) { + if (name === 'items') { + // @ts-expect-error ts-error + const matches = fullName.match(ITEM_PATH_REGEX); + + if (matches?.length) { const property = matches[matches.length - 1]; - const itemPath = args.fullName.replace(`.${property}`, ''); + // @ts-expect-error ts-error + const itemPath = fullName.replace(`.${property}`, ''); const item = this.option(itemPath); - this._itemOptionChanged(item, property, args.value, args.previousValue); + // @ts-expect-error ts-error + this._itemOptionChanged(item, property, value, previousValue); return; } } - switch (args.name) { + switch (name) { case 'items': case '_itemAttributes': case 'itemTemplateProperty': @@ -520,11 +683,14 @@ const CollectionWidget = Widget.inherit({ this._invalidate(); break; case 'dataSource': + // @ts-expect-error ts-error this._refreshDataSource(); + // @ts-expect-error ts-error this._renderEmptyMessage(); break; case 'noDataText': case 'encodeNoDataText': + // @ts-expect-error ts-error this._renderEmptyMessage(); break; case 'itemTemplate': @@ -543,6 +709,7 @@ const CollectionWidget = Widget.inherit({ this._attachContextMenuEvent(); break; case 'onFocusedItemChanged': + // @ts-expect-error ts-error this.onFocusedItemChanged = this._createActionByOption('onFocusedItemChanged'); break; case 'selectOnFocus': @@ -550,8 +717,8 @@ const CollectionWidget = Widget.inherit({ case 'focusOnSelectedItem': break; case 'focusedElement': - this._updateFocusedItemState(args.previousValue, false, true); - this._setFocusedItem($(args.value)); + this._updateFocusedItemState(previousValue as Element | undefined, false, true); + this._setFocusedItem($(value as Element | undefined)); break; case 'displayExpr': this._compileDisplayGetter(); @@ -563,39 +730,43 @@ const CollectionWidget = Widget.inherit({ this._invalidate(); break; default: - this.callBase(args); + super._optionChanged(args); } - }, + } - _invalidate() { + _invalidate(): void { this.option('focusedElement', null); - return this.callBase.apply(this, arguments); - }, + super._invalidate(); + } - _loadNextPage() { + _loadNextPage(): Promise { this._expectNextPageLoading(); - + // @ts-expect-error ts-error + // eslint-disable-next-line @typescript-eslint/no-unsafe-return return this._dataController.loadNextPage(); - }, + } - _expectNextPageLoading() { + _expectNextPageLoading(): void { this._startIndexForAppendedItems = 0; - }, + } - _expectLastItemLoading() { + _expectLastItemLoading(): void { this._startIndexForAppendedItems = -1; - }, + } - _forgetNextPageLoading() { + _forgetNextPageLoading(): void { this._startIndexForAppendedItems = null; - }, + } - _dataSourceChangedHandler(newItems) { + _dataSourceChangedHandler(newItems: TItem[]): void { const items = this.option('items'); if (this._initialized && items && this._shouldAppendItems()) { + // @ts-expect-error ts-error this._renderedItemsCount = items.length; + // @ts-expect-error ts-error if (!this._isLastPage() || this._startIndexForAppendedItems !== -1) { + // @ts-expect-error ts-error this.option().items = items.concat(newItems.slice(this._startIndexForAppendedItems)); } @@ -604,118 +775,134 @@ const CollectionWidget = Widget.inherit({ } else { this.option('items', newItems.slice()); } - }, + } - _refreshContent() { + _refreshContent(): void { this._prepareContent(); this._renderContent(); - }, + } - _dataSourceLoadErrorHandler() { + _dataSourceLoadErrorHandler(): void { this._forgetNextPageLoading(); this.option('items', this.option('items')); - }, + } - _shouldAppendItems() { + _shouldAppendItems(): boolean { return this._startIndexForAppendedItems != null && this._allowDynamicItemsAppend(); - }, + } - _allowDynamicItemsAppend() { + // eslint-disable-next-line class-methods-use-this + _allowDynamicItemsAppend(): boolean { return false; - }, + } - _clean() { + _clean(): void { this._cleanFocusState(); this._cleanItemContainer(); - this._inkRipple && delete this._inkRipple; + + if (this._inkRipple) { + delete this._inkRipple; + } + this._resetActiveState(); - }, + } - _cleanItemContainer() { + _cleanItemContainer(): void { $(this._itemContainer()).empty(); - }, + } - _dispose() { - this.callBase(); + _dispose(): void { + super._dispose(); clearTimeout(this._itemFocusTimeout); - }, + } - _refresh() { + _refresh(): void { this._cleanRenderedItems(); - this.callBase.apply(this, arguments); - }, + super._refresh(); + } - _itemContainer() { + _itemContainer(): dxElementWrapper { return this.$element(); - }, + } - _itemClass() { + // eslint-disable-next-line class-methods-use-this + _itemClass(): string { return ITEM_CLASS; - }, + } - _itemContentClass() { - return this._itemClass() + CONTENT_CLASS_POSTFIX; - }, + _itemContentClass(): string { + return `${this._itemClass()}${CONTENT_CLASS_POSTFIX}`; + } - _selectedItemClass() { + // eslint-disable-next-line class-methods-use-this + _selectedItemClass(): string { return SELECTED_ITEM_CLASS; - }, + } - _itemResponseWaitClass() { + // eslint-disable-next-line class-methods-use-this + _itemResponseWaitClass(): string { return ITEM_RESPONSE_WAIT_CLASS; - }, + } - _itemSelector() { + _itemSelector(): string { return `.${this._itemClass()}`; - }, + } - _itemDataKey() { + // eslint-disable-next-line class-methods-use-this + _itemDataKey(): string { return ITEM_DATA_KEY; - }, + } - _itemIndexKey() { + // eslint-disable-next-line class-methods-use-this + _itemIndexKey(): string { return ITEM_INDEX_KEY; - }, + } - _itemElements() { + _itemElements(): dxElementWrapper { return this._itemContainer().find(this._itemSelector()); - }, + } - _initMarkup() { - this.callBase(); + _initMarkup(): void { + super._initMarkup(); + // @ts-expect-error ts-error this.onFocusedItemChanged = this._createActionByOption('onFocusedItemChanged'); this.$element().addClass(COLLECTION_CLASS); this._prepareContent(); - }, + } - _prepareContent: deferRenderer(function () { - this._renderContentImpl(); - }), + _prepareContent(): void { + deferRenderer(() => { + this._renderContentImpl(); + })(); + } - _renderContent() { + _renderContent(): void { + // eslint-disable-next-line @typescript-eslint/no-floating-promises this._fireContentReadyAction(); - }, + } - _render() { - this.callBase(); + _render(): void { + super._render(); this._attachClickEvent(); this._attachHoldEvent(); this._attachContextMenuEvent(); - }, + } - _getPointerEvent() { + // eslint-disable-next-line class-methods-use-this + _getPointerEvent(): string { return pointerEvents.down; - }, + } - _attachClickEvent() { + _attachClickEvent(): void { const itemSelector = this._itemSelector(); const pointerEvent = this._getPointerEvent(); - + // @ts-expect-error ts-error const clickEventNamespace = addNamespace(clickEventName, this.NAME); + // @ts-expect-error ts-error const pointerEventNamespace = addNamespace(pointerEvent, this.NAME); const pointerAction = new Action((args) => { @@ -724,8 +911,8 @@ const CollectionWidget = Widget.inherit({ this._itemPointerDownHandler(event); }); - const clickEventCallback = (e) => this._itemClickHandler(e); - const pointerEventCallback = (e) => { + const clickEventCallback = (e): void => this._itemClickHandler(e); + const pointerEventCallback = (e): void => { pointerAction.execute({ element: $(e.target), event: e, @@ -735,21 +922,29 @@ const CollectionWidget = Widget.inherit({ eventsEngine.off(this._itemContainer(), clickEventNamespace, itemSelector); eventsEngine.off(this._itemContainer(), pointerEventNamespace, itemSelector); eventsEngine.on(this._itemContainer(), clickEventNamespace, itemSelector, clickEventCallback); - eventsEngine.on(this._itemContainer(), pointerEventNamespace, itemSelector, pointerEventCallback); - }, - - _itemClickHandler(e, args, config) { + eventsEngine.on( + this._itemContainer(), + pointerEventNamespace, + itemSelector, + pointerEventCallback, + ); + } + + _itemClickHandler( + e: DxEvent, + args?: Record, + config?: ActionConfig, + ): void { this._itemDXEventHandler(e, 'onItemClick', args, config); - }, + } - _itemPointerDownHandler(e) { + _itemPointerDownHandler(e: DxEvent): void { if (!this.option('focusStateEnabled')) { return; } - - this._itemFocusHandler = function () { + this._itemFocusHandler = (): void => { clearTimeout(this._itemFocusTimeout); - this._itemFocusHandler = null; + this._itemFocusHandler = undefined; if (e.isDefaultPrevented()) { return; @@ -765,168 +960,223 @@ const CollectionWidget = Widget.inherit({ this.option('focusedElement', getPublicElement($closestItem)); this._shouldSkipSelectOnFocus = false; } - }.bind(this); - - this._itemFocusTimeout = setTimeout(this._forcePointerDownFocus.bind(this)); - }, + }; - _closestFocusable($target) { + // eslint-disable-next-line no-restricted-globals + this._itemFocusTimeout = setTimeout( + this._forcePointerDownFocus.bind(this), + ); + } + + // eslint-disable-next-line class-methods-use-this + _closestFocusable( + $target: dxElementWrapper, + ): dxElementWrapper | undefined { + // @ts-expect-error ts-error if ($target.is(focusable)) { return $target; } - $target = $target.parent(); - while ($target.length && !domAdapter.isDocument($target.get(0)) && !domAdapter.isDocumentFragment($target.get(0))) { - if ($target.is(focusable)) { - return $target; + let $nextTarget = $target.parent(); + while ($nextTarget.length + && !domAdapter.isDocument($nextTarget.get(0)) + && !domAdapter.isDocumentFragment($nextTarget.get(0)) + ) { + // @ts-expect-error ts-error + if ($nextTarget.is(focusable)) { + return $nextTarget; } - $target = $target.parent(); + $nextTarget = $nextTarget.parent(); } - }, - _forcePointerDownFocus() { - this._itemFocusHandler && this._itemFocusHandler(); - }, + return undefined; + } - _updateFocusState() { - this.callBase.apply(this, arguments); + _forcePointerDownFocus(): void { + if (this._itemFocusHandler) { + this._itemFocusHandler(); + } + } + + _updateFocusState(e: DxEvent, isFocused: boolean): void { + super._updateFocusState(e, isFocused); this._forcePointerDownFocus(); - }, + } - _attachHoldEvent() { + _attachHoldEvent(): void { const $itemContainer = this._itemContainer(); const itemSelector = this._itemSelector(); + // @ts-expect-error ts-error const eventName = addNamespace(holdEvent.name, this.NAME); eventsEngine.off($itemContainer, eventName, itemSelector); - // @ts-expect-error - eventsEngine.on($itemContainer, eventName, itemSelector, { timeout: this._getHoldTimeout() }, this._itemHoldHandler.bind(this)); - }, - - _getHoldTimeout() { - return this.option('itemHoldTimeout'); - }, - - _shouldFireHoldEvent() { + eventsEngine.on( + $itemContainer, + eventName, + itemSelector, + { timeout: this._getHoldTimeout() }, + // @ts-expect-error ts-error + this._itemHoldHandler.bind(this), + ); + } + + _getHoldTimeout(): number | undefined { + const { itemHoldTimeout } = this.option(); + + return itemHoldTimeout; + } + + _shouldFireHoldEvent(): boolean { return this.hasActionSubscription('onItemHold'); - }, + } - _itemHoldHandler(e) { + _itemHoldHandler(e: DxEvent & Cancelable): void { if (this._shouldFireHoldEvent()) { this._itemDXEventHandler(e, 'onItemHold'); } else { e.cancel = true; } - }, + } - _attachContextMenuEvent() { + _attachContextMenuEvent(): void { const $itemContainer = this._itemContainer(); const itemSelector = this._itemSelector(); + // @ts-expect-error ts-error const eventName = addNamespace(contextMenuEventName, this.NAME); eventsEngine.off($itemContainer, eventName, itemSelector); - eventsEngine.on($itemContainer, eventName, itemSelector, this._itemContextMenuHandler.bind(this)); - }, - - _shouldFireContextMenuEvent() { + eventsEngine.on( + $itemContainer, + eventName, + itemSelector, + this._itemContextMenuHandler.bind(this), + ); + } + + _shouldFireContextMenuEvent(): boolean { return this.hasActionSubscription('onItemContextMenu'); - }, + } - _itemContextMenuHandler(e) { + _itemContextMenuHandler(e: DxEvent & Cancelable): void { if (this._shouldFireContextMenuEvent()) { this._itemDXEventHandler(e, 'onItemContextMenu'); } else { e.cancel = true; } - }, + } + + _renderContentImpl(): void { + const { items } = this.option(); + const itemsToRender = items ?? []; - _renderContentImpl() { - const items = this.option('items') || []; if (this._renderedItemsCount) { - this._renderItems(items.slice(this._renderedItemsCount)); + this._renderItems(itemsToRender.slice(this._renderedItemsCount)); } else { - this._renderItems(items); + this._renderItems(itemsToRender); } - }, + } - _renderItems(items) { + _renderItems(items: TItem[]): void { if (items.length) { each(items, (index, itemData) => { + // @ts-expect-error ts-error + // eslint-disable-next-line @typescript-eslint/restrict-plus-operands this._renderItem(this._renderedItemsCount + index, itemData); }); } - + // @ts-expect-error ts-error this._renderEmptyMessage(); - }, + } - _getItemsContainer() { + _getItemsContainer(): dxElementWrapper { return this._itemContainer(); - }, + } - _setAttributes($element) { + _setAttributes($element: dxElementWrapper): void { const attributes = { ...this.option('_itemAttributes') }; + // @ts-expect-error ts-error const { class: customClassValue } = attributes; if (customClassValue) { const currentClassValue = $element.get(0).className; - + // @ts-expect-error ts-error attributes.class = [currentClassValue, customClassValue].join(' '); } - + // @ts-expect-error ts-error $element.attr(attributes); - }, - - _renderItem(index, itemData, $container, $itemToReplace) { + } + + _renderItem( + index: { group: number; item: number } | number, + itemData: TItem, + $container: dxElementWrapper | null, + $itemToReplace?: dxElementWrapper, + ): dxElementWrapper { + // @ts-expect-error ts-error const itemIndex = index?.item ?? index; - $container = $container || this._getItemsContainer(); - const $itemFrame = this._renderItemFrame(itemIndex, itemData, $container, $itemToReplace); + const $containerToRender = $container ?? this._getItemsContainer(); + const $itemFrame = this._renderItemFrame( + itemIndex, + itemData, + $containerToRender, + $itemToReplace, + ); this._setElementData($itemFrame, itemData, itemIndex); this._setAttributes($itemFrame); this._attachItemClickEvent(itemData, $itemFrame); const $itemContent = this._getItemContent($itemFrame); + const { itemTemplate } = this.option(); + const renderContentPromise = this._renderItemContent({ index: itemIndex, itemData, container: getPublicElement($itemContent), contentClass: this._itemContentClass(), - defaultTemplateName: this.option('itemTemplate'), + defaultTemplateName: itemTemplate, }); - const that = this; - when(renderContentPromise).done(($itemContent) => { - that._postprocessRenderItem({ + // eslint-disable-next-line @typescript-eslint/no-floating-promises + when(renderContentPromise).done(($content) => { + this._postprocessRenderItem({ itemElement: $itemFrame, - itemContent: $itemContent, + itemContent: $content, itemData, itemIndex, }); - that._executeItemRenderAction(index, itemData, getPublicElement($itemFrame)); + // @ts-expect-error ts-error + this._executeItemRenderAction(index, itemData, getPublicElement($itemFrame)); }); return $itemFrame; - }, + } - _getItemContent($itemFrame) { + // eslint-disable-next-line class-methods-use-this + _getItemContent($itemFrame: dxElementWrapper): dxElementWrapper { const $itemContent = $itemFrame.find(`.${ITEM_CONTENT_PLACEHOLDER_CLASS}`); $itemContent.removeClass(ITEM_CONTENT_PLACEHOLDER_CLASS); return $itemContent; - }, + } - _attachItemClickEvent(itemData, $itemElement) { + _attachItemClickEvent(itemData: TItem, $itemElement: dxElementWrapper): void { + // @ts-expect-error ts-error + // eslint-disable-next-line @typescript-eslint/prefer-optional-chain if (!itemData || !itemData.onClick) { return; } eventsEngine.on($itemElement, clickEventName, (e) => { + // @ts-expect-error ts-error this._itemEventHandlerByHandler($itemElement, itemData.onClick, { event: e, }); }); - }, + } - _renderItemContent(args) { + _renderItemContent( + args: ItemRenderInfo, + ): dxElementWrapper | DeferredObj { const itemTemplateName = this._getItemTemplateName(args); const itemTemplate = this._getTemplate(itemTemplateName); @@ -937,221 +1187,306 @@ const CollectionWidget = Widget.inherit({ } return this._renderItemContentByNode(args, $templateResult); - }, + } - _renderItemContentByNode(args, $node) { + _renderItemContentByNode( + args: ItemRenderInfo, + $node: dxElementWrapper, + ): dxElementWrapper { $(args.container).replaceWith($node); args.container = getPublicElement($node); this._addItemContentClasses(args); return $node; - }, + } - _addItemContentClasses(args) { + // eslint-disable-next-line class-methods-use-this + _addItemContentClasses(args: ItemRenderInfo): void { const classes = [ ITEM_CLASS + CONTENT_CLASS_POSTFIX, args.contentClass, ]; $(args.container).addClass(classes.join(' ')); - }, - - // eslint-disable-next-line @typescript-eslint/no-unused-vars - _appendItemToContainer($container, $itemFrame, index) { + } + + // eslint-disable-next-line class-methods-use-this + _appendItemToContainer( + $container: dxElementWrapper, + $itemFrame: dxElementWrapper, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + index: number, + ): void { $itemFrame.appendTo($container); - }, - - _renderItemFrame(index, itemData, $container, $itemToReplace) { + } + + _renderItemFrame( + index: number, + itemData: TItem, + $container: dxElementWrapper, + $itemToReplace?: dxElementWrapper, + ): dxElementWrapper { const $itemFrame = $('
'); + // @ts-expect-error ts-error // eslint-disable-next-line no-new new this.constructor.ItemClass($itemFrame, this._itemOptions(), itemData || {}); - if ($itemToReplace && $itemToReplace.length) { + if ($itemToReplace?.length) { $itemToReplace.replaceWith($itemFrame); } else { this._appendItemToContainer.call(this, $container, $itemFrame, index); } if (this.option('useItemTextAsTitle')) { + // @ts-expect-error ts-error const displayValue = this._displayGetter ? this._displayGetter(itemData) : itemData; $itemFrame.attr('title', displayValue); } return $itemFrame; - }, + } - _itemOptions() { - const that = this; + _itemOptions(): Record { return { - watchMethod() { - return that.option('integrationOptions.watchMethod'); - }, - owner: that, - fieldGetter(field) { - const expr = that.option(`${field}Expr`); + watchMethod: () => this.option('integrationOptions.watchMethod'), + owner: this, + fieldGetter: (field): unknown => { + const expr = this.option(`${field}Expr`); + // @ts-expect-error ts-error const getter = compileGetter(expr); return getter; }, }; - }, - - _postprocessRenderItem: noop, - - _executeItemRenderAction(index, itemData, itemElement) { + } + + // eslint-disable-next-line class-methods-use-this + _postprocessRenderItem( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + args: { + itemElement: dxElementWrapper; + itemContent: dxElementWrapper; + itemData: TItem; + itemIndex: number; + }, + ): void {} + + _executeItemRenderAction( + index: number, + itemData: TItem, + itemElement: HTMLElement, + ): void { this._getItemRenderAction()({ itemElement, itemIndex: index, itemData, }); - }, + } - _setElementData(element, data, index) { + _setElementData( + element: dxElementWrapper, + data: TItem, + index: number, + ): void { element .addClass([ITEM_CLASS, this._itemClass()].join(' ')) .data(this._itemDataKey(), data) .data(this._itemIndexKey(), index); - }, + } - _createItemRenderAction() { - // eslint-disable-next-line no-return-assign - return (this._itemRenderAction = this._createActionByOption('onItemRendered', { + _createItemRenderAction(): (event?: Partial & ItemInfo>) => void { + this._itemRenderAction = this._createActionByOption('onItemRendered', { element: this.element(), excludeValidators: ['disabled', 'readOnly'], category: 'rendering', - })); - }, + }); - _getItemRenderAction() { - return this._itemRenderAction || this._createItemRenderAction(); - }, + return this._itemRenderAction; + } - _getItemTemplateName(args) { + _getItemRenderAction(): (event?: Partial & ItemInfo>) => void { + return this._itemRenderAction ?? this._createItemRenderAction(); + } + + _getItemTemplateName( + args: ItemRenderInfo, + ): ItemTemplate { const data = args.itemData; + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const templateProperty = args.templateProperty || this.option('itemTemplateProperty'); + // @ts-expect-error ts-error + // eslint-disable-next-line @typescript-eslint/prefer-optional-chain const template = data && data[templateProperty]; + // eslint-disable-next-line @typescript-eslint/no-unsafe-return return template || args.defaultTemplateName; - }, - - _createItemByTemplate(itemTemplate, renderArgs) { + } + + // eslint-disable-next-line max-len + // eslint-disable-next-line @typescript-eslint/explicit-function-return-type, @typescript-eslint/explicit-module-boundary-types + _createItemByTemplate( + // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types + itemTemplate, + renderArgs: ItemRenderInfo, + ) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-return return itemTemplate.render({ model: renderArgs.itemData, container: renderArgs.container, index: renderArgs.index, onRendered: this._onItemTemplateRendered(itemTemplate, renderArgs), }); - }, - - _onItemTemplateRendered() { - return noop; - }, - - _emptyMessageContainer() { + } + + // eslint-disable-next-line class-methods-use-this + _onItemTemplateRendered( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + itemTemplate: { source: () => unknown }, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + renderArgs: { itemData: unknown }, + ): () => void { + return (): void => {}; + } + + _emptyMessageContainer(): dxElementWrapper { return this._itemContainer(); - }, + } - _renderEmptyMessage(items) { + _renderEmptyMessage(items: TItem[]): void { + // eslint-disable-next-line no-param-reassign items = items || this.option('items'); const noDataText = this.option('noDataText'); + // @ts-expect-error ts-error + // eslint-disable-next-line @typescript-eslint/prefer-optional-chain const hideNoData = !noDataText || (items && items.length) || this._dataController.isLoading(); if (hideNoData && this._$noData) { this._$noData.remove(); + // @ts-expect-error ts-error this._$noData = null; this.setAria('label', undefined); } if (!hideNoData) { - this._$noData = this._$noData || $('
').addClass('dx-empty-message'); + this._$noData = this._$noData ?? $('
').addClass('dx-empty-message'); this._$noData.appendTo(this._emptyMessageContainer()); if (this.option('encodeNoDataText')) { + // @ts-expect-error ts-error this._$noData.text(noDataText); } else { + // @ts-expect-error ts-error this._$noData.html(noDataText); } } this.$element().toggleClass(EMPTY_COLLECTION, !hideNoData); - }, - - _itemDXEventHandler(dxEvent, handlerOptionName, actionArgs, actionConfig) { + } + + _itemDXEventHandler( + dxEvent: DxEvent, + handlerOptionName: string, + actionArgs?: Record, + actionConfig?: ActionConfig, + ): void { this._itemEventHandler(dxEvent.target, handlerOptionName, extend(actionArgs, { event: dxEvent, }), actionConfig); - }, - - _itemEventHandler(initiator, handlerOptionName, actionArgs, actionConfig) { + } + + _itemEventHandler( + initiator: dxElementWrapper | Element, + handlerOptionName: string, + actionArgs: Record, + actionConfig?: ActionConfig, + ): void { const action = this._createActionByOption(handlerOptionName, extend({ validatingTargetName: 'itemElement', }, actionConfig)); return this._itemEventHandlerImpl(initiator, action, actionArgs); - }, - - _itemEventHandlerByHandler(initiator, handler, actionArgs, actionConfig) { + } + + _itemEventHandlerByHandler( + initiator: dxElementWrapper | Element, + handler: () => void, + actionArgs: Record, + actionConfig: ActionConfig, + ): void { const action = this._createAction(handler, extend({ validatingTargetName: 'itemElement', }, actionConfig)); return this._itemEventHandlerImpl(initiator, action, actionArgs); - }, + } - _itemEventHandlerImpl(initiator, action, actionArgs) { + _itemEventHandlerImpl( + initiator: dxElementWrapper | Element, + action: (event?: Record) => void, + actionArgs: ActionConfig, + ): void { const $itemElement = this._closestItemElement($(initiator)); const args = extend({}, actionArgs); return action(extend(actionArgs, this._extendActionArgs($itemElement), args)); - }, + } - _extendActionArgs($itemElement) { + _extendActionArgs($itemElement: dxElementWrapper): ItemInfo { return { itemElement: getPublicElement($itemElement), itemIndex: this._itemElements().index($itemElement), itemData: this._getItemData($itemElement), }; - }, + } - _closestItemElement($element) { + _closestItemElement($element: dxElementWrapper): dxElementWrapper { return $($element).closest(this._itemSelector()); - }, + } - _getItemData(itemElement) { + _getItemData(itemElement: Element | dxElementWrapper): TItem { + // @ts-expect-error ts-error return $(itemElement).data(this._itemDataKey()); - }, - - _getSummaryItemsSize(dimension, items, includeMargin) { + } + + // eslint-disable-next-line class-methods-use-this + _getSummaryItemsSize( + dimension: string, + items: dxElementWrapper, + includeMargin?: boolean, + ): number { let result = 0; if (items) { each(items, (_, item) => { if (dimension === 'width') { - result += getOuterWidth(item, includeMargin || false); + result += getOuterWidth(item, includeMargin ?? false); } else if (dimension === 'height') { - result += getOuterHeight(item, includeMargin || false); + result += getOuterHeight(item, includeMargin ?? false); } }); } return result; - }, + } - getFocusedItemId() { + getFocusedItemId(): string { if (!this._focusedItemId) { this._focusedItemId = `dx-${new Guid()}`; } return this._focusedItemId; - }, + } - itemElements() { + itemElements(): dxElementWrapper { return this._itemElements(); - }, + } - itemsContainer() { + itemsContainer(): dxElementWrapper { return this._itemContainer(); - }, + } +} -}).include(DataHelperMixin); +// eslint-disable-next-line @typescript-eslint/no-explicit-any +(CollectionWidget as any).include(DataHelperMixin); +// @ts-expect-error ts-error CollectionWidget.ItemClass = CollectionWidgetItem; export default CollectionWidget; diff --git a/packages/devextreme/js/__internal/ui/collection/m_collection_widget.edit.ts b/packages/devextreme/js/__internal/ui/collection/m_collection_widget.edit.ts index 2a6f79d24a2e..824a6a420aaf 100644 --- a/packages/devextreme/js/__internal/ui/collection/m_collection_widget.edit.ts +++ b/packages/devextreme/js/__internal/ui/collection/m_collection_widget.edit.ts @@ -14,9 +14,9 @@ import { extend } from '@js/core/utils/extend'; import { each } from '@js/core/utils/iterator'; import { isDefined } from '@js/core/utils/type'; import errors from '@js/ui/widget/ui.errors'; +import BaseCollectionWidget from '@ts/ui/collection/m_collection_widget.base'; import Selection from '@ts/ui/selection/m_selection'; -import BaseCollectionWidget from './m_collection_widget.base'; import PlainEditStrategy from './m_collection_widget.edit.strategy.plain'; const ITEM_DELETING_DATA_KEY = 'dxItemDeleting'; @@ -25,7 +25,7 @@ const NOT_EXISTING_INDEX = -1; const indexExists = function (index) { return index !== NOT_EXISTING_INDEX; }; - +// @ts-expect-error const CollectionWidget = BaseCollectionWidget.inherit({ _setOptionsByReference() { diff --git a/packages/devextreme/js/__internal/ui/context_menu/m_context_menu.ts b/packages/devextreme/js/__internal/ui/context_menu/m_context_menu.ts index ec4cf6cfe046..a7568ab671a9 100644 --- a/packages/devextreme/js/__internal/ui/context_menu/m_context_menu.ts +++ b/packages/devextreme/js/__internal/ui/context_menu/m_context_menu.ts @@ -1007,7 +1007,6 @@ class ContextMenu extends MenuBase { this._overlay.$content().addClass(this._widgetClass()); this._renderFocusState(); this._attachHoverEvents(); - // @ts-expect-error this._attachClickEvent(); this._renderItems(this._dataAdapter.getRootNodes()); } diff --git a/packages/devextreme/js/__internal/ui/context_menu/m_menu_base.ts b/packages/devextreme/js/__internal/ui/context_menu/m_menu_base.ts index e952c338c7fa..97f36ada33a3 100644 --- a/packages/devextreme/js/__internal/ui/context_menu/m_menu_base.ts +++ b/packages/devextreme/js/__internal/ui/context_menu/m_menu_base.ts @@ -7,7 +7,7 @@ import { extend } from '@js/core/utils/extend'; import { each } from '@js/core/utils/iterator'; import { isDefined, isObject, isPlainObject } from '@js/core/utils/type'; import type { dxMenuBaseOptions } from '@js/ui/context_menu/ui.menu_base'; -import type { Item } from '@js/ui/menu'; +import type { Item, SubmenuShowMode } from '@js/ui/menu'; import { render } from '@js/ui/widget/utils.ink_ripple'; import HierarchicalCollectionWidget from '@ts/ui/collection/hierarchical'; import MenuItem from '@ts/ui/collection/m_item'; @@ -36,6 +36,7 @@ const DX_MENU_ITEM_CAPTION_URL_CLASS = `${DX_MENU_ITEM_CAPTION_CLASS}-with-url`; const DX_ICON_WITH_URL_CLASS = 'dx-icon-with-url'; const ITEM_URL_CLASS = 'dx-item-url'; +// @ts-expect-error ts-error export type Properties = dxMenuBaseOptions; class MenuBase extends HierarchicalCollectionWidget { @@ -45,12 +46,7 @@ class MenuBase extends HierarchicalCollectionWidget { hasIcons?: boolean; - _inkRipple?: { - showWave: (args: any) => void; - hideWave: (args: any) => void; - }; - - _showSubmenusTimeout?: any; + _showSubmenusTimeout?: ReturnType; _getDefaultOptions() { return extend(super._getDefaultOptions(), { @@ -144,9 +140,9 @@ class MenuBase extends HierarchicalCollectionWidget { } _init(): void { - // @ts-expect-error - this._activeStateUnit = `.${ITEM_CLASS}`; super._init(); + this._activeStateUnit = `.${ITEM_CLASS}`; + this._renderSelectedItem(); this._initActions(); } @@ -283,13 +279,13 @@ class MenuBase extends HierarchicalCollectionWidget { } } - _getShowSubmenuMode() { + _getShowSubmenuMode(): SubmenuShowMode | undefined { const defaultValue = 'onClick'; - let optionValue = this.option('showSubmenuMode'); - // @ts-expect-error - optionValue = isObject(optionValue) ? optionValue.name : optionValue; + const { showSubmenuMode } = this.option(); - return this._isDesktopDevice() ? optionValue : defaultValue; + const showMode = isObject(showSubmenuMode) ? showSubmenuMode.name : showSubmenuMode; + + return this._isDesktopDevice() ? showMode : defaultValue; } _initSelectedItems() {} @@ -319,7 +315,7 @@ class MenuBase extends HierarchicalCollectionWidget { if (!$itemElement || this._isItemDisabled($itemElement)) return; e.stopPropagation(); - // @ts-expect-error + if (this._getShowSubmenuMode() === 'onHover') { clearTimeout(this._showSubmenusTimeout); this._showSubmenusTimeout = setTimeout(this._showSubmenu.bind(this, $itemElement), this._getSubmenuDelay('show')); @@ -488,12 +484,12 @@ class MenuBase extends HierarchicalCollectionWidget { _refreshItem($item: dxElementWrapper, item: Item): void { const node = this._dataAdapter.getNodeByItem(item); + // @ts-expect-error - const index = $item.data(this._itemIndexKey()); + const index: number = $item.data(this._itemIndexKey()); const $nodeContainer = $item.closest('ul'); const $nodeElement = $item.closest('li'); - // @ts-expect-error this._renderItem(index, node, $nodeContainer, $nodeElement); } @@ -558,7 +554,6 @@ class MenuBase extends HierarchicalCollectionWidget { const itemClickActionHandler = this._createAction(this._updateSubmenuVisibilityOnClick.bind(this)); this._itemDXEventHandler(e, 'onItemClick', {}, { beforeExecute: this._itemClick, - // @ts-expect-error afterExecute: itemClickActionHandler.bind(this), }); e._skipHandling = true; @@ -692,7 +687,7 @@ class MenuBase extends HierarchicalCollectionWidget { }); } - selectItem(itemElement): void { + selectItem(itemElement: Element): void { const itemData = itemElement.nodeType ? this._getItemData(itemElement) : itemElement; const selectedKey = this._dataAdapter.getSelectedNodesKeys()[0]; const selectedItem = this.option('selectedItem'); @@ -708,7 +703,7 @@ class MenuBase extends HierarchicalCollectionWidget { } } - unselectItem(itemElement): void { + unselectItem(itemElement: Element): void { const itemData = itemElement.nodeType ? this._getItemData(itemElement) : itemElement; const node = this._dataAdapter.getNodeByItem(itemData); const selectedItem = this.option('selectedItem'); diff --git a/packages/devextreme/js/__internal/ui/editor/editor.ts b/packages/devextreme/js/__internal/ui/editor/editor.ts index 25d36592c809..afbd4c7d2e87 100644 --- a/packages/devextreme/js/__internal/ui/editor/editor.ts +++ b/packages/devextreme/js/__internal/ui/editor/editor.ts @@ -9,6 +9,7 @@ import $ from '@js/core/renderer'; import Callbacks from '@js/core/utils/callbacks'; import { extend } from '@js/core/utils/extend'; import { hasWindow } from '@js/core/utils/window'; +import type { DxEvent } from '@js/events'; import type PublicEditor from '@js/ui/editor/editor'; import type { EditorOptions, @@ -192,7 +193,7 @@ class Editor< this._valueChangeEventInstance = e; } - _focusInHandler(e: NativeEventInfo): void { + _focusInHandler(e: DxEvent): void { const { validationMessageMode } = this.option(); const isValidationMessageShownOnFocus = validationMessageMode === 'auto'; diff --git a/packages/devextreme/js/__internal/ui/list/m_list.base.ts b/packages/devextreme/js/__internal/ui/list/m_list.base.ts index 5ef4607c8288..048ce80b73c2 100644 --- a/packages/devextreme/js/__internal/ui/list/m_list.base.ts +++ b/packages/devextreme/js/__internal/ui/list/m_list.base.ts @@ -58,9 +58,6 @@ const groupItemsGetter = compileGetter('items'); let _scrollView; export const ListBase = CollectionWidget.inherit({ - - _activeStateUnit: [LIST_ITEM_SELECTOR, SELECT_ALL_ITEM_SELECTOR].join(','), - _supportedKeys() { const that = this; @@ -395,8 +392,10 @@ export const ListBase = CollectionWidget.inherit({ }, _init() { - this._updateActiveStateUnit(); this.callBase(); + + this._updateActiveStateUnit(); + this._dataController.resetDataSourcePageIndex(); this._$container = this.$element(); diff --git a/packages/devextreme/js/__internal/ui/m_accordion.ts b/packages/devextreme/js/__internal/ui/m_accordion.ts index 9dff961f85a7..63e6a649639f 100644 --- a/packages/devextreme/js/__internal/ui/m_accordion.ts +++ b/packages/devextreme/js/__internal/ui/m_accordion.ts @@ -30,9 +30,6 @@ const ACCORDION_ITEM_TITLE_CAPTION_CLASS = 'dx-accordion-item-title-caption'; const ACCORDION_ITEM_DATA_KEY = 'dxAccordionItemData'; const Accordion = CollectionWidget.inherit({ - - _activeStateUnit: `.${ACCORDION_ITEM_CLASS}`, - _getDefaultOptions() { return extend(this.callBase(), { @@ -91,6 +88,8 @@ const Accordion = CollectionWidget.inherit({ _init() { this.callBase(); + this._activeStateUnit = `.${ACCORDION_ITEM_CLASS}`; + this.option('selectionRequired', !this.option('collapsible')); this.option('selectionMode', this.option('multiple') ? 'multiple' : 'single'); diff --git a/packages/devextreme/js/__internal/ui/m_gallery.ts b/packages/devextreme/js/__internal/ui/m_gallery.ts index da1f5b71aff6..bebb9d2df665 100644 --- a/packages/devextreme/js/__internal/ui/m_gallery.ts +++ b/packages/devextreme/js/__internal/ui/m_gallery.ts @@ -92,7 +92,6 @@ const GalleryNavButton = Widget.inherit({ const Gallery = CollectionWidget.inherit({ - _activeStateUnit: GALLERY_ITEM_SELECTOR, _wasAnyItemTemplateRendered: false, _getDefaultOptions() { @@ -138,6 +137,7 @@ const Gallery = CollectionWidget.inherit({ _init() { this.callBase(); + this._activeStateUnit = GALLERY_ITEM_SELECTOR; this.option('loopItemFocus', this.option('loop')); }, diff --git a/packages/devextreme/js/__internal/ui/m_multi_view.ts b/packages/devextreme/js/__internal/ui/m_multi_view.ts index 7a8ad4f3ae99..d8014ddce78d 100644 --- a/packages/devextreme/js/__internal/ui/m_multi_view.ts +++ b/packages/devextreme/js/__internal/ui/m_multi_view.ts @@ -30,9 +30,6 @@ const toNumber = (value) => +value; const position = ($element) => locate($element).left; const MultiView = CollectionWidget.inherit({ - - _activeStateUnit: `.${MULTIVIEW_ITEM_CLASS}`, - _supportedKeys() { return extend(this.callBase(), { pageUp: noop, @@ -137,6 +134,8 @@ const MultiView = CollectionWidget.inherit({ _init() { this.callBase.apply(this, arguments); + this._activeStateUnit = `.${MULTIVIEW_ITEM_CLASS}`; + const $element = this.$element(); $element.addClass(MULTIVIEW_CLASS); diff --git a/packages/devextreme/js/__internal/ui/m_tile_view.ts b/packages/devextreme/js/__internal/ui/m_tile_view.ts index 53e568889378..f57753a1e769 100644 --- a/packages/devextreme/js/__internal/ui/m_tile_view.ts +++ b/packages/devextreme/js/__internal/ui/m_tile_view.ts @@ -51,9 +51,6 @@ const CONFIGS = { }; const TileView = CollectionWidget.inherit({ - - _activeStateUnit: TILEVIEW_ITEM_SELECTOR, - _getDefaultOptions() { return extend(this.callBase(), { items: null, @@ -105,6 +102,8 @@ const TileView = CollectionWidget.inherit({ _init() { this.callBase(); + this._activeStateUnit = TILEVIEW_ITEM_SELECTOR; + this.$element().addClass(TILEVIEW_CLASS); this._initScrollView(); }, diff --git a/packages/devextreme/js/__internal/ui/menu/m_menu.ts b/packages/devextreme/js/__internal/ui/menu/m_menu.ts index f5b418ffbceb..57e61d6be877 100644 --- a/packages/devextreme/js/__internal/ui/menu/m_menu.ts +++ b/packages/devextreme/js/__internal/ui/menu/m_menu.ts @@ -427,6 +427,7 @@ class Menu extends MenuBase { }); return extend(menuOptions, { + // @ts-expect-error dataSource: this.getDataSource(), animationEnabled: !!this.option('animation'), onItemClick: this._treeviewItemClickHandler.bind(this), diff --git a/packages/devextreme/js/__internal/ui/radio_group/m_radio_collection.ts b/packages/devextreme/js/__internal/ui/radio_group/m_radio_collection.ts index 02cd9fb1ecdb..6a446dec87e6 100644 --- a/packages/devextreme/js/__internal/ui/radio_group/m_radio_collection.ts +++ b/packages/devextreme/js/__internal/ui/radio_group/m_radio_collection.ts @@ -4,8 +4,7 @@ import { deferRender } from '@js/core/utils/common'; import { extend } from '@js/core/utils/extend'; import DataExpressionMixin from '@js/ui/editor/ui.data_expression'; import CollectionWidget from '@ts/ui/collection/edit'; - -import type { TypedCollectionWidgetOptions } from '../collection/base'; +import type { CollectionWidgetBaseProperties } from '@ts/ui/collection/m_collection_widget.base'; const RADIO_BUTTON_CHECKED_CLASS = 'dx-radiobutton-checked'; const RADIO_BUTTON_ICON_CHECKED_CLASS = 'dx-radiobutton-icon-checked'; @@ -14,7 +13,7 @@ const RADIO_BUTTON_ICON_DOT_CLASS = 'dx-radiobutton-icon-dot'; const RADIO_VALUE_CONTAINER_CLASS = 'dx-radio-value-container'; const RADIO_BUTTON_CLASS = 'dx-radiobutton'; -export type Properties = TypedCollectionWidgetOptions; +export type Properties = CollectionWidgetBaseProperties; class RadioCollection extends CollectionWidget { _focusTarget(): dxElementWrapper { @@ -44,7 +43,7 @@ class RadioCollection extends CollectionWidget { }); } - _keyboardEventBindingTarget() { + _keyboardEventBindingTarget(): dxElementWrapper { return this._focusTarget(); } @@ -106,6 +105,7 @@ class RadioCollection extends CollectionWidget { return this._itemContainer().children(this._itemSelector()); } + // eslint-disable-next-line class-methods-use-this _setAriaSelectionAttribute(): void {} } diff --git a/packages/devextreme/js/__internal/ui/radio_group/m_radio_group.ts b/packages/devextreme/js/__internal/ui/radio_group/m_radio_group.ts index 2cccfe5a7ad5..5ddb57de57bb 100644 --- a/packages/devextreme/js/__internal/ui/radio_group/m_radio_group.ts +++ b/packages/devextreme/js/__internal/ui/radio_group/m_radio_group.ts @@ -87,9 +87,7 @@ class RadioGroup extends Editor { _init(): void { super._init(); - // @ts-expect-error this._activeStateUnit = `.${RADIO_BUTTON_CLASS}`; - // @ts-expect-error this._feedbackHideTimeout = RADIO_FEEDBACK_HIDE_TIMEOUT; // @ts-expect-error this._initDataExpressions(); diff --git a/packages/devextreme/js/__internal/ui/slider/m_slider.ts b/packages/devextreme/js/__internal/ui/slider/m_slider.ts index cbd72f849fa1..6ed431d3a95a 100644 --- a/packages/devextreme/js/__internal/ui/slider/m_slider.ts +++ b/packages/devextreme/js/__internal/ui/slider/m_slider.ts @@ -35,9 +35,6 @@ const INVALID_MESSAGE_VISIBLE_CLASS = 'dx-invalid-message-visible'; const SLIDER_VALIDATION_NAMESPACE = 'Validation'; const Slider = TrackBar.inherit({ - - _activeStateUnit: SLIDER_HANDLE_SELECTOR, - _supportedKeys() { const isRTL = this.option('rtlEnabled'); @@ -155,6 +152,12 @@ const Slider = TrackBar.inherit({ }); }, + _init() { + this.callBase(); + + this._activeStateUnit = SLIDER_HANDLE_SELECTOR; + }, + _toggleValidationMessage(visible) { if (!this.option('isValid')) { this.$element() diff --git a/packages/devextreme/js/__internal/ui/splitter/splitter.ts b/packages/devextreme/js/__internal/ui/splitter/splitter.ts index de6c761beb85..aa17f45c8db0 100644 --- a/packages/devextreme/js/__internal/ui/splitter/splitter.ts +++ b/packages/devextreme/js/__internal/ui/splitter/splitter.ts @@ -25,9 +25,10 @@ import type { ResizeEvent, ResizeStartEvent, } from '@js/ui/splitter'; +import type { OptionChanged } from '@ts/core/widget/types'; import CollectionWidget from '@ts/ui/collection/live_update'; +import type { CollectionWidgetBaseProperties, ItemRenderInfo } from '@ts/ui/collection/m_collection_widget.base'; -import type { TypedCollectionWidgetOptions } from '../collection/base'; import type ResizeHandle from './resize_handle'; import type { ResizeHandleOptions } from './resize_handle'; import { RESIZE_HANDLE_CLASS } from './resize_handle'; @@ -96,8 +97,8 @@ export interface Properties< TKey = any, > extends PublicProperties, Omit< - TypedCollectionWidgetOptions, - keyof PublicProperties & keyof TypedCollectionWidgetOptions + CollectionWidgetBaseProperties, + keyof PublicProperties & keyof CollectionWidgetBaseProperties > { _renderQueue?: RenderQueueItem[]; } @@ -178,7 +179,7 @@ class Splitter extends CollectionWidget { } _pushItemToRenderQueue( - itemContent: Element, + itemContent: dxElementWrapper, splitterConfig: Properties, ): void { this._renderQueue.push({ itemContent, splitterConfig }); @@ -604,7 +605,7 @@ class Splitter extends CollectionWidget { _createItemByTemplate( itemTemplate: { source: () => unknown }, - args: { itemData: Item }, + args: ItemRenderInfo, ): unknown { const { itemData } = args; @@ -619,7 +620,12 @@ class Splitter extends CollectionWidget { return super._createItemByTemplate(itemTemplate, args); } - _postprocessRenderItem(args: { itemData: Item; itemContent: Element }): void { + _postprocessRenderItem(args: { + itemElement: dxElementWrapper; + itemContent: dxElementWrapper; + itemData: Item; + itemIndex: number; + }): void { const splitterConfig = args.itemData.splitter; if (!splitterConfig) { return; @@ -952,7 +958,7 @@ class Splitter extends CollectionWidget { this._layout = this._getDefaultLayoutBasedOnSize(); } - _optionChanged(args: Record): void { + _optionChanged(args: OptionChanged): void { const { name, value } = args; switch (name) { diff --git a/packages/devextreme/js/__internal/ui/splitter/splitter_item.ts b/packages/devextreme/js/__internal/ui/splitter/splitter_item.ts index 9b04d538c37f..8614ebb6c13b 100644 --- a/packages/devextreme/js/__internal/ui/splitter/splitter_item.ts +++ b/packages/devextreme/js/__internal/ui/splitter/splitter_item.ts @@ -50,6 +50,8 @@ class SplitterItem extends CollectionWidgetItem { } getIndex(): number { + // @ts-expect-error + // eslint-disable-next-line @typescript-eslint/no-unsafe-return return this._owner._getIndexByItemData(this._rawData); } diff --git a/packages/devextreme/js/__internal/ui/splitter/utils/types.ts b/packages/devextreme/js/__internal/ui/splitter/utils/types.ts index 69dd6ffcae67..f1ac6a020be6 100644 --- a/packages/devextreme/js/__internal/ui/splitter/utils/types.ts +++ b/packages/devextreme/js/__internal/ui/splitter/utils/types.ts @@ -1,3 +1,4 @@ +import type { dxElementWrapper } from '@js/core/renderer'; import type { ItemCollapsedEvent, ItemExpandedEvent, Properties, ResizeEndEvent, ResizeEvent, ResizeStartEvent, } from '@js/ui/splitter'; @@ -18,7 +19,7 @@ export interface ResizeOffset { } export interface RenderQueueItem { - itemContent: Element; + itemContent: dxElementWrapper; splitterConfig: Properties; } diff --git a/packages/devextreme/js/__internal/ui/tabs/m_tabs.ts b/packages/devextreme/js/__internal/ui/tabs/m_tabs.ts index deb4f7c1d79f..a384712cf9a3 100644 --- a/packages/devextreme/js/__internal/ui/tabs/m_tabs.ts +++ b/packages/devextreme/js/__internal/ui/tabs/m_tabs.ts @@ -114,9 +114,6 @@ const STYLING_MODE = { }; const Tabs = CollectionWidget.inherit({ - - _activeStateUnit: `.${TABS_ITEM_CLASS}`, - _getDefaultOptions() { return extend(this.callBase(), { hoverStateEnabled: true, @@ -191,6 +188,8 @@ const Tabs = CollectionWidget.inherit({ const indicatorPosition = this._getIndicatorPosition(); this.callBase(); + + this._activeStateUnit = `.${TABS_ITEM_CLASS}`; this.setAria('role', 'tablist'); this.$element().addClass(TABS_CLASS); this._toggleScrollingEnabledClass(scrollingEnabled); diff --git a/packages/devextreme/js/__internal/ui/toolbar/m_toolbar.base.ts b/packages/devextreme/js/__internal/ui/toolbar/m_toolbar.base.ts index f6a25563734c..2329d0240f20 100644 --- a/packages/devextreme/js/__internal/ui/toolbar/m_toolbar.base.ts +++ b/packages/devextreme/js/__internal/ui/toolbar/m_toolbar.base.ts @@ -13,10 +13,11 @@ import { // @ts-expect-error waitWebFont, } from '@js/ui/themes'; -import type { Item, Properties as PublicProperties } from '@js/ui/toolbar'; +import type { Item, Properties } from '@js/ui/toolbar'; +import type { OptionChanged } from '@ts/core/widget/types'; import AsyncCollectionWidget from '@ts/ui/collection/async'; +import type { CollectionWidgetBaseProperties } from '@ts/ui/collection/m_collection_widget.base'; -import type { TypedCollectionWidgetOptions } from '../collection/base'; import { TOOLBAR_CLASS } from './m_constants'; const TOOLBAR_BEFORE_CLASS = 'dx-toolbar-before'; @@ -39,19 +40,24 @@ const ANIMATION_TIMEOUT = 15; type ItemLike = string | Item | any; -export interface Properties< +export interface ToolbarBaseProperties< // eslint-disable-next-line @typescript-eslint/no-explicit-any TItem extends ItemLike = any, // eslint-disable-next-line @typescript-eslint/no-explicit-any TKey = any, -> extends PublicProperties, +> extends Properties, Omit< - TypedCollectionWidgetOptions, - keyof PublicProperties & keyof TypedCollectionWidgetOptions + CollectionWidgetBaseProperties, + keyof Properties & keyof CollectionWidgetBaseProperties > { + grouped: boolean; + renderAs: 'topToolbar'; + useFlatButtons: boolean; + useDefaultButtons: boolean; + compactMode: boolean; } -class ToolbarBase extends AsyncCollectionWidget { +class ToolbarBase extends AsyncCollectionWidget { _$toolbarItemsContainer?: any; _$beforeSection?: dxElementWrapper; @@ -120,10 +126,9 @@ class ToolbarBase extends AsyncCollectionWidget { }); } - _getDefaultOptions(): Properties { + _getDefaultOptions(): ToolbarBaseProperties { return { ...super._getDefaultOptions(), - // @ts-expect-error renderAs: 'topToolbar', grouped: false, useFlatButtons: false, @@ -139,7 +144,6 @@ class ToolbarBase extends AsyncCollectionWidget { return isMaterialBased(); }, options: { - // @ts-expect-error useFlatButtons: true, }, }, @@ -440,7 +444,7 @@ class ToolbarBase extends AsyncCollectionWidget { this._arrangeItems(); } - _optionChanged(args: Record): void { + _optionChanged(args: OptionChanged): void { const { name } = args; switch (name) { diff --git a/packages/devextreme/js/__internal/ui/toolbar/m_toolbar.ts b/packages/devextreme/js/__internal/ui/toolbar/m_toolbar.ts index 6a589495d60a..853aa10cee5a 100644 --- a/packages/devextreme/js/__internal/ui/toolbar/m_toolbar.ts +++ b/packages/devextreme/js/__internal/ui/toolbar/m_toolbar.ts @@ -1,7 +1,8 @@ import registerComponent from '@js/core/component_registrator'; import type { dxElementWrapper } from '@js/core/renderer'; +import type { OptionChanged } from '@ts/core/widget/types'; -import type { Properties as ToolbarBaseProperties } from './m_toolbar.base'; +import type { ToolbarBaseProperties } from './m_toolbar.base'; import ToolbarBase from './m_toolbar.base'; import { toggleItemFocusableElementTabIndex } from './m_toolbar.utils'; import { MultiLineStrategy } from './strategy/m_toolbar.multiline'; @@ -157,7 +158,7 @@ class Toolbar extends ToolbarBase { return itemData.location === undefined || itemData.locateInMenu === 'never'; } - _optionChanged(args: Record): void { + _optionChanged(args: OptionChanged): void { const { name, value } = args; this._layoutStrategy._optionChanged(name, value); @@ -181,7 +182,7 @@ class Toolbar extends ToolbarBase { } // it is not public - updateDimensions() { + updateDimensions(): void { this._dimensionChanged(); } } diff --git a/packages/devextreme/js/__internal/ui/tree_view/m_tree_view.base.ts b/packages/devextreme/js/__internal/ui/tree_view/m_tree_view.base.ts index 7bbcc586858a..368748e2ab04 100644 --- a/packages/devextreme/js/__internal/ui/tree_view/m_tree_view.base.ts +++ b/packages/devextreme/js/__internal/ui/tree_view/m_tree_view.base.ts @@ -156,8 +156,6 @@ const TreeViewBase = (HierarchicalCollectionWidget as any).inherit({ return $(element); }, - _activeStateUnit: `.${ITEM_CLASS}`, - _widgetClass() { return WIDGET_CLASS; }, @@ -404,6 +402,8 @@ const TreeViewBase = (HierarchicalCollectionWidget as any).inherit({ this._filter = {}; this.callBase(); + this._activeStateUnit = `.${ITEM_CLASS}`; + this._initStoreChangeHandlers(); },