@fibery/ui-kit 1.38.0 → 1.38.2

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 (111) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/config/jest/testFrameworkSetup.js +1 -1
  3. package/package.json +23 -22
  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 +4 -4
  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/index.tsx +4 -2
  19. package/src/collapsible-section.tsx +3 -1
  20. package/src/date-picker/autocomplete.tsx +11 -5
  21. package/src/date-picker/date-range-input.tsx +5 -1
  22. package/src/date-picker/date-range-picker-popup-content.tsx +31 -13
  23. package/src/date-picker/single-date-input.tsx +5 -1
  24. package/src/date-picker/styles.ts +20 -0
  25. package/src/design-system.ts +26 -1
  26. package/src/dropdown-menu/index.tsx +11 -1
  27. package/src/emoji-picker/emoji-picker-preview-footer.tsx +4 -0
  28. package/src/emoji-picker/emoji.tsx +4 -3
  29. package/src/emoji-picker/primitives/emoji.tsx +49 -51
  30. package/src/emoji-picker/primitives/footer.tsx +6 -0
  31. package/src/emoji-picker/primitives/search.tsx +8 -0
  32. package/src/emoji-picker/primitives/skin-tone.tsx +12 -2
  33. package/src/fibermoji-placeholder.tsx +2 -29
  34. package/src/file-item-2.tsx +566 -0
  35. package/src/file-item.tsx +196 -162
  36. package/src/header-layout.tsx +11 -0
  37. package/src/html-styles.ts +13 -4
  38. package/src/icons/ast/Back.ts +1 -1
  39. package/src/icons/ast/ExtensionFiles.ts +1 -1
  40. package/src/icons/ast/FileArchive.ts +8 -0
  41. package/src/icons/ast/FileBroken.ts +8 -0
  42. package/src/icons/ast/FileDocument.ts +8 -0
  43. package/src/icons/ast/FileImage.ts +8 -0
  44. package/src/icons/ast/FilePresentation.ts +8 -0
  45. package/src/icons/ast/FileTable.ts +8 -0
  46. package/src/icons/ast/FileUpload.ts +1 -1
  47. package/src/icons/ast/FileVideo.ts +8 -0
  48. package/src/icons/ast/SwitchToMention.ts +8 -0
  49. package/src/icons/ast/SwitchToText.ts +8 -0
  50. package/src/icons/ast/SwitchToWidget.ts +8 -0
  51. package/src/icons/ast/ViewGallery.ts +8 -0
  52. package/src/icons/ast/index.tsx +11 -0
  53. package/src/icons/react/FileArchive.tsx +13 -0
  54. package/src/icons/react/FileBroken.tsx +13 -0
  55. package/src/icons/react/FileDocument.tsx +13 -0
  56. package/src/icons/react/FileImage.tsx +13 -0
  57. package/src/icons/react/FilePresentation.tsx +13 -0
  58. package/src/icons/react/FileTable.tsx +13 -0
  59. package/src/icons/react/FileVideo.tsx +13 -0
  60. package/src/icons/react/SwitchToMention.tsx +13 -0
  61. package/src/icons/react/SwitchToText.tsx +13 -0
  62. package/src/icons/react/SwitchToWidget.tsx +13 -0
  63. package/src/icons/react/ViewGallery.tsx +13 -0
  64. package/src/icons/react/index.tsx +11 -0
  65. package/src/icons/svg/back.svg +3 -1
  66. package/src/icons/svg/extension/files.svg +3 -1
  67. package/src/icons/svg/file-archive.svg +3 -0
  68. package/src/icons/svg/file-broken.svg +3 -0
  69. package/src/icons/svg/file-document.svg +3 -0
  70. package/src/icons/svg/file-image.svg +3 -0
  71. package/src/icons/svg/file-presentation.svg +3 -0
  72. package/src/icons/svg/file-table.svg +3 -0
  73. package/src/icons/svg/file-upload.svg +3 -6
  74. package/src/icons/svg/file-video.svg +3 -0
  75. package/src/icons/svg/switch-to-mention.svg +3 -0
  76. package/src/icons/svg/switch-to-text.svg +4 -0
  77. package/src/icons/svg/switch-to-widget.svg +4 -0
  78. package/src/icons/svg/view-gallery.svg +4 -0
  79. package/src/images-gallery/images-gallery-fall-through-provider.tsx +11 -0
  80. package/src/images-gallery/images-gallery.tsx +13 -10
  81. package/src/images-gallery/zoom.tsx +13 -2
  82. package/src/images-gallery-2/images-gallery-2.tsx +522 -0
  83. package/src/images-gallery-2/slide-buttons.tsx +271 -0
  84. package/src/images-gallery-2/zoom.tsx +35 -0
  85. package/src/kbd.tsx +46 -0
  86. package/src/loading-sausage.tsx +2 -2
  87. package/src/modal-menu/modal-menu-item.tsx +10 -2
  88. package/src/modal-menu/modal-menu-trigger.tsx +19 -2
  89. package/src/notification-dot.tsx +16 -7
  90. package/src/platform-symbols.ts +9 -0
  91. package/src/platform.ts +2 -0
  92. package/src/popover/index.tsx +31 -8
  93. package/src/popover/modifiers.tsx +26 -19
  94. package/src/reactions/reaction-button.tsx +323 -101
  95. package/src/reactions/reaction-picker.tsx +14 -1
  96. package/src/reactions/reactions.tsx +11 -1
  97. package/src/reactions/tootltip.tsx +55 -0
  98. package/src/rich-text-embed-error.tsx +2 -1
  99. package/src/select/components/group-heading.tsx +8 -0
  100. package/src/select/components/menu-list-virtualized.tsx +6 -2
  101. package/src/select/components/option.tsx +4 -0
  102. package/src/select/select-control-settings-context.tsx +11 -2
  103. package/src/select/select-in-popover.tsx +10 -7
  104. package/src/select/styles.ts +21 -1
  105. package/src/tab-nav/tab-nav.tsx +1 -1
  106. package/src/toggle.tsx +8 -0
  107. package/src/tooltip.tsx +28 -19
  108. package/src/type-badge.tsx +5 -2
  109. package/src/unit/unit-with-tooltip.tsx +1 -1
  110. package/src/use-is-phone.tsx +34 -6
  111. package/src/shortcut-badge.tsx +0 -29
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # @fibery/ui-kit
2
2
 
