@fibery/ui-kit 1.37.0 → 1.38.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.
- package/CHANGELOG.md +14 -0
- package/package.json +8 -5
- package/src/actions-menu/actions-menu-item.tsx +18 -6
- package/src/actions-menu/actions-menu-props.tsx +4 -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 +24 -8
- package/src/actions-panel.tsx +12 -2
- 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 +5 -3
- package/src/button/button-group.tsx +1 -1
- package/src/button/button.tsx +31 -0
- package/src/button/icon-button.tsx +9 -0
- package/src/button/select-button.tsx +4 -0
- package/src/card-container.tsx +7 -4
- 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/date-range-picker.tsx +6 -3
- package/src/date-picker/relative-date-picker.tsx +6 -2
- package/src/date-picker/single-date-picker.tsx +8 -5
- package/src/date-picker/styles.ts +32 -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 +21 -12
- package/src/dropdown-menu/index.tsx +8 -1
- package/src/emoji-picker/app-icon-picker.tsx +6 -4
- package/src/emoji-picker/emoji-picker-preview-footer.tsx +1 -1
- package/src/emoji-picker/emoji-picker.tsx +3 -0
- package/src/emoji-picker/emoji.tsx +2 -1
- package/src/emoji-picker/icon-emoji-picker.tsx +10 -1
- package/src/emoji-picker/primitives/footer.tsx +0 -1
- package/src/emoji-picker/primitives/skin-tone.tsx +1 -0
- 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/field-icon.tsx +4 -1
- package/src/file-item.tsx +164 -47
- package/src/html-styles.ts +8 -0
- package/src/icons/ast/ActivityFilled.ts +8 -0
- package/src/icons/ast/AiAssistantFilled.ts +8 -0
- 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/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/TypeDate.ts +1 -1
- package/src/icons/ast/index.tsx +12 -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/index.tsx +12 -0
- package/src/icons/svg/activity-filled.svg +4 -0
- package/src/icons/svg/ai-assistant-filled.svg +3 -0
- 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/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/type/date.svg +3 -2
- package/src/images-gallery/images-gallery.tsx +254 -0
- package/src/images-gallery/zoom.tsx +112 -0
- package/src/is-in-popup.ts +1 -1
- 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 +37 -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 +37 -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/online-users.tsx +3 -3
- package/src/palette.ts +1 -1
- package/src/popover/index.tsx +687 -0
- package/src/popover/mobile-popup-context.tsx +29 -0
- package/src/{popup → popover}/modifiers.tsx +0 -7
- package/src/{popup → popover}/popup-modifiers-context.ts +3 -3
- package/src/reactions/reaction-button.tsx +30 -45
- package/src/reactions/reaction-picker.tsx +39 -45
- package/src/select/index.tsx +8 -4
- package/src/select/select-in-popover.tsx +21 -33
- package/src/tab-nav/tab-nav.tsx +35 -9
- 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 +3 -3
- package/src/tooltip.tsx +2 -2
- package/src/unit/styles.ts +2 -2
- package/src/use-is-phone.tsx +28 -3
- 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/{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
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
<
|
|
1
|
+
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M4.64001 11.3477C4.64001 8.94531 6.26302 7.28711 8.91152 7.28711H12.3861L13.7279 7.3457L12.7669 6.54883L11.4369 5.24805C11.2962 5.11328 11.2025 4.94922 11.2025 4.7207C11.2025 4.30469 11.4955 4 11.9349 4C12.1283 4 12.3275 4.08203 12.4798 4.22852L15.7728 7.48633C15.9193 7.62695 16.0013 7.83789 16.0013 8.03711C16.0013 8.24219 15.9193 8.45312 15.7728 8.59375L12.4798 11.8457C12.3275 11.9922 12.1283 12.0801 11.9349 12.0801C11.4955 12.0801 11.2025 11.7695 11.2025 11.3535C11.2025 11.125 11.2962 10.9609 11.4369 10.8262L12.7669 9.52539L13.7279 8.72852L12.3861 8.79297H8.92321C7.14781 8.79297 6.12242 9.83008 6.12242 11.3125C6.12242 12.7891 7.14781 13.8555 8.92321 13.8555H10.3119C10.7513 13.8555 11.0736 14.1953 11.0736 14.6113C11.0736 15.0215 10.7513 15.3613 10.3119 15.3613H8.84702C6.23962 15.3613 4.64001 13.7793 4.64001 11.3477Z" />
|
|
3
|
+
</svg>
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
<
|
|
1
|
+
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M15.3613 11.3477C15.3613 8.94531 13.7383 7.28711 11.0898 7.28711H7.61523L6.27344 7.3457L7.23438 6.54883L8.56445 5.24805C8.70508 5.11328 8.79883 4.94922 8.79883 4.7207C8.79883 4.30469 8.50586 4 8.06641 4C7.87305 4 7.67383 4.08203 7.52148 4.22852L4.22852 7.48633C4.08203 7.62695 4 7.83789 4 8.03711C4 8.24219 4.08203 8.45312 4.22852 8.59375L7.52148 11.8457C7.67383 11.9922 7.87305 12.0801 8.06641 12.0801C8.50586 12.0801 8.79883 11.7695 8.79883 11.3535C8.79883 11.125 8.70508 10.9609 8.56445 10.8262L7.23438 9.52539L6.27344 8.72852L7.61523 8.79297H11.0781C12.8535 8.79297 13.8789 9.83008 13.8789 11.3125C13.8789 12.7891 12.8535 13.8555 11.0781 13.8555H9.68945C9.25 13.8555 8.92773 14.1953 8.92773 14.6113C8.92773 15.0215 9.25 15.3613 9.68945 15.3613H11.1543C13.7617 15.3613 15.3613 13.7793 15.3613 11.3477Z" />
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M13.875 8.75C13.875 5.91954 11.5805 3.625 8.75 3.625C5.91954 3.625 3.625 5.91954 3.625 8.75C3.625 11.5805 5.91954 13.875 8.75 13.875C10.1655 13.875 11.4453 13.3027 12.374 12.374C13.3026 11.4454 13.875 10.1654 13.875 8.75ZM16.125 8.75C16.125 10.3801 15.5937 11.8867 14.6982 13.1074L18.2959 16.7041C18.7352 17.1435 18.7352 17.8566 18.2959 18.2959C17.8565 18.7352 17.1434 18.7352 16.7041 18.2959L13.1074 14.6982C11.8867 15.5937 10.3801 16.125 8.75 16.125C4.6769 16.125 1.375 12.8231 1.375 8.75C1.375 4.6769 4.6769 1.375 8.75 1.375C12.8231 1.375 16.125 4.6769 16.125 8.75Z" />
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.5 1.34961C10.8958 1.35078 11.2824 1.47186 11.6084 1.69629C11.9343 1.92065 12.1847 2.23836 12.3272 2.60742L12.7539 3.70898L14.0703 4.4668L15.2568 4.28613C15.6429 4.23378 16.036 4.29728 16.3858 4.46875C16.7355 4.64028 17.0266 4.91185 17.2217 5.24902L17.2236 5.25293L17.707 6.09961C17.9066 6.44122 17.9986 6.83577 17.9707 7.23047C17.9427 7.62564 17.7961 8.0032 17.5498 8.31348L16.8242 9.23828V10.7559L17.5723 11.6836C17.8198 11.9944 17.967 12.3732 17.9951 12.7695C18.0231 13.1642 17.931 13.5588 17.7315 13.9004L17.2481 14.7471L17.2461 14.751C17.0511 15.0881 16.7599 15.3597 16.4102 15.5312C16.0604 15.7027 15.6672 15.7662 15.2813 15.7139L15.2686 15.7129L14.0947 15.5332L12.7783 16.291L12.3516 17.3916C12.2091 17.7609 11.9589 18.0792 11.6328 18.3037C11.3068 18.5282 10.9203 18.6492 10.5244 18.6504H9.50001C9.10419 18.6492 8.71765 18.5281 8.39161 18.3037C8.06583 18.0794 7.81537 17.7615 7.67286 17.3926L7.24611 16.291L5.9297 15.5332L4.74318 15.7139C4.35716 15.7662 3.96405 15.7027 3.61427 15.5312C3.26453 15.3597 2.97339 15.0882 2.77833 14.751L2.77638 14.7471L2.29298 13.9004C2.09345 13.5588 2.00138 13.1642 2.02931 12.7695C2.05734 12.3744 2.20395 11.9968 2.45021 11.6865L3.17579 10.7617V9.24414L2.42775 8.31641C2.18022 8.00564 2.03301 7.62676 2.0049 7.23047C1.97697 6.83577 2.06903 6.44122 2.26857 6.09961L2.75392 5.24902C2.94895 4.91188 3.24016 4.64028 3.58986 4.46875C3.93974 4.29723 4.33361 4.2337 4.71974 4.28613L4.73146 4.28711L5.90822 4.4668L7.24708 3.70703L7.67286 2.6084C7.81537 2.23947 8.06583 1.92059 8.39161 1.69629C8.71765 1.47185 9.10418 1.35078 9.50001 1.34961H10.5ZM10 7.25C8.48124 7.25001 7.25001 8.48122 7.25001 10C7.25001 11.5188 8.48124 12.75 10 12.75C11.5188 12.75 12.75 11.5188 12.75 10C12.75 8.48122 11.5188 7.25 10 7.25Z" />
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path clip-rule="evenodd" d="m18 5.75c0-1.51878-1.2312-2.75-2.75-2.75h-10.5c-1.51878 0-2.75 1.23122-2.75 2.75v8.5c0 1.5188 1.23122 2.75 2.75 2.75h10.5c1.5188 0 2.75-1.2312 2.75-2.75zm-11-1.25c.69036 0 1.25.55964 1.25 1.25v8.5c0 .6904-.55964 1.25-1.25 1.25h-2.25c-.69036 0-1.25-.5596-1.25-1.25v-8.5c0-.69036.55964-1.25 1.25-1.25z" fill-rule="evenodd"/></svg>
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
<
|
|
1
|
+
<svg height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.6 3H14V1.80391C14 1.59174 13.9157 1.38825 13.7657 1.23822C13.6157 1.0882 13.4122 1.00391 13.2 1.00391C12.9878 1.00391 12.7843 1.0882 12.6343 1.23822C12.4843 1.38825 12.4 1.59174 12.4 1.80391V3H7.6V1.80391C7.6 1.59174 7.51571 1.38825 7.36569 1.23822C7.21566 1.0882 7.01217 1.00391 6.8 1.00391C6.58783 1.00391 6.38434 1.0882 6.23431 1.23822C6.08429 1.38825 6 1.59174 6 1.80391V3H4.4C3.76348 3 3.15303 3.25286 2.70294 3.70294C2.25286 4.15303 2 4.76348 2 5.4V14.6C2 15.2365 2.25286 15.847 2.70294 16.2971C3.15303 16.7471 3.76348 17 4.4 17H15.6C16.2365 17 16.847 16.7471 17.2971 16.2971C17.7471 15.847 18 15.2365 18 14.6V5.4C18 4.76348 17.7471 4.15303 17.2971 3.70294C16.847 3.25286 16.2365 3 15.6 3ZM16.1657 15.1657C16.3157 15.0157 16.4 14.8122 16.4 14.6V9H3.6V14.6C3.6 14.8122 3.68429 15.0157 3.83431 15.1657C3.98434 15.3157 4.18783 15.4 4.4 15.4H15.6C15.8122 15.4 16.0157 15.3157 16.1657 15.1657ZM3.6 7.4H16.4V5.4C16.4 5.18783 16.3157 4.98434 16.1657 4.83431C16.0157 4.68429 15.8122 4.6 15.6 4.6H4.4C4.18783 4.6 3.98434 4.68429 3.83431 4.83431C3.68429 4.98434 3.6 5.18783 3.6 5.4V7.4Z" />
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import {ReactNode, useCallback, useEffect, useMemo, useReducer, useRef, useState} from "react";
|
|
2
|
+
import _ from "lodash";
|
|
3
|
+
import {createContext} from "@fibery/react/src/create-context";
|
|
4
|
+
import {useIsPhone} from "../use-is-phone";
|
|
5
|
+
import {safeAreaInsetBottomVar} from "../mobile-styles";
|
|
6
|
+
import {buttonGroup, ButtonGroup} from "../button/button-group";
|
|
7
|
+
import {IconButton} from "../button/icon-button";
|
|
8
|
+
import ArrowRight from "../icons/react/ArrowRight";
|
|
9
|
+
import ArrowLeft from "../icons/react/ArrowLeft";
|
|
10
|
+
import {css} from "@linaria/core";
|
|
11
|
+
import cx from "classnames";
|
|
12
|
+
|
|
13
|
+
type Registry = Map<string, {zoomed: boolean; setZoomed: (zoomed: boolean) => void}>;
|
|
14
|
+
|
|
15
|
+
const [ImagesGalleryRegistryProvider, useImagesGalleryRegistry] = createContext(
|
|
16
|
+
"ImagesGalleryRegistryContext",
|
|
17
|
+
new Map()
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
export {useImagesGalleryRegistry};
|
|
21
|
+
|
|
22
|
+
type Methods = {
|
|
23
|
+
setVisible: (visible: boolean) => void;
|
|
24
|
+
setActivated: (activated: boolean) => void;
|
|
25
|
+
update: () => void;
|
|
26
|
+
nextImage: () => void;
|
|
27
|
+
prevImage: () => void;
|
|
28
|
+
};
|
|
29
|
+
const [ImagesGalleryMethodsProvider, useImagesGalleryMethods] = createContext<Methods>("ImagesGalleryMethodsProvider", {
|
|
30
|
+
setVisible: _.noop,
|
|
31
|
+
setActivated: _.noop,
|
|
32
|
+
update: _.noop,
|
|
33
|
+
nextImage: _.noop,
|
|
34
|
+
prevImage: _.noop,
|
|
35
|
+
});
|
|
36
|
+
type State = {visible: boolean; activated: boolean; _inc: number};
|
|
37
|
+
|
|
38
|
+
const [ImagesGalleryStateProvider, useImagesGalleryState] = createContext<State>("ImagesGalleryStateContext", {
|
|
39
|
+
visible: false,
|
|
40
|
+
activated: false,
|
|
41
|
+
_inc: 0,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
export {useImagesGalleryMethods, useImagesGalleryState};
|
|
45
|
+
|
|
46
|
+
type Actions = {type: "set-visible"; payload: boolean} | {type: "set-activated"; payload: boolean} | {type: "inc"};
|
|
47
|
+
|
|
48
|
+
function initialState(): State {
|
|
49
|
+
return {visible: false, activated: false, _inc: 0};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function imagesGalleryReducer(state: State, action: Actions) {
|
|
53
|
+
if (action.type === "set-visible") {
|
|
54
|
+
return {...state, visible: action.payload};
|
|
55
|
+
}
|
|
56
|
+
if (action.type === "set-activated") {
|
|
57
|
+
return {...state, activated: action.payload};
|
|
58
|
+
}
|
|
59
|
+
if (action.type === "inc") {
|
|
60
|
+
return {...state, _inc: state._inc + 1};
|
|
61
|
+
}
|
|
62
|
+
return state;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const controlsGroupStyle = css`
|
|
66
|
+
&.${buttonGroup} {
|
|
67
|
+
display: none;
|
|
68
|
+
}
|
|
69
|
+
`;
|
|
70
|
+
|
|
71
|
+
export function Controls() {
|
|
72
|
+
const imagesRegistry = useImagesGalleryRegistry();
|
|
73
|
+
const {visible} = useImagesGalleryState();
|
|
74
|
+
const isPhone = useIsPhone();
|
|
75
|
+
const {prevImage, nextImage, setVisible} = useImagesGalleryMethods();
|
|
76
|
+
// Determine if there is a zoomed image and its position in the registry
|
|
77
|
+
let activeNext = true;
|
|
78
|
+
let activePrev = true;
|
|
79
|
+
let i = 0;
|
|
80
|
+
for (const image of imagesRegistry.values()) {
|
|
81
|
+
if (image.zoomed) {
|
|
82
|
+
if (i === 0) {
|
|
83
|
+
activePrev = false;
|
|
84
|
+
}
|
|
85
|
+
if (i === imagesRegistry.size - 1) {
|
|
86
|
+
activeNext = false;
|
|
87
|
+
}
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
i++;
|
|
91
|
+
}
|
|
92
|
+
const visibleState = visible || isPhone;
|
|
93
|
+
if (imagesRegistry.size > 1) {
|
|
94
|
+
const size = isPhone ? "xLarge" : "small";
|
|
95
|
+
return (
|
|
96
|
+
<div
|
|
97
|
+
className={css`
|
|
98
|
+
position: fixed;
|
|
99
|
+
bottom: max(var(${safeAreaInsetBottomVar}), 12px);
|
|
100
|
+
left: 0;
|
|
101
|
+
right: 0;
|
|
102
|
+
display: grid;
|
|
103
|
+
align-items: center;
|
|
104
|
+
justify-content: center;
|
|
105
|
+
&:hover .${controlsGroupStyle}.${buttonGroup} {
|
|
106
|
+
display: flex;
|
|
107
|
+
}
|
|
108
|
+
`}
|
|
109
|
+
>
|
|
110
|
+
<ButtonGroup
|
|
111
|
+
className={cx(
|
|
112
|
+
controlsGroupStyle,
|
|
113
|
+
visibleState &&
|
|
114
|
+
css`
|
|
115
|
+
&.${controlsGroupStyle}.${buttonGroup} {
|
|
116
|
+
display: flex;
|
|
117
|
+
}
|
|
118
|
+
`
|
|
119
|
+
)}
|
|
120
|
+
>
|
|
121
|
+
<IconButton
|
|
122
|
+
variant={"outline"}
|
|
123
|
+
size={size}
|
|
124
|
+
onClick={() => {
|
|
125
|
+
prevImage();
|
|
126
|
+
setVisible(true);
|
|
127
|
+
}}
|
|
128
|
+
disabled={!activePrev}
|
|
129
|
+
>
|
|
130
|
+
<ArrowLeft />
|
|
131
|
+
</IconButton>
|
|
132
|
+
<IconButton
|
|
133
|
+
variant={"outline"}
|
|
134
|
+
size={size}
|
|
135
|
+
onClick={() => {
|
|
136
|
+
nextImage();
|
|
137
|
+
setVisible(true);
|
|
138
|
+
}}
|
|
139
|
+
disabled={!activeNext}
|
|
140
|
+
>
|
|
141
|
+
<ArrowRight />
|
|
142
|
+
</IconButton>
|
|
143
|
+
</ButtonGroup>
|
|
144
|
+
</div>
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function ImagesGalleryProvider({children}: {children: ReactNode}) {
|
|
151
|
+
const [imagesRegistry] = useState<Registry>(() => new Map());
|
|
152
|
+
const timeoutRef = useRef<ReturnType<typeof setTimeout>>();
|
|
153
|
+
const [galleryState, dispatchState] = useReducer(imagesGalleryReducer, [], initialState);
|
|
154
|
+
const setVisible = useCallback((visible: boolean) => dispatchState({type: "set-visible", payload: visible}), []);
|
|
155
|
+
const setActivated = useCallback(
|
|
156
|
+
(activated: boolean) => dispatchState({type: "set-activated", payload: activated}),
|
|
157
|
+
[]
|
|
158
|
+
);
|
|
159
|
+
const update = useCallback(() => dispatchState({type: "inc"}), []);
|
|
160
|
+
const {visible} = galleryState;
|
|
161
|
+
const timeout = 3000;
|
|
162
|
+
useEffect(() => {
|
|
163
|
+
if (visible) {
|
|
164
|
+
clearTimeout(timeoutRef.current);
|
|
165
|
+
timeoutRef.current = setTimeout(() => {
|
|
166
|
+
setVisible(false);
|
|
167
|
+
}, timeout);
|
|
168
|
+
}
|
|
169
|
+
return () => {
|
|
170
|
+
clearTimeout(timeoutRef.current);
|
|
171
|
+
};
|
|
172
|
+
}, [setVisible, visible]);
|
|
173
|
+
const nextImage = useCallback(() => {
|
|
174
|
+
let i = 0;
|
|
175
|
+
for (const image of imagesRegistry.values()) {
|
|
176
|
+
if (image.zoomed) {
|
|
177
|
+
if (i === imagesRegistry.size - 1) {
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
image.setZoomed(false);
|
|
181
|
+
const nextImage = Array.from(imagesRegistry.values())[i + 1];
|
|
182
|
+
nextImage.setZoomed(true);
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
i++;
|
|
186
|
+
}
|
|
187
|
+
clearTimeout(timeoutRef.current);
|
|
188
|
+
timeoutRef.current = setTimeout(() => {
|
|
189
|
+
setVisible(false);
|
|
190
|
+
}, timeout);
|
|
191
|
+
}, [imagesRegistry, setVisible]);
|
|
192
|
+
|
|
193
|
+
const prevImage = useCallback(() => {
|
|
194
|
+
let i = 0;
|
|
195
|
+
for (const image of imagesRegistry.values()) {
|
|
196
|
+
if (image.zoomed) {
|
|
197
|
+
if (i === 0) {
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
image.setZoomed(false);
|
|
201
|
+
const prevImage = Array.from(imagesRegistry.values())[i - 1];
|
|
202
|
+
prevImage.setZoomed(true);
|
|
203
|
+
break;
|
|
204
|
+
}
|
|
205
|
+
i++;
|
|
206
|
+
}
|
|
207
|
+
clearTimeout(timeoutRef.current);
|
|
208
|
+
timeoutRef.current = setTimeout(() => {
|
|
209
|
+
setVisible(false);
|
|
210
|
+
}, timeout);
|
|
211
|
+
}, [imagesRegistry, setVisible]);
|
|
212
|
+
|
|
213
|
+
const methods = useMemo(
|
|
214
|
+
() => ({setVisible, setActivated, update, nextImage, prevImage}),
|
|
215
|
+
[setVisible, setActivated, update, nextImage, prevImage]
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
useEffect(() => {
|
|
219
|
+
const listener = (evt: KeyboardEvent) => {
|
|
220
|
+
const hasActive = Array.from(imagesRegistry.values()).some((image) => image.zoomed);
|
|
221
|
+
if (!hasActive) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
if (evt.key === "Escape") {
|
|
225
|
+
for (const image of imagesRegistry.values()) {
|
|
226
|
+
if (image.zoomed) {
|
|
227
|
+
image.setZoomed(false);
|
|
228
|
+
break;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
if (evt.key === "ArrowRight") {
|
|
233
|
+
nextImage();
|
|
234
|
+
}
|
|
235
|
+
if (evt.key === "ArrowLeft") {
|
|
236
|
+
prevImage();
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
document.addEventListener("keydown", listener, {capture: true});
|
|
240
|
+
return () => {
|
|
241
|
+
document.removeEventListener("keydown", listener, {capture: true});
|
|
242
|
+
};
|
|
243
|
+
}, [imagesRegistry, nextImage, prevImage]);
|
|
244
|
+
|
|
245
|
+
return (
|
|
246
|
+
<>
|
|
247
|
+
<ImagesGalleryRegistryProvider value={imagesRegistry}>
|
|
248
|
+
<ImagesGalleryMethodsProvider value={methods}>
|
|
249
|
+
<ImagesGalleryStateProvider value={galleryState}>{children}</ImagesGalleryStateProvider>
|
|
250
|
+
</ImagesGalleryMethodsProvider>
|
|
251
|
+
</ImagesGalleryRegistryProvider>
|
|
252
|
+
</>
|
|
253
|
+
);
|
|
254
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import {css} from "@linaria/core";
|
|
2
|
+
import React, {ReactNode, useCallback} from "react";
|
|
3
|
+
import {Controlled} from "react-medium-image-zoom";
|
|
4
|
+
import "react-medium-image-zoom/dist/styles.css";
|
|
5
|
+
import {themeVars} from "../design-system";
|
|
6
|
+
import {IconButton} from "../button/icon-button";
|
|
7
|
+
import Close from "../icons/react/Close";
|
|
8
|
+
import {Controls, useImagesGalleryMethods} from "./images-gallery";
|
|
9
|
+
import {useIsPhone} from "../use-is-phone";
|
|
10
|
+
|
|
11
|
+
const dialogCss = css`
|
|
12
|
+
:global() {
|
|
13
|
+
[data-rmiz-modal-overlay="hidden"] {
|
|
14
|
+
background-color: transparent;
|
|
15
|
+
}
|
|
16
|
+
[data-rmiz-modal-overlay="visible"] {
|
|
17
|
+
background-color: ${themeVars.colorBgEditorImageZoomed};
|
|
18
|
+
}
|
|
19
|
+
[data-rmiz-content="found"] > img {
|
|
20
|
+
cursor: auto;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
`;
|
|
24
|
+
|
|
25
|
+
type ModalState = "LOADED" | "LOADING" | "UNLOADED" | "UNLOADING";
|
|
26
|
+
|
|
27
|
+
const ZoomContent = ({
|
|
28
|
+
img,
|
|
29
|
+
modalState,
|
|
30
|
+
onUnzoom,
|
|
31
|
+
}: {
|
|
32
|
+
img: React.ReactElement | null;
|
|
33
|
+
modalState: ModalState;
|
|
34
|
+
onUnzoom: (e: Event) => void;
|
|
35
|
+
}) => {
|
|
36
|
+
const imagesGalleryMethods = useImagesGalleryMethods();
|
|
37
|
+
const isPhone = useIsPhone();
|
|
38
|
+
|
|
39
|
+
const button = modalState === "LOADED" && (
|
|
40
|
+
<IconButton
|
|
41
|
+
size={isPhone ? "xLarge" : "small"}
|
|
42
|
+
color="neutral"
|
|
43
|
+
variant="ghost"
|
|
44
|
+
className={css`
|
|
45
|
+
position: absolute;
|
|
46
|
+
inset: 20px 20px auto auto;
|
|
47
|
+
z-index: 1;
|
|
48
|
+
`}
|
|
49
|
+
onClick={onUnzoom as () => void}
|
|
50
|
+
>
|
|
51
|
+
<Close />
|
|
52
|
+
</IconButton>
|
|
53
|
+
);
|
|
54
|
+
return (
|
|
55
|
+
<>
|
|
56
|
+
<div
|
|
57
|
+
onMouseMove={() => {
|
|
58
|
+
imagesGalleryMethods.setVisible(true);
|
|
59
|
+
}}
|
|
60
|
+
className={css`
|
|
61
|
+
position: absolute;
|
|
62
|
+
inset: 0;
|
|
63
|
+
`}
|
|
64
|
+
>
|
|
65
|
+
{img}
|
|
66
|
+
{button}
|
|
67
|
+
</div>
|
|
68
|
+
<Controls />
|
|
69
|
+
</>
|
|
70
|
+
);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
type Props = {
|
|
74
|
+
zoomed: boolean;
|
|
75
|
+
onZoomedChange: (value: boolean) => void;
|
|
76
|
+
children: ReactNode;
|
|
77
|
+
className?: string;
|
|
78
|
+
openOnClick?: boolean;
|
|
79
|
+
zoomImg?: {src: string; alt?: string};
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export const Zoom = (props: Props) => {
|
|
83
|
+
const {zoomed, onZoomedChange, children, className, openOnClick, zoomImg} = props;
|
|
84
|
+
const imagesGalleryMethods = useImagesGalleryMethods();
|
|
85
|
+
const onClick = useCallback(() => {
|
|
86
|
+
if (zoomed) {
|
|
87
|
+
onZoomedChange(false);
|
|
88
|
+
} else if (openOnClick) {
|
|
89
|
+
onZoomedChange(true);
|
|
90
|
+
}
|
|
91
|
+
}, [zoomed, onZoomedChange, openOnClick]);
|
|
92
|
+
|
|
93
|
+
const onDoubleClick = useCallback(() => {
|
|
94
|
+
if (!zoomed) {
|
|
95
|
+
onZoomedChange(true);
|
|
96
|
+
}
|
|
97
|
+
}, [zoomed, onZoomedChange]);
|
|
98
|
+
|
|
99
|
+
return (
|
|
100
|
+
<div className={className} onClick={onClick} onDoubleClick={openOnClick ? undefined : onDoubleClick}>
|
|
101
|
+
<Controlled
|
|
102
|
+
zoomImg={zoomImg}
|
|
103
|
+
onZoomChange={imagesGalleryMethods.update}
|
|
104
|
+
classDialog={dialogCss}
|
|
105
|
+
isZoomed={zoomed}
|
|
106
|
+
ZoomContent={ZoomContent}
|
|
107
|
+
>
|
|
108
|
+
{children}
|
|
109
|
+
</Controlled>
|
|
110
|
+
</div>
|
|
111
|
+
);
|
|
112
|
+
};
|
package/src/is-in-popup.ts
CHANGED
package/src/layout-styles.ts
CHANGED
|
@@ -5,18 +5,38 @@ import {
|
|
|
5
5
|
sidebarMenuItemHeightVar,
|
|
6
6
|
sidebarMenuIconSizeVar,
|
|
7
7
|
textStyles,
|
|
8
|
+
menuItemHeightVar,
|
|
8
9
|
} from "./design-system";
|
|
9
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
keyboardHeightVar,
|
|
12
|
+
keyboardInsetBottomVar,
|
|
13
|
+
mobileRootClassName,
|
|
14
|
+
safeAreaInsetLeftVar,
|
|
15
|
+
safeAreaInsetRightVar,
|
|
16
|
+
safeAreaInsetTopVar,
|
|
17
|
+
safeAreaInsetBottomVar,
|
|
18
|
+
} from "./mobile-styles";
|
|
10
19
|
|
|
11
20
|
export const layoutStyles = css`
|
|
12
21
|
:global() {
|
|
13
22
|
html:root {
|
|
23
|
+
${safeAreaInsetLeftVar}: var(--app-safe-area-inset-left, env(safe-area-inset-left));
|
|
24
|
+
${safeAreaInsetRightVar}: var(--app-safe-area-inset-right, env(safe-area-inset-right));
|
|
25
|
+
${safeAreaInsetTopVar}: var(--app-safe-area-inset-top, env(safe-area-inset-top));
|
|
26
|
+
${safeAreaInsetBottomVar}: var(--app-safe-area-inset-bottom, env(safe-area-inset-bottom));
|
|
27
|
+
${keyboardInsetBottomVar}: var(--app-current-keyboard-height, 0px);
|
|
28
|
+
${keyboardHeightVar}: 350px;
|
|
29
|
+
|
|
30
|
+
${menuItemHeightVar}: ${layout.menuItemHeight}px;
|
|
14
31
|
${sidebarMenuItemHeightVar}: ${layout.newMenuItemHeight}px;
|
|
15
32
|
${sidebarMenuIconSizeVar}: ${layout.newMenuIconSize}px;
|
|
16
33
|
${listRowSurfaceFontSizeVar}: ${textStyles.regular.fontSize}px;
|
|
34
|
+
|
|
17
35
|
&.${mobileRootClassName} {
|
|
36
|
+
${menuItemHeightVar}: ${layout.mobileMenuItemHeight}px;
|
|
18
37
|
${sidebarMenuItemHeightVar}: ${layout.mobileSidebarMenuItemHeight}px;
|
|
19
38
|
${sidebarMenuIconSizeVar}: ${layout.mobileSidebarIconSize}px;
|
|
39
|
+
${listRowSurfaceFontSizeVar}: ${textStyles.big.fontSize}px;
|
|
20
40
|
}
|
|
21
41
|
}
|
|
22
42
|
}
|
|
@@ -7,6 +7,7 @@ import {useActionsMenuContext} from "../actions-menu";
|
|
|
7
7
|
import {ActionsMenuItemProps} from "../actions-menu/actions-menu-item";
|
|
8
8
|
import {useActiveDangerousRow, useSetActiveDangerousRow} from "../actions-menu/contexts/actions-menu-dangerous-rows";
|
|
9
9
|
import {colors, layout, lineHeight, space, textStyles, themeVars} from "../design-system";
|
|
10
|
+
import {useIsSupportHover} from "../use-is-support-hover";
|
|
10
11
|
import {
|
|
11
12
|
ListRowContent,
|
|
12
13
|
ListRowContentProps,
|
|
@@ -66,6 +67,7 @@ export const actionMenuItemSurface = css`
|
|
|
66
67
|
export const ActionMenuItemSurface = forwardRef<HTMLDivElement, ActionMenuItemSurfaceProps>(
|
|
67
68
|
({testId, className, loading, selected, hovered, focused, title, disabled, children, dangerous, ...props}, ref) => {
|
|
68
69
|
const id = useId();
|
|
70
|
+
const platformSupportsHover = useIsSupportHover();
|
|
69
71
|
const activeDangerousRow = useActiveDangerousRow();
|
|
70
72
|
const showWarning = activeDangerousRow === id;
|
|
71
73
|
const onSelect = useCallbackRef(props.onSelect || _.noop);
|
|
@@ -100,7 +102,7 @@ export const ActionMenuItemSurface = forwardRef<HTMLDivElement, ActionMenuItemSu
|
|
|
100
102
|
listRowSurfaceStylesBase,
|
|
101
103
|
actionMenuItemSurface,
|
|
102
104
|
className,
|
|
103
|
-
hovered === undefined && NATURAL_HOVER_CLASS,
|
|
105
|
+
platformSupportsHover && hovered === undefined && NATURAL_HOVER_CLASS,
|
|
104
106
|
focused === undefined && NATURAL_FOCUS_CLASS,
|
|
105
107
|
focused && "focus",
|
|
106
108
|
disabled && "done",
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import {css, cx} from "@linaria/core";
|
|
2
2
|
import {ForwardedRef, forwardRef, HTMLAttributes, PropsWithChildren, ReactNode} from "react";
|
|
3
3
|
import {border, layoutVars, space, textStyles, themeVars, transition} from "../design-system";
|
|
4
|
+
import {useIsSupportHover} from "../use-is-support-hover";
|
|
5
|
+
import {mobileRootSelector} from "../mobile-styles";
|
|
4
6
|
|
|
5
7
|
interface ListRowSurfaceBase extends HTMLAttributes<HTMLDivElement> {
|
|
6
8
|
testId?: string;
|
|
@@ -152,6 +154,7 @@ export const listRowSurfaceStatesDark = css`
|
|
|
152
154
|
|
|
153
155
|
export const ListRowSurface = forwardRef<HTMLDivElement, ListRowSurfaceProps>(
|
|
154
156
|
({selected, focused, darker, hovered, done, className, children, ...rest}, ref) => {
|
|
157
|
+
const platformSupportsHover = useIsSupportHover();
|
|
155
158
|
return (
|
|
156
159
|
<div
|
|
157
160
|
{...rest}
|
|
@@ -159,7 +162,7 @@ export const ListRowSurface = forwardRef<HTMLDivElement, ListRowSurfaceProps>(
|
|
|
159
162
|
listRowSurfaceStylesBase,
|
|
160
163
|
darker ? listRowSurfaceStatesDark : listRowSurfaceStatesDefault,
|
|
161
164
|
className,
|
|
162
|
-
hovered === undefined && NATURAL_HOVER_CLASS,
|
|
165
|
+
platformSupportsHover && hovered === undefined && NATURAL_HOVER_CLASS,
|
|
163
166
|
focused === undefined && NATURAL_FOCUS_CLASS,
|
|
164
167
|
focused && "focus",
|
|
165
168
|
hovered && "hover",
|
|
@@ -204,6 +207,9 @@ const ListRowContentSegment = css`
|
|
|
204
207
|
min-width: 0; // allows ellipsis in flex contexts :)
|
|
205
208
|
max-width: 100%;
|
|
206
209
|
width: 100%;
|
|
210
|
+
${mobileRootSelector} & {
|
|
211
|
+
${textStyles.big}
|
|
212
|
+
}
|
|
207
213
|
`;
|
|
208
214
|
export const ListRowContent = forwardRef<HTMLDivElement, ListRowContentProps>(
|
|
209
215
|
(
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import {ReactNode, useEffect, useRef} from "react";
|
|
2
|
+
import {createPortal} from "react-dom";
|
|
3
|
+
import _ from "lodash";
|
|
4
|
+
import {css, cx} from "@linaria/core";
|
|
5
|
+
import {border, space, themeVars} from "./design-system";
|
|
6
|
+
import {keyboardInsetBottomVar, safeAreaInsetBottomVar} from "./mobile-styles";
|
|
7
|
+
|
|
8
|
+
export const mobileKeyboardAwarePopupZIndex = 1001;
|
|
9
|
+
|
|
10
|
+
export function MobileKeyboardAwarePopup({children, className}: {children: ReactNode; className?: string}) {
|
|
11
|
+
const ref = useRef<HTMLDivElement>(null);
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
const viewport = window.visualViewport;
|
|
14
|
+
if (!viewport) {
|
|
15
|
+
return _.noop;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const manualKeyboardModeHandler = document.documentElement.classList.contains("fibery-manual-keyboard-mode");
|
|
19
|
+
|
|
20
|
+
let pendingUpdate = false;
|
|
21
|
+
const layoutViewport = document.getElementById("root") as HTMLDivElement;
|
|
22
|
+
const timeoutId = setTimeout(() => {
|
|
23
|
+
if (viewport.offsetTop >= 0 && ref.current) {
|
|
24
|
+
ref.current.style.transform = `translateY(${
|
|
25
|
+
manualKeyboardModeHandler
|
|
26
|
+
? viewport.offsetTop
|
|
27
|
+
: viewport.height - layoutViewport.getBoundingClientRect().height + viewport.offsetTop
|
|
28
|
+
}px)`;
|
|
29
|
+
}
|
|
30
|
+
}, 0);
|
|
31
|
+
|
|
32
|
+
function viewportHandler() {
|
|
33
|
+
clearTimeout(timeoutId);
|
|
34
|
+
if (pendingUpdate) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
pendingUpdate = true;
|
|
38
|
+
|
|
39
|
+
requestAnimationFrame(() => {
|
|
40
|
+
pendingUpdate = false;
|
|
41
|
+
|
|
42
|
+
if (viewport && viewport.offsetTop >= 0 && ref.current) {
|
|
43
|
+
ref.current.style.transform = `translateY(${
|
|
44
|
+
manualKeyboardModeHandler
|
|
45
|
+
? viewport.offsetTop
|
|
46
|
+
: viewport.height - layoutViewport.getBoundingClientRect().height + viewport.offsetTop
|
|
47
|
+
}px)`;
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
viewport.addEventListener("scroll", viewportHandler);
|
|
53
|
+
viewport.addEventListener("resize", viewportHandler);
|
|
54
|
+
return () => {
|
|
55
|
+
clearTimeout(timeoutId);
|
|
56
|
+
viewport.removeEventListener("scroll", viewportHandler);
|
|
57
|
+
viewport.removeEventListener("resize", viewportHandler);
|
|
58
|
+
};
|
|
59
|
+
}, []);
|
|
60
|
+
return createPortal(
|
|
61
|
+
<div
|
|
62
|
+
ref={ref}
|
|
63
|
+
className={cx(
|
|
64
|
+
css`
|
|
65
|
+
box-shadow: ${themeVars.shadow200};
|
|
66
|
+
background-color: ${themeVars.actionMenuBg};
|
|
67
|
+
position: fixed;
|
|
68
|
+
bottom: max(max(var(${keyboardInsetBottomVar}), var(${safeAreaInsetBottomVar})), 8px);
|
|
69
|
+
left: 0;
|
|
70
|
+
right: 0;
|
|
71
|
+
z-index: ${mobileKeyboardAwarePopupZIndex};
|
|
72
|
+
transform: translateY(0px);
|
|
73
|
+
border-radius: ${border.radius16}px;
|
|
74
|
+
border: 1px solid ${themeVars.separatorColor};
|
|
75
|
+
margin: 0 ${space.s8}px;
|
|
76
|
+
.fibery-manual-keyboard-mode & {
|
|
77
|
+
margin-bottom: 8px;
|
|
78
|
+
}
|
|
79
|
+
`,
|
|
80
|
+
className
|
|
81
|
+
)}
|
|
82
|
+
>
|
|
83
|
+
{children}
|
|
84
|
+
</div>,
|
|
85
|
+
document.body
|
|
86
|
+
);
|
|
87
|
+
}
|
package/src/mobile-styles.ts
CHANGED
|
@@ -1,2 +1,10 @@
|
|
|
1
1
|
export const mobileRootClassName = "fibery-mobile";
|
|
2
2
|
export const mobileRootSelector = `.${mobileRootClassName}`;
|
|
3
|
+
export const mobileKeyboardOpenClassName = "fibery-mobile-keyboard-open";
|
|
4
|
+
export const mobileKeyboardOpenSelector = `.${mobileKeyboardOpenClassName}`;
|
|
5
|
+
export const keyboardHeightVar = "--fibery-on-screen-keyboard-height";
|
|
6
|
+
export const safeAreaInsetLeftVar = "--safe-area-inset-left";
|
|
7
|
+
export const safeAreaInsetRightVar = "--safe-area-inset-right";
|
|
8
|
+
export const safeAreaInsetTopVar = "--safe-area-inset-top";
|
|
9
|
+
export const safeAreaInsetBottomVar = "--safe-area-inset-bottom";
|
|
10
|
+
export const keyboardInsetBottomVar = "--keyboard-inset-bottom";
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {createContext} from "@fibery/react/src/create-context";
|
|
2
|
+
|
|
3
|
+
export type SubmenuItem = {
|
|
4
|
+
id: string;
|
|
5
|
+
title: string;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export type ModalMenuContext = {
|
|
9
|
+
open: boolean;
|
|
10
|
+
title: string;
|
|
11
|
+
submenuStack: SubmenuItem[];
|
|
12
|
+
contentContainer: HTMLDivElement | null;
|
|
13
|
+
setContentContainer: (el: HTMLDivElement | null) => void;
|
|
14
|
+
onOpenSubmenu: (item: SubmenuItem) => void;
|
|
15
|
+
onNavigateBack: () => void;
|
|
16
|
+
onOpenChange: (open: boolean) => void;
|
|
17
|
+
height?: string;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const [ModalMenuContextProvider, useModalMenu] = createContext<ModalMenuContext>("ModalMenuContext");
|
|
21
|
+
|
|
22
|
+
export {ModalMenuContextProvider, useModalMenu};
|