reshaped 3.9.0-canary.2 → 3.9.0-canary.24
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/dist/bundle.css +1 -1
- package/dist/bundle.d.ts +2 -0
- package/dist/bundle.js +2 -31
- package/dist/components/Actionable/Actionable.module.css +1 -1
- package/dist/components/Autocomplete/Autocomplete.js +2 -2
- package/dist/components/Autocomplete/Autocomplete.types.d.ts +1 -1
- package/dist/components/Avatar/Avatar.js +7 -24
- package/dist/components/Avatar/Avatar.module.css +1 -1
- package/dist/components/Badge/Badge.js +2 -2
- package/dist/components/Badge/Badge.module.css +1 -1
- package/dist/components/Badge/Badge.types.d.ts +1 -1
- package/dist/components/Button/Button.module.css +1 -1
- package/dist/components/Calendar/Calendar.module.css +1 -1
- package/dist/components/Calendar/Calendar.types.d.ts +19 -6
- package/dist/components/Calendar/CalendarControlled.js +43 -8
- package/dist/components/Calendar/CalendarControls.js +9 -9
- package/dist/components/Calendar/CalendarDate.js +9 -7
- package/dist/components/Calendar/CalendarMonth.js +2 -2
- package/dist/components/Card/Card.d.ts +1 -1
- package/dist/components/Card/Card.types.d.ts +5 -5
- package/dist/components/Checkbox/Checkbox.js +2 -12
- package/dist/components/DropdownMenu/DropdownMenu.types.d.ts +1 -1
- package/dist/components/FileUpload/FileUpload.js +7 -5
- package/dist/components/FileUpload/FileUpload.module.css +1 -1
- package/dist/components/FileUpload/FileUpload.types.d.ts +2 -0
- package/dist/components/Flyout/Flyout.constants.d.ts +3 -3
- package/dist/components/Flyout/Flyout.constants.js +1 -0
- package/dist/components/Flyout/Flyout.module.css +1 -1
- package/dist/components/Flyout/Flyout.types.d.ts +8 -7
- package/dist/components/Flyout/FlyoutContent.js +4 -3
- package/dist/components/Flyout/FlyoutControlled.js +33 -11
- package/dist/components/Flyout/useFlyout.d.ts +2 -2
- package/dist/components/Flyout/useFlyout.js +8 -21
- package/dist/components/Flyout/utilities/calculatePosition.d.ts +6 -6
- package/dist/components/Flyout/utilities/calculatePosition.js +24 -17
- package/dist/components/Flyout/utilities/constants.d.ts +1 -0
- package/dist/components/Flyout/utilities/constants.js +1 -0
- package/dist/components/Flyout/utilities/flyout.js +37 -6
- package/dist/components/Flyout/utilities/isFullyVisible.d.ts +4 -3
- package/dist/components/Flyout/utilities/isFullyVisible.js +5 -4
- package/dist/components/Grid/Grid.types.d.ts +4 -4
- package/dist/components/HiddenInput/HiddenInput.js +33 -0
- package/dist/components/HiddenInput/HiddenInput.types.d.ts +26 -0
- package/dist/components/Image/Image.js +13 -8
- package/dist/components/Image/Image.module.css +1 -1
- package/dist/components/Image/Image.types.d.ts +3 -1
- package/dist/components/Modal/Modal.js +2 -5
- package/dist/components/Modal/Modal.module.css +1 -1
- package/dist/components/Popover/Popover.module.css +1 -1
- package/dist/components/Popover/Popover.types.d.ts +1 -1
- package/dist/components/Radio/Radio.js +2 -12
- package/dist/components/Reshaped/Reshaped.css +1 -1
- package/dist/components/Scrim/Scrim.js +4 -3
- package/dist/components/Scrim/Scrim.module.css +1 -1
- package/dist/components/Scrim/Scrim.types.d.ts +2 -1
- package/dist/components/ScrollArea/ScrollArea.js +7 -7
- package/dist/components/Slider/SliderControlled.js +4 -4
- package/dist/components/Tabs/Tabs.module.css +1 -1
- package/dist/components/Tabs/Tabs.types.d.ts +3 -1
- package/dist/components/Tabs/TabsContext.d.ts +1 -0
- package/dist/components/Tabs/TabsControlled.js +2 -1
- package/dist/components/Tabs/TabsItem.js +3 -3
- package/dist/components/Tabs/TabsList.js +9 -5
- package/dist/components/Tabs/TabsPanel.js +1 -1
- package/dist/components/Text/Text.d.ts +1 -1
- package/dist/components/Text/Text.js +2 -2
- package/dist/components/Text/Text.module.css +1 -1
- package/dist/components/Text/Text.types.d.ts +5 -3
- package/dist/components/Tooltip/Tooltip.js +2 -2
- package/dist/components/Tooltip/Tooltip.module.css +1 -1
- package/dist/components/Tooltip/Tooltip.types.d.ts +1 -1
- package/dist/components/View/View.types.d.ts +4 -4
- package/dist/hooks/_private/useDrag.js +0 -3
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/types/global.d.ts +1 -1
- package/dist/utilities/dom/index.d.ts +0 -1
- package/dist/utilities/dom/index.js +0 -1
- package/dist/utilities/scroll/disable.js +4 -2
- package/package.json +4 -98
- package/README.md +0 -24
- package/dist/components/_private/HiddenInput/HiddenInput.js +0 -10
- package/dist/components/_private/HiddenInput/HiddenInput.types.d.ts +0 -15
- package/dist/utilities/dom/userSelect.d.ts +0 -2
- package/dist/utilities/dom/userSelect.js +0 -6
- /package/dist/components/{_private/HiddenInput → HiddenInput}/HiddenInput.d.ts +0 -0
- /package/dist/components/{_private/HiddenInput → HiddenInput}/HiddenInput.module.css +0 -0
- /package/dist/components/{_private/HiddenInput → HiddenInput}/HiddenInput.types.js +0 -0
- /package/dist/components/{_private/HiddenInput → HiddenInput}/index.d.ts +0 -0
- /package/dist/components/{_private/HiddenInput → HiddenInput}/index.js +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import React from "react";
|
|
4
|
-
import HiddenInput from "../_private/HiddenInput/index.js";
|
|
5
4
|
import { useCheckboxGroup } from "../CheckboxGroup/index.js";
|
|
6
5
|
import { useFormControl } from "../FormControl/index.js";
|
|
6
|
+
import HiddenInput from "../HiddenInput/index.js";
|
|
7
7
|
import Icon from "../Icon/index.js";
|
|
8
8
|
import Text from "../Text/index.js";
|
|
9
9
|
import useIsomorphicLayoutEffect from "../../hooks/useIsomorphicLayoutEffect.js";
|
|
@@ -21,20 +21,10 @@ const Checkbox = (props) => {
|
|
|
21
21
|
const name = checkboxGroup ? checkboxGroup.name : props.name;
|
|
22
22
|
const inputRef = React.useRef(null);
|
|
23
23
|
const rootClassName = classNames(s.root, className, size && hasError && s["--error"], disabled && s["--disabled"], size && responsiveClassNames(s, "--size", size));
|
|
24
|
-
const handleChange = (event) => {
|
|
25
|
-
if (!name)
|
|
26
|
-
return;
|
|
27
|
-
const { checked } = event.target;
|
|
28
|
-
const changeArgs = { name, value, checked, event };
|
|
29
|
-
if (onChange)
|
|
30
|
-
onChange(changeArgs);
|
|
31
|
-
if (checkboxGroup?.onChange)
|
|
32
|
-
checkboxGroup.onChange(changeArgs);
|
|
33
|
-
};
|
|
34
24
|
useIsomorphicLayoutEffect(() => {
|
|
35
25
|
inputRef.current.indeterminate = indeterminate || false;
|
|
36
26
|
}, [indeterminate, checked]);
|
|
37
|
-
return (_jsxs("label", { ...attributes, className: rootClassName, children: [_jsxs("span", { className: s.field, children: [_jsx(HiddenInput, { className: s.input, type: "checkbox", checked: checked, defaultChecked: defaultChecked, name: name, disabled: disabled, value: value, onChange:
|
|
27
|
+
return (_jsxs("label", { ...attributes, className: rootClassName, children: [_jsxs("span", { className: s.field, children: [_jsx(HiddenInput, { className: s.input, type: "checkbox", checked: checked, defaultChecked: defaultChecked, name: name, disabled: disabled, value: value, onChange: onChange, onFocus: onFocus, onBlur: onBlur, attributes: {
|
|
38
28
|
...inputAttributes,
|
|
39
29
|
ref: inputRef,
|
|
40
30
|
} }), _jsx("div", { className: s.decorator, children: _jsx(Icon, { svg: IconCheckmark, className: s.icon, size: responsivePropDependency(size, (size) => {
|
|
@@ -3,7 +3,7 @@ import type { MenuItemProps } from "../MenuItem";
|
|
|
3
3
|
import type { PopoverProps, PopoverInstance } from "../Popover";
|
|
4
4
|
import type React from "react";
|
|
5
5
|
export type Instance = PopoverInstance;
|
|
6
|
-
export type Props = Pick<PopoverProps, "children" | "position" | "forcePosition" | "fallbackPositions" | "fallbackAdjustLayout" | "fallbackMinWidth" | "fallbackMinHeight" | "triggerType" | "contentGap" | "contentShift" | "onOpen" | "onClose" | "active" | "defaultActive" | "width" | "disableHideAnimation" | "disableCloseOnOutsideClick" | "instanceRef" | "containerRef" | "positionRef" | "originCoordinates" | "borderRadius" | "elevation" | "initialFocusRef"> & {
|
|
6
|
+
export type Props = Pick<PopoverProps, "children" | "position" | "forcePosition" | "fallbackPositions" | "fallbackAdjustLayout" | "fallbackMinWidth" | "fallbackMinHeight" | "triggerType" | "contentGap" | "contentShift" | "contentMaxHeight" | "onOpen" | "onClose" | "active" | "defaultActive" | "width" | "disableHideAnimation" | "disableCloseOnOutsideClick" | "instanceRef" | "containerRef" | "positionRef" | "originCoordinates" | "borderRadius" | "elevation" | "initialFocusRef"> & {
|
|
7
7
|
/** Change component trap focus keyboard behavior and shortcuts */
|
|
8
8
|
trapFocusMode?: Extract<PopoverProps["trapFocusMode"], "action-menu" | "selection-menu"> | false;
|
|
9
9
|
};
|
|
@@ -10,9 +10,9 @@ export const FileUploadTrigger = (props) => {
|
|
|
10
10
|
return _jsx("span", { className: s.trigger, children: children });
|
|
11
11
|
};
|
|
12
12
|
const FileUpload = (props) => {
|
|
13
|
-
const { name, children, height, variant = "outline", inline, className, attributes, inputAttributes, onChange, } = props;
|
|
13
|
+
const { name, children, height, variant = "outline", inline, className, disabled, attributes, inputAttributes, onChange, } = props;
|
|
14
14
|
const highlightToggle = useToggle();
|
|
15
|
-
const rootClassNames = classNames(s.root, variant && s[`--variant-${variant}`], inline && s[`--inline`], highlightToggle.active && s["--highlighted"], className);
|
|
15
|
+
const rootClassNames = classNames(s.root, variant && s[`--variant-${variant}`], inline && s[`--inline`], highlightToggle.active && s["--highlighted"], disabled && s["--disabled"], className);
|
|
16
16
|
const handleDragOver = (event) => {
|
|
17
17
|
event.preventDefault();
|
|
18
18
|
attributes?.onDragOver?.(event);
|
|
@@ -41,15 +41,17 @@ const FileUpload = (props) => {
|
|
|
41
41
|
onChange?.({ name, event, value: Array.from(nextValue) });
|
|
42
42
|
inputAttributes?.onChange?.(event);
|
|
43
43
|
};
|
|
44
|
-
const inputNode = (_jsx(HiddenVisually, { children: _jsx("input", { ...inputAttributes, type: "file", className: s.field, name: name, onChange: handleChange }) }));
|
|
44
|
+
const inputNode = (_jsx(HiddenVisually, { children: _jsx("input", { ...inputAttributes, type: "file", className: s.field, name: name, disabled: disabled, onChange: handleChange }) }));
|
|
45
45
|
const childrenNode = typeof children === "function" ? children({ highlighted: highlightToggle.active }) : children;
|
|
46
|
-
return (_jsx(View, { className: rootClassNames, height: height,
|
|
46
|
+
return (_jsx(View, { className: rootClassNames, height: height,
|
|
47
|
+
// For the focus ring radius
|
|
48
|
+
borderRadius: "medium", attributes: {
|
|
47
49
|
...attributes,
|
|
48
50
|
onDragOver: handleDragOver,
|
|
49
51
|
onDragEnter: handleDragEnter,
|
|
50
52
|
onDragLeave: handleDragLeave,
|
|
51
53
|
onDrop: handleDrop,
|
|
52
|
-
}, children: variant === "outline" && !inline ? (_jsxs(View, { as: "label", className: s.triggerLayer, padding: 6, borderRadius: "medium", gap: 2, align: "center", justify: "center", textAlign: "center",
|
|
54
|
+
}, children: variant === "outline" && !inline ? (_jsxs(View, { as: "label", className: s.triggerLayer, padding: 6, borderRadius: "medium", gap: 2, align: "center", justify: "center", textAlign: "center", height: "100%", children: [inputNode, _jsx(View.Item, { children: childrenNode })] })) : (_jsxs("label", { className: s.triggerLayer, children: [inputNode, childrenNode] })) }));
|
|
53
55
|
};
|
|
54
56
|
FileUpload.displayName = "FileUpload";
|
|
55
57
|
FileUploadTrigger.displayName = "FileUpload.Trigger";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
.root{--rs-file-upload-radius:var(--rs-radius-medium);display:block}[data-rs-keyboard] .root:focus-within{box-shadow:var(--rs-shadow-focus)}.--inline{--rs-file-upload-radius:var(--rs-radius-small)}.--inline,.--inline .triggerLayer{display:inline-block;vertical-align:top}[data-rs-keyboard] .--inline:focus-within{box-shadow:none}[data-rs-keyboard] .--inline:focus-within .triggerLayer>*{box-shadow:var(--rs-shadow-focus)}.--variant-outline .triggerLayer{border:1px dashed var(--rs-
|
|
1
|
+
.root{--rs-file-upload-radius:var(--rs-radius-medium);--rs-file-upload-border-color:var(--rs-color-border-neutral);--rs-file-upload-hover-background-color:rgba(var(--rs-color-rgb-background-neutral),0.16);display:block}[data-rs-keyboard] .root:focus-within{box-shadow:var(--rs-shadow-focus)}.triggerLayer:has(.trigger){pointer-events:none}.triggerLayer:has(.trigger) .trigger,.triggerLayer:has(.trigger) a,.triggerLayer:has(.trigger) button{pointer-events:all}.trigger{display:contents}.--inline{--rs-file-upload-radius:var(--rs-radius-small)}.--inline,.--inline .triggerLayer{display:inline-block;vertical-align:top}[data-rs-keyboard] .--inline:focus-within{box-shadow:none}[data-rs-keyboard] .--inline:focus-within .triggerLayer>*{box-shadow:var(--rs-shadow-focus)}.--variant-outline .triggerLayer{border:1px dashed var(--rs-file-upload-border-color);border-radius:var(--rs-file-upload-radius);transition:var(--rs-duration-fast) var(--rs-easing-standard);transition-property:background-color,border-color}.--highlighted.--variant-outline .triggerLayer{background:rgba(var(--rs-color-rgb-background-primary),.08);border-color:var(--rs-color-border-primary)}@media (hover:hover) and (pointer:fine){.--variant-outline .triggerLayer:hover:not(:has(.trigger)){background:var(--rs-file-upload-hover-background-color)}}.--disabled{--rs-file-upload-border-color:var(--rs-color-border-disabled);--rs-file-upload-hover-background-color:transparent}.--disabled .triggerLayer{cursor:not-allowed;opacity:.4}
|
|
@@ -4,6 +4,8 @@ import type * as G from "../../types/global";
|
|
|
4
4
|
export type Props = {
|
|
5
5
|
/** Name of the input element */
|
|
6
6
|
name: string;
|
|
7
|
+
/** Disable the file upload input */
|
|
8
|
+
disabled?: boolean;
|
|
7
9
|
/** Node for inserting children, can be a render function that receives component state */
|
|
8
10
|
children?: React.ReactNode | ((props: {
|
|
9
11
|
highlighted?: boolean;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type * as T from "./Flyout.types";
|
|
2
1
|
export declare const mouseEnter = 600;
|
|
3
|
-
export declare const
|
|
4
|
-
export declare const
|
|
2
|
+
export declare const mouseLeave = 150;
|
|
3
|
+
export declare const defaultStyles: React.CSSProperties;
|
|
4
|
+
export declare const resetStyles: React.CSSProperties;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
.content{--rs-flyout-gap:0;--rs-flyout-origin-x:50%;--rs-flyout-origin-y:50%;isolation:isolate;pointer-events:none;position:absolute}.content.--hover{pointer-events:all}.content.--hover-disabled,.content.--hover-disabled .inner{pointer-events:none}.inner{backface-visibility:hidden;height:100%;max-height:
|
|
1
|
+
.content{--rs-flyout-gap:0;--rs-flyout-max-h:100%;--rs-flyout-max-w:100%;--rs-flyout-origin-x:50%;--rs-flyout-origin-y:50%;display:flex;flex-direction:column;isolation:isolate;pointer-events:none;position:absolute}.content.--hover{pointer-events:all}.content.--hover-disabled,.content.--hover-disabled .inner{pointer-events:none}.inner{backface-visibility:hidden;flex-grow:1;height:100%;max-height:var(--rs-flyout-max-h);max-width:var(--rs-flyout-max-w);opacity:0;outline:none;overflow:auto;pointer-events:all;transform:scale(.92) translateY(0);transform-origin:var(--rs-flyout-origin-x) var(--rs-flyout-origin-y);transition:1ms var(--rs-easing-accelerate)}[data-rs-keyboard] .inner:focus{box-shadow:var(--rs-shadow-focus)}.content.--width-trigger .inner{transform:scale(1) translateY(var(--rs-unit-x2))}.content.--position-top,.content.--position-top-end,.content.--position-top-start{--rs-flyout-origin-y:100%;padding-bottom:calc(var(--rs-unit-x1) * var(--rs-flyout-gap))}.content.--position-bottom,.content.--position-bottom-end,.content.--position-bottom-start{--rs-flyout-origin-y:0%;padding-top:calc(var(--rs-unit-x1) * var(--rs-flyout-gap))}.content.--position-bottom-start,.content.--position-top-start{--rs-flyout-origin-x:0%}.content.--position-bottom-end,.content.--position-top-end{--rs-flyout-origin-x:100%}.content.--position-start,.content.--position-start-bottom,.content.--position-start-top{--rs-flyout-origin-x:100%;padding-right:calc(var(--rs-unit-x1) * var(--rs-flyout-gap))}.content.--position-end,.content.--position-end-bottom,.content.--position-end-top{--rs-flyout-origin-x:0%;padding-left:calc(var(--rs-unit-x1) * var(--rs-flyout-gap))}.content.--position-end-top,.content.--position-start-top{--rs-flyout-origin-y:0%}.content.--position-end-bottom,.content.--position-start-bottom{--rs-flyout-origin-y:100%}.content.--visible .inner{opacity:1;transform:scale(1) translateY(0)}.content.--animated .inner{transition-duration:var(--rs-duration-rapid);transition-property:opacity,transform}.content.--animated.--visible .inner{transition-duration:var(--rs-duration-fast);transition-timing-function:var(--rs-easing-decelerate)}
|
|
@@ -23,17 +23,14 @@ export type Options = Pick<BaseProps, "width" | "fallbackAdjustLayout" | "fallba
|
|
|
23
23
|
lastUsedPosition: Position;
|
|
24
24
|
onPositionChoose: (position: Position) => void;
|
|
25
25
|
};
|
|
26
|
-
export type Styles = React.CSSProperties;
|
|
27
26
|
export type State = {
|
|
28
|
-
styles: Styles;
|
|
29
27
|
position?: Position;
|
|
30
28
|
status: "idle" | "rendered" | "positioned" | "visible" | "hidden";
|
|
31
29
|
};
|
|
32
30
|
export type FlyoutData = {
|
|
33
|
-
styles: Styles;
|
|
34
31
|
position: Position;
|
|
35
32
|
};
|
|
36
|
-
export type UseFlyoutData = Pick<State, "
|
|
33
|
+
export type UseFlyoutData = Pick<State, "position" | "status"> & {
|
|
37
34
|
updatePosition: (args?: {
|
|
38
35
|
sync?: boolean;
|
|
39
36
|
fallback?: boolean;
|
|
@@ -72,7 +69,7 @@ export type TriggerAttributes = {
|
|
|
72
69
|
onFocus?: () => void;
|
|
73
70
|
onMouseDown?: () => void;
|
|
74
71
|
onMouseEnter?: () => void;
|
|
75
|
-
onMouseLeave?: () => void;
|
|
72
|
+
onMouseLeave?: (e: React.MouseEvent) => void;
|
|
76
73
|
onTouchStart?: () => void;
|
|
77
74
|
onClick?: () => void;
|
|
78
75
|
"aria-describedby"?: string;
|
|
@@ -132,6 +129,10 @@ type BaseProps = {
|
|
|
132
129
|
contentGap?: number;
|
|
133
130
|
/** Shift the content on the secondary axis, relative to its original position */
|
|
134
131
|
contentShift?: number;
|
|
132
|
+
/** Maximum height for the content */
|
|
133
|
+
contentMaxHeight?: string;
|
|
134
|
+
/** Maximum width for the content */
|
|
135
|
+
contentMaxWidth?: string;
|
|
135
136
|
/** Additional classname for the content element */
|
|
136
137
|
contentClassName?: string;
|
|
137
138
|
/** Additional attributes for the content element */
|
|
@@ -178,7 +179,7 @@ export type ContextProps = {
|
|
|
178
179
|
}) => void;
|
|
179
180
|
handleOpen: () => void;
|
|
180
181
|
handleMouseEnter: () => void;
|
|
181
|
-
handleMouseLeave: () => void;
|
|
182
|
+
handleMouseLeave: (e: React.MouseEvent) => void;
|
|
182
183
|
handleMouseDown: () => void;
|
|
183
184
|
handleTransitionEnd: (e: React.TransitionEvent) => void;
|
|
184
185
|
handleTransitionStart: (e: TransitionEvent) => void;
|
|
@@ -189,7 +190,7 @@ export type ContextProps = {
|
|
|
189
190
|
handleContentMouseDown: () => void;
|
|
190
191
|
handleContentMouseUp: () => void;
|
|
191
192
|
isSubmenu: boolean;
|
|
192
|
-
} & Pick<Props, "triggerType" | "contentClassName" | "contentAttributes" | "contentGap" | "trapFocusMode" | "containerRef" | "disableContentHover" | "autoFocus">;
|
|
193
|
+
} & Pick<Props, "triggerType" | "contentClassName" | "contentAttributes" | "contentGap" | "contentMaxHeight" | "contentMaxWidth" | "trapFocusMode" | "containerRef" | "disableContentHover" | "autoFocus">;
|
|
193
194
|
export type TriggerContextProps = {
|
|
194
195
|
elRef?: ContextProps["triggerElRef"];
|
|
195
196
|
};
|
|
@@ -11,8 +11,8 @@ import s from "./Flyout.module.css";
|
|
|
11
11
|
import cooldown from "./utilities/cooldown.js";
|
|
12
12
|
const FlyoutContent = (props) => {
|
|
13
13
|
const { children, className, attributes } = props;
|
|
14
|
-
const { flyout, id, flyoutElRef, triggerElRef, handleClose, handleTransitionEnd, handleTransitionStart, triggerType, handleMouseEnter, handleMouseLeave, handleContentMouseDown, handleContentMouseUp, contentClassName, contentAttributes, contentGap, trapFocusMode, disableContentHover, autoFocus, width, containerRef: passedContainerRef, isSubmenu, } = useFlyoutContext();
|
|
15
|
-
const {
|
|
14
|
+
const { flyout, id, flyoutElRef, triggerElRef, handleClose, handleTransitionEnd, handleTransitionStart, triggerType, handleMouseEnter, handleMouseLeave, handleContentMouseDown, handleContentMouseUp, contentClassName, contentAttributes, contentGap, contentMaxHeight, contentMaxWidth, trapFocusMode, disableContentHover, autoFocus, width, containerRef: passedContainerRef, isSubmenu, } = useFlyoutContext();
|
|
15
|
+
const { status, position } = flyout;
|
|
16
16
|
const [mounted, setMounted] = React.useState(false);
|
|
17
17
|
const closestFixedContainer = React.useMemo(() => {
|
|
18
18
|
if (!mounted)
|
|
@@ -95,8 +95,9 @@ const FlyoutContent = (props) => {
|
|
|
95
95
|
role = "menubar";
|
|
96
96
|
}
|
|
97
97
|
const content = (_jsx(ContentProvider, { value: { elRef: flyoutElRef }, children: _jsx("div", { className: rootClassNames, style: {
|
|
98
|
-
...styles,
|
|
99
98
|
"--rs-flyout-gap": contentGap,
|
|
99
|
+
"--rs-flyout-max-h": contentMaxHeight,
|
|
100
|
+
"--rs-flyout-max-w": contentMaxWidth,
|
|
100
101
|
}, ref: flyoutElRef, onTransitionEnd: handleTransitionEnd, onMouseEnter: triggerType === "hover" ? handleMouseEnter : undefined, onMouseLeave: triggerType === "hover" ? handleMouseLeave : undefined, onMouseDown: handleContentMouseDown, onTouchStart: handleContentMouseDown, onMouseUp: handleContentMouseUp, onTouchEnd: handleContentMouseUp, children: _jsx("div", { role: role, ...attributes, id: id, tabIndex: !autoFocus ? -1 : undefined, "aria-modal": role === "dialog" ? true : undefined, style: { ...attributes?.style, ...contentAttributes?.style }, className: innerClassNames, children: children }) }) }));
|
|
101
102
|
return _jsx(Portal, { targetRef: containerRef, children: content });
|
|
102
103
|
};
|
|
@@ -15,7 +15,7 @@ import { Provider, useFlyoutTriggerContext, useFlyoutContext, useFlyoutContentCo
|
|
|
15
15
|
import useFlyout from "./useFlyout.js";
|
|
16
16
|
import cooldown from "./utilities/cooldown.js";
|
|
17
17
|
const FlyoutControlled = (props) => {
|
|
18
|
-
const { triggerType = "click", groupTimeouts, onOpen, onClose, children, disabled, forcePosition, fallbackAdjustLayout, fallbackMinWidth, fallbackMinHeight, trapFocusMode = "dialog", width, disableHideAnimation, disableContentHover, disableCloseOnOutsideClick, autoFocus = true, originCoordinates, contentGap = 2, contentShift, contentClassName, contentAttributes, position: passedPosition, active: passedActive, id: passedId, instanceRef, containerRef, initialFocusRef, positionRef, } = props;
|
|
18
|
+
const { triggerType = "click", groupTimeouts, onOpen, onClose, children, disabled, forcePosition, fallbackAdjustLayout, fallbackMinWidth, fallbackMinHeight, trapFocusMode = "dialog", width, disableHideAnimation, disableContentHover, disableCloseOnOutsideClick, autoFocus = true, originCoordinates, contentGap = 2, contentShift, contentMaxHeight, contentMaxWidth, contentClassName, contentAttributes, position: passedPosition, active: passedActive, id: passedId, instanceRef, containerRef, initialFocusRef, positionRef, } = props;
|
|
19
19
|
const fallbackPositions = props.fallbackPositions === false || forcePosition ? [] : props.fallbackPositions;
|
|
20
20
|
const onOpenRef = useHandlerRef(onOpen);
|
|
21
21
|
const onCloseRef = useHandlerRef(onClose);
|
|
@@ -55,12 +55,13 @@ const FlyoutControlled = (props) => {
|
|
|
55
55
|
// Touch devices trigger onMouseEnter but we don't need to apply regular hover timeouts
|
|
56
56
|
// So we're saving a flag on touch start and then change the mouse enter behavior
|
|
57
57
|
const hoverTriggeredWithTouchEventRef = React.useRef(false);
|
|
58
|
+
const originCoordinatesRef = React.useRef(originCoordinates ?? null);
|
|
58
59
|
// eslint-disable-next-line react-hooks/refs
|
|
60
|
+
originCoordinatesRef.current = originCoordinates ?? null;
|
|
59
61
|
const flyout = useFlyout({
|
|
60
62
|
triggerElRef: positionRef ?? triggerElRef,
|
|
61
63
|
flyoutElRef,
|
|
62
|
-
|
|
63
|
-
triggerBounds: originCoordinates ?? triggerBoundsRef.current,
|
|
64
|
+
triggerBoundsRef: originCoordinates ? originCoordinatesRef : triggerBoundsRef,
|
|
64
65
|
width,
|
|
65
66
|
position: passedPosition,
|
|
66
67
|
defaultActive: resolvedActive,
|
|
@@ -103,7 +104,7 @@ const FlyoutControlled = (props) => {
|
|
|
103
104
|
return;
|
|
104
105
|
onCloseRef.current?.({ reason: options.reason });
|
|
105
106
|
if (options?.closeParents) {
|
|
106
|
-
parentFlyoutContext?.handleClose?.({});
|
|
107
|
+
parentFlyoutContext?.handleClose?.({ closeParents: true, reason: options.reason });
|
|
107
108
|
}
|
|
108
109
|
}, [isRendered, isDismissible, triggerType, onCloseRef, disabled, parentFlyoutContext]);
|
|
109
110
|
/**
|
|
@@ -143,14 +144,31 @@ const FlyoutControlled = (props) => {
|
|
|
143
144
|
cooldown.warm();
|
|
144
145
|
timerRef.current = setTimeout(() => {
|
|
145
146
|
handleOpen();
|
|
146
|
-
}, groupTimeouts && cooldown.status === "warming"
|
|
147
|
+
}, groupTimeouts && cooldown.status === "warming"
|
|
148
|
+
? timeouts.mouseEnter
|
|
149
|
+
: isSubmenu
|
|
150
|
+
? timeouts.mouseEnter
|
|
151
|
+
: 0);
|
|
147
152
|
}
|
|
148
|
-
}, [clearTimer, handleOpen, groupTimeouts]);
|
|
149
|
-
const handleMouseLeave = React.useCallback(() => {
|
|
153
|
+
}, [clearTimer, handleOpen, groupTimeouts, isSubmenu]);
|
|
154
|
+
const handleMouseLeave = React.useCallback((e) => {
|
|
155
|
+
if (e.relatedTarget === flyoutElRef.current ||
|
|
156
|
+
(e.relatedTarget instanceof Node && flyoutElRef.current?.contains(e.relatedTarget)))
|
|
157
|
+
return;
|
|
158
|
+
if (e.relatedTarget === triggerElRef.current ||
|
|
159
|
+
(e.relatedTarget instanceof Node && triggerElRef.current?.contains(e.relatedTarget)))
|
|
160
|
+
return;
|
|
150
161
|
cooldown.cool();
|
|
151
162
|
clearTimer();
|
|
152
|
-
|
|
153
|
-
|
|
163
|
+
if (isSubmenu) {
|
|
164
|
+
timerRef.current = setTimeout(() => {
|
|
165
|
+
handleClose({});
|
|
166
|
+
}, timeouts.mouseLeave);
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
handleClose({});
|
|
170
|
+
}
|
|
171
|
+
}, [clearTimer, handleClose, triggerElRef, flyoutElRef, isSubmenu]);
|
|
154
172
|
const handleTriggerClick = React.useCallback(() => {
|
|
155
173
|
if (!isRendered) {
|
|
156
174
|
handleOpen();
|
|
@@ -286,8 +304,10 @@ const FlyoutControlled = (props) => {
|
|
|
286
304
|
resizeObserver.observe(document.body);
|
|
287
305
|
if (triggerElRef.current)
|
|
288
306
|
resizeObserver.observe(triggerElRef.current);
|
|
307
|
+
if (flyoutElRef.current)
|
|
308
|
+
resizeObserver.observe(flyoutElRef.current);
|
|
289
309
|
return () => resizeObserver.disconnect();
|
|
290
|
-
}, [updatePosition, triggerElRef, isRendered]);
|
|
310
|
+
}, [updatePosition, triggerElRef, isRendered, flyoutElRef]);
|
|
291
311
|
React.useEffect(() => {
|
|
292
312
|
updatePosition({ sync: true });
|
|
293
313
|
}, [isRTL, updatePosition]);
|
|
@@ -305,7 +325,7 @@ const FlyoutControlled = (props) => {
|
|
|
305
325
|
shouldReturnFocusRef.current = false;
|
|
306
326
|
handleClose({ reason: "outside-click" });
|
|
307
327
|
}, {
|
|
308
|
-
disabled:
|
|
328
|
+
disabled: !isRendered || disableCloseOnOutsideClick,
|
|
309
329
|
});
|
|
310
330
|
return (_jsx(Provider, { value: {
|
|
311
331
|
id,
|
|
@@ -331,6 +351,8 @@ const FlyoutControlled = (props) => {
|
|
|
331
351
|
contentClassName,
|
|
332
352
|
contentAttributes,
|
|
333
353
|
contentGap,
|
|
354
|
+
contentMaxHeight,
|
|
355
|
+
contentMaxWidth,
|
|
334
356
|
containerRef,
|
|
335
357
|
disableContentHover,
|
|
336
358
|
autoFocus,
|
|
@@ -6,8 +6,8 @@ type UseFlyout = (args: Pick<T.Props, "width" | "position" | "defaultActive" | "
|
|
|
6
6
|
container?: HTMLElement | null;
|
|
7
7
|
triggerElRef: React.RefObject<HTMLElement | null>;
|
|
8
8
|
flyoutElRef: React.RefObject<HTMLElement | null>;
|
|
9
|
-
|
|
10
|
-
}) => Pick<T.State, "
|
|
9
|
+
triggerBoundsRef: React.RefObject<DOMRect | G.Coordinates | null>;
|
|
10
|
+
}) => Pick<T.State, "position" | "status"> & {
|
|
11
11
|
updatePosition: (options?: {
|
|
12
12
|
sync?: boolean;
|
|
13
13
|
}) => void;
|
|
@@ -1,43 +1,32 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import useRTL from "../../hooks/useRTL.js";
|
|
3
|
-
import { defaultStyles, resetStyles } from "./Flyout.constants.js";
|
|
4
3
|
import flyout from "./utilities/flyout.js";
|
|
5
4
|
const flyoutReducer = (state, action) => {
|
|
6
5
|
switch (action.type) {
|
|
7
6
|
case "render":
|
|
8
|
-
if (state.status !== "idle")
|
|
9
|
-
return state;
|
|
10
7
|
// Disable events before it's positioned to avoid mouseleave getting triggered
|
|
11
|
-
return { ...state, status: "rendered"
|
|
8
|
+
return { ...state, status: "rendered" };
|
|
12
9
|
case "position":
|
|
13
|
-
if (!action.payload.sync && state.status !== "rendered")
|
|
14
|
-
return state;
|
|
15
|
-
if (action.payload.sync && state.status !== "visible")
|
|
16
|
-
return state;
|
|
17
10
|
return {
|
|
18
11
|
...state,
|
|
19
|
-
status: action.payload.sync ?
|
|
12
|
+
status: action.payload.sync ? state.status : "positioned",
|
|
20
13
|
position: action.payload.position,
|
|
21
|
-
styles: { ...defaultStyles, ...action.payload.styles },
|
|
22
14
|
};
|
|
23
15
|
case "show":
|
|
16
|
+
// Checking because we're positioning inside nextAnimationFrame
|
|
24
17
|
if (state.status !== "positioned")
|
|
25
18
|
return state;
|
|
26
19
|
return { ...state, status: "visible" };
|
|
27
20
|
case "hide":
|
|
28
|
-
if (state.status !== "visible")
|
|
29
|
-
return state;
|
|
30
21
|
return { ...state, status: "hidden" };
|
|
31
22
|
case "remove":
|
|
32
|
-
|
|
33
|
-
return state;
|
|
34
|
-
return { ...state, status: "idle", styles: resetStyles };
|
|
23
|
+
return { ...state, status: "idle" };
|
|
35
24
|
default:
|
|
36
25
|
throw new Error("[Reshaped] Invalid flyout reducer type");
|
|
37
26
|
}
|
|
38
27
|
};
|
|
39
28
|
const useFlyout = (args) => {
|
|
40
|
-
const { triggerElRef, flyoutElRef,
|
|
29
|
+
const { triggerElRef, flyoutElRef, triggerBoundsRef, contentGap, contentShift, ...options } = args;
|
|
41
30
|
const { position: defaultPosition = "bottom", fallbackPositions, fallbackAdjustLayout, fallbackMinWidth, fallbackMinHeight, width, container, } = options;
|
|
42
31
|
const lastUsedPositionRef = React.useRef(defaultPosition);
|
|
43
32
|
// Memo the array internally to avoid new arrays triggering useCallback
|
|
@@ -47,7 +36,6 @@ const useFlyout = (args) => {
|
|
|
47
36
|
const [isRTL] = useRTL();
|
|
48
37
|
const [state, dispatch] = React.useReducer(flyoutReducer, {
|
|
49
38
|
position: defaultPosition,
|
|
50
|
-
styles: defaultStyles,
|
|
51
39
|
status: "idle",
|
|
52
40
|
});
|
|
53
41
|
const render = React.useCallback(() => {
|
|
@@ -72,7 +60,7 @@ const useFlyout = (args) => {
|
|
|
72
60
|
const nextFlyoutData = flyout({
|
|
73
61
|
triggerEl: triggerElRef.current,
|
|
74
62
|
flyoutEl: flyoutElRef.current,
|
|
75
|
-
triggerBounds,
|
|
63
|
+
triggerBounds: triggerBoundsRef.current,
|
|
76
64
|
width,
|
|
77
65
|
position: changePositon ? defaultPosition : lastUsedPositionRef.current,
|
|
78
66
|
fallbackPositions: changePositon ? cachedFallbackPositions : [],
|
|
@@ -100,7 +88,7 @@ const useFlyout = (args) => {
|
|
|
100
88
|
isRTL,
|
|
101
89
|
flyoutElRef,
|
|
102
90
|
triggerElRef,
|
|
103
|
-
|
|
91
|
+
triggerBoundsRef,
|
|
104
92
|
width,
|
|
105
93
|
contentGap,
|
|
106
94
|
contentShift,
|
|
@@ -114,13 +102,12 @@ const useFlyout = (args) => {
|
|
|
114
102
|
}, [state.status, updatePosition]);
|
|
115
103
|
return React.useMemo(() => ({
|
|
116
104
|
position: state.position,
|
|
117
|
-
styles: state.styles,
|
|
118
105
|
status: state.status,
|
|
119
106
|
updatePosition,
|
|
120
107
|
render,
|
|
121
108
|
hide,
|
|
122
109
|
remove,
|
|
123
110
|
show,
|
|
124
|
-
}), [render, updatePosition, hide, remove, show, state.position, state.
|
|
111
|
+
}), [render, updatePosition, hide, remove, show, state.position, state.status]);
|
|
125
112
|
};
|
|
126
113
|
export default useFlyout;
|
|
@@ -13,13 +13,13 @@ declare const calculatePosition: (args: {
|
|
|
13
13
|
} & Pick<T.Options, "position" | "rtl" | "width" | "contentGap" | "contentShift" | "fallbackAdjustLayout" | "fallbackMinWidth" | "fallbackMinHeight">) => {
|
|
14
14
|
position: T.Position;
|
|
15
15
|
styles: {
|
|
16
|
-
left:
|
|
17
|
-
right:
|
|
18
|
-
top:
|
|
19
|
-
bottom:
|
|
16
|
+
left: string | null;
|
|
17
|
+
right: string | null;
|
|
18
|
+
top: string | null;
|
|
19
|
+
bottom: string | null;
|
|
20
20
|
transform: string;
|
|
21
|
-
height:
|
|
22
|
-
width: string |
|
|
21
|
+
height: string | null;
|
|
22
|
+
width: string | null;
|
|
23
23
|
};
|
|
24
24
|
boundaries: {
|
|
25
25
|
left: number;
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import { SCREEN_OFFSET } from "./constants.js";
|
|
1
2
|
import { getRTLPosition, centerBySize } from "./helpers.js";
|
|
2
|
-
const SCREEN_OFFSET = 8;
|
|
3
3
|
/**
|
|
4
4
|
* Calculate styles for the current position
|
|
5
5
|
*/
|
|
6
6
|
const calculatePosition = (args) => {
|
|
7
|
-
const { triggerBounds, flyoutBounds, containerBounds, position: passedPosition, rtl, width: passedWidth, contentGap = 0, contentShift = 0, passedContainer, fallbackAdjustLayout,
|
|
7
|
+
const { triggerBounds, flyoutBounds, containerBounds, position: passedPosition, rtl, width: passedWidth, contentGap = 0, contentShift = 0, passedContainer, fallbackAdjustLayout,
|
|
8
|
+
// fallbackMinWidth,
|
|
9
|
+
fallbackMinHeight, } = args;
|
|
8
10
|
const isFullWidth = passedWidth === "full" || passedWidth === "100%";
|
|
9
11
|
let left = 0;
|
|
10
12
|
let top = 0;
|
|
@@ -137,15 +139,20 @@ const calculatePosition = (args) => {
|
|
|
137
139
|
if (bottom !== null)
|
|
138
140
|
bottom = bottom + (flyoutHeight - height);
|
|
139
141
|
}
|
|
140
|
-
if
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
142
|
+
// TODO: Decide if we need horizontal scrolling for the fallbacks, might be a bad practice anyways
|
|
143
|
+
// if (updatedOverflow.left > 0) {
|
|
144
|
+
// width = Math.max(
|
|
145
|
+
// fallbackMinWidth ? parseInt(fallbackMinWidth) : 0,
|
|
146
|
+
// flyoutWidth - updatedOverflow.left
|
|
147
|
+
// );
|
|
148
|
+
// left = left + (flyoutWidth - width);
|
|
149
|
+
// } else if (updatedOverflow.right > 0) {
|
|
150
|
+
// width = Math.max(
|
|
151
|
+
// fallbackMinWidth ? parseInt(fallbackMinWidth) : 0,
|
|
152
|
+
// flyoutWidth - updatedOverflow.right
|
|
153
|
+
// );
|
|
154
|
+
// if (right !== null) right = right + (flyoutWidth - width);
|
|
155
|
+
// }
|
|
149
156
|
}
|
|
150
157
|
if (isFullWidth) {
|
|
151
158
|
left = SCREEN_OFFSET;
|
|
@@ -159,13 +166,13 @@ const calculatePosition = (args) => {
|
|
|
159
166
|
return {
|
|
160
167
|
position,
|
|
161
168
|
styles: {
|
|
162
|
-
left: right === null ?
|
|
163
|
-
right: right === null ?
|
|
164
|
-
top: bottom === null ?
|
|
165
|
-
bottom: bottom === null ?
|
|
169
|
+
left: right === null ? "0px" : null,
|
|
170
|
+
right: right === null ? null : "0px",
|
|
171
|
+
top: bottom === null ? "0px" : null,
|
|
172
|
+
bottom: bottom === null ? null : "0px",
|
|
166
173
|
transform: `translate(${translateX}px, ${translateY}px)`,
|
|
167
|
-
height,
|
|
168
|
-
width: width ??
|
|
174
|
+
height: height !== undefined ? `${height}px` : null,
|
|
175
|
+
width: width !== undefined ? `${width}px` : (passedWidth ?? null),
|
|
169
176
|
},
|
|
170
177
|
boundaries: {
|
|
171
178
|
left,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const SCREEN_OFFSET = 8;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const SCREEN_OFFSET = 8;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getRectFromCoordinates, getShadowRoot, findClosestPositionContainer } from "../../../utilities/dom/index.js";
|
|
2
2
|
import { resetStyles } from "../Flyout.constants.js";
|
|
3
3
|
import calculatePosition from "./calculatePosition.js";
|
|
4
|
+
import { SCREEN_OFFSET } from "./constants.js";
|
|
4
5
|
import getPositionFallbacks from "./getPositionFallbacks.js";
|
|
5
6
|
import isFullyVisible from "./isFullyVisible.js";
|
|
6
7
|
/**
|
|
@@ -33,16 +34,26 @@ const flyout = (args) => {
|
|
|
33
34
|
const shadowRoot = triggerEl && getShadowRoot(triggerEl);
|
|
34
35
|
// Insert inside shadow root if possible to make sure styles are applied correctly
|
|
35
36
|
(shadowRoot || document.body).appendChild(targetClone);
|
|
36
|
-
const cloneRect = targetClone.getBoundingClientRect();
|
|
37
|
-
const flyoutBounds = { width: cloneRect.width, height: cloneRect.height };
|
|
38
37
|
const closestFixedContainer = !passedContainer && triggerEl ? findClosestPositionContainer({ el: triggerEl }) : undefined;
|
|
39
38
|
const container = passedContainer ||
|
|
40
39
|
// Render inside fixed position container automatically to keep their position synced on scroll
|
|
41
40
|
closestFixedContainer ||
|
|
42
41
|
document.body;
|
|
43
42
|
const renderContainerBounds = container.getBoundingClientRect();
|
|
44
|
-
const
|
|
45
|
-
|
|
43
|
+
const applyPosition = (position, options) => {
|
|
44
|
+
const widthOption = options?.width || width;
|
|
45
|
+
// If there is a width override, apply it to calculate the position and the height correctly
|
|
46
|
+
if (widthOption === "full") {
|
|
47
|
+
targetClone.style.width = `calc(100% - ${SCREEN_OFFSET * 2}px)`;
|
|
48
|
+
}
|
|
49
|
+
else if (widthOption === "trigger") {
|
|
50
|
+
targetClone.style.width = `${resolvedTriggerBounds.width}px`;
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
targetClone.style.width = widthOption || "";
|
|
54
|
+
}
|
|
55
|
+
const cloneRect = targetClone.getBoundingClientRect();
|
|
56
|
+
const flyoutBounds = { width: cloneRect.width, height: cloneRect.height };
|
|
46
57
|
return calculatePosition({
|
|
47
58
|
triggerBounds: resolvedTriggerBounds,
|
|
48
59
|
flyoutBounds,
|
|
@@ -51,7 +62,7 @@ const flyout = (args) => {
|
|
|
51
62
|
contentGap: contentGap * unitModifier,
|
|
52
63
|
contentShift: contentShift * unitModifier,
|
|
53
64
|
rtl,
|
|
54
|
-
width,
|
|
65
|
+
width: widthOption,
|
|
55
66
|
passedContainer: passedContainer ||
|
|
56
67
|
(closestFixedContainer !== document.body ? closestFixedContainer : undefined),
|
|
57
68
|
fallbackAdjustLayout,
|
|
@@ -60,6 +71,12 @@ const flyout = (args) => {
|
|
|
60
71
|
});
|
|
61
72
|
};
|
|
62
73
|
const testVisibility = (calculated) => {
|
|
74
|
+
const visualContainerBounds = passedContainer?.getBoundingClientRect() ?? {
|
|
75
|
+
width: window.innerWidth,
|
|
76
|
+
height: window.innerHeight,
|
|
77
|
+
left: window.scrollX,
|
|
78
|
+
top: window.scrollY,
|
|
79
|
+
};
|
|
63
80
|
return isFullyVisible({
|
|
64
81
|
flyoutBounds: calculated.boundaries,
|
|
65
82
|
visualContainerBounds,
|
|
@@ -75,10 +92,24 @@ const flyout = (args) => {
|
|
|
75
92
|
calculated = tested;
|
|
76
93
|
return visible;
|
|
77
94
|
});
|
|
95
|
+
// Try full width positions in case it doesn't fit on any side
|
|
96
|
+
if (!calculated) {
|
|
97
|
+
const smallScreenFallbackPositions = ["top", "bottom"].filter((position) => testOrder.includes(position));
|
|
98
|
+
smallScreenFallbackPositions.some((position) => {
|
|
99
|
+
const tested = applyPosition(position, { width: "full" });
|
|
100
|
+
const visible = testVisibility(tested);
|
|
101
|
+
if (visible)
|
|
102
|
+
calculated = tested;
|
|
103
|
+
return visible;
|
|
104
|
+
});
|
|
105
|
+
}
|
|
78
106
|
if (!calculated)
|
|
79
107
|
calculated = applyPosition(lastUsedPosition);
|
|
80
108
|
onPositionChoose(calculated.position);
|
|
81
109
|
targetClone.parentNode?.removeChild(targetClone);
|
|
82
|
-
|
|
110
|
+
Object.entries(calculated.styles).forEach(([key, value]) => {
|
|
111
|
+
flyoutEl.style.setProperty(key, value);
|
|
112
|
+
});
|
|
113
|
+
return { position: calculated.position };
|
|
83
114
|
};
|
|
84
115
|
export default flyout;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
+
type Bounds = Pick<DOMRect, "left" | "top" | "width" | "height">;
|
|
1
2
|
/**
|
|
2
3
|
* Check if element visually fits within its render container
|
|
3
4
|
*/
|
|
4
5
|
declare const isFullyVisible: (args: {
|
|
5
6
|
/** Bounds of the flyout content */
|
|
6
|
-
flyoutBounds:
|
|
7
|
+
flyoutBounds: Bounds;
|
|
7
8
|
/** Bounds of the container where the flyout content should fit */
|
|
8
|
-
visualContainerBounds:
|
|
9
|
+
visualContainerBounds: Bounds;
|
|
9
10
|
/** Bounds of the container where flyout content is rendered */
|
|
10
|
-
renderContainerBounds:
|
|
11
|
+
renderContainerBounds: Bounds;
|
|
11
12
|
}) => boolean;
|
|
12
13
|
export default isFullyVisible;
|
|
@@ -1,20 +1,21 @@
|
|
|
1
|
+
import { SCREEN_OFFSET } from "./constants.js";
|
|
1
2
|
/**
|
|
2
3
|
* Check if element visually fits within its render container
|
|
3
4
|
*/
|
|
4
5
|
const isFullyVisible = (args) => {
|
|
5
6
|
const { flyoutBounds, visualContainerBounds, renderContainerBounds } = args;
|
|
6
|
-
if (renderContainerBounds.left + flyoutBounds.left < visualContainerBounds.left) {
|
|
7
|
+
if (renderContainerBounds.left + flyoutBounds.left < visualContainerBounds.left + SCREEN_OFFSET) {
|
|
7
8
|
return false;
|
|
8
9
|
}
|
|
9
|
-
if (renderContainerBounds.top + flyoutBounds.top < visualContainerBounds.top) {
|
|
10
|
+
if (renderContainerBounds.top + flyoutBounds.top < visualContainerBounds.top + SCREEN_OFFSET) {
|
|
10
11
|
return false;
|
|
11
12
|
}
|
|
12
13
|
if (renderContainerBounds.left + flyoutBounds.left + flyoutBounds.width >
|
|
13
|
-
visualContainerBounds.
|
|
14
|
+
visualContainerBounds.left + visualContainerBounds.width - SCREEN_OFFSET) {
|
|
14
15
|
return false;
|
|
15
16
|
}
|
|
16
17
|
if (renderContainerBounds.top + flyoutBounds.top + flyoutBounds.height >
|
|
17
|
-
visualContainerBounds.
|
|
18
|
+
visualContainerBounds.top + visualContainerBounds.height - SCREEN_OFFSET) {
|
|
18
19
|
return false;
|
|
19
20
|
}
|
|
20
21
|
return true;
|