react-native-unistyles 1.0.0-beta.1

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.
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
+ )