Skip to content

Commit 62e6d7c

Browse files
authored
refactor(EstimateCost): vanilla extract (#5737)
* refactor: estimate cost vanilla extract * fix: feedback
1 parent 137020b commit 62e6d7c

27 files changed

+3131
-27986
lines changed

.changeset/rare-regions-exist.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@ultraviolet/plus": minor
3+
---
4+
5+
Refactor component `EstimateCost` to use vanilla extract instead of Emotion

packages/plus/src/components/EstimateCost/Components/Item.tsx

Lines changed: 77 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
'use client'
22

3-
import { css } from '@emotion/react'
4-
import styled from '@emotion/styled'
53
import { HelpCircleOutlineIcon } from '@ultraviolet/icons'
6-
import { Badge, Stack, Text, Tooltip, zoomIn } from '@ultraviolet/ui'
4+
import { Badge, Stack, Text, Tooltip } from '@ultraviolet/ui'
5+
import { assignInlineVars } from '@vanilla-extract/dynamic'
76
import type { ComponentProps, ReactNode } from 'react'
87
import {
98
Children,
@@ -17,28 +16,35 @@ import {
1716
useState,
1817
} from 'react'
1918
import {
20-
OverlayRow,
21-
priceCell,
22-
Cell as StyledCell,
23-
StyledDiv,
24-
StyledLeftSide,
25-
StyledTr,
26-
} from '../componentStyle'
27-
import {
28-
MAX_CELL_WIDTH,
2919
maximumFractionDigits,
3020
maximumFractionDigitsLong,
3121
multiplier,
3222
} from '../constants'
3323
import { useEstimateCost } from '../EstimateCostProvider'
3424
import { calculatePrice } from '../helper'
3525
import { useOverlay } from '../OverlayContext'
26+
import {
27+
estimateCostCell,
28+
estimateCostOverlayRow,
29+
estimateCostPriceCell,
30+
paddingLeftCell,
31+
} from '../styles.css'
3632
import type {
3733
BareEstimateProduct,
3834
EstimateProduct,
3935
Iteration,
4036
Units,
4137
} from '../types'
38+
import {
39+
estimateCostBadgeItem,
40+
estimateCostLeftSide,
41+
estimateCostMaxWidthText,
42+
estimateCostResourceName,
43+
estimateCostTextItem,
44+
estimateCostTooltip,
45+
estimateCostTr,
46+
styledDiv,
47+
} from './components.css'
4248

4349
const TIME_RELATED_UNIT: Units[] = [
4450
'seconds',
@@ -48,52 +54,6 @@ const TIME_RELATED_UNIT: Units[] = [
4854
'months',
4955
]
5056

51-
const StyledResourceName = styled('div', {
52-
shouldForwardProp: prop => !['isOverlay', 'animated'].includes(prop),
53-
})<{
54-
isOverlay: boolean
55-
animated: boolean
56-
}>`
57-
text-align: ${({ isOverlay }) => (isOverlay ? 'initial' : 'right')};
58-
59-
${({ isOverlay, animated }) =>
60-
isOverlay
61-
? css`
62-
height: 48px;
63-
display: flex;
64-
flex-direction: column;
65-
-webkit-box-pack: center;
66-
justify-content: center;
67-
animation: ${animated ? css`800ms ${zoomIn}` : ''};
68-
`
69-
: null}
70-
`
71-
72-
const StyledBadge = styled(Badge)`
73-
margin-left: ${({ theme }) => theme.space['1']};
74-
align-self: center;
75-
`
76-
77-
const StyledText = styled(Text)`
78-
margin-left: ${({ theme }) => theme.space['1']};
79-
`
80-
81-
const MaxWidthText = styled(Text)`
82-
max-width: 75%;
83-
`
84-
85-
const TextAlignRight = styled(Text)`
86-
text-align: right;
87-
`
88-
89-
const StyledTooltip = styled(Tooltip)`
90-
vertical-align: text-top;
91-
`
92-
93-
const StyledPriceCell = styled(StyledCell)`
94-
${({ theme }) => priceCell(theme)}
95-
`
96-
9757
type ExtraProps = {
9858
itemCallback: (amount: number, isVariant: boolean) => void
9959
amount: number
@@ -227,10 +187,6 @@ type ItemProps = {
227187
strikeThrough?: boolean
228188
}
229189

230-
const StyleNoPriceItem = styled(Text)`
231-
text-align: right;
232-
`
233-
234190
export const Item = memo(
235191
({
236192
discount = 0,
@@ -298,9 +254,9 @@ export const Item = memo(
298254
}, [baseUnit, locales])
299255

300256
const { isOverlay } = useOverlay()
301-
const Row = isOverlay ? OverlayRow : StyledTr
302-
const Cell = isOverlay ? StyledCell.withComponent('div') : StyledCell
303-
const LeftSide = isOverlay ? 'div' : StyledLeftSide
257+
const Row = isOverlay ? 'li' : 'tr'
258+
const Cell = isOverlay ? 'div' : 'td'
259+
const LeftSide = 'div'
304260

305261
const [amount, setAmount] = useState(currentAmount)
306262
const [isVariant, setIsVariant] = useState(false)
@@ -390,16 +346,25 @@ export const Item = memo(
390346

391347
return (
392348
<Row
393-
hideFromOverlay={hideFromOverlay}
394-
isFirstElement={isFirstElement}
395-
shouldBeHidden={shouldBeHidden}
349+
className={
350+
isOverlay
351+
? estimateCostOverlayRow({
352+
hideFromOverlay,
353+
isFirstElement,
354+
shouldBeHidden,
355+
})
356+
: estimateCostTr
357+
}
396358
>
397359
<Cell
398-
hasBorder={!isLastElement && !noBorder && !isOverlay}
399-
tabulation={tabulation}
400-
width={!isOverlay ? MAX_CELL_WIDTH : 'inherit'}
360+
className={estimateCostCell({
361+
hasBorder: !isLastElement && !noBorder && !isOverlay,
362+
})}
363+
style={assignInlineVars({
364+
[paddingLeftCell]: `${(tabulation ?? 0) * 8 + 16}px`,
365+
})}
401366
>
402-
<LeftSide>
367+
<LeftSide className={isOverlay ? '' : estimateCostLeftSide}>
403368
<Stack>
404369
<Stack direction="row">
405370
<Text
@@ -410,34 +375,51 @@ export const Item = memo(
410375
{label}
411376
</Text>
412377
{tooltipInfo ? (
413-
<StyledDiv>
414-
<StyledTooltip text={tooltipInfo}>
378+
<div className={styledDiv}>
379+
<Tooltip className={estimateCostTooltip} text={tooltipInfo}>
415380
<HelpCircleOutlineIcon size="medium" />
416-
</StyledTooltip>
417-
</StyledDiv>
381+
</Tooltip>
382+
</div>
418383
) : null}
419384
{subLabel && !isOverlay ? (
420-
<StyledText as="p" italic sentiment="primary" variant="body">
385+
<Text
386+
as="p"
387+
className={estimateCostTextItem}
388+
italic
389+
sentiment="primary"
390+
variant="body"
391+
>
421392
{subLabel}
422-
</StyledText>
393+
</Text>
423394
) : null}
424395
{discount > 0 && discountText ? (
425-
<StyledBadge
396+
<Badge
397+
className={estimateCostBadgeItem}
426398
prominence="strong"
427399
sentiment="warning"
428400
size="small"
429401
>
430402
{discountText}
431-
</StyledBadge>
403+
</Badge>
432404
) : null}
433405
</Stack>
434406
{notice ? (
435-
<MaxWidthText as="p" prominence="weak" variant="caption">
407+
<Text
408+
as="p"
409+
className={estimateCostMaxWidthText}
410+
prominence="weak"
411+
variant="caption"
412+
>
436413
{notice}
437-
</MaxWidthText>
414+
</Text>
438415
) : null}
439416
</Stack>
440-
<StyledResourceName animated={animated} isOverlay={isOverlay}>
417+
<div
418+
className={estimateCostResourceName({
419+
isAnimated: isOverlay && animated,
420+
isOverlay,
421+
})}
422+
>
441423
{isDefined
442424
? Children.map(children, child =>
443425
isValidElement<ExtraProps>(child)
@@ -450,18 +432,21 @@ export const Item = memo(
450432
: null,
451433
)
452434
: textNotDefined || locales['estimate.cost.notDefined']}
453-
</StyledResourceName>
435+
</div>
454436
</LeftSide>
455437
</Cell>
456438
{!isOverlay ? (
457-
<StyledPriceCell
458-
hasBorder={!isLastElement && !noBorder}
459-
primary={isPrimaryBackground}
439+
<td
440+
className={`${estimateCostCell({ hasBorder: !isLastElement && !noBorder, primary: isPrimaryBackground })} ${estimateCostPriceCell}`}
441+
style={assignInlineVars({
442+
[paddingLeftCell]: `16px`,
443+
})}
460444
>
461445
{!noPrice ? (
462446
<>
463-
<StyleNoPriceItem
447+
<Text
464448
as="p"
449+
placement="right"
465450
prominence={
466451
computedItemPrice === 0 && computedMaxItemPrice === 0
467452
? 'weak'
@@ -491,10 +476,10 @@ export const Item = memo(
491476
maximumFractionDigits: formatMaximumFractionDigits,
492477
})}`
493478
: null}
494-
</StyleNoPriceItem>
479+
</Text>
495480
{(amount - amountFree !== 1 && computedItemPrice > 0) ||
496481
(maxAmount > 0 && computedMaxItemPrice > 0) ? (
497-
<TextAlignRight as="p" variant="body">
482+
<Text as="p" placement="right" variant="body">
498483
{formatNumber(
499484
calculatePrice({
500485
amount: 1,
@@ -519,11 +504,11 @@ export const Item = memo(
519504
'estimate.cost.units.hours.label'
520505
].toLowerCase()}`
521506
: null}
522-
</TextAlignRight>
507+
</Text>
523508
) : null}
524509
</>
525510
) : null}
526-
</StyledPriceCell>
511+
</td>
527512
) : null}
528513
</Row>
529514
)
Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,19 @@
11
'use client'
22

3-
import { css } from '@emotion/react'
4-
import styled from '@emotion/styled'
3+
import type { ComponentProps } from 'react'
4+
import { estimateCostLineThrough } from './components.css'
55

6-
type LineThroughProps = {
6+
type LineThroughProps = ComponentProps<'span'> & {
77
isActive?: boolean
88
}
99

10-
export const LineThrough = styled('span', {
11-
shouldForwardProp: prop => !['isActive'].includes(prop),
12-
})<LineThroughProps>`
13-
${({ isActive, theme }) =>
14-
isActive
15-
? css`
16-
text-decoration-line: line-through;
17-
text-decoration-color: ${theme.colors.warning.border};
18-
`
19-
: null}
20-
`
10+
export const LineThrough = ({
11+
isActive,
12+
className,
13+
...props
14+
}: LineThroughProps) => (
15+
<span
16+
className={`${className ? `${className} ` : ''} ${isActive ? estimateCostLineThrough : ''}`}
17+
{...props}
18+
/>
19+
)

packages/plus/src/components/EstimateCost/Components/NumberInput.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
import { NumberInput as NumberInputUV } from '@ultraviolet/ui'
44
import { useEffect, useState } from 'react'
5-
import { ItemResourceName } from '../componentStyle'
65
import { useOverlay } from '../OverlayContext'
6+
import { estimateCostItemResourceName } from './components.css'
77
import { Regular } from './Regular'
88

99
type NumberInputProps = {
@@ -31,9 +31,9 @@ export const NumberInput = ({
3131
}, [getAmountValue, amount])
3232

3333
return isOverlay ? (
34-
<ItemResourceName animated={false}>
34+
<div className={estimateCostItemResourceName()}>
3535
<Regular>{amount}</Regular>
36-
</ItemResourceName>
36+
</div>
3737
) : (
3838
<NumberInputUV
3939
controls={controls}

packages/plus/src/components/EstimateCost/Components/Region.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,13 @@
11
'use client'
22

3-
import styled from '@emotion/styled'
43
import type { ComponentProps, ReactNode } from 'react'
54
import { memo } from 'react'
65
import { useEstimateCost } from '../EstimateCostProvider'
6+
import { estimateCostImage } from '../styles.css'
77
import type { BareEstimateProduct, EstimateProduct, Iteration } from '../types'
88
import { Item } from './Item'
99
import { Strong } from './Strong'
1010

11-
const StyledImage = styled.img`
12-
width: 15px;
13-
margin-right: ${({ theme }) => theme.space['1']};
14-
`
15-
1611
type RegionProps = {
1712
shouldBeHidden?: boolean
1813
priceText?: ReactNode
@@ -65,7 +60,7 @@ export const Region = memo(
6560
shouldBeHidden={shouldBeHidden}
6661
>
6762
<Strong>
68-
<StyledImage alt={label} src={image} />
63+
<img alt={label} className={estimateCostImage} src={image} />
6964
{label}
7065
</Strong>
7166
</Item>

0 commit comments

Comments
 (0)