@hanzo/ui 4.0.5 → 4.1.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.
Files changed (28) hide show
  1. package/blocks/components/accordian-block.tsx +1 -1
  2. package/blocks/components/bullet-cards-block.tsx +1 -1
  3. package/blocks/components/card-block/index.tsx +1 -1
  4. package/blocks/components/card-block/link-out-button.tsx +1 -1
  5. package/blocks/components/card-block/util.ts +1 -1
  6. package/blocks/components/carte-blanche-block/index.tsx +1 -1
  7. package/blocks/components/carte-blanche-block/variant-content-left.tsx +1 -1
  8. package/blocks/components/cta-block.tsx +4 -6
  9. package/blocks/components/enh-heading-block.tsx +2 -2
  10. package/blocks/components/heading-block.tsx +1 -1
  11. package/blocks/components/screenful-block/index.tsx +1 -1
  12. package/blocks/components/space-block.tsx +1 -1
  13. package/blocks/components/video-block.tsx +1 -1
  14. package/blocks/def/cta-block.ts +7 -13
  15. package/package.json +3 -2
  16. package/primitives/action-button.tsx +0 -7
  17. package/primitives/combobox.tsx +143 -0
  18. package/primitives/command.tsx +4 -2
  19. package/primitives/{index.ts → index-common.ts} +1 -8
  20. package/primitives/index-next.ts +2 -0
  21. package/primitives/{image.tsx → next/image.tsx} +2 -2
  22. package/primitives/next/index.ts +7 -0
  23. package/primitives/{inline-icon.tsx → next/inline-icon.tsx} +1 -1
  24. package/primitives/{link-element.tsx → next/link-element.tsx} +3 -3
  25. package/primitives/{media-stack.tsx → next/media-stack.tsx} +3 -3
  26. package/primitives/{nav-items.tsx → next/nav-items.tsx} +2 -2
  27. package/primitives/{youtube-embed.tsx → next/youtube-embed.tsx} +1 -1
  28. /package/primitives/{mdx-link.tsx → next/mdx-link.tsx} +0 -0
@@ -6,7 +6,7 @@ import {
6
6
  AccordionItem,
7
7
  AccordionTrigger,
8
8
  ApplyTypography
9
- } from '../../primitives'
9
+ } from '../../primitives/index-common'
10
10
 
11
11
  import { cn } from '../../util'
12
12
 
@@ -2,7 +2,7 @@ import React from 'react'
2
2
 
3
3
  import { containsToken, cn } from '../../util'
4
4
  import type { Block, BulletCardsBlock } from '../def'
5
- import InlineIcon from '../../primitives/inline-icon'
5
+ import InlineIcon from '../../primitives/next/inline-icon'
6
6
 
7
7
  import type BlockComponentProps from './block-component-props'
8
8
  import GridBlockComponent from './grid-block'
@@ -11,7 +11,7 @@ import {
11
11
  CardHeader,
12
12
  CardTitle,
13
13
  type TypographySize
14
- } from '../../../primitives'
14
+ } from '../../../primitives/index-common'
15
15
 
16
16
  import type { CardBlock, VideoBlock } from '../../def'
17
17
 
@@ -1,7 +1,7 @@
1
1
  import React from 'react'
2
2
 
3
3
  import type { LinkDef } from '../../../types'
4
- import { LinkElement, Icons } from '../../../primitives'
4
+ import { LinkElement, Icons } from '../../../primitives/index-next'
5
5
 
6
6
  const ArrowLinkElement: React.FC<{
7
7
  def: LinkDef,
@@ -1,5 +1,5 @@
1
1
  import type { Dimensions } from '../../../types'
2
- import type {TypographySize } from '../../../primitives'
2
+ import type {TypographySize } from '../../../primitives/index-common'
3
3
  import {
4
4
  getSpecifierData,
5
5
  getPrimaryStartingWith,
@@ -5,7 +5,7 @@ import {
5
5
  CardContent,
6
6
  CardFooter,
7
7
  CardHeader,
8
- } from '../../../primitives'
8
+ } from '../../../primitives/index-common'
9
9
 
10
10
  import { cn, containsToken } from '../../../util'
11
11
 
@@ -3,7 +3,7 @@ import {
3
3
  CardContent,
4
4
  CardFooter,
5
5
  CardHeader,
6
- } from '../../../primitives'
6
+ } from '../../../primitives/index-common'
7
7
  import { cn } from '../../../util'
