@fibery/ui-kit 1.38.0 → 1.38.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/config/jest/testFrameworkSetup.js +1 -1
  3. package/package.json +16 -15
  4. package/src/abbreviate-name.ts +42 -0
  5. package/src/actions-menu/actions-menu-item.tsx +14 -5
  6. package/src/actions-menu/actions-menu-props.tsx +1 -0
  7. package/src/actions-menu/actions-menu.tsx +4 -1
  8. package/src/actions-menu/context-actions-menu.tsx +22 -0
  9. package/src/animated-height-container.tsx +24 -5
  10. package/src/antd/ant-upload.tsx +1 -1
  11. package/src/antd/input.tsx +4 -0
  12. package/src/avatar.tsx +1 -27
  13. package/src/button/base-button.tsx +2 -0
  14. package/src/button/button.tsx +3 -2
  15. package/src/button/icon-button.tsx +3 -3
  16. package/src/card-container.tsx +3 -2
  17. package/src/checkbox.tsx +17 -0
  18. package/src/collapsible-section.tsx +3 -1
  19. package/src/date-picker/autocomplete.tsx +11 -5
  20. package/src/date-picker/date-range-input.tsx +5 -1
  21. package/src/date-picker/date-range-picker-popup-content.tsx +31 -13
  22. package/src/date-picker/single-date-input.tsx +5 -1
  23. package/src/date-picker/styles.ts +20 -0
  24. package/src/design-system.ts +24 -0
  25. package/src/dropdown-menu/index.tsx +11 -1
  26. package/src/emoji-picker/emoji-picker-preview-footer.tsx +4 -0
  27. package/src/emoji-picker/emoji.tsx +4 -3
  28. package/src/emoji-picker/primitives/emoji.tsx +49 -51
  29. package/src/emoji-picker/primitives/footer.tsx +6 -0
  30. package/src/emoji-picker/primitives/search.tsx +8 -0
  31. package/src/emoji-picker/primitives/skin-tone.tsx +12 -2
  32. package/src/fibermoji-placeholder.tsx +1 -27
  33. package/src/file-item-2.tsx +408 -0
  34. package/src/file-item.tsx +63 -12
  35. package/src/header-layout.tsx +11 -0
  36. package/src/html-styles.ts +13 -4
  37. package/src/icons/ast/Back.ts +1 -1
  38. package/src/icons/ast/ExtensionFiles.ts +1 -1
  39. package/src/icons/ast/FileUpload.ts +1 -1
  40. package/src/icons/ast/SwitchToMention.ts +8 -0
  41. package/src/icons/ast/SwitchToText.ts +8 -0
  42. package/src/icons/ast/SwitchToWidget.ts +8 -0
  43. package/src/icons/ast/ViewGallery.ts +8 -0
  44. package/src/icons/ast/index.tsx +4 -0
  45. package/src/icons/react/SwitchToMention.tsx +13 -0
  46. package/src/icons/react/SwitchToText.tsx +13 -0
  47. package/src/icons/react/SwitchToWidget.tsx +13 -0
  48. package/src/icons/react/ViewGallery.tsx +13 -0
  49. package/src/icons/react/index.tsx +4 -0
  50. package/src/icons/svg/back.svg +3 -1
  51. package/src/icons/svg/extension/files.svg +3 -1
  52. package/src/icons/svg/file-upload.svg +3 -6
  53. package/src/icons/svg/switch-to-mention.svg +3 -0
  54. package/src/icons/svg/switch-to-text.svg +4 -0
  55. package/src/icons/svg/switch-to-widget.svg +4 -0
  56. package/src/icons/svg/view-gallery.svg +4 -0
  57. package/src/images-gallery/images-gallery-fall-through-provider.tsx +11 -0
  58. package/src/images-gallery/images-gallery.tsx +13 -10
  59. package/src/images-gallery/zoom.tsx +13 -2
  60. package/src/images-gallery-2/images-gallery-2.tsx +442 -0
  61. package/src/images-gallery-2/slide-buttons.tsx +230 -0
  62. package/src/images-gallery-2/zoom.tsx +35 -0
  63. package/src/kbd.tsx +46 -0
  64. package/src/modal-menu/modal-menu-item.tsx +10 -2
  65. package/src/modal-menu/modal-menu-trigger.tsx +19 -2
  66. package/src/notification-dot.tsx +16 -7
  67. package/src/platform-symbols.ts +9 -0
  68. package/src/platform.ts +2 -0
  69. package/src/popover/index.tsx +31 -8
  70. package/src/popover/modifiers.tsx +26 -19
  71. package/src/reactions/reaction-button.tsx +323 -101
  72. package/src/reactions/reaction-picker.tsx +14 -1
  73. package/src/reactions/reactions.tsx +11 -1
  74. package/src/reactions/tootltip.tsx +55 -0
  75. package/src/rich-text-embed-error.tsx +2 -1
  76. package/src/select/components/group-heading.tsx +8 -0
  77. package/src/select/components/menu-list-virtualized.tsx +6 -2
  78. package/src/select/components/option.tsx +4 -0
  79. package/src/select/select-control-settings-context.tsx +11 -2
  80. package/src/select/select-in-popover.tsx +10 -7
  81. package/src/select/styles.ts +21 -1
  82. package/src/tab-nav/tab-nav.tsx +1 -1
  83. package/src/toggle.tsx +8 -0
  84. package/src/tooltip.tsx +27 -18
  85. package/src/type-badge.tsx +5 -2
  86. package/src/unit/unit-with-tooltip.tsx +1 -1
  87. package/src/use-is-phone.tsx +27 -6
  88. package/src/shortcut-badge.tsx +0 -29
