@ztwoint/z-ui 0.1.147 → 0.1.148
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/pdf-preview/components/pdf-error-state.d.ts +9 -0
- package/dist/components/pdf-preview/components/pdf-error-state.js +18 -0
- package/dist/components/pdf-preview/components/pdf-loading-state.d.ts +3 -0
- package/dist/components/pdf-preview/components/pdf-loading-state.js +34 -0
- package/dist/components/pdf-preview/components/pdf-toolbar.d.ts +16 -0
- package/dist/components/pdf-preview/components/pdf-toolbar.js +47 -0
- package/dist/components/pdf-preview/components/pdf-viewer.d.ts +22 -0
- package/dist/components/pdf-preview/components/pdf-viewer.js +6 -0
- package/dist/components/pdf-preview/index.d.ts +3 -0
- package/dist/components/pdf-preview/pdf-preview.const.d.ts +29 -0
- package/dist/components/pdf-preview/pdf-preview.const.js +29 -0
- package/dist/components/pdf-preview/pdf-preview.d.ts +16 -0
- package/dist/components/pdf-preview/pdf-preview.hook.d.ts +12 -0
- package/dist/components/pdf-preview/pdf-preview.hook.js +69 -0
- package/dist/components/pdf-preview/pdf-preview.js +77 -0
- package/dist/components/pdf-preview/pdf-preview.type.d.ts +81 -0
- package/dist/components/primitives/table-card/table-card.js +11 -10
- package/dist/components/table/components/cell/avatar-cell.js +3 -2
- package/dist/components/table/table-provider.js +1 -0
- package/dist/css/styles/tailwind.css +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +56 -54
- package/dist/sample-resume.pdf +0 -0
- package/dist/types/components/pdf-preview/components/pdf-error-state.d.ts +9 -0
- package/dist/types/components/pdf-preview/components/pdf-loading-state.d.ts +3 -0
- package/dist/types/components/pdf-preview/components/pdf-toolbar.d.ts +16 -0
- package/dist/types/components/pdf-preview/components/pdf-viewer.d.ts +22 -0
- package/dist/types/components/pdf-preview/index.d.ts +3 -0
- package/dist/types/components/pdf-preview/pdf-preview.const.d.ts +29 -0
- package/dist/types/components/pdf-preview/pdf-preview.d.ts +16 -0
- package/dist/types/components/pdf-preview/pdf-preview.hook.d.ts +12 -0
- package/dist/types/components/pdf-preview/pdf-preview.type.d.ts +81 -0
- package/dist/types/index.d.ts +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { PdfPreviewError } from '../pdf-preview.type';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
interface PdfErrorStateProps {
|
|
4
|
+
error: PdfPreviewError;
|
|
5
|
+
onRetry: () => void;
|
|
6
|
+
}
|
|
7
|
+
/** Default error UI shown when PDF loading fails. Displays warning icon, error message, and a retry button. */
|
|
8
|
+
export declare const PdfErrorState: React.FC<PdfErrorStateProps>;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { jsxs as a, jsx as e } from "react/jsx-runtime";
|
|
2
|
+
import { Button as l } from "../../button/button.js";
|
|
3
|
+
import s from "../../assets/icons/triangle-warning.js";
|
|
4
|
+
const n = ({ error: t, onRetry: r }) => /* @__PURE__ */ a(
|
|
5
|
+
"div",
|
|
6
|
+
{
|
|
7
|
+
"data-slot": "pdf-error-state",
|
|
8
|
+
className: "flex flex-1 flex-col items-center justify-center gap-3 p-6 text-center",
|
|
9
|
+
children: [
|
|
10
|
+
/* @__PURE__ */ e(s, { width: "2em", height: "2em", className: "text-text-danger-primary" }),
|
|
11
|
+
/* @__PURE__ */ e("p", { className: "text-sm text-text-neutral-primary", children: t.message || "Failed to load PDF" }),
|
|
12
|
+
/* @__PURE__ */ e(l, { onClick: r, variant: "stroke", shade: "neutral", size: "small", label: "Retry" })
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
);
|
|
16
|
+
export {
|
|
17
|
+
n as PdfErrorState
|
|
18
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { jsx as t, jsxs as e } from "react/jsx-runtime";
|
|
2
|
+
const a = () => /* @__PURE__ */ t("div", { "data-slot": "pdf-loading-state", className: "flex flex-1 items-center justify-center", children: /* @__PURE__ */ e(
|
|
3
|
+
"svg",
|
|
4
|
+
{
|
|
5
|
+
className: "h-8 w-8 animate-spin text-text-neutral-secondary",
|
|
6
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
7
|
+
fill: "none",
|
|
8
|
+
viewBox: "0 0 24 24",
|
|
9
|
+
children: [
|
|
10
|
+
/* @__PURE__ */ t(
|
|
11
|
+
"circle",
|
|
12
|
+
{
|
|
13
|
+
className: "opacity-25",
|
|
14
|
+
cx: "12",
|
|
15
|
+
cy: "12",
|
|
16
|
+
r: "10",
|
|
17
|
+
stroke: "currentColor",
|
|
18
|
+
strokeWidth: "4"
|
|
19
|
+
}
|
|
20
|
+
),
|
|
21
|
+
/* @__PURE__ */ t(
|
|
22
|
+
"path",
|
|
23
|
+
{
|
|
24
|
+
className: "opacity-75",
|
|
25
|
+
fill: "currentColor",
|
|
26
|
+
d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
|
|
27
|
+
}
|
|
28
|
+
)
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
) });
|
|
32
|
+
export {
|
|
33
|
+
a as PdfLoadingState
|
|
34
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
interface PdfToolbarProps {
|
|
3
|
+
title: string;
|
|
4
|
+
showDownload: boolean;
|
|
5
|
+
onDownload: () => void;
|
|
6
|
+
downloadDisabled?: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Toolbar displayed at the top of the PDF preview dialog.
|
|
10
|
+
* Contains:
|
|
11
|
+
* - DialogPrimitive.Title: serves as both the visible title and Radix's required accessible title
|
|
12
|
+
* - Download button (optional): triggers the parent's download handler
|
|
13
|
+
* - Close button: uses DialogPrimitive.Close to close the dialog via Radix
|
|
14
|
+
*/
|
|
15
|
+
export declare const PdfToolbar: React.FC<PdfToolbarProps>;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { jsxs as a, jsx as e } from "react/jsx-runtime";
|
|
2
|
+
import { Download as i } from "lucide-react";
|
|
3
|
+
import { Button as t } from "../../button/button.js";
|
|
4
|
+
import { Z2DialogTitle as m, Z2DialogClose as n } from "../../dialog/dialog.js";
|
|
5
|
+
import d from "../../assets/icons/x.js";
|
|
6
|
+
const b = ({
|
|
7
|
+
title: r,
|
|
8
|
+
showDownload: l,
|
|
9
|
+
onDownload: o,
|
|
10
|
+
downloadDisabled: s
|
|
11
|
+
}) => /* @__PURE__ */ a(
|
|
12
|
+
"div",
|
|
13
|
+
{
|
|
14
|
+
"data-slot": "pdf-toolbar",
|
|
15
|
+
className: "flex items-center justify-between border-b border-stroke-neutral-default px-4 py-2.5 gap-2",
|
|
16
|
+
children: [
|
|
17
|
+
/* @__PURE__ */ e(m, { className: "text-sm font-medium text-text-neutral-primary truncate", children: r }),
|
|
18
|
+
/* @__PURE__ */ a("div", { className: "flex items-center gap-1.5 shrink-0 ml-2", children: [
|
|
19
|
+
l && /* @__PURE__ */ e(
|
|
20
|
+
t,
|
|
21
|
+
{
|
|
22
|
+
onClick: o,
|
|
23
|
+
variant: "ghost",
|
|
24
|
+
shade: "neutral",
|
|
25
|
+
size: "small",
|
|
26
|
+
leftIcon: /* @__PURE__ */ e(i, { className: "w-3.5 h-3.5" }),
|
|
27
|
+
"aria-label": "Download PDF",
|
|
28
|
+
disabled: s
|
|
29
|
+
}
|
|
30
|
+
),
|
|
31
|
+
/* @__PURE__ */ e(n, { asChild: !0, children: /* @__PURE__ */ e(
|
|
32
|
+
t,
|
|
33
|
+
{
|
|
34
|
+
variant: "ghost",
|
|
35
|
+
shade: "neutral",
|
|
36
|
+
size: "small",
|
|
37
|
+
leftIcon: /* @__PURE__ */ e(d, {}),
|
|
38
|
+
"aria-label": "Close"
|
|
39
|
+
}
|
|
40
|
+
) })
|
|
41
|
+
] })
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
);
|
|
45
|
+
export {
|
|
46
|
+
b as PdfToolbar
|
|
47
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
interface PdfViewerProps {
|
|
3
|
+
url: string;
|
|
4
|
+
title: string;
|
|
5
|
+
className?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Browser-native PDF renderer with a two-level fallback:
|
|
9
|
+
*
|
|
10
|
+
* 1. <object type="application/pdf"> — uses the browser's built-in PDF plugin
|
|
11
|
+
* (Chrome, Firefox, Edge all have mature viewers with zoom, search, print)
|
|
12
|
+
*
|
|
13
|
+
* 2. <iframe> — fallback rendered as <object>'s child if the plugin is unavailable
|
|
14
|
+
*
|
|
15
|
+
* Note: <iframe> does not support child fallback content (unlike <object>), so a
|
|
16
|
+
* download link inside <iframe> would be unreachable. If the browser can't render
|
|
17
|
+
* the PDF at all, the iframe will show a blank page or its own error.
|
|
18
|
+
*
|
|
19
|
+
* This approach adds zero JS bundle size since it relies entirely on browser capabilities.
|
|
20
|
+
*/
|
|
21
|
+
export declare const PdfViewer: React.FC<PdfViewerProps>;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { jsx as a } from "react/jsx-runtime";
|
|
2
|
+
import { cn as f } from "../../../lib/utils.js";
|
|
3
|
+
const o = ({ url: e, title: l, className: r }) => /* @__PURE__ */ a("div", { "data-slot": "pdf-viewer", className: f("flex-1 min-h-0", r), children: /* @__PURE__ */ a("object", { data: e, type: "application/pdf", className: "h-full w-full", "aria-label": l, children: /* @__PURE__ */ a("iframe", { src: e, title: l, className: "h-full w-full border-0" }) }) });
|
|
4
|
+
export {
|
|
5
|
+
o as PdfViewer
|
|
6
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** Available dialog size options for the PDF preview modal. */
|
|
2
|
+
export declare const PDF_PREVIEW_SIZES: {
|
|
3
|
+
readonly SM: "sm";
|
|
4
|
+
readonly MD: "md";
|
|
5
|
+
readonly LG: "lg";
|
|
6
|
+
readonly XL: "xl";
|
|
7
|
+
readonly FULL: "full";
|
|
8
|
+
};
|
|
9
|
+
export type PdfPreviewSize = (typeof PDF_PREVIEW_SIZES)[keyof typeof PDF_PREVIEW_SIZES];
|
|
10
|
+
/** Default prop values used when the consumer doesn't provide them. */
|
|
11
|
+
export declare const PDF_PREVIEW_DEFAULTS: {
|
|
12
|
+
readonly size: PdfPreviewSize;
|
|
13
|
+
readonly showToolbar: true;
|
|
14
|
+
readonly showDownload: true;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* CVA variants for the dialog content container.
|
|
18
|
+
* Each size sets a max width/height using min() to stay responsive,
|
|
19
|
+
* with a 2rem margin from viewport edges. 'full' takes up nearly the entire screen.
|
|
20
|
+
*
|
|
21
|
+
* Note: Z2DialogContent's base styles include `grid gap-4 max-w-[calc(100%-2rem)] sm:max-w-lg`
|
|
22
|
+
* which conflict with our layout. We override them here with:
|
|
23
|
+
* - `flex flex-col` → overrides `grid` (tailwind-merge handles display conflicts)
|
|
24
|
+
* - `max-w-none sm:max-w-none` → cancels the max-width caps so our w-[min(...)] sizing works
|
|
25
|
+
* - `gap-0` → removes the default gap between children
|
|
26
|
+
*/
|
|
27
|
+
export declare const pdfDialogContentVariants: (props?: ({
|
|
28
|
+
size?: "sm" | "md" | "full" | "lg" | "xl" | null | undefined;
|
|
29
|
+
} & import('class-variance-authority/dist/types').ClassProp) | undefined) => string;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { cva as c } from "class-variance-authority";
|
|
2
|
+
const e = {
|
|
3
|
+
LG: "lg"
|
|
4
|
+
}, m = {
|
|
5
|
+
size: e.LG,
|
|
6
|
+
showToolbar: !0,
|
|
7
|
+
showDownload: !0
|
|
8
|
+
}, a = c(
|
|
9
|
+
"flex flex-col max-w-none sm:max-w-none gap-0 overflow-hidden rounded-lg",
|
|
10
|
+
{
|
|
11
|
+
variants: {
|
|
12
|
+
size: {
|
|
13
|
+
sm: "w-[min(500px,calc(100vw-2rem))] h-[min(400px,calc(100vh-2rem))]",
|
|
14
|
+
md: "w-[min(680px,calc(100vw-2rem))] h-[min(560px,calc(100vh-2rem))]",
|
|
15
|
+
lg: "w-[min(900px,calc(100vw-2rem))] h-[min(700px,calc(100vh-2rem))]",
|
|
16
|
+
xl: "w-[min(1100px,calc(100vw-2rem))] h-[min(800px,calc(100vh-2rem))]",
|
|
17
|
+
full: "w-[calc(100vw-2rem)] h-[calc(100vh-2rem)]"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
defaultVariants: {
|
|
21
|
+
size: "lg"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
);
|
|
25
|
+
export {
|
|
26
|
+
m as PDF_PREVIEW_DEFAULTS,
|
|
27
|
+
e as PDF_PREVIEW_SIZES,
|
|
28
|
+
a as pdfDialogContentVariants
|
|
29
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { PdfPreviewProps } from './pdf-preview.type';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
/**
|
|
4
|
+
* PdfPreview — A zero-dependency PDF preview dialog component.
|
|
5
|
+
*
|
|
6
|
+
* Uses the browser's built-in PDF renderer (<object> + <iframe> fallback)
|
|
7
|
+
* instead of pdf.js, resulting in zero additional bundle size.
|
|
8
|
+
*
|
|
9
|
+
* Supports:
|
|
10
|
+
* - Multiple source types: URL string, Blob, File, or async fetch function
|
|
11
|
+
* - Controlled & uncontrolled open state
|
|
12
|
+
* - Customizable loading/error states
|
|
13
|
+
* - `renderPdf` escape hatch for plugging in custom renderers (e.g. react-pdf)
|
|
14
|
+
*/
|
|
15
|
+
declare const PdfPreview: React.FC<PdfPreviewProps>;
|
|
16
|
+
export { PdfPreview };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { UsePdfPreviewProps, UsePdfPreviewReturn } from './pdf-preview.type';
|
|
2
|
+
/**
|
|
3
|
+
* Core hook that manages the entire PDF preview lifecycle:
|
|
4
|
+
* - Controlled/uncontrolled open state (like popconfirm.hook.ts pattern)
|
|
5
|
+
* - Lazy source resolution — async fetch only runs when dialog opens
|
|
6
|
+
* - Blob URL memory management — created on open, revoked on close/unmount
|
|
7
|
+
* - Status state machine: idle → loading → ready | error
|
|
8
|
+
* - Abort tracking to prevent stale state updates if dialog closes mid-fetch
|
|
9
|
+
*/
|
|
10
|
+
export declare function usePdfPreview(props: UsePdfPreviewProps): UsePdfPreviewReturn & {
|
|
11
|
+
resolvedTitle: string;
|
|
12
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { useRef as c, useState as h, useCallback as R, useEffect as x } from "react";
|
|
2
|
+
function A(t) {
|
|
3
|
+
if (typeof t == "string")
|
|
4
|
+
try {
|
|
5
|
+
const n = new URL(t, "http://localhost").pathname.split("/").pop();
|
|
6
|
+
if (n && n.endsWith(".pdf")) return decodeURIComponent(n);
|
|
7
|
+
} catch {
|
|
8
|
+
}
|
|
9
|
+
return t instanceof File ? t.name : "PDF Preview";
|
|
10
|
+
}
|
|
11
|
+
function W(t) {
|
|
12
|
+
const { src: u, open: n, onOpenChange: a, onError: L, onLoad: P } = t, i = c(u);
|
|
13
|
+
i.current = u;
|
|
14
|
+
const f = c(P);
|
|
15
|
+
f.current = P;
|
|
16
|
+
const d = c(L);
|
|
17
|
+
d.current = L;
|
|
18
|
+
const [k, w] = h(!1), [O, p] = h("idle"), [S, b] = h(null), [j, g] = h(null), v = c(null), m = c(null), y = n !== void 0, C = y ? n : k, o = R(() => {
|
|
19
|
+
v.current && (URL.revokeObjectURL(v.current), v.current = null);
|
|
20
|
+
}, []), U = R(async () => {
|
|
21
|
+
var l, E, F;
|
|
22
|
+
(l = m.current) == null || l.abort();
|
|
23
|
+
const e = new AbortController();
|
|
24
|
+
m.current = e, p("loading"), g(null), b(null), o();
|
|
25
|
+
try {
|
|
26
|
+
let r;
|
|
27
|
+
if (typeof i.current == "function" ? r = await i.current(e.signal) : r = i.current, e.signal.aborted) return;
|
|
28
|
+
if (typeof r == "string")
|
|
29
|
+
b(r);
|
|
30
|
+
else {
|
|
31
|
+
const s = URL.createObjectURL(r);
|
|
32
|
+
v.current = s, b(s);
|
|
33
|
+
}
|
|
34
|
+
p("ready"), (E = f.current) == null || E.call(f);
|
|
35
|
+
} catch (r) {
|
|
36
|
+
if (e.signal.aborted) return;
|
|
37
|
+
const s = {
|
|
38
|
+
message: r instanceof Error ? r.message : "Failed to load PDF",
|
|
39
|
+
cause: r
|
|
40
|
+
};
|
|
41
|
+
g(s), p("error"), (F = d.current) == null || F.call(d, s);
|
|
42
|
+
}
|
|
43
|
+
}, [o]), D = R(
|
|
44
|
+
(e) => {
|
|
45
|
+
var l;
|
|
46
|
+
y || w(e), a == null || a(e), e || ((l = m.current) == null || l.abort(), p("idle"), b(null), g(null), o());
|
|
47
|
+
},
|
|
48
|
+
[y, a, o]
|
|
49
|
+
);
|
|
50
|
+
x(() => (C && U(), () => {
|
|
51
|
+
var e;
|
|
52
|
+
(e = m.current) == null || e.abort(), o();
|
|
53
|
+
}), [C, U, o]);
|
|
54
|
+
const I = R(() => {
|
|
55
|
+
U();
|
|
56
|
+
}, [U]), T = A(u);
|
|
57
|
+
return {
|
|
58
|
+
open: C,
|
|
59
|
+
handleOpenChange: D,
|
|
60
|
+
status: O,
|
|
61
|
+
resolvedUrl: S,
|
|
62
|
+
error: j,
|
|
63
|
+
retry: I,
|
|
64
|
+
resolvedTitle: T
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
export {
|
|
68
|
+
W as usePdfPreview
|
|
69
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { jsxs as P, jsx as o } from "react/jsx-runtime";
|
|
2
|
+
import * as v from "react";
|
|
3
|
+
import { cn as j } from "../../lib/utils.js";
|
|
4
|
+
import { Z2Dialog as L, Z2DialogTrigger as O, Z2DialogContent as U, Z2DialogTitle as W } from "../dialog/dialog.js";
|
|
5
|
+
import { PDF_PREVIEW_DEFAULTS as m, pdfDialogContentVariants as z } from "./pdf-preview.const.js";
|
|
6
|
+
import { usePdfPreview as A } from "./pdf-preview.hook.js";
|
|
7
|
+
import { PdfToolbar as F } from "./components/pdf-toolbar.js";
|
|
8
|
+
import { PdfViewer as I } from "./components/pdf-viewer.js";
|
|
9
|
+
import { PdfLoadingState as $ } from "./components/pdf-loading-state.js";
|
|
10
|
+
import { PdfErrorState as q } from "./components/pdf-error-state.js";
|
|
11
|
+
const B = ({
|
|
12
|
+
src: y,
|
|
13
|
+
title: w,
|
|
14
|
+
size: D = m.size,
|
|
15
|
+
open: C,
|
|
16
|
+
onOpenChange: E,
|
|
17
|
+
disabled: t = !1,
|
|
18
|
+
showToolbar: c = m.showToolbar,
|
|
19
|
+
showDownload: T = m.showDownload,
|
|
20
|
+
downloadFilename: u,
|
|
21
|
+
onDownload: l,
|
|
22
|
+
loadingContent: b,
|
|
23
|
+
errorContent: n,
|
|
24
|
+
renderPdf: g,
|
|
25
|
+
className: N,
|
|
26
|
+
viewerClassName: Z,
|
|
27
|
+
onError: k,
|
|
28
|
+
onLoad: x,
|
|
29
|
+
children: h
|
|
30
|
+
}) => {
|
|
31
|
+
const { open: f, handleOpenChange: d, status: a, resolvedUrl: e, error: s, retry: R, resolvedTitle: S } = A({
|
|
32
|
+
src: y,
|
|
33
|
+
open: C,
|
|
34
|
+
onOpenChange: E,
|
|
35
|
+
onError: k,
|
|
36
|
+
onLoad: x
|
|
37
|
+
}), i = w || S, V = v.useCallback(() => {
|
|
38
|
+
if (!e)
|
|
39
|
+
return;
|
|
40
|
+
l && l();
|
|
41
|
+
const r = document.createElement("a");
|
|
42
|
+
r.href = e;
|
|
43
|
+
const p = u || i || "document.pdf";
|
|
44
|
+
r.download = p.endsWith(".pdf") ? p : `${p}.pdf`, r.target = "_blank", r.rel = "noopener noreferrer", document.body.appendChild(r), r.click(), document.body.removeChild(r);
|
|
45
|
+
}, [l, e, u, i]), _ = () => a === "idle" || a === "loading" ? b || /* @__PURE__ */ o($, {}) : a === "error" && s ? n ? typeof n == "function" ? n(s) : n : /* @__PURE__ */ o(q, { error: s, onRetry: R }) : a === "ready" && e ? g ? g(e) : /* @__PURE__ */ o(I, { url: e, title: i, className: Z }) : null;
|
|
46
|
+
return v.useEffect(() => {
|
|
47
|
+
t && f && d(!1);
|
|
48
|
+
}, [t, f, d]), // Z2Dialog wraps Radix Dialog — manages focus trapping, escape key, and overlay click-to-close
|
|
49
|
+
/* @__PURE__ */ P(L, { open: t ? !1 : f, onOpenChange: t ? void 0 : d, children: [
|
|
50
|
+
h && /* @__PURE__ */ o(O, { asChild: !0, disabled: t, "data-slot": "pdf-preview-trigger", children: h }),
|
|
51
|
+
/* @__PURE__ */ P(
|
|
52
|
+
U,
|
|
53
|
+
{
|
|
54
|
+
"data-slot": "pdf-preview-content",
|
|
55
|
+
className: j(z({ size: D }), N),
|
|
56
|
+
"aria-describedby": void 0,
|
|
57
|
+
children: [
|
|
58
|
+
c && /* @__PURE__ */ o(
|
|
59
|
+
F,
|
|
60
|
+
{
|
|
61
|
+
title: i,
|
|
62
|
+
showDownload: T,
|
|
63
|
+
onDownload: V,
|
|
64
|
+
downloadDisabled: !e
|
|
65
|
+
}
|
|
66
|
+
),
|
|
67
|
+
!c && /* @__PURE__ */ o(W, { className: "sr-only", children: i }),
|
|
68
|
+
_()
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
)
|
|
72
|
+
] });
|
|
73
|
+
};
|
|
74
|
+
B.displayName = "PdfPreview";
|
|
75
|
+
export {
|
|
76
|
+
B as PdfPreview
|
|
77
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { PdfPreviewSize } from './pdf-preview.const';
|
|
3
|
+
/**
|
|
4
|
+
* Represents an error that occurred while loading or processing a PDF.
|
|
5
|
+
* Used by error callbacks and the error state UI.
|
|
6
|
+
*/
|
|
7
|
+
export interface PdfPreviewError {
|
|
8
|
+
message: string;
|
|
9
|
+
cause?: unknown;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* State machine for the PDF loading lifecycle:
|
|
13
|
+
* idle → loading → ready | error
|
|
14
|
+
* Resets back to 'idle' when the dialog closes.
|
|
15
|
+
*/
|
|
16
|
+
export type PdfPreviewStatus = 'idle' | 'loading' | 'ready' | 'error';
|
|
17
|
+
/**
|
|
18
|
+
* Props for the PdfPreview component.
|
|
19
|
+
*
|
|
20
|
+
* Supports both controlled (open/onOpenChange) and uncontrolled usage.
|
|
21
|
+
* The `src` prop accepts multiple source types to handle different use cases:
|
|
22
|
+
* - Static URL string (e.g. "/files/report.pdf")
|
|
23
|
+
* - Blob or File object (e.g. from a file input)
|
|
24
|
+
* - Async function that returns any of the above (e.g. server-side fetch)
|
|
25
|
+
*/
|
|
26
|
+
export interface PdfPreviewProps {
|
|
27
|
+
/** PDF source — URL string, Blob, File, or async function returning any of those.
|
|
28
|
+
* Async functions receive an AbortSignal so the fetch can be cancelled when the dialog closes. */
|
|
29
|
+
src: string | Blob | File | ((signal: AbortSignal) => Promise<string | Blob | File>);
|
|
30
|
+
/** Dialog title. Auto-detected from filename if not provided */
|
|
31
|
+
title?: string;
|
|
32
|
+
/** Dialog size variant */
|
|
33
|
+
size?: PdfPreviewSize;
|
|
34
|
+
/** Controlled open state */
|
|
35
|
+
open?: boolean;
|
|
36
|
+
/** Callback when open state changes */
|
|
37
|
+
onOpenChange?: (open: boolean) => void;
|
|
38
|
+
/** Disable the trigger */
|
|
39
|
+
disabled?: boolean;
|
|
40
|
+
/** Show the toolbar (default: true) */
|
|
41
|
+
showToolbar?: boolean;
|
|
42
|
+
/** Show the download button in the toolbar (default: true) */
|
|
43
|
+
showDownload?: boolean;
|
|
44
|
+
/** Filename used when downloading */
|
|
45
|
+
downloadFilename?: string;
|
|
46
|
+
/** Custom download handler */
|
|
47
|
+
onDownload?: () => void;
|
|
48
|
+
/** Custom loading content */
|
|
49
|
+
loadingContent?: ReactNode;
|
|
50
|
+
/** Custom error content or render function */
|
|
51
|
+
errorContent?: ReactNode | ((error: PdfPreviewError) => ReactNode);
|
|
52
|
+
/** Escape hatch: render your own PDF viewer given the resolved URL */
|
|
53
|
+
renderPdf?: (resolvedUrl: string) => ReactNode;
|
|
54
|
+
/** Additional class name for the dialog content */
|
|
55
|
+
className?: string;
|
|
56
|
+
/** Additional class name for the PDF viewer area */
|
|
57
|
+
viewerClassName?: string;
|
|
58
|
+
/** Called when an error occurs */
|
|
59
|
+
onError?: (error: PdfPreviewError) => void;
|
|
60
|
+
/** Called when the PDF loads successfully */
|
|
61
|
+
onLoad?: () => void;
|
|
62
|
+
/** Click trigger element (rendered via Radix asChild) */
|
|
63
|
+
children?: ReactNode;
|
|
64
|
+
}
|
|
65
|
+
/** Props passed to the usePdfPreview hook for managing dialog state and PDF source resolution. */
|
|
66
|
+
export interface UsePdfPreviewProps {
|
|
67
|
+
src: PdfPreviewProps['src'];
|
|
68
|
+
open?: boolean;
|
|
69
|
+
onOpenChange?: (open: boolean) => void;
|
|
70
|
+
onError?: (error: PdfPreviewError) => void;
|
|
71
|
+
onLoad?: () => void;
|
|
72
|
+
}
|
|
73
|
+
/** Return value of usePdfPreview — provides state and handlers to the main component. */
|
|
74
|
+
export interface UsePdfPreviewReturn {
|
|
75
|
+
open: boolean;
|
|
76
|
+
handleOpenChange: (open: boolean) => void;
|
|
77
|
+
status: PdfPreviewStatus;
|
|
78
|
+
resolvedUrl: string | null;
|
|
79
|
+
error: PdfPreviewError | null;
|
|
80
|
+
retry: () => void;
|
|
81
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as t, jsxs as o } from "react/jsx-runtime";
|
|
2
2
|
import { Table as r } from "../../table/table-provider.js";
|
|
3
3
|
import "react";
|
|
4
|
-
import { cn as
|
|
4
|
+
import { cn as p } from "../../../lib/utils.js";
|
|
5
5
|
/* empty css */
|
|
6
6
|
import "../../alert/alert.const.js";
|
|
7
7
|
import "../../button/button.js";
|
|
@@ -57,8 +57,9 @@ import "../../z2map/components/map-controls.js";
|
|
|
57
57
|
import "../../z2map/components/map-zoom-control.js";
|
|
58
58
|
import "../../z2map/components/map-style-control.js";
|
|
59
59
|
import "../../kpi-card/kpi-card.js";
|
|
60
|
+
import "../../pdf-preview/pdf-preview.js";
|
|
60
61
|
import "../../table/table.context.js";
|
|
61
|
-
const
|
|
62
|
+
const Ut = ({
|
|
62
63
|
dataSource: b,
|
|
63
64
|
schema: k,
|
|
64
65
|
loading: H,
|
|
@@ -70,7 +71,7 @@ const Mt = ({
|
|
|
70
71
|
headerClassName: T,
|
|
71
72
|
search: s,
|
|
72
73
|
filter: e,
|
|
73
|
-
headerLeftContent:
|
|
74
|
+
headerLeftContent: h,
|
|
74
75
|
headerActions: u,
|
|
75
76
|
body: l = {
|
|
76
77
|
cell: { hasBorder: !0 },
|
|
@@ -96,13 +97,13 @@ const Mt = ({
|
|
|
96
97
|
typeof x == "string" && /* @__PURE__ */ t("div", { className: "text-text-warning-secondary text-sm", children: x })
|
|
97
98
|
] })
|
|
98
99
|
] }) });
|
|
99
|
-
const N = a && a.totalPage && a.totalPage >= 2, v = m && m.totalPage && m.totalPage >= 2 || !!i || N || !!d, F = s || e ||
|
|
100
|
-
return /* @__PURE__ */ o("div", { className:
|
|
100
|
+
const N = a && a.totalPage && a.totalPage >= 2, v = m && m.totalPage && m.totalPage >= 2 || !!i || N || !!d, F = s || e || h || u, S = typeof (e == null ? void 0 : e.showFilterButton) > "u" ? !0 : e == null ? void 0 : e.showFilterButton;
|
|
101
|
+
return /* @__PURE__ */ o("div", { className: p("flex flex-col overflow-hidden relative", j), children: [
|
|
101
102
|
/* @__PURE__ */ o(r, { dataSource: b, schema: k, emptyMessage: f, children: [
|
|
102
103
|
P && F && /* @__PURE__ */ o(
|
|
103
104
|
r.Header,
|
|
104
105
|
{
|
|
105
|
-
className:
|
|
106
|
+
className: p(
|
|
106
107
|
"flex-shrink-0",
|
|
107
108
|
c && "border-stroke-solid-medium border-1 border-b-0",
|
|
108
109
|
n && "rounded-t-xl",
|
|
@@ -110,7 +111,7 @@ const Mt = ({
|
|
|
110
111
|
),
|
|
111
112
|
children: [
|
|
112
113
|
/* @__PURE__ */ o(r.HeaderContent, { className: "overflow-x-auto p-[1px]", children: [
|
|
113
|
-
|
|
114
|
+
h && h,
|
|
114
115
|
s && /* @__PURE__ */ t(
|
|
115
116
|
r.Search,
|
|
116
117
|
{
|
|
@@ -151,7 +152,7 @@ const Mt = ({
|
|
|
151
152
|
dataSourceError: R,
|
|
152
153
|
cell: l == null ? void 0 : l.cell,
|
|
153
154
|
sort: l == null ? void 0 : l.sort,
|
|
154
|
-
className:
|
|
155
|
+
className: p(
|
|
155
156
|
"flex-1 min-h-0",
|
|
156
157
|
c && "border-stroke-solid-light border-1",
|
|
157
158
|
n && !(P && F) && "rounded-t-xl",
|
|
@@ -166,7 +167,7 @@ const Mt = ({
|
|
|
166
167
|
C && v && /* @__PURE__ */ o(
|
|
167
168
|
r.Footer,
|
|
168
169
|
{
|
|
169
|
-
className:
|
|
170
|
+
className: p(
|
|
170
171
|
"flex-shrink-0 border-stroke-solid-light border-t-[1px] mt-[-2px]",
|
|
171
172
|
c && "border",
|
|
172
173
|
n && "rounded-b-xl",
|
|
@@ -218,5 +219,5 @@ const Mt = ({
|
|
|
218
219
|
] });
|
|
219
220
|
};
|
|
220
221
|
export {
|
|
221
|
-
|
|
222
|
+
Ut as default
|
|
222
223
|
};
|
|
@@ -57,7 +57,8 @@ import "../../../z2map/components/map-controls.js";
|
|
|
57
57
|
import "../../../z2map/components/map-zoom-control.js";
|
|
58
58
|
import "../../../z2map/components/map-style-control.js";
|
|
59
59
|
import "../../../kpi-card/kpi-card.js";
|
|
60
|
-
|
|
60
|
+
import "../../../pdf-preview/pdf-preview.js";
|
|
61
|
+
const Nt = ({
|
|
61
62
|
avatar: m,
|
|
62
63
|
value: a,
|
|
63
64
|
rightIcon: o,
|
|
@@ -95,5 +96,5 @@ const ht = ({
|
|
|
95
96
|
}
|
|
96
97
|
);
|
|
97
98
|
export {
|
|
98
|
-
|
|
99
|
+
Nt as AvatarCell
|
|
99
100
|
};
|
|
@@ -62,6 +62,7 @@ import "../z2map/components/map-controls.js";
|
|
|
62
62
|
import "../z2map/components/map-zoom-control.js";
|
|
63
63
|
import "../z2map/components/map-style-control.js";
|
|
64
64
|
import "../kpi-card/kpi-card.js";
|
|
65
|
+
import "../pdf-preview/pdf-preview.js";
|
|
65
66
|
import { TableHeaderWrapper as T } from "./components/table-header-wrapper.js";
|
|
66
67
|
import { TableHeaderContent as b } from "./components/table-header-content.js";
|
|
67
68
|
import { TableFooter as s } from "./components/table-footer.js";
|