reshaped 2.11.10 → 2.11.11
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 +3 -0
- package/bundle.css +1 -1
- package/bundle.js +8 -8
- package/components/Alert/Alert.js +1 -1
- package/components/Modal/Modal.js +3 -2
- package/components/Modal/Modal.module.css +1 -1
- package/components/Modal/Modal.types.d.ts +2 -0
- package/components/Modal/tests/Modal.stories.d.ts +2 -1
- package/components/Modal/tests/Modal.stories.js +3 -0
- package/components/Overlay/Overlay.js +5 -1
- package/components/Tooltip/Tooltip.js +3 -1
- package/components/Tooltip/Tooltip.types.d.ts +3 -2
- package/components/Tooltip/tests/Tooltip.stories.d.ts +1 -0
- package/components/Tooltip/tests/Tooltip.stories.js +20 -1
- package/components/_private/Flyout/Flyout.types.d.ts +35 -5
- package/components/_private/Flyout/FlyoutControlled.js +23 -18
- package/components/_private/Flyout/useFlyout.d.ts +21 -0
- package/{hooks/_private → components/_private/Flyout}/useFlyout.js +33 -120
- package/components/_private/Flyout/utilities/calculatePosition.d.ts +18 -0
- package/components/_private/Flyout/utilities/calculatePosition.js +97 -0
- package/package.json +1 -1
- package/utilities/a11y/TrapFocus.d.ts +1 -0
- package/utilities/a11y/TrapFocus.js +3 -3
- package/hooks/_private/useFlyout.d.ts +0 -27
|
@@ -14,7 +14,7 @@ const Alert = (props) => {
|
|
|
14
14
|
const applyActions = (content) => {
|
|
15
15
|
if (!actionsSlot)
|
|
16
16
|
return content;
|
|
17
|
-
return (_jsxs(View, { gap: 2, direction: inline ? "row" : "column", children: [inline ? _jsx(View.Item, { grow: true, children: content }) : content, actionsSlot && (_jsx(Text, { variant: "body-3", weight: "medium", children: _jsx(View, { direction: "row", gap: 3, children: actionsSlot }) }))] }));
|
|
17
|
+
return (_jsxs(View, { gap: inline ? 4 : 2, direction: inline ? "row" : "column", children: [inline ? _jsx(View.Item, { grow: true, children: content }) : content, actionsSlot && (_jsx(Text, { variant: "body-3", weight: "medium", children: _jsx(View, { direction: "row", gap: 3, children: actionsSlot }) }))] }));
|
|
18
18
|
};
|
|
19
19
|
return (_jsx(View, { direction: "row", gap: 3, padding: 4, bleed: bleed, borderRadius: "medium", borderColor: `${color}-faded`, backgroundColor: `${color}-faded`, className: className, attributes: Object.assign(Object.assign({}, attributes), { role: color === "critical" ? "alert" : "status" }), children: icon ? (_jsxs(_Fragment, { children: [_jsx(Icon, { svg: icon, size: 5, color: isNeutral ? "primary" : color }), _jsx(View.Item, { grow: true, children: applyActions(renderContent()) })] })) : (applyActions(renderContent())) }));
|
|
20
20
|
};
|
|
@@ -39,7 +39,7 @@ const ModalSubtitle = (props) => {
|
|
|
39
39
|
return (_jsx(Text, { variant: "body-3", color: "neutral-faded", attributes: { id: `${id}-subtitle` }, children: children }));
|
|
40
40
|
};
|
|
41
41
|
const Modal = (props) => {
|
|
42
|
-
const { children, onClose, active, size, padding = 4, position = "center", transparentOverlay, overlayClassName, className, attributes, } = props;
|
|
42
|
+
const { children, onClose, active, size, padding = 4, position = "center", transparentOverlay, ariaLabel, autoFocus = true, overlayClassName, className, attributes, } = props;
|
|
43
43
|
const id = useElementId();
|
|
44
44
|
const clientPosition = useResponsiveClientValue(position);
|
|
45
45
|
const [titleMounted, setTitleMounted] = React.useState(false);
|
|
@@ -160,9 +160,10 @@ const Modal = (props) => {
|
|
|
160
160
|
onTouchStart: handleDragStart,
|
|
161
161
|
}, children: ({ active }) => {
|
|
162
162
|
const rootClassNames = classNames(s.root, className, paddingStyles === null || paddingStyles === void 0 ? void 0 : paddingStyles.classNames, active && s["--active"], dragging && s["--dragging"], responsiveClassNames(s, "--position", position));
|
|
163
|
+
console.log({ autoFocus });
|
|
163
164
|
return (_jsx(Context.Provider, { value: value, children: _jsx("div", Object.assign({}, attributes, { style: Object.assign(Object.assign(Object.assign({}, paddingStyles === null || paddingStyles === void 0 ? void 0 : paddingStyles.variables), responsiveVariables("--rs-modal-size", size)), { "--rs-modal-drag": Math.abs(dragDistance) < DRAG_THRESHOLD
|
|
164
165
|
? "0px"
|
|
165
|
-
: `${dragDistance + DRAG_THRESHOLD * (clientPosition === "start" ? 1 : -1)}px` }), "aria-labelledby": titleMounted ? `${id}-title` : undefined, "aria-describedby": subtitleMounted ? `${id}-subtitle` : undefined, className: rootClassNames, "aria-modal": "true", role: "dialog", ref: rootRef, onTransitionEnd: handleTransitionEnd, children: children })) }));
|
|
166
|
+
: `${dragDistance + DRAG_THRESHOLD * (clientPosition === "start" ? 1 : -1)}px` }), "aria-labelledby": titleMounted ? `${id}-title` : undefined, "aria-describedby": subtitleMounted ? `${id}-subtitle` : undefined, "aria-label": ariaLabel || (attributes === null || attributes === void 0 ? void 0 : attributes["aria-label"]), className: rootClassNames, "aria-modal": "true", role: "dialog", tabIndex: !autoFocus ? -1 : undefined, ref: rootRef, onTransitionEnd: handleTransitionEnd, children: children })) }));
|
|
166
167
|
} }));
|
|
167
168
|
};
|
|
168
169
|
Modal.Title = ModalTitle;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
.root{background:var(--rs-color-background-elevation-overlay);box-shadow:var(--rs-shadow-overlay);color:var(--rs-color-foreground-neutral);transition:var(--rs-easing-accelerate) var(--rs-duration-medium);transition-property:transform,opacity;will-change:transform}.--dragging{transition:none}.root{--rs-modal-size-s:calc(var(--rs-unit-x1) * 100);--rs-modal-size-m:var(--rs-modal-size-s);--rs-modal-size-l:var(--rs-modal-size-m);--rs-modal-size-xl:var(--rs-modal-size-l);--rs-modal-size:var(--rs-modal-size-s)}.--position-center{--rs-modal-size-s:calc(var(--rs-unit-x1) * 100);border-radius:var(--rs-unit-radius-large);height:auto;inset:0;margin:var(--rs-unit-x4);max-height:none;max-width:calc(100vw - var(--rs-unit-x8));opacity:0;overflow:hidden;position:relative;transform:scale(.96);width:var(--rs-modal-size)}.--position-center.--active,[dir=rtl] .--position-center.--active{opacity:1;transform:translate(0) scale(1)!important}.--position-bottom{--rs-modal-size-s:auto;border-radius:var(--rs-unit-radius-large) var(--rs-unit-radius-large) 0 0;height:var(--rs-modal-size);inset:0;inset-block-start:auto;margin:0;margin-top:var(--rs-unit-x4);max-height:calc(100vh - var(--rs-unit-x4));max-width:100%;opacity:1;overflow:auto;position:fixed;transform:translateY(100%);width:100%}.--position-bottom.--active,[dir=rtl] .--position-bottom.--active{transform:translateY(max(var(--rs-modal-drag,0px),0px)) scale(1)!important}.--position-start{--rs-modal-size-s:calc(var(--rs-unit-x1) * 100);border-radius:0;height:100%;inset:0;inset-inline-end:auto;margin:0;margin-inline-end:var(--rs-unit-x4);max-height:100%;max-width:calc(100vw - var(--rs-unit-x4));opacity:1;overflow:auto;position:fixed;transform:translate(-100%);width:var(--rs-modal-size)}[dir=rtl] .--position-start{transform:translate(100%)}.--position-start.--active,[dir=rtl] .--position-start.--active{transform:translate(min(var(--rs-modal-drag,0px),0px)) scale(1)!important}.--position-end{--rs-modal-size-s:calc(var(--rs-unit-x1) * 100);border-radius:0;height:100%;inset:0;inset-inline-start:auto;margin:0;margin-inline-start:var(--rs-unit-x4);max-height:100%;max-width:calc(100vw - var(--rs-unit-x4));opacity:1;overflow:auto;position:fixed;transform:translate(100%);width:var(--rs-modal-size)}[dir=rtl] .--position-end{transform:translate(-100%)}.--position-end.--active,[dir=rtl] .--position-end.--active{transform:translate(max(var(--rs-modal-drag,0px),0px)) scale(1)!important}.--position-full-screen{--rs-modal-size-s:100%;border-radius:0;height:100%;inset:0;inset-block-start:auto;margin:0;max-height:100%;max-width:100%;opacity:0;overflow:auto;position:fixed;transform:translateY(var(--rs-unit-x4));width:100%}.--position-full-screen.--active,[dir=rtl] .--position-full-screen.--active{opacity:1;transform:translate(0)!important}.--active,[dir=rtl] .--active{transition-timing-function:var(--rs-easing-decelerate)}@media (--rs-viewport-m ){.root{--rs-modal-size:var(--rs-modal-size-m)}.--position-center--m{--rs-modal-size-s:calc(var(--rs-unit-x1) * 100);border-radius:var(--rs-unit-radius-large);height:auto;inset:0;margin:var(--rs-unit-x4);max-height:none;max-width:calc(100vw - var(--rs-unit-x8));opacity:0;overflow:hidden;position:relative;transform:scale(.96);width:var(--rs-modal-size)}.--position-center--m.--active,[dir=rtl] .--position-center--m.--active{opacity:1;transform:translate(0) scale(1)!important}.--position-bottom--m{--rs-modal-size-s:auto;border-radius:var(--rs-unit-radius-large) var(--rs-unit-radius-large) 0 0;height:var(--rs-modal-size);inset:0;inset-block-start:auto;margin:0;margin-top:var(--rs-unit-x4);max-height:calc(100vh - var(--rs-unit-x4));max-width:100%;opacity:1;overflow:auto;position:fixed;transform:translateY(100%);width:100%}.--position-bottom--m.--active,[dir=rtl] .--position-bottom--m.--active{transform:translateY(max(var(--rs-modal-drag,0px),0px)) scale(1)!important}.--position-start--m{--rs-modal-size-s:calc(var(--rs-unit-x1) * 100);border-radius:0;height:100%;inset:0;inset-inline-end:auto;margin:0;margin-inline-end:var(--rs-unit-x4);max-height:100%;max-width:calc(100vw - var(--rs-unit-x4));opacity:1;overflow:auto;position:fixed;transform:translate(-100%);width:var(--rs-modal-size)}[dir=rtl] .--position-start--m{transform:translate(100%)}.--position-start--m.--active,[dir=rtl] .--position-start--m.--active{transform:translate(min(var(--rs-modal-drag,0px),0px)) scale(1)!important}.--position-end--m{--rs-modal-size-s:calc(var(--rs-unit-x1) * 100);border-radius:0;height:100%;inset:0;inset-inline-start:auto;margin:0;margin-inline-start:var(--rs-unit-x4);max-height:100%;max-width:calc(100vw - var(--rs-unit-x4));opacity:1;overflow:auto;position:fixed;transform:translate(100%);width:var(--rs-modal-size)}[dir=rtl] .--position-end--m{transform:translate(-100%)}.--position-end--m.--active,[dir=rtl] .--position-end--m.--active{transform:translate(max(var(--rs-modal-drag,0px),0px)) scale(1)!important}.--position-full-screen--m{--rs-modal-size-s:100%;border-radius:0;height:100%;inset:0;inset-block-start:auto;margin:0;max-height:100%;max-width:100%;opacity:0;overflow:auto;position:fixed;transform:translateY(var(--rs-unit-x4));width:100%}.--position-full-screen--m.--active,[dir=rtl] .--position-full-screen--m.--active{opacity:1;transform:translate(0)!important}}@media (--rs-viewport-l ){.root{--rs-modal-size:var(--rs-modal-size-l)}.--position-center--l{--rs-modal-size-s:calc(var(--rs-unit-x1) * 100);border-radius:var(--rs-unit-radius-large);height:auto;inset:0;margin:var(--rs-unit-x4);max-height:none;max-width:calc(100vw - var(--rs-unit-x8));opacity:0;overflow:hidden;position:relative;transform:scale(.96);width:var(--rs-modal-size)}.--position-center--l.--active,[dir=rtl] .--position-center--l.--active{opacity:1;transform:translate(0) scale(1)!important}.--position-bottom--l{--rs-modal-size-s:auto;border-radius:var(--rs-unit-radius-large) var(--rs-unit-radius-large) 0 0;height:var(--rs-modal-size);inset:0;inset-block-start:auto;margin:0;margin-top:var(--rs-unit-x4);max-height:calc(100vh - var(--rs-unit-x4));max-width:100%;opacity:1;overflow:auto;position:fixed;transform:translateY(100%);width:100%}.--position-bottom--l.--active,[dir=rtl] .--position-bottom--l.--active{transform:translateY(max(var(--rs-modal-drag,0px),0px)) scale(1)!important}.--position-start--l{--rs-modal-size-s:calc(var(--rs-unit-x1) * 100);border-radius:0;height:100%;inset:0;inset-inline-end:auto;margin:0;margin-inline-end:var(--rs-unit-x4);max-height:100%;max-width:calc(100vw - var(--rs-unit-x4));opacity:1;overflow:auto;position:fixed;transform:translate(-100%);width:var(--rs-modal-size)}[dir=rtl] .--position-start--l{transform:translate(100%)}.--position-start--l.--active,[dir=rtl] .--position-start--l.--active{transform:translate(min(var(--rs-modal-drag,0px),0px)) scale(1)!important}.--position-end--l{--rs-modal-size-s:calc(var(--rs-unit-x1) * 100);border-radius:0;height:100%;inset:0;inset-inline-start:auto;margin:0;margin-inline-start:var(--rs-unit-x4);max-height:100%;max-width:calc(100vw - var(--rs-unit-x4));opacity:1;overflow:auto;position:fixed;transform:translate(100%);width:var(--rs-modal-size)}[dir=rtl] .--position-end--l{transform:translate(-100%)}.--position-end--l.--active,[dir=rtl] .--position-end--l.--active{transform:translate(max(var(--rs-modal-drag,0px),0px)) scale(1)!important}.--position-full-screen--l{--rs-modal-size-s:100%;border-radius:0;height:100%;inset:0;inset-block-start:auto;margin:0;max-height:100%;max-width:100%;opacity:0;overflow:auto;position:fixed;transform:translateY(var(--rs-unit-x4));width:100%}.--position-full-screen--l.--active,[dir=rtl] .--position-full-screen--l.--active{opacity:1;transform:translate(0)!important}}@media (--rs-viewport-xl ){.root{--rs-modal-size:var(--rs-modal-size-xl)}.--position-center--xl{--rs-modal-size-s:calc(var(--rs-unit-x1) * 100);border-radius:var(--rs-unit-radius-large);height:auto;inset:0;margin:var(--rs-unit-x4);max-height:none;max-width:calc(100vw - var(--rs-unit-x8));opacity:0;overflow:hidden;position:relative;transform:scale(.96);width:var(--rs-modal-size)}.--position-center--xl.--active,[dir=rtl] .--position-center--xl.--active{opacity:1;transform:translate(0) scale(1)!important}.--position-bottom--xl{--rs-modal-size-s:auto;border-radius:var(--rs-unit-radius-large) var(--rs-unit-radius-large) 0 0;height:var(--rs-modal-size);inset:0;inset-block-start:auto;margin:0;margin-top:var(--rs-unit-x4);max-height:calc(100vh - var(--rs-unit-x4));max-width:100%;opacity:1;overflow:auto;position:fixed;transform:translateY(100%);width:100%}.--position-bottom--xl.--active,[dir=rtl] .--position-bottom--xl.--active{transform:translateY(max(var(--rs-modal-drag,0px),0px)) scale(1)!important}.--position-start--xl{--rs-modal-size-s:calc(var(--rs-unit-x1) * 100);border-radius:0;height:100%;inset:0;inset-inline-end:auto;margin:0;margin-inline-end:var(--rs-unit-x4);max-height:100%;max-width:calc(100vw - var(--rs-unit-x4));opacity:1;overflow:auto;position:fixed;transform:translate(-100%);width:var(--rs-modal-size)}[dir=rtl] .--position-start--xl{transform:translate(100%)}.--position-start--xl.--active,[dir=rtl] .--position-start--xl.--active{transform:translate(min(var(--rs-modal-drag,0px),0px)) scale(1)!important}.--position-end--xl{--rs-modal-size-s:calc(var(--rs-unit-x1) * 100);border-radius:0;height:100%;inset:0;inset-inline-start:auto;margin:0;margin-inline-start:var(--rs-unit-x4);max-height:100%;max-width:calc(100vw - var(--rs-unit-x4));opacity:1;overflow:auto;position:fixed;transform:translate(100%);width:var(--rs-modal-size)}[dir=rtl] .--position-end--xl{transform:translate(-100%)}.--position-end--xl.--active,[dir=rtl] .--position-end--xl.--active{transform:translate(max(var(--rs-modal-drag,0px),0px)) scale(1)!important}.--position-full-screen--xl{--rs-modal-size-s:100%;border-radius:0;height:100%;inset:0;inset-block-start:auto;margin:0;max-height:100%;max-width:100%;opacity:0;overflow:auto;position:fixed;transform:translateY(var(--rs-unit-x4));width:100%}.--position-full-screen--xl.--active,[dir=rtl] .--position-full-screen--xl.--active{opacity:1;transform:translate(0)!important}}
|
|
1
|
+
.root{background:var(--rs-color-background-elevation-overlay);box-shadow:var(--rs-shadow-overlay);color:var(--rs-color-foreground-neutral);transition:var(--rs-easing-accelerate) var(--rs-duration-medium);transition-property:transform,opacity;will-change:transform}.root:focus-visible{box-shadow:var(--rs-focus-shadow);outline:none}.--dragging{transition:none}.root{--rs-modal-size-s:calc(var(--rs-unit-x1) * 100);--rs-modal-size-m:var(--rs-modal-size-s);--rs-modal-size-l:var(--rs-modal-size-m);--rs-modal-size-xl:var(--rs-modal-size-l);--rs-modal-size:var(--rs-modal-size-s)}.--position-center{--rs-modal-size-s:calc(var(--rs-unit-x1) * 100);border-radius:var(--rs-unit-radius-large);height:auto;inset:0;margin:var(--rs-unit-x4);max-height:none;max-width:calc(100vw - var(--rs-unit-x8));opacity:0;overflow:hidden;position:relative;transform:scale(.96);width:var(--rs-modal-size)}.--position-center.--active,[dir=rtl] .--position-center.--active{opacity:1;transform:translate(0) scale(1)!important}.--position-bottom{--rs-modal-size-s:auto;border-radius:var(--rs-unit-radius-large) var(--rs-unit-radius-large) 0 0;height:var(--rs-modal-size);inset:0;inset-block-start:auto;margin:0;margin-top:var(--rs-unit-x4);max-height:calc(100vh - var(--rs-unit-x4));max-width:100%;opacity:1;overflow:auto;position:fixed;transform:translateY(100%);width:100%}.--position-bottom.--active,[dir=rtl] .--position-bottom.--active{transform:translateY(max(var(--rs-modal-drag,0px),0px)) scale(1)!important}.--position-start{--rs-modal-size-s:calc(var(--rs-unit-x1) * 100);border-radius:0;height:100%;inset:0;inset-inline-end:auto;margin:0;margin-inline-end:var(--rs-unit-x4);max-height:100%;max-width:calc(100vw - var(--rs-unit-x4));opacity:1;overflow:auto;position:fixed;transform:translate(-100%);width:var(--rs-modal-size)}[dir=rtl] .--position-start{transform:translate(100%)}.--position-start.--active,[dir=rtl] .--position-start.--active{transform:translate(min(var(--rs-modal-drag,0px),0px)) scale(1)!important}.--position-end{--rs-modal-size-s:calc(var(--rs-unit-x1) * 100);border-radius:0;height:100%;inset:0;inset-inline-start:auto;margin:0;margin-inline-start:var(--rs-unit-x4);max-height:100%;max-width:calc(100vw - var(--rs-unit-x4));opacity:1;overflow:auto;position:fixed;transform:translate(100%);width:var(--rs-modal-size)}[dir=rtl] .--position-end{transform:translate(-100%)}.--position-end.--active,[dir=rtl] .--position-end.--active{transform:translate(max(var(--rs-modal-drag,0px),0px)) scale(1)!important}.--position-full-screen{--rs-modal-size-s:100%;border-radius:0;height:100%;inset:0;inset-block-start:auto;margin:0;max-height:100%;max-width:100%;opacity:0;overflow:auto;position:fixed;transform:translateY(var(--rs-unit-x4));width:100%}.--position-full-screen.--active,[dir=rtl] .--position-full-screen.--active{opacity:1;transform:translate(0)!important}.--active,[dir=rtl] .--active{transition-timing-function:var(--rs-easing-decelerate)}@media (--rs-viewport-m ){.root{--rs-modal-size:var(--rs-modal-size-m)}.--position-center--m{--rs-modal-size-s:calc(var(--rs-unit-x1) * 100);border-radius:var(--rs-unit-radius-large);height:auto;inset:0;margin:var(--rs-unit-x4);max-height:none;max-width:calc(100vw - var(--rs-unit-x8));opacity:0;overflow:hidden;position:relative;transform:scale(.96);width:var(--rs-modal-size)}.--position-center--m.--active,[dir=rtl] .--position-center--m.--active{opacity:1;transform:translate(0) scale(1)!important}.--position-bottom--m{--rs-modal-size-s:auto;border-radius:var(--rs-unit-radius-large) var(--rs-unit-radius-large) 0 0;height:var(--rs-modal-size);inset:0;inset-block-start:auto;margin:0;margin-top:var(--rs-unit-x4);max-height:calc(100vh - var(--rs-unit-x4));max-width:100%;opacity:1;overflow:auto;position:fixed;transform:translateY(100%);width:100%}.--position-bottom--m.--active,[dir=rtl] .--position-bottom--m.--active{transform:translateY(max(var(--rs-modal-drag,0px),0px)) scale(1)!important}.--position-start--m{--rs-modal-size-s:calc(var(--rs-unit-x1) * 100);border-radius:0;height:100%;inset:0;inset-inline-end:auto;margin:0;margin-inline-end:var(--rs-unit-x4);max-height:100%;max-width:calc(100vw - var(--rs-unit-x4));opacity:1;overflow:auto;position:fixed;transform:translate(-100%);width:var(--rs-modal-size)}[dir=rtl] .--position-start--m{transform:translate(100%)}.--position-start--m.--active,[dir=rtl] .--position-start--m.--active{transform:translate(min(var(--rs-modal-drag,0px),0px)) scale(1)!important}.--position-end--m{--rs-modal-size-s:calc(var(--rs-unit-x1) * 100);border-radius:0;height:100%;inset:0;inset-inline-start:auto;margin:0;margin-inline-start:var(--rs-unit-x4);max-height:100%;max-width:calc(100vw - var(--rs-unit-x4));opacity:1;overflow:auto;position:fixed;transform:translate(100%);width:var(--rs-modal-size)}[dir=rtl] .--position-end--m{transform:translate(-100%)}.--position-end--m.--active,[dir=rtl] .--position-end--m.--active{transform:translate(max(var(--rs-modal-drag,0px),0px)) scale(1)!important}.--position-full-screen--m{--rs-modal-size-s:100%;border-radius:0;height:100%;inset:0;inset-block-start:auto;margin:0;max-height:100%;max-width:100%;opacity:0;overflow:auto;position:fixed;transform:translateY(var(--rs-unit-x4));width:100%}.--position-full-screen--m.--active,[dir=rtl] .--position-full-screen--m.--active{opacity:1;transform:translate(0)!important}}@media (--rs-viewport-l ){.root{--rs-modal-size:var(--rs-modal-size-l)}.--position-center--l{--rs-modal-size-s:calc(var(--rs-unit-x1) * 100);border-radius:var(--rs-unit-radius-large);height:auto;inset:0;margin:var(--rs-unit-x4);max-height:none;max-width:calc(100vw - var(--rs-unit-x8));opacity:0;overflow:hidden;position:relative;transform:scale(.96);width:var(--rs-modal-size)}.--position-center--l.--active,[dir=rtl] .--position-center--l.--active{opacity:1;transform:translate(0) scale(1)!important}.--position-bottom--l{--rs-modal-size-s:auto;border-radius:var(--rs-unit-radius-large) var(--rs-unit-radius-large) 0 0;height:var(--rs-modal-size);inset:0;inset-block-start:auto;margin:0;margin-top:var(--rs-unit-x4);max-height:calc(100vh - var(--rs-unit-x4));max-width:100%;opacity:1;overflow:auto;position:fixed;transform:translateY(100%);width:100%}.--position-bottom--l.--active,[dir=rtl] .--position-bottom--l.--active{transform:translateY(max(var(--rs-modal-drag,0px),0px)) scale(1)!important}.--position-start--l{--rs-modal-size-s:calc(var(--rs-unit-x1) * 100);border-radius:0;height:100%;inset:0;inset-inline-end:auto;margin:0;margin-inline-end:var(--rs-unit-x4);max-height:100%;max-width:calc(100vw - var(--rs-unit-x4));opacity:1;overflow:auto;position:fixed;transform:translate(-100%);width:var(--rs-modal-size)}[dir=rtl] .--position-start--l{transform:translate(100%)}.--position-start--l.--active,[dir=rtl] .--position-start--l.--active{transform:translate(min(var(--rs-modal-drag,0px),0px)) scale(1)!important}.--position-end--l{--rs-modal-size-s:calc(var(--rs-unit-x1) * 100);border-radius:0;height:100%;inset:0;inset-inline-start:auto;margin:0;margin-inline-start:var(--rs-unit-x4);max-height:100%;max-width:calc(100vw - var(--rs-unit-x4));opacity:1;overflow:auto;position:fixed;transform:translate(100%);width:var(--rs-modal-size)}[dir=rtl] .--position-end--l{transform:translate(-100%)}.--position-end--l.--active,[dir=rtl] .--position-end--l.--active{transform:translate(max(var(--rs-modal-drag,0px),0px)) scale(1)!important}.--position-full-screen--l{--rs-modal-size-s:100%;border-radius:0;height:100%;inset:0;inset-block-start:auto;margin:0;max-height:100%;max-width:100%;opacity:0;overflow:auto;position:fixed;transform:translateY(var(--rs-unit-x4));width:100%}.--position-full-screen--l.--active,[dir=rtl] .--position-full-screen--l.--active{opacity:1;transform:translate(0)!important}}@media (--rs-viewport-xl ){.root{--rs-modal-size:var(--rs-modal-size-xl)}.--position-center--xl{--rs-modal-size-s:calc(var(--rs-unit-x1) * 100);border-radius:var(--rs-unit-radius-large);height:auto;inset:0;margin:var(--rs-unit-x4);max-height:none;max-width:calc(100vw - var(--rs-unit-x8));opacity:0;overflow:hidden;position:relative;transform:scale(.96);width:var(--rs-modal-size)}.--position-center--xl.--active,[dir=rtl] .--position-center--xl.--active{opacity:1;transform:translate(0) scale(1)!important}.--position-bottom--xl{--rs-modal-size-s:auto;border-radius:var(--rs-unit-radius-large) var(--rs-unit-radius-large) 0 0;height:var(--rs-modal-size);inset:0;inset-block-start:auto;margin:0;margin-top:var(--rs-unit-x4);max-height:calc(100vh - var(--rs-unit-x4));max-width:100%;opacity:1;overflow:auto;position:fixed;transform:translateY(100%);width:100%}.--position-bottom--xl.--active,[dir=rtl] .--position-bottom--xl.--active{transform:translateY(max(var(--rs-modal-drag,0px),0px)) scale(1)!important}.--position-start--xl{--rs-modal-size-s:calc(var(--rs-unit-x1) * 100);border-radius:0;height:100%;inset:0;inset-inline-end:auto;margin:0;margin-inline-end:var(--rs-unit-x4);max-height:100%;max-width:calc(100vw - var(--rs-unit-x4));opacity:1;overflow:auto;position:fixed;transform:translate(-100%);width:var(--rs-modal-size)}[dir=rtl] .--position-start--xl{transform:translate(100%)}.--position-start--xl.--active,[dir=rtl] .--position-start--xl.--active{transform:translate(min(var(--rs-modal-drag,0px),0px)) scale(1)!important}.--position-end--xl{--rs-modal-size-s:calc(var(--rs-unit-x1) * 100);border-radius:0;height:100%;inset:0;inset-inline-start:auto;margin:0;margin-inline-start:var(--rs-unit-x4);max-height:100%;max-width:calc(100vw - var(--rs-unit-x4));opacity:1;overflow:auto;position:fixed;transform:translate(100%);width:var(--rs-modal-size)}[dir=rtl] .--position-end--xl{transform:translate(-100%)}.--position-end--xl.--active,[dir=rtl] .--position-end--xl.--active{transform:translate(max(var(--rs-modal-drag,0px),0px)) scale(1)!important}.--position-full-screen--xl{--rs-modal-size-s:100%;border-radius:0;height:100%;inset:0;inset-block-start:auto;margin:0;max-height:100%;max-width:100%;opacity:0;overflow:auto;position:fixed;transform:translateY(var(--rs-unit-x4));width:100%}.--position-full-screen--xl.--active,[dir=rtl] .--position-full-screen--xl.--active{opacity:1;transform:translate(0)!important}}
|
|
@@ -20,7 +20,9 @@ export type Props = {
|
|
|
20
20
|
padding?: G.Responsive<number>;
|
|
21
21
|
active?: boolean;
|
|
22
22
|
transparentOverlay?: boolean;
|
|
23
|
+
autoFocus?: boolean;
|
|
23
24
|
onClose?: () => void;
|
|
25
|
+
ariaLabel?: string;
|
|
24
26
|
className?: G.ClassName;
|
|
25
27
|
overlayClassName?: G.ClassName;
|
|
26
28
|
attributes?: G.Attributes<"div", Props>;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { type ModalProps } from "./..";
|
|
1
2
|
declare const _default: {
|
|
2
3
|
title: string;
|
|
3
4
|
component: {
|
|
4
|
-
(props:
|
|
5
|
+
(props: ModalProps): import("react").JSX.Element;
|
|
5
6
|
Title: (props: import("../Modal.types").TitleProps) => import("react").JSX.Element;
|
|
6
7
|
Subtitle: (props: import("../Modal.types").SubtitleProps) => import("react").JSX.Element;
|
|
7
8
|
};
|
|
@@ -114,6 +114,9 @@ export const edgeCases = () => {
|
|
|
114
114
|
const menuModalToggle = useToggle();
|
|
115
115
|
const scrollModalToggle = useToggle();
|
|
116
116
|
return (<Example>
|
|
117
|
+
<Example.Item title="trap focus works with custom children components">
|
|
118
|
+
<Demo title="Modal title" autoFocus={false} active/>
|
|
119
|
+
</Example.Item>
|
|
117
120
|
<Example.Item title="trap focus works with custom children components">
|
|
118
121
|
<Demo title="Modal title">
|
|
119
122
|
<View gap={3} direction="row">
|
|
@@ -78,10 +78,14 @@ const Overlay = (props) => {
|
|
|
78
78
|
});
|
|
79
79
|
}, [rendered, show, lockScroll, clickThrough]);
|
|
80
80
|
React.useEffect(() => {
|
|
81
|
+
console.log(1221212121, rendered, contentRef);
|
|
81
82
|
if (!rendered || !contentRef.current)
|
|
82
83
|
return;
|
|
83
84
|
const trapFocus = new TrapFocus(contentRef.current);
|
|
84
|
-
|
|
85
|
+
console.log("efffect", contentRef.current.querySelector("[role=dialog]"));
|
|
86
|
+
trapFocus.trap({
|
|
87
|
+
initialFocusEl: contentRef.current.querySelector("[role=dialog][tabindex='-1']"),
|
|
88
|
+
});
|
|
85
89
|
return () => trapFocus.release();
|
|
86
90
|
}, [rendered]);
|
|
87
91
|
// Unlock scroll on unmount
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import Theme from "../Theme/index.js";
|
|
4
4
|
import Text from "../Text/index.js";
|
|
5
5
|
import Flyout from "../_private/Flyout/index.js";
|
|
6
6
|
import s from "./Tooltip.module.css";
|
|
7
7
|
const Tooltip = (props) => {
|
|
8
8
|
const { id, text, children, onOpen, onClose, position = "bottom", active } = props;
|
|
9
|
+
if (!text)
|
|
10
|
+
return _jsx(_Fragment, { children: children({}) });
|
|
9
11
|
return (_jsxs(Flyout, { id: id, active: active, position: position, onOpen: onOpen, onClose: onClose, triggerType: "hover", children: [_jsx(Flyout.Trigger, { children: children }), _jsx(Flyout.Content, { children: _jsx(Theme, { colorMode: "inverted", children: _jsx(Text, { variant: "caption-1", className: s.root, children: text }) }) })] }));
|
|
10
12
|
};
|
|
11
13
|
export default Tooltip;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import type { FlyoutProps, FlyoutTriggerProps } from "../_private/Flyout";
|
|
3
|
-
export type Props = Pick<FlyoutProps, "id" | "position" | "onOpen" | "onClose" | "active"> &
|
|
4
|
-
|
|
3
|
+
export type Props = Pick<FlyoutProps, "id" | "position" | "onOpen" | "onClose" | "active"> & {
|
|
4
|
+
children: (attributes: Parameters<FlyoutTriggerProps["children"]>[0] | {}) => React.ReactNode;
|
|
5
|
+
text?: React.ReactNode;
|
|
5
6
|
};
|
|
@@ -13,6 +13,7 @@ import { Example } from "../../../utilities/storybook/index.js";
|
|
|
13
13
|
import Tooltip from "../index.js";
|
|
14
14
|
import Button from "../../Button/index.js";
|
|
15
15
|
import View from "../../View/index.js";
|
|
16
|
+
import useResponsiveClientValue from "../../../hooks/useResponsiveClientValue.js";
|
|
16
17
|
export default {
|
|
17
18
|
title: "Components/Tooltip",
|
|
18
19
|
component: Tooltip,
|
|
@@ -28,6 +29,16 @@ const Demo = (props) => {
|
|
|
28
29
|
{(attributes) => <Button attributes={attributes}>Show tooltip</Button>}
|
|
29
30
|
</Tooltip>);
|
|
30
31
|
};
|
|
32
|
+
const DemoResponsive = (props) => {
|
|
33
|
+
const { position } = props, rest = __rest(props, ["position"]);
|
|
34
|
+
const screenSize = useResponsiveClientValue({
|
|
35
|
+
s: "small",
|
|
36
|
+
m: "medium",
|
|
37
|
+
});
|
|
38
|
+
return (<Tooltip text={position} position={position} {...rest} active={screenSize === "small"}>
|
|
39
|
+
{(attributes) => <Button attributes={attributes}>Show tooltip</Button>}
|
|
40
|
+
</Tooltip>);
|
|
41
|
+
};
|
|
31
42
|
export const position = () => (<Example>
|
|
32
43
|
<Example.Item title="position: bottom-start">
|
|
33
44
|
<Demo position="bottom-start"/>
|
|
@@ -60,6 +71,14 @@ export const position = () => (<Example>
|
|
|
60
71
|
</Example>);
|
|
61
72
|
export const controlled = () => (<Example>
|
|
62
73
|
<Example.Item title="active, controlled, position: bottom">
|
|
63
|
-
<Demo position="bottom"
|
|
74
|
+
<Demo position="bottom"/>
|
|
75
|
+
</Example.Item>
|
|
76
|
+
</Example>);
|
|
77
|
+
export const edgeCases = () => (<Example>
|
|
78
|
+
<Example.Item title="without text">
|
|
79
|
+
<Tooltip>{() => <Button>Button</Button>}</Tooltip>
|
|
80
|
+
</Example.Item>
|
|
81
|
+
<Example.Item title="responsive visibility">
|
|
82
|
+
<DemoResponsive />
|
|
64
83
|
</Example.Item>
|
|
65
84
|
</Example>);
|
|
@@ -1,7 +1,37 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import type * as G from "../../../types/global";
|
|
3
3
|
import type { TrapMode } from "../../../utilities/a11y/types";
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Utility
|
|
6
|
+
*/
|
|
7
|
+
export type Position = "bottom" | "bottom-start" | "bottom-end" | "top" | "top-start" | "top-end" | "start" | "start-top" | "start-bottom" | "end" | "end-top" | "end-bottom";
|
|
8
|
+
export type Width = "trigger" | string;
|
|
9
|
+
export type Options = {
|
|
10
|
+
width?: Width;
|
|
11
|
+
position: Position;
|
|
12
|
+
rtl: boolean;
|
|
13
|
+
forcePosition?: boolean;
|
|
14
|
+
};
|
|
15
|
+
export type Styles = React.CSSProperties;
|
|
16
|
+
export type State = {
|
|
17
|
+
styles: Styles;
|
|
18
|
+
position?: Position;
|
|
19
|
+
status: "idle" | "rendered" | "positioned" | "visible" | "hidden";
|
|
20
|
+
};
|
|
21
|
+
export type FlyoutData = {
|
|
22
|
+
styles: Styles;
|
|
23
|
+
position: Position;
|
|
24
|
+
};
|
|
25
|
+
export type UseFlyoutData = Pick<State, "styles" | "position" | "status"> & {
|
|
26
|
+
updatePosition: () => void;
|
|
27
|
+
render: () => void;
|
|
28
|
+
hide: () => void;
|
|
29
|
+
remove: () => void;
|
|
30
|
+
show: () => void;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Component
|
|
34
|
+
*/
|
|
5
35
|
export type InstanceRef = {
|
|
6
36
|
open: () => void;
|
|
7
37
|
close: () => void;
|
|
@@ -30,14 +60,14 @@ export type TriggerAttributes = {
|
|
|
30
60
|
type BaseProps = {
|
|
31
61
|
id?: string;
|
|
32
62
|
triggerType?: "hover" | "click" | "focus";
|
|
33
|
-
position?:
|
|
63
|
+
position?: Position;
|
|
34
64
|
forcePosition?: boolean;
|
|
35
65
|
trapFocusMode?: TrapMode;
|
|
36
66
|
disableHideAnimation?: boolean;
|
|
37
67
|
children?: React.ReactNode;
|
|
38
68
|
onOpen?: () => void;
|
|
39
69
|
onClose?: () => void;
|
|
40
|
-
width?:
|
|
70
|
+
width?: Width;
|
|
41
71
|
contentGap?: number;
|
|
42
72
|
contentClassName?: string;
|
|
43
73
|
contentAttributes?: G.Attributes<"div">;
|
|
@@ -60,8 +90,8 @@ export type ContentProps = {
|
|
|
60
90
|
};
|
|
61
91
|
export type ContextProps = {
|
|
62
92
|
id: string;
|
|
63
|
-
flyout:
|
|
64
|
-
width?:
|
|
93
|
+
flyout: UseFlyoutData;
|
|
94
|
+
width?: Width;
|
|
65
95
|
triggerElRef: React.RefObject<HTMLButtonElement>;
|
|
66
96
|
flyoutElRef: React.RefObject<HTMLDivElement>;
|
|
67
97
|
handleClose: (options?: {
|
|
@@ -8,10 +8,10 @@ import useIsDismissible from "../../../hooks/_private/useIsDismissible.js";
|
|
|
8
8
|
import useElementId from "../../../hooks/useElementId.js";
|
|
9
9
|
import useIsomorphicLayoutEffect from "../../../hooks/useIsomorphicLayoutEffect.js";
|
|
10
10
|
import useHotkeys from "../../../hooks/useHotkeys.js";
|
|
11
|
-
import useFlyout from "../../../hooks/_private/useFlyout.js";
|
|
12
11
|
import useOnClickOutside from "../../../hooks/_private/useOnClickOutside.js";
|
|
13
12
|
import useRTL from "../../../hooks/useRTL.js";
|
|
14
|
-
import { checkTransitions } from "../../../utilities/animation.js";
|
|
13
|
+
import { checkTransitions, onNextFrame } from "../../../utilities/animation.js";
|
|
14
|
+
import useFlyout from "./useFlyout.js";
|
|
15
15
|
import { Provider, useFlyoutContext } from "./Flyout.context.js";
|
|
16
16
|
const FlyoutRoot = (props) => {
|
|
17
17
|
const { triggerType = "click", onOpen, onClose, children, forcePosition, trapFocusMode, width, disableHideAnimation, contentGap, contentClassName, contentAttributes, position: passedPosition, active: passedActive, id: passedId, instanceRef, } = props;
|
|
@@ -33,7 +33,7 @@ const FlyoutRoot = (props) => {
|
|
|
33
33
|
defaultActive: passedActive,
|
|
34
34
|
forcePosition,
|
|
35
35
|
});
|
|
36
|
-
const { status, updatePosition, render, hide, remove } = flyout;
|
|
36
|
+
const { status, updatePosition, render, hide, remove, show } = flyout;
|
|
37
37
|
// Don't create dismissible queue for hover flyout because they close all together on mouseout
|
|
38
38
|
const isDismissible = useIsDismissible(triggerType !== "hover" && status !== "idle", flyoutElRef, triggerElRef);
|
|
39
39
|
const clearTimer = React.useCallback(() => {
|
|
@@ -102,6 +102,21 @@ const FlyoutRoot = (props) => {
|
|
|
102
102
|
}, [status, handleOpen, handleClose]);
|
|
103
103
|
const handleContentMouseDown = () => (lockedBlurEffects.current = true);
|
|
104
104
|
const handleContentMouseUp = () => (lockedBlurEffects.current = false);
|
|
105
|
+
const handleTransitionStart = React.useCallback((e) => {
|
|
106
|
+
if (!passedActive)
|
|
107
|
+
return;
|
|
108
|
+
if (flyoutElRef.current !== e.currentTarget || e.propertyName !== "transform")
|
|
109
|
+
return;
|
|
110
|
+
transitionStartedRef.current = true;
|
|
111
|
+
}, [passedActive]);
|
|
112
|
+
const handleTransitionEnd = React.useCallback((e) => {
|
|
113
|
+
if (flyoutElRef.current !== e.currentTarget || e.propertyName !== "transform")
|
|
114
|
+
return;
|
|
115
|
+
if (status === "hidden") {
|
|
116
|
+
transitionStartedRef.current = false;
|
|
117
|
+
remove();
|
|
118
|
+
}
|
|
119
|
+
}, [remove, status]);
|
|
105
120
|
/**
|
|
106
121
|
* Control the display based on the props
|
|
107
122
|
*/
|
|
@@ -122,21 +137,11 @@ const FlyoutRoot = (props) => {
|
|
|
122
137
|
remove();
|
|
123
138
|
}
|
|
124
139
|
}, [passedActive, render, hide, disableHideAnimation]);
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
transitionStartedRef.current = true;
|
|
131
|
-
}, [passedActive]);
|
|
132
|
-
const handleTransitionEnd = React.useCallback((e) => {
|
|
133
|
-
if (flyoutElRef.current !== e.currentTarget || e.propertyName !== "transform")
|
|
134
|
-
return;
|
|
135
|
-
if (status === "hidden") {
|
|
136
|
-
transitionStartedRef.current = false;
|
|
137
|
-
remove();
|
|
138
|
-
}
|
|
139
|
-
}, [remove, status]);
|
|
140
|
+
React.useEffect(() => {
|
|
141
|
+
// Wait after positioning before show is triggered to animate flyout from the right side
|
|
142
|
+
if (status === "positioned")
|
|
143
|
+
onNextFrame(() => show());
|
|
144
|
+
}, [status, show]);
|
|
140
145
|
/**
|
|
141
146
|
* Handle focus trap
|
|
142
147
|
*
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type * as T from "./Flyout.types";
|
|
3
|
+
/**
|
|
4
|
+
* Typings
|
|
5
|
+
*/
|
|
6
|
+
type ElementRef = React.RefObject<HTMLElement>;
|
|
7
|
+
type PassedFlyoutOptions = {
|
|
8
|
+
width?: T.Width;
|
|
9
|
+
position?: T.Position;
|
|
10
|
+
defaultActive?: boolean;
|
|
11
|
+
forcePosition?: boolean;
|
|
12
|
+
};
|
|
13
|
+
type UseFlyout = (originRef: ElementRef, targetRef: ElementRef, options: PassedFlyoutOptions) => Pick<T.State, "styles" | "position" | "status"> & {
|
|
14
|
+
updatePosition: () => void;
|
|
15
|
+
render: () => void;
|
|
16
|
+
hide: () => void;
|
|
17
|
+
remove: () => void;
|
|
18
|
+
show: () => void;
|
|
19
|
+
};
|
|
20
|
+
declare const useFlyout: UseFlyout;
|
|
21
|
+
export default useFlyout;
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import useRTL from "
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
const SCREEN_OFFSET = 16;
|
|
2
|
+
import useRTL from "../../../hooks/useRTL.js";
|
|
3
|
+
import { getClosestFlyoutTarget } from "../../../utilities/dom.js";
|
|
4
|
+
import calculatePosition from "./utilities/calculatePosition.js";
|
|
6
5
|
const topPos = ["top-start", "top", "top-end"];
|
|
7
6
|
const bottomPos = ["bottom-start", "bottom", "bottom-end"];
|
|
8
7
|
const startPos = ["start", "start-bottom", "start-top"];
|
|
@@ -13,19 +12,6 @@ const order = {
|
|
|
13
12
|
start: [...startPos, ...endPos, ...topPos, ...bottomPos],
|
|
14
13
|
end: [...endPos, ...startPos, ...topPos, ...bottomPos],
|
|
15
14
|
};
|
|
16
|
-
const getRTLPosition = (position) => {
|
|
17
|
-
if (position.includes("start"))
|
|
18
|
-
return position.replace("start", "end");
|
|
19
|
-
if (position.includes("end"))
|
|
20
|
-
return position.replace("end", "start");
|
|
21
|
-
return position;
|
|
22
|
-
};
|
|
23
|
-
/**
|
|
24
|
-
* Get a position value which centers 2 elements vertically or horizontally
|
|
25
|
-
*/
|
|
26
|
-
const centerBySize = (originSize, targetSize) => {
|
|
27
|
-
return Math.floor(originSize / 2 - targetSize / 2);
|
|
28
|
-
};
|
|
29
15
|
/**
|
|
30
16
|
* Get an order of positions to try to fit popover on the screen based on its starting position
|
|
31
17
|
*/
|
|
@@ -48,88 +34,6 @@ const fullyVisible = (bounds) => {
|
|
|
48
34
|
bounds.top >= pageTop &&
|
|
49
35
|
bounds.top + bounds.height <= pageBottom);
|
|
50
36
|
};
|
|
51
|
-
/**
|
|
52
|
-
* Calculate styles for the current position
|
|
53
|
-
*/
|
|
54
|
-
const calculatePosition = (originBounds, targetBounds, parentOffset, options) => {
|
|
55
|
-
const { position: passedPosition, rtl, width } = options;
|
|
56
|
-
let left = 0;
|
|
57
|
-
let top = 0;
|
|
58
|
-
let position = passedPosition;
|
|
59
|
-
if (rtl)
|
|
60
|
-
position = getRTLPosition(position);
|
|
61
|
-
if (width === "full" || width === "trigger") {
|
|
62
|
-
position = position.includes("top") ? "top" : "bottom";
|
|
63
|
-
}
|
|
64
|
-
switch (position) {
|
|
65
|
-
case "bottom":
|
|
66
|
-
case "top":
|
|
67
|
-
left = centerBySize(originBounds.width, targetBounds.width) + originBounds.left;
|
|
68
|
-
break;
|
|
69
|
-
case "start":
|
|
70
|
-
case "start-top":
|
|
71
|
-
case "start-bottom":
|
|
72
|
-
left = originBounds.left - targetBounds.width;
|
|
73
|
-
break;
|
|
74
|
-
case "end":
|
|
75
|
-
case "end-top":
|
|
76
|
-
case "end-bottom":
|
|
77
|
-
left = originBounds.right;
|
|
78
|
-
break;
|
|
79
|
-
case "top-start":
|
|
80
|
-
case "bottom-start":
|
|
81
|
-
left = originBounds.left;
|
|
82
|
-
break;
|
|
83
|
-
case "top-end":
|
|
84
|
-
case "bottom-end":
|
|
85
|
-
left = originBounds.right - targetBounds.width;
|
|
86
|
-
break;
|
|
87
|
-
default:
|
|
88
|
-
break;
|
|
89
|
-
}
|
|
90
|
-
switch (position) {
|
|
91
|
-
case "top":
|
|
92
|
-
case "top-start":
|
|
93
|
-
case "top-end":
|
|
94
|
-
top = originBounds.top - targetBounds.height;
|
|
95
|
-
break;
|
|
96
|
-
case "bottom":
|
|
97
|
-
case "bottom-start":
|
|
98
|
-
case "bottom-end":
|
|
99
|
-
top = originBounds.bottom;
|
|
100
|
-
break;
|
|
101
|
-
case "start":
|
|
102
|
-
case "end":
|
|
103
|
-
top = centerBySize(originBounds.height, targetBounds.height) + originBounds.top;
|
|
104
|
-
break;
|
|
105
|
-
case "start-top":
|
|
106
|
-
case "end-top":
|
|
107
|
-
top = originBounds.top;
|
|
108
|
-
break;
|
|
109
|
-
case "start-bottom":
|
|
110
|
-
case "end-bottom":
|
|
111
|
-
top = originBounds.bottom - targetBounds.height;
|
|
112
|
-
break;
|
|
113
|
-
default:
|
|
114
|
-
break;
|
|
115
|
-
}
|
|
116
|
-
if (top === undefined || left === undefined) {
|
|
117
|
-
throw Error(`[Reshaped, flyout]: ${position} position is not valid`);
|
|
118
|
-
}
|
|
119
|
-
top = Math.round(top + (window.scrollY || 0) - parentOffset.top);
|
|
120
|
-
left = Math.round(left + (window.scrollX || 0) - parentOffset.left);
|
|
121
|
-
let widthStyle = Math.ceil(targetBounds.width);
|
|
122
|
-
const height = Math.ceil(targetBounds.height);
|
|
123
|
-
if (width === "full") {
|
|
124
|
-
left = SCREEN_OFFSET;
|
|
125
|
-
widthStyle = window.innerWidth - SCREEN_OFFSET * 2;
|
|
126
|
-
}
|
|
127
|
-
else if (width === "trigger") {
|
|
128
|
-
widthStyle = originBounds.width;
|
|
129
|
-
}
|
|
130
|
-
const styles = { left, top, width: widthStyle, height };
|
|
131
|
-
return { styles, position };
|
|
132
|
-
};
|
|
133
37
|
/**
|
|
134
38
|
* Order of keys here is responsible for the order of styles applied
|
|
135
39
|
*/
|
|
@@ -154,10 +58,10 @@ const resetStyles = {
|
|
|
154
58
|
/**
|
|
155
59
|
* Set position of the target element to fit on the screen
|
|
156
60
|
*/
|
|
157
|
-
const flyout = (
|
|
61
|
+
const flyout = (triggerEl, flyoutEl, options) => {
|
|
158
62
|
const { position, forcePosition, width } = options;
|
|
159
|
-
const targetClone =
|
|
160
|
-
const
|
|
63
|
+
const targetClone = flyoutEl.cloneNode(true);
|
|
64
|
+
const triggerBounds = triggerEl.getBoundingClientRect();
|
|
161
65
|
// Reset all styles applied on the previous hook execution
|
|
162
66
|
targetClone.style = "";
|
|
163
67
|
Object.keys(resetStyles).forEach((key) => {
|
|
@@ -166,21 +70,21 @@ const flyout = (origin, target, options) => {
|
|
|
166
70
|
});
|
|
167
71
|
if (width) {
|
|
168
72
|
if (width === "trigger") {
|
|
169
|
-
targetClone.style.width = `${
|
|
73
|
+
targetClone.style.width = `${triggerBounds.width}px`;
|
|
170
74
|
}
|
|
171
75
|
else if (width !== "full") {
|
|
172
76
|
targetClone.style.width = width;
|
|
173
77
|
}
|
|
174
78
|
}
|
|
175
79
|
document.body.appendChild(targetClone);
|
|
176
|
-
const
|
|
177
|
-
const scrollableParent = getClosestFlyoutTarget(
|
|
178
|
-
const
|
|
179
|
-
const
|
|
180
|
-
top:
|
|
181
|
-
left:
|
|
80
|
+
const flyoutBounds = targetClone.getBoundingClientRect();
|
|
81
|
+
const scrollableParent = getClosestFlyoutTarget(triggerEl);
|
|
82
|
+
const scopeBounds = scrollableParent.getBoundingClientRect();
|
|
83
|
+
const scopeOffset = {
|
|
84
|
+
top: scopeBounds.top + document.documentElement.scrollTop - scrollableParent.scrollTop,
|
|
85
|
+
left: scopeBounds.left + document.documentElement.scrollLeft - scrollableParent.scrollLeft,
|
|
182
86
|
};
|
|
183
|
-
let calculated = calculatePosition(
|
|
87
|
+
let calculated = calculatePosition(Object.assign({ triggerBounds, flyoutBounds, scopeOffset }, options));
|
|
184
88
|
if (!fullyVisible(calculated.styles) && !forcePosition) {
|
|
185
89
|
const order = getPositionOrder(position);
|
|
186
90
|
const mobileOrder = order.filter((position) => position === "top" || position === "bottom");
|
|
@@ -188,7 +92,9 @@ const flyout = (origin, target, options) => {
|
|
|
188
92
|
const { fullWidth } = extraOptions;
|
|
189
93
|
testOrder.some((currentPosition) => {
|
|
190
94
|
const calculateOptions = Object.assign(Object.assign({}, options), { width: fullWidth ? "full" : options.width, position: currentPosition });
|
|
191
|
-
const tested = calculatePosition(
|
|
95
|
+
const tested = calculatePosition(Object.assign({ triggerBounds,
|
|
96
|
+
flyoutBounds,
|
|
97
|
+
scopeOffset }, calculateOptions));
|
|
192
98
|
if (fullyVisible(tested.styles)) {
|
|
193
99
|
calculated = tested;
|
|
194
100
|
return true;
|
|
@@ -207,16 +113,25 @@ const flyout = (origin, target, options) => {
|
|
|
207
113
|
const flyoutReducer = (state, action) => {
|
|
208
114
|
switch (action.type) {
|
|
209
115
|
case "render":
|
|
116
|
+
if (state.status !== "idle")
|
|
117
|
+
return state;
|
|
210
118
|
// Disable events before it's positioned to avoid mouseleave getting triggered
|
|
211
119
|
return Object.assign(Object.assign({}, state), { status: "rendered", styles: Object.assign({ pointerEvents: "none" }, resetStyles) });
|
|
212
120
|
case "position":
|
|
213
|
-
|
|
121
|
+
if (state.status !== "rendered")
|
|
122
|
+
return state;
|
|
123
|
+
return Object.assign(Object.assign({}, state), { status: "positioned", position: action.payload.position, styles: Object.assign(Object.assign({}, defaultStyles), action.payload.styles) });
|
|
214
124
|
case "show":
|
|
215
|
-
|
|
216
|
-
|
|
125
|
+
if (state.status !== "positioned")
|
|
126
|
+
return state;
|
|
127
|
+
return Object.assign(Object.assign({}, state), { status: "visible" });
|
|
217
128
|
case "hide":
|
|
218
|
-
|
|
129
|
+
if (state.status !== "visible")
|
|
130
|
+
return state;
|
|
131
|
+
return Object.assign(Object.assign({}, state), { status: "hidden" });
|
|
219
132
|
case "remove":
|
|
133
|
+
if (state.status !== "hidden" && state.status !== "visible")
|
|
134
|
+
return state;
|
|
220
135
|
return Object.assign(Object.assign({}, state), { status: "idle", styles: resetStyles });
|
|
221
136
|
default:
|
|
222
137
|
throw new Error("Invalid reducer type");
|
|
@@ -256,10 +171,7 @@ const useFlyout = (originRef, targetRef, options) => {
|
|
|
256
171
|
React.useEffect(() => {
|
|
257
172
|
if (state.status === "rendered")
|
|
258
173
|
updatePosition();
|
|
259
|
-
|
|
260
|
-
if (state.status === "positioned")
|
|
261
|
-
onNextFrame(() => show());
|
|
262
|
-
}, [state.status, updatePosition, show]);
|
|
174
|
+
}, [state.status, updatePosition]);
|
|
263
175
|
return React.useMemo(() => ({
|
|
264
176
|
position: state.position,
|
|
265
177
|
styles: state.styles,
|
|
@@ -268,6 +180,7 @@ const useFlyout = (originRef, targetRef, options) => {
|
|
|
268
180
|
render,
|
|
269
181
|
hide,
|
|
270
182
|
remove,
|
|
271
|
-
|
|
183
|
+
show,
|
|
184
|
+
}), [render, updatePosition, hide, remove, show, state.position, state.styles, state.status]);
|
|
272
185
|
};
|
|
273
186
|
export default useFlyout;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type * as T from "../Flyout.types";
|
|
2
|
+
/**
|
|
3
|
+
* Calculate styles for the current position
|
|
4
|
+
*/
|
|
5
|
+
declare const calculatePosition: (args: T.Options & {
|
|
6
|
+
triggerBounds: DOMRect;
|
|
7
|
+
flyoutBounds: DOMRect;
|
|
8
|
+
scopeOffset: Record<"left" | "top", number>;
|
|
9
|
+
}) => {
|
|
10
|
+
styles: {
|
|
11
|
+
left: number;
|
|
12
|
+
top: number;
|
|
13
|
+
width: number;
|
|
14
|
+
height: number;
|
|
15
|
+
};
|
|
16
|
+
position: T.Position;
|
|
17
|
+
};
|
|
18
|
+
export default calculatePosition;
|