package/src/kbd.tsx ADDED
@@ -0,0 +1,46 @@
1
+ import {css, cx} from "@linaria/core";
2
+ import {border, lineHeight, space, textStyles, themeVars} from "./design-system";
3
+ import {useIsSupportHardwareKeyboard} from "./use-is-support-hardware-keyboard";
4
+
5
+ export const kbdCss = css`
6
+ ${{
7
+ ...textStyles.small,
8
+ ...textStyles.numeric.tabularOn,
9
+ }}
10
+ display: inline-flex;
11
+ align-items: center;
12
+ justify-content: center;
13
+ min-width: ${space.s18}px;
14
+ height: ${space.s18}px;
15
+ padding: ${space.s2}px;
16
+ border-radius: ${border.radius4}px;
17
+ border: ${themeVars.shortcutBorderColor};
18
+ color: ${themeVars.shortcutTextColor};
19
+ line-height: ${lineHeight.nowrap};
20
+ white-space: nowrap;
21
+ user-select: none;
22
+ `;
23
+
24
+ export const Kbd = ({className, ...props}: React.ComponentProps<"kbd">): JSX.Element | null => {
25
+ const isSupportHardwareKeyboard = useIsSupportHardwareKeyboard();
26
+ if (!isSupportHardwareKeyboard) {
27
+ return null;
28
+ }
29
+ return <kbd className={cx(kbdCss, className)} {...props} />;
30
+ };
31
+
32
+ export const KbdGroup = ({className, ...props}: React.ComponentProps<"kbd">) => {
33
+ return (
34
+ <kbd
35
+ className={cx(
36
+ className,
37
+ css`
38
+ display: flex;
39
+ align-items: center;
40
+ gap: ${space.s2}px;
41
+ `
42
+ )}
43
+ {...props}
44
+ />
45
+ );
46
+ };
@@ -4,11 +4,12 @@ import {space, textStyles} from "../design-system";
4
4
  import {useModalMenu} from "./contexts/modal-menu-context";
5
5
 
6
6
  interface ModalMenuItemProps extends Omit<ComponentProps<"div">, "onSelect"> {
7
+ disabled?: boolean;
7
8
  onSelect?: (event: Event) => void;
8
9
  children?: ReactNode;
9
10
  }
