@luxfi/core 5.2.6 → 5.2.8

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.
@@ -19,6 +19,13 @@ import type { CommerceDrawer, SelectAndBuy, RecentActivity } from './store'
19
19
  import { CommerceUIStore } from './store'
20
20
  import conf from './conf'
21
21
 
22
+ const LOG = false ////////////////////
23
+ const log = (s: string) => {
24
+ if (LOG) {
25
+ console.log('CMMC UI CONTEXT ' + s)
26
+ }
27
+ }
28
+
22
29
  // https://dev.to/ivandotv/mobx-server-side-rendering-with-next-js-4m18
23
30
  enableStaticRendering(typeof window === "undefined")
24
31
 
@@ -41,13 +48,9 @@ const CommerceUIProvider: React.FC<PropsWithChildren> = ({
41
48
  }) => {
42
49
 
43
50
  const cmmc = useCommerce()
44
- const pathName = usePathname()
45
- const isCheckout = pathName === '/checkout'
46
- const ref = useRef<CommerceUIStore>(new CommerceUIStore(cmmc, conf))
47
-
48
- if (ref.current.checkingOut != isCheckout) {
49
- ref.current.setCheckingOut(isCheckout)
50
- }
51
+ const pathname = usePathname()
52
+ const storeRef = useRef<CommerceUIStore>(new CommerceUIStore(cmmc, conf))
53
+ const prevPathRef = useRef<string>('initial')
51
54
 
52
55
  const onResize = () => {
53
56
  const width = window.innerWidth
@@ -58,36 +61,57 @@ const CommerceUIProvider: React.FC<PropsWithChildren> = ({
58
61
  desktopMin = parseInt(twConfig.theme?.screens.md)
59
62
  }
60
63
  if (width < desktopMin) {
61
- if (!ref.current.isMobile) {
62
- ref.current.setMobile(true)
64
+ if (!storeRef.current.isMobile) {
65
+ storeRef.current.setMobile(true)
63
66
  }
64
67
  }
65
- else if (ref.current.isMobile) {
66
- ref.current.setMobile(false)
68
+ else if (storeRef.current.isMobile) {
69
+ storeRef.current.setMobile(false)
67
70
  }
68
71
  }
69
- ref.current.setViewportHeight(window.innerHeight)
72
+ storeRef.current.setViewportHeight(window.innerHeight)
70
73
  }
71
74
 
72
75
  const onResize_debounced = useDebounceCallback(onResize, 500)
73
76
 
74
77
  useLayoutEffect(() => {
75
- ref.current.initialize()
78
+ storeRef.current.initialize()
76
79
  onResize()
77
80
  window.addEventListener('resize', onResize_debounced);
78
81
  return () => {
79
82
  window.removeEventListener('resize', onResize_debounced)
80
- ref.current.dispose()
83
+ storeRef.current.dispose()
81
84
  }
82
85
  }, [])
83
86
 
84
87
  useEffect(() => {
85
- ref.current.reset()
86
- }, [pathName])
88
+ const checkingOut = (pathname === '/checkout')
89
+
90
+ /////////////////////////////////////
91
+ log("useEffect: pathname: " + pathname)
92
+ log("useEffect: prev pathname: " + prevPathRef.current)
93
+
94
+ if (storeRef.current.checkingOut === undefined || storeRef.current._checkingOut!== checkingOut) {
95
+ log("useEffect: setting checkingOut to: " + checkingOut) /////////////////////////////////////
96
+ storeRef.current.setCheckingOut(checkingOut)
97
+ }
98
+ if ( prevPathRef.current === 'initial') {
99
+ prevPathRef.current = pathname
100
+ // no need to reset
101
+ }
102
+ else if (
103
+ !checkingOut
104
+ &&
105
+ prevPathRef.current !== pathname
106
+ ) {
107
+ storeRef.current.reset()
108
+ prevPathRef.current = pathname
109
+ }
110
+ }, [pathname])
87
111
 
88
112
 
89
113
  return (
90
- <CommerceUIContext.Provider value={ref.current}>
114
+ <CommerceUIContext.Provider value={storeRef.current}>
91
115
  {children}
92
116
  </CommerceUIContext.Provider>
93
117
  )
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  action,
3
+ autorun,
3
4
  computed,
4
5
  makeObservable,
5
6
  observable,
@@ -9,9 +10,10 @@ import {
9
10
 
10
11
  import type { CommerceService, LineItem, ObsLineItemRef } from '@hanzo/commerce/types'
11
12
 
12
- const logOn = false
13
+ const LOG = false ////////////////////
14
+
13
15
  const log = (s: string) => {
14
- if (logOn) {
16
+ if (LOG) {
15
17
  console.log('COMMERCE_UI ' + s)
16
18
  }
17
19
  }
@@ -69,7 +71,7 @@ class CommerceUIStore implements
69
71
 
70
72
  _currentSkuPath: string | undefined = undefined
71
73
  _closedByUser: boolean = false
72
- _checkingOut: boolean = false
74
+ _checkingOut: boolean | undefined = undefined
73
75
  _ignoreStateChange: boolean = false
74
76
  _activePoint: SnapPoint | null = null
75
77
 
@@ -116,6 +118,7 @@ class CommerceUIStore implements
116
118
  showCheckout: computed,
117
119
  snapPointPx: computed,
118
120
  state: computed,
121
+ open: computed
119
122
  })
120
123
  }
121
124
 
@@ -135,6 +138,16 @@ class CommerceUIStore implements
135
138
  }
136
139
  }
