@spree/dashboard-ui 0.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 (85) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +26 -0
  3. package/package.json +86 -0
  4. package/src/hooks/use-copy-to-clipboard.ts +44 -0
  5. package/src/hooks/use-mobile.ts +19 -0
  6. package/src/hooks/use-scrolled.ts +30 -0
  7. package/src/index.ts +99 -0
  8. package/src/lib/date-locale.ts +29 -0
  9. package/src/lib/utils.ts +6 -0
  10. package/src/lib/validation-messages.ts +19 -0
  11. package/src/spree/address-block.tsx +74 -0
  12. package/src/spree/back-button.tsx +48 -0
  13. package/src/spree/bulk-dialog.tsx +71 -0
  14. package/src/spree/bulk-price-table.tsx +254 -0
  15. package/src/spree/calculator-summary.tsx +120 -0
  16. package/src/spree/color-picker.tsx +202 -0
  17. package/src/spree/confirm-dialog.tsx +82 -0
  18. package/src/spree/copy-to-clipboard-button.tsx +90 -0
  19. package/src/spree/country-flag.tsx +30 -0
  20. package/src/spree/data-grid/cells.tsx +415 -0
  21. package/src/spree/data-grid/context.ts +59 -0
  22. package/src/spree/data-grid/data-grid.tsx +214 -0
  23. package/src/spree/data-grid/fill-handle.tsx +153 -0
  24. package/src/spree/data-grid/helpers.ts +18 -0
  25. package/src/spree/data-grid/index.ts +5 -0
  26. package/src/spree/data-grid/types.ts +36 -0
  27. package/src/spree/data-grid/use-data-grid-keyboard.ts +254 -0
  28. package/src/spree/data-grid/use-stable-cell-registration.ts +45 -0
  29. package/src/spree/drag-handle.tsx +51 -0
  30. package/src/spree/form-actions.tsx +140 -0
  31. package/src/spree/json-preview-drawer.tsx +254 -0
  32. package/src/spree/json-value-view.tsx +149 -0
  33. package/src/spree/language-menu-items.tsx +54 -0
  34. package/src/spree/metadata/metadata-card.tsx +62 -0
  35. package/src/spree/relative-time.tsx +49 -0
  36. package/src/spree/resource-combobox.tsx +108 -0
  37. package/src/spree/resource-layout.tsx +31 -0
  38. package/src/spree/resource-multi-autocomplete.tsx +180 -0
  39. package/src/spree/resource-name-cell.tsx +44 -0
  40. package/src/spree/route-error-boundary.tsx +102 -0
  41. package/src/spree/row-actions.tsx +85 -0
  42. package/src/spree/row-click-bridge.tsx +17 -0
  43. package/src/spree/secret-input.tsx +137 -0
  44. package/src/spree/storefront-visible-switch.tsx +58 -0
  45. package/src/spree/tag-list.tsx +26 -0
  46. package/src/spree/theme-provider.tsx +83 -0
  47. package/src/spree/theme-toggle.tsx +35 -0
  48. package/src/styles.css +338 -0
  49. package/src/ui/attachment.tsx +187 -0
  50. package/src/ui/avatar.tsx +94 -0
  51. package/src/ui/badge.tsx +161 -0
  52. package/src/ui/breadcrumb.tsx +109 -0
  53. package/src/ui/button.tsx +60 -0
  54. package/src/ui/calendar.tsx +66 -0
  55. package/src/ui/card.tsx +72 -0
  56. package/src/ui/chart.tsx +94 -0
  57. package/src/ui/checkbox.tsx +50 -0
  58. package/src/ui/collapsible.tsx +18 -0
  59. package/src/ui/combobox.tsx +270 -0
  60. package/src/ui/command.tsx +172 -0
  61. package/src/ui/data-table.tsx +60 -0
  62. package/src/ui/date-picker.tsx +253 -0
  63. package/src/ui/date-range-picker.tsx +150 -0
  64. package/src/ui/dialog.tsx +214 -0
  65. package/src/ui/dropdown-menu.tsx +345 -0
  66. package/src/ui/empty.tsx +94 -0
  67. package/src/ui/field.tsx +221 -0
  68. package/src/ui/input-group.tsx +141 -0
  69. package/src/ui/input.tsx +19 -0
  70. package/src/ui/label.tsx +29 -0
  71. package/src/ui/pagination.tsx +123 -0
  72. package/src/ui/popover.tsx +76 -0
  73. package/src/ui/progress.tsx +73 -0
  74. package/src/ui/radio-group.tsx +42 -0
  75. package/src/ui/rich-text-editor.tsx +263 -0
  76. package/src/ui/select.tsx +213 -0
  77. package/src/ui/separator.tsx +31 -0
  78. package/src/ui/sheet.tsx +208 -0
  79. package/src/ui/sidebar.tsx +679 -0
  80. package/src/ui/skeleton.tsx +13 -0
  81. package/src/ui/slot.tsx +35 -0
  82. package/src/ui/sonner.tsx +47 -0
  83. package/src/ui/switch.tsx +39 -0
  84. package/src/ui/textarea.tsx +18 -0
  85. package/src/ui/tooltip.tsx +100 -0
