@fibery/ui-kit 1.36.2 → 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 (186) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/package.json +1 -1
  3. package/src/action-badge.tsx +5 -4
  4. package/src/actions-menu/actions-menu-confirmation.tsx +1 -12
  5. package/src/actions-menu/actions-menu-item.tsx +1 -1
  6. package/src/antd/ant-modal.tsx +17 -2
  7. package/src/antd/input.tsx +4 -3
  8. package/src/app-icon-with-fallback.tsx +5 -8
  9. package/src/app-icon-wrapper.tsx +4 -4
  10. package/src/appIcons.json +20 -0
  11. package/src/badge.tsx +14 -7
  12. package/src/beta-badge.tsx +12 -8
  13. package/src/button/actions-button-compact.tsx +1 -1
  14. package/src/button/base-button.tsx +2 -1
  15. package/src/button/button.tsx +89 -2
  16. package/src/button/icon-button.tsx +4 -2
  17. package/src/button/select-button.tsx +23 -8
  18. package/src/card-container.tsx +29 -65
  19. package/src/card-hidden-link.tsx +52 -0
  20. package/src/collapsible-section.tsx +13 -3
  21. package/src/color-picker/index.js +65 -60
  22. package/src/color-picker/swatch.tsx +28 -14
  23. package/src/command-menu/index.tsx +2 -2
  24. package/src/count-badge.tsx +57 -0
  25. package/src/date-picker/date-range-input.tsx +1 -1
  26. package/src/date-picker/fake-date-input.tsx +1 -1
  27. package/src/date-picker/relative-date-picker.tsx +1 -1
  28. package/src/date-picker/single-date-input.tsx +1 -1
  29. package/src/date-picker/utils.ts +9 -2
  30. package/src/design-system.ts +72 -41
  31. package/src/emoji-picker/emoji-picker-content-with-color.tsx +3 -9
  32. package/src/emoji-picker/icon-emoji-picker.tsx +75 -69
  33. package/src/emoji-picker/primitives/header.tsx +1 -0
  34. package/src/emoji-picker/primitives/search.tsx +12 -13
  35. package/src/error-alert/error-alert.tsx +19 -7
  36. package/src/field-app-icon.tsx +29 -0
  37. package/src/field-container.tsx +4 -2
  38. package/src/field-icon.tsx +26 -0
  39. package/src/field-type-icon.tsx +82 -0
  40. package/src/guide-link.tsx +4 -3
  41. package/src/hint.tsx +10 -1
  42. package/src/html-styles.ts +15 -13
  43. package/src/icons/ast/AiFiberyBuild.ts +8 -0
  44. package/src/icons/ast/Anthropic.ts +1 -1
  45. package/src/icons/ast/Apple.ts +8 -0
  46. package/src/icons/ast/ArrowBottom.ts +1 -1
  47. package/src/icons/ast/ArrowForward.ts +1 -1
  48. package/src/icons/ast/ArrowLeft.ts +1 -1
  49. package/src/icons/ast/ArrowRight.ts +1 -1
  50. package/src/icons/ast/ArrowTop.ts +1 -1
  51. package/src/icons/ast/Crosshair.ts +8 -0
  52. package/src/icons/ast/Document.ts +8 -0
  53. package/src/icons/ast/EntityCreate.ts +8 -0
  54. package/src/icons/ast/ExpandAll.ts +8 -0
  55. package/src/icons/ast/FiberyDesktopApp.ts +8 -0
  56. package/src/icons/ast/FileDownload.ts +8 -0
  57. package/src/icons/ast/GraduationCapFilled.ts +8 -0
  58. package/src/icons/ast/Home.ts +1 -1
  59. package/src/icons/ast/ImportFilled.ts +8 -0
  60. package/src/icons/ast/IntegrationsFilled.ts +8 -0
  61. package/src/icons/ast/LocationEdit.ts +8 -0
  62. package/src/icons/ast/MessagePlus.ts +8 -0
  63. package/src/icons/ast/OpenAi.ts +1 -1
  64. package/src/icons/ast/RicheditorMarkHighlight.ts +8 -0
  65. package/src/icons/ast/RicheditorMarkStrike.ts +1 -1
  66. package/src/icons/ast/RicheditorMarkUnderline.ts +1 -1
  67. package/src/icons/ast/SpaceApp.ts +8 -0
  68. package/src/icons/ast/SpaceGenerate.ts +8 -0
  69. package/src/icons/ast/SpaceScratch.ts +8 -0
  70. package/src/icons/ast/SpaceTemplate.ts +8 -0
  71. package/src/icons/ast/TableLayout.ts +8 -0
  72. package/src/icons/ast/TemplatesFilled.ts +8 -0
  73. package/src/icons/ast/ThumbsDown.ts +8 -0
  74. package/src/icons/ast/ThumbsUp.ts +8 -0
  75. package/src/icons/ast/ViewDashboard.ts +8 -0
  76. package/src/icons/ast/WarningTriangleFilled.ts +8 -0
  77. package/src/icons/ast/Windows.ts +8 -0
  78. package/src/icons/ast/index.tsx +25 -0
  79. package/src/icons/react/AiFiberyBuild.tsx +13 -0
  80. package/src/icons/react/Apple.tsx +13 -0
  81. package/src/icons/react/Crosshair.tsx +13 -0
  82. package/src/icons/react/Document.tsx +13 -0
  83. package/src/icons/react/EntityCreate.tsx +13 -0
  84. package/src/icons/react/ExpandAll.tsx +13 -0
  85. package/src/icons/react/FiberyDesktopApp.tsx +13 -0
  86. package/src/icons/react/FileDownload.tsx +13 -0
  87. package/src/icons/react/GraduationCapFilled.tsx +13 -0
  88. package/src/icons/react/ImportFilled.tsx +13 -0
  89. package/src/icons/react/IntegrationsFilled.tsx +13 -0
  90. package/src/icons/react/LocationEdit.tsx +13 -0
  91. package/src/icons/react/MessagePlus.tsx +13 -0
  92. package/src/icons/react/RicheditorMarkHighlight.tsx +13 -0
  93. package/src/icons/react/SpaceApp.tsx +13 -0
  94. package/src/icons/react/SpaceGenerate.tsx +13 -0
  95. package/src/icons/react/SpaceScratch.tsx +13 -0
  96. package/src/icons/react/SpaceTemplate.tsx +13 -0
  97. package/src/icons/react/TableLayout.tsx +13 -0
  98. package/src/icons/react/TemplatesFilled.tsx +13 -0
  99. package/src/icons/react/ThumbsDown.tsx +13 -0
  100. package/src/icons/react/ThumbsUp.tsx +13 -0
  101. package/src/icons/react/ViewDashboard.tsx +13 -0
  102. package/src/icons/react/WarningTriangleFilled.tsx +13 -0
  103. package/src/icons/react/Windows.tsx +13 -0
  104. package/src/icons/react/index.tsx +25 -0
  105. package/src/icons/svg/ai-fibery-build.svg +24 -0
  106. package/src/icons/svg/anthropic.svg +2 -14
  107. package/src/icons/svg/apple.svg +4 -0
  108. package/src/icons/svg/arrow-bottom.svg +1 -1
  109. package/src/icons/svg/arrow-forward.svg +1 -1
  110. package/src/icons/svg/arrow-left.svg +1 -1
  111. package/src/icons/svg/arrow-right.svg +1 -1
  112. package/src/icons/svg/arrow-top.svg +1 -1
  113. package/src/icons/svg/crosshair.svg +4 -0
  114. package/src/icons/svg/document.svg +4 -0
  115. package/src/icons/svg/entity-create.svg +3 -0
  116. package/src/icons/svg/expand-all.svg +3 -0
  117. package/src/icons/svg/fibery-desktop-app.svg +101 -0
  118. package/src/icons/svg/file-download.svg +4 -0
  119. package/src/icons/svg/go-to.svg +1 -3
  120. package/src/icons/svg/graduation-cap-filled.svg +4 -0
  121. package/src/icons/svg/home.svg +4 -2
  122. package/src/icons/svg/import-filled.svg +4 -0
  123. package/src/icons/svg/integrations-filled.svg +4 -0
  124. package/src/icons/svg/location-edit.svg +13 -0
  125. package/src/icons/svg/message-plus.svg +4 -0
  126. package/src/icons/svg/open-ai.svg +2 -7
  127. package/src/icons/svg/open-as-page.svg +2 -3
  128. package/src/icons/svg/richeditor/mark/code.svg +4 -5
  129. package/src/icons/svg/richeditor/mark/em.svg +3 -2
  130. package/src/icons/svg/richeditor/mark/highlight.svg +3 -0
  131. package/src/icons/svg/richeditor/mark/strike.svg +3 -2
  132. package/src/icons/svg/richeditor/mark/strong.svg +3 -2
  133. package/src/icons/svg/richeditor/mark/underline.svg +4 -2
  134. package/src/icons/svg/space-app.svg +3 -0
  135. package/src/icons/svg/space-generate.svg +3 -0
  136. package/src/icons/svg/space-scratch.svg +3 -0
  137. package/src/icons/svg/space-template.svg +3 -0
  138. package/src/icons/svg/table-layout.svg +3 -0
  139. package/src/icons/svg/templates-filled.svg +6 -0
  140. package/src/icons/svg/thumbs-down.svg +3 -0
  141. package/src/icons/svg/thumbs-up.svg +3 -0
  142. package/src/icons/svg/view-dashboard.svg +5 -0
  143. package/src/icons/svg/warning-triangle-filled.svg +3 -0
  144. package/src/icons/svg/windows.svg +15 -0
  145. package/src/integration-compact-info-button.tsx +3 -1
  146. package/src/layout-styles.ts +23 -0
  147. package/src/lists/list-row-surface.tsx +2 -1
  148. package/src/loaders.tsx +6 -6
  149. package/src/logo.tsx +16 -9
  150. package/src/mobile-styles.ts +2 -0
  151. package/src/new-badge.tsx +4 -7
  152. package/src/number-input/text-area-auto-sized.tsx +47 -0
  153. package/src/number-input/text-input-auto-sized.tsx +49 -0
  154. package/src/palette.ts +50 -50
  155. package/src/popup/index.tsx +1 -0
  156. package/src/rich-text-embed-error.tsx +2 -2
  157. package/src/select/{custom-select-partials → components}/menu.tsx +13 -7
  158. package/src/select/{custom-select-partials → components}/no-option-message.tsx +0 -1
  159. package/src/select/constants.ts +1 -0
  160. package/src/select/index.tsx +136 -145
  161. package/src/select/select-in-popover.tsx +101 -108
  162. package/src/select/styles.ts +60 -24
  163. package/src/shortcut-badge.tsx +1 -0
  164. package/src/tab-nav/tab-nav.tsx +12 -19
  165. package/src/theme-provider.tsx +9 -1
  166. package/src/tooltip-if-overflown.tsx +9 -3
  167. package/src/unit/index.tsx +9 -1
  168. package/src/unit/loading-unit-value.tsx +1 -0
  169. package/src/unit/maybe-unit-value.tsx +3 -3
  170. package/src/unit/primitive.tsx +58 -42
  171. package/src/unit/styles.ts +8 -12
  172. package/src/unit/types.ts +4 -2
  173. package/src/unit/unit-button-group.tsx +6 -11
  174. package/src/unit/unit-content.tsx +13 -5
  175. package/src/unit/unit-with-title.tsx +6 -1
  176. package/src/unit/unit-with-tooltip.tsx +24 -9
  177. package/src/use-is-phone.tsx +12 -0
  178. package/src/workflow-progress-icon.tsx +1 -1
  179. package/src/number-input/text-area-with-autosize.tsx +0 -91
  180. package/src/number-input/text-inline-input-with-autosize.tsx +0 -60
  181. package/src/use-is-phone.ts +0 -5
  182. /package/src/select/{custom-select-partials → components}/clear-indicator.tsx +0 -0
  183. /package/src/select/{custom-select-partials → components}/drop-down-indicator.tsx +0 -0
  184. /package/src/select/{custom-select-partials → components}/group-heading.tsx +0 -0
  185. /package/src/select/{custom-select-partials → components}/menu-list-virtualized.tsx +0 -0
  186. /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,53 +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;
