@vendure-io/ui 1.3.0 → 2.0.0-beta.1
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 +10 -5
- 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,41 @@
|
|
|
1
|
+
const UNITS: Array<{ unit: Intl.RelativeTimeFormatUnit; ms: number }> = [
|
|
2
|
+
{ unit: 'year', ms: 365 * 24 * 60 * 60 * 1000 },
|
|
3
|
+
{ unit: 'month', ms: 30 * 24 * 60 * 60 * 1000 },
|
|
4
|
+
{ unit: 'day', ms: 24 * 60 * 60 * 1000 },
|
|
5
|
+
{ unit: 'hour', ms: 60 * 60 * 1000 },
|
|
6
|
+
{ unit: 'minute', ms: 60 * 1000 },
|
|
7
|
+
{ unit: 'second', ms: 1000 },
|
|
8
|
+
];
|
|
9
|
+
|
|
10
|
+
interface FormatRelativeOptions {
|
|
11
|
+
locale?: string;
|
|
12
|
+
numeric?: 'auto' | 'always';
|
|
13
|
+
unitStyle?: Intl.RelativeTimeFormatOptions['style'];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Formats an instant relative to now, for non-React sites (table titles, CSV
|
|
18
|
+
* export, `<time title>`). Picks the largest unit the delta clears, then defers
|
|
19
|
+
* wording to Intl — signed input yields "in 3 days" / "2 hours ago" without a
|
|
20
|
+
* manual past/future branch.
|
|
21
|
+
*
|
|
22
|
+
* Unparseable input (an invalid date string) yields the zero-delta phrase —
|
|
23
|
+
* "now" under `numeric: 'auto'` — rather than throwing; validate upstream if
|
|
24
|
+
* you need to distinguish it (the `<RelativeTime>` molecule renders its
|
|
25
|
+
* `fallback` instead).
|
|
26
|
+
*/
|
|
27
|
+
function formatRelative(
|
|
28
|
+
value: string | number | Date,
|
|
29
|
+
{ locale, numeric = 'auto', unitStyle = 'long' }: FormatRelativeOptions = {},
|
|
30
|
+
): string {
|
|
31
|
+
const date = value instanceof Date ? value : new Date(value);
|
|
32
|
+
const diff = date.getTime() - Date.now();
|
|
33
|
+
const abs = Math.abs(diff);
|
|
34
|
+
const rtf = new Intl.RelativeTimeFormat(locale, { numeric, style: unitStyle });
|
|
35
|
+
for (const { unit, ms } of UNITS) {
|
|
36
|
+
if (abs >= ms) return rtf.format(Math.round(diff / ms), unit);
|
|
37
|
+
}
|
|
38
|
+
return rtf.format(0, 'second');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export { formatRelative, type FormatRelativeOptions };
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The state dictionary — the mechanism that makes the same entity state look
|
|
3
|
+
* the same in every Vendure surface (see CONTEXT.md → "State dictionary").
|
|
4
|
+
*
|
|
5
|
+
* This module ships the *contract*, not the app's states: the tone vocabulary,
|
|
6
|
+
* the typed declaration helper, the severity rollup, and one universal map for
|
|
7
|
+
* states every app shares (`commonStates`). Domain maps — deployment states,
|
|
8
|
+
* quote states, order states — live in their owning repo, declared with
|
|
9
|
+
* `defineStateEntries` and reviewed against the Storybook reference table.
|
|
10
|
+
* The ui package never learns app enums: the app owns what `DEPLOYING` means;
|
|
11
|
+
* the design system owns what `progress` looks like.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The semantic meaning a color expresses about a state. Tone ≠ token name:
|
|
16
|
+
* `critical` renders with the `destructive` slots and `progress` renders with
|
|
17
|
+
* the `neutral` slots plus an info-colored pulsing dot — see StatusBadge.
|
|
18
|
+
*/
|
|
19
|
+
export type Tone = 'neutral' | 'info' | 'success' | 'warning' | 'critical' | 'progress';
|
|
20
|
+
|
|
21
|
+
export interface StateEntry {
|
|
22
|
+
tone: Tone;
|
|
23
|
+
defaultLabel: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* A declared, exhaustiveness-checked state map plus lookups that tolerate open
|
|
28
|
+
* unions. `toneFor` / `labelFor` accept any string (states arrive from the wire
|
|
29
|
+
* as bare strings) and fall back to `neutral` / the raw state, warning once per
|
|
30
|
+
* unknown state in development so a typo surfaces without spamming a 200-row
|
|
31
|
+
* table.
|
|
32
|
+
*/
|
|
33
|
+
export interface StateMap<S extends string> {
|
|
34
|
+
entries: Record<S, StateEntry>;
|
|
35
|
+
toneFor(state: string): Tone;
|
|
36
|
+
labelFor(state: string): string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const isDev = process.env.NODE_ENV !== 'production';
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Declare a domain's state→tone map. The `Record<S, StateEntry>` argument is
|
|
43
|
+
* exhaustive over `S`, so typing the call as `defineStateEntries<DeploymentStatus>`
|
|
44
|
+
* makes the compiler flag any enum member the map forgets. Lookups are
|
|
45
|
+
* case-insensitive because the same state ships as `RUNNING`, `running`, and
|
|
46
|
+
* `Running` across the estate.
|
|
47
|
+
*/
|
|
48
|
+
export function defineStateEntries<S extends string>(entries: Record<S, StateEntry>): StateMap<S> {
|
|
49
|
+
// Case-insensitive index built once at declaration, not per lookup.
|
|
50
|
+
const index = new Map<string, StateEntry>();
|
|
51
|
+
for (const [state, entry] of Object.entries(entries) as [S, StateEntry][]) {
|
|
52
|
+
index.set(state.toLowerCase(), entry);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const warned = new Set<string>();
|
|
56
|
+
function resolve(state: string): StateEntry | undefined {
|
|
57
|
+
const key = state.toLowerCase();
|
|
58
|
+
const entry = index.get(key);
|
|
59
|
+
// Dedup on the lowercased key so casing variants of the same unknown state
|
|
60
|
+
// ("Foo" / "foo") warn once — matching the lookup semantics.
|
|
61
|
+
if (!entry && isDev && !warned.has(key)) {
|
|
62
|
+
warned.add(key);
|
|
63
|
+
console.warn(
|
|
64
|
+
`[state-dictionary] Unmapped state "${state}" — rendering as neutral. ` +
|
|
65
|
+
'Add it to the domain map or check for a typo.',
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
return entry;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
entries,
|
|
73
|
+
toneFor: (state) => resolve(state)?.tone ?? 'neutral',
|
|
74
|
+
labelFor: (state) => resolve(state)?.defaultLabel ?? state,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* The universal map — the only state strings this package ships. Every entry
|
|
80
|
+
* has one unambiguous tone regardless of domain.
|
|
81
|
+
*
|
|
82
|
+
* `pending` and `running` are deliberately absent: they have no single tone
|
|
83
|
+
* (principles 1 & 3 — a pending approval is `warning`, a queued job is
|
|
84
|
+
* `neutral`; a running job is `progress`, a running service is `success`), so
|
|
85
|
+
* every domain must decide them explicitly in its own map.
|
|
86
|
+
*/
|
|
87
|
+
export const commonStates = defineStateEntries({
|
|
88
|
+
enabled: { tone: 'success', defaultLabel: 'Enabled' },
|
|
89
|
+
disabled: { tone: 'neutral', defaultLabel: 'Disabled' },
|
|
90
|
+
completed: { tone: 'success', defaultLabel: 'Completed' },
|
|
91
|
+
failed: { tone: 'critical', defaultLabel: 'Failed' },
|
|
92
|
+
cancelled: { tone: 'neutral', defaultLabel: 'Cancelled' },
|
|
93
|
+
expired: { tone: 'neutral', defaultLabel: 'Expired' },
|
|
94
|
+
draft: { tone: 'neutral', defaultLabel: 'Draft' },
|
|
95
|
+
suspended: { tone: 'warning', defaultLabel: 'Suspended' },
|
|
96
|
+
approved: { tone: 'success', defaultLabel: 'Approved' },
|
|
97
|
+
rejected: { tone: 'critical', defaultLabel: 'Rejected' },
|
|
98
|
+
error: { tone: 'critical', defaultLabel: 'Error' },
|
|
99
|
+
degraded: { tone: 'warning', defaultLabel: 'Degraded' },
|
|
100
|
+
unknown: { tone: 'neutral', defaultLabel: 'Unknown' },
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Severity ordering, `neutral` (0) → `critical` (5). Used by `maxTone` to roll
|
|
105
|
+
* a set of child states up to a single parent tone (a "worst-of" rollup for
|
|
106
|
+
* parent status rows, e.g. an environment summarizing its deployments).
|
|
107
|
+
*/
|
|
108
|
+
export const TONE_SEVERITY = {
|
|
109
|
+
neutral: 0,
|
|
110
|
+
success: 1,
|
|
111
|
+
info: 2,
|
|
112
|
+
progress: 3,
|
|
113
|
+
warning: 4,
|
|
114
|
+
critical: 5,
|
|
115
|
+
} satisfies Record<Tone, number>;
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* The worst-of rollup: given child tones, return the most severe. An empty call
|
|
119
|
+
* rolls up to `neutral` (nothing to report).
|
|
120
|
+
*/
|
|
121
|
+
export function maxTone(...tones: Tone[]): Tone {
|
|
122
|
+
let worst: Tone = 'neutral';
|
|
123
|
+
for (const tone of tones) {
|
|
124
|
+
if (TONE_SEVERITY[tone] > TONE_SEVERITY[worst]) {
|
|
125
|
+
worst = tone;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return worst;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* `progress` states are exactly the "poll me" states — the system is working
|
|
133
|
+
* right now and the value will change on its own. A polling loop keys on this.
|
|
134
|
+
*/
|
|
135
|
+
export function isProgressTone(tone: Tone): boolean {
|
|
136
|
+
return tone === 'progress';
|
|
137
|
+
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
"use client"
|
|
2
|
-
|
|
3
|
-
import { Checkbox as CheckboxPrimitive } from "@base-ui/react/checkbox"
|
|
4
|
-
|
|
5
|
-
import { cn } from "@vendure-io/ui/lib/utils"
|
|
6
|
-
import { CheckIcon } from "lucide-react"
|
|
7
|
-
|
|
8
|
-
// [vendure] shadow removed for flat look — restore if overwritten by shadcn upgrade
|
|
9
|
-
function Checkbox({ className, ...props }: CheckboxPrimitive.Root.Props) {
|
|
10
|
-
return (
|
|
11
|
-
<CheckboxPrimitive.Root
|
|
12
|
-
data-slot="checkbox"
|
|
13
|
-
className={cn(
|
|
14
|
-
"border-input dark:bg-input/30 data-checked:bg-primary data-checked:text-primary-foreground dark:data-checked:bg-primary data-checked:border-primary aria-invalid:aria-checked:border-primary aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 peer relative flex size-4 shrink-0 items-center justify-center rounded-[4px] border transition-shadow outline-none group-has-disabled/field:opacity-50 after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:ring-3 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:ring-3",
|
|
15
|
-
className
|
|
16
|
-
)}
|
|
17
|
-
{...props}
|
|
18
|
-
>
|
|
19
|
-
<CheckboxPrimitive.Indicator
|
|
20
|
-
data-slot="checkbox-indicator"
|
|
21
|
-
className="grid place-content-center text-current transition-none [&>svg]:size-3.5"
|
|
22
|
-
>
|
|
23
|
-
<CheckIcon
|
|
24
|
-
/>
|
|
25
|
-
</CheckboxPrimitive.Indicator>
|
|
26
|
-
</CheckboxPrimitive.Root>
|
|
27
|
-
)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export { Checkbox }
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { cn } from "@vendure-io/ui/lib/utils"
|
|
2
|
-
|
|
3
|
-
function Skeleton({ className, ...props }: React.ComponentProps<"div">) {
|
|
4
|
-
return (
|
|
5
|
-
<div
|
|
6
|
-
data-slot="skeleton"
|
|
7
|
-
className={cn("bg-muted animate-pulse rounded-md", className)}
|
|
8
|
-
{...props}
|
|
9
|
-
/>
|
|
10
|
-
)
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export { Skeleton }
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|