@fibery/ui-kit 1.25.0 → 1.26.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fibery/ui-kit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.26.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"files": [
|
|
6
6
|
"src/antd/styles.ts",
|
|
@@ -69,8 +69,8 @@
|
|
|
69
69
|
"screenfull": "6.0.1",
|
|
70
70
|
"ua-parser-js": "0.7.24",
|
|
71
71
|
"@fibery/emoji-data": "2.3.0",
|
|
72
|
-
"@fibery/
|
|
73
|
-
"@fibery/
|
|
72
|
+
"@fibery/helpers": "1.2.0",
|
|
73
|
+
"@fibery/react": "1.3.0"
|
|
74
74
|
},
|
|
75
75
|
"peerDependencies": {
|
|
76
76
|
"react": "^18.2.0",
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import {ForwardedRef, forwardRef, HTMLAttributes, PropsWithChildren, ReactNode} from "react";
|
|
1
|
+
import {ForwardedRef, forwardRef, HTMLAttributes, PropsWithChildren, ReactNode, useId} from "react";
|
|
2
2
|
import {border, colors, layout, lineHeight, space, textStyles, themeVars} from "../design-system";
|
|
3
3
|
import {css, cx} from "@linaria/core";
|
|
4
4
|
import {ActionsMenuItemProps} from "../actions-menu/actions-menu-item";
|
|
5
5
|
import {useActionsMenuContext} from "../actions-menu";
|
|
6
6
|
import {stopPropagation} from "@fibery/react/src/stop-propagation";
|
|
7
|
-
import {useSetActiveDangerousRow} from "../actions-menu/contexts/actions-menu-dangerous-rows";
|
|
7
|
+
import {useActiveDangerousRow, useSetActiveDangerousRow} from "../actions-menu/contexts/actions-menu-dangerous-rows";
|
|
8
8
|
import _ from "lodash";
|
|
9
|
+
import {useCallbackRef} from "@fibery/react/src/use-callback-ref";
|
|
9
10
|
|
|
10
11
|
interface ListRowSurfaceBase extends HTMLAttributes<HTMLDivElement> {
|
|
11
12
|
testId?: string;
|
|
@@ -19,11 +20,7 @@ export interface ListRowSurfaceProps extends ListRowSurfaceBase {
|
|
|
19
20
|
}
|
|
20
21
|
interface ActionMenuItemSurfaceProps
|
|
21
22
|
extends Omit<ActionsMenuItemProps, "description">,
|
|
22
|
-
Omit<ListRowSurfaceProps, "children" | "darker" | "onSelect"> {
|
|
23
|
-
id?: string;
|
|
24
|
-
showWarning?: boolean;
|
|
25
|
-
onSelect?: (e: Event) => void;
|
|
26
|
-
}
|
|
23
|
+
Omit<ListRowSurfaceProps, "children" | "darker" | "onSelect" | "id"> {}
|
|
27
24
|
export const NATUAL_HOVER_CLASS = "natural-hover";
|
|
28
25
|
export const NATUAL_FOCUS_CLASS = "natural-focus";
|
|
29
26
|
export const NATURAL_HOVER = `&.${NATUAL_HOVER_CLASS}:hover`;
|
|
@@ -227,27 +224,14 @@ export const ListRowSurface = forwardRef<HTMLDivElement, ListRowSurfaceProps>(
|
|
|
227
224
|
}
|
|
228
225
|
);
|
|
229
226
|
export const ActionMenuItemSurface = forwardRef<HTMLDivElement, ActionMenuItemSurfaceProps>(
|
|
230
|
-
(
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
id,
|
|
236
|
-
selected,
|
|
237
|
-
hovered,
|
|
238
|
-
focused,
|
|
239
|
-
title,
|
|
240
|
-
disabled,
|
|
241
|
-
children,
|
|
242
|
-
dangerous,
|
|
243
|
-
showWarning,
|
|
244
|
-
onSelect = _.noop,
|
|
245
|
-
},
|
|
246
|
-
ref
|
|
247
|
-
) => {
|
|
227
|
+
({testId, className, loading, selected, hovered, focused, title, disabled, children, dangerous, ...props}, ref) => {
|
|
228
|
+
const id = useId();
|
|
229
|
+
const activeDangerousRow = useActiveDangerousRow();
|
|
230
|
+
const showWarning = activeDangerousRow === id;
|
|
231
|
+
const onSelect = useCallbackRef(props.onSelect || _.noop);
|
|
248
232
|
const {MenuPrimitive} = useActionsMenuContext();
|
|
249
233
|
const setActiveDangerousRow = useSetActiveDangerousRow();
|
|
250
|
-
const handleSelect =
|
|
234
|
+
const handleSelect = (e: Event) => {
|
|
251
235
|
e.stopPropagation();
|
|
252
236
|
|
|
253
237
|
if (loading || !id) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {GroupHeadingProps, GroupProps, MenuListProps} from "react-select";
|
|
2
2
|
import {ItemContent, Virtuoso, VirtuosoHandle} from "react-virtuoso";
|
|
3
|
-
import {Children, ComponentType, ReactNode, useContext, useEffect, useRef} from "react";
|
|
3
|
+
import {Children, ComponentType, CSSProperties, ReactNode, useContext, useEffect, useRef, useState} from "react";
|
|
4
4
|
import {GroupBase, ReactSelectRefContext} from "../util";
|
|
5
5
|
import {layout} from "../../../src/design-system";
|
|
6
6
|
import _, {isFunction, isObject} from "lodash";
|
|
@@ -54,17 +54,10 @@ export function MenuListVirtualized<
|
|
|
54
54
|
Option,
|
|
55
55
|
IsMulti extends boolean = boolean,
|
|
56
56
|
Group extends GroupBase<Option> = GroupBase<Option>
|
|
57
|
-
>({
|
|
58
|
-
children,
|
|
59
|
-
focusedOption,
|
|
60
|
-
innerRef,
|
|
61
|
-
maxHeight,
|
|
62
|
-
theme,
|
|
63
|
-
getStyles,
|
|
64
|
-
cx,
|
|
65
|
-
selectProps,
|
|
66
|
-
}: MenuListProps<Option, IsMulti, Group>) {
|
|
57
|
+
>(props: MenuListProps<Option, IsMulti, Group>) {
|
|
58
|
+
const {children, focusedOption, innerRef, maxHeight, theme, getStyles, cx, selectProps} = props;
|
|
67
59
|
const virtuoso = useRef<VirtuosoHandle>(null);
|
|
60
|
+
|
|
68
61
|
// options props come non-filtered and we have insufficient info (props) to render groups and options from here.
|
|
69
62
|
// Also you never know what contents also possible as list content.
|
|
70
63
|
// that's why it is better working with children and find options and groups among them (hope internal API does not change)
|
|
@@ -89,11 +82,17 @@ export function MenuListVirtualized<
|
|
|
89
82
|
) : null;
|
|
90
83
|
};
|
|
91
84
|
const select = useContext(ReactSelectRefContext);
|
|
85
|
+
const [initialFocusedOption, setInitialFocusedOption] = useState<Option | null>(null);
|
|
92
86
|
|
|
93
87
|
const flattenChildren = flattenGroupChildren(children, renderGroup);
|
|
94
88
|
//fix for select not having focused option when open. if no focused item present, at least first option must be focused.
|
|
95
|
-
|
|
96
|
-
|
|
89
|
+
//Unfortunately, we can not rely on select focusedOption to determine option that should be focused initially:
|
|
90
|
+
//to mark selected option react-select uses value field of Option object.
|
|
91
|
+
//to define initially focused option react select uses whole Option object reference equality which is not always the case
|
|
92
|
+
//if select value is not exactly same object as option, we end up having initially focusedOption being just first option.
|
|
93
|
+
//fix below ensures that initial focusedOption is always selectedOption in cost of one more rerender
|
|
94
|
+
if (select.current && flattenChildren.length && !initialFocusedOption) {
|
|
95
|
+
let firstExistingOption: unknown;
|
|
97
96
|
let selectedOption: unknown;
|
|
98
97
|
//if an options exists, but there is no focused option, looking for first selected / existing option
|
|
99
98
|
for (let i = 0; i < flattenChildren.length; i++) {
|
|
@@ -113,23 +112,25 @@ export function MenuListVirtualized<
|
|
|
113
112
|
selectedOption = child.props.data;
|
|
114
113
|
break;
|
|
115
114
|
}
|
|
116
|
-
if (!
|
|
117
|
-
|
|
115
|
+
if (!firstExistingOption) {
|
|
116
|
+
firstExistingOption = child.props.data;
|
|
118
117
|
}
|
|
119
118
|
}
|
|
120
119
|
}
|
|
121
120
|
}
|
|
122
121
|
if (selectedOption) {
|
|
122
|
+
setInitialFocusedOption(selectedOption as Option);
|
|
123
123
|
select.current.setState({focusedOption: selectedOption});
|
|
124
|
-
} else if (
|
|
125
|
-
|
|
124
|
+
} else if (firstExistingOption) {
|
|
125
|
+
setInitialFocusedOption(firstExistingOption as Option);
|
|
126
|
+
select.current.setState({focusedOption: firstExistingOption});
|
|
126
127
|
}
|
|
127
128
|
}
|
|
128
129
|
const menuHeight = Math.min(flattenChildren.length * layout.menuItemHeight, maxHeight);
|
|
129
130
|
//scrolling to focused option
|
|
130
131
|
useEffect(() => {
|
|
131
132
|
let to: ReturnType<typeof setTimeout> | undefined;
|
|
132
|
-
if (focusedOption && virtuoso.current) {
|
|
133
|
+
if (initialFocusedOption && focusedOption && virtuoso.current) {
|
|
133
134
|
const index = flattenChildren.findIndex((child) => {
|
|
134
135
|
if (isObject(child) && "props" in child) {
|
|
135
136
|
if (isObject(child.props) && "data" in child.props) {
|
|
@@ -167,10 +168,10 @@ export function MenuListVirtualized<
|
|
|
167
168
|
return () => {
|
|
168
169
|
clearTimeout(to);
|
|
169
170
|
};
|
|
170
|
-
}, [focusedOption, flattenChildren, menuHeight, virtuoso]);
|
|
171
|
+
}, [focusedOption, flattenChildren, menuHeight, initialFocusedOption, virtuoso]);
|
|
171
172
|
return (
|
|
172
173
|
// Needed for correct display inside portals and etc.
|
|
173
|
-
<div>
|
|
174
|
+
<div style={getStyles("menuList", props) as CSSProperties}>
|
|
174
175
|
<Virtuoso
|
|
175
176
|
ref={virtuoso}
|
|
176
177
|
// in reality only HTMLDiveElement | null will appear here. We do not use Virtuoso's useWindowScroll prop
|
|
@@ -10,11 +10,11 @@ const noOptionMessageClass = css`
|
|
|
10
10
|
`;
|
|
11
11
|
const noOptionMessageContentClass = css`
|
|
12
12
|
padding: 0 ${space.s6}px;
|
|
13
|
-
line-height: ${layout.menuItemHeight}px;
|
|
14
13
|
white-space: nowrap;
|
|
15
14
|
overflow: hidden;
|
|
16
15
|
text-overflow: ellipsis;
|
|
17
16
|
${{...textStyles.regular}}
|
|
17
|
+
line-height: ${layout.menuItemHeight}px;
|
|
18
18
|
`;
|
|
19
19
|
|
|
20
20
|
export const NoOptionsMessage = ({children}: {children: ReactNode}) => {
|
package/src/error-alert.tsx
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import {css} from "@linaria/core";
|
|
2
|
-
import {layout, border, space, textStyles, themeVars} from "./design-system";
|
|
3
|
-
import {Button} from "./button/button";
|
|
4
|
-
import CloseIcon from "./icons/react/Close";
|
|
5
|
-
import {useTheme} from "./theme-provider";
|
|
6
|
-
|
|
7
|
-
const errorAlert = css`
|
|
8
|
-
background-color: ${themeVars.errorBgColor};
|
|
9
|
-
padding: ${space.s8}px ${space.s12}px;
|
|
10
|
-
min-height: ${layout.itemHeight}px;
|
|
11
|
-
border-radius: ${border.radius6}px;
|
|
12
|
-
display: flex;
|
|
13
|
-
gap: ${space.s6}px;
|
|
14
|
-
align-items: center;
|
|
15
|
-
`;
|
|
16
|
-
|
|
17
|
-
const messageStyle = css`
|
|
18
|
-
${textStyles.heading5};
|
|
19
|
-
color: ${themeVars.errorTextColor};
|
|
20
|
-
`;
|
|
21
|
-
|
|
22
|
-
const descriptionStyle = css`
|
|
23
|
-
${textStyles.regular};
|
|
24
|
-
color: ${themeVars.errorTextColor};
|
|
25
|
-
`;
|
|
26
|
-
|
|
27
|
-
export function ErrorAlert({
|
|
28
|
-
message,
|
|
29
|
-
description,
|
|
30
|
-
closable,
|
|
31
|
-
onClose,
|
|
32
|
-
}: {
|
|
33
|
-
message: string;
|
|
34
|
-
description?: React.ReactNode;
|
|
35
|
-
closable?: boolean;
|
|
36
|
-
onClose?: () => void;
|
|
37
|
-
}): JSX.Element {
|
|
38
|
-
const theme = useTheme();
|
|
39
|
-
const buttonColor = theme.errorButtonColor;
|
|
40
|
-
return (
|
|
41
|
-
<div className={errorAlert}>
|
|
42
|
-
<div
|
|
43
|
-
className={css`
|
|
44
|
-
flex-grow: 2;
|
|
45
|
-
`}
|
|
46
|
-
>
|
|
47
|
-
<div className={messageStyle}>{message}</div>
|
|
48
|
-
{description ? <div className={descriptionStyle}>{description}</div> : null}
|
|
49
|
-
</div>
|
|
50
|
-
{closable && onClose ? (
|
|
51
|
-
<div>
|
|
52
|
-
<Button borderless onClick={onClose} color={buttonColor} Icon={CloseIcon} width={24} />
|
|
53
|
-
</div>
|
|
54
|
-
) : null}
|
|
55
|
-
</div>
|
|
56
|
-
);
|
|
57
|
-
}
|