@luxfi/core 5.0.5 → 5.0.7
Sign up to get free protection for your applications and to get access to all the features.
- package/commerce/{index.ts → data/index.ts} +1 -1
- package/commerce/ui-context/commerce-ui.ts +118 -0
- package/commerce/ui-context/index.tsx +50 -0
- package/components/commerce/add-widget.tsx +20 -0
- package/components/commerce/buy-button.tsx +34 -0
- package/components/commerce/buy-drawer/drawer.tsx +46 -4
- package/components/commerce/buy-drawer/index.tsx +215 -17
- package/components/commerce/checkout-button.tsx +27 -14
- package/components/commerce/checkout-widget/index.tsx +143 -37
- package/components/commerce/checkout-widget/use-anim-clx-set.ts +3 -1
- package/components/index.ts +2 -8
- package/conf/index.ts +2 -0
- package/package.json +12 -10
- package/root-layout/index.tsx +6 -4
- package/style/drawer-handle-overrides.css +154 -0
- package/tsconfig.json +3 -3
- package/components/commerce/checkout-widget/use-lagging-item-ref.ts +0 -30
- /package/commerce/{AUTO-GEN-bullion-by-family.json → data/AUTO-GEN-bullion-by-family.json} +0 -0
- /package/commerce/{EDIT-ME-bullion-market-prices.ts → data/EDIT-ME-bullion-market-prices.ts} +0 -0
- /package/commerce/{assign-prices.ts → data/assign-prices.ts} +0 -0
- /package/commerce/{assign-videos-by-family-group.ts → data/assign-videos-by-family-group.ts} +0 -0
- /package/commerce/{bullion-price-1oz.ts → data/bullion-price-1oz.ts} +0 -0
- /package/{commerce/lux-service-options.ts → conf/lux-commerce-options.ts} +0 -0
@@ -13,6 +13,6 @@ export const getBullionFamilies = (videoMap: Map<string, VideoDef>) => (
|
|
13
13
|
)
|
14
14
|
)
|
15
15
|
|
16
|
-
export { default as serviceOptions } from '
|
16
|
+
export { default as serviceOptions } from '../../conf/lux-commerce-options'
|
17
17
|
export { default as bullionPrice1oz } from './bullion-price-1oz'
|
18
18
|
|
@@ -0,0 +1,118 @@
|
|
1
|
+
import {
|
2
|
+
action,
|
3
|
+
computed,
|
4
|
+
makeObservable,
|
5
|
+
observable,
|
6
|
+
} from 'mobx'
|
7
|
+
import type { CommerceService, LineItem, ObsLineItemRef } from '@hanzo/commerce/types'
|
8
|
+
|
9
|
+
|
10
|
+
interface CommerceUI extends ObsLineItemRef {
|
11
|
+
showBuyOptions: (skuPath: string) => void
|
12
|
+
hideBuyOptions: () => void
|
13
|
+
get buyOptionsSkuPath(): string | undefined
|
14
|
+
|
15
|
+
itemQuantityChanged(sku: string, val: number, prevVal: number): void
|
16
|
+
|
17
|
+
get closed(): boolean
|
18
|
+
setClosed(b: boolean): void
|
19
|
+
|
20
|
+
}
|
21
|
+
|
22
|
+
class CommerceUIStore implements CommerceUI {
|
23
|
+
|
24
|
+
static readonly TIMEOUT = 1500
|
25
|
+
_buyOptionsSkuPath: string | undefined = undefined
|
26
|
+
_closed: boolean = false
|
27
|
+
_paused: boolean = false
|
28
|
+
_activeItem: LineItem | undefined = undefined
|
29
|
+
_lastActivity: number | undefined = undefined
|
30
|
+
_service: CommerceService
|
31
|
+
|
32
|
+
constructor(s: CommerceService) {
|
33
|
+
this._service = s
|
34
|
+
makeObservable(this, {
|
35
|
+
_buyOptionsSkuPath: observable,
|
36
|
+
_activeItem: observable.shallow,
|
37
|
+
_closed: observable,
|
38
|
+
showBuyOptions: action,
|
39
|
+
hideBuyOptions: action,
|
40
|
+
buyOptionsSkuPath: computed,
|
41
|
+
itemQuantityChanged: action,
|
42
|
+
setClosed: action,
|
43
|
+
closed: computed,
|
44
|
+
tick: action,
|
45
|
+
item: computed
|
46
|
+
})
|
47
|
+
}
|
48
|
+
|
49
|
+
showBuyOptions = (skuPath: string): void => {
|
50
|
+
this._service.setCurrentItem(undefined)
|
51
|
+
this._buyOptionsSkuPath = skuPath
|
52
|
+
this._paused = true
|
53
|
+
this._closed = false
|
54
|
+
}
|
55
|
+
|
56
|
+
hideBuyOptions = (): void => {
|
57
|
+
this._buyOptionsSkuPath = undefined
|
58
|
+
this._paused = false
|
59
|
+
if (this._lastActivity) {
|
60
|
+
this._lastActivity = Date.now()
|
61
|
+
}
|
62
|
+
}
|
63
|
+
|
64
|
+
get buyOptionsSkuPath(): string | undefined {
|
65
|
+
return this._buyOptionsSkuPath
|
66
|
+
}
|
67
|
+
|
68
|
+
tick = () => {
|
69
|
+
if (
|
70
|
+
!this._paused
|
71
|
+
&&
|
72
|
+
this._lastActivity
|
73
|
+
&&
|
74
|
+
(Date.now() - this._lastActivity >= CommerceUIStore.TIMEOUT)
|
75
|
+
) {
|
76
|
+
this._activeItem = undefined
|
77
|
+
this._lastActivity = undefined
|
78
|
+
}
|
79
|
+
}
|
80
|
+
|
81
|
+
itemQuantityChanged = (sku: string, val: number, oldVal: number): void => {
|
82
|
+
|
83
|
+
if (val === 0) {
|
84
|
+
if (this._activeItem?.sku === sku) {
|
85
|
+
this._activeItem = undefined
|
86
|
+
this._lastActivity = undefined
|
87
|
+
}
|
88
|
+
// otherwise ignore
|
89
|
+
}
|
90
|
+
else if (val < oldVal) {
|
91
|
+
if (this._activeItem?.sku === sku) {
|
92
|
+
this._lastActivity = Date.now()
|
93
|
+
}
|
94
|
+
// otherwise ignore
|
95
|
+
}
|
96
|
+
else {
|
97
|
+
this._activeItem = this._service.getItemBySku(sku)
|
98
|
+
this._lastActivity = Date.now()
|
99
|
+
}
|
100
|
+
}
|
101
|
+
|
102
|
+
get item(): LineItem | undefined {
|
103
|
+
return this._activeItem
|
104
|
+
}
|
105
|
+
|
106
|
+
get closed(): boolean {
|
107
|
+
return this._closed
|
108
|
+
}
|
109
|
+
|
110
|
+
setClosed = (b: boolean): void => { this._closed = b}
|
111
|
+
|
112
|
+
dispose = () => {}
|
113
|
+
}
|
114
|
+
|
115
|
+
export {
|
116
|
+
CommerceUIStore,
|
117
|
+
type CommerceUI
|
118
|
+
}
|
@@ -0,0 +1,50 @@
|
|
1
|
+
'use client'
|
2
|
+
import React, {
|
3
|
+
createContext,
|
4
|
+
useContext,
|
5
|
+
useRef,
|
6
|
+
type PropsWithChildren,
|
7
|
+
useEffect
|
8
|
+
} from 'react'
|
9
|
+
|
10
|
+
// https://dev.to/ivandotv/mobx-server-side-rendering-with-next-js-4m18
|
11
|
+
import { enableStaticRendering } from 'mobx-react-lite'
|
12
|
+
enableStaticRendering(typeof window === "undefined")
|
13
|
+
|
14
|
+
import { type CommerceUI, CommerceUIStore } from './commerce-ui'
|
15
|
+
import { useCommerce } from '@hanzo/commerce'
|
16
|
+
|
17
|
+
const CommerceUIContext = createContext<CommerceUIStore | undefined>(undefined)
|
18
|
+
|
19
|
+
const useCommerceUI = (): CommerceUI => {
|
20
|
+
return useContext(CommerceUIContext) as CommerceUIStore
|
21
|
+
}
|
22
|
+
|
23
|
+
const CommerceUIProvider: React.FC<PropsWithChildren & {
|
24
|
+
DEBUG_NO_TICK?: boolean
|
25
|
+
}> = ({
|
26
|
+
children,
|
27
|
+
DEBUG_NO_TICK=false
|
28
|
+
}) => {
|
29
|
+
|
30
|
+
const cmmc = useCommerce()
|
31
|
+
const valueRef = useRef<CommerceUIStore>(new CommerceUIStore(cmmc))
|
32
|
+
|
33
|
+
useEffect(() => {
|
34
|
+
|
35
|
+
//valueRef.current = new CommerceUIStore(cmmc)
|
36
|
+
return () => { valueRef.current?.dispose() }
|
37
|
+
}, [])
|
38
|
+
|
39
|
+
return (
|
40
|
+
<CommerceUIContext.Provider value={valueRef.current}>
|
41
|
+
{children}
|
42
|
+
</CommerceUIContext.Provider>
|
43
|
+
)
|
44
|
+
}
|
45
|
+
|
46
|
+
export {
|
47
|
+
useCommerceUI,
|
48
|
+
CommerceUIProvider
|
49
|
+
}
|
50
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
'use client'
|
2
|
+
import React from 'react'
|
3
|
+
|
4
|
+
import type { LineItem } from '@hanzo/commerce/types'
|
5
|
+
import { AddToCartWidget } from '@hanzo/commerce'
|
6
|
+
|
7
|
+
import { useCommerceUI } from '../../commerce/ui-context'
|
8
|
+
|
9
|
+
const AddWidget: React.FC<{
|
10
|
+
item: LineItem
|
11
|
+
disabled?: boolean
|
12
|
+
className?: string
|
13
|
+
buttonClx?: string
|
14
|
+
variant?: 'minimal' | 'primary' | 'outline'
|
15
|
+
}> = (props) => {
|
16
|
+
const ui = useCommerceUI()
|
17
|
+
return <AddToCartWidget {...props} onQuantityChanged={ui.itemQuantityChanged}/>
|
18
|
+
}
|
19
|
+
|
20
|
+
export default AddWidget
|
@@ -0,0 +1,34 @@
|
|
1
|
+
'use client'
|
2
|
+
import React, {type PropsWithChildren} from 'react'
|
3
|
+
|
4
|
+
import { Button, buttonVariants } from '@hanzo/ui/primitives'
|
5
|
+
import { type VariantProps } from '@hanzo/ui/util'
|
6
|
+
|
7
|
+
import { cn } from '@hanzo/ui/util'
|
8
|
+
import { useCommerceUI } from '../../commerce/ui-context'
|
9
|
+
|
10
|
+
const BuyButton: React.FC<
|
11
|
+
PropsWithChildren &
|
12
|
+
VariantProps<typeof buttonVariants> &
|
13
|
+
{
|
14
|
+
skuPath: string
|
15
|
+
className?: string
|
16
|
+
}
|
17
|
+
> = ({
|
18
|
+
skuPath,
|
19
|
+
children,
|
20
|
+
className='',
|
21
|
+
...rest
|
22
|
+
}) => {
|
23
|
+
|
24
|
+
const ui = useCommerceUI()
|
25
|
+
const handleClick = () => { ui.showBuyOptions(skuPath) }
|
26
|
+
|
27
|
+
return (
|
28
|
+
<Button onClick={handleClick} {...rest} className={cn(className, '')}>
|
29
|
+
{children}
|
30
|
+
</Button>
|
31
|
+
)
|
32
|
+
}
|
33
|
+
|
34
|
+
export default BuyButton
|
@@ -3,29 +3,70 @@ import React, {type PropsWithChildren } from 'react'
|
|
3
3
|
|
4
4
|
import { X as LucideX} from 'lucide-react'
|
5
5
|
|
6
|
-
import {
|
6
|
+
import {
|
7
|
+
Button,
|
8
|
+
Drawer,
|
9
|
+
DrawerContent,
|
10
|
+
DrawerHandle,
|
11
|
+
type DrawerProps,
|
12
|
+
useDrawerContext
|
13
|
+
} from '@hanzo/ui/primitives'
|
7
14
|
import { cn } from '@hanzo/ui/util'
|
8
15
|
|
16
|
+
import '../../../style/drawer-handle-overrides.css'
|
17
|
+
|
9
18
|
const CommerceDrawer: React.FC<PropsWithChildren &
|
10
19
|
Omit<DrawerProps, 'onOpenChange'> &
|
11
20
|
{
|
12
21
|
setOpen: (b: boolean) => void
|
22
|
+
handleHandleClicked: () => void
|
13
23
|
drawerClx?: string
|
24
|
+
setActiveSPIndexSetter?: (fn: (snapPoint: number | string | null) => void) => void
|
14
25
|
}
|
15
26
|
> = ({
|
16
27
|
children,
|
17
28
|
open,
|
18
29
|
setOpen,
|
19
30
|
modal,
|
31
|
+
snapPoints,
|
32
|
+
setActiveSnapPoint,
|
33
|
+
activeSnapPoint,
|
34
|
+
handleHandleClicked,
|
35
|
+
setActiveSPIndexSetter,
|
20
36
|
drawerClx='',
|
21
37
|
...rest
|
22
|
-
}) =>
|
38
|
+
}) => {
|
39
|
+
|
40
|
+
|
41
|
+
return (
|
23
42
|
// @ts-ignore
|
24
|
-
<Drawer
|
25
|
-
|
43
|
+
<Drawer
|
44
|
+
open={open}
|
45
|
+
onOpenChange={setOpen}
|
46
|
+
modal={modal}
|
47
|
+
snapPoints={snapPoints}
|
48
|
+
setActiveSnapPoint={setActiveSnapPoint}
|
49
|
+
activeSnapPoint={activeSnapPoint}
|
50
|
+
fastDragSkipsToEnd={false}
|
51
|
+
handleOnly={true}
|
52
|
+
setActiveSPIndexSetter={setActiveSPIndexSetter}
|
53
|
+
|
54
|
+
|
55
|
+
{...rest}
|
56
|
+
>
|
57
|
+
<DrawerContent defaultHandle={false} className={cn(
|
26
58
|
'rounded-t-xl mt-6 pt-6',
|
27
59
|
drawerClx
|
28
60
|
)}>
|
61
|
+
|
62
|
+
<DrawerHandle
|
63
|
+
className={
|
64
|
+
'absolute left-0 right-0 mx-auto top-2 ' +
|
65
|
+
'w-[100px] h-3 rounded-full bg-level-3 hover:bg-level-2 shrink-0'
|
66
|
+
}
|
67
|
+
handleClick={handleHandleClicked}
|
68
|
+
/>
|
69
|
+
|
29
70
|
{children}
|
30
71
|
<Button
|
31
72
|
variant='ghost'
|
@@ -38,6 +79,7 @@ const CommerceDrawer: React.FC<PropsWithChildren &
|
|
38
79
|
</DrawerContent>
|
39
80
|
</Drawer>
|
40
81
|
)
|
82
|
+
}
|
41
83
|
|
42
84
|
|
43
85
|
export default CommerceDrawer
|
@@ -1,44 +1,242 @@
|
|
1
1
|
'use client'
|
2
|
-
import React from 'react'
|
3
|
-
import { useRouter } from 'next/navigation'
|
2
|
+
import React, { useEffect, useRef, useState } from 'react'
|
3
|
+
import { usePathname, useRouter } from 'next/navigation'
|
4
|
+
import { action, computed, makeObservable, observable, reaction, type IReactionDisposer } from 'mobx'
|
4
5
|
import { observer } from 'mobx-react-lite'
|
5
6
|
|
6
|
-
import {
|
7
|
+
import { CarouselBuyCard, useCommerce } from '@hanzo/commerce'
|
8
|
+
|
9
|
+
import { useCommerceUI } from '../../../commerce/ui-context'
|
7
10
|
|
8
11
|
import CommerceDrawer from './drawer'
|
9
12
|
import CheckoutButton from '../checkout-button'
|
10
13
|
|
14
|
+
const BUY = '700px'
|
15
|
+
const MICRO = '120px'
|
16
|
+
const BOTH = [MICRO, BUY]
|
17
|
+
const BUY_ONLY = [BUY]
|
18
|
+
const MICRO_ONLY = [MICRO]
|
19
|
+
|
20
|
+
type DrawerMode = 'checkout' | 'added' | 'buy' | 'buy-added' | 'buy-checkout' | 'none' | 'closed' // manually
|
21
|
+
type DrawerState = 'micro' | 'buy' | 'closed'
|
22
|
+
|
23
|
+
const MODE_TO_STATE = {
|
24
|
+
checkout: 'micro',
|
25
|
+
added: 'micro',
|
26
|
+
buy: 'buy',
|
27
|
+
'buy-checkout': 'buy',
|
28
|
+
'buy-added': 'buy',
|
29
|
+
none: 'closed',
|
30
|
+
closed: 'closed'
|
31
|
+
} satisfies Record<DrawerMode, DrawerState>
|
32
|
+
|
33
|
+
const MODE_TO_POINTS = {
|
34
|
+
checkout: MICRO_ONLY,
|
35
|
+
added: BOTH,
|
36
|
+
buy: BUY_ONLY,
|
37
|
+
'buy-checkout': BOTH,
|
38
|
+
'buy-added': BOTH,
|
39
|
+
none: BOTH,
|
40
|
+
closed: BOTH
|
41
|
+
}
|
42
|
+
|
43
|
+
|
44
|
+
class ObsDrawerState {
|
45
|
+
|
46
|
+
_mode: DrawerMode = 'none'
|
47
|
+
|
48
|
+
constructor() {
|
49
|
+
makeObservable(this, {
|
50
|
+
_mode: observable,
|
51
|
+
setMode: action,
|
52
|
+
mode: computed,
|
53
|
+
state: computed,
|
54
|
+
points: computed,
|
55
|
+
modal: computed,
|
56
|
+
activePoint: computed
|
57
|
+
})
|
58
|
+
}
|
59
|
+
|
60
|
+
get mode(): DrawerMode {return this._mode}
|
61
|
+
get state(): DrawerState { return MODE_TO_STATE[this._mode] }
|
62
|
+
get points(): (number | string)[] { return MODE_TO_POINTS[this._mode] }
|
63
|
+
get modal(): boolean { return this.state !== 'micro' }
|
64
|
+
get activePoint(): number | string | null {
|
65
|
+
if (this.state === 'buy') return BUY
|
66
|
+
if (this.state === 'micro') return MICRO
|
67
|
+
return null
|
68
|
+
}
|
69
|
+
|
70
|
+
setMode = (m: DrawerMode) => {this._mode = m}
|
71
|
+
}
|
72
|
+
|
11
73
|
const CommerceUIComponent: React.FC = observer(() => {
|
12
74
|
|
75
|
+
const cmmc = useCommerce()
|
13
76
|
const ui = useCommerceUI()
|
14
77
|
const router = useRouter()
|
78
|
+
const isCheckout = usePathname() === '/checkout'
|
79
|
+
|
80
|
+
const stateRef = useRef<ObsDrawerState>(new ObsDrawerState())
|
81
|
+
const reactionDisposers = useRef<IReactionDisposer[]>([])
|
82
|
+
|
83
|
+
const [activeSnapPoint, setActiveSnapPoint] = useState<string | number | null>(null)
|
84
|
+
const setterRef = useRef<((index: number ) => void) | undefined>(undefined)
|
85
|
+
|
86
|
+
useEffect(() => {
|
87
|
+
|
88
|
+
reactionDisposers.current.push(reaction(
|
89
|
+
|
90
|
+
() => ({
|
91
|
+
buy: !!ui.buyOptionsSkuPath,
|
92
|
+
added: !isCheckout && ui.item,
|
93
|
+
checkout: !isCheckout && !cmmc.cartEmpty,
|
94
|
+
closed: ui.closed
|
95
|
+
}),
|
96
|
+
({buy, added, checkout, closed}) => {
|
97
|
+
let mode: DrawerMode = 'none' // TODO: 'closed'
|
98
|
+
if (buy) {
|
99
|
+
if (added) {
|
100
|
+
mode = 'buy-added'
|
101
|
+
}
|
102
|
+
else if (checkout) {
|
103
|
+
mode = 'buy-checkout'
|
104
|
+
}
|
105
|
+
else {
|
106
|
+
mode = 'buy'
|
107
|
+
}
|
108
|
+
}
|
109
|
+
else {
|
110
|
+
if (closed) {
|
111
|
+
mode = 'closed'
|
112
|
+
}
|
113
|
+
else if (added) {
|
114
|
+
mode = 'added'
|
115
|
+
}
|
116
|
+
else if (checkout) {
|
117
|
+
mode = 'checkout'
|
118
|
+
}
|
119
|
+
}
|
120
|
+
stateRef.current.setMode(mode)
|
121
|
+
},
|
122
|
+
{equals: (val, prev) => (
|
123
|
+
val.buy === prev.buy
|
124
|
+
&&
|
125
|
+
val.added === prev.added
|
126
|
+
&&
|
127
|
+
val.checkout === prev.checkout
|
128
|
+
&&
|
129
|
+
val.closed === prev.closed
|
130
|
+
)}
|
131
|
+
)),
|
132
|
+
reactionDisposers.current.push(reaction(
|
133
|
+
() => ( stateRef.current.state ),
|
134
|
+
(s) => {
|
135
|
+
if (s === 'buy') {
|
136
|
+
//setterRef.current?.(stateRef.current.points.length - 1)
|
137
|
+
setActiveSnapPoint(BUY)
|
138
|
+
}
|
139
|
+
else if (s === 'micro') {
|
140
|
+
//setterRef.current?.(0)
|
141
|
+
setActiveSnapPoint(MICRO)
|
142
|
+
}
|
143
|
+
}
|
144
|
+
))
|
145
|
+
return () => {
|
146
|
+
reactionDisposers.current?.forEach((d) => {d()})
|
147
|
+
}
|
148
|
+
}, [isCheckout])
|
149
|
+
|
150
|
+
const _setActiveSnapPoint = (pt: string | number | null): void => {
|
151
|
+
console.log("ON CHANGE: ", pt)
|
152
|
+
setActiveSnapPoint(pt)
|
153
|
+
}
|
15
154
|
|
16
155
|
const handleCheckout = () => {
|
17
156
|
router.push('/checkout')
|
18
157
|
}
|
19
158
|
|
20
|
-
// Should only ever be called internally to close
|
21
159
|
const reallyOnlyCloseDrawer = (b: boolean) => {
|
22
|
-
|
23
|
-
|
160
|
+
// Should only ever be called internally to close
|
161
|
+
// Using handleCloseGesture()
|
162
|
+
}
|
163
|
+
|
164
|
+
const handleHandleClicked = () => {
|
165
|
+
console.log("HANDLE CLICKED")
|
166
|
+
|
167
|
+
if (stateRef.current.state === 'buy') {
|
168
|
+
const toks = stateRef.current.mode.split('-')
|
169
|
+
if (toks.length <= 1) {
|
170
|
+
console.log("CLOSING 'BUY' ... ")
|
171
|
+
ui.hideBuyOptions()
|
172
|
+
}
|
173
|
+
else {
|
174
|
+
console.log("CLOSING 'BUY' to ", toks[1])
|
175
|
+
ui.hideBuyOptions()
|
176
|
+
}
|
177
|
+
}
|
178
|
+
else if (stateRef.current.state === 'micro') {
|
179
|
+
if (stateRef.current.mode === 'checkout') {
|
180
|
+
console.log(" CLOSING 'CHECKOUT' ... ")
|
181
|
+
ui.setClosed(true)
|
182
|
+
}
|
183
|
+
else if (stateRef.current.mode === 'added') {
|
184
|
+
console.log(" OPENING 'ADDED' ... ")
|
185
|
+
ui.showBuyOptions(ui.item?.sku ?? '')
|
186
|
+
}
|
24
187
|
}
|
25
188
|
}
|
26
189
|
|
190
|
+
const handleCloseGesture = () => {
|
191
|
+
if (stateRef.current.state === 'buy') {
|
192
|
+
console.log(" CLOSING 'BUY' ... ")
|
193
|
+
const toks = stateRef.current.mode.split('-')
|
194
|
+
if (toks.length <= 1) {
|
195
|
+
stateRef.current.setMode('none')
|
196
|
+
}
|
197
|
+
else {
|
198
|
+
stateRef.current.setMode(toks[1] as DrawerMode) // 'checkout' or 'added'
|
199
|
+
}
|
200
|
+
return true // "handled!"
|
201
|
+
}
|
202
|
+
console.log("DEFAULT CLOSE ACTION")
|
203
|
+
return false
|
204
|
+
}
|
205
|
+
|
206
|
+
|
207
|
+
const setActiveSPIndexSetter = (fn: (index: number ) => void): void => {
|
208
|
+
setterRef.current = fn
|
209
|
+
}
|
210
|
+
|
211
|
+
|
27
212
|
return (
|
28
213
|
<CommerceDrawer
|
29
|
-
open={
|
214
|
+
open={!(stateRef.current.state === 'closed')}
|
30
215
|
setOpen={reallyOnlyCloseDrawer}
|
31
|
-
drawerClx={'w-full
|
216
|
+
drawerClx={'w-full h-full'}
|
217
|
+
snapPoints={stateRef.current.points}
|
218
|
+
modal={stateRef.current.modal}
|
219
|
+
activeSnapPoint={activeSnapPoint}
|
220
|
+
setActiveSnapPoint={_setActiveSnapPoint}
|
221
|
+
handleHandleClicked={handleHandleClicked}
|
222
|
+
setActiveSPIndexSetter={setActiveSPIndexSetter}
|
223
|
+
handleCloseGesture={handleCloseGesture}
|
32
224
|
>
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
225
|
+
{stateRef.current.state === 'buy' && (
|
226
|
+
<CarouselBuyCard
|
227
|
+
skuPath={ui.buyOptionsSkuPath!}
|
228
|
+
checkoutButton={
|
229
|
+
<CheckoutButton handleCheckout={handleCheckout} className='w-full min-w-[160px] sm:max-w-[320px]'/>
|
230
|
+
}
|
231
|
+
onQuantityChanged={ui.itemQuantityChanged}
|
232
|
+
clx='w-full'
|
233
|
+
addBtnClx='w-full min-w-[160px] sm:max-w-[320px]'
|
234
|
+
selectorClx='max-w-[475px]'
|
235
|
+
/>
|
236
|
+
)}
|
237
|
+
{stateRef.current.state === 'micro' && (
|
238
|
+
<p>Mode: {stateRef.current.mode}</p>
|
239
|
+
)}
|
42
240
|
</CommerceDrawer>
|
43
241
|
)
|
44
242
|
})
|
@@ -2,7 +2,6 @@
|
|
2
2
|
import React, { useEffect, useRef } from 'react'
|
3
3
|
import { observable, type IObservableValue, reaction } from 'mobx'
|
4
4
|
import { observer } from 'mobx-react-lite'
|
5
|
-
import { type LucideProps } from 'lucide-react'
|
6
5
|
|
7
6
|
import { Button, type ButtonProps } from '@hanzo/ui/primitives'
|
8
7
|
import { cn } from '@hanzo/ui/util'
|
@@ -12,11 +11,15 @@ import * as Icons from '../icons'
|
|
12
11
|
|
13
12
|
const IconAndQuantity: React.FC<{
|
14
13
|
animateOnQuantityChange?: boolean
|
14
|
+
showArrow?: boolean
|
15
|
+
showQuantity?: boolean
|
15
16
|
clx?: string
|
16
17
|
iconClx?: string
|
17
18
|
digitClx?: string
|
18
19
|
}> = observer(({
|
19
|
-
animateOnQuantityChange=
|
20
|
+
animateOnQuantityChange=false,
|
21
|
+
showArrow=true,
|
22
|
+
showQuantity=true,
|
20
23
|
clx='',
|
21
24
|
iconClx='',
|
22
25
|
digitClx=''
|
@@ -47,6 +50,7 @@ const IconAndQuantity: React.FC<{
|
|
47
50
|
|
48
51
|
return (
|
49
52
|
<div className={cn('flex items-center justify-center', clx)}>
|
53
|
+
{showQuantity && (
|
50
54
|
<div className={cn(
|
51
55
|
'relative flex items-center justify-center mr-1',
|
52
56
|
((wiggleRef.current.get() === 'more') ?
|
@@ -60,12 +64,13 @@ const IconAndQuantity: React.FC<{
|
|
60
64
|
'absolute left-0 right-0 top-0 bottom-0',
|
61
65
|
digitClx
|
62
66
|
)}>
|
63
|
-
<div style={{color: 'white'
|
67
|
+
<div style={{/* color: 'white' tailwind bug? ,*/ fontSize: '11px', position: 'relative', top: '1px' }}>{cmmc.cartQuantity}</div>
|
64
68
|
</div>
|
65
69
|
)}
|
66
70
|
<Icons.bag width='19' height='24' className={cn('relative -top-[3px] opacity-70' , iconClx)} aria-hidden="true" />
|
67
71
|
</div>
|
68
|
-
|
72
|
+
)}
|
73
|
+
{showArrow && (<span style={{fontSize: '17px',}}>›</span>)}
|
69
74
|
</div>
|
70
75
|
)
|
71
76
|
})
|
@@ -73,6 +78,7 @@ const IconAndQuantity: React.FC<{
|
|
73
78
|
const CheckoutButton: React.FC<ButtonProps & {
|
74
79
|
handleCheckout: () => void
|
75
80
|
showQuantity?: boolean
|
81
|
+
showArrow?: boolean
|
76
82
|
animateOnQuantityChange?: boolean
|
77
83
|
centerText?: boolean
|
78
84
|
}> = ({
|
@@ -81,8 +87,10 @@ const CheckoutButton: React.FC<ButtonProps & {
|
|
81
87
|
rounded='lg',
|
82
88
|
className,
|
83
89
|
showQuantity=true,
|
90
|
+
showArrow=true,
|
84
91
|
animateOnQuantityChange=true,
|
85
92
|
centerText=true,
|
93
|
+
children,
|
86
94
|
...rest
|
87
95
|
}) => {
|
88
96
|
|
@@ -93,22 +101,27 @@ const CheckoutButton: React.FC<ButtonProps & {
|
|
93
101
|
variant={variant}
|
94
102
|
rounded={rounded}
|
95
103
|
className={cn(
|
104
|
+
'flex justify-between items-stretch group',
|
105
|
+
showQuantity ? (centerText ? 'px-1.5' : 'pl-2.5 pr-1.5') : '',
|
96
106
|
className,
|
97
|
-
'flex justify-between items-stretch',
|
98
|
-
showQuantity ? (centerText ? 'px-1.5' : 'pl-2.5 pr-1.5') : ''
|
99
107
|
)}
|
100
108
|
>
|
101
|
-
{
|
102
|
-
<IconAndQuantity clx='invisible' />
|
103
|
-
)}
|
104
|
-
<div className='flex justify-center items-center'>Checkout</div>
|
105
|
-
{showQuantity && (
|
109
|
+
{centerText && ( // must scale this one too, as it effects layout
|
106
110
|
<IconAndQuantity
|
107
|
-
|
108
|
-
|
109
|
-
|
111
|
+
showArrow={showArrow}
|
112
|
+
showQuantity={showQuantity}
|
113
|
+
clx='invisible group-hover:scale-105 transition-scale transition-duration-300'
|
110
114
|
/>
|
111
115
|
)}
|
116
|
+
{children ?? (<div className='flex justify-center items-center'>Checkout</div>)}
|
117
|
+
<IconAndQuantity
|
118
|
+
clx='group-hover:scale-105 transition-scale transition-duration-300'
|
119
|
+
animateOnQuantityChange={animateOnQuantityChange}
|
120
|
+
showArrow={showArrow}
|
121
|
+
showQuantity={showQuantity}
|
122
|
+
iconClx='fill-background'
|
123
|
+
digitClx='text-foreground group-hover:opacity-80 leading-none font-bold font-sans'
|
124
|
+
/>
|
112
125
|
</Button>
|
113
126
|
)
|
114
127
|
}
|
@@ -1,18 +1,104 @@
|
|
1
1
|
'use client'
|
2
|
-
import React from 'react'
|
2
|
+
import React, { useRef } from 'react'
|
3
3
|
import { createPortal } from 'react-dom'
|
4
4
|
import { usePathname, useRouter } from 'next/navigation'
|
5
5
|
import { observer } from 'mobx-react-lite'
|
6
6
|
|
7
7
|
import { cn } from '@hanzo/ui/util'
|
8
|
+
import { useStepAnimation } from '@hanzo/ui/util-client'
|
9
|
+
|
8
10
|
import { Image } from '@hanzo/ui/primitives'
|
9
11
|
|
10
|
-
import { useCommerceUI } from '
|
12
|
+
import { useCommerceUI } from '../../../commerce/ui-context'
|
11
13
|
|
12
14
|
import CheckoutButton from '../checkout-button'
|
13
15
|
import useAnimationClxSet from './use-anim-clx-set'
|
14
|
-
import useLaggingItemRef from './use-lagging-item-ref'
|
15
16
|
import CONST from './const'
|
17
|
+
import type { LineItem } from '@hanzo/commerce/types'
|
18
|
+
|
19
|
+
const transStyle = (t: { transition: string, from : string, to: string } | undefined) : any => (
|
20
|
+
t ? {
|
21
|
+
transitionProperty: t.transition,
|
22
|
+
transitionTimingFunction: CONST.animTimingFn,
|
23
|
+
transitionDuration: `${CONST.animDurationMs}ms`
|
24
|
+
} : {}
|
25
|
+
)
|
26
|
+
|
27
|
+
const transClx = (on: boolean, t: { transition: string, from : string, to: string } | undefined) : string => (
|
28
|
+
on ? (t?.from ?? '') : (t?.to ?? '')
|
29
|
+
)
|
30
|
+
|
31
|
+
const VARS: any = {
|
32
|
+
BR: {
|
33
|
+
pos: 'bottom-[24px] right-[66px]',
|
34
|
+
width: 'w-initial',
|
35
|
+
centerText: false,
|
36
|
+
coClx: 'w-auto',
|
37
|
+
infoClx: 'w-auto',
|
38
|
+
activeItemAnim: {
|
39
|
+
co: {
|
40
|
+
transition: 'none',
|
41
|
+
from : 'px-3 gap-2.5',
|
42
|
+
to: ''
|
43
|
+
},
|
44
|
+
coText: {
|
45
|
+
transition: 'max-width',
|
46
|
+
from : 'max-w-[100px]',
|
47
|
+
to: 'max-w-[0px]'
|
48
|
+
},
|
49
|
+
info: {
|
50
|
+
transition: 'transform, opacity',
|
51
|
+
from : 'scale-x-100 opacity-100 origin-right',
|
52
|
+
to: 'scale-x-0 opacity-0 origin-right'
|
53
|
+
}
|
54
|
+
},
|
55
|
+
showArrow: true
|
56
|
+
},
|
57
|
+
TR: {
|
58
|
+
pos: 'top-[48px] md:top-[80px] right-[28px]',
|
59
|
+
width: 'w-initial',
|
60
|
+
centerText: false,
|
61
|
+
showQuantity: false,
|
62
|
+
showArrow: true,
|
63
|
+
coClx: 'w-auto px-3 gap-1',
|
64
|
+
infoClx: 'w-auto',
|
65
|
+
activeItemAnim: {
|
66
|
+
co: {
|
67
|
+
transition: 'none',
|
68
|
+
from : 'px-3 gap-2.5',
|
69
|
+
to: ''
|
70
|
+
},
|
71
|
+
coText: {
|
72
|
+
transition: 'max-width',
|
73
|
+
from : 'max-w-[100px]',
|
74
|
+
to: 'max-w-[0px]'
|
75
|
+
},
|
76
|
+
info: {
|
77
|
+
transition: 'transform',
|
78
|
+
from : 'scale-x-100 origin-right',
|
79
|
+
to: 'scale-x-0 origin-right'
|
80
|
+
}
|
81
|
+
},
|
82
|
+
},
|
83
|
+
TRIO: {
|
84
|
+
pos: 'top-[48px] md:top-[70px] right-[28px]',
|
85
|
+
centerText: false,
|
86
|
+
showQuantity: true,
|
87
|
+
showArrow: true,
|
88
|
+
width: 'w-initial',
|
89
|
+
coClx: 'hidden',
|
90
|
+
infoClx: 'w-auto',
|
91
|
+
activeItemAnim: {
|
92
|
+
info: {
|
93
|
+
transition: 'transform, opacity',
|
94
|
+
from : 'scale-x-100 opacity-100',
|
95
|
+
to: 'scale-x-50 opacity-0'
|
96
|
+
}
|
97
|
+
},
|
98
|
+
}
|
99
|
+
}
|
100
|
+
|
101
|
+
const v = 'TR'
|
16
102
|
|
17
103
|
const CheckoutWidget: React.FC<{
|
18
104
|
clx?: string
|
@@ -26,58 +112,78 @@ const CheckoutWidget: React.FC<{
|
|
26
112
|
const clxSet = useAnimationClxSet(isCheckout)
|
27
113
|
|
28
114
|
const itemRef = useCommerceUI()
|
29
|
-
|
115
|
+
|
116
|
+
// for rendering content after itemRef.item() would return false
|
117
|
+
const persistentRef = useRef<LineItem | undefined>(undefined)
|
118
|
+
|
119
|
+
// Doing double duty of being initial step fn for StepAnimation,
|
120
|
+
// and also capturing the item for persistentRef :)
|
121
|
+
const initialStepFn = (): boolean => {
|
122
|
+
if (!!itemRef.item && !persistentRef.current) {
|
123
|
+
persistentRef.current = itemRef.item
|
124
|
+
}
|
125
|
+
return !!itemRef.item
|
126
|
+
}
|
127
|
+
const steps = useStepAnimation(initialStepFn, [CONST.animDurationMs, CONST.animDurationMs, CONST.animDurationMs])
|
30
128
|
|
31
129
|
const handleCheckout = () => { router.push('/checkout')}
|
32
130
|
|
33
131
|
return globalThis?.document?.body && createPortal(
|
34
132
|
(<div
|
35
133
|
className={cn(
|
36
|
-
|
37
|
-
'z-below-modal-2 fixed
|
38
|
-
|
134
|
+
VARS[v].width,
|
135
|
+
'z-below-modal-2 fixed ',
|
136
|
+
VARS[v].pos,
|
137
|
+
'rounded-lg',
|
39
138
|
'flex',
|
40
|
-
|
139
|
+
steps.notPast(0) ? 'bg-background' : '',
|
140
|
+
steps.notPast(1) ? 'gap-2' : '',
|
41
141
|
clxSet.asArray.join(' ')
|
42
142
|
)}
|
43
|
-
style={
|
143
|
+
style={steps.notPast(1) ? {} : VARS[v].coClx?.includes('hidden') ? {} : CONST.shadowStyle}
|
44
144
|
>
|
45
145
|
<div
|
46
146
|
className={cn(
|
47
147
|
'flex flex-row justify-between items-center',
|
48
|
-
|
49
|
-
|
148
|
+
transClx(steps.notPast(0), VARS[v].activeItemAnim.info),
|
149
|
+
VARS[v].itemClx,
|
150
|
+
steps.notPast(1) ? 'px-3 border rounded-lg bg-level-1 border-muted-3' : ''
|
50
151
|
)}
|
51
|
-
style={
|
52
|
-
transitionProperty: 'width',
|
53
|
-
transitionTimingFunction: CONST.animTimingFn,
|
54
|
-
transitionDuration: `${CONST.animDurationMs}ms`
|
55
|
-
}}
|
152
|
+
style={transStyle(VARS[v].activeItemAnim.info)}
|
56
153
|
>
|
57
|
-
{
|
58
|
-
<Image def={
|
59
|
-
)
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
{laggingRef.item && (<>
|
65
|
-
<p className='whitespace-nowrap text-sm'>{laggingRef.item.title}</p>
|
66
|
-
<p className='whitespace-nowrap text-xxs' >recently added...</p>
|
67
|
-
</>)}
|
68
|
-
</div>
|
154
|
+
{steps.notPast(1) && persistentRef.current?.img && (
|
155
|
+
<Image def={persistentRef.current.img} constrainTo={CONST.itemImgConstraint} preload className='grow-0 shrink-0'/>
|
156
|
+
)}
|
157
|
+
{steps.notPast(1) && persistentRef.current && (<div className='text-foreground grow ml-1'>
|
158
|
+
<p className='whitespace-nowrap text-ellipsis text-sm'>{persistentRef.current.title}</p>
|
159
|
+
<p className='whitespace-nowrap text-clip text-xxs' >recently added...</p>
|
160
|
+
</div>)}
|
69
161
|
</div>
|
70
162
|
<CheckoutButton
|
71
163
|
handleCheckout={handleCheckout}
|
72
|
-
centerText={
|
73
|
-
variant='primary'
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
164
|
+
centerText={VARS[v].centerText ?? !steps.notPast(0)}
|
165
|
+
variant='primary'
|
166
|
+
rounded='lg'
|
167
|
+
showQuantity={VARS[v].showQuantity ?? true}
|
168
|
+
showArrow={VARS[v].showArrow ?? true}
|
169
|
+
className={cn(
|
170
|
+
// for setting and unsetting 'gap'
|
171
|
+
transClx((VARS[v].activeItemAnim.coText ? steps.notPast(3) : true), VARS[v].activeItemAnim.co),
|
172
|
+
VARS[v].coClx
|
173
|
+
)}
|
174
|
+
style={transStyle(VARS[v].activeItemAnim.co)}
|
175
|
+
>
|
176
|
+
<div
|
177
|
+
className={cn(
|
178
|
+
'overflow-hidden',
|
179
|
+
'flex justify-center items-center',
|
180
|
+
transClx(steps.notPast(2), VARS[v].activeItemAnim.coText),
|
181
|
+
)}
|
182
|
+
style={transStyle(VARS[v].activeItemAnim.coText)}
|
183
|
+
>
|
184
|
+
Checkout
|
185
|
+
</div>
|
186
|
+
</CheckoutButton>
|
81
187
|
</div>),
|
82
188
|
globalThis?.document?.body
|
83
189
|
)
|
@@ -1,8 +1,10 @@
|
|
1
1
|
import { useEffect, useRef } from 'react'
|
2
2
|
import { reaction, runInAction} from 'mobx'
|
3
3
|
|
4
|
+
import { useCommerce } from '@hanzo/commerce'
|
5
|
+
|
4
6
|
import ObsStringSet from './obs-string-set'
|
5
|
-
import {
|
7
|
+
import { useCommerceUI } from '../../../commerce/ui-context'
|
6
8
|
|
7
9
|
export default (isCheckout: boolean): ObsStringSet => {
|
8
10
|
|
package/components/index.ts
CHANGED
@@ -10,18 +10,12 @@ export { default as MiniChart } from './mini-chart'
|
|
10
10
|
export { default as NotFound } from './not-found'
|
11
11
|
|
12
12
|
export { default as AuthListener } from './auth/auth-listener'
|
13
|
+
export { default as AddWidget } from './commerce/add-widget'
|
13
14
|
export { default as BuyDrawer } from './commerce/buy-drawer'
|
15
|
+
export { default as BuyButton } from './commerce/buy-button'
|
14
16
|
export { default as CheckoutButton } from './commerce/checkout-button'
|
15
17
|
export { default as CheckoutPanel } from './commerce/checkout-panel'
|
16
18
|
export { default as CheckoutWidget } from './commerce/checkout-widget'
|
17
19
|
export { default as LoginPanel } from './auth/login-panel'
|
18
20
|
export { default as Scripts } from './scripts'
|
19
21
|
|
20
|
-
|
21
|
-
/* PLEASE KEEP
|
22
|
-
export {
|
23
|
-
default as HeadMetadata,
|
24
|
-
getTitleFromTemplateString,
|
25
|
-
TwitterComponent
|
26
|
-
} from './head-metadata'
|
27
|
-
*/
|
package/conf/index.ts
CHANGED
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@luxfi/core",
|
3
|
-
"version": "5.0.
|
3
|
+
"version": "5.0.7",
|
4
4
|
"description": "Library that contains shared UI primitives, support for a common design system, and other boilerplate support.",
|
5
5
|
"publishConfig": {
|
6
6
|
"registry": "https://registry.npmjs.org/",
|
@@ -27,7 +27,7 @@
|
|
27
27
|
},
|
28
28
|
"exports": {
|
29
29
|
".": "./components/index.ts",
|
30
|
-
"./commerce": "./commerce/index.ts",
|
30
|
+
"./commerce-data": "./commerce/data/index.ts",
|
31
31
|
"./root-layout": "./root-layout/index.tsx",
|
32
32
|
"./server-actions": "./server-actions/index.ts",
|
33
33
|
"./next": "./next/index.ts",
|
@@ -38,8 +38,8 @@
|
|
38
38
|
},
|
39
39
|
"dependencies": {
|
40
40
|
"@hanzo/auth": "2.4.6",
|
41
|
-
"@hanzo/commerce": "7.0.
|
42
|
-
"@hanzo/ui": "3.7.
|
41
|
+
"@hanzo/commerce": "7.0.3",
|
42
|
+
"@hanzo/ui": "3.7.22",
|
43
43
|
"@next/third-parties": "^14.1.0",
|
44
44
|
"cookies-next": "^4.1.1",
|
45
45
|
"date-fns": "^3.6.0",
|
@@ -50,13 +50,15 @@
|
|
50
50
|
"peerDependencies": {
|
51
51
|
"@hookform/resolvers": "^3.3.2",
|
52
52
|
"lucide-react": "^0.344.0",
|
53
|
+
"mobx": "^6.12.0",
|
54
|
+
"mobx-react-lite": "^4.0.5",
|
53
55
|
"next": "14.1.3",
|
54
56
|
"next-themes": "^0.2.1",
|
55
|
-
"react": "^18.
|
56
|
-
"react-dom": "^18.
|
57
|
-
"react-hook-form": "^7.51.
|
57
|
+
"react": "^18.3.1",
|
58
|
+
"react-dom": "^18.3.1",
|
59
|
+
"react-hook-form": "^7.51.4",
|
58
60
|
"validator": "^13.11.0",
|
59
|
-
"zod": "3.
|
61
|
+
"zod": "3.23.8"
|
60
62
|
},
|
61
63
|
"devDependencies": {
|
62
64
|
"@mdx-js/loader": "^3.0.0",
|
@@ -64,8 +66,8 @@
|
|
64
66
|
"@types/facebook-pixel": "^0.0.30",
|
65
67
|
"@types/gtag.js": "^0.0.19",
|
66
68
|
"@types/mdx": "^2.0.9",
|
67
|
-
"@types/react": "^18.2
|
68
|
-
"@types/react-dom": "^18.
|
69
|
+
"@types/react": "^18.3.2",
|
70
|
+
"@types/react-dom": "^18.3.0",
|
69
71
|
"tailwindcss": "^3.4.2",
|
70
72
|
"typescript": "5.3.3"
|
71
73
|
}
|
package/root-layout/index.tsx
CHANGED
@@ -10,9 +10,10 @@ import { CommerceProvider } from '@hanzo/commerce'
|
|
10
10
|
import getAppRouterBodyFontClasses from '../next/font/get-app-router-font-classes'
|
11
11
|
import { FacebookPixelHead } from '../next/analytics/pixel-analytics'
|
12
12
|
|
13
|
+
import { CommerceUIProvider } from '../commerce/ui-context'
|
13
14
|
import { AuthListener, ChatWidget, Header, Scripts } from '../components'
|
15
|
+
|
14
16
|
import BuyDrawer from '../components/commerce/buy-drawer'
|
15
|
-
import CheckoutWidget from '../components/commerce/checkout-widget'
|
16
17
|
|
17
18
|
import { selectionUISpecifiers } from '../conf'
|
18
19
|
import type SiteDef from '../types/site-def'
|
@@ -99,9 +100,10 @@ const RootLayout: React.FC<PropsWithChildren & {
|
|
99
100
|
options={siteDef.commerce!.options}
|
100
101
|
uiSpecs={selectionUISpecifiers}
|
101
102
|
>
|
102
|
-
<
|
103
|
-
|
104
|
-
|
103
|
+
<CommerceUIProvider >
|
104
|
+
<Guts />
|
105
|
+
<BuyDrawer />
|
106
|
+
</CommerceUIProvider>
|
105
107
|
</CommerceProvider>
|
106
108
|
) : (
|
107
109
|
<Guts />
|
@@ -0,0 +1,154 @@
|
|
1
|
+
[vaul-drawer] {
|
2
|
+
touch-action: none;
|
3
|
+
transition: transform 0.5s cubic-bezier(0.32, 0.72, 0, 1);
|
4
|
+
}
|
5
|
+
|
6
|
+
[vaul-drawer][vaul-drawer-direction='bottom'] {
|
7
|
+
transform: translate3d(0, 100%, 0);
|
8
|
+
}
|
9
|
+
|
10
|
+
[vaul-drawer][vaul-drawer-direction='top'] {
|
11
|
+
transform: translate3d(0, -100%, 0);
|
12
|
+
}
|
13
|
+
|
14
|
+
[vaul-drawer][vaul-drawer-direction='left'] {
|
15
|
+
transform: translate3d(-100%, 0, 0);
|
16
|
+
}
|
17
|
+
|
18
|
+
[vaul-drawer][vaul-drawer-direction='right'] {
|
19
|
+
transform: translate3d(100%, 0, 0);
|
20
|
+
}
|
21
|
+
|
22
|
+
.vaul-dragging .vaul-scrollable [vault-drawer-direction='top'] {
|
23
|
+
overflow-y: hidden !important;
|
24
|
+
}
|
25
|
+
.vaul-dragging .vaul-scrollable [vault-drawer-direction='bottom'] {
|
26
|
+
overflow-y: hidden !important;
|
27
|
+
}
|
28
|
+
|
29
|
+
.vaul-dragging .vaul-scrollable [vault-drawer-direction='left'] {
|
30
|
+
overflow-x: hidden !important;
|
31
|
+
}
|
32
|
+
|
33
|
+
.vaul-dragging .vaul-scrollable [vault-drawer-direction='right'] {
|
34
|
+
overflow-x: hidden !important;
|
35
|
+
}
|
36
|
+
|
37
|
+
[vaul-drawer][vaul-drawer-visible='true'][vaul-drawer-direction='top'] {
|
38
|
+
transform: translate3d(0, var(--snap-point-height, 0), 0);
|
39
|
+
}
|
40
|
+
|
41
|
+
[vaul-drawer][vaul-drawer-visible='true'][vaul-drawer-direction='bottom'] {
|
42
|
+
transform: translate3d(0, var(--snap-point-height, 0), 0);
|
43
|
+
}
|
44
|
+
|
45
|
+
[vaul-drawer][vaul-drawer-visible='true'][vaul-drawer-direction='left'] {
|
46
|
+
transform: translate3d(var(--snap-point-height, 0), 0, 0);
|
47
|
+
}
|
48
|
+
|
49
|
+
[vaul-drawer][vaul-drawer-visible='true'][vaul-drawer-direction='right'] {
|
50
|
+
transform: translate3d(var(--snap-point-height, 0), 0, 0);
|
51
|
+
}
|
52
|
+
|
53
|
+
[vaul-overlay] {
|
54
|
+
opacity: 0;
|
55
|
+
transition: opacity 0.5s cubic-bezier(0.32, 0.72, 0, 1);
|
56
|
+
}
|
57
|
+
|
58
|
+
[vaul-overlay][vaul-drawer-visible='true'] {
|
59
|
+
opacity: 1;
|
60
|
+
}
|
61
|
+
|
62
|
+
[vaul-drawer]::after {
|
63
|
+
content: '';
|
64
|
+
position: absolute;
|
65
|
+
background: inherit;
|
66
|
+
background-color: inherit;
|
67
|
+
}
|
68
|
+
|
69
|
+
[vaul-drawer][vaul-drawer-direction='top']::after {
|
70
|
+
top: initial;
|
71
|
+
bottom: 100%;
|
72
|
+
left: 0;
|
73
|
+
right: 0;
|
74
|
+
height: 200%;
|
75
|
+
}
|
76
|
+
|
77
|
+
[vaul-drawer][vaul-drawer-direction='bottom']::after {
|
78
|
+
top: 100%;
|
79
|
+
bottom: initial;
|
80
|
+
left: 0;
|
81
|
+
right: 0;
|
82
|
+
height: 200%;
|
83
|
+
}
|
84
|
+
|
85
|
+
[vaul-drawer][vaul-drawer-direction='left']::after {
|
86
|
+
left: initial;
|
87
|
+
right: 100%;
|
88
|
+
top: 0;
|
89
|
+
bottom: 0;
|
90
|
+
width: 200%;
|
91
|
+
}
|
92
|
+
|
93
|
+
[vaul-drawer][vaul-drawer-direction='right']::after {
|
94
|
+
left: 100%;
|
95
|
+
right: initial;
|
96
|
+
top: 0;
|
97
|
+
bottom: 0;
|
98
|
+
width: 200%;
|
99
|
+
}
|
100
|
+
|
101
|
+
[vaul-handle] {
|
102
|
+
/* opacity: 0.8; */
|
103
|
+
touch-action: pan-y;
|
104
|
+
cursor: grab;
|
105
|
+
}
|
106
|
+
|
107
|
+
/* [vaul-handle]:hover, */
|
108
|
+
[vaul-handle]:active {
|
109
|
+
opacity: 1;
|
110
|
+
}
|
111
|
+
|
112
|
+
[vaul-handle]:active {
|
113
|
+
cursor: grabbing;
|
114
|
+
}
|
115
|
+
|
116
|
+
[vaul-handle-hitarea] {
|
117
|
+
position: absolute;
|
118
|
+
left: 50%;
|
119
|
+
top: 50%;
|
120
|
+
transform: translate(-50%, -50%);
|
121
|
+
width: max(100%, 2.75rem); /* 44px */
|
122
|
+
height: max(100%, 2.75rem); /* 44px */
|
123
|
+
touch-action: inherit;
|
124
|
+
}
|
125
|
+
|
126
|
+
[vaul-overlay][vaul-snap-points='true']:not([vaul-snap-points-overlay='true']):not([data-state='closed']) {
|
127
|
+
opacity: 0;
|
128
|
+
}
|
129
|
+
|
130
|
+
[vaul-overlay][vaul-snap-points-overlay='true']:not([vaul-drawer-visible='false']) {
|
131
|
+
opacity: 1;
|
132
|
+
}
|
133
|
+
|
134
|
+
/* This will allow us to not animate via animation, but still benefit from delaying unmount via Radix. */
|
135
|
+
@keyframes fake-animation {
|
136
|
+
from {
|
137
|
+
}
|
138
|
+
to {
|
139
|
+
}
|
140
|
+
}
|
141
|
+
|
142
|
+
@media (pointer: fine) {
|
143
|
+
[vaul-handle-hitarea] {
|
144
|
+
width: 100%;
|
145
|
+
height: 100%;
|
146
|
+
}
|
147
|
+
}
|
148
|
+
|
149
|
+
@media (hover: hover) and (pointer: fine) {
|
150
|
+
[vaul-drawer] {
|
151
|
+
user-select: none;
|
152
|
+
}
|
153
|
+
}
|
154
|
+
|
package/tsconfig.json
CHANGED
@@ -1,30 +0,0 @@
|
|
1
|
-
import { useEffect, useRef } from 'react'
|
2
|
-
import { reaction } from 'mobx'
|
3
|
-
|
4
|
-
import type { LineItem, ObsLineItemRef } from "@hanzo/commerce/types"
|
5
|
-
import { LineItemRef } from '@hanzo/commerce'
|
6
|
-
|
7
|
-
export default (orig: ObsLineItemRef, lagMs: number): ObsLineItemRef => {
|
8
|
-
|
9
|
-
// a ref that is synced to 'orig', but persists for lagMs longer
|
10
|
-
// so ui does not jump while animating out.
|
11
|
-
// (Fascilitates for start and end states in animation)
|
12
|
-
const laggingRef = useRef<LineItemRef>(new LineItemRef())
|
13
|
-
|
14
|
-
useEffect(() => (
|
15
|
-
reaction(
|
16
|
-
() => (orig.item),
|
17
|
-
(item: LineItem | undefined) => {
|
18
|
-
if (item) {
|
19
|
-
laggingRef.current.set(item)
|
20
|
-
}
|
21
|
-
else {
|
22
|
-
setTimeout(() => { laggingRef.current.set(undefined) }, lagMs)
|
23
|
-
}
|
24
|
-
},
|
25
|
-
{equals: (val, prev) => (val?.sku === prev?.sku)}
|
26
|
-
)
|
27
|
-
), [])
|
28
|
-
|
29
|
-
return laggingRef.current
|
30
|
-
}
|
File without changes
|
/package/commerce/{EDIT-ME-bullion-market-prices.ts → data/EDIT-ME-bullion-market-prices.ts}
RENAMED
File without changes
|
File without changes
|
/package/commerce/{assign-videos-by-family-group.ts → data/assign-videos-by-family-group.ts}
RENAMED
File without changes
|
File without changes
|
File without changes
|