@fibery/ui-kit 1.37.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.
- package/CHANGELOG.md +25 -0
- package/config/jest/testFrameworkSetup.js +1 -1
- package/package.json +20 -16
- package/src/abbreviate-name.ts +42 -0
- package/src/actions-menu/actions-menu-item.tsx +32 -11
- package/src/actions-menu/actions-menu-props.tsx +5 -0
- package/src/actions-menu/actions-menu-sub-command-menu.tsx +7 -4
- package/src/actions-menu/actions-menu-sub-menu.tsx +9 -3
- package/src/actions-menu/actions-menu.tsx +28 -9
- package/src/actions-menu/context-actions-menu.tsx +22 -0
- package/src/actions-panel.tsx +12 -2
- package/src/animated-height-container.tsx +24 -5
- package/src/antd/ant-upload.tsx +1 -1
- package/src/antd/input.tsx +4 -0
- package/src/avatar.tsx +1 -27
- package/src/axis-header.tsx +136 -76
- package/src/box.tsx +1 -1
- package/src/breadcrumb.tsx +78 -0
- package/src/button/actions-button-compact.tsx +4 -1
- package/src/button/base-button.tsx +7 -3
- package/src/button/button-group.tsx +1 -1
- package/src/button/button.tsx +33 -1
- package/src/button/icon-button.tsx +10 -1
- package/src/button/select-button.tsx +4 -0
- package/src/card-container.tsx +10 -6
- package/src/checkbox.tsx +17 -0
- package/src/collapsible-section.tsx +3 -1
- package/src/color-picker/swatch.tsx +1 -0
- package/src/command-menu/index.tsx +3 -3
- package/src/context-menu/index.tsx +10 -1
- package/src/date-picker/autocomplete.tsx +11 -5
- package/src/date-picker/date-range-input.tsx +5 -1
- package/src/date-picker/date-range-picker-popup-content.tsx +31 -13
- package/src/date-picker/date-range-picker.tsx +6 -3
- package/src/date-picker/relative-date-picker.tsx +6 -2
- package/src/date-picker/single-date-input.tsx +5 -1
- package/src/date-picker/single-date-picker.tsx +8 -5
- package/src/date-picker/styles.ts +52 -26
- package/src/date-picker/types.ts +3 -1
- package/src/day-select/day-select.tsx +21 -75
- package/src/day-select/iso-week-day-select.tsx +1 -1
- package/src/day-select/mount-day-select.tsx +2 -2
- package/src/day-select/week-day-select.tsx +1 -5
- package/src/design-system.ts +45 -12
- package/src/dropdown-menu/index.tsx +19 -2
- package/src/emoji-picker/app-icon-picker.tsx +6 -4
- package/src/emoji-picker/emoji-picker-preview-footer.tsx +5 -1
- package/src/emoji-picker/emoji-picker.tsx +3 -0
- package/src/emoji-picker/emoji.tsx +5 -3
- package/src/emoji-picker/icon-emoji-picker.tsx +10 -1
- package/src/emoji-picker/primitives/emoji.tsx +49 -51
- package/src/emoji-picker/primitives/footer.tsx +5 -0
- package/src/emoji-picker/primitives/search.tsx +8 -0
- package/src/emoji-picker/primitives/skin-tone.tsx +12 -1
- package/src/emoji-picker/use-responsive-emoji-size.ts +11 -0
- package/src/emoji-picker/utils/emoji-set.ts +2 -1
- package/src/empty-state/empty-state.tsx +6 -0
- package/src/fibermoji-placeholder.tsx +1 -27
- package/src/field-icon.tsx +4 -1
- package/src/file-item-2.tsx +408 -0
- package/src/file-item.tsx +215 -47
- package/src/header-layout.tsx +11 -0
- package/src/html-styles.ts +21 -4
- package/src/icons/ast/ActivityFilled.ts +8 -0
- package/src/icons/ast/AiAssistantFilled.ts +8 -0
- package/src/icons/ast/Back.ts +1 -1
- package/src/icons/ast/CollapseAllHorizontal.ts +8 -0
- package/src/icons/ast/DateRange.ts +1 -1
- package/src/icons/ast/EntityCreateFilled.ts +8 -0
- package/src/icons/ast/ExpandAllHorizontal.ts +8 -0
- package/src/icons/ast/ExtensionFiles.ts +1 -1
- package/src/icons/ast/FileUpload.ts +1 -1
- package/src/icons/ast/GlobeUnpublish.ts +8 -0
- package/src/icons/ast/HomeFilled.ts +8 -0
- package/src/icons/ast/KeyboardHideDown.ts +8 -0
- package/src/icons/ast/LayoutMultiple.ts +8 -0
- package/src/icons/ast/RicheditorHistoryRedo.ts +1 -1
- package/src/icons/ast/RicheditorHistoryUndo.ts +1 -1
- package/src/icons/ast/SearchFilled.ts +8 -0
- package/src/icons/ast/SettingsFilled.ts +8 -0
- package/src/icons/ast/SlideMenuFilled.ts +8 -0
- package/src/icons/ast/SwitchToMention.ts +8 -0
- package/src/icons/ast/SwitchToText.ts +8 -0
- package/src/icons/ast/SwitchToWidget.ts +8 -0
- package/src/icons/ast/TypeDate.ts +1 -1
- package/src/icons/ast/ViewGallery.ts +8 -0
- package/src/icons/ast/index.tsx +16 -0
- package/src/icons/react/ActivityFilled.tsx +13 -0
- package/src/icons/react/AiAssistantFilled.tsx +13 -0
- package/src/icons/react/CollapseAllHorizontal.tsx +13 -0
- package/src/icons/react/EntityCreateFilled.tsx +13 -0
- package/src/icons/react/ExpandAllHorizontal.tsx +13 -0
- package/src/icons/react/GlobeUnpublish.tsx +13 -0
- package/src/icons/react/HomeFilled.tsx +13 -0
- package/src/icons/react/KeyboardHideDown.tsx +13 -0
- package/src/icons/react/LayoutMultiple.tsx +13 -0
- package/src/icons/react/SearchFilled.tsx +13 -0
- package/src/icons/react/SettingsFilled.tsx +13 -0
- package/src/icons/react/SlideMenuFilled.tsx +13 -0
- package/src/icons/react/SwitchToMention.tsx +13 -0
- package/src/icons/react/SwitchToText.tsx +13 -0
- package/src/icons/react/SwitchToWidget.tsx +13 -0
- package/src/icons/react/ViewGallery.tsx +13 -0
- package/src/icons/react/index.tsx +16 -0
- package/src/icons/svg/activity-filled.svg +4 -0
- package/src/icons/svg/ai-assistant-filled.svg +3 -0
- package/src/icons/svg/back.svg +3 -1
- package/src/icons/svg/collapse-all-horizontal.svg +3 -0
- package/src/icons/svg/date-range.svg +3 -3
- package/src/icons/svg/entity-create-filled.svg +4 -0
- package/src/icons/svg/expand-all-horizontal.svg +3 -0
- package/src/icons/svg/extension/files.svg +3 -1
- package/src/icons/svg/file-upload.svg +3 -6
- package/src/icons/svg/globe-unpublish.svg +4 -0
- package/src/icons/svg/home-filled.svg +3 -0
- package/src/icons/svg/keyboard-hide-down.svg +1 -0
- package/src/icons/svg/layout-multiple.svg +3 -0
- package/src/icons/svg/richeditor/history/redo.svg +3 -2
- package/src/icons/svg/richeditor/history/undo.svg +3 -2
- package/src/icons/svg/search-filled.svg +3 -0
- package/src/icons/svg/settings-filled.svg +3 -0
- package/src/icons/svg/slide-menu-filled.svg +1 -0
- package/src/icons/svg/switch-to-mention.svg +3 -0
- package/src/icons/svg/switch-to-text.svg +4 -0
- package/src/icons/svg/switch-to-widget.svg +4 -0
- package/src/icons/svg/type/date.svg +3 -2
- package/src/icons/svg/view-gallery.svg +4 -0
- package/src/images-gallery/images-gallery-fall-through-provider.tsx +11 -0
- package/src/images-gallery/images-gallery.tsx +257 -0
- package/src/images-gallery/zoom.tsx +123 -0
- package/src/images-gallery-2/images-gallery-2.tsx +442 -0
- package/src/images-gallery-2/slide-buttons.tsx +230 -0
- package/src/images-gallery-2/zoom.tsx +35 -0
- package/src/is-in-popup.ts +1 -1
- package/src/kbd.tsx +46 -0
- package/src/layout-styles.ts +21 -1
- package/src/lists/actions-menu-row-surface.tsx +3 -1
- package/src/lists/list-row-surface.tsx +7 -1
- package/src/mobile-keyboard-aware-popup.tsx +87 -0
- package/src/mobile-styles.ts +8 -0
- package/src/modal-menu/contexts/modal-menu-context.tsx +22 -0
- package/src/modal-menu/contexts/modal-submenu-context.tsx +16 -0
- package/src/modal-menu/index.tsx +14 -0
- package/src/modal-menu/modal-menu-content.tsx +68 -0
- package/src/modal-menu/modal-menu-group.tsx +10 -0
- package/src/modal-menu/modal-menu-item.tsx +45 -0
- package/src/modal-menu/modal-menu-label.tsx +24 -0
- package/src/modal-menu/modal-menu-root.tsx +57 -0
- package/src/modal-menu/modal-menu-separator.tsx +14 -0
- package/src/modal-menu/modal-menu-trigger.tsx +54 -0
- package/src/modal-menu/modal-submenu-content.tsx +49 -0
- package/src/modal-menu/modal-submenu-trigger.tsx +34 -0
- package/src/modal-menu/modal-submenu.tsx +17 -0
- package/src/notification-dot.tsx +16 -7
- package/src/online-users.tsx +3 -3
- package/src/palette.ts +1 -1
- package/src/platform-symbols.ts +9 -0
- package/src/platform.ts +2 -0
- package/src/popover/index.tsx +710 -0
- package/src/popover/mobile-popup-context.tsx +29 -0
- package/src/{popup → popover}/modifiers.tsx +25 -25
- package/src/{popup → popover}/popup-modifiers-context.ts +3 -3
- package/src/reactions/reaction-button.tsx +342 -135
- package/src/reactions/reaction-picker.tsx +51 -44
- package/src/reactions/reactions.tsx +11 -1
- package/src/reactions/tootltip.tsx +55 -0
- package/src/rich-text-embed-error.tsx +2 -1
- package/src/select/components/group-heading.tsx +8 -0
- package/src/select/components/menu-list-virtualized.tsx +6 -2
- package/src/select/components/option.tsx +4 -0
- package/src/select/index.tsx +8 -4
- package/src/select/select-control-settings-context.tsx +11 -2
- package/src/select/select-in-popover.tsx +30 -39
- package/src/select/styles.ts +21 -1
- package/src/tab-nav/tab-nav.tsx +36 -10
- package/src/toast/primitives.tsx +8 -1
- package/src/toggle-button/round-toggle-button.tsx +23 -0
- package/src/toggle-button/toggle-button-group.tsx +34 -0
- package/src/toggle-button/toggle-button.tsx +164 -0
- package/src/toggle.tsx +11 -3
- package/src/tooltip.tsx +29 -20
- package/src/type-badge.tsx +5 -2
- package/src/unit/styles.ts +2 -2
- package/src/unit/unit-with-tooltip.tsx +1 -1
- package/src/use-is-phone.tsx +50 -4
- package/src/use-is-support-hover.ts +1 -1
- package/src/use-on-screen-keyboard-data.tsx +66 -0
- package/src/workflow-progress-icon.tsx +16 -22
- package/src/popup/index.tsx +0 -383
- package/src/shortcut-badge.tsx +0 -29
- /package/src/{popup → popover}/popup-stack-context.tsx +0 -0
- /package/src/{popup → popover}/reference.ts +0 -0
- /package/src/{popup → popover}/styles.ts +0 -0
- /package/src/{popup → popover}/use-click-outside.ts +0 -0
package/src/tab-nav/tab-nav.tsx
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
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
|
+
import {mobileRootSelector} from "../mobile-styles";
|
|
17
18
|
import {TooltipIfOverflown} from "../tooltip-if-overflown";
|
|
18
19
|
import {useCallbackRef} from "@fibery/react/src/use-callback-ref";
|
|
19
20
|
import {useResizeObserver} from "@fibery/react/src/use-resize-observer";
|
|
@@ -35,7 +36,11 @@ const tabNavItem = css`
|
|
|
35
36
|
list-style: none;
|
|
36
37
|
`;
|
|
37
38
|
|
|
38
|
-
const
|
|
39
|
+
const tabNavItemWide = css`
|
|
40
|
+
flex: 1 0 0;
|
|
41
|
+
`;
|
|
42
|
+
|
|
43
|
+
export const tabButton = css`
|
|
39
44
|
all: unset;
|
|
40
45
|
display: flex;
|
|
41
46
|
align-items: center;
|
|
@@ -54,23 +59,40 @@ const tabButton = css`
|
|
|
54
59
|
font-weight: ${fontWeight.medium};
|
|
55
60
|
line-height: 16px;
|
|
56
61
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
62
|
+
@media (any-hover: hover) {
|
|
63
|
+
&:hover {
|
|
64
|
+
background-color: ${themeVars.colorBgTabHover};
|
|
65
|
+
color: ${themeVars.textColor};
|
|
66
|
+
}
|
|
61
67
|
}
|
|
62
68
|
|
|
63
69
|
&:focus-visible {
|
|
70
|
+
color: ${themeVars.textColor};
|
|
71
|
+
background-color: ${themeVars.colorBgTabHover};
|
|
64
72
|
outline: 2px solid ${themeVars.colorBorderNeutralFocusRing};
|
|
65
73
|
}
|
|
66
74
|
|
|
67
75
|
&[data-active] {
|
|
68
76
|
color: ${themeVars.textColor};
|
|
69
77
|
}
|
|
78
|
+
|
|
79
|
+
.${tabNavItemWide} & {
|
|
80
|
+
justify-content: center;
|
|
81
|
+
text-align: center;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
${mobileRootSelector} & {
|
|
85
|
+
padding: ${space.s4}px ${space.s8}px ${space.s8}px ${space.s4}px;
|
|
86
|
+
font-size: ${textStyles.regular.fontSize}px;
|
|
87
|
+
}
|
|
70
88
|
`;
|
|
71
89
|
|
|
72
90
|
const tabNavButtonText = css`
|
|
73
91
|
padding: 0 ${space.s4}px;
|
|
92
|
+
|
|
93
|
+
${mobileRootSelector} & {
|
|
94
|
+
padding: 0 ${space.s6}px;
|
|
95
|
+
}
|
|
74
96
|
`;
|
|
75
97
|
|
|
76
98
|
const tabNavIndicatorTrack = css`
|
|
@@ -145,15 +167,15 @@ const useTabNavIndicator = ({active, itemRef}: {active?: boolean; itemRef: RefOb
|
|
|
145
167
|
useResizeObserver(itemRef, () => updateIndicator());
|
|
146
168
|
};
|
|
147
169
|
|
|
148
|
-
export const TabNavItem = forwardRef<HTMLLIElement, NavigationMenuItemProps & {active?: boolean}>(
|
|
149
|
-
({className, children, active, ...props}, forwardedRef) => {
|
|
170
|
+
export const TabNavItem = forwardRef<HTMLLIElement, NavigationMenuItemProps & {active?: boolean; wide?: boolean}>(
|
|
171
|
+
({className, children, active, wide, ...props}, forwardedRef) => {
|
|
150
172
|
const itemRef = useRef(null);
|
|
151
173
|
const ref = useComposedRefs(itemRef, forwardedRef);
|
|
152
174
|
|
|
153
175
|
useTabNavIndicator({active, itemRef});
|
|
154
176
|
|
|
155
177
|
return (
|
|
156
|
-
<NavigationMenuItem ref={ref} className={cx(tabNavItem, className)} {...props}>
|
|
178
|
+
<NavigationMenuItem ref={ref} className={cx(tabNavItem, wide && tabNavItemWide, className)} {...props}>
|
|
157
179
|
{children}
|
|
158
180
|
</NavigationMenuItem>
|
|
159
181
|
);
|
|
@@ -165,9 +187,13 @@ export const TabNavLink = forwardRef<
|
|
|
165
187
|
Omit<NavigationMenuLinkProps, "asChild"> & {
|
|
166
188
|
before?: ReactNode;
|
|
167
189
|
after?: ReactNode;
|
|
190
|
+
wide?: boolean;
|
|
168
191
|
itemClassName?: string;
|
|
169
192
|
}
|
|
170
|
-
>(function TabNavLink(
|
|
193
|
+
>(function TabNavLink(
|
|
194
|
+
{children, className, itemClassName, active, wide, before, after, href, ...linkProps},
|
|
195
|
+
forwardedRef
|
|
196
|
+
) {
|
|
171
197
|
const renderAsButton = typeof href === "undefined";
|
|
172
198
|
|
|
173
199
|
const Component = renderAsButton ? "button" : "a";
|
|
@@ -178,7 +204,7 @@ export const TabNavLink = forwardRef<
|
|
|
178
204
|
return (
|
|
179
205
|
<TooltipIfOverflown title={children}>
|
|
180
206
|
{({setNode}) => (
|
|
181
|
-
<TabNavItem className={itemClassName} active={active}>
|
|
207
|
+
<TabNavItem className={itemClassName} active={active} wide={wide}>
|
|
182
208
|
<NavigationMenuLink
|
|
183
209
|
ref={forwardedRef}
|
|
184
210
|
className={cx(tabButton, className)}
|
package/src/toast/primitives.tsx
CHANGED
|
@@ -5,6 +5,12 @@ import {ElementRef, forwardRef} from "react";
|
|
|
5
5
|
import {IconButton} from "../button/icon-button";
|
|
6
6
|
import {border, space, textStyles, themeVars, transition} from "../design-system";
|
|
7
7
|
import CloseIcon from "../icons/react/Close";
|
|
8
|
+
import {
|
|
9
|
+
safeAreaInsetBottomVar,
|
|
10
|
+
safeAreaInsetLeftVar,
|
|
11
|
+
safeAreaInsetRightVar,
|
|
12
|
+
safeAreaInsetTopVar,
|
|
13
|
+
} from "../mobile-styles";
|
|
8
14
|
|
|
9
15
|
const viewportCss = css`
|
|
10
16
|
position: fixed;
|
|
@@ -17,7 +23,8 @@ const viewportCss = css`
|
|
|
17
23
|
gap: ${space.s16}px;
|
|
18
24
|
margin: 0;
|
|
19
25
|
z-index: 1010; // inherited from old toast implementation
|
|
20
|
-
padding:
|
|
26
|
+
padding: var(${safeAreaInsetTopVar}) var(${safeAreaInsetRightVar}) var(${safeAreaInsetBottomVar})
|
|
27
|
+
var(${safeAreaInsetLeftVar});
|
|
21
28
|
list-style: none;
|
|
22
29
|
|
|
23
30
|
transition: bottom ${transition}; // bottom may change dynamically
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import {ComponentRef, forwardRef} from "react";
|
|
2
|
+
import {ToggleButton, ToggleButtonProps} from "./toggle-button";
|
|
3
|
+
import {css, cx} from "@linaria/core";
|
|
4
|
+
|
|
5
|
+
const roundToggleButtonCss = css`
|
|
6
|
+
&:is(&) {
|
|
7
|
+
border-radius: 100%;
|
|
8
|
+
width: 28px;
|
|
9
|
+
height: 28px;
|
|
10
|
+
padding: 0;
|
|
11
|
+
justify-content: center;
|
|
12
|
+
}
|
|
13
|
+
`;
|
|
14
|
+
|
|
15
|
+
export const RoundToggleButton = forwardRef<ComponentRef<typeof ToggleButton>, Omit<ToggleButtonProps, "iconStart">>(
|
|
16
|
+
function RoundToggleButton({children, className, ...props}, ref) {
|
|
17
|
+
return (
|
|
18
|
+
<ToggleButton ref={ref} className={cx(roundToggleButtonCss, className)} {...props}>
|
|
19
|
+
{children}
|
|
20
|
+
</ToggleButton>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import {css, cx} from "@linaria/core";
|
|
2
|
+
import {
|
|
3
|
+
ToggleGroup,
|
|
4
|
+
ToggleGroupItem,
|
|
5
|
+
ToggleGroupItemProps,
|
|
6
|
+
ToggleGroupMultipleProps,
|
|
7
|
+
ToggleGroupSingleProps,
|
|
8
|
+
} from "@radix-ui/react-toggle-group";
|
|
9
|
+
import {ComponentRef, forwardRef} from "react";
|
|
10
|
+
import {ToggleButton, ToggleButtonProps} from "./toggle-button";
|
|
11
|
+
import {space} from "../design-system";
|
|
12
|
+
|
|
13
|
+
export const toggleButtonGroupCss = css`
|
|
14
|
+
display: flex;
|
|
15
|
+
flex-direction: row;
|
|
16
|
+
`;
|
|
17
|
+
|
|
18
|
+
export const ToggleButtonGroup = forwardRef<
|
|
19
|
+
ComponentRef<typeof ToggleGroup>,
|
|
20
|
+
(ToggleGroupSingleProps | ToggleGroupMultipleProps) & {gap?: number}
|
|
21
|
+
>(function ToggleButtonGroup({className, gap = space.s4, ...props}, ref) {
|
|
22
|
+
return <ToggleGroup ref={ref} style={{gap}} className={cx(toggleButtonGroupCss, className)} {...props} />;
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export const ToggleButtonGroupItem = forwardRef<
|
|
26
|
+
ComponentRef<typeof ToggleGroupItem>,
|
|
27
|
+
ToggleGroupItemProps & ToggleButtonProps
|
|
28
|
+
>(function ToggleButtonGroupItem({className, children, asChild, ...props}, ref) {
|
|
29
|
+
return (
|
|
30
|
+
<ToggleGroupItem ref={ref} className={className} {...props} asChild>
|
|
31
|
+
{asChild ? children : <ToggleButton>{children}</ToggleButton>}
|
|
32
|
+
</ToggleGroupItem>
|
|
33
|
+
);
|
|
34
|
+
});
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import {css, cx} from "@linaria/core";
|
|
2
|
+
import {Toggle, ToggleProps} from "@radix-ui/react-toggle";
|
|
3
|
+
import {forwardRef} from "react";
|
|
4
|
+
import {border, space, textStyles, themeVars} from "../design-system";
|
|
5
|
+
import {iconColorVar, iconSizeVar} from "../icons/Icon";
|
|
6
|
+
|
|
7
|
+
export const toggleButtonCss = css`
|
|
8
|
+
button:where(&) {
|
|
9
|
+
all: unset;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
padding-inline: ${space.s6}px;
|
|
13
|
+
box-sizing: border-box;
|
|
14
|
+
display: flex;
|
|
15
|
+
align-items: center;
|
|
16
|
+
min-height: 24px;
|
|
17
|
+
font-size: ${textStyles.small.fontSize}px;
|
|
18
|
+
border-radius: ${border.radius8}px;
|
|
19
|
+
|
|
20
|
+
transition-property: border, background-color, color, opacity, box-shadow;
|
|
21
|
+
transition-duration: 0.15s;
|
|
22
|
+
|
|
23
|
+
color: ${themeVars.textColor};
|
|
24
|
+
${iconColorVar}: ${themeVars.colorIconButtonGhostNeutral};
|
|
25
|
+
|
|
26
|
+
${iconSizeVar}: 16px;
|
|
27
|
+
|
|
28
|
+
border: 1.5px solid ${themeVars.colorBorderReactionsHover};
|
|
29
|
+
background-color: ${themeVars.colorBgReactionsDefault};
|
|
30
|
+
|
|
31
|
+
&[aria-readonly="true"] {
|
|
32
|
+
background-color: ${themeVars.colorBgReactionsHover};
|
|
33
|
+
border-color: ${themeVars.colorBgReactionsHover};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
cursor: pointer;
|
|
37
|
+
line-height: 16px;
|
|
38
|
+
user-select: none;
|
|
39
|
+
|
|
40
|
+
&[data-size="medium"] {
|
|
41
|
+
min-height: 28px;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
&[data-size="large"] {
|
|
45
|
+
min-height: 32px;
|
|
46
|
+
padding-inline: 7px;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
&:not(:disabled, [aria-readonly="true"]) {
|
|
50
|
+
&:hover {
|
|
51
|
+
background-color: ${themeVars.colorBgReactionsHover};
|
|
52
|
+
border-color: ${themeVars.colorBorderReactionsHover};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
&:is(:active, [aria-expanded="true"]) {
|
|
56
|
+
background-color: ${themeVars.colorBgReactionsHover};
|
|
57
|
+
border-color: ${themeVars.colorBorderReactionsHover};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
&:disabled,
|
|
62
|
+
&[aria-readonly="true"] {
|
|
63
|
+
cursor: default;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
&:focus {
|
|
67
|
+
outline: none;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
&:focus-visible {
|
|
71
|
+
background-color: ${themeVars.colorBgReactionsHover};
|
|
72
|
+
outline: 2px solid ${themeVars.colorBorderReactionsHover};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
&:is([aria-pressed="true"], [aria-checked="true"]) {
|
|
76
|
+
color: ${themeVars.colorTextReactionsSelected};
|
|
77
|
+
${iconColorVar}: ${themeVars.colorIconButtonGhostAccent};
|
|
78
|
+
background-color: ${themeVars.colorBgReactionsSelectedDefault};
|
|
79
|
+
border-color: ${themeVars.colorBorderReactionsSelectedDefault};
|
|
80
|
+
|
|
81
|
+
&[aria-readonly="true"] {
|
|
82
|
+
background-color: ${themeVars.colorBgReactionsSelectedDefault};
|
|
83
|
+
border-color: ${themeVars.colorBgReactionsSelectedDefault};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
&:not(:disabled, [aria-readonly="true"]) {
|
|
87
|
+
&:hover {
|
|
88
|
+
background-color: ${themeVars.colorBgReactionsSelectedHover};
|
|
89
|
+
border-color: ${themeVars.colorBorderReactionsSelectedHover};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
&:active {
|
|
93
|
+
background-color: ${themeVars.colorBgReactionsSelectedDefault};
|
|
94
|
+
border-color: ${themeVars.colorBorderReactionsSelectedHover};
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
`;
|
|
99
|
+
|
|
100
|
+
export const toggleButtonCssWithIconStart = css`
|
|
101
|
+
padding-left: ${space.s4}px;
|
|
102
|
+
`;
|
|
103
|
+
|
|
104
|
+
export const toggleButtonContent = css`
|
|
105
|
+
display: flex;
|
|
106
|
+
align-items: center;
|
|
107
|
+
gap: ${space.s4}px;
|
|
108
|
+
height: 100%;
|
|
109
|
+
|
|
110
|
+
transition-property: opacity;
|
|
111
|
+
transition-duration: 0.15s;
|
|
112
|
+
|
|
113
|
+
.${toggleButtonCss}:is(:active, [aria-expanded="true"]) > & {
|
|
114
|
+
opacity: 0.8;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.${toggleButtonCss}:disabled > & {
|
|
118
|
+
opacity: 0.6;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
overflow: hidden;
|
|
122
|
+
`;
|
|
123
|
+
|
|
124
|
+
export type ToggleButtonVariant = "outline";
|
|
125
|
+
export type ToggleButtonSize = "small" | "medium" | "large";
|
|
126
|
+
|
|
127
|
+
export type ToggleButtonProps = {
|
|
128
|
+
iconStart?: React.ReactNode;
|
|
129
|
+
variant?: ToggleButtonVariant;
|
|
130
|
+
size?: ToggleButtonSize;
|
|
131
|
+
readOnly?: boolean;
|
|
132
|
+
} & Omit<ToggleProps, "asChild">;
|
|
133
|
+
|
|
134
|
+
export const ToggleButton = forwardRef<HTMLButtonElement, ToggleButtonProps>(
|
|
135
|
+
(
|
|
136
|
+
{
|
|
137
|
+
className,
|
|
138
|
+
iconStart,
|
|
139
|
+
size = "small",
|
|
140
|
+
variant = "outline",
|
|
141
|
+
children,
|
|
142
|
+
"aria-readonly": ariaReadonly,
|
|
143
|
+
readOnly = ariaReadonly,
|
|
144
|
+
...props
|
|
145
|
+
},
|
|
146
|
+
ref
|
|
147
|
+
): JSX.Element => {
|
|
148
|
+
return (
|
|
149
|
+
<Toggle
|
|
150
|
+
ref={ref}
|
|
151
|
+
className={cx(toggleButtonCss, iconStart && toggleButtonCssWithIconStart, className)}
|
|
152
|
+
data-variant={variant}
|
|
153
|
+
data-size={size}
|
|
154
|
+
aria-readonly={readOnly}
|
|
155
|
+
{...props}
|
|
156
|
+
>
|
|
157
|
+
<div className={toggleButtonContent}>
|
|
158
|
+
{iconStart}
|
|
159
|
+
{children}
|
|
160
|
+
</div>
|
|
161
|
+
</Toggle>
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
);
|
package/src/toggle.tsx
CHANGED
|
@@ -2,9 +2,10 @@ import {css, cx} from "@linaria/core";
|
|
|
2
2
|
import {styled} from "@linaria/react";
|
|
3
3
|
import chroma from "chroma-js";
|
|
4
4
|
import {ComponentProps, FC, ReactNode} from "react";
|
|
5
|
-
import {
|
|
5
|
+
import {space, textStyles, transition} from "./design-system";
|
|
6
6
|
import _ from "lodash";
|
|
7
7
|
import SpinnerIcon from "./icons/react/Spinner";
|
|
8
|
+
import {mobileRootSelector} from "./mobile-styles";
|
|
8
9
|
|
|
9
10
|
const toggleIconHeightVar = "--fibery-toggle-icon-height";
|
|
10
11
|
const toggleIconWidthVar = "--fibery-toggle-icon-width";
|
|
@@ -26,15 +27,16 @@ const Input = styled.input<{outlineColor: string}>`
|
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
&:focus-visible {
|
|
29
|
-
|
|
30
|
+
outline: ${({outlineColor}) => `2px solid ${outlineColor}`};
|
|
31
|
+
outline-offset: 1px;
|
|
30
32
|
}
|
|
31
33
|
`;
|
|
32
34
|
|
|
33
35
|
const Label = styled.div<{labelPosition: "last" | "first"; disabled?: boolean}>`
|
|
36
|
+
display: flex;
|
|
34
37
|
margin-left: ${({labelPosition}) => (labelPosition === "last" ? `${space.s8}px` : 0)};
|
|
35
38
|
margin-right: ${({labelPosition}) => (labelPosition === "first" ? `${space.s8}px` : 0)};
|
|
36
39
|
opacity: ${({disabled}) => (disabled ? 0.5 : 1)};
|
|
37
|
-
line-height: ${layout.checkboxSize}px;
|
|
38
40
|
width: 100%;
|
|
39
41
|
min-width: 0;
|
|
40
42
|
`;
|
|
@@ -94,10 +96,16 @@ const toggleSize = {
|
|
|
94
96
|
large: css`
|
|
95
97
|
${textStyles.regular}
|
|
96
98
|
${toggleIconHeightVar}: 18px;
|
|
99
|
+
${mobileRootSelector} & {
|
|
100
|
+
${textStyles.big}
|
|
101
|
+
}
|
|
97
102
|
`,
|
|
98
103
|
"extra-large": css`
|
|
99
104
|
${textStyles.regular}
|
|
100
105
|
${toggleIconHeightVar}: 20px;
|
|
106
|
+
${mobileRootSelector} & {
|
|
107
|
+
${textStyles.big}
|
|
108
|
+
}
|
|
101
109
|
`,
|
|
102
110
|
};
|
|
103
111
|
const toggleSizeStyle = css`
|
package/src/tooltip.tsx
CHANGED
|
@@ -2,7 +2,6 @@ import {css, cx} from "@linaria/core";
|
|
|
2
2
|
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
|
3
3
|
import {forwardRef, type ReactNode, type SyntheticEvent} from "react";
|
|
4
4
|
import {border, fontWeight, lineHeight, space, themeVars, tooltipDelay} from "./design-system";
|
|
5
|
-
import {ShortcutBadge} from "./shortcut-badge";
|
|
6
5
|
|
|
7
6
|
const isFlagPresent = (flag: string) => new RegExp(`[?&]${flag}\\b`).test(window.location.search);
|
|
8
7
|
|
|
@@ -24,10 +23,10 @@ const descriptionStyle = css`
|
|
|
24
23
|
`;
|
|
25
24
|
|
|
26
25
|
export const tooltipStyle = css`
|
|
27
|
-
font-size:
|
|
26
|
+
font-size: 12px;
|
|
28
27
|
color: ${themeVars.whiteColor};
|
|
29
28
|
z-index: 100000;
|
|
30
|
-
min-height:
|
|
29
|
+
min-height: 28px;
|
|
31
30
|
max-width: 300px;
|
|
32
31
|
background-color: ${themeVars.tooltipBgColor};
|
|
33
32
|
padding: ${space.s6}px ${space.s8}px;
|
|
@@ -76,27 +75,37 @@ const whiteBgStyle = css`
|
|
|
76
75
|
`;
|
|
77
76
|
|
|
78
77
|
export const TooltipTitle = ({children}: {children: ReactNode}) => <div className={titleStyle}>{children}</div>;
|
|
78
|
+
|
|
79
79
|
export const TooltipDescription = ({children}: {children: ReactNode}) => (
|
|
80
80
|
<div className={descriptionStyle}>{children}</div>
|
|
81
81
|
);
|
|
82
82
|
|
|
83
|
-
export const TooltipContent = ({
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
83
|
+
export const TooltipContent = ({
|
|
84
|
+
direction = "horizontal",
|
|
85
|
+
className,
|
|
86
|
+
...rest
|
|
87
|
+
}: {direction?: "horizontal" | "vertical"} & React.ComponentProps<"div">) => {
|
|
88
|
+
return (
|
|
89
|
+
<div
|
|
90
|
+
className={cx(
|
|
91
|
+
className,
|
|
92
|
+
direction === "horizontal"
|
|
93
|
+
? css`
|
|
94
|
+
display: flex;
|
|
95
|
+
align-items: center;
|
|
96
|
+
gap: ${space.s8}px;
|
|
97
|
+
`
|
|
98
|
+
: css`
|
|
99
|
+
display: flex;
|
|
100
|
+
flex-direction: column;
|
|
101
|
+
align-items: center;
|
|
102
|
+
gap: ${space.s4}px;
|
|
103
|
+
`
|
|
104
|
+
)}
|
|
105
|
+
{...rest}
|
|
106
|
+
/>
|
|
107
|
+
);
|
|
108
|
+
};
|
|
100
109
|
|
|
101
110
|
export const TooltipProvider: React.FC<TooltipPrimitive.TooltipProviderProps> = (props) => (
|
|
102
111
|
<TooltipPrimitive.Provider disableHoverableContent skipDelayDuration={150} {...props} />
|
package/src/type-badge.tsx
CHANGED
|
@@ -150,6 +150,7 @@ type TypeBadgeProps = {
|
|
|
150
150
|
tooltip?: ReactNode;
|
|
151
151
|
faded?: boolean;
|
|
152
152
|
big?: boolean;
|
|
153
|
+
style?: CSSProperties;
|
|
153
154
|
vertical?: boolean;
|
|
154
155
|
className?: string;
|
|
155
156
|
noTooltip?: boolean; // pass true to force disable tooltip for abbr
|
|
@@ -173,6 +174,7 @@ export const TypeBadge = memo(
|
|
|
173
174
|
vertical = false,
|
|
174
175
|
className,
|
|
175
176
|
noTooltip,
|
|
177
|
+
style,
|
|
176
178
|
},
|
|
177
179
|
ref
|
|
178
180
|
) {
|
|
@@ -206,7 +208,8 @@ export const TypeBadge = memo(
|
|
|
206
208
|
light2: baseColor,
|
|
207
209
|
});
|
|
208
210
|
|
|
209
|
-
const
|
|
211
|
+
const resultingStyle = {
|
|
212
|
+
...style,
|
|
210
213
|
[colorProp]: baseColor ? textBadgeColor : colors.inversedTextColor,
|
|
211
214
|
//[colorProp]: baseColor ? getTextColor(baseColor) : colors.inversedTextColor,
|
|
212
215
|
[colorBackgroundProp]: backgroundBadgeColor || colors.shades.opacity25,
|
|
@@ -220,7 +223,7 @@ export const TypeBadge = memo(
|
|
|
220
223
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
221
224
|
// @ts-ignore
|
|
222
225
|
ref={ref}
|
|
223
|
-
style={
|
|
226
|
+
style={resultingStyle}
|
|
224
227
|
className={cx(
|
|
225
228
|
typeBadgeStyle,
|
|
226
229
|
big ? bigTypeBadgeStaticStyle : compact ? compactTypeBadgeStaticStyle : normalTypeBadgeStaticStyle,
|
package/src/unit/styles.ts
CHANGED
|
@@ -146,14 +146,14 @@ export const unitContentContainerClassName = css`
|
|
|
146
146
|
`;
|
|
147
147
|
|
|
148
148
|
export const unitDescriptionClassName = css`
|
|
149
|
-
margin-bottom: ${space.
|
|
149
|
+
margin-bottom: ${space.s1}px;
|
|
150
150
|
`;
|
|
151
151
|
|
|
152
152
|
export const fullUnitWrapperClassName = css`
|
|
153
153
|
display: flex;
|
|
154
154
|
align-items: center;
|
|
155
155
|
padding: ${space.s6}px;
|
|
156
|
-
border-radius: ${space.
|
|
156
|
+
border-radius: ${space.s5}px;
|
|
157
157
|
background-color: ${themeVars.cardBg};
|
|
158
158
|
margin-bottom: ${space.s4}px;
|
|
159
159
|
`;
|
|
@@ -31,7 +31,7 @@ export const UnitWithTooltip = ({children, title, description}: Props) => {
|
|
|
31
31
|
// Had to use additional way to validate if we are still over unit
|
|
32
32
|
if (isHoveredRef.current && unitElementRef.current && unitElementRef.current.matches(":hover")) {
|
|
33
33
|
setShouldDisplayTooltip(true);
|
|
34
|
-
const intervalId = setInterval(() => {
|
|
34
|
+
const intervalId = window.setInterval(() => {
|
|
35
35
|
if (isHoveredRef.current && unitElementRef.current) {
|
|
36
36
|
if (!unitElementRef.current.matches(":hover")) {
|
|
37
37
|
isHoveredRef.current = false;
|
package/src/use-is-phone.tsx
CHANGED
|
@@ -1,12 +1,58 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {ReactNode, useLayoutEffect} from "react";
|
|
2
2
|
import {createContext} from "@fibery/react/src/create-context";
|
|
3
|
-
import {
|
|
3
|
+
import {useIsMediaQueryMatched} from "./use-is-media-query-matched";
|
|
4
|
+
import {getMediaQueryList} from "./media-query-utils";
|
|
4
5
|
|
|
5
6
|
const [Provider, useIsPhone] = createContext<boolean>("PhoneContext", false);
|
|
6
7
|
|
|
7
8
|
export {useIsPhone};
|
|
8
9
|
|
|
10
|
+
declare global {
|
|
11
|
+
const __DISABLE_VERTICAL_MOBILE_BREAKPOINT__: boolean | undefined;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function isVerticalMobileBreakpointDisabled() {
|
|
15
|
+
// noinspection PointlessBooleanExpressionJS
|
|
16
|
+
if (
|
|
17
|
+
typeof __DISABLE_VERTICAL_MOBILE_BREAKPOINT__ !== "undefined" &&
|
|
18
|
+
__DISABLE_VERTICAL_MOBILE_BREAKPOINT__ === true
|
|
19
|
+
) {
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
23
|
+
return urlParams.has("no-vertical-mobile-breakpoint");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const isPhoneApp = Boolean(
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
28
|
+
// @ts-ignore - injected by consumer app
|
|
29
|
+
window.__FIBERY_MOBILE_APP_API
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
export const phoneMediaQuery = isVerticalMobileBreakpointDisabled()
|
|
33
|
+
? "(max-width: 450px)"
|
|
34
|
+
: "(max-width: 450px), (max-height: 450px)";
|
|
35
|
+
|
|
36
|
+
export function isPhoneMode() {
|
|
37
|
+
return isPhoneApp || getMediaQueryList(phoneMediaQuery).matches;
|
|
38
|
+
}
|
|
39
|
+
|
|
9
40
|
export function IsPhoneProvider({children}: {children: ReactNode}) {
|
|
10
|
-
const isPhone = useIsMediaQueryMatched(
|
|
11
|
-
|
|
41
|
+
const isPhone = useIsMediaQueryMatched(phoneMediaQuery);
|
|
42
|
+
useLayoutEffect(() => {
|
|
43
|
+
const htmlElement = document.querySelector("html");
|
|
44
|
+
if (!htmlElement || isPhoneApp) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (isPhone) {
|
|
48
|
+
htmlElement.classList.add("fibery-mobile");
|
|
49
|
+
} else {
|
|
50
|
+
htmlElement.classList.remove("fibery-mobile");
|
|
51
|
+
}
|
|
52
|
+
// eslint-disable-next-line consistent-return
|
|
53
|
+
return () => {
|
|
54
|
+
htmlElement.classList.remove("fibery-mobile");
|
|
55
|
+
};
|
|
56
|
+
}, [isPhone]);
|
|
57
|
+
return <Provider value={isPhoneApp || isPhone}>{children}</Provider>;
|
|
12
58
|
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import {ReactNode, useEffect, useState} from "react";
|
|
2
|
+
import {createContext} from "@fibery/react/src/create-context";
|
|
3
|
+
import _ from "lodash";
|
|
4
|
+
import {useIsPhone} from "./use-is-phone";
|
|
5
|
+
import {keyboardHeightVar, mobileKeyboardOpenClassName} from "./mobile-styles";
|
|
6
|
+
|
|
7
|
+
const defaultKeyboardHeight = 350;
|
|
8
|
+
|
|
9
|
+
const [OnScreenKeyboardHeightValueProvider, useOnScreenKeyboardHeight] = createContext<number>(
|
|
10
|
+
"OnScreenKeyboardHeightProvider",
|
|
11
|
+
defaultKeyboardHeight
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
const [IsOnScreenKeyboardOpenedValueProvider, useIsOnScreenKeyboardOpened] = createContext<boolean>(
|
|
15
|
+
"IsOnScreenKeyboardOpenedValueProvider",
|
|
16
|
+
false
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
export function OnScreenKeyboardContextProvider({children}: {children: ReactNode}) {
|
|
20
|
+
const isPhone = useIsPhone();
|
|
21
|
+
const [keyboardHeight, setKeyboardHeight] = useState<number>(defaultKeyboardHeight);
|
|
22
|
+
const [keyboardVisible, setKeyboardVisible] = useState<boolean>(false);
|
|
23
|
+
const [initialViewPortHeight] = useState(() => window.visualViewport?.height || 0);
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
const viewport = window.visualViewport;
|
|
26
|
+
if (!viewport || !isPhone) {
|
|
27
|
+
return _.noop;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function viewportHandler() {
|
|
31
|
+
if (viewport) {
|
|
32
|
+
// console.log({height: viewport.height, initialViewPortHeight, windowHeight: window.innerHeight});
|
|
33
|
+
// Calculate keyboard height as difference between window height and viewport height
|
|
34
|
+
const calculatedHeight = Math.max(0, initialViewPortHeight - viewport.height);
|
|
35
|
+
if (calculatedHeight && keyboardHeight !== calculatedHeight && calculatedHeight > 200) {
|
|
36
|
+
setKeyboardHeight(calculatedHeight);
|
|
37
|
+
document.body.style.setProperty(keyboardHeightVar, `${calculatedHeight}px`);
|
|
38
|
+
}
|
|
39
|
+
if (viewport.height !== initialViewPortHeight && !keyboardVisible) {
|
|
40
|
+
const htmlElement = document.querySelector("html");
|
|
41
|
+
htmlElement?.classList.add(mobileKeyboardOpenClassName);
|
|
42
|
+
setKeyboardVisible(true);
|
|
43
|
+
} else if (viewport.height === initialViewPortHeight && keyboardVisible) {
|
|
44
|
+
setKeyboardVisible(false);
|
|
45
|
+
const htmlElement = document.querySelector("html");
|
|
46
|
+
htmlElement?.classList.remove(mobileKeyboardOpenClassName);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
viewport.addEventListener("resize", viewportHandler);
|
|
52
|
+
// Initial calculation
|
|
53
|
+
viewportHandler();
|
|
54
|
+
|
|
55
|
+
return () => {
|
|
56
|
+
viewport.removeEventListener("resize", viewportHandler);
|
|
57
|
+
};
|
|
58
|
+
}, [initialViewPortHeight, isPhone, keyboardHeight, keyboardVisible]);
|
|
59
|
+
return (
|
|
60
|
+
<OnScreenKeyboardHeightValueProvider value={keyboardHeight}>
|
|
61
|
+
<IsOnScreenKeyboardOpenedValueProvider value={keyboardVisible}>{children}</IsOnScreenKeyboardOpenedValueProvider>
|
|
62
|
+
</OnScreenKeyboardHeightValueProvider>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export {useOnScreenKeyboardHeight, useIsOnScreenKeyboardOpened};
|