Skip to content

Commit 252a4e0

Browse files
Merge pull request #4 from drinking-code/enable-ssr
Enable SSR
2 parents af7a09c + 1d37dfd commit 252a4e0

File tree

9 files changed

+120
-79
lines changed

9 files changed

+120
-79
lines changed

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.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-round-div",
3-
"version": "1.1.0",
3+
"version": "1.2.0",
44
"description": "Make your rounded corners look phenomenal with g2 continuity.",
55
"main": "dist/main.js",
66
"scripts": {

src/css-utils.js

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import CSS_COLOR_NAMES from "./external/bobspace:html-colors";
2-
import toPx from "./external/heygrady:units:length";
1+
import CSS_COLOR_NAMES from './external/bobspace:html-colors';
2+
3+
const toPx = typeof document !== 'undefined' && require('./external/heygrady:units:length').default;
34

45
/** @returns {string} */
56
function convertPlainColor(val) {
@@ -25,7 +26,7 @@ function convertPlainColor(val) {
2526
function convertColorOpacity(val) {
2627
if (val?.startsWith('rgba') || val?.startsWith('hsla')) {
2728
return Number(val.match(/(\d*\.?\d+)?\)$/)[1])
28-
} else return 1
29+
} else return 0
2930
}
3031

3132
const htmlLengthNotSvgErrorTemplate = (a, b) => `<RoundDiv> ${a} must be ${b ? `either ${b}, or` : ''} in one of the following units: ch, cm, em, ex, in, mm, pc, pt, px, rem, vh, vmax, vmin, vw.`
@@ -42,7 +43,12 @@ function toNumber(length, element, err) {
4243
if (err) throw err
4344
else return false
4445
else if (length?.match(/(\d+(\.\d+)?(ch|cm|em|ex|in|mm|pc|pt|px|rem|vh|vmax|vmin|vw)|0)/))
45-
return toPx(element, length)
46+
if (typeof toPx === 'function')
47+
return toPx(element, length)
48+
else if (length.endsWith('px'))
49+
return Number(length.substring(0, length.length - 2))
50+
else
51+
return false
4652
}
4753

4854
/** @returns {number} */

src/external/apearce:eact-shadow-dom.js renamed to src/external/apearce:react-shadow-dom.js

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,22 @@
33
* by apearce
44
*/
55

6-
import React from 'react';
6+
import React, {Fragment} from 'react';
77
import ReactDOM from 'react-dom';
88
import PropTypes from 'prop-types';
99

10-
const constructableStylesheetsSupported = window
10+
const constructableStylesheetsSupported = typeof window !== 'undefined' && window
1111
&& window.ShadowRoot
1212
&& window.ShadowRoot.prototype.hasOwnProperty('adoptedStyleSheets')
1313
&& window.CSSStyleSheet
1414
&& window.CSSStyleSheet.prototype.hasOwnProperty('replace');
1515

16-
const shadowRootSupported = window
16+
const shadowRootSupported = typeof window !== 'undefined' && window
1717
&& window.Element
1818
&& window.Element.prototype.hasOwnProperty('attachShadow');
1919

2020
export default class ShadowRoot extends React.PureComponent {
2121
static constructableStylesheetsSupported = constructableStylesheetsSupported;
22-
static constructibleStylesheetsSupported = constructableStylesheetsSupported;
2322
static defaultProps = {
2423
delegatesFocus: false,
2524
mode: 'open'
@@ -68,7 +67,7 @@ export default class ShadowRoot extends React.PureComponent {
6867

6968
render() {
7069
if (!this.state.initialized) {
71-
return <span ref={this.placeholder}></span>;
70+
return <span ref={this.placeholder}/>;
7271
}
7372

7473
return ReactDOM.createPortal(this.props.children, this.shadowRoot);

src/external/getMatchedCSSRules-polyfill.js

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
/* eslint-disable */
22
// polyfill element.matches
3-
if (!Element.prototype.matches) {
3+
if (typeof Element !== 'undefined' && !Element.prototype.matches) {
44
Element.prototype.matches =
55
Element.prototype.matchesSelector ||
66
Element.prototype.mozMatchesSelector ||
77
Element.prototype.msMatchesSelector ||
88
Element.prototype.oMatchesSelector ||
99
Element.prototype.webkitMatchesSelector ||
10-
function(s) {
10+
function (s) {
1111
var matches = (this.document || this.ownerDocument).querySelectorAll(s),
1212
i = matches.length;
1313
while (--i >= 0 && matches.item(i) !== this) {}
@@ -16,42 +16,43 @@ if (!Element.prototype.matches) {
1616
}
1717

1818
// polyfill window.getMatchedCSSRules() in FireFox 6+
19-
if ( typeof window.getMatchedCSSRules !== 'function' ) {
19+
if (typeof window !== 'undefined' && typeof window.getMatchedCSSRules !== 'function') {
2020
var ELEMENT_RE = /[\w-]+/g,
2121
ID_RE = /#[\w-]+/g,
2222
CLASS_RE = /\.[\w-]+/g,
2323
ATTR_RE = /\[[^\]]+\]/g,
2424
// :not() pseudo-class does not add to specificity, but its content does as if it was outside it
2525
PSEUDO_CLASSES_RE = /\:(?!not)[\w-]+(\(.*\))?/g,
2626
PSEUDO_ELEMENTS_RE = /\:\:?(after|before|first-letter|first-line|selection)/g;
27+
2728
// convert an array-like object to array
28-
function toArray (list) {
29+
function toArray(list) {
2930
return [].slice.call(list);
3031
}
3132

3233
// handles extraction of `cssRules` as an `Array` from a stylesheet or something that behaves the same
33-
function getSheetRules (stylesheet) {
34+
function getSheetRules(stylesheet) {
3435
var sheet_media = stylesheet.media && stylesheet.media.mediaText;
3536
// if this sheet is disabled skip it
36-
if ( stylesheet.disabled ) return [];
37+
if (stylesheet.disabled) return [];
3738
// if this sheet's media is specified and doesn't match the viewport then skip it
38-
if ( sheet_media && sheet_media.length && ! window.matchMedia(sheet_media).matches ) return [];
39+
if (sheet_media && sheet_media.length && !window.matchMedia(sheet_media).matches) return [];
3940
// get the style rules of this sheet
4041
return toArray(stylesheet.cssRules);
4142
}
4243

43-
function _find (string, re) {
44+
function _find(string, re) {
4445
var matches = string.match(re);
4546
return re ? re.length : 0;
4647
}
4748

4849
// calculates the specificity of a given `selector`
49-
function calculateScore (selector) {
50-
var score = [0,0,0],
50+
function calculateScore(selector) {
51+
var score = [0, 0, 0],
5152
parts = selector.split(' '),
5253
part, match;
5354
//TODO: clean the ':not' part since the last ELEMENT_RE will pick it up
54-
while ( part = parts.shift(), typeof part == 'string' ) {
55+
while (part = parts.shift(), typeof part == 'string') {
5556
// find all pseudo-elements
5657
match = _find(part, PSEUDO_ELEMENTS_RE);
5758
score[2] = match;
@@ -84,21 +85,21 @@ if ( typeof window.getMatchedCSSRules !== 'function' ) {
8485
}
8586

8687
// returns the heights possible specificity score an element can get from a give rule's selectorText
87-
function getSpecificityScore (element, selector_text) {
88+
function getSpecificityScore(element, selector_text) {
8889
var selectors = selector_text.split(','),
8990
selector, score, result = 0;
90-
while ( selector = selectors.shift() ) {
91-
if ( element.matches(selector) ) {
91+
while (selector = selectors.shift()) {
92+
if (element.matches(selector)) {
9293
score = calculateScore(selector);
9394
result = score > result ? score : result;
9495
}
9596
}
9697
return result;
9798
}
9899

99-
function sortBySpecificity (element, rules) {
100+
function sortBySpecificity(element, rules) {
100101
// comparing function that sorts CSSStyleRules according to specificity of their `selectorText`
101-
function compareSpecificity (a, b) {
102+
function compareSpecificity(a, b) {
102103
return getSpecificityScore(element, b.selectorText) - getSpecificityScore(element, a.selectorText);
103104
}
104105

@@ -116,28 +117,28 @@ if ( typeof window.getMatchedCSSRules !== 'function' ) {
116117

117118
// assuming the browser hands us stylesheets in order of appearance
118119
// we iterate them from the beginning to follow proper cascade order
119-
while ( sheet = style_sheets.shift() ) {
120+
while (sheet = style_sheets.shift()) {
120121
// get the style rules of this sheet
121122
rules = getSheetRules(sheet);
122123
// loop the rules in order of appearance
123-
while ( rule = rules.shift() ) {
124+
while (rule = rules.shift()) {
124125
// if this is an @import rule
125-
if ( rule.styleSheet ) {
126+
if (rule.styleSheet) {
126127
// insert the imported stylesheet's rules at the beginning of this stylesheet's rules
127128
rules = getSheetRules(rule.styleSheet).concat(rules);
128129
// and skip this rule
129130
continue;
130131
}
131132
// if there's no stylesheet attribute BUT there IS a media attribute it's a media rule
132-
else if ( rule.media ) {
133+
else if (rule.media) {
133134
// insert the contained rules of this media rule to the beginning of this stylesheet's rules
134135
rules = getSheetRules(rule).concat(rules);
135136
// and skip it
136137
continue
137138
}
138139
//TODO: for now only polyfilling Gecko
139140
// check if this element matches this rule's selector
140-
if ( element.matches(rule.selectorText) ) {
141+
if (element.matches(rule.selectorText)) {
141142
// push the rule to the results set
142143
result.push(rule);
143144
}

src/generator.js

Lines changed: 48 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -51,61 +51,81 @@ export default function generateSvgSquircle(height, width, radius) {
5151
a0xw = a0xF(width),
5252
a0xh = a0xF(height)
5353

54-
/*function mapRange(number, in_min, in_max, out_min, out_max) {
55-
return (number - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
56-
}*/
54+
function mapRange(number, inMin, inMax, outMin, outMax) {
55+
return (number - inMin) * (outMax - outMin) / (inMax - inMin) + outMin;
56+
}
5757

58-
// const maxRadius = Math.max(...radius);
58+
function clip(number, min, max) {
59+
return Math.max(min, Math.min(number, max))
60+
}
5961

60-
const yOffsetF = (x) => 0,
61-
hyOffset = yOffsetF(height) || 0,
62-
wyOffset = yOffsetF(width) || 0
62+
const yOffsetF = (r1, r2, l) => {
63+
if (r1 + r2 < l)
64+
return 0
65+
else {
66+
const maximumStraightLengthRatio = 1 / 6
67+
const straightLength = l - (r1 + r2)
68+
const straightLengthRatio = straightLength / l
69+
const clippedStraightLengthRatio = clip(straightLengthRatio, 0, maximumStraightLengthRatio)
70+
const reversedClippedStraightLengthRatio = mapRange(clippedStraightLengthRatio, 0, maximumStraightLengthRatio, maximumStraightLengthRatio, 0)
71+
return reversedClippedStraightLengthRatio * l / 14
72+
}
73+
}
74+
const topYOffset = yOffsetF(radius[1], radius[2], width) || 0
75+
const rightYOffset = yOffsetF(radius[2], radius[3], height) || 0
76+
const bottomYOffset = yOffsetF(radius[3], radius[0], width) || 0
77+
const leftYOffset = yOffsetF(radius[0], radius[1], height) || 0
6378

64-
const startPoint = `${a0xw},${wyOffset}`
79+
const startPoint = `${a0xw},${topYOffset}`
6580

66-
return `M${startPoint}
67-
${width / 2 < a0x[1]
81+
const path = `M${startPoint}
82+
${width / 2 < a0x[2]
6883
? ''
6984
: `L${width - a0xw},0`
7085
}
7186
72-
C${width - a1x[1]},0,${width - a2x[1]},0,${width - a3x[1]},${a3y[1]}
73-
C${width - b1x[1]},${b1y[1]},${width - b1y[1]},${b1x[1]},${width - b0y[1]},${b0x[1]}
74-
C${width},${a2x[1]},${width},${a1x[1]},
87+
C${width - a1x[2]},0,${width - a2x[2]},0,${width - a3x[2]},${a3y[2]}
88+
C${width - b1x[2]},${b1y[2]},${width - b1y[2]},${b1x[2]},${width - b0y[2]},${b0x[2]}
89+
C${width},${a2x[2]},${width},${a1x[2]},
7590
76-
${width - hyOffset},${a0xh}
77-
${height / 2 < a0x[2]
91+
${width - rightYOffset},${a0xh}
92+
${height / 2 < a0x[3]
7893
? ''
7994
: `L${width},${height - a0xh}`
8095
}
8196
82-
C${width},${height - a1x[2]},${width},${height - a2x[2]},${width - a3y[2]},${height - a3x[2]}
83-
C${width - b1y[2]},${height - b1x[2]},${width - b1x[2]},${height - b1y[2]},${width - b0x[2]},${height - b0y[2]}
84-
C${width - a2x[2]},${height},${width - a1x[2]},${height},
97+
C${width},${height - a1x[3]},${width},${height - a2x[3]},${width - a3y[3]},${height - a3x[3]}
98+
C${width - b1y[3]},${height - b1x[3]},${width - b1x[3]},${height - b1y[3]},${width - b0x[3]},${height - b0y[3]}
99+
C${width - a2x[3]},${height},${width - a1x[3]},${height},
85100
86-
${width - a0xw},${height - wyOffset}
87-
${width / 2 < a0x[3]
101+
${width - a0xw},${height - bottomYOffset}
102+
${width / 2 < a0x[0]
88103
? ''
89104
: `L${a0xw},${height}`
90105
}
91106
92-
C${a1x[3]},${height},${a2x[3]},${height},${a3x[3]},${height - a3y[3]}
93-
C${b1x[3]},${height - b1y[3]},${b1y[3]},${height - b1x[3]},${b0y[3]},${height - b0x[3]}
94-
C0,${height - a2x[3]},0,${height - a1x[3]},
107+
C${a1x[0]},${height},${a2x[0]},${height},${a3x[0]},${height - a3y[0]}
108+
C${b1x[0]},${height - b1y[0]},${b1y[0]},${height - b1x[0]},${b0y[0]},${height - b0x[0]}
109+
C0,${height - a2x[0]},0,${height - a1x[0]},
95110
96-
${hyOffset},${height - a0xh}
97-
${height / 2 < a0x[0]
111+
${leftYOffset},${height - a0xh}
112+
${height / 2 < a0x[1]
98113
? ''
99114
: `L0,${a0xh}`
100115
}
101116
102-
C0,${a1x[0]},0,${a2x[0]},${a3y[0]},${a3x[0]}
103-
C${b1y[0]},${b1x[0]},${b1x[0]},${b1y[0]},${b0x[0]},${b0y[0]}
104-
C${a2x[0]},0,${a1x[0]},0,${startPoint}
117+
C0,${a1x[1]},0,${a2x[1]},${a3y[1]},${a3x[1]}
118+
C${b1y[1]},${b1x[1]},${b1x[1]},${b1y[1]},${b0x[1]},${b0y[1]}
119+
C${a2x[1]},0,${a1x[1]},0,${startPoint}
105120
Z`
106121
.replace(/[\n ]/g, '')
107122
.replace(/NaN/g, '0')
108123
.replace(/\d+\.\d+/g, match =>
109124
Math.round(Number(match) * (10 ** roundToNthPlace)) / (10 ** roundToNthPlace)
110125
)
126+
127+
if (path.match(/[^ M0LCZ,]/) === null)
128+
return ''
129+
130+
return path
111131
}

src/main.js

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React, {useRef, useEffect, useState, useCallback} from 'react'
22
import generateSvgSquircle from './generator'
33
import './external/getMatchedCSSRules-polyfill'
44
import updateStates from "./updateStates"
5-
import ShadowRoot from "./external/apearce:eact-shadow-dom"
5+
import ShadowRoot from "./external/apearce:react-shadow-dom"
66
import attachCSSWatcher from './styleSheetWatcher'
77
import getMaskPaths from './mask-generator'
88

@@ -14,7 +14,7 @@ export default function RoundDiv({style, children, ...props}) {
1414
const [radius, setRadius] = useState(Array(4).fill(0))
1515

1616
const [borderColor, setBorderColor] = useState(Array(4).fill('transparent'))
17-
const [borderOpacity, setBorderOpacity] = useState(Array(4).fill(1))
17+
const [borderOpacity, setBorderOpacity] = useState(Array(4).fill(0))
1818
const [borderWidth, setBorderWidth] = useState(Array(4).fill(0))
1919

2020
const [path, setPath] = useState('Z')
@@ -23,17 +23,19 @@ export default function RoundDiv({style, children, ...props}) {
2323

2424
const div = useRef()
2525

26-
const updateStatesWithArgs = useCallback(() => updateStates({
27-
div,
28-
style,
29-
setPosition,
30-
setHeight,
31-
setWidth,
32-
setRadius,
33-
setBorderColor,
34-
setBorderWidth,
35-
setBorderOpacity
36-
}), [style])
26+
const updateStatesWithArgs = useCallback(() => {
27+
updateStates({
28+
div,
29+
style,
30+
setPosition,
31+
setHeight,
32+
setWidth,
33+
setRadius,
34+
setBorderColor,
35+
setBorderWidth,
36+
setBorderOpacity
37+
})
38+
}, [style])
3739

3840
useEffect(updateStatesWithArgs, [style, updateStatesWithArgs])
3941

@@ -81,8 +83,9 @@ export default function RoundDiv({style, children, ...props}) {
8183

8284
const divStyle = {
8385
...style,
84-
clipPath: `path("${path}")`,
85-
borderColor: 'transparent'
86+
clipPath: (path.startsWith('Z') || path === '') ? '' : `path("${path}")`,
87+
borderColor: 'transparent',
88+
borderRadius: 0,
8689
}
8790

8891
return <div {...props} style={divStyle} ref={div}>

0 commit comments

Comments
 (0)