@gentleduck/registry-ui 0.2.5 → 0.2.8

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 (51) hide show
  1. package/.turbo/turbo-check-types.log +1 -0
  2. package/.turbo/turbo-test.log +23 -0
  3. package/CHANGELOG.md +21 -0
  4. package/package.json +9 -8
  5. package/src/_old/_table/index.ts +9 -0
  6. package/src/_old/_table/table.tsx +7 -7
  7. package/src/_old/_upload/index.ts +13 -0
  8. package/src/_old/_upload/upload-sonner.tsx +1 -1
  9. package/src/alert-dialog/alert-dialog.tsx +11 -4
  10. package/src/aspect-ratio/aspect-ratio.tsx +9 -11
  11. package/src/audio/audio-visualizer.tsx +28 -2
  12. package/src/audio/audio.types.ts +1 -2
  13. package/src/button/__test__/button.test.tsx +80 -0
  14. package/src/button/button.tsx +1 -1
  15. package/src/button-group/button-group.tsx +1 -0
  16. package/src/calendar/calendar.tsx +161 -141
  17. package/src/carousel/carousel.tsx +1 -0
  18. package/src/chart/__test__/chart.test.tsx +40 -0
  19. package/src/chart/chart.tsx +16 -7
  20. package/src/checkbox/checkbox.tsx +1 -0
  21. package/src/collapsible/collapsible.tsx +2 -1
  22. package/src/combobox/combobox.tsx +96 -69
  23. package/src/command/command.tsx +34 -37
  24. package/src/context-menu/context-menu.tsx +11 -3
  25. package/src/dialog/dialog-responsive.tsx +12 -1
  26. package/src/dialog/dialog.tsx +12 -4
  27. package/src/dropdown-menu/dropdown-menu.tsx +11 -3
  28. package/src/empty/empty.tsx +30 -17
  29. package/src/field/field.tsx +138 -109
  30. package/src/input-group/input-group.tsx +3 -0
  31. package/src/item/item.tsx +1 -0
  32. package/src/json-editor/json-editor.tsx +59 -60
  33. package/src/json-editor/json-editor.view.tsx +1 -0
  34. package/src/label/label.tsx +1 -0
  35. package/src/menubar/menubar.tsx +10 -3
  36. package/src/popover/popover.tsx +4 -0
  37. package/src/preview-panel/preview-panel-dialog.tsx +86 -80
  38. package/src/preview-panel/preview-panel.tsx +280 -273
  39. package/src/resizable/resizable.tsx +17 -15
  40. package/src/select/select.tsx +3 -0
  41. package/src/separator/separator.tsx +0 -1
  42. package/src/sheet/sheet.tsx +16 -4
  43. package/src/sidebar/sidebar.tsx +436 -378
  44. package/src/slider/slider.tsx +8 -10
  45. package/src/sonner/sonner.chunks.tsx +3 -0
  46. package/src/sonner/sonner.tsx +23 -20
  47. package/src/switch/switch.tsx +1 -0
  48. package/src/tabs/tabs.tsx +2 -2
  49. package/src/toggle/toggle.constants.ts +2 -2
  50. package/src/tooltip/tooltip.tsx +3 -0
  51. package/tsconfig.json +10 -1
@@ -0,0 +1 @@
1
+ $ tsc -p tsconfig.json --noEmit --pretty false --skipLibCheck
@@ -0,0 +1,23 @@
1
+ $ bun test
2
+ bun test v1.3.5 (1e86cebd)
3
+
4
+ ::group::src/chart/__test__/chart.test.tsx:
5
+ (pass) registry-ui chart > ChartContainer server render does not emit invalid size warnings [53.00ms]
6
+
7
+ ::endgroup::
8
+
9
+ ::group::src/button/__test__/button.test.tsx:
10
+ (pass) registry-ui button > buttonVariants returns the shared base styles and defaults [1.00ms]
11
+ (pass) registry-ui button > buttonVariants applies explicit variant and size overrides
12
+ (pass) registry-ui button > button exports keep stable display names
13
+ (pass) registry-ui button > Button renders loading state as a busy disabled native button [3.00ms]
14
+ (pass) registry-ui button > Button preserves explicit disabled state even when loading is false [1.00ms]
15
+ (pass) registry-ui button > Button collapses into icon-only mode and hides secondary content
16
+ (pass) registry-ui button > AnimationIcon renders left and right placements around children [1.00ms]
17
+
18
+ ::endgroup::
19
+
20
+ 8 pass
21
+ 0 fail
22
+ 25 expect() calls
23
+ Ran 8 tests across 2 files. [574.00ms]
package/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # @gentleduck/registry-ui
2
2
 
