@hanzo/ui 3.1.1 → 3.2.0

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.
@@ -3,18 +3,18 @@ import Image from 'next/image'
3
3
 
4
4
  import type { Dimensions } from '../../types'
5
5
  import type { ImageBlock } from '../def'
6
- import { constrain, containsToken, cn } from '../../util'
6
+ import { resolveDimensions, 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
- constraint?: Dimensions
12
+ constraintTo?: {w: number, h: number}
13
13
  }> = ({
14
14
  block,
15
15
  className='',
16
16
  agent,
17
- constraint
17
+ constraintTo
18
18
  }) => {
19
19
 
20
20
  if (block.blockType !== 'image') {
@@ -25,8 +25,8 @@ const ImageBlockComponent: React.FC<BlockComponentProps & {
25
25
  src,
26
26
  alt,
27
27
  dim,
28
- ar,
29
28
  props,
29
+ sizes,
30
30
  fullWidthOnMobile,
31
31
  svgFillClass,
32
32
  specifiers
@@ -36,9 +36,9 @@ const ImageBlockComponent: React.FC<BlockComponentProps & {
36
36
 
37
37
  const toSpread: any = {}
38
38
  if (props?.fill === undefined) {
39
- const dimCon = (constraint ? constrain(dim, constraint) : dim)
40
- toSpread.width = dimCon.w
41
- toSpread.height = dimCon.h
39
+ const resolved = resolveDimensions(dim, constraintTo)
40
+ toSpread.width = resolved.w
41
+ toSpread.height = resolved.h
42
42
  }
43
43
 
44
44
  let _alt: string
@@ -66,9 +66,10 @@ const ImageBlockComponent: React.FC<BlockComponentProps & {
66
66
  sizes: '100vw',
67
67
  }
68
68
  // only for aspect ratio and to satisfy parser
69
- toSpread.width = dim.w
70
- toSpread.height = dim.h
71
-
69
+ const resolved = resolveDimensions(dim)
70
+ toSpread.width = resolved.w
71
+ toSpread.height = resolved.h
72
+
72
73
  return (
73
74
  <div className='flex flex-col items-center w-full'>
74
75
  <Image src={src} alt={_alt} {...toSpread} className={cn(_svgFillClass, className)}/>
@@ -83,13 +84,15 @@ const ImageBlockComponent: React.FC<BlockComponentProps & {
83
84
  props.style.width = props.style.width *.75
84
85
  }
85
86
  else if (props?.style && !props?.style.width) {
86
- if (dim) {
87
- toSpread.width = +dim.w * .75
88
- toSpread.height = +dim.h * .75
89
- }
87
+ const resolved = resolveDimensions(dim)
88
+ toSpread.width = resolved.w * .75
89
+ toSpread.height = resolved.w * .75
90
90
  }
91
91
  }
92
92
  }
93
+ if (sizes) {
94
+ toSpread.sizes = sizes
95
+ }
93
96
 
94
97
  const right = containsToken(specifiers, 'right')
95
98
  const center = containsToken(specifiers, 'center')
@@ -13,17 +13,17 @@ import type BlockComponentProps from './block-component-props'
13
13
  const VideoBlockComponent: React.FC<BlockComponentProps & {
14
14
  usePoster?: boolean
15
15
  size?: TShirtSize
16
- constraint?: Dimensions
16
+ constrainTo?: {w: number, h: number}
17
17
  }> = ({
18
18
  block,
19
19
  className='',
20
20
  agent,
21
21
  usePoster=false,
22
22
  size='md',
23
- constraint
23
+ constrainTo
24
24
  }) => {
25
25
 
26
- const [_dim, setDim] = useState<Dimensions | undefined>(undefined)
26
+ const [_dim, setDim] = useState<{w: number, h: number} | undefined>(undefined)
27
27
 
28
28
  const onResize = () => {
29
29
  setDim({
@@ -69,7 +69,7 @@ const VideoBlockComponent: React.FC<BlockComponentProps & {
69
69
  }} />
70
70
  }
71
71
  else {
72
- const width = ((b.sizing.mobile.vw / 100) * asNum(_dim.w))
72
+ const width = ((b.sizing.mobile.vw / 100) * _dim.w)
73
73
  const dim = {
74
74
  h: width / ar,
75
75
  w: width
@@ -101,7 +101,8 @@ const VideoBlockComponent: React.FC<BlockComponentProps & {
101
101
  }} />
102
102
  }
103
103
  else {
104
- const height = ((b.sizing.vh / 100) * asNum(_dim.h))
104
+
105
+ const height = ((b.sizing.vh / 100) * _dim.h)
105
106
  const dim = {
106
107
  h: height,
107
108
  w: height * ar
@@ -119,8 +120,8 @@ const VideoBlockComponent: React.FC<BlockComponentProps & {
119
120
  }
120
121
 
121
122
  const videoDims = b.dim as TShirtDimensions
122
- const dim = ((size && size in videoDims) ? videoDims[size] : videoDims.md) as Dimensions
123
- const conDim = (constraint ? constrain(dim, constraint) : dim)
123
+ const dim = ((size && size in videoDims) ? videoDims[size] : videoDims.md) as {w: number, h: number}
124
+ const conDim = (constrainTo ? constrain(dim, constrainTo) : dim)
124
125
  return usePoster ? (
125
126
  <Image src={b.poster!} alt='image' width={conDim.w} height={conDim.h} className={className}/>
126
127
  ) : (
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hanzo/ui",
3
- "version": "3.1.1",
3
+ "version": "3.2.0",
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/",
@@ -1,14 +1,14 @@
1
1
  'use client'
2
2
 
3
3
  import * as React from 'react'
4
- import useEmblaCarousel, { type UseEmblaCarouselType, type EmblaOptionsType } from 'embla-carousel-react'
4
+ import useEmblaCarousel, { type EmblaOptionsType, type EmblaCarouselType } from 'embla-carousel-react'
5
5
  import Autoplay from 'embla-carousel-autoplay'
6
6
  import { ArrowLeft, ArrowRight } from 'lucide-react'
7
7
 
8
8
  import { cn } from '../util'
9
9
  import Button from './button'
10
10
 
11
- type CarouselApi = UseEmblaCarouselType[1]
11
+ type CarouselApi = EmblaCarouselType
12
12
  type UseCarouselParameters = Parameters<typeof useEmblaCarousel>
13
13
  type CarouselOptions = UseCarouselParameters[0]
14
14
  type CarouselPlugins = UseCarouselParameters[1]
@@ -18,6 +18,7 @@ type CarouselProps = {
18
18
  plugins?: CarouselPlugins
19
19
  orientation?: 'horizontal' | 'vertical'
20
20
  setApi?: (api: CarouselApi) => void
21
+ onSelect?: (api: CarouselApi) => void
21
22
  }
22
23
 
23
24
  type CarouselContextProps = {
@@ -53,6 +54,7 @@ const Carousel = React.forwardRef<
53
54
  plugins,
54
55
  className,
55
56
  children,
57
+ onSelect: _onSelect,
56
58
  ...props
57
59
  },
58
60
  ref
@@ -74,6 +76,9 @@ const Carousel = React.forwardRef<
74
76
 
75
77
  setCanScrollPrev(api.canScrollPrev())
76
78
  setCanScrollNext(api.canScrollNext())
79
+ if (_onSelect) {
80
+ _onSelect(api)
81
+ }
77
82
  }, [])
78
83
 
79
84
  const scrollPrev = React.useCallback(() => {
@@ -0,0 +1,73 @@
1
+ import React from 'react'
2
+ import NextImage from 'next/image'
3
+
4
+ import type { ImageDef } from '../types'
5
+ import { resolveDimensions, cn } from '../util'
6
+
7
+ const Image: React.FC<{
8
+ def: ImageDef
9
+ constrainTo?: {w: number, h: number}
10
+ fullWidth?: boolean
11
+ className?: string
12
+ preload?: boolean
13
+ }> = ({
14
+ def,
15
+ constrainTo,
16
+ fullWidth=false,
17
+ className='',
18
+ preload=false
19
+ }) => {
20
+
21
+ const {
22
+ src,
23
+ alt: _alt,
24
+ dim,
25
+ sizes,
26
+ svgFillClass: _svgFillClass,
27
+ } = def
28
+
29
+ const toSpread: any = {}
30
+ if (fullWidth) {
31
+ toSpread.style = {
32
+ width: '100%',
33
+ height: 'auto',
34
+ }
35
+ if (constrainTo) {
36
+ toSpread.style.maxWidth = constrainTo.w
37
+ toSpread.style.maxHeight = constrainTo.h
38
+ }
39
+ }
40
+ else {
41
+ const resolved = resolveDimensions(dim, constrainTo)
42
+ toSpread.width = resolved.w
43
+ toSpread.height = resolved.h
44
+ }
45
+
46
+ if (sizes) {
47
+ toSpread.sizes = sizes
48
+ }
49
+
50
+ // Note: cannot be spread (a Next thing)
51
+ let alt: string
52
+ if (_alt) {
53
+ alt = _alt
54
+ }
55
+ else {
56
+ const tokens = src.split('/')
57
+ // Something remotely meaningful
58
+ alt = (tokens.length > 0) ? tokens[tokens.length - 1] : src
59
+ }
60
+
61
+ const svgFillClass = _svgFillClass ?? ''
62
+
63
+ return (fullWidth) ? (
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)}/>
66
+ </div>
67
+ ) : (
68
+ <NextImage src={src} alt={alt} {...toSpread} priority={preload} loading={preload ? 'eager' : 'lazy'} className={cn(svgFillClass, className)}/>
69
+ )
70
+ }
71
+
72
+ export default Image
73
+
@@ -173,6 +173,7 @@ export { default as Switch } from './switch'
173
173
  export { default as TextArea } from './text-area'
174
174
  export { default as Calendar } from './calendar'
175
175
  export { default as Checkbox } from './checkbox'
176
+ export { default as Image } from './image'
176
177
  export { default as Progress } from './progress'
177
178
  export { default as Separator } from './separator'
178
179
  export { default as Skeleton } from './skeleton'
@@ -183,3 +184,5 @@ export { default as ListBox } from './list-box'
183
184
  export { default as StepIndicator } from './step-indicator'
184
185
 
185
186
  export * as Icons from './icons'
187
+
188
+
@@ -9,7 +9,7 @@ import { cva, type VariantProps } from "class-variance-authority"
9
9
  import { cn } from "../util"
10
10
 
11
11
  const labelVariants = cva(
12
- "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
12
+ "font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
13
13
  )
14
14
 
15
15
  const Label = React.forwardRef<
@@ -22,19 +22,31 @@ RadioGroup.displayName = RadioGroupPrimitive.Root.displayName
22
22
 
23
23
  const RadioGroupItem = React.forwardRef<
24
24
  React.ElementRef<typeof RadioGroupPrimitive.Item>,
25
- React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>
26
- >(({ className, ...props }, ref) => {
25
+ React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item> & {
26
+ larger?: boolean
27
+ }
28
+ >(({
29
+ larger=false,
30
+ className,
31
+ ...props
32
+ }, ref) => {
27
33
  return (
28
34
  <RadioGroupPrimitive.Item
29
35
  ref={ref}
30
36
  className={cn(
31
- "aspect-square h-4 w-4 rounded-full border border-muted text-foreground ring-offset-background focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
37
+ larger ? 'h-5 w-5' : 'h-4 w-4',
38
+ 'aspect-square rounded-full border border-muted text-foreground ring-offset-background ' ,
39
+ 'focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
40
+ 'disabled:cursor-not-allowed disabled:opacity-50',
32
41
  className
33
42
  )}
34
43
  {...props}
35
44
  >
36
- <RadioGroupPrimitive.Indicator className="flex items-center justify-center">
37
- <Circle className="h-2.5 w-2.5 fill-current text-current" />
45
+ <RadioGroupPrimitive.Indicator className="w-full h-full flex items-center justify-center">
46
+ <div className={cn(
47
+ larger ? 'h-[70%] w-[70%] ' : 'h-[75%] w-[75%]',
48
+ 'rounded-full aspect-square bg-foreground' ,
49
+ )}/>
38
50
  </RadioGroupPrimitive.Indicator>
39
51
  </RadioGroupPrimitive.Item>
40
52
  )
@@ -1,20 +1,14 @@
1
- // From Next Image Dim
2
1
  type Dimensions = {
3
- w: number | `${number}`
4
- h: number | `${number}`
5
- }
6
-
7
- type TShirtDimensions = {
8
- xs?: Dimensions
9
- sm?: Dimensions
10
- md: Dimensions
11
- lg?: Dimensions
12
- xl?: Dimensions
2
+ w: number
3
+ ar: number
4
+ } | {
5
+ h: number
6
+ ar: number
7
+ } | {
8
+ w: number
9
+ h: number
13
10
  }
14
11
 
15
12
  export {
16
- type Dimensions,
17
- type TShirtDimensions
13
+ type Dimensions as default
18
14
  }
19
-
20
-
@@ -1,4 +1,4 @@
1
- import type { Dimensions } from './dimensions'
1
+ import type Dimensions from './dimensions'
2
2
 
3
3
  /**
4
4
  * Defines a in image to render.
@@ -9,6 +9,8 @@ interface ImageDef {
9
9
  src: string
10
10
  /** defaults to short filename */
11
11
  alt?: string
12
+ /** See next js docs */
13
+ sizes?: string
12
14
  /**
13
15
  * Tailwind class for svg files (usually a text-<color>).
14
16
  * All affect 'fill' props in the svg file
@@ -21,7 +23,6 @@ interface ImageDef {
21
23
  * can determine the aspect ratio
22
24
  */
23
25
  dim: Dimensions
24
- ar?: number
25
26
  }
26
27
 
27
28
  export {
package/types/index.ts CHANGED
@@ -8,7 +8,8 @@ export {
8
8
 
9
9
  export { COMMON_GRID_1_COL, COMMON_GRID_2_COL, COMMON_GRID_3_COL, COMMON_GRID_4_COL } from './grid-def'
10
10
  export type {default as GridDef, GridColumnSpec} from './grid-def'
11
- export type { TShirtDimensions, Dimensions } from './dimensions'
11
+ export type { default as Dimensions } from './dimensions'
12
+ export type { default as TShirtDimensions } from './tshirt-dimensions'
12
13
  export type { ContactInfo, ContactInfoFields } from './contact-info'
13
14
 
14
15
  export type { default as BulletItem } from './bullet-item'
@@ -0,0 +1,20 @@
1
+ type ConcreteDimensions = {
2
+ w: number
3
+ h: number
4
+ }
5
+
6
+ // TODO: This is only used by VideoDef.
7
+ // Is there a better way w @next/video?
8
+ type TShirtDimensions = {
9
+ xs?: ConcreteDimensions
10
+ sm?: ConcreteDimensions
11
+ md: ConcreteDimensions
12
+ lg?: ConcreteDimensions
13
+ xl?: ConcreteDimensions
14
+ }
15
+
16
+ export {
17
+ type TShirtDimensions as default
18
+ }
19
+
20
+
@@ -1,4 +1,4 @@
1
- import type { TShirtDimensions } from './dimensions'
1
+ import type TShirtDimensions from './tshirt-dimensions'
2
2
 
3
3
  interface VideoDef {
4
4
  videoProps?: any // For example,
package/util/index.ts CHANGED
@@ -50,16 +50,16 @@ 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
+
53
61
  // https://stackoverflow.com/questions/3971841/how-to-resize-images-proportionally-keeping-the-aspect-ratio
54
- export const constrain = (dim: Dimensions, constraint: Dimensions): Dimensions => {
55
- const c = {
56
- w: asNum(constraint.w),
57
- h: asNum(constraint.h)
58
- }
59
- const d = {
60
- w: asNum(dim.w),
61
- h: asNum(dim.h)
62
- }
62
+ export const constrain = (d: {w: number, h: number}, c: {w: number, h: number}): {w: number, h: number} => {
63
63
 
64
64
  const ratio = Math.min(c.w / d.w, c.h / d.h)
65
65
  return {