@canonical/react-components 2.15.1 → 2.16.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.
@@ -22,6 +22,14 @@ export type Props = {
22
22
  * Whether the side panel has an error. This will show an error message in the panel instead of rendering the children.
23
23
  */
24
24
  hasError?: boolean;
25
+ /**
26
+ * Whether the side panel animates on open and close. This requires the side panel to be controlled by the `isOpen` prop instead of conditional rendering. If you use `overlay: true`, you must also include `overflow: hidden` on the document body.
27
+ */
28
+ isAnimated?: boolean;
29
+ /**
30
+ * Whether the side panel is open or not.
31
+ */
32
+ isOpen?: boolean;
25
33
  /**
26
34
  * Whether the side panel is currently loading. This will show a spinner in the panel instead of rendering the children.
27
35
  */
@@ -4,7 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
- var _react = _interopRequireDefault(require("react"));
7
+ var _react = _interopRequireWildcard(require("react"));
8
8
  var _classnames = _interopRequireDefault(require("classnames"));
9
9
  var _reactDom = require("react-dom");
10
10
  var _Content = _interopRequireDefault(require("./common/Content"));
@@ -17,6 +17,8 @@ var _AppAside = _interopRequireDefault(require("../ApplicationLayout/AppAside"))
17
17
  var _Spinner = _interopRequireDefault(require("../Spinner"));
18
18
  require("./SidePanel.scss");
19
19
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
20
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
21
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
20
22
  /**
21
23
  * The props for the SidePanelComponent component.
22
24
  */
@@ -70,17 +72,34 @@ const SidePanelComponent = _ref => {
70
72
  overlay,
71
73
  pinned,
72
74
  width = "",
73
- parentId = "l-application"
75
+ parentId = "l-application",
76
+ isOpen = true,
77
+ isAnimated
74
78
  } = _ref;
79
+ const [hiding, setHiding] = (0, _react.useState)(true);
80
+ const [previousIsOpen, setPreviousIsOpen] = (0, _react.useState)(false);
75
81
  const container = document.getElementById(parentId) || document.body;
82
+ if (isOpen !== previousIsOpen) {
83
+ setPreviousIsOpen(isOpen);
84
+ setHiding(true);
85
+ }
86
+
87
+ // Pinned side panels don't get animation in Vanilla
88
+ const isAnimatedFinal = isAnimated && !pinned;
89
+ if (!isOpen && !(isAnimatedFinal && hiding)) {
90
+ return null;
91
+ }
76
92
  return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/(0, _reactDom.createPortal)( /*#__PURE__*/_react.default.createElement(_AppAside.default, {
77
93
  className: (0, _classnames.default)("side-panel", className, {
78
- "is-overlay": overlay
94
+ "is-overlay": overlay,
95
+ "slide-in": isAnimatedFinal
79
96
  }),
97
+ collapsed: !isOpen,
80
98
  "aria-label": "Side panel",
81
99
  pinned: pinned,
82
100
  narrow: width === "narrow",
83
- wide: width === "wide"
101
+ wide: width === "wide",
102
+ onTransitionEnd: () => setHiding(false)
84
103
  }, loading ? /*#__PURE__*/_react.default.createElement("div", {
85
104
  className: "loading"
86
105
  }, /*#__PURE__*/_react.default.createElement(_Spinner.default, null)) : hasError ? /*#__PURE__*/_react.default.createElement("div", {
@@ -43,3 +43,15 @@
43
43
  bottom: 0;
44
44
  }
45
45
  }
46
+
47
+ .slide-in {
48
+ animation: slideIn 0.1s;
49
+ }
50
+
51
+ @keyframes slideIn {
52
+ from {
53
+ box-shadow: 0 0 0 0 transparent;
54
+ transform: translateX(100%);
55
+ visibility: hidden;
56
+ }
57
+ }
@@ -9,3 +9,4 @@ export declare const Loading: Story;
9
9
  export declare const Error: Story;
10
10
  export declare const Narrow: Story;
11
11
  export declare const Wide: Story;
12
+ export declare const Animated: Story;
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.default = exports.Wide = exports.Pinned = exports.Narrow = exports.Loading = exports.Error = exports.Default = void 0;
6
+ exports.default = exports.Wide = exports.Pinned = exports.Narrow = exports.Loading = exports.Error = exports.Default = exports.Animated = void 0;
7
7
  var _react = _interopRequireWildcard(require("react"));
8
8
  var _SidePanel = _interopRequireDefault(require("./SidePanel"));
9
9
  var _Button = _interopRequireDefault(require("../Button"));
@@ -68,14 +68,16 @@ const StoryExample = args => {
68
68
  style: {
69
69
  margin: "1rem"
70
70
  }
71
- }, "Close side panel")), isOpen && /*#__PURE__*/_react.default.createElement(_SidePanel.default, {
71
+ }, "Close side panel")), /*#__PURE__*/_react.default.createElement(_SidePanel.default, {
72
72
  overlay: args.overlay,
73
73
  loading: args.loading,
74
74
  hasError: args.hasError,
75
75
  parentId: parentId,
76
76
  pinned: args.pinned,
77
77
  width: args.width,
78
- className: "u-no-padding--top u-no-padding--bottom"
78
+ className: "u-no-padding--top u-no-padding--bottom",
79
+ isOpen: isOpen,
80
+ isAnimated: args.isAnimated
79
81
  }, /*#__PURE__*/_react.default.createElement(_SidePanel.default.Sticky, null, /*#__PURE__*/_react.default.createElement(_SidePanel.default.Header, null, /*#__PURE__*/_react.default.createElement(_SidePanel.default.HeaderTitle, null, "Edit panel"), /*#__PURE__*/_react.default.createElement(_SidePanel.default.HeaderControls, null, /*#__PURE__*/_react.default.createElement(_Button.default, {
80
82
  appearance: "base",
81
83
  className: "u-no-margin--bottom",
@@ -173,4 +175,17 @@ const Wide = exports.Wide = {
173
175
  width: "wide"
174
176
  },
175
177
  render: StoryExample
178
+ };
179
+ const Animated = exports.Animated = {
180
+ args: {
181
+ className: "",
182
+ hasError: false,
183
+ parentId: "l-application-default",
184
+ pinned: false,
185
+ loading: false,
186
+ overlay: false,
187
+ width: "",
188
+ isAnimated: true
189
+ },
190
+ render: StoryExample
176
191
  };
@@ -22,6 +22,14 @@ export type Props = {
22
22
  * Whether the side panel has an error. This will show an error message in the panel instead of rendering the children.
23
23
  */
24
24
  hasError?: boolean;
25
+ /**
26
+ * Whether the side panel animates on open and close. This requires the side panel to be controlled by the `isOpen` prop instead of conditional rendering. If you use `overlay: true`, you must also include `overflow: hidden` on the document body.
27
+ */
28
+ isAnimated?: boolean;
29
+ /**
30
+ * Whether the side panel is open or not.
31
+ */
32
+ isOpen?: boolean;
25
33
  /**
26
34
  * Whether the side panel is currently loading. This will show a spinner in the panel instead of rendering the children.
27
35
  */
@@ -1,4 +1,4 @@
1
- import React from "react";
1
+ import React, { useState } from "react";
2
2
  import classnames from "classnames";
3
3
  import { createPortal } from "react-dom";
4
4
  import Content from "./common/Content";
@@ -64,17 +64,34 @@ var SidePanelComponent = _ref => {
64
64
  overlay,
65
65
  pinned,
66
66
  width = "",
67
- parentId = "l-application"
67
+ parentId = "l-application",
68
+ isOpen = true,
69
+ isAnimated
68
70
  } = _ref;
71
+ var [hiding, setHiding] = useState(true);
72
+ var [previousIsOpen, setPreviousIsOpen] = useState(false);
69
73
  var container = document.getElementById(parentId) || document.body;
74
+ if (isOpen !== previousIsOpen) {
75
+ setPreviousIsOpen(isOpen);
76
+ setHiding(true);
77
+ }
78
+
79
+ // Pinned side panels don't get animation in Vanilla
80
+ var isAnimatedFinal = isAnimated && !pinned;
81
+ if (!isOpen && !(isAnimatedFinal && hiding)) {
82
+ return null;
83
+ }
70
84
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/createPortal( /*#__PURE__*/React.createElement(AppAside, {
71
85
  className: classnames("side-panel", className, {
72
- "is-overlay": overlay
86
+ "is-overlay": overlay,
87
+ "slide-in": isAnimatedFinal
73
88
  }),
89
+ collapsed: !isOpen,
74
90
  "aria-label": "Side panel",
75
91
  pinned: pinned,
76
92
  narrow: width === "narrow",
77
- wide: width === "wide"
93
+ wide: width === "wide",
94
+ onTransitionEnd: () => setHiding(false)
78
95
  }, loading ? /*#__PURE__*/React.createElement("div", {
79
96
  className: "loading"
80
97
  }, /*#__PURE__*/React.createElement(Spinner, null)) : hasError ? /*#__PURE__*/React.createElement("div", {
@@ -43,3 +43,15 @@
43
43
  bottom: 0;
44
44
  }
45
45
  }
46
+
47
+ .slide-in {
48
+ animation: slideIn 0.1s;
49
+ }
50
+
51
+ @keyframes slideIn {
52
+ from {
53
+ box-shadow: 0 0 0 0 transparent;
54
+ transform: translateX(100%);
55
+ visibility: hidden;
56
+ }
57
+ }
@@ -9,3 +9,4 @@ export declare const Loading: Story;
9
9
  export declare const Error: Story;
10
10
  export declare const Narrow: Story;
11
11
  export declare const Wide: Story;
12
+ export declare const Animated: Story;
@@ -59,14 +59,16 @@ var StoryExample = args => {
59
59
  style: {
60
60
  margin: "1rem"
61
61
  }
62
- }, "Close side panel")), isOpen && /*#__PURE__*/React.createElement(SidePanel, {
62
+ }, "Close side panel")), /*#__PURE__*/React.createElement(SidePanel, {
63
63
  overlay: args.overlay,
64
64
  loading: args.loading,
65
65
  hasError: args.hasError,
66
66
  parentId: parentId,
67
67
  pinned: args.pinned,
68
68
  width: args.width,
69
- className: "u-no-padding--top u-no-padding--bottom"
69
+ className: "u-no-padding--top u-no-padding--bottom",
70
+ isOpen: isOpen,
71
+ isAnimated: args.isAnimated
70
72
  }, /*#__PURE__*/React.createElement(SidePanel.Sticky, null, /*#__PURE__*/React.createElement(SidePanel.Header, null, /*#__PURE__*/React.createElement(SidePanel.HeaderTitle, null, "Edit panel"), /*#__PURE__*/React.createElement(SidePanel.HeaderControls, null, /*#__PURE__*/React.createElement(Button, {
71
73
  appearance: "base",
72
74
  className: "u-no-margin--bottom",
@@ -164,4 +166,17 @@ export var Wide = {
164
166
  width: "wide"
165
167
  },
166
168
  render: StoryExample
169
+ };
170
+ export var Animated = {
171
+ args: {
172
+ className: "",
173
+ hasError: false,
174
+ parentId: "l-application-default",
175
+ pinned: false,
176
+ loading: false,
177
+ overlay: false,
178
+ width: "",
179
+ isAnimated: true
180
+ },
181
+ render: StoryExample
167
182
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canonical/react-components",
3
- "version": "2.15.1",
3
+ "version": "2.16.0",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index.js",
6
6
  "author": {
@@ -93,7 +93,7 @@
93
93
  "tsc-alias": "1.8.10",
94
94
  "typescript": "5.7.3",
95
95
  "typescript-eslint": "8.24.1",
96
- "vanilla-framework": "4.29.0",
96
+ "vanilla-framework": "4.30.0",
97
97
  "wait-on": "8.0.2",
98
98
  "webpack": "5.98.0"
99
99
  },