@vendure-io/ui 1.3.0 → 2.0.0-beta.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/README.md +5 -5
- package/package.json +9 -4
- package/src/components/{ui → atoms}/alert-dialog.tsx +4 -4
- package/src/components/{ui → atoms}/badge.tsx +6 -3
- package/src/components/{ui → atoms}/button-group.tsx +1 -2
- package/src/components/{ui → atoms}/button.tsx +8 -2
- package/src/components/{ui → atoms}/calendar.tsx +1 -1
- package/src/components/{ui → atoms}/card.tsx +2 -3
- package/src/components/{ui → atoms}/carousel.tsx +1 -1
- package/src/components/atoms/checkbox.tsx +29 -0
- package/src/components/{ui → atoms}/combobox.tsx +3 -4
- package/src/components/{ui → atoms}/command.tsx +2 -2
- package/src/components/{ui → atoms}/context-menu.tsx +1 -1
- package/src/components/{ui → atoms}/dialog.tsx +4 -4
- package/src/components/{ui → atoms}/drawer.tsx +3 -3
- package/src/components/{ui → atoms}/dropdown-menu.tsx +3 -2
- package/src/components/{ui → atoms}/empty.tsx +1 -1
- package/src/components/{ui → atoms}/field.tsx +2 -2
- package/src/components/{ui → atoms}/hover-card.tsx +1 -1
- package/src/components/{ui → atoms}/input-group.tsx +3 -4
- package/src/components/{ui → atoms}/input-otp.tsx +0 -1
- package/src/components/{ui → atoms}/input.tsx +0 -1
- package/src/components/{ui → atoms}/item.tsx +2 -2
- package/src/components/{ui → atoms}/menubar.tsx +3 -4
- package/src/components/{ui → atoms}/native-select.tsx +0 -1
- package/src/components/{ui → atoms}/navigation-menu.tsx +7 -4
- package/src/components/{ui → atoms}/pagination.tsx +1 -1
- package/src/components/{ui → atoms}/popover.tsx +2 -2
- package/src/components/{ui → atoms}/select.tsx +22 -4
- package/src/components/{ui → atoms}/sheet.tsx +4 -4
- package/src/components/{ui → atoms}/sidebar.tsx +6 -6
- package/src/components/atoms/skeleton.tsx +16 -0
- package/src/components/{ui → atoms}/slider.tsx +0 -1
- package/src/components/{ui → atoms}/sonner.tsx +1 -1
- package/src/components/{ui → atoms}/switch.tsx +0 -1
- package/src/components/{ui → atoms}/tabs.tsx +6 -4
- package/src/components/{ui → atoms}/textarea.tsx +0 -1
- package/src/components/{ui → atoms}/toggle-group.tsx +3 -3
- package/src/components/{ui → atoms}/toggle.tsx +0 -1
- package/src/components/{ui → atoms}/tooltip.tsx +2 -1
- package/src/components/molecules/anonymized-token.tsx +170 -0
- package/src/components/molecules/chip.tsx +85 -0
- package/src/components/{custom → molecules}/combobox-free-text.tsx +7 -3
- package/src/components/molecules/confirm-dialog.tsx +108 -0
- package/src/components/molecules/copyable-text.tsx +102 -0
- package/src/components/molecules/data-table/data-table-bulk-actions.tsx +69 -0
- package/src/components/molecules/data-table/data-table-column-header.tsx +61 -0
- package/src/components/molecules/data-table/data-table-filters.tsx +198 -0
- package/src/components/molecules/data-table/data-table-helpers.tsx +73 -0
- package/src/components/molecules/data-table/data-table-types.tsx +241 -0
- package/src/components/molecules/data-table/data-table-view-options.tsx +73 -0
- package/src/components/molecules/data-table/data-table.tsx +500 -0
- package/src/components/molecules/data-table/list-header.tsx +53 -0
- package/src/components/molecules/data-table/table-pagination.tsx +263 -0
- package/src/components/molecules/date-time.tsx +73 -0
- package/src/components/molecules/description-list.tsx +120 -0
- package/src/components/molecules/format-provider.tsx +46 -0
- package/src/components/molecules/id-chip.tsx +79 -0
- package/src/components/molecules/illustrations/access-denied.tsx +55 -0
- package/src/components/molecules/illustrations/empty-collection.tsx +66 -0
- package/src/components/molecules/illustrations/empty-database.tsx +44 -0
- package/src/components/molecules/illustrations/empty-media.tsx +68 -0
- package/src/components/molecules/illustrations/error.tsx +64 -0
- package/src/components/molecules/illustrations/first-run.tsx +55 -0
- package/src/components/molecules/illustrations/illustration-types.tsx +9 -0
- package/src/components/molecules/illustrations/no-activity.tsx +49 -0
- package/src/components/molecules/illustrations/no-deployments.tsx +49 -0
- package/src/components/molecules/illustrations/no-documents.tsx +67 -0
- package/src/components/molecules/illustrations/no-keys.tsx +50 -0
- package/src/components/molecules/illustrations/no-logs.tsx +53 -0
- package/src/components/molecules/illustrations/no-members.tsx +56 -0
- package/src/components/molecules/illustrations/no-notifications.tsx +52 -0
- package/src/components/molecules/illustrations/no-orders.tsx +48 -0
- package/src/components/molecules/illustrations/no-plugins.tsx +72 -0
- package/src/components/molecules/illustrations/no-results.tsx +69 -0
- package/src/components/molecules/illustrations/not-found.tsx +48 -0
- package/src/components/molecules/illustrations/offline.tsx +43 -0
- package/src/components/molecules/illustrations/pending-approval.tsx +56 -0
- package/src/components/molecules/illustrations/upload-dropzone.tsx +59 -0
- package/src/components/molecules/money.tsx +91 -0
- package/src/components/{custom → molecules}/multi-select.tsx +2 -2
- package/src/components/molecules/page-header.tsx +80 -0
- package/src/components/molecules/password-input.tsx +47 -0
- package/src/components/molecules/relative-time.tsx +81 -0
- package/src/components/molecules/stat-card.tsx +134 -0
- package/src/components/molecules/state-views/empty-state.tsx +75 -0
- package/src/components/molecules/state-views/error-state.tsx +91 -0
- package/src/components/molecules/state-views/loading-state.tsx +80 -0
- package/src/components/molecules/status-badge.tsx +100 -0
- package/src/hooks/use-copy.ts +51 -0
- package/src/lib/base-ui.ts +1 -1
- package/src/lib/format-relative.ts +41 -0
- package/src/lib/state-dictionary.ts +137 -0
- package/src/components/ui/checkbox.tsx +0 -30
- package/src/components/ui/skeleton.tsx +0 -13
- /package/src/components/{ui → atoms}/accordion.tsx +0 -0
- /package/src/components/{ui → atoms}/alert.tsx +0 -0
- /package/src/components/{ui → atoms}/aspect-ratio.tsx +0 -0
- /package/src/components/{ui → atoms}/avatar.tsx +0 -0
- /package/src/components/{ui → atoms}/breadcrumb.tsx +0 -0
- /package/src/components/{ui → atoms}/chart.tsx +0 -0
- /package/src/components/{ui → atoms}/collapsible.tsx +0 -0
- /package/src/components/{ui → atoms}/direction.tsx +0 -0
- /package/src/components/{ui → atoms}/kbd.tsx +0 -0
- /package/src/components/{ui → atoms}/label.tsx +0 -0
- /package/src/components/{ui → atoms}/progress.tsx +0 -0
- /package/src/components/{ui → atoms}/radio-group.tsx +0 -0
- /package/src/components/{ui → atoms}/resizable.tsx +0 -0
- /package/src/components/{ui → atoms}/scroll-area.tsx +0 -0
- /package/src/components/{ui → atoms}/separator.tsx +0 -0
- /package/src/components/{ui → atoms}/spinner.tsx +0 -0
- /package/src/components/{ui → atoms}/table.tsx +0 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { IllustrationProps } from '@vendure-io/ui/components/molecules/illustrations/illustration-types';
|
|
2
|
+
import { cn } from '@vendure-io/ui/lib/utils';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A bell at rest, its clapper still, with faint dashed arcs trailing off
|
|
6
|
+
* where a ring would sound — nothing new has come in. For an empty
|
|
7
|
+
* notifications/alerts panel where the user is caught up — pass as
|
|
8
|
+
* `illustration` to `EmptyState`. Not for a generic empty list with no bell
|
|
9
|
+
* shape (use `EmptyCollectionIllustration` instead).
|
|
10
|
+
*/
|
|
11
|
+
function NoNotificationsIllustration({ className, size = 160 }: IllustrationProps) {
|
|
12
|
+
return (
|
|
13
|
+
<svg
|
|
14
|
+
viewBox="0 0 160 120"
|
|
15
|
+
width={size}
|
|
16
|
+
height={(size * 120) / 160}
|
|
17
|
+
fill="none"
|
|
18
|
+
strokeWidth={1.5}
|
|
19
|
+
strokeLinecap="round"
|
|
20
|
+
strokeLinejoin="round"
|
|
21
|
+
aria-hidden="true"
|
|
22
|
+
focusable="false"
|
|
23
|
+
className={cn('shrink-0', className)}
|
|
24
|
+
>
|
|
25
|
+
<ellipse cx="80" cy="104" rx="28" ry="5" className="fill-muted" />
|
|
26
|
+
|
|
27
|
+
{/* faint arcs where a ring would sound — dashed, trailing off */}
|
|
28
|
+
<path d="M48,44 Q40,52 48,60" className="stroke-border" strokeDasharray="2 5" />
|
|
29
|
+
<path d="M112,44 Q120,52 112,60" className="stroke-border" strokeDasharray="2 5" />
|
|
30
|
+
|
|
31
|
+
{/* hanging loop */}
|
|
32
|
+
<circle cx="80" cy="29" r="3" className="fill-surface stroke-muted-foreground" />
|
|
33
|
+
|
|
34
|
+
{/* bell body, dome flaring to a flat skirt */}
|
|
35
|
+
<path
|
|
36
|
+
d="M62,68 C62,48 70,34 80,34 C90,34 98,48 98,68 C101,68 103,70 103,71 L57,71 C57,70 59,68 62,68 Z"
|
|
37
|
+
className="fill-surface stroke-muted-foreground"
|
|
38
|
+
/>
|
|
39
|
+
|
|
40
|
+
{/* clapper, still and centered — nothing ringing it */}
|
|
41
|
+
<circle cx="80" cy="72" r="2.5" className="fill-muted-foreground" />
|
|
42
|
+
|
|
43
|
+
{/* check mark — the one brand accent, caught up */}
|
|
44
|
+
<path
|
|
45
|
+
d="M95,78 L92.6,75.6 L91.9,76.4 L95,79.5 L101.6,72.9 L100.8,72.1 Z"
|
|
46
|
+
className="fill-brand"
|
|
47
|
+
/>
|
|
48
|
+
</svg>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export { NoNotificationsIllustration };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { IllustrationProps } from '@vendure-io/ui/components/molecules/illustrations/illustration-types';
|
|
2
|
+
import { cn } from '@vendure-io/ui/lib/utils';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* An empty cart standing still, with faded motion dashes behind it where
|
|
6
|
+
* incoming orders would trail in. For order/checkout lists with nothing in
|
|
7
|
+
* them yet.
|
|
8
|
+
*/
|
|
9
|
+
function NoOrdersIllustration({ className, size = 160 }: IllustrationProps) {
|
|
10
|
+
return (
|
|
11
|
+
<svg
|
|
12
|
+
viewBox="0 0 160 120"
|
|
13
|
+
width={size}
|
|
14
|
+
height={(size * 120) / 160}
|
|
15
|
+
fill="none"
|
|
16
|
+
strokeWidth={1.5}
|
|
17
|
+
strokeLinecap="round"
|
|
18
|
+
strokeLinejoin="round"
|
|
19
|
+
aria-hidden="true"
|
|
20
|
+
focusable="false"
|
|
21
|
+
className={cn('shrink-0', className)}
|
|
22
|
+
>
|
|
23
|
+
<ellipse cx="78" cy="104" rx="30" ry="5" className="fill-muted" />
|
|
24
|
+
|
|
25
|
+
{/* stillness dashes, nothing rolling in */}
|
|
26
|
+
<line x1="10" y1="56" x2="22" y2="56" className="stroke-border" strokeDasharray="2 4" />
|
|
27
|
+
<line x1="6" y1="66" x2="20" y2="66" className="stroke-border" strokeDasharray="2 4" />
|
|
28
|
+
<line x1="10" y1="76" x2="22" y2="76" className="stroke-border" strokeDasharray="2 4" />
|
|
29
|
+
|
|
30
|
+
{/* handle */}
|
|
31
|
+
<path d="M42,50 L32,26 L44,26" className="stroke-muted-foreground" />
|
|
32
|
+
|
|
33
|
+
{/* basket */}
|
|
34
|
+
<path d="M40,50 L120,50 L108,86 L54,86 Z" className="fill-surface stroke-muted-foreground" />
|
|
35
|
+
<line x1="52" y1="62" x2="106" y2="62" className="stroke-border" strokeDasharray="3 3" />
|
|
36
|
+
<line x1="55" y1="74" x2="103" y2="74" className="stroke-border" strokeDasharray="3 3" />
|
|
37
|
+
|
|
38
|
+
{/* wheels */}
|
|
39
|
+
<circle cx="60" cy="94" r="6" className="fill-surface stroke-muted-foreground" />
|
|
40
|
+
<circle cx="100" cy="94" r="6" className="fill-surface stroke-muted-foreground" />
|
|
41
|
+
|
|
42
|
+
{/* waiting indicator — the one brand accent */}
|
|
43
|
+
<circle cx="112" cy="42" r="5" className="fill-brand" />
|
|
44
|
+
</svg>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export { NoOrdersIllustration };
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { IllustrationProps } from '@vendure-io/ui/components/molecules/illustrations/illustration-types';
|
|
2
|
+
import { cn } from '@vendure-io/ui/lib/utils';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A module block hovering above a dashed socket outline shaped just like it —
|
|
6
|
+
* an extension point with nothing plugged in. For an empty plugin list, or a
|
|
7
|
+
* plugin catalog with nothing installed — pass as `illustration` to
|
|
8
|
+
* `EmptyState`.
|
|
9
|
+
*
|
|
10
|
+
* Not for a search/filter miss in a populated catalog — pair that with
|
|
11
|
+
* `NoResultsIllustration` instead.
|
|
12
|
+
*/
|
|
13
|
+
function NoPluginsIllustration({ className, size = 160 }: IllustrationProps) {
|
|
14
|
+
return (
|
|
15
|
+
<svg
|
|
16
|
+
viewBox="0 0 160 120"
|
|
17
|
+
width={size}
|
|
18
|
+
height={(size * 120) / 160}
|
|
19
|
+
fill="none"
|
|
20
|
+
strokeWidth={1.5}
|
|
21
|
+
strokeLinecap="round"
|
|
22
|
+
strokeLinejoin="round"
|
|
23
|
+
aria-hidden="true"
|
|
24
|
+
focusable="false"
|
|
25
|
+
className={cn('shrink-0', className)}
|
|
26
|
+
>
|
|
27
|
+
<ellipse cx="80" cy="104" rx="28" ry="5" className="fill-muted" />
|
|
28
|
+
|
|
29
|
+
{/* module block, hovering */}
|
|
30
|
+
<rect
|
|
31
|
+
x="62"
|
|
32
|
+
y="20"
|
|
33
|
+
width="36"
|
|
34
|
+
height="28"
|
|
35
|
+
rx="4"
|
|
36
|
+
className="fill-surface stroke-muted-foreground"
|
|
37
|
+
/>
|
|
38
|
+
<rect
|
|
39
|
+
x="74"
|
|
40
|
+
y="46"
|
|
41
|
+
width="12"
|
|
42
|
+
height="12"
|
|
43
|
+
rx="2"
|
|
44
|
+
className="fill-surface stroke-muted-foreground"
|
|
45
|
+
/>
|
|
46
|
+
{/* connector pin — the one brand accent */}
|
|
47
|
+
<circle cx="80" cy="52" r="2.5" className="fill-brand" />
|
|
48
|
+
|
|
49
|
+
{/* empty socket, same shape, waiting below */}
|
|
50
|
+
<rect
|
|
51
|
+
x="74"
|
|
52
|
+
y="70"
|
|
53
|
+
width="12"
|
|
54
|
+
height="12"
|
|
55
|
+
rx="2"
|
|
56
|
+
className="stroke-border"
|
|
57
|
+
strokeDasharray="2 4"
|
|
58
|
+
/>
|
|
59
|
+
<rect
|
|
60
|
+
x="62"
|
|
61
|
+
y="80"
|
|
62
|
+
width="36"
|
|
63
|
+
height="16"
|
|
64
|
+
rx="4"
|
|
65
|
+
className="stroke-border"
|
|
66
|
+
strokeDasharray="3 4"
|
|
67
|
+
/>
|
|
68
|
+
</svg>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export { NoPluginsIllustration };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { IllustrationProps } from '@vendure-io/ui/components/molecules/illustrations/illustration-types';
|
|
2
|
+
import { cn } from '@vendure-io/ui/lib/utils';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A magnifying glass turning up nothing: dashed ghost rows behind the lens
|
|
6
|
+
* instead of results. For a search/filter that matched zero rows — pair with
|
|
7
|
+
* `EmptyState`. Not for "nothing exists yet" (use `EmptyCollectionIllustration`).
|
|
8
|
+
*/
|
|
9
|
+
function NoResultsIllustration({ className, size = 160 }: IllustrationProps) {
|
|
10
|
+
return (
|
|
11
|
+
<svg
|
|
12
|
+
viewBox="0 0 160 120"
|
|
13
|
+
width={size}
|
|
14
|
+
height={(size * 120) / 160}
|
|
15
|
+
fill="none"
|
|
16
|
+
strokeWidth={1.5}
|
|
17
|
+
strokeLinecap="round"
|
|
18
|
+
strokeLinejoin="round"
|
|
19
|
+
aria-hidden="true"
|
|
20
|
+
focusable="false"
|
|
21
|
+
className={cn('shrink-0', className)}
|
|
22
|
+
>
|
|
23
|
+
<ellipse cx="80" cy="104" rx="32" ry="5" className="fill-muted" />
|
|
24
|
+
|
|
25
|
+
{/* ghost result rows, unmatched */}
|
|
26
|
+
<rect
|
|
27
|
+
x="30"
|
|
28
|
+
y="40"
|
|
29
|
+
width="56"
|
|
30
|
+
height="10"
|
|
31
|
+
rx="5"
|
|
32
|
+
className="stroke-border"
|
|
33
|
+
strokeDasharray="3 4"
|
|
34
|
+
/>
|
|
35
|
+
<rect
|
|
36
|
+
x="30"
|
|
37
|
+
y="56"
|
|
38
|
+
width="44"
|
|
39
|
+
height="10"
|
|
40
|
+
rx="5"
|
|
41
|
+
className="stroke-border"
|
|
42
|
+
strokeDasharray="3 4"
|
|
43
|
+
/>
|
|
44
|
+
<rect
|
|
45
|
+
x="30"
|
|
46
|
+
y="72"
|
|
47
|
+
width="50"
|
|
48
|
+
height="10"
|
|
49
|
+
rx="5"
|
|
50
|
+
className="stroke-border"
|
|
51
|
+
strokeDasharray="3 4"
|
|
52
|
+
/>
|
|
53
|
+
|
|
54
|
+
{/* lens */}
|
|
55
|
+
<circle cx="100" cy="48" r="22" className="fill-surface stroke-muted-foreground" />
|
|
56
|
+
<line x1="116" y1="64" x2="134" y2="82" className="stroke-muted-foreground" />
|
|
57
|
+
<line x1="93" y1="41" x2="107" y2="55" className="stroke-border" />
|
|
58
|
+
<line x1="107" y1="41" x2="93" y2="55" className="stroke-border" />
|
|
59
|
+
|
|
60
|
+
{/* sparkle — the one brand accent */}
|
|
61
|
+
<polygon
|
|
62
|
+
points="128,20 129.5,24.5 134,26 129.5,27.5 128,32 126.5,27.5 122,26 126.5,24.5"
|
|
63
|
+
className="fill-brand"
|
|
64
|
+
/>
|
|
65
|
+
</svg>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export { NoResultsIllustration };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { IllustrationProps } from '@vendure-io/ui/components/molecules/illustrations/illustration-types';
|
|
2
|
+
import { cn } from '@vendure-io/ui/lib/utils';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A compass whose needle points off a dashed trail that dead-ends in an "x".
|
|
6
|
+
* For 404s and missing-resource errors — pass as `illustration` to
|
|
7
|
+
* `ErrorState` alongside a "Go back" action.
|
|
8
|
+
*/
|
|
9
|
+
function NotFoundIllustration({ className, size = 160 }: IllustrationProps) {
|
|
10
|
+
return (
|
|
11
|
+
<svg
|
|
12
|
+
viewBox="0 0 160 120"
|
|
13
|
+
width={size}
|
|
14
|
+
height={(size * 120) / 160}
|
|
15
|
+
fill="none"
|
|
16
|
+
strokeWidth={1.5}
|
|
17
|
+
strokeLinecap="round"
|
|
18
|
+
strokeLinejoin="round"
|
|
19
|
+
aria-hidden="true"
|
|
20
|
+
focusable="false"
|
|
21
|
+
className={cn('shrink-0', className)}
|
|
22
|
+
>
|
|
23
|
+
<ellipse cx="80" cy="104" rx="30" ry="5" className="fill-muted" />
|
|
24
|
+
|
|
25
|
+
{/* map, folded corner */}
|
|
26
|
+
<rect x="30" y="30" width="60" height="44" rx="2" className="fill-surface stroke-border" />
|
|
27
|
+
<polygon points="90,30 90,42 78,30" className="fill-muted stroke-border" />
|
|
28
|
+
|
|
29
|
+
{/* trail off the edge, lost */}
|
|
30
|
+
<path d="M96,70 Q120,80 148,64" className="stroke-border" strokeDasharray="3 4" />
|
|
31
|
+
<line x1="144" y1="60" x2="152" y2="68" className="stroke-muted-foreground" />
|
|
32
|
+
<line x1="152" y1="60" x2="144" y2="68" className="stroke-muted-foreground" />
|
|
33
|
+
|
|
34
|
+
{/* compass */}
|
|
35
|
+
<circle cx="76" cy="58" r="20" className="fill-surface stroke-muted-foreground" />
|
|
36
|
+
<line x1="76" y1="40" x2="76" y2="44" className="stroke-border" />
|
|
37
|
+
<line x1="76" y1="72" x2="76" y2="76" className="stroke-border" />
|
|
38
|
+
<line x1="58" y1="58" x2="62" y2="58" className="stroke-border" />
|
|
39
|
+
<line x1="90" y1="58" x2="94" y2="58" className="stroke-border" />
|
|
40
|
+
<polygon points="76,58 82,44 76,50" className="fill-muted-foreground" />
|
|
41
|
+
{/* needle tip — the one brand accent */}
|
|
42
|
+
<polygon points="76,58 70,72 76,66" className="fill-brand" />
|
|
43
|
+
<circle cx="76" cy="58" r="2" className="fill-surface stroke-muted-foreground" />
|
|
44
|
+
</svg>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export { NotFoundIllustration };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { IllustrationProps } from '@vendure-io/ui/components/molecules/illustrations/illustration-types';
|
|
2
|
+
import { cn } from '@vendure-io/ui/lib/utils';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A cloud cut by a diagonal slash, with fading signal arcs above it. For
|
|
6
|
+
* network/connectivity failures — pass as `illustration` to `ErrorState`.
|
|
7
|
+
*/
|
|
8
|
+
function OfflineIllustration({ className, size = 160 }: IllustrationProps) {
|
|
9
|
+
return (
|
|
10
|
+
<svg
|
|
11
|
+
viewBox="0 0 160 120"
|
|
12
|
+
width={size}
|
|
13
|
+
height={(size * 120) / 160}
|
|
14
|
+
fill="none"
|
|
15
|
+
strokeWidth={1.5}
|
|
16
|
+
strokeLinecap="round"
|
|
17
|
+
strokeLinejoin="round"
|
|
18
|
+
aria-hidden="true"
|
|
19
|
+
focusable="false"
|
|
20
|
+
className={cn('shrink-0', className)}
|
|
21
|
+
>
|
|
22
|
+
<ellipse cx="80" cy="104" rx="28" ry="5" className="fill-muted" />
|
|
23
|
+
|
|
24
|
+
{/* fading signal, cut off */}
|
|
25
|
+
<path d="M70,20 a14,14 0 0,1 20,0" className="stroke-border" strokeDasharray="2 4" />
|
|
26
|
+
<path d="M65,12 a24,24 0 0,1 30,0" className="stroke-border" strokeDasharray="2 5" />
|
|
27
|
+
|
|
28
|
+
{/* cloud */}
|
|
29
|
+
<path
|
|
30
|
+
d="M46,66 C40,66 36,61 36,55 C36,49 41,44 47,44 C48,36 55,30 64,30 C72,30 79,35 81,42 C82,42 83,41 85,41 C93,41 100,48 100,56 C100,64 93,71 85,71 L52,71 C48,71 46,69 46,66 Z"
|
|
31
|
+
className="fill-surface stroke-muted-foreground"
|
|
32
|
+
/>
|
|
33
|
+
|
|
34
|
+
{/* slash */}
|
|
35
|
+
<line x1="32" y1="32" x2="104" y2="74" className="stroke-muted-foreground" />
|
|
36
|
+
|
|
37
|
+
{/* reconnect dot — the one brand accent */}
|
|
38
|
+
<circle cx="104" cy="74" r="4" className="fill-brand" />
|
|
39
|
+
</svg>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export { OfflineIllustration };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { IllustrationProps } from '@vendure-io/ui/components/molecules/illustrations/illustration-types';
|
|
2
|
+
import { cn } from '@vendure-io/ui/lib/utils';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* An hourglass mid-turn, sand piled solid at top and settling as a dashed
|
|
6
|
+
* pile below. For an invitation pending, an account awaiting setup or
|
|
7
|
+
* provisioning, or access awaiting approval. Not for a hard permission
|
|
8
|
+
* denial (use `AccessDeniedIllustration`) or a loading spinner state.
|
|
9
|
+
*/
|
|
10
|
+
function PendingApprovalIllustration({ className, size = 160 }: IllustrationProps) {
|
|
11
|
+
return (
|
|
12
|
+
<svg
|
|
13
|
+
viewBox="0 0 160 120"
|
|
14
|
+
width={size}
|
|
15
|
+
height={(size * 120) / 160}
|
|
16
|
+
fill="none"
|
|
17
|
+
strokeWidth={1.5}
|
|
18
|
+
strokeLinecap="round"
|
|
19
|
+
strokeLinejoin="round"
|
|
20
|
+
aria-hidden="true"
|
|
21
|
+
focusable="false"
|
|
22
|
+
className={cn('shrink-0', className)}
|
|
23
|
+
>
|
|
24
|
+
<ellipse cx="80" cy="104" rx="28" ry="5" className="fill-muted" />
|
|
25
|
+
|
|
26
|
+
{/* frame */}
|
|
27
|
+
<line x1="62" y1="26" x2="98" y2="26" className="stroke-muted-foreground" />
|
|
28
|
+
<line x1="62" y1="90" x2="98" y2="90" className="stroke-muted-foreground" />
|
|
29
|
+
|
|
30
|
+
{/* glass body, pinched at the waist */}
|
|
31
|
+
<path
|
|
32
|
+
d="M66,26 L66,42 Q66,58 80,58 Q94,58 94,42 L94,26 Z"
|
|
33
|
+
className="fill-surface stroke-muted-foreground"
|
|
34
|
+
/>
|
|
35
|
+
<path
|
|
36
|
+
d="M66,90 L66,74 Q66,58 80,58 Q94,58 94,74 L94,90 Z"
|
|
37
|
+
className="fill-surface stroke-muted-foreground"
|
|
38
|
+
/>
|
|
39
|
+
|
|
40
|
+
{/* settled sand, still piling — awaiting completion */}
|
|
41
|
+
<path
|
|
42
|
+
d="M71,84 Q80,72 89,84 Q80,88 71,84 Z"
|
|
43
|
+
className="fill-muted stroke-muted-foreground"
|
|
44
|
+
strokeDasharray="2 5"
|
|
45
|
+
/>
|
|
46
|
+
|
|
47
|
+
{/* remaining sand up top, already solid */}
|
|
48
|
+
<path d="M70,30 L90,30 L82,44 L78,44 Z" className="fill-muted" />
|
|
49
|
+
|
|
50
|
+
{/* falling stream, the one brand accent */}
|
|
51
|
+
<circle cx="80" cy="61" r="2" className="fill-brand" />
|
|
52
|
+
</svg>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export { PendingApprovalIllustration };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { IllustrationProps } from '@vendure-io/ui/components/molecules/illustrations/illustration-types';
|
|
2
|
+
import { cn } from '@vendure-io/ui/lib/utils';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A dashed-outline tray with a file card rising into it on an upward arrow.
|
|
6
|
+
* For a drag-and-drop upload target with nothing dropped yet ("drop files
|
|
7
|
+
* here to upload") — pass as `illustration` to `EmptyState`. Not for an
|
|
8
|
+
* already-existing media library that just happens to be empty (use
|
|
9
|
+
* `EmptyMediaIllustration`).
|
|
10
|
+
*/
|
|
11
|
+
function UploadDropzoneIllustration({ className, size = 160 }: IllustrationProps) {
|
|
12
|
+
return (
|
|
13
|
+
<svg
|
|
14
|
+
viewBox="0 0 160 120"
|
|
15
|
+
width={size}
|
|
16
|
+
height={(size * 120) / 160}
|
|
17
|
+
fill="none"
|
|
18
|
+
strokeWidth={1.5}
|
|
19
|
+
strokeLinecap="round"
|
|
20
|
+
strokeLinejoin="round"
|
|
21
|
+
aria-hidden="true"
|
|
22
|
+
focusable="false"
|
|
23
|
+
className={cn('shrink-0', className)}
|
|
24
|
+
>
|
|
25
|
+
<ellipse cx="80" cy="104" rx="28" ry="5" className="fill-muted" />
|
|
26
|
+
|
|
27
|
+
{/* tray — the drop target, empty */}
|
|
28
|
+
<rect
|
|
29
|
+
x="32"
|
|
30
|
+
y="14"
|
|
31
|
+
width="96"
|
|
32
|
+
height="46"
|
|
33
|
+
rx="10"
|
|
34
|
+
className="stroke-border"
|
|
35
|
+
strokeDasharray="3 4"
|
|
36
|
+
/>
|
|
37
|
+
|
|
38
|
+
{/* file card, folded corner, about to be dropped */}
|
|
39
|
+
<rect
|
|
40
|
+
x="66"
|
|
41
|
+
y="72"
|
|
42
|
+
width="28"
|
|
43
|
+
height="20"
|
|
44
|
+
rx="2"
|
|
45
|
+
className="fill-surface stroke-muted-foreground"
|
|
46
|
+
/>
|
|
47
|
+
<polygon points="94,72 94,78 88,72" className="fill-muted stroke-border" />
|
|
48
|
+
<line x1="71" y1="83" x2="85" y2="83" className="stroke-border" />
|
|
49
|
+
<line x1="71" y1="88" x2="79" y2="88" className="stroke-border" />
|
|
50
|
+
|
|
51
|
+
{/* rising into the tray */}
|
|
52
|
+
<line x1="80" y1="70" x2="80" y2="40" className="stroke-muted-foreground" />
|
|
53
|
+
{/* arrowhead — the one brand accent */}
|
|
54
|
+
<polygon points="80,28 70,44 90,44" className="fill-brand" />
|
|
55
|
+
</svg>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export { UploadDropzoneIllustration };
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useFormatSettings } from '@vendure-io/ui/components/molecules/format-provider';
|
|
4
|
+
import { cn } from '@vendure-io/ui/lib/utils';
|
|
5
|
+
import type { ComponentProps } from 'react';
|
|
6
|
+
|
|
7
|
+
// How many minor-unit digits a currency uses — 2 for USD (cents), 0 for JPY, 3
|
|
8
|
+
// for BHD. Derived from Intl rather than a hardcoded `/100`, which is wrong for
|
|
9
|
+
// zero- and three-decimal currencies (the enterprise-portal `Price` bug this
|
|
10
|
+
// fixes). Falls back to 2 for an unrecognised code so a typo can't throw.
|
|
11
|
+
function currencyFractionDigits(currency?: string): number {
|
|
12
|
+
if (!currency) return 2;
|
|
13
|
+
try {
|
|
14
|
+
return (
|
|
15
|
+
new Intl.NumberFormat(undefined, { style: 'currency', currency }).resolvedOptions()
|
|
16
|
+
.maximumFractionDigits ?? 2
|
|
17
|
+
);
|
|
18
|
+
} catch {
|
|
19
|
+
return 2;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Dev-warn once per session, not once per render — a table of currency-less
|
|
24
|
+
// cells would otherwise flood the console.
|
|
25
|
+
let warnedMissingCurrency = false;
|
|
26
|
+
|
|
27
|
+
interface MoneyProps extends ComponentProps<'span'> {
|
|
28
|
+
/** Amount in integer minor units (Vendure convention), e.g. `2500` = $25.00. */
|
|
29
|
+
value: number;
|
|
30
|
+
/** ISO 4217 code. Falls back to `FormatProvider`'s `currency`. */
|
|
31
|
+
currency?: string;
|
|
32
|
+
/** BCP 47 locale. Falls back to `FormatProvider`, then the runtime default. */
|
|
33
|
+
locale?: string;
|
|
34
|
+
/**
|
|
35
|
+
* Minor-unit digits, used to scale minor→major and to set the displayed
|
|
36
|
+
* fraction digits. Resolution: prop → context `currencyPrecision` → the
|
|
37
|
+
* currency's own Intl fraction digits.
|
|
38
|
+
*/
|
|
39
|
+
precision?: number;
|
|
40
|
+
currencyDisplay?: Intl.NumberFormatOptions['currencyDisplay'];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* SSR note: output depends on locale, so server and client renders can disagree
|
|
45
|
+
* when it falls back to the runtime default. SSR consumers should pin `locale`
|
|
46
|
+
* via `FormatProvider` (or the prop) to avoid hydration mismatches.
|
|
47
|
+
*/
|
|
48
|
+
function Money({
|
|
49
|
+
value,
|
|
50
|
+
currency,
|
|
51
|
+
locale,
|
|
52
|
+
precision,
|
|
53
|
+
currencyDisplay,
|
|
54
|
+
className,
|
|
55
|
+
...props
|
|
56
|
+
}: MoneyProps) {
|
|
57
|
+
const settings = useFormatSettings();
|
|
58
|
+
const resolvedCurrency = currency ?? settings.currency;
|
|
59
|
+
const resolvedLocale = locale ?? settings.locale;
|
|
60
|
+
const resolvedPrecision =
|
|
61
|
+
precision ?? settings.currencyPrecision ?? currencyFractionDigits(resolvedCurrency);
|
|
62
|
+
|
|
63
|
+
if (!resolvedCurrency && !warnedMissingCurrency && process.env.NODE_ENV !== 'production') {
|
|
64
|
+
warnedMissingCurrency = true;
|
|
65
|
+
console.warn(
|
|
66
|
+
'<Money> was rendered without a `currency` prop or a `FormatProvider` currency; ' +
|
|
67
|
+
'the amount is shown as a plain number.',
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const major = value / 10 ** resolvedPrecision;
|
|
72
|
+
const options: Intl.NumberFormatOptions = {
|
|
73
|
+
minimumFractionDigits: resolvedPrecision,
|
|
74
|
+
maximumFractionDigits: resolvedPrecision,
|
|
75
|
+
};
|
|
76
|
+
if (resolvedCurrency) {
|
|
77
|
+
options.style = 'currency';
|
|
78
|
+
options.currency = resolvedCurrency;
|
|
79
|
+
if (currencyDisplay) options.currencyDisplay = currencyDisplay;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const formatted = new Intl.NumberFormat(resolvedLocale, options).format(major);
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<span data-slot="money" className={cn('tabular-nums', className)} {...props}>
|
|
86
|
+
{formatted}
|
|
87
|
+
</span>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export { Money, type MoneyProps };
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
SelectItem,
|
|
8
8
|
SelectTrigger,
|
|
9
9
|
SelectValue,
|
|
10
|
-
} from '@vendure-io/ui/components/
|
|
10
|
+
} from '@vendure-io/ui/components/atoms/select';
|
|
11
11
|
import { cn } from '@vendure-io/ui/lib/utils';
|
|
12
12
|
import * as React from 'react';
|
|
13
13
|
|
|
@@ -133,7 +133,7 @@ function MultiSelect<T>({
|
|
|
133
133
|
name={name}
|
|
134
134
|
required={required}
|
|
135
135
|
>
|
|
136
|
-
{/*
|
|
136
|
+
{/* Default to a stable, container-width trigger so it doesn't grow with the
|
|
137
137
|
selection — the underlying SelectTrigger is `w-fit`, which we override here. */}
|
|
138
138
|
<SelectTrigger
|
|
139
139
|
id={id}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { cn } from '@vendure-io/ui/lib/utils';
|
|
2
|
+
import type * as React from 'react';
|
|
3
|
+
|
|
4
|
+
// Compound-only, by decision: there is no simple-props sugar and
|
|
5
|
+
// no dual-mode root. Callers assemble the parts, which keeps one way to build a
|
|
6
|
+
// header and lets variance in the wild (back links, badge rows beside the title,
|
|
7
|
+
// mono subtitles) live as free children rather than as an ever-growing prop set.
|
|
8
|
+
|
|
9
|
+
/** The header row: title/description on the left, actions on the right. */
|
|
10
|
+
function PageHeader({ className, ...props }: React.ComponentProps<'header'>) {
|
|
11
|
+
return (
|
|
12
|
+
<header
|
|
13
|
+
data-slot="page-header"
|
|
14
|
+
className={cn('flex items-start justify-between gap-4', className)}
|
|
15
|
+
{...props}
|
|
16
|
+
/>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Left column holding the title, description, and any inline badges. */
|
|
21
|
+
function PageHeaderContent({ className, ...props }: React.ComponentProps<'div'>) {
|
|
22
|
+
return (
|
|
23
|
+
<div
|
|
24
|
+
data-slot="page-header-content"
|
|
25
|
+
className={cn('flex min-w-0 flex-col gap-1', className)}
|
|
26
|
+
{...props}
|
|
27
|
+
/>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function PageHeaderTitle({ className, ...props }: React.ComponentProps<'h1'>) {
|
|
32
|
+
return (
|
|
33
|
+
<h1
|
|
34
|
+
data-slot="page-header-title"
|
|
35
|
+
className={cn('text-style-page-title break-words', className)}
|
|
36
|
+
{...props}
|
|
37
|
+
/>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function PageHeaderDescription({ className, ...props }: React.ComponentProps<'p'>) {
|
|
42
|
+
return (
|
|
43
|
+
<p
|
|
44
|
+
data-slot="page-header-description"
|
|
45
|
+
className={cn('text-sm text-muted-foreground', className)}
|
|
46
|
+
{...props}
|
|
47
|
+
/>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Right-hand action slot (buttons, menus). Stays put as the title wraps. */
|
|
52
|
+
function PageHeaderActions({ className, ...props }: React.ComponentProps<'div'>) {
|
|
53
|
+
return (
|
|
54
|
+
<div
|
|
55
|
+
data-slot="page-header-actions"
|
|
56
|
+
className={cn('flex shrink-0 items-center gap-2', className)}
|
|
57
|
+
{...props}
|
|
58
|
+
/>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Optional row rendered above the header — typically a back link. */
|
|
63
|
+
function PageHeaderBackLink({ className, ...props }: React.ComponentProps<'div'>) {
|
|
64
|
+
return (
|
|
65
|
+
<div
|
|
66
|
+
data-slot="page-header-back-link"
|
|
67
|
+
className={cn('flex items-center gap-1 text-sm text-muted-foreground', className)}
|
|
68
|
+
{...props}
|
|
69
|
+
/>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export {
|
|
74
|
+
PageHeader,
|
|
75
|
+
PageHeaderContent,
|
|
76
|
+
PageHeaderTitle,
|
|
77
|
+
PageHeaderDescription,
|
|
78
|
+
PageHeaderActions,
|
|
79
|
+
PageHeaderBackLink,
|
|
80
|
+
};
|