Skip to content

Commit 46af6c7

Browse files
committed
improve border rendering
1 parent 013df7f commit 46af6c7

8 files changed

Lines changed: 91 additions & 200 deletions

File tree

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ Here is a very clear demonstration of these smooth corners:
2222
npm i react-round-div
2323
```
2424

25+
#### Size
26+
27+
| | Gzipped | Minified + Gzipped |
28+
|----------------------------------|---------:|-------------------:|
29+
| `react-round-div` | 7.8 KB | 5.28 KB |
30+
| `react-round-div` + dependencies | 14.97 KB | **9.17 KB** |
31+
2532
## Usage
2633

2734
Simply import the package and replace any divs with rounded corners (`border-radius`) that you want to

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/main.js

Lines changed: 43 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -3,52 +3,49 @@ import React, {useRef, useEffect, useState} from 'react'
33
const ShadowRoot = typeof window !== 'undefined' ? require('react-shadow-root').default : () => 0
44

55
import generateSvgSquircle from './generator'
6-
import getMaskPaths from './mask-generator'
76
import {attachCSSWatcher, detachCSSWatcher} from './styleSheetWatcher'
87
import updateStates from './updateStates'
98

10-
import {lazySetObjectsState} from './utils/react-utils'
119
import {camelise} from './utils/string-manipulation'
1210

1311
/**
1412
* @function RoundDiv
1513
* @extends React.PureComponent
1614
* */
1715
export default function RoundDiv({style, children, dontConvertShadow, ...props}) {
16+
const array = (length, defaultValue) => Array(length).fill(defaultValue)
1817
// welcome to react states hell
19-
// const [position, setPosition] = useState([0, 0])
20-
const [padding, setPadding] = useState(Array(4).fill(0))
18+
const [padding, setPadding] = useState(array(4, 0))
2119
const [height, setHeight] = useState(0)
2220
const [width, setWidth] = useState(0)
23-
const [radius, setRadius] = useState(Array(4).fill(0))
21+
const [radius, setRadius] = useState(array(4, 0))
2422

25-
const [transition, setTransition] = useState(Array(4).fill(0))
23+
const [transition, setTransition] = useState(array(4, 0))
2624

27-
const [borderColor, setBorderColor] = useState(Array(4).fill('transparent'))
28-
const [borderOpacity, setBorderOpacity] = useState(Array(4).fill(0))
29-
const [borderWidth, setBorderWidth] = useState(Array(4).fill(0))
3025
const [background, setBackground] = useState({})
31-
const [shadows, setShadows] = useState(Array(2).fill([]))
26+
const [border, setBorder] = useState({width: array(4, 0)})
27+
const [borderImage, setBorderImage] = useState({})
28+
// const [borderColor, setBorderColor] = useState(array(4, 'transparent'))
29+
// const [borderOpacity, setBorderOpacity] = useState(array(4, 0))
30+
// const [borderWidth, setBorderWidth] = useState(array(4, 0))
31+
const [shadows, setShadows] = useState(array(2, []))
3232

3333
const [path, setPath] = useState('Z')
3434
const [innerPath, setInnerPath] = useState('Z')
35-
const [maskPaths, setMaskPaths] = useState('Z')
3635

3736
const div = useRef()
3837

3938
const updateStatesWithArgs = () => {
4039
updateStates({
4140
div,
4241
style,
43-
// setPosition,
4442
setPadding,
4543
setHeight,
4644
setWidth,
4745
setRadius,
4846
setBackground,
49-
setBorderColor,
50-
setBorderWidth,
51-
setBorderOpacity,
47+
setBorder,
48+
setBorderImage,
5249
setShadows,
5350
setTransition,
5451
})
@@ -65,23 +62,22 @@ export default function RoundDiv({style, children, dontConvertShadow, ...props})
6562
const svgRef = useRef();
6663

6764
useEffect(() => {
68-
lazySetObjectsState(setMaskPaths, getMaskPaths(borderWidth, height, width, radius))
6965
setInnerPath(generateSvgSquircle(
70-
height - (borderWidth[0] + borderWidth[2]),
71-
width - (borderWidth[1] + borderWidth[3]),
66+
height - (border.width[0] + border.width[2]),
67+
width - (border.width[1] + border.width[3]),
7268
radius.map((val, i) =>
7369
Math.max(0,
74-
val - Math.max(borderWidth[i], borderWidth[i === 0 ? 3 : i - 1])
70+
val - Math.max(border.width[i], border.width[i === 0 ? 3 : i - 1])
7571
)
7672
)
7773
).replace(
7874
/(\d+(\.\d+)?),(\d+(\.\d+)?)/g,
7975
match => match.split(',').map((number, i) =>
80-
Number(number) + (i === 0 ? borderWidth[3] : borderWidth[0])
76+
Number(number) + (i === 0 ? border.width[3] : border.width[0])
8177
).join(',')
8278
))
8379
setPath(generateSvgSquircle(height, width, radius))
84-
}, [height, width, radius, borderWidth])
80+
}, [height, width, radius, border.width])
8581

8682
useEffect(() => {
8783
// patch for webkit's svg bug
@@ -95,13 +91,14 @@ export default function RoundDiv({style, children, dontConvertShadow, ...props})
9591
svgRef.current.style.position = oldPosition
9692
}, 10)
9793
}, 0)
98-
}, [radius, borderWidth, borderColor, borderOpacity])
94+
}, [radius, border, borderImage])
9995

10096
const pathIsEmpty = (path.startsWith('Z') || path === '')
10197
const divStyle = {
10298
...style,
10399
...(pathIsEmpty ? {} : {
104-
borderColor: 'transparent',
100+
border: 'none',
101+
borderImage: 'none',
105102
background: 'transparent',
106103
boxShadow: dontConvertShadow
107104
// "box-shadow" must be overridden for the style extraction to work (with nth: 1, and not nth: 0)
@@ -118,10 +115,12 @@ export default function RoundDiv({style, children, dontConvertShadow, ...props})
118115
position: 'fixed',
119116
left: 0,
120117
top: 0,
121-
transform: `translate(-${padding[3] + borderWidth[3]}px, -${padding[0] + borderWidth[0]}px)`,
118+
transform: `translate(-${padding[3] + border.width[3]}px, -${padding[0] + border.width[0]}px)`,
122119
zIndex: -1,
123120
}
124121

122+
const widenedBorderWidth = border.width.map(v => v + Math.max(.5, v * .1))
123+
125124
return <div {...props} style={divStyle} ref={div}>
126125
{pathIsEmpty ? null : <ShadowRoot>
127126
<div style={{
@@ -138,34 +137,27 @@ export default function RoundDiv({style, children, dontConvertShadow, ...props})
138137
}))),
139138
transition,
140139
}}/>
141-
<svg viewBox={`0 0 ${width} ${height}`} style={{
140+
<div style={{
142141
...shapeComponentStyles,
143-
overflow: 'visible',
144-
}}
145-
preserveAspectRatio={'xMidYMid slice'} ref={svgRef}>
146-
<defs>
147-
<clipPath id="inner">
148-
<path d={`M0,0V${height}H${width}V0Z` + innerPath} fillRule={'evenodd'}/>
149-
</clipPath>
150-
<clipPath id="outer">
151-
<path d={path} fillRule={'evenodd'}/>
152-
</clipPath>
153-
</defs>
154-
<g clipPath={'url(#outer)'}>
155-
{Object.keys(maskPaths).map((key, i) => {
156-
if (borderColor[i] === borderColor[i - 1]) return ''
157-
158-
let path = maskPaths[key]
159-
while (borderColor[i] === borderColor[i + 1]) {
160-
path += maskPaths[Object.keys(maskPaths)[i + 1]]
161-
i++
162-
}
163-
164-
return <path d={path} clipPath={'url(#inner)'} key={key}
165-
fill={borderColor[i]} opacity={borderOpacity[i]}/>
166-
})}
167-
</g>
168-
</svg>
142+
clipPath: `path("${path}")`
143+
}}>
144+
<div style={{
145+
height: height - (widenedBorderWidth[0] + widenedBorderWidth[2]),
146+
width: width - (widenedBorderWidth[1] + widenedBorderWidth[3]),
147+
clipPath: `path("M0,0V${height}H${width}V0Z${innerPath}")`,
148+
borderRadius: radius.map(n => (n - 1) + 'px').join(' '),
149+
borderColor: border.color,
150+
borderWidth: widenedBorderWidth.map(v => v + 'px').join(' '),
151+
borderStyle: border.style,
152+
...(Object.fromEntries(Object.keys(borderImage).map(key => {
153+
return [
154+
camelise('border-image-' + key),
155+
borderImage[key] + (key === 'slice' ? ' fill' : '')
156+
]
157+
}))),
158+
transition,
159+
}}/>
160+
</div>
169161
<slot style={{overflow: 'visible'}}/>
170162
</div>
171163
</ShadowRoot>}

src/mask-generator.js

Lines changed: 0 additions & 70 deletions
This file was deleted.

src/styleSheetWatcher.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ function getCSSText(element) {
5454
} catch (e) {
5555
return
5656
}
57-
// console.log(rule.selectorText)
5857
CSS += rule.cssText
5958
})
6059
return CSS

0 commit comments

Comments
 (0)