react-native-unistyles 1.0.0-beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +243 -0
  3. package/lib/commonjs/UnistylesTheme.js +21 -0
  4. package/lib/commonjs/UnistylesTheme.js.map +1 -0
  5. package/lib/commonjs/createUnistyles.js +52 -0
  6. package/lib/commonjs/createUnistyles.js.map +1 -0
  7. package/lib/commonjs/index.js +20 -0
  8. package/lib/commonjs/index.js.map +1 -0
  9. package/lib/commonjs/types.js +6 -0
  10. package/lib/commonjs/types.js.map +1 -0
  11. package/lib/commonjs/utils/breakpoints.js +139 -0
  12. package/lib/commonjs/utils/breakpoints.js.map +1 -0
  13. package/lib/commonjs/utils/breakpoints.spec.js +149 -0
  14. package/lib/commonjs/utils/breakpoints.spec.js.map +1 -0
  15. package/lib/commonjs/utils/common.js +11 -0
  16. package/lib/commonjs/utils/common.js.map +1 -0
  17. package/lib/commonjs/utils/index.js +32 -0
  18. package/lib/commonjs/utils/index.js.map +1 -0
  19. package/lib/commonjs/utils/mediaQueries.js +189 -0
  20. package/lib/commonjs/utils/mediaQueries.js.map +1 -0
  21. package/lib/commonjs/utils/mediaQueries.spec.js +220 -0
  22. package/lib/commonjs/utils/mediaQueries.spec.js.map +1 -0
  23. package/lib/commonjs/utils/styles.js +82 -0
  24. package/lib/commonjs/utils/styles.js.map +1 -0
  25. package/lib/commonjs/utils/styles.spec.js +98 -0
  26. package/lib/commonjs/utils/styles.spec.js.map +1 -0
  27. package/lib/module/UnistylesTheme.js +12 -0
  28. package/lib/module/UnistylesTheme.js.map +1 -0
  29. package/lib/module/createUnistyles.js +45 -0
  30. package/lib/module/createUnistyles.js.map +1 -0
  31. package/lib/module/index.js +3 -0
  32. package/lib/module/index.js.map +1 -0
  33. package/lib/module/types.js +2 -0
  34. package/lib/module/types.js.map +1 -0
  35. package/lib/module/utils/breakpoints.js +131 -0
  36. package/lib/module/utils/breakpoints.js.map +1 -0
  37. package/lib/module/utils/breakpoints.spec.js +147 -0
  38. package/lib/module/utils/breakpoints.spec.js.map +1 -0
  39. package/lib/module/utils/common.js +4 -0
  40. package/lib/module/utils/common.js.map +1 -0
  41. package/lib/module/utils/index.js +3 -0
  42. package/lib/module/utils/index.js.map +1 -0
  43. package/lib/module/utils/mediaQueries.js +176 -0
  44. package/lib/module/utils/mediaQueries.js.map +1 -0
  45. package/lib/module/utils/mediaQueries.spec.js +218 -0
  46. package/lib/module/utils/mediaQueries.spec.js.map +1 -0
  47. package/lib/module/utils/styles.js +75 -0
  48. package/lib/module/utils/styles.js.map +1 -0
  49. package/lib/module/utils/styles.spec.js +96 -0
  50. package/lib/module/utils/styles.spec.js.map +1 -0
  51. package/lib/typescript/src/UnistylesTheme.d.ts +9 -0
  52. package/lib/typescript/src/UnistylesTheme.d.ts.map +1 -0
  53. package/lib/typescript/src/createUnistyles.d.ts +9 -0
  54. package/lib/typescript/src/createUnistyles.d.ts.map +1 -0
  55. package/lib/typescript/src/index.d.ts +3 -0
  56. package/lib/typescript/src/index.d.ts.map +1 -0
  57. package/lib/typescript/src/types.d.ts +27 -0
  58. package/lib/typescript/src/types.d.ts.map +1 -0
  59. package/lib/typescript/src/utils/breakpoints.d.ts +63 -0
  60. package/lib/typescript/src/utils/breakpoints.d.ts.map +1 -0
  61. package/lib/typescript/src/utils/breakpoints.spec.d.ts +2 -0
  62. package/lib/typescript/src/utils/breakpoints.spec.d.ts.map +1 -0
  63. package/lib/typescript/src/utils/common.d.ts +2 -0
  64. package/lib/typescript/src/utils/common.d.ts.map +1 -0
  65. package/lib/typescript/src/utils/index.d.ts +3 -0
  66. package/lib/typescript/src/utils/index.d.ts.map +1 -0
  67. package/lib/typescript/src/utils/mediaQueries.d.ts +130 -0
  68. package/lib/typescript/src/utils/mediaQueries.d.ts.map +1 -0
  69. package/lib/typescript/src/utils/mediaQueries.spec.d.ts +2 -0
  70. package/lib/typescript/src/utils/mediaQueries.spec.d.ts.map +1 -0
  71. package/lib/typescript/src/utils/styles.d.ts +56 -0
  72. package/lib/typescript/src/utils/styles.d.ts.map +1 -0
  73. package/lib/typescript/src/utils/styles.spec.d.ts +2 -0
  74. package/lib/typescript/src/utils/styles.spec.d.ts.map +1 -0
  75. package/package.json +132 -0
  76. package/src/UnistylesTheme.tsx +17 -0
  77. package/src/createUnistyles.ts +56 -0
  78. package/src/index.ts +2 -0
  79. package/src/types.ts +52 -0
  80. package/src/utils/breakpoints.ts +140 -0
  81. package/src/utils/common.ts +3 -0
  82. package/src/utils/index.ts +2 -0
  83. package/src/utils/mediaQueries.ts +201 -0
  84. package/src/utils/styles.ts +95 -0
