@deque/cauldron-react 6.7.0 → 6.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,36 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+
5
+ function _interopNamespace(e) {
6
+ if (e && e.__esModule) return e;
7
+ var n = Object.create(null);
8
+ if (e) {
9
+ Object.keys(e).forEach(function (k) {
10
+ if (k !== 'default') {
11
+ var d = Object.getOwnPropertyDescriptor(e, k);
12
+ Object.defineProperty(n, k, d.get ? d : {
13
+ enumerable: true,
14
+ get: function () { return e[k]; }
15
+ });
16
+ }
17
+ });
18
+ }
19
+ n["default"] = e;
20
+ return Object.freeze(n);
21
+ }
22
+
23
+ var React__namespace = /*#__PURE__*/_interopNamespace(React);
24
+
25
+ var _path;
26
+ function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
27
+ const SvgBrokenImage = props => /*#__PURE__*/React__namespace.createElement("svg", _extends({
28
+ viewBox: "0 0 24 24",
29
+ fill: "currentColor",
30
+ height: 24,
31
+ width: 24
32
+ }, props), _path || (_path = /*#__PURE__*/React__namespace.createElement("path", {
33
+ d: "M22.154 0H1.846c-.49 0-.96.23-1.305.639C.195 1.049 0 1.603 0 2.182v19.636c0 .579.195 1.134.54 1.543.347.41.817.639 1.306.639h7.385a.831.831 0 0 0 .54-.206c.157-.134.274-.323.335-.54l1.712-6.065 4.22-1.994a.935.935 0 0 0 .31-.242c.088-.105.158-.23.205-.366l1.687-4.984 5.132-2.023a.952.952 0 0 0 .455-.398A1.23 1.23 0 0 0 24 6.545V2.182c0-.579-.195-1.134-.54-1.543C23.112.229 22.642 0 22.153 0ZM10.2 16.019l-1.636 5.8H1.846V18l6-7.09 3.51 4.147-.625.293a.933.933 0 0 0-.327.266c-.092.115-.16.253-.203.403Zm11.953-10.26-4.907 1.933a.908.908 0 0 0-.342.242 1.117 1.117 0 0 0-.224.388l-1.698 5.021-1.762.839-4.07-4.81c-.346-.409-.815-.638-1.305-.638s-.959.23-1.305.638l-4.695 5.542V2.182h20.308v3.577Zm1.463 4.5a.852.852 0 0 0-.4-.194.789.789 0 0 0-.432.044l-2.746 1.082a.908.908 0 0 0-.341.241 1.117 1.117 0 0 0-.224.388l-1.652 4.878-4.127 1.951a.934.934 0 0 0-.328.265 1.146 1.146 0 0 0-.204.403l-.916 3.246a1.28 1.28 0 0 0-.037.51c.021.17.078.333.163.474.086.14.198.254.329.333.13.079.274.12.42.12h9.032c.49 0 .96-.23 1.305-.639.346-.41.541-.964.541-1.543V11.145c0-.173-.035-.343-.101-.497a1.062 1.062 0 0 0-.282-.388v-.001Zm-1.463 11.56h-7.75l.374-1.33 4.098-1.937a.936.936 0 0 0 .31-.242c.088-.104.158-.229.204-.366l1.639-4.842 1.125-.443v9.16Z"
34
+ })));
35
+
36
+ exports["default"] = SvgBrokenImage;
package/lib/cauldron.css CHANGED
@@ -39,6 +39,12 @@
39
39
  }
40
40
  }
41
41
 
42
+ a.Button--primary,
43
+ a.Button--secondary,
44
+ a.Button--thin {
45
+ font-weight: var(--font-weight-medium);
46
+ }
47
+
42
48
  a.Button--primary,
43
49
  a.Button--secondary {
44
50
  text-decoration: none;
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import { ContentNode } from '../../types';
3
+ declare const BottomSheet: React.ForwardRefExoticComponent<{
4
+ label: ContentNode;
5
+ closeButtonText?: ContentNode | undefined;
6
+ open?: boolean | undefined;
7
+ } & React.HTMLAttributes<HTMLDivElement> & Pick<import("../Drawer").DrawerProps<HTMLElement> & React.RefAttributes<HTMLDivElement>, "open" | "onClose" | "portal" | "focusOptions"> & React.RefAttributes<HTMLDivElement>>;
8
+ export default BottomSheet;
@@ -4,23 +4,7 @@ export interface ClickOutsideListenerProps<T extends HTMLElement = HTMLElement>
4
4
  onClickOutside: (e: MouseEvent | TouchEvent) => void;
5
5
  mouseEvent?: 'mousedown' | 'click' | 'mouseup' | false;
6
6
  touchEvent?: 'touchstart' | 'touchend' | false;
7
- target?: T;
8
- }
9
- export default class ClickOutsideListener extends React.Component<ClickOutsideListenerProps> {
10
- static displayName: string;
11
- static defaultProps: {
12
- mouseEvent: string;
13
- touchEvent: string;
14
- };
15
- private nodeRef;
16
- handleEvent: (event: MouseEvent | TouchEvent) => void;
17
- componentDidMount(): void;
18
- componentDidUpdate(prevProps: ClickOutsideListenerProps): void;
19
- componentWillUnmount(): void;
20
- private attachEventListeners;
21
- private removeEventListeners;
22
- resolveRef: (node: HTMLElement) => void;
23
- render(): React.FunctionComponentElement<{
24
- ref: (node: HTMLElement) => void;
25
- }> | null;
7
+ target?: T | React.RefObject<T> | React.MutableRefObject<T>;
26
8
  }
