@react-fabric/core 1.0.0-beta.1 → 1.0.0-beta.12
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/css/index.js +13 -13
- package/dist/cjs/components/actionLabel/ActionLabel.js +1 -0
- package/dist/cjs/components/animations/Animations.js +13 -6
- package/dist/cjs/components/avatar/Avatar.js +6 -7
- package/dist/cjs/components/badge/Badge.js +6 -4
- package/dist/cjs/components/breadcrumbs/Breadcrumbs.js +2 -2
- package/dist/cjs/components/button/Button.js +9 -7
- package/dist/cjs/components/button/Button.module.css +1 -1
- package/dist/cjs/components/button/ConfirmButton.js +4 -2
- package/dist/cjs/components/callout/Callout.js +3 -2
- package/dist/cjs/components/card/Card.js +4 -2
- package/dist/cjs/components/chip/Chip.js +2 -2
- package/dist/cjs/components/chip/Chip.module.css +1 -1
- package/dist/cjs/components/collapsable/Collapsable.js +5 -3
- package/dist/cjs/components/divider/Divider.js +3 -2
- package/dist/cjs/components/divider/Divider.module.css +1 -0
- package/dist/cjs/components/dropdown/Dropdown.js +4 -2
- package/dist/cjs/components/dropdown/DropdownTool.js +3 -2
- package/dist/cjs/components/icon/Icon.js +8 -7
- package/dist/cjs/components/menu/ContextMenu.js +30 -10
- package/dist/cjs/components/menu/Menu.js +1 -1
- package/dist/cjs/components/menu/MenuItem.js +1 -1
- package/dist/cjs/components/navigator/Navigator.js +15 -9
- package/dist/cjs/components/panel/Panel.js +2 -0
- package/dist/cjs/components/tabpanel/Tab.js +55 -36
- package/dist/cjs/components/tabpanel/TabPanel.js +18 -13
- package/dist/cjs/components/tabpanel/TabPanel.module.css +1 -1
- package/dist/cjs/core/aside/Aside.js +7 -2
- package/dist/cjs/core/content/Content.js +8 -5
- package/dist/cjs/core/headfoot/HeadFoot.js +1 -1
- package/dist/cjs/core/headfoot/HeadFoot.module.css +1 -1
- package/dist/cjs/core/page/Page.js +1 -0
- package/dist/cjs/core/section/Section.js +5 -2
- package/dist/cjs/hooks/useNavigator.js +6 -4
- package/dist/cjs/index.js +3 -2
- package/dist/cjs/overlays/alert/Alert.js +38 -16
- package/dist/cjs/overlays/modal/Modal.js +1 -1
- package/dist/cjs/overlays/tooltip/Tooltip.js +3 -3
- package/dist/cjs/overlays/tooltip/Tooltip.module.css +1 -1
- package/dist/cjs/types/icons.js +3 -0
- package/dist/cjs/typography/Abbr.js +2 -0
- package/dist/cjs/typography/{Link.js → Anchor.js} +2 -2
- package/dist/cjs/typography/Typography.module.css +1 -1
- package/dist/esm/components/actionLabel/ActionLabel.js +1 -0
- package/dist/esm/components/animations/Animations.js +13 -6
- package/dist/esm/components/avatar/Avatar.js +7 -8
- package/dist/esm/components/badge/Badge.js +7 -5
- package/dist/esm/components/breadcrumbs/Breadcrumbs.js +2 -2
- package/dist/esm/components/button/Button.js +9 -7
- package/dist/esm/components/button/Button.module.css +1 -1
- package/dist/esm/components/button/ConfirmButton.js +4 -2
- package/dist/esm/components/callout/Callout.js +3 -2
- package/dist/esm/components/card/Card.js +4 -2
- package/dist/esm/components/chip/Chip.js +2 -2
- package/dist/esm/components/chip/Chip.module.css +1 -1
- package/dist/esm/components/collapsable/Collapsable.js +5 -3
- package/dist/esm/components/divider/Divider.js +3 -2
- package/dist/esm/components/divider/Divider.module.css +1 -0
- package/dist/esm/components/dropdown/Dropdown.js +4 -2
- package/dist/esm/components/dropdown/DropdownTool.js +3 -2
- package/dist/esm/components/icon/Icon.js +8 -7
- package/dist/esm/components/menu/ContextMenu.js +32 -12
- package/dist/esm/components/menu/Menu.js +1 -1
- package/dist/esm/components/menu/MenuItem.js +1 -1
- package/dist/esm/components/navigator/Navigator.js +15 -9
- package/dist/esm/components/panel/Panel.js +2 -0
- package/dist/esm/components/tabpanel/Tab.js +56 -37
- package/dist/esm/components/tabpanel/TabPanel.js +18 -13
- package/dist/esm/components/tabpanel/TabPanel.module.css +1 -1
- package/dist/esm/core/aside/Aside.js +7 -2
- package/dist/esm/core/content/Content.js +8 -5
- package/dist/esm/core/headfoot/HeadFoot.js +1 -1
- package/dist/esm/core/headfoot/HeadFoot.module.css +1 -1
- package/dist/esm/core/page/Page.js +1 -0
- package/dist/esm/core/section/Section.js +5 -2
- package/dist/esm/hooks/useNavigator.js +7 -5
- package/dist/esm/index.js +2 -1
- package/dist/esm/overlays/alert/Alert.js +27 -5
- package/dist/esm/overlays/modal/Modal.js +1 -1
- package/dist/esm/overlays/tooltip/Tooltip.js +3 -3
- package/dist/esm/overlays/tooltip/Tooltip.module.css +1 -1
- package/dist/esm/types/icons.js +3 -0
- package/dist/esm/typography/Abbr.js +2 -0
- package/dist/esm/typography/{Link.js → Anchor.js} +2 -2
- package/dist/esm/typography/Typography.module.css +1 -1
- package/dist/types/components/actionLabel/ActionLabel.d.ts +2 -2
- package/dist/types/components/animations/Animations.d.ts +1 -1
- package/dist/types/components/breadcrumbs/Breadcrumbs.d.ts +2 -2
- package/dist/types/components/button/Button.d.ts +5 -2
- package/dist/types/components/button/ConfirmButton.d.ts +6 -1
- package/dist/types/components/callout/Callout.d.ts +3 -3
- package/dist/types/components/card/Card.d.ts +3 -3
- package/dist/types/components/collapsable/Collapsable.d.ts +9 -1
- package/dist/types/components/dropdown/DropdownTool.d.ts +2 -1
- package/dist/types/components/media/Media.d.ts +2 -2
- package/dist/types/components/menu/ContextMenu.d.ts +2 -1
- package/dist/types/components/menu/types.d.ts +2 -2
- package/dist/types/components/navigator/Navigator.d.ts +3 -3
- package/dist/types/components/tabpanel/Tab.d.ts +8 -4
- package/dist/types/components/tabpanel/TabPanel.d.ts +10 -1
- package/dist/types/core/aside/Aside.d.ts +9 -5
- package/dist/types/core/content/Content.d.ts +3 -2
- package/dist/types/core/section/Section.d.ts +2 -2
- package/dist/types/overlays/alert/Alert.d.ts +9 -1
- package/dist/types/overlays/modal/Modal.d.ts +1 -1
- package/dist/types/types/icons.d.ts +3 -0
- package/dist/types/types/index.d.ts +6 -2
- package/dist/types/typography/Abbr.d.ts +3 -3
- package/dist/types/typography/{Link.d.ts → Anchor.d.ts} +4 -3
- package/dist/types/typography/index.d.ts +1 -1
- package/package.json +3 -3
- package/src/components/actionLabel/ActionLabel.tsx +13 -3
- package/src/components/animations/Animations.tsx +9 -3
- package/src/components/avatar/Avatar.tsx +68 -81
- package/src/components/badge/Badge.tsx +24 -20
- package/src/components/breadcrumbs/Breadcrumbs.tsx +3 -3
- package/src/components/button/Button.module.css +1 -1
- package/src/components/button/Button.tsx +16 -10
- package/src/components/button/ConfirmButton.tsx +10 -4
- package/src/components/callout/Callout.tsx +8 -1
- package/src/components/card/Card.tsx +4 -0
- package/src/components/chip/Chip.module.css +1 -1
- package/src/components/chip/Chip.tsx +2 -4
- package/src/components/collapsable/Collapsable.tsx +12 -1
- package/src/components/divider/Divider.module.css +32 -0
- package/src/components/divider/Divider.tsx +3 -2
- package/src/components/dropdown/Dropdown.tsx +3 -2
- package/src/components/dropdown/DropdownTool.tsx +3 -1
- package/src/components/icon/Icon.tsx +46 -57
- package/src/components/media/Media.tsx +2 -2
- package/src/components/menu/ContextMenu.tsx +36 -11
- package/src/components/menu/Menu.tsx +2 -2
- package/src/components/menu/types.ts +2 -2
- package/src/components/navigator/Navigator.tsx +16 -4
- package/src/components/panel/Panel.tsx +2 -0
- package/src/components/tabpanel/Tab.tsx +78 -59
- package/src/components/tabpanel/TabPanel.module.css +19 -26
- package/src/components/tabpanel/TabPanel.tsx +32 -10
- package/src/core/aside/Aside.tsx +26 -4
- package/src/core/content/Content.tsx +16 -10
- package/src/core/headfoot/HeadFoot.module.css +2 -0
- package/src/core/headfoot/HeadFoot.tsx +1 -1
- package/src/core/page/Page.tsx +1 -0
- package/src/core/section/Section.tsx +8 -2
- package/src/hooks/useNavigator.tsx +10 -5
- package/src/overlays/alert/Alert.tsx +25 -2
- package/src/overlays/modal/Modal.tsx +2 -2
- package/src/overlays/tooltip/Tooltip.module.css +1 -1
- package/src/overlays/tooltip/Tooltip.tsx +4 -4
- package/src/types/icons.ts +6 -0
- package/src/types/index.ts +10 -2
- package/src/typography/Abbr.tsx +4 -3
- package/src/typography/{Link.tsx → Anchor.tsx} +6 -3
- package/src/typography/Typography.module.css +2 -2
- package/src/typography/index.ts +1 -1
|
@@ -31,10 +31,12 @@ export const DropdownTool = ({
|
|
|
31
31
|
children,
|
|
32
32
|
className,
|
|
33
33
|
groupHover,
|
|
34
|
+
icon,
|
|
34
35
|
...props
|
|
35
36
|
}: ChildProp &
|
|
36
37
|
CssProp &
|
|
37
38
|
Omit<DropdownProps, "children"> & {
|
|
39
|
+
icon?: string;
|
|
38
40
|
/**
|
|
39
41
|
* hide until group hovered
|
|
40
42
|
*/
|
|
@@ -43,7 +45,7 @@ export const DropdownTool = ({
|
|
|
43
45
|
return (
|
|
44
46
|
<Dropdown {...props}>
|
|
45
47
|
<Icon
|
|
46
|
-
icon={CoreIcons.caretDown}
|
|
48
|
+
icon={icon ?? CoreIcons.caretDown}
|
|
47
49
|
className={classNames(
|
|
48
50
|
className,
|
|
49
51
|
"outline bg-base flex-content pointer-events-auto cursor-pointer",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
|
|
24
24
|
import { isString, isSvgPath } from "@react-fabric/utilities";
|
|
25
25
|
import classNames from "classnames";
|
|
26
|
-
import {
|
|
26
|
+
import { useMemo } from "react";
|
|
27
27
|
import {
|
|
28
28
|
type AriaProps,
|
|
29
29
|
type ColorType,
|
|
@@ -101,66 +101,54 @@ export const Icon = ({
|
|
|
101
101
|
...rest
|
|
102
102
|
}: IconProps) => {
|
|
103
103
|
/** ***************** style map *******************/
|
|
104
|
-
const styles =
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
},
|
|
121
|
-
[bg, color, size],
|
|
122
|
-
"Icon styles",
|
|
123
|
-
);
|
|
104
|
+
const styles = useMemo(() => {
|
|
105
|
+
const s: KeyValue = {};
|
|
106
|
+
if (bg) {
|
|
107
|
+
s.backgroundColor = getColor(bg);
|
|
108
|
+
}
|
|
109
|
+
if (color) {
|
|
110
|
+
s.color = getColor(color);
|
|
111
|
+
}
|
|
112
|
+
if (size && !(size in SizeMap)) {
|
|
113
|
+
s.fontSize = size;
|
|
114
|
+
}
|
|
115
|
+
if (size && size in SizeMap) {
|
|
116
|
+
s.fontSize = SizeMap[size];
|
|
117
|
+
}
|
|
118
|
+
return s;
|
|
119
|
+
}, [bg, color, size]);
|
|
124
120
|
|
|
125
121
|
/** ***************** check if icon is svg path *******************/
|
|
126
|
-
const isSvg =
|
|
127
|
-
()
|
|
128
|
-
|
|
129
|
-
},
|
|
130
|
-
[icon],
|
|
131
|
-
"Icon isSvg",
|
|
132
|
-
);
|
|
122
|
+
const isSvg = useMemo(() => {
|
|
123
|
+
return isSvgPath(icon);
|
|
124
|
+
}, [icon]);
|
|
133
125
|
|
|
134
126
|
/** ***************** render icon *******************/
|
|
135
|
-
const iconEl =
|
|
136
|
-
()
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
<
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
<
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
},
|
|
161
|
-
[icon, isSvg, viewBox],
|
|
162
|
-
"Icon el",
|
|
163
|
-
);
|
|
127
|
+
const iconEl = useMemo(() => {
|
|
128
|
+
if (!isString(icon)) {
|
|
129
|
+
throw Error("Invalid icon expected string");
|
|
130
|
+
}
|
|
131
|
+
return isSvg ? (
|
|
132
|
+
<svg viewBox={viewBox}>
|
|
133
|
+
<path fill="currentColor" d={icon.toString()} />
|
|
134
|
+
</svg>
|
|
135
|
+
) : icon?.toString().length <= 4 ? (
|
|
136
|
+
<svg role="img">
|
|
137
|
+
<text
|
|
138
|
+
x="50%"
|
|
139
|
+
y="50%"
|
|
140
|
+
dy=".1em"
|
|
141
|
+
dominantBaseline="middle"
|
|
142
|
+
textAnchor="middle"
|
|
143
|
+
style={{ fontSize: SvgTextSize[icon.length] ?? "1em" }}
|
|
144
|
+
>
|
|
145
|
+
{icon}
|
|
146
|
+
</text>
|
|
147
|
+
</svg>
|
|
148
|
+
) : (
|
|
149
|
+
<i className={`${icon}`} />
|
|
150
|
+
);
|
|
151
|
+
}, [icon, isSvg, viewBox]);
|
|
164
152
|
|
|
165
153
|
return (
|
|
166
154
|
<dfn
|
|
@@ -181,6 +169,7 @@ export const Icon = ({
|
|
|
181
169
|
data-flip={rtlFlip}
|
|
182
170
|
style={styles}
|
|
183
171
|
data-clickable={!!onClick}
|
|
172
|
+
data-inner-clickable={!!onClick}
|
|
184
173
|
>
|
|
185
174
|
{iconEl}
|
|
186
175
|
</dfn>
|
|
@@ -24,12 +24,12 @@
|
|
|
24
24
|
import { getImageColorset } from "@react-fabric/utilities";
|
|
25
25
|
import classNames from "classnames";
|
|
26
26
|
import { useMemo, useRef, useState } from "react";
|
|
27
|
-
import { type AriaProps, type CssProp } from "../../types";
|
|
27
|
+
import { type AriaProps, type CssProp, type TestProps } from "../../types";
|
|
28
28
|
import { CoreIcons } from "../../types/icons";
|
|
29
29
|
import { Button } from "../button/Button";
|
|
30
30
|
import classes from "./Media.module.css";
|
|
31
31
|
|
|
32
|
-
export interface BaseProps extends CssProp, AriaProps {
|
|
32
|
+
export interface BaseProps extends CssProp, TestProps, AriaProps {
|
|
33
33
|
/**
|
|
34
34
|
* media source
|
|
35
35
|
*/
|
|
@@ -29,30 +29,41 @@ import {
|
|
|
29
29
|
useClick,
|
|
30
30
|
useDismiss,
|
|
31
31
|
useFloating,
|
|
32
|
+
useFloatingNodeId,
|
|
32
33
|
useInteractions,
|
|
33
34
|
} from "@floating-ui/react";
|
|
34
|
-
import { cloneElement, useRef, useState } from "react";
|
|
35
|
+
import { cloneElement, useEffect, useRef, useState } from "react";
|
|
35
36
|
import { type ChildrenProp } from "../../types";
|
|
36
37
|
import { type Menu } from "./Menu";
|
|
37
38
|
|
|
38
39
|
export interface ContextMenuProps extends ChildrenProp {
|
|
39
40
|
menu: React.ReactElement<typeof Menu>;
|
|
41
|
+
|
|
42
|
+
disabled?: boolean;
|
|
40
43
|
}
|
|
41
44
|
|
|
42
|
-
export const ContextMenu = ({ children, menu }: ContextMenuProps) => {
|
|
45
|
+
export const ContextMenu = ({ children, menu, disabled }: ContextMenuProps) => {
|
|
43
46
|
const [isOpen, setIsOpen] = useState(false);
|
|
47
|
+
const nodeId = useFloatingNodeId();
|
|
44
48
|
|
|
45
49
|
const { refs, floatingStyles, context } = useFloating({
|
|
46
50
|
open: isOpen,
|
|
47
|
-
|
|
51
|
+
nodeId,
|
|
52
|
+
onOpenChange: (open, evt, reason) => {
|
|
53
|
+
const target = evt?.target as HTMLElement;
|
|
54
|
+
if (!target?.closest(".menu-list")) setIsOpen(open);
|
|
55
|
+
},
|
|
48
56
|
strategy: "fixed",
|
|
49
57
|
placement: "bottom-start",
|
|
50
58
|
whileElementsMounted: autoUpdate,
|
|
51
59
|
middleware: [offset(8), flip()],
|
|
52
60
|
});
|
|
53
61
|
|
|
54
|
-
const click = useClick(context, {
|
|
55
|
-
|
|
62
|
+
const click = useClick(context, {
|
|
63
|
+
toggle: true,
|
|
64
|
+
ignoreMouse: true,
|
|
65
|
+
});
|
|
66
|
+
const dismiss = useDismiss(context, { bubbles: true });
|
|
56
67
|
|
|
57
68
|
const { getFloatingProps } = useInteractions([dismiss, click]);
|
|
58
69
|
|
|
@@ -78,10 +89,19 @@ export const ContextMenu = ({ children, menu }: ContextMenuProps) => {
|
|
|
78
89
|
return false;
|
|
79
90
|
});
|
|
80
91
|
|
|
81
|
-
const wrapperRef = useRef(
|
|
82
|
-
|
|
83
|
-
el
|
|
84
|
-
|
|
92
|
+
const wrapperRef = useRef<HTMLDivElement>(null);
|
|
93
|
+
useEffect(() => {
|
|
94
|
+
const el = wrapperRef.current;
|
|
95
|
+
if (el && !disabled) {
|
|
96
|
+
el?.parentElement?.addEventListener("contextmenu", handleClick.current);
|
|
97
|
+
return () => {
|
|
98
|
+
el?.parentElement?.removeEventListener(
|
|
99
|
+
"contextmenu",
|
|
100
|
+
handleClick.current,
|
|
101
|
+
);
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
}, [disabled]);
|
|
85
105
|
|
|
86
106
|
const tryClosing = useRef((e: React.MouseEvent) => {
|
|
87
107
|
if ((e.target as HTMLElement)?.closest("[data-dropdown-dismiss='true']"))
|
|
@@ -91,12 +111,17 @@ export const ContextMenu = ({ children, menu }: ContextMenuProps) => {
|
|
|
91
111
|
return (
|
|
92
112
|
<div
|
|
93
113
|
className="contents"
|
|
94
|
-
ref={wrapperRef
|
|
114
|
+
ref={wrapperRef}
|
|
95
115
|
onMouseUpCapture={tryClosing.current}
|
|
96
116
|
>
|
|
97
117
|
{children}
|
|
98
118
|
{isOpen && (
|
|
99
|
-
<FloatingPortal
|
|
119
|
+
<FloatingPortal
|
|
120
|
+
root={
|
|
121
|
+
refs.domReference.current?.closest<HTMLElement>(".theme-base") ??
|
|
122
|
+
undefined
|
|
123
|
+
}
|
|
124
|
+
>
|
|
100
125
|
{cloneElement(menu as AnyObject, {
|
|
101
126
|
...getFloatingProps(),
|
|
102
127
|
style: {
|
|
@@ -162,7 +162,7 @@ const MenuComponent = ({
|
|
|
162
162
|
(e: React.MouseEvent) => {
|
|
163
163
|
const el = e.target as HTMLElement;
|
|
164
164
|
if (el.dataset.id) {
|
|
165
|
-
onClick?.(el.dataset.id);
|
|
165
|
+
onClick?.(el.dataset.id as AnyObject);
|
|
166
166
|
}
|
|
167
167
|
},
|
|
168
168
|
[onClick],
|
|
@@ -224,7 +224,7 @@ const MenuComponent = ({
|
|
|
224
224
|
"outline shadow-lg rounded-capped max-h-96 overflow-auto scroll-thin z-[var(--z-popover)]",
|
|
225
225
|
)}
|
|
226
226
|
autoFocus
|
|
227
|
-
ref={mergeRefs(
|
|
227
|
+
ref={mergeRefs(isNested ? refs.setFloating : ref)}
|
|
228
228
|
{...getFloatingProps({
|
|
229
229
|
onClick: isNested ? undefined : handleClick,
|
|
230
230
|
})}
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
-
import { type ElementType } from "react";
|
|
24
|
+
import { type ElementType, type MouseEvent } from "react";
|
|
25
25
|
import {
|
|
26
26
|
type AriaProps,
|
|
27
27
|
type BadgeType,
|
|
@@ -77,7 +77,7 @@ export interface MenuItemProps
|
|
|
77
77
|
/**
|
|
78
78
|
* click handler
|
|
79
79
|
*/
|
|
80
|
-
onClick?: () => CallbackReturn;
|
|
80
|
+
onClick?: (e: MouseEvent) => CallbackReturn;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
export interface MenuRootProps extends CssProp {
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
import classNames from "classnames";
|
|
25
25
|
import { HotKey } from "../../hotkeys/HotKey";
|
|
26
26
|
import {
|
|
27
|
+
type ChildProp,
|
|
27
28
|
type AriaProps,
|
|
28
29
|
type ColorType,
|
|
29
30
|
type CssProp,
|
|
@@ -31,8 +32,13 @@ import {
|
|
|
31
32
|
} from "../../types";
|
|
32
33
|
import { CoreIcons } from "../../types/icons";
|
|
33
34
|
import { Icon } from "../icon/Icon";
|
|
35
|
+
import { useCallback } from "react";
|
|
34
36
|
|
|
35
|
-
export interface NavigatorProps
|
|
37
|
+
export interface NavigatorProps
|
|
38
|
+
extends CssProp,
|
|
39
|
+
AriaProps,
|
|
40
|
+
TestProps,
|
|
41
|
+
Partial<ChildProp> {
|
|
36
42
|
/**
|
|
37
43
|
* navigator button color
|
|
38
44
|
*/
|
|
@@ -47,28 +53,34 @@ export const Navigator = ({
|
|
|
47
53
|
className,
|
|
48
54
|
onNavigate,
|
|
49
55
|
color,
|
|
56
|
+
children,
|
|
50
57
|
...aria
|
|
51
58
|
}: NavigatorProps) => {
|
|
59
|
+
const navPrev = useCallback(() => onNavigate(-1), [onNavigate]);
|
|
60
|
+
const navNext = useCallback(() => onNavigate(+1), [onNavigate]);
|
|
52
61
|
return (
|
|
53
62
|
<div
|
|
54
|
-
className={classNames(className, "inline-
|
|
63
|
+
className={classNames(className, "inline-flex items-center leading-none")}
|
|
55
64
|
{...aria}
|
|
56
65
|
>
|
|
57
|
-
<HotKey keyCombo="left" handler={
|
|
58
|
-
<HotKey keyCombo="right" handler={
|
|
66
|
+
<HotKey keyCombo="left" handler={navPrev} />
|
|
67
|
+
<HotKey keyCombo="right" handler={navNext} />
|
|
59
68
|
<Icon
|
|
60
69
|
rtlFlip
|
|
61
70
|
color={color}
|
|
62
71
|
className="text-[1em] p-1"
|
|
63
72
|
aria-label="previous"
|
|
73
|
+
data-testid="previous"
|
|
64
74
|
icon={CoreIcons.chevronLeft}
|
|
65
75
|
onClick={(e) => [e.stopPropagation(), onNavigate(-1)]}
|
|
66
76
|
/>
|
|
77
|
+
{children}
|
|
67
78
|
<Icon
|
|
68
79
|
rtlFlip
|
|
69
80
|
className="text-[1em] p-1"
|
|
70
81
|
color={color}
|
|
71
82
|
aria-label="next"
|
|
83
|
+
data-testid="next"
|
|
72
84
|
icon={CoreIcons.chevronRight}
|
|
73
85
|
onClick={(e) => [e.stopPropagation(), onNavigate(1)]}
|
|
74
86
|
/>
|
|
@@ -176,6 +176,7 @@ export const Panel = ({
|
|
|
176
176
|
headerClassName,
|
|
177
177
|
"flex flex-nowrap items-center area-head",
|
|
178
178
|
)}
|
|
179
|
+
data-testid="panel-header"
|
|
179
180
|
onClick={collapsable ? toggleCollapse : undefined}
|
|
180
181
|
>
|
|
181
182
|
{onBack && (
|
|
@@ -240,6 +241,7 @@ export const Panel = ({
|
|
|
240
241
|
</header>
|
|
241
242
|
{(!collapsed || expanded) && (
|
|
242
243
|
<div
|
|
244
|
+
data-testid="panel-body"
|
|
243
245
|
className={classNames(
|
|
244
246
|
classes.panelBody,
|
|
245
247
|
"area-content grid overflow-hidden",
|
|
@@ -21,8 +21,10 @@
|
|
|
21
21
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
+
import { isString } from "@react-fabric/utilities";
|
|
24
25
|
import classNames from "classnames";
|
|
25
|
-
import { type ReactElement, useMemo } from "react";
|
|
26
|
+
import { Fragment, type ReactElement, useMemo } from "react";
|
|
27
|
+
import { Tooltip } from "../../overlays";
|
|
26
28
|
import {
|
|
27
29
|
type AriaProps,
|
|
28
30
|
type BadgeType,
|
|
@@ -34,6 +36,7 @@ import {
|
|
|
34
36
|
type PolymorphicProps,
|
|
35
37
|
type RefProp,
|
|
36
38
|
type TestProps,
|
|
39
|
+
type TooltipProp,
|
|
37
40
|
} from "../../types";
|
|
38
41
|
import { Badge, getBadgeProps } from "../badge/Badge";
|
|
39
42
|
import { DropdownTool } from "../dropdown/DropdownTool";
|
|
@@ -46,7 +49,8 @@ export interface TabProps
|
|
|
46
49
|
RefProp,
|
|
47
50
|
AriaProps,
|
|
48
51
|
TestProps,
|
|
49
|
-
IconProps
|
|
52
|
+
IconProps,
|
|
53
|
+
TooltipProp {
|
|
50
54
|
/**
|
|
51
55
|
* tab id
|
|
52
56
|
*/
|
|
@@ -62,7 +66,7 @@ export interface TabProps
|
|
|
62
66
|
/**
|
|
63
67
|
* tab badge
|
|
64
68
|
*/
|
|
65
|
-
badge?: BadgeType;
|
|
69
|
+
badge?: string | number | BadgeType;
|
|
66
70
|
/**
|
|
67
71
|
* disabled
|
|
68
72
|
*/
|
|
@@ -83,6 +87,10 @@ export interface TabProps
|
|
|
83
87
|
* close handler
|
|
84
88
|
*/
|
|
85
89
|
onClose?: () => CallbackReturn;
|
|
90
|
+
/**
|
|
91
|
+
* click handler
|
|
92
|
+
*/
|
|
93
|
+
onClick?: (id: string) => CallbackReturn;
|
|
86
94
|
}
|
|
87
95
|
|
|
88
96
|
export const Tab = <Tag extends React.ElementType = "button">({
|
|
@@ -106,6 +114,7 @@ export const Tab = <Tag extends React.ElementType = "button">({
|
|
|
106
114
|
tabFlex,
|
|
107
115
|
color,
|
|
108
116
|
actions,
|
|
117
|
+
tooltip,
|
|
109
118
|
activeClassName,
|
|
110
119
|
...aria
|
|
111
120
|
}: TabProps & PolymorphicProps<Tag>) => {
|
|
@@ -113,63 +122,73 @@ export const Tab = <Tag extends React.ElementType = "button">({
|
|
|
113
122
|
return getBadgeProps(badge);
|
|
114
123
|
}, [badge]);
|
|
115
124
|
|
|
125
|
+
const tooltipProps = useMemo(() => {
|
|
126
|
+
if (isString(tooltip)) return { content: tooltip };
|
|
127
|
+
|
|
128
|
+
return tooltip ?? {};
|
|
129
|
+
}, [tooltip]);
|
|
130
|
+
|
|
116
131
|
const E = as ?? "button";
|
|
132
|
+
const W = tooltip ? Tooltip : Fragment;
|
|
117
133
|
return (
|
|
118
|
-
<
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
className
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
"
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
e
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
134
|
+
<W {...tooltipProps}>
|
|
135
|
+
<E
|
|
136
|
+
data-id={id}
|
|
137
|
+
disabled={disabled}
|
|
138
|
+
data-color={color}
|
|
139
|
+
data-inner-clickable
|
|
140
|
+
className={classNames(
|
|
141
|
+
classes.tabButton,
|
|
142
|
+
className,
|
|
143
|
+
active && "active pointer-events-none",
|
|
144
|
+
active && activeClassName,
|
|
145
|
+
disabled && "text-tint-500 pointer-events-none",
|
|
146
|
+
tabFlex ? "flex-1" : "flex-initial max-w-36 min-w-24",
|
|
147
|
+
"flex items-center justify-center px-1 rounded overflow-hidden",
|
|
148
|
+
)}
|
|
149
|
+
onClick={() => !active && onClick?.(id)}
|
|
150
|
+
ref={ref as AnyObject}
|
|
151
|
+
{...aria}
|
|
152
|
+
>
|
|
153
|
+
{icon && (
|
|
154
|
+
<Icon
|
|
155
|
+
icon={icon}
|
|
156
|
+
bg={iconBg}
|
|
157
|
+
color={iconColor}
|
|
158
|
+
rtlFlip={rtlFlip}
|
|
159
|
+
className="flex-content"
|
|
160
|
+
/>
|
|
161
|
+
)}
|
|
162
|
+
{!minimal && (
|
|
163
|
+
<label className="flex-initial truncate text-center px-1 py-1">
|
|
164
|
+
{label}
|
|
165
|
+
</label>
|
|
166
|
+
)}
|
|
167
|
+
{badge && (
|
|
168
|
+
<Badge
|
|
169
|
+
{...badgeProps}
|
|
170
|
+
placement={minimal ? "end" : ""}
|
|
171
|
+
className={classNames("me-1", badgeProps.className)}
|
|
172
|
+
/>
|
|
173
|
+
)}
|
|
174
|
+
{actions && active && (
|
|
175
|
+
<DropdownTool className="bg-base/20 me-1 z-5">{actions}</DropdownTool>
|
|
176
|
+
)}
|
|
177
|
+
{onClose && (
|
|
178
|
+
<span
|
|
179
|
+
role="none"
|
|
180
|
+
className={classNames(
|
|
181
|
+
"cursor-pointer me-1 opacity-65 hover:opacity-90 pointer-events-auto",
|
|
182
|
+
)}
|
|
183
|
+
onClick={(e) => {
|
|
184
|
+
onClose?.();
|
|
185
|
+
e.stopPropagation();
|
|
186
|
+
}}
|
|
187
|
+
>
|
|
188
|
+
×
|
|
189
|
+
</span>
|
|
190
|
+
)}
|
|
191
|
+
</E>
|
|
192
|
+
</W>
|
|
174
193
|
);
|
|
175
194
|
};
|