@fibery/ui-kit 1.37.0 → 1.38.1

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 (194) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/config/jest/testFrameworkSetup.js +1 -1
  3. package/package.json +20 -16
  4. package/src/abbreviate-name.ts +42 -0
  5. package/src/actions-menu/actions-menu-item.tsx +32 -11
  6. package/src/actions-menu/actions-menu-props.tsx +5 -0
  7. package/src/actions-menu/actions-menu-sub-command-menu.tsx +7 -4
  8. package/src/actions-menu/actions-menu-sub-menu.tsx +9 -3
  9. package/src/actions-menu/actions-menu.tsx +28 -9
  10. package/src/actions-menu/context-actions-menu.tsx +22 -0
  11. package/src/actions-panel.tsx +12 -2
  12. package/src/animated-height-container.tsx +24 -5
  13. package/src/antd/ant-upload.tsx +1 -1
  14. package/src/antd/input.tsx +4 -0
  15. package/src/avatar.tsx +1 -27
  16. package/src/axis-header.tsx +136 -76
  17. package/src/box.tsx +1 -1
  18. package/src/breadcrumb.tsx +78 -0
  19. package/src/button/actions-button-compact.tsx +4 -1
  20. package/src/button/base-button.tsx +7 -3
  21. package/src/button/button-group.tsx +1 -1
  22. package/src/button/button.tsx +33 -1
  23. package/src/button/icon-button.tsx +10 -1
  24. package/src/button/select-button.tsx +4 -0
  25. package/src/card-container.tsx +10 -6
  26. package/src/checkbox.tsx +17 -0
  27. package/src/collapsible-section.tsx +3 -1
  28. package/src/color-picker/swatch.tsx +1 -0
  29. package/src/command-menu/index.tsx +3 -3
  30. package/src/context-menu/index.tsx +10 -1
  31. package/src/date-picker/autocomplete.tsx +11 -5
  32. package/src/date-picker/date-range-input.tsx +5 -1
  33. package/src/date-picker/date-range-picker-popup-content.tsx +31 -13
  34. package/src/date-picker/date-range-picker.tsx +6 -3
  35. package/src/date-picker/relative-date-picker.tsx +6 -2
  36. package/src/date-picker/single-date-input.tsx +5 -1
  37. package/src/date-picker/single-date-picker.tsx +8 -5
  38. package/src/date-picker/styles.ts +52 -26
  39. package/src/date-picker/types.ts +3 -1
  40. package/src/day-select/day-select.tsx +21 -75
  41. package/src/day-select/iso-week-day-select.tsx +1 -1
  42. package/src/day-select/mount-day-select.tsx +2 -2
  43. package/src/day-select/week-day-select.tsx +1 -5
  44. package/src/design-system.ts +45 -12
  45. package/src/dropdown-menu/index.tsx +19 -2
  46. package/src/emoji-picker/app-icon-picker.tsx +6 -4
  47. package/src/emoji-picker/emoji-picker-preview-footer.tsx +5 -1
  48. package/src/emoji-picker/emoji-picker.tsx +3 -0
  49. package/src/emoji-picker/emoji.tsx +5 -3
  50. package/src/emoji-picker/icon-emoji-picker.tsx +10 -1
  51. package/src/emoji-picker/primitives/emoji.tsx +49 -51
  52. package/src/emoji-picker/primitives/footer.tsx +5 -0
  53. package/src/emoji-picker/primitives/search.tsx +8 -0
  54. package/src/emoji-picker/primitives/skin-tone.tsx +12 -1
  55. package/src/emoji-picker/use-responsive-emoji-size.ts +11 -0
  56. package/src/emoji-picker/utils/emoji-set.ts +2 -1
  57. package/src/empty-state/empty-state.tsx +6 -0
  58. package/src/fibermoji-placeholder.tsx +1 -27
  59. package/src/field-icon.tsx +4 -1
  60. package/src/file-item-2.tsx +408 -0
  61. package/src/file-item.tsx +215 -47
  62. package/src/header-layout.tsx +11 -0
  63. package/src/html-styles.ts +21 -4
  64. package/src/icons/ast/ActivityFilled.ts +8 -0
  65. package/src/icons/ast/AiAssistantFilled.ts +8 -0
  66. package/src/icons/ast/Back.ts +1 -1
  67. package/src/icons/ast/CollapseAllHorizontal.ts +8 -0
  68. package/src/icons/ast/DateRange.ts +1 -1
  69. package/src/icons/ast/EntityCreateFilled.ts +8 -0
  70. package/src/icons/ast/ExpandAllHorizontal.ts +8 -0
  71. package/src/icons/ast/ExtensionFiles.ts +1 -1
  72. package/src/icons/ast/FileUpload.ts +1 -1
  73. package/src/icons/ast/GlobeUnpublish.ts +8 -0
  74. package/src/icons/ast/HomeFilled.ts +8 -0
  75. package/src/icons/ast/KeyboardHideDown.ts +8 -0
  76. package/src/icons/ast/LayoutMultiple.ts +8 -0
  77. package/src/icons/ast/RicheditorHistoryRedo.ts +1 -1
  78. package/src/icons/ast/RicheditorHistoryUndo.ts +1 -1
  79. package/src/icons/ast/SearchFilled.ts +8 -0
  80. package/src/icons/ast/SettingsFilled.ts +8 -0
  81. package/src/icons/ast/SlideMenuFilled.ts +8 -0
  82. package/src/icons/ast/SwitchToMention.ts +8 -0
  83. package/src/icons/ast/SwitchToText.ts +8 -0
  84. package/src/icons/ast/SwitchToWidget.ts +8 -0
  85. package/src/icons/ast/TypeDate.ts +1 -1
  86. package/src/icons/ast/ViewGallery.ts +8 -0
  87. package/src/icons/ast/index.tsx +16 -0
  88. package/src/icons/react/ActivityFilled.tsx +13 -0
  89. package/src/icons/react/AiAssistantFilled.tsx +13 -0
  90. package/src/icons/react/CollapseAllHorizontal.tsx +13 -0
  91. package/src/icons/react/EntityCreateFilled.tsx +13 -0
  92. package/src/icons/react/ExpandAllHorizontal.tsx +13 -0
  93. package/src/icons/react/GlobeUnpublish.tsx +13 -0
  94. package/src/icons/react/HomeFilled.tsx +13 -0
  95. package/src/icons/react/KeyboardHideDown.tsx +13 -0
  96. package/src/icons/react/LayoutMultiple.tsx +13 -0
  97. package/src/icons/react/SearchFilled.tsx +13 -0
  98. package/src/icons/react/SettingsFilled.tsx +13 -0
  99. package/src/icons/react/SlideMenuFilled.tsx +13 -0
  100. package/src/icons/react/SwitchToMention.tsx +13 -0
  101. package/src/icons/react/SwitchToText.tsx +13 -0
  102. package/src/icons/react/SwitchToWidget.tsx +13 -0
  103. package/src/icons/react/ViewGallery.tsx +13 -0
  104. package/src/icons/react/index.tsx +16 -0
  105. package/src/icons/svg/activity-filled.svg +4 -0
  106. package/src/icons/svg/ai-assistant-filled.svg +3 -0
  107. package/src/icons/svg/back.svg +3 -1
  108. package/src/icons/svg/collapse-all-horizontal.svg +3 -0
  109. package/src/icons/svg/date-range.svg +3 -3
  110. package/src/icons/svg/entity-create-filled.svg +4 -0
  111. package/src/icons/svg/expand-all-horizontal.svg +3 -0
  112. package/src/icons/svg/extension/files.svg +3 -1
  113. package/src/icons/svg/file-upload.svg +3 -6
  114. package/src/icons/svg/globe-unpublish.svg +4 -0
  115. package/src/icons/svg/home-filled.svg +3 -0
  116. package/src/icons/svg/keyboard-hide-down.svg +1 -0
  117. package/src/icons/svg/layout-multiple.svg +3 -0
  118. package/src/icons/svg/richeditor/history/redo.svg +3 -2
  119. package/src/icons/svg/richeditor/history/undo.svg +3 -2
  120. package/src/icons/svg/search-filled.svg +3 -0
  121. package/src/icons/svg/settings-filled.svg +3 -0
  122. package/src/icons/svg/slide-menu-filled.svg +1 -0
  123. package/src/icons/svg/switch-to-mention.svg +3 -0
  124. package/src/icons/svg/switch-to-text.svg +4 -0
  125. package/src/icons/svg/switch-to-widget.svg +4 -0
  126. package/src/icons/svg/type/date.svg +3 -2
  127. package/src/icons/svg/view-gallery.svg +4 -0
  128. package/src/images-gallery/images-gallery-fall-through-provider.tsx +11 -0
  129. package/src/images-gallery/images-gallery.tsx +257 -0
  130. package/src/images-gallery/zoom.tsx +123 -0
  131. package/src/images-gallery-2/images-gallery-2.tsx +442 -0
  132. package/src/images-gallery-2/slide-buttons.tsx +230 -0
  133. package/src/images-gallery-2/zoom.tsx +35 -0
  134. package/src/is-in-popup.ts +1 -1
  135. package/src/kbd.tsx +46 -0
  136. package/src/layout-styles.ts +21 -1
  137. package/src/lists/actions-menu-row-surface.tsx +3 -1
  138. package/src/lists/list-row-surface.tsx +7 -1
  139. package/src/mobile-keyboard-aware-popup.tsx +87 -0
  140. package/src/mobile-styles.ts +8 -0
  141. package/src/modal-menu/contexts/modal-menu-context.tsx +22 -0
  142. package/src/modal-menu/contexts/modal-submenu-context.tsx +16 -0
  143. package/src/modal-menu/index.tsx +14 -0
  144. package/src/modal-menu/modal-menu-content.tsx +68 -0
  145. package/src/modal-menu/modal-menu-group.tsx +10 -0
  146. package/src/modal-menu/modal-menu-item.tsx +45 -0
  147. package/src/modal-menu/modal-menu-label.tsx +24 -0
  148. package/src/modal-menu/modal-menu-root.tsx +57 -0
  149. package/src/modal-menu/modal-menu-separator.tsx +14 -0
  150. package/src/modal-menu/modal-menu-trigger.tsx +54 -0
  151. package/src/modal-menu/modal-submenu-content.tsx +49 -0
  152. package/src/modal-menu/modal-submenu-trigger.tsx +34 -0
  153. package/src/modal-menu/modal-submenu.tsx +17 -0
  154. package/src/notification-dot.tsx +16 -7
  155. package/src/online-users.tsx +3 -3
  156. package/src/palette.ts +1 -1
  157. package/src/platform-symbols.ts +9 -0
  158. package/src/platform.ts +2 -0
  159. package/src/popover/index.tsx +710 -0
  160. package/src/popover/mobile-popup-context.tsx +29 -0
  161. package/src/{popup → popover}/modifiers.tsx +25 -25
  162. package/src/{popup → popover}/popup-modifiers-context.ts +3 -3
  163. package/src/reactions/reaction-button.tsx +342 -135
  164. package/src/reactions/reaction-picker.tsx +51 -44
  165. package/src/reactions/reactions.tsx +11 -1
  166. package/src/reactions/tootltip.tsx +55 -0
  167. package/src/rich-text-embed-error.tsx +2 -1
  168. package/src/select/components/group-heading.tsx +8 -0
  169. package/src/select/components/menu-list-virtualized.tsx +6 -2
  170. package/src/select/components/option.tsx +4 -0
  171. package/src/select/index.tsx +8 -4
  172. package/src/select/select-control-settings-context.tsx +11 -2
  173. package/src/select/select-in-popover.tsx +30 -39
  174. package/src/select/styles.ts +21 -1
  175. package/src/tab-nav/tab-nav.tsx +36 -10
  176. package/src/toast/primitives.tsx +8 -1
  177. package/src/toggle-button/round-toggle-button.tsx +23 -0
  178. package/src/toggle-button/toggle-button-group.tsx +34 -0
  179. package/src/toggle-button/toggle-button.tsx +164 -0
  180. package/src/toggle.tsx +11 -3
  181. package/src/tooltip.tsx +29 -20
  182. package/src/type-badge.tsx +5 -2
  183. package/src/unit/styles.ts +2 -2
  184. package/src/unit/unit-with-tooltip.tsx +1 -1
  185. package/src/use-is-phone.tsx +50 -4
  186. package/src/use-is-support-hover.ts +1 -1
  187. package/src/use-on-screen-keyboard-data.tsx +66 -0
  188. package/src/workflow-progress-icon.tsx +16 -22
  189. package/src/popup/index.tsx +0 -383
  190. package/src/shortcut-badge.tsx +0 -29
  191. /package/src/{popup → popover}/popup-stack-context.tsx +0 -0
  192. /package/src/{popup → popover}/reference.ts +0 -0
  193. /package/src/{popup → popover}/styles.ts +0 -0
  194. /package/src/{popup → popover}/use-click-outside.ts +0 -0