8
8
  import Content from '../content'
9
9
 
@@ -1,7 +1,7 @@
1
1
  import React from 'react'
2
2
 
3
3
  import type { LinkDef, ButtonDef} from '../../types'
4
- import { buttonVariants, ActionButton, LinkElement } from '../../primitives'
4
+ import { buttonVariants, ActionButton, LinkElement } from '../../primitives/index-next'
5
5
  import type { CTABlock } from '../def'
6
6
  import { cn, containsToken, type VariantProps } from '../../util'
7
7
 
@@ -44,6 +44,9 @@ const CtaBlockComponent: React.FC<BlockComponentProps & {
44
44
  }
45
45
 
46
46
  const mobile2Columns = containsToken(specifiers, 'mobile-2-columns')
47
+ // normally 'default' buttons have a min width only at > lg.
48
+ // generally if more than one we don't want this and override it,
49
+ // but this specifier asks to observe the default behavior.
47
50
  const fillEvenly = !containsToken(specifiers, 'desktop-dont-fill')
48
51
  const mobileCenterFirstIfOdd = containsToken(specifiers, 'mobile-center-first-if-odd')
49
52
  const mobileOddFullWidth = containsToken(specifiers, 'mobile-odd-full-width')
@@ -55,11 +58,6 @@ const CtaBlockComponent: React.FC<BlockComponentProps & {
55
58
  layoutclx = 'grid grid-cols-2 gap-2 self-stretch '
56
59
  resetMinWidth = true
57
60
  }
