1- import React , { useRef , useEffect , useState , useCallback } from 'react'
1+ import React , { useRef , useEffect , useState } from 'react'
22
33const ShadowRoot = typeof window !== 'undefined' ? require ( 'react-shadow-root' ) . default : ( ) => 0
44
55import generateSvgSquircle from './generator'
66import getMaskPaths from './mask-generator'
7- import attachCSSWatcher from './styleSheetWatcher'
7+ import { attachCSSWatcher , detachCSSWatcher } from './styleSheetWatcher'
88import updateStates from './updateStates'
99
1010import { lazySetObjectsState } from './utils/react-utils'
@@ -16,7 +16,8 @@ import {camelise} from './utils/string-manipulation'
1616 * */
1717export default function RoundDiv ( { style, children, dontConvertShadow, ...props } ) {
1818 // welcome to react states hell
19- const [ position , setPosition ] = useState ( [ 0 , 0 ] )
19+ // const [position, setPosition] = useState([0, 0])
20+ const [ padding , setPadding ] = useState ( Array ( 4 ) . fill ( 0 ) )
2021 const [ height , setHeight ] = useState ( 0 )
2122 const [ width , setWidth ] = useState ( 0 )
2223 const [ radius , setRadius ] = useState ( Array ( 4 ) . fill ( 0 ) )
@@ -33,11 +34,12 @@ export default function RoundDiv({style, children, dontConvertShadow, ...props})
3334
3435 const div = useRef ( )
3536
36- const updateStatesWithArgs = useCallback ( ( ) => {
37+ const updateStatesWithArgs = ( ) => {
3738 updateStates ( {
3839 div,
3940 style,
40- setPosition,
41+ // setPosition,
42+ setPadding,
4143 setHeight,
4244 setWidth,
4345 setRadius,
@@ -47,18 +49,20 @@ export default function RoundDiv({style, children, dontConvertShadow, ...props})
4749 setBorderOpacity,
4850 setShadows
4951 } )
50- } , [ style ] )
51-
52- useEffect ( updateStatesWithArgs , [ style , updateStatesWithArgs ] )
52+ }
5353
5454 useEffect ( ( ) => {
55- attachCSSWatcher ( ( ) => updateStatesWithArgs ( ) ) // todo: make this a react hook
56- } , [ updateStatesWithArgs ] )
55+ const watcherId = attachCSSWatcher ( updateStatesWithArgs , div . current ) // todo: make this a react hook
56+ updateStatesWithArgs ( )
57+ return ( ) => {
58+ detachCSSWatcher ( watcherId )
59+ }
60+ } , [ ] )
5761
5862 const svgRef = useRef ( ) ;
5963
6064 useEffect ( ( ) => {
61- setPath ( generateSvgSquircle ( height , width , radius ) )
65+ lazySetObjectsState ( setMaskPaths , getMaskPaths ( borderWidth , height , width , radius ) )
6266 setInnerPath ( generateSvgSquircle (
6367 height - ( borderWidth [ 0 ] + borderWidth [ 2 ] ) ,
6468 width - ( borderWidth [ 1 ] + borderWidth [ 3 ] ) ,
@@ -73,18 +77,17 @@ export default function RoundDiv({style, children, dontConvertShadow, ...props})
7377 Number ( number ) + ( i === 0 ? borderWidth [ 3 ] : borderWidth [ 0 ] )
7478 ) . join ( ',' )
7579 ) )
80+ setPath ( generateSvgSquircle ( height , width , radius ) )
81+ } , [ height , width , radius , borderWidth ] )
7682
77- lazySetObjectsState ( setMaskPaths , getMaskPaths ( borderWidth , height , width , radius ) )
78-
79- // patch for webkit's svg bug
80- if ( svgRef . current )
83+ // patch for webkit's svg bug
84+ if ( svgRef . current )
85+ setTimeout ( ( ) => {
86+ svgRef . current . style . position = ''
8187 setTimeout ( ( ) => {
82- svgRef . current . style . position = ''
83- setTimeout ( ( ) => {
84- svgRef . current . style . position = 'fixed'
85- } , 0 )
88+ svgRef . current . style . position = 'fixed'
8689 } , 0 )
87- } , [ height , width , radius , borderWidth ] )
90+ } , 0 )
8891
8992 const pathIsEmpty = ( path . startsWith ( 'Z' ) || path === '' )
9093 const divStyle = {
@@ -100,52 +103,60 @@ export default function RoundDiv({style, children, dontConvertShadow, ...props})
100103 filter : dontConvertShadow ? '' : shadows [ 0 ] . map ( shadowData => `drop-shadow(${ shadowData } )` ) . join ( ' ' ) ,
101104 } )
102105 }
106+
103107 const shapeComponentStyles = {
104108 height,
105109 width,
106110 position : 'fixed' ,
107- left : Math . round ( position [ 0 ] ) ,
108- top : Math . round ( position [ 1 ] ) ,
111+ left : 0 ,
112+ top : 0 ,
113+ transform : `translate(-${ padding [ 3 ] } px, -${ padding [ 0 ] } px)` ,
109114 zIndex : - 1 ,
110115 }
111116
112117 return < div { ...props } style = { divStyle } ref = { div } >
113118 { pathIsEmpty ? null : < ShadowRoot >
114119 < div style = { {
115- ...shapeComponentStyles ,
116- clipPath : `path("${ path } ")` ,
117- // inset shadow only
118- boxShadow : shadows [ 1 ] . join ( ',' ) ,
119- ...( Object . fromEntries ( Object . keys ( background ) . map ( key => {
120- return [ camelise ( key === 'null' ? 'background' : ( 'background-' + key ) ) , background [ key ] ]
121- } ) ) ) ,
122- } } />
123- < svg viewBox = { `0 0 ${ width } ${ height } ` } style = { shapeComponentStyles } preserveAspectRatio = { 'xMidYMid slice' }
124- ref = { svgRef } >
125- < defs >
126- < clipPath id = "inner" clipPathUnits = "userSpaceOnUse" >
127- < path d = { `M0,0V${ height } H${ width } V0Z` + innerPath } fillRule = { 'evenodd' } />
128- </ clipPath >
129- < clipPath id = "outer" clipPathUnits = "userSpaceOnUse" >
130- < path d = { path } fillRule = { 'evenodd' } />
131- </ clipPath >
132- </ defs >
133- < g clipPath = { 'url(#outer)' } >
134- { Object . keys ( maskPaths ) . map ( ( key , i ) => {
135- if ( borderColor [ i ] === borderColor [ i - 1 ] ) return ''
136-
137- let path = maskPaths [ key ]
138- while ( borderColor [ i ] === borderColor [ i + 1 ] ) {
139- path += maskPaths [ Object . keys ( maskPaths ) [ i + 1 ] ]
140- i ++
141- }
142-
143- return < path d = { path } clipPath = { 'url(#inner)' } key = { key }
144- fill = { borderColor [ i ] } opacity = { borderOpacity [ i ] } />
145- } ) }
146- </ g >
147- </ svg >
148- < slot style = { { overflow : 'visible' } } />
120+ transform : 'scale(1)'
121+ } } >
122+ < div style = { {
123+ ...shapeComponentStyles ,
124+ clipPath : `path("${ path } ")` ,
125+ // inset shadow only
126+ boxShadow : shadows [ 1 ] . join ( ',' ) ,
127+ borderRadius : radius . map ( n => ( n - 1 ) + 'px' ) . join ( ' ' ) ,
128+ ...( Object . fromEntries ( Object . keys ( background ) . map ( key => {
129+ return [ camelise ( key === 'null' ? 'background' : ( 'background-' + key ) ) , background [ key ] ]
130+ } ) ) ) ,
131+ } } />
132+ < svg viewBox = { `0 0 ${ width } ${ height } ` } style = { shapeComponentStyles }
133+ preserveAspectRatio = { 'xMidYMid slice' }
134+ ref = { svgRef } >
135+ < defs >
136+ < clipPath id = "inner" clipPathUnits = "userSpaceOnUse" >
137+ < path d = { `M0,0V${ height } H${ width } V0Z` + innerPath } fillRule = { 'evenodd' } />
138+ </ clipPath >
139+ < clipPath id = "outer" clipPathUnits = "userSpaceOnUse" >
140+ < path d = { path } fillRule = { 'evenodd' } />
141+ </ clipPath >
142+ </ defs >
143+ < g clipPath = { 'url(#outer)' } >
144+ { Object . keys ( maskPaths ) . map ( ( key , i ) => {
145+ if ( borderColor [ i ] === borderColor [ i - 1 ] ) return ''
146+
147+ let path = maskPaths [ key ]
148+ while ( borderColor [ i ] === borderColor [ i + 1 ] ) {
149+ path += maskPaths [ Object . keys ( maskPaths ) [ i + 1 ] ]
150+ i ++
151+ }
152+
153+ return < path d = { path } clipPath = { 'url(#inner)' } key = { key }
154+ fill = { borderColor [ i ] } opacity = { borderOpacity [ i ] } />
155+ } ) }
156+ </ g >
157+ </ svg >
158+ < slot style = { { overflow : 'visible' } } />
159+ </ div >
149160 </ ShadowRoot > }
150161 { children }
151162 </ div >
0 commit comments