Skip to content

Commit 9728aa6

Browse files
committed
feat!: change sides&corners types to object
1 parent ea11389 commit 9728aa6

6 files changed

Lines changed: 90 additions & 68 deletions

File tree

CHANGELOG.md

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,19 @@
77
* `containerViewProps` property.
88
* `childrenViewProps` property.
99

10-
### Renamed
11-
* `viewStyle` to `style`.
12-
* `containerViewStyle` to `containerStyle`.
13-
* `finalColor` to `endColor`, to follow the `start/end` pattern of the RTL changes below.
14-
##### [RTL Related](https://reactnative.dev/blog/2016/08/19/right-to-left-support-for-react-native-apps)
15-
> Based on https://necolas.github.io/react-native-web/docs/styling/#non-standard-properties.
16-
* `sides` type: `('left' | 'right' | 'top' | 'bottom')[]` to `('start' | 'end' | 'top' | 'bottom')[]`.
17-
* `corners` type: `('topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight')[]` to `('topStart' | 'topEnd' | 'bottomStart' | 'bottomEnd')[]`.
10+
### Changes
11+
* Renamed `viewStyle` to `style`.
12+
* Renamed `containerViewStyle` to `containerStyle`.
13+
* Renamed `finalColor` to `endColor`, to follow the `start/end` pattern of the following change.
14+
* `left`/`right` in `sides` and `corners` were changed to `start`/`end` for [RTL friendliness](https://reactnative.dev/blog/2016/08/19/right-to-left-support-for-react-native-apps)
15+
* `sides` and `corners` properties are now objects instead of arrays.
16+
> `sides` new type: `Record<'start' | 'end' | 'top' | 'bottom', boolean>`
17+
18+
> `corners` new type: `Record<'topStart' | 'topEnd' | 'bottomStart' | 'bottomEnd', boolean>`.
1819
1920
> Note that you may still use `borderTopLeftRadius` etc in `style` besides `borderTopStartRadius` if you want to.
2021
21-
### Removed
22+
### Removals
2223
<ul>
2324
<li><code>size</code> property. The size now can only be defined in the Shadow's or child's <code>style</code>'s <code>width</code> and <code>height</code> properties.</li>
2425
<li><code>radius</code> property. The radii now can only be defined in the Shadow's or child's <code>style</code>'s <code>borderRadius</code> related properties, such as <code>borderTopStartRadius</code>/<code>borderTopLeftRadius</code> etc.</li>
@@ -30,16 +31,17 @@ Properties removed for the sake of simplicity of this package. Probably no one u
3031
</li>
3132
</ul>
3233

33-
### Improved
34-
* Significant performance and RAM usage due to some general refactorings, simplified the SVGs' code (with the same appearence) and improved memoizations.
34+
### Improvements
35+
* Significant performance and RAM usage due to general refactorings, SVGs' simplification (with the same appearence), improved memoizations and micro performance improvements.
3536
* Now using `colord` package instead of `polished` to deal with colors' alpha.
3637

37-
### Fixed
38+
### Fixes
3839
* [RTL in web](https://github.com/necolas/react-native-web/issues/2350#issuecomment-1193642853).
3940
* Error when there is more than a child. [#38](https://github.com/SrBrahma/react-native-shadow-2/issues/38)
4041
* Error when there isn't a child. [#38 (comment)](https://github.com/SrBrahma/react-native-shadow-2/issues/38#issuecomment-1059716569)
4142
* Situational 1-pixel overlap of corners.
42-
<hr/>
43+
44+
<br/><hr/><br/>
4345

4446
## 6.0.3 - 2022-02-11
4547
* Fixed paintInside gaps on iOS. [#36](https://github.com/SrBrahma/react-native-shadow-2/issues/36). Thanks, [@walterholohan](https://github.com/walterholohan)!

sandbox/src/App.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const defaults = {
1515
borderRadius: 30,
1616
width: 200,
1717
height: 200,
18-
startColor: tinycolor('#00000090').toHex8String(),
18+
startColor: tinycolor('#00000020').toHex8String(),
1919
finalColor: tinycolor('#0000').toHex8String(),
2020
childColor: tinycolor('#fff').toHex8String(), // tinycolor('#fff').toHex8String(),
2121
};

sandbox/src/src/index.tsx

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { colord } from 'colord';
77
import type { Corner, CornerRadius, CornerRadiusShadow, RadialGradientPropsOmited, Side } from './utils';
88
import {
99
additional, cornersArray, divDps, generateGradientIdSuffix, objFromKeys,
10-
P, R, radialGradient, rtlScaleX, scale, sidesArray, sumDps,
10+
P, R, radialGradient, rtlScaleX, scale, sumDps,
1111
} from './utils';
1212

1313

@@ -28,13 +28,17 @@ export interface ShadowProps {
2828
distance?: number;
2929
/** The sides that have the shadows drawn. Doesn't include corners.
3030
*
31-
* @default ['start', 'end', 'top', 'bottom'] */
31+
* Undefined sides fallbacks to true.
32+
*
33+
* @default undefined */
3234
// We are using the raw type here instead of Side/Corner so TypeDoc/Readme output is better for the users, won't be just `Side`.
33-
sides?: ('start' | 'end' | 'top' | 'bottom')[];
35+
sides?: Record<'start' | 'end' | 'top' | 'bottom', boolean>;
3436
/** The corners that have the shadows drawn.
3537
*
36-
* @default ['topStart', 'topEnd', 'bottomStart', 'bottomEnd'] */
37-
corners?: ('topStart' | 'topEnd' | 'bottomStart' | 'bottomEnd')[];
38+
* Undefined corners fallbacks to true.
39+
*
40+
* @default undefined */
41+
corners?: Record<'topStart' | 'topEnd' | 'bottomStart' | 'bottomEnd', boolean>;
3842
/** Moves the shadow. Negative x moves it to the left, negative y moves it up.
3943
*
4044
* Accepts `'x%'` values, in relation to the child's size.
@@ -94,7 +98,6 @@ export interface ShadowProps {
9498

9599
// For better memoization and performance.
96100
const emptyObj: Record<string, unknown> = {};
97-
const emptyArray: any[] = [];
98101
const defaultOffset = [0, 0] as [x: number | string, y: number | string];
99102

100103
export function Shadow(props: ShadowProps): JSX.Element {
@@ -129,28 +132,16 @@ function ShadowInner(props: ShadowProps): JSX.Element {
129132
containerViewProps,
130133
} = props;
131134

132-
/** Which sides will have shadow. */
133-
const activeSides: Record<Side, boolean> = useMemo(() => objFromKeys(sidesArray, (k) => sides?.includes(k) ?? true),
134-
// eslint-disable-next-line react-hooks/exhaustive-deps
135-
(sides ?? emptyArray).slice(4),
136-
);
137-
138-
/** Which corners will have shadow. */
139-
const activeCorners: Record<Corner, boolean> = useMemo(() => objFromKeys(cornersArray, (k) => corners?.includes(k) ?? true),
140-
// eslint-disable-next-line react-hooks/exhaustive-deps
141-
(corners ?? emptyArray).slice(4),
142-
);
143-
144135
/** `s` is a shortcut for `style` I am using in another lib of mine (react-native-gev). While currently no one uses it besides me,
145136
* I believe it may come to be a popular pattern eventually :) */
146137
const childProps: {style?: ViewStyle; s?: ViewStyle} = (Children.count(children) === 1) ? (Children.only(children) as JSX.Element).props ?? emptyObj : emptyObj;
147138

148-
const childStyleStr = useMemo(() => (childProps.style ? JSON.stringify(childProps.style) : '{}'), [childProps.style]);
149-
const childSStr = useMemo(() => (childProps.s ? JSON.stringify(childProps.s) : '{}'), [childProps.s]);
139+
const childStyleStr: string | null = useMemo(() => (childProps.style ? JSON.stringify(childProps.style) : null), [childProps.style]);
140+
const childSStr: string | null = useMemo(() => (childProps.s ? JSON.stringify(childProps.s) : null), [childProps.s]);
150141

151142
/** Child's style. */
152143
const cStyle: ViewStyle = useMemo(() => {
153-
const cStyle = StyleSheet.flatten<ViewStyle>([JSON.parse(childStyleStr), JSON.parse(childSStr)]);
144+
const cStyle = StyleSheet.flatten<ViewStyle>([childStyleStr && JSON.parse(childStyleStr), childSStr && JSON.parse(childSStr)]);
154145
if (typeof cStyle.width === 'number')
155146
cStyle.width = R(cStyle.width);
156147
if (typeof cStyle.height === 'number')
@@ -168,11 +159,11 @@ function ShadowInner(props: ShadowProps): JSX.Element {
168159
};
169160
}, [cStyle]);
170161

171-
const styleStr: string = useMemo(() => (styleProp ? JSON.stringify(styleProp) : '{}'), [styleProp]);
162+
const styleStr: string | null = useMemo(() => (styleProp ? JSON.stringify(styleProp) : null), [styleProp]);
172163

173164
/** Flattened style. */
174165
const { style, sRadii }: { style: ViewStyle; sRadii: Record<Corner, number | undefined> } = useMemo(() => {
175-
const style = StyleSheet.flatten<ViewStyle>(JSON.parse(styleStr));
166+
const style = StyleSheet.flatten<ViewStyle>(styleStr && JSON.parse(styleStr));
176167
if (typeof style.width === 'number')
177168
style.width = R(style.width);
178169
if (typeof style.height === 'number')
@@ -211,8 +202,28 @@ function ShadowInner(props: ShadowProps): JSX.Element {
211202
const shadow = useMemo(() => getShadow({
212203
topStart, topEnd, bottomStart, bottomEnd, width, height,
213204
isRTL, distanceProp, startColorProp, endColorProp, paintInside,
214-
safeRender, activeSides, activeCorners, idSuffix,
215-
}), [topStart, topEnd, bottomStart, bottomEnd, width, height, isRTL, distanceProp, startColorProp, endColorProp, paintInside, safeRender, activeSides, activeCorners, idSuffix]);
205+
safeRender,
206+
activeSides: {
207+
bottom: sides?.bottom ?? true,
208+
top: sides?.top ?? true,
209+
start: sides?.start ?? true,
210+
end: sides?.end ?? true,
211+
}, activeCorners: {
212+
topStart: corners?.topStart ?? true,
213+
topEnd: corners?.topEnd ?? true,
214+
bottomStart: corners?.bottomStart ?? true,
215+
bottomEnd: corners?.bottomEnd ?? true,
216+
},
217+
idSuffix,
218+
}), [
219+
width, height, distanceProp,
220+
startColorProp, endColorProp,
221+
topStart, topEnd, bottomStart, bottomEnd,
222+
paintInside,
223+
sides?.bottom, sides?.top, sides?.start, sides?.end,
224+
corners?.topStart, corners?.topEnd, corners?.bottomStart, corners?.bottomEnd,
225+
safeRender, isRTL, idSuffix,
226+
]);
216227

217228
// Not yet sure if we should memo this.
218229
return getResult({
@@ -429,7 +440,7 @@ function getShadow({
429440
<Mask id={`maskInside.${idSuffix}`}>
430441
{/* Paint all white, then black on border external areas to erase them */}
431442
<Rect width={width} height={height} fill='#fff'/>
432-
{/* Remove the corners, as squares. Could use <Path/>, but this way seems to be more maintainable. */}
443+
{/* Remove the corners */}
433444
<Rect width={topStart} height={topStart} fill='#000'/>
434445
<Rect width={topEnd} height={topEnd} x={width} transform={`translate(${-topEnd}, 0)`} fill='#000'/>
435446
<Rect width={bottomStart} height={bottomStart} y={height} transform={`translate(0, ${-bottomStart})`} fill='#000'/>

sandbox/src/src/utils.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ export type CornerRadiusShadow = Record<`${Corner}Shadow`, number>;
1414
* and somehow may be useful to you. */
1515
export const version = '7.0.0';
1616

17-
export const sidesArray = ['start', 'end', 'top', 'bottom'] as const;
1817
export const cornersArray = ['topStart', 'topEnd', 'bottomStart', 'bottomEnd'] as const;
1918

2019
const isWeb = Platform.OS === 'web';

src/index.tsx

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { colord } from 'colord';
77
import type { Corner, CornerRadius, CornerRadiusShadow, RadialGradientPropsOmited, Side } from './utils';
88
import {
99
additional, cornersArray, divDps, generateGradientIdSuffix, objFromKeys,
10-
P, R, radialGradient, rtlScaleX, scale, sidesArray, sumDps,
10+
P, R, radialGradient, rtlScaleX, scale, sumDps,
1111
} from './utils';
1212

1313

@@ -28,13 +28,17 @@ export interface ShadowProps {
2828
distance?: number;
2929
/** The sides that have the shadows drawn. Doesn't include corners.
3030
*
31-
* @default ['start', 'end', 'top', 'bottom'] */
31+
* Undefined sides fallbacks to true.
32+
*
33+
* @default undefined */
3234
// We are using the raw type here instead of Side/Corner so TypeDoc/Readme output is better for the users, won't be just `Side`.
33-
sides?: ('start' | 'end' | 'top' | 'bottom')[];
35+
sides?: Record<'start' | 'end' | 'top' | 'bottom', boolean>;
3436
/** The corners that have the shadows drawn.
3537
*
36-
* @default ['topStart', 'topEnd', 'bottomStart', 'bottomEnd'] */
37-
corners?: ('topStart' | 'topEnd' | 'bottomStart' | 'bottomEnd')[];
38+
* Undefined corners fallbacks to true.
39+
*
40+
* @default undefined */
41+
corners?: Record<'topStart' | 'topEnd' | 'bottomStart' | 'bottomEnd', boolean>;
3842
/** Moves the shadow. Negative x moves it to the left, negative y moves it up.
3943
*
4044
* Accepts `'x%'` values, in relation to the child's size.
@@ -94,7 +98,6 @@ export interface ShadowProps {
9498

9599
// For better memoization and performance.
96100
const emptyObj: Record<string, unknown> = {};
97-
const emptyArray: any[] = [];
98101
const defaultOffset = [0, 0] as [x: number | string, y: number | string];
99102

100103
export function Shadow(props: ShadowProps): JSX.Element {
@@ -129,28 +132,16 @@ function ShadowInner(props: ShadowProps): JSX.Element {
129132
containerViewProps,
130133
} = props;
131134

132-
/** Which sides will have shadow. */
133-
const activeSides: Record<Side, boolean> = useMemo(() => objFromKeys(sidesArray, (k) => sides?.includes(k) ?? true),
134-
// eslint-disable-next-line react-hooks/exhaustive-deps
135-
(sides ?? emptyArray).slice(4),
136-
);
137-
138-
/** Which corners will have shadow. */
139-
const activeCorners: Record<Corner, boolean> = useMemo(() => objFromKeys(cornersArray, (k) => corners?.includes(k) ?? true),
140-
// eslint-disable-next-line react-hooks/exhaustive-deps
141-
(corners ?? emptyArray).slice(4),
142-
);
143-
144135
/** `s` is a shortcut for `style` I am using in another lib of mine (react-native-gev). While currently no one uses it besides me,
145136
* I believe it may come to be a popular pattern eventually :) */
146137
const childProps: {style?: ViewStyle; s?: ViewStyle} = (Children.count(children) === 1) ? (Children.only(children) as JSX.Element).props ?? emptyObj : emptyObj;
147138

148-
const childStyleStr = useMemo(() => (childProps.style ? JSON.stringify(childProps.style) : '{}'), [childProps.style]);
149-
const childSStr = useMemo(() => (childProps.s ? JSON.stringify(childProps.s) : '{}'), [childProps.s]);
139+
const childStyleStr: string | null = useMemo(() => (childProps.style ? JSON.stringify(childProps.style) : null), [childProps.style]);
140+
const childSStr: string | null = useMemo(() => (childProps.s ? JSON.stringify(childProps.s) : null), [childProps.s]);
150141

151142
/** Child's style. */
152143
const cStyle: ViewStyle = useMemo(() => {
153-
const cStyle = StyleSheet.flatten<ViewStyle>([JSON.parse(childStyleStr), JSON.parse(childSStr)]);
144+
const cStyle = StyleSheet.flatten<ViewStyle>([childStyleStr && JSON.parse(childStyleStr), childSStr && JSON.parse(childSStr)]);
154145
if (typeof cStyle.width === 'number')
155146
cStyle.width = R(cStyle.width);
156147
if (typeof cStyle.height === 'number')
@@ -168,11 +159,11 @@ function ShadowInner(props: ShadowProps): JSX.Element {
168159
};
169160
}, [cStyle]);
170161

171-
const styleStr: string = useMemo(() => (styleProp ? JSON.stringify(styleProp) : '{}'), [styleProp]);
162+
const styleStr: string | null = useMemo(() => (styleProp ? JSON.stringify(styleProp) : null), [styleProp]);
172163

173164
/** Flattened style. */
174165
const { style, sRadii }: { style: ViewStyle; sRadii: Record<Corner, number | undefined> } = useMemo(() => {
175-
const style = StyleSheet.flatten<ViewStyle>(JSON.parse(styleStr));
166+
const style = StyleSheet.flatten<ViewStyle>(styleStr && JSON.parse(styleStr));
176167
if (typeof style.width === 'number')
177168
style.width = R(style.width);
178169
if (typeof style.height === 'number')
@@ -211,8 +202,28 @@ function ShadowInner(props: ShadowProps): JSX.Element {
211202
const shadow = useMemo(() => getShadow({
212203
topStart, topEnd, bottomStart, bottomEnd, width, height,
213204
isRTL, distanceProp, startColorProp, endColorProp, paintInside,
214-
safeRender, activeSides, activeCorners, idSuffix,
215-
}), [topStart, topEnd, bottomStart, bottomEnd, width, height, isRTL, distanceProp, startColorProp, endColorProp, paintInside, safeRender, activeSides, activeCorners, idSuffix]);
205+
safeRender,
206+
activeSides: {
207+
bottom: sides?.bottom ?? true,
208+
top: sides?.top ?? true,
209+
start: sides?.start ?? true,
210+
end: sides?.end ?? true,
211+
}, activeCorners: {
212+
topStart: corners?.topStart ?? true,
213+
topEnd: corners?.topEnd ?? true,
214+
bottomStart: corners?.bottomStart ?? true,
215+
bottomEnd: corners?.bottomEnd ?? true,
216+
},
217+
idSuffix,
218+
}), [
219+
width, height, distanceProp,
220+
startColorProp, endColorProp,
221+
topStart, topEnd, bottomStart, bottomEnd,
222+
paintInside,
223+
sides?.bottom, sides?.top, sides?.start, sides?.end,
224+
corners?.topStart, corners?.topEnd, corners?.bottomStart, corners?.bottomEnd,
225+
safeRender, isRTL, idSuffix,
226+
]);
216227

217228
// Not yet sure if we should memo this.
218229
return getResult({
@@ -429,7 +440,7 @@ function getShadow({
429440
<Mask id={`maskInside.${idSuffix}`}>
430441
{/* Paint all white, then black on border external areas to erase them */}
431442
<Rect width={width} height={height} fill='#fff'/>
432-
{/* Remove the corners, as squares. Could use <Path/>, but this way seems to be more maintainable. */}
443+
{/* Remove the corners */}
433444
<Rect width={topStart} height={topStart} fill='#000'/>
434445
<Rect width={topEnd} height={topEnd} x={width} transform={`translate(${-topEnd}, 0)`} fill='#000'/>
435446
<Rect width={bottomStart} height={bottomStart} y={height} transform={`translate(0, ${-bottomStart})`} fill='#000'/>

src/utils.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ export type CornerRadiusShadow = Record<`${Corner}Shadow`, number>;
1414
* and somehow may be useful to you. */
1515
export const version = '7.0.0';
1616

17-
export const sidesArray = ['start', 'end', 'top', 'bottom'] as const;
1817
export const cornersArray = ['topStart', 'topEnd', 'bottomStart', 'bottomEnd'] as const;
1918

2019
const isWeb = Platform.OS === 'web';

0 commit comments

Comments
 (0)