@fibery/ui-kit 1.26.5 → 1.26.7

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.26.5",
3
+ "version": "1.26.7",
4
4
  "private": false,
5
5
  "files": [
6
6
  "src/antd/styles.ts",
@@ -28,10 +28,16 @@
28
28
  "src/toast/**/*.ts*",
29
29
  "src/lists/**/*.ts*",
30
30
  "src/a11y-color.ts",
31
- "src/integration-compact-info-button.tsx"
31
+ "src/integration-compact-info-button.tsx",
32
+ "src/dropdown-menu",
33
+ "src/shortcut-badge",
34
+ "src/tsfixme"
32
35
  ],
33
36
  "license": "UNLICENSED",
34
37
  "dependencies": {
38
+ "@fibery/emoji-data": "2.4.0",
39
+ "@fibery/helpers": "1.2.0",
40
+ "@fibery/react": "1.3.1",
35
41
  "@linaria/core": "5.0.1",
36
42
  "@linaria/react": "5.0.1",
37
43
  "@popperjs/core": "2.11.6",
@@ -68,10 +74,7 @@
68
74
  "react-select-country-list": "2.2.1",
69
75
  "react-virtuoso": "4.6.0",
70
76
  "screenfull": "6.0.1",
71
- "ua-parser-js": "0.7.24",
72
- "@fibery/emoji-data": "2.4.0",
73
- "@fibery/helpers": "1.2.0",
74
- "@fibery/react": "1.3.0"
77
+ "ua-parser-js": "0.7.24"
75
78
  },
