@particle-network/ui-react 0.7.0-beta.2 → 0.7.0-beta.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/ProgressWrapper/index.js +47 -45
- package/dist/components/UXButton/button-theme.js +8 -8
- package/dist/components/UXColorPicker/color-fields.js +1 -1
- package/dist/components/UXHint/index.d.ts +6 -3
- package/dist/components/UXHint/index.js +9 -19
- package/dist/components/UXSimplePopover/index.d.ts +1 -0
- package/dist/components/UXSimplePopover/index.js +1 -0
- package/dist/components/UXSimplePopover/provider.d.ts +22 -0
- package/dist/components/UXSimplePopover/provider.js +197 -0
- package/dist/components/UXSimplePopover/simple-popover.d.ts +8 -3
- package/dist/components/UXSimplePopover/simple-popover.js +114 -104
- package/dist/components/UXTable/base/index.d.ts +10 -0
- package/dist/components/UXTable/base/index.js +6 -0
- package/dist/components/UXTable/base/table-body.d.ts +20 -0
- package/dist/components/UXTable/base/table-body.js +4 -0
- package/dist/components/UXTable/base/table-cell.d.ts +6 -0
- package/dist/components/UXTable/base/table-cell.js +4 -0
- package/dist/components/UXTable/base/table-column.d.ts +6 -0
- package/dist/components/UXTable/base/table-column.js +4 -0
- package/dist/components/UXTable/base/table-header.d.ts +6 -0
- package/dist/components/UXTable/base/table-header.js +4 -0
- package/dist/components/UXTable/base/table-row.d.ts +6 -0
- package/dist/components/UXTable/base/table-row.js +4 -0
- package/dist/components/UXTable/index.d.ts +7 -37
- package/dist/components/UXTable/index.js +5 -14
- package/dist/components/UXTable/table-body.d.ts +15 -0
- package/dist/components/UXTable/table-body.js +87 -0
- package/dist/components/UXTable/table-cell.d.ts +19 -0
- package/dist/components/UXTable/table-cell.js +45 -0
- package/dist/components/UXTable/table-checkbox-cell.d.ts +23 -0
- package/dist/components/UXTable/table-checkbox-cell.js +48 -0
- package/dist/components/UXTable/table-column-header.d.ts +25 -0
- package/dist/components/UXTable/table-column-header.js +66 -0
- package/dist/components/UXTable/table-header-row.d.ts +14 -0
- package/dist/components/UXTable/table-header-row.js +29 -0
- package/dist/components/UXTable/table-row-group.d.ts +8 -0
- package/dist/components/UXTable/table-row-group.js +24 -0
- package/dist/components/UXTable/table-row.d.ts +15 -0
- package/dist/components/UXTable/table-row.js +61 -0
- package/dist/components/UXTable/table-select-all-checkbox.d.ts +18 -0
- package/dist/components/UXTable/table-select-all-checkbox.js +46 -0
- package/dist/components/UXTable/table-theme.d.ts +452 -0
- package/dist/components/UXTable/table-theme.js +282 -0
- package/dist/components/UXTable/table.d.ts +8 -0
- package/dist/components/UXTable/table.js +96 -0
- package/dist/components/UXTable/use-table.d.ts +145 -0
- package/dist/components/UXTable/use-table.js +127 -0
- package/dist/components/UXTable/virtualized-table-body.d.ts +17 -0
- package/dist/components/UXTable/virtualized-table-body.js +107 -0
- package/dist/components/UXTable/virtualized-table.d.ts +8 -0
- package/dist/components/UXTable/virtualized-table.js +115 -0
- package/dist/components/UXThemeSwitch/theme-switch.js +8 -1
- package/dist/components/UXThemeSwitch/use-theme.js +1 -1
- package/dist/components/UXToast/index.d.ts +4 -1
- package/dist/components/UXToast/index.js +2 -2
- package/dist/components/layout/Box/box-theme.d.ts +2 -2
- package/dist/components/layout/Box/box-theme.js +1 -1
- package/dist/components/typography/text-theme.d.ts +2 -2
- package/dist/components/typography/text-theme.js +1 -1
- package/package.json +10 -4
- package/dist/components/UXTable/table.extend.d.ts +0 -34
- package/dist/components/UXTable/table.extend.js +0 -145
|
@@ -5,36 +5,61 @@ import { radiusMap, useThemeColor } from "@particle-network/ui-shared";
|
|
|
5
5
|
import { useSize } from "ahooks";
|
|
6
6
|
import { cn } from "../../utils/index.js";
|
|
7
7
|
import { Center } from "../layout/index.js";
|
|
8
|
+
function createPathData(x, y, w, h, r) {
|
|
9
|
+
if (0 === r) return `
|
|
10
|
+
M ${x + w} ${y + h}
|
|
11
|
+
L ${x} ${y + h}
|
|
12
|
+
L ${x} ${y}
|
|
13
|
+
L ${x + w} ${y}
|
|
14
|
+
Z
|
|
15
|
+
`;
|
|
16
|
+
return `
|
|
17
|
+
M ${x + w - r} ${y + h}
|
|
18
|
+
L ${x + r} ${y + h}
|
|
19
|
+
Q ${x} ${y + h} ${x} ${y + h - r}
|
|
20
|
+
L ${x} ${y + r}
|
|
21
|
+
Q ${x} ${y} ${x + r} ${y}
|
|
22
|
+
L ${x + w - r} ${y}
|
|
23
|
+
Q ${x + w} ${y} ${x + w} ${y + r}
|
|
24
|
+
L ${x + w} ${y + h - r}
|
|
25
|
+
Q ${x + w} ${y + h} ${x + w - r} ${y + h}
|
|
26
|
+
Z
|
|
27
|
+
`;
|
|
28
|
+
}
|
|
8
29
|
const ProgressWrapper = ({ className, value = 0, width, height, radius = 'sm', strokeWidth = 1, color = 'primary', children, svgClassName, ...restProps })=>{
|
|
9
30
|
const uxColors = useThemeColor();
|
|
10
31
|
const autoLayout = !width && !height;
|
|
11
32
|
const containerRef = useRef(null);
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const widthValue = useMemo(()=>{
|
|
17
|
-
|
|
18
|
-
|
|
33
|
+
const size = useSize(autoLayout ? containerRef : void 0);
|
|
34
|
+
const childWidth = size?.width ?? 0;
|
|
35
|
+
const childHeight = size?.height ?? 0;
|
|
36
|
+
const radiusValue = 'number' == typeof radius ? radius : radiusMap[radius];
|
|
37
|
+
const { widthValue, heightValue, pathData, perimeter, strokeDashoffset } = useMemo(()=>{
|
|
38
|
+
const w = width ?? childWidth + 2 * strokeWidth;
|
|
39
|
+
const h = height ?? childHeight + 2 * strokeWidth;
|
|
40
|
+
const rectWidth = w - strokeWidth;
|
|
41
|
+
const rectHeight = h - strokeWidth;
|
|
42
|
+
const rectXY = strokeWidth / 2;
|
|
43
|
+
const p = 2 * (rectWidth + rectHeight);
|
|
44
|
+
const clamped = Math.max(0, Math.min(100, value));
|
|
45
|
+
const offset = p * (1 - clamped / 100);
|
|
46
|
+
const path = createPathData(rectXY, rectXY, rectWidth, rectHeight, radiusValue);
|
|
47
|
+
return {
|
|
48
|
+
widthValue: w,
|
|
49
|
+
heightValue: h,
|
|
50
|
+
pathData: path,
|
|
51
|
+
perimeter: p,
|
|
52
|
+
strokeDashoffset: offset
|
|
53
|
+
};
|
|
19
54
|
}, [
|
|
55
|
+
width,
|
|
56
|
+
height,
|
|
20
57
|
childWidth,
|
|
21
|
-
strokeWidth,
|
|
22
|
-
width
|
|
23
|
-
]);
|
|
24
|
-
const heightValue = useMemo(()=>{
|
|
25
|
-
if (height) return height;
|
|
26
|
-
return childHeight + 2 * strokeWidth;
|
|
27
|
-
}, [
|
|
28
58
|
childHeight,
|
|
29
59
|
strokeWidth,
|
|
30
|
-
|
|
60
|
+
value,
|
|
61
|
+
radiusValue
|
|
31
62
|
]);
|
|
32
|
-
const clampedProgress = Math.max(0, Math.min(100, value));
|
|
33
|
-
const rectWidth = widthValue - strokeWidth;
|
|
34
|
-
const rectHeight = heightValue - strokeWidth;
|
|
35
|
-
const rectXY = strokeWidth / 2;
|
|
36
|
-
const perimeter = 2 * (rectWidth + rectHeight);
|
|
37
|
-
const strokeDashoffset = perimeter * (1 - clampedProgress / 100);
|
|
38
63
|
const colorValue = useMemo(()=>{
|
|
39
64
|
if ('transparent' === color) return 'transparent';
|
|
40
65
|
if (color.startsWith('#')) return color;
|
|
@@ -50,29 +75,6 @@ const ProgressWrapper = ({ className, value = 0, width, height, radius = 'sm', s
|
|
|
50
75
|
color,
|
|
51
76
|
colorValue
|
|
52
77
|
]);
|
|
53
|
-
const radiusValue = 'number' == typeof radius ? radius : radiusMap[radius];
|
|
54
|
-
const createPathData = (x, y, w, h, r)=>{
|
|
55
|
-
if (0 === r) return `
|
|
56
|
-
M ${x + w} ${y + h}
|
|
57
|
-
L ${x} ${y + h}
|
|
58
|
-
L ${x} ${y}
|
|
59
|
-
L ${x + w} ${y}
|
|
60
|
-
Z
|
|
61
|
-
`;
|
|
62
|
-
return `
|
|
63
|
-
M ${x + w - r} ${y + h}
|
|
64
|
-
L ${x + r} ${y + h}
|
|
65
|
-
Q ${x} ${y + h} ${x} ${y + h - r}
|
|
66
|
-
L ${x} ${y + r}
|
|
67
|
-
Q ${x} ${y} ${x + r} ${y}
|
|
68
|
-
L ${x + w - r} ${y}
|
|
69
|
-
Q ${x + w} ${y} ${x + w} ${y + r}
|
|
70
|
-
L ${x + w} ${y + h - r}
|
|
71
|
-
Q ${x + w} ${y + h} ${x + w - r} ${y + h}
|
|
72
|
-
Z
|
|
73
|
-
`;
|
|
74
|
-
};
|
|
75
|
-
const pathData = createPathData(rectXY, rectXY, rectWidth, rectHeight, radiusValue);
|
|
76
78
|
return /*#__PURE__*/ jsxs(Center, {
|
|
77
79
|
style: {
|
|
78
80
|
width: `${widthValue}px`,
|
|
@@ -82,7 +84,7 @@ const ProgressWrapper = ({ className, value = 0, width, height, radius = 'sm', s
|
|
|
82
84
|
...restProps,
|
|
83
85
|
children: [
|
|
84
86
|
/*#__PURE__*/ jsxs("svg", {
|
|
85
|
-
className: cn('absolute
|
|
87
|
+
className: cn('absolute top-0 left-0', svgClassName),
|
|
86
88
|
width: widthValue,
|
|
87
89
|
height: heightValue,
|
|
88
90
|
children: [
|
|
@@ -33,10 +33,10 @@ const button_theme_button = tv({
|
|
|
33
33
|
text: 'bg-transparent min-w-0 w-auto h-auto px-0'
|
|
34
34
|
},
|
|
35
35
|
size: {
|
|
36
|
-
xs: 'gap-1 rounded-
|
|
37
|
-
sm: 'gap-1 rounded-
|
|
38
|
-
md: 'gap-1 rounded-
|
|
39
|
-
lg: 'gap-1 rounded-
|
|
36
|
+
xs: 'gap-1 rounded-[4px] !text-caption1 min-w-min font-medium [&>svg]:size-[14px]',
|
|
37
|
+
sm: 'gap-1 rounded-[6px] !text-body3 min-w-min font-medium [&>svg]:size-4',
|
|
38
|
+
md: 'gap-1 rounded-[6px] text-tiny min-w-min font-medium [&>svg]:size-[18px]',
|
|
39
|
+
lg: 'gap-1 rounded-[8px] text-sm min-w-min font-medium [&>svg]:size-5',
|
|
40
40
|
xl: 'gap-1 rounded-[10px] text-medium min-w-min font-medium [&>svg]:size-6',
|
|
41
41
|
auto: 'min-w-min rounded-[10px]'
|
|
42
42
|
},
|
|
@@ -492,22 +492,22 @@ const button_theme_button = tv({
|
|
|
492
492
|
{
|
|
493
493
|
isInGroup: true,
|
|
494
494
|
size: 'xs',
|
|
495
|
-
class: 'rounded-none first:rounded-s-
|
|
495
|
+
class: 'rounded-none first:rounded-s-[4px] last:rounded-e-[4px]'
|
|
496
496
|
},
|
|
497
497
|
{
|
|
498
498
|
isInGroup: true,
|
|
499
499
|
size: 'sm',
|
|
500
|
-
class: 'rounded-none first:rounded-s-
|
|
500
|
+
class: 'rounded-none first:rounded-s-[6px] last:rounded-e-[6px]'
|
|
501
501
|
},
|
|
502
502
|
{
|
|
503
503
|
isInGroup: true,
|
|
504
504
|
size: 'md',
|
|
505
|
-
class: 'rounded-none first:rounded-s-
|
|
505
|
+
class: 'rounded-none first:rounded-s-[6px] last:rounded-e-[6px]'
|
|
506
506
|
},
|
|
507
507
|
{
|
|
508
508
|
isInGroup: true,
|
|
509
509
|
size: 'lg',
|
|
510
|
-
class: 'rounded-none first:rounded-s-
|
|
510
|
+
class: 'rounded-none first:rounded-s-[8px] last:rounded-e-[8px]'
|
|
511
511
|
},
|
|
512
512
|
{
|
|
513
513
|
isInGroup: true,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useCallback, useState } from "react";
|
|
4
|
-
import
|
|
4
|
+
import Switch3Icon from "@particle-network/icons/web/Switch3Icon";
|
|
5
5
|
import { Flex, VStack } from "../layout/index.js";
|
|
6
6
|
import { Text } from "../typography/Text.js";
|
|
7
7
|
import { UXButton } from "../UXButton/index.js";
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { type
|
|
3
|
-
export
|
|
2
|
+
import { type SimplePopoverPlacement } from '..';
|
|
3
|
+
export interface UXHintProps {
|
|
4
|
+
content?: React.ReactNode;
|
|
5
|
+
children?: React.ReactNode;
|
|
4
6
|
triggerType?: 'hover' | 'click';
|
|
7
|
+
placement?: SimplePopoverPlacement;
|
|
5
8
|
buttonClassName?: string;
|
|
6
9
|
iconClassName?: string;
|
|
7
|
-
}
|
|
10
|
+
}
|
|
8
11
|
export declare const UXHint: React.FC<UXHintProps>;
|
|
@@ -1,31 +1,21 @@
|
|
|
1
|
-
import { jsx
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
2
|
import "react";
|
|
3
3
|
import CircleQuestionIcon from "@particle-network/icons/web/CircleQuestionIcon";
|
|
4
|
-
import { Center,
|
|
4
|
+
import { Center, UXSimplePopover } from "../index.js";
|
|
5
5
|
import { cn } from "../../utils/index.js";
|
|
6
6
|
const UXHint = (props)=>{
|
|
7
|
-
const { content, children, buttonClassName, iconClassName, triggerType = 'hover',
|
|
8
|
-
|
|
7
|
+
const { content, children, buttonClassName, iconClassName, triggerType = 'hover', placement = 'top' } = props;
|
|
8
|
+
return /*#__PURE__*/ jsx(UXSimplePopover, {
|
|
9
|
+
content: content || children,
|
|
10
|
+
triggerType: triggerType,
|
|
11
|
+
placement: placement,
|
|
12
|
+
children: /*#__PURE__*/ jsx(Center, {
|
|
9
13
|
className: cn('min-h-4 min-w-4 cursor-pointer', buttonClassName),
|
|
10
14
|
children: /*#__PURE__*/ jsx(CircleQuestionIcon, {
|
|
11
15
|
size: 14,
|
|
12
16
|
className: iconClassName
|
|
13
17
|
})
|
|
14
|
-
})
|
|
15
|
-
if ('hover' === triggerType) return /*#__PURE__*/ jsx(UXTooltip, {
|
|
16
|
-
content: content || children,
|
|
17
|
-
...restProps,
|
|
18
|
-
children: renderTriggerContent()
|
|
19
|
-
});
|
|
20
|
-
return /*#__PURE__*/ jsxs(UXPopover, {
|
|
21
|
-
children: [
|
|
22
|
-
/*#__PURE__*/ jsx(UXPopoverTrigger, {
|
|
23
|
-
children: renderTriggerContent()
|
|
24
|
-
}),
|
|
25
|
-
/*#__PURE__*/ jsx(UXPopoverContent, {
|
|
26
|
-
children: content || children
|
|
27
|
-
})
|
|
28
|
-
]
|
|
18
|
+
})
|
|
29
19
|
});
|
|
30
20
|
};
|
|
31
21
|
UXHint.displayName = 'UX.Hint';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { SimplePopoverPlacement, SimplePopoverSize } from './simple-popover';
|
|
3
|
+
export interface TriggerOptions {
|
|
4
|
+
placement?: SimplePopoverPlacement;
|
|
5
|
+
size?: SimplePopoverSize;
|
|
6
|
+
offset?: number;
|
|
7
|
+
delay?: number;
|
|
8
|
+
closeDelay?: number;
|
|
9
|
+
contentClassName?: string;
|
|
10
|
+
}
|
|
11
|
+
interface SimplePopoverCtx {
|
|
12
|
+
show: (anchor: HTMLElement, content: React.ReactNode, options?: TriggerOptions) => void;
|
|
13
|
+
hide: (closeDelay?: number) => void;
|
|
14
|
+
prepare: (anchor: HTMLElement, content: React.ReactNode, options?: TriggerOptions) => void;
|
|
15
|
+
toggle: () => void;
|
|
16
|
+
}
|
|
17
|
+
export declare function useSimplePopoverContext(): SimplePopoverCtx | null;
|
|
18
|
+
export interface UXSimplePopoverProviderProps {
|
|
19
|
+
children: React.ReactNode;
|
|
20
|
+
}
|
|
21
|
+
export declare const UXSimplePopoverProvider: React.FC<UXSimplePopoverProviderProps>;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import react, { createContext, useCallback, useContext, useEffect, useId, useRef, useState } from "react";
|
|
4
|
+
import { tv } from "@heroui/theme";
|
|
5
|
+
import { cn } from "../../utils/index.js";
|
|
6
|
+
const popoverVariants = tv({
|
|
7
|
+
base: 'bg-content1 text-foreground-300 shadow-box text-tiny leading-1.4 rounded-medium max-w-[300px] break-words wrap-break-word antialiased',
|
|
8
|
+
variants: {
|
|
9
|
+
size: {
|
|
10
|
+
sm: 'p-1.5',
|
|
11
|
+
md: 'p-2.5',
|
|
12
|
+
lg: 'p-3.5'
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
defaultVariants: {
|
|
16
|
+
size: 'md'
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
const PopoverContext = /*#__PURE__*/ createContext(null);
|
|
20
|
+
function useSimplePopoverContext() {
|
|
21
|
+
return useContext(PopoverContext);
|
|
22
|
+
}
|
|
23
|
+
const OFFSET_MARGIN = {
|
|
24
|
+
top: {
|
|
25
|
+
marginBottom: 8
|
|
26
|
+
},
|
|
27
|
+
bottom: {
|
|
28
|
+
marginTop: 8
|
|
29
|
+
},
|
|
30
|
+
left: {
|
|
31
|
+
marginRight: 8
|
|
32
|
+
},
|
|
33
|
+
right: {
|
|
34
|
+
marginLeft: 8
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
const MARGIN_SIDE_MAP = {
|
|
38
|
+
top: 'Bottom',
|
|
39
|
+
bottom: 'Top',
|
|
40
|
+
left: 'Right',
|
|
41
|
+
right: 'Left'
|
|
42
|
+
};
|
|
43
|
+
const UXSimplePopoverProvider = ({ children })=>{
|
|
44
|
+
const uid = useId().replace(/:/g, '');
|
|
45
|
+
const popoverRef = useRef(null);
|
|
46
|
+
const openTimerRef = useRef(null);
|
|
47
|
+
const closeTimerRef = useRef(null);
|
|
48
|
+
const triggerModeRef = useRef('hover');
|
|
49
|
+
const currentAnchorRef = useRef(null);
|
|
50
|
+
const [content, setContent] = useState(null);
|
|
51
|
+
const [anchorStyle, setAnchorStyle] = useState({});
|
|
52
|
+
const [contentClassName, setContentClassName] = useState(void 0);
|
|
53
|
+
const [size, setSize] = useState('md');
|
|
54
|
+
const clearTimers = useCallback(()=>{
|
|
55
|
+
if (null !== openTimerRef.current) {
|
|
56
|
+
clearTimeout(openTimerRef.current);
|
|
57
|
+
openTimerRef.current = null;
|
|
58
|
+
}
|
|
59
|
+
if (null !== closeTimerRef.current) {
|
|
60
|
+
clearTimeout(closeTimerRef.current);
|
|
61
|
+
closeTimerRef.current = null;
|
|
62
|
+
}
|
|
63
|
+
}, []);
|
|
64
|
+
const resolveAnchorName = useCallback((anchor)=>{
|
|
65
|
+
if (!anchor.style.getPropertyValue('anchor-name')) anchor.style.setProperty('anchor-name', `--sp-${uid}-${Math.random().toString(36).slice(2, 8)}`);
|
|
66
|
+
return anchor.style.getPropertyValue('anchor-name');
|
|
67
|
+
}, [
|
|
68
|
+
uid
|
|
69
|
+
]);
|
|
70
|
+
const computeAnchorStyle = useCallback((anchorName, options)=>{
|
|
71
|
+
const { placement = 'top', offset = 8 } = options;
|
|
72
|
+
const primarySide = placement.split('-')[0];
|
|
73
|
+
const marginSide = MARGIN_SIDE_MAP[primarySide] ?? 'Bottom';
|
|
74
|
+
const offsetStyle = 8 !== offset ? {
|
|
75
|
+
[`margin${marginSide}`]: offset
|
|
76
|
+
} : OFFSET_MARGIN[primarySide];
|
|
77
|
+
return {
|
|
78
|
+
positionAnchor: anchorName,
|
|
79
|
+
positionArea: placement.replace(/-/g, ' '),
|
|
80
|
+
positionTryFallbacks: 'flip-block, flip-inline, flip-block flip-inline',
|
|
81
|
+
...offsetStyle
|
|
82
|
+
};
|
|
83
|
+
}, []);
|
|
84
|
+
const show = useCallback((anchor, node, options)=>{
|
|
85
|
+
const opts = options ?? {};
|
|
86
|
+
const delay = opts.delay ?? 300;
|
|
87
|
+
clearTimers();
|
|
88
|
+
triggerModeRef.current = 'hover';
|
|
89
|
+
const anchorName = resolveAnchorName(anchor);
|
|
90
|
+
setContent(node);
|
|
91
|
+
setContentClassName(opts.contentClassName);
|
|
92
|
+
setSize(opts.size ?? 'md');
|
|
93
|
+
setAnchorStyle(computeAnchorStyle(anchorName, opts));
|
|
94
|
+
openTimerRef.current = setTimeout(()=>{
|
|
95
|
+
openTimerRef.current = null;
|
|
96
|
+
popoverRef.current?.showPopover();
|
|
97
|
+
}, delay);
|
|
98
|
+
}, [
|
|
99
|
+
clearTimers,
|
|
100
|
+
resolveAnchorName,
|
|
101
|
+
computeAnchorStyle
|
|
102
|
+
]);
|
|
103
|
+
const hide = useCallback((closeDelay)=>{
|
|
104
|
+
const cd = closeDelay ?? 100;
|
|
105
|
+
clearTimers();
|
|
106
|
+
closeTimerRef.current = setTimeout(()=>{
|
|
107
|
+
closeTimerRef.current = null;
|
|
108
|
+
popoverRef.current?.hidePopover();
|
|
109
|
+
}, cd);
|
|
110
|
+
}, [
|
|
111
|
+
clearTimers
|
|
112
|
+
]);
|
|
113
|
+
const prepare = useCallback((anchor, node, options)=>{
|
|
114
|
+
const opts = options ?? {};
|
|
115
|
+
clearTimers();
|
|
116
|
+
triggerModeRef.current = 'click';
|
|
117
|
+
currentAnchorRef.current = anchor;
|
|
118
|
+
const anchorName = resolveAnchorName(anchor);
|
|
119
|
+
setContent(node);
|
|
120
|
+
setContentClassName(opts.contentClassName);
|
|
121
|
+
setSize(opts.size ?? 'md');
|
|
122
|
+
setAnchorStyle(computeAnchorStyle(anchorName, opts));
|
|
123
|
+
}, [
|
|
124
|
+
clearTimers,
|
|
125
|
+
resolveAnchorName,
|
|
126
|
+
computeAnchorStyle
|
|
127
|
+
]);
|
|
128
|
+
const toggle = useCallback(()=>{
|
|
129
|
+
const el = popoverRef.current;
|
|
130
|
+
if (!el) return;
|
|
131
|
+
try {
|
|
132
|
+
if (el.matches(':popover-open')) el.hidePopover();
|
|
133
|
+
else el.showPopover();
|
|
134
|
+
} catch {}
|
|
135
|
+
}, []);
|
|
136
|
+
useEffect(()=>{
|
|
137
|
+
const handlePointerDown = (e)=>{
|
|
138
|
+
const el = popoverRef.current;
|
|
139
|
+
if (!el || 'click' !== triggerModeRef.current) return;
|
|
140
|
+
try {
|
|
141
|
+
if (!el.matches(':popover-open')) return;
|
|
142
|
+
} catch {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
const target = e.target;
|
|
146
|
+
if (!el.contains(target) && !currentAnchorRef.current?.contains(target)) el.hidePopover();
|
|
147
|
+
};
|
|
148
|
+
document.addEventListener('pointerdown', handlePointerDown);
|
|
149
|
+
return ()=>document.removeEventListener('pointerdown', handlePointerDown);
|
|
150
|
+
}, []);
|
|
151
|
+
useEffect(()=>()=>{
|
|
152
|
+
clearTimers();
|
|
153
|
+
}, [
|
|
154
|
+
clearTimers
|
|
155
|
+
]);
|
|
156
|
+
const ctx = react.useMemo(()=>({
|
|
157
|
+
show,
|
|
158
|
+
hide,
|
|
159
|
+
prepare,
|
|
160
|
+
toggle
|
|
161
|
+
}), [
|
|
162
|
+
show,
|
|
163
|
+
hide,
|
|
164
|
+
prepare,
|
|
165
|
+
toggle
|
|
166
|
+
]);
|
|
167
|
+
const handlePopoverMouseEnter = useCallback(()=>{
|
|
168
|
+
if ('hover' === triggerModeRef.current) clearTimers();
|
|
169
|
+
}, [
|
|
170
|
+
clearTimers
|
|
171
|
+
]);
|
|
172
|
+
const handlePopoverMouseLeave = useCallback(()=>{
|
|
173
|
+
if ('hover' === triggerModeRef.current) hide();
|
|
174
|
+
}, [
|
|
175
|
+
hide
|
|
176
|
+
]);
|
|
177
|
+
return /*#__PURE__*/ jsxs(PopoverContext.Provider, {
|
|
178
|
+
value: ctx,
|
|
179
|
+
children: [
|
|
180
|
+
children,
|
|
181
|
+
/*#__PURE__*/ jsx("div", {
|
|
182
|
+
ref: popoverRef,
|
|
183
|
+
id: `ux-sp-${uid}`,
|
|
184
|
+
popover: "manual",
|
|
185
|
+
className: cn(popoverVariants({
|
|
186
|
+
size
|
|
187
|
+
}), contentClassName),
|
|
188
|
+
style: anchorStyle,
|
|
189
|
+
onMouseEnter: handlePopoverMouseEnter,
|
|
190
|
+
onMouseLeave: handlePopoverMouseLeave,
|
|
191
|
+
children: content
|
|
192
|
+
})
|
|
193
|
+
]
|
|
194
|
+
});
|
|
195
|
+
};
|
|
196
|
+
UXSimplePopoverProvider.displayName = 'UX.SimplePopoverProvider';
|
|
197
|
+
export { UXSimplePopoverProvider, useSimplePopoverContext };
|
|
@@ -1,20 +1,25 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
export type SimplePopoverPlacement = 'top' | 'bottom' | 'left' | 'right';
|
|
2
|
+
export type SimplePopoverPlacement = 'top' | 'top-left' | 'top-right' | 'bottom' | 'bottom-left' | 'bottom-right' | 'left' | 'left-top' | 'left-bottom' | 'right' | 'right-top' | 'right-bottom';
|
|
3
3
|
export type SimplePopoverTriggerType = 'click' | 'hover';
|
|
4
|
+
export type SimplePopoverSize = 'sm' | 'md' | 'lg';
|
|
4
5
|
export interface UXSimplePopoverProps {
|
|
5
6
|
/** Popover content */
|
|
6
7
|
content: React.ReactNode;
|
|
7
8
|
/** Trigger element(s) */
|
|
8
9
|
children: React.ReactNode;
|
|
9
|
-
/** How to open: click
|
|
10
|
+
/** How to open: click or hover */
|
|
10
11
|
triggerType?: SimplePopoverTriggerType;
|
|
11
12
|
/** Placement relative to trigger; uses CSS Anchor Positioning when supported */
|
|
12
13
|
placement?: SimplePopoverPlacement;
|
|
14
|
+
/** Popover padding size */
|
|
15
|
+
size?: SimplePopoverSize;
|
|
13
16
|
/** Hover only: delay before opening (ms) */
|
|
14
17
|
delay?: number;
|
|
15
18
|
/** Hover only: delay before closing (ms) */
|
|
16
19
|
closeDelay?: number;
|
|
17
|
-
/**
|
|
20
|
+
/** Distance between popover and trigger (px) */
|
|
21
|
+
offset?: number;
|
|
22
|
+
/** ClassName for the trigger element and popover content */
|
|
18
23
|
classNames?: {
|
|
19
24
|
trigger?: string;
|
|
20
25
|
content?: string;
|