@spree/dashboard-ui 6.0.3 → 6.0.4
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 +20 -19
- package/src/index.ts +5 -0
- package/src/lib/field-trigger.ts +10 -0
- package/src/lib/same-rich-text.ts +12 -3
- package/src/lib/utils.ts +14 -1
- package/src/spree/address-block.tsx +3 -3
- package/src/spree/address-book-row.tsx +88 -0
- package/src/spree/bulk-price-table.tsx +3 -3
- package/src/spree/claim-resolve-dialog.tsx +1 -1
- package/src/spree/collapsible-card.tsx +2 -2
- package/src/spree/color-picker.tsx +1 -1
- package/src/spree/currency-label.tsx +71 -0
- package/src/spree/data-grid/cells.tsx +2 -2
- package/src/spree/data-grid/data-grid.tsx +2 -2
- package/src/spree/delivery-form-dialog.tsx +1 -1
- package/src/spree/drag-handle.tsx +1 -1
- package/src/spree/editable-note-card.tsx +2 -2
- package/src/spree/form-actions.tsx +32 -10
- package/src/spree/fulfill-items-form.tsx +20 -22
- package/src/spree/fulfillment-edit-dialog.tsx +1 -1
- package/src/spree/fulfillment-item-list.tsx +87 -28
- package/src/spree/fulfillment-panel.tsx +2 -2
- package/src/spree/icons.ts +8 -0
- package/src/spree/json-preview-drawer.tsx +32 -7
- package/src/spree/json-value-view.tsx +14 -4
- package/src/spree/label-upload-dialog.tsx +1 -1
- package/src/spree/language-menu-items.tsx +1 -1
- package/src/spree/metadata/metadata-card.tsx +2 -2
- package/src/spree/order-cancel-dialog.tsx +3 -3
- package/src/spree/post-sale-create-dialogs.tsx +36 -33
- package/src/spree/post-sale-fields.tsx +30 -1
- package/src/spree/product-identity.tsx +74 -0
- package/src/spree/product-membership-list.tsx +79 -41
- package/src/spree/products/status-card.tsx +1 -1
- package/src/spree/quantity-tier-editor.tsx +1 -1
- package/src/spree/return-dialogs.tsx +2 -2
- package/src/spree/search-input.tsx +3 -1
- package/src/spree/secret-input.tsx +1 -1
- package/src/spree/section.tsx +55 -0
- package/src/spree/stat-item.tsx +27 -0
- package/src/spree/tax-identifiers-card.tsx +117 -76
- package/src/spree/theme-toggle.tsx +1 -1
- package/src/spree/wizard.tsx +2 -2
- package/src/styles.css +226 -120
- package/src/ui/alert.tsx +20 -17
- package/src/ui/attachment.tsx +1 -1
- package/src/ui/avatar.tsx +2 -2
- package/src/ui/badge.tsx +1 -1
- package/src/ui/breadcrumb.tsx +1 -1
- package/src/ui/button.tsx +14 -11
- package/src/ui/calendar.tsx +2 -2
- package/src/ui/card.tsx +14 -37
- package/src/ui/chart.tsx +1 -1
- package/src/ui/checkbox.tsx +2 -2
- package/src/ui/code-editor.tsx +6 -2
- package/src/ui/collapsible.tsx +21 -2
- package/src/ui/combobox.tsx +12 -16
- package/src/ui/command.tsx +8 -6
- package/src/ui/context-menu.tsx +1 -1
- package/src/ui/data-table.tsx +58 -15
- package/src/ui/date-picker.tsx +3 -3
- package/src/ui/date-range-panel.tsx +102 -0
- package/src/ui/date-range-picker.tsx +33 -72
- package/src/ui/dialog.tsx +3 -3
- package/src/ui/dropdown-menu.tsx +6 -6
- package/src/ui/empty.tsx +3 -3
- package/src/ui/field.tsx +33 -12
- package/src/ui/input-group.tsx +17 -6
- package/src/ui/input.tsx +148 -4
- package/src/ui/item.tsx +7 -4
- package/src/ui/label.tsx +1 -1
- package/src/ui/media-preview.tsx +40 -5
- package/src/ui/pagination.tsx +16 -4
- package/src/ui/progress.tsx +2 -2
- package/src/ui/radio-group.tsx +2 -2
- package/src/ui/rich-text-editor.tsx +3 -3
- package/src/ui/select.tsx +7 -16
- package/src/ui/sheet.tsx +13 -5
- package/src/ui/sidebar.tsx +5 -5
- package/src/ui/switch.tsx +8 -2
- package/src/ui/tabs.tsx +45 -9
- package/src/ui/textarea.tsx +1 -1
- package/src/ui/toast.tsx +2 -2
- package/src/ui/tooltip.tsx +1 -1
package/src/ui/sidebar.tsx
CHANGED
|
@@ -361,7 +361,7 @@ function SidebarInset({ className, id = 'main-content', ...props }: React.Compon
|
|
|
361
361
|
// The inset sheet is the raised surface, so it takes the card colour —
|
|
362
362
|
// pure white in light mode — rather than the page grey, which is now the
|
|
363
363
|
// ground the rail sits on.
|
|
364
|
-
'relative z-0 flex w-full min-w-0 flex-1 flex-col bg-background md:peer-data-[variant=inset]:bg-card md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-
|
|
364
|
+
'relative z-0 flex w-full min-w-0 flex-1 flex-col bg-background md:peer-data-[variant=inset]:bg-card md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-2xl md:peer-data-[variant=inset]:border md:peer-data-[variant=inset]:border-sidebar-border',
|
|
365
365
|
className,
|
|
366
366
|
)}
|
|
367
367
|
{...props}
|
|
@@ -548,7 +548,7 @@ function SidebarGroupContent({ className, ...props }: React.ComponentProps<'div'
|
|
|
548
548
|
<div
|
|
549
549
|
data-slot="sidebar-group-content"
|
|
550
550
|
data-sidebar="group-content"
|
|
551
|
-
className={cn('w-full text-
|
|
551
|
+
className={cn('w-full text-base', className)}
|
|
552
552
|
{...props}
|
|
553
553
|
/>
|
|
554
554
|
)
|
|
@@ -587,7 +587,7 @@ const sidebarMenuButtonVariants = cva(
|
|
|
587
587
|
// badge. Without it the flex line wraps and the label visibly squashes to two
|
|
588
588
|
// lines inside the fixed height until the animation lands. Labels clip
|
|
589
589
|
// instead — which is what the `truncate` below already intends.
|
|
590
|
-
'peer/menu-button group/menu-button flex gap-2 w-full items-center overflow-hidden whitespace-nowrap rounded-
|
|
590
|
+
'peer/menu-button group/menu-button flex gap-2 w-full items-center overflow-hidden whitespace-nowrap rounded-lg p-1 text-left font-normal text-base text-sidebar-foreground/80 outline-hidden transition-[color,background-color,border-color,box-shadow] duration-100 ease-out group-has-data-[sidebar=menu-action]/menu-item:pr-8 group-data-[collapsible=icon]:size-10! group-data-[collapsible=icon]:items-center group-data-[collapsible=icon]:justify-center group-data-[collapsible=icon]:overflow-visible group-data-[collapsible=icon]:p-0! group-data-[collapsible=icon]:gap-0 group-data-[collapsible=icon]:[&>span:last-child]:hidden hover:bg-sidebar-accent-hover hover:text-sidebar-foreground focus-visible:shadow-[0_0_0_3px_color-mix(in_srgb,var(--ring)_15%,transparent)] disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-open:hover:bg-sidebar-accent-hover data-open:hover:text-sidebar-foreground data-active:bg-sidebar-active data-active:text-foreground data-active:font-semibold data-active:hover:bg-sidebar-active-hover [&>span:last-child]:truncate',
|
|
591
591
|
{
|
|
592
592
|
variants: {
|
|
593
593
|
variant: {
|
|
@@ -601,7 +601,7 @@ const sidebarMenuButtonVariants = cva(
|
|
|
601
601
|
// desktop rail keeps its compact pointer-sized rows.
|
|
602
602
|
default:
|
|
603
603
|
'h-8 text-base in-data-[mobile=true]:h-12 in-data-[mobile=true]:px-2 in-data-[mobile=true]:[&_svg]:size-5',
|
|
604
|
-
sm: 'h-7 text-xs in-data-[mobile=true]:h-11 in-data-[mobile=true]:text-
|
|
604
|
+
sm: 'h-7 text-xs in-data-[mobile=true]:h-11 in-data-[mobile=true]:text-base',
|
|
605
605
|
lg: 'h-12 text-base group-data-[collapsible=icon]:p-0!',
|
|
606
606
|
},
|
|
607
607
|
},
|
|
@@ -798,7 +798,7 @@ function SidebarMenuSubButton({
|
|
|
798
798
|
data-size={size}
|
|
799
799
|
data-active={isActive}
|
|
800
800
|
className={cn(
|
|
801
|
-
'relative flex h-7 in-data-[mobile=true]:h-11 in-data-[mobile=true]:px-2 min-w-0 items-center gap-2 overflow-hidden rounded-lg p-1 font-
|
|
801
|
+
'relative flex h-7 in-data-[mobile=true]:h-11 in-data-[mobile=true]:px-2 min-w-0 items-center gap-2 overflow-hidden rounded-lg p-1 font-normal text-sidebar-foreground/80 outline-hidden group-data-[collapsible=icon]:hidden hover:bg-sidebar-accent-hover hover:text-sidebar-foreground focus-visible:shadow-[0_0_0_3px_color-mix(in_srgb,var(--ring)_15%,transparent)] disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[size=md]:text-base data-[size=sm]:text-xs data-active:font-semibold data-active:text-foreground data-active:bg-transparent data-active:shadow-none data-active:before:absolute data-active:before:-left-4 data-active:before:top-[10%] data-active:before:h-[80%] data-active:before:w-[3px] data-active:before:rounded-sm data-active:before:bg-foreground [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0',
|
|
802
802
|
className,
|
|
803
803
|
)}
|
|
804
804
|
{...props}
|
package/src/ui/switch.tsx
CHANGED
|
@@ -22,14 +22,20 @@ function Switch({
|
|
|
22
22
|
disabled={disabled}
|
|
23
23
|
name={name}
|
|
24
24
|
className={cn(
|
|
25
|
-
|
|
25
|
+
// A flat track with a hairline edge instead of depth, and a capsule
|
|
26
|
+
// knob wider than it is tall, after the macOS switch.
|
|
27
|
+
// Base UI renders a <span>, which is never `:disabled`, so disabled
|
|
28
|
+
// styles key off `data-disabled`.
|
|
29
|
+
'group/switch peer inline-flex h-[18px] w-[34px] shrink-0 cursor-pointer items-center rounded-full p-0.5 shadow-[inset_0_0_0_0.5px_rgb(0_0_0/0.08)] transition-[background-color,box-shadow] duration-200 ease-out outline-none focus-visible:shadow-field-focus data-[checked]:bg-blue-500 data-[unchecked]:bg-switch-off data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50',
|
|
26
30
|
className,
|
|
27
31
|
)}
|
|
28
32
|
{...props}
|
|
29
33
|
>
|
|
30
34
|
<SwitchPrimitive.Thumb
|
|
31
35
|
className={cn(
|
|
32
|
-
|
|
36
|
+
// While pressed the knob turns to glass: it grows, clears to a
|
|
37
|
+
// frosted tint over the track, and keeps a bright rim.
|
|
38
|
+
'pointer-events-none block h-3.5 w-5 rounded-full bg-white shadow-[0_0_0_0.5px_rgb(0_0_0/0.06),0_1px_2px_rgb(0_0_0/0.1)] transition-[translate,scale,background-color,box-shadow] duration-200 ease-[cubic-bezier(0.3,1.3,0.6,1)] motion-reduce:transition-none data-[checked]:translate-x-2.5 data-[unchecked]:translate-x-0 group-active/switch:scale-x-[1.3] group-active/switch:scale-y-[1.2] group-active/switch:bg-white/35 group-active/switch:shadow-[inset_0_0_0_1px_rgb(255_255_255/0.85),0_1px_4px_rgb(0_0_0/0.15)] group-active/switch:backdrop-blur-[2px] group-data-[disabled]/switch:scale-100 group-data-[disabled]/switch:bg-white',
|
|
33
39
|
)}
|
|
34
40
|
/>
|
|
35
41
|
</SwitchPrimitive.Root>
|
package/src/ui/tabs.tsx
CHANGED
|
@@ -20,7 +20,25 @@ function Tabs({
|
|
|
20
20
|
)
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* The track a set of tabs sits in, a glass capsule in the manner of a macOS
|
|
25
|
+
* segmented control. The selected pill is an indicator that slides between
|
|
26
|
+
* tabs; until it has measured its tab, the selected tab draws the same pill
|
|
27
|
+
* itself.
|
|
28
|
+
*/
|
|
29
|
+
// The track: the recessed surface, edged by the faint divider rule. Flat — no
|
|
30
|
+
// blur or sheen, which a control this small would only muddy.
|
|
31
|
+
const TAB_TRACK = 'bg-track-recessed shadow-[inset_0_0_0_1px_var(--border-subtle)]'
|
|
32
|
+
|
|
33
|
+
// The selected tab's surface: a flat pill set off by its fill and a card's
|
|
34
|
+
// edge, never a drop shadow. A card's white in the light; in the dark the
|
|
35
|
+
// strong accent, the step a dark surface lifts to.
|
|
36
|
+
const TAB_RAISED = 'bg-card shadow-[0_0_0_1px_var(--card-edge)] dark:bg-accent-strong'
|
|
37
|
+
|
|
38
|
+
// Capsules side by side; a vertical stack keeps rounded rectangles, which read
|
|
39
|
+
// better as a column.
|
|
40
|
+
const TAB_SHAPE = 'rounded-full group-data-[orientation=vertical]/tabs:rounded-lg'
|
|
41
|
+
|
|
24
42
|
function TabsList({
|
|
25
43
|
className,
|
|
26
44
|
children,
|
|
@@ -30,12 +48,23 @@ function TabsList({
|
|
|
30
48
|
<TabsPrimitive.List
|
|
31
49
|
data-slot="tabs-list"
|
|
32
50
|
className={cn(
|
|
33
|
-
'inline-flex w-fit items-center justify-center gap-
|
|
51
|
+
'group/tabs-list relative inline-flex w-fit items-center justify-center gap-0.5 rounded-full p-0.5 text-muted-foreground group-data-[orientation=vertical]/tabs:rounded-xl',
|
|
52
|
+
TAB_TRACK,
|
|
34
53
|
'group-data-[orientation=vertical]/tabs:h-auto group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:flex-col',
|
|
35
54
|
className,
|
|
36
55
|
)}
|
|
37
56
|
{...props}
|
|
38
57
|
>
|
|
58
|
+
<TabsPrimitive.Indicator
|
|
59
|
+
data-slot="tabs-indicator"
|
|
60
|
+
className={cn(
|
|
61
|
+
TAB_RAISED,
|
|
62
|
+
TAB_SHAPE,
|
|
63
|
+
'absolute top-(--active-tab-top) left-(--active-tab-left) h-(--active-tab-height) w-(--active-tab-width)',
|
|
64
|
+
// The switch's curve, so the two controls move alike.
|
|
65
|
+
'transition-[left,top,width,height] duration-200 ease-[cubic-bezier(0.3,1.3,0.6,1)] motion-reduce:transition-none',
|
|
66
|
+
)}
|
|
67
|
+
/>
|
|
39
68
|
{children}
|
|
40
69
|
</TabsPrimitive.List>
|
|
41
70
|
)
|
|
@@ -58,17 +87,22 @@ function TabsTrigger({
|
|
|
58
87
|
className={cn(
|
|
59
88
|
// min-h-7 + py-1 keeps the hit area past the 24px WCAG target size at
|
|
60
89
|
// every text size; the old h-[calc(100%-1px)] left it to the parent.
|
|
61
|
-
'inline-flex min-h-7 flex-1 cursor-pointer items-center justify-center gap-1.5
|
|
90
|
+
'relative z-10 inline-flex min-h-7 flex-1 cursor-pointer items-center justify-center gap-1.5 px-3 py-1 text-base font-medium whitespace-nowrap',
|
|
62
91
|
'transition-[color,background-color,box-shadow] duration-150 ease-out outline-none motion-reduce:transition-none',
|
|
92
|
+
TAB_SHAPE,
|
|
63
93
|
'group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:justify-start',
|
|
64
94
|
// Unselected tabs recede so the selected one reads as chosen; hover
|
|
65
95
|
// promotes to full foreground rather than only shifting the surface,
|
|
66
96
|
// which is the part a colour-blind or low-vision reader can see.
|
|
67
|
-
|
|
68
|
-
//
|
|
69
|
-
|
|
70
|
-
//
|
|
71
|
-
|
|
97
|
+
// An unselected tab under the pointer takes a pill one step under the
|
|
98
|
+
// selected one, as a sidebar item does.
|
|
99
|
+
'text-muted-foreground hover:text-foreground not-data-[active]:hover:bg-accent-strong dark:not-data-[active]:hover:bg-accent',
|
|
100
|
+
// The selected tab draws its own pill until the indicator has
|
|
101
|
+
// measured it, so the selection never depends on that rendering;
|
|
102
|
+
// then it turns clear and the sliding indicator shows through.
|
|
103
|
+
cn(TAB_RAISED, 'not-data-[active]:bg-transparent not-data-[active]:shadow-none'),
|
|
104
|
+
'data-[active]:text-foreground',
|
|
105
|
+
'group-has-[>[data-slot=tabs-indicator]:not([hidden])]/tabs-list:bg-transparent group-has-[>[data-slot=tabs-indicator]:not([hidden])]/tabs-list:shadow-none',
|
|
72
106
|
// Same focus treatment as Button, so a keyboard user sees one
|
|
73
107
|
// consistent indicator across the dashboard.
|
|
74
108
|
'focus-visible:shadow-[0_0_0_3px_color-mix(in_srgb,var(--ring)_15%,transparent)]',
|
|
@@ -80,7 +114,9 @@ function TabsTrigger({
|
|
|
80
114
|
>
|
|
81
115
|
{children}
|
|
82
116
|
{count !== undefined && (
|
|
83
|
-
<span className="rounded-full bg-
|
|
117
|
+
<span className="rounded-full bg-accent-strong-hover px-1.5 py-0.5 text-xs text-foreground tabular-nums">
|
|
118
|
+
{count}
|
|
119
|
+
</span>
|
|
84
120
|
)}
|
|
85
121
|
</TabsPrimitive.Tab>
|
|
86
122
|
)
|
package/src/ui/textarea.tsx
CHANGED
|
@@ -7,7 +7,7 @@ function Textarea({ className, ...props }: React.ComponentProps<'textarea'>) {
|
|
|
7
7
|
<textarea
|
|
8
8
|
data-slot="textarea"
|
|
9
9
|
className={cn(
|
|
10
|
-
'flex field-sizing-content min-h-16 w-full rounded-
|
|
10
|
+
'flex field-sizing-content min-h-16 w-full cursor-default focus:cursor-text rounded-xl border border-field-border shadow-control bg-card px-2.5 py-1.5 text-base font-normal leading-normal text-foreground transition-[color,background-color,border-color,box-shadow] duration-100 ease-out outline-none placeholder:text-muted-foreground not-disabled:not-read-only:not-focus:hover:bg-field-hover focus:border-blue-500 focus:shadow-field-focus disabled:cursor-not-allowed disabled:bg-muted disabled:text-muted-foreground aria-invalid:border-destructive',
|
|
11
11
|
className,
|
|
12
12
|
)}
|
|
13
13
|
{...props}
|
package/src/ui/toast.tsx
CHANGED
|
@@ -121,10 +121,10 @@ function ToastList() {
|
|
|
121
121
|
<ToastContent>
|
|
122
122
|
<ToastIcon type={toast.type} />
|
|
123
123
|
<div className="flex min-w-0 flex-1 flex-col gap-1">
|
|
124
|
-
<ToastPrimitive.Title data-slot="toast-title" className="font-medium text-
|
|
124
|
+
<ToastPrimitive.Title data-slot="toast-title" className="font-medium text-base" />
|
|
125
125
|
<ToastPrimitive.Description
|
|
126
126
|
data-slot="toast-description"
|
|
127
|
-
className="text-muted-foreground text-
|
|
127
|
+
className="text-muted-foreground text-base"
|
|
128
128
|
/>
|
|
129
129
|
</div>
|
|
130
130
|
<ToastPrimitive.Action
|
package/src/ui/tooltip.tsx
CHANGED
|
@@ -87,7 +87,7 @@ function TooltipContent({
|
|
|
87
87
|
className={cn(
|
|
88
88
|
// `origin-(--transform-origin)` so it grows out of the element it
|
|
89
89
|
// describes rather than its own centre.
|
|
90
|
-
'z-50 inline-flex w-fit max-w-[200px] items-center gap-1.5 rounded-
|
|
90
|
+
'z-50 inline-flex w-fit max-w-[200px] items-center gap-1.5 rounded-xl border border-border bg-popover px-2 py-1 text-base font-normal text-popover-foreground shadow-md origin-(--transform-origin) data-[starting-style]:opacity-0 data-[starting-style]:scale-95 data-[ending-style]:opacity-0 data-[ending-style]:scale-95 transition-[opacity,transform,translate,scale] duration-100 ease-out',
|
|
91
91
|
className,
|
|
92
92
|
)}
|
|
93
93
|
{...props}
|