@fibery/ui-kit 1.36.1 → 1.37.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 (209) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/package.json +3 -3
  3. package/scripts/generate-icons.mjs +15 -1
  4. package/src/action-badge.tsx +5 -4
  5. package/src/actions-menu/actions-menu-confirmation.tsx +1 -12
  6. package/src/actions-menu/actions-menu-item.tsx +3 -3
  7. package/src/actions-menu/actions-menu-sub-command-menu.tsx +3 -0
  8. package/src/antd/ant-modal.tsx +17 -2
  9. package/src/antd/input.tsx +4 -3
  10. package/src/app-icon-with-fallback.tsx +5 -8
  11. package/src/app-icon-wrapper.tsx +4 -4
  12. package/src/appIcons.json +20 -0
  13. package/src/badge.tsx +14 -7
  14. package/src/beta-badge.tsx +21 -0
  15. package/src/button/actions-button-compact.tsx +1 -1
  16. package/src/button/base-button.tsx +4 -3
  17. package/src/button/button.tsx +89 -2
  18. package/src/button/icon-button.tsx +4 -2
  19. package/src/button/select-button.tsx +23 -8
  20. package/src/card-container.tsx +29 -65
  21. package/src/card-hidden-link.tsx +52 -0
  22. package/src/collapsible-section.tsx +13 -3
  23. package/src/color-picker/index.js +65 -60
  24. package/src/color-picker/swatch.tsx +28 -14
  25. package/src/command-menu/index.tsx +16 -11
  26. package/src/command-menu/nested-command-menu.tsx +8 -1
  27. package/src/context-menu/index.tsx +3 -3
  28. package/src/count-badge.tsx +57 -0
  29. package/src/date-picker/date-range-input.tsx +1 -1
  30. package/src/date-picker/fake-date-input.tsx +1 -1
  31. package/src/date-picker/relative-date-picker.tsx +1 -1
  32. package/src/date-picker/single-date-input.tsx +1 -1
  33. package/src/date-picker/utils.ts +9 -2
  34. package/src/design-system.ts +85 -50
  35. package/src/dropdown-menu/index.tsx +1 -1
  36. package/src/emoji-picker/emoji-picker-content-with-color.tsx +3 -9
  37. package/src/emoji-picker/icon-emoji-picker.tsx +75 -69
  38. package/src/emoji-picker/primitives/header.tsx +1 -0
  39. package/src/emoji-picker/primitives/search.tsx +12 -13
  40. package/src/error-alert/error-alert.tsx +19 -7
  41. package/src/field-app-icon.tsx +29 -0
  42. package/src/field-container.tsx +4 -2
  43. package/src/field-icon.tsx +26 -0
  44. package/src/field-type-icon.tsx +82 -0
  45. package/src/format-date-from-now.ts +1 -1
  46. package/src/guide-link.tsx +4 -3
  47. package/src/hint.tsx +10 -1
  48. package/src/html-styles.ts +15 -13
  49. package/src/icons/ast/AiFiberyBuild.ts +8 -0
  50. package/src/icons/ast/Anthropic.ts +8 -0
  51. package/src/icons/ast/Apple.ts +8 -0
  52. package/src/icons/ast/ArrowBottom.ts +1 -1
  53. package/src/icons/ast/ArrowForward.ts +1 -1
  54. package/src/icons/ast/ArrowLeft.ts +1 -1
  55. package/src/icons/ast/ArrowRight.ts +1 -1
  56. package/src/icons/ast/ArrowTop.ts +1 -1
  57. package/src/icons/ast/Crosshair.ts +8 -0
  58. package/src/icons/ast/Csv.ts +8 -0
  59. package/src/icons/ast/Document.ts +8 -0
  60. package/src/icons/ast/EntityCreate.ts +8 -0
  61. package/src/icons/ast/ExpandAll.ts +8 -0
  62. package/src/icons/ast/FiberyDesktopApp.ts +8 -0
  63. package/src/icons/ast/FiberyMono.ts +1 -1
  64. package/src/icons/ast/FileDownload.ts +8 -0
  65. package/src/icons/ast/GraduationCapFilled.ts +8 -0
  66. package/src/icons/ast/Home.ts +1 -1
  67. package/src/icons/ast/ImportFilled.ts +8 -0
  68. package/src/icons/ast/IntegrationsFilled.ts +8 -0
  69. package/src/icons/ast/LocationEdit.ts +8 -0
  70. package/src/icons/ast/MessagePlus.ts +8 -0
  71. package/src/icons/ast/OpenAi.ts +8 -0
  72. package/src/icons/ast/RicheditorMarkHighlight.ts +8 -0
  73. package/src/icons/ast/RicheditorMarkStrike.ts +1 -1
  74. package/src/icons/ast/RicheditorMarkUnderline.ts +1 -1
  75. package/src/icons/ast/SpaceApp.ts +8 -0
  76. package/src/icons/ast/SpaceGenerate.ts +8 -0
  77. package/src/icons/ast/SpaceList.ts +8 -0
  78. package/src/icons/ast/SpaceScratch.ts +8 -0
  79. package/src/icons/ast/SpaceTemplate.ts +8 -0
  80. package/src/icons/ast/SuggestIntegration.ts +8 -0
  81. package/src/icons/ast/TableLayout.ts +8 -0
  82. package/src/icons/ast/TemplatesFilled.ts +8 -0
  83. package/src/icons/ast/ThumbsDown.ts +8 -0
  84. package/src/icons/ast/ThumbsUp.ts +8 -0
  85. package/src/icons/ast/ViewDashboard.ts +8 -0
  86. package/src/icons/ast/WarningTriangleFilled.ts +8 -0
  87. package/src/icons/ast/Windows.ts +8 -0
  88. package/src/icons/ast/index.tsx +30 -0
  89. package/src/icons/react/AiFiberyBuild.tsx +13 -0
  90. package/src/icons/react/Anthropic.tsx +13 -0
  91. package/src/icons/react/Apple.tsx +13 -0
  92. package/src/icons/react/Crosshair.tsx +13 -0
  93. package/src/icons/react/Csv.tsx +13 -0
  94. package/src/icons/react/Document.tsx +13 -0
  95. package/src/icons/react/EntityCreate.tsx +13 -0
  96. package/src/icons/react/ExpandAll.tsx +13 -0
  97. package/src/icons/react/FiberyDesktopApp.tsx +13 -0
  98. package/src/icons/react/FileDownload.tsx +13 -0
  99. package/src/icons/react/GraduationCapFilled.tsx +13 -0
  100. package/src/icons/react/ImportFilled.tsx +13 -0
  101. package/src/icons/react/IntegrationsFilled.tsx +13 -0
  102. package/src/icons/react/LocationEdit.tsx +13 -0
  103. package/src/icons/react/MessagePlus.tsx +13 -0
  104. package/src/icons/react/OpenAi.tsx +13 -0
  105. package/src/icons/react/RicheditorMarkHighlight.tsx +13 -0
  106. package/src/icons/react/SpaceApp.tsx +13 -0
  107. package/src/icons/react/SpaceGenerate.tsx +13 -0
  108. package/src/icons/react/SpaceList.tsx +13 -0
  109. package/src/icons/react/SpaceScratch.tsx +13 -0
  110. package/src/icons/react/SpaceTemplate.tsx +13 -0
  111. package/src/icons/react/SuggestIntegration.tsx +13 -0
  112. package/src/icons/react/TableLayout.tsx +13 -0
  113. package/src/icons/react/TemplatesFilled.tsx +13 -0
  114. package/src/icons/react/ThumbsDown.tsx +13 -0
  115. package/src/icons/react/ThumbsUp.tsx +13 -0
  116. package/src/icons/react/ViewDashboard.tsx +13 -0
  117. package/src/icons/react/WarningTriangleFilled.tsx +13 -0
  118. package/src/icons/react/Windows.tsx +13 -0
  119. package/src/icons/react/index.tsx +30 -0
  120. package/src/icons/svg/ai-fibery-build.svg +24 -0
  121. package/src/icons/svg/anthropic.svg +3 -0
  122. package/src/icons/svg/apple.svg +4 -0
  123. package/src/icons/svg/arrow-bottom.svg +1 -1
  124. package/src/icons/svg/arrow-forward.svg +1 -1
  125. package/src/icons/svg/arrow-left.svg +1 -1
  126. package/src/icons/svg/arrow-right.svg +1 -1
  127. package/src/icons/svg/arrow-top.svg +1 -1
  128. package/src/icons/svg/crosshair.svg +4 -0
  129. package/src/icons/svg/csv.svg +3 -0
  130. package/src/icons/svg/document.svg +4 -0
  131. package/src/icons/svg/entity-create.svg +3 -0
  132. package/src/icons/svg/expand-all.svg +3 -0
  133. package/src/icons/svg/fibery-desktop-app.svg +101 -0
  134. package/src/icons/svg/fibery-mono.svg +6 -1
  135. package/src/icons/svg/file-download.svg +4 -0
  136. package/src/icons/svg/go-to.svg +1 -3
  137. package/src/icons/svg/graduation-cap-filled.svg +4 -0
  138. package/src/icons/svg/home.svg +4 -2
  139. package/src/icons/svg/import-filled.svg +4 -0
  140. package/src/icons/svg/integrations-filled.svg +4 -0
  141. package/src/icons/svg/location-edit.svg +13 -0
  142. package/src/icons/svg/message-plus.svg +4 -0
  143. package/src/icons/svg/open-ai.svg +3 -0
  144. package/src/icons/svg/open-as-page.svg +2 -3
  145. package/src/icons/svg/richeditor/mark/code.svg +4 -5
  146. package/src/icons/svg/richeditor/mark/em.svg +3 -2
  147. package/src/icons/svg/richeditor/mark/highlight.svg +3 -0
  148. package/src/icons/svg/richeditor/mark/strike.svg +3 -2
  149. package/src/icons/svg/richeditor/mark/strong.svg +3 -2
  150. package/src/icons/svg/richeditor/mark/underline.svg +4 -2
  151. package/src/icons/svg/space-app.svg +3 -0
  152. package/src/icons/svg/space-generate.svg +3 -0
  153. package/src/icons/svg/space-list.svg +4 -0
  154. package/src/icons/svg/space-scratch.svg +3 -0
  155. package/src/icons/svg/space-template.svg +3 -0
  156. package/src/icons/svg/suggest-integration.svg +4 -0
  157. package/src/icons/svg/table-layout.svg +3 -0
  158. package/src/icons/svg/templates-filled.svg +6 -0
  159. package/src/icons/svg/thumbs-down.svg +3 -0
  160. package/src/icons/svg/thumbs-up.svg +3 -0
  161. package/src/icons/svg/view-dashboard.svg +5 -0
  162. package/src/icons/svg/warning-triangle-filled.svg +3 -0
  163. package/src/icons/svg/windows.svg +15 -0
  164. package/src/icons/types.ts +2 -2
  165. package/src/integration-compact-info-button.tsx +3 -1
  166. package/src/layout-styles.ts +23 -0
  167. package/src/lists/list-row-surface.tsx +2 -1
  168. package/src/loaders.tsx +6 -6
  169. package/src/logo.tsx +23 -48
  170. package/src/mobile-styles.ts +2 -0
  171. package/src/new-badge.tsx +5 -6
  172. package/src/number-input/text-area-auto-sized.tsx +47 -0
  173. package/src/number-input/text-input-auto-sized.tsx +49 -0
  174. package/src/palette.ts +50 -50
  175. package/src/popup/index.tsx +1 -0
  176. package/src/rich-text-embed-error.tsx +2 -2
  177. package/src/select/{custom-select-partials → components}/menu.tsx +13 -7
  178. package/src/select/{custom-select-partials → components}/no-option-message.tsx +0 -1
  179. package/src/select/constants.ts +1 -0
  180. package/src/select/index.tsx +136 -145
  181. package/src/select/select-in-popover.tsx +103 -108
  182. package/src/select/styles.ts +60 -24
  183. package/src/shortcut-badge.tsx +1 -0
  184. package/src/tab-nav/tab-nav.tsx +12 -19
  185. package/src/theme-provider.tsx +9 -1
  186. package/src/toast/utils/toastify-item-name.ts +1 -1
  187. package/src/tooltip-if-overflown.tsx +9 -3
  188. package/src/type-badge-box.tsx +4 -2
  189. package/src/type-badge.tsx +20 -12
  190. package/src/unit/index.tsx +9 -1
  191. package/src/unit/loading-unit-value.tsx +1 -0
  192. package/src/unit/maybe-unit-value.tsx +3 -3
  193. package/src/unit/primitive.tsx +60 -41
  194. package/src/unit/styles.ts +12 -12
  195. package/src/unit/types.ts +5 -2
  196. package/src/unit/unit-button-group.tsx +6 -11
  197. package/src/unit/unit-content.tsx +13 -5
  198. package/src/unit/unit-with-title.tsx +6 -1
  199. package/src/unit/unit-with-tooltip.tsx +24 -9
  200. package/src/use-is-phone.tsx +12 -0
  201. package/src/workflow-progress-icon.tsx +1 -1
  202. package/src/number-input/text-area-with-autosize.tsx +0 -91
  203. package/src/number-input/text-inline-input-with-autosize.tsx +0 -60
  204. package/src/use-is-phone.ts +0 -5
  205. /package/src/select/{custom-select-partials → components}/clear-indicator.tsx +0 -0
  206. /package/src/select/{custom-select-partials → components}/drop-down-indicator.tsx +0 -0
  207. /package/src/select/{custom-select-partials → components}/group-heading.tsx +0 -0
  208. /package/src/select/{custom-select-partials → components}/menu-list-virtualized.tsx +0 -0
  209. /package/src/select/{custom-select-partials → components}/option.tsx +0 -0