128
95
  iconStart?: ReactNode;
129
96
  pending?: boolean;
97
+ pressed?: boolean;
98
+ menuOpened?: boolean;
130
99
  onKeyDown?: React.KeyboardEventHandler;
131
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;
132
108
  };
133
109
 
134
- const Trigger = ({innerRef, children, onClick, onKeyDown}: TriggerProps) => {
110
+ const TriggerDefault = ({innerRef, children, onClick, onKeyDown}: TriggerProps) => {
135
111
  return (
136
112
  <div ref={innerRef} onClick={onClick} onKeyDown={onKeyDown} tabIndex={0} className={valueClassName}>
137
113
  {children}
@@ -139,59 +115,54 @@ const Trigger = ({innerRef, children, onClick, onKeyDown}: TriggerProps) => {
139
115
  );
140
116
  };
141
117
 
142
- type Components = {
143
- Trigger: ComponentType<TriggerProps>;
144
- 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>;
145
120
  };
146
121
 
147
- export type ComponentsConfig = Partial<Components>;
148
-
149
- const defaultComponents = {Trigger, Menu};
150
-
151
- type Ref = {
122
+ type SelectInPopoverRef<T, U extends boolean, V extends GroupBase<T>> = {
152
123
  valueRef: HTMLDivElement | null;
153
- selectRef: $TSFixMe | null;
124
+ selectRef: SelectInstance<T, U, V> | null;
154
125
  };
155
126
 
156
- type Props<Option, IsMulti extends boolean, Group extends GroupBase<Option>> = {
157
- value?: PropsValue<Option>;
127
+ type Props<T, U extends boolean, V extends GroupBase<T>> = {
128
+ value?: PropsValue<T>;
158
129
  menuIsOpen?: boolean;
159
130
  autoFocus?: boolean;
160
131
  virtualized?: boolean;
161
132
  defaultMenuIsOpen?: boolean;
162
133
  placeholder?: string;
163
134
  noOptionsMessage?: () => string | JSX.Element | null;
164
- options: OptionsOrGroups<Option, Group>;
165
- filterOption?: SelectProps<Option>["filterOption"];
135
+ options: OptionsOrGroups<T, V>;
136
+ filterOption?: SelectProps<T, U, V>["filterOption"];
166
137
  inputValue?: string;
167
138
  disabled?: boolean;
168
- isCollectionMode?: IsMulti;
139
+ isCollectionMode?: U;
169
140
  isClearable?: boolean;
170
141
  renderValue?: () => ReactNode;
171
142
  title?: string;
172
143
  maxMenuHeight?: number;
173
- hideOnChange?: boolean | ((newValue: OnChangeValue<Option, IsMulti>, actionMeta: ActionMeta<Option>) => boolean);
144
+ hideOnChange?: boolean | ((newValue: OnChangeValue<T, U>, actionMeta: ActionMeta<T>) => boolean);
174
145
  renderInPortal?: boolean;
175
146
  popupStyles?: string;
176
- selectStyles?: StylesConfig<Option, IsMulti, Group>;
177
- formatGroupLabel?: (group: Group) => ReactNode;
178
- formatOptionLabel?: (option: Option, {context}: {context: "menu" | "value"}) => ReactNode;
179
- 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>;
180
151
  onInputChange?: (s: string, actionType: {action: string}) => void;
181
152
  onFocus?: () => void;
182
- onChange: (newValue: OnChangeValue<Option, IsMulti>, actionMeta: ActionMeta<Option>) => void;
153
+ onChange: (newValue: OnChangeValue<T, U>, actionMeta: ActionMeta<T>) => void;
183
154
  onMenuOpen?: () => void;
184
155
  onMenuClose?: () => void | boolean;
185
156
  getPopupContainer?: () => HTMLElement;
186
157
  onSelectKeyDown?: React.KeyboardEventHandler<HTMLDivElement>;
187
158
  forbidValuesClearInCollnMode?: boolean;
188
159
  otherSelectProps?: Record<string, unknown>;
189
- isOptionDisabled?: (option: Option) => boolean;
160
+ isOptionDisabled?: (option: T) => boolean;
190
161
  };
191
162
 
192
- function SelectInPopoverInner<Option, IsMulti extends boolean, Group extends GroupBase<Option>>(
193
- props: Omit<Props<Option, IsMulti, Group>, "maxMenuHeight">,
194
- 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>>
195
166
  ) {
196
167
  const {
197
168
  value,
@@ -236,7 +207,7 @@ function SelectInPopoverInner<Option, IsMulti extends boolean, Group extends Gro
236
207
  },
237
208
  });
238
209
  const blurTimeoutRef = useRef<ReturnType<typeof setTimeout>>();
239
- const selectRef = useRef<{focus: () => void}>(null);
210
+ const selectRef = useRef<SelectInstance<T, U, V>>(null);
240
211
  const ref = useRef<HTMLDivElement | null>(null);
241
212
 
242
213
  useImperativeHandle(
@@ -245,11 +216,13 @@ function SelectInPopoverInner<Option, IsMulti extends boolean, Group extends Gro
245
216
  ({
246
217
  valueRef: ref.current,
247
218
  selectRef: selectRef.current,
248
- } as {valueRef: HTMLDivElement; selectRef: $TSFixMe | null})
219
+ } as {valueRef: HTMLDivElement; selectRef: SelectInstance<T, U, V> | null})
249
220
  );
221
+
250
222
  useEffect(() => {
251
223
  setTriggerElement(ref.current);
252
224
  }, []);
225
+
253
226
  useEffect(() => {
254
227
  if (blurTimeoutRef.current) {
255
228
  clearTimeout(blurTimeoutRef.current);
@@ -301,7 +274,7 @@ function SelectInPopoverInner<Option, IsMulti extends boolean, Group extends Gro
301
274
  }, [disabled, onMenuOpen, setVisible]);
302
275
 
303
276
  const styles = useMemo(() => {
304
- return combineStyles<Option, IsMulti, Group>([selectInPopupStyles, selectStyles]);
277
+ return combineStyles<T, U, V>([makeSelectInPopoverStyles(), selectStyles]);
305
278
  }, [selectStyles]);
306
279
 
307
280
  const onTriggerClick: React.MouseEventHandler = useCallback(
@@ -326,27 +299,74 @@ function SelectInPopoverInner<Option, IsMulti extends boolean, Group extends Gro
326
299
  },
327
300
  [onShow, visible]
328
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
+
329
340
  const paddingPopup = popupPaddingTop + popupPaddingBottom;
330
341
  const paddingMenu = 6 + 6 + 6;
331
- const isPhone = useIsPhone();
342
+
332
343
  const maxMenuHeight = isPhone
333
- ? document.body.clientHeight - 45 - valueMaxHeight
344
+ ? document.body.clientHeight - 45 - SELECT_IN_POPOVER_VALUE_MAX_HEIGHT
334
345
  : Math.max((document.body.clientHeight / 100) * popupHeightVH, popupMinHeightPx) -
335
- valueMaxHeight -
346
+ SELECT_IN_POPOVER_VALUE_MAX_HEIGHT -
336
347
  paddingPopup -
337
348
  paddingMenu;
338
- 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
+ };
339
357
 
340
358
  return (
341
359
  <>
342
- <mergedComponents.Trigger
360
+ <Trigger
343
361
  innerRef={ref}
362
+ menuOpened={visible}
363
+ disabled={disabled}
364
+ valueSelected={Boolean(value)}
344
365
  onClick={onTriggerClick}
345
366
  onKeyDown={onTriggerKeyDown}
346
- disabled={disabled}
347
367
  >
348
368
  {renderValue ? renderValue() : null}
349
- </mergedComponents.Trigger>
369
+ </Trigger>
350
370
  {Boolean(triggerElement) && (
351
371
  <Popup
352
372
  supportMobile
@@ -369,42 +389,19 @@ function SelectInPopoverInner<Option, IsMulti extends boolean, Group extends Gro
369
389
  {/*Render target in controlled by Popover here. So we just override SelectControlContext here and set popupContainerElement to undefined. */}
370
390
  {/*So in dom react-select will be a child of popover. */}
371
391
  <SelectControlSettingsProvider getPopupContainerElement={undefined}>
372
- <ReactSelect
392
+ <ReactSelect<T, U, V>
373
393
  ref={selectRef}
374
394
  styles={styles}
375
395
  isSearchable={true}
376
- onKeyDown={(event) => {
377
- if ((event.key === "Escape" || event.key === "Tab") && visible) {
378
- onHide();
379
- event.preventDefault();
380
- event.stopPropagation();
381
- }
382
- onSelectKeyDown?.(event);
383
- }}
396
+ onKeyDown={onKeyDown}
384
397
  autoFocus={autoFocus}
385
- onBlur={() => {
386
- if (isPhone) {
387
- return;
388
- }
389
- blurTimeoutRef.current = setTimeout(() => {
390
- onHide(false);
391
- }, 250);
392
- }}
398
+ onBlur={onBlur}
393
399
  value={value}
394
400
  defaultMenuIsOpen={defaultMenuIsOpen}
395
401
  controlShouldRenderValue
396
402
  closeMenuOnScroll={false}
397
403
  closeMenuOnSelect={false}
398
- onChange={(newValue, actionMeta) => {
399
- if (typeof hideOnChange === "function") {
400
- if (hideOnChange(newValue, actionMeta)) {
401
- onHide();
402
- }
403
- } else if (hideOnChange) {
404
- onHide();
405
- }
406
- onChange(newValue, actionMeta);
407
- }}
404
+ onChange={handleChange}
408
405
  placeholder={placeholder}
409
406
  onInputChange={onInputChange}
410
407
  noOptionsMessage={noOptionsMessage}
@@ -421,11 +418,7 @@ function SelectInPopoverInner<Option, IsMulti extends boolean, Group extends Gro
421
418
  formatGroupLabel={formatGroupLabel}
422
419
  formatOptionLabel={formatOptionLabel}
423
420
  {...otherSelectProps}
424
- components={{
425
- DropdownIndicator: null,
426
- IndicatorSeparator: null,
427
- Menu: mergedComponents.Menu as $TSFixMe,
428
- }}
421
+ components={selectComponents}
429
422
  forbidValuesClearInCollnMode={forbidValuesClearInCollnMode}
430
423
  isOptionDisabled={isOptionDisabled}
431
424
  />
@@ -436,8 +429,8 @@ function SelectInPopoverInner<Option, IsMulti extends boolean, Group extends Gro
436
429
  );
437
430
  }
438
431
 
439
- type SelectInPopoverType = <Option, IsMulti extends boolean, Group extends GroupBase<Option>>(
440
- 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>>}
441
434
  ) => ReturnType<typeof SelectInPopoverInner>;
442
435
 
443
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";
@@ -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})}
@@ -51,5 +51,13 @@ export const OptionUnit = (props: UnitPrimitiveProps) => {
51
51
  };
