@geomak/ui 7.8.0 → 7.10.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/dist/index.cjs +767 -515
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +48 -6
- package/dist/index.d.ts +48 -6
- package/dist/index.js +424 -172
- package/dist/index.js.map +1 -1
- package/dist/styles.css +16 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { X, Error as Error$1, Warning, CheckCircle, Info } from './chunk-KAFJJO5
|
|
|
2
2
|
export { icons_default as Icon, createIcon } from './chunk-KAFJJO5O.js';
|
|
3
3
|
import { colors_default } from './chunk-DXOWXLKK.js';
|
|
4
4
|
export { colors_default as COLORS, PALETTE as palette, semanticTokens, vars } from './chunk-DXOWXLKK.js';
|
|
5
|
-
import
|
|
5
|
+
import React36, { useMemo, createContext, useState, useEffect, useId, useCallback, useRef, useContext, useSyncExternalStore, useLayoutEffect } from 'react';
|
|
6
6
|
import { createPortal } from 'react-dom';
|
|
7
7
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
8
8
|
import * as AvatarPrimitive from '@radix-ui/react-avatar';
|
|
@@ -453,7 +453,7 @@ function Typography({
|
|
|
453
453
|
}
|
|
454
454
|
);
|
|
455
455
|
}
|
|
456
|
-
var IconButton =
|
|
456
|
+
var IconButton = React36.forwardRef(function IconButton2({
|
|
457
457
|
icon,
|
|
458
458
|
onClick,
|
|
459
459
|
type = "primary",
|
|
@@ -562,7 +562,7 @@ var SIZE_CLASSES = {
|
|
|
562
562
|
md: "h-9 px-4 text-sm gap-1.5 rounded-lg",
|
|
563
563
|
lg: "h-11 px-5 text-sm gap-2 rounded-xl"
|
|
564
564
|
};
|
|
565
|
-
var Button =
|
|
565
|
+
var Button = React36.forwardRef(function Button2({
|
|
566
566
|
content,
|
|
567
567
|
variant = "primary",
|
|
568
568
|
size = "md",
|
|
@@ -670,7 +670,7 @@ function MenuButton({
|
|
|
670
670
|
"data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
|
|
671
671
|
"data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95"
|
|
672
672
|
].join(" "),
|
|
673
|
-
children: items.map((item) => /* @__PURE__ */ jsxs(
|
|
673
|
+
children: items.map((item) => /* @__PURE__ */ jsxs(React36.Fragment, { children: [
|
|
674
674
|
item.separatorBefore && /* @__PURE__ */ jsx(DropdownMenu2.Separator, { className: "my-1 h-px bg-border" }),
|
|
675
675
|
/* @__PURE__ */ jsxs(
|
|
676
676
|
DropdownMenu2.Item,
|
|
@@ -693,6 +693,10 @@ function MenuButton({
|
|
|
693
693
|
) })
|
|
694
694
|
] });
|
|
695
695
|
}
|
|
696
|
+
var DialogContainerContext = createContext(null);
|
|
697
|
+
function useDialogContainer() {
|
|
698
|
+
return useContext(DialogContainerContext);
|
|
699
|
+
}
|
|
696
700
|
var SIZE_MAP = {
|
|
697
701
|
sm: 400,
|
|
698
702
|
md: 600,
|
|
@@ -717,6 +721,7 @@ function Modal({
|
|
|
717
721
|
className = ""
|
|
718
722
|
}) {
|
|
719
723
|
const reduced = useReducedMotion();
|
|
724
|
+
const [panelEl, setPanelEl] = useState(null);
|
|
720
725
|
const maxWidth = width ?? SIZE_MAP[size];
|
|
721
726
|
return /* @__PURE__ */ jsx(Dialog.Root, { open, onOpenChange: (next) => {
|
|
722
727
|
if (!next) onClose?.();
|
|
@@ -734,6 +739,7 @@ function Modal({
|
|
|
734
739
|
/* @__PURE__ */ jsx(AnimatePresence, { children: open && /* @__PURE__ */ jsx(Dialog.Content, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
735
740
|
motion.div,
|
|
736
741
|
{
|
|
742
|
+
ref: setPanelEl,
|
|
737
743
|
className: `fixed left-1/2 top-1/2 z-modal flex flex-col w-[calc(100%-2rem)] max-h-[90dvh] bg-surface rounded-2xl shadow-xl overflow-hidden focus:outline-none ${className}`.trim(),
|
|
738
744
|
style: {
|
|
739
745
|
maxWidth,
|
|
@@ -761,7 +767,7 @@ function Modal({
|
|
|
761
767
|
}
|
|
762
768
|
) })
|
|
763
769
|
] }),
|
|
764
|
-
/* @__PURE__ */ jsx("div", { className: `flex-1 overflow-y-auto p-5 ${hasFooter ? "" : "pb-5"}`, children }),
|
|
770
|
+
/* @__PURE__ */ jsx("div", { className: `flex-1 overflow-y-auto p-5 ${hasFooter ? "" : "pb-5"}`, children: /* @__PURE__ */ jsx(DialogContainerContext.Provider, { value: panelEl, children }) }),
|
|
765
771
|
hasFooter && /* @__PURE__ */ jsxs("div", { className: "flex flex-shrink-0 items-center justify-end gap-3 border-t border-border px-5 py-3", children: [
|
|
766
772
|
/* @__PURE__ */ jsx(
|
|
767
773
|
Button_default,
|
|
@@ -812,6 +818,7 @@ function Drawer({
|
|
|
812
818
|
className = ""
|
|
813
819
|
}) {
|
|
814
820
|
const reduced = useReducedMotion();
|
|
821
|
+
const [panelEl, setPanelEl] = useState(null);
|
|
815
822
|
const isRight = placement === "right";
|
|
816
823
|
const hiddenX = isRight ? "100%" : "-100%";
|
|
817
824
|
const resolvedWidth = width ?? SIZE_MAP2[size];
|
|
@@ -832,6 +839,7 @@ function Drawer({
|
|
|
832
839
|
/* @__PURE__ */ jsx(AnimatePresence, { children: open && /* @__PURE__ */ jsx(Dialog.Content, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
833
840
|
motion.div,
|
|
834
841
|
{
|
|
842
|
+
ref: setPanelEl,
|
|
835
843
|
className: `fixed top-0 bottom-0 ${isRight ? "right-0" : "left-0"} z-modal flex flex-col bg-surface shadow-xl focus:outline-none ${className}`.trim(),
|
|
836
844
|
style: { width: `min(calc(100vw - 1rem), ${widthCss})` },
|
|
837
845
|
initial: { x: reduced ? 0 : hiddenX, opacity: reduced ? 0 : 1 },
|
|
@@ -858,7 +866,7 @@ function Drawer({
|
|
|
858
866
|
}
|
|
859
867
|
) })
|
|
860
868
|
] }),
|
|
861
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto p-5", children }),
|
|
869
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto p-5", children: /* @__PURE__ */ jsx(DialogContainerContext.Provider, { value: panelEl, children }) }),
|
|
862
870
|
hasFooter && /* @__PURE__ */ jsxs("div", { className: `flex flex-shrink-0 items-center gap-3 border-t border-border px-5 py-3 ${isRight ? "justify-start" : "justify-end"}`, children: [
|
|
863
871
|
/* @__PURE__ */ jsx(Button_default, { style: { width: 90 }, variant: cancelVariant, content: cancelText, onClick: onCancel }),
|
|
864
872
|
/* @__PURE__ */ jsx(Button_default, { style: { width: 90 }, variant: okVariant, content: okText, onClick: onOk })
|
|
@@ -1817,7 +1825,7 @@ function Kbd({
|
|
|
1817
1825
|
style
|
|
1818
1826
|
}) {
|
|
1819
1827
|
if (keys && keys.length > 0) {
|
|
1820
|
-
return /* @__PURE__ */ jsx("span", { className: cx("inline-flex items-center gap-1", className), style, children: keys.map((k, i) => /* @__PURE__ */ jsxs(
|
|
1828
|
+
return /* @__PURE__ */ jsx("span", { className: cx("inline-flex items-center gap-1", className), style, children: keys.map((k, i) => /* @__PURE__ */ jsxs(React36.Fragment, { children: [
|
|
1821
1829
|
i > 0 && /* @__PURE__ */ jsx("span", { className: "text-foreground-muted text-xs select-none", children: separator }),
|
|
1822
1830
|
/* @__PURE__ */ jsx("kbd", { className: [cap, SIZE3[size]].join(" "), children: k })
|
|
1823
1831
|
] }, `${k}-${i}`)) });
|
|
@@ -1909,7 +1917,7 @@ function FlatCarousel({
|
|
|
1909
1917
|
style
|
|
1910
1918
|
}) {
|
|
1911
1919
|
const scrollerRef = useRef(null);
|
|
1912
|
-
const slides =
|
|
1920
|
+
const slides = React36.Children.toArray(children);
|
|
1913
1921
|
const [active, setActive] = useState(0);
|
|
1914
1922
|
const [atStart, setAtStart] = useState(true);
|
|
1915
1923
|
const [atEnd, setAtEnd] = useState(false);
|
|
@@ -1964,7 +1972,7 @@ function RotatingCarousel({
|
|
|
1964
1972
|
className = "",
|
|
1965
1973
|
style
|
|
1966
1974
|
}) {
|
|
1967
|
-
const slides =
|
|
1975
|
+
const slides = React36.Children.toArray(children);
|
|
1968
1976
|
const count = slides.length;
|
|
1969
1977
|
const [active, setActive] = useState(0);
|
|
1970
1978
|
const reduced = useReducedMotion();
|
|
@@ -5245,7 +5253,7 @@ function Wizard({
|
|
|
5245
5253
|
] });
|
|
5246
5254
|
}
|
|
5247
5255
|
var SearchIcon = /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", className: "w-4 h-4", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { fillRule: "evenodd", d: "M10.5 3.75a6.75 6.75 0 100 13.5 6.75 6.75 0 000-13.5zM2.25 10.5a8.25 8.25 0 1114.59 5.28l4.69 4.69a.75.75 0 11-1.06 1.06l-4.69-4.69A8.25 8.25 0 012.25 10.5z", clipRule: "evenodd" }) });
|
|
5248
|
-
var SearchInput =
|
|
5256
|
+
var SearchInput = React36.forwardRef(function SearchInput2({ value, onChange, disabled, label, htmlFor, placeholder, name, inputStyle, style, layout = "vertical", size = "md", icon, helperText, className }, ref) {
|
|
5249
5257
|
return /* @__PURE__ */ jsx(Field, { className, label, htmlFor, layout, helperText, children: /* @__PURE__ */ jsxs(
|
|
5250
5258
|
"div",
|
|
5251
5259
|
{
|
|
@@ -5562,7 +5570,7 @@ function TableBody({
|
|
|
5562
5570
|
return /* @__PURE__ */ jsx("tbody", { children: rows.map((row, i) => {
|
|
5563
5571
|
const rowKey = getRowKey(row, i);
|
|
5564
5572
|
const isExpanded = expanded.has(rowKey);
|
|
5565
|
-
return /* @__PURE__ */ jsxs(
|
|
5573
|
+
return /* @__PURE__ */ jsxs(React36.Fragment, { children: [
|
|
5566
5574
|
/* @__PURE__ */ jsxs(
|
|
5567
5575
|
"tr",
|
|
5568
5576
|
{
|
|
@@ -5937,6 +5945,15 @@ async function sourceToBytes(source, remote) {
|
|
|
5937
5945
|
}
|
|
5938
5946
|
throw new Error("Unsupported source type");
|
|
5939
5947
|
}
|
|
5948
|
+
function downloadBlob(blob, name) {
|
|
5949
|
+
if (typeof document === "undefined") return;
|
|
5950
|
+
const url = URL.createObjectURL(blob);
|
|
5951
|
+
const a = document.createElement("a");
|
|
5952
|
+
a.href = url;
|
|
5953
|
+
a.download = name;
|
|
5954
|
+
a.click();
|
|
5955
|
+
setTimeout(() => URL.revokeObjectURL(url), 1e3);
|
|
5956
|
+
}
|
|
5940
5957
|
function sourceName(source) {
|
|
5941
5958
|
if (typeof File !== "undefined" && source instanceof File) return source.name;
|
|
5942
5959
|
if (isUrlSource(source)) {
|
|
@@ -5947,17 +5964,45 @@ function sourceName(source) {
|
|
|
5947
5964
|
return void 0;
|
|
5948
5965
|
}
|
|
5949
5966
|
var pdfjsPromise = null;
|
|
5950
|
-
function loadPdfjs() {
|
|
5967
|
+
function loadPdfjs(workerSrc) {
|
|
5951
5968
|
if (pdfjsPromise) return pdfjsPromise;
|
|
5952
5969
|
pdfjsPromise = import('pdfjs-dist').then((pdfjs) => {
|
|
5953
5970
|
if (!pdfjs.GlobalWorkerOptions.workerSrc) {
|
|
5954
|
-
pdfjs.GlobalWorkerOptions.workerSrc = `https://cdn.jsdelivr.net/npm/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.mjs`;
|
|
5971
|
+
pdfjs.GlobalWorkerOptions.workerSrc = workerSrc ?? `https://cdn.jsdelivr.net/npm/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.mjs`;
|
|
5955
5972
|
}
|
|
5956
5973
|
return pdfjs;
|
|
5957
5974
|
});
|
|
5958
5975
|
return pdfjsPromise;
|
|
5959
5976
|
}
|
|
5960
5977
|
var GAP = 12;
|
|
5978
|
+
var SEARCH_DEBOUNCE = 220;
|
|
5979
|
+
var TEXT_LAYER_STYLE_ID = "oxygen-pdf-textlayer";
|
|
5980
|
+
var TEXT_LAYER_CSS = `
|
|
5981
|
+
.oxy-textLayer{position:absolute;inset:0;overflow:clip;line-height:1;text-size-adjust:none;forced-color-adjust:none;transform-origin:0 0}
|
|
5982
|
+
.oxy-textLayer span,.oxy-textLayer br{color:transparent;position:absolute;white-space:pre;cursor:text;transform-origin:0 0}
|
|
5983
|
+
.oxy-textLayer span.markedContent{top:0;height:0}
|
|
5984
|
+
.oxy-textLayer ::selection{background:color-mix(in srgb, var(--color-accent) 35%, transparent)}
|
|
5985
|
+
`;
|
|
5986
|
+
function ensureTextLayerStyles() {
|
|
5987
|
+
if (typeof document === "undefined" || document.getElementById(TEXT_LAYER_STYLE_ID)) return;
|
|
5988
|
+
const el = document.createElement("style");
|
|
5989
|
+
el.id = TEXT_LAYER_STYLE_ID;
|
|
5990
|
+
el.textContent = TEXT_LAYER_CSS;
|
|
5991
|
+
document.head.appendChild(el);
|
|
5992
|
+
}
|
|
5993
|
+
function pageIndexAt(offsets, y) {
|
|
5994
|
+
let lo = 0;
|
|
5995
|
+
let hi = offsets.length - 1;
|
|
5996
|
+
let ans = 0;
|
|
5997
|
+
while (lo <= hi) {
|
|
5998
|
+
const mid = lo + hi >> 1;
|
|
5999
|
+
if (offsets[mid] <= y) {
|
|
6000
|
+
ans = mid;
|
|
6001
|
+
lo = mid + 1;
|
|
6002
|
+
} else hi = mid - 1;
|
|
6003
|
+
}
|
|
6004
|
+
return ans;
|
|
6005
|
+
}
|
|
5961
6006
|
function PdfViewer({
|
|
5962
6007
|
source,
|
|
5963
6008
|
remote,
|
|
@@ -5966,9 +6011,12 @@ function PdfViewer({
|
|
|
5966
6011
|
toolbar = true,
|
|
5967
6012
|
thumbnails = false,
|
|
5968
6013
|
textLayer = true,
|
|
6014
|
+
workerSrc,
|
|
5969
6015
|
onLoad,
|
|
5970
6016
|
onError,
|
|
5971
6017
|
onPageChange,
|
|
6018
|
+
height = 600,
|
|
6019
|
+
width,
|
|
5972
6020
|
className = "",
|
|
5973
6021
|
style
|
|
5974
6022
|
}) {
|
|
@@ -5976,6 +6024,7 @@ function PdfViewer({
|
|
|
5976
6024
|
const [doc, setDoc] = useState(null);
|
|
5977
6025
|
const [numPages, setNumPages] = useState(0);
|
|
5978
6026
|
const [baseSize, setBaseSize] = useState(null);
|
|
6027
|
+
const [sizes, setSizes] = useState([]);
|
|
5979
6028
|
const [status, setStatus] = useState("loading");
|
|
5980
6029
|
const [error, setError] = useState(null);
|
|
5981
6030
|
const [reloadKey, setReloadKey] = useState(0);
|
|
@@ -5988,6 +6037,13 @@ function PdfViewer({
|
|
|
5988
6037
|
const [query, setQuery] = useState("");
|
|
5989
6038
|
const [matchPages, setMatchPages] = useState(null);
|
|
5990
6039
|
const [matchIdx, setMatchIdx] = useState(0);
|
|
6040
|
+
const [searching, setSearching] = useState(false);
|
|
6041
|
+
const [pageDraft, setPageDraft] = useState("");
|
|
6042
|
+
const pageEditing = useRef(false);
|
|
6043
|
+
const pageText = useRef(/* @__PURE__ */ new Map());
|
|
6044
|
+
const searchSeq = useRef(0);
|
|
6045
|
+
const searchTimer = useRef(null);
|
|
6046
|
+
const measured = useRef(/* @__PURE__ */ new Set());
|
|
5991
6047
|
const tb = toolbar === true ? { zoom: true, pager: true, download: true, print: true, search: true } : toolbar || {};
|
|
5992
6048
|
useEffect(() => {
|
|
5993
6049
|
let cancelled = false;
|
|
@@ -5996,7 +6052,12 @@ function PdfViewer({
|
|
|
5996
6052
|
setError(null);
|
|
5997
6053
|
setDoc(null);
|
|
5998
6054
|
setBaseSize(null);
|
|
5999
|
-
|
|
6055
|
+
setSizes([]);
|
|
6056
|
+
pageText.current.clear();
|
|
6057
|
+
measured.current = /* @__PURE__ */ new Set();
|
|
6058
|
+
setMatchPages(null);
|
|
6059
|
+
setMatchIdx(0);
|
|
6060
|
+
loadPdfjs(workerSrc).then(async (pdfjs2) => {
|
|
6000
6061
|
if (cancelled) return;
|
|
6001
6062
|
setPdfjs(pdfjs2);
|
|
6002
6063
|
const params = isUrlSource(source) ? { url: urlHref(source), httpHeaders: remote?.httpHeaders, withCredentials: remote?.withCredentials } : { data: source instanceof Uint8Array || source instanceof ArrayBuffer ? source : new Uint8Array(await source.arrayBuffer()) };
|
|
@@ -6009,9 +6070,12 @@ function PdfViewer({
|
|
|
6009
6070
|
const first = await pdf.getPage(1);
|
|
6010
6071
|
const vp = first.getViewport({ scale: 1 });
|
|
6011
6072
|
if (cancelled) return;
|
|
6073
|
+
const base = { width: vp.width, height: vp.height };
|
|
6012
6074
|
setDoc(pdf);
|
|
6013
6075
|
setNumPages(pdf.numPages);
|
|
6014
|
-
setBaseSize(
|
|
6076
|
+
setBaseSize(base);
|
|
6077
|
+
setSizes(Array.from({ length: pdf.numPages }, () => base));
|
|
6078
|
+
measured.current.add(1);
|
|
6015
6079
|
setStatus("ready");
|
|
6016
6080
|
onLoad?.({ numPages: pdf.numPages });
|
|
6017
6081
|
}).catch((err) => {
|
|
@@ -6024,7 +6088,7 @@ function PdfViewer({
|
|
|
6024
6088
|
cancelled = true;
|
|
6025
6089
|
task?.destroy?.();
|
|
6026
6090
|
};
|
|
6027
|
-
}, [source, remote, reloadKey]);
|
|
6091
|
+
}, [source, remote, reloadKey, workerSrc]);
|
|
6028
6092
|
useEffect(() => () => {
|
|
6029
6093
|
doc?.destroy?.();
|
|
6030
6094
|
}, [doc]);
|
|
@@ -6037,59 +6101,101 @@ function PdfViewer({
|
|
|
6037
6101
|
ro.observe(el);
|
|
6038
6102
|
return () => ro.disconnect();
|
|
6039
6103
|
}, [status]);
|
|
6104
|
+
const handleMeasure = useCallback((p, size) => {
|
|
6105
|
+
setSizes((prev) => {
|
|
6106
|
+
const cur = prev[p - 1];
|
|
6107
|
+
if (cur && Math.abs(cur.width - size.width) < 0.5 && Math.abs(cur.height - size.height) < 0.5) return prev;
|
|
6108
|
+
const next = prev.slice();
|
|
6109
|
+
next[p - 1] = size;
|
|
6110
|
+
return next;
|
|
6111
|
+
});
|
|
6112
|
+
}, []);
|
|
6040
6113
|
const scale = useMemo(() => {
|
|
6041
6114
|
if (!baseSize) return 1;
|
|
6042
6115
|
if (typeof zoomMode === "number") return zoomMode;
|
|
6043
|
-
const avail = Math.max(
|
|
6116
|
+
const avail = Math.max(1, (viewport.w || baseSize.width) - 32);
|
|
6044
6117
|
if (zoomMode === "page-width" || zoomMode === "auto") return avail / baseSize.width;
|
|
6045
6118
|
if (zoomMode === "page-fit") {
|
|
6046
|
-
const availH = Math.max(
|
|
6119
|
+
const availH = Math.max(1, (viewport.h || baseSize.height) - 32);
|
|
6047
6120
|
return Math.min(avail / baseSize.width, availH / baseSize.height);
|
|
6048
6121
|
}
|
|
6049
6122
|
return 1;
|
|
6050
6123
|
}, [zoomMode, baseSize, viewport]);
|
|
6051
|
-
const
|
|
6052
|
-
|
|
6053
|
-
|
|
6124
|
+
const { offsets, total } = useMemo(() => {
|
|
6125
|
+
const offs = new Array(sizes.length);
|
|
6126
|
+
let acc = 0;
|
|
6127
|
+
for (let i = 0; i < sizes.length; i++) {
|
|
6128
|
+
offs[i] = acc;
|
|
6129
|
+
acc += sizes[i].height * scale + GAP;
|
|
6130
|
+
}
|
|
6131
|
+
return { offsets: offs, total: acc };
|
|
6132
|
+
}, [sizes, scale]);
|
|
6054
6133
|
const overscan = 1;
|
|
6055
|
-
const
|
|
6056
|
-
const
|
|
6134
|
+
const hasLayout = offsets.length > 0 && total > 0;
|
|
6135
|
+
const startIdx = hasLayout ? Math.max(0, pageIndexAt(offsets, scrollTop) - overscan) : 0;
|
|
6136
|
+
const endIdx = hasLayout ? Math.min(numPages, pageIndexAt(offsets, scrollTop + viewport.h) + 1 + overscan) : 0;
|
|
6057
6137
|
const visiblePages = Array.from({ length: Math.max(0, endIdx - startIdx) }, (_, i) => startIdx + i + 1);
|
|
6138
|
+
const scrollToPage = useCallback((p) => {
|
|
6139
|
+
const el = scrollRef.current;
|
|
6140
|
+
if (!el || !offsets.length) return;
|
|
6141
|
+
const clamped = Math.min(offsets.length, Math.max(1, p));
|
|
6142
|
+
el.scrollTo({ top: offsets[clamped - 1] ?? 0, behavior: "smooth" });
|
|
6143
|
+
}, [offsets]);
|
|
6058
6144
|
useEffect(() => {
|
|
6059
|
-
if (!
|
|
6060
|
-
const cur =
|
|
6145
|
+
if (!hasLayout) return;
|
|
6146
|
+
const cur = pageIndexAt(offsets, scrollTop + viewport.h / 2) + 1;
|
|
6061
6147
|
if (cur !== page) {
|
|
6062
6148
|
setPage(cur);
|
|
6063
6149
|
onPageChange?.(cur);
|
|
6064
6150
|
}
|
|
6065
|
-
}, [scrollTop,
|
|
6066
|
-
const scrollToPage = useCallback((p) => {
|
|
6067
|
-
const el = scrollRef.current;
|
|
6068
|
-
if (!el || !pageH) return;
|
|
6069
|
-
el.scrollTo({ top: (p - 1) * pageH, behavior: "smooth" });
|
|
6070
|
-
}, [pageH]);
|
|
6151
|
+
}, [scrollTop, offsets, viewport.h, numPages]);
|
|
6071
6152
|
useEffect(() => {
|
|
6072
6153
|
if (status === "ready" && initialPage > 1) scrollToPage(initialPage);
|
|
6073
|
-
}, [status]);
|
|
6154
|
+
}, [status, initialPage]);
|
|
6074
6155
|
const runSearch = useCallback(async (q) => {
|
|
6075
|
-
|
|
6076
|
-
if (!doc || !
|
|
6156
|
+
const needle = q.trim().toLowerCase();
|
|
6157
|
+
if (!doc || !needle) {
|
|
6077
6158
|
setMatchPages(null);
|
|
6078
6159
|
setMatchIdx(0);
|
|
6160
|
+
setSearching(false);
|
|
6079
6161
|
return;
|
|
6080
6162
|
}
|
|
6081
|
-
const
|
|
6163
|
+
const seq = ++searchSeq.current;
|
|
6164
|
+
setSearching(true);
|
|
6082
6165
|
const hits = [];
|
|
6083
6166
|
for (let p = 1; p <= numPages; p++) {
|
|
6084
|
-
|
|
6085
|
-
|
|
6086
|
-
|
|
6167
|
+
let text = pageText.current.get(p);
|
|
6168
|
+
if (text === void 0) {
|
|
6169
|
+
const pg = await doc.getPage(p);
|
|
6170
|
+
const tc = await pg.getTextContent();
|
|
6171
|
+
const built = tc.items.map((it) => "str" in it ? it.str : "").join(" ").toLowerCase();
|
|
6172
|
+
pageText.current.set(p, built);
|
|
6173
|
+
text = built;
|
|
6174
|
+
}
|
|
6175
|
+
if (seq !== searchSeq.current) return;
|
|
6087
6176
|
if (text.includes(needle)) hits.push(p);
|
|
6088
6177
|
}
|
|
6178
|
+
if (seq !== searchSeq.current) return;
|
|
6089
6179
|
setMatchPages(hits);
|
|
6090
6180
|
setMatchIdx(0);
|
|
6181
|
+
setSearching(false);
|
|
6091
6182
|
if (hits.length) scrollToPage(hits[0]);
|
|
6092
6183
|
}, [doc, numPages, scrollToPage]);
|
|
6184
|
+
const onQueryChange = useCallback((v) => {
|
|
6185
|
+
setQuery(v);
|
|
6186
|
+
if (searchTimer.current) clearTimeout(searchTimer.current);
|
|
6187
|
+
if (!v.trim()) {
|
|
6188
|
+
searchSeq.current++;
|
|
6189
|
+
setMatchPages(null);
|
|
6190
|
+
setMatchIdx(0);
|
|
6191
|
+
setSearching(false);
|
|
6192
|
+
return;
|
|
6193
|
+
}
|
|
6194
|
+
searchTimer.current = setTimeout(() => runSearch(v), SEARCH_DEBOUNCE);
|
|
6195
|
+
}, [runSearch]);
|
|
6196
|
+
useEffect(() => () => {
|
|
6197
|
+
if (searchTimer.current) clearTimeout(searchTimer.current);
|
|
6198
|
+
}, []);
|
|
6093
6199
|
const gotoMatch = (dir) => {
|
|
6094
6200
|
if (!matchPages?.length) return;
|
|
6095
6201
|
const next = (matchIdx + dir + matchPages.length) % matchPages.length;
|
|
@@ -6103,15 +6209,9 @@ function PdfViewer({
|
|
|
6103
6209
|
if (typeof Blob !== "undefined" && source instanceof Blob) return new Uint8Array(await source.arrayBuffer());
|
|
6104
6210
|
throw new Error("No bytes available");
|
|
6105
6211
|
}, [doc, source]);
|
|
6106
|
-
const
|
|
6212
|
+
const download = useCallback(async () => {
|
|
6107
6213
|
const bytes = await getBytes();
|
|
6108
|
-
|
|
6109
|
-
const url = URL.createObjectURL(blob);
|
|
6110
|
-
const a = document.createElement("a");
|
|
6111
|
-
a.href = url;
|
|
6112
|
-
a.download = sourceName(source) || "document.pdf";
|
|
6113
|
-
a.click();
|
|
6114
|
-
setTimeout(() => URL.revokeObjectURL(url), 1e3);
|
|
6214
|
+
downloadBlob(new Blob([bytes], { type: "application/pdf" }), sourceName(source) || "document.pdf");
|
|
6115
6215
|
}, [getBytes, source]);
|
|
6116
6216
|
const print = useCallback(async () => {
|
|
6117
6217
|
const bytes = await getBytes();
|
|
@@ -6137,6 +6237,12 @@ function PdfViewer({
|
|
|
6137
6237
|
const cur = typeof zoomMode === "number" ? zoomMode : scale;
|
|
6138
6238
|
setZoomMode(Math.min(5, Math.max(0.25, +(cur * factor).toFixed(2))));
|
|
6139
6239
|
};
|
|
6240
|
+
const zoomPct = Math.round(scale * 100);
|
|
6241
|
+
const commitPageDraft = () => {
|
|
6242
|
+
pageEditing.current = false;
|
|
6243
|
+
const n = parseInt(pageDraft, 10);
|
|
6244
|
+
if (Number.isFinite(n)) scrollToPage(n);
|
|
6245
|
+
};
|
|
6140
6246
|
if (status === "error") {
|
|
6141
6247
|
return /* @__PURE__ */ jsxs("div", { className: cx("flex flex-col items-center justify-center gap-3 rounded-lg border border-border bg-surface p-8 text-center", className), style, children: [
|
|
6142
6248
|
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-status-error", children: "Couldn\u2019t load the PDF" }),
|
|
@@ -6144,80 +6250,127 @@ function PdfViewer({
|
|
|
6144
6250
|
/* @__PURE__ */ jsx(Button_default, { content: "Retry", size: "sm", variant: "outline", onClick: () => setReloadKey((k) => k + 1) })
|
|
6145
6251
|
] });
|
|
6146
6252
|
}
|
|
6147
|
-
|
|
6148
|
-
|
|
6149
|
-
|
|
6150
|
-
|
|
6151
|
-
/* @__PURE__ */ jsxs("
|
|
6152
|
-
|
|
6153
|
-
"
|
|
6154
|
-
|
|
6253
|
+
const ready = status === "ready";
|
|
6254
|
+
return /* @__PURE__ */ jsxs("div", { className: cx("flex flex-col overflow-hidden rounded-lg border border-border bg-surface-raised", className), style: { height, width, ...style }, children: [
|
|
6255
|
+
toolbar !== false && /* @__PURE__ */ jsxs("div", { className: "flex flex-shrink-0 flex-col border-b border-border bg-surface", children: [
|
|
6256
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 px-2 py-1.5", children: [
|
|
6257
|
+
tb.pager && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
6258
|
+
/* @__PURE__ */ jsx(IconButton_default, { type: "ghost", size: "sm", title: "Previous page", onClick: () => scrollToPage(page - 1), icon: /* @__PURE__ */ jsx(Chevron5, { dir: "up" }), disabled: !ready || page <= 1 }),
|
|
6259
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 text-xs text-foreground-secondary select-none", children: [
|
|
6260
|
+
/* @__PURE__ */ jsx(
|
|
6261
|
+
"input",
|
|
6262
|
+
{
|
|
6263
|
+
value: pageEditing.current ? pageDraft : ready ? String(page) : "\u2013",
|
|
6264
|
+
onFocus: () => {
|
|
6265
|
+
pageEditing.current = true;
|
|
6266
|
+
setPageDraft(String(page));
|
|
6267
|
+
},
|
|
6268
|
+
onChange: (e) => setPageDraft(e.target.value.replace(/[^\d]/g, "")),
|
|
6269
|
+
onBlur: commitPageDraft,
|
|
6270
|
+
onKeyDown: (e) => {
|
|
6271
|
+
if (e.key === "Enter") e.target.blur();
|
|
6272
|
+
},
|
|
6273
|
+
disabled: !ready,
|
|
6274
|
+
"aria-label": "Page number",
|
|
6275
|
+
className: "h-6 w-9 rounded border border-border bg-surface-raised text-center tabular-nums text-foreground outline-none focus:border-accent disabled:opacity-50"
|
|
6276
|
+
}
|
|
6277
|
+
),
|
|
6278
|
+
/* @__PURE__ */ jsxs("span", { className: "tabular-nums", children: [
|
|
6279
|
+
"/ ",
|
|
6280
|
+
numPages || "\u2013"
|
|
6281
|
+
] })
|
|
6282
|
+
] }),
|
|
6283
|
+
/* @__PURE__ */ jsx(IconButton_default, { type: "ghost", size: "sm", title: "Next page", onClick: () => scrollToPage(page + 1), icon: /* @__PURE__ */ jsx(Chevron5, { dir: "down" }), disabled: !ready || page >= numPages })
|
|
6155
6284
|
] }),
|
|
6156
|
-
/* @__PURE__ */ jsx(
|
|
6157
|
-
|
|
6158
|
-
|
|
6159
|
-
|
|
6160
|
-
|
|
6161
|
-
|
|
6162
|
-
|
|
6163
|
-
|
|
6164
|
-
|
|
6165
|
-
|
|
6166
|
-
|
|
6167
|
-
|
|
6285
|
+
tb.pager && tb.zoom && /* @__PURE__ */ jsx("span", { className: "mx-1 h-5 w-px bg-border", "aria-hidden": "true" }),
|
|
6286
|
+
tb.zoom && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
6287
|
+
/* @__PURE__ */ jsx(IconButton_default, { type: "ghost", size: "sm", title: "Zoom out", onClick: () => setZoomNum(1 / 1.2), icon: /* @__PURE__ */ jsx(MinusIcon, {}), disabled: !ready }),
|
|
6288
|
+
/* @__PURE__ */ jsx("span", { className: "w-10 text-center text-xs tabular-nums text-foreground-secondary select-none", children: ready ? `${zoomPct}%` : "\u2013" }),
|
|
6289
|
+
/* @__PURE__ */ jsx(IconButton_default, { type: "ghost", size: "sm", title: "Zoom in", onClick: () => setZoomNum(1.2), icon: /* @__PURE__ */ jsx(PlusIcon, {}), disabled: !ready }),
|
|
6290
|
+
/* @__PURE__ */ jsx(IconButton_default, { type: "ghost", size: "sm", title: "Fit width", onClick: () => setZoomMode("page-width"), icon: /* @__PURE__ */ jsx(FitWidthIcon, {}), disabled: !ready }),
|
|
6291
|
+
/* @__PURE__ */ jsx(IconButton_default, { type: "ghost", size: "sm", title: "Fit page", onClick: () => setZoomMode("page-fit"), icon: /* @__PURE__ */ jsx(FitPageIcon, {}), disabled: !ready })
|
|
6292
|
+
] }),
|
|
6293
|
+
/* @__PURE__ */ jsxs("div", { className: "ml-auto flex items-center gap-1", children: [
|
|
6294
|
+
tb.search && /* @__PURE__ */ jsx(IconButton_default, { type: showSearch ? "bordered" : "ghost", size: "sm", title: "Search", onClick: () => setShowSearch((s) => !s), icon: /* @__PURE__ */ jsx(SearchIcon2, {}), disabled: !ready }),
|
|
6295
|
+
tb.search && (tb.download || tb.print) && /* @__PURE__ */ jsx("span", { className: "mx-1 h-5 w-px bg-border", "aria-hidden": "true" }),
|
|
6296
|
+
tb.download && /* @__PURE__ */ jsx(IconButton_default, { type: "ghost", size: "sm", title: "Download", onClick: download, icon: /* @__PURE__ */ jsx(DownloadIcon, {}), disabled: !ready }),
|
|
6297
|
+
tb.print && /* @__PURE__ */ jsx(IconButton_default, { type: "ghost", size: "sm", title: "Print", onClick: print, icon: /* @__PURE__ */ jsx(PrintIcon, {}), disabled: !ready })
|
|
6298
|
+
] })
|
|
6168
6299
|
] }),
|
|
6169
|
-
tb.search && showSearch && /* @__PURE__ */ jsxs("div", { className: "flex
|
|
6300
|
+
tb.search && showSearch && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-t border-border px-2 py-1.5", children: [
|
|
6301
|
+
/* @__PURE__ */ jsx(SearchIcon2, {}),
|
|
6170
6302
|
/* @__PURE__ */ jsx(
|
|
6171
6303
|
"input",
|
|
6172
6304
|
{
|
|
6173
6305
|
autoFocus: true,
|
|
6174
6306
|
value: query,
|
|
6175
|
-
onChange: (e) =>
|
|
6307
|
+
onChange: (e) => onQueryChange(e.target.value),
|
|
6308
|
+
onKeyDown: (e) => {
|
|
6309
|
+
if (e.key === "Enter") gotoMatch(e.shiftKey ? -1 : 1);
|
|
6310
|
+
},
|
|
6176
6311
|
placeholder: "Find in document\u2026",
|
|
6177
|
-
className: "h-7 flex-1
|
|
6312
|
+
className: "h-7 flex-1 bg-transparent text-sm text-foreground outline-none placeholder:text-foreground-muted"
|
|
6178
6313
|
}
|
|
6179
6314
|
),
|
|
6180
|
-
/* @__PURE__ */ jsx("span", { className: "text-xs tabular-nums text-foreground-muted", children: matchPages == null ? "" : matchPages.length ? `${matchIdx + 1}
|
|
6315
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs tabular-nums text-foreground-muted", children: searching ? "Searching\u2026" : matchPages == null ? "" : matchPages.length ? `${matchIdx + 1} of ${matchPages.length}` : "No matches" }),
|
|
6181
6316
|
/* @__PURE__ */ jsx(IconButton_default, { type: "ghost", size: "sm", title: "Previous match", onClick: () => gotoMatch(-1), icon: /* @__PURE__ */ jsx(Chevron5, { dir: "up" }), disabled: !matchPages?.length }),
|
|
6182
|
-
/* @__PURE__ */ jsx(IconButton_default, { type: "ghost", size: "sm", title: "Next match", onClick: () => gotoMatch(1), icon: /* @__PURE__ */ jsx(Chevron5, { dir: "down" }), disabled: !matchPages?.length })
|
|
6317
|
+
/* @__PURE__ */ jsx(IconButton_default, { type: "ghost", size: "sm", title: "Next match", onClick: () => gotoMatch(1), icon: /* @__PURE__ */ jsx(Chevron5, { dir: "down" }), disabled: !matchPages?.length }),
|
|
6318
|
+
/* @__PURE__ */ jsx(IconButton_default, { type: "ghost", size: "sm", title: "Close search", onClick: () => {
|
|
6319
|
+
setShowSearch(false);
|
|
6320
|
+
onQueryChange("");
|
|
6321
|
+
}, icon: /* @__PURE__ */ jsx(CloseIcon, {}) })
|
|
6183
6322
|
] })
|
|
6184
6323
|
] }),
|
|
6185
6324
|
/* @__PURE__ */ jsxs("div", { className: "flex min-h-0 flex-1", children: [
|
|
6186
|
-
thumbnails &&
|
|
6187
|
-
|
|
6188
|
-
|
|
6189
|
-
|
|
6190
|
-
|
|
6191
|
-
|
|
6192
|
-
|
|
6193
|
-
|
|
6194
|
-
|
|
6195
|
-
|
|
6196
|
-
|
|
6197
|
-
|
|
6198
|
-
|
|
6199
|
-
|
|
6200
|
-
|
|
6325
|
+
thumbnails && ready && doc && baseSize && /* @__PURE__ */ jsx("div", { className: "w-32 flex-shrink-0 overflow-y-auto border-r border-border bg-surface p-2", children: Array.from({ length: numPages }, (_, i) => i + 1).map((p) => {
|
|
6326
|
+
const s = sizes[p - 1] ?? baseSize;
|
|
6327
|
+
return /* @__PURE__ */ jsx(
|
|
6328
|
+
"button",
|
|
6329
|
+
{
|
|
6330
|
+
type: "button",
|
|
6331
|
+
onClick: () => scrollToPage(p),
|
|
6332
|
+
className: cx(
|
|
6333
|
+
"mb-2 block w-full overflow-hidden rounded border bg-surface-raised transition-colors",
|
|
6334
|
+
p === page ? "border-accent ring-1 ring-accent" : "border-border hover:border-border-strong"
|
|
6335
|
+
),
|
|
6336
|
+
style: { aspectRatio: `${s.width} / ${s.height}` },
|
|
6337
|
+
"aria-label": `Page ${p}`,
|
|
6338
|
+
"aria-current": p === page,
|
|
6339
|
+
children: Math.abs(p - page) <= 8 ? /* @__PURE__ */ jsx(PdfPage, { pdfjs, doc, page: p, scale: 112 / s.width, textLayer: false }) : /* @__PURE__ */ jsx("span", { className: "block py-4 text-center text-xs text-foreground-muted", children: p })
|
|
6340
|
+
},
|
|
6341
|
+
p
|
|
6342
|
+
);
|
|
6343
|
+
}) }),
|
|
6201
6344
|
/* @__PURE__ */ jsx(
|
|
6202
6345
|
"div",
|
|
6203
6346
|
{
|
|
6204
6347
|
ref: scrollRef,
|
|
6205
6348
|
onScroll: (e) => setScrollTop(e.currentTarget.scrollTop),
|
|
6206
6349
|
className: "relative flex-1 overflow-auto bg-background",
|
|
6207
|
-
children:
|
|
6208
|
-
|
|
6209
|
-
|
|
6210
|
-
|
|
6211
|
-
|
|
6212
|
-
|
|
6213
|
-
|
|
6214
|
-
|
|
6350
|
+
children: !ready || !baseSize ? /* @__PURE__ */ jsx("div", { className: "flex flex-col items-center gap-3 p-6", children: /* @__PURE__ */ jsx(SkeletonBox, { width: Math.min((viewport.w || 528) - 48, 560), height: 680, className: "rounded" }) }) : numPages === 0 ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center text-sm text-foreground-muted", children: "Empty document" }) : /* @__PURE__ */ jsx("div", { style: { height: total, position: "relative" }, children: visiblePages.map((p) => {
|
|
6351
|
+
const s = sizes[p - 1] ?? baseSize;
|
|
6352
|
+
return /* @__PURE__ */ jsx(
|
|
6353
|
+
"div",
|
|
6354
|
+
{
|
|
6355
|
+
style: { position: "absolute", top: offsets[p - 1], left: 0, right: 0, display: "flex", justifyContent: "center", paddingTop: GAP / 2 },
|
|
6356
|
+
children: /* @__PURE__ */ jsx("div", { className: "relative shadow-md", style: { width: s.width * scale, height: s.height * scale }, children: /* @__PURE__ */ jsx(PdfPage, { pdfjs, doc, page: p, scale, textLayer, onMeasure: handleMeasure }) })
|
|
6357
|
+
},
|
|
6358
|
+
p
|
|
6359
|
+
);
|
|
6360
|
+
}) })
|
|
6215
6361
|
}
|
|
6216
6362
|
)
|
|
6217
6363
|
] })
|
|
6218
6364
|
] });
|
|
6219
6365
|
}
|
|
6220
|
-
function PdfPage({
|
|
6366
|
+
function PdfPage({
|
|
6367
|
+
pdfjs,
|
|
6368
|
+
doc,
|
|
6369
|
+
page,
|
|
6370
|
+
scale,
|
|
6371
|
+
textLayer,
|
|
6372
|
+
onMeasure
|
|
6373
|
+
}) {
|
|
6221
6374
|
const canvasRef = useRef(null);
|
|
6222
6375
|
const textRef = useRef(null);
|
|
6223
6376
|
useEffect(() => {
|
|
@@ -6227,6 +6380,7 @@ function PdfPage({ pdfjs, doc, page, scale, textLayer }) {
|
|
|
6227
6380
|
const pg = await doc.getPage(page);
|
|
6228
6381
|
if (cancelled) return;
|
|
6229
6382
|
const viewport = pg.getViewport({ scale });
|
|
6383
|
+
onMeasure?.(page, { width: viewport.width / scale, height: viewport.height / scale });
|
|
6230
6384
|
const canvas = canvasRef.current;
|
|
6231
6385
|
if (!canvas) return;
|
|
6232
6386
|
const ratio = typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1;
|
|
@@ -6243,6 +6397,7 @@ function PdfPage({ pdfjs, doc, page, scale, textLayer }) {
|
|
|
6243
6397
|
}
|
|
6244
6398
|
if (cancelled || !textLayer || !textRef.current || !pdfjs?.TextLayer) return;
|
|
6245
6399
|
try {
|
|
6400
|
+
ensureTextLayerStyles();
|
|
6246
6401
|
textRef.current.innerHTML = "";
|
|
6247
6402
|
textRef.current.style.setProperty("--scale-factor", String(scale));
|
|
6248
6403
|
const tl = new pdfjs.TextLayer({ textContentSource: pg.streamTextContent(), container: textRef.current, viewport });
|
|
@@ -6254,17 +6409,20 @@ function PdfPage({ pdfjs, doc, page, scale, textLayer }) {
|
|
|
6254
6409
|
cancelled = true;
|
|
6255
6410
|
renderTask?.cancel?.();
|
|
6256
6411
|
};
|
|
6257
|
-
}, [pdfjs, doc, page, scale, textLayer]);
|
|
6412
|
+
}, [pdfjs, doc, page, scale, textLayer, onMeasure]);
|
|
6258
6413
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
6259
6414
|
/* @__PURE__ */ jsx("canvas", { ref: canvasRef, className: "block bg-white" }),
|
|
6260
|
-
textLayer && /* @__PURE__ */ jsx("div", { ref: textRef, className: "textLayer
|
|
6415
|
+
textLayer && /* @__PURE__ */ jsx("div", { ref: textRef, className: "oxy-textLayer", "aria-hidden": "true" })
|
|
6261
6416
|
] });
|
|
6262
6417
|
}
|
|
6263
6418
|
var Chevron5 = ({ dir }) => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: dir === "up" ? "m6 15 6-6 6 6" : "m6 9 6 6 6-6" }) });
|
|
6264
|
-
var
|
|
6419
|
+
var MinusIcon = () => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", d: "M5 12h14" }) });
|
|
6420
|
+
var PlusIcon = () => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", d: "M12 5v14M5 12h14" }) });
|
|
6421
|
+
var SearchIcon2 = () => /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4 text-foreground-muted", "aria-hidden": "true", children: [
|
|
6265
6422
|
/* @__PURE__ */ jsx("circle", { cx: "11", cy: "11", r: "7" }),
|
|
6266
6423
|
/* @__PURE__ */ jsx("path", { strokeLinecap: "round", d: "m21 21-4.3-4.3" })
|
|
6267
6424
|
] });
|
|
6425
|
+
var CloseIcon = () => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", d: "M6 6l12 12M18 6 6 18" }) });
|
|
6268
6426
|
var DownloadIcon = () => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 3v12m0 0 4-4m-4 4-4-4M4 21h16" }) });
|
|
6269
6427
|
var PrintIcon = () => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 9V3h12v6M6 18H4v-7h16v7h-2M8 14h8v7H8z" }) });
|
|
6270
6428
|
var FitWidthIcon = () => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 12h18m0 0-4-4m4 4-4 4M3 12l4-4m-4 4 4 4" }) });
|
|
@@ -6274,11 +6432,20 @@ var FitPageIcon = () => /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", fill
|
|
|
6274
6432
|
] });
|
|
6275
6433
|
var DEFAULT_COL_WIDTH = 140;
|
|
6276
6434
|
var GUTTER = 52;
|
|
6435
|
+
var END_PAD = 12;
|
|
6436
|
+
function compareValues2(a, b) {
|
|
6437
|
+
if (a == null && b == null) return 0;
|
|
6438
|
+
if (a == null) return 1;
|
|
6439
|
+
if (b == null) return -1;
|
|
6440
|
+
if (typeof a === "number" && typeof b === "number") return a - b;
|
|
6441
|
+
if (typeof a === "boolean" && typeof b === "boolean") return a === b ? 0 : a ? 1 : -1;
|
|
6442
|
+
return String(a).localeCompare(String(b), void 0, { numeric: true, sensitivity: "base" });
|
|
6443
|
+
}
|
|
6277
6444
|
function resolveWidth(w) {
|
|
6278
|
-
if (typeof w === "number") return w;
|
|
6445
|
+
if (typeof w === "number" && Number.isFinite(w)) return w;
|
|
6279
6446
|
if (typeof w === "string") {
|
|
6280
|
-
const
|
|
6281
|
-
if (
|
|
6447
|
+
const m = /^\s*(\d+(?:\.\d+)?)(px)?\s*$/.exec(w);
|
|
6448
|
+
if (m) return parseFloat(m[1]);
|
|
6282
6449
|
}
|
|
6283
6450
|
return DEFAULT_COL_WIDTH;
|
|
6284
6451
|
}
|
|
@@ -6292,7 +6459,11 @@ function DataGrid({
|
|
|
6292
6459
|
rowHeight = 34,
|
|
6293
6460
|
headerHeight = 38,
|
|
6294
6461
|
height = 480,
|
|
6462
|
+
width,
|
|
6295
6463
|
editable = false,
|
|
6464
|
+
sortable = false,
|
|
6465
|
+
sort: sortProp,
|
|
6466
|
+
onSortChange,
|
|
6296
6467
|
virtualize = true,
|
|
6297
6468
|
overscan = 4,
|
|
6298
6469
|
rowNumbers = true,
|
|
@@ -6306,7 +6477,10 @@ function DataGrid({
|
|
|
6306
6477
|
const [viewport, setViewport] = useState({ w: 0, h: 0 });
|
|
6307
6478
|
const [editing, setEditing] = useState(null);
|
|
6308
6479
|
const [draft, setDraft] = useState("");
|
|
6480
|
+
const [internalSort, setInternalSort] = useState(null);
|
|
6481
|
+
const sort = sortProp !== void 0 ? sortProp : internalSort;
|
|
6309
6482
|
const gutter = rowNumbers ? GUTTER : 0;
|
|
6483
|
+
const colSortable = (c) => c.sortable ?? sortable;
|
|
6310
6484
|
const { widths, offsets, totalWidth } = useMemo(() => {
|
|
6311
6485
|
const widths2 = columns.map((c) => resolveWidth(c.width));
|
|
6312
6486
|
const offsets2 = [];
|
|
@@ -6317,6 +6491,18 @@ function DataGrid({
|
|
|
6317
6491
|
}
|
|
6318
6492
|
return { widths: widths2, offsets: offsets2, totalWidth: acc };
|
|
6319
6493
|
}, [columns]);
|
|
6494
|
+
const order = useMemo(() => {
|
|
6495
|
+
const idx = rows.map((_, i) => i);
|
|
6496
|
+
if (!sort) return idx;
|
|
6497
|
+
const dir = sort.dir === "asc" ? 1 : -1;
|
|
6498
|
+
return idx.sort((ia, ib) => dir * compareValues2(rows[ia]?.[sort.key] ?? null, rows[ib]?.[sort.key] ?? null));
|
|
6499
|
+
}, [rows, sort]);
|
|
6500
|
+
const toggleSort = (key) => {
|
|
6501
|
+
const nextDir = sort?.key !== key ? "asc" : sort.dir === "asc" ? "desc" : null;
|
|
6502
|
+
const next = nextDir ? { key, dir: nextDir } : null;
|
|
6503
|
+
if (sortProp === void 0) setInternalSort(next);
|
|
6504
|
+
onSortChange?.(next);
|
|
6505
|
+
};
|
|
6320
6506
|
const totalHeight = rows.length * rowHeight;
|
|
6321
6507
|
useEffect(() => {
|
|
6322
6508
|
const el = scrollRef.current;
|
|
@@ -6347,14 +6533,14 @@ function DataGrid({
|
|
|
6347
6533
|
const commit = useCallback(() => {
|
|
6348
6534
|
if (!editing) return;
|
|
6349
6535
|
const col = columns[editing.col];
|
|
6350
|
-
onCellEdit?.({ row: editing.
|
|
6536
|
+
onCellEdit?.({ row: order[editing.disp], column: col.key, value: draft });
|
|
6351
6537
|
setEditing(null);
|
|
6352
|
-
}, [editing, columns, draft, onCellEdit]);
|
|
6353
|
-
const startEdit = (
|
|
6538
|
+
}, [editing, columns, draft, onCellEdit, order]);
|
|
6539
|
+
const startEdit = (disp, col) => {
|
|
6354
6540
|
const c = columns[col];
|
|
6355
6541
|
if (!(c.editable ?? editable)) return;
|
|
6356
|
-
setDraft(displayValue(rows[
|
|
6357
|
-
setEditing({
|
|
6542
|
+
setDraft(displayValue(rows[order[disp]]?.[c.key] ?? ""));
|
|
6543
|
+
setEditing({ disp, col });
|
|
6358
6544
|
};
|
|
6359
6545
|
return /* @__PURE__ */ jsxs(
|
|
6360
6546
|
"div",
|
|
@@ -6362,12 +6548,12 @@ function DataGrid({
|
|
|
6362
6548
|
ref: scrollRef,
|
|
6363
6549
|
onScroll: (e) => setScroll({ top: e.currentTarget.scrollTop, left: e.currentTarget.scrollLeft }),
|
|
6364
6550
|
className: cx("relative overflow-auto rounded-lg border border-border bg-surface-raised text-sm", className),
|
|
6365
|
-
style: { height, ...style },
|
|
6551
|
+
style: { height, width, ...style },
|
|
6366
6552
|
role: "grid",
|
|
6367
6553
|
"aria-rowcount": rows.length,
|
|
6368
6554
|
"aria-colcount": columns.length,
|
|
6369
6555
|
children: [
|
|
6370
|
-
/* @__PURE__ */ jsxs("div", { style: { position: "relative", width: gutter + totalWidth, height: headerHeight + totalHeight }, children: [
|
|
6556
|
+
/* @__PURE__ */ jsxs("div", { style: { position: "relative", width: gutter + totalWidth + END_PAD, height: headerHeight + totalHeight + END_PAD }, children: [
|
|
6371
6557
|
rowNumbers && /* @__PURE__ */ jsx(
|
|
6372
6558
|
"div",
|
|
6373
6559
|
{
|
|
@@ -6377,11 +6563,18 @@ function DataGrid({
|
|
|
6377
6563
|
),
|
|
6378
6564
|
visibleCols.map((ci) => {
|
|
6379
6565
|
const c = columns[ci];
|
|
6380
|
-
|
|
6566
|
+
const sortDir = sort?.key === c.key ? sort.dir : null;
|
|
6567
|
+
const canSort = colSortable(c);
|
|
6568
|
+
return /* @__PURE__ */ jsxs(
|
|
6381
6569
|
"div",
|
|
6382
6570
|
{
|
|
6383
6571
|
role: "columnheader",
|
|
6384
|
-
|
|
6572
|
+
"aria-sort": sortDir ? sortDir === "asc" ? "ascending" : "descending" : void 0,
|
|
6573
|
+
onClick: canSort ? () => toggleSort(c.key) : void 0,
|
|
6574
|
+
className: cx(
|
|
6575
|
+
"flex items-center gap-1 border-b border-r border-border bg-surface px-3 font-medium text-foreground-secondary",
|
|
6576
|
+
canSort && "cursor-pointer select-none hover:text-foreground"
|
|
6577
|
+
),
|
|
6385
6578
|
style: {
|
|
6386
6579
|
position: "absolute",
|
|
6387
6580
|
top: scroll.top,
|
|
@@ -6391,38 +6584,42 @@ function DataGrid({
|
|
|
6391
6584
|
zIndex: 2,
|
|
6392
6585
|
justifyContent: c.align === "right" ? "flex-end" : c.align === "center" ? "center" : "flex-start"
|
|
6393
6586
|
},
|
|
6394
|
-
children:
|
|
6587
|
+
children: [
|
|
6588
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: c.label ?? c.key }),
|
|
6589
|
+
canSort && /* @__PURE__ */ jsx(SortCaret, { dir: sortDir })
|
|
6590
|
+
]
|
|
6395
6591
|
},
|
|
6396
6592
|
`h-${c.key}`
|
|
6397
6593
|
);
|
|
6398
6594
|
}),
|
|
6399
|
-
rowNumbers && visibleRows.map((
|
|
6595
|
+
rowNumbers && visibleRows.map((disp) => /* @__PURE__ */ jsx(
|
|
6400
6596
|
"div",
|
|
6401
6597
|
{
|
|
6402
6598
|
className: "flex items-center justify-center border-b border-r border-border bg-surface text-xs tabular-nums text-foreground-muted",
|
|
6403
|
-
style: { position: "absolute", left: scroll.left, top: headerHeight +
|
|
6404
|
-
children:
|
|
6599
|
+
style: { position: "absolute", left: scroll.left, top: headerHeight + disp * rowHeight, width: gutter, height: rowHeight, zIndex: 1 },
|
|
6600
|
+
children: disp + 1
|
|
6405
6601
|
},
|
|
6406
|
-
`g-${
|
|
6602
|
+
`g-${disp}`
|
|
6407
6603
|
)),
|
|
6408
|
-
visibleRows.map(
|
|
6409
|
-
|
|
6604
|
+
visibleRows.map((disp) => {
|
|
6605
|
+
const ri = order[disp];
|
|
6606
|
+
return visibleCols.map((ci) => {
|
|
6410
6607
|
const c = columns[ci];
|
|
6411
|
-
const isEditing = editing?.
|
|
6608
|
+
const isEditing = editing?.disp === disp && editing?.col === ci;
|
|
6412
6609
|
const canEdit = c.editable ?? editable;
|
|
6413
6610
|
return /* @__PURE__ */ jsx(
|
|
6414
6611
|
"div",
|
|
6415
6612
|
{
|
|
6416
6613
|
role: "gridcell",
|
|
6417
|
-
onDoubleClick: () => startEdit(
|
|
6614
|
+
onDoubleClick: () => startEdit(disp, ci),
|
|
6418
6615
|
className: cx(
|
|
6419
6616
|
"flex items-center border-b border-r border-border px-3",
|
|
6420
|
-
|
|
6617
|
+
disp % 2 ? "bg-surface-raised" : "bg-surface",
|
|
6421
6618
|
canEdit && "cursor-text"
|
|
6422
6619
|
),
|
|
6423
6620
|
style: {
|
|
6424
6621
|
position: "absolute",
|
|
6425
|
-
top: headerHeight +
|
|
6622
|
+
top: headerHeight + disp * rowHeight,
|
|
6426
6623
|
left: gutter + offsets[ci],
|
|
6427
6624
|
width: widths[ci],
|
|
6428
6625
|
height: rowHeight,
|
|
@@ -6443,16 +6640,22 @@ function DataGrid({
|
|
|
6443
6640
|
}
|
|
6444
6641
|
) : /* @__PURE__ */ jsx("span", { className: "truncate text-foreground", children: displayValue(rows[ri]?.[c.key] ?? "") })
|
|
6445
6642
|
},
|
|
6446
|
-
`${
|
|
6643
|
+
`${disp}-${c.key}`
|
|
6447
6644
|
);
|
|
6448
|
-
})
|
|
6449
|
-
)
|
|
6645
|
+
});
|
|
6646
|
+
})
|
|
6450
6647
|
] }),
|
|
6451
6648
|
rows.length === 0 && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center text-foreground-muted", style: { top: headerHeight }, children: emptyState })
|
|
6452
6649
|
]
|
|
6453
6650
|
}
|
|
6454
6651
|
);
|
|
6455
6652
|
}
|
|
6653
|
+
function SortCaret({ dir }) {
|
|
6654
|
+
return /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 16 16", className: "h-3 w-3 flex-shrink-0", fill: "none", stroke: "currentColor", strokeWidth: 1.75, "aria-hidden": "true", children: [
|
|
6655
|
+
/* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 6.5 8 3.5l3 3", className: dir === "asc" ? "text-accent" : "text-foreground-muted opacity-50" }),
|
|
6656
|
+
/* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 9.5 8 12.5l3-3", className: dir === "desc" ? "text-accent" : "text-foreground-muted opacity-50" })
|
|
6657
|
+
] });
|
|
6658
|
+
}
|
|
6456
6659
|
function toColumns(cols) {
|
|
6457
6660
|
return cols.map((c) => typeof c === "string" ? { key: c, label: c } : { ...c, label: c.label ?? c.key });
|
|
6458
6661
|
}
|
|
@@ -6471,13 +6674,16 @@ var xlsxPromise = null;
|
|
|
6471
6674
|
var loadXlsx = () => xlsxPromise ??= import('xlsx');
|
|
6472
6675
|
var jspdfPromise = null;
|
|
6473
6676
|
var loadJspdf = () => jspdfPromise ??= import('jspdf');
|
|
6474
|
-
function
|
|
6475
|
-
|
|
6476
|
-
|
|
6477
|
-
|
|
6478
|
-
|
|
6479
|
-
|
|
6480
|
-
|
|
6677
|
+
function coerceToCellType(prev, next) {
|
|
6678
|
+
if (typeof prev === "number") {
|
|
6679
|
+
const n = Number(next);
|
|
6680
|
+
return next.trim() !== "" && Number.isFinite(n) ? n : next;
|
|
6681
|
+
}
|
|
6682
|
+
if (typeof prev === "boolean") {
|
|
6683
|
+
if (/^(true|false)$/i.test(next.trim())) return next.trim().toLowerCase() === "true";
|
|
6684
|
+
return next;
|
|
6685
|
+
}
|
|
6686
|
+
return next;
|
|
6481
6687
|
}
|
|
6482
6688
|
function Spreadsheet({
|
|
6483
6689
|
source,
|
|
@@ -6488,6 +6694,9 @@ function Spreadsheet({
|
|
|
6488
6694
|
export: exportFormats = ["xlsx", "csv", "pdf"],
|
|
6489
6695
|
fileName,
|
|
6490
6696
|
virtualize = true,
|
|
6697
|
+
sortable = true,
|
|
6698
|
+
height = 480,
|
|
6699
|
+
width,
|
|
6491
6700
|
className = "",
|
|
6492
6701
|
style
|
|
6493
6702
|
}) {
|
|
@@ -6545,20 +6754,23 @@ function Spreadsheet({
|
|
|
6545
6754
|
const columns = useMemo(() => sheet ? toColumns(sheet.columns) : [], [sheet]);
|
|
6546
6755
|
const plainRows = useMemo(() => sheet ? toPlainRows(sheet, columns) : [], [sheet, columns]);
|
|
6547
6756
|
const handleCellEdit = useCallback(({ row, column, value }) => {
|
|
6757
|
+
let coerced = value;
|
|
6548
6758
|
setSheets((prev) => {
|
|
6549
6759
|
if (!prev) return prev;
|
|
6550
6760
|
const next = prev.map((s, i) => i === active ? { ...s, rows: s.rows.map((r) => ({ ...r })) } : s);
|
|
6551
6761
|
const target = next[active];
|
|
6552
6762
|
const existing = target.rows[row]?.[column];
|
|
6763
|
+
const prevValue = cellValue(existing);
|
|
6764
|
+
coerced = coerceToCellType(prevValue, value);
|
|
6553
6765
|
if (existing != null && typeof existing === "object" && "value" in existing) {
|
|
6554
|
-
target.rows[row][column] = { ...existing, value };
|
|
6766
|
+
target.rows[row][column] = { ...existing, value: coerced };
|
|
6555
6767
|
} else {
|
|
6556
|
-
target.rows[row][column] =
|
|
6768
|
+
target.rows[row][column] = coerced;
|
|
6557
6769
|
}
|
|
6558
6770
|
onChange?.(next);
|
|
6559
6771
|
return next;
|
|
6560
6772
|
});
|
|
6561
|
-
onCellEdit?.({ sheet: sheets?.[active]?.name ?? "", row, column, value });
|
|
6773
|
+
onCellEdit?.({ sheet: sheets?.[active]?.name ?? "", row, column, value: coerced });
|
|
6562
6774
|
}, [active, onCellEdit, onChange, sheets]);
|
|
6563
6775
|
const baseName = useMemo(
|
|
6564
6776
|
() => (fileName || (typeof source === "object" && "name" in source ? sourceName(source) : null) || "spreadsheet").replace(/\.[^.]+$/, ""),
|
|
@@ -6579,7 +6791,7 @@ function Spreadsheet({
|
|
|
6579
6791
|
XLSX.utils.book_append_sheet(wb, ws, (s.name || "Sheet").slice(0, 31));
|
|
6580
6792
|
});
|
|
6581
6793
|
const out = XLSX.write(wb, { bookType: "xlsx", type: "array" });
|
|
6582
|
-
|
|
6794
|
+
downloadBlob(new Blob([out], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }), `${baseName}.xlsx`);
|
|
6583
6795
|
}, [sheets, sheetAoa, baseName]);
|
|
6584
6796
|
const exportCsv = useCallback(() => {
|
|
6585
6797
|
if (!sheet) return;
|
|
@@ -6589,7 +6801,7 @@ function Spreadsheet({
|
|
|
6589
6801
|
return /[",\n]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
|
|
6590
6802
|
};
|
|
6591
6803
|
const csv = aoa.map((row) => row.map(esc).join(",")).join("\r\n");
|
|
6592
|
-
|
|
6804
|
+
downloadBlob(new Blob([`\uFEFF${csv}`], { type: "text/csv;charset=utf-8" }), `${baseName}.csv`);
|
|
6593
6805
|
}, [sheet, sheetAoa, baseName]);
|
|
6594
6806
|
const exportPdf = useCallback(async () => {
|
|
6595
6807
|
if (!sheet) return;
|
|
@@ -6632,50 +6844,87 @@ function Spreadsheet({
|
|
|
6632
6844
|
else void exportPdf();
|
|
6633
6845
|
};
|
|
6634
6846
|
if (status === "error") {
|
|
6635
|
-
return /* @__PURE__ */ jsxs("div", { className: cx("flex flex-col items-center justify-center gap-3 rounded-lg border border-border bg-surface p-8 text-center", className), style, children: [
|
|
6847
|
+
return /* @__PURE__ */ jsxs("div", { className: cx("flex flex-col items-center justify-center gap-3 rounded-lg border border-border bg-surface p-8 text-center", className), style: { height, width, ...style }, children: [
|
|
6636
6848
|
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-status-error", children: "Couldn\u2019t load the spreadsheet" }),
|
|
6637
6849
|
error?.message && /* @__PURE__ */ jsx("p", { className: "max-w-md text-xs text-foreground-muted", children: error.message }),
|
|
6638
6850
|
/* @__PURE__ */ jsx(Button_default, { content: "Retry", size: "sm", variant: "outline", onClick: () => setReloadKey((k) => k + 1) })
|
|
6639
6851
|
] });
|
|
6640
6852
|
}
|
|
6641
6853
|
if (status === "loading" || !sheets) {
|
|
6642
|
-
return /* @__PURE__ */ jsxs("div", { className: cx("rounded-lg border border-border bg-surface-raised p-4", className), style, children: [
|
|
6854
|
+
return /* @__PURE__ */ jsxs("div", { className: cx("overflow-hidden rounded-lg border border-border bg-surface-raised p-4", className), style: { height, width, ...style }, children: [
|
|
6643
6855
|
/* @__PURE__ */ jsx(SkeletonBox, { height: 32, className: "mb-3 rounded" }),
|
|
6644
|
-
/* @__PURE__ */ jsx(SkeletonBox, { height:
|
|
6856
|
+
/* @__PURE__ */ jsx(SkeletonBox, { height: "calc(100% - 44px)", className: "rounded" })
|
|
6645
6857
|
] });
|
|
6646
6858
|
}
|
|
6647
6859
|
const formats = exportFormats || [];
|
|
6648
|
-
|
|
6649
|
-
|
|
6650
|
-
|
|
6651
|
-
|
|
6652
|
-
|
|
6653
|
-
|
|
6654
|
-
|
|
6655
|
-
|
|
6656
|
-
|
|
6657
|
-
|
|
6658
|
-
|
|
6659
|
-
|
|
6660
|
-
|
|
6661
|
-
|
|
6662
|
-
|
|
6663
|
-
|
|
6664
|
-
|
|
6665
|
-
|
|
6860
|
+
const exportLabels = {
|
|
6861
|
+
xlsx: "Excel workbook (.xlsx)",
|
|
6862
|
+
csv: "CSV \u2014 this sheet (.csv)",
|
|
6863
|
+
pdf: "PDF table (.pdf)"
|
|
6864
|
+
};
|
|
6865
|
+
return /* @__PURE__ */ jsxs("div", { className: cx("flex flex-col overflow-hidden rounded-lg border border-border bg-surface-raised", className), style: { height, width, ...style }, children: [
|
|
6866
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-shrink-0 items-center gap-2 border-b border-border bg-surface px-3 py-1.5", children: [
|
|
6867
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-sm font-semibold text-foreground", children: sheet?.name || "Sheet 1" }),
|
|
6868
|
+
/* @__PURE__ */ jsxs("span", { className: "hidden flex-shrink-0 text-xs tabular-nums text-foreground-muted sm:inline", children: [
|
|
6869
|
+
plainRows.length.toLocaleString(),
|
|
6870
|
+
" ",
|
|
6871
|
+
plainRows.length === 1 ? "row" : "rows",
|
|
6872
|
+
" \xB7 ",
|
|
6873
|
+
columns.length,
|
|
6874
|
+
" cols"
|
|
6875
|
+
] }),
|
|
6876
|
+
formats.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
6877
|
+
/* @__PURE__ */ jsx("span", { className: "h-5 w-px flex-shrink-0 bg-border", "aria-hidden": "true" }),
|
|
6878
|
+
/* @__PURE__ */ jsx(
|
|
6879
|
+
MenuButton,
|
|
6880
|
+
{
|
|
6881
|
+
label: "Export",
|
|
6882
|
+
size: "sm",
|
|
6883
|
+
variant: "outline",
|
|
6884
|
+
align: "end",
|
|
6885
|
+
icon: /* @__PURE__ */ jsx(DownloadIcon2, {}),
|
|
6886
|
+
items: formats.map((fmt) => ({
|
|
6887
|
+
key: fmt,
|
|
6888
|
+
label: exportLabels[fmt],
|
|
6889
|
+
onSelect: () => runExport(fmt)
|
|
6890
|
+
}))
|
|
6891
|
+
}
|
|
6892
|
+
)
|
|
6893
|
+
] })
|
|
6666
6894
|
] }),
|
|
6667
|
-
/* @__PURE__ */ jsx(
|
|
6895
|
+
/* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsx(
|
|
6668
6896
|
DataGrid,
|
|
6669
6897
|
{
|
|
6670
6898
|
columns,
|
|
6671
6899
|
rows: plainRows,
|
|
6672
6900
|
editable,
|
|
6901
|
+
sortable,
|
|
6673
6902
|
virtualize,
|
|
6674
|
-
onCellEdit: handleCellEdit
|
|
6675
|
-
|
|
6676
|
-
|
|
6903
|
+
onCellEdit: handleCellEdit,
|
|
6904
|
+
height: "100%",
|
|
6905
|
+
className: "!rounded-none !border-0"
|
|
6906
|
+
},
|
|
6907
|
+
active
|
|
6908
|
+
) }),
|
|
6909
|
+
sheets.length > 1 && /* @__PURE__ */ jsx("div", { role: "tablist", "aria-label": "Sheets", className: "flex flex-shrink-0 items-center gap-1 overflow-x-auto border-t border-border bg-surface px-2 py-1", children: sheets.map((s, i) => /* @__PURE__ */ jsx(
|
|
6910
|
+
"button",
|
|
6911
|
+
{
|
|
6912
|
+
role: "tab",
|
|
6913
|
+
type: "button",
|
|
6914
|
+
"aria-selected": i === active,
|
|
6915
|
+
onClick: () => setActive(i),
|
|
6916
|
+
className: cx(
|
|
6917
|
+
"flex-shrink-0 rounded-md px-3 py-1 text-xs font-medium transition-colors",
|
|
6918
|
+
"focus:outline-none focus-visible:ring-2 focus-visible:ring-accent",
|
|
6919
|
+
i === active ? "bg-surface-raised text-foreground shadow-sm" : "text-foreground-secondary hover:bg-surface-raised hover:text-foreground"
|
|
6920
|
+
),
|
|
6921
|
+
children: s.name || `Sheet ${i + 1}`
|
|
6922
|
+
},
|
|
6923
|
+
`${s.name}-${i}`
|
|
6924
|
+
)) })
|
|
6677
6925
|
] });
|
|
6678
6926
|
}
|
|
6927
|
+
var DownloadIcon2 = () => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 3v12m0 0 4-4m-4 4-4-4M4 21h16" }) });
|
|
6679
6928
|
function ThemeSwitch({ checked, onChange, label = "Toggle dark mode", className = "" }) {
|
|
6680
6929
|
const id = useId();
|
|
6681
6930
|
return /* @__PURE__ */ jsx("label", { htmlFor: id, className: `flex items-center gap-2 cursor-pointer select-none ${className}`.trim(), children: /* @__PURE__ */ jsx(
|
|
@@ -6776,7 +7025,7 @@ function FlyoutItems({ items }) {
|
|
|
6776
7025
|
}
|
|
6777
7026
|
function CollapsedFlyout({ item, trigger }) {
|
|
6778
7027
|
const [open, setOpen] = useState(false);
|
|
6779
|
-
const closeTimer =
|
|
7028
|
+
const closeTimer = React36.useRef(void 0);
|
|
6780
7029
|
const openNow = () => {
|
|
6781
7030
|
window.clearTimeout(closeTimer.current);
|
|
6782
7031
|
setOpen(true);
|
|
@@ -6785,7 +7034,7 @@ function CollapsedFlyout({ item, trigger }) {
|
|
|
6785
7034
|
window.clearTimeout(closeTimer.current);
|
|
6786
7035
|
closeTimer.current = window.setTimeout(() => setOpen(false), 150);
|
|
6787
7036
|
};
|
|
6788
|
-
|
|
7037
|
+
React36.useEffect(() => () => window.clearTimeout(closeTimer.current), []);
|
|
6789
7038
|
return /* @__PURE__ */ jsxs(DropdownMenu2.Root, { open, onOpenChange: setOpen, modal: false, children: [
|
|
6790
7039
|
/* @__PURE__ */ jsx(
|
|
6791
7040
|
DropdownMenu2.Trigger,
|
|
@@ -7077,8 +7326,8 @@ function MegaMenuLink({ href, icon, description, active, onClick, children, clas
|
|
|
7077
7326
|
function MegaMenuFeatured({ children, className = "" }) {
|
|
7078
7327
|
return /* @__PURE__ */ jsx("div", { className: cx("min-w-0 rounded-lg bg-surface-raised border border-border p-4 flex flex-col", className), children });
|
|
7079
7328
|
}
|
|
7080
|
-
var elementsOfType = (children, type) =>
|
|
7081
|
-
(c) =>
|
|
7329
|
+
var elementsOfType = (children, type) => React36.Children.toArray(children).filter(
|
|
7330
|
+
(c) => React36.isValidElement(c) && c.type === type
|
|
7082
7331
|
);
|
|
7083
7332
|
var MOBILE_CHEVRON = /* @__PURE__ */ jsx(
|
|
7084
7333
|
"svg",
|
|
@@ -7115,9 +7364,9 @@ function MobileLinkRow({ link, onNavigate }) {
|
|
|
7115
7364
|
);
|
|
7116
7365
|
}
|
|
7117
7366
|
function MobilePanel({ panel, onNavigate }) {
|
|
7118
|
-
const nodes =
|
|
7367
|
+
const nodes = React36.Children.toArray(panel.props.children);
|
|
7119
7368
|
return /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-4 px-2 pb-3 pt-1", children: nodes.map((node, i) => {
|
|
7120
|
-
if (!
|
|
7369
|
+
if (!React36.isValidElement(node)) return null;
|
|
7121
7370
|
const el = node;
|
|
7122
7371
|
if (el.type === MegaMenuSection) {
|
|
7123
7372
|
const { title, children } = el.props;
|
|
@@ -7526,7 +7775,7 @@ function ThemeProvider({
|
|
|
7526
7775
|
className = "",
|
|
7527
7776
|
style
|
|
7528
7777
|
}) {
|
|
7529
|
-
const id =
|
|
7778
|
+
const id = React36.useId().replace(/:/g, "");
|
|
7530
7779
|
const scopeClass = `geo-th-${id}`;
|
|
7531
7780
|
const divRef = useRef(null);
|
|
7532
7781
|
useEffect(() => {
|
|
@@ -8339,8 +8588,11 @@ function Dropdown({
|
|
|
8339
8588
|
labelStyle = {},
|
|
8340
8589
|
placeholder,
|
|
8341
8590
|
size = "md",
|
|
8342
|
-
className = ""
|
|
8591
|
+
className = "",
|
|
8592
|
+
container
|
|
8343
8593
|
}) {
|
|
8594
|
+
const dialogContainer = useDialogContainer();
|
|
8595
|
+
const portalContainer = container ?? dialogContainer ?? void 0;
|
|
8344
8596
|
const [open, setOpen] = useState(false);
|
|
8345
8597
|
const [selectedItems, setSelectedItems] = useState([]);
|
|
8346
8598
|
const [searchTerm, setSearchTerm] = useState("");
|
|
@@ -8446,7 +8698,7 @@ function Dropdown({
|
|
|
8446
8698
|
]
|
|
8447
8699
|
}
|
|
8448
8700
|
) }),
|
|
8449
|
-
/* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsxs(
|
|
8701
|
+
/* @__PURE__ */ jsx(Popover.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxs(
|
|
8450
8702
|
Popover.Content,
|
|
8451
8703
|
{
|
|
8452
8704
|
align: "start",
|
|
@@ -9834,7 +10086,7 @@ function OtpInput({
|
|
|
9834
10086
|
emit(valid.join(""));
|
|
9835
10087
|
focusBox(valid.length);
|
|
9836
10088
|
};
|
|
9837
|
-
return /* @__PURE__ */ jsx(Field, { className, label, htmlFor, errorId, errorMessage, required, layout, helperText, children: /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center gap-2", role: "group", "aria-label": typeof label === "string" ? label : "One-time code", children: chars.map((char, idx) => /* @__PURE__ */ jsxs(
|
|
10089
|
+
return /* @__PURE__ */ jsx(Field, { className, label, htmlFor, errorId, errorMessage, required, layout, helperText, children: /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center gap-2", role: "group", "aria-label": typeof label === "string" ? label : "One-time code", children: chars.map((char, idx) => /* @__PURE__ */ jsxs(React36.Fragment, { children: [
|
|
9838
10090
|
/* @__PURE__ */ jsx(
|
|
9839
10091
|
"input",
|
|
9840
10092
|
{
|
|
@@ -10893,7 +11145,7 @@ function Blog({
|
|
|
10893
11145
|
post.tag != null && !post.image && /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Badge, { tone: "accent", variant: "soft", size: "sm", children: post.tag }) }),
|
|
10894
11146
|
/* @__PURE__ */ jsx("h3", { className: "text-base font-semibold leading-snug text-foreground transition-colors group-hover:text-accent", children: post.title }),
|
|
10895
11147
|
post.excerpt != null && /* @__PURE__ */ jsx("p", { className: "line-clamp-3 text-sm leading-relaxed text-foreground-secondary", children: post.excerpt }),
|
|
10896
|
-
meta.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-auto flex flex-wrap items-center gap-x-2 gap-y-1 pt-3 text-xs text-foreground-muted", children: meta.map((m, j) => /* @__PURE__ */ jsxs(
|
|
11148
|
+
meta.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-auto flex flex-wrap items-center gap-x-2 gap-y-1 pt-3 text-xs text-foreground-muted", children: meta.map((m, j) => /* @__PURE__ */ jsxs(React36.Fragment, { children: [
|
|
10897
11149
|
j > 0 && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xB7" }),
|
|
10898
11150
|
/* @__PURE__ */ jsx("span", { children: m })
|
|
10899
11151
|
] }, j)) })
|