rn-css 1.6.6 → 1.6.9

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
package/dist/features.js CHANGED
@@ -68,7 +68,7 @@ const useLayout = (onLayout, needsLayout) => {
68
68
  exports.useLayout = useLayout;
69
69
  /** Apply the new fontSize to the component before we can calculate em units */
70
70
  const useFontSize = (fontSizeTarget, rem, em) => {
71
- const [fontSize, fontUnit] = react_1.default.useMemo(() => fontSizeTarget === undefined ? [fontSizeTarget] : (0, convertUnits_1.parseValue)(fontSizeTarget), [fontSizeTarget]);
71
+ const [fontSize, fontUnit] = react_1.default.useMemo(() => fontSizeTarget === undefined ? [] : (0, convertUnits_1.parseValue)(fontSizeTarget), [fontSizeTarget]);
72
72
  const isRelative = fontUnit && ['rem', 'em', '%'].includes(fontUnit);
73
73
  const newSize = react_1.default.useMemo(() => {
74
74
  if (fontSize && isRelative) {
@@ -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) => {
@@ -30,15 +48,10 @@ const styled = (Component) => {
30
48
  // Build the css string with the context
31
49
  const css = react_1.default.useMemo(() => buildCSSString(chunks, functs, props, shared), [props, shared]);
32
50
  // Store the style in RN format
33
- const [rnStyle, setRNStyle] = react_1.default.useState(() => (0, cssToRN_1.default)(css));
34
- react_1.default.useEffect(() => {
35
- // Try to load an existing style from the style map or save it for next time
36
- const style = (0, cssToRN_1.default)(css);
37
- setRNStyle(style);
38
- }, [css]);
51
+ const rnStyle = react_1.default.useMemo(() => (0, cssToRN_1.default)(css), [css]);
39
52
  const { needsLayout, needsHover } = react_1.default.useMemo(() => ({
40
53
  // needsFontSize: !!css.match(/\b(\d+)(\.\d+)?em\b/)
41
- // 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,
42
55
  needsLayout: !!css.match(/\d%/),
43
56
  needsHover: !!rnStyle.hover
44
57
  }), [css, rnStyle.hover]);
@@ -82,18 +95,24 @@ const styled = (Component) => {
82
95
  return style;
83
96
  }, [em, mediaQuery, tempStyle]);
84
97
  const units = react_1.default.useMemo(() => ({ ...baseUnits, em }), [baseUnits, em]);
85
- const styleConvertedFromCSS = react_1.default.useMemo(() => (0, convertStyle_1.default)(finalStyle, units), [finalStyle, units]);
86
- const style = react_1.default.useMemo(() => react_native_1.StyleSheet.flatten([styleConvertedFromCSS, props.style]), [props.style, styleConvertedFromCSS]);
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]);
87
104
  const newProps = react_1.default.useMemo(() => {
88
- const newProps = { style, onMouseEnter, onMouseLeave, onLayout };
89
- if (style.textOverflow === 'ellipsis')
105
+ const newProps = { style: [styleConvertedFromCSS, props.style], onMouseEnter, onMouseLeave, onLayout };
106
+ if (finalStyle.textOverflow === 'ellipsis') {
90
107
  Object.assign(newProps, { numberOfLines: 1 });
108
+ }
91
109
  return newProps;
92
- }, [onLayout, onMouseEnter, onMouseLeave, style]);
110
+ }, [finalStyle.textOverflow, onLayout, onMouseEnter, onMouseLeave, props.style, styleConvertedFromCSS]);
111
+ react_1.default.useEffect(() => () => removeStyle(hash), [hash]);
93
112
  // The lines below can improve perfs, but it causes the component to remount when the font size changes
94
113
  // const currentFontSize = React.useContext(FontSizeContext)
95
114
  // if (em !== currentFontSize) {
96
- if (style.fontSize) {
115
+ if (styleConvertedFromCSS.fontSize) {
97
116
  return react_1.default.createElement(exports.FontSizeContext.Provider, { value: em },
98
117
  react_1.default.createElement(Component, { ref: ref, ...props, ...newProps }));
99
118
  }
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.6",
3
+ "version": "1.6.9",
4
4
  "scripts": {
5
5
  "test": "jest",
6
6
  "prepare": "tsc",
package/src/features.tsx CHANGED
@@ -59,7 +59,7 @@ export const useLayout = (onLayout: undefined | ((event: LayoutChangeEvent) => v
59
59
 
60
60
  /** Apply the new fontSize to the component before we can calculate em units */
61
61
  export const useFontSize = (fontSizeTarget: string | undefined, rem: number, em: number): { em: number } => {
62
- const [fontSize, fontUnit] = React.useMemo(() => fontSizeTarget === undefined ? [fontSizeTarget] : parseValue(fontSizeTarget), [fontSizeTarget])
62
+ const [fontSize, fontUnit] = React.useMemo(() => fontSizeTarget === undefined ? [] : parseValue(fontSizeTarget), [fontSizeTarget])
63
63
  const isRelative = fontUnit && ['rem', 'em', '%'].includes(fontUnit)
64
64
  const newSize = React.useMemo(() => {
65
65
  if (fontSize && isRelative) {
@@ -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) => {
@@ -37,16 +54,11 @@ const styled = <Props, >(Component: React.ComponentType<Props>) => {
37
54
  // Build the css string with the context
38
55
  const css = React.useMemo(() => buildCSSString(chunks, functs, props, shared), [props, shared])
39
56
  // Store the style in RN format
40
- const [rnStyle, setRNStyle] = React.useState<Style>(() => cssToStyle(css))
41
- React.useEffect(() => {
42
- // Try to load an existing style from the style map or save it for next time
43
- const style = cssToStyle(css)
44
- setRNStyle(style)
45
- }, [css])
57
+ const rnStyle = React.useMemo(() => cssToStyle(css), [css])
46
58
 
47
59
  const { needsLayout, needsHover } = React.useMemo(() => ({
48
60
  // needsFontSize: !!css.match(/\b(\d+)(\.\d+)?em\b/)
49
- // 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,
50
62
  needsLayout: !!css.match(/\d%/),
51
63
  needsHover: !!rnStyle.hover
52
64
  }), [css, rnStyle.hover])
@@ -94,18 +106,26 @@ const styled = <Props, >(Component: React.ComponentType<Props>) => {
94
106
 
95
107
  const units = React.useMemo<Units>(() => ({ ...baseUnits, em }), [baseUnits, em])
96
108
 
97
- const styleConvertedFromCSS = React.useMemo(() => convertStyle(finalStyle, units), [finalStyle, units])
98
- const style: StyleProp<any> = React.useMemo(() => StyleSheet.flatten([styleConvertedFromCSS, props.style]), [props.style, styleConvertedFromCSS])
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])
99
115
  const newProps = React.useMemo(() => {
100
- const newProps: OptionalProps = { style, onMouseEnter, onMouseLeave, onLayout }
101
- if (style.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
+ }
102
120
  return newProps
103
- }, [onLayout, onMouseEnter, onMouseLeave, style])
121
+ }, [finalStyle.textOverflow, onLayout, onMouseEnter, onMouseLeave, props.style, styleConvertedFromCSS])
122
+
123
+ React.useEffect(() => () => removeStyle(hash), [hash])
104
124
 
105
125
  // The lines below can improve perfs, but it causes the component to remount when the font size changes
106
126
  // const currentFontSize = React.useContext(FontSizeContext)
107
127
  // if (em !== currentFontSize) {
108
- if (style.fontSize) {
128
+ if (styleConvertedFromCSS.fontSize) {
109
129
  return <FontSizeContext.Provider value={em}>
110
130
  <Component ref={ref} {...props} {...newProps} />
111
131
  </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