@flamingo-stack/openframe-frontend-core 0.0.473-snapshot.20260724114839 → 0.0.473
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-RIPWRVA3.js → chunk-2SPAHQYE.js} +5 -5
- package/dist/{chunk-2R5NM3FC.cjs → chunk-4EU6WL5O.cjs} +40 -40
- package/dist/{chunk-2R5NM3FC.cjs.map → chunk-4EU6WL5O.cjs.map} +1 -1
- package/dist/{chunk-KXKTXAGN.cjs → chunk-4WHDDAVP.cjs} +40 -40
- package/dist/{chunk-KXKTXAGN.cjs.map → chunk-4WHDDAVP.cjs.map} +1 -1
- package/dist/{chunk-K52S6LZ5.js → chunk-4Y6LX6XR.js} +3 -3
- package/dist/{chunk-OKRUL7YV.js → chunk-4YH4WKLC.js} +4 -4
- package/dist/{chunk-LFXUFFDZ.cjs → chunk-5LTLYPIP.cjs} +73 -73
- package/dist/{chunk-LFXUFFDZ.cjs.map → chunk-5LTLYPIP.cjs.map} +1 -1
- package/dist/{chunk-YJWISFIK.cjs → chunk-6OGOPPTI.cjs} +12 -12
- package/dist/{chunk-YJWISFIK.cjs.map → chunk-6OGOPPTI.cjs.map} +1 -1
- package/dist/{chunk-KPVKZ5ML.cjs → chunk-6VEEQBVJ.cjs} +15 -15
- package/dist/{chunk-KPVKZ5ML.cjs.map → chunk-6VEEQBVJ.cjs.map} +1 -1
- package/dist/{chunk-SAH4FR36.js → chunk-6WPUUGW5.js} +5 -5
- package/dist/{chunk-6KD6KVAI.cjs → chunk-B472QGDO.cjs} +5 -5
- package/dist/{chunk-6KD6KVAI.cjs.map → chunk-B472QGDO.cjs.map} +1 -1
- package/dist/{chunk-3NNCBZEM.js → chunk-B52SBOUY.js} +6 -6
- package/dist/{chunk-5TQQ3CPE.cjs → chunk-CDBQQA7V.cjs} +29 -29
- package/dist/{chunk-5TQQ3CPE.cjs.map → chunk-CDBQQA7V.cjs.map} +1 -1
- package/dist/{chunk-7VBGYCXG.cjs → chunk-CH7MDKPI.cjs} +7 -7
- package/dist/{chunk-7VBGYCXG.cjs.map → chunk-CH7MDKPI.cjs.map} +1 -1
- package/dist/{chunk-S6IB3BZK.js → chunk-DBYUQOLS.js} +2 -2
- package/dist/{chunk-AGX565ZT.js → chunk-FPOHUGEK.js} +2 -2
- package/dist/{chunk-R4OGP4OV.js → chunk-H6FKYKEQ.js} +3 -3
- package/dist/{chunk-FM5KWLKU.cjs → chunk-HQL5GJ35.cjs} +3 -3
- package/dist/{chunk-FM5KWLKU.cjs.map → chunk-HQL5GJ35.cjs.map} +1 -1
- package/dist/{chunk-PTFSF3UP.js → chunk-I5L3KUTE.js} +6 -6
- package/dist/{chunk-GELW7JOQ.cjs → chunk-J5S5U76A.cjs} +32 -32
- package/dist/{chunk-GELW7JOQ.cjs.map → chunk-J5S5U76A.cjs.map} +1 -1
- package/dist/{chunk-464NJS2W.cjs → chunk-KP37QDNS.cjs} +73 -73
- package/dist/{chunk-464NJS2W.cjs.map → chunk-KP37QDNS.cjs.map} +1 -1
- package/dist/{chunk-PFD2VRZI.cjs → chunk-KXBXPOYM.cjs} +18 -18
- package/dist/{chunk-PFD2VRZI.cjs.map → chunk-KXBXPOYM.cjs.map} +1 -1
- package/dist/{chunk-VNDAMVMI.js → chunk-LWIVRGDN.js} +2 -2
- package/dist/{chunk-ZPUZPJDV.js → chunk-OTV4A6NA.js} +14 -80
- package/dist/chunk-OTV4A6NA.js.map +1 -0
- package/dist/{chunk-IIOHHNMI.js → chunk-QESV36I2.js} +70 -36
- package/dist/chunk-QESV36I2.js.map +1 -0
- package/dist/{chunk-FBUIZTAI.js → chunk-SWNZZVYG.js} +2 -2
- package/dist/{chunk-VCOL4C2W.cjs → chunk-TONMD7QX.cjs} +20 -86
- package/dist/chunk-TONMD7QX.cjs.map +1 -0
- package/dist/{chunk-Z4LAZ4ZZ.js → chunk-UCY6VITT.js} +3 -3
- package/dist/{chunk-BOPLMNSN.cjs → chunk-ZQRGJHNH.cjs} +151 -117
- package/dist/chunk-ZQRGJHNH.cjs.map +1 -0
- package/dist/components/case-studies/index.cjs +9 -9
- package/dist/components/case-studies/index.js +3 -3
- package/dist/components/chat/index.cjs +3 -3
- package/dist/components/chat/index.js +2 -2
- package/dist/components/contact/index.cjs +4 -4
- package/dist/components/contact/index.js +3 -3
- package/dist/components/docs/index.cjs +6 -6
- package/dist/components/docs/index.js +5 -5
- package/dist/components/embeds/index.cjs +4 -4
- package/dist/components/embeds/index.js +3 -3
- package/dist/components/faq/index.cjs +5 -5
- package/dist/components/faq/index.js +4 -4
- package/dist/components/features/index.cjs +3 -3
- package/dist/components/features/index.js +2 -2
- package/dist/components/help-center-pages/index.cjs +22 -22
- package/dist/components/help-center-pages/index.js +13 -13
- package/dist/components/index.cjs +136 -136
- package/dist/components/index.js +11 -11
- package/dist/components/navigation/index.cjs +3 -3
- package/dist/components/navigation/index.js +2 -2
- package/dist/components/navigation/mobile-burger-menu.d.ts.map +1 -1
- package/dist/components/onboarding-guides/index.cjs +7 -7
- package/dist/components/onboarding-guides/index.js +6 -6
- package/dist/components/related-content/index.cjs +5 -5
- package/dist/components/related-content/index.js +4 -4
- package/dist/components/tickets/index.cjs +6 -6
- package/dist/components/tickets/index.js +5 -5
- package/dist/components/ui/entity-image.d.ts.map +1 -1
- package/dist/components/ui/image-uploader.d.ts.map +1 -1
- package/dist/components/ui/index.cjs +3 -3
- package/dist/components/ui/index.js +2 -2
- package/dist/components/ui/simple-markdown-renderer.d.ts.map +1 -1
- package/dist/components/ui/square-avatar.d.ts.map +1 -1
- package/dist/hooks/index.cjs +2 -6
- package/dist/hooks/index.cjs.map +1 -1
- package/dist/hooks/index.d.ts +0 -1
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -5
- package/dist/index.cjs +3 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -6
- package/dist/utils/embed-authed-fetch.d.ts +0 -15
- package/dist/utils/embed-authed-fetch.d.ts.map +1 -1
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/navigation/mobile-burger-menu.tsx +0 -1
- package/src/components/ui/entity-image.tsx +3 -5
- package/src/components/ui/image-uploader.tsx +12 -21
- package/src/components/ui/simple-markdown-renderer.tsx +58 -57
- package/src/components/ui/square-avatar.tsx +3 -5
- package/src/hooks/index.ts +0 -1
- package/src/utils/embed-authed-fetch.ts +0 -30
- package/dist/chunk-BOPLMNSN.cjs.map +0 -1
- package/dist/chunk-IIOHHNMI.js.map +0 -1
- package/dist/chunk-VCOL4C2W.cjs.map +0 -1
- package/dist/chunk-ZPUZPJDV.js.map +0 -1
- package/dist/hooks/use-authed-image-src.d.ts +0 -10
- package/dist/hooks/use-authed-image-src.d.ts.map +0 -1
- package/src/hooks/use-authed-image-src.ts +0 -93
- /package/dist/{chunk-RIPWRVA3.js.map → chunk-2SPAHQYE.js.map} +0 -0
- /package/dist/{chunk-K52S6LZ5.js.map → chunk-4Y6LX6XR.js.map} +0 -0
- /package/dist/{chunk-OKRUL7YV.js.map → chunk-4YH4WKLC.js.map} +0 -0
- /package/dist/{chunk-SAH4FR36.js.map → chunk-6WPUUGW5.js.map} +0 -0
- /package/dist/{chunk-3NNCBZEM.js.map → chunk-B52SBOUY.js.map} +0 -0
- /package/dist/{chunk-S6IB3BZK.js.map → chunk-DBYUQOLS.js.map} +0 -0
- /package/dist/{chunk-AGX565ZT.js.map → chunk-FPOHUGEK.js.map} +0 -0
- /package/dist/{chunk-R4OGP4OV.js.map → chunk-H6FKYKEQ.js.map} +0 -0
- /package/dist/{chunk-PTFSF3UP.js.map → chunk-I5L3KUTE.js.map} +0 -0
- /package/dist/{chunk-VNDAMVMI.js.map → chunk-LWIVRGDN.js.map} +0 -0
- /package/dist/{chunk-FBUIZTAI.js.map → chunk-SWNZZVYG.js.map} +0 -0
- /package/dist/{chunk-Z4LAZ4ZZ.js.map → chunk-UCY6VITT.js.map} +0 -0
package/package.json
CHANGED
|
@@ -79,7 +79,6 @@ export const MobileBurgerMenu = React.memo(function MobileBurgerMenu({
|
|
|
79
79
|
disabled={disabled}
|
|
80
80
|
className={cn(
|
|
81
81
|
"flex items-center gap-1 p-3 relative",
|
|
82
|
-
"focus:outline-none focus-visible:outline-none",
|
|
83
82
|
"transition-colors duration-200",
|
|
84
83
|
"bg-ods-card border border-ods-border rounded-md",
|
|
85
84
|
!disabled && "hover:bg-ods-bg-hover",
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
3
|
import React from 'react'
|
|
4
|
-
import { useAuthedImageSrc } from '../../hooks/use-authed-image-src'
|
|
5
4
|
import { cn } from '../../utils/cn'
|
|
6
5
|
import { getFirstLastInitials } from '../../utils/format'
|
|
7
6
|
|
|
@@ -14,14 +13,13 @@ export interface EntityImageProps {
|
|
|
14
13
|
}
|
|
15
14
|
|
|
16
15
|
export function EntityImage({ src, alt, fallbackText, className }: EntityImageProps) {
|
|
17
|
-
const resolvedSrc = useAuthedImageSrc(src)
|
|
18
16
|
const [imageFailed, setImageFailed] = React.useState(false)
|
|
19
17
|
|
|
20
18
|
React.useEffect(() => {
|
|
21
19
|
setImageFailed(false)
|
|
22
|
-
}, [
|
|
20
|
+
}, [src])
|
|
23
21
|
|
|
24
|
-
const showFallback = imageFailed || !
|
|
22
|
+
const showFallback = imageFailed || !src
|
|
25
23
|
const initials = getFirstLastInitials(fallbackText ?? alt)
|
|
26
24
|
|
|
27
25
|
if (showFallback) {
|
|
@@ -40,7 +38,7 @@ export function EntityImage({ src, alt, fallbackText, className }: EntityImagePr
|
|
|
40
38
|
|
|
41
39
|
return (
|
|
42
40
|
<img
|
|
43
|
-
src={
|
|
41
|
+
src={src ?? undefined}
|
|
44
42
|
alt={alt ?? ''}
|
|
45
43
|
onError={() => setImageFailed(true)}
|
|
46
44
|
className={cn(
|
|
@@ -5,7 +5,6 @@ import { Loader2 } from "lucide-react"
|
|
|
5
5
|
import { ImagePlusIcon } from "../icons-v2-generated/audio-and-visual/image-plus-icon"
|
|
6
6
|
import { Refresh02VrIcon } from "../icons-v2-generated/media-playback/refresh-02-vr-icon"
|
|
7
7
|
import { TrashIcon } from "../icons-v2-generated/interface/trash-icon"
|
|
8
|
-
import { useAuthedImageSrc } from "../../hooks/use-authed-image-src"
|
|
9
8
|
import { cn } from "../../utils/cn"
|
|
10
9
|
import { FieldWrapper } from "./field-wrapper"
|
|
11
10
|
|
|
@@ -99,12 +98,6 @@ export function ImageUploader({
|
|
|
99
98
|
const [validationError, setValidationError] = React.useState<string | null>(null)
|
|
100
99
|
|
|
101
100
|
const interactive = !disabled && !loading
|
|
102
|
-
// Bearer-mode shells: swap a gateway URL for an authed blob URL (native
|
|
103
|
-
// <img> loads can't carry Authorization); pass-through everywhere else,
|
|
104
|
-
// including local blob/data preview URLs. `hasImage` stays keyed on the
|
|
105
|
-
// caller's `value` so the preview chrome doesn't flash to the empty
|
|
106
|
-
// state while the blob fetch is in flight.
|
|
107
|
-
const resolvedValue = useAuthedImageSrc(value)
|
|
108
101
|
const hasImage = Boolean(value)
|
|
109
102
|
const displayError = error || validationError || undefined
|
|
110
103
|
const resolvedHint = hint === undefined ? `Max. size: ${formatSize(maxSize)}` : hint
|
|
@@ -203,20 +196,18 @@ export function ImageUploader({
|
|
|
203
196
|
{hasImage ? (
|
|
204
197
|
<>
|
|
205
198
|
<div className="relative min-h-0 w-full flex-1 overflow-hidden rounded-md">
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
/>
|
|
219
|
-
)}
|
|
199
|
+
<img
|
|
200
|
+
src={value}
|
|
201
|
+
alt={alt}
|
|
202
|
+
className={cn(
|
|
203
|
+
"pointer-events-none absolute inset-0 size-full",
|
|
204
|
+
objectFit === "cover" && "object-cover",
|
|
205
|
+
objectFit === "contain" && "object-contain",
|
|
206
|
+
objectFit === "fill" && "object-fill",
|
|
207
|
+
objectFit === "none" && "object-none",
|
|
208
|
+
objectFit === "scale-down" && "object-scale-down",
|
|
209
|
+
)}
|
|
210
|
+
/>
|
|
220
211
|
</div>
|
|
221
212
|
|
|
222
213
|
<div className="absolute left-1/2 top-1/2 flex -translate-x-1/2 -translate-y-1/2 items-center gap-4">
|
|
@@ -9,7 +9,6 @@ import rehypeHighlight from 'rehype-highlight';
|
|
|
9
9
|
import rehypeRaw from 'rehype-raw';
|
|
10
10
|
import { visit } from 'unist-util-visit';
|
|
11
11
|
import Image from '../../embed-shims/next-image';
|
|
12
|
-
import { useAuthedImageSrc } from '../../hooks/use-authed-image-src';
|
|
13
12
|
import { AlertCircleIcon } from '../icons-v2-generated';
|
|
14
13
|
import { cn } from '../../utils/cn';
|
|
15
14
|
import type { ResolveLinkResult } from '../../types/doc-source';
|
|
@@ -454,58 +453,6 @@ const MermaidDiagram: React.FC<{ chart: string }> = ({ chart }) => {
|
|
|
454
453
|
);
|
|
455
454
|
};
|
|
456
455
|
|
|
457
|
-
// ---------------------------------------------------------------------------
|
|
458
|
-
// MarkdownContentImage
|
|
459
|
-
// ---------------------------------------------------------------------------
|
|
460
|
-
// Inline content image renderer. Used by blog posts, docs, AND chat
|
|
461
|
-
// messages (where users may attach screenshots / photos via the +
|
|
462
|
-
// attachment button). A standalone component (rather than inline JSX in
|
|
463
|
-
// the `img` renderer) because it needs `useAuthedImageSrc`: in
|
|
464
|
-
// bearer-mode native shells a gateway-hosted image can't load via a
|
|
465
|
-
// plain `<img>` (no Authorization header on native asset loads), so the
|
|
466
|
-
// hook swaps in an authed blob URL; everywhere else it passes `src`
|
|
467
|
-
// through untouched. While the blob fetch is in flight the component
|
|
468
|
-
// renders nothing — same as the no-src case.
|
|
469
|
-
//
|
|
470
|
-
// Sizing rules (2025-2026 best practice — Claude.ai, ChatGPT,
|
|
471
|
-
// iMessage, Slack, Discord inline image patterns):
|
|
472
|
-
//
|
|
473
|
-
// - CAP max-width at 400px so inline images don't blow out the
|
|
474
|
-
// message column on wide panels. Click-to-expand opens a
|
|
475
|
-
// full-resolution modal for users who need detail.
|
|
476
|
-
// - CAP max-height at 400px so portrait-orientation images
|
|
477
|
-
// don't dominate vertical space (a 1000x3000 phone screenshot
|
|
478
|
-
// would otherwise push the next message off-screen).
|
|
479
|
-
// - Small images render at NATURAL pixel size — a 64x64
|
|
480
|
-
// thumbnail stays 64x64, not stretched to fill the column.
|
|
481
|
-
// - `object-contain` preserves aspect ratio when both dimensions
|
|
482
|
-
// are constrained (long landscape, tall portrait).
|
|
483
|
-
//
|
|
484
|
-
// Implementation: Next.js `<Image>` — the project's canonical
|
|
485
|
-
// image primitive (WebP/AVIF conversion, responsive `srcset`, lazy
|
|
486
|
-
// loading, async decode). `width={400} height={400}` are REQUIRED by
|
|
487
|
-
// Next.js `<Image>` (non-`fill` mode throws without them) but they're
|
|
488
|
-
// effectively a CEILING here, not the display size — the CSS overrides
|
|
489
|
-
// (`w-auto h-auto max-w-full max-h-[400px]`) drive the actual rendered
|
|
490
|
-
// size, and the inline `style={{ width: 'auto', height: 'auto' }}` is
|
|
491
|
-
// belt-and-suspenders against the rendered `<img>`'s HTML width/height
|
|
492
|
-
// attributes.
|
|
493
|
-
const MarkdownContentImage: React.FC<{ src: string; alt?: string }> = ({ src, alt }) => {
|
|
494
|
-
const resolvedSrc = useAuthedImageSrc(src);
|
|
495
|
-
if (!resolvedSrc) return null;
|
|
496
|
-
return (
|
|
497
|
-
<Image
|
|
498
|
-
src={resolvedSrc}
|
|
499
|
-
alt={alt ?? 'No image available'}
|
|
500
|
-
width={400}
|
|
501
|
-
height={400}
|
|
502
|
-
sizes="(max-width: 400px) 100vw, 400px"
|
|
503
|
-
className="max-w-full max-h-[400px] w-auto h-auto rounded-lg object-contain"
|
|
504
|
-
style={{ width: 'auto', height: 'auto' }}
|
|
505
|
-
/>
|
|
506
|
-
);
|
|
507
|
-
};
|
|
508
|
-
|
|
509
456
|
// ---------------------------------------------------------------------------
|
|
510
457
|
// Utility: extract plain text from React children
|
|
511
458
|
// ---------------------------------------------------------------------------
|
|
@@ -873,12 +820,66 @@ const SimpleMarkdownRendererImpl: React.FC<SimpleMarkdownRendererProps> = ({
|
|
|
873
820
|
},
|
|
874
821
|
|
|
875
822
|
// --- images ---
|
|
876
|
-
//
|
|
877
|
-
//
|
|
878
|
-
//
|
|
823
|
+
// Inline content image renderer. Used by blog posts, docs, AND chat
|
|
824
|
+
// messages (where users may attach screenshots / photos via the +
|
|
825
|
+
// attachment button).
|
|
826
|
+
//
|
|
827
|
+
// Sizing rules (2025-2026 best practice — Claude.ai, ChatGPT,
|
|
828
|
+
// iMessage, Slack, Discord inline image patterns):
|
|
829
|
+
//
|
|
830
|
+
// - CAP max-width at 400px so inline images don't blow out the
|
|
831
|
+
// message column on wide panels. Click-to-expand opens a
|
|
832
|
+
// full-resolution modal for users who need detail.
|
|
833
|
+
// - CAP max-height at 400px so portrait-orientation images
|
|
834
|
+
// don't dominate vertical space (a 1000x3000 phone screenshot
|
|
835
|
+
// would otherwise push the next message off-screen).
|
|
836
|
+
// - Small images render at NATURAL pixel size — a 64x64
|
|
837
|
+
// thumbnail stays 64x64, not stretched to fill the column.
|
|
838
|
+
// - `object-contain` preserves aspect ratio when both dimensions
|
|
839
|
+
// are constrained (long landscape, tall portrait).
|
|
840
|
+
//
|
|
841
|
+
// Implementation: Next.js `<Image>` — the project's canonical
|
|
842
|
+
// image primitive. Gives us:
|
|
843
|
+
// - WebP/AVIF format conversion for modern browsers (smaller
|
|
844
|
+
// bytes for the same visual quality).
|
|
845
|
+
// - Responsive `srcset` via the `sizes` prop (browser picks the
|
|
846
|
+
// right variant for the viewport).
|
|
847
|
+
// - Automatic lazy-loading (`loading="lazy"` by default, mid-
|
|
848
|
+
// page images skipped until they near the viewport).
|
|
849
|
+
// - Automatic `decoding="async"` so image decode doesn't block
|
|
850
|
+
// paint.
|
|
851
|
+
//
|
|
852
|
+
// `width={400} height={400}` props are REQUIRED by Next.js
|
|
853
|
+
// `<Image>` (non-`fill` mode throws without them) but they're
|
|
854
|
+
// effectively a CEILING here, not the display size — the CSS
|
|
855
|
+
// overrides (`w-auto h-auto max-w-full max-h-[400px]`) drive
|
|
856
|
+
// the actual rendered size. The inline `style={{ width: 'auto',
|
|
857
|
+
// height: 'auto' }}` is belt-and-suspenders: Next.js Image sets
|
|
858
|
+
// matching HTML `width`/`height` attributes on the rendered
|
|
859
|
+
// `<img>` and inline style wins over both HTML attributes AND
|
|
860
|
+
// utility classes regardless of CSS-specificity surprises.
|
|
861
|
+
//
|
|
862
|
+
// Layout reservation trade-off: until image bytes arrive, the
|
|
863
|
+
// browser may reserve a placeholder box up to 400x400 (the props'
|
|
864
|
+
// intrinsic-ratio hint). Once loaded, the box collapses to the
|
|
865
|
+
// natural size if smaller. This is the standard Next.js Image
|
|
866
|
+
// behavior across the codebase — accepted for the optimizer +
|
|
867
|
+
// responsive-srcset benefits. Chat attachments hosted in side
|
|
868
|
+
// panels see this only on first render of a fresh attachment
|
|
869
|
+
// (cached re-renders pop in without a perceptible shift).
|
|
879
870
|
img: ({ src, alt }: any) => {
|
|
880
871
|
if (!src || typeof src !== 'string' || src.trim() === '') return null;
|
|
881
|
-
return
|
|
872
|
+
return (
|
|
873
|
+
<Image
|
|
874
|
+
src={src}
|
|
875
|
+
alt={alt ?? 'No image available'}
|
|
876
|
+
width={400}
|
|
877
|
+
height={400}
|
|
878
|
+
sizes="(max-width: 400px) 100vw, 400px"
|
|
879
|
+
className="max-w-full max-h-[400px] w-auto h-auto rounded-lg object-contain"
|
|
880
|
+
style={{ width: 'auto', height: 'auto' }}
|
|
881
|
+
/>
|
|
882
|
+
);
|
|
882
883
|
},
|
|
883
884
|
|
|
884
885
|
// --- lists ---
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import Image from "../../embed-shims/next-image";
|
|
5
|
-
import { useAuthedImageSrc } from "../../hooks/use-authed-image-src";
|
|
6
5
|
import { cn } from "../../utils/cn";
|
|
7
6
|
import { getFirstLastInitials } from "../../utils/format";
|
|
8
7
|
|
|
@@ -23,7 +22,6 @@ interface SquareAvatarProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
23
22
|
|
|
24
23
|
const SquareAvatar = React.memo(React.forwardRef<HTMLDivElement, SquareAvatarProps>(
|
|
25
24
|
({ className, src, alt, size = 'md', sizePx, fallback, variant = 'square', initialsClassName, style, ...props }, ref) => {
|
|
26
|
-
const resolvedSrc = useAuthedImageSrc(src)
|
|
27
25
|
const sizeClasses = {
|
|
28
26
|
sm: 'h-8 w-8',
|
|
29
27
|
md: 'h-10 w-10',
|
|
@@ -68,14 +66,14 @@ const SquareAvatar = React.memo(React.forwardRef<HTMLDivElement, SquareAvatarPro
|
|
|
68
66
|
// keeps the later class).
|
|
69
67
|
'flex items-center justify-center text-xs font-medium text-[color:var(--ods-avatar-initials,var(--color-text-primary))]',
|
|
70
68
|
initialsClassName,
|
|
71
|
-
|
|
69
|
+
src && 'hidden'
|
|
72
70
|
)}>
|
|
73
71
|
{getFirstLastInitials(fallback || alt) || '?'}
|
|
74
72
|
</div>
|
|
75
|
-
{
|
|
73
|
+
{src && (
|
|
76
74
|
<Image
|
|
77
75
|
className="absolute -inset-px h-[calc(100%+2px)] w-[calc(100%+2px)] max-w-none object-cover"
|
|
78
|
-
src={
|
|
76
|
+
src={src}
|
|
79
77
|
alt={alt || ''}
|
|
80
78
|
width={sizePx ?? sizePxBySize[size]}
|
|
81
79
|
height={sizePx ?? sizePxBySize[size]}
|
package/src/hooks/index.ts
CHANGED
|
@@ -156,36 +156,6 @@ export function hasEmbedAuthAdapter(): boolean {
|
|
|
156
156
|
return getRegisteredAuthAdapter() !== null
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
-
/**
|
|
160
|
-
* Whether `url` is an asset the browser CANNOT load natively because its
|
|
161
|
-
* auth rides in request headers: the registered adapter is currently
|
|
162
|
-
* supplying an `Authorization` header AND the URL's origin is one the
|
|
163
|
-
* adapter explicitly sanctions for that bearer (`allowedOrigins` — the
|
|
164
|
-
* host's gateway, cross-origin by construction in native shells).
|
|
165
|
-
*
|
|
166
|
-
* Native asset loads (`<img src>`, CSS `background-image`) can't carry
|
|
167
|
-
* custom headers, so a URL this returns `true` for must go through
|
|
168
|
-
* `embedAuthedFetch` → blob object-URL instead (see `useAuthedImageSrc`).
|
|
169
|
-
* Everything else — cookie-auth web (no Authorization), relative /
|
|
170
|
-
* same-origin URLs (cookies work), third-party origins the bearer does
|
|
171
|
-
* NOT belong to (public images) — loads natively, unchanged.
|
|
172
|
-
*/
|
|
173
|
-
export function needsBearerAssetFetch(url: string): boolean {
|
|
174
|
-
if (typeof window === 'undefined') return false
|
|
175
|
-
const adapter = getRegisteredAuthAdapter()
|
|
176
|
-
if (!adapter?.allowedOrigins?.length || adapter.getHeaders?.().Authorization === undefined) {
|
|
177
|
-
return false
|
|
178
|
-
}
|
|
179
|
-
let target: URL
|
|
180
|
-
try {
|
|
181
|
-
target = new URL(url, window.location.href)
|
|
182
|
-
} catch {
|
|
183
|
-
return false
|
|
184
|
-
}
|
|
185
|
-
if (target.protocol !== 'http:' && target.protocol !== 'https:') return false
|
|
186
|
-
return adapter.allowedOrigins.includes(target.origin)
|
|
187
|
-
}
|
|
188
|
-
|
|
189
159
|
/**
|
|
190
160
|
* `fetch` wrapper that attaches embed-proxy bearer headers (when
|
|
191
161
|
* present in sessionStorage) and forces `credentials: 'same-origin'`
|