From e3dbfd4ed7aa33e1f90dfae4eaae2871c5ef8029 Mon Sep 17 00:00:00 2001 From: Peter Skelin Date: Thu, 21 Nov 2024 23:39:24 +0200 Subject: [PATCH 01/10] feat: add strict event type checking --- packages/ai/src/Button.ts | 2 +- packages/ai/src/PromptInput.ts | 2 +- packages/base/src/UI5Element.ts | 9 ++-- packages/base/src/UI5ElementMetadata.ts | 2 +- packages/base/src/decorators.ts | 2 + packages/base/src/decorators/event-strict.ts | 30 ++++++++++++ packages/base/src/decorators/event.ts | 1 + packages/compat/src/Table.ts | 26 ++++++---- packages/compat/src/TableGroupRow.ts | 5 +- packages/compat/src/TableRow.ts | 28 +++++++---- packages/fiori/src/BarcodeScannerDialog.ts | 19 ++++--- packages/fiori/src/DynamicPage.ts | 6 ++- .../fiori/src/DynamicPageHeaderActions.ts | 8 ++- packages/fiori/src/DynamicPageTitle.ts | 5 +- packages/fiori/src/DynamicSideContent.ts | 9 ++-- packages/fiori/src/FlexibleColumnLayout.ts | 9 ++-- packages/fiori/src/MediaGallery.ts | 13 +++-- packages/fiori/src/MediaGalleryItem.ts | 5 +- packages/fiori/src/NotificationList.ts | 19 ++++--- .../fiori/src/NotificationListGroupItem.ts | 9 +++- packages/fiori/src/NotificationListItem.ts | 14 ++++-- packages/fiori/src/ProductSwitchItem.ts | 8 ++- packages/fiori/src/ShellBar.ts | 37 ++++++++------ packages/fiori/src/ShellBarItem.ts | 10 ++-- packages/fiori/src/SideNavigation.ts | 9 ++-- .../src/SideNavigationSelectableItemBase.ts | 5 +- packages/fiori/src/TimelineGroupItem.ts | 5 +- packages/fiori/src/TimelineItem.ts | 7 ++- packages/fiori/src/UploadCollection.ts | 14 ++++-- packages/fiori/src/UploadCollectionItem.ts | 10 +++- packages/fiori/src/ViewSettingsDialog.ts | 19 ++++--- packages/fiori/src/Wizard.ts | 9 ++-- packages/fiori/src/WizardTab.ts | 6 ++- packages/main/src/Avatar.ts | 6 ++- packages/main/src/AvatarGroup.ts | 11 +++-- packages/main/src/Breadcrumbs.ts | 20 +++++--- packages/main/src/Button.ts | 6 ++- packages/main/src/Calendar.ts | 12 +++-- packages/main/src/CalendarLegend.ts | 10 ++-- packages/main/src/CardHeader.ts | 6 ++- packages/main/src/Carousel.ts | 13 +++-- packages/main/src/CheckBox.ts | 6 ++- packages/main/src/ColorPalette.ts | 9 ++-- packages/main/src/ColorPalettePopover.ts | 10 ++-- packages/main/src/ColorPicker.ts | 5 +- packages/main/src/ComboBox.ts | 13 +++-- packages/main/src/DatePicker.ts | 24 ++++++--- packages/main/src/DayPicker.ts | 14 ++++-- packages/main/src/FileUploader.ts | 16 +++--- packages/main/src/Icon.ts | 5 +- packages/main/src/Input.ts | 26 +++++++--- packages/main/src/Link.ts | 9 ++-- packages/main/src/List.ts | 49 ++++++++++++------- packages/main/src/ListItem.ts | 13 +++-- packages/main/src/ListItemBase.ts | 12 ++++- packages/main/src/ListItemGroup.ts | 14 ++++-- packages/main/src/Menu.ts | 15 ++++-- packages/main/src/MessageStrip.ts | 6 ++- packages/main/src/MonthPicker.ts | 13 +++-- packages/main/src/MultiComboBox.ts | 13 +++-- packages/main/src/MultiComboBoxItem.ts | 7 ++- packages/main/src/MultiInput.ts | 10 ++-- packages/main/src/Panel.ts | 5 +- packages/main/src/Popup.ts | 22 ++++++--- packages/main/src/RadioButton.ts | 5 +- packages/main/src/RatingIndicator.ts | 5 +- packages/main/src/SegmentedButton.ts | 9 ++-- packages/main/src/Select.ts | 24 ++++++--- packages/main/src/SliderBase.ts | 6 ++- packages/main/src/SplitButton.ts | 6 ++- packages/main/src/StepInput.ts | 11 +++-- packages/main/src/Switch.ts | 6 ++- packages/main/src/TabContainer.ts | 27 +++++----- packages/main/src/Table.ts | 9 ++-- packages/main/src/TableGrowing.ts | 5 +- packages/main/src/TableSelection.ts | 5 +- packages/main/src/Tag.ts | 6 ++- packages/main/src/TextArea.ts | 18 +++++-- packages/main/src/TimePicker.ts | 17 +++++-- packages/main/src/TimePickerClock.ts | 23 +++++---- packages/main/src/TimePickerInternals.ts | 9 ++-- packages/main/src/TimeSelectionClocks.ts | 5 +- packages/main/src/TimeSelectionInputs.ts | 5 +- packages/main/src/Toast.ts | 5 +- packages/main/src/Token.ts | 10 ++-- packages/main/src/Tokenizer.ts | 40 ++++++++------- packages/main/src/Toolbar.ts | 9 ++-- packages/main/src/ToolbarButton.ts | 6 ++- packages/main/src/ToolbarSelect.ts | 9 +++- packages/main/src/Tree.ts | 49 ++++++++++++------- packages/main/src/TreeItemBase.ts | 23 +++++---- packages/main/src/YearPicker.ts | 12 +++-- 92 files changed, 779 insertions(+), 347 deletions(-) create mode 100644 packages/base/src/decorators/event-strict.ts diff --git a/packages/ai/src/Button.ts b/packages/ai/src/Button.ts index fd8193098c7a..1a4f231decb1 100644 --- a/packages/ai/src/Button.ts +++ b/packages/ai/src/Button.ts @@ -2,7 +2,7 @@ import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js"; import { renderFinished } from "@ui5/webcomponents-base/dist/Render.js"; import customElement from "@ui5/webcomponents-base/dist/decorators/customElement.js"; import property from "@ui5/webcomponents-base/dist/decorators/property.js"; -import event from "@ui5/webcomponents-base/dist/decorators/event.js"; +import event from "@ui5/webcomponents-base/dist/decorators/event-strict.js"; import slot from "@ui5/webcomponents-base/dist/decorators/slot.js"; import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js"; import MainButton from "@ui5/webcomponents/dist/Button.js"; diff --git a/packages/ai/src/PromptInput.ts b/packages/ai/src/PromptInput.ts index d29bf7f493a3..9a052d1122ef 100644 --- a/packages/ai/src/PromptInput.ts +++ b/packages/ai/src/PromptInput.ts @@ -1,7 +1,7 @@ import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js"; import customElement from "@ui5/webcomponents-base/dist/decorators/customElement.js"; import property from "@ui5/webcomponents-base/dist/decorators/property.js"; -import event from "@ui5/webcomponents-base/dist/decorators/event.js"; +import event from "@ui5/webcomponents-base/dist/decorators/event-strict.js"; import slot from "@ui5/webcomponents-base/dist/decorators/slot.js"; import i18n from "@ui5/webcomponents-base/dist/decorators/i18n.js"; import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js"; diff --git a/packages/base/src/UI5Element.ts b/packages/base/src/UI5Element.ts index 14d4a7dbf3d1..f95773e361cf 100644 --- a/packages/base/src/UI5Element.ts +++ b/packages/base/src/UI5Element.ts @@ -148,6 +148,7 @@ function getPropertyDescriptor(proto: any, name: PropertyKey): PropertyDescripto * @public */ abstract class UI5Element extends HTMLElement { + eventDetails!: object; __id?: string; _suppressInvalidation: boolean; _changedState: Array; @@ -970,13 +971,13 @@ abstract class UI5Element extends HTMLElement { * @param data - additional data for the event * @returns false, if the event was cancelled (preventDefault called), true otherwise */ - fireDecoratorEvent(name: string, data?: T): boolean { - const eventData = this.getEventData(name); + fireDecoratorEvent(name: N, data?: this["eventDetails"][N] | undefined): boolean { + const eventData = this.getEventData(name as string); const cancellable = eventData ? eventData.cancelable : false; const bubbles = eventData ? eventData.bubbles : false; - const eventResult = this._fireEvent(name, data, cancellable, bubbles); - const pascalCaseEventName = kebabToPascalCase(name); + const eventResult = this._fireEvent(name as string, data, cancellable, bubbles); + const pascalCaseEventName = kebabToPascalCase(name as string); // pascal events are more convinient for native react usage // live-change: diff --git a/packages/base/src/UI5ElementMetadata.ts b/packages/base/src/UI5ElementMetadata.ts index 516da95064d7..719578e3ab70 100644 --- a/packages/base/src/UI5ElementMetadata.ts +++ b/packages/base/src/UI5ElementMetadata.ts @@ -29,7 +29,7 @@ type Property = { type PropertyValue = boolean | number | string | object | undefined | null; -type EventData = Record, cancelable: boolean, bubbles: boolean }>; +type EventData = Record, cancelable?: boolean, bubbles?: boolean }>; type I18nBundleAccessorValue = { bundleName: string, diff --git a/packages/base/src/decorators.ts b/packages/base/src/decorators.ts index 15de885f46a7..225607134f3b 100644 --- a/packages/base/src/decorators.ts +++ b/packages/base/src/decorators.ts @@ -1,11 +1,13 @@ import customElement from "./decorators/customElement.js"; import event from "./decorators/event.js"; +import eventStrict from "./decorators/event-strict.js"; import property from "./decorators/property.js"; import slot from "./decorators/slot.js"; export { customElement, event, + eventStrict, property, slot, }; diff --git a/packages/base/src/decorators/event-strict.ts b/packages/base/src/decorators/event-strict.ts new file mode 100644 index 000000000000..fac6025bb169 --- /dev/null +++ b/packages/base/src/decorators/event-strict.ts @@ -0,0 +1,30 @@ +import type UI5Element from "../UI5Element.js"; + +/** + * Returns an event class decorator. + * + * @param { string } name the event name + * @param { EventData } data the event data + * @returns { ClassDecorator } + */ +const event = ["eventDetails"]>(name: N, data: { detail?: Record["eventDetails"][N], { type: any}>, bubbles?: boolean, cancelable?: boolean } = {}): (target: T) => T | void => { + return (target: T) => { + if (!Object.prototype.hasOwnProperty.call(target, "metadata")) { + target.metadata = {}; + } + + const metadata = target.metadata; + if (!metadata.events) { + metadata.events = {}; + } + + const eventsMetadata = metadata.events; + if (!eventsMetadata[name as string]) { + data.bubbles = !!data.bubbles; + data.cancelable = !!data.cancelable; + eventsMetadata[name as string] = data; + } + }; +}; + +export default event; diff --git a/packages/base/src/decorators/event.ts b/packages/base/src/decorators/event.ts index 726b9d999637..450efca3f907 100644 --- a/packages/base/src/decorators/event.ts +++ b/packages/base/src/decorators/event.ts @@ -1,6 +1,7 @@ /** * Returns an event class decorator. * + * @deprecated Use `@ui5/webcomponents-base/dist/decorators/event-strict.js` instead. * @param { string } name the event name * @param { EventData } data the event data * @returns { ClassDecorator } diff --git a/packages/compat/src/Table.ts b/packages/compat/src/Table.ts index 81f57ef019d2..8b5f4041e1ee 100644 --- a/packages/compat/src/Table.ts +++ b/packages/compat/src/Table.ts @@ -2,7 +2,7 @@ import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js"; import type { ChangeInfo } from "@ui5/webcomponents-base/dist/UI5Element.js"; import customElement from "@ui5/webcomponents-base/dist/decorators/customElement.js"; import property from "@ui5/webcomponents-base/dist/decorators/property.js"; -import event from "@ui5/webcomponents-base/dist/decorators/event.js"; +import event from "@ui5/webcomponents-base/dist/decorators/event-strict.js"; import slot from "@ui5/webcomponents-base/dist/decorators/slot.js"; import i18n from "@ui5/webcomponents-base/dist/decorators/i18n.js"; import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js"; @@ -182,7 +182,7 @@ enum TableFocusTargetElement { * @param {HTMLElement} row the activated row. * @public */ -@event("row-click", { +@event("row-click", { detail: { /** * @public @@ -198,7 +198,7 @@ enum TableFocusTargetElement { * @since 2.0.0 * @public */ -@event("popin-change", { +@event("popin-change", { detail: { /** * @public @@ -229,7 +229,7 @@ enum TableFocusTargetElement { * @public * @since 2.0.0 */ -@event("selection-change", { +@event("selection-change", { detail: { /** * @public @@ -243,6 +243,12 @@ enum TableFocusTargetElement { bubbles: true, }) class Table extends UI5Element { + eventDetails!: { + "row-click": TableRowClickEventDetail, + "popin-change": TablePopinChangeEventDetail, + "load-more": void, + "selection-change": TableSelectionChangeEventDetail, + } /** * Defines the text that will be displayed when there is no data and `hideNoData` is not present. * @default undefined @@ -673,7 +679,7 @@ class Table extends UI5Element { const selectedRows = this.selectedRows; - this.fireDecoratorEvent("selection-change", { + this.fireDecoratorEvent("selection-change", { selectedRows, previouslySelectedRows, }); @@ -705,7 +711,7 @@ class Table extends UI5Element { const selectedRows: Array = this.selectedRows; - this.fireDecoratorEvent("selection-change", { + this.fireDecoratorEvent("selection-change", { selectedRows, previouslySelectedRows, }); @@ -967,7 +973,7 @@ class Table extends UI5Element { } }); row.selected = true; - this.fireDecoratorEvent("selection-change", { + this.fireDecoratorEvent("selection-change", { selectedRows: [row], previouslySelectedRows, }); @@ -992,7 +998,7 @@ class Table extends UI5Element { this._allRowsSelected = false; } - this.fireDecoratorEvent("selection-change", { + this.fireDecoratorEvent("selection-change", { selectedRows, previouslySelectedRows, }); @@ -1021,7 +1027,7 @@ class Table extends UI5Element { const selectedRows = bAllSelected ? this.rows : []; - this.fireDecoratorEvent("selection-change", { + this.fireDecoratorEvent("selection-change", { selectedRows, previouslySelectedRows, }); @@ -1096,7 +1102,7 @@ class Table extends UI5Element { // invalidate if hidden columns count has changed or columns are shown if (hiddenColumnsChange || shownColumnsChange) { this._hiddenColumns = hiddenColumns; - this.fireDecoratorEvent("popin-change", { + this.fireDecoratorEvent("popin-change", { poppedColumns: this._hiddenColumns, }); } diff --git a/packages/compat/src/TableGroupRow.ts b/packages/compat/src/TableGroupRow.ts index 859065a86267..5b9664d4bc1d 100644 --- a/packages/compat/src/TableGroupRow.ts +++ b/packages/compat/src/TableGroupRow.ts @@ -1,7 +1,7 @@ import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js"; import customElement from "@ui5/webcomponents-base/dist/decorators/customElement.js"; import property from "@ui5/webcomponents-base/dist/decorators/property.js"; -import event from "@ui5/webcomponents-base/dist/decorators/event.js"; +import event from "@ui5/webcomponents-base/dist/decorators/event-strict.js"; import i18n from "@ui5/webcomponents-base/dist/decorators/i18n.js"; import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js"; import type I18nBundle from "@ui5/webcomponents-base/dist/i18nBundle.js"; @@ -47,6 +47,9 @@ import tableGroupRowStyles from "./generated/themes/TableGroupRow.css.js"; bubbles: true, }) class TableGroupRow extends UI5Element implements ITableRow { + eventDetails!: { + _focused: FocusEvent, + } /** * Defines the mode of the row * @default "None" diff --git a/packages/compat/src/TableRow.ts b/packages/compat/src/TableRow.ts index b20a11bb2e09..f41435bde9e9 100644 --- a/packages/compat/src/TableRow.ts +++ b/packages/compat/src/TableRow.ts @@ -1,7 +1,7 @@ import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js"; import customElement from "@ui5/webcomponents-base/dist/decorators/customElement.js"; import property from "@ui5/webcomponents-base/dist/decorators/property.js"; -import event from "@ui5/webcomponents-base/dist/decorators/event.js"; +import event from "@ui5/webcomponents-base/dist/decorators/event-strict.js"; import slot from "@ui5/webcomponents-base/dist/decorators/slot.js"; import i18n from "@ui5/webcomponents-base/dist/decorators/i18n.js"; import type I18nBundle from "@ui5/webcomponents-base/dist/i18nBundle.js"; @@ -89,7 +89,7 @@ type TableRowF7PressEventDetail = { /** * @private */ -@event("_forward-before", { +@event("_forward-before", { detail: { target: { type: HTMLElement, @@ -100,7 +100,7 @@ type TableRowF7PressEventDetail = { /** * @private */ -@event("_forward-after", { +@event("_forward-after", { detail: { target: { type: HTMLElement, @@ -125,6 +125,14 @@ type TableRowF7PressEventDetail = { bubbles: true, }) class TableRow extends UI5Element implements ITableRow { + eventDetails!: { + "row-click": TableRowClickEventDetail, + "_focused": FocusEvent, + "_forward-before": TableRowForwardBeforeEventDetail, + "_forward-after": TableRowForwardAfterEventDetail, + "selection-requested": TableRowSelectionRequestedEventDetail, + "f7-pressed": TableRowF7PressEventDetail, + } /** * Defines the visual indication and behavior of the component. * @@ -236,11 +244,11 @@ class TableRow extends UI5Element implements ITableRow { const lastFocusableElement = elements.pop(); if (isTabNext(e) && activeElement === (lastFocusableElement || this.root)) { - this.fireDecoratorEvent("_forward-after", { target: activeElement }); + this.fireDecoratorEvent("_forward-after", { target: activeElement }); } if (isTabPrevious(e) && activeElement === this.root) { - this.fireDecoratorEvent("_forward-before", { target: activeElement }); + this.fireDecoratorEvent("_forward-before", { target: activeElement }); } if (isSpace(e) && target.tagName.toLowerCase() === "tr") { @@ -249,11 +257,11 @@ class TableRow extends UI5Element implements ITableRow { if (isRowFocused && !checkboxPressed) { if ((isSpace(e) && itemSelectable) || (isEnter(e) && isSingleSelect)) { - this.fireDecoratorEvent("selection-requested", { row: this }); + this.fireDecoratorEvent("selection-requested", { row: this }); } if (isEnter(e) && itemActive) { - this.fireDecoratorEvent("row-click", { row: this }); + this.fireDecoratorEvent("row-click", { row: this }); if (!isSingleSelect) { this.activate(); } @@ -262,7 +270,7 @@ class TableRow extends UI5Element implements ITableRow { if (isF7(e)) { e.preventDefault(); - this.fireDecoratorEvent("f7-pressed", { row: this }); + this.fireDecoratorEvent("f7-pressed", { row: this }); } } @@ -315,13 +323,13 @@ class TableRow extends UI5Element implements ITableRow { } if (this.type === TableRowType.Active && !checkboxPressed) { - this.fireDecoratorEvent("row-click", { row: this }); + this.fireDecoratorEvent("row-click", { row: this }); } } } _handleSelection() { - this.fireDecoratorEvent("selection-requested", { row: this }); + this.fireDecoratorEvent("selection-requested", { row: this }); } _activeElementHasAttribute(attr: string): boolean { diff --git a/packages/fiori/src/BarcodeScannerDialog.ts b/packages/fiori/src/BarcodeScannerDialog.ts index db1610138b64..f8f6fc5b24e8 100644 --- a/packages/fiori/src/BarcodeScannerDialog.ts +++ b/packages/fiori/src/BarcodeScannerDialog.ts @@ -7,7 +7,7 @@ import Button from "@ui5/webcomponents/dist/Button.js"; import BusyIndicator from "@ui5/webcomponents/dist/BusyIndicator.js"; import customElement from "@ui5/webcomponents-base/dist/decorators/customElement.js"; import property from "@ui5/webcomponents-base/dist/decorators/property.js"; -import event from "@ui5/webcomponents-base/dist/decorators/event.js"; +import event from "@ui5/webcomponents-base/dist/decorators/event-strict.js"; import i18n from "@ui5/webcomponents-base/dist/decorators/i18n.js"; import { getI18nBundle } from "@ui5/webcomponents-base/dist/i18nBundle.js"; import type { Result, Exception } from "@zxing/library"; @@ -102,7 +102,7 @@ type BarcodeScannerDialogScanErrorEventDetail = { * @param {Object} rawBytes the scan result as a Uint8Array * @public */ -@event("scan-success", { +@event("scan-success", { detail: { /** * @public @@ -121,7 +121,7 @@ type BarcodeScannerDialogScanErrorEventDetail = { * @param {string} message the error message * @public */ -@event("scan-error", { +@event("scan-error", { detail: { /** * @public @@ -132,6 +132,11 @@ type BarcodeScannerDialogScanErrorEventDetail = { }) class BarcodeScannerDialog extends UI5Element { + eventDetails!: { + close: void, + "scan-success": BarcodeScannerDialogScanSuccessEventDetail, + "scan-error": BarcodeScannerDialogScanErrorEventDetail, + } /** * Defines the header HTML Element. * @@ -209,7 +214,7 @@ class BarcodeScannerDialog extends UI5Element { async onAfterRendering() { if (!this._hasGetUserMedia()) { - this.fireDecoratorEvent("scan-error", { message: "getUserMedia() is not supported by your browser" }); + this.fireDecoratorEvent("scan-error", { message: "getUserMedia() is not supported by your browser" }); return; } @@ -231,7 +236,7 @@ class BarcodeScannerDialog extends UI5Element { video.addEventListener("loadeddata", this._handleVideoPlayingBound); video.srcObject = stream; } catch (error) { - this.fireDecoratorEvent("scan-error", { message: (error as Error).message }); + this.fireDecoratorEvent("scan-error", { message: (error as Error).message }); this.loading = false; } } @@ -412,7 +417,7 @@ class BarcodeScannerDialog extends UI5Element { } _handleScanSuccess(result: Result) { - this.fireDecoratorEvent("scan-success", { + this.fireDecoratorEvent("scan-success", { text: result.getText(), rawBytes: result.getRawBytes(), }); @@ -423,7 +428,7 @@ class BarcodeScannerDialog extends UI5Element { return; } - this.fireDecoratorEvent("scan-error", { message: error.message }); + this.fireDecoratorEvent("scan-error", { message: error.message }); } _handleVideoPlaying() { diff --git a/packages/fiori/src/DynamicPage.ts b/packages/fiori/src/DynamicPage.ts index 2c536f9f09e7..b8693bed4123 100644 --- a/packages/fiori/src/DynamicPage.ts +++ b/packages/fiori/src/DynamicPage.ts @@ -3,7 +3,7 @@ import customElement from "@ui5/webcomponents-base/dist/decorators/customElement import property from "@ui5/webcomponents-base/dist/decorators/property.js"; import slot from "@ui5/webcomponents-base/dist/decorators/slot.js"; import query from "@ui5/webcomponents-base/dist/decorators/query.js"; -import event from "@ui5/webcomponents-base/dist/decorators/event.js"; +import event from "@ui5/webcomponents-base/dist/decorators/event-strict.js"; import i18n from "@ui5/webcomponents-base/dist/decorators/i18n.js"; import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js"; import { renderFinished } from "@ui5/webcomponents-base/dist/Render.js"; @@ -123,6 +123,10 @@ const SCROLL_THRESHOLD = 10; // px }) class DynamicPage extends UI5Element { + eventDetails!: { + "pin-button-toggle": void; + "title-toggle": void; + } /** * Defines if the pin button is hidden. * diff --git a/packages/fiori/src/DynamicPageHeaderActions.ts b/packages/fiori/src/DynamicPageHeaderActions.ts index 29e9eeae2e01..99ddff6db301 100644 --- a/packages/fiori/src/DynamicPageHeaderActions.ts +++ b/packages/fiori/src/DynamicPageHeaderActions.ts @@ -1,6 +1,6 @@ import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js"; import customElement from "@ui5/webcomponents-base/dist/decorators/customElement.js"; -import event from "@ui5/webcomponents-base/dist/decorators/event.js"; +import event from "@ui5/webcomponents-base/dist/decorators/event-strict.js"; import property from "@ui5/webcomponents-base/dist/decorators/property.js"; import i18n from "@ui5/webcomponents-base/dist/decorators/i18n.js"; import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js"; @@ -85,6 +85,12 @@ import { bubbles: true, }) class DynamicPageHeaderActions extends UI5Element { + eventDetails!: { + "expand-button-click": void; + "pin-button-click": void; + "expand-button-hover-in": void; + "expand-button-hover-out": void; + } /** * Defines whether the header is pinned. * diff --git a/packages/fiori/src/DynamicPageTitle.ts b/packages/fiori/src/DynamicPageTitle.ts index 1f8b9d94e52f..6112b83262bd 100644 --- a/packages/fiori/src/DynamicPageTitle.ts +++ b/packages/fiori/src/DynamicPageTitle.ts @@ -2,7 +2,7 @@ import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js"; import customElement from "@ui5/webcomponents-base/dist/decorators/customElement.js"; import property from "@ui5/webcomponents-base/dist/decorators/property.js"; import slot from "@ui5/webcomponents-base/dist/decorators/slot.js"; -import event from "@ui5/webcomponents-base/dist/decorators/event.js"; +import event from "@ui5/webcomponents-base/dist/decorators/event-strict.js"; import i18n from "@ui5/webcomponents-base/dist/decorators/i18n.js"; import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js"; import type I18nBundle from "@ui5/webcomponents-base/dist/i18nBundle.js"; @@ -77,6 +77,9 @@ import { }) class DynamicPageTitle extends UI5Element { + eventDetails!: { + "_toggle-title": void; + } /** * Defines if the title is snapped. * diff --git a/packages/fiori/src/DynamicSideContent.ts b/packages/fiori/src/DynamicSideContent.ts index 498f24adbf25..6344d9f3abcb 100644 --- a/packages/fiori/src/DynamicSideContent.ts +++ b/packages/fiori/src/DynamicSideContent.ts @@ -1,6 +1,6 @@ import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js"; import customElement from "@ui5/webcomponents-base/dist/decorators/customElement.js"; -import event from "@ui5/webcomponents-base/dist/decorators/event.js"; +import event from "@ui5/webcomponents-base/dist/decorators/event-strict.js"; import property from "@ui5/webcomponents-base/dist/decorators/property.js"; import slot from "@ui5/webcomponents-base/dist/decorators/slot.js"; import i18n from "@ui5/webcomponents-base/dist/decorators/i18n.js"; @@ -121,7 +121,7 @@ type DynamicSideContentLayoutChangeEventDetail = { * @param {boolean} sideContentVisible visibility of the side content. * @public */ -@event("layout-change", { +@event("layout-change", { detail: { /** * @public @@ -151,6 +151,9 @@ type DynamicSideContentLayoutChangeEventDetail = { bubbles: true, }) class DynamicSideContent extends UI5Element { + eventDetails!: { + "layout-change": DynamicSideContentLayoutChangeEventDetail + } /** * Defines the visibility of the main content. * @default false @@ -466,7 +469,7 @@ class DynamicSideContent extends UI5Element { mainContentVisible: mainSize !== this.span0, sideContentVisible: sideSize !== this.span0, }; - this.fireDecoratorEvent("layout-change", eventParams); + this.fireDecoratorEvent("layout-change", eventParams); this._currentBreakpoint = this.breakpoint; } diff --git a/packages/fiori/src/FlexibleColumnLayout.ts b/packages/fiori/src/FlexibleColumnLayout.ts index f9d899120d46..2409485ca024 100644 --- a/packages/fiori/src/FlexibleColumnLayout.ts +++ b/packages/fiori/src/FlexibleColumnLayout.ts @@ -2,7 +2,7 @@ import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js"; import customElement from "@ui5/webcomponents-base/dist/decorators/customElement.js"; import property from "@ui5/webcomponents-base/dist/decorators/property.js"; import slot from "@ui5/webcomponents-base/dist/decorators/slot.js"; -import event from "@ui5/webcomponents-base/dist/decorators/event.js"; +import event from "@ui5/webcomponents-base/dist/decorators/event-strict.js"; import i18n from "@ui5/webcomponents-base/dist/decorators/i18n.js"; import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js"; import ResizeHandler from "@ui5/webcomponents-base/dist/delegate/ResizeHandler.js"; @@ -184,7 +184,7 @@ type UserDefinedColumnLayouts = { * @param {boolean} resized Indicates if the layout was changed by resizing the entire component * @public */ -@event("layout-change", { +@event("layout-change", { detail: { /** * @public @@ -218,6 +218,9 @@ type UserDefinedColumnLayouts = { bubbles: true, }) class FlexibleColumnLayout extends UI5Element { + eventDetails!: { + "layout-change": FlexibleColumnLayoutLayoutChangeEventDetail, + } /** * Defines the columns layout and their proportion. * @@ -494,7 +497,7 @@ class FlexibleColumnLayout extends UI5Element { } fireLayoutChange(separatorUsed: boolean, resized: boolean) { - this.fireDecoratorEvent("layout-change", { + this.fireDecoratorEvent("layout-change", { layout: this.layout, columnLayout: this._columnLayout!, startColumnVisible: this.startColumnVisible, diff --git a/packages/fiori/src/MediaGallery.ts b/packages/fiori/src/MediaGallery.ts index 19cc50ed1a41..6b73e3ca12f8 100644 --- a/packages/fiori/src/MediaGallery.ts +++ b/packages/fiori/src/MediaGallery.ts @@ -11,7 +11,7 @@ import Carousel from "@ui5/webcomponents/dist/Carousel.js"; import customElement from "@ui5/webcomponents-base/dist/decorators/customElement.js"; import property from "@ui5/webcomponents-base/dist/decorators/property.js"; import slot from "@ui5/webcomponents-base/dist/decorators/slot.js"; -import event from "@ui5/webcomponents-base/dist/decorators/event.js"; +import event from "@ui5/webcomponents-base/dist/decorators/event-strict.js"; import type { ITabbable } from "@ui5/webcomponents-base/dist/delegate/ItemNavigation.js"; import MediaGalleryItem from "./MediaGalleryItem.js"; import MediaGalleryItemLayout from "./types/MediaGalleryItemLayout.js"; @@ -101,7 +101,7 @@ const COLUMNS_COUNT: Record = { * @param {HTMLElement} item the selected item. * @public */ -@event("selection-change", { +@event("selection-change", { detail: { /** * @public @@ -130,6 +130,11 @@ const COLUMNS_COUNT: Record = { }) class MediaGallery extends UI5Element { + eventDetails!: { + "selection-change": MediaGallerySelectionChangeEventDetail, + "overflow-click": void, + "display-area-click": void, + } /** * If set to `true`, all thumbnails are rendered in a scrollable container. * If `false`, only up to five thumbnails are rendered, followed by @@ -388,7 +393,7 @@ class MediaGallery extends UI5Element { this._itemNavigation.setCurrentItem(item); if (userInteraction) { - this.fireDecoratorEvent("selection-change", { item }); + this.fireDecoratorEvent("selection-change", { item }); } if (isPhone()) { @@ -453,7 +458,7 @@ class MediaGallery extends UI5Element { const selectedIndex = e.detail.selectedIndex, item = this._selectableItems[selectedIndex]; - this.fireDecoratorEvent("selection-change", { item }); + this.fireDecoratorEvent("selection-change", { item }); } get _mainItemTabIndex() { diff --git a/packages/fiori/src/MediaGalleryItem.ts b/packages/fiori/src/MediaGalleryItem.ts index 2a4c20d96d1a..d36e7a44d42a 100644 --- a/packages/fiori/src/MediaGalleryItem.ts +++ b/packages/fiori/src/MediaGalleryItem.ts @@ -6,7 +6,7 @@ import Icon from "@ui5/webcomponents/dist/Icon.js"; import "@ui5/webcomponents-icons/dist/background.js"; import customElement from "@ui5/webcomponents-base/dist/decorators/customElement.js"; import property from "@ui5/webcomponents-base/dist/decorators/property.js"; -import event from "@ui5/webcomponents-base/dist/decorators/event.js"; +import event from "@ui5/webcomponents-base/dist/decorators/event-strict.js"; import slot from "@ui5/webcomponents-base/dist/decorators/slot.js"; import type MediaGalleryItemLayout from "./types/MediaGalleryItemLayout.js"; import type { IMediaGalleryItem } from "./MediaGallery.js"; @@ -54,6 +54,9 @@ import MediaGalleryItemTemplate from "./generated/templates/MediaGalleryItemTemp bubbles: true, }) class MediaGalleryItem extends UI5Element implements IMediaGalleryItem { + eventDetails!: { + click: { item: MediaGalleryItem }, + } /** * Defines the selected state of the component. * @default false diff --git a/packages/fiori/src/NotificationList.ts b/packages/fiori/src/NotificationList.ts index 1667d98e7728..4834fa9f4969 100644 --- a/packages/fiori/src/NotificationList.ts +++ b/packages/fiori/src/NotificationList.ts @@ -2,7 +2,7 @@ import customElement from "@ui5/webcomponents-base/dist/decorators/customElement import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js"; import slot from "@ui5/webcomponents-base/dist/decorators/slot.js"; import property from "@ui5/webcomponents-base/dist/decorators/property.js"; -import event from "@ui5/webcomponents-base/dist/decorators/event.js"; +import event from "@ui5/webcomponents-base/dist/decorators/event-strict.js"; import i18n from "@ui5/webcomponents-base/dist/decorators/i18n.js"; import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js"; import type I18nBundle from "@ui5/webcomponents-base/dist/i18nBundle.js"; @@ -80,7 +80,7 @@ type NotificationItemCloseEventDetail = NotificationItemEventDetail; * @param {HTMLElement} item The clicked item. * @public */ -@event("item-click", { +@event("item-click", { detail: { /** * @public @@ -96,7 +96,7 @@ type NotificationItemCloseEventDetail = NotificationItemEventDetail; * @param {HTMLElement} item the item about to be closed. * @public */ -@event("item-close", { +@event("item-close", { detail: { /** * @public @@ -113,7 +113,7 @@ type NotificationItemCloseEventDetail = NotificationItemEventDetail; * @param {HTMLElement} item the toggled item. * @public */ -@event("item-toggle", { +@event("item-toggle", { detail: { /** * @public @@ -125,6 +125,11 @@ type NotificationItemCloseEventDetail = NotificationItemEventDetail; }) class NotificationList extends UI5Element { + eventDetails!: { + "item-click": NotificationItemClickEventDetail; + "item-close": NotificationItemCloseEventDetail; + "item-toggle": NotificationItemToggleEventDetail; + } /** * Defines the items of the component. * @@ -159,7 +164,7 @@ class NotificationList extends UI5Element { _onItemClick(e: CustomEvent) { const item = e.detail.item as NotificationListItemBase; - if (!this.fireDecoratorEvent("item-click", { item })) { + if (!this.fireDecoratorEvent("item-click", { item })) { e.preventDefault(); } } @@ -167,7 +172,7 @@ class NotificationList extends UI5Element { _onItemClose(e: CustomEvent) { const item = e.detail.item as NotificationListItemBase; - if (!this.fireDecoratorEvent("item-close", { item })) { + if (!this.fireDecoratorEvent("item-close", { item })) { e.preventDefault(); } } @@ -175,7 +180,7 @@ class NotificationList extends UI5Element { _onItemToggle(e: CustomEvent) { const item = e.detail.item as NotificationListItemBase; - if (!this.fireDecoratorEvent("item-toggle", { item })) { + if (!this.fireDecoratorEvent("item-toggle", { item })) { e.preventDefault(); } } diff --git a/packages/fiori/src/NotificationListGroupItem.ts b/packages/fiori/src/NotificationListGroupItem.ts index 075c492b0812..c76b2bc9638c 100644 --- a/packages/fiori/src/NotificationListGroupItem.ts +++ b/packages/fiori/src/NotificationListGroupItem.ts @@ -4,7 +4,7 @@ import { import customElement from "@ui5/webcomponents-base/dist/decorators/customElement.js"; import property from "@ui5/webcomponents-base/dist/decorators/property.js"; import slot from "@ui5/webcomponents-base/dist/decorators/slot.js"; -import event from "@ui5/webcomponents-base/dist/decorators/event.js"; +import event from "@ui5/webcomponents-base/dist/decorators/event-strict.js"; import Button from "@ui5/webcomponents/dist/Button.js"; import BusyIndicator from "@ui5/webcomponents/dist/BusyIndicator.js"; import Icon from "@ui5/webcomponents/dist/Icon.js"; @@ -89,6 +89,7 @@ type NotificationListGroupItemToggleEventDetail = { * @public */ @event("toggle", { + // TODO: XXX detail bubbles: true, }) @@ -103,6 +104,10 @@ type NotificationListGroupItemToggleEventDetail = { }) class NotificationListGroupItem extends NotificationListItemBase { + eventDetails!: NotificationListItemBase["eventDetails"] & { + toggle: NotificationListGroupItemToggleEventDetail; + "load-more": void; + } /** * Defines if the group is collapsed or expanded. * @default false @@ -202,7 +207,7 @@ class NotificationListGroupItem extends NotificationListItemBase { toggleCollapsed() { this.collapsed = !this.collapsed; - this.fireDecoratorEvent("toggle", { item: this }); + this.fireDecoratorEvent("toggle", { item: this }); } /** diff --git a/packages/fiori/src/NotificationListItem.ts b/packages/fiori/src/NotificationListItem.ts index 1f9aa7cfebca..ede37c201ece 100644 --- a/packages/fiori/src/NotificationListItem.ts +++ b/packages/fiori/src/NotificationListItem.ts @@ -5,7 +5,7 @@ import customElement from "@ui5/webcomponents-base/dist/decorators/customElement import property from "@ui5/webcomponents-base/dist/decorators/property.js"; import query from "@ui5/webcomponents-base/dist/decorators/query.js"; import slot from "@ui5/webcomponents-base/dist/decorators/slot.js"; -import event from "@ui5/webcomponents-base/dist/decorators/event.js"; +import event from "@ui5/webcomponents-base/dist/decorators/event-strict.js"; import ResizeHandler from "@ui5/webcomponents-base/dist/delegate/ResizeHandler.js"; import type { ResizeObserverCallback } from "@ui5/webcomponents-base/dist/delegate/ResizeHandler.js"; import Button from "@ui5/webcomponents/dist/Button.js"; @@ -155,7 +155,7 @@ const ICON_PER_STATUS_DESIGN = { * @param {HTMLElement} item the closed item. * @public */ -@event("close", { +@event("close", { detail: { /** * @public @@ -168,6 +168,10 @@ const ICON_PER_STATUS_DESIGN = { }) class NotificationListItem extends NotificationListItemBase { + eventDetails!: NotificationListItemBase["eventDetails"] & { + _press: NotificationListItemPressEventDetail, + close: NotificationListItemCloseEventDetail, + } /** * Defines if the `titleText` and `description` should wrap, * they truncate by default. @@ -555,7 +559,7 @@ class NotificationListItem extends NotificationListItemBase { } if (isDelete(e)) { - this.fireDecoratorEvent("close", { item: this }); + this.fireDecoratorEvent("close", { item: this }); } if (isF10Shift(e)) { @@ -568,7 +572,7 @@ class NotificationListItem extends NotificationListItemBase { } _onBtnCloseClick() { - this.fireDecoratorEvent("close", { item: this }); + this.fireDecoratorEvent("close", { item: this }); } _onBtnMenuClick() { @@ -596,7 +600,7 @@ class NotificationListItem extends NotificationListItemBase { return; } - this.fireDecoratorEvent("_press", { item: this }); + this.fireDecoratorEvent("_press", { item: this }); } onResize() { diff --git a/packages/fiori/src/ProductSwitchItem.ts b/packages/fiori/src/ProductSwitchItem.ts index 8de01f256dc8..78c675199a1a 100644 --- a/packages/fiori/src/ProductSwitchItem.ts +++ b/packages/fiori/src/ProductSwitchItem.ts @@ -4,7 +4,7 @@ import { isSpace, isEnter, isSpaceShift } from "@ui5/webcomponents-base/dist/Key import { isDesktop } from "@ui5/webcomponents-base/dist/Device.js"; import Icon from "@ui5/webcomponents/dist/Icon.js"; import property from "@ui5/webcomponents-base/dist/decorators/property.js"; -import event from "@ui5/webcomponents-base/dist/decorators/event.js"; +import event from "@ui5/webcomponents-base/dist/decorators/event-strict.js"; import customElement from "@ui5/webcomponents-base/dist/decorators/customElement.js"; import ProductSwitchItemTemplate from "./generated/templates/ProductSwitchItemTemplate.lit.js"; import type { IProductSwitchItem } from "./ProductSwitch.js"; @@ -54,6 +54,10 @@ import ProductSwitchItemCss from "./generated/themes/ProductSwitchItem.css.js"; bubbles: true, }) class ProductSwitchItem extends UI5Element implements IProductSwitchItem { + eventDetails!: { + click: { item: ProductSwitchItem }, + _focused: FocusEvent, + } /** * Defines the title of the component. * @default undefined @@ -196,10 +200,12 @@ class ProductSwitchItem extends UI5Element implements IProductSwitchItem { } _onfocusin(e: FocusEvent) { + // TODO: XXX this.fireDecoratorEvent("_focused", e); } _fireItemClick() { + // TODO: XXX this.fireDecoratorEvent("click", { item: this }); } } diff --git a/packages/fiori/src/ShellBar.ts b/packages/fiori/src/ShellBar.ts index 9cccfdc9e7f4..5bfe6c6c50bc 100644 --- a/packages/fiori/src/ShellBar.ts +++ b/packages/fiori/src/ShellBar.ts @@ -3,7 +3,7 @@ import { renderFinished } from "@ui5/webcomponents-base/dist/Render.js"; import property from "@ui5/webcomponents-base/dist/decorators/property.js"; import slot from "@ui5/webcomponents-base/dist/decorators/slot.js"; import customElement from "@ui5/webcomponents-base/dist/decorators/customElement.js"; -import event from "@ui5/webcomponents-base/dist/decorators/event.js"; +import event from "@ui5/webcomponents-base/dist/decorators/event-strict.js"; import i18n from "@ui5/webcomponents-base/dist/decorators/i18n.js"; import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js"; import ResizeHandler from "@ui5/webcomponents-base/dist/delegate/ResizeHandler.js"; @@ -165,7 +165,7 @@ const HANDLE_RESIZE_DEBOUNCE_RATE = 200; // ms * @param {HTMLElement} targetRef dom ref of the activated element * @public */ -@event("notifications-click", { +@event("notifications-click", { detail: { /** * @public @@ -181,7 +181,7 @@ const HANDLE_RESIZE_DEBOUNCE_RATE = 200; // ms * @param {HTMLElement} targetRef dom ref of the activated element * @public */ -@event("profile-click", { +@event("profile-click", { detail: { /** * @public @@ -198,7 +198,7 @@ const HANDLE_RESIZE_DEBOUNCE_RATE = 200; // ms * @param {HTMLElement} targetRef dom ref of the activated element * @public */ -@event("product-switch-click", { +@event("product-switch-click", { detail: { /** * @public @@ -215,7 +215,7 @@ const HANDLE_RESIZE_DEBOUNCE_RATE = 200; // ms * @since 0.10 * @public */ -@event("logo-click", { +@event("logo-click", { detail: { /** * @public @@ -233,7 +233,7 @@ const HANDLE_RESIZE_DEBOUNCE_RATE = 200; // ms * @since 0.10 * @public */ -@event("menu-item-click", { +@event("menu-item-click", { detail: { /** * @public @@ -253,7 +253,7 @@ const HANDLE_RESIZE_DEBOUNCE_RATE = 200; // ms * @public */ -@event("search-button-click", { +@event("search-button-click", { detail: { targetRef: { type: HTMLElement }, searchFieldVisible: { type: Boolean }, @@ -263,6 +263,14 @@ const HANDLE_RESIZE_DEBOUNCE_RATE = 200; // ms }) class ShellBar extends UI5Element { + eventDetails!: { + "notifications-click": ShellBarNotificationsClickEventDetail, + "profile-click": ShellBarProfileClickEventDetail, + "product-switch-click": ShellBarProductSwitchClickEventDetail, + "logo-click": ShellBarLogoClickEventDetail, + "menu-item-click": ShellBarMenuItemClickEventDetail, + "search-button-click": ShellBarSearchButtonEventDetail, + } /** * Defines the `primaryTitle`. * @@ -535,7 +543,7 @@ class ShellBar extends UI5Element { } _menuItemPress(e: CustomEvent) { - const shouldContinue = this.fireDecoratorEvent("menu-item-click", { + const shouldContinue = this.fireDecoratorEvent("menu-item-click", { item: e.detail.selectedItems[0], }); if (shouldContinue) { @@ -544,8 +552,9 @@ class ShellBar extends UI5Element { } _logoPress() { - this.fireDecoratorEvent("logo-click", { - targetRef: this.shadowRoot!.querySelector(".ui5-shellbar-logo")!, + this.fireDecoratorEvent("logo-click", { + // TODO: XXX + targetRef: this.shadowRoot!.querySelector(".ui5-shellbar-logo")!, }); } @@ -739,7 +748,7 @@ class ShellBar extends UI5Element { _handleSearchIconPress() { const searchButtonRef = this.shadowRoot!.querySelector