@@ -1,8 +1,8 @@
1
1
  import {useControllableState} from "@fibery/react/src/use-controllable-state";
2
2
  import {css, cx} from "@linaria/core";
3
3
  import React, {
4
- ComponentProps,
5
4
  ComponentType,
5
+ ForwardedRef,
6
6
  forwardRef,
7
7
  ReactNode,
8
8
  useCallback,
@@ -15,9 +15,8 @@ import React, {
15
15
  import {inputOverrides} from "../antd/styles";
16
16
  import {border, space, textStyles} from "../design-system";
17
17
  import {Popup} from "../popup";
18
- import {$TSFixMe} from "../tsfixme";
19
18
  import {useIsPhone} from "../use-is-phone";
20
- import {Menu} from "./custom-select-partials/menu";
19
+ import {MenuTransparent} from "./components/menu";
21
20
  import {
22
21
  ActionMeta,
23
22
  combineStyles,
@@ -30,6 +29,10 @@ import {
30
29
  StylesConfig,
31
30
  } from "./index";
32
31
  import {SelectControlSettingsProvider} from "./select-control-settings-context";
32
+ import {ButtonColor, ButtonVariant} from "../button/base-button";
33
+ import {makeSelectInPopoverStyles} from "./styles";
34
+ import {SelectInstance} from "react-select";
35
+ import {SELECT_IN_POPOVER_VALUE_MAX_HEIGHT} from "./constants";
33
36
 
34
37
  const offset = [0, space.s4] as [number, number];
35
38
  const popupHeightVH = 45;
@@ -85,51 +88,26 @@ const titleClassName = css`
85
88
  padding-inline: ${space.s12}px;
86
89
  `;
87
90
 
88
- export const valueMaxHeight = 116;
89
-
90
- export const selectInPopupStyles = {
91
- container: (props: $TSFixMe) => ({
92
- ...props,
93
- minWidth: 180,
94
- width: "100%",
95
- paddingTop: space.s6,
96
- paddingInline: space.s6,
97
- }),
98
- option: (props: $TSFixMe) => ({
99
- ...props,
100
- padding: 0,
101
- borderRadius: border.radius4,
102
- paddingLeft: 0,
103
- paddingRight: 0,
104
- }),
105
- control: (props: $TSFixMe) => ({
106
- ...props,
107
- maxHeight: valueMaxHeight,
108
- overflow: "auto",
109
- margin: space.s2,
110
- marginBottom: space.s4,
111
- width: `calc(100% - ${space.s2 * 2}px)`,
112
- borderRadius: border.radius4,
113
- }),
114
- menu: (props: $TSFixMe) => ({
115
- ...props,
116
- minWidth: 100,
117
- position: "static",
118
- marginBlock: 0,
119
- boxShadow: "none !important",
120
- borderRadius: border.radius4,
121
- }),
122
- };
123
-
124
91
  export type TriggerProps = {
125
92
  innerRef: React.Ref<HTMLDivElement>;
126
93
  children: ReactNode;
127
94
  onClick?: React.MouseEventHandler;
95
+ iconStart?: ReactNode;
96
+ pending?: boolean;
97
+ pressed?: boolean;
98
+ menuOpened?: boolean;
128
99
  onKeyDown?: React.KeyboardEventHandler;
129
100
  disabled?: boolean;
101
+ size?: "small" | "medium" | "large";
102
+ fullWidth?: boolean;
103
+ style?: React.CSSProperties;
104
+ className?: string;
105
+ variant?: ButtonVariant;
106
+ color?: ButtonColor;
107
+ valueSelected: boolean;
130
108
  };
131
109
 
132
- const Trigger = ({innerRef, children, onClick, onKeyDown}: TriggerProps) => {
110
+ const TriggerDefault = ({innerRef, children, onClick, onKeyDown}: TriggerProps) => {
133
111
  return (
134
112
  <div ref={innerRef} onClick={onClick} onKeyDown={onKeyDown} tabIndex={0} className={valueClassName}>
135
113
  {children}
@@ -137,59 +115,54 @@ const Trigger = ({innerRef, children, onClick, onKeyDown}: TriggerProps) => {
137
115
  );
138
116
  };
139
117
 
140
- type Components = {
141
- Trigger: ComponentType<TriggerProps>;
142
- Menu: ComponentType<ComponentProps<typeof Menu>>;
118
+ export type SelectComponents<T, U extends boolean, V extends GroupBase<T>> = SelectProps<T, U, V>["components"] & {
119
+ Trigger?: ComponentType<TriggerProps>;
143
120
  };
144
121
 
145
- export type ComponentsConfig = Partial<Components>;
146
-
147
- const defaultComponents = {Trigger, Menu};
148
-
149
- type Ref = {
122
+ type SelectInPopoverRef<T, U extends boolean, V extends GroupBase<T>> = {
150
123
  valueRef: HTMLDivElement | null;
151
- selectRef: $TSFixMe | null;
124
+ selectRef: SelectInstance<T, U, V> | null;
152
125
  };
153
126
 
154
- type Props<Option, IsMulti extends boolean, Group extends GroupBase<Option>> = {
155
- value?: PropsValue<Option>;
127
+ type Props<T, U extends boolean, V extends GroupBase<T>> = {
128
+ value?: PropsValue<T>;
156
129
  menuIsOpen?: boolean;
157
130
  autoFocus?: boolean;
158
131
  virtualized?: boolean;
159
132
  defaultMenuIsOpen?: boolean;
160
133
  placeholder?: string;
161
134
  noOptionsMessage?: () => string | JSX.Element | null;
162
- options: OptionsOrGroups<Option, Group>;
163
- filterOption?: SelectProps<Option>["filterOption"];
135
+ options: OptionsOrGroups<T, V>;
136
+ filterOption?: SelectProps<T, U, V>["filterOption"];
164
137
  inputValue?: string;
165
138
  disabled?: boolean;
166
- isCollectionMode?: IsMulti;
139
+ isCollectionMode?: U;
167
140
  isClearable?: boolean;
168
141
  renderValue?: () => ReactNode;
169
142
  title?: string;
170
143
  maxMenuHeight?: number;
171
- hideOnChange?: boolean | ((newValue: OnChangeValue<Option, IsMulti>, actionMeta: ActionMeta<Option>) => boolean);
144
+ hideOnChange?: boolean | ((newValue: OnChangeValue<T, U>, actionMeta: ActionMeta<T>) => boolean);
172
145
  renderInPortal?: boolean;
173
146
  popupStyles?: string;
174
- selectStyles?: StylesConfig<Option, IsMulti, Group>;
175
- formatGroupLabel?: (group: Group) => ReactNode;
176
- formatOptionLabel?: (option: Option, {context}: {context: "menu" | "value"}) => ReactNode;
177
- components?: ComponentsConfig;
147
+ selectStyles?: StylesConfig<T, U, V>;
148
+ formatGroupLabel?: (group: V) => ReactNode;
149
+ formatOptionLabel?: (option: T, {context}: {context: "menu" | "value"}) => ReactNode;
150
+ components?: SelectComponents<T, U, V>;
178
151
  onInputChange?: (s: string, actionType: {action: string}) => void;
179
152
  onFocus?: () => void;
180
- onChange: (newValue: OnChangeValue<Option, IsMulti>, actionMeta: ActionMeta<Option>) => void;
153
+ onChange: (newValue: OnChangeValue<T, U>, actionMeta: ActionMeta<T>) => void;
181
154
  onMenuOpen?: () => void;
182
155
  onMenuClose?: () => void | boolean;
183
156
  getPopupContainer?: () => HTMLElement;
184
157
  onSelectKeyDown?: React.KeyboardEventHandler<HTMLDivElement>;
185
158
  forbidValuesClearInCollnMode?: boolean;
186
159
  otherSelectProps?: Record<string, unknown>;
187
- isOptionDisabled?: (option: Option) => boolean;
160
+ isOptionDisabled?: (option: T) => boolean;
188
161
  };
189
162
 
190
- function SelectInPopoverInner<Option, IsMulti extends boolean, Group extends GroupBase<Option>>(
191
- props: Omit<Props<Option, IsMulti, Group>, "maxMenuHeight">,
192
- forwardedRef: React.ForwardedRef<Ref>
163
+ function SelectInPopoverInner<T, U extends boolean, V extends GroupBase<T>>(
164
+ props: Omit<Props<T, U, V>, "maxMenuHeight">,
165
+ forwardedRef: ForwardedRef<SelectInPopoverRef<T, U, V>>
193
166
  ) {
194
167
  const {
195
168
  value,
@@ -234,7 +207,7 @@ function SelectInPopoverInner<Option, IsMulti extends boolean, Group extends Gro
234
207
  },
235
208
  });
236
209
  const blurTimeoutRef = useRef<ReturnType<typeof setTimeout>>();
237
- const selectRef = useRef<{focus: () => void}>(null);
210
+ const selectRef = useRef<SelectInstance<T, U, V>>(null);
238
211
  const ref = useRef<HTMLDivElement | null>(null);
239
212
 
240
213
  useImperativeHandle(
@@ -243,11 +216,13 @@ function SelectInPopoverInner<Option, IsMulti extends boolean, Group extends Gro
243
216
  ({
244
217
  valueRef: ref.current,
245
218
  selectRef: selectRef.current,
246
- } as {valueRef: HTMLDivElement; selectRef: $TSFixMe | null})
219
+ } as {valueRef: HTMLDivElement; selectRef: SelectInstance<T, U, V> | null})
247
220
  );
221
+
248
222
  useEffect(() => {
249
223
  setTriggerElement(ref.current);
250
224
  }, []);
225
+
251
226
  useEffect(() => {
252
227
  if (blurTimeoutRef.current) {
253
228
  clearTimeout(blurTimeoutRef.current);
@@ -299,7 +274,7 @@ function SelectInPopoverInner<Option, IsMulti extends boolean, Group extends Gro
299
274
  }, [disabled, onMenuOpen, setVisible]);
300
275
 
301
276
  const styles = useMemo(() => {
302
- return combineStyles<Option, IsMulti, Group>([selectInPopupStyles, selectStyles]);
277
+ return combineStyles<T, U, V>([makeSelectInPopoverStyles(), selectStyles]);
303
278
  }, [selectStyles]);
304
279
 
305
280
  const onTriggerClick: React.MouseEventHandler = useCallback(
@@ -324,27 +299,74 @@ function SelectInPopoverInner<Option, IsMulti extends boolean, Group extends Gro
324
299
  },
325
300
  [onShow, visible]
326
301
  );
302
+
303
+ const onKeyDown: React.KeyboardEventHandler<HTMLDivElement> = useCallback(
304
+ (event) => {
305
+ if ((event.key === "Escape" || event.key === "Tab") && visible) {
306
+ onHide();
307
+ event.preventDefault();
308
+ event.stopPropagation();
309
+ }
310
+ onSelectKeyDown?.(event);
311
+ },
312
+ [onHide, onSelectKeyDown, visible]
313
+ );
314
+
315
+ const isPhone = useIsPhone();
316
+
317
+ const onBlur: React.FocusEventHandler<HTMLDivElement> = useCallback(() => {
318
+ if (isPhone) {
319
+ return;
320
+ }
321
+ blurTimeoutRef.current = setTimeout(() => {
322
+ onHide(false);
323
+ }, 250);
324
+ }, [isPhone, onHide]);
325
+
326
+ const handleChange = useCallback(
327
+ (newValue: OnChangeValue<T, U>, actionMeta: ActionMeta<T>) => {
328
+ if (typeof hideOnChange === "function") {
329
+ if (hideOnChange(newValue, actionMeta)) {
330
+ onHide();
331
+ }
332
+ } else if (hideOnChange) {
333
+ onHide();
334
+ }
335
+ onChange(newValue, actionMeta);
336
+ },
337
+ [hideOnChange, onChange, onHide]
338
+ );
339
+
327
340
  const paddingPopup = popupPaddingTop + popupPaddingBottom;
328
341
  const paddingMenu = 6 + 6 + 6;
329
- const isPhone = useIsPhone();
342
+
330
343
  const maxMenuHeight = isPhone
331
- ? document.body.clientHeight - 45 - valueMaxHeight
344
+ ? document.body.clientHeight - 45 - SELECT_IN_POPOVER_VALUE_MAX_HEIGHT
332
345
  : Math.max((document.body.clientHeight / 100) * popupHeightVH, popupMinHeightPx) -
333
- valueMaxHeight -
346
+ SELECT_IN_POPOVER_VALUE_MAX_HEIGHT -
334
347
  paddingPopup -
335
348
  paddingMenu;
336
- const mergedComponents = {...defaultComponents, ...components};
349
+
350
+ const Trigger = components.Trigger || TriggerDefault;
351
+ const selectComponents = {
352
+ Menu: MenuTransparent,
353
+ DropdownIndicator: null,
354
+ IndicatorSeparator: null,
355
+ ...components,
356
+ };
337
357
 
338
358
  return (
339
359
  <>
340
- <mergedComponents.Trigger
360
+ <Trigger
341
361
  innerRef={ref}
362
+ menuOpened={visible}
363
+ disabled={disabled}
364
+ valueSelected={Boolean(value)}
342
365
  onClick={onTriggerClick}
343
366
  onKeyDown={onTriggerKeyDown}
344
- disabled={disabled}
345
367
  >
346
368
  {renderValue ? renderValue() : null}
347
- </mergedComponents.Trigger>
369
+ </Trigger>
348
370
  {Boolean(triggerElement) && (
349
371
  <Popup
350
372
  supportMobile
@@ -367,42 +389,19 @@ function SelectInPopoverInner<Option, IsMulti extends boolean, Group extends Gro
367
389
  {/*Render target in controlled by Popover here. So we just override SelectControlContext here and set popupContainerElement to undefined. */}
368
390
  {/*So in dom react-select will be a child of popover. */}
369
391
  <SelectControlSettingsProvider getPopupContainerElement={undefined}>
370
- <ReactSelect
392
+ <ReactSelect<T, U, V>
371
393
  ref={selectRef}
372
394
  styles={styles}
373
395
  isSearchable={true}
374
- onKeyDown={(event) => {
375
- if ((event.key === "Escape" || event.key === "Tab") && visible) {
376
- onHide();
377
- event.preventDefault();
378
- event.stopPropagation();
379
- }
380
- onSelectKeyDown?.(event);
381
- }}
396
+ onKeyDown={onKeyDown}
382
397
  autoFocus={autoFocus}
383
- onBlur={() => {
384
- if (isPhone) {
385
- return;
386
- }
387
- blurTimeoutRef.current = setTimeout(() => {
388
- onHide(false);
389
- }, 250);
390
- }}
398
+ onBlur={onBlur}
391
399
  value={value}
392
400
  defaultMenuIsOpen={defaultMenuIsOpen}
393
401
  controlShouldRenderValue
394
402
  closeMenuOnScroll={false}
395
403
  closeMenuOnSelect={false}
396
- onChange={(newValue, actionMeta) => {
397
- if (typeof hideOnChange === "function") {
398
- if (hideOnChange(newValue, actionMeta)) {
399
- onHide();
400
- }
401
- } else if (hideOnChange) {
402
- onHide();
403
- }
404
- onChange(newValue, actionMeta);
405
- }}
404
+ onChange={handleChange}
406
405
  placeholder={placeholder}
407
406
  onInputChange={onInputChange}
408
407
  noOptionsMessage={noOptionsMessage}
@@ -419,11 +418,7 @@ function SelectInPopoverInner<Option, IsMulti extends boolean, Group extends Gro
419
418
  formatGroupLabel={formatGroupLabel}
420
419
  formatOptionLabel={formatOptionLabel}
421
420
  {...otherSelectProps}
422
- components={{
423
- DropdownIndicator: null,
424
- IndicatorSeparator: null,
425
- Menu: mergedComponents.Menu as $TSFixMe,
426
- }}
421
+ components={selectComponents}
427
422
  forbidValuesClearInCollnMode={forbidValuesClearInCollnMode}
428
423
  isOptionDisabled={isOptionDisabled}
429
424
  />
@@ -434,8 +429,8 @@ function SelectInPopoverInner<Option, IsMulti extends boolean, Group extends Gro
434
429
  );
435
430
  }
436
431
 
437
- type SelectInPopoverType = <Option, IsMulti extends boolean, Group extends GroupBase<Option>>(
438
- props: Omit<Props<Option, IsMulti, Group>, "maxMenuHeight"> & {ref?: React.ForwardedRef<Ref>}
432
+ type SelectInPopoverType = <T, U extends boolean, V extends GroupBase<T>>(
433
+ props: Omit<Props<T, U, V>, "maxMenuHeight"> & {ref?: ForwardedRef<SelectInPopoverRef<T, U, V>>}
439
434
  ) => ReturnType<typeof SelectInPopoverInner>;
440
435
 
441
436
  // Explicit type assertion to specify that component accepts generic props because forwardRef breaks it
@@ -1,20 +1,21 @@
1
1
  import {css} from "@linaria/core";
2
- import type {ControlProps, CSSObjectWithLabel, StylesConfig} from "react-select";
2
+ import type {CSSObjectWithLabel, GroupBase, StylesConfig} from "react-select";
3
3
  import {inputOverrides} from "../antd/styles";
4
- import {layout, space, themeVars} from "../design-system";
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";
4
+ import {border, layout, space, themeVars} from "../design-system";
5
+ import {groupHeadingNulledStyles} from "./components/group-heading";
6
+ import {MenuListNulledStyles, MenuNulledStyles} from "./components/menu";
7
+ import {OptionNulledStyles, OptionNulledVitualizedStyles} from "./components/option";
8
+ import {SELECT_IN_POPOVER_VALUE_MAX_HEIGHT} from "./constants";
8
9
 
9
10
  export const expanderExpandedStyle = css`
10
11
  transform: rotate(180deg);
11
12
  `;
12
13
 
13
- function createControlStyle({
14
+ function makeControlStyle<T, U extends boolean, V extends GroupBase<T>>({
14
15
  isSingleLine,
15
16
  }: {
16
17
  isSingleLine: boolean;
17
- }): (base: CSSObjectWithLabel, props: ControlProps) => CSSObjectWithLabel {
18
+ }): StylesConfig<T, U, V> {
18
19
  const childDivStyle: CSSObjectWithLabel = {
19
20
  padding: 0,
20
21
  overflow: "visible",
@@ -24,8 +25,8 @@ function createControlStyle({
24
25
  childDivStyle.flexWrap = "nowrap";
25
26
  }
26
27
 
27
- return (provided, state) =>
28
- ({
28
+ return {
29
+ control: (provided, state) => ({
29
30
  display: "flex",
30
31
  flexWrap: isSingleLine ? "nowrap" : "wrap",
31
32
  justifyContent: "space-between",
@@ -38,27 +39,30 @@ function createControlStyle({
38
39
  paddingLeft: space.s10,
39
40
  paddingRight: space.s12,
40
41
  "& > div": childDivStyle,
41
- } as unknown as CSSObjectWithLabel);
42
+ }),
43
+ };
42
44
  }
43
45
 
44
- export const virtualizedStyles: StylesConfig = {
46
+ export const makeVirtualizedStyles = <T, U extends boolean, V extends GroupBase<T>>(): StylesConfig<T, U, V> => ({
45
47
  option: () => ({...OptionNulledVitualizedStyles, ...OptionNulledStyles}),
46
48
  groupHeading: (provided) => ({
47
49
  ...provided,
48
50
  ...groupHeadingNulledStyles,
49
51
  height: layout.menuItemHeight,
50
52
  }),
51
- };
53
+ });
52
54
 
53
- export const nonVirtualizedStyles: StylesConfig = {
55
+ export const makeNonVirtualizedStyles = <T, U extends boolean, V extends GroupBase<T>>(): StylesConfig<T, U, V> => ({
54
56
  menuList: (provided) => ({
55
57
  ...provided,
56
58
  paddingTop: 6,
57
59
  paddingBottom: 6,
58
60
  }),
59
- };
61
+ });
60
62
 
61
- export const zIndexStyles = (zIndex: number): StylesConfig => ({
63
+ export const makeZIndexStyles = <T, U extends boolean, V extends GroupBase<T>>(
64
+ zIndex: number
65
+ ): StylesConfig<T, U, V> => ({
62
66
  menuPortal: (provided) => ({
63
67
  ...provided,
64
68
  zIndex: zIndex,
@@ -69,13 +73,11 @@ export const zIndexStyles = (zIndex: number): StylesConfig => ({
69
73
  }),
70
74
  });
71
75
 
72
- export const componentsStyles: StylesConfig = {
76
+ export const makeComponentsStyles = <T, U extends boolean, V extends GroupBase<T>>(): StylesConfig<T, U, V> => ({
73
77
  option: () => OptionNulledStyles,
74
78
  noOptionsMessage: (provided) => ({
75
79
  ...provided,
76
- paddingLeft: "",
77
- paddingTop: "",
78
- paddingBottom: "",
80
+ padding: 0,
79
81
  }),
80
82
  placeholder: (provided) => ({
81
83
  ...provided,
@@ -112,7 +114,7 @@ export const componentsStyles: StylesConfig = {
112
114
  alignItems: "center",
113
115
  height: layout.inputHeight - 2,
114
116
  }),
115
- control: createControlStyle({isSingleLine: false}),
117
+ control: makeControlStyle<T, U, V>({isSingleLine: false}).control,
116
118
  group: (provided) => ({
117
119
  ...provided,
118
120
  padding: 0,
@@ -150,8 +152,42 @@ export const componentsStyles: StylesConfig = {
150
152
  color: themeVars.textColor,
151
153
  };
152
154
  },
153
- };
155
+ });
156
+
157
+ export const makeSingleLineStyles = <T, U extends boolean, V extends GroupBase<T>>(): StylesConfig<T, U, V> => ({
158
+ control: makeControlStyle<T, U, V>({isSingleLine: true}).control,
159
+ });
154
160
 
155
- export const singleLineComponentsStyle: StylesConfig = {
156
- control: createControlStyle({isSingleLine: true}),
157
- };
161
+ export const makeSelectInPopoverStyles = <T, U extends boolean, V extends GroupBase<T>>(): StylesConfig<T, U, V> => ({
162
+ container: (props) => ({
163
+ ...props,
164
+ minWidth: 180,
165
+ width: "100%",
166
+ paddingTop: space.s6,
167
+ paddingInline: space.s6,
168
+ }),
169
+ option: (props) => ({
170
+ ...props,
171
+ padding: 0,
172
+ borderRadius: border.radius4,
173
+ paddingLeft: 0,
174
+ paddingRight: 0,
175
+ }),
176
+ control: (props) => ({
177
+ ...props,
178
+ maxHeight: SELECT_IN_POPOVER_VALUE_MAX_HEIGHT,
179
+ overflow: "auto",
180
+ margin: space.s2,
181
+ marginBottom: space.s4,
182
+ width: `calc(100% - ${space.s2 * 2}px)`,
183
+ borderRadius: border.radius4,
184
+ }),
185
+ menu: (props) => ({
186
+ ...props,
187
+ minWidth: 100,
188
+ position: "static",
189
+ marginBlock: 0,
190
+ boxShadow: "none !important",
191
+ borderRadius: border.radius4,
192
+ }),
193
+ });
@@ -5,6 +5,7 @@ import {useIsSupportHardwareKeyboard} from "./use-is-support-hardware-keyboard";
5
5
  export const shortcutCss = css`
6
6
  ${{
7
7
  ...textStyles.small,
8
+ ...textStyles.numeric.tabularOn,
8
9
  borderRadius: border.radius4,
9
10
  border: themeVars.shortcutBorderColor,
10
11
  color: themeVars.shortcutTextColor,
@@ -15,6 +15,8 @@ import {forwardRef, ReactNode, RefObject, useLayoutEffect, useRef} from "react";
15
15
  import {border, fontWeight, space, textStyles, themeVars} from "../design-system";
16
16
  import {ellipsis} from "../styles-utils";
17
17
  import {TooltipIfOverflown} from "../tooltip-if-overflown";
18
+ import {useCallbackRef} from "@fibery/react/src/use-callback-ref";
19
+ import {useResizeObserver} from "@fibery/react/src/use-resize-observer";
18
20
 
19
21
  const tabNavIndicatorWidth = 100;
20
22
 
@@ -124,32 +126,23 @@ export const TabNavList = forwardRef<HTMLUListElement, NavigationMenuListProps>(
124
126
  }
125
127
  );
126
128
 
127
- const useTabNavIndicator = (
128
- {
129
- active,
130
- itemRef,
131
- }: {
132
- active?: boolean;
133
- itemRef: RefObject<HTMLElement>;
134
- },
135
- deps: Array<unknown> = []
136
- ) => {
129
+ const useTabNavIndicator = ({active, itemRef}: {active?: boolean; itemRef: RefObject<HTMLElement>}) => {
137
130
  const indicatorRef = useTabNavIndicatorCtx();
138
131
 
139
- useLayoutEffect(() => {
132
+ const updateIndicator = useCallbackRef(() => {
140
133
  if (active && itemRef.current && indicatorRef.current) {
141
134
  indicatorRef.current.style.transform = `translateX(${itemRef.current.offsetLeft}px) scaleX(${
142
135
  itemRef.current.offsetWidth / tabNavIndicatorWidth
143
136
  })`;
144
137
  indicatorRef.current.classList.add(tabNavIndicatorMounted);
145
138
  }
146
- }, [
147
- active,
148
- indicatorRef,
149
- itemRef,
150
- // eslint-disable-next-line react-hooks/exhaustive-deps
151
- ...deps,
152
- ]);
139
+ });
140
+
141
+ useLayoutEffect(() => {
142
+ updateIndicator();
143
+ }, [updateIndicator, active, indicatorRef, itemRef]);
144
+
145
+ useResizeObserver(itemRef, () => updateIndicator());
153
146
  };
154
147
 
155
148
  export const TabNavItem = forwardRef<HTMLLIElement, NavigationMenuItemProps & {active?: boolean}>(
@@ -157,7 +150,7 @@ export const TabNavItem = forwardRef<HTMLLIElement, NavigationMenuItemProps & {a
157
150
  const itemRef = useRef(null);
158
151
  const ref = useComposedRefs(itemRef, forwardedRef);
159
152
 
160
- useTabNavIndicator({active, itemRef}, [children]);
153
+ useTabNavIndicator({active, itemRef});
161
154
 
162
155
  return (
163
156
  <NavigationMenuItem ref={ref} className={cx(tabNavItem, className)} {...props}>
@@ -1,6 +1,7 @@
1
1
  import invariant from "invariant";
2
2
  import {themeStyles} from "./theme-styles";
3
- import {createContext, ReactNode, useContext, useEffect, useState} from "react";
3
+ import {layoutStyles} from "./layout-styles";
4
+ import {createContext, ReactNode, useContext, useEffect, useLayoutEffect, useState} from "react";
4
5
  import {colors, getThemeColors, ThemeColors} from "./design-system";
5
6
  import {
6
7
  subscribeOnThemeMenuPreferenceChange,
@@ -86,6 +87,13 @@ export function RootThemeProvider({
86
87
  unsubscribeMenuPreference();
87
88
  };
88
89
  }, []);
90
+ useLayoutEffect(() => {
91
+ const documentElement = document.documentElement;
92
+ documentElement.classList.add(layoutStyles);
93
+ return () => {
94
+ documentElement.classList.remove(layoutStyles);
95
+ };
96
+ }, []);
89
97
  useEffect(() => {
90
98
  const darkThemeClassName = "dark-theme";
91
99
  const lightThemeAndDarkMenuClassName = "light-theme-and-dark-menu";
@@ -1,4 +1,4 @@
1
- const trimDynamicToastText = (str: string, charLimit: number) =>
1
+ export const trimDynamicToastText = (str: string, charLimit: number) =>
2
2
  str.length > charLimit ? `${str.slice(0, charLimit)}…` : str;
3
3
 
4
4
  export const toastifyItemName = ({
@@ -4,9 +4,7 @@ import {Tooltip, TooltipProps} from "./tooltip";
4
4
 
5
5
  type SetNode = (element: HTMLElement | null) => void;
6
6
 
7
- export const TooltipIfOverflown: React.FC<
8
- Omit<TooltipProps, "children"> & {children: (args: {setNode: SetNode}) => JSX.Element | null}
9
- > = ({children, ...tooltipProps}) => {
7
+ export const useTruncated = () => {
10
8
  const [truncated, setTruncated] = useState(false);
11
9
  const [node, setNode] = useState<HTMLElement | null>(null);
12
10
 
@@ -18,6 +16,14 @@ export const TooltipIfOverflown: React.FC<
18
16
  : target.scrollWidth > target.clientWidth;
19
17
  setTruncated(truncated);
20
18
  });
19
+
20
+ return {setNode, truncated};
21
+ };
22
+
23
+ export const TooltipIfOverflown: React.FC<
24
+ Omit<TooltipProps, "children"> & {children: (args: {setNode: SetNode}) => JSX.Element | null}
25
+ > = ({children, ...tooltipProps}) => {
26
+ const {truncated, setNode} = useTruncated();
21
27
  return (
22
28
  <Tooltip {...tooltipProps} disabled={!truncated}>
23
29
  {children({setNode})}
@@ -8,9 +8,10 @@ type Props = {
8
8
  height: number;
9
9
  typeObject: {title: string};
10
10
  children: ReactNode;
11
+ className?: string;
11
12
  };
12
13
 
13
- export const TypeBadgeBox = ({width, height, typeObject, children}: Props) => {
14
+ export const TypeBadgeBox = ({width, height, typeObject, children, className}: Props) => {
14
15
  const abbr = makeAbbreviation(typeObject.title);
15
16
 
16
17
  return (
@@ -33,7 +34,8 @@ export const TypeBadgeBox = ({width, height, typeObject, children}: Props) => {
33
34
  & > div {
34
35
  mask-image: linear-gradient(90deg, #000 60%, rgba(0, 0, 0, 0.4));
35
36
  }
36
- `
37
+ `,
38
+ className
37
39
  )}
38
40
  >
39
41
  {children}