@ui5/webcomponents-base 2.20.0 → 2.20.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,26 @@
1
+ /**
2
+ * React wrapper factory for UI5 Web Components.
3
+ *
4
+ * This lightweight factory creates typed React components that wrap UI5 Web Components.
5
+ * It handles:
6
+ * - Event prop conversion (onXxx → ui5-xxx event listeners)
7
+ * - Ref forwarding
8
+ * - Children handling
9
+ *
10
+ * Note: Supports React >=19.
11
+ *
12
+ * Note: This is for documentation samples only - for production React apps,
13
+ * use the official @ui5/webcomponents-react library.
14
+ */
15
+ import type UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js";
16
+ /**
17
+ * Creates a React component wrapper for a UI5 Web Component.
18
+ *
19
+ * @param ComponentClass - The UI5 Web Component class (e.g., Button from "@ui5/webcomponents/dist/Button.js")
20
+ * @returns A React component that renders the custom element with proper TypeScript types
21
+ * @since 2.21.0
22
+ * @example
23
+ * import Button from "@ui5/webcomponents/dist/Button.js";
24
+ * const ReactButton = createReactComponent(Button);
25
+ */
26
+ export default function createReactComponent<T extends typeof UI5Element>(klass: T): (props: InstanceType<T>["_jsxProps"]) => import("react").DOMElement<Record<string, unknown>, Element>;
@@ -0,0 +1,51 @@
1
+ /**
2
+ * React wrapper factory for UI5 Web Components.
3
+ *
4
+ * This lightweight factory creates typed React components that wrap UI5 Web Components.
5
+ * It handles:
6
+ * - Event prop conversion (onXxx → ui5-xxx event listeners)
7
+ * - Ref forwarding
8
+ * - Children handling
9
+ *
10
+ * Note: Supports React >=19.
11
+ *
12
+ * Note: This is for documentation samples only - for production React apps,
13
+ * use the official @ui5/webcomponents-react library.
14
+ */
15
+ import { createElement } from "react";
16
+ /**
17
+ * Creates a React component wrapper for a UI5 Web Component.
18
+ *
19
+ * @param ComponentClass - The UI5 Web Component class (e.g., Button from "@ui5/webcomponents/dist/Button.js")
20
+ * @returns A React component that renders the custom element with proper TypeScript types
21
+ * @since 2.21.0
22
+ * @example
23
+ * import Button from "@ui5/webcomponents/dist/Button.js";
24
+ * const ReactButton = createReactComponent(Button);
25
+ */
26
+ export default function createReactComponent(klass) {
27
+ const tag = klass.getMetadata().getTag();
28
+ return function Component(props) {
29
+ const patchedProps = {};
30
+ Object.entries(props).forEach(([key, value]) => {
31
+ if (key.startsWith("on") && typeof value === "function") {
32
+ // React 19 wraps DOM events (change, click, input, etc.) in SyntheticEvent,
33
+ // hiding CustomEvent.detail under nativeEvent.detail.
34
+ // Patch all event handlers to restore detail from nativeEvent.
35
+ const originalHandler = value;
36
+ patchedProps[key] = (e) => {
37
+ const nativeDetail = e.nativeEvent?.detail;
38
+ if (nativeDetail !== undefined) {
39
+ e.detail = nativeDetail;
40
+ }
41
+ originalHandler(e);
42
+ };
43
+ }
44
+ else {
45
+ patchedProps[key] = value;
46
+ }
47
+ });
48
+ return createElement(tag, patchedProps);
49
+ };
50
+ }
51
+ //# sourceMappingURL=createReactComponent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createReactComponent.js","sourceRoot":"","sources":["../src/createReactComponent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAGtC;;;;;;;;;GASG;AACH,MAAM,CAAC,OAAO,UAAU,oBAAoB,CAA8B,KAAQ;IACjF,MAAM,GAAG,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC,MAAM,EAAE,CAAC;IAEzC,OAAO,SAAS,SAAS,CAAC,KAAmC;QAC5D,MAAM,YAAY,GAA4B,EAAE,CAAC;QAEjD,MAAM,CAAC,OAAO,CAAC,KAAgC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE;YACzE,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,OAAO,KAAK,KAAK,UAAU,EAAE,CAAC;gBACzD,4EAA4E;gBAC5E,sDAAsD;gBACtD,+DAA+D;gBAC/D,MAAM,eAAe,GAAG,KAAK,CAAC;gBAC9B,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAQ,EAAE,EAAE;oBAChC,MAAM,YAAY,GAAI,CAAsD,CAAC,WAAW,EAAE,MAAM,CAAC;oBACjG,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;wBAC/B,CAAoC,CAAC,MAAM,GAAG,YAAY,CAAC;oBAC7D,CAAC;oBACD,eAAe,CAAC,CAAC,CAAC,CAAC;gBACpB,CAAC,CAAC;YACH,CAAC;iBAAM,CAAC;gBACP,YAAY,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;YAC3B,CAAC;QACF,CAAC,CAAC,CAAC;QAEH,OAAO,aAAa,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IACzC,CAAC,CAAC;AACH,CAAC","sourcesContent":["/**\n * React wrapper factory for UI5 Web Components.\n *\n * This lightweight factory creates typed React components that wrap UI5 Web Components.\n * It handles:\n * - Event prop conversion (onXxx → ui5-xxx event listeners)\n * - Ref forwarding\n * - Children handling\n *\n * Note: Supports React >=19.\n *\n * Note: This is for documentation samples only - for production React apps,\n * use the official @ui5/webcomponents-react library.\n */\n\nimport { createElement } from \"react\";\nimport type UI5Element from \"@ui5/webcomponents-base/dist/UI5Element.js\";\n\n/**\n * Creates a React component wrapper for a UI5 Web Component.\n *\n * @param ComponentClass - The UI5 Web Component class (e.g., Button from \"@ui5/webcomponents/dist/Button.js\")\n * @returns A React component that renders the custom element with proper TypeScript types\n * @since 2.21.0\n * @example\n * import Button from \"@ui5/webcomponents/dist/Button.js\";\n * const ReactButton = createReactComponent(Button);\n */\nexport default function createReactComponent<T extends typeof UI5Element>(klass: T) {\n\tconst tag = klass.getMetadata().getTag();\n\n\treturn function Component(props: InstanceType<T>[\"_jsxProps\"]) {\n\t\tconst patchedProps: Record<string, unknown> = {};\n\n\t\tObject.entries(props as Record<string, unknown>).forEach(([key, value]) => {\n\t\t\tif (key.startsWith(\"on\") && typeof value === \"function\") {\n\t\t\t\t// React 19 wraps DOM events (change, click, input, etc.) in SyntheticEvent,\n\t\t\t\t// hiding CustomEvent.detail under nativeEvent.detail.\n\t\t\t\t// Patch all event handlers to restore detail from nativeEvent.\n\t\t\t\tconst originalHandler = value;\n\t\t\t\tpatchedProps[key] = (e: Event) => {\n\t\t\t\t\tconst nativeDetail = (e as unknown as { nativeEvent?: { detail: unknown } }).nativeEvent?.detail;\n\t\t\t\t\tif (nativeDetail !== undefined) {\n\t\t\t\t\t\t(e as unknown as { detail: unknown }).detail = nativeDetail;\n\t\t\t\t\t}\n\t\t\t\t\toriginalHandler(e);\n\t\t\t\t};\n\t\t\t} else {\n\t\t\t\tpatchedProps[key] = value;\n\t\t\t}\n\t\t});\n\n\t\treturn createElement(tag, patchedProps);\n\t};\n}\n"]}
@@ -842,6 +842,21 @@
842
842
  }
