@hanzo/ui 3.5.3 → 3.6.1

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.5.3",
3
+ "version": "3.6.1",
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/",
@@ -43,6 +43,7 @@
43
43
  "@radix-ui/react-scroll-area": "^1.0.5",
44
44
  "@radix-ui/react-select": "^2.0.0",
45
45
  "@radix-ui/react-separator": "^1.0.3",
46
+ "@radix-ui/react-slider": "^1.1.2",
46
47
  "@radix-ui/react-slot": "^1.0.2",
47
48
  "@radix-ui/react-switch": "^1.0.3",
48
49
  "@radix-ui/react-tabs": "^1.0.4",
@@ -1,18 +1,20 @@
1
1
  import React from 'react'
2
2
  import NextImage from 'next/image'
3
3
 
4
- import type { ImageDef, Dimensions } from '../types'
5
- import { constrain, cn } from '../util'
4
+ import type { ImageDef, Dimensions, MediaTransform } from '../types'
5
+ import { constrain, cn, spreadToTransform } from '../util'
6
6
 
7
7
  const Image: React.FC<{
8
8
  def: ImageDef
9
9
  constrainTo?: Dimensions
10
+ transform?: MediaTransform
10
11
  fullWidth?: boolean
11
12
  className?: string
12
13
  preload?: boolean
13
14
  }> = ({
14
15
  def,
15
16
  constrainTo,
17
+ transform={},
16
18
  fullWidth=false,
17
19
  className='',
18
20
  preload=false
@@ -31,6 +33,7 @@ const Image: React.FC<{
31
33
  toSpread.style = {
32
34
  width: '100%',
33
35
  height: 'auto',
36
+ ...spreadToTransform(transform)
34
37
  }
35
38
  if (constrainTo) {
36
39
  toSpread.style.maxWidth = constrainTo.w
@@ -41,6 +44,7 @@ const Image: React.FC<{
41
44
  const resolved = constrainTo ? constrain(dim, constrainTo) : dim
42
45
  toSpread.width = resolved.w
43
46
  toSpread.height = resolved.h
47
+ toSpread.style = {...spreadToTransform(transform)}
44
48
  }
45
49
 
46
50
  if (sizes) {
@@ -61,13 +65,28 @@ const Image: React.FC<{
61
65
  const svgFillClass = _svgFillClass ?? ''
62
66
 
63
67
  return (fullWidth) ? (
64
- <div className='relative flex flex-col items-center w-full'>
65
- <NextImage src={src} alt={alt} data-vaul-no-drag {...toSpread} priority={preload} loading={preload ? 'eager' : 'lazy'} className={cn(svgFillClass, className)}/>
68
+ <div className='relative flex flex-col items-center justify-center w-full'>
69
+ <NextImage
70
+ data-vaul-no-drag
71
+ src={src}
72
+ alt={alt}
73
+ {...toSpread}
74
+ priority={preload}
75
+ loading={preload ? 'eager' : 'lazy'}
76
+ className={cn(svgFillClass, className)}
77
+ />
66
78
  </div>
67
79
  ) : (
68
- <NextImage src={src} alt={alt} data-vaul-no-drag {...toSpread} priority={preload} loading={preload ? 'eager' : 'lazy'} className={cn(svgFillClass, className)}/>
80
+ <NextImage
81
+ src={src}
82
+ alt={alt}
83
+ data-vaul-no-drag
84
+ {...toSpread}
85
+ priority={preload}
86
+ loading={preload ? 'eager' : 'lazy'}
87
+ className={cn(svgFillClass, className)}
88
+ />
69
89
  )
70
90
  }
71
91
 
72
92
  export default Image
73
-
@@ -1,6 +1,25 @@
1
- export { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from './accordion'
2
- export { default as ApplyTypography, type TypographySize} from './apply-typography'
3
- export { default as ActionButton } from './action-button'
1
+ export {
2
+ Accordion,
3
+ AccordionItem,
4
+ AccordionTrigger,
5
+ AccordionContent
6
+ } from './accordion'
7
+
8
+ export {
9
+ Avatar,
10
+ AvatarImage,
11
+ AvatarFallback
12
+ } from './avatar'
13
+
14
+ export {
15
+ Breadcrumb,
16
+ BreadcrumbList,
17
+ BreadcrumbItem,
18
+ BreadcrumbLink,
19
+ BreadcrumbPage,
20
+ BreadcrumbSeparator,
21
+ BreadcrumbEllipsis,
22
+ } from './breadcrumb'
4
23
 
5
24
  export {
6
25
  default as Button,
@@ -10,20 +29,36 @@ export {
10
29
  buttonVariants,
11
30
  } from './button'
12
31
 
13
- export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } from './card'
14
- export { default as DialogVideoController } from './dialog-video-controller'
32
+ export {
33
+ Card,
34
+ CardHeader,
35
+ CardFooter,
36
+ CardTitle,
37
+ CardDescription,
38
+ CardContent
39
+ } from './card'
40
+
15
41
  export {
16
- Dialog,
17
- DialogPortal,
18
- DialogOverlay,
19
- DialogClose,
20
- DialogTrigger,
21
- DialogContent,
22
- DialogHeader,
23
- DialogFooter,
24
- DialogTitle,
25
- DialogDescription,
26
- } from './dialog'
42
+ type CarouselApi,
43
+ type CarouselOptions,
44
+ Carousel,
45
+ CarouselContent,
46
+ CarouselItem,
47
+ CarouselNext,
48
+ CarouselPrevious,
49
+ } from './carousel'
50
+
51
+ export {
52
+ Command,
53
+ CommandDialog,
54
+ CommandInput,
55
+ CommandList,
56
+ CommandEmpty,
57
+ CommandGroup,
58
+ CommandItem,
59
+ CommandShortcut,
60
+ CommandSeparator,
61
+ } from './command'
27
62
 
28
63
  export {
29
64
  Drawer,
@@ -38,6 +73,18 @@ export {
38
73
  DrawerDescription,
39
74
  } from './drawer'
40
75
 
76
+ export {
77
+ Dialog,
78
+ DialogPortal,
79
+ DialogOverlay,
80
+ DialogClose,
81
+ DialogTrigger,
82
+ DialogContent,
83
+ DialogHeader,
84
+ DialogFooter,
85
+ DialogTitle,
86
+ DialogDescription,
87
+ } from './dialog'
41
88
 
42
89
  export {
43
90
  useFormField,
@@ -50,20 +97,34 @@ export {
50
97
  FormField,
51
98
  } from './form'
52
99
 
53
- export { default as Input } from './input'
54
- export { default as Label } from './label'
55
- export { default as LinkElement } from './link-element'
56
- export { default as MDXLink } from './mdx-link'
100
+ export {
101
+ InputOTP,
102
+ InputOTPGroup,
103
+ InputOTPSeparator,
104
+ InputOTPSlot,
105
+ } from './input-otp'
106
+
107
+ export {
108
+ Popover,
109
+ PopoverAnchor,
110
+ PopoverArrow,
111
+ PopoverClose,
112
+ PopoverContent,
113
+ PopoverTrigger,
114
+ } from './popover'
57
115
 
58
116
  export {
59
- Breadcrumb,
60
- BreadcrumbList,
61
- BreadcrumbItem,
62
- BreadcrumbLink,
63
- BreadcrumbPage,
64
- BreadcrumbSeparator,
65
- BreadcrumbEllipsis,
66
- } from './breadcrumb'
117
+ Select,
118
+ SelectGroup,
119
+ SelectValue,
120
+ SelectTrigger,
121
+ SelectContent,
122
+ SelectLabel,
123
+ SelectItem,
124
+ SelectSeparator,
125
+ SelectScrollUpButton,
126
+ SelectScrollDownButton,
127
+ } from './select'
67
128
 
68
129
  export {
69
130
  Sheet,
@@ -89,42 +150,6 @@ export {
89
150
  TableCaption,
90
151
  } from './table'
91
152
 
92
- export { default as BreakpointIndicator } from './breakpoint-indicator'
93
-
94
- export {
95
- Select,
96
- SelectGroup,
97
- SelectValue,
98
- SelectTrigger,
99
- SelectContent,
100
- SelectLabel,
101
- SelectItem,
102
- SelectSeparator,
103
- SelectScrollUpButton,
104
- SelectScrollDownButton,
105
- } from './select'
106
-
107
- export {
108
- Popover,
109
- PopoverAnchor,
110
- PopoverArrow,
111
- PopoverClose,
112
- PopoverContent,
113
- PopoverTrigger,
114
- } from './popover'
115
-
116
- export {
117
- Command,
118
- CommandDialog,
119
- CommandInput,
120
- CommandList,
121
- CommandEmpty,
122
- CommandGroup,
123
- CommandItem,
124
- CommandShortcut,
125
- CommandSeparator,
126
- } from './command'
127
-
128
153
  export {
129
154
  Tabs,
130
155
  TabsList,
@@ -132,56 +157,38 @@ export {
132
157
  TabsContent
133
158
  } from './tabs'
134
159
 
135
- export {
136
- Avatar,
137
- AvatarImage,
138
- AvatarFallback
139
- } from './avatar'
140
-
141
- export {
142
- InputOTP,
143
- InputOTPGroup,
144
- InputOTPSeparator,
145
- InputOTPSlot,
146
- } from './input-otp'
147
-
148
- export {
149
- type CarouselApi,
150
- type CarouselOptions,
151
- Carousel,
152
- CarouselContent,
153
- CarouselItem,
154
- CarouselNext,
155
- CarouselPrevious,
156
- } from './carousel'
157
-
158
- export { Toggle, toggleVariants } from './toggle'
159
- export { ToggleGroup, ToggleGroupItem } from './toggle-group'
160
-
161
-
162
- export { ScrollArea, ScrollBar } from './scroll-area'
163
-
164
- export { Toaster, toast } from './sonner'
165
- export { RadioGroup, RadioGroupItem } from './radio-group'
166
-
160
+ export { default as ActionButton } from './action-button'
161
+ export { default as ApplyTypography, type TypographySize} from './apply-typography'
167
162
  export { default as AspectRatio } from './aspect-ratio'
168
163
  export { default as Badge } from './badge'
169
- export { default as VideoPlayer } from './video-player'
170
- export { default as YouTubeEmbed } from './youtube-embed'
171
- export { default as Switch } from './switch'
172
- export { default as TextArea } from './text-area'
164
+ export { default as BreakpointIndicator } from './breakpoint-indicator'
173
165
  export { default as Calendar } from './calendar'
174
166
  export { default as Checkbox } from './checkbox'
167
+ export { default as DialogVideoController } from './dialog-video-controller'
175
168
  export { default as Image } from './image'
176
- export { default as Progress } from './progress'
169
+ export { default as InlineIcon } from './inline-icon'
170
+ export { default as Input } from './input'
171
+ export { default as Label } from './label'
172
+ export { default as LinkElement } from './link-element'
173
+ export { default as ListBox } from './list-box'
174
+ export { default as Main } from './main'
175
+ export { default as MDXLink } from './mdx-link'
177
176
  export { default as MediaStack } from './media-stack'
177
+ export { default as NavItems} from './nav-items'
178
+ export { default as Progress } from './progress'
179
+ export { RadioGroup, RadioGroupItem } from './radio-group'
180
+ export { ScrollArea, ScrollBar } from './scroll-area'
178
181
  export { default as Separator } from './separator'
182
+ export { default as Slider } from './slider'
179
183
  export { default as Skeleton } from './skeleton'
180
- export { default as InlineIcon } from './inline-icon'
181
- export { default as NavItems} from './nav-items'
182
- export { default as Main } from './main'
183
- export { default as ListBox } from './list-box'
184
184
  export { default as StepIndicator } from './step-indicator'
185
+ export { default as Switch } from './switch'
186
+ export { default as TextArea } from './text-area'
187
+ export { Toaster, toast } from './sonner'
188
+ export { Toggle, toggleVariants } from './toggle'
189
+ export { ToggleGroup, ToggleGroupItem } from './toggle-group'
190
+ export { default as VideoPlayer } from './video-player'
191
+ export { default as YouTubeEmbed } from './youtube-embed'
185
192
 
186
193
  export * as Icons from './icons'
187
194
 
@@ -3,8 +3,7 @@ import React from 'react'
3
3
 
4
4
  import Spline from '@splinetool/react-spline'
5
5
 
6
- import { cn, constrain } from '../util'
7
- import { type Block, type VideoBlock, VideoBlockComponent } from '../blocks'
6
+ import { cn, constrain, spreadToTransform } from '../util'
8
7
  import type { MediaStackDef, Dimensions } from '../types'
9
8
 
10
9
  import Image from './image'
@@ -15,11 +14,13 @@ const MediaStack: React.FC<{
15
14
  constrainTo?: Dimensions
16
15
  clx?: string
17
16
  }> = ({
18
- media: {img, video, animation},
17
+ media,
19
18
  constrainTo: cnst = {w: 250, h: 250},
20
19
  clx=''
21
20
  }) => {
21
+ const {img, video, animation, mediaTransform} = media
22
22
 
23
+ const transform = mediaTransform ?? {}
23
24
 
24
25
  // Order of precedence: 3D > MP4 > Image
25
26
  if (animation) {
@@ -31,22 +32,23 @@ const MediaStack: React.FC<{
31
32
  style={{
32
33
  // // !aspect-[12/10]
33
34
  width: (6/5 * (typeof cnst.h === 'number' ? cnst.h as number : parseInt(cnst.h as string)) ),
34
- height: cnst.h
35
+ height: cnst.h,
36
+ ...spreadToTransform(transform)
35
37
  }}
36
38
  />
37
39
  )
38
40
  }
39
41
  if (video) {
40
-
41
42
  const dim = constrain(video.dim.md, cnst)
42
43
  return (
43
44
  <VideoPlayer
44
- className={cn('mx-auto', clx)}
45
+ className={clx}
45
46
  sources={video.sources}
46
47
  width={dim.w}
47
48
  height={dim.h}
48
49
  style={{
49
- minHeight: dim.h // prevents layout jumps
50
+ minHeight: dim.h, // prevents layout jumps
51
+ ...spreadToTransform(transform)
50
52
  }}
51
53
  {...video.videoProps}
52
54
  />
@@ -56,12 +58,12 @@ const MediaStack: React.FC<{
56
58
  <Image
57
59
  def={img}
58
60
  constrainTo={cnst}
59
- className={cn('mx-auto', clx)}
61
+ className={clx}
62
+ transform={transform}
60
63
  />
61
64
  ) : (
62
65
  <div style={{width: cnst.w, height: cnst.h}} className={cn('bg-level-2', clx)} />
63
66
  )
64
-
65
67
  }
66
68
 
67
69
  export default MediaStack
@@ -0,0 +1,72 @@
1
+ 'use client'
2
+ import * as React from 'react'
3
+ import * as SliderPrimitive from '@radix-ui/react-slider'
4
+
5
+ import { cn } from '../util'
6
+ import { useState } from 'react'
7
+
8
+ const Slider = React.forwardRef<
9
+ React.ElementRef<typeof SliderPrimitive.Root>,
10
+ React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root> & {
11
+ trackBgClx?: string
12
+ rangeBgClx?: string
13
+ thumbClx?: string
14
+ thumbSlidingClx?: string
15
+ }
16
+ >(({
17
+ className,
18
+ trackBgClx='bg-level-2',
19
+ rangeBgClx='bg-primary',
20
+ thumbClx='',
21
+ thumbSlidingClx='',
22
+ onValueChange,
23
+ onValueCommit,
24
+ ...rest
25
+ }, ref) => {
26
+
27
+ const [sliding, setSliding] = useState<boolean>(false)
28
+
29
+ const _onChange = (value: number[]): void => {
30
+ if (!sliding) {
31
+ setSliding(true)
32
+ }
33
+ if (onValueChange) {
34
+ onValueChange(value)
35
+ }
36
+ }
37
+
38
+ const _onCommit = (value: number[]): void => {
39
+ setSliding(false)
40
+ if (onValueCommit) {
41
+ onValueCommit(value)
42
+ }
43
+ }
44
+
45
+ return (
46
+ <SliderPrimitive.Root
47
+ ref={ref}
48
+ className={cn(
49
+ 'relative flex w-full touch-none select-none items-center',
50
+ className
51
+ )}
52
+ onValueChange={_onChange}
53
+ onValueCommit={_onCommit}
54
+ {...rest}
55
+ >
56
+ <SliderPrimitive.Track data-vaul-no-drag className={'relative h-2 w-full grow overflow-hidden rounded-full ' + trackBgClx}>
57
+ <SliderPrimitive.Range data-vaul-no-drag className={'absolute h-full ' + rangeBgClx} />
58
+ </SliderPrimitive.Track>
59
+ <SliderPrimitive.Thumb data-vaul-no-drag className={cn(
60
+ 'block h-5 w-5 rounded-full border-2 border-primary bg-background ',
61
+ 'ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-1 ',
62
+ 'focus-visible:ring-muted-2 focus-visible:ring-offset-1 disabled:pointer-events-none disabled:opacity-50',
63
+ thumbClx,
64
+ (sliding ? thumbSlidingClx : '')
65
+ )}/>
66
+ </SliderPrimitive.Root>
67
+ )
68
+ })
69
+
70
+ Slider.displayName = SliderPrimitive.Root.displayName
71
+
72
+ export default Slider
package/types/index.ts CHANGED
@@ -24,8 +24,8 @@ export {
24
24
  export type { default as Icon } from './icon'
25
25
  export type { default as ImageDef } from './image-def'
26
26
  export type { default as LinkDef } from './link-def'
27
- export type { default as MediaStackDef } from './media-stack-def'
28
27
  export type { default as TShirtDimensions } from './tshirt-dimensions'
29
28
  export type { default as TShirtSize } from './t-shirt-size'
30
29
  export type { default as VideoDef } from './video-def'
31
30
 
31
+ export type { MediaStackDef, MediaTransform } from './media-stack-def'
@@ -2,10 +2,25 @@ import type AnimationDef from './animation-def'
2
2
  import type ImageDef from './image-def'
3
3
  import type VideoDef from './video-def'
4
4
 
5
+ /**
6
+ * This will be implemented via css transforms,
7
+ * so will be a subset of those capabilities.
8
+ * Individual transforms will be added as they
9
+ * are needed.
10
+ */
11
+ interface MediaTransform {
12
+ /** (X and Y) or [X, Y] */
13
+ scale?: number | number[]
14
+ }
15
+
5
16
  interface MediaStackDef {
6
17
  img?: ImageDef
7
18
  video?: VideoDef
8
19
  animation?: AnimationDef
20
+ mediaTransform?: MediaTransform
9
21
  }
10
22
 
11
- export { type MediaStackDef as default }
23
+ export type {
24
+ MediaStackDef,
25
+ MediaTransform
26
+ }
package/util/index.ts CHANGED
@@ -70,3 +70,5 @@ export const ldMerge = (
70
70
  export const capitalize = (str: string): string => (
71
71
  str.charAt(0).toUpperCase() + str.slice(1)
72
72
  )
73
+
74
+ export { default as spreadToTransform } from './spread-to-transform'
@@ -0,0 +1,24 @@
1
+ import type { MediaTransform } from '../types'
2
+
3
+ export default (t: MediaTransform) => {
4
+
5
+ let transformStrings: string[] = []
6
+ const scaleVal = 'scale' in t ? t.scale : undefined
7
+ if (scaleVal) {
8
+ if (typeof scaleVal === 'number') {
9
+ transformStrings.push(`scale(${scaleVal})`)
10
+ }
11
+ else if (
12
+ Array.isArray(scaleVal) &&
13
+ scaleVal.length == 2 &&
14
+ typeof scaleVal[0] === 'number'
15
+ ) {
16
+ transformStrings.push(`scale(${scaleVal[0]}, ${scaleVal[1]})`)
17
+ }
18
+ else {
19
+ throw new Error("parsing MediaTransform: Unrecognized value for 'scale'!")
20
+ }
21
+ }
22
+
23
+ return transformStrings.length > 0 ? { transform: transformStrings.join(' ') } : {}
24
+ }