@fibery/ui-kit 1.29.1 → 1.29.4

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.
Files changed (77) hide show
  1. package/package.json +4 -4
  2. package/src/actions-menu/actions-menu-confirmation.tsx +70 -0
  3. package/src/actions-menu/actions-menu-item.tsx +3 -1
  4. package/src/actions-menu/actions-menu-sub-command-menu.tsx +104 -141
  5. package/src/actions-menu/actions-menu-sub-menu.tsx +3 -1
  6. package/src/actions-menu/actions-menu.tsx +6 -1
  7. package/src/actions-menu/context-actions-menu.tsx +5 -1
  8. package/src/actions-menu/contexts/actions-menu-context.tsx +6 -2
  9. package/src/button/button-base.tsx +1 -1
  10. package/src/button/button.tsx +1 -1
  11. package/src/design-system.ts +83 -25
  12. package/src/dropdown-menu/index.tsx +7 -2
  13. package/src/emoji-picker/primitives/footer.tsx +1 -1
  14. package/src/icons/ast/Abort.ts +8 -0
  15. package/src/icons/ast/AiAvatar.ts +1 -1
  16. package/src/icons/ast/Database.ts +1 -1
  17. package/src/icons/ast/DatabaseStroke.ts +8 -0
  18. package/src/icons/ast/ExtensionComments.ts +1 -1
  19. package/src/icons/ast/FieldUnit.ts +8 -0
  20. package/src/icons/ast/InfoCircle.ts +8 -0
  21. package/src/icons/ast/IntegrationsIntegrationDiscourseColor.ts +8 -0
  22. package/src/icons/ast/IntegrationsIntegrationIntercomColor.ts +8 -0
  23. package/src/icons/ast/IntegrationsIntegrationSlackColor.ts +8 -0
  24. package/src/icons/ast/IntegrationsIntegrationZendeskColor.ts +8 -0
  25. package/src/icons/ast/Key.ts +8 -0
  26. package/src/icons/ast/MoveBottom.ts +8 -0
  27. package/src/icons/ast/MoveLeft.ts +8 -0
  28. package/src/icons/ast/MoveRight.ts +8 -0
  29. package/src/icons/ast/MoveTop.ts +8 -0
  30. package/src/icons/ast/Pin.ts +8 -0
  31. package/src/icons/ast/RicheditorCommentCreate.ts +1 -1
  32. package/src/icons/ast/SendArrow.ts +8 -0
  33. package/src/icons/ast/UnitsAvatar.ts +8 -0
  34. package/src/icons/ast/UnitsCollection.ts +8 -0
  35. package/src/icons/ast/UnitsCounter.ts +8 -0
  36. package/src/icons/ast/UnitsDbBadgeAbbr.ts +8 -0
  37. package/src/icons/ast/UnitsDbBadgeFull.ts +8 -0
  38. package/src/icons/ast/UnitsDbIcon.ts +8 -0
  39. package/src/icons/ast/UnitsField.ts +8 -0
  40. package/src/icons/ast/UnitsInput.ts +8 -0
  41. package/src/icons/ast/UnitsProgressBar.ts +8 -0
  42. package/src/icons/ast/UnitsRichText.ts +8 -0
  43. package/src/icons/ast/UnitsSnippet.ts +8 -0
  44. package/src/icons/ast/index.tsx +26 -0
  45. package/src/icons/react/Abort.tsx +12 -0
  46. package/src/icons/react/DatabaseStroke.tsx +12 -0
  47. package/src/icons/react/FieldUnit.tsx +12 -0
  48. package/src/icons/react/InfoCircle.tsx +12 -0
  49. package/src/icons/react/IntegrationsIntegrationDiscourseColor.tsx +12 -0
  50. package/src/icons/react/IntegrationsIntegrationIntercomColor.tsx +12 -0
  51. package/src/icons/react/IntegrationsIntegrationSlackColor.tsx +12 -0
  52. package/src/icons/react/IntegrationsIntegrationZendeskColor.tsx +12 -0
  53. package/src/icons/react/Key.tsx +12 -0
  54. package/src/icons/react/MoveBottom.tsx +12 -0
  55. package/src/icons/react/MoveLeft.tsx +12 -0
  56. package/src/icons/react/MoveRight.tsx +12 -0
  57. package/src/icons/react/MoveTop.tsx +12 -0
  58. package/src/icons/react/Pin.tsx +12 -0
  59. package/src/icons/react/SendArrow.tsx +12 -0
  60. package/src/icons/react/UnitsAvatar.tsx +12 -0
  61. package/src/icons/react/UnitsCollection.tsx +12 -0
  62. package/src/icons/react/UnitsCounter.tsx +12 -0
  63. package/src/icons/react/UnitsDbBadgeAbbr.tsx +12 -0
  64. package/src/icons/react/UnitsDbBadgeFull.tsx +12 -0
  65. package/src/icons/react/UnitsDbIcon.tsx +12 -0
  66. package/src/icons/react/UnitsField.tsx +12 -0
  67. package/src/icons/react/UnitsInput.tsx +12 -0
  68. package/src/icons/react/UnitsProgressBar.tsx +12 -0
  69. package/src/icons/react/UnitsRichText.tsx +12 -0
  70. package/src/icons/react/UnitsSnippet.tsx +12 -0
  71. package/src/icons/react/index.tsx +26 -0
  72. package/src/item.tsx +1 -1
  73. package/src/select/custom-select-partials/menu.tsx +1 -1
  74. package/src/select/select-in-popover.tsx +58 -11
  75. package/src/theme-settings.ts +10 -8
  76. package/src/toggle.tsx +3 -1
  77. package/src/tooltip.tsx +4 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fibery/ui-kit",
