@windrun-huaiin/third-ui 7.1.0 → 7.1.2
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/fuma/mdx/mermaid.js +21 -1
- package/dist/fuma/mdx/mermaid.mjs +21 -1
- package/dist/main/x-button.js +1 -1
- package/dist/main/x-button.mjs +1 -1
- package/dist/node_modules/.pnpm/cose-base@1.0.3/node_modules/cose-base/cose-base.js +1 -1
- package/dist/node_modules/.pnpm/cose-base@2.2.0/node_modules/cose-base/cose-base.js +1 -1
- package/dist/node_modules/.pnpm/layout-base@1.0.2/node_modules/layout-base/layout-base.js +1 -1
- package/dist/node_modules/.pnpm/layout-base@2.0.1/node_modules/layout-base/layout-base.js +1 -1
- package/package.json +3 -3
- package/src/fuma/mdx/mermaid.tsx +36 -8
- package/src/fuma/mdx/toc-base.tsx +1 -1
- package/src/main/x-button.tsx +1 -1
package/dist/fuma/mdx/mermaid.js
CHANGED
|
@@ -9,6 +9,12 @@ var React = require('react');
|
|
|
9
9
|
|
|
10
10
|
function _interopNamespaceDefaultOnly (e) { return Object.freeze({ __proto__: null, default: e }); }
|
|
11
11
|
|
|
12
|
+
function sanitizeFilename(name) {
|
|
13
|
+
return name
|
|
14
|
+
.replace(/[\/:*?"<>|]/g, '_')
|
|
15
|
+
.replace(/\s+/g, '_')
|
|
16
|
+
.slice(0, 120);
|
|
17
|
+
}
|
|
12
18
|
function Mermaid({ chart, title, watermarkEnabled, watermarkText, enablePreview = true }) {
|
|
13
19
|
const id = React.useId();
|
|
14
20
|
const [svg, setSvg] = React.useState('');
|
|
@@ -95,6 +101,20 @@ function Mermaid({ chart, title, watermarkEnabled, watermarkText, enablePreview
|
|
|
95
101
|
isPanningRef.current = false;
|
|
96
102
|
e.currentTarget.releasePointerCapture(e.pointerId);
|
|
97
103
|
}, []);
|
|
104
|
+
const handleDownload = React.useCallback(() => {
|
|
105
|
+
if (!svg)
|
|
106
|
+
return;
|
|
107
|
+
const fileName = `${sanitizeFilename(title !== null && title !== void 0 ? title : 'mermaid')}.svg`;
|
|
108
|
+
const blob = new Blob([svg], { type: 'image/svg+xml;charset=utf-8' });
|
|
109
|
+
const url = URL.createObjectURL(blob);
|
|
110
|
+
const a = document.createElement('a');
|
|
111
|
+
a.href = url;
|
|
112
|
+
a.download = fileName;
|
|
113
|
+
document.body.appendChild(a);
|
|
114
|
+
a.click();
|
|
115
|
+
a.remove();
|
|
116
|
+
URL.revokeObjectURL(url);
|
|
117
|
+
}, [svg, title]);
|
|
98
118
|
// prevent browser-level zoom (touchpad pinch/shortcut) from taking effect when the dialog is open
|
|
99
119
|
React.useEffect(() => {
|
|
100
120
|
if (!open)
|
|
@@ -154,7 +174,7 @@ function Mermaid({ chart, title, watermarkEnabled, watermarkText, enablePreview
|
|
|
154
174
|
window.scrollTo(0, scrollY);
|
|
155
175
|
};
|
|
156
176
|
}, [open]);
|
|
157
|
-
return (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsxs("div", { className: enablePreview ? 'group relative cursor-zoom-in' : undefined, onClick: () => enablePreview && svg && setOpen(true), children: [jsxRuntime.jsx("div", { dangerouslySetInnerHTML: { __html: svg } }), enablePreview && svg && (jsxRuntime.jsx("div", { className: "pointer-events-none absolute right-2 top-2 hidden rounded bg-black/50 px-2 py-0.5 text-[12px] text-white group-hover:block", children: "Preview Chart" }))] }), title && (jsxRuntime.jsxs("div", { className: "mt-2 flex items-center justify-center text-center text-[13px] font-italic text-[#AC62FD]", children: [jsxRuntime.jsx(server.globalLucideIcons.Mmd, { className: 'mr-1 h-4 w-4' }), jsxRuntime.jsx("span", { children: title })] })), enablePreview && open && (jsxRuntime.jsxs("div", { role: "dialog", "aria-modal": "true", "aria-label": typeof title === 'string' ? title : 'Mermaid Preview', className: "fixed inset-0 z-[9999] flex items-center justify-center", children: [jsxRuntime.jsx("div", { className: "absolute inset-0 bg-black/60", onClick: () => { setOpen(false); resetTransform(); }, onWheel: (e) => { e.preventDefault(); e.stopPropagation(); }, onTouchMove: (e) => { e.preventDefault(); e.stopPropagation(); } }), jsxRuntime.jsxs("div", { className: "relative z-[1] max-w-[95vw] w-[95vw] h-[88vh] p-0 bg-white dark:bg-neutral-900 border border-neutral-200 dark:border-neutral-700 rounded-md shadow-2xl overflow-hidden", children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-3 py-2 border-b border-neutral-200 dark:border-neutral-700", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-sm text-neutral-600 dark:text-neutral-300", children: [jsxRuntime.jsx(server.globalLucideIcons.Mmd, { className: "h-4 w-4" }), jsxRuntime.jsx("span", { className: "truncate max-w-[50vw]", children: title !== null && title !== void 0 ? title : 'Mermaid Preview' })] }), jsxRuntime.jsxs("div", { className: "flex items-center gap-0.5", children: [jsxRuntime.jsx("button", { "aria-label": "Zoom out", className: "flex h-6 w-6 items-center justify-center rounded border border-neutral-300 dark:border-neutral-600 text-[13px]", onClick: () => zoomBy(-0.5), children: "\uFF0D" }), jsxRuntime.jsxs("span", { className: "mx-0.5 text-[12px] w-12 text-center select-none", children: [Math.round(scale * 100), "%"] }), jsxRuntime.jsx("button", { "aria-label": "Zoom in", className: "flex h-6 w-6 items-center justify-center rounded border border-neutral-300 dark:border-neutral-600 text-[13px]", onClick: () => zoomBy(0.5), children: "\uFF0B" }), jsxRuntime.jsx("div", { className: "mx-1 h-4 w-px bg-neutral-300 dark:bg-neutral-700" }), jsxRuntime.jsx("button", { "aria-label": "Zoom 100%", className: "inline-flex h-6 min-w-8 items-center justify-center rounded border border-neutral-300 dark:border-neutral-600 px-1.5 text-[12px]", onClick: () => setScale(1), children: "X1" }), jsxRuntime.jsx("button", { "aria-label": "Zoom 200%", className: "ml-1 inline-flex h-6 min-w-8 items-center justify-center rounded border border-neutral-300 dark:border-neutral-600 px-1.5 text-[12px]", onClick: () => setScale(2), children: "X2" }), jsxRuntime.jsx("button", { "aria-label": "Zoom 300%", className: "ml-1 inline-flex h-6 min-w-8 items-center justify-center rounded border border-neutral-300 dark:border-neutral-600 px-1.5 text-[12px]", onClick: () => setScale(3), children: "X3" }), jsxRuntime.jsx("button", { "aria-label": "Zoom 1000%", className: "ml-1 inline-flex h-6 min-w-10 items-center justify-center rounded border border-neutral-300 dark:border-neutral-600 px-1.5 text-[12px]", onClick: () => setScale(10), children: "X10" }), jsxRuntime.jsx("button", { "aria-label": "Reset", className: "ml-1 flex h-6 w-6 items-center justify-center rounded text-purple-500 hover:text-purple-600", onClick: resetTransform, children: jsxRuntime.jsx(server.globalLucideIcons.RefreshCcw, { className: "h-3.5 w-3.5" }) }), jsxRuntime.jsx("button", { "aria-label": "Close", className: "ml-1 flex h-6 w-6 items-center justify-center rounded text-purple-500 hover:text-purple-600", onClick: () => { setOpen(false); resetTransform(); }, children: jsxRuntime.jsx(server.globalLucideIcons.X, { className: "h-3.5 w-3.5" }) })] })] }), jsxRuntime.jsxs("div", { className: "relative h-[calc(88vh-40px)] w-full overflow-hidden bg-white dark:bg-neutral-900 touch-none overscroll-contain", onWheel: onWheel, onPointerDown: onPointerDown, onPointerMove: onPointerMove, onPointerUp: onPointerUp, children: [jsxRuntime.jsx("div", { className: "absolute left-1/2 top-1/2", style: { transform: `translate(-50%, -50%) translate(${translate.x}px, ${translate.y}px)` }, children: jsxRuntime.jsx("div", { style: { transform: `scale(${scale})`, transformOrigin: '50% 50%' }, dangerouslySetInnerHTML: { __html: svg } }) }), jsxRuntime.jsx("div", { className: "pointer-events-none absolute bottom-2 right-3 rounded bg-black/40 px-2 py-1 text-xs text-white", children: "Drag to pan, hold Cmd/Ctrl + scroll to zoom" })] })] })] }))] }));
|
|
177
|
+
return (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsxs("div", { className: enablePreview ? 'group relative cursor-zoom-in' : undefined, onClick: () => enablePreview && svg && setOpen(true), children: [jsxRuntime.jsx("div", { dangerouslySetInnerHTML: { __html: svg } }), enablePreview && svg && (jsxRuntime.jsx("div", { className: "pointer-events-none absolute right-2 top-2 hidden rounded bg-black/50 px-2 py-0.5 text-[12px] text-white group-hover:block", children: "Preview Chart" }))] }), title && (jsxRuntime.jsxs("div", { className: "mt-2 flex items-center justify-center text-center text-[13px] font-italic text-[#AC62FD]", children: [jsxRuntime.jsx(server.globalLucideIcons.Mmd, { className: 'mr-1 h-4 w-4' }), jsxRuntime.jsx("span", { children: title })] })), enablePreview && open && (jsxRuntime.jsxs("div", { role: "dialog", "aria-modal": "true", "aria-label": typeof title === 'string' ? title : 'Mermaid Preview', className: "fixed inset-0 z-[9999] flex items-center justify-center", children: [jsxRuntime.jsx("div", { className: "absolute inset-0 bg-black/60", onClick: () => { setOpen(false); resetTransform(); }, onWheel: (e) => { e.preventDefault(); e.stopPropagation(); }, onTouchMove: (e) => { e.preventDefault(); e.stopPropagation(); } }), jsxRuntime.jsxs("div", { className: "relative z-[1] max-w-[95vw] w-[95vw] h-[88vh] p-0 bg-white dark:bg-neutral-900 border border-neutral-200 dark:border-neutral-700 rounded-md shadow-2xl overflow-hidden", children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-3 py-2 border-b border-neutral-200 dark:border-neutral-700", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-sm text-neutral-600 dark:text-neutral-300", children: [jsxRuntime.jsx(server.globalLucideIcons.Mmd, { className: "h-4 w-4" }), jsxRuntime.jsx("span", { className: "truncate max-w-[50vw]", children: title !== null && title !== void 0 ? title : 'Mermaid Preview' })] }), jsxRuntime.jsxs("div", { className: "flex items-center gap-0.5", children: [jsxRuntime.jsx("button", { "aria-label": "Zoom out", className: "flex h-6 w-6 items-center justify-center rounded border border-neutral-300 dark:border-neutral-600 text-[13px] transition-colors hover:bg-neutral-100 active:bg-neutral-200 hover:border-neutral-400 active:border-neutral-500 dark:hover:bg-neutral-700 dark:active:bg-neutral-600 dark:hover:border-neutral-500 dark:active:border-neutral-400", onClick: () => zoomBy(-0.5), children: "\uFF0D" }), jsxRuntime.jsxs("span", { className: "mx-0.5 text-[12px] w-12 text-center select-none", children: [Math.round(scale * 100), "%"] }), jsxRuntime.jsx("button", { "aria-label": "Zoom in", className: "flex h-6 w-6 items-center justify-center rounded border border-neutral-300 dark:border-neutral-600 text-[13px] transition-colors hover:bg-neutral-100 active:bg-neutral-200 hover:border-neutral-400 active:border-neutral-500 dark:hover:bg-neutral-700 dark:active:bg-neutral-600 dark:hover:border-neutral-500 dark:active:border-neutral-400", onClick: () => zoomBy(0.5), children: "\uFF0B" }), jsxRuntime.jsx("div", { className: "mx-1 h-4 w-px bg-neutral-300 dark:bg-neutral-700" }), jsxRuntime.jsx("button", { "aria-label": "Zoom 100%", className: "inline-flex h-6 min-w-8 items-center justify-center rounded border border-neutral-300 dark:border-neutral-600 px-1.5 text-[12px] transition-colors hover:bg-neutral-100 active:bg-neutral-200 hover:border-neutral-400 active:border-neutral-500 dark:hover:bg-neutral-700 dark:active:bg-neutral-600 dark:hover:border-neutral-500 dark:active:border-neutral-400", onClick: () => setScale(1), children: "X1" }), jsxRuntime.jsx("button", { "aria-label": "Zoom 200%", className: "ml-1 inline-flex h-6 min-w-8 items-center justify-center rounded border border-neutral-300 dark:border-neutral-600 px-1.5 text-[12px] transition-colors hover:bg-neutral-100 active:bg-neutral-200 hover:border-neutral-400 active:border-neutral-500 dark:hover:bg-neutral-700 dark:active:bg-neutral-600 dark:hover:border-neutral-500 dark:active:border-neutral-400", onClick: () => setScale(2), children: "X2" }), jsxRuntime.jsx("button", { "aria-label": "Zoom 300%", className: "ml-1 inline-flex h-6 min-w-8 items-center justify-center rounded border border-neutral-300 dark:border-neutral-600 px-1.5 text-[12px] transition-colors hover:bg-neutral-100 active:bg-neutral-200 hover:border-neutral-400 active:border-neutral-500 dark:hover:bg-neutral-700 dark:active:bg-neutral-600 dark:hover:border-neutral-500 dark:active:border-neutral-400", onClick: () => setScale(3), children: "X3" }), jsxRuntime.jsx("button", { "aria-label": "Zoom 1000%", className: "ml-1 inline-flex h-6 min-w-10 items-center justify-center rounded border border-neutral-300 dark:border-neutral-600 px-1.5 text-[12px] transition-colors hover:bg-neutral-100 active:bg-neutral-200 hover:border-neutral-400 active:border-neutral-500 dark:hover:bg-neutral-700 dark:active:bg-neutral-600 dark:hover:border-neutral-500 dark:active:border-neutral-400", onClick: () => setScale(10), children: "X10" }), jsxRuntime.jsx("button", { "aria-label": "Reset", className: "ml-1 flex h-6 w-6 items-center justify-center rounded text-purple-500 hover:text-purple-600 transition-colors hover:bg-purple-50 active:bg-purple-100 dark:hover:bg-purple-500/20 dark:active:bg-purple-500/30", onClick: resetTransform, children: jsxRuntime.jsx(server.globalLucideIcons.RefreshCcw, { className: "h-3.5 w-3.5" }) }), jsxRuntime.jsx("button", { "aria-label": "Download SVG", className: "ml-1 flex h-6 w-6 items-center justify-center rounded text-purple-500 hover:text-purple-600 transition-colors hover:bg-purple-50 active:bg-purple-100 dark:hover:bg-purple-500/20 dark:active:bg-purple-500/30", onClick: handleDownload, children: jsxRuntime.jsx(server.globalLucideIcons.Download, { className: "h-3.5 w-3.5" }) }), jsxRuntime.jsx("button", { "aria-label": "Close", className: "ml-1 flex h-6 w-6 items-center justify-center rounded text-purple-500 hover:text-purple-600 transition-colors hover:bg-purple-50 active:bg-purple-100 dark:hover:bg-purple-500/20 dark:active:bg-purple-500/30", onClick: () => { setOpen(false); resetTransform(); }, children: jsxRuntime.jsx(server.globalLucideIcons.X, { className: "h-3.5 w-3.5" }) })] })] }), jsxRuntime.jsxs("div", { className: "relative h-[calc(88vh-40px)] w-full overflow-hidden bg-white dark:bg-neutral-900 touch-none overscroll-contain", onWheel: onWheel, onPointerDown: onPointerDown, onPointerMove: onPointerMove, onPointerUp: onPointerUp, children: [jsxRuntime.jsx("div", { className: "absolute left-1/2 top-1/2", style: { transform: `translate(-50%, -50%) translate(${translate.x}px, ${translate.y}px)` }, children: jsxRuntime.jsx("div", { style: { transform: `scale(${scale})`, transformOrigin: '50% 50%' }, dangerouslySetInnerHTML: { __html: svg } }) }), jsxRuntime.jsx("div", { className: "pointer-events-none absolute bottom-2 right-3 rounded bg-black/40 px-2 py-1 text-xs text-white", children: "Drag to pan, hold Cmd/Ctrl + scroll to zoom" })] })] })] }))] }));
|
|
158
178
|
}
|
|
159
179
|
function addWatermarkToSvg(svg, watermark) {
|
|
160
180
|
const watermarkText = `
|
|
@@ -5,6 +5,12 @@ import { globalLucideIcons } from '@windrun-huaiin/base-ui/components/server';
|
|
|
5
5
|
import { useTheme } from 'next-themes';
|
|
6
6
|
import { useId, useState, useRef, useEffect, useCallback } from 'react';
|
|
7
7
|
|
|
8
|
+
function sanitizeFilename(name) {
|
|
9
|
+
return name
|
|
10
|
+
.replace(/[\/:*?"<>|]/g, '_')
|
|
11
|
+
.replace(/\s+/g, '_')
|
|
12
|
+
.slice(0, 120);
|
|
13
|
+
}
|
|
8
14
|
function Mermaid({ chart, title, watermarkEnabled, watermarkText, enablePreview = true }) {
|
|
9
15
|
const id = useId();
|
|
10
16
|
const [svg, setSvg] = useState('');
|
|
@@ -91,6 +97,20 @@ function Mermaid({ chart, title, watermarkEnabled, watermarkText, enablePreview
|
|
|
91
97
|
isPanningRef.current = false;
|
|
92
98
|
e.currentTarget.releasePointerCapture(e.pointerId);
|
|
93
99
|
}, []);
|
|
100
|
+
const handleDownload = useCallback(() => {
|
|
101
|
+
if (!svg)
|
|
102
|
+
return;
|
|
103
|
+
const fileName = `${sanitizeFilename(title !== null && title !== void 0 ? title : 'mermaid')}.svg`;
|
|
104
|
+
const blob = new Blob([svg], { type: 'image/svg+xml;charset=utf-8' });
|
|
105
|
+
const url = URL.createObjectURL(blob);
|
|
106
|
+
const a = document.createElement('a');
|
|
107
|
+
a.href = url;
|
|
108
|
+
a.download = fileName;
|
|
109
|
+
document.body.appendChild(a);
|
|
110
|
+
a.click();
|
|
111
|
+
a.remove();
|
|
112
|
+
URL.revokeObjectURL(url);
|
|
113
|
+
}, [svg, title]);
|
|
94
114
|
// prevent browser-level zoom (touchpad pinch/shortcut) from taking effect when the dialog is open
|
|
95
115
|
useEffect(() => {
|
|
96
116
|
if (!open)
|
|
@@ -150,7 +170,7 @@ function Mermaid({ chart, title, watermarkEnabled, watermarkText, enablePreview
|
|
|
150
170
|
window.scrollTo(0, scrollY);
|
|
151
171
|
};
|
|
152
172
|
}, [open]);
|
|
153
|
-
return (jsxs("div", { children: [jsxs("div", { className: enablePreview ? 'group relative cursor-zoom-in' : undefined, onClick: () => enablePreview && svg && setOpen(true), children: [jsx("div", { dangerouslySetInnerHTML: { __html: svg } }), enablePreview && svg && (jsx("div", { className: "pointer-events-none absolute right-2 top-2 hidden rounded bg-black/50 px-2 py-0.5 text-[12px] text-white group-hover:block", children: "Preview Chart" }))] }), title && (jsxs("div", { className: "mt-2 flex items-center justify-center text-center text-[13px] font-italic text-[#AC62FD]", children: [jsx(globalLucideIcons.Mmd, { className: 'mr-1 h-4 w-4' }), jsx("span", { children: title })] })), enablePreview && open && (jsxs("div", { role: "dialog", "aria-modal": "true", "aria-label": typeof title === 'string' ? title : 'Mermaid Preview', className: "fixed inset-0 z-[9999] flex items-center justify-center", children: [jsx("div", { className: "absolute inset-0 bg-black/60", onClick: () => { setOpen(false); resetTransform(); }, onWheel: (e) => { e.preventDefault(); e.stopPropagation(); }, onTouchMove: (e) => { e.preventDefault(); e.stopPropagation(); } }), jsxs("div", { className: "relative z-[1] max-w-[95vw] w-[95vw] h-[88vh] p-0 bg-white dark:bg-neutral-900 border border-neutral-200 dark:border-neutral-700 rounded-md shadow-2xl overflow-hidden", children: [jsxs("div", { className: "flex items-center justify-between px-3 py-2 border-b border-neutral-200 dark:border-neutral-700", children: [jsxs("div", { className: "flex items-center gap-2 text-sm text-neutral-600 dark:text-neutral-300", children: [jsx(globalLucideIcons.Mmd, { className: "h-4 w-4" }), jsx("span", { className: "truncate max-w-[50vw]", children: title !== null && title !== void 0 ? title : 'Mermaid Preview' })] }), jsxs("div", { className: "flex items-center gap-0.5", children: [jsx("button", { "aria-label": "Zoom out", className: "flex h-6 w-6 items-center justify-center rounded border border-neutral-300 dark:border-neutral-600 text-[13px]", onClick: () => zoomBy(-0.5), children: "\uFF0D" }), jsxs("span", { className: "mx-0.5 text-[12px] w-12 text-center select-none", children: [Math.round(scale * 100), "%"] }), jsx("button", { "aria-label": "Zoom in", className: "flex h-6 w-6 items-center justify-center rounded border border-neutral-300 dark:border-neutral-600 text-[13px]", onClick: () => zoomBy(0.5), children: "\uFF0B" }), jsx("div", { className: "mx-1 h-4 w-px bg-neutral-300 dark:bg-neutral-700" }), jsx("button", { "aria-label": "Zoom 100%", className: "inline-flex h-6 min-w-8 items-center justify-center rounded border border-neutral-300 dark:border-neutral-600 px-1.5 text-[12px]", onClick: () => setScale(1), children: "X1" }), jsx("button", { "aria-label": "Zoom 200%", className: "ml-1 inline-flex h-6 min-w-8 items-center justify-center rounded border border-neutral-300 dark:border-neutral-600 px-1.5 text-[12px]", onClick: () => setScale(2), children: "X2" }), jsx("button", { "aria-label": "Zoom 300%", className: "ml-1 inline-flex h-6 min-w-8 items-center justify-center rounded border border-neutral-300 dark:border-neutral-600 px-1.5 text-[12px]", onClick: () => setScale(3), children: "X3" }), jsx("button", { "aria-label": "Zoom 1000%", className: "ml-1 inline-flex h-6 min-w-10 items-center justify-center rounded border border-neutral-300 dark:border-neutral-600 px-1.5 text-[12px]", onClick: () => setScale(10), children: "X10" }), jsx("button", { "aria-label": "Reset", className: "ml-1 flex h-6 w-6 items-center justify-center rounded text-purple-500 hover:text-purple-600", onClick: resetTransform, children: jsx(globalLucideIcons.RefreshCcw, { className: "h-3.5 w-3.5" }) }), jsx("button", { "aria-label": "Close", className: "ml-1 flex h-6 w-6 items-center justify-center rounded text-purple-500 hover:text-purple-600", onClick: () => { setOpen(false); resetTransform(); }, children: jsx(globalLucideIcons.X, { className: "h-3.5 w-3.5" }) })] })] }), jsxs("div", { className: "relative h-[calc(88vh-40px)] w-full overflow-hidden bg-white dark:bg-neutral-900 touch-none overscroll-contain", onWheel: onWheel, onPointerDown: onPointerDown, onPointerMove: onPointerMove, onPointerUp: onPointerUp, children: [jsx("div", { className: "absolute left-1/2 top-1/2", style: { transform: `translate(-50%, -50%) translate(${translate.x}px, ${translate.y}px)` }, children: jsx("div", { style: { transform: `scale(${scale})`, transformOrigin: '50% 50%' }, dangerouslySetInnerHTML: { __html: svg } }) }), jsx("div", { className: "pointer-events-none absolute bottom-2 right-3 rounded bg-black/40 px-2 py-1 text-xs text-white", children: "Drag to pan, hold Cmd/Ctrl + scroll to zoom" })] })] })] }))] }));
|
|
173
|
+
return (jsxs("div", { children: [jsxs("div", { className: enablePreview ? 'group relative cursor-zoom-in' : undefined, onClick: () => enablePreview && svg && setOpen(true), children: [jsx("div", { dangerouslySetInnerHTML: { __html: svg } }), enablePreview && svg && (jsx("div", { className: "pointer-events-none absolute right-2 top-2 hidden rounded bg-black/50 px-2 py-0.5 text-[12px] text-white group-hover:block", children: "Preview Chart" }))] }), title && (jsxs("div", { className: "mt-2 flex items-center justify-center text-center text-[13px] font-italic text-[#AC62FD]", children: [jsx(globalLucideIcons.Mmd, { className: 'mr-1 h-4 w-4' }), jsx("span", { children: title })] })), enablePreview && open && (jsxs("div", { role: "dialog", "aria-modal": "true", "aria-label": typeof title === 'string' ? title : 'Mermaid Preview', className: "fixed inset-0 z-[9999] flex items-center justify-center", children: [jsx("div", { className: "absolute inset-0 bg-black/60", onClick: () => { setOpen(false); resetTransform(); }, onWheel: (e) => { e.preventDefault(); e.stopPropagation(); }, onTouchMove: (e) => { e.preventDefault(); e.stopPropagation(); } }), jsxs("div", { className: "relative z-[1] max-w-[95vw] w-[95vw] h-[88vh] p-0 bg-white dark:bg-neutral-900 border border-neutral-200 dark:border-neutral-700 rounded-md shadow-2xl overflow-hidden", children: [jsxs("div", { className: "flex items-center justify-between px-3 py-2 border-b border-neutral-200 dark:border-neutral-700", children: [jsxs("div", { className: "flex items-center gap-2 text-sm text-neutral-600 dark:text-neutral-300", children: [jsx(globalLucideIcons.Mmd, { className: "h-4 w-4" }), jsx("span", { className: "truncate max-w-[50vw]", children: title !== null && title !== void 0 ? title : 'Mermaid Preview' })] }), jsxs("div", { className: "flex items-center gap-0.5", children: [jsx("button", { "aria-label": "Zoom out", className: "flex h-6 w-6 items-center justify-center rounded border border-neutral-300 dark:border-neutral-600 text-[13px] transition-colors hover:bg-neutral-100 active:bg-neutral-200 hover:border-neutral-400 active:border-neutral-500 dark:hover:bg-neutral-700 dark:active:bg-neutral-600 dark:hover:border-neutral-500 dark:active:border-neutral-400", onClick: () => zoomBy(-0.5), children: "\uFF0D" }), jsxs("span", { className: "mx-0.5 text-[12px] w-12 text-center select-none", children: [Math.round(scale * 100), "%"] }), jsx("button", { "aria-label": "Zoom in", className: "flex h-6 w-6 items-center justify-center rounded border border-neutral-300 dark:border-neutral-600 text-[13px] transition-colors hover:bg-neutral-100 active:bg-neutral-200 hover:border-neutral-400 active:border-neutral-500 dark:hover:bg-neutral-700 dark:active:bg-neutral-600 dark:hover:border-neutral-500 dark:active:border-neutral-400", onClick: () => zoomBy(0.5), children: "\uFF0B" }), jsx("div", { className: "mx-1 h-4 w-px bg-neutral-300 dark:bg-neutral-700" }), jsx("button", { "aria-label": "Zoom 100%", className: "inline-flex h-6 min-w-8 items-center justify-center rounded border border-neutral-300 dark:border-neutral-600 px-1.5 text-[12px] transition-colors hover:bg-neutral-100 active:bg-neutral-200 hover:border-neutral-400 active:border-neutral-500 dark:hover:bg-neutral-700 dark:active:bg-neutral-600 dark:hover:border-neutral-500 dark:active:border-neutral-400", onClick: () => setScale(1), children: "X1" }), jsx("button", { "aria-label": "Zoom 200%", className: "ml-1 inline-flex h-6 min-w-8 items-center justify-center rounded border border-neutral-300 dark:border-neutral-600 px-1.5 text-[12px] transition-colors hover:bg-neutral-100 active:bg-neutral-200 hover:border-neutral-400 active:border-neutral-500 dark:hover:bg-neutral-700 dark:active:bg-neutral-600 dark:hover:border-neutral-500 dark:active:border-neutral-400", onClick: () => setScale(2), children: "X2" }), jsx("button", { "aria-label": "Zoom 300%", className: "ml-1 inline-flex h-6 min-w-8 items-center justify-center rounded border border-neutral-300 dark:border-neutral-600 px-1.5 text-[12px] transition-colors hover:bg-neutral-100 active:bg-neutral-200 hover:border-neutral-400 active:border-neutral-500 dark:hover:bg-neutral-700 dark:active:bg-neutral-600 dark:hover:border-neutral-500 dark:active:border-neutral-400", onClick: () => setScale(3), children: "X3" }), jsx("button", { "aria-label": "Zoom 1000%", className: "ml-1 inline-flex h-6 min-w-10 items-center justify-center rounded border border-neutral-300 dark:border-neutral-600 px-1.5 text-[12px] transition-colors hover:bg-neutral-100 active:bg-neutral-200 hover:border-neutral-400 active:border-neutral-500 dark:hover:bg-neutral-700 dark:active:bg-neutral-600 dark:hover:border-neutral-500 dark:active:border-neutral-400", onClick: () => setScale(10), children: "X10" }), jsx("button", { "aria-label": "Reset", className: "ml-1 flex h-6 w-6 items-center justify-center rounded text-purple-500 hover:text-purple-600 transition-colors hover:bg-purple-50 active:bg-purple-100 dark:hover:bg-purple-500/20 dark:active:bg-purple-500/30", onClick: resetTransform, children: jsx(globalLucideIcons.RefreshCcw, { className: "h-3.5 w-3.5" }) }), jsx("button", { "aria-label": "Download SVG", className: "ml-1 flex h-6 w-6 items-center justify-center rounded text-purple-500 hover:text-purple-600 transition-colors hover:bg-purple-50 active:bg-purple-100 dark:hover:bg-purple-500/20 dark:active:bg-purple-500/30", onClick: handleDownload, children: jsx(globalLucideIcons.Download, { className: "h-3.5 w-3.5" }) }), jsx("button", { "aria-label": "Close", className: "ml-1 flex h-6 w-6 items-center justify-center rounded text-purple-500 hover:text-purple-600 transition-colors hover:bg-purple-50 active:bg-purple-100 dark:hover:bg-purple-500/20 dark:active:bg-purple-500/30", onClick: () => { setOpen(false); resetTransform(); }, children: jsx(globalLucideIcons.X, { className: "h-3.5 w-3.5" }) })] })] }), jsxs("div", { className: "relative h-[calc(88vh-40px)] w-full overflow-hidden bg-white dark:bg-neutral-900 touch-none overscroll-contain", onWheel: onWheel, onPointerDown: onPointerDown, onPointerMove: onPointerMove, onPointerUp: onPointerUp, children: [jsx("div", { className: "absolute left-1/2 top-1/2", style: { transform: `translate(-50%, -50%) translate(${translate.x}px, ${translate.y}px)` }, children: jsx("div", { style: { transform: `scale(${scale})`, transformOrigin: '50% 50%' }, dangerouslySetInnerHTML: { __html: svg } }) }), jsx("div", { className: "pointer-events-none absolute bottom-2 right-3 rounded bg-black/40 px-2 py-1 text-xs text-white", children: "Drag to pan, hold Cmd/Ctrl + scroll to zoom" })] })] })] }))] }));
|
|
154
174
|
}
|
|
155
175
|
function addWatermarkToSvg(svg, watermark) {
|
|
156
176
|
const watermarkText = `
|
package/dist/main/x-button.js
CHANGED
|
@@ -55,7 +55,7 @@ function XButton(props) {
|
|
|
55
55
|
// Split button
|
|
56
56
|
const { mainButton, menuItems, loadingText, menuWidth = 'w-40', className = '', mainButtonClassName = '', dropdownButtonClassName = '' } = props;
|
|
57
57
|
const isMainDisabled = mainButton.disabled || isLoading;
|
|
58
|
-
// loadingText
|
|
58
|
+
// loadingText prioty:props.loadingText > mainButton.text > 'Loading...'
|
|
59
59
|
const actualLoadingText = loadingText || ((_b = mainButton.text) === null || _b === void 0 ? void 0 : _b.trim()) || 'Loading...';
|
|
60
60
|
return (jsxRuntime.jsxs("div", { className: `relative flex bg-neutral-200 dark:bg-neutral-800 rounded-full ${className}`, children: [jsxRuntime.jsx("button", { onClick: () => handleButtonClick(mainButton.onClick), disabled: isMainDisabled, className: `flex-1 ${baseButtonClass} rounded-l-full ${isMainDisabled ? disabledClass : ''} ${mainButtonClassName}`, onMouseDown: e => { if (e.button === 2)
|
|
61
61
|
e.preventDefault(); }, style: { borderTopRightRadius: 0, borderBottomRightRadius: 0 }, children: isLoading ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(server.globalLucideIcons.Loader2, { className: "w-5 h-5 mr-1 animate-spin" }), jsxRuntime.jsx("span", { children: actualLoadingText })] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [mainButton.icon, jsxRuntime.jsx("span", { children: mainButton.text })] })) }), jsxRuntime.jsx("span", { className: `flex items-center justify-center w-10 py-2 cursor-pointer transition hover:bg-neutral-300 dark:hover:bg-neutral-700 rounded-r-full ${dropdownButtonClassName}`, onClick: e => { e.stopPropagation(); setMenuOpen(v => !v); }, tabIndex: 0, style: { borderTopLeftRadius: 0, borderBottomLeftRadius: 0 }, children: jsxRuntime.jsx(server.globalLucideIcons.ChevronDown, { className: "w-6 h-6" }) }), menuOpen && (jsxRuntime.jsx("div", { ref: menuRef, className: `absolute right-0 top-full ${menuWidth} bg-white dark:bg-neutral-800 text-neutral-800 dark:text-white text-sm rounded-xl shadow-lg z-50 border border-neutral-200 dark:border-neutral-700 overflow-hidden animate-fade-in`, children: menuItems.map((item, index) => (jsxRuntime.jsxs("button", { onClick: () => {
|
package/dist/main/x-button.mjs
CHANGED
|
@@ -53,7 +53,7 @@ function XButton(props) {
|
|
|
53
53
|
// Split button
|
|
54
54
|
const { mainButton, menuItems, loadingText, menuWidth = 'w-40', className = '', mainButtonClassName = '', dropdownButtonClassName = '' } = props;
|
|
55
55
|
const isMainDisabled = mainButton.disabled || isLoading;
|
|
56
|
-
// loadingText
|
|
56
|
+
// loadingText prioty:props.loadingText > mainButton.text > 'Loading...'
|
|
57
57
|
const actualLoadingText = loadingText || ((_b = mainButton.text) === null || _b === void 0 ? void 0 : _b.trim()) || 'Loading...';
|
|
58
58
|
return (jsxs("div", { className: `relative flex bg-neutral-200 dark:bg-neutral-800 rounded-full ${className}`, children: [jsx("button", { onClick: () => handleButtonClick(mainButton.onClick), disabled: isMainDisabled, className: `flex-1 ${baseButtonClass} rounded-l-full ${isMainDisabled ? disabledClass : ''} ${mainButtonClassName}`, onMouseDown: e => { if (e.button === 2)
|
|
59
59
|
e.preventDefault(); }, style: { borderTopRightRadius: 0, borderBottomRightRadius: 0 }, children: isLoading ? (jsxs(Fragment, { children: [jsx(globalLucideIcons.Loader2, { className: "w-5 h-5 mr-1 animate-spin" }), jsx("span", { children: actualLoadingText })] })) : (jsxs(Fragment, { children: [mainButton.icon, jsx("span", { children: mainButton.text })] })) }), jsx("span", { className: `flex items-center justify-center w-10 py-2 cursor-pointer transition hover:bg-neutral-300 dark:hover:bg-neutral-700 rounded-r-full ${dropdownButtonClassName}`, onClick: e => { e.stopPropagation(); setMenuOpen(v => !v); }, tabIndex: 0, style: { borderTopLeftRadius: 0, borderBottomLeftRadius: 0 }, children: jsx(globalLucideIcons.ChevronDown, { className: "w-6 h-6" }) }), menuOpen && (jsx("div", { ref: menuRef, className: `absolute right-0 top-full ${menuWidth} bg-white dark:bg-neutral-800 text-neutral-800 dark:text-white text-sm rounded-xl shadow-lg z-50 border border-neutral-200 dark:border-neutral-700 overflow-hidden animate-fade-in`, children: menuItems.map((item, index) => (jsxs("button", { onClick: () => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var coseBase$1 = require('../../../../../_virtual/cose-
|
|
3
|
+
var coseBase$1 = require('../../../../../_virtual/cose-base2.js');
|
|
4
4
|
var layoutBase = require('../../../layout-base@1.0.2/node_modules/layout-base/layout-base.js');
|
|
5
5
|
|
|
6
6
|
var coseBase = coseBase$1.__module.exports;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var coseBase$1 = require('../../../../../_virtual/cose-
|
|
3
|
+
var coseBase$1 = require('../../../../../_virtual/cose-base.js');
|
|
4
4
|
var layoutBase = require('../../../layout-base@2.0.1/node_modules/layout-base/layout-base.js');
|
|
5
5
|
|
|
6
6
|
var coseBase = coseBase$1.__module.exports;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@windrun-huaiin/third-ui",
|
|
3
|
-
"version": "7.1.
|
|
3
|
+
"version": "7.1.2",
|
|
4
4
|
"description": "Third-party integrated UI components for windrun-huaiin projects",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -64,8 +64,8 @@
|
|
|
64
64
|
"mermaid": "^11.6.0",
|
|
65
65
|
"react-medium-image-zoom": "^5.2.14",
|
|
66
66
|
"zod": "^3.22.4",
|
|
67
|
-
"@windrun-huaiin/
|
|
68
|
-
"@windrun-huaiin/
|
|
67
|
+
"@windrun-huaiin/base-ui": "^8.1.1",
|
|
68
|
+
"@windrun-huaiin/lib": "^7.1.1"
|
|
69
69
|
},
|
|
70
70
|
"peerDependencies": {
|
|
71
71
|
"react": "19.1.0",
|
package/src/fuma/mdx/mermaid.tsx
CHANGED
|
@@ -6,6 +6,13 @@ import type { MermaidConfig } from 'mermaid';
|
|
|
6
6
|
import { useTheme } from 'next-themes';
|
|
7
7
|
import { useCallback, useEffect, useId, useRef, useState } from 'react';
|
|
8
8
|
|
|
9
|
+
function sanitizeFilename(name: string) {
|
|
10
|
+
return name
|
|
11
|
+
.replace(/[\/:*?"<>|]/g, '_')
|
|
12
|
+
.replace(/\s+/g, '_')
|
|
13
|
+
.slice(0, 120);
|
|
14
|
+
}
|
|
15
|
+
|
|
9
16
|
interface MermaidProps {
|
|
10
17
|
chart: string;
|
|
11
18
|
title?: string;
|
|
@@ -111,6 +118,20 @@ export function Mermaid({ chart, title, watermarkEnabled, watermarkText, enableP
|
|
|
111
118
|
(e.currentTarget as HTMLDivElement).releasePointerCapture(e.pointerId);
|
|
112
119
|
}, []);
|
|
113
120
|
|
|
121
|
+
const handleDownload = useCallback(() => {
|
|
122
|
+
if (!svg) return;
|
|
123
|
+
const fileName = `${sanitizeFilename(title ?? 'mermaid')}.svg`;
|
|
124
|
+
const blob = new Blob([svg], { type: 'image/svg+xml;charset=utf-8' });
|
|
125
|
+
const url = URL.createObjectURL(blob);
|
|
126
|
+
const a = document.createElement('a');
|
|
127
|
+
a.href = url;
|
|
128
|
+
a.download = fileName;
|
|
129
|
+
document.body.appendChild(a);
|
|
130
|
+
a.click();
|
|
131
|
+
a.remove();
|
|
132
|
+
URL.revokeObjectURL(url);
|
|
133
|
+
}, [svg, title]);
|
|
134
|
+
|
|
114
135
|
// prevent browser-level zoom (touchpad pinch/shortcut) from taking effect when the dialog is open
|
|
115
136
|
useEffect(() => {
|
|
116
137
|
if (!open) return;
|
|
@@ -213,7 +234,7 @@ export function Mermaid({ chart, title, watermarkEnabled, watermarkText, enableP
|
|
|
213
234
|
<div className="flex items-center gap-0.5">
|
|
214
235
|
<button
|
|
215
236
|
aria-label="Zoom out"
|
|
216
|
-
className="flex h-6 w-6 items-center justify-center rounded border border-neutral-300 dark:border-neutral-600 text-[13px]"
|
|
237
|
+
className="flex h-6 w-6 items-center justify-center rounded border border-neutral-300 dark:border-neutral-600 text-[13px] transition-colors hover:bg-neutral-100 active:bg-neutral-200 hover:border-neutral-400 active:border-neutral-500 dark:hover:bg-neutral-700 dark:active:bg-neutral-600 dark:hover:border-neutral-500 dark:active:border-neutral-400"
|
|
217
238
|
onClick={() => zoomBy(-0.5)}
|
|
218
239
|
>
|
|
219
240
|
-
|
|
@@ -221,7 +242,7 @@ export function Mermaid({ chart, title, watermarkEnabled, watermarkText, enableP
|
|
|
221
242
|
<span className="mx-0.5 text-[12px] w-12 text-center select-none">{Math.round(scale * 100)}%</span>
|
|
222
243
|
<button
|
|
223
244
|
aria-label="Zoom in"
|
|
224
|
-
className="flex h-6 w-6 items-center justify-center rounded border border-neutral-300 dark:border-neutral-600 text-[13px]"
|
|
245
|
+
className="flex h-6 w-6 items-center justify-center rounded border border-neutral-300 dark:border-neutral-600 text-[13px] transition-colors hover:bg-neutral-100 active:bg-neutral-200 hover:border-neutral-400 active:border-neutral-500 dark:hover:bg-neutral-700 dark:active:bg-neutral-600 dark:hover:border-neutral-500 dark:active:border-neutral-400"
|
|
225
246
|
onClick={() => zoomBy(0.5)}
|
|
226
247
|
>
|
|
227
248
|
+
|
|
@@ -230,42 +251,49 @@ export function Mermaid({ chart, title, watermarkEnabled, watermarkText, enableP
|
|
|
230
251
|
<div className="mx-1 h-4 w-px bg-neutral-300 dark:bg-neutral-700" />
|
|
231
252
|
<button
|
|
232
253
|
aria-label="Zoom 100%"
|
|
233
|
-
className="inline-flex h-6 min-w-8 items-center justify-center rounded border border-neutral-300 dark:border-neutral-600 px-1.5 text-[12px]"
|
|
254
|
+
className="inline-flex h-6 min-w-8 items-center justify-center rounded border border-neutral-300 dark:border-neutral-600 px-1.5 text-[12px] transition-colors hover:bg-neutral-100 active:bg-neutral-200 hover:border-neutral-400 active:border-neutral-500 dark:hover:bg-neutral-700 dark:active:bg-neutral-600 dark:hover:border-neutral-500 dark:active:border-neutral-400"
|
|
234
255
|
onClick={() => setScale(1)}
|
|
235
256
|
>
|
|
236
257
|
X1
|
|
237
258
|
</button>
|
|
238
259
|
<button
|
|
239
260
|
aria-label="Zoom 200%"
|
|
240
|
-
className="ml-1 inline-flex h-6 min-w-8 items-center justify-center rounded border border-neutral-300 dark:border-neutral-600 px-1.5 text-[12px]"
|
|
261
|
+
className="ml-1 inline-flex h-6 min-w-8 items-center justify-center rounded border border-neutral-300 dark:border-neutral-600 px-1.5 text-[12px] transition-colors hover:bg-neutral-100 active:bg-neutral-200 hover:border-neutral-400 active:border-neutral-500 dark:hover:bg-neutral-700 dark:active:bg-neutral-600 dark:hover:border-neutral-500 dark:active:border-neutral-400"
|
|
241
262
|
onClick={() => setScale(2)}
|
|
242
263
|
>
|
|
243
264
|
X2
|
|
244
265
|
</button>
|
|
245
266
|
<button
|
|
246
267
|
aria-label="Zoom 300%"
|
|
247
|
-
className="ml-1 inline-flex h-6 min-w-8 items-center justify-center rounded border border-neutral-300 dark:border-neutral-600 px-1.5 text-[12px]"
|
|
268
|
+
className="ml-1 inline-flex h-6 min-w-8 items-center justify-center rounded border border-neutral-300 dark:border-neutral-600 px-1.5 text-[12px] transition-colors hover:bg-neutral-100 active:bg-neutral-200 hover:border-neutral-400 active:border-neutral-500 dark:hover:bg-neutral-700 dark:active:bg-neutral-600 dark:hover:border-neutral-500 dark:active:border-neutral-400"
|
|
248
269
|
onClick={() => setScale(3)}
|
|
249
270
|
>
|
|
250
271
|
X3
|
|
251
272
|
</button>
|
|
252
273
|
<button
|
|
253
274
|
aria-label="Zoom 1000%"
|
|
254
|
-
className="ml-1 inline-flex h-6 min-w-10 items-center justify-center rounded border border-neutral-300 dark:border-neutral-600 px-1.5 text-[12px]"
|
|
275
|
+
className="ml-1 inline-flex h-6 min-w-10 items-center justify-center rounded border border-neutral-300 dark:border-neutral-600 px-1.5 text-[12px] transition-colors hover:bg-neutral-100 active:bg-neutral-200 hover:border-neutral-400 active:border-neutral-500 dark:hover:bg-neutral-700 dark:active:bg-neutral-600 dark:hover:border-neutral-500 dark:active:border-neutral-400"
|
|
255
276
|
onClick={() => setScale(10)}
|
|
256
277
|
>
|
|
257
278
|
X10
|
|
258
279
|
</button>
|
|
259
280
|
<button
|
|
260
281
|
aria-label="Reset"
|
|
261
|
-
className="ml-1 flex h-6 w-6 items-center justify-center rounded text-purple-500 hover:text-purple-600"
|
|
282
|
+
className="ml-1 flex h-6 w-6 items-center justify-center rounded text-purple-500 hover:text-purple-600 transition-colors hover:bg-purple-50 active:bg-purple-100 dark:hover:bg-purple-500/20 dark:active:bg-purple-500/30"
|
|
262
283
|
onClick={resetTransform}
|
|
263
284
|
>
|
|
264
285
|
<icons.RefreshCcw className="h-3.5 w-3.5" />
|
|
265
286
|
</button>
|
|
287
|
+
<button
|
|
288
|
+
aria-label="Download SVG"
|
|
289
|
+
className="ml-1 flex h-6 w-6 items-center justify-center rounded text-purple-500 hover:text-purple-600 transition-colors hover:bg-purple-50 active:bg-purple-100 dark:hover:bg-purple-500/20 dark:active:bg-purple-500/30"
|
|
290
|
+
onClick={handleDownload}
|
|
291
|
+
>
|
|
292
|
+
<icons.Download className="h-3.5 w-3.5" />
|
|
293
|
+
</button>
|
|
266
294
|
<button
|
|
267
295
|
aria-label="Close"
|
|
268
|
-
className="ml-1 flex h-6 w-6 items-center justify-center rounded text-purple-500 hover:text-purple-600"
|
|
296
|
+
className="ml-1 flex h-6 w-6 items-center justify-center rounded text-purple-500 hover:text-purple-600 transition-colors hover:bg-purple-50 active:bg-purple-100 dark:hover:bg-purple-500/20 dark:active:bg-purple-500/30"
|
|
269
297
|
onClick={() => { setOpen(false); resetTransform(); }}
|
|
270
298
|
>
|
|
271
299
|
<icons.X className="h-3.5 w-3.5" />
|
|
@@ -97,7 +97,7 @@ export function LastUpdatedDate({ date }: { date: string | undefined }) {
|
|
|
97
97
|
return (
|
|
98
98
|
<div className="flex items-center gap-x-2 text-stone-600 dark:text-stone-400 text-sm">
|
|
99
99
|
<icons.LastUpdated/>
|
|
100
|
-
|
|
100
|
+
Latest on {date ? date : "Ages ago"}
|
|
101
101
|
</div>
|
|
102
102
|
);
|
|
103
103
|
}
|
package/src/main/x-button.tsx
CHANGED
|
@@ -116,7 +116,7 @@ export function XButton(props: xButtonProps) {
|
|
|
116
116
|
// Split button
|
|
117
117
|
const { mainButton, menuItems, loadingText, menuWidth = 'w-40', className = '', mainButtonClassName = '', dropdownButtonClassName = '' } = props
|
|
118
118
|
const isMainDisabled = mainButton.disabled || isLoading
|
|
119
|
-
// loadingText
|
|
119
|
+
// loadingText prioty:props.loadingText > mainButton.text > 'Loading...'
|
|
120
120
|
const actualLoadingText = loadingText || mainButton.text?.trim() || 'Loading...'
|
|
121
121
|
|
|
122
122
|
return (
|