@hanzo/ui 3.4.4 → 3.5.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/blocks/components/image-block.tsx +7 -9
- package/blocks/components/screenful-block/index.tsx +3 -1
- package/blocks/components/video-block.tsx +3 -3
- package/package.json +3 -1
- package/primitives/button.tsx +4 -4
- package/primitives/carousel.tsx +49 -85
- package/primitives/drawer.tsx +1 -1
- package/primitives/image.tsx +6 -6
- package/primitives/index.ts +2 -1
- package/primitives/input-otp.tsx +1 -1
- package/primitives/input.tsx +2 -2
- package/primitives/media-stack.tsx +67 -0
- package/primitives/select.tsx +2 -2
- package/primitives/text-area.tsx +2 -2
- package/primitives/video-player.tsx +1 -4
- package/style/hanzo-default-colors.css +2 -3
- package/tailwind/colors.tailwind.js +0 -1
- package/tailwind/typography-test.mdx +1 -1
- package/types/animation-def.ts +3 -0
- package/types/dimensions.ts +1 -7
- package/types/image-def.ts +3 -0
- package/types/index.ts +20 -10
- package/types/media-stack-def.ts +11 -0
- package/util/index.ts +1 -9
|
@@ -3,13 +3,13 @@ import Image from 'next/image'
|
|
|
3
3
|
|
|
4
4
|
import type { Dimensions } from '../../types'
|
|
5
5
|
import type { ImageBlock } from '../def'
|
|
6
|
-
import {
|
|
6
|
+
import { constrain, containsToken, cn } from '../../util'
|
|
7
7
|
|
|
8
8
|
import type BlockComponentProps from './block-component-props'
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
const ImageBlockComponent: React.FC<BlockComponentProps & {
|
|
12
|
-
constraintTo?:
|
|
12
|
+
constraintTo?: Dimensions
|
|
13
13
|
}> = ({
|
|
14
14
|
block,
|
|
15
15
|
className='',
|
|
@@ -36,7 +36,7 @@ const ImageBlockComponent: React.FC<BlockComponentProps & {
|
|
|
36
36
|
|
|
37
37
|
const toSpread: any = {}
|
|
38
38
|
if (props?.fill === undefined) {
|
|
39
|
-
const resolved =
|
|
39
|
+
const resolved = constraintTo ? constrain(dim, constraintTo) : dim
|
|
40
40
|
toSpread.width = resolved.w
|
|
41
41
|
toSpread.height = resolved.h
|
|
42
42
|
}
|
|
@@ -66,9 +66,8 @@ const ImageBlockComponent: React.FC<BlockComponentProps & {
|
|
|
66
66
|
sizes: '100vw',
|
|
67
67
|
}
|
|
68
68
|
// only for aspect ratio and to satisfy parser
|
|
69
|
-
|
|
70
|
-
toSpread.
|
|
71
|
-
toSpread.height = resolved.h
|
|
69
|
+
toSpread.width = dim.w
|
|
70
|
+
toSpread.height = dim.h
|
|
72
71
|
|
|
73
72
|
return (
|
|
74
73
|
<div className='flex flex-col items-center w-full'>
|
|
@@ -84,9 +83,8 @@ const ImageBlockComponent: React.FC<BlockComponentProps & {
|
|
|
84
83
|
props.style.width = props.style.width *.75
|
|
85
84
|
}
|
|
86
85
|
else if (props?.style && !props?.style.width) {
|
|
87
|
-
|
|
88
|
-
toSpread.
|
|
89
|
-
toSpread.height = resolved.w * .75
|
|
86
|
+
toSpread.width = dim.w * .75
|
|
87
|
+
toSpread.height = dim.h * .75
|
|
90
88
|
}
|
|
91
89
|
}
|
|
92
90
|
}
|
|
@@ -37,6 +37,7 @@ const ScreenfulComponent: React.FC<{
|
|
|
37
37
|
const specified = (s: string) => (containsToken(b.specifiers, s))
|
|
38
38
|
const narrowGutters = specified('narrow-gutters') // eg, for a table object that is large
|
|
39
39
|
const noGutters = specified('no-gutters')
|
|
40
|
+
const fullScreenWidth = specified('full-screen-width')
|
|
40
41
|
const vertCenter = specified('vert-center')
|
|
41
42
|
|
|
42
43
|
// content wrapper clx:
|
|
@@ -46,7 +47,8 @@ const ScreenfulComponent: React.FC<{
|
|
|
46
47
|
// p&m-modifiers
|
|
47
48
|
// ]
|
|
48
49
|
const cwclx = [
|
|
49
|
-
'xl:mx-auto
|
|
50
|
+
'xl:mx-auto overflow-y-hidden ',
|
|
51
|
+
fullScreenWidth ? '' : 'max-w-screen-xl',
|
|
50
52
|
// desktop header: 80px / pt-20
|
|
51
53
|
// mobile header: 44px / pt-11
|
|
52
54
|
narrowGutters ?
|
|
@@ -13,7 +13,7 @@ import type BlockComponentProps from './block-component-props'
|
|
|
13
13
|
const VideoBlockComponent: React.FC<BlockComponentProps & {
|
|
14
14
|
usePoster?: boolean
|
|
15
15
|
size?: TShirtSize
|
|
16
|
-
constrainTo?:
|
|
16
|
+
constrainTo?: Dimensions
|
|
17
17
|
}> = ({
|
|
18
18
|
block,
|
|
19
19
|
className='',
|
|
@@ -23,7 +23,7 @@ const VideoBlockComponent: React.FC<BlockComponentProps & {
|
|
|
23
23
|
constrainTo
|
|
24
24
|
}) => {
|
|
25
25
|
|
|
26
|
-
const [_dim, setDim] = useState<
|
|
26
|
+
const [_dim, setDim] = useState<Dimensions | undefined>(undefined)
|
|
27
27
|
|
|
28
28
|
const onResize = () => {
|
|
29
29
|
setDim({
|
|
@@ -120,7 +120,7 @@ const VideoBlockComponent: React.FC<BlockComponentProps & {
|
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
const videoDims = b.dim as TShirtDimensions
|
|
123
|
-
const dim = ((size && size in videoDims) ? videoDims[size] : videoDims.md) as
|
|
123
|
+
const dim = ((size && size in videoDims) ? videoDims[size] : videoDims.md) as Dimensions
|
|
124
124
|
const conDim = (constrainTo ? constrain(dim, constrainTo) : dim)
|
|
125
125
|
return usePoster ? (
|
|
126
126
|
<Image src={b.poster!} alt='image' width={conDim.w} height={conDim.h} className={className}/>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hanzo/ui",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.5.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/",
|
|
@@ -49,6 +49,8 @@
|
|
|
49
49
|
"@radix-ui/react-toast": "^1.1.5",
|
|
50
50
|
"@radix-ui/react-toggle": "^1.0.3",
|
|
51
51
|
"@radix-ui/react-toggle-group": "^1.0.4",
|
|
52
|
+
"@splinetool/react-spline": "^2.2.6",
|
|
53
|
+
"@splinetool/runtime": "^1.0.75",
|
|
52
54
|
"@tailwindcss/container-queries": "^0.1.1",
|
|
53
55
|
"class-variance-authority": "^0.7.0",
|
|
54
56
|
"clsx": "^2.1.0",
|
package/primitives/button.tsx
CHANGED
|
@@ -7,7 +7,7 @@ import { cn } from "../util"
|
|
|
7
7
|
const variant = {
|
|
8
8
|
primary: "bg-primary text-primary-fg hover:bg-primary-hover font-nav whitespace-nowrap not-typography",
|
|
9
9
|
secondary: "bg-secondary text-secondary-fg hover:bg-secondary-hover font-nav whitespace-nowrap not-typography",
|
|
10
|
-
outline: "text-foreground bg-background border border-muted-
|
|
10
|
+
outline: "text-foreground bg-background border border-muted-1 hover:bg-level-1 hover:text-accent hover:border-accent font-nav whitespace-nowrap not-typography",
|
|
11
11
|
destructive: "bg-destructive text-destructive-fg font-sans whitespace-nowrap hover:bg-destructive-hover",
|
|
12
12
|
ghost: "text-foreground hover:bg-level-1 hover:text-accent whitespace-nowrap font-sans ",
|
|
13
13
|
link: "text-foreground hover:text-muted-1 font-sans ",
|
|
@@ -19,7 +19,7 @@ const size = {
|
|
|
19
19
|
xs: "h-8 px-2 text-xs",
|
|
20
20
|
sm: "h-9 px-3 text-xs",
|
|
21
21
|
square: 'h-10 py-2 px-2 text-sm aspect-square',
|
|
22
|
-
default: "h-10 py-2 px-4 text-sm
|
|
22
|
+
default: "h-10 py-2 px-4 text-sm min-w-0",
|
|
23
23
|
lg: "h-10 px-8 text-sm md:text-base min-w-0 md:min-w-[260px] lg:min-w-[300px]",
|
|
24
24
|
icon: "h-10 w-10",
|
|
25
25
|
}
|
|
@@ -54,7 +54,7 @@ const buttonVariants = cva(
|
|
|
54
54
|
|
|
55
55
|
type ButtonVariants = keyof typeof variant
|
|
56
56
|
type ButtonSizes = keyof typeof size
|
|
57
|
-
type
|
|
57
|
+
type ButtonRoundedValue = keyof typeof rounded
|
|
58
58
|
|
|
59
59
|
interface ButtonProps extends
|
|
60
60
|
React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
@@ -83,6 +83,6 @@ export {
|
|
|
83
83
|
type ButtonProps,
|
|
84
84
|
type ButtonVariants,
|
|
85
85
|
type ButtonSizes,
|
|
86
|
-
type
|
|
86
|
+
type ButtonRoundedValue,
|
|
87
87
|
buttonVariants,
|
|
88
88
|
}
|
package/primitives/carousel.tsx
CHANGED
|
@@ -2,26 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
import * as React from 'react'
|
|
4
4
|
import useEmblaCarousel from 'embla-carousel-react'
|
|
5
|
-
import type { EmblaCarouselType, EmblaOptionsType } from 'embla-carousel'
|
|
5
|
+
import type { EmblaCarouselType, EmblaOptionsType, EmblaPluginType } from 'embla-carousel'
|
|
6
|
+
|
|
6
7
|
import { ArrowLeft, ArrowRight } from 'lucide-react'
|
|
7
8
|
|
|
8
9
|
import { cn } from '../util'
|
|
9
10
|
import Button from './button'
|
|
10
11
|
|
|
11
12
|
type CarouselApi = EmblaCarouselType
|
|
12
|
-
type
|
|
13
|
-
type
|
|
14
|
-
type CarouselPlugins = UseCarouselParameters[1]
|
|
13
|
+
type CarouselOptions = EmblaOptionsType
|
|
14
|
+
type CarouselPlugin = EmblaPluginType
|
|
15
15
|
|
|
16
16
|
type CarouselProps = {
|
|
17
17
|
options?: CarouselOptions
|
|
18
|
-
plugins?:
|
|
18
|
+
plugins?: CarouselPlugin[]
|
|
19
19
|
orientation?: 'horizontal' | 'vertical'
|
|
20
20
|
setApi?: (api: CarouselApi) => void
|
|
21
21
|
onCarouselSelect?: (api: CarouselApi) => void
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
type
|
|
24
|
+
type UseCarouselType = {
|
|
25
25
|
carouselRef: ReturnType<typeof useEmblaCarousel>[0]
|
|
26
26
|
api: ReturnType<typeof useEmblaCarousel>[1]
|
|
27
27
|
scrollPrev: () => void
|
|
@@ -30,112 +30,76 @@ type CarouselContextProps = {
|
|
|
30
30
|
canScrollNext: boolean
|
|
31
31
|
} & CarouselProps
|
|
32
32
|
|
|
33
|
-
const CarouselContext = React.createContext<
|
|
34
|
-
|
|
35
|
-
function useCarousel(): CarouselContextProps {
|
|
36
|
-
const context = React.useContext(CarouselContext)
|
|
33
|
+
const CarouselContext = React.createContext<UseCarouselType | null>(null)
|
|
37
34
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return context
|
|
35
|
+
const useCarousel = (): UseCarouselType => {
|
|
36
|
+
const service = React.useContext(CarouselContext)
|
|
37
|
+
if (!service) { throw new Error('useCarousel must be used within a <Carousel />') }
|
|
38
|
+
return service
|
|
43
39
|
}
|
|
44
40
|
|
|
45
41
|
// https://github.com/emilkowalski/vaul/pull/250
|
|
46
42
|
// See data-vaul-no-drag throughout
|
|
47
43
|
|
|
48
|
-
const Carousel = React.forwardRef<
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
) => {
|
|
65
|
-
const [carouselRef, api] = useEmblaCarousel(
|
|
66
|
-
{
|
|
67
|
-
...options,
|
|
68
|
-
axis: orientation === 'horizontal' ? 'x' : 'y',
|
|
69
|
-
},
|
|
70
|
-
plugins
|
|
71
|
-
)
|
|
72
|
-
const [canScrollPrev, setCanScrollPrev] = React.useState(false)
|
|
73
|
-
const [canScrollNext, setCanScrollNext] = React.useState(false)
|
|
44
|
+
const Carousel = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement> & CarouselProps>(
|
|
45
|
+
({
|
|
46
|
+
orientation = 'horizontal',
|
|
47
|
+
options,
|
|
48
|
+
setApi,
|
|
49
|
+
plugins,
|
|
50
|
+
className,
|
|
51
|
+
children,
|
|
52
|
+
onCarouselSelect,
|
|
53
|
+
...props
|
|
54
|
+
}, ref ) => {
|
|
55
|
+
|
|
56
|
+
const [carouselRef, api] = useEmblaCarousel({...options, axis: orientation === 'horizontal' ? 'x' : 'y'}, plugins)
|
|
57
|
+
|
|
58
|
+
const [canScrollPrev, setCanScrollPrev] = React.useState<boolean>(false)
|
|
59
|
+
const [canScrollNext, setCanScrollNext] = React.useState<boolean>(false)
|
|
74
60
|
|
|
75
61
|
const onSelect = React.useCallback((api: CarouselApi) => {
|
|
76
|
-
if (!api) {
|
|
77
|
-
return
|
|
78
|
-
}
|
|
62
|
+
if (!api) { return } // would this ever happen??
|
|
79
63
|
|
|
80
64
|
setCanScrollPrev(api.canScrollPrev())
|
|
81
65
|
setCanScrollNext(api.canScrollNext())
|
|
82
|
-
if (onCarouselSelect) {
|
|
83
|
-
onCarouselSelect(api)
|
|
84
|
-
}
|
|
66
|
+
if (onCarouselSelect) { onCarouselSelect(api)}
|
|
85
67
|
}, [])
|
|
86
68
|
|
|
87
|
-
const scrollPrev = React.useCallback(() => {
|
|
88
|
-
|
|
89
|
-
}, [api])
|
|
69
|
+
const scrollPrev = React.useCallback(() => { api?.scrollPrev()}, [api])
|
|
70
|
+
const scrollNext = React.useCallback(() => { api?.scrollNext()}, [api])
|
|
90
71
|
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
(event
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
scrollPrev()
|
|
100
|
-
}
|
|
101
|
-
else if (event.key === 'ArrowRight') {
|
|
102
|
-
event.preventDefault()
|
|
103
|
-
scrollNext()
|
|
104
|
-
}
|
|
105
|
-
},
|
|
106
|
-
[scrollPrev, scrollNext]
|
|
107
|
-
)
|
|
108
|
-
|
|
109
|
-
React.useEffect(() => {
|
|
110
|
-
if (!api || !setApi) {
|
|
111
|
-
return
|
|
72
|
+
const handleKeyDown = React.useCallback((event: React.KeyboardEvent<HTMLDivElement>) => {
|
|
73
|
+
if (event.key === 'ArrowLeft') {
|
|
74
|
+
event.preventDefault()
|
|
75
|
+
scrollPrev()
|
|
76
|
+
}
|
|
77
|
+
else if (event.key === 'ArrowRight') {
|
|
78
|
+
event.preventDefault()
|
|
79
|
+
scrollNext()
|
|
112
80
|
}
|
|
81
|
+
}, [scrollPrev, scrollNext])
|
|
113
82
|
|
|
83
|
+
React.useEffect(() => {
|
|
84
|
+
if (!api || !setApi) { return }
|
|
114
85
|
setApi(api)
|
|
115
86
|
}, [api, setApi])
|
|
116
87
|
|
|
117
88
|
React.useEffect(() => {
|
|
118
|
-
if (!api) {
|
|
119
|
-
return
|
|
120
|
-
}
|
|
121
|
-
|
|
89
|
+
if (!api) { return }
|
|
122
90
|
onSelect(api)
|
|
123
91
|
api.on('reInit', onSelect)
|
|
124
92
|
api.on('select', onSelect)
|
|
125
|
-
|
|
126
|
-
return () => {
|
|
127
|
-
api?.off('select', onSelect)
|
|
128
|
-
}
|
|
93
|
+
return () => { api?.off('select', onSelect) }
|
|
129
94
|
}, [api, onSelect])
|
|
130
95
|
|
|
131
96
|
return (
|
|
132
97
|
<CarouselContext.Provider
|
|
133
98
|
value={{
|
|
134
99
|
carouselRef,
|
|
135
|
-
api
|
|
100
|
+
api,
|
|
136
101
|
options,
|
|
137
|
-
orientation:
|
|
138
|
-
orientation || (options?.axis === 'y' ? 'vertical' : 'horizontal'),
|
|
102
|
+
orientation: orientation || (options?.axis === 'y' ? 'vertical' : 'horizontal'),
|
|
139
103
|
scrollPrev,
|
|
140
104
|
scrollNext,
|
|
141
105
|
canScrollPrev,
|
|
@@ -207,7 +171,7 @@ CarouselItem.displayName = 'CarouselItem'
|
|
|
207
171
|
const CarouselPrevious = React.forwardRef<
|
|
208
172
|
HTMLButtonElement,
|
|
209
173
|
React.ComponentProps<typeof Button>
|
|
210
|
-
>(({ className, variant = '
|
|
174
|
+
>(({ className, variant = 'ghost', size = 'icon', ...props }, ref) => {
|
|
211
175
|
const { orientation, scrollPrev, canScrollPrev } = useCarousel()
|
|
212
176
|
|
|
213
177
|
return (
|
|
@@ -236,7 +200,7 @@ CarouselPrevious.displayName = 'CarouselPrevious'
|
|
|
236
200
|
const CarouselNext = React.forwardRef<
|
|
237
201
|
HTMLButtonElement,
|
|
238
202
|
React.ComponentProps<typeof Button>
|
|
239
|
-
>(({ className, variant = '
|
|
203
|
+
>(({ className, variant = 'ghost', size = 'icon', ...props }, ref) => {
|
|
240
204
|
const { orientation, scrollNext, canScrollNext } = useCarousel()
|
|
241
205
|
|
|
242
206
|
return (
|
|
@@ -264,7 +228,7 @@ CarouselNext.displayName = 'CarouselNext'
|
|
|
264
228
|
|
|
265
229
|
export {
|
|
266
230
|
type CarouselApi,
|
|
267
|
-
type
|
|
231
|
+
type CarouselOptions,
|
|
268
232
|
Carousel,
|
|
269
233
|
CarouselContent,
|
|
270
234
|
CarouselItem,
|
package/primitives/drawer.tsx
CHANGED
|
@@ -49,7 +49,7 @@ const DrawerContent = React.forwardRef<
|
|
|
49
49
|
)}
|
|
50
50
|
{...props}
|
|
51
51
|
>
|
|
52
|
-
<div className='absolute left-0 right-0 mx-auto top-2 h-2 w-[100px] rounded-full bg-level-
|
|
52
|
+
<div className='absolute left-0 right-0 mx-auto top-2 h-2 w-[100px] rounded-full bg-level-3 shrink-0' />
|
|
53
53
|
{children}
|
|
54
54
|
</DrawerPrimitive.Content>
|
|
55
55
|
</DrawerPortal>
|
package/primitives/image.tsx
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import NextImage from 'next/image'
|
|
3
3
|
|
|
4
|
-
import type { ImageDef } from '../types'
|
|
5
|
-
import {
|
|
4
|
+
import type { ImageDef, Dimensions } from '../types'
|
|
5
|
+
import { constrain, cn } from '../util'
|
|
6
6
|
|
|
7
7
|
const Image: React.FC<{
|
|
8
8
|
def: ImageDef
|
|
9
|
-
constrainTo?:
|
|
9
|
+
constrainTo?: Dimensions
|
|
10
10
|
fullWidth?: boolean
|
|
11
11
|
className?: string
|
|
12
12
|
preload?: boolean
|
|
@@ -38,7 +38,7 @@ const Image: React.FC<{
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
else {
|
|
41
|
-
const resolved =
|
|
41
|
+
const resolved = constrainTo ? constrain(dim, constrainTo) : dim
|
|
42
42
|
toSpread.width = resolved.w
|
|
43
43
|
toSpread.height = resolved.h
|
|
44
44
|
}
|
|
@@ -62,10 +62,10 @@ const Image: React.FC<{
|
|
|
62
62
|
|
|
63
63
|
return (fullWidth) ? (
|
|
64
64
|
<div className='relative flex flex-col items-center w-full'>
|
|
65
|
-
<NextImage src={src} alt={alt} {...toSpread} priority={preload} loading={preload ? 'eager' : 'lazy'} className={cn(svgFillClass, className)}/>
|
|
65
|
+
<NextImage src={src} alt={alt} data-vaul-no-drag {...toSpread} priority={preload} loading={preload ? 'eager' : 'lazy'} className={cn(svgFillClass, className)}/>
|
|
66
66
|
</div>
|
|
67
67
|
) : (
|
|
68
|
-
<NextImage src={src} alt={alt} {...toSpread} priority={preload} loading={preload ? 'eager' : 'lazy'} className={cn(svgFillClass, className)}/>
|
|
68
|
+
<NextImage src={src} alt={alt} data-vaul-no-drag {...toSpread} priority={preload} loading={preload ? 'eager' : 'lazy'} className={cn(svgFillClass, className)}/>
|
|
69
69
|
)
|
|
70
70
|
}
|
|
71
71
|
|
package/primitives/index.ts
CHANGED
|
@@ -147,7 +147,7 @@ export {
|
|
|
147
147
|
|
|
148
148
|
export {
|
|
149
149
|
type CarouselApi,
|
|
150
|
-
type
|
|
150
|
+
type CarouselOptions,
|
|
151
151
|
Carousel,
|
|
152
152
|
CarouselContent,
|
|
153
153
|
CarouselItem,
|
|
@@ -174,6 +174,7 @@ export { default as Calendar } from './calendar'
|
|
|
174
174
|
export { default as Checkbox } from './checkbox'
|
|
175
175
|
export { default as Image } from './image'
|
|
176
176
|
export { default as Progress } from './progress'
|
|
177
|
+
export { default as MediaStack } from './media-stack'
|
|
177
178
|
export { default as Separator } from './separator'
|
|
178
179
|
export { default as Skeleton } from './skeleton'
|
|
179
180
|
export { default as InlineIcon } from './inline-icon'
|
package/primitives/input-otp.tsx
CHANGED
|
@@ -34,7 +34,7 @@ const InputOTPSlot = React.forwardRef<
|
|
|
34
34
|
<div
|
|
35
35
|
ref={ref}
|
|
36
36
|
className={cn(
|
|
37
|
-
'relative flex h-10 w-10 items-center justify-center border-y border-r border-muted-
|
|
37
|
+
'relative flex h-10 w-10 items-center justify-center border-y border-r border-muted-3 text-sm ',
|
|
38
38
|
'transition-all first:rounded-l-md first:border-l last:rounded-r-md',
|
|
39
39
|
isActive && 'z-above-content ring-2 ring-muted', // TODO: couldn't find: 'ring-offset-background'
|
|
40
40
|
className
|
package/primitives/input.tsx
CHANGED
|
@@ -13,8 +13,8 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
|
13
13
|
<input
|
|
14
14
|
type={type}
|
|
15
15
|
className={cn(
|
|
16
|
-
'flex h-10 w-full rounded-md border border-
|
|
17
|
-
'file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-
|
|
16
|
+
'flex h-10 w-full rounded-md border border-muted-3 bg-inherit px-3 py-2 text-sm ring-offset-background ' +
|
|
17
|
+
'file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-2 ' +
|
|
18
18
|
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 ' +
|
|
19
19
|
'first-letter:disabled:cursor-not-allowed disabled:opacity-50',
|
|
20
20
|
className
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
|
|
4
|
+
import Spline from '@splinetool/react-spline'
|
|
5
|
+
|
|
6
|
+
import { cn, constrain } from '../util'
|
|
7
|
+
import { type Block, type VideoBlock, VideoBlockComponent } from '../blocks'
|
|
8
|
+
import type { MediaStackDef, Dimensions } from '../types'
|
|
9
|
+
|
|
10
|
+
import Image from './image'
|
|
11
|
+
import VideoPlayer from './video-player'
|
|
12
|
+
|
|
13
|
+
const MediaStack: React.FC<{
|
|
14
|
+
media: MediaStackDef
|
|
15
|
+
constrainTo?: Dimensions
|
|
16
|
+
clx?: string
|
|
17
|
+
}> = ({
|
|
18
|
+
media: {img, video, animation},
|
|
19
|
+
constrainTo: cnst = {w: 250, h: 250},
|
|
20
|
+
clx=''
|
|
21
|
+
}) => {
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
// Order of precedence: 3D > MP4 > Image
|
|
25
|
+
if (animation) {
|
|
26
|
+
return (
|
|
27
|
+
<Spline
|
|
28
|
+
scene={animation}
|
|
29
|
+
className={cn(clx, 'pointer-events-none')}
|
|
30
|
+
data-vaul-no-drag
|
|
31
|
+
style={{
|
|
32
|
+
// // !aspect-[12/10]
|
|
33
|
+
width: (6/5 * (typeof cnst.h === 'number' ? cnst.h as number : parseInt(cnst.h as string)) ),
|
|
34
|
+
height: cnst.h
|
|
35
|
+
}}
|
|
36
|
+
/>
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
if (video) {
|
|
40
|
+
|
|
41
|
+
const dim = constrain(video.dim.md, cnst)
|
|
42
|
+
return (
|
|
43
|
+
<VideoPlayer
|
|
44
|
+
className={cn('mx-auto', clx)}
|
|
45
|
+
sources={video.sources}
|
|
46
|
+
width={dim.w}
|
|
47
|
+
height={dim.h}
|
|
48
|
+
style={{
|
|
49
|
+
minHeight: dim.h // prevents layout jumps
|
|
50
|
+
}}
|
|
51
|
+
{...video.videoProps}
|
|
52
|
+
/>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
return img ? (
|
|
56
|
+
<Image
|
|
57
|
+
def={img}
|
|
58
|
+
constrainTo={cnst}
|
|
59
|
+
className={cn('mx-auto', clx)}
|
|
60
|
+
/>
|
|
61
|
+
) : (
|
|
62
|
+
<div style={{width: cnst.w, height: cnst.h}} className={cn('bg-level-2', clx)} />
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export default MediaStack
|
package/primitives/select.tsx
CHANGED
|
@@ -17,8 +17,8 @@ const SelectTrigger = React.forwardRef<
|
|
|
17
17
|
<SelectPrimitive.Trigger
|
|
18
18
|
ref={ref}
|
|
19
19
|
className={cn(
|
|
20
|
-
'flex h-10 w-full items-center justify-between rounded-md border border-muted-
|
|
21
|
-
'bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-
|
|
20
|
+
'flex h-10 w-full items-center justify-between rounded-md border border-muted-3 ' +
|
|
21
|
+
'bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-2 ' +
|
|
22
22
|
'focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 ' +
|
|
23
23
|
'disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1',
|
|
24
24
|
className
|
package/primitives/text-area.tsx
CHANGED
|
@@ -10,8 +10,8 @@ const TextArea = React.forwardRef<HTMLTextAreaElement, TextAreaProps>(
|
|
|
10
10
|
return (
|
|
11
11
|
<textarea
|
|
12
12
|
className={cn(
|
|
13
|
-
'flex min-h-[80px] w-full rounded-md border border-muted-
|
|
14
|
-
'placeholder:text-muted-
|
|
13
|
+
'flex min-h-[80px] w-full rounded-md border border-muted-3 px-3 py-2 text-sm ' +
|
|
14
|
+
'placeholder:text-muted-2 focus-visible:outline-none focus-visible:ring-2 ' +
|
|
15
15
|
'focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
|
|
16
16
|
className
|
|
17
17
|
)}
|
|
@@ -3,19 +3,16 @@ import React from 'react'
|
|
|
3
3
|
|
|
4
4
|
interface VideoProps extends React.ComponentPropsWithoutRef<"video"> {
|
|
5
5
|
sources: string[]
|
|
6
|
-
className?: string
|
|
7
6
|
}
|
|
8
7
|
|
|
9
8
|
const VideoPlayer = React.forwardRef<HTMLVideoElement, VideoProps>(
|
|
10
9
|
({
|
|
11
10
|
sources,
|
|
12
|
-
className='',
|
|
13
11
|
...rest
|
|
14
12
|
}, ref) => {
|
|
15
13
|
|
|
16
|
-
|
|
17
14
|
return (
|
|
18
|
-
<video ref={ref} {...rest}
|
|
15
|
+
<video ref={ref} {...rest} data-vaul-no-drag >
|
|
19
16
|
{sources.map((source, index) => (
|
|
20
17
|
<source key={index} src={source} />
|
|
21
18
|
))}
|
|
@@ -45,8 +45,7 @@
|
|
|
45
45
|
--hz-ui-destructive-hover: hsl(0 62.8% 25%);
|
|
46
46
|
--hz-ui-destructive-fg: hsl(0 0% 100%);
|
|
47
47
|
|
|
48
|
-
--hz-ui-
|
|
49
|
-
--hz-ui-ring: var(--hz-ui-fg-1);
|
|
48
|
+
--hz-ui-ring: var(--hz-ui-fg-2);
|
|
50
49
|
|
|
51
50
|
--hz-ui-radius: 0.5rem;
|
|
52
51
|
}
|
|
@@ -54,7 +53,7 @@
|
|
|
54
53
|
.hanzo-ui-dark-theme {
|
|
55
54
|
|
|
56
55
|
--hz-ui-fg-0: hsl(0 0% 100%);
|
|
57
|
-
--hz-ui-fg-body: hsl(0,
|
|
56
|
+
--hz-ui-fg-body: hsl(0, 0%, 97%);
|
|
58
57
|
--hz-ui-fg-1: hsl(0 0% 85%);
|
|
59
58
|
--hz-ui-fg-2: hsl(0 0% 70%);
|
|
60
59
|
--hz-ui-fg-3: hsl(0 0% 55%);
|
|
@@ -17,7 +17,7 @@ laboris nisi ut aliquip ex ea commodo consequat.
|
|
|
17
17
|
2) dolor in reprehenderit
|
|
18
18
|
3) in voluptate velit esse
|
|
19
19
|
|
|
20
|
-
Cillum dolore eu fugiat nulla pariatur. Excepteur sint
|
|
20
|
+
Cillum dolore eu fugiat nulla pariatur. Excepteur sint occaefam cupidatat non proident,
|
|
21
21
|
|
|
22
22
|
- sunt in culpa
|
|
23
23
|
- qui officia deserunt
|
package/types/dimensions.ts
CHANGED
package/types/image-def.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ButtonRoundedValue } from '../primitives/button'
|
|
1
2
|
import type Dimensions from './dimensions'
|
|
2
3
|
|
|
3
4
|
/**
|
|
@@ -23,6 +24,8 @@ interface ImageDef {
|
|
|
23
24
|
* can determine the aspect ratio
|
|
24
25
|
*/
|
|
25
26
|
dim: Dimensions
|
|
27
|
+
|
|
28
|
+
rounded?: ButtonRoundedValue
|
|
26
29
|
}
|
|
27
30
|
|
|
28
31
|
export {
|
package/types/index.ts
CHANGED
|
@@ -1,21 +1,31 @@
|
|
|
1
|
+
|
|
2
|
+
export type { default as AnimationDef } from './animation-def'
|
|
1
3
|
export { type Breakpoint, Breakpoints } from './breakpoints'
|
|
2
|
-
export {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
export type { default as BulletItem } from './bullet-item'
|
|
5
|
+
|
|
6
|
+
export type {
|
|
7
|
+
ButtonDef,
|
|
8
|
+
SubmitServerAction,
|
|
9
|
+
ButtonModalProps,
|
|
10
|
+
ButtonModalDef,
|
|
7
11
|
} from './button-def'
|
|
8
12
|
|
|
9
|
-
export { COMMON_GRID_1_COL, COMMON_GRID_2_COL, COMMON_GRID_3_COL, COMMON_GRID_4_COL } from './grid-def'
|
|
10
|
-
export type {default as GridDef, GridColumnSpec} from './grid-def'
|
|
11
|
-
export type { default as Dimensions } from './dimensions'
|
|
12
|
-
export type { default as TShirtDimensions } from './tshirt-dimensions'
|
|
13
13
|
export type { ContactInfo, ContactInfoFields } from './contact-info'
|
|
14
|
+
export type { default as Dimensions } from './dimensions'
|
|
15
|
+
|
|
16
|
+
export type { default as GridDef, GridColumnSpec } from './grid-def'
|
|
17
|
+
export {
|
|
18
|
+
COMMON_GRID_1_COL,
|
|
19
|
+
COMMON_GRID_2_COL,
|
|
20
|
+
COMMON_GRID_3_COL,
|
|
21
|
+
COMMON_GRID_4_COL
|
|
22
|
+
} from './grid-def'
|
|
14
23
|
|
|
15
|
-
export type { default as BulletItem } from './bullet-item'
|
|
16
24
|
export type { default as Icon } from './icon'
|
|
17
25
|
export type { default as ImageDef } from './image-def'
|
|
18
26
|
export type { default as LinkDef } from './link-def'
|
|
27
|
+
export type { default as MediaStackDef } from './media-stack-def'
|
|
28
|
+
export type { default as TShirtDimensions } from './tshirt-dimensions'
|
|
19
29
|
export type { default as TShirtSize } from './t-shirt-size'
|
|
20
30
|
export type { default as VideoDef } from './video-def'
|
|
21
31
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type AnimationDef from './animation-def'
|
|
2
|
+
import type ImageDef from './image-def'
|
|
3
|
+
import type VideoDef from './video-def'
|
|
4
|
+
|
|
5
|
+
interface MediaStackDef {
|
|
6
|
+
img?: ImageDef
|
|
7
|
+
video?: VideoDef
|
|
8
|
+
animation?: AnimationDef
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export { type MediaStackDef as default }
|
package/util/index.ts
CHANGED
|
@@ -50,16 +50,8 @@ export const asNum = (n: number | `${number}`): number => (
|
|
|
50
50
|
(typeof n === 'number') ? n : parseInt(n, 10)
|
|
51
51
|
)
|
|
52
52
|
|
|
53
|
-
export const resolveDimensions = (dim: Dimensions, constraint?: {w: number, h: number}): {w: number, h: number} => {
|
|
54
|
-
|
|
55
|
-
const resolved = ('w' in dim) ?
|
|
56
|
-
(('h' in dim) ? {w: dim.w, h: dim.h} : { w: dim.w, h: dim.w / dim.ar }) : { w: dim.h * dim.ar, h: dim.h }
|
|
57
|
-
|
|
58
|
-
return constraint ? constrain(resolved, constraint) : resolved
|
|
59
|
-
}
|
|
60
|
-
|
|
61
53
|
// https://stackoverflow.com/questions/3971841/how-to-resize-images-proportionally-keeping-the-aspect-ratio
|
|
62
|
-
export const constrain = (d:
|
|
54
|
+
export const constrain = (d: Dimensions, c: Dimensions): Dimensions => {
|
|
63
55
|
|
|
64
56
|
const ratio = Math.min(c.w / d.w, c.h / d.h)
|
|
65
57
|
return {
|