@hanzo/commerce 7.3.2 → 7.3.4
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/components/Icons.tsx +34 -34
- package/components/add-to-cart-widget.tsx +183 -183
- package/components/buy/buy-card.tsx +259 -259
- package/components/buy/carousel-buy-card.tsx +242 -242
- package/components/buy/multi-family/all-variants-carousel.tsx +261 -261
- package/components/buy/multi-family/family-carousel/index.tsx +77 -77
- package/components/buy/multi-family/family-carousel/slide.tsx +83 -83
- package/components/buy/multi-family/family-carousel/state.ts +87 -87
- package/components/buy/multi-family/index.ts +2 -2
- package/components/buy/single-family-selector.tsx +90 -90
- package/components/buy/title-and-byline.tsx +25 -25
- package/components/cart/cart-panel/cart-line-item.tsx +76 -76
- package/components/cart/cart-panel/index.tsx +154 -154
- package/components/cart/cart-panel/promo-code.tsx +106 -106
- package/components/cart/cart-panel/total-area.tsx +60 -60
- package/components/checkout/payment-step-form/card-icon-row.tsx +26 -26
- package/components/checkout/payment-step-form/card-icons/amex.tsx +32 -32
- package/components/checkout/payment-step-form/card-icons/diners-club.tsx +13 -13
- package/components/checkout/payment-step-form/card-icons/discover.tsx +25 -25
- package/components/checkout/payment-step-form/card-icons/jcb.tsx +26 -26
- package/components/checkout/payment-step-form/card-icons/mastercard.tsx +27 -27
- package/components/checkout/payment-step-form/card-icons/visa.tsx +25 -25
- package/components/checkout/payment-step-form/cc-button.tsx +17 -17
- package/components/checkout/payment-step-form/contact-form.tsx +49 -49
- package/components/checkout/payment-step-form/crypto-icons/btc.tsx +11 -11
- package/components/checkout/payment-step-form/crypto-icons/eth.tsx +20 -20
- package/components/checkout/payment-step-form/crypto-icons/usdt.tsx +13 -13
- package/components/checkout/payment-step-form/index.tsx +122 -122
- package/components/checkout/payment-step-form/methods/bank-transfer.tsx +79 -79
- package/components/checkout/payment-step-form/methods/card.tsx +232 -232
- package/components/checkout/payment-step-form/methods/crypto.tsx +227 -227
- package/components/checkout/payment-step-form/methods/index.ts +22 -22
- package/components/checkout/shipping-step-form.tsx +172 -172
- package/components/index.ts +11 -11
- package/components/item/product-card.tsx +48 -48
- package/components/item-selector/button.tsx +188 -188
- package/components/item-selector/carousel/index.tsx +197 -197
- package/components/item-selector/carousel/slider.tsx +40 -40
- package/components/item-selector/index.ts +5 -5
- package/components/item-selector/quantity-indicator.tsx +48 -48
- package/components/node-tabs/index.tsx +91 -91
- package/components/node-tabs/node-image.tsx +31 -31
- package/index.ts +12 -12
- package/package.json +60 -60
- package/service/context.tsx +45 -45
- package/service/debug.ts +41 -41
- package/service/impls/standalone/actual-line-item.ts +135 -135
- package/service/impls/standalone/get-instance.ts +64 -64
- package/service/impls/standalone/index.ts +579 -579
- package/service/impls/standalone/order/firebase.ts +14 -14
- package/service/impls/standalone/order/index.ts +128 -128
- package/service/impls/standalone/persistence.ts +33 -33
- package/service/path-utils.ts +25 -25
- package/service/sep.ts +6 -6
- package/tsconfig.json +10 -10
- package/types/README.md +1 -1
- package/types/category-node.ts +49 -49
- package/types/checkout.ts +46 -46
- package/types/commerce-config.ts +13 -13
- package/types/commerce-service.ts +127 -127
- package/types/family.ts +25 -25
- package/types/index.ts +15 -15
- package/types/item-selector.ts +96 -96
- package/types/line-item.ts +29 -29
- package/types/multi-family-selector-props.ts +19 -19
- package/types/product.ts +20 -20
- package/types/promo.ts +9 -9
- package/types/selection-ui-specifier.ts +51 -51
- package/types/string-mutator.ts +13 -13
- package/types/token-separators.ts +7 -7
- package/util/analytics.ts +20 -20
- package/util/countries.ts +195 -195
- package/util/error.ts +34 -34
- package/util/index.ts +70 -70
- package/util/item-selector-options-accessor.ts +34 -34
- package/util/line-item-ref.ts +23 -23
- package/util/multi-family-selector-options-accessor.ts +14 -14
- package/util/obs-string-mutator.ts +22 -22
- package/util/product-media-accessor.ts +58 -58
- package/util/promo-codes.ts +108 -108
- package/util/selection-ui-specifiers.ts +29 -29
- package/util/square-payment.ts +42 -42
- package/util/use-sync-sku-param-w-current-item.ts +88 -88
|
@@ -1,188 +1,188 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
import React from 'react'
|
|
3
|
-
import { observer } from 'mobx-react-lite'
|
|
4
|
-
|
|
5
|
-
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group"
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
Image,
|
|
9
|
-
Label,
|
|
10
|
-
RadioGroup,
|
|
11
|
-
ScrollArea
|
|
12
|
-
} from '@hanzo/ui/primitives'
|
|
13
|
-
import { cn } from '@hanzo/ui/util'
|
|
14
|
-
import type { Dimensions } from '@hanzo/ui/types'
|
|
15
|
-
|
|
16
|
-
import type { ItemSelectorProps, LineItem } from '../../types'
|
|
17
|
-
import { accessItemOptions, formatCurrencyValue } from '../../util'
|
|
18
|
-
|
|
19
|
-
import QuantityIndicator from './quantity-indicator'
|
|
20
|
-
|
|
21
|
-
const DEFAULT_CONSTRAINT = {h: 36, w: 72} // // Apple suggest 42px for clickability
|
|
22
|
-
|
|
23
|
-
const ImageRadioGroupItem = React.forwardRef<
|
|
24
|
-
React.ElementRef<typeof RadioGroupPrimitive.Item>,
|
|
25
|
-
Omit<React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>, 'value' | 'id'> & {
|
|
26
|
-
item: LineItem,
|
|
27
|
-
constrainTo: Dimensions
|
|
28
|
-
}
|
|
29
|
-
>(({
|
|
30
|
-
item,
|
|
31
|
-
constrainTo,
|
|
32
|
-
className,
|
|
33
|
-
...props
|
|
34
|
-
}, ref) => {
|
|
35
|
-
|
|
36
|
-
const img = item.optionImg ? item.optionImg : item.img
|
|
37
|
-
|
|
38
|
-
return (
|
|
39
|
-
<RadioGroupPrimitive.Item
|
|
40
|
-
ref={ref}
|
|
41
|
-
data-vaul-no-drag
|
|
42
|
-
className={cn(
|
|
43
|
-
'ring-offset-background focus:outline-none focus-visible:ring-2 focus-visible:ring-ring',
|
|
44
|
-
'focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
|
|
45
|
-
className,
|
|
46
|
-
'overflow-hidden',
|
|
47
|
-
img?.rounded ? `rounded-${img.rounded}` : 'rounded-sm'
|
|
48
|
-
)}
|
|
49
|
-
{...props}
|
|
50
|
-
id={item.sku}
|
|
51
|
-
value={item.sku}
|
|
52
|
-
>
|
|
53
|
-
{img ? (
|
|
54
|
-
<Image def={img} constrainTo={constrainTo} preload className=''/>
|
|
55
|
-
) : ( // placeholder so things align
|
|
56
|
-
<div style={{height: constrainTo.h, width: constrainTo.w}}/>
|
|
57
|
-
)}
|
|
58
|
-
</RadioGroupPrimitive.Item>
|
|
59
|
-
)
|
|
60
|
-
})
|
|
61
|
-
ImageRadioGroupItem.displayName = 'ImageRadioGroupItem'
|
|
62
|
-
|
|
63
|
-
const ButtonItemSelector: React.FC<ItemSelectorProps> = observer(({
|
|
64
|
-
items,
|
|
65
|
-
selectedItemRef: itemRef,
|
|
66
|
-
selectSku,
|
|
67
|
-
clx='',
|
|
68
|
-
itemClx='',
|
|
69
|
-
soleItemClx='',
|
|
70
|
-
scrollable=false,
|
|
71
|
-
mobile=false,
|
|
72
|
-
options={}
|
|
73
|
-
}) => {
|
|
74
|
-
|
|
75
|
-
const {
|
|
76
|
-
showPrice,
|
|
77
|
-
showQuantity,
|
|
78
|
-
showFamilyInOption,
|
|
79
|
-
buttonType,
|
|
80
|
-
horizButtons,
|
|
81
|
-
showButtonIfOnlyOne
|
|
82
|
-
} = accessItemOptions(options)
|
|
83
|
-
|
|
84
|
-
const showImage = buttonType !== 'text'
|
|
85
|
-
const showText = buttonType !== 'image'
|
|
86
|
-
const showBoth = buttonType === 'image-and-text'
|
|
87
|
-
|
|
88
|
-
const labelAndPrice = (item : LineItem) => (
|
|
89
|
-
(showFamilyInOption ? (item.familyTitle + ', ' + item.optionLabel) : item.optionLabel) +
|
|
90
|
-
(showPrice ? ((showFamilyInOption ? ': ' : ', ') + formatCurrencyValue(item.price)) : '')
|
|
91
|
-
)
|
|
92
|
-
|
|
93
|
-
const Item: React.FC<{
|
|
94
|
-
item: LineItem
|
|
95
|
-
selected: boolean
|
|
96
|
-
}> = observer(({
|
|
97
|
-
item,
|
|
98
|
-
selected
|
|
99
|
-
}) => {
|
|
100
|
-
|
|
101
|
-
const textClx = (selected) ? 'text-accent' : 'text-muted'
|
|
102
|
-
const cursorClx = (selected) ? 'hover:cursor-default' : 'hover:cursor-pointer'
|
|
103
|
-
const justifyClx = (showBoth) ? '' : 'justify-center'
|
|
104
|
-
// If no image, the Label must fill the entire button since it has to be
|
|
105
|
-
// clickable all the way to the border
|
|
106
|
-
const paddingClx = (showImage) ? (scrollable ? 'px-4 py-2' : 'px-2 py-2' ) : ''
|
|
107
|
-
let bgClx = ''
|
|
108
|
-
let borderClx = ''
|
|
109
|
-
if (scrollable) {
|
|
110
|
-
borderClx += (selected) ? 'border-foreground border ' : 'border-b border-muted-2 '
|
|
111
|
-
}
|
|
112
|
-
else if (!showImage) {
|
|
113
|
-
borderClx += 'border rounded-lg '
|
|
114
|
-
borderClx += (selected) ? 'border-foreground ' : 'border-muted-2 '
|
|
115
|
-
bgClx += 'hover:bg-level-2'
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
const outerClx = ['h-10 flex items-center', justifyClx, paddingClx, bgClx, borderClx]
|
|
119
|
-
|
|
120
|
-
return (
|
|
121
|
-
<div className={cn(...outerClx, itemClx )} data-vaul-no-drag >
|
|
122
|
-
<ImageRadioGroupItem
|
|
123
|
-
item={item}
|
|
124
|
-
constrainTo={DEFAULT_CONSTRAINT}
|
|
125
|
-
className={cn(
|
|
126
|
-
cursorClx,
|
|
127
|
-
(scrollable ? '' : 'border-transparent border-2 data-[state=checked]:border-foreground'),
|
|
128
|
-
showBoth ? 'mr-2' : (showImage ? '' : 'hidden')
|
|
129
|
-
)}
|
|
130
|
-
/>
|
|
131
|
-
<Label htmlFor={item.sku} className={cn(
|
|
132
|
-
showQuantity ? 'flex items-center' : 'block',
|
|
133
|
-
textClx,
|
|
134
|
-
cursorClx,
|
|
135
|
-
(showImage ? '' : 'self-stretch w-full flex items-center justify-center px-3 py-2'),
|
|
136
|
-
(showText ? '' : 'hidden')
|
|
137
|
-
)}>
|
|
138
|
-
<div className={showQuantity ? 'grow' : ''}>{labelAndPrice(item)}</div>
|
|
139
|
-
{showQuantity && (
|
|
140
|
-
<QuantityIndicator
|
|
141
|
-
item={item}
|
|
142
|
-
clx='grow-0 shrink-0 h-[20px] ml-2'
|
|
143
|
-
iconClx={selected ? 'fill-foreground' : 'fill-muted'}
|
|
144
|
-
digitClx='font-semibold text-primary-fg leading-none font-sans text-xxs'
|
|
145
|
-
/>
|
|
146
|
-
)}
|
|
147
|
-
</Label>
|
|
148
|
-
</div>
|
|
149
|
-
)
|
|
150
|
-
})
|
|
151
|
-
|
|
152
|
-
return showButtonIfOnlyOne || items.length > 1 ? (
|
|
153
|
-
<RadioGroup
|
|
154
|
-
className={cn(
|
|
155
|
-
(scrollable ? 'shrink min-h-0 gap-0' : (mobile ? 'gap-3' : 'gap-1')),
|
|
156
|
-
(horizButtons ? `grid grid-cols-${items.length} gap-1` : 'flex flex-col'),
|
|
157
|
-
(mobile && showText) ? 'min-w-pr-50' : '',
|
|
158
|
-
clx,
|
|
159
|
-
)}
|
|
160
|
-
onValueChange={selectSku}
|
|
161
|
-
value={itemRef.item ? itemRef.item.sku : ''}
|
|
162
|
-
data-vaul-no-drag
|
|
163
|
-
>
|
|
164
|
-
{scrollable ? (
|
|
165
|
-
<ScrollArea className='mt-2 w-full h-full py-0 border border-muted-2' data-vaul-no-drag>
|
|
166
|
-
{items.map((item) => (
|
|
167
|
-
<Item item={item} selected={itemRef.item?.sku === item.sku} key={item.sku}/>
|
|
168
|
-
))}
|
|
169
|
-
</ScrollArea>
|
|
170
|
-
) : (<>
|
|
171
|
-
{items.map((item) => (
|
|
172
|
-
<Item item={item} selected={itemRef.item?.sku === item.sku} key={item.sku}/>
|
|
173
|
-
))}
|
|
174
|
-
</>)}
|
|
175
|
-
</RadioGroup>
|
|
176
|
-
) : (
|
|
177
|
-
<div className={cn(showQuantity ? 'flex items-center' : 'block', soleItemClx )}>
|
|
178
|
-
<div className={showQuantity ? 'grow' : ''}>
|
|
179
|
-
{labelAndPrice(items[0])}
|
|
180
|
-
</div>
|
|
181
|
-
{showQuantity && (
|
|
182
|
-
<QuantityIndicator item={items[0]} clx='grow-0 shrink-0 font-semibold text-sm leading-none px-2' />
|
|
183
|
-
)}
|
|
184
|
-
</div>
|
|
185
|
-
)
|
|
186
|
-
})
|
|
187
|
-
|
|
188
|
-
export default ButtonItemSelector
|
|
1
|
+
'use client'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import { observer } from 'mobx-react-lite'
|
|
4
|
+
|
|
5
|
+
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group"
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
Image,
|
|
9
|
+
Label,
|
|
10
|
+
RadioGroup,
|
|
11
|
+
ScrollArea
|
|
12
|
+
} from '@hanzo/ui/primitives'
|
|
13
|
+
import { cn } from '@hanzo/ui/util'
|
|
14
|
+
import type { Dimensions } from '@hanzo/ui/types'
|
|
15
|
+
|
|
16
|
+
import type { ItemSelectorProps, LineItem } from '../../types'
|
|
17
|
+
import { accessItemOptions, formatCurrencyValue } from '../../util'
|
|
18
|
+
|
|
19
|
+
import QuantityIndicator from './quantity-indicator'
|
|
20
|
+
|
|
21
|
+
const DEFAULT_CONSTRAINT = {h: 36, w: 72} // // Apple suggest 42px for clickability
|
|
22
|
+
|
|
23
|
+
const ImageRadioGroupItem = React.forwardRef<
|
|
24
|
+
React.ElementRef<typeof RadioGroupPrimitive.Item>,
|
|
25
|
+
Omit<React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>, 'value' | 'id'> & {
|
|
26
|
+
item: LineItem,
|
|
27
|
+
constrainTo: Dimensions
|
|
28
|
+
}
|
|
29
|
+
>(({
|
|
30
|
+
item,
|
|
31
|
+
constrainTo,
|
|
32
|
+
className,
|
|
33
|
+
...props
|
|
34
|
+
}, ref) => {
|
|
35
|
+
|
|
36
|
+
const img = item.optionImg ? item.optionImg : item.img
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<RadioGroupPrimitive.Item
|
|
40
|
+
ref={ref}
|
|
41
|
+
data-vaul-no-drag
|
|
42
|
+
className={cn(
|
|
43
|
+
'ring-offset-background focus:outline-none focus-visible:ring-2 focus-visible:ring-ring',
|
|
44
|
+
'focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
|
|
45
|
+
className,
|
|
46
|
+
'overflow-hidden',
|
|
47
|
+
img?.rounded ? `rounded-${img.rounded}` : 'rounded-sm'
|
|
48
|
+
)}
|
|
49
|
+
{...props}
|
|
50
|
+
id={item.sku}
|
|
51
|
+
value={item.sku}
|
|
52
|
+
>
|
|
53
|
+
{img ? (
|
|
54
|
+
<Image def={img} constrainTo={constrainTo} preload className=''/>
|
|
55
|
+
) : ( // placeholder so things align
|
|
56
|
+
<div style={{height: constrainTo.h, width: constrainTo.w}}/>
|
|
57
|
+
)}
|
|
58
|
+
</RadioGroupPrimitive.Item>
|
|
59
|
+
)
|
|
60
|
+
})
|
|
61
|
+
ImageRadioGroupItem.displayName = 'ImageRadioGroupItem'
|
|
62
|
+
|
|
63
|
+
const ButtonItemSelector: React.FC<ItemSelectorProps> = observer(({
|
|
64
|
+
items,
|
|
65
|
+
selectedItemRef: itemRef,
|
|
66
|
+
selectSku,
|
|
67
|
+
clx='',
|
|
68
|
+
itemClx='',
|
|
69
|
+
soleItemClx='',
|
|
70
|
+
scrollable=false,
|
|
71
|
+
mobile=false,
|
|
72
|
+
options={}
|
|
73
|
+
}) => {
|
|
74
|
+
|
|
75
|
+
const {
|
|
76
|
+
showPrice,
|
|
77
|
+
showQuantity,
|
|
78
|
+
showFamilyInOption,
|
|
79
|
+
buttonType,
|
|
80
|
+
horizButtons,
|
|
81
|
+
showButtonIfOnlyOne
|
|
82
|
+
} = accessItemOptions(options)
|
|
83
|
+
|
|
84
|
+
const showImage = buttonType !== 'text'
|
|
85
|
+
const showText = buttonType !== 'image'
|
|
86
|
+
const showBoth = buttonType === 'image-and-text'
|
|
87
|
+
|
|
88
|
+
const labelAndPrice = (item : LineItem) => (
|
|
89
|
+
(showFamilyInOption ? (item.familyTitle + ', ' + item.optionLabel) : item.optionLabel) +
|
|
90
|
+
(showPrice ? ((showFamilyInOption ? ': ' : ', ') + formatCurrencyValue(item.price)) : '')
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
const Item: React.FC<{
|
|
94
|
+
item: LineItem
|
|
95
|
+
selected: boolean
|
|
96
|
+
}> = observer(({
|
|
97
|
+
item,
|
|
98
|
+
selected
|
|
99
|
+
}) => {
|
|
100
|
+
|
|
101
|
+
const textClx = (selected) ? 'text-accent' : 'text-muted'
|
|
102
|
+
const cursorClx = (selected) ? 'hover:cursor-default' : 'hover:cursor-pointer'
|
|
103
|
+
const justifyClx = (showBoth) ? '' : 'justify-center'
|
|
104
|
+
// If no image, the Label must fill the entire button since it has to be
|
|
105
|
+
// clickable all the way to the border
|
|
106
|
+
const paddingClx = (showImage) ? (scrollable ? 'px-4 py-2' : 'px-2 py-2' ) : ''
|
|
107
|
+
let bgClx = ''
|
|
108
|
+
let borderClx = ''
|
|
109
|
+
if (scrollable) {
|
|
110
|
+
borderClx += (selected) ? 'border-foreground border ' : 'border-b border-muted-2 '
|
|
111
|
+
}
|
|
112
|
+
else if (!showImage) {
|
|
113
|
+
borderClx += 'border rounded-lg '
|
|
114
|
+
borderClx += (selected) ? 'border-foreground ' : 'border-muted-2 '
|
|
115
|
+
bgClx += 'hover:bg-level-2'
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const outerClx = ['h-10 flex items-center', justifyClx, paddingClx, bgClx, borderClx]
|
|
119
|
+
|
|
120
|
+
return (
|
|
121
|
+
<div className={cn(...outerClx, itemClx )} data-vaul-no-drag >
|
|
122
|
+
<ImageRadioGroupItem
|
|
123
|
+
item={item}
|
|
124
|
+
constrainTo={DEFAULT_CONSTRAINT}
|
|
125
|
+
className={cn(
|
|
126
|
+
cursorClx,
|
|
127
|
+
(scrollable ? '' : 'border-transparent border-2 data-[state=checked]:border-foreground'),
|
|
128
|
+
showBoth ? 'mr-2' : (showImage ? '' : 'hidden')
|
|
129
|
+
)}
|
|
130
|
+
/>
|
|
131
|
+
<Label htmlFor={item.sku} className={cn(
|
|
132
|
+
showQuantity ? 'flex items-center' : 'block',
|
|
133
|
+
textClx,
|
|
134
|
+
cursorClx,
|
|
135
|
+
(showImage ? '' : 'self-stretch w-full flex items-center justify-center px-3 py-2'),
|
|
136
|
+
(showText ? '' : 'hidden')
|
|
137
|
+
)}>
|
|
138
|
+
<div className={showQuantity ? 'grow' : ''}>{labelAndPrice(item)}</div>
|
|
139
|
+
{showQuantity && (
|
|
140
|
+
<QuantityIndicator
|
|
141
|
+
item={item}
|
|
142
|
+
clx='grow-0 shrink-0 h-[20px] ml-2'
|
|
143
|
+
iconClx={selected ? 'fill-foreground' : 'fill-muted'}
|
|
144
|
+
digitClx='font-semibold text-primary-fg leading-none font-sans text-xxs'
|
|
145
|
+
/>
|
|
146
|
+
)}
|
|
147
|
+
</Label>
|
|
148
|
+
</div>
|
|
149
|
+
)
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
return showButtonIfOnlyOne || items.length > 1 ? (
|
|
153
|
+
<RadioGroup
|
|
154
|
+
className={cn(
|
|
155
|
+
(scrollable ? 'shrink min-h-0 gap-0' : (mobile ? 'gap-3' : 'gap-1')),
|
|
156
|
+
(horizButtons ? `grid grid-cols-${items.length} gap-1` : 'flex flex-col'),
|
|
157
|
+
(mobile && showText) ? 'min-w-pr-50' : '',
|
|
158
|
+
clx,
|
|
159
|
+
)}
|
|
160
|
+
onValueChange={selectSku}
|
|
161
|
+
value={itemRef.item ? itemRef.item.sku : ''}
|
|
162
|
+
data-vaul-no-drag
|
|
163
|
+
>
|
|
164
|
+
{scrollable ? (
|
|
165
|
+
<ScrollArea className='mt-2 w-full h-full py-0 border border-muted-2' data-vaul-no-drag>
|
|
166
|
+
{items.map((item) => (
|
|
167
|
+
<Item item={item} selected={itemRef.item?.sku === item.sku} key={item.sku}/>
|
|
168
|
+
))}
|
|
169
|
+
</ScrollArea>
|
|
170
|
+
) : (<>
|
|
171
|
+
{items.map((item) => (
|
|
172
|
+
<Item item={item} selected={itemRef.item?.sku === item.sku} key={item.sku}/>
|
|
173
|
+
))}
|
|
174
|
+
</>)}
|
|
175
|
+
</RadioGroup>
|
|
176
|
+
) : (
|
|
177
|
+
<div className={cn(showQuantity ? 'flex items-center' : 'block', soleItemClx )}>
|
|
178
|
+
<div className={showQuantity ? 'grow' : ''}>
|
|
179
|
+
{labelAndPrice(items[0])}
|
|
180
|
+
</div>
|
|
181
|
+
{showQuantity && (
|
|
182
|
+
<QuantityIndicator item={items[0]} clx='grow-0 shrink-0 font-semibold text-sm leading-none px-2' />
|
|
183
|
+
)}
|
|
184
|
+
</div>
|
|
185
|
+
)
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
export default ButtonItemSelector
|