3
+ ## 1.38.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 91fc1ea: Bump react to 18.3.1
8
+ - Updated dependencies [91fc1ea]
9
+ - @fibery/react@1.4.6
10
+
11
+ ## 1.38.1
12
+
13
+ ### Patch Changes
14
+
15
+ - db89c7a: Add Gallery View
16
+ - 00766c6: switch to pnpm catalogs. Update to latest
17
+ - Updated dependencies [00766c6]
18
+ - @fibery/emoji-data@2.7.1
19
+ - @fibery/helpers@1.3.4
20
+ - @fibery/react@1.4.5
21
+
3
22
  ## 1.38.0
4
23
 
5
24
  ### Minor Changes
@@ -1 +1 @@
1
- import "@testing-library/jest-dom/extend-expect";
1
+ import "@testing-library/jest-dom";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fibery/ui-kit",
3
- "version": "1.38.0",
3
+ "version": "1.38.2",
4
4
  "private": false,
5
5
  "license": "UNLICENSED",
6
6
  "dependencies": {
@@ -31,59 +31,60 @@
31
31
  "lodash": "4.17.21",
32
32
  "md5": "2.2.1",
33
33
  "moment": "2.29.4",
34
+ "photoswipe": "5.4.4",
34
35
  "popper-max-size-modifier": "0.2.0",
35
36
  "prop-types": "15.7.2",
36
37
  "rc-input-number": "8.5.0",
37
38
  "rc-progress": "3.4.1",
38
39
  "react-color": "2.19.3",
39
- "react-day-picker": "8.1.4",
40
+ "react-day-picker": "8.10.1",
40
41
  "react-intersection-observer": "9.3.5",
41
42
  "react-medium-image-zoom": "5.2.10",
42
43
  "react-popper": "2.3.0",
43
44
  "react-select": "5.3.2",
44
45
  "react-select-country-list": "2.2.1",
45
- "react-virtuoso": "4.6.0",
46
- "screenfull": "6.0.1",
46
+ "react-virtuoso": "4.14.1",
47
+ "screenfull": "6.0.2",
47
48
  "tabbable": "5.2.1",
48
49
  "ua-parser-js": "1.0.39",
49
- "@fibery/emoji-data": "2.7.0",
50
- "@fibery/helpers": "1.3.3",
51
- "@fibery/react": "1.4.4"
50
+ "@fibery/emoji-data": "2.7.1",
51
+ "@fibery/helpers": "1.3.4",
52
+ "@fibery/react": "1.4.6"
52
53
  },
53
54
  "peerDependencies": {
54
- "react": "^18.2.0",
55
- "react-dom": "^18.2.0"
55
+ "react": "18.3.1",
56
+ "react-dom": "18.3.1"
56
57
  },