@@ -0,0 +1,35 @@
1
+ import * as React from 'react'
2
+ import { cn } from '../lib/utils'
3
+
4
+ /**
5
+ * A simple Slot component that merges props onto its single child element.
6
+ * This replaces the Radix UI `Slot` primitive for `asChild`-style composition.
7
+ */
8
+ function Slot({
9
+ children,
10
+ ...props
11
+ }: React.HTMLAttributes<HTMLElement> & { children?: React.ReactNode }) {
12
+ if (React.isValidElement(children)) {
13
+ const childProps = children.props as Record<string, unknown>
14
+ return React.cloneElement(children, {
15
+ ...props,
16
+ ...childProps,
17
+ className: cn(
18
+ (props as Record<string, unknown>).className as string | undefined,
19
+ childProps.className as string | undefined,
20
+ ),
21
+ style: {
22
+ ...((props as Record<string, unknown>).style as React.CSSProperties | undefined),
23
+ ...(childProps.style as React.CSSProperties | undefined),
24
+ },
25
+ } as React.HTMLAttributes<HTMLElement>)
26
+ }
27
+
28
+ if (React.Children.count(children) > 1) {
29
+ React.Children.only(null)
30
+ }
31
+
32
+ return null
33
+ }
34
+
35
+ export { Slot }
@@ -0,0 +1,47 @@
1
+ import {
2
+ CircleCheckIcon,
3
+ InfoIcon,
4
+ Loader2Icon,
5
+ OctagonXIcon,
6
+ TriangleAlertIcon,
7
+ } from 'lucide-react'
8
+ import type { CSSProperties } from 'react'
9
+ import { Toaster as Sonner, type ToasterProps } from 'sonner'
10
+ import { useTheme } from '../spree/theme-provider'
11
+
12
+ const Toaster = ({ ...props }: ToasterProps) => {
13
+ // The shadcn-default Sonner template assumes `next-themes`. This app has its
14
+ // own ThemeProvider that exposes a `mode` (the user's selection: light/dark/system)
15
+ // — Sonner's `theme` prop accepts the same three values, so we forward it.
16
+ const { mode } = useTheme()
17
+
18
+ return (
19
+ <Sonner
20
+ theme={mode as ToasterProps['theme']}
21
+ className="toaster group"
22
+ icons={{
23
+ success: <CircleCheckIcon className="size-4" />,
24
+ info: <InfoIcon className="size-4" />,
25
+ warning: <TriangleAlertIcon className="size-4" />,
26
+ error: <OctagonXIcon className="size-4" />,
27
+ loading: <Loader2Icon className="size-4 animate-spin" />,
28
+ }}
29
+ style={
30
+ {
31
+ '--normal-bg': 'var(--popover)',
32
+ '--normal-text': 'var(--popover-foreground)',
33
+ '--normal-border': 'var(--border)',
34
+ '--border-radius': 'var(--radius)',
35
+ } as CSSProperties
36
+ }
37
+ toastOptions={{
38
+ classNames: {
39
+ toast: 'cn-toast',
40
+ },
41
+ }}
42
+ {...props}
43
+ />
44
+ )
45
+ }
46
+
47
+ export { Toaster }
@@ -0,0 +1,39 @@
1
+ import { Switch as SwitchPrimitive } from '@base-ui/react/switch'
2
+ import type * as React from 'react'
3
+ import { cn } from '../lib/utils'
4
+
5
+ function Switch({
6
+ className,
7
+ checked,
8
+ defaultChecked,
9
+ onCheckedChange,
10
+ disabled,
11
+ name,
12
+ ...props
13
+ }: Omit<React.ComponentProps<typeof SwitchPrimitive.Root>, 'children'> & {
14
+ onCheckedChange?: (checked: boolean) => void
15
+ }) {
16
+ return (
17
+ <SwitchPrimitive.Root
18
+ data-slot="switch"
19
+ checked={checked}
20
+ defaultChecked={defaultChecked}
21
+ onCheckedChange={onCheckedChange ? (checked) => onCheckedChange(checked) : undefined}
22
+ disabled={disabled}
23
+ name={name}
24
+ className={cn(
25
+ 'peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-xs transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[checked]:bg-blue-600 data-[unchecked]:bg-input',
26
+ className,
27
+ )}
28
+ {...props}
29
+ >
30
+ <SwitchPrimitive.Thumb
31
+ className={cn(
32
+ 'pointer-events-none block h-4 w-4 rounded-full bg-white shadow-lg ring-0 transition-transform data-[checked]:translate-x-4 data-[unchecked]:translate-x-0',
33
+ )}
34
+ />
35
+ </SwitchPrimitive.Root>
36
+ )
37
+ }
38
+
39
+ export { Switch }
@@ -0,0 +1,18 @@
1
+ import * as React from 'react'
2
+
3
+ import { cn } from '../lib/utils'
4
+
5
+ function Textarea({ className, ...props }: React.ComponentProps<'textarea'>) {
6
+ return (
7
+ <textarea
8
+ data-slot="textarea"
9
+ className={cn(
10
+ 'flex field-sizing-content min-h-16 w-full rounded-lg border border-border bg-card px-2.5 py-1.5 text-base font-normal leading-normal text-foreground shadow-xs transition-all duration-100 ease-in-out outline-none placeholder:text-muted-foreground focus:border-blue-500 focus:shadow-[0_0_0_3px_rgba(59,130,246,0.15)] disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-muted disabled:border-border disabled:text-muted-foreground disabled:shadow-none aria-invalid:border-destructive',
11
+ className,
12
+ )}
13
+ {...props}
14
+ />
15
+ )
16
+ }
17
+
18
+ export { Textarea }
@@ -0,0 +1,100 @@
1
+ 'use client'
2
+
3
+ import { Tooltip as TooltipPrimitive } from '@base-ui/react/tooltip'
4
+ import * as React from 'react'
5
+
6
+ import { cn } from '../lib/utils'
7
+
8
+ function TooltipProvider({
9
+ delayDuration = 0,
10
+ children,
11
+ ...props
12
+ }: {
13
+ delayDuration?: number
14
+ children: React.ReactNode
15
+ } & Omit<React.ComponentProps<typeof TooltipPrimitive.Provider>, 'delay'>) {
16
+ return (
17
+ <TooltipPrimitive.Provider data-slot="tooltip-provider" delay={delayDuration} {...props}>
18
+ {children}
19
+ </TooltipPrimitive.Provider>
20
+ )
21
+ }
22
+
23
+ function Tooltip({
24
+ children,
25
+ ...props
26
+ }: {
27
+ children?: React.ReactNode
28
+ open?: boolean
29
+ defaultOpen?: boolean
30
+ onOpenChange?: (open: boolean, eventDetails: TooltipPrimitive.Root.ChangeEventDetails) => void
31
+ }) {
32
+ return (
33
+ <TooltipPrimitive.Root data-slot="tooltip" {...props}>
34
+ {children}
35
+ </TooltipPrimitive.Root>
36
+ )
37
+ }
38
+
39
+ function TooltipTrigger({
40
+ asChild,
41
+ children,
42
+ ...props
43
+ }: React.ComponentProps<typeof TooltipPrimitive.Trigger> & {
44
+ asChild?: boolean
45
+ }) {
46
+ if (asChild && React.isValidElement(children)) {
47
+ return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" render={children} {...props} />
48
+ }
49
+
50
+ return (
51
+ <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props}>
52
+ {children}
53
+ </TooltipPrimitive.Trigger>
54
+ )
55
+ }
56
+
57
+ function TooltipContent({
58
+ className,
59
+ sideOffset = 4,
60
+ side = 'top',
61
+ align = 'center',
62
+ children,
63
+ hidden,
64
+ ...props
65
+ }: {
66
+ className?: string
67
+ sideOffset?: number
68
+ side?: 'top' | 'bottom' | 'left' | 'right'
69
+ align?: 'start' | 'center' | 'end'
70
+ children?: React.ReactNode
71
+ hidden?: boolean
72
+ } & Omit<React.ComponentProps<typeof TooltipPrimitive.Popup>, 'className'>) {
73
+ if (hidden) {
74
+ return null
75
+ }
76
+
77
+ return (
78
+ <TooltipPrimitive.Portal>
79
+ <TooltipPrimitive.Positioner
80
+ side={side}
81
+ sideOffset={sideOffset}
82
+ align={align}
83
+ className="z-50"
84
+ >
85
+ <TooltipPrimitive.Popup
86
+ data-slot="tooltip-content"
87
+ className={cn(
88
+ 'z-50 inline-flex w-fit max-w-[200px] items-center gap-1.5 rounded-lg border border-border bg-popover px-2 py-1 text-sm font-normal text-popover-foreground shadow-md data-[starting-style]:opacity-0 data-[starting-style]:scale-95 data-[ending-style]:opacity-0 data-[ending-style]:scale-95 transition-[opacity,transform] duration-100',
89
+ className,
90
+ )}
91
+ {...props}
92
+ >
93
+ {children}
94
+ </TooltipPrimitive.Popup>
95
+ </TooltipPrimitive.Positioner>
96
+ </TooltipPrimitive.Portal>
97
+ )
98
+ }
99
+
100
+ export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger }