@caratlogic/design-system 0.1.10 → 0.1.11
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/components/organisms/MediaGallery/MediaGallery.d.ts +1 -1
- package/dist/components/organisms/MediaGallery/MediaGallery.d.ts.map +1 -1
- package/dist/components/organisms/MediaGallery/MediaGallery.utils.d.ts +6 -0
- package/dist/components/organisms/MediaGallery/MediaGallery.utils.d.ts.map +1 -1
- package/dist/constants/filePatterns.d.ts +3 -0
- package/dist/constants/filePatterns.d.ts.map +1 -1
- package/dist/index.cjs.js +25 -3
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +25 -3
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MediaGallery.d.ts","sourceRoot":"","sources":["../../../../src/components/organisms/MediaGallery/MediaGallery.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,
|
|
1
|
+
{"version":3,"file":"MediaGallery.d.ts","sourceRoot":"","sources":["../../../../src/components/organisms/MediaGallery/MediaGallery.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,EAAE,EAAE,MAAM,OAAO,CAAC;AAY1C,OAAO,KAAK,EACV,iBAAiB,EAGlB,MAAM,sBAAsB,CAAC;AAwI9B,eAAO,MAAM,YAAY,EAAE,EAAE,CAAC,iBAAiB,CA+H9C,CAAC"}
|
|
@@ -2,6 +2,12 @@ import type { MediaItem, MediaKind } from './MediaGallery.types';
|
|
|
2
2
|
/** Seek to ~1st frame for static video thumbnails (HTML5 media fragment). */
|
|
3
3
|
export declare const videoThumbnailSrc: (src: string) => string;
|
|
4
4
|
export declare const createVideoMediaItem: (src: string, index: number, idPrefix?: string) => MediaItem;
|
|
5
|
+
/**
|
|
6
|
+
* True when a "video" is really an interactive viewer page. Supplier 360°
|
|
7
|
+
* spinners (Vision360, Varni) serve `text/html`, so `<video>` renders nothing
|
|
8
|
+
* and there is no frame to seek for a thumbnail — they need an iframe.
|
|
9
|
+
*/
|
|
10
|
+
export declare const isEmbedMediaItem: (item: MediaItem) => boolean;
|
|
5
11
|
export declare const isPdfMediaItem: (item: MediaItem) => boolean;
|
|
6
12
|
export declare const MEDIA_KIND_ORDER: MediaKind[];
|
|
7
13
|
export declare const MEDIA_KIND_LABEL: Record<MediaKind, string>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MediaGallery.utils.d.ts","sourceRoot":"","sources":["../../../../src/components/organisms/MediaGallery/MediaGallery.utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjE,6EAA6E;AAC7E,eAAO,MAAM,iBAAiB,GAAI,KAAK,MAAM,KAAG,MAI/C,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,KAAK,MAAM,EACX,OAAO,MAAM,EACb,iBAAgB,KACf,SAKD,CAAC;AAEH,eAAO,MAAM,cAAc,GAAI,MAAM,SAAS,KAAG,OAGa,CAAC;AAE/D,eAAO,MAAM,gBAAgB,EAAE,SAAS,EAAsC,CAAC;AAE/E,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAItD,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAC3B,OAAO,SAAS,EAAE,KACjB,MAAM,CAAC,SAAS,EAAE,SAAS,EAAE,CAU/B,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,OAAO,SAAS,EAAE,KAAG,SAAS,EACU,CAAC;AAExE,eAAO,MAAM,iBAAiB,GAAI,KAAK,MAAM,EAAE,WAAW,MAAM,KAAG,IASlE,CAAC"}
|
|
1
|
+
{"version":3,"file":"MediaGallery.utils.d.ts","sourceRoot":"","sources":["../../../../src/components/organisms/MediaGallery/MediaGallery.utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjE,6EAA6E;AAC7E,eAAO,MAAM,iBAAiB,GAAI,KAAK,MAAM,KAAG,MAI/C,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,KAAK,MAAM,EACX,OAAO,MAAM,EACb,iBAAgB,KACf,SAKD,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAAI,MAAM,SAAS,KAAG,OACE,CAAC;AAEtD,eAAO,MAAM,cAAc,GAAI,MAAM,SAAS,KAAG,OAGa,CAAC;AAE/D,eAAO,MAAM,gBAAgB,EAAE,SAAS,EAAsC,CAAC;AAE/E,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAItD,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAC3B,OAAO,SAAS,EAAE,KACjB,MAAM,CAAC,SAAS,EAAE,SAAS,EAAE,CAU/B,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,OAAO,SAAS,EAAE,KAAG,SAAS,EACU,CAAC;AAExE,eAAO,MAAM,iBAAiB,GAAI,KAAK,MAAM,EAAE,WAAW,MAAM,KAAG,IASlE,CAAC"}
|
|
@@ -4,6 +4,8 @@ export declare const FILE_TYPE_PATTERNS: {
|
|
|
4
4
|
readonly DOCUMENT: RegExp;
|
|
5
5
|
readonly VIDEO: RegExp;
|
|
6
6
|
readonly AUDIO: RegExp;
|
|
7
|
+
/** Interactive viewer pages (supplier 360° spinners), not media files. */
|
|
8
|
+
readonly EMBED: RegExp;
|
|
7
9
|
};
|
|
8
10
|
export declare const isFileType: {
|
|
9
11
|
readonly pdf: (url: string) => boolean;
|
|
@@ -11,5 +13,6 @@ export declare const isFileType: {
|
|
|
11
13
|
readonly document: (url: string) => boolean;
|
|
12
14
|
readonly video: (url: string) => boolean;
|
|
13
15
|
readonly audio: (url: string) => boolean;
|
|
16
|
+
readonly embed: (url: string) => boolean;
|
|
14
17
|
};
|
|
15
18
|
//# sourceMappingURL=filePatterns.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filePatterns.d.ts","sourceRoot":"","sources":["../../src/constants/filePatterns.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kBAAkB;;;;;;
|
|
1
|
+
{"version":3,"file":"filePatterns.d.ts","sourceRoot":"","sources":["../../src/constants/filePatterns.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kBAAkB;;;;;;IAM7B,0EAA0E;;CAElE,CAAC;AAEX,eAAO,MAAM,UAAU;wBACV,MAAM;0BACJ,MAAM;6BACH,MAAM;0BACT,MAAM;0BACN,MAAM;0BACN,MAAM;CACX,CAAC"}
|
package/dist/index.cjs.js
CHANGED
|
@@ -64671,6 +64671,8 @@ const FILE_TYPE_PATTERNS = {
|
|
|
64671
64671
|
DOCUMENT: /\.(doc|docx|xls|xlsx|ppt|pptx)($|\?)/i,
|
|
64672
64672
|
VIDEO: /\.(mp4|m4v|avi|mov|wmv|flv|webm|mkv|ogv|mpe?g|3gp)($|\?)/i,
|
|
64673
64673
|
AUDIO: /\.(mp3|wav|flac|aac|ogg)($|\?)/i,
|
|
64674
|
+
/** Interactive viewer pages (supplier 360° spinners), not media files. */
|
|
64675
|
+
EMBED: /\.html?($|\?|#)/i,
|
|
64674
64676
|
};
|
|
64675
64677
|
const isFileType = {
|
|
64676
64678
|
pdf: (url) => FILE_TYPE_PATTERNS.PDF.test(url),
|
|
@@ -64678,6 +64680,7 @@ const isFileType = {
|
|
|
64678
64680
|
document: (url) => FILE_TYPE_PATTERNS.DOCUMENT.test(url),
|
|
64679
64681
|
video: (url) => FILE_TYPE_PATTERNS.VIDEO.test(url),
|
|
64680
64682
|
audio: (url) => FILE_TYPE_PATTERNS.AUDIO.test(url),
|
|
64683
|
+
embed: (url) => FILE_TYPE_PATTERNS.EMBED.test(url),
|
|
64681
64684
|
};
|
|
64682
64685
|
|
|
64683
64686
|
/** Seek to ~1st frame for static video thumbnails (HTML5 media fragment). */
|
|
@@ -64693,6 +64696,12 @@ const createVideoMediaItem = (src, index, idPrefix = 'vid') => ({
|
|
|
64693
64696
|
src,
|
|
64694
64697
|
thumbSrc: videoThumbnailSrc(src),
|
|
64695
64698
|
});
|
|
64699
|
+
/**
|
|
64700
|
+
* True when a "video" is really an interactive viewer page. Supplier 360°
|
|
64701
|
+
* spinners (Vision360, Varni) serve `text/html`, so `<video>` renders nothing
|
|
64702
|
+
* and there is no frame to seek for a thumbnail — they need an iframe.
|
|
64703
|
+
*/
|
|
64704
|
+
const isEmbedMediaItem = (item) => item.kind === 'video' && isFileType.embed(item.src);
|
|
64696
64705
|
const isPdfMediaItem = (item) => item.isPdf === true ||
|
|
64697
64706
|
isFileType.pdf(item.src) ||
|
|
64698
64707
|
(item.kind === 'certificate' && !isFileType.image(item.src));
|
|
@@ -65800,9 +65809,22 @@ const PdfPreview = ({ item }) => {
|
|
|
65800
65809
|
const docsViewer = `https://docs.google.com/gview?embedded=1&url=${encodeURIComponent(item.src)}`;
|
|
65801
65810
|
return (jsxRuntime.jsx("object", { data: item.src, type: "application/pdf", className: "h-full w-full bg-card", "aria-label": item.name ?? 'Certificate PDF', children: jsxRuntime.jsx("iframe", { title: item.name ?? 'Certificate PDF', className: "h-full w-full border-0 bg-card", src: docsViewer }) }));
|
|
65802
65811
|
};
|
|
65812
|
+
/**
|
|
65813
|
+
* Videos arrive as either a real file or a supplier's 360° viewer page. The URL
|
|
65814
|
+
* settles most cases, but not every viewer ends in `.html` (v360, loupe360),
|
|
65815
|
+
* so a `<video>` that fails to load falls back to the iframe as well. Remounted
|
|
65816
|
+
* per selection via `key`, which resets that fallback.
|
|
65817
|
+
*/
|
|
65818
|
+
const VideoOrEmbed = ({ item }) => {
|
|
65819
|
+
const [useEmbed, setUseEmbed] = React.useState(() => isEmbedMediaItem(item));
|
|
65820
|
+
if (useEmbed) {
|
|
65821
|
+
return (jsxRuntime.jsx("iframe", { src: item.src, title: item.name ?? '360\u00B0 viewer', className: "h-full w-full border-0 bg-card", allowFullScreen: true }));
|
|
65822
|
+
}
|
|
65823
|
+
return (jsxRuntime.jsx("video", { src: item.src, controls: true, onError: () => setUseEmbed(true), className: "h-full w-full object-cover", "aria-label": item.name ?? 'Video' }));
|
|
65824
|
+
};
|
|
65803
65825
|
const MainMedia = ({ item }) => {
|
|
65804
65826
|
if (item.kind === 'video') {
|
|
65805
|
-
return
|
|
65827
|
+
return jsxRuntime.jsx(VideoOrEmbed, { item: item });
|
|
65806
65828
|
}
|
|
65807
65829
|
if (isPdfMediaItem(item)) {
|
|
65808
65830
|
return jsxRuntime.jsx(PdfPreview, { item: item });
|
|
@@ -65812,7 +65834,7 @@ const MainMedia = ({ item }) => {
|
|
|
65812
65834
|
const Thumbnail = ({ item, isActive, onSelect }) => {
|
|
65813
65835
|
const Icon = KIND_ICON[item.kind];
|
|
65814
65836
|
const isPdf = isPdfMediaItem(item);
|
|
65815
|
-
const isVideoWithoutThumb = item.kind === 'video' && !item.thumbSrc;
|
|
65837
|
+
const isVideoWithoutThumb = item.kind === 'video' && (!item.thumbSrc || isEmbedMediaItem(item));
|
|
65816
65838
|
return (jsxRuntime.jsxs("button", { type: "button", onClick: onSelect, "aria-label": `Select ${item.name ?? item.kind}`, "aria-pressed": isActive, className: cn('group relative flex aspect-square w-full cursor-pointer overflow-hidden rounded-lg border transition-colors', isActive
|
|
65817
65839
|
? 'border-primary ring-2 ring-primary/30'
|
|
65818
65840
|
: 'border-border hover:border-primary/40'), children: [isPdf ? (jsxRuntime.jsxs("span", { className: "flex h-full w-full flex-col items-center justify-center gap-1 bg-muted p-2 text-muted-foreground", children: [jsxRuntime.jsx(Icon, { size: 20 }), jsxRuntime.jsx("span", { className: "text-[10px] font-medium uppercase", children: "PDF" })] })) : isVideoWithoutThumb ? (jsxRuntime.jsx("div", { className: "h-full w-full flex items-center justify-center bg-muted", children: jsxRuntime.jsx(Icon, { size: 24, className: "text-muted-foreground" }) })) : item.kind === 'video' ? (jsxRuntime.jsx("video", { src: item.thumbSrc ?? item.src, muted: true, playsInline: true, preload: "metadata", className: "h-full w-full object-cover", "aria-hidden": "true" })) : (jsxRuntime.jsx("img", { src: item.thumbSrc ?? item.src, alt: "", className: "h-full w-full object-cover" })), !isPdf && item.kind !== 'image' && !isVideoWithoutThumb && (jsxRuntime.jsx("span", { className: "pointer-events-none absolute inset-0 flex items-center justify-center bg-black/30 text-white", children: jsxRuntime.jsx(Icon, { size: 20 }) })), isVideoWithoutThumb && (jsxRuntime.jsx("span", { className: "pointer-events-none absolute inset-0 flex items-center justify-center bg-black/30" }))] }));
|
|
@@ -65833,7 +65855,7 @@ const MediaGallery = ({ items, thumbsVisible = 4, hideTabs = false, mainAspectCl
|
|
|
65833
65855
|
(kinds.length > 0 ? (jsxRuntime.jsx(Tabs, { value: activeKind ?? undefined, onValueChange: (v) => setActiveKind(v), tabStyle: "boxed", size: "sm", children: jsxRuntime.jsx(TabsList, { children: kinds.map((kind) => {
|
|
65834
65856
|
const Icon = KIND_ICON[kind];
|
|
65835
65857
|
return (jsxRuntime.jsx(TabsTrigger, { value: kind, icon: jsxRuntime.jsx(Icon, { size: 14 }), children: MEDIA_KIND_LABEL[kind] }, kind));
|
|
65836
|
-
}) }) })) : (jsxRuntime.jsx("div", { className: "h-9", "aria-hidden": "true" }))), selected && isZoomableImage ? (jsxRuntime.jsxs("div", { className: "relative", children: [jsxRuntime.jsx(ZoomSplitViewer, { src: selected.src, alt: selected.name ?? 'Media' }), !hideDownload && (jsxRuntime.jsx("div", { className: "absolute right-3 top-3 z-20", children: jsxRuntime.jsx("button", { type: "button", onClick: handleDownload, "aria-label": "Download media", className: "inline-flex h-9 w-9 cursor-pointer items-center justify-center rounded-md border border-border bg-card text-foreground transition-all hover:border-primary hover:shadow-[0_0_0_4px_rgba(49,122,81,0.10)] focus-visible:border-primary focus-visible:shadow-[0_0_0_4px_rgba(49,122,81,0.10)] focus-visible:outline-none", children: jsxRuntime.jsx(Download, { className: "h-4 w-4" }) }) }))] })) : selected ? (jsxRuntime.jsxs("div", { className: cn('relative overflow-hidden rounded-xl border border-border bg-muted', mainAspectClassName), children: [jsxRuntime.jsx(MainMedia, { item: selected }), !hideDownload && (jsxRuntime.jsx("div", { className: "absolute right-3 top-3", children: jsxRuntime.jsx("button", { type: "button", onClick: handleDownload, "aria-label": "Download media", className: "inline-flex h-9 w-9 cursor-pointer items-center justify-center rounded-md border border-border bg-card text-foreground transition-all hover:border-primary hover:shadow-[0_0_0_4px_rgba(49,122,81,0.10)] focus-visible:border-primary focus-visible:shadow-[0_0_0_4px_rgba(49,122,81,0.10)] focus-visible:outline-none", children: jsxRuntime.jsx(Download, { className: "h-4 w-4" }) }) }))] })) : (jsxRuntime.jsx("div", { className: cn('flex items-center justify-center rounded-xl border border-dashed border-border bg-muted/40 text-sm text-muted-foreground', mainAspectClassName), children: emptyText })), visibleItems.length > 1 && (jsxRuntime.jsx("div", { className: "grid gap-3", style: {
|
|
65858
|
+
}) }) })) : (jsxRuntime.jsx("div", { className: "h-9", "aria-hidden": "true" }))), selected && isZoomableImage ? (jsxRuntime.jsxs("div", { className: "relative", children: [jsxRuntime.jsx(ZoomSplitViewer, { src: selected.src, alt: selected.name ?? 'Media' }), !hideDownload && (jsxRuntime.jsx("div", { className: "absolute right-3 top-3 z-20", children: jsxRuntime.jsx("button", { type: "button", onClick: handleDownload, "aria-label": "Download media", className: "inline-flex h-9 w-9 cursor-pointer items-center justify-center rounded-md border border-border bg-card text-foreground transition-all hover:border-primary hover:shadow-[0_0_0_4px_rgba(49,122,81,0.10)] focus-visible:border-primary focus-visible:shadow-[0_0_0_4px_rgba(49,122,81,0.10)] focus-visible:outline-none", children: jsxRuntime.jsx(Download, { className: "h-4 w-4" }) }) }))] })) : selected ? (jsxRuntime.jsxs("div", { className: cn('relative overflow-hidden rounded-xl border border-border bg-muted', mainAspectClassName), children: [jsxRuntime.jsx(MainMedia, { item: selected }, selected.id), !hideDownload && !isEmbedMediaItem(selected) && (jsxRuntime.jsx("div", { className: "absolute right-3 top-3", children: jsxRuntime.jsx("button", { type: "button", onClick: handleDownload, "aria-label": "Download media", className: "inline-flex h-9 w-9 cursor-pointer items-center justify-center rounded-md border border-border bg-card text-foreground transition-all hover:border-primary hover:shadow-[0_0_0_4px_rgba(49,122,81,0.10)] focus-visible:border-primary focus-visible:shadow-[0_0_0_4px_rgba(49,122,81,0.10)] focus-visible:outline-none", children: jsxRuntime.jsx(Download, { className: "h-4 w-4" }) }) }))] })) : (jsxRuntime.jsx("div", { className: cn('flex items-center justify-center rounded-xl border border-dashed border-border bg-muted/40 text-sm text-muted-foreground', mainAspectClassName), children: emptyText })), visibleItems.length > 1 && (jsxRuntime.jsx("div", { className: "grid gap-3", style: {
|
|
65837
65859
|
gridTemplateColumns: `repeat(${Math.min(visibleItems.length, thumbsVisible)}, minmax(0, 1fr))`,
|
|
65838
65860
|
}, children: visibleItems.slice(0, thumbsVisible).map((item) => (jsxRuntime.jsx(Thumbnail, { item: item, isActive: selected?.id === item.id, onSelect: () => setSelected(item) }, item.id))) }))] }));
|
|
65839
65861
|
};
|