843
843
  ]
844
844
  },
845
+ {
846
+ "kind": "javascript-module",
847
+ "path": "dist/createReactComponent.js",
848
+ "declarations": [],
849
+ "exports": [
850
+ {
851
+ "kind": "js",
852
+ "name": "default",
853
+ "declaration": {
854
+ "name": "createReactComponent",
855
+ "module": "dist/createReactComponent.js"
856
+ }
857
+ }
858
+ ]
859
+ },
845
860
  {
846
861
  "kind": "javascript-module",
847
862
  "path": "dist/decorators.js",
@@ -827,6 +827,21 @@
827
827
  }
828
828
  ]
829
829
  },
830
+ {
831
+ "kind": "javascript-module",
832
+ "path": "dist/createReactComponent.js",
833
+ "declarations": [],
834
+ "exports": [
835
+ {
836
+ "kind": "js",
837
+ "name": "default",
838
+ "declaration": {
839
+ "name": "createReactComponent",
840
+ "module": "dist/createReactComponent.js"
841
+ }
842
+ }
843
+ ]
844
+ },
830
845
  {
831
846
  "kind": "javascript-module",
832
847
  "path": "dist/decorators.js",
@@ -1,11 +1,11 @@
1
1
  const VersionInfo = {
2
- version: "2.20.0",
2
+ version: "2.20.1",
3
3
  major: 2,
4
4
  minor: 20,
5
- patch: 0,
5
+ patch: 1,
6
6
  suffix: "",
7
7
  isNext: false,
8
- buildTime: 1772704608,
8
+ buildTime: 1773431170,
9
9
  };
10
10
  export default VersionInfo;
11
11
  //# sourceMappingURL=VersionInfo.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"VersionInfo.js","sourceRoot":"","sources":["../../src/generated/VersionInfo.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,GAAG;IACnB,OAAO,EAAE,QAAQ;IACjB,KAAK,EAAE,CAAC;IACR,KAAK,EAAE,EAAE;IACT,KAAK,EAAE,CAAC;IACR,MAAM,EAAE,EAAE;IACV,MAAM,EAAE,KAAK;IACb,SAAS,EAAE,UAAU;CACrB,CAAC;AACF,eAAe,WAAW,CAAC","sourcesContent":["const VersionInfo = {\n\tversion: \"2.20.0\",\n\tmajor: 2,\n\tminor: 20,\n\tpatch: 0,\n\tsuffix: \"\",\n\tisNext: false,\n\tbuildTime: 1772704608,\n};\nexport default VersionInfo;"]}
1
+ {"version":3,"file":"VersionInfo.js","sourceRoot":"","sources":["../../src/generated/VersionInfo.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,GAAG;IACnB,OAAO,EAAE,QAAQ;IACjB,KAAK,EAAE,CAAC;IACR,KAAK,EAAE,EAAE;IACT,KAAK,EAAE,CAAC;IACR,MAAM,EAAE,EAAE;IACV,MAAM,EAAE,KAAK;IACb,SAAS,EAAE,UAAU;CACrB,CAAC;AACF,eAAe,WAAW,CAAC","sourcesContent":["const VersionInfo = {\n\tversion: \"2.20.1\",\n\tmajor: 2,\n\tminor: 20,\n\tpatch: 1,\n\tsuffix: \"\",\n\tisNext: false,\n\tbuildTime: 1773431170,\n};\nexport default VersionInfo;"]}
@@ -0,0 +1,2 @@
1
+ "use strict";import{createElement as d}from"react";export default function p(i){const s=i.getMetadata().getTag();return function(r){const n={};return Object.entries(r).forEach(([t,e])=>{if(t.startsWith("on")&&typeof e=="function"){const c=e;n[t]=o=>{const a=o.nativeEvent?.detail;a!==void 0&&(o.detail=a),c(o)}}else n[t]=e}),d(s,n)}}
2
+ //# sourceMappingURL=createReactComponent.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/createReactComponent.ts"],
4
+ "sourcesContent": ["/**\n * React wrapper factory for UI5 Web Components.\n *\n * This lightweight factory creates typed React components that wrap UI5 Web Components.\n * It handles:\n * - Event prop conversion (onXxx \u2192 ui5-xxx event listeners)\n * - Ref forwarding\n * - Children handling\n *\n * Note: Supports React >=19.\n *\n * Note: This is for documentation samples only - for production React apps,\n * use the official @ui5/webcomponents-react library.\n */\n\nimport { createElement } from \"react\";\nimport type UI5Element from \"@ui5/webcomponents-base/dist/UI5Element.js\";\n\n/**\n * Creates a React component wrapper for a UI5 Web Component.\n *\n * @param ComponentClass - The UI5 Web Component class (e.g., Button from \"@ui5/webcomponents/dist/Button.js\")\n * @returns A React component that renders the custom element with proper TypeScript types\n * @since 2.21.0\n * @example\n * import Button from \"@ui5/webcomponents/dist/Button.js\";\n * const ReactButton = createReactComponent(Button);\n */\nexport default function createReactComponent<T extends typeof UI5Element>(klass: T) {\n\tconst tag = klass.getMetadata().getTag();\n\n\treturn function Component(props: InstanceType<T>[\"_jsxProps\"]) {\n\t\tconst patchedProps: Record<string, unknown> = {};\n\n\t\tObject.entries(props as Record<string, unknown>).forEach(([key, value]) => {\n\t\t\tif (key.startsWith(\"on\") && typeof value === \"function\") {\n\t\t\t\t// React 19 wraps DOM events (change, click, input, etc.) in SyntheticEvent,\n\t\t\t\t// hiding CustomEvent.detail under nativeEvent.detail.\n\t\t\t\t// Patch all event handlers to restore detail from nativeEvent.\n\t\t\t\tconst originalHandler = value;\n\t\t\t\tpatchedProps[key] = (e: Event) => {\n\t\t\t\t\tconst nativeDetail = (e as unknown as { nativeEvent?: { detail: unknown } }).nativeEvent?.detail;\n\t\t\t\t\tif (nativeDetail !== undefined) {\n\t\t\t\t\t\t(e as unknown as { detail: unknown }).detail = nativeDetail;\n\t\t\t\t\t}\n\t\t\t\t\toriginalHandler(e);\n\t\t\t\t};\n\t\t\t} else {\n\t\t\t\tpatchedProps[key] = value;\n\t\t\t}\n\t\t});\n\n\t\treturn createElement(tag, patchedProps);\n\t};\n}\n"],
5
+ "mappings": "aAeA,OAAS,iBAAAA,MAAqB,QAa9B,wBAAwBC,EAAkDC,EAAU,CACnF,MAAMC,EAAMD,EAAM,YAAY,EAAE,OAAO,EAEvC,OAAO,SAAmBE,EAAqC,CAC9D,MAAMC,EAAwC,CAAC,EAE/C,cAAO,QAAQD,CAAgC,EAAE,QAAQ,CAAC,CAACE,EAAKC,CAAK,IAAM,CAC1E,GAAID,EAAI,WAAW,IAAI,GAAK,OAAOC,GAAU,WAAY,CAIxD,MAAMC,EAAkBD,EACxBF,EAAaC,CAAG,EAAKG,GAAa,CACjC,MAAMC,EAAgBD,EAAuD,aAAa,OACtFC,IAAiB,SACnBD,EAAqC,OAASC,GAEhDF,EAAgBC,CAAC,CAClB,CACD,MACCJ,EAAaC,CAAG,EAAIC,CAEtB,CAAC,EAEMP,EAAcG,EAAKE,CAAY,CACvC,CACD",
6
+ "names": ["createElement", "createReactComponent", "klass", "tag", "props", "patchedProps", "key", "value", "originalHandler", "e", "nativeDetail"]
7
+ }
@@ -1,2 +1,2 @@
1
- "use strict";const e={version:"2.20.0",major:2,minor:20,patch:0,suffix:"",isNext:!1,buildTime:1772704608};export default e;
1
+ "use strict";const e={version:"2.20.1",major:2,minor:20,patch:1,suffix:"",isNext:!1,buildTime:1773431170};export default e;
2
2
  //# sourceMappingURL=VersionInfo.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/generated/VersionInfo.ts"],
4
- "sourcesContent": ["const VersionInfo = {\n\tversion: \"2.20.0\",\n\tmajor: 2,\n\tminor: 20,\n\tpatch: 0,\n\tsuffix: \"\",\n\tisNext: false,\n\tbuildTime: 1772704608,\n};\nexport default VersionInfo;"],
4
+ "sourcesContent": ["const VersionInfo = {\n\tversion: \"2.20.1\",\n\tmajor: 2,\n\tminor: 20,\n\tpatch: 1,\n\tsuffix: \"\",\n\tisNext: false,\n\tbuildTime: 1773431170,\n};\nexport default VersionInfo;"],
5
5
  "mappings": "aAAA,MAAMA,EAAc,CACnB,QAAS,SACT,MAAO,EACP,MAAO,GACP,MAAO,EACP,OAAQ,GACR,OAAQ,GACR,UAAW,UACZ,EACA,eAAeA",
6
6
  "names": ["VersionInfo"]
7
7
  }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * React wrapper factory for UI5 Web Components.
