From 3cad29182e4433874bb335ad3f200f4ba331911d Mon Sep 17 00:00:00 2001 From: stoychevamaria89 Date: Mon, 17 Nov 2025 17:42:08 +0200 Subject: [PATCH 1/6] feat: add type imports and exports to generator logic --- .../executors/generate/component-template.ts | 76 ++++++++++++++++--- .../src/executors/generate/executor.ts | 13 +--- 2 files changed, 66 insertions(+), 23 deletions(-) diff --git a/libs/webc-generator/src/executors/generate/component-template.ts b/libs/webc-generator/src/executors/generate/component-template.ts index 44015723588..c42599bf5a6 100644 --- a/libs/webc-generator/src/executors/generate/component-template.ts +++ b/libs/webc-generator/src/executors/generate/component-template.ts @@ -39,10 +39,9 @@ function hasCvaHostDirective(data: CEM.CustomElementDeclaration): boolean { function generateTypeImports( data: CEM.CustomElementDeclaration, - allEnums: { name: string; members: string[] }[], - enumPackageMapping: Record + allEnums: { name: string; members: string[] }[] ): { componentImports: string[]; componentEnums: string[] } { - const componentImports: string[] = []; + const componentImports: Set = new Set(); const typeNames = new Set(); const members = (data.members as CEM.ClassField[] | undefined) || []; @@ -74,9 +73,9 @@ function generateTypeImports( reference.module?.includes('/types/') ) { // Use default import for direct type imports and default exports - componentImports.push(`import { default as ${reference.name} } from '${importPath}';`); + componentImports.add(`import { default as ${reference.name} } from '${importPath}';`); } else { - componentImports.push(`import { ${reference.name} } from '${importPath}';`); + componentImports.add(`import { ${reference.name} } from '${importPath}';`); } typeNames.add(reference.name); } @@ -84,9 +83,20 @@ function generateTypeImports( } } } + + // Add event types + const events = data.events || []; + for (const event of events) { + if (event.type?.references?.length) { + for (const reference of event.type.references) { + componentImports.add(`import { ${reference.name} } from '${reference.package}/${reference.module}';`); + } + } + } + const extractedEnums = allEnums.filter((e) => typeNames.has(e.name)).map((e) => e.name); - return { componentImports, componentEnums: extractedEnums }; + return { componentImports: Array.from(componentImports), componentEnums: extractedEnums }; } /** Helper function to generate input properties for the component. */ @@ -204,24 +214,66 @@ function generateOutputs(data: CEM.CustomElementDeclaration, className: string): data.events?.forEach((event) => { // Convert kebab-case to PascalCase after ui5 prefix const pascalCaseEventName = kebabToCamelCase(event.name).replace(/^./, (char) => char.toUpperCase()); - outputs.push(` + + if (event.type.references?.length) { + outputs.push(` + /** + * ${event.description || ''} + */ + ui5${pascalCaseEventName} = output<${event.type.text}>();`); + } else { + outputs.push(` /** * ${event.description || ''} */ ui5${pascalCaseEventName} = output>();`); + } }); + return outputs.join('\n'); } +function generateExports(data: CEM.CustomElementDeclaration): string { + const className = data.name; + const exports: Set = new Set(); + const isExportedFromComponent = (ref: CEM.TypeReference): boolean | undefined => + ref.module?.split('.')[0].endsWith(className); + + const members = (data.members as CEM.ClassField[] | undefined) || []; + members?.forEach((member) => { + if (member.type?.references?.length) { + member.type.references.forEach((ref) => { + // export only those types that are exported from the current component + if (isExportedFromComponent(ref)) { + exports.add(ref.name); + } + }); + } + }); + + data.events?.forEach((event) => { + event.type.references?.forEach((ref) => { + // export only those types that are exported from the current component + if (isExportedFromComponent(ref)) { + exports.add(ref.name); + } + }); + }); + + return exports.size + ? `export type {\n${Array.from(exports) + .map((type) => `\t${type}`) + .join(',\n')}\n};` + : ''; +} + /** Generate the Angular component wrapper. */ export function componentTemplate( data: CEM.CustomElementDeclaration, - cemPackage: CEM.Package, allEnums: { name: string; members: string[] }[], - packageName: string, - enumPackageMapping: Record + packageName: string ): string { - const { componentImports, componentEnums } = generateTypeImports(data, allEnums, enumPackageMapping); + const { componentImports, componentEnums } = generateTypeImports(data, allEnums); const tagName = data.tagName || ''; const className = data.name; const { readonlyProperties, privateProperties } = generateProperties(data); @@ -411,5 +463,7 @@ ${(() => { })()} } } + +${generateExports(data)} `; } diff --git a/libs/webc-generator/src/executors/generate/executor.ts b/libs/webc-generator/src/executors/generate/executor.ts index 8091156bcac..d37f6487515 100644 --- a/libs/webc-generator/src/executors/generate/executor.ts +++ b/libs/webc-generator/src/executors/generate/executor.ts @@ -18,13 +18,6 @@ const FILES = { THEMING_TEMPLATE: 'utils/theming-service-template.tpl' }; -const DEFAULT_ENUM_PACKAGE_MAPPING: Record = { - '@ui5/webcomponents': '@fundamental-ngx/ui5-webcomponents/types', - '@ui5/webcomponents-base': '@fundamental-ngx/ui5-webcomponents-base/types', - '@ui5/webcomponents-fiori': '@fundamental-ngx/ui5-webcomponents-fiori/types', - '@ui5/webcomponents-ai': '@fundamental-ngx/ui5-webcomponents-ai/types' -}; - /** Converts PascalCase to kebab-case (e.g., 'Ui5Button' -> 'ui5-button'). */ const pascalToKebabCase = (str: string): string => str.replace(/\B([A-Z])/g, '-$1').toLowerCase(); @@ -173,7 +166,6 @@ async function generateThemingFiles(packageName: string, targetDir: string): Pro */ async function generateComponentFiles( componentDeclarations: { declaration: CEM.CustomElementDeclaration; modulePath: string }[], - cemData: CEM.Package, allEnums: ExtractedCemData['allEnums'], packageName: string, targetDir: string @@ -197,10 +189,8 @@ async function generateComponentFiles( const templateContent = componentTemplate( declaration, - cemData, allEnums.map((e) => ({ name: e.name, members: e.members })), - packageName, - DEFAULT_ENUM_PACKAGE_MAPPING + packageName ); return ensureDirAndWriteFile(componentIndexPath, templateContent).then(() => @@ -282,7 +272,6 @@ const runExecutor: PromiseExecutor = async (options, con // Generate Component Wrappers const componentExports = await generateComponentFiles( componentDeclarations, - cemData, allEnums, packageName, targetDir From 6a13d6739fd552b28e11052860a23752408831b6 Mon Sep 17 00:00:00 2001 From: stoychevamaria89 Date: Mon, 17 Nov 2025 17:42:47 +0200 Subject: [PATCH 2/6] fix: amend some event types --- .../button/examples/button-sample.ts | 5 +- .../calendar/examples/calendar-sample.html | 20 +++--- .../calendar/examples/calendar-sample.ts | 16 +++-- .../carousel/examples/carousel-sample.ts | 64 +++++++++---------- .../form/examples/validation.ts | 15 ++--- .../list/examples/drag-and-drop.ts | 11 ++-- .../time-picker/examples/basic-sample.ts | 3 +- 7 files changed, 61 insertions(+), 73 deletions(-) diff --git a/libs/docs/ui5-webcomponents/button/examples/button-sample.ts b/libs/docs/ui5-webcomponents/button/examples/button-sample.ts index 8ef934fdd2d..a17c240cb6d 100644 --- a/libs/docs/ui5-webcomponents/button/examples/button-sample.ts +++ b/libs/docs/ui5-webcomponents/button/examples/button-sample.ts @@ -1,5 +1,6 @@ import { Component, signal } from '@angular/core'; -import { Button } from '@fundamental-ngx/ui5-webcomponents/button'; +import { Button, ButtonClickEventDetail } from '@fundamental-ngx/ui5-webcomponents/button'; + import '@ui5/webcomponents-icons/dist/AllIcons.js'; @Component({ @@ -17,7 +18,7 @@ import '@ui5/webcomponents-icons/dist/AllIcons.js'; }) export class ButtonExample { // Example click handler - onButtonClick(event: any, buttonLabel: string): void { + onButtonClick(event: CustomEvent, buttonLabel: string): void { console.log(`${buttonLabel} clicked`, event); } diff --git a/libs/docs/ui5-webcomponents/calendar/examples/calendar-sample.html b/libs/docs/ui5-webcomponents/calendar/examples/calendar-sample.html index d397edb9e83..5a278dd62f2 100644 --- a/libs/docs/ui5-webcomponents/calendar/examples/calendar-sample.html +++ b/libs/docs/ui5-webcomponents/calendar/examples/calendar-sample.html @@ -2,7 +2,7 @@

Calendar

- +

Selected Dates: {{ selectedDatesDisplay() }}

Selection Mode: {{ currentSelectionMode() }}

@@ -41,7 +41,7 @@

Quick Actions

[formatPattern]="formatPattern()" [minDate]="minDate()" [maxDate]="maxDate()" - (ui5selectionChange)="onSelectionChange($event)" + (ui5SelectionChange)="onSelectionChange($event)" aria-label="Configured calendar example" > @if (currentSelectionMode() !== 'Range') { @for (date of selectedDates(); track date) { @@ -66,7 +66,7 @@

Range Selection Calendar

@@ -83,7 +83,7 @@

Multiple Selection Calendar @@ -104,7 +104,7 @@

Calendar with Date Restri minDate="2024-06-01" maxDate="2024-12-31" formatPattern="MM/dd/yyyy" - (ui5selectionChange)="onSelectionChange($event)" + (ui5SelectionChange)="onSelectionChange($event)" aria-label="Date restricted calendar" > @@ -129,7 +129,7 @@

Gregorian Calendar

@@ -146,7 +146,7 @@

Islamic Calendar

@@ -163,7 +163,7 @@

Japanese Calendar

@@ -180,7 +180,7 @@

Buddhist Calendar

@@ -199,7 +199,7 @@

Dual Calendar Type

primaryCalendarType="Gregorian" secondaryCalendarType="Islamic" selectionMode="Single" - (ui5selectionChange)="onSelectionChange($event)" + (ui5SelectionChange)="onSelectionChange($event)" aria-label="Dual calendar type example" > diff --git a/libs/docs/ui5-webcomponents/calendar/examples/calendar-sample.ts b/libs/docs/ui5-webcomponents/calendar/examples/calendar-sample.ts index 046de4482fd..ff5811f4b20 100644 --- a/libs/docs/ui5-webcomponents/calendar/examples/calendar-sample.ts +++ b/libs/docs/ui5-webcomponents/calendar/examples/calendar-sample.ts @@ -1,8 +1,11 @@ import { Component, computed, effect, signal } from '@angular/core'; import { Button } from '@fundamental-ngx/ui5-webcomponents/button'; -import { Calendar } from '@fundamental-ngx/ui5-webcomponents/calendar'; +import { Calendar, CalendarSelectionChangeEventDetail } from '@fundamental-ngx/ui5-webcomponents/calendar'; import { CalendarDate } from '@fundamental-ngx/ui5-webcomponents/calendar-date'; -import { SegmentedButton } from '@fundamental-ngx/ui5-webcomponents/segmented-button'; +import { + SegmentedButton, + SegmentedButtonSelectionChangeEventDetail +} from '@fundamental-ngx/ui5-webcomponents/segmented-button'; import { SegmentedButtonItem } from '@fundamental-ngx/ui5-webcomponents/segmented-button-item'; import { CalendarSelectionMode, CalendarWeekNumbering } from '@fundamental-ngx/ui5-webcomponents/types'; @@ -79,10 +82,9 @@ export class CalendarExample { } // Event handlers using Angular 20 patterns - onSelectionChange(event: any): void { - const calendarEvent = event.detail; + onSelectionChange(event: CustomEvent): void { // Extract selectedValues (date strings) instead of selectedDates (timestamps) - const dates = calendarEvent.selectedValues || []; + const dates = event.detail.selectedValues || []; this.selectedDates.set(dates); console.log('Calendar selection changed:', dates); } @@ -98,7 +100,7 @@ export class CalendarExample { } // Event handlers for UI5 segmented buttons - onSelectionModeChange(event: any): void { + onSelectionModeChange(event: CustomEvent): void { console.log('onSelectionModeChange called', event.detail); const selectedItems = event.detail.selectedItems; if (selectedItems && selectedItems.length > 0) { @@ -107,7 +109,7 @@ export class CalendarExample { } } - onCalendarTypeChange(event: any): void { + onCalendarTypeChange(event: CustomEvent): void { console.log('onCalendarTypeChange called:', event.detail.selectedItems[0].innerText); const selectedItems = event.detail.selectedItems; if (selectedItems && selectedItems.length > 0) { diff --git a/libs/docs/ui5-webcomponents/carousel/examples/carousel-sample.ts b/libs/docs/ui5-webcomponents/carousel/examples/carousel-sample.ts index fc5f75aca24..c283fc9a6b2 100644 --- a/libs/docs/ui5-webcomponents/carousel/examples/carousel-sample.ts +++ b/libs/docs/ui5-webcomponents/carousel/examples/carousel-sample.ts @@ -2,10 +2,13 @@ import { Component, computed, effect, signal } from '@angular/core'; import { Button } from '@fundamental-ngx/ui5-webcomponents/button'; import { Card } from '@fundamental-ngx/ui5-webcomponents/card'; import { CardHeader } from '@fundamental-ngx/ui5-webcomponents/card-header'; -import { Carousel } from '@fundamental-ngx/ui5-webcomponents/carousel'; +import { Carousel, CarouselNavigateEventDetail } from '@fundamental-ngx/ui5-webcomponents/carousel'; import { Icon } from '@fundamental-ngx/ui5-webcomponents/icon'; import { Label } from '@fundamental-ngx/ui5-webcomponents/label'; -import { SegmentedButton } from '@fundamental-ngx/ui5-webcomponents/segmented-button'; +import { + SegmentedButton, + SegmentedButtonSelectionChangeEventDetail +} from '@fundamental-ngx/ui5-webcomponents/segmented-button'; import { SegmentedButtonItem } from '@fundamental-ngx/ui5-webcomponents/segmented-button-item'; import { Switch } from '@fundamental-ngx/ui5-webcomponents/switch'; import { Tag } from '@fundamental-ngx/ui5-webcomponents/tag'; @@ -166,32 +169,32 @@ export class CarouselExample { } // Navigation event handlers - onBasicNavigate(event: any): void { + onBasicNavigate(event: CustomEvent): void { const detail = event.detail; this.basicCurrentPage.set(detail.selectedIndex); console.log('Basic carousel navigated to page:', detail.selectedIndex); } - onImageNavigate(event: any): void { + onImageNavigate(event: CustomEvent): void { const detail = event.detail; this.currentImagePage.set(detail.selectedIndex); console.log('Image carousel navigated to page:', detail.selectedIndex); } - onProductNavigate(event: any): void { + onProductNavigate(event: CustomEvent): void { const detail = event.detail; this.currentProductPage.set(detail.selectedIndex); console.log('Product carousel navigated to page:', detail.selectedIndex); } - onFeatureNavigate(event: any): void { + onFeatureNavigate(event: CustomEvent): void { const detail = event.detail; this.currentFeaturePage.set(detail.selectedIndex); console.log('Feature carousel navigated to page:', detail.selectedIndex); } // Configuration change handlers - onPageIndicatorTypeChange(event: any): void { + onPageIndicatorTypeChange(event: CustomEvent): void { const detail = event.detail; const selectedItems = detail.selectedItems || []; if (selectedItems.length > 0) { @@ -200,16 +203,7 @@ export class CarouselExample { } } - onBackgroundDesignChange(event: any): void { - const detail = event.detail; - const selectedItems = detail.selectedItems || []; - if (selectedItems.length > 0) { - const selectedDesign = selectedItems[0].innerText as BackgroundDesign; - this.backgroundDesign.set(selectedDesign); - } - } - - onArrowsPlacementChange(event: any): void { + onArrowsPlacementChange(event: CustomEvent): void { const detail = event.detail; const selectedItems = detail.selectedItems || []; if (selectedItems.length > 0) { @@ -276,30 +270,30 @@ export class CarouselExample { return types[status] || '1'; } - getImageStyle(image: any): string { + getImageStyle(image: { url: string; title: string; description: string; gradient: string }): string { return ` - height: 500px; - background: ${image.gradient}; - background-image: url('${image.url}'); - background-size: cover; - background-position: center; - background-blend-mode: overlay; - display: flex; - align-items: center; + height: 500px; + background: ${image.gradient}; + background-image: url('${image.url}'); + background-size: cover; + background-position: center; + background-blend-mode: overlay; + display: flex; + align-items: center; justify-content: center; `; } - getCardImageStyle(image: any): string { + getCardImageStyle(image: { url: string; title: string; description: string; gradient: string }): string { return ` - height: 250px; - background: ${image.gradient}; - background-image: url('${image.url}'); - background-size: cover; - background-position: center; - background-blend-mode: overlay; - display: flex; - align-items: center; + height: 250px; + background: ${image.gradient}; + background-image: url('${image.url}'); + background-size: cover; + background-position: center; + background-blend-mode: overlay; + display: flex; + align-items: center; justify-content: center; `; } diff --git a/libs/docs/ui5-webcomponents/form/examples/validation.ts b/libs/docs/ui5-webcomponents/form/examples/validation.ts index 9ddf7ef6627..c548750ff51 100644 --- a/libs/docs/ui5-webcomponents/form/examples/validation.ts +++ b/libs/docs/ui5-webcomponents/form/examples/validation.ts @@ -9,12 +9,7 @@ import { FormItem } from '@fundamental-ngx/ui5-webcomponents/form-item'; import { Input } from '@fundamental-ngx/ui5-webcomponents/input'; import { Label } from '@fundamental-ngx/ui5-webcomponents/label'; import { MessageStrip } from '@fundamental-ngx/ui5-webcomponents/message-strip'; -import { TextArea } from '@fundamental-ngx/ui5-webcomponents/text-area'; - -// Import UI5 custom event types -import { UI5CustomEvent } from '@ui5/webcomponents-base'; -import { default as _Input } from '@ui5/webcomponents/dist/Input.js'; -import { default as _TextArea } from '@ui5/webcomponents/dist/TextArea.js'; +import { TextArea, TextAreaInputEventDetail } from '@fundamental-ngx/ui5-webcomponents/text-area'; // Import Fundamental Styles import 'fundamental-styles/dist/layout-grid.css'; @@ -185,20 +180,20 @@ export class FormValidationSample { return 'Invalid input'; } - onInputChange(fieldName: string, event: UI5CustomEvent<_Input, 'input'>): void { + onInputChange(fieldName: string, event: CustomEvent): void { const value = (event.target as any)?.value; this.registrationForm.get(fieldName)?.setValue(value); this.registrationForm.get(fieldName)?.markAsDirty(); } - onTextAreaChange(fieldName: string, event: UI5CustomEvent<_TextArea, 'input'>): void { + onTextAreaChange(fieldName: string, event: CustomEvent): void { const value = (event.target as any)?.value; this.registrationForm.get(fieldName)?.setValue(value); this.registrationForm.get(fieldName)?.markAsDirty(); } - onCheckboxChange(fieldName: string, event: any): void { - const checked = event.target.checked; + onCheckboxChange(fieldName: string, event: CustomEvent): void { + const checked = (event.target as any)?.checked; this.registrationForm.get(fieldName)?.setValue(checked); this.registrationForm.get(fieldName)?.markAsDirty(); } diff --git a/libs/docs/ui5-webcomponents/list/examples/drag-and-drop.ts b/libs/docs/ui5-webcomponents/list/examples/drag-and-drop.ts index fd599582766..467d04b1e63 100644 --- a/libs/docs/ui5-webcomponents/list/examples/drag-and-drop.ts +++ b/libs/docs/ui5-webcomponents/list/examples/drag-and-drop.ts @@ -1,11 +1,8 @@ import { Component, signal } from '@angular/core'; import { MovePlacement } from '@fundamental-ngx/ui5-webcomponents-base/types'; -import { List } from '@fundamental-ngx/ui5-webcomponents/list'; +import { List, ListMoveEventDetail } from '@fundamental-ngx/ui5-webcomponents/list'; import { ListItemStandard } from '@fundamental-ngx/ui5-webcomponents/list-item-standard'; -import { UI5CustomEvent } from '@ui5/webcomponents-base'; -import { default as _List } from '@ui5/webcomponents/dist/List.js'; - // Import the icon used in this example import '@ui5/webcomponents-icons/dist/checklist-item.js'; @@ -18,7 +15,7 @@ import '@ui5/webcomponents-icons/dist/checklist-item.js'; export class ListDragAndDropExample { readonly items = signal(['Item #1', 'Item #2', 'Item #3', 'Item #4']); - onItemMove(event: any): void { + onItemMove(event: CustomEvent): void { const { destination, source } = event.detail; switch (destination.placement) { @@ -34,7 +31,7 @@ export class ListDragAndDropExample { } } - onItemMoveOver(event: UI5CustomEvent<_List, 'move-over'>): void { + onItemMoveOver(event: CustomEvent): void { const { source } = event.detail; if (!(event.target as HTMLElement).contains(source.element)) { @@ -44,7 +41,7 @@ export class ListDragAndDropExample { this.handleBeforeItemMove(event); } - private handleBeforeItemMove(event: UI5CustomEvent<_List, 'move-over'>): void { + private handleBeforeItemMove(event: CustomEvent): void { const { destination } = event.detail; if (destination.placement === 'Before' || destination.placement === 'After') { diff --git a/libs/docs/ui5-webcomponents/time-picker/examples/basic-sample.ts b/libs/docs/ui5-webcomponents/time-picker/examples/basic-sample.ts index b2289d7b3df..9ebbaba2981 100644 --- a/libs/docs/ui5-webcomponents/time-picker/examples/basic-sample.ts +++ b/libs/docs/ui5-webcomponents/time-picker/examples/basic-sample.ts @@ -1,7 +1,6 @@ import { NgStyle } from '@angular/common'; import { Component, signal } from '@angular/core'; -import { TimePicker } from '@fundamental-ngx/ui5-webcomponents/time-picker'; -import { TimePickerChangeEventDetail } from '@ui5/webcomponents/dist/TimePicker.js'; +import { TimePicker, TimePickerChangeEventDetail } from '@fundamental-ngx/ui5-webcomponents/time-picker'; // Ensure CLDR data is available for all time-picker components import '@ui5/webcomponents-localization/dist/Assets.js'; From 1ed4ec0631414d7422279448fd049b58f78dfaf3 Mon Sep 17 00:00:00 2001 From: stoychevamaria89 Date: Wed, 19 Nov 2025 15:13:28 +0200 Subject: [PATCH 3/6] feat: suggest another approach to handling event emitter types --- .../button/examples/button-sample.ts | 5 +- .../calendar/examples/calendar-sample.ts | 14 ++--- .../carousel/examples/carousel-sample.ts | 21 ++++--- .../form/examples/validation.ts | 7 ++- .../list/examples/drag-and-drop.ts | 9 +-- .../time-picker/examples/basic-sample.ts | 9 +-- .../time-picker/examples/events.ts | 11 ++-- libs/ui5-webcomponents-base/index.ts | 8 +++ .../executors/generate/component-template.ts | 57 +------------------ .../src/executors/generate/executor.ts | 18 ++++++ 10 files changed, 65 insertions(+), 94 deletions(-) diff --git a/libs/docs/ui5-webcomponents/button/examples/button-sample.ts b/libs/docs/ui5-webcomponents/button/examples/button-sample.ts index a17c240cb6d..d2105dc245c 100644 --- a/libs/docs/ui5-webcomponents/button/examples/button-sample.ts +++ b/libs/docs/ui5-webcomponents/button/examples/button-sample.ts @@ -1,5 +1,6 @@ import { Component, signal } from '@angular/core'; -import { Button, ButtonClickEventDetail } from '@fundamental-ngx/ui5-webcomponents/button'; +import type { UI5WrapperCustomEvent } from '@fundamental-ngx/ui5-webcomponents-base'; +import { Button } from '@fundamental-ngx/ui5-webcomponents/button'; import '@ui5/webcomponents-icons/dist/AllIcons.js'; @@ -18,7 +19,7 @@ import '@ui5/webcomponents-icons/dist/AllIcons.js'; }) export class ButtonExample { // Example click handler - onButtonClick(event: CustomEvent, buttonLabel: string): void { + onButtonClick(event: UI5WrapperCustomEvent, buttonLabel: string): void { console.log(`${buttonLabel} clicked`, event); } diff --git a/libs/docs/ui5-webcomponents/calendar/examples/calendar-sample.ts b/libs/docs/ui5-webcomponents/calendar/examples/calendar-sample.ts index ff5811f4b20..edc8e2f8af4 100644 --- a/libs/docs/ui5-webcomponents/calendar/examples/calendar-sample.ts +++ b/libs/docs/ui5-webcomponents/calendar/examples/calendar-sample.ts @@ -1,11 +1,9 @@ import { Component, computed, effect, signal } from '@angular/core'; +import type { UI5WrapperCustomEvent } from '@fundamental-ngx/ui5-webcomponents-base'; import { Button } from '@fundamental-ngx/ui5-webcomponents/button'; -import { Calendar, CalendarSelectionChangeEventDetail } from '@fundamental-ngx/ui5-webcomponents/calendar'; +import { Calendar } from '@fundamental-ngx/ui5-webcomponents/calendar'; import { CalendarDate } from '@fundamental-ngx/ui5-webcomponents/calendar-date'; -import { - SegmentedButton, - SegmentedButtonSelectionChangeEventDetail -} from '@fundamental-ngx/ui5-webcomponents/segmented-button'; +import { SegmentedButton } from '@fundamental-ngx/ui5-webcomponents/segmented-button'; import { SegmentedButtonItem } from '@fundamental-ngx/ui5-webcomponents/segmented-button-item'; import { CalendarSelectionMode, CalendarWeekNumbering } from '@fundamental-ngx/ui5-webcomponents/types'; @@ -82,7 +80,7 @@ export class CalendarExample { } // Event handlers using Angular 20 patterns - onSelectionChange(event: CustomEvent): void { + onSelectionChange(event: UI5WrapperCustomEvent): void { // Extract selectedValues (date strings) instead of selectedDates (timestamps) const dates = event.detail.selectedValues || []; this.selectedDates.set(dates); @@ -100,7 +98,7 @@ export class CalendarExample { } // Event handlers for UI5 segmented buttons - onSelectionModeChange(event: CustomEvent): void { + onSelectionModeChange(event: UI5WrapperCustomEvent): void { console.log('onSelectionModeChange called', event.detail); const selectedItems = event.detail.selectedItems; if (selectedItems && selectedItems.length > 0) { @@ -109,7 +107,7 @@ export class CalendarExample { } } - onCalendarTypeChange(event: CustomEvent): void { + onCalendarTypeChange(event: UI5WrapperCustomEvent): void { console.log('onCalendarTypeChange called:', event.detail.selectedItems[0].innerText); const selectedItems = event.detail.selectedItems; if (selectedItems && selectedItems.length > 0) { diff --git a/libs/docs/ui5-webcomponents/carousel/examples/carousel-sample.ts b/libs/docs/ui5-webcomponents/carousel/examples/carousel-sample.ts index c283fc9a6b2..60be505a8d1 100644 --- a/libs/docs/ui5-webcomponents/carousel/examples/carousel-sample.ts +++ b/libs/docs/ui5-webcomponents/carousel/examples/carousel-sample.ts @@ -1,14 +1,12 @@ import { Component, computed, effect, signal } from '@angular/core'; +import type { UI5WrapperCustomEvent } from '@fundamental-ngx/ui5-webcomponents-base'; import { Button } from '@fundamental-ngx/ui5-webcomponents/button'; import { Card } from '@fundamental-ngx/ui5-webcomponents/card'; import { CardHeader } from '@fundamental-ngx/ui5-webcomponents/card-header'; -import { Carousel, CarouselNavigateEventDetail } from '@fundamental-ngx/ui5-webcomponents/carousel'; +import { Carousel } from '@fundamental-ngx/ui5-webcomponents/carousel'; import { Icon } from '@fundamental-ngx/ui5-webcomponents/icon'; import { Label } from '@fundamental-ngx/ui5-webcomponents/label'; -import { - SegmentedButton, - SegmentedButtonSelectionChangeEventDetail -} from '@fundamental-ngx/ui5-webcomponents/segmented-button'; +import { SegmentedButton } from '@fundamental-ngx/ui5-webcomponents/segmented-button'; import { SegmentedButtonItem } from '@fundamental-ngx/ui5-webcomponents/segmented-button-item'; import { Switch } from '@fundamental-ngx/ui5-webcomponents/switch'; import { Tag } from '@fundamental-ngx/ui5-webcomponents/tag'; @@ -19,6 +17,7 @@ import { CarouselArrowsPlacement, CarouselPageIndicatorType } from '@fundamental-ngx/ui5-webcomponents/types'; + import '@ui5/webcomponents-icons/dist/AllIcons.js'; // Import Fundamental Styles @@ -169,32 +168,32 @@ export class CarouselExample { } // Navigation event handlers - onBasicNavigate(event: CustomEvent): void { + onBasicNavigate(event: UI5WrapperCustomEvent): void { const detail = event.detail; this.basicCurrentPage.set(detail.selectedIndex); console.log('Basic carousel navigated to page:', detail.selectedIndex); } - onImageNavigate(event: CustomEvent): void { + onImageNavigate(event: UI5WrapperCustomEvent): void { const detail = event.detail; this.currentImagePage.set(detail.selectedIndex); console.log('Image carousel navigated to page:', detail.selectedIndex); } - onProductNavigate(event: CustomEvent): void { + onProductNavigate(event: UI5WrapperCustomEvent): void { const detail = event.detail; this.currentProductPage.set(detail.selectedIndex); console.log('Product carousel navigated to page:', detail.selectedIndex); } - onFeatureNavigate(event: CustomEvent): void { + onFeatureNavigate(event: UI5WrapperCustomEvent): void { const detail = event.detail; this.currentFeaturePage.set(detail.selectedIndex); console.log('Feature carousel navigated to page:', detail.selectedIndex); } // Configuration change handlers - onPageIndicatorTypeChange(event: CustomEvent): void { + onPageIndicatorTypeChange(event: UI5WrapperCustomEvent): void { const detail = event.detail; const selectedItems = detail.selectedItems || []; if (selectedItems.length > 0) { @@ -203,7 +202,7 @@ export class CarouselExample { } } - onArrowsPlacementChange(event: CustomEvent): void { + onArrowsPlacementChange(event: UI5WrapperCustomEvent): void { const detail = event.detail; const selectedItems = detail.selectedItems || []; if (selectedItems.length > 0) { diff --git a/libs/docs/ui5-webcomponents/form/examples/validation.ts b/libs/docs/ui5-webcomponents/form/examples/validation.ts index c548750ff51..912607d1d4c 100644 --- a/libs/docs/ui5-webcomponents/form/examples/validation.ts +++ b/libs/docs/ui5-webcomponents/form/examples/validation.ts @@ -1,6 +1,7 @@ import { JsonPipe } from '@angular/common'; import { Component, computed, effect, signal } from '@angular/core'; import { AbstractControl, FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms'; +import type { UI5WrapperCustomEvent } from '@fundamental-ngx/ui5-webcomponents-base'; import { Button } from '@fundamental-ngx/ui5-webcomponents/button'; import { CheckBox } from '@fundamental-ngx/ui5-webcomponents/check-box'; import { Form } from '@fundamental-ngx/ui5-webcomponents/form'; @@ -9,7 +10,7 @@ import { FormItem } from '@fundamental-ngx/ui5-webcomponents/form-item'; import { Input } from '@fundamental-ngx/ui5-webcomponents/input'; import { Label } from '@fundamental-ngx/ui5-webcomponents/label'; import { MessageStrip } from '@fundamental-ngx/ui5-webcomponents/message-strip'; -import { TextArea, TextAreaInputEventDetail } from '@fundamental-ngx/ui5-webcomponents/text-area'; +import { TextArea } from '@fundamental-ngx/ui5-webcomponents/text-area'; // Import Fundamental Styles import 'fundamental-styles/dist/layout-grid.css'; @@ -186,13 +187,13 @@ export class FormValidationSample { this.registrationForm.get(fieldName)?.markAsDirty(); } - onTextAreaChange(fieldName: string, event: CustomEvent): void { + onTextAreaChange(fieldName: string, event: UI5WrapperCustomEvent): void { const value = (event.target as any)?.value; this.registrationForm.get(fieldName)?.setValue(value); this.registrationForm.get(fieldName)?.markAsDirty(); } - onCheckboxChange(fieldName: string, event: CustomEvent): void { + onCheckboxChange(fieldName: string, event: UI5WrapperCustomEvent): void { const checked = (event.target as any)?.checked; this.registrationForm.get(fieldName)?.setValue(checked); this.registrationForm.get(fieldName)?.markAsDirty(); diff --git a/libs/docs/ui5-webcomponents/list/examples/drag-and-drop.ts b/libs/docs/ui5-webcomponents/list/examples/drag-and-drop.ts index 467d04b1e63..f53f36dbbda 100644 --- a/libs/docs/ui5-webcomponents/list/examples/drag-and-drop.ts +++ b/libs/docs/ui5-webcomponents/list/examples/drag-and-drop.ts @@ -1,6 +1,7 @@ import { Component, signal } from '@angular/core'; +import type { UI5WrapperCustomEvent } from '@fundamental-ngx/ui5-webcomponents-base'; import { MovePlacement } from '@fundamental-ngx/ui5-webcomponents-base/types'; -import { List, ListMoveEventDetail } from '@fundamental-ngx/ui5-webcomponents/list'; +import { List } from '@fundamental-ngx/ui5-webcomponents/list'; import { ListItemStandard } from '@fundamental-ngx/ui5-webcomponents/list-item-standard'; // Import the icon used in this example @@ -15,7 +16,7 @@ import '@ui5/webcomponents-icons/dist/checklist-item.js'; export class ListDragAndDropExample { readonly items = signal(['Item #1', 'Item #2', 'Item #3', 'Item #4']); - onItemMove(event: CustomEvent): void { + onItemMove(event: UI5WrapperCustomEvent): void { const { destination, source } = event.detail; switch (destination.placement) { @@ -31,7 +32,7 @@ export class ListDragAndDropExample { } } - onItemMoveOver(event: CustomEvent): void { + onItemMoveOver(event: UI5WrapperCustomEvent): void { const { source } = event.detail; if (!(event.target as HTMLElement).contains(source.element)) { @@ -41,7 +42,7 @@ export class ListDragAndDropExample { this.handleBeforeItemMove(event); } - private handleBeforeItemMove(event: CustomEvent): void { + private handleBeforeItemMove(event: UI5WrapperCustomEvent): void { const { destination } = event.detail; if (destination.placement === 'Before' || destination.placement === 'After') { diff --git a/libs/docs/ui5-webcomponents/time-picker/examples/basic-sample.ts b/libs/docs/ui5-webcomponents/time-picker/examples/basic-sample.ts index 9ebbaba2981..2717cf83ad4 100644 --- a/libs/docs/ui5-webcomponents/time-picker/examples/basic-sample.ts +++ b/libs/docs/ui5-webcomponents/time-picker/examples/basic-sample.ts @@ -1,6 +1,7 @@ import { NgStyle } from '@angular/common'; import { Component, signal } from '@angular/core'; -import { TimePicker, TimePickerChangeEventDetail } from '@fundamental-ngx/ui5-webcomponents/time-picker'; +import type { UI5WrapperCustomEvent } from '@fundamental-ngx/ui5-webcomponents-base'; +import { TimePicker } from '@fundamental-ngx/ui5-webcomponents/time-picker'; // Ensure CLDR data is available for all time-picker components import '@ui5/webcomponents-localization/dist/Assets.js'; @@ -20,15 +21,15 @@ export class TimePickerBasicSample { readonly placeholderValue = signal(''); readonly formattedValue = signal('14:30:00'); - onBasicValueChange(event: CustomEvent): void { + onBasicValueChange(event: UI5WrapperCustomEvent): void { this.basicValue.set(event.detail.value); } - onPlaceholderValueChange(event: CustomEvent): void { + onPlaceholderValueChange(event: UI5WrapperCustomEvent): void { this.placeholderValue.set(event.detail.value); } - onFormattedValueChange(event: CustomEvent): void { + onFormattedValueChange(event: UI5WrapperCustomEvent): void { this.formattedValue.set(event.detail.value); } } diff --git a/libs/docs/ui5-webcomponents/time-picker/examples/events.ts b/libs/docs/ui5-webcomponents/time-picker/examples/events.ts index a42c5357070..ccbb558cce3 100644 --- a/libs/docs/ui5-webcomponents/time-picker/examples/events.ts +++ b/libs/docs/ui5-webcomponents/time-picker/examples/events.ts @@ -3,12 +3,11 @@ import { Label } from '@fundamental-ngx/ui5-webcomponents/label'; import { Text } from '@fundamental-ngx/ui5-webcomponents/text'; import { TimePicker } from '@fundamental-ngx/ui5-webcomponents/time-picker'; -import { TimePickerChangeEventDetail, TimePickerInputEventDetail } from '@ui5/webcomponents/dist/TimePicker.js'; - // Ensure CLDR data is available for all time-picker components import '@ui5/webcomponents-localization/dist/Assets.js'; // Import Fundamental Styles +import type { UI5WrapperCustomEvent } from '@fundamental-ngx/ui5-webcomponents-base'; import 'fundamental-styles/dist/form-item.css'; import 'fundamental-styles/dist/margins.css'; import 'fundamental-styles/dist/text.css'; @@ -32,20 +31,20 @@ export class TimePickerEventsSample { this.eventLog.update((log) => [eventDescription, ...log].slice(0, 10)); // Keep last 10 events } - onTimeChange(event: CustomEvent): void { + onTimeChange(event: UI5WrapperCustomEvent): void { this.timeValue.set(event.detail.value); this.addEvent('ui5Change', { value: event.detail.value }); } - onTimeInput(event: CustomEvent): void { + onTimeInput(event: UI5WrapperCustomEvent): void { this.addEvent('ui5Input', { value: event.detail.value }); } - onTimeOpen(_event: CustomEvent): void { + onTimeOpen(_event: UI5WrapperCustomEvent): void { this.addEvent('ui5Open'); } - onTimeClose(_event: CustomEvent): void { + onTimeClose(_event: UI5WrapperCustomEvent): void { this.addEvent('ui5Close'); } } diff --git a/libs/ui5-webcomponents-base/index.ts b/libs/ui5-webcomponents-base/index.ts index fcb073fefcd..64d3dafb01c 100644 --- a/libs/ui5-webcomponents-base/index.ts +++ b/libs/ui5-webcomponents-base/index.ts @@ -1 +1,9 @@ export * from './types'; + +import { OutputEmitterRef } from '@angular/core'; + +type OutputKeys = { + [K in keyof T]: T[K] extends OutputEmitterRef ? K : never; +}[keyof T]; + +export type UI5WrapperCustomEvent> = T[N] extends OutputEmitterRef ? E : never; diff --git a/libs/webc-generator/src/executors/generate/component-template.ts b/libs/webc-generator/src/executors/generate/component-template.ts index c42599bf5a6..38e20365f3b 100644 --- a/libs/webc-generator/src/executors/generate/component-template.ts +++ b/libs/webc-generator/src/executors/generate/component-template.ts @@ -84,16 +84,6 @@ function generateTypeImports( } } - // Add event types - const events = data.events || []; - for (const event of events) { - if (event.type?.references?.length) { - for (const reference of event.type.references) { - componentImports.add(`import { ${reference.name} } from '${reference.package}/${reference.module}';`); - } - } - } - const extractedEnums = allEnums.filter((e) => typeNames.has(e.name)).map((e) => e.name); return { componentImports: Array.from(componentImports), componentEnums: extractedEnums }; @@ -214,59 +204,16 @@ function generateOutputs(data: CEM.CustomElementDeclaration, className: string): data.events?.forEach((event) => { // Convert kebab-case to PascalCase after ui5 prefix const pascalCaseEventName = kebabToCamelCase(event.name).replace(/^./, (char) => char.toUpperCase()); - - if (event.type.references?.length) { - outputs.push(` - /** - * ${event.description || ''} - */ - ui5${pascalCaseEventName} = output<${event.type.text}>();`); - } else { - outputs.push(` + outputs.push(` /** * ${event.description || ''} */ ui5${pascalCaseEventName} = output>();`); - } }); return outputs.join('\n'); } -function generateExports(data: CEM.CustomElementDeclaration): string { - const className = data.name; - const exports: Set = new Set(); - const isExportedFromComponent = (ref: CEM.TypeReference): boolean | undefined => - ref.module?.split('.')[0].endsWith(className); - - const members = (data.members as CEM.ClassField[] | undefined) || []; - members?.forEach((member) => { - if (member.type?.references?.length) { - member.type.references.forEach((ref) => { - // export only those types that are exported from the current component - if (isExportedFromComponent(ref)) { - exports.add(ref.name); - } - }); - } - }); - - data.events?.forEach((event) => { - event.type.references?.forEach((ref) => { - // export only those types that are exported from the current component - if (isExportedFromComponent(ref)) { - exports.add(ref.name); - } - }); - }); - - return exports.size - ? `export type {\n${Array.from(exports) - .map((type) => `\t${type}`) - .join(',\n')}\n};` - : ''; -} - /** Generate the Angular component wrapper. */ export function componentTemplate( data: CEM.CustomElementDeclaration, @@ -463,7 +410,5 @@ ${(() => { })()} } } - -${generateExports(data)} `; } diff --git a/libs/webc-generator/src/executors/generate/executor.ts b/libs/webc-generator/src/executors/generate/executor.ts index d37f6487515..454103d9a45 100644 --- a/libs/webc-generator/src/executors/generate/executor.ts +++ b/libs/webc-generator/src/executors/generate/executor.ts @@ -18,6 +18,8 @@ const FILES = { THEMING_TEMPLATE: 'utils/theming-service-template.tpl' }; +const WEB_COMPONENTS_BASE = 'ui5-webcomponents-base'; + /** Converts PascalCase to kebab-case (e.g., 'Ui5Button' -> 'ui5-button'). */ const pascalToKebabCase = (str: string): string => str.replace(/\B([A-Z])/g, '-$1').toLowerCase(); @@ -228,6 +230,18 @@ async function generateUtilsFiles(targetDir: string): Promise { await writeFile(ngPackagePath, JSON.stringify({ lib: { entryFile: './index.ts' } }, null, 2), 'utf-8'); } +function addUI5WrapperCustomEventType(): string { + return ` +import { OutputEmitterRef } from '@angular/core'; + +type OutputKeys = { + [K in keyof T]: T[K] extends OutputEmitterRef ? K : never; +}[keyof T]; + +export type UI5WrapperCustomEvent> = T[N] extends OutputEmitterRef ? E : never; +`; +} + /** * An NX executor that generates Angular components from UI5 Web Components' * custom-elements-internal.json schema. @@ -282,6 +296,10 @@ const runExecutor: PromiseExecutor = async (options, con exportsContent += `\nexport * from './${SUBDIRS.THEMING}';\n`; } + if (context.projectName === WEB_COMPONENTS_BASE) { + exportsContent += addUI5WrapperCustomEventType(); + } + // Generate the root index.ts file const rootIndexPath = path.join(targetDir, FILES.INDEX_TS); await writeFile(rootIndexPath, exportsContent, 'utf-8'); From 1f2ad32210274175916dd954e2773ea592d8fc2b Mon Sep 17 00:00:00 2001 From: stoychevamaria89 Date: Thu, 20 Nov 2025 16:19:11 +0200 Subject: [PATCH 4/6] fix: move the new event type to webcomponents-base/types --- libs/ui5-webcomponents-base/index.ts | 8 -------- .../src/executors/generate/executor.ts | 16 ++++++++++------ 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/libs/ui5-webcomponents-base/index.ts b/libs/ui5-webcomponents-base/index.ts index 64d3dafb01c..fcb073fefcd 100644 --- a/libs/ui5-webcomponents-base/index.ts +++ b/libs/ui5-webcomponents-base/index.ts @@ -1,9 +1 @@ export * from './types'; - -import { OutputEmitterRef } from '@angular/core'; - -type OutputKeys = { - [K in keyof T]: T[K] extends OutputEmitterRef ? K : never; -}[keyof T]; - -export type UI5WrapperCustomEvent> = T[N] extends OutputEmitterRef ? E : never; diff --git a/libs/webc-generator/src/executors/generate/executor.ts b/libs/webc-generator/src/executors/generate/executor.ts index 454103d9a45..745e10de440 100644 --- a/libs/webc-generator/src/executors/generate/executor.ts +++ b/libs/webc-generator/src/executors/generate/executor.ts @@ -127,7 +127,11 @@ function extractCemData(cemData: CEM.Package, options: GenerateExecutorSchema): /** * Generates the types/index.ts file and its ng-package.json. */ -async function generateTypesFiles(allEnums: ExtractedCemData['allEnums'], targetDir: string): Promise { +async function generateTypesFiles( + allEnums: ExtractedCemData['allEnums'], + targetDir: string, + projectName: string +): Promise { let typesContent = allEnums .map( (e) => @@ -136,6 +140,10 @@ async function generateTypesFiles(allEnums: ExtractedCemData['allEnums'], target ) .join('\n'); + if (projectName === WEB_COMPONENTS_BASE) { + typesContent += addUI5WrapperCustomEventType(); + } + // Add one empty line at the end if there's content if (typesContent) { typesContent += '\n'; @@ -270,7 +278,7 @@ const runExecutor: PromiseExecutor = async (options, con let exportsContent = ''; if (allEnums.length > 0) { - exportsContent += await generateTypesFiles(allEnums, targetDir); + exportsContent += await generateTypesFiles(allEnums, targetDir, context.projectName); } if (options.skipComponents !== true) { @@ -296,10 +304,6 @@ const runExecutor: PromiseExecutor = async (options, con exportsContent += `\nexport * from './${SUBDIRS.THEMING}';\n`; } - if (context.projectName === WEB_COMPONENTS_BASE) { - exportsContent += addUI5WrapperCustomEventType(); - } - // Generate the root index.ts file const rootIndexPath = path.join(targetDir, FILES.INDEX_TS); await writeFile(rootIndexPath, exportsContent, 'utf-8'); From 2b7b8aa57a921901d791051fb3220225f6cd7d9a Mon Sep 17 00:00:00 2001 From: stoychevamaria89 Date: Thu, 20 Nov 2025 23:58:44 +0200 Subject: [PATCH 5/6] fix: disable nx cache when generating the wrappers --- netlify.toml | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/netlify.toml b/netlify.toml index cb2e8f4cd16..6e26b638cc1 100644 --- a/netlify.toml +++ b/netlify.toml @@ -8,7 +8,7 @@ [build] ignore = 'sh ./ignore.sh' publish = "dist/apps/docs" - command = "NODE_OPTIONS=--max_old_space_size=8192 npx nx run-many --target=generate --projects=ui5-webcomponents-base,ui5-webcomponents,ui5-webcomponents-ai,ui5-webcomponents-fiori && npx nx run docs:compile:production-unoptimized --base-href=\"/\"" + command = "NODE_OPTIONS=--max_old_space_size=8192 npx nx run-many --target=generate --projects=ui5-webcomponents-base,ui5-webcomponents,ui5-webcomponents-ai,ui5-webcomponents-fiori --skip-nx-cache && npx nx run docs:compile:production-unoptimized --base-href=\"/\"" [build.environment] NODE_VERSION = "22.12.0" diff --git a/package.json b/package.json index c8b2c5bca03..09b5c506c16 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "build:prepare": "echo Building libraries and preparing for publishing && nx run-many --target=prepare --all --pack --configuration=production --skip-nx-cache", "test": "echo Running unit tests && nx run-many --target=test --all --parallel=10", "cleanup": "find libs/ui5-webcomponents -mindepth 1 -type d -exec rm -r {} + && rm libs/ui5-webcomponents/index.ts && find libs/ui5-webcomponents-ai -mindepth 1 -type d -exec rm -r {} + && rm libs/ui5-webcomponents-ai/index.ts && find libs/ui5-webcomponents-fiori -mindepth 1 -type d -exec rm -r {} + && rm libs/ui5-webcomponents-fiori/index.ts && rm -rf libs/ui5-webcomponents-base/types && rm -rf dist", - "generate:ui5": "echo Generating UI5 Webcomponents Wrappers && nx run-many --target=generate --projects=ui5-webcomponents,ui5-webcomponents-ai,ui5-webcomponents-fiori,ui5-webcomponents-base", + "generate:ui5": "echo Generating UI5 Webcomponents Wrappers && nx run-many --target=generate --projects=ui5-webcomponents,ui5-webcomponents-ai,ui5-webcomponents-fiori,ui5-webcomponents-base --skip-nx-cache", "app:e2e:affected": "echo Running affected e2e tests on local && nx run docs:e2e-app:affected-local", "app:e2e:all": "echo Running all e2e tests on local && nx run docs:e2e-app:all-local", "ng": "ng", From 2112f54521fa3db3307687500d2ef7ab1a18854a Mon Sep 17 00:00:00 2001 From: stoychevamaria89 Date: Fri, 21 Nov 2025 10:02:56 +0200 Subject: [PATCH 6/6] fix: replace CustomEvent with UI5WrapperCustomEvent --- libs/docs/ui5-webcomponents/form/examples/validation.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/docs/ui5-webcomponents/form/examples/validation.ts b/libs/docs/ui5-webcomponents/form/examples/validation.ts index 912607d1d4c..cedae628bf4 100644 --- a/libs/docs/ui5-webcomponents/form/examples/validation.ts +++ b/libs/docs/ui5-webcomponents/form/examples/validation.ts @@ -181,7 +181,7 @@ export class FormValidationSample { return 'Invalid input'; } - onInputChange(fieldName: string, event: CustomEvent): void { + onInputChange(fieldName: string, event: UI5WrapperCustomEvent): void { const value = (event.target as any)?.value; this.registrationForm.get(fieldName)?.setValue(value); this.registrationForm.get(fieldName)?.markAsDirty();