@windrun-huaiin/third-ui 29.2.0 → 30.0.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/fuma/mdx/cheet-table.d.ts +13 -0
- package/dist/fuma/mdx/cheet-table.js +295 -0
- package/dist/fuma/mdx/cheet-table.mjs +293 -0
- package/dist/fuma/mdx/index.d.ts +1 -0
- package/dist/fuma/mdx/index.js +2 -0
- package/dist/fuma/mdx/index.mjs +1 -0
- package/dist/fuma/server/features/widgets.js +2 -0
- package/dist/fuma/server/features/widgets.mjs +2 -0
- package/dist/lib/fuma-schema-check-util.d.ts +1 -1
- package/dist/main/alert-dialog/confirm-dialog.d.ts +2 -1
- package/dist/main/alert-dialog/confirm-dialog.js +3 -3
- package/dist/main/alert-dialog/confirm-dialog.mjs +4 -4
- package/dist/main/alert-dialog/dialog-loading-action.d.ts +2 -1
- package/dist/main/alert-dialog/dialog-loading-action.js +6 -3
- package/dist/main/alert-dialog/dialog-loading-action.mjs +6 -3
- package/dist/main/alert-dialog/dialog-styles.d.ts +4 -2
- package/dist/main/alert-dialog/dialog-styles.js +8 -4
- package/dist/main/alert-dialog/dialog-styles.mjs +7 -5
- package/dist/main/alert-dialog/high-priority-confirm-dialog.d.ts +2 -1
- package/dist/main/alert-dialog/high-priority-confirm-dialog.js +7 -7
- package/dist/main/alert-dialog/high-priority-confirm-dialog.mjs +8 -8
- package/dist/main/alert-dialog/info-dialog.d.ts +2 -1
- package/dist/main/alert-dialog/info-dialog.js +3 -3
- package/dist/main/alert-dialog/info-dialog.mjs +4 -4
- package/dist/main/alert-dialog/undoable-confirm-dialog.d.ts +2 -1
- package/dist/main/alert-dialog/undoable-confirm-dialog.js +4 -4
- package/dist/main/alert-dialog/undoable-confirm-dialog.mjs +5 -5
- package/dist/main/anime/anime-beam-frame.d.ts +3 -0
- package/dist/main/anime/anime-beam-frame.js +63 -0
- package/dist/main/anime/anime-beam-frame.mjs +61 -0
- package/dist/main/anime/anime-spiral-loading.d.ts +10 -0
- package/dist/main/anime/anime-spiral-loading.js +77 -0
- package/dist/main/anime/anime-spiral-loading.mjs +75 -0
- package/dist/main/anime/index.d.ts +2 -0
- package/dist/main/anime/index.js +10 -0
- package/dist/main/anime/index.mjs +3 -0
- package/dist/main/beam-frame/animate.d.ts +3 -0
- package/dist/main/beam-frame/animate.js +63 -0
- package/dist/main/beam-frame/animate.mjs +61 -0
- package/dist/main/beam-frame/beam-frame.d.ts +4 -0
- package/dist/main/beam-frame/beam-frame.js +262 -0
- package/dist/main/beam-frame/beam-frame.mjs +258 -0
- package/dist/main/beam-frame/index.d.ts +4 -0
- package/dist/main/beam-frame/index.js +11 -0
- package/dist/main/beam-frame/index.mjs +3 -0
- package/dist/main/beam-frame/motion.d.ts +3 -0
- package/dist/main/beam-frame/motion.js +61 -0
- package/dist/main/beam-frame/motion.mjs +59 -0
- package/dist/main/beam-frame/share-config.d.ts +54 -0
- package/dist/main/beam-frame/share-config.js +161 -0
- package/dist/main/beam-frame/share-config.mjs +152 -0
- package/dist/main/beam-frame-config.d.ts +54 -0
- package/dist/main/beam-frame-config.js +161 -0
- package/dist/main/beam-frame-config.mjs +152 -0
- package/dist/main/calendar/random-date-range-dialog.d.ts +5 -2
- package/dist/main/calendar/random-date-range-dialog.js +239 -109
- package/dist/main/calendar/random-date-range-dialog.mjs +242 -112
- package/dist/main/cta.js +17 -1
- package/dist/main/cta.mjs +18 -2
- package/dist/main/delayed-img.d.ts +1 -1
- package/dist/main/delayed-img.js +8 -5
- package/dist/main/delayed-img.mjs +8 -5
- package/dist/main/info-tooltip.js +70 -9
- package/dist/main/info-tooltip.mjs +70 -9
- package/dist/main/loading-frame/index.d.ts +1 -0
- package/dist/main/loading.d.ts +2 -1
- package/dist/main/loading.js +64 -26
- package/dist/main/loading.mjs +64 -26
- package/dist/main/motion/index.d.ts +1 -0
- package/dist/main/motion/index.js +9 -0
- package/dist/main/motion/index.mjs +2 -0
- package/dist/main/motion/motion-beam-frame.d.ts +3 -0
- package/dist/main/motion/motion-beam-frame.js +61 -0
- package/dist/main/motion/motion-beam-frame.mjs +59 -0
- package/dist/main/snake-loading-frame.d.ts +7 -3
- package/dist/main/snake-loading-frame.js +44 -252
- package/dist/main/snake-loading-frame.mjs +46 -254
- package/package.json +16 -5
- package/src/fuma/mdx/cheet-table.tsx +650 -0
- package/src/fuma/mdx/index.ts +1 -0
- package/src/fuma/server/features/widgets.tsx +2 -0
- package/src/main/alert-dialog/confirm-dialog.tsx +5 -2
- package/src/main/alert-dialog/dialog-loading-action.tsx +22 -5
- package/src/main/alert-dialog/dialog-styles.ts +13 -3
- package/src/main/alert-dialog/high-priority-confirm-dialog.tsx +29 -24
- package/src/main/alert-dialog/info-dialog.tsx +5 -2
- package/src/main/alert-dialog/undoable-confirm-dialog.tsx +21 -18
- package/src/main/anime/anime-beam-frame.tsx +128 -0
- package/src/main/anime/anime-spiral-loading.tsx +123 -0
- package/src/main/anime/index.ts +9 -0
- package/src/main/beam-frame-config.tsx +341 -0
- package/src/main/calendar/random-date-range-dialog.tsx +242 -74
- package/src/main/cta.tsx +50 -21
- package/src/main/delayed-img.tsx +9 -4
- package/src/main/info-tooltip.tsx +116 -20
- package/src/main/loading-frame/index.ts +4 -0
- package/src/main/loading.tsx +75 -24
- package/src/main/motion/index.ts +8 -0
- package/src/main/motion/motion-beam-frame.tsx +137 -0
- package/src/main/snake-loading-frame.tsx +95 -496
- package/src/styles/cta.css +21 -4
- package/src/styles/third-ui.css +0 -20
|
@@ -3,5 +3,5 @@ interface DelayedImgProps extends ImageProps {
|
|
|
3
3
|
wrapperClassName?: string;
|
|
4
4
|
placeholderClassName?: string;
|
|
5
5
|
}
|
|
6
|
-
export declare function DelayedImg({ alt, wrapperClassName, placeholderClassName, className, onLoad, ...imageProps }: DelayedImgProps): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
export declare function DelayedImg({ alt, wrapperClassName, placeholderClassName, className, onError, onLoad, ...imageProps }: DelayedImgProps): import("react/jsx-runtime").JSX.Element;
|
|
7
7
|
export {};
|
package/dist/main/delayed-img.js
CHANGED
|
@@ -17,10 +17,10 @@ const ENV_DELAY_MS = Number.isFinite(parsedDelaySeconds) && parsedDelaySeconds >
|
|
|
17
17
|
? parsedDelaySeconds * 1000
|
|
18
18
|
: 0;
|
|
19
19
|
function DelayedImg(_a) {
|
|
20
|
-
var { alt, wrapperClassName, placeholderClassName, className, onLoad } = _a, imageProps = tslib.__rest(_a, ["alt", "wrapperClassName", "placeholderClassName", "className", "onLoad"]);
|
|
20
|
+
var { alt, wrapperClassName, placeholderClassName, className, onError, onLoad } = _a, imageProps = tslib.__rest(_a, ["alt", "wrapperClassName", "placeholderClassName", "className", "onError", "onLoad"]);
|
|
21
21
|
const shouldDelay = ENV_DELAY_ENABLED && ENV_DELAY_MS > 0;
|
|
22
22
|
const [isMounted, setIsMounted] = React.useState(!shouldDelay);
|
|
23
|
-
const [
|
|
23
|
+
const [isSettled, setIsSettled] = React.useState(false);
|
|
24
24
|
React.useEffect(() => {
|
|
25
25
|
if (!shouldDelay || isMounted) {
|
|
26
26
|
return;
|
|
@@ -30,10 +30,13 @@ function DelayedImg(_a) {
|
|
|
30
30
|
}, ENV_DELAY_MS);
|
|
31
31
|
return () => window.clearTimeout(timer);
|
|
32
32
|
}, [isMounted, shouldDelay]);
|
|
33
|
-
return (jsxRuntime.jsxs("div", { className: utils.cn("relative", wrapperClassName), children: [(!isMounted || !
|
|
34
|
-
|
|
33
|
+
return (jsxRuntime.jsxs("div", { className: utils.cn("relative", wrapperClassName), children: [(!isMounted || !isSettled) && (jsxRuntime.jsx(snakeLoadingFrame.SnakeLoadingFrame, { shape: "rounded-rect", loading: true, themeColor: lib.themeSvgIconColor, className: utils.cn("absolute inset-0 rounded-[inherit] border shadow-sm bg-white/70 dark:bg-white/5", lib.themeBgColor, placeholderClassName), contentClassName: "h-full w-full", children: jsxRuntime.jsx("div", { "aria-hidden": "true", className: "absolute inset-0 rounded-[inherit] bg-white/20 dark:bg-white/0" }) })), isMounted && (jsxRuntime.jsx(Image, Object.assign({}, imageProps, { alt: alt, onError: (event) => {
|
|
34
|
+
setIsSettled(true);
|
|
35
|
+
onError === null || onError === void 0 ? void 0 : onError(event);
|
|
36
|
+
}, onLoad: (event) => {
|
|
37
|
+
setIsSettled(true);
|
|
35
38
|
onLoad === null || onLoad === void 0 ? void 0 : onLoad(event);
|
|
36
|
-
}, className: utils.cn("transition duration-300",
|
|
39
|
+
}, className: utils.cn("transition duration-300", isSettled ? "opacity-100" : "opacity-0", className) })))] }));
|
|
37
40
|
}
|
|
38
41
|
|
|
39
42
|
exports.DelayedImg = DelayedImg;
|
|
@@ -15,10 +15,10 @@ const ENV_DELAY_MS = Number.isFinite(parsedDelaySeconds) && parsedDelaySeconds >
|
|
|
15
15
|
? parsedDelaySeconds * 1000
|
|
16
16
|
: 0;
|
|
17
17
|
function DelayedImg(_a) {
|
|
18
|
-
var { alt, wrapperClassName, placeholderClassName, className, onLoad } = _a, imageProps = __rest(_a, ["alt", "wrapperClassName", "placeholderClassName", "className", "onLoad"]);
|
|
18
|
+
var { alt, wrapperClassName, placeholderClassName, className, onError, onLoad } = _a, imageProps = __rest(_a, ["alt", "wrapperClassName", "placeholderClassName", "className", "onError", "onLoad"]);
|
|
19
19
|
const shouldDelay = ENV_DELAY_ENABLED && ENV_DELAY_MS > 0;
|
|
20
20
|
const [isMounted, setIsMounted] = useState(!shouldDelay);
|
|
21
|
-
const [
|
|
21
|
+
const [isSettled, setIsSettled] = useState(false);
|
|
22
22
|
useEffect(() => {
|
|
23
23
|
if (!shouldDelay || isMounted) {
|
|
24
24
|
return;
|
|
@@ -28,10 +28,13 @@ function DelayedImg(_a) {
|
|
|
28
28
|
}, ENV_DELAY_MS);
|
|
29
29
|
return () => window.clearTimeout(timer);
|
|
30
30
|
}, [isMounted, shouldDelay]);
|
|
31
|
-
return (jsxs("div", { className: cn("relative", wrapperClassName), children: [(!isMounted || !
|
|
32
|
-
|
|
31
|
+
return (jsxs("div", { className: cn("relative", wrapperClassName), children: [(!isMounted || !isSettled) && (jsx(SnakeLoadingFrame, { shape: "rounded-rect", loading: true, themeColor: themeSvgIconColor, className: cn("absolute inset-0 rounded-[inherit] border shadow-sm bg-white/70 dark:bg-white/5", themeBgColor, placeholderClassName), contentClassName: "h-full w-full", children: jsx("div", { "aria-hidden": "true", className: "absolute inset-0 rounded-[inherit] bg-white/20 dark:bg-white/0" }) })), isMounted && (jsx(Image, Object.assign({}, imageProps, { alt: alt, onError: (event) => {
|
|
32
|
+
setIsSettled(true);
|
|
33
|
+
onError === null || onError === void 0 ? void 0 : onError(event);
|
|
34
|
+
}, onLoad: (event) => {
|
|
35
|
+
setIsSettled(true);
|
|
33
36
|
onLoad === null || onLoad === void 0 ? void 0 : onLoad(event);
|
|
34
|
-
}, className: cn("transition duration-300",
|
|
37
|
+
}, className: cn("transition duration-300", isSettled ? "opacity-100" : "opacity-0", className) })))] }));
|
|
35
38
|
}
|
|
36
39
|
|
|
37
40
|
export { DelayedImg };
|
|
@@ -3,21 +3,69 @@
|
|
|
3
3
|
|
|
4
4
|
var jsxRuntime = require('react/jsx-runtime');
|
|
5
5
|
var React = require('react');
|
|
6
|
+
var reactDom = require('react-dom');
|
|
6
7
|
var icons = require('@windrun-huaiin/base-ui/icons');
|
|
7
8
|
var lib = require('@windrun-huaiin/base-ui/lib');
|
|
8
9
|
var utils = require('@windrun-huaiin/lib/utils');
|
|
9
10
|
|
|
11
|
+
const TOOLTIP_MARGIN = 12;
|
|
12
|
+
const TOOLTIP_GAP = 8;
|
|
13
|
+
const TOOLTIP_MAX_WIDTH = 288;
|
|
14
|
+
function clamp(value, min, max) {
|
|
15
|
+
return Math.min(Math.max(value, min), max);
|
|
16
|
+
}
|
|
17
|
+
function getTooltipPosition(target, align, desktopSide) {
|
|
18
|
+
const rect = target.getBoundingClientRect();
|
|
19
|
+
const viewportWidth = window.innerWidth;
|
|
20
|
+
const viewportHeight = window.innerHeight;
|
|
21
|
+
const maxWidth = Math.min(TOOLTIP_MAX_WIDTH, Math.max(160, viewportWidth - TOOLTIP_MARGIN * 2));
|
|
22
|
+
const useInlineSide = desktopSide === 'right' && viewportWidth >= 768;
|
|
23
|
+
if (useInlineSide) {
|
|
24
|
+
const rightSpace = viewportWidth - rect.right - TOOLTIP_GAP - TOOLTIP_MARGIN;
|
|
25
|
+
const leftSpace = rect.left - TOOLTIP_GAP - TOOLTIP_MARGIN;
|
|
26
|
+
const placeRight = rightSpace >= Math.min(220, maxWidth) || rightSpace >= leftSpace;
|
|
27
|
+
const preferredLeft = placeRight
|
|
28
|
+
? rect.right + TOOLTIP_GAP
|
|
29
|
+
: rect.left - maxWidth - TOOLTIP_GAP;
|
|
30
|
+
return {
|
|
31
|
+
left: clamp(preferredLeft, TOOLTIP_MARGIN, viewportWidth - maxWidth - TOOLTIP_MARGIN),
|
|
32
|
+
top: clamp(rect.top + rect.height / 2, TOOLTIP_MARGIN + 40, viewportHeight - TOOLTIP_MARGIN - 40),
|
|
33
|
+
maxWidth,
|
|
34
|
+
side: 'inline',
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const preferredLeft = align === 'start'
|
|
38
|
+
? rect.left
|
|
39
|
+
: rect.right - maxWidth;
|
|
40
|
+
return {
|
|
41
|
+
left: clamp(preferredLeft, TOOLTIP_MARGIN, viewportWidth - maxWidth - TOOLTIP_MARGIN),
|
|
42
|
+
top: Math.min(rect.bottom + TOOLTIP_GAP, viewportHeight - TOOLTIP_MARGIN),
|
|
43
|
+
maxWidth,
|
|
44
|
+
side: 'bottom',
|
|
45
|
+
};
|
|
46
|
+
}
|
|
10
47
|
function InfoTooltip({ content, className, align = 'end', desktopSide = 'right', }) {
|
|
11
48
|
const normalizedContent = content.trim();
|
|
12
49
|
const containerRef = React.useRef(null);
|
|
50
|
+
const tooltipRef = React.useRef(null);
|
|
13
51
|
const [open, setOpen] = React.useState(false);
|
|
52
|
+
const [position, setPosition] = React.useState(null);
|
|
53
|
+
const updatePosition = () => {
|
|
54
|
+
if (!containerRef.current) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
setPosition(getTooltipPosition(containerRef.current, align, desktopSide));
|
|
58
|
+
};
|
|
14
59
|
React.useEffect(() => {
|
|
15
60
|
function handlePointerDown(event) {
|
|
61
|
+
var _a;
|
|
16
62
|
if (!containerRef.current) {
|
|
17
63
|
return;
|
|
18
64
|
}
|
|
19
65
|
const target = event.target;
|
|
20
|
-
if (target instanceof Node &&
|
|
66
|
+
if (target instanceof Node &&
|
|
67
|
+
!containerRef.current.contains(target) &&
|
|
68
|
+
!((_a = tooltipRef.current) === null || _a === void 0 ? void 0 : _a.contains(target))) {
|
|
21
69
|
setOpen(false);
|
|
22
70
|
}
|
|
23
71
|
}
|
|
@@ -28,21 +76,34 @@ function InfoTooltip({ content, className, align = 'end', desktopSide = 'right',
|
|
|
28
76
|
document.removeEventListener('touchstart', handlePointerDown);
|
|
29
77
|
};
|
|
30
78
|
}, []);
|
|
79
|
+
React.useEffect(() => {
|
|
80
|
+
if (!open) {
|
|
81
|
+
setPosition(null);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
updatePosition();
|
|
85
|
+
window.addEventListener('resize', updatePosition);
|
|
86
|
+
window.addEventListener('scroll', updatePosition, true);
|
|
87
|
+
return () => {
|
|
88
|
+
window.removeEventListener('resize', updatePosition);
|
|
89
|
+
window.removeEventListener('scroll', updatePosition, true);
|
|
90
|
+
};
|
|
91
|
+
}, [align, desktopSide, open]);
|
|
31
92
|
if (!normalizedContent) {
|
|
32
93
|
return null;
|
|
33
94
|
}
|
|
34
|
-
return (jsxRuntime.jsxs("span", { ref: containerRef, className: utils.cn('
|
|
95
|
+
return (jsxRuntime.jsxs("span", { ref: containerRef, className: utils.cn('inline-flex h-5 w-5 shrink-0 align-middle', className), onMouseLeave: () => setOpen(false), children: [jsxRuntime.jsx("button", { type: "button", onMouseEnter: () => setOpen(true), onPointerDown: (event) => {
|
|
35
96
|
event.stopPropagation();
|
|
36
97
|
}, onClick: (event) => {
|
|
37
98
|
event.stopPropagation();
|
|
38
99
|
setOpen((value) => !value);
|
|
39
|
-
}, className: utils.cn('inline-flex h-5 w-5 items-center justify-center rounded-full text-slate-400 transition', 'hover:bg-black/5 hover:dark:bg-white/5', 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 dark:focus-visible:ring-offset-slate-950', 'hover:text-slate-700 dark:hover:text-white focus-visible:text-slate-700 dark:focus-visible:text-white', lib.themeIconColor, lib.themeRingColor), "aria-label": normalizedContent, "aria-expanded": open, children: jsxRuntime.jsx(icons.CircleQuestionMarkIcon, { className: "h-4 w-4" }) }),
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
:
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
100
|
+
}, className: utils.cn('inline-flex h-5 w-5 items-center justify-center rounded-full text-slate-400 transition', 'hover:bg-black/5 hover:dark:bg-white/5', 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 dark:focus-visible:ring-offset-slate-950', 'hover:text-slate-700 dark:hover:text-white focus-visible:text-slate-700 dark:focus-visible:text-white', lib.themeIconColor, lib.themeRingColor), "aria-label": normalizedContent, "aria-expanded": open, children: jsxRuntime.jsx(icons.CircleQuestionMarkIcon, { className: "h-4 w-4" }) }), open && position
|
|
101
|
+
? reactDom.createPortal(jsxRuntime.jsx("span", { ref: tooltipRef, className: utils.cn('pointer-events-none fixed z-50 max-h-[calc(100vh-1.5rem)] overflow-y-auto rounded-2xl border bg-white/95 px-3 py-2 text-xs leading-5 text-slate-600 shadow-xl backdrop-blur-sm dark:bg-slate-950/95 dark:text-slate-300', position.side === 'inline' && '-translate-y-1/2', lib.themeBorderColor), style: {
|
|
102
|
+
left: position.left,
|
|
103
|
+
top: position.top,
|
|
104
|
+
width: position.maxWidth,
|
|
105
|
+
}, role: "tooltip", children: normalizedContent }), document.body)
|
|
106
|
+
: null] }));
|
|
46
107
|
}
|
|
47
108
|
|
|
48
109
|
exports.InfoTooltip = InfoTooltip;
|
|
@@ -1,21 +1,69 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
3
3
|
import { useRef, useState, useEffect } from 'react';
|
|
4
|
+
import { createPortal } from 'react-dom';
|
|
4
5
|
import { CircleQuestionMarkIcon } from '@windrun-huaiin/base-ui/icons';
|
|
5
6
|
import { themeIconColor, themeRingColor, themeBorderColor } from '@windrun-huaiin/base-ui/lib';
|
|
6
7
|
import { cn } from '@windrun-huaiin/lib/utils';
|
|
7
8
|
|
|
9
|
+
const TOOLTIP_MARGIN = 12;
|
|
10
|
+
const TOOLTIP_GAP = 8;
|
|
11
|
+
const TOOLTIP_MAX_WIDTH = 288;
|
|
12
|
+
function clamp(value, min, max) {
|
|
13
|
+
return Math.min(Math.max(value, min), max);
|
|
14
|
+
}
|
|
15
|
+
function getTooltipPosition(target, align, desktopSide) {
|
|
16
|
+
const rect = target.getBoundingClientRect();
|
|
17
|
+
const viewportWidth = window.innerWidth;
|
|
18
|
+
const viewportHeight = window.innerHeight;
|
|
19
|
+
const maxWidth = Math.min(TOOLTIP_MAX_WIDTH, Math.max(160, viewportWidth - TOOLTIP_MARGIN * 2));
|
|
20
|
+
const useInlineSide = desktopSide === 'right' && viewportWidth >= 768;
|
|
21
|
+
if (useInlineSide) {
|
|
22
|
+
const rightSpace = viewportWidth - rect.right - TOOLTIP_GAP - TOOLTIP_MARGIN;
|
|
23
|
+
const leftSpace = rect.left - TOOLTIP_GAP - TOOLTIP_MARGIN;
|
|
24
|
+
const placeRight = rightSpace >= Math.min(220, maxWidth) || rightSpace >= leftSpace;
|
|
25
|
+
const preferredLeft = placeRight
|
|
26
|
+
? rect.right + TOOLTIP_GAP
|
|
27
|
+
: rect.left - maxWidth - TOOLTIP_GAP;
|
|
28
|
+
return {
|
|
29
|
+
left: clamp(preferredLeft, TOOLTIP_MARGIN, viewportWidth - maxWidth - TOOLTIP_MARGIN),
|
|
30
|
+
top: clamp(rect.top + rect.height / 2, TOOLTIP_MARGIN + 40, viewportHeight - TOOLTIP_MARGIN - 40),
|
|
31
|
+
maxWidth,
|
|
32
|
+
side: 'inline',
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
const preferredLeft = align === 'start'
|
|
36
|
+
? rect.left
|
|
37
|
+
: rect.right - maxWidth;
|
|
38
|
+
return {
|
|
39
|
+
left: clamp(preferredLeft, TOOLTIP_MARGIN, viewportWidth - maxWidth - TOOLTIP_MARGIN),
|
|
40
|
+
top: Math.min(rect.bottom + TOOLTIP_GAP, viewportHeight - TOOLTIP_MARGIN),
|
|
41
|
+
maxWidth,
|
|
42
|
+
side: 'bottom',
|
|
43
|
+
};
|
|
44
|
+
}
|
|
8
45
|
function InfoTooltip({ content, className, align = 'end', desktopSide = 'right', }) {
|
|
9
46
|
const normalizedContent = content.trim();
|
|
10
47
|
const containerRef = useRef(null);
|
|
48
|
+
const tooltipRef = useRef(null);
|
|
11
49
|
const [open, setOpen] = useState(false);
|
|
50
|
+
const [position, setPosition] = useState(null);
|
|
51
|
+
const updatePosition = () => {
|
|
52
|
+
if (!containerRef.current) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
setPosition(getTooltipPosition(containerRef.current, align, desktopSide));
|
|
56
|
+
};
|
|
12
57
|
useEffect(() => {
|
|
13
58
|
function handlePointerDown(event) {
|
|
59
|
+
var _a;
|
|
14
60
|
if (!containerRef.current) {
|
|
15
61
|
return;
|
|
16
62
|
}
|
|
17
63
|
const target = event.target;
|
|
18
|
-
if (target instanceof Node &&
|
|
64
|
+
if (target instanceof Node &&
|
|
65
|
+
!containerRef.current.contains(target) &&
|
|
66
|
+
!((_a = tooltipRef.current) === null || _a === void 0 ? void 0 : _a.contains(target))) {
|
|
19
67
|
setOpen(false);
|
|
20
68
|
}
|
|
21
69
|
}
|
|
@@ -26,21 +74,34 @@ function InfoTooltip({ content, className, align = 'end', desktopSide = 'right',
|
|
|
26
74
|
document.removeEventListener('touchstart', handlePointerDown);
|
|
27
75
|
};
|
|
28
76
|
}, []);
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
if (!open) {
|
|
79
|
+
setPosition(null);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
updatePosition();
|
|
83
|
+
window.addEventListener('resize', updatePosition);
|
|
84
|
+
window.addEventListener('scroll', updatePosition, true);
|
|
85
|
+
return () => {
|
|
86
|
+
window.removeEventListener('resize', updatePosition);
|
|
87
|
+
window.removeEventListener('scroll', updatePosition, true);
|
|
88
|
+
};
|
|
89
|
+
}, [align, desktopSide, open]);
|
|
29
90
|
if (!normalizedContent) {
|
|
30
91
|
return null;
|
|
31
92
|
}
|
|
32
|
-
return (jsxs("span", { ref: containerRef, className: cn('
|
|
93
|
+
return (jsxs("span", { ref: containerRef, className: cn('inline-flex h-5 w-5 shrink-0 align-middle', className), onMouseLeave: () => setOpen(false), children: [jsx("button", { type: "button", onMouseEnter: () => setOpen(true), onPointerDown: (event) => {
|
|
33
94
|
event.stopPropagation();
|
|
34
95
|
}, onClick: (event) => {
|
|
35
96
|
event.stopPropagation();
|
|
36
97
|
setOpen((value) => !value);
|
|
37
|
-
}, className: cn('inline-flex h-5 w-5 items-center justify-center rounded-full text-slate-400 transition', 'hover:bg-black/5 hover:dark:bg-white/5', 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 dark:focus-visible:ring-offset-slate-950', 'hover:text-slate-700 dark:hover:text-white focus-visible:text-slate-700 dark:focus-visible:text-white', themeIconColor, themeRingColor), "aria-label": normalizedContent, "aria-expanded": open, children: jsx(CircleQuestionMarkIcon, { className: "h-4 w-4" }) }),
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
:
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
98
|
+
}, className: cn('inline-flex h-5 w-5 items-center justify-center rounded-full text-slate-400 transition', 'hover:bg-black/5 hover:dark:bg-white/5', 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 dark:focus-visible:ring-offset-slate-950', 'hover:text-slate-700 dark:hover:text-white focus-visible:text-slate-700 dark:focus-visible:text-white', themeIconColor, themeRingColor), "aria-label": normalizedContent, "aria-expanded": open, children: jsx(CircleQuestionMarkIcon, { className: "h-4 w-4" }) }), open && position
|
|
99
|
+
? createPortal(jsx("span", { ref: tooltipRef, className: cn('pointer-events-none fixed z-50 max-h-[calc(100vh-1.5rem)] overflow-y-auto rounded-2xl border bg-white/95 px-3 py-2 text-xs leading-5 text-slate-600 shadow-xl backdrop-blur-sm dark:bg-slate-950/95 dark:text-slate-300', position.side === 'inline' && '-translate-y-1/2', themeBorderColor), style: {
|
|
100
|
+
left: position.left,
|
|
101
|
+
top: position.top,
|
|
102
|
+
width: position.maxWidth,
|
|
103
|
+
}, role: "tooltip", children: normalizedContent }), document.body)
|
|
104
|
+
: null] }));
|
|
44
105
|
}
|
|
45
106
|
|
|
46
107
|
export { InfoTooltip };
|
package/dist/main/loading.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ interface LoadingProps {
|
|
|
5
5
|
className?: string;
|
|
6
6
|
label?: string;
|
|
7
7
|
labelClassName?: string;
|
|
8
|
+
paused?: boolean;
|
|
8
9
|
}
|
|
9
|
-
export declare function Loading({ themeColor, compact, className, label, labelClassName, }?: LoadingProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export declare function Loading({ themeColor, compact, className, label, labelClassName, paused, }?: LoadingProps): import("react/jsx-runtime").JSX.Element;
|
|
10
11
|
export {};
|
package/dist/main/loading.js
CHANGED
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var jsxRuntime = require('react/jsx-runtime');
|
|
5
|
+
var React = require('react');
|
|
5
6
|
var utils = require('@windrun-huaiin/lib/utils');
|
|
6
7
|
var lib = require('@windrun-huaiin/base-ui/lib');
|
|
8
|
+
var animejs = require('animejs');
|
|
7
9
|
|
|
8
10
|
const NUM_ROWS = 15;
|
|
9
11
|
const NUM_COLS = 15;
|
|
@@ -53,36 +55,77 @@ function createLoadingPalette(baseHex) {
|
|
|
53
55
|
shiftColor(baseHex, { r: -24, g: -14, b: 6 }),
|
|
54
56
|
];
|
|
55
57
|
}
|
|
56
|
-
function Loading({ themeColor = lib.themeSvgIconColor, compact = false, className, label = 'Loading...', labelClassName, } = {}) {
|
|
57
|
-
const
|
|
58
|
-
const
|
|
58
|
+
function Loading({ themeColor = lib.themeSvgIconColor, compact = false, className, label = 'Loading...', labelClassName, paused = false, } = {}) {
|
|
59
|
+
const gridRef = React.useRef(null);
|
|
60
|
+
const animationRef = React.useRef(null);
|
|
61
|
+
const pausedRef = React.useRef(paused);
|
|
62
|
+
const colors = React.useMemo(() => createLoadingPalette(themeColor), [themeColor]);
|
|
59
63
|
const centerX = (NUM_COLS - 1) / 2;
|
|
60
64
|
const centerY = (NUM_ROWS - 1) / 2;
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
65
|
+
const dots = React.useMemo(() => {
|
|
66
|
+
const nextDots = [];
|
|
67
|
+
for (let i = 0; i < NUM_ROWS; i++) {
|
|
68
|
+
for (let j = 0; j < NUM_COLS; j++) {
|
|
69
|
+
const distance = Math.sqrt(Math.pow(i - centerY, 2) + Math.pow(j - centerX, 2));
|
|
70
|
+
nextDots.push({
|
|
71
|
+
id: `${i}-${j}`,
|
|
72
|
+
row: i,
|
|
73
|
+
col: j,
|
|
74
|
+
delay: distance * STAGGER_DELAY_FACTOR,
|
|
75
|
+
color: colors[Math.floor(distance) % colors.length],
|
|
76
|
+
});
|
|
77
|
+
}
|
|
74
78
|
}
|
|
75
|
-
|
|
79
|
+
return nextDots;
|
|
80
|
+
}, [centerX, centerY, colors]);
|
|
76
81
|
// Calculate the total width and height of the dot container
|
|
77
82
|
const containerWidth = (NUM_COLS - 1) * SPACING + DOT_SIZE;
|
|
78
83
|
const containerHeight = (NUM_ROWS - 1) * SPACING + DOT_SIZE;
|
|
79
|
-
|
|
84
|
+
pausedRef.current = paused;
|
|
85
|
+
React.useEffect(() => {
|
|
86
|
+
var _a;
|
|
87
|
+
const grid = gridRef.current;
|
|
88
|
+
if (!grid) {
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
const dotNodes = Array.from(grid.querySelectorAll('[data-loading-dot]'));
|
|
92
|
+
(_a = animationRef.current) === null || _a === void 0 ? void 0 : _a.revert();
|
|
93
|
+
animationRef.current = animejs.animate(dotNodes, {
|
|
94
|
+
opacity: [0, 1, 0.7, 0],
|
|
95
|
+
scale: [0.2, 1.2, 0.8, 0.2],
|
|
96
|
+
duration: ANIMATION_DURATION * 1000,
|
|
97
|
+
delay: (target) => { var _a; return Number((_a = target === null || target === void 0 ? void 0 : target.dataset.loadingDelay) !== null && _a !== void 0 ? _a : 0) * 1000; },
|
|
98
|
+
ease: 'inOutSine',
|
|
99
|
+
loop: true,
|
|
100
|
+
});
|
|
101
|
+
if (pausedRef.current) {
|
|
102
|
+
animationRef.current.pause();
|
|
103
|
+
}
|
|
104
|
+
return () => {
|
|
105
|
+
var _a;
|
|
106
|
+
(_a = animationRef.current) === null || _a === void 0 ? void 0 : _a.revert();
|
|
107
|
+
animationRef.current = null;
|
|
108
|
+
};
|
|
109
|
+
}, [dots]);
|
|
110
|
+
React.useEffect(() => {
|
|
111
|
+
const animation = animationRef.current;
|
|
112
|
+
if (!animation) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (paused) {
|
|
116
|
+
animation.pause();
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
animation.play();
|
|
120
|
+
}
|
|
121
|
+
}, [paused]);
|
|
122
|
+
return (jsxRuntime.jsx("div", { className: utils.cn('flex flex-col items-center justify-center bg-neutral-100 dark:bg-neutral-900', compact ? 'min-h-[250px] rounded-[28px] px-4 py-2' : 'min-h-screen', className), children: jsxRuntime.jsxs("div", { ref: gridRef, style: {
|
|
80
123
|
width: containerWidth,
|
|
81
124
|
height: containerHeight,
|
|
82
125
|
position: 'relative',
|
|
83
126
|
borderRadius: '50%', // Make the container circular
|
|
84
127
|
overflow: 'hidden', // Clip dots outside the circle
|
|
85
|
-
}, children: [dots.map(dot => (jsxRuntime.jsx("div", { style: {
|
|
128
|
+
}, children: [dots.map(dot => (jsxRuntime.jsx("div", { "data-loading-dot": "", "data-loading-delay": dot.delay, style: {
|
|
86
129
|
position: 'absolute',
|
|
87
130
|
left: dot.col * SPACING,
|
|
88
131
|
top: dot.row * SPACING,
|
|
@@ -90,13 +133,8 @@ function Loading({ themeColor = lib.themeSvgIconColor, compact = false, classNam
|
|
|
90
133
|
height: DOT_SIZE,
|
|
91
134
|
backgroundColor: dot.color,
|
|
92
135
|
borderRadius: '50%',
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
animationTimingFunction: 'cubic-bezier(0.45, 0, 0.55, 1)',
|
|
96
|
-
animationIterationCount: 'infinite',
|
|
97
|
-
animationDelay: `${dot.delay}s`,
|
|
98
|
-
opacity: 0,
|
|
99
|
-
transform: 'scale(0)',
|
|
136
|
+
opacity: 0.35,
|
|
137
|
+
transform: 'scale(0.2)',
|
|
100
138
|
} }, dot.id))), jsxRuntime.jsx("div", { className: "absolute inset-0 flex items-center justify-center", style: { pointerEvents: 'none' }, children: jsxRuntime.jsx("p", { className: utils.cn('text-xl font-semibold text-white', labelClassName), children: label }) })] }) }));
|
|
101
139
|
}
|
|
102
140
|
|
package/dist/main/loading.mjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
3
|
+
import { useRef, useMemo, useEffect } from 'react';
|
|
3
4
|
import { cn } from '@windrun-huaiin/lib/utils';
|
|
4
5
|
import { themeSvgIconColor } from '@windrun-huaiin/base-ui/lib';
|
|
6
|
+
import { animate } from 'animejs';
|
|
5
7
|
|
|
6
8
|
const NUM_ROWS = 15;
|
|
7
9
|
const NUM_COLS = 15;
|
|
@@ -51,36 +53,77 @@ function createLoadingPalette(baseHex) {
|
|
|
51
53
|
shiftColor(baseHex, { r: -24, g: -14, b: 6 }),
|
|
52
54
|
];
|
|
53
55
|
}
|
|
54
|
-
function Loading({ themeColor = themeSvgIconColor, compact = false, className, label = 'Loading...', labelClassName, } = {}) {
|
|
55
|
-
const
|
|
56
|
-
const
|
|
56
|
+
function Loading({ themeColor = themeSvgIconColor, compact = false, className, label = 'Loading...', labelClassName, paused = false, } = {}) {
|
|
57
|
+
const gridRef = useRef(null);
|
|
58
|
+
const animationRef = useRef(null);
|
|
59
|
+
const pausedRef = useRef(paused);
|
|
60
|
+
const colors = useMemo(() => createLoadingPalette(themeColor), [themeColor]);
|
|
57
61
|
const centerX = (NUM_COLS - 1) / 2;
|
|
58
62
|
const centerY = (NUM_ROWS - 1) / 2;
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
63
|
+
const dots = useMemo(() => {
|
|
64
|
+
const nextDots = [];
|
|
65
|
+
for (let i = 0; i < NUM_ROWS; i++) {
|
|
66
|
+
for (let j = 0; j < NUM_COLS; j++) {
|
|
67
|
+
const distance = Math.sqrt(Math.pow(i - centerY, 2) + Math.pow(j - centerX, 2));
|
|
68
|
+
nextDots.push({
|
|
69
|
+
id: `${i}-${j}`,
|
|
70
|
+
row: i,
|
|
71
|
+
col: j,
|
|
72
|
+
delay: distance * STAGGER_DELAY_FACTOR,
|
|
73
|
+
color: colors[Math.floor(distance) % colors.length],
|
|
74
|
+
});
|
|
75
|
+
}
|
|
72
76
|
}
|
|
73
|
-
|
|
77
|
+
return nextDots;
|
|
78
|
+
}, [centerX, centerY, colors]);
|
|
74
79
|
// Calculate the total width and height of the dot container
|
|
75
80
|
const containerWidth = (NUM_COLS - 1) * SPACING + DOT_SIZE;
|
|
76
81
|
const containerHeight = (NUM_ROWS - 1) * SPACING + DOT_SIZE;
|
|
77
|
-
|
|
82
|
+
pausedRef.current = paused;
|
|
83
|
+
useEffect(() => {
|
|
84
|
+
var _a;
|
|
85
|
+
const grid = gridRef.current;
|
|
86
|
+
if (!grid) {
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
const dotNodes = Array.from(grid.querySelectorAll('[data-loading-dot]'));
|
|
90
|
+
(_a = animationRef.current) === null || _a === void 0 ? void 0 : _a.revert();
|
|
91
|
+
animationRef.current = animate(dotNodes, {
|
|
92
|
+
opacity: [0, 1, 0.7, 0],
|
|
93
|
+
scale: [0.2, 1.2, 0.8, 0.2],
|
|
94
|
+
duration: ANIMATION_DURATION * 1000,
|
|
95
|
+
delay: (target) => { var _a; return Number((_a = target === null || target === void 0 ? void 0 : target.dataset.loadingDelay) !== null && _a !== void 0 ? _a : 0) * 1000; },
|
|
96
|
+
ease: 'inOutSine',
|
|
97
|
+
loop: true,
|
|
98
|
+
});
|
|
99
|
+
if (pausedRef.current) {
|
|
100
|
+
animationRef.current.pause();
|
|
101
|
+
}
|
|
102
|
+
return () => {
|
|
103
|
+
var _a;
|
|
104
|
+
(_a = animationRef.current) === null || _a === void 0 ? void 0 : _a.revert();
|
|
105
|
+
animationRef.current = null;
|
|
106
|
+
};
|
|
107
|
+
}, [dots]);
|
|
108
|
+
useEffect(() => {
|
|
109
|
+
const animation = animationRef.current;
|
|
110
|
+
if (!animation) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (paused) {
|
|
114
|
+
animation.pause();
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
animation.play();
|
|
118
|
+
}
|
|
119
|
+
}, [paused]);
|
|
120
|
+
return (jsx("div", { className: cn('flex flex-col items-center justify-center bg-neutral-100 dark:bg-neutral-900', compact ? 'min-h-[250px] rounded-[28px] px-4 py-2' : 'min-h-screen', className), children: jsxs("div", { ref: gridRef, style: {
|
|
78
121
|
width: containerWidth,
|
|
79
122
|
height: containerHeight,
|
|
80
123
|
position: 'relative',
|
|
81
124
|
borderRadius: '50%', // Make the container circular
|
|
82
125
|
overflow: 'hidden', // Clip dots outside the circle
|
|
83
|
-
}, children: [dots.map(dot => (jsx("div", { style: {
|
|
126
|
+
}, children: [dots.map(dot => (jsx("div", { "data-loading-dot": "", "data-loading-delay": dot.delay, style: {
|
|
84
127
|
position: 'absolute',
|
|
85
128
|
left: dot.col * SPACING,
|
|
86
129
|
top: dot.row * SPACING,
|
|
@@ -88,13 +131,8 @@ function Loading({ themeColor = themeSvgIconColor, compact = false, className, l
|
|
|
88
131
|
height: DOT_SIZE,
|
|
89
132
|
backgroundColor: dot.color,
|
|
90
133
|
borderRadius: '50%',
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
animationTimingFunction: 'cubic-bezier(0.45, 0, 0.55, 1)',
|
|
94
|
-
animationIterationCount: 'infinite',
|
|
95
|
-
animationDelay: `${dot.delay}s`,
|
|
96
|
-
opacity: 0,
|
|
97
|
-
transform: 'scale(0)',
|
|
134
|
+
opacity: 0.35,
|
|
135
|
+
transform: 'scale(0.2)',
|
|
98
136
|
} }, dot.id))), jsx("div", { className: "absolute inset-0 flex items-center justify-center", style: { pointerEvents: 'none' }, children: jsx("p", { className: cn('text-xl font-semibold text-white', labelClassName), children: label }) })] }) }));
|
|
99
137
|
}
|
|
100
138
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { MotionBeamFrame, MotionBeamFrame as BeamFrame, type BeamFrameProps, type BeamFrameTone, } from './motion-beam-frame';
|