3
+ *
4
+ * This lightweight factory creates typed React components that wrap UI5 Web Components.
5
+ * It handles:
6
+ * - Event prop conversion (onXxx → ui5-xxx event listeners)
7
+ * - Ref forwarding
8
+ * - Children handling
9
+ *
10
+ * Note: The function supports react >= 18.
11
+ * Note: This is for documentation samples only - for production React apps,
12
+ * use the official @ui5/webcomponents-react library.
13
+ */
14
+ import * as React from "react";
15
+ import type { ReactNode } from "react";
16
+ import type UI5Element from "../UI5Element.js";
17
+ interface UI5ComponentClass<T extends UI5Element = UI5Element> {
18
+ new (): T;
19
+ getMetadata(): {
20
+ getTag(): string;
21
+ };
22
+ }
23
+ /**
24
+ * Creates a React component wrapper for a UI5 Web Component.
25
+ * Uses the component's _jsxProps type for full TypeScript support.
26
+ *
27
+ * @param ComponentClass - The UI5 Web Component class (e.g., Button from "@ui5/webcomponents/dist/Button.js")
28
+ * @returns A React component that renders the custom element with proper TypeScript types
29
+ * @since 2.21.0
30
+ * @example
31
+ * import Button from "@ui5/webcomponents/dist/Button.js";
32
+ * const ReactButton = createReactComponent(Button);
33
+ * // ReactButton props are typed based on Button's _jsxProps
34
+ */
35
+ declare function createReactComponent<T extends UI5Element>(ComponentClass: UI5ComponentClass<T>): React.ForwardRefExoticComponent<React.PropsWithoutRef<T["_jsxProps"] & {
36
+ children?: ReactNode;
37
+ }> & React.RefAttributes<T>>;
38
+ export default createReactComponent;
@@ -0,0 +1,112 @@
1
+ /**
2
+ * React wrapper factory for UI5 Web Components.
3
+ *
4
+ * This lightweight factory creates typed React components that wrap UI5 Web Components.
5
+ * It handles:
6
+ * - Event prop conversion (onXxx → ui5-xxx event listeners)
7
+ * - Ref forwarding
8
+ * - Children handling
9
+ *
10
+ * Note: The function supports react >= 18.
11
+ * Note: This is for documentation samples only - for production React apps,
12
+ * use the official @ui5/webcomponents-react library.
13
+ */
14
+ import * as React from "react";
15
+ import { useRef, useEffect, forwardRef, } from "react";
16
+ // Helper to convert event name
17
+ const toEventName = (propName) => {
18
+ return propName
19
+ .slice(2) // Remove "on"
20
+ .replace(/([A-Z])/g, (match, letter, index) => {
21
+ return index === 0 ? letter.toLowerCase() : `-${letter.toLowerCase()}`;
22
+ });
23
+ };
24
+ // Helper to create cleanup function for event listener
25
+ const createEventCleanup = (element, eventName, handler) => {
26
+ element.addEventListener(eventName, handler);
27
+ return () => element.removeEventListener(eventName, handler);
28
+ };
29
+ /**
30
+ * Creates a React component wrapper for a UI5 Web Component.
31
+ * Uses the component's _jsxProps type for full TypeScript support.
32
+ *
33
+ * @param ComponentClass - The UI5 Web Component class (e.g., Button from "@ui5/webcomponents/dist/Button.js")
34
+ * @returns A React component that renders the custom element with proper TypeScript types
35
+ * @since 2.21.0
36
+ * @example
37
+ * import Button from "@ui5/webcomponents/dist/Button.js";
38
+ * const ReactButton = createReactComponent(Button);
39
+ * // ReactButton props are typed based on Button's _jsxProps
40
+ */
41
+ function createReactComponent(ComponentClass) {
42
+ const tagName = ComponentClass.getMetadata().getTag();
43
+ const Component = forwardRef((props, ref) => {
44
+ const { children, ...restProps } = props;
45
+ const elementRef = useRef(null);
46
+ // Forward ref
47
+ useEffect(() => {
48
+ if (ref) {
49
+ if (typeof ref === "function") {
50
+ ref(elementRef.current);
51
+ }
52
+ else {
53
+ ref.current = elementRef.current;
54
+ }
55
+ }
56
+ }, [ref]);
57
+ // Handle event props and boolean props imperatively
58
+ useEffect(() => {
59
+ const element = elementRef.current;
60
+ if (!element) {
61
+ return;
62
+ }
63
+ const eventCleanups = [];
64
+ Object.keys(restProps).forEach(propName => {
65
+ const propValue = restProps[propName];
66
+ if (propName.startsWith("on") && typeof propValue === "function") {
67
+ // Convert React event naming (onClick, onSelectionChange) to DOM event naming
68
+ // onClick -> click, onSelectionChange -> selection-change
69
+ const eventName = toEventName(propName);
70
+ const handler = propValue;
71
+ eventCleanups.push(createEventCleanup(element, eventName, handler));
72
+ }
73
+ else if (typeof propValue === "boolean") {
74
+ // React 18 sets false booleans as empty string attributes on custom elements.
75
+ // Set as property directly to avoid this.
76
+ element[propName] = propValue;
77
+ }
78
+ });
79
+ return () => {
80
+ eventCleanups.forEach(cleanup => cleanup());
81
+ };
82
+ }, [restProps]);
83
+ // Filter out event handlers and booleans from DOM props
84
+ const domProps = {};
85
+ Object.keys(restProps).forEach(propName => {
86
+ const propValue = restProps[propName];
87
+ if (propName.startsWith("on") && typeof propValue === "function") {
88
+ return;
89
+ }
90
+ if (typeof propValue === "boolean") {
91
+ return;
92
+ } // handled in useEffect
93
+ // className → class for React compatibility
94
+ if (propName === "className") {
95
+ // eslint-disable-next-line dot-notation
96
+ domProps["class"] = propValue;
97
+ return;
98
+ }
99
+ // Convert camelCase to kebab-case for HTML attributes
100
+ const attrName = propName.replace(/([A-Z])/g, "-$1").toLowerCase();
101
+ domProps[attrName] = propValue;
102
+ });
103
+ return React.createElement(tagName, { ref: elementRef, ...domProps }, children);
104
+ });
105
+ Component.displayName = tagName
106
+ .split("-")
107
+ .map(part => part.charAt(0).toUpperCase() + part.slice(1))
108
+ .join("");
109
+ return Component;
110
+ }
111
+ export default createReactComponent;
112
+ //# sourceMappingURL=createReactComponent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createReactComponent.js","sourceRoot":"","sources":["../../src/react18/createReactComponent.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n * React wrapper factory for UI5 Web Components.\n *\n * This lightweight factory creates typed React components that wrap UI5 Web Components.\n * It handles:\n * - Event prop conversion (onXxx → ui5-xxx event listeners)\n * - Ref forwarding\n * - Children handling\n *\n * Note: The function supports react >= 18.\n * Note: This is for documentation samples only - for production React apps,\n * use the official @ui5/webcomponents-react library.\n */\n\nimport * as React from \"react\";\nimport type { ReactNode } from \"react\";\nimport {\n\tuseRef,\n\tuseEffect,\n\tforwardRef,\n} from \"react\";\nimport type UI5Element from \"../UI5Element.js\";\n\ntype EventHandler<E = Event> = (event: E) => void;\n\n// Interface for UI5 Web Component classes with _jsxProps support\ninterface UI5ComponentClass<T extends UI5Element = UI5Element> {\n\tnew (): T;\n\tgetMetadata(): {\n\t\tgetTag(): string;\n\t};\n}\n\n// Helper to convert event name\nconst toEventName = (propName: string): string => {\n\treturn propName\n\t\t.slice(2) // Remove \"on\"\n\t\t.replace(/([A-Z])/g, (match: string, letter: string, index: number): string => {\n\t\t\treturn index === 0 ? letter.toLowerCase() : `-${letter.toLowerCase()}`;\n\t\t});\n};\n\n// Helper to create cleanup function for event listener\nconst createEventCleanup = (element: UI5Element, eventName: string, handler: EventHandler): (() => void) => {\n\telement.addEventListener(eventName, handler);\n\treturn () => element.removeEventListener(eventName, handler);\n};\n\n/**\n * Creates a React component wrapper for a UI5 Web Component.\n * Uses the component's _jsxProps type for full TypeScript support.\n *\n * @param ComponentClass - The UI5 Web Component class (e.g., Button from \"@ui5/webcomponents/dist/Button.js\")\n * @returns A React component that renders the custom element with proper TypeScript types\n * @since 2.21.0\n * @example\n * import Button from \"@ui5/webcomponents/dist/Button.js\";\n * const ReactButton = createReactComponent(Button);\n * // ReactButton props are typed based on Button's _jsxProps\n */\nfunction createReactComponent<T extends UI5Element>(\n\tComponentClass: UI5ComponentClass<T>,\n): React.ForwardRefExoticComponent<\n\tReact.PropsWithoutRef<T[\"_jsxProps\"] & { children?: ReactNode }> & React.RefAttributes<T>\n> {\n\tconst tagName = ComponentClass.getMetadata().getTag();\n\n\tconst Component = forwardRef<T, T[\"_jsxProps\"] & { children?: ReactNode }>((props, ref) => {\n\t\tconst { children, ...restProps } = props;\n\t\tconst elementRef = useRef<T>(null);\n\n\t\t// Forward ref\n\t\tuseEffect(() => {\n\t\t\tif (ref) {\n\t\t\t\tif (typeof ref === \"function\") {\n\t\t\t\t\tref(elementRef.current);\n\t\t\t\t} else {\n\t\t\t\t\tref.current = elementRef.current;\n\t\t\t\t}\n\t\t\t}\n\t\t}, [ref]);\n\n\t\t// Handle event props and boolean props imperatively\n\t\tuseEffect(() => {\n\t\t\tconst element = elementRef.current;\n\t\t\tif (!element) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst eventCleanups: Array<() => void> = [];\n\n\t\t\tObject.keys(restProps).forEach(propName => {\n\t\t\t\tconst propValue = (restProps as Record<string, unknown>)[propName];\n\t\t\t\tif (propName.startsWith(\"on\") && typeof propValue === \"function\") {\n\t\t\t\t\t// Convert React event naming (onClick, onSelectionChange) to DOM event naming\n\t\t\t\t\t// onClick -> click, onSelectionChange -> selection-change\n\t\t\t\t\tconst eventName = toEventName(propName);\n\t\t\t\t\tconst handler = propValue as EventHandler;\n\t\t\t\t\teventCleanups.push(createEventCleanup(element, eventName, handler));\n\t\t\t\t} else if (typeof propValue === \"boolean\") {\n\t\t\t\t\t// React 18 sets false booleans as empty string attributes on custom elements.\n\t\t\t\t\t// Set as property directly to avoid this.\n\t\t\t\t\t(element as any)[propName] = propValue;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\treturn () => {\n\t\t\t\teventCleanups.forEach(cleanup => cleanup());\n\t\t\t};\n\t\t}, [restProps]);\n\n\t\t// Filter out event handlers and booleans from DOM props\n\t\tconst domProps: Record<string, unknown> = {};\n\t\tObject.keys(restProps).forEach(propName => {\n\t\t\tconst propValue = (restProps as Record<string, unknown>)[propName];\n\t\t\tif (propName.startsWith(\"on\") && typeof propValue === \"function\") { return; }\n\t\t\tif (typeof propValue === \"boolean\") { return; } // handled in useEffect\n\t\t\t// className → class for React compatibility\n\t\t\tif (propName === \"className\") {\n\t\t\t\t// eslint-disable-next-line dot-notation\n\t\t\t\tdomProps[\"class\"] = propValue;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// Convert camelCase to kebab-case for HTML attributes\n\t\t\tconst attrName = propName.replace(/([A-Z])/g, \"-$1\").toLowerCase();\n\t\t\tdomProps[attrName] = propValue;\n\t\t});\n\n\t\treturn React.createElement(tagName, { ref: elementRef, ...domProps }, children);\n\t});\n\n\tComponent.displayName = tagName\n\t\t.split(\"-\")\n\t\t.map(part => part.charAt(0).toUpperCase() + part.slice(1))\n\t\t.join(\"\");\n\n\treturn Component;\n}\n\nexport default createReactComponent;\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ui5/webcomponents-base",
3
- "version": "2.20.0",
3
+ "version": "2.20.1",
4
4
  "description": "UI5 Web Components: webcomponents.base",
