@hanzo/ui 3.7.0 → 3.7.22

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hanzo/ui",
3
- "version": "3.7.0",
3
+ "version": "3.7.22",
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/",
@@ -39,7 +39,8 @@
39
39
  "./style/": "./style/*",
40
40
  "./tailwind": "./tailwind/index.ts",
41
41
  "./types": "./types/index.ts",
42
- "./util": "./util/index.ts"
42
+ "./util": "./util/index.ts",
43
+ "./util-client": "./util/index-client.ts"
43
44
  },
44
45
  "dependencies": {
45
46
  "@next/third-parties": "^14.1.0",
@@ -82,19 +83,20 @@
82
83
  "tailwind-merge": "^2.3.0",
83
84
  "tailwindcss-animate": "^1.0.7",
84
85
  "tailwindcss-interaction-media": "^0.1.0",
85
- "vaul": "^0.9.0"
86
+ "@hanzo/react-drawer": "0.9.1"
86
87
  },
87
88
  "peerDependencies": {
88
89
  "@hookform/resolvers": "^3.3.2",
89
90
  "embla-carousel": "^8.0.2",
90
91
  "lucide-react": "^0.344.0",
92
+ "mobx": "^6.12.0",
91
93
  "next": "14.1.3",
92
94
  "next-themes": "^0.2.1",
93
- "react": "^18.2.0",
94
- "react-dom": "^18.2.0",
95
- "react-hook-form": "^7.51.3",
95
+ "react": "^18.3.1",
96
+ "react-dom": "^18.3.1",
97
+ "react-hook-form": "^7.51.4",
96
98
  "validator": "^13.11.0",
97
- "zod": "3.21.4"
99
+ "zod": "3.23.8"
98
100
  },