3
+ ## 0.2.8
4
+
5
+ ### Patch Changes
6
+
7
+ - e7ee580: fix(registry-ui): replace workspace:\* dependencies with published npm versions
8
+
9
+ The published package had `workspace:*` references that broke any consumer's install.
10
+
11
+ ## 0.2.6
12
+
13
+ ### Patch Changes
14
+
15
+ - 2b6e8d0: Resolve all biome lint warnings, improve type safety, and add test coverage across the monorepo.
16
+ - Updated dependencies [2b6e8d0]
17
+ - @gentleduck/primitives@0.2.5
18
+ - @gentleduck/variants@0.1.20
19
+ - @gentleduck/hooks@0.1.12
20
+ - @gentleduck/motion@0.1.17
21
+ - @gentleduck/libs@0.1.15
22
+ - @gentleduck/vim@0.1.16
23
+
3
24
  ## 0.2.5
4
25
 
5
26
  ### Patch Changes
package/package.json CHANGED
@@ -4,12 +4,12 @@
4
4
  "node": ">=22.0.0"
5
5
  },
6
6
  "dependencies": {
7
- "@gentleduck/hooks": "workspace:*",
8
- "@gentleduck/libs": "workspace:*",
9
- "@gentleduck/motion": "workspace:*",
10
- "@gentleduck/primitives": "workspace:*",
11
- "@gentleduck/variants": "workspace:*",
12
- "@gentleduck/vim": "workspace:*",
7
+ "@gentleduck/hooks": "^0.1.12",
8
+ "@gentleduck/libs": "^0.1.15",
9
+ "@gentleduck/motion": "^0.1.17",
10
+ "@gentleduck/primitives": "^0.2.5",
11
+ "@gentleduck/variants": "^0.1.20",
12
+ "@gentleduck/vim": "^0.1.16",
13
13
  "embla-carousel-react": "8.6.0",
14
14
  "lucide-react": "0.576.0",
15
15
  "next-themes": "^0.4.6",
@@ -52,8 +52,9 @@
52
52
  "access": "public"
53
53
  },
54
54
  "scripts": {
55
- "check-types": "tsc -p tsconfig.json --noEmit --pretty false --skipLibCheck"
55
+ "check-types": "tsc -p tsconfig.json --noEmit --pretty false --skipLibCheck",
56
+ "test": "bun test"
56
57
  },
57
58
  "type": "module",
58
- "version": "0.2.5"
59
+ "version": "0.2.8"
59
60
  }
@@ -1,5 +1,14 @@
1
+ /**
2
+ * @deprecated These table components are deprecated and no longer maintained.
3
+ * Use the components from `@duck-ui/registry-ui/table` instead.
4
+ * This module will be removed in a future release.
5
+ */
1
6
  export * from './table'
7
+ /** @deprecated Use components from `@duck-ui/registry-ui/table` instead. */
2
8
  export * from './table.constants'
9
+ /** @deprecated Use components from `@duck-ui/registry-ui/table` instead. */
3
10
  export * from './table.hook'
11
+ /** @deprecated Use components from `@duck-ui/registry-ui/table` instead. */
4
12
  export * from './table.lib'
13
+ /** @deprecated Use components from `@duck-ui/registry-ui/table` instead. */
5
14
  export * from './table.types'
@@ -206,7 +206,7 @@
206
206
  // DuckTableSearchInputProps
207
207
  // >(({ trigger, label, badge, keys }, ref) => {
208
208
  // const {
209
- // children: badgeChildren = '⌃+⇧+F',
209
+ // children: badgeChildren = 'Ctrl+Shift+F',
210
210
  // className: badgeClassName,
211
211
  // ...badgeProps
212
212
  // } = badge ?? {}
@@ -415,7 +415,7 @@
415
415
  // children: 'View',
416
416
  // command: {
417
417
  // key: 'ctrl+shift+v',
418
- // label: '⌃+⇧+V',
418
+ // label: 'Ctrl+Shift+V',
419
419
  // },
420
420
  // icon: {
421
421
  // children: MixerHorizontalIcon as LucideIcon,
@@ -527,7 +527,7 @@
527
527
  // // }),
528
528
  // // command: {
529
529
  // // key: 'ctrl+shift+down',
530
- // // label: '⌃+⇧+↓',
530
+ // // label: 'Ctrl+Shift+Down',
531
531
  // // action: () =>
532
532
  // // setPaginationState({
533
533
  // // ...paginationState,
