orcs-design-system 2.1.8 → 2.1.10

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.
@@ -320,6 +320,45 @@ export var textButtonActionsMenu = function textButtonActionsMenu() {
320
320
  return /*#__PURE__*/React.createElement(TextButtonActionsMenu, null);
321
321
  };
322
322
  textButtonActionsMenu.storyName = "Text Button Actions Menu";
323
+ export var keepInViewExample = function keepInViewExample() {
324
+ return /*#__PURE__*/React.createElement(Flex, {
325
+ alignItems: "flex-end",
326
+ width: "100%",
327
+ flexDirection: "column"
328
+ }, /*#__PURE__*/React.createElement(ActionsMenu, {
329
+ direction: "right",
330
+ mb: "r"
331
+ }, /*#__PURE__*/React.createElement(ActionsMenuItem, {
332
+ href: "https://orchestrated.io/"
333
+ }, "Open details page"), /*#__PURE__*/React.createElement(BrowserRouter, null, /*#__PURE__*/React.createElement(ActionsMenuItem, {
334
+ as: Link,
335
+ to: "/"
336
+ }, "Edit")), /*#__PURE__*/React.createElement(ActionsMenuItem, {
337
+ onClick: action("clicked")
338
+ }, "Remove")), /*#__PURE__*/React.createElement(ActionsMenu, {
339
+ direction: "right",
340
+ menuTopPosition: "30px",
341
+ menuLeftPosition: "0",
342
+ menuWidth: "220px",
343
+ customTriggerComponent: /*#__PURE__*/React.createElement(Button, {
344
+ variant: "ghost",
345
+ type: "button",
346
+ iconRight: true,
347
+ small: true
348
+ }, "Contact via...", /*#__PURE__*/React.createElement(Icon, {
349
+ icon: ["fas", "chevron-down"]
350
+ }))
351
+ }, /*#__PURE__*/React.createElement(ActionsMenuItem, {
352
+ href: "#"
353
+ }, "Email"), /*#__PURE__*/React.createElement(ActionsMenuItem, {
354
+ href: "#"
355
+ }, "Phone"), /*#__PURE__*/React.createElement(ActionsMenuItem, {
356
+ href: "#"
357
+ }, "MS Teams"), /*#__PURE__*/React.createElement(ActionsMenuItem, {
358
+ href: "#"
359
+ }, "Slack")));
360
+ };
361
+ keepInViewExample.storyName = "Keep In View Example";
323
362
  defaultActionsMenu.__docgenInfo = {
324
363
  "description": "",
325
364
  "methods": [],
@@ -344,4 +383,9 @@ textButtonActionsMenu.__docgenInfo = {
344
383
  "description": "",
345
384
  "methods": [],
346
385
  "displayName": "textButtonActionsMenu"
386
+ };
387
+ keepInViewExample.__docgenInfo = {
388
+ "description": "",
389
+ "methods": [],
390
+ "displayName": "keepInViewExample"
347
391
  };
@@ -7,11 +7,12 @@ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (O
7
7
 
8
8
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
9
9
 
10
- import React, { useState, useEffect, useImperativeHandle } from "react";
10
+ import React, { useState, useEffect, useImperativeHandle, useCallback } from "react";
11
11
  import styled, { css, keyframes, ThemeProvider } from "styled-components";
12
12
  import PropTypes from "prop-types";
13
13
  import { space, layout } from "styled-system";
14
14
  import { themeGet } from "@styled-system/theme-get";
15
+ import { useKeepInView } from "../../hooks/keepInView";
15
16
  var crossTransform1 = keyframes(["0%{transform:translate(0,-6px);border-radius:2px;}50%{transform:translate(0,0);border-radius:2px;}75%{transform:rotate(-45deg) translate(0,0);border-radius:2px;}100%{transform:rotate(-45deg) translate(0,0) scaleX(4);border-radius:0;}"]);
16
17
  var crossTransform2 = keyframes(["0%{transform:translate(0,6px);border-radius:2px;}50%{transform:translate(0,0);border-radius:2px;}75%{transform:rotate(45deg) translate(0,0);border-radius:2px;}100%{transform:rotate(45deg) translate(0,0) scaleX(4);border-radius:0;}"]);
17
18
  var Wrapper = styled.div.withConfig({
@@ -125,15 +126,54 @@ export var ActionsMenuBody = function ActionsMenuBody(_ref) {
125
126
  children = _ref.children,
126
127
  props = _objectWithoutProperties(_ref, ["theme", "onToggle", "toggleState", "direction", "menuTopPosition", "menuLeftPosition", "menuRightPosition", "menuWidth", "customTriggerComponent", "children"]);
127
128
 
129
+ var _useState = useState({
130
+ menuLeftPosition: menuLeftPosition,
131
+ menuRightPosition: menuRightPosition,
132
+ menuTopPosition: menuTopPosition
133
+ }),
134
+ _useState2 = _slicedToArray(_useState, 1),
135
+ menuPosition = _useState2[0];
136
+
137
+ var _useState3 = useState(direction),
138
+ _useState4 = _slicedToArray(_useState3, 2),
139
+ inViewDirection = _useState4[0],
140
+ setInViewDirection = _useState4[1];
141
+
142
+ var setMenuPosition = useCallback(function (newDirection) {
143
+ if (typeof menuLeftPosition !== "undefined" || typeof menuRightPosition !== "undefined") {
144
+ if (menuPosition.menuLeftPosition) {
145
+ menuPosition.menuRightPosition = menuPosition.menuLeftPosition;
146
+ menuPosition.menuLeftPosition = null;
147
+ } else if (menuPosition.menuRightPosition) {
148
+ menuPosition.menuLeftPosition = menuPosition.menuRightPosition;
149
+ menuPosition.menuRightPosition = null;
150
+ }
151
+ }
152
+
153
+ setInViewDirection(newDirection);
154
+ }, [menuLeftPosition, menuRightPosition, menuPosition, setInViewDirection]);
155
+
156
+ var _useKeepInView = useKeepInView({
157
+ direction: direction,
158
+ callback: setMenuPosition,
159
+ shown: true
160
+ }),
161
+ _useKeepInView2 = _slicedToArray(_useKeepInView, 1),
162
+ ref = _useKeepInView2[0];
163
+
164
+ var onToggleInView = function onToggleInView(e) {
165
+ onToggle(e);
166
+ };
167
+
128
168
  var triggerBtn = null;
129
169
 
130
170
  if (customTriggerComponent) {
131
171
  triggerBtn = /*#__PURE__*/React.cloneElement(customTriggerComponent, {
132
- onClick: onToggle
172
+ onClick: onToggleInView
133
173
  });
134
174
  } else {
135
175
  triggerBtn = /*#__PURE__*/React.createElement(Control, {
136
- onClick: onToggle
176
+ onClick: onToggleInView
137
177
  }, /*#__PURE__*/React.createElement(Icon, {
138
178
  isOpen: toggleState
139
179
  }));
@@ -141,11 +181,12 @@ export var ActionsMenuBody = function ActionsMenuBody(_ref) {
141
181
 
142
182
  var component = /*#__PURE__*/React.createElement(Wrapper, props, triggerBtn, /*#__PURE__*/React.createElement(Menu, {
143
183
  isOpen: toggleState,
144
- direction: direction,
145
- menuTopPosition: menuTopPosition,
146
- menuLeftPosition: menuLeftPosition,
147
- menuRightPosition: menuRightPosition,
148
- menuWidth: menuWidth
184
+ direction: inViewDirection,
185
+ menuTopPosition: menuPosition.menuTopPosition,
186
+ menuLeftPosition: menuPosition.menuLeftPosition,
187
+ menuRightPosition: menuPosition.menuRightPosition,
188
+ menuWidth: menuWidth,
189
+ ref: ref
149
190
  }, children));
150
191
  return theme ? /*#__PURE__*/React.createElement(ThemeProvider, {
151
192
  theme: theme
@@ -174,10 +215,10 @@ var ActionsMenu = /*#__PURE__*/React.forwardRef(function (_ref2, ref) {
174
215
  closeOnClick = _ref2$closeOnClick === void 0 ? true : _ref2$closeOnClick,
175
216
  props = _objectWithoutProperties(_ref2, ["children", "customTriggerComponent", "direction", "isOpen", "theme", "closeOnClick"]);
176
217
 
177
- var _useState = useState(isOpen),
178
- _useState2 = _slicedToArray(_useState, 2),
179
- toggleState = _useState2[0],
180
- setToggle = _useState2[1];
218
+ var _useState5 = useState(isOpen),
219
+ _useState6 = _slicedToArray(_useState5, 2),
220
+ toggleState = _useState6[0],
221
+ setToggle = _useState6[1];
181
222
 
182
223
  useImperativeHandle(ref, function () {
183
224
  return {
@@ -129,6 +129,15 @@ export var tooltipWithLinkExample = function tooltipWithLinkExample() {
129
129
  });
130
130
  };
131
131
  tooltipWithLinkExample.storyName = "Tooltip with link Example";
132
+ export var keepInViewExample = function keepInViewExample() {
133
+ return /*#__PURE__*/React.createElement(Flex, {
134
+ justifyContent: "flex-end",
135
+ width: "100%"
136
+ }, /*#__PURE__*/React.createElement(Popover, {
137
+ text: "Description that explains child element"
138
+ }, /*#__PURE__*/React.createElement(Button, null, "Hover Me!")));
139
+ };
140
+ keepInViewExample.storyName = "Keep In View Example";
132
141
  defaultPopover.__docgenInfo = {
133
142
  "description": "",
134
143
  "methods": [],
@@ -163,4 +172,9 @@ tooltipWithLinkExample.__docgenInfo = {
163
172
  "description": "",
164
173
  "methods": [],
165
174
  "displayName": "tooltipWithLinkExample"
175
+ };
176
+ keepInViewExample.__docgenInfo = {
177
+ "description": "",
178
+ "methods": [],
179
+ "displayName": "keepInViewExample"
166
180
  };
@@ -1,11 +1,14 @@
1
1
  import _extends from "@babel/runtime/helpers/extends";
2
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
3
  import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
3
- import React from "react";
4
+ import React, { useState } from "react";
4
5
  import PropTypes from "prop-types";
5
6
  import styled, { css, ThemeProvider } from "styled-components";
6
7
  import { space, layout } from "styled-system";
8
+ import { keys } from "lodash";
7
9
  import Icon from "../Icon";
8
10
  import { themeGet } from "@styled-system/theme-get";
11
+ import { useKeepInView, directions } from "../../hooks/keepInView";
9
12
  var Container = styled.div.withConfig({
10
13
  displayName: "Popover__Container",
11
14
  componentId: "sc-1bwoak-0"
@@ -70,12 +73,33 @@ export default function Popover(_ref2) {
70
73
  enableSelectAll = _ref2$enableSelectAll === void 0 ? true : _ref2$enableSelectAll,
71
74
  props = _objectWithoutProperties(_ref2, ["children", "direction", "width", "textAlign", "text", "inlineBlock", "theme", "variant", "enableSelectAll"]);
72
75
 
76
+ var _useState = useState(direction),
77
+ _useState2 = _slicedToArray(_useState, 2),
78
+ inViewDirection = _useState2[0],
79
+ setInViewDirection = _useState2[1];
80
+
81
+ var _useKeepInView = useKeepInView({
82
+ direction: direction,
83
+ callback: setInViewDirection
84
+ }),
85
+ _useKeepInView2 = _slicedToArray(_useKeepInView, 2),
86
+ ref = _useKeepInView2[0],
87
+ setIsShown = _useKeepInView2[1];
88
+
73
89
  var component = /*#__PURE__*/React.createElement(Container, _extends({
74
90
  inlineBlock: inlineBlock
75
- }, props), !!text && /*#__PURE__*/React.createElement(Text, {
91
+ }, props, {
92
+ onMouseEnter: function onMouseEnter() {
93
+ return setIsShown(true);
94
+ },
95
+ onMouseLeave: function onMouseLeave() {
96
+ return setIsShown(false);
97
+ }
98
+ }), !!text && /*#__PURE__*/React.createElement(Text, {
99
+ ref: ref,
76
100
  className: "popoverText",
77
101
  textAlign: textAlign,
78
- direction: direction,
102
+ direction: inViewDirection,
79
103
  width: width,
80
104
  enableSelectAll: enableSelectAll
81
105
  }, text), variant === "tooltip" && /*#__PURE__*/React.createElement(TooltipControl, {
@@ -93,7 +117,7 @@ Popover.propTypes = {
93
117
  children: PropTypes.element,
94
118
 
95
119
  /** Specifies the direction of the popover. Defaults to right if not specified */
96
- direction: PropTypes.oneOf(["top", "topRight", "right", "bottomRight", "bottom", "bottomLeft", "left", "topLeft"]),
120
+ direction: PropTypes.oneOf(keys(directions)),
97
121
 
98
122
  /** The text contained in the popover element */
99
123
  text: PropTypes.node,
@@ -142,31 +166,8 @@ Popover.__docgenInfo = {
142
166
  "direction": {
143
167
  "type": {
144
168
  "name": "enum",
145
- "value": [{
146
- "value": "\"top\"",
147
- "computed": false
148
- }, {
149
- "value": "\"topRight\"",
150
- "computed": false
151
- }, {
152
- "value": "\"right\"",
153
- "computed": false
154
- }, {
155
- "value": "\"bottomRight\"",
156
- "computed": false
157
- }, {
158
- "value": "\"bottom\"",
159
- "computed": false
160
- }, {
161
- "value": "\"bottomLeft\"",
162
- "computed": false
163
- }, {
164
- "value": "\"left\"",
165
- "computed": false
166
- }, {
167
- "value": "\"topLeft\"",
168
- "computed": false
169
- }]
169
+ "computed": true,
170
+ "value": "keys(directions)"
170
171
  },
171
172
  "required": false,
172
173
  "description": "Specifies the direction of the popover. Defaults to right if not specified"
@@ -23,7 +23,7 @@ var Group = styled("div").withConfig({
23
23
  var IconWrapper = styled.label.withConfig({
24
24
  displayName: "TextInput__IconWrapper",
25
25
  componentId: "shde0o-0"
26
- })(["svg{opacity:0.4;position:absolute;}", ";"], function (props) {
26
+ })(["display:flex;align-items:center;position:relative;svg{opacity:0.4;position:absolute;}", ";"], function (props) {
27
27
  return props.iconLeft && !props.floating ? css(["svg{bottom:", ";left:12px;}"], function (props) {
28
28
  var inputHeight = themeGet("appScale.inputHeightDefault")(props);
29
29
  return "calc(".concat(inputHeight, " / 3 - 1px)");
@@ -0,0 +1,77 @@
1
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
+ import { useState, useEffect } from "react";
3
+ import { useInView } from "react-intersection-observer";
4
+ /**
5
+ * An explicit mapping of directions to their opposites
6
+ * This is used in oppositeDirection() to move the Popover when it leaves the viewPort
7
+ */
8
+
9
+ export var directions = {
10
+ top: "bottom",
11
+ topRight: "bottomLeft",
12
+ right: "left",
13
+ bottomRight: "topLeft",
14
+ bottom: "top",
15
+ bottomLeft: "topRight",
16
+ left: "right",
17
+ topLeft: "bottomRight"
18
+ };
19
+ export var oppositeDirection = function oppositeDirection(direction) {
20
+ if (!direction || !directions[direction]) return "left";
21
+ return directions[direction];
22
+ };
23
+ /**
24
+ * This hook keeps track of the in view status of a component that has a direction setting, like a Popover or ActionsMenu.
25
+ *
26
+ * It does this by tracking the "in view" status of a component that has a direction property and then calling a specified
27
+ * callback with the exact opposite direction setting when it falls out of the view port.
28
+ *
29
+ * The hook returns a `ref` (see https://www.npmjs.com/package/react-intersection-observer) which must be set on the
30
+ * component that is beinbg tracked. It also returns a callback to be called when the component is made visible to the
31
+ * user. This is useful for Popovers where the direction must only be set on hover or on a mouse click for example. For
32
+ * components that are always visible set the default visibility prop to `true`.
33
+ *
34
+ * To use this hook pass in:
35
+ * - the initial direction setting
36
+ * - the default visibility of the component
37
+ * - the `useInView` options (see https://www.npmjs.com/package/react-intersection-observer)
38
+ * - a callback to change the direction of the component when it leaves the view port
39
+ *
40
+ */
41
+
42
+ export var useKeepInView = function useKeepInView(_ref) {
43
+ var direction = _ref.direction,
44
+ _ref$shown = _ref.shown,
45
+ shown = _ref$shown === void 0 ? false : _ref$shown,
46
+ _ref$inViewOptions = _ref.inViewOptions,
47
+ inViewOptions = _ref$inViewOptions === void 0 ? {
48
+ threshold: 1,
49
+ initialInView: true,
50
+ fallbackInView: true
51
+ } : _ref$inViewOptions,
52
+ callback = _ref.callback;
53
+
54
+ var _useState = useState({
55
+ direction: direction
56
+ }),
57
+ _useState2 = _slicedToArray(_useState, 1),
58
+ lastDirection = _useState2[0];
59
+
60
+ var _useState3 = useState(shown),
61
+ _useState4 = _slicedToArray(_useState3, 2),
62
+ isShown = _useState4[0],
63
+ setIsShown = _useState4[1];
64
+
65
+ var _useInView = useInView(inViewOptions),
66
+ ref = _useInView.ref,
67
+ inView = _useInView.inView;
68
+
69
+ useEffect(function () {
70
+ if (!inView && isShown) {
71
+ var newDirection = oppositeDirection(lastDirection.direction);
72
+ callback(newDirection);
73
+ lastDirection.direction = newDirection;
74
+ }
75
+ }, [inView, direction, isShown, callback, lastDirection]);
76
+ return [ref, setIsShown];
77
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orcs-design-system",
3
- "version": "2.1.8",
3
+ "version": "2.1.10",
4
4
  "description": "Orchestrated's Design System, aka: ORCS",
5
5
  "keywords": [
6
6
  "design",
@@ -52,6 +52,7 @@
52
52
  "react-cool-onclickoutside": "^1.5.9",
53
53
  "react-dates": "^21.8.0",
54
54
  "react-docgen": "^5.3.0",
55
+ "react-intersection-observer": "^9.4.3",
55
56
  "react-number-format": "^4.4.1",
56
57
  "react-router": "^5.2.0",
57
58
  "react-router-dom": "^5.2.0",