@hanzo/ui 4.1.0 → 4.1.2

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": "4.1.0",
3
+ "version": "4.1.2",
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,7 +44,7 @@
44
44
  "./util-client": "./util/index-client.ts"
45
45
  },
46
46
  "dependencies": {
47
- "@hanzo/react-drawer": "0.1.7",
47
+ "@hanzo/react-drawer": "^0.1.8",
48
48
  "@next/third-parties": "^15.0.1",
49
49
  "@radix-ui/react-accordion": "^1.1.2",
50
50
  "@radix-ui/react-aspect-ratio": "^1.0.3",
@@ -92,13 +92,13 @@
92
92
  "peerDependencies": {
93
93
  "@hookform/resolvers": "^3.3.2",
94
94
  "embla-carousel": "^8.1.6",
95
- "lucide-react": "^0.344.0",
95
+ "lucide-react": "catalog:",
96
96
  "mobx": "^6.12.3",
97
- "next": "^14.2.16",
97
+ "next": "catalog:",
98
98
  "next-themes": "^0.2.1",
99
- "react": "^18.3.1",
100
- "react-dom": "^18.3.1",
101
- "react-hook-form": "^7.51.4",
99
+ "react": "catalog:",
100
+ "react-dom": "catalog:",
101
+ "react-hook-form": "catalog:",
102
102
  "validator": "^13.11.0",
103
103
  "zod": "3.23.8"
104
104
  },
@@ -109,10 +109,10 @@
109
109
  "@types/gtag.js": "^0.0.19",
110
110
  "@types/lodash.merge": "^4.6.9",
111
111
  "@types/mdx": "^2.0.13",
112
- "@types/node": "^17.0.45",
113
- "@types/react": "^18.3.1",
114
- "@types/react-dom": "^18.3.0",
115
- "tailwindcss": "^3.4.3",
116
- "typescript": "5.6.3"
112
+ "@types/node": "catalog:",
113
+ "@types/react": "catalog:",
114
+ "@types/react-dom": "catalog:",
115
+ "tailwindcss": "catalog:",
116
+ "typescript": "catalog:"
117
117
  }
118
118
  }
@@ -19,64 +19,68 @@ import {
19
19
  PopoverTrigger,
20
20
  } from './popover'
21
21
 
22
- interface SelectElement {
23
- value: string,
24
- label?: string,
25
- imageUrl?: string
26
- }
27
-
28
- const IMAGE_SIZE = 32
22
+ import type ListAdaptor from './list-adaptor'
29
23
 
30
24
  const ElementImage: React.FC<{
31
25
  url: string | undefined
32
26
  alt?: string
33
27
  w: number
34
28
  h: number
29
+ className?: string
35
30
  }> = ({
36
31
  url,
37
32
  alt,
38
33
  w,
39
- h
40
- }) => (url &&
41
- <img
42
- src={url}
43
- alt={alt ?? 'image'}
44
- height={h}
45
- width={w}
46
- loading="eager"
47
- className="rounded-sm object-contain"
48
- />
34
+ h,
35
+ className=''
36
+ }) => (url ? (
37
+ <img
38
+ src={url}
39
+ alt={alt ?? 'image'}
40
+ height={h}
41
+ width={w}
42
+ loading="eager"
43
+ className={className}
44
+ />
45
+ ) : null
49
46
  )
47
+ // "rounded-sm object-contain"
50
48
 
