@deque/cauldron-react 4.1.0-canary.3eec0660 → 4.1.0-canary.4ee8aabd

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.
@@ -1,10 +1,11 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
- export interface ClickOutsideListenerProps {
4
- children: React.ReactNode;
3
+ export interface ClickOutsideListenerProps<T extends HTMLElement = HTMLElement> {
4
+ children?: React.ReactNode;
5
5
  onClickOutside: (e: MouseEvent | TouchEvent) => void;
6
6
  mouseEvent?: 'mousedown' | 'click' | 'mouseup' | false;
7
7
  touchEvent?: 'touchstart' | 'touchend' | false;
8
+ target?: T;
8
9
  }
9
10
  export default class ClickOutsideListener extends React.Component<ClickOutsideListenerProps> {
10
11
  static defaultProps: {
@@ -12,7 +13,8 @@ export default class ClickOutsideListener extends React.Component<ClickOutsideLi
12
13
  touchEvent: string;
13
14
  };
14
15
  static propTypes: {
15
- children: PropTypes.Validator<string | number | boolean | {} | PropTypes.ReactElementLike | PropTypes.ReactNodeArray>;
16
+ children: PropTypes.Requireable<PropTypes.ReactNodeLike>;
17
+ target: PropTypes.Requireable<any>;
16
18
  onClickOutside: PropTypes.Validator<(...args: any[]) => any>;
17
19
  mouseEvent: PropTypes.Requireable<string | boolean>;
18
20
  touchEvent: PropTypes.Requireable<string | boolean>;
@@ -27,5 +29,5 @@ export default class ClickOutsideListener extends React.Component<ClickOutsideLi
27
29
  resolveRef: (node: HTMLElement) => void;
28
30
  render(): React.FunctionComponentElement<{
29
31
  ref: (node: HTMLElement) => void;
30
- }>;
32
+ }> | null;
31
33
  }
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+ interface ColumnGroupHeaderProps extends React.HTMLAttributes<HTMLDivElement> {
3
+ }
4
+ declare const ColumnGroupHeader: React.ForwardRefExoticComponent<ColumnGroupHeaderProps & React.RefAttributes<HTMLDivElement>>;
5
+ export default ColumnGroupHeader;
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+ interface ColumnHeaderProps extends React.HTMLAttributes<HTMLDivElement> {
3
+ }
4
+ declare const ColumnHeader: React.ForwardRefExoticComponent<ColumnHeaderProps & React.RefAttributes<HTMLDivElement>>;
5
+ export default ColumnHeader;
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ declare const ColumnLeft: React.ForwardRefExoticComponent<(React.HTMLAttributes<HTMLDivElement> & {
3
+ 'aria-label': string;
4
+ } & React.RefAttributes<HTMLDivElement>) | (React.HTMLAttributes<HTMLDivElement> & {
5
+ 'aria-labelledby': string;
6
+ } & React.RefAttributes<HTMLDivElement>)>;
7
+ export default ColumnLeft;
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+ interface ColumnListProps extends React.HTMLAttributes<HTMLDivElement> {
3
+ }
4
+ declare const ColumnList: React.ForwardRefExoticComponent<ColumnListProps & React.RefAttributes<HTMLDivElement>>;
5
+ export default ColumnList;
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ declare const ColumnRight: React.ForwardRefExoticComponent<(React.HTMLAttributes<HTMLDivElement> & {
3
+ 'aria-label': string;
4
+ } & React.RefAttributes<HTMLDivElement>) | (React.HTMLAttributes<HTMLDivElement> & {
5
+ 'aria-labelledby': string;
6
+ } & React.RefAttributes<HTMLDivElement>)>;
7
+ export default ColumnRight;
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ interface TwoColumnPanelProps extends React.HTMLAttributes<HTMLDivElement> {
3
+ initialCollapsed?: boolean;
4
+ showCollapsedPanelLabel?: string;
5
+ hideCollapsedPanelLabel?: string;
6
+ }
7
+ declare const TwoColumnPanel: React.ForwardRefExoticComponent<TwoColumnPanelProps & React.RefAttributes<HTMLDivElement>>;
8
+ export default TwoColumnPanel;
@@ -0,0 +1,6 @@
1
+ export { default } from './TwoColumnPanel';
2
+ export { default as ColumnHeader } from './ColumnHeader';
3
+ export { default as ColumnGroupHeader } from './ColumnGroupHeader';
4
+ export { default as ColumnLeft } from './ColumnLeft';
5
+ export { default as ColumnRight } from './ColumnRight';
6
+ export { default as ColumnList } from './ColumnList';
package/lib/index.d.ts CHANGED
@@ -48,6 +48,7 @@ export { Address, AddressLine, AddressCityStateZip } from './components/Address'
48
48
  export { default as Pagination } from './components/Pagination';
49
49
  export { default as FieldWrap } from './components/FieldWrap';
50
50
  export { default as Breadcrumb, BreadcrumbItem, BreadcrumbLink } from './components/Breadcrumb';
51
+ export { default as TwoColumnPanel, ColumnHeader, ColumnGroupHeader, ColumnLeft, ColumnRight, ColumnList } from './components/TwoColumnPanel';
51
52
  /**
52
53
  * Helpers / Utils
53
54
  */
package/lib/index.js CHANGED
@@ -608,12 +608,13 @@ var ClickOutsideListener = /** @class */ (function (_super) {
608
608
  var _this = _super !== null && _super.apply(this, arguments) || this;
609
609
  _this.handleEvent = function (event) {
610
610
  var _a = _this, nodeRef = _a.nodeRef, props = _a.props;
611
- var onClickOutside = props.onClickOutside;
611
+ var onClickOutside = props.onClickOutside, target = props.target;
612
612
  if (event.defaultPrevented) {
613
613
  return;
614
614
  }
615
- var target = event.target;
616
- if (nodeRef && !nodeRef.contains(target)) {
615
+ var eventTarget = event.target;
616
+ if ((target && !target.contains(eventTarget)) ||
617
+ (nodeRef && !nodeRef.contains(eventTarget))) {
617
618
  onClickOutside(event);
618
619
  }
619
620
  };
@@ -656,16 +657,19 @@ var ClickOutsideListener = /** @class */ (function (_super) {
656
657
  };
657
658
  ClickOutsideListener.prototype.render = function () {
658
659
  var _a = this, props = _a.props, resolveRef = _a.resolveRef;
659
- return React__default.cloneElement(props.children, {
660
- ref: resolveRef
661
- });
660
+ return !props.children
661
+ ? null
662
+ : React__default.cloneElement(props.children, {
663
+ ref: resolveRef
664
+ });
662
665
  };
663
666
  ClickOutsideListener.defaultProps = {
664
667
  mouseEvent: 'click',
665
668
  touchEvent: 'touchend'
666
669
  };
667
670
  ClickOutsideListener.propTypes = {
668
- children: PropTypes.node.isRequired,
671
+ children: PropTypes.node,
672
+ target: PropTypes.any,
669
673
  onClickOutside: PropTypes.func.isRequired,
670
674
  mouseEvent: PropTypes.oneOf(['mousedown', 'click', 'mouseup', false]),
671
675
  touchEvent: PropTypes.oneOf(['touchstart', 'touchend', false])
@@ -2012,7 +2016,7 @@ var queryAll = function (selector, context) {
2012
2016
  var typeMap = {
2013
2017
  confirmation: {
2014
2018
  className: 'success',
2015
- icon: 'info-circle'
2019
+ icon: 'check-circle'
2016
2020
  },
2017
2021
  caution: {
2018
2022
  className: 'warning',
@@ -8483,6 +8487,172 @@ var BreadcrumbLink = React.forwardRef(function (_a, ref) {
8483
8487
  return (React__default.createElement(ElementType, tslib.__assign({ className: classNames('Link', 'Breadcrumb__Link', className), ref: ref }, props), children));
8484
8488
  });
8485
8489
 
8490
+ var TwoColumnPanel = React.forwardRef(function (_a, ref) {
8491
+ var className = _a.className, children = _a.children, _b = _a.initialCollapsed, initialCollapsed = _b === void 0 ? false : _b, _c = _a.showCollapsedPanelLabel, showCollapsedPanelLabel = _c === void 0 ? 'Show Panel' : _c, _d = _a.hideCollapsedPanelLabel, hideCollapsedPanelLabel = _d === void 0 ? 'Hide Panel' : _d, props = tslib.__rest(_a, ["className", "children", "initialCollapsed", "showCollapsedPanelLabel", "hideCollapsedPanelLabel"]);
8492
+ var _e = tslib.__read(React.useState(initialCollapsed), 2), isCollapsed = _e[0], setCollapsed = _e[1];
8493
+ var _f = tslib.__read(React.useState(false), 2), isFocusTrap = _f[0], setIsFocusTrap = _f[1];
8494
+ var _g = tslib.__read(React.useState(!initialCollapsed), 2), showPanel = _g[0], setShowPanel = _g[1];
8495
+ var togglePanel = function () {
8496
+ if (isCollapsed) {
8497
+ setShowPanel(true);
8498
+ }
8499
+ // Set collapsed state on next tick so css transitions can be applied
8500
+ requestAnimationFrame(function () {
8501
+ var _a, _b;
8502
+ var collapsed = !isCollapsed;
8503
+ setCollapsed(collapsed);
8504
+ if (!collapsed) {
8505
+ (_a = columnLeftRef.current) === null || _a === void 0 ? void 0 : _a.focus();
8506
+ }
8507
+ else {
8508
+ (_b = columnRightRef.current) === null || _b === void 0 ? void 0 : _b.focus();
8509
+ }
8510
+ });
8511
+ };
8512
+ var toggleButtonRef = React.useRef(null);
8513
+ var closeButtonRef = React.useRef(null);
8514
+ var columnLeftRef = React.useRef(null);
8515
+ var columnRightRef = React.useRef(null);
8516
+ var columnLeft = React__default.Children.toArray(children).find(function (child) { return child.type === ColumnLeft; });
8517
+ // The ColumnLeftComponent will end up being a focus trap when < 720px
8518
+ // This component also gets unmounted when not visible meaning that any
8519
+ // aria relationships cannot be set to items inside the component since
8520
+ // they will not be present in the dom
8521
+ var ColumnLeftComponent;
8522
+ var columnLeftId;
8523
+ if (React.isValidElement(columnLeft)) {
8524
+ var ref_1 = columnLeft.props.ref || columnLeftRef;
8525
+ var id = (columnLeftId =
8526
+ columnLeft.props.id || nextId.useId(undefined, 'sidebar-')[0]);
8527
+ var CloseButton = (React__default.createElement("div", { className: "TwoColumnPanel__Close" },
8528
+ React__default.createElement("button", { type: "button", onClick: togglePanel, ref: closeButtonRef, "aria-label": hideCollapsedPanelLabel },
8529
+ React__default.createElement(Icon, { type: "close" })),
8530
+ React__default.createElement(Tooltip, { target: closeButtonRef, association: "aria-labelledby", hideElementOnHidden: true }, hideCollapsedPanelLabel)));
8531
+ var children_1 = tslib.__spread([
8532
+ CloseButton
8533
+ ], React__default.Children.toArray(columnLeft.props.children));
8534
+ ColumnLeftComponent = React.cloneElement(columnLeft, { id: id, ref: ref_1, tabIndex: -1 }, children_1.map(function (child, index) {
8535
+ return React.cloneElement(child, { key: "left-" + index });
8536
+ }));
8537
+ }
8538
+ var columnRight = React__default.Children.toArray(children).find(function (child) { return child.type === ColumnRight; });
8539
+ var ColumnRightComponent;
8540
+ if (React.isValidElement(columnRight)) {
8541
+ var ref_2 = columnRight.props.ref || columnRightRef;
8542
+ var ToggleButton = (React__default.createElement("div", { className: "TwoColumnPanel__ButtonToggle" },
8543
+ React__default.createElement("button", { type: "button", onClick: togglePanel, ref: toggleButtonRef, "aria-label": !isCollapsed ? hideCollapsedPanelLabel : showCollapsedPanelLabel, "aria-expanded": !isCollapsed, "aria-controls": columnLeftId },
8544
+ React__default.createElement(Icon, { type: !isCollapsed ? 'chevron-double-left' : 'chevron-double-right' })),
8545
+ React__default.createElement(Tooltip, { target: toggleButtonRef, association: "aria-labelledby", hideElementOnHidden: true }, !isCollapsed ? hideCollapsedPanelLabel : showCollapsedPanelLabel)));
8546
+ var children_2 = tslib.__spread([
8547
+ ToggleButton
8548
+ ], React__default.Children.toArray(columnRight.props.children));
8549
+ ColumnRightComponent = React.cloneElement(columnRight, { ref: ref_2, tabIndex: -1 }, children_2.map(function (child, index) {
8550
+ return React.cloneElement(child, { key: "right-" + index });
8551
+ }));
8552
+ }
8553
+ React.useLayoutEffect(function () {
8554
+ var _a;
8555
+ var handleTransitionEnd = function () {
8556
+ if (columnLeftRef.current && isCollapsed) {
8557
+ setShowPanel(false);
8558
+ }
8559
+ };
8560
+ (_a = columnLeftRef.current) === null || _a === void 0 ? void 0 : _a.addEventListener('transitionend', handleTransitionEnd);
8561
+ return function () {
8562
+ var _a;
8563
+ (_a = columnLeftRef.current) === null || _a === void 0 ? void 0 : _a.removeEventListener('transitionend', handleTransitionEnd);
8564
+ };
8565
+ }, [columnLeftRef.current, isCollapsed]);
8566
+ // When the collapsable panel starts to overlay content, it needs to become a focus trap and collapsed by default
8567
+ React.useLayoutEffect(function () {
8568
+ var mediaQueryList = matchMedia('(max-width: 45rem)');
8569
+ var handleMatch = function (matches) {
8570
+ setIsFocusTrap(matches);
8571
+ var collapsed = matches ? true : isCollapsed;
8572
+ setCollapsed(collapsed);
8573
+ setShowPanel(!collapsed);
8574
+ };
8575
+ var listener = function (_a) {
8576
+ var matches = _a.matches;
8577
+ return handleMatch(matches);
8578
+ };
8579
+ if (mediaQueryList.matches) {
8580
+ handleMatch(mediaQueryList.matches);
8581
+ }
8582
+ mediaQueryList.addEventListener('change', listener);
8583
+ return function () {
8584
+ mediaQueryList.removeEventListener('change', listener);
8585
+ };
8586
+ }, []);
8587
+ React.useEffect(function () {
8588
+ var handleEscape = function (event) {
8589
+ if (event.key === 'Escape' ||
8590
+ event.key === 'Esc' ||
8591
+ event.keyCode === 27) {
8592
+ setCollapsed(true);
8593
+ }
8594
+ };
8595
+ var targetElement = document.body;
8596
+ if (isFocusTrap) {
8597
+ targetElement.addEventListener('keyup', handleEscape);
8598
+ }
8599
+ else {
8600
+ targetElement.removeEventListener('keyup', handleEscape);
8601
+ }
8602
+ return function () {
8603
+ targetElement.removeEventListener('keyup', handleEscape);
8604
+ };
8605
+ }, [isFocusTrap]);
8606
+ var handleClickOutside = function () {
8607
+ if (!isCollapsed && isFocusTrap) {
8608
+ setCollapsed(true);
8609
+ }
8610
+ };
8611
+ return (React__default.createElement("div", tslib.__assign({ className: classNames('TwoColumnPanel', className, {
8612
+ 'TwoColumnPanel--show': !isCollapsed,
8613
+ 'TwoColumnPanel--hide': isCollapsed
8614
+ }) }, props, { ref: ref }),
8615
+ React__default.createElement(FocusTrap, { active: !isCollapsed && isFocusTrap, focusTrapOptions: {
8616
+ escapeDeactivates: true,
8617
+ allowOutsideClick: true,
8618
+ fallbackFocus: columnLeftRef.current
8619
+ }, containerElements: [columnLeftRef.current] }),
8620
+ React__default.createElement(ClickOutsideListener, { onClickOutside: handleClickOutside, target: columnLeftRef.current }),
8621
+ showPanel ? ColumnLeftComponent : null,
8622
+ ColumnRightComponent));
8623
+ });
8624
+ TwoColumnPanel.displayName = 'TwoColumnPanel';
8625
+
8626
+ var ColumnHeader = React.forwardRef(function (_a, ref) {
8627
+ var className = _a.className, children = _a.children, props = tslib.__rest(_a, ["className", "children"]);
8628
+ return (React__default.createElement("div", tslib.__assign({ className: classNames('TwoColumnPanel__Header', className) }, props, { ref: ref }), children));
8629
+ });
8630
+ ColumnHeader.displayName = 'ColumnHeader';
8631
+
8632
+ var ColumnGroupHeader = React.forwardRef(function (_a, ref) {
8633
+ var className = _a.className, children = _a.children, props = tslib.__rest(_a, ["className", "children"]);
8634
+ return (React__default.createElement("div", tslib.__assign({ className: classNames('TwoColumnPanel__GroupHeader', className) }, props, { ref: ref }), children));
8635
+ });
8636
+ ColumnGroupHeader.displayName = 'ColumnGroupHeader';
8637
+
8638
+ var ColumnLeft = React.forwardRef(function (_a, ref) {
8639
+ var className = _a.className, children = _a.children, props = tslib.__rest(_a, ["className", "children"]);
8640
+ return (React__default.createElement("section", tslib.__assign({ className: classNames('TwoColumnPanel__Left', className) }, props, { ref: ref }), children));
8641
+ });
8642
+ ColumnLeft.displayName = 'ColumnLeft';
8643
+
8644
+ var ColumnRight = React.forwardRef(function (_a, ref) {
8645
+ var className = _a.className, children = _a.children, props = tslib.__rest(_a, ["className", "children"]);
8646
+ return (React__default.createElement("section", tslib.__assign({ className: classNames('TwoColumnPanel__Right', className) }, props, { ref: ref }), children));
8647
+ });
8648
+ ColumnRight.displayName = 'ColumnRight';
8649
+
8650
+ var ColumnList = React.forwardRef(function (_a, ref) {
8651
+ var className = _a.className, children = _a.children, props = tslib.__rest(_a, ["className", "children"]);
8652
+ return (React__default.createElement("div", tslib.__assign({ className: classNames('TwoColumnPanel__List', className) }, props, { ref: ref }), children));
8653
+ });
8654
+ ColumnList.displayName = 'ColumnList';
8655
+
8486
8656
  var LIGHT_THEME_CLASS = 'cauldron--theme-light';
8487
8657
  var DARK_THEME_CLASS = 'cauldron--theme-dark';
8488
8658
  var ThemeContext = React.createContext({});
@@ -8560,6 +8730,11 @@ exports.CardHeader = CardHeader;
8560
8730
  exports.Checkbox = Checkbox;
8561
8731
  exports.ClickOutsideListener = ClickOutsideListener;
8562
8732
  exports.Code = Code;
8733
+ exports.ColumnGroupHeader = ColumnGroupHeader;
8734
+ exports.ColumnHeader = ColumnHeader;
8735
+ exports.ColumnLeft = ColumnLeft;
8736
+ exports.ColumnList = ColumnList;
8737
+ exports.ColumnRight = ColumnRight;
8563
8738
  exports.DescriptionDetails = DescriptionDetails;
8564
8739
  exports.DescriptionList = DescriptionList;
8565
8740
  exports.DescriptionListItem = DescriptionListItem;
@@ -8628,6 +8803,7 @@ exports.TopBar = TopBar$1;
8628
8803
  exports.TopBarItem = MenuItem;
8629
8804
  exports.TopBarMenu = TopBarMenu;
8630
8805
  exports.TopBarTrigger = TopBarTrigger;
8806
+ exports.TwoColumnPanel = TwoColumnPanel;
8631
8807
  exports.Workspace = Workspace;
8632
8808
  exports.focusableSelector = focusableSelector;
8633
8809
  exports.iconTypes = iconTypes;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deque/cauldron-react",
3
- "version": "4.1.0-canary.3eec0660",
3
+ "version": "4.1.0-canary.4ee8aabd",
4
4
  "description": "Fully accessible react components library for Deque Cauldron",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -23,7 +23,7 @@
23
23
  "dependencies": {
24
24
  "@popperjs/core": "^2.5.4",
25
25
  "classnames": "^2.2.6",
26
- "focus-trap-react": "^3.0.5",
26
+ "focus-trap-react": "^8.9.0",
27
27
  "focusable": "^2.3.0",
28
28
  "keyname": "^0.1.0",
29
29
  "prop-types": "^15.6.0",