10
11
 
11
- export const ModalMenuItem = ({children, onSelect, ...otherProps}: ModalMenuItemProps) => {
12
+ export const ModalMenuItem = ({children, disabled, onSelect, ...otherProps}: ModalMenuItemProps) => {
12
13
  const {onOpenChange} = useModalMenu();
13
14
 
14
15
  return (
@@ -20,10 +21,17 @@ export const ModalMenuItem = ({children, onSelect, ...otherProps}: ModalMenuItem
20
21
  css`
21
22
  ${textStyles.big}
22
23
  padding: ${space.s10}px ${space.s16}px ${space.s10}px ${space.s16}px;
23
- `
24
+ `,
25
+ disabled &&
26
+ css`
27
+ opacity: 0.4;
28
+ `
24
29
  )}
25
30
  onClick={(event) => {
26
31
  otherProps.onClick?.(event);
32
+ if (disabled) {
33
+ return;
34
+ }
27
35
  const selectionEvent = new CustomEvent("modal-menu-select", {bubbles: true, cancelable: true});
28
36
  onSelect?.(selectionEvent);
29
37
  if (!selectionEvent.defaultPrevented) {
@@ -4,11 +4,20 @@ import {useModalMenu} from "./contexts/modal-menu-context";
4
4
 
5
5
  interface ModalMenuTriggerProps extends ComponentProps<"div"> {
6
6
  asChild?: boolean;
7
+ triggerEvent?: "click" | "context-menu";
7
8
  children: ReactHTMLElement<HTMLDivElement> | ReactNode;
8
9
  }
9
10
 
10
- export const ModalMenuTrigger = ({asChild, children, onClick, ...otherProps}: ModalMenuTriggerProps) => {
11
+ export const ModalMenuTrigger = ({
12
+ asChild,
13
+ triggerEvent,
14
+ children,
15
+ onClick,
16
+ onContextMenu,
17
+ ...otherProps
18
+ }: ModalMenuTriggerProps) => {
11
19
  const {open, onOpenChange} = useModalMenu();
20
+
12
21
  if (asChild) {
13
22
  const className = (children as ReactHTMLElement<HTMLDivElement>)?.props?.className;
14
23
  return cloneElement(children as ReactHTMLElement<HTMLDivElement>, {
@@ -16,7 +25,15 @@ export const ModalMenuTrigger = ({asChild, children, onClick, ...otherProps}: Mo
16
25
  className: cx(className, otherProps.className),
17
26
  onClick: (event) => {
18
27
  onClick?.(event);
19
- onOpenChange(!open);
28
+ if (triggerEvent === "click") {
29
+ onOpenChange(!open);
30
+ }
31
+ },
32
+ onContextMenu: (event) => {
33
+ onContextMenu?.(event);
34
+ if (triggerEvent === "context-menu") {
35
+ onOpenChange(!open);
36
+ }
20
37
  },
21
38
  });
22
39
  }
@@ -10,14 +10,23 @@ const activityIndicatorStyle = css`
10
10
  }}
11
11
  `;
12
12
 
13
- export const NotificationDot = ({big = true, color = themeVars.active}: {big: boolean; color: string}) => {
13
+ type PropsType = {
14
+ big?: boolean;
15
+ color?: string;
16
+ style?: Record<string, string | number | null>;
17
+ };
18
+
19
+ export const NotificationDot = ({big = true, color = themeVars.active, style}: PropsType) => {
14
20
  const size = big ? space.s6 : space.s4;
15
21
  const marginTop = big ? -6 : -1;
16
22
  const marginRight = big ? -1 : 0;
17
- return (
18
- <div
19
- className={activityIndicatorStyle}
20
- style={{backgroundColor: color, width: size, height: size, marginTop, marginRight}}
21
- />
22
- );
23
+ const styleObject = {
24
+ backgroundColor: color,
25
+ width: size,
26
+ height: size,
27
+ marginTop,
28
+ marginRight,
29
+ ...style,
30
+ };
31
+ return <div className={activityIndicatorStyle} style={styleObject} />;
23
32
  };
@@ -0,0 +1,9 @@
1
+ import {isMac} from "./platform";
2
+
3
+ export const ctrlSymbol = isMac ? "⌘" : "Ctrl";
4
+ export const explicitCtrlSymbol = isMac ? "⌃" : "Ctrl";
5
+ export const winSymbol = isMac ? "⌘" : "Win";
6
+ export const shiftSymbol = isMac ? "⇧" : "⇧";
7
+ export const altSymbol = isMac ? "⌥" : "Alt";
8
+ export const deleteSymbol = isMac ? "⌫" : "Delete";
9
+ export const enterSymbol = isMac ? "↵" : "↵";
package/src/platform.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  import {UAParser} from "ua-parser-js";
2
2
 
3
3
  export const isMac = navigator.platform.startsWith("Mac");
4
+ export const isWindows = navigator.platform.startsWith("Win");
5
+ export const isLinux = navigator.platform.startsWith("Linux");
4
6
  export const isMobile = new UAParser(navigator.userAgent).getDevice().type === "mobile";
@@ -36,7 +36,7 @@ import {useTheme} from "../theme-provider";
36
36
  import {$TSFixMe} from "../tsfixme";
37
37
  import {useIsPhone} from "../use-is-phone";
38
38
  import {usePopupModifiers} from "./popup-modifiers-context";
39
- import {getMaxSize, observeWidth} from "./modifiers";
39
+ import {applyMaxSize, makeMaxSizeModifier, observeWidth} from "./modifiers";
40
40
  import {isElementReference, Reference} from "./reference";
41
41
  import {basicPopupClassName, basicPopupContainerClassName, hidePopupWhenTriggerIsHiddenClassName} from "./styles";
42
42
  import {MobilePopupProvider, useMobilePopup} from "./mobile-popup-context";
@@ -249,13 +249,13 @@ const Trigger = ({asChild = false, reference, children}: TriggerProps) => {
249
249
  }
250
250
  }, [reference, setTriggerElement]);
251
251
 
252
- if (reference) {
252
+ // Reference is passed
253
+ if (reference !== undefined) {
253
254
  return null;
254
255
  }
255
256
 
256
257
  if (asChild && isValidElement(children)) {
257
258
  return cloneElement(children, {
258
- // @ts-expect-error: React.cloneElement typing does not include `ref`, but it's valid at runtime
259
259
  ref: setTriggerElement,
260
260
  "aria-expanded": open,
261
261
  "aria-haspopup": true,
@@ -307,6 +307,8 @@ type ContentProps = {
307
307
 
308
308
  export type ContentRef = {update: (() => Promise<unknown>) | null};
309
309
 
310
+ const padding = space.s8;
311
+
310
312
  const Content = forwardRef<ContentRef, ContentProps>(function PopoverContentInner(
311
313
  {
312
314
  children,
@@ -341,23 +343,44 @@ const Content = forwardRef<ContentRef, ContentProps>(function PopoverContentInne
341
343
 
342
344
  // We get infinite popup renders if this is not in a separate memo
343
345
  const shrinkableModifiers = useMemo(() => {
344
- return shrinkable ? getMaxSize(preventOverflowOptions) : [];
346
+ return shrinkable
347
+ ? [
348
+ makeMaxSizeModifier({
349
+ padding,
350
+ ...preventOverflowOptions,
351
+ }),
352
+ applyMaxSize,
353
+ ]
354
+ : [];
345
355
  }, [preventOverflowOptions, shrinkable]);
346
356
 
347
357
  const modifiers = useMemo(() => {
348
358
  return _.compact([
349
- {name: "flip", options: {...popupModifiers.flipOptions, ...flipOptions}},
359
+ {
360
+ name: "flip",
361
+ options: {
362
+ padding,
363
+ ...popupModifiers.flipOptions,
364
+ ...flipOptions,
365
+ },
366
+ },
350
367
  {
351
368
  name: "preventOverflow",
352
369
  options: {
353
370
  tether: false,
354
- padding: space.s6,
371
+ padding,
355
372
  ...popupModifiers.preventOverflowOptions,
356
373
  ...preventOverflowOptions,
357
374
  },
358
375
  },
359
- {name: "offset", options: {offset: offset}},
360
- !transform && {name: "computeStyles", options: {gpuAcceleration: false}},
376
+ {
377
+ name: "offset",
378
+ options: {offset},
379
+ },
380
+ !transform && {
381
+ name: "computeStyles",
382
+ options: {gpuAcceleration: false},
383
+ },
361
384
  observeWidth,
362
385
  ...shrinkableModifiers,
363
386
  ...additionalModifiers,
@@ -1,30 +1,37 @@
1
1
  import {Options as PreventOverflowOptions} from "@popperjs/core/lib/modifiers/preventOverflow";
2
- import {$TSFixMe} from "../tsfixme";
3
- import {Modifier, ModifierArguments} from "@popperjs/core";
2
+ import {Modifier, ModifierArguments, Placement, Boundary, RootBoundary, Padding, Context} from "@popperjs/core";
4
3
  import maxSize from "popper-max-size-modifier";
5
4
  import {getResizeListener} from "@fibery/helpers/utils/resize-listener";
6
5
  import {isElementReference} from "./reference";
7
6
  import _ from "lodash";
8
7
 
9
- type PopupModifier = Modifier<$TSFixMe, $TSFixMe>;
8
+ type MaxSizeOptions = {
9
+ placement: Placement;
10
+ boundary: Boundary;
11
+ rootBoundary: RootBoundary;
12
+ elementContext: Context;
13
+ altBoundary: boolean;
14
+ padding: Padding;
15
+ };
10
16
 
11
- export const getMaxSize = (overflowOptions: Partial<PreventOverflowOptions>): PopupModifier[] => [
12
- {
17
+ export const makeMaxSizeModifier = (options: Partial<PreventOverflowOptions>): Modifier<"maxSize", MaxSizeOptions> => {
18
+ return {
13
19
  ...maxSize,
14
- options: overflowOptions,
15
- },
16
- {
17
- name: "applyMaxSize",
18
- enabled: true,
19
- phase: "beforeWrite",
20
- requires: ["maxSize"],
21
- fn({state}) {
22
- const {width, height} = state.modifiersData.maxSize;
23
- state.styles.popper.maxWidth = `${width}px`;
24
- state.styles.popper.maxHeight = `${height}px`;
25
- },
20
+ options,
21
+ };
22
+ };
23
+
24
+ export const applyMaxSize: Modifier<"applyMaxSize", Record<string, never>> = {
25
+ name: "applyMaxSize",
26
+ enabled: true,
27
+ phase: "beforeWrite",
28
+ requires: ["maxSize"],
29
+ fn({state}) {
30
+ const {width, height} = state.modifiersData.maxSize;
31
+ state.styles.popper.maxWidth = `${width}px`;
32
+ state.styles.popper.maxHeight = `${height}px`;
26
33
  },
27
- ];
34
+ };
28
35
 
29
36
  const observeWidthEffect: (arg0: ModifierArguments<Record<string, unknown>>) => void = ({state, instance}) => {
30
37
  const {popper, reference} = state.elements;
@@ -54,7 +61,7 @@ const observeWidthEffect: (arg0: ModifierArguments<Record<string, unknown>>) =>
54
61
  };
55
62
  };
56
63
 
57
- export const observeWidth: PopupModifier = {
64
+ export const observeWidth: Modifier<"observeWidth", Record<string, never>> = {
58
65
  name: "observeWidth",
59
66
  enabled: true,
60
67
  phase: "main",