@tutti-os/ui-system 0.0.227 → 0.0.228
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/dist/{chunk-FQWIOPDU.js → chunk-GYBECSSN.js} +111 -13
- package/dist/chunk-GYBECSSN.js.map +1 -0
- package/dist/components/index.d.ts +3 -1
- package/dist/components/index.js +1 -1
- package/dist/index.js +1 -1
- package/dist/metadata/components.json +3 -1
- package/dist/metadata/index.js +3 -1
- package/dist/metadata/index.js.map +1 -1
- package/package.json +1 -1
- package/ui-system.md +14 -8
- package/dist/chunk-FQWIOPDU.js.map +0 -1
|
@@ -23,6 +23,8 @@ import {
|
|
|
23
23
|
// src/components/avatar/avatar.tsx
|
|
24
24
|
import { Avatar as AvatarPrimitive } from "radix-ui";
|
|
25
25
|
import {
|
|
26
|
+
useEffect,
|
|
27
|
+
useRef,
|
|
26
28
|
useState
|
|
27
29
|
} from "react";
|
|
28
30
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -32,15 +34,52 @@ var sizeClassNames = {
|
|
|
32
34
|
md: "size-8",
|
|
33
35
|
lg: "size-10"
|
|
34
36
|
};
|
|
37
|
+
var sizePixels = {
|
|
38
|
+
xs: 16,
|
|
39
|
+
sm: 24,
|
|
40
|
+
md: 32,
|
|
41
|
+
lg: 40
|
|
42
|
+
};
|
|
43
|
+
var avatarDeliveryBuckets = [32, 48, 64, 96, 128, 192, 256, 384, 512];
|
|
35
44
|
function avatarInitial(label, initial) {
|
|
36
45
|
const value = initial?.trim() || label.trim();
|
|
37
46
|
return Array.from(value)[0]?.toLocaleUpperCase() || "?";
|
|
38
47
|
}
|
|
48
|
+
function avatarSizePixels(size) {
|
|
49
|
+
return typeof size === "number" && Number.isFinite(size) && size > 0 ? size : typeof size === "number" ? sizePixels.md : sizePixels[size];
|
|
50
|
+
}
|
|
51
|
+
function avatarDeliveryDimension(value) {
|
|
52
|
+
const desiredSize = Math.ceil(value * 2);
|
|
53
|
+
return avatarDeliveryBuckets.find((bucket) => bucket >= desiredSize) ?? avatarDeliveryBuckets.at(-1) ?? desiredSize;
|
|
54
|
+
}
|
|
55
|
+
function avatarTransformUrl(src, dimensions) {
|
|
56
|
+
let url;
|
|
57
|
+
try {
|
|
58
|
+
url = new URL(src);
|
|
59
|
+
} catch {
|
|
60
|
+
return src;
|
|
61
|
+
}
|
|
62
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
63
|
+
return src;
|
|
64
|
+
}
|
|
65
|
+
const fragmentIndex = src.indexOf("#");
|
|
66
|
+
const sourceWithoutFragment = fragmentIndex >= 0 ? src.slice(0, fragmentIndex) : src;
|
|
67
|
+
const fragment = fragmentIndex >= 0 ? src.slice(fragmentIndex) : "";
|
|
68
|
+
const separator = sourceWithoutFragment.includes("?") ? sourceWithoutFragment.endsWith("?") || sourceWithoutFragment.endsWith("&") ? "" : "&" : "?";
|
|
69
|
+
const transformQuery = new URLSearchParams({
|
|
70
|
+
width: String(avatarDeliveryDimension(dimensions.width)),
|
|
71
|
+
height: String(avatarDeliveryDimension(dimensions.height)),
|
|
72
|
+
format: "webp",
|
|
73
|
+
fit: "inside"
|
|
74
|
+
});
|
|
75
|
+
return `${sourceWithoutFragment}${separator}${transformQuery}${fragment}`;
|
|
76
|
+
}
|
|
39
77
|
function Avatar({
|
|
40
78
|
children,
|
|
41
79
|
className,
|
|
42
80
|
fallback = "initial",
|
|
43
81
|
fallbackColor,
|
|
82
|
+
fallbackSrc,
|
|
44
83
|
imageClassName,
|
|
45
84
|
imageProps,
|
|
46
85
|
initial,
|
|
@@ -50,10 +89,24 @@ function Avatar({
|
|
|
50
89
|
src,
|
|
51
90
|
style,
|
|
52
91
|
surfaceClassName,
|
|
92
|
+
transform = false,
|
|
53
93
|
...rootProps
|
|
54
94
|
}) {
|
|
55
95
|
const normalizedSrc = src?.trim() ?? "";
|
|
56
|
-
const
|
|
96
|
+
const normalizedFallbackSrc = fallbackSrc?.trim() ?? "";
|
|
97
|
+
const initialSize = avatarSizePixels(size);
|
|
98
|
+
const surfaceRef = useRef(null);
|
|
99
|
+
const [renderedDimensions, setRenderedDimensions] = useState(null);
|
|
100
|
+
const [failedTransformUrl, setFailedTransformUrl] = useState("");
|
|
101
|
+
const [failedOriginalUrl, setFailedOriginalUrl] = useState("");
|
|
102
|
+
const transformedImageSrc = transform ? avatarTransformUrl(
|
|
103
|
+
normalizedSrc,
|
|
104
|
+
renderedDimensions ?? { height: initialSize, width: initialSize }
|
|
105
|
+
) : normalizedSrc;
|
|
106
|
+
const shouldRetryOriginal = transformedImageSrc !== normalizedSrc && failedTransformUrl === transformedImageSrc;
|
|
107
|
+
const originalCandidateSrc = shouldRetryOriginal ? normalizedSrc : transformedImageSrc;
|
|
108
|
+
const shouldUseFallback = normalizedSrc.length > 0 && originalCandidateSrc === normalizedSrc && failedOriginalUrl === normalizedSrc;
|
|
109
|
+
const effectiveImageSrc = loading ? "" : shouldUseFallback ? normalizedFallbackSrc : originalCandidateSrc;
|
|
57
110
|
const [imageState, setImageState] = useState({ src: "", status: "idle" });
|
|
58
111
|
const imageStatus = imageState.src === effectiveImageSrc ? imageState.status : effectiveImageSrc ? "loading" : "error";
|
|
59
112
|
const showImage = imageStatus === "loaded" && effectiveImageSrc.length > 0;
|
|
@@ -61,6 +114,46 @@ function Avatar({
|
|
|
61
114
|
const imageSrcForPrimitive = imageStatus === "error" ? void 0 : effectiveImageSrc || void 0;
|
|
62
115
|
const avatarState = loading ? "loading" : effectiveImageSrc.length === 0 ? fallback : imageStatus === "loading" || imageStatus === "idle" ? "loading" : showImage ? "image" : fallback;
|
|
63
116
|
const numericSizeStyle = typeof size === "number" ? { height: `${size}px`, width: `${size}px`, ...style } : style;
|
|
117
|
+
useEffect(() => {
|
|
118
|
+
setFailedTransformUrl("");
|
|
119
|
+
setFailedOriginalUrl("");
|
|
120
|
+
}, [normalizedFallbackSrc, normalizedSrc, transform]);
|
|
121
|
+
useEffect(() => {
|
|
122
|
+
const surface = surfaceRef.current;
|
|
123
|
+
if (!surface) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const updateDimensions = (width, height) => {
|
|
127
|
+
if (width <= 0 || height <= 0) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
setRenderedDimensions(
|
|
131
|
+
(current) => current?.width === width && current.height === height ? current : { height, width }
|
|
132
|
+
);
|
|
133
|
+
};
|
|
134
|
+
const rect = surface.getBoundingClientRect();
|
|
135
|
+
updateDimensions(rect.width, rect.height);
|
|
136
|
+
if (typeof ResizeObserver === "undefined") {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const observer = new ResizeObserver(([entry]) => {
|
|
140
|
+
if (entry) {
|
|
141
|
+
updateDimensions(entry.contentRect.width, entry.contentRect.height);
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
observer.observe(surface);
|
|
145
|
+
return () => {
|
|
146
|
+
observer.disconnect();
|
|
147
|
+
};
|
|
148
|
+
}, []);
|
|
149
|
+
const markImageError = () => {
|
|
150
|
+
if (transformedImageSrc !== normalizedSrc && effectiveImageSrc === transformedImageSrc && shouldRetryOriginal === false) {
|
|
151
|
+
setFailedTransformUrl(transformedImageSrc);
|
|
152
|
+
} else if (effectiveImageSrc === normalizedSrc) {
|
|
153
|
+
setFailedOriginalUrl(normalizedSrc);
|
|
154
|
+
}
|
|
155
|
+
setImageState({ src: effectiveImageSrc, status: "error" });
|
|
156
|
+
};
|
|
64
157
|
return /* @__PURE__ */ jsxs(
|
|
65
158
|
AvatarPrimitive.Root,
|
|
66
159
|
{
|
|
@@ -84,6 +177,7 @@ function Avatar({
|
|
|
84
177
|
surfaceClassName
|
|
85
178
|
),
|
|
86
179
|
"data-slot": "avatar-surface",
|
|
180
|
+
ref: surfaceRef,
|
|
87
181
|
style: fallback === "initial" && fallbackColor && !showImage && !loading && !imagePending ? { backgroundColor: fallbackColor } : void 0,
|
|
88
182
|
children: [
|
|
89
183
|
/* @__PURE__ */ jsx(
|
|
@@ -97,11 +191,15 @@ function Avatar({
|
|
|
97
191
|
),
|
|
98
192
|
src: imageSrcForPrimitive,
|
|
99
193
|
onError: (event) => {
|
|
100
|
-
|
|
194
|
+
markImageError();
|
|
101
195
|
imageProps?.onError?.(event);
|
|
102
196
|
},
|
|
103
197
|
onLoadingStatusChange: (status) => {
|
|
104
|
-
|
|
198
|
+
if (status === "error") {
|
|
199
|
+
markImageError();
|
|
200
|
+
} else {
|
|
201
|
+
setImageState({ src: effectiveImageSrc, status });
|
|
202
|
+
}
|
|
105
203
|
imageProps?.onLoadingStatusChange?.(status);
|
|
106
204
|
}
|
|
107
205
|
}
|
|
@@ -3125,7 +3223,7 @@ function SectionTabs({
|
|
|
3125
3223
|
}
|
|
3126
3224
|
|
|
3127
3225
|
// src/components/segment-bar/segment-bar.tsx
|
|
3128
|
-
import { useEffect as
|
|
3226
|
+
import { useEffect as useEffect6, useLayoutEffect as useLayoutEffect2, useRef as useRef5, useState as useState8 } from "react";
|
|
3129
3227
|
import { jsx as jsx26, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
3130
3228
|
function SegmentBar({
|
|
3131
3229
|
segments,
|
|
@@ -3135,8 +3233,8 @@ function SegmentBar({
|
|
|
3135
3233
|
className,
|
|
3136
3234
|
testId
|
|
3137
3235
|
}) {
|
|
3138
|
-
const containerRef =
|
|
3139
|
-
const buttonRefs =
|
|
3236
|
+
const containerRef = useRef5(null);
|
|
3237
|
+
const buttonRefs = useRef5({});
|
|
3140
3238
|
const [indicator, setIndicator] = useState8({
|
|
3141
3239
|
left: 0,
|
|
3142
3240
|
width: 0,
|
|
@@ -3159,7 +3257,7 @@ function SegmentBar({
|
|
|
3159
3257
|
(current) => current.left === next.left && current.width === next.width && current.ready === next.ready ? current : next
|
|
3160
3258
|
);
|
|
3161
3259
|
}, [segments, value]);
|
|
3162
|
-
|
|
3260
|
+
useEffect6(() => {
|
|
3163
3261
|
const container = containerRef.current;
|
|
3164
3262
|
if (!container || typeof ResizeObserver === "undefined") {
|
|
3165
3263
|
return;
|
|
@@ -4110,7 +4208,7 @@ function ToastViewport({
|
|
|
4110
4208
|
}
|
|
4111
4209
|
|
|
4112
4210
|
// src/components/underline-tabs/underline-tabs.tsx
|
|
4113
|
-
import { useEffect as
|
|
4211
|
+
import { useEffect as useEffect8, useLayoutEffect as useLayoutEffect4, useRef as useRef6, useState as useState10 } from "react";
|
|
4114
4212
|
import { jsx as jsx36, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
4115
4213
|
function UnderlineTabs({
|
|
4116
4214
|
tabs,
|
|
@@ -4126,9 +4224,9 @@ function UnderlineTabs({
|
|
|
4126
4224
|
scrollRightTestId,
|
|
4127
4225
|
preventMouseDownDefault = false
|
|
4128
4226
|
}) {
|
|
4129
|
-
const viewportRef =
|
|
4130
|
-
const rowRef =
|
|
4131
|
-
const buttonRefs =
|
|
4227
|
+
const viewportRef = useRef6(null);
|
|
4228
|
+
const rowRef = useRef6(null);
|
|
4229
|
+
const buttonRefs = useRef6({});
|
|
4132
4230
|
const [indicatorStyle, setIndicatorStyle] = useState10({ left: 0, width: 0 });
|
|
4133
4231
|
const [overflow, setOverflow] = useState10({
|
|
4134
4232
|
canScrollLeft: false,
|
|
@@ -4151,7 +4249,7 @@ function UnderlineTabs({
|
|
|
4151
4249
|
(current) => current.left === nextStyle.left && current.width === nextStyle.width ? current : nextStyle
|
|
4152
4250
|
);
|
|
4153
4251
|
}, [tabs, value]);
|
|
4154
|
-
|
|
4252
|
+
useEffect8(() => {
|
|
4155
4253
|
const viewport = viewportRef.current;
|
|
4156
4254
|
if (!viewport) {
|
|
4157
4255
|
return;
|
|
@@ -4743,4 +4841,4 @@ export {
|
|
|
4743
4841
|
UnderlineTabs,
|
|
4744
4842
|
ViewportMenuSurface
|
|
4745
4843
|
};
|
|
4746
|
-
//# sourceMappingURL=chunk-
|
|
4844
|
+
//# sourceMappingURL=chunk-GYBECSSN.js.map
|