@datarobot/design-system 28.2.2 → 28.3.0-experimental.2

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.
@@ -3,6 +3,7 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core';
3
3
  import { TooltipPlacementsType } from '../tooltip';
4
4
  import './dropdown-item-title.less';
5
5
  export type DropdownItemTitleOption = {
6
+ key: string | number;
6
7
  iconClass?: string;
7
8
  icon?: IconProp;
8
9
  title?: ReactNode;
@@ -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 _faChevronRight = require("@fortawesome/free-solid-svg-icons/faChevronRight");
10
10
  var _fontAwesomeIcon = require("../font-awesome-icon");
@@ -12,6 +12,7 @@ var _truncateWithTooltip = require("../truncate-with-tooltip");
12
12
  var _tooltip = require("../tooltip");
13
13
  var _jsxRuntime = require("react/jsx-runtime");
14
14
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
15
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
15
16
  const DropdownItemTitle = ({
16
17
  option,
17
18
  isMultiLevelHandler = false
@@ -25,7 +26,8 @@ const DropdownItemTitle = ({
25
26
  tooltipPlacement,
26
27
  tooltipText,
27
28
  tooltipDocsLink,
28
- tooltipTestId
29
+ tooltipTestId,
30
+ key
29
31
  } = option;
30
32
  const props = {
31
33
  tooltipText,
@@ -59,14 +61,14 @@ const DropdownItemTitle = ({
59
61
  })
60
62
  });
61
63
  const withTruncatableText = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
62
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_truncateWithTooltip.TruncateWithTooltip, {
64
+ children: [/*#__PURE__*/(0, _react.createElement)(_truncateWithTooltip.TruncateWithTooltip, {
63
65
  ...props,
64
- children: itemTitle
65
- }), subtext && /*#__PURE__*/(0, _jsxRuntime.jsx)(_truncateWithTooltip.TruncateWithTooltip, {
66
+ key: key
67
+ }, itemTitle), subtext && /*#__PURE__*/(0, _react.createElement)(_truncateWithTooltip.TruncateWithTooltip, {
66
68
  ...props,
67
69
  tooltipTestId: `${tooltipTestId}-subtext`,
68
- children: itemSubText
69
- })]
70
+ key: `${key}-subtext`
71
+ }, itemSubText)]
70
72
  });
71
73
  return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
72
74
  className: (0, _classnames.default)('drop-item-content-wrap', {
@@ -18,11 +18,16 @@ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r
18
18
  const DefaultTriggerContent = ({
19
19
  selectedItem,
20
20
  defaultTriggerText
21
- }) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_truncateWithTooltip.TruncateWithTooltip, {
22
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
23
- children: selectedItem?.title ?? defaultTriggerText
24
- })
25
- });
21
+ }) => {
22
+ const id = (0, _react.useId)();
23
+ const title = selectedItem?.title ?? defaultTriggerText;
24
+ const key = typeof title === 'string' && title.length ? title : id;
25
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_truncateWithTooltip.TruncateWithTooltip, {
26
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
27
+ children: title
28
+ })
29
+ }, key);
30
+ };
26
31
  const DropdownMenuTrigger = /*#__PURE__*/(0, _react.forwardRef)(({
27
32
  onClick,
28
33
  isOpen,
@@ -31,6 +31,7 @@ const DefaultTriggerContent = function ({
31
31
  });
32
32
  }
33
33
  const triggerContent = getGenericTriggerContent(selectedItem, options);
34
+ const key = selectedItem?.key;
34
35
  if (triggerContent) {
35
36
  return /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
36
37
  className: "selected-item-details",
@@ -38,7 +39,7 @@ const DefaultTriggerContent = function ({
38
39
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
39
40
  children: triggerContent
40
41
  })
41
- })
42
+ }, key)
42
43
  });
43
44
  }
44
45
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_truncateWithTooltip.TruncateWithTooltip, {
@@ -46,7 +47,7 @@ const DefaultTriggerContent = function ({
46
47
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
47
48
  children: defaultTriggerText
48
49
  })
49
- });
50
+ }, key);
50
51
  };