58
- /*
59
- else {
60
- layoutclx = 'flex flex-col items-stretch gap-2 self-stretch md:flex-row sm:justify-center'
61
- }
62
- */
63
61
  if (fillEvenly) {
64
62
  layoutclx = (layoutclx ?? 'grid grid-cols-2 gap-2 self-stretch')
65
63
  resetMinWidth = true
@@ -2,11 +2,11 @@ import React, {type ElementType} from 'react'
2
2
 
3
3
  import type { Icon } from '../../types'
4
4
  import type { EnhHeadingBlock } from '../def'
5
- import { ApplyTypography } from '../../primitives'
5
+ import { ApplyTypography } from '../../primitives/index-common'
6
6
  import { cn, containsToken } from '../../util'
7
7
 
8
8
  import type BlockComponentProps from './block-component-props'
9
- import InlineIcon from '../../primitives/inline-icon'
9
+ import InlineIcon from '../../primitives/next/inline-icon'
10
10
 
11
11
  const DEFAULTS = {
12
12
  preheading: {
@@ -1,7 +1,7 @@
1
1
  import React from 'react'
2
2
 
3
3
  import type { HeadingBlock } from '../def'
4
- import { ApplyTypography } from '../../primitives'
4
+ import { ApplyTypography } from '../../primitives/index-common'
5
5
 
6
6
  import type BlockComponentProps from './block-component-props'
7
7
 
@@ -3,7 +3,7 @@ import dynamic from 'next/dynamic'
3
3
 
4
4
  import type { Block, ScreenfulBlock, VideoBlock } from '../../def'
5
5
  import { containsToken, cn } from '../../../util'
6
- import { ApplyTypography } from '../../../primitives'
6
+ import { ApplyTypography } from '../../../primitives/index-common'
7
7
 
8
8
  import Poster from './poster-background'
9
9
  import Content from './content'
@@ -5,7 +5,7 @@ import { ldMerge, cn } from '../../util'
5
5
  import type { Breakpoint } from '../../types'
6
6
  import { SPACE_DEFAULTS , type TWSpaceUnit, type HeadingLevel} from '../def/space-block'
7
7
  import type SpaceBlock from '../def/space-block'
8
- import { ApplyTypography } from '../../primitives'
8
+ import { ApplyTypography } from '../../primitives/index-common'
9
9
 
10
10
  import type BlockComponentProps from './block-component-props'
11
11
 
@@ -6,7 +6,7 @@ import Image from 'next/image'
6
6
  import type { Dimensions, TShirtSize, TShirtDimensions } from '../../types'
7
7
  import { constrain, asNum, cn } from '../../util'
8
8
  import type { VideoBlock } from '../def'
9
- import { VideoPlayer } from '../../primitives'
9
+ import { VideoPlayer } from '../../primitives/index-common'
10
10
 
11
11
  import type BlockComponentProps from './block-component-props'
12
12
 
@@ -3,19 +3,13 @@ import type Block from './block'
3
3
 
4
4
  interface CTABlock extends Block {
5
5
  blockType: 'cta'
6
-
7
- /**
8
- * fill: fills the parent width with the elements
9
- left / right: (>= md) left or right justify the elements (default is center)
10
- mobile-2-columns: mobile defaults to rendering each element full width,
11
- on it's own line. This renders them in two columns instead.
12
- mobile-center-first-if-odd: if (mobile-2-columns) and length is odd,
13
- default is to center last
14
- mobile-odd-full-width: fills the full two columns w the centered element
15
- desktop-dont-fill: normally 'default' buttons have a min width only at > lg.
16
- generally if more than one we don't want this and override it,
17
- but this specifier asks to observe the default behavior.
18
- */
6
+ // fill: fills the parent width with the elements
7
+ // left / right: (>= md) left or right justify the elements (default is center)
8
+ // mobile-2-columns: mobile defaults to rendering each element full width,
9
+ // on it's own line. This renders them in two columns instead.
10
+ // mobile-center-first-if-odd: if (mobile-2-columns) and length is odd,
11
+ // default is to center last
12
+ // mobile-odd-full-width: fills the full two columns w the centered element
19
13
  specifiers?: string
20
14
  elements: (LinkDef | ButtonDef)[]
21
15
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hanzo/ui",
3
- "version": "4.0.5",
3
+ "version": "4.1.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/",
@@ -35,7 +35,8 @@
35
35
  },
36
36
  "exports": {
37
37
  "./blocks": "./blocks/index.ts",
38
- "./primitives": "./primitives/index.ts",
38
+ "./primitives": "./primitives/index-next.ts",
39
+ "./primitives-common": "./primitives/index-common.ts",
39
40
  "./style/": "./style/*",
40
41
  "./tailwind": "./tailwind/index.ts",
41
42
  "./types": "./types/index.ts",
@@ -1,6 +1,5 @@
1
1
  'use client'
2
2
  import React from 'react'
3
- import dynamic from 'next/dynamic'
4
3
 
5
4
  import { cn, type VariantProps } from '../util'
6
5
 
@@ -8,12 +7,6 @@ import type { ButtonDef, ButtonModalDef } from '../types'
8
7
  import type { buttonVariants } from './button'
9
8
  import DVC from './dialog-video-controller'
10
9
 
11
- // The DVC must be rendered client-side since it accesses the DOM directly.
12
- // There is no need for a loading UI since the dialog only opens
13
- // once it's been rendered and the user is already waiting.
14
- // https://nextjs.org/docs/app/building-your-application/optimizing/lazy-loading
15
- //const DynamicDVC = dynamic(() => (import('./dialog-video-controller')), {ssr: false})
16
-
17
10
  const ActionButton: React.FC<
18
11
  VariantProps<typeof buttonVariants> &
19
12
  {
@@ -0,0 +1,143 @@
1
+ 'use client'
2
+ import React, { useState } from 'react'
3
+ import { Check, ChevronDown } from 'lucide-react'
4
+
5
+ import { cn } from '../util'
6
+ import Button from './button'
7
+ import {
8
+ Command,
9
+ CommandEmpty,
10
+ CommandGroup,
11
+ CommandInput,
12
+ CommandItem,
13
+ CommandList,
14
+ } from './command'
15
+
16
+ import {
17
+ Popover,
18
+ PopoverContent,
19
+ PopoverTrigger,
20
+ } from './popover'
21
+
22
+ interface SelectElement {
23
+ value: string,
24
+ label?: string,
25
+ imageUrl?: string
26
+ }
27
+
28
+ const IMAGE_SIZE = 32
29
+
30
+ const ElementImage: React.FC<{
31
+ url: string | undefined
32
+ alt?: string
33
+ w: number
34
+ h: number
35
+ }> = ({
36
+ url,
37
+ alt,
38
+ 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
+ />
49
+ )
50
+
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
70
+ }) => {
71
+
72
+ const [open, setOpen] = useState<boolean>(false)
73
+ const [current, setCurrent] = useState<SelectElement | null>(initial ?? null)
74
+
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()) )
79
+
80
+ if (found) {
81
+ setCurrent(found)
82
+ elementSelected(found)
83
+ }
84
+ setOpen(false)
85
+ }
86
+
87
+ const isCurrent = (el: SelectElement): boolean => (
88
+ !!current && (el.value.toUpperCase() === current.value.toUpperCase())
89
+ )
90
+
91
+ return (
92
+ <Popover open={open} onOpenChange={setOpen}>
93
+ <PopoverTrigger asChild>
94
+ <Button
95
+ variant='outline'
96
+ role='combobox'
97
+ aria-expanded={open}
98
+ className={'flex justify-between ' + buttonClx}
99
+ disabled={disabled}
100
+ >
101
+ <div className='flex justify-start items-center gap-2'>
102
+ {current && (
103
+ <ElementImage url={current.imageUrl} w={IMAGE_SIZE} h={IMAGE_SIZE} alt={current.value + ' image'}/>
104
+ )}
105
+ <span>{ current ? (current.label ?? current.value) : buttonPlaceholder }</span>
106
+ </div>
107
+ <ChevronDown className={open ? '' : 'opacity-50'} />
108
+ </Button>
109
+ </PopoverTrigger>
110
+ <PopoverContent className={'p-0 ' + popoverClx}>
111
+ <Command>
112
+ <CommandInput placeholder={searchPlaceholder} />
113
+ <CommandList>
114
+ <CommandEmpty>No element found.</CommandEmpty>
115
+ <CommandGroup>
116
+ {elements.map((element) => (
117
+ <CommandItem
118
+ key={element.value}
119
+ value={element.value}
120
+ onSelect={handleSelect}
121
+ className='flex justify-between'
122
+ >
123
+ <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>
126
+ </div>
127
+ <div>
128
+ <Check className={cn('ml-auto', (isCurrent(element)) ? '' : 'invisible' )} />
129
+ </div>
130
+ </CommandItem>
131
+ ))}
132
+ </CommandGroup>
133
+ </CommandList>
134
+ </Command>
135
+ </PopoverContent>
136
+ </Popover>
137
+ )
138
+ }
139
+
140
+ export {
141
+ type SelectElement,
142
+ Combobox as default
143
+ }
@@ -89,7 +89,7 @@ const CommandGroup = React.forwardRef<
89
89
  <CommandPrimitive.Group
90
90
  ref={ref}
91
91
  className={cn(
92
- "overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground",
92
+ "overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted",
93
93
  className
94
94
  )}
95
95
  {...props}
@@ -117,7 +117,9 @@ const CommandItem = React.forwardRef<
117
117
  <CommandPrimitive.Item
118
118
  ref={ref}
119
119
  className={cn(
120
- "relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-selected:bg-accent aria-selected:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
120
+ 'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none',
121
+ 'aria-selected:bg-level-3 aria-selected:text-accent',
122
+ 'data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
121
123
  className
122
124
  )}
123
125
  {...props}
@@ -191,7 +191,6 @@ export {
191
191
 
192
192
  export * from './tooltip'
193
193
 
194
-
195
194
  export { default as ActionButton } from './action-button'
196
195
  export { default as ApplyTypography, type TypographySize} from './apply-typography'
197
196
  export { default as AspectRatio } from './aspect-ratio'
@@ -199,16 +198,11 @@ export { default as Badge } from './badge'
199
198
  export { default as BreakpointIndicator } from './breakpoint-indicator'
200
199
  export { default as Calendar } from './calendar'
201
200
  export { default as Checkbox } from './checkbox'
201
+ export { default as Combobox, type SelectElement } from './combobox'
202
202
  export { default as DialogVideoController } from './dialog-video-controller'
203
- export { default as Image } from './image'
204
- export { default as InlineIcon } from './inline-icon'
205
203
  export { default as Input } from './input'
206
204
  export { default as Label } from './label'
207
- export { default as LinkElement } from './link-element'
208
205
  export { default as ListBox } from './list-box'
209
- export { default as MDXLink } from './mdx-link'
210
- export { default as MediaStack } from './media-stack'
211
- export { default as NavItems} from './nav-items'
212
206
  export { default as Progress } from './progress'
213
207
  export { RadioGroup, RadioGroupItem } from './radio-group'
214
208
  export { ScrollArea, ScrollBar } from './scroll-area'
@@ -222,7 +216,6 @@ export { Toaster, toast } from './sonner'
222
216
  export { Toggle, toggleVariants } from './toggle'
223
217
  export { ToggleGroup, ToggleGroupItem } from './toggle-group'
224
218
  export { default as VideoPlayer } from './video-player'
225
- export { default as YouTubeEmbed } from './youtube-embed'
226
219
 
227
220
  export * as Icons from './icons'
228
221
 
@@ -0,0 +1,2 @@
1
+ export * from './index-common'
2
+ export * from './next'
@@ -1,8 +1,8 @@
1
1
  import React from 'react'
2
2
  import NextImage from 'next/image'
3
3
 
4
- import type { ImageDef, Dimensions, MediaTransform } from '../types'
5
- import { constrain, cn, spreadToTransform } 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
@@ -0,0 +1,7 @@
1
+ export { default as Image } from './image'
2
+ export { default as InlineIcon } from './inline-icon'
3
+ export { default as LinkElement } from './link-element'
4
+ export { default as MDXLink } from './mdx-link'
5
+ export { default as MediaStack } from './media-stack'
6
+ export { default as NavItems } from './nav-items'
7
+ export { default as YouTubeEmbed } from './youtube-embed'
@@ -1,7 +1,7 @@
1
1
  import React from 'react'
2
2
  import Image from 'next/image'
3
3
 
4
- import type { Icon } from '../types'
4
+ import type { Icon } from '../../types'
5
5
 
6
6
  const InlineIcon: React.FC<{
7
7
  /**
@@ -1,9 +1,9 @@
1
1
  import React, { type PropsWithChildren } from 'react'
2
2
  import Link from 'next/link'
3
3
 
4
- import type { LinkDef, Icon } from '../types'
5
- import { buttonVariants } from './button'
6
- import { cn, type VariantProps } from '../util'
4
+ import type { LinkDef, Icon } from '../../types'
5
+ import { buttonVariants } from '../button'
6
+ import { cn, type VariantProps } from '../../util'
7
7
 
8
8
  /**
9
9
  * If this is rendered directly (and not auto generated in a Block)
@@ -3,11 +3,11 @@ import React from 'react'
3
3
 
4
4
  import Spline from '@splinetool/react-spline'
5
5
 
6
- import { cn, constrain, spreadToTransform } from '../util'
7
- import type { MediaStackDef, Dimensions } from '../types'
6
+ import { cn, constrain, spreadToTransform } from '../../util'
7
+ import type { MediaStackDef, Dimensions } from '../../types'
8
8
 
9
9
  import Image from './image'
10
- import VideoPlayer from './video-player'
10
+ import VideoPlayer from '../video-player'
11
11
 
12
12
  const MediaStack: React.FC<{
13
13
  media: MediaStackDef
@@ -1,8 +1,8 @@
1
1
  import React from 'react'
2
2
 
3
- import type { LinkDef } from '../types'
3
+ import type { LinkDef } from '../../types'
4
4
  import LinkElement from './link-element'
5
- import { cn } from '../util'
5
+ import { cn } from '../../util'
6
6
 
7
7
  const NavItems: React.FC<{
8
8
  items: LinkDef[]
@@ -3,7 +3,7 @@
3
3
  import { useState } from 'react'
4
4
  import Image from 'next/image'
5
5
 
6
- import * as Icons from './icons'
6
+ import * as Icons from '../icons'
7
7
 
8
8
  // Concept based on https://www.youtube.com/watch?v=lLqRchtjN00
9
9
  // (https://github.com/a-trost/fableton)
File without changes