@react-fabric/core 1.0.0-beta.3 → 1.0.0-beta.30
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 +14 -14
- package/css/reset/_reset.css +1 -1
- package/dist/cjs/components/actionLabel/ActionLabel.js +1 -0
- package/dist/cjs/components/animations/Animations.js +14 -7
- package/dist/cjs/components/avatar/Avatar.js +8 -10
- package/dist/cjs/components/avatar/AvatarGroup.js +1 -0
- package/dist/cjs/components/badge/Badge.js +5 -4
- package/dist/cjs/components/breadcrumbs/Breadcrumbs.js +5 -2
- package/dist/cjs/components/button/Button.js +5 -4
- package/dist/cjs/components/button/Button.module.css +1 -1
- package/dist/cjs/components/button/ButtonGroup.js +3 -1
- package/dist/cjs/components/button/ConfirmButton.js +7 -2
- package/dist/cjs/components/button/ToggleButtonGroup.js +2 -1
- package/dist/cjs/components/callout/Callout.js +7 -2
- package/dist/cjs/components/card/Card.js +5 -3
- package/dist/cjs/components/card/CardCover.js +1 -1
- package/dist/cjs/components/chip/Chip.js +9 -4
- package/dist/cjs/components/chip/Chip.module.css +1 -1
- package/dist/cjs/components/collapsable/Collapsable.js +3 -2
- package/dist/cjs/components/divider/Divider.js +4 -3
- 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 +4 -3
- package/dist/cjs/components/icon/Icon.js +14 -12
- package/dist/cjs/components/icon/Icon.module.css +1 -1
- package/dist/cjs/components/menu/ContextMenu.js +30 -10
- package/dist/cjs/components/menu/Menu.js +39 -20
- package/dist/cjs/components/menu/MenuItem.js +29 -14
- package/dist/cjs/components/navigator/Navigator.js +16 -9
- package/dist/cjs/components/panel/Panel.js +3 -1
- package/dist/cjs/components/progress/ProgressBar.js +2 -1
- package/dist/cjs/components/progress/ProgressCircle.js +2 -1
- package/dist/cjs/components/tabpanel/Tab.js +55 -36
- package/dist/cjs/components/tabpanel/TabPanel.js +19 -14
- package/dist/cjs/components/tabpanel/TabPanel.module.css +1 -1
- package/dist/cjs/core/aside/Aside.js +6 -2
- package/dist/cjs/core/content/Content.js +8 -5
- package/dist/cjs/core/headfoot/HeadFoot.js +3 -2
- package/dist/cjs/core/headfoot/HeadFoot.module.css +1 -1
- package/dist/cjs/core/page/Page.js +1 -0
- package/dist/cjs/core/responsive/Responsive.js +1 -1
- package/dist/cjs/core/section/Section.module.css +1 -1
- package/dist/cjs/hooks/useNavigator.js +6 -4
- package/dist/cjs/index.js +7 -2
- package/dist/cjs/overlays/alert/Alert.js +42 -17
- package/dist/cjs/overlays/alert/Alert.module.css +1 -1
- package/dist/cjs/overlays/flyout/Flyout.js +40 -42
- package/dist/cjs/overlays/message/Message.js +1 -1
- package/dist/cjs/overlays/modal/Modal.js +4 -5
- package/dist/cjs/overlays/toast/Toast.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 +1 -1
- package/dist/cjs/typography/{Link.js → Anchor.js} +4 -3
- package/dist/cjs/typography/Mark.js +1 -1
- package/dist/cjs/typography/Text.js +2 -2
- package/dist/cjs/typography/Title.js +3 -2
- package/dist/cjs/typography/Typography.module.css +1 -1
- package/dist/cjs/utils/cloneElement.js +44 -0
- package/dist/esm/components/actionLabel/ActionLabel.js +1 -0
- package/dist/esm/components/animations/Animations.js +14 -7
- package/dist/esm/components/avatar/Avatar.js +9 -11
- package/dist/esm/components/avatar/AvatarGroup.js +1 -0
- package/dist/esm/components/badge/Badge.js +5 -4
- package/dist/esm/components/breadcrumbs/Breadcrumbs.js +5 -2
- package/dist/esm/components/button/Button.js +5 -4
- package/dist/esm/components/button/Button.module.css +1 -1
- package/dist/esm/components/button/ButtonGroup.js +4 -2
- package/dist/esm/components/button/ConfirmButton.js +7 -2
- package/dist/esm/components/button/ToggleButtonGroup.js +3 -2
- package/dist/esm/components/callout/Callout.js +7 -2
- package/dist/esm/components/card/Card.js +5 -3
- package/dist/esm/components/card/CardCover.js +1 -1
- package/dist/esm/components/chip/Chip.js +9 -4
- package/dist/esm/components/chip/Chip.module.css +1 -1
- package/dist/esm/components/collapsable/Collapsable.js +3 -2
- package/dist/esm/components/divider/Divider.js +4 -3
- 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 +4 -3
- package/dist/esm/components/icon/Icon.js +14 -12
- package/dist/esm/components/icon/Icon.module.css +1 -1
- package/dist/esm/components/menu/ContextMenu.js +32 -12
- package/dist/esm/components/menu/Menu.js +41 -22
- package/dist/esm/components/menu/MenuItem.js +23 -8
- package/dist/esm/components/navigator/Navigator.js +16 -9
- package/dist/esm/components/panel/Panel.js +3 -1
- package/dist/esm/components/progress/ProgressBar.js +2 -1
- package/dist/esm/components/progress/ProgressCircle.js +2 -1
- package/dist/esm/components/tabpanel/Tab.js +56 -37
- package/dist/esm/components/tabpanel/TabPanel.js +19 -14
- package/dist/esm/components/tabpanel/TabPanel.module.css +1 -1
- package/dist/esm/core/aside/Aside.js +6 -2
- package/dist/esm/core/content/Content.js +8 -5
- package/dist/esm/core/headfoot/HeadFoot.js +3 -2
- package/dist/esm/core/headfoot/HeadFoot.module.css +1 -1
- package/dist/esm/core/page/Page.js +1 -0
- package/dist/esm/core/responsive/Responsive.js +1 -1
- package/dist/esm/core/section/Section.module.css +1 -1
- package/dist/esm/hooks/useNavigator.js +7 -5
- package/dist/esm/index.js +4 -1
- package/dist/esm/overlays/alert/Alert.js +31 -6
- package/dist/esm/overlays/alert/Alert.module.css +1 -1
- package/dist/esm/overlays/flyout/Flyout.js +41 -43
- package/dist/esm/overlays/message/Message.js +1 -1
- package/dist/esm/overlays/modal/Modal.js +5 -6
- package/dist/esm/overlays/toast/Toast.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 +1 -1
- package/dist/esm/typography/{Link.js → Anchor.js} +4 -3
- package/dist/esm/typography/Mark.js +1 -1
- package/dist/esm/typography/Text.js +2 -2
- package/dist/esm/typography/Title.js +3 -2
- package/dist/esm/typography/Typography.module.css +1 -1
- package/dist/esm/utils/cloneElement.js +44 -0
- package/dist/types/components/actionLabel/ActionLabel.d.ts +2 -2
- package/dist/types/components/animations/Animations.d.ts +1 -1
- package/dist/types/components/badge/Badge.d.ts +5 -1
- package/dist/types/components/breadcrumbs/Breadcrumbs.d.ts +2 -2
- package/dist/types/components/button/Button.d.ts +5 -3
- package/dist/types/components/button/ConfirmButton.d.ts +6 -1
- package/dist/types/components/card/Card.d.ts +3 -3
- package/dist/types/components/chip/Chip.d.ts +1 -1
- package/dist/types/components/collapsable/Collapsable.d.ts +5 -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/MenuItem.d.ts +1 -1
- package/dist/types/components/navigator/Navigator.d.ts +3 -3
- package/dist/types/components/tabpanel/Tab.d.ts +4 -4
- package/dist/types/components/tabpanel/TabPanel.d.ts +10 -1
- package/dist/types/core/aside/Aside.d.ts +7 -3
- package/dist/types/core/content/Content.d.ts +3 -2
- package/dist/types/core/responsive/Responsive.d.ts +1 -1
- package/dist/types/core/theme/ThemeProvider.d.ts +1 -1
- package/dist/types/hooks/useOverlayService.d.ts +3 -3
- package/dist/types/index.d.ts +3 -0
- package/dist/types/overlays/alert/Alert.d.ts +9 -1
- package/dist/types/overlays/flyout/Flyout.d.ts +3 -2
- package/dist/types/overlays/modal/Modal.d.ts +4 -3
- package/dist/types/types/icons.d.ts +3 -0
- package/dist/types/types/index.d.ts +8 -1
- package/dist/types/typography/{Link.d.ts → Anchor.d.ts} +2 -2
- package/dist/types/typography/index.d.ts +1 -1
- package/dist/types/utils/cloneElement.d.ts +2 -0
- package/dist/types/utils/index.d.ts +1 -0
- package/package.json +5 -5
- package/src/components/actionLabel/ActionLabel.tsx +13 -3
- package/src/components/animations/Animations.tsx +9 -3
- package/src/components/avatar/Avatar.tsx +69 -81
- package/src/components/avatar/AvatarGroup.tsx +1 -0
- package/src/components/badge/Badge.tsx +9 -4
- package/src/components/breadcrumbs/Breadcrumbs.tsx +9 -4
- package/src/components/button/Button.module.css +8 -1
- package/src/components/button/Button.tsx +12 -9
- package/src/components/button/ButtonGroup.tsx +3 -2
- package/src/components/button/ConfirmButton.tsx +15 -5
- package/src/components/button/ToggleButtonGroup.tsx +3 -2
- package/src/components/callout/Callout.tsx +12 -3
- package/src/components/card/Card.tsx +4 -0
- package/src/components/chip/Chip.module.css +4 -1
- package/src/components/chip/Chip.tsx +9 -4
- package/src/components/collapsable/Collapsable.tsx +6 -0
- 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 +4 -2
- package/src/components/icon/Icon.module.css +0 -1
- package/src/components/icon/Icon.tsx +48 -58
- package/src/components/media/Media.tsx +2 -2
- package/src/components/menu/ContextMenu.tsx +36 -11
- package/src/components/menu/Menu.tsx +51 -30
- package/src/components/menu/MenuItem.tsx +14 -3
- package/src/components/navigator/Navigator.tsx +17 -4
- package/src/components/panel/Panel.tsx +3 -1
- package/src/components/tabpanel/Tab.tsx +74 -59
- package/src/components/tabpanel/TabPanel.module.css +19 -30
- package/src/components/tabpanel/TabPanel.tsx +33 -10
- package/src/core/aside/Aside.tsx +17 -3
- 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/responsive/Responsive.tsx +3 -2
- package/src/core/section/Section.module.css +1 -1
- package/src/core/theme/ThemeProvider.tsx +1 -1
- package/src/hooks/useNavigator.tsx +10 -5
- package/src/hooks/useOverlayService.tsx +12 -4
- package/src/index.ts +4 -0
- package/src/overlays/alert/Alert.module.css +1 -1
- package/src/overlays/alert/Alert.tsx +30 -4
- package/src/overlays/flyout/Flyout.tsx +63 -62
- package/src/overlays/modal/Modal.tsx +13 -8
- package/src/overlays/tooltip/Tooltip.module.css +7 -7
- package/src/overlays/tooltip/Tooltip.tsx +4 -4
- package/src/types/icons.ts +6 -0
- package/src/types/index.ts +10 -9
- package/src/typography/{Link.tsx → Anchor.tsx} +3 -3
- package/src/typography/Text.tsx +1 -1
- package/src/typography/Title.tsx +0 -1
- package/src/typography/Typography.module.css +4 -2
- package/src/typography/index.ts +1 -1
- package/src/utils/cloneElement.ts +44 -0
- package/src/utils/index.ts +1 -0
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
type PaletteType,
|
|
31
31
|
} from "../../types";
|
|
32
32
|
import { getBgClass, getBorderClass, getColorClass } from "../../utils";
|
|
33
|
+
import classes from "./Divider.module.css";
|
|
33
34
|
|
|
34
35
|
export interface DividerProps extends CssProp, Partial<ChildProp> {
|
|
35
36
|
/**
|
|
@@ -67,7 +68,7 @@ export const Divider = ({
|
|
|
67
68
|
className,
|
|
68
69
|
vertical && "vertical",
|
|
69
70
|
!flex && "self-stretch",
|
|
70
|
-
vertical ?
|
|
71
|
+
vertical ? classes.vertical : classes.horizontal,
|
|
71
72
|
color && getBorderClass(color + "-200"),
|
|
72
73
|
)}
|
|
73
74
|
/>
|
|
@@ -88,7 +89,7 @@ export const Divider = ({
|
|
|
88
89
|
<div
|
|
89
90
|
className={classNames(
|
|
90
91
|
"px-2 whitespace-nowrap",
|
|
91
|
-
vertical ?
|
|
92
|
+
vertical ? classes.vertical : classes.horizontal,
|
|
92
93
|
fill && getBgClass((color ?? "tint") + "-200"),
|
|
93
94
|
!fill && getColorClass((color ?? "tint") + "-600"),
|
|
94
95
|
"rounded-full text-[0.75em]",
|
|
@@ -224,6 +224,7 @@ const DropdownElement = ({
|
|
|
224
224
|
e.stopPropagation();
|
|
225
225
|
},
|
|
226
226
|
}),
|
|
227
|
+
"data-inner-clickable": "true",
|
|
227
228
|
"data-dropdown-open": isOpen ? true : undefined,
|
|
228
229
|
ref: innerRef,
|
|
229
230
|
})}
|
|
@@ -248,6 +249,7 @@ const DropdownElement = ({
|
|
|
248
249
|
zIndex: "var(--z-popover)",
|
|
249
250
|
...floatingStyles,
|
|
250
251
|
}}
|
|
252
|
+
data-ref="dropdownBody"
|
|
251
253
|
{...getFloatingProps({
|
|
252
254
|
onClick: (e) => e.stopPropagation(),
|
|
253
255
|
})}
|
|
@@ -257,8 +259,7 @@ const DropdownElement = ({
|
|
|
257
259
|
className={classNames(
|
|
258
260
|
classes.dropdownBody,
|
|
259
261
|
dropdownClassName,
|
|
260
|
-
!plainDropdown &&
|
|
261
|
-
"shadow-lg shadow-base bg-base ring-1 ring-tint-100",
|
|
262
|
+
!plainDropdown && "shadow-lg bg-base ring-1 ring-tint-100",
|
|
262
263
|
"rounded-capped overflow-auto scroll-thin grid max-h-[70vh]",
|
|
263
264
|
)}
|
|
264
265
|
onMouseUpCapture={tryClosing}
|
|
@@ -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,12 +45,12 @@ 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",
|
|
50
52
|
groupHover &&
|
|
51
|
-
"hidden group-hover:inline-block data-[dropdown-open]:inline-block",
|
|
53
|
+
"hidden group-hover/tool:inline-block data-[dropdown-open]:inline-block",
|
|
52
54
|
)}
|
|
53
55
|
/>
|
|
54
56
|
{children}
|
|
@@ -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,71 +101,60 @@ 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] }}
|
|
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
|
|
167
|
-
|
|
155
|
+
data-ref="icon"
|
|
168
156
|
ref={ref}
|
|
157
|
+
{...rest}
|
|
169
158
|
role="presentation"
|
|
170
159
|
className={classNames(
|
|
171
160
|
classes.icon,
|
|
@@ -181,6 +170,7 @@ export const Icon = ({
|
|
|
181
170
|
data-flip={rtlFlip}
|
|
182
171
|
style={styles}
|
|
183
172
|
data-clickable={!!onClick}
|
|
173
|
+
data-inner-clickable={!!onClick}
|
|
184
174
|
>
|
|
185
175
|
{iconEl}
|
|
186
176
|
</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: {
|
|
@@ -48,7 +48,6 @@ import {
|
|
|
48
48
|
import { mergeRefs } from "@react-fabric/utilities";
|
|
49
49
|
import classNames from "classnames";
|
|
50
50
|
import {
|
|
51
|
-
Children,
|
|
52
51
|
cloneElement,
|
|
53
52
|
Fragment,
|
|
54
53
|
useCallback,
|
|
@@ -56,8 +55,9 @@ import {
|
|
|
56
55
|
useRef,
|
|
57
56
|
useState,
|
|
58
57
|
} from "react";
|
|
58
|
+
import { HotKeyWrapper } from "../../hotkeys/HotKeyWrapper";
|
|
59
59
|
import { CoreIcons } from "../../types/icons";
|
|
60
|
-
import { nodeCheck } from "../../utils";
|
|
60
|
+
import { cloneChildren, nodeCheck } from "../../utils";
|
|
61
61
|
import { MenuItem } from "./MenuItem";
|
|
62
62
|
import { type MenuProps } from "./types";
|
|
63
63
|
|
|
@@ -104,8 +104,9 @@ const MenuComponent = ({
|
|
|
104
104
|
handleClose: safePolygon({ blockPointerEvents: true }),
|
|
105
105
|
});
|
|
106
106
|
const click = useClick(context, {
|
|
107
|
-
|
|
108
|
-
|
|
107
|
+
event: "mousedown",
|
|
108
|
+
toggle: !isNested,
|
|
109
|
+
ignoreMouse: isNested,
|
|
109
110
|
});
|
|
110
111
|
const role = useRole(context, { role: "menu" });
|
|
111
112
|
const dismiss = useDismiss(context, { bubbles: true });
|
|
@@ -187,6 +188,16 @@ const MenuComponent = ({
|
|
|
187
188
|
);
|
|
188
189
|
}, [isOpen]);
|
|
189
190
|
|
|
191
|
+
useEffect(() => {
|
|
192
|
+
if ((!isNested || isOpen) && activeIndex) {
|
|
193
|
+
setTimeout(() => {
|
|
194
|
+
elementsRef.current[activeIndex]?.scrollIntoView({
|
|
195
|
+
block: "nearest",
|
|
196
|
+
});
|
|
197
|
+
}, 100);
|
|
198
|
+
}
|
|
199
|
+
}, [isOpen, activeIndex]);
|
|
200
|
+
|
|
190
201
|
return (
|
|
191
202
|
<FloatingNode id={nodeId}>
|
|
192
203
|
{isNested && (
|
|
@@ -210,29 +221,29 @@ const MenuComponent = ({
|
|
|
210
221
|
{(!isNested || isOpen) && (
|
|
211
222
|
<Wrapper {...wrapperProps}>
|
|
212
223
|
{isNested && <FloatingOverlay />}
|
|
213
|
-
<
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
<div
|
|
220
|
-
className={classNames(
|
|
221
|
-
menuClassName,
|
|
222
|
-
"flex flex-col bg-base p-1 menu-list",
|
|
223
|
-
isNested &&
|
|
224
|
-
"outline shadow-lg rounded-capped max-h-96 overflow-auto scroll-thin z-[var(--z-popover)]",
|
|
225
|
-
)}
|
|
226
|
-
autoFocus
|
|
227
|
-
ref={mergeRefs(refs.setFloating, isNested ? undefined : ref)}
|
|
228
|
-
{...getFloatingProps({
|
|
229
|
-
onClick: isNested ? undefined : handleClick,
|
|
230
|
-
})}
|
|
231
|
-
// @ts-expect-error ignore
|
|
232
|
-
{...{ style: !isNested ? rest.style : floatingStyles }}
|
|
224
|
+
<HotKeyWrapper>
|
|
225
|
+
<FloatingFocusManager
|
|
226
|
+
context={context}
|
|
227
|
+
modal={!isNested}
|
|
228
|
+
initialFocus={isNested ? -1 : 0}
|
|
229
|
+
returnFocus={!isNested}
|
|
233
230
|
>
|
|
234
|
-
|
|
235
|
-
|
|
231
|
+
<div
|
|
232
|
+
className={classNames(
|
|
233
|
+
menuClassName,
|
|
234
|
+
"flex flex-col bg-base p-1 menu-list",
|
|
235
|
+
isNested &&
|
|
236
|
+
"outline shadow-lg rounded-capped max-h-96 overflow-auto scroll-thin z-[var(--z-popover)]",
|
|
237
|
+
)}
|
|
238
|
+
autoFocus
|
|
239
|
+
ref={mergeRefs(isNested ? refs.setFloating : ref)}
|
|
240
|
+
{...getFloatingProps({
|
|
241
|
+
onClick: isNested ? undefined : handleClick,
|
|
242
|
+
})}
|
|
243
|
+
// @ts-expect-error ignore
|
|
244
|
+
{...{ style: !isNested ? rest.style : floatingStyles }}
|
|
245
|
+
>
|
|
246
|
+
{cloneChildren(children, (child: AnyObject, index) => {
|
|
236
247
|
labelsRef.current[index] = child.props.label;
|
|
237
248
|
return cloneElement(
|
|
238
249
|
child,
|
|
@@ -249,10 +260,10 @@ const MenuComponent = ({
|
|
|
249
260
|
}
|
|
250
261
|
: {},
|
|
251
262
|
);
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
</
|
|
255
|
-
</
|
|
263
|
+
})}
|
|
264
|
+
</div>
|
|
265
|
+
</FloatingFocusManager>
|
|
266
|
+
</HotKeyWrapper>
|
|
256
267
|
</Wrapper>
|
|
257
268
|
)}
|
|
258
269
|
</FloatingList>
|
|
@@ -262,6 +273,7 @@ const MenuComponent = ({
|
|
|
262
273
|
|
|
263
274
|
export const Menu = (props: MenuProps) => {
|
|
264
275
|
const parentId = useFloatingParentNodeId();
|
|
276
|
+
const tree = useFloatingTree();
|
|
265
277
|
|
|
266
278
|
if (parentId === null) {
|
|
267
279
|
return (
|
|
@@ -274,5 +286,14 @@ export const Menu = (props: MenuProps) => {
|
|
|
274
286
|
);
|
|
275
287
|
}
|
|
276
288
|
|
|
289
|
+
if (tree) {
|
|
290
|
+
return (
|
|
291
|
+
<MenuComponent
|
|
292
|
+
{...(props as AnyObject)}
|
|
293
|
+
menuClassName={props.className}
|
|
294
|
+
/>
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
|
|
277
298
|
return <MenuComponent {...props} />;
|
|
278
299
|
};
|
|
@@ -22,9 +22,10 @@
|
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
24
|
import { useFloatingTree } from "@floating-ui/react";
|
|
25
|
-
import { iconToken } from "@react-fabric/utilities";
|
|
25
|
+
import { iconToken, mergeRefs } from "@react-fabric/utilities";
|
|
26
26
|
import classNames from "classnames";
|
|
27
|
-
import { Fragment, useCallback, useMemo } from "react";
|
|
27
|
+
import { Fragment, useCallback, useEffect, useMemo, useRef } from "react";
|
|
28
|
+
import { HotKey } from "../../hotkeys/HotKey";
|
|
28
29
|
import { HotKeyLabel } from "../../hotkeys/HotKeyLabel";
|
|
29
30
|
import { Tooltip } from "../../overlays";
|
|
30
31
|
import { type PolymorphicProps } from "../../types";
|
|
@@ -50,6 +51,7 @@ export const MenuItem = <Tag extends React.ElementType = "button">({
|
|
|
50
51
|
onClick,
|
|
51
52
|
badge,
|
|
52
53
|
hotKey,
|
|
54
|
+
tabIndex = -1,
|
|
53
55
|
// @ts-expect-error ignore
|
|
54
56
|
minimal,
|
|
55
57
|
// @ts-expect-error ignore
|
|
@@ -58,11 +60,16 @@ export const MenuItem = <Tag extends React.ElementType = "button">({
|
|
|
58
60
|
ref,
|
|
59
61
|
...aria
|
|
60
62
|
}: MenuItemProps & PolymorphicProps<Tag>) => {
|
|
63
|
+
const elRef = useRef<HTMLElement>(null);
|
|
61
64
|
const tree = useFloatingTree();
|
|
62
65
|
const badgeProps = useMemo(() => {
|
|
63
66
|
return getBadgeProps(badge);
|
|
64
67
|
}, [badge]);
|
|
65
68
|
|
|
69
|
+
useEffect(() => {
|
|
70
|
+
tabIndex === 0 && elRef.current?.focus();
|
|
71
|
+
}, [tabIndex]);
|
|
72
|
+
|
|
66
73
|
const iconEl = useMemo(() => {
|
|
67
74
|
let path = icon;
|
|
68
75
|
if (minimal && !path) {
|
|
@@ -135,7 +142,7 @@ export const MenuItem = <Tag extends React.ElementType = "button">({
|
|
|
135
142
|
return (
|
|
136
143
|
<Wrapper {...aria}>
|
|
137
144
|
<E
|
|
138
|
-
ref={ref}
|
|
145
|
+
ref={mergeRefs(ref, elRef)}
|
|
139
146
|
data-dropdown-dismiss
|
|
140
147
|
data-color={color}
|
|
141
148
|
className={classNames(
|
|
@@ -150,11 +157,15 @@ export const MenuItem = <Tag extends React.ElementType = "button">({
|
|
|
150
157
|
data-open={childOpen}
|
|
151
158
|
disabled={disabled}
|
|
152
159
|
data-id={id}
|
|
160
|
+
tabIndex={tabIndex}
|
|
153
161
|
onClick={(e) => {
|
|
154
162
|
onClick?.(e) !== false && tree?.events.emit("click");
|
|
155
163
|
}}
|
|
156
164
|
{...(minimal ? {} : aria)}
|
|
157
165
|
>
|
|
166
|
+
{hotKey && (
|
|
167
|
+
<HotKey keyCombo={hotKey} handler={() => elRef.current?.click?.()} />
|
|
168
|
+
)}
|
|
158
169
|
{menuLabel}
|
|
159
170
|
</E>
|
|
160
171
|
</Wrapper>
|
|
@@ -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,35 @@ 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
|
-
|
|
63
|
+
data-ref="navigator"
|
|
64
|
+
className={classNames(className, "inline-flex items-center leading-none")}
|
|
55
65
|
{...aria}
|
|
56
66
|
>
|
|
57
|
-
<HotKey keyCombo="left" handler={
|
|
58
|
-
<HotKey keyCombo="right" handler={
|
|
67
|
+
<HotKey keyCombo="left" handler={navPrev} />
|
|
68
|
+
<HotKey keyCombo="right" handler={navNext} />
|
|
59
69
|
<Icon
|
|
60
70
|
rtlFlip
|
|
61
71
|
color={color}
|
|
62
72
|
className="text-[1em] p-1"
|
|
63
73
|
aria-label="previous"
|
|
74
|
+
data-ref="previous"
|
|
64
75
|
icon={CoreIcons.chevronLeft}
|
|
65
76
|
onClick={(e) => [e.stopPropagation(), onNavigate(-1)]}
|
|
66
77
|
/>
|
|
78
|
+
{children}
|
|
67
79
|
<Icon
|
|
68
80
|
rtlFlip
|
|
69
81
|
className="text-[1em] p-1"
|
|
70
82
|
color={color}
|
|
71
83
|
aria-label="next"
|
|
84
|
+
data-ref="next"
|
|
72
85
|
icon={CoreIcons.chevronRight}
|
|
73
86
|
onClick={(e) => [e.stopPropagation(), onNavigate(1)]}
|
|
74
87
|
/>
|
|
@@ -176,6 +176,7 @@ export const Panel = ({
|
|
|
176
176
|
headerClassName,
|
|
177
177
|
"flex flex-nowrap items-center area-head",
|
|
178
178
|
)}
|
|
179
|
+
data-ref="panelHeader"
|
|
179
180
|
onClick={collapsable ? toggleCollapse : undefined}
|
|
180
181
|
>
|
|
181
182
|
{onBack && (
|
|
@@ -204,7 +205,7 @@ export const Panel = ({
|
|
|
204
205
|
>
|
|
205
206
|
{title}
|
|
206
207
|
</div>
|
|
207
|
-
<div className="px-1">{actions}</div>
|
|
208
|
+
<div className="px-1 leading-none">{actions}</div>
|
|
208
209
|
{hasTools && (
|
|
209
210
|
<div
|
|
210
211
|
role="none"
|
|
@@ -240,6 +241,7 @@ export const Panel = ({
|
|
|
240
241
|
</header>
|
|
241
242
|
{(!collapsed || expanded) && (
|
|
242
243
|
<div
|
|
244
|
+
data-ref="panelBody"
|
|
243
245
|
className={classNames(
|
|
244
246
|
classes.panelBody,
|
|
245
247
|
"area-content grid overflow-hidden",
|