Skip to content

Commit c2e59cd

Browse files
refactor: reuse UI5 Event Details instead of generating them (#4652)
1 parent cce51b5 commit c2e59cd

File tree

39 files changed

+214
-186
lines changed

39 files changed

+214
-186
lines changed

packages/main/scripts/create-web-components-wrapper.mjs

Lines changed: 54 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
import fioriWebComponentsSpec from '@ui5/webcomponents-fiori/dist/api.json' assert { type: 'json' };
33
import mainWebComponentsSpec from '@ui5/webcomponents/dist/api.json' assert { type: 'json' };
44
import dedent from 'dedent';
5-
import fs from 'node:fs';
5+
import { spawnSync } from 'node:child_process';
6+
import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
67
import path from 'node:path';
78
import prettier from 'prettier';
89
import PATHS from '../../../config/paths.js';
@@ -199,7 +200,7 @@ const allWebComponents = [
199200
return true;
200201
});
201202

202-
fs.writeFileSync(
203+
writeFileSync(
203204
path.join(PATHS.root, 'scripts', 'web-component-wrappers', 'interfaces.json'),
204205
JSON.stringify(Array.from(interfaces))
205206
);
@@ -234,34 +235,45 @@ const replaceTagNameWithModuleName = (description) => {
234235
return parsedDescription;
235236
};
236237

237-
const getEventParameters = (name, parameters) => {
238-
const resolvedEventParameters = parameters.map((property) => {
239-
return {
240-
...property,
241-
...Utils.getTypeDefinitionForProperty(property, { event: true })
242-
};
243-
});
238+
const getEventParameters = (moduleName, eventSpec) => {
239+
const eventTarget = `${moduleName}DomRef`;
240+
if (eventSpec.native === 'true') {
241+
if (eventSpec.name === 'click') {
242+
return {
243+
tsType: `MouseEventHandler<${eventTarget}>`,
244+
importStatements: ["import { MouseEventHandler } from 'react';"]
245+
};
246+
} else if (eventSpec.name === 'drop') {
247+
return {
248+
tsType: `DragEventHandler<${eventTarget}>`,
249+
importStatements: ["import { DragEventHandler } from 'react';"]
250+
};
251+
} else {
252+
console.warn(
253+
`----------------------\n${moduleName}: ${eventSpec.name} event didn't receive its type, please add it to the script! \n----------------------`
254+
);
255+
}
256+
}
244257

245-
const importStatements = [`import type { Ui5CustomEvent } from '../../interfaces/index.js';`];
258+
const importSpecifier = `@ui5/webcomponents${
259+
componentsFromFioriPackage.has(moduleName) ? '-fiori' : ''
260+
}/dist/${moduleName}.js`;
246261

247-
const eventTarget = `${name}DomRef`;
262+
const eventName = `${moduleName}${Utils.capitalizeFirstLetter(Utils.snakeToCamel(eventSpec.name))}EventDetail`;
248263

249-
if (resolvedEventParameters.length === 0) {
264+
const importStatements = [`import type { Ui5CustomEvent } from '../../interfaces/index.js';`];
265+
266+
if ((eventSpec.parameters ?? []).length === 0) {
250267
return {
251268
tsType: `(event: Ui5CustomEvent<${eventTarget}>) => void`,
252269
importStatements
253270
};
254271
}
255272

256-
const detailPayload = resolvedEventParameters.map((parameter) => {
257-
if (parameter.importStatement) {
258-
importStatements.push(parameter.importStatement);
259-
}
260-
return `${parameter.name}: ${parameter.tsType}`;
261-
});
273+
importStatements.unshift(`import type { ${eventName} } from '${importSpecifier}';`);
262274

263275
return {
264-
tsType: `(event: Ui5CustomEvent<${eventTarget}, {${detailPayload.join('; ')}}>) => void`,
276+
tsType: `(event: Ui5CustomEvent<${eventTarget}, ${eventName}>) => void`,
265277
importStatements
266278
};
267279
};
@@ -442,7 +454,7 @@ const resolveInheritedAttributes = (componentSpec) => {
442454
443455
`;
444456

445-
fs.writeFileSync(path.join(ENUMS_DIR, `${spec.basename}.ts`), prettier.format(template, Utils.prettierConfig));
457+
writeFileSync(path.join(ENUMS_DIR, `${spec.basename}.ts`), prettier.format(template, Utils.prettierConfig));
446458
});
447459

448460
const propDescription = (componentSpec, property) => {
@@ -549,27 +561,7 @@ allWebComponents
549561
(componentSpec.events || [])
550562
.filter((eventSpec) => eventSpec.visibility === 'public')
551563
.forEach((eventSpec) => {
552-
let eventParameters;
553-
if (eventSpec.native === 'true') {
554-
const eventTarget = `${componentSpec.module}DomRef`;
555-
if (eventSpec.name === 'click') {
556-
eventParameters = {
557-
tsType: `MouseEventHandler<${eventTarget}>`,
558-
importStatements: ["import { MouseEventHandler } from 'react';"]
559-
};
560-
} else if (eventSpec.name === 'drop') {
561-
eventParameters = {
562-
tsType: `DragEventHandler<${eventTarget}>`,
563-
importStatements: ["import { DragEventHandler } from 'react';"]
564-
};
565-
} else {
566-
console.warn(
567-
`----------------------\n${componentSpec.module}: ${eventSpec.name} event didn't receive its type, please add it to the script! \n----------------------`
568-
);
569-
}
570-
} else {
571-
eventParameters = getEventParameters(componentSpec.module, eventSpec.parameters || []);
572-
}
564+
const eventParameters = getEventParameters(componentSpec.module, eventSpec);
573565
importStatements.push(...eventParameters.importStatements);
574566
let onChangeDescription;
575567
if (INPUT_COMPONENTS.has(componentSpec.module) && eventSpec.name === 'change') {
@@ -616,14 +608,14 @@ allWebComponents
616608

617609
// check if folder exists and create it if necessary
618610
const webComponentFolderPath = path.join(WEB_COMPONENTS_ROOT_DIR, componentSpec.module);
619-
if (!fs.existsSync(webComponentFolderPath)) {
620-
fs.mkdirSync(webComponentFolderPath);
611+
if (!existsSync(webComponentFolderPath)) {
612+
mkdirSync(webComponentFolderPath);
621613
}
622614

623615
// create empty index file for eslint
624616
const webComponentWrapperPath = path.join(webComponentFolderPath, 'index.tsx');
625-
if (!fs.existsSync(webComponentWrapperPath)) {
626-
fs.writeFileSync(webComponentWrapperPath, '');
617+
if (!existsSync(webComponentWrapperPath)) {
618+
writeFileSync(webComponentWrapperPath, '');
627619
}
628620

629621
// fill index
@@ -650,12 +642,12 @@ allWebComponents
650642
(componentSpec.slots || []).filter(filterNonPublicAttributes).map(({ name }) => name),
651643
(componentSpec.events || []).filter(filterNonPublicAttributes).map(({ name }) => name)
652644
);
653-
fs.writeFileSync(webComponentWrapperPath, webComponentWrapper);
645+
writeFileSync(webComponentWrapperPath, webComponentWrapper);
654646

655647
// create test
656-
if (!fs.existsSync(path.join(webComponentFolderPath, `${componentSpec.module}.cy.tsx`))) {
648+
if (!existsSync(path.join(webComponentFolderPath, `${componentSpec.module}.cy.tsx`))) {
657649
const webComponentTest = renderTest({ name: componentSpec.module, tagname: componentSpec.tagname });
658-
fs.writeFileSync(path.join(webComponentFolderPath, `${componentSpec.module}.cy.tsx`), webComponentTest);
650+
writeFileSync(path.join(webComponentFolderPath, `${componentSpec.module}.cy.tsx`), webComponentTest);
659651
}
660652

661653
// create demo
@@ -670,7 +662,7 @@ allWebComponents
670662
componentSpec,
671663
false
672664
)}\n${formatDemoDescription(description, componentSpec, false)}`;
673-
fs.writeFileSync(
665+
writeFileSync(
674666
path.join(webComponentFolderPath, `${componentSpec.module}Description.md`),
675667
subComponentDescription
676668
);
@@ -679,7 +671,7 @@ allWebComponents
679671
const formattedDescription = formatDemoDescription(description, componentSpec);
680672
// create component description
681673
if (formattedDescription) {
682-
fs.writeFileSync(
674+
writeFileSync(
683675
path.join(webComponentFolderPath, `${componentSpec.module}Description.md`),
684676
formattedDescription
685677
);
@@ -692,22 +684,20 @@ allWebComponents
692684
];
693685

694686
if (publicProperties.length) {
695-
fs.writeFileSync(
687+
writeFileSync(
696688
path.join(webComponentFolderPath, `${componentSpec.module}DomRef.json`),
697689
prettier.format(JSON.stringify(publicProperties), {
698690
...Utils.prettierConfig,
699691
parser: 'json'
700692
})
701693
);
702694
let hasMethodsTable = false;
703-
if (fs.existsSync(path.join(webComponentFolderPath, `${componentSpec.module}.stories.mdx`))) {
704-
hasMethodsTable = fs
705-
.readFileSync(path.join(webComponentFolderPath, `${componentSpec.module}.stories.mdx`))
695+
if (existsSync(path.join(webComponentFolderPath, `${componentSpec.module}.stories.mdx`))) {
696+
hasMethodsTable = readFileSync(path.join(webComponentFolderPath, `${componentSpec.module}.stories.mdx`))
706697
.toString()
707698
.includes(`<DomRefTable rows={${componentSpec.module}DomRef.json} />`);
708-
} else if (fs.existsSync(path.join(webComponentFolderPath, `${componentSpec.module}.mdx`))) {
709-
hasMethodsTable = fs
710-
.readFileSync(path.join(webComponentFolderPath, `${componentSpec.module}.mdx`))
699+
} else if (existsSync(path.join(webComponentFolderPath, `${componentSpec.module}.mdx`))) {
700+
hasMethodsTable = readFileSync(path.join(webComponentFolderPath, `${componentSpec.module}.mdx`))
711701
.toString()
712702
.includes(`<DomRefTable rows={${componentSpec.module}DomRef.json} />`);
713703
}
@@ -721,8 +711,8 @@ allWebComponents
721711

722712
if (
723713
CREATE_SINGLE_COMPONENT === componentSpec.module ||
724-
(!fs.existsSync(path.join(webComponentFolderPath, `${componentSpec.module}.stories.mdx`)) &&
725-
!fs.existsSync(path.join(webComponentFolderPath, `${componentSpec.module}.stories.tsx`)))
714+
(!existsSync(path.join(webComponentFolderPath, `${componentSpec.module}.stories.mdx`)) &&
715+
!existsSync(path.join(webComponentFolderPath, `${componentSpec.module}.stories.tsx`)))
726716
) {
727717
await createStory(componentSpec, allComponentProperties);
728718
await createDocumentation(componentSpec, allComponentProperties, description);
@@ -732,11 +722,12 @@ allWebComponents
732722
});
733723

734724
// create index file for exporting all web components
735-
fs.writeFileSync(
725+
writeFileSync(
736726
path.join(WEB_COMPONENTS_ROOT_DIR, 'index.ts'),
737-
fs
738-
.readdirSync(WEB_COMPONENTS_ROOT_DIR)
739-
.filter((f) => fs.statSync(path.join(WEB_COMPONENTS_ROOT_DIR, f)).isDirectory())
727+
readdirSync(WEB_COMPONENTS_ROOT_DIR)
728+
.filter((f) => statSync(path.join(WEB_COMPONENTS_ROOT_DIR, f)).isDirectory())
740729
.map((folder) => `export * from './${folder}/index.js';`)
741730
.join('\n')
742731
);
732+
733+
spawnSync('prettier', [WEB_COMPONENTS_ROOT_DIR, '--write'], { stdio: [0, 1, 2] });

packages/main/src/webComponents/AvatarGroup/index.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
'use client';
22

33
import '@ui5/webcomponents/dist/AvatarGroup.js';
4+
import type { AvatarGroupClickEventDetail } from '@ui5/webcomponents/dist/AvatarGroup.js';
45
import type { ReactNode } from 'react';
5-
import type { AvatarColorScheme } from '../../enums/index.js';
66
import { AvatarGroupType } from '../../enums/index.js';
7+
import type { AvatarColorScheme } from '../../enums/index.js';
78
import type { Ui5CustomEvent, CommonProps, Ui5DomRef } from '../../interfaces/index.js';
89
import { withWebComponent } from '../../internal/withWebComponent.js';
910
import type { UI5WCSlotsNode } from '../../types/index.js';
@@ -53,9 +54,7 @@ export interface AvatarGroupPropTypes extends AvatarGroupAttributes, Omit<Common
5354
/**
5455
* Fired when the component is activated either with a click/tap or by using the Enter or Space key.
5556
*/
56-
onClick?: (
57-
event: Ui5CustomEvent<AvatarGroupDomRef, { targetRef: HTMLElement; overflowButtonClicked: boolean }>
58-
) => void;
57+
onClick?: (event: Ui5CustomEvent<AvatarGroupDomRef, AvatarGroupClickEventDetail>) => void;
5958
/**
6059
* Fired when the count of visible `Avatar` elements in the component has changed
6160
*/

packages/main/src/webComponents/BarcodeScannerDialog/index.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
'use client';
22

33
import '@ui5/webcomponents-fiori/dist/BarcodeScannerDialog.js';
4+
import type {
5+
BarcodeScannerDialogScanErrorEventDetail,
6+
BarcodeScannerDialogScanSuccessEventDetail
7+
} from '@ui5/webcomponents-fiori/dist/BarcodeScannerDialog.js';
48
import type { Ui5CustomEvent, CommonProps, Ui5DomRef } from '../../interfaces/index.js';
59
import { withWebComponent } from '../../internal/withWebComponent.js';
610

@@ -21,12 +25,12 @@ export interface BarcodeScannerDialogPropTypes extends BarcodeScannerDialogAttri
2125
/**
2226
* Fires when the scan fails with error.
2327
*/
24-
onScanError?: (event: Ui5CustomEvent<BarcodeScannerDialogDomRef, { message: string }>) => void;
28+
onScanError?: (event: Ui5CustomEvent<BarcodeScannerDialogDomRef, BarcodeScannerDialogScanErrorEventDetail>) => void;
2529
/**
2630
* Fires when the scan is completed successfuuly.
2731
*/
2832
onScanSuccess?: (
29-
event: Ui5CustomEvent<BarcodeScannerDialogDomRef, { text: string; rawBytes: Record<string, unknown> }>
33+
event: Ui5CustomEvent<BarcodeScannerDialogDomRef, BarcodeScannerDialogScanSuccessEventDetail>
3034
) => void;
3135
}
3236

packages/main/src/webComponents/Breadcrumbs/index.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use client';
22

33
import '@ui5/webcomponents/dist/Breadcrumbs.js';
4+
import type { BreadcrumbsItemClickEventDetail } from '@ui5/webcomponents/dist/Breadcrumbs.js';
45
import type { ReactNode } from 'react';
56
import { BreadcrumbsDesign, BreadcrumbsSeparatorStyle } from '../../enums/index.js';
67
import type { Ui5CustomEvent, CommonProps, Ui5DomRef } from '../../interfaces/index.js';
@@ -40,12 +41,7 @@ export interface BreadcrumbsPropTypes extends BreadcrumbsAttributes, CommonProps
4041
/**
4142
* Fires when a `BreadcrumbsItem` is clicked. **Note:** You can prevent browser location change by calling `event.preventDefault()`.
4243
*/
43-
onItemClick?: (
44-
event: Ui5CustomEvent<
45-
BreadcrumbsDomRef,
46-
{ item: HTMLElement; altKey: boolean; ctrlKey: boolean; metaKey: boolean; shiftKey: boolean }
47-
>
48-
) => void;
44+
onItemClick?: (event: Ui5CustomEvent<BreadcrumbsDomRef, BreadcrumbsItemClickEventDetail>) => void;
4945
}
5046

5147
/**

packages/main/src/webComponents/Calendar/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use client';
22

33
import '@ui5/webcomponents/dist/Calendar.js';
4+
import type { CalendarSelectedDatesChangeEventDetail } from '@ui5/webcomponents/dist/Calendar.js';
45
import type { ReactNode } from 'react';
56
import type { CalendarType } from '../../enums/index.js';
67
import { CalendarSelectionMode } from '../../enums/index.js';
@@ -54,7 +55,7 @@ export interface CalendarPropTypes extends CalendarAttributes, CommonProps {
5455
/**
5556
* Fired when the selected dates change. **Note:** If you call `preventDefault()` for this event, the component will not create instances of `CalendarDate` for the newly selected dates. In that case you should do this manually.
5657
*/
57-
onSelectedDatesChange?: (event: Ui5CustomEvent<CalendarDomRef, { values: unknown[]; dates: unknown[] }>) => void;
58+
onSelectedDatesChange?: (event: Ui5CustomEvent<CalendarDomRef, CalendarSelectedDatesChangeEventDetail>) => void;
5859
}
5960

6061
/**

packages/main/src/webComponents/Carousel/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use client';
22

33
import '@ui5/webcomponents/dist/Carousel.js';
4+
import type { CarouselNavigateEventDetail } from '@ui5/webcomponents/dist/Carousel.js';
45
import type { ReactNode } from 'react';
56
import {
67
CarouselArrowsPlacement,
@@ -88,7 +89,7 @@ export interface CarouselPropTypes extends CarouselAttributes, CommonProps {
8889
/**
8990
* Fired whenever the page changes due to user interaction, when the user clicks on the navigation arrows or while resizing, based on the `items-per-page-l`, `items-per-page-m` and `items-per-page-s` properties.
9091
*/
91-
onNavigate?: (event: Ui5CustomEvent<CarouselDomRef, { selectedIndex: number }>) => void;
92+
onNavigate?: (event: Ui5CustomEvent<CarouselDomRef, CarouselNavigateEventDetail>) => void;
9293
}
9394

9495
/**

packages/main/src/webComponents/ColorPalette/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use client';
22

33
import '@ui5/webcomponents/dist/ColorPalette.js';
4+
import type { ColorPaletteItemClickEventDetail } from '@ui5/webcomponents/dist/ColorPalette.js';
45
import type { ReactNode } from 'react';
56
import type { Ui5CustomEvent, CommonProps, Ui5DomRef } from '../../interfaces/index.js';
67
import { withWebComponent } from '../../internal/withWebComponent.js';
@@ -17,7 +18,7 @@ export interface ColorPalettePropTypes extends ColorPaletteAttributes, CommonPro
1718
/**
1819
* Fired when the user selects a color.
1920
*/
20-
onItemClick?: (event: Ui5CustomEvent<ColorPaletteDomRef, { color: string }>) => void;
21+
onItemClick?: (event: Ui5CustomEvent<ColorPaletteDomRef, ColorPaletteItemClickEventDetail>) => void;
2122
}
2223

2324
/**

packages/main/src/webComponents/ColorPalettePopover/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use client';
22

33
import '@ui5/webcomponents/dist/ColorPalettePopover.js';
4+
import type { ColorPalettePopoverItemClickEventDetail } from '@ui5/webcomponents/dist/ColorPalettePopover.js';
45
import type { CSSProperties, ReactNode } from 'react';
56
import type { Ui5CustomEvent, CommonProps, Ui5DomRef } from '../../interfaces/index.js';
67
import { withWebComponent } from '../../internal/withWebComponent.js';
@@ -46,7 +47,7 @@ export interface ColorPalettePopoverPropTypes extends ColorPalettePopoverAttribu
4647
/**
4748
* Fired when the user selects a color.
4849
*/
49-
onItemClick?: (event: Ui5CustomEvent<ColorPalettePopoverDomRef, { color: string }>) => void;
50+
onItemClick?: (event: Ui5CustomEvent<ColorPalettePopoverDomRef, ColorPalettePopoverItemClickEventDetail>) => void;
5051
}
5152

5253
/**

packages/main/src/webComponents/ComboBox/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use client';
22

33
import '@ui5/webcomponents/dist/ComboBox.js';
4+
import type { ComboBoxSelectionChangeEventDetail } from '@ui5/webcomponents/dist/ComboBox.js';
45
import type { ReactNode } from 'react';
56
import { ComboBoxFilter, ValueState } from '../../enums/index.js';
67
import type { Ui5CustomEvent, CommonProps, Ui5DomRef } from '../../interfaces/index.js';
@@ -107,7 +108,7 @@ export interface ComboBoxPropTypes extends ComboBoxAttributes, Omit<CommonProps,
107108
/**
108109
* Fired when selection is changed by user interaction
109110
*/
110-
onSelectionChange?: (event: Ui5CustomEvent<ComboBoxDomRef, { item: HTMLElement }>) => void;
111+
onSelectionChange?: (event: Ui5CustomEvent<ComboBoxDomRef, ComboBoxSelectionChangeEventDetail>) => void;
111112
}
112113

113114
/**

0 commit comments

Comments
 (0)