@telus-uds/components-base 1.80.1 → 1.82.0
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/CHANGELOG.md +30 -2
- package/lib/Autocomplete/Autocomplete.js +3 -1
- package/lib/Badge/Badge.js +1 -10
- package/lib/Fieldset/Fieldset.js +3 -1
- package/lib/Fieldset/FieldsetContainer.js +9 -2
- package/lib/Fieldset/FieldsetContainer.native.js +7 -1
- package/lib/Icon/Icon.js +24 -2
- package/lib/Listbox/Listbox.js +7 -1
- package/lib/Modal/Modal.js +40 -4
- package/lib/Modal/WebModal.js +73 -0
- package/lib/PriceLockup/PriceLockup.js +4 -1
- package/lib/PriceLockup/utils/renderFootnoteContent.js +2 -2
- package/lib/PriceLockup/utils/renderFootnoteLinks.js +2 -2
- package/lib/PriceLockup/utils/renderPrice.js +2 -2
- package/lib/PriceLockup/utils/renderTypography.js +1 -1
- package/lib/ProductCard/ProductCard.js +238 -0
- package/lib/ProductCard/dictionary.js +45 -0
- package/lib/ProductCard/index.js +10 -0
- package/lib/ProductCardGroup/ProductCardGroup.js +79 -0
- package/lib/ProductCardGroup/index.js +10 -0
- package/lib/TextInput/TextInput.js +1 -0
- package/lib/TextInput/TextInputBase.js +4 -1
- package/lib/index.js +16 -0
- package/lib/utils/ssr-media-query/create-stylesheet/index.js +2 -1
- package/lib/utils/ssr-media-query/utils/common.js +21 -2
- package/lib-module/Autocomplete/Autocomplete.js +3 -1
- package/lib-module/Badge/Badge.js +1 -10
- package/lib-module/Fieldset/Fieldset.js +3 -1
- package/lib-module/Fieldset/FieldsetContainer.js +7 -2
- package/lib-module/Fieldset/FieldsetContainer.native.js +10 -3
- package/lib-module/Icon/Icon.js +24 -2
- package/lib-module/Listbox/Listbox.js +7 -1
- package/lib-module/Modal/Modal.js +42 -5
- package/lib-module/Modal/WebModal.js +65 -0
- package/lib-module/PriceLockup/PriceLockup.js +4 -1
- package/lib-module/PriceLockup/utils/renderFootnoteContent.js +2 -2
- package/lib-module/PriceLockup/utils/renderFootnoteLinks.js +2 -2
- package/lib-module/PriceLockup/utils/renderPrice.js +2 -2
- package/lib-module/PriceLockup/utils/renderTypography.js +1 -1
- package/lib-module/ProductCard/ProductCard.js +231 -0
- package/lib-module/ProductCard/dictionary.js +38 -0
- package/lib-module/ProductCard/index.js +2 -0
- package/lib-module/ProductCardGroup/ProductCardGroup.js +69 -0
- package/lib-module/ProductCardGroup/index.js +2 -0
- package/lib-module/TextInput/TextInput.js +1 -0
- package/lib-module/TextInput/TextInputBase.js +4 -1
- package/lib-module/index.js +2 -0
- package/lib-module/utils/ssr-media-query/create-stylesheet/index.js +3 -2
- package/lib-module/utils/ssr-media-query/utils/common.js +19 -1
- package/package.json +2 -2
- package/src/Autocomplete/Autocomplete.jsx +4 -1
- package/src/Badge/Badge.jsx +7 -10
- package/src/Fieldset/Fieldset.jsx +3 -1
- package/src/Fieldset/FieldsetContainer.jsx +8 -1
- package/src/Fieldset/FieldsetContainer.native.jsx +7 -2
- package/src/Icon/Icon.jsx +30 -2
- package/src/Listbox/Listbox.jsx +6 -1
- package/src/Modal/Modal.jsx +42 -3
- package/src/Modal/WebModal.jsx +60 -0
- package/src/PriceLockup/PriceLockup.jsx +8 -2
- package/src/PriceLockup/utils/renderFootnoteContent.jsx +2 -2
- package/src/PriceLockup/utils/renderFootnoteLinks.jsx +2 -2
- package/src/PriceLockup/utils/renderPrice.jsx +2 -2
- package/src/PriceLockup/utils/renderTypography.jsx +1 -1
- package/src/ProductCard/ProductCard.jsx +193 -0
- package/src/ProductCard/dictionary.js +38 -0
- package/src/ProductCard/index.js +3 -0
- package/src/ProductCardGroup/ProductCardGroup.jsx +75 -0
- package/src/ProductCardGroup/index.js +3 -0
- package/src/TextInput/TextInput.jsx +1 -0
- package/src/TextInput/TextInputBase.jsx +4 -1
- package/src/index.js +2 -0
- package/src/utils/ssr-media-query/create-stylesheet/index.js +3 -2
- package/src/utils/ssr-media-query/utils/common.js +19 -1
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import PropTypes from 'prop-types'
|
|
3
|
+
import { StyleSheet, View, Image } from 'react-native'
|
|
4
|
+
import { useViewport } from '../ViewportProvider'
|
|
5
|
+
import { useThemeTokens } from '../ThemeProvider'
|
|
6
|
+
import defaultDictionary from './dictionary'
|
|
7
|
+
import {
|
|
8
|
+
selectSystemProps,
|
|
9
|
+
getTokensPropType,
|
|
10
|
+
htmlAttrs,
|
|
11
|
+
viewProps,
|
|
12
|
+
useInputValue,
|
|
13
|
+
useCopy,
|
|
14
|
+
a11yProps
|
|
15
|
+
} from '../utils'
|
|
16
|
+
|
|
17
|
+
import Badge from '../Badge'
|
|
18
|
+
import PriceLockup from '../PriceLockup'
|
|
19
|
+
import Typography from '../Typography'
|
|
20
|
+
import { Button } from '../Button'
|
|
21
|
+
import StackView from '../StackView'
|
|
22
|
+
import Box from '../Box'
|
|
23
|
+
import Icon from '../Icon'
|
|
24
|
+
|
|
25
|
+
const [selectProps, selectedSystemPropTypes] = selectSystemProps([htmlAttrs, viewProps, a11yProps])
|
|
26
|
+
|
|
27
|
+
const selectProductCardTokens = ({
|
|
28
|
+
borderStyle,
|
|
29
|
+
borderColor,
|
|
30
|
+
borderWidth,
|
|
31
|
+
borderRadius,
|
|
32
|
+
paddingHorizontal,
|
|
33
|
+
paddingVertical
|
|
34
|
+
}) => ({
|
|
35
|
+
borderStyle,
|
|
36
|
+
borderColor,
|
|
37
|
+
borderWidth,
|
|
38
|
+
borderRadius,
|
|
39
|
+
paddingHorizontal,
|
|
40
|
+
paddingVertical
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
const ProductCard = ({
|
|
44
|
+
copy = 'en',
|
|
45
|
+
dictionary = defaultDictionary,
|
|
46
|
+
image = {
|
|
47
|
+
src: '',
|
|
48
|
+
alt: ''
|
|
49
|
+
},
|
|
50
|
+
cardId,
|
|
51
|
+
isSelected,
|
|
52
|
+
onSelect,
|
|
53
|
+
tokens,
|
|
54
|
+
...rest
|
|
55
|
+
}) => {
|
|
56
|
+
const viewport = useViewport()
|
|
57
|
+
const themeTokens = useThemeTokens('ProductCard', tokens, { viewport })
|
|
58
|
+
|
|
59
|
+
const getCopy = useCopy({ copy, dictionary })
|
|
60
|
+
|
|
61
|
+
const { currentValue, setValue } = useInputValue()
|
|
62
|
+
const hasClicked = isSelected || currentValue
|
|
63
|
+
|
|
64
|
+
const handlePress = (event) => {
|
|
65
|
+
if (cardId) {
|
|
66
|
+
onSelect(cardId)
|
|
67
|
+
} else {
|
|
68
|
+
setValue(!currentValue, event)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const renderButton = hasClicked ? (
|
|
73
|
+
<Box vertical={1}>
|
|
74
|
+
<StackView space={2} direction="row">
|
|
75
|
+
<Icon icon={themeTokens.selectedButtonIcon} variant={{ color: 'success' }} />
|
|
76
|
+
<Typography variant={{ size: 'h4' }} tokens={{ fontWeight: 400 }}>
|
|
77
|
+
{getCopy('selectedButtonLabel')}
|
|
78
|
+
</Typography>
|
|
79
|
+
</StackView>
|
|
80
|
+
</Box>
|
|
81
|
+
) : (
|
|
82
|
+
<Button onPress={handlePress} variant={{ purpose: 'primary', size: 'small', width: 'full' }}>
|
|
83
|
+
{getCopy('buttonLabel')}
|
|
84
|
+
</Button>
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
return (
|
|
88
|
+
<View
|
|
89
|
+
{...selectProps(rest)}
|
|
90
|
+
style={[selectProductCardTokens(themeTokens), staticStyles.container]}
|
|
91
|
+
>
|
|
92
|
+
{image?.src ? (
|
|
93
|
+
<View style={staticStyles.imageContainer}>
|
|
94
|
+
<Image
|
|
95
|
+
source={image.src}
|
|
96
|
+
style={staticStyles.image}
|
|
97
|
+
alt={image.alt}
|
|
98
|
+
accessibilityLabel={image.alt}
|
|
99
|
+
resizeMethod="resize"
|
|
100
|
+
accessibilityIgnoresInvertColors
|
|
101
|
+
/>
|
|
102
|
+
</View>
|
|
103
|
+
) : null}
|
|
104
|
+
|
|
105
|
+
<View style={staticStyles.textContainer}>
|
|
106
|
+
<Box left={3}>
|
|
107
|
+
<StackView space={1}>
|
|
108
|
+
{getCopy('badgeText') ? (
|
|
109
|
+
<Badge variant={{ outline: true, purpose: 'editorial' }}>
|
|
110
|
+
{getCopy('badgeText')}
|
|
111
|
+
</Badge>
|
|
112
|
+
) : null}
|
|
113
|
+
<Typography variant={{ size: 'h6' }}>{getCopy('brandName')}</Typography>
|
|
114
|
+
<Typography variant={{ size: 'h4', colour: 'brand' }} tokens={{ fontWeight: 400 }}>
|
|
115
|
+
{getCopy('productName')}
|
|
116
|
+
</Typography>
|
|
117
|
+
<StackView space={3} divider direction="row">
|
|
118
|
+
<PriceLockup {...getCopy('primaryPrice')} size="small" ratePosition="bottom" />
|
|
119
|
+
{getCopy('secondaryPrice')?.price ? (
|
|
120
|
+
<PriceLockup {...getCopy('secondaryPrice')} size="small" ratePosition="bottom" />
|
|
121
|
+
) : null}
|
|
122
|
+
</StackView>
|
|
123
|
+
<Box top={2}>
|
|
124
|
+
<StackView space={2}>
|
|
125
|
+
<Typography variant={{ size: 'h6' }} tokens={{ fontWeight: 500 }}>
|
|
126
|
+
{getCopy('term')}
|
|
127
|
+
</Typography>
|
|
128
|
+
{getCopy('buttonLabel') ? <Box top={1}>{renderButton}</Box> : null}
|
|
129
|
+
</StackView>
|
|
130
|
+
</Box>
|
|
131
|
+
</StackView>
|
|
132
|
+
</Box>
|
|
133
|
+
</View>
|
|
134
|
+
</View>
|
|
135
|
+
)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
ProductCard.displayName = 'ProductCard'
|
|
139
|
+
|
|
140
|
+
// If a language dictionary entry is provided, it must contain every key
|
|
141
|
+
const dictionaryContentShape = PropTypes.shape({
|
|
142
|
+
badgeText: PropTypes.string,
|
|
143
|
+
brandName: PropTypes.string.isRequired,
|
|
144
|
+
productName: PropTypes.string.isRequired,
|
|
145
|
+
primaryPrice: PropTypes.object.isRequired,
|
|
146
|
+
secondaryPrice: PropTypes.object,
|
|
147
|
+
term: PropTypes.string.isRequired,
|
|
148
|
+
buttonLabel: PropTypes.string.isRequired,
|
|
149
|
+
selectedButtonLabel: PropTypes.string.isRequired
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
ProductCard.propTypes = {
|
|
153
|
+
...selectedSystemPropTypes,
|
|
154
|
+
image: PropTypes.shape({
|
|
155
|
+
src: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
|
|
156
|
+
alt: PropTypes.string
|
|
157
|
+
}),
|
|
158
|
+
/**
|
|
159
|
+
* Select English or French copy for the place holder labels.
|
|
160
|
+
* You may also pass in a custom dictionary object.
|
|
161
|
+
*/
|
|
162
|
+
copy: PropTypes.oneOfType([PropTypes.oneOf(['en', 'fr'])]),
|
|
163
|
+
/**
|
|
164
|
+
* Override the default dictionary, by passing the complete dictionary object for `en` and `fr`
|
|
165
|
+
*/
|
|
166
|
+
dictionary: PropTypes.shape({
|
|
167
|
+
en: dictionaryContentShape,
|
|
168
|
+
fr: dictionaryContentShape
|
|
169
|
+
}),
|
|
170
|
+
tokens: getTokensPropType('ProductCard')
|
|
171
|
+
}
|
|
172
|
+
export default ProductCard
|
|
173
|
+
|
|
174
|
+
const staticStyles = StyleSheet.create({
|
|
175
|
+
container: {
|
|
176
|
+
flexDirection: 'row',
|
|
177
|
+
flex: 1
|
|
178
|
+
},
|
|
179
|
+
imageContainer: {
|
|
180
|
+
width: '30%',
|
|
181
|
+
minWidth: 96,
|
|
182
|
+
maxWidth: 96
|
|
183
|
+
},
|
|
184
|
+
image: {
|
|
185
|
+
resizeMode: 'contain',
|
|
186
|
+
width: '100%',
|
|
187
|
+
height: undefined, // This is to maintain the aspect ratio
|
|
188
|
+
aspectRatio: 0.8
|
|
189
|
+
},
|
|
190
|
+
textContainer: {
|
|
191
|
+
width: '70%'
|
|
192
|
+
}
|
|
193
|
+
})
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
en: {
|
|
3
|
+
badgeText: '',
|
|
4
|
+
brandName: 'Brand name',
|
|
5
|
+
productName: 'Product name',
|
|
6
|
+
primaryPrice: {
|
|
7
|
+
price: '00',
|
|
8
|
+
signDirection: 'left',
|
|
9
|
+
rateText: '/month'
|
|
10
|
+
},
|
|
11
|
+
secondaryPrice: {
|
|
12
|
+
price: '',
|
|
13
|
+
signDirection: 'left',
|
|
14
|
+
rateText: 'Upfront'
|
|
15
|
+
},
|
|
16
|
+
term: '24 months | 0% APR Bring-it-Back applied',
|
|
17
|
+
buttonLabel: 'Select this phone',
|
|
18
|
+
selectedButtonLabel: 'Selected phone'
|
|
19
|
+
},
|
|
20
|
+
fr: {
|
|
21
|
+
badgeText: '',
|
|
22
|
+
brandName: 'Brand name',
|
|
23
|
+
productName: 'Product name',
|
|
24
|
+
primaryPrice: {
|
|
25
|
+
price: '00',
|
|
26
|
+
signDirection: 'right',
|
|
27
|
+
rateText: '/mois'
|
|
28
|
+
},
|
|
29
|
+
secondaryPrice: {
|
|
30
|
+
price: '',
|
|
31
|
+
signDirection: 'right',
|
|
32
|
+
rateText: "d'acompte"
|
|
33
|
+
},
|
|
34
|
+
term: '24 mois | TAP de 0% | avec Option retour',
|
|
35
|
+
buttonLabel: 'Sélectionner ce téléphone',
|
|
36
|
+
selectedButtonLabel: 'Téléphone sélectionné'
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import React, { useState } from 'react'
|
|
2
|
+
import PropTypes from 'prop-types'
|
|
3
|
+
import { View } from 'react-native'
|
|
4
|
+
import { selectSystemProps, htmlAttrs, viewProps, a11yProps } from '../utils'
|
|
5
|
+
|
|
6
|
+
import ProductCard from '../ProductCard'
|
|
7
|
+
import { StackWrap } from '../StackView'
|
|
8
|
+
|
|
9
|
+
const [selectProps, selectedSystemPropTypes] = selectSystemProps([htmlAttrs, viewProps, a11yProps])
|
|
10
|
+
|
|
11
|
+
const ProductCardGroup = ({ productCards, maxSelection = 1, ...rest }) => {
|
|
12
|
+
const [selectedCardIds, setSelectedCardIds] = useState([])
|
|
13
|
+
|
|
14
|
+
const handleSelect = (id) => {
|
|
15
|
+
const isAlreadySelected = selectedCardIds.includes(id)
|
|
16
|
+
let updatedSelectedCardIds
|
|
17
|
+
|
|
18
|
+
if (isAlreadySelected) {
|
|
19
|
+
updatedSelectedCardIds = selectedCardIds.filter((cardId) => cardId !== id)
|
|
20
|
+
} else if (maxSelection && selectedCardIds.length >= maxSelection) {
|
|
21
|
+
updatedSelectedCardIds = selectedCardIds.filter((_, index) => index !== 0).concat(id)
|
|
22
|
+
} else {
|
|
23
|
+
updatedSelectedCardIds = [...selectedCardIds, id]
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
setSelectedCardIds(updatedSelectedCardIds)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<View {...selectProps(rest)}>
|
|
31
|
+
<StackWrap direction={{ xs: 'column', lg: 'row' }} space={4}>
|
|
32
|
+
{productCards.map((cardProperties, index) => {
|
|
33
|
+
const cardId = cardProperties.id || index
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<View key={cardId}>
|
|
37
|
+
<ProductCard
|
|
38
|
+
key={cardId}
|
|
39
|
+
cardId={cardId}
|
|
40
|
+
isSelected={selectedCardIds.includes(cardId)}
|
|
41
|
+
onSelect={handleSelect}
|
|
42
|
+
{...cardProperties}
|
|
43
|
+
/>
|
|
44
|
+
</View>
|
|
45
|
+
)
|
|
46
|
+
})}
|
|
47
|
+
</StackWrap>
|
|
48
|
+
</View>
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
ProductCardGroup.displayName = 'ProductCardGroup'
|
|
53
|
+
|
|
54
|
+
ProductCardGroup.propTypes = {
|
|
55
|
+
...selectedSystemPropTypes,
|
|
56
|
+
/**
|
|
57
|
+
* The maximum number of ProductCards a user may select at once. Defaults to 1.
|
|
58
|
+
* To have no limit and allow any number of selections, pass `null`.
|
|
59
|
+
*/
|
|
60
|
+
maxSelection: PropTypes.number,
|
|
61
|
+
/**
|
|
62
|
+
* Props to be passed to the `ProductCard` component.
|
|
63
|
+
* id is required for each card.
|
|
64
|
+
* You may also pass in a custom dictionary object.
|
|
65
|
+
*/
|
|
66
|
+
productCards: PropTypes.arrayOf(
|
|
67
|
+
PropTypes.shape({
|
|
68
|
+
id: PropTypes.string.isRequired,
|
|
69
|
+
image: PropTypes.object,
|
|
70
|
+
dictionary: PropTypes.object
|
|
71
|
+
})
|
|
72
|
+
).isRequired
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export default ProductCardGroup
|
|
@@ -71,6 +71,7 @@ TextInput.propTypes = {
|
|
|
71
71
|
* A callback which if provided will get a clear button rendered and will be called whenever that button gets pressed.
|
|
72
72
|
*/
|
|
73
73
|
onClear: PropTypes.func,
|
|
74
|
+
onKeyPress: PropTypes.func,
|
|
74
75
|
tokens: getTokensPropType('TextInput'),
|
|
75
76
|
variant: variantProp.propType
|
|
76
77
|
}
|
|
@@ -182,6 +182,7 @@ const TextInputBase = forwardRef(
|
|
|
182
182
|
value,
|
|
183
183
|
variant = {},
|
|
184
184
|
type,
|
|
185
|
+
onKeyPress,
|
|
185
186
|
...rest
|
|
186
187
|
},
|
|
187
188
|
ref
|
|
@@ -311,7 +312,8 @@ const TextInputBase = forwardRef(
|
|
|
311
312
|
onChange: handleChangeText,
|
|
312
313
|
defaultValue: initialValue,
|
|
313
314
|
maxLength: type === 'card' ? 19 : undefined,
|
|
314
|
-
value: isControlled ? currentValue : undefined
|
|
315
|
+
value: isControlled ? currentValue : undefined,
|
|
316
|
+
onKeyPress
|
|
315
317
|
}
|
|
316
318
|
|
|
317
319
|
const { themeOptions } = useTheme()
|
|
@@ -388,6 +390,7 @@ TextInputBase.propTypes = {
|
|
|
388
390
|
onFocus: PropTypes.func,
|
|
389
391
|
onMouseOut: PropTypes.func,
|
|
390
392
|
onMouseOver: PropTypes.func,
|
|
393
|
+
onKeyPress: PropTypes.func,
|
|
391
394
|
readOnly: PropTypes.bool,
|
|
392
395
|
tokens: getTokensPropType('TextInput', 'TextArea'),
|
|
393
396
|
value: PropTypes.string,
|
package/src/index.js
CHANGED
|
@@ -33,6 +33,8 @@ export { default as Notification } from './Notification'
|
|
|
33
33
|
export { default as OrderedList } from './OrderedList'
|
|
34
34
|
export { default as Pagination } from './Pagination'
|
|
35
35
|
export { default as PriceLockup } from './PriceLockup'
|
|
36
|
+
export { default as ProductCard } from './ProductCard'
|
|
37
|
+
export { default as ProductCardGroup } from './ProductCardGroup'
|
|
36
38
|
export { default as Progress } from './Progress'
|
|
37
39
|
export { default as QuickLinks } from './QuickLinks'
|
|
38
40
|
export { default as QuickLinksFeature } from './QuickLinksFeature'
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { addCss } from '../utils/inject'
|
|
2
2
|
import createDeclarationBlock from '../utils/create-declaration-block'
|
|
3
3
|
import hash from '../hash'
|
|
4
|
-
import { isMediaOrPseudo, deepClone, createCssRule } from '../utils/common'
|
|
4
|
+
import { isMediaOrPseudo, deepClone, createCssRule, sanitizeStyle } from '../utils/common'
|
|
5
5
|
|
|
6
6
|
const createStyleSheet = (stylesWithQuery) => {
|
|
7
7
|
if (!stylesWithQuery) return { ids: {}, styles: {}, fullStyles: {} }
|
|
@@ -14,7 +14,8 @@ const createStyleSheet = (stylesWithQuery) => {
|
|
|
14
14
|
|
|
15
15
|
const mediaQueriesAndPseudoClasses = Object.keys(stylesWithQuery[key]).filter(isMediaOrPseudo)
|
|
16
16
|
mediaQueriesAndPseudoClasses.forEach((query) => {
|
|
17
|
-
const
|
|
17
|
+
const sanitizedStyle = sanitizeStyle(stylesWithQuery[key][query])
|
|
18
|
+
const css = createDeclarationBlock(sanitizedStyle)
|
|
18
19
|
const stringHash = `rnmq-${hash(`${key}${query}${css}`)}`
|
|
19
20
|
const rule = createCssRule(query, stringHash, css)
|
|
20
21
|
|
|
@@ -17,4 +17,22 @@ const createCssRule = (query, stringHash, css) => {
|
|
|
17
17
|
return rule
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Sanitizes the style object by converting any functions to their string representation.
|
|
22
|
+
*
|
|
23
|
+
* @param {Object} style - The style object to sanitize.
|
|
24
|
+
* @returns {Object} - The sanitized style object.
|
|
25
|
+
*/
|
|
26
|
+
const sanitizeStyle = (style) => {
|
|
27
|
+
const sanitizedStyle = { ...style }
|
|
28
|
+
|
|
29
|
+
Object.keys(sanitizedStyle).forEach((property) => {
|
|
30
|
+
if (typeof sanitizedStyle[property] === 'function') {
|
|
31
|
+
sanitizedStyle[property] = sanitizedStyle[property].toString()
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
return sanitizedStyle
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export { isMedia, isPseudo, isMediaOrPseudo, deepClone, createCssRule, sanitizeStyle }
|