reshaped 2.11.10 → 2.11.12
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 +2 -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 +3 -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);
|
@@ -162,7 +162,7 @@ const Modal = (props) => {
|
|
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
163
|
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
164
|
? "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 })) }));
|
165
|
+
: `${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
166
|
} }));
|
167
167
|
};
|
168
168
|
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">
|
@@ -81,7 +81,9 @@ const Overlay = (props) => {
|
|
81
81
|
if (!rendered || !contentRef.current)
|
82
82
|
return;
|
83
83
|
const trapFocus = new TrapFocus(contentRef.current);
|
84
|
-
trapFocus.trap(
|
84
|
+
trapFocus.trap({
|
85
|
+
initialFocusEl: contentRef.current.querySelector("[role=dialog][tabindex='-1']"),
|
86
|
+
});
|
85
87
|
return () => trapFocus.release();
|
86
88
|
}, [rendered]);
|
87
89
|
// 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;
|