@@ -0,0 +1,140 @@
1
+ import { throwError } from './common'
2
+ import type { ScreenSize } from '../types'
3
+ import { getKeyForCustomMediaQuery, isMediaQuery } from './mediaQueries'
4
+
5
+ /**
6
+ * Sorts the breakpoints object based on its numeric values in ascending order and validates them.
7
+ *
8
+ * This function takes an object where keys represent breakpoint names and values are numeric.
9
+ * It returns a new object with the same keys but sorted based on their corresponding numeric values.
10
+ * Additionally, it validates that:
11
+ * 1. The first breakpoint starts with a value of 0.
12
+ * 2. No duplicate breakpoint values exist.
13
+ *
14
+ * If the validation fails, appropriate error messages are logged to the console.
15
+ *
16
+ * @template B - An object type where keys are strings and values are numbers.
17
+ * @param {B} breakpoints - The breakpoints object to be sorted and validated.
18
+ * @returns {B} A new object with sorted and validated breakpoints.
19
+ *
20
+ * @example
21
+ * const input = { md: 768, lg: 1024, sm: 0 }
22
+ * sortAndValidateBreakpoints(input) // returns { sm: 0, md: 768, lg: 1024 }
23
+ */
24
+ export const sortAndValidateBreakpoints = <B extends Record<string, number>>(breakpoints: B): B => {
25
+ const sortedPairs = Object
26
+ .entries(breakpoints)
27
+ .sort((breakpoint1, breakpoint2) => {
28
+ const [, value1] = breakpoint1
29
+ const [, value2] = breakpoint2
30
+
31
+ return value1 - value2
32
+ })
33
+
34
+ const sortedBreakpoints = Object.freeze(Object.fromEntries(sortedPairs)) as B
35
+ const breakpointValues = Object.values(sortedBreakpoints)
36
+ const [firstBreakpoint] = breakpointValues
37
+
38
+ if (firstBreakpoint !== 0) {
39
+ throwError('first breakpoint must start with 0')
40
+ }
41
+
42
+ if (breakpointValues.length !== new Set(breakpointValues).size) {
43
+ throwError('breakpoint values are duplicated')
44
+ }
45
+
46
+ return sortedBreakpoints
47
+ }
48
+
49
+ /**
50
+ * Determines the appropriate breakpoint key for a given screen width based on provided breakpoints.
51
+ *
52
+ * This function takes a screen width and an object of breakpoints. It returns the key of the breakpoint
53
+ * that the screen width falls into. The breakpoints are assumed to be sorted in ascending order.
54
+ *
55
+ * @template B - An object type where keys are strings and values are numbers representing screen widths.
56
+ * @param {number} width - The screen width to determine the breakpoint for.
57
+ * @param {B} breakpoints - The breakpoints object to use for determination.
58
+ * @returns {keyof B & string} The key of the breakpoint that the screen width falls into.
59
+ *
60
+ * @example
61
+ * const breakpoints = { sm: 0, md: 768, lg: 1024 }
62
+ * getBreakpointFromScreenWidth(800, breakpoints) // returns 'md'
63
+ */
64
+ export const getBreakpointFromScreenWidth = <B extends Record<string, number>>(width: number, breakpoints: B): keyof B & string => {
65
+ const [key] = Object
66
+ .entries(breakpoints)
67
+ .find(([, value], index, otherBreakpoints) => {
68
+ const minVal = value
69
+ const maxVal = otherBreakpoints[index + 1]?.[1]
70
+
71
+ if (!maxVal) {
72
+ return true
73
+ }
74
+
75
+ return width >= minVal && width < maxVal
76
+ }) as [keyof B & string, number]
77
+
78
+ return key
79
+ }
80
+
81
+ /**
82
+ * Retrieves the value associated with a given breakpoint or custom media query based on the provided screen size.
83
+ *
84
+ * The function first checks for custom media queries. If a matching custom media query is found, its associated value is returned.
85
+ * If no custom media query matches, the function then checks for a direct breakpoint match.
86
+ * If there's no direct breakpoint match, the function simulates CSS cascading to find the closest matching breakpoint.
87
+ *
88
+ * @template B - An object type where keys represent breakpoint names and values represent breakpoint values.
89
+ *
90
+ * @param {Record<keyof B & string, string | number>} value - An object containing values associated with breakpoints or custom media queries.
91
+ * @param {keyof B & string} breakpoint - The breakpoint name to check against.
92
+ * @param {ScreenSize} screenSize - An object representing the screen size to be checked against the media queries.
93
+ * @param {B} breakpoints - An object representing the defined breakpoints.
94
+ *
95
+ * @returns {string | number | undefined} Returns the value associated with the matching breakpoint or custom media query, or `undefined` if no match is found.
96
+ *
97
+ * @example
98
+ *
99
+ * const values = { ':w[200]': 'value1', sm: 'value2', md: 'value3' }
100
+ * const screenSize = { width: 250, height: 400 }
101
+ * const breakpoints = { sm: 300, md: 600, lg: 900 }
102
+ *
103
+ * getValueForBreakpoint(values, 'sm', screenSize, breakpoints); // 'value1'
104
+ */
105
+ export const getValueForBreakpoint = <B extends Record<string, number>>(value: Record<keyof B & string, string | number | undefined>, breakpoint: keyof B & string, screenSize: ScreenSize, breakpoints: B) => {
106
+ // the highest priority is for custom media queries
107
+ const customMediaQueries = Object
108
+ .entries(value)
109
+ .filter(([key]) => isMediaQuery(key))
110
+ const customMediaQueryKey = getKeyForCustomMediaQuery(customMediaQueries, screenSize)
111
+
112
+ if (customMediaQueryKey && customMediaQueryKey in value) {
113
+ return value[customMediaQueryKey]
114
+ }
115
+
116
+ // if no custom media query, or didn't match, proceed with defined breakpoints
117
+ const unifiedKey = breakpoint.toLowerCase()
118
+ const directBreakpoint = value[unifiedKey]
119
+
120
+ // if there is a direct key like 'sm' or 'md', or value for this key exists but its undefined
121
+ if (directBreakpoint || (unifiedKey in value)) {
122
+ return directBreakpoint
123
+ }
124
+
125
+ // there is no direct hit for breakpoint nor media-query, so let's simulate CSS cascading
126
+ const allBreakpoints = Object
127
+ .entries(breakpoints)
128
+ .map(([key, bpValue]) => [key.toLowerCase(), bpValue])
129
+
130
+ const currentBreakpoint = allBreakpoints
131
+ .findIndex(([key]) => key === unifiedKey)
132
+
133
+ const availableBreakpoints = allBreakpoints
134
+ .filter(([key], index) => index < currentBreakpoint && key && key in value)
135
+ .map(([key]) => key)
136
+
137
+ return allBreakpoints.length > 0
138
+ ? value[availableBreakpoints[availableBreakpoints.length - 1] as keyof B & string]
139
+ : undefined
140
+ }
@@ -0,0 +1,3 @@
1
+ export const throwError = (message: string) => {
2
+ throw new Error(`🦄 [react-native-unistyles]: ${message}`)
3
+ }
@@ -0,0 +1,2 @@
1
+ export { getBreakpointFromScreenWidth, sortAndValidateBreakpoints } from './breakpoints'
2
+ export { proxifyFunction, parseStyle } from './styles'
@@ -0,0 +1,201 @@
1
+ import type { ScreenSize } from '../types'
2
+
3
+ /**
4
+ * Extracts numeric values from a coded string.
5
+ *
6
+ * The function is designed to process strings that have a format like "w[100,200]" or "h[300]".
7
+ * It removes characters 'w', 'h', '[', and ']' from the input string and then extracts the numbers.
8
+ *
9
+ * @param {string} codedValue - The input string to extract values from.
10
+ * @returns {Array<number>} An array of extracted numbers. Can contain one or two numbers based on the input format.
11
+ *
12
+ * @example
13
+ * extractValues("w[100,200]") // returns [100, 200]
14
+ * extractValues("h[300]") // returns [300]
15
+ * extractValues("h[,300]") // returns [0,300]
16
+ * extractValues("h[100,]") // returns [100]
17
+ */
18
+ export const extractValues = (codedValue: string): Array<number> => {
19
+ const [lh, rh] = codedValue
20
+ .replace(/[wh[\]]/g, '')
21
+ .split(',')
22
+
23
+ return rh
24
+ ? [Number(lh), Number(rh)]
25
+ : [Number(lh)]
26
+ }
27
+
28
+ /**
29
+ * Determines if the given screen size matches the specified breakpoint query.
30
+ *
31
+ * The function checks if the screen size (width and/or height) falls within the range
32
+ * specified by the breakpoint query. The query can specify width (using 'w'), height (using 'h'),
33
+ * or both.
34
+ *
35
+ * @param {string} query - The breakpoint query string. Examples: 'w[100,200]', 'h[300]', 'w[100,200]h[300,400]'.
36
+ * @param {ScreenSize} screenSize - The screen size to check against the breakpoint query.
37
+ * @returns {boolean} True if the screen size matches the breakpoint query, false otherwise.
38
+ *
39
+ * @example
40
+ * const screenSize = { width: 150, height: 350 }
41
+ * isWithinBreakpoint('w[100,200]', screenSize) // returns true
42
+ * isWithinBreakpoint('h[400]', screenSize) // returns false
43
+ */
44
+ export const isWithinBreakpoint = (query: string, screenSize: ScreenSize): boolean => {
45
+ if (query.includes('w') && query.includes('h')) {
46
+ return isWithinTheWidthAndHeight(query, screenSize)
47
+ }
48
+
49
+ if (query.charAt(0) === 'w') {
50
+ return isWithinTheWidth(query, screenSize.width)
51
+ }
52
+
53
+ if (query.charAt(0) === 'h') {
54
+ return isWithinTheHeight(query, screenSize.height)
55
+ }
56
+
57
+ return false
58
+ }
59
+
60
+ /**
61
+ * Determines if the given width matches the specified width range in the query.
62
+ *
63
+ * The function checks if the provided width falls within the range specified by the query.
64
+ * The query specifies a width range using a format like 'w[100,200]'. If only one value is provided,
65
+ * it's treated as a minimum width.
66
+ *
67
+ * @param {string} query - The width query string. Examples: 'w[100,200]' or 'w[100]'.
68
+ * @param {number} width - The width to check against the query.
69
+ * @returns {boolean} True if the width matches the query range, false otherwise.
70
+ *
71
+ * @example
72
+ * isWithinTheWidth('w[100,200]', 150) // returns true
73
+ * isWithinTheWidth('w[100]', 50) // returns false
74
+ * isWithinTheWidth('w[100]', 150) // returns true
75
+ */
76
+ export const isWithinTheWidth = (query: string, width: number): boolean => {
77
+ const [minWidth, maxWidth] = extractValues(query) as [number, number | undefined]
78
+
79
+ if (maxWidth && width >= minWidth && width <= maxWidth) {
80
+ return true
81
+ }
82
+
83
+ return !maxWidth && width >= minWidth
84
+ }
85
+
86
+ /**
87
+ * Determines if the given height matches the specified height range in the query.
88
+ *
89
+ * The function checks if the provided height falls within the range specified by the query.
90
+ * The query specifies a height range using a format like 'h[100,200]'. If only one value is provided,
91
+ * it's treated as a minimum height.
92
+ *
93
+ * @param {string} query - The height query string. Examples: 'h[100,200]' or 'h[100]'.
94
+ * @param {number} height - The height to check against the query.
95
+ * @returns {boolean} True if the height matches the query range, false otherwise.
96
+ *
97
+ * @example
98
+ * isWithinTheHeight('h[100,200]', 150) // returns true
99
+ * isWithinTheHeight('h[100]', 50) // returns false
100
+ * isWithinTheHeight('h[100]', 150) // returns true
101
+ */
102
+ export const isWithinTheHeight = (query: string, height: number): boolean => {
103
+ const [minHeight, maxHeight] = extractValues(query) as [number, number | undefined]
104
+
105
+ if (maxHeight && height >= minHeight && height <= maxHeight) {
106
+ return true
107
+ }
108
+
109
+ return !maxHeight && height >= minHeight
110
+ }
111
+
112
+ /**
113
+ * Determines if the given screen size matches both the specified width and height ranges in the query.
114
+ *
115
+ * The function checks if the provided screen size (both width and height) falls within the ranges
116
+ * specified by the query. The query can specify both width and height using a format like 'w[100,200]:h[300,400]'.
117
+ *
118
+ * @param {string} query - The combined width and height query string. Example: 'w[100,200]:h[300,400]'.
119
+ * @param {ScreenSize} screenSize - The screen size to check against the query.
120
+ * @returns {boolean} True if the screen size matches both the width and height ranges in the query, false otherwise.
121
+ *
122
+ * @example
123
+ * const screenSize = { width: 150, height: 350 }
124
+ * isWithinTheWidthAndHeight('w[100,200]:h[300,400]', screenSize) // returns true
125
+ * isWithinTheWidthAndHeight('w[100,200]:h[400,500]', screenSize) // returns false
126
+ */
127
+ export const isWithinTheWidthAndHeight = (query: string, screenSize: ScreenSize): boolean => {
128
+ const result = query
129
+ .split(':')
130
+ .filter(Boolean)
131
+ .map(q => isWithinBreakpoint(q, screenSize))
132
+ .filter(Boolean)
133
+
134
+ return result.length === 2
135
+ }
136
+
137
+ /**
138
+ * Checks if the given query string is a valid custom media query.
139
+ *
140
+ * The valid custom media query formats include:
141
+ * - :w[200]
142
+ * - :w[0, 200]
143
+ * - :w[, 300]
144
+ * - :h[200]
145
+ * - :h[0, 500]
146
+ * - :h[,200]
147
+ * - :w[100, 300]:h[200,500]
148
+ * - :h[200,500]:w[100, 300]
149
+ *
150
+ * @param {string} query - The query string to be checked.
151
+ * @returns {boolean} Returns `true` if the query is a valid custom media query, otherwise `false`.
152
+ * @example
153
+ *
154
+ * isMediaQuery(':w[200]') // true
155
+ * isMediaQuery(':w100]') // false
156
+ */
157
+ export const isMediaQuery = (query: string): boolean => {
158
+ const regex = /^(?:(:w\[\d*(?:,\s?\d+)?])?(:h\[\d*(?:,\s?\d+)?])?|(:h\[\d*(?:,\s?\d+)?])?(:w\[\d*(?:,\s?\d+)?])?)$/
159
+
160
+ return query.length > 0 && regex.test(query)
161
+ }
162
+
163
+ /**
164
+ * Retrieves the first matching custom media query key based on the provided screen size.
165
+ *
166
+ * The function processes an array of media queries and returns the first query that matches
167
+ * the given screen size. The media queries can be in formats like:
168
+ * - w[200]
169
+ * - w[0, 200]
170
+ * - w[, 300]
171
+ * - h[200]
172
+ * - h[0, 500]
173
+ * - h[,200]
174
+ * - w[100, 300]:h[200,500]
175
+ * - h[200,500]:w[100, 300]
176
+ *
177
+ * @param {Array<[string, string | number]>} mediaQueries - An array of tuples containing media query keys and associated values.
178
+ * @param {ScreenSize} screenSize - An object representing the screen size to be checked against the media queries.
179
+ * @returns {string | undefined} Returns the first matching media query key or `undefined` if no match is found.
180
+ * @example
181
+ *
182
+ * const queries = [[':w[200]', 'value1'], [':h[300,500]', 'value2']]
183
+ * const size = { width: 250, height: 400 }
184
+ * getKeyForCustomMediaQuery(queries, size) // ':w[200]
185
+ */
186
+ export const getKeyForCustomMediaQuery = (mediaQueries: Array<[string, string | number | undefined]>, screenSize: ScreenSize): string | undefined => {
187
+ const [matchedQuery] = mediaQueries
188
+ .flatMap(([key]) => {
189
+ if (key.includes('w') && key.includes('h')) {
190
+ return isWithinBreakpoint(key, screenSize) ? key : undefined
191
+ }
192
+
193
+ return key
194
+ .split(':')
195
+ .filter(Boolean)
196
+ .map(query => isWithinBreakpoint(query, screenSize) ? key : undefined)
197
+ })
198
+ .filter(Boolean)
199
+
200
+ return matchedQuery
201
+ }
@@ -0,0 +1,95 @@
1
+ import type { CustomNamedStyles, ScreenSize } from '../types'
2
+ import { getValueForBreakpoint } from './breakpoints'
3
+
4
+ /**
5
+ * Proxies a function to parse its return value for custom media queries or breakpoints.
6
+ *
7
+ * If the function's string representation contains a custom media query or a defined breakpoint,
8
+ * the returned function will be proxied to parse its return value based on the provided screen size and breakpoints.
9
+ * If neither is found, the original function is returned.
10
+ *
11
+ * @template B - An object type where keys represent breakpoint names and values represent breakpoint values.
12
+ *
13
+ * @param {Function} fn - The function to be proxified.
14
+ * @param {keyof B & string} breakpoint - The breakpoint name to check against.
15
+ * @param {ScreenSize} screenSize - An object representing the screen size to be checked against the media queries.
16
+ * @param {B} breakpoints - An object representing the defined breakpoints.
17
+ *
18
+ * @returns {Function} Returns the proxified function or the original function if no custom media query or breakpoint is found in its string representation.
19
+ *
20
+ * @example
21
+ *
22
+ * const myFunction = () => ({ ':w[200]': 'value1', sm: 'value2' })
23
+ * const screenSize = { width: 250, height: 400 }
24
+ * const breakpoints = { sm: 300, md: 600 }
25
+ *
26
+ * const proxifiedFunction = proxifyFunction(myFunction, 'sm', screenSize, breakpoints)
27
+ * proxifiedFunction() // parsed style based on screenSize and breakpoints
28
+ */
29
+ export const proxifyFunction = <B extends Record<string, number>>(
30
+ fn: Function, breakpoint: keyof B & string,
31
+ screenSize: ScreenSize,
32
+ breakpoints: B
33
+ ): Function => {
34
+ const stringifiedFunction = fn.toString()
35
+ const hasCustomMediaQuery = stringifiedFunction.includes(':w[') || stringifiedFunction.includes(':h[')
36
+ const hasBreakpoint = Object
37
+ .keys(breakpoints)
38
+ .some(bp => stringifiedFunction.includes(bp))
39
+
40
+ if (!hasCustomMediaQuery && !hasBreakpoint) {
41
+ return fn
42
+ }
43
+
44
+ return new Proxy(fn, {
45
+ apply: (target, thisArg, argumentsList) =>
46
+ parseStyle(target.apply(thisArg, argumentsList), breakpoint, screenSize, breakpoints)
47
+ })
48
+ }
49
+
50
+ /**
51
+ * Parses a style object to resolve custom media queries or breakpoints based on the provided screen size and breakpoints.
52
+ *
53
+ * The function processes each key-value pair in the style object. If the value is a function or a valid style (not an object or a 'transform' key),
54
+ * it is returned as-is. Otherwise, the function attempts to resolve the value based on the provided breakpoint, screen size, and defined breakpoints.
55
+ *
56
+ * @template T - The type of the style object.
57
+ * @template B - An object type where keys represent breakpoint names and values represent breakpoint values.
58
+ *
59
+ * @param {CustomNamedStyles<T, B>} style - The style object to be parsed.
60
+ * @param {keyof B & string} breakpoint - The breakpoint name to check against.
61
+ * @param {ScreenSize} screenSize - An object representing the screen size to be checked against the media queries.
62
+ * @param {B} breakpoints - An object representing the defined breakpoints.
63
+ *
64
+ * @returns {Record<string, string | number | Function>} Returns the parsed style object with resolved custom media queries or breakpoints.
65
+ *
66
+ * @example
67
+ *
68
+ * const style = { fontSize: { sm: '12px', md: '16px' } }
69
+ * const screenSize = { width: 300, height: 400 }
70
+ * const breakpoints = { xs: 0, sm: 300, md: 600 }
71
+ *
72
+ * const parsedStyle = parseStyle(style, 'sm', screenSize, breakpoints)
73
+ * // { fontSize: '12px' }
74
+ */
75
+ export const parseStyle = <T, B extends Record<string, number>>(
76
+ style: CustomNamedStyles<T, B>,
77
+ breakpoint: keyof B & string,
78
+ screenSize: ScreenSize,
79
+ breakpoints: B
80
+ ) => Object
81
+ .fromEntries(Object
82
+ .entries(style)
83
+ .map(([key, value]) => {
84
+ const isDynamicFunction = typeof value === 'function'
85
+ const isValidStyle = typeof value !== 'object' || key === 'transform'
86
+
87
+ if (isDynamicFunction || isValidStyle) {
88
+ return [key, value]
89
+ }
90
+
91
+ const valueWithBreakpoint = value as Record<keyof B & string, string | number>
92
+
93
+ return [key, getValueForBreakpoint<B>(valueWithBreakpoint, breakpoint, screenSize, breakpoints)]
94
+ })
95
+ )