99
101
  "devDependencies": {
100
102
  "@mdx-js/loader": "^3.0.0",
@@ -103,8 +105,8 @@
103
105
  "@types/gtag.js": "^0.0.19",
104
106
  "@types/lodash.merge": "^4.6.9",
105
107
  "@types/mdx": "^2.0.13",
106
- "@types/react": "^18.2.79",
107
- "@types/react-dom": "^18.2.25",
108
+ "@types/react": "^18.3.1",
109
+ "@types/react-dom": "^18.3.0",
108
110
  "embla-carousel": "^8.0.2",
109
111
  "tailwindcss": "^3.4.3",
110
112
  "typescript": "5.3.3"
@@ -1,7 +1,7 @@
1
1
  'use client'
2
2
 
3
3
  import * as React from 'react'
4
- import { Drawer as DrawerPrimitive } from 'vaul'
4
+ import { Drawer as DrawerPrimitive, useDrawerContext } from '@hanzo/react-drawer'
5
5
 
6
6
  import { cn } from '../util'
7
7
 
@@ -18,6 +18,7 @@ Drawer.displayName = 'Drawer'
18
18
 
19
19
  const DrawerTrigger = DrawerPrimitive.Trigger
20
20
  const DrawerPortal = DrawerPrimitive.Portal
21
+ const DrawerHandle = DrawerPrimitive.Handle
21
22
  const DrawerClose = DrawerPrimitive.Close
22
23
 
23
24
  const DrawerOverlay = React.forwardRef<
@@ -36,12 +37,16 @@ const DrawerContent = React.forwardRef<
36
37
  React.ElementRef<typeof DrawerPrimitive.Content>,
37
38
  React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Content> & {
38
39
  overlayClx?: string
39
- // Redundancy of 'modal' sent to Root, since we have no access to that.
40
- // Hack that avoids forking their code.
41
- modal?: boolean
40
+ defaultHandle?: boolean
42
41
  }
43
- >(({ className, children, overlayClx='', modal=true, ...props }, ref) => {
44
-
42
+ >(({
43
+ className,
44
+ children,
45
+ overlayClx='',
46
+ defaultHandle=true,
47
+ ...props
48
+ }, ref) => {
49
+
45
50
  return (
46
51
  <DrawerPortal>
47
52
  {/* If no or same z index, overlay should precede content */}
@@ -50,15 +55,14 @@ const DrawerContent = React.forwardRef<
50
55
  ref={ref}
51
56
  className={cn('fixed left-0 right-0 bottom-0 z-modal',
52
57
  'mt-24 flex flex-col rounded-t-[10px] pt-6 border bg-background',
53
- // 'h-[80%]'
58
+ // 'h-[80%]'
54
59
  className
55
60
  )}
56
- // A bug / omission in Vaul
57
- onFocusOutside={(e) => { if (!modal) { e.preventDefault(); return } }}
58
- onEscapeKeyDown={(e) => { if (!modal) { e.preventDefault(); return } }}
59
61
  {...props}
60
62
  >
61
- <div className='absolute left-0 right-0 mx-auto top-2 h-2 w-[100px] rounded-full bg-level-3 shrink-0' />
63
+ {defaultHandle && (
64
+ <div className='absolute left-0 right-0 mx-auto top-2 h-2 w-[100px] rounded-full bg-level-3 shrink-0' />
65
+ )}
62
66
  {children}
63
67
  </DrawerPrimitive.Content>
64
68
  </DrawerPortal>
@@ -126,8 +130,10 @@ export {
126
130
  DrawerTrigger,
127
131
  DrawerClose,
128
132
  DrawerContent,
133
+ DrawerHandle,
129
134
  DrawerHeader,
130
135
  DrawerFooter,
131
136
  DrawerTitle,
132
137
  DrawerDescription,
138
+ useDrawerContext
133
139
  }
@@ -66,10 +66,12 @@ export {
66
66
  DrawerTrigger,
67
67
  DrawerClose,
68
68
  DrawerContent,
69
+ DrawerHandle,
69
70
  DrawerHeader,
70
71
  DrawerFooter,
71
72
  DrawerTitle,
72
73
  DrawerDescription,
74
+ useDrawerContext
73
75
  } from './drawer'
74
76
 
75
77
  export {
@@ -0,0 +1,163 @@
1
+ /* This is a copy of vaul/src/style.css */
2
+
3
+ [vaul-drawer] {
4
+ touch-action: none;
5
+ transition: transform 0.5s cubic-bezier(0.32, 0.72, 0, 1);
6
+ }
7
+
8
+ [vaul-drawer][vaul-drawer-direction='bottom'] {
9
+ transform: translate3d(0, 100%, 0);
10
+ }
11
+
12
+ [vaul-drawer][vaul-drawer-direction='top'] {
13
+ transform: translate3d(0, -100%, 0);
14
+ }
15
+
16
+ [vaul-drawer][vaul-drawer-direction='left'] {
17
+ transform: translate3d(-100%, 0, 0);
18
+ }
19
+
20
+ [vaul-drawer][vaul-drawer-direction='right'] {
21
+ transform: translate3d(100%, 0, 0);
22
+ }
23
+
24
+ .vaul-dragging .vaul-scrollable [vault-drawer-direction='top'] {
25
+ overflow-y: hidden !important;
26
+ }
27
+ .vaul-dragging .vaul-scrollable [vault-drawer-direction='bottom'] {
28
+ overflow-y: hidden !important;
29
+ }
30
+
31
+ .vaul-dragging .vaul-scrollable [vault-drawer-direction='left'] {
32
+ overflow-x: hidden !important;
33
+ }
34
+
35
+ .vaul-dragging .vaul-scrollable [vault-drawer-direction='right'] {
36
+ overflow-x: hidden !important;
37
+ }
38
+
39
+ [vaul-drawer][vaul-drawer-visible='true'][vaul-drawer-direction='top'] {
40
+ transform: translate3d(0, var(--snap-point-height, 0), 0);
41
+ }
42
+
43
+ [vaul-drawer][vaul-drawer-visible='true'][vaul-drawer-direction='bottom'] {
44
+ transform: translate3d(0, var(--snap-point-height, 0), 0);
45
+ }
46
+
47
+ [vaul-drawer][vaul-drawer-visible='true'][vaul-drawer-direction='left'] {
48
+ transform: translate3d(var(--snap-point-height, 0), 0, 0);
49
+ }
50
+
51
+ [vaul-drawer][vaul-drawer-visible='true'][vaul-drawer-direction='right'] {
52
+ transform: translate3d(var(--snap-point-height, 0), 0, 0);
53
+ }
54
+
55
+ [vaul-overlay] {
56
+ opacity: 0;
57
+ transition: opacity 0.5s cubic-bezier(0.32, 0.72, 0, 1);
58
+ }
59
+
60
+ [vaul-overlay][vaul-drawer-visible='true'] {
61
+ opacity: 1;
62
+ }
63
+
64
+ [vaul-drawer]::after {
65
+ content: '';
66
+ position: absolute;
67
+ background: inherit;
68
+ background-color: inherit;
69
+ }
70
+
71
+ [vaul-drawer][vaul-drawer-direction='top']::after {
72
+ top: initial;
73
+ bottom: 100%;
74
+ left: 0;
75
+ right: 0;
76
+ height: 200%;
77
+ }
78
+
79
+ [vaul-drawer][vaul-drawer-direction='bottom']::after {
80
+ top: 100%;
81
+ bottom: initial;
82
+ left: 0;
83
+ right: 0;
84
+ height: 200%;
85
+ }
86
+
87
+ [vaul-drawer][vaul-drawer-direction='left']::after {
88
+ left: initial;
89
+ right: 100%;
90
+ top: 0;
91
+ bottom: 0;
92
+ width: 200%;
93
+ }
94
+
95
+ [vaul-drawer][vaul-drawer-direction='right']::after {
96
+ left: 100%;
97
+ right: initial;
98
+ top: 0;
99
+ bottom: 0;
100
+ width: 200%;
101
+ }
102
+
103
+ [vaul-handle] {
104
+ display: block;
105
+ position: relative;
106
+ opacity: 0.8;
107
+ margin-left: auto;
108
+ margin-right: auto;
109
+ height: 5px;
110
+ width: 56px;
111
+ border-radius: 1rem;
112
+ touch-action: pan-y;
113
+ cursor: grab;
114
+ }
115
+
116
+ [vaul-handle]:hover,
117
+ [vaul-handle]:active {
118
+ opacity: 1;
119
+ }
120
+
121
+ [vaul-handle]:active {
122
+ cursor: grabbing;
123
+ }
124
+
125
+ [vaul-handle-hitarea] {
126
+ position: absolute;
127
+ left: 50%;
128
+ top: 50%;
129
+ transform: translate(-50%, -50%);
130
+ width: max(100%, 2.75rem); /* 44px */
131
+ height: max(100%, 2.75rem); /* 44px */
132
+ touch-action: inherit;
133
+ }
134
+
135
+ [vaul-overlay][vaul-snap-points='true']:not([vaul-snap-points-overlay='true']):not([data-state='closed']) {
136
+ opacity: 0;
137
+ }
138
+
139
+ [vaul-overlay][vaul-snap-points-overlay='true']:not([vaul-drawer-visible='false']) {
140
+ opacity: 1;
141
+ }
142
+
143
+ /* This will allow us to not animate via animation, but still benefit from delaying unmount via Radix. */
144
+ @keyframes fake-animation {
145
+ from {
146
+ }
147
+ to {
148
+ }
149
+ }
150
+
151
+ @media (pointer: fine) {
152
+ [vaul-handle-hitarea] {
153
+ width: 100%;
154
+ height: 100%;
155
+ }
156
+ }
157
+
158
+ @media (hover: hover) and (pointer: fine) {
159
+ [vaul-drawer] {
160
+ user-select: none;
161
+ }
162
+ }
163
+
package/tsconfig.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "extends": "../tsconfig.hanzo-modules.base.json",
2
+ "extends": "../tsconfig.hanzo.base.json",
3
3
  "include": [
4
4
  "**/*.ts",
5
5
  "**/*.tsx",
@@ -0,0 +1,3 @@
1
+ export * from './index'
2
+ // Must be imported from 'use client'
3
+ export * from './step-animation'
package/util/index.ts CHANGED
@@ -74,4 +74,6 @@ export const capitalize = (str: string): string => (
74
74
  )
75
75
 
76
76
  export { default as spreadToTransform } from './spread-to-transform'
77
+ // Must be imported from 'use client'
78
+ // export * from './step-animation'
77
79
 
@@ -0,0 +1,90 @@
1
+ import { useEffect, useRef } from 'react'
2
+ import { makeObservable, reaction, computed, type IReactionDisposer, observable, action } from 'mobx'
3
+
4
+ interface StepAnimation {
5
+ notPast(step: number): boolean
6
+ }
7
+
8
+ class MyStepAnimation implements StepAnimation {
9
+
10
+ _step: number = -1
11
+ _reactionDisposer: IReactionDisposer | undefined = undefined
12
+
13
+ _initialStep: () => boolean
14
+ _intervals: number[]
15
+
16
+ /** initialStep: false -> true: step 0
17
+ true -> false: step 1
18
+ after intervals[0] : step 2
19
+ after intervals[1] : step 3
20
+
21
+ initialStep must contain at least one mobx observable and return boolean
22
+ see: https://mobx.js.org/reactions.html#reaction
23
+ */
24
+ constructor(initialStep: () => boolean, intervals: number[]) {
25
+
26
+ this._initialStep = initialStep
27
+ this._intervals = intervals
28
+
29
+ makeObservable(this, {
30
+ _step: observable,
31
+ _setStep: action
32
+ })
33
+ }
34
+
35
+ // This is separated out because reactions have to be created
36
+ // once we have a valid doc / window etc. (mobx internals)
37
+ // Can't just do it in constructor and assign to ref
38
+ initialize = () => {
39
+
40
+ const fireNext = () => {
41
+ this._setStep(this._step + 1)
42
+ if (this._step <= this._intervals.length) {
43
+ // No need to call clearTimeout(): https://stackoverflow.com/a/7391588/11645689
44
+ setTimeout(() => { fireNext() }, this._intervals[this._step - 1])
45
+ }
46
+ }
47
+
48
+ this._reactionDisposer = reaction(
49
+ this._initialStep,
50
+ (triggered: boolean) => {
51
+ if (triggered && this._step === -1) {
52
+ this._setStep(0)
53
+ }
54
+ // extra safe
55
+ else if (this._step === 0) {
56
+ fireNext()
57
+ }
58
+ }
59
+ )
60
+ }
61
+
62
+ _setStep = (v: number): void => {this._step = v}
63
+
64
+ dispose = () => {
65
+ if (this._reactionDisposer) {
66
+ this._reactionDisposer()
67
+ }
68
+ }
69
+
70
+ // https://mobx.js.org/computeds-with-args.html#2-close-over-the-arguments
71
+ notPast = (step: number): boolean => (
72
+ computed(() => (this._step > -1 && this._step <= step)).get()
73
+ )
74
+ }
75
+
76
+ const useStepAnimation = (initialStep: () => boolean, intervals: number[]): StepAnimation => {
77
+
78
+ const animRef = useRef<MyStepAnimation>(new MyStepAnimation(initialStep, intervals))
79
+ useEffect(() => {
80
+ animRef.current.initialize()
81
+ return animRef.current.dispose
82
+ }, [])
83
+
84
+ return animRef.current
85
+ }
86
+
87
+ export {
88
+ type StepAnimation,
89
+ useStepAnimation
90
+ }