3
- "version": "1.29.1",
3
+ "version": "1.29.4",
4
4
  "private": false,
5
5
  "files": [
6
6
  "src/antd/styles.ts",
@@ -54,7 +54,7 @@
54
54
  "chroma-js": "2.1.2",
55
55
  "chrono-node": "^2.7.5",
56
56
  "classnames": "2.3.1",
57
- "cmdk": "0.2.0",
57
+ "cmdk": "1.0.0",
58
58
  "color-hash": "1.0.3",
59
59
  "d3-shape": "1.3.7",
60
60
  "date-fns": "2.29.2",
@@ -110,8 +110,8 @@
110
110
  "svgo": "2.8.0",
111
111
  "typescript": "5.4.3",
112
112
  "unist-util-reduce": "0.2.2",
113
- "@fibery/eslint-config": "8.6.0",
114
- "@fibery/babel-preset": "7.4.0"
113
+ "@fibery/babel-preset": "7.4.0",
114
+ "@fibery/eslint-config": "8.6.0"
115
115
  },
116
116
  "jest": {
117
117
  "testEnvironment": "jsdom",
@@ -0,0 +1,70 @@
1
+ import {css} from "@linaria/core";
2
+ import {AntModal} from "../antd/ant-modal";
3
+ import {border, space, themeVars} from "../design-system";
4
+ import {ActionsPanel} from "../actions-panel";
5
+ import {Button} from "../button";
6
+ import {useActionsMenuContext} from "./contexts/actions-menu-context";
7
+
8
+ const modalClass = css`
9
+ & .ant-modal-content {
10
+ box-shadow: ${themeVars.shadowModal};
11
+ margin-left: ${space.s6}px;
12
+ margin-right: ${space.s6}px;
13
+ background-color: ${themeVars.modalContentBg};
14
+ border-radius: ${border.radius6}px;
15
+ }
16
+ `;
17
+
18
+ export type ActionsMenuConfirmationProps = {
19
+ message: string;
20
+ onCancel?: () => void;
21
+ onConfirm: () => void;
22
+ };
23
+
24
+ export const ActionsMenuConfirmation: React.FC<ActionsMenuConfirmationProps> = ({message, onCancel, onConfirm}) => {
25
+ const {showConfirmation} = useActionsMenuContext();
26
+
27
+ // TODO: use radix dialog
28
+ return (
29
+ <AntModal
30
+ zIndex={1001} // ant vs radix -- round 1
31
+ open={true}
32
+ closable={false}
33
+ footer={null}
34
+ maskStyle={{backgroundColor: themeVars.modalBg}}
35
+ className={modalClass}
36
+ maskClosable
37
+ onCancel={() => showConfirmation(null)}
38
+ >
39
+ {message}
40
+
41
+ <div
42
+ className={css`
43
+ margin-top: ${space.s24}px;
44
+ display: flex;
45
+ gap: ${space.s6}px;
46
+ `}
47
+ >
48
+ <ActionsPanel inline>
49
+ <Button
50
+ primary
51
+ onClick={() => {
52
+ onConfirm();
53
+ showConfirmation(null);
54
+ }}
55
+ >
56
+ Proceed
57
+ </Button>
58
+ <Button
59
+ onClick={() => {
60
+ showConfirmation(null);
61
+ onCancel?.();
62
+ }}
63
+ >
64
+ Cancel
65
+ </Button>
66
+ </ActionsPanel>
67
+ </div>
68
+ </AntModal>
69
+ );
70
+ };
@@ -40,6 +40,8 @@ const dangerousItemCss = css`
40
40
  &[data-highlighted] {
41
41
  color: ${themeVars.danger};
42
42
  background-color: ${themeVars.colorBgActionsMenuItemDangerHover};
43
+
44
+ --actions-menu-item-icon-color: ${themeVars.danger};
43
45
  }
44
46
  }
45
47
  `;
@@ -94,7 +96,7 @@ const RightCorner = ({shortcut, loading, checked}: {shortcut?: string; loading?:
94
96
  const LeftCorner = ({Icon}: {Icon: FunctionComponent<IconBaseProps> | void}) => {
95
97
  return Icon ? (
96
98
  <div className={cornerCss}>
97
- <Icon color={themeVars.iconColor} iconSize={18} />
99
+ <Icon color={`var(--actions-menu-item-icon-color, ${themeVars.iconColor})`} iconSize={18} />
98
100
  </div>
99
101
  ) : null;
100
102
  };
@@ -1,59 +1,41 @@
1
+ import {composeEventHandlers} from "@fibery/react/src/compose-event-handlers";
2
+ import {createContext} from "@fibery/react/src/create-context";
3
+ import {stopPropagation} from "@fibery/react/src/stop-propagation";
1
4
  import {css, cx} from "@linaria/core";
2
- import {CommandInput, CommandItem, CommandList, CommandRoot, CommandEmpty} from "cmdk";
3
- import {border, layout, space, textStyles, themeVars} from "../design-system";
4
- import Search from "../icons/react/Search";
5
- import {useActionsMenuContext} from "./contexts/actions-menu-context";
5
+ import React, {RefObject, useEffect, useMemo, useRef, useState} from "react";
6
+ import {
7
+ CommandMenuEmpty,
8
+ CommandMenuGroup,
9
+ CommandMenuInput,
10
+ CommandMenuItem,
11
+ CommandMenuList,
12
+ CommandMenuRoot,
13
+ } from "../command-menu";
6
14
  import {ActionsMenuSubMenu} from "./actions-menu-sub-menu";
7
- import {styled} from "@linaria/react";
8
- import {useRef, useState} from "react";
9
- import {stopPropagation} from "@fibery/react/src/stop-propagation";
10
- /**
11
- *
12
- * Probably commands menu deserves to be extracted to a separate primitive component not connected to ActionsMenu
13
- * but for now we don't have other use cases for it so no idea how a primitive should look like
14
- *
15
- * Feel free to extract it to a separate one
16
- *
17
- */
18
-
19
- const inputContainerCss = css`
20
- display: flex;
21
- padding: ${space.s8}px ${space.s12}px;
22
- align-items: center;
23
- border-bottom: 1px solid ${themeVars.separatorColor};
24
-
25
- & input {
26
- min-width: 120px;
27
- width: 100%;
28
- color: ${themeVars.textColor};
29
- background-color: ${themeVars.transparent};
30
- margin-left: ${space.s8}px;
31
- font-size: 13px;
32
- border: none;
33
- outline: none;
34
- resize: none;
35
- }
15
+ import {useActionsMenuContext} from "./contexts/actions-menu-context";
36
16
 
37
- & input::placeholder {
38
- color: ${themeVars.accentTextColor};
39
- }
40
- `;
17
+ const [ActionsMenuSubCommandMenuProvider, useActionsMenuSubCommandMenuCtx] = createContext<{
18
+ subMenuOpenRef: RefObject<boolean>;
19
+ subMenuTriggerRef: RefObject<HTMLDivElement>;
20
+ }>("ActionsMenuSubCommandMenu");
41
21
 
42
22
  type ActionsMenuSubCommandMenuProps = React.PropsWithChildren<{
43
23
  trigger?: React.ReactNode;
44
24
  disabled?: boolean;
45
- filter?: React.ComponentPropsWithoutRef<typeof CommandRoot>["filter"];
46
25
  }>;
47
- export const ActionsMenuSubCommandMenu: React.FC<ActionsMenuSubCommandMenuProps> = ({
48
- disabled,
49
- trigger,
50
- filter,
51
- children,
52
- }) => {
26
+ export const ActionsMenuSubCommandMenu: React.FC<ActionsMenuSubCommandMenuProps> = ({disabled, trigger, children}) => {
53
27
  const [open, onOpenChange] = useState(false);
54
28
  const triggerRef = useRef(null);
55
29
  const openRef = useRef(false);
56
30
 
31
+ const ctx = useMemo(
32
+ () => ({
33
+ subMenuOpenRef: openRef,
34
+ subMenuTriggerRef: triggerRef,
35
+ }),
36
+ []
37
+ );
38
+
57
39
  return (
58
40
  <ActionsMenuSubMenu
59
41
  disabled={disabled}
@@ -64,126 +46,107 @@ export const ActionsMenuSubCommandMenu: React.FC<ActionsMenuSubCommandMenuProps>
64
46
  }}
65
47
  trigger={trigger}
66
48
  triggerRef={triggerRef}
49
+ contentClassName={css`
50
+ &:is(&) {
51
+ overflow: hidden;
52
+ display: flex;
53
+ flex-direction: column;
54
+ max-height: 400px; // we use fixed height instead of --radix-dropdown-menu-content-available-height because it doesn't restore well after filtering if submenu was opened near the bottom of viewport. https://the.fibery.io/SoftDev/bug/It's-impossible-to-place-cursor-in-search-input-in-Existing-views-and-Convert-to-popup-10357/comment=14877
55
+ }
56
+ `}
67
57
  >
68
- <CommandRoot
69
- filter={filter}
70
- onClick={stopPropagation}
71
- onBlur={(e) => {
72
- /**
73
- * Submenu Trigger tries to steal the focus from input on every onPointerMove
74
- * to avoid this we lock focus on input and do not let it move to back to triger while menu is still open
75
- *
76
- * We use openRef here because react state will be updated only on next render
77
- */
78
- if (openRef.current && e.target.hasAttribute("cmdk-input") && e.relatedTarget === triggerRef.current) {
79
- e.target.focus();
80
- }
81
- }}
82
- >
83
- {children}
84
- </CommandRoot>
58
+ <ActionsMenuSubCommandMenuProvider value={ctx}>{children}</ActionsMenuSubCommandMenuProvider>
85
59
  </ActionsMenuSubMenu>
86
60
  );
87
61
  };
88
62
 
89
- type ActionsMenuSubCommandMenuInputProps = {
90
- placeholder?: string;
91
- autoFocus?: boolean;
92
- };
93
- export const ActionsMenuSubCommandMenuInput: React.FC<ActionsMenuSubCommandMenuInputProps> = ({
94
- placeholder,
95
- autoFocus = true,
63
+ export const ActionsMenuSubCommandMenuRoot: React.FC<React.ComponentPropsWithoutRef<typeof CommandMenuRoot>> = ({
64
+ className,
65
+ onClick,
66
+ onBlur,
67
+ ...props
96
68
  }) => {
69
+ const {subMenuOpenRef, subMenuTriggerRef} = useActionsMenuSubCommandMenuCtx();
70
+
97
71
  return (
98
- <div className={inputContainerCss}>
99
- <Search iconSize={16} aria-hidden />
100
- <CommandInput
101
- onKeyDown={(e) => {
102
- // prevent submenu from closing if input is not empty
103
- if ((e.target as HTMLInputElement).value.length > 0) {
104
- e.stopPropagation();
72
+ <CommandMenuRoot
73
+ className={cx(
74
+ css`
75
+ &:is(&) {
76
+ width: 250px;
105
77
  }
106
- }}
107
- placeholder={placeholder}
108
- autoFocus={autoFocus}
109
- />
110
- </div>
78
+ `,
79
+ className
80
+ )}
81
+ onClick={composeEventHandlers(onClick, stopPropagation)}
82
+ onBlur={composeEventHandlers(onBlur, (e) => {
83
+ /**
84
+ * Submenu Trigger tries to steal the focus from input on every onPointerMove
85
+ * to avoid this we lock focus on input and do not let it move to back to triger while menu is still open
86
+ *
87
+ * setTimeout is needed for firefox https://the.fibery.io/SoftDev/bug/Automatically-place-the-cursor-in-the-search-input-in-the-list-of-spaces-in-'Move-to'-option-10524
88
+ *
89
+ * We use subMenuOpenRef here because react state will be updated only on next render. Alternatively we can try to use flushSync
90
+ */
91
+ if (
92
+ subMenuOpenRef.current &&
93
+ e.target.hasAttribute("cmdk-input") &&
94
+ e.relatedTarget === subMenuTriggerRef.current
95
+ ) {
96
+ setTimeout(() => e.target.focus(), 0);
97
+ }
98
+ })}
99
+ {...props}
100
+ />
111
101
  );
112
102
  };
113
103
 
114
- export const ActionsMenuSubCommandMenuList = styled(CommandList)`
115
- overflow-y: scroll;
116
- width: 250px;
117
- height: var(--cmdk-list-height);
118
- max-height: 600px;
119
- transition: height 100ms ease;
120
- margin-top: ${space.s4}px;
121
- `;
122
-
123
- const commandItemCss = css`
124
- display: flex;
125
- align-items: center;
126
- gap: ${space.s6}px;
127
- padding: 0 ${space.s12}px;
128
- cursor: pointer;
129
- min-height: ${layout.menuItemHeight}px;
130
- margin: 0 ${space.s4}px;
104
+ type ActionsMenuSubCommandMenuInputProps = React.ComponentPropsWithoutRef<typeof CommandMenuInput>;
105
+ export const ActionsMenuSubCommandMenuInput: React.FC<ActionsMenuSubCommandMenuInputProps> = ({
106
+ autoFocus = true,
107
+ onKeyDown,
108
+ ...otherProps
109
+ }) => {
110
+ const inputRef = useRef<HTMLInputElement | null>(null);
131
111
 
132
- &[data-selected] {
133
- margin: 0 4px;
134
- background-color: ${themeVars.colorBgActionsMenuItemHover};
135
- border-radius: ${border.radius6}px;
136
- }
137
- `;
138
- const commandItemTitleCss = css`
139
- white-space: nowrap;
140
- text-overflow: ellipsis;
141
- overflow: hidden;
142
- `;
112
+ useEffect(() => {
113
+ // html autofocus doesn't work reliably in Context Menu
114
+ if (autoFocus) {
115
+ setTimeout(() => inputRef.current?.focus(), 0);
116
+ }
117
+ }, [autoFocus]);
143
118
 
144
- type ActionsMenuSubCommandMenuItemProps = React.ComponentPropsWithoutRef<typeof CommandItem> & {
145
- icon?: React.ReactNode;
119
+ return (
120
+ <CommandMenuInput
121
+ ref={inputRef}
122
+ onKeyDown={(e) => {
123
+ // prevent submenu from closing if input is not empty
124
+ if ((e.target as HTMLInputElement).value.length > 0 && e.key === "ArrowLeft") {
125
+ e.stopPropagation();
126
+ }
127
+ onKeyDown?.(e);
128
+ }}
129
+ autoFocus={autoFocus}
130
+ {...otherProps}
131
+ />
132
+ );
146
133
  };
147
134
 
148
- export const ActionsMenuSubCommandMenuItem: React.FC<ActionsMenuSubCommandMenuItemProps> = ({
135
+ export const ActionsMenuSubCommandMenuList = CommandMenuList;
136
+
137
+ export const ActionsMenuSubCommandMenuItem: React.FC<React.ComponentPropsWithoutRef<typeof CommandMenuItem>> = ({
149
138
  onSelect,
150
- icon,
151
- children,
152
- className,
153
139
  ...props
154
140
  }) => {
155
141
  const {close} = useActionsMenuContext();
156
- const [showTitle, setShowTitle] = useState(false);
157
-
158
142
  const onSelectItem = (value: string) => {
159
143
  onSelect?.(value);
160
144
  close();
161
145
  };
162
146
 
163
- return (
164
- <CommandItem className={cx(commandItemCss, className)} onSelect={onSelectItem} {...props}>
165
- {icon}
166
- <span
167
- title={showTitle ? (children as string) : ""}
168
- onMouseEnter={(e) => {
169
- const target = e.target as HTMLElement;
170
- if (typeof children === "string" && target.offsetWidth < target.scrollWidth) {
171
- setShowTitle(true);
172
- }
173
- }}
174
- className={commandItemTitleCss}
175
- >
176
- {children}
177
- </span>
178
- </CommandItem>
179
- );
147
+ return <CommandMenuItem onSelect={onSelectItem} {...props}></CommandMenuItem>;
180
148
  };
181
149
 
182
- export const ActionsMenuSubCommandMenuEmpty = styled(CommandEmpty)`
183
- ${textStyles.small}
184
- display: flex;
185
- align-items: center;
186
- padding: 0 ${space.s12}px;
187
- min-height: ${layout.itemHeight}px;
188
- color: ${themeVars.accentTextColor};
189
- `;
150
+ export const ActionsMenuSubCommandMenuEmpty = CommandMenuEmpty;
151
+
152
+ export const ActionsMenuSubCommandMenuGroup = CommandMenuGroup;
@@ -22,6 +22,7 @@ type Props = React.PropsWithChildren<{
22
22
  open?: boolean;
23
23
  onOpenChange?: (v: boolean) => void;
24
24
  disabled?: boolean;
25
+ contentClassName?: string;
25
26
  }>;
26
27
 
27
28
  export const ActionsMenuSubMenu: React.FC<Props> = ({
@@ -31,6 +32,7 @@ export const ActionsMenuSubMenu: React.FC<Props> = ({
31
32
  triggerRef,
32
33
  children,
33
34
  disabled = false,
35
+ contentClassName,
34
36
  }) => {
35
37
  const {MenuPrimitive} = useActionsMenuContext();
36
38
 
@@ -51,7 +53,7 @@ export const ActionsMenuSubMenu: React.FC<Props> = ({
51
53
  />
52
54
  </div>
53
55
  </MenuPrimitive.SubTrigger>
54
- <MenuPrimitive.SubContent>{children}</MenuPrimitive.SubContent>
56
+ <MenuPrimitive.SubContent className={contentClassName}>{children}</MenuPrimitive.SubContent>
55
57
  </MenuPrimitive.Sub>
56
58
  );
57
59
  };
@@ -5,6 +5,8 @@ import {ActionsMenuContextProvider} from "./contexts/actions-menu-context";
5
5
  import {ActionsMenuDangerousRowsProvider} from "./contexts/actions-menu-dangerous-rows";
6
6
  import {ActionsMenuProps} from "./actions-menu-props";
7
7
  import {preventDefault} from "@fibery/react/src/prevent-default";
8
+ import {useState} from "react";
9
+ import {ActionsMenuConfirmation, ActionsMenuConfirmationProps} from "./actions-menu-confirmation";
8
10
 
9
11
  export const preventDefaultAndStopPropagation = (event: React.MouseEvent) => {
10
12
  event.preventDefault();
@@ -35,9 +37,10 @@ export const ActionsMenu = ({
35
37
  sticky,
36
38
  }: ActionsMenuProps): JSX.Element => {
37
39
  const [isOpen = false, setOpen] = useControllableState({value: open, onChange: onOpenChange});
40
+ const [confirmation, setConfirmation] = useState<ActionsMenuConfirmationProps | null>(null);
38
41
 
39
42
  return (
40
- <ActionsMenuContextProvider setOpen={setOpen} MenuPrimitive={DropdownMenu}>
43
+ <ActionsMenuContextProvider setOpen={setOpen} showConfirmation={setConfirmation} MenuPrimitive={DropdownMenu}>
41
44
  <DropdownMenu.Root open={isOpen} onOpenChange={setOpen} modal={modal || false}>
42
45
  <DropdownMenu.Trigger
43
46
  // backward compatibility for dropdown styles
@@ -63,6 +66,8 @@ export const ActionsMenu = ({
63
66
  <ActionsMenuDangerousRowsProvider open={isOpen}>{children}</ActionsMenuDangerousRowsProvider>
64
67
  </DropdownMenu.Content>
65
68
  </DropdownMenu.Root>
69
+
70
+ {confirmation ? <ActionsMenuConfirmation {...confirmation} /> : null}
66
71
  </ActionsMenuContextProvider>
67
72
  );
68
73
  };
@@ -5,6 +5,8 @@ import * as ContextMenu from "../context-menu";
5
5
  import {ActionsMenuDangerousRowsProvider} from "./contexts/actions-menu-dangerous-rows";
6
6
  import {ActionsMenuProps} from "./actions-menu-props";
7
7
  import {preventDefault} from "@fibery/react/src/prevent-default";
8
+ import {ActionsMenuConfirmation, ActionsMenuConfirmationProps} from "./actions-menu-confirmation";
9
+ import {useState} from "react";
8
10
 
9
11
  export const ContextActionsMenu = ({
10
12
  open,
@@ -15,9 +17,10 @@ export const ContextActionsMenu = ({
15
17
  autoFocusOnClose = true,
16
18
  }: ActionsMenuProps): JSX.Element => {
17
19
  const [isOpen = false, setOpen] = useControllableState({value: open, onChange: onOpenChange});
20
+ const [confirmation, setConfirmation] = useState<ActionsMenuConfirmationProps | null>(null);
18
21
 
19
22
  return (
20
- <ActionsMenuContextProvider setOpen={setOpen} MenuPrimitive={ContextMenu}>
23
+ <ActionsMenuContextProvider setOpen={setOpen} showConfirmation={setConfirmation} MenuPrimitive={ContextMenu}>
21
24
  <ContextMenu.Root onOpenChange={onOpenChange}>
22
25
  <ContextMenu.Trigger disabled={disabled} asChild>
23
26
  {trigger}
@@ -28,6 +31,7 @@ export const ContextActionsMenu = ({
28
31
  </ContextMenu.Content>
29
32
  </ContextMenu.Portal>
30
33
  </ContextMenu.Root>
34
+ {confirmation ? <ActionsMenuConfirmation {...confirmation} /> : null}
31
35
  </ActionsMenuContextProvider>
32
36
  );
33
37
  };
@@ -1,5 +1,6 @@
1
1
  import {createContext} from "@fibery/react/src/create-context";
2
2
  import {useMemo} from "react";
3
+ import {ActionsMenuConfirmationProps} from "../actions-menu-confirmation";
3
4
 
4
5
  type MenuPrimitive = {
5
6
  Item: React.ElementType;
@@ -13,6 +14,7 @@ type MenuPrimitive = {
13
14
 
14
15
  type ActionsMenuContext = {
15
16
  close: () => void;
17
+ showConfirmation: (args: ActionsMenuConfirmationProps | null) => void;
16
18
  MenuPrimitive: MenuPrimitive;
17
19
  };
18
20
 
@@ -20,16 +22,18 @@ const [Provider, useContext] = createContext<ActionsMenuContext>("ActionsMenuCon
20
22
 
21
23
  type Props = React.PropsWithChildren<{
22
24
  setOpen: (value: boolean) => void;
25
+ showConfirmation: (args: ActionsMenuConfirmationProps | null) => void;
23
26
  MenuPrimitive: MenuPrimitive;
24
27
  }>;
25
28
 
26
- export const ActionsMenuContextProvider: React.FC<Props> = ({setOpen, MenuPrimitive, children}) => {
29
+ export const ActionsMenuContextProvider: React.FC<Props> = ({setOpen, showConfirmation, MenuPrimitive, children}) => {
27
30
  const context = useMemo<ActionsMenuContext>(
28
31
  () => ({
29
32
  close: () => setOpen(false),
30
33
  MenuPrimitive,
34
+ showConfirmation,
31
35
  }),
32
- [setOpen, MenuPrimitive]
36
+ [MenuPrimitive, showConfirmation, setOpen]
33
37
  );
34
38
 
35
39
  return <Provider value={context}>{children}</Provider>;
@@ -105,7 +105,7 @@ type StyledProps = {
105
105
  borderWidth: number;
106
106
  };
107
107
 
108
- const StyledButtonBase = styled.button<StyledProps>`
108
+ export const StyledButtonBase = styled.button<StyledProps>`
109
109
  display: block;
110
110
  box-sizing: border-box;
111
111
  font-weight: ${fontWeight.medium};
@@ -31,7 +31,7 @@ const FontSizes = {
31
31
  } as const;
32
32
 
33
33
  const HorizontalPaddings = {
34
- ":button-size/super-small": 4,
34
+ ":button-size/super-small": 6,
35
35
  ":button-size/smaller": 8,
36
36
  ":button-size/small": 8,
37
37
  ":button-size/normal": 12,