@luxfi/core 5.0.5 → 5.0.6
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/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.6",
|
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
|