11import React from 'react' ;
22import ReactDOM from 'react-dom' ;
3+ import { HotEditorElement } from './types' ;
34
45let bulkComponentContainer = null ;
56
@@ -9,6 +10,22 @@ let bulkComponentContainer = null;
910export const AUTOSIZE_WARNING = 'Your `HotTable` configuration includes `autoRowSize`/`autoColumnSize` options, which are not compatible with ' +
1011 ' the component-based renderers`. Disable `autoRowSize` and `autoColumnSize` to prevent row and column misalignment.' ;
1112
13+ /**
14+ * Default classname given to the wrapper container.
15+ */
16+ const DEFAULT_CLASSNAME = 'hot-wrapper-editor-container' ;
17+
18+ /**
19+ * Logs warn to the console if the `console` object is exposed.
20+ *
21+ * @param {...* } args Values which will be logged.
22+ */
23+ export function warn ( ...args ) {
24+ if ( typeof console !== 'undefined' ) {
25+ console . warn ( ...args ) ;
26+ }
27+ }
28+
1229/**
1330 * Filter out and return elements of the provided `type` from the `HotColumn` component's children.
1431 *
@@ -36,26 +53,27 @@ export function getChildElementByType(children: React.ReactNode, type: string):
3653}
3754
3855/**
39- * Get the component node name .
56+ * Get the reference to the original editor class .
4057 *
41- * @param {React.ReactElement } componentNode
42- * @returns {String } Provided component's name .
58+ * @param {React.ReactElement } editorElement React element of the editor class.
59+ * @returns {Function } Original class of the editor component .
4360 */
44- export function getComponentNodeName ( componentNode : React . ReactElement ) : string {
45- if ( ! componentNode ) {
61+ export function getOriginalEditorClass ( editorElement : HotEditorElement ) {
62+ if ( ! editorElement ) {
4663 return null ;
4764 }
4865
49- return ( componentNode . type as Function ) . name || ( ( componentNode . type as any ) . WrappedComponent as Function ) . name ;
66+ return editorElement . type . WrappedComponent ? editorElement . type . WrappedComponent : editorElement . type ;
5067}
5168
5269/**
5370 * Remove editor containers from DOM.
5471 *
55- * @param [doc] Document to be used.
72+ * @param {Document } [doc] Document to be used.
73+ * @param {Map } editorCache The editor cache reference.
5674 */
5775export function removeEditorContainers ( doc = document ) : void {
58- doc . querySelectorAll ( '[id ^="hot-wrapper-editor-container-"]' ) . forEach ( ( domNode ) => {
76+ doc . querySelectorAll ( `[class ^="${ DEFAULT_CLASSNAME } "]` ) . forEach ( ( domNode ) => {
5977 if ( domNode . parentNode ) {
6078 domNode . parentNode . removeChild ( domNode ) ;
6179 }
@@ -65,23 +83,31 @@ export function removeEditorContainers(doc = document): void {
6583/**
6684 * Create an editor portal.
6785 *
86+ * @param {Document } [doc] Document to be used.
6887 * @param {React.ReactElement } editorElement Editor's element.
88+ * @param {Map } editorCache The editor cache reference.
6989 * @returns {React.ReactPortal } The portal for the editor.
7090 */
71- export function createEditorPortal ( editorElement : React . ReactElement ) : React . ReactPortal {
91+ export function createEditorPortal ( doc = document , editorElement : HotEditorElement , editorCache : Map < Function , React . Component > ) : React . ReactPortal {
7292 if ( editorElement === null ) {
7393 return ;
7494 }
7595
76- const componentName : string = getComponentNodeName ( editorElement ) ;
96+ const editorContainer = doc . createElement ( 'DIV' ) ;
97+ const { id, className, style} = getContainerAttributesProps ( editorElement . props , false ) ;
7798
78- let editorContainer = document . querySelector ( '#hot-wrapper-editor-container-' + componentName ) ;
79- if ( ! document . querySelector ( '#hot-wrapper-editor-container-' + componentName ) ) {
80- editorContainer = document . createElement ( 'DIV' ) ;
81- editorContainer . id = 'hot-wrapper-editor-container-' + componentName ;
82- document . body . appendChild ( editorContainer ) ;
99+ if ( id ) {
100+ editorContainer . id = id ;
83101 }
84102
103+ editorContainer . className = [ DEFAULT_CLASSNAME , className ] . join ( ' ' ) ;
104+
105+ if ( style ) {
106+ Object . assign ( editorContainer . style , style ) ;
107+ }
108+
109+ doc . body . appendChild ( editorContainer ) ;
110+
85111 return ReactDOM . createPortal ( editorElement , editorContainer ) ;
86112}
87113
@@ -92,21 +118,20 @@ export function createEditorPortal(editorElement: React.ReactElement): React.Rea
92118 * @param {Map } editorCache Component's editor cache.
93119 * @returns {React.ReactElement } An editor element containing the additional methods.
94120 */
95- export function getExtendedEditorElement ( children : React . ReactNode , editorCache : Map < string , object > ) : React . ReactElement | null {
121+ export function getExtendedEditorElement ( children : React . ReactNode , editorCache : Map < Function , object > ) : React . ReactElement | null {
96122 const editorElement = getChildElementByType ( children , 'hot-editor' ) ;
123+ const editorClass = getOriginalEditorClass ( editorElement ) ;
97124
98125 if ( ! editorElement ) {
99126 return null ;
100127 }
101128
102129 return React . cloneElement ( editorElement , {
103- emitEditorInstance : ( editorName , editorInstance ) => {
104- if ( ! editorCache . has ( editorName ) ) {
105- editorCache . set ( editorName , editorInstance ) ;
106- }
130+ emitEditorInstance : ( editorInstance ) => {
131+ editorCache . set ( editorClass , editorInstance ) ;
107132 } ,
108133 isEditor : true
109- } ) ;
134+ } as object ) ;
110135}
111136
112137/**
@@ -144,23 +169,42 @@ export function createPortal(rElement: React.ReactElement, props, callback: Func
144169 } ;
145170}
146171
172+ /**
173+ * Get an object containing the `id`, `className` and `style` keys, representing the corresponding props passed to the
174+ * component.
175+ *
176+ * @param {Object } props Object containing the react element props.
177+ * @param {Boolean } randomizeId If set to `true`, the function will randomize the `id` property when no `id` was present in the `prop` object.
178+ * @returns An object containing the `id`, `className` and `style` keys, representing the corresponding props passed to the
179+ * component.
180+ */
181+ export function getContainerAttributesProps ( props , randomizeId : boolean = true ) : { id : string , className : string , style : object } {
182+ return {
183+ id : props . id || ( randomizeId ? 'hot-' + Math . random ( ) . toString ( 36 ) . substring ( 5 ) : void 0 ) ,
184+ className : props . className || '' ,
185+ style : props . style || { } ,
186+ }
187+ }
188+
147189/**
148190 * Add the `UNSAFE_` prefixes to the deprecated lifecycle methods for React >= 16.3.
149191 *
150- * @param {Function } Klass Class to have the methods renamed.
151- * @returns {Function } Class with the renamed methods.
192+ * @param {Object } instance Instance to have the methods renamed.
152193 */
153- export function addUnsafePrefixes < T extends any > ( Klass : T ) : T {
194+ export function addUnsafePrefixes ( instance : {
195+ UNSAFE_componentWillUpdate ?: Function ,
196+ componentWillUpdate : Function ,
197+ UNSAFE_componentWillMount ?: Function ,
198+ componentWillMount : Function
199+ } ) : void {
154200 const reactSemverArray = React . version . split ( '.' ) . map ( ( v ) => parseInt ( v ) ) ;
155201 const shouldPrefix = reactSemverArray [ 0 ] >= 16 && reactSemverArray [ 1 ] >= 3 ;
156202
157203 if ( shouldPrefix ) {
158- Klass . prototype . UNSAFE_componentWillUpdate = Klass . prototype . componentWillUpdate ;
159- delete Klass . prototype . componentWillUpdate ;
204+ instance . UNSAFE_componentWillUpdate = instance . componentWillUpdate ;
205+ instance . componentWillUpdate = void 0 ;
160206
161- Klass . prototype . UNSAFE_componentWillMount = Klass . prototype . componentWillMount ;
162- delete Klass . prototype . componentWillMount ;
207+ instance . UNSAFE_componentWillMount = instance . componentWillMount ;
208+ instance . componentWillMount = void 0 ;
163209 }
164-
165- return Klass ;
166210}
0 commit comments