diff --git a/packages/devextreme/js/__internal/ui/radio_group/m_radio_button.ts b/packages/devextreme/js/__internal/ui/radio_group/m_radio_button.ts index 9de60a290d3a..bc57525482a4 100644 --- a/packages/devextreme/js/__internal/ui/radio_group/m_radio_button.ts +++ b/packages/devextreme/js/__internal/ui/radio_group/m_radio_button.ts @@ -8,7 +8,7 @@ import type { dxElementWrapper } from '@js/core/renderer'; import $ from '@js/core/renderer'; import type { DxEvent } from '@js/events'; import type { OptionChanged } from '@ts/core/widget/types'; -import type { EditorProperties } from '@ts/ui/editor/editor'; +import type { EditorProperties, ValueChangedEvent } from '@ts/ui/editor/editor'; import Editor from '@ts/ui/editor/editor'; const RADIO_BUTTON_CLASS = 'dx-radiobutton'; @@ -24,11 +24,10 @@ class RadioButton extends Editor { _clickAction?: (event?: Record) => void; - // eslint-disable-next-line @typescript-eslint/no-invalid-void-type - _supportedKeys(): Record void | boolean> { - const click = function (e) { + _supportedKeys(): Record void> { + const click = (e: KeyboardEvent): void => { e.preventDefault(); - this._clickAction({ event: e }); + this._clickAction?.({ event: e }); }; return { ...super._supportedKeys(), @@ -70,10 +69,12 @@ class RadioButton extends Editor { } _initMarkup(): void { + const { value } = this.option(); + super._initMarkup(); this._renderIcon(); - this._renderCheckedState(this.option('value')); + this._renderCheckedState(value); this._renderClick(); this.setAria('role', 'radio'); } @@ -85,7 +86,7 @@ class RadioButton extends Editor { this.$element().append(this._$icon); } - _renderCheckedState(checked): void { + _renderCheckedState(checked: boolean): void { this.$element() .toggleClass(RADIO_BUTTON_CHECKED_CLASS, checked) .find(`.${RADIO_BUTTON_ICON_CLASS}`) @@ -94,10 +95,9 @@ class RadioButton extends Editor { } _renderClick(): void { - // @ts-expect-error ts-error - const eventName = addNamespace(clickEventName, this.NAME); + const eventName = addNamespace(clickEventName, this.NAME ?? ''); - this._clickAction = this._createAction((args): void => { + this._clickAction = this._createAction((args: { event: ValueChangedEvent }): void => { this._clickHandler(args.event); }); @@ -107,7 +107,7 @@ class RadioButton extends Editor { }); } - _clickHandler(e): void { + _clickHandler(e: ValueChangedEvent): void { this._saveValueChangeEvent(e); this.option('value', true); this._saveValueChangeEvent(undefined); 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 04e297f40ee3..d444101ddbfc 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 @@ -1,7 +1,7 @@ import type { dxElementWrapper } from '@js/core/renderer'; import $ from '@js/core/renderer'; import { deferRender } from '@js/core/utils/common'; -import { extend } from '@js/core/utils/extend'; +import type { DxEvent } from '@js/events'; import DataExpressionMixin from '@js/ui/editor/ui.data_expression'; import type { CollectionWidgetBaseProperties } from '@ts/ui/collection/collection_widget.base'; import CollectionWidget from '@ts/ui/collection/collection_widget.edit'; @@ -26,12 +26,13 @@ class RadioCollection extends CollectionWidget { } _getDefaultOptions(): Properties { - const defaultOptions = super._getDefaultOptions(); - - // @ts-expect-error - return extend(defaultOptions, DataExpressionMixin._dataExpressionDefaultOptions(), { + return { + ...super._getDefaultOptions(), + // @ts-expect-error DataExpressionMixin._dataExpressionDefaultOptions() + // should be added to the type + ...DataExpressionMixin._dataExpressionDefaultOptions(), _itemAttributes: { role: 'radio' }, - }); + } as Properties; } _initMarkup(): void { @@ -83,22 +84,21 @@ class RadioCollection extends CollectionWidget { this._renderContent(); } - _supportedKeys(): Record void> { + _supportedKeys(): Record) => void> { const parent = super._supportedKeys(); - return extend({}, parent, { - enter(e) { + return { + ...parent, + enter(e: DxEvent): void { e.preventDefault(); - // @ts-expect-error - return parent.enter.apply(this, arguments); + parent.enter?.apply(this, [e]); }, - space(e) { + space(e: DxEvent): void { e.preventDefault(); - // @ts-expect-error - return parent.space.apply(this, arguments); + parent.space?.apply(this, [e]); }, - }); + }; } _itemElements(): dxElementWrapper { 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 048e6cfe8330..7b829774727f 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 @@ -5,12 +5,13 @@ import type { dxElementWrapper } from '@js/core/renderer'; import $ from '@js/core/renderer'; import type { DeferredObj } from '@js/core/utils/deferred'; import { Deferred } from '@js/core/utils/deferred'; -import { extend } from '@js/core/utils/extend'; import { isDefined } from '@js/core/utils/type'; +import type { ItemInfo, NativeEventInfo } from '@js/events'; +import type { ItemLike } from '@js/ui/collection/ui.collection_widget.base'; import DataExpressionMixin from '@js/ui/editor/ui.data_expression'; import type { Properties } from '@js/ui/radio_group'; import type { OptionChanged } from '@ts/core/widget/types'; -import type { EditorProperties, UnresolvedEvents } from '@ts/ui/editor/editor'; +import type { EditorProperties, UnresolvedEvents, ValueChangedEvent } from '@ts/ui/editor/editor'; import Editor from '@ts/ui/editor/editor'; import RadioCollection from './m_radio_collection'; @@ -28,21 +29,18 @@ interface RadioGroupProperties extends Properties, class RadioGroup extends Editor { private _radios?: RadioCollection; - private _areRadiosCreated!: DeferredObj; + private _areRadiosCreated!: DeferredObj; private _$submitElement!: dxElementWrapper; - // eslint-disable-next-line class-methods-use-this _dataSourceOptions(): { paginate: boolean } { return { paginate: false }; } - // eslint-disable-next-line class-methods-use-this protected _activeStateUnit(): string { return `.${RADIO_BUTTON_CLASS}`; } - // eslint-disable-next-line class-methods-use-this protected _feedbackHideTimeout(): number { return RADIO_FEEDBACK_HIDE_TIMEOUT; } @@ -63,32 +61,38 @@ class RadioGroup extends Editor { }]); } - // @ts-expect-error + // @ts-expect-error widget.ts _fireContentReadyAction should accept an optional `force` parameter _fireContentReadyAction(force: boolean): void { - force && super._fireContentReadyAction(); + if (!force) { + return; + } + + // eslint-disable-next-line @typescript-eslint/no-floating-promises + super._fireContentReadyAction(); } - _focusTarget() { + _focusTarget(): dxElementWrapper { return this.$element(); } - _getAriaTarget() { + _getAriaTarget(): dxElementWrapper { return this.$element(); } - _getDefaultOptions() { - const defaultOptions = super._getDefaultOptions(); - - // @ts-expect-error - return extend(defaultOptions, extend(DataExpressionMixin._dataExpressionDefaultOptions(), { + _getDefaultOptions(): RadioGroupProperties { + return { + ...super._getDefaultOptions(), + // @ts-expect-error DataExpressionMixin should expose _dataExpressionDefaultOptions as a + // typed static method + ...DataExpressionMixin._dataExpressionDefaultOptions(), hoverStateEnabled: true, activeStateEnabled: true, layout: 'vertical', - })); + } as RadioGroupProperties; } - _getItemValue(item) { - // @ts-expect-error + _getItemValue(item: ItemLike): unknown { + // @ts-expect-error valueGetter is injected by DataExpressionMixin return this._valueGetter ? this._valueGetter(item) : item.text; } @@ -99,7 +103,7 @@ class RadioGroup extends Editor { _init(): void { super._init(); - // @ts-expect-error + // @ts-expect-error _initDataExpressions is injected by DataExpressionMixin this._initDataExpressions(); } @@ -112,28 +116,29 @@ class RadioGroup extends Editor { super._initMarkup(); } - _itemClickHandler({ itemElement, event, itemData }): void { - // @ts-expect-error - if (this.itemElements().is(itemElement)) { + _itemClickHandler({ itemElement, event, itemData }: + NativeEventInfo & ItemInfo): void { + if (this.itemElements()?.is($(itemElement))) { + const { value } = this.option(); const newValue = this._getItemValue(itemData); - if (newValue !== this.option('value')) { - this._saveValueChangeEvent(event); + if (newValue !== value) { + this._saveValueChangeEvent(event as unknown as ValueChangedEvent); this.option('value', newValue); } } } - _getSelectedItemKeys(value) { - // @ts-expect-error - const isNullSelectable = this.option('valueExpr') !== 'this'; - const shouldSelectValue = isNullSelectable && value === null || isDefined(value); + _getSelectedItemKeys(value: unknown): unknown[] { + const { valueExpr } = this.option(); + const isNullSelectable = valueExpr !== 'this'; + const shouldSelectValue = (isNullSelectable && value === null) || isDefined(value); return shouldSelectValue ? [value] : []; } - _setSelection(currentValue): void { - // @ts-expect-error + _setSelection(currentValue: unknown): void { + // @ts-expect-error _unwrappedValue is injected by DataExpressionMixin const value = this._unwrappedValue(currentValue); this._setCollectionWidgetOption('selectedItemKeys', this._getSelectedItemKeys(value)); } @@ -147,7 +152,7 @@ class RadioGroup extends Editor { _optionChanged(args: OptionChanged): void { const { name, value } = args; - // @ts-expect-error + // @ts-expect-error _dataExpressionOptionChanged is injected by DataExpressionMixin this._dataExpressionOptionChanged(args); switch (name) { @@ -164,7 +169,7 @@ class RadioGroup extends Editor { this._setCollectionWidgetOption(name, value); break; case 'valueExpr': - // @ts-expect-error + // @ts-expect-error _getCollectionKeyExpr is injected by DataExpressionMixin this._setCollectionWidgetOption('keyExpr', this._getCollectionKeyExpr()); break; case 'value': @@ -173,7 +178,7 @@ class RadioGroup extends Editor { super._optionChanged(args); break; case 'items': - this._setSelection(this.option('value')); + this._setSelection(this.option().value); break; case 'itemTemplate': case 'displayExpr': @@ -215,21 +220,20 @@ class RadioGroup extends Editor { onInitialized: ({ component }) => { this._radios = component; }, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - onContentReady: (e) => { + onContentReady: () => { this._fireContentReadyAction(true); }, - // @ts-expect-error onItemClick: this._itemClickHandler.bind(this), displayExpr, accessKey, - // @ts-expect-error + // @ts-expect-error _dataSource is injected by DataExpressionMixin dataSource: this._dataSource, focusStateEnabled, itemTemplate, - // @ts-expect-error + // @ts-expect-error _getCollectionKeyExpr is injected by DataExpressionMixin keyExpr: this._getCollectionKeyExpr(), noDataText: '', + // @ts-expect-error scrollingEnabled is absent from CollectionWidgetProperties scrollingEnabled: false, selectByClick: false, selectionMode: 'single', @@ -249,35 +253,33 @@ class RadioGroup extends Editor { _setOptionsByReference(): void { super._setOptionsByReference(); - extend(this._optionsByReference, { value: true }); + this._optionsByReference = { ...this._optionsByReference, value: true }; } _setSubmitValue(value?: unknown): void { - value = value ?? this.option('value'); - // @ts-expect-error - const submitValue = this.option('valueExpr') === 'this' - // @ts-expect-error - ? this._displayGetter(value) - : value; + const { valueExpr, value: optionValue } = this.option(); + const resolvedValue = value ?? optionValue; - this._$submitElement.val(submitValue); - } + const submitValue = valueExpr === 'this' + // @ts-expect-error _displayGetter is injected by DataExpressionMixin + ? this._displayGetter(resolvedValue) + : resolvedValue; - // eslint-disable-next-line @typescript-eslint/no-unused-vars - _setCollectionWidgetOption(name: string, value: unknown): void { - // @ts-expect-error + this._$submitElement.val(submitValue as string | number | undefined); + } - this._areRadiosCreated.done(this._setWidgetOption.bind(this, '_radios', arguments)); + _setCollectionWidgetOption(...args: [string, unknown]): void { + // @ts-expect-error widget._setWidgetOption args should be typed as ArrayLike + this._areRadiosCreated.done(this._setWidgetOption.bind(this, '_radios', args)); } _updateItemsSize(): void { - const { layout } = this.option(); + const { layout, items } = this.option(); if (layout === 'horizontal') { this.itemElements()?.css('height', 'auto'); } else { - // @ts-expect-error - const itemsCount = this.option('items').length; + const itemsCount = (items ?? []).length; this.itemElements()?.css('height', `${100 / itemsCount}%`); } @@ -291,7 +293,7 @@ class RadioGroup extends Editor { return this._radios?._itemElements(); } } -// @ts-expect-error +// @ts-expect-error Widget base class should define a typed static include() method RadioGroup.include(DataExpressionMixin); registerComponent('dxRadioGroup', RadioGroup);