137
140
  ))
141
+ this._reactionDisposers.push(autorun(() => {
142
+ log('AUTORUN: OPEN: ' + this.open)
143
+ log('AUTORUN:' + // ===============
144
+ '[showCheckout: ' + this.showCheckout +
145
+ '], [showAdded: ' + this.showAdded +
146
+ '], [showBuy: ' + this.showBuy +
147
+ '], [closedByUser: ' + this._closedByUser +
148
+ '], [checkingOut: ' + this._checkingOut + ']'
149
+ ) // ===========
150
+ }))
138
151
  }
139
152
 
140
153
  reset = () => {
@@ -191,7 +204,7 @@ class CommerceUIStore implements
191
204
  get ignoreStateChange(): boolean { return this._ignoreStateChange }
192
205
  setIgnoreStateChange = (b: boolean): void => { this._ignoreStateChange = b}
193
206
 
194
- get checkingOut(): boolean { return this._checkingOut }
207
+ get checkingOut(): boolean | undefined { return this._checkingOut }
195
208
  setCheckingOut = (b: boolean): void => { this._checkingOut = b }
196
209
 
197
210
  get activePoint(): SnapPoint | null { return this._activePoint }
@@ -218,26 +231,41 @@ class CommerceUIStore implements
218
231
  }
219
232
 
220
233
  get open(): boolean {
234
+
235
+ log('open():' + // ===============
236
+ ' showCheckout: ' + this.showCheckout +
237
+ ' showAdded: ' + this.showAdded +
238
+ ' showBuy: ' + this.showBuy
239
+ ) // ===========
240
+
241
+
242
+
221
243
  return (
222
- !this.closedByUser
244
+ this._checkingOut !== undefined
245
+ &&
246
+ !this._checkingOut
247
+ &&
248
+ !this.closedByUser
223
249
  &&
224
250
  (this.showCheckout || this.showAdded || this.showBuy)
225
251
  )
226
252
  }
227
253
 