76
79
  "peerDependencies": {
77
80
  "react": "^18.2.0",
@@ -80,6 +83,8 @@
80
83
  "devDependencies": {
81
84
  "@babel/core": "7.23.9",
82
85
  "@babel/runtime": "7.23.9",
86
+ "@fibery/babel-preset": "7.4.0",
87
+ "@fibery/eslint-config": "8.5.1",
83
88
  "@linaria/babel-preset": "5.0.3",
84
89
  "@testing-library/dom": "8.19.1",
85
90
  "@testing-library/jest-dom": "5.16.5",
@@ -103,9 +108,7 @@
103
108
  "svg-parser": "2.0.4",
104
109
  "svgo": "2.8.0",
105
110
  "typescript": "5.1.6",
106
- "unist-util-reduce": "0.2.2",
107
- "@fibery/eslint-config": "8.5.1",
108
- "@fibery/babel-preset": "7.4.0"
111
+ "unist-util-reduce": "0.2.2"
109
112
  },
110
113
  "jest": {
111
114
  "testEnvironment": "jsdom",
@@ -0,0 +1,169 @@
1
+ import {Wrap} from "@fibery/react/src/wrap";
2
+ import {css, cx} from "@linaria/core";
3
+ import {styled} from "@linaria/react";
4
+ import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
5
+ import {forwardRef} from "react";
6
+ import {border, layout, space, textStyles, themeVars} from "../design-system";
7
+
8
+ export const Root = (dropdownMenuProps: DropdownMenuPrimitive.DropdownMenuProps) => (
9
+ <DropdownMenuPrimitive.Root dir="ltr" modal={false} {...dropdownMenuProps} />
10
+ );
11
+
12
+ export const Trigger = DropdownMenuPrimitive.Trigger;
13
+
14
+ const rowItemStyles = {
15
+ ...textStyles.regular,
16
+ display: "flex",
17
+ alignItems: "center",
18
+ minHeight: layout.menuItemHeight,
19
+ outline: "none",
20
+ borderRadius: border.radius6,
21
+ padding: `0px ${space.s12}px`,
22
+ margin: `0px ${space.s4}px`,
23
+ cursor: "pointer",
24
+
25
+ "&:hover,&[data-highlighted]": {
26
+ marginLeft: 4,
27
+ marginRight: 4,
28
+ backgroundColor: themeVars.colorBgActionsMenuItemHover,
29
+ borderRadius: border.radius6,
30
+ },
31
+
32
+ "&[data-disabled]": {
33
+ cursor: "default",
34
+ opacity: 0.4,
35
+
36
+ "&:hover": {
37
+ backgroundColor: "unset",
38
+ },
39
+ },
40
+ };
41
+
42
+ const dropdownMenuContentStyles = css`
43
+ @keyframes slideDown {
44
+ from {
45
+ opacity: 0;
46
+ transform: translateY(-2px);
47
+ }
48
+ to {
49
+ opacity: 1;
50
+ transform: translateY(0);
51
+ }
52
+ }
53
+ @keyframes slideUp {
54
+ from {
55
+ opacity: 0;
56
+ transform: translateY(2px);
57
+ }
58
+ to {
59
+ opacity: 1;
60
+ transform: translateY(0);
61
+ }
62
+ }
63
+
64
+ overflow-y: auto;
65
+ overflow-x: hidden;
66
+
67
+ /* ant dropdown have z-index 1000 and sometimes we need to open dropdown from ant's one
68
+ * e.g. backlog actions on calendar
69
+ * TODO: use more reliable z-index strategy
70
+ */
71
+ z-index: 1001;
72
+
73
+ max-height: min(var(--radix-dropdown-menu-content-available-height), 692px);
74
+ padding-top: ${space.s4}px;
75
+ padding-bottom: ${space.s4}px;
76
+ min-width: 200px;
77
+ box-shadow: ${themeVars.actionMenuShadow};
78
+ border-radius: ${border.radius8}px;
79
+ backdrop-filter: ${themeVars.effectBgActionsMenu};
80
+ background-color: ${themeVars.colorBgActionsMenu};
81
+
82
+ @media (prefers-reduced-motion: no-preference) {
83
+ animation-duration: 400ms;
84
+ animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
85
+ animation-fill-mode: forwards;
86
+ will-change: transform, opacity;
87
+ &[data-state="open"] {
88
+ &[data-side="top"] {
89
+ animation-name: slideUp;
90
+ }
91
+ &[data-side="bottom"] {
92
+ animation-name: slideDown;
93
+ }
94
+ }
95
+ }
96
+ `;
97
+
98
+ export type ContentProps = DropdownMenuPrimitive.DropdownMenuContentProps & {
99
+ /* render content in portal. NOTE: Changing this prop will lead to re-mount */
100
+ portalled?: boolean;
101
+ collisionPadding?: number;
102
+ };
103
+
104
+ const onContentKeyDown = (e: React.KeyboardEvent) => {
105
+ // Escape is attached to document that's why we can't stop propagation of it
106
+ // For other cases we'd like to avoid accidental key handlers e.g. in Inbox
107
+ // (we can chage it in the future ref. https://fibery.slack.com/archives/C05CH6YTSKW/p1692271916224909 https://fibery.slack.com/archives/C05CH6YTSKW/p1692272716431819)
108
+ if (e.key !== "Escape") {
109
+ e.stopPropagation();
110
+ }
111
+ };
112
+
113
+ export const Content = forwardRef<HTMLDivElement, ContentProps>(function DropdownMenuContent(
114
+ {className, portalled = true, collisionPadding = space.s12, ...rest},
115
+ ref
116
+ ) {
117
+ return (
118
+ <Wrap if={portalled} with={DropdownMenuPrimitive.Portal}>
119
+ <DropdownMenuPrimitive.Content
120
+ onKeyDown={onContentKeyDown}
121
+ ref={ref}
122
+ className={cx(dropdownMenuContentStyles, className)}
123
+ side="bottom"
124
+ align="start"
125
+ collisionPadding={collisionPadding}
126
+ sideOffset={space.s4}
127
+ {...rest}
128
+ />
129
+ </Wrap>
130
+ );
131
+ });
132
+
133
+ export const Sub = DropdownMenuPrimitive.Sub;
134
+
135
+ export const SubContent = forwardRef<HTMLDivElement, DropdownMenuPrimitive.DropdownMenuSubContentProps>(
136
+ function DropdownMenuSubContent({className, ...rest}, ref) {
137
+ return (
138
+ <DropdownMenuPrimitive.Portal>
139
+ <DropdownMenuPrimitive.SubContent ref={ref} className={cx(dropdownMenuContentStyles, className)} {...rest} />
140
+ </DropdownMenuPrimitive.Portal>
141
+ );
142
+ }
143
+ );
144
+
145
+ export const SubTrigger = styled(DropdownMenuPrimitive.SubTrigger)`
146
+ ${rowItemStyles}
147
+ `;
148
+
149
+ export const Item = styled(DropdownMenuPrimitive.Item)`
150
+ ${rowItemStyles}
151
+ `;
152
+
153
+ export const Separator = styled(DropdownMenuPrimitive.Separator)`
154
+ ${{
155
+ backgroundColor: themeVars.separatorColor,
156
+ height: 1,
157
+ margin: `${space.s4}px 0`,
158
+ }}
159
+ `;
160
+
161
+ export const Group = DropdownMenuPrimitive.Group;
162
+
163
+ export const Label = styled(DropdownMenuPrimitive.Label)`
164
+ ${{
165
+ ...textStyles.small,
166
+ color: themeVars.accentTextColor,
167
+ padding: `${space.s6}px ${space.s12}px`,
168
+ }}
169
+ `;
@@ -0,0 +1,144 @@
1
+ import {stopPropagation} from "@fibery/react/src/stop-propagation";
2
+ import {useCallbackRef} from "@fibery/react/src/use-callback-ref";
3
+ import {css, cx} from "@linaria/core";
4
+ import _ from "lodash";
5
+ import {forwardRef, useId} from "react";
6
+ import {useActionsMenuContext} from "../actions-menu";
7
+ import {ActionsMenuItemProps} from "../actions-menu/actions-menu-item";
8
+ import {useActiveDangerousRow, useSetActiveDangerousRow} from "../actions-menu/contexts/actions-menu-dangerous-rows";
9
+ import {colors, layout, lineHeight, space, textStyles, themeVars} from "../design-system";
10
+ import {
11
+ ListRowContent,
12
+ ListRowContentProps,
13
+ ListRowSurfaceProps,
14
+ NATUAL_FOCUS_CLASS,
15
+ NATUAL_HOVER_CLASS,
16
+ NATURAL_HOVER,
17
+ listRowSurfaceStylesBase,
18
+ } from "./list-row-surface";
19
+
20
+ interface ActionMenuItemSurfaceProps
21
+ extends Omit<ActionsMenuItemProps, "description">,
22
+ Omit<ListRowSurfaceProps, "children" | "darker" | "onSelect" | "id"> {}
23
+
24
+ export const actionMenuItemSurface = css`
25
+ margin: 0 ${space.s4}px;
26
+ background-color: ${themeVars.colorBgListItemGeneral};
27
+ ${NATURAL_HOVER},
28
+ &[data-highlighted] {
29
+ background-color: ${themeVars.colorBgActionsMenuItemHover};
30
+ }
31
+ &.done,
32
+ &[data-disabled] {
33
+ cursor: not-allowed;
34
+ color: ${themeVars.colorTextListItemGeneralDisabled};
35
+ background-color: ${themeVars.colorBgListItemGeneralDisabled};
36
+ ${NATURAL_HOVER}, &.hover > * {
37
+ opacity: ${themeVars.opacityListItemGeneralDisabled};
38
+ }
39
+ }
40
+ &.selected {
41
+ cursor: default;
42
+ background-color: ${themeVars.colorBgActionsMenuItemSelected};
43
+ ${NATURAL_HOVER},&.hover, &[data-highlighted] {
44
+ background-color: ${themeVars.colorBgActionsMenuItemSelectedHover};
45
+ }
46
+ }
47
+ &.dangerous {
48
+ background-color: ${themeVars.colorBgActionsMenuItemDangerActive};
49
+ ${NATURAL_HOVER},
50
+ &.hover,
51
+ &[data-highlighted] {
52
+ background-color: ${themeVars.colorBgActionsMenuItemDangerActive};
53
+ }
54
+ }
55
+ &.warm {
56
+ background-color: ${themeVars.colorBgActionsMenuItemDangerActive};
57
+ color: ${colors.inversedTextColor};
58
+ ${NATURAL_HOVER}, &.hover,
59
+ &[data-highlighted] {
60
+ background-color: ${themeVars.colorBgActionsMenuItemDangerActive};
61
+ color: ${colors.inversedTextColor};
62
+ }
63
+ }
64
+ `;
65
+
66
+ export const ActionMenuItemSurface = forwardRef<HTMLDivElement, ActionMenuItemSurfaceProps>(
67
+ ({testId, className, loading, selected, hovered, focused, title, disabled, children, dangerous, ...props}, ref) => {
68
+ const id = useId();
69
+ const activeDangerousRow = useActiveDangerousRow();
70
+ const showWarning = activeDangerousRow === id;
71
+ const onSelect = useCallbackRef(props.onSelect || _.noop);
72
+ const {MenuPrimitive} = useActionsMenuContext();
73
+ const setActiveDangerousRow = useSetActiveDangerousRow();
74
+ const handleSelect = (e: Event) => {
75
+ e.stopPropagation();
76
+
77
+ if (loading || !id) {
78
+ e.preventDefault();
79
+ return;
80
+ }
81
+
82
+ if (dangerous && !showWarning) {
83
+ e.preventDefault();
84
+ setActiveDangerousRow(id);
85
+ return;
86
+ }
87
+
88
+ setActiveDangerousRow(null);
89
+
90
+ onSelect(e);
91
+ };
92
+ return (
93
+ <MenuPrimitive.Item
94
+ ref={ref}
95
+ data-testid={testId}
96
+ onClick={stopPropagation}
97
+ onSelect={handleSelect}
98
+ title={title ? title : ""}
99
+ className={cx(
100
+ listRowSurfaceStylesBase,
101
+ actionMenuItemSurface,
102
+ className,
103
+ hovered === undefined && NATUAL_HOVER_CLASS,
104
+ focused === undefined && NATUAL_FOCUS_CLASS,
105
+ focused && "focus",
106
+ disabled && "done",
107
+ selected && "selected",
108
+ dangerous && "dangerous",
109
+ showWarning && "warn"
110
+ )}
111
+ disabled={disabled}
112
+ >
113
+ {children}
114
+ </MenuPrimitive.Item>
115
+ );
116
+ }
117
+ );
118
+
119
+ interface ActionMenuItemContentProps extends ListRowContentProps {
120
+ description?: string;
121
+ }
122
+ const actionMenuItemDescriptionClass = css`
123
+ ${textStyles.small};
124
+ line-height: ${lineHeight.nowrap};
125
+ color: ${themeVars.accentTextColor};
126
+ padding: ${space.s2}px ${space.s8}px 0;
127
+ `;
128
+ const actionMenuItemContentClass = css`
129
+ line-height: ${layout.menuItemHeight}px;
130
+ padding: 0 ${space.s8}px;
131
+ `;
132
+ const actionMenuItemWithDescription = css`
133
+ min-height: ${layout.itemWithSubtitleHeight}px;
134
+ `;
135
+ export const ActionMenuItemContent = forwardRef<HTMLDivElement, ActionMenuItemContentProps>(
136
+ ({contentClassName, description, ...rest}, ref) => {
137
+ return (
138
+ <div className={cx(description && actionMenuItemWithDescription)}>
139
+ <ListRowContent contentClassName={cx(contentClassName, actionMenuItemContentClass)} ref={ref} {...rest} />
140
+ {description ? <div className={actionMenuItemDescriptionClass}>{description}</div> : null}
141
+ </div>
142
+ );
143
+ }
144
+ );
@@ -1,12 +1,6 @@
1
- import {ForwardedRef, forwardRef, HTMLAttributes, PropsWithChildren, ReactNode, useId} from "react";
2
- import {border, colors, layout, lineHeight, space, textStyles, themeVars} from "../design-system";
3
1
  import {css, cx} from "@linaria/core";
4
- import {ActionsMenuItemProps} from "../actions-menu/actions-menu-item";
5
- import {useActionsMenuContext} from "../actions-menu";
6
- import {stopPropagation} from "@fibery/react/src/stop-propagation";
7
- import {useActiveDangerousRow, useSetActiveDangerousRow} from "../actions-menu/contexts/actions-menu-dangerous-rows";
8
- import _ from "lodash";
9
- import {useCallbackRef} from "@fibery/react/src/use-callback-ref";
2
+ import {ForwardedRef, forwardRef, HTMLAttributes, PropsWithChildren, ReactNode} from "react";
3
+ import {border, space, textStyles, themeVars} from "../design-system";
10
4
 
11
5
  interface ListRowSurfaceBase extends HTMLAttributes<HTMLDivElement> {
12
6
  testId?: string;
@@ -18,9 +12,7 @@ export interface ListRowSurfaceProps extends ListRowSurfaceBase {
18
12
  focused?: boolean;
19
13
  hovered?: boolean;
20
14
  }
21
- interface ActionMenuItemSurfaceProps
22
- extends Omit<ActionsMenuItemProps, "description">,
23
- Omit<ListRowSurfaceProps, "children" | "darker" | "onSelect" | "id"> {}
15
+
24
16
  export const NATUAL_HOVER_CLASS = "natural-hover";
25
17
  export const NATUAL_FOCUS_CLASS = "natural-focus";
26
18
  export const NATURAL_HOVER = `&.${NATUAL_HOVER_CLASS}:hover`;
@@ -152,48 +144,6 @@ export const listRowSurfaceStatesDark = css`
152
144
  }
153
145
  `;
154
146
 
155
- export const actionMenuItemSurface = css`
156
- margin: 0 ${space.s4}px;
157
- background-color: ${themeVars.colorBgListItemGeneral};
158
- ${NATURAL_HOVER},
159
- &[data-highlighted] {
160
- background-color: ${themeVars.colorBgActionsMenuItemHover};
161
- }
162
- &.done,
163
- &[data-disabled] {
164
- cursor: not-allowed;
165
- color: ${themeVars.colorTextListItemGeneralDisabled};
166
- background-color: ${themeVars.colorBgListItemGeneralDisabled};
167
- ${NATURAL_HOVER}, &.hover > * {
168
- opacity: ${themeVars.opacityListItemGeneralDisabled};
169
- }
170
- }
171
- &.selected {
172
- cursor: default;
173
- background-color: ${themeVars.colorBgActionsMenuItemSelected};
174
- ${NATURAL_HOVER},&.hover, &[data-highlighted] {
175
- background-color: ${themeVars.colorBgActionsMenuItemSelectedHover};
176
- }
177
- }
178
- &.dangerous {
179
- background-color: ${themeVars.colorBgActionsMenuItemDangerActive};
180
- ${NATURAL_HOVER},
181
- &.hover,
182
- &[data-highlighted] {
183
- background-color: ${themeVars.colorBgActionsMenuItemDangerActive};
184
- }
185
- }
186
- &.warm {
187
- background-color: ${themeVars.colorBgActionsMenuItemDangerActive};
188
- color: ${colors.inversedTextColor};
189
- ${NATURAL_HOVER}, &.hover,
190
- &[data-highlighted] {
191
- background-color: ${themeVars.colorBgActionsMenuItemDangerActive};
192
- color: ${colors.inversedTextColor};
193
- }
194
- }
195
- `;
196
-
197
147
  /**
198
148
  * This should be responsible for all flat list items existing in UI in Fibery. Options, action menus and etc.
199
149
  * You can enforce it's state with props focused, hovered, selected, done (use it for disabled too)
@@ -222,58 +172,6 @@ export const ListRowSurface = forwardRef<HTMLDivElement, ListRowSurfaceProps>(
222
172
  );
223
173
  }
224
174
  );
225
- export const ActionMenuItemSurface = forwardRef<HTMLDivElement, ActionMenuItemSurfaceProps>(
226
- ({testId, className, loading, selected, hovered, focused, title, disabled, children, dangerous, ...props}, ref) => {
227
- const id = useId();
228
- const activeDangerousRow = useActiveDangerousRow();
229
- const showWarning = activeDangerousRow === id;
230
- const onSelect = useCallbackRef(props.onSelect || _.noop);
231
- const {MenuPrimitive} = useActionsMenuContext();
232
- const setActiveDangerousRow = useSetActiveDangerousRow();
233
- const handleSelect = (e: Event) => {
234
- e.stopPropagation();
235
-
236
- if (loading || !id) {
237
- e.preventDefault();
238
- return;
239
- }
240
-
241
- if (dangerous && !showWarning) {
242
- e.preventDefault();
243
- setActiveDangerousRow(id);
244
- return;
245
- }
246
-
247
- setActiveDangerousRow(null);
248
-
249
- onSelect(e);
250
- };
251
- return (
252
- <MenuPrimitive.Item
253
- ref={ref}
254
- data-testid={testId}
255
- onClick={stopPropagation}
256
- onSelect={handleSelect}
257
- title={title ? title : ""}
258
- className={cx(
259
- listRowSurfaceStylesBase,
260
- actionMenuItemSurface,
261
- className,
262
- hovered === undefined && NATUAL_HOVER_CLASS,
263
- focused === undefined && NATUAL_FOCUS_CLASS,
264
- focused && "focus",
265
- disabled && "done",
266
- selected && "selected",
267
- dangerous && "dangerous",
268
- showWarning && "warn"
269
- )}
270
- disabled={disabled}
271
- >
272
- {children}
273
- </MenuPrimitive.Item>
274
- );
275
- }
276
- );
277
175
 
278
176
  export interface ListRowContentProps extends PropsWithChildren<Omit<HTMLAttributes<HTMLDivElement>, "className">> {
279
177
  rootClassName?: string;
@@ -322,30 +220,3 @@ export const ListRowContent = forwardRef<HTMLDivElement, ListRowContentProps>(
322
220
  );
323
221
  }
324
222
  );
325
-
326
- interface ActionMenuItemContentProps extends ListRowContentProps {
327
- description?: string;
328
- }
329
- const actionMenuItemDescriptionClass = css`
330
- ${textStyles.small};
331
- line-height: ${lineHeight.nowrap};
332
- color: ${themeVars.accentTextColor};
333
- padding: ${space.s2}px ${space.s8}px 0;
334
- `;
335
- const actionMenuItemContentClass = css`
336
- line-height: ${layout.menuItemHeight}px;
337
- padding: 0 ${space.s8}px;
338
- `;
339
- const actionMenuItemWithDescription = css`
340
- min-height: ${layout.itemWithSubtitleHeight}px;
341
- `;
342
- export const ActionMenuItemContent = forwardRef<HTMLDivElement, ActionMenuItemContentProps>(
343
- ({contentClassName, description, ...rest}, ref) => {
344
- return (
345
- <div className={cx(description && actionMenuItemWithDescription)}>
346
- <ListRowContent contentClassName={cx(contentClassName, actionMenuItemContentClass)} ref={ref} {...rest} />
347
- {description ? <div className={actionMenuItemDescriptionClass}>{description}</div> : null}
348
- </div>
349
- );
350
- }
351
- );
@@ -131,7 +131,7 @@ export function MenuListVirtualized<
131
131
  const menuHeight = Math.min(flattenChildren.length * layout.menuItemHeight, maxHeight);
132
132
  //scrolling to focused option
133
133
  useEffect(() => {
134
- let to: ReturnType<typeof setTimeout> | undefined;
134
+ let to: number | undefined;
135
135
  if (initialFocusedOption && focusedOption && virtuoso.current) {
136
136
  const index = flattenChildren.findIndex((child) => {
137
137
  if (isObject(child) && "props" in child) {
@@ -144,7 +144,7 @@ export function MenuListVirtualized<
144
144
  if (index >= 0) {
145
145
  const focusedOptionPosition = index * OPTION_HEIGHT;
146
146
  virtuoso.current.getState((state) => {
147
- to = setTimeout(() => {
147
+ to = window.setTimeout(() => {
148
148
  if (!virtuoso.current) {
149
149
  return;
150
150
  }
@@ -168,7 +168,7 @@ export function MenuListVirtualized<
168
168
  }
169
169
  }
170
170
  return () => {
171
- clearTimeout(to);
171
+ window.clearTimeout(to);
172
172
  };
173
173
  }, [focusedOption, flattenChildren, menuHeight, initialFocusedOption, virtuoso]);
174
174
  return (