5
5
  "author": "SAP SE (https://www.sap.com)",
6
6
  "license": "Apache-2.0",
@@ -66,7 +66,7 @@
66
66
  "@openui5/sap.ui.core": "1.120.17",
67
67
  "@sap-theming/theming-base-content": "11.33.0",
68
68
  "@ui5/cypress-internal": "0.1.0",
69
- "@ui5/webcomponents-tools": "2.20.0",
69
+ "@ui5/webcomponents-tools": "2.20.1",
70
70
  "clean-css": "^5.2.2",
71
71
  "cypress": "15.9.0",
72
72
  "mocha": "^11.7.2",
@@ -76,6 +76,14 @@
76
76
  "typescript": "^5.6.2",
77
77
  "vite": "5.4.21"
78
78
  },
79
+ "peerDependencies": {
80
+ "react": ">=18"
81
+ },
82
+ "peerDependenciesMeta": {
83
+ "react": {
84
+ "optional": true
85
+ }
86
+ },
79
87
  "customElements": "dist/custom-elements.json",
80
- "gitHead": "2642c2e61d49914e75d59f48d63576486037ff63"
88
+ "gitHead": "e99d0cc3b83e5320263a207f7ae3fcd159982e9f"
81
89
  }
@@ -0,0 +1,140 @@
1
+ /**
2
+ * React wrapper factory for UI5 Web Components.
3
+ *
4
+ * This lightweight factory creates typed React components that wrap UI5 Web Components.
5
+ * It handles:
6
+ * - Event prop conversion (onXxx → ui5-xxx event listeners)
7
+ * - Ref forwarding
8
+ * - Children handling
9
+ *
10
+ * Note: The function supports react >= 18.
11
+ * Note: This is for documentation samples only - for production React apps,
12
+ * use the official @ui5/webcomponents-react library.
13
+ */
14
+
15
+ import * as React from "react";
16
+ import type { ReactNode } from "react";
17
+ import {
18
+ useRef,
19
+ useEffect,
20
+ forwardRef,
21
+ } from "react";
22
+ import type UI5Element from "../UI5Element.js";
23
+
24
+ type EventHandler<E = Event> = (event: E) => void;
25
+
26
+ // Interface for UI5 Web Component classes with _jsxProps support
27
+ interface UI5ComponentClass<T extends UI5Element = UI5Element> {
28
+ new (): T;
29
+ getMetadata(): {
30
+ getTag(): string;
31
+ };
32
+ }
33
+
34
+ // Helper to convert event name
35
+ const toEventName = (propName: string): string => {
36
+ return propName
37
+ .slice(2) // Remove "on"
38
+ .replace(/([A-Z])/g, (match: string, letter: string, index: number): string => {
39
+ return index === 0 ? letter.toLowerCase() : `-${letter.toLowerCase()}`;
40
+ });
41
+ };
42
+
43
+ // Helper to create cleanup function for event listener
44
+ const createEventCleanup = (element: UI5Element, eventName: string, handler: EventHandler): (() => void) => {
45
+ element.addEventListener(eventName, handler);
46
+ return () => element.removeEventListener(eventName, handler);
47
+ };
48
+
49
+ /**
50
+ * Creates a React component wrapper for a UI5 Web Component.
51
+ * Uses the component's _jsxProps type for full TypeScript support.
52
+ *
53
+ * @param ComponentClass - The UI5 Web Component class (e.g., Button from "@ui5/webcomponents/dist/Button.js")
54
+ * @returns A React component that renders the custom element with proper TypeScript types
55
+ * @since 2.21.0
56
+ * @example
57
+ * import Button from "@ui5/webcomponents/dist/Button.js";
58
+ * const ReactButton = createReactComponent(Button);
59
+ * // ReactButton props are typed based on Button's _jsxProps
60
+ */
61
+ function createReactComponent<T extends UI5Element>(
62
+ ComponentClass: UI5ComponentClass<T>,
63
+ ): React.ForwardRefExoticComponent<
64
+ React.PropsWithoutRef<T["_jsxProps"] & { children?: ReactNode }> & React.RefAttributes<T>
65
+ > {
66
+ const tagName = ComponentClass.getMetadata().getTag();
67
+
68
+ const Component = forwardRef<T, T["_jsxProps"] & { children?: ReactNode }>((props, ref) => {
69
+ const { children, ...restProps } = props;
70
+ const elementRef = useRef<T>(null);
71
+
72
+ // Forward ref
73
+ useEffect(() => {
74
+ if (ref) {
75
+ if (typeof ref === "function") {
76
+ ref(elementRef.current);
77
+ } else {
78
+ ref.current = elementRef.current;
79
+ }
80
+ }
81
+ }, [ref]);
82
+
83
+ // Handle event props and boolean props imperatively
84
+ useEffect(() => {
85
+ const element = elementRef.current;
86
+ if (!element) {
87
+ return;
88
+ }
89
+
90
+ const eventCleanups: Array<() => void> = [];
91
+
92
+ Object.keys(restProps).forEach(propName => {
93
+ const propValue = (restProps as Record<string, unknown>)[propName];
94
+ if (propName.startsWith("on") && typeof propValue === "function") {
95
+ // Convert React event naming (onClick, onSelectionChange) to DOM event naming
96
+ // onClick -> click, onSelectionChange -> selection-change
97
+ const eventName = toEventName(propName);
98
+ const handler = propValue as EventHandler;
99
+ eventCleanups.push(createEventCleanup(element, eventName, handler));
100
+ } else if (typeof propValue === "boolean") {
101
+ // React 18 sets false booleans as empty string attributes on custom elements.
102
+ // Set as property directly to avoid this.
103
+ (element as any)[propName] = propValue;
104
+ }
105
+ });
106
+
107
+ return () => {
108
+ eventCleanups.forEach(cleanup => cleanup());
109
+ };
110
+ }, [restProps]);
111
+
112
+ // Filter out event handlers and booleans from DOM props
113
+ const domProps: Record<string, unknown> = {};
114
+ Object.keys(restProps).forEach(propName => {
115
+ const propValue = (restProps as Record<string, unknown>)[propName];
116
+ if (propName.startsWith("on") && typeof propValue === "function") { return; }
117
+ if (typeof propValue === "boolean") { return; } // handled in useEffect
118
+ // className → class for React compatibility
119
+ if (propName === "className") {
120
+ // eslint-disable-next-line dot-notation
121
+ domProps["class"] = propValue;
122
+ return;
123
+ }
124
+ // Convert camelCase to kebab-case for HTML attributes
125
+ const attrName = propName.replace(/([A-Z])/g, "-$1").toLowerCase();
126
+ domProps[attrName] = propValue;
127
+ });
128
+
129
+ return React.createElement(tagName, { ref: elementRef, ...domProps }, children);
130
+ });
131
+
132
+ Component.displayName = tagName
133
+ .split("-")
134
+ .map(part => part.charAt(0).toUpperCase() + part.slice(1))
135
+ .join("");
136
+
137
+ return Component;
138
+ }
139
+
140
+ export default createReactComponent;