@@ -1,16 +1,17 @@
1
1
  import {EmojiItem} from "@fibery/emoji-data";
2
- import {measureScrollbar} from "@fibery/helpers/utils/measure-scrollbar";
3
2
  import {useControllableState} from "@fibery/react/src/use-controllable-state";
4
3
  import {css} from "@linaria/core";
5
4
  import {CSSProperties, type FC, useCallback, useState} from "react";
6
5
  import {IconButton} from "../button/icon-button";
7
6
  import {layout, space, themeVars} from "../design-system";
8
7
  import {type EmojiPickerProps} from "../emoji-picker/emoji-picker";
8
+ import {useResponsiveEmojiSize} from "../emoji-picker/use-responsive-emoji-size";
9
9
  import AddReactions from "../icons/react/AddReactions";
10
- import {Popup} from "../popup";
10
+ import {Popover} from "../popover";
11
+ import {ToggleButton} from "../toggle-button/toggle-button";
11
12
  import {Tooltip} from "../tooltip";
13
+ import {mobileRootSelector} from "../mobile-styles";
12
14
  import {useIsPhone} from "../use-is-phone";
13
- import {reactionButtonCss} from "./reaction-button";
14
15
 
15
16
  type Props = {
16
17
  mode: "default" | "in-row";
@@ -28,6 +29,14 @@ const popupContainerCss = css`
28
29
  z-index: ${zIndex};
29
30
  `;
30
31
 
32
+ const buttonCss = css`
33
+ ${mobileRootSelector} & {
34
+ min-width: ${space.s28}px;
35
+ height: ${space.s28}px;
36
+ padding-inline: ${space.s8}px;
37
+ }
38
+ `;
39
+
31
40
  const popupCss = css`
32
41
  //background-color: transparent;
33
42
  //box-shadow: none;
@@ -52,7 +61,7 @@ const pickerOffset: [number, number] = [0, space.s4];
52
61
  export const ReactionPicker = ({mode, onSelect, open, onOpenChange, EmojiPicker}: Props): JSX.Element => {
53
62
  const [isOpen = false, setOpen] = useControllableState({value: open, onChange: onOpenChange});
54
63
  const [triggerDomElement, setTriggerDomElement] = useState<HTMLButtonElement | null>(null);
55
- const isPhone = useIsPhone();
64
+ const emojiSize = useResponsiveEmojiSize();
56
65
  const onEmojiSelect = useCallback(
57
66
  (emojiData: EmojiItem) => {
58
67
  onSelect(emojiData.colons);
@@ -61,66 +70,64 @@ export const ReactionPicker = ({mode, onSelect, open, onOpenChange, EmojiPicker}
61
70
  [onSelect, setOpen]
62
71
  );
63
72
 
73
+ const isPhone = useIsPhone();
74
+
64
75
  return (
65
76
  <div>
66
77
  <Tooltip side="bottom" title="Add reaction">
67
78
  {mode === "in-row" ? (
68
- <button
79
+ <ToggleButton
80
+ className={buttonCss}
69
81
  ref={setTriggerDomElement}
70
- type="button"
71
- onClick={() => {
72
- setOpen(!isOpen);
82
+ onClick={() => setOpen(!isOpen)}
83
+ aria-expanded={isOpen}
84
+ aria-pressed={undefined}
85
+ style={{
86
+ // TODO: add IconToggleButton? or a separate prop?
87
+ width: "24px",
88
+ justifyContent: "center",
89
+ paddingInline: 0,
73
90
  }}
74
- className={reactionButtonCss}
75
91
  >
76
- <AddReactions viewBox={"0 0 20 20"} containerSize={16} iconSize={20} color={themeVars.iconColor} />
77
- </button>
92
+ <AddReactions iconSize={isPhone ? 20 : 16} />
93
+ </ToggleButton>
78
94
  ) : (
79
95
  <IconButton
80
96
  ref={setTriggerDomElement}
97
+ aria-expanded={isOpen}
81
98
  onClick={() => {
82
99
  setOpen(!isOpen);
83
100
  }}
84
101
  size="small"
102
+ supportMobile
85
103
  >
86
104
  <AddReactions />
87
105
  </IconButton>
88
106
  )}
89
107
  </Tooltip>
90
- {triggerDomElement ? (
91
- <Popup
92
- supportMobile
93
- mobilePopupStyle={
94
- {
95
- "--fibery-emoji-container-width": "100%",
96
- "--fibery-emoji-grid-height": "auto",
97
- "--fibery-emoji-content-max-height": "auto",
98
- zIndex: zIndex,
99
- } as CSSProperties
100
- }
101
- title={"Add reaction"}
102
- placement="auto"
103
- offset={pickerOffset}
104
- popupContainerClassName={popupContainerCss}
105
- popupClassName={popupCss}
106
- open={isOpen}
107
- triggerDomElement={triggerDomElement}
108
- trigger={<></>}
109
- renderInPortal
110
- onOpen={() => setOpen(true)}
111
- onClose={() => setOpen(false)}
112
- >
113
- <EmojiPicker
114
- emojiSize={
115
- isPhone
116
- ? Math.min(Math.floor((document.body.clientWidth - 24 - measureScrollbar() - 9 * 12) / 9), 40)
117
- : 20
108
+ <Popover.Root open={isOpen} onOpen={() => setOpen(true)} onClose={() => setOpen(false)}>
109
+ <Popover.Trigger reference={triggerDomElement}></Popover.Trigger>
110
+ <Popover.Portal>
111
+ <Popover.Content
112
+ supportMobile
113
+ mobilePopupStyle={
114
+ {
115
+ "--fibery-emoji-container-width": "100%",
116
+ "--fibery-emoji-grid-height": "auto",
117
+ "--fibery-emoji-content-max-height": "auto",
118
+ zIndex: zIndex,
119
+ } as CSSProperties
118
120
  }
119
- showSkinTones
120
- onSelect={onEmojiSelect}
121
- />
122
- </Popup>
123
- ) : null}
121
+ title={"Add reaction"}
122
+ placement="auto"
123
+ offset={pickerOffset}
124
+ popupContainerClassName={popupContainerCss}
125
+ popupClassName={popupCss}
126
+ >
127
+ <EmojiPicker emojiSize={emojiSize} showSkinTones onSelect={onEmojiSelect} />
128
+ </Popover.Content>
129
+ </Popover.Portal>
130
+ </Popover.Root>
124
131
  </div>
125
132
  );
126
133
  };
@@ -4,6 +4,7 @@ import {ReactionPicker} from "./reaction-picker";
4
4
  import {EmojiPickerProps} from "../emoji-picker/emoji-picker";
5
5
  import {space} from "../design-system";
6
6
  import {type FC} from "react";
7
+ import {mobileRootSelector} from "../mobile-styles";
7
8
 
8
9
  type Props = {
9
10
  reactions: Array<Reaction>;
@@ -16,13 +17,22 @@ const blockReactionsCss = css`
16
17
  display: flex;
17
18
  flex-wrap: wrap;
18
19
  gap: ${space.s4}px;
20
+ ${mobileRootSelector} & {
21
+ gap: ${space.s6}px;
22
+ }
19
23
  `;
20
24
 
21
25
  export const Reactions: React.FC<Props> = ({reactions, onSelect, readonly, EmojiPicker}) => {
22
26
  return (
23
27
  <div className={blockReactionsCss}>
24
28
  {reactions.map((reaction) => (
25
- <ReactionButton disabled={readonly} key={reaction.key} reaction={reaction} onSelect={onSelect} />
29
+ <ReactionButton
30
+ reactions={reactions}
31
+ disabled={readonly}
32
+ key={reaction.key}
33
+ reaction={reaction}
34
+ onSelect={onSelect}
35
+ />
26
36
  ))}
27
37
  {!readonly ? <ReactionPicker EmojiPicker={EmojiPicker} mode={"in-row"} onSelect={onSelect} /> : null}
28
38
  </div>
@@ -0,0 +1,55 @@
1
+ import {css, cx} from "@linaria/core";
2
+ import {border, space, themeVars} from "../design-system";
3
+ import {Emoji} from "../emoji-picker/emoji";
4
+ import {useIsPhone} from "../use-is-phone";
5
+ import {ReactNode} from "react";
6
+
7
+ export const EmojiTooltipTitle = ({emoji}: {emoji: string}) => {
8
+ return (
9
+ <div
10
+ className={css`
11
+ padding-top: ${space.s6}px;
12
+ padding-left: ${space.s6}px;
13
+ padding-right: ${space.s6}px;
14
+ display: flex;
15
+ justify-content: center;
16
+ `}
17
+ >
18
+ <div
19
+ className={css`
20
+ display: flex;
21
+ background-color: ${themeVars.whiteColor};
22
+ padding: ${space.s4}px;
23
+ border-radius: ${border.radius4}px;
24
+ `}
25
+ >
26
+ <Emoji emoji={emoji} size={64} />
27
+ </div>
28
+ </div>
29
+ );
30
+ };
31
+
32
+ export const EmojiTooltipDescription = ({children}: {children: ReactNode}) => {
33
+ const isPhone = useIsPhone();
34
+ return (
35
+ <div
36
+ className={cx(
37
+ css`
38
+ padding-top: ${space.s8}px;
39
+ padding-bottom: ${space.s6}px;
40
+ padding-left: ${space.s6}px;
41
+ padding-right: ${space.s6}px;
42
+ text-align: center;
43
+ word-wrap: break-word;
44
+ color: ${themeVars.whiteColor};
45
+ `,
46
+ !isPhone &&
47
+ css`
48
+ max-width: 200px;
49
+ `
50
+ )}
51
+ >
52
+ {children}
53
+ </div>
54
+ );
55
+ };
@@ -4,7 +4,8 @@ import ImageXmark from "./icons/react/ImageXmark";
4
4
  import {type ReactNode} from "react";
5
5
 
6
6
  export const richTextEmbedErrorStyle = css`
7
- height: 380px;
7
+ min-height: 380px;
8
+ height: 100%;
8
9
  display: flex;
9
10
  flex-direction: column;
10
11
  align-items: center;
@@ -4,6 +4,7 @@ import {layout, space, textStyles, themeVars} from "../../design-system";
4
4
  import {TooltipIfOverflown} from "../../tooltip-if-overflown";
5
5
  import {GroupBase} from "../index";
6
6
  import {isPureTextChildren} from "../util";
7
+ import {mobileRootSelector} from "../../mobile-styles";
7
8
 
8
9
  export const groupHeadingNulledStyles = {
9
10
  paddingLeft: "",
@@ -15,6 +16,9 @@ export const groupHeadingNulledStyles = {
15
16
  ...textStyles.small,
16
17
  color: "",
17
18
  height: layout.menuItemHeight,
19
+ [`${mobileRootSelector} &`]: {
20
+ height: layout.mobileMenuItemHeight,
21
+ },
18
22
  };
19
23
  const groupHeadingClass = css`
20
24
  min-height: ${layout.menuItemHeight}px;
@@ -26,6 +30,10 @@ const groupHeadingClass = css`
26
30
  white-space: nowrap;
27
31
  overflow: hidden;
28
32
  text-overflow: ellipsis;
33
+ ${mobileRootSelector} & {
34
+ min-height: ${layout.mobileMenuItemHeight}px;
35
+ font-size: ${textStyles.regular.fontSize}px;
36
+ }
29
37
  `;
30
38
  const groupHeadingContentClass = css`
31
39
  white-space: nowrap;
@@ -5,6 +5,8 @@ import {GroupHeadingProps, GroupProps, MenuListProps} from "react-select";
5
5
  import {ItemContent, Virtuoso, VirtuosoHandle} from "react-virtuoso";
6
6
  import {layout} from "../../../src/design-system";
7
7
  import {GroupBase, ReactSelectRefContext} from "../util";
8
+ import {useSelectControlSettings} from "../select-control-settings-context";
9
+ import {useIsPhone} from "../../use-is-phone";
8
10
 
9
11
  const PADDING_BLOCK_HEIGHT = 6;
10
12
 
@@ -72,6 +74,8 @@ export function MenuListVirtualized<
72
74
  Group extends GroupBase<Option> = GroupBase<Option>
73
75
  >(props: MenuListProps<Option, IsMulti, Group>) {
74
76
  const {children, focusedOption, innerRef, maxHeight, theme, getStyles, cx, selectProps} = props;
77
+ const isPhone = useIsPhone();
78
+ const {inPopover} = useSelectControlSettings();
75
79
  const virtuoso = useRef<VirtuosoHandle>(null);
76
80
 
77
81
  // options props come non-filtered, and we have insufficient info (props) to render groups and options from here.
@@ -195,8 +199,8 @@ export function MenuListVirtualized<
195
199
  ref={virtuoso}
196
200
  // in reality only HTMLDiveElement | null will appear here. We do not use Virtuoso's useWindowScroll prop
197
201
  scrollerRef={innerRef as (ref: HTMLElement | Window | null) => void}
198
- style={{height: menuHeight}}
199
- fixedItemHeight={layout.menuItemHeight}
202
+ style={isPhone && inPopover ? undefined : {height: menuHeight}}
203
+ fixedItemHeight={isPhone ? layout.mobileMenuItemHeight : layout.menuItemHeight}
200
204
  data={flattenChildren}
201
205
  totalCount={flattenChildren.length}
202
206
  itemContent={drawListElement}
@@ -7,9 +7,13 @@ import {ListRowContent, ListRowSurface} from "../../lists/list-row-surface";
7
7
  import {TooltipIfOverflown} from "../../tooltip-if-overflown";
8
8
  import {GroupBase} from "../index";
9
9
  import {isPureTextChildren} from "../util";
10
+ import {mobileRootSelector} from "../../mobile-styles";
10
11
 
11
12
  export const OptionNulledVitualizedStyles = {
12
13
  height: layout.menuItemHeight,
14
+ [`${mobileRootSelector} &`]: {
15
+ height: layout.mobileMenuItemHeight,
16
+ },
13
17
  };
14
18
  export const OptionNulledStyles = {
15
19
  minHeight: layout.menuItemHeight,
@@ -7,6 +7,7 @@ import BaseSelect, {
7
7
  createFilter,
8
8
  MenuListProps,
9
9
  MenuProps,
10
+ ControlProps,
10
11
  mergeStyles,
11
12
  MultiValue,
12
13
  MultiValueProps,
@@ -44,6 +45,7 @@ export type {
44
45
  GroupBase,
45
46
  MenuListProps,
46
47
  MenuProps,
48
+ ControlProps,
47
49
  MultiValue,
48
50
  MultiValueProps,
49
51
  OnChangeValue,
@@ -53,6 +55,8 @@ export type {
53
55
  SingleValue,
54
56
  SingleValueProps,
55
57
  StylesConfig,
58
+ SelectInstance,
59
+ BaseSelectProps,
56
60
  };
57
61
 
58
62
  export {reactSelectComponents as components, MenuListVirtualized, createFilter};
@@ -207,8 +211,8 @@ export const Select = forwardRef(function Select<
207
211
  [onKeyDown, menuOpenState]
208
212
  );
209
213
 
210
- const contextRef = useRef<SelectInstance<T, U, V> | null>(null);
211
- const combined = useComposedRefs(forwardedRef, contextRef);
214
+ const selectRef = useRef<SelectInstance<T, U, V> | null>(null);
215
+ const composedRef = useComposedRefs(forwardedRef, selectRef);
212
216
 
213
217
  const selectComponents = useSelectComponents({
214
218
  components,
@@ -221,9 +225,9 @@ export const Select = forwardRef(function Select<
221
225
  const combinedStyles = useSelectStyles({virtualized, zIndex, styles});
222
226
 
223
227
  return (
224
- <ReactSelectRefContext.Provider value={contextRef as RefObject<SelectInstance>}>
228
+ <ReactSelectRefContext.Provider value={selectRef as RefObject<SelectInstance>}>
225
229
  <BaseSelect<T, U, V>
226
- ref={combined}
230
+ ref={composedRef}
227
231
  // There are places, where it is useful to override menuPortalTarget globally for all selects.
228
232
  // When you are already in some popup. e.g. user input in buttons, relation filter popover.
229
233
  menuPortalTarget={getPopupContainerElement ? getPopupContainerElement() : menuPortalTarget}
@@ -1,6 +1,10 @@
1
1
  import {createContext, ReactNode, useContext, useMemo} from "react";
2
2
 
3
- const SelectControlSettings = createContext<{getPopupContainerElement?: () => HTMLElement | null; zIndex?: number}>({});
3
+ const SelectControlSettings = createContext<{
4
+ getPopupContainerElement?: () => HTMLElement | null;
5
+ zIndex?: number;
6
+ inPopover?: boolean;
7
+ }>({});
4
8
 
5
9
  // Overrides zIndex and getPopupContainerElement for all selects, except select-in-popover.
6
10
  // It has more priority than "menuPortalTarget" prop. Use at your own risk!
@@ -8,12 +12,17 @@ export function SelectControlSettingsProvider({
8
12
  children,
9
13
  getPopupContainerElement,
10
14
  zIndex,
15
+ inPopover = false,
11
16
  }: {
12
17
  children: ReactNode;
13
18
  getPopupContainerElement?: () => HTMLElement | null;
14
19
  zIndex?: number;
20
+ inPopover?: boolean;
15
21
  }) {
16
- const settings = useMemo(() => ({getPopupContainerElement, zIndex}), [getPopupContainerElement, zIndex]);
22
+ const settings = useMemo(
23
+ () => ({getPopupContainerElement, zIndex, inPopover}),
24
+ [getPopupContainerElement, zIndex, inPopover]
25
+ );
17
26
  return <SelectControlSettings.Provider value={settings}>{children}</SelectControlSettings.Provider>;
18
27
  }
19
28
 
@@ -5,6 +5,7 @@ import React, {
5
5
  ForwardedRef,
6
6
  forwardRef,
7
7
  ReactNode,
8
+ RefObject,
8
9
  useCallback,
9
10
  useEffect,
10
11
  useImperativeHandle,
@@ -14,7 +15,7 @@ import React, {
14
15
  } from "react";
15
16
  import {inputOverrides} from "../antd/styles";
16
17
  import {border, space, textStyles} from "../design-system";
17
- import {Popup} from "../popup";
18
+ import {Popover, Placement} from "../popover";
18
19
  import {useIsPhone} from "../use-is-phone";
19
20
  import {MenuTransparent} from "./components/menu";
20
21
  import {
@@ -33,6 +34,7 @@ import {ButtonColor, ButtonVariant} from "../button/base-button";
33
34
  import {makeSelectInPopoverStyles} from "./styles";
34
35
  import {SelectInstance} from "react-select";
35
36
  import {SELECT_IN_POPOVER_VALUE_MAX_HEIGHT} from "./constants";
37
+ import {Wrap} from "@fibery/react/src/wrap";
36
38
 
37
39
  const offset = [0, space.s4] as [number, number];
38
40
  const popupHeightVH = 45;
@@ -58,12 +60,15 @@ export const popupClassName = css`
58
60
  max-width: 440px;
59
61
  `;
60
62
  const mobileClassName = css`
63
+ display: grid;
64
+ min-height: 0;
61
65
  padding-top: ${space.s12}px;
62
66
  padding-left: ${space.s12}px;
63
67
  padding-right: ${space.s12}px;
64
68
  `;
65
69
 
66
- const valueClassName = css`
70
+ const triggerCss = css`
71
+ min-width: 0;
67
72
  border-radius: ${border.radius6}px;
68
73
 
69
74
  &:focus {
@@ -109,7 +114,7 @@ export type TriggerProps = {
109
114
 
110
115
  const TriggerDefault = ({innerRef, children, onClick, onKeyDown}: TriggerProps) => {
111
116
  return (
112
- <div ref={innerRef} onClick={onClick} onKeyDown={onKeyDown} tabIndex={0} className={valueClassName}>
117
+ <div ref={innerRef} onClick={onClick} onKeyDown={onKeyDown} tabIndex={0} className={triggerCss}>
113
118
  {children}
114
119
  </div>
115
120
  );
@@ -119,9 +124,9 @@ export type SelectComponents<T, U extends boolean, V extends GroupBase<T>> = Sel
119
124
  Trigger?: ComponentType<TriggerProps>;
120
125
  };
121
126
 
122
- type SelectInPopoverRef<T, U extends boolean, V extends GroupBase<T>> = {
127
+ export type SelectInPopoverRef<T, U extends boolean, V extends GroupBase<T>> = {
123
128
  valueRef: HTMLDivElement | null;
124
- selectRef: SelectInstance<T, U, V> | null;
129
+ selectRef: RefObject<SelectInstance<T, U, V>>;
125
130
  };
126
131
 
127
132
  type Props<T, U extends boolean, V extends GroupBase<T>> = {
@@ -158,6 +163,7 @@ type Props<T, U extends boolean, V extends GroupBase<T>> = {
158
163
  forbidValuesClearInCollnMode?: boolean;
159
164
  otherSelectProps?: Record<string, unknown>;
160
165
  isOptionDisabled?: (option: T) => boolean;
166
+ popoverPlacement?: Placement;
161
167
  };
162
168
 
163
169
  function SelectInPopoverInner<T, U extends boolean, V extends GroupBase<T>>(
@@ -197,8 +203,8 @@ function SelectInPopoverInner<T, U extends boolean, V extends GroupBase<T>>(
197
203
  otherSelectProps,
198
204
  forbidValuesClearInCollnMode,
199
205
  isOptionDisabled,
206
+ popoverPlacement = "bottom-start",
200
207
  } = props;
201
- const [triggerElement, setTriggerElement] = useState<HTMLDivElement | null>(null);
202
208
  const [visible, setVisible] = useControllableState({
203
209
  value: menuIsOpen,
204
210
  defaultValue: false,
@@ -206,22 +212,15 @@ function SelectInPopoverInner<T, U extends boolean, V extends GroupBase<T>>(
206
212
  return value ? onMenuOpen?.() : onMenuClose?.();
207
213
  },
208
214
  });
215
+ const isPhone = useIsPhone();
209
216
  const blurTimeoutRef = useRef<ReturnType<typeof setTimeout>>();
210
217
  const selectRef = useRef<SelectInstance<T, U, V>>(null);
211
- const ref = useRef<HTMLDivElement | null>(null);
212
-
213
- useImperativeHandle(
214
- forwardedRef,
215
- () =>
216
- ({
217
- valueRef: ref.current,
218
- selectRef: selectRef.current,
219
- } as {valueRef: HTMLDivElement; selectRef: SelectInstance<T, U, V> | null})
220
- );
218
+ const [triggerElement, setTriggerElement] = useState<HTMLDivElement | null>(null);
221
219
 
222
- useEffect(() => {
223
- setTriggerElement(ref.current);
224
- }, []);
220
+ useImperativeHandle(forwardedRef, () => ({
221
+ valueRef: triggerElement,
222
+ selectRef,
223
+ }));
225
224
 
226
225
  useEffect(() => {
227
226
  if (blurTimeoutRef.current) {
@@ -274,8 +273,8 @@ function SelectInPopoverInner<T, U extends boolean, V extends GroupBase<T>>(
274
273
  }, [disabled, onMenuOpen, setVisible]);
275
274
 
276
275
  const styles = useMemo(() => {
277
- return combineStyles<T, U, V>([makeSelectInPopoverStyles(), selectStyles]);
278
- }, [selectStyles]);
276
+ return combineStyles<T, U, V>([makeSelectInPopoverStyles(isPhone), selectStyles]);
277
+ }, [selectStyles, isPhone]);
279
278
 
280
279
  const onTriggerClick: React.MouseEventHandler = useCallback(
281
280
  (event) => {
@@ -312,8 +311,6 @@ function SelectInPopoverInner<T, U extends boolean, V extends GroupBase<T>>(
312
311
  [onHide, onSelectKeyDown, visible]
313
312
  );
314
313
 
315
- const isPhone = useIsPhone();
316
-
317
314
  const onBlur: React.FocusEventHandler<HTMLDivElement> = useCallback(() => {
318
315
  if (isPhone) {
319
316
  return;
@@ -356,9 +353,9 @@ function SelectInPopoverInner<T, U extends boolean, V extends GroupBase<T>>(
356
353
  };
357
354
 
358
355
  return (
359
- <>
356
+ <Popover.Root open={visible} onOpen={() => onShow()} onClose={() => onHide()}>
360
357
  <Trigger
361
- innerRef={ref}
358
+ innerRef={setTriggerElement}
362
359
  menuOpened={visible}
363
360
  disabled={disabled}
364
361
  valueSelected={Boolean(value)}
@@ -367,28 +364,22 @@ function SelectInPopoverInner<T, U extends boolean, V extends GroupBase<T>>(
367
364
  >
368
365
  {renderValue ? renderValue() : null}
369
366
  </Trigger>
370
- {Boolean(triggerElement) && (
371
- <Popup
367
+ <Popover.Trigger reference={triggerElement} />
368
+ <Wrap with={Popover.Portal} if={renderInPortal} getPopupContainer={getPopupContainer}>
369
+ <Popover.Content
372
370
  supportMobile
373
371
  title={title}
374
372
  offset={offset}
375
373
  popupContainerClassName={popupContainerClassName}
376
374
  popupClassName={cx(popupClassName, popupStyles)}
377
375
  mobilePopupContentClassName={mobileClassName}
378
- placement="bottom-start"
379
- renderInPortal={renderInPortal}
380
- open={visible}
381
- onOpen={() => onShow()}
382
- onClose={() => onHide()}
383
- trigger={<></>}
384
- triggerDomElement={triggerElement}
385
- getPopupContainer={getPopupContainer}
376
+ placement={popoverPlacement}
386
377
  >
387
378
  {title && !isPhone && <div className={titleClassName}>{title}</div>}
388
379
  {/*Usually we set popupContainerElement for react-select via context (SelectControlSettingsProvider). But here we render react-select in popover.*/}
389
380
  {/*Render target in controlled by Popover here. So we just override SelectControlContext here and set popupContainerElement to undefined. */}
390
381
  {/*So in dom react-select will be a child of popover. */}
391
- <SelectControlSettingsProvider getPopupContainerElement={undefined}>
382
+ <SelectControlSettingsProvider inPopover={true} getPopupContainerElement={undefined}>
392
383
  <ReactSelect<T, U, V>
393
384
  ref={selectRef}
394
385
  styles={styles}
@@ -423,9 +414,9 @@ function SelectInPopoverInner<T, U extends boolean, V extends GroupBase<T>>(
423
414
  isOptionDisabled={isOptionDisabled}
424
415
  />
425
416
  </SelectControlSettingsProvider>
426
- </Popup>
427
- )}
428
- </>
417
+ </Popover.Content>
418
+ </Wrap>
419
+ </Popover.Root>
429
420
  );
430
421
  }
431
422
 
@@ -158,13 +158,23 @@ export const makeSingleLineStyles = <T, U extends boolean, V extends GroupBase<T
158
158
  control: makeControlStyle<T, U, V>({isSingleLine: true}).control,
159
159
  });
160
160
 
161
- export const makeSelectInPopoverStyles = <T, U extends boolean, V extends GroupBase<T>>(): StylesConfig<T, U, V> => ({
161
+ export const makeSelectInPopoverStyles = <T, U extends boolean, V extends GroupBase<T>>(
162
+ isPhone: boolean
163
+ ): StylesConfig<T, U, V> => ({
162
164
  container: (props) => ({
163
165
  ...props,
164
166
  minWidth: 180,
165
167
  width: "100%",
166
168
  paddingTop: space.s6,
167
169
  paddingInline: space.s6,
170
+ ...(isPhone
171
+ ? {
172
+ display: "grid",
173
+ gridTemplateRows: "auto 1fr",
174
+ minHeight: 0,
175
+ paddingBottom: space.s20,
176
+ }
177
+ : {}),
168
178
  }),
169
179
  option: (props) => ({
170
180
  ...props,
@@ -182,6 +192,16 @@ export const makeSelectInPopoverStyles = <T, U extends boolean, V extends GroupB
182
192
  width: `calc(100% - ${space.s2 * 2}px)`,
183
193
  borderRadius: border.radius4,
184
194
  }),
195
+ menuList: (props) => {
196
+ if (isPhone) {
197
+ return {
198
+ ...props,
199
+ maxHeight: "100%",
200
+ height: "100%",
201
+ };
202
+ }
203
+ return props;
204
+ },
185
205
  menu: (props) => ({
186
206
  ...props,
187
207
  minWidth: 100,