51
-
52
- const Combobox: React.FC<{
53
- elements: SelectElement[]
54
- buttonClx?: string
55
- popoverClx?: string
56
- buttonPlaceholder?: string
57
- searchPlaceholder?: string
58
- initial?: SelectElement,
59
- elementSelected: (e: SelectElement) => void
60
- disabled?: boolean
61
- }> = ({
62
- elements,
63
- buttonClx='',
64
- popoverClx='',
65
- initial,
66
- searchPlaceholder='Search...',
67
- buttonPlaceholder='Select...',
68
- elementSelected,
69
- disabled=false
49
+ const Combobox = <T,>(
50
+ {
51
+ elements,
52
+ adaptor,
53
+ buttonClx='',
54
+ popoverClx='',
55
+ imageClx='',
56
+ initial,
57
+ searchPlaceholder='Search...',
58
+ buttonPlaceholder='Select...',
59
+ noneFoundMessage='None found.',
60
+ elementSelected,
61
+ disabled=false,
62
+ imageSize=32
63
+ }: {
64
+ elements: T[]
65
+ adaptor: ListAdaptor<T>
66
+ elementSelected: (e: T) => void
67
+ buttonClx?: string
68
+ popoverClx?: string
69
+ imageClx?: string
70
+ buttonPlaceholder?: string
71
+ searchPlaceholder?: string
72
+ noneFoundMessage?: string
73
+ initial?: T,
74
+ disabled?: boolean
75
+ imageSize?: number
70
76
  }) => {
71
77
 
72
78
  const [open, setOpen] = useState<boolean>(false)
73
- const [current, setCurrent] = useState<SelectElement | null>(initial ?? null)
79
+ const [current, setCurrent] = useState<T | null>(initial ?? null)
74
80
 
75
- const handleSelect = (selectedValue: string) => {
76
-
77
- // some issue w case... I know, right??
78
- const found = elements.find((el: SelectElement) => (el.value.toUpperCase() === selectedValue.toUpperCase()) )
81
+ const handleSelect = (selString: string) => {
79
82
 
83
+ const found = elements.find((el: T) => (adaptor.valueEquals(el, selString)))
80
84
  if (found) {
81
85
  setCurrent(found)
82
86
  elementSelected(found)
@@ -84,9 +88,17 @@ const Combobox: React.FC<{
84
88
  setOpen(false)
85
89
  }
86
90
 
87
- const isCurrent = (el: SelectElement): boolean => (
88
- !!current && (el.value.toUpperCase() === current.value.toUpperCase())
89
- )
91
+ const isCurrent = (el: T): boolean => (!!current && (adaptor.equals(el, current)))
92
+
93
+ let currentValue: string | undefined
94
+ let currentLabel: string | undefined
95
+ let currentImageUrl: string | undefined
96
+
97
+ if (current) {
98
+ currentValue = adaptor.getValue(current)
99
+ currentLabel = adaptor.getLabel ? adaptor.getLabel(current) : undefined
100
+ currentImageUrl = adaptor.getImageUrl ? adaptor.getImageUrl(current) : undefined
101
+ }
90
102
 
91
103
  return (
92
104
  <Popover open={open} onOpenChange={setOpen}>
@@ -100,9 +112,9 @@ const Combobox: React.FC<{
100
112
  >
101
113
  <div className='flex justify-start items-center gap-2'>
102
114
  {current && (
103
- <ElementImage url={current.imageUrl} w={IMAGE_SIZE} h={IMAGE_SIZE} alt={current.value + ' image'}/>
115
+ <ElementImage url={currentImageUrl} w={imageSize} h={imageSize} className={imageClx} alt={currentValue + ' image'}/>
104
116
  )}
105
- <span>{ current ? (current.label ?? current.value) : buttonPlaceholder }</span>
117
+ <span>{ current ? (currentLabel ?? currentValue) : buttonPlaceholder }</span>
106
118
  </div>
107
119
  <ChevronDown className={open ? '' : 'opacity-50'} />
108
120
  </Button>
@@ -111,21 +123,27 @@ const Combobox: React.FC<{
111
123
  <Command>
112
124
  <CommandInput placeholder={searchPlaceholder} />
113
125
  <CommandList>
114
- <CommandEmpty>No element found.</CommandEmpty>
126
+ <CommandEmpty>{noneFoundMessage}</CommandEmpty>
115
127
  <CommandGroup>
116
- {elements.map((element) => (
128
+ {elements.map((el) => (
117
129
  <CommandItem
118
- key={element.value}
119
- value={element.value}
130
+ key={adaptor.getValue(el)}
131
+ value={adaptor.getValue(el)}
120
132
  onSelect={handleSelect}
121
133
  className='flex justify-between'
122
134
  >
123
135
  <div className='flex justify-start items-center gap-2'>
124
- <ElementImage url={element.imageUrl} w={IMAGE_SIZE} h={IMAGE_SIZE} alt={element.value + ' image'}/>
125
- <span>{ element.label ?? element.value }</span>
136
+ <ElementImage
137
+ url={adaptor.getImageUrl ? adaptor.getImageUrl(el) : undefined}
138
+ w={imageSize}
139
+ h={imageSize}
140
+ className={imageClx}
141
+ alt={adaptor.getValue(el) + ' image'}
142
+ />
143
+ <span>{ adaptor.getLabel ? adaptor.getLabel(el) : adaptor.getValue(el) }</span>
126
144
  </div>
127
145
  <div>
128
- <Check className={cn('ml-auto', (isCurrent(element)) ? '' : 'invisible' )} />
146
+ <Check className={cn('ml-auto', (isCurrent(el)) ? '' : 'invisible' )} />
129
147
  </div>
130
148
  </CommandItem>
131
149
  ))}
@@ -137,7 +155,4 @@ const Combobox: React.FC<{
137
155
  )
138
156
  }
139
157
 
140
- export {
141
- type SelectElement,
142
- Combobox as default
143
- }
158
+ export default Combobox
@@ -198,10 +198,11 @@ export { default as Badge } from './badge'
198
198
  export { default as BreakpointIndicator } from './breakpoint-indicator'
199
199
  export { default as Calendar } from './calendar'
200
200
  export { default as Checkbox } from './checkbox'
201
- export { default as Combobox, type SelectElement } from './combobox'
201
+ export { default as Combobox } from './combobox'
202
202
  export { default as DialogVideoController } from './dialog-video-controller'
203
203
  export { default as Input } from './input'
204
204
  export { default as Label } from './label'
205
+ export type { default as ListAdaptor } from './list-adaptor'
205
206
  export { default as ListBox } from './list-box'
206
207
  export { default as Progress } from './progress'
207
208
  export { RadioGroup, RadioGroupItem } from './radio-group'
@@ -0,0 +1,11 @@
1
+ interface ListAdaptor<T> {
2
+ getValue: (el: T) => string
3
+ equals: (el1: T, el2: T) => boolean
4
+ valueEquals: (el: T, v: string) => boolean
5
+ getLabel?: (el: T) => string
6
+ getImageUrl?: (el: T) => string
7
+ }
8
+
9
+ export {
10
+ type ListAdaptor as default
11
+ }