@@ -546,7 +546,7 @@
546
546
  // // onClick: () => setPaginationState({ ...paginationState, activePage: 0 }),
547
547
  // // command: {
548
548
  // // key: 'ctrl+shift+left',
549
- // // label: '⌃+⇧+←',
549
+ // // label: 'Ctrl+Shift+Left',
550
550
  // // action: () => setPaginationState({ ...paginationState, activePage: 0 }),
551
551
  // // },
552
552
  // label: {
@@ -561,7 +561,7 @@
561
561
  // // onClick: () => setPaginationState({ ...paginationState, activePage: resultArrays.length - 1 }),
562
562
  // // command: {
563
563
  // // key: 'ctrl+shift+right',
564
- // // label: '⌃+⇧+->',
564
+ // // label: 'Ctrl+Shift+Right',
565
565
  // // action: () => setPaginationState({ ...paginationState, activePage: resultArrays.length - 1 }),
566
566
  // // },
567
567
  // label: {
@@ -575,7 +575,7 @@
575
575
  // right={{
576
576
  // command: {
577
577
  // key: 'ctrl+shift+up',
578
- // label: '⌃+⇧+↑',
578
+ // label: 'Ctrl+Shift+Up',
579
579
  // // action: () =>
580
580
  // // setPaginationState({
581
581
  // // ...paginationState,
@@ -677,7 +677,7 @@
677
677
  // className: 'w-[4.5rem] h-[32px] gap-0',
678
678
  // command: {
679
679
  // key: 'ctrl+shift+c',
680
- // label: '⌃+⇧+C',
680
+ // label: 'Ctrl+Shift+C',
681
681
  // },
682
682
  // label: {
683
683
  // children: 'Rows per page',
@@ -1,9 +1,22 @@
1
+ /**
2
+ * @deprecated These upload components are deprecated and no longer maintained.
3
+ * Use the components from `@duck-ui/registry-ui/upload` instead.
4
+ * This module will be removed in a future release.
5
+ */
1
6
  export * from './upload'
7
+ /** @deprecated Use components from `@duck-ui/registry-ui/upload` instead. */
2
8
  export * from './upload.assets'
9
+ /** @deprecated Use components from `@duck-ui/registry-ui/upload` instead. */
3
10
  export * from './upload.constants'
11
+ /** @deprecated Use components from `@duck-ui/registry-ui/upload` instead. */
4
12
  export * from './upload.dto'
13
+ /** @deprecated Use components from `@duck-ui/registry-ui/upload` instead. */
5
14
  export * from './upload.lib'
15
+ /** @deprecated Use components from `@duck-ui/registry-ui/upload` instead. */
6
16
  export * from './upload.types'
17
+ /** @deprecated Use components from `@duck-ui/registry-ui/upload` instead. */
7
18
  export * from './upload-advanced'
19
+ /** @deprecated Use components from `@duck-ui/registry-ui/upload` instead. */
8
20
  export * from './upload-advanced-chunks'
21
+ /** @deprecated Use components from `@duck-ui/registry-ui/upload` instead. */
9
22
  export * from './upload-sonner'
@@ -34,7 +34,7 @@
34
34
  // </p>
35
35
  // <div className="flex items-center gap-2">
36
36
  // {remainingTime && (
37
- // <p className="text-foreground-light text-sm font-mono">{`${remainingTime && !isNaN(remainingTime) && isFinite(remainingTime) && remainingTime !== 0 ? `${formatTime(remainingTime)} remaining ` : ''}`}</p>
37
+ // <p className="text-foreground-light text-sm font-mono">{`${remainingTime && !isNaN(remainingTime) && isFinite(remainingTime) && remainingTime !== 0 ? `${formatTime(remainingTime)} remaining -` : ''}`}</p>
38
38
  // )}
39
39
  // <p className="text-foreground-light text-sm font-mono">{`${progress}%`}</p>
40
40
  // </div>
@@ -6,10 +6,13 @@ import * as React from 'react'
6
6
  import { buttonVariants } from '../button'
7
7
 
8
8
  const AlertDialog = AlertDialogPrimitive.Root
9
+ AlertDialog.displayName = 'AlertDialog'
9
10
 
10
11
  const AlertDialogTrigger = AlertDialogPrimitive.Trigger
12
+ AlertDialogTrigger.displayName = 'AlertDialogTrigger'
11
13
 
12
14
  const AlertDialogPortal = AlertDialogPrimitive.Portal
15
+ AlertDialogPortal.displayName = 'AlertDialogPortal'
13
16
 
14
17
  const AlertDialogOverlay = React.forwardRef<
