@burtson-labs/ui 0.14.0 → 0.15.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/LICENSES/DEPENDENCIES.txt +1 -1
- package/README.md +15 -11
- package/dist/components/accordion.d.ts +3 -3
- package/dist/components/accordion.js +13 -10
- package/dist/components/accordion.js.map +1 -1
- package/dist/components/agent-run.d.ts +22 -0
- package/dist/components/agent-run.js +131 -0
- package/dist/components/agent-run.js.map +1 -0
- package/dist/components/alert-dialog.d.ts +12 -10
- package/dist/components/alert-dialog.js +29 -20
- package/dist/components/alert-dialog.js.map +1 -1
- package/dist/components/alert.d.ts +5 -3
- package/dist/components/alert.js +11 -7
- package/dist/components/alert.js.map +1 -1
- package/dist/components/app-shell.d.ts +7 -6
- package/dist/components/app-shell.js +21 -14
- package/dist/components/app-shell.js.map +1 -1
- package/dist/components/attachment.d.ts +3 -3
- package/dist/components/attachment.js +10 -7
- package/dist/components/attachment.js.map +1 -1
- package/dist/components/audio-player.d.ts +2 -2
- package/dist/components/audio-player.js +8 -6
- package/dist/components/audio-player.js.map +1 -1
- package/dist/components/avatar-upload.d.ts +19 -0
- package/dist/components/avatar-upload.js +359 -0
- package/dist/components/avatar-upload.js.map +1 -0
- package/dist/components/avatar.d.ts +3 -3
- package/dist/components/avatar.js +10 -7
- package/dist/components/avatar.js.map +1 -1
- package/dist/components/badge.d.ts +1 -1
- package/dist/components/badge.js +12 -10
- package/dist/components/badge.js.map +1 -1
- package/dist/components/breadcrumb.d.ts +8 -8
- package/dist/components/breadcrumb.js +24 -17
- package/dist/components/breadcrumb.js.map +1 -1
- package/dist/components/button.d.ts +8 -1
- package/dist/components/button.js +12 -3
- package/dist/components/button.js.map +1 -1
- package/dist/components/card.d.ts +8 -8
- package/dist/components/card.js +32 -23
- package/dist/components/card.js.map +1 -1
- package/dist/components/chat-history.d.ts +1 -1
- package/dist/components/chat-history.js +10 -9
- package/dist/components/chat-history.js.map +1 -1
- package/dist/components/chat-layout.d.ts +1 -1
- package/dist/components/chat-layout.js +7 -3
- package/dist/components/chat-layout.js.map +1 -1
- package/dist/components/checkbox-card.d.ts +2 -2
- package/dist/components/checkbox-card.js +9 -7
- package/dist/components/checkbox-card.js.map +1 -1
- package/dist/components/checkbox.d.ts +23 -2
- package/dist/components/checkbox.js +48 -6
- package/dist/components/checkbox.js.map +1 -1
- package/dist/components/collapsible.d.ts +2 -2
- package/dist/components/collapsible.js +7 -5
- package/dist/components/collapsible.js.map +1 -1
- package/dist/components/combobox.d.ts +14 -4
- package/dist/components/combobox.js +18 -8
- package/dist/components/combobox.js.map +1 -1
- package/dist/components/command.d.ts +68 -12
- package/dist/components/command.js +38 -25
- package/dist/components/command.js.map +1 -1
- package/dist/components/composer.d.ts +2 -2
- package/dist/components/composer.js +9 -7
- package/dist/components/composer.js.map +1 -1
- package/dist/components/connection-status.d.ts +3 -3
- package/dist/components/connection-status.js +18 -14
- package/dist/components/connection-status.js.map +1 -1
- package/dist/components/context-menu.d.ts +14 -13
- package/dist/components/context-menu.js +33 -23
- package/dist/components/context-menu.js.map +1 -1
- package/dist/components/conversation.d.ts +1 -1
- package/dist/components/conversation.js +6 -5
- package/dist/components/conversation.js.map +1 -1
- package/dist/components/copy-button.d.ts +1 -1
- package/dist/components/copy-button.js +3 -2
- package/dist/components/copy-button.js.map +1 -1
- package/dist/components/data-table.d.ts +7 -2
- package/dist/components/data-table.js +16 -42
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/dialog.d.ts +18 -9
- package/dist/components/dialog.js +38 -22
- package/dist/components/dialog.js.map +1 -1
- package/dist/components/dropdown-menu.d.ts +14 -13
- package/dist/components/dropdown-menu.js +33 -23
- package/dist/components/dropdown-menu.js.map +1 -1
- package/dist/components/editor-tabs.d.ts +1 -1
- package/dist/components/editor-tabs.js +6 -5
- package/dist/components/editor-tabs.js.map +1 -1
- package/dist/components/empty-state.d.ts +5 -5
- package/dist/components/empty-state.js +16 -11
- package/dist/components/empty-state.js.map +1 -1
- package/dist/components/error-summary.d.ts +21 -0
- package/dist/components/error-summary.js +62 -0
- package/dist/components/error-summary.js.map +1 -0
- package/dist/components/field.d.ts +66 -7
- package/dist/components/field.js +151 -20
- package/dist/components/field.js.map +1 -1
- package/dist/components/form-actions.d.ts +18 -0
- package/dist/components/form-actions.js +30 -0
- package/dist/components/form-actions.js.map +1 -0
- package/dist/components/icon-button.d.ts +3 -1
- package/dist/components/icon-button.js +5 -3
- package/dist/components/icon-button.js.map +1 -1
- package/dist/components/input.d.ts +42 -7
- package/dist/components/input.js +53 -10
- package/dist/components/input.js.map +1 -1
- package/dist/components/kbd.d.ts +2 -2
- package/dist/components/kbd.js +7 -5
- package/dist/components/kbd.js.map +1 -1
- package/dist/components/label.d.ts +6 -1
- package/dist/components/label.js +10 -4
- package/dist/components/label.js.map +1 -1
- package/dist/components/markdown.d.ts +4 -3
- package/dist/components/markdown.js +7 -6
- package/dist/components/markdown.js.map +1 -1
- package/dist/components/menubar.d.ts +16 -14
- package/dist/components/menubar.js +39 -27
- package/dist/components/menubar.js.map +1 -1
- package/dist/components/message-actions.d.ts +3 -3
- package/dist/components/message-actions.js +15 -12
- package/dist/components/message-actions.js.map +1 -1
- package/dist/components/message.d.ts +1 -1
- package/dist/components/message.js +5 -3
- package/dist/components/message.js.map +1 -1
- package/dist/components/mobile-nav.d.ts +1 -1
- package/dist/components/mobile-nav.js +6 -5
- package/dist/components/mobile-nav.js.map +1 -1
- package/dist/components/native-select.d.ts +16 -0
- package/dist/components/native-select.js +33 -0
- package/dist/components/native-select.js.map +1 -0
- package/dist/components/navigation-menu.d.ts +12 -11
- package/dist/components/navigation-menu.js +32 -23
- package/dist/components/navigation-menu.js.map +1 -1
- package/dist/components/number-input.d.ts +23 -0
- package/dist/components/number-input.js +45 -0
- package/dist/components/number-input.js.map +1 -0
- package/dist/components/onboarding-checklist.d.ts +1 -1
- package/dist/components/onboarding-checklist.js +4 -3
- package/dist/components/onboarding-checklist.js.map +1 -1
- package/dist/components/page-header.d.ts +7 -6
- package/dist/components/page-header.js +22 -15
- package/dist/components/page-header.js.map +1 -1
- package/dist/components/pagination.d.ts +1 -1
- package/dist/components/pagination.js +3 -2
- package/dist/components/pagination.js.map +1 -1
- package/dist/components/popover.d.ts +13 -10
- package/dist/components/popover.js +23 -17
- package/dist/components/popover.js.map +1 -1
- package/dist/components/progress.d.ts +1 -1
- package/dist/components/progress.js +6 -5
- package/dist/components/progress.js.map +1 -1
- package/dist/components/radio-group.d.ts +22 -3
- package/dist/components/radio-group.js +51 -10
- package/dist/components/radio-group.js.map +1 -1
- package/dist/components/reasoning.d.ts +3 -3
- package/dist/components/reasoning.js +9 -7
- package/dist/components/reasoning.js.map +1 -1
- package/dist/components/scroll-area.d.ts +3 -2
- package/dist/components/scroll-area.js +10 -7
- package/dist/components/scroll-area.js.map +1 -1
- package/dist/components/secret-input.d.ts +3 -2
- package/dist/components/secret-input.js +6 -4
- package/dist/components/secret-input.js.map +1 -1
- package/dist/components/select.d.ts +11 -6
- package/dist/components/select.js +24 -18
- package/dist/components/select.js.map +1 -1
- package/dist/components/separator.d.ts +1 -1
- package/dist/components/separator.js +4 -3
- package/dist/components/separator.js.map +1 -1
- package/dist/components/sheet.d.ts +10 -8
- package/dist/components/sheet.js +31 -20
- package/dist/components/sheet.js.map +1 -1
- package/dist/components/skeleton.d.ts +2 -1
- package/dist/components/skeleton.js +6 -4
- package/dist/components/skeleton.js.map +1 -1
- package/dist/components/slider.d.ts +10 -6
- package/dist/components/slider.js +15 -7
- package/dist/components/slider.js.map +1 -1
- package/dist/components/source.d.ts +2 -2
- package/dist/components/source.js +9 -7
- package/dist/components/source.js.map +1 -1
- package/dist/components/spinner.d.ts +4 -2
- package/dist/components/spinner.js +4 -3
- package/dist/components/spinner.js.map +1 -1
- package/dist/components/stat-card.d.ts +27 -2
- package/dist/components/stat-card.js +69 -9
- package/dist/components/stat-card.js.map +1 -1
- package/dist/components/status.d.ts +7 -6
- package/dist/components/status.js +11 -5
- package/dist/components/status.js.map +1 -1
- package/dist/components/steps.d.ts +1 -1
- package/dist/components/steps.js +4 -3
- package/dist/components/steps.js.map +1 -1
- package/dist/components/switch.d.ts +46 -2
- package/dist/components/switch.js +85 -8
- package/dist/components/switch.js.map +1 -1
- package/dist/components/table.d.ts +29 -12
- package/dist/components/table.js +79 -34
- package/dist/components/table.js.map +1 -1
- package/dist/components/tabs.d.ts +9 -4
- package/dist/components/tabs.js +22 -13
- package/dist/components/tabs.js.map +1 -1
- package/dist/components/textarea.d.ts +6 -1
- package/dist/components/textarea.js +3 -3
- package/dist/components/textarea.js.map +1 -1
- package/dist/components/toast.d.ts +10 -6
- package/dist/components/toast.js +27 -18
- package/dist/components/toast.js.map +1 -1
- package/dist/components/toaster.d.ts +4 -2
- package/dist/components/toaster.js +6 -2
- package/dist/components/toaster.js.map +1 -1
- package/dist/components/tool-call.d.ts +3 -3
- package/dist/components/tool-call.js +16 -12
- package/dist/components/tool-call.js.map +1 -1
- package/dist/components/toolbar.d.ts +9 -4
- package/dist/components/toolbar.js +14 -9
- package/dist/components/toolbar.js.map +1 -1
- package/dist/components/tooltip.d.ts +3 -2
- package/dist/components/tooltip.js +7 -4
- package/dist/components/tooltip.js.map +1 -1
- package/dist/components/tour.js +2 -2
- package/dist/components/tour.js.map +1 -1
- package/dist/components/tree-view.d.ts +1 -1
- package/dist/components/tree-view.js +9 -5
- package/dist/components/tree-view.js.map +1 -1
- package/dist/components/voice-recorder.d.ts +1 -1
- package/dist/components/voice-recorder.js +4 -2
- package/dist/components/voice-recorder.js.map +1 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.js +19 -12
- package/dist/lib/media.d.ts +18 -0
- package/dist/lib/media.js +34 -0
- package/dist/lib/media.js.map +1 -0
- package/dist/lib/utils.d.ts +32 -0
- package/dist/lib/utils.js +33 -1
- package/dist/lib/utils.js.map +1 -1
- package/dist/mui/index.js +20 -8
- package/dist/mui/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/theme.css +36 -17
- package/dist/tokens.d.ts +78 -36
- package/dist/tokens.js +63 -32
- package/dist/tokens.js.map +1 -1
- package/package.json +5 -3
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../lib/utils.js";
|
|
3
|
+
import { Button } from "./button.js";
|
|
4
|
+
import { Avatar, AvatarFallback, AvatarImage } from "./avatar.js";
|
|
5
|
+
import { Slider } from "./slider.js";
|
|
6
|
+
import * as React from "react";
|
|
7
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
import Camera from "@burtson-labs/icons/react/camera";
|
|
9
|
+
//#region src/components/avatar-upload.tsx
|
|
10
|
+
var clamp = (n) => Math.min(1, Math.max(0, n));
|
|
11
|
+
/** Choose, position and save a profile photo. No storage or networking is built in. */
|
|
12
|
+
function AvatarUpload({ src, hasPhoto = Boolean(src), name, fallback, onUpload, onRemove, disabled = false, maxBytes = 10485760, outputSize = 512, className, ...props }) {
|
|
13
|
+
const input = React.useRef(null);
|
|
14
|
+
const trigger = React.useRef(null);
|
|
15
|
+
const crop = React.useRef(null);
|
|
16
|
+
const request = React.useRef(0);
|
|
17
|
+
const saving = React.useRef(false);
|
|
18
|
+
const returnFocus = React.useRef(false);
|
|
19
|
+
const ownedUrl = React.useRef(null);
|
|
20
|
+
const drag = React.useRef(null);
|
|
21
|
+
const [photo, setPhoto] = React.useState(null);
|
|
22
|
+
const [position, setPosition] = React.useState({
|
|
23
|
+
x: .5,
|
|
24
|
+
y: .5
|
|
25
|
+
});
|
|
26
|
+
const [zoom, setZoom] = React.useState(1);
|
|
27
|
+
const [busy, setBusy] = React.useState(false);
|
|
28
|
+
const [reading, setReading] = React.useState(false);
|
|
29
|
+
const [error, setError] = React.useState("");
|
|
30
|
+
const [message, setMessage] = React.useState("");
|
|
31
|
+
const helpId = React.useId();
|
|
32
|
+
const errorId = React.useId();
|
|
33
|
+
const blocked = disabled || busy || reading;
|
|
34
|
+
React.useEffect(() => () => {
|
|
35
|
+
request.current++;
|
|
36
|
+
if (ownedUrl.current) URL.revokeObjectURL(ownedUrl.current);
|
|
37
|
+
}, []);
|
|
38
|
+
React.useEffect(() => {
|
|
39
|
+
if (photo) crop.current?.focus();
|
|
40
|
+
}, [photo]);
|
|
41
|
+
React.useEffect(() => {
|
|
42
|
+
if (returnFocus.current && !photo && !blocked) {
|
|
43
|
+
returnFocus.current = false;
|
|
44
|
+
trigger.current?.focus();
|
|
45
|
+
}
|
|
46
|
+
}, [photo, blocked]);
|
|
47
|
+
const discard = () => {
|
|
48
|
+
request.current++;
|
|
49
|
+
returnFocus.current = true;
|
|
50
|
+
if (ownedUrl.current) URL.revokeObjectURL(ownedUrl.current);
|
|
51
|
+
ownedUrl.current = null;
|
|
52
|
+
setPhoto(null);
|
|
53
|
+
setReading(false);
|
|
54
|
+
};
|
|
55
|
+
const choose = (file) => {
|
|
56
|
+
if (!file || blocked || saving.current) return;
|
|
57
|
+
setError("");
|
|
58
|
+
setMessage("");
|
|
59
|
+
if (![
|
|
60
|
+
"image/jpeg",
|
|
61
|
+
"image/png",
|
|
62
|
+
"image/webp"
|
|
63
|
+
].includes(file.type)) {
|
|
64
|
+
setError("Choose a JPEG, PNG or WebP photo. Export HEIC photos as JPEG first.");
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (!file.size || file.size > maxBytes) {
|
|
68
|
+
setError(`Choose a photo under ${Math.round(maxBytes / 1024 / 1024)} MB that is not empty.`);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const id = ++request.current;
|
|
72
|
+
const url = URL.createObjectURL(file);
|
|
73
|
+
if (ownedUrl.current) URL.revokeObjectURL(ownedUrl.current);
|
|
74
|
+
ownedUrl.current = url;
|
|
75
|
+
setPhoto(null);
|
|
76
|
+
setReading(true);
|
|
77
|
+
const image = new Image();
|
|
78
|
+
image.onload = () => {
|
|
79
|
+
if (id !== request.current) return;
|
|
80
|
+
setReading(false);
|
|
81
|
+
if (!image.naturalWidth || !image.naturalHeight) {
|
|
82
|
+
setError("This photo could not be opened. Try another image.");
|
|
83
|
+
URL.revokeObjectURL(url);
|
|
84
|
+
ownedUrl.current = null;
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
setPosition({
|
|
88
|
+
x: .5,
|
|
89
|
+
y: .5
|
|
90
|
+
});
|
|
91
|
+
setZoom(1);
|
|
92
|
+
setPhoto({
|
|
93
|
+
url,
|
|
94
|
+
image
|
|
95
|
+
});
|
|
96
|
+
};
|
|
97
|
+
image.onerror = () => {
|
|
98
|
+
if (id !== request.current) return;
|
|
99
|
+
setReading(false);
|
|
100
|
+
setError("This photo could not be opened. Try another image.");
|
|
101
|
+
URL.revokeObjectURL(url);
|
|
102
|
+
ownedUrl.current = null;
|
|
103
|
+
};
|
|
104
|
+
image.src = url;
|
|
105
|
+
};
|
|
106
|
+
const side = photo ? Math.min(photo.image.naturalWidth, photo.image.naturalHeight) / zoom : 1;
|
|
107
|
+
const act = async (remove = false) => {
|
|
108
|
+
if (blocked || saving.current || !remove && !photo) return;
|
|
109
|
+
saving.current = true;
|
|
110
|
+
setBusy(true);
|
|
111
|
+
setError("");
|
|
112
|
+
setMessage("");
|
|
113
|
+
try {
|
|
114
|
+
if (remove) await onRemove?.();
|
|
115
|
+
else if (photo) {
|
|
116
|
+
const canvas = document.createElement("canvas");
|
|
117
|
+
canvas.width = canvas.height = Math.min(2048, Math.max(64, Math.round(outputSize) || 512));
|
|
118
|
+
const ctx = canvas.getContext("2d");
|
|
119
|
+
if (!ctx) throw new Error("Your browser could not prepare the photo. Please try again.");
|
|
120
|
+
ctx.fillStyle = "#ffffff";
|
|
121
|
+
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
122
|
+
ctx.drawImage(photo.image, (photo.image.naturalWidth - side) * position.x, (photo.image.naturalHeight - side) * position.y, side, side, 0, 0, canvas.width, canvas.height);
|
|
123
|
+
const blob = await new Promise((resolve, reject) => canvas.toBlob((value) => value ? resolve(value) : reject(/* @__PURE__ */ new Error("Could not prepare this photo. Try another image.")), "image/jpeg", .9));
|
|
124
|
+
await onUpload(new File([blob], "profile-photo.jpg", { type: "image/jpeg" }));
|
|
125
|
+
}
|
|
126
|
+
discard();
|
|
127
|
+
setMessage(remove ? "Profile photo removed." : "Profile photo updated.");
|
|
128
|
+
} catch (err) {
|
|
129
|
+
setError(err instanceof Error ? err.message : "Could not save your photo. Please try again.");
|
|
130
|
+
} finally {
|
|
131
|
+
saving.current = false;
|
|
132
|
+
setBusy(false);
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
136
|
+
"data-slot": "avatar-upload",
|
|
137
|
+
"aria-busy": busy || reading || void 0,
|
|
138
|
+
className: cn("grid min-w-0 gap-4", className),
|
|
139
|
+
...props,
|
|
140
|
+
onDragOver: (event) => {
|
|
141
|
+
props.onDragOver?.(event);
|
|
142
|
+
event.preventDefault();
|
|
143
|
+
},
|
|
144
|
+
onDrop: (event) => {
|
|
145
|
+
props.onDrop?.(event);
|
|
146
|
+
event.preventDefault();
|
|
147
|
+
choose(event.dataTransfer.files[0]);
|
|
148
|
+
},
|
|
149
|
+
children: [
|
|
150
|
+
/* @__PURE__ */ jsxs("div", {
|
|
151
|
+
className: "flex flex-wrap items-center gap-4",
|
|
152
|
+
children: [
|
|
153
|
+
/* @__PURE__ */ jsxs(Avatar, {
|
|
154
|
+
className: "size-16",
|
|
155
|
+
children: [src && /* @__PURE__ */ jsx(AvatarImage, {
|
|
156
|
+
src,
|
|
157
|
+
alt: `${name}'s profile photo`,
|
|
158
|
+
referrerPolicy: "no-referrer"
|
|
159
|
+
}), /* @__PURE__ */ jsx(AvatarFallback, {
|
|
160
|
+
className: "text-lg",
|
|
161
|
+
children: fallback ?? name.slice(0, 2).toUpperCase()
|
|
162
|
+
})]
|
|
163
|
+
}),
|
|
164
|
+
/* @__PURE__ */ jsxs("div", {
|
|
165
|
+
className: "grid min-w-0 flex-1 gap-2",
|
|
166
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
167
|
+
className: "flex flex-wrap gap-2",
|
|
168
|
+
children: [/* @__PURE__ */ jsxs(Button, {
|
|
169
|
+
ref: trigger,
|
|
170
|
+
variant: "outline",
|
|
171
|
+
disabled: blocked,
|
|
172
|
+
onClick: () => input.current?.click(),
|
|
173
|
+
"aria-describedby": `${helpId}${error ? ` ${errorId}` : ""}`,
|
|
174
|
+
children: [
|
|
175
|
+
/* @__PURE__ */ jsx(Camera, {}),
|
|
176
|
+
" ",
|
|
177
|
+
hasPhoto ? "Change photo" : "Choose photo"
|
|
178
|
+
]
|
|
179
|
+
}), onRemove && hasPhoto && !photo && /* @__PURE__ */ jsx(Button, {
|
|
180
|
+
variant: "ghost",
|
|
181
|
+
disabled: blocked,
|
|
182
|
+
onClick: () => void act(true),
|
|
183
|
+
children: "Remove photo"
|
|
184
|
+
})]
|
|
185
|
+
}), /* @__PURE__ */ jsxs("p", {
|
|
186
|
+
id: helpId,
|
|
187
|
+
className: "text-xs text-muted-foreground",
|
|
188
|
+
children: [
|
|
189
|
+
"JPEG, PNG or WebP · up to ",
|
|
190
|
+
Math.round(maxBytes / 1024 / 1024),
|
|
191
|
+
" MB. You can also drop a photo here."
|
|
192
|
+
]
|
|
193
|
+
})]
|
|
194
|
+
}),
|
|
195
|
+
/* @__PURE__ */ jsx("input", {
|
|
196
|
+
ref: input,
|
|
197
|
+
type: "file",
|
|
198
|
+
accept: "image/jpeg,image/png,image/webp",
|
|
199
|
+
"aria-label": "Choose profile photo",
|
|
200
|
+
className: "hidden",
|
|
201
|
+
disabled: blocked,
|
|
202
|
+
onChange: (event) => {
|
|
203
|
+
const file = event.target.files?.[0];
|
|
204
|
+
event.target.value = "";
|
|
205
|
+
choose(file);
|
|
206
|
+
}
|
|
207
|
+
})
|
|
208
|
+
]
|
|
209
|
+
}),
|
|
210
|
+
photo && /* @__PURE__ */ jsxs("div", {
|
|
211
|
+
className: "grid gap-4 rounded-lg border border-border bg-surface p-4",
|
|
212
|
+
children: [
|
|
213
|
+
/* @__PURE__ */ jsx("div", {
|
|
214
|
+
ref: crop,
|
|
215
|
+
tabIndex: -1,
|
|
216
|
+
role: "group",
|
|
217
|
+
"aria-label": "Photo crop preview. Use the zoom and position controls to adjust it.",
|
|
218
|
+
className: cn("relative mx-auto aspect-square w-full max-w-64 touch-none overflow-hidden rounded-full bg-muted", "outline-none focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring", !blocked && "cursor-move"),
|
|
219
|
+
onPointerDown: (event) => {
|
|
220
|
+
if (blocked) return;
|
|
221
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
222
|
+
drag.current = {
|
|
223
|
+
x: event.clientX,
|
|
224
|
+
y: event.clientY,
|
|
225
|
+
px: position.x,
|
|
226
|
+
py: position.y
|
|
227
|
+
};
|
|
228
|
+
},
|
|
229
|
+
onPointerMove: (event) => {
|
|
230
|
+
if (!drag.current || blocked) return;
|
|
231
|
+
const scale = event.currentTarget.clientWidth / side;
|
|
232
|
+
const dx = (photo.image.naturalWidth - side) * scale;
|
|
233
|
+
const dy = (photo.image.naturalHeight - side) * scale;
|
|
234
|
+
setPosition({
|
|
235
|
+
x: dx ? clamp(drag.current.px - (event.clientX - drag.current.x) / dx) : .5,
|
|
236
|
+
y: dy ? clamp(drag.current.py - (event.clientY - drag.current.y) / dy) : .5
|
|
237
|
+
});
|
|
238
|
+
},
|
|
239
|
+
onPointerUp: () => {
|
|
240
|
+
drag.current = null;
|
|
241
|
+
},
|
|
242
|
+
onPointerCancel: () => {
|
|
243
|
+
drag.current = null;
|
|
244
|
+
},
|
|
245
|
+
onLostPointerCapture: () => {
|
|
246
|
+
drag.current = null;
|
|
247
|
+
},
|
|
248
|
+
children: /* @__PURE__ */ jsx("img", {
|
|
249
|
+
src: photo.url,
|
|
250
|
+
alt: "Crop preview",
|
|
251
|
+
draggable: false,
|
|
252
|
+
className: "pointer-events-none absolute max-w-none select-none",
|
|
253
|
+
style: {
|
|
254
|
+
width: `${photo.image.naturalWidth / side * 100}%`,
|
|
255
|
+
height: `${photo.image.naturalHeight / side * 100}%`,
|
|
256
|
+
left: `${-(photo.image.naturalWidth - side) * position.x / side * 100}%`,
|
|
257
|
+
top: `${-(photo.image.naturalHeight - side) * position.y / side * 100}%`
|
|
258
|
+
}
|
|
259
|
+
})
|
|
260
|
+
}),
|
|
261
|
+
/* @__PURE__ */ jsx("p", {
|
|
262
|
+
className: "text-center text-xs text-muted-foreground",
|
|
263
|
+
children: "Drag to reposition. Use position controls for precise adjustments."
|
|
264
|
+
}),
|
|
265
|
+
/* @__PURE__ */ jsxs("label", {
|
|
266
|
+
className: "grid gap-2 text-sm",
|
|
267
|
+
children: [
|
|
268
|
+
"Zoom",
|
|
269
|
+
" ",
|
|
270
|
+
/* @__PURE__ */ jsx(Slider, {
|
|
271
|
+
min: 1,
|
|
272
|
+
max: 3,
|
|
273
|
+
step: .05,
|
|
274
|
+
value: zoom,
|
|
275
|
+
onValueChange: setZoom,
|
|
276
|
+
disabled: blocked,
|
|
277
|
+
"aria-valuetext": `${Math.round(zoom * 100)}%`
|
|
278
|
+
})
|
|
279
|
+
]
|
|
280
|
+
}),
|
|
281
|
+
/* @__PURE__ */ jsxs("details", {
|
|
282
|
+
className: "rounded-md border border-border px-3 text-sm",
|
|
283
|
+
children: [/* @__PURE__ */ jsx("summary", {
|
|
284
|
+
className: "flex min-h-11 cursor-pointer items-center font-medium",
|
|
285
|
+
children: "Position controls"
|
|
286
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
287
|
+
className: "grid gap-3 pb-3 sm:grid-cols-2",
|
|
288
|
+
children: [/* @__PURE__ */ jsxs("label", {
|
|
289
|
+
className: "grid gap-2",
|
|
290
|
+
htmlFor: `${helpId}-x`,
|
|
291
|
+
children: ["Horizontal position", /* @__PURE__ */ jsx(Slider, {
|
|
292
|
+
min: 0,
|
|
293
|
+
max: 100,
|
|
294
|
+
step: 1,
|
|
295
|
+
id: `${helpId}-x`,
|
|
296
|
+
value: Math.round(position.x * 100),
|
|
297
|
+
onValueChange: (value) => setPosition((p) => ({
|
|
298
|
+
...p,
|
|
299
|
+
x: value / 100
|
|
300
|
+
})),
|
|
301
|
+
disabled: blocked || photo.image.naturalWidth <= side,
|
|
302
|
+
"aria-valuetext": `${Math.round(position.x * 100)}%`
|
|
303
|
+
})]
|
|
304
|
+
}), /* @__PURE__ */ jsxs("label", {
|
|
305
|
+
className: "grid gap-2",
|
|
306
|
+
htmlFor: `${helpId}-y`,
|
|
307
|
+
children: ["Vertical position", /* @__PURE__ */ jsx(Slider, {
|
|
308
|
+
min: 0,
|
|
309
|
+
max: 100,
|
|
310
|
+
step: 1,
|
|
311
|
+
id: `${helpId}-y`,
|
|
312
|
+
value: Math.round(position.y * 100),
|
|
313
|
+
onValueChange: (value) => setPosition((p) => ({
|
|
314
|
+
...p,
|
|
315
|
+
y: value / 100
|
|
316
|
+
})),
|
|
317
|
+
disabled: blocked || photo.image.naturalHeight <= side,
|
|
318
|
+
"aria-valuetext": `${Math.round(position.y * 100)}%`
|
|
319
|
+
})]
|
|
320
|
+
})]
|
|
321
|
+
})]
|
|
322
|
+
}),
|
|
323
|
+
/* @__PURE__ */ jsxs("div", {
|
|
324
|
+
className: "flex flex-wrap justify-end gap-2",
|
|
325
|
+
children: [/* @__PURE__ */ jsx(Button, {
|
|
326
|
+
variant: "outline",
|
|
327
|
+
disabled: busy,
|
|
328
|
+
onClick: () => {
|
|
329
|
+
discard();
|
|
330
|
+
setError("");
|
|
331
|
+
},
|
|
332
|
+
children: "Cancel"
|
|
333
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
334
|
+
disabled: blocked,
|
|
335
|
+
onClick: () => void act(),
|
|
336
|
+
children: busy ? "Saving photo…" : "Save photo"
|
|
337
|
+
})]
|
|
338
|
+
})
|
|
339
|
+
]
|
|
340
|
+
}),
|
|
341
|
+
error && /* @__PURE__ */ jsx("p", {
|
|
342
|
+
id: errorId,
|
|
343
|
+
role: "alert",
|
|
344
|
+
className: "text-sm text-destructive",
|
|
345
|
+
children: error
|
|
346
|
+
}),
|
|
347
|
+
/* @__PURE__ */ jsx("p", {
|
|
348
|
+
role: "status",
|
|
349
|
+
"aria-live": "polite",
|
|
350
|
+
className: cn("text-sm text-muted-foreground", !reading && !busy && !message && "sr-only"),
|
|
351
|
+
children: reading ? "Opening photo…" : busy ? "Saving your profile photo…" : message
|
|
352
|
+
})
|
|
353
|
+
]
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
//#endregion
|
|
357
|
+
export { AvatarUpload };
|
|
358
|
+
|
|
359
|
+
//# sourceMappingURL=avatar-upload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"avatar-upload.js","names":[],"sources":["../../src/components/avatar-upload.tsx"],"sourcesContent":["import Camera from '@burtson-labs/icons/react/camera';\nimport * as React from 'react';\n\nimport { cn, focusRingClasses } from '../lib/utils';\n\nimport { Avatar, AvatarFallback, AvatarImage } from './avatar';\nimport { Button } from './button';\nimport { Slider } from './slider';\n\nexport interface AvatarUploadProps extends Omit<React.ComponentProps<'div'>, 'onError'> {\n src?: string;\n /** A stored photo may exist even when its preview cannot be loaded. */\n hasPhoto?: boolean;\n /** The person's name, used to label the current photo. */\n name: string;\n fallback?: React.ReactNode;\n /** Receives a square JPEG. Resolve only after it has been saved; reject to offer retry. */\n onUpload: (file: File) => Promise<void>;\n onRemove?: () => Promise<void>;\n disabled?: boolean;\n /** Maximum size of the original file. Default: 10 MiB. */\n maxBytes?: number;\n /** Exported square dimension. Default: 512px. */\n outputSize?: number;\n}\n\ntype Photo = { url: string; image: HTMLImageElement };\nconst clamp = (n: number) => Math.min(1, Math.max(0, n));\n\n/** Choose, position and save a profile photo. No storage or networking is built in. */\nexport function AvatarUpload({\n src,\n hasPhoto = Boolean(src),\n name,\n fallback,\n onUpload,\n onRemove,\n disabled = false,\n maxBytes = 10 * 1024 * 1024,\n outputSize = 512,\n className,\n ...props\n}: AvatarUploadProps) {\n const input = React.useRef<HTMLInputElement>(null);\n const trigger = React.useRef<HTMLButtonElement>(null);\n const crop = React.useRef<HTMLDivElement>(null);\n const request = React.useRef(0);\n const saving = React.useRef(false);\n const returnFocus = React.useRef(false);\n const ownedUrl = React.useRef<string | null>(null);\n const drag = React.useRef<{ x: number; y: number; px: number; py: number } | null>(null);\n const [photo, setPhoto] = React.useState<Photo | null>(null);\n const [position, setPosition] = React.useState({ x: 0.5, y: 0.5 });\n const [zoom, setZoom] = React.useState(1);\n const [busy, setBusy] = React.useState(false);\n const [reading, setReading] = React.useState(false);\n const [error, setError] = React.useState('');\n const [message, setMessage] = React.useState('');\n const helpId = React.useId();\n const errorId = React.useId();\n const blocked = disabled || busy || reading;\n\n React.useEffect(\n () => () => {\n request.current++;\n if (ownedUrl.current) URL.revokeObjectURL(ownedUrl.current);\n },\n [],\n );\n React.useEffect(() => {\n if (photo) crop.current?.focus();\n }, [photo]);\n React.useEffect(() => {\n if (returnFocus.current && !photo && !blocked) {\n returnFocus.current = false;\n trigger.current?.focus();\n }\n }, [photo, blocked]);\n\n const discard = () => {\n request.current++;\n returnFocus.current = true;\n if (ownedUrl.current) URL.revokeObjectURL(ownedUrl.current);\n ownedUrl.current = null;\n setPhoto(null);\n setReading(false);\n };\n\n const choose = (file?: File) => {\n if (!file || blocked || saving.current) return;\n setError('');\n setMessage('');\n if (!['image/jpeg', 'image/png', 'image/webp'].includes(file.type)) {\n setError('Choose a JPEG, PNG or WebP photo. Export HEIC photos as JPEG first.');\n return;\n }\n if (!file.size || file.size > maxBytes) {\n setError(`Choose a photo under ${Math.round(maxBytes / 1024 / 1024)} MB that is not empty.`);\n return;\n }\n const id = ++request.current;\n const url = URL.createObjectURL(file);\n if (ownedUrl.current) URL.revokeObjectURL(ownedUrl.current);\n ownedUrl.current = url;\n setPhoto(null);\n setReading(true);\n const image = new Image();\n image.onload = () => {\n if (id !== request.current) return;\n setReading(false);\n if (!image.naturalWidth || !image.naturalHeight) {\n setError('This photo could not be opened. Try another image.');\n URL.revokeObjectURL(url);\n ownedUrl.current = null;\n return;\n }\n setPosition({ x: 0.5, y: 0.5 });\n setZoom(1);\n setPhoto({ url, image });\n };\n image.onerror = () => {\n if (id !== request.current) return;\n setReading(false);\n setError('This photo could not be opened. Try another image.');\n URL.revokeObjectURL(url);\n ownedUrl.current = null;\n };\n image.src = url;\n };\n\n const side = photo ? Math.min(photo.image.naturalWidth, photo.image.naturalHeight) / zoom : 1;\n const act = async (remove = false) => {\n if (blocked || saving.current || (!remove && !photo)) return;\n saving.current = true;\n setBusy(true);\n setError('');\n setMessage('');\n try {\n if (remove) await onRemove?.();\n else if (photo) {\n const canvas = document.createElement('canvas');\n canvas.width = canvas.height = Math.min(2048, Math.max(64, Math.round(outputSize) || 512));\n const ctx = canvas.getContext('2d');\n if (!ctx) throw new Error('Your browser could not prepare the photo. Please try again.');\n ctx.fillStyle = '#ffffff';\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n ctx.drawImage(\n photo.image,\n (photo.image.naturalWidth - side) * position.x,\n (photo.image.naturalHeight - side) * position.y,\n side,\n side,\n 0,\n 0,\n canvas.width,\n canvas.height,\n );\n const blob = await new Promise<Blob>((resolve, reject) =>\n canvas.toBlob(\n (value) =>\n value\n ? resolve(value)\n : reject(new Error('Could not prepare this photo. Try another image.')),\n 'image/jpeg',\n 0.9,\n ),\n );\n await onUpload(new File([blob], 'profile-photo.jpg', { type: 'image/jpeg' }));\n }\n discard();\n setMessage(remove ? 'Profile photo removed.' : 'Profile photo updated.');\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Could not save your photo. Please try again.');\n } finally {\n saving.current = false;\n setBusy(false);\n }\n };\n\n return (\n <div\n data-slot=\"avatar-upload\"\n aria-busy={busy || reading || undefined}\n className={cn('grid min-w-0 gap-4', className)}\n {...props}\n onDragOver={(event) => {\n props.onDragOver?.(event);\n event.preventDefault();\n }}\n onDrop={(event) => {\n props.onDrop?.(event);\n event.preventDefault();\n choose(event.dataTransfer.files[0]);\n }}\n >\n <div className=\"flex flex-wrap items-center gap-4\">\n <Avatar className=\"size-16\">\n {src && (\n <AvatarImage src={src} alt={`${name}'s profile photo`} referrerPolicy=\"no-referrer\" />\n )}\n <AvatarFallback className=\"text-lg\">\n {fallback ?? name.slice(0, 2).toUpperCase()}\n </AvatarFallback>\n </Avatar>\n <div className=\"grid min-w-0 flex-1 gap-2\">\n <div className=\"flex flex-wrap gap-2\">\n <Button\n ref={trigger}\n variant=\"outline\"\n disabled={blocked}\n onClick={() => input.current?.click()}\n aria-describedby={`${helpId}${error ? ` ${errorId}` : ''}`}\n >\n <Camera /> {hasPhoto ? 'Change photo' : 'Choose photo'}\n </Button>\n {onRemove && hasPhoto && !photo && (\n <Button variant=\"ghost\" disabled={blocked} onClick={() => void act(true)}>\n Remove photo\n </Button>\n )}\n </div>\n <p id={helpId} className=\"text-xs text-muted-foreground\">\n JPEG, PNG or WebP · up to {Math.round(maxBytes / 1024 / 1024)} MB. You can also drop a\n photo here.\n </p>\n </div>\n <input\n ref={input}\n type=\"file\"\n accept=\"image/jpeg,image/png,image/webp\"\n aria-label=\"Choose profile photo\"\n className=\"hidden\"\n disabled={blocked}\n onChange={(event) => {\n const file = event.target.files?.[0];\n event.target.value = '';\n choose(file);\n }}\n />\n </div>\n {photo && (\n <div className=\"grid gap-4 rounded-lg border border-border bg-surface p-4\">\n <div\n ref={crop}\n tabIndex={-1}\n role=\"group\"\n aria-label=\"Photo crop preview. Use the zoom and position controls to adjust it.\"\n className={cn(\n 'relative mx-auto aspect-square w-full max-w-64 touch-none overflow-hidden rounded-full bg-muted',\n focusRingClasses,\n !blocked && 'cursor-move',\n )}\n onPointerDown={(event) => {\n if (blocked) return;\n event.currentTarget.setPointerCapture(event.pointerId);\n drag.current = { x: event.clientX, y: event.clientY, px: position.x, py: position.y };\n }}\n onPointerMove={(event) => {\n if (!drag.current || blocked) return;\n const scale = event.currentTarget.clientWidth / side;\n const dx = (photo.image.naturalWidth - side) * scale;\n const dy = (photo.image.naturalHeight - side) * scale;\n setPosition({\n x: dx ? clamp(drag.current.px - (event.clientX - drag.current.x) / dx) : 0.5,\n y: dy ? clamp(drag.current.py - (event.clientY - drag.current.y) / dy) : 0.5,\n });\n }}\n onPointerUp={() => {\n drag.current = null;\n }}\n onPointerCancel={() => {\n drag.current = null;\n }}\n onLostPointerCapture={() => {\n drag.current = null;\n }}\n >\n <img\n src={photo.url}\n alt=\"Crop preview\"\n draggable={false}\n className=\"pointer-events-none absolute max-w-none select-none\"\n style={{\n width: `${(photo.image.naturalWidth / side) * 100}%`,\n height: `${(photo.image.naturalHeight / side) * 100}%`,\n left: `${((-(photo.image.naturalWidth - side) * position.x) / side) * 100}%`,\n top: `${((-(photo.image.naturalHeight - side) * position.y) / side) * 100}%`,\n }}\n />\n </div>\n <p className=\"text-center text-xs text-muted-foreground\">\n Drag to reposition. Use position controls for precise adjustments.\n </p>\n <label className=\"grid gap-2 text-sm\">\n Zoom{' '}\n <Slider\n min={1}\n max={3}\n step={0.05}\n value={zoom}\n onValueChange={setZoom}\n disabled={blocked}\n aria-valuetext={`${Math.round(zoom * 100)}%`}\n />\n </label>\n <details className=\"rounded-md border border-border px-3 text-sm\">\n <summary className=\"flex min-h-11 cursor-pointer items-center font-medium\">\n Position controls\n </summary>\n <div className=\"grid gap-3 pb-3 sm:grid-cols-2\">\n <label className=\"grid gap-2\" htmlFor={`${helpId}-x`}>\n Horizontal position\n <Slider\n min={0}\n max={100}\n step={1}\n id={`${helpId}-x`}\n value={Math.round(position.x * 100)}\n onValueChange={(value) => setPosition((p) => ({ ...p, x: value / 100 }))}\n disabled={blocked || photo.image.naturalWidth <= side}\n aria-valuetext={`${Math.round(position.x * 100)}%`}\n />\n </label>\n <label className=\"grid gap-2\" htmlFor={`${helpId}-y`}>\n Vertical position\n <Slider\n min={0}\n max={100}\n step={1}\n id={`${helpId}-y`}\n value={Math.round(position.y * 100)}\n onValueChange={(value) => setPosition((p) => ({ ...p, y: value / 100 }))}\n disabled={blocked || photo.image.naturalHeight <= side}\n aria-valuetext={`${Math.round(position.y * 100)}%`}\n />\n </label>\n </div>\n </details>\n <div className=\"flex flex-wrap justify-end gap-2\">\n <Button\n variant=\"outline\"\n disabled={busy}\n onClick={() => {\n discard();\n setError('');\n }}\n >\n Cancel\n </Button>\n <Button disabled={blocked} onClick={() => void act()}>\n {busy ? 'Saving photo…' : 'Save photo'}\n </Button>\n </div>\n </div>\n )}\n {error && (\n <p id={errorId} role=\"alert\" className=\"text-sm text-destructive\">\n {error}\n </p>\n )}\n <p\n role=\"status\"\n aria-live=\"polite\"\n className={cn('text-sm text-muted-foreground', !reading && !busy && !message && 'sr-only')}\n >\n {reading ? 'Opening photo…' : busy ? 'Saving your profile photo…' : message}\n </p>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import * as AvatarPrimitive from '../primitives/vendor/radix/react-avatar';
|
|
3
|
-
declare
|
|
4
|
-
declare
|
|
5
|
-
declare
|
|
3
|
+
declare const Avatar: React.ForwardRefExoticComponent<Omit<AvatarPrimitive.AvatarProps & React.RefAttributes<HTMLSpanElement>, "ref"> & React.RefAttributes<HTMLSpanElement>>;
|
|
4
|
+
declare const AvatarImage: React.ForwardRefExoticComponent<Omit<AvatarPrimitive.AvatarImageProps & React.RefAttributes<HTMLImageElement>, "ref"> & React.RefAttributes<HTMLImageElement>>;
|
|
5
|
+
declare const AvatarFallback: React.ForwardRefExoticComponent<Omit<AvatarPrimitive.AvatarFallbackProps & React.RefAttributes<HTMLSpanElement>, "ref"> & React.RefAttributes<HTMLSpanElement>>;
|
|
6
6
|
export { Avatar, AvatarFallback, AvatarImage };
|
|
@@ -1,30 +1,33 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn } from "../lib/utils.js";
|
|
3
3
|
import { Avatar as Avatar$1, AvatarFallback as AvatarFallback$1, AvatarImage as AvatarImage$1 } from "../primitives/vendor/radix/react-avatar/avatar.js";
|
|
4
|
-
import "react";
|
|
4
|
+
import * as React from "react";
|
|
5
5
|
import { jsx } from "react/jsx-runtime";
|
|
6
6
|
//#region src/components/avatar.tsx
|
|
7
|
-
function Avatar({ className, ...props }) {
|
|
7
|
+
var Avatar = React.forwardRef(function Avatar({ className, ...props }, ref) {
|
|
8
8
|
return /* @__PURE__ */ jsx(Avatar$1, {
|
|
9
|
+
ref,
|
|
9
10
|
"data-slot": "avatar",
|
|
10
11
|
className: cn("relative flex size-8 shrink-0 overflow-hidden rounded-full", className),
|
|
11
12
|
...props
|
|
12
13
|
});
|
|
13
|
-
}
|
|
14
|
-
function AvatarImage({ className, ...props }) {
|
|
14
|
+
});
|
|
15
|
+
var AvatarImage = React.forwardRef(function AvatarImage({ className, ...props }, ref) {
|
|
15
16
|
return /* @__PURE__ */ jsx(AvatarImage$1, {
|
|
17
|
+
ref,
|
|
16
18
|
"data-slot": "avatar-image",
|
|
17
19
|
className: cn("aspect-square size-full object-cover", className),
|
|
18
20
|
...props
|
|
19
21
|
});
|
|
20
|
-
}
|
|
21
|
-
function AvatarFallback({ className, ...props }) {
|
|
22
|
+
});
|
|
23
|
+
var AvatarFallback = React.forwardRef(function AvatarFallback({ className, ...props }, ref) {
|
|
22
24
|
return /* @__PURE__ */ jsx(AvatarFallback$1, {
|
|
25
|
+
ref,
|
|
23
26
|
"data-slot": "avatar-fallback",
|
|
24
27
|
className: cn("flex size-full items-center justify-center rounded-full border border-brand/15 bg-brand-soft text-xs font-semibold text-brand-soft-foreground", className),
|
|
25
28
|
...props
|
|
26
29
|
});
|
|
27
|
-
}
|
|
30
|
+
});
|
|
28
31
|
//#endregion
|
|
29
32
|
export { Avatar, AvatarFallback, AvatarImage };
|
|
30
33
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"avatar.js","names":["AvatarPrimitive.Root","AvatarPrimitive.Image","AvatarPrimitive.Fallback"],"sources":["../../src/components/avatar.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { cn } from '../lib/utils';\nimport * as AvatarPrimitive from '../primitives/vendor/radix/react-avatar';\n\
|
|
1
|
+
{"version":3,"file":"avatar.js","names":["AvatarPrimitive.Root","AvatarPrimitive.Image","AvatarPrimitive.Fallback"],"sources":["../../src/components/avatar.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { cn } from '../lib/utils';\nimport * as AvatarPrimitive from '../primitives/vendor/radix/react-avatar';\n\nconst Avatar = React.forwardRef<HTMLSpanElement, React.ComponentProps<typeof AvatarPrimitive.Root>>(\n function Avatar({ className, ...props }, ref) {\n return (\n <AvatarPrimitive.Root\n ref={ref}\n data-slot=\"avatar\"\n className={cn('relative flex size-8 shrink-0 overflow-hidden rounded-full', className)}\n {...props}\n />\n );\n },\n);\n\nconst AvatarImage = React.forwardRef<\n HTMLImageElement,\n React.ComponentProps<typeof AvatarPrimitive.Image>\n>(function AvatarImage({ className, ...props }, ref) {\n return (\n <AvatarPrimitive.Image\n ref={ref}\n data-slot=\"avatar-image\"\n className={cn('aspect-square size-full object-cover', className)}\n {...props}\n />\n );\n});\n\nconst AvatarFallback = React.forwardRef<\n HTMLSpanElement,\n React.ComponentProps<typeof AvatarPrimitive.Fallback>\n>(function AvatarFallback({ className, ...props }, ref) {\n return (\n <AvatarPrimitive.Fallback\n ref={ref}\n data-slot=\"avatar-fallback\"\n className={cn(\n 'flex size-full items-center justify-center rounded-full border border-brand/15 bg-brand-soft text-xs font-semibold text-brand-soft-foreground',\n className,\n )}\n {...props}\n />\n );\n});\n\nexport { Avatar, AvatarFallback, AvatarImage };\n"],"mappings":";;;;;;AAKA,IAAM,SAAS,MAAM,WACnB,SAAS,OAAO,EAAE,WAAW,GAAG,SAAS,KAAK;CAC5C,OACE,oBAACA,UAAD;EACO;EACL,aAAU;EACV,WAAW,GAAG,8DAA8D,SAAS;EACrF,GAAI;CACL,CAAA;AAEL,CACF;AAEA,IAAM,cAAc,MAAM,WAGxB,SAAS,YAAY,EAAE,WAAW,GAAG,SAAS,KAAK;CACnD,OACE,oBAACC,eAAD;EACO;EACL,aAAU;EACV,WAAW,GAAG,wCAAwC,SAAS;EAC/D,GAAI;CACL,CAAA;AAEL,CAAC;AAED,IAAM,iBAAiB,MAAM,WAG3B,SAAS,eAAe,EAAE,WAAW,GAAG,SAAS,KAAK;CACtD,OACE,oBAACC,kBAAD;EACO;EACL,aAAU;EACV,WAAW,GACT,iJACA,SACF;EACA,GAAI;CACL,CAAA;AAEL,CAAC"}
|
|
@@ -6,5 +6,5 @@ declare const badgeVariants: (props?: ({
|
|
|
6
6
|
export interface BadgeProps extends React.ComponentProps<'span'>, VariantProps<typeof badgeVariants> {
|
|
7
7
|
asChild?: boolean;
|
|
8
8
|
}
|
|
9
|
-
declare
|
|
9
|
+
declare const Badge: React.ForwardRefExoticComponent<Omit<BadgeProps, "ref"> & React.RefAttributes<HTMLSpanElement>>;
|
|
10
10
|
export { Badge, badgeVariants };
|
package/dist/components/badge.js
CHANGED
|
@@ -1,30 +1,32 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { cn } from "../lib/utils.js";
|
|
2
|
+
import { cn, focusRingClasses } from "../lib/utils.js";
|
|
3
3
|
import { Root as Slot } from "../primitives/vendor/radix/react-slot/slot.js";
|
|
4
|
-
import "react";
|
|
4
|
+
import * as React from "react";
|
|
5
5
|
import { jsx } from "react/jsx-runtime";
|
|
6
6
|
import { cva } from "class-variance-authority";
|
|
7
7
|
//#region src/components/badge.tsx
|
|
8
|
-
var badgeVariants = cva(
|
|
8
|
+
var badgeVariants = cva(`inline-flex w-fit shrink-0 items-center gap-1.5 rounded-full border px-2 py-0.5 text-[11px] font-semibold leading-4 whitespace-nowrap transition-colors ${focusRingClasses} [&>svg]:size-3`, {
|
|
9
9
|
variants: { variant: {
|
|
10
10
|
default: "border-border bg-surface-muted text-foreground",
|
|
11
11
|
secondary: "border-border bg-surface-muted text-foreground",
|
|
12
12
|
brand: "border-brand/20 bg-brand-soft text-brand-soft-foreground",
|
|
13
|
-
success: "border-success/20 bg-success/10 text-success",
|
|
14
|
-
warning: "border-warning/20 bg-warning/10 text-warning",
|
|
15
|
-
destructive: "border-destructive/20 bg-destructive/10 text-destructive",
|
|
16
|
-
info: "border-info/20 bg-info/10 text-info",
|
|
13
|
+
success: "border-success/20 bg-success/10 text-[color-mix(in_srgb,var(--success)_75%,var(--foreground))]",
|
|
14
|
+
warning: "border-warning/20 bg-warning/10 text-[color-mix(in_srgb,var(--warning)_75%,var(--foreground))]",
|
|
15
|
+
destructive: "border-destructive/20 bg-destructive/10 text-[color-mix(in_srgb,var(--destructive)_75%,var(--foreground))]",
|
|
16
|
+
info: "border-info/20 bg-info/10 text-[color-mix(in_srgb,var(--info)_75%,var(--foreground))]",
|
|
17
17
|
outline: "border-border-strong bg-transparent text-muted-foreground"
|
|
18
18
|
} },
|
|
19
19
|
defaultVariants: { variant: "default" }
|
|
20
20
|
});
|
|
21
|
-
function Badge({ className, variant, asChild = false, ...props }) {
|
|
21
|
+
var Badge = React.forwardRef(function Badge({ className, variant, asChild = false, ...props }, ref) {
|
|
22
22
|
return /* @__PURE__ */ jsx(asChild ? Slot : "span", {
|
|
23
|
+
ref,
|
|
23
24
|
"data-slot": "badge",
|
|
24
|
-
|
|
25
|
+
"data-variant": variant ?? "default",
|
|
26
|
+
className: cn(badgeVariants({ variant }), asChild && "relative pointer-coarse:before:absolute pointer-coarse:before:inset-x-0 pointer-coarse:before:top-1/2 pointer-coarse:before:h-11 pointer-coarse:before:-translate-y-1/2 pointer-coarse:before:content-['']", className),
|
|
25
27
|
...props
|
|
26
28
|
});
|
|
27
|
-
}
|
|
29
|
+
});
|
|
28
30
|
//#endregion
|
|
29
31
|
export { Badge, badgeVariants };
|
|
30
32
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"badge.js","names":["Slot.Root"],"sources":["../../src/components/badge.tsx"],"sourcesContent":["import { cva, type VariantProps } from 'class-variance-authority';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\nimport * as Slot from '../primitives/vendor/radix/react-slot';\n\nconst badgeVariants = cva(\n
|
|
1
|
+
{"version":3,"file":"badge.js","names":["Slot.Root"],"sources":["../../src/components/badge.tsx"],"sourcesContent":["import { cva, type VariantProps } from 'class-variance-authority';\nimport * as React from 'react';\n\nimport { cn, focusRingClasses, touchTargetRowClasses } from '../lib/utils';\nimport * as Slot from '../primitives/vendor/radix/react-slot';\n\nconst badgeVariants = cva(\n `inline-flex w-fit shrink-0 items-center gap-1.5 rounded-full border px-2 py-0.5 text-[11px] font-semibold leading-4 whitespace-nowrap transition-colors ${focusRingClasses} [&>svg]:size-3`,\n {\n variants: {\n variant: {\n default: 'border-border bg-surface-muted text-foreground',\n // 0.x name for the neutral tag; kept so existing apps keep compiling.\n secondary: 'border-border bg-surface-muted text-foreground',\n brand: 'border-brand/20 bg-brand-soft text-brand-soft-foreground',\n // Status text is the tone mixed a quarter toward the foreground: the\n // plain tone reads at 4.3–4.5:1 on its own tint, the mixed one at 6:1\n // (4.5:1 inside a terminal Card). Mixing toward the foreground darkens\n // it in light mode and lightens it in dark mode and in a terminal Card,\n // which re-points --foreground.\n success:\n 'border-success/20 bg-success/10 text-[color-mix(in_srgb,var(--success)_75%,var(--foreground))]',\n warning:\n 'border-warning/20 bg-warning/10 text-[color-mix(in_srgb,var(--warning)_75%,var(--foreground))]',\n destructive:\n 'border-destructive/20 bg-destructive/10 text-[color-mix(in_srgb,var(--destructive)_75%,var(--foreground))]',\n info: 'border-info/20 bg-info/10 text-[color-mix(in_srgb,var(--info)_75%,var(--foreground))]',\n outline: 'border-border-strong bg-transparent text-muted-foreground',\n },\n },\n defaultVariants: { variant: 'default' },\n },\n);\n\nexport interface BadgeProps\n extends React.ComponentProps<'span'>, VariantProps<typeof badgeVariants> {\n asChild?: boolean;\n}\n\nconst Badge = React.forwardRef<HTMLSpanElement, BadgeProps>(function Badge(\n { className, variant, asChild = false, ...props },\n ref,\n) {\n const Comp = asChild ? Slot.Root : 'span';\n return (\n <Comp\n ref={ref}\n data-slot=\"badge\"\n data-variant={variant ?? 'default'}\n // A badge that is a link or button (asChild) gets a 44px hit area on touch screens.\n className={cn(badgeVariants({ variant }), asChild && touchTargetRowClasses, className)}\n {...props}\n />\n );\n});\n\nexport { Badge, badgeVariants };\n"],"mappings":";;;;;;;AAMA,IAAM,gBAAgB,IACpB,2JAA2J,iBAAiB,kBAC5K;CACE,UAAU,EACR,SAAS;EACP,SAAS;EAET,WAAW;EACX,OAAO;EAMP,SACE;EACF,SACE;EACF,aACE;EACF,MAAM;EACN,SAAS;CACX,EACF;CACA,iBAAiB,EAAE,SAAS,UAAU;AACxC,CACF;AAOA,IAAM,QAAQ,MAAM,WAAwC,SAAS,MACnE,EAAE,WAAW,SAAS,UAAU,OAAO,GAAG,SAC1C,KACA;CAEA,OACE,oBAFW,UAAUA,OAAY,QAEjC;EACO;EACL,aAAU;EACV,gBAAc,WAAW;EAEzB,WAAW,GAAG,cAAc,EAAE,QAAQ,CAAC,GAAG,WAAA,8MAAkC,SAAS;EACrF,GAAI;CACL,CAAA;AAEL,CAAC"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
declare
|
|
3
|
-
declare
|
|
4
|
-
declare
|
|
5
|
-
declare
|
|
2
|
+
declare const Breadcrumb: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>, "ref"> & React.RefAttributes<HTMLElement>>;
|
|
3
|
+
declare const BreadcrumbList: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.OlHTMLAttributes<HTMLOListElement>, HTMLOListElement>, "ref"> & React.RefAttributes<HTMLOListElement>>;
|
|
4
|
+
declare const BreadcrumbItem: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>, "ref"> & React.RefAttributes<HTMLLIElement>>;
|
|
5
|
+
declare const BreadcrumbLink: React.ForwardRefExoticComponent<Omit<React.ClassAttributes<HTMLAnchorElement> & React.AnchorHTMLAttributes<HTMLAnchorElement> & {
|
|
6
6
|
asChild?: boolean;
|
|
7
|
-
}
|
|
8
|
-
declare
|
|
9
|
-
declare
|
|
10
|
-
declare
|
|
7
|
+
}, "ref"> & React.RefAttributes<HTMLAnchorElement>>;
|
|
8
|
+
declare const BreadcrumbPage: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "ref"> & React.RefAttributes<HTMLSpanElement>>;
|
|
9
|
+
declare const BreadcrumbSeparator: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>, "ref"> & React.RefAttributes<HTMLLIElement>>;
|
|
10
|
+
declare const BreadcrumbEllipsis: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "ref"> & React.RefAttributes<HTMLSpanElement>>;
|
|
11
11
|
export { Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, };
|