9
+ declare const _default: React.ForwardRefExoticComponent<ClickOutsideListenerProps<HTMLElement> & React.RefAttributes<HTMLElement>>;
10
+ export default _default;
@@ -0,0 +1,15 @@
1
+ import React from 'react';
2
+ export 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;
@@ -2,6 +2,6 @@
2
2
  * GENERATED CODE. DO NOT EDIT DIRECTLY!
3
3
  */
4
4
  /** IconType represents each valid icon type. */
5
- export type IconType = 'add-user' | 'arrow-circle-up' | 'arrow-circle-down' | 'arrow-circle-left' | 'arrow-circle-right' | 'arrow-up' | 'arrow-down' | 'arrow-left' | 'arrow-right' | 'arrows-alt' | 'bolt' | 'caution' | 'check-circle' | 'check-shield' | 'check-solid' | 'check' | 'checkbox-checked' | 'checkbox-unchecked' | 'chevron-double-up' | 'chevron-double-down' | 'chevron-double-left' | 'chevron-double-right' | 'chevron-up' | 'chevron-down' | 'chevron-left' | 'chevron-right' | 'clipboard' | 'clock' | 'close' | 'code' | 'copy' | 'download' | 'dropper' | 'exchange' | 'export-solid' | 'external-link' | 'eye' | 'filter-solid' | 'filter' | 'flag' | 'gears' | 'github' | 'grid' | 'hamburger-menu' | 'hashtag' | 'highlight' | 'images' | 'info-circle-alt' | 'info-circle' | 'info-square' | 'kabob' | 'link' | 'linkedin' | 'list' | 'lock' | 'magnifying-glass' | 'menu' | 'minus' | 'new-releases' | 'new' | 'no' | 'pencil' | 'person-running' | 'play' | 'plus' | 'question-circle-alt' | 'question-circle' | 'radio-checked' | 'radio-unchecked' | 'recycle-square' | 'recycle' | 'resend' | 'robot' | 'run-again' | 'save' | 'share-nodes' | 'share' | 'sort-triangle' | 'sort' | 'star' | 'step-back' | 'step-forward' | 'sun' | 'table-sort-ascending' | 'table-sort-descending' | 'tag' | 'target' | 'trash' | 'triangle-up' | 'triangle-down' | 'triangle-left' | 'triangle-right' | 'twitter' | 'upload';
5
+ export type IconType = 'add-user' | 'arrow-circle-up' | 'arrow-circle-down' | 'arrow-circle-left' | 'arrow-circle-right' | 'arrow-up' | 'arrow-down' | 'arrow-left' | 'arrow-right' | 'arrows-alt' | 'bolt' | 'broken-image' | 'caution' | 'check-circle' | 'check-shield' | 'check-solid' | 'check' | 'checkbox-checked' | 'checkbox-unchecked' | 'chevron-double-up' | 'chevron-double-down' | 'chevron-double-left' | 'chevron-double-right' | 'chevron-up' | 'chevron-down' | 'chevron-left' | 'chevron-right' | 'clipboard' | 'clock' | 'close' | 'code' | 'copy' | 'download' | 'dropper' | 'exchange' | 'export-solid' | 'external-link' | 'eye' | 'filter-solid' | 'filter' | 'flag' | 'gears' | 'github' | 'grid' | 'hamburger-menu' | 'hashtag' | 'highlight' | 'images' | 'info-circle-alt' | 'info-circle' | 'info-square' | 'kabob' | 'link' | 'linkedin' | 'list' | 'lock' | 'magnifying-glass' | 'menu' | 'minus' | 'new-releases' | 'new' | 'no' | 'pencil' | 'person-running' | 'play' | 'plus' | 'question-circle-alt' | 'question-circle' | 'radio-checked' | 'radio-unchecked' | 'recycle-square' | 'recycle' | 'resend' | 'robot' | 'run-again' | 'save' | 'share-nodes' | 'share' | 'sort-triangle' | 'sort' | 'star' | 'step-back' | 'step-forward' | 'sun' | 'table-sort-ascending' | 'table-sort-descending' | 'tag' | 'target' | 'trash' | 'triangle-up' | 'triangle-down' | 'triangle-left' | 'triangle-right' | 'twitter' | 'upload';
6
6
  /** iconTypes holds each valid icon type. */
7
7
  export declare const iconTypes: string[];
