rn-css 1.6.8 → 1.6.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -180,6 +180,14 @@ if(width < 70 * em) { /* Do something when width is lesser than 70em */ }
180
180
  return <View onLayout={event => setWidth(event.nativeEvent.layout.width)}>...</View>
181
181
  ```
182
182
 
183
+ Default value for `rem` units is 16. If you want to declare another value, you can use `RemContext`:
184
+
185
+ ```javascript
186
+ import { RemContext } from 'rn-css'
187
+ ...
188
+ return <RemContext.Provider value={10}>{children}</RemContext.Provider>
189
+ ```
190
+
183
191
  ---
184
192
 
185
193
  ## Convert a CSS string to React-Native Style
@@ -1,6 +1,6 @@
1
1
  import type { Style, Transform } from '../types';
2
2
  /** Parse a css value for border */
3
- export declare function border(prefixKey: 'border' | 'borderLeft' | 'borderRight' | 'borderTop' | 'borderBottom', value: string): {
3
+ export declare function border(prefixKey: 'border' | 'borderLeft' | 'borderRight' | 'borderTop' | 'borderBottom' | 'outline', value: string): {
4
4
  [x: string]: string;
5
5
  };
6
6
  export declare function shadow(prefix: 'textShadow' | 'shadow', value: string): {
@@ -69,6 +69,7 @@ function cssChunkToStyle(css) {
69
69
  const key = kebab2camel(rawKey.trim());
70
70
  const value = stripSpaces(rawValue.trim()); // We need this to correctly read calc() values
71
71
  switch (key) {
72
+ case 'outline':
72
73
  case 'border':
73
74
  case 'borderTop':
74
75
  case 'borderLeft':
@@ -11,6 +11,7 @@ const react_native_1 = require("react-native");
11
11
  const convertStyle_1 = __importDefault(require("./convertStyle"));
12
12
  const cssToRN_1 = __importDefault(require("./cssToRN"));
13
13
  const features_1 = require("./features");
14
+ const generateHash_1 = __importDefault(require("./generateHash"));
14
15
  exports.defaultUnits = { em: 16, vw: 1, vh: 1, vmin: 1, vmax: 1, rem: 16, px: 1, pt: 72 / 96, in: 96, pc: 9, cm: 96 / 2.54, mm: 96 / 25.4 };
15
16
  exports.RemContext = react_1.default.createContext(exports.defaultUnits.rem);
16
17
  exports.FontSizeContext = react_1.default.createContext(exports.defaultUnits.em);
@@ -22,6 +23,23 @@ function buildCSSString(chunks, functs, props, shared) {
22
23
  computedString += props.rnCSS.replace(/=/gm, ':') + ';';
23
24
  return computedString;
24
25
  }
26
+ const styleMap = {};
27
+ function getStyle(hash, style) {
28
+ const styleInfo = styleMap[hash];
29
+ if (styleInfo) {
30
+ styleInfo.usage++;
31
+ return styleInfo.style;
32
+ }
33
+ else {
34
+ const sheet = react_native_1.StyleSheet.create({ [hash]: style });
35
+ return (styleMap[hash] = { style: sheet[hash], usage: 1 }).style;
36
+ }
37
+ }
38
+ function removeStyle(hash) {
39
+ styleMap[hash].usage--;
40
+ if (styleMap[hash].usage <= 0)
41
+ delete styleMap[hash];
42
+ }
25
43
  const styled = (Component) => {
26
44
  const styledComponent = (chunks, ...functs) => {
27
45
  const ForwardRefComponent = react_1.default.forwardRef((props, ref) => {
@@ -33,7 +51,7 @@ const styled = (Component) => {
33
51
  const rnStyle = react_1.default.useMemo(() => (0, cssToRN_1.default)(css), [css]);
34
52
  const { needsLayout, needsHover } = react_1.default.useMemo(() => ({
35
53
  // needsFontSize: !!css.match(/\b(\d+)(\.\d+)?em\b/)
36
- // needsScreenSize: !!cssString.current.match(/\b(\d+)(\.\d+)?v([hw]|min|max)\b/) || !!rnStyle.media,
54
+ // needsScreenSize: !!css.match(/\b(\d+)(\.\d*)?v([hw]|min|max)\b/) || !!rnStyle.media,
37
55
  needsLayout: !!css.match(/\d%/),
38
56
  needsHover: !!rnStyle.hover
39
57
  }), [css, rnStyle.hover]);
@@ -77,19 +95,22 @@ const styled = (Component) => {
77
95
  return style;
78
96
  }, [em, mediaQuery, tempStyle]);
79
97
  const units = react_1.default.useMemo(() => ({ ...baseUnits, em }), [baseUnits, em]);
80
- const styleConvertedFromCSS = react_1.default.useMemo(() => (0, convertStyle_1.default)(finalStyle, units), [finalStyle, units]);
81
- const style = react_1.default.useMemo(() => [styleConvertedFromCSS, props.style], [props.style, styleConvertedFromCSS]);
82
- const flatStyle = react_1.default.useMemo(() => react_native_1.StyleSheet.flatten(style), [style]);
98
+ const { style: styleConvertedFromCSS, hash } = react_1.default.useMemo(() => {
99
+ const style = (0, convertStyle_1.default)(finalStyle, units);
100
+ delete style.textOverflow;
101
+ const hash = (0, generateHash_1.default)(JSON.stringify(style));
102
+ return { style: getStyle(hash, style), hash };
103
+ }, [finalStyle, units]);
83
104
  const newProps = react_1.default.useMemo(() => {
84
- const newProps = { style, onMouseEnter, onMouseLeave, onLayout };
85
- if (flatStyle.textOverflow === 'ellipsis')
105
+ const newProps = { style: [styleConvertedFromCSS, props.style], onMouseEnter, onMouseLeave, onLayout };
106
+ if (finalStyle.textOverflow === 'ellipsis') {
86
107
  Object.assign(newProps, { numberOfLines: 1 });
108
+ }
87
109
  return newProps;
88
- }, [flatStyle.textOverflow, onLayout, onMouseEnter, onMouseLeave, style]);
89
- // The lines below can improve perfs, but it causes the component to remount when the font size changes
90
- // const currentFontSize = React.useContext(FontSizeContext)
91
- // if (em !== currentFontSize) {
92
- if (flatStyle.fontSize) {
110
+ }, [finalStyle.textOverflow, onLayout, onMouseEnter, onMouseLeave, props.style, styleConvertedFromCSS]);
111
+ react_1.default.useEffect(() => () => removeStyle(hash), [hash]);
112
+ // em !== parentEm alone is a bit dangerous as the component would rerender when the font size change
113
+ if (em !== parentEm || finalStyle.fontSize !== undefined) {
93
114
  return react_1.default.createElement(exports.FontSizeContext.Provider, { value: em },
94
115
  react_1.default.createElement(Component, { ref: ref, ...props, ...newProps }));
95
116
  }
package/dist/types.d.ts CHANGED
@@ -60,6 +60,7 @@ export declare type PartialStyle = Partial<Record<keyof ViewStyle | keyof TextSt
60
60
  width: string;
61
61
  height: string;
62
62
  };
63
+ textOverflow?: 'ellipsis';
63
64
  transform?: Transform[];
64
65
  };
65
66
  export declare type Style = PartialStyle & {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rn-css",
3
- "version": "1.6.8",
3
+ "version": "1.6.11",
4
4
  "scripts": {
5
5
  "test": "jest",
6
6
  "prepare": "tsc",
@@ -23,7 +23,7 @@ function findNumbers (value: string) {
23
23
  }
24
24
 
25
25
  /** Parse a css value for border */
26
- export function border (prefixKey: 'border' | 'borderLeft' | 'borderRight' | 'borderTop' | 'borderBottom', value: string): { [x:string]: string } {
26
+ export function border (prefixKey: 'border' | 'borderLeft' | 'borderRight' | 'borderTop' | 'borderBottom' | 'outline', value: string): { [x:string]: string } {
27
27
  const values = value.split(/\s+/mg)
28
28
  const result = {
29
29
  [prefixKey + 'Width']: '0',
@@ -66,6 +66,7 @@ function cssChunkToStyle (css: string) {
66
66
  const key = kebab2camel(rawKey.trim())
67
67
  const value = stripSpaces(rawValue.trim())// We need this to correctly read calc() values
68
68
  switch (key) {
69
+ case 'outline':
69
70
  case 'border':
70
71
  case 'borderTop':
71
72
  case 'borderLeft':
@@ -1,11 +1,12 @@
1
1
  /* eslint-disable react/prop-types */
2
2
  /* eslint-disable react/display-name */
3
3
  import React, { MouseEvent } from 'react'
4
- import { FlatList, FlatListProps, LayoutChangeEvent, Platform, SectionList, SectionListProps, StyleProp, StyleSheet, VirtualizedList, VirtualizedListProps } from 'react-native'
4
+ import { FlatList, FlatListProps, LayoutChangeEvent, Platform, SectionList, SectionListProps, StyleProp, StyleSheet, TextStyle, ViewStyle, VirtualizedList, VirtualizedListProps } from 'react-native'
5
5
  import convertStyle from './convertStyle'
6
6
  import cssToStyle from './cssToRN'
7
7
  import { useFontSize, useHover, useLayout, useScreenSize, useMediaQuery } from './features'
8
8
  import type { Style, Units } from './types'
9
+ import generateHash from './generateHash'
9
10
 
10
11
  export const defaultUnits: Units = { em: 16, vw: 1, vh: 1, vmin: 1, vmax: 1, rem: 16, px: 1, pt: 72 / 96, in: 96, pc: 9, cm: 96 / 2.54, mm: 96 / 25.4 }
11
12
  export const RemContext = React.createContext<number>(defaultUnits.rem)
@@ -29,6 +30,22 @@ function buildCSSString<T extends { rnCSS?: string }> (chunks: TemplateStringsAr
29
30
  if (props.rnCSS) computedString += props.rnCSS.replace(/=/gm, ':') + ';'
30
31
  return computedString
31
32
  }
33
+ const styleMap: Record<string, { style: ViewStyle & TextStyle, usage: number }> = {}
34
+ function getStyle (hash: string, style: ViewStyle & TextStyle) {
35
+ const styleInfo = styleMap[hash]
36
+ if (styleInfo) {
37
+ styleInfo.usage++
38
+ return styleInfo.style
39
+ }
40
+ else {
41
+ const sheet = StyleSheet.create({ [hash]: style })
42
+ return (styleMap[hash] = { style: sheet[hash], usage: 1 }).style
43
+ }
44
+ }
45
+ function removeStyle (hash: string) {
46
+ styleMap[hash].usage--
47
+ if (styleMap[hash].usage <= 0) delete styleMap[hash]
48
+ }
32
49
  const styled = <Props, >(Component: React.ComponentType<Props>) => {
33
50
  const styledComponent = <S, >(chunks: TemplateStringsArray, ...functs: (Primitive | Functs<S & Props>)[]) => {
34
51
  const ForwardRefComponent = React.forwardRef<React.ComponentType<S & Props & OptionalProps>, S & Props & OptionalProps>((props: S & Props & OptionalProps, ref) => {
@@ -41,7 +58,7 @@ const styled = <Props, >(Component: React.ComponentType<Props>) => {
41
58
 
42
59
  const { needsLayout, needsHover } = React.useMemo(() => ({
43
60
  // needsFontSize: !!css.match(/\b(\d+)(\.\d+)?em\b/)
44
- // needsScreenSize: !!cssString.current.match(/\b(\d+)(\.\d+)?v([hw]|min|max)\b/) || !!rnStyle.media,
61
+ // needsScreenSize: !!css.match(/\b(\d+)(\.\d*)?v([hw]|min|max)\b/) || !!rnStyle.media,
45
62
  needsLayout: !!css.match(/\d%/),
46
63
  needsHover: !!rnStyle.hover
47
64
  }), [css, rnStyle.hover])
@@ -89,19 +106,24 @@ const styled = <Props, >(Component: React.ComponentType<Props>) => {
89
106
 
90
107
  const units = React.useMemo<Units>(() => ({ ...baseUnits, em }), [baseUnits, em])
91
108
 
92
- const styleConvertedFromCSS = React.useMemo(() => convertStyle(finalStyle, units), [finalStyle, units])
93
- const style: StyleProp<any> = React.useMemo(() => [styleConvertedFromCSS, props.style], [props.style, styleConvertedFromCSS])
94
- const flatStyle = React.useMemo(() => StyleSheet.flatten(style), [style])
109
+ const { style: styleConvertedFromCSS, hash } = React.useMemo(() => {
110
+ const style = convertStyle(finalStyle, units)
111
+ delete (style as Style).textOverflow
112
+ const hash = generateHash(JSON.stringify(style))
113
+ return { style: getStyle(hash, style), hash }
114
+ }, [finalStyle, units])
95
115
  const newProps = React.useMemo(() => {
96
- const newProps: OptionalProps = { style, onMouseEnter, onMouseLeave, onLayout }
97
- if (flatStyle.textOverflow === 'ellipsis') Object.assign(newProps, { numberOfLines: 1 })
116
+ const newProps: OptionalProps = { style: [styleConvertedFromCSS, props.style], onMouseEnter, onMouseLeave, onLayout }
117
+ if (finalStyle.textOverflow === 'ellipsis') {
118
+ Object.assign(newProps, { numberOfLines: 1 })
119
+ }
98
120
  return newProps
99
- }, [flatStyle.textOverflow, onLayout, onMouseEnter, onMouseLeave, style])
121
+ }, [finalStyle.textOverflow, onLayout, onMouseEnter, onMouseLeave, props.style, styleConvertedFromCSS])
122
+
123
+ React.useEffect(() => () => removeStyle(hash), [hash])
100
124
 
101
- // The lines below can improve perfs, but it causes the component to remount when the font size changes
102
- // const currentFontSize = React.useContext(FontSizeContext)
103
- // if (em !== currentFontSize) {
104
- if (flatStyle.fontSize) {
125
+ // em !== parentEm alone is a bit dangerous as the component would rerender when the font size change
126
+ if (em !== parentEm || finalStyle.fontSize !== undefined) {
105
127
  return <FontSizeContext.Provider value={em}>
106
128
  <Component ref={ref} {...props} {...newProps} />
107
129
  </FontSizeContext.Provider>
package/src/types.ts CHANGED
@@ -63,6 +63,7 @@ export type PartialStyle = Partial<Record<keyof ViewStyle | keyof TextStyle, str
63
63
  width: string;
64
64
  height: string;
65
65
  };
66
+ textOverflow?: 'ellipsis'
66
67
  transform?: Transform[];
67
68
  }
68
69