@fibery/ui-kit 1.34.7 → 1.35.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.
Files changed (67) hide show
  1. package/package.json +2 -2
  2. package/src/actions-menu/actions-menu-sub-menu.tsx +3 -0
  3. package/src/antd/styles.ts +6 -6
  4. package/src/button/base-button.tsx +1 -1
  5. package/src/button/icon-button.tsx +2 -2
  6. package/src/design-system.ts +88 -31
  7. package/src/dropdown-menu/index.tsx +2 -3
  8. package/src/emoji-picker/app-icon-picker.tsx +1 -0
  9. package/src/emoji-picker/emoji-picker-content-with-color.tsx +1 -1
  10. package/src/emoji-picker/primitives/emoji.tsx +4 -2
  11. package/src/emoji-picker/primitives/render-config-provider.tsx +12 -0
  12. package/src/icons/ast/AddDatabase.ts +8 -0
  13. package/src/icons/ast/AddIntegration.ts +8 -0
  14. package/src/icons/ast/AiSearch.ts +8 -0
  15. package/src/icons/ast/Clean.ts +8 -0
  16. package/src/icons/ast/CollapseAll.ts +8 -0
  17. package/src/icons/ast/CreditsFilled.ts +8 -0
  18. package/src/icons/ast/DatabaseOff.ts +8 -0
  19. package/src/icons/ast/Dependency.ts +8 -0
  20. package/src/icons/ast/Gift.ts +8 -0
  21. package/src/icons/ast/ManyPeople.ts +8 -0
  22. package/src/icons/ast/Markdown.ts +8 -0
  23. package/src/icons/ast/PeopleCheck.ts +8 -0
  24. package/src/icons/ast/PresentPlay.ts +8 -0
  25. package/src/icons/ast/PresentStop.ts +8 -0
  26. package/src/icons/ast/SendArrow.ts +1 -1
  27. package/src/icons/ast/SettingsOff.ts +8 -0
  28. package/src/icons/ast/Template.ts +8 -0
  29. package/src/icons/ast/UserCheck.ts +8 -0
  30. package/src/icons/ast/UserGroupRemove.ts +8 -0
  31. package/src/icons/ast/UserX.ts +8 -0
  32. package/src/icons/ast/ViewAi.ts +8 -0
  33. package/src/icons/ast/Views.ts +1 -1
  34. package/src/icons/ast/index.tsx +20 -0
  35. package/src/icons/react/AddDatabase.tsx +13 -0
  36. package/src/icons/react/AddIntegration.tsx +13 -0
  37. package/src/icons/react/AiSearch.tsx +13 -0
  38. package/src/icons/react/Clean.tsx +13 -0
  39. package/src/icons/react/CollapseAll.tsx +13 -0
  40. package/src/icons/react/CreditsFilled.tsx +13 -0
  41. package/src/icons/react/DatabaseOff.tsx +13 -0
  42. package/src/icons/react/Dependency.tsx +13 -0
  43. package/src/icons/react/Gift.tsx +13 -0
  44. package/src/icons/react/ManyPeople.tsx +13 -0
  45. package/src/icons/react/Markdown.tsx +13 -0
  46. package/src/icons/react/PeopleCheck.tsx +13 -0
  47. package/src/icons/react/PresentPlay.tsx +13 -0
  48. package/src/icons/react/PresentStop.tsx +13 -0
  49. package/src/icons/react/SettingsOff.tsx +13 -0
  50. package/src/icons/react/Template.tsx +13 -0
  51. package/src/icons/react/UserCheck.tsx +13 -0
  52. package/src/icons/react/UserGroupRemove.tsx +13 -0
  53. package/src/icons/react/UserX.tsx +13 -0
  54. package/src/icons/react/ViewAi.tsx +13 -0
  55. package/src/icons/react/index.tsx +20 -0
  56. package/src/palette.ts +2 -30
  57. package/src/select/custom-select-partials/clear-indicator.tsx +4 -0
  58. package/src/select/custom-select-partials/group-heading.tsx +7 -5
  59. package/src/select/custom-select-partials/menu-list-virtualized.tsx +22 -4
  60. package/src/select/custom-select-partials/menu.tsx +5 -6
  61. package/src/select/index.tsx +39 -28
  62. package/src/select/select-in-popover.tsx +32 -19
  63. package/src/select/styles.ts +10 -2
  64. package/src/toast/primitives.tsx +3 -1
  65. package/src/toast/toast-queue.ts +22 -0
  66. package/src/toast/toaster.tsx +2 -1
  67. package/src/tooltip.tsx +13 -0