package/lib/index.d.ts CHANGED
@@ -59,6 +59,8 @@ 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';
63
+ export { default as BottomSheet } from './components/BottomSheet';
62
64
  /**
63
65
  * Helpers / Utils
64
66
  */
package/lib/index.js CHANGED
@@ -114,6 +114,7 @@ var iconTypes = [
114
114
  'arrow-right',
115
115
  'arrows-alt',
116
116
  'bolt',
117
+ 'broken-image',
117
118
  'caution',
118
119
  'check-circle',
119
120
  'check-shield',
@@ -206,6 +207,7 @@ function __variableDynamicImportRuntime0__(path) {
206
207
  case './icons/arrow.svg': return Promise.resolve().then(function () { return require('./arrow.js'); });
207
208
  case './icons/arrows-alt.svg': return Promise.resolve().then(function () { return require('./arrows-alt.js'); });
208
209
  case './icons/bolt.svg': return Promise.resolve().then(function () { return require('./bolt.js'); });
210
+ case './icons/broken-image.svg': return Promise.resolve().then(function () { return require('./broken-image.js'); });
209
211
  case './icons/caution.svg': return Promise.resolve().then(function () { return require('./caution.js'); });
210
212
  case './icons/check-circle.svg': return Promise.resolve().then(function () { return require('./check-circle.js'); });
211
213
  case './icons/check-shield.svg': return Promise.resolve().then(function () { return require('./check-shield.js'); });
@@ -791,74 +793,70 @@ var OptionsMenuWrapper = function (_a) {
791
793
  return (React__default["default"].createElement("div", tslib.__assign({ className: classNames__default["default"]('OptionsMenu', menuAlignment(align), className) }, other)));
792
794
  };
793
795
 
794
- var ClickOutsideListener = /** @class */ (function (_super) {
795
- tslib.__extends(ClickOutsideListener, _super);
796
- function ClickOutsideListener() {
797
- var _this = _super !== null && _super.apply(this, arguments) || this;
798
- _this.handleEvent = function (event) {
799
- var _a = _this, nodeRef = _a.nodeRef, props = _a.props;
800
- var onClickOutside = props.onClickOutside, target = props.target;
801
- if (event.defaultPrevented) {
802
- return;
803
- }
804
- var eventTarget = event.target;
805
- if ((target && !target.contains(eventTarget)) ||
806
- (nodeRef && !nodeRef.contains(eventTarget))) {
807
- onClickOutside(event);
808
- }
809
- };
810
- _this.attachEventListeners = function () {
811
- var _a = _this.props, mouseEvent = _a.mouseEvent, touchEvent = _a.touchEvent;
812
- typeof mouseEvent === 'string' &&
813
- document.addEventListener(mouseEvent, _this.handleEvent);
814
- typeof touchEvent === 'string' &&
815
- document.addEventListener(touchEvent, _this.handleEvent);
816
- };
817
- _this.removeEventListeners = function (mouseEvent, touchEvent) {
818
- typeof mouseEvent === 'string' &&
819
- document.removeEventListener(mouseEvent, _this.handleEvent);
820
- typeof touchEvent === 'string' &&
821
- document.removeEventListener(touchEvent, _this.handleEvent);
822
- };
823
- _this.resolveRef = function (node) {
824
- _this.nodeRef = node;
825
- // If child has its own ref, we want to update
826
- // its ref with the newly cloned node
827
- var ref = _this.props.children.ref;
828
- setRef(ref, node);
829
- };
830
- return _this;
796
+ /**
797
+ * When an element can be passed as a value that is either an element or an
798
+ * elementRef, this will resolve the property down to the resulting element
799
+ */
800
+ function resolveElement(elementOrRef) {
801
+ if (elementOrRef instanceof Element) {
802
+ return elementOrRef;
831
803
  }
832
- ClickOutsideListener.prototype.componentDidMount = function () {
833
- this.attachEventListeners();
834
- };
835
- ClickOutsideListener.prototype.componentDidUpdate = function (prevProps) {
836
- var _a = this.props, mouseEvent = _a.mouseEvent, touchEvent = _a.touchEvent;
837
- if (prevProps.mouseEvent !== mouseEvent ||
838
- prevProps.touchEvent !== touchEvent) {
839
- this.removeEventListeners(prevProps.mouseEvent, prevProps.touchEvent);
840
- this.attachEventListeners();
804
+ if (elementOrRef &&
805
+ typeof elementOrRef === 'object' &&
806
+ 'current' in elementOrRef &&
807
+ elementOrRef.current instanceof Element) {
808
+ return elementOrRef.current;
809
+ }
810
+ return null;
811
+ }
812
+
813
+ function ClickOutsideListener(_a, ref) {
814
+ 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;
815
+ var childElementRef = React.useRef();
816
+ var handleEvent = function (event) {
817
+ if (event.defaultPrevented) {
818
+ return;
819
+ }
820
+ var eventTarget = event.target;
821
+ var elementTarget = resolveElement(target);
822
+ if (target && !(elementTarget === null || elementTarget === void 0 ? void 0 : elementTarget.contains(eventTarget))) {
823
+ onClickOutside(event);
824
+ // If a target is passed in via a prop, we defer to utilizing that
825
+ // target instead of a child element target
826
+ return;
827
+ }
828
+ if (childElementRef.current &&
829
+ !childElementRef.current.contains(eventTarget)) {
830
+ onClickOutside(event);
841
831
  }
842
832
  };
843
- ClickOutsideListener.prototype.componentWillUnmount = function () {
844
- var _a = this.props, mouseEvent = _a.mouseEvent, touchEvent = _a.touchEvent;
845
- this.removeEventListeners(mouseEvent, touchEvent);
846
- };
847
- ClickOutsideListener.prototype.render = function () {
848
- var _a = this, props = _a.props, resolveRef = _a.resolveRef;
849
- return !props.children
850
- ? null
851
- : React__default["default"].cloneElement(props.children, {
852
- ref: resolveRef
853
- });
854
- };
855
- ClickOutsideListener.displayName = 'ClickOutsideListener';
856
- ClickOutsideListener.defaultProps = {
857
- mouseEvent: 'click',
858
- touchEvent: 'touchend'
833
+ var resolveRef = function (node) {
834
+ childElementRef.current = node;
835
+ // Ref for this component should pass-through to the child node
836
+ setRef(ref, node);
837
+ // If child has its own ref, we want to update
838
+ // its ref with the newly cloned node
839
+ var childRef = children.ref;
840
+ setRef(childRef, node);
859
841
  };
860
- return ClickOutsideListener;
861
- }(React__default["default"].Component));
842
+ React.useEffect(function () {
843
+ typeof mouseEvent === 'string' &&
844
+ document.addEventListener(mouseEvent, handleEvent);
845
+ typeof touchEvent === 'string' &&
846
+ document.addEventListener(touchEvent, handleEvent);
847
+ return function () {
848
+ typeof mouseEvent === 'string' &&
849
+ document.removeEventListener(mouseEvent, handleEvent);
850
+ typeof touchEvent === 'string' &&
851
+ document.removeEventListener(touchEvent, handleEvent);
852
+ };
853
+ }, [mouseEvent, touchEvent]);
854
+ return !children
855
+ ? null
856
+ : React__default["default"].cloneElement(children, { ref: resolveRef });
857
+ }
858
+ ClickOutsideListener.displayName = 'ClickOutsideListener';
859
+ var ClickOutsideListener$1 = React__default["default"].forwardRef(ClickOutsideListener);
862
860
 
863
861
  var _a$2 = tslib.__read([38, 40, 9, 13, 32, 27], 6), up = _a$2[0], down$1 = _a$2[1], tab = _a$2[2], enter = _a$2[3], space = _a$2[4], esc = _a$2[5];
864
862
  var OptionsMenuList = /** @class */ (function (_super) {
@@ -964,7 +962,7 @@ var OptionsMenuList = /** @class */ (function (_super) {
964
962
  // Key event is being handled in componentDidMount
965
963
  /* eslint-disable jsx-a11y/click-events-have-key-events */
966
964
  /* eslint-disable jsx-a11y/role-supports-aria-props */
967
- return (React__default["default"].createElement(ClickOutsideListener, { onClickOutside: this.handleClickOutside, mouseEvent: clickOutsideEventActive, touchEvent: clickOutsideEventActive },
965
+ return (React__default["default"].createElement(ClickOutsideListener$1, { onClickOutside: this.handleClickOutside, mouseEvent: clickOutsideEventActive, touchEvent: clickOutsideEventActive },
968
966
  React__default["default"].createElement("ul", tslib.__assign({}, other, { className: classNames__default["default"]('OptionsMenu__list', className), "aria-expanded": show, role: "menu", onClick: handleClick, ref: function (el) {
969
967
  _this.menuRef = el;
970
968
  if (menuRef) {
@@ -1312,7 +1310,7 @@ var SideBar = /** @class */ (function (_super) {
1312
1310
  var _b = this.props, children = _b.children, className = _b.className, show = _b.show; _b.onDismiss; var navProps = _b.navProps, other = tslib.__rest(_b, ["children", "className", "show", "onDismiss", "navProps"]);
1313
1311
  /* eslint-disable jsx-a11y/no-noninteractive-element-interactions */
1314
1312
  return (React__default["default"].createElement(React.Fragment, null,
1315
- React__default["default"].createElement(ClickOutsideListener, { onClickOutside: this.handleClickOutside },
1313
+ React__default["default"].createElement(ClickOutsideListener$1, { onClickOutside: this.handleClickOutside },
1316
1314
  React__default["default"].createElement("nav", tslib.__assign({}, navProps),
1317
1315
  React__default["default"].createElement("ul", tslib.__assign({ className: classNames__default["default"]('SideBar', className, animateClass) }, other, { ref: this.navList, onKeyDown: this.onKeyDown }), children))),
1318
1316
  React__default["default"].createElement(Scrim, { show: !wide && show })));
@@ -1451,7 +1449,7 @@ var Dialog = /** @class */ (function (_super) {
1451
1449
  escapeDeactivates: false,
1452
1450
  fallbackFocus: '.Dialog__heading'
1453
1451
  } },
1454
- React__default["default"].createElement(ClickOutsideListener, { onClickOutside: this.handleClickOutside },
1452
+ React__default["default"].createElement(ClickOutsideListener$1, { onClickOutside: this.handleClickOutside },
1455
1453
  React__default["default"].createElement("div", tslib.__assign({ role: "dialog", className: classNames__default["default"]('Dialog', className, {
1456
1454
  'Dialog--show': show
1457
1455
  }), ref: function (el) {
@@ -1667,6 +1665,46 @@ function hasIdRef(ids, id) {
1667
1665
  return idRefs(ids).has(id);
1668
1666
  }
1669
1667
 
1668
+ var isEscapeKey = function (event) {
1669
+ return event.key === 'Escape' || event.key === 'Esc' || event.keyCode === 27;
1670
+ };
1671
+ /**
1672
+ * When a component needs to implement an escape handler, such as in modal
1673
+ * dialogs, useEscapeKey will handle the events and call the provided callback
1674
+ * handler when an escape key event has been fired.
1675
+ *
1676
+ * @example
1677
+ * useEscapeKey(() => close())
1678
+ */
1679
+ function useEscapeKey(options, dependencies) {
1680
+ if (dependencies === void 0) { dependencies = []; }
1681
+ var callback = options.callback;
1682
+ var event = options.event || 'keyup';
1683
+ var target = resolveElement(options.target) || document.body;
1684
+ var active = typeof options.active === 'boolean' ? options.active : true;
1685
+ React.useEffect(function () {
1686
+ var eventListener = function (event) {
1687
+ if (isEscapeKey(event) &&
1688
+ (options.defaultPrevented ? !event.defaultPrevented : true)) {
1689
+ callback(event);
1690
+ }
1691
+ };
1692
+ if (active) {
1693
+ target === null || target === void 0 ? void 0 : target.addEventListener(event, eventListener, options.capture);
1694
+ }
1695
+ return function () {
1696
+ target === null || target === void 0 ? void 0 : target.removeEventListener(event, eventListener, options.capture);
1697
+ };
1698
+ }, tslib.__spreadArray([
1699
+ active,
1700
+ callback,
1701
+ event,
1702
+ target,
1703
+ options.capture,
1704
+ options.defaultPrevented
1705
+ ], tslib.__read(dependencies), false));
1706
+ }
1707
+
1670
1708
  var TIP_HIDE_DELAY = 100;
1671
1709
  // fires a custom "cauldron:tooltip:show" / "cauldron:tooltip:hide" event
1672
1710
  // to allow projects using cauldron to hook into when a tooltip is shown/hidden
@@ -1755,30 +1793,14 @@ function Tooltip(_a) {
1755
1793
  attributes.popper['data-popper-placement']) ||
1756
1794
  initialPlacement;
1757
1795
  // Only listen to key ups when the tooltip is visible
1758
- React.useEffect(function () {
1759
- var handleEscape = function (event) {
1760
- if (event.key === 'Escape' ||
1761
- event.key === 'Esc' ||
1762
- event.keyCode === 27) {
1763
- event.preventDefault();
1764
- setShowTooltip(false);
1765
- }
1766
- };
1767
- var targetElement = document.body;
1768
- if (showTooltip && typeof showProp !== 'boolean') {
1769
- targetElement.addEventListener('keyup', handleEscape, { capture: true });
1770
- }
1771
- else {
1772
- targetElement.removeEventListener('keyup', handleEscape, {
1773
- capture: true
1774
- });
1775
- }
1776
- return function () {
1777
- targetElement.removeEventListener('keyup', handleEscape, {
1778
- capture: true
1779
- });
1780
- };
1781
- }, [showTooltip, showProp]);
1796
+ useEscapeKey({
1797
+ callback: function (event) {
1798
+ event.preventDefault();
1799
+ setShowTooltip(false);
1800
+ },
1801
+ capture: true,
1802
+ active: showTooltip && typeof showProp !== 'boolean'
1803
+ }, [setShowTooltip]);
1782
1804
  // Handle hover and focus events for the targetElement
1783
1805
  React.useEffect(function () {
1784
1806
  if (typeof showProp !== 'boolean') {
@@ -3294,25 +3316,10 @@ var TwoColumnPanel = React.forwardRef(function (_a, ref) {
3294
3316
  mediaQueryList.removeEventListener('change', listener);
3295
3317
  };
3296
3318
  }, []);
3297
- React.useEffect(function () {
3298
- var handleEscape = function (event) {
3299
- if (event.key === 'Escape' ||
3300
- event.key === 'Esc' ||
3301
- event.keyCode === 27) {
3302
- setCollapsed(true);
3303
- }
3304
- };
3305
- var targetElement = document.body;
3306
- if (isFocusTrap) {
3307
- targetElement.addEventListener('keyup', handleEscape);
3308
- }
3309
- else {
3310
- targetElement.removeEventListener('keyup', handleEscape);
3311
- }
3312
- return function () {
3313
- targetElement.removeEventListener('keyup', handleEscape);
3314
- };
3315
- }, [isFocusTrap]);
3319
+ useEscapeKey({
3320
+ callback: function () { return setCollapsed(true); },
3321
+ active: isFocusTrap
3322
+ }, [setCollapsed]);
3316
3323
  var handleClickOutside = function () {
3317
3324
  if (!isCollapsed && isFocusTrap) {
3318
3325
  setCollapsed(true);
@@ -3328,7 +3335,7 @@ var TwoColumnPanel = React.forwardRef(function (_a, ref) {
3328
3335
  allowOutsideClick: true,
3329
3336
  fallbackFocus: columnLeftRef.current
3330
3337
  }, containerElements: [columnLeftRef.current] }),
3331
- React__default["default"].createElement(ClickOutsideListener, { onClickOutside: handleClickOutside, target: columnLeftRef.current }),
3338
+ React__default["default"].createElement(ClickOutsideListener$1, { onClickOutside: handleClickOutside, target: columnLeftRef.current }),
3332
3339
  isCollapsed ? null : skipLink,
3333
3340
  showPanel ? ColumnLeftComponent : null,
3334
3341
  ColumnRightComponent)));
@@ -3360,8 +3367,8 @@ var iconTypeMap = {
3360
3367
  };
3361
3368
  var Notice = React.forwardRef(function (_a, ref) {
3362
3369
  var _b;
3363
- var _c = _a.type, type = _c === void 0 ? 'info' : _c, title = _a.title, icon = _a.icon, _d = _a.variant, variant = _d === void 0 ? 'default' : _d, children = _a.children, otherProps = tslib.__rest(_a, ["type", "title", "icon", "variant", "children"]);
3364
- return (React__default["default"].createElement("div", tslib.__assign({ className: classNames__default["default"]('Notice', (_b = {},
3370
+ var className = _a.className, _c = _a.type, type = _c === void 0 ? 'info' : _c, title = _a.title, icon = _a.icon, _d = _a.variant, variant = _d === void 0 ? 'default' : _d, children = _a.children, otherProps = tslib.__rest(_a, ["className", "type", "title", "icon", "variant", "children"]);
3371
+ return (React__default["default"].createElement("div", tslib.__assign({ className: classNames__default["default"]('Notice', className, (_b = {},
3365
3372
  _b["Notice--".concat(type)] = type,
3366
3373
  _b["Notice--condensed"] = variant === 'condensed',
3367
3374
  _b)), ref: ref }, otherProps),
@@ -4095,24 +4102,6 @@ var Popover = React.forwardRef(function (_a, ref) {
4095
4102
  }
4096
4103
  targetElement === null || targetElement === void 0 ? void 0 : targetElement.setAttribute('aria-expanded', Boolean(show).toString());
4097
4104
  }, [show, popoverRef.current]);
4098
- React.useEffect(function () {
4099
- var handleEscape = function (event) {
4100
- if (event.key === 'Escape' ||
4101
- event.key === 'Esc' ||
4102
- event.keyCode === 27) {
4103
- handleClosePopover();
4104
- }
4105
- };
4106
- if (show) {
4107
- document.body.addEventListener('keyup', handleEscape);
4108
- }
4109
- else {
4110
- document.body.removeEventListener('keyup', handleEscape);
4111
- }
4112
- return function () {
4113
- document.body.removeEventListener('keyup', handleEscape);
4114
- };
4115
- }, [show]);
4116
4105
  React.useEffect(function () {
4117
4106
  var attrText = targetElement === null || targetElement === void 0 ? void 0 : targetElement.getAttribute('aria-controls');
4118
4107
  var hasPopupAttr = targetElement === null || targetElement === void 0 ? void 0 : targetElement.getAttribute('aria-haspopup');
@@ -4139,13 +4128,17 @@ var Popover = React.forwardRef(function (_a, ref) {
4139
4128
  onClose();
4140
4129
  }
4141
4130
  };
4131
+ useEscapeKey({
4132
+ callback: handleClosePopover,
4133
+ active: show
4134
+ }, [show]);
4142
4135
  if (!show || !isBrowser())
4143
4136
  return null;
4144
4137
  return reactDom.createPortal(React__default["default"].createElement(FocusTrap__default["default"], { focusTrapOptions: {
4145
4138
  allowOutsideClick: true,
4146
4139
  fallbackFocus: '.Popover__borderLeft'
4147
4140
  } },
4148
- React__default["default"].createElement(ClickOutsideListener, { onClickOutside: handleClickOutside },
4141
+ React__default["default"].createElement(ClickOutsideListener$1, { onClickOutside: handleClickOutside },
4149
4142
  React__default["default"].createElement("div", tslib.__assign({ id: id, className: classNames__default["default"]('Popover', "Popover--".concat(placement), className, {
4150
4143
  'Popover--hidden': !show,
4151
4144
  'Popover--prompt': variant === 'prompt'
@@ -4216,6 +4209,133 @@ var TextEllipsis = React__default["default"].forwardRef(function (_a, ref) {
4216
4209
  });
4217
4210
  TextEllipsis.displayName = 'TextEllipsis';
4218
4211
 
4212
+ var Drawer = React.forwardRef(function (_a, ref) {
4213
+ 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"]);
4214
+ var drawerRef = useSharedRef(ref);
4215
+ var openRef = React.useRef(!!open);
4216
+ var previousActiveElementRef = React.useRef(null);
4217
+ var focusInitial = focusOptions.initialFocus, focusReturn = focusOptions.returnFocus;
4218
+ var _e = tslib.__read(React.useState(!!open), 2), isTransitioning = _e[0], setIsTransitioning = _e[1];
4219
+ var isModal = behavior === 'modal';
4220
+ var handleClose = React.useCallback(function () {
4221
+ // istanbul ignore next
4222
+ if (open && typeof onClose === 'function') {
4223
+ onClose();
4224
+ }
4225
+ }, [open, onClose]);
4226
+ React.useEffect(function () {
4227
+ // jsdom does not trigger transitionend event
4228
+ // istanbul ignore next
4229
+ var transitionEndHandler = function () { return setIsTransitioning(false); };
4230
+ document.addEventListener('transitionend', transitionEndHandler);
4231
+ return function () {
4232
+ document.removeEventListener('transitionend', transitionEndHandler);
4233
+ };
4234
+ }, [setIsTransitioning]);
4235
+ React.useEffect(function () {
4236
+ if (openRef.current !== open) {
4237
+ setIsTransitioning(true);
4238
+ }
4239
+ openRef.current = open;
4240
+ }, [open, setIsTransitioning]);
4241
+ React.useEffect(function () {
4242
+ if (!isModal) {
4243
+ return;
4244
+ }
4245
+ var isolator = new AriaIsolate(drawerRef.current);
4246
+ if (open) {
4247
+ isolator.activate();
4248
+ }
4249
+ else {
4250
+ isolator.deactivate();
4251
+ }
4252
+ return function () {
4253
+ isolator.deactivate();
4254
+ };
4255
+ }, [isModal, open]);
4256
+ React.useLayoutEffect(function () {
4257
+ var _a, _b, _c;
4258
+ if (open) {
4259
+ previousActiveElementRef.current =
4260
+ document.activeElement;
4261
+ var initialFocusElement = resolveElement(focusInitial);
4262
+ if (initialFocusElement) {
4263
+ initialFocusElement.focus();
4264
+ }
4265
+ else {
4266
+ var focusable = (_a = drawerRef.current) === null || _a === void 0 ? void 0 : _a.querySelector(focusableSelector);
4267
+ if (focusable) {
4268
+ focusable.focus();
4269
+ }
4270
+ else {
4271
+ // fallback focus
4272
+ (_b = drawerRef.current) === null || _b === void 0 ? void 0 : _b.focus();
4273
+ }
4274
+ }
4275
+ }
4276
+ else if (previousActiveElementRef.current) {
4277
+ var returnFocusElement = resolveElement(focusReturn);
4278
+ if (returnFocusElement) {
4279
+ returnFocusElement.focus();
4280
+ }
4281
+ else {
4282
+ // fallback focus
4283
+ (_c = previousActiveElementRef.current) === null || _c === void 0 ? void 0 : _c.focus();
4284
+ }
4285
+ }
4286
+ }, [open, focusInitial, focusReturn]);
4287
+ useEscapeKey({ callback: handleClose, active: open, defaultPrevented: true }, [onClose]);
4288
+ // istanbul ignore next
4289
+ if (!isBrowser()) {
4290
+ return null;
4291
+ }
4292
+ var portalElement = resolveElement(portal);
4293
+ return reactDom.createPortal(React__default["default"].createElement(React__default["default"].Fragment, null,
4294
+ React__default["default"].createElement(ClickOutsideListener$1, { onClickOutside: handleClose, mouseEvent: open ? undefined : false, touchEvent: open ? undefined : false, target: drawerRef },
4295
+ React__default["default"].createElement(FocusTrap__default["default"], { active: !!isModal && !!open, focusTrapOptions: {
4296
+ allowOutsideClick: true,
4297
+ escapeDeactivates: false,
4298
+ clickOutsideDeactivates: false,
4299
+ initialFocus: false,
4300
+ setReturnFocus: false,
4301
+ fallbackFocus: function () { return drawerRef.current; }
4302
+ } },
4303
+ React__default["default"].createElement("div", tslib.__assign({ ref: drawerRef, className: classNames__default["default"](className, 'Drawer', {
4304
+ 'Drawer--open': !!open,
4305
+ 'Drawer--top': position === 'top',
4306
+ 'Drawer--bottom': position === 'bottom',
4307
+ 'Drawer--left': position === 'left',
4308
+ 'Drawer--right': position === 'right'
4309
+ }), "aria-hidden": !open || undefined, style: tslib.__assign({ visibility: !open && !isTransitioning ? 'hidden' : undefined }, style), tabIndex: open ? -1 : undefined }, props), children))),
4310
+ React__default["default"].createElement(Scrim, { show: !!open && !!isModal })), portalElement ||
4311
+ (
4312
+ // eslint-disable-next-line ssr-friendly/no-dom-globals-in-react-fc
4313
+ document === null || document === void 0 ? void 0 : document.body));
4314
+ });
4315
+ Drawer.displayName = 'Drawer';
4316
+
4317
+ var BottomSheet = React.forwardRef(function (_a, ref) {
4318
+ var label = _a.label, children = _a.children, className = _a.className, _b = _a.closeButtonText, closeButtonText = _b === void 0 ? 'Close' : _b, _c = _a.open, open = _c === void 0 ? false : _c, onClose = _a.onClose, focusOptions = _a.focusOptions, props = tslib.__rest(_a, ["label", "children", "className", "closeButtonText", "open", "onClose", "focusOptions"]);
4319
+ var bottomSheetRef = useSharedRef(ref);
4320
+ var _d = tslib.__read(nextId.useId(1, 'bottom-sheet-label'), 1), labelId = _d[0];
4321
+ var handleClose = React.useCallback(function () {
4322
+ // istanbul ignore else
4323
+ if (typeof onClose === 'function') {
4324
+ onClose();
4325
+ }
4326
+ }, [onClose]);
4327
+ return (React__default["default"].createElement(Drawer, tslib.__assign({ open: open, onClose: handleClose, focusOptions: tslib.__assign({ initialFocus: bottomSheetRef }, focusOptions) }, props, { behavior: "modal", position: "bottom" }),
4328
+ React__default["default"].createElement("div", { ref: bottomSheetRef, className: classNames__default["default"]('BottomSheet', className), tabIndex: -1, role: "dialog", "aria-labelledby": labelId },
4329
+ React__default["default"].createElement("div", { className: "BottomSheet__header" },
4330
+ React__default["default"].createElement("div", { id: labelId, className: "BottomSheet__title" }, label),
4331
+ React__default["default"].createElement(IconButton, { icon: "close", label: closeButtonText, "aria-label": "".concat(closeButtonText), onClick: handleClose, tooltipProps: {
4332
+ show: false,
4333
+ association: 'none'
4334
+ } })),
4335
+ React__default["default"].createElement("div", { className: "BottomSheet__contents" }, children))));
4336
+ });
4337
+ BottomSheet.displayName = 'BottomSheet';
4338
+
4219
4339
  var LIGHT_THEME_CLASS = 'cauldron--theme-light';
4220
4340
  var DARK_THEME_CLASS = 'cauldron--theme-dark';
4221
4341
  var ThemeContext = React.createContext({
@@ -4295,12 +4415,13 @@ exports.AlertContent = AlertContent;
4295
4415
  exports.AriaIsolate = AriaIsolate;
4296
4416
  exports.Badge = Badge;
4297
4417
  exports.BadgeLabel = BadgeLabel;
4418
+ exports.BottomSheet = BottomSheet;
4298
4419
  exports.Breadcrumb = Breadcrumb;
4299
4420
  exports.BreadcrumbItem = BreadcrumbItem;
4300
4421
  exports.BreadcrumbLink = BreadcrumbLink;
4301
4422
  exports.Button = Button;
4302
4423
  exports.Checkbox = Checkbox;
4303
- exports.ClickOutsideListener = ClickOutsideListener;
4424
+ exports.ClickOutsideListener = ClickOutsideListener$1;
4304
4425
  exports.Code = Code;
4305
4426
  exports.ColumnGroupHeader = ColumnGroupHeader;
4306
4427
  exports.ColumnHeader = ColumnHeader;
@@ -4318,6 +4439,7 @@ exports.DescriptionTerm = DescriptionTerm;
4318
4439
  exports.Dialog = Dialog;
4319
4440
  exports.DialogContent = DialogContent;
4320
4441
  exports.DialogFooter = DialogFooter;
4442
+ exports.Drawer = Drawer;
4321
4443
  exports.ExpandCollapsePanel = ExpandCollapsePanel;
4322
4444
  exports.FieldWrap = FieldWrap;
4323
4445
  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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deque/cauldron-react",
3
- "version": "6.7.0",
3
+ "version": "6.8.0",
4
4
  "license": "MPL-2.0",
5
5
  "description": "Fully accessible react components library for Deque Cauldron",
6
6
  "homepage": "https://cauldron.dequelabs.com/",