diff --git a/react/package.json b/react/package.json index e5d50f7ec39..6de301ead87 100644 --- a/react/package.json +++ b/react/package.json @@ -48,7 +48,7 @@ "react-dom": "^16.7.0", "react-router": "^4.3.1", "react-router-dom": "^4.3.1", - "react-testing-library": "^5.5.3", + "react-testing-library": "^7.0.0", "ts-jest": "^23.10.5", "typescript": "^3.2.2" }, diff --git a/react/src/components/IonActionSheet.tsx b/react/src/components/IonActionSheet.tsx index e16b26ab5ca..2cb2d94a7c9 100644 --- a/react/src/components/IonActionSheet.tsx +++ b/react/src/components/IonActionSheet.tsx @@ -1,7 +1,8 @@ import { Components } from '@ionic/core'; import { createOverlayComponent } from './createOverlayComponent'; +import { ReactProps } from './ReactProps'; export type ActionSheetOptions = Components.IonActionSheetAttributes; -const IonActionSheet = createOverlayComponent('ion-action-sheet', 'ion-action-sheet-controller') +const IonActionSheet = createOverlayComponent('ion-action-sheet', 'ion-action-sheet-controller') export default IonActionSheet; diff --git a/react/src/components/IonAlert.tsx b/react/src/components/IonAlert.tsx index 60c4a27035d..f2d3a9e7a72 100644 --- a/react/src/components/IonAlert.tsx +++ b/react/src/components/IonAlert.tsx @@ -1,7 +1,8 @@ import { Components } from '@ionic/core'; import { createControllerComponent } from './createControllerComponent'; +import { ReactProps } from './ReactProps'; export type AlertOptions = Components.IonAlertAttributes; -const IonAlert = createControllerComponent('ion-alert', 'ion-alert-controller') +const IonAlert = createControllerComponent('ion-alert', 'ion-alert-controller') export default IonAlert; diff --git a/react/src/components/IonLoading.tsx b/react/src/components/IonLoading.tsx index 66c4d2379a5..6cfdae36718 100644 --- a/react/src/components/IonLoading.tsx +++ b/react/src/components/IonLoading.tsx @@ -1,7 +1,8 @@ import { Components } from '@ionic/core'; import { createControllerComponent } from './createControllerComponent'; +import { ReactProps } from './ReactProps'; export type LoadingOptions = Components.IonLoadingAttributes; -const IonLoading = createControllerComponent('ion-loading', 'ion-loading-controller') +const IonLoading = createControllerComponent('ion-loading', 'ion-loading-controller') export default IonLoading; diff --git a/react/src/components/IonModal.tsx b/react/src/components/IonModal.tsx index 50e452c0f42..ed92ab14641 100644 --- a/react/src/components/IonModal.tsx +++ b/react/src/components/IonModal.tsx @@ -1,10 +1,11 @@ import { Components } from '@ionic/core'; import { createOverlayComponent } from './createOverlayComponent'; import { Omit } from '../types'; +import { ReactProps } from './ReactProps'; export type ModalOptions = Omit & { children: React.ReactNode; }; -const IonModal = createOverlayComponent('ion-modal', 'ion-modal-controller') +const IonModal = createOverlayComponent('ion-modal', 'ion-modal-controller') export default IonModal; diff --git a/react/src/components/IonPopover.tsx b/react/src/components/IonPopover.tsx index 65dd5d623f8..d6a99ad7ee7 100644 --- a/react/src/components/IonPopover.tsx +++ b/react/src/components/IonPopover.tsx @@ -1,10 +1,11 @@ import { Components } from '@ionic/core'; import { createOverlayComponent } from './createOverlayComponent'; import { Omit } from '../types'; +import { ReactProps } from './ReactProps'; export type PopoverOptions = Omit & { children: React.ReactNode; }; -const IonPopover = createOverlayComponent('ion-popover', 'ion-popover-controller') +const IonPopover = createOverlayComponent('ion-popover', 'ion-popover-controller') export default IonPopover; diff --git a/react/src/components/IonToast.tsx b/react/src/components/IonToast.tsx index 952376095fa..a58b034fe6f 100644 --- a/react/src/components/IonToast.tsx +++ b/react/src/components/IonToast.tsx @@ -1,7 +1,8 @@ import { Components } from '@ionic/core'; import { createControllerComponent } from './createControllerComponent'; +import { ReactProps } from './ReactProps'; export type ToastOptions = Components.IonToastAttributes; -const IonToast = createControllerComponent('ion-toast', 'ion-toast-controller') +const IonToast = createControllerComponent('ion-toast', 'ion-toast-controller') export default IonToast; diff --git a/react/src/components/ReactProps.ts b/react/src/components/ReactProps.ts new file mode 100644 index 00000000000..6e5ba8021cb --- /dev/null +++ b/react/src/components/ReactProps.ts @@ -0,0 +1,3 @@ +export interface ReactProps { + className?: string; +} diff --git a/react/src/components/__tests__/createComponent.spec.tsx b/react/src/components/__tests__/createComponent.spec.tsx index 2d5de2719b5..735c435a5a0 100644 --- a/react/src/components/__tests__/createComponent.spec.tsx +++ b/react/src/components/__tests__/createComponent.spec.tsx @@ -1,7 +1,8 @@ import React from 'react'; import { Components } from '@ionic/core'; import { createReactComponent } from '../createComponent'; -import { render, fireEvent, cleanup } from 'react-testing-library'; +import { render, fireEvent, cleanup, RenderResult } from 'react-testing-library'; +import { IonButton } from '../index'; afterEach(cleanup); @@ -47,3 +48,88 @@ describe('createComponent - ref', () => { expect(ionButtonRef.current).toEqual(ionButtonItem); }); }); + +describe('when working with css classes', () => { + const myClass = 'my-class' + const myClass2 = 'my-class2' + const customClass = 'custom-class'; + + describe('when a class is added to className', () => { + let renderResult: RenderResult; + let button: HTMLElement; + + beforeEach(() => { + renderResult = render( + + Hello! + + ); + button = renderResult.getByText(/Hello/); + }); + + it('then it should be in the class list', () => { + expect(button.classList.contains(myClass)).toBeTruthy(); + }); + + it('when a class is added to class list outside of React, then that class should still be in class list when rendered again', () => { + button.classList.add(customClass); + expect(button.classList.contains(customClass)).toBeTruthy(); + renderResult.rerender( + + Hello! + + ); + expect(button.classList.contains(customClass)).toBeTruthy(); + }); + }); + + describe('when multiple classes are added to className', () => { + let renderResult: RenderResult; + let button: HTMLElement; + + beforeEach(() => { + renderResult = render( + + Hello! + + ); + button = renderResult.getByText(/Hello/); + }); + + it('then both classes should be in class list', () => { + expect(button.classList.contains(myClass)).toBeTruthy(); + expect(button.classList.contains(myClass2)).toBeTruthy(); + }); + + it('when one of the classes is removed, then only the remaining class should be in class list', () => { + expect(button.classList.contains(myClass)).toBeTruthy(); + expect(button.classList.contains(myClass2)).toBeTruthy(); + + renderResult.rerender( + + Hello! + + ); + + expect(button.classList.contains(myClass)).toBeTruthy(); + expect(button.classList.contains(myClass2)).toBeFalsy(); + }); + + it('when a custom class is added outside of React and one of the classes is removed, then only the remaining class and the custom class should be in class list', () => { + button.classList.add(customClass); + expect(button.classList.contains(myClass)).toBeTruthy(); + expect(button.classList.contains(myClass2)).toBeTruthy(); + expect(button.classList.contains(customClass)).toBeTruthy(); + + renderResult.rerender( + + Hello! + + ); + + expect(button.classList.contains(myClass)).toBeTruthy(); + expect(button.classList.contains(myClass)).toBeTruthy(); + expect(button.classList.contains(myClass2)).toBeFalsy(); + }); + }) +}); diff --git a/react/src/components/__tests__/createControllerComponent.spec.tsx b/react/src/components/__tests__/createControllerComponent.spec.tsx index 2d30934d8f4..bbac8777cc7 100644 --- a/react/src/components/__tests__/createControllerComponent.spec.tsx +++ b/react/src/components/__tests__/createControllerComponent.spec.tsx @@ -68,7 +68,7 @@ describe('createControllerComponent - events', () => { duration: 2000, children: 'ButtonNameA', onIonLoadingDidDismiss: onDidDismiss - }); + }, expect.any(Object)); }); test('should dismiss component on hiding', async () => { diff --git a/react/src/components/__tests__/createOverlayComponent.spec.tsx b/react/src/components/__tests__/createOverlayComponent.spec.tsx index 11247e6c630..ae6550eb23d 100644 --- a/react/src/components/__tests__/createOverlayComponent.spec.tsx +++ b/react/src/components/__tests__/createOverlayComponent.spec.tsx @@ -65,7 +65,7 @@ describe('createOverlayComponent - events', () => { expect(attachEventPropsSpy).toHaveBeenCalledWith(element, { buttons: [], onIonActionSheetDidDismiss: onDidDismiss - }); + }, expect.any(Object)); }); test('should dismiss component on hiding', async () => { diff --git a/react/src/components/createComponent.tsx b/react/src/components/createComponent.tsx index ee863daf8f0..8ecf764086d 100644 --- a/react/src/components/createComponent.tsx +++ b/react/src/components/createComponent.tsx @@ -2,24 +2,24 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { dashToPascalCase, attachEventProps } from './utils'; -export function createReactComponent(tagName: string) { +export function createReactComponent(tagName: string) { const displayName = dashToPascalCase(tagName); type IonicReactInternalProps = { - forwardedRef?: React.RefObject; + forwardedRef?: React.RefObject; children?: React.ReactNode; } - type InternalProps = T & IonicReactInternalProps; + type InternalProps = PropType & IonicReactInternalProps; type IonicReactExternalProps = { - ref?: React.RefObject; + ref?: React.RefObject; children?: React.ReactNode; } class ReactComponent extends React.Component { - componentRef: React.RefObject; + componentRef: React.RefObject; - constructor(props: T & IonicReactInternalProps) { + constructor(props: PropType & IonicReactInternalProps) { super(props); this.componentRef = React.createRef(); } @@ -34,8 +34,7 @@ export function createReactComponent(tagName: string) { componentWillReceiveProps(props: InternalProps) { const node = ReactDOM.findDOMNode(this) as HTMLElement; - - attachEventProps(node, props); + attachEventProps(node, props, this.props); } render() { @@ -52,10 +51,10 @@ export function createReactComponent(tagName: string) { } } - function forwardRef(props: InternalProps, ref: React.RefObject) { + function forwardRef(props: InternalProps, ref: React.RefObject) { return ; } forwardRef.displayName = displayName; - return React.forwardRef(forwardRef); + return React.forwardRef(forwardRef); } diff --git a/react/src/components/createControllerComponent.tsx b/react/src/components/createControllerComponent.tsx index b2a46834d6a..f467b071e10 100644 --- a/react/src/components/createControllerComponent.tsx +++ b/react/src/components/createControllerComponent.tsx @@ -45,7 +45,7 @@ export function createControllerComponent('ion-icon'); +export const IonIcon = createReactComponent('ion-icon'); // createReactComponent -export const IonTabBarInner = createReactComponent('ion-tab-bar'); -export const IonRouterOutletInner = createReactComponent('ion-router-outlet'); -export const IonBackButtonInner = createReactComponent('ion-back-button'); -export const IonTab = createReactComponent('ion-tab'); -export const IonTabButton = createReactComponent('ion-tab-button'); -export const IonAnchor = createReactComponent('ion-anchor'); -export const IonApp = createReactComponent('ion-app'); -export const IonAvatar = createReactComponent('ion-avatar'); -export const IonBackdrop = createReactComponent('ion-backdrop'); -export const IonBadge = createReactComponent('ion-badge'); -export const IonButton = createReactComponent('ion-button'); -export const IonButtons = createReactComponent('ion-buttons'); -export const IonCard = createReactComponent('ion-card'); -export const IonCardContent = createReactComponent('ion-card-content'); -export const IonCardHeader = createReactComponent('ion-card-header'); -export const IonCardSubtitle = createReactComponent('ion-card-subtitle'); -export const IonCardTitle = createReactComponent('ion-card-title'); -export const IonCheckbox = createReactComponent('ion-checkbox'); -export const IonCol = createReactComponent('ion-col'); -export const IonContent = createReactComponent('ion-content'); -export const IonChip = createReactComponent('ion-chip'); -export const IonDatetime = createReactComponent('ion-datetime'); -export const IonFab= createReactComponent('ion-fab'); -export const IonFabButton= createReactComponent('ion-fab-button'); -export const IonFabList = createReactComponent('ion-fab-list'); -export const IonFooter = createReactComponent('ion-footer'); -export const IonGrid = createReactComponent('ion-grid'); -export const IonHeader = createReactComponent('ion-header'); -export const IonImg = createReactComponent('ion-img'); -export const IonInfiniteScroll = createReactComponent('ion-infinite-scroll'); -export const IonInput = createReactComponent('ion-input'); -export const IonItem = createReactComponent('ion-item'); -export const IonItemDivider = createReactComponent('ion-item-divider'); -export const IonItemGroup = createReactComponent('ion-item-group'); -export const IonItemOption = createReactComponent('ion-item-option'); -export const IonItemOptions = createReactComponent('ion-item-options'); -export const IonItemSliding = createReactComponent('ion-item-sliding'); -export const IonLabel = createReactComponent('ion-label'); -export const IonList = createReactComponent('ion-list'); -export const IonListHeader = createReactComponent('ion-list-header'); -export const IonMenu = createReactComponent('ion-menu'); -export const IonMenuButton = createReactComponent('ion-menu-button'); -export const IonMenuToggle = createReactComponent('ion-menu-toggle'); -export const IonNote = createReactComponent('ion-note'); -export const IonPicker = createReactComponent('ion-picker'); -export const IonPickerColumn = createReactComponent('ion-picker-column'); -export const IonNav = createReactComponent('ion-nav'); -export const IonProgressBar = createReactComponent('ion-progress-bar'); -export const IonRadio = createReactComponent('ion-radio'); -export const IonRadioGroup = createReactComponent('ion-radio-group'); -export const IonRange = createReactComponent('ion-range'); -export const IonRefresher = createReactComponent('ion-refresher'); -export const IonRefresherContent = createReactComponent('ion-refresher-content'); -export const IonReorder = createReactComponent('ion-reorder'); -export const IonReorderGroup = createReactComponent('ion-reorder-group'); -export const IonRippleEffect = createReactComponent('ion-ripple-effect'); -export const IonRow = createReactComponent('ion-row'); -export const IonSearchbar= createReactComponent('ion-searchbar'); -export const IonSegment= createReactComponent('ion-segment'); -export const IonSegmentButton= createReactComponent('ion-segment-button'); -export const IonSelect = createReactComponent('ion-select'); -export const IonSelectOption = createReactComponent('ion-select-option'); -export const IonSelectPopover = createReactComponent('ion-select-popover'); -export const IonSkeletonText = createReactComponent('ion-skeleton-text'); -export const IonSlide = createReactComponent('ion-slide'); -export const IonSlides = createReactComponent('ion-slides'); -export const IonSpinner = createReactComponent('ion-spinner'); -export const IonSplitPane = createReactComponent('ion-split-pane'); -export const IonText = createReactComponent('ion-text'); -export const IonTextarea = createReactComponent('ion-textarea'); -export const IonThumbnail = createReactComponent('ion-thumbnail'); -export const IonTitle = createReactComponent('ion-title'); -export const IonToggle = createReactComponent('ion-toggle'); -export const IonToolbar = createReactComponent('ion-toolbar'); -export const IonVirtualScroll = createReactComponent('ion-virtual-scroll'); +export const IonTabBarInner = createReactComponent('ion-tab-bar'); +export const IonRouterOutletInner = createReactComponent('ion-router-outlet'); +export const IonBackButtonInner = createReactComponent('ion-back-button'); +export const IonTab = createReactComponent('ion-tab'); +export const IonTabButton = createReactComponent('ion-tab-button'); +export const IonAnchor = createReactComponent('ion-anchor'); +export const IonApp = createReactComponent('ion-app'); +export const IonAvatar = createReactComponent('ion-avatar'); +export const IonBackdrop = createReactComponent('ion-backdrop'); +export const IonBadge = createReactComponent('ion-badge'); +export const IonButton = createReactComponent('ion-button'); +export const IonButtons = createReactComponent('ion-buttons'); +export const IonCard = createReactComponent('ion-card'); +export const IonCardContent = createReactComponent('ion-card-content'); +export const IonCardHeader = createReactComponent('ion-card-header'); +export const IonCardSubtitle = createReactComponent('ion-card-subtitle'); +export const IonCardTitle = createReactComponent('ion-card-title'); +export const IonCheckbox = createReactComponent('ion-checkbox'); +export const IonCol = createReactComponent('ion-col'); +export const IonContent = createReactComponent('ion-content'); +export const IonChip = createReactComponent('ion-chip'); +export const IonDatetime = createReactComponent('ion-datetime'); +export const IonFab= createReactComponent('ion-fab'); +export const IonFabButton= createReactComponent('ion-fab-button'); +export const IonFabList = createReactComponent('ion-fab-list'); +export const IonFooter = createReactComponent('ion-footer'); +export const IonGrid = createReactComponent('ion-grid'); +export const IonHeader = createReactComponent('ion-header'); +export const IonImg = createReactComponent('ion-img'); +export const IonInfiniteScroll = createReactComponent('ion-infinite-scroll'); +export const IonInput = createReactComponent('ion-input'); +export const IonItem = createReactComponent('ion-item'); +export const IonItemDivider = createReactComponent('ion-item-divider'); +export const IonItemGroup = createReactComponent('ion-item-group'); +export const IonItemOption = createReactComponent('ion-item-option'); +export const IonItemOptions = createReactComponent('ion-item-options'); +export const IonItemSliding = createReactComponent('ion-item-sliding'); +export const IonLabel = createReactComponent('ion-label'); +export const IonList = createReactComponent('ion-list'); +export const IonListHeader = createReactComponent('ion-list-header'); +export const IonMenu = createReactComponent('ion-menu'); +export const IonMenuButton = createReactComponent('ion-menu-button'); +export const IonMenuToggle = createReactComponent('ion-menu-toggle'); +export const IonNote = createReactComponent('ion-note'); +export const IonPicker = createReactComponent('ion-picker'); +export const IonPickerColumn = createReactComponent('ion-picker-column'); +export const IonNav = createReactComponent('ion-nav'); +export const IonProgressBar = createReactComponent('ion-progress-bar'); +export const IonRadio = createReactComponent('ion-radio'); +export const IonRadioGroup = createReactComponent('ion-radio-group'); +export const IonRange = createReactComponent('ion-range'); +export const IonRefresher = createReactComponent('ion-refresher'); +export const IonRefresherContent = createReactComponent('ion-refresher-content'); +export const IonReorder = createReactComponent('ion-reorder'); +export const IonReorderGroup = createReactComponent('ion-reorder-group'); +export const IonRippleEffect = createReactComponent('ion-ripple-effect'); +export const IonRow = createReactComponent('ion-row'); +export const IonSearchbar= createReactComponent('ion-searchbar'); +export const IonSegment= createReactComponent('ion-segment'); +export const IonSegmentButton= createReactComponent('ion-segment-button'); +export const IonSelect = createReactComponent('ion-select'); +export const IonSelectOption = createReactComponent('ion-select-option'); +export const IonSelectPopover = createReactComponent('ion-select-popover'); +export const IonSkeletonText = createReactComponent('ion-skeleton-text'); +export const IonSlide = createReactComponent('ion-slide'); +export const IonSlides = createReactComponent('ion-slides'); +export const IonSpinner = createReactComponent('ion-spinner'); +export const IonSplitPane = createReactComponent('ion-split-pane'); +export const IonText = createReactComponent('ion-text'); +export const IonTextarea = createReactComponent('ion-textarea'); +export const IonThumbnail = createReactComponent('ion-thumbnail'); +export const IonTitle = createReactComponent('ion-title'); +export const IonToggle = createReactComponent('ion-toggle'); +export const IonToolbar = createReactComponent('ion-toolbar'); +export const IonVirtualScroll = createReactComponent('ion-virtual-scroll'); diff --git a/react/src/components/utils/attachEventProps.ts b/react/src/components/utils/attachEventProps.ts new file mode 100644 index 00000000000..9df26881adf --- /dev/null +++ b/react/src/components/utils/attachEventProps.ts @@ -0,0 +1,83 @@ +export function attachEventProps(node: HTMLElement, newProps: any, oldProps: any = {}) { + const className = getClassName(node.classList, newProps, oldProps); + if(className) { + node.className = className; + } + + Object.keys(newProps).forEach(name => { + if (name === 'children' || name === 'style' || name === 'ref' || name === 'className') { + return; + } + if (name.indexOf('on') === 0 && name[2] === name[2].toUpperCase()) { + const eventName = name.substring(2); + const eventNameLc = eventName[0].toLowerCase() + eventName.substring(1); + + if (!isCoveredByReact(eventNameLc)) { + syncEvent(node, eventNameLc, newProps[name]); + } + } else { + (node as any)[name] = newProps[name]; + } + }); +} + +export function getClassName(classList: DOMTokenList, newProps: any, oldProps: any) { + // map the classes to Maps for performance + const currentClasses = arrayToMap(classList); + const incomingPropClasses = arrayToMap(newProps.className ? newProps.className.split(' ') : []); + const oldPropClasses = arrayToMap(oldProps.className ? oldProps.className.split(' ') : []); + const finalClassNames: string[] = []; + // loop through each of the current classes on the component + // to see if it should be a part of the classNames added + currentClasses.forEach((currentClass) => { + if (incomingPropClasses.has(currentClass)) { + // add it as its already included in classnames coming in from newProps + finalClassNames.push(currentClass); + incomingPropClasses.delete(currentClass); + } + else if (!oldPropClasses.has(currentClass)) { + // add it as it has NOT been removed by user + finalClassNames.push(currentClass); + } + }); + incomingPropClasses.forEach(s => finalClassNames.push(s)); + return finalClassNames.join(' '); +} + +/** + * Checks if an event is supported in the current execution environment. + * @license Modernizr 3.0.0pre (Custom Build) | MIT + */ +export function isCoveredByReact(eventNameSuffix: string, doc: Document = document) { + const eventName = 'on' + eventNameSuffix; + let isSupported = eventName in doc; + + if (!isSupported) { + const element = doc.createElement('div'); + element.setAttribute(eventName, 'return;'); + isSupported = typeof (element)[eventName] === 'function'; + } + + return isSupported; +} + +export function syncEvent(node: Element, eventName: string, newEventHandler: (e: Event) => any) { + const eventStore = (node as any).__events || ((node as any).__events = {}); + const oldEventHandler = eventStore[eventName]; + + // Remove old listener so they don't double up. + if (oldEventHandler) { + node.removeEventListener(eventName, oldEventHandler); + } + + // Bind new listener. + node.addEventListener(eventName, eventStore[eventName] = function handler(e: Event) { + newEventHandler.call(this, e); + }); +} + +function arrayToMap(arr: string[] | DOMTokenList) { + const map = new Map(); + arr.forEach((s: string) => map.set(s, s)); + return map; +} diff --git a/react/src/components/utils/index.ts b/react/src/components/utils/index.ts index 40078c644c8..95592807232 100644 --- a/react/src/components/utils/index.ts +++ b/react/src/components/utils/index.ts @@ -1,34 +1,4 @@ -/** - * Checks if an event is supported in the current execution environment. - * @license Modernizr 3.0.0pre (Custom Build) | MIT - */ -export function isCoveredByReact(eventNameSuffix: string, doc: Document = document) { - const eventName = 'on' + eventNameSuffix; - let isSupported = eventName in doc; - if (!isSupported) { - const element = doc.createElement('div'); - element.setAttribute(eventName, 'return;'); - isSupported = typeof (element)[eventName] === 'function'; - } - - return isSupported; -} - -export function syncEvent(node: Element, eventName: string, newEventHandler: (e: Event) => any) { - const eventStore = (node as any).__events || ((node as any).__events = {}); - const oldEventHandler = eventStore[eventName]; - - // Remove old listener so they don't double up. - if (oldEventHandler) { - node.removeEventListener(eventName, oldEventHandler); - } - - // Bind new listener. - node.addEventListener(eventName, eventStore[eventName] = function handler(e: Event) { - newEventHandler.call(this, e); - }); -} export const dashToPascalCase = (str: string) => str.toLowerCase().split('-').map(segment => segment.charAt(0).toUpperCase() + segment.slice(1)).join(''); @@ -41,29 +11,11 @@ export function ensureElementInBody(elementName: string): return element; } -export function attachEventProps(node: E, props: any) { - Object.keys(props).forEach(name => { - if (name === 'children' || name === 'style' || name === 'ref') { - return; - } - - if (name.indexOf('on') === 0 && name[2] === name[2].toUpperCase()) { - const eventName = name.substring(2); - const eventNameLc = eventName[0].toLowerCase() + eventName.substring(1); - - if (!isCoveredByReact(eventNameLc)) { - syncEvent(node, eventNameLc, props[name]); - } - } else { - (node as any)[name] = props[name]; - } - }); -} - - export function generateUniqueId() { return ([1e7].toString() + -1e3.toString() + -4e3.toString() + -8e3.toString() + -1e11.toString()).replace(/[018]/g, function(c: any) { const random = crypto.getRandomValues(new Uint8Array(1)) as Uint8Array; return (c ^ random[0] & 15 >> c / 4).toString(16); }); } + +export * from './attachEventProps';