Skip to content

Commit 70f9f27

Browse files
feat(react 19): bind web components event handlers using react lifecycle (#6169)
1 parent cc0ee8b commit 70f9f27

File tree

1 file changed

+27
-4
lines changed

1 file changed

+27
-4
lines changed

packages/main/src/internal/withWebComponent.tsx

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@
33
import { getEffectiveScopingSuffixForTag } from '@ui5/webcomponents-base/dist/CustomElementsScope.js';
44
import { useIsomorphicLayoutEffect, useSyncRef } from '@ui5/webcomponents-react-base';
55
import type { ComponentType, ReactElement, ReactNode, Ref } from 'react';
6-
import { cloneElement, forwardRef, Fragment, isValidElement, useEffect, useState } from 'react';
6+
import { cloneElement, forwardRef, Fragment, isValidElement, useEffect, useState, version } from 'react';
77
import type { CommonProps, Ui5DomRef } from '../types/index.js';
88
import { useServerSideEffect } from './ssr.js';
99
import { camelToKebabCase, capitalizeFirstLetter, kebabToCamelCase } from './utils.js';
1010

11+
const SEMVER_REGEX =
12+
/^(?<major>0|[1-9]\d*)\.(?<minor>0|[1-9]\d*)\.(?<patch>0|[1-9]\d*)(?:-(?<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
13+
1114
const createEventPropName = (eventName: string) => `on${capitalizeFirstLetter(kebabToCamelCase(eventName))}`;
1215

1316
const isPrimitiveAttribute = (value: unknown): boolean => {
@@ -35,6 +38,8 @@ export const withWebComponent = <Props extends Record<string, any>, RefType = Ui
3538
eventProperties: string[],
3639
loader: () => Promise<unknown>
3740
) => {
41+
const reactMajorVersion = SEMVER_REGEX.exec(version)?.groups?.major;
42+
const webComponentsSupported = parseInt(reactMajorVersion) >= 19;
3843
// displayName will be assigned in the individual files
3944
// eslint-disable-next-line react/display-name
4045
return forwardRef<RefType, Props & WithWebComponentPropTypes>((props, wcRef) => {
@@ -61,10 +66,14 @@ export const withWebComponent = <Props extends Record<string, any>, RefType = Ui
6166

6267
// boolean properties - only attach if they are truthy
6368
const booleanProps = booleanProperties.reduce((acc, name) => {
64-
if (rest[name] === true || rest[name] === 'true') {
65-
return { ...acc, [camelToKebabCase(name)]: true };
69+
if (webComponentsSupported) {
70+
return { ...acc, [camelToKebabCase(name)]: rest[name] };
71+
} else {
72+
if (rest[name] === true || rest[name] === 'true') {
73+
return { ...acc, [camelToKebabCase(name)]: true };
74+
}
75+
return acc;
6676
}
67-
return acc;
6877
}, {});
6978

7079
const slots = slotProperties.reduce((acc, name) => {
@@ -119,6 +128,11 @@ export const withWebComponent = <Props extends Record<string, any>, RefType = Ui
119128

120129
// event binding
121130
useIsomorphicLayoutEffect(() => {
131+
if (webComponentsSupported) {
132+
return () => {
133+
// React can handle events
134+
};
135+
}
122136
const localRef = ref.current;
123137
const eventRegistry: Record<string, EventHandler> = {};
124138
if (!waitForDefine || isDefined) {
@@ -140,6 +154,14 @@ export const withWebComponent = <Props extends Record<string, any>, RefType = Ui
140154
}
141155
}, [...eventProperties.map((eventName) => rest[createEventPropName(eventName)]), isDefined, waitForDefine]);
142156

157+
const eventHandlers = eventProperties.reduce((events, eventName) => {
158+
const eventHandlerProp = rest[createEventPropName(eventName)];
159+
if (webComponentsSupported && eventHandlerProp) {
160+
events[`on${eventName}`] = eventHandlerProp;
161+
}
162+
return events;
163+
}, {});
164+
143165
// non web component related props, just pass them
144166
const nonWebComponentRelatedProps = Object.entries(rest)
145167
.filter(([key]) => !regularProperties.includes(key))
@@ -185,6 +207,7 @@ export const withWebComponent = <Props extends Record<string, any>, RefType = Ui
185207
ref={componentRef}
186208
{...booleanProps}
187209
{...regularProps}
210+
{...eventHandlers}
188211
{...nonWebComponentRelatedProps}
189212
class={className}
190213
suppressHydrationWarning

0 commit comments

Comments
 (0)