57
58
  "devDependencies": {
58
- "@babel/core": "7.23.9",
59
- "@babel/runtime": "7.23.9",
59
+ "@babel/core": "7.28.5",
60
+ "@babel/runtime": "7.28.4",
60
61
  "@testing-library/dom": "8.19.1",
61
- "@testing-library/jest-dom": "5.16.5",
62
+ "@testing-library/jest-dom": "6.9.1",
62
63
  "@testing-library/react": "13.4.0",
63
64
  "@testing-library/user-event": "13.5.0",
64
65
  "@types/chroma-js": "2.1.3",
65
66
  "@types/color-hash": "1.0.2",
66
67
  "@types/history": "4.7.11",
67
68
  "@types/invariant": "2.2.34",
68
- "@types/jest": "27.0.1",
69
+ "@types/jest": "30.0.0",
69
70
  "@types/lodash": "4.14.172",
70
71
  "@types/prop-types": "15.7.5",
71
- "@types/react": "18.0.26",
72
- "@types/react-dom": "18.0.10",
72
+ "@types/react": "18.3.12",
73
+ "@types/react-dom": "18.3.1",
73
74
  "@wyw-in-js/babel-preset": "0.5.5",
74
75
  "csstype": "3.0.8",
75
76
  "fs-extra": "10.0.0",
76
77
  "glob": "7.1.7",
77
- "jest": "27.5.1",
78
- "jest-junit": "13.0.0",
79
- "react": "18.2.0",
80
- "react-dom": "18.2.0",
78
+ "jest": "30.2.0",
79
+ "jest-junit": "16.0.0",
80
+ "react": "18.3.1",
81
+ "react-dom": "18.3.1",
81
82
  "svg-parser": "2.0.4",
82
83
  "svgo": "2.8.0",
83
- "typescript": "5.8.3",
84
+ "typescript": "5.9.3",
84
85
  "unist-util-reduce": "0.2.2",
85
- "@fibery/eslint-config": "8.6.1",
86
- "@fibery/babel-preset": "7.4.0"
86
+ "@fibery/babel-preset": "7.4.1",
87
+ "@fibery/eslint-config": "8.6.2"
87
88
  },