51
52
  function getGenericTriggerContent(selectedItem, options) {
52
53
  const selectedOptions = options.filter(option => option.isChecked).map(option => option.title);
@@ -79,18 +79,7 @@ function InlineEdit({
79
79
  const [touched, setTouched] = (0, _react.useState)(false);
80
80
  const [inputValue, setInputValue] = (0, _react.useState)(value);
81
81
  const [componentId] = (0, _react.useState)(() => (0, _uniqueId.default)());
82
-
83
- // check if 2 elements have autofocus and render in same time
84
- const [isEditMode, setIsEditMode] = (0, _react.useState)(() => {
85
- if (isSomeOneOpen() || readOnly || isLoading) {
86
- return false;
87
- }
88
- if (autoFocus) {
89
- openState.set(componentId, true);
90
- return true;
91
- }
92
- return false;
93
- });
82
+ const [isEditMode, setIsEditMode] = (0, _react.useState)(false);
94
83
  const container = (0, _react.useRef)(null);
95
84
  const handleCancel = () => {
96
85
  setInputValue(value);
@@ -119,6 +108,18 @@ function InlineEdit({
119
108
  (0, _react.useEffect)(() => () => {
120
109
  openState.delete(componentId);
121
110
  }, []);
111
+ (0, _react.useLayoutEffect)(() => {
112
+ // If the component is mounted, autoFocus is true, and there are no other inline edits in edit mode -
113
+ // set the open state and edit mode to true
114
+ // previously it was set in state initialization function but since react 18 that initialization function
115
+ // can be called twice without unmount if 2+ components rendering inline edit are wrapped in Suspense and lazy loaded
116
+ // it results in inline edits being locked up because first id is set to true, however latest render would use different id
117
+ // it turns out to be common react thing: https://stackoverflow.com/questions/73325723/suspense-as-a-root-element-causes-two-instances-of-component-in-production-and
118
+ if (autoFocus && !(isSomeOneOpen() || readOnly || isLoading)) {
119
+ openState.set(componentId, true);
120
+ setIsEditMode(true);
121
+ }
122
+ }, []);
122
123
  const onTextClick = e => {
123
124
  e.preventDefault();
124
125
  if (!isSomeOneOpen() && !readOnly && !isLoading) {
@@ -3,6 +3,7 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core';
3
3
  import { TooltipPlacementsType } from '../tooltip';
4
4
  import './dropdown-item-title.less';
5
5
  export type DropdownItemTitleOption = {
6
+ key: string | number;
6
7
  iconClass?: string;
7
8
  icon?: IconProp;
8
9
  title?: ReactNode;
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React, { createElement as _createElement } from 'react';
2
2
  import classnames from 'classnames';
3
3
  import { faChevronRight } from '@fortawesome/free-solid-svg-icons/faChevronRight';
4
4
  import { FontAwesomeIcon } from '../font-awesome-icon';
@@ -18,7 +18,8 @@ const DropdownItemTitle = ({
18
18
  tooltipPlacement,
19
19
  tooltipText,
20
20
  tooltipDocsLink,
21
- tooltipTestId
21
+ tooltipTestId,
22
+ key
22
23
  } = option;
23
24
  const props = {
24
25
  tooltipText,
@@ -52,14 +53,14 @@ const DropdownItemTitle = ({
52
53
  })
53
54
  });
54
55
  const withTruncatableText = /*#__PURE__*/_jsxs(_Fragment, {
55
- children: [/*#__PURE__*/_jsx(TruncateWithTooltip, {
56
+ children: [/*#__PURE__*/_createElement(TruncateWithTooltip, {
56
57
  ...props,
57
- children: itemTitle
58
- }), subtext && /*#__PURE__*/_jsx(TruncateWithTooltip, {
58
+ key: key
59
+ }, itemTitle), subtext && /*#__PURE__*/_createElement(TruncateWithTooltip, {
59
60
  ...props,
60
61
  tooltipTestId: `${tooltipTestId}-subtext`,
61
- children: itemSubText
62
- })]
62
+ key: `${key}-subtext`
63
+ }, itemSubText)]
63
64
  });
64
65
  return /*#__PURE__*/_jsx("div", {
65
66
  className: classnames('drop-item-content-wrap', {
@@ -1,4 +1,4 @@
1
- import React, { forwardRef } from 'react';
1
+ import React, { forwardRef, useId } from 'react';
2
2
  import classNames from 'classnames';
3
3
  import { faChevronDown } from '@fortawesome/free-solid-svg-icons/faChevronDown';
4
4
  import { FontAwesomeIcon } from '../font-awesome-icon';
@@ -10,11 +10,16 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
10
10
  const DefaultTriggerContent = ({
11
11
  selectedItem,
12
12
  defaultTriggerText
13
- }) => /*#__PURE__*/_jsx(TruncateWithTooltip, {
14
- children: /*#__PURE__*/_jsx("span", {
15
- children: selectedItem?.title ?? defaultTriggerText
16
- })
17
- });
13
+ }) => {
14
+ const id = useId();
15
+ const title = selectedItem?.title ?? defaultTriggerText;
16
+ const key = typeof title === 'string' && title.length ? title : id;
17
+ return /*#__PURE__*/_jsx(TruncateWithTooltip, {
18
+ children: /*#__PURE__*/_jsx("span", {
19
+ children: title
20
+ })
21
+ }, key);
22
+ };
18
23
  const DropdownMenuTrigger = /*#__PURE__*/forwardRef(({
19
24
  onClick,
20
25
  isOpen,
@@ -23,6 +23,7 @@ const DefaultTriggerContent = function ({
23
23
  });
24
24
  }
25
25
  const triggerContent = getGenericTriggerContent(selectedItem, options);
26
+ const key = selectedItem?.key;
26
27
  if (triggerContent) {
27
28
  return /*#__PURE__*/_jsx("span", {
28
29
  className: "selected-item-details",
@@ -30,7 +31,7 @@ const DefaultTriggerContent = function ({
30
31
  children: /*#__PURE__*/_jsx("span", {
31
32
  children: triggerContent
32
33
  })
33
- })
34
+ }, key)
34
35
  });
35
36
  }
36
37
  return /*#__PURE__*/_jsx(TruncateWithTooltip, {
@@ -38,7 +39,7 @@ const DefaultTriggerContent = function ({
38
39
  children: /*#__PURE__*/_jsx("span", {
39
40
  children: defaultTriggerText
40
41
  })
41
- });
42
+ }, key);
42
43
  };
43
44
  function getGenericTriggerContent(selectedItem, options) {
44
45
  const selectedOptions = options.filter(option => option.isChecked).map(option => option.title);
@@ -1,4 +1,4 @@
1
- import React, { useState, useEffect, useMemo, useRef } from 'react';
1
+ import React, { useState, useEffect, useMemo, useRef, useLayoutEffect } from 'react';
2
2
  import cls from 'classnames';
3
3
  import uniqueId from 'lodash-es/uniqueId';
4
4
  import { faPen } from '@fortawesome/free-solid-svg-icons/faPen';
@@ -71,18 +71,7 @@ export default function InlineEdit({
71
71
  const [touched, setTouched] = useState(false);
72
72
  const [inputValue, setInputValue] = useState(value);
73
73
  const [componentId] = useState(() => uniqueId());
74
-
75
- // check if 2 elements have autofocus and render in same time
76
- const [isEditMode, setIsEditMode] = useState(() => {
77
- if (isSomeOneOpen() || readOnly || isLoading) {
78
- return false;
79
- }
80
- if (autoFocus) {
81
- openState.set(componentId, true);
82
- return true;
83
- }
84
- return false;
85
- });
74
+ const [isEditMode, setIsEditMode] = useState(false);
86
75
  const container = useRef(null);
87
76
  const handleCancel = () => {
88
77
  setInputValue(value);
@@ -111,6 +100,18 @@ export default function InlineEdit({
111
100
  useEffect(() => () => {
112
101
  openState.delete(componentId);
113
102
  }, []);
103
+ useLayoutEffect(() => {
104
+ // If the component is mounted, autoFocus is true, and there are no other inline edits in edit mode -
105
+ // set the open state and edit mode to true
106
+ // previously it was set in state initialization function but since react 18 that initialization function
107
+ // can be called twice without unmount if 2+ components rendering inline edit are wrapped in Suspense and lazy loaded
108
+ // it results in inline edits being locked up because first id is set to true, however latest render would use different id
109
+ // it turns out to be common react thing: https://stackoverflow.com/questions/73325723/suspense-as-a-root-element-causes-two-instances-of-component-in-production-and
110
+ if (autoFocus && !(isSomeOneOpen() || readOnly || isLoading)) {
111
+ openState.set(componentId, true);
112
+ setIsEditMode(true);
113
+ }
114
+ }, []);
114
115
  const onTextClick = e => {
115
116
  e.preventDefault();
116
117
  if (!isSomeOneOpen() && !readOnly && !isLoading) {