Skip to content

Commit 8ba7f96

Browse files
committed
fix(src/hooks/svg-filters) Fix tests from f9f306f
1 parent f9f306f commit 8ba7f96

1 file changed

Lines changed: 40 additions & 19 deletions

File tree

src/components/svg-filters.js

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ import PropTypes from 'prop-types'
33
import React from 'react'
44

55
const NumberOrString = PropTypes.oneOfType([PropTypes.string, PropTypes.number])
6+
const Percentage = (props, propName, componentName) => {
7+
if (props[propName] && !props[propName].endsWith('%')) {
8+
return new Error(`Invalid prop ${propName} supplied to ${componentName}. Validation failed.`)
9+
}
10+
}
611

712
/**
813
* ColorCorrection :: Props -> React.Element
@@ -35,7 +40,7 @@ const Glow = props =>
3540
<feMorphology in={props.in} operator='dilate' radius={props.spread} />
3641
<feGaussianBlur stdDeviation={props.blur} />
3742
<ColorCorrection lightness={props.lightness} opacity={props.opacity} />
38-
<feBlend in='SourceGraphic' mode='screen' result={props.result} />
43+
<feBlend in={props.in ?? 'SourceGraphic'} mode='screen' result={props.result} />
3944
</>
4045

4146
Glow.propTypes = {
@@ -58,7 +63,7 @@ const GlowInset = props =>
5863
<feMorphology in={props.in} operator='erode' radius={props.threshold} />
5964
<feGaussianBlur stdDeviation={props.blur} result='blur' />
6065
<ColorCorrection lightness={props.lightness} opacity={props.opacity} />
61-
<feBlend in='SourceGraphic' mode='screen' result={props.result} />
66+
<feBlend in={props.in ?? 'SourceGraphic'} mode='screen' result={props.result} />
6267
</>
6368

6469
GlowInset.propTypes = {
@@ -101,8 +106,8 @@ const Noise = ({ blend = 'multiply', color = 'black', ...props }) =>
101106
<feFlood floodColor={color} />
102107
<ColorCorrection lightness={props.lightness} opacity={props.opacity} />
103108
<feComposite in2='noise' operator='in' />
104-
<feComposite in={props.in} operator='in' />
105-
<feBlend in={props.in} mode={blend} result={props.result} />
109+
<feComposite in2={props.in ?? 'SourceGraphic'} operator='in' />
110+
<feBlend in={props.in ?? 'SourceGraphic'} mode={blend} result={props.result} />
106111
</>
107112

108113
Noise.propTypes = {
@@ -137,7 +142,7 @@ const Shadow = ({ offsetX = 0, offsetY = 0, ...props }) =>
137142
<feComposite in2='blur' operator='in' />
138143
<ColorCorrection opacity={props.opacity} />
139144
<feOffset dx={offsetX} dy={offsetY} />
140-
<feComposite in={props.in} result={props.result} />
145+
<feComposite in={props.in ?? 'SourceGraphic'} result={props.result} />
141146
</>
142147

143148
Shadow.propTypes = {
@@ -162,9 +167,9 @@ const ShadowInset = ({ offsetX = 0, offsetY = 0, ...props }) =>
162167
<feMorphology in={props.in} operator='dilate' radius={props.threshold} />
163168
<feGaussianBlur stdDeviation={props.blur} />
164169
<feOffset dx={offsetX} dy={offsetY} />
165-
<feComposite in='SourceGraphic' operator='out' />
166-
<ColorCorrection lightness={props.lightness} opacity={props.opacity} />
167-
<feBlend in='SourceGraphic' mode='multiply' result={props.result} />
170+
<feComposite in={props.in ?? 'SourceGraphic'} operator='out' />
171+
<ColorCorrection opacity={props.opacity} />
172+
<feBlend in={props.in ?? 'SourceGraphic'} mode='multiply' result={props.result} />
168173
</>
169174

170175
ShadowInset.propTypes = {
@@ -190,35 +195,51 @@ const primitives = {
190195
'shadow-inset': ShadowInset,
191196
}
192197

198+
const baseArea = { height: '100%', width: '100%', x: '0%', y: '0%' }
199+
const largeArea = { height: '300%', width: '300%', x: '-100%', y: '-100%' }
200+
193201
/**
194202
* Filter :: Props -> React.Element
195203
*
196204
* Props => { name: String, [SVGFeAttribute]: SVGFeAttributeValue }
197205
*
198206
* It should not wrap the filter primitive inside a `<filter>` container if a
199207
* previous `in` or a following `result` filter primitive id is given as prop.
200-
*
201-
* Memo: the first primitive doesn't require a `in` prop, as it will default to
202-
* `SourceGraphic` natively.
203208
*/
204-
const Filter = ({ name, id = name, ...props }) => {
205-
206-
if (props.in || props.result) {
209+
const Filter = ({ height: h, name, id = name, x: offsetX, y: offsetY, width: w, ...props }) => {
210+
211+
const { height, x, y, width } = React.useMemo(
212+
() => {
213+
if ((w ?? h) && (offsetX ?? offsetY)) {
214+
return {
215+
height: h,
216+
width: w,
217+
x: w ? `-${(w.slice(0, -1) - 100) / 2}%` : '0%',
218+
y: h ? `-${(h.slice(0, -1) - 100) / 2}%` : '0%',
219+
}
220+
} else if (name.endsWith('-inset')) {
221+
return baseArea
222+
}
223+
return largeArea
224+
},
225+
[h, name, offsetX, offsetY, w])
226+
227+
if (props.in ?? props.result) {
207228
return primitives[name](props)
208229
}
209230

210-
const { height, width, x, y } = id === 'glow'
211-
? { height: '300%', width: '300%', x: '-100%', y: '-100%' }
212-
: { height: '200%', width: '200%', x: '-50%', y: '-50%' }
213-
214-
return <filter id={id} x={x} y={y} width={width} height={height}>{primitives[name](props)}</filter>
231+
return <filter id={id} width={width} height={height} x={offsetX ?? x} y={offsetY ?? y}>{primitives[name](props)}</filter>
215232
}
216233

217234
Filter.propTypes = {
235+
height: Percentage,
218236
id: PropTypes.string,
219237
in: PropTypes.string,
220238
name: PropTypes.oneOf(Object.keys(primitives)),
221239
result: PropTypes.string,
240+
width: Percentage,
241+
x: Percentage,
242+
y: Percentage,
222243
}
223244

224245
export default Filter

0 commit comments

Comments
 (0)