228
254
  get state(): DrawerState {
229
- if (this.showBuy) {
230
- return 'full'
231
- }
232
- else if (!this.closedByUser && (this.showAdded || this.showCheckout)) {
233
- return 'micro'
255
+ if (!this.closedByUser && !this._checkingOut) {
256
+ if (this.showBuy) {
257
+ return 'full'
258
+ }
259
+ else if (this.showAdded || this.showCheckout) {
260
+ return 'micro'
261
+ }
234
262
  }
235
263
  return 'closed'
236
264
  }
237
265
 
238
266
  get showBuy(): boolean {return !!this.currentSkuPath}
239
- get showAdded(): boolean { return !this._checkingOut && !!this.item}
240
- get showCheckout(): boolean { return !this._checkingOut && !this._service.cartEmpty}
267
+ get showAdded(): boolean { return !!this.item}
268
+ get showCheckout(): boolean { return !this._service.cartEmpty}
241
269
  get modal(): boolean { return this.state !== 'micro'}
242
270
 
243
271
  get microHeight(): SnapPoint {
@@ -58,7 +58,7 @@ const LoginPanel: React.FC<{
58
58
  onClick={close}
59
59
  className='w-fit !min-w-0 p-2'
60
60
  >
61
- <Logo size='md' spanClassName='!cursor-pointer' layout='text-only'/>
61
+ <Logo size='md' textClx='!cursor-pointer' variant='text-only'/>
62
62
  </Button>
63
63
  <Carousel
64
64
  options={{ align: 'center', loop: true }}
@@ -0,0 +1,42 @@
1
+ 'use client'
2
+ import React from 'react'
3
+ import { useRouter } from 'next/navigation'
4
+
5
+ import { ChevronLeft } from 'lucide-react'
6
+
7
+
8
+ import {
9
+ Button,
10
+ buttonVariants,
11
+ } from '@hanzo/ui/primitives'
12
+
13
+ import type { VariantProps } from '@hanzo/ui/util'
14
+
15
+ const BackButton: React.FC<{
16
+ variant?: VariantProps<typeof buttonVariants>['variant']
17
+ size?: VariantProps<typeof buttonVariants>['size']
18
+ clx?: string
19
+ iconClx?: string
20
+ }> = ({
21
+ variant='ghost',
22
+ size='default',
23
+ clx='',
24
+ iconClx='',
25
+ }) => {
26
+
27
+ const router = useRouter()
28
+ const back = () => {router.back()}
29
+
30
+ return (
31
+ <Button
32
+ variant={variant}
33
+ size={size}
34
+ onClick={back}
35
+ className={clx}
36
+ >
37
+ <ChevronLeft className={iconClx}/>
38
+ </Button>
39
+ )
40
+ }
41
+
42
+ export default BackButton
@@ -1,56 +1,73 @@
1
1
  'use client'
2
2
  import React, { type PropsWithChildren } from 'react'
3
+ import { observer } from 'mobx-react-lite'
3
4
 
4
5
  import { ScrollArea, StepIndicator } from '@hanzo/ui/primitives'
5
6
  import { AuthWidget } from '@hanzo/auth/components'
6
- import { CartPanel } from '@hanzo/commerce'
7
+ import { CartPanel, useCommerce } from '@hanzo/commerce'
8
+ import { cn } from '@hanzo/ui/util'
7
9
 
8
- import * as Icons from '../../icons'
10
+ import { BackButton, Logo, Tooltip } from '../..'
9
11
  import DesktopBagCarousel from './dt-bag-carousel'
10
- import CloseButton from './close-button'
11
- import { cn } from '@hanzo/ui/util'
12
12
  import LinksRow from './links-row'
13
13
 
14
14
  const DesktopCheckoutPanel: React.FC<PropsWithChildren & {
15
15
  index: number
16
16
  stepNames: string[]
17
- close:() => void
17
+ close: () => void
18
18
  className?: string
19
- }> = ({
19
+ }> = observer(({
20
20
  index,
21
21
  stepNames,
22
22
  close,
23
23
  className='',
24
24
  children
25
- }) => (
25
+ }) => {
26
26
 
27
+ const cmmc = useCommerce()
28
+
29
+ return (
27
30
  <div /* id='CHECKOUT_PANEL' */ className={cn('grid grid-cols-2', className)}>
28
- <div className='w-full h-full bg-background flex flex-row items-start justify-end'>
29
- <div className='w-full max-w-[750px] relative flex flex-col items-center justify-start p-8'>
30
- <CloseButton close={close} size='md'/>
31
- <div className='w-full max-w-[550px] mx-auto flex flex-col gap-3'>
32
- <DesktopBagCarousel className='h-[260px] w-[360px] lg:w-[420px] mx-auto -mt-8' constrainTo={{w: 250, h: 250}}/>
31
+ <div key={1} className='w-full h-full bg-background flex flex-row items-start justify-end'>
32
+ <div className='w-full h-full max-w-[750px] relative flex flex-col items-stretch justify-start px-8 pb-8'>
33
+ <div key={1} className='h-[80px] grow-0 flex flex-row items-center z-10' >
34
+ <Logo onClick={close} size='md' href='/' variant='text-only' outerClx='logo-outer-tooltip-class' />
35
+ <Tooltip select='.logo-outer-tooltip-class' text='home' position='right' offset={6}/>
36
+ </div>
37
+ <BackButton size='sm' clx={
38
+ 'z-10 absolute top-14 left-6 !px-0 aspect-square ' +
39
+ 'rounded-full hover:!bg-level-3 ' +
40
+ //'border border-transparent hover:border-muted-2 ' +
41
+ 'back-button-tooltip-class '
42
+ }/>
43
+ <Tooltip select='.back-button-tooltip-class' text='back' position='right' offset={5}/>
44
+ <div key={2} className={cn(
45
+ 'w-full grow min-h-0 max-w-[550px] mx-auto flex flex-col gap-3',
46
+ (cmmc.cartItems.length > 4 ? 'justify-between' : 'justify-start gap-10 pt-10')
47
+ )}>
48
+ <DesktopBagCarousel className='grow-0 h-[260px] w-[360px] lg:w-[420px] mx-auto -mt-8' constrainTo={{w: 250, h: 250}}/>
33
49
  <CartPanel
34
50
  className='w-full border-none p-0'
35
- itemClx='mb-3'
36
- totalClx='sticky -bottom-1 p-1 bg-background'
51
+ itemClx='mb-2'
52
+ totalClx='sticky bottom-0 bg-background'
37
53
  listClx='pr-3'
38
54
  scrollAfter={5}
39
- scrollHeightClx='h-[50vh]'
55
+ scrollHeightClx='min-h-[50vh] grow'
40
56
  showPromoCode
41
57
  showShipping
58
+ selectItems
42
59
  />
43
60
  </div>
44
61
  </div>
45
62
  </div>
46
- <div className='w-full h-full flex flex-col bg-level-1 min-h-screen justify-between'>
63
+ <div key={2} className='w-full h-full flex flex-col bg-level-1 min-h-screen justify-between'>
47
64
  <ScrollArea className='w-full flex flex-row items-start justify-start overflow-y-auto'>
48
65
  <div className='h-full w-full max-w-[750px] relative flex flex-col items-center px-8 pt-0'>
49
- <div className='bg-level-1 sticky h-30 pb-8 w-full top-0 flex justify-center items-end'>
66
+ <div key={1} className='bg-level-1 sticky h-30 pb-8 w-full top-0 flex justify-center items-end'>
50
67
  <AuthWidget noLogin className='hidden md:flex absolute top-4 right-4 '/>
51
68
  <StepIndicator dotSizeRem={1.5} steps={stepNames} currentStep={index} className='gap-2 text-base w-pr-70' />
52
69
  </div>
53
- <div className='w-full max-w-[550px] mx-auto pb-10'>
70
+ <div key={2} className='w-full max-w-[550px] mx-auto pb-10'>
54
71
  {children}
55
72
  </div>
56
73
  </div>
@@ -63,5 +80,6 @@ const DesktopCheckoutPanel: React.FC<PropsWithChildren & {
63
80
  </div>
64
81
  </div>
65
82
  )
83
+ })
66
84
 
67
85
  export default DesktopCheckoutPanel
@@ -6,7 +6,7 @@ import { cn } from '@hanzo/ui/util'
6
6
  import { AuthWidget } from '@hanzo/auth/components'
7
7
  import { CartAccordian } from '@hanzo/commerce'
8
8
 
9
- import CloseButton from './close-button'
9
+ import { Logo } from '../..'
10
10
  import BagButton from '../bag-button'
11
11
  import LinksRow from './links-row'
12
12
 
@@ -25,7 +25,7 @@ const MobileCheckoutPanel: React.FC<PropsWithChildren & {
25
25
 
26
26
  <div /* id='MOBILE_GRID' */ className={cn('bg-background flex flex-col justify-start px-4', className)}>
27
27
  <div className='sticky top-0 w-full flex flex-row justify-between items-center bg-background'>
28
- <CloseButton close={close} size='xs' />
28
+ <Logo onClick={close} size='xs' href='/' />
29
29
  {/* Need wrapper div since 'noLogin' returns null if no logged in user */}
30
30
  <div className='w-10 h-10 flex items-center justify-center'><AuthWidget noLogin className=''/></div>
31
31
  </div>
@@ -17,111 +17,6 @@ import {
17
17
  } from '@hanzo/ui/primitives'
18
18
  import Warpcast from "../icons/warpcast"
19
19
 
20
- // const components: { title: string; href: string; description: string }[] = [
21
- // {
22
- // title: "Alert Dialog",
23
- // href: "/docs/primitives/alert-dialog",
24
- // description:
25
- // "A modal dialog that interrupts the user with important content and expects a response.",
26
- // },
27
- // {
28
- // title: "Hover Card",
29
- // href: "/docs/primitives/hover-card",
30
- // description:
31
- // "For sighted users to preview content available behind a link.",
32
- // },
33
- // {
34
- // title: "Progress",
35
- // href: "/docs/primitives/progress",
36
- // description:
37
- // "Displays an indicator showing the completion progress of a task, typically displayed as a progress bar.",
38
- // },
39
- // {
40
- // title: "Scroll-area",
41
- // href: "/docs/primitives/scroll-area",
42
- // description: "Visually or semantically separates content.",
43
- // },
44
- // {
45
- // title: "Tabs",
46
- // href: "/docs/primitives/tabs",
47
- // description:
48
- // "A set of layered sections of content—known as tab panels—that are displayed one at a time.",
49
- // },
50
- // {
51
- // title: "Tooltip",
52
- // href: "/docs/primitives/tooltip",
53
- // description:
54
- // "A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.",
55
- // },
56
- // ]
57
-
58
- // export function NavigationMenuDemo() {
59
- // return (
60
- // <NavigationMenu>
61
- // <NavigationMenuList>
62
- // <NavigationMenuItem>
63
- // <NavigationMenuTrigger>Getting started</NavigationMenuTrigger>
64
- // <NavigationMenuContent>
65
- // <ul className="grid gap-3 p-6 md:w-[400px] lg:w-[500px] lg:grid-cols-[.75fr_1fr]">
66
- // <li className="row-span-3">
67
- // <NavigationMenuLink asChild>
68
- // <a
69
- // className="flex h-full w-full select-none flex-col justify-end rounded-md bg-gradient-to-b from-muted/50 to-muted p-6 no-underline outline-none focus:shadow-md"
70
- // href="/"
71
- // >
72
- // {/* <Icons.logo className="h-6 w-6" /> */}
73
- // <div className="mb-2 mt-4 text-lg font-medium">
74
- // shadcn/ui
75
- // </div>
76
- // <p className="text-sm leading-tight text-muted-foreground">
77
- // Beautifully designed components that you can copy and
78
- // paste into your apps. Accessible. Customizable. Open
79
- // Source.
80
- // </p>
81
- // </a>
82
- // </NavigationMenuLink>
83
- // </li>
84
- // <ListItem href="/docs" title="Introduction">
85
- // Re-usable components built using Radix UI and Tailwind CSS.
86
- // </ListItem>
87
- // <ListItem href="/docs/installation" title="Installation">
88
- // How to install dependencies and structure your app.
89
- // </ListItem>
90
- // <ListItem href="/docs/primitives/typography" title="Typography">
91
- // Styles for headings, paragraphs, lists...etc
92
- // </ListItem>
93
- // </ul>
94
- // </NavigationMenuContent>
95
- // </NavigationMenuItem>
96
- // <NavigationMenuItem>
97
- // <NavigationMenuTrigger>Components</NavigationMenuTrigger>
98
- // <NavigationMenuContent>
99
- // <ul className="w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-1 lg:w-[600px] ">
100
- // {components.map((component) => (
101
- // <ListItem
102
- // key={component.title}
103
- // title={component.title}
104
- // href={component.href}
105
- // >
106
- // {component.description}
107
- // </ListItem>
108
- // ))}
109
- // </ul>
110
- // </NavigationMenuContent>
111
- // </NavigationMenuItem>
112
- // <NavigationMenuItem>
113
- // <Link href="/docs" legacyBehavior passHref>
114
- // <NavigationMenuLink className={navigationMenuTriggerStyle()}>
115
- // Documentation
116
- // </NavigationMenuLink>
117
- // </Link>
118
- // </NavigationMenuItem>
119
- // </NavigationMenuList>
120
- // </NavigationMenu>
121
- // )
122
- // }
123
-
124
-
125
20
  const DesktopNav: React.FC<{
126
21
  links: LinkDefExtended[],
127
22
  }> = ({
@@ -135,7 +30,7 @@ const DesktopNav: React.FC<{
135
30
 
136
31
  if (el.isAIMenu) {
137
32
  return (
138
- <NavigationMenuItem>
33
+ <NavigationMenuItem key={index}>
139
34
  <Link href={el.href} legacyBehavior passHref>
140
35
  <NavigationMenuLink className={navigationMenuTriggerStyle()}>
141
36
  {el.title}
@@ -145,11 +40,11 @@ const DesktopNav: React.FC<{
145
40
  )
146
41
  } else if (el.title == 'Community') {
147
42
  return (
148
- <NavigationMenuItem>
43
+ <NavigationMenuItem key={index}>
149
44
  <NavigationMenuTrigger>{el.title}</NavigationMenuTrigger>
150
45
  <NavigationMenuContent>
151
- <ul className="grid md:grid-cols-2 gap-3 p-6 md:w-[400px] lg:w-[500px]">
152
- <li className="row-span-3">
46
+ <ul className="grid md:grid-cols-2 gap-3 p-6 md:w-[400px] lg:w-[500px]" key={index}>
47
+ <li className="row-span-3" key='0'>
153
48
  <NavigationMenuLink asChild>
154
49
  <a
155
50
  className="flex h-full w-full select-none flex-col justify-end rounded-md bg-gradient-to-b from-muted/50 to-muted p-6 no-underline outline-none focus:shadow-md"
@@ -165,12 +60,12 @@ const DesktopNav: React.FC<{
165
60
  </a>
166
61
  </NavigationMenuLink>
167
62
  </li>
168
- {el.childMenu?.map((component) => (
169
- <div className="relative flex items-center my-2">
63
+ {el.childMenu?.map((component, index) => (
64
+ <div className="relative flex items-center my-2" key={index}>
170
65
  <div className="mr-2 mt-0">
171
66
  {component.icon}
172
67
  </div>
173
- <ListItem href={component.href} title={component.title}>
68
+ <ListItem href={component.href} title={component.title} key={index}>
174
69
  {component.contents}
175
70
  </ListItem>
176
71
  </div>
@@ -182,13 +77,13 @@ const DesktopNav: React.FC<{
182
77
  )
183
78
  } else {
184
79
  return (
185
- <NavigationMenuItem>
80
+ <NavigationMenuItem key={index}>
186
81
  <NavigationMenuTrigger>{el.title}</NavigationMenuTrigger>
187
82
  <NavigationMenuContent>
188
- <ul className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[500px] ">
189
- {el.childMenu?.map((component) => (
83
+ <ul className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[500px] " key={index}>
84
+ {el.childMenu?.map((component, index) => (
190
85
  <ListItem
191
- key={component.title}
86
+ key={index}
192
87
  title={component.title}
193
88
  href={component.href}
194
89
  >
@@ -211,9 +106,9 @@ export default DesktopNav
211
106
  const ListItem = React.forwardRef<
212
107
  React.ElementRef<"a">,
213
108
  React.ComponentPropsWithoutRef<"a">
214
- >(({ className, title, children, ...props }, ref) => {
109
+ >(({ className, title, children, key, ...props }, ref) => {
215
110
  return (
216
- <li>
111
+ <li key={key}>
217
112
  <NavigationMenuLink asChild>
218
113
  <a
219
114
  ref={ref}
@@ -27,14 +27,6 @@ const CommerceUIComponent: React.FC = observer(() => {
27
27
  router.push('/checkout')
28
28
  }
29
29
 
30
- // see handleCloseGesture()
31
- const setOpen = (b: boolean): void => {
32
- if (!b) {
33
- if (!drawer.closedByUser) {
34
- drawer.setClosedByUser(true)
35
- }
36
- }
37
- }
38
30
 
39
31
  const handleHandleClicked = (): void => {
40
32
 
@@ -64,19 +56,10 @@ const CommerceUIComponent: React.FC = observer(() => {
64
56
  return false
65
57
  }
66
58
 
67
-
68
59
  return (
69
60
  <CommerceDrawer
70
- open={drawer.open}
71
- setOpen={setOpen}
72
- snapPoints={drawer.points}
73
- modal={drawer.modal}
74
- activeSnapPoint={drawer.activePoint}
75
- setActiveSnapPoint={drawer.onActivePointChanged.bind(drawer)}
76
61
  handleHandleClicked={handleHandleClicked}
77
62
  handleCloseGesture={handleCloseGesture}
78
- micro={drawer.state === 'micro'}
79
- mobile={drawer.isMobile}
80
63
  drawerClx='flex flex-col'
81
64
  >
82
65
  {drawer.state === 'full' && (
@@ -1,5 +1,6 @@
1
1
  'use client'
2
2
  import React, {type PropsWithChildren } from 'react'
3
+ import { observer } from 'mobx-react-lite'
3
4
 
4
5
  import {
5
6
  Drawer,
@@ -10,74 +11,75 @@ import {
10
11
  import { cn } from '@hanzo/ui/util'
11
12
 
12
13
  import '../../../style/drawer-handle-overrides.css'
14
+ import { useCommerceDrawer } from '../../../commerce/ui/context'
13
15
 
14
16
  const CommerceDrawer: React.FC<PropsWithChildren &
15
- Omit<DrawerProps, 'onOpenChange'> &
17
+ Omit<DrawerProps,
18
+ 'onOpenChange' |
19
+ 'open' |
20
+ 'snapPoints' |
21
+ 'modal' |
22
+ 'setActiveSnapPoint' |
23
+ 'activeSnapPoint'
24
+ > &
16
25
  {
17
- setOpen: (b: boolean) => void
18
26
  handleHandleClicked: () => void
19
27
  drawerClx?: string
20
- mobile?: boolean
21
- micro?: boolean
22
28
  }
23
- > = ({
29
+ > = observer(({
24
30
  children,
25
- open,
26
- setOpen,
27
- modal,
28
- snapPoints,
29
- setActiveSnapPoint,
30
- activeSnapPoint,
31
31
  handleHandleClicked,
32
32
  drawerClx='',
33
- mobile=false,
34
- micro=false,
35
33
  ...rest
36
- }) => (
37
- // @ts-ignore
38
- <Drawer
39
- open={open}
40
- onOpenChange={setOpen}
41
- modal={modal}
42
- snapPoints={snapPoints}
43
- setActiveSnapPoint={setActiveSnapPoint}
44
- activeSnapPoint={activeSnapPoint}
45
- fastDragSkipsToEnd={false}
46
- dragHandleOnly={true}
47
- handleHandleClicked={handleHandleClicked}
48
- extendHandleDragRegion={false}
49
- // debugOutput
50
- {...rest}
51
- >
52
- <DrawerContent
53
- defaultHandle={false}
54
- className={cn(
55
- 'border-0',
56
- //(micro ? (mobile ? 'mt-4 pt-1.5' : 'mt-5 pt-4') : 'mt-5 pt-5'),
57
- mobile ? 'pt-5' : 'pt-6',
58
- 'w-full h-full',
59
- )}
60
- // https://github.com/radix-ui/primitives/discussions/935
61
- onOpenAutoFocus={(e) => {e.preventDefault()}}
34
+ }) => {
35
+
36
+ const drawer = useCommerceDrawer()
37
+
38
+ return (
39
+ <Drawer
40
+ open={drawer.open}
41
+ onOpenChange={() => {}}
42
+ modal={drawer.modal}
43
+ snapPoints={drawer.points}
44
+ activeSnapPoint={drawer.activePoint}
45
+ setActiveSnapPoint={drawer.onActivePointChanged.bind(drawer)}
46
+ fastDragSkipsToEnd={false}
47
+ dragHandleOnly={true}
48
+ handleHandleClicked={handleHandleClicked}
49
+ extendHandleDragRegion={false}
50
+ // debugOutput
51
+ {...rest}
62
52
  >
63
- <DrawerHandle
53
+ <DrawerContent
54
+ defaultHandle={false}
64
55
  className={cn(
65
- 'absolute top-0 left-0 right-0 mx-auto z-10',
66
- 'flex justify-center items-start',
67
- 'border-t rounded-t-lg border-muted-2',
68
- mobile ? 'h-5 touch-pan-y' : 'h-6',
69
- )}
56
+ 'border-0',
57
+ drawer.isMobile ? 'pt-5' : 'pt-6',
58
+ 'w-full h-full',
59
+ )}
60
+ // https://github.com/radix-ui/primitives/discussions/935
61
+ onOpenAutoFocus={(e) => {e.preventDefault()}}
70
62
  >
71
- <div className={cn(
72
- // pseudo-handle
73
- 'rounded-[3px] bg-level-3',
74
- mobile ? 'w-[155px] mt-[5px] h-1.5' : 'w-[180px] mt-[3px] h-2.5 hover:bg-level-4',
75
- !mobile ? 'cursor-grab active:cursor-grabbing' : '',
76
- )} />
77
- </DrawerHandle>
78
- {children}
79
- </DrawerContent>
80
- </Drawer>
81
- )
63
+ <DrawerHandle
64
+ className={cn(
65
+ 'absolute top-0 left-0 right-0 mx-auto z-10',
66
+ 'flex justify-center items-start',
67
+ 'border-t rounded-t-lg border-muted-3',
68
+ drawer.isMobile ? 'h-5 touch-pan-y' : 'h-6',
69
+ )}
70
+ >
71
+ <div className={cn(
72
+ // pseudo-handle
73
+ 'rounded-[3px] bg-level-3',
74
+ drawer.isMobile ? 'w-[155px] mt-[5px] h-1.5' : 'w-[180px] mt-[3px] h-2.5 hover:bg-level-4',
75
+ !drawer.isMobile ? 'cursor-grab active:cursor-grabbing' : '',
76
+ )} />
77
+ </DrawerHandle>
78
+ {children}
79
+ </DrawerContent>
80
+ </Drawer>
81
+ )
82
+ })
83
+
82
84
 
83
85
  export default CommerceDrawer
@@ -2,9 +2,7 @@
2
2
  import React, { useState } from 'react'
3
3
  import { Plus } from 'lucide-react'
4
4
  import { Search } from '../icons'
5
- import { ChatWidget } from '../../components'
6
5
  import { Button, Card } from '@hanzo/ui/primitives'
7
- import LuxLogo from '../icons/lux-logo'
8
6
 
9
7
  interface MobileNavMenuAIProps {
10
8
  setMenuOpen: (open: boolean) => void
@@ -33,7 +33,7 @@ const Footer: React.FC<{
33
33
  'md:flex md:flex-row md:justify-between '
34
34
  }>
35
35
  <div className='hidden lg:flex flex-col' key={0}>
36
- <Logo size='md' layout='text-only' />
36
+ <Logo size='md' variant='text-only' />
37
37
  </div>
38
38
  {footer.map((defs: LinkDef[], index: number) => {
39
39
 
@@ -32,18 +32,10 @@ const DesktopHeader: React.FC<{
32
32
  'flex flex-row h-[80px] items-center justify-between ' +
33
33
  'px-[8px] w-full mx-auto max-w-screen'
34
34
  }>
35
- <Logo size='md' href='/' className='hidden lg:flex' key='two' layout='text-only'/>
36
- <Logo size='sm' href='/' className='hidden md:flex lg:hidden' key='one' layout='text-only'/>
35
+ <Logo size='md' href='/' outerClx='hidden lg:flex' key='two' variant='text-only'/>
36
+ <Logo size='sm' href='/' outerClx='hidden md:flex lg:hidden' key='one' variant='text-only'/>
37
37
  {/* md or larger */}
38
38
  <div className='flex gap-4 items-center'>
39
- {/* <NavItems
40
- currentAs={currentAs}
41
- items={links}
42
- className='flex md:gap-4 lg:justify-between lg:gap-7'
43
- itemClx='font-nav h-8'
44
- key='three'
45
- /> */}
46
-
47
39
  <DesktopNav links = {links}/>
48
40
  <DesktopBagPopup popupClx='w-[340px]' trigger={<BagButton className='text-primary -mr-[3px] lg:min-w-0' />} />
49
41
  <AuthWidget/>
@@ -86,28 +86,25 @@ const MobileHeader: React.FC<{
86
86
  // header element MUST be fixed, and NOT sticky. Or else drawer breaks on mobile browsers
87
87
  return (<>
88
88
  <header className={cn(
89
- `bg-background fixed z-header top-0 left-0 w-full h-19 ${menuOpen() ? 'hidden' : 'block'}`,
89
+ `bg-background fixed z-header top-0 left-0 w-full ${menuOpen() ? 'hidden' : 'block'}`,
90
90
  className
91
91
  )}>
92
92
  {/* smaller than md: mobile style drawer menu; h-11 is 44px, the standard mobile header height */}
93
- <div className="flex h-11 items-center justify-between pl-6 pr-4">
94
- <div className='h-[74px] w-pr-100 flex flex-row justify-between items-center font-bold'>
95
- <Logo href='/' size='sm' className={'top-[3px] h-full'} layout='text-only' />
96
- {/* Not that key to the cross-fade effect
97
- is that this is **on top of** the logo. */}
98
- {menuOpen() && (
99
- <div className={'absolute left-0 top-0 bottom-0 right-0 pl-8 ' +
100
- 'flex flex-row ' +
101
- 'bg-background animate-mobile-menu-open'
102
- }>
103
- <Icons.Avatar className='self-center ' />
104
- </div>
105
- )}
106
- <div className='flex gap-0 flex-row'>
107
- <BagButton className='text-primary -mr-[3px]' onClick={openBag} />
108
- <MenuToggleButton className='text-foreground' open={menuOpen()} setOpen={setMenuOpen} />
93
+ <div className='w-full h-11 flex flex-row justify-between items-center font-bold pl-6 pr-4'>
94
+ <Logo href='/' size='sm' outerClx={'top-[3px] h-full'} variant='text-only' />
95
+ {/* Not that key to the cross-fade effect
96
+ is that this is **on top of** the logo. */}
97
+ {menuOpen() && (
98
+ <div className={'absolute left-0 top-0 bottom-0 right-0 pl-8 ' +
99
+ 'flex flex-row ' +
100
+ 'bg-background animate-mobile-menu-open'
101
+ }>
102
+ <Icons.Avatar className='self-center ' />
109
103
  </div>
110
-
104
+ )}
105
+ <div className='flex gap-0 flex-row'>
106
+ <BagButton className='text-primary -mr-[3px]' onClick={openBag} />
107
+ <MenuToggleButton className='text-foreground' open={menuOpen()} setOpen={setMenuOpen} />
111
108
  </div>
112
109
 
113
110
  </div>
@@ -12,6 +12,7 @@ export { default as NotFound } from './not-found'
12
12
 
13
13
  export { default as AuthListener } from './auth/auth-listener'
14
14
  export { default as AddWidget } from './commerce/add-widget'
15
+ export { default as BackButton } from './back-button'
15
16
  export { default as BuyDrawer } from './commerce/drawer'
16
17
  export { default as DrawerMargin } from './drawer-margin'
17
18
  export { default as BuyButton } from './commerce/buy-button'
@@ -20,6 +21,7 @@ export { default as CheckoutPanel } from './commerce/checkout-panel'
20
21
  export { default as CheckoutWidget } from './commerce/checkout-widget'
21
22
  export { default as LoginPanel } from './auth/login-panel'
22
23
  export { default as Scripts } from './scripts'
24
+ export { default as Tooltip } from './tooltip'
23
25
 
24
26
  export { default as EmblaAutoplay } from 'embla-carousel-autoplay'
25
27
 
@@ -2,77 +2,85 @@ import React from 'react'
2
2
  import Link from 'next/link'
3
3
 
4
4
  import { type TShirtSize } from '@hanzo/ui/types'
5
+
5
6
  import { cn } from '@hanzo/ui/util'
6
7
 
7
8
  import * as Icons from './icons'
8
9
 
10
+ const TEXT = 'LUX'
11
+
9
12
  const Logo: React.FC<{
10
13
  size?: TShirtSize
11
- layout?: 'text-only' | 'logo-only' | 'full'
14
+ variant?: 'text-only' | 'logo-only' | 'full'
15
+ onClick?: () => void
12
16
  href?: string
13
- className?: string
14
- spanClassName?: string
17
+ outerClx?: string
18
+ textClx?: string
15
19
  }> = ({
16
20
  size,
17
21
  href, // no default please!
18
- className='',
19
- spanClassName,
20
- layout='full'
22
+ outerClx='',
23
+ textClx='',
24
+ variant='full',
25
+ onClick,
21
26
  }) => {
22
27
  let classes: any = {}
23
- const toAdd = (layout === 'logo-only') ? {
24
- span: ' hidden',
25
- icon: ''
26
- } :
27
- (layout === 'text-only') ? {
28
- span: '',
29
- icon: ' hidden'
30
- } :
31
- {
32
- span: '',
33
- icon: ''
34
- }
28
+ const toAdd = (variant === 'logo-only') ?
29
+ {
30
+ span: 'hidden',
31
+ icon: ''
32
+ }
33
+ :
34
+ (variant === 'text-only') ?
35
+ {
36
+ span: '',
37
+ icon: 'hidden'
38
+ }
39
+ :
40
+ {
41
+ span: '',
42
+ icon: ''
43
+ }
35
44
 
36
45
  if (size === 'lg' || size === 'xl' ) { // for safety
37
- classes.icon = 'h-10 w-10 mr-4 color-inherit' + toAdd.icon
38
- classes.span = 'text-3xl' + toAdd.span
46
+ classes.icon = 'h-10 w-10 mr-4 color-inherit '
47
+ classes.span = 'text-3xl '
39
48
  }
40
49
  // match lux.network
41
50
  else if (size === 'md') {
42
- classes.icon = 'h-[32px] w-[32px] mr-[12px] color-inherit' + toAdd.icon
43
- classes.span = 'text-[1.8rem]/[1.8rem] tracking-tighter' + toAdd.span
51
+ classes.icon = 'h-[32px] w-[32px] mr-[12px] color-inherit '
52
+ classes.span = 'text-[1.8rem]/[1.8rem] tracking-tighter '
44
53
  }
45
54
  else if (size === 'sm' ) {
46
- classes.icon = 'h-6 w-6 mr-2 color-inherit' + toAdd.icon
47
- classes.span = 'text-lg' + toAdd.span
55
+ classes.icon = 'h-6 w-6 mr-2 color-inherit '
56
+ classes.span = 'text-lg '
48
57
  }
49
58
  // xs
50
59
  else {
51
- classes.icon = 'h-4 w-4 mr-1 color-inherit' + toAdd.icon
52
- classes.span = 'text-base' + toAdd.span
60
+ classes.icon = 'h-4 w-4 mr-1 color-inherit '
61
+ classes.span = 'text-base '
53
62
  }
54
63
 
55
- const outerClasses = 'flex flex-row items-center ' + className
56
- const spanClasses = 'inline-block font-bold font-heading '
57
- + spanClassName
58
- + (href ? ' hover:text-accent ' : ' cursor-default ')
59
- + classes.span
64
+ classes.icon += toAdd.icon
65
+ classes.span += toAdd.span
60
66
 
61
- const Inner: React.FC = () => (<>
62
- <Icons.logo className={classes.icon} />
63
- <span className={cn(spanClasses, ' text-inherit')}>LUX</span>
64
- </>)
65
67
 
68
+ const outerClasses = 'flex flex-row items-center ' + outerClx
69
+ const spanClasses = 'inline-block font-bold font-heading '
70
+ + textClx
71
+ + (href ? ' hover:text-accent cursor-pointer ' : ' cursor-default ')
72
+ + classes.span
66
73
 
67
74
  return (
68
75
  href ? (
69
- <Link href={href} className={outerClasses} >
70
- <Inner />
76
+ <Link href={href} className={outerClasses} onClick={onClick} >
77
+ <Icons.logo className={classes.icon} />
78
+ <span className={spanClasses}>{TEXT}</span>
71
79
  </Link>
72
-
73
80
  ) : (
74
- <span className={outerClasses} >
75
- <Inner />
81
+ <span className={outerClasses} onClick={onClick}>
82
+ <Icons.logo className={classes.icon} />
83
+ <span className={spanClasses}>{TEXT}</span>
76
84
  </span>
77
85
  )
78
86
  )
@@ -0,0 +1,31 @@
1
+ 'use client'
2
+ import React from 'react'
3
+ import { Tooltip as RTTooltip, type PlacesType } from 'react-tooltip'
4
+
5
+ const Tooltip: React.FC<{
6
+ select: string
7
+ text: string
8
+ position?: PlacesType // https://react-tooltip.com/docs/options
9
+ clx?: string
10
+ offset?: number
11
+ }> = ({
12
+ select,
13
+ text,
14
+ clx='',
15
+ position='bottom',
16
+ offset=2
17
+ }) => (
18
+ <RTTooltip
19
+ anchorSelect={select}
20
+ noArrow
21
+ opacity={1}
22
+ content={text}
23
+ place={position}
24
+ offset={offset}
25
+ delayShow={100}
26
+ delayHide={100}
27
+ className={'!opacity-100 !bg-level-2 border rounded-[3px] !px-1.5 !py-1 z-floating' + clx}
28
+ />
29
+ )
30
+
31
+ export default Tooltip
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@luxfi/core",
3
- "version": "5.2.6",
3
+ "version": "5.2.8",
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/",
@@ -44,6 +44,7 @@
44
44
  "firebase": "10.12.0",
45
45
  "react-device-detect": "^2.2.3",
46
46
  "react-social-icons": "^6.4.0",
47
+ "react-tooltip": "^5.26.4",
47
48
  "request": "^2.88.2",
48
49
  "usehooks-ts": "^3.1.0"
49
50
  },
@@ -1,26 +0,0 @@
1
- 'use client'
2
- import React from 'react'
3
-
4
- import { cn } from '@hanzo/ui/util'
5
-
6
- import Logo from '../../logo'
7
- import type { TShirtSize } from '@hanzo/ui/types'
8
-
9
- const CloseButton: React.FC<{
10
- close: () => void
11
- size?: TShirtSize
12
- className?: string
13
- }> = ({
14
- close,
15
- size,
16
- className=''
17
- }) => (
18
- <div
19
- onClick={close}
20
- className={cn('md:self-start', className)}
21
- >
22
- <Logo layout='text-only' href='/' size={size}/>
23
- </div>
24
- )
25
-
26
- export default CloseButton