88
89
  "jest": {
89
90
  "testEnvironment": "jsdom",
@@ -0,0 +1,42 @@
1
+ const preservedNameEmojis = ["🤖", "👻", "🧮", "🪄", "🔌", "🔗", "🔒"];
2
+
3
+ export const abbreviateName = (name?: string | null) => {
4
+ if (name === undefined) {
5
+ return "…";
6
+ }
7
+ if (name && preservedNameEmojis.includes(name)) {
8
+ return name;
9
+ }
10
+
11
+ // Check if name looks like "Surname, Name"
12
+ const hasComma = (name || "").includes(",");
13
+
14
+ const cleaned = (name || "")
15
+ .replace(/\p{Emoji_Presentation}|\p{Emoji}\uFE0F?/gu, "") // remove emojis
16
+ .replace(/[^\p{L}\p{M}'\-\s,]+/gu, " ") // keep comma to detect order before removing
17
+ .trim();
18
+
19
+ // Split on whitespace and commas
20
+ let parts = cleaned.split(/[,\s]+/).filter(Boolean);
21
+
22
+ // If there was a comma, assume it's "Surname, Name" and reverse
23
+ if (hasComma && parts.length > 1) {
24
+ parts = parts.reverse();
25
+ }
26
+ let result: string;
27
+ if (parts.length === 1) {
28
+ // Take the first two codepoints (safer for emoji / astral / surrogate pairs)
29
+ result = [...parts[0]].slice(0, 2).join("");
30
+ } else {
31
+ // Take the first codepoint of the first two parts and upper-case
32
+ result = parts
33
+ .slice(0, 2)
34
+ .map((p) => {
35
+ const first = [...p][0] || "";
36
+ return first.toUpperCase();
37
+ })
38
+ .join("");
39
+ }
40
+
41
+ return result || "?";
42
+ };
@@ -7,11 +7,12 @@ import CheckedIcon from "../icons/react/Checked";
7
7
  import {IconBaseProps} from "../icons/types";
8
8
  import {Spinner} from "../loaders";
9
9
  import {mobileRootSelector} from "../mobile-styles";
10
- import {ShortcutBadge} from "../shortcut-badge";
10
+ import {Kbd, KbdGroup} from "../kbd";
11
11
  import {useTheme} from "../theme-provider";
12
12
  import {useIsPhone} from "../use-is-phone";
13
13
  import {useActionsMenuContext} from "./contexts/actions-menu-context";
14
14
  import {useActiveDangerousRow, useSetActiveDangerousRow} from "./contexts/actions-menu-dangerous-rows";
15
+ import _ from "lodash";
15
16
 
16
17
  const hiddenTextCss = css`
17
18
  visibility: hidden;
@@ -90,14 +91,22 @@ const firstLetterToLowerCase = (str: string) => {
90
91
  return str.charAt(0).toLowerCase() + str.slice(1);
91
92
  };
92
93
 
93
- const RightCorner = ({shortcut, loading, checked}: {shortcut?: string; loading?: boolean; checked?: boolean}) => {
94
+ const RightCorner = ({shortcut, loading, checked}: {shortcut?: string[]; loading?: boolean; checked?: boolean}) => {
94
95
  const theme = useTheme();
95
96
  const isPhone = useIsPhone();
96
97
 
97
- return loading || shortcut || checked ? (
98
+ const shortcuts = _.isArray(shortcut) ? shortcut : shortcut ? [shortcut] : null;
99
+
100
+ return loading || shortcuts || checked ? (
98
101
  <div className={cornerCss}>
99
102
  {loading ? <Spinner color={theme.primary} iconSize={16} containerSize={16} /> : null}
100
- {shortcut ? <ShortcutBadge shortcut={shortcut} /> : null}
103
+ {shortcuts ? (
104
+ <KbdGroup>
105
+ {shortcuts.map((item) => (
106
+ <Kbd key={item}>{item}</Kbd>
107
+ ))}
108
+ </KbdGroup>
109
+ ) : null}
101
110
  {checked ? <CheckedIcon iconSize={isPhone ? 20 : 18} color={themeVars.textColor} /> : null}
102
111
  </div>
103
112
  ) : null;
@@ -127,7 +136,7 @@ export type ActionsMenuItemProps = {
127
136
  Icon?: FunctionComponent<IconBaseProps>;
128
137
  iconColor?: string;
129
138
  /** Hint for keyboard shortcut for this action */
130
- shortcut?: string;
139
+ shortcut?: string[];
131
140
  disabled?: boolean;
132
141
  /** Whether the action requires confirmation */
133
142
  dangerous?: boolean;
@@ -5,6 +5,7 @@ import {ContentProps} from "../dropdown-menu";
5
5
  export type ActionsMenuProps = {
6
6
  /** Clicking on this node will open actions menu. Make sure that trigger forwards ref AND props to html element */
7
7
  trigger: ReactNode;
8
+ triggerEvent?: "click" | "context-menu";
8
9
  children: ReactNode;
9
10
  align?: ContentProps["align"];
10
11
  disabled?: boolean;
@@ -23,6 +23,7 @@ const wideCss = css`
23
23
 
24
24
  export const ActionsMenu = ({
25
25
  trigger,
26
+ triggerEvent = "click",
26
27
  wide,
27
28
  align = "start",
28
29
  alignOffset,
@@ -77,7 +78,9 @@ export const ActionsMenu = ({
77
78
  <MenuPrimitive.Trigger
78
79
  // backward compatibility for dropdown styles
79
80
  className={isOpen ? "actions-visible" : "actions-hidden actions-visible-on-mobile"}
80
- onClick={preventDefaultAndStopPropagation}
81
+ onClick={triggerEvent === "click" ? preventDefaultAndStopPropagation : undefined}
82
+ onContextMenu={triggerEvent === "context-menu" ? preventDefaultAndStopPropagation : undefined}
83
+ triggerEvent={triggerEvent}
81
84
  disabled={disabled}
82
85
  asChild
83
86
  >
@@ -2,6 +2,8 @@ import _ from "lodash";
2
2
  import {useControllableState} from "@fibery/react/src/use-controllable-state";
3
3
  import {ActionsMenuContextProvider} from "./contexts/actions-menu-context";
4
4
  import * as ContextMenu from "../context-menu";
5
+ import {ActionsMenu} from "./actions-menu";
6
+ import {useIsPhone} from "../use-is-phone";
5
7
  import {ActionsMenuDangerousRowsProvider} from "./contexts/actions-menu-dangerous-rows";
6
8
  import {ActionsMenuProps} from "./actions-menu-props";
7
9
  import {preventDefault} from "@fibery/react/src/prevent-default";
@@ -14,11 +16,31 @@ export const ContextActionsMenu = ({
14
16
  trigger,
15
17
  children,
16
18
  disabled,
19
+ mobileTitle,
20
+ supportsMobile,
17
21
  autoFocusOnClose = true,
18
22
  }: ActionsMenuProps): JSX.Element => {
23
+ const isPhone = useIsPhone();
19
24
  const [isOpen = false, setOpen] = useControllableState({value: open, onChange: onOpenChange});
20
25
  const [confirmation, setConfirmation] = useState<ActionsMenuConfirmationProps | null>(null);
21
26
 
27
+ // Special mode - on mobile, open context menu in modal
28
+ if (isPhone && supportsMobile) {
29
+ return (
30
+ <ActionsMenu
31
+ open={open}
32
+ onOpenChange={onOpenChange}
33
+ mobileTitle={mobileTitle}
34
+ supportsMobile
35
+ // Extra div is important here to not loose the original onClick handler
36
+ trigger={<div>{trigger}</div>}
37
+ triggerEvent="context-menu"
38
+ >
39
+ {children}
40
+ </ActionsMenu>
41
+ );
42
+ }
43
+
22
44
  return (
23
45
  <ActionsMenuContextProvider setOpen={setOpen} showConfirmation={setConfirmation} MenuPrimitive={ContextMenu}>
24
46
  <ContextMenu.Root onOpenChange={onOpenChange}>
@@ -1,16 +1,20 @@
1
1
  import {useSize} from "@fibery/react/src/use-size";
2
2
  import React, {ComponentProps, forwardRef, useEffect, useRef, useState} from "react";
3
3
  import {duration, transition} from "./design-system";
4
- import cx from "classnames";
5
4
  import _ from "lodash";
6
5
  import {useComposedRefs} from "@fibery/react/src/use-composed-refs";
7
6
 
8
- interface AnimatedHeightContainerProps extends ComponentProps<"div"> {
7
+ type AnimatedHeightContainerProps = ComponentProps<"div"> & {
9
8
  noAnimation?: boolean;
10
- }
9
+ onTransitionStart?: (event: TransitionEvent) => void;
10
+ onTransitionEnd?: (event: TransitionEvent) => void;
11
+ };
11
12
 
12
13
  export const AnimatedHeightContainer = forwardRef<HTMLDivElement, AnimatedHeightContainerProps>(
13
- function AnimatedHeightContainerComponent({className, noAnimation = false, children, ...otherProps}, ref) {
14
+ function AnimatedHeightContainerComponent(
15
+ {className, noAnimation = false, onTransitionStart = _.noop, onTransitionEnd = _.noop, children, ...otherProps},
16
+ ref
17
+ ) {
14
18
  const measuredContainer = useRef<HTMLDivElement | null>(null);
15
19
  const size = useSize(measuredContainer);
16
20
 
@@ -60,6 +64,21 @@ export const AnimatedHeightContainer = forwardRef<HTMLDivElement, AnimatedHeight
60
64
  return cleanup;
61
65
  }, [animating]);
62
66
 
67
+ useEffect(() => {
68
+ const element = containerRef.current;
69
+ if (!element) {
70
+ return () => {};
71
+ }
72
+
73
+ element.addEventListener("transitionstart", onTransitionStart);
74
+ element.addEventListener("transitionend", onTransitionEnd);
75
+
76
+ return () => {
77
+ element.removeEventListener("transitionstart", onTransitionStart);
78
+ element.removeEventListener("transitionend", onTransitionEnd);
79
+ };
80
+ }, [onTransitionStart, onTransitionEnd]);
81
+
63
82
  const style = animating
64
83
  ? {
65
84
  ...otherProps.style,
@@ -74,7 +93,7 @@ export const AnimatedHeightContainer = forwardRef<HTMLDivElement, AnimatedHeight
74
93
  };
75
94
 
76
95
  return (
77
- <div ref={composedRef} className={cx(className)} {...otherProps} style={style}>
96
+ <div ref={composedRef} className={className} {...otherProps} style={style}>
78
97
  <div ref={measuredContainer}>{children}</div>
79
98
  </div>
80
99
  );
@@ -27,7 +27,7 @@ export const antUploadStyle = css`
27
27
  alignItems: "stretch",
28
28
  alignContent: "stretch",
29
29
  },
30
- "& .ant-upload.ant-upload-drag, .ant-upload.ant-upload-select-picture-card": {
30
+ "& .ant-upload:where(.ant-upload-drag), .ant-upload:where(.ant-upload-select-picture-card)": {
31
31
  border: `1px dashed ${themeVars.separator}`,
32
32
  position: "relative",
33
33
  backgroundColor: themeVars.transparent,
@@ -2,6 +2,7 @@ import {getWrapper} from "./get-wrapper";
2
2
  import Input from "antd/lib/input";
3
3
  import "antd/lib/input/style/css";
4
4
  import {css} from "@linaria/core";
5
+ import {mobileRootSelector} from "../mobile-styles";
5
6
  import {opacity, textStyles, themeVars} from "../design-system";
6
7
 
7
8
  import {inputStyles} from "./styles";
@@ -24,6 +25,9 @@ export const transparentInputStyle = css`
24
25
  transition: "none",
25
26
  ...textStyles.regular,
26
27
  ...textStyles.numeric.tabularOff,
28
+ [`${mobileRootSelector} &`]: {
29
+ ...textStyles.big,
30
+ },
27
31
  },
28
32
  "& textarea.ant-input": {
29
33
  fontVariant: "inherit",
package/src/avatar.tsx CHANGED
@@ -5,33 +5,7 @@ import {getDarkenColor, getObjectColorMemoized, textStyles, themeVars} from "./d
5
5
  import {FibermojiPlaceholder} from "./fibermoji-placeholder";
6
6
  import {getShiftStyle} from "./icons/get-shift-style";
7
7
  import {useFeatures} from "./features";
8
-
9
- const preservedNameEmojis = ["🤖", "👻", "🧮", "🪄", "🔌", "🔗", "🔒"];
10
-
11
- export const abbreviateName = (name?: string) => {
12
- if (name === undefined) {
13
- return "…";
14
- }
15
- if (preservedNameEmojis.includes(name)) {
16
- return name;
17
- }
18
- const filteredName = (name || "").replace(/[!~.\-@[\]]/g, "").trim();
19
- const match = filteredName.match(/\p{Letter}[\p{Letter} ]+/gu);
20
- const processedName = match ? match[0] : "";
21
- const parts = processedName.split(" ").filter((part) => part !== "");
22
- let result;
23
- if (parts.length === 1) {
24
- result = processedName.slice(0, 2);
25
- } else {
26
- result = parts
27
- .filter((part, index) => index < 2)
28
- .map((part) => {
29
- return part[0].toUpperCase();
30
- })
31
- .join("");
32
- }
33
- return result || "?";
34
- };
8
+ import {abbreviateName} from "./abbreviate-name";
35
9
 
36
10
  export const getContainerStyle = _.memoize((containerSize) => {
37
11
  return {
@@ -14,6 +14,8 @@ export type BaseButtonProps = {
14
14
  supportMobile?: boolean;
15
15
  } & React.ComponentPropsWithRef<"button">;
16
16
 
17
+ export const xLargeButtonHeight = 40;
18
+
17
19
  export const baseButton = css`
18
20
  position: relative;
19
21
  box-sizing: border-box;
@@ -3,7 +3,7 @@ import {forwardRef} from "react";
3
3
  import {border, fontWeight, space, textStyles} from "../design-system";
4
4
  import {iconSizeVar} from "../icons/Icon";
5
5
  import SpinnerIcon from "../icons/react/Spinner";
6
- import {BaseButton, BaseButtonProps, ButtonSize} from "./base-button";
6
+ import {BaseButton, BaseButtonProps, ButtonSize, xLargeButtonHeight} from "./base-button";
7
7
  import {useIsSupportHardwareKeyboard} from "../use-is-support-hardware-keyboard";
8
8
  import {useIsPhone} from "../use-is-phone";
9
9
 
@@ -145,12 +145,11 @@ const buttonSize = {
145
145
  }
146
146
  `,
147
147
  xLarge: css`
148
- font-size: ${textStyles.heading3.fontSize}px;
148
+ font-size: ${textStyles.heading4.fontSize}px;
149
149
  line-height: 20px;
150
- letter-spacing: ${textStyles.heading3.letterSpacing};
151
150
 
152
151
  border-radius: ${border.radius6}px;
153
- min-height: 44px;
152
+ min-height: ${xLargeButtonHeight}px;
154
153
  padding: ${space.s6}px ${space.s12}px;
155
154
  gap: ${space.s6}px;
156
155
 
@@ -205,6 +204,7 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
205
204
  ref={ref}
206
205
  disabled={disabled || pending}
207
206
  className={cx(
207
+ "notranslate",
208
208
  className,
209
209
  button,
210
210
  buttonSize[supportMobile && isPhone ? "large" : size],
@@ -3,7 +3,7 @@ import {forwardRef} from "react";
3
3
  import {border, space} from "../design-system";
4
4
  import {iconSizeVar} from "../icons/Icon";
5
5
  import Spinner from "../icons/react/Spinner";
6
- import {BaseButton, BaseButtonProps, ButtonSize} from "./base-button";
6
+ import {BaseButton, BaseButtonProps, ButtonSize, xLargeButtonHeight} from "./base-button";
7
7
  import {useIsPhone} from "../use-is-phone";
8
8
 
9
9
  export type IconButtonProps = {
@@ -55,8 +55,8 @@ export const iconButtonSizes = {
55
55
  xLarge: css`
56
56
  padding: ${space.s6}px;
57
57
 
58
- min-width: 44px;
59
- min-height: 44px;
58
+ min-width: ${xLargeButtonHeight}px;
59
+ min-height: ${xLargeButtonHeight}px;
60
60
  border-radius: ${border.radius6}px;
61
61
 
62
62
  ${iconSizeVar}: 24px;
@@ -247,7 +247,8 @@ const floatingStyles = {
247
247
  };
248
248
 
249
249
  const coverClassName = css`
250
- margin: ${-space.s4}px;
250
+ // box padding -1px to go below the outline
251
+ margin: ${-space.s5}px;
251
252
 
252
253
  &:empty {
253
254
  display: none;
@@ -255,7 +256,7 @@ const coverClassName = css`
255
256
  `;
256
257
 
257
258
  const coverWithContentClassName = css`
258
- border-bottom: ${themeVars.separators.opacity5};
259
+ border-bottom: ${themeVars.shortcutBorder};
259
260
  margin-bottom: 0;
260
261
  `;
261
262
 
package/src/checkbox.tsx CHANGED
@@ -14,6 +14,7 @@ import {
14
14
  } from "react";
15
15
  import {colors, getDarkenColor, getOpacities, layout, space, textStyles, ThemeColors, themeVars} from "./design-system";
16
16
  import {smallHtmlStylesClass} from "./html-styles";
17
+ import {mobileRootSelector} from "./mobile-styles";
17
18
 
18
19
  const checkboxColor = `--fibery-checkbox-color`;
19
20
  const checkboxColorVar = `var(${checkboxColor})`;
@@ -36,6 +37,10 @@ const backgroundStyle = css`
36
37
  box-shadow: 0 0 0 1.5px ${borderColorVar};
37
38
  background-color: ${themeVars.panelBg};
38
39
 
40
+ ${mobileRootSelector} & {
41
+ box-shadow: 0 0 0 1.6px ${borderColorVar};
42
+ }
43
+
39
44
  .${smallHtmlStylesClass} & {
40
45
  width: ${layout.checkboxSize - 2}px;
41
46
  height: ${layout.checkboxSize - 2}px;
@@ -53,6 +58,9 @@ const checkboxRootStyle = css`
53
58
  & input[type="checkbox"]:checked + .${backgroundStyle} {
54
59
  background-color: ${checkboxColorVar};
55
60
  box-shadow: 0 0 0 1.5px ${checkboxColorVar} !important;
61
+ ${mobileRootSelector} & {
62
+ box-shadow: 0 0 0 1.6px ${checkboxColorVar} !important;
63
+ }
56
64
  }
57
65
 
58
66
  & input[type="checkbox"]:indeterminate + .${backgroundStyle} {
@@ -66,15 +74,24 @@ const checkboxRootStyle = css`
66
74
  &:hover input[type="checkbox"]:checked:not(:disabled) + .${backgroundStyle} {
67
75
  background-color: ${darkenColorVar};
68
76
  box-shadow: 0 0 0 1.5px ${darkenColorVar};
77
+ ${mobileRootSelector} & {
78
+ box-shadow: 0 0 0 1.6px ${darkenColorVar};
79
+ }
69
80
  }
70
81
 
71
82
  &:hover input[type="checkbox"]:checked:focus:not(:disabled) + .${backgroundStyle} {
72
83
  background-color: ${darkenColorVar};
73
84
  box-shadow: 0 0 0 1.5px ${darkenColorVar}, 0 0 0 4px ${focusColorVar};
85
+ ${mobileRootSelector} & {
86
+ box-shadow: 0 0 0 1.6px ${darkenColorVar}, 0 0 0 4px ${focusColorVar};
87
+ }
74
88
  }
75
89
 
76
90
  & input[type="checkbox"]:focus + .${backgroundStyle} {
77
91
  box-shadow: 0 0 0 1.5px ${checkboxColorVar}, 0 0 0 4px ${focusColorVar};
92
+ ${mobileRootSelector} & {
93
+ box-shadow: 0 0 0 1.6px ${checkboxColorVar}, 0 0 0 4px ${focusColorVar};
94
+ }
78
95
  }
79
96
 
80
97
  .${smallHtmlStylesClass} & {
@@ -1,6 +1,8 @@
1
1
  import {styled} from "@linaria/react";
2
2
  import * as Collapsible from "@radix-ui/react-collapsible";
3
3
 
4
+ export type CollapsibleRootProps = Collapsible.CollapsibleProps;
5
+
4
6
  export const CollapsibleRoot = Collapsible.Root;
5
7
 
6
8
  export const CollapsibleTrigger = Collapsible.Trigger;
@@ -34,10 +36,10 @@ export const CollapsibleContent = styled(Collapsible.Content)`
34
36
 
35
37
  @media (prefers-reduced-motion: no-preference) {
36
38
  &[data-state="open"] {
37
- animation: slideDown 200ms ease-out;
39
+ animation: slideDown 150ms ease-out;
38
40
  }
39
41
  &[data-state="closed"] {
40
- animation: slideUp 200ms ease-out;
42
+ animation: slideUp 150ms ease-out;
41
43
  }
42
44
  }
43
45
  `;
@@ -25,6 +25,7 @@ type Props = {
25
25
  children: ReactNode;
26
26
  badge?: ReactNode;
27
27
  keepChildren?: boolean;
28
+ className?: string;
28
29
  };
29
30
 
30
31
  export const CollapsibleSection = ({
@@ -35,6 +36,7 @@ export const CollapsibleSection = ({
35
36
  onCollapsedChange,
36
37
  children,
37
38
  badge,
39
+ className,
38
40
  }: Props) => {
39
41
  const [isCollapsed, setIsCollapsed] = useControllableState({
40
42
  value: collapsed,
@@ -71,7 +73,7 @@ export const CollapsibleSection = ({
71
73
  const regularHeader = label && <div className={headerCss}>{label}</div>;
72
74
 
73
75
  return (
74
- <div>
76
+ <div className={className}>
75
77
  {collapsible ? collapsibleHeader : regularHeader}
76
78
  <div style={{display: collapsible && isCollapsed ? "none" : "block"}}>{children}</div>
77
79
  </div>
@@ -2,7 +2,8 @@ import moment from "moment";
2
2
  import {useMemo} from "react";
3
3
  import {Select} from "../select";
4
4
  import {SelectControlSettingsProvider} from "../select/select-control-settings-context";
5
- import {timeFormat as defaultTimeFormat} from "../design-system";
5
+ import {timeFormat as defaultTimeFormat, space} from "../design-system";
6
+ import {useIsPhone} from "../use-is-phone";
6
7
 
7
8
  const step = 30;
8
9
 
@@ -26,6 +27,8 @@ export const AutoComplete = ({
26
27
  menuIsOpen: boolean;
27
28
  position: number;
28
29
  }) => {
30
+ const isPhone = useIsPhone();
31
+
29
32
  const options = useMemo(
30
33
  () =>
31
34
  Array.from({length: (24 * 60) / step}, (value, index) => {
@@ -61,12 +64,15 @@ export const AutoComplete = ({
61
64
  ...props,
62
65
  zIndex: 1000000,
63
66
  position: "absolute",
64
- width: "auto",
65
- top: position,
67
+ width: isPhone ? `calc(100vw - ${2 * space.s12}px)` : "auto",
68
+ top: isPhone ? space.s18 : position,
66
69
  margin: 0,
67
- left: 100,
70
+ left: isPhone ? -space.s12 : 100,
71
+ }),
72
+ menuList: (props) => ({
73
+ ...props,
74
+ width: isPhone ? "auto" : 100,
68
75
  }),
69
- menuList: (props) => ({...props, width: 100}),
70
76
  }}
71
77
  />
72
78
  </SelectControlSettingsProvider>
@@ -2,6 +2,7 @@ import {css} from "@linaria/core";
2
2
  import cx from "classnames";
3
3
  import React, {forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState} from "react";
4
4
  import {MonthChangeEventHandler} from "react-day-picker";
5
+ import {mobileRootSelector} from "../mobile-styles";
5
6
  import {AntTransparentInput} from "../antd/input";
6
7
  import {AntTransparentTextArea} from "../antd/input";
7
8
  import {inputOverrides} from "../antd/styles";
@@ -292,6 +293,9 @@ export const DateRangeInput = forwardRef<
292
293
  display: flex;
293
294
  margin-bottom: ${space.s12 + space.s6}px;
294
295
  padding-right: ${space.s12 - 2}px;
296
+ ${mobileRootSelector} & {
297
+ min-height: ${space.s44}px;
298
+ }
295
299
  `,
296
300
  {[selectedStyle]: selected, [disabledStyle]: disabled}
297
301
  )}
@@ -335,7 +339,7 @@ export const DateRangeInput = forwardRef<
335
339
  />
336
340
  </div>
337
341
  {allowClear && inputValue !== "" && (
338
- <IconButton onClick={onClear} size={"tiny"}>
342
+ <IconButton onClick={onClear} size={"tiny"} supportMobile>
339
343
  <RemoveIcon />
340
344
  </IconButton>
341
345
  )}