@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.
- package/LICENSE +21 -0
- package/README.md +26 -0
- package/package.json +86 -0
- package/src/hooks/use-copy-to-clipboard.ts +44 -0
- package/src/hooks/use-mobile.ts +19 -0
- package/src/hooks/use-scrolled.ts +30 -0
- package/src/index.ts +99 -0
- package/src/lib/date-locale.ts +29 -0
- package/src/lib/utils.ts +6 -0
- package/src/lib/validation-messages.ts +19 -0
- package/src/spree/address-block.tsx +74 -0
- package/src/spree/back-button.tsx +48 -0
- package/src/spree/bulk-dialog.tsx +71 -0
- package/src/spree/bulk-price-table.tsx +254 -0
- package/src/spree/calculator-summary.tsx +120 -0
- package/src/spree/color-picker.tsx +202 -0
- package/src/spree/confirm-dialog.tsx +82 -0
- package/src/spree/copy-to-clipboard-button.tsx +90 -0
- package/src/spree/country-flag.tsx +30 -0
- package/src/spree/data-grid/cells.tsx +415 -0
- package/src/spree/data-grid/context.ts +59 -0
- package/src/spree/data-grid/data-grid.tsx +214 -0
- package/src/spree/data-grid/fill-handle.tsx +153 -0
- package/src/spree/data-grid/helpers.ts +18 -0
- package/src/spree/data-grid/index.ts +5 -0
- package/src/spree/data-grid/types.ts +36 -0
- package/src/spree/data-grid/use-data-grid-keyboard.ts +254 -0
- package/src/spree/data-grid/use-stable-cell-registration.ts +45 -0
- package/src/spree/drag-handle.tsx +51 -0
- package/src/spree/form-actions.tsx +140 -0
- package/src/spree/json-preview-drawer.tsx +254 -0
- package/src/spree/json-value-view.tsx +149 -0
- package/src/spree/language-menu-items.tsx +54 -0
- package/src/spree/metadata/metadata-card.tsx +62 -0
- package/src/spree/relative-time.tsx +49 -0
- package/src/spree/resource-combobox.tsx +108 -0
- package/src/spree/resource-layout.tsx +31 -0
- package/src/spree/resource-multi-autocomplete.tsx +180 -0
- package/src/spree/resource-name-cell.tsx +44 -0
- package/src/spree/route-error-boundary.tsx +102 -0
- package/src/spree/row-actions.tsx +85 -0
- package/src/spree/row-click-bridge.tsx +17 -0
- package/src/spree/secret-input.tsx +137 -0
- package/src/spree/storefront-visible-switch.tsx +58 -0
- package/src/spree/tag-list.tsx +26 -0
- package/src/spree/theme-provider.tsx +83 -0
- package/src/spree/theme-toggle.tsx +35 -0
- package/src/styles.css +338 -0
- package/src/ui/attachment.tsx +187 -0
- package/src/ui/avatar.tsx +94 -0
- package/src/ui/badge.tsx +161 -0
- package/src/ui/breadcrumb.tsx +109 -0
- package/src/ui/button.tsx +60 -0
- package/src/ui/calendar.tsx +66 -0
- package/src/ui/card.tsx +72 -0
- package/src/ui/chart.tsx +94 -0
- package/src/ui/checkbox.tsx +50 -0
- package/src/ui/collapsible.tsx +18 -0
- package/src/ui/combobox.tsx +270 -0
- package/src/ui/command.tsx +172 -0
- package/src/ui/data-table.tsx +60 -0
- package/src/ui/date-picker.tsx +253 -0
- package/src/ui/date-range-picker.tsx +150 -0
- package/src/ui/dialog.tsx +214 -0
- package/src/ui/dropdown-menu.tsx +345 -0
- package/src/ui/empty.tsx +94 -0
- package/src/ui/field.tsx +221 -0
- package/src/ui/input-group.tsx +141 -0
- package/src/ui/input.tsx +19 -0
- package/src/ui/label.tsx +29 -0
- package/src/ui/pagination.tsx +123 -0
- package/src/ui/popover.tsx +76 -0
- package/src/ui/progress.tsx +73 -0
- package/src/ui/radio-group.tsx +42 -0
- package/src/ui/rich-text-editor.tsx +263 -0
- package/src/ui/select.tsx +213 -0
- package/src/ui/separator.tsx +31 -0
- package/src/ui/sheet.tsx +208 -0
- package/src/ui/sidebar.tsx +679 -0
- package/src/ui/skeleton.tsx +13 -0
- package/src/ui/slot.tsx +35 -0
- package/src/ui/sonner.tsx +47 -0
- package/src/ui/switch.tsx +39 -0
- package/src/ui/textarea.tsx +18 -0
- package/src/ui/tooltip.tsx +100 -0
package/src/ui/slot.tsx
ADDED
|
@@ -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 }
|