15
18
  React.ComponentRef<typeof AlertDialogPrimitive.Overlay>,
@@ -46,13 +49,17 @@ const AlertDialogContent = React.forwardRef<
46
49
  ))
47
50
  AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName
48
51
 
49
- const AlertDialogHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
50
- <div className={cn('flex flex-col space-y-2 text-center sm:text-start', className)} {...props} />
52
+ const AlertDialogHeader = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
53
+ ({ className, ...props }, ref) => (
54
+ <div ref={ref} className={cn('flex flex-col space-y-2 text-center sm:text-start', className)} {...props} />
55
+ ),
51
56
  )
52
57
  AlertDialogHeader.displayName = 'AlertDialogHeader'
53
58
 
54
- const AlertDialogFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
55
- <div className={cn('flex flex-col-reverse sm:flex-row sm:justify-end sm:gap-2', className)} {...props} />
59
+ const AlertDialogFooter = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
60
+ ({ className, ...props }, ref) => (
61
+ <div ref={ref} className={cn('flex flex-col-reverse sm:flex-row sm:justify-end sm:gap-2', className)} {...props} />
62
+ ),
56
63
  )
57
64
  AlertDialogFooter.displayName = 'AlertDialogFooter'
58
65
 
@@ -3,17 +3,14 @@
3
3
  import { cn } from '@gentleduck/libs/cn'
4
4
  import { type Direction, useDirection } from '@gentleduck/primitives/direction'
5
5
  import { Slot } from '@gentleduck/primitives/slot'
6
+ import React from 'react'
6
7
 
7
- function AspectRatio({
8
- style,
9
- className,
10
- ratio,
11
- ref,
12
- dir,
13
- ...props
14
- }: React.ComponentPropsWithRef<typeof Slot> & {
15
- ratio: string
16
- }) {
8
+ const AspectRatio = React.forwardRef<
9
+ React.ComponentRef<typeof Slot>,
10
+ React.ComponentPropsWithoutRef<typeof Slot> & {
11
+ ratio: string
12
+ }
13
+ >(({ style, className, ratio, dir, ...props }, ref) => {
17
14
  const direction = useDirection(dir as Direction)
18
15
  return (
19
16
  <Slot
@@ -28,6 +25,7 @@ function AspectRatio({
28
25
  data-slot="aspect-ratio"
29
26
  />
30
27
  )
31
- }
28
+ })
29
+ AspectRatio.displayName = 'AspectRatio'
32
30
 
33
31
  export { AspectRatio }
@@ -337,7 +337,19 @@ const AudioVisualizer: React.FC<AudioVisualizerProps> = ({
337
337
  setLoading,
338
338
  width,
339
339
  })
340
- }, [blob])
340
+ }, [
341
+ blob,
342
+ barWidth,
343
+ currentColors.backgroundColor,
344
+ currentColors.barColor,
345
+ currentColors.barPlayedColor,
346
+ gap,
347
+ height,
348
+ minBarHeight,
349
+ process_audio,
350
+ setLoading,
351
+ width,
352
+ ])
341
353
 
342
354
  React.useEffect(() => {
343
355
  if (!canvasRef.current) return
@@ -359,7 +371,19 @@ const AudioVisualizer: React.FC<AudioVisualizerProps> = ({
359
371
  gap,
360
372
  minBarHeight,
361
373
  })
362
- }, [data, width, height, currentTime, duration, animationProgress, theme])
374
+ }, [
375
+ data,
376
+ width,
377
+ currentTime,
378
+ duration,
379
+ animationProgress,
380
+ barWidth,
381
+ currentColors.backgroundColor,
382
+ currentColors.barColor,
383
+ currentColors.barPlayedColor,
384
+ gap,
385
+ minBarHeight,
386
+ ])
363
387
 
364
388
  return (
365
389
  <canvas
@@ -374,4 +398,6 @@ const AudioVisualizer: React.FC<AudioVisualizerProps> = ({
374
398
  )
375
399
  }
376
400
 
401
+ AudioVisualizer.displayName = 'AudioVisualizer'
402
+
377
403
  export { AudioVisualizer }
@@ -6,8 +6,7 @@ export interface RecordingParams {
6
6
 
7
7
  export interface StopRecordingHandlerParam {
8
8
  setRecording: React.Dispatch<React.SetStateAction<boolean>>
9
- // @ts-ignore
10
- intervalRef: React.RefObject<NodeJS.Timeout | null>
9
+ intervalRef: React.RefObject<ReturnType<typeof setInterval> | null>
11
10
  mediaRecorderRef: React.RefObject<MediaRecorder | null>
12
11
  durationRef: React.RefObject<number>
13
12
  }
@@ -0,0 +1,80 @@
1
+ import { describe, expect, test } from 'bun:test'
2
+ import * as React from 'react'
3
+ import { renderToStaticMarkup } from 'react-dom/server'
4
+ import { AnimationIcon, Button } from '../button'
5
+ import { buttonVariants } from '../button.constants'
6
+
7
+ describe('registry-ui button', () => {
8
+ test('buttonVariants returns the shared base styles and defaults', () => {
9
+ const classes = buttonVariants()
10
+
11
+ expect(classes).toContain('inline-flex')
12
+ expect(classes).toContain('bg-primary')
13
+ expect(classes).toContain('h-9')
14
+ })
15
+
16
+ test('buttonVariants applies explicit variant and size overrides', () => {
17
+ const classes = buttonVariants({ size: 'sm', variant: 'ghost' })
18
+
19
+ expect(classes).toContain('h-8')
20
+ expect(classes).toContain('hover:bg-accent')
21
+ })
22
+
23
+ test('button exports keep stable display names', () => {
24
+ expect(Button).toBeDefined()
25
+ expect(Button.displayName).toBe('Button')
26
+ expect(AnimationIcon.displayName).toBe('AnimationIcon')
27
+ })
28
+
29
+ test('Button renders loading state as a busy disabled native button', () => {
30
+ const html = renderToStaticMarkup(<Button loading>Save</Button>)
31
+
32
+ expect(html).toContain('type="button"')
33
+ expect(html).toContain('aria-busy="true"')
34
+ expect(html).toContain('disabled=""')
35
+ expect(html).toContain('animate-spin')
36
+ expect(html).toContain('Save')
37
+ })
38
+
39
+ test('Button preserves explicit disabled state even when loading is false', () => {
40
+ const html = renderToStaticMarkup(
41
+ <Button disabled loading={false}>
42
+ Save
43
+ </Button>,
44
+ )
45
+
46
+ expect(html).toContain('disabled=""')
47
+ expect(html).not.toContain('aria-busy="true"')
48
+ })
49
+
50
+ test('Button collapses into icon-only mode and hides secondary content', () => {
51
+ const html = renderToStaticMarkup(
52
+ <Button icon={<span data-icon="left">L</span>} isCollapsed secondIcon={<span data-icon="right">R</span>}>
53
+ Save
54
+ </Button>,
55
+ )
56
+
57
+ expect(html).toContain('data-icon="left"')
58
+ expect(html).toContain('size-9')
59
+ expect(html).not.toContain('Save')
60
+ expect(html).not.toContain('data-icon="right"')
61
+ })
62
+
63
+ test('AnimationIcon renders left and right placements around children', () => {
64
+ const leftHtml = renderToStaticMarkup(
65
+ <AnimationIcon animationIcon={{ icon: <span data-icon="left">L</span>, iconPlacement: 'left' }}>
66
+ Label
67
+ </AnimationIcon>,
68
+ )
69
+ const rightHtml = renderToStaticMarkup(
70
+ <AnimationIcon animationIcon={{ icon: <span data-icon="right">R</span>, iconPlacement: 'right' }}>
71
+ Label
72
+ </AnimationIcon>,
73
+ )
74
+
75
+ expect(leftHtml).toContain('data-icon="left"')
76
+ expect(leftHtml.indexOf('data-icon="left"')).toBeLessThan(leftHtml.indexOf('Label'))
77
+ expect(rightHtml).toContain('data-icon="right"')
78
+ expect(rightHtml.indexOf('Label')).toBeLessThan(rightHtml.indexOf('data-icon="right"'))
79
+ })
80
+ })
@@ -42,7 +42,7 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
42
42
  variant,
43
43
  }),
44
44
  )}
45
- disabled={loading ?? disabled}
45
+ disabled={Boolean(loading) || disabled}
46
46
  ref={ref}
47
47
  type={type}>
48
48
  {loading ? <Loader aria-hidden="true" className="animate-spin" /> : icon}
@@ -12,6 +12,7 @@ const ButtonGroup = React.forwardRef<
12
12
  >(({ className, orientation = 'horizontal', dir, ...props }, ref) => {
13
13
  const direction = useDirection(dir as Direction)
14
14
  return (
15
+ // biome-ignore lint/a11y/useSemanticElements: group role is semantically correct for button groups
15
16
  <div
16
17
  className={cn(buttonGroupVariants({ orientation }), className)}
17
18
  data-orientation={orientation}