package/src/palette.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export const slate = {
2
+ slateBase: "hsl(0, 0%, 99%)",
2
3
  slate1: "hsl(206, 30%, 99%)",
3
4
  slate2: "hsl(210, 17%, 98%)",
4
5
  slate3: "hsl(209, 13%, 95%)",
@@ -14,6 +15,7 @@ export const slate = {
14
15
  } as const;
15
16
 
16
17
  export const slateDark = {
18
+ slateBase: "hsl(0, 0%, 3%)",
17
19
  slate1: "hsl(200, 7%, 9%)",
18
20
  slate2: "hsl(195, 7%, 11%)",
19
21
  slate3: "hsl(197, 7%, 14%)",
@@ -28,36 +30,6 @@ export const slateDark = {
28
30
  slate12: "hsl(210, 6%, 93%)",
29
31
  } as const;
30
32
 
31
- export const sage = {
32
- sage1: "hsl(155, 30%, 99%)",
33
- sage2: "hsl(150, 17%, 98%)",
34
- sage3: "hsl(151, 11%, 95%)",
35
- sage4: "hsl(151, 9%, 93%)",
36
- sage5: "hsl(151, 8%, 91%)",
37
- sage6: "hsl(152, 7%, 88%)",
38
- sage7: "hsl(153, 7%, 85%)",
39
- sage8: "hsl(154, 6%, 78%)",
40
- sage9: "hsl(155, 4%, 56%)",
41
- sage10: "hsl(154, 3%, 52%)",
42
- sage11: "hsl(155, 3%, 43%)",
43
- sage12: "hsl(155, 24%, 9%)",
44
- } as const;
45
-
46
- export const sageDark = {
47
- sage1: "hsl(160, 7%, 8%)",
48
- sage2: "hsl(150, 7%, 11%)",
49
- sage3: "hsl(150, 7%, 13%)",
50
- sage4: "hsl(150, 6%, 15%)",
51
- sage5: "hsl(150, 6%, 17%)",
52
- sage6: "hsl(150, 6%, 20%)",
53
- sage7: "hsl(150, 5%, 24%)",
54
- sage8: "hsl(150, 5%, 31%)",
55
- sage9: "hsl(155, 6%, 42%)",
56
- sage10: "hsl(153, 5%, 48%)",
57
- sage11: "hsl(155, 5%, 62%)",
58
- sage12: "hsl(155, 6%, 93%)",
59
- } as const;
60
-
61
33
  export const teal = {
62
34
  teal1: "hsl(165, 60%, 99%)",
63
35
  teal2: "hsl(169, 65%, 97%)",
@@ -21,3 +21,7 @@ export function ClearIndicator<
21
21
  </div>
22
22
  );
23
23
  }
24
+
25
+ export function NoClearIndicator() {
26
+ return null;
27
+ }
@@ -1,10 +1,9 @@
1
- import {GroupBase} from "../index";
2
- import {GroupHeadingProps, components} from "react-select";
3
1
  import {css} from "@linaria/core";
2
+ import {GroupHeadingProps, components} from "react-select";
4
3
  import {layout, space, textStyles, themeVars} from "../../design-system";
5
- import React from "react";
6
- import {isPureTextChildren} from "../util";
7
4
  import {TooltipIfOverflown} from "../../tooltip-if-overflown";
5
+ import {GroupBase} from "../index";
6
+ import {isPureTextChildren} from "../util";
8
7
 
9
8
  export const groupHeadingNulledStyles = {
10
9
  paddingLeft: "",
@@ -20,7 +19,7 @@ export const groupHeadingNulledStyles = {
20
19
  const groupHeadingClass = css`
21
20
  min-height: ${layout.menuItemHeight}px;
22
21
  color: ${themeVars.disabledTextColor};
23
- padding: 0 ${space.s6}px 0 ${space.s8}px;
22
+ padding: 0 ${space.s6}px ${space.s2}px ${space.s8}px;
24
23
  display: flex;
25
24
  align-content: flex-end;
26
25
  align-items: flex-end;
@@ -56,6 +55,9 @@ export function GroupHeading<
56
55
  if (props.data.separator) {
57
56
  return <GroupDivider />;
58
57
  }
58
+ if (props.data.label === undefined) {
59
+ return null;
60
+ }
59
61
  const isPureText = isPureTextChildren(children);
60
62
  return (
61
63
  <components.GroupHeading {...props} className={groupHeadingClass}>
@@ -1,9 +1,25 @@
1
+ import {css} from "@linaria/core";
2
+ import _, {isFunction, isObject} from "lodash";
3
+ import {Children, ComponentType, CSSProperties, ReactNode, useContext, useEffect, useRef, useState} from "react";
1
4
  import {GroupHeadingProps, GroupProps, MenuListProps} from "react-select";
2
5
  import {ItemContent, Virtuoso, VirtuosoHandle} from "react-virtuoso";
3
- import {Children, ComponentType, CSSProperties, ReactNode, useContext, useEffect, useRef, useState} from "react";
4
- import {GroupBase, ReactSelectRefContext} from "../util";
5
6
  import {layout} from "../../../src/design-system";
6
- import _, {isFunction, isObject} from "lodash";
7
+ import {GroupBase, ReactSelectRefContext} from "../util";
8
+
9
+ const PADDING_BLOCK_HEIGHT = 6;
10
+
11
+ const Spacer = () => (
12
+ <div
13
+ className={css`
14
+ height: ${PADDING_BLOCK_HEIGHT}px;
15
+ `}
16
+ />
17
+ );
18
+
19
+ const components = {
20
+ Footer: Spacer,
21
+ Header: Spacer,
22
+ };
7
23
 
8
24
  const OPTION_HEIGHT = layout.menuItemHeight;
9
25
  // this code is logic stolen from windowed-select SCROLL_INTO_VIEW_CHECK_FIX prevents list scrolling when focusing
@@ -128,7 +144,7 @@ export function MenuListVirtualized<
128
144
  }
129
145
  }
130
146
  }, [flattenChildren, initialFocusedOption, select]);
131
- const menuHeight = Math.min(flattenChildren.length * layout.menuItemHeight, maxHeight);
147
+ const menuHeight = Math.min(flattenChildren.length * layout.menuItemHeight + PADDING_BLOCK_HEIGHT * 2, maxHeight);
132
148
  //scrolling to focused option
133
149
  useEffect(() => {
134
150
  let to: number | undefined;
@@ -171,6 +187,7 @@ export function MenuListVirtualized<
171
187
  window.clearTimeout(to);
172
188
  };
173
189
  }, [focusedOption, flattenChildren, menuHeight, initialFocusedOption, virtuoso]);
190
+
174
191
  return (
175
192
  // Needed for correct display inside portals and etc.
176
193
  <div style={getStyles("menuList", props) as CSSProperties}>
@@ -183,6 +200,7 @@ export function MenuListVirtualized<
183
200
  data={flattenChildren}
184
201
  totalCount={flattenChildren.length}
185
202
  itemContent={drawListElement}
203
+ components={components}
186
204
  />
187
205
  </div>
188
206
  );
@@ -1,8 +1,8 @@
1
- import {GroupBase} from "../index";
2
- import {CSSObjectWithLabel, MenuProps, components} from "react-select";
3
- import cn from "classnames";
4
1
  import {css} from "@linaria/core";
5
- import {border, space, themeVars} from "../../design-system";
2
+ import cn from "classnames";
3
+ import {CSSObjectWithLabel, MenuProps, components} from "react-select";
4
+ import {border, themeVars} from "../../design-system";
5
+ import {GroupBase} from "../index";
6
6
 
7
7
  export const MenuListNulledStyles: CSSObjectWithLabel = {
8
8
  paddingTop: "",
@@ -21,10 +21,9 @@ const MenuRootClass = css`
21
21
  background-color: ${themeVars.colorBgSelectMenu};
22
22
  box-shadow: ${themeVars.shadowSelectMenu};
23
23
  border-radius: ${border.radius6}px;
24
- padding-top: ${space.s6}px;
25
- padding-bottom: ${space.s6}px;
26
24
  overflow: hidden;
27
25
  `;
26
+
28
27
  export function Menu<Option, IsMulti extends boolean = false, Group extends GroupBase<Option> = GroupBase<Option>>(
29
28
  props: MenuProps<Option, IsMulti, Group>
30
29
  ) {
@@ -1,7 +1,8 @@
1
+ import {useComposedRefs} from "@fibery/react/src/use-composed-refs";
1
2
  import {forwardRef, RefObject, useCallback, useMemo, useRef, useState} from "react";
2
3
  import BaseSelect, {
3
4
  ActionMeta,
4
- components as reactSelectComponents,
5
+ Props as BaseSelectProps,
5
6
  createFilter,
6
7
  MenuListProps,
7
8
  MenuProps,
@@ -11,43 +12,47 @@ import BaseSelect, {
11
12
  OnChangeValue,
12
13
  OptionProps,
13
14
  OptionsOrGroups,
14
- Props as BaseSelectProps,
15
15
  PropsValue,
16
+ components as reactSelectComponents,
16
17
  SelectInstance,
17
18
  SingleValue,
18
19
  SingleValueProps,
19
20
  StylesConfig,
20
21
  } from "react-select";
21
22
  import BaseCreatableSelect, {CreatableProps} from "react-select/creatable";
22
- import {componentsStyles, singleLineComponentsStyle, virtualizedStyles, zIndexStyles} from "./styles";
23
- import {useSelectControlSettings} from "./select-control-settings-context";
24
- import {Option, OptionSlow} from "./custom-select-partials/option";
25
- import {Menu} from "./custom-select-partials/menu";
26
- import {GroupHeading} from "./custom-select-partials/group-heading";
23
+ import {ClearIndicator, NoClearIndicator} from "./custom-select-partials/clear-indicator";
27
24
  import {DropdownIndicator} from "./custom-select-partials/drop-down-indicator";
25
+ import {GroupHeading} from "./custom-select-partials/group-heading";
26
+ import {Menu} from "./custom-select-partials/menu";
27
+ import {MenuListVirtualized} from "./custom-select-partials/menu-list-virtualized";
28
28
  import {NoOptionsMessage} from "./custom-select-partials/no-option-message";
29
- import {ClearIndicator} from "./custom-select-partials/clear-indicator";
29
+ import {Option, OptionSlow} from "./custom-select-partials/option";
30
+ import {useSelectControlSettings} from "./select-control-settings-context";
31
+ import {
32
+ componentsStyles,
33
+ nonVirtualizedStyles,
34
+ singleLineComponentsStyle,
35
+ virtualizedStyles,
36
+ zIndexStyles,
37
+ } from "./styles";
30
38
  import {countOptions, GroupBase, ReactSelectRefContext} from "./util";
31
- import {MenuListVirtualized} from "./custom-select-partials/menu-list-virtualized";
32
- import {useComposedRefs} from "@fibery/react/src/use-composed-refs";
33
39
 
40
+ export {reactSelectComponents as components, MenuListVirtualized};
34
41
  export type {
35
- OptionsOrGroups,
42
+ ActionMeta,
36
43
  GroupBase,
37
- StylesConfig,
38
- MenuProps,
39
44
  MenuListProps,
40
- OptionProps,
41
- SingleValueProps,
42
- MultiValueProps,
43
- SingleValue,
45
+ MenuProps,
44
46
  MultiValue,
45
- ActionMeta,
47
+ MultiValueProps,
46
48
  OnChangeValue,
49
+ OptionProps,
50
+ OptionsOrGroups,
47
51
  PropsValue,
52
+ SingleValue,
53
+ SingleValueProps,
54
+ StylesConfig,
48
55
  };
49
- export {reactSelectComponents as components};
50
- export {MenuListVirtualized};
51
56
 
52
57
  //Group dummy for virtualized option-lists. For performance.
53
58
  function GroupVirtualized() {
@@ -71,6 +76,7 @@ export type SelectProps<
71
76
  virtualized?: boolean;
72
77
  isCollectionMode?: IsMulti;
73
78
  disabled?: boolean;
79
+ forbidValuesClearInCollnMode?: boolean;
74
80
  };
75
81
 
76
82
  export function SingleRowSelect<
@@ -110,6 +116,7 @@ export const Select = forwardRef(function Select<
110
116
  onMenuOpen,
111
117
  onMenuClose,
112
118
  onChange,
119
+ forbidValuesClearInCollnMode,
113
120
  ...rest
114
121
  }: SelectProps<Option, IsMulti, Group>,
115
122
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -161,11 +168,10 @@ export const Select = forwardRef(function Select<
161
168
  },
162
169
  [onKeyDown, menuOpenState]
163
170
  );
164
-
165
171
  const combinedStyles = useMemo(() => {
166
172
  return combineStyles<Option, IsMulti, Group>([
167
173
  componentsStyles,
168
- virtualized ? virtualizedStyles : {},
174
+ virtualized ? virtualizedStyles : nonVirtualizedStyles,
169
175
  zIndex ? zIndexStyles(zIndex) : {},
170
176
  styles,
171
177
  ] as StylesConfig<Option, IsMulti, Group>[]);
@@ -183,7 +189,7 @@ export const Select = forwardRef(function Select<
183
189
  menuPlacement={"auto"}
184
190
  styles={combinedStyles}
185
191
  isMulti={isCollectionMode}
186
- backspaceRemovesValue={isCollectionMode}
192
+ backspaceRemovesValue={isCollectionMode && !forbidValuesClearInCollnMode}
187
193
  tabSelectsValue={false}
188
194
  components={{
189
195
  Menu: Menu,
@@ -195,7 +201,7 @@ export const Select = forwardRef(function Select<
195
201
  Read Option definition for more info
196
202
  bug here: https://the.fibery.io/SoftDev/bug/Select-option-behaviour-is-incorrect-9413
197
203
  */
198
- MultiValueRemove: ClearIndicator,
204
+ MultiValueRemove: isCollectionMode && forbidValuesClearInCollnMode ? NoClearIndicator : ClearIndicator,
199
205
  NoOptionsMessage,
200
206
  GroupHeading,
201
207
  Option: optionsCount > FAST_OPTION_USAGE_THRESHOLD ? Option : OptionSlow,
@@ -253,15 +259,20 @@ export function CreatableSelectInner<
253
259
  return countOptions<Option, Group>(rest.options);
254
260
  }, [rest.options]);
255
261
 
262
+ const combinedStyles = useMemo(() => {
263
+ return combineStyles<Option, IsMulti, Group>([
264
+ componentsStyles,
265
+ virtualized ? virtualizedStyles : nonVirtualizedStyles,
266
+ styles,
267
+ ] as StylesConfig<Option, IsMulti, Group>[]);
268
+ }, [styles, virtualized]);
269
+
256
270
  return (
257
271
  <BaseCreatableSelect
258
272
  ref={ref}
259
273
  menuPortalTarget={menuPortalTarget}
260
274
  menuPlacement={"auto"}
261
- styles={combineStyles<Option, IsMulti, Group>([
262
- componentsStyles as unknown as StylesConfig<Option, IsMulti, Group>,
263
- styles,
264
- ])}
275
+ styles={combinedStyles}
265
276
  isMulti={isCollectionMode}
266
277
  backspaceRemovesValue={isCollectionMode}
267
278
  tabSelectsValue={false}
@@ -1,6 +1,5 @@
1
+ import {useControllableState} from "@fibery/react/src/use-controllable-state";
1
2
  import {css, cx} from "@linaria/core";
2
- import {border, space, textStyles} from "../design-system";
3
- import {inputOverrides} from "../antd/styles";
4
3
  import React, {
5
4
  ComponentProps,
6
5
  ComponentType,
@@ -13,8 +12,12 @@ import React, {
13
12
  useRef,
14
13
  useState,
15
14
  } from "react";
15
+ import {inputOverrides} from "../antd/styles";
16
+ import {border, space, textStyles} from "../design-system";
16
17
  import {Popup} from "../popup";
17
18
  import {$TSFixMe} from "../tsfixme";
19
+ import {useIsPhone} from "../use-is-phone";
20
+ import {Menu} from "./custom-select-partials/menu";
18
21
  import {
19
22
  ActionMeta,
20
23
  combineStyles,
@@ -27,9 +30,6 @@ import {
27
30
  StylesConfig,
28
31
  } from "./index";
29
32
  import {SelectControlSettingsProvider} from "./select-control-settings-context";
30
- import {Menu} from "./custom-select-partials/menu";
31
- import {useIsPhone} from "../use-is-phone";
32
- import {useControllableState} from "@fibery/react/src/use-controllable-state";
33
33
 
34
34
  const offset = [0, space.s4] as [number, number];
35
35
  const popupHeightVH = 45;
@@ -53,10 +53,6 @@ const popupContainerClassName = css`
53
53
  const popupClassName = css`
54
54
  min-width: 320px;
55
55
  max-width: 440px;
56
- padding-top: ${popupPaddingTop}px;
57
- padding-bottom: ${popupPaddingBottom}px;
58
- padding-left: ${space.s8}px;
59
- padding-right: ${space.s8}px;
60
56
  `;
61
57
  const mobileClassName = css`
62
58
  padding-top: ${space.s12}px;
@@ -85,10 +81,8 @@ const valueClassName = css`
85
81
 
86
82
  const titleClassName = css`
87
83
  ${textStyles.heading6}
88
- padding-top: ${space.s6}px;
89
- padding-left: ${space.s8}px;
90
- padding-right: ${space.s8}px;
91
- padding-bottom: ${space.s12}px;
84
+ padding-top: ${space.s12}px;
85
+ padding-inline: ${space.s12}px;
92
86
  `;
93
87
 
94
88
  export const valueMaxHeight = 116;
@@ -98,6 +92,8 @@ export const selectInPopupStyles = {
98
92
  ...props,
99
93
  minWidth: 180,
100
94
  width: "100%",
95
+ paddingTop: space.s6,
96
+ paddingInline: space.s6,
101
97
  }),
102
98
  option: (props: $TSFixMe) => ({
103
99
  ...props,
@@ -110,13 +106,16 @@ export const selectInPopupStyles = {
110
106
  ...props,
111
107
  maxHeight: valueMaxHeight,
112
108
  overflow: "auto",
109
+ margin: space.s2,
110
+ marginBottom: space.s4,
111
+ width: `calc(100% - ${space.s2 * 2}px)`,
112
+ borderRadius: border.radius4,
113
113
  }),
114
114
  menu: (props: $TSFixMe) => ({
115
115
  ...props,
116
116
  minWidth: 100,
117
117
  position: "static",
118
- marginTop: space.s6,
119
- marginBottom: 0,
118
+ marginBlock: 0,
120
119
  boxShadow: "none !important",
121
120
  borderRadius: border.radius4,
122
121
  }),
@@ -169,12 +168,12 @@ type Props<Option, IsMulti extends boolean, Group extends GroupBase<Option>> = {
169
168
  renderValue?: () => ReactNode;
170
169
  title?: string;
171
170
  maxMenuHeight?: number;
172
- hideOnChange?: boolean;
171
+ hideOnChange?: boolean | ((newValue: OnChangeValue<Option, IsMulti>, actionMeta: ActionMeta<Option>) => boolean);
173
172
  renderInPortal?: boolean;
174
173
  popupStyles?: string;
175
174
  selectStyles?: StylesConfig<Option, IsMulti, Group>;
176
175
  formatGroupLabel?: (group: Group) => ReactNode;
177
- formatOptionLabel?: (option: Option) => ReactNode;
176
+ formatOptionLabel?: (option: Option, {context}: {context: "menu" | "value"}) => ReactNode;
178
177
  components?: ComponentsConfig;
179
178
  onInputChange?: (s: string, actionType: {action: string}) => void;
180
179
  onFocus?: () => void;
@@ -183,6 +182,8 @@ type Props<Option, IsMulti extends boolean, Group extends GroupBase<Option>> = {
183
182
  onMenuClose?: () => void | boolean;
184
183
  getPopupContainer?: () => HTMLElement;
185
184
  onSelectKeyDown?: React.KeyboardEventHandler<HTMLDivElement>;
185
+ forbidValuesClearInCollnMode?: boolean;
186
+ otherSelectProps?: Record<string, unknown>;
186
187
  };
187
188
 
188
189
  function SelectInPopoverInner<Option, IsMulti extends boolean, Group extends GroupBase<Option>>(
@@ -219,6 +220,8 @@ function SelectInPopoverInner<Option, IsMulti extends boolean, Group extends Gro
219
220
  onMenuClose,
220
221
  getPopupContainer,
221
222
  onSelectKeyDown,
223
+ otherSelectProps,
224
+ forbidValuesClearInCollnMode,
222
225
  } = props;
223
226
  const [triggerElement, setTriggerElement] = useState<HTMLDivElement | null>(null);
224
227
  const [visible, setVisible] = useControllableState({
@@ -280,6 +283,10 @@ function SelectInPopoverInner<Option, IsMulti extends boolean, Group extends Gro
280
283
  }, [visible]);
281
284
 
282
285
  const onShow = useCallback(() => {
286
+ if (disabled) {
287
+ return;
288
+ }
289
+
283
290
  if (blurTimeoutRef.current) {
284
291
  clearTimeout(blurTimeoutRef.current);
285
292
  }
@@ -287,7 +294,7 @@ function SelectInPopoverInner<Option, IsMulti extends boolean, Group extends Gro
287
294
  if (onMenuOpen) {
288
295
  onMenuOpen();
289
296
  }
290
- }, [onMenuOpen, setVisible]);
297
+ }, [disabled, onMenuOpen, setVisible]);
291
298
 
292
299
  const styles = useMemo(() => {
293
300
  return combineStyles<Option, IsMulti, Group>([selectInPopupStyles, selectStyles]);
@@ -385,7 +392,11 @@ function SelectInPopoverInner<Option, IsMulti extends boolean, Group extends Gro
385
392
  closeMenuOnScroll={false}
386
393
  closeMenuOnSelect={false}
387
394
  onChange={(newValue, actionMeta) => {
388
- if (hideOnChange) {
395
+ if (typeof hideOnChange === "function") {
396
+ if (hideOnChange(newValue, actionMeta)) {
397
+ onHide();
398
+ }
399
+ } else if (hideOnChange) {
389
400
  onHide();
390
401
  }
391
402
  onChange(newValue, actionMeta);
@@ -405,11 +416,13 @@ function SelectInPopoverInner<Option, IsMulti extends boolean, Group extends Gro
405
416
  isClearable={!isCollectionMode && isClearable}
406
417
  formatGroupLabel={formatGroupLabel}
407
418
  formatOptionLabel={formatOptionLabel}
419
+ {...otherSelectProps}
408
420
  components={{
409
421
  DropdownIndicator: null,
410
422
  IndicatorSeparator: null,
411
423
  Menu: mergedComponents.Menu as $TSFixMe,
412
424
  }}
425
+ forbidValuesClearInCollnMode={forbidValuesClearInCollnMode}
413
426
  />
414
427
  </SelectControlSettingsProvider>
415
428
  </Popup>
@@ -2,9 +2,9 @@ import {css} from "@linaria/core";
2
2
  import type {ControlProps, CSSObjectWithLabel, StylesConfig} from "react-select";
3
3
  import {inputOverrides} from "../antd/styles";
4
4
  import {layout, space, themeVars} from "../design-system";
5
- import {OptionNulledStyles, OptionNulledVitualizedStyles} from "./custom-select-partials/option";
6
- import {MenuListNulledStyles, MenuNulledStyles} from "./custom-select-partials/menu";
7
5
  import {groupHeadingNulledStyles} from "./custom-select-partials/group-heading";
6
+ import {MenuListNulledStyles, MenuNulledStyles} from "./custom-select-partials/menu";
7
+ import {OptionNulledStyles, OptionNulledVitualizedStyles} from "./custom-select-partials/option";
8
8
 
9
9
  export const expanderExpandedStyle = css`
10
10
  transform: rotate(180deg);
@@ -50,6 +50,14 @@ export const virtualizedStyles: StylesConfig = {
50
50
  }),
51
51
  };
52
52
 
53
+ export const nonVirtualizedStyles: StylesConfig = {
54
+ menuList: (provided) => ({
55
+ ...provided,
56
+ paddingTop: 6,
57
+ paddingBottom: 6,
58
+ }),
59
+ };
60
+
53
61
  export const zIndexStyles = (zIndex: number): StylesConfig => ({
54
62
  menuPortal: (provided) => ({
55
63
  ...provided,
@@ -3,7 +3,7 @@ import {css, cx} from "@linaria/core";
3
3
  import * as ToastPrimitives from "@radix-ui/react-toast";
4
4
  import {ElementRef, forwardRef} from "react";
5
5
  import {IconButton} from "../button/icon-button";
6
- import {border, space, textStyles, themeVars} from "../design-system";
6
+ import {border, space, textStyles, themeVars, transition} from "../design-system";
7
7
  import CloseIcon from "../icons/react/Close";
8
8
 
9
9
  const viewportCss = css`
@@ -21,6 +21,8 @@ const viewportCss = css`
21
21
  padding: 0;
22
22
  list-style: none;
23
23
 
24
+ transition: bottom ${transition}; // bottom may change dynamically
25
+
24
26
  &:not(:empty) {
25
27
  padding: ${space.s24}px; // increased mouse hover area to pause timers of toast
26
28
  }
@@ -13,6 +13,11 @@ type QueuedToast = AddToastProps & {
13
13
  id: string;
14
14
  };
15
15
 
16
+ type BottomOffsetRequest = {
17
+ id: string;
18
+ bottomOffset: number;
19
+ };
20
+
16
21
  type ToastQueueOpts = {
17
22
  maxActiveToasts?: number;
18
23
  onToastAdd?: (params: AddToastProps) => void;
@@ -27,6 +32,7 @@ export const makeToastQueue = ({maxActiveToasts = 1, onToastAdd, transformToast}
27
32
  const pubSub = makePubSub();
28
33
  let queue: QueuedToast[] = [];
29
34
  let activeToasts: QueuedToast[] = [];
35
+ let bottomOffsets: BottomOffsetRequest[] = [];
30
36
 
31
37
  let count = 0;
32
38
 
@@ -87,6 +93,22 @@ export const makeToastQueue = ({maxActiveToasts = 1, onToastAdd, transformToast}
87
93
  getActiveToasts() {
88
94
  return activeToasts;
89
95
  },
96
+ addBottomOffset: (bottomOffset: number) => {
97
+ const id = `${Math.random()}`;
98
+ bottomOffsets.push({id, bottomOffset});
99
+ pubSub.publish();
100
+
101
+ return () => {
102
+ bottomOffsets = bottomOffsets.filter((v) => v.id !== id);
103
+ pubSub.publish();
104
+ };
105
+ },
106
+ getBottomOffset() {
107
+ if (bottomOffsets.length === 0) {
108
+ return 0;
109
+ }
110
+ return Math.max(...bottomOffsets.map((v) => v.bottomOffset));
111
+ },
90
112
  subscribe: pubSub.subscribe,
91
113
  unsubscribe: pubSub.unsubscribe,
92
114
 
@@ -24,6 +24,7 @@ export const Toaster: React.FC = () => {
24
24
  const toastQueue = useToast();
25
25
 
26
26
  const toasts = useSyncExternalStore(toastQueue.subscribe, toastQueue.getActiveToasts);
27
+ const bottomOffset = useSyncExternalStore(toastQueue.subscribe, toastQueue.getBottomOffset);
27
28
 
28
29
  return (
29
30
  <ToastThemeProvider>
@@ -45,7 +46,7 @@ export const Toaster: React.FC = () => {
45
46
  />
46
47
  ))}
47
48
 
48
- <ToastViewport id={viewportId} />
49
+ <ToastViewport id={viewportId} style={{bottom: bottomOffset}} />
49
50
  </ToastThemeProvider>
50
51
  );
51
52
  };
package/src/tooltip.tsx CHANGED
@@ -4,6 +4,8 @@ import {forwardRef, type ReactNode, type SyntheticEvent} from "react";
4
4
  import {border, fontWeight, lineHeight, space, themeVars, tooltipDelay} from "./design-system";
5
5
  import {ShortcutBadge} from "./shortcut-badge";
6
6
 
7
+ const isFlagPresent = (flag: string) => new RegExp(`[?&]${flag}\\b`).test(window.location.search);
8
+
7
9
  const preventDefaultAndStopPropagation = (e: SyntheticEvent) => {
8
10
  e.preventDefault();
9
11
  e.stopPropagation();
@@ -114,6 +116,11 @@ export type TooltipProps = Omit<TooltipPrimitive.TooltipTriggerProps, "title"> &
114
116
  visible?: boolean;
115
117
  onVisibleChange?: (visible: boolean) => void;
116
118
  disabled?: boolean;
119
+ /**
120
+ * When `false`, allows to hover the content without closing the tooltip.
121
+ * @defaultValue trues
122
+ */
123
+ disableHoverableContent?: boolean;
117
124
  /** should keep tooltip visible after click */
118
125
  keepOnClick?: boolean;
119
126
  };
@@ -152,6 +159,7 @@ export const Tooltip = forwardRef<HTMLButtonElement, TooltipProps>(
152
159
  setContentElement,
153
160
  container,
154
161
  tooltipContentStyle,
162
+ disableHoverableContent,
155
163
  ...triggerProps
156
164
  },
157
165
  ref
@@ -169,11 +177,16 @@ export const Tooltip = forwardRef<HTMLButtonElement, TooltipProps>(
169
177
  }
170
178
  : null;
171
179
 
180
+ if (isFlagPresent("no-tooltips")) {
181
+ return <>{children}</>;
182
+ }
183
+
172
184
  return (
173
185
  <TooltipPrimitive.Root
174
186
  delayDuration={instant ? 0 : tooltipDelay.enter}
175
187
  open={disabled ? false : Boolean(content) && visible}
176
188
  onOpenChange={onVisibleChange}
189
+ disableHoverableContent={disableHoverableContent}
177
190
  >
178
191
  <TooltipPrimitive.Trigger ref={ref} {...triggerProps} {...keepOnClickProps} asChild>
179
192
  {children}