@deque/cauldron-react 6.7.0-canary.2d78ed57 → 6.7.0-canary.4be82cb3
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/lib/components/Drawer/index.d.ts +15 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +182 -66
- package/lib/utils/resolveElement.d.ts +6 -0
- package/lib/utils/useEscapeKey.d.ts +17 -0
- package/package.json +1 -1
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface DrawerProps<T extends HTMLElement = HTMLElement> extends React.HTMLAttributes<HTMLDivElement> {
|
|
3
|
+
children: React.ReactNode;
|
|
4
|
+
position: 'top' | 'bottom' | 'left' | 'right';
|
|
5
|
+
open?: boolean;
|
|
6
|
+
behavior?: 'modal' | 'non-modal';
|
|
7
|
+
focusOptions?: {
|
|
8
|
+
initialFocus?: T | React.RefObject<T> | React.MutableRefObject<T>;
|
|
9
|
+
returnFocus?: T | React.RefObject<T> | React.MutableRefObject<T>;
|
|
10
|
+
};
|
|
11
|
+
onClose?: () => void;
|
|
12
|
+
portal?: React.RefObject<HTMLElement> | HTMLElement;
|
|
13
|
+
}
|
|
14
|
+
declare const Drawer: React.ForwardRefExoticComponent<DrawerProps<HTMLElement> & React.RefAttributes<HTMLDivElement>>;
|
|
15
|
+
export default Drawer;
|
package/lib/index.d.ts
CHANGED
|
@@ -59,6 +59,7 @@ export { default as Popover } from './components/Popover';
|
|
|
59
59
|
export { default as Timeline, TimelineItem } from './components/Timeline';
|
|
60
60
|
export { default as TextEllipsis } from './components/TextEllipsis';
|
|
61
61
|
export { default as CopyButton } from './components/CopyButton';
|
|
62
|
+
export { default as Drawer } from './components/Drawer';
|
|
62
63
|
/**
|
|
63
64
|
* Helpers / Utils
|
|
64
65
|
*/
|
package/lib/index.js
CHANGED
|
@@ -791,6 +791,23 @@ var OptionsMenuWrapper = function (_a) {
|
|
|
791
791
|
return (React__default["default"].createElement("div", tslib.__assign({ className: classNames__default["default"]('OptionsMenu', menuAlignment(align), className) }, other)));
|
|
792
792
|
};
|
|
793
793
|
|
|
794
|
+
/**
|
|
795
|
+
* When an element can be passed as a value that is either an element or an
|
|
796
|
+
* elementRef, this will resolve the property down to the resulting element
|
|
797
|
+
*/
|
|
798
|
+
function resolveElement(elementOrRef) {
|
|
799
|
+
if (elementOrRef instanceof Element) {
|
|
800
|
+
return elementOrRef;
|
|
801
|
+
}
|
|
802
|
+
if (elementOrRef &&
|
|
803
|
+
typeof elementOrRef === 'object' &&
|
|
804
|
+
'current' in elementOrRef &&
|
|
805
|
+
elementOrRef.current instanceof Element) {
|
|
806
|
+
return elementOrRef.current;
|
|
807
|
+
}
|
|
808
|
+
return null;
|
|
809
|
+
}
|
|
810
|
+
|
|
794
811
|
function ClickOutsideListener(_a, ref) {
|
|
795
812
|
var children = _a.children, _b = _a.mouseEvent, mouseEvent = _b === void 0 ? 'click' : _b, _c = _a.touchEvent, touchEvent = _c === void 0 ? 'touchend' : _c, target = _a.target, _d = _a.onClickOutside, onClickOutside = _d === void 0 ? function () { return null; } : _d;
|
|
796
813
|
var childElementRef = React.useRef();
|
|
@@ -799,11 +816,9 @@ function ClickOutsideListener(_a, ref) {
|
|
|
799
816
|
return;
|
|
800
817
|
}
|
|
801
818
|
var eventTarget = event.target;
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
onClickOutside(event);
|
|
806
|
-
}
|
|
819
|
+
var elementTarget = resolveElement(target);
|
|
820
|
+
if (target && !(elementTarget === null || elementTarget === void 0 ? void 0 : elementTarget.contains(eventTarget))) {
|
|
821
|
+
onClickOutside(event);
|
|
807
822
|
// If a target is passed in via a prop, we defer to utilizing that
|
|
808
823
|
// target instead of a child element target
|
|
809
824
|
return;
|
|
@@ -1648,6 +1663,46 @@ function hasIdRef(ids, id) {
|
|
|
1648
1663
|
return idRefs(ids).has(id);
|
|
1649
1664
|
}
|
|
1650
1665
|
|
|
1666
|
+
var isEscapeKey = function (event) {
|
|
1667
|
+
return event.key === 'Escape' || event.key === 'Esc' || event.keyCode === 27;
|
|
1668
|
+
};
|
|
1669
|
+
/**
|
|
1670
|
+
* When a component needs to implement an escape handler, such as in modal
|
|
1671
|
+
* dialogs, useEscapeKey will handle the events and call the provided callback
|
|
1672
|
+
* handler when an escape key event has been fired.
|
|
1673
|
+
*
|
|
1674
|
+
* @example
|
|
1675
|
+
* useEscapeKey(() => close())
|
|
1676
|
+
*/
|
|
1677
|
+
function useEscapeKey(options, dependencies) {
|
|
1678
|
+
if (dependencies === void 0) { dependencies = []; }
|
|
1679
|
+
var callback = options.callback;
|
|
1680
|
+
var event = options.event || 'keyup';
|
|
1681
|
+
var target = resolveElement(options.target) || document.body;
|
|
1682
|
+
var active = typeof options.active === 'boolean' ? options.active : true;
|
|
1683
|
+
React.useEffect(function () {
|
|
1684
|
+
var eventListener = function (event) {
|
|
1685
|
+
if (isEscapeKey(event) &&
|
|
1686
|
+
(options.defaultPrevented ? !event.defaultPrevented : true)) {
|
|
1687
|
+
callback(event);
|
|
1688
|
+
}
|
|
1689
|
+
};
|
|
1690
|
+
if (active) {
|
|
1691
|
+
target === null || target === void 0 ? void 0 : target.addEventListener(event, eventListener, options.capture);
|
|
1692
|
+
}
|
|
1693
|
+
return function () {
|
|
1694
|
+
target === null || target === void 0 ? void 0 : target.removeEventListener(event, eventListener, options.capture);
|
|
1695
|
+
};
|
|
1696
|
+
}, tslib.__spreadArray([
|
|
1697
|
+
active,
|
|
1698
|
+
callback,
|
|
1699
|
+
event,
|
|
1700
|
+
target,
|
|
1701
|
+
options.capture,
|
|
1702
|
+
options.defaultPrevented
|
|
1703
|
+
], tslib.__read(dependencies), false));
|
|
1704
|
+
}
|
|
1705
|
+
|
|
1651
1706
|
var TIP_HIDE_DELAY = 100;
|
|
1652
1707
|
// fires a custom "cauldron:tooltip:show" / "cauldron:tooltip:hide" event
|
|
1653
1708
|
// to allow projects using cauldron to hook into when a tooltip is shown/hidden
|
|
@@ -1736,30 +1791,14 @@ function Tooltip(_a) {
|
|
|
1736
1791
|
attributes.popper['data-popper-placement']) ||
|
|
1737
1792
|
initialPlacement;
|
|
1738
1793
|
// Only listen to key ups when the tooltip is visible
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
};
|
|
1748
|
-
var targetElement = document.body;
|
|
1749
|
-
if (showTooltip && typeof showProp !== 'boolean') {
|
|
1750
|
-
targetElement.addEventListener('keyup', handleEscape, { capture: true });
|
|
1751
|
-
}
|
|
1752
|
-
else {
|
|
1753
|
-
targetElement.removeEventListener('keyup', handleEscape, {
|
|
1754
|
-
capture: true
|
|
1755
|
-
});
|
|
1756
|
-
}
|
|
1757
|
-
return function () {
|
|
1758
|
-
targetElement.removeEventListener('keyup', handleEscape, {
|
|
1759
|
-
capture: true
|
|
1760
|
-
});
|
|
1761
|
-
};
|
|
1762
|
-
}, [showTooltip, showProp]);
|
|
1794
|
+
useEscapeKey({
|
|
1795
|
+
callback: function (event) {
|
|
1796
|
+
event.preventDefault();
|
|
1797
|
+
setShowTooltip(false);
|
|
1798
|
+
},
|
|
1799
|
+
capture: true,
|
|
1800
|
+
active: showTooltip && typeof showProp !== 'boolean'
|
|
1801
|
+
}, [setShowTooltip]);
|
|
1763
1802
|
// Handle hover and focus events for the targetElement
|
|
1764
1803
|
React.useEffect(function () {
|
|
1765
1804
|
if (typeof showProp !== 'boolean') {
|
|
@@ -3275,25 +3314,10 @@ var TwoColumnPanel = React.forwardRef(function (_a, ref) {
|
|
|
3275
3314
|
mediaQueryList.removeEventListener('change', listener);
|
|
3276
3315
|
};
|
|
3277
3316
|
}, []);
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
event.keyCode === 27) {
|
|
3283
|
-
setCollapsed(true);
|
|
3284
|
-
}
|
|
3285
|
-
};
|
|
3286
|
-
var targetElement = document.body;
|
|
3287
|
-
if (isFocusTrap) {
|
|
3288
|
-
targetElement.addEventListener('keyup', handleEscape);
|
|
3289
|
-
}
|
|
3290
|
-
else {
|
|
3291
|
-
targetElement.removeEventListener('keyup', handleEscape);
|
|
3292
|
-
}
|
|
3293
|
-
return function () {
|
|
3294
|
-
targetElement.removeEventListener('keyup', handleEscape);
|
|
3295
|
-
};
|
|
3296
|
-
}, [isFocusTrap]);
|
|
3317
|
+
useEscapeKey({
|
|
3318
|
+
callback: function () { return setCollapsed(true); },
|
|
3319
|
+
active: isFocusTrap
|
|
3320
|
+
}, [setCollapsed]);
|
|
3297
3321
|
var handleClickOutside = function () {
|
|
3298
3322
|
if (!isCollapsed && isFocusTrap) {
|
|
3299
3323
|
setCollapsed(true);
|
|
@@ -4076,24 +4100,6 @@ var Popover = React.forwardRef(function (_a, ref) {
|
|
|
4076
4100
|
}
|
|
4077
4101
|
targetElement === null || targetElement === void 0 ? void 0 : targetElement.setAttribute('aria-expanded', Boolean(show).toString());
|
|
4078
4102
|
}, [show, popoverRef.current]);
|
|
4079
|
-
React.useEffect(function () {
|
|
4080
|
-
var handleEscape = function (event) {
|
|
4081
|
-
if (event.key === 'Escape' ||
|
|
4082
|
-
event.key === 'Esc' ||
|
|
4083
|
-
event.keyCode === 27) {
|
|
4084
|
-
handleClosePopover();
|
|
4085
|
-
}
|
|
4086
|
-
};
|
|
4087
|
-
if (show) {
|
|
4088
|
-
document.body.addEventListener('keyup', handleEscape);
|
|
4089
|
-
}
|
|
4090
|
-
else {
|
|
4091
|
-
document.body.removeEventListener('keyup', handleEscape);
|
|
4092
|
-
}
|
|
4093
|
-
return function () {
|
|
4094
|
-
document.body.removeEventListener('keyup', handleEscape);
|
|
4095
|
-
};
|
|
4096
|
-
}, [show]);
|
|
4097
4103
|
React.useEffect(function () {
|
|
4098
4104
|
var attrText = targetElement === null || targetElement === void 0 ? void 0 : targetElement.getAttribute('aria-controls');
|
|
4099
4105
|
var hasPopupAttr = targetElement === null || targetElement === void 0 ? void 0 : targetElement.getAttribute('aria-haspopup');
|
|
@@ -4120,6 +4126,10 @@ var Popover = React.forwardRef(function (_a, ref) {
|
|
|
4120
4126
|
onClose();
|
|
4121
4127
|
}
|
|
4122
4128
|
};
|
|
4129
|
+
useEscapeKey({
|
|
4130
|
+
callback: handleClosePopover,
|
|
4131
|
+
active: show
|
|
4132
|
+
}, [show]);
|
|
4123
4133
|
if (!show || !isBrowser())
|
|
4124
4134
|
return null;
|
|
4125
4135
|
return reactDom.createPortal(React__default["default"].createElement(FocusTrap__default["default"], { focusTrapOptions: {
|
|
@@ -4197,6 +4207,111 @@ var TextEllipsis = React__default["default"].forwardRef(function (_a, ref) {
|
|
|
4197
4207
|
});
|
|
4198
4208
|
TextEllipsis.displayName = 'TextEllipsis';
|
|
4199
4209
|
|
|
4210
|
+
var Drawer = React.forwardRef(function (_a, ref) {
|
|
4211
|
+
var children = _a.children, className = _a.className, position = _a.position, _b = _a.open, open = _b === void 0 ? false : _b, _c = _a.behavior, behavior = _c === void 0 ? 'modal' : _c, _d = _a.focusOptions, focusOptions = _d === void 0 ? {} : _d, portal = _a.portal, onClose = _a.onClose, style = _a.style, props = tslib.__rest(_a, ["children", "className", "position", "open", "behavior", "focusOptions", "portal", "onClose", "style"]);
|
|
4212
|
+
var drawerRef = useSharedRef(ref);
|
|
4213
|
+
var openRef = React.useRef(!!open);
|
|
4214
|
+
var previousActiveElementRef = React.useRef(null);
|
|
4215
|
+
var focusInitial = focusOptions.initialFocus, focusReturn = focusOptions.returnFocus;
|
|
4216
|
+
var _e = tslib.__read(React.useState(!!open), 2), isTransitioning = _e[0], setIsTransitioning = _e[1];
|
|
4217
|
+
var isModal = behavior === 'modal';
|
|
4218
|
+
var handleClose = React.useCallback(function () {
|
|
4219
|
+
// istanbul ignore next
|
|
4220
|
+
if (open && typeof onClose === 'function') {
|
|
4221
|
+
onClose();
|
|
4222
|
+
}
|
|
4223
|
+
}, [open, onClose]);
|
|
4224
|
+
React.useEffect(function () {
|
|
4225
|
+
// jsdom does not trigger transitionend event
|
|
4226
|
+
// istanbul ignore next
|
|
4227
|
+
var transitionEndHandler = function () { return setIsTransitioning(false); };
|
|
4228
|
+
document.addEventListener('transitionend', transitionEndHandler);
|
|
4229
|
+
return function () {
|
|
4230
|
+
document.removeEventListener('transitionend', transitionEndHandler);
|
|
4231
|
+
};
|
|
4232
|
+
}, [setIsTransitioning]);
|
|
4233
|
+
React.useEffect(function () {
|
|
4234
|
+
if (openRef.current !== open) {
|
|
4235
|
+
setIsTransitioning(true);
|
|
4236
|
+
}
|
|
4237
|
+
openRef.current = open;
|
|
4238
|
+
}, [open, setIsTransitioning]);
|
|
4239
|
+
React.useEffect(function () {
|
|
4240
|
+
if (!isModal) {
|
|
4241
|
+
return;
|
|
4242
|
+
}
|
|
4243
|
+
var isolator = new AriaIsolate(drawerRef.current);
|
|
4244
|
+
if (open) {
|
|
4245
|
+
isolator.activate();
|
|
4246
|
+
}
|
|
4247
|
+
else {
|
|
4248
|
+
isolator.deactivate();
|
|
4249
|
+
}
|
|
4250
|
+
return function () {
|
|
4251
|
+
isolator.deactivate();
|
|
4252
|
+
};
|
|
4253
|
+
}, [isModal, open]);
|
|
4254
|
+
React.useLayoutEffect(function () {
|
|
4255
|
+
var _a, _b, _c;
|
|
4256
|
+
if (open) {
|
|
4257
|
+
previousActiveElementRef.current =
|
|
4258
|
+
document.activeElement;
|
|
4259
|
+
var initialFocusElement = resolveElement(focusInitial);
|
|
4260
|
+
if (initialFocusElement) {
|
|
4261
|
+
initialFocusElement.focus();
|
|
4262
|
+
}
|
|
4263
|
+
else {
|
|
4264
|
+
var focusable = (_a = drawerRef.current) === null || _a === void 0 ? void 0 : _a.querySelector(focusableSelector);
|
|
4265
|
+
if (focusable) {
|
|
4266
|
+
focusable.focus();
|
|
4267
|
+
}
|
|
4268
|
+
else {
|
|
4269
|
+
// fallback focus
|
|
4270
|
+
(_b = drawerRef.current) === null || _b === void 0 ? void 0 : _b.focus();
|
|
4271
|
+
}
|
|
4272
|
+
}
|
|
4273
|
+
}
|
|
4274
|
+
else if (previousActiveElementRef.current) {
|
|
4275
|
+
var returnFocusElement = resolveElement(focusReturn);
|
|
4276
|
+
if (returnFocusElement) {
|
|
4277
|
+
returnFocusElement.focus();
|
|
4278
|
+
}
|
|
4279
|
+
else {
|
|
4280
|
+
// fallback focus
|
|
4281
|
+
(_c = previousActiveElementRef.current) === null || _c === void 0 ? void 0 : _c.focus();
|
|
4282
|
+
}
|
|
4283
|
+
}
|
|
4284
|
+
}, [open, focusInitial, focusReturn]);
|
|
4285
|
+
useEscapeKey({ callback: handleClose, active: open, defaultPrevented: true }, [onClose]);
|
|
4286
|
+
// istanbul ignore next
|
|
4287
|
+
if (!isBrowser()) {
|
|
4288
|
+
return null;
|
|
4289
|
+
}
|
|
4290
|
+
var portalElement = resolveElement(portal);
|
|
4291
|
+
return reactDom.createPortal(React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
4292
|
+
React__default["default"].createElement(ClickOutsideListener$1, { onClickOutside: handleClose, mouseEvent: open ? undefined : false, touchEvent: open ? undefined : false, target: drawerRef },
|
|
4293
|
+
React__default["default"].createElement(FocusTrap__default["default"], { active: !!isModal && !!open, focusTrapOptions: {
|
|
4294
|
+
allowOutsideClick: true,
|
|
4295
|
+
escapeDeactivates: false,
|
|
4296
|
+
clickOutsideDeactivates: false,
|
|
4297
|
+
initialFocus: false,
|
|
4298
|
+
setReturnFocus: false,
|
|
4299
|
+
fallbackFocus: function () { return drawerRef.current; }
|
|
4300
|
+
} },
|
|
4301
|
+
React__default["default"].createElement("div", tslib.__assign({ ref: drawerRef, className: classNames__default["default"](className, 'Drawer', {
|
|
4302
|
+
'Drawer--open': !!open,
|
|
4303
|
+
'Drawer--top': position === 'top',
|
|
4304
|
+
'Drawer--bottom': position === 'bottom',
|
|
4305
|
+
'Drawer--left': position === 'left',
|
|
4306
|
+
'Drawer--right': position === 'right'
|
|
4307
|
+
}), "aria-hidden": !open || undefined, style: tslib.__assign({ visibility: !open && !isTransitioning ? 'hidden' : undefined }, style), tabIndex: open ? -1 : undefined }, props), children))),
|
|
4308
|
+
React__default["default"].createElement(Scrim, { show: !!open && !!isModal })), portalElement ||
|
|
4309
|
+
(
|
|
4310
|
+
// eslint-disable-next-line ssr-friendly/no-dom-globals-in-react-fc
|
|
4311
|
+
document === null || document === void 0 ? void 0 : document.body));
|
|
4312
|
+
});
|
|
4313
|
+
Drawer.displayName = 'Drawer';
|
|
4314
|
+
|
|
4200
4315
|
var LIGHT_THEME_CLASS = 'cauldron--theme-light';
|
|
4201
4316
|
var DARK_THEME_CLASS = 'cauldron--theme-dark';
|
|
4202
4317
|
var ThemeContext = React.createContext({
|
|
@@ -4299,6 +4414,7 @@ exports.DescriptionTerm = DescriptionTerm;
|
|
|
4299
4414
|
exports.Dialog = Dialog;
|
|
4300
4415
|
exports.DialogContent = DialogContent;
|
|
4301
4416
|
exports.DialogFooter = DialogFooter;
|
|
4417
|
+
exports.Drawer = Drawer;
|
|
4302
4418
|
exports.ExpandCollapsePanel = ExpandCollapsePanel;
|
|
4303
4419
|
exports.FieldWrap = FieldWrap;
|
|
4304
4420
|
exports.Icon = Icon;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { RefObject, MutableRefObject } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* When an element can be passed as a value that is either an element or an
|
|
4
|
+
* elementRef, this will resolve the property down to the resulting element
|
|
5
|
+
*/
|
|
6
|
+
export default function resolveElement<T extends Element = Element>(elementOrRef: T | RefObject<T> | MutableRefObject<T> | undefined): T | null;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type DependencyList } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* When a component needs to implement an escape handler, such as in modal
|
|
4
|
+
* dialogs, useEscapeKey will handle the events and call the provided callback
|
|
5
|
+
* handler when an escape key event has been fired.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* useEscapeKey(() => close())
|
|
9
|
+
*/
|
|
10
|
+
export default function useEscapeKey<T extends HTMLElement = HTMLElement>(options: {
|
|
11
|
+
active?: boolean;
|
|
12
|
+
callback: (event: KeyboardEvent) => void;
|
|
13
|
+
event?: 'keydown' | 'keypress' | 'keyup';
|
|
14
|
+
target?: T | React.RefObject<T> | React.MutableRefObject<T>;
|
|
15
|
+
defaultPrevented?: boolean;
|
|
16
|
+
capture?: boolean;
|
|
17
|
+
}, dependencies?: DependencyList): void;
|
package/package.json
CHANGED