52
52
 
53
53
  export const HistoryUnit = (props: UnitPrimitiveProps & {size: CardSize}) => {
54
- return <UnitPrimitive big={props.size === ":card-size/cell"} bgColor={themeVars.unitBg} border={false} {...props} />;
54
+ return (
55
+ <UnitPrimitive
56
+ big={props.size === ":card-size/cell"}
57
+ bgColor={themeVars.unitBg}
58
+ border={false}
59
+ tooltip={false}
60
+ {...props}
61
+ />
62
+ );
55
63
  };
@@ -2,6 +2,7 @@ import {css} from "@linaria/core";
2
2
  import {LoadingSausage, LoadingSausageProps} from "../loading-sausage";
3
3
 
4
4
  export const unitTextHeight = 8;
5
+
5
6
  export const LoadingUnitValue = (props: LoadingSausageProps) => (
6
7
  <div
7
8
  className={css`
@@ -1,9 +1,9 @@
1
1
  import {LoadingUnitValue} from "./loading-unit-value";
2
2
 
3
- interface MaybeUnitValueProps {
3
+ type Props = {
4
4
  value?: string;
5
- }
5
+ };
6
6
 
7
- export const MaybeUnitValue: React.FC<MaybeUnitValueProps> = ({value}) => {
7
+ export const MaybeUnitValue: React.FC<Props> = ({value}) => {
8
8
  return value === undefined ? <LoadingUnitValue minWidth={18} maxWidth